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.
Files changed (330) hide show
  1. package/.desktop-dist/main.js +4 -3
  2. package/dist/client/assets/App-B_gjv_L4.js +156 -0
  3. package/dist/client/assets/App-B_gjv_L4.js.br +0 -0
  4. package/dist/client/assets/App-B_gjv_L4.js.gz +0 -0
  5. package/dist/client/assets/{ChangeWalkthroughPanel-N09mFFHb.js → ChangeWalkthroughPanel-B7xfrwV0.js} +2 -2
  6. package/dist/client/assets/ChangeWalkthroughPanel-B7xfrwV0.js.br +0 -0
  7. package/dist/client/assets/ChangeWalkthroughPanel-B7xfrwV0.js.gz +0 -0
  8. package/dist/client/assets/{DagPlayground-BjU87Tm4.js → DagPlayground-DD8Mudl0.js} +1 -1
  9. package/dist/client/assets/DagPlayground-DD8Mudl0.js.br +0 -0
  10. package/dist/client/assets/DagPlayground-DD8Mudl0.js.gz +0 -0
  11. package/dist/client/assets/{DiffLab-COA-b5pN.js → DiffLab-DfMaEfdB.js} +1 -1
  12. package/dist/client/assets/DiffLab-DfMaEfdB.js.br +0 -0
  13. package/dist/client/assets/DiffLab-DfMaEfdB.js.gz +0 -0
  14. package/dist/client/assets/{DiffReview-DPEzF3Wb.js → DiffReview-FIaqdDPy.js} +1 -1
  15. package/dist/client/assets/DiffReview-FIaqdDPy.js.br +0 -0
  16. package/dist/client/assets/DiffReview-FIaqdDPy.js.gz +0 -0
  17. package/dist/client/assets/{DiffReviewLab-Dq9gLO5P.js → DiffReviewLab-CkC9diid.js} +1 -1
  18. package/dist/client/assets/DiffReviewLab-CkC9diid.js.br +0 -0
  19. package/dist/client/assets/DiffReviewLab-CkC9diid.js.gz +0 -0
  20. package/dist/client/assets/DiffViewer-CYEoT3NM.js +37 -0
  21. package/dist/client/assets/DiffViewer-CYEoT3NM.js.br +0 -0
  22. package/dist/client/assets/DiffViewer-CYEoT3NM.js.gz +0 -0
  23. package/dist/client/assets/{ModelPreview-uqYy4UHn.js → ModelPreview-38AXZG5e.js} +1 -1
  24. package/dist/client/assets/ModelPreview-38AXZG5e.js.br +0 -0
  25. package/dist/client/assets/ModelPreview-38AXZG5e.js.gz +0 -0
  26. package/dist/client/assets/{RightSidebar-Do0_u2am.js → RightSidebar-A1dkYC_K.js} +4 -4
  27. package/dist/client/assets/RightSidebar-A1dkYC_K.js.br +0 -0
  28. package/dist/client/assets/RightSidebar-A1dkYC_K.js.gz +0 -0
  29. package/dist/client/assets/{abnfDiagram-VCTEODGH-C-F1hNwL.js → abnfDiagram-VCTEODGH-BvFKrJvp.js} +1 -1
  30. package/dist/client/assets/abnfDiagram-VCTEODGH-BvFKrJvp.js.br +0 -0
  31. package/dist/client/assets/abnfDiagram-VCTEODGH-BvFKrJvp.js.gz +0 -0
  32. package/dist/client/assets/{app-BB-UfzoN.js → app-CojGYCuR.js} +12 -12
  33. package/dist/client/assets/app-CojGYCuR.js.br +0 -0
  34. package/dist/client/assets/app-CojGYCuR.js.gz +0 -0
  35. package/dist/client/assets/{arc-Bj1HTggS.js → arc-KrauQCou.js} +1 -1
  36. package/dist/client/assets/arc-KrauQCou.js.br +0 -0
  37. package/dist/client/assets/arc-KrauQCou.js.gz +0 -0
  38. package/dist/client/assets/{architectureDiagram-5GKGNRK7-DiQ9VX2i.js → architectureDiagram-5GKGNRK7-m4EFlQe5.js} +1 -1
  39. package/dist/client/assets/architectureDiagram-5GKGNRK7-m4EFlQe5.js.br +0 -0
  40. package/dist/client/assets/{architectureDiagram-5GKGNRK7-DiQ9VX2i.js.gz → architectureDiagram-5GKGNRK7-m4EFlQe5.js.gz} +0 -0
  41. package/dist/client/assets/{blockDiagram-I7D4REHJ-Bs_OA90h.js → blockDiagram-I7D4REHJ-DYKVPCAg.js} +1 -1
  42. package/dist/client/assets/blockDiagram-I7D4REHJ-DYKVPCAg.js.br +0 -0
  43. package/dist/client/assets/blockDiagram-I7D4REHJ-DYKVPCAg.js.gz +0 -0
  44. package/dist/client/assets/{c4Diagram-7LVT6UL2-BF4InYpU.js → c4Diagram-7LVT6UL2-Bom-ry7C.js} +1 -1
  45. package/dist/client/assets/c4Diagram-7LVT6UL2-Bom-ry7C.js.br +0 -0
  46. package/dist/client/assets/c4Diagram-7LVT6UL2-Bom-ry7C.js.gz +0 -0
  47. package/dist/client/assets/channel-DPQ_m-tX.js +1 -0
  48. package/dist/client/assets/{chunk-2Q5K7J3B-Cagkfj0j.js → chunk-2Q5K7J3B-DruGlr2i.js} +1 -1
  49. package/dist/client/assets/{chunk-5VM5RSS4-CgX5Whwp.js → chunk-5VM5RSS4-BzuDLW6I.js} +1 -1
  50. package/dist/client/assets/{chunk-F27PBJKO-B8w3974i.js → chunk-F27PBJKO-BmOruelE.js} +1 -1
  51. package/dist/client/assets/chunk-F27PBJKO-BmOruelE.js.br +0 -0
  52. package/dist/client/assets/chunk-F27PBJKO-BmOruelE.js.gz +0 -0
  53. package/dist/client/assets/{chunk-IMKFNOWR-BgtujxgQ.js → chunk-IMKFNOWR-C_QAjdvx.js} +1 -1
  54. package/dist/client/assets/chunk-IMKFNOWR-C_QAjdvx.js.br +0 -0
  55. package/dist/client/assets/chunk-IMKFNOWR-C_QAjdvx.js.gz +0 -0
  56. package/dist/client/assets/{chunk-JWPE2WC7-Cf7NLgli.js → chunk-JWPE2WC7-COrvoLHM.js} +1 -1
  57. package/dist/client/assets/{chunk-POPQ4Y6H-BQst9Llh.js → chunk-POPQ4Y6H-B1ZbbBXT.js} +1 -1
  58. package/dist/client/assets/{chunk-SVP7TREG-D4PwA2QX.js → chunk-SVP7TREG-D1tHVHrA.js} +1 -1
  59. package/dist/client/assets/chunk-SVP7TREG-D1tHVHrA.js.br +0 -0
  60. package/dist/client/assets/chunk-SVP7TREG-D1tHVHrA.js.gz +0 -0
  61. package/dist/client/assets/{chunk-TICWLB2K-DHnYkG_x.js → chunk-TICWLB2K-CUf6WDYE.js} +1 -1
  62. package/dist/client/assets/chunk-TICWLB2K-CUf6WDYE.js.br +0 -0
  63. package/dist/client/assets/chunk-TICWLB2K-CUf6WDYE.js.gz +0 -0
  64. package/dist/client/assets/{chunk-XXDRQBXY-BHWFSVth.js → chunk-XXDRQBXY-DSiiDaTY.js} +1 -1
  65. package/dist/client/assets/classDiagram-ZZMXUADV-Kz6tCBai.js +1 -0
  66. package/dist/client/assets/classDiagram-v2-VYDZK3BY-Kz6tCBai.js +1 -0
  67. package/dist/client/assets/{cose-bilkent-JH36ORCC-CCFMhjak.js → cose-bilkent-JH36ORCC-T3qCojhn.js} +1 -1
  68. package/dist/client/assets/cose-bilkent-JH36ORCC-T3qCojhn.js.br +0 -0
  69. package/dist/client/assets/cose-bilkent-JH36ORCC-T3qCojhn.js.gz +0 -0
  70. package/dist/client/assets/{cynefin-OW5HDTMX-aeeCA73W.js → cynefin-OW5HDTMX-KpUgbXRL.js} +1 -1
  71. package/dist/client/assets/cynefin-OW5HDTMX-KpUgbXRL.js.br +0 -0
  72. package/dist/client/assets/cynefin-OW5HDTMX-KpUgbXRL.js.gz +0 -0
  73. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-Qd4yv-WB.js → cynefinDiagram-5FMLGOSQ-DPYl0L-K.js} +1 -1
  74. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DPYl0L-K.js.br +0 -0
  75. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-DPYl0L-K.js.gz +0 -0
  76. package/dist/client/assets/{dagre-GXQ25YYZ-tYsGlQq_.js → dagre-GXQ25YYZ-Bxp13G_N.js} +1 -1
  77. package/dist/client/assets/dagre-GXQ25YYZ-Bxp13G_N.js.br +0 -0
  78. package/dist/client/assets/dagre-GXQ25YYZ-Bxp13G_N.js.gz +0 -0
  79. package/dist/client/assets/{diagram-S7CK7UJ4-C1Bc6nbm.js → diagram-S7CK7UJ4-CpE50wgs.js} +1 -1
  80. package/dist/client/assets/diagram-S7CK7UJ4-CpE50wgs.js.br +0 -0
  81. package/dist/client/assets/diagram-S7CK7UJ4-CpE50wgs.js.gz +0 -0
  82. package/dist/client/assets/{diagram-UQ7AKVKN-SdvjJa7O.js → diagram-UQ7AKVKN-CQJFD7tB.js} +1 -1
  83. package/dist/client/assets/diagram-UQ7AKVKN-CQJFD7tB.js.br +0 -0
  84. package/dist/client/assets/diagram-UQ7AKVKN-CQJFD7tB.js.gz +0 -0
  85. package/dist/client/assets/{diagram-VSXAHHWV-CopEWwGT.js → diagram-VSXAHHWV-CcCMRaVS.js} +1 -1
  86. package/dist/client/assets/diagram-VSXAHHWV-CcCMRaVS.js.br +0 -0
  87. package/dist/client/assets/diagram-VSXAHHWV-CcCMRaVS.js.gz +0 -0
  88. package/dist/client/assets/{diagram-VX7I27RA-CKdAVxN-.js → diagram-VX7I27RA-BJHjGgyM.js} +1 -1
  89. package/dist/client/assets/diagram-VX7I27RA-BJHjGgyM.js.br +0 -0
  90. package/dist/client/assets/diagram-VX7I27RA-BJHjGgyM.js.gz +0 -0
  91. package/dist/client/assets/{diagram-Z3DM3KII-x9ISSrse.js → diagram-Z3DM3KII-Ctr0Mur_.js} +1 -1
  92. package/dist/client/assets/diagram-Z3DM3KII-Ctr0Mur_.js.br +0 -0
  93. package/dist/client/assets/diagram-Z3DM3KII-Ctr0Mur_.js.gz +0 -0
  94. package/dist/client/assets/{ebnfDiagram-PWID7BFC-Bta60dSv.js → ebnfDiagram-PWID7BFC-CKEPPhZD.js} +1 -1
  95. package/dist/client/assets/ebnfDiagram-PWID7BFC-CKEPPhZD.js.br +0 -0
  96. package/dist/client/assets/ebnfDiagram-PWID7BFC-CKEPPhZD.js.gz +0 -0
  97. package/dist/client/assets/{erDiagram-RLTQ6QDP-sB_bIQ0I.js → erDiagram-RLTQ6QDP-CFjw9WX4.js} +1 -1
  98. package/dist/client/assets/erDiagram-RLTQ6QDP-CFjw9WX4.js.br +0 -0
  99. package/dist/client/assets/erDiagram-RLTQ6QDP-CFjw9WX4.js.gz +0 -0
  100. package/dist/client/assets/{flowDiagram-HODETNUW-D-5EW4Om.js → flowDiagram-HODETNUW-ahJZ_2Y3.js} +1 -1
  101. package/dist/client/assets/flowDiagram-HODETNUW-ahJZ_2Y3.js.br +0 -0
  102. package/dist/client/assets/flowDiagram-HODETNUW-ahJZ_2Y3.js.gz +0 -0
  103. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-x4bF8XHI.js → ganttDiagram-EL5Y4UJY-CZvH1BVH.js} +1 -1
  104. package/dist/client/assets/ganttDiagram-EL5Y4UJY-CZvH1BVH.js.br +0 -0
  105. package/dist/client/assets/ganttDiagram-EL5Y4UJY-CZvH1BVH.js.gz +0 -0
  106. package/dist/client/assets/{gestureArbiter-C7V1_Sm6.js → gestureArbiter-CYcLJOkb.js} +1 -1
  107. package/dist/client/assets/gestureArbiter-CYcLJOkb.js.br +0 -0
  108. package/dist/client/assets/gestureArbiter-CYcLJOkb.js.gz +0 -0
  109. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-pKX7lvtX.js → gitGraphDiagram-WWUBYQGX-5k2btOuf.js} +1 -1
  110. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-5k2btOuf.js.br +0 -0
  111. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-5k2btOuf.js.gz +0 -0
  112. package/dist/client/assets/{index-CQGiUA31.css → index--h47b0ln.css} +1 -1
  113. package/dist/client/assets/index--h47b0ln.css.br +0 -0
  114. package/dist/client/assets/{index-CQGiUA31.css.gz → index--h47b0ln.css.gz} +0 -0
  115. package/dist/client/assets/{infoDiagram-27XIBGKW-ibYLF4lB.js → infoDiagram-27XIBGKW-B75F2r0B.js} +1 -1
  116. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BF0rhBil.js → ishikawaDiagram-5VMMS53U-D82lZtnM.js} +1 -1
  117. package/dist/client/assets/ishikawaDiagram-5VMMS53U-D82lZtnM.js.br +0 -0
  118. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BF0rhBil.js.gz → ishikawaDiagram-5VMMS53U-D82lZtnM.js.gz} +0 -0
  119. package/dist/client/assets/{journeyDiagram-3NMN7TZE-DR_bXhpA.js → journeyDiagram-3NMN7TZE-DDco1Uz5.js} +1 -1
  120. package/dist/client/assets/journeyDiagram-3NMN7TZE-DDco1Uz5.js.br +0 -0
  121. package/dist/client/assets/journeyDiagram-3NMN7TZE-DDco1Uz5.js.gz +0 -0
  122. package/dist/client/assets/{kanban-definition-UXKFOSKX-rLtDawpv.js → kanban-definition-UXKFOSKX-bFUaJw_7.js} +1 -1
  123. package/dist/client/assets/kanban-definition-UXKFOSKX-bFUaJw_7.js.br +0 -0
  124. package/dist/client/assets/kanban-definition-UXKFOSKX-bFUaJw_7.js.gz +0 -0
  125. package/dist/client/assets/{layout-abNq6Us0.js → layout-DqoIDxOD.js} +1 -1
  126. package/dist/client/assets/{layout-abNq6Us0.js.br → layout-DqoIDxOD.js.br} +0 -0
  127. package/dist/client/assets/{layout-abNq6Us0.js.gz → layout-DqoIDxOD.js.gz} +0 -0
  128. package/dist/client/assets/{linear-B6ZlmcfV.js → linear-iI_YMQHc.js} +1 -1
  129. package/dist/client/assets/linear-iI_YMQHc.js.br +0 -0
  130. package/dist/client/assets/linear-iI_YMQHc.js.gz +0 -0
  131. package/dist/client/assets/{mermaid.core-DH5DL9hV.js → mermaid.core-5yt2YuB8.js} +5 -5
  132. package/dist/client/assets/mermaid.core-5yt2YuB8.js.br +0 -0
  133. package/dist/client/assets/{mermaid.core-DH5DL9hV.js.gz → mermaid.core-5yt2YuB8.js.gz} +0 -0
  134. package/dist/client/assets/{mindmap-definition-YA3MSWOX-Bjmuduw6.js → mindmap-definition-YA3MSWOX-ChlqCeNZ.js} +1 -1
  135. package/dist/client/assets/mindmap-definition-YA3MSWOX-ChlqCeNZ.js.br +0 -0
  136. package/dist/client/assets/mindmap-definition-YA3MSWOX-ChlqCeNZ.js.gz +0 -0
  137. package/dist/client/assets/{passwordBootstrap-J17_f0uK.js → passwordBootstrap-CYPeNLru.js} +1 -1
  138. package/dist/client/assets/passwordBootstrap-CYPeNLru.js.br +0 -0
  139. package/dist/client/assets/passwordBootstrap-CYPeNLru.js.gz +0 -0
  140. package/dist/client/assets/{pegDiagram-XKGWAZYB-BVVc1guP.js → pegDiagram-XKGWAZYB-Crg6gf5W.js} +1 -1
  141. package/dist/client/assets/pegDiagram-XKGWAZYB-Crg6gf5W.js.br +0 -0
  142. package/dist/client/assets/pegDiagram-XKGWAZYB-Crg6gf5W.js.gz +0 -0
  143. package/dist/client/assets/{pieDiagram-E7YTZNPT-iyGrttc6.js → pieDiagram-E7YTZNPT-BXdoZQZj.js} +1 -1
  144. package/dist/client/assets/pieDiagram-E7YTZNPT-BXdoZQZj.js.br +0 -0
  145. package/dist/client/assets/pieDiagram-E7YTZNPT-BXdoZQZj.js.gz +0 -0
  146. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Djqtsu2z.js → quadrantDiagram-AXDQQJYC-DX07rl7R.js} +1 -1
  147. package/dist/client/assets/quadrantDiagram-AXDQQJYC-DX07rl7R.js.br +0 -0
  148. package/dist/client/assets/quadrantDiagram-AXDQQJYC-DX07rl7R.js.gz +0 -0
  149. package/dist/client/assets/{railroadDiagram-O6MQD6OU-C2ph9wgs.js → railroadDiagram-O6MQD6OU-C2ZzDGxp.js} +1 -1
  150. package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ZzDGxp.js.br +0 -0
  151. package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ZzDGxp.js.gz +0 -0
  152. package/dist/client/assets/{referenceLongPress-Bm0VuySQ.js → referenceLongPress-gi-7KSUT.js} +1 -1
  153. package/dist/client/assets/referenceLongPress-gi-7KSUT.js.br +0 -0
  154. package/dist/client/assets/referenceLongPress-gi-7KSUT.js.gz +0 -0
  155. package/dist/client/assets/{requirementDiagram-BXWQKSXE-vXjbhdRD.js → requirementDiagram-BXWQKSXE-FuuHXQEq.js} +1 -1
  156. package/dist/client/assets/requirementDiagram-BXWQKSXE-FuuHXQEq.js.br +0 -0
  157. package/dist/client/assets/requirementDiagram-BXWQKSXE-FuuHXQEq.js.gz +0 -0
  158. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-SNiiKcgp.js → sankeyDiagram-P5KCCOFB-Bk1BrUVk.js} +1 -1
  159. package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bk1BrUVk.js.br +0 -0
  160. package/dist/client/assets/sankeyDiagram-P5KCCOFB-Bk1BrUVk.js.gz +0 -0
  161. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-Fn2oExLH.js → sequenceDiagram-WJ2MYXX4-9A9f6S8W.js} +1 -1
  162. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-9A9f6S8W.js.br +0 -0
  163. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-9A9f6S8W.js.gz +0 -0
  164. package/dist/client/assets/{sizeCapture-INFHLROL-FoHuOCXL.js → sizeCapture-INFHLROL-DQBQsVnW.js} +1 -1
  165. package/dist/client/assets/sizeCapture-INFHLROL-DQBQsVnW.js.br +0 -0
  166. package/dist/client/assets/sizeCapture-INFHLROL-DQBQsVnW.js.gz +0 -0
  167. package/dist/client/assets/{sparkles-BpV0BVRF.js → sparkles-VMoDkivK.js} +1 -1
  168. package/dist/client/assets/{stateDiagram-D77RDMKH-BiBiBFDH.js → stateDiagram-D77RDMKH-BXufbeMX.js} +1 -1
  169. package/dist/client/assets/stateDiagram-D77RDMKH-BXufbeMX.js.br +0 -0
  170. package/dist/client/assets/stateDiagram-D77RDMKH-BXufbeMX.js.gz +0 -0
  171. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-QrSvO0ee.js +1 -0
  172. package/dist/client/assets/{swimlanes-42K2YHIH-8_6AEHBA.js → swimlanes-42K2YHIH-DrRwVG23.js} +1 -1
  173. package/dist/client/assets/swimlanes-42K2YHIH-DrRwVG23.js.br +0 -0
  174. package/dist/client/assets/swimlanes-42K2YHIH-DrRwVG23.js.gz +0 -0
  175. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-C1DRM79Q.js +8 -0
  176. package/dist/client/assets/{timeline-definition-24CTP7MA-vh_kdWEp.js → timeline-definition-24CTP7MA-CWgWzJ8C.js} +1 -1
  177. package/dist/client/assets/timeline-definition-24CTP7MA-CWgWzJ8C.js.br +0 -0
  178. package/dist/client/assets/timeline-definition-24CTP7MA-CWgWzJ8C.js.gz +0 -0
  179. package/dist/client/assets/{triangle-alert-BDY-HlS4.js → triangle-alert-BvcHjqm6.js} +1 -1
  180. package/dist/client/assets/{vennDiagram-4TSXK5OY-DD1-E-ya.js → vennDiagram-4TSXK5OY-CRUebJIC.js} +1 -1
  181. package/dist/client/assets/vennDiagram-4TSXK5OY-CRUebJIC.js.br +0 -0
  182. package/dist/client/assets/vennDiagram-4TSXK5OY-CRUebJIC.js.gz +0 -0
  183. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-HMOrL8bB.js → wardleyDiagram-VM6X3IG4-BFSHgvns.js} +1 -1
  184. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BFSHgvns.js.br +0 -0
  185. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BFSHgvns.js.gz +0 -0
  186. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DUxhnGCd.js → xychartDiagram-S5SC5T6Z-B9YiYLj1.js} +1 -1
  187. package/dist/client/assets/xychartDiagram-S5SC5T6Z-B9YiYLj1.js.br +0 -0
  188. package/dist/client/assets/xychartDiagram-S5SC5T6Z-B9YiYLj1.js.gz +0 -0
  189. package/dist/client/index.html +2 -2
  190. package/dist/client/index.html.br +0 -0
  191. package/dist/client/index.html.gz +0 -0
  192. package/dist/client/sw.js +1 -1
  193. package/dist/client/sw.js.br +0 -0
  194. package/dist/client/sw.js.gz +0 -0
  195. package/dist/server/android/liveBitrate.js +162 -0
  196. package/dist/server/android/scrcpy.js +51 -5
  197. package/dist/server/cli.js +1 -1
  198. package/dist/server/entry.js +1 -1
  199. package/dist/server/federation/runtime.js +1 -1
  200. package/dist/server/onboardingServer.js +1 -2
  201. package/dist/server/routes/android.js +11 -0
  202. package/dist/server/routes/filesystem.js +29 -15
  203. package/dist/server/routes/onboarding.js +0 -99
  204. package/dist/server/utils/localAccess.js +1 -1
  205. package/package.json +1 -1
  206. package/runtime-manifest.json +3 -3
  207. package/scripts/android-bitrate/CaptureReset.java +86 -0
  208. package/scripts/android-bitrate/LICENSE +203 -0
  209. package/scripts/android-bitrate/README.md +50 -0
  210. package/scripts/android-bitrate/bitrate.jar +0 -0
  211. package/scripts/android-bitrate/build.sh +28 -0
  212. package/scripts/android-bitrate/fetch-server.sh +12 -0
  213. package/scripts/android-bitrate/scrcpy-server-v3.3.4 +0 -0
  214. package/dist/client/assets/App-DzRCmm_W.js +0 -156
  215. package/dist/client/assets/App-DzRCmm_W.js.br +0 -0
  216. package/dist/client/assets/App-DzRCmm_W.js.gz +0 -0
  217. package/dist/client/assets/ChangeWalkthroughPanel-N09mFFHb.js.br +0 -0
  218. package/dist/client/assets/ChangeWalkthroughPanel-N09mFFHb.js.gz +0 -0
  219. package/dist/client/assets/DagPlayground-BjU87Tm4.js.br +0 -0
  220. package/dist/client/assets/DagPlayground-BjU87Tm4.js.gz +0 -0
  221. package/dist/client/assets/DiffLab-COA-b5pN.js.br +0 -0
  222. package/dist/client/assets/DiffLab-COA-b5pN.js.gz +0 -0
  223. package/dist/client/assets/DiffReview-DPEzF3Wb.js.br +0 -0
  224. package/dist/client/assets/DiffReview-DPEzF3Wb.js.gz +0 -0
  225. package/dist/client/assets/DiffReviewLab-Dq9gLO5P.js.br +0 -0
  226. package/dist/client/assets/DiffReviewLab-Dq9gLO5P.js.gz +0 -0
  227. package/dist/client/assets/DiffViewer-DNd0R8FA.js +0 -37
  228. package/dist/client/assets/DiffViewer-DNd0R8FA.js.br +0 -0
  229. package/dist/client/assets/DiffViewer-DNd0R8FA.js.gz +0 -0
  230. package/dist/client/assets/ModelPreview-uqYy4UHn.js.br +0 -0
  231. package/dist/client/assets/ModelPreview-uqYy4UHn.js.gz +0 -0
  232. package/dist/client/assets/RightSidebar-Do0_u2am.js.br +0 -0
  233. package/dist/client/assets/RightSidebar-Do0_u2am.js.gz +0 -0
  234. package/dist/client/assets/abnfDiagram-VCTEODGH-C-F1hNwL.js.br +0 -0
  235. package/dist/client/assets/abnfDiagram-VCTEODGH-C-F1hNwL.js.gz +0 -0
  236. package/dist/client/assets/app-BB-UfzoN.js.br +0 -0
  237. package/dist/client/assets/app-BB-UfzoN.js.gz +0 -0
  238. package/dist/client/assets/arc-Bj1HTggS.js.br +0 -0
  239. package/dist/client/assets/arc-Bj1HTggS.js.gz +0 -0
  240. package/dist/client/assets/architectureDiagram-5GKGNRK7-DiQ9VX2i.js.br +0 -0
  241. package/dist/client/assets/blockDiagram-I7D4REHJ-Bs_OA90h.js.br +0 -0
  242. package/dist/client/assets/blockDiagram-I7D4REHJ-Bs_OA90h.js.gz +0 -0
  243. package/dist/client/assets/c4Diagram-7LVT6UL2-BF4InYpU.js.br +0 -0
  244. package/dist/client/assets/c4Diagram-7LVT6UL2-BF4InYpU.js.gz +0 -0
  245. package/dist/client/assets/channel-D4Mx8Qe2.js +0 -1
  246. package/dist/client/assets/chunk-F27PBJKO-B8w3974i.js.br +0 -0
  247. package/dist/client/assets/chunk-F27PBJKO-B8w3974i.js.gz +0 -0
  248. package/dist/client/assets/chunk-IMKFNOWR-BgtujxgQ.js.br +0 -0
  249. package/dist/client/assets/chunk-IMKFNOWR-BgtujxgQ.js.gz +0 -0
  250. package/dist/client/assets/chunk-SVP7TREG-D4PwA2QX.js.br +0 -0
  251. package/dist/client/assets/chunk-SVP7TREG-D4PwA2QX.js.gz +0 -0
  252. package/dist/client/assets/chunk-TICWLB2K-DHnYkG_x.js.br +0 -0
  253. package/dist/client/assets/chunk-TICWLB2K-DHnYkG_x.js.gz +0 -0
  254. package/dist/client/assets/classDiagram-ZZMXUADV-e0EybKcM.js +0 -1
  255. package/dist/client/assets/classDiagram-v2-VYDZK3BY-e0EybKcM.js +0 -1
  256. package/dist/client/assets/cose-bilkent-JH36ORCC-CCFMhjak.js.br +0 -0
  257. package/dist/client/assets/cose-bilkent-JH36ORCC-CCFMhjak.js.gz +0 -0
  258. package/dist/client/assets/cynefin-OW5HDTMX-aeeCA73W.js.br +0 -0
  259. package/dist/client/assets/cynefin-OW5HDTMX-aeeCA73W.js.gz +0 -0
  260. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Qd4yv-WB.js.br +0 -0
  261. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Qd4yv-WB.js.gz +0 -0
  262. package/dist/client/assets/dagre-GXQ25YYZ-tYsGlQq_.js.br +0 -0
  263. package/dist/client/assets/dagre-GXQ25YYZ-tYsGlQq_.js.gz +0 -0
  264. package/dist/client/assets/diagram-S7CK7UJ4-C1Bc6nbm.js.br +0 -0
  265. package/dist/client/assets/diagram-S7CK7UJ4-C1Bc6nbm.js.gz +0 -0
  266. package/dist/client/assets/diagram-UQ7AKVKN-SdvjJa7O.js.br +0 -0
  267. package/dist/client/assets/diagram-UQ7AKVKN-SdvjJa7O.js.gz +0 -0
  268. package/dist/client/assets/diagram-VSXAHHWV-CopEWwGT.js.br +0 -0
  269. package/dist/client/assets/diagram-VSXAHHWV-CopEWwGT.js.gz +0 -0
  270. package/dist/client/assets/diagram-VX7I27RA-CKdAVxN-.js.br +0 -0
  271. package/dist/client/assets/diagram-VX7I27RA-CKdAVxN-.js.gz +0 -0
  272. package/dist/client/assets/diagram-Z3DM3KII-x9ISSrse.js.br +0 -0
  273. package/dist/client/assets/diagram-Z3DM3KII-x9ISSrse.js.gz +0 -0
  274. package/dist/client/assets/ebnfDiagram-PWID7BFC-Bta60dSv.js.br +0 -0
  275. package/dist/client/assets/ebnfDiagram-PWID7BFC-Bta60dSv.js.gz +0 -0
  276. package/dist/client/assets/erDiagram-RLTQ6QDP-sB_bIQ0I.js.br +0 -0
  277. package/dist/client/assets/erDiagram-RLTQ6QDP-sB_bIQ0I.js.gz +0 -0
  278. package/dist/client/assets/flowDiagram-HODETNUW-D-5EW4Om.js.br +0 -0
  279. package/dist/client/assets/flowDiagram-HODETNUW-D-5EW4Om.js.gz +0 -0
  280. package/dist/client/assets/ganttDiagram-EL5Y4UJY-x4bF8XHI.js.br +0 -0
  281. package/dist/client/assets/ganttDiagram-EL5Y4UJY-x4bF8XHI.js.gz +0 -0
  282. package/dist/client/assets/gestureArbiter-C7V1_Sm6.js.br +0 -0
  283. package/dist/client/assets/gestureArbiter-C7V1_Sm6.js.gz +0 -0
  284. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-pKX7lvtX.js.br +0 -0
  285. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-pKX7lvtX.js.gz +0 -0
  286. package/dist/client/assets/index-CQGiUA31.css.br +0 -0
  287. package/dist/client/assets/ishikawaDiagram-5VMMS53U-BF0rhBil.js.br +0 -0
  288. package/dist/client/assets/journeyDiagram-3NMN7TZE-DR_bXhpA.js.br +0 -0
  289. package/dist/client/assets/journeyDiagram-3NMN7TZE-DR_bXhpA.js.gz +0 -0
  290. package/dist/client/assets/kanban-definition-UXKFOSKX-rLtDawpv.js.br +0 -0
  291. package/dist/client/assets/kanban-definition-UXKFOSKX-rLtDawpv.js.gz +0 -0
  292. package/dist/client/assets/linear-B6ZlmcfV.js.br +0 -0
  293. package/dist/client/assets/linear-B6ZlmcfV.js.gz +0 -0
  294. package/dist/client/assets/mermaid.core-DH5DL9hV.js.br +0 -0
  295. package/dist/client/assets/mindmap-definition-YA3MSWOX-Bjmuduw6.js.br +0 -0
  296. package/dist/client/assets/mindmap-definition-YA3MSWOX-Bjmuduw6.js.gz +0 -0
  297. package/dist/client/assets/passwordBootstrap-J17_f0uK.js.br +0 -0
  298. package/dist/client/assets/passwordBootstrap-J17_f0uK.js.gz +0 -0
  299. package/dist/client/assets/pegDiagram-XKGWAZYB-BVVc1guP.js.br +0 -0
  300. package/dist/client/assets/pegDiagram-XKGWAZYB-BVVc1guP.js.gz +0 -0
  301. package/dist/client/assets/pieDiagram-E7YTZNPT-iyGrttc6.js.br +0 -0
  302. package/dist/client/assets/pieDiagram-E7YTZNPT-iyGrttc6.js.gz +0 -0
  303. package/dist/client/assets/quadrantDiagram-AXDQQJYC-Djqtsu2z.js.br +0 -0
  304. package/dist/client/assets/quadrantDiagram-AXDQQJYC-Djqtsu2z.js.gz +0 -0
  305. package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ph9wgs.js.br +0 -0
  306. package/dist/client/assets/railroadDiagram-O6MQD6OU-C2ph9wgs.js.gz +0 -0
  307. package/dist/client/assets/referenceLongPress-Bm0VuySQ.js.br +0 -0
  308. package/dist/client/assets/referenceLongPress-Bm0VuySQ.js.gz +0 -0
  309. package/dist/client/assets/requirementDiagram-BXWQKSXE-vXjbhdRD.js.br +0 -0
  310. package/dist/client/assets/requirementDiagram-BXWQKSXE-vXjbhdRD.js.gz +0 -0
  311. package/dist/client/assets/sankeyDiagram-P5KCCOFB-SNiiKcgp.js.br +0 -0
  312. package/dist/client/assets/sankeyDiagram-P5KCCOFB-SNiiKcgp.js.gz +0 -0
  313. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Fn2oExLH.js.br +0 -0
  314. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Fn2oExLH.js.gz +0 -0
  315. package/dist/client/assets/sizeCapture-INFHLROL-FoHuOCXL.js.br +0 -0
  316. package/dist/client/assets/sizeCapture-INFHLROL-FoHuOCXL.js.gz +0 -0
  317. package/dist/client/assets/stateDiagram-D77RDMKH-BiBiBFDH.js.br +0 -0
  318. package/dist/client/assets/stateDiagram-D77RDMKH-BiBiBFDH.js.gz +0 -0
  319. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-_Vs6ah69.js +0 -1
  320. package/dist/client/assets/swimlanes-42K2YHIH-8_6AEHBA.js.br +0 -0
  321. package/dist/client/assets/swimlanes-42K2YHIH-8_6AEHBA.js.gz +0 -0
  322. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DCbcOwps.js +0 -8
  323. package/dist/client/assets/timeline-definition-24CTP7MA-vh_kdWEp.js.br +0 -0
  324. package/dist/client/assets/timeline-definition-24CTP7MA-vh_kdWEp.js.gz +0 -0
  325. package/dist/client/assets/vennDiagram-4TSXK5OY-DD1-E-ya.js.br +0 -0
  326. package/dist/client/assets/vennDiagram-4TSXK5OY-DD1-E-ya.js.gz +0 -0
  327. package/dist/client/assets/wardleyDiagram-VM6X3IG4-HMOrL8bB.js.br +0 -0
  328. package/dist/client/assets/wardleyDiagram-VM6X3IG4-HMOrL8bB.js.gz +0 -0
  329. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DUxhnGCd.js.br +0 -0
  330. 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 = Buffer.from(this.videoBuffer.subarray(FRAME_HEADER_LENGTH, FRAME_HEADER_LENGTH + size));
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
  }
@@ -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('Setup:')} ${c.cyan(state.onboardingUrl)} ${c.dim('(open this on your phone to download the CA certificate)')}`);
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}`);
@@ -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(`Mobile setup: ${onboardingUrl} (open this on your phone to download the CA certificate)`);
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}/onboarding` : null;
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
- let baseRef = trimmedBase.includes('/') ? trimmedBase : `origin/${trimmedBase}`;
2293
- if (trimmedBase.includes('/')) {
2294
- await execGit(['rev-parse', '--verify', '--quiet', baseRef], repoRoot, signal);
2295
- }
2296
- else {
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
- await execGit(['fetch', 'origin', trimmedBase, '--no-tags'], repoRoot, signal, GIT_ROUTE_TIMEOUT_MS);
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
- const localRef = await execGit(['rev-parse', '--verify', '--quiet', trimmedBase], repoRoot, signal)
2302
- .then(() => trimmedBase)
2303
- .catch(() => null);
2304
- if (!localRef)
2311
+ if (signal.aborted)
2305
2312
  throw error;
2306
- baseRef = localRef;
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', baseRef, compareHead], repoRoot, signal)
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 ?? `${baseRef}...${compareHead}`;
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', `${baseRef}..${compareHead}`, '--oneline', '--no-merges'], repoRoot, MAX_BRANCH_DIFF_LOG_BYTES, false, signal),
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, baseRef, parseBranchDiffHunks(diff), signal);
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, '&amp;')
13
- .replace(/</g, '&lt;')
14
- .replace(/>/g, '&gt;')
15
- .replace(/"/g, '&quot;')
16
- .replace(/'/g, '&#39;');
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 &lt;path&gt; 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}/onboarding` : null,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termdock",
3
- "version": "1.4.266",
3
+ "version": "1.4.268",
4
4
  "description": "A complete web-based terminal application with modern UI",
5
5
  "type": "module",
6
6
  "main": ".desktop-dist/main.js",
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "packageName": "termdock",
4
- "version": "1.4.266",
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-OzEmGLQ2089pXmDouFuQcJQt6ZHuQfArddq3xlvkjrU=",
10
- "clientBundleHash": "sha256-SM1viL4lDEGX0IJs/ltbippjKurPa5ahbqiu8hL2BcQ=",
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
+ }