termdock 1.4.266 → 1.4.268
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/.desktop-dist/main.js +4 -3
- package/dist/client/assets/App-B_gjv_L4.js +156 -0
- package/dist/client/assets/App-B_gjv_L4.js.br +0 -0
- package/dist/client/assets/App-B_gjv_L4.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-N09mFFHb.js → ChangeWalkthroughPanel-B7xfrwV0.js} +2 -2
- package/dist/client/assets/ChangeWalkthroughPanel-B7xfrwV0.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-B7xfrwV0.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-BjU87Tm4.js → DagPlayground-DD8Mudl0.js} +1 -1
- package/dist/client/assets/DagPlayground-DD8Mudl0.js.br +0 -0
- package/dist/client/assets/DagPlayground-DD8Mudl0.js.gz +0 -0
- package/dist/client/assets/{DiffLab-COA-b5pN.js → DiffLab-DfMaEfdB.js} +1 -1
- package/dist/client/assets/DiffLab-DfMaEfdB.js.br +0 -0
- package/dist/client/assets/DiffLab-DfMaEfdB.js.gz +0 -0
- package/dist/client/assets/{DiffReview-DPEzF3Wb.js → DiffReview-FIaqdDPy.js} +1 -1
- package/dist/client/assets/DiffReview-FIaqdDPy.js.br +0 -0
- package/dist/client/assets/DiffReview-FIaqdDPy.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-Dq9gLO5P.js → DiffReviewLab-CkC9diid.js} +1 -1
- package/dist/client/assets/DiffReviewLab-CkC9diid.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CkC9diid.js.gz +0 -0
- package/dist/client/assets/DiffViewer-CYEoT3NM.js +37 -0
- package/dist/client/assets/DiffViewer-CYEoT3NM.js.br +0 -0
- package/dist/client/assets/DiffViewer-CYEoT3NM.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-uqYy4UHn.js → ModelPreview-38AXZG5e.js} +1 -1
- package/dist/client/assets/ModelPreview-38AXZG5e.js.br +0 -0
- package/dist/client/assets/ModelPreview-38AXZG5e.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-Do0_u2am.js → RightSidebar-A1dkYC_K.js} +4 -4
- package/dist/client/assets/RightSidebar-A1dkYC_K.js.br +0 -0
- package/dist/client/assets/RightSidebar-A1dkYC_K.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-C-F1hNwL.js → abnfDiagram-VCTEODGH-BvFKrJvp.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-BvFKrJvp.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-BvFKrJvp.js.gz +0 -0
- package/dist/client/assets/{app-BB-UfzoN.js → app-CojGYCuR.js} +12 -12
- package/dist/client/assets/app-CojGYCuR.js.br +0 -0
- package/dist/client/assets/app-CojGYCuR.js.gz +0 -0
- package/dist/client/assets/{arc-Bj1HTggS.js → arc-KrauQCou.js} +1 -1
- package/dist/client/assets/arc-KrauQCou.js.br +0 -0
- package/dist/client/assets/arc-KrauQCou.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-DiQ9VX2i.js → architectureDiagram-5GKGNRK7-m4EFlQe5.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-m4EFlQe5.js.br +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-DiQ9VX2i.js.gz → architectureDiagram-5GKGNRK7-m4EFlQe5.js.gz} +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-Bs_OA90h.js → blockDiagram-I7D4REHJ-DYKVPCAg.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-DYKVPCAg.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-DYKVPCAg.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-BF4InYpU.js → c4Diagram-7LVT6UL2-Bom-ry7C.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-Bom-ry7C.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-Bom-ry7C.js.gz +0 -0
- package/dist/client/assets/channel-DPQ_m-tX.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-Cagkfj0j.js → chunk-2Q5K7J3B-DruGlr2i.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-CgX5Whwp.js → chunk-5VM5RSS4-BzuDLW6I.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-B8w3974i.js → chunk-F27PBJKO-BmOruelE.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-BmOruelE.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-BmOruelE.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-BgtujxgQ.js → chunk-IMKFNOWR-C_QAjdvx.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-C_QAjdvx.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-C_QAjdvx.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-Cf7NLgli.js → chunk-JWPE2WC7-COrvoLHM.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-BQst9Llh.js → chunk-POPQ4Y6H-B1ZbbBXT.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-D4PwA2QX.js → chunk-SVP7TREG-D1tHVHrA.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-D1tHVHrA.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-D1tHVHrA.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-DHnYkG_x.js → chunk-TICWLB2K-CUf6WDYE.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-CUf6WDYE.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CUf6WDYE.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-BHWFSVth.js → chunk-XXDRQBXY-DSiiDaTY.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-Kz6tCBai.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-Kz6tCBai.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-CCFMhjak.js → cose-bilkent-JH36ORCC-T3qCojhn.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-T3qCojhn.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-T3qCojhn.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-aeeCA73W.js → cynefin-OW5HDTMX-KpUgbXRL.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-KpUgbXRL.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-KpUgbXRL.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-Qd4yv-WB.js → cynefinDiagram-5FMLGOSQ-DPYl0L-K.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DPYl0L-K.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DPYl0L-K.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-tYsGlQq_.js → dagre-GXQ25YYZ-Bxp13G_N.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-Bxp13G_N.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-Bxp13G_N.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-C1Bc6nbm.js → diagram-S7CK7UJ4-CpE50wgs.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-CpE50wgs.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-CpE50wgs.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-SdvjJa7O.js → diagram-UQ7AKVKN-CQJFD7tB.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-CQJFD7tB.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-CQJFD7tB.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-CopEWwGT.js → diagram-VSXAHHWV-CcCMRaVS.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-CcCMRaVS.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CcCMRaVS.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-CKdAVxN-.js → diagram-VX7I27RA-BJHjGgyM.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-BJHjGgyM.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-BJHjGgyM.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-x9ISSrse.js → diagram-Z3DM3KII-Ctr0Mur_.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-Ctr0Mur_.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-Ctr0Mur_.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-Bta60dSv.js → ebnfDiagram-PWID7BFC-CKEPPhZD.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-CKEPPhZD.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-CKEPPhZD.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-sB_bIQ0I.js → erDiagram-RLTQ6QDP-CFjw9WX4.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-CFjw9WX4.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-CFjw9WX4.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-D-5EW4Om.js → flowDiagram-HODETNUW-ahJZ_2Y3.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-ahJZ_2Y3.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-ahJZ_2Y3.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-x4bF8XHI.js → ganttDiagram-EL5Y4UJY-CZvH1BVH.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CZvH1BVH.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CZvH1BVH.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-C7V1_Sm6.js → gestureArbiter-CYcLJOkb.js} +1 -1
- package/dist/client/assets/gestureArbiter-CYcLJOkb.js.br +0 -0
- package/dist/client/assets/gestureArbiter-CYcLJOkb.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-pKX7lvtX.js → gitGraphDiagram-WWUBYQGX-5k2btOuf.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-5k2btOuf.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-5k2btOuf.js.gz +0 -0
- package/dist/client/assets/{index-CQGiUA31.css → index--h47b0ln.css} +1 -1
- package/dist/client/assets/index--h47b0ln.css.br +0 -0
- package/dist/client/assets/{index-CQGiUA31.css.gz → index--h47b0ln.css.gz} +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-ibYLF4lB.js → infoDiagram-27XIBGKW-B75F2r0B.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BF0rhBil.js → ishikawaDiagram-5VMMS53U-D82lZtnM.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-D82lZtnM.js.br +0 -0
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BF0rhBil.js.gz → ishikawaDiagram-5VMMS53U-D82lZtnM.js.gz} +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-DR_bXhpA.js → journeyDiagram-3NMN7TZE-DDco1Uz5.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DDco1Uz5.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DDco1Uz5.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-rLtDawpv.js → kanban-definition-UXKFOSKX-bFUaJw_7.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-bFUaJw_7.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-bFUaJw_7.js.gz +0 -0
- package/dist/client/assets/{layout-abNq6Us0.js → layout-DqoIDxOD.js} +1 -1
- package/dist/client/assets/{layout-abNq6Us0.js.br → layout-DqoIDxOD.js.br} +0 -0
- package/dist/client/assets/{layout-abNq6Us0.js.gz → layout-DqoIDxOD.js.gz} +0 -0
- package/dist/client/assets/{linear-B6ZlmcfV.js → linear-iI_YMQHc.js} +1 -1
- package/dist/client/assets/linear-iI_YMQHc.js.br +0 -0
- package/dist/client/assets/linear-iI_YMQHc.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-DH5DL9hV.js → mermaid.core-5yt2YuB8.js} +5 -5
- package/dist/client/assets/mermaid.core-5yt2YuB8.js.br +0 -0
- package/dist/client/assets/{mermaid.core-DH5DL9hV.js.gz → mermaid.core-5yt2YuB8.js.gz} +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-Bjmuduw6.js → mindmap-definition-YA3MSWOX-ChlqCeNZ.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-ChlqCeNZ.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-ChlqCeNZ.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-J17_f0uK.js → passwordBootstrap-CYPeNLru.js} +1 -1
- package/dist/client/assets/passwordBootstrap-CYPeNLru.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-CYPeNLru.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-BVVc1guP.js → pegDiagram-XKGWAZYB-Crg6gf5W.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-Crg6gf5W.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-Crg6gf5W.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-iyGrttc6.js → pieDiagram-E7YTZNPT-BXdoZQZj.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-BXdoZQZj.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-BXdoZQZj.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Djqtsu2z.js → quadrantDiagram-AXDQQJYC-DX07rl7R.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DX07rl7R.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DX07rl7R.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-C2ph9wgs.js → railroadDiagram-O6MQD6OU-C2ZzDGxp.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ZzDGxp.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ZzDGxp.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-Bm0VuySQ.js → referenceLongPress-gi-7KSUT.js} +1 -1
- package/dist/client/assets/referenceLongPress-gi-7KSUT.js.br +0 -0
- package/dist/client/assets/referenceLongPress-gi-7KSUT.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-vXjbhdRD.js → requirementDiagram-BXWQKSXE-FuuHXQEq.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-FuuHXQEq.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-FuuHXQEq.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-SNiiKcgp.js → sankeyDiagram-P5KCCOFB-Bk1BrUVk.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bk1BrUVk.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bk1BrUVk.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-Fn2oExLH.js → sequenceDiagram-WJ2MYXX4-9A9f6S8W.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-9A9f6S8W.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-9A9f6S8W.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-FoHuOCXL.js → sizeCapture-INFHLROL-DQBQsVnW.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-DQBQsVnW.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-DQBQsVnW.js.gz +0 -0
- package/dist/client/assets/{sparkles-BpV0BVRF.js → sparkles-VMoDkivK.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-BiBiBFDH.js → stateDiagram-D77RDMKH-BXufbeMX.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-BXufbeMX.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BXufbeMX.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-QrSvO0ee.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-8_6AEHBA.js → swimlanes-42K2YHIH-DrRwVG23.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-DrRwVG23.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-DrRwVG23.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-C1DRM79Q.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-vh_kdWEp.js → timeline-definition-24CTP7MA-CWgWzJ8C.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-CWgWzJ8C.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-CWgWzJ8C.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-BDY-HlS4.js → triangle-alert-BvcHjqm6.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-DD1-E-ya.js → vennDiagram-4TSXK5OY-CRUebJIC.js} +1 -1
- package/dist/client/assets/vennDiagram-4TSXK5OY-CRUebJIC.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CRUebJIC.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-HMOrL8bB.js → wardleyDiagram-VM6X3IG4-BFSHgvns.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-BFSHgvns.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-BFSHgvns.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DUxhnGCd.js → xychartDiagram-S5SC5T6Z-B9YiYLj1.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-B9YiYLj1.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-B9YiYLj1.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.js +1 -1
- package/dist/client/sw.js.br +0 -0
- package/dist/client/sw.js.gz +0 -0
- package/dist/server/android/liveBitrate.js +162 -0
- package/dist/server/android/scrcpy.js +51 -5
- package/dist/server/cli.js +1 -1
- package/dist/server/entry.js +1 -1
- package/dist/server/federation/runtime.js +1 -1
- package/dist/server/onboardingServer.js +1 -2
- package/dist/server/routes/android.js +11 -0
- package/dist/server/routes/filesystem.js +29 -15
- package/dist/server/routes/onboarding.js +0 -99
- package/dist/server/utils/localAccess.js +1 -1
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- package/scripts/android-bitrate/CaptureReset.java +86 -0
- package/scripts/android-bitrate/LICENSE +203 -0
- package/scripts/android-bitrate/README.md +50 -0
- package/scripts/android-bitrate/bitrate.jar +0 -0
- package/scripts/android-bitrate/build.sh +28 -0
- package/scripts/android-bitrate/fetch-server.sh +12 -0
- package/scripts/android-bitrate/scrcpy-server-v3.3.4 +0 -0
- package/dist/client/assets/App-DzRCmm_W.js +0 -156
- package/dist/client/assets/App-DzRCmm_W.js.br +0 -0
- package/dist/client/assets/App-DzRCmm_W.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-N09mFFHb.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-N09mFFHb.js.gz +0 -0
- package/dist/client/assets/DagPlayground-BjU87Tm4.js.br +0 -0
- package/dist/client/assets/DagPlayground-BjU87Tm4.js.gz +0 -0
- package/dist/client/assets/DiffLab-COA-b5pN.js.br +0 -0
- package/dist/client/assets/DiffLab-COA-b5pN.js.gz +0 -0
- package/dist/client/assets/DiffReview-DPEzF3Wb.js.br +0 -0
- package/dist/client/assets/DiffReview-DPEzF3Wb.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-Dq9gLO5P.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-Dq9gLO5P.js.gz +0 -0
- package/dist/client/assets/DiffViewer-DNd0R8FA.js +0 -37
- package/dist/client/assets/DiffViewer-DNd0R8FA.js.br +0 -0
- package/dist/client/assets/DiffViewer-DNd0R8FA.js.gz +0 -0
- package/dist/client/assets/ModelPreview-uqYy4UHn.js.br +0 -0
- package/dist/client/assets/ModelPreview-uqYy4UHn.js.gz +0 -0
- package/dist/client/assets/RightSidebar-Do0_u2am.js.br +0 -0
- package/dist/client/assets/RightSidebar-Do0_u2am.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-C-F1hNwL.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-C-F1hNwL.js.gz +0 -0
- package/dist/client/assets/app-BB-UfzoN.js.br +0 -0
- package/dist/client/assets/app-BB-UfzoN.js.gz +0 -0
- package/dist/client/assets/arc-Bj1HTggS.js.br +0 -0
- package/dist/client/assets/arc-Bj1HTggS.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DiQ9VX2i.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-Bs_OA90h.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-Bs_OA90h.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-BF4InYpU.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-BF4InYpU.js.gz +0 -0
- package/dist/client/assets/channel-D4Mx8Qe2.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-B8w3974i.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-B8w3974i.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BgtujxgQ.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BgtujxgQ.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-D4PwA2QX.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-D4PwA2QX.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-DHnYkG_x.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-DHnYkG_x.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-e0EybKcM.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-e0EybKcM.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-CCFMhjak.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-CCFMhjak.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-aeeCA73W.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-aeeCA73W.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Qd4yv-WB.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Qd4yv-WB.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-tYsGlQq_.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-tYsGlQq_.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-C1Bc6nbm.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-C1Bc6nbm.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-SdvjJa7O.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-SdvjJa7O.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CopEWwGT.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CopEWwGT.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CKdAVxN-.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CKdAVxN-.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-x9ISSrse.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-x9ISSrse.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bta60dSv.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bta60dSv.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-sB_bIQ0I.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-sB_bIQ0I.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-D-5EW4Om.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-D-5EW4Om.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-x4bF8XHI.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-x4bF8XHI.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-C7V1_Sm6.js.br +0 -0
- package/dist/client/assets/gestureArbiter-C7V1_Sm6.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-pKX7lvtX.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-pKX7lvtX.js.gz +0 -0
- package/dist/client/assets/index-CQGiUA31.css.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-BF0rhBil.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DR_bXhpA.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-DR_bXhpA.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-rLtDawpv.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-rLtDawpv.js.gz +0 -0
- package/dist/client/assets/linear-B6ZlmcfV.js.br +0 -0
- package/dist/client/assets/linear-B6ZlmcfV.js.gz +0 -0
- package/dist/client/assets/mermaid.core-DH5DL9hV.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-Bjmuduw6.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-Bjmuduw6.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-J17_f0uK.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-J17_f0uK.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-BVVc1guP.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-BVVc1guP.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-iyGrttc6.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-iyGrttc6.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-Djqtsu2z.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-Djqtsu2z.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ph9wgs.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ph9wgs.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-Bm0VuySQ.js.br +0 -0
- package/dist/client/assets/referenceLongPress-Bm0VuySQ.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-vXjbhdRD.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-vXjbhdRD.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-SNiiKcgp.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-SNiiKcgp.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Fn2oExLH.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Fn2oExLH.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-FoHuOCXL.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-FoHuOCXL.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BiBiBFDH.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BiBiBFDH.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-_Vs6ah69.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-8_6AEHBA.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-8_6AEHBA.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DCbcOwps.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-vh_kdWEp.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-vh_kdWEp.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DD1-E-ya.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DD1-E-ya.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-HMOrL8bB.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-HMOrL8bB.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-DUxhnGCd.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-DUxhnGCd.js.gz +0 -0
|
@@ -4,6 +4,7 @@ import net from 'node:net';
|
|
|
4
4
|
import { delimiter, dirname, join } from 'node:path';
|
|
5
5
|
import { randomInt } from 'node:crypto';
|
|
6
6
|
import { adbSearchPath, resolveAdbBinary } from './adb.js';
|
|
7
|
+
import { LiveBitrateChannel, inspectLiveBitrate, resolveBundledPreviewServer, bitrateOverlayPath, bitrateOverlayRemote } from './liveBitrate.js';
|
|
7
8
|
const DEVICE_NAME_LENGTH = 64;
|
|
8
9
|
const VIDEO_HEADER_LENGTH = 12;
|
|
9
10
|
const FRAME_HEADER_LENGTH = 12;
|
|
@@ -131,6 +132,7 @@ export class ScrcpySession {
|
|
|
131
132
|
events;
|
|
132
133
|
options;
|
|
133
134
|
scid = randomInt(1, 0x7fffffff);
|
|
135
|
+
bitrateChannel = null;
|
|
134
136
|
child = null;
|
|
135
137
|
server = null;
|
|
136
138
|
videoSocket = null;
|
|
@@ -172,7 +174,7 @@ export class ScrcpySession {
|
|
|
172
174
|
return;
|
|
173
175
|
this.started = true;
|
|
174
176
|
try {
|
|
175
|
-
const { serverJar, version } = await resolveScrcpyBinaries();
|
|
177
|
+
const { serverJar, version } = await resolveBundledPreviewServer() ?? await resolveScrcpyBinaries();
|
|
176
178
|
this.protocol = Number.parseInt(version.split('.')[0] ?? '0', 10) >= 4 ? 'session' : 'legacy';
|
|
177
179
|
const remoteJar = remoteJarPath(version);
|
|
178
180
|
await runAdbCapture(['-s', this.serial, 'push', serverJar, remoteJar], 60_000);
|
|
@@ -184,10 +186,45 @@ export class ScrcpySession {
|
|
|
184
186
|
server.listen(0, '127.0.0.1', () => { this.port = server.address().port; resolve(); });
|
|
185
187
|
});
|
|
186
188
|
await runAdbCapture(['-s', this.serial, 'reverse', `localabstract:scrcpy_${scidHex(this.scid)}`, `tcp:${this.port}`], 15_000);
|
|
189
|
+
let liveBitrate = false;
|
|
190
|
+
let bitrateFailure = await inspectLiveBitrate(serverJar, version);
|
|
191
|
+
let bitrateStage = 'BITRATE_LISTEN_FAILED';
|
|
192
|
+
const reportBitrate = (ready, detail) => {
|
|
193
|
+
if (this.stopped)
|
|
194
|
+
return;
|
|
195
|
+
const diagnostic = detail ? `${detail}; scrcpy=${version}; device=${this.serial}` : undefined;
|
|
196
|
+
if (diagnostic)
|
|
197
|
+
console.warn('[android] ' + diagnostic);
|
|
198
|
+
this.events.onBitrateSupport?.(ready, diagnostic);
|
|
199
|
+
};
|
|
200
|
+
if (!bitrateFailure) {
|
|
201
|
+
try {
|
|
202
|
+
this.bitrateChannel = new LiveBitrateChannel(reportBitrate);
|
|
203
|
+
const port = await this.bitrateChannel.listen();
|
|
204
|
+
bitrateStage = 'BITRATE_PUSH_FAILED';
|
|
205
|
+
await runAdbCapture(['-s', this.serial, 'push', bitrateOverlayPath, bitrateOverlayRemote]);
|
|
206
|
+
bitrateStage = 'BITRATE_TUNNEL_FAILED';
|
|
207
|
+
await runAdbCapture(['-s', this.serial, 'reverse', `localabstract:termdock_bitrate_${scidHex(this.scid)}`, `tcp:${port}`]);
|
|
208
|
+
liveBitrate = true;
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
bitrateFailure = `${bitrateStage}: ${String(error)}`;
|
|
212
|
+
this.bitrateChannel?.close();
|
|
213
|
+
this.bitrateChannel = null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!liveBitrate)
|
|
217
|
+
reportBitrate(false, bitrateFailure ?? 'BITRATE_UNAVAILABLE');
|
|
218
|
+
if (this.stopped) {
|
|
219
|
+
this.bitrateChannel?.close();
|
|
220
|
+
this.server?.close();
|
|
221
|
+
await Promise.allSettled(['scrcpy_', 'termdock_bitrate_'].map(prefix => runAdbCapture(['-s', this.serial, 'reverse', '--remove', `localabstract:${prefix}${scidHex(this.scid)}`], 8000)));
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
187
224
|
const args = [
|
|
188
225
|
'-s', this.serial, 'shell',
|
|
189
|
-
`CLASSPATH=${remoteJar}`,
|
|
190
|
-
'app_process', '/',
|
|
226
|
+
`CLASSPATH=${liveBitrate ? bitrateOverlayRemote + ":" : ""}${remoteJar}`,
|
|
227
|
+
'app_process', ...(liveBitrate ? [`-Dtermdock.bitrate=termdock_bitrate_${scidHex(this.scid)}`] : []), '/',
|
|
191
228
|
'com.genymobile.scrcpy.Server', version,
|
|
192
229
|
`scid=${this.scid.toString(16)}`,
|
|
193
230
|
'log_level=info',
|
|
@@ -246,7 +283,7 @@ export class ScrcpySession {
|
|
|
246
283
|
readVideo(chunk) {
|
|
247
284
|
if (this.stopped)
|
|
248
285
|
return;
|
|
249
|
-
this.videoBuffer = Buffer.concat([this.videoBuffer, chunk]);
|
|
286
|
+
this.videoBuffer = this.videoBuffer.length ? Buffer.concat([this.videoBuffer, chunk]) : chunk;
|
|
250
287
|
if (this.videoStage === 'meta') {
|
|
251
288
|
if (this.videoBuffer.length < DEVICE_NAME_LENGTH)
|
|
252
289
|
return;
|
|
@@ -310,7 +347,7 @@ export class ScrcpySession {
|
|
|
310
347
|
const size = this.videoBuffer.readUInt32BE(8);
|
|
311
348
|
if (this.videoBuffer.length < FRAME_HEADER_LENGTH + size)
|
|
312
349
|
break;
|
|
313
|
-
const payload =
|
|
350
|
+
const payload = this.videoBuffer.subarray(FRAME_HEADER_LENGTH, FRAME_HEADER_LENGTH + size);
|
|
314
351
|
this.videoBuffer = this.videoBuffer.subarray(FRAME_HEADER_LENGTH + size);
|
|
315
352
|
const session = this.protocol === 'session';
|
|
316
353
|
const config = session ? ((ptsFlags >> 62n) & 1n) === 1n : ((ptsFlags >> 63n) & 1n) === 1n;
|
|
@@ -375,11 +412,16 @@ export class ScrcpySession {
|
|
|
375
412
|
return false;
|
|
376
413
|
}
|
|
377
414
|
}
|
|
415
|
+
get bitrateFailure() { return this.bitrateChannel?.lastFailure; }
|
|
416
|
+
setBitrate(value) {
|
|
417
|
+
return this.bitrateChannel?.setBitrate(value) ?? Promise.resolve(false);
|
|
418
|
+
}
|
|
378
419
|
async stop() {
|
|
379
420
|
if (this.stopped)
|
|
380
421
|
return;
|
|
381
422
|
this.stopped = true;
|
|
382
423
|
activeSessions.delete(this);
|
|
424
|
+
this.bitrateChannel?.close();
|
|
383
425
|
const child = this.child;
|
|
384
426
|
this.child = null;
|
|
385
427
|
try {
|
|
@@ -407,6 +449,10 @@ export class ScrcpySession {
|
|
|
407
449
|
await runAdbCapture(['-s', this.serial, 'reverse', '--remove', `localabstract:scrcpy_${scidHex(this.scid)}`], 8000);
|
|
408
450
|
}
|
|
409
451
|
catch { /* reverse 可能已随进程退出被清理 */ }
|
|
452
|
+
try {
|
|
453
|
+
await runAdbCapture(['-s', this.serial, 'reverse', '--remove', `localabstract:termdock_bitrate_${scidHex(this.scid)}`], 8000);
|
|
454
|
+
}
|
|
455
|
+
catch { /* optional channel */ }
|
|
410
456
|
this.events.onClose();
|
|
411
457
|
}
|
|
412
458
|
}
|
package/dist/server/cli.js
CHANGED
|
@@ -527,7 +527,7 @@ function printRunningState(state) {
|
|
|
527
527
|
if (state.lanUrl)
|
|
528
528
|
console.log(` ${c.dim('LAN:')} ${c.cyan(state.lanUrl)} ${state.localAccessStatus ? c.dim(`(${state.localAccessStatus})`) : ''}`);
|
|
529
529
|
if (state.onboardingUrl)
|
|
530
|
-
console.log(` ${c.dim('
|
|
530
|
+
console.log(` ${c.dim('CA certificate:')} ${c.cyan(state.onboardingUrl)} ${c.dim('(open this on your phone to download the CA certificate)')}`);
|
|
531
531
|
if (state.localAccessReason)
|
|
532
532
|
console.log(` ${c.dim('LAN note:')} ${state.localAccessReason}`);
|
|
533
533
|
console.log(` ${c.dim('Log:')} ${state.logFile}`);
|
package/dist/server/entry.js
CHANGED
|
@@ -752,7 +752,7 @@ export function startServer(options = {}) {
|
|
|
752
752
|
if (state.status === 'active') {
|
|
753
753
|
console.log(`LAN access: ${state.url}`);
|
|
754
754
|
if (onboardingUrl)
|
|
755
|
-
console.log(`
|
|
755
|
+
console.log(`CA certificate: ${onboardingUrl} (open this on your phone to download the CA certificate)`);
|
|
756
756
|
}
|
|
757
757
|
else {
|
|
758
758
|
console.log(`LAN access: ${state.status}${state.reason ? ` (${state.reason})` : ''}`);
|
|
@@ -604,7 +604,7 @@ export async function createFederationRuntime(app, directory, handlers, options
|
|
|
604
604
|
if (item.android) {
|
|
605
605
|
if (!full(subjectId))
|
|
606
606
|
throw new Error('AUTHORIZATION_DENIED');
|
|
607
|
-
if (!['control', 'ack', 'ping'].includes(data?.type))
|
|
607
|
+
if (!['control', 'ack', 'ping', 'bitrate'].includes(data?.type))
|
|
608
608
|
throw new Error('ACTION_NOT_ALLOWED');
|
|
609
609
|
}
|
|
610
610
|
else if (item.sessionId) {
|
|
@@ -24,7 +24,6 @@ export function startOnboardingServer(options) {
|
|
|
24
24
|
res.setHeader('Content-Disposition', 'attachment; filename="rootCA.pem"');
|
|
25
25
|
res.send(fs.readFileSync(options.caCertPath));
|
|
26
26
|
});
|
|
27
|
-
app.get('/', (_req, res) => res.redirect('/onboarding'));
|
|
28
27
|
const server = createServer(app);
|
|
29
28
|
server.on('error', (error) => {
|
|
30
29
|
console.warn('[onboarding] HTTP setup server failed:', error);
|
|
@@ -33,7 +32,7 @@ export function startOnboardingServer(options) {
|
|
|
33
32
|
const address = server.address();
|
|
34
33
|
const port = address?.port ?? null;
|
|
35
34
|
const host = getLanIPv4Addresses()[0] ?? 'localhost';
|
|
36
|
-
activeUrl = port ? `http://${host}:${port}/
|
|
35
|
+
activeUrl = port ? `http://${host}:${port}/ca` : null;
|
|
37
36
|
});
|
|
38
37
|
server.listen(0, '0.0.0.0');
|
|
39
38
|
activeServer = server;
|
|
@@ -185,6 +185,7 @@ export function handleAndroidWebSocket(socket, serial, _clientId, requested = {}
|
|
|
185
185
|
socket.on('error', () => { closed = true; clearInterval(flowTimer); if (statsTimer)
|
|
186
186
|
clearInterval(statsTimer); void session?.stop(); session = null; });
|
|
187
187
|
session = createScrcpySession(serial, {
|
|
188
|
+
onBitrateSupport: (supported, detail) => send({ type: 'bitrate-support', supported, detail }),
|
|
188
189
|
onHeader: header => { send({ type: 'header', ...header }); },
|
|
189
190
|
onFrame: frame => {
|
|
190
191
|
if (closed)
|
|
@@ -226,6 +227,16 @@ export function handleAndroidWebSocket(socket, serial, _clientId, requested = {}
|
|
|
226
227
|
return;
|
|
227
228
|
}
|
|
228
229
|
switch (message.type) {
|
|
230
|
+
case 'bitrate': {
|
|
231
|
+
if (typeof message.requestId !== 'number' || !Number.isSafeInteger(message.requestId)
|
|
232
|
+
|| typeof message.bitRate !== 'number' || !Number.isInteger(message.bitRate)
|
|
233
|
+
|| message.bitRate < 300_000 || message.bitRate > 30_000_000)
|
|
234
|
+
return;
|
|
235
|
+
const requestId = message.requestId, bitRate = message.bitRate;
|
|
236
|
+
const current = session;
|
|
237
|
+
void current.setBitrate(bitRate).then(applied => send({ type: 'bitrate-result', requestId, bitRate, applied, detail: current.bitrateFailure }));
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
229
240
|
case 'control': {
|
|
230
241
|
if (typeof message.data !== 'string' || message.data.length > 64 * 1024)
|
|
231
242
|
return;
|
|
@@ -2289,23 +2289,37 @@ async function getBranchDiffPayload(workspaceRoot, repoRoot, baseBranch, options
|
|
|
2289
2289
|
return { available: false, workspaceRoot, repoRoot, baseBranch: trimmedBase, error: 'Invalid target branch name' };
|
|
2290
2290
|
}
|
|
2291
2291
|
const includeUncommitted = options?.includeUncommitted ?? true;
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2292
|
+
const remotes = (await execGit(['remote'], repoRoot, signal)).split('\n').filter(Boolean);
|
|
2293
|
+
const remoteBase = trimmedBase.replace(/^refs\/remotes\//, '');
|
|
2294
|
+
// Match configured remotes, not arbitrary slashes in local branch names.
|
|
2295
|
+
const baseRemote = remotes.sort((a, b) => b.length - a.length)
|
|
2296
|
+
.find((remote) => remoteBase.startsWith(`${remote}/`))
|
|
2297
|
+
?? (!trimmedBase.includes('/') && remotes.includes('origin') ? 'origin' : null);
|
|
2298
|
+
let baseRef = trimmedBase;
|
|
2299
|
+
if (baseRemote) {
|
|
2300
|
+
const remoteBranch = remoteBase.startsWith(`${baseRemote}/`)
|
|
2301
|
+
? remoteBase.slice(baseRemote.length + 1)
|
|
2302
|
+
: trimmedBase;
|
|
2303
|
+
baseRef = `${baseRemote}/${remoteBranch}`;
|
|
2304
|
+
const trackingRef = `refs/remotes/${baseRef}`;
|
|
2297
2305
|
try {
|
|
2298
|
-
|
|
2306
|
+
// Explicitly update the selected tracking ref even with a narrow fetch
|
|
2307
|
+
// refspec, and accept a baseline that was force-pushed on the remote.
|
|
2308
|
+
await execGit(['fetch', '--no-tags', '--', baseRemote, `+refs/heads/${remoteBranch}:${trackingRef}`], repoRoot, signal, GIT_ROUTE_TIMEOUT_MS);
|
|
2299
2309
|
}
|
|
2300
2310
|
catch (error) {
|
|
2301
|
-
|
|
2302
|
-
.then(() => trimmedBase)
|
|
2303
|
-
.catch(() => null);
|
|
2304
|
-
if (!localRef)
|
|
2311
|
+
if (signal.aborted)
|
|
2305
2312
|
throw error;
|
|
2306
|
-
|
|
2313
|
+
return {
|
|
2314
|
+
available: false, workspaceRoot, repoRoot, baseBranch: trimmedBase, baseRef,
|
|
2315
|
+
error: `Failed to refresh baseline ${baseRef}. Check remote access and retry. No comparison was generated from a stale local baseline.`,
|
|
2316
|
+
};
|
|
2307
2317
|
}
|
|
2308
2318
|
}
|
|
2319
|
+
// Keep the display/audit key stable, but use the full namespace for Git so
|
|
2320
|
+
// a same-named local branch cannot shadow the refreshed tracking ref.
|
|
2321
|
+
const baseGitRef = baseRemote ? `refs/remotes/${baseRef}` : baseRef;
|
|
2322
|
+
await execGit(['rev-parse', '--verify', '--quiet', `${baseGitRef}^{commit}`], repoRoot, signal);
|
|
2309
2323
|
let compareHead = 'HEAD';
|
|
2310
2324
|
if (hasRequestedHead) {
|
|
2311
2325
|
compareHead = requestedHead.includes('/') ? requestedHead : requestedHead;
|
|
@@ -2317,11 +2331,11 @@ async function getBranchDiffPayload(workspaceRoot, repoRoot, baseBranch, options
|
|
|
2317
2331
|
// instead of two overlapping per-file diffs concatenated together.
|
|
2318
2332
|
// Falls back to the concatenated form when there is no merge base.
|
|
2319
2333
|
const mergeBase = includeWorkingTree
|
|
2320
|
-
? await execGit(['merge-base',
|
|
2334
|
+
? await execGit(['merge-base', baseGitRef, compareHead], repoRoot, signal)
|
|
2321
2335
|
.then((result) => result.trim() || null)
|
|
2322
2336
|
.catch(() => null)
|
|
2323
2337
|
: null;
|
|
2324
|
-
const diffBase = mergeBase ?? `${
|
|
2338
|
+
const diffBase = mergeBase ?? `${baseGitRef}...${compareHead}`;
|
|
2325
2339
|
const fetchSeparateWorktreeDiff = includeWorkingTree && !mergeBase;
|
|
2326
2340
|
const [currentBranch, headRef, statResult, nameResult, workingNameResult, logResult, diffResult, workingDiffResult] = await Promise.all([
|
|
2327
2341
|
execGit(['branch', '--show-current'], repoRoot, signal).catch(emptyOnNonAbortGitError),
|
|
@@ -2329,7 +2343,7 @@ async function getBranchDiffPayload(workspaceRoot, repoRoot, baseBranch, options
|
|
|
2329
2343
|
execGitLimited(['diff', diffBase, '--stat'], repoRoot, MAX_BRANCH_DIFF_STAT_BYTES, false, signal),
|
|
2330
2344
|
execGitLimited(['diff', '--name-only', diffBase], repoRoot, MAX_BRANCH_DIFF_NAME_BYTES, false, signal),
|
|
2331
2345
|
fetchSeparateWorktreeDiff ? execGitLimited(['diff', '--name-only', 'HEAD'], repoRoot, MAX_BRANCH_DIFF_NAME_BYTES, false, signal) : Promise.resolve({ stdout: '', truncated: false }),
|
|
2332
|
-
execGitLimited(['log', `${
|
|
2346
|
+
execGitLimited(['log', `${baseGitRef}..${compareHead}`, '--oneline', '--no-merges'], repoRoot, MAX_BRANCH_DIFF_LOG_BYTES, false, signal),
|
|
2333
2347
|
execGitLimited(['diff', diffBase], repoRoot, MAX_BRANCH_DIFF_BYTES, false, signal),
|
|
2334
2348
|
fetchSeparateWorktreeDiff ? execGitLimited(['diff', 'HEAD'], repoRoot, MAX_BRANCH_DIFF_BYTES, false, signal) : Promise.resolve({ stdout: '', truncated: false }),
|
|
2335
2349
|
]);
|
|
@@ -2347,7 +2361,7 @@ async function getBranchDiffPayload(workspaceRoot, repoRoot, baseBranch, options
|
|
|
2347
2361
|
...workingNameResult.stdout.split('\n').map((line) => line.trim()).filter(Boolean),
|
|
2348
2362
|
...untrackedResult.files,
|
|
2349
2363
|
]));
|
|
2350
|
-
const hunks = await annotateBranchDiffHunks(repoRoot,
|
|
2364
|
+
const hunks = await annotateBranchDiffHunks(repoRoot, baseGitRef, parseBranchDiffHunks(diff), signal);
|
|
2351
2365
|
const commits = logResult.stdout.split('\n').map((line) => line.trim()).filter(Boolean);
|
|
2352
2366
|
const fingerprint = buildChangeAuditFingerprint([
|
|
2353
2367
|
repoRoot,
|
|
@@ -1,112 +1,13 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import fs from 'fs';
|
|
3
|
-
import QRCode from 'qrcode';
|
|
4
3
|
import { localAccessManager } from '../utils/localAccess.js';
|
|
5
4
|
function sendCaCertificate(res, caCertPath) {
|
|
6
5
|
res.setHeader('Content-Type', 'application/x-x509-ca-cert');
|
|
7
6
|
res.setHeader('Content-Disposition', 'attachment; filename="rootCA.pem"');
|
|
8
7
|
res.send(fs.readFileSync(caCertPath));
|
|
9
8
|
}
|
|
10
|
-
function escapeHtml(value) {
|
|
11
|
-
return value
|
|
12
|
-
.replace(/&/g, '&')
|
|
13
|
-
.replace(/</g, '<')
|
|
14
|
-
.replace(/>/g, '>')
|
|
15
|
-
.replace(/"/g, '"')
|
|
16
|
-
.replace(/'/g, ''');
|
|
17
|
-
}
|
|
18
|
-
function createQrCards(items) {
|
|
19
|
-
return items.map((item) => `
|
|
20
|
-
<div class="qr-card">
|
|
21
|
-
${item.qr ? `<div class="qr"><img src="${item.qr}" alt="QR code for ${escapeHtml(item.url)}" /></div>` : ''}
|
|
22
|
-
<div>
|
|
23
|
-
<div class="label">${escapeHtml(item.label)} · ${escapeHtml(item.address)}</div>
|
|
24
|
-
<code>${escapeHtml(item.url)}</code>
|
|
25
|
-
</div>
|
|
26
|
-
</div>`).join('');
|
|
27
|
-
}
|
|
28
|
-
function createPage(caAvailable, qrItems, targetUrl) {
|
|
29
|
-
const state = localAccessManager.getState();
|
|
30
|
-
const url = escapeHtml(targetUrl ?? state.url);
|
|
31
|
-
const fallbackUrl = escapeHtml(state.fallbackUrl);
|
|
32
|
-
const status = escapeHtml(state.status);
|
|
33
|
-
const reason = state.reason ? escapeHtml(state.reason) : '';
|
|
34
|
-
const caButton = caAvailable
|
|
35
|
-
? '<a class="button" href="/onboarding/ca.crt">Download CA certificate</a>'
|
|
36
|
-
: '<div class="warn">CA file is not configured. Start Termdock with --https-ca <path> to enable certificate download.</div>';
|
|
37
|
-
return `<!doctype html>
|
|
38
|
-
<html lang="en">
|
|
39
|
-
<head>
|
|
40
|
-
<meta charset="utf-8" />
|
|
41
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
42
|
-
<title>Termdock Local Access</title>
|
|
43
|
-
<style>
|
|
44
|
-
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #100F0F; color: #CECDC3; }
|
|
45
|
-
main { max-width: 720px; margin: 0 auto; padding: 32px 20px 48px; }
|
|
46
|
-
.card { border: 1px solid rgba(255,255,255,.12); border-radius: 20px; background: rgba(255,255,255,.05); padding: 20px; }
|
|
47
|
-
h1 { font-size: 28px; margin: 0 0 8px; }
|
|
48
|
-
h2 { font-size: 18px; margin: 24px 0 8px; }
|
|
49
|
-
p, li { color: rgba(255,255,255,.78); line-height: 1.6; }
|
|
50
|
-
code { word-break: break-all; color: #4385BE; }
|
|
51
|
-
.button { display: inline-flex; margin: 12px 0; padding: 12px 16px; border-radius: 999px; background: #879A39; color: #100F0F; font-weight: 700; text-decoration: none; }
|
|
52
|
-
.warn { margin: 12px 0; padding: 12px; border-radius: 12px; background: rgba(208, 162, 21, .15); color: #D0A215; }
|
|
53
|
-
.muted { color: rgba(255,255,255,.55); font-size: 13px; }
|
|
54
|
-
.qr { display: inline-block; margin: 12px 0; padding: 10px; border-radius: 16px; background: #fff; }
|
|
55
|
-
.qr img { display: block; width: 160px; height: 160px; }
|
|
56
|
-
.qr-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; margin: 14px 0; }
|
|
57
|
-
.qr-card { border: 1px solid rgba(255,255,255,.1); border-radius: 16px; padding: 12px; background: rgba(255,255,255,.04); }
|
|
58
|
-
.label { margin: 4px 0 6px; font-weight: 700; color: rgba(255,255,255,.86); }
|
|
59
|
-
</style>
|
|
60
|
-
</head>
|
|
61
|
-
<body>
|
|
62
|
-
<main>
|
|
63
|
-
<div class="card">
|
|
64
|
-
<h1>Termdock Local Access</h1>
|
|
65
|
-
<p>Scan one of these QR codes to open an IP fallback address on your phone:</p>
|
|
66
|
-
<div class="qr-grid">${createQrCards(qrItems)}</div>
|
|
67
|
-
<p>Install the local CA on your phone first, then open:</p>
|
|
68
|
-
<p><code>${url}</code></p>
|
|
69
|
-
<p class="muted">If mDNS does not resolve on your Wi‑Fi, use this IP fallback after installing the CA: <code>${fallbackUrl}</code></p>
|
|
70
|
-
<p class="muted">Status: ${status}${reason ? ` · ${reason}` : ''}</p>
|
|
71
|
-
${caButton}
|
|
72
|
-
<p class="muted">Short link: <code>/ca</code> (same certificate download)</p>
|
|
73
|
-
<h2>iPhone / iPad</h2>
|
|
74
|
-
<ol>
|
|
75
|
-
<li>Tap “Download CA certificate”.</li>
|
|
76
|
-
<li>Open Settings and install the downloaded profile.</li>
|
|
77
|
-
<li>Go to Settings → General → About → Certificate Trust Settings, then fully trust the CA.</li>
|
|
78
|
-
<li>Return to <code>${url}</code>.</li>
|
|
79
|
-
</ol>
|
|
80
|
-
<h2>Android</h2>
|
|
81
|
-
<ol>
|
|
82
|
-
<li>Tap “Download CA certificate”.</li>
|
|
83
|
-
<li>Install it as a CA certificate from system security settings.</li>
|
|
84
|
-
<li>Return to <code>${url}</code>.</li>
|
|
85
|
-
</ol>
|
|
86
|
-
</div>
|
|
87
|
-
</main>
|
|
88
|
-
</body>
|
|
89
|
-
</html>`;
|
|
90
|
-
}
|
|
91
9
|
export function createOnboardingRouter(options = {}) {
|
|
92
10
|
const router = express.Router();
|
|
93
|
-
router.get('/', async (_req, res) => {
|
|
94
|
-
const caAvailable = Boolean(options.caCertPath && fs.existsSync(options.caCertPath));
|
|
95
|
-
const state = localAccessManager.getState();
|
|
96
|
-
const targetUrl = state.hostname
|
|
97
|
-
? `${state.httpsEnabled ? 'https' : 'http'}://${state.hostname}:${options.port ?? 9834}`
|
|
98
|
-
: state.url;
|
|
99
|
-
const qrItems = await Promise.all(state.interfaces.map(async (entry) => {
|
|
100
|
-
const url = `${state.httpsEnabled ? 'https' : 'http'}://${entry.address}:${options.port ?? 9834}`;
|
|
101
|
-
const qr = await QRCode.toDataURL(url, {
|
|
102
|
-
margin: 1,
|
|
103
|
-
width: 160,
|
|
104
|
-
errorCorrectionLevel: 'M',
|
|
105
|
-
}).catch(() => null);
|
|
106
|
-
return { label: `${entry.label} (${entry.name})`, address: entry.address, url, qr };
|
|
107
|
-
}));
|
|
108
|
-
res.type('html').send(createPage(caAvailable, qrItems, targetUrl));
|
|
109
|
-
});
|
|
110
11
|
router.get('/status', (_req, res) => {
|
|
111
12
|
const state = localAccessManager.getState();
|
|
112
13
|
res.json({
|
|
@@ -58,7 +58,7 @@ function buildState(setting, options, status, reason) {
|
|
|
58
58
|
fallbackHostname,
|
|
59
59
|
url: `${options.scheme}://${hostname}:${options.port}`,
|
|
60
60
|
fallbackUrl: `${options.scheme}://${fallbackHostname}:${options.port}`,
|
|
61
|
-
onboardingUrl: onboardingHost ? `http://${onboardingHost}:${options.onboardingPort ?? options.port}/
|
|
61
|
+
onboardingUrl: onboardingHost ? `http://${onboardingHost}:${options.onboardingPort ?? options.port}/ca` : null,
|
|
62
62
|
status,
|
|
63
63
|
reason,
|
|
64
64
|
httpsEnabled: options.scheme === 'https',
|
package/package.json
CHANGED
package/runtime-manifest.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "termdock",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.268",
|
|
5
5
|
"runtimeProtocolVersion": 1,
|
|
6
6
|
"minimumDesktopVersion": "1.4.46",
|
|
7
7
|
"nodeMajor": 22,
|
|
8
8
|
"dependencyHash": "sha256-K4KyYJuVoQDpZsBM8ZX1Rw3MddOxAzVdp/cPm0iGZz0=",
|
|
9
|
-
"serverBundleHash": "sha256-
|
|
10
|
-
"clientBundleHash": "sha256-
|
|
9
|
+
"serverBundleHash": "sha256-5s4aavmMB1RPNhkzWZM9dGKt9Uys6E0bSvz6Qk5lhJc=",
|
|
10
|
+
"clientBundleHash": "sha256-UyN8TKeB+T8JHqNVB42eXm1EprZNw/7bvxOx7aS9AC4=",
|
|
11
11
|
"entrypoint": "dist/server/cli.js",
|
|
12
12
|
"clientEntrypoint": "dist/client/index.html"
|
|
13
13
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Based on scrcpy 3.3.4 CaptureReset, Copyright Genymobile.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// Termdock addition: a separate, session-scoped bitrate control socket.
|
|
4
|
+
package com.genymobile.scrcpy.video;
|
|
5
|
+
|
|
6
|
+
import android.media.MediaCodec;
|
|
7
|
+
import android.net.LocalSocket;
|
|
8
|
+
import android.net.LocalSocketAddress;
|
|
9
|
+
import android.os.Bundle;
|
|
10
|
+
import java.io.DataInputStream;
|
|
11
|
+
import java.io.DataOutputStream;
|
|
12
|
+
import java.io.IOException;
|
|
13
|
+
import java.nio.charset.StandardCharsets;
|
|
14
|
+
import java.util.concurrent.atomic.AtomicBoolean;
|
|
15
|
+
|
|
16
|
+
public class CaptureReset implements SurfaceCapture.CaptureListener {
|
|
17
|
+
private final AtomicBoolean reset = new AtomicBoolean();
|
|
18
|
+
private MediaCodec runningMediaCodec;
|
|
19
|
+
private int bitrate;
|
|
20
|
+
private boolean started;
|
|
21
|
+
|
|
22
|
+
public boolean consumeReset() { return reset.getAndSet(false); }
|
|
23
|
+
|
|
24
|
+
public synchronized void reset() {
|
|
25
|
+
reset.set(true);
|
|
26
|
+
if (runningMediaCodec != null) {
|
|
27
|
+
try { runningMediaCodec.signalEndOfInputStream(); }
|
|
28
|
+
catch (IllegalStateException ignored) { }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public synchronized void setRunningMediaCodec(MediaCodec codec) {
|
|
33
|
+
runningMediaCodec = codec;
|
|
34
|
+
// Reapply after an actual rotation/reset, without causing one ourselves.
|
|
35
|
+
if (codec != null && bitrate > 0) applyBitrate(bitrate);
|
|
36
|
+
String name = System.getProperty("termdock.bitrate");
|
|
37
|
+
if (codec != null && !started && name != null) {
|
|
38
|
+
started = true;
|
|
39
|
+
Thread thread = new Thread(() -> serve(name), "termdock-bitrate");
|
|
40
|
+
thread.setDaemon(true);
|
|
41
|
+
thread.start();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private synchronized String applyBitrate(int value) {
|
|
46
|
+
if (runningMediaCodec == null) return "Encoder temporarily unavailable during reset";
|
|
47
|
+
if (value < 300000 || value > 30000000) return "Bitrate outside supported request range";
|
|
48
|
+
try {
|
|
49
|
+
Bundle params = new Bundle();
|
|
50
|
+
params.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, value);
|
|
51
|
+
runningMediaCodec.setParameters(params);
|
|
52
|
+
bitrate = value;
|
|
53
|
+
return null;
|
|
54
|
+
} catch (IllegalArgumentException | IllegalStateException error) {
|
|
55
|
+
String diagnostic = error instanceof MediaCodec.CodecException
|
|
56
|
+
? ((MediaCodec.CodecException) error).getDiagnosticInfo() : error.getClass().getSimpleName();
|
|
57
|
+
return diagnostic + ": " + error.getMessage();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private void serve(String name) {
|
|
62
|
+
try (LocalSocket socket = new LocalSocket()) {
|
|
63
|
+
socket.connect(new LocalSocketAddress(name));
|
|
64
|
+
DataInputStream input = new DataInputStream(socket.getInputStream());
|
|
65
|
+
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
|
|
66
|
+
output.writeInt(0x54444232); // TDB2: rejection includes length-prefixed UTF-8 diagnostic
|
|
67
|
+
output.flush();
|
|
68
|
+
while (true) {
|
|
69
|
+
int requested = input.readInt();
|
|
70
|
+
String failure = applyBitrate(requested);
|
|
71
|
+
output.writeInt(failure == null ? requested : 0);
|
|
72
|
+
if (failure != null) {
|
|
73
|
+
byte[] detail = failure.substring(0, Math.min(512, failure.length())).getBytes(StandardCharsets.UTF_8);
|
|
74
|
+
output.writeInt(detail.length);
|
|
75
|
+
output.write(detail);
|
|
76
|
+
}
|
|
77
|
+
output.flush();
|
|
78
|
+
}
|
|
79
|
+
} catch (IOException ignored) {
|
|
80
|
+
// A bitrate-channel failure must never tear down video/control.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Override
|
|
85
|
+
public void onInvalidated() { reset(); }
|
|
86
|
+
}
|