termdock 1.4.320 → 1.4.322
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-BF6YvbKL.js → App-DEKo4SNL.js} +67 -67
- package/dist/client/assets/App-DEKo4SNL.js.br +0 -0
- package/dist/client/assets/App-DEKo4SNL.js.gz +0 -0
- package/dist/client/assets/{ArchitecturePanel-D1Jca05w.js → ArchitecturePanel-VDM6hrwp.js} +2 -2
- package/dist/client/assets/ArchitecturePanel-VDM6hrwp.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-VDM6hrwp.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-B59JwhzK.js → ChangeWalkthroughPanel-B64j3i8o.js} +1 -1
- package/dist/client/assets/ChangeWalkthroughPanel-B64j3i8o.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-B64j3i8o.js.gz +0 -0
- package/dist/client/assets/{CollaborationMainWorkspace-CS_o2iYt.js → CollaborationMainWorkspace-DG8TQNqo.js} +1 -1
- package/dist/client/assets/CollaborationMainWorkspace-DG8TQNqo.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-DG8TQNqo.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-msQsgVaI.js +2 -0
- package/dist/client/assets/{ComputerControlView-CRquP12U.js → ComputerControlView-Co-TTYas.js} +2 -2
- package/dist/client/assets/ComputerControlView-Co-TTYas.js.br +0 -0
- package/dist/client/assets/ComputerControlView-Co-TTYas.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-CAfziHw_.js → DagPlayground-kJczdJ6J.js} +1 -1
- package/dist/client/assets/DagPlayground-kJczdJ6J.js.br +0 -0
- package/dist/client/assets/DagPlayground-kJczdJ6J.js.gz +0 -0
- package/dist/client/assets/{DiffLab-CPlA_7PJ.js → DiffLab-BaaioC-q.js} +1 -1
- package/dist/client/assets/DiffLab-BaaioC-q.js.br +0 -0
- package/dist/client/assets/DiffLab-BaaioC-q.js.gz +0 -0
- package/dist/client/assets/{DiffReview-CjEi6PCy.js → DiffReview-Wfck3RIS.js} +1 -1
- package/dist/client/assets/DiffReview-Wfck3RIS.js.br +0 -0
- package/dist/client/assets/DiffReview-Wfck3RIS.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-BFRqRotl.js → DiffReviewLab-Dblr3wgw.js} +1 -1
- package/dist/client/assets/DiffReviewLab-Dblr3wgw.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-Dblr3wgw.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-Bh6lvUYN.js → DiffViewer-C-utC5Ga.js} +1 -1
- package/dist/client/assets/DiffViewer-C-utC5Ga.js.br +0 -0
- package/dist/client/assets/DiffViewer-C-utC5Ga.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-D_WFk4yX.js → ModelPreview-BBLnHWVQ.js} +1 -1
- package/dist/client/assets/ModelPreview-BBLnHWVQ.js.br +0 -0
- package/dist/client/assets/ModelPreview-BBLnHWVQ.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-7C9-PfhA.js → RightSidebar-CUHSFkmZ.js} +3 -3
- package/dist/client/assets/RightSidebar-CUHSFkmZ.js.br +0 -0
- package/dist/client/assets/{RightSidebar-7C9-PfhA.js.gz → RightSidebar-CUHSFkmZ.js.gz} +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-DDAdRY3H.js → abnfDiagram-VCTEODGH-DDd99QpA.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-DDd99QpA.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-DDd99QpA.js.gz +0 -0
- package/dist/client/assets/{app-BRESmgxW.js → app-CfqF7_nh.js} +3 -3
- package/dist/client/assets/app-CfqF7_nh.js.br +0 -0
- package/dist/client/assets/app-CfqF7_nh.js.gz +0 -0
- package/dist/client/assets/{arc-CV9RqbOa.js → arc-C3dck_E0.js} +1 -1
- package/dist/client/assets/arc-C3dck_E0.js.br +0 -0
- package/dist/client/assets/arc-C3dck_E0.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-Ct8CtmBh.js → architectureDiagram-5GKGNRK7-C3bCQc2w.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-C3bCQc2w.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-C3bCQc2w.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-CVjuOZ0h.js → blockDiagram-I7D4REHJ-znMn6iCQ.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-znMn6iCQ.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-znMn6iCQ.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-CSKcN0J-.js → c4Diagram-7LVT6UL2-C0sopIsj.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-C0sopIsj.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-C0sopIsj.js.gz +0 -0
- package/dist/client/assets/channel-CMC8t83j.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-CF6SP9Cv.js → chunk-2Q5K7J3B-f7USyccJ.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-DZhLGwG4.js → chunk-5VM5RSS4-Ck2xirDs.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-CwqjUNpz.js → chunk-F27PBJKO-DaDCIj30.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-DaDCIj30.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-DaDCIj30.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-C9WCfeN9.js → chunk-IMKFNOWR-DEC_On5x.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-DEC_On5x.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-DEC_On5x.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-DUIVW6rN.js → chunk-JWPE2WC7-BrswC3n2.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-YgwJ3iH4.js → chunk-POPQ4Y6H-ClMbDV47.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-A-vVSOuv.js → chunk-SVP7TREG-D7_1VwC5.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-D7_1VwC5.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-D7_1VwC5.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-akdXuwgx.js → chunk-TICWLB2K-D5jzVTZ8.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-D5jzVTZ8.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-D5jzVTZ8.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-Da273BkJ.js → chunk-XXDRQBXY-DOhaoLcX.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-ElMHzA-E.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-ElMHzA-E.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-CGfQhg7T.js → cose-bilkent-JH36ORCC-DOsaKgiX.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-DOsaKgiX.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-DOsaKgiX.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-C9RaJCMn.js → cynefin-OW5HDTMX-CMcLh_wh.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-CMcLh_wh.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-CMcLh_wh.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-C6SWqaZK.js → cynefinDiagram-5FMLGOSQ-Dd8bfq9V.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Dd8bfq9V.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Dd8bfq9V.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-DTMtzPmS.js → dagre-GXQ25YYZ-BlW7fAi0.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-BlW7fAi0.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-BlW7fAi0.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-CRalzYBW.js → diagram-S7CK7UJ4-B0-tKahG.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-B0-tKahG.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-B0-tKahG.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-B5qxEH5p.js → diagram-UQ7AKVKN-BQumj4Dw.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-BQumj4Dw.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-BQumj4Dw.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-CPSmBWU-.js → diagram-VSXAHHWV-Zx_FLmPP.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-Zx_FLmPP.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-Zx_FLmPP.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-CU8A_voC.js → diagram-VX7I27RA-CEZvatNH.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-CEZvatNH.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CEZvatNH.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-CtT4QOY-.js → diagram-Z3DM3KII-CJ9IEQ8j.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-CJ9IEQ8j.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-CJ9IEQ8j.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-Cvk6Y8JV.js → ebnfDiagram-PWID7BFC-sQQMv3ea.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-sQQMv3ea.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-sQQMv3ea.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-_9Ct2AHs.js → erDiagram-RLTQ6QDP-D3rMpj7M.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-D3rMpj7M.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-D3rMpj7M.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-BR29aDF_.js → flowDiagram-HODETNUW-B6QZiE0-.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-B6QZiE0-.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-B6QZiE0-.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-BvVG7ism.js → ganttDiagram-EL5Y4UJY-Bw9bltcu.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-Bw9bltcu.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-Bw9bltcu.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-DalDKZKj.js → gestureArbiter-Cczz34oI.js} +1 -1
- package/dist/client/assets/gestureArbiter-Cczz34oI.js.br +0 -0
- package/dist/client/assets/gestureArbiter-Cczz34oI.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-BHOjoasY.js → gitGraphDiagram-WWUBYQGX-mdnkxjeD.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-mdnkxjeD.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-mdnkxjeD.js.gz +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-DgmnLtPV.js → infoDiagram-27XIBGKW-DyrPP3Yf.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-DoiUx_u1.js → ishikawaDiagram-5VMMS53U-CEPH_ePM.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CEPH_ePM.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CEPH_ePM.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-sz2KwGQ4.js → journeyDiagram-3NMN7TZE-CQ0PjBy7.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-CQ0PjBy7.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-CQ0PjBy7.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-CdAnN6NF.js → kanban-definition-UXKFOSKX-BpQUXA60.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-BpQUXA60.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-BpQUXA60.js.gz +0 -0
- package/dist/client/assets/{layout-7mCqPnQ2.js → layout-BdptC7rq.js} +1 -1
- package/dist/client/assets/layout-BdptC7rq.js.br +0 -0
- package/dist/client/assets/layout-BdptC7rq.js.gz +0 -0
- package/dist/client/assets/{linear-CtGxEwoA.js → linear-C2cSRCxu.js} +1 -1
- package/dist/client/assets/linear-C2cSRCxu.js.br +0 -0
- package/dist/client/assets/linear-C2cSRCxu.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-BxJ2mx92.js → mermaid.core-ClVMFyAU.js} +5 -5
- package/dist/client/assets/mermaid.core-ClVMFyAU.js.br +0 -0
- package/dist/client/assets/mermaid.core-ClVMFyAU.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-Ck2pdDVb.js → mindmap-definition-YA3MSWOX-D0AFCmsY.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-D0AFCmsY.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-D0AFCmsY.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-gTJ9KuKa.js → passwordBootstrap-R2qlU2Pq.js} +1 -1
- package/dist/client/assets/passwordBootstrap-R2qlU2Pq.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-R2qlU2Pq.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-CYBdOhd0.js → pegDiagram-XKGWAZYB-BGAh0bwg.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-BGAh0bwg.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-BGAh0bwg.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-IxFUaefz.js → pieDiagram-E7YTZNPT-CDOZUF44.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-CDOZUF44.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-CDOZUF44.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-CSirkHeE.js → quadrantDiagram-AXDQQJYC-D_Qn6NTU.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-D_Qn6NTU.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-D_Qn6NTU.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-CYoi1Ctl.js → railroadDiagram-O6MQD6OU-qUVGWhJN.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-qUVGWhJN.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-qUVGWhJN.js.gz +0 -0
- package/dist/client/assets/{rdpSession-BQ_xI5BI.js → rdpSession-hgCM4i-j.js} +1 -1
- package/dist/client/assets/rdpSession-hgCM4i-j.js.br +0 -0
- package/dist/client/assets/rdpSession-hgCM4i-j.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-DfQ5jnsk.js → referenceLongPress-BEMsP11a.js} +1 -1
- package/dist/client/assets/referenceLongPress-BEMsP11a.js.br +0 -0
- package/dist/client/assets/referenceLongPress-BEMsP11a.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-BCoG9aBY.js → requirementDiagram-BXWQKSXE-BBQMQuVZ.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BBQMQuVZ.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BBQMQuVZ.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-BM0bKWHQ.js → sankeyDiagram-P5KCCOFB-CeEExsqW.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CeEExsqW.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CeEExsqW.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-CVc-3QVK.js → sequenceDiagram-WJ2MYXX4-7ZPO-X0a.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-7ZPO-X0a.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-7ZPO-X0a.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-70GusSOh.js → sizeCapture-INFHLROL-MBjz7Snm.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-MBjz7Snm.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-MBjz7Snm.js.gz +0 -0
- package/dist/client/assets/{sparkles-DbcgKKVd.js → sparkles-C9ShmGPf.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-BCw-OQPL.js → stateDiagram-D77RDMKH-DtLp89uP.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-DtLp89uP.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DtLp89uP.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CIQb4Dp7.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH--yebjz0I.js → swimlanes-42K2YHIH-Bc02S1q-.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-Bc02S1q-.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-Bc02S1q-.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-RiKL7eXI.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-B9_XXo4h.js → timeline-definition-24CTP7MA-BLLwbOm5.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-BLLwbOm5.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-BLLwbOm5.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-DG_BJhJY.js → triangle-alert-i_L8ws6U.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-BjYW4tQw.js → vennDiagram-4TSXK5OY-8FcrAdbk.js} +1 -1
- package/dist/client/assets/vennDiagram-4TSXK5OY-8FcrAdbk.js.br +0 -0
- package/dist/client/assets/{vennDiagram-4TSXK5OY-BjYW4tQw.js.gz → vennDiagram-4TSXK5OY-8FcrAdbk.js.gz} +0 -0
- package/dist/client/assets/{videoCompression-DrYmE1Ed.js → videoCompression-RIaDabW4.js} +1 -1
- package/dist/client/assets/videoCompression-RIaDabW4.js.br +0 -0
- package/dist/client/assets/videoCompression-RIaDabW4.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-DNVW8Yot.js → wardleyDiagram-VM6X3IG4-paL2wRrJ.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-paL2wRrJ.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-paL2wRrJ.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-l7gJBKpK.js → xychartDiagram-S5SC5T6Z-BM5qJ4E7.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BM5qJ4E7.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BM5qJ4E7.js.gz +0 -0
- package/dist/client/index.html +1 -1
- 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 +30 -3
- package/dist/server/agent/collaborationDeliveryWorker.js +27 -8
- package/dist/server/agent/collaborationPeerTransport.js +3 -2
- package/dist/server/agent/collaborationRoutes.js +14 -1
- package/dist/server/agent/collaborationRouting.js +32 -0
- package/dist/server/agent/collaborationStore.js +27 -1
- package/dist/server/agent/collaborationTaskCli.js +1 -1
- package/dist/server/agent/collaborationTaskGuidance.js +2 -0
- package/dist/server/agent/collaborationTaskStore.js +18 -11
- package/dist/server/agent/collaborationTmuxDelivery.js +3 -2
- package/dist/server/agent/integrationCli.js +6 -0
- package/dist/server/agent/integrationServer.js +2 -0
- package/dist/server/agent/promptDelivery.js +2 -2
- package/dist/server/agent/sessionBindingRecovery.js +1 -1
- package/dist/server/agent/sessionLaunchState.js +20 -0
- package/dist/server/agent/terminalInput.js +17 -0
- package/dist/server/routes/terminal.js +125 -47
- package/docs/integrations.md +122 -0
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- package/dist/client/assets/App-BF6YvbKL.js.br +0 -0
- package/dist/client/assets/App-BF6YvbKL.js.gz +0 -0
- package/dist/client/assets/ArchitecturePanel-D1Jca05w.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-D1Jca05w.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-B59JwhzK.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-B59JwhzK.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-CS_o2iYt.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-CS_o2iYt.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-WQ5CC-0d.js +0 -2
- package/dist/client/assets/ComputerControlView-CRquP12U.js.br +0 -0
- package/dist/client/assets/ComputerControlView-CRquP12U.js.gz +0 -0
- package/dist/client/assets/DagPlayground-CAfziHw_.js.br +0 -0
- package/dist/client/assets/DagPlayground-CAfziHw_.js.gz +0 -0
- package/dist/client/assets/DiffLab-CPlA_7PJ.js.br +0 -0
- package/dist/client/assets/DiffLab-CPlA_7PJ.js.gz +0 -0
- package/dist/client/assets/DiffReview-CjEi6PCy.js.br +0 -0
- package/dist/client/assets/DiffReview-CjEi6PCy.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-BFRqRotl.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-BFRqRotl.js.gz +0 -0
- package/dist/client/assets/DiffViewer-Bh6lvUYN.js.br +0 -0
- package/dist/client/assets/DiffViewer-Bh6lvUYN.js.gz +0 -0
- package/dist/client/assets/ModelPreview-D_WFk4yX.js.br +0 -0
- package/dist/client/assets/ModelPreview-D_WFk4yX.js.gz +0 -0
- package/dist/client/assets/RightSidebar-7C9-PfhA.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-DDAdRY3H.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-DDAdRY3H.js.gz +0 -0
- package/dist/client/assets/app-BRESmgxW.js.br +0 -0
- package/dist/client/assets/app-BRESmgxW.js.gz +0 -0
- package/dist/client/assets/arc-CV9RqbOa.js.br +0 -0
- package/dist/client/assets/arc-CV9RqbOa.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-Ct8CtmBh.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-Ct8CtmBh.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CVjuOZ0h.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CVjuOZ0h.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-CSKcN0J-.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-CSKcN0J-.js.gz +0 -0
- package/dist/client/assets/channel-BDjp8qZS.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-CwqjUNpz.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-CwqjUNpz.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-C9WCfeN9.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-C9WCfeN9.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-A-vVSOuv.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-A-vVSOuv.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-akdXuwgx.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-akdXuwgx.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-CkFBQKLs.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-CkFBQKLs.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-CGfQhg7T.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-CGfQhg7T.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-C9RaJCMn.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-C9RaJCMn.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-C6SWqaZK.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-C6SWqaZK.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-DTMtzPmS.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-DTMtzPmS.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-CRalzYBW.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-CRalzYBW.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B5qxEH5p.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B5qxEH5p.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CPSmBWU-.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CPSmBWU-.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CU8A_voC.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CU8A_voC.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-CtT4QOY-.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-CtT4QOY-.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Cvk6Y8JV.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Cvk6Y8JV.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-_9Ct2AHs.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-_9Ct2AHs.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BR29aDF_.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BR29aDF_.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-BvVG7ism.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-BvVG7ism.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-DalDKZKj.js.br +0 -0
- package/dist/client/assets/gestureArbiter-DalDKZKj.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BHOjoasY.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BHOjoasY.js.gz +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DoiUx_u1.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DoiUx_u1.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-sz2KwGQ4.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-sz2KwGQ4.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CdAnN6NF.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CdAnN6NF.js.gz +0 -0
- package/dist/client/assets/layout-7mCqPnQ2.js.br +0 -0
- package/dist/client/assets/layout-7mCqPnQ2.js.gz +0 -0
- package/dist/client/assets/linear-CtGxEwoA.js.br +0 -0
- package/dist/client/assets/linear-CtGxEwoA.js.gz +0 -0
- package/dist/client/assets/mermaid.core-BxJ2mx92.js.br +0 -0
- package/dist/client/assets/mermaid.core-BxJ2mx92.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-Ck2pdDVb.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-Ck2pdDVb.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-gTJ9KuKa.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-gTJ9KuKa.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-CYBdOhd0.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-CYBdOhd0.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-IxFUaefz.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-IxFUaefz.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CSirkHeE.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CSirkHeE.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CYoi1Ctl.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CYoi1Ctl.js.gz +0 -0
- package/dist/client/assets/rdpSession-BQ_xI5BI.js.br +0 -0
- package/dist/client/assets/rdpSession-BQ_xI5BI.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-DfQ5jnsk.js.br +0 -0
- package/dist/client/assets/referenceLongPress-DfQ5jnsk.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BCoG9aBY.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BCoG9aBY.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-BM0bKWHQ.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-BM0bKWHQ.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-CVc-3QVK.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-CVc-3QVK.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-70GusSOh.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-70GusSOh.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BCw-OQPL.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BCw-OQPL.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-C2WqSO6X.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH--yebjz0I.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH--yebjz0I.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-Cyxi7gqq.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-B9_XXo4h.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-B9_XXo4h.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-BjYW4tQw.js.br +0 -0
- package/dist/client/assets/videoCompression-DrYmE1Ed.js.br +0 -0
- package/dist/client/assets/videoCompression-DrYmE1Ed.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-DNVW8Yot.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-DNVW8Yot.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-l7gJBKpK.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-l7gJBKpK.js.gz +0 -0
|
@@ -51,7 +51,8 @@ import { archiveTaskWorkspace, restoreTaskWorkspace, snapshotTaskWorkspace } fro
|
|
|
51
51
|
import { isTmuxRecoveryCandidate } from '../utils/tmuxRecoveryCandidate.js';
|
|
52
52
|
import { AutomationStore, normalizeAutomationSchedule } from '../agent/automationStore.js';
|
|
53
53
|
import { writeBracketedPrompt, canDeliverPromptToAgent } from '../agent/promptDelivery.js';
|
|
54
|
-
import { captureTerminalInputGuard,
|
|
54
|
+
import { captureTerminalInputGuard, captureRuntimeInputGuard, waitAndWriteTerminalInput } from '../agent/terminalInput.js';
|
|
55
|
+
import { mergeSessionLaunchState } from '../agent/sessionLaunchState.js';
|
|
55
56
|
import { agentLaunchBlockReason, normalizeAgentLaunchCheck } from '../agent/agentLaunchCheck.js';
|
|
56
57
|
import { prepareSupervisionEnable } from '../utils/enableSupervision.js';
|
|
57
58
|
import { buildServerHealthState, dismissServerHealth } from '../utils/serverHealth.js';
|
|
@@ -66,7 +67,7 @@ import { SessionSearchStore } from '../agent/sessionSearchStore.js';
|
|
|
66
67
|
import { NativeSessionSearch } from '../agent/nativeSessionSearch.js';
|
|
67
68
|
import { CollaborationError } from '../agent/collaborationProtocol.js';
|
|
68
69
|
import { resolveCollaborationBackend, resolveCollaborationSessionId } from '../agent/sessionBindingRecovery.js';
|
|
69
|
-
import { CollaborationRoutingStore, selectCollaborationPane, selectDrivePane } from '../agent/collaborationRouting.js';
|
|
70
|
+
import { CollaborationRoutingStore, selectCollaborationPane, selectDrivePane, assessCollaborationRouteIdentity } from '../agent/collaborationRouting.js';
|
|
70
71
|
import { CollaborationDeliveryWorker } from '../agent/collaborationDeliveryWorker.js';
|
|
71
72
|
import { approveCollaborationDialog, captureTmuxPaneHistory, captureTmuxPaneText, sendTmuxPaneKey, writeCollaborationTmuxPane } from '../agent/collaborationTmuxDelivery.js';
|
|
72
73
|
import { listAllHookAgents, refreshStaleHooksAtLaunch, installHooksForSlug, uninstallHooksForSlug, } from '../agent/installers.js';
|
|
@@ -678,6 +679,9 @@ process.on('SIGINT', () => { void shutdownWithRecordings(); });
|
|
|
678
679
|
// 服务启动时从磁盘加载(带去重,防止历史累积的重复条目复活)
|
|
679
680
|
void (async () => {
|
|
680
681
|
await Promise.all([loadGlobalSessionStateFromDisk(), loadTmuxRecoveryStateFromDisk()]);
|
|
682
|
+
// Delivery needs the loaded inventory, not optional PTY adoption/metadata backfill.
|
|
683
|
+
// Those steps must not leave durable messages without a background scheduler.
|
|
684
|
+
collaborationDeliveryWorker.start();
|
|
681
685
|
await watchGlobalSessionStateFile();
|
|
682
686
|
// pty-host adoption runs after the state load (its record upserts must not
|
|
683
687
|
// be clobbered) and before pruning (surviving shell records' backends are
|
|
@@ -687,7 +691,6 @@ void (async () => {
|
|
|
687
691
|
});
|
|
688
692
|
pruneOrphanSessions();
|
|
689
693
|
await backfillPersistedTmuxMetadata();
|
|
690
|
-
collaborationDeliveryWorker.start();
|
|
691
694
|
})();
|
|
692
695
|
caffeinateManager.startNetworkMonitor();
|
|
693
696
|
// 清理磁盘恢复后后端已不存在的 session 引用。
|
|
@@ -1080,8 +1083,9 @@ async function withInventoryOpenLock(key, task) {
|
|
|
1080
1083
|
inventoryOpenLocks.set(key, pending);
|
|
1081
1084
|
return pending;
|
|
1082
1085
|
}
|
|
1083
|
-
function upsertGlobalSessionRecord(record) {
|
|
1084
|
-
const
|
|
1086
|
+
function upsertGlobalSessionRecord(record, launchChange) {
|
|
1087
|
+
const current = globalSessionState.sessions.find(candidate => candidate.sessionId === record.sessionId);
|
|
1088
|
+
const normalized = normalizePersistedClientSession(mergeSessionLaunchState(record, current, launchChange));
|
|
1085
1089
|
if (!normalized) {
|
|
1086
1090
|
throw new Error('invalid session record');
|
|
1087
1091
|
}
|
|
@@ -1460,8 +1464,16 @@ async function beginAgentLaunchCheck(frontendSessionId, agentSlug, nativeSession
|
|
|
1460
1464
|
if (!record)
|
|
1461
1465
|
throw new Error('SESSION_REMOVED');
|
|
1462
1466
|
const id = randomUUID();
|
|
1463
|
-
upsertGlobalSessionRecord(
|
|
1464
|
-
|
|
1467
|
+
const updated = upsertGlobalSessionRecord(record, { expectedGeneration: record.agentLaunchGeneration ?? null,
|
|
1468
|
+
expectedCheckId: record.agentLaunchCheck?.id ?? null, generation: id,
|
|
1469
|
+
check: { id, agentSlug, nativeSessionId, deadline: Date.now() + 120_000 } });
|
|
1470
|
+
// Capture the guard before persistence yields. The launch command must use
|
|
1471
|
+
// this exact generation, even if another launch occurs during an await.
|
|
1472
|
+
const assertCurrent = terminalInputGuard(updated);
|
|
1473
|
+
assertCurrent('guard_capture');
|
|
1474
|
+
await persistGlobalStateNow(true);
|
|
1475
|
+
assertCurrent('launch_persisted');
|
|
1476
|
+
return assertCurrent;
|
|
1465
1477
|
}
|
|
1466
1478
|
async function observeAgentLaunchCheck(record, observed) {
|
|
1467
1479
|
const check = record.agentLaunchCheck;
|
|
@@ -1475,51 +1487,56 @@ async function observeAgentLaunchCheck(record, observed) {
|
|
|
1475
1487
|
return { state: 'offline', reason: 'SESSION_REMOVED' };
|
|
1476
1488
|
if (latest.agentLaunchCheck?.id !== check.id)
|
|
1477
1489
|
return { state: 'recovering', reason: 'AGENT_LAUNCH_CHANGED' };
|
|
1478
|
-
upsertGlobalSessionRecord(
|
|
1490
|
+
upsertGlobalSessionRecord(latest, { expectedGeneration: latest.agentLaunchGeneration ?? null,
|
|
1491
|
+
expectedCheckId: check.id, generation: latest.agentLaunchGeneration ?? null, check: null });
|
|
1479
1492
|
await persistGlobalStateNow();
|
|
1480
1493
|
return null;
|
|
1481
1494
|
}
|
|
1482
1495
|
function terminalInputGuard(record) {
|
|
1483
1496
|
const frontendSessionId = record.sessionId;
|
|
1484
1497
|
const backendSessionId = record.backendSessionId;
|
|
1485
|
-
const
|
|
1486
|
-
|
|
1487
|
-
|
|
1498
|
+
const expected = { backendSessionId, launchId: record.agentLaunchGeneration ?? null,
|
|
1499
|
+
routeRevision: collaborationRouting.get(frontendSessionId)?.routeRevision ?? null,
|
|
1500
|
+
backendInstance: backendSessionId ? terminalSessions.get(backendSessionId) : undefined };
|
|
1501
|
+
return captureRuntimeInputGuard(() => {
|
|
1488
1502
|
const latest = globalSessionState.sessions.find(candidate => candidate.sessionId === frontendSessionId);
|
|
1489
1503
|
if (!latest)
|
|
1490
1504
|
throw new Error('SESSION_REMOVED');
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
}
|
|
1496
|
-
};
|
|
1505
|
+
return { backendSessionId: latest.backendSessionId, launchId: latest.agentLaunchGeneration ?? null,
|
|
1506
|
+
routeRevision: collaborationRouting.get(frontendSessionId)?.routeRevision ?? null,
|
|
1507
|
+
backendInstance: latest.backendSessionId ? terminalSessions.get(latest.backendSessionId) : undefined };
|
|
1508
|
+
}, expected);
|
|
1497
1509
|
}
|
|
1498
1510
|
/** tmux input always uses the pane queue, including automation and launch commands. */
|
|
1499
1511
|
async function automaticTerminalInput(record, assertCurrent = terminalInputGuard(record), progress) {
|
|
1500
|
-
|
|
1512
|
+
progress?.('guard_captured');
|
|
1513
|
+
assertCurrent('runtime_resolve');
|
|
1514
|
+
progress?.('runtime_resolving');
|
|
1501
1515
|
if (record.mode === 'tmux') {
|
|
1502
1516
|
const binding = collaborationRouting.get(record.sessionId) ?? {
|
|
1503
1517
|
sessionId: record.sessionId, backendSessionId: record.backendSessionId, mode: record.mode,
|
|
1504
1518
|
tmuxSessionName: record.tmuxSessionName, agentSlug: null, nativeSessionId: null, pane: null,
|
|
1505
1519
|
};
|
|
1506
1520
|
const inspected = await inspectCollaborationTmux(binding, null, true);
|
|
1507
|
-
assertCurrent();
|
|
1521
|
+
assertCurrent('runtime_resolved');
|
|
1508
1522
|
if (inspected.state !== 'ready' || !inspected.pane)
|
|
1509
1523
|
throw new Error(inspected.reason ?? 'TMUX_PANE_UNAVAILABLE');
|
|
1510
1524
|
const pane = inspected.pane;
|
|
1525
|
+
progress?.('runtime_resolved');
|
|
1511
1526
|
return (prompt) => writeCollaborationTmuxPane(runTmux, pane, prompt, runTmuxStdin, assertCurrent, progress);
|
|
1512
1527
|
}
|
|
1513
1528
|
const backend = record.backendSessionId ? terminalSessions.get(record.backendSessionId) : null;
|
|
1514
1529
|
if (!backend)
|
|
1515
1530
|
throw new Error('SHELL_BACKEND_NOT_RUNNING');
|
|
1531
|
+
assertCurrent('runtime_resolved');
|
|
1532
|
+
progress?.('runtime_resolved');
|
|
1516
1533
|
return (prompt) => writeBracketedPrompt(backend.ptyProcess, prompt, assertCurrent, progress);
|
|
1517
1534
|
}
|
|
1518
|
-
async function writeAutomaticTerminalPrompt(frontendSessionId, prompt, progress) {
|
|
1535
|
+
async function writeAutomaticTerminalPrompt(frontendSessionId, prompt, progress, launchGuard) {
|
|
1519
1536
|
const record = globalSessionState.sessions.find(candidate => candidate.sessionId === frontendSessionId);
|
|
1520
1537
|
if (!record)
|
|
1521
1538
|
throw new Error('SESSION_REMOVED');
|
|
1522
|
-
const write = await automaticTerminalInput(record, terminalInputGuard(record), progress);
|
|
1539
|
+
const write = await automaticTerminalInput(record, launchGuard ?? terminalInputGuard(record), progress);
|
|
1523
1540
|
await write(prompt);
|
|
1524
1541
|
}
|
|
1525
1542
|
async function deliverAutomationPromptWhenReady(backendSessionId, prompt) {
|
|
@@ -1576,9 +1593,8 @@ async function runAgentAutomation(automation, req) {
|
|
|
1576
1593
|
throw new Error('自动任务会话创建失败');
|
|
1577
1594
|
if (automation.command) {
|
|
1578
1595
|
const agent = detectAgentFromCommand(automation.command, agentCustomCommands());
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
await writeAutomaticTerminalPrompt(frontendSessionId, automation.command);
|
|
1596
|
+
const launchGuard = agent ? await beginAgentLaunchCheck(frontendSessionId, agent.slug) : undefined;
|
|
1597
|
+
await writeAutomaticTerminalPrompt(frontendSessionId, automation.command, undefined, launchGuard);
|
|
1582
1598
|
}
|
|
1583
1599
|
if (automation.prompt) {
|
|
1584
1600
|
if (automation.command)
|
|
@@ -1612,6 +1628,7 @@ export function resolveStableFederationSessionId(id) {
|
|
|
1612
1628
|
}
|
|
1613
1629
|
function collaborationRemoteSessions() {
|
|
1614
1630
|
return Array.from(new Map(collaborationStore.list().flatMap((group) => group.remoteSessions ?? [])
|
|
1631
|
+
.filter(session => session.sessionId.startsWith('remote:'))
|
|
1615
1632
|
.map((session) => {
|
|
1616
1633
|
const facts = collaborationStore.sessionFacts(session.sessionId, false);
|
|
1617
1634
|
const { currentTask: _currentTask, ...terminalSession } = session;
|
|
@@ -1622,8 +1639,7 @@ function collaborationRemoteSessions() {
|
|
|
1622
1639
|
})).values());
|
|
1623
1640
|
}
|
|
1624
1641
|
function tryDeliverCollaborationInbox(frontendSessionId) {
|
|
1625
|
-
|
|
1626
|
-
if (remote) {
|
|
1642
|
+
if (frontendSessionId.startsWith('remote:')) {
|
|
1627
1643
|
return { delivered: [], pending: collaborationStore.pendingCount(frontendSessionId), waitable: true,
|
|
1628
1644
|
reason: '跨服务消息已入队,服务后台正在投递;使用 message get 查看送达回执或注册、重试原因。' };
|
|
1629
1645
|
}
|
|
@@ -1669,7 +1685,7 @@ function formatLocalCollaborationMessages(frontendSessionId, messages) {
|
|
|
1669
1685
|
* agent-keyed selector can never reach it. Delivery still needs an agent (the
|
|
1670
1686
|
* confirm gate and prompt formatting assume a TUI); driving a terminal —
|
|
1671
1687
|
* run/capture — is a shell operation and works on any pane. */
|
|
1672
|
-
async function inspectCollaborationTmux(binding, requestedPane, allowPlainPane = false, nativeProcessIdentity = false, freshProcess = false) {
|
|
1688
|
+
async function inspectCollaborationTmux(binding, requestedPane, allowPlainPane = false, nativeProcessIdentity = false, freshProcess = false, describeNativeFailure = false) {
|
|
1673
1689
|
if (!binding.tmuxSessionName)
|
|
1674
1690
|
return { state: 'offline', reason: 'TMUX_BINDING_MISSING' };
|
|
1675
1691
|
const name = `=${binding.tmuxSessionName}`;
|
|
@@ -1696,14 +1712,16 @@ async function inspectCollaborationTmux(binding, requestedPane, allowPlainPane =
|
|
|
1696
1712
|
const program = await resolveTmuxPaneProgram(pane, true, nativeProcessIdentity || freshProcess);
|
|
1697
1713
|
const agent = detectAgentFromCommand(program?.rawArgs ?? program?.command ?? '', agentCustomCommands());
|
|
1698
1714
|
const identity = nativeProcessIdentity ? await observeProgramNativeIdentity(agent, program)
|
|
1699
|
-
: { nativeId: agent && program?.rawArgs ? inferResumeSessionId(agent, splitCommandToArgv(program.rawArgs)) : null, failure: null };
|
|
1700
|
-
if (identity.failure)
|
|
1715
|
+
: { nativeId: agent && program?.rawArgs ? inferResumeSessionId(agent, splitCommandToArgv(program.rawArgs)) : null, failure: null, source: null };
|
|
1716
|
+
if (identity.failure && !describeNativeFailure)
|
|
1701
1717
|
integrationError(identity.failure === 'NATIVE_SESSION_IDENTITY_CONFLICT'
|
|
1702
1718
|
? 'NATIVE_SESSION_ID_MISMATCH' : 'NATIVE_SESSION_OWNER_UNCONFIRMED', 'Current process native identity evidence conflicts or cannot be uniquely verified', 409);
|
|
1703
1719
|
const nativeSessionId = identity.nativeId;
|
|
1704
1720
|
return { serverPid, sessionId: layout.sessionId, paneId: pane.id, panePid: pane.pid,
|
|
1705
1721
|
agentSlug: agent?.slug ?? '', nativeSessionId, cwd: pane.currentPath,
|
|
1706
|
-
isShell: shellNamesBackend.has(normalizeProgramName(program?.command ?? '')?.toLowerCase() ?? '')
|
|
1722
|
+
isShell: shellNamesBackend.has(normalizeProgramName(program?.command ?? '')?.toLowerCase() ?? ''),
|
|
1723
|
+
...(nativeProcessIdentity ? { nativeIdentitySource: identity.source, nativeIdentityFailure: identity.failure,
|
|
1724
|
+
nativeIdentityVerified: identity.source === 'linux-flock-owner' && !identity.failure } : {}) };
|
|
1707
1725
|
}));
|
|
1708
1726
|
const candidates = requestedPane ? panes.filter((pane) => pane.paneId === requestedPane) : panes;
|
|
1709
1727
|
if (allowPlainPane && !binding.pane) {
|
|
@@ -1711,24 +1729,56 @@ async function inspectCollaborationTmux(binding, requestedPane, allowPlainPane =
|
|
|
1711
1729
|
// pane so a plain shell member is drivable (run/capture are shell ops).
|
|
1712
1730
|
return selectDrivePane(binding, candidates, layout.activePaneId);
|
|
1713
1731
|
}
|
|
1714
|
-
return selectCollaborationPane(binding, candidates);
|
|
1732
|
+
return { ...selectCollaborationPane(binding, candidates), candidates };
|
|
1733
|
+
}
|
|
1734
|
+
function routeOwnershipConfirmed(frontendSessionId, binding, panes) {
|
|
1735
|
+
const record = globalSessionState.sessions.find(candidate => candidate.sessionId === frontendSessionId);
|
|
1736
|
+
return !!record && record.mode === 'tmux' && record.tmuxSessionName === binding.tmuxSessionName
|
|
1737
|
+
&& !globalSessionState.sessions.some(other => other.sessionId !== frontendSessionId && (other.tmuxSessionName === binding.tmuxSessionName
|
|
1738
|
+
|| !!binding.backendSessionId && other.backendSessionId === binding.backendSessionId))
|
|
1739
|
+
&& (!binding.backendSessionId || [null, frontendSessionId].includes(collaborationRouting.ownerOfBackend(binding.backendSessionId)))
|
|
1740
|
+
&& panes.every(pane => !collaborationRouting.hasOtherPaneOwner(frontendSessionId, pane));
|
|
1741
|
+
}
|
|
1742
|
+
function routeHasUnconfirmedWrite(frontendSessionId) {
|
|
1743
|
+
return collaborationStore.hasUnconfirmedDelivery(frontendSessionId);
|
|
1744
|
+
}
|
|
1745
|
+
async function describeCollaborationRoute(frontendSessionId) {
|
|
1746
|
+
const record = globalSessionState.sessions.find(candidate => candidate.sessionId === frontendSessionId);
|
|
1747
|
+
if (!record)
|
|
1748
|
+
throw new Error('SESSION_REMOVED');
|
|
1749
|
+
const binding = collaborationRouting.get(frontendSessionId);
|
|
1750
|
+
if (!binding || binding.mode !== 'tmux')
|
|
1751
|
+
return { session_id: frontendSessionId, binding,
|
|
1752
|
+
worker: collaborationDeliveryWorker.diagnostics(frontendSessionId), identity: null };
|
|
1753
|
+
const inspected = await inspectCollaborationTmux(binding, null, false, true, true, true);
|
|
1754
|
+
const assessment = assessCollaborationRouteIdentity(binding, inspected.candidates ?? [], routeOwnershipConfirmed(frontendSessionId, binding, inspected.candidates ?? []), routeHasUnconfirmedWrite(frontendSessionId));
|
|
1755
|
+
return { session_id: frontendSessionId, binding, worker: collaborationDeliveryWorker.diagnostics(frontendSessionId),
|
|
1756
|
+
observed_at: Date.now(), state: inspected.state, error: inspected.reason ?? null, identity: assessment.diagnostics,
|
|
1757
|
+
integration_managed: record.tmuxSessionName?.startsWith('wt-integration-') ?? false };
|
|
1715
1758
|
}
|
|
1716
1759
|
async function rebindCollaborationRoute(frontendSessionId, paneId) {
|
|
1717
1760
|
await collaborationDeliveryWorker.reconfigure(frontendSessionId, async () => {
|
|
1718
1761
|
const record = globalSessionState.sessions.find((candidate) => candidate.sessionId === frontendSessionId);
|
|
1719
1762
|
if (!record)
|
|
1720
1763
|
throw new Error('SESSION_REMOVED');
|
|
1764
|
+
if (record.tmuxSessionName?.startsWith('wt-integration-'))
|
|
1765
|
+
throw new Error('INTEGRATION_SESSION_RESTORE_REQUIRED: use the owning principal session restore lifecycle');
|
|
1721
1766
|
const previous = collaborationRouting.get(frontendSessionId);
|
|
1767
|
+
if (routeHasUnconfirmedWrite(frontendSessionId))
|
|
1768
|
+
throw new Error('ROUTE_DELIVERY_OUTCOME_UNCONFIRMED: inspect prior write outcome before rebinding; the body is not replayed');
|
|
1722
1769
|
const binding = {
|
|
1723
1770
|
sessionId: frontendSessionId, backendSessionId: previous?.backendSessionId ?? record.backendSessionId,
|
|
1724
1771
|
mode: record.mode, tmuxSessionName: record.tmuxSessionName ?? previous?.tmuxSessionName ?? null,
|
|
1725
1772
|
agentSlug: null, nativeSessionId: null, pane: null,
|
|
1773
|
+
routeRevision: crypto.randomUUID(), lastRecovery: { kind: 'owner-confirmed', at: Date.now(), previousPane: previous?.pane ?? null },
|
|
1726
1774
|
};
|
|
1727
1775
|
if (binding.mode === 'tmux') {
|
|
1728
1776
|
const inspected = await inspectCollaborationTmux(binding, paneId);
|
|
1729
1777
|
if (inspected.state !== 'ready' || !inspected.pane)
|
|
1730
1778
|
throw new Error(inspected.reason ?? 'AGENT_NOT_RUNNING');
|
|
1731
1779
|
const pane = inspected.pane;
|
|
1780
|
+
if (!routeOwnershipConfirmed(frontendSessionId, binding, [pane]))
|
|
1781
|
+
throw new Error('ROUTE_OWNERSHIP_UNCONFIRMED');
|
|
1732
1782
|
binding.pane = { serverPid: pane.serverPid, sessionId: pane.sessionId, paneId: pane.paneId, panePid: pane.panePid,
|
|
1733
1783
|
agentSlug: pane.agentSlug, nativeSessionId: pane.nativeSessionId };
|
|
1734
1784
|
binding.agentSlug = pane.agentSlug;
|
|
@@ -1759,6 +1809,7 @@ async function rebindCollaborationRoute(frontendSessionId, paneId) {
|
|
|
1759
1809
|
* snapshot of the recipient after the write, and the sender judges from that.
|
|
1760
1810
|
*/
|
|
1761
1811
|
async function resolveCollaborationRoute(frontendSessionId) {
|
|
1812
|
+
let recoveredNativeIdentity = false;
|
|
1762
1813
|
let record = globalSessionState.sessions.find((candidate) => candidate.sessionId === frontendSessionId);
|
|
1763
1814
|
if (!record)
|
|
1764
1815
|
return { state: 'offline', reason: 'SESSION_REMOVED' };
|
|
@@ -1774,7 +1825,26 @@ async function resolveCollaborationRoute(frontendSessionId) {
|
|
|
1774
1825
|
agentSlug: record.agentResume?.slug ?? null, nativeSessionId: record.agentResume?.sessionId ?? null, pane: null,
|
|
1775
1826
|
};
|
|
1776
1827
|
if (binding.mode === 'tmux') {
|
|
1777
|
-
|
|
1828
|
+
let inspected = await inspectCollaborationTmux(binding, undefined, false, Boolean(record.agentLaunchCheck?.nativeSessionId), Boolean(record.agentLaunchCheck));
|
|
1829
|
+
if (inspected.state === 'identity-mismatch' && !record.tmuxSessionName?.startsWith('wt-integration-')) {
|
|
1830
|
+
const observed = await inspectCollaborationTmux(binding, null, false, true, true, true);
|
|
1831
|
+
const assessment = assessCollaborationRouteIdentity(binding, observed.candidates ?? [], routeOwnershipConfirmed(frontendSessionId, binding, observed.candidates ?? []), routeHasUnconfirmedWrite(frontendSessionId));
|
|
1832
|
+
if (assessment.diagnostics.recovery !== 'automatic' || !assessment.pane)
|
|
1833
|
+
return { state: 'identity-mismatch', reason: 'TMUX_PANE_CHANGED', diagnostics: assessment.diagnostics };
|
|
1834
|
+
const previous = collaborationRouting.get(frontendSessionId);
|
|
1835
|
+
if (JSON.stringify(previous) !== JSON.stringify(binding))
|
|
1836
|
+
return { state: 'recovering', reason: 'ROUTE_CHANGED_DURING_RECOVERY' };
|
|
1837
|
+
const verify = await inspectCollaborationTmux(binding, null, false, true, true, true);
|
|
1838
|
+
const confirmed = assessCollaborationRouteIdentity(binding, verify.candidates ?? [], routeOwnershipConfirmed(frontendSessionId, binding, verify.candidates ?? []), routeHasUnconfirmedWrite(frontendSessionId));
|
|
1839
|
+
if (confirmed.diagnostics.recovery !== 'automatic' || !confirmed.pane || JSON.stringify(confirmed.pane) !== JSON.stringify(assessment.pane)) {
|
|
1840
|
+
return { state: 'identity-mismatch', reason: 'ROUTE_CHANGED_DURING_RECOVERY', diagnostics: confirmed.diagnostics };
|
|
1841
|
+
}
|
|
1842
|
+
binding = { ...binding, pane: confirmed.pane, routeRevision: crypto.randomUUID(),
|
|
1843
|
+
lastRecovery: { kind: 'native-identity', at: Date.now(), previousPane: binding.pane } };
|
|
1844
|
+
collaborationRouting.bind(binding);
|
|
1845
|
+
inspected = { state: 'ready', pane: confirmed.pane };
|
|
1846
|
+
recoveredNativeIdentity = true;
|
|
1847
|
+
}
|
|
1778
1848
|
assertGeneration();
|
|
1779
1849
|
if (inspected.state !== 'ready' || !inspected.pane)
|
|
1780
1850
|
return inspected;
|
|
@@ -1816,6 +1886,14 @@ async function resolveCollaborationRoute(frontendSessionId) {
|
|
|
1816
1886
|
return { state: 'ready', isShell: pane.isShell, capture: async () => captureTmuxPaneText(runTmux, pinned), write: async (messages) => {
|
|
1817
1887
|
if (!globalSessionState.sessions.some((candidate) => candidate.sessionId === frontendSessionId))
|
|
1818
1888
|
throw new Error('SESSION_REMOVED');
|
|
1889
|
+
if (recoveredNativeIdentity) {
|
|
1890
|
+
const current = await inspectCollaborationTmux(binding, null, false, true, true, true);
|
|
1891
|
+
const proof = current.candidates?.find(candidate => candidate.serverPid === pinned.serverPid && candidate.sessionId === pinned.sessionId
|
|
1892
|
+
&& candidate.paneId === pinned.paneId && candidate.panePid === pinned.panePid);
|
|
1893
|
+
if (!proof?.nativeIdentityVerified || proof.nativeIdentityFailure || proof.nativeSessionId !== pinned.nativeSessionId
|
|
1894
|
+
|| proof.agentSlug !== pinned.agentSlug || !routeOwnershipConfirmed(frontendSessionId, binding, [proof]))
|
|
1895
|
+
throw new Error('ROUTE_NATIVE_IDENTITY_CHANGED_BEFORE_WRITE');
|
|
1896
|
+
}
|
|
1819
1897
|
await writeCollaborationTmuxPane(runTmux, pinned, formatLocalCollaborationMessages(frontendSessionId, messages), runTmuxStdin, () => { assertGeneration(); assertCurrent(); });
|
|
1820
1898
|
backend.lastActivity = Date.now();
|
|
1821
1899
|
} };
|
|
@@ -1904,7 +1982,7 @@ async function spawnCollaborationAgentSession(req, group, sourceSessionId, input
|
|
|
1904
1982
|
const backend = terminalSessions.get(opened.terminalSession.sessionId);
|
|
1905
1983
|
if (!backend)
|
|
1906
1984
|
throw new HttpStatusError(500, 'Agent Session 创建失败', 'COLLAB_AGENT_SESSION_FAILED');
|
|
1907
|
-
await beginAgentLaunchCheck(frontendSessionId, launcher.slug);
|
|
1985
|
+
const launchGuard = await beginAgentLaunchCheck(frontendSessionId, launcher.slug);
|
|
1908
1986
|
const latestGroup = collaborationStore.getGroup(group.id);
|
|
1909
1987
|
if (!latestGroup || latestGroup.deleted) {
|
|
1910
1988
|
const created = globalSessionState.sessions.find(record => record.sessionId === frontendSessionId);
|
|
@@ -1927,7 +2005,7 @@ async function spawnCollaborationAgentSession(req, group, sourceSessionId, input
|
|
|
1927
2005
|
collaborationStore.setRole({ groupId: group.id, sessionId: frontendSessionId, role: bootstrapRole, creationKey });
|
|
1928
2006
|
if (profile)
|
|
1929
2007
|
collaborationStore.setMemberLaunchProfile(group.id, frontendSessionId, profile);
|
|
1930
|
-
await writeAutomaticTerminalPrompt(frontendSessionId, buildCollaborationSpawnCommand({ slug: launcher.slug, command: profile?.command ?? launcher.command }));
|
|
2008
|
+
await writeAutomaticTerminalPrompt(frontendSessionId, buildCollaborationSpawnCommand({ slug: launcher.slug, command: profile?.command ?? launcher.command }), undefined, launchGuard);
|
|
1931
2009
|
const requestedTask = typeof input.task === 'string' ? input.task.trim().slice(0, 20_000) : '';
|
|
1932
2010
|
collaborationStore.send({
|
|
1933
2011
|
groupId: updatedGroup.id,
|
|
@@ -2357,8 +2435,8 @@ async function launchIntegrationTerminal(record, restoring, prepared, progress,
|
|
|
2357
2435
|
backend.agent = null;
|
|
2358
2436
|
backend.agentResumeRecovered = false;
|
|
2359
2437
|
progress?.('launch_intent');
|
|
2360
|
-
await beginAgentLaunchCheck(record.session_id, record.agent_slug, restoring ? record.agent_native_session_id : null);
|
|
2361
|
-
await writeAutomaticTerminalPrompt(record.session_id, integrationLaunchCommand(record, restoring), progress);
|
|
2438
|
+
const launchGuard = await beginAgentLaunchCheck(record.session_id, record.agent_slug, restoring ? record.agent_native_session_id : null);
|
|
2439
|
+
await writeAutomaticTerminalPrompt(record.session_id, integrationLaunchCommand(record, restoring), progress, launchGuard);
|
|
2362
2440
|
broadcastClientState();
|
|
2363
2441
|
});
|
|
2364
2442
|
}
|
|
@@ -2405,12 +2483,12 @@ export function prepareCollaborationTaskWorker(task, template, dependencies, ser
|
|
|
2405
2483
|
throw error;
|
|
2406
2484
|
}
|
|
2407
2485
|
if (!currentAgent && (!launch || launch.backendId !== opened.terminalSession.sessionId)) {
|
|
2408
|
-
await beginAgentLaunchCheck(record.sessionId, launcher.slug);
|
|
2486
|
+
const launchGuard = await beginAgentLaunchCheck(record.sessionId, launcher.slug);
|
|
2409
2487
|
// Persist before typing: a retry must never type the launcher into a newly booted Agent's prompt.
|
|
2410
2488
|
const temporary = `${launchFile}.${process.pid}.tmp`;
|
|
2411
2489
|
await fs.promises.writeFile(temporary, JSON.stringify({ sessionId: record.sessionId, backendId: opened.terminalSession.sessionId }), { mode: 0o600 });
|
|
2412
2490
|
await fs.promises.rename(temporary, launchFile);
|
|
2413
|
-
await writeAutomaticTerminalPrompt(opened.session.sessionId, buildCollaborationSpawnCommand({ slug: launcher.slug, command: inheritedProfile?.command ?? launcher.command }));
|
|
2491
|
+
await writeAutomaticTerminalPrompt(opened.session.sessionId, buildCollaborationSpawnCommand({ slug: launcher.slug, command: inheritedProfile?.command ?? launcher.command }), undefined, launchGuard);
|
|
2414
2492
|
}
|
|
2415
2493
|
const group = collaborationStore.getGroup(task.groupId);
|
|
2416
2494
|
if (!group || group.deleted)
|
|
@@ -6078,8 +6156,8 @@ router.post('/tmux/recovery/restore-all', async (_req, res) => {
|
|
|
6078
6156
|
const previous = collaborationRouting.get(frontendSessionId);
|
|
6079
6157
|
if (previous)
|
|
6080
6158
|
collaborationRouting.bind({ ...previous, pane: null });
|
|
6081
|
-
await beginAgentLaunchCheck(frontendSessionId, agent.slug, target.nativeSessionId);
|
|
6082
|
-
await writeAutomaticTerminalPrompt(frontendSessionId, command);
|
|
6159
|
+
const launchGuard = await beginAgentLaunchCheck(frontendSessionId, agent.slug, target.nativeSessionId);
|
|
6160
|
+
await writeAutomaticTerminalPrompt(frontendSessionId, command, undefined, launchGuard);
|
|
6083
6161
|
}));
|
|
6084
6162
|
outcomes.push({ sessionId: frontendSessionId, restored: true });
|
|
6085
6163
|
}
|
|
@@ -6474,7 +6552,8 @@ router.get('/operations/collaboration-groups/:groupId/messages', (req, res) => {
|
|
|
6474
6552
|
return ambiguousGroupResponse(res, ambiguous);
|
|
6475
6553
|
if (!group)
|
|
6476
6554
|
return res.status(404).json({ error: '协作组不存在' });
|
|
6477
|
-
res.json({ messages: collaborationStore.listMessages(group.id, Number(req.query.limit) || 200)
|
|
6555
|
+
res.json({ messages: collaborationStore.listMessages(group.id, Number(req.query.limit) || 200)
|
|
6556
|
+
.map(message => ({ ...message, delivery: collaborationStore.receipt(message.id).delivery })) });
|
|
6478
6557
|
});
|
|
6479
6558
|
router.post('/operations/collaboration-groups/:groupId/messages', (req, res) => {
|
|
6480
6559
|
try {
|
|
@@ -6789,7 +6868,7 @@ router.post('/operations/orchestration/drive', async (req, res) => {
|
|
|
6789
6868
|
}
|
|
6790
6869
|
});
|
|
6791
6870
|
router.use('/operations/orchestration', collaborationRoutes({ store: collaborationStore, resolveSession: resolveFrontendSessionId,
|
|
6792
|
-
deliver: tryDeliverCollaborationInbox, rebind: rebindCollaborationRoute,
|
|
6871
|
+
deliver: tryDeliverCollaborationInbox, rebind: rebindCollaborationRoute, diagnoseRoute: describeCollaborationRoute,
|
|
6793
6872
|
resolveNames: (ids) => {
|
|
6794
6873
|
const names = new Map([...collaborationRemoteSessions(),
|
|
6795
6874
|
...globalSessionState.sessions.map(orchestrationSessionSnapshot)].map((session) => [session.sessionId, session.name]));
|
|
@@ -7031,8 +7110,8 @@ router.post('/operations/execution-archives/:sessionId/restore', executionArchiv
|
|
|
7031
7110
|
broadcastClientState();
|
|
7032
7111
|
throw error;
|
|
7033
7112
|
}
|
|
7034
|
-
await beginAgentLaunchCheck(record.sessionId, target.slug, target.nativeSessionId);
|
|
7035
|
-
await writeAutomaticTerminalPrompt(opened.session.sessionId, command);
|
|
7113
|
+
const launchGuard = await beginAgentLaunchCheck(record.sessionId, target.slug, target.nativeSessionId);
|
|
7114
|
+
await writeAutomaticTerminalPrompt(opened.session.sessionId, command, undefined, launchGuard);
|
|
7036
7115
|
restoreArchivedMembership(entry, record.sessionId);
|
|
7037
7116
|
await persistGlobalStateNow();
|
|
7038
7117
|
broadcastClientState();
|
|
@@ -8276,10 +8355,9 @@ router.post('/:sessionId/agent-resume', async (req, res) => {
|
|
|
8276
8355
|
try {
|
|
8277
8356
|
const frontend = globalSessionState.sessions.find(candidate => candidate.backendSessionId === sessionId);
|
|
8278
8357
|
const launch = async () => {
|
|
8358
|
+
const launchGuard = frontend ? await beginAgentLaunchCheck(frontend.sessionId, target.slug, target.nativeSessionId) : undefined;
|
|
8279
8359
|
if (frontend)
|
|
8280
|
-
await
|
|
8281
|
-
if (frontend)
|
|
8282
|
-
await writeAutomaticTerminalPrompt(frontend.sessionId, target.command);
|
|
8360
|
+
await writeAutomaticTerminalPrompt(frontend.sessionId, target.command, undefined, launchGuard);
|
|
8283
8361
|
else
|
|
8284
8362
|
await writeBracketedPrompt(session.ptyProcess, target.command, captureTerminalInputGuard(() => terminalSessions.get(sessionId), session));
|
|
8285
8363
|
};
|
package/docs/integrations.md
CHANGED
|
@@ -1169,3 +1169,125 @@ TD/native session ID、消息/reply、事件/consumer 历史。没有 Agent 启
|
|
|
1169
1169
|
并发不同键竞争/同键重放、删除/跨服务、管理员 Unix 路由/CLI 权限及 JSON、网页列表
|
|
1170
1170
|
回读和旧网页表单版本冲突。DevBox 业务组及真实 macOS/iOS 显示尚待接入方实机验收,
|
|
1171
1171
|
不以源码/模拟回归代替其运行现场。
|
|
1172
|
+
|
|
1173
|
+
## 1.4.321:普通协作会话的承载变化、阻断诊断与恢复
|
|
1174
|
+
|
|
1175
|
+
最低 CLI/实际服务均为 **1.4.321**;普通协作协议仍为 2,integration protocol 仍为 1。
|
|
1176
|
+
当前 CLI 版本不能替代实际服务版本;普通成员使用
|
|
1177
|
+
`td collab --session <自身ID> capabilities --json` 回读 `server_version`、
|
|
1178
|
+
`route_diagnostics=true`、`route_identity_recovery=true`、
|
|
1179
|
+
`route_identity_recovery_min_version=1.4.321`。
|
|
1180
|
+
|
|
1181
|
+
```sh
|
|
1182
|
+
td collab --session <自身ID> route get <精确本地目标ID> --json
|
|
1183
|
+
td collab --session <自身ID> message get <原消息ID> --receipt-only --json
|
|
1184
|
+
# 只有目标拥有者在自己的真实终端确认“当前承载就是目标”后执行:
|
|
1185
|
+
td collab --session <目标自身ID> rebind --pane <当前pane-ID> --json
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
`route get` 为只读 `GET /operations/orchestration/route/:id`,只允许自身或共享组的本地
|
|
1189
|
+
成员;不解析前缀/名称,不替远端拥有者查询其当前进程。旧服务缺能力时 CLI 明确拒绝。
|
|
1190
|
+
返回 `route.session_id/binding/worker/observed_at/state/error/identity`:worker 包括
|
|
1191
|
+
`started/tick_in_progress/recipient_in_progress/last_tick_at/route/pending_count`;identity
|
|
1192
|
+
包括原 `expected`、当前 `observed`(最多 20 项、`truncated`)、`recovery/reason` 和
|
|
1193
|
+
拥有者正式 `rebind_command`。只导出承载标识、Agent 类型及原生身份证据元数据,
|
|
1194
|
+
没有终端正文、argv、环境或凭据。证据未知即未知,不使用旧缓存 UUID 替代当前身份。
|
|
1195
|
+
只读查询不启动/恢复 Agent、改绑或补键,不把进程/身份正确称为输入已就绪。
|
|
1196
|
+
|
|
1197
|
+
已绑定的 tmux server/session/pane/PID 变化时,原物理身份保护仍拒绝直接写入。
|
|
1198
|
+
消息维持 `status=pending`,诊断会给 `delivery.stage=blocked`、`error=TMUX_PANE_CHANGED`、
|
|
1199
|
+
`route_state`、`requires_confirmation` 及 `route` 差异/建议;`attempt_count=0` 表示尚未
|
|
1200
|
+
尝试写入,不等于失败后可重发。现有 `message.delivery` 主动事件携带该 receipt;
|
|
1201
|
+
网页协作记录也展示绑定变化和投递暂停,保留原正文。跨服务交换在状态不变但错误变化
|
|
1202
|
+
时仍同步错误,不因 pending 状态相同而隐去新的阻断。运行服务未采集过的历史差异
|
|
1203
|
+
不能由新版本凭空补出;`worker.started` 等字段用于确认当前调度事实。
|
|
1204
|
+
|
|
1205
|
+
本地/远端目标依据稳定 `remote:` 地址区分,组是否 federated 不影响组内本地消息进入
|
|
1206
|
+
本地 worker。后台 worker 在会话登记加载完成后启动,不等待额外 PTY adoption 或
|
|
1207
|
+
tmux 元数据 backfill;订阅消息存储变化并保留定时重试。缺绑定/进程/权限时仍保留原
|
|
1208
|
+
消息,诊断拒绝原因,不依赖网页维持投递。此加固不能替代旧现场的运行证据,也不能
|
|
1209
|
+
从过去缺少 transport 条目推断唯一内部根因。
|
|
1210
|
+
|
|
1211
|
+
承载变化后的**自动**更新仅用于普通 tmux 会话,并同时要求:原生 ID/Agent 类型已知,
|
|
1212
|
+
当前可信 provider 独立核验同一原生 ID、同一 Agent,唯一匹配且原逻辑记录/后端/pane
|
|
1213
|
+
归属无冲突,没有原待投递消息的未确认写入尝试。对账前再次核验当前候选和登记,
|
|
1214
|
+
首次继续写入前再次核验当前原生身份。只改绑定,不启动/恢复/切换原生 Agent。
|
|
1215
|
+
当前独立证据 provider 是已配置的 Linux flock-owner 核验;核心不按 Agent 名称或
|
|
1216
|
+
TUI 展示字符串分支。argv 的 resume ID 只能作为启动意图元数据,单独不满足自动更新。
|
|
1217
|
+
因此没有可靠 provider 的 Mac 冷启动 Codex 等场景需要明确拥有者确认,不能宣称跨
|
|
1218
|
+
平台自动身份恢复已通过。独立证据的能力/适用平台由 provider 决定。
|
|
1219
|
+
|
|
1220
|
+
原生身份缺失/不同、多匹配、归属不明或此前写入结果不明时,保留原消息并显示
|
|
1221
|
+
`confirmation-required` 及对应原因(`NATIVE_IDENTITY_UNCONFIRMED`、
|
|
1222
|
+
`MULTIPLE_NATIVE_IDENTITY_MATCHES`、`ROUTE_OWNERSHIP_UNCONFIRMED`、
|
|
1223
|
+
`DELIVERY_OUTCOME_UNCONFIRMED`)。拥有者确认当前承载后可用现有 rebind 明确接受当前
|
|
1224
|
+
Agent/原生身份;这不是承诺精确恢复旧原生历史,也不要求猜 UUID 或编辑私有记录。
|
|
1225
|
+
无运行 tmux 的情况须先通过原会话恢复入口恢复承载,不能靠 rebind 新建。
|
|
1226
|
+
|
|
1227
|
+
重新绑定与投递按该逻辑成员的 worker 屏障串行,持久保存 `routeRevision` 和
|
|
1228
|
+
`lastRecovery={kind,at,previousPane}`,后者只记录最近一次自动/显式绑定恢复。
|
|
1229
|
+
绑定以 routing 文件原子替换提交;失败不采用新绑定。输入队列同时核验 routeRevision,
|
|
1230
|
+
旧队列不能在新绑定上继续粘贴/提交。待处理消息已经记录尝试(`attempt_count>0`)而结果
|
|
1231
|
+
未确认时,显式 rebind 返回 `ROUTE_DELIVERY_OUTCOME_UNCONFIRMED`,先对账,不能借修复
|
|
1232
|
+
重发正文。记录不承诺永久审计或跨掉电的恰好一次输入;原终端传输的写入语义/保留
|
|
1233
|
+
边界不变。
|
|
1234
|
+
|
|
1235
|
+
`IntegrationSession` 不通过普通 rebind 绕过其代次/精确 UUID/配置与所有者保护,须继续
|
|
1236
|
+
用受限 principal 的 `session get/restore`;普通 rebind 对此返回
|
|
1237
|
+
`INTEGRATION_SESSION_RESTORE_REQUIRED`。当前修复不改变业务任务、principal、组、
|
|
1238
|
+
message/thread/幂等键或历史,不自动补 Enter、不用屏幕文字识别消费;delivered 仍只
|
|
1239
|
+
表示终端写入,完成须明确回复。
|
|
1240
|
+
|
|
1241
|
+
回归覆盖同组本地消息处于 federated 组、存储变化唤醒/后台阻断、修复后原消息单次
|
|
1242
|
+
投递、不同/缺失/弱原生证据、多匹配/归属/未知旧写入拒绝、绑定持久化和失败、
|
|
1243
|
+
只读路由权限/CLI、网页暂停提示及加密传输边界。Mac 实际现场的当前原生身份尚未独立确认,原消息尚待拥有者确认及接入方实际服务
|
|
1244
|
+
升级/回读后继续投递;不以维护机回归冒充该现场已恢复。
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
## 1.4.322:启动代次一致性与输入检查诊断
|
|
1248
|
+
|
|
1249
|
+
最低实际服务 **1.4.322**,配套 CLI 也升级至 1.4.322。`capabilities` 回读:
|
|
1250
|
+
`agent_launch_generation_consistency=true`、
|
|
1251
|
+
`agent_launch_generation_consistency_min_version=1.4.322`、
|
|
1252
|
+
`terminal_input_check_diagnostics=true`。普通协作协议仍为 2,integration protocol 仍为 1;
|
|
1253
|
+
不新增权限。只更新 CLI 不会改变正在运行的旧服务。
|
|
1254
|
+
|
|
1255
|
+
启动代次是 TD 服务生成的 `agentLaunchGeneration`,与原生 Agent UUID、
|
|
1256
|
+
IntegrationSession 的数值 `generation` 分别记录。同一 backend 在启动准备时从 null
|
|
1257
|
+
变为新的启动 UUID 是正常动作。名称、cwd、原生身份元数据等整记录更新过去可能
|
|
1258
|
+
携带 await 之前的旧启动字段写回;本版将启动字段交由专门的比较后更新路径管理,
|
|
1259
|
+
普通元数据更新继承当前启动代次与一次性检查,不能覆盖或复活旧值。
|
|
1260
|
+
|
|
1261
|
+
启动操作在写入本次代次后、持久化之前捕获自己的输入检查令牌,并在持久化返回、
|
|
1262
|
+
承载解析、获取输入队列及粘贴/提交前持续使用它。冷启动、精确恢复、显式 cold retry
|
|
1263
|
+
和普通启动共用这条保护;不会为了继续输入而采纳后来出现的启动代次。启动状态
|
|
1264
|
+
落盘失败时不输入。真实 backend 对象/ID、绑定版本、tmux pane 或启动代次变化仍拒绝,
|
|
1265
|
+
保留 `TERMINAL_INPUT_TARGET_CHANGED` / `TMUX_PANE_CHANGED` 等错误。
|
|
1266
|
+
|
|
1267
|
+
管理员沿现有入口读取已保存的诊断:
|
|
1268
|
+
|
|
1269
|
+
```sh
|
|
1270
|
+
td integration diagnostics <TD-session-id>
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
`launch_diagnostics.steps` 追加可选阶段 `guard_captured / runtime_resolving / runtime_resolved`;
|
|
1274
|
+
既有 `queue_wait / queue_acquired / paste_* / submit_*` 保留。拒绝时
|
|
1275
|
+
`target_change` 可含 `check_phase / guard_captured_at / checked_at`,以及
|
|
1276
|
+
`expected_launch_id / current_launch_id`、backend ID/实例比较、绑定版本比较。
|
|
1277
|
+
`check_phase` 包含 `launch_state_commit / guard_capture / launch_persisted / runtime_resolve /
|
|
1278
|
+
runtime_resolved / queue_acquired / before_paste / before_submit`。时间是 TD 检查时间,
|
|
1279
|
+
不是内核首字节写入时间;不包含正文、argv、环境或凭据。旧记录不补造缺失的证据。
|
|
1280
|
+
|
|
1281
|
+
这次修复不增加自动重试:原 create 同键只回读原操作。失败现场保留,先用
|
|
1282
|
+
`session get` 核对当前事实;明确授权后才按现有 `session retry-cold` 契约显式操作,
|
|
1283
|
+
必须满足无原生 UUID、无 TD 消息历史或待投递、精确原 shell、配置指纹与代次等条件。
|
|
1284
|
+
已有原生 UUID 的会话继续精确 restore,不能以 cold retry 替代。消息正文不因升级重发。
|
|
1285
|
+
|
|
1286
|
+
升级由现场唯一维护者协调:保留现有 HTTPS/鉴权参数,仅替换并重启 TD 服务;
|
|
1287
|
+
核对在跑 tmux/Agent 完整身份没有变化,再回读实际服务版本和以上能力。
|
|
1288
|
+
本版不要求重启、重建或重试业务 Agent,不更改 launch profile、sandbox 或业务调度。
|
|
1289
|
+
终端动作仍是粘贴一次、50ms 后发送一次回车;TD 仍不保证应用提交、消费或执行完成。
|
|
1290
|
+
|
|
1291
|
+
确定性交错回归覆盖延迟改名/元数据回写、清除检查、持久化等待、输入队列等待、
|
|
1292
|
+
真实第二次启动、backend 替换及重新绑定;发生真实换代时,旧输入及旧的延迟回车
|
|
1293
|
+
仍被拒绝。测试证明 TD 一致性与终端写入边界,不代替私有 Agent 的实机消费验收。
|
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.322",
|
|
5
5
|
"runtimeProtocolVersion": 1,
|
|
6
6
|
"minimumDesktopVersion": "1.4.46",
|
|
7
7
|
"nodeMajor": 22,
|
|
8
8
|
"dependencyHash": "sha256-oaGYi/P5ob8sd6VnNBOwshKozjhdV+hYiCmLAsn5x00=",
|
|
9
|
-
"serverBundleHash": "sha256-
|
|
10
|
-
"clientBundleHash": "sha256
|
|
9
|
+
"serverBundleHash": "sha256-T9JZp3X9tfMUYciSrnZbiUIXuc+IHqHJuGp6Wf5bHs8=",
|
|
10
|
+
"clientBundleHash": "sha256-4wVT4/UzD+TMRQjVw307g0c0x0cJm6NknoDeybiIQfA=",
|
|
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{by as r}from"./app-BRESmgxW.js";import{b as m}from"./dnd-BCFAPC0L.js";import{b as n}from"./RightSidebar-7C9-PfhA.js";import"./react-XDCjal2T.js";import"./terminal-C7X98Amf.js";import"./App-BF6YvbKL.js";import"./gestureArbiter-DalDKZKj.js";import"./triangle-alert-DG_BJhJY.js";import"./referenceLongPress-DfQ5jnsk.js";import"./DiffReview-CjEi6PCy.js";import"./sparkles-DbcgKKVd.js";import"./DiffViewer-Bh6lvUYN.js";import"./ChangeWalkthroughPanel-B59JwhzK.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
|