termdock 1.4.322 → 1.4.325
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-D8MWr9xp.js +186 -0
- package/dist/client/assets/App-D8MWr9xp.js.br +0 -0
- package/dist/client/assets/App-D8MWr9xp.js.gz +0 -0
- package/dist/client/assets/{ArchitecturePanel-VDM6hrwp.js → ArchitecturePanel-CJXvqmtu.js} +2 -2
- package/dist/client/assets/ArchitecturePanel-CJXvqmtu.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-CJXvqmtu.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-B64j3i8o.js → ChangeWalkthroughPanel-ChPZVfRz.js} +1 -1
- package/dist/client/assets/ChangeWalkthroughPanel-ChPZVfRz.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-ChPZVfRz.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-DkNhqCj4.js +1 -0
- package/dist/client/assets/CollaborationMainWorkspace-DkNhqCj4.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-DkNhqCj4.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-BA3bVNJo.js +2 -0
- package/dist/client/assets/{ComputerControlView-Co-TTYas.js → ComputerControlView-BTntDI6C.js} +2 -2
- package/dist/client/assets/ComputerControlView-BTntDI6C.js.br +0 -0
- package/dist/client/assets/ComputerControlView-BTntDI6C.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-kJczdJ6J.js → DagPlayground-BIL5vjer.js} +1 -1
- package/dist/client/assets/DagPlayground-BIL5vjer.js.br +0 -0
- package/dist/client/assets/DagPlayground-BIL5vjer.js.gz +0 -0
- package/dist/client/assets/{DiffLab-BaaioC-q.js → DiffLab-CX1AwU2v.js} +1 -1
- package/dist/client/assets/DiffLab-CX1AwU2v.js.br +0 -0
- package/dist/client/assets/DiffLab-CX1AwU2v.js.gz +0 -0
- package/dist/client/assets/{DiffReview-Wfck3RIS.js → DiffReview-CLc1hwO7.js} +1 -1
- package/dist/client/assets/DiffReview-CLc1hwO7.js.br +0 -0
- package/dist/client/assets/DiffReview-CLc1hwO7.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-Dblr3wgw.js → DiffReviewLab-DE6m1o4p.js} +1 -1
- package/dist/client/assets/DiffReviewLab-DE6m1o4p.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-DE6m1o4p.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-C-utC5Ga.js → DiffViewer-BDwtwbQM.js} +1 -1
- package/dist/client/assets/DiffViewer-BDwtwbQM.js.br +0 -0
- package/dist/client/assets/DiffViewer-BDwtwbQM.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-BBLnHWVQ.js → ModelPreview-DEwATnxi.js} +1 -1
- package/dist/client/assets/ModelPreview-DEwATnxi.js.br +0 -0
- package/dist/client/assets/ModelPreview-DEwATnxi.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-CUHSFkmZ.js → RightSidebar-jOQJePDV.js} +36 -36
- package/dist/client/assets/RightSidebar-jOQJePDV.js.br +0 -0
- package/dist/client/assets/RightSidebar-jOQJePDV.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-DDd99QpA.js → abnfDiagram-VCTEODGH-GBSf8AEr.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-GBSf8AEr.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-GBSf8AEr.js.gz +0 -0
- package/dist/client/assets/app-VCmiASzh.js +35 -0
- package/dist/client/assets/app-VCmiASzh.js.br +0 -0
- package/dist/client/assets/app-VCmiASzh.js.gz +0 -0
- package/dist/client/assets/{arc-C3dck_E0.js → arc-BecvFgjf.js} +1 -1
- package/dist/client/assets/arc-BecvFgjf.js.br +0 -0
- package/dist/client/assets/arc-BecvFgjf.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-C3bCQc2w.js → architectureDiagram-5GKGNRK7-Cfk47zEF.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-Cfk47zEF.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-Cfk47zEF.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-znMn6iCQ.js → blockDiagram-I7D4REHJ-BHYgsLvx.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-BHYgsLvx.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-BHYgsLvx.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-C0sopIsj.js → c4Diagram-7LVT6UL2-ClWWjTyz.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-ClWWjTyz.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-ClWWjTyz.js.gz +0 -0
- package/dist/client/assets/channel-8F8qxLSK.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-f7USyccJ.js → chunk-2Q5K7J3B-Cat1Dsqx.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-Ck2xirDs.js → chunk-5VM5RSS4-CT0S2-E8.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-DaDCIj30.js → chunk-F27PBJKO-7o5_yA1b.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-7o5_yA1b.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-7o5_yA1b.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-DEC_On5x.js → chunk-IMKFNOWR-iAZxGMup.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-iAZxGMup.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-iAZxGMup.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-BrswC3n2.js → chunk-JWPE2WC7-DLvwOWZm.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-ClMbDV47.js → chunk-POPQ4Y6H-BpiRuG56.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-D7_1VwC5.js → chunk-SVP7TREG-DpB7xpqI.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-DpB7xpqI.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-DpB7xpqI.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-D5jzVTZ8.js → chunk-TICWLB2K-Z_Sti6yX.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-Z_Sti6yX.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-Z_Sti6yX.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-DOhaoLcX.js → chunk-XXDRQBXY-DKngx1rf.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-C0AmKz7U.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-C0AmKz7U.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-DOsaKgiX.js → cose-bilkent-JH36ORCC-CDo8eUXo.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-CDo8eUXo.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-CDo8eUXo.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-CMcLh_wh.js → cynefin-OW5HDTMX-R6vltrl4.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-R6vltrl4.js.br +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-CMcLh_wh.js.gz → cynefin-OW5HDTMX-R6vltrl4.js.gz} +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-Dd8bfq9V.js → cynefinDiagram-5FMLGOSQ-BTGMG-zO.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BTGMG-zO.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BTGMG-zO.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-BlW7fAi0.js → dagre-GXQ25YYZ-D67dNSHU.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-D67dNSHU.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-D67dNSHU.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-B0-tKahG.js → diagram-S7CK7UJ4-CxZmcHs4.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-CxZmcHs4.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-CxZmcHs4.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-BQumj4Dw.js → diagram-UQ7AKVKN-BErivsDz.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-BErivsDz.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-BErivsDz.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-Zx_FLmPP.js → diagram-VSXAHHWV-BQWEvK9d.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-BQWEvK9d.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-BQWEvK9d.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-CEZvatNH.js → diagram-VX7I27RA-COR5k4JL.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-COR5k4JL.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-COR5k4JL.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-CJ9IEQ8j.js → diagram-Z3DM3KII-Cx6oTlVi.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-Cx6oTlVi.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-Cx6oTlVi.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-sQQMv3ea.js → ebnfDiagram-PWID7BFC-dKNZki9k.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-dKNZki9k.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-dKNZki9k.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-D3rMpj7M.js → erDiagram-RLTQ6QDP-DD06d9Gl.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-DD06d9Gl.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DD06d9Gl.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-B6QZiE0-.js → flowDiagram-HODETNUW-DXNAvw1d.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-DXNAvw1d.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-DXNAvw1d.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-Bw9bltcu.js → ganttDiagram-EL5Y4UJY-BSMu3Rsd.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-BSMu3Rsd.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-BSMu3Rsd.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-Cczz34oI.js → gestureArbiter-D1TteC76.js} +1 -1
- package/dist/client/assets/gestureArbiter-D1TteC76.js.br +0 -0
- package/dist/client/assets/gestureArbiter-D1TteC76.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-mdnkxjeD.js → gitGraphDiagram-WWUBYQGX-DNDKI803.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DNDKI803.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DNDKI803.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-BRmB1D5B.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-CEPH_ePM.js → ishikawaDiagram-5VMMS53U-DXU4nnZ6.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DXU4nnZ6.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-DXU4nnZ6.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-CQ0PjBy7.js → journeyDiagram-3NMN7TZE-DFx7AfiP.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DFx7AfiP.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DFx7AfiP.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-BpQUXA60.js → kanban-definition-UXKFOSKX-B1ikfXJe.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-B1ikfXJe.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-B1ikfXJe.js.gz +0 -0
- package/dist/client/assets/{layout-BdptC7rq.js → layout-DkyvZr1Y.js} +1 -1
- package/dist/client/assets/layout-DkyvZr1Y.js.br +0 -0
- package/dist/client/assets/layout-DkyvZr1Y.js.gz +0 -0
- package/dist/client/assets/{linear-C2cSRCxu.js → linear-CECAbRuX.js} +1 -1
- package/dist/client/assets/linear-CECAbRuX.js.br +0 -0
- package/dist/client/assets/linear-CECAbRuX.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-ClVMFyAU.js → mermaid.core-CYY7Wb75.js} +5 -5
- package/dist/client/assets/mermaid.core-CYY7Wb75.js.br +0 -0
- package/dist/client/assets/mermaid.core-CYY7Wb75.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-D0AFCmsY.js → mindmap-definition-YA3MSWOX-CTs-Y3Lq.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-CTs-Y3Lq.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-CTs-Y3Lq.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-R2qlU2Pq.js → passwordBootstrap-CPNGDwv6.js} +1 -1
- package/dist/client/assets/passwordBootstrap-CPNGDwv6.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-CPNGDwv6.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-BGAh0bwg.js → pegDiagram-XKGWAZYB-Y1oZrwtK.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-Y1oZrwtK.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-Y1oZrwtK.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-CDOZUF44.js → pieDiagram-E7YTZNPT-DYSm5OxQ.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-DYSm5OxQ.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DYSm5OxQ.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-D_Qn6NTU.js → quadrantDiagram-AXDQQJYC-DpibIBz0.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DpibIBz0.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DpibIBz0.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-qUVGWhJN.js → railroadDiagram-O6MQD6OU-b7jp7C1K.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-b7jp7C1K.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-b7jp7C1K.js.gz +0 -0
- package/dist/client/assets/{rdpSession-hgCM4i-j.js → rdpSession-DU_OJfX5.js} +1 -1
- package/dist/client/assets/rdpSession-DU_OJfX5.js.br +0 -0
- package/dist/client/assets/rdpSession-DU_OJfX5.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-BEMsP11a.js → referenceLongPress-BPQ_i68g.js} +1 -1
- package/dist/client/assets/referenceLongPress-BPQ_i68g.js.br +0 -0
- package/dist/client/assets/referenceLongPress-BPQ_i68g.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-BBQMQuVZ.js → requirementDiagram-BXWQKSXE-BMinO1mf.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BMinO1mf.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BMinO1mf.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-CeEExsqW.js → sankeyDiagram-P5KCCOFB-CmC977VA.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CmC977VA.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CmC977VA.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-7ZPO-X0a.js → sequenceDiagram-WJ2MYXX4-D6eGbgK8.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D6eGbgK8.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D6eGbgK8.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-MBjz7Snm.js → sizeCapture-INFHLROL-CnRvyBd8.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-CnRvyBd8.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CnRvyBd8.js.gz +0 -0
- package/dist/client/assets/{sparkles-C9ShmGPf.js → sparkles-DzadqrlX.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-DtLp89uP.js → stateDiagram-D77RDMKH-DRSalH10.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-DRSalH10.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DRSalH10.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DKe8v_ic.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-Bc02S1q-.js → swimlanes-42K2YHIH-u-NnDSzq.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-u-NnDSzq.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-u-NnDSzq.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-ei5b8ZYx.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-BLLwbOm5.js → timeline-definition-24CTP7MA-DkLijg_J.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-DkLijg_J.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-DkLijg_J.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-i_L8ws6U.js → triangle-alert-D_6xTTiX.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-8FcrAdbk.js → vennDiagram-4TSXK5OY-AWGJtiv3.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-8FcrAdbk.js.br → vennDiagram-4TSXK5OY-AWGJtiv3.js.br} +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-AWGJtiv3.js.gz +0 -0
- package/dist/client/assets/{videoCompression-RIaDabW4.js → videoCompression-D3y7Bq8J.js} +1 -1
- package/dist/client/assets/videoCompression-D3y7Bq8J.js.br +0 -0
- package/dist/client/assets/videoCompression-D3y7Bq8J.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-paL2wRrJ.js → wardleyDiagram-VM6X3IG4-DI0aZr_y.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-DI0aZr_y.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-DI0aZr_y.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-BM5qJ4E7.js → xychartDiagram-S5SC5T6Z-CCoIN3uU.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-CCoIN3uU.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-CCoIN3uU.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 +145 -3
- 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 +285 -85
- package/dist/server/utils/autoUpdate.js +55 -8
- package/dist/server/utils/hostResources.js +128 -0
- 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/dist/server/utils/tmuxRecoveryOperations.js +348 -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/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.br +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.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.br +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
|
@@ -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 {
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { execFile } from 'node:child_process';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
import { detectAgentFromCommand } from '../agent/registry.js';
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
function parseMemAvailable(contents) {
|
|
8
|
+
const match = contents.match(/^MemAvailable:\s+(\d+)\s+kB$/m);
|
|
9
|
+
return match ? Number(match[1]) * 1024 : null;
|
|
10
|
+
}
|
|
11
|
+
function parsePressure(contents) {
|
|
12
|
+
const parse = (kind) => {
|
|
13
|
+
const line = contents.split('\n').find(item => item.startsWith(`${kind} `));
|
|
14
|
+
const value = line?.match(/\bavg10=([\d.]+)/)?.[1];
|
|
15
|
+
return value === undefined ? null : Number(value);
|
|
16
|
+
};
|
|
17
|
+
const someAvg10 = parse('some');
|
|
18
|
+
const fullAvg10 = parse('full');
|
|
19
|
+
return someAvg10 === null && fullAvg10 === null ? null : { someAvg10, fullAvg10 };
|
|
20
|
+
}
|
|
21
|
+
function parseProcesses(contents, customCommands = {}) {
|
|
22
|
+
return contents.split('\n').flatMap(line => {
|
|
23
|
+
const match = line.trim().match(/^(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(.*)$/);
|
|
24
|
+
if (!match)
|
|
25
|
+
return [];
|
|
26
|
+
const [, pidRaw, pgidRaw, state, ttyRaw, rssRaw, commandRaw] = match;
|
|
27
|
+
const pid = Number(pidRaw), processGroupId = Number(pgidRaw), rssKb = Number(rssRaw);
|
|
28
|
+
if (!Number.isSafeInteger(pid) || pid <= 0 || !Number.isSafeInteger(processGroupId) || processGroupId <= 0 || !Number.isFinite(rssKb))
|
|
29
|
+
return [];
|
|
30
|
+
const command = commandRaw ?? '';
|
|
31
|
+
const comm = (command.split(/\s+/, 1)[0] ?? '').toLowerCase().split('/').at(-1) ?? '';
|
|
32
|
+
return [{
|
|
33
|
+
pid, processGroupId, state: state ?? '?', tty: ttyRaw === '?' ? '' : ttyRaw, command,
|
|
34
|
+
rssBytes: Math.max(0, rssKb) * 1024,
|
|
35
|
+
agent: Boolean(detectAgentFromCommand(command, customCommands)),
|
|
36
|
+
browser: /^(chrome|chromium|firefox|webkit|agent-browser)(-|$)/.test(comm),
|
|
37
|
+
kswapd: /^\[?kswapd\d*\]?$/.test(comm),
|
|
38
|
+
}];
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export async function collectHostResourceSnapshot(customCommands = {}) {
|
|
42
|
+
let memoryAvailableBytes = os.freemem();
|
|
43
|
+
let memorySnapshotAvailable = false;
|
|
44
|
+
let memoryPressure = null;
|
|
45
|
+
if (process.platform === 'linux') {
|
|
46
|
+
const [meminfo, pressure] = await Promise.all([
|
|
47
|
+
fs.readFile('/proc/meminfo', 'utf8').catch(() => ''),
|
|
48
|
+
fs.readFile('/proc/pressure/memory', 'utf8').catch(() => ''),
|
|
49
|
+
]);
|
|
50
|
+
const parsedAvailable = parseMemAvailable(meminfo);
|
|
51
|
+
if (parsedAvailable !== null) {
|
|
52
|
+
memoryAvailableBytes = parsedAvailable;
|
|
53
|
+
memorySnapshotAvailable = true;
|
|
54
|
+
}
|
|
55
|
+
memoryPressure = parsePressure(pressure);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
memorySnapshotAvailable = Number.isFinite(memoryAvailableBytes);
|
|
59
|
+
}
|
|
60
|
+
let processRows = [];
|
|
61
|
+
let processSnapshotAvailable = false;
|
|
62
|
+
try {
|
|
63
|
+
const { stdout } = await execFileAsync('ps', ['-e', '-o', 'pid=,pgid=,stat=,tty=,rss=,args='], { timeout: 5000, maxBuffer: 8 * 1024 * 1024 });
|
|
64
|
+
processRows = parseProcesses(stdout, customCommands);
|
|
65
|
+
processSnapshotAvailable = processRows.length > 0;
|
|
66
|
+
}
|
|
67
|
+
catch { /* process metrics are diagnostic; memory admission remains fail-closed below */ }
|
|
68
|
+
const groupRss = new Map();
|
|
69
|
+
const agentGroupIds = new Set();
|
|
70
|
+
for (const row of processRows) {
|
|
71
|
+
groupRss.set(row.processGroupId, (groupRss.get(row.processGroupId) ?? 0) + row.rssBytes);
|
|
72
|
+
if (row.agent)
|
|
73
|
+
agentGroupIds.add(row.processGroupId);
|
|
74
|
+
}
|
|
75
|
+
const agentRss = [...agentGroupIds].reduce((sum, id) => sum + (groupRss.get(id) ?? 0), 0);
|
|
76
|
+
return {
|
|
77
|
+
sampledAt: Date.now(), platform: process.platform, memoryAvailableBytes, memoryTotalBytes: os.totalmem(), memoryPressure,
|
|
78
|
+
dStateProcessCount: processRows.filter(row => row.state.includes('D')).length,
|
|
79
|
+
kswapd: processRows.filter(row => row.kswapd).map(({ pid, state }) => ({ pid, state })),
|
|
80
|
+
residentAgentCount: agentGroupIds.size,
|
|
81
|
+
residentAgentRssBytes: agentRss,
|
|
82
|
+
browserProcessCount: processRows.filter(row => row.browser).length,
|
|
83
|
+
memorySnapshotAvailable,
|
|
84
|
+
processSnapshotAvailable,
|
|
85
|
+
processRows,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function configuredAgentResourceBudget(env = process.env) {
|
|
89
|
+
const readMb = (key, fallback, min, max) => {
|
|
90
|
+
const raw = env[key];
|
|
91
|
+
if (raw === undefined || raw.trim() === '')
|
|
92
|
+
return fallback * 1024 ** 2;
|
|
93
|
+
const value = Number(raw);
|
|
94
|
+
if (!Number.isInteger(value) || value < min || value > max)
|
|
95
|
+
throw new Error(`${key} must be an integer from ${min} to ${max} MiB`);
|
|
96
|
+
return value * 1024 ** 2;
|
|
97
|
+
};
|
|
98
|
+
const readCount = (key, fallback, max) => {
|
|
99
|
+
const raw = env[key];
|
|
100
|
+
if (raw === undefined || raw.trim() === '')
|
|
101
|
+
return fallback;
|
|
102
|
+
const value = Number(raw);
|
|
103
|
+
if (!Number.isInteger(value) || value < 1 || value > max)
|
|
104
|
+
throw new Error(`${key} must be an integer from 1 to ${max}`);
|
|
105
|
+
return value;
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
minAvailableBytes: readMb('TD_AGENT_MIN_AVAILABLE_MB', 2048, 256, 131072),
|
|
109
|
+
estimatedRssBytes: readMb('TD_AGENT_ESTIMATED_RSS_MB', 512, 64, 32768),
|
|
110
|
+
maxResidentAgents: readCount('TD_MAX_RESIDENT_AGENTS', 48, 10000),
|
|
111
|
+
maxAgentsPerGroup: readCount('TD_MAX_AGENTS_PER_GROUP', 32, 1000),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export function assessAgentResourceBudget(input) {
|
|
115
|
+
if (input.snapshot.memorySnapshotAvailable === false || input.snapshot.processSnapshotAvailable === false)
|
|
116
|
+
return { admitted: false, reason: 'RESOURCE_SNAPSHOT_UNAVAILABLE' };
|
|
117
|
+
const required = input.budget.minAvailableBytes + input.budget.estimatedRssBytes;
|
|
118
|
+
if (input.snapshot.memoryAvailableBytes < required)
|
|
119
|
+
return { admitted: false, reason: 'MEMORY_BUDGET_LOW' };
|
|
120
|
+
if (input.snapshot.residentAgentCount >= input.budget.maxResidentAgents)
|
|
121
|
+
return { admitted: false, reason: 'MAX_RESIDENT_AGENTS' };
|
|
122
|
+
if (input.residentAgentsInGroup >= input.budget.maxAgentsPerGroup)
|
|
123
|
+
return { admitted: false, reason: 'MAX_GROUP_AGENTS' };
|
|
124
|
+
return { admitted: true };
|
|
125
|
+
}
|
|
126
|
+
export function parseHostResourcesForTest(contents) {
|
|
127
|
+
return { memAvailableBytes: parseMemAvailable(contents.meminfo), pressure: parsePressure(contents.pressure), processes: parseProcesses(contents.ps) };
|
|
128
|
+
}
|
|
@@ -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
|
];
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
export const TMUX_COPY_MAX_BYTES = 256 * 1024;
|
|
3
|
+
const FORMAT = '#{session_id}\t#{pane_id}\t#{pane_in_mode}\t#{selection_present}';
|
|
4
|
+
function state(value) {
|
|
5
|
+
const parts = value.replace(/\r?\n$/, '').split('\t');
|
|
6
|
+
if (parts.length !== 4 || !/^\$\d+$/.test(parts[0]) || !/^%\d+$/.test(parts[1]) || !/^[01]$/.test(parts[2]) || !/^[01]?$/.test(parts[3]))
|
|
7
|
+
throw new Error('Tmux selection state was not confirmed');
|
|
8
|
+
return { session: parts[0], pane: parts[1], inMode: parts[2] === '1', selected: parts[3] === '1' };
|
|
9
|
+
}
|
|
10
|
+
/** Read this session's current selection through a unique, self-owned buffer.
|
|
11
|
+
* No global last-buffer read, shell copy command, clipboard write or mode exit. */
|
|
12
|
+
export async function copyTmuxSelection(target, run) {
|
|
13
|
+
if (!target.trim() || /[\0\r\n]/.test(target))
|
|
14
|
+
throw new Error('Invalid tmux selection target');
|
|
15
|
+
const exact = `=${target}:`;
|
|
16
|
+
const read = () => run(['display-message', '-t', exact, '-p', FORMAT], { maxBuffer: 1024 }).then(state);
|
|
17
|
+
const before = await read();
|
|
18
|
+
const empty = () => ({ status: 'empty', paneId: before.pane, text: '', bytes: 0 });
|
|
19
|
+
if (!before.inMode || !before.selected)
|
|
20
|
+
return empty();
|
|
21
|
+
const prefix = `termdock-copy-${randomUUID()}-`;
|
|
22
|
+
const own = new RegExp(`^${prefix}[0-9]+$`);
|
|
23
|
+
const buffers = [];
|
|
24
|
+
let failed = false;
|
|
25
|
+
let primaryError;
|
|
26
|
+
const listArgs = ['list-buffers', '-f', `#{m:${prefix}*,#{buffer_name}}`, '-F', '#{buffer_name}\t#{buffer_size}'];
|
|
27
|
+
try {
|
|
28
|
+
await run(['send-keys', '-t', before.pane, '-X', 'copy-selection-no-clear', prefix], { maxBuffer: 1024 });
|
|
29
|
+
const metadata = await run(listArgs, { maxBuffer: 64 * 1024 });
|
|
30
|
+
for (const line of metadata.split('\n').filter(Boolean)) {
|
|
31
|
+
const [name, count] = line.split('\t');
|
|
32
|
+
if (!own.test(name))
|
|
33
|
+
throw new Error('Tmux returned an unowned selection buffer');
|
|
34
|
+
buffers.push({ name, bytes: Number(count) });
|
|
35
|
+
if (!/^\d+$/.test(count) || !Number.isSafeInteger(Number(count)))
|
|
36
|
+
throw new Error('Invalid owned tmux buffer metadata');
|
|
37
|
+
}
|
|
38
|
+
if (!buffers.length)
|
|
39
|
+
return empty();
|
|
40
|
+
if (buffers.length !== 1)
|
|
41
|
+
throw new Error('Tmux produced ambiguous selection buffers');
|
|
42
|
+
const buffer = buffers[0];
|
|
43
|
+
if (buffer.bytes > TMUX_COPY_MAX_BYTES)
|
|
44
|
+
throw new Error('Tmux selection exceeds the 256 KiB copy limit');
|
|
45
|
+
const text = await run(['save-buffer', '-b', buffer.name, '-'], { maxBuffer: TMUX_COPY_MAX_BYTES + 1 });
|
|
46
|
+
const after = await read();
|
|
47
|
+
if (after.session !== before.session || after.pane !== before.pane || !after.inMode || !after.selected)
|
|
48
|
+
throw new Error('Tmux selection target changed while copying');
|
|
49
|
+
const bytes = Buffer.byteLength(text, 'utf8');
|
|
50
|
+
if (bytes !== buffer.bytes || bytes > TMUX_COPY_MAX_BYTES)
|
|
51
|
+
throw new Error('Tmux selection was not read completely');
|
|
52
|
+
return bytes ? { status: 'copied', paneId: before.pane, text, bytes } : empty();
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
failed = true;
|
|
56
|
+
primaryError = error;
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
// A command may create its buffer before its reply fails. Enumerate only
|
|
61
|
+
// this UUID prefix even after metadata failure and attempt every own delete.
|
|
62
|
+
const names = new Set(buffers.map(buffer => buffer.name));
|
|
63
|
+
const cleanupErrors = [];
|
|
64
|
+
try {
|
|
65
|
+
const remaining = await run(listArgs, { maxBuffer: 64 * 1024 });
|
|
66
|
+
for (const line of remaining.split('\n').filter(Boolean)) {
|
|
67
|
+
const name = line.split('\t')[0];
|
|
68
|
+
if (!own.test(name)) {
|
|
69
|
+
cleanupErrors.push(new Error('Tmux cleanup returned an unowned buffer'));
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
names.add(name);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
cleanupErrors.push(error);
|
|
77
|
+
}
|
|
78
|
+
for (const name of names) {
|
|
79
|
+
try {
|
|
80
|
+
await run(['delete-buffer', '-b', name], { maxBuffer: 1024 });
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
cleanupErrors.push(error);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (cleanupErrors.length) {
|
|
87
|
+
const error = new AggregateError(cleanupErrors, 'Owned tmux copy buffer cleanup failed');
|
|
88
|
+
if (!failed)
|
|
89
|
+
throw error;
|
|
90
|
+
if (primaryError instanceof Error)
|
|
91
|
+
primaryError.cause = error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** A has-session failure is not evidence that tmux itself is unavailable.
|
|
2
|
+
* Confirm this one empty-server case without changing generic error handling. */
|
|
3
|
+
export async function isConfirmedEmptyTmuxServer(error, target, run) {
|
|
4
|
+
if (!target.trim() || !error || typeof error !== 'object')
|
|
5
|
+
return false;
|
|
6
|
+
const value = error;
|
|
7
|
+
if (value.code !== 1 || typeof value.stderr !== 'string' || value.stderr.trim() !== 'no current target')
|
|
8
|
+
return false;
|
|
9
|
+
try {
|
|
10
|
+
return (await run(['list-sessions', '-F', '#{session_id}'])).trim() === '';
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|