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.
- package/dist/client/assets/{App-7PpqNtmr.js → App-BN_iuuvE.js} +6 -6
- package/dist/client/assets/App-BN_iuuvE.js.br +0 -0
- package/dist/client/assets/App-BN_iuuvE.js.gz +0 -0
- package/dist/client/assets/{ArchitecturePanel-BeGg_w36.js → ArchitecturePanel-sTwptDpa.js} +2 -2
- package/dist/client/assets/ArchitecturePanel-sTwptDpa.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-sTwptDpa.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-DMX0seQh.js → ChangeWalkthroughPanel-DvOSOwLu.js} +1 -1
- package/dist/client/assets/ChangeWalkthroughPanel-DvOSOwLu.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-DvOSOwLu.js.gz +0 -0
- package/dist/client/assets/{CollaborationMainWorkspace-EM8iRchZ.js → CollaborationMainWorkspace-DseFwFSR.js} +1 -1
- package/dist/client/assets/CollaborationMainWorkspace-DseFwFSR.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-DseFwFSR.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-DL4Im2wQ.js +2 -0
- package/dist/client/assets/{ComputerControlView-qpYuVzPh.js → ComputerControlView-CWlfdXhY.js} +3 -3
- package/dist/client/assets/ComputerControlView-CWlfdXhY.js.br +0 -0
- package/dist/client/assets/ComputerControlView-CWlfdXhY.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-CK7VBLZx.js → DagPlayground-B1IytHVy.js} +1 -1
- package/dist/client/assets/DagPlayground-B1IytHVy.js.br +0 -0
- package/dist/client/assets/DagPlayground-B1IytHVy.js.gz +0 -0
- package/dist/client/assets/{DiffLab-oKSML0WX.js → DiffLab-B6gSsPoJ.js} +1 -1
- package/dist/client/assets/DiffLab-B6gSsPoJ.js.br +0 -0
- package/dist/client/assets/DiffLab-B6gSsPoJ.js.gz +0 -0
- package/dist/client/assets/{DiffReview-BshWCx_C.js → DiffReview-BYI8gVYo.js} +1 -1
- package/dist/client/assets/DiffReview-BYI8gVYo.js.br +0 -0
- package/dist/client/assets/DiffReview-BYI8gVYo.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-QyzjteoK.js → DiffReviewLab-BYUQFzsG.js} +1 -1
- package/dist/client/assets/DiffReviewLab-BYUQFzsG.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-BYUQFzsG.js.gz +0 -0
- package/dist/client/assets/{DiffViewer--QG609jF.js → DiffViewer-P1mbq4LM.js} +1 -1
- package/dist/client/assets/DiffViewer-P1mbq4LM.js.br +0 -0
- package/dist/client/assets/DiffViewer-P1mbq4LM.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-BY-nllCI.js → ModelPreview-BpIynSeJ.js} +1 -1
- package/dist/client/assets/ModelPreview-BpIynSeJ.js.br +0 -0
- package/dist/client/assets/ModelPreview-BpIynSeJ.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-CdEMgc2G.js → RightSidebar-DyX2uyW6.js} +47 -45
- package/dist/client/assets/RightSidebar-DyX2uyW6.js.br +0 -0
- package/dist/client/assets/RightSidebar-DyX2uyW6.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-D_YYeniU.js → abnfDiagram-VCTEODGH-Cjq0zd9z.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-Cjq0zd9z.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-Cjq0zd9z.js.gz +0 -0
- package/dist/client/assets/app-HTVDUkx-.js +35 -0
- package/dist/client/assets/app-HTVDUkx-.js.br +0 -0
- package/dist/client/assets/app-HTVDUkx-.js.gz +0 -0
- package/dist/client/assets/{arc-sDYgQVIO.js → arc-DkPjbARe.js} +1 -1
- package/dist/client/assets/arc-DkPjbARe.js.br +0 -0
- package/dist/client/assets/arc-DkPjbARe.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-mzycNt3i.js → architectureDiagram-5GKGNRK7-DvErYV6b.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DvErYV6b.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DvErYV6b.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-CmBIG7tu.js → blockDiagram-I7D4REHJ-Bds9HO1o.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-Bds9HO1o.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-Bds9HO1o.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-CyaMSX6v.js → c4Diagram-7LVT6UL2-C2OH1wSt.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-C2OH1wSt.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-C2OH1wSt.js.gz +0 -0
- package/dist/client/assets/channel-CdhDWMew.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-BDL3ltwl.js → chunk-2Q5K7J3B-DVaF1NsT.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-BlxmnqT8.js → chunk-5VM5RSS4-Dkbpeqfb.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-C23_F1Qb.js → chunk-F27PBJKO-CRPAOyuh.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-CRPAOyuh.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-CRPAOyuh.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-BNhZFCbM.js → chunk-IMKFNOWR-CphgPwod.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-CphgPwod.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-CphgPwod.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-BKtQVfYl.js → chunk-JWPE2WC7-CWlXUB6G.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-DU-TCVcH.js → chunk-POPQ4Y6H-BAAz8QH8.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-CeD3DY62.js → chunk-SVP7TREG-C9qRACkp.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-C9qRACkp.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-C9qRACkp.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-C7EI51Ae.js → chunk-TICWLB2K-CAn30A5F.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-CAn30A5F.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CAn30A5F.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-CO7EB_T2.js → chunk-XXDRQBXY-i2tZFJ9V.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-_NMbO90f.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-_NMbO90f.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-CN8cwue3.js → cose-bilkent-JH36ORCC-_ejU8hPT.js} +1 -1
- package/dist/client/assets/{cose-bilkent-JH36ORCC-CN8cwue3.js.br → cose-bilkent-JH36ORCC-_ejU8hPT.js.br} +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-_ejU8hPT.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-ZJmZp774.js → cynefin-OW5HDTMX-BkzgMwVY.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-BkzgMwVY.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-BkzgMwVY.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-C-O7V1Tk.js → cynefinDiagram-5FMLGOSQ-f623ycDk.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-f623ycDk.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-f623ycDk.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-CgNLkZqS.js → dagre-GXQ25YYZ-CZKJoNzx.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-CZKJoNzx.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CZKJoNzx.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-_e0IES0l.js → diagram-S7CK7UJ4-C4Sjb6W8.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-C4Sjb6W8.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-C4Sjb6W8.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-IknuU7gc.js → diagram-UQ7AKVKN-Buov_WHB.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-Buov_WHB.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-Buov_WHB.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-xp0eP0gd.js → diagram-VSXAHHWV-B3v-ZnXu.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-B3v-ZnXu.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-B3v-ZnXu.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-YM3d3Rh5.js → diagram-VX7I27RA-DCEWE8mj.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-DCEWE8mj.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-DCEWE8mj.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-vjaumOKc.js → diagram-Z3DM3KII-bK4WKBJF.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-bK4WKBJF.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-bK4WKBJF.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-DL19bAk6.js → ebnfDiagram-PWID7BFC-wOu6iW76.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-wOu6iW76.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-wOu6iW76.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-CL8YGnYl.js → erDiagram-RLTQ6QDP-D83VmrYf.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-D83VmrYf.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-D83VmrYf.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-Dmxmmzef.js → flowDiagram-HODETNUW-DCxfJLXu.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-DCxfJLXu.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-DCxfJLXu.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-Cg95sExn.js → ganttDiagram-EL5Y4UJY-CF9XnXOS.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CF9XnXOS.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CF9XnXOS.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-ZMwmrdcg.js → gestureArbiter-DOugsAle.js} +1 -1
- package/dist/client/assets/gestureArbiter-DOugsAle.js.br +0 -0
- package/dist/client/assets/gestureArbiter-DOugsAle.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-BhPjxbUY.js → gitGraphDiagram-WWUBYQGX-jT8-SkeT.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-jT8-SkeT.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-jT8-SkeT.js.gz +0 -0
- package/dist/client/assets/{index-A-ZC9mbr.css → index-DtPsPZ7W.css} +1 -1
- package/dist/client/assets/index-DtPsPZ7W.css.br +0 -0
- package/dist/client/assets/{index-A-ZC9mbr.css.gz → index-DtPsPZ7W.css.gz} +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-J73ysnHU.js → infoDiagram-27XIBGKW-B-LDzk7Q.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-DYno2wlU.js → ishikawaDiagram-5VMMS53U-CsosD6UL.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CsosD6UL.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CsosD6UL.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-D1i0ft78.js → journeyDiagram-3NMN7TZE-Bv5RcxaN.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-Bv5RcxaN.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-Bv5RcxaN.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-dO2PhUIk.js → kanban-definition-UXKFOSKX-D1ukvOoH.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-D1ukvOoH.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-D1ukvOoH.js.gz +0 -0
- package/dist/client/assets/{layout-DmeRjjIH.js → layout-VC45eUZy.js} +1 -1
- package/dist/client/assets/layout-VC45eUZy.js.br +0 -0
- package/dist/client/assets/layout-VC45eUZy.js.gz +0 -0
- package/dist/client/assets/{linear-FrAcYoA2.js → linear-C3VBb8xa.js} +1 -1
- package/dist/client/assets/linear-C3VBb8xa.js.br +0 -0
- package/dist/client/assets/linear-C3VBb8xa.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-CvYA1lvj.js → mermaid.core-DG2QUI-L.js} +5 -5
- package/dist/client/assets/mermaid.core-DG2QUI-L.js.br +0 -0
- package/dist/client/assets/mermaid.core-DG2QUI-L.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-Dclk8rJC.js → mindmap-definition-YA3MSWOX-CpA9V0iU.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-CpA9V0iU.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-CpA9V0iU.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-DWMjsDcc.js → passwordBootstrap-DILrqabi.js} +1 -1
- package/dist/client/assets/passwordBootstrap-DILrqabi.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-DILrqabi.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-ACqEwiS4.js → pegDiagram-XKGWAZYB-C7OQC7uD.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-C7OQC7uD.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-C7OQC7uD.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-p7ypBbNQ.js → pieDiagram-E7YTZNPT-Ot6_RqeC.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-Ot6_RqeC.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-Ot6_RqeC.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-DMn4p4aH.js → quadrantDiagram-AXDQQJYC-Bf7jut-u.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-DMn4p4aH.js.br → quadrantDiagram-AXDQQJYC-Bf7jut-u.js.br} +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-Bf7jut-u.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-DWdLvY3f.js → railroadDiagram-O6MQD6OU-WrpZgg8t.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-WrpZgg8t.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-WrpZgg8t.js.gz +0 -0
- package/dist/client/assets/{rdpSession-AXXpTcnA.js → rdpSession-D5nvZxrU.js} +1 -1
- package/dist/client/assets/rdpSession-D5nvZxrU.js.br +0 -0
- package/dist/client/assets/rdpSession-D5nvZxrU.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-Bi1LDzVG.js → referenceLongPress-C6YZh55M.js} +1 -1
- package/dist/client/assets/referenceLongPress-C6YZh55M.js.br +0 -0
- package/dist/client/assets/referenceLongPress-C6YZh55M.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-Dy_QUxq3.js → requirementDiagram-BXWQKSXE-DSDgL_p4.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DSDgL_p4.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DSDgL_p4.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-HagpiSZn.js → sankeyDiagram-P5KCCOFB-C_ytO8Ty.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-C_ytO8Ty.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-C_ytO8Ty.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-BN1oDRj1.js → sequenceDiagram-WJ2MYXX4-DhZKcw8h.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DhZKcw8h.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DhZKcw8h.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-CQevvCDc.js → sizeCapture-INFHLROL-BM1PVyhM.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-BM1PVyhM.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-BM1PVyhM.js.gz +0 -0
- package/dist/client/assets/{sparkles-CzTc2Jfu.js → sparkles-BONmCbTi.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-CWhm9E8u.js → stateDiagram-D77RDMKH-BJ9RE6YD.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-BJ9RE6YD.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BJ9RE6YD.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BMIQgRVo.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-BiI3okul.js → swimlanes-42K2YHIH-CM-hxgek.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-CM-hxgek.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-CM-hxgek.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-BS47Goc0.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-CmkDj1rm.js → timeline-definition-24CTP7MA--ZFOA2ds.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA--ZFOA2ds.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA--ZFOA2ds.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-oEokybAQ.js → triangle-alert-B-7heGu-.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-BLDxV0rO.js → vennDiagram-4TSXK5OY-CAKGCM6V.js} +1 -1
- package/dist/client/assets/vennDiagram-4TSXK5OY-CAKGCM6V.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CAKGCM6V.js.gz +0 -0
- package/dist/client/assets/{videoCompression-GVC1hIjh.js → videoCompression-D8Kt2prC.js} +1 -1
- package/dist/client/assets/videoCompression-D8Kt2prC.js.br +0 -0
- package/dist/client/assets/videoCompression-D8Kt2prC.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-BWDriNMk.js → wardleyDiagram-VM6X3IG4-5g9ZJdVF.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-5g9ZJdVF.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-5g9ZJdVF.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-Z9KXLnuy.js → xychartDiagram-S5SC5T6Z-CJ1hIdXS.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-CJ1hIdXS.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-CJ1hIdXS.js.gz +0 -0
- package/dist/client/index.html +2 -2
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/sw.js +1 -1
- package/dist/client/sw.js.br +0 -0
- package/dist/client/sw.js.gz +0 -0
- package/dist/server/agent/collaborationCli.js +3 -0
- package/dist/server/agent/integrationCli.js +16 -2
- package/dist/server/agent/integrationServer.js +4 -1
- package/dist/server/agent/integrationShellWait.js +33 -0
- package/dist/server/agent/integrationStore.js +4 -0
- package/dist/server/agent/nativeProcessIdentity.js +21 -0
- package/dist/server/agent/sessionLaunchDiagnostics.js +2 -0
- package/dist/server/agent/sessionLaunchState.js +35 -1
- package/dist/server/federation/invitations.js +15 -1
- package/dist/server/federation/runtime.js +5 -1
- package/dist/server/routes/terminal.js +85 -26
- package/dist/server/utils/tmuxRecovery.js +22 -15
- package/docs/integrations.md +29 -0
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- package/dist/client/assets/App-7PpqNtmr.js.br +0 -0
- package/dist/client/assets/App-7PpqNtmr.js.gz +0 -0
- package/dist/client/assets/ArchitecturePanel-BeGg_w36.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-BeGg_w36.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-DMX0seQh.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-DMX0seQh.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-EM8iRchZ.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-EM8iRchZ.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-D_5vDZEM.js +0 -2
- package/dist/client/assets/ComputerControlView-qpYuVzPh.js.br +0 -0
- package/dist/client/assets/ComputerControlView-qpYuVzPh.js.gz +0 -0
- package/dist/client/assets/DagPlayground-CK7VBLZx.js.br +0 -0
- package/dist/client/assets/DagPlayground-CK7VBLZx.js.gz +0 -0
- package/dist/client/assets/DiffLab-oKSML0WX.js.br +0 -0
- package/dist/client/assets/DiffLab-oKSML0WX.js.gz +0 -0
- package/dist/client/assets/DiffReview-BshWCx_C.js.br +0 -0
- package/dist/client/assets/DiffReview-BshWCx_C.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-QyzjteoK.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-QyzjteoK.js.gz +0 -0
- package/dist/client/assets/DiffViewer--QG609jF.js.br +0 -0
- package/dist/client/assets/DiffViewer--QG609jF.js.gz +0 -0
- package/dist/client/assets/ModelPreview-BY-nllCI.js.br +0 -0
- package/dist/client/assets/ModelPreview-BY-nllCI.js.gz +0 -0
- package/dist/client/assets/RightSidebar-CdEMgc2G.js.br +0 -0
- package/dist/client/assets/RightSidebar-CdEMgc2G.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-D_YYeniU.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-D_YYeniU.js.gz +0 -0
- package/dist/client/assets/app-VY9J50Vn.js +0 -35
- package/dist/client/assets/app-VY9J50Vn.js.br +0 -0
- package/dist/client/assets/app-VY9J50Vn.js.gz +0 -0
- package/dist/client/assets/arc-sDYgQVIO.js.br +0 -0
- package/dist/client/assets/arc-sDYgQVIO.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-mzycNt3i.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-mzycNt3i.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CmBIG7tu.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CmBIG7tu.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-CyaMSX6v.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-CyaMSX6v.js.gz +0 -0
- package/dist/client/assets/channel-CvSg8DFp.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-C23_F1Qb.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-C23_F1Qb.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BNhZFCbM.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BNhZFCbM.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-CeD3DY62.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-CeD3DY62.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-C7EI51Ae.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-C7EI51Ae.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-HK--o17k.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-HK--o17k.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-CN8cwue3.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-ZJmZp774.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-ZJmZp774.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-C-O7V1Tk.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-C-O7V1Tk.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CgNLkZqS.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CgNLkZqS.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-_e0IES0l.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-_e0IES0l.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-IknuU7gc.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-IknuU7gc.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-xp0eP0gd.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-xp0eP0gd.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-YM3d3Rh5.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-YM3d3Rh5.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-vjaumOKc.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-vjaumOKc.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-DL19bAk6.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-DL19bAk6.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-CL8YGnYl.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-CL8YGnYl.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-Dmxmmzef.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-Dmxmmzef.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-Cg95sExn.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-Cg95sExn.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-ZMwmrdcg.js.br +0 -0
- package/dist/client/assets/gestureArbiter-ZMwmrdcg.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BhPjxbUY.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BhPjxbUY.js.gz +0 -0
- package/dist/client/assets/index-A-ZC9mbr.css.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DYno2wlU.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DYno2wlU.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-D1i0ft78.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-D1i0ft78.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-dO2PhUIk.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-dO2PhUIk.js.gz +0 -0
- package/dist/client/assets/layout-DmeRjjIH.js.br +0 -0
- package/dist/client/assets/layout-DmeRjjIH.js.gz +0 -0
- package/dist/client/assets/linear-FrAcYoA2.js.br +0 -0
- package/dist/client/assets/linear-FrAcYoA2.js.gz +0 -0
- package/dist/client/assets/mermaid.core-CvYA1lvj.js.br +0 -0
- package/dist/client/assets/mermaid.core-CvYA1lvj.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-Dclk8rJC.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-Dclk8rJC.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-DWMjsDcc.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-DWMjsDcc.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-ACqEwiS4.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-ACqEwiS4.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-p7ypBbNQ.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-p7ypBbNQ.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DMn4p4aH.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DWdLvY3f.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DWdLvY3f.js.gz +0 -0
- package/dist/client/assets/rdpSession-AXXpTcnA.js.br +0 -0
- package/dist/client/assets/rdpSession-AXXpTcnA.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-Bi1LDzVG.js.br +0 -0
- package/dist/client/assets/referenceLongPress-Bi1LDzVG.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Dy_QUxq3.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Dy_QUxq3.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-HagpiSZn.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-HagpiSZn.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BN1oDRj1.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BN1oDRj1.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CQevvCDc.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CQevvCDc.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-CWhm9E8u.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-CWhm9E8u.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DG15Rf80.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-BiI3okul.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-BiI3okul.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-C4d165Yd.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-CmkDj1rm.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-CmkDj1rm.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-BLDxV0rO.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-BLDxV0rO.js.gz +0 -0
- package/dist/client/assets/videoCompression-GVC1hIjh.js.br +0 -0
- package/dist/client/assets/videoCompression-GVC1hIjh.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-BWDriNMk.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-BWDriNMk.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-Z9KXLnuy.js.br +0 -0
- 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:
|
|
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
|
|
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
|
|
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
|
|
2516
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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:
|
|
56
|
+
affectedSessionIds: missing.map((candidate) => candidate.sessionId),
|
|
50
57
|
};
|
|
51
58
|
}
|
|
52
59
|
// A dismissed loss stays acknowledged until that session is observed alive
|
package/docs/integrations.md
CHANGED
|
@@ -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
package/runtime-manifest.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "termdock",
|
|
4
|
-
"version": "1.4.
|
|
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-
|
|
10
|
-
"clientBundleHash": "sha256-
|
|
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
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|