termdock 1.4.344 → 1.4.346

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 (354) hide show
  1. package/dist/client/assets/{App-7PpqNtmr.js → App-BN_iuuvE.js} +6 -6
  2. package/dist/client/assets/App-BN_iuuvE.js.br +0 -0
  3. package/dist/client/assets/App-BN_iuuvE.js.gz +0 -0
  4. package/dist/client/assets/{ArchitecturePanel-BeGg_w36.js → ArchitecturePanel-sTwptDpa.js} +2 -2
  5. package/dist/client/assets/ArchitecturePanel-sTwptDpa.js.br +0 -0
  6. package/dist/client/assets/ArchitecturePanel-sTwptDpa.js.gz +0 -0
  7. package/dist/client/assets/{ChangeWalkthroughPanel-DMX0seQh.js → ChangeWalkthroughPanel-DvOSOwLu.js} +1 -1
  8. package/dist/client/assets/ChangeWalkthroughPanel-DvOSOwLu.js.br +0 -0
  9. package/dist/client/assets/ChangeWalkthroughPanel-DvOSOwLu.js.gz +0 -0
  10. package/dist/client/assets/{CollaborationMainWorkspace-EM8iRchZ.js → CollaborationMainWorkspace-DseFwFSR.js} +1 -1
  11. package/dist/client/assets/CollaborationMainWorkspace-DseFwFSR.js.br +0 -0
  12. package/dist/client/assets/CollaborationMainWorkspace-DseFwFSR.js.gz +0 -0
  13. package/dist/client/assets/CollaborationTaskContent-DL4Im2wQ.js +2 -0
  14. package/dist/client/assets/{ComputerControlView-qpYuVzPh.js → ComputerControlView-CWlfdXhY.js} +3 -3
  15. package/dist/client/assets/ComputerControlView-CWlfdXhY.js.br +0 -0
  16. package/dist/client/assets/ComputerControlView-CWlfdXhY.js.gz +0 -0
  17. package/dist/client/assets/{DagPlayground-CK7VBLZx.js → DagPlayground-B1IytHVy.js} +1 -1
  18. package/dist/client/assets/DagPlayground-B1IytHVy.js.br +0 -0
  19. package/dist/client/assets/DagPlayground-B1IytHVy.js.gz +0 -0
  20. package/dist/client/assets/{DiffLab-oKSML0WX.js → DiffLab-B6gSsPoJ.js} +1 -1
  21. package/dist/client/assets/DiffLab-B6gSsPoJ.js.br +0 -0
  22. package/dist/client/assets/DiffLab-B6gSsPoJ.js.gz +0 -0
  23. package/dist/client/assets/{DiffReview-BshWCx_C.js → DiffReview-BYI8gVYo.js} +1 -1
  24. package/dist/client/assets/DiffReview-BYI8gVYo.js.br +0 -0
  25. package/dist/client/assets/DiffReview-BYI8gVYo.js.gz +0 -0
  26. package/dist/client/assets/{DiffReviewLab-QyzjteoK.js → DiffReviewLab-BYUQFzsG.js} +1 -1
  27. package/dist/client/assets/DiffReviewLab-BYUQFzsG.js.br +0 -0
  28. package/dist/client/assets/DiffReviewLab-BYUQFzsG.js.gz +0 -0
  29. package/dist/client/assets/{DiffViewer--QG609jF.js → DiffViewer-P1mbq4LM.js} +1 -1
  30. package/dist/client/assets/DiffViewer-P1mbq4LM.js.br +0 -0
  31. package/dist/client/assets/DiffViewer-P1mbq4LM.js.gz +0 -0
  32. package/dist/client/assets/{ModelPreview-BY-nllCI.js → ModelPreview-BpIynSeJ.js} +1 -1
  33. package/dist/client/assets/ModelPreview-BpIynSeJ.js.br +0 -0
  34. package/dist/client/assets/ModelPreview-BpIynSeJ.js.gz +0 -0
  35. package/dist/client/assets/{RightSidebar-CdEMgc2G.js → RightSidebar-DyX2uyW6.js} +47 -45
  36. package/dist/client/assets/RightSidebar-DyX2uyW6.js.br +0 -0
  37. package/dist/client/assets/RightSidebar-DyX2uyW6.js.gz +0 -0
  38. package/dist/client/assets/{abnfDiagram-VCTEODGH-D_YYeniU.js → abnfDiagram-VCTEODGH-Cjq0zd9z.js} +1 -1
  39. package/dist/client/assets/abnfDiagram-VCTEODGH-Cjq0zd9z.js.br +0 -0
  40. package/dist/client/assets/abnfDiagram-VCTEODGH-Cjq0zd9z.js.gz +0 -0
  41. package/dist/client/assets/app-HTVDUkx-.js +35 -0
  42. package/dist/client/assets/app-HTVDUkx-.js.br +0 -0
  43. package/dist/client/assets/app-HTVDUkx-.js.gz +0 -0
  44. package/dist/client/assets/{arc-sDYgQVIO.js → arc-DkPjbARe.js} +1 -1
  45. package/dist/client/assets/arc-DkPjbARe.js.br +0 -0
  46. package/dist/client/assets/arc-DkPjbARe.js.gz +0 -0
  47. package/dist/client/assets/{architectureDiagram-5GKGNRK7-mzycNt3i.js → architectureDiagram-5GKGNRK7-DvErYV6b.js} +1 -1
  48. package/dist/client/assets/architectureDiagram-5GKGNRK7-DvErYV6b.js.br +0 -0
  49. package/dist/client/assets/architectureDiagram-5GKGNRK7-DvErYV6b.js.gz +0 -0
  50. package/dist/client/assets/{blockDiagram-I7D4REHJ-CmBIG7tu.js → blockDiagram-I7D4REHJ-Bds9HO1o.js} +1 -1
  51. package/dist/client/assets/blockDiagram-I7D4REHJ-Bds9HO1o.js.br +0 -0
  52. package/dist/client/assets/blockDiagram-I7D4REHJ-Bds9HO1o.js.gz +0 -0
  53. package/dist/client/assets/{c4Diagram-7LVT6UL2-CyaMSX6v.js → c4Diagram-7LVT6UL2-C2OH1wSt.js} +1 -1
  54. package/dist/client/assets/c4Diagram-7LVT6UL2-C2OH1wSt.js.br +0 -0
  55. package/dist/client/assets/c4Diagram-7LVT6UL2-C2OH1wSt.js.gz +0 -0
  56. package/dist/client/assets/channel-CdhDWMew.js +1 -0
  57. package/dist/client/assets/{chunk-2Q5K7J3B-BDL3ltwl.js → chunk-2Q5K7J3B-DVaF1NsT.js} +1 -1
  58. package/dist/client/assets/{chunk-5VM5RSS4-BlxmnqT8.js → chunk-5VM5RSS4-Dkbpeqfb.js} +1 -1
  59. package/dist/client/assets/{chunk-F27PBJKO-C23_F1Qb.js → chunk-F27PBJKO-CRPAOyuh.js} +1 -1
  60. package/dist/client/assets/chunk-F27PBJKO-CRPAOyuh.js.br +0 -0
  61. package/dist/client/assets/chunk-F27PBJKO-CRPAOyuh.js.gz +0 -0
  62. package/dist/client/assets/{chunk-IMKFNOWR-BNhZFCbM.js → chunk-IMKFNOWR-CphgPwod.js} +1 -1
  63. package/dist/client/assets/chunk-IMKFNOWR-CphgPwod.js.br +0 -0
  64. package/dist/client/assets/chunk-IMKFNOWR-CphgPwod.js.gz +0 -0
  65. package/dist/client/assets/{chunk-JWPE2WC7-BKtQVfYl.js → chunk-JWPE2WC7-CWlXUB6G.js} +1 -1
  66. package/dist/client/assets/{chunk-POPQ4Y6H-DU-TCVcH.js → chunk-POPQ4Y6H-BAAz8QH8.js} +1 -1
  67. package/dist/client/assets/{chunk-SVP7TREG-CeD3DY62.js → chunk-SVP7TREG-C9qRACkp.js} +1 -1
  68. package/dist/client/assets/chunk-SVP7TREG-C9qRACkp.js.br +0 -0
  69. package/dist/client/assets/chunk-SVP7TREG-C9qRACkp.js.gz +0 -0
  70. package/dist/client/assets/{chunk-TICWLB2K-C7EI51Ae.js → chunk-TICWLB2K-CAn30A5F.js} +1 -1
  71. package/dist/client/assets/chunk-TICWLB2K-CAn30A5F.js.br +0 -0
  72. package/dist/client/assets/chunk-TICWLB2K-CAn30A5F.js.gz +0 -0
  73. package/dist/client/assets/{chunk-XXDRQBXY-CO7EB_T2.js → chunk-XXDRQBXY-i2tZFJ9V.js} +1 -1
  74. package/dist/client/assets/classDiagram-ZZMXUADV-_NMbO90f.js +1 -0
  75. package/dist/client/assets/classDiagram-v2-VYDZK3BY-_NMbO90f.js +1 -0
  76. package/dist/client/assets/{cose-bilkent-JH36ORCC-CN8cwue3.js → cose-bilkent-JH36ORCC-_ejU8hPT.js} +1 -1
  77. package/dist/client/assets/{cose-bilkent-JH36ORCC-CN8cwue3.js.br → cose-bilkent-JH36ORCC-_ejU8hPT.js.br} +0 -0
  78. package/dist/client/assets/cose-bilkent-JH36ORCC-_ejU8hPT.js.gz +0 -0
  79. package/dist/client/assets/{cynefin-OW5HDTMX-ZJmZp774.js → cynefin-OW5HDTMX-BkzgMwVY.js} +1 -1
  80. package/dist/client/assets/cynefin-OW5HDTMX-BkzgMwVY.js.br +0 -0
  81. package/dist/client/assets/cynefin-OW5HDTMX-BkzgMwVY.js.gz +0 -0
  82. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-C-O7V1Tk.js → cynefinDiagram-5FMLGOSQ-f623ycDk.js} +1 -1
  83. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-f623ycDk.js.br +0 -0
  84. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-f623ycDk.js.gz +0 -0
  85. package/dist/client/assets/{dagre-GXQ25YYZ-CgNLkZqS.js → dagre-GXQ25YYZ-CZKJoNzx.js} +1 -1
  86. package/dist/client/assets/dagre-GXQ25YYZ-CZKJoNzx.js.br +0 -0
  87. package/dist/client/assets/dagre-GXQ25YYZ-CZKJoNzx.js.gz +0 -0
  88. package/dist/client/assets/{diagram-S7CK7UJ4-_e0IES0l.js → diagram-S7CK7UJ4-C4Sjb6W8.js} +1 -1
  89. package/dist/client/assets/diagram-S7CK7UJ4-C4Sjb6W8.js.br +0 -0
  90. package/dist/client/assets/diagram-S7CK7UJ4-C4Sjb6W8.js.gz +0 -0
  91. package/dist/client/assets/{diagram-UQ7AKVKN-IknuU7gc.js → diagram-UQ7AKVKN-Buov_WHB.js} +1 -1
  92. package/dist/client/assets/diagram-UQ7AKVKN-Buov_WHB.js.br +0 -0
  93. package/dist/client/assets/diagram-UQ7AKVKN-Buov_WHB.js.gz +0 -0
  94. package/dist/client/assets/{diagram-VSXAHHWV-xp0eP0gd.js → diagram-VSXAHHWV-B3v-ZnXu.js} +1 -1
  95. package/dist/client/assets/diagram-VSXAHHWV-B3v-ZnXu.js.br +0 -0
  96. package/dist/client/assets/diagram-VSXAHHWV-B3v-ZnXu.js.gz +0 -0
  97. package/dist/client/assets/{diagram-VX7I27RA-YM3d3Rh5.js → diagram-VX7I27RA-DCEWE8mj.js} +1 -1
  98. package/dist/client/assets/diagram-VX7I27RA-DCEWE8mj.js.br +0 -0
  99. package/dist/client/assets/diagram-VX7I27RA-DCEWE8mj.js.gz +0 -0
  100. package/dist/client/assets/{diagram-Z3DM3KII-vjaumOKc.js → diagram-Z3DM3KII-bK4WKBJF.js} +1 -1
  101. package/dist/client/assets/diagram-Z3DM3KII-bK4WKBJF.js.br +0 -0
  102. package/dist/client/assets/diagram-Z3DM3KII-bK4WKBJF.js.gz +0 -0
  103. package/dist/client/assets/{ebnfDiagram-PWID7BFC-DL19bAk6.js → ebnfDiagram-PWID7BFC-wOu6iW76.js} +1 -1
  104. package/dist/client/assets/ebnfDiagram-PWID7BFC-wOu6iW76.js.br +0 -0
  105. package/dist/client/assets/ebnfDiagram-PWID7BFC-wOu6iW76.js.gz +0 -0
  106. package/dist/client/assets/{erDiagram-RLTQ6QDP-CL8YGnYl.js → erDiagram-RLTQ6QDP-D83VmrYf.js} +1 -1
  107. package/dist/client/assets/erDiagram-RLTQ6QDP-D83VmrYf.js.br +0 -0
  108. package/dist/client/assets/erDiagram-RLTQ6QDP-D83VmrYf.js.gz +0 -0
  109. package/dist/client/assets/{flowDiagram-HODETNUW-Dmxmmzef.js → flowDiagram-HODETNUW-DCxfJLXu.js} +1 -1
  110. package/dist/client/assets/flowDiagram-HODETNUW-DCxfJLXu.js.br +0 -0
  111. package/dist/client/assets/flowDiagram-HODETNUW-DCxfJLXu.js.gz +0 -0
  112. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-Cg95sExn.js → ganttDiagram-EL5Y4UJY-CF9XnXOS.js} +1 -1
  113. package/dist/client/assets/ganttDiagram-EL5Y4UJY-CF9XnXOS.js.br +0 -0
  114. package/dist/client/assets/ganttDiagram-EL5Y4UJY-CF9XnXOS.js.gz +0 -0
  115. package/dist/client/assets/{gestureArbiter-ZMwmrdcg.js → gestureArbiter-DOugsAle.js} +1 -1
  116. package/dist/client/assets/gestureArbiter-DOugsAle.js.br +0 -0
  117. package/dist/client/assets/gestureArbiter-DOugsAle.js.gz +0 -0
  118. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-BhPjxbUY.js → gitGraphDiagram-WWUBYQGX-jT8-SkeT.js} +1 -1
  119. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-jT8-SkeT.js.br +0 -0
  120. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-jT8-SkeT.js.gz +0 -0
  121. package/dist/client/assets/{index-A-ZC9mbr.css → index-DtPsPZ7W.css} +1 -1
  122. package/dist/client/assets/index-DtPsPZ7W.css.br +0 -0
  123. package/dist/client/assets/{index-A-ZC9mbr.css.gz → index-DtPsPZ7W.css.gz} +0 -0
  124. package/dist/client/assets/{infoDiagram-27XIBGKW-J73ysnHU.js → infoDiagram-27XIBGKW-B-LDzk7Q.js} +1 -1
  125. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-DYno2wlU.js → ishikawaDiagram-5VMMS53U-CsosD6UL.js} +1 -1
  126. package/dist/client/assets/ishikawaDiagram-5VMMS53U-CsosD6UL.js.br +0 -0
  127. package/dist/client/assets/ishikawaDiagram-5VMMS53U-CsosD6UL.js.gz +0 -0
  128. package/dist/client/assets/{journeyDiagram-3NMN7TZE-D1i0ft78.js → journeyDiagram-3NMN7TZE-Bv5RcxaN.js} +1 -1
  129. package/dist/client/assets/journeyDiagram-3NMN7TZE-Bv5RcxaN.js.br +0 -0
  130. package/dist/client/assets/journeyDiagram-3NMN7TZE-Bv5RcxaN.js.gz +0 -0
  131. package/dist/client/assets/{kanban-definition-UXKFOSKX-dO2PhUIk.js → kanban-definition-UXKFOSKX-D1ukvOoH.js} +1 -1
  132. package/dist/client/assets/kanban-definition-UXKFOSKX-D1ukvOoH.js.br +0 -0
  133. package/dist/client/assets/kanban-definition-UXKFOSKX-D1ukvOoH.js.gz +0 -0
  134. package/dist/client/assets/{layout-DmeRjjIH.js → layout-VC45eUZy.js} +1 -1
  135. package/dist/client/assets/layout-VC45eUZy.js.br +0 -0
  136. package/dist/client/assets/layout-VC45eUZy.js.gz +0 -0
  137. package/dist/client/assets/{linear-FrAcYoA2.js → linear-C3VBb8xa.js} +1 -1
  138. package/dist/client/assets/linear-C3VBb8xa.js.br +0 -0
  139. package/dist/client/assets/linear-C3VBb8xa.js.gz +0 -0
  140. package/dist/client/assets/{mermaid.core-CvYA1lvj.js → mermaid.core-DG2QUI-L.js} +5 -5
  141. package/dist/client/assets/mermaid.core-DG2QUI-L.js.br +0 -0
  142. package/dist/client/assets/mermaid.core-DG2QUI-L.js.gz +0 -0
  143. package/dist/client/assets/{mindmap-definition-YA3MSWOX-Dclk8rJC.js → mindmap-definition-YA3MSWOX-CpA9V0iU.js} +1 -1
  144. package/dist/client/assets/mindmap-definition-YA3MSWOX-CpA9V0iU.js.br +0 -0
  145. package/dist/client/assets/mindmap-definition-YA3MSWOX-CpA9V0iU.js.gz +0 -0
  146. package/dist/client/assets/{passwordBootstrap-DWMjsDcc.js → passwordBootstrap-DILrqabi.js} +1 -1
  147. package/dist/client/assets/passwordBootstrap-DILrqabi.js.br +0 -0
  148. package/dist/client/assets/passwordBootstrap-DILrqabi.js.gz +0 -0
  149. package/dist/client/assets/{pegDiagram-XKGWAZYB-ACqEwiS4.js → pegDiagram-XKGWAZYB-C7OQC7uD.js} +1 -1
  150. package/dist/client/assets/pegDiagram-XKGWAZYB-C7OQC7uD.js.br +0 -0
  151. package/dist/client/assets/pegDiagram-XKGWAZYB-C7OQC7uD.js.gz +0 -0
  152. package/dist/client/assets/{pieDiagram-E7YTZNPT-p7ypBbNQ.js → pieDiagram-E7YTZNPT-Ot6_RqeC.js} +1 -1
  153. package/dist/client/assets/pieDiagram-E7YTZNPT-Ot6_RqeC.js.br +0 -0
  154. package/dist/client/assets/pieDiagram-E7YTZNPT-Ot6_RqeC.js.gz +0 -0
  155. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-DMn4p4aH.js → quadrantDiagram-AXDQQJYC-Bf7jut-u.js} +1 -1
  156. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-DMn4p4aH.js.br → quadrantDiagram-AXDQQJYC-Bf7jut-u.js.br} +0 -0
  157. package/dist/client/assets/quadrantDiagram-AXDQQJYC-Bf7jut-u.js.gz +0 -0
  158. package/dist/client/assets/{railroadDiagram-O6MQD6OU-DWdLvY3f.js → railroadDiagram-O6MQD6OU-WrpZgg8t.js} +1 -1
  159. package/dist/client/assets/railroadDiagram-O6MQD6OU-WrpZgg8t.js.br +0 -0
  160. package/dist/client/assets/railroadDiagram-O6MQD6OU-WrpZgg8t.js.gz +0 -0
  161. package/dist/client/assets/{rdpSession-AXXpTcnA.js → rdpSession-D5nvZxrU.js} +1 -1
  162. package/dist/client/assets/rdpSession-D5nvZxrU.js.br +0 -0
  163. package/dist/client/assets/rdpSession-D5nvZxrU.js.gz +0 -0
  164. package/dist/client/assets/{referenceLongPress-Bi1LDzVG.js → referenceLongPress-C6YZh55M.js} +1 -1
  165. package/dist/client/assets/referenceLongPress-C6YZh55M.js.br +0 -0
  166. package/dist/client/assets/referenceLongPress-C6YZh55M.js.gz +0 -0
  167. package/dist/client/assets/{requirementDiagram-BXWQKSXE-Dy_QUxq3.js → requirementDiagram-BXWQKSXE-DSDgL_p4.js} +1 -1
  168. package/dist/client/assets/requirementDiagram-BXWQKSXE-DSDgL_p4.js.br +0 -0
  169. package/dist/client/assets/requirementDiagram-BXWQKSXE-DSDgL_p4.js.gz +0 -0
  170. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-HagpiSZn.js → sankeyDiagram-P5KCCOFB-C_ytO8Ty.js} +1 -1
  171. package/dist/client/assets/sankeyDiagram-P5KCCOFB-C_ytO8Ty.js.br +0 -0
  172. package/dist/client/assets/sankeyDiagram-P5KCCOFB-C_ytO8Ty.js.gz +0 -0
  173. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-BN1oDRj1.js → sequenceDiagram-WJ2MYXX4-DhZKcw8h.js} +1 -1
  174. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DhZKcw8h.js.br +0 -0
  175. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DhZKcw8h.js.gz +0 -0
  176. package/dist/client/assets/{sizeCapture-INFHLROL-CQevvCDc.js → sizeCapture-INFHLROL-BM1PVyhM.js} +1 -1
  177. package/dist/client/assets/sizeCapture-INFHLROL-BM1PVyhM.js.br +0 -0
  178. package/dist/client/assets/sizeCapture-INFHLROL-BM1PVyhM.js.gz +0 -0
  179. package/dist/client/assets/{sparkles-CzTc2Jfu.js → sparkles-BONmCbTi.js} +1 -1
  180. package/dist/client/assets/{stateDiagram-D77RDMKH-CWhm9E8u.js → stateDiagram-D77RDMKH-BJ9RE6YD.js} +1 -1
  181. package/dist/client/assets/stateDiagram-D77RDMKH-BJ9RE6YD.js.br +0 -0
  182. package/dist/client/assets/stateDiagram-D77RDMKH-BJ9RE6YD.js.gz +0 -0
  183. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BMIQgRVo.js +1 -0
  184. package/dist/client/assets/{swimlanes-42K2YHIH-BiI3okul.js → swimlanes-42K2YHIH-CM-hxgek.js} +1 -1
  185. package/dist/client/assets/swimlanes-42K2YHIH-CM-hxgek.js.br +0 -0
  186. package/dist/client/assets/swimlanes-42K2YHIH-CM-hxgek.js.gz +0 -0
  187. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-BS47Goc0.js +8 -0
  188. package/dist/client/assets/{timeline-definition-24CTP7MA-CmkDj1rm.js → timeline-definition-24CTP7MA--ZFOA2ds.js} +1 -1
  189. package/dist/client/assets/timeline-definition-24CTP7MA--ZFOA2ds.js.br +0 -0
  190. package/dist/client/assets/timeline-definition-24CTP7MA--ZFOA2ds.js.gz +0 -0
  191. package/dist/client/assets/{triangle-alert-oEokybAQ.js → triangle-alert-B-7heGu-.js} +1 -1
  192. package/dist/client/assets/{vennDiagram-4TSXK5OY-BLDxV0rO.js → vennDiagram-4TSXK5OY-CAKGCM6V.js} +1 -1
  193. package/dist/client/assets/vennDiagram-4TSXK5OY-CAKGCM6V.js.br +0 -0
  194. package/dist/client/assets/vennDiagram-4TSXK5OY-CAKGCM6V.js.gz +0 -0
  195. package/dist/client/assets/{videoCompression-GVC1hIjh.js → videoCompression-D8Kt2prC.js} +1 -1
  196. package/dist/client/assets/videoCompression-D8Kt2prC.js.br +0 -0
  197. package/dist/client/assets/videoCompression-D8Kt2prC.js.gz +0 -0
  198. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-BWDriNMk.js → wardleyDiagram-VM6X3IG4-5g9ZJdVF.js} +1 -1
  199. package/dist/client/assets/wardleyDiagram-VM6X3IG4-5g9ZJdVF.js.br +0 -0
  200. package/dist/client/assets/wardleyDiagram-VM6X3IG4-5g9ZJdVF.js.gz +0 -0
  201. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-Z9KXLnuy.js → xychartDiagram-S5SC5T6Z-CJ1hIdXS.js} +1 -1
  202. package/dist/client/assets/xychartDiagram-S5SC5T6Z-CJ1hIdXS.js.br +0 -0
  203. package/dist/client/assets/xychartDiagram-S5SC5T6Z-CJ1hIdXS.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 +3 -0
  211. package/dist/server/agent/integrationCli.js +16 -2
  212. package/dist/server/agent/integrationServer.js +4 -1
  213. package/dist/server/agent/integrationShellWait.js +33 -0
  214. package/dist/server/agent/integrationStore.js +4 -0
  215. package/dist/server/agent/nativeProcessIdentity.js +21 -0
  216. package/dist/server/agent/sessionLaunchDiagnostics.js +2 -0
  217. package/dist/server/agent/sessionLaunchState.js +35 -1
  218. package/dist/server/federation/invitations.js +15 -1
  219. package/dist/server/federation/runtime.js +5 -1
  220. package/dist/server/routes/terminal.js +85 -26
  221. package/dist/server/utils/tmuxRecovery.js +22 -15
  222. package/docs/integrations.md +29 -0
  223. package/package.json +1 -1
  224. package/runtime-manifest.json +3 -3
  225. package/dist/client/assets/App-7PpqNtmr.js.br +0 -0
  226. package/dist/client/assets/App-7PpqNtmr.js.gz +0 -0
  227. package/dist/client/assets/ArchitecturePanel-BeGg_w36.js.br +0 -0
  228. package/dist/client/assets/ArchitecturePanel-BeGg_w36.js.gz +0 -0
  229. package/dist/client/assets/ChangeWalkthroughPanel-DMX0seQh.js.br +0 -0
  230. package/dist/client/assets/ChangeWalkthroughPanel-DMX0seQh.js.gz +0 -0
  231. package/dist/client/assets/CollaborationMainWorkspace-EM8iRchZ.js.br +0 -0
  232. package/dist/client/assets/CollaborationMainWorkspace-EM8iRchZ.js.gz +0 -0
  233. package/dist/client/assets/CollaborationTaskContent-D_5vDZEM.js +0 -2
  234. package/dist/client/assets/ComputerControlView-qpYuVzPh.js.br +0 -0
  235. package/dist/client/assets/ComputerControlView-qpYuVzPh.js.gz +0 -0
  236. package/dist/client/assets/DagPlayground-CK7VBLZx.js.br +0 -0
  237. package/dist/client/assets/DagPlayground-CK7VBLZx.js.gz +0 -0
  238. package/dist/client/assets/DiffLab-oKSML0WX.js.br +0 -0
  239. package/dist/client/assets/DiffLab-oKSML0WX.js.gz +0 -0
  240. package/dist/client/assets/DiffReview-BshWCx_C.js.br +0 -0
  241. package/dist/client/assets/DiffReview-BshWCx_C.js.gz +0 -0
  242. package/dist/client/assets/DiffReviewLab-QyzjteoK.js.br +0 -0
  243. package/dist/client/assets/DiffReviewLab-QyzjteoK.js.gz +0 -0
  244. package/dist/client/assets/DiffViewer--QG609jF.js.br +0 -0
  245. package/dist/client/assets/DiffViewer--QG609jF.js.gz +0 -0
  246. package/dist/client/assets/ModelPreview-BY-nllCI.js.br +0 -0
  247. package/dist/client/assets/ModelPreview-BY-nllCI.js.gz +0 -0
  248. package/dist/client/assets/RightSidebar-CdEMgc2G.js.br +0 -0
  249. package/dist/client/assets/RightSidebar-CdEMgc2G.js.gz +0 -0
  250. package/dist/client/assets/abnfDiagram-VCTEODGH-D_YYeniU.js.br +0 -0
  251. package/dist/client/assets/abnfDiagram-VCTEODGH-D_YYeniU.js.gz +0 -0
  252. package/dist/client/assets/app-VY9J50Vn.js +0 -35
  253. package/dist/client/assets/app-VY9J50Vn.js.br +0 -0
  254. package/dist/client/assets/app-VY9J50Vn.js.gz +0 -0
  255. package/dist/client/assets/arc-sDYgQVIO.js.br +0 -0
  256. package/dist/client/assets/arc-sDYgQVIO.js.gz +0 -0
  257. package/dist/client/assets/architectureDiagram-5GKGNRK7-mzycNt3i.js.br +0 -0
  258. package/dist/client/assets/architectureDiagram-5GKGNRK7-mzycNt3i.js.gz +0 -0
  259. package/dist/client/assets/blockDiagram-I7D4REHJ-CmBIG7tu.js.br +0 -0
  260. package/dist/client/assets/blockDiagram-I7D4REHJ-CmBIG7tu.js.gz +0 -0
  261. package/dist/client/assets/c4Diagram-7LVT6UL2-CyaMSX6v.js.br +0 -0
  262. package/dist/client/assets/c4Diagram-7LVT6UL2-CyaMSX6v.js.gz +0 -0
  263. package/dist/client/assets/channel-CvSg8DFp.js +0 -1
  264. package/dist/client/assets/chunk-F27PBJKO-C23_F1Qb.js.br +0 -0
  265. package/dist/client/assets/chunk-F27PBJKO-C23_F1Qb.js.gz +0 -0
  266. package/dist/client/assets/chunk-IMKFNOWR-BNhZFCbM.js.br +0 -0
  267. package/dist/client/assets/chunk-IMKFNOWR-BNhZFCbM.js.gz +0 -0
  268. package/dist/client/assets/chunk-SVP7TREG-CeD3DY62.js.br +0 -0
  269. package/dist/client/assets/chunk-SVP7TREG-CeD3DY62.js.gz +0 -0
  270. package/dist/client/assets/chunk-TICWLB2K-C7EI51Ae.js.br +0 -0
  271. package/dist/client/assets/chunk-TICWLB2K-C7EI51Ae.js.gz +0 -0
  272. package/dist/client/assets/classDiagram-ZZMXUADV-HK--o17k.js +0 -1
  273. package/dist/client/assets/classDiagram-v2-VYDZK3BY-HK--o17k.js +0 -1
  274. package/dist/client/assets/cose-bilkent-JH36ORCC-CN8cwue3.js.gz +0 -0
  275. package/dist/client/assets/cynefin-OW5HDTMX-ZJmZp774.js.br +0 -0
  276. package/dist/client/assets/cynefin-OW5HDTMX-ZJmZp774.js.gz +0 -0
  277. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-C-O7V1Tk.js.br +0 -0
  278. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-C-O7V1Tk.js.gz +0 -0
  279. package/dist/client/assets/dagre-GXQ25YYZ-CgNLkZqS.js.br +0 -0
  280. package/dist/client/assets/dagre-GXQ25YYZ-CgNLkZqS.js.gz +0 -0
  281. package/dist/client/assets/diagram-S7CK7UJ4-_e0IES0l.js.br +0 -0
  282. package/dist/client/assets/diagram-S7CK7UJ4-_e0IES0l.js.gz +0 -0
  283. package/dist/client/assets/diagram-UQ7AKVKN-IknuU7gc.js.br +0 -0
  284. package/dist/client/assets/diagram-UQ7AKVKN-IknuU7gc.js.gz +0 -0
  285. package/dist/client/assets/diagram-VSXAHHWV-xp0eP0gd.js.br +0 -0
  286. package/dist/client/assets/diagram-VSXAHHWV-xp0eP0gd.js.gz +0 -0
  287. package/dist/client/assets/diagram-VX7I27RA-YM3d3Rh5.js.br +0 -0
  288. package/dist/client/assets/diagram-VX7I27RA-YM3d3Rh5.js.gz +0 -0
  289. package/dist/client/assets/diagram-Z3DM3KII-vjaumOKc.js.br +0 -0
  290. package/dist/client/assets/diagram-Z3DM3KII-vjaumOKc.js.gz +0 -0
  291. package/dist/client/assets/ebnfDiagram-PWID7BFC-DL19bAk6.js.br +0 -0
  292. package/dist/client/assets/ebnfDiagram-PWID7BFC-DL19bAk6.js.gz +0 -0
  293. package/dist/client/assets/erDiagram-RLTQ6QDP-CL8YGnYl.js.br +0 -0
  294. package/dist/client/assets/erDiagram-RLTQ6QDP-CL8YGnYl.js.gz +0 -0
  295. package/dist/client/assets/flowDiagram-HODETNUW-Dmxmmzef.js.br +0 -0
  296. package/dist/client/assets/flowDiagram-HODETNUW-Dmxmmzef.js.gz +0 -0
  297. package/dist/client/assets/ganttDiagram-EL5Y4UJY-Cg95sExn.js.br +0 -0
  298. package/dist/client/assets/ganttDiagram-EL5Y4UJY-Cg95sExn.js.gz +0 -0
  299. package/dist/client/assets/gestureArbiter-ZMwmrdcg.js.br +0 -0
  300. package/dist/client/assets/gestureArbiter-ZMwmrdcg.js.gz +0 -0
  301. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BhPjxbUY.js.br +0 -0
  302. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BhPjxbUY.js.gz +0 -0
  303. package/dist/client/assets/index-A-ZC9mbr.css.br +0 -0
  304. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DYno2wlU.js.br +0 -0
  305. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DYno2wlU.js.gz +0 -0
  306. package/dist/client/assets/journeyDiagram-3NMN7TZE-D1i0ft78.js.br +0 -0
  307. package/dist/client/assets/journeyDiagram-3NMN7TZE-D1i0ft78.js.gz +0 -0
  308. package/dist/client/assets/kanban-definition-UXKFOSKX-dO2PhUIk.js.br +0 -0
  309. package/dist/client/assets/kanban-definition-UXKFOSKX-dO2PhUIk.js.gz +0 -0
  310. package/dist/client/assets/layout-DmeRjjIH.js.br +0 -0
  311. package/dist/client/assets/layout-DmeRjjIH.js.gz +0 -0
  312. package/dist/client/assets/linear-FrAcYoA2.js.br +0 -0
  313. package/dist/client/assets/linear-FrAcYoA2.js.gz +0 -0
  314. package/dist/client/assets/mermaid.core-CvYA1lvj.js.br +0 -0
  315. package/dist/client/assets/mermaid.core-CvYA1lvj.js.gz +0 -0
  316. package/dist/client/assets/mindmap-definition-YA3MSWOX-Dclk8rJC.js.br +0 -0
  317. package/dist/client/assets/mindmap-definition-YA3MSWOX-Dclk8rJC.js.gz +0 -0
  318. package/dist/client/assets/passwordBootstrap-DWMjsDcc.js.br +0 -0
  319. package/dist/client/assets/passwordBootstrap-DWMjsDcc.js.gz +0 -0
  320. package/dist/client/assets/pegDiagram-XKGWAZYB-ACqEwiS4.js.br +0 -0
  321. package/dist/client/assets/pegDiagram-XKGWAZYB-ACqEwiS4.js.gz +0 -0
  322. package/dist/client/assets/pieDiagram-E7YTZNPT-p7ypBbNQ.js.br +0 -0
  323. package/dist/client/assets/pieDiagram-E7YTZNPT-p7ypBbNQ.js.gz +0 -0
  324. package/dist/client/assets/quadrantDiagram-AXDQQJYC-DMn4p4aH.js.gz +0 -0
  325. package/dist/client/assets/railroadDiagram-O6MQD6OU-DWdLvY3f.js.br +0 -0
  326. package/dist/client/assets/railroadDiagram-O6MQD6OU-DWdLvY3f.js.gz +0 -0
  327. package/dist/client/assets/rdpSession-AXXpTcnA.js.br +0 -0
  328. package/dist/client/assets/rdpSession-AXXpTcnA.js.gz +0 -0
  329. package/dist/client/assets/referenceLongPress-Bi1LDzVG.js.br +0 -0
  330. package/dist/client/assets/referenceLongPress-Bi1LDzVG.js.gz +0 -0
  331. package/dist/client/assets/requirementDiagram-BXWQKSXE-Dy_QUxq3.js.br +0 -0
  332. package/dist/client/assets/requirementDiagram-BXWQKSXE-Dy_QUxq3.js.gz +0 -0
  333. package/dist/client/assets/sankeyDiagram-P5KCCOFB-HagpiSZn.js.br +0 -0
  334. package/dist/client/assets/sankeyDiagram-P5KCCOFB-HagpiSZn.js.gz +0 -0
  335. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BN1oDRj1.js.br +0 -0
  336. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BN1oDRj1.js.gz +0 -0
  337. package/dist/client/assets/sizeCapture-INFHLROL-CQevvCDc.js.br +0 -0
  338. package/dist/client/assets/sizeCapture-INFHLROL-CQevvCDc.js.gz +0 -0
  339. package/dist/client/assets/stateDiagram-D77RDMKH-CWhm9E8u.js.br +0 -0
  340. package/dist/client/assets/stateDiagram-D77RDMKH-CWhm9E8u.js.gz +0 -0
  341. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DG15Rf80.js +0 -1
  342. package/dist/client/assets/swimlanes-42K2YHIH-BiI3okul.js.br +0 -0
  343. package/dist/client/assets/swimlanes-42K2YHIH-BiI3okul.js.gz +0 -0
  344. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-C4d165Yd.js +0 -8
  345. package/dist/client/assets/timeline-definition-24CTP7MA-CmkDj1rm.js.br +0 -0
  346. package/dist/client/assets/timeline-definition-24CTP7MA-CmkDj1rm.js.gz +0 -0
  347. package/dist/client/assets/vennDiagram-4TSXK5OY-BLDxV0rO.js.br +0 -0
  348. package/dist/client/assets/vennDiagram-4TSXK5OY-BLDxV0rO.js.gz +0 -0
  349. package/dist/client/assets/videoCompression-GVC1hIjh.js.br +0 -0
  350. package/dist/client/assets/videoCompression-GVC1hIjh.js.gz +0 -0
  351. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BWDriNMk.js.br +0 -0
  352. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BWDriNMk.js.gz +0 -0
  353. package/dist/client/assets/xychartDiagram-S5SC5T6Z-Z9KXLnuy.js.br +0 -0
  354. package/dist/client/assets/xychartDiagram-S5SC5T6Z-Z9KXLnuy.js.gz +0 -0
@@ -1,5 +1,6 @@
1
1
  import { CollaborationError } from './collaborationProtocol.js';
2
2
  import { TerminalInputTargetChangedError } from './terminalInput.js';
3
+ import { IntegrationShellWaitError } from './integrationShellWait.js';
3
4
  export function beginLaunchDiagnostics(operation_id, generation, kind) {
4
5
  const now = Date.now();
5
6
  return { operation_id, generation, kind, phase: 'configuration', updated_at: now,
@@ -22,5 +23,6 @@ export function launchFailure(current, error, error_code) {
22
23
  : typeof value?.code === 'string' && standard.has(value.code) ? value.code
23
24
  : typeof value?.message === 'string' && standard.has(value.message) ? value.message : 'UNCLASSIFIED_LAUNCH_ERROR';
24
25
  return { ...current, updated_at: Date.now(), error_code, reason_code,
26
+ ...(error instanceof IntegrationShellWaitError ? { shell_check: structuredClone(error.shellEvidence) } : {}),
25
27
  ...(error instanceof TerminalInputTargetChangedError ? { target_change: error.evidence } : {}) };
26
28
  }
@@ -6,6 +6,7 @@ export function mergeSessionLaunchState(candidate, current, change) {
6
6
  return current ? { ...candidate,
7
7
  agentLaunchGeneration: current.agentLaunchGeneration ?? null,
8
8
  agentLaunchCheck: current.agentLaunchCheck ?? null,
9
+ agentNativeIdentity: current.agentNativeIdentity ?? null,
9
10
  } : candidate;
10
11
  if (!current || (current.agentLaunchGeneration ?? null) !== change.expectedGeneration
11
12
  || (current.agentLaunchCheck?.id ?? null) !== change.expectedCheckId) {
@@ -16,5 +17,38 @@ export function mergeSessionLaunchState(candidate, current, change) {
16
17
  check_phase: 'launch_state_commit', checked_at: Date.now(),
17
18
  });
18
19
  }
19
- return { ...candidate, agentLaunchGeneration: change.generation, agentLaunchCheck: change.check };
20
+ return { ...candidate, agentLaunchGeneration: change.generation, agentLaunchCheck: change.check,
21
+ agentNativeIdentity: change.nativeIdentity === undefined ? current.agentNativeIdentity ?? null : change.nativeIdentity };
22
+ }
23
+ /** A file watcher can finish reading an old snapshot after an in-memory launch
24
+ * or deletion. It must not revert server-owned fields or resurrect that ID. */
25
+ export function mergeReloadedSessionState(disk, beforeRead, current) {
26
+ const before = new Map(beforeRead.map(record => [record.sessionId, record]));
27
+ const live = new Map(current.map(record => [record.sessionId, record]));
28
+ const result = [];
29
+ const seen = new Set();
30
+ for (const candidate of disk) {
31
+ const id = candidate.sessionId, now = live.get(id), old = before.get(id);
32
+ if (seen.has(id) || old && !now)
33
+ continue;
34
+ seen.add(id);
35
+ result.push(now ? JSON.stringify(now) !== JSON.stringify(old) ? now
36
+ : mergeSessionLaunchState(candidate, now) : candidate);
37
+ }
38
+ for (const record of current) {
39
+ if (!seen.has(record.sessionId) && (JSON.stringify(record) !== JSON.stringify(before.get(record.sessionId))
40
+ || record.agentLaunchGeneration || record.agentNativeIdentity))
41
+ result.push(record);
42
+ }
43
+ return result;
44
+ }
45
+ /** Serialize durable global snapshots, taking a fresh value when each write
46
+ * acquires the queue. A delayed old rename must not overwrite a later launch. */
47
+ export function createSessionStateWriter(current, write) {
48
+ let pending = Promise.resolve();
49
+ return () => {
50
+ const next = pending.catch(() => undefined).then(() => write(structuredClone(current())));
51
+ pending = next;
52
+ return next;
53
+ };
20
54
  }
@@ -84,6 +84,20 @@ export class InvitationStore {
84
84
  }
85
85
  }
86
86
  }
87
+ listPending() {
88
+ const now = this.now();
89
+ return this.read().filter(i => i.consumedAt === undefined && i.invitationExpiresAt > now && (i.expiresAt === undefined || i.expiresAt > now))
90
+ .map(({ hash, scope, actions, label, expiresAt, createdAt, invitationExpiresAt }) => ({ id: hash, scope, actions, ...(label ? { label } : {}), ...(expiresAt === undefined ? {} : { expiresAt }), createdAt, invitationExpiresAt }));
91
+ }
92
+ revoke(id) {
93
+ const current = this.read();
94
+ const index = current.findIndex(i => i.hash === id && i.consumedAt === undefined);
95
+ if (index < 0)
96
+ return false;
97
+ current.splice(index, 1);
98
+ this.save(current);
99
+ return true;
100
+ }
87
101
  create(issuerId, input) {
88
102
  requireValid(identity(issuerId));
89
103
  validateInvitation(input);
@@ -103,7 +117,7 @@ export class InvitationStore {
103
117
  const invitation = { ...structuredClone(input), ...(input.label ? { label: input.label.trim() } : {}), hash: this.hash(code), issuerId, createdAt: now, invitationExpiresAt: now + TTL };
104
118
  current.push(invitation);
105
119
  this.save(current);
106
- return { code, expiresAt: invitation.invitationExpiresAt };
120
+ return { invitationId: invitation.hash, code, expiresAt: invitation.invitationExpiresAt };
107
121
  }
108
122
  consume(code, subjectId, issuerAllowed) {
109
123
  if (!/^[A-Za-z0-9_-]{43}$/.test(code) || !identity(subjectId))
@@ -496,7 +496,11 @@ export async function createFederationRuntime(app, directory, handlers, options
496
496
  }
497
497
  else if (packet.type === 'grants-list') {
498
498
  check('authorization.manage');
499
- send({ type: 'result', id: packet.id, grants: store.list(), deviceProfiles: deviceProfiles.list(), subjectLabels: { ...invitations.subjectLabels(), ...deviceNames.list() } });
499
+ send({ type: 'result', id: packet.id, grants: store.list(), invitations: invitations.listPending(), deviceProfiles: deviceProfiles.list(), subjectLabels: { ...invitations.subjectLabels(), ...deviceNames.list() } });
500
+ }
501
+ else if (packet.type === 'invite-revoke') {
502
+ check('authorization.manage');
503
+ send({ type: 'result', id: packet.id, revoked: typeof packet.invitationId === 'string' && invitations.revoke(packet.invitationId) });
500
504
  }
501
505
  else if (packet.type === 'grant') {
502
506
  check('authorization.manage');
@@ -4,7 +4,7 @@ import { isConfirmedEmptyTmuxServer } from '../utils/tmuxEmptyServerProbe.js';
4
4
  import { collaborationSessionDisplayName } from '../utils/sessionDisplayName.js';
5
5
  import { integrationError } from '../agent/integrationStore.js';
6
6
  import { assertNativeResumeAvailable, collectNativeResumeOwnerCandidates } from '../agent/nativeResumeOwner.js';
7
- import { readNativeProcessIdentity } from '../agent/nativeProcessIdentity.js';
7
+ import { nativeIdentityDirectory, readNativeProcessIdentity, resolveProfileNativeIdentity } from '../agent/nativeProcessIdentity.js';
8
8
  import { closeSessionRuntime, foregroundProcessInstance, processStartIdentity } from '../agent/sessionManagement.js';
9
9
  import { releaseSessionRuntime } from '../agent/sessionLifecycle.js';
10
10
  import { resumeConfigurationFingerprint } from '../agent/sessionResumeConfiguration.js';
@@ -59,7 +59,8 @@ import { assessAgentResourceBudget, collectHostResourceSnapshot, configuredAgent
59
59
  import { AutomationStore, normalizeAutomationSchedule } from '../agent/automationStore.js';
60
60
  import { writeBracketedPrompt, canDeliverPromptToAgent } from '../agent/promptDelivery.js';
61
61
  import { captureTerminalInputGuard, captureRuntimeInputGuard, waitAndWriteTerminalInput } from '../agent/terminalInput.js';
62
- import { mergeSessionLaunchState } from '../agent/sessionLaunchState.js';
62
+ import { createSessionStateWriter, mergeReloadedSessionState, mergeSessionLaunchState } from '../agent/sessionLaunchState.js';
63
+ import { waitForIntegrationShell, IntegrationShellWaitError } from '../agent/integrationShellWait.js';
63
64
  import { agentLaunchBlockReason, normalizeAgentLaunchCheck } from '../agent/agentLaunchCheck.js';
64
65
  import { prepareSupervisionEnable } from '../utils/enableSupervision.js';
65
66
  import { buildServerHealthState, dismissServerHealth } from '../utils/serverHealth.js';
@@ -531,12 +532,14 @@ async function migrateFromClientStatesFile() {
531
532
  return null;
532
533
  }
533
534
  }
534
- async function loadGlobalSessionStateFromDisk() {
535
+ async function loadGlobalSessionStateFromDisk(reload = false) {
536
+ const beforeRead = structuredClone(globalSessionState.sessions);
535
537
  try {
536
538
  const data = await readJsonFileIfExists(GLOBAL_SESSION_STATE_FILE);
537
539
  if (data) {
540
+ const sessions = deduplicateGlobalSessions((data.sessions || []).map(s => normalizePersistedClientSession(s)).filter((s) => s !== null));
538
541
  globalSessionState = {
539
- sessions: deduplicateGlobalSessions((data.sessions || []).map(s => normalizePersistedClientSession(s)).filter((s) => s !== null)),
542
+ sessions: reload ? mergeReloadedSessionState(sessions, beforeRead, globalSessionState.sessions) : sessions,
540
543
  updatedAt: typeof data.updatedAt === 'number' ? data.updatedAt : Date.now(),
541
544
  };
542
545
  console.log(`[session-persist] Loaded ${globalSessionState.sessions.length} sessions from global state`);
@@ -587,7 +590,7 @@ async function persistTmuxRecoveryState() {
587
590
  async function reloadGlobalSessionStateFromDisk(source) {
588
591
  try {
589
592
  const previous = JSON.stringify(globalSessionState);
590
- await loadGlobalSessionStateFromDisk();
593
+ await loadGlobalSessionStateFromDisk(true);
591
594
  const next = JSON.stringify(globalSessionState);
592
595
  if (previous === next) {
593
596
  return;
@@ -637,12 +640,13 @@ async function watchGlobalSessionStateFile() {
637
640
  reportFailure('[session-persist] Failed to watch global state file:', error);
638
641
  }
639
642
  }
643
+ const writeGlobalSessionState = createSessionStateWriter(() => globalSessionState, snapshot => writeJsonFile(GLOBAL_SESSION_STATE_FILE, snapshot));
640
644
  function schedulePersistGlobalState() {
641
645
  if (persistGlobalStateTimer)
642
646
  clearTimeout(persistGlobalStateTimer);
643
647
  persistGlobalStateTimer = setTimeout(() => {
644
648
  try {
645
- void writeJsonFile(GLOBAL_SESSION_STATE_FILE, globalSessionState).catch((error) => {
649
+ void writeGlobalSessionState().catch((error) => {
646
650
  console.warn('[session-persist] Failed to persist global state:', getErrorMessage(error));
647
651
  });
648
652
  }
@@ -657,7 +661,7 @@ async function persistGlobalStateNow(strict = false) {
657
661
  persistGlobalStateTimer = null;
658
662
  }
659
663
  try {
660
- await writeJsonFile(GLOBAL_SESSION_STATE_FILE, globalSessionState);
664
+ await writeGlobalSessionState();
661
665
  }
662
666
  catch (error) {
663
667
  console.warn('[session-persist] Failed to persist global state:', getErrorMessage(error));
@@ -1002,6 +1006,8 @@ function normalizePersistedClientSession(input) {
1002
1006
  agentLaunchCheck: normalizeAgentLaunchCheck(candidate.agentLaunchCheck),
1003
1007
  agentLaunchGeneration: typeof candidate.agentLaunchGeneration === 'string' ? candidate.agentLaunchGeneration
1004
1008
  : normalizeAgentLaunchCheck(candidate.agentLaunchCheck)?.id ?? null,
1009
+ agentNativeIdentity: nativeIdentityDirectory(candidate.agentNativeIdentity)
1010
+ ? { kind: 'linux-flock-owner', directory: nativeIdentityDirectory(candidate.agentNativeIdentity) } : null,
1005
1011
  };
1006
1012
  }
1007
1013
  function generateTmuxSessionName() {
@@ -1485,14 +1491,18 @@ function searchMetadataForBackend(backendSessionId, session) {
1485
1491
  updatedAt: session.lastActivity,
1486
1492
  };
1487
1493
  }
1488
- async function beginAgentLaunchCheck(frontendSessionId, agentSlug, nativeSessionId = null) {
1494
+ async function beginAgentLaunchCheck(frontendSessionId, agentSlug, nativeSessionId = null, nativeIdentity) {
1489
1495
  const record = globalSessionState.sessions.find(candidate => candidate.sessionId === frontendSessionId);
1490
1496
  if (!record)
1491
1497
  throw new Error('SESSION_REMOVED');
1492
1498
  const id = randomUUID();
1493
1499
  const updated = upsertGlobalSessionRecord(record, { expectedGeneration: record.agentLaunchGeneration ?? null,
1494
1500
  expectedCheckId: record.agentLaunchCheck?.id ?? null, generation: id,
1495
- check: { id, agentSlug, nativeSessionId, deadline: Date.now() + 120_000 } });
1501
+ check: { id, agentSlug, nativeSessionId, deadline: Date.now() + 120_000 },
1502
+ nativeIdentity: nativeIdentity === undefined
1503
+ ? record.agentResume?.slug === agentSlug || collaborationRouting.get(frontendSessionId)?.agentSlug === agentSlug
1504
+ ? record.agentNativeIdentity ?? null : null
1505
+ : nativeIdentity });
1496
1506
  // Capture the guard before persistence yields. The launch command must use
1497
1507
  // this exact generation, even if another launch occurs during an await.
1498
1508
  const assertCurrent = terminalInputGuard(updated);
@@ -1711,7 +1721,7 @@ function formatLocalCollaborationMessages(frontendSessionId, messages) {
1711
1721
  * agent-keyed selector can never reach it. Delivery still needs an agent (the
1712
1722
  * confirm gate and prompt formatting assume a TUI); driving a terminal —
1713
1723
  * run/capture — is a shell operation and works on any pane. */
1714
- async function inspectCollaborationTmux(binding, requestedPane, allowPlainPane = false, nativeProcessIdentity = false, freshProcess = false, describeNativeFailure = false) {
1724
+ async function inspectCollaborationTmux(binding, requestedPane, allowPlainPane = false, nativeProcessIdentity = false, freshProcess = false, describeNativeFailure = false, identityOverride) {
1715
1725
  if (!binding.tmuxSessionName)
1716
1726
  return { state: 'offline', reason: 'TMUX_BINDING_MISSING' };
1717
1727
  const name = `=${binding.tmuxSessionName}`;
@@ -1737,7 +1747,7 @@ async function inspectCollaborationTmux(binding, requestedPane, allowPlainPane =
1737
1747
  // pane_current_command alone cannot prove an exact resumed conversation.
1738
1748
  const program = await resolveTmuxPaneProgram(pane, true, nativeProcessIdentity || freshProcess);
1739
1749
  const agent = detectAgentFromCommand(program?.rawArgs ?? program?.command ?? '', agentCustomCommands());
1740
- const identity = nativeProcessIdentity ? await observeProgramNativeIdentity(agent, program)
1750
+ const identity = nativeProcessIdentity ? await observeProgramNativeIdentity(agent, program, identityOverride ?? globalSessionState.sessions.find(record => record.sessionId === binding.sessionId)?.agentNativeIdentity ?? undefined)
1741
1751
  : { nativeId: agent && program?.rawArgs ? inferResumeSessionId(agent, splitCommandToArgv(program.rawArgs)) : null, failure: null, source: null };
1742
1752
  if (identity.failure && !describeNativeFailure)
1743
1753
  integrationError(identity.failure === 'NATIVE_SESSION_IDENTITY_CONFLICT'
@@ -2050,6 +2060,37 @@ async function spawnCollaborationAgentSession(req, group, sourceSessionId, input
2050
2060
  async function integrationPaneIsIdleShell(pane) {
2051
2061
  return (await inspectIntegrationShell(pane)).confirmed;
2052
2062
  }
2063
+ function integrationNativeIdentity(record) {
2064
+ if (!record.profile.nativeIdentity)
2065
+ return undefined;
2066
+ if (process.platform !== 'linux')
2067
+ integrationError('SESSION_PROFILE_NATIVE_IDENTITY_UNSUPPORTED', 'Profile writer-lock identity requires Linux', 409);
2068
+ const config = resolveProfileNativeIdentity(record.profile.nativeIdentity, record.cwd);
2069
+ if (!config)
2070
+ integrationError('INVALID_NATIVE_IDENTITY_CONFIG', 'Stored native identity scope is invalid', 409);
2071
+ return config;
2072
+ }
2073
+ async function waitForOwnedIntegrationShell(record, expected) {
2074
+ return waitForIntegrationShell({ expected, async observe() {
2075
+ const terminal = integrationTerminalRecord(record);
2076
+ if (!terminal)
2077
+ return { binding: null, confirmed: false, agent: false, reason: 'RUNTIME_NOT_REGISTERED', pgid: null, tpgid: null };
2078
+ const layout = await getTmuxLayout(terminal.tmuxSessionName);
2079
+ if (layout.windows.flatMap(window => window.panes).length !== 1) {
2080
+ return { binding: null, confirmed: false, agent: false, reason: 'MULTIPLE_TERMINAL_PANES', pgid: null, tpgid: null };
2081
+ }
2082
+ const inspected = await inspectCollaborationTmux({ sessionId: record.session_id, backendSessionId: terminal.backendSessionId,
2083
+ mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: null, nativeSessionId: null, pane: expected }, null, true, false, true);
2084
+ const pane = inspected.pane;
2085
+ if (inspected.state !== 'ready' || !pane)
2086
+ return { binding: null, confirmed: false, agent: false,
2087
+ reason: inspected.reason ?? 'PANE_UNCONFIRMED', pgid: null, tpgid: null };
2088
+ const shell = await inspectIntegrationShell(pane);
2089
+ return { binding: { serverPid: pane.serverPid, sessionId: pane.sessionId, paneId: pane.paneId, panePid: pane.panePid,
2090
+ agentSlug: '', nativeSessionId: null }, confirmed: shell.confirmed, agent: !!pane.agentSlug,
2091
+ reason: pane.isShell ? shell.failure : 'PANE_NOT_SHELL', pgid: shell.pgid, tpgid: shell.tpgid };
2092
+ } });
2093
+ }
2053
2094
  async function inspectIntegrationShell(pane) {
2054
2095
  if (!pane.isShell)
2055
2096
  return { confirmed: false, failure: null, pgid: null, tpgid: null };
@@ -2157,7 +2198,7 @@ async function observeIntegrationCloseTarget(record) {
2157
2198
  if (!record.agent_native_session_id || agent.slug !== record.agent_slug || program?.source !== 'tmux-tty' || !program.processPid) {
2158
2199
  integrationError('SESSION_CLOSE_TARGET_UNCONFIRMED', 'A running Agent requires a live exact native identity', 409);
2159
2200
  }
2160
- const identity = await observeProgramNativeIdentity(agent, program);
2201
+ const identity = await observeProgramNativeIdentity(agent, program, integrationNativeIdentity(record));
2161
2202
  if (identity.failure || identity.nativeId !== record.agent_native_session_id)
2162
2203
  integrationError('SESSION_IDENTITY_MISMATCH', 'Current Agent native identity differs from the owned record', 409);
2163
2204
  kind = 'agent';
@@ -2246,7 +2287,7 @@ export const integrationSessionAdapter = {
2246
2287
  if (!agent || !command)
2247
2288
  integrationError('EXACT_RESUME_UNSUPPORTED', 'Agent must support exact native recovery', 409);
2248
2289
  return { version: 1, slug: agent.slug, aliases: agent.aliases, capabilities: agent.capabilities ?? [],
2249
- resume: getPluginResumeConfig(agent.slug) ?? command, nativeIdentity: getPluginNativeIdentityConfig(agent.slug) ?? null };
2290
+ resume: getPluginResumeConfig(agent.slug) ?? command, nativeIdentity: integrationNativeIdentity(record) ?? getPluginNativeIdentityConfig(agent.slug) ?? null };
2250
2291
  },
2251
2292
  async runtimePresent(record) {
2252
2293
  if (integrationTerminalRecord(record))
@@ -2303,7 +2344,7 @@ export const integrationSessionAdapter = {
2303
2344
  const binding = { sessionId: record.session_id, backendSessionId: terminal.backendSessionId,
2304
2345
  mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: record.agent_slug,
2305
2346
  nativeSessionId: record.agent_native_session_id, pane: record.terminal_binding ?? null };
2306
- const inspected = await inspectCollaborationTmux(binding, undefined, false, true);
2347
+ const inspected = await inspectCollaborationTmux(binding, undefined, false, true, false, false, integrationNativeIdentity(record));
2307
2348
  if (inspected.state === 'offline')
2308
2349
  return { exists: false, running: false, shell: false, agentSlug: null, nativeId: null };
2309
2350
  if (inspected.state !== 'ready' || !inspected.pane)
@@ -2443,7 +2484,7 @@ async function assertIntegrationNativeResumeAvailable(record) {
2443
2484
  return Promise.all(layout.windows.flatMap(window => window.panes).map(async (pane) => {
2444
2485
  const program = await resolveTmuxPaneProgram(pane, true, true);
2445
2486
  const agent = detectAgentFromCommand(program?.rawArgs ?? program?.command ?? '', agentCustomCommands());
2446
- const identity = await observeProgramNativeIdentity(agent, program);
2487
+ const identity = await observeProgramNativeIdentity(agent, program, globalSessionState.sessions.find(record => record.sessionId === candidate.sessionId)?.agentNativeIdentity ?? integrationNativeIdentity(record));
2447
2488
  const shell = await inspectIntegrationShell({ panePid: pane.pid,
2448
2489
  isShell: !agent && shellNamesBackend.has(normalizeProgramName(program?.command ?? '')?.toLowerCase() ?? '') });
2449
2490
  return { confirmed: !identity.failure && (shell.confirmed || program?.source === 'tmux-tty' && Boolean(program.rawArgs)),
@@ -2512,13 +2553,17 @@ async function launchIntegrationTerminal(record, restoring, prepared, progress,
2512
2553
  mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: null, nativeSessionId: null,
2513
2554
  // A recreated tmux may get a new pane only during explicit exact resume.
2514
2555
  pane: original.exists ? record.terminal_binding ?? null : null }, null, true);
2515
- if (inspected.state !== 'ready' || !inspected.pane || !await integrationPaneIsIdleShell(inspected.pane))
2516
- integrationError('SESSION_TARGET_NOT_SHELL', 'Refusing to launch into an unverified shell', 409);
2556
+ if (inspected.state !== 'ready' || !inspected.pane)
2557
+ throw new IntegrationShellWaitError('SESSION_TARGET_NOT_SHELL', {
2558
+ samples: 1, waited_ms: 0, reason: inspected.reason ?? 'PANE_UNCONFIRMED', binding: null, pgid: null, tpgid: null
2559
+ });
2517
2560
  const pane = inspected.pane;
2518
2561
  const pinned = { serverPid: pane.serverPid, sessionId: pane.sessionId,
2519
2562
  paneId: pane.paneId, panePid: pane.panePid, agentSlug: record.agent_slug, nativeSessionId: record.agent_native_session_id };
2520
2563
  progress?.('binding_persist');
2521
2564
  prepared(pinned); // Must persist before the command enters the terminal.
2565
+ progress?.('runtime_shell_wait');
2566
+ await waitForOwnedIntegrationShell(record, pinned);
2522
2567
  collaborationRouting.bind({ sessionId: record.session_id, backendSessionId: opened.terminalSession.sessionId,
2523
2568
  mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: record.agent_slug, nativeSessionId: record.agent_native_session_id, pane: pinned });
2524
2569
  const latest = collaborationStore.getGroup(group.id);
@@ -2540,17 +2585,14 @@ async function launchIntegrationTerminal(record, restoring, prepared, progress,
2540
2585
  await assertIntegrationNativeResumeAvailable(record);
2541
2586
  }
2542
2587
  progress?.('runtime_verify');
2543
- const shell = await inspectCollaborationTmux({ sessionId: record.session_id, backendSessionId: opened.terminalSession.sessionId,
2544
- mode: 'tmux', tmuxSessionName: terminal.tmuxSessionName, agentSlug: null, nativeSessionId: null, pane: pinned });
2545
- if (shell.state !== 'ready' || !shell.pane || !await integrationPaneIsIdleShell(shell.pane))
2546
- integrationError('SESSION_TARGET_NOT_SHELL', 'Owned shell changed before launch', 409);
2588
+ await waitForOwnedIntegrationShell(record, pinned);
2547
2589
  // This owned pane is a verified shell; clear stale rich state before a new
2548
2590
  // process starts, so its new SessionStart must supply the native binding.
2549
2591
  backend.agentSession = null;
2550
2592
  backend.agent = null;
2551
2593
  backend.agentResumeRecovered = false;
2552
2594
  progress?.('launch_intent');
2553
- const launchGuard = await beginAgentLaunchCheck(record.session_id, record.agent_slug, restoring ? record.agent_native_session_id : null);
2595
+ const launchGuard = await beginAgentLaunchCheck(record.session_id, record.agent_slug, restoring ? record.agent_native_session_id : null, integrationNativeIdentity(record) ?? null);
2554
2596
  await writeAutomaticTerminalPrompt(record.session_id, integrationLaunchCommand(record, restoring), progress, launchGuard);
2555
2597
  broadcastClientState();
2556
2598
  });
@@ -3172,10 +3214,22 @@ async function observeTmuxServerGeneration(liveTmuxSessions, authoritativeTmuxLi
3172
3214
  return;
3173
3215
  }
3174
3216
  const liveSessionNames = new Set(liveTmuxSessions.map((session) => session.name));
3217
+ const liveTmuxByName = new Map(liveTmuxSessions.map(session => [session.name, session]));
3218
+ const restoredSessionIds = new Set();
3175
3219
  const candidates = globalSessionState.sessions.flatMap((record) => {
3176
3220
  if (record.mode !== 'tmux' || !record.tmuxSessionName)
3177
3221
  return [];
3178
3222
  const backend = record.backendSessionId ? terminalSessions.get(record.backendSessionId) : null;
3223
+ const live = liveTmuxByName.get(record.tmuxSessionName);
3224
+ // rawArgs comes from the refreshed foreground probe, not persisted tmux
3225
+ // options. A live shell alone does not prove its Agent was restored.
3226
+ const liveAgent = live?.rawArgs
3227
+ ? detectAgentFromCommand(live.rawArgs, agentCustomCommands())
3228
+ : null;
3229
+ if (live && record.agentResume?.slug
3230
+ && (liveAgent?.slug === record.agentResume.slug || backend?.agent?.slug === record.agentResume.slug)) {
3231
+ restoredSessionIds.add(record.sessionId);
3232
+ }
3179
3233
  return [{
3180
3234
  sessionId: record.sessionId,
3181
3235
  tmuxSessionName: record.tmuxSessionName,
@@ -3191,6 +3245,7 @@ async function observeTmuxServerGeneration(liveTmuxSessions, authoritativeTmuxLi
3191
3245
  liveSessionNames,
3192
3246
  intentionallyDeleting: intentionallyDeletingTmuxSessions,
3193
3247
  existingIncident: tmuxRecoveryState.incident,
3248
+ restoredSessionIds,
3194
3249
  // Apply acknowledgements before rearming sessions observed alive in this scan.
3195
3250
  dismissedSessionIds: new Set(tmuxRecoveryState.dismissedSessionIds),
3196
3251
  });
@@ -3200,7 +3255,7 @@ async function observeTmuxServerGeneration(liveTmuxSessions, authoritativeTmuxLi
3200
3255
  tmuxRecoveryState.incident = incident;
3201
3256
  changed = true;
3202
3257
  if (incident) {
3203
- console.error(`[tmux-recovery] shared server loss detected; ${incident.affectedSessionIds.length} Agent session(s) can be restored`);
3258
+ console.warn(`[tmux-recovery] session recovery pending; ${incident.affectedSessionIds.length} Agent session(s) can be restored`);
3204
3259
  }
3205
3260
  }
3206
3261
  if (currentServerPid !== null && currentServerPid !== tmuxRecoveryState.lastServerPid) {
@@ -3227,7 +3282,6 @@ async function buildSessionInventory() {
3227
3282
  liveTmuxSessions = [];
3228
3283
  }
3229
3284
  }
3230
- await observeTmuxServerGeneration(liveTmuxSessions, authoritativeTmuxList);
3231
3285
  const refreshedTmuxSessions = await Promise.all(liveTmuxSessions.map(async (tmux) => {
3232
3286
  if (!isTermdockManagedTmuxSession(tmux)) {
3233
3287
  return tmux;
@@ -3253,6 +3307,7 @@ async function buildSessionInventory() {
3253
3307
  return tmux;
3254
3308
  }
3255
3309
  }));
3310
+ await observeTmuxServerGeneration(refreshedTmuxSessions, authoritativeTmuxList);
3256
3311
  const liveTmuxByName = new Map(refreshedTmuxSessions.map((session) => [session.name, session]));
3257
3312
  let synchronizedPersistedFields = false;
3258
3313
  globalSessionState = {
@@ -4519,9 +4574,9 @@ async function resolveTmuxPaneProgram(pane, requireArgs = false, refreshTty = fa
4519
4574
  }
4520
4575
  return { command, source: 'tmux-pane', rawArgs: null };
4521
4576
  }
4522
- async function observeProgramNativeIdentity(agent, program) {
4577
+ async function observeProgramNativeIdentity(agent, program, override) {
4523
4578
  const fromArgs = agent && program?.rawArgs ? inferResumeSessionId(agent, splitCommandToArgv(program.rawArgs)) : null;
4524
- const config = agent ? getPluginNativeIdentityConfig(agent.slug) : undefined;
4579
+ const config = agent ? override ?? getPluginNativeIdentityConfig(agent.slug) : undefined;
4525
4580
  if (config && program?.processPid) {
4526
4581
  const proof = await readNativeProcessIdentity(program.processPid, config, program.processComm, program.rawArgs ?? undefined);
4527
4582
  if (proof.outcome === 'ambiguous' || proof.outcome === 'process_changed' || proof.outcome === 'unconfirmed')
@@ -4533,7 +4588,11 @@ async function observeProgramNativeIdentity(agent, program) {
4533
4588
  return { nativeId: null, source: null, failure: 'NATIVE_SESSION_IDENTITY_CONFLICT' };
4534
4589
  return { nativeId: proof.nativeId, source: 'linux-flock-owner', failure: null };
4535
4590
  }
4591
+ if (override)
4592
+ return { nativeId: null, source: null, failure: 'NATIVE_SESSION_OWNERSHIP_UNCONFIRMED' };
4536
4593
  }
4594
+ if (override && agent)
4595
+ return { nativeId: null, source: null, failure: 'NATIVE_SESSION_OWNERSHIP_UNCONFIRMED' };
4537
4596
  return { nativeId: fromArgs, source: fromArgs ? 'argv' : null, failure: null };
4538
4597
  }
4539
4598
  /**
@@ -20,25 +20,32 @@ export function detectTmuxRecoveryIncident(input) {
20
20
  // A failed/disabled inventory is an unknown observation, never evidence of loss.
21
21
  if (!input.authoritativeTmuxList)
22
22
  return input.existingIncident ?? null;
23
- if (input.existingIncident)
24
- return input.existingIncident;
25
23
  const intentionallyDeleting = input.intentionallyDeleting ?? new Set();
26
24
  const recoverable = input.candidates.filter((candidate) => candidate.resumable
27
25
  && !input.dismissedSessionIds?.has(candidate.sessionId)
26
+ && !input.restoredSessionIds?.has(candidate.sessionId)
28
27
  && !intentionallyDeleting.has(candidate.tmuxSessionName));
29
28
  const missing = recoverable.filter((candidate) => !input.liveSessionNames.has(candidate.tmuxSessionName));
30
- if (recoverable.length === 0)
31
- return null;
32
- const knownTmuxCount = input.candidates.filter((candidate) => !intentionallyDeleting.has(candidate.tmuxSessionName)).length;
33
- const serverGenerationChanged = input.previousServerPid !== null
34
- && input.currentServerPid !== input.previousServerPid;
35
- const bulkLoss = knownTmuxCount >= 2
36
- && input.liveSessionNames.size === 0
37
- && missing.length >= 1;
38
- if (!serverGenerationChanged && !bulkLoss && missing.length === 0)
39
- return null;
40
- const affected = serverGenerationChanged ? recoverable : missing;
41
- if (affected.length === 0)
29
+ const existingIncident = input.existingIncident;
30
+ if (existingIncident) {
31
+ const eligibleIds = new Set(recoverable.map(candidate => candidate.sessionId));
32
+ // A recreated shell still needs recovery. Only a verified running Agent,
33
+ // removed record or explicit acknowledgement can retire its old entry.
34
+ const affectedSessionIds = Array.from(new Set([
35
+ ...existingIncident.affectedSessionIds.filter(id => eligibleIds.has(id)),
36
+ ...missing.map(candidate => candidate.sessionId),
37
+ ]));
38
+ if (affectedSessionIds.length === 0)
39
+ return null;
40
+ if (affectedSessionIds.length === existingIncident.affectedSessionIds.length
41
+ && affectedSessionIds.every((id, index) => id === existingIncident.affectedSessionIds[index])) {
42
+ return existingIncident;
43
+ }
44
+ return { ...existingIncident, affectedSessionIds };
45
+ }
46
+ // A PID change is diagnostic context, not proof of session loss or a crash.
47
+ // Require an actually missing session before creating a recovery incident.
48
+ if (missing.length === 0)
42
49
  return null;
43
50
  const now = input.now ?? Date.now();
44
51
  return {
@@ -46,7 +53,7 @@ export function detectTmuxRecoveryIncident(input) {
46
53
  detectedAt: now,
47
54
  previousServerPid: input.previousServerPid,
48
55
  currentServerPid: input.currentServerPid,
49
- affectedSessionIds: affected.map((candidate) => candidate.sessionId),
56
+ affectedSessionIds: missing.map((candidate) => candidate.sessionId),
50
57
  };
51
58
  }
52
59
  // A dismissed loss stays acknowledged until that session is observed alive
@@ -1354,3 +1354,32 @@ flock-owner 身份独立核验出原 agent slug 与原生 UUID。目标元组会
1354
1354
  fail-closed,旧绑定与原消息保留,`session get` 仍报告身份错误;不会按 tmux 名称、PID
1355
1355
  缓存、cwd、argv 中的 resume 参数或显示名猜测认领。此 capability 不新增权限;仅通过
1356
1356
  `session.read` 认证的所属 principal 可触发其自身记录的对账。
1357
+
1358
+ ## 1.4.346:启动磁盘重载、原 shell 核验与独立原生目录
1359
+
1360
+ 最低 CLI / 实际服务均为 **1.4.346**。通过所属 principal 的 `capabilities` 回读:
1361
+
1362
+ - `session_launch_reload_fence=true`:服务运行期间的磁盘重载保留当前服务生成的 launch token、已解除的一次性 check 和显式原生目录。读取期间新增的会话不会消失,已删除的会话不会由旧读盘复活;全局状态写入串行,并在执行写入时采集当前快照。服务首次启动仍加载磁盘记录。这修复了磁盘 watch 路径绕过元数据 upsert 保护的缺口,不把每一例历史 `TERMINAL_INPUT_TARGET_CHANGED` 都归因为此。
1363
+ - `session_shell_startup_wait=true`:启动前先记录唯一原 pane 身份,再最多等待 5 秒核实该 shell 的前台关系和合格 shell 参数。只观察同一 tmux server/session/pane/PID,采样使用新鲜进程证据;承载改变、pane 不唯一或已有 Agent 时拒绝。不输入探针、不清理画面、不重建承载、不发送额外回车,也不把 shell 核验当成应用 input-ready。
1364
+ - `session_profile_native_identity=true`:当前仅 Linux 支持 profile 级只读 writer-lock 目录,覆盖该受管会话的插件缺省目录,不改变共享插件配置。三个字段分别有同名 `_min_version` 字段,值为 `1.4.346`。能力支持不等于 principal 已被授予权限。
1365
+
1366
+ 本机管理员可在现有完整 policy 的目标 `launchProfiles` 中加:
1367
+
1368
+ ```json
1369
+ "nativeIdentity": {
1370
+ "kind": "linux-flock-owner",
1371
+ "directory": "{cwd}/.agent-home/cli/thread-writer-locks"
1372
+ }
1373
+ ```
1374
+
1375
+ 目录是示例,必须按实际 Agent 的持锁协议填写。支持管理员指定的绝对目录、`~/` 目录,以及仅以前缀 `{cwd}/` 锚定的模板;模板不允许 `..` 或其它变量,解析后的目录须在 TD 服务用户 home 内。调用现有 `td integration update --file <完整policy.json>`,不增加权限、不重建 principal 或凭据。CLI 在旧服务/非 Linux 服务上拒绝该配置,不能静默忽略。原有不配置此项的 profile 保持插件缺省行为。
1376
+
1377
+ wrapper 负责实际设置 Agent 自己的数据目录、准备 hooks/参数,并最终运行真正的 Agent;这个字段只声明 TD 的核验目录,不设置环境、不执行脚本、不创建目录,不自动读取 `TRAECLI_HOME` 等私有变量。TD 仍检查目录与文件权限、进程 starttime、前台关系、实际 FD/inode 和当前内核 flock,要求唯一 native UUID。显式 profile 目录不可证明时不降级到 argv/hook/旧 UUID,多个持锁 UUID 仍拒绝。目录语义纳入恢复配置指纹,保存至启动代次;服务重启、metadata 更新、check 解除不会丢失它。
1378
+
1379
+ 该配置只用于之后创建的 session;旧 session 保留原 profile 快照,policy update 不迁移旧记录或修改运行 Agent。不要为旧未知结果自动 create 新 ID 或 retry-cold。原 UUID 恢复、重复 owner 保护、关闭仍遵守现有身份/代次/幂等门禁;独立数据目录不构成对同 UID 进程的安全隔离。
1380
+
1381
+ 启动失败管理员用 `td integration diagnostics <原TD-ID>` 回读;shell 等待失败新增 `shell_check={samples,waited_ms,reason,binding,pgid,tpgid}`,不包含 argv/env/终端正文。`SESSION_TARGET_NOT_SHELL` 表示有限核验未通过,不表示 wrapper 已执行;`paste/submit=not_attempted` 与后续 `runtime_present` 现场回读分开保存。失败不自动再次启动,只有符合原 `session retry-cold` 所有条件才可明确重试。
1382
+
1383
+ 用 stdin 文件给启动命令附带业务 prompt 是接入方的 bootstrap:TD 不为其中业务副作用提供消息幂等或执行确认;无 TD message 历史也不等于没有业务执行。冷启动与精确 resume 应分开处理,恢复时不得重放初始业务文件。host 收取 final/hook receipt 是 host 侧证据,不伪造成 TD 明确 reply。仍只粘贴一次、等待 50ms、写一次 CR。
1384
+
1385
+ 回归包含确定性交错的旧读盘覆盖/串行写入/删除不复活、同 pane shell 初始化等待与超时/换 pane/已有 Agent 拒绝、CLI 对旧服务拒绝,以及 Linux 真实 tmux/内核 flock 的独立目录核验。私有 TraeX/DevBox 的启动兼容仍需接入方维护窗实机验证;维护机合成测试不冒充该项通过。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termdock",
3
- "version": "1.4.344",
3
+ "version": "1.4.346",
4
4
  "description": "A complete web-based terminal application with modern UI",
5
5
  "type": "module",
6
6
  "main": ".desktop-dist/main.js",
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "packageName": "termdock",
4
- "version": "1.4.344",
4
+ "version": "1.4.346",
5
5
  "runtimeProtocolVersion": 1,
6
6
  "minimumDesktopVersion": "1.4.46",
7
7
  "nodeMajor": 22,
8
8
  "dependencyHash": "sha256-ObG1OGq7e7fMFQmYoPxPp3jRodEusYHulVNa5mT1aW8=",
9
- "serverBundleHash": "sha256-Ln+odmvyZxmEopnizE6Y2RlGc4cLxM5xteZJrN6nbRY=",
10
- "clientBundleHash": "sha256-9mUE4GR3rOA1F3MoVEnmhS4q7PvQbqF2Shdl5wlbbrk=",
9
+ "serverBundleHash": "sha256-14J5QvRzetON18qbhx5HXdLAx08WrjndjMlOCMpgfOc=",
10
+ "clientBundleHash": "sha256-kn3Tg+BTj+H4rZe0g9OE5JUEQNsBGiUSGew8Epm5A38=",
11
11
  "entrypoint": "dist/server/cli.js",
12
12
  "clientEntrypoint": "dist/client/index.html"
13
13
  }
@@ -1,2 +0,0 @@
1
- import{bA as r}from"./app-VY9J50Vn.js";import{b as m}from"./dnd-BCFAPC0L.js";import{b as n}from"./RightSidebar-CdEMgc2G.js";import"./react-XDCjal2T.js";import"./terminal-Dea8wJF3.js";import"./App-7PpqNtmr.js";import"./gestureArbiter-ZMwmrdcg.js";import"./triangle-alert-oEokybAQ.js";import"./referenceLongPress-Bi1LDzVG.js";import"./DiffReview-BshWCx_C.js";import"./sparkles-CzTc2Jfu.js";import"./DiffViewer--QG609jF.js";import"./ChangeWalkthroughPanel-DMX0seQh.js";function g({content:o}){const e=m.useMemo(()=>n(o.split(`
2
- `),null,null),[o]);return r.jsx("div",{className:"min-w-0 space-y-3 break-words text-sm leading-6 text-foreground [&_h1]:text-lg [&_h2]:text-base [&_h3]:text-sm [&_pre]:max-w-full [&_table]:text-xs",children:e.map((t,i)=>r.jsx("div",{className:"min-w-0",children:typeof t.content=="function"?t.content(null):t.content},i))})}export{g as default};