@hienlh/ppm 0.21.0 → 0.22.1

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 (620) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/CLAUDE.md +29 -4
  3. package/THIRD-PARTY-NOTICES.md +1 -1
  4. package/assets/skills/ppm/SKILL.md +1 -1
  5. package/assets/skills/ppm/references/cli-reference.md +4 -4
  6. package/assets/skills/ppm/references/http-api.md +1 -1
  7. package/bun.lock +16 -1
  8. package/dist/web/assets/accounts-settings-section-D3BylchP.js +1 -0
  9. package/dist/web/assets/{ai-resource-editor-F09pf8Hd.js → ai-resource-editor-BLPcnhTM.js} +1 -1
  10. package/dist/web/assets/ai-settings-section-BtR7rF-T.js +1 -0
  11. package/dist/web/assets/ai-settings-section-r9JctHNM.js +1 -0
  12. package/dist/web/assets/{angular-html-DkR4iCth.js → angular-html-G66FNlyn.js} +1 -1
  13. package/dist/web/assets/{angular-ts-DcyL4Chx.js → angular-ts-B-PnUMyt.js} +1 -1
  14. package/dist/web/assets/{api-client-bfB7cXRM.js → api-client-C1ZwRL4Y.js} +1 -1
  15. package/dist/web/assets/api-client-pQL53cDQ.js +1 -0
  16. package/dist/web/assets/{api-settings-BcNjZIvG.js → api-settings-_7Q-ULxp.js} +1 -1
  17. package/dist/web/assets/{api-themes-DBfyVUtX.js → api-themes-DRAERo4Q.js} +1 -1
  18. package/dist/web/assets/{apl-BVlrVtjt.js → apl-BmDqqwE8.js} +1 -1
  19. package/dist/web/assets/{appearance-settings-section-whgnq3ss.js → appearance-settings-section-CiMdk3sb.js} +1 -1
  20. package/dist/web/assets/architecture-PBZL5I3N-Dx6nBEKT.js +1 -0
  21. package/dist/web/assets/{astro-MjJlozLj.js → astro-BfwMNfxr.js} +1 -1
  22. package/dist/web/assets/{audio-preview-Bc54GCAV.js → audio-preview-DsYvgKqj.js} +1 -1
  23. package/dist/web/assets/{blade-DnJWi1fz.js → blade-BsFV4pnN.js} +1 -1
  24. package/dist/web/assets/branch-review-tab-B1pFjlKM.js +1 -0
  25. package/dist/web/assets/{bsl-DCmJxSIz.js → bsl-Cw9Outng.js} +1 -1
  26. package/dist/web/assets/{button-VW4QGKCn.js → button-B9CTrsEf.js} +1 -1
  27. package/dist/web/assets/{cairo-C8dDenub.js → cairo-DOK5Wqnd.js} +1 -1
  28. package/dist/web/assets/chat-tab-DZagX06m.js +15 -0
  29. package/dist/web/assets/{cobol-DPx_nifl.js → cobol-DRaRy4FK.js} +1 -1
  30. package/dist/web/assets/code-editor-BJhOEsnZ.js +7 -0
  31. package/dist/web/assets/{codex-daily-guard-CfybHv_c.js → codex-daily-guard-CaCQJ4r_.js} +1 -1
  32. package/dist/web/assets/{coffee-DvFzqhgN.js → coffee-DvXuBmEJ.js} +1 -1
  33. package/dist/web/assets/{conflict-editor-DenQUOT2.js → conflict-editor-B7u_p49h.js} +3 -3
  34. package/dist/web/assets/context-menu-C6pIsf83.js +1 -0
  35. package/dist/web/assets/{cpp-BLJN0umi.js → cpp-zCmm8rKA.js} +1 -1
  36. package/dist/web/assets/{crystal-BXR-9fGw.js → crystal-CdQx6lB6.js} +1 -1
  37. package/dist/web/assets/{csv-preview-CClrJOuR.js → csv-preview-CttjJU1e.js} +1 -1
  38. package/dist/web/assets/{data-grid-overlay-editor-D4fhcMfT.js → data-grid-overlay-editor-6xUCeLHh.js} +1 -1
  39. package/dist/web/assets/{database-viewer-DItjm8wB.js → database-viewer-Ca4HxIfx.js} +1 -1
  40. package/dist/web/assets/{dialog-DQTn55Mt.js → dialog-B84_DJQ8.js} +1 -1
  41. package/dist/web/assets/diff-viewer-9-XjLIwa.js +4 -0
  42. package/dist/web/assets/{docx-preview-DYBkiUaE.js → docx-preview-CXuk-emm.js} +1 -1
  43. package/dist/web/assets/{edge-rWOlCmXT.js → edge-E8QLt7oi.js} +1 -1
  44. package/dist/web/assets/{edit-diff-preview-COtmo54G.js → edit-diff-preview-BGGGecVw.js} +1 -1
  45. package/dist/web/assets/{editor-language-service-DxkZ51E5.js → editor-language-service-D0DuEOs_.js} +1 -1
  46. package/dist/web/assets/{elixir-E7Y82okW.js → elixir-DPb_-72P.js} +1 -1
  47. package/dist/web/assets/{elm-DTPGbc-w.js → elm-BMzJY5b0.js} +1 -1
  48. package/dist/web/assets/{erb-DHqLHrE6.js → erb-AABQNtMK.js} +1 -1
  49. package/dist/web/assets/{erlang-Byg0nNiV.js → erlang-CEIKOkfP.js} +1 -1
  50. package/dist/web/assets/{esm-D_DmOM7n.js → esm-B9RVMpwV.js} +1 -1
  51. package/dist/web/assets/explorer-body-VdCBqcZu.js +2 -0
  52. package/dist/web/assets/explorer-window-content-BIsbl7Th.js +1 -0
  53. package/dist/web/assets/extension-manager-section-HkY7geS5.js +1 -0
  54. package/dist/web/assets/{extension-webview-DI4VL2tJ.js → extension-webview-DZG8YHX9.js} +1 -1
  55. package/dist/web/assets/file-icons-BXdvggK2.js +1 -0
  56. package/dist/web/assets/file-icons.generated-BtBErEwb.css +1 -0
  57. package/dist/web/assets/file-store-ojgMXgAw.js +1 -0
  58. package/dist/web/assets/files-settings-section-qnRtkX05.js +1 -0
  59. package/dist/web/assets/{format-file-meta-DOpzJJhS.js → format-file-meta-C77h04cZ.js} +1 -1
  60. package/dist/web/assets/{fortran-fixed-form-CY1n0Xf6.js → fortran-fixed-form-CrXvLHyi.js} +1 -1
  61. package/dist/web/assets/{fsharp-_vEDSCJz.js → fsharp-DCI4qAz_.js} +1 -1
  62. package/dist/web/assets/{gdresource-B6XT0wAC.js → gdresource-Vb2kO1MG.js} +1 -1
  63. package/dist/web/assets/{general-settings-section-BcxwiZ0X.js → general-settings-section-BAFSZmCE.js} +1 -1
  64. package/dist/web/assets/{git-commit-Wk9ovq59.js → git-commit-BMI_OWn-.js} +1 -1
  65. package/dist/web/assets/git-log-panel-2sGpfEla.js +1 -0
  66. package/dist/web/assets/{git-rebase-DSarGPvK.js → git-rebase-D-d_2iqZ.js} +1 -1
  67. package/dist/web/assets/{git-repo-store-Dy69YCHN.js → git-repo-store-88Z8v-pF.js} +1 -1
  68. package/dist/web/assets/gitGraph-HDMCJU4V-C6qRruHI.js +1 -0
  69. package/dist/web/assets/{glide-data-grid-BvgAqSUr.js → glide-data-grid-f0hyITiF.js} +7 -7
  70. package/dist/web/assets/{glimmer-js-CkYI35_P.js → glimmer-js-BmNNiR0Z.js} +1 -1
  71. package/dist/web/assets/{glimmer-ts-BqmIZcds.js → glimmer-ts-DQE2Ufha.js} +1 -1
  72. package/dist/web/assets/{glsl-Be-yBCF5.js → glsl-BcIDsxRJ.js} +1 -1
  73. package/dist/web/assets/{graphql-a5DrENHY.js → graphql-DGKSLmGH.js} +1 -1
  74. package/dist/web/assets/group-chat-tab-Ck6sk7yY.js +1 -0
  75. package/dist/web/assets/{hack-BLAg20aD.js → hack-YiC8bEIb.js} +1 -1
  76. package/dist/web/assets/{haml-Dj6bGOQH.js → haml-DjblxAsz.js} +1 -1
  77. package/dist/web/assets/{handlebars-dmEa36Oh.js → handlebars-BQepOXaU.js} +1 -1
  78. package/dist/web/assets/{html-yacZYzSE.js → html-Cayj_2GP.js} +1 -1
  79. package/dist/web/assets/{html-derivative-lLi3-RNT.js → html-derivative-Weq79bL6.js} +1 -1
  80. package/dist/web/assets/{http-1KaxcE4e.js → http-BeLfdGdz.js} +1 -1
  81. package/dist/web/assets/{hurl-ST-dEEZR.js → hurl-D9rypCLK.js} +1 -1
  82. package/dist/web/assets/{hxml-CpDtuq__.js → hxml-clG8mmSH.js} +1 -1
  83. package/dist/web/assets/{image-preview-CJVxL0uH.js → image-preview-CzCc4_Do.js} +1 -1
  84. package/dist/web/assets/image-preview-geometry-9lgeLYB3.js +1 -0
  85. package/dist/web/assets/index-BH99TIE0.css +1 -0
  86. package/dist/web/assets/index-CEZVxM4G.js +52 -0
  87. package/dist/web/assets/info-3K5VOQVL-BOSpdwlz.js +1 -0
  88. package/dist/web/assets/{jinja-Cjw-evAn.js → jinja-BShBWfs5.js} +1 -1
  89. package/dist/web/assets/{jira-watcher-section-DIC1yIV3.js → jira-watcher-section-CeLmhvu1.js} +1 -1
  90. package/dist/web/assets/{jison-DfATMYoY.js → jison-dN2Nf_Dr.js} +1 -1
  91. package/dist/web/assets/{julia-DDCaxiqT.js → julia-5U0vR-uJ.js} +1 -1
  92. package/dist/web/assets/{just-CJL529u6.js → just-BMppVRy6.js} +1 -1
  93. package/dist/web/assets/keybindings-store-C_3ChOEf.js +1 -0
  94. package/dist/web/assets/{keyboard-shortcuts-section-BW03P3AF.js → keyboard-shortcuts-section-PVz6kuh2.js} +1 -1
  95. package/dist/web/assets/{latex-Zc4EpLpW.js → latex-DSSOKjis.js} +1 -1
  96. package/dist/web/assets/{liquid-B_6KMNYS.js → liquid-C24dKoyI.js} +1 -1
  97. package/dist/web/assets/{lua-BtS2idK7.js → lua-DNOsnyhn.js} +1 -1
  98. package/dist/web/assets/{markdown-renderer-CvL1pWeK.js → markdown-renderer-C140Ijk0.js} +3 -3
  99. package/dist/web/assets/markdown-renderer-Dz7-DYUg.js +1 -0
  100. package/dist/web/assets/{marko-Wk6LBnck.js → marko-26MHO_Q9.js} +1 -1
  101. package/dist/web/assets/{mdc-cRaXBrzL.js → mdc-Dhw9mGrC.js} +1 -1
  102. package/dist/web/assets/{media-url-DL8OCGGg.js → media-url-yfqHpPz0.js} +1 -1
  103. package/dist/web/assets/{mobile-bottom-sheet-CoUauvLF.js → mobile-bottom-sheet-C3TniEP-.js} +1 -1
  104. package/dist/web/assets/mobile-explorer-sheet-CUG_owdf.js +1 -0
  105. package/dist/web/assets/{nextflow-Bos2wvDV.js → nextflow-xH4oJTex.js} +1 -1
  106. package/dist/web/assets/{nginx-DMlOwzdr.js → nginx-CMz4w0M8.js} +1 -1
  107. package/dist/web/assets/{nim-D2dZQA88.js → nim-D8FnIYsx.js} +1 -1
  108. package/dist/web/assets/notification-store-6vib1ISy.js +1 -0
  109. package/dist/web/assets/{notifications-settings-section-DPUROMw-.js → notifications-settings-section-DqlPDfNX.js} +1 -1
  110. package/dist/web/assets/{number-overlay-editor-DZ2i_Bnb.js → number-overlay-editor-CRGwULhR.js} +1 -1
  111. package/dist/web/assets/{overview-panel-R146OIom.js → overview-panel-Di-3aV9p.js} +1 -1
  112. package/dist/web/assets/packet-RMMSAZCW-BGIE1QdU.js +1 -0
  113. package/dist/web/assets/panel-store-CboGJAwh.js +1 -0
  114. package/dist/web/assets/{pdf-preview-BWUPGLp6.js → pdf-preview-CmBI6E7d.js} +1 -1
  115. package/dist/web/assets/{perl-C5-Z6fPn.js → perl-D9iNWYwb.js} +1 -1
  116. package/dist/web/assets/{php-BXNNhkMH.js → php-Bw3Qo0Zv.js} +1 -1
  117. package/dist/web/assets/pie-UPGHQEXC-Dg-QTbXX.js +1 -0
  118. package/dist/web/assets/{postgres-viewer-CjOvaruz.js → postgres-viewer-8ZAqEALv.js} +3 -3
  119. package/dist/web/assets/{ppmbot-settings-section-DrvWh8l8.js → ppmbot-settings-section-Cji-Mil-.js} +1 -1
  120. package/dist/web/assets/problems-panel-a6_hrWvl.js +1 -0
  121. package/dist/web/assets/{process-table-BRMS1MrX.js → process-table-CiIqlOIK.js} +1 -1
  122. package/dist/web/assets/project-framework-store-B70Q3dNM.js +1 -0
  123. package/dist/web/assets/project-store-B87hLRSk.js +1 -0
  124. package/dist/web/assets/{proxy-settings-section-Bv0Ny-Yy.js → proxy-settings-section-BjI4IFgp.js} +1 -1
  125. package/dist/web/assets/{pug-C1zf1yWy.js → pug-fT5JC6Vm.js} +1 -1
  126. package/dist/web/assets/{qml-OW58jGpD.js → qml-P_wEDB1w.js} +1 -1
  127. package/dist/web/assets/{query-audit-section-BcHJZcVC.js → query-audit-section-By6qyqdB.js} +1 -1
  128. package/dist/web/assets/radar-KQ55EAFF-DZ6IVu2s.js +1 -0
  129. package/dist/web/assets/{razor-DzjSaobM.js → razor-Drrt2_Ph.js} +1 -1
  130. package/dist/web/assets/remote-desktop-clipboard-notice-eXYvwgx7.js +1 -0
  131. package/dist/web/assets/remote-desktop-mobile-sheet-Doh-fci-.js +2 -0
  132. package/dist/web/assets/remote-desktop-mobile-view-Dt8Akc3p.js +1 -0
  133. package/dist/web/assets/{remote-desktop-readiness-gate-BTzss2wX.js → remote-desktop-readiness-gate-t83fqbID.js} +1 -1
  134. package/dist/web/assets/remote-desktop-window-content-CguhZMmx.js +1 -0
  135. package/dist/web/assets/{rst-RfuihOUW.js → rst-Dr2mW4-h.js} +1 -1
  136. package/dist/web/assets/{ruby-CNO3pli1.js → ruby-C6EpUsTY.js} +1 -1
  137. package/dist/web/assets/{run-in-terminal-Cb_hVU8x.js → run-in-terminal-CdefEe_R.js} +1 -1
  138. package/dist/web/assets/{sas-DZY5BtXx.js → sas-D8ZEeP6v.js} +1 -1
  139. package/dist/web/assets/{schedules-settings-section-DO8xAOVj.js → schedules-settings-section-BVkpW5ms.js} +1 -1
  140. package/dist/web/assets/{scroll-area-LtNV8g5o.js → scroll-area-BzeiOd-B.js} +1 -1
  141. package/dist/web/assets/{scss--4g-REcN.js → scss-ITL7jQ1f.js} +1 -1
  142. package/dist/web/assets/{send-to-chat-Cnpru1M0.js → send-to-chat-F207yH3u.js} +1 -1
  143. package/dist/web/assets/{separator-Cds1yxy8.js → separator-TRMsJUYe.js} +1 -1
  144. package/dist/web/assets/settings-body-CoIxYAh6.js +2 -0
  145. package/dist/web/assets/settings-store-krC6bc79.js +2 -0
  146. package/dist/web/assets/settings-tab-7DKVUTbM.js +1 -0
  147. package/dist/web/assets/settings-window-content-3_39TeX-.js +1 -0
  148. package/dist/web/assets/{shaderlab-Cu4sBiVn.js → shaderlab-mW-IIlhk.js} +1 -1
  149. package/dist/web/assets/{shellsession-DWzJfEv7.js → shellsession-DhNl5STt.js} +1 -1
  150. package/dist/web/assets/{soy-BnqE-5Ff.js → soy-SdY0Qjtr.js} +1 -1
  151. package/dist/web/assets/{sparql-Ctg__NhZ.js → sparql-ftqZo2i-.js} +1 -1
  152. package/dist/web/assets/{sql-query-editor-D9k19T_M.js → sql-query-editor-CQB7Yp7U.js} +1 -1
  153. package/dist/web/assets/{sqlite-viewer-DoV9hnWJ.js → sqlite-viewer-Bd7rjr1D.js} +1 -1
  154. package/dist/web/assets/{stata-Qk2h66XW.js → stata-Bj7Yjb4b.js} +1 -1
  155. package/dist/web/assets/{surrealql-8QEX7EfH.js → surrealql-CLhYGAfB.js} +1 -1
  156. package/dist/web/assets/{svelte-D_mubC5-.js → svelte-DTAlRHhK.js} +1 -1
  157. package/dist/web/assets/system-monitor-body-DsRXeMyU.js +2 -0
  158. package/dist/web/assets/system-monitor-tab-DdSZgux3.js +1 -0
  159. package/dist/web/assets/{system-monitor-window-content-qXLcicFM.js → system-monitor-window-content-ClPo4-El.js} +1 -1
  160. package/dist/web/assets/{tab-host-window-content-7fPZNEni.js → tab-host-window-content-d2TAD4PU.js} +1 -1
  161. package/dist/web/assets/{tab-store-DGJGnbwv.js → tab-store-OJa1GPCq.js} +1 -1
  162. package/dist/web/assets/team-member-sheet-7d2Qp-ie.js +2 -0
  163. package/dist/web/assets/{team-member-window-content-BgvJFypM.js → team-member-window-content-Bctg2gmg.js} +1 -1
  164. package/dist/web/assets/{templ-C1jV0fsO.js → templ-BMfhACxb.js} +1 -1
  165. package/dist/web/assets/{terminal-tab-Cs0sGljx.js → terminal-tab-0HQic25V.js} +3 -3
  166. package/dist/web/assets/{tex-D_StFXy_.js → tex-BcssM-QA.js} +1 -1
  167. package/dist/web/assets/tool-cards-CmLLRACd.js +9 -0
  168. package/dist/web/assets/treemap-KZPCXAKY-CE30wCXa.js +1 -0
  169. package/dist/web/assets/{ts-tags-B5m47rEm.js → ts-tags-CrR5IYI8.js} +1 -1
  170. package/dist/web/assets/{twig-C_br6GIl.js → twig-DchfUmyI.js} +1 -1
  171. package/dist/web/assets/{use-blob-url-C-SGi_Hb.js → use-blob-url-CPtCcY3i.js} +1 -1
  172. package/dist/web/assets/{use-inline-blame-B4trxGcR.js → use-inline-blame-sDMjcz1-.js} +3 -3
  173. package/dist/web/assets/{use-lsp-CV0vzILO.js → use-lsp-CBgID-EU.js} +1 -1
  174. package/dist/web/assets/{use-monaco-theme-DBqbWjWX.js → use-monaco-theme-gvhJ_jZh.js} +1 -1
  175. package/dist/web/assets/{use-open-team-member-DENsjp0s.js → use-open-team-member-C3mrUzIC.js} +1 -1
  176. package/dist/web/assets/{use-websocket-LgXiX1qN.js → use-websocket-C9wlRliB.js} +1 -1
  177. package/dist/web/assets/{vendor-mermaid-Cbig5zA6.js → vendor-mermaid-BitiXJlL.js} +1 -1
  178. package/dist/web/assets/{vendor-ui-BBdkypKW.js → vendor-ui-DmZ-Mb-H.js} +1 -1
  179. package/dist/web/assets/video-preview-CSDK5j6H.js +1 -0
  180. package/dist/web/assets/{vue-DQwCnLdr.js → vue-1EL6Pw1h.js} +1 -1
  181. package/dist/web/assets/{vue-html-T_EoGpPJ.js → vue-html-BPQNwPC6.js} +1 -1
  182. package/dist/web/assets/{vue-vine-DmxLqX50.js → vue-vine-Bb_dsWLt.js} +1 -1
  183. package/dist/web/assets/{window-pip-registry-3l4hoxuD.js → window-pip-registry-yD6esSju.js} +1 -1
  184. package/dist/web/assets/ws-auth-CEYVQ8NH.js +1 -0
  185. package/dist/web/assets/{xml-Bs6Bw8is.js → xml-dxkLNA0K.js} +1 -1
  186. package/dist/web/assets/{xsl-f5ZNhRCc.js → xsl-Bw2adwrl.js} +1 -1
  187. package/dist/web/index.html +27 -26
  188. package/dist/web/sw.js +1 -1
  189. package/docs/architecture/ai-chat-and-providers.md +9 -0
  190. package/docs/architecture/plugins-and-tracing.md +285 -0
  191. package/docs/lessons-learned.md +31 -0
  192. package/docs/system-architecture.md +1 -0
  193. package/package.json +2 -1
  194. package/packages/ext-git-graph/src/compare-diff-base.test.ts +173 -0
  195. package/packages/ext-git-graph/src/compare-view.ts +22 -3
  196. package/packages/ext-git-graph/src/extension.ts +6 -0
  197. package/packages/ext-git-graph/src/types.ts +19 -0
  198. package/packages/ext-git-graph/src/webview-html.test.ts +159 -1
  199. package/packages/ext-git-graph/src/webview-html.ts +344 -26
  200. package/scripts/gen-file-icons.ts +493 -242
  201. package/src/providers/claude-agent-sdk.ts +42 -1
  202. package/src/providers/codex-app-server/codex-history.ts +77 -23
  203. package/src/server/index.ts +42 -7
  204. package/src/server/routes/chat.ts +15 -11
  205. package/src/server/routes/git.ts +83 -3
  206. package/src/server/routes/remote-desktop.ts +7 -2
  207. package/src/server/ws/global.ts +1 -1
  208. package/src/server/ws/remote-desktop.ts +12 -5
  209. package/src/services/binary-content.ts +25 -0
  210. package/src/services/chat-search.service.ts +1 -1
  211. package/src/services/chat.service.ts +9 -0
  212. package/src/services/edge-forwarder.ts +191 -191
  213. package/src/services/event-loop-lag.ts +208 -0
  214. package/src/services/file-lines.ts +114 -0
  215. package/src/services/file-watcher/recreated-dir-poller.ts +108 -6
  216. package/src/services/file-watcher/watch-tree.ts +131 -10
  217. package/src/services/file-watcher.service.ts +73 -23
  218. package/src/services/git-branch-diff/branch-diff-parse.ts +151 -0
  219. package/src/services/git-branch-diff/branch-diff.service.ts +79 -0
  220. package/src/services/git-hunks/git-hunks.service.ts +26 -11
  221. package/src/services/git-hunks/unified-diff.ts +15 -1
  222. package/src/services/git.service.ts +74 -24
  223. package/src/services/jsonl-transcript-parser.ts +138 -6
  224. package/src/services/log-rotate.ts +142 -0
  225. package/src/services/media-transcode/ffmpeg-capabilities.ts +72 -2
  226. package/src/services/remote-desktop/remote-desktop-audio.ts +193 -0
  227. package/src/services/remote-desktop/remote-desktop-capture-input.ts +87 -14
  228. package/src/services/remote-desktop/remote-desktop-capture.ts +40 -7
  229. package/src/services/remote-desktop/remote-desktop-clipboard.ts +166 -0
  230. package/src/services/remote-desktop/remote-desktop-displays.ts +77 -1
  231. package/src/services/remote-desktop/remote-desktop-encoder-args.ts +25 -6
  232. package/src/services/remote-desktop/remote-desktop-evdev-key-map.ts +69 -0
  233. package/src/services/remote-desktop/remote-desktop-input-linux.ts +253 -0
  234. package/src/services/remote-desktop/remote-desktop-input-uinput.ts +242 -0
  235. package/src/services/remote-desktop/remote-desktop-input.ts +40 -8
  236. package/src/services/remote-desktop/remote-desktop-linux-session.ts +146 -0
  237. package/src/services/remote-desktop/remote-desktop-ogg-opus.ts +144 -0
  238. package/src/services/remote-desktop/remote-desktop-privacy.ts +163 -0
  239. package/src/services/remote-desktop/remote-desktop-quality.ts +138 -0
  240. package/src/services/remote-desktop/remote-desktop-requirements.ts +158 -5
  241. package/src/services/remote-desktop/remote-desktop-resolution.ts +302 -0
  242. package/src/services/remote-desktop/remote-desktop-session.ts +523 -21
  243. package/src/services/remote-desktop/remote-desktop-x11.ts +250 -0
  244. package/src/services/supervisor.ts +47 -4
  245. package/src/services/windows-process-tree.ts +351 -351
  246. package/src/shared/codex-daily-guard.ts +12 -5
  247. package/src/shared/remote-desktop-custom-quality.ts +117 -0
  248. package/src/shared/remote-desktop-quality.ts +127 -0
  249. package/src/types/chat.ts +4 -0
  250. package/src/types/git.ts +52 -0
  251. package/src/web/components/branch-review/branch-review-tab.tsx +360 -0
  252. package/src/web/components/branch-review/branch-review-tree-row.tsx +138 -0
  253. package/src/web/components/chat/attachment-chips.tsx +30 -6
  254. package/src/web/components/chat/chat-tab.tsx +12 -1
  255. package/src/web/components/chat/message-events.tsx +273 -0
  256. package/src/web/components/chat/message-list.tsx +107 -861
  257. package/src/web/components/chat/message-markdown.tsx +34 -0
  258. package/src/web/components/chat/message-media.tsx +174 -0
  259. package/src/web/components/chat/message-user-bubble.tsx +399 -0
  260. package/src/web/components/chat/provider-selector.tsx +30 -22
  261. package/src/web/components/chat/session-history-list.tsx +2 -2
  262. package/src/web/components/chat/session-list-panel.tsx +3 -2
  263. package/src/web/components/editor/binary-diff-view.tsx +212 -0
  264. package/src/web/components/editor/diff-viewer.tsx +76 -3
  265. package/src/web/components/explorer/file-tree.tsx +235 -134
  266. package/src/web/components/explorer/flatten-visible-tree.ts +35 -40
  267. package/src/web/components/explorer/tree-node.tsx +69 -69
  268. package/src/web/components/explorer/use-tree-row-dnd.ts +3 -4
  269. package/src/web/components/extensions/extension-tree-view.tsx +4 -11
  270. package/src/web/components/git/git-status-panel.tsx +25 -0
  271. package/src/web/components/layout/command-palette.tsx +2 -18
  272. package/src/web/components/layout/draggable-tab.tsx +4 -2
  273. package/src/web/components/layout/nav-section-rail.tsx +12 -3
  274. package/src/web/components/layout/status-bar.tsx +10 -6
  275. package/src/web/components/layout/tab-content.tsx +5 -0
  276. package/src/web/components/layout/tab-pool.tsx +1 -0
  277. package/src/web/components/layout/upgrade-button.tsx +5 -1
  278. package/src/web/components/remote-desktop/remote-desktop-clipboard-client.ts +67 -0
  279. package/src/web/components/remote-desktop/remote-desktop-clipboard-notice.tsx +127 -0
  280. package/src/web/components/remote-desktop/remote-desktop-codec-labels.ts +28 -0
  281. package/src/web/components/remote-desktop/remote-desktop-custom-quality-dialog.tsx +144 -0
  282. package/src/web/components/remote-desktop/remote-desktop-mobile-key-bar.tsx +13 -2
  283. package/src/web/components/remote-desktop/remote-desktop-mobile-settings.tsx +232 -0
  284. package/src/web/components/remote-desktop/remote-desktop-mobile-toolbar.tsx +21 -8
  285. package/src/web/components/remote-desktop/remote-desktop-mobile-view.tsx +82 -3
  286. package/src/web/components/remote-desktop/remote-desktop-recording.ts +76 -0
  287. package/src/web/components/remote-desktop/remote-desktop-resolution-list.ts +100 -0
  288. package/src/web/components/remote-desktop/remote-desktop-toolbar.tsx +497 -0
  289. package/src/web/components/remote-desktop/remote-desktop-view-style.ts +145 -0
  290. package/src/web/components/remote-desktop/remote-desktop-window-content.tsx +126 -35
  291. package/src/web/components/remote-desktop/use-h264-canvas-decoder.ts +11 -0
  292. package/src/web/components/remote-desktop/use-opus-audio-player.ts +148 -0
  293. package/src/web/components/remote-desktop/use-remote-desktop-connection.ts +284 -1
  294. package/src/web/components/remote-desktop/use-remote-desktop-readiness.ts +75 -1
  295. package/src/web/components/remote-desktop/use-remote-desktop-recorder.ts +103 -0
  296. package/src/web/components/remote-desktop/use-remote-desktop-virtual-keyboard.ts +19 -2
  297. package/src/web/components/remote-desktop/use-remote-input-capture.ts +39 -3
  298. package/src/web/components/settings/accounts/account-card.tsx +2 -2
  299. package/src/web/components/settings/accounts/codex-accounts-section.tsx +4 -4
  300. package/src/web/components/settings/extension-manager-section.tsx +8 -1
  301. package/src/web/components/settings/theme-picker.tsx +2 -1
  302. package/src/web/components/ui/tooltip.tsx +15 -2
  303. package/src/web/lib/branch-review-state.ts +175 -0
  304. package/src/web/lib/extension-icons.ts +70 -0
  305. package/src/web/lib/file-icon-name.ts +62 -0
  306. package/src/web/lib/file-icons.generated.ts +3287 -25
  307. package/src/web/lib/file-icons.tsx +71 -73
  308. package/src/web/lib/flatten-expansions.ts +18 -5
  309. package/src/web/lib/message-ordinals.ts +23 -0
  310. package/src/web/lib/provider-logos.tsx +143 -0
  311. package/src/web/lib/tab-type-icons.ts +25 -0
  312. package/src/web/stores/file-store.ts +73 -35
  313. package/src/web/stores/panel-utils.ts +5 -0
  314. package/src/web/stores/project-framework-store.ts +82 -0
  315. package/src/web/stores/project-store.ts +7 -1
  316. package/src/web/stores/settings-store.ts +128 -0
  317. package/src/web/stores/tab-store.ts +1 -0
  318. package/src/web/stores/window-panel-persistence.ts +1 -0
  319. package/src/web/styles/file-icons.generated.css +3282 -234
  320. package/src/web/styles/globals.css +26 -0
  321. package/dist/web/assets/accounts-settings-section-BuxD9zH3.js +0 -1
  322. package/dist/web/assets/ai-settings-section-Dd9tOUp0.js +0 -1
  323. package/dist/web/assets/ai-settings-section-FrU2X8Fu.js +0 -1
  324. package/dist/web/assets/api-client-BUCo1lms.js +0 -1
  325. package/dist/web/assets/architecture-PBZL5I3N-5K0wEkAn.js +0 -1
  326. package/dist/web/assets/chat-tab-Cr6_KSGO.js +0 -15
  327. package/dist/web/assets/code-editor-DfmlGamv.js +0 -7
  328. package/dist/web/assets/context-menu-DOODKZdF.js +0 -1
  329. package/dist/web/assets/diff-viewer-BpNj7pN9.js +0 -4
  330. package/dist/web/assets/explorer-body-D-5z464e.js +0 -2
  331. package/dist/web/assets/explorer-window-content-7-1wuRul.js +0 -1
  332. package/dist/web/assets/extension-manager-section-BhwB6nqr.js +0 -1
  333. package/dist/web/assets/file-icons-EzPL0q-k.js +0 -1
  334. package/dist/web/assets/file-icons.generated-CfaJuvZu.css +0 -1
  335. package/dist/web/assets/file-store-DMABxOkV.js +0 -1
  336. package/dist/web/assets/files-settings-section-CZzABuKz.js +0 -1
  337. package/dist/web/assets/git-log-panel-CRN4JVOx.js +0 -1
  338. package/dist/web/assets/gitGraph-HDMCJU4V-DkVT2MAM.js +0 -1
  339. package/dist/web/assets/group-chat-tab-DFa5mAx5.js +0 -1
  340. package/dist/web/assets/index-D7DbXD3G.css +0 -1
  341. package/dist/web/assets/index-ZtfxZOyb.js +0 -52
  342. package/dist/web/assets/info-3K5VOQVL-BBsmKGzA.js +0 -1
  343. package/dist/web/assets/keybindings-store-tVfhPANS.js +0 -1
  344. package/dist/web/assets/markdown-renderer-sJNNVhlS.js +0 -1
  345. package/dist/web/assets/mobile-explorer-sheet-CZ0HZ2E_.js +0 -1
  346. package/dist/web/assets/notification-store-BZbsPnW0.js +0 -1
  347. package/dist/web/assets/packet-RMMSAZCW-DwmYPOlx.js +0 -1
  348. package/dist/web/assets/panel-store-BVLBRn6M.js +0 -1
  349. package/dist/web/assets/pie-UPGHQEXC-D0oogIFi.js +0 -1
  350. package/dist/web/assets/problems-panel-B7BWVhdy.js +0 -1
  351. package/dist/web/assets/project-store-BhMbVln3.js +0 -1
  352. package/dist/web/assets/radar-KQ55EAFF-CQIJOQGa.js +0 -1
  353. package/dist/web/assets/remote-desktop-mobile-sheet-ByjaeZKX.js +0 -2
  354. package/dist/web/assets/remote-desktop-mobile-view-D13mtr9F.js +0 -1
  355. package/dist/web/assets/remote-desktop-window-content-CbqTCaC6.js +0 -1
  356. package/dist/web/assets/settings-body-Rnu-FcX-.js +0 -2
  357. package/dist/web/assets/settings-store-DZPgPtEA.js +0 -2
  358. package/dist/web/assets/settings-tab-C6PHxs0Z.js +0 -1
  359. package/dist/web/assets/settings-window-content-CQ4gT2qj.js +0 -1
  360. package/dist/web/assets/system-monitor-body-2vQ1kMxE.js +0 -2
  361. package/dist/web/assets/system-monitor-tab-krAcvwF7.js +0 -1
  362. package/dist/web/assets/team-member-sheet-2FnRmk1a.js +0 -2
  363. package/dist/web/assets/tool-cards-DU_S2o51.js +0 -9
  364. package/dist/web/assets/treemap-KZPCXAKY-BhEtjljr.js +0 -1
  365. package/dist/web/assets/use-remote-desktop-display-choice-BK_f787P.js +0 -1
  366. package/dist/web/assets/video-preview-BDNwumbW.js +0 -1
  367. package/dist/web/assets/ws-auth-DEAJiGCR.js +0 -1
  368. package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
  369. package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
  370. package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
  371. package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
  372. /package/dist/web/assets/{abap-tkptwpsK.js → abap-IN2yINdN.js} +0 -0
  373. /package/dist/web/assets/{actionscript-3-Di9TMGwg.js → actionscript-3-C_t772eR.js} +0 -0
  374. /package/dist/web/assets/{ada-CB9F079D.js → ada-DPme3emm.js} +0 -0
  375. /package/dist/web/assets/{andromeeda-Dcl8jpb7.js → andromeeda-DSV4i4mZ.js} +0 -0
  376. /package/dist/web/assets/{apache-D0Nk0qsH.js → apache-CWr8s8I8.js} +0 -0
  377. /package/dist/web/assets/{apex-mQIoWncD.js → apex-Z20JnDF5.js} +0 -0
  378. /package/dist/web/assets/{applescript-C6ljbcsI.js → applescript-BKNPu3ga.js} +0 -0
  379. /package/dist/web/assets/{apply-theme-BwIMNXyX.js → apply-theme-CbR31K6I.js} +0 -0
  380. /package/dist/web/assets/{ara-WFqRPGPe.js → ara-hWdY3O96.js} +0 -0
  381. /package/dist/web/assets/{asciidoc-bNd8w4nf.js → asciidoc-eynhq496.js} +0 -0
  382. /package/dist/web/assets/{asm-BQ1_F580.js → asm-Bu02Kq4P.js} +0 -0
  383. /package/dist/web/assets/{aurora-x-Ciqs_Dbu.js → aurora-x-BHBGXbIZ.js} +0 -0
  384. /package/dist/web/assets/{awk-GCR-6KZV.js → awk-B4ojezyv.js} +0 -0
  385. /package/dist/web/assets/{ayu-dark-DxJXuj99.js → ayu-dark-D0GQzFi9.js} +0 -0
  386. /package/dist/web/assets/{ayu-light-jvSyJWDV.js → ayu-light-BVYb5Yn8.js} +0 -0
  387. /package/dist/web/assets/{ayu-mirage-Cg3BPO6H.js → ayu-mirage-BGFW6oNb.js} +0 -0
  388. /package/dist/web/assets/{ballerina-BPz4CrX6.js → ballerina-B6Og3IKT.js} +0 -0
  389. /package/dist/web/assets/{bat-CSTs2hIG.js → bat-D8YFILfx.js} +0 -0
  390. /package/dist/web/assets/{beancount-DMateAZX.js → beancount-BjlbBBuX.js} +0 -0
  391. /package/dist/web/assets/{berry-9lXg0GRM.js → berry-Cz1ygeoj.js} +0 -0
  392. /package/dist/web/assets/{bibtex-DIbqmvFg.js → bibtex-CVkJceJh.js} +0 -0
  393. /package/dist/web/assets/{bicep-02WGsoJ8.js → bicep-DrhYI5GX.js} +0 -0
  394. /package/dist/web/assets/{bird2-BY0tbu3k.js → bird2-BV-KJtmc.js} +0 -0
  395. /package/dist/web/assets/{c-jMBX_9Je.js → c-CuLlvxbG.js} +0 -0
  396. /package/dist/web/assets/{c3-B8JVbNjW.js → c3-CI7-1CJ0.js} +0 -0
  397. /package/dist/web/assets/{cadence-DUIf1tvL.js → cadence-DjxhNP3Q.js} +0 -0
  398. /package/dist/web/assets/{can-open-in-ppm-DGEc0s4P.js → can-open-in-ppm-cv5--yHX.js} +0 -0
  399. /package/dist/web/assets/{catppuccin-frappe-FhUCVxex.js → catppuccin-frappe-CEozpJRh.js} +0 -0
  400. /package/dist/web/assets/{catppuccin-latte-CzfrtmgL.js → catppuccin-latte-C4sXQFMc.js} +0 -0
  401. /package/dist/web/assets/{catppuccin-macchiato-6xL0lOtj.js → catppuccin-macchiato-Ci-fDhXy.js} +0 -0
  402. /package/dist/web/assets/{catppuccin-mocha-D39-xS3P.js → catppuccin-mocha-CH7YXw8d.js} +0 -0
  403. /package/dist/web/assets/{clarity-D8TeGvoT.js → clarity-BWrJ7UmT.js} +0 -0
  404. /package/dist/web/assets/{clojure-Dx_acSX7.js → clojure-C94fh2hb.js} +0 -0
  405. /package/dist/web/assets/{cmake-CyeYPq8o.js → cmake-CtvCkMsG.js} +0 -0
  406. /package/dist/web/assets/{codeowners-DrTI0lmI.js → codeowners-CJnubqzH.js} +0 -0
  407. /package/dist/web/assets/{codeql-CPkFxVW-.js → codeql-BOoP5HY2.js} +0 -0
  408. /package/dist/web/assets/{common-lisp-B0k-3LTj.js → common-lisp-B9nlMFJd.js} +0 -0
  409. /package/dist/web/assets/{coq-uygpo7to.js → coq-CgzIQiSH.js} +0 -0
  410. /package/dist/web/assets/{csharp-DKUYGfSp.js → csharp-4xAIx3jw.js} +0 -0
  411. /package/dist/web/assets/{css-DoOUp7v4.js → css-D4YoLYGn.js} +0 -0
  412. /package/dist/web/assets/{csv-B3YE13gi.js → csv-C2v-ZakW.js} +0 -0
  413. /package/dist/web/assets/{csv-parser-DXePqmXe.js → csv-parser-_oDBUkwQ.js} +0 -0
  414. /package/dist/web/assets/{cue-DViO2wvn.js → cue-Bbznh_an.js} +0 -0
  415. /package/dist/web/assets/{cypher-4BMCIW5N.js → cypher-BKhVEARF.js} +0 -0
  416. /package/dist/web/assets/{d-BT_sTHas.js → d-D6IhWopl.js} +0 -0
  417. /package/dist/web/assets/{dark-plus-DVVXu-1N.js → dark-plus-xAWu790O.js} +0 -0
  418. /package/dist/web/assets/{dart-DHz6f6_6.js → dart-Bj6S9O1j.js} +0 -0
  419. /package/dist/web/assets/{data-grid-types-OgUxMLdQ.js → data-grid-types-C5bthITf.js} +0 -0
  420. /package/dist/web/assets/{dax-ChYCjweK.js → dax-CF2zvaqq.js} +0 -0
  421. /package/dist/web/assets/{desktop-D6Lt4p04.js → desktop-CnmyxMKE.js} +0 -0
  422. /package/dist/web/assets/{diff-D8TDe4hP.js → diff-Qi8WuJsI.js} +0 -0
  423. /package/dist/web/assets/{dist-DOTlFQJA.js → dist-Bjseolz4.js} +0 -0
  424. /package/dist/web/assets/{dist-CrBOCtCW.js → dist-Czq7BUMy.js} +0 -0
  425. /package/dist/web/assets/{docker-Bsp0YbPx.js → docker-vLbbNP5d.js} +0 -0
  426. /package/dist/web/assets/{dotenv-B_7giSY_.js → dotenv-DJMvvNzn.js} +0 -0
  427. /package/dist/web/assets/{dracula-TrQL2iB5.js → dracula-CtAh2rhB.js} +0 -0
  428. /package/dist/web/assets/{dracula-soft-n2XOlgh-.js → dracula-soft-CXtuAAf6.js} +0 -0
  429. /package/dist/web/assets/{dream-maker-CdIEdhpT.js → dream-maker-D5YQyK49.js} +0 -0
  430. /package/dist/web/assets/{editor-font-BDrdiGf1.js → editor-font-ClTC9gaD.js} +0 -0
  431. /package/dist/web/assets/{emacs-lisp-CSbixs6u.js → emacs-lisp-CGTjbiqF.js} +0 -0
  432. /package/dist/web/assets/{everforest-dark-BuZahZYp.js → everforest-dark-D59p7vAQ.js} +0 -0
  433. /package/dist/web/assets/{everforest-light-DPH53z5H.js → everforest-light-B3Qtud3V.js} +0 -0
  434. /package/dist/web/assets/{fennel-B1-K_hlJ.js → fennel-BCyHNUwf.js} +0 -0
  435. /package/dist/web/assets/{fish-Cy12Dbua.js → fish-DDDlLV2G.js} +0 -0
  436. /package/dist/web/assets/{fluent-B_82ys8E.js → fluent-By54R9tl.js} +0 -0
  437. /package/dist/web/assets/{format-bytes-D5sBgIqU.js → format-bytes-D1AQyUCt.js} +0 -0
  438. /package/dist/web/assets/{fortran-free-form-BRQdNzZF.js → fortran-free-form-tP8mRym_.js} +0 -0
  439. /package/dist/web/assets/{gdscript-XBDmLUm9.js → gdscript-nHC2z6Te.js} +0 -0
  440. /package/dist/web/assets/{gdshader-DhVfB3u4.js → gdshader-K-cSmPlW.js} +0 -0
  441. /package/dist/web/assets/{genie-X3K29Y49.js → genie-BAcRhvEe.js} +0 -0
  442. /package/dist/web/assets/{gherkin-DKIx-6cX.js → gherkin-CcifxMLb.js} +0 -0
  443. /package/dist/web/assets/{github-dark-Bf7zdp5s.js → github-dark-67KKlMdB.js} +0 -0
  444. /package/dist/web/assets/{github-dark-default-DqsBBV11.js → github-dark-default-tja8pidR.js} +0 -0
  445. /package/dist/web/assets/{github-dark-dimmed-X2gqRz6w.js → github-dark-dimmed-CtjhYQtx.js} +0 -0
  446. /package/dist/web/assets/{github-dark-high-contrast-Z7tvbGX4.js → github-dark-high-contrast-Bf-LPFgn.js} +0 -0
  447. /package/dist/web/assets/{github-light-BKxt-7zZ.js → github-light-CbJxE7n3.js} +0 -0
  448. /package/dist/web/assets/{github-light-default-B0liF4d4.js → github-light-default-DRQmdHxt.js} +0 -0
  449. /package/dist/web/assets/{github-light-high-contrast-F4encJwr.js → github-light-high-contrast-CJkDgTeM.js} +0 -0
  450. /package/dist/web/assets/{gleam-Pz2bHgBB.js → gleam-D4LCl2ri.js} +0 -0
  451. /package/dist/web/assets/{gn-CgmdNsPU.js → gn-COY8zZmC.js} +0 -0
  452. /package/dist/web/assets/{gnuplot-qLNF5yZ9.js → gnuplot-ROk1VitR.js} +0 -0
  453. /package/dist/web/assets/{go-CSDUNhE7.js → go-H30c3p0C.js} +0 -0
  454. /package/dist/web/assets/{groovy-B3NEnOHF.js → groovy-DBLCaelV.js} +0 -0
  455. /package/dist/web/assets/{gruvbox-dark-hard-DcoftiUX.js → gruvbox-dark-hard-DJy4irps.js} +0 -0
  456. /package/dist/web/assets/{gruvbox-dark-medium-D1wVSuD8.js → gruvbox-dark-medium-Dhfw1QTO.js} +0 -0
  457. /package/dist/web/assets/{gruvbox-dark-soft-DWpunymH.js → gruvbox-dark-soft-BncJU-8w.js} +0 -0
  458. /package/dist/web/assets/{gruvbox-light-hard-rHMvyUdS.js → gruvbox-light-hard-Cq12_YvM.js} +0 -0
  459. /package/dist/web/assets/{gruvbox-light-medium-3O2KiXO7.js → gruvbox-light-medium-DqVja5_v.js} +0 -0
  460. /package/dist/web/assets/{gruvbox-light-soft-lNlXJPwH.js → gruvbox-light-soft-IvwhveGF.js} +0 -0
  461. /package/dist/web/assets/{haskell-aaG3aC0h.js → haskell-DA1JV-MC.js} +0 -0
  462. /package/dist/web/assets/{haxe-CPcHhUDd.js → haxe-V9RTRc5E.js} +0 -0
  463. /package/dist/web/assets/{hcl-CMQNlR_4.js → hcl-hr1lyZ10.js} +0 -0
  464. /package/dist/web/assets/{hjson-DeuklPFj.js → hjson-D3vW3i7X.js} +0 -0
  465. /package/dist/web/assets/{hlsl-BI3hlsaM.js → hlsl-BB85gfJT.js} +0 -0
  466. /package/dist/web/assets/{horizon-C7-gOcjs.js → horizon-DU8OOnj8.js} +0 -0
  467. /package/dist/web/assets/{horizon-bright-Cxt9bRW7.js → horizon-bright-DNMUclW6.js} +0 -0
  468. /package/dist/web/assets/{houston-DbF2G7iD.js → houston-DAiZKf6T.js} +0 -0
  469. /package/dist/web/assets/{hy-DRG6Hs2I.js → hy-C6Zv0LMe.js} +0 -0
  470. /package/dist/web/assets/{image-gallery-CObzTisL.js → image-gallery-CGvlv8zR.js} +0 -0
  471. /package/dist/web/assets/{imba-CxKv_2TW.js → imba-Didnp6Y-.js} +0 -0
  472. /package/dist/web/assets/{ini-BiHsyCdO.js → ini-m0T7q4gQ.js} +0 -0
  473. /package/dist/web/assets/{input-D-dR8RI6.js → input-C7Q8FxeL.js} +0 -0
  474. /package/dist/web/assets/{java-D3RZzgDB.js → java-Buy07jGn.js} +0 -0
  475. /package/dist/web/assets/{javascript-4FmSqG-T.js → javascript-Cjq3CbRL.js} +0 -0
  476. /package/dist/web/assets/{json-CjB236_E.js → json-BSVu8IqD.js} +0 -0
  477. /package/dist/web/assets/{json5-bkfO-Rco.js → json5-NN_Vb7e6.js} +0 -0
  478. /package/dist/web/assets/{jsonc-BwaTeLyv.js → jsonc-BdyZhBUw.js} +0 -0
  479. /package/dist/web/assets/{jsonl-CfxNSwGd.js → jsonl-BsDSNvwi.js} +0 -0
  480. /package/dist/web/assets/{jsonnet-CQETCYrp.js → jsonnet-Gm963F-U.js} +0 -0
  481. /package/dist/web/assets/{jssm-D5o3Zzdz.js → jssm-Ds3bKWgJ.js} +0 -0
  482. /package/dist/web/assets/{jsx-BAMILPLo.js → jsx-BT5mW58X.js} +0 -0
  483. /package/dist/web/assets/{kanagawa-dragon-BhGVxu3R.js → kanagawa-dragon-BvNvf7xd.js} +0 -0
  484. /package/dist/web/assets/{kanagawa-lotus-FH4Y59ro.js → kanagawa-lotus-CuSiliSn.js} +0 -0
  485. /package/dist/web/assets/{kanagawa-wave-eilvP9MB.js → kanagawa-wave-C6g-d6jT.js} +0 -0
  486. /package/dist/web/assets/{kdl-BQ-yvXUK.js → kdl-Bx4kZef-.js} +0 -0
  487. /package/dist/web/assets/{kotlin-BuCx0-VT.js → kotlin-qvaVvCcm.js} +0 -0
  488. /package/dist/web/assets/{kusto-DAN_n_Cy.js → kusto-BPLyNCN6.js} +0 -0
  489. /package/dist/web/assets/{laserwave-Cq2BlxrT.js → laserwave-Sf8ZEhWP.js} +0 -0
  490. /package/dist/web/assets/{lean-Dhq7uXKw.js → lean-DGe6uqgk.js} +0 -0
  491. /package/dist/web/assets/{less-CxaMQb8j.js → less-CqM85x-9.js} +0 -0
  492. /package/dist/web/assets/{lib-BVwmtv2i.js → lib-CD6pOS4u.js} +0 -0
  493. /package/dist/web/assets/{libesm-DdtEjhIi.js → libesm-CPh1Av0r.js} +0 -0
  494. /package/dist/web/assets/{light-plus-B4sMAend.js → light-plus-DBtKwhFA.js} +0 -0
  495. /package/dist/web/assets/{llvm-DQ6-B_6Y.js → llvm-Dpbq3gky.js} +0 -0
  496. /package/dist/web/assets/{log-Bb_vqvu7.js → log-qKMcPm9S.js} +0 -0
  497. /package/dist/web/assets/{logo-BzfYv3A_.js → logo-DFo7i5KH.js} +0 -0
  498. /package/dist/web/assets/{luau-BnAeNR77.js → luau-DGlqWFyL.js} +0 -0
  499. /package/dist/web/assets/{make-B6IFuxpC.js → make-CixdvUQe.js} +0 -0
  500. /package/dist/web/assets/{markdown-Z0xi77Fn.js → markdown-CmRnbngE.js} +0 -0
  501. /package/dist/web/assets/{material-theme-1scy1SYn.js → material-theme-WDUbafB-.js} +0 -0
  502. /package/dist/web/assets/{material-theme-darker-G-JykXQP.js → material-theme-darker-u8y2xpOk.js} +0 -0
  503. /package/dist/web/assets/{material-theme-lighter-BtKkCMVq.js → material-theme-lighter-cyQZK3Tg.js} +0 -0
  504. /package/dist/web/assets/{material-theme-ocean-irrDC89L.js → material-theme-ocean-LBAVvw7k.js} +0 -0
  505. /package/dist/web/assets/{material-theme-palenight-Eq5_K4LM.js → material-theme-palenight-BJqhBxL0.js} +0 -0
  506. /package/dist/web/assets/{matlab-BE3oCXZC.js → matlab-B38sOJee.js} +0 -0
  507. /package/dist/web/assets/{mdx-DYiuFTGw.js → mdx-C8QrE_IW.js} +0 -0
  508. /package/dist/web/assets/{mermaid-DVlaEvtw.js → mermaid-BQ-eeU8A.js} +0 -0
  509. /package/dist/web/assets/{min-dark-DSkeTpQa.js → min-dark-D4gNa5tv.js} +0 -0
  510. /package/dist/web/assets/{min-light-CFv2Q0uF.js → min-light-Dfbhn_PL.js} +0 -0
  511. /package/dist/web/assets/{mipsasm-CiAFuZQ2.js → mipsasm-bLOhJkdm.js} +0 -0
  512. /package/dist/web/assets/{mojo-ARshcaSQ.js → mojo-B0BCOMQW.js} +0 -0
  513. /package/dist/web/assets/{monaco-dotenv-language-BDYnKcnr.js → monaco-dotenv-language-uB-wok6C.js} +0 -0
  514. /package/dist/web/assets/{monokai-CPTV-SOg.js → monokai-Bdw_07OM.js} +0 -0
  515. /package/dist/web/assets/{moonbit-D57B0dZr.js → moonbit-BFdGaeuk.js} +0 -0
  516. /package/dist/web/assets/{move-qgy3G_o9.js → move-CyXQFGPM.js} +0 -0
  517. /package/dist/web/assets/{narrat-CZ3rC-oc.js → narrat-9DvTD3_3.js} +0 -0
  518. /package/dist/web/assets/{nextflow-groovy-BxxIOcI4.js → nextflow-groovy-C4VY3kNY.js} +0 -0
  519. /package/dist/web/assets/{night-owl-B1ryGCda.js → night-owl-feYm66V0.js} +0 -0
  520. /package/dist/web/assets/{night-owl-light-BZvNnvMF.js → night-owl-light-DALqFjvx.js} +0 -0
  521. /package/dist/web/assets/{nix-BVBQi8yv.js → nix-C1kPA9Sw.js} +0 -0
  522. /package/dist/web/assets/{nord-3NXw613h.js → nord-1dvrj1Al.js} +0 -0
  523. /package/dist/web/assets/{nushell-BMOLRalb.js → nushell-DSQ_9Uqj.js} +0 -0
  524. /package/dist/web/assets/{objective-c-AxruEUgh.js → objective-c-Dhcn5ZK8.js} +0 -0
  525. /package/dist/web/assets/{objective-cpp-cFT0qRsD.js → objective-cpp-CGVYCSrp.js} +0 -0
  526. /package/dist/web/assets/{ocaml-_8JH6O8J.js → ocaml-rxXW21An.js} +0 -0
  527. /package/dist/web/assets/{odin-nwYvR0O6.js → odin-ClSJX2DE.js} +0 -0
  528. /package/dist/web/assets/{one-dark-pro-C1LaYJaH.js → one-dark-pro-3gbWDfFW.js} +0 -0
  529. /package/dist/web/assets/{one-light-B7rMc__c.js → one-light-C2q5ZZAw.js} +0 -0
  530. /package/dist/web/assets/{openscad-Cwes8bKO.js → openscad-eHXeafBl.js} +0 -0
  531. /package/dist/web/assets/{pascal-DMt-6tdZ.js → pascal-kKha3Txs.js} +0 -0
  532. /package/dist/web/assets/{pkl-QBTyYQmB.js → pkl-CTiPytg-.js} +0 -0
  533. /package/dist/web/assets/{plastic-BTSUp8Fk.js → plastic-D1Ygezi4.js} +0 -0
  534. /package/dist/web/assets/{plsql-DQv3IFXP.js → plsql-D_gbgZIr.js} +0 -0
  535. /package/dist/web/assets/{po-CNwZx4tW.js → po-BkhbDUnq.js} +0 -0
  536. /package/dist/web/assets/{poimandres-8Os7Qequ.js → poimandres-Do6NywrA.js} +0 -0
  537. /package/dist/web/assets/{polar-b4yK8oD8.js → polar-B3B23wca.js} +0 -0
  538. /package/dist/web/assets/{postcss-sFctwpxx.js → postcss-Dv_YBvWd.js} +0 -0
  539. /package/dist/web/assets/{powerquery-Cg_WrtuN.js → powerquery-fKJWI-Sh.js} +0 -0
  540. /package/dist/web/assets/{powershell-C7Ifz95h.js → powershell-B4Y7KIgx.js} +0 -0
  541. /package/dist/web/assets/{prisma-Z52HUJzQ.js → prisma-J--XdTXX.js} +0 -0
  542. /package/dist/web/assets/{prolog-DLqW-zR1.js → prolog-BBTg4Vb3.js} +0 -0
  543. /package/dist/web/assets/{proto-BOIzxCCJ.js → proto-DWlum3T8.js} +0 -0
  544. /package/dist/web/assets/{puppet-De7TjZIf.js → puppet-ZiUfc9JV.js} +0 -0
  545. /package/dist/web/assets/{purescript-R76ou1WT.js → purescript-CmT8SCHB.js} +0 -0
  546. /package/dist/web/assets/{python-Dprm0tNP.js → python-BURpj-fq.js} +0 -0
  547. /package/dist/web/assets/{qmldir-Clp_jpNw.js → qmldir-CpaiJywQ.js} +0 -0
  548. /package/dist/web/assets/{qss-eQPYYzSo.js → qss-C-zdz0i5.js} +0 -0
  549. /package/dist/web/assets/{r-CCcRHIf5.js → r-K56BeS-s.js} +0 -0
  550. /package/dist/web/assets/{racket-CzE472yp.js → racket-gkn6Z_Jw.js} +0 -0
  551. /package/dist/web/assets/{raku-DQwXrTSi.js → raku-C0ZBuKlx.js} +0 -0
  552. /package/dist/web/assets/{red-KCS6wyop.js → red-BWZ6x-3p.js} +0 -0
  553. /package/dist/web/assets/{reg-CcrAddUh.js → reg-Dt_EsyGR.js} +0 -0
  554. /package/dist/web/assets/{regexp-DDbud-Ri.js → regexp-CT6BLG2C.js} +0 -0
  555. /package/dist/web/assets/{rel-99GDgaHp.js → rel-MJ2LcyzJ.js} +0 -0
  556. /package/dist/web/assets/{resolve-theme-CW2niGV2.js → resolve-theme-B_ukrg_8.js} +0 -0
  557. /package/dist/web/assets/{riscv-Dm2eNv0R.js → riscv-BZYWzMAA.js} +0 -0
  558. /package/dist/web/assets/{ron-CzFt0ygH.js → ron-CLbwHWMn.js} +0 -0
  559. /package/dist/web/assets/{rose-pine-Ck6lCrCP.js → rose-pine-BPiI_daR.js} +0 -0
  560. /package/dist/web/assets/{rose-pine-dawn-vtALRJNj.js → rose-pine-dawn-BjkJc7dW.js} +0 -0
  561. /package/dist/web/assets/{rose-pine-moon-DPto8qXw.js → rose-pine-moon-BQSxkt7g.js} +0 -0
  562. /package/dist/web/assets/{rosmsg-NtS6429H.js → rosmsg-yt4151pJ.js} +0 -0
  563. /package/dist/web/assets/{rust-BjIXvF9h.js → rust-1dAcengL.js} +0 -0
  564. /package/dist/web/assets/{sass-CQ23wf5E.js → sass-DUgtQJsg.js} +0 -0
  565. /package/dist/web/assets/{scala-LfKLM143.js → scala-CxoGYpS0.js} +0 -0
  566. /package/dist/web/assets/{scheme-D3SLBXlF.js → scheme-B2K3u9e3.js} +0 -0
  567. /package/dist/web/assets/{sdbl-ODRd2rGN.js → sdbl-C0Ygk0n6.js} +0 -0
  568. /package/dist/web/assets/{shellscript-3KB1G_oA.js → shellscript-C2CvhqMk.js} +0 -0
  569. /package/dist/web/assets/{slack-dark-DTtyWmIy.js → slack-dark-DYdgzRGj.js} +0 -0
  570. /package/dist/web/assets/{slack-ochin-Bu0PApk3.js → slack-ochin-X-WD0WCg.js} +0 -0
  571. /package/dist/web/assets/{smalltalk-haMT-Sbe.js → smalltalk-Dp7g_zb9.js} +0 -0
  572. /package/dist/web/assets/{snazzy-light-DXJzefE9.js → snazzy-light-DWHWr-a6.js} +0 -0
  573. /package/dist/web/assets/{solarized-dark-B6LyYa18.js → solarized-dark-CxdLsjvb.js} +0 -0
  574. /package/dist/web/assets/{solarized-light-QLADebkv.js → solarized-light-Cz9rAvG5.js} +0 -0
  575. /package/dist/web/assets/{solidity-mzfq1aDc.js → solidity-D33gHHdn.js} +0 -0
  576. /package/dist/web/assets/{splunk-CyH4RWBp.js → splunk-BFbOroYw.js} +0 -0
  577. /package/dist/web/assets/{sql-CWVlT5D3.js → sql-ChpxvmdY.js} +0 -0
  578. /package/dist/web/assets/{ssh-config-DNvQJ1Qx.js → ssh-config-CUuSQ6JG.js} +0 -0
  579. /package/dist/web/assets/{streaming-store-uDu3PoN1.js → streaming-store-BYukdB56.js} +0 -0
  580. /package/dist/web/assets/{stylus-ByQQdtmf.js → stylus-DDihP0_W.js} +0 -0
  581. /package/dist/web/assets/{swift-D1cpY4ow.js → swift-XoalUn4x.js} +0 -0
  582. /package/dist/web/assets/{synthwave-84-BDF_-QiW.js → synthwave-84-DjkG0Bff.js} +0 -0
  583. /package/dist/web/assets/{system-verilog-BYrkMydC.js → system-verilog-f_pLKMYd.js} +0 -0
  584. /package/dist/web/assets/{systemd-CQm3zyK0.js → systemd-DjDcLfxp.js} +0 -0
  585. /package/dist/web/assets/{talonscript-DMW5CzE1.js → talonscript-BpUzYcDl.js} +0 -0
  586. /package/dist/web/assets/{tasl-BhFzMCr2.js → tasl-DP-cUbg8.js} +0 -0
  587. /package/dist/web/assets/{tcl-D7VEAF-9.js → tcl-BHoy-dfE.js} +0 -0
  588. /package/dist/web/assets/{terraform-DdT5A0Vy.js → terraform-vCVxN25B.js} +0 -0
  589. /package/dist/web/assets/{tokyo-night-WGLMM6Q9.js → tokyo-night-D0u4xZba.js} +0 -0
  590. /package/dist/web/assets/{toml-CZ7ipXHZ.js → toml-BS8D0__A.js} +0 -0
  591. /package/dist/web/assets/{tsv-B1zVvoTr.js → tsv-DCb-NQh3.js} +0 -0
  592. /package/dist/web/assets/{tsx-D4HwRUBq.js → tsx-DF8YeRgG.js} +0 -0
  593. /package/dist/web/assets/{turtle-B4r8KEJH.js → turtle-Bhx1GlIy.js} +0 -0
  594. /package/dist/web/assets/{typescript-BnHhxMtp.js → typescript-CAVD2Wb6.js} +0 -0
  595. /package/dist/web/assets/{typespec-DP2q46GT.js → typespec-D7mchdY_.js} +0 -0
  596. /package/dist/web/assets/{typst-DFsD_yaD.js → typst-CeXzq6Yw.js} +0 -0
  597. /package/dist/web/assets/{use-is-mobile-BQ9Bv5Ga.js → use-is-mobile-TkcwP1Gx.js} +0 -0
  598. /package/dist/web/assets/{use-visual-viewport-CbwnktSG.js → use-visual-viewport-Lp878uzs.js} +0 -0
  599. /package/dist/web/assets/{v-Bji8hSVT.js → v-DhzO54je.js} +0 -0
  600. /package/dist/web/assets/{vala-D3TIgGmU.js → vala-Dw_RAk3E.js} +0 -0
  601. /package/dist/web/assets/{vb-DvcxFS2q.js → vb-CiXdNh2Y.js} +0 -0
  602. /package/dist/web/assets/{vendor-xterm-BqPDsE9b.js → vendor-xterm-BHEY6Ctu.js} +0 -0
  603. /package/dist/web/assets/{verilog-Dy7cF35d.js → verilog-fITdxqwV.js} +0 -0
  604. /package/dist/web/assets/{vesper-BzjwUv9J.js → vesper-B1wm_At7.js} +0 -0
  605. /package/dist/web/assets/{vhdl-DuFnFNmW.js → vhdl-ebHjqKp9.js} +0 -0
  606. /package/dist/web/assets/{viml-yAPgKlbz.js → viml-Dgmnoxoo.js} +0 -0
  607. /package/dist/web/assets/{vitesse-black-oSSQdyIZ.js → vitesse-black-BZ5gMb7l.js} +0 -0
  608. /package/dist/web/assets/{vitesse-dark-BZxwPihB.js → vitesse-dark-Lij7kkOt.js} +0 -0
  609. /package/dist/web/assets/{vitesse-light-uIigycvt.js → vitesse-light-DW6Wq7VC.js} +0 -0
  610. /package/dist/web/assets/{vyper-CX3NAxm5.js → vyper-6FxDnVNg.js} +0 -0
  611. /package/dist/web/assets/{wasm-6mEOOvVa.js → wasm-BDxaNPCj.js} +0 -0
  612. /package/dist/web/assets/{wasm-D9td37qO.js → wasm-DKhAtzfe.js} +0 -0
  613. /package/dist/web/assets/{wenyan-lwNIHgk6.js → wenyan-C0k0DYG_.js} +0 -0
  614. /package/dist/web/assets/{wgsl-DQAzCfog.js → wgsl-Y2zagbdn.js} +0 -0
  615. /package/dist/web/assets/{wikitext-DTXmt5NE.js → wikitext-C4QGWzkY.js} +0 -0
  616. /package/dist/web/assets/{wit-Bdw_7WDH.js → wit-CQESzjHy.js} +0 -0
  617. /package/dist/web/assets/{wolfram-DqyHDZ07.js → wolfram-B-ia69Ia.js} +0 -0
  618. /package/dist/web/assets/{yaml-CPXhdByd.js → yaml-CEYYTQPm.js} +0 -0
  619. /package/dist/web/assets/{zenscript-6s_i5zek.js → zenscript-BggWXIeJ.js} +0 -0
  620. /package/dist/web/assets/{zig-B2htezJ_.js → zig-CbaUfBQe.js} +0 -0
@@ -9,14 +9,23 @@
9
9
  import { useRef, useState, useCallback } from "react";
10
10
  import { RotateCw, MonitorX } from "@/lib/icons";
11
11
  import { useVisualViewport } from "@/hooks/use-visual-viewport";
12
+ import { useSettingsStore } from "@/stores/settings-store";
12
13
  import { useRemoteDesktopConnection } from "./use-remote-desktop-connection";
13
14
  import { useRemoteDesktopTouch, type RemoteDesktopInputMode } from "./use-remote-desktop-touch";
14
15
  import { useRemoteDesktopVirtualKeyboard } from "./use-remote-desktop-virtual-keyboard";
15
16
  import { RemoteDesktopMobileToolbar } from "./remote-desktop-mobile-toolbar";
17
+ import {
18
+ nextQualityChoice, shortQualityLabel, type QualityChoice,
19
+ } from "../../../shared/remote-desktop-quality";
16
20
  import { RemoteDesktopMobileKeyBar } from "./remote-desktop-mobile-key-bar";
21
+ import { RemoteDesktopMobileSettings } from "./remote-desktop-mobile-settings";
22
+ import { useRemoteDesktopRecorder } from "./use-remote-desktop-recorder";
23
+ import { saveCanvasScreenshot } from "./remote-desktop-recording";
17
24
  import { RemoteDesktopStatsOverlay } from "./remote-desktop-stats-overlay";
18
25
  import { letterboxedContentRect } from "./remote-desktop-coords";
19
26
  import { useRemoteDesktopDisplayChoice } from "./use-remote-desktop-display-choice";
27
+ import { RemoteDesktopClipboardNotice } from "./remote-desktop-clipboard-notice";
28
+ import { useRemoteDesktopReadiness } from "./use-remote-desktop-readiness";
20
29
 
21
30
  export interface RemoteDesktopMobileViewProps {
22
31
  onClose: () => void;
@@ -27,12 +36,21 @@ export default function RemoteDesktopMobileView({ onClose }: RemoteDesktopMobile
27
36
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
28
37
  const [mode, setMode] = useState<RemoteDesktopInputMode>("mouse");
29
38
  const [keyBarOpen, setKeyBarOpen] = useState(false);
39
+ const [settingsOpen, setSettingsOpen] = useState(false);
30
40
  const display = useRemoteDesktopDisplayChoice();
31
41
 
32
42
  const {
33
43
  connState, errorMessage, decoderStatus, decoderErrorMessage, sendMessage, reconnect,
34
- getTotalBytes, getFrameCount,
44
+ getTotalBytes, getFrameCount, quality, setQuality, showCursor, setShowCursor,
45
+ audioOn, setAudioOn, getAudioTracks, privacyOn, privacyError, setPrivacyOn,
46
+ hostModeId, hostOriginalModeId, resolutionError, setHostMode,
47
+ pendingHostClipboard, clearHostClipboard, sendClipboard, requestHostClipboard,
35
48
  } = useRemoteDesktopConnection(canvasRef, { displayId: display.displayId });
49
+ const statsVisible = useSettingsStore((s) => s.remoteDesktopStatsVisible);
50
+ const toggleStats = useSettingsStore((s) => s.toggleRemoteDesktopStatsVisible);
51
+ const clipboardSync = useSettingsStore((s) => s.remoteDesktopClipboardSync);
52
+ const setClipboardSync = useSettingsStore((s) => s.setRemoteDesktopClipboardSync);
53
+ const qualityChoice = useSettingsStore((st) => st.remoteDesktopQuality);
36
54
  const streaming = connState === "streaming";
37
55
 
38
56
  const { transform, virtualCursor, resetZoom } = useRemoteDesktopTouch({
@@ -42,7 +60,24 @@ export default function RemoteDesktopMobileView({ onClose }: RemoteDesktopMobile
42
60
  sendMessage,
43
61
  enabled: streaming,
44
62
  });
45
- const { inputRef: keyboardInputRef, show: showKeyboard } = useRemoteDesktopVirtualKeyboard(sendMessage, streaming);
63
+ // A phone paste goes through the *host clipboard* rather than being typed character by
64
+ // character: typing is subject to the host's IME (a Telex host rewrites "World" as "ửold"),
65
+ // and a pasted URL or token is exactly the text that must survive verbatim. The server falls
66
+ // back to typing by itself when the host has no clipboard tool.
67
+ const [pasteAttempted, setPasteAttempted] = useState(false);
68
+ // Undefined with sync off, which is how the toggle is implemented on this surface: the
69
+ // virtual keyboard then lets the `paste` event's own default action stand (i.e. nothing
70
+ // leaves the device), and the key bar's Ctrl+V button still pastes the *host's* clipboard.
71
+ const onPasteText = useCallback((text: string) => {
72
+ setPasteAttempted(true);
73
+ sendClipboard(text, true);
74
+ }, [sendClipboard]);
75
+ // One fetch, no polling — read only to explain a paste that had to fall back to typing, and
76
+ // an audio toggle the host cannot honour.
77
+ const { caps } = useRemoteDesktopReadiness(false);
78
+ const recorder = useRemoteDesktopRecorder(canvasRef, getAudioTracks);
79
+ const { inputRef: keyboardInputRef, show: showKeyboard } =
80
+ useRemoteDesktopVirtualKeyboard(sendMessage, streaming, clipboardSync ? onPasteText : undefined);
46
81
 
47
82
  // Lifts the toolbar/key-bar row above the on-screen keyboard instead of the whole sheet
48
83
  // shrinking to make room for it (that was the previous, since-reverted behavior — see
@@ -169,14 +204,58 @@ export default function RemoteDesktopMobileView({ onClose }: RemoteDesktopMobile
169
204
  style={keyboardInset > 0 ? { transform: `translateY(-${keyboardInset}px)` } : undefined}
170
205
  data-testid="remote-desktop-mobile-bottom-bar"
171
206
  >
172
- {keyBarOpen && <RemoteDesktopMobileKeyBar sendMessage={sendMessage} />}
207
+ {/* In flow above the key bar so it rides the same `keyboardInset` lift and is never
208
+ hidden behind the toolbar. */}
209
+ <RemoteDesktopClipboardNotice
210
+ pendingText={pendingHostClipboard}
211
+ onDismiss={clearHostClipboard}
212
+ missingToolAction={pasteAttempted && caps && !caps.clipboard.available ? caps.clipboard.action : null}
213
+ onDismissMissingTool={() => setPasteAttempted(false)}
214
+ positionClassName="mx-2 mb-1 max-w-[calc(100%-1rem)]"
215
+ />
216
+ {settingsOpen && (
217
+ <RemoteDesktopMobileSettings
218
+ statsVisible={statsVisible}
219
+ onToggleStats={toggleStats}
220
+ showCursor={showCursor}
221
+ onSetShowCursor={setShowCursor}
222
+ clipboardEnabled={clipboardSync}
223
+ onSetClipboardEnabled={setClipboardSync}
224
+ audioOn={audioOn}
225
+ audioReason={caps && !caps.audio.available ? caps.audio.reason : null}
226
+ onSetAudioOn={setAudioOn}
227
+ privacyOn={privacyOn}
228
+ privacyReason={privacyError ?? (caps && !caps.privacy.available ? caps.privacy.reason : null)}
229
+ hostModes={caps?.resolutions?.modes ?? []}
230
+ hostModeId={hostModeId}
231
+ hostOriginalModeId={hostOriginalModeId}
232
+ onSetHostMode={setHostMode}
233
+ canResizeHost={caps?.inputReady ?? false}
234
+ resolutionError={resolutionError}
235
+ onSetPrivacyOn={setPrivacyOn}
236
+ recording={recorder.recording}
237
+ recordingSupported={recorder.supported}
238
+ onToggleRecording={recorder.toggle}
239
+ onScreenshot={() => void saveCanvasScreenshot(canvasRef.current)}
240
+ />
241
+ )}
242
+ {keyBarOpen && (
243
+ <RemoteDesktopMobileKeyBar
244
+ sendMessage={sendMessage}
245
+ onCopyCombo={clipboardSync ? requestHostClipboard : undefined}
246
+ />
247
+ )}
173
248
  <RemoteDesktopMobileToolbar
174
249
  displayLabel={display.displays.length > 1 ? display.current?.label ?? null : null}
175
250
  onNextDisplay={display.next}
251
+ qualityLabel={shortQualityLabel(qualityChoice)}
252
+ onNextQuality={() => setQuality(nextQualityChoice(qualityChoice))}
176
253
  mode={mode}
177
254
  onToggleMode={toggleMode}
178
255
  onOpenKeyboard={openKeyboard}
179
256
  onResetZoom={resetZoom}
257
+ settingsOpen={settingsOpen}
258
+ onToggleSettings={() => setSettingsOpen((open) => !open)}
180
259
  onClose={onClose}
181
260
  />
182
261
  </div>
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Screenshot and session recording, both taken from the **canvas** rather than from the wire.
3
+ *
4
+ * That is a deliberate trade. Muxing the access units the host already sent would be lossless
5
+ * and free of CPU cost, but it needs an MP4 muxer in the browser and it would record the rung
6
+ * the host chose rather than what the user was looking at — a mid-recording quality change
7
+ * switches resolution and SPS, which no single-track MP4 can express. `captureStream()` +
8
+ * `MediaRecorder` re-encodes (so it costs the *client* CPU) and in exchange records exactly
9
+ * what was on screen, survives every rung change, and carries the audio track in the same file.
10
+ *
11
+ * `captureStream()` is called with no frame rate on purpose: that makes the stream emit a frame
12
+ * whenever the canvas is drawn to, which is the decoder's own cadence. Passing a number
13
+ * resamples to it, so a 30 fps argument against a 60 fps rung would throw half the frames away
14
+ * and a 60 against a 15 fps rung would triple every one of them.
15
+ */
16
+
17
+ /** Container/codec preference. VP9 is the best quality per byte that is universally present in
18
+ * Chromium; H.264-in-MP4 goes first where it exists because it is the one a phone's gallery and
19
+ * every video editor will open without being converted. */
20
+ const MIME_CANDIDATES = [
21
+ "video/mp4;codecs=avc1.42E01E,mp4a.40.2",
22
+ "video/mp4",
23
+ "video/webm;codecs=vp9,opus",
24
+ "video/webm;codecs=vp8,opus",
25
+ "video/webm",
26
+ ];
27
+
28
+ /** The first candidate this browser will actually record, or null when none is supported (no
29
+ * `MediaRecorder` at all — Safari before 14.1, or a locked-down embedded webview). */
30
+ export function pickRecordingMime(
31
+ isSupported: (mime: string) => boolean = (m) =>
32
+ typeof MediaRecorder !== "undefined" && MediaRecorder.isTypeSupported(m),
33
+ ): string | null {
34
+ if (typeof MediaRecorder === "undefined") return null;
35
+ return MIME_CANDIDATES.find(isSupported) ?? null;
36
+ }
37
+
38
+ /** `video/webm;codecs=vp9,opus` → `webm`. Taken from the MIME the recorder actually accepted,
39
+ * because a file named `.webm` that holds MP4 bytes is one no player will open. */
40
+ export function extensionForMime(mime: string): string {
41
+ return mime.startsWith("video/mp4") ? "mp4" : "webm";
42
+ }
43
+
44
+ /** `ppm-remote-2026-09-11_14-32-08.mp4` — sortable, and with no `:` so it survives Windows. */
45
+ export function recordingFileName(ext: string, now = new Date()): string {
46
+ const p = (n: number) => String(n).padStart(2, "0");
47
+ const stamp = `${now.getFullYear()}-${p(now.getMonth() + 1)}-${p(now.getDate())}`
48
+ + `_${p(now.getHours())}-${p(now.getMinutes())}-${p(now.getSeconds())}`;
49
+ return `ppm-remote-${stamp}.${ext}`;
50
+ }
51
+
52
+ /** Hand a blob to the browser as a download. The object URL is revoked on the next task rather
53
+ * than immediately: revoking in the same tick can beat the navigation the click starts, which
54
+ * fails as a "network error" download with nothing in the console. */
55
+ export function downloadBlob(blob: Blob, fileName: string): void {
56
+ const url = URL.createObjectURL(blob);
57
+ const a = document.createElement("a");
58
+ a.href = url;
59
+ a.download = fileName;
60
+ a.rel = "noopener";
61
+ document.body.appendChild(a);
62
+ a.click();
63
+ a.remove();
64
+ setTimeout(() => URL.revokeObjectURL(url), 10_000);
65
+ }
66
+
67
+ /** Save the current frame as a PNG. Resolves false when the canvas has no picture yet (a 0×0
68
+ * canvas, i.e. before the first frame) — `toBlob` on one of those yields a blank image rather
69
+ * than failing, which would download a file that looks like a bug in the capture. */
70
+ export async function saveCanvasScreenshot(canvas: HTMLCanvasElement | null): Promise<boolean> {
71
+ if (!canvas || canvas.width === 0 || canvas.height === 0) return false;
72
+ const blob = await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, "image/png"));
73
+ if (!blob) return false;
74
+ downloadBlob(blob, recordingFileName("png"));
75
+ return true;
76
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Turns the host's raw mode list into the menu RustDesk's `_ResolutionsMenu` shows.
3
+ *
4
+ * The raw list is per *timing*, not per resolution: this dev host advertises 37 modes across 15
5
+ * distinct sizes (seven separate 1920x1080 entries alone). A menu of 37 rows is unusable and
6
+ * says nothing a remote user wants to decide, so they collapse to one row per size.
7
+ *
8
+ * Which one survives the collapse is the part that is easy to get wrong. Keeping the highest
9
+ * refresh looks obviously right — and then a host sitting on 3440x1440@60 while it also
10
+ * advertises @100 has *nothing* ticked in the menu, because the id that is live was dropped.
11
+ * So `current` wins within a group and the refresh only breaks the remaining ties.
12
+ */
13
+ import type { HostMode } from "./use-remote-desktop-readiness";
14
+
15
+ /** One row of the resolution menu. */
16
+ export interface ResolutionChoice {
17
+ /** The mode id to ask the host for. */
18
+ id: string;
19
+ width: number;
20
+ height: number;
21
+ refresh: number;
22
+ current: boolean;
23
+ preferred: boolean;
24
+ }
25
+
26
+ /** One row per distinct size, largest first. */
27
+ export function resolutionChoices(modes: readonly HostMode[]): ResolutionChoice[] {
28
+ const bySize = new Map<string, HostMode>();
29
+ for (const mode of modes) {
30
+ if (mode.width <= 0 || mode.height <= 0) continue;
31
+ const key = `${mode.width}x${mode.height}`;
32
+ const held = bySize.get(key);
33
+ if (!held || beats(mode, held)) bySize.set(key, mode);
34
+ }
35
+ return [...bySize.values()]
36
+ .sort((a, b) => b.width * b.height - a.width * a.height || b.refresh - a.refresh)
37
+ .map((m) => ({
38
+ id: m.id, width: m.width, height: m.height, refresh: m.refresh,
39
+ // `preferred` is kept per *group*: whichever timing survived, the size is still the
40
+ // display's native one and that is what the badge means to a user.
41
+ current: m.current, preferred: m.preferred,
42
+ }));
43
+ }
44
+
45
+ function beats(candidate: HostMode, held: HostMode): boolean {
46
+ if (candidate.current !== held.current) return candidate.current;
47
+ if (candidate.preferred !== held.preferred) return candidate.preferred;
48
+ return candidate.refresh > held.refresh;
49
+ }
50
+
51
+ /** The client's own screen, in the units the host reports its modes in. */
52
+ export interface LocalScreen {
53
+ width: number;
54
+ height: number;
55
+ }
56
+
57
+ /**
58
+ * RustDesk's `_getBestFitResolution` and `_isRemoteResolutionFitLocal` as one decision: the mode
59
+ * to switch to so the host matches this client's screen, or null when the item must not be shown.
60
+ *
61
+ * The match is **exact** — no nearest, no letterboxed approximation. That reads like a missing
62
+ * feature and is the opposite: offering 1920x1080 to a 1366x768 client puts the picture back on
63
+ * the scaler the item exists to avoid, so RustDesk returns null and hides the button instead.
64
+ * On most client/host pairs it is therefore never visible, which is correct.
65
+ */
66
+ export function fitLocalMode(
67
+ modes: readonly HostMode[],
68
+ local: LocalScreen | null,
69
+ currentModeId: string | null,
70
+ ): HostMode | null {
71
+ if (!local || local.width <= 0 || local.height <= 0) return null;
72
+ const group = modes.filter((m) => m.width === local.width && m.height === local.height);
73
+ if (group.length === 0) return null;
74
+ // Compared by *size*, the way RustDesk compares against the display rect rather than a mode id:
75
+ // the host may be on another timing of the size the client already has, and switching between
76
+ // two refresh rates of it would be a menu item that changes nothing the user can see.
77
+ const live = modes.find((m) => m.id === currentModeId) ?? modes.find((m) => m.current) ?? null;
78
+ if (live && live.width === local.width && live.height === local.height) return null;
79
+ // Whichever timing the size's own menu row would offer, so the two cannot disagree.
80
+ return group.reduce((held, m) => (beats(m, held) ? m : held));
81
+ }
82
+
83
+ /**
84
+ * The client's screen in CSS pixels. RustDesk's web branch divides the physical size by
85
+ * `scaleFactor` to get this number; in a browser `screen.width` already is it, and it is the
86
+ * one that makes `scale: original` fill the viewport rather than land at 1 host pixel per
87
+ * *device* pixel — half size on any 2x display.
88
+ */
89
+ export function localScreenSize(): LocalScreen | null {
90
+ if (typeof window === "undefined" || !window.screen) return null;
91
+ const width = Math.round(window.screen.width);
92
+ const height = Math.round(window.screen.height);
93
+ return width > 0 && height > 0 ? { width, height } : null;
94
+ }
95
+
96
+ /** `3440 × 1440`, with the refresh only when there is one to show. */
97
+ export function resolutionLabel(choice: ResolutionChoice): string {
98
+ const size = `${choice.width} × ${choice.height}`;
99
+ return choice.refresh > 0 ? `${size} · ${choice.refresh} Hz` : size;
100
+ }