termdock 1.4.314 → 1.4.316

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 (353) hide show
  1. package/dist/client/assets/{App-BCTGnwU1.js → App-BF_s1-_u.js} +6 -6
  2. package/dist/client/assets/App-BF_s1-_u.js.br +0 -0
  3. package/dist/client/assets/App-BF_s1-_u.js.gz +0 -0
  4. package/dist/client/assets/{ArchitecturePanel-CVTIYbyj.js → ArchitecturePanel-CdgUQsVD.js} +2 -2
  5. package/dist/client/assets/ArchitecturePanel-CdgUQsVD.js.br +0 -0
  6. package/dist/client/assets/ArchitecturePanel-CdgUQsVD.js.gz +0 -0
  7. package/dist/client/assets/{ChangeWalkthroughPanel-BKsuofw6.js → ChangeWalkthroughPanel-DHp5r1k9.js} +1 -1
  8. package/dist/client/assets/ChangeWalkthroughPanel-DHp5r1k9.js.br +0 -0
  9. package/dist/client/assets/ChangeWalkthroughPanel-DHp5r1k9.js.gz +0 -0
  10. package/dist/client/assets/{CollaborationMainWorkspace-DZ0qwLUz.js → CollaborationMainWorkspace-P_jXjsT-.js} +1 -1
  11. package/dist/client/assets/CollaborationMainWorkspace-P_jXjsT-.js.br +0 -0
  12. package/dist/client/assets/CollaborationMainWorkspace-P_jXjsT-.js.gz +0 -0
  13. package/dist/client/assets/CollaborationTaskContent-DSkxOlKQ.js +2 -0
  14. package/dist/client/assets/ComputerControlView-B5Yng8Dt.js +5 -0
  15. package/dist/client/assets/ComputerControlView-B5Yng8Dt.js.br +0 -0
  16. package/dist/client/assets/ComputerControlView-B5Yng8Dt.js.gz +0 -0
  17. package/dist/client/assets/{DagPlayground-ZgszT1TH.js → DagPlayground-rZE40fcL.js} +1 -1
  18. package/dist/client/assets/DagPlayground-rZE40fcL.js.br +0 -0
  19. package/dist/client/assets/DagPlayground-rZE40fcL.js.gz +0 -0
  20. package/dist/client/assets/{DiffLab-D_9U-zfZ.js → DiffLab-3sIn0W3p.js} +1 -1
  21. package/dist/client/assets/DiffLab-3sIn0W3p.js.br +0 -0
  22. package/dist/client/assets/DiffLab-3sIn0W3p.js.gz +0 -0
  23. package/dist/client/assets/{DiffReview-8Pfe_BNO.js → DiffReview-CBf8-Tli.js} +1 -1
  24. package/dist/client/assets/DiffReview-CBf8-Tli.js.br +0 -0
  25. package/dist/client/assets/DiffReview-CBf8-Tli.js.gz +0 -0
  26. package/dist/client/assets/{DiffReviewLab-p3ZSl0P2.js → DiffReviewLab-BXhskTlx.js} +1 -1
  27. package/dist/client/assets/DiffReviewLab-BXhskTlx.js.br +0 -0
  28. package/dist/client/assets/DiffReviewLab-BXhskTlx.js.gz +0 -0
  29. package/dist/client/assets/{DiffViewer-Cz64sLJT.js → DiffViewer-DZfgjOBh.js} +1 -1
  30. package/dist/client/assets/DiffViewer-DZfgjOBh.js.br +0 -0
  31. package/dist/client/assets/DiffViewer-DZfgjOBh.js.gz +0 -0
  32. package/dist/client/assets/{ModelPreview-B28x060d.js → ModelPreview-Bzdi_sPh.js} +1 -1
  33. package/dist/client/assets/ModelPreview-Bzdi_sPh.js.br +0 -0
  34. package/dist/client/assets/ModelPreview-Bzdi_sPh.js.gz +0 -0
  35. package/dist/client/assets/{RightSidebar-SIqDjggD.js → RightSidebar-DaRdlJzn.js} +42 -42
  36. package/dist/client/assets/RightSidebar-DaRdlJzn.js.br +0 -0
  37. package/dist/client/assets/RightSidebar-DaRdlJzn.js.gz +0 -0
  38. package/dist/client/assets/{abnfDiagram-VCTEODGH--t0bQKCQ.js → abnfDiagram-VCTEODGH-CarKrfAf.js} +1 -1
  39. package/dist/client/assets/abnfDiagram-VCTEODGH-CarKrfAf.js.br +0 -0
  40. package/dist/client/assets/abnfDiagram-VCTEODGH-CarKrfAf.js.gz +0 -0
  41. package/dist/client/assets/{app-DWidKLU2.js → app-BCTEfclM.js} +3 -3
  42. package/dist/client/assets/app-BCTEfclM.js.br +0 -0
  43. package/dist/client/assets/app-BCTEfclM.js.gz +0 -0
  44. package/dist/client/assets/{arc-DMWsmL7t.js → arc-B6Qdq2Vw.js} +1 -1
  45. package/dist/client/assets/arc-B6Qdq2Vw.js.br +0 -0
  46. package/dist/client/assets/arc-B6Qdq2Vw.js.gz +0 -0
  47. package/dist/client/assets/{architectureDiagram-5GKGNRK7-BYkvSKnR.js → architectureDiagram-5GKGNRK7-DgPJ0l9i.js} +1 -1
  48. package/dist/client/assets/architectureDiagram-5GKGNRK7-DgPJ0l9i.js.br +0 -0
  49. package/dist/client/assets/architectureDiagram-5GKGNRK7-DgPJ0l9i.js.gz +0 -0
  50. package/dist/client/assets/{blockDiagram-I7D4REHJ-B574d9TS.js → blockDiagram-I7D4REHJ-BsorvNo4.js} +1 -1
  51. package/dist/client/assets/blockDiagram-I7D4REHJ-BsorvNo4.js.br +0 -0
  52. package/dist/client/assets/blockDiagram-I7D4REHJ-BsorvNo4.js.gz +0 -0
  53. package/dist/client/assets/{c4Diagram-7LVT6UL2-D__CwUct.js → c4Diagram-7LVT6UL2-Bbpi62ab.js} +1 -1
  54. package/dist/client/assets/{c4Diagram-7LVT6UL2-D__CwUct.js.br → c4Diagram-7LVT6UL2-Bbpi62ab.js.br} +0 -0
  55. package/dist/client/assets/c4Diagram-7LVT6UL2-Bbpi62ab.js.gz +0 -0
  56. package/dist/client/assets/channel-uZtI4GD8.js +1 -0
  57. package/dist/client/assets/{chunk-2Q5K7J3B-BvwmL72I.js → chunk-2Q5K7J3B-Cm7mDz66.js} +1 -1
  58. package/dist/client/assets/{chunk-5VM5RSS4-BktO-a5l.js → chunk-5VM5RSS4-BMERXU_m.js} +1 -1
  59. package/dist/client/assets/{chunk-F27PBJKO-DeClqFBe.js → chunk-F27PBJKO-fe9Yw7OI.js} +1 -1
  60. package/dist/client/assets/chunk-F27PBJKO-fe9Yw7OI.js.br +0 -0
  61. package/dist/client/assets/chunk-F27PBJKO-fe9Yw7OI.js.gz +0 -0
  62. package/dist/client/assets/{chunk-IMKFNOWR-DBRCslkn.js → chunk-IMKFNOWR-QquKV9k-.js} +1 -1
  63. package/dist/client/assets/chunk-IMKFNOWR-QquKV9k-.js.br +0 -0
  64. package/dist/client/assets/chunk-IMKFNOWR-QquKV9k-.js.gz +0 -0
  65. package/dist/client/assets/{chunk-JWPE2WC7-BfpbqgrR.js → chunk-JWPE2WC7-CVe8_YO4.js} +1 -1
  66. package/dist/client/assets/{chunk-POPQ4Y6H-Bw-dqneu.js → chunk-POPQ4Y6H-DT8PalJ4.js} +1 -1
  67. package/dist/client/assets/{chunk-SVP7TREG-BdxOWBjP.js → chunk-SVP7TREG-BUQulipE.js} +1 -1
  68. package/dist/client/assets/chunk-SVP7TREG-BUQulipE.js.br +0 -0
  69. package/dist/client/assets/chunk-SVP7TREG-BUQulipE.js.gz +0 -0
  70. package/dist/client/assets/{chunk-TICWLB2K-BtNXehgz.js → chunk-TICWLB2K-fubKwUCg.js} +1 -1
  71. package/dist/client/assets/chunk-TICWLB2K-fubKwUCg.js.br +0 -0
  72. package/dist/client/assets/chunk-TICWLB2K-fubKwUCg.js.gz +0 -0
  73. package/dist/client/assets/{chunk-XXDRQBXY-CUxGdImw.js → chunk-XXDRQBXY-CdwTi82y.js} +1 -1
  74. package/dist/client/assets/classDiagram-ZZMXUADV-CgJJ1J4J.js +1 -0
  75. package/dist/client/assets/classDiagram-v2-VYDZK3BY-CgJJ1J4J.js +1 -0
  76. package/dist/client/assets/{cose-bilkent-JH36ORCC-Buod2YZ0.js → cose-bilkent-JH36ORCC-DmEDc2ee.js} +1 -1
  77. package/dist/client/assets/cose-bilkent-JH36ORCC-DmEDc2ee.js.br +0 -0
  78. package/dist/client/assets/cose-bilkent-JH36ORCC-DmEDc2ee.js.gz +0 -0
  79. package/dist/client/assets/{cynefin-OW5HDTMX-i2eiybdj.js → cynefin-OW5HDTMX-C-mfarRX.js} +1 -1
  80. package/dist/client/assets/cynefin-OW5HDTMX-C-mfarRX.js.br +0 -0
  81. package/dist/client/assets/cynefin-OW5HDTMX-C-mfarRX.js.gz +0 -0
  82. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-D_YF2Yi3.js → cynefinDiagram-5FMLGOSQ-CgVmp8od.js} +1 -1
  83. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CgVmp8od.js.br +0 -0
  84. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CgVmp8od.js.gz +0 -0
  85. package/dist/client/assets/{dagre-GXQ25YYZ-CfLEvt7Z.js → dagre-GXQ25YYZ-WU_d2fSU.js} +1 -1
  86. package/dist/client/assets/dagre-GXQ25YYZ-WU_d2fSU.js.br +0 -0
  87. package/dist/client/assets/dagre-GXQ25YYZ-WU_d2fSU.js.gz +0 -0
  88. package/dist/client/assets/{diagram-S7CK7UJ4-BV0Wackt.js → diagram-S7CK7UJ4-Dtikk80Z.js} +1 -1
  89. package/dist/client/assets/diagram-S7CK7UJ4-Dtikk80Z.js.br +0 -0
  90. package/dist/client/assets/diagram-S7CK7UJ4-Dtikk80Z.js.gz +0 -0
  91. package/dist/client/assets/{diagram-UQ7AKVKN-jwaoLY_P.js → diagram-UQ7AKVKN-DuTCB36P.js} +1 -1
  92. package/dist/client/assets/diagram-UQ7AKVKN-DuTCB36P.js.br +0 -0
  93. package/dist/client/assets/diagram-UQ7AKVKN-DuTCB36P.js.gz +0 -0
  94. package/dist/client/assets/{diagram-VSXAHHWV-CuAFyl0n.js → diagram-VSXAHHWV-DSLAcWi6.js} +1 -1
  95. package/dist/client/assets/diagram-VSXAHHWV-DSLAcWi6.js.br +0 -0
  96. package/dist/client/assets/diagram-VSXAHHWV-DSLAcWi6.js.gz +0 -0
  97. package/dist/client/assets/{diagram-VX7I27RA-bbmA7rRk.js → diagram-VX7I27RA-DyQOu10m.js} +1 -1
  98. package/dist/client/assets/diagram-VX7I27RA-DyQOu10m.js.br +0 -0
  99. package/dist/client/assets/diagram-VX7I27RA-DyQOu10m.js.gz +0 -0
  100. package/dist/client/assets/{diagram-Z3DM3KII-CX3-Mxwo.js → diagram-Z3DM3KII-CuMI1k1t.js} +1 -1
  101. package/dist/client/assets/diagram-Z3DM3KII-CuMI1k1t.js.br +0 -0
  102. package/dist/client/assets/diagram-Z3DM3KII-CuMI1k1t.js.gz +0 -0
  103. package/dist/client/assets/{ebnfDiagram-PWID7BFC-Pkq6omzy.js → ebnfDiagram-PWID7BFC-Di8RxhNL.js} +1 -1
  104. package/dist/client/assets/ebnfDiagram-PWID7BFC-Di8RxhNL.js.br +0 -0
  105. package/dist/client/assets/ebnfDiagram-PWID7BFC-Di8RxhNL.js.gz +0 -0
  106. package/dist/client/assets/{erDiagram-RLTQ6QDP-CjdD0JCI.js → erDiagram-RLTQ6QDP-C1wPuBtH.js} +1 -1
  107. package/dist/client/assets/erDiagram-RLTQ6QDP-C1wPuBtH.js.br +0 -0
  108. package/dist/client/assets/erDiagram-RLTQ6QDP-C1wPuBtH.js.gz +0 -0
  109. package/dist/client/assets/{flowDiagram-HODETNUW-DKECYHVY.js → flowDiagram-HODETNUW-D0SIEpUy.js} +1 -1
  110. package/dist/client/assets/flowDiagram-HODETNUW-D0SIEpUy.js.br +0 -0
  111. package/dist/client/assets/flowDiagram-HODETNUW-D0SIEpUy.js.gz +0 -0
  112. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-BPCGT0Kd.js → ganttDiagram-EL5Y4UJY-DgeD2fKd.js} +1 -1
  113. package/dist/client/assets/ganttDiagram-EL5Y4UJY-DgeD2fKd.js.br +0 -0
  114. package/dist/client/assets/ganttDiagram-EL5Y4UJY-DgeD2fKd.js.gz +0 -0
  115. package/dist/client/assets/{gestureArbiter-DVPPQnKq.js → gestureArbiter-Xl7awIrX.js} +1 -1
  116. package/dist/client/assets/gestureArbiter-Xl7awIrX.js.br +0 -0
  117. package/dist/client/assets/gestureArbiter-Xl7awIrX.js.gz +0 -0
  118. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-DFCvVJ6L.js → gitGraphDiagram-WWUBYQGX-CzFKSKK_.js} +1 -1
  119. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-CzFKSKK_.js.br +0 -0
  120. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-CzFKSKK_.js.gz +0 -0
  121. package/dist/client/assets/index-BObjbh2R.css +1 -0
  122. package/dist/client/assets/index-BObjbh2R.css.br +0 -0
  123. package/dist/client/assets/{index-CSp4mPGE.css.gz → index-BObjbh2R.css.gz} +0 -0
  124. package/dist/client/assets/{infoDiagram-27XIBGKW-BTL8-sSN.js → infoDiagram-27XIBGKW-C9mmJGhv.js} +1 -1
  125. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-Xtc0AfGK.js → ishikawaDiagram-5VMMS53U-D9uVb4Og.js} +1 -1
  126. package/dist/client/assets/ishikawaDiagram-5VMMS53U-D9uVb4Og.js.br +0 -0
  127. package/dist/client/assets/ishikawaDiagram-5VMMS53U-D9uVb4Og.js.gz +0 -0
  128. package/dist/client/assets/{journeyDiagram-3NMN7TZE-BLtTDKtV.js → journeyDiagram-3NMN7TZE-BMKNUyUx.js} +1 -1
  129. package/dist/client/assets/journeyDiagram-3NMN7TZE-BMKNUyUx.js.br +0 -0
  130. package/dist/client/assets/journeyDiagram-3NMN7TZE-BMKNUyUx.js.gz +0 -0
  131. package/dist/client/assets/{kanban-definition-UXKFOSKX-C65azoTU.js → kanban-definition-UXKFOSKX-8i7nyqix.js} +1 -1
  132. package/dist/client/assets/kanban-definition-UXKFOSKX-8i7nyqix.js.br +0 -0
  133. package/dist/client/assets/kanban-definition-UXKFOSKX-8i7nyqix.js.gz +0 -0
  134. package/dist/client/assets/{layout-TEicKqeV.js → layout-BS5SCHbc.js} +1 -1
  135. package/dist/client/assets/layout-BS5SCHbc.js.br +0 -0
  136. package/dist/client/assets/layout-BS5SCHbc.js.gz +0 -0
  137. package/dist/client/assets/{linear-DQSikGMo.js → linear-fo2zkK6T.js} +1 -1
  138. package/dist/client/assets/linear-fo2zkK6T.js.br +0 -0
  139. package/dist/client/assets/linear-fo2zkK6T.js.gz +0 -0
  140. package/dist/client/assets/{mermaid.core-vZB1UnWX.js → mermaid.core-B8k3pAmc.js} +5 -5
  141. package/dist/client/assets/mermaid.core-B8k3pAmc.js.br +0 -0
  142. package/dist/client/assets/mermaid.core-B8k3pAmc.js.gz +0 -0
  143. package/dist/client/assets/{mindmap-definition-YA3MSWOX-B-coBapV.js → mindmap-definition-YA3MSWOX-BwgQTj2Q.js} +1 -1
  144. package/dist/client/assets/mindmap-definition-YA3MSWOX-BwgQTj2Q.js.br +0 -0
  145. package/dist/client/assets/mindmap-definition-YA3MSWOX-BwgQTj2Q.js.gz +0 -0
  146. package/dist/client/assets/{passwordBootstrap-LSQpoVpD.js → passwordBootstrap-DvQk0qYt.js} +1 -1
  147. package/dist/client/assets/passwordBootstrap-DvQk0qYt.js.br +0 -0
  148. package/dist/client/assets/passwordBootstrap-DvQk0qYt.js.gz +0 -0
  149. package/dist/client/assets/{pegDiagram-XKGWAZYB--jWB5n1V.js → pegDiagram-XKGWAZYB-CumSoxLr.js} +1 -1
  150. package/dist/client/assets/pegDiagram-XKGWAZYB-CumSoxLr.js.br +0 -0
  151. package/dist/client/assets/pegDiagram-XKGWAZYB-CumSoxLr.js.gz +0 -0
  152. package/dist/client/assets/{pieDiagram-E7YTZNPT-DmAqsAUK.js → pieDiagram-E7YTZNPT-Dc3txkBL.js} +1 -1
  153. package/dist/client/assets/pieDiagram-E7YTZNPT-Dc3txkBL.js.br +0 -0
  154. package/dist/client/assets/pieDiagram-E7YTZNPT-Dc3txkBL.js.gz +0 -0
  155. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-CqsfUApA.js → quadrantDiagram-AXDQQJYC-D92mwZnT.js} +1 -1
  156. package/dist/client/assets/quadrantDiagram-AXDQQJYC-D92mwZnT.js.br +0 -0
  157. package/dist/client/assets/quadrantDiagram-AXDQQJYC-D92mwZnT.js.gz +0 -0
  158. package/dist/client/assets/{railroadDiagram-O6MQD6OU-CzvYijD5.js → railroadDiagram-O6MQD6OU-O1UOZ30Y.js} +1 -1
  159. package/dist/client/assets/railroadDiagram-O6MQD6OU-O1UOZ30Y.js.br +0 -0
  160. package/dist/client/assets/railroadDiagram-O6MQD6OU-O1UOZ30Y.js.gz +0 -0
  161. package/dist/client/assets/{rdpSession-DGvDRc95.js → rdpSession-Dr_tPwzx.js} +1 -1
  162. package/dist/client/assets/rdpSession-Dr_tPwzx.js.br +0 -0
  163. package/dist/client/assets/rdpSession-Dr_tPwzx.js.gz +0 -0
  164. package/dist/client/assets/{referenceLongPress-BwP_B3l2.js → referenceLongPress-YuGU-PYw.js} +1 -1
  165. package/dist/client/assets/referenceLongPress-YuGU-PYw.js.br +0 -0
  166. package/dist/client/assets/referenceLongPress-YuGU-PYw.js.gz +0 -0
  167. package/dist/client/assets/{requirementDiagram-BXWQKSXE-E2FSO_hc.js → requirementDiagram-BXWQKSXE-uD1cgrxA.js} +1 -1
  168. package/dist/client/assets/requirementDiagram-BXWQKSXE-uD1cgrxA.js.br +0 -0
  169. package/dist/client/assets/requirementDiagram-BXWQKSXE-uD1cgrxA.js.gz +0 -0
  170. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-uSCR6gDg.js → sankeyDiagram-P5KCCOFB-CIJE4-pc.js} +1 -1
  171. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CIJE4-pc.js.br +0 -0
  172. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CIJE4-pc.js.gz +0 -0
  173. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-BqxdP03l.js → sequenceDiagram-WJ2MYXX4-BT6LG37W.js} +1 -1
  174. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BT6LG37W.js.br +0 -0
  175. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BT6LG37W.js.gz +0 -0
  176. package/dist/client/assets/{sizeCapture-INFHLROL-B7GSZxIt.js → sizeCapture-INFHLROL-DoYY94Rj.js} +1 -1
  177. package/dist/client/assets/sizeCapture-INFHLROL-DoYY94Rj.js.br +0 -0
  178. package/dist/client/assets/sizeCapture-INFHLROL-DoYY94Rj.js.gz +0 -0
  179. package/dist/client/assets/{sparkles-DBVpVoIl.js → sparkles-DFYGpezN.js} +1 -1
  180. package/dist/client/assets/{stateDiagram-D77RDMKH-DJ9UpQL9.js → stateDiagram-D77RDMKH-C4xmgR_-.js} +1 -1
  181. package/dist/client/assets/stateDiagram-D77RDMKH-C4xmgR_-.js.br +0 -0
  182. package/dist/client/assets/stateDiagram-D77RDMKH-C4xmgR_-.js.gz +0 -0
  183. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BLHH60cg.js +1 -0
  184. package/dist/client/assets/{swimlanes-42K2YHIH-B6f_z8xv.js → swimlanes-42K2YHIH-mRdmZmAA.js} +1 -1
  185. package/dist/client/assets/swimlanes-42K2YHIH-mRdmZmAA.js.br +0 -0
  186. package/dist/client/assets/swimlanes-42K2YHIH-mRdmZmAA.js.gz +0 -0
  187. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-D-lNPW5d.js +8 -0
  188. package/dist/client/assets/{timeline-definition-24CTP7MA-CMNs0nui.js → timeline-definition-24CTP7MA-BFFrD5kR.js} +1 -1
  189. package/dist/client/assets/timeline-definition-24CTP7MA-BFFrD5kR.js.br +0 -0
  190. package/dist/client/assets/timeline-definition-24CTP7MA-BFFrD5kR.js.gz +0 -0
  191. package/dist/client/assets/{triangle-alert-CN3m1g76.js → triangle-alert-BwJ6Q_Y0.js} +1 -1
  192. package/dist/client/assets/{vennDiagram-4TSXK5OY-B2glpBlo.js → vennDiagram-4TSXK5OY-Dy59OxIM.js} +1 -1
  193. package/dist/client/assets/vennDiagram-4TSXK5OY-Dy59OxIM.js.br +0 -0
  194. package/dist/client/assets/vennDiagram-4TSXK5OY-Dy59OxIM.js.gz +0 -0
  195. package/dist/client/assets/{videoCompression-DwronsgA.js → videoCompression-DrQ47oZA.js} +1 -1
  196. package/dist/client/assets/videoCompression-DrQ47oZA.js.br +0 -0
  197. package/dist/client/assets/videoCompression-DrQ47oZA.js.gz +0 -0
  198. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-DyMNl-ZC.js → wardleyDiagram-VM6X3IG4-B-BKlX7o.js} +1 -1
  199. package/dist/client/assets/wardleyDiagram-VM6X3IG4-B-BKlX7o.js.br +0 -0
  200. package/dist/client/assets/wardleyDiagram-VM6X3IG4-B-BKlX7o.js.gz +0 -0
  201. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DhZFXjY5.js → xychartDiagram-S5SC5T6Z-79qktI_4.js} +1 -1
  202. package/dist/client/assets/xychartDiagram-S5SC5T6Z-79qktI_4.js.br +0 -0
  203. package/dist/client/assets/xychartDiagram-S5SC5T6Z-79qktI_4.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.js +1 -1
  208. package/dist/client/sw.js.br +0 -0
  209. package/dist/client/sw.js.gz +0 -0
  210. package/dist/server/agent/collaborationCli.js +17 -7
  211. package/dist/server/agent/integrationCli.js +9 -2
  212. package/dist/server/agent/integrationServer.js +12 -0
  213. package/dist/server/agent/integrationSessions.js +197 -3
  214. package/dist/server/agent/integrationStore.js +1 -1
  215. package/dist/server/agent/sessionLifecycle.js +4 -0
  216. package/dist/server/agent/sessionManagement.js +87 -0
  217. package/dist/server/routes/terminal.js +129 -3
  218. package/dist/server/utils/settings.js +14 -0
  219. package/docs/integrations.md +110 -0
  220. package/package.json +1 -1
  221. package/runtime-manifest.json +3 -3
  222. package/dist/client/assets/App-BCTGnwU1.js.br +0 -0
  223. package/dist/client/assets/App-BCTGnwU1.js.gz +0 -0
  224. package/dist/client/assets/ArchitecturePanel-CVTIYbyj.js.br +0 -0
  225. package/dist/client/assets/ArchitecturePanel-CVTIYbyj.js.gz +0 -0
  226. package/dist/client/assets/ChangeWalkthroughPanel-BKsuofw6.js.br +0 -0
  227. package/dist/client/assets/ChangeWalkthroughPanel-BKsuofw6.js.gz +0 -0
  228. package/dist/client/assets/CollaborationMainWorkspace-DZ0qwLUz.js.br +0 -0
  229. package/dist/client/assets/CollaborationMainWorkspace-DZ0qwLUz.js.gz +0 -0
  230. package/dist/client/assets/CollaborationTaskContent-BLQNknOq.js +0 -2
  231. package/dist/client/assets/ComputerControlView-DN6cXOnb.js +0 -5
  232. package/dist/client/assets/ComputerControlView-DN6cXOnb.js.br +0 -0
  233. package/dist/client/assets/ComputerControlView-DN6cXOnb.js.gz +0 -0
  234. package/dist/client/assets/DagPlayground-ZgszT1TH.js.br +0 -0
  235. package/dist/client/assets/DagPlayground-ZgszT1TH.js.gz +0 -0
  236. package/dist/client/assets/DiffLab-D_9U-zfZ.js.br +0 -0
  237. package/dist/client/assets/DiffLab-D_9U-zfZ.js.gz +0 -0
  238. package/dist/client/assets/DiffReview-8Pfe_BNO.js.br +0 -0
  239. package/dist/client/assets/DiffReview-8Pfe_BNO.js.gz +0 -0
  240. package/dist/client/assets/DiffReviewLab-p3ZSl0P2.js.br +0 -0
  241. package/dist/client/assets/DiffReviewLab-p3ZSl0P2.js.gz +0 -0
  242. package/dist/client/assets/DiffViewer-Cz64sLJT.js.br +0 -0
  243. package/dist/client/assets/DiffViewer-Cz64sLJT.js.gz +0 -0
  244. package/dist/client/assets/ModelPreview-B28x060d.js.br +0 -0
  245. package/dist/client/assets/ModelPreview-B28x060d.js.gz +0 -0
  246. package/dist/client/assets/RightSidebar-SIqDjggD.js.br +0 -0
  247. package/dist/client/assets/RightSidebar-SIqDjggD.js.gz +0 -0
  248. package/dist/client/assets/abnfDiagram-VCTEODGH--t0bQKCQ.js.br +0 -0
  249. package/dist/client/assets/abnfDiagram-VCTEODGH--t0bQKCQ.js.gz +0 -0
  250. package/dist/client/assets/app-DWidKLU2.js.br +0 -0
  251. package/dist/client/assets/app-DWidKLU2.js.gz +0 -0
  252. package/dist/client/assets/arc-DMWsmL7t.js.br +0 -0
  253. package/dist/client/assets/arc-DMWsmL7t.js.gz +0 -0
  254. package/dist/client/assets/architectureDiagram-5GKGNRK7-BYkvSKnR.js.br +0 -0
  255. package/dist/client/assets/architectureDiagram-5GKGNRK7-BYkvSKnR.js.gz +0 -0
  256. package/dist/client/assets/blockDiagram-I7D4REHJ-B574d9TS.js.br +0 -0
  257. package/dist/client/assets/blockDiagram-I7D4REHJ-B574d9TS.js.gz +0 -0
  258. package/dist/client/assets/c4Diagram-7LVT6UL2-D__CwUct.js.gz +0 -0
  259. package/dist/client/assets/channel-BonXK9tr.js +0 -1
  260. package/dist/client/assets/chunk-F27PBJKO-DeClqFBe.js.br +0 -0
  261. package/dist/client/assets/chunk-F27PBJKO-DeClqFBe.js.gz +0 -0
  262. package/dist/client/assets/chunk-IMKFNOWR-DBRCslkn.js.br +0 -0
  263. package/dist/client/assets/chunk-IMKFNOWR-DBRCslkn.js.gz +0 -0
  264. package/dist/client/assets/chunk-SVP7TREG-BdxOWBjP.js.br +0 -0
  265. package/dist/client/assets/chunk-SVP7TREG-BdxOWBjP.js.gz +0 -0
  266. package/dist/client/assets/chunk-TICWLB2K-BtNXehgz.js.br +0 -0
  267. package/dist/client/assets/chunk-TICWLB2K-BtNXehgz.js.gz +0 -0
  268. package/dist/client/assets/classDiagram-ZZMXUADV-CXO_pgVP.js +0 -1
  269. package/dist/client/assets/classDiagram-v2-VYDZK3BY-CXO_pgVP.js +0 -1
  270. package/dist/client/assets/cose-bilkent-JH36ORCC-Buod2YZ0.js.br +0 -0
  271. package/dist/client/assets/cose-bilkent-JH36ORCC-Buod2YZ0.js.gz +0 -0
  272. package/dist/client/assets/cynefin-OW5HDTMX-i2eiybdj.js.br +0 -0
  273. package/dist/client/assets/cynefin-OW5HDTMX-i2eiybdj.js.gz +0 -0
  274. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-D_YF2Yi3.js.br +0 -0
  275. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-D_YF2Yi3.js.gz +0 -0
  276. package/dist/client/assets/dagre-GXQ25YYZ-CfLEvt7Z.js.br +0 -0
  277. package/dist/client/assets/dagre-GXQ25YYZ-CfLEvt7Z.js.gz +0 -0
  278. package/dist/client/assets/diagram-S7CK7UJ4-BV0Wackt.js.br +0 -0
  279. package/dist/client/assets/diagram-S7CK7UJ4-BV0Wackt.js.gz +0 -0
  280. package/dist/client/assets/diagram-UQ7AKVKN-jwaoLY_P.js.br +0 -0
  281. package/dist/client/assets/diagram-UQ7AKVKN-jwaoLY_P.js.gz +0 -0
  282. package/dist/client/assets/diagram-VSXAHHWV-CuAFyl0n.js.br +0 -0
  283. package/dist/client/assets/diagram-VSXAHHWV-CuAFyl0n.js.gz +0 -0
  284. package/dist/client/assets/diagram-VX7I27RA-bbmA7rRk.js.br +0 -0
  285. package/dist/client/assets/diagram-VX7I27RA-bbmA7rRk.js.gz +0 -0
  286. package/dist/client/assets/diagram-Z3DM3KII-CX3-Mxwo.js.br +0 -0
  287. package/dist/client/assets/diagram-Z3DM3KII-CX3-Mxwo.js.gz +0 -0
  288. package/dist/client/assets/ebnfDiagram-PWID7BFC-Pkq6omzy.js.br +0 -0
  289. package/dist/client/assets/ebnfDiagram-PWID7BFC-Pkq6omzy.js.gz +0 -0
  290. package/dist/client/assets/erDiagram-RLTQ6QDP-CjdD0JCI.js.br +0 -0
  291. package/dist/client/assets/erDiagram-RLTQ6QDP-CjdD0JCI.js.gz +0 -0
  292. package/dist/client/assets/flowDiagram-HODETNUW-DKECYHVY.js.br +0 -0
  293. package/dist/client/assets/flowDiagram-HODETNUW-DKECYHVY.js.gz +0 -0
  294. package/dist/client/assets/ganttDiagram-EL5Y4UJY-BPCGT0Kd.js.br +0 -0
  295. package/dist/client/assets/ganttDiagram-EL5Y4UJY-BPCGT0Kd.js.gz +0 -0
  296. package/dist/client/assets/gestureArbiter-DVPPQnKq.js.br +0 -0
  297. package/dist/client/assets/gestureArbiter-DVPPQnKq.js.gz +0 -0
  298. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DFCvVJ6L.js.br +0 -0
  299. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DFCvVJ6L.js.gz +0 -0
  300. package/dist/client/assets/index-CSp4mPGE.css +0 -1
  301. package/dist/client/assets/index-CSp4mPGE.css.br +0 -0
  302. package/dist/client/assets/ishikawaDiagram-5VMMS53U-Xtc0AfGK.js.br +0 -0
  303. package/dist/client/assets/ishikawaDiagram-5VMMS53U-Xtc0AfGK.js.gz +0 -0
  304. package/dist/client/assets/journeyDiagram-3NMN7TZE-BLtTDKtV.js.br +0 -0
  305. package/dist/client/assets/journeyDiagram-3NMN7TZE-BLtTDKtV.js.gz +0 -0
  306. package/dist/client/assets/kanban-definition-UXKFOSKX-C65azoTU.js.br +0 -0
  307. package/dist/client/assets/kanban-definition-UXKFOSKX-C65azoTU.js.gz +0 -0
  308. package/dist/client/assets/layout-TEicKqeV.js.br +0 -0
  309. package/dist/client/assets/layout-TEicKqeV.js.gz +0 -0
  310. package/dist/client/assets/linear-DQSikGMo.js.br +0 -0
  311. package/dist/client/assets/linear-DQSikGMo.js.gz +0 -0
  312. package/dist/client/assets/mermaid.core-vZB1UnWX.js.br +0 -0
  313. package/dist/client/assets/mermaid.core-vZB1UnWX.js.gz +0 -0
  314. package/dist/client/assets/mindmap-definition-YA3MSWOX-B-coBapV.js.br +0 -0
  315. package/dist/client/assets/mindmap-definition-YA3MSWOX-B-coBapV.js.gz +0 -0
  316. package/dist/client/assets/passwordBootstrap-LSQpoVpD.js.br +0 -0
  317. package/dist/client/assets/passwordBootstrap-LSQpoVpD.js.gz +0 -0
  318. package/dist/client/assets/pegDiagram-XKGWAZYB--jWB5n1V.js.br +0 -0
  319. package/dist/client/assets/pegDiagram-XKGWAZYB--jWB5n1V.js.gz +0 -0
  320. package/dist/client/assets/pieDiagram-E7YTZNPT-DmAqsAUK.js.br +0 -0
  321. package/dist/client/assets/pieDiagram-E7YTZNPT-DmAqsAUK.js.gz +0 -0
  322. package/dist/client/assets/quadrantDiagram-AXDQQJYC-CqsfUApA.js.br +0 -0
  323. package/dist/client/assets/quadrantDiagram-AXDQQJYC-CqsfUApA.js.gz +0 -0
  324. package/dist/client/assets/railroadDiagram-O6MQD6OU-CzvYijD5.js.br +0 -0
  325. package/dist/client/assets/railroadDiagram-O6MQD6OU-CzvYijD5.js.gz +0 -0
  326. package/dist/client/assets/rdpSession-DGvDRc95.js.br +0 -0
  327. package/dist/client/assets/rdpSession-DGvDRc95.js.gz +0 -0
  328. package/dist/client/assets/referenceLongPress-BwP_B3l2.js.br +0 -0
  329. package/dist/client/assets/referenceLongPress-BwP_B3l2.js.gz +0 -0
  330. package/dist/client/assets/requirementDiagram-BXWQKSXE-E2FSO_hc.js.br +0 -0
  331. package/dist/client/assets/requirementDiagram-BXWQKSXE-E2FSO_hc.js.gz +0 -0
  332. package/dist/client/assets/sankeyDiagram-P5KCCOFB-uSCR6gDg.js.br +0 -0
  333. package/dist/client/assets/sankeyDiagram-P5KCCOFB-uSCR6gDg.js.gz +0 -0
  334. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BqxdP03l.js.br +0 -0
  335. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BqxdP03l.js.gz +0 -0
  336. package/dist/client/assets/sizeCapture-INFHLROL-B7GSZxIt.js.br +0 -0
  337. package/dist/client/assets/sizeCapture-INFHLROL-B7GSZxIt.js.gz +0 -0
  338. package/dist/client/assets/stateDiagram-D77RDMKH-DJ9UpQL9.js.br +0 -0
  339. package/dist/client/assets/stateDiagram-D77RDMKH-DJ9UpQL9.js.gz +0 -0
  340. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-P9vVPNJW.js +0 -1
  341. package/dist/client/assets/swimlanes-42K2YHIH-B6f_z8xv.js.br +0 -0
  342. package/dist/client/assets/swimlanes-42K2YHIH-B6f_z8xv.js.gz +0 -0
  343. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-Deucv-sT.js +0 -8
  344. package/dist/client/assets/timeline-definition-24CTP7MA-CMNs0nui.js.br +0 -0
  345. package/dist/client/assets/timeline-definition-24CTP7MA-CMNs0nui.js.gz +0 -0
  346. package/dist/client/assets/vennDiagram-4TSXK5OY-B2glpBlo.js.br +0 -0
  347. package/dist/client/assets/vennDiagram-4TSXK5OY-B2glpBlo.js.gz +0 -0
  348. package/dist/client/assets/videoCompression-DwronsgA.js.br +0 -0
  349. package/dist/client/assets/videoCompression-DwronsgA.js.gz +0 -0
  350. package/dist/client/assets/wardleyDiagram-VM6X3IG4-DyMNl-ZC.js.br +0 -0
  351. package/dist/client/assets/wardleyDiagram-VM6X3IG4-DyMNl-ZC.js.gz +0 -0
  352. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DhZFXjY5.js.br +0 -0
  353. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DhZFXjY5.js.gz +0 -0
@@ -1,4 +1,5 @@
1
1
  import fs from 'node:fs';
2
+ import { cleanMemberName } from './collaborationRoutes.js';
2
3
  import path from 'node:path';
3
4
  import { createHash, randomBytes, randomUUID } from 'node:crypto';
4
5
  import { atomicJson, integrationError } from './integrationStore.js';
@@ -22,8 +23,8 @@ function startupInput(record, now) {
22
23
  return condition ? { state: 'pending', deadline: now + (condition.timeoutMs ?? 120000), matched_since: null, observed_at: null } : undefined;
23
24
  }
24
25
  export function publicIntegrationSession(record) {
25
- const { profile: _, deadline: _deadline, launch_submitted: _submitted, startup_condition: _condition, restore_diagnostics: diagnostics, launch_diagnostics: launchDiagnostics, launch_diagnostics_history: _history, message_history_seen: _messages, ...publicRecord } = record;
26
- return { ...publicRecord, ...(diagnostics ? { restore_diagnostics_available: true } : {}),
26
+ const { profile: _, deadline: _deadline, launch_submitted: _submitted, startup_condition: _condition, restore_diagnostics: diagnostics, launch_diagnostics: launchDiagnostics, launch_diagnostics_history: _history, message_history_seen: _messages, close_intent: _closeIntent, ...publicRecord } = record;
27
+ return { ...publicRecord, close_pending: !!_closeIntent, ...(diagnostics ? { restore_diagnostics_available: true } : {}),
27
28
  ...(launchDiagnostics ? { launch_diagnostics_available: true } : {}) };
28
29
  }
29
30
  export function permittedCwd(profile, cwd) {
@@ -60,6 +61,7 @@ export class IntegrationSessions {
60
61
  lifecycle = new SessionLifecycleCoordinator();
61
62
  mutations = new Map();
62
63
  coldRetries = new Set();
64
+ closingOperations = new Set();
63
65
  timers = new Set();
64
66
  stopObservation;
65
67
  stopDeliveryGuard;
@@ -84,7 +86,7 @@ export class IntegrationSessions {
84
86
  record.runtime_present ??= null;
85
87
  }
86
88
  for (const record of this.doc.sessions)
87
- if (['starting', 'restoring', 'binding_pending'].includes(record.state) || record.state === 'releasing' || record.startup_input?.state === 'pending')
89
+ if (['starting', 'restoring', 'binding_pending'].includes(record.state) || ['releasing', 'closing'].includes(record.state) || record.startup_input?.state === 'pending')
88
90
  this.scheduleRefresh(record);
89
91
  // A pre-restart partial match cannot prove continuity of the live screen.
90
92
  for (const record of this.doc.sessions)
@@ -245,8 +247,14 @@ export class IntegrationSessions {
245
247
  }
246
248
  assertRuntimeMessage(id) {
247
249
  const record = this.doc.sessions.find(s => s.session_id === id);
250
+ if (this.closingOperations.has(id))
251
+ integrationError('SESSION_OPERATION_IN_PROGRESS', 'Session close preflight is in progress', 409);
248
252
  if (this.coldRetries.has(id) || record?.cold_retry_pending)
249
253
  integrationError('SESSION_OPERATION_IN_PROGRESS', 'Cold retry must finish or be reconciled before sending', 409);
254
+ if (record?.state === 'closing' && !record.operation_uncertain)
255
+ integrationError('SESSION_OPERATION_IN_PROGRESS', 'Session close is in progress', 409);
256
+ if (record?.close_intent)
257
+ integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Close outcome requires reconciliation', 409);
250
258
  assertMessageRuntime(record);
251
259
  // Durable, conservative latch before admission; even a later enqueue
252
260
  // failure cannot make a previously attempted business request disappear.
@@ -301,6 +309,7 @@ export class IntegrationSessions {
301
309
  const request = this.request(principal, key, ['retry-cold', id, generation]);
302
310
  if (request.previous)
303
311
  return this.replayRequest(principal, id, request.previous);
312
+ this.assertManagementSettled(this.lookup(principal, id));
304
313
  if (!this.adapter.retryCold || !this.adapter.messageHistory)
305
314
  integrationError('SESSION_COLD_RETRY_UNSUPPORTED', 'Runtime adapter does not support verified cold retry', 409);
306
315
  if (this.pending.has(id))
@@ -308,6 +317,7 @@ export class IntegrationSessions {
308
317
  this.coldRetries.add(id);
309
318
  try {
310
319
  const record = await this.get(principal, id);
320
+ this.assertManagementSettled(record);
311
321
  assertReleaseGeneration(record, generation);
312
322
  if (record.cold_retry_pending || record.operation_uncertain)
313
323
  integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Reconcile prior lifecycle outcome before cold retry', 409);
@@ -373,6 +383,7 @@ export class IntegrationSessions {
373
383
  let releaseNative;
374
384
  try {
375
385
  const record = await this.get(principal, id);
386
+ this.assertManagementSettled(record);
376
387
  if (record.cold_retry_pending)
377
388
  integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Reconcile the cold retry before native restore', 409);
378
389
  if (!record.agent_native_session_id)
@@ -448,6 +459,7 @@ export class IntegrationSessions {
448
459
  const record = structuredClone(this.doc.sessions.find(s => s.session_id === id));
449
460
  if (!record)
450
461
  return integrationError('INTEGRATION_SESSION_NOT_FOUND', 'Recovery record does not exist', 404);
462
+ this.assertManagementSettled(record);
451
463
  assertReleaseGeneration(record, generation);
452
464
  if (this.pending.has(id) || record.operation_uncertain || ['starting', 'restoring', 'binding_pending', 'releasing'].includes(record.state)) {
453
465
  integrationError('SESSION_OPERATION_IN_PROGRESS', 'Resolve the current lifecycle operation before clearing startup input conditions', 409);
@@ -469,6 +481,7 @@ export class IntegrationSessions {
469
481
  const record = structuredClone(this.doc.sessions.find(s => s.session_id === id));
470
482
  if (!record)
471
483
  return integrationError('INTEGRATION_SESSION_NOT_FOUND', 'Recovery record does not exist', 404);
484
+ this.assertManagementSettled(record);
472
485
  assertReleaseGeneration(record, generation);
473
486
  if (this.pending.has(id) || ['starting', 'restoring', 'binding_pending', 'releasing'].includes(record.state))
474
487
  integrationError('SESSION_OPERATION_IN_PROGRESS', 'Resolve the current operation before confirming compatibility', 409);
@@ -481,16 +494,145 @@ export class IntegrationSessions {
481
494
  return record;
482
495
  });
483
496
  }
497
+ assertManagementSettled(record) {
498
+ if (record.state === 'closed')
499
+ integrationError('SESSION_CLOSED', 'Explicitly closed sessions cannot be restored or restarted', 409);
500
+ if (record.state === 'closing' && !record.operation_uncertain)
501
+ integrationError('SESSION_OPERATION_IN_PROGRESS', 'Session close is in progress', 409);
502
+ if (record.close_intent || record.state === 'closing')
503
+ integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Reconcile the pending close before any lifecycle operation', 409);
504
+ if (record.rename_pending)
505
+ integrationError('SESSION_RENAME_SYNC_PENDING', 'Read session get to reconcile the pending name update', 409);
506
+ }
507
+ assertManagementIdle(record) {
508
+ if (this.pending.has(record.session_id) || record.cold_retry_pending || record.operation_uncertain || ['starting', 'restoring', 'binding_pending', 'releasing', 'closing'].includes(record.state)) {
509
+ integrationError('SESSION_OPERATION_IN_PROGRESS', 'Resolve the current lifecycle operation first', 409);
510
+ }
511
+ }
512
+ async rename(principal, id, generation, value, key) {
513
+ if (typeof value !== 'string')
514
+ integrationError('INVALID_NAME', 'name must be non-empty text up to 80 characters');
515
+ const name = cleanMemberName(value);
516
+ if (!name)
517
+ integrationError('INVALID_NAME', 'name must be non-empty text up to 80 characters');
518
+ return this.mutate(principal, key, ['rename', id, generation, name], () => this.lifecycle.run(id, async () => {
519
+ const request = this.request(principal, key, ['rename', id, generation, name]);
520
+ if (request.previous)
521
+ return this.replayRequest(principal, id, request.previous);
522
+ if (!this.adapter.rename)
523
+ integrationError('SESSION_RENAME_UNSUPPORTED', 'Runtime adapter does not support renaming', 409);
524
+ const record = await this.get(principal, id);
525
+ assertReleaseGeneration(record, generation);
526
+ if (record.close_intent || record.rename_pending)
527
+ integrationError('SESSION_OPERATION_IN_PROGRESS', 'Resolve the pending management operation first', 409);
528
+ this.assertManagementIdle(record);
529
+ await this.adapter.prepareRename?.(record);
530
+ record.name = name;
531
+ record.name_updated_at = Date.now();
532
+ record.updated_at = record.name_updated_at;
533
+ record.generation = generation + 1;
534
+ record.name_generation = record.generation;
535
+ record.name_operation_id = record.operation_id;
536
+ record.rename_pending = true;
537
+ this.doc.requests[request.scoped] = { hash: request.hash, sessionId: id, operationId: record.operation_id, generation: record.generation };
538
+ try {
539
+ this.saveRecord(record);
540
+ }
541
+ catch (error) {
542
+ delete this.doc.requests[request.scoped];
543
+ throw error;
544
+ }
545
+ try {
546
+ await this.adapter.rename(record);
547
+ record.rename_pending = false;
548
+ this.saveRecord(record);
549
+ }
550
+ catch { /* Durable intent is retried by get/restart; no runtime is created. */ }
551
+ return this.lookup(principal, id);
552
+ }));
553
+ }
554
+ async closeSession(principal, id, generation, key) {
555
+ return this.mutate(principal, key, ['close', id, generation], () => this.lifecycle.run(id, async () => {
556
+ const request = this.request(principal, key, ['close', id, generation]);
557
+ if (request.previous)
558
+ return this.replayRequest(principal, id, request.previous);
559
+ this.closingOperations.add(id);
560
+ try {
561
+ if (!this.adapter.prepareClose || !this.adapter.closeRuntime || !this.adapter.runtimePresent)
562
+ integrationError('SESSION_CLOSE_UNSUPPORTED', 'Runtime adapter does not support closing', 409);
563
+ const record = await this.get(principal, id);
564
+ assertReleaseGeneration(record, generation);
565
+ if (record.close_intent || record.rename_pending)
566
+ integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Read session get to reconcile prior management intent', 409);
567
+ this.assertManagementIdle(record);
568
+ if (record.state === 'closed') {
569
+ if (await this.adapter.runtimePresent(record))
570
+ integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Unexpected runtime exists for a closed record', 409);
571
+ this.doc.requests[request.scoped] = { hash: request.hash, sessionId: id, operationId: record.operation_id, generation: record.generation };
572
+ try {
573
+ this.save();
574
+ }
575
+ catch (error) {
576
+ delete this.doc.requests[request.scoped];
577
+ throw error;
578
+ }
579
+ return record;
580
+ }
581
+ if (this.adapter.pendingMessages?.(id))
582
+ integrationError('SESSION_PENDING_MESSAGES', 'Pending messages must be resolved before closing', 409);
583
+ const target = await this.adapter.prepareClose(record);
584
+ record.operation_id = randomUUID();
585
+ record.generation = generation + 1;
586
+ record.state = 'closing';
587
+ record.close_intent = { operation_id: record.operation_id, target };
588
+ record.error_code = null;
589
+ record.operation_uncertain = false;
590
+ record.updated_at = Date.now();
591
+ this.doc.requests[request.scoped] = { hash: request.hash, sessionId: id, operationId: record.operation_id, generation: record.generation };
592
+ try {
593
+ this.saveRecord(record);
594
+ }
595
+ catch (error) {
596
+ delete this.doc.requests[request.scoped];
597
+ throw error;
598
+ }
599
+ try {
600
+ await this.adapter.closeRuntime(record, false);
601
+ if (await this.adapter.runtimePresent(record))
602
+ integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Runtime removal cannot be confirmed', 409);
603
+ record.state = 'closed';
604
+ record.runtime_present = false;
605
+ record.terminal_binding = null;
606
+ record.startup_input = undefined;
607
+ record.close_intent = undefined;
608
+ }
609
+ catch (error) {
610
+ record.state = 'failed';
611
+ record.operation_uncertain = true;
612
+ record.runtime_present = null;
613
+ record.error_code = typeof error.code === 'string' ? error.code : 'SESSION_CLOSE_FAILED';
614
+ }
615
+ record.updated_at = Date.now();
616
+ this.saveRecord(record);
617
+ return record;
618
+ }
619
+ finally {
620
+ this.closingOperations.delete(id);
621
+ }
622
+ }));
623
+ }
484
624
  async release(principal, id, generation, key) {
485
625
  return this.mutate(principal, key, ['release', id, generation], () => this.lifecycle.run(id, async () => {
486
626
  const request = this.request(principal, key, ['release', id, generation]);
487
627
  if (request.previous)
488
628
  return this.replayRequest(principal, id, request.previous);
629
+ this.assertManagementSettled(this.lookup(principal, id));
489
630
  if (!this.adapter.release || !this.adapter.runtimePresent)
490
631
  integrationError('SESSION_RELEASE_UNSUPPORTED', 'Runtime adapter does not support release', 409);
491
632
  if (this.pending.has(id))
492
633
  integrationError('SESSION_OPERATION_IN_PROGRESS', 'Launch is in progress', 409);
493
634
  const record = await this.get(principal, id);
635
+ this.assertManagementSettled(record);
494
636
  assertReleaseGeneration(record, generation);
495
637
  if (record.state !== 'released') {
496
638
  assertReleaseFacts(record, await this.adapter.inspect(record));
@@ -552,6 +694,52 @@ export class IntegrationSessions {
552
694
  const record = structuredClone(this.doc.sessions.find(s => s.session_id === id));
553
695
  if (!record)
554
696
  return;
697
+ if (record.rename_pending) {
698
+ if (this.lifecycle.active(id))
699
+ return;
700
+ try {
701
+ await this.lifecycle.run(id, async () => {
702
+ if (!this.adapter.rename)
703
+ return;
704
+ await this.adapter.rename(record);
705
+ if (JSON.stringify(this.doc.sessions.find(s => s.session_id === id)) !== JSON.stringify(record))
706
+ return;
707
+ record.rename_pending = false;
708
+ this.saveRecord(record);
709
+ });
710
+ }
711
+ catch { /* Keep the persisted intent for a later get/restart. */ }
712
+ return;
713
+ }
714
+ if (record.state === 'closed' || record.state === 'closing' || record.close_intent) {
715
+ if (this.lifecycle.active(id))
716
+ return;
717
+ try {
718
+ if (record.state !== 'closed') {
719
+ if (!this.adapter.closeRuntime)
720
+ integrationError('SESSION_CLOSE_UNSUPPORTED', 'Close reconciliation is unavailable', 409);
721
+ await this.adapter.closeRuntime(record, true);
722
+ }
723
+ if (!this.adapter.runtimePresent || await this.adapter.runtimePresent(record))
724
+ integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Runtime exists for a closed or closing session', 409);
725
+ const next = { ...record, state: 'closed', runtime_present: false, terminal_binding: null, close_intent: undefined,
726
+ operation_uncertain: false, error_code: null, startup_input: undefined };
727
+ if (JSON.stringify(this.doc.sessions.find(s => s.session_id === id)) !== JSON.stringify(record))
728
+ return;
729
+ if (JSON.stringify(next) !== JSON.stringify(record))
730
+ this.saveRecord({ ...next, updated_at: Date.now() });
731
+ }
732
+ catch (error) {
733
+ if (JSON.stringify(this.doc.sessions.find(s => s.session_id === id)) !== JSON.stringify(record))
734
+ return;
735
+ // Keep closed terminal, and keep unresolved intent fenced. Never kill on refresh.
736
+ const next = { ...record, runtime_present: null, operation_uncertain: true,
737
+ error_code: typeof error.code === 'string' ? error.code : 'OPERATION_OUTCOME_UNCONFIRMED' };
738
+ if (JSON.stringify(next) !== JSON.stringify(record))
739
+ this.saveRecord({ ...next, updated_at: Date.now() });
740
+ }
741
+ return;
742
+ }
555
743
  if (record.cold_retry_pending && (this.lifecycle.active(id) || this.pending.has(id)))
556
744
  return;
557
745
  if (record.state === 'released' || record.state === 'releasing' || record.operation_uncertain) {
@@ -688,6 +876,12 @@ export class IntegrationSessions {
688
876
  const existing = this.doc.sessions.find(record => record.session_id === id);
689
877
  if (!existing)
690
878
  return null;
879
+ if (this.closingOperations.has(id))
880
+ return { allowed: false, reason: 'SESSION_OPERATION_IN_PROGRESS' };
881
+ if (existing.state === 'closed')
882
+ return { allowed: false, reason: 'SESSION_CLOSED' };
883
+ if (existing.close_intent || existing.state === 'closing')
884
+ return { allowed: false, reason: 'SESSION_OPERATION_IN_PROGRESS' };
691
885
  if (existing.state === 'released' || existing.state === 'releasing' || existing.operation_uncertain)
692
886
  return { allowed: false, reason: existing.state === 'released' ? 'SESSION_RELEASED' : 'SESSION_OPERATION_IN_PROGRESS' };
693
887
  if (!existing.startup_input)
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import { createHash, randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
4
4
  import { CollaborationError } from './collaborationProtocol.js';
5
5
  export const INTEGRATION_PROTOCOL = 1;
6
- export const INTEGRATION_OPERATIONS = ['message.send', 'message.read', 'task.read', 'task.create', 'task.configure', 'task.assign', 'task.comment', 'task.revise', 'task.answer', 'events.read', 'session.create', 'session.read', 'session.restore', 'session.release'];
6
+ export const INTEGRATION_OPERATIONS = ['message.send', 'message.read', 'task.read', 'task.create', 'task.configure', 'task.assign', 'task.comment', 'task.revise', 'task.answer', 'events.read', 'session.create', 'session.read', 'session.restore', 'session.release', 'session.rename', 'session.close'];
7
7
  export function integrationError(code, message, status = 400) { throw new CollaborationError(code, message, status); }
8
8
  export function atomicJson(file, value) {
9
9
  fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
@@ -50,6 +50,10 @@ export function assertReleaseFacts(record, facts) {
50
50
  export function assertMessageRuntime(record) {
51
51
  if (!record)
52
52
  return;
53
+ if (record.state === 'closed')
54
+ fail('SESSION_CLOSED', 'Session was explicitly closed; it cannot be sent to or restored');
55
+ if (record.state === 'closing')
56
+ fail('SESSION_OPERATION_IN_PROGRESS', 'Session close is in progress');
53
57
  if (record.state === 'released')
54
58
  fail('SESSION_RELEASED', 'Runtime was released; explicitly restore this session before sending');
55
59
  if (record.state === 'releasing')
@@ -0,0 +1,87 @@
1
+ import fs from 'node:fs/promises';
2
+ import { execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ import { CollaborationError } from './collaborationProtocol.js';
5
+ const fail = (code, message) => { throw new CollaborationError(code, message, 409); };
6
+ /** Read the live foreground process instance, not a historical PID. */
7
+ export async function foregroundProcessInstance(pid) {
8
+ if (!Number.isSafeInteger(pid) || pid < 1)
9
+ return fail('SESSION_CLOSE_TARGET_UNCONFIRMED', 'Foreground process is unavailable');
10
+ try {
11
+ if (process.platform === 'linux') {
12
+ const stat = await fs.readFile(`/proc/${pid}/stat`, 'utf8');
13
+ const fields = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\s+/);
14
+ if (fields[0] === 'Z' || Number(fields[2]) <= 0 || fields[2] !== fields[5] || !/^\d+$/.test(fields[19]))
15
+ throw new Error();
16
+ return `linux:${fields[19]}`;
17
+ }
18
+ if (process.platform === 'darwin') {
19
+ const { stdout } = await promisify(execFile)('ps', ['-p', String(pid), '-o', 'pgid=,tpgid=,stat=,lstart='], { timeout: 2000 });
20
+ const match = stdout.trim().match(/^(\d+)\s+(\d+)\s+(\S+)\s+(.+)$/);
21
+ if (!match || Number(match[1]) < 1 || match[1] !== match[2] || match[3].startsWith('Z'))
22
+ throw new Error();
23
+ return `darwin:${match[4]}`;
24
+ }
25
+ }
26
+ catch { /* Never fall back to PID existence. */ }
27
+ return fail('SESSION_CLOSE_TARGET_UNCONFIRMED', 'Current foreground process instance cannot be verified');
28
+ }
29
+ /** A missing PID is absence; inaccessible identity remains an error. */
30
+ export async function processStartIdentity(pid) {
31
+ if (process.platform === 'linux') {
32
+ try {
33
+ const stat = await fs.readFile(`/proc/${pid}/stat`, 'utf8');
34
+ const fields = stat.slice(stat.lastIndexOf(')') + 2).trim().split(/\s+/);
35
+ if (fields[0] === 'Z')
36
+ return null;
37
+ if (!/^\d+$/.test(fields[19]))
38
+ throw new Error();
39
+ return `linux:${fields[19]}`;
40
+ }
41
+ catch (error) {
42
+ if (error.code === 'ENOENT')
43
+ return null;
44
+ }
45
+ }
46
+ else if (process.platform === 'darwin') {
47
+ try {
48
+ const { stdout } = await promisify(execFile)('ps', ['-p', String(pid), '-o', 'stat=,lstart='], { timeout: 2000 });
49
+ const match = stdout.trim().match(/^(\S+)\s+(.+)$/);
50
+ if (match)
51
+ return match[1].startsWith('Z') ? null : `darwin:${match[2]}`;
52
+ }
53
+ catch {
54
+ try {
55
+ process.kill(pid, 0);
56
+ }
57
+ catch (error) {
58
+ if (error.code === 'ESRCH')
59
+ return null;
60
+ }
61
+ }
62
+ }
63
+ return fail('SESSION_CLOSE_TARGET_UNCONFIRMED', 'Process disappearance cannot be verified');
64
+ }
65
+ /** Restart reconciliation never issues termination. External tmux/process
66
+ * changes are outside the service lock; final fresh checks reduce, not erase,
67
+ * that race. The exact tmux session ID is used for teardown. */
68
+ export async function closeSessionRuntime(adapter, target, reconcile) {
69
+ await adapter.barrier(async () => {
70
+ if (adapter.pendingMessages())
71
+ fail('SESSION_PENDING_MESSAGES', 'Pending messages must be resolved before closing');
72
+ if (await adapter.exists()) {
73
+ if (reconcile)
74
+ fail('OPERATION_OUTCOME_UNCONFIRMED', 'Runtime still exists; reconciliation will not terminate a process');
75
+ if (!target || JSON.stringify(await adapter.observe()) !== JSON.stringify(target))
76
+ fail('SESSION_CLOSE_TARGET_CHANGED', 'Runtime or process instance changed after close intent');
77
+ await adapter.destroy(target);
78
+ const deadline = Date.now() + 2000;
79
+ // Observe actual disappearance; do not issue repeated termination.
80
+ while (await adapter.exists() && Date.now() < deadline)
81
+ await new Promise(resolve => setTimeout(resolve, 50));
82
+ }
83
+ if (await adapter.exists())
84
+ fail('OPERATION_OUTCOME_UNCONFIRMED', 'Runtime absence cannot be confirmed');
85
+ await adapter.forgetRuntime();
86
+ });
87
+ }
@@ -2,6 +2,7 @@ import { collaborationSessionDisplayName } from '../utils/sessionDisplayName.js'
2
2
  import { integrationError } from '../agent/integrationStore.js';
3
3
  import { assertNativeResumeAvailable, collectNativeResumeOwnerCandidates } from '../agent/nativeResumeOwner.js';
4
4
  import { readNativeProcessIdentity } from '../agent/nativeProcessIdentity.js';
5
+ import { closeSessionRuntime, foregroundProcessInstance, processStartIdentity } from '../agent/sessionManagement.js';
5
6
  import { releaseSessionRuntime } from '../agent/sessionLifecycle.js';
6
7
  import { resumeConfigurationFingerprint } from '../agent/sessionResumeConfiguration.js';
7
8
  import { integrationLaunchCommand } from '../agent/integrationSessions.js';
@@ -34,7 +35,7 @@ import { getPtyHostManager } from '../ptyhost/manager.js';
34
35
  import { pathValidator } from '../utils/pathValidator.js';
35
36
  import { TERMINAL, TMUX } from '../config.js';
36
37
  import { localAccessManager, localAccessInterfaceUrl } from '../utils/localAccess.js';
37
- import { normalizeLocalAccessName, getLocaleSetting, setLocaleSetting, getContextDraftHeightSetting, setContextDraftHeightSetting, getAutoRenameAgentsSetting, setAutoRenameAgentsSetting, getAutoRenameNamerSetting, setAutoRenameNamerSetting, getAutoRenameModelsSetting, setAutoRenameModelsSetting, getAutoRenameIntervalMinutesSetting, setAutoRenameIntervalMinutesSetting, getAutoRenamePromptPreferenceSetting, setAutoRenamePromptPreferenceSetting, getAutoRenamePromptPayloadCharsSetting, setAutoRenamePromptPayloadCharsSetting, getNewSessionAgentSlugSetting, setNewSessionAgentSlugSetting, getRunningSessionButtonEnabledSetting, getAttentionButtonEnabledSetting, getCollaborationPanelsSetting, setCollaborationPanelSetting, getAndroidPanelSetting, setAndroidPanelSetting, normalizeAndroidPanel, getCollaborationFloatingGroupIdSetting, setCollaborationFloatingGroupIdSetting, getServiceSwitcherExpandedSetting, setServiceSwitcherExpandedSetting, setRunningSessionButtonEnabledSetting, setAttentionButtonEnabledSetting, getFileSortModesSetting, getHideGitIgnoredRootsSetting, getGitIgnoreExceptionsSetting, setGitIgnoreExceptionsSetting, setHideGitIgnoredRootSetting, setFileSortModesSetting, setFileSortModeSetting, getNestedGitScanRootsSetting, setNestedGitScanRootSetting, getPinnedExplorerRootsSetting, setPinnedExplorerRootsSetting, setPinnedExplorerRootSetting, watchPinnedExplorerRootsSetting, getActiveGitReposSetting, setActiveGitRepoSetting, } from '../utils/settings.js';
38
+ import { normalizeLocalAccessName, getLocaleSetting, setLocaleSetting, getContextDraftHeightSetting, setContextDraftHeightSetting, getAutoRenameAgentsSetting, setAutoRenameAgentsSetting, getAutoRenameNamerSetting, setAutoRenameNamerSetting, getAutoRenameModelsSetting, setAutoRenameModelsSetting, getAutoRenameIntervalMinutesSetting, setAutoRenameIntervalMinutesSetting, getAutoRenamePromptPreferenceSetting, setAutoRenamePromptPreferenceSetting, getAutoRenamePromptPayloadCharsSetting, setAutoRenamePromptPayloadCharsSetting, getNewSessionAgentSlugSetting, setNewSessionAgentSlugSetting, getRunningSessionButtonEnabledSetting, getAttentionButtonEnabledSetting, getCollaborationPanelsSetting, setCollaborationPanelSetting, getAndroidPanelSetting, setAndroidPanelSetting, getRightSidebarTabsSetting, setRightSidebarTabsSetting, normalizeAndroidPanel, getCollaborationFloatingGroupIdSetting, setCollaborationFloatingGroupIdSetting, getServiceSwitcherExpandedSetting, setServiceSwitcherExpandedSetting, setRunningSessionButtonEnabledSetting, setAttentionButtonEnabledSetting, getFileSortModesSetting, getHideGitIgnoredRootsSetting, getGitIgnoreExceptionsSetting, setGitIgnoreExceptionsSetting, setHideGitIgnoredRootSetting, setFileSortModesSetting, setFileSortModeSetting, getNestedGitScanRootsSetting, setNestedGitScanRootSetting, getPinnedExplorerRootsSetting, setPinnedExplorerRootsSetting, setPinnedExplorerRootSetting, watchPinnedExplorerRootsSetting, getActiveGitReposSetting, setActiveGitRepoSetting, } from '../utils/settings.js';
38
39
  import { loadContextDraft, saveContextDraft } from '../utils/contextDraft.js';
39
40
  import { getOnboardingServerUrl } from '../onboardingServer.js';
40
41
  import { inspectLinuxInotifyUsage, isWatchResourceExhaustion } from '../utils/fileWatchPolicy.js';
@@ -629,7 +630,7 @@ function schedulePersistGlobalState() {
629
630
  }
630
631
  }, 200);
631
632
  }
632
- async function persistGlobalStateNow() {
633
+ async function persistGlobalStateNow(strict = false) {
633
634
  if (persistGlobalStateTimer) {
634
635
  clearTimeout(persistGlobalStateTimer);
635
636
  persistGlobalStateTimer = null;
@@ -639,6 +640,8 @@ async function persistGlobalStateNow() {
639
640
  }
640
641
  catch (error) {
641
642
  console.warn('[session-persist] Failed to persist global state:', getErrorMessage(error));
643
+ if (strict)
644
+ throw error;
642
645
  }
643
646
  }
644
647
  // 进程退出前立即刷盘,避免 tsx watch 重启导致状态丢失
@@ -1980,10 +1983,129 @@ async function integrationTmuxPresent(record) {
1980
1983
  throw error;
1981
1984
  }
1982
1985
  }
1986
+ async function verifyIntegrationRuntimeOwnership(record) {
1987
+ await integrationSessionAdapter.prepareRelease(record);
1988
+ const terminal = integrationTerminalRecord(record);
1989
+ if (terminal && globalSessionState.sessions.some(other => other.sessionId !== record.session_id
1990
+ && (other.tmuxSessionName === terminal.tmuxSessionName || terminal.backendSessionId && other.backendSessionId === terminal.backendSessionId))) {
1991
+ integrationError('SESSION_IDENTITY_MISMATCH', 'Runtime has another logical owner', 409);
1992
+ }
1993
+ }
1994
+ async function forgetIntegrationRuntime(record) {
1995
+ if (await integrationTmuxPresent(record))
1996
+ integrationError('OPERATION_OUTCOME_UNCONFIRMED', 'Owned tmux still exists', 409);
1997
+ await verifyIntegrationRuntimeOwnership(record);
1998
+ for (const [id, backend] of terminalSessions)
1999
+ if (backend.mode === 'tmux' && backend.tmuxSessionName === `wt-integration-${record.session_id}`)
2000
+ cleanupSession(id, { killProcess: true });
2001
+ removeGlobalSessionRecord(record.session_id);
2002
+ collaborationStore.archiveSession(record.session_id);
2003
+ collaborationRouting.remove(record.session_id);
2004
+ await persistGlobalStateNow(true);
2005
+ broadcastClientState();
2006
+ }
2007
+ async function observeIntegrationCloseTarget(record) {
2008
+ await verifyIntegrationRuntimeOwnership(record);
2009
+ const terminal = integrationTerminalRecord(record);
2010
+ if (!terminal || !record.terminal_binding)
2011
+ integrationError('SESSION_CLOSE_TARGET_UNCONFIRMED', 'Original runtime binding is unavailable', 409);
2012
+ const inspected = await inspectCollaborationTmux({ sessionId: record.session_id, backendSessionId: terminal.backendSessionId,
2013
+ mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: record.agent_slug,
2014
+ nativeSessionId: record.agent_native_session_id, pane: record.terminal_binding }, undefined, false, true);
2015
+ if (inspected.state !== 'ready' || !inspected.pane)
2016
+ integrationError('SESSION_CLOSE_TARGET_UNCONFIRMED', 'Original pinned pane cannot be verified', 409);
2017
+ const layout = await getTmuxLayout(terminal.tmuxSessionName);
2018
+ const panes = layout.windows.flatMap(window => window.panes);
2019
+ if (panes.length !== 1 || layout.activePaneId !== record.terminal_binding.paneId)
2020
+ integrationError('SESSION_IDENTITY_MISMATCH', 'Only the single original owned pane can be closed', 409);
2021
+ const pane = panes[0];
2022
+ const paneOwners = (await runTmux(['list-panes', '-a', '-F', '#{session_id} #{pane_id}'])).trim().split('\n');
2023
+ if (paneOwners.some(line => { const [owner, id] = line.trim().split(/\s+/); return id === pane.id && owner !== record.terminal_binding.sessionId; }))
2024
+ integrationError('SESSION_SCOPE_CONFLICT', 'Owned pane is linked into another tmux session', 409);
2025
+ if (process.platform === 'linux')
2026
+ await getProcessSnapshot(true);
2027
+ const program = await resolveTmuxPaneProgram(pane, true, true);
2028
+ const agent = detectAgentFromCommand(program?.rawArgs ?? program?.command ?? '', agentCustomCommands());
2029
+ let kind, pid, nativeId = null;
2030
+ if (agent) {
2031
+ if (!record.agent_native_session_id || agent.slug !== record.agent_slug || program?.source !== 'tmux-tty' || !program.processPid) {
2032
+ integrationError('SESSION_CLOSE_TARGET_UNCONFIRMED', 'A running Agent requires a live exact native identity', 409);
2033
+ }
2034
+ const identity = await observeProgramNativeIdentity(agent, program);
2035
+ if (identity.failure || identity.nativeId !== record.agent_native_session_id)
2036
+ integrationError('SESSION_IDENTITY_MISMATCH', 'Current Agent native identity differs from the owned record', 409);
2037
+ kind = 'agent';
2038
+ pid = program.processPid;
2039
+ nativeId = identity.nativeId;
2040
+ }
2041
+ else {
2042
+ if (!await integrationPaneIsIdleShell(inspected.pane))
2043
+ integrationError('SESSION_CLOSE_TARGET_UNCONFIRMED', 'Current runtime is not a verified foreground shell', 409);
2044
+ kind = 'shell';
2045
+ pid = pane.pid;
2046
+ }
2047
+ const serverStart = await processStartIdentity(record.terminal_binding.serverPid);
2048
+ if (!serverStart)
2049
+ integrationError('SESSION_CLOSE_TARGET_UNCONFIRMED', 'Current tmux server instance is unavailable', 409);
2050
+ return { binding: { ...record.terminal_binding }, tmux_server_start_id: serverStart, kind, process_pid: pid,
2051
+ process_start_id: await foregroundProcessInstance(pid), native_id: nativeId };
2052
+ }
1983
2053
  export const integrationSessionAdapter = {
1984
2054
  subscribe(listener) { integrationSessionObservers.add(listener); return () => { integrationSessionObservers.delete(listener); }; },
1985
2055
  registerDeliveryGuard(guard) { integrationDeliveryGuard = guard; return () => { if (integrationDeliveryGuard === guard)
1986
2056
  integrationDeliveryGuard = undefined; }; },
2057
+ async prepareRename(record) {
2058
+ await verifyIntegrationRuntimeOwnership(record);
2059
+ if (!integrationTerminalRecord(record) && await integrationTmuxPresent(record))
2060
+ integrationError('SESSION_IDENTITY_MISMATCH', 'Live tmux lacks its owned terminal registration', 409);
2061
+ },
2062
+ async rename(record) {
2063
+ await integrationSessionAdapter.prepareRename(record);
2064
+ const terminal = integrationTerminalRecord(record);
2065
+ if (!terminal)
2066
+ return; // Metadata survives released/closed; never recreate a runtime.
2067
+ if (!record.name)
2068
+ integrationError('INVALID_NAME', 'Missing persistent display name');
2069
+ if (await integrationTmuxPresent(record))
2070
+ await setTmuxOption(terminal.tmuxSessionName, '@termdock-friendly-name', record.name);
2071
+ upsertGlobalSessionRecord({ ...terminal, name: record.name, customName: true, autoTitle: null });
2072
+ await persistGlobalStateNow(true);
2073
+ await getSessionInventorySnapshot({ refresh: true });
2074
+ broadcastClientState();
2075
+ },
2076
+ async prepareClose(record) {
2077
+ if (collaborationStore.pendingCount(record.session_id))
2078
+ integrationError('SESSION_PENDING_MESSAGES', 'Pending messages must be resolved before closing', 409);
2079
+ await verifyIntegrationRuntimeOwnership(record);
2080
+ return await integrationTmuxPresent(record) ? observeIntegrationCloseTarget(record) : null;
2081
+ },
2082
+ async closeRuntime(record, reconcile) {
2083
+ await closeSessionRuntime({
2084
+ barrier: action => collaborationDeliveryWorker.reconfigure(record.session_id, action),
2085
+ async exists() {
2086
+ if (await integrationTmuxPresent(record))
2087
+ return true;
2088
+ const target = record.close_intent?.target;
2089
+ return !!target && await processStartIdentity(target.process_pid) === target.process_start_id;
2090
+ },
2091
+ pendingMessages: () => collaborationStore.pendingCount(record.session_id),
2092
+ observe: () => observeIntegrationCloseTarget(record),
2093
+ async destroy(target) {
2094
+ // Kill by immutable tmux session ID, not by a potentially reused name.
2095
+ // No process-group kill or application prompt is sent.
2096
+ if (JSON.stringify(await observeIntegrationCloseTarget(record)) !== JSON.stringify(target))
2097
+ integrationError('SESSION_CLOSE_TARGET_CHANGED', 'Close target changed before teardown', 409);
2098
+ intentionallyDeletingTmuxSessions.add(`wt-integration-${record.session_id}`);
2099
+ try {
2100
+ await runTmux(['kill-session', '-t', target.binding.sessionId]);
2101
+ }
2102
+ finally {
2103
+ intentionallyDeletingTmuxSessions.delete(`wt-integration-${record.session_id}`);
2104
+ }
2105
+ },
2106
+ forgetRuntime: () => forgetIntegrationRuntime(record),
2107
+ }, record.close_intent?.target ?? null, reconcile);
2108
+ },
1987
2109
  pendingMessages(id) { return collaborationStore.pendingCount(id); },
1988
2110
  messageHistory(id) { return collaborationStore.hasTerminalMessageHistory(id); },
1989
2111
  async prepareRelease(record) {
@@ -2186,7 +2308,7 @@ async function launchIntegrationTerminal(record, restoring, prepared, progress,
2186
2308
  }
2187
2309
  const opened = await openInventorySession({}, { preferredFrontendSessionId: record.session_id,
2188
2310
  mode: 'tmux', tmuxSessionName: `wt-integration-${record.session_id}`, cwd: record.cwd,
2189
- name: `${record.agent_slug} · ${group.name}`, customName: true });
2311
+ name: record.name ?? `${record.agent_slug} · ${group.name}`, customName: true });
2190
2312
  if (opened.session.sessionId !== record.session_id)
2191
2313
  integrationError('SESSION_IDENTITY_MISMATCH', 'Terminal id changed', 409);
2192
2314
  const terminal = integrationTerminalRecord(record);
@@ -7147,6 +7269,7 @@ async function getSettingsPayload() {
7147
7269
  attentionButtonEnabled: getAttentionButtonEnabledSetting(),
7148
7270
  collaborationPanels: getCollaborationPanelsSetting(),
7149
7271
  androidPanel: getAndroidPanelSetting(),
7272
+ rightSidebarTabs: getRightSidebarTabsSetting(),
7150
7273
  collaborationFloatingGroupId: getCollaborationFloatingGroupIdSetting(),
7151
7274
  serviceSwitcherExpanded: getServiceSwitcherExpandedSetting(),
7152
7275
  fileSortModes: getFileSortModesSetting(),
@@ -7293,6 +7416,9 @@ router.put('/settings', async (req, res) => {
7293
7416
  }
7294
7417
  setNewSessionAgentSlugSetting(slug);
7295
7418
  }
7419
+ if (body.rightSidebarTabs && typeof body.rightSidebarTabs === 'object') {
7420
+ setRightSidebarTabsSetting(body.rightSidebarTabs);
7421
+ }
7296
7422
  if (body.androidPanel && typeof body.androidPanel === 'object') {
7297
7423
  // 与现有设置合并后再校验:允许只更新部分字段(如仅切开关)。
7298
7424
  const merged = normalizeAndroidPanel({ ...getAndroidPanelSetting(), ...body.androidPanel });
@@ -253,6 +253,7 @@ function normalizeSettings(value) {
253
253
  attentionButtonEnabled: raw.attentionButtonEnabled !== false,
254
254
  collaborationPanels: normalizeCollaborationPanels(raw.collaborationPanels),
255
255
  androidPanel: normalizeAndroidPanel(raw.androidPanel),
256
+ rightSidebarTabs: normalizeRightSidebarTabs(raw.rightSidebarTabs),
256
257
  collaborationFloatingGroupId: typeof raw.collaborationFloatingGroupId === 'string' && raw.collaborationFloatingGroupId.trim() ? raw.collaborationFloatingGroupId.trim() : null,
257
258
  serviceSwitcherExpanded: raw.serviceSwitcherExpanded === true,
258
259
  fileSortModes: normalizeFileSortModes(raw.fileSortModes),
@@ -769,6 +770,19 @@ export function normalizeCollaborationPanels(value, depth = 0) {
769
770
  }
770
771
  return result;
771
772
  }
773
+ export function normalizeRightSidebarTabs(value) {
774
+ const raw = value && typeof value === 'object' ? value : {};
775
+ return { architecture: raw.architecture !== false, computer: raw.computer !== false };
776
+ }
777
+ export function getRightSidebarTabsSetting() { return loadSettings().rightSidebarTabs; }
778
+ export function setRightSidebarTabsSetting(patch) {
779
+ return updateSettings(settings => {
780
+ for (const key of ['architecture', 'computer']) {
781
+ if (typeof patch[key] === 'boolean')
782
+ settings.rightSidebarTabs[key] = patch[key];
783
+ }
784
+ });
785
+ }
772
786
  export function getAndroidPanelSetting() { return loadSettings().androidPanel; }
773
787
  export function setAndroidPanelSetting(patch) {
774
788
  return updateSettings((settings) => {