termdock 1.4.322 → 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-VDM6hrwp.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-B64j3i8o.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-Co-TTYas.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-kJczdJ6J.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-BaaioC-q.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-Wfck3RIS.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-Dblr3wgw.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-C-utC5Ga.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-BBLnHWVQ.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-CUHSFkmZ.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-DDd99QpA.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-C3dck_E0.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-C3bCQc2w.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-znMn6iCQ.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-C0sopIsj.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-f7USyccJ.js → chunk-2Q5K7J3B-BPd2UShA.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-Ck2xirDs.js → chunk-5VM5RSS4-CoFZ5Fo3.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-DaDCIj30.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-DEC_On5x.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-BrswC3n2.js → chunk-JWPE2WC7-GpMoViQf.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-ClMbDV47.js → chunk-POPQ4Y6H-C_vgVPaw.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-D7_1VwC5.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-D5jzVTZ8.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-DOhaoLcX.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-DOsaKgiX.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-CMcLh_wh.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-Dd8bfq9V.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-BlW7fAi0.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-B0-tKahG.js → diagram-S7CK7UJ4-c_8HfHGA.js} +1 -1
- package/dist/client/assets/{diagram-S7CK7UJ4-B0-tKahG.js.br → 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-BQumj4Dw.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-Zx_FLmPP.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-CEZvatNH.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-CJ9IEQ8j.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-sQQMv3ea.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-D3rMpj7M.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-B6QZiE0-.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-Bw9bltcu.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-Cczz34oI.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-mdnkxjeD.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-DyrPP3Yf.js → infoDiagram-27XIBGKW-CsA6WdPn.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-CEPH_ePM.js → ishikawaDiagram-5VMMS53U-CsKPUwTw.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CsKPUwTw.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CsKPUwTw.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-CQ0PjBy7.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-BpQUXA60.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-BdptC7rq.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-C2cSRCxu.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-ClVMFyAU.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-D0AFCmsY.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-BGAh0bwg.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-CDOZUF44.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-D_Qn6NTU.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-qUVGWhJN.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-hgCM4i-j.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-BEMsP11a.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-BBQMQuVZ.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-CeEExsqW.js → sankeyDiagram-P5KCCOFB-1mZ4s-lv.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-CeEExsqW.js.br → 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-7ZPO-X0a.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-MBjz7Snm.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-C9ShmGPf.js → sparkles-CDonlwGu.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-DtLp89uP.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-Bc02S1q-.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-BLLwbOm5.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-i_L8ws6U.js → triangle-alert-BgErMO2V.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-8FcrAdbk.js → vennDiagram-4TSXK5OY-CPE6pVwh.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-8FcrAdbk.js.br → vennDiagram-4TSXK5OY-CPE6pVwh.js.br} +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CPE6pVwh.js.gz +0 -0
- package/dist/client/assets/{videoCompression-RIaDabW4.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-paL2wRrJ.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-BM5qJ4E7.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/collaborationGroupRoutes.js +15 -0
- package/dist/server/agent/collaborationStore.js +63 -2
- package/dist/server/agent/collaborationTaskRoutes.js +5 -1
- package/dist/server/agent/integrationCli.js +38 -20
- package/dist/server/agent/integrationServer.js +18 -1
- 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 +60 -20
- 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 +36 -0
- package/package.json +5 -2
- package/runtime-manifest.json +3 -3
- package/.desktop-dist/main.js +0 -1989
- package/dist/client/assets/App-DEKo4SNL.js +0 -186
- 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-VDM6hrwp.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-VDM6hrwp.js.gz +0 -0
- 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-DG8TQNqo.js +0 -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 +0 -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-kJczdJ6J.js.br +0 -0
- package/dist/client/assets/DagPlayground-kJczdJ6J.js.gz +0 -0
- 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-Wfck3RIS.js.br +0 -0
- package/dist/client/assets/DiffReview-Wfck3RIS.js.gz +0 -0
- 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-C-utC5Ga.js.br +0 -0
- package/dist/client/assets/DiffViewer-C-utC5Ga.js.gz +0 -0
- 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-CUHSFkmZ.js.br +0 -0
- package/dist/client/assets/RightSidebar-CUHSFkmZ.js.gz +0 -0
- 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-CfqF7_nh.js +0 -35
- 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-C3dck_E0.js.br +0 -0
- package/dist/client/assets/arc-C3dck_E0.js.gz +0 -0
- 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-znMn6iCQ.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-znMn6iCQ.js.gz +0 -0
- 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 +0 -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-DEC_On5x.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-DEC_On5x.js.gz +0 -0
- 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-D5jzVTZ8.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-D5jzVTZ8.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-ElMHzA-E.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-ElMHzA-E.js +0 -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-CMcLh_wh.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-CMcLh_wh.js.gz +0 -0
- 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-BlW7fAi0.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-BlW7fAi0.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-B0-tKahG.js.gz +0 -0
- 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-Zx_FLmPP.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-Zx_FLmPP.js.gz +0 -0
- 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-CJ9IEQ8j.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-CJ9IEQ8j.js.gz +0 -0
- 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-D3rMpj7M.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-D3rMpj7M.js.gz +0 -0
- 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-Bw9bltcu.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-Bw9bltcu.js.gz +0 -0
- 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-mdnkxjeD.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-mdnkxjeD.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-CEPH_ePM.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-CEPH_ePM.js.gz +0 -0
- 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-BpQUXA60.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-BpQUXA60.js.gz +0 -0
- 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-C2cSRCxu.js.br +0 -0
- package/dist/client/assets/linear-C2cSRCxu.js.gz +0 -0
- 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-D0AFCmsY.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-D0AFCmsY.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-R2qlU2Pq.js +0 -2
- 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-BGAh0bwg.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-BGAh0bwg.js.gz +0 -0
- 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-D_Qn6NTU.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-D_Qn6NTU.js.gz +0 -0
- 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-hgCM4i-j.js.br +0 -0
- package/dist/client/assets/rdpSession-hgCM4i-j.js.gz +0 -0
- 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-BBQMQuVZ.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BBQMQuVZ.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CeEExsqW.js.gz +0 -0
- 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-MBjz7Snm.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-MBjz7Snm.js.gz +0 -0
- 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 +0 -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 +0 -8
- 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/vennDiagram-4TSXK5OY-8FcrAdbk.js.gz +0 -0
- 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-paL2wRrJ.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-paL2wRrJ.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BM5qJ4E7.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BM5qJ4E7.js.gz +0 -0
|
@@ -24,12 +24,14 @@ class LogicalSocket extends EventEmitter {
|
|
|
24
24
|
canRead;
|
|
25
25
|
OPEN = 1;
|
|
26
26
|
readyState = 1;
|
|
27
|
-
bufferedAmount
|
|
28
|
-
|
|
27
|
+
get bufferedAmount() { return this.channel.queuedBytesFor(this.id); }
|
|
28
|
+
maxQueuedBytes;
|
|
29
|
+
constructor(channel, id, canRead, maxQueuedBytes = 4 * 1024 * 1024) {
|
|
29
30
|
super();
|
|
30
31
|
this.channel = channel;
|
|
31
32
|
this.id = id;
|
|
32
33
|
this.canRead = canRead;
|
|
34
|
+
this.maxQueuedBytes = maxQueuedBytes;
|
|
33
35
|
}
|
|
34
36
|
send(data) {
|
|
35
37
|
if (this.readyState !== 1)
|
|
@@ -38,12 +40,18 @@ class LogicalSocket extends EventEmitter {
|
|
|
38
40
|
this.close(4003, 'Authorization revoked');
|
|
39
41
|
return;
|
|
40
42
|
}
|
|
43
|
+
// Apply the terminal backlog threshold to bytes already queued, leaving a
|
|
44
|
+
// single protocol-valid record (up to MAX_PACKET) intact. Other logical
|
|
45
|
+
// streams retain the shared channel budget and its own backpressure guard.
|
|
46
|
+
if (this.channel.queuedBytesFor(this.id) > this.maxQueuedBytes) {
|
|
47
|
+
this.close(1013, 'Output consumer is too slow');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
41
50
|
try {
|
|
42
51
|
this.channel.send({ type: 'ws-data', id: this.id, data });
|
|
43
52
|
}
|
|
44
|
-
catch
|
|
45
|
-
this.
|
|
46
|
-
this.close();
|
|
53
|
+
catch {
|
|
54
|
+
this.close(1013, 'Output consumer is too slow');
|
|
47
55
|
}
|
|
48
56
|
}
|
|
49
57
|
close(code = 1000, reason = '') {
|
|
@@ -100,7 +108,9 @@ export async function createFederationRuntime(app, directory, handlers, options
|
|
|
100
108
|
delete request.headers['x-termdock-inner'];
|
|
101
109
|
const subject = request.headers['x-termdock-device'];
|
|
102
110
|
delete request.headers['x-termdock-device'];
|
|
103
|
-
|
|
111
|
+
const fullService = request.headers['x-termdock-full-service'] === '1';
|
|
112
|
+
delete request.headers['x-termdock-full-service'];
|
|
113
|
+
markEncryptedRequest(request, typeof subject === 'string' ? subject : undefined, fullService);
|
|
104
114
|
app(request, response);
|
|
105
115
|
});
|
|
106
116
|
await new Promise((resolve, reject) => { internal.once('error', reject); internal.listen(0, '127.0.0.1', resolve); });
|
|
@@ -177,7 +187,8 @@ export async function createFederationRuntime(app, directory, handlers, options
|
|
|
177
187
|
};
|
|
178
188
|
try {
|
|
179
189
|
httpAllowed(operation.head);
|
|
180
|
-
const headers = new Headers({ 'x-termdock-inner': internalToken, 'x-termdock-device': subjectId
|
|
190
|
+
const headers = new Headers({ 'x-termdock-inner': internalToken, 'x-termdock-device': subjectId,
|
|
191
|
+
'x-termdock-full-service': full(subjectId) ? '1' : '0' });
|
|
181
192
|
const supplied = operation.head.headers;
|
|
182
193
|
if (supplied && typeof supplied === 'object')
|
|
183
194
|
for (const [name, value] of Object.entries(supplied)) {
|
|
@@ -580,7 +591,7 @@ export async function createFederationRuntime(app, directory, handlers, options
|
|
|
580
591
|
}
|
|
581
592
|
else
|
|
582
593
|
throw new Error('API_NOT_ALLOWED');
|
|
583
|
-
const logical = new LogicalSocket(channel, packet.id, () => (androidMatch || computer) ? full(subjectId) : allowed(subjectId, match ? 'session.view' : 'service.view', match?.[1]));
|
|
594
|
+
const logical = new LogicalSocket(channel, packet.id, () => (androidMatch || computer) ? full(subjectId) : allowed(subjectId, match ? 'session.view' : 'service.view', match?.[1]), match ? 1024 * 1024 : undefined);
|
|
584
595
|
sockets.set(packet.id, { socket: logical, sessionId: match?.[1], android: Boolean(androidMatch), computer,
|
|
585
596
|
computerProtocol: computer ? url.searchParams.get('protocol') ?? 'vnc' : undefined });
|
|
586
597
|
logical.once('close', () => sockets.delete(packet.id));
|
|
@@ -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';
|
|
@@ -2522,10 +2525,10 @@ function getTmuxBinary() {
|
|
|
2522
2525
|
}
|
|
2523
2526
|
return 'tmux'; // fallback to PATH
|
|
2524
2527
|
}
|
|
2525
|
-
async function runTmux(args) {
|
|
2528
|
+
async function runTmux(args, options) {
|
|
2526
2529
|
const { stdout } = await execFileAsync(getTmuxBinary(), args, {
|
|
2527
2530
|
timeout: 5000,
|
|
2528
|
-
maxBuffer: 2 * 1024 * 1024,
|
|
2531
|
+
maxBuffer: options?.maxBuffer ?? 2 * 1024 * 1024,
|
|
2529
2532
|
env: buildInteractiveColorEnvironment(process.env),
|
|
2530
2533
|
});
|
|
2531
2534
|
return stdout;
|
|
@@ -4684,19 +4687,26 @@ async function resolveTmuxClientTty(sessionName, preferredClientPid) {
|
|
|
4684
4687
|
}
|
|
4685
4688
|
async function ensureTmuxSessionExists(sessionName, cwd) {
|
|
4686
4689
|
let serverWasMissing = false;
|
|
4690
|
+
let serverIsEmpty = false;
|
|
4691
|
+
let sessionExists = false;
|
|
4687
4692
|
try {
|
|
4688
4693
|
await runTmux(['has-session', '-t', sessionName]);
|
|
4689
|
-
|
|
4690
|
-
return;
|
|
4694
|
+
sessionExists = true;
|
|
4691
4695
|
}
|
|
4692
4696
|
catch (error) {
|
|
4693
4697
|
const errorMessage = getErrorMessage(error);
|
|
4694
4698
|
serverWasMissing = isTmuxServerMissingMessage(errorMessage);
|
|
4695
4699
|
if (!isTmuxSessionMissingMessage(errorMessage)) {
|
|
4696
|
-
|
|
4700
|
+
serverIsEmpty = await isConfirmedEmptyTmuxServer(error, sessionName, runTmux);
|
|
4701
|
+
if (!serverIsEmpty)
|
|
4702
|
+
throw error;
|
|
4697
4703
|
}
|
|
4698
4704
|
}
|
|
4699
|
-
if (
|
|
4705
|
+
if (sessionExists) {
|
|
4706
|
+
await ensureTmuxColorEnvironment(sessionName);
|
|
4707
|
+
return;
|
|
4708
|
+
}
|
|
4709
|
+
if (!serverWasMissing && !serverIsEmpty) {
|
|
4700
4710
|
await ensureTmuxColorEnvironment();
|
|
4701
4711
|
}
|
|
4702
4712
|
const innerTerm = await resolveTmuxInnerTerm();
|
|
@@ -8306,7 +8316,10 @@ router.post('/:sessionId/input', express.text({ type: '*/*' }), (req, res) => {
|
|
|
8306
8316
|
}
|
|
8307
8317
|
const data = typeof req.body === 'string' ? req.body : '';
|
|
8308
8318
|
try {
|
|
8309
|
-
|
|
8319
|
+
const paste = new TerminalPasteBuffer(() => { });
|
|
8320
|
+
const parts = paste.complete(data);
|
|
8321
|
+
for (const part of parts)
|
|
8322
|
+
session.ptyProcess.write(part);
|
|
8310
8323
|
session.lastActivity = Date.now();
|
|
8311
8324
|
res.json({ success: true });
|
|
8312
8325
|
}
|
|
@@ -8475,7 +8488,7 @@ router.post('/:sessionId/tmux', async (req, res) => {
|
|
|
8475
8488
|
broadcastEvent(sessionId, { type: 'tmux-layout', layout });
|
|
8476
8489
|
return res.json({ success: true, layout });
|
|
8477
8490
|
}
|
|
8478
|
-
return res.json({ success: true });
|
|
8491
|
+
return res.json({ success: true, ...(result.selection ? { selection: result.selection } : {}) });
|
|
8479
8492
|
}
|
|
8480
8493
|
catch (error) {
|
|
8481
8494
|
const errorMessage = getErrorMessage(error);
|
|
@@ -8570,6 +8583,10 @@ router.post('/force-kill', (req, res) => {
|
|
|
8570
8583
|
async function executeTmuxAction(tmuxTarget, action, body, control) {
|
|
8571
8584
|
let shouldBroadcastLayout = true;
|
|
8572
8585
|
switch (action) {
|
|
8586
|
+
case 'copy-selection': {
|
|
8587
|
+
const selection = await copyTmuxSelection(tmuxTarget, runTmux);
|
|
8588
|
+
return { shouldBroadcastLayout: false, selection };
|
|
8589
|
+
}
|
|
8573
8590
|
case 'select-pane': {
|
|
8574
8591
|
const paneId = typeof body.paneId === 'string' ? body.paneId : '';
|
|
8575
8592
|
if (!paneId)
|
|
@@ -8960,6 +8977,12 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
|
|
|
8960
8977
|
if (ws.readyState === ws.OPEN)
|
|
8961
8978
|
ws.send(JSON.stringify(event));
|
|
8962
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
|
+
});
|
|
8963
8986
|
// Handle client → server messages
|
|
8964
8987
|
ws.on('message', async (raw) => {
|
|
8965
8988
|
const messageReceivedAt = performance.now();
|
|
@@ -8974,20 +8997,30 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
|
|
|
8974
8997
|
switch (msg.type) {
|
|
8975
8998
|
case 'input': {
|
|
8976
8999
|
if (typeof msg.data === 'string' && msg.data.length > 0) {
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
9000
|
+
let parts;
|
|
9001
|
+
try {
|
|
9002
|
+
parts = pasteInput.push(msg.data);
|
|
9003
|
+
}
|
|
9004
|
+
catch (error) {
|
|
9005
|
+
ws.send(JSON.stringify({ type: 'error', error: getErrorMessage(error) }));
|
|
9006
|
+
ws.close(1008, 'Invalid terminal paste');
|
|
9007
|
+
return;
|
|
8981
9008
|
}
|
|
8982
|
-
|
|
8983
|
-
|
|
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 {
|
|
8984
9021
|
session.lastActivity = Date.now();
|
|
8985
9022
|
session.ptyProcess.write(data);
|
|
8986
|
-
}
|
|
8987
|
-
}
|
|
8988
|
-
else {
|
|
8989
|
-
session.lastActivity = Date.now();
|
|
8990
|
-
session.ptyProcess.write(data);
|
|
9023
|
+
}
|
|
8991
9024
|
}
|
|
8992
9025
|
}
|
|
8993
9026
|
break;
|
|
@@ -9055,8 +9088,14 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
|
|
|
9055
9088
|
}
|
|
9056
9089
|
const result = await enqueueTmuxIo(session, async () => {
|
|
9057
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' };
|
|
9058
9097
|
});
|
|
9059
|
-
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 } : {}) }));
|
|
9060
9099
|
if (result.shouldBroadcastLayout && session.tmuxSessionName) {
|
|
9061
9100
|
try {
|
|
9062
9101
|
const layout = await getTmuxLayout(session.tmuxSessionName);
|
|
@@ -9154,6 +9193,7 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
|
|
|
9154
9193
|
});
|
|
9155
9194
|
// Cleanup on close
|
|
9156
9195
|
ws.on('close', () => {
|
|
9196
|
+
pasteInput.clear();
|
|
9157
9197
|
initialScreen?.cancel();
|
|
9158
9198
|
initialScreen = null;
|
|
9159
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
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const START = '\x1b[200~';
|
|
2
|
+
const END = '\x1b[201~';
|
|
3
|
+
const MAX_BYTES = 1024 * 1024;
|
|
4
|
+
const TIMEOUT_MS = 10_000;
|
|
5
|
+
const INCOMPLETE = '粘贴内容未完整送达,已取消,请重新粘贴。';
|
|
6
|
+
/** A socket owns its pending paste. Never expose its opening delimiter to the
|
|
7
|
+
* PTY until the closing delimiter has arrived, even across input records.
|
|
8
|
+
* Ordinary keyboard/mouse records remain synchronous and unbuffered. */
|
|
9
|
+
export class TerminalPasteBuffer {
|
|
10
|
+
onTimeout;
|
|
11
|
+
pending = '';
|
|
12
|
+
startedAt = 0;
|
|
13
|
+
timer;
|
|
14
|
+
constructor(onTimeout) {
|
|
15
|
+
this.onTimeout = onTimeout;
|
|
16
|
+
}
|
|
17
|
+
push(data) {
|
|
18
|
+
const previousStart = this.startedAt;
|
|
19
|
+
const continuing = this.pending.length > 0;
|
|
20
|
+
const input = this.pending + data;
|
|
21
|
+
const output = [];
|
|
22
|
+
this.clear();
|
|
23
|
+
let offset = 0;
|
|
24
|
+
while (offset < input.length) {
|
|
25
|
+
const start = input.indexOf(START, offset);
|
|
26
|
+
if (start < 0) {
|
|
27
|
+
output.push(input.slice(offset));
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
if (start > offset)
|
|
31
|
+
output.push(input.slice(offset, start));
|
|
32
|
+
const end = input.indexOf(END, start + START.length);
|
|
33
|
+
const nested = input.indexOf(START, start + START.length);
|
|
34
|
+
if (nested >= 0 && (end < 0 || nested < end))
|
|
35
|
+
throw new Error(INCOMPLETE);
|
|
36
|
+
const paste = input.slice(start, end < 0 ? undefined : end + END.length);
|
|
37
|
+
if (Buffer.byteLength(paste) > MAX_BYTES)
|
|
38
|
+
throw new Error('粘贴内容超过 1 MiB,请分段粘贴。');
|
|
39
|
+
if (end < 0) {
|
|
40
|
+
this.pending = paste;
|
|
41
|
+
this.startedAt = continuing && start === 0 ? previousStart : Date.now();
|
|
42
|
+
this.timer = setTimeout(() => { this.clear(); this.onTimeout(INCOMPLETE); }, Math.max(0, this.startedAt + TIMEOUT_MS - Date.now()));
|
|
43
|
+
this.timer.unref();
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
output.push(paste);
|
|
47
|
+
offset = end + END.length;
|
|
48
|
+
}
|
|
49
|
+
return output;
|
|
50
|
+
}
|
|
51
|
+
/** HTTP input has no continuation stream. Reject its entire body on failure. */
|
|
52
|
+
complete(data) {
|
|
53
|
+
const output = this.push(data);
|
|
54
|
+
if (this.pending) {
|
|
55
|
+
this.clear();
|
|
56
|
+
throw new Error(INCOMPLETE);
|
|
57
|
+
}
|
|
58
|
+
return output;
|
|
59
|
+
}
|
|
60
|
+
clear() {
|
|
61
|
+
clearTimeout(this.timer);
|
|
62
|
+
this.timer = undefined;
|
|
63
|
+
this.pending = '';
|
|
64
|
+
this.startedAt = 0;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -15,6 +15,10 @@ export async function supportsTmuxClientFeatures(binary) {
|
|
|
15
15
|
}
|
|
16
16
|
export function buildTmuxAttachArgs(sessionName, supportsFeatures) {
|
|
17
17
|
return [
|
|
18
|
+
// The Web/native terminal consumes UTF-8 regardless of the server launcher's
|
|
19
|
+
// locale. GUI-launched services may inherit C; tmux otherwise emits _ for
|
|
20
|
+
// non-ASCII cells before the encrypted output ever reaches the renderer.
|
|
21
|
+
'-u',
|
|
18
22
|
...(supportsFeatures ? ['-T', 'RGB,sync'] : []),
|
|
19
23
|
'attach-session', '-t', sessionName,
|
|
20
24
|
];
|