termdock 1.4.321 → 1.4.324
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-7IUcmCLC.js +186 -0
- package/dist/client/assets/App-7IUcmCLC.js.br +0 -0
- package/dist/client/assets/App-7IUcmCLC.js.gz +0 -0
- package/dist/client/assets/{ArchitecturePanel-BIlIOGx7.js → ArchitecturePanel-CUAB0wFe.js} +6 -6
- package/dist/client/assets/ArchitecturePanel-CUAB0wFe.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-CUAB0wFe.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-BtXqyUzD.js → ChangeWalkthroughPanel-CKIG8diY.js} +2 -2
- package/dist/client/assets/ChangeWalkthroughPanel-CKIG8diY.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-CKIG8diY.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-CIq-JAbF.js +1 -0
- package/dist/client/assets/CollaborationMainWorkspace-CIq-JAbF.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-CIq-JAbF.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-7vWDzH-d.js +2 -0
- package/dist/client/assets/{ComputerControlView-D81udDZO.js → ComputerControlView-CPSI-M86.js} +2 -2
- package/dist/client/assets/ComputerControlView-CPSI-M86.js.br +0 -0
- package/dist/client/assets/ComputerControlView-CPSI-M86.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-B3hTlIFu.js → DagPlayground-BxocNRPm.js} +1 -1
- package/dist/client/assets/DagPlayground-BxocNRPm.js.br +0 -0
- package/dist/client/assets/DagPlayground-BxocNRPm.js.gz +0 -0
- package/dist/client/assets/{DiffLab-C5sDPAZ5.js → DiffLab-COGOFO0s.js} +2 -2
- package/dist/client/assets/DiffLab-COGOFO0s.js.br +0 -0
- package/dist/client/assets/DiffLab-COGOFO0s.js.gz +0 -0
- package/dist/client/assets/{DiffReview-DQFgOJPF.js → DiffReview-5ERdwz1C.js} +1 -1
- package/dist/client/assets/DiffReview-5ERdwz1C.js.br +0 -0
- package/dist/client/assets/DiffReview-5ERdwz1C.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-CZvBmujD.js → DiffReviewLab-BSz9IND6.js} +1 -1
- package/dist/client/assets/DiffReviewLab-BSz9IND6.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-BSz9IND6.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-DOvGC9bh.js → DiffViewer-RT-p-ZBo.js} +8 -8
- package/dist/client/assets/DiffViewer-RT-p-ZBo.js.br +0 -0
- package/dist/client/assets/DiffViewer-RT-p-ZBo.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-ClKH4BQ7.js → ModelPreview-DI9anVWA.js} +1 -1
- package/dist/client/assets/ModelPreview-DI9anVWA.js.br +0 -0
- package/dist/client/assets/ModelPreview-DI9anVWA.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-BeegDfBO.js → RightSidebar-DOLn8R7c.js} +36 -36
- package/dist/client/assets/RightSidebar-DOLn8R7c.js.br +0 -0
- package/dist/client/assets/RightSidebar-DOLn8R7c.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-CHUZIHQo.js → abnfDiagram-VCTEODGH-CXd0unH5.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-CXd0unH5.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-CXd0unH5.js.gz +0 -0
- package/dist/client/assets/app-DCFOZi_L.js +35 -0
- package/dist/client/assets/app-DCFOZi_L.js.br +0 -0
- package/dist/client/assets/app-DCFOZi_L.js.gz +0 -0
- package/dist/client/assets/{arc-CIJEXYV7.js → arc-DCqJmX8M.js} +1 -1
- package/dist/client/assets/arc-DCqJmX8M.js.br +0 -0
- package/dist/client/assets/arc-DCqJmX8M.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-CcX1UBXG.js → architectureDiagram-5GKGNRK7-DGu_m54H.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DGu_m54H.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DGu_m54H.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-gDLrIBDk.js → blockDiagram-I7D4REHJ-BI0gsxDN.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-BI0gsxDN.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-BI0gsxDN.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-BQA7WLEL.js → c4Diagram-7LVT6UL2-Ct3xzGtD.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-Ct3xzGtD.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-Ct3xzGtD.js.gz +0 -0
- package/dist/client/assets/channel-BLSCUksA.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-CPCY618J.js → chunk-2Q5K7J3B-BPd2UShA.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-Cc3Czx6A.js → chunk-5VM5RSS4-CoFZ5Fo3.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-3scxqZTK.js → chunk-F27PBJKO-C5gZrGp4.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-C5gZrGp4.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-C5gZrGp4.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-BOCOE1VY.js → chunk-IMKFNOWR-GW8b9ya-.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-GW8b9ya-.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-GW8b9ya-.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-DX2Onu68.js → chunk-JWPE2WC7-GpMoViQf.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-C4MN3QRd.js → chunk-POPQ4Y6H-C_vgVPaw.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-DOKo3BNt.js → chunk-SVP7TREG-bA7RXwWn.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-bA7RXwWn.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-bA7RXwWn.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-CPpFFmO9.js → chunk-TICWLB2K-BG8DAtll.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-BG8DAtll.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-BG8DAtll.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-Zp_XOFU2.js → chunk-XXDRQBXY-Ces56sud.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-DkVIqOvw.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-DkVIqOvw.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-iYXdWZMG.js → cose-bilkent-JH36ORCC-Bwch0qL5.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-Bwch0qL5.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-Bwch0qL5.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-CXRpxmcA.js → cynefin-OW5HDTMX-CrAXyA2Z.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-CrAXyA2Z.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-CrAXyA2Z.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CH1TQhgO.js → cynefinDiagram-5FMLGOSQ-YlP0Q93l.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-YlP0Q93l.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-YlP0Q93l.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-BdshuKJr.js → dagre-GXQ25YYZ-CZ4XcPK9.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-CZ4XcPK9.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CZ4XcPK9.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-VbNBimIR.js → diagram-S7CK7UJ4-c_8HfHGA.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-c_8HfHGA.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-c_8HfHGA.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-D_NUFcq3.js → diagram-UQ7AKVKN-BGtRfxMR.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-BGtRfxMR.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-BGtRfxMR.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-CfYRQ4mq.js → diagram-VSXAHHWV-_9yZnhuv.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-_9yZnhuv.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-_9yZnhuv.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-YHy6vMjY.js → diagram-VX7I27RA-C_mnc4_u.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-C_mnc4_u.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-C_mnc4_u.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-DvHqYL0O.js → diagram-Z3DM3KII-sZ_AiSpj.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-sZ_AiSpj.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-sZ_AiSpj.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-Bl9bDxAP.js → ebnfDiagram-PWID7BFC-Dm-BXeqS.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Dm-BXeqS.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Dm-BXeqS.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-DauNoBZZ.js → erDiagram-RLTQ6QDP-Dz4cBepd.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-Dz4cBepd.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-Dz4cBepd.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-D6eDWfJY.js → flowDiagram-HODETNUW-CbRG8-WW.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-CbRG8-WW.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CbRG8-WW.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-CWHSwTR6.js → ganttDiagram-EL5Y4UJY-CmBXWlr0.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CmBXWlr0.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CmBXWlr0.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-nU4jhK3S.js → gestureArbiter-B26W6rS7.js} +1 -1
- package/dist/client/assets/gestureArbiter-B26W6rS7.js.br +0 -0
- package/dist/client/assets/gestureArbiter-B26W6rS7.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-BHYt5-_X.js → gitGraphDiagram-WWUBYQGX-JW5QMYEk.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-JW5QMYEk.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-JW5QMYEk.js.gz +0 -0
- package/dist/client/assets/index-Ctz-IDjR.css +1 -0
- package/dist/client/assets/index-Ctz-IDjR.css.br +0 -0
- package/dist/client/assets/{index-B4bEMUyn.css.gz → index-Ctz-IDjR.css.gz} +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-DPmlcUaZ.js → infoDiagram-27XIBGKW-CsA6WdPn.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-DAn65XKZ.js → ishikawaDiagram-5VMMS53U-CsKPUwTw.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-DAn65XKZ.js.br → ishikawaDiagram-5VMMS53U-CsKPUwTw.js.br} +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CsKPUwTw.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-B2c5x9jb.js → journeyDiagram-3NMN7TZE-DpN98gN0.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DpN98gN0.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DpN98gN0.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-CMeEp_9r.js → kanban-definition-UXKFOSKX-RHO--43O.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-RHO--43O.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-RHO--43O.js.gz +0 -0
- package/dist/client/assets/{layout-Db99ysGT.js → layout-Cm_prknW.js} +1 -1
- package/dist/client/assets/layout-Cm_prknW.js.br +0 -0
- package/dist/client/assets/layout-Cm_prknW.js.gz +0 -0
- package/dist/client/assets/{linear-B6mREmTG.js → linear-BVAsPkvS.js} +1 -1
- package/dist/client/assets/linear-BVAsPkvS.js.br +0 -0
- package/dist/client/assets/linear-BVAsPkvS.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-DndzUmju.js → mermaid.core-ufe77Xaz.js} +5 -5
- package/dist/client/assets/mermaid.core-ufe77Xaz.js.br +0 -0
- package/dist/client/assets/mermaid.core-ufe77Xaz.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-qYAlDvc4.js → mindmap-definition-YA3MSWOX-CRyy1U2d.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-CRyy1U2d.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-CRyy1U2d.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-3_SIzSH7.js +2 -0
- package/dist/client/assets/passwordBootstrap-3_SIzSH7.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-3_SIzSH7.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-Dg5DCFIn.js → pegDiagram-XKGWAZYB-DSHgdU9q.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-DSHgdU9q.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-DSHgdU9q.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-dje1AAFI.js → pieDiagram-E7YTZNPT-lIUeAuhN.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-lIUeAuhN.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-lIUeAuhN.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-DLXI6hrS.js → quadrantDiagram-AXDQQJYC-CIgG9vBX.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CIgG9vBX.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-CIgG9vBX.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-DcY-P8Q_.js → railroadDiagram-O6MQD6OU-DjP8oesA.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DjP8oesA.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DjP8oesA.js.gz +0 -0
- package/dist/client/assets/{rdpSession-JkZuPKb3.js → rdpSession-BshIobdj.js} +1 -1
- package/dist/client/assets/rdpSession-BshIobdj.js.br +0 -0
- package/dist/client/assets/rdpSession-BshIobdj.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-CR3uo3V0.js → referenceLongPress-DBJnfFHa.js} +1 -1
- package/dist/client/assets/referenceLongPress-DBJnfFHa.js.br +0 -0
- package/dist/client/assets/referenceLongPress-DBJnfFHa.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-B-GLzS7h.js → requirementDiagram-BXWQKSXE-Dbvu6IC_.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Dbvu6IC_.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-Dbvu6IC_.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-CINtGjgu.js → sankeyDiagram-P5KCCOFB-1mZ4s-lv.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-1mZ4s-lv.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-1mZ4s-lv.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-BRE-_raI.js → sequenceDiagram-WJ2MYXX4-Cu3hhzlV.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Cu3hhzlV.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Cu3hhzlV.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-v2bGYNk3.js → sizeCapture-INFHLROL-xfm69HlR.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-xfm69HlR.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-xfm69HlR.js.gz +0 -0
- package/dist/client/assets/{sparkles-Dx518Xui.js → sparkles-CDonlwGu.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-CIQ1zGkb.js → stateDiagram-D77RDMKH-u-bh6mDK.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-u-bh6mDK.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-u-bh6mDK.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BQ_m8Gzd.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-DEjGaJr6.js → swimlanes-42K2YHIH-U8WN__SO.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-U8WN__SO.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-U8WN__SO.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-FDEo3QWw.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-BPbZrudq.js → timeline-definition-24CTP7MA-CMsoNo4F.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-CMsoNo4F.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-CMsoNo4F.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-CVm2qdGE.js → triangle-alert-BgErMO2V.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-CAsKNSfN.js → vennDiagram-4TSXK5OY-CPE6pVwh.js} +1 -1
- package/dist/client/assets/vennDiagram-4TSXK5OY-CPE6pVwh.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CPE6pVwh.js.gz +0 -0
- package/dist/client/assets/{videoCompression-CCOgxfhm.js → videoCompression-BWkZvEjM.js} +1 -1
- package/dist/client/assets/videoCompression-BWkZvEjM.js.br +0 -0
- package/dist/client/assets/videoCompression-BWkZvEjM.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-EeabO9yU.js → wardleyDiagram-VM6X3IG4-4lWd-R4N.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-4lWd-R4N.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-4lWd-R4N.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-MSUoQl2z.js → xychartDiagram-S5SC5T6Z-CpKJMCWV.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-CpKJMCWV.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-CpKJMCWV.js.gz +0 -0
- package/dist/client/index.html +2 -2
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/sw-encrypted-background.js +1 -1
- package/dist/client/sw-encrypted-background.js.br +0 -0
- package/dist/client/sw-encrypted-background.js.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 +5 -1
- package/dist/server/agent/collaborationGroupRoutes.js +15 -0
- package/dist/server/agent/collaborationRoutes.js +2 -0
- package/dist/server/agent/collaborationStore.js +63 -2
- package/dist/server/agent/collaborationTaskCli.js +1 -1
- package/dist/server/agent/collaborationTaskGuidance.js +2 -0
- package/dist/server/agent/collaborationTaskRoutes.js +5 -1
- package/dist/server/agent/collaborationTaskStore.js +18 -11
- package/dist/server/agent/collaborationTmuxDelivery.js +3 -2
- package/dist/server/agent/integrationCli.js +44 -20
- package/dist/server/agent/integrationServer.js +20 -1
- package/dist/server/agent/promptDelivery.js +2 -2
- package/dist/server/agent/sessionLaunchState.js +20 -0
- package/dist/server/agent/terminalInput.js +17 -0
- package/dist/server/federation/packets.js +179 -28
- package/dist/server/federation/requestContext.js +6 -1
- package/dist/server/federation/runtime.js +19 -8
- package/dist/server/routes/terminal.js +108 -57
- package/dist/server/utils/autoUpdate.js +55 -8
- package/dist/server/utils/npmUpdate.js +84 -8
- package/dist/server/utils/terminalPasteBuffer.js +66 -0
- package/dist/server/utils/tmuxClientCapabilities.js +4 -0
- package/dist/server/utils/tmuxCopySelection.js +94 -0
- package/dist/server/utils/tmuxEmptyServerProbe.js +15 -0
- package/docs/integrations.md +85 -0
- package/package.json +5 -2
- package/runtime-manifest.json +3 -3
- package/.desktop-dist/main.js +0 -1989
- package/dist/client/assets/App-VAvoVlm2.js +0 -186
- package/dist/client/assets/App-VAvoVlm2.js.br +0 -0
- package/dist/client/assets/App-VAvoVlm2.js.gz +0 -0
- package/dist/client/assets/ArchitecturePanel-BIlIOGx7.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-BIlIOGx7.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-BtXqyUzD.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-BtXqyUzD.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-DUw3cqW-.js +0 -1
- package/dist/client/assets/CollaborationMainWorkspace-DUw3cqW-.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-DUw3cqW-.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-C2sQQp6K.js +0 -2
- package/dist/client/assets/ComputerControlView-D81udDZO.js.br +0 -0
- package/dist/client/assets/ComputerControlView-D81udDZO.js.gz +0 -0
- package/dist/client/assets/DagPlayground-B3hTlIFu.js.br +0 -0
- package/dist/client/assets/DagPlayground-B3hTlIFu.js.gz +0 -0
- package/dist/client/assets/DiffLab-C5sDPAZ5.js.br +0 -0
- package/dist/client/assets/DiffLab-C5sDPAZ5.js.gz +0 -0
- package/dist/client/assets/DiffReview-DQFgOJPF.js.br +0 -0
- package/dist/client/assets/DiffReview-DQFgOJPF.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CZvBmujD.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CZvBmujD.js.gz +0 -0
- package/dist/client/assets/DiffViewer-DOvGC9bh.js.br +0 -0
- package/dist/client/assets/DiffViewer-DOvGC9bh.js.gz +0 -0
- package/dist/client/assets/ModelPreview-ClKH4BQ7.js.br +0 -0
- package/dist/client/assets/ModelPreview-ClKH4BQ7.js.gz +0 -0
- package/dist/client/assets/RightSidebar-BeegDfBO.js.br +0 -0
- package/dist/client/assets/RightSidebar-BeegDfBO.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-CHUZIHQo.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-CHUZIHQo.js.gz +0 -0
- package/dist/client/assets/app-Bj0N393t.js +0 -35
- package/dist/client/assets/app-Bj0N393t.js.br +0 -0
- package/dist/client/assets/app-Bj0N393t.js.gz +0 -0
- package/dist/client/assets/arc-CIJEXYV7.js.br +0 -0
- package/dist/client/assets/arc-CIJEXYV7.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-CcX1UBXG.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-CcX1UBXG.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-gDLrIBDk.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-gDLrIBDk.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-BQA7WLEL.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-BQA7WLEL.js.gz +0 -0
- package/dist/client/assets/channel-OHMJip5O.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-3scxqZTK.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-3scxqZTK.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BOCOE1VY.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BOCOE1VY.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-DOKo3BNt.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-DOKo3BNt.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CPpFFmO9.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CPpFFmO9.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-DwA5mGyC.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-DwA5mGyC.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-iYXdWZMG.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-iYXdWZMG.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-CXRpxmcA.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-CXRpxmcA.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CH1TQhgO.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CH1TQhgO.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-BdshuKJr.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-BdshuKJr.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-VbNBimIR.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-VbNBimIR.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-D_NUFcq3.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-D_NUFcq3.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CfYRQ4mq.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CfYRQ4mq.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-YHy6vMjY.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-YHy6vMjY.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-DvHqYL0O.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-DvHqYL0O.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bl9bDxAP.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bl9bDxAP.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DauNoBZZ.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DauNoBZZ.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-D6eDWfJY.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-D6eDWfJY.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CWHSwTR6.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CWHSwTR6.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-nU4jhK3S.js.br +0 -0
- package/dist/client/assets/gestureArbiter-nU4jhK3S.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BHYt5-_X.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BHYt5-_X.js.gz +0 -0
- package/dist/client/assets/index-B4bEMUyn.css +0 -1
- package/dist/client/assets/index-B4bEMUyn.css.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DAn65XKZ.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B2c5x9jb.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B2c5x9jb.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CMeEp_9r.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CMeEp_9r.js.gz +0 -0
- package/dist/client/assets/layout-Db99ysGT.js.br +0 -0
- package/dist/client/assets/layout-Db99ysGT.js.gz +0 -0
- package/dist/client/assets/linear-B6mREmTG.js.br +0 -0
- package/dist/client/assets/linear-B6mREmTG.js.gz +0 -0
- package/dist/client/assets/mermaid.core-DndzUmju.js.br +0 -0
- package/dist/client/assets/mermaid.core-DndzUmju.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-qYAlDvc4.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-qYAlDvc4.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-DaJXVcdB.js +0 -2
- package/dist/client/assets/passwordBootstrap-DaJXVcdB.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-DaJXVcdB.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-Dg5DCFIn.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-Dg5DCFIn.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-dje1AAFI.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-dje1AAFI.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DLXI6hrS.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DLXI6hrS.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DcY-P8Q_.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DcY-P8Q_.js.gz +0 -0
- package/dist/client/assets/rdpSession-JkZuPKb3.js.br +0 -0
- package/dist/client/assets/rdpSession-JkZuPKb3.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-CR3uo3V0.js.br +0 -0
- package/dist/client/assets/referenceLongPress-CR3uo3V0.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-B-GLzS7h.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-B-GLzS7h.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CINtGjgu.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CINtGjgu.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BRE-_raI.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BRE-_raI.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-v2bGYNk3.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-v2bGYNk3.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-CIQ1zGkb.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-CIQ1zGkb.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DCGuhzdh.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-DEjGaJr6.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-DEjGaJr6.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-Bj14fTzZ.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-BPbZrudq.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-BPbZrudq.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CAsKNSfN.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CAsKNSfN.js.gz +0 -0
- package/dist/client/assets/videoCompression-CCOgxfhm.js.br +0 -0
- package/dist/client/assets/videoCompression-CCOgxfhm.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-EeabO9yU.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-EeabO9yU.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-MSUoQl2z.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-MSUoQl2z.js.gz +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { copyTmuxSelection } from '../utils/tmuxCopySelection.js';
|
|
2
|
+
import { isConfirmedEmptyTmuxServer } from '../utils/tmuxEmptyServerProbe.js';
|
|
1
3
|
import { collaborationSessionDisplayName } from '../utils/sessionDisplayName.js';
|
|
2
4
|
import { integrationError } from '../agent/integrationStore.js';
|
|
3
5
|
import { assertNativeResumeAvailable, collectNativeResumeOwnerCandidates } from '../agent/nativeResumeOwner.js';
|
|
@@ -14,6 +16,7 @@ import { ensureNodePty } from '../utils/ensureNodePty.js';
|
|
|
14
16
|
import { PtySpawnBackoff, PtySpawnDeferredError } from '../utils/ptySpawnBackoff.js';
|
|
15
17
|
import { collaborationGroupRoutes } from '../agent/collaborationGroupRoutes.js';
|
|
16
18
|
import { TerminalClientAttachment } from '../utils/terminalClientAttachment.js';
|
|
19
|
+
import { TerminalPasteBuffer } from '../utils/terminalPasteBuffer.js';
|
|
17
20
|
import { SharedSessionSampler, SharedSnapshotCache } from '../utils/sharedSampling.js';
|
|
18
21
|
import { batchTmuxOptions, TmuxMetadataWriter } from '../utils/tmuxMetadataWriter.js';
|
|
19
22
|
import { redrawTmuxClient } from '../utils/tmuxClientRedraw.js';
|
|
@@ -51,7 +54,8 @@ import { archiveTaskWorkspace, restoreTaskWorkspace, snapshotTaskWorkspace } fro
|
|
|
51
54
|
import { isTmuxRecoveryCandidate } from '../utils/tmuxRecoveryCandidate.js';
|
|
52
55
|
import { AutomationStore, normalizeAutomationSchedule } from '../agent/automationStore.js';
|
|
53
56
|
import { writeBracketedPrompt, canDeliverPromptToAgent } from '../agent/promptDelivery.js';
|
|
54
|
-
import { captureTerminalInputGuard,
|
|
57
|
+
import { captureTerminalInputGuard, captureRuntimeInputGuard, waitAndWriteTerminalInput } from '../agent/terminalInput.js';
|
|
58
|
+
import { mergeSessionLaunchState } from '../agent/sessionLaunchState.js';
|
|
55
59
|
import { agentLaunchBlockReason, normalizeAgentLaunchCheck } from '../agent/agentLaunchCheck.js';
|
|
56
60
|
import { prepareSupervisionEnable } from '../utils/enableSupervision.js';
|
|
57
61
|
import { buildServerHealthState, dismissServerHealth } from '../utils/serverHealth.js';
|
|
@@ -1082,8 +1086,9 @@ async function withInventoryOpenLock(key, task) {
|
|
|
1082
1086
|
inventoryOpenLocks.set(key, pending);
|
|
1083
1087
|
return pending;
|
|
1084
1088
|
}
|
|
1085
|
-
function upsertGlobalSessionRecord(record) {
|
|
1086
|
-
const
|
|
1089
|
+
function upsertGlobalSessionRecord(record, launchChange) {
|
|
1090
|
+
const current = globalSessionState.sessions.find(candidate => candidate.sessionId === record.sessionId);
|
|
1091
|
+
const normalized = normalizePersistedClientSession(mergeSessionLaunchState(record, current, launchChange));
|
|
1087
1092
|
if (!normalized) {
|
|
1088
1093
|
throw new Error('invalid session record');
|
|
1089
1094
|
}
|
|
@@ -1462,8 +1467,16 @@ async function beginAgentLaunchCheck(frontendSessionId, agentSlug, nativeSession
|
|
|
1462
1467
|
if (!record)
|
|
1463
1468
|
throw new Error('SESSION_REMOVED');
|
|
1464
1469
|
const id = randomUUID();
|
|
1465
|
-
upsertGlobalSessionRecord(
|
|
1466
|
-
|
|
1470
|
+
const updated = upsertGlobalSessionRecord(record, { expectedGeneration: record.agentLaunchGeneration ?? null,
|
|
1471
|
+
expectedCheckId: record.agentLaunchCheck?.id ?? null, generation: id,
|
|
1472
|
+
check: { id, agentSlug, nativeSessionId, deadline: Date.now() + 120_000 } });
|
|
1473
|
+
// Capture the guard before persistence yields. The launch command must use
|
|
1474
|
+
// this exact generation, even if another launch occurs during an await.
|
|
1475
|
+
const assertCurrent = terminalInputGuard(updated);
|
|
1476
|
+
assertCurrent('guard_capture');
|
|
1477
|
+
await persistGlobalStateNow(true);
|
|
1478
|
+
assertCurrent('launch_persisted');
|
|
1479
|
+
return assertCurrent;
|
|
1467
1480
|
}
|
|
1468
1481
|
async function observeAgentLaunchCheck(record, observed) {
|
|
1469
1482
|
const check = record.agentLaunchCheck;
|
|
@@ -1477,53 +1490,56 @@ async function observeAgentLaunchCheck(record, observed) {
|
|
|
1477
1490
|
return { state: 'offline', reason: 'SESSION_REMOVED' };
|
|
1478
1491
|
if (latest.agentLaunchCheck?.id !== check.id)
|
|
1479
1492
|
return { state: 'recovering', reason: 'AGENT_LAUNCH_CHANGED' };
|
|
1480
|
-
upsertGlobalSessionRecord(
|
|
1493
|
+
upsertGlobalSessionRecord(latest, { expectedGeneration: latest.agentLaunchGeneration ?? null,
|
|
1494
|
+
expectedCheckId: check.id, generation: latest.agentLaunchGeneration ?? null, check: null });
|
|
1481
1495
|
await persistGlobalStateNow();
|
|
1482
1496
|
return null;
|
|
1483
1497
|
}
|
|
1484
1498
|
function terminalInputGuard(record) {
|
|
1485
1499
|
const frontendSessionId = record.sessionId;
|
|
1486
1500
|
const backendSessionId = record.backendSessionId;
|
|
1487
|
-
const
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
return () => {
|
|
1501
|
+
const expected = { backendSessionId, launchId: record.agentLaunchGeneration ?? null,
|
|
1502
|
+
routeRevision: collaborationRouting.get(frontendSessionId)?.routeRevision ?? null,
|
|
1503
|
+
backendInstance: backendSessionId ? terminalSessions.get(backendSessionId) : undefined };
|
|
1504
|
+
return captureRuntimeInputGuard(() => {
|
|
1491
1505
|
const latest = globalSessionState.sessions.find(candidate => candidate.sessionId === frontendSessionId);
|
|
1492
1506
|
if (!latest)
|
|
1493
1507
|
throw new Error('SESSION_REMOVED');
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
expected_launch_id: launchId, current_launch_id: latest.agentLaunchGeneration ?? null, backend_instance_matches: instanceMatches });
|
|
1499
|
-
}
|
|
1500
|
-
};
|
|
1508
|
+
return { backendSessionId: latest.backendSessionId, launchId: latest.agentLaunchGeneration ?? null,
|
|
1509
|
+
routeRevision: collaborationRouting.get(frontendSessionId)?.routeRevision ?? null,
|
|
1510
|
+
backendInstance: latest.backendSessionId ? terminalSessions.get(latest.backendSessionId) : undefined };
|
|
1511
|
+
}, expected);
|
|
1501
1512
|
}
|
|
1502
1513
|
/** tmux input always uses the pane queue, including automation and launch commands. */
|
|
1503
1514
|
async function automaticTerminalInput(record, assertCurrent = terminalInputGuard(record), progress) {
|
|
1504
|
-
|
|
1515
|
+
progress?.('guard_captured');
|
|
1516
|
+
assertCurrent('runtime_resolve');
|
|
1517
|
+
progress?.('runtime_resolving');
|
|
1505
1518
|
if (record.mode === 'tmux') {
|
|
1506
1519
|
const binding = collaborationRouting.get(record.sessionId) ?? {
|
|
1507
1520
|
sessionId: record.sessionId, backendSessionId: record.backendSessionId, mode: record.mode,
|
|
1508
1521
|
tmuxSessionName: record.tmuxSessionName, agentSlug: null, nativeSessionId: null, pane: null,
|
|
1509
1522
|
};
|
|
1510
1523
|
const inspected = await inspectCollaborationTmux(binding, null, true);
|
|
1511
|
-
assertCurrent();
|
|
1524
|
+
assertCurrent('runtime_resolved');
|
|
1512
1525
|
if (inspected.state !== 'ready' || !inspected.pane)
|
|
1513
1526
|
throw new Error(inspected.reason ?? 'TMUX_PANE_UNAVAILABLE');
|
|
1514
1527
|
const pane = inspected.pane;
|
|
1528
|
+
progress?.('runtime_resolved');
|
|
1515
1529
|
return (prompt) => writeCollaborationTmuxPane(runTmux, pane, prompt, runTmuxStdin, assertCurrent, progress);
|
|
1516
1530
|
}
|
|
1517
1531
|
const backend = record.backendSessionId ? terminalSessions.get(record.backendSessionId) : null;
|
|
1518
1532
|
if (!backend)
|
|
1519
1533
|
throw new Error('SHELL_BACKEND_NOT_RUNNING');
|
|
1534
|
+
assertCurrent('runtime_resolved');
|
|
1535
|
+
progress?.('runtime_resolved');
|
|
1520
1536
|
return (prompt) => writeBracketedPrompt(backend.ptyProcess, prompt, assertCurrent, progress);
|
|
1521
1537
|
}
|
|
1522
|
-
async function writeAutomaticTerminalPrompt(frontendSessionId, prompt, progress) {
|
|
1538
|
+
async function writeAutomaticTerminalPrompt(frontendSessionId, prompt, progress, launchGuard) {
|
|
1523
1539
|
const record = globalSessionState.sessions.find(candidate => candidate.sessionId === frontendSessionId);
|
|
1524
1540
|
if (!record)
|
|
1525
1541
|
throw new Error('SESSION_REMOVED');
|
|
1526
|
-
const write = await automaticTerminalInput(record, terminalInputGuard(record), progress);
|
|
1542
|
+
const write = await automaticTerminalInput(record, launchGuard ?? terminalInputGuard(record), progress);
|
|
1527
1543
|
await write(prompt);
|
|
1528
1544
|
}
|
|
1529
1545
|
async function deliverAutomationPromptWhenReady(backendSessionId, prompt) {
|
|
@@ -1580,9 +1596,8 @@ async function runAgentAutomation(automation, req) {
|
|
|
1580
1596
|
throw new Error('自动任务会话创建失败');
|
|
1581
1597
|
if (automation.command) {
|
|
1582
1598
|
const agent = detectAgentFromCommand(automation.command, agentCustomCommands());
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
await writeAutomaticTerminalPrompt(frontendSessionId, automation.command);
|
|
1599
|
+
const launchGuard = agent ? await beginAgentLaunchCheck(frontendSessionId, agent.slug) : undefined;
|
|
1600
|
+
await writeAutomaticTerminalPrompt(frontendSessionId, automation.command, undefined, launchGuard);
|
|
1586
1601
|
}
|
|
1587
1602
|
if (automation.prompt) {
|
|
1588
1603
|
if (automation.command)
|
|
@@ -1970,7 +1985,7 @@ async function spawnCollaborationAgentSession(req, group, sourceSessionId, input
|
|
|
1970
1985
|
const backend = terminalSessions.get(opened.terminalSession.sessionId);
|
|
1971
1986
|
if (!backend)
|
|
1972
1987
|
throw new HttpStatusError(500, 'Agent Session 创建失败', 'COLLAB_AGENT_SESSION_FAILED');
|
|
1973
|
-
await beginAgentLaunchCheck(frontendSessionId, launcher.slug);
|
|
1988
|
+
const launchGuard = await beginAgentLaunchCheck(frontendSessionId, launcher.slug);
|
|
1974
1989
|
const latestGroup = collaborationStore.getGroup(group.id);
|
|
1975
1990
|
if (!latestGroup || latestGroup.deleted) {
|
|
1976
1991
|
const created = globalSessionState.sessions.find(record => record.sessionId === frontendSessionId);
|
|
@@ -1993,7 +2008,7 @@ async function spawnCollaborationAgentSession(req, group, sourceSessionId, input
|
|
|
1993
2008
|
collaborationStore.setRole({ groupId: group.id, sessionId: frontendSessionId, role: bootstrapRole, creationKey });
|
|
1994
2009
|
if (profile)
|
|
1995
2010
|
collaborationStore.setMemberLaunchProfile(group.id, frontendSessionId, profile);
|
|
1996
|
-
await writeAutomaticTerminalPrompt(frontendSessionId, buildCollaborationSpawnCommand({ slug: launcher.slug, command: profile?.command ?? launcher.command }));
|
|
2011
|
+
await writeAutomaticTerminalPrompt(frontendSessionId, buildCollaborationSpawnCommand({ slug: launcher.slug, command: profile?.command ?? launcher.command }), undefined, launchGuard);
|
|
1997
2012
|
const requestedTask = typeof input.task === 'string' ? input.task.trim().slice(0, 20_000) : '';
|
|
1998
2013
|
collaborationStore.send({
|
|
1999
2014
|
groupId: updatedGroup.id,
|
|
@@ -2423,8 +2438,8 @@ async function launchIntegrationTerminal(record, restoring, prepared, progress,
|
|
|
2423
2438
|
backend.agent = null;
|
|
2424
2439
|
backend.agentResumeRecovered = false;
|
|
2425
2440
|
progress?.('launch_intent');
|
|
2426
|
-
await beginAgentLaunchCheck(record.session_id, record.agent_slug, restoring ? record.agent_native_session_id : null);
|
|
2427
|
-
await writeAutomaticTerminalPrompt(record.session_id, integrationLaunchCommand(record, restoring), progress);
|
|
2441
|
+
const launchGuard = await beginAgentLaunchCheck(record.session_id, record.agent_slug, restoring ? record.agent_native_session_id : null);
|
|
2442
|
+
await writeAutomaticTerminalPrompt(record.session_id, integrationLaunchCommand(record, restoring), progress, launchGuard);
|
|
2428
2443
|
broadcastClientState();
|
|
2429
2444
|
});
|
|
2430
2445
|
}
|
|
@@ -2471,12 +2486,12 @@ export function prepareCollaborationTaskWorker(task, template, dependencies, ser
|
|
|
2471
2486
|
throw error;
|
|
2472
2487
|
}
|
|
2473
2488
|
if (!currentAgent && (!launch || launch.backendId !== opened.terminalSession.sessionId)) {
|
|
2474
|
-
await beginAgentLaunchCheck(record.sessionId, launcher.slug);
|
|
2489
|
+
const launchGuard = await beginAgentLaunchCheck(record.sessionId, launcher.slug);
|
|
2475
2490
|
// Persist before typing: a retry must never type the launcher into a newly booted Agent's prompt.
|
|
2476
2491
|
const temporary = `${launchFile}.${process.pid}.tmp`;
|
|
2477
2492
|
await fs.promises.writeFile(temporary, JSON.stringify({ sessionId: record.sessionId, backendId: opened.terminalSession.sessionId }), { mode: 0o600 });
|
|
2478
2493
|
await fs.promises.rename(temporary, launchFile);
|
|
2479
|
-
await writeAutomaticTerminalPrompt(opened.session.sessionId, buildCollaborationSpawnCommand({ slug: launcher.slug, command: inheritedProfile?.command ?? launcher.command }));
|
|
2494
|
+
await writeAutomaticTerminalPrompt(opened.session.sessionId, buildCollaborationSpawnCommand({ slug: launcher.slug, command: inheritedProfile?.command ?? launcher.command }), undefined, launchGuard);
|
|
2480
2495
|
}
|
|
2481
2496
|
const group = collaborationStore.getGroup(task.groupId);
|
|
2482
2497
|
if (!group || group.deleted)
|
|
@@ -2510,10 +2525,10 @@ function getTmuxBinary() {
|
|
|
2510
2525
|
}
|
|
2511
2526
|
return 'tmux'; // fallback to PATH
|
|
2512
2527
|
}
|
|
2513
|
-
async function runTmux(args) {
|
|
2528
|
+
async function runTmux(args, options) {
|
|
2514
2529
|
const { stdout } = await execFileAsync(getTmuxBinary(), args, {
|
|
2515
2530
|
timeout: 5000,
|
|
2516
|
-
maxBuffer: 2 * 1024 * 1024,
|
|
2531
|
+
maxBuffer: options?.maxBuffer ?? 2 * 1024 * 1024,
|
|
2517
2532
|
env: buildInteractiveColorEnvironment(process.env),
|
|
2518
2533
|
});
|
|
2519
2534
|
return stdout;
|
|
@@ -4672,19 +4687,26 @@ async function resolveTmuxClientTty(sessionName, preferredClientPid) {
|
|
|
4672
4687
|
}
|
|
4673
4688
|
async function ensureTmuxSessionExists(sessionName, cwd) {
|
|
4674
4689
|
let serverWasMissing = false;
|
|
4690
|
+
let serverIsEmpty = false;
|
|
4691
|
+
let sessionExists = false;
|
|
4675
4692
|
try {
|
|
4676
4693
|
await runTmux(['has-session', '-t', sessionName]);
|
|
4677
|
-
|
|
4678
|
-
return;
|
|
4694
|
+
sessionExists = true;
|
|
4679
4695
|
}
|
|
4680
4696
|
catch (error) {
|
|
4681
4697
|
const errorMessage = getErrorMessage(error);
|
|
4682
4698
|
serverWasMissing = isTmuxServerMissingMessage(errorMessage);
|
|
4683
4699
|
if (!isTmuxSessionMissingMessage(errorMessage)) {
|
|
4684
|
-
|
|
4700
|
+
serverIsEmpty = await isConfirmedEmptyTmuxServer(error, sessionName, runTmux);
|
|
4701
|
+
if (!serverIsEmpty)
|
|
4702
|
+
throw error;
|
|
4685
4703
|
}
|
|
4686
4704
|
}
|
|
4687
|
-
if (
|
|
4705
|
+
if (sessionExists) {
|
|
4706
|
+
await ensureTmuxColorEnvironment(sessionName);
|
|
4707
|
+
return;
|
|
4708
|
+
}
|
|
4709
|
+
if (!serverWasMissing && !serverIsEmpty) {
|
|
4688
4710
|
await ensureTmuxColorEnvironment();
|
|
4689
4711
|
}
|
|
4690
4712
|
const innerTerm = await resolveTmuxInnerTerm();
|
|
@@ -6144,8 +6166,8 @@ router.post('/tmux/recovery/restore-all', async (_req, res) => {
|
|
|
6144
6166
|
const previous = collaborationRouting.get(frontendSessionId);
|
|
6145
6167
|
if (previous)
|
|
6146
6168
|
collaborationRouting.bind({ ...previous, pane: null });
|
|
6147
|
-
await beginAgentLaunchCheck(frontendSessionId, agent.slug, target.nativeSessionId);
|
|
6148
|
-
await writeAutomaticTerminalPrompt(frontendSessionId, command);
|
|
6169
|
+
const launchGuard = await beginAgentLaunchCheck(frontendSessionId, agent.slug, target.nativeSessionId);
|
|
6170
|
+
await writeAutomaticTerminalPrompt(frontendSessionId, command, undefined, launchGuard);
|
|
6149
6171
|
}));
|
|
6150
6172
|
outcomes.push({ sessionId: frontendSessionId, restored: true });
|
|
6151
6173
|
}
|
|
@@ -7098,8 +7120,8 @@ router.post('/operations/execution-archives/:sessionId/restore', executionArchiv
|
|
|
7098
7120
|
broadcastClientState();
|
|
7099
7121
|
throw error;
|
|
7100
7122
|
}
|
|
7101
|
-
await beginAgentLaunchCheck(record.sessionId, target.slug, target.nativeSessionId);
|
|
7102
|
-
await writeAutomaticTerminalPrompt(opened.session.sessionId, command);
|
|
7123
|
+
const launchGuard = await beginAgentLaunchCheck(record.sessionId, target.slug, target.nativeSessionId);
|
|
7124
|
+
await writeAutomaticTerminalPrompt(opened.session.sessionId, command, undefined, launchGuard);
|
|
7103
7125
|
restoreArchivedMembership(entry, record.sessionId);
|
|
7104
7126
|
await persistGlobalStateNow();
|
|
7105
7127
|
broadcastClientState();
|
|
@@ -8294,7 +8316,10 @@ router.post('/:sessionId/input', express.text({ type: '*/*' }), (req, res) => {
|
|
|
8294
8316
|
}
|
|
8295
8317
|
const data = typeof req.body === 'string' ? req.body : '';
|
|
8296
8318
|
try {
|
|
8297
|
-
|
|
8319
|
+
const paste = new TerminalPasteBuffer(() => { });
|
|
8320
|
+
const parts = paste.complete(data);
|
|
8321
|
+
for (const part of parts)
|
|
8322
|
+
session.ptyProcess.write(part);
|
|
8298
8323
|
session.lastActivity = Date.now();
|
|
8299
8324
|
res.json({ success: true });
|
|
8300
8325
|
}
|
|
@@ -8343,10 +8368,9 @@ router.post('/:sessionId/agent-resume', async (req, res) => {
|
|
|
8343
8368
|
try {
|
|
8344
8369
|
const frontend = globalSessionState.sessions.find(candidate => candidate.backendSessionId === sessionId);
|
|
8345
8370
|
const launch = async () => {
|
|
8371
|
+
const launchGuard = frontend ? await beginAgentLaunchCheck(frontend.sessionId, target.slug, target.nativeSessionId) : undefined;
|
|
8346
8372
|
if (frontend)
|
|
8347
|
-
await
|
|
8348
|
-
if (frontend)
|
|
8349
|
-
await writeAutomaticTerminalPrompt(frontend.sessionId, target.command);
|
|
8373
|
+
await writeAutomaticTerminalPrompt(frontend.sessionId, target.command, undefined, launchGuard);
|
|
8350
8374
|
else
|
|
8351
8375
|
await writeBracketedPrompt(session.ptyProcess, target.command, captureTerminalInputGuard(() => terminalSessions.get(sessionId), session));
|
|
8352
8376
|
};
|
|
@@ -8464,7 +8488,7 @@ router.post('/:sessionId/tmux', async (req, res) => {
|
|
|
8464
8488
|
broadcastEvent(sessionId, { type: 'tmux-layout', layout });
|
|
8465
8489
|
return res.json({ success: true, layout });
|
|
8466
8490
|
}
|
|
8467
|
-
return res.json({ success: true });
|
|
8491
|
+
return res.json({ success: true, ...(result.selection ? { selection: result.selection } : {}) });
|
|
8468
8492
|
}
|
|
8469
8493
|
catch (error) {
|
|
8470
8494
|
const errorMessage = getErrorMessage(error);
|
|
@@ -8559,6 +8583,10 @@ router.post('/force-kill', (req, res) => {
|
|
|
8559
8583
|
async function executeTmuxAction(tmuxTarget, action, body, control) {
|
|
8560
8584
|
let shouldBroadcastLayout = true;
|
|
8561
8585
|
switch (action) {
|
|
8586
|
+
case 'copy-selection': {
|
|
8587
|
+
const selection = await copyTmuxSelection(tmuxTarget, runTmux);
|
|
8588
|
+
return { shouldBroadcastLayout: false, selection };
|
|
8589
|
+
}
|
|
8562
8590
|
case 'select-pane': {
|
|
8563
8591
|
const paneId = typeof body.paneId === 'string' ? body.paneId : '';
|
|
8564
8592
|
if (!paneId)
|
|
@@ -8949,6 +8977,12 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
|
|
|
8949
8977
|
if (ws.readyState === ws.OPEN)
|
|
8950
8978
|
ws.send(JSON.stringify(event));
|
|
8951
8979
|
});
|
|
8980
|
+
const pasteInput = new TerminalPasteBuffer(error => {
|
|
8981
|
+
if (ws.readyState === ws.OPEN) {
|
|
8982
|
+
ws.send(JSON.stringify({ type: 'error', error }));
|
|
8983
|
+
ws.close(1008, 'Incomplete terminal paste');
|
|
8984
|
+
}
|
|
8985
|
+
});
|
|
8952
8986
|
// Handle client → server messages
|
|
8953
8987
|
ws.on('message', async (raw) => {
|
|
8954
8988
|
const messageReceivedAt = performance.now();
|
|
@@ -8963,20 +8997,30 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
|
|
|
8963
8997
|
switch (msg.type) {
|
|
8964
8998
|
case 'input': {
|
|
8965
8999
|
if (typeof msg.data === 'string' && msg.data.length > 0) {
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
|
|
8969
|
-
attachment.write(data);
|
|
9000
|
+
let parts;
|
|
9001
|
+
try {
|
|
9002
|
+
parts = pasteInput.push(msg.data);
|
|
8970
9003
|
}
|
|
8971
|
-
|
|
8972
|
-
|
|
9004
|
+
catch (error) {
|
|
9005
|
+
ws.send(JSON.stringify({ type: 'error', error: getErrorMessage(error) }));
|
|
9006
|
+
ws.close(1008, 'Invalid terminal paste');
|
|
9007
|
+
return;
|
|
9008
|
+
}
|
|
9009
|
+
for (const data of parts) {
|
|
9010
|
+
if (attachment) {
|
|
9011
|
+
session.lastActivity = Date.now();
|
|
9012
|
+
attachment.write(data);
|
|
9013
|
+
}
|
|
9014
|
+
else if (session.mode === 'tmux') {
|
|
9015
|
+
await enqueueTmuxIo(session, async () => {
|
|
9016
|
+
session.lastActivity = Date.now();
|
|
9017
|
+
session.ptyProcess.write(data);
|
|
9018
|
+
});
|
|
9019
|
+
}
|
|
9020
|
+
else {
|
|
8973
9021
|
session.lastActivity = Date.now();
|
|
8974
9022
|
session.ptyProcess.write(data);
|
|
8975
|
-
}
|
|
8976
|
-
}
|
|
8977
|
-
else {
|
|
8978
|
-
session.lastActivity = Date.now();
|
|
8979
|
-
session.ptyProcess.write(data);
|
|
9023
|
+
}
|
|
8980
9024
|
}
|
|
8981
9025
|
}
|
|
8982
9026
|
break;
|
|
@@ -9044,8 +9088,14 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
|
|
|
9044
9088
|
}
|
|
9045
9089
|
const result = await enqueueTmuxIo(session, async () => {
|
|
9046
9090
|
return executeTmuxAction(session.tmuxSessionName, msg.action, msg, session.tmuxControl);
|
|
9091
|
+
}).catch((error) => {
|
|
9092
|
+
// A correlated copy failure must settle this socket's request, not
|
|
9093
|
+
// become an unrelated terminal error followed by a 30-second wait.
|
|
9094
|
+
if (msg.action !== 'copy-selection')
|
|
9095
|
+
throw error;
|
|
9096
|
+
return { shouldBroadcastLayout: false, error: getErrorMessage(error) || 'Tmux selection copy failed' };
|
|
9047
9097
|
});
|
|
9048
|
-
ws.send(JSON.stringify({ type: 'tmux-result', reqId, success: !result.error, error: result.error }));
|
|
9098
|
+
ws.send(JSON.stringify({ type: 'tmux-result', reqId, success: !result.error, error: result.error, ...(result.selection ? { selection: result.selection } : {}) }));
|
|
9049
9099
|
if (result.shouldBroadcastLayout && session.tmuxSessionName) {
|
|
9050
9100
|
try {
|
|
9051
9101
|
const layout = await getTmuxLayout(session.tmuxSessionName);
|
|
@@ -9143,6 +9193,7 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
|
|
|
9143
9193
|
});
|
|
9144
9194
|
// Cleanup on close
|
|
9145
9195
|
ws.on('close', () => {
|
|
9196
|
+
pasteInput.clear();
|
|
9146
9197
|
initialScreen?.cancel();
|
|
9147
9198
|
initialScreen = null;
|
|
9148
9199
|
attachment?.close();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { compareVersions, updateTermdockFromOfficialRegistry, } from './npmUpdate.js';
|
|
3
|
+
import { compareVersions, verifyRunningTermdockInstallation, updateTermdockFromOfficialRegistry, } from './npmUpdate.js';
|
|
4
4
|
export const AUTO_UPDATE_INITIAL_DELAY_MS = 15_000;
|
|
5
5
|
export const AUTO_UPDATE_INTERVAL_MS = 6 * 60 * 60 * 1_000;
|
|
6
6
|
function initialState(currentVersion) {
|
|
@@ -44,11 +44,11 @@ export class TermdockAutoUpdateManager {
|
|
|
44
44
|
return;
|
|
45
45
|
this.initialTimer = setTimeout(() => {
|
|
46
46
|
this.initialTimer = null;
|
|
47
|
-
void this.checkNow();
|
|
47
|
+
void this.checkNow(false);
|
|
48
48
|
}, AUTO_UPDATE_INITIAL_DELAY_MS);
|
|
49
49
|
this.initialTimer.unref?.();
|
|
50
50
|
this.intervalTimer = setInterval(() => {
|
|
51
|
-
void this.checkNow();
|
|
51
|
+
void this.checkNow(false);
|
|
52
52
|
}, AUTO_UPDATE_INTERVAL_MS);
|
|
53
53
|
this.intervalTimer.unref?.();
|
|
54
54
|
}
|
|
@@ -60,12 +60,24 @@ export class TermdockAutoUpdateManager {
|
|
|
60
60
|
this.initialTimer = null;
|
|
61
61
|
this.intervalTimer = null;
|
|
62
62
|
}
|
|
63
|
-
checkNow() {
|
|
63
|
+
checkNow(explicit = true) {
|
|
64
|
+
// Failed installation validation requires a user-requested check, not a timer retry.
|
|
65
|
+
if (!explicit && this.state.status === 'error' && hasPendingTermdockUpdate(this.state))
|
|
66
|
+
return Promise.resolve(this.getState());
|
|
64
67
|
// Once an installed update is waiting for explicit confirmation, periodic
|
|
65
68
|
// checks must never turn any external state change into implicit consent.
|
|
66
69
|
// Keep the reminder until the user confirms or restarts manually.
|
|
67
70
|
if (this.state.status === 'ready' && hasPendingTermdockUpdate(this.state)) {
|
|
68
|
-
|
|
71
|
+
try {
|
|
72
|
+
this.verifyInstalled(this.state.latestVersion);
|
|
73
|
+
return Promise.resolve(this.getState());
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
this.installationError(error);
|
|
77
|
+
if (!explicit)
|
|
78
|
+
return Promise.resolve(this.getState());
|
|
79
|
+
}
|
|
80
|
+
// Only the explicit check repairs an invalid pending installation; never restart here.
|
|
69
81
|
}
|
|
70
82
|
if (this.checkPromise)
|
|
71
83
|
return this.checkPromise;
|
|
@@ -78,10 +90,33 @@ export class TermdockAutoUpdateManager {
|
|
|
78
90
|
if (this.state.status !== 'ready' || !hasPendingTermdockUpdate(this.state)) {
|
|
79
91
|
throw new Error('No installed Termdock update is waiting for restart.');
|
|
80
92
|
}
|
|
93
|
+
try {
|
|
94
|
+
this.verifyInstalled(this.state.latestVersion);
|
|
95
|
+
if (process.env.TERMDOCK_SUPERVISED !== '1' || !process.connected)
|
|
96
|
+
throw new Error('Automatic restart requires the verified supervised Termdock entry; restart manually.');
|
|
97
|
+
this.dependencies.verifyRestartEntry?.();
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
this.installationError(error);
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
81
103
|
this.setState({ ...this.state, status: 'restarting', error: null });
|
|
82
|
-
|
|
104
|
+
try {
|
|
105
|
+
this.dependencies.requestRestart();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
this.installationError(error);
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
83
111
|
return this.getState();
|
|
84
112
|
}
|
|
113
|
+
verifyInstalled(version) {
|
|
114
|
+
(this.dependencies.verifyInstalled ?? verifyRunningTermdockInstallation)(version);
|
|
115
|
+
}
|
|
116
|
+
installationError(error) {
|
|
117
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
118
|
+
this.setState({ ...this.state, status: 'error', error: detail });
|
|
119
|
+
}
|
|
85
120
|
async runCheck() {
|
|
86
121
|
this.setState({ ...this.state, status: 'checking', checkedAt: Date.now(), error: null });
|
|
87
122
|
try {
|
|
@@ -110,6 +145,7 @@ export class TermdockAutoUpdateManager {
|
|
|
110
145
|
});
|
|
111
146
|
return this.getState();
|
|
112
147
|
}
|
|
148
|
+
this.verifyInstalled(result.latestVersion);
|
|
113
149
|
this.setState({
|
|
114
150
|
status: 'ready',
|
|
115
151
|
currentVersion: result.currentVersion,
|
|
@@ -145,13 +181,24 @@ export class TermdockAutoUpdateManager {
|
|
|
145
181
|
return fallback;
|
|
146
182
|
if (value.status !== 'ready' && value.status !== 'restarting' && value.status !== 'error')
|
|
147
183
|
return fallback;
|
|
184
|
+
let restoredStatus = value.status === 'restarting' ? 'ready' : value.status;
|
|
185
|
+
let restoredError = typeof value.error === 'string' ? value.error : null;
|
|
186
|
+
if (restoredStatus === 'ready') {
|
|
187
|
+
try {
|
|
188
|
+
this.verifyInstalled(value.latestVersion);
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
restoredStatus = 'error';
|
|
192
|
+
restoredError = error instanceof Error ? error.message : String(error);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
148
195
|
return {
|
|
149
|
-
status:
|
|
196
|
+
status: restoredStatus,
|
|
150
197
|
currentVersion: this.dependencies.currentVersion,
|
|
151
198
|
latestVersion: value.latestVersion,
|
|
152
199
|
source: value.source === 'configured' ? 'configured' : 'official',
|
|
153
200
|
checkedAt: typeof value.checkedAt === 'number' ? value.checkedAt : null,
|
|
154
|
-
error:
|
|
201
|
+
error: restoredError,
|
|
155
202
|
};
|
|
156
203
|
}
|
|
157
204
|
catch {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { execFile, spawn } from 'node:child_process';
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
3
6
|
const execFileAsync = promisify(execFile);
|
|
4
7
|
export const OFFICIAL_NPM_REGISTRY = 'https://registry.npmjs.org';
|
|
5
8
|
const TERMDOCK_PACKAGE = 'termdock';
|
|
@@ -41,7 +44,7 @@ export function buildNpmViewArgs(registry = OFFICIAL_NPM_REGISTRY) {
|
|
|
41
44
|
args.push('--registry', registry);
|
|
42
45
|
return args;
|
|
43
46
|
}
|
|
44
|
-
export function buildNpmInstallArgs(version, registry = OFFICIAL_NPM_REGISTRY) {
|
|
47
|
+
export function buildNpmInstallArgs(version, registry = OFFICIAL_NPM_REGISTRY, prefix) {
|
|
45
48
|
if (!parseVersion(version))
|
|
46
49
|
throw new Error(`Invalid Termdock version from npm: ${version}`);
|
|
47
50
|
const args = [
|
|
@@ -49,11 +52,56 @@ export function buildNpmInstallArgs(version, registry = OFFICIAL_NPM_REGISTRY) {
|
|
|
49
52
|
'--global',
|
|
50
53
|
`${TERMDOCK_PACKAGE}@${version}`,
|
|
51
54
|
];
|
|
55
|
+
if (prefix)
|
|
56
|
+
args.push('--prefix', prefix);
|
|
52
57
|
if (registry)
|
|
53
58
|
args.push('--registry', registry);
|
|
54
59
|
args.push('--foreground-scripts');
|
|
55
60
|
return args;
|
|
56
61
|
}
|
|
62
|
+
function installedVersion(installation) {
|
|
63
|
+
// Fresh filesystem reads: npm replaces this package while this process keeps
|
|
64
|
+
// running old JS. Neither require/import caches nor TERMDOCK_VERSION attest it.
|
|
65
|
+
if (fs.realpathSync(installation.packageRoot) !== installation.packageRoot) {
|
|
66
|
+
throw new Error('Running Termdock installation changed location; check for updates again.');
|
|
67
|
+
}
|
|
68
|
+
const value = JSON.parse(fs.readFileSync(path.join(installation.packageRoot, 'package.json'), 'utf8'));
|
|
69
|
+
if (!value || typeof value !== 'object' || !('name' in value) || value.name !== TERMDOCK_PACKAGE
|
|
70
|
+
|| !('version' in value) || typeof value.version !== 'string' || !parseVersion(value.version)) {
|
|
71
|
+
throw new Error('Running Termdock installation has invalid package metadata.');
|
|
72
|
+
}
|
|
73
|
+
return value.version;
|
|
74
|
+
}
|
|
75
|
+
/** Resolve the module which is actually running, never PATH's unrelated npm root. */
|
|
76
|
+
export function resolveRunningTermdockInstallation(moduleUrl = import.meta.url, runningEntry = process.argv[1]) {
|
|
77
|
+
const moduleFile = fs.realpathSync(fileURLToPath(moduleUrl));
|
|
78
|
+
const packageRoot = path.resolve(path.dirname(moduleFile), '../../..');
|
|
79
|
+
const nodeModules = path.dirname(packageRoot);
|
|
80
|
+
if (path.basename(packageRoot) !== TERMDOCK_PACKAGE || path.basename(nodeModules) !== 'node_modules') {
|
|
81
|
+
throw new Error('Automatic updates require a supported global Termdock installation.');
|
|
82
|
+
}
|
|
83
|
+
const parent = path.dirname(nodeModules);
|
|
84
|
+
let prefix;
|
|
85
|
+
if (process.platform === 'win32')
|
|
86
|
+
prefix = parent;
|
|
87
|
+
else if (path.basename(parent) === 'lib')
|
|
88
|
+
prefix = path.dirname(parent);
|
|
89
|
+
else
|
|
90
|
+
throw new Error('Automatic updates require a supported global Termdock installation.');
|
|
91
|
+
const installation = { packageRoot, prefix };
|
|
92
|
+
// supervisor resolves and reuses this child's argv entry. A module loaded
|
|
93
|
+
// from another installation must never approve that different restart root.
|
|
94
|
+
if (!runningEntry || fs.realpathSync(runningEntry) !== path.join(packageRoot, 'dist/server/cli.js')) {
|
|
95
|
+
throw new Error('Running Termdock entry does not match its update installation.');
|
|
96
|
+
}
|
|
97
|
+
installedVersion(installation);
|
|
98
|
+
return installation;
|
|
99
|
+
}
|
|
100
|
+
export function verifyRunningTermdockInstallation(version, installation = resolveRunningTermdockInstallation()) {
|
|
101
|
+
if (compareVersions(installedVersion(installation), version) < 0) {
|
|
102
|
+
throw new Error('Running Termdock installation has not completed this update; check for updates again.');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
57
105
|
export function parseNpmVersionOutput(output) {
|
|
58
106
|
let value;
|
|
59
107
|
try {
|
|
@@ -67,6 +115,26 @@ export function parseNpmVersionOutput(output) {
|
|
|
67
115
|
}
|
|
68
116
|
return value;
|
|
69
117
|
}
|
|
118
|
+
export function npmRuntimeEnvironment(execPath = process.execPath, env = process.env, platform = process.platform) {
|
|
119
|
+
const systemBins = platform === 'darwin' ? ['/opt/homebrew/bin', '/usr/local/bin'] : [];
|
|
120
|
+
return { ...env, PATH: [path.dirname(execPath), ...systemBins, env.PATH].filter(Boolean).join(path.delimiter) };
|
|
121
|
+
}
|
|
122
|
+
async function installEnvironment() {
|
|
123
|
+
const env = npmRuntimeEnvironment();
|
|
124
|
+
if (process.platform === 'darwin') {
|
|
125
|
+
// New CLT releases can leave node-gyp's implicit libc++ search path stale.
|
|
126
|
+
// Use the SDK selected by xcrun without changing the user's global setup.
|
|
127
|
+
const { stdout } = await execFileAsync('/usr/bin/xcrun', ['--show-sdk-path'], { timeout: 5000, env });
|
|
128
|
+
const sdk = stdout.trim();
|
|
129
|
+
const headers = path.join(sdk, 'usr/include/c++/v1');
|
|
130
|
+
if (!path.isAbsolute(sdk) || !fs.existsSync(path.join(headers, 'functional'))) {
|
|
131
|
+
throw new Error('macOS C++ SDK headers are unavailable. Install or repair Command Line Tools, then retry.');
|
|
132
|
+
}
|
|
133
|
+
env.SDKROOT = sdk;
|
|
134
|
+
env.CPLUS_INCLUDE_PATH = [headers, env.CPLUS_INCLUDE_PATH].filter(Boolean).join(path.delimiter);
|
|
135
|
+
}
|
|
136
|
+
return env;
|
|
137
|
+
}
|
|
70
138
|
function npmExecutable() {
|
|
71
139
|
return process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
72
140
|
}
|
|
@@ -76,7 +144,7 @@ async function fetchLatestVersion(registry) {
|
|
|
76
144
|
const result = await execFileAsync(npmExecutable(), buildNpmViewArgs(registry), {
|
|
77
145
|
timeout: NPM_QUERY_TIMEOUT_MS,
|
|
78
146
|
maxBuffer: 256 * 1024,
|
|
79
|
-
env:
|
|
147
|
+
env: npmRuntimeEnvironment(),
|
|
80
148
|
});
|
|
81
149
|
stdout = result.stdout;
|
|
82
150
|
}
|
|
@@ -87,11 +155,15 @@ async function fetchLatestVersion(registry) {
|
|
|
87
155
|
}
|
|
88
156
|
return parseNpmVersionOutput(stdout);
|
|
89
157
|
}
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
158
|
+
export async function installTermdockVersion(version, registry, installation, executable = npmExecutable()) {
|
|
159
|
+
if (compareVersions(installedVersion(installation), version) > 0) {
|
|
160
|
+
throw new Error('Running Termdock location already contains a newer version; restart that installation manually.');
|
|
161
|
+
}
|
|
162
|
+
const env = await installEnvironment();
|
|
163
|
+
await new Promise((resolve, reject) => {
|
|
164
|
+
const child = spawn(executable, buildNpmInstallArgs(version, registry, installation.prefix), {
|
|
93
165
|
stdio: 'inherit',
|
|
94
|
-
env
|
|
166
|
+
env,
|
|
95
167
|
});
|
|
96
168
|
child.once('error', reject);
|
|
97
169
|
child.once('exit', (code, signal) => {
|
|
@@ -103,6 +175,9 @@ function installVersion(version, registry) {
|
|
|
103
175
|
reject(new Error(`npm failed to install Termdock (${reason}).`));
|
|
104
176
|
});
|
|
105
177
|
});
|
|
178
|
+
if (installedVersion(installation) !== version) {
|
|
179
|
+
throw new Error('npm did not install the requested version at the running Termdock location.');
|
|
180
|
+
}
|
|
106
181
|
}
|
|
107
182
|
export async function updateTermdockFromOfficialRegistry(currentVersion, onFallback, onLatest) {
|
|
108
183
|
if (!parseVersion(currentVersion))
|
|
@@ -124,8 +199,9 @@ export async function updateTermdockFromOfficialRegistry(currentVersion, onFallb
|
|
|
124
199
|
return { status: 'current', currentVersion, latestVersion, source };
|
|
125
200
|
if (comparison > 0)
|
|
126
201
|
return { status: 'newer-than-registry', currentVersion, latestVersion, source };
|
|
202
|
+
const installation = resolveRunningTermdockInstallation();
|
|
127
203
|
try {
|
|
128
|
-
await
|
|
204
|
+
await installTermdockVersion(latestVersion, source === 'official' ? OFFICIAL_NPM_REGISTRY : null, installation);
|
|
129
205
|
}
|
|
130
206
|
catch (error) {
|
|
131
207
|
if (source === 'configured')
|
|
@@ -133,7 +209,7 @@ export async function updateTermdockFromOfficialRegistry(currentVersion, onFallb
|
|
|
133
209
|
const cause = error instanceof Error ? error : new Error(String(error));
|
|
134
210
|
onFallback?.('install', cause);
|
|
135
211
|
source = 'configured';
|
|
136
|
-
await
|
|
212
|
+
await installTermdockVersion(latestVersion, null, installation);
|
|
137
213
|
}
|
|
138
214
|
return { status: 'updated', currentVersion, latestVersion, source };
|
|
139
215
|
}
|