termdock 1.4.168 → 1.4.169
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/ChangeWalkthroughPanel-u9y3e-pI.js +2 -0
- package/dist/client/assets/ChangeWalkthroughPanel-u9y3e-pI.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-u9y3e-pI.js.gz +0 -0
- package/dist/client/assets/DagPlayground-BLUwaOMM.js +1 -0
- package/dist/client/assets/DagPlayground-BLUwaOMM.js.br +0 -0
- package/dist/client/assets/DagPlayground-BLUwaOMM.js.gz +0 -0
- package/dist/client/assets/DiffLab-ThgXydJA.js +370 -0
- package/dist/client/assets/DiffLab-ThgXydJA.js.br +0 -0
- package/dist/client/assets/DiffLab-ThgXydJA.js.gz +0 -0
- package/dist/client/assets/DiffReview-DNkXOQ2y.js +1 -0
- package/dist/client/assets/DiffReview-DNkXOQ2y.js.br +0 -0
- package/dist/client/assets/DiffReview-DNkXOQ2y.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CHyV1WMR.js +2 -0
- package/dist/client/assets/DiffReviewLab-CHyV1WMR.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CHyV1WMR.js.gz +0 -0
- package/dist/client/assets/DiffViewer-CxxOpsVz.js +35 -0
- package/dist/client/assets/DiffViewer-CxxOpsVz.js.br +0 -0
- package/dist/client/assets/DiffViewer-CxxOpsVz.js.gz +0 -0
- package/dist/client/assets/DiffViewer-T3uj2-aP.css +1 -0
- package/dist/client/assets/DiffViewer-T3uj2-aP.css.br +0 -0
- package/dist/client/assets/DiffViewer-T3uj2-aP.css.gz +0 -0
- package/dist/client/assets/ModelPreview-DZzx3Tzo.js +4112 -0
- package/dist/client/assets/ModelPreview-DZzx3Tzo.js.br +0 -0
- package/dist/client/assets/ModelPreview-DZzx3Tzo.js.gz +0 -0
- package/dist/client/assets/RightSidebar-Bv8Y6hqx.js +55 -0
- package/dist/client/assets/RightSidebar-Bv8Y6hqx.js.br +0 -0
- package/dist/client/assets/RightSidebar-Bv8Y6hqx.js.gz +0 -0
- package/dist/client/assets/RightSidebar-DW-JEgm2.css +1 -0
- package/dist/client/assets/{abnfDiagram-VRR7QNED-BPFn9m09.js → abnfDiagram-VCTEODGH-DKmZLRlf.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-DKmZLRlf.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-DKmZLRlf.js.gz +0 -0
- package/dist/client/assets/app-tT08GaCs.js +175 -0
- package/dist/client/assets/app-tT08GaCs.js.br +0 -0
- package/dist/client/assets/app-tT08GaCs.js.gz +0 -0
- package/dist/client/assets/arc-CjmHoRed.js +1 -0
- package/dist/client/assets/arc-CjmHoRed.js.br +0 -0
- package/dist/client/assets/arc-CjmHoRed.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-B0EDOwYH.js +36 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-B0EDOwYH.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-B0EDOwYH.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CW-AaouZ.js +129 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CW-AaouZ.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CW-AaouZ.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-aE7hFKfo.js +38 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-aE7hFKfo.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-aE7hFKfo.js.gz +0 -0
- package/dist/client/assets/channel-DhsPQnwY.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-CXqAcWtO.js → chunk-2Q5K7J3B-FAEL5P17.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-B2ewCivF.js → chunk-5VM5RSS4-BQJAvucM.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-DEkt187T.js +1 -0
- package/dist/client/assets/chunk-F27PBJKO-DEkt187T.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-DEkt187T.js.gz +0 -0
- package/dist/client/assets/{chunk-EX3LRPZG-DcpNYccw.js → chunk-IMKFNOWR-BfOJ-x_l.js} +5 -5
- package/dist/client/assets/chunk-IMKFNOWR-BfOJ-x_l.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BfOJ-x_l.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-DJGW22NC.js → chunk-JWPE2WC7-BN6q6jKH.js} +1 -1
- package/dist/client/assets/chunk-POPQ4Y6H-BrhQRNCn.js +1 -0
- package/dist/client/assets/{chunk-MOJQB5TN-CI12TXOM.js → chunk-SVP7TREG-CjZOC5Dj.js} +4 -4
- package/dist/client/assets/chunk-SVP7TREG-CjZOC5Dj.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-CjZOC5Dj.js.gz +0 -0
- package/dist/client/assets/{chunk-V7JOEXUC-D2J88tQk.js → chunk-TICWLB2K-Wshj9ws7.js} +3 -3
- package/dist/client/assets/chunk-TICWLB2K-Wshj9ws7.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-Wshj9ws7.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-DFycwWDp.js → chunk-XXDRQBXY-BPPghuc3.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-2OomHNTG.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-2OomHNTG.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-D8eG4PZe.js → cose-bilkent-JH36ORCC-BjxJYQH8.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-BjxJYQH8.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-BjxJYQH8.js.gz +0 -0
- package/dist/client/assets/{cynefin-VYW2F7L2-B9Z9SAtQ.js → cynefin-OW5HDTMX-QmUTVmd_.js} +38 -38
- package/dist/client/assets/cynefin-OW5HDTMX-QmUTVmd_.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-QmUTVmd_.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBJtWB9m.js +62 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBJtWB9m.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBJtWB9m.js.gz +0 -0
- package/dist/client/assets/cytoscape.esm-D3_iZ_3b.js.br +0 -0
- package/dist/client/assets/cytoscape.esm-D3_iZ_3b.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CJFctjtR.js +4 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CJFctjtR.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CJFctjtR.js.gz +0 -0
- package/dist/client/assets/defaultLocale-CrowFXzY.js.br +0 -0
- package/dist/client/assets/defaultLocale-CrowFXzY.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-e7Jn-RGH.js +30 -0
- package/dist/client/assets/diagram-S7CK7UJ4-e7Jn-RGH.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-e7Jn-RGH.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B1G-uMf2.js +41 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B1G-uMf2.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B1G-uMf2.js.gz +0 -0
- package/dist/client/assets/{diagram-FQU43EPY-BSU4bMc7.js → diagram-VSXAHHWV-cp7u53yF.js} +3 -3
- package/dist/client/assets/diagram-VSXAHHWV-cp7u53yF.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-cp7u53yF.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-DJWrVfMd.js +24 -0
- package/dist/client/assets/diagram-VX7I27RA-DJWrVfMd.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-DJWrVfMd.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-B-IZbqzJ.js +24 -0
- package/dist/client/assets/diagram-Z3DM3KII-B-IZbqzJ.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-B-IZbqzJ.js.gz +0 -0
- package/dist/client/assets/diffWorker-CAzvFFr7.js +27 -0
- package/dist/client/assets/diffWorker-CAzvFFr7.js.br +0 -0
- package/dist/client/assets/diffWorker-CAzvFFr7.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-CCIWWBDH-N_k0E7sQ.js → ebnfDiagram-PWID7BFC-Bt4zDbpn.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bt4zDbpn.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bt4zDbpn.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DUPOkndO.js +99 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DUPOkndO.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DUPOkndO.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CBSvTIxa.js +168 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CBSvTIxa.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CBSvTIxa.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-C7BvkSc8.js +292 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-C7BvkSc8.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-C7BvkSc8.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C4v6Do2L.js +106 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C4v6Do2L.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C4v6Do2L.js.gz +0 -0
- package/dist/client/assets/index-BaBARzax.css +1 -0
- package/dist/client/assets/index-BaBARzax.css.br +0 -0
- package/dist/client/assets/index-BaBARzax.css.gz +0 -0
- package/dist/client/assets/{index-Ca-rq7yX.js → index-UqXCGE5m.js} +4 -4
- package/dist/client/assets/index-UqXCGE5m.js.br +0 -0
- package/dist/client/assets/index-UqXCGE5m.js.gz +0 -0
- package/dist/client/assets/infoDiagram-27XIBGKW-CVQtEdgb.js +2 -0
- package/dist/client/assets/{ishikawaDiagram-FXEZZL3T-Ew07ODU5.js → ishikawaDiagram-5VMMS53U-Cf7tUoyW.js} +5 -5
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-Cf7tUoyW.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-Cf7tUoyW.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-5HDEW3XC-BUjwylu4.js → journeyDiagram-3NMN7TZE-B-9CWrlr.js} +5 -5
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B-9CWrlr.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B-9CWrlr.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-HUTT4EX6-Cjv8zokk.js → kanban-definition-UXKFOSKX-LDN2IZeo.js} +7 -7
- package/dist/client/assets/kanban-definition-UXKFOSKX-LDN2IZeo.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-LDN2IZeo.js.gz +0 -0
- package/dist/client/assets/katex-55ZPZeOF.css.br +0 -0
- package/dist/client/assets/katex-55ZPZeOF.css.gz +0 -0
- package/dist/client/assets/katex-DnlPpQZa.js.br +0 -0
- package/dist/client/assets/katex-DnlPpQZa.js.gz +0 -0
- package/dist/client/assets/katex-HP8lGamR.js.br +0 -0
- package/dist/client/assets/katex-HP8lGamR.js.gz +0 -0
- package/dist/client/assets/layout-DvqSuFgF.js +1 -0
- package/dist/client/assets/layout-DvqSuFgF.js.br +0 -0
- package/dist/client/assets/layout-DvqSuFgF.js.gz +0 -0
- package/dist/client/assets/{linear-C6Z8ZZfN.js → linear-D43LQnis.js} +1 -1
- package/dist/client/assets/linear-D43LQnis.js.br +0 -0
- package/dist/client/assets/linear-D43LQnis.js.gz +0 -0
- package/dist/client/assets/mermaid.core-DiblHLKe.js +308 -0
- package/dist/client/assets/mermaid.core-DiblHLKe.js.br +0 -0
- package/dist/client/assets/mermaid.core-DiblHLKe.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-LN4V7U3C-DACHJUhw.js → mindmap-definition-YA3MSWOX-k3f4uWuu.js} +3 -3
- package/dist/client/assets/mindmap-definition-YA3MSWOX-k3f4uWuu.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-k3f4uWuu.js.gz +0 -0
- package/dist/client/assets/ordinal-Cboi1Yqb.js.br +0 -0
- package/dist/client/assets/ordinal-Cboi1Yqb.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-2B236MQR-C6YRG4Sp.js → pegDiagram-XKGWAZYB-Dj32Fl3j.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-Dj32Fl3j.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-Dj32Fl3j.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DWGSixfl.js +39 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DWGSixfl.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DWGSixfl.js.gz +0 -0
- package/dist/client/assets/purify.es-4eNOHKSq.js +3 -0
- package/dist/client/assets/purify.es-4eNOHKSq.js.br +0 -0
- package/dist/client/assets/purify.es-4eNOHKSq.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-ABIIQ3AL-DugxSPrH.js → quadrantDiagram-AXDQQJYC-BPScfZWR.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BPScfZWR.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BPScfZWR.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CL00HIC2.js +1 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CL00HIC2.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CL00HIC2.js.gz +0 -0
- package/dist/client/assets/react-XDCjal2T.js.br +0 -0
- package/dist/client/assets/react-XDCjal2T.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-TGXJPOKE-BzaF87gc.js → requirementDiagram-BXWQKSXE-CosES4L6.js} +12 -12
- package/dist/client/assets/requirementDiagram-BXWQKSXE-CosES4L6.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-CosES4L6.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CjM8CYFn.js +40 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CjM8CYFn.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CjM8CYFn.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-DBY2YBRQ-B1gfbBUX.js → sequenceDiagram-WJ2MYXX4-3RKv_35o.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-3RKv_35o.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-3RKv_35o.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-X5ZJPWSS-Cx3c55P-.js → sizeCapture-INFHLROL-BrVkA4VD.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-BrVkA4VD.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-BrVkA4VD.js.gz +0 -0
- package/dist/client/assets/sparkles-B3pwUd8-.js +1 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DeWhyAVC.js +1 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DeWhyAVC.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DeWhyAVC.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DvdrGmTm.js +1 -0
- package/dist/client/assets/swimlanes-42K2YHIH-i2m0Wmhn.js +1 -0
- package/dist/client/assets/swimlanes-42K2YHIH-i2m0Wmhn.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-i2m0Wmhn.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DIzij9pB.js +8 -0
- package/dist/client/assets/terminal-C7X98Amf.js.br +0 -0
- package/dist/client/assets/terminal-C7X98Amf.js.gz +0 -0
- package/dist/client/assets/{timeline-definition-FHXFAJF6-Dmjeiy4n.js → timeline-definition-24CTP7MA-BImN0AS_.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-BImN0AS_.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-BImN0AS_.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DVUHKmvC.js +34 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DVUHKmvC.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DVUHKmvC.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-EHGQE667-C0Qt8nhi.js → wardleyDiagram-VM6X3IG4-B9qi-hc7.js} +4 -4
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B9qi-hc7.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B9qi-hc7.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-3jgBcYVl.js +7 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-3jgBcYVl.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-3jgBcYVl.js.gz +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-38-022d7c89c800.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-39-63f8fa5b3eba.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3a-2d8d46cc4dca.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3b-e75aed5d3969.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c-ac2534aae681.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c0-8c49a98e75c4.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c1-971c5e7a86ce.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c2-e5c4893acfb9.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c3-156f2560c871.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c4-49f0d18a7492.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c5-33d81ad28c5c.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c6-5c301879d053.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3d-52c90894de44.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-text-9e8d9df2dd02.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-38-7942d3c93afb.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-39-19989a2be535.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3a-7786ff4a4dd9.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3b-a759fd623d7e.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c-2a1178076740.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c0-6f2c7518f354.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c1-4bf64cae9dd2.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c2-7f26d4c7240b.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c3-fc8e5a85d620.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c4-91819b7977d3.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c5-26933eec54e2.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c6-af186404c8af.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3d-b004d85f5642.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-text-da002b4e56d3.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-38-b3e69191d92f.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-39-c4d8d66882cb.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3a-27609324e8a3.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3b-5e73d85d7506.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c-7e535d65bbdb.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c0-6465060a06a1.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c1-9fd72ccd9350.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c2-ea7dd77de270.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c3-12808f88907a.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c4-14b598e5e739.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c5-3d40530ce6c2.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c6-7020aec0d9e1.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3d-19831897003a.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-text-b7a9c776b048.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-38-a637901140d8.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-39-838726e8eeca.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3a-ec149087d0b9.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3b-db8e5a24d580.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c-2290d2ad4621.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c0-3b9edaf85d65.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c1-5e7fb0696bbc.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c2-cfad2884adf5.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c3-d641de88278b.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c4-3b0227356b3b.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c5-9dc67c4d20b4.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c6-c5b444110c62.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3d-2b19b65bb43a.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-text-d7b9316fdf4f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-4e-46bdca5c323f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-4f-17200dc0dd0d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-50-370e36250c30.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-51-66352f738581.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-52-191f4025d2b5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-53-fb0a637c39bf.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-54-66f2e72c9ca0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-55-54b538fd4fd8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-56-88f45aeb2030.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-57-154d4324f0ce.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-58-1660c86b8a05.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-59-31a4c5afa3aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5a-fa1d1941710e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5b-031a2b2ebeb7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5c-065b634c07b3.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5d-71f6cd3ed180.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5e-f59de7a6e5c5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5f-8cbe737b6011.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-60-22913526da09.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-61-c810c1d1a3a3.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-62-9464d5d87d65.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-63-79564d99f5da.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-64-4b7cff1dae6f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-65-8dd48db5e297.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-66-a808e22a3d14.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-67-ae5f61af3f79.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-68-a46bf47bd9ba.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-69-28210414eafb.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6a-6bfb1f5e4fb7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6b-39be890e04e4.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6c-79a4ff740d98.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6d-2de5a763980e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6e-8e55b339244d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6f-a56caf9fc7fc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-70-d70c6ee8e03c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-71-ac6f5f86dfef.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-72-db3d346ecc61.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-73-e7371bd71f0b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-74-43946d9b2f0b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-75-ea7cf53e31fa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-76-04c7fa4e0ebf.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-77-24d70898f6b8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-78-c6a5d7135296.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-79-7812cb6432aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7a-6e123be5cd36.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7b-a183ddc6890f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7c-0895291ece9c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7d-1d44252384cf.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7e-7be4dc6f056e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7f-0d8e987db151.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-80-c0c154bb8be0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-81-5343baca5ce7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-82-6d89af9614ce.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-83-fa17ef529c5b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-84-287ecb493fad.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-85-fea695c48165.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-86-8bb35373cb82.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-87-f83e9f70a6cc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-88-894cd19292c1.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-89-2903a6eaf546.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8a-3ce275bfcf96.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8b-3aaeb26309a6.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8c-719b6608b746.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8d-a7f1ccd0dfb7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8e-d503ad5c4958.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8f-18c6d04746c8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-90-e9d94d915dfe.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-91-c258b07ec626.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-92-e4833a556b60.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-94-0889f5b84499.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-95-7ef116efe7ee.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-96-afbc0d2cacda.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-97-df3903d86f65.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-98-0f21094931ee.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-99-eb95f4bead58.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9a-764e8b8723ec.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9b-33a540b9196a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9c-60d6040aa049.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9e-4a64c65bf44d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9f-4d84fba11345.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-punctuation-f1b7708e797a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-4e-bb1ec5541ecc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-4f-d6e8daa67360.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-50-63c2ae7f85e8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-51-41b6e0624888.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-52-57de15003b8d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-53-94382657e2bc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-54-177141086f32.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-55-5ec6fae9813a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-56-720aa493b429.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-57-a8884711a286.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-58-42a3e7e1fe9a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-59-887ee4253daa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5a-c45806889e3c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5b-da142b99dca9.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5c-2bb495e5b511.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5d-9da87d6061f2.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5e-e4010764e593.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5f-a9c9021f6e01.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-60-306f229a68e0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-61-6e4546c5f52a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-62-a73e47933059.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-63-e8f49f472799.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-64-37b54957eadc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-65-2742b20127ad.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-66-239656e7fe56.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-67-5dfa72b26c3f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-68-fe3d1fc05aae.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-69-22535dbbd090.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6a-c4117cd520aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6b-895d3349f7de.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6c-56a0c71eb1b4.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6d-9ec807661604.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6e-3b633363cd57.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6f-91a1f1c31b75.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-70-3a904a2a2371.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-71-e8efb60879b0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-72-591318b99498.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-73-d8f444050aa7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-74-55a832a12d7e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-75-660977996a4c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-76-441a04df9fb5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-77-5915143c4398.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-78-242fbc33c745.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-79-24d13953150a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7a-41973af74017.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7b-f9661fdaf003.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7c-ef5167770bf7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7d-d84ad5d95f37.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7e-66841a1c6381.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7f-5090e017351a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-80-9ad74a67c2b9.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-81-423a60a6dcf1.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-82-aad812217807.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-83-3dc74dbac89c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-84-68db7802ffe8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-85-fa235a7160e4.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-86-75a6a33d0db2.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-87-7d98ea8ce063.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-88-363fa8f178aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-89-f2d185e8721f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8a-e372253a07f5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8b-0af53db9bdc1.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8c-6a43d3643480.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8d-09c4b5345b99.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8e-122a752954a6.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8f-c651bbfffeb3.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-90-ab0a5fef3083.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-91-e07b5cbe4792.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-92-cba0a8ee6758.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-94-e7a6bd14e248.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-95-420f721d52ba.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-96-90fd476b83f2.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-97-34036fc287f7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-98-5c3cdd76911e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-99-73e6090fd7c8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9a-673ebaebe683.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9b-90a5a3ee22d6.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9c-116d201c978b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9e-78db36865caa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9f-27e8d16243d5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-punctuation-a4288065ed29.woff2 +0 -0
- package/dist/client/fonts/terminal/manifest.json +1349 -0
- package/dist/client/fonts/terminal/manifest.json.br +0 -0
- package/dist/client/fonts/terminal/manifest.json.gz +0 -0
- package/dist/client/icons/agents/claude.svg.br +0 -0
- package/dist/client/icons/agents/claude.svg.gz +0 -0
- package/dist/client/icons/agents/codex.svg.br +0 -0
- package/dist/client/icons/agents/codex.svg.gz +0 -0
- package/dist/client/icons/agents/copilot.svg.br +0 -0
- package/dist/client/icons/agents/copilot.svg.gz +0 -0
- package/dist/client/icons/agents/droid.svg.br +0 -0
- package/dist/client/icons/agents/droid.svg.gz +0 -0
- package/dist/client/icons/agents/gemini.svg.br +0 -0
- package/dist/client/icons/agents/gemini.svg.gz +0 -0
- package/dist/client/icons/agents/goose.svg.br +0 -0
- package/dist/client/icons/agents/goose.svg.gz +0 -0
- package/dist/client/index.html +7 -52
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/sw-notifications.js.br +0 -0
- package/dist/client/sw-notifications.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/client/workbox-9845bf53.js.br +0 -0
- package/dist/client/workbox-9845bf53.js.gz +0 -0
- package/dist/server/agent/installers.js +47 -27
- package/dist/server/cli.js +4 -4
- package/dist/server/entry.js +57 -145
- package/dist/server/routes/auth.js +9 -3
- package/dist/server/routes/filesystem.js +39 -9
- package/dist/server/routes/local.js +3 -2
- package/dist/server/routes/terminal.js +337 -225
- package/dist/server/utils/apiAccess.js +27 -0
- package/dist/server/utils/apiCachePolicy.js +10 -0
- package/dist/server/utils/authProtection.js +140 -38
- package/dist/server/utils/cookieSecurity.js +3 -2
- package/dist/server/utils/csrfProtection.js +2 -6
- package/dist/server/utils/previewValidation.js +16 -0
- package/dist/server/utils/publicSecurity.js +44 -0
- package/dist/server/utils/requestDeadline.js +2 -0
- package/dist/server/utils/requestSecurity.js +23 -28
- package/dist/server/utils/staticAssets.js +97 -0
- package/dist/server/utils/terminalClientAttachment.js +61 -0
- package/dist/server/utils/terminalHandshakeDimensions.js +9 -0
- package/dist/server/utils/terminalOutputDelivery.js +90 -0
- package/dist/server/utils/tmuxClientRedraw.js +16 -0
- package/dist/server/utils/tmuxInitialScreen.js +50 -0
- package/dist/server/utils/tmuxResizeReady.js +56 -0
- package/dist/server/utils/webSocketSecurity.js +28 -0
- package/package.json +7 -4
- package/runtime-manifest.json +4 -4
- package/scripts/generate-font-subsets.py +88 -0
- package/scripts/precompress-client.mjs +28 -0
- package/dist/client/assets/ModelPreview-BVdIA5hh.js +0 -4108
- package/dist/client/assets/app-uayLhfKS.js +0 -632
- package/dist/client/assets/arc-BrdWVufU.js +0 -1
- package/dist/client/assets/architectureDiagram-ZJ3FMSHR-M74Mohos.js +0 -36
- package/dist/client/assets/blockDiagram-677ZJIJ3-D6OG5gyC.js +0 -132
- package/dist/client/assets/c4Diagram-LMCZKHZV-C2w-_Jc4.js +0 -10
- package/dist/client/assets/channel-B3PaW8my.js +0 -1
- package/dist/client/assets/chunk-32BRIVSS-CEtSQTtD.js +0 -1
- package/dist/client/assets/chunk-RYQCIY6F-DS5ufo5c.js +0 -1
- package/dist/client/assets/chunk-VR4S4FIN-0lqTHFzc.js +0 -1
- package/dist/client/assets/classDiagram-OUVF2IWQ-CLK6o5ur.js +0 -1
- package/dist/client/assets/classDiagram-v2-EOCWNBFH-CLK6o5ur.js +0 -1
- package/dist/client/assets/cynefinDiagram-TSTJHNR4-DLfD0XDP.js +0 -62
- package/dist/client/assets/dagre-VKFMJZFB-BVcVxS_K.js +0 -4
- package/dist/client/assets/diagram-G47NLZAW-U4SDLU5l.js +0 -24
- package/dist/client/assets/diagram-NH7WQ7WH-DzUUOLaX.js +0 -24
- package/dist/client/assets/diagram-OA4YK3LP-CkCRYrYh.js +0 -30
- package/dist/client/assets/diagram-WEI45ONY-D5_8zUCk.js +0 -41
- package/dist/client/assets/diffWorker-Bg2YXCD-.js +0 -27
- package/dist/client/assets/erDiagram-Q63AITRT-CaBjWdJp.js +0 -85
- package/dist/client/assets/flowDiagram-23GEKE2U-CVOqw7CA.js +0 -156
- package/dist/client/assets/ganttDiagram-NO4QXBWP-DI8IFeJE.js +0 -292
- package/dist/client/assets/gitGraphDiagram-IHSO6WYX-CnpSm3yq.js +0 -106
- package/dist/client/assets/graph-D2o_JWn5.js +0 -1
- package/dist/client/assets/index-C13NrW5y.css +0 -1
- package/dist/client/assets/infoDiagram-FWYZ7A6U-C-dKF4KW.js +0 -2
- package/dist/client/assets/layout-1eBIAoSl.js +0 -1
- package/dist/client/assets/map-BdqsVdb3.js +0 -1
- package/dist/client/assets/mermaid.core-B13cUj_d.js +0 -306
- package/dist/client/assets/pieDiagram-ENE6RG2P-7cfuhoAx.js +0 -39
- package/dist/client/assets/purify.es-CC4Brkr_.js +0 -3
- package/dist/client/assets/railroadDiagram-RFXS5EU6-BhRp2Kow.js +0 -1
- package/dist/client/assets/sankeyDiagram-HTMAVEWB-4yvODBzh.js +0 -40
- package/dist/client/assets/stateDiagram-2N3HPSRC-CyZ_X_VK.js +0 -1
- package/dist/client/assets/stateDiagram-v2-6OUMAXLB-9hsqTyV0.js +0 -1
- package/dist/client/assets/swimlanes-5IMT3BWC-BZPAGrt1.js +0 -2
- package/dist/client/assets/swimlanesDiagram-G3AALYLV-DYvi0MbZ.js +0 -8
- package/dist/client/assets/vennDiagram-L72KCM5P-BC2FrHDP.js +0 -34
- package/dist/client/assets/xychartDiagram-FW5EYKEG-cQNpjzG4.js +0 -7
- package/dist/client/registerSW.js +0 -1
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { TerminalClientAttachment } from '../utils/terminalClientAttachment.js';
|
|
2
|
+
import { redrawTmuxClient } from '../utils/tmuxClientRedraw.js';
|
|
3
|
+
import { TmuxInitialScreen } from '../utils/tmuxInitialScreen.js';
|
|
4
|
+
import { TerminalOutputDelivery, resolveTerminalReplayCursor } from '../utils/terminalOutputDelivery.js';
|
|
1
5
|
import express from 'express';
|
|
2
6
|
import fs from 'fs';
|
|
3
7
|
import os from 'os';
|
|
@@ -111,6 +115,10 @@ const TERMDOCK_GUI_DETACHED_AT_OPTION = '@termdock-gui-detached-at';
|
|
|
111
115
|
const TERMDOCK_FRONTEND_SESSION_ID_OPTION = '@termdock-frontend-session-id';
|
|
112
116
|
// WebSocket clients per session (separate from SSE clients).
|
|
113
117
|
const wsClients = new Map();
|
|
118
|
+
const outputDeliveries = new WeakMap();
|
|
119
|
+
const independentTmuxClients = new WeakSet();
|
|
120
|
+
const independentTmuxReplays = new WeakMap();
|
|
121
|
+
const TERMINAL_STREAM_EPOCH = crypto.randomUUID();
|
|
114
122
|
// Sessions where copy-mode -e just auto-exited at the bottom.
|
|
115
123
|
// Prevents immediate re-entry on subsequent scroll-down commands.
|
|
116
124
|
const exitedAtBottom = new Set();
|
|
@@ -780,7 +788,10 @@ function getHistorySince(sessionId, sinceSeq) {
|
|
|
780
788
|
: history.chunks.slice();
|
|
781
789
|
return { chunks, lastSeq, outOfWindow: false };
|
|
782
790
|
}
|
|
783
|
-
if (sinceSeq
|
|
791
|
+
if (sinceSeq > lastSeq) {
|
|
792
|
+
return { chunks: history.chunks.slice(), lastSeq, outOfWindow: true };
|
|
793
|
+
}
|
|
794
|
+
if (sinceSeq === lastSeq) {
|
|
784
795
|
return { chunks: [], lastSeq, outOfWindow: false };
|
|
785
796
|
}
|
|
786
797
|
const oldestSeq = history.chunks.length > 0 ? history.chunks[0].seq : history.nextSeq;
|
|
@@ -2215,89 +2226,6 @@ function enqueueTmuxIo(session, operation) {
|
|
|
2215
2226
|
session.tmuxIoChain = result.then(() => undefined, () => undefined);
|
|
2216
2227
|
return result;
|
|
2217
2228
|
}
|
|
2218
|
-
function markTmuxClientsForScreenSync(sessionId, session) {
|
|
2219
|
-
if (session.mode !== 'tmux')
|
|
2220
|
-
return;
|
|
2221
|
-
const clients = wsClients.get(sessionId);
|
|
2222
|
-
if (!clients || clients.size === 0)
|
|
2223
|
-
return;
|
|
2224
|
-
const pending = session.tmuxScreenSyncClients ?? new Set();
|
|
2225
|
-
for (const clientId of clients.keys())
|
|
2226
|
-
pending.add(clientId);
|
|
2227
|
-
session.tmuxScreenSyncClients = pending;
|
|
2228
|
-
session.tmuxResizeGeneration = (session.tmuxResizeGeneration ?? 0) + 1;
|
|
2229
|
-
}
|
|
2230
|
-
function markTmuxClientForScreenSync(session, clientId) {
|
|
2231
|
-
if (session.mode !== 'tmux')
|
|
2232
|
-
return;
|
|
2233
|
-
const pending = session.tmuxScreenSyncClients ?? new Set();
|
|
2234
|
-
pending.add(clientId);
|
|
2235
|
-
session.tmuxScreenSyncClients = pending;
|
|
2236
|
-
session.tmuxResizeGeneration = (session.tmuxResizeGeneration ?? 0) + 1;
|
|
2237
|
-
}
|
|
2238
|
-
const TMUX_RESIZE_SCREEN_SYNC_DELAY_MS = 180;
|
|
2239
|
-
function clearTmuxScreenSyncTimer(session, clientId) {
|
|
2240
|
-
const timer = session.tmuxScreenSyncTimers?.get(clientId);
|
|
2241
|
-
if (timer)
|
|
2242
|
-
clearTimeout(timer);
|
|
2243
|
-
session.tmuxScreenSyncTimers?.delete(clientId);
|
|
2244
|
-
if (session.tmuxScreenSyncTimers?.size === 0) {
|
|
2245
|
-
session.tmuxScreenSyncTimers = undefined;
|
|
2246
|
-
}
|
|
2247
|
-
}
|
|
2248
|
-
function scheduleTmuxScreenSyncAfterResize(sessionId, session, clientId) {
|
|
2249
|
-
if (session.mode !== 'tmux' || !session.tmuxSessionName)
|
|
2250
|
-
return;
|
|
2251
|
-
clearTmuxScreenSyncTimer(session, clientId);
|
|
2252
|
-
const timers = session.tmuxScreenSyncTimers ?? new Map();
|
|
2253
|
-
const timer = setTimeout(() => {
|
|
2254
|
-
clearTmuxScreenSyncTimer(session, clientId);
|
|
2255
|
-
const ws = wsClients.get(sessionId)?.get(clientId);
|
|
2256
|
-
if (!ws || ws.readyState !== ws.OPEN)
|
|
2257
|
-
return;
|
|
2258
|
-
void enqueueTmuxIo(session, () => syncTmuxScreenBeforeScroll(sessionId, clientId, session, ws));
|
|
2259
|
-
}, TMUX_RESIZE_SCREEN_SYNC_DELAY_MS);
|
|
2260
|
-
timer.unref?.();
|
|
2261
|
-
timers.set(clientId, timer);
|
|
2262
|
-
session.tmuxScreenSyncTimers = timers;
|
|
2263
|
-
}
|
|
2264
|
-
function isTmuxWheelInput(data) {
|
|
2265
|
-
return /^(?:\u001b\[<6[45];\d+;\d+[Mm])+$/.test(data);
|
|
2266
|
-
}
|
|
2267
|
-
async function syncTmuxScreenBeforeScroll(sessionId, clientId, session, ws) {
|
|
2268
|
-
clearTmuxScreenSyncTimer(session, clientId);
|
|
2269
|
-
if (session.mode !== 'tmux'
|
|
2270
|
-
|| !session.tmuxSessionName
|
|
2271
|
-
|| !session.tmuxScreenSyncClients?.has(clientId)) {
|
|
2272
|
-
return;
|
|
2273
|
-
}
|
|
2274
|
-
const generation = session.tmuxResizeGeneration ?? 0;
|
|
2275
|
-
try {
|
|
2276
|
-
// capture-pane itself enters tmux's command queue after the tty resize.
|
|
2277
|
-
// Do not call refresh-client here: that emits another incremental repaint
|
|
2278
|
-
// through node-pty which can arrive after this authoritative snapshot and
|
|
2279
|
-
// be applied twice (for example, duplicate Codex "Working" rows).
|
|
2280
|
-
const snapshot = await captureTmuxPane(session.tmuxSessionName);
|
|
2281
|
-
if (ws.readyState === ws.OPEN) {
|
|
2282
|
-
ws.send(JSON.stringify({
|
|
2283
|
-
type: 'tmux-screen-sync',
|
|
2284
|
-
chunks: buildTmuxScreenSnapshot(snapshot),
|
|
2285
|
-
cols: session.cols,
|
|
2286
|
-
rows: session.rows,
|
|
2287
|
-
generation,
|
|
2288
|
-
}));
|
|
2289
|
-
session.tmuxScreenSyncClients.delete(clientId);
|
|
2290
|
-
if (session.tmuxScreenSyncClients.size === 0) {
|
|
2291
|
-
session.tmuxScreenSyncClients = undefined;
|
|
2292
|
-
}
|
|
2293
|
-
}
|
|
2294
|
-
}
|
|
2295
|
-
catch (error) {
|
|
2296
|
-
// Keep the client marked dirty. Its next wheel event retries the exact
|
|
2297
|
-
// synchronization instead of permanently accepting a partial screen.
|
|
2298
|
-
console.warn(`[tmux-screen-sync] failed session=${sessionId} client=${clientId}: ${getErrorMessage(error)}`);
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
2229
|
async function isTmuxPaneInMode(target, control) {
|
|
2302
2230
|
const paneInModeRaw = (await sendTmuxCommand(target, control, [
|
|
2303
2231
|
'display-message',
|
|
@@ -3576,9 +3504,7 @@ async function resolveTmuxClientTty(sessionName, preferredClientPid) {
|
|
|
3576
3504
|
}
|
|
3577
3505
|
if (preferredClientPid !== null) {
|
|
3578
3506
|
const matched = rows.find(([clientPid]) => clientPid === String(preferredClientPid));
|
|
3579
|
-
|
|
3580
|
-
return matched[1];
|
|
3581
|
-
}
|
|
3507
|
+
return matched?.[1] || null;
|
|
3582
3508
|
}
|
|
3583
3509
|
return rows[0][1] || null;
|
|
3584
3510
|
}
|
|
@@ -4088,10 +4014,6 @@ function cleanupSession(sessionId, options) {
|
|
|
4088
4014
|
}
|
|
4089
4015
|
session.flowPausedClientTimers.clear();
|
|
4090
4016
|
session.flowPausedClients.clear();
|
|
4091
|
-
for (const timer of session.tmuxScreenSyncTimers?.values() ?? []) {
|
|
4092
|
-
clearTimeout(timer);
|
|
4093
|
-
}
|
|
4094
|
-
session.tmuxScreenSyncTimers = undefined;
|
|
4095
4017
|
if (session.ptyPausedForFlowControl) {
|
|
4096
4018
|
applyPtyFlowControl(sessionId, session, false, 'session-cleanup');
|
|
4097
4019
|
}
|
|
@@ -4138,7 +4060,7 @@ function cleanupSession(sessionId, options) {
|
|
|
4138
4060
|
}
|
|
4139
4061
|
}
|
|
4140
4062
|
}
|
|
4141
|
-
function broadcastToWs(sessionId, data, excludeClientId) {
|
|
4063
|
+
function broadcastToWs(sessionId, data, excludeClientId, output, eventType) {
|
|
4142
4064
|
const clients = wsClients.get(sessionId);
|
|
4143
4065
|
const session = terminalSessions.get(sessionId);
|
|
4144
4066
|
if (!clients)
|
|
@@ -4146,8 +4068,20 @@ function broadcastToWs(sessionId, data, excludeClientId) {
|
|
|
4146
4068
|
for (const [clientId, ws] of clients.entries()) {
|
|
4147
4069
|
if (excludeClientId && clientId === excludeClientId)
|
|
4148
4070
|
continue;
|
|
4071
|
+
if (independentTmuxClients.has(ws) && (output || eventType === 'pty-size'))
|
|
4072
|
+
continue;
|
|
4149
4073
|
try {
|
|
4150
|
-
ws.
|
|
4074
|
+
if (ws.readyState !== ws.OPEN)
|
|
4075
|
+
continue;
|
|
4076
|
+
if (ws.bufferedAmount > 1024 * 1024) {
|
|
4077
|
+
ws.close(1013, 'Output transport is congested');
|
|
4078
|
+
continue;
|
|
4079
|
+
}
|
|
4080
|
+
const delivery = outputDeliveries.get(ws);
|
|
4081
|
+
if (output && delivery)
|
|
4082
|
+
delivery.enqueue(output);
|
|
4083
|
+
else
|
|
4084
|
+
ws.send(data);
|
|
4151
4085
|
}
|
|
4152
4086
|
catch {
|
|
4153
4087
|
clients.delete(clientId);
|
|
@@ -4157,7 +4091,8 @@ function broadcastToWs(sessionId, data, excludeClientId) {
|
|
|
4157
4091
|
}
|
|
4158
4092
|
}
|
|
4159
4093
|
function broadcastJsonWs(sessionId, payload, excludeClientId) {
|
|
4160
|
-
|
|
4094
|
+
const output = payload?.type === 'data' ? payload : undefined;
|
|
4095
|
+
broadcastToWs(sessionId, JSON.stringify(payload), excludeClientId, output, payload?.type);
|
|
4161
4096
|
}
|
|
4162
4097
|
// 统一的 pty resize 入口:调用 ptyProcess.resize 改变 pty size 之后,把
|
|
4163
4098
|
// 真实尺寸广播给除发起方之外的所有 ws client。多端场景下,B 端把 pty
|
|
@@ -4183,11 +4118,7 @@ function applyPtyResize(sessionId, session, cols, rows, source, originClientId)
|
|
|
4183
4118
|
session.autoTitleTerminal.resize(cleanCols, cleanRows);
|
|
4184
4119
|
session.lastActivity = Date.now();
|
|
4185
4120
|
if (changed) {
|
|
4186
|
-
markTmuxClientsForScreenSync(sessionId, session);
|
|
4187
4121
|
broadcastJsonWs(sessionId, { type: 'pty-size', cols: cleanCols, rows: cleanRows, source }, originClientId);
|
|
4188
|
-
if (originClientId) {
|
|
4189
|
-
scheduleTmuxScreenSyncAfterResize(sessionId, session, originClientId);
|
|
4190
|
-
}
|
|
4191
4122
|
}
|
|
4192
4123
|
return true;
|
|
4193
4124
|
}
|
|
@@ -4497,7 +4428,9 @@ async function spawnTerminalSession(req, input) {
|
|
|
4497
4428
|
? getTmuxBinary()
|
|
4498
4429
|
: (process.platform === 'win32' ? 'powershell.exe' : resolveShellCandidates()[0]);
|
|
4499
4430
|
const args = mode === 'tmux' && tmuxSessionName
|
|
4500
|
-
|
|
4431
|
+
// xterm supports DEC 2026. Declare it on this attached client so tmux
|
|
4432
|
+
// emits real synchronized-output boundaries around its redraw batches.
|
|
4433
|
+
? ['-T', 'RGB,sync', 'attach-session', '-t', tmuxSessionName]
|
|
4501
4434
|
: (process.platform === 'win32' ? buildPowerShellCwdHookArgs() : []);
|
|
4502
4435
|
const envPath = buildAugmentedPath();
|
|
4503
4436
|
const resolvedEnv = buildInteractiveColorEnvironment({
|
|
@@ -6759,6 +6692,27 @@ router.post('/:sessionId/resize', async (req, res) => {
|
|
|
6759
6692
|
res.status(500).json({ error: errorMessage || 'Failed to resize terminal' });
|
|
6760
6693
|
}
|
|
6761
6694
|
});
|
|
6695
|
+
async function switchTmuxBackendSession(sessionId, session, target) {
|
|
6696
|
+
if (!target)
|
|
6697
|
+
throw new Error('tmuxSessionName is required');
|
|
6698
|
+
const clientTty = await resolveTmuxClientTty(session.tmuxSessionName, getPtyProcessPid(session.ptyProcess));
|
|
6699
|
+
if (!clientTty)
|
|
6700
|
+
throw new Error('No tmux client available for current session');
|
|
6701
|
+
await prepareManagedTmuxSession(target, session.cwd);
|
|
6702
|
+
await sendTmuxCommand(session.tmuxSessionName, session.tmuxControl, ['switch-client', '-c', clientTty, '-t', target]);
|
|
6703
|
+
session.tmuxSessionName = target;
|
|
6704
|
+
session.lastActivity = Date.now();
|
|
6705
|
+
if (updateGlobalBindingForBackendSession(sessionId, {
|
|
6706
|
+
mode: 'tmux', tmuxSessionName: target, cwd: session.cwd, lastActivity: session.lastActivity,
|
|
6707
|
+
}))
|
|
6708
|
+
persistAndBroadcastGlobalState();
|
|
6709
|
+
// Each display must attach to the newly selected task and initialize its
|
|
6710
|
+
// own parser stream; the metadata client's bytes are never a replacement.
|
|
6711
|
+
await Promise.all([...wsClients.get(sessionId)?.values() ?? []].map(ws => independentTmuxReplays.get(ws)?.()));
|
|
6712
|
+
const layout = await getTmuxLayout(target);
|
|
6713
|
+
broadcastEvent(sessionId, { type: 'tmux-layout', layout });
|
|
6714
|
+
return layout;
|
|
6715
|
+
}
|
|
6762
6716
|
router.post('/:sessionId/tmux', async (req, res) => {
|
|
6763
6717
|
const { sessionId } = req.params;
|
|
6764
6718
|
const session = terminalSessions.get(sessionId);
|
|
@@ -6779,25 +6733,7 @@ router.post('/:sessionId/tmux', async (req, res) => {
|
|
|
6779
6733
|
if (!targetSessionName) {
|
|
6780
6734
|
return res.status(400).json({ error: 'tmuxSessionName is required' });
|
|
6781
6735
|
}
|
|
6782
|
-
const
|
|
6783
|
-
const clientTty = await resolveTmuxClientTty(tmuxTarget, preferredClientPid);
|
|
6784
|
-
if (!clientTty) {
|
|
6785
|
-
return res.status(500).json({ error: 'No tmux client available for current session' });
|
|
6786
|
-
}
|
|
6787
|
-
await prepareManagedTmuxSession(targetSessionName, session.cwd);
|
|
6788
|
-
await sendTmuxCommand(tmuxTarget, session.tmuxControl, ['switch-client', '-c', clientTty, '-t', targetSessionName]);
|
|
6789
|
-
session.tmuxSessionName = targetSessionName;
|
|
6790
|
-
session.lastActivity = Date.now();
|
|
6791
|
-
if (updateGlobalBindingForBackendSession(sessionId, {
|
|
6792
|
-
mode: 'tmux',
|
|
6793
|
-
tmuxSessionName: targetSessionName,
|
|
6794
|
-
cwd: session.cwd,
|
|
6795
|
-
lastActivity: session.lastActivity,
|
|
6796
|
-
})) {
|
|
6797
|
-
persistAndBroadcastGlobalState();
|
|
6798
|
-
}
|
|
6799
|
-
const layout = await getTmuxLayout(targetSessionName);
|
|
6800
|
-
broadcastEvent(sessionId, { type: 'tmux-layout', layout });
|
|
6736
|
+
const layout = await switchTmuxBackendSession(sessionId, session, targetSessionName);
|
|
6801
6737
|
return res.json({ success: true, layout });
|
|
6802
6738
|
}
|
|
6803
6739
|
// All other actions: delegate to shared executeTmuxAction
|
|
@@ -7048,13 +6984,65 @@ async function executeTmuxAction(tmuxTarget, action, body, control) {
|
|
|
7048
6984
|
}
|
|
7049
6985
|
return { shouldBroadcastLayout };
|
|
7050
6986
|
}
|
|
7051
|
-
export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}) {
|
|
6987
|
+
export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, initialDimensions) {
|
|
7052
6988
|
const session = terminalSessions.get(sessionId);
|
|
7053
6989
|
if (!session) {
|
|
7054
6990
|
ws.close(4001, 'Session not found');
|
|
7055
6991
|
return;
|
|
7056
6992
|
}
|
|
7057
|
-
const
|
|
6993
|
+
const initialSince = options.sinceSeq ?? 0;
|
|
6994
|
+
const delivery = new TerminalOutputDelivery((frame) => {
|
|
6995
|
+
if (ws.readyState === ws.OPEN)
|
|
6996
|
+
ws.send(JSON.stringify(frame));
|
|
6997
|
+
}, options.flowControl === true, 128 * 1024, 512 * 1024, () => {
|
|
6998
|
+
// No ACK may be outstanding (e.g. a single oversized frame). Reconnect
|
|
6999
|
+
// against authoritative history instead of leaving this observer stalled.
|
|
7000
|
+
if (ws.readyState === ws.OPEN)
|
|
7001
|
+
ws.close(1013, 'Output observer exceeded budget');
|
|
7002
|
+
});
|
|
7003
|
+
outputDeliveries.set(ws, delivery);
|
|
7004
|
+
let outputWanted = options.outputActive !== false;
|
|
7005
|
+
let clientPaused = false;
|
|
7006
|
+
let replayRequest = null;
|
|
7007
|
+
let clientCols = session.cols;
|
|
7008
|
+
let clientRows = session.rows;
|
|
7009
|
+
let initialAttachmentResize = true;
|
|
7010
|
+
let initialScreen = null;
|
|
7011
|
+
if (initialDimensions && options.independentTmux) {
|
|
7012
|
+
clientCols = initialDimensions.cols;
|
|
7013
|
+
clientRows = initialDimensions.rows;
|
|
7014
|
+
}
|
|
7015
|
+
const ownTmux = session.mode === 'tmux' && options.independentTmux === true;
|
|
7016
|
+
if (ownTmux)
|
|
7017
|
+
independentTmuxClients.add(ws);
|
|
7018
|
+
const attachment = ownTmux ? new TerminalClientAttachment(async (cols, rows) => {
|
|
7019
|
+
const provider = await getPtyProvider();
|
|
7020
|
+
// The metadata observer must not choose the pane size while a browser
|
|
7021
|
+
// owns an attached client. Resolve by exact PID, never another client.
|
|
7022
|
+
const raw = await runTmux(['list-clients', '-t', session.tmuxSessionName, '-F', '#{client_pid} #{client_tty}']);
|
|
7023
|
+
const metadata = raw.split('\n').map(line => line.trim().split(/\s+/))
|
|
7024
|
+
.find(([pid]) => pid === String(session.ptyProcess.pid));
|
|
7025
|
+
if (metadata?.[1])
|
|
7026
|
+
await runTmux(['refresh-client', '-t', metadata[1], '-f', 'ignore-size']);
|
|
7027
|
+
const env = buildInteractiveColorEnvironment({ ...process.env, PATH: buildAugmentedPath() });
|
|
7028
|
+
delete env.TMUX;
|
|
7029
|
+
delete env.TMUX_PANE;
|
|
7030
|
+
return provider.spawn(getTmuxBinary(), ['-T', 'RGB,sync', 'attach-session', '-t', session.tmuxSessionName], {
|
|
7031
|
+
name: 'xterm-256color', cols, rows, cwd: session.cwd || os.homedir(),
|
|
7032
|
+
env: { ...env, TERM: 'xterm-256color', COLORTERM: 'truecolor' },
|
|
7033
|
+
});
|
|
7034
|
+
}, (data) => {
|
|
7035
|
+
if (ws.readyState !== ws.OPEN)
|
|
7036
|
+
return;
|
|
7037
|
+
if (ws.bufferedAmount > 1024 * 1024) {
|
|
7038
|
+
ws.close(1013, 'Output transport is congested');
|
|
7039
|
+
return;
|
|
7040
|
+
}
|
|
7041
|
+
const liveData = initialScreen ? initialScreen.push(data) : data;
|
|
7042
|
+
if (liveData)
|
|
7043
|
+
delivery.enqueue({ type: 'data', data: liveData });
|
|
7044
|
+
}, () => { if (ws.readyState === ws.OPEN)
|
|
7045
|
+
ws.close(1012, 'Tmux display client detached'); }) : null;
|
|
7058
7046
|
// Register client
|
|
7059
7047
|
let clients = wsClients.get(sessionId);
|
|
7060
7048
|
if (!clients) {
|
|
@@ -7067,86 +7055,153 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}) {
|
|
|
7067
7055
|
if (updateGlobalBindingForBackendSession(sessionId, { cwd: session.cwd, lastActivity: session.lastActivity })) {
|
|
7068
7056
|
persistAndBroadcastGlobalState();
|
|
7069
7057
|
}
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7058
|
+
const sendReplay = (requestedSince = initialSince, clientEpoch = options.streamEpoch) => {
|
|
7059
|
+
if (replayRequest)
|
|
7060
|
+
return replayRequest;
|
|
7061
|
+
const sinceSeq = resolveTerminalReplayCursor(requestedSince, clientEpoch, TERMINAL_STREAM_EPOCH);
|
|
7062
|
+
delivery.replaying = true;
|
|
7063
|
+
if (attachment) {
|
|
7064
|
+
attachment.close();
|
|
7065
|
+
initialScreen?.cancel();
|
|
7066
|
+
initialScreen = null;
|
|
7067
|
+
initialAttachmentResize = true;
|
|
7068
|
+
delivery.setActive(false); // Discard only this observer's obsolete stream.
|
|
7069
|
+
}
|
|
7070
|
+
replayRequest = (async () => {
|
|
7071
|
+
// 连接时立即检测一次 activeProgram,避免前端首次显示闪烁
|
|
7072
|
+
try {
|
|
7073
|
+
if (session.mode === 'shell') {
|
|
7074
|
+
const ap = await detectShellActiveProgram(session);
|
|
7075
|
+
if (ap)
|
|
7076
|
+
session.activeProgram = ap;
|
|
7077
|
+
}
|
|
7078
|
+
else if (session.mode === 'tmux' && session.tmuxSessionName) {
|
|
7079
|
+
const layout = await getCachedTmuxLayout(session.tmuxSessionName);
|
|
7080
|
+
const ap = getActiveProgramFromTmuxLayout(layout);
|
|
7081
|
+
if (ap)
|
|
7082
|
+
session.activeProgram = ap;
|
|
7083
|
+
}
|
|
7077
7084
|
}
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7085
|
+
catch { /* ignore */ }
|
|
7086
|
+
// 计算重连补帧:
|
|
7087
|
+
// - sinceSeq > 0:短线重连,shell 模式按 seq 补增量;超出窗口则发 outOfWindow + 全量。
|
|
7088
|
+
// - sinceSeq == 0:首次连接(包括手机 PWA 冷启动)。以前这里只回 lastSeq、不带数据,
|
|
7089
|
+
// 靠客户端单独走 HTTP /attach 拿 scrollback;但那条路径会阻塞 MultiTerminalView 的
|
|
7090
|
+
// "Restoring sessions..." 全屏 loading(蜂窝 RTT 1-3 秒)。现在直接把 restore history
|
|
7091
|
+
// 塞进 'connected' 事件,省掉一次 HTTP 往返,前端 UI 可以立刻渲染、scrollback 随 WS
|
|
7092
|
+
// 到达即填充。tmux 模式发 capture-pane 输出(带 clear-screen 前缀,避免与 xterm 默认
|
|
7093
|
+
// 内容拼接),shell 模式发 ring buffer 内容(最多 100KB)。
|
|
7094
|
+
//
|
|
7095
|
+
// replayOutOfWindow=true 的语义在 sinceSeq=0 时是"你没有基线,请清空已有内容
|
|
7096
|
+
// 再应用 replayChunks"。这正好覆盖客户端"localStorage hydrate 出来的缓存 buffer"
|
|
7097
|
+
// 场景:缓存内容会被服务端权威版本干净地替换,不会出现重复或顺序错位。
|
|
7098
|
+
let replayChunks = [];
|
|
7099
|
+
let replayLastSeq = 0;
|
|
7100
|
+
let replayOutOfWindow = false;
|
|
7101
|
+
if (attachment) {
|
|
7102
|
+
if (ws.readyState !== ws.OPEN)
|
|
7103
|
+
return;
|
|
7104
|
+
delivery.setActive(outputWanted && !clientPaused);
|
|
7105
|
+
if (delivery.active) {
|
|
7106
|
+
const screen = new TmuxInitialScreen();
|
|
7107
|
+
initialScreen = screen;
|
|
7108
|
+
if (!await attachment.open(clientCols, clientRows)) {
|
|
7109
|
+
screen.cancel();
|
|
7110
|
+
return;
|
|
7111
|
+
}
|
|
7112
|
+
const first = await screen.ready;
|
|
7113
|
+
if (initialScreen === screen)
|
|
7114
|
+
initialScreen = null;
|
|
7115
|
+
if (first.status === 'cancelled' || ws.readyState !== ws.OPEN)
|
|
7116
|
+
return;
|
|
7117
|
+
if (first.status === 'overflow')
|
|
7118
|
+
throw new Error('Initial tmux screen exceeded output budget');
|
|
7119
|
+
// Bootstrap with the actual first PTY redraw, not a standalone empty
|
|
7120
|
+
// reset followed by the screen in a second client write. Subsequent
|
|
7121
|
+
// bytes already wait in delivery and retain their original ordering.
|
|
7122
|
+
replayChunks = first.data ? [first.data] : ['\x1bc'];
|
|
7123
|
+
}
|
|
7124
|
+
else {
|
|
7125
|
+
replayChunks = ['\x1bc'];
|
|
7126
|
+
}
|
|
7127
|
+
replayOutOfWindow = true;
|
|
7083
7128
|
}
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
// 靠客户端单独走 HTTP /attach 拿 scrollback;但那条路径会阻塞 MultiTerminalView 的
|
|
7090
|
-
// "Restoring sessions..." 全屏 loading(蜂窝 RTT 1-3 秒)。现在直接把 restore history
|
|
7091
|
-
// 塞进 'connected' 事件,省掉一次 HTTP 往返,前端 UI 可以立刻渲染、scrollback 随 WS
|
|
7092
|
-
// 到达即填充。tmux 模式发 capture-pane 输出(带 clear-screen 前缀,避免与 xterm 默认
|
|
7093
|
-
// 内容拼接),shell 模式发 ring buffer 内容(最多 100KB)。
|
|
7094
|
-
//
|
|
7095
|
-
// replayOutOfWindow=true 的语义在 sinceSeq=0 时是"你没有基线,请清空已有内容
|
|
7096
|
-
// 再应用 replayChunks"。这正好覆盖客户端"localStorage hydrate 出来的缓存 buffer"
|
|
7097
|
-
// 场景:缓存内容会被服务端权威版本干净地替换,不会出现重复或顺序错位。
|
|
7098
|
-
let replayChunks = [];
|
|
7099
|
-
let replayLastSeq = 0;
|
|
7100
|
-
let replayOutOfWindow = false;
|
|
7101
|
-
if (sinceSeq > 0 && session.mode === 'shell') {
|
|
7102
|
-
const since = getHistorySince(sessionId, sinceSeq);
|
|
7103
|
-
replayChunks = since.chunks.map((c) => c.data);
|
|
7104
|
-
replayLastSeq = since.lastSeq;
|
|
7105
|
-
replayOutOfWindow = since.outOfWindow;
|
|
7106
|
-
}
|
|
7107
|
-
else {
|
|
7108
|
-
// 首次连接:直接补全量 scrollback,并强制让客户端清空已有内容(处理缓存 hydrate)
|
|
7109
|
-
try {
|
|
7110
|
-
replayChunks = await getRestoreHistory(sessionId, session);
|
|
7129
|
+
else if (sinceSeq > 0 && session.mode === 'shell') {
|
|
7130
|
+
const since = getHistorySince(sessionId, sinceSeq);
|
|
7131
|
+
replayChunks = since.chunks.map((c) => c.data);
|
|
7132
|
+
replayLastSeq = since.lastSeq;
|
|
7133
|
+
replayOutOfWindow = since.outOfWindow;
|
|
7111
7134
|
}
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7135
|
+
else {
|
|
7136
|
+
// 首次连接:直接补全量 scrollback,并强制让客户端清空已有内容(处理缓存 hydrate)
|
|
7137
|
+
try {
|
|
7138
|
+
replayChunks = session.mode === 'shell' ? getReconnectionHistory(sessionId) : await getRestoreHistory(sessionId, session);
|
|
7139
|
+
}
|
|
7140
|
+
catch (error) {
|
|
7141
|
+
console.warn(`[ws] getRestoreHistory failed for ${sessionId}: ${getErrorMessage(error)}`);
|
|
7142
|
+
replayChunks = [];
|
|
7143
|
+
}
|
|
7144
|
+
replayLastSeq = session.mode === 'shell' ? getHistoryLastSeq(sessionId) : 0;
|
|
7145
|
+
replayOutOfWindow = replayChunks.length > 0;
|
|
7115
7146
|
}
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7147
|
+
if (ws.readyState !== ws.OPEN)
|
|
7148
|
+
return;
|
|
7149
|
+
// Empty authoritative histories still need to clear an obsolete baseline.
|
|
7150
|
+
if (sinceSeq === 0 && replayChunks.length === 0) {
|
|
7151
|
+
replayChunks = ['\x1bc'];
|
|
7152
|
+
replayOutOfWindow = true;
|
|
7153
|
+
}
|
|
7154
|
+
// Send connected event (after initial detection)
|
|
7155
|
+
const runtime = globalThis.Bun ? 'bun' : 'node';
|
|
7156
|
+
ws.send(JSON.stringify({
|
|
7157
|
+
type: 'connected',
|
|
7158
|
+
streamEpoch: TERMINAL_STREAM_EPOCH,
|
|
7159
|
+
outputProtocol: options.flowControl ? 2 : undefined,
|
|
7160
|
+
runtime,
|
|
7161
|
+
ptyBackend: session.ptyBackend || 'unknown',
|
|
7162
|
+
mode: session.mode,
|
|
7163
|
+
tmuxSessionName: session.tmuxSessionName,
|
|
7164
|
+
cwd: session.cwd ?? null,
|
|
7165
|
+
activeProgram: session.activeProgram?.command ?? getPersistedActiveProgramForBackend(sessionId),
|
|
7166
|
+
activeProgramRaw: session.activeProgram?.rawArgs ?? null,
|
|
7167
|
+
activeProgramSource: session.activeProgram?.source ?? null,
|
|
7168
|
+
tuiProgress: session.tuiProgress,
|
|
7169
|
+
shellTitle: session.lastOscTitle,
|
|
7170
|
+
promptState: session.lastPromptState,
|
|
7171
|
+
focusTrackingRequested: session.focusTrackingRequested,
|
|
7172
|
+
// 短线重连补帧:
|
|
7173
|
+
// replayChunks 为补发数据;replayLastSeq 是客户端应记录的新基线;
|
|
7174
|
+
// replayOutOfWindow 表示客户端基线已被服务端淘汰,前端可以选择清屏后再回放。
|
|
7175
|
+
replayChunks,
|
|
7176
|
+
replayLastSeq,
|
|
7177
|
+
replayOutOfWindow,
|
|
7178
|
+
}));
|
|
7179
|
+
delivery.finishReplay(replayLastSeq);
|
|
7180
|
+
// Rich agent state rides its own message (see the SSE path above).
|
|
7181
|
+
if (session.agent || session.agentSession || session.agentResumeRecovered) {
|
|
7182
|
+
ws.send(JSON.stringify(buildAgentStatusPayload(sessionId, session)));
|
|
7183
|
+
}
|
|
7184
|
+
if (session.gitStatus) {
|
|
7185
|
+
ws.send(JSON.stringify({ type: 'git-status', gitStatus: session.gitStatus }));
|
|
7186
|
+
}
|
|
7187
|
+
})().catch((error) => {
|
|
7188
|
+
initialScreen?.cancel();
|
|
7189
|
+
initialScreen = null;
|
|
7190
|
+
console.warn(`[ws] replay failed session=${sessionId}: ${getErrorMessage(error)}`);
|
|
7191
|
+
if (ws.readyState === ws.OPEN)
|
|
7192
|
+
ws.close(1011, 'Replay unavailable');
|
|
7193
|
+
}).finally(() => { replayRequest = null; });
|
|
7194
|
+
return replayRequest;
|
|
7195
|
+
};
|
|
7196
|
+
if (attachment)
|
|
7197
|
+
independentTmuxReplays.set(ws, async () => {
|
|
7198
|
+
attachment.close();
|
|
7199
|
+
initialScreen?.cancel();
|
|
7200
|
+
await replayRequest;
|
|
7201
|
+
if (ws.readyState === ws.OPEN)
|
|
7202
|
+
await sendReplay(0);
|
|
7203
|
+
});
|
|
7204
|
+
void sendReplay();
|
|
7150
7205
|
// Tmux layout polling (per-client, like the SSE stream does)
|
|
7151
7206
|
let tmuxInterval = null;
|
|
7152
7207
|
let activeProgramInterval = null;
|
|
@@ -7284,11 +7339,12 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}) {
|
|
|
7284
7339
|
case 'input': {
|
|
7285
7340
|
if (typeof msg.data === 'string' && msg.data.length > 0) {
|
|
7286
7341
|
const data = msg.data;
|
|
7287
|
-
if (
|
|
7342
|
+
if (attachment) {
|
|
7343
|
+
session.lastActivity = Date.now();
|
|
7344
|
+
attachment.write(data);
|
|
7345
|
+
}
|
|
7346
|
+
else if (session.mode === 'tmux') {
|
|
7288
7347
|
await enqueueTmuxIo(session, async () => {
|
|
7289
|
-
if (isTmuxWheelInput(data)) {
|
|
7290
|
-
await syncTmuxScreenBeforeScroll(sessionId, clientId, session, ws);
|
|
7291
|
-
}
|
|
7292
7348
|
session.lastActivity = Date.now();
|
|
7293
7349
|
session.ptyProcess.write(data);
|
|
7294
7350
|
});
|
|
@@ -7303,34 +7359,47 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}) {
|
|
|
7303
7359
|
case 'resize': {
|
|
7304
7360
|
const cols = Number(msg.cols);
|
|
7305
7361
|
const rows = Number(msg.rows);
|
|
7306
|
-
if (cols > 0 && rows > 0) {
|
|
7307
|
-
|
|
7362
|
+
if (Number.isFinite(cols) && Number.isFinite(rows) && cols > 0 && rows > 0) {
|
|
7363
|
+
if (attachment) {
|
|
7364
|
+
const cleanCols = Math.floor(cols), cleanRows = Math.floor(rows);
|
|
7365
|
+
const sameSize = clientCols === cleanCols && clientRows === cleanRows;
|
|
7366
|
+
const ok = sameSize ? attachment.attached : attachment.resize(cleanCols, cleanRows);
|
|
7367
|
+
if (ok) {
|
|
7368
|
+
// The first resize confirms the grid supplied at attachment.
|
|
7369
|
+
// Its PTY is already drawing that grid; forcing refresh-client
|
|
7370
|
+
// here repeats the initial clear/full redraw. Later same-size
|
|
7371
|
+
// requests remain explicit display recovery requests.
|
|
7372
|
+
const needsRedraw = sameSize && !initialAttachmentResize;
|
|
7373
|
+
initialAttachmentResize = false;
|
|
7374
|
+
clientCols = cleanCols;
|
|
7375
|
+
clientRows = cleanRows;
|
|
7376
|
+
session.lastActivity = Date.now();
|
|
7377
|
+
if (needsRedraw)
|
|
7378
|
+
await redrawTmuxClient(runTmux, session.tmuxSessionName, attachment.pid);
|
|
7379
|
+
}
|
|
7380
|
+
if (ws.readyState === ws.OPEN)
|
|
7381
|
+
ws.send(JSON.stringify({
|
|
7382
|
+
type: 'resize-ack', seq: typeof msg.seq === 'number' ? msg.seq : undefined,
|
|
7383
|
+
ok, cols: clientCols, rows: clientRows, screenSyncPending: false,
|
|
7384
|
+
}));
|
|
7385
|
+
break;
|
|
7386
|
+
}
|
|
7387
|
+
const sameSize = session.cols === Math.floor(cols) && session.rows === Math.floor(rows);
|
|
7308
7388
|
const ok = session.mode === 'tmux'
|
|
7309
7389
|
? await enqueueTmuxIo(session, () => applyPtyResize(sessionId, session, cols, rows, `ws-resize:${clientId}`, clientId))
|
|
7310
7390
|
: applyPtyResize(sessionId, session, cols, rows, `ws-resize:${clientId}`, clientId);
|
|
7311
|
-
//
|
|
7312
|
-
//
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
if (ok
|
|
7316
|
-
&& session.mode === 'tmux'
|
|
7317
|
-
&& (session.tmuxResizeGeneration ?? 0) === screenSyncGenerationBefore) {
|
|
7318
|
-
markTmuxClientForScreenSync(session, clientId);
|
|
7319
|
-
scheduleTmuxScreenSyncAfterResize(sessionId, session, clientId);
|
|
7391
|
+
// Same-size requests explicitly recover the display; actual geometry
|
|
7392
|
+
// changes already cause tmux to redraw its attached client.
|
|
7393
|
+
if (ok && session.mode === 'tmux' && sameSize) {
|
|
7394
|
+
await enqueueTmuxIo(session, () => redrawTmuxClient(runTmux, session.tmuxSessionName, session.ptyProcess.pid));
|
|
7320
7395
|
}
|
|
7321
|
-
const screenSyncGeneration = session.tmuxResizeGeneration ?? 0;
|
|
7322
|
-
const screenSyncPending = ok
|
|
7323
|
-
&& session.mode === 'tmux'
|
|
7324
|
-
&& screenSyncGeneration > screenSyncGenerationBefore
|
|
7325
|
-
&& session.tmuxScreenSyncClients?.has(clientId) === true;
|
|
7326
7396
|
ws.send(JSON.stringify({
|
|
7327
7397
|
type: 'resize-ack',
|
|
7328
7398
|
seq: typeof msg.seq === 'number' ? msg.seq : undefined,
|
|
7329
7399
|
ok,
|
|
7330
7400
|
cols: session.cols,
|
|
7331
7401
|
rows: session.rows,
|
|
7332
|
-
screenSyncPending,
|
|
7333
|
-
screenSyncGeneration: screenSyncPending ? screenSyncGeneration : undefined,
|
|
7402
|
+
screenSyncPending: false,
|
|
7334
7403
|
}));
|
|
7335
7404
|
}
|
|
7336
7405
|
break;
|
|
@@ -7341,10 +7410,14 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}) {
|
|
|
7341
7410
|
ws.send(JSON.stringify({ type: 'tmux-result', reqId, success: false, error: 'Not in tmux mode' }));
|
|
7342
7411
|
break;
|
|
7343
7412
|
}
|
|
7413
|
+
if (msg.action === 'switch-session') {
|
|
7414
|
+
const target = typeof msg.tmuxSessionName === 'string' ? msg.tmuxSessionName.trim() : '';
|
|
7415
|
+
await enqueueTmuxIo(session, () => switchTmuxBackendSession(sessionId, session, target));
|
|
7416
|
+
if (ws.readyState === ws.OPEN)
|
|
7417
|
+
ws.send(JSON.stringify({ type: 'tmux-result', reqId, success: true }));
|
|
7418
|
+
break;
|
|
7419
|
+
}
|
|
7344
7420
|
const result = await enqueueTmuxIo(session, async () => {
|
|
7345
|
-
if (msg.action === 'scroll') {
|
|
7346
|
-
await syncTmuxScreenBeforeScroll(sessionId, clientId, session, ws);
|
|
7347
|
-
}
|
|
7348
7421
|
return executeTmuxAction(session.tmuxSessionName, msg.action, msg, session.tmuxControl);
|
|
7349
7422
|
});
|
|
7350
7423
|
ws.send(JSON.stringify({ type: 'tmux-result', reqId, success: !result.error, error: result.error }));
|
|
@@ -7360,7 +7433,12 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}) {
|
|
|
7360
7433
|
case 'focus': {
|
|
7361
7434
|
const focused = msg.focused === true;
|
|
7362
7435
|
const reason = typeof msg.reason === 'string' ? msg.reason : 'client-focus';
|
|
7363
|
-
|
|
7436
|
+
if (attachment) {
|
|
7437
|
+
if (session.focusTrackingRequested)
|
|
7438
|
+
attachment.write(getFocusSequence(focused));
|
|
7439
|
+
}
|
|
7440
|
+
else
|
|
7441
|
+
updateClientFocusState(sessionId, session, clientId, focused, reason);
|
|
7364
7442
|
break;
|
|
7365
7443
|
}
|
|
7366
7444
|
case 'viewing': {
|
|
@@ -7375,10 +7453,41 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}) {
|
|
|
7375
7453
|
}
|
|
7376
7454
|
break;
|
|
7377
7455
|
}
|
|
7456
|
+
case 'output-subscription': {
|
|
7457
|
+
if (!options.flowControl || typeof msg.active !== 'boolean')
|
|
7458
|
+
break;
|
|
7459
|
+
outputWanted = msg.active;
|
|
7460
|
+
const resumed = delivery.setActive(outputWanted && !clientPaused);
|
|
7461
|
+
if (!delivery.active)
|
|
7462
|
+
attachment?.close();
|
|
7463
|
+
if (resumed && delivery.active) {
|
|
7464
|
+
void sendReplay(typeof msg.since === 'number' ? msg.since : 0, typeof msg.epoch === 'string' ? msg.epoch : undefined);
|
|
7465
|
+
}
|
|
7466
|
+
break;
|
|
7467
|
+
}
|
|
7468
|
+
case 'output-ack': {
|
|
7469
|
+
if (!options.flowControl || typeof msg.flowSeq !== 'number')
|
|
7470
|
+
break;
|
|
7471
|
+
delivery.acknowledge(msg.flowSeq);
|
|
7472
|
+
if (delivery.needsReplay && delivery.active) {
|
|
7473
|
+
void sendReplay(typeof msg.since === 'number' ? msg.since : 0, typeof msg.epoch === 'string' ? msg.epoch : undefined);
|
|
7474
|
+
}
|
|
7475
|
+
break;
|
|
7476
|
+
}
|
|
7378
7477
|
case 'flow-control': {
|
|
7379
7478
|
if (typeof msg.paused === 'boolean') {
|
|
7380
7479
|
const reason = typeof msg.reason === 'string' ? msg.reason : 'client-flow-control';
|
|
7381
|
-
|
|
7480
|
+
if (options.flowControl) {
|
|
7481
|
+
const wasPaused = clientPaused;
|
|
7482
|
+
clientPaused = msg.paused;
|
|
7483
|
+
delivery.setActive(outputWanted && !clientPaused);
|
|
7484
|
+
if (!delivery.active)
|
|
7485
|
+
attachment?.close();
|
|
7486
|
+
if (wasPaused && delivery.active)
|
|
7487
|
+
void sendReplay(0);
|
|
7488
|
+
}
|
|
7489
|
+
else
|
|
7490
|
+
setClientFlowPaused(sessionId, session, clientId, msg.paused, reason);
|
|
7382
7491
|
}
|
|
7383
7492
|
break;
|
|
7384
7493
|
}
|
|
@@ -7412,6 +7521,9 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}) {
|
|
|
7412
7521
|
});
|
|
7413
7522
|
// Cleanup on close
|
|
7414
7523
|
ws.on('close', () => {
|
|
7524
|
+
initialScreen?.cancel();
|
|
7525
|
+
initialScreen = null;
|
|
7526
|
+
attachment?.close();
|
|
7415
7527
|
if (tmuxInterval)
|
|
7416
7528
|
clearInterval(tmuxInterval);
|
|
7417
7529
|
if (activeProgramInterval)
|
|
@@ -7423,8 +7535,8 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}) {
|
|
|
7423
7535
|
wsClients.delete(sessionId);
|
|
7424
7536
|
}
|
|
7425
7537
|
}
|
|
7426
|
-
|
|
7427
|
-
|
|
7538
|
+
if (!attachment)
|
|
7539
|
+
removeClientFocus(sessionId, session, clientId);
|
|
7428
7540
|
if (options.pushClientId) {
|
|
7429
7541
|
setClientViewingSession(options.pushClientId, sessionId, false);
|
|
7430
7542
|
}
|