termdock 1.4.324 → 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 (343) 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-CUAB0wFe.js → ArchitecturePanel-CJXvqmtu.js} +6 -6
  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-CKIG8diY.js → ChangeWalkthroughPanel-ChPZVfRz.js} +2 -2
  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-CIq-JAbF.js → CollaborationMainWorkspace-DkNhqCj4.js} +1 -1
  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-CPSI-M86.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-BxocNRPm.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-COGOFO0s.js → DiffLab-CX1AwU2v.js} +2 -2
  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-5ERdwz1C.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-BSz9IND6.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-RT-p-ZBo.js → DiffViewer-BDwtwbQM.js} +8 -8
  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-DI9anVWA.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-DOLn8R7c.js → RightSidebar-jOQJePDV.js} +3 -3
  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-CXd0unH5.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-DCqJmX8M.js → arc-BecvFgjf.js} +1 -1
  45. package/dist/client/assets/{arc-DCqJmX8M.js.br → arc-BecvFgjf.js.br} +0 -0
  46. package/dist/client/assets/arc-BecvFgjf.js.gz +0 -0
  47. package/dist/client/assets/{architectureDiagram-5GKGNRK7-DGu_m54H.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-BI0gsxDN.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-Ct3xzGtD.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-BPd2UShA.js → chunk-2Q5K7J3B-Cat1Dsqx.js} +1 -1
  58. package/dist/client/assets/{chunk-5VM5RSS4-CoFZ5Fo3.js → chunk-5VM5RSS4-CT0S2-E8.js} +1 -1
  59. package/dist/client/assets/{chunk-F27PBJKO-C5gZrGp4.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-GW8b9ya-.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-GpMoViQf.js → chunk-JWPE2WC7-DLvwOWZm.js} +1 -1
  66. package/dist/client/assets/{chunk-POPQ4Y6H-C_vgVPaw.js → chunk-POPQ4Y6H-BpiRuG56.js} +1 -1
  67. package/dist/client/assets/{chunk-SVP7TREG-bA7RXwWn.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-BG8DAtll.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-Ces56sud.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-Bwch0qL5.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-CrAXyA2Z.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-R6vltrl4.js.gz +0 -0
  82. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-YlP0Q93l.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-CZ4XcPK9.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-c_8HfHGA.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-BGtRfxMR.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-_9yZnhuv.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-C_mnc4_u.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-sZ_AiSpj.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-Dm-BXeqS.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-Dz4cBepd.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-CbRG8-WW.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-CmBXWlr0.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-B26W6rS7.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-JW5QMYEk.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/{infoDiagram-27XIBGKW-CsA6WdPn.js → infoDiagram-27XIBGKW-BRmB1D5B.js} +1 -1
  122. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-CsKPUwTw.js → ishikawaDiagram-5VMMS53U-DXU4nnZ6.js} +1 -1
  123. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DXU4nnZ6.js.br +0 -0
  124. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DXU4nnZ6.js.gz +0 -0
  125. package/dist/client/assets/{journeyDiagram-3NMN7TZE-DpN98gN0.js → journeyDiagram-3NMN7TZE-DFx7AfiP.js} +1 -1
  126. package/dist/client/assets/journeyDiagram-3NMN7TZE-DFx7AfiP.js.br +0 -0
  127. package/dist/client/assets/journeyDiagram-3NMN7TZE-DFx7AfiP.js.gz +0 -0
  128. package/dist/client/assets/{kanban-definition-UXKFOSKX-RHO--43O.js → kanban-definition-UXKFOSKX-B1ikfXJe.js} +1 -1
  129. package/dist/client/assets/kanban-definition-UXKFOSKX-B1ikfXJe.js.br +0 -0
  130. package/dist/client/assets/kanban-definition-UXKFOSKX-B1ikfXJe.js.gz +0 -0
  131. package/dist/client/assets/{layout-Cm_prknW.js → layout-DkyvZr1Y.js} +1 -1
  132. package/dist/client/assets/layout-DkyvZr1Y.js.br +0 -0
  133. package/dist/client/assets/layout-DkyvZr1Y.js.gz +0 -0
  134. package/dist/client/assets/{linear-BVAsPkvS.js → linear-CECAbRuX.js} +1 -1
  135. package/dist/client/assets/linear-CECAbRuX.js.br +0 -0
  136. package/dist/client/assets/linear-CECAbRuX.js.gz +0 -0
  137. package/dist/client/assets/{mermaid.core-ufe77Xaz.js → mermaid.core-CYY7Wb75.js} +5 -5
  138. package/dist/client/assets/mermaid.core-CYY7Wb75.js.br +0 -0
  139. package/dist/client/assets/mermaid.core-CYY7Wb75.js.gz +0 -0
  140. package/dist/client/assets/{mindmap-definition-YA3MSWOX-CRyy1U2d.js → mindmap-definition-YA3MSWOX-CTs-Y3Lq.js} +1 -1
  141. package/dist/client/assets/mindmap-definition-YA3MSWOX-CTs-Y3Lq.js.br +0 -0
  142. package/dist/client/assets/mindmap-definition-YA3MSWOX-CTs-Y3Lq.js.gz +0 -0
  143. package/dist/client/assets/passwordBootstrap-CPNGDwv6.js +2 -0
  144. package/dist/client/assets/passwordBootstrap-CPNGDwv6.js.br +0 -0
  145. package/dist/client/assets/passwordBootstrap-CPNGDwv6.js.gz +0 -0
  146. package/dist/client/assets/{pegDiagram-XKGWAZYB-DSHgdU9q.js → pegDiagram-XKGWAZYB-Y1oZrwtK.js} +1 -1
  147. package/dist/client/assets/pegDiagram-XKGWAZYB-Y1oZrwtK.js.br +0 -0
  148. package/dist/client/assets/pegDiagram-XKGWAZYB-Y1oZrwtK.js.gz +0 -0
  149. package/dist/client/assets/{pieDiagram-E7YTZNPT-lIUeAuhN.js → pieDiagram-E7YTZNPT-DYSm5OxQ.js} +1 -1
  150. package/dist/client/assets/pieDiagram-E7YTZNPT-DYSm5OxQ.js.br +0 -0
  151. package/dist/client/assets/pieDiagram-E7YTZNPT-DYSm5OxQ.js.gz +0 -0
  152. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-CIgG9vBX.js → quadrantDiagram-AXDQQJYC-DpibIBz0.js} +1 -1
  153. package/dist/client/assets/quadrantDiagram-AXDQQJYC-DpibIBz0.js.br +0 -0
  154. package/dist/client/assets/quadrantDiagram-AXDQQJYC-DpibIBz0.js.gz +0 -0
  155. package/dist/client/assets/{railroadDiagram-O6MQD6OU-DjP8oesA.js → railroadDiagram-O6MQD6OU-b7jp7C1K.js} +1 -1
  156. package/dist/client/assets/railroadDiagram-O6MQD6OU-b7jp7C1K.js.br +0 -0
  157. package/dist/client/assets/railroadDiagram-O6MQD6OU-b7jp7C1K.js.gz +0 -0
  158. package/dist/client/assets/{rdpSession-BshIobdj.js → rdpSession-DU_OJfX5.js} +1 -1
  159. package/dist/client/assets/rdpSession-DU_OJfX5.js.br +0 -0
  160. package/dist/client/assets/rdpSession-DU_OJfX5.js.gz +0 -0
  161. package/dist/client/assets/{referenceLongPress-DBJnfFHa.js → referenceLongPress-BPQ_i68g.js} +1 -1
  162. package/dist/client/assets/referenceLongPress-BPQ_i68g.js.br +0 -0
  163. package/dist/client/assets/referenceLongPress-BPQ_i68g.js.gz +0 -0
  164. package/dist/client/assets/{requirementDiagram-BXWQKSXE-Dbvu6IC_.js → requirementDiagram-BXWQKSXE-BMinO1mf.js} +1 -1
  165. package/dist/client/assets/requirementDiagram-BXWQKSXE-BMinO1mf.js.br +0 -0
  166. package/dist/client/assets/requirementDiagram-BXWQKSXE-BMinO1mf.js.gz +0 -0
  167. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-1mZ4s-lv.js → sankeyDiagram-P5KCCOFB-CmC977VA.js} +1 -1
  168. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CmC977VA.js.br +0 -0
  169. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CmC977VA.js.gz +0 -0
  170. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-Cu3hhzlV.js → sequenceDiagram-WJ2MYXX4-D6eGbgK8.js} +1 -1
  171. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D6eGbgK8.js.br +0 -0
  172. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D6eGbgK8.js.gz +0 -0
  173. package/dist/client/assets/{sizeCapture-INFHLROL-xfm69HlR.js → sizeCapture-INFHLROL-CnRvyBd8.js} +1 -1
  174. package/dist/client/assets/sizeCapture-INFHLROL-CnRvyBd8.js.br +0 -0
  175. package/dist/client/assets/sizeCapture-INFHLROL-CnRvyBd8.js.gz +0 -0
  176. package/dist/client/assets/{sparkles-CDonlwGu.js → sparkles-DzadqrlX.js} +1 -1
  177. package/dist/client/assets/{stateDiagram-D77RDMKH-u-bh6mDK.js → stateDiagram-D77RDMKH-DRSalH10.js} +1 -1
  178. package/dist/client/assets/stateDiagram-D77RDMKH-DRSalH10.js.br +0 -0
  179. package/dist/client/assets/stateDiagram-D77RDMKH-DRSalH10.js.gz +0 -0
  180. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DKe8v_ic.js +1 -0
  181. package/dist/client/assets/{swimlanes-42K2YHIH-U8WN__SO.js → swimlanes-42K2YHIH-u-NnDSzq.js} +1 -1
  182. package/dist/client/assets/swimlanes-42K2YHIH-u-NnDSzq.js.br +0 -0
  183. package/dist/client/assets/swimlanes-42K2YHIH-u-NnDSzq.js.gz +0 -0
  184. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-ei5b8ZYx.js +8 -0
  185. package/dist/client/assets/{timeline-definition-24CTP7MA-CMsoNo4F.js → timeline-definition-24CTP7MA-DkLijg_J.js} +1 -1
  186. package/dist/client/assets/timeline-definition-24CTP7MA-DkLijg_J.js.br +0 -0
  187. package/dist/client/assets/timeline-definition-24CTP7MA-DkLijg_J.js.gz +0 -0
  188. package/dist/client/assets/{triangle-alert-BgErMO2V.js → triangle-alert-D_6xTTiX.js} +1 -1
  189. package/dist/client/assets/{vennDiagram-4TSXK5OY-CPE6pVwh.js → vennDiagram-4TSXK5OY-AWGJtiv3.js} +1 -1
  190. package/dist/client/assets/{vennDiagram-4TSXK5OY-CPE6pVwh.js.br → vennDiagram-4TSXK5OY-AWGJtiv3.js.br} +0 -0
  191. package/dist/client/assets/vennDiagram-4TSXK5OY-AWGJtiv3.js.gz +0 -0
  192. package/dist/client/assets/{videoCompression-BWkZvEjM.js → videoCompression-D3y7Bq8J.js} +1 -1
  193. package/dist/client/assets/videoCompression-D3y7Bq8J.js.br +0 -0
  194. package/dist/client/assets/videoCompression-D3y7Bq8J.js.gz +0 -0
  195. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-4lWd-R4N.js → wardleyDiagram-VM6X3IG4-DI0aZr_y.js} +1 -1
  196. package/dist/client/assets/wardleyDiagram-VM6X3IG4-DI0aZr_y.js.br +0 -0
  197. package/dist/client/assets/wardleyDiagram-VM6X3IG4-DI0aZr_y.js.gz +0 -0
  198. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-CpKJMCWV.js → xychartDiagram-S5SC5T6Z-CCoIN3uU.js} +1 -1
  199. package/dist/client/assets/xychartDiagram-S5SC5T6Z-CCoIN3uU.js.br +0 -0
  200. package/dist/client/assets/xychartDiagram-S5SC5T6Z-CCoIN3uU.js.gz +0 -0
  201. package/dist/client/index.html +1 -1
  202. package/dist/client/index.html.br +0 -0
  203. package/dist/client/index.html.gz +0 -0
  204. package/dist/client/sw.js +1 -1
  205. package/dist/client/sw.js.br +0 -0
  206. package/dist/client/sw.js.gz +0 -0
  207. package/dist/server/agent/integrationServer.js +127 -2
  208. package/dist/server/routes/terminal.js +225 -65
  209. package/dist/server/utils/hostResources.js +128 -0
  210. package/dist/server/utils/tmuxRecoveryOperations.js +348 -0
  211. package/package.json +1 -1
  212. package/runtime-manifest.json +3 -3
  213. package/dist/client/assets/App-7IUcmCLC.js +0 -186
  214. package/dist/client/assets/App-7IUcmCLC.js.br +0 -0
  215. package/dist/client/assets/App-7IUcmCLC.js.gz +0 -0
  216. package/dist/client/assets/ArchitecturePanel-CUAB0wFe.js.br +0 -0
  217. package/dist/client/assets/ArchitecturePanel-CUAB0wFe.js.gz +0 -0
  218. package/dist/client/assets/ChangeWalkthroughPanel-CKIG8diY.js.br +0 -0
  219. package/dist/client/assets/ChangeWalkthroughPanel-CKIG8diY.js.gz +0 -0
  220. package/dist/client/assets/CollaborationMainWorkspace-CIq-JAbF.js.br +0 -0
  221. package/dist/client/assets/CollaborationMainWorkspace-CIq-JAbF.js.gz +0 -0
  222. package/dist/client/assets/CollaborationTaskContent-7vWDzH-d.js +0 -2
  223. package/dist/client/assets/ComputerControlView-CPSI-M86.js.br +0 -0
  224. package/dist/client/assets/ComputerControlView-CPSI-M86.js.gz +0 -0
  225. package/dist/client/assets/DagPlayground-BxocNRPm.js.br +0 -0
  226. package/dist/client/assets/DagPlayground-BxocNRPm.js.gz +0 -0
  227. package/dist/client/assets/DiffLab-COGOFO0s.js.br +0 -0
  228. package/dist/client/assets/DiffLab-COGOFO0s.js.gz +0 -0
  229. package/dist/client/assets/DiffReview-5ERdwz1C.js.br +0 -0
  230. package/dist/client/assets/DiffReview-5ERdwz1C.js.gz +0 -0
  231. package/dist/client/assets/DiffReviewLab-BSz9IND6.js.br +0 -0
  232. package/dist/client/assets/DiffReviewLab-BSz9IND6.js.gz +0 -0
  233. package/dist/client/assets/DiffViewer-RT-p-ZBo.js.br +0 -0
  234. package/dist/client/assets/DiffViewer-RT-p-ZBo.js.gz +0 -0
  235. package/dist/client/assets/ModelPreview-DI9anVWA.js.br +0 -0
  236. package/dist/client/assets/ModelPreview-DI9anVWA.js.gz +0 -0
  237. package/dist/client/assets/RightSidebar-DOLn8R7c.js.br +0 -0
  238. package/dist/client/assets/RightSidebar-DOLn8R7c.js.gz +0 -0
  239. package/dist/client/assets/abnfDiagram-VCTEODGH-CXd0unH5.js.br +0 -0
  240. package/dist/client/assets/abnfDiagram-VCTEODGH-CXd0unH5.js.gz +0 -0
  241. package/dist/client/assets/app-DCFOZi_L.js +0 -35
  242. package/dist/client/assets/app-DCFOZi_L.js.br +0 -0
  243. package/dist/client/assets/app-DCFOZi_L.js.gz +0 -0
  244. package/dist/client/assets/arc-DCqJmX8M.js.gz +0 -0
  245. package/dist/client/assets/architectureDiagram-5GKGNRK7-DGu_m54H.js.br +0 -0
  246. package/dist/client/assets/architectureDiagram-5GKGNRK7-DGu_m54H.js.gz +0 -0
  247. package/dist/client/assets/blockDiagram-I7D4REHJ-BI0gsxDN.js.br +0 -0
  248. package/dist/client/assets/blockDiagram-I7D4REHJ-BI0gsxDN.js.gz +0 -0
  249. package/dist/client/assets/c4Diagram-7LVT6UL2-Ct3xzGtD.js.br +0 -0
  250. package/dist/client/assets/c4Diagram-7LVT6UL2-Ct3xzGtD.js.gz +0 -0
  251. package/dist/client/assets/channel-BLSCUksA.js +0 -1
  252. package/dist/client/assets/chunk-F27PBJKO-C5gZrGp4.js.br +0 -0
  253. package/dist/client/assets/chunk-F27PBJKO-C5gZrGp4.js.gz +0 -0
  254. package/dist/client/assets/chunk-IMKFNOWR-GW8b9ya-.js.br +0 -0
  255. package/dist/client/assets/chunk-IMKFNOWR-GW8b9ya-.js.gz +0 -0
  256. package/dist/client/assets/chunk-SVP7TREG-bA7RXwWn.js.br +0 -0
  257. package/dist/client/assets/chunk-SVP7TREG-bA7RXwWn.js.gz +0 -0
  258. package/dist/client/assets/chunk-TICWLB2K-BG8DAtll.js.br +0 -0
  259. package/dist/client/assets/chunk-TICWLB2K-BG8DAtll.js.gz +0 -0
  260. package/dist/client/assets/classDiagram-ZZMXUADV-DkVIqOvw.js +0 -1
  261. package/dist/client/assets/classDiagram-v2-VYDZK3BY-DkVIqOvw.js +0 -1
  262. package/dist/client/assets/cose-bilkent-JH36ORCC-Bwch0qL5.js.br +0 -0
  263. package/dist/client/assets/cose-bilkent-JH36ORCC-Bwch0qL5.js.gz +0 -0
  264. package/dist/client/assets/cynefin-OW5HDTMX-CrAXyA2Z.js.br +0 -0
  265. package/dist/client/assets/cynefin-OW5HDTMX-CrAXyA2Z.js.gz +0 -0
  266. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-YlP0Q93l.js.br +0 -0
  267. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-YlP0Q93l.js.gz +0 -0
  268. package/dist/client/assets/dagre-GXQ25YYZ-CZ4XcPK9.js.br +0 -0
  269. package/dist/client/assets/dagre-GXQ25YYZ-CZ4XcPK9.js.gz +0 -0
  270. package/dist/client/assets/diagram-S7CK7UJ4-c_8HfHGA.js.br +0 -0
  271. package/dist/client/assets/diagram-S7CK7UJ4-c_8HfHGA.js.gz +0 -0
  272. package/dist/client/assets/diagram-UQ7AKVKN-BGtRfxMR.js.br +0 -0
  273. package/dist/client/assets/diagram-UQ7AKVKN-BGtRfxMR.js.gz +0 -0
  274. package/dist/client/assets/diagram-VSXAHHWV-_9yZnhuv.js.br +0 -0
  275. package/dist/client/assets/diagram-VSXAHHWV-_9yZnhuv.js.gz +0 -0
  276. package/dist/client/assets/diagram-VX7I27RA-C_mnc4_u.js.br +0 -0
  277. package/dist/client/assets/diagram-VX7I27RA-C_mnc4_u.js.gz +0 -0
  278. package/dist/client/assets/diagram-Z3DM3KII-sZ_AiSpj.js.br +0 -0
  279. package/dist/client/assets/diagram-Z3DM3KII-sZ_AiSpj.js.gz +0 -0
  280. package/dist/client/assets/ebnfDiagram-PWID7BFC-Dm-BXeqS.js.br +0 -0
  281. package/dist/client/assets/ebnfDiagram-PWID7BFC-Dm-BXeqS.js.gz +0 -0
  282. package/dist/client/assets/erDiagram-RLTQ6QDP-Dz4cBepd.js.br +0 -0
  283. package/dist/client/assets/erDiagram-RLTQ6QDP-Dz4cBepd.js.gz +0 -0
  284. package/dist/client/assets/flowDiagram-HODETNUW-CbRG8-WW.js.br +0 -0
  285. package/dist/client/assets/flowDiagram-HODETNUW-CbRG8-WW.js.gz +0 -0
  286. package/dist/client/assets/ganttDiagram-EL5Y4UJY-CmBXWlr0.js.br +0 -0
  287. package/dist/client/assets/ganttDiagram-EL5Y4UJY-CmBXWlr0.js.gz +0 -0
  288. package/dist/client/assets/gestureArbiter-B26W6rS7.js.br +0 -0
  289. package/dist/client/assets/gestureArbiter-B26W6rS7.js.gz +0 -0
  290. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-JW5QMYEk.js.br +0 -0
  291. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-JW5QMYEk.js.gz +0 -0
  292. package/dist/client/assets/ishikawaDiagram-5VMMS53U-CsKPUwTw.js.br +0 -0
  293. package/dist/client/assets/ishikawaDiagram-5VMMS53U-CsKPUwTw.js.gz +0 -0
  294. package/dist/client/assets/journeyDiagram-3NMN7TZE-DpN98gN0.js.br +0 -0
  295. package/dist/client/assets/journeyDiagram-3NMN7TZE-DpN98gN0.js.gz +0 -0
  296. package/dist/client/assets/kanban-definition-UXKFOSKX-RHO--43O.js.br +0 -0
  297. package/dist/client/assets/kanban-definition-UXKFOSKX-RHO--43O.js.gz +0 -0
  298. package/dist/client/assets/layout-Cm_prknW.js.br +0 -0
  299. package/dist/client/assets/layout-Cm_prknW.js.gz +0 -0
  300. package/dist/client/assets/linear-BVAsPkvS.js.br +0 -0
  301. package/dist/client/assets/linear-BVAsPkvS.js.gz +0 -0
  302. package/dist/client/assets/mermaid.core-ufe77Xaz.js.br +0 -0
  303. package/dist/client/assets/mermaid.core-ufe77Xaz.js.gz +0 -0
  304. package/dist/client/assets/mindmap-definition-YA3MSWOX-CRyy1U2d.js.br +0 -0
  305. package/dist/client/assets/mindmap-definition-YA3MSWOX-CRyy1U2d.js.gz +0 -0
  306. package/dist/client/assets/passwordBootstrap-3_SIzSH7.js +0 -2
  307. package/dist/client/assets/passwordBootstrap-3_SIzSH7.js.br +0 -0
  308. package/dist/client/assets/passwordBootstrap-3_SIzSH7.js.gz +0 -0
  309. package/dist/client/assets/pegDiagram-XKGWAZYB-DSHgdU9q.js.br +0 -0
  310. package/dist/client/assets/pegDiagram-XKGWAZYB-DSHgdU9q.js.gz +0 -0
  311. package/dist/client/assets/pieDiagram-E7YTZNPT-lIUeAuhN.js.br +0 -0
  312. package/dist/client/assets/pieDiagram-E7YTZNPT-lIUeAuhN.js.gz +0 -0
  313. package/dist/client/assets/quadrantDiagram-AXDQQJYC-CIgG9vBX.js.br +0 -0
  314. package/dist/client/assets/quadrantDiagram-AXDQQJYC-CIgG9vBX.js.gz +0 -0
  315. package/dist/client/assets/railroadDiagram-O6MQD6OU-DjP8oesA.js.br +0 -0
  316. package/dist/client/assets/railroadDiagram-O6MQD6OU-DjP8oesA.js.gz +0 -0
  317. package/dist/client/assets/rdpSession-BshIobdj.js.br +0 -0
  318. package/dist/client/assets/rdpSession-BshIobdj.js.gz +0 -0
  319. package/dist/client/assets/referenceLongPress-DBJnfFHa.js.br +0 -0
  320. package/dist/client/assets/referenceLongPress-DBJnfFHa.js.gz +0 -0
  321. package/dist/client/assets/requirementDiagram-BXWQKSXE-Dbvu6IC_.js.br +0 -0
  322. package/dist/client/assets/requirementDiagram-BXWQKSXE-Dbvu6IC_.js.gz +0 -0
  323. package/dist/client/assets/sankeyDiagram-P5KCCOFB-1mZ4s-lv.js.br +0 -0
  324. package/dist/client/assets/sankeyDiagram-P5KCCOFB-1mZ4s-lv.js.gz +0 -0
  325. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Cu3hhzlV.js.br +0 -0
  326. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Cu3hhzlV.js.gz +0 -0
  327. package/dist/client/assets/sizeCapture-INFHLROL-xfm69HlR.js.br +0 -0
  328. package/dist/client/assets/sizeCapture-INFHLROL-xfm69HlR.js.gz +0 -0
  329. package/dist/client/assets/stateDiagram-D77RDMKH-u-bh6mDK.js.br +0 -0
  330. package/dist/client/assets/stateDiagram-D77RDMKH-u-bh6mDK.js.gz +0 -0
  331. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BQ_m8Gzd.js +0 -1
  332. package/dist/client/assets/swimlanes-42K2YHIH-U8WN__SO.js.br +0 -0
  333. package/dist/client/assets/swimlanes-42K2YHIH-U8WN__SO.js.gz +0 -0
  334. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-FDEo3QWw.js +0 -8
  335. package/dist/client/assets/timeline-definition-24CTP7MA-CMsoNo4F.js.br +0 -0
  336. package/dist/client/assets/timeline-definition-24CTP7MA-CMsoNo4F.js.gz +0 -0
  337. package/dist/client/assets/vennDiagram-4TSXK5OY-CPE6pVwh.js.gz +0 -0
  338. package/dist/client/assets/videoCompression-BWkZvEjM.js.br +0 -0
  339. package/dist/client/assets/videoCompression-BWkZvEjM.js.gz +0 -0
  340. package/dist/client/assets/wardleyDiagram-VM6X3IG4-4lWd-R4N.js.br +0 -0
  341. package/dist/client/assets/wardleyDiagram-VM6X3IG4-4lWd-R4N.js.gz +0 -0
  342. package/dist/client/assets/xychartDiagram-S5SC5T6Z-CpKJMCWV.js.br +0 -0
  343. package/dist/client/assets/xychartDiagram-S5SC5T6Z-CpKJMCWV.js.gz +0 -0
@@ -52,6 +52,8 @@ import { AgentResumeHistoryStore } from '../agent/resumeHistory.js';
52
52
  import { completedExecution, ExecutionArchiveStore } from '../agent/executionArchives.js';
53
53
  import { archiveTaskWorkspace, restoreTaskWorkspace, snapshotTaskWorkspace } from '../agent/collaborationTaskWorkspace.js';
54
54
  import { isTmuxRecoveryCandidate } from '../utils/tmuxRecoveryCandidate.js';
55
+ import { configuredTmuxRecoveryConcurrency, TmuxRecoveryOperationStore } from '../utils/tmuxRecoveryOperations.js';
56
+ import { assessAgentResourceBudget, collectHostResourceSnapshot, configuredAgentResourceBudget } from '../utils/hostResources.js';
55
57
  import { AutomationStore, normalizeAutomationSchedule } from '../agent/automationStore.js';
56
58
  import { writeBracketedPrompt, canDeliverPromptToAgent } from '../agent/promptDelivery.js';
57
59
  import { captureTerminalInputGuard, captureRuntimeInputGuard, waitAndWriteTerminalInput } from '../agent/terminalInput.js';
@@ -204,7 +206,11 @@ const agentResumeHistory = new AgentResumeHistoryStore(`${TERMDOCK_DIR}/agent-re
204
206
  const executionArchives = new ExecutionArchiveStore(`${TERMDOCK_DIR}/execution-archives.json`);
205
207
  let executionArchiveMutation = Promise.resolve();
206
208
  const TMUX_RECOVERY_STATE_FILE = `${TERMDOCK_DIR}/tmux-recovery-state.json`;
209
+ const TMUX_RECOVERY_OPERATIONS_FILE = `${TERMDOCK_DIR}/tmux-recovery-operations.json`;
207
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;
208
214
  const intentionallyDeletingTmuxSessions = new Set();
209
215
  let tmuxRecoveryState = { lastServerPid: null, incident: null, dismissedSessionIds: [] };
210
216
  let persistGlobalStateTimer = null;
@@ -215,6 +221,10 @@ let globalSessionStateReloadTimer = null;
215
221
  // receives deltas on every mutation (PUT/DELETE client-state, dead-session
216
222
  // reconciliation, etc.). Replaces the 5-second poll on the front-end. ──
217
223
  const controlClients = new Map();
224
+ tmuxRecoveryOperations.subscribe(() => {
225
+ latestSessionInventoryAt = 0;
226
+ broadcastClientState();
227
+ });
218
228
  let latestSessionInventory = null;
219
229
  // Only authoritative observations may remove persisted tmux sessions.
220
230
  const inventoryTmuxLiveness = new WeakMap();
@@ -543,8 +553,10 @@ async function loadGlobalSessionStateFromDisk() {
543
553
  async function loadTmuxRecoveryStateFromDisk() {
544
554
  try {
545
555
  const data = await readJsonFileIfExists(TMUX_RECOVERY_STATE_FILE);
546
- if (!data)
556
+ if (!data) {
557
+ await tmuxRecoveryOperations.load();
547
558
  return;
559
+ }
548
560
  tmuxRecoveryState = {
549
561
  lastServerPid: typeof data.lastServerPid === 'number' && Number.isInteger(data.lastServerPid)
550
562
  ? data.lastServerPid
@@ -554,6 +566,7 @@ async function loadTmuxRecoveryStateFromDisk() {
554
566
  ? data.dismissedSessionIds.filter((id) => typeof id === 'string')
555
567
  : [],
556
568
  };
569
+ await tmuxRecoveryOperations.load();
557
570
  }
558
571
  catch (error) {
559
572
  console.warn('[tmux-recovery] Failed to load recovery state:', getErrorMessage(error));
@@ -666,6 +679,8 @@ const shutdownWithRecordings = async () => {
666
679
  if (shuttingDown)
667
680
  return;
668
681
  shuttingDown = true;
682
+ if (tmuxRecoveryHealthTimer)
683
+ clearInterval(tmuxRecoveryHealthTimer);
669
684
  flushPersistAndExit();
670
685
  void persistToolbarPresetsNow();
671
686
  caffeinateManager.shutdown();
@@ -682,6 +697,9 @@ process.on('SIGINT', () => { void shutdownWithRecordings(); });
682
697
  // 服务启动时从磁盘加载(带去重,防止历史累积的重复条目复活)
683
698
  void (async () => {
684
699
  await Promise.all([loadGlobalSessionStateFromDisk(), loadTmuxRecoveryStateFromDisk()]);
700
+ await sampleTmuxRecoveryHealth();
701
+ tmuxRecoveryHealthTimer = setInterval(() => void sampleTmuxRecoveryHealth(), 15_000);
702
+ tmuxRecoveryHealthTimer.unref?.();
685
703
  // Delivery needs the loaded inventory, not optional PTY adoption/metadata backfill.
686
704
  // Those steps must not leave durable messages without a background scheduler.
687
705
  collaborationDeliveryWorker.start();
@@ -694,6 +712,7 @@ void (async () => {
694
712
  });
695
713
  pruneOrphanSessions();
696
714
  await backfillPersistedTmuxMetadata();
715
+ await tmuxRecoveryOperations.resumePending();
697
716
  })();
698
717
  caffeinateManager.startNetworkMonitor();
699
718
  // 清理磁盘恢复后后端已不存在的 session 引用。
@@ -3009,8 +3028,21 @@ async function getTmuxServerPid() {
3009
3028
  }
3010
3029
  function getTmuxRecoveryView() {
3011
3030
  const incident = tmuxRecoveryState.incident;
3012
- if (!incident)
3013
- 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;
3014
3046
  const affected = new Set(incident.affectedSessionIds);
3015
3047
  const sessions = globalSessionState.sessions.flatMap((record) => {
3016
3048
  if (!affected.has(record.sessionId) || record.mode !== 'tmux' || !record.tmuxSessionName
@@ -3029,7 +3061,7 @@ function getTmuxRecoveryView() {
3029
3061
  }];
3030
3062
  });
3031
3063
  return sessions.length > 0
3032
- ? { id: incident.id, detectedAt: incident.detectedAt, sessions }
3064
+ ? { id: incident.id, detectedAt: incident.detectedAt, operation, sessions }
3033
3065
  : null;
3034
3066
  }
3035
3067
  async function observeTmuxServerGeneration(liveTmuxSessions) {
@@ -5938,7 +5970,7 @@ async function resolveShellIntegrationDir() {
5938
5970
  /**
5939
5971
  * Inject termdock shell integration via environment variables.
5940
5972
  *
5941
- * This replaces the old injectShellTitleHooks with a full Ghostty-style
5973
+ * This replaces the old injectShellTitleHooks with full shell
5942
5974
  * integration that emits OSC 133 (prompt marks), OSC 2 (title), and OSC 7 (cwd).
5943
5975
  *
5944
5976
  * Works for both shell mode (env passed to PTY spawn) and tmux mode
@@ -5958,7 +5990,7 @@ async function injectShellIntegration(shellPath, baseEnv) {
5958
5990
  }
5959
5991
  if (shellType === 'zsh') {
5960
5992
  // Create a temporary ZDOTDIR that sources user's zshenv/zshrc then
5961
- // sources our integration script. Same approach as Ghostty.
5993
+ // sources our integration script. This preserves the user shell configuration.
5962
5994
  const zdotdir = '/tmp/termdock-zsh-' + String(process.pid);
5963
5995
  try {
5964
5996
  await fs.promises.mkdir(zdotdir, { recursive: true });
@@ -6122,74 +6154,202 @@ router.get('/tmux/status', async (_req, res) => {
6122
6154
  const status = await getTmuxStatus();
6123
6155
  res.json(status);
6124
6156
  });
6125
- router.post('/tmux/recovery/restore-all', async (_req, res) => {
6126
- const incident = tmuxRecoveryState.incident;
6127
- if (!incident)
6128
- return res.status(404).json({ error: 'no tmux recovery is pending' });
6129
- const outcomes = [];
6130
- for (const frontendSessionId of incident.affectedSessionIds) {
6131
- const record = globalSessionState.sessions.find((session) => session.sessionId === frontendSessionId);
6132
- if (!record || record.mode !== 'tmux' || !record.tmuxSessionName || !record.cwd
6133
- || !record.agentResume?.sessionId) {
6134
- outcomes.push({ sessionId: frontendSessionId, restored: false, error: 'recovery metadata is incomplete' });
6135
- continue;
6136
- }
6137
- const agent = agentBySlug(record.agentResume.slug);
6138
- const command = agent
6139
- ? buildResumeCommand(agent, record.agentResume.sessionId, record.agentResume.launchArgv)
6140
- : null;
6141
- if (!agent || !command) {
6142
- outcomes.push({ sessionId: frontendSessionId, restored: false, error: 'Agent does not support resume' });
6143
- continue;
6144
- }
6145
- const target = {
6146
- slug: agent.slug,
6147
- nativeSessionId: record.agentResume.sessionId,
6148
- command,
6149
- };
6150
- const activeBackend = findActiveAgentResumeOwner('', target);
6151
- const activeWriterPid = activeBackend ? null : await findExternalCodexWriter(target);
6152
- if (activeBackend || activeWriterPid) {
6153
- outcomes.push({ sessionId: frontendSessionId, restored: true });
6154
- 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' });
6155
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);
6156
6187
  try {
6157
- await collaborationDeliveryWorker.reconfigure(frontendSessionId, () => tmuxLifecycle.run(`restore:${record.tmuxSessionName}`, async () => {
6158
- await prepareManagedTmuxSessionUnlocked(record.tmuxSessionName, record.cwd);
6159
- const metadata = await resolveLiveTmuxMetadata(record.tmuxSessionName);
6160
- const foreground = metadata?.program?.toLowerCase() ?? null;
6161
- if (foreground && !shellNamesBackend.has(foreground)) {
6162
- throw new Error(`pane is busy with ${foreground}`);
6163
- }
6164
- // Explicit recovery may replace the vanished tmux pane. A pending
6165
- // message alone must never replace that binding.
6166
- const previous = collaborationRouting.get(frontendSessionId);
6167
- if (previous)
6168
- collaborationRouting.bind({ ...previous, pane: null });
6169
- const launchGuard = await beginAgentLaunchCheck(frontendSessionId, agent.slug, target.nativeSessionId);
6170
- await writeAutomaticTerminalPrompt(frontendSessionId, command, undefined, launchGuard);
6171
- }));
6172
- outcomes.push({ sessionId: frontendSessionId, restored: true });
6188
+ reportPhase('paste_submit');
6189
+ await writeAutomaticTerminalPrompt(frontendSessionId, command, stage => reportPhase(stage), launchGuard);
6173
6190
  }
6174
6191
  catch (error) {
6175
- 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 });
6176
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();
6177
6204
  }
6178
- const restoredIds = new Set(outcomes.filter((outcome) => outcome.restored).map((outcome) => outcome.sessionId));
6179
- const remaining = incident.affectedSessionIds.filter((sessionId) => !restoredIds.has(sessionId));
6180
- tmuxRecoveryState.incident = remaining.length > 0
6181
- ? { ...incident, affectedSessionIds: remaining }
6182
- : null;
6183
- await persistTmuxRecoveryState();
6184
- latestSessionInventoryAt = 0;
6185
- broadcastClientState();
6186
- res.status(remaining.length > 0 ? 207 : 200).json({
6187
- restored: restoredIds.size,
6188
- failed: remaining.length,
6189
- 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;
6190
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' });
6191
6348
  });
6192
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
+ }
6193
6353
  tmuxRecoveryState.dismissedSessionIds = Array.from(new Set([
6194
6354
  ...tmuxRecoveryState.dismissedSessionIds,
6195
6355
  ...(tmuxRecoveryState.incident?.affectedSessionIds ?? []),
@@ -0,0 +1,128 @@
1
+ import fs from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import { execFile } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ import { detectAgentFromCommand } from '../agent/registry.js';
6
+ const execFileAsync = promisify(execFile);
7
+ function parseMemAvailable(contents) {
8
+ const match = contents.match(/^MemAvailable:\s+(\d+)\s+kB$/m);
9
+ return match ? Number(match[1]) * 1024 : null;
10
+ }
11
+ function parsePressure(contents) {
12
+ const parse = (kind) => {
13
+ const line = contents.split('\n').find(item => item.startsWith(`${kind} `));
14
+ const value = line?.match(/\bavg10=([\d.]+)/)?.[1];
15
+ return value === undefined ? null : Number(value);
16
+ };
17
+ const someAvg10 = parse('some');
18
+ const fullAvg10 = parse('full');
19
+ return someAvg10 === null && fullAvg10 === null ? null : { someAvg10, fullAvg10 };
20
+ }
21
+ function parseProcesses(contents, customCommands = {}) {
22
+ return contents.split('\n').flatMap(line => {
23
+ const match = line.trim().match(/^(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(.*)$/);
24
+ if (!match)
25
+ return [];
26
+ const [, pidRaw, pgidRaw, state, ttyRaw, rssRaw, commandRaw] = match;
27
+ const pid = Number(pidRaw), processGroupId = Number(pgidRaw), rssKb = Number(rssRaw);
28
+ if (!Number.isSafeInteger(pid) || pid <= 0 || !Number.isSafeInteger(processGroupId) || processGroupId <= 0 || !Number.isFinite(rssKb))
29
+ return [];
30
+ const command = commandRaw ?? '';
31
+ const comm = (command.split(/\s+/, 1)[0] ?? '').toLowerCase().split('/').at(-1) ?? '';
32
+ return [{
33
+ pid, processGroupId, state: state ?? '?', tty: ttyRaw === '?' ? '' : ttyRaw, command,
34
+ rssBytes: Math.max(0, rssKb) * 1024,
35
+ agent: Boolean(detectAgentFromCommand(command, customCommands)),
36
+ browser: /^(chrome|chromium|firefox|webkit|agent-browser)(-|$)/.test(comm),
37
+ kswapd: /^\[?kswapd\d*\]?$/.test(comm),
38
+ }];
39
+ });
40
+ }
41
+ export async function collectHostResourceSnapshot(customCommands = {}) {
42
+ let memoryAvailableBytes = os.freemem();
43
+ let memorySnapshotAvailable = false;
44
+ let memoryPressure = null;
45
+ if (process.platform === 'linux') {
46
+ const [meminfo, pressure] = await Promise.all([
47
+ fs.readFile('/proc/meminfo', 'utf8').catch(() => ''),
48
+ fs.readFile('/proc/pressure/memory', 'utf8').catch(() => ''),
49
+ ]);
50
+ const parsedAvailable = parseMemAvailable(meminfo);
51
+ if (parsedAvailable !== null) {
52
+ memoryAvailableBytes = parsedAvailable;
53
+ memorySnapshotAvailable = true;
54
+ }
55
+ memoryPressure = parsePressure(pressure);
56
+ }
57
+ else {
58
+ memorySnapshotAvailable = Number.isFinite(memoryAvailableBytes);
59
+ }
60
+ let processRows = [];
61
+ let processSnapshotAvailable = false;
62
+ try {
63
+ const { stdout } = await execFileAsync('ps', ['-e', '-o', 'pid=,pgid=,stat=,tty=,rss=,args='], { timeout: 5000, maxBuffer: 8 * 1024 * 1024 });
64
+ processRows = parseProcesses(stdout, customCommands);
65
+ processSnapshotAvailable = processRows.length > 0;
66
+ }
67
+ catch { /* process metrics are diagnostic; memory admission remains fail-closed below */ }
68
+ const groupRss = new Map();
69
+ const agentGroupIds = new Set();
70
+ for (const row of processRows) {
71
+ groupRss.set(row.processGroupId, (groupRss.get(row.processGroupId) ?? 0) + row.rssBytes);
72
+ if (row.agent)
73
+ agentGroupIds.add(row.processGroupId);
74
+ }
75
+ const agentRss = [...agentGroupIds].reduce((sum, id) => sum + (groupRss.get(id) ?? 0), 0);
76
+ return {
77
+ sampledAt: Date.now(), platform: process.platform, memoryAvailableBytes, memoryTotalBytes: os.totalmem(), memoryPressure,
78
+ dStateProcessCount: processRows.filter(row => row.state.includes('D')).length,
79
+ kswapd: processRows.filter(row => row.kswapd).map(({ pid, state }) => ({ pid, state })),
80
+ residentAgentCount: agentGroupIds.size,
81
+ residentAgentRssBytes: agentRss,
82
+ browserProcessCount: processRows.filter(row => row.browser).length,
83
+ memorySnapshotAvailable,
84
+ processSnapshotAvailable,
85
+ processRows,
86
+ };
87
+ }
88
+ export function configuredAgentResourceBudget(env = process.env) {
89
+ const readMb = (key, fallback, min, max) => {
90
+ const raw = env[key];
91
+ if (raw === undefined || raw.trim() === '')
92
+ return fallback * 1024 ** 2;
93
+ const value = Number(raw);
94
+ if (!Number.isInteger(value) || value < min || value > max)
95
+ throw new Error(`${key} must be an integer from ${min} to ${max} MiB`);
96
+ return value * 1024 ** 2;
97
+ };
98
+ const readCount = (key, fallback, max) => {
99
+ const raw = env[key];
100
+ if (raw === undefined || raw.trim() === '')
101
+ return fallback;
102
+ const value = Number(raw);
103
+ if (!Number.isInteger(value) || value < 1 || value > max)
104
+ throw new Error(`${key} must be an integer from 1 to ${max}`);
105
+ return value;
106
+ };
107
+ return {
108
+ minAvailableBytes: readMb('TD_AGENT_MIN_AVAILABLE_MB', 2048, 256, 131072),
109
+ estimatedRssBytes: readMb('TD_AGENT_ESTIMATED_RSS_MB', 512, 64, 32768),
110
+ maxResidentAgents: readCount('TD_MAX_RESIDENT_AGENTS', 48, 10000),
111
+ maxAgentsPerGroup: readCount('TD_MAX_AGENTS_PER_GROUP', 32, 1000),
112
+ };
113
+ }
114
+ export function assessAgentResourceBudget(input) {
115
+ if (input.snapshot.memorySnapshotAvailable === false || input.snapshot.processSnapshotAvailable === false)
116
+ return { admitted: false, reason: 'RESOURCE_SNAPSHOT_UNAVAILABLE' };
117
+ const required = input.budget.minAvailableBytes + input.budget.estimatedRssBytes;
118
+ if (input.snapshot.memoryAvailableBytes < required)
119
+ return { admitted: false, reason: 'MEMORY_BUDGET_LOW' };
120
+ if (input.snapshot.residentAgentCount >= input.budget.maxResidentAgents)
121
+ return { admitted: false, reason: 'MAX_RESIDENT_AGENTS' };
122
+ if (input.residentAgentsInGroup >= input.budget.maxAgentsPerGroup)
123
+ return { admitted: false, reason: 'MAX_GROUP_AGENTS' };
124
+ return { admitted: true };
125
+ }
126
+ export function parseHostResourcesForTest(contents) {
127
+ return { memAvailableBytes: parseMemAvailable(contents.meminfo), pressure: parsePressure(contents.pressure), processes: parseProcesses(contents.ps) };
128
+ }