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
|
@@ -355,7 +355,8 @@ export class CollaborationPeerTransport {
|
|
|
355
355
|
return [];
|
|
356
356
|
const facts = terminalMessage(message);
|
|
357
357
|
const known = Array.isArray(packet.known) ? packet.known.find((item) => item?.id === message.id) : undefined;
|
|
358
|
-
if (known && known.status === facts.status && known.deliveredAt === facts.deliveredAt && known.shellConfirmed === message.shellConfirmed && (known.hasSnapshot || !message.snapshot)
|
|
358
|
+
if (known && known.status === facts.status && known.deliveredAt === facts.deliveredAt && known.shellConfirmed === message.shellConfirmed && (known.hasSnapshot || !message.snapshot)
|
|
359
|
+
&& known.last_error === (store.diagnostic(message.id)?.last_error ?? null))
|
|
359
360
|
return [];
|
|
360
361
|
const receipt = store.receipt(message.id);
|
|
361
362
|
return [{ id: message.id, status: facts.status, deliveredAt: facts.deliveredAt,
|
|
@@ -447,7 +448,7 @@ export class CollaborationPeerTransport {
|
|
|
447
448
|
for (const message of payloads) {
|
|
448
449
|
const result = await client.request({ type: 'collaboration-exchange', groupId: b.groupId,
|
|
449
450
|
context: mapContext(store.context(b.groupId), id => id.startsWith('remote:') ? id : remoteSession(b.localOrigin, id)),
|
|
450
|
-
ids: batch.map(m => m.id), known: batch.map(m => ({ id: m.id, status: m.status, deliveredAt: m.deliveredAt, hasSnapshot: !!m.snapshot, shellConfirmed: m.shellConfirmed })), ...(message ? { message } : {}) });
|
|
451
|
+
ids: batch.map(m => m.id), known: batch.map(m => ({ id: m.id, status: m.status, deliveredAt: m.deliveredAt, hasSnapshot: !!m.snapshot, shellConfirmed: m.shellConfirmed, last_error: store.diagnostic(m.id)?.last_error ?? null })), ...(message ? { message } : {}) });
|
|
451
452
|
if (Array.isArray(result.activity))
|
|
452
453
|
for (const item of result.activity.slice(0, 500)) {
|
|
453
454
|
if (!item || typeof item.sessionId !== 'string' || item.sessionId.startsWith('remote:'))
|
|
@@ -10,7 +10,7 @@ import { COLLAB_LIMITS, CollaborationError, MIN_ID_PREFIX_LENGTH, ambiguousIdMes
|
|
|
10
10
|
export function cleanMemberName(value) {
|
|
11
11
|
return value.replace(/[\u0000-\u001f\u007f]/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 80);
|
|
12
12
|
}
|
|
13
|
-
export function collaborationRoutes({ store, resolveSession, deliver, rebind, resolveNames, renameSession }) {
|
|
13
|
+
export function collaborationRoutes({ store, resolveSession, deliver, rebind, diagnoseRoute, resolveNames, renameSession }) {
|
|
14
14
|
const router = Router();
|
|
15
15
|
const run = (handler) => async (req, res) => {
|
|
16
16
|
try {
|
|
@@ -96,6 +96,16 @@ export function collaborationRoutes({ store, resolveSession, deliver, rebind, re
|
|
|
96
96
|
}
|
|
97
97
|
res.json({ ok: true, route: await rebind(sessionId, pane ?? null) });
|
|
98
98
|
}));
|
|
99
|
+
router.get('/route/:id', run(async (req, res, sessionId) => {
|
|
100
|
+
const id = String(req.params.id);
|
|
101
|
+
if (id !== sessionId && !store.groupsForSession(sessionId).some(group => group.sessionIds.includes(id)))
|
|
102
|
+
throw new CollaborationError('NOT_A_GROUP_MEMBER', 'Route diagnostics require a shared group', 403);
|
|
103
|
+
if (id.startsWith('remote:'))
|
|
104
|
+
throw new CollaborationError('REMOTE_ROUTE_DIAGNOSTICS_UNSUPPORTED', 'Query the owning service for the current runtime evidence', 409);
|
|
105
|
+
if (!diagnoseRoute)
|
|
106
|
+
throw new CollaborationError('ROUTE_DIAGNOSTICS_UNAVAILABLE', 'The running service does not support route diagnostics (minimum 1.4.321)', 409);
|
|
107
|
+
res.json({ ok: true, route: await diagnoseRoute(id) });
|
|
108
|
+
}));
|
|
99
109
|
/** Accepts the short id a terminal shows as well as the full one; an
|
|
100
110
|
* ambiguous prefix is refused rather than guessed, so a reply can never
|
|
101
111
|
* land on the wrong thread. */
|
|
@@ -152,6 +162,9 @@ export function collaborationRoutes({ store, resolveSession, deliver, rebind, re
|
|
|
152
162
|
};
|
|
153
163
|
router.get('/capabilities', run((_req, res) => {
|
|
154
164
|
res.json({ protocol_version: 2, server_version: getTermdockVersion(), limits: COLLAB_LIMITS,
|
|
165
|
+
route_diagnostics: !!diagnoseRoute, route_identity_recovery: !!diagnoseRoute, route_identity_recovery_min_version: '1.4.321',
|
|
166
|
+
agent_launch_generation_consistency: true, agent_launch_generation_consistency_min_version: '1.4.322',
|
|
167
|
+
terminal_input_check_diagnostics: true,
|
|
155
168
|
task_workflow: { version: 2, command: 'td collab task', single_authority: true, explicit_reports: true,
|
|
156
169
|
managed_goals: true, automatic_review: true, dependency_dispatch: true, isolated_worktrees: true, encrypted_commit_transfer: true,
|
|
157
170
|
durable_questions: true, user_acceptance: true, versioned_artifacts: true, independent_reviews: true,
|
|
@@ -17,6 +17,11 @@ export class CollaborationRoutingStore {
|
|
|
17
17
|
|| !/^%\d+$/.test(binding.pane.paneId) || !/^\$\d+$/.test(binding.pane.sessionId) || typeof binding.pane.agentSlug !== 'string'))) {
|
|
18
18
|
throw new Error('Invalid collaboration binding');
|
|
19
19
|
}
|
|
20
|
+
if (binding.routeRevision !== undefined && (typeof binding.routeRevision !== 'string' || !/^[a-zA-Z0-9-]{1,80}$/.test(binding.routeRevision)))
|
|
21
|
+
throw new Error('Invalid route revision');
|
|
22
|
+
if (binding.lastRecovery !== undefined && (!binding.lastRecovery || !['native-identity', 'owner-confirmed'].includes(binding.lastRecovery.kind)
|
|
23
|
+
|| !Number.isSafeInteger(binding.lastRecovery.at)))
|
|
24
|
+
throw new Error('Invalid route recovery record');
|
|
20
25
|
this.bindings.set(binding.sessionId, binding);
|
|
21
26
|
}
|
|
22
27
|
}
|
|
@@ -38,6 +43,10 @@ export class CollaborationRoutingStore {
|
|
|
38
43
|
ownerOfBackend(id) {
|
|
39
44
|
return [...this.bindings.values()].find((binding) => binding.backendSessionId === id)?.sessionId ?? null;
|
|
40
45
|
}
|
|
46
|
+
hasOtherPaneOwner(id, pane) {
|
|
47
|
+
return [...this.bindings.values()].some(binding => binding.sessionId !== id && binding.pane
|
|
48
|
+
&& binding.pane.serverPid === pane.serverPid && binding.pane.sessionId === pane.sessionId && binding.pane.paneId === pane.paneId);
|
|
49
|
+
}
|
|
41
50
|
bind(binding) {
|
|
42
51
|
this.assertReadable();
|
|
43
52
|
const owner = binding.backendSessionId ? this.ownerOfBackend(binding.backendSessionId) : null;
|
|
@@ -65,6 +74,29 @@ export class CollaborationRoutingStore {
|
|
|
65
74
|
this.bindings = next;
|
|
66
75
|
}
|
|
67
76
|
}
|
|
77
|
+
export function assessCollaborationRouteIdentity(binding, panes, ownershipConfirmed, unconfirmedWrite) {
|
|
78
|
+
const selected = selectCollaborationPane(binding, panes);
|
|
79
|
+
const metadata = (pane) => ({ serverPid: pane.serverPid, sessionId: pane.sessionId,
|
|
80
|
+
paneId: pane.paneId, panePid: pane.panePid, agentSlug: pane.agentSlug, nativeSessionId: pane.nativeSessionId });
|
|
81
|
+
const diagnostics = { expected: binding.pane ? { ...binding.pane } : null,
|
|
82
|
+
observed: panes.slice(0, 20).map(pane => ({ ...metadata(pane), nativeIdentitySource: pane.nativeIdentitySource ?? null, nativeIdentityFailure: pane.nativeIdentityFailure ?? null, nativeIdentityVerified: pane.nativeIdentityVerified === true })),
|
|
83
|
+
truncated: panes.length > 20, recovery: 'unchanged', reason: null,
|
|
84
|
+
rebind_command: `td collab --session ${binding.sessionId} rebind${panes.length === 1 ? ` --pane ${panes[0].paneId}` : ''}` };
|
|
85
|
+
if (selected.state !== 'identity-mismatch')
|
|
86
|
+
return { ...selected, diagnostics };
|
|
87
|
+
const nativeId = binding.pane?.nativeSessionId ?? binding.nativeSessionId;
|
|
88
|
+
const slug = binding.pane?.agentSlug || binding.agentSlug;
|
|
89
|
+
const matching = panes.filter(pane => !pane.isShell && pane.agentSlug === slug && pane.nativeSessionId === nativeId
|
|
90
|
+
&& !pane.nativeIdentityFailure && pane.nativeIdentityVerified === true);
|
|
91
|
+
diagnostics.recovery = 'confirmation-required';
|
|
92
|
+
diagnostics.reason = unconfirmedWrite ? 'DELIVERY_OUTCOME_UNCONFIRMED' : !ownershipConfirmed ? 'ROUTE_OWNERSHIP_UNCONFIRMED'
|
|
93
|
+
: !nativeId || !slug ? 'NATIVE_IDENTITY_UNCONFIRMED' : matching.length > 1 ? 'MULTIPLE_NATIVE_IDENTITY_MATCHES'
|
|
94
|
+
: matching.length !== 1 ? 'NATIVE_IDENTITY_UNCONFIRMED' : null;
|
|
95
|
+
if (diagnostics.reason)
|
|
96
|
+
return { ...selected, diagnostics };
|
|
97
|
+
diagnostics.recovery = 'automatic';
|
|
98
|
+
return { state: 'ready', pane: matching[0], diagnostics };
|
|
99
|
+
}
|
|
68
100
|
// Once pinned, changing the active pane cannot change the recipient. A reused
|
|
69
101
|
// tmux name/pane after a server restart must not inherit an old peer's inbox.
|
|
70
102
|
export function selectCollaborationPane(binding, panes) {
|
|
@@ -584,6 +584,10 @@ export class CollaborationStore {
|
|
|
584
584
|
this.expire();
|
|
585
585
|
return [...new Set(this.document.messages.filter((message) => message.status === 'pending').map((message) => message.toSessionId))];
|
|
586
586
|
}
|
|
587
|
+
hasUnconfirmedDelivery(sessionId) {
|
|
588
|
+
return this.document.messages.some(message => message.toSessionId === sessionId && message.status === 'pending'
|
|
589
|
+
&& (this.document.transport?.[message.id]?.attempt_count ?? 0) > 0);
|
|
590
|
+
}
|
|
587
591
|
confirmShell(messageId) {
|
|
588
592
|
const message = this.getMessage(messageId);
|
|
589
593
|
if (!message || message.status !== 'pending')
|
|
@@ -773,6 +777,25 @@ export class CollaborationStore {
|
|
|
773
777
|
(this.document.transport ??= {})[id] = diagnostic;
|
|
774
778
|
this.persist();
|
|
775
779
|
}
|
|
780
|
+
/** A route blocks the whole recipient queue, not just its first message. */
|
|
781
|
+
recordRecipientTransport(sessionId, patch) {
|
|
782
|
+
let changed = false;
|
|
783
|
+
for (const message of this.document.messages) {
|
|
784
|
+
if (message.toSessionId !== sessionId || message.status !== 'pending')
|
|
785
|
+
continue;
|
|
786
|
+
const previous = this.document.transport?.[message.id];
|
|
787
|
+
if ((previous?.checked_at ?? 0) > patch.checked_at)
|
|
788
|
+
continue;
|
|
789
|
+
const next = { relay_online: null, peer_reachable: null, next_retry_at: null, last_error: null,
|
|
790
|
+
...previous, ...patch, attempt_count: previous?.attempt_count ?? 0 };
|
|
791
|
+
if (JSON.stringify(previous) === JSON.stringify(next))
|
|
792
|
+
continue;
|
|
793
|
+
(this.document.transport ??= {})[message.id] = next;
|
|
794
|
+
changed = true;
|
|
795
|
+
}
|
|
796
|
+
if (changed)
|
|
797
|
+
this.persist();
|
|
798
|
+
}
|
|
776
799
|
receipt(id, raw = false) {
|
|
777
800
|
const message = this.getMessage(id);
|
|
778
801
|
if (!message)
|
|
@@ -788,7 +811,10 @@ export class CollaborationStore {
|
|
|
788
811
|
failure_reason: message.failureReason ?? null, delivery_semantics: message.status === 'stored' ? 'durable_storage' : facts.deliverySource ?? (facts.deliveredAt === null ? 'not_delivered' : 'legacy_or_unspecified'),
|
|
789
812
|
snapshot: message.snapshot ? (raw ? message.snapshot : plainCollaborationSnapshot(message.snapshot)) : null,
|
|
790
813
|
delivery: { status: facts.status,
|
|
791
|
-
stage: message.status === 'stored' ? 'stored' : facts.deliveredAt !== null ? 'terminal_written' : diagnostic?.remote_received_at ? 'remote_received' : 'queued',
|
|
814
|
+
stage: message.status === 'stored' ? 'stored' : facts.deliveredAt !== null ? 'terminal_written' : diagnostic?.route_state === 'identity-mismatch' || diagnostic?.last_error === 'TMUX_PANE_CHANGED' ? 'blocked' : diagnostic?.remote_received_at ? 'remote_received' : 'queued',
|
|
815
|
+
...(!diagnostic?.route_diagnostics && diagnostic?.last_error === 'TMUX_PANE_CHANGED' ? { requires_confirmation: true } : {}),
|
|
816
|
+
...(diagnostic?.route_diagnostics ? { route: diagnostic.route_diagnostics, route_state: diagnostic.route_state,
|
|
817
|
+
requires_confirmation: diagnostic.route_diagnostics.recovery === 'confirmation-required' } : {}),
|
|
792
818
|
remote_received_at: diagnostic?.remote_received_at ?? null, delivered_at: facts.deliveredAt, error: message.failureReason ?? diagnostic?.last_error ?? null },
|
|
793
819
|
reply: { status: replies.length ? 'received' : 'pending', ack_at: replies.find(reply => reply.responseKind === 'ack')?.createdAt ?? null, reply_ids: replies.map(reply => reply.id) },
|
|
794
820
|
idempotency_key: message.idempotencyKey ?? null,
|
|
@@ -15,7 +15,7 @@ export async function executeTaskCommand(command, request, io) {
|
|
|
15
15
|
plan: [...bodyOptions, 'attempt', 'evidence'], review: [...bodyOptions, 'artifact', 'evidence', 'verdict'], comment: bodyOptions,
|
|
16
16
|
'request-review': [...bodyOptions, 'artifact', 'assignee', 'revision'],
|
|
17
17
|
revise: [...bodyOptions, 'revision'], close: [...bodyOptions, 'revision'], reopen: [...bodyOptions, 'revision'],
|
|
18
|
-
coordinate: [...bodyOptions, 'revision'], pause: [...bodyOptions, 'revision'], resume: [...bodyOptions, 'revision'], retry: [...bodyOptions, 'revision'],
|
|
18
|
+
coordinate: [...bodyOptions, 'revision', 'summary'], pause: [...bodyOptions, 'revision'], resume: [...bodyOptions, 'revision'], retry: [...bodyOptions, 'revision'],
|
|
19
19
|
};
|
|
20
20
|
for (const flag of Object.keys(o))
|
|
21
21
|
if (![...allowed[operation], ...(o.principal ? originOptions : []), 'principal', 'session', 'json', 'jsonl', 'text', 'help'].includes(flag))
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** Shared across first dispatch and subsequent coordination wakes. */
|
|
2
|
+
export const GOAL_EXPERIENCE_GUIDE = "用户可理解的拆分与更新:一个用户目标保留一张主卡片,所有执行工作都挂在这个目标下;跟进与返工沿用原目标,不用新的顶层目标表达同一件事。子任务按可验收成果划分,一项有明确产物、负责人、完成标准和必要依赖;标题用简短动词加成果名称,不用角色名、过程日志、ID或‘好的/按计划’。简单问题只安排一个必要执行任务;复杂任务仅在产物或负责人可独立验收时拆分,不为采集、复述、重复汇总制造多份卡片。首次拆分后、范围或依赖变化、明确里程碑或受阻时,用 task coordinate --revision <最新版本> --summary '已完成什么;当前推进什么;下一步或需要用户什么' --content '工作划分、各项产物、依赖顺序和依据' 更新当前目标。摘要面向用户,简短说明变化和下一步,不堆哈希、路径、版本号和验证日志;完整证据保留正文。执行成员用 report --attempt <当前尝试> --status working|blocked|failed --summary '当前明确进展或缺少的条件';没有新事实不要重复发报告,不报告百分比、预估剩余时间或无法观测的内部活动。只有存在必要的人类决定时用 task ask,普通安排说明不要求用户确认方案。";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GOAL_EXPERIENCE_GUIDE } from './collaborationTaskGuidance.js';
|
|
1
2
|
import { randomBytes, createHash } from 'node:crypto';
|
|
2
3
|
import { readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs';
|
|
3
4
|
import { dirname } from 'node:path';
|
|
@@ -186,15 +187,17 @@ export class CollaborationTaskStore {
|
|
|
186
187
|
const current = task.attempts.find(a => a.id === task.activeAttemptId);
|
|
187
188
|
const result = task.artifacts.filter(a => a.kind === 'result' && a.attemptId === task.activeAttemptId).at(-1);
|
|
188
189
|
const plan = task.artifacts.filter(a => a.kind === 'plan' && a.attemptId === task.activeAttemptId).at(-1);
|
|
189
|
-
const reportSummary = current?.report?.content.split(/\n\s*\n/).map(paragraph => paragraph.split('\n').filter(line => !/^#{1,6}\s/.test(line)).join('\n').trim()).find(Boolean)?.slice(0, 512);
|
|
190
|
+
const reportSummary = (current?.report?.summary || current?.report?.content.split(/\n\s*\n/).map(paragraph => paragraph.split('\n').filter(line => !/^#{1,6}\s/.test(line)).join('\n').trim()).find(Boolean))?.slice(0, 512);
|
|
191
|
+
const coordination = task.events.filter(e => e.kind === 'coordinate' && e.attemptId === task.activeAttemptId).at(-1);
|
|
190
192
|
const automationIssueSource = task.automationIssue ? current?.report && ['blocked', 'failed'].includes(current.report.status)
|
|
191
193
|
&& task.automationIssue === current.report.content.slice(0, 1000) ? 'member-report' : 'system' : undefined;
|
|
192
|
-
return { ...task, ...(task.purpose === 'automation' ? { execution: taskExecution(task) } : {}), automationIssueSource, spec: task.spec.slice(0, 512), constraints: '', acceptance:
|
|
194
|
+
return { ...task, ...(task.purpose === 'automation' ? { execution: taskExecution(task) } : {}), automationIssueSource, spec: task.spec.slice(0, 512), constraints: '', acceptance: task.acceptance.slice(0, 512),
|
|
193
195
|
deliveries: task.deliveries.filter(d => d.attemptId === task.activeAttemptId && d.error).slice(-1),
|
|
194
|
-
attempts: current ? [{ ...current, report: current.report ? { ...current.report, summary: reportSummary, content: '', evidence: undefined } : undefined }] : [],
|
|
196
|
+
attempts: current ? [{ ...current, report: current.report ? { ...current.report, summary: reportSummary, summarySource: current.report.summary?.trim() ? 'explicit' : 'excerpt', content: '', evidence: undefined } : undefined }] : [],
|
|
195
197
|
artifacts: [plan, result, ...task.artifacts.filter(a => a.kind === 'review' && a.reviewsArtifactId === result?.id)].filter((a) => !!a).map(a => ({ ...a, content: '', summary: (a.summary || (a.kind === 'result' && collaborationResultPresentation(a.content).condensed ? collaborationResultPresentation(a.content).summary : undefined))?.slice(0, 800), evidence: undefined })),
|
|
196
198
|
decisions: task.decisions.filter(d => d.status === 'pending').map(d => ({ ...d, question: d.question.slice(0, 512), options: [] })),
|
|
197
|
-
events: task.events.filter(e => ['revise', 'request-review'].includes(e.kind) && e.attemptId === task.activeAttemptId).slice(-4).map(e => ({ ...e, content: ['user', 'integration'].includes(e.source ?? '') && e.kind === 'revise' ? e.content.slice(0, 512) : '' }))
|
|
199
|
+
events: [...task.events.filter(e => ['revise', 'request-review'].includes(e.kind) && e.attemptId === task.activeAttemptId).slice(-4).map(e => ({ ...e, content: ['user', 'integration'].includes(e.source ?? '') && e.kind === 'revise' ? e.content.slice(0, 512) : '' })),
|
|
200
|
+
...(coordination ? [{ ...coordination, content: (coordination.summary || coordination.content).slice(0, 512), summary: coordination.summary?.slice(0, 512), evidence: undefined }] : [])].sort((a, b) => a.sequence - b.sequence) };
|
|
198
201
|
}));
|
|
199
202
|
}
|
|
200
203
|
heads(groupIds, owner) { return this.document.tasks.filter(t => groupIds.includes(t.groupId) && t.ownerServiceId === owner).map(t => ({ id: t.id, revision: t.revision })); }
|
|
@@ -227,10 +230,10 @@ export class CollaborationTaskStore {
|
|
|
227
230
|
task.attempts.push({ id: attemptId, assignee: member(assignee), createdAt: Date.now(), threadId });
|
|
228
231
|
this.event(task, 'assigned', actor, content || '任务已分派');
|
|
229
232
|
doc.outbox.push({ id: id(), taskId: task.id, attemptId, target: assignee, kind: 'task', threadId,
|
|
230
|
-
content: `本次执行身份:${assignee.sessionId}。所有 td collab 命令显式带 --session ${assignee.sessionId};这是服务核对的实际身份,正文中的模板身份和 tmux 标识不能替代它。\n任务:${task.title}\n${task.spec}${task.constraints ? `\n约束:${task.constraints}` : ''}${task.acceptance ? `\n完成标准:${task.acceptance}` : ''}\n${content}\n任务 ID:${task.id}\n尝试 ID:${attemptId}\n用 td collab task get ${task.id} --text 查询完整上下文;用 td collab task report ${task.id} --attempt ${attemptId} --status ack --content '接手说明' 显式回复;遇必要问题用 task ask,提交结果用 report --status complete --summary '简短结论、关键交付和限制'。摘要先回答用户问题,不放任务 ID、版本、分支或流程日志;完整证据保留在 --content/--file
|
|
233
|
+
content: `本次执行身份:${assignee.sessionId}。所有 td collab 命令显式带 --session ${assignee.sessionId};这是服务核对的实际身份,正文中的模板身份和 tmux 标识不能替代它。\n任务:${task.title}\n${task.spec}${task.constraints ? `\n约束:${task.constraints}` : ''}${task.acceptance ? `\n完成标准:${task.acceptance}` : ''}\n${content}\n任务 ID:${task.id}\n尝试 ID:${attemptId}\n用 td collab task get ${task.id} --text 查询完整上下文;用 td collab task report ${task.id} --attempt ${attemptId} --status ack --content '接手说明' 显式回复;遇必要问题用 task ask,提交结果用 report --status complete --summary '简短结论、关键交付和限制'。摘要先回答用户问题,不放任务 ID、版本、分支或流程日志;完整证据保留在 --content/--file 正文中。明确里程碑、交付范围变化或遇到阻塞时,可用 report --status working|blocked|failed --summary '用户能理解的当前进展与下一步' --content '原始说明与证据' 更新,不以终端有输出代替报告,不重复无变化的进展。如果同一尝试已经交付或任务已归档,不要重复实施。${task.purpose === 'automation' ? '\n这是独立后台自动化执行记录:complete 是你明确提交的执行结果,无需等待用户 accepted。机械校验和外部发布由接入系统处理;纯咨询用 respond 关联原 comment,不重复提交 complete。必要问题用 ask 保留原文,由接入系统联系用户并回答。' : ''}${task.workspace ? `\n代码只能在独立目录 ${task.workspace.cwd} 修改。分支 ${task.workspace.branch}。交付前提交代码,结果说明提交、变更、验证与限制。不能修改原仓库、合并到用户分支或发布。` : ''}${task.workflow?.workType === 'read-only' ? '\n这是只读查询或分析任务:在本机会话中采集并交付报告,不修改代码或系统,不创建提交、构建、部署或终止进程。结果需说明采样时间、证据和限制。' : ''}${task.workflow?.kind === 'step' ? '\n完成报告会自动请求独立评审;评审要求修改时继续完成,重新提交 complete。代码交付前运行受影响的测试和必要构建;查询交付核对数据来源、采样时间和限制。未实际验收的路径必须明确说明。' : ''}` });
|
|
231
234
|
}
|
|
232
235
|
goalInstructions(task) {
|
|
233
|
-
return `${this.baseGoalInstructions(task)}\n启动 Agent 前,读取 task get 返回的 launchProfiles、defaultLaunchProfileId 和 roster.launchProfile。根据用户填写的 notes 判断适用任务;这些是选用建议,不是能力或性能保证。需要另一种模型或参数时,用 td collab spawn ${task.groupId} <agentSlug> --launch-profile <方案id> --cwd <项目目录> --session ${task.coordinator?.sessionId} 创建对应执行成员,再把子任务分派给它。已有成员及其代码执行会话保留创建时的启动方案,不因默认方案变更而更换模型。`;
|
|
236
|
+
return `${this.baseGoalInstructions(task)}\n${GOAL_EXPERIENCE_GUIDE}\n启动 Agent 前,读取 task get 返回的 launchProfiles、defaultLaunchProfileId 和 roster.launchProfile。根据用户填写的 notes 判断适用任务;这些是选用建议,不是能力或性能保证。需要另一种模型或参数时,用 td collab spawn ${task.groupId} <agentSlug> --launch-profile <方案id> --cwd <项目目录> --session ${task.coordinator?.sessionId} 创建对应执行成员,再把子任务分派给它。已有成员及其代码执行会话保留创建时的启动方案,不因默认方案变更而更换模型。`;
|
|
234
237
|
}
|
|
235
238
|
baseGoalInstructions(task) {
|
|
236
239
|
return `你是此目标的协调者,负责把目标推进到可验收交付,不亲自实施子任务。\n目标:${task.spec}\n约束:${task.constraints || '未补充'}\n完成标准:${task.acceptance || '满足用户目标,说明交付与限制'}\n任务 ID:${task.id}\n当前协调身份:${task.coordinator?.sessionId};所有命令显式带 --session ${task.coordinator?.sessionId},不使用 tmux 标识。\n用 td collab task get ${task.id} --json 读取 roster、子任务、完整记录和 revision。\n先报告 ack;拆分为可交付子任务,用 td collab task create --group ${task.groupId} --parent ${task.id} --title '标题' --content '完整要求' --assignee <roster里的成员sessionId> --acceptance '明确标准' --work-type read-only|code。先按目标明确分类:查询、检查、研究、分析用 read-only,复用现有执行成员会话,不创建 Git 目录;修改代码用 code,才创建独立目录。简单问题只建一个必要任务,不为了形式拆成采集、复述、汇总多份任务。子任务继承自动评审与协调者。依赖任务用 --depends-on id,id,服务在依赖评审通过后自动分派。保持分工合理,不根据终端输出推断谁有空。\n每次收到明确更新后读取最新记录,处理失败与交接。服务自动安排独立评审、返工和依赖接续;不要重复请求评审或催促正在等待回复的成员。必要的人类决策用 task ask --attempt <本轮id>;方案需要用户确认时提交 task plan,不把普通回复当授权。\n只有已交付代码任务实际包含相对 base 的提交变化时,才需创建 --work-type code --integration 的最终集成子任务,--depends-on 依赖全部代码实施任务;独立目录会包含依赖的提交。不得在原仓库自动合并或发布。\n结束本次协调用 td collab task coordinate ${task.id} --revision <最新版本> --content '已安排的工作和下一步';有新事件服务会再次唤起你。所有子任务评审通过后报告 complete --summary '直接回答用户的简短结果和限制';只读目标直接汇总已核对结果,不创建集成或重复汇总任务。正文保留证据、评审结论和限制,仅代码目标补充目录、分支和提交,等待用户最终验收。任何异常都要留下明确说明,不伪造完成或进度。`;
|
|
@@ -354,8 +357,8 @@ export class CollaborationTaskStore {
|
|
|
354
357
|
taskPurpose(input.purpose);
|
|
355
358
|
const content = text(input.content, '内容');
|
|
356
359
|
const summary = text(input.summary, '结果摘要', 2400);
|
|
357
|
-
if (summary && (input.kind !== 'report' || input.status
|
|
358
|
-
throw new CollaborationError('INVALID_SUMMARY', '
|
|
360
|
+
if (summary && input.kind !== 'coordinate' && (input.kind !== 'report' || !['working', 'blocked', 'failed', 'complete'].includes(input.status ?? '')))
|
|
361
|
+
throw new CollaborationError('INVALID_SUMMARY', '摘要只能用于进展、阻塞、失败、结果或协调说明');
|
|
359
362
|
if (input.verdict !== undefined && !['pass', 'changes', 'blocked'].includes(input.verdict))
|
|
360
363
|
throw new CollaborationError('INVALID_VERDICT', '评审结论无效');
|
|
361
364
|
if (input.evidence !== undefined && Buffer.byteLength(JSON.stringify(input.evidence)) > 16_384)
|
|
@@ -470,10 +473,12 @@ export class CollaborationTaskStore {
|
|
|
470
473
|
if (plan && task.approvedPlanArtifactId !== plan.id)
|
|
471
474
|
throw new CollaborationError('PLAN_PENDING', '方案尚未由用户确认,请先等待决定', 409);
|
|
472
475
|
}
|
|
473
|
-
attempt.report = { status: input.status, content, evidence: input.evidence, createdAt: Date.now() };
|
|
476
|
+
attempt.report = { status: input.status, content, ...(summary ? { summary } : {}), evidence: input.evidence, createdAt: Date.now() };
|
|
474
477
|
const event = this.event(task, 'report', actor, content, attempt.id);
|
|
475
478
|
event.reportStatus = input.status;
|
|
476
479
|
event.evidence = input.evidence;
|
|
480
|
+
if (summary)
|
|
481
|
+
event.summary = summary;
|
|
477
482
|
if (input.status === 'complete' && attempt.id === task.activeAttemptId && task.status === 'accepted') {
|
|
478
483
|
task.status = 'open';
|
|
479
484
|
delete task.acceptedArtifactId;
|
|
@@ -631,7 +636,9 @@ export class CollaborationTaskStore {
|
|
|
631
636
|
else if (input.kind === 'coordinate') {
|
|
632
637
|
if (task.workflow?.kind !== 'goal' || !sameMember(actor, task.coordinator) || !content)
|
|
633
638
|
throw new CollaborationError('COORDINATOR_REQUIRED', '请由目标协调者提交本次协调说明', 403);
|
|
634
|
-
this.event(task, 'coordinate', actor, content);
|
|
639
|
+
const event = this.event(task, 'coordinate', actor, content);
|
|
640
|
+
if (summary)
|
|
641
|
+
event.summary = summary;
|
|
635
642
|
task.coordination = { notifiedSequence: task.events.at(-1).sequence, acknowledgedSequence: task.events.at(-1).sequence, notifiedAt: Date.now() };
|
|
636
643
|
delete task.automationIssue;
|
|
637
644
|
}
|
|
@@ -807,7 +814,7 @@ export class CollaborationTaskStore {
|
|
|
807
814
|
else if (action === 'wake') {
|
|
808
815
|
const updates = task.events.filter(e => e.sequence > task.coordination.notifiedSequence && e.kind !== 'coordinate');
|
|
809
816
|
doc.outbox.push({ id: id(), taskId: task.id, attemptId: task.activeAttemptId, target: task.coordinator, kind: 'message', threadId: task.id,
|
|
810
|
-
content: `当前协调身份:${task.coordinator.sessionId};命令带 --session ${task.coordinator.sessionId}。\n目标「${task.title}」有新的明确事件,请继续协调:\n${updates.slice(-8).map(e => `${new Date(e.createdAt).toISOString()} ${e.content.slice(0, 1200)}`).join('\n')}\n用 td collab task get ${task.id} --json 读取完整上下文与子任务;安排必要下一步后 task coordinate ${task.id} --revision <最新版本> --content '协调说明'。自动评审和依赖已由服务接续,不要重复分派。\n当前流程指南:查询、检查、分析必须 --work-type read-only,复用 roster 现有执行成员;只有修改代码才用 code 和独立目录。只读报告由你直接汇总,不新增仅转述的汇总子任务。已评审且 HEAD 等于 base
|
|
817
|
+
content: `当前协调身份:${task.coordinator.sessionId};命令带 --session ${task.coordinator.sessionId}。\n目标「${task.title}」有新的明确事件,请继续协调:\n${updates.slice(-8).map(e => `${new Date(e.createdAt).toISOString()} ${e.content.slice(0, 1200)}`).join('\n')}\n用 td collab task get ${task.id} --json 读取完整上下文与子任务;安排必要下一步后 task coordinate ${task.id} --revision <最新版本> --content '协调说明'。自动评审和依赖已由服务接续,不要重复分派。\n当前流程指南:查询、检查、分析必须 --work-type read-only,复用 roster 现有执行成员;只有修改代码才用 code 和独立目录。只读报告由你直接汇总,不新增仅转述的汇总子任务。已评审且 HEAD 等于 base 的交付没有代码变化,不需要集成;有代码变化才安排必要集成。用户有新要求时继续本目标,交付新版本,不重做已有采样。最终汇总通过评审且无新要求时等待用户验收,不重复提交相同结果。\n${GOAL_EXPERIENCE_GUIDE}` });
|
|
811
818
|
task.coordination.notifiedSequence = task.events.at(-1).sequence;
|
|
812
819
|
task.coordination.notifiedAt = Date.now();
|
|
813
820
|
}
|
|
@@ -40,6 +40,7 @@ export function writeCollaborationTmuxPane(run, pane, prompt, stdin, assertCurre
|
|
|
40
40
|
progress?.('queue_wait');
|
|
41
41
|
return serializeTerminalInput(paneInputKey(pane), () => {
|
|
42
42
|
progress?.('queue_acquired');
|
|
43
|
+
assertCurrent?.('queue_acquired');
|
|
43
44
|
return writeTmuxPrompt(run, pane, prompt, stdin, assertCurrent, progress);
|
|
44
45
|
});
|
|
45
46
|
}
|
|
@@ -47,7 +48,7 @@ async function writeTmuxPrompt(run, pane, prompt,
|
|
|
47
48
|
/** Body travels on stdin so tmux cannot parse its semicolons/backslashes. */
|
|
48
49
|
stdin, assertCurrent, progress) {
|
|
49
50
|
await assertSamePane(run, pane);
|
|
50
|
-
assertCurrent?.();
|
|
51
|
+
assertCurrent?.('before_paste');
|
|
51
52
|
// A fixed pane target is independent of the current window, keyboard focus
|
|
52
53
|
// and browser presence. Delivery goes through a named tmux buffer rather
|
|
53
54
|
// than `send-keys -l`: while a pane is in copy-mode, literal bytes are
|
|
@@ -81,7 +82,7 @@ stdin, assertCurrent, progress) {
|
|
|
81
82
|
progress?.('paste_written');
|
|
82
83
|
await waitForPromptSubmit();
|
|
83
84
|
await assertSamePane(run, pane);
|
|
84
|
-
assertCurrent?.();
|
|
85
|
+
assertCurrent?.('before_submit');
|
|
85
86
|
progress?.('submit_attempted');
|
|
86
87
|
await run([
|
|
87
88
|
// The submit key rides outside the paste block: inside it, an editor
|
|
@@ -61,6 +61,12 @@ export const INTEGRATION_HELP = `td integration — local scoped integration adm
|
|
|
61
61
|
diagnostics <TD-session-id> (read stored launch/restore diagnostics; administrator only)
|
|
62
62
|
1.4.314 adds phase/timestamps, paste/submit write facts and target-change
|
|
63
63
|
evidence; no argv/environment/credentials or application readiness claim.
|
|
64
|
+
1.4.322 adds guard_captured/runtime_resolving/runtime_resolved stages and
|
|
65
|
+
target_change.check_phase/guard_captured_at/checked_at, launch IDs and route revisions.
|
|
66
|
+
Check actual server agent_launch_generation_consistency=true (minimum 1.4.322),
|
|
67
|
+
terminal_input_check_diagnostics=true; upgrading only the CLI does not fix a running service.
|
|
68
|
+
TERMINAL_INPUT_TARGET_CHANGED still rejects an actually replaced target.
|
|
69
|
+
create never auto-retries; retry-cold remains a separate, explicitly authorized operation.
|
|
64
70
|
Prior versions cannot reconstruct missing launch evidence retroactively.
|
|
65
71
|
create --file <policy.json> --credential-file <private-output.json>
|
|
66
72
|
update --file <policy.json> (same identity/group; preserves the credential)
|
|
@@ -246,6 +246,8 @@ export class IntegrationRuntime {
|
|
|
246
246
|
session_startup_input_clear: true, session_startup_input_clear_min_version: '1.4.310',
|
|
247
247
|
agent_launch_process_check: true, agent_launch_process_check_min_version: '1.4.312',
|
|
248
248
|
terminal_input_runtime_fence: true, terminal_input_runtime_fence_min_version: '1.4.313',
|
|
249
|
+
agent_launch_generation_consistency: true, agent_launch_generation_consistency_min_version: '1.4.322',
|
|
250
|
+
terminal_input_check_diagnostics: true,
|
|
249
251
|
session_launch_diagnostics: true, session_launch_diagnostics_min_version: '1.4.314',
|
|
250
252
|
session_cold_retry: true, session_cold_retry_min_version: '1.4.314',
|
|
251
253
|
session_rename: true, session_rename_min_version: '1.4.315',
|
|
@@ -22,12 +22,12 @@ export function writeBracketedPrompt(target, prompt, assertCurrent, progress) {
|
|
|
22
22
|
progress?.('queue_wait');
|
|
23
23
|
return serializeTerminalInput(target, async () => {
|
|
24
24
|
progress?.('queue_acquired');
|
|
25
|
-
assertCurrent?.();
|
|
25
|
+
assertCurrent?.('queue_acquired');
|
|
26
26
|
progress?.('paste_attempted');
|
|
27
27
|
target.write(buildBracketedPasteBytes(prompt));
|
|
28
28
|
progress?.('paste_written');
|
|
29
29
|
await waitForPromptSubmit();
|
|
30
|
-
assertCurrent?.();
|
|
30
|
+
assertCurrent?.('before_submit');
|
|
31
31
|
progress?.('submit_attempted');
|
|
32
32
|
target.write('\r');
|
|
33
33
|
progress?.('submit_written');
|
|
@@ -39,7 +39,7 @@ export function resolveCollaborationBackend(record, records, backends, routing)
|
|
|
39
39
|
return null;
|
|
40
40
|
if (records.some((other) => other.sessionId !== record.sessionId && other.backendSessionId === id))
|
|
41
41
|
return null;
|
|
42
|
-
routing.bind({ sessionId: record.sessionId, backendSessionId: id, mode: backend.mode,
|
|
42
|
+
routing.bind({ ...binding, sessionId: record.sessionId, backendSessionId: id, mode: backend.mode,
|
|
43
43
|
tmuxSessionName: backend.tmuxSessionName,
|
|
44
44
|
agentSlug: binding?.agentSlug ?? backend.agent?.slug ?? record.agentResume?.slug ?? null,
|
|
45
45
|
nativeSessionId: binding?.nativeSessionId ?? backend.agentSession?.sessionId ?? record.agentResume?.sessionId ?? null,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TerminalInputTargetChangedError } from './terminalInput.js';
|
|
2
|
+
/** Display/identity metadata may have crossed an await with an old snapshot.
|
|
3
|
+
* Only the launch lifecycle can change these server-owned control fields. */
|
|
4
|
+
export function mergeSessionLaunchState(candidate, current, change) {
|
|
5
|
+
if (!change)
|
|
6
|
+
return current ? { ...candidate,
|
|
7
|
+
agentLaunchGeneration: current.agentLaunchGeneration ?? null,
|
|
8
|
+
agentLaunchCheck: current.agentLaunchCheck ?? null,
|
|
9
|
+
} : candidate;
|
|
10
|
+
if (!current || (current.agentLaunchGeneration ?? null) !== change.expectedGeneration
|
|
11
|
+
|| (current.agentLaunchCheck?.id ?? null) !== change.expectedCheckId) {
|
|
12
|
+
throw new TerminalInputTargetChangedError({
|
|
13
|
+
expected_backend_session_id: candidate.backendSessionId, current_backend_session_id: current?.backendSessionId ?? null,
|
|
14
|
+
expected_launch_id: change.expectedGeneration, current_launch_id: current?.agentLaunchGeneration ?? null,
|
|
15
|
+
backend_instance_matches: !!current && candidate.backendSessionId === current.backendSessionId,
|
|
16
|
+
check_phase: 'launch_state_commit', checked_at: Date.now(),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return { ...candidate, agentLaunchGeneration: change.generation, agentLaunchCheck: change.check };
|
|
20
|
+
}
|
|
@@ -22,6 +22,23 @@ export class TerminalInputTargetChangedError extends Error {
|
|
|
22
22
|
this.evidence = evidence;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
/** Capture once, including for a launch's own command. Never adopt a newer
|
|
26
|
+
* generation simply because the physical backend has stayed the same. */
|
|
27
|
+
export function captureRuntimeInputGuard(current, expected = current()) {
|
|
28
|
+
const capturedAt = Date.now();
|
|
29
|
+
return (phase = 'guard_capture') => {
|
|
30
|
+
const actual = current();
|
|
31
|
+
const matches = actual.backendInstance === expected.backendInstance;
|
|
32
|
+
if (actual.backendSessionId !== expected.backendSessionId || !matches
|
|
33
|
+
|| actual.launchId !== expected.launchId || actual.routeRevision !== expected.routeRevision) {
|
|
34
|
+
throw new TerminalInputTargetChangedError({ expected_backend_session_id: expected.backendSessionId,
|
|
35
|
+
current_backend_session_id: actual.backendSessionId, expected_launch_id: expected.launchId,
|
|
36
|
+
current_launch_id: actual.launchId, backend_instance_matches: matches, check_phase: phase,
|
|
37
|
+
guard_captured_at: capturedAt, checked_at: Date.now(), expected_route_revision: expected.routeRevision,
|
|
38
|
+
current_route_revision: actual.routeRevision });
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
25
42
|
/** Clearing a one-time launch check does not change the runtime generation. */
|
|
26
43
|
export function captureTerminalInputGuard(current, expected = current()) {
|
|
27
44
|
return () => {
|