@hienlh/ppm 0.18.14 → 0.18.15

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 (539) hide show
  1. package/.rdtest2-cf.out +0 -0
  2. package/CHANGELOG.md +18 -0
  3. package/CLAUDE.md +3 -0
  4. package/assets/skills/ppm/SKILL.md +1 -1
  5. package/assets/skills/ppm/references/cli-reference.md +22 -4
  6. package/assets/skills/ppm/references/http-api.md +8 -1
  7. package/dist/web/assets/{adaptive-context-menu-DCZtgOL7.js → adaptive-context-menu-ChBZWLLq.js} +1 -1
  8. package/dist/web/assets/{ai-resource-editor-D5CPBg06.js → ai-resource-editor-C8aAY8Po.js} +1 -1
  9. package/dist/web/assets/{ai-settings-section-DY-t1bK8.js → ai-settings-section-ERu1WiZc.js} +1 -1
  10. package/dist/web/assets/{angular-html-CTvM4ulF.js → angular-html-CXgHIQ2U.js} +1 -1
  11. package/dist/web/assets/{angular-ts-B_vSkjco.js → angular-ts-C8renMV9.js} +1 -1
  12. package/dist/web/assets/api-client-WpZ2FDHg.js +1 -0
  13. package/dist/web/assets/api-settings-BgSEE6et.js +1 -0
  14. package/dist/web/assets/{api-settings-B2iNXQ0c.js → api-settings-R59c66DE.js} +1 -1
  15. package/dist/web/assets/{api-themes-DrWnJbhs.js → api-themes-DKxrwJda.js} +1 -1
  16. package/dist/web/assets/{apl-DywzTry0.js → apl-DkGH8laI.js} +1 -1
  17. package/dist/web/assets/architecture-PBZL5I3N-CCalSKAt.js +1 -0
  18. package/dist/web/assets/{astro-1JaRgaSb.js → astro-tHUd8Zlg.js} +1 -1
  19. package/dist/web/assets/{audio-preview-DAuGvOiK.js → audio-preview-B_C6Dpvz.js} +1 -1
  20. package/dist/web/assets/{blade-CDeeJWBb.js → blade-BbKpjIYK.js} +1 -1
  21. package/dist/web/assets/{bsl-BfgoPVYR.js → bsl-DA0UYto0.js} +1 -1
  22. package/dist/web/assets/{button-tNy0ba3y.js → button-DBSpDPS0.js} +1 -1
  23. package/dist/web/assets/{cairo-C26gNwWW.js → cairo-79ayucbB.js} +1 -1
  24. package/dist/web/assets/chat-tab-BraiJsYG.js +15 -0
  25. package/dist/web/assets/{cobol-D92nBnON.js → cobol-DSS2EOYo.js} +1 -1
  26. package/dist/web/assets/code-editor-lhmLNhXu.js +10 -0
  27. package/dist/web/assets/{coffee-CIWH40R1.js → coffee-DvSxq2iD.js} +1 -1
  28. package/dist/web/assets/{conflict-editor-CDp0I3mD.js → conflict-editor-C4VCv51R.js} +1 -1
  29. package/dist/web/assets/{context-menu-BO1c9jKy.js → context-menu-BpwUny-o.js} +1 -1
  30. package/dist/web/assets/{cpp-DOrBqXCn.js → cpp-BhWZ-FSn.js} +1 -1
  31. package/dist/web/assets/{crystal-BNKqmHux.js → crystal-yP2OeF-f.js} +1 -1
  32. package/dist/web/assets/{csv-preview-D4svNDAq.js → csv-preview-D46W_icb.js} +1 -1
  33. package/dist/web/assets/{data-grid-overlay-editor-BqV0AxZg.js → data-grid-overlay-editor-DeGkPYtA.js} +1 -1
  34. package/dist/web/assets/{database-viewer-BCvv_Bwf.js → database-viewer-DFI4YtrH.js} +1 -1
  35. package/dist/web/assets/{dialog-DcLGDwaX.js → dialog-RIpeb87v.js} +1 -1
  36. package/dist/web/assets/{diff-viewer-D41fCFAi.js → diff-viewer-eaNOLcBL.js} +1 -1
  37. package/dist/web/assets/{docx-preview-DfaQn9v7.js → docx-preview-Cbj-pOK3.js} +1 -1
  38. package/dist/web/assets/{edge-Dbjp42Pt.js → edge-D3K9cd-p.js} +1 -1
  39. package/dist/web/assets/{edit-diff-preview-BqcUuFCc.js → edit-diff-preview-DDqy3KLA.js} +1 -1
  40. package/dist/web/assets/{elixir-na3b1pYy.js → elixir-D4PBmsLp.js} +1 -1
  41. package/dist/web/assets/{elm-_Nalil1R.js → elm-DSpXjuaH.js} +1 -1
  42. package/dist/web/assets/{erb-CW_7dubf.js → erb-CaYZMTJW.js} +1 -1
  43. package/dist/web/assets/{erlang-DmZ7Zzb0.js → erlang-DX5BFqJj.js} +1 -1
  44. package/dist/web/assets/{esm-CwyBetO1.js → esm-Cv7HsFnk.js} +1 -1
  45. package/dist/web/assets/explorer-body-BxbSttfl.js +2 -0
  46. package/dist/web/assets/explorer-window-content-DUqQCC7A.js +1 -0
  47. package/dist/web/assets/{extension-store-DUaZINyC.js → extension-store-B1EClUAr.js} +1 -1
  48. package/dist/web/assets/{extension-webview-BW_mccb3.js → extension-webview-BaGvDk8v.js} +1 -1
  49. package/dist/web/assets/{file-store-yReVbR8q.js → file-store-m9crh6uq.js} +1 -1
  50. package/dist/web/assets/{fortran-fixed-form-DB2A8L4-.js → fortran-fixed-form-B0bAufUe.js} +1 -1
  51. package/dist/web/assets/{fsharp-BYHrti7z.js → fsharp-C2AL2b1M.js} +1 -1
  52. package/dist/web/assets/{gdresource-D5GBin40.js → gdresource-DRQsDMNI.js} +1 -1
  53. package/dist/web/assets/{git-commit-CUiOBoIL.js → git-commit-GtBdnrzk.js} +1 -1
  54. package/dist/web/assets/{git-log-panel-C1QDkmgl.js → git-log-panel-hwV1flSO.js} +1 -1
  55. package/dist/web/assets/{git-rebase-DOxGnpdw.js → git-rebase-h_0CGA6F.js} +1 -1
  56. package/dist/web/assets/gitGraph-HDMCJU4V-DAUrJCqi.js +1 -0
  57. package/dist/web/assets/glide-data-grid-YsN-xm6x.js +138 -0
  58. package/dist/web/assets/{glimmer-js-Begy4UT7.js → glimmer-js-Bxwu93bS.js} +1 -1
  59. package/dist/web/assets/{glimmer-ts-rPApRY8N.js → glimmer-ts-CIUYdR4E.js} +1 -1
  60. package/dist/web/assets/{glsl-wrbPvrBL.js → glsl-CfxLI5jn.js} +1 -1
  61. package/dist/web/assets/{graphql-Cu4-NR__.js → graphql-CstqDPde.js} +1 -1
  62. package/dist/web/assets/group-chat-tab-B7mJO1gG.js +1 -0
  63. package/dist/web/assets/{hack-Ddo93XKD.js → hack-Bjqnssb5.js} +1 -1
  64. package/dist/web/assets/{haml-BFX_1i8j.js → haml-lVc-DfbM.js} +1 -1
  65. package/dist/web/assets/hand-x0ejq3fS.js +1 -0
  66. package/dist/web/assets/{handlebars-5gFKA4H5.js → handlebars-Yy6fPQI_.js} +1 -1
  67. package/dist/web/assets/{html-derivative-e5JLAFZF.js → html-derivative-CchzCY1z.js} +1 -1
  68. package/dist/web/assets/{html-C06I-zeO.js → html-lqtcy6-2.js} +1 -1
  69. package/dist/web/assets/{http-CrAAhSU7.js → http-ChclRrko.js} +1 -1
  70. package/dist/web/assets/{hurl-T1V3SX9T.js → hurl-CoOK7sXa.js} +1 -1
  71. package/dist/web/assets/{hxml-B056LLKN.js → hxml-fZSZ7Iyt.js} +1 -1
  72. package/dist/web/assets/{image-preview-DWyuCYT3.js → image-preview-ClAcqDlL.js} +1 -1
  73. package/dist/web/assets/index-CtJbMNNI.css +2 -0
  74. package/dist/web/assets/index-H_gScEOk.js +52 -0
  75. package/dist/web/assets/info-3K5VOQVL-Cx1ZfJbp.js +1 -0
  76. package/dist/web/assets/{input-DouJ9Zvt.js → input-DXPgUtxi.js} +1 -1
  77. package/dist/web/assets/{jinja-DGdtRh43.js → jinja-Y0w_KBdE.js} +1 -1
  78. package/dist/web/assets/{jison-Ah6QobPS.js → jison-BILj3F2e.js} +1 -1
  79. package/dist/web/assets/{julia-BJeGOK0K.js → julia-DRfOPDts.js} +1 -1
  80. package/dist/web/assets/{just-iw9oRs7j.js → just-n3U_oODO.js} +1 -1
  81. package/dist/web/assets/keybindings-store-BqctreaI.js +1 -0
  82. package/dist/web/assets/{keybindings-store-0Wqfa7Qp.js → keybindings-store-D-CHdq-G.js} +1 -1
  83. package/dist/web/assets/keyboard-DBBaoQSu.js +1 -0
  84. package/dist/web/assets/{latex-DHjj5hyN.js → latex-D6gztEOL.js} +1 -1
  85. package/dist/web/assets/{liquid-B-FFecDc.js → liquid-DPqCEVb9.js} +1 -1
  86. package/dist/web/assets/{lua-DDianJp_.js → lua-I40KPUm-.js} +1 -1
  87. package/dist/web/assets/markdown-renderer-BwOkiZC1.js +1 -0
  88. package/dist/web/assets/{markdown-renderer-BHiUhQN8.js → markdown-renderer-oJ9jPdQ2.js} +3 -3
  89. package/dist/web/assets/{marko-BW5SBVng.js → marko-DMjsThSW.js} +1 -1
  90. package/dist/web/assets/{mdc-B9gL9bjl.js → mdc-CN2alsbo.js} +1 -1
  91. package/dist/web/assets/{media-url-DUK-k0bB.js → media-url-COUvasjn.js} +1 -1
  92. package/dist/web/assets/mobile-bottom-sheet-Cj1YBq-c.js +1 -0
  93. package/dist/web/assets/mobile-explorer-sheet-D1nM0Ik1.js +1 -0
  94. package/dist/web/assets/{nextflow-dTluY6qy.js → nextflow-CGa4JeZ6.js} +1 -1
  95. package/dist/web/assets/{nginx-DlwghGI-.js → nginx-CmqrIj84.js} +1 -1
  96. package/dist/web/assets/{nim-N9jddb5D.js → nim-CqhmTeMa.js} +1 -1
  97. package/dist/web/assets/notification-store-n-XEQ5pH.js +1 -0
  98. package/dist/web/assets/{number-overlay-editor-BVXM7aAs.js → number-overlay-editor-BEzJ1YeD.js} +1 -1
  99. package/dist/web/assets/{overview-panel-DCCDmtCQ.js → overview-panel-Bf9Gn8qV.js} +1 -1
  100. package/dist/web/assets/packet-RMMSAZCW-Bqwiy7dz.js +1 -0
  101. package/dist/web/assets/{panel-store-B4rijFKN.js → panel-store-UWCH6B-_.js} +1 -1
  102. package/dist/web/assets/{pdf-preview-D7yLmAZW.js → pdf-preview-BMHM5cR2.js} +1 -1
  103. package/dist/web/assets/{perl-CkmpYKa_.js → perl-BOwpb6Tb.js} +1 -1
  104. package/dist/web/assets/{php-BwZ3KDPo.js → php-wT9fVxxu.js} +1 -1
  105. package/dist/web/assets/pie-UPGHQEXC-BXSJ2God.js +1 -0
  106. package/dist/web/assets/{postgres-viewer--CRN1fvO.js → postgres-viewer-D8rfEY5b.js} +3 -3
  107. package/dist/web/assets/process-table-CsQ-hDJr.js +1 -0
  108. package/dist/web/assets/{project-store-BuY7rxn_.js → project-store-CKAOr23O.js} +1 -1
  109. package/dist/web/assets/{pug-B3rBPqQo.js → pug-DdlNnj-p.js} +1 -1
  110. package/dist/web/assets/{qml-BfDbWFmg.js → qml-C5zBdydf.js} +1 -1
  111. package/dist/web/assets/radar-KQ55EAFF-D6XrM7HH.js +1 -0
  112. package/dist/web/assets/{razor-B1ww1r38.js → razor-DqcJX4iq.js} +1 -1
  113. package/dist/web/assets/remote-desktop-mobile-sheet-CTiipn4k.js +2 -0
  114. package/dist/web/assets/remote-desktop-mobile-view-Cf5B0dKo.js +1 -0
  115. package/dist/web/assets/remote-desktop-stats-overlay-vhJBIW7s.js +1 -0
  116. package/dist/web/assets/remote-desktop-window-content-wCJUfI6G.js +1 -0
  117. package/dist/web/assets/{rst-C0MSq6m-.js → rst-DiMiMYUO.js} +1 -1
  118. package/dist/web/assets/{ruby-ClIZ1wb3.js → ruby-DK62iflA.js} +1 -1
  119. package/dist/web/assets/{run-in-terminal-4efbW2Xv.js → run-in-terminal-DJSL6nwZ.js} +1 -1
  120. package/dist/web/assets/{sas-DR0j3o4_.js → sas-6QPGJRa5.js} +1 -1
  121. package/dist/web/assets/{scroll-area-ZP8wcwTI.js → scroll-area-DXGXeiRz.js} +1 -1
  122. package/dist/web/assets/{scss-Vh3JLayR.js → scss-DmUqh48_.js} +1 -1
  123. package/dist/web/assets/{send-to-chat-BNrEpAyC.js → send-to-chat-BOony0sO.js} +1 -1
  124. package/dist/web/assets/settings-store-BpcY5aYE.js +2 -0
  125. package/dist/web/assets/settings-tab-BVqRO01j.js +1 -0
  126. package/dist/web/assets/settings-tab-FH581A_i.js +3 -0
  127. package/dist/web/assets/{shaderlab-0rHRnQ18.js → shaderlab-DopFR1mi.js} +1 -1
  128. package/dist/web/assets/{shellsession-Dxdw6D8c.js → shellsession-Bp_TGuXb.js} +1 -1
  129. package/dist/web/assets/{soy-BHlSNj1y.js → soy-DEB9KEFb.js} +1 -1
  130. package/dist/web/assets/{sparql-B2QaPpni.js → sparql-C8lEwO1p.js} +1 -1
  131. package/dist/web/assets/{sql-query-editor-R_iKjPP9.js → sql-query-editor-MMfk0Kbz.js} +1 -1
  132. package/dist/web/assets/{sqlite-viewer-b2onA0SP.js → sqlite-viewer-vglzrgnZ.js} +1 -1
  133. package/dist/web/assets/{stata-CwIxjsEJ.js → stata-DVep4apN.js} +1 -1
  134. package/dist/web/assets/{surrealql-C6vo-rp-.js → surrealql-fSlJApOA.js} +1 -1
  135. package/dist/web/assets/{svelte-LLdJ6rlH.js → svelte-DezWBEDi.js} +1 -1
  136. package/dist/web/assets/{switch-DV-BDjyk.js → switch-DqL_ZjB_.js} +1 -1
  137. package/dist/web/assets/system-monitor-body-BYUfyF8f.js +2 -0
  138. package/dist/web/assets/system-monitor-tab-CKGXB8lH.js +1 -0
  139. package/dist/web/assets/{system-monitor-window-content-BPif0azo.js → system-monitor-window-content-CiJ2yIsr.js} +1 -1
  140. package/dist/web/assets/{tab-host-window-content-BnAN6m4K.js → tab-host-window-content-DYlXR0cg.js} +1 -1
  141. package/dist/web/assets/{tab-store-tFnyPmm4.js → tab-store-D2thn4Vv.js} +1 -1
  142. package/dist/web/assets/team-member-sheet-Bnygu7Xw.js +2 -0
  143. package/dist/web/assets/{team-member-window-content-BSyU-5Uc.js → team-member-window-content-qrgFTC96.js} +1 -1
  144. package/dist/web/assets/{templ-CJGvhEP5.js → templ-D0zB42a9.js} +1 -1
  145. package/dist/web/assets/{terminal-tab-Ncor0Rfu.js → terminal-tab-D_-R5rGm.js} +3 -3
  146. package/dist/web/assets/{tex-psXWhc4t.js → tex-BJiPijcH.js} +1 -1
  147. package/dist/web/assets/{tool-cards-DdVP1wrD.js → tool-cards-BW7Xc20J.js} +4 -4
  148. package/dist/web/assets/treemap-KZPCXAKY-BobWhcHN.js +1 -0
  149. package/dist/web/assets/{ts-tags-D5Ar_ZCO.js → ts-tags-Dcr4u6y5.js} +1 -1
  150. package/dist/web/assets/{twig-vJgGC-qY.js → twig-B-SQU0bg.js} +1 -1
  151. package/dist/web/assets/{use-blob-url-BOVGWg9F.js → use-blob-url-BtPlqwLr.js} +1 -1
  152. package/dist/web/assets/{use-monaco-theme-BshnLXoY.js → use-monaco-theme-DQY1ZSaf.js} +1 -1
  153. package/dist/web/assets/{use-open-team-member-CY3wOdWL.js → use-open-team-member-C5LQ_TCM.js} +1 -1
  154. package/dist/web/assets/use-visual-viewport-pVxLfE5B.js +1 -0
  155. package/dist/web/assets/{use-websocket-B7xjNsyD.js → use-websocket-l39Odhlp.js} +1 -1
  156. package/dist/web/assets/{vendor-mermaid-999ksD45.js → vendor-mermaid-CtDsSxbM.js} +1 -1
  157. package/dist/web/assets/{video-preview-7F72sRwf.js → video-preview-C5AhkIDl.js} +1 -1
  158. package/dist/web/assets/{vue-BWngFyav.js → vue-Cw10Sfbh.js} +1 -1
  159. package/dist/web/assets/{vue-html-BN5ZLu-H.js → vue-html-Cc5C_Z_w.js} +1 -1
  160. package/dist/web/assets/{vue-vine-BZHnO8yV.js → vue-vine-BuNMlnvu.js} +1 -1
  161. package/dist/web/assets/{window-pip-registry-BnYU83LE.js → window-pip-registry-C7oz3Dfy.js} +1 -1
  162. package/dist/web/assets/window-store-B5ZswdYg.js +1 -0
  163. package/dist/web/assets/{xml-DS2beZHp.js → xml-DqT1wkky.js} +1 -1
  164. package/dist/web/assets/{xsl-Ciiku1Bq.js → xsl-DLkge3A2.js} +1 -1
  165. package/dist/web/index.html +45 -43
  166. package/dist/web/sw.js +1 -1
  167. package/docs/architecture/ai-chat-and-providers.md +3 -0
  168. package/package.json +1 -1
  169. package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
  170. package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
  171. package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
  172. package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
  173. package/src/cli/commands/backup-cmd.ts +119 -0
  174. package/src/index.ts +3 -0
  175. package/src/providers/claude-agent-sdk.ts +29 -1
  176. package/src/server/index.ts +42 -15
  177. package/src/server/routes/accounts.ts +30 -2
  178. package/src/server/routes/chat.ts +8 -1
  179. package/src/server/routes/named-tunnel.ts +5 -2
  180. package/src/server/routes/remote-desktop.ts +64 -0
  181. package/src/server/routes/settings.ts +1 -0
  182. package/src/server/ws/chat.ts +126 -7
  183. package/src/server/ws/remote-desktop.ts +86 -0
  184. package/src/services/account.service.ts +106 -23
  185. package/src/services/db-backup/db-backup-paths.ts +66 -0
  186. package/src/services/db-backup/db-backup-restore.ts +105 -0
  187. package/src/services/db-backup/db-backup-retention.ts +96 -0
  188. package/src/services/db-backup/db-backup-sync.ts +113 -0
  189. package/src/services/db-backup/db-backup.service.ts +61 -0
  190. package/src/services/db.service.ts +29 -1
  191. package/src/services/edge-forwarder.ts +191 -191
  192. package/src/services/fs-credential-path-guard.ts +19 -1
  193. package/src/services/named-tunnel/cloudflared-login.service.ts +2 -2
  194. package/src/services/nested-subagent-spy.ts +206 -0
  195. package/src/services/remote-desktop/access-unit-assembler.ts +90 -0
  196. package/src/services/remote-desktop/avc1-codec-string.ts +18 -0
  197. package/src/services/remote-desktop/nal-splitter.ts +100 -0
  198. package/src/services/remote-desktop/remote-desktop-capture.ts +120 -0
  199. package/src/services/remote-desktop/remote-desktop-encoder-args.ts +42 -0
  200. package/src/services/remote-desktop/remote-desktop-flag.ts +10 -0
  201. package/src/services/remote-desktop/remote-desktop-input.ts +217 -0
  202. package/src/services/remote-desktop/remote-desktop-nonce.ts +38 -0
  203. package/src/services/remote-desktop/remote-desktop-session.ts +189 -0
  204. package/src/services/remote-desktop/remote-desktop-vk-map.ts +41 -0
  205. package/src/services/subagent-transcript-merger.ts +92 -75
  206. package/src/services/subprocess-retention.ts +29 -6
  207. package/src/services/supervisor.ts +58 -0
  208. package/src/services/team-member-activity/subagent-transcript-index.ts +56 -0
  209. package/src/services/windows-process-tree.ts +351 -351
  210. package/src/types/chat.ts +2 -0
  211. package/src/web/app.tsx +8 -0
  212. package/src/web/components/chat/account-dialogs.tsx +11 -4
  213. package/src/web/components/chat/question-card.tsx +9 -2
  214. package/src/web/components/chat/usage-badge.tsx +17 -3
  215. package/src/web/components/floating-window/window-content-registry.ts +2 -0
  216. package/src/web/components/floating-window/window-store-types.ts +1 -1
  217. package/src/web/components/layout/mobile-drawer.tsx +38 -27
  218. package/src/web/components/layout/nav-section-rail.tsx +10 -2
  219. package/src/web/components/remote-desktop/open-remote-desktop.ts +26 -0
  220. package/src/web/components/remote-desktop/remote-desktop-coords.ts +98 -0
  221. package/src/web/components/remote-desktop/remote-desktop-frame-timestamp.ts +21 -0
  222. package/src/web/components/remote-desktop/remote-desktop-gesture-classifiers.ts +56 -0
  223. package/src/web/components/remote-desktop/remote-desktop-mobile-key-bar.tsx +131 -0
  224. package/src/web/components/remote-desktop/remote-desktop-mobile-sheet.tsx +43 -0
  225. package/src/web/components/remote-desktop/remote-desktop-mobile-toolbar.tsx +79 -0
  226. package/src/web/components/remote-desktop/remote-desktop-mobile-view.tsx +190 -0
  227. package/src/web/components/remote-desktop/remote-desktop-stats-overlay.tsx +54 -0
  228. package/src/web/components/remote-desktop/remote-desktop-stats.ts +37 -0
  229. package/src/web/components/remote-desktop/remote-desktop-touch-gesture-tracker.ts +195 -0
  230. package/src/web/components/remote-desktop/remote-desktop-window-content.tsx +72 -0
  231. package/src/web/components/remote-desktop/remote-desktop-ws-url.ts +22 -0
  232. package/src/web/components/remote-desktop/use-h264-canvas-decoder.ts +175 -0
  233. package/src/web/components/remote-desktop/use-remote-desktop-available.ts +29 -0
  234. package/src/web/components/remote-desktop/use-remote-desktop-connection.ts +147 -0
  235. package/src/web/components/remote-desktop/use-remote-desktop-mobile-open-state.ts +18 -0
  236. package/src/web/components/remote-desktop/use-remote-desktop-touch.ts +224 -0
  237. package/src/web/components/remote-desktop/use-remote-desktop-virtual-keyboard.ts +50 -0
  238. package/src/web/components/remote-desktop/use-remote-input-capture.ts +92 -0
  239. package/src/web/components/tunnels/named-tunnel/named-tunnel-copy.ts +59 -59
  240. package/src/web/components/tunnels/named-tunnel/named-tunnel-section.tsx +2 -2
  241. package/src/web/hooks/use-notification-badge.ts +19 -11
  242. package/src/web/lib/feature-badges.ts +2 -0
  243. package/src/web/stores/settings-store.ts +13 -0
  244. package/src/web/stores/streaming-store.ts +21 -2
  245. package/dist/web/assets/api-client-BogqsFna.js +0 -1
  246. package/dist/web/assets/api-settings-DRF9oYkn.js +0 -1
  247. package/dist/web/assets/architecture-PBZL5I3N-nw5-j_I_.js +0 -1
  248. package/dist/web/assets/chat-tab-IcnU3nqQ.js +0 -15
  249. package/dist/web/assets/code-editor-Dno5Srkm.js +0 -10
  250. package/dist/web/assets/explorer-body-DB1L30pa.js +0 -2
  251. package/dist/web/assets/explorer-window-content-Cwlt3C3I.js +0 -1
  252. package/dist/web/assets/gitGraph-HDMCJU4V-C1xf87gN.js +0 -1
  253. package/dist/web/assets/glide-data-grid-Dz8lx6n2.js +0 -138
  254. package/dist/web/assets/group-chat-tab-DFwr-pig.js +0 -1
  255. package/dist/web/assets/index-DWpNR3nB.css +0 -2
  256. package/dist/web/assets/index-oUKV5nIA.js +0 -52
  257. package/dist/web/assets/info-3K5VOQVL-C2z7FTDe.js +0 -1
  258. package/dist/web/assets/keybindings-store-d54pv2NK.js +0 -1
  259. package/dist/web/assets/markdown-renderer-CnE36_gd.js +0 -1
  260. package/dist/web/assets/mobile-bottom-sheet-CJ7ApOkI.js +0 -1
  261. package/dist/web/assets/mobile-explorer-sheet-BzjlS1Xn.js +0 -1
  262. package/dist/web/assets/notification-store-C7UBqxYP.js +0 -1
  263. package/dist/web/assets/packet-RMMSAZCW-DQUxN0wU.js +0 -1
  264. package/dist/web/assets/pie-UPGHQEXC-BOr9ek4Q.js +0 -1
  265. package/dist/web/assets/process-table-CXC10GSy.js +0 -1
  266. package/dist/web/assets/radar-KQ55EAFF-DSErxZFb.js +0 -1
  267. package/dist/web/assets/settings-store-OLJE7dPH.js +0 -2
  268. package/dist/web/assets/settings-tab-B1rvHFc6.js +0 -3
  269. package/dist/web/assets/settings-tab-BUlmPJ2w.js +0 -1
  270. package/dist/web/assets/system-monitor-body-DPYQlBEt.js +0 -2
  271. package/dist/web/assets/system-monitor-tab-CPQdWv27.js +0 -1
  272. package/dist/web/assets/team-member-sheet-Bu2wG1sm.js +0 -2
  273. package/dist/web/assets/treemap-KZPCXAKY-C17p0LQw.js +0 -1
  274. package/dist/web/assets/window-store-CQ1lghvv.js +0 -1
  275. /package/dist/web/assets/{abap-CjzrhAS2.js → abap-CKgBNk5K.js} +0 -0
  276. /package/dist/web/assets/{actionscript-3-B59Kbl-9.js → actionscript-3-oARhAY6c.js} +0 -0
  277. /package/dist/web/assets/{ada-B7gItKAE.js → ada-2vi8ASy3.js} +0 -0
  278. /package/dist/web/assets/{andromeeda-Dy5zcy0Q.js → andromeeda-B3vMjPKd.js} +0 -0
  279. /package/dist/web/assets/{apache-B6T9jrc0.js → apache-DnIEr338.js} +0 -0
  280. /package/dist/web/assets/{apex-CTsIxDQw.js → apex-B7Qs5AY5.js} +0 -0
  281. /package/dist/web/assets/{api-client-oY1tC3tM.js → api-client-BkGKTjsq.js} +0 -0
  282. /package/dist/web/assets/{applescript-DuycKmmb.js → applescript-EbQNUCWb.js} +0 -0
  283. /package/dist/web/assets/{apply-theme-r8tKDrCR.js → apply-theme-Dd_cqGa-.js} +0 -0
  284. /package/dist/web/assets/{ara-CISL3599.js → ara-CtHdhFRw.js} +0 -0
  285. /package/dist/web/assets/{asciidoc-BXyE2Lpr.js → asciidoc-BH6qin_O.js} +0 -0
  286. /package/dist/web/assets/{asm-y258phtP.js → asm-D1XU1ACk.js} +0 -0
  287. /package/dist/web/assets/{aurora-x-Dq3Jc78M.js → aurora-x-BkhcxkuS.js} +0 -0
  288. /package/dist/web/assets/{awk-DxL6XSJv.js → awk-DijzB6o7.js} +0 -0
  289. /package/dist/web/assets/{ayu-dark-DjoK6Evo.js → ayu-dark-tysG77WC.js} +0 -0
  290. /package/dist/web/assets/{ayu-light-CKKXBLMI.js → ayu-light-Dg0WMETC.js} +0 -0
  291. /package/dist/web/assets/{ayu-mirage-DGXSrrXB.js → ayu-mirage--RsJCjC4.js} +0 -0
  292. /package/dist/web/assets/{ballerina-DZSXFmUf.js → ballerina-DT_5-l82.js} +0 -0
  293. /package/dist/web/assets/{bat-BNsZk6nY.js → bat-BRpDlkv0.js} +0 -0
  294. /package/dist/web/assets/{beancount-cPl4gJct.js → beancount--8Df-WGG.js} +0 -0
  295. /package/dist/web/assets/{berry-DGAodERk.js → berry-Bc9fo35J.js} +0 -0
  296. /package/dist/web/assets/{bibtex-DftVoRif.js → bibtex-CwyBpp9X.js} +0 -0
  297. /package/dist/web/assets/{bicep-Suioyyzh.js → bicep-DiyH2Bs7.js} +0 -0
  298. /package/dist/web/assets/{bird2-DjU24I2P.js → bird2-CHgK4a2A.js} +0 -0
  299. /package/dist/web/assets/{c-DFi8Y_nN.js → c-BM1qL6-f.js} +0 -0
  300. /package/dist/web/assets/{c3-1eSHnH5V.js → c3-D2oOjrP7.js} +0 -0
  301. /package/dist/web/assets/{cadence-DLLsFwQP.js → cadence-nS45wqF6.js} +0 -0
  302. /package/dist/web/assets/{can-open-in-ppm-in727eFQ.js → can-open-in-ppm-DwP9KU8o.js} +0 -0
  303. /package/dist/web/assets/{catppuccin-frappe-DDj0JEiY.js → catppuccin-frappe-BpnJHiCj.js} +0 -0
  304. /package/dist/web/assets/{catppuccin-latte-DPyANHyR.js → catppuccin-latte-Bb95Wj3h.js} +0 -0
  305. /package/dist/web/assets/{catppuccin-macchiato-CO-h8VTT.js → catppuccin-macchiato-Btx8c17W.js} +0 -0
  306. /package/dist/web/assets/{catppuccin-mocha-BCmbN2IZ.js → catppuccin-mocha-B4DZOUGI.js} +0 -0
  307. /package/dist/web/assets/{clarity-C0pYsZjs.js → clarity-1ps69jU6.js} +0 -0
  308. /package/dist/web/assets/{clipboard-DBLGKMrH.js → clipboard-CrHX8AYw.js} +0 -0
  309. /package/dist/web/assets/{clojure-JFr6s8iZ.js → clojure-BklC0hKV.js} +0 -0
  310. /package/dist/web/assets/{cmake-EEcLEgVy.js → cmake-B573LYAQ.js} +0 -0
  311. /package/dist/web/assets/{codeowners-Deh3Lx0u.js → codeowners-BoYeX89M.js} +0 -0
  312. /package/dist/web/assets/{codeql-C317igT5.js → codeql-7Dhf5Udk.js} +0 -0
  313. /package/dist/web/assets/{common-lisp-DepbATZs.js → common-lisp-m1nxlthv.js} +0 -0
  314. /package/dist/web/assets/{coq-MxgxU5ya.js → coq-DNhGmd4a.js} +0 -0
  315. /package/dist/web/assets/{csharp-eEFXdsAq.js → csharp-P-nAurtS.js} +0 -0
  316. /package/dist/web/assets/{css-Db-syWW9.js → css-LYbSeh3-.js} +0 -0
  317. /package/dist/web/assets/{csv-DHeYcbaq.js → csv-DHZZZm7X.js} +0 -0
  318. /package/dist/web/assets/{csv-parser-_JWMLGl3.js → csv-parser-CY9Ggtg5.js} +0 -0
  319. /package/dist/web/assets/{cue-BmUNowrt.js → cue-D8yLUOle.js} +0 -0
  320. /package/dist/web/assets/{cypher-XjXHgCNS.js → cypher-9cbW8RYA.js} +0 -0
  321. /package/dist/web/assets/{d-BWJnZtig.js → d-ZihzhxqI.js} +0 -0
  322. /package/dist/web/assets/{dark-plus-Db7umas1.js → dark-plus-C8xIA1u3.js} +0 -0
  323. /package/dist/web/assets/{dart-DSI4HYh1.js → dart-CBm6jKc7.js} +0 -0
  324. /package/dist/web/assets/{data-grid-types-CfVHh9gv.js → data-grid-types-DkEQ-Na9.js} +0 -0
  325. /package/dist/web/assets/{dax-yw1JsAni.js → dax-B3cx6YeV.js} +0 -0
  326. /package/dist/web/assets/{desktop-C2QO4RvD.js → desktop-C03SpXth.js} +0 -0
  327. /package/dist/web/assets/{diff-Drt8aEyp.js → diff-D8LnnvFY.js} +0 -0
  328. /package/dist/web/assets/{dist-DNRvhVdz.js → dist-C4XoS_zo.js} +0 -0
  329. /package/dist/web/assets/{dist-VBxOHLmN.js → dist-Do3fljss.js} +0 -0
  330. /package/dist/web/assets/{docker-ByDKbmLl.js → docker-DwFiOQWW.js} +0 -0
  331. /package/dist/web/assets/{dotenv-BkfOLytR.js → dotenv-CVJ_vFSQ.js} +0 -0
  332. /package/dist/web/assets/{dracula-DAmrm-Un.js → dracula-DMw8UACY.js} +0 -0
  333. /package/dist/web/assets/{dracula-soft-BUOEnKqR.js → dracula-soft-BnB3nDrA.js} +0 -0
  334. /package/dist/web/assets/{dream-maker-DQBIfSiO.js → dream-maker-2riXUQXo.js} +0 -0
  335. /package/dist/web/assets/{emacs-lisp-Blh5kBD3.js → emacs-lisp-BQdYaiB5.js} +0 -0
  336. /package/dist/web/assets/{everforest-dark-CEzhDxHq.js → everforest-dark-C2FPIWdj.js} +0 -0
  337. /package/dist/web/assets/{everforest-light-CPk_5Khm.js → everforest-light-DMOWf9sD.js} +0 -0
  338. /package/dist/web/assets/{fennel-B1MT_EBZ.js → fennel-JtSHp0vW.js} +0 -0
  339. /package/dist/web/assets/{fish-C_HGcewt.js → fish-CflDcRfe.js} +0 -0
  340. /package/dist/web/assets/{fluent-Dp1Iclmx.js → fluent-D4eu6Vac.js} +0 -0
  341. /package/dist/web/assets/{format-bytes-53WBtyi2.js → format-bytes-DR3228bu.js} +0 -0
  342. /package/dist/web/assets/{fortran-free-form-B_-UA4XC.js → fortran-free-form-hO4RuC9Z.js} +0 -0
  343. /package/dist/web/assets/{gdscript-Bm_JpjS_.js → gdscript-D7n3a8VM.js} +0 -0
  344. /package/dist/web/assets/{gdshader-C_PNmfYU.js → gdshader-BhUmrlzG.js} +0 -0
  345. /package/dist/web/assets/{genie-B5rmR2TF.js → genie-VbyftqBp.js} +0 -0
  346. /package/dist/web/assets/{gherkin-BTJ34TJ9.js → gherkin-BZzhvUUb.js} +0 -0
  347. /package/dist/web/assets/{github-dark-DOkNVj9H.js → github-dark-C4q41woW.js} +0 -0
  348. /package/dist/web/assets/{github-dark-default-DTsmiyVo.js → github-dark-default-CMNi7dQX.js} +0 -0
  349. /package/dist/web/assets/{github-dark-dimmed-CjbxAe9s.js → github-dark-dimmed-BRf_-LlY.js} +0 -0
  350. /package/dist/web/assets/{github-dark-high-contrast-r_M8F_k7.js → github-dark-high-contrast-xanKBsRI.js} +0 -0
  351. /package/dist/web/assets/{github-light-BzfxyMyb.js → github-light-BEQeNQCs.js} +0 -0
  352. /package/dist/web/assets/{github-light-default-BOqiBIy5.js → github-light-default-ceQrtdXg.js} +0 -0
  353. /package/dist/web/assets/{github-light-high-contrast-DQzBrDM4.js → github-light-high-contrast-doKbXzgW.js} +0 -0
  354. /package/dist/web/assets/{gleam-BWmuAtD8.js → gleam-Chzqf4fT.js} +0 -0
  355. /package/dist/web/assets/{gn-CNQPjiZW.js → gn-CCN_-6fp.js} +0 -0
  356. /package/dist/web/assets/{gnuplot-BlHjcPMe.js → gnuplot-CIplgwwP.js} +0 -0
  357. /package/dist/web/assets/{go-Bn8Ba9uz.js → go-Cjj-9dRs.js} +0 -0
  358. /package/dist/web/assets/{groovy-C1Y1_F4V.js → groovy-PqD4K7X1.js} +0 -0
  359. /package/dist/web/assets/{gruvbox-dark-hard-DueOsHav.js → gruvbox-dark-hard-BAbpUSF-.js} +0 -0
  360. /package/dist/web/assets/{gruvbox-dark-medium-DaQjD538.js → gruvbox-dark-medium-BWcWXDBB.js} +0 -0
  361. /package/dist/web/assets/{gruvbox-dark-soft-CbbX2WOm.js → gruvbox-dark-soft-Dkx1okkk.js} +0 -0
  362. /package/dist/web/assets/{gruvbox-light-hard-E2M70ljZ.js → gruvbox-light-hard-WVsDK0MM.js} +0 -0
  363. /package/dist/web/assets/{gruvbox-light-medium-B_DDLY6h.js → gruvbox-light-medium-tiR9t7gr.js} +0 -0
  364. /package/dist/web/assets/{gruvbox-light-soft-2SZmyC1F.js → gruvbox-light-soft-HzHohaX6.js} +0 -0
  365. /package/dist/web/assets/{haskell-D8DeoXtG.js → haskell-B1eIZfr6.js} +0 -0
  366. /package/dist/web/assets/{haxe-BmZm7B0W.js → haxe-BcDdi5xr.js} +0 -0
  367. /package/dist/web/assets/{hcl-CKnBM3ng.js → hcl-Dq-HKVni.js} +0 -0
  368. /package/dist/web/assets/{hjson-Ct9t4-ci.js → hjson-Dr9D9WVU.js} +0 -0
  369. /package/dist/web/assets/{hlsl-BZSASBqS.js → hlsl-Bo8t2FuZ.js} +0 -0
  370. /package/dist/web/assets/{horizon-CzX1AZ08.js → horizon-DWG5IXc-.js} +0 -0
  371. /package/dist/web/assets/{horizon-bright-CCVNeRIP.js → horizon-bright-DFr9wTTx.js} +0 -0
  372. /package/dist/web/assets/{houston-DBlJN7xc.js → houston-NAVNhkup.js} +0 -0
  373. /package/dist/web/assets/{hy-Dyc6h6Xb.js → hy-DnyvUk3B.js} +0 -0
  374. /package/dist/web/assets/{image-gallery-DujlrjOC.js → image-gallery-DoFdNF9i.js} +0 -0
  375. /package/dist/web/assets/{imba-Bauru7s2.js → imba-CPbR5W_A.js} +0 -0
  376. /package/dist/web/assets/{ini-SjdwtaTp.js → ini-lc8_Lt0y.js} +0 -0
  377. /package/dist/web/assets/{java-D2r0ocpf.js → java-B0KCo2vK.js} +0 -0
  378. /package/dist/web/assets/{javascript-y-lof7iP.js → javascript-YqEbNRpd.js} +0 -0
  379. /package/dist/web/assets/{json-DO4LSx5A.js → json-Co0WtOlh.js} +0 -0
  380. /package/dist/web/assets/{json5-BEwWf-W3.js → json5-2Jhb0QUN.js} +0 -0
  381. /package/dist/web/assets/{jsonc-OBEFv7gP.js → jsonc-e72F11nU.js} +0 -0
  382. /package/dist/web/assets/{jsonl-DOyW4Mg3.js → jsonl-Bff8IPye.js} +0 -0
  383. /package/dist/web/assets/{jsonnet-BL5R2CpP.js → jsonnet-DRCkb-_H.js} +0 -0
  384. /package/dist/web/assets/{jssm-ksPusAyg.js → jssm-C6UiwVEm.js} +0 -0
  385. /package/dist/web/assets/{jsx-B6XEu6O-.js → jsx-u1aZlnfA.js} +0 -0
  386. /package/dist/web/assets/{kanagawa-dragon-JBVe_ji_.js → kanagawa-dragon-De-RQFV3.js} +0 -0
  387. /package/dist/web/assets/{kanagawa-lotus-ChprO68_.js → kanagawa-lotus-K8elE4QU.js} +0 -0
  388. /package/dist/web/assets/{kanagawa-wave-D_uB_R0Q.js → kanagawa-wave-BrStl_zx.js} +0 -0
  389. /package/dist/web/assets/{kdl-pf5B8N_m.js → kdl-CLCfMeZy.js} +0 -0
  390. /package/dist/web/assets/{kotlin-BdF0METC.js → kotlin-DEEC3pNh.js} +0 -0
  391. /package/dist/web/assets/{kusto-BneVP-OU.js → kusto-DTqRhCup.js} +0 -0
  392. /package/dist/web/assets/{laserwave-C4-UPIyG.js → laserwave-DsgpUSbA.js} +0 -0
  393. /package/dist/web/assets/{lean-BN6Jdymq.js → lean-Dl9MI0Y3.js} +0 -0
  394. /package/dist/web/assets/{less-Cx-fdlDC.js → less-Bg21rao6.js} +0 -0
  395. /package/dist/web/assets/{lib-CMuBa85c.js → lib-CXUwxw1M.js} +0 -0
  396. /package/dist/web/assets/{libesm-BB74PRsH.js → libesm-CVkncAQz.js} +0 -0
  397. /package/dist/web/assets/{light-plus-DFnnn_iL.js → light-plus-DGNbbK1V.js} +0 -0
  398. /package/dist/web/assets/{llvm-BGxtW0Nw.js → llvm-91_ZX3p-.js} +0 -0
  399. /package/dist/web/assets/{loader-circle-Dpqcv0eS.js → loader-circle-DouKgIXy.js} +0 -0
  400. /package/dist/web/assets/{lock-DldbT31x.js → lock-CNxUGpTk.js} +0 -0
  401. /package/dist/web/assets/{log-kQb4eJnj.js → log-DSXzbq8u.js} +0 -0
  402. /package/dist/web/assets/{logo-DqAzaq7s.js → logo-BQRNd4tc.js} +0 -0
  403. /package/dist/web/assets/{luau-Dc2cp-zS.js → luau-BE-TMpiZ.js} +0 -0
  404. /package/dist/web/assets/{make-DYg9dwaJ.js → make-ePYGKTpc.js} +0 -0
  405. /package/dist/web/assets/{markdown-O4EPpS3K.js → markdown-Cst3wgMW.js} +0 -0
  406. /package/dist/web/assets/{material-theme-ClP8yfQ2.js → material-theme-9XyvnNLb.js} +0 -0
  407. /package/dist/web/assets/{material-theme-darker-LOK55hGu.js → material-theme-darker-H1VN4MTS.js} +0 -0
  408. /package/dist/web/assets/{material-theme-lighter-j72tzZqi.js → material-theme-lighter-DAreBbuF.js} +0 -0
  409. /package/dist/web/assets/{material-theme-ocean-C19LKClA.js → material-theme-ocean-BpTR-3II.js} +0 -0
  410. /package/dist/web/assets/{material-theme-palenight-DJ5tN2ax.js → material-theme-palenight-DUNzX711.js} +0 -0
  411. /package/dist/web/assets/{matlab-DQNZ_NU8.js → matlab-BpYNufBU.js} +0 -0
  412. /package/dist/web/assets/{mdx-CJayB7XK.js → mdx-BYjfe1DK.js} +0 -0
  413. /package/dist/web/assets/{mermaid-Cb0TRX92.js → mermaid-DPCcIW9B.js} +0 -0
  414. /package/dist/web/assets/{min-dark-CWM8Bo-m.js → min-dark-DnGOAGCo.js} +0 -0
  415. /package/dist/web/assets/{min-light-BBR1sjS2.js → min-light-CwV-o31y.js} +0 -0
  416. /package/dist/web/assets/{mipsasm-Jc7u7YSS.js → mipsasm-DdeCPC97.js} +0 -0
  417. /package/dist/web/assets/{mojo-CTB0cutd.js → mojo-BmxxZ3iM.js} +0 -0
  418. /package/dist/web/assets/{monitor-4vWfqzuN.js → monitor-C835ucWH.js} +0 -0
  419. /package/dist/web/assets/{monokai-CvM_YNKx.js → monokai-Cx6cQ-MA.js} +0 -0
  420. /package/dist/web/assets/{moonbit-CbFEfYYM.js → moonbit-D2-Gj5vj.js} +0 -0
  421. /package/dist/web/assets/{move-BT38p0kT.js → move-DSWGoQa8.js} +0 -0
  422. /package/dist/web/assets/{narrat-55QZ_kOG.js → narrat-D9TnZSSu.js} +0 -0
  423. /package/dist/web/assets/{nextflow-groovy-Bg8peyqg.js → nextflow-groovy-BbL-8PwD.js} +0 -0
  424. /package/dist/web/assets/{night-owl-DzS77iPK.js → night-owl-CZitKm5d.js} +0 -0
  425. /package/dist/web/assets/{night-owl-light-DER7fGnx.js → night-owl-light-DJVX1Pno.js} +0 -0
  426. /package/dist/web/assets/{nix-BSI8YesN.js → nix-R6hr3oln.js} +0 -0
  427. /package/dist/web/assets/{nord-9bn7iNWo.js → nord-ChGHya3l.js} +0 -0
  428. /package/dist/web/assets/{nushell-qDVZn_lw.js → nushell-QQWB-GWx.js} +0 -0
  429. /package/dist/web/assets/{objective-c-Blf-ATos.js → objective-c-C0pZ6y73.js} +0 -0
  430. /package/dist/web/assets/{objective-cpp-Bz8bAq47.js → objective-cpp-BdzVM31a.js} +0 -0
  431. /package/dist/web/assets/{ocaml-B9heAsc3.js → ocaml-D4KktNlS.js} +0 -0
  432. /package/dist/web/assets/{odin-BaFYnOwO.js → odin-Y-fypmGT.js} +0 -0
  433. /package/dist/web/assets/{one-dark-pro-D6B_hSe-.js → one-dark-pro-BwecIxQL.js} +0 -0
  434. /package/dist/web/assets/{one-light-Ba-f0wyk.js → one-light-Cz7UVzLU.js} +0 -0
  435. /package/dist/web/assets/{openscad-UvYyL2MK.js → openscad-DtRe3qYD.js} +0 -0
  436. /package/dist/web/assets/{pascal-B4-qvEoG.js → pascal-Ck6I1fGG.js} +0 -0
  437. /package/dist/web/assets/{pkl-B146nqGx.js → pkl-DdFK94VW.js} +0 -0
  438. /package/dist/web/assets/{plastic-L38t-Id3.js → plastic-BQSAzZwR.js} +0 -0
  439. /package/dist/web/assets/{play-CpCAoQRZ.js → play-CJlWpVMw.js} +0 -0
  440. /package/dist/web/assets/{plsql-ItOG5Cca.js → plsql-DjXg_CP0.js} +0 -0
  441. /package/dist/web/assets/{po-imiCTaNX.js → po-Bw2SuM4r.js} +0 -0
  442. /package/dist/web/assets/{poimandres-Bu6sIba9.js → poimandres-YMK6c5VN.js} +0 -0
  443. /package/dist/web/assets/{polar-CTeGoFxV.js → polar-BMu17-O0.js} +0 -0
  444. /package/dist/web/assets/{portal-container-context-a399Hd9F.js → portal-container-context-DSGdlXrJ.js} +0 -0
  445. /package/dist/web/assets/{postcss-jvFe6GNE.js → postcss-DWib10RZ.js} +0 -0
  446. /package/dist/web/assets/{powerquery-D9Dw1hJp.js → powerquery-Dht4CK0b.js} +0 -0
  447. /package/dist/web/assets/{powershell-CZqvYQtg.js → powershell-DvrCg8ji.js} +0 -0
  448. /package/dist/web/assets/{prisma-B4D2nO_7.js → prisma-DbodYvCM.js} +0 -0
  449. /package/dist/web/assets/{prolog-CQbyUcCF.js → prolog-DZ-m6ysB.js} +0 -0
  450. /package/dist/web/assets/{proto-Cwpo0cW1.js → proto-HHpG3tGO.js} +0 -0
  451. /package/dist/web/assets/{puppet-CKxCwBod.js → puppet-BljHe_75.js} +0 -0
  452. /package/dist/web/assets/{purescript-B-MyXMMp.js → purescript-DzCiFR0B.js} +0 -0
  453. /package/dist/web/assets/{python-D6QbSR2S.js → python-B5BQ27cC.js} +0 -0
  454. /package/dist/web/assets/{qmldir-BpTSVcw_.js → qmldir-CYlcXrnn.js} +0 -0
  455. /package/dist/web/assets/{qss-DBc4gbpe.js → qss-Ce7T_TEg.js} +0 -0
  456. /package/dist/web/assets/{r-i9jMMi0s.js → r-Bku-2Jp_.js} +0 -0
  457. /package/dist/web/assets/{racket-BWNaxU7C.js → racket-DtfSL3WR.js} +0 -0
  458. /package/dist/web/assets/{raku-fqTZLn7L.js → raku-CnDLsBJr.js} +0 -0
  459. /package/dist/web/assets/{react-X4jUntEf.js → react-Dfio3PfK.js} +0 -0
  460. /package/dist/web/assets/{red-D-JEcuzA.js → red-vbqcE9b-.js} +0 -0
  461. /package/dist/web/assets/{refresh-cw-B9iv7csb.js → refresh-cw-84mz8aOE.js} +0 -0
  462. /package/dist/web/assets/{reg-BbirlU1S.js → reg-DIDLT8-A.js} +0 -0
  463. /package/dist/web/assets/{regexp-D8VTFrtg.js → regexp-CB4h-VPu.js} +0 -0
  464. /package/dist/web/assets/{rel-ByQGKiNM.js → rel-CiQEnWXa.js} +0 -0
  465. /package/dist/web/assets/{resolve-theme-Cqb9zWYc.js → resolve-theme-DPTQHAy1.js} +0 -0
  466. /package/dist/web/assets/{riscv-B5nqCfLE.js → riscv-R78iq5Rf.js} +0 -0
  467. /package/dist/web/assets/{ron-DOVh_iZR.js → ron-DhYENxc4.js} +0 -0
  468. /package/dist/web/assets/{rose-pine-jp51ZUzi.js → rose-pine-5wBeyjfJ.js} +0 -0
  469. /package/dist/web/assets/{rose-pine-dawn-B7hkmmWy.js → rose-pine-dawn-FpKtPCuH.js} +0 -0
  470. /package/dist/web/assets/{rose-pine-moon-Ff063yLj.js → rose-pine-moon-BwcIYc7C.js} +0 -0
  471. /package/dist/web/assets/{rosmsg-Cyk7Il8z.js → rosmsg-DWIGAYMl.js} +0 -0
  472. /package/dist/web/assets/{rotate-ccw-DnuPzJRE.js → rotate-ccw-CNTk2J7l.js} +0 -0
  473. /package/dist/web/assets/{rust-DRNM5epF.js → rust-DU_ofKgt.js} +0 -0
  474. /package/dist/web/assets/{sass-D_cB0-M1.js → sass-U9SUuYEy.js} +0 -0
  475. /package/dist/web/assets/{save-DxonD4y1.js → save-CtW9ojKk.js} +0 -0
  476. /package/dist/web/assets/{scala-Crl-1kKS.js → scala-op4gjA6j.js} +0 -0
  477. /package/dist/web/assets/{scheme-DCaWyEJ0.js → scheme-tEjkR8rL.js} +0 -0
  478. /package/dist/web/assets/{sdbl-BbXNqwtX.js → sdbl-C6SSRmZg.js} +0 -0
  479. /package/dist/web/assets/{send-B-t5Mz26.js → send-C_sLFt56.js} +0 -0
  480. /package/dist/web/assets/{shallow-4zAfs2KW.js → shallow-C1YoJQA-.js} +0 -0
  481. /package/dist/web/assets/{shellscript-BAgksBhW.js → shellscript-Bf2KiwQj.js} +0 -0
  482. /package/dist/web/assets/{shield-check-CdTiK1j2.js → shield-check-Du6HKYn9.js} +0 -0
  483. /package/dist/web/assets/{shield-off-DuetkXKM.js → shield-off-CWKb1MQL.js} +0 -0
  484. /package/dist/web/assets/{slack-dark-GB-ElUW_.js → slack-dark-oGgCey8r.js} +0 -0
  485. /package/dist/web/assets/{slack-ochin-tU6CFD3S.js → slack-ochin-CemlB8cE.js} +0 -0
  486. /package/dist/web/assets/{smalltalk-DSVGUbtL.js → smalltalk-CTE-6jrZ.js} +0 -0
  487. /package/dist/web/assets/{snazzy-light-DZhi3PoS.js → snazzy-light-DoEIGnmz.js} +0 -0
  488. /package/dist/web/assets/{solarized-dark-D6AMCco7.js → solarized-dark-CStiJyBg.js} +0 -0
  489. /package/dist/web/assets/{solarized-light-DepuTWSE.js → solarized-light-CfuNycS9.js} +0 -0
  490. /package/dist/web/assets/{solidity-CsxN618l.js → solidity-DL6sO5rd.js} +0 -0
  491. /package/dist/web/assets/{splunk-CF1m0Kkv.js → splunk-yK4ZUFBB.js} +0 -0
  492. /package/dist/web/assets/{sql-DvyMDgrB.js → sql-Lw03eoN8.js} +0 -0
  493. /package/dist/web/assets/{ssh-config-a8sDo-Q8.js → ssh-config-DeRp25TR.js} +0 -0
  494. /package/dist/web/assets/{stylus-DCJ-6AjT.js → stylus-D8OMsPh-.js} +0 -0
  495. /package/dist/web/assets/{swift-c-ZFxyPP.js → swift-nsl9stPV.js} +0 -0
  496. /package/dist/web/assets/{synthwave-84-9NPgBcuv.js → synthwave-84-exAgsgpf.js} +0 -0
  497. /package/dist/web/assets/{system-verilog-DPD02IOo.js → system-verilog-DBWf00T6.js} +0 -0
  498. /package/dist/web/assets/{systemd-BUr5HRtU.js → systemd-nhu27Dw5.js} +0 -0
  499. /package/dist/web/assets/{table-FLU8ei8b.js → table-GAR4upb6.js} +0 -0
  500. /package/dist/web/assets/{talonscript-BNBQV5YJ.js → talonscript-CNOEcGDc.js} +0 -0
  501. /package/dist/web/assets/{tasl-BETjpSyu.js → tasl-CjYZenSH.js} +0 -0
  502. /package/dist/web/assets/{tcl-Clp_AZiC.js → tcl-BVA09RDz.js} +0 -0
  503. /package/dist/web/assets/{terraform-B0kZ0lim.js → terraform-C5EloH1q.js} +0 -0
  504. /package/dist/web/assets/{text-wrap-B05VGRa-.js → text-wrap-D71Jqz5U.js} +0 -0
  505. /package/dist/web/assets/{tokyo-night-oOJ0a7Dk.js → tokyo-night-D764DdhO.js} +0 -0
  506. /package/dist/web/assets/{toml-DOPCSumy.js → toml-CCDYblSB.js} +0 -0
  507. /package/dist/web/assets/{trash-2-CTXlTflF.js → trash-2-C08fhIg1.js} +0 -0
  508. /package/dist/web/assets/{triangle-alert-BRq0VAfd.js → triangle-alert-85BQgs3T.js} +0 -0
  509. /package/dist/web/assets/{tsv-D6qUGf84.js → tsv-BZ4sA05e.js} +0 -0
  510. /package/dist/web/assets/{tsx-B6qYhT6O.js → tsx-DPLBzAt5.js} +0 -0
  511. /package/dist/web/assets/{turtle-C0Rjzw73.js → turtle-CwGHCq40.js} +0 -0
  512. /package/dist/web/assets/{typescript-BiydShEu.js → typescript-CUH0vBAl.js} +0 -0
  513. /package/dist/web/assets/{typespec-DjmF6Aww.js → typespec-Bq31Vq4u.js} +0 -0
  514. /package/dist/web/assets/{typst-CPuscfcL.js → typst-MD9BR9W5.js} +0 -0
  515. /package/dist/web/assets/{use-is-mobile-b94q8RvF.js → use-is-mobile-DUuki97q.js} +0 -0
  516. /package/dist/web/assets/{utils-C9OjCrou.js → utils-u2fbYPrY.js} +0 -0
  517. /package/dist/web/assets/{v-DE4vpLLQ.js → v-DZV7IxIT.js} +0 -0
  518. /package/dist/web/assets/{vala-CmUF2pS5.js → vala-urd1zi9S.js} +0 -0
  519. /package/dist/web/assets/{vb-BvcRoX4b.js → vb-DIZU3zbJ.js} +0 -0
  520. /package/dist/web/assets/{vendor-xterm-K8kpLxdb.js → vendor-xterm-DCj0zgSC.js} +0 -0
  521. /package/dist/web/assets/{verilog-BGIzyH3R.js → verilog-Ndz_ciTA.js} +0 -0
  522. /package/dist/web/assets/{vesper-CG7IrHQQ.js → vesper-C86M7LJp.js} +0 -0
  523. /package/dist/web/assets/{vhdl-DMSumomw.js → vhdl-_klwDUjd.js} +0 -0
  524. /package/dist/web/assets/{viml-Drt7AEmU.js → viml-DzRXWoQh.js} +0 -0
  525. /package/dist/web/assets/{vitesse-black-DmsjfN0b.js → vitesse-black-TWZ20_3U.js} +0 -0
  526. /package/dist/web/assets/{vitesse-dark-Dl55_WeJ.js → vitesse-dark-Dl7R6fy9.js} +0 -0
  527. /package/dist/web/assets/{vitesse-light-Crbv9aGg.js → vitesse-light-Cs0Dt2_n.js} +0 -0
  528. /package/dist/web/assets/{vyper-CB7psEJj.js → vyper-qnCVj8ia.js} +0 -0
  529. /package/dist/web/assets/{wasm-Dck8KPgP.js → wasm-Ckx9jBPe.js} +0 -0
  530. /package/dist/web/assets/{wasm-BY1tuM5m.js → wasm-Dy-SJ3W9.js} +0 -0
  531. /package/dist/web/assets/{wenyan-DhewQ68b.js → wenyan-DTEy2Lx-.js} +0 -0
  532. /package/dist/web/assets/{wgsl-DlmiP456.js → wgsl-DC7n63Sy.js} +0 -0
  533. /package/dist/web/assets/{wikitext-cQCnqNgE.js → wikitext-1zFoZiW6.js} +0 -0
  534. /package/dist/web/assets/{wit-S5MaCngB.js → wit-DtTfCRph.js} +0 -0
  535. /package/dist/web/assets/{wolfram-Bh8n_9zr.js → wolfram-B2Bgu1KL.js} +0 -0
  536. /package/dist/web/assets/{x-YDu4m2Iq.js → x-CeN0Qybc.js} +0 -0
  537. /package/dist/web/assets/{yaml-BoK_17l9.js → yaml-B-Jxk0IQ.js} +0 -0
  538. /package/dist/web/assets/{zenscript-DB3ZFwNJ.js → zenscript-BWRfvNER.js} +0 -0
  539. /package/dist/web/assets/{zig-Bv1BWmfT.js → zig-CkwuvETm.js} +0 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Captures pointer + keyboard on the canvas and forwards them as JSON over the caller's WS.
3
+ * `code` (physical key, layout-independent) is sent for keys, never `key` — the host maps
4
+ * `code` → VK, so a client-side layout mismatch can't inject the wrong character.
5
+ */
6
+ import { useEffect, useCallback } from "react";
7
+ import { fractionFromPoint } from "./remote-desktop-coords";
8
+
9
+ type PointerButton = "left" | "right" | null;
10
+
11
+ export function useRemoteInputCapture(
12
+ canvasRef: React.RefObject<HTMLCanvasElement | null>,
13
+ sendMessage: (msg: Record<string, unknown>) => void,
14
+ enabled: boolean,
15
+ ): void {
16
+ const sendPointer = useCallback((clientX: number, clientY: number, button: PointerButton, down: boolean | null) => {
17
+ const canvas = canvasRef.current;
18
+ if (!canvas) return;
19
+ const { xFrac, yFrac } = fractionFromPoint(clientX, clientY, canvas.getBoundingClientRect());
20
+ sendMessage({ type: "pointer", xFrac, yFrac, button, down });
21
+ }, [canvasRef, sendMessage]);
22
+
23
+ useEffect(() => {
24
+ const canvas = canvasRef.current;
25
+ if (!canvas || !enabled) return;
26
+
27
+ const toButton = (b: number): PointerButton => (b === 0 ? "left" : b === 2 ? "right" : null);
28
+ // A lost keyup (blur, tab hidden, WS drop) must not leave a modifier logically held on
29
+ // the host — force a release on every path that could lose the matching keyup.
30
+ const releaseAll = () => sendMessage({ type: "releaseAll" });
31
+
32
+ // Coalesce moves to one message per animation frame (~60Hz). Raw pointermove fires per
33
+ // pixel — unthrottled that floods the WS, and over a relayed tunnel the move backlog
34
+ // starves the button down/up that follow (clicks "don't land"). Down/up/keys are never
35
+ // throttled so they stay prompt.
36
+ let pendingMove: { x: number; y: number } | null = null;
37
+ let rafId = 0;
38
+ const flushMove = () => {
39
+ rafId = 0;
40
+ if (pendingMove) {
41
+ sendPointer(pendingMove.x, pendingMove.y, null, null);
42
+ pendingMove = null;
43
+ }
44
+ };
45
+ const flushPendingNow = () => {
46
+ if (rafId) { cancelAnimationFrame(rafId); rafId = 0; }
47
+ if (pendingMove) { sendPointer(pendingMove.x, pendingMove.y, null, null); pendingMove = null; }
48
+ };
49
+
50
+ const onPointerDown = (e: PointerEvent) => {
51
+ e.preventDefault();
52
+ canvas.setPointerCapture(e.pointerId);
53
+ canvas.focus();
54
+ flushPendingNow(); // land any queued move at the press position first
55
+ sendPointer(e.clientX, e.clientY, toButton(e.button), true);
56
+ };
57
+ const onPointerMove = (e: PointerEvent) => {
58
+ pendingMove = { x: e.clientX, y: e.clientY };
59
+ if (!rafId) rafId = requestAnimationFrame(flushMove);
60
+ };
61
+ const onPointerUp = (e: PointerEvent) => {
62
+ flushPendingNow();
63
+ sendPointer(e.clientX, e.clientY, toButton(e.button), false);
64
+ };
65
+ const onContextMenu = (e: MouseEvent) => e.preventDefault();
66
+ const onKeyDown = (e: KeyboardEvent) => { e.preventDefault(); sendMessage({ type: "key", code: e.code, down: true }); };
67
+ const onKeyUp = (e: KeyboardEvent) => { e.preventDefault(); sendMessage({ type: "key", code: e.code, down: false }); };
68
+ const onVisibilityChange = () => { if (document.hidden) releaseAll(); };
69
+
70
+ canvas.tabIndex = 0; // focusable so it can receive keydown/keyup at all
71
+ canvas.addEventListener("pointerdown", onPointerDown);
72
+ canvas.addEventListener("pointermove", onPointerMove);
73
+ canvas.addEventListener("pointerup", onPointerUp);
74
+ canvas.addEventListener("contextmenu", onContextMenu);
75
+ canvas.addEventListener("keydown", onKeyDown);
76
+ canvas.addEventListener("keyup", onKeyUp);
77
+ canvas.addEventListener("blur", releaseAll);
78
+ document.addEventListener("visibilitychange", onVisibilityChange);
79
+
80
+ return () => {
81
+ if (rafId) cancelAnimationFrame(rafId);
82
+ canvas.removeEventListener("pointerdown", onPointerDown);
83
+ canvas.removeEventListener("pointermove", onPointerMove);
84
+ canvas.removeEventListener("pointerup", onPointerUp);
85
+ canvas.removeEventListener("contextmenu", onContextMenu);
86
+ canvas.removeEventListener("keydown", onKeyDown);
87
+ canvas.removeEventListener("keyup", onKeyUp);
88
+ canvas.removeEventListener("blur", releaseAll);
89
+ document.removeEventListener("visibilitychange", onVisibilityChange);
90
+ };
91
+ }, [canvasRef, enabled, sendPointer, sendMessage]);
92
+ }
@@ -1,96 +1,96 @@
1
1
  /**
2
2
  * All user-facing strings for the named-tunnel setup flow, kept in one file so
3
- * a future i18n pass has a single place to swap. Vietnamese is the primary
4
- * language here — no English fallback is implemented yet.
3
+ * a future i18n pass has a single place to swap. English, like the rest of the
4
+ * PPM interface.
5
5
  */
6
6
  export const namedTunnelCopy = {
7
7
  askDomain: {
8
- title: "Bạn đã domain trên Cloudflare chưa?",
9
- body: " domain riêng thì PPM thể gắn một địa chỉ cố định (không đổi khi khởi động lại). Không domain thì vẫn dùng bình thường với link tạm thời.",
10
- yes: "",
11
- no: "Chưa",
8
+ title: "Do you have a domain on Cloudflare?",
9
+ body: "With your own domain, PPM can keep one fixed address that survives restarts. Without one, everything still works through a temporary link.",
10
+ yes: "Yes",
11
+ no: "Not yet",
12
12
  },
13
13
  noDomain: {
14
- title: "Không sao cả",
15
- body: "PPM sẽ tiếp tục dùng link tạm thời (quick tunnel). Bạn thể bật lại tính năng này bất cứ lúc nào trong mục Tunnel Manager.",
16
- close: "Đóng",
14
+ title: "No problem",
15
+ body: "PPM will keep using a temporary link (quick tunnel). You can turn this on later from Tunnel Manager.",
16
+ close: "Close",
17
17
  },
18
18
  login: {
19
- title: "Đăng nhập Cloudflare",
20
- hint: "Mở link bên dưới để đăng nhập thể làm trên điện thoại nếu tiện hơn.",
21
- finishOnPhone: " thể hoàn tất bước này trên điện thoại nếu dễ hơn.",
22
- copy: "Sao chép",
23
- copied: "Đã sao chép",
24
- open: "Mở link",
25
- waiting: "Đang chờ đăng nhập…",
26
- slowTitle: "Vẫn đang đăng nhập?",
27
- slowBody: "Cloudflare đôi khi mất vài phút. Tiến trình vẫn đang chạybạn thể tiếp tục chờ hoặc huỷ.",
28
- keepWaiting: "Tiếp tục chờ",
29
- cancel: "Huỷ",
19
+ title: "Sign in to Cloudflare",
20
+ hint: "Open the link below to sign ina phone works just as well.",
21
+ finishOnPhone: "You can finish this step on your phone if that is easier.",
22
+ copy: "Copy",
23
+ copied: "Copied",
24
+ open: "Open link",
25
+ waiting: "Waiting for sign-in…",
26
+ slowTitle: "Still signing in?",
27
+ slowBody: "Cloudflare sometimes takes a few minutes. The process is still runningkeep waiting or cancel.",
28
+ keepWaiting: "Keep waiting",
29
+ cancel: "Cancel",
30
30
  },
31
31
  timeout: {
32
- title: "Link đăng nhập đã hết hạn",
33
- body: "Link hết hạn sau 5 phút không dùng. Bấm Thử lại để lấy link mới.",
34
- retry: "Thử lại",
32
+ title: "Sign-in link expired",
33
+ body: "The link expires after 5 minutes unused. Press Retry to get a fresh one.",
34
+ retry: "Retry",
35
35
  },
36
36
  cancelled: {
37
- title: "Đã huỷ đăng nhập",
38
- body: "Bạn đã huỷ quá trình đăng nhập Cloudflare.",
39
- retry: "Thử lại",
37
+ title: "Sign-in cancelled",
38
+ body: "You cancelled the Cloudflare sign-in.",
39
+ retry: "Retry",
40
40
  },
41
41
  confirmZone: {
42
- title: "Xác nhận vùng miền",
43
- body: (zone: string) => `Máy này sẽ được gán một địa chỉ cố định dưới ${zone}. Tiếp tục?`,
44
- confirm: "Tiếp tục",
45
- startOver: "Bắt đầu lại",
42
+ title: "Confirm your zone",
43
+ body: (zone: string) => `This machine will get a fixed address under ${zone}. Continue?`,
44
+ confirm: "Continue",
45
+ startOver: "Start over",
46
46
  },
47
47
  needsRelogin: {
48
- title: "Cần đăng nhập lại Cloudflare",
49
- certInvalid: "Phiên đăng nhập Cloudflare đã hết hiệu lực.",
50
- certMismatch: "Chứng chỉ này thuộc một tài khoản Cloudflare kháccần đăng nhập lại.",
51
- action: "Đăng nhập lại",
48
+ title: "Cloudflare sign-in needed",
49
+ certInvalid: "Your Cloudflare sign-in is no longer valid.",
50
+ certMismatch: "This certificate belongs to a different Cloudflare accountsign in again.",
51
+ action: "Sign in again",
52
52
  },
53
53
  hostname: {
54
- title: "Chọn địa chỉ",
55
- prefixLabel: "Tiền tố",
56
- suffixHint: "Phần đuôi được cố định theo tài khoản bạn vừa đăng nhập.",
57
- submit: "Xác nhận",
54
+ title: "Choose the address",
55
+ prefixLabel: "Prefix",
56
+ suffixHint: "The suffix is fixed by the account you just signed in with.",
57
+ submit: "Confirm",
58
58
  },
59
59
  applying: {
60
- title: "Đang thiết lập…",
60
+ title: "Setting up…",
61
61
  },
62
62
  done: {
63
- title: "Đã thiết lập xong",
64
- body: (hostname: string) => `Địa chỉ cố định: https://${hostname}`,
65
- close: "Đóng",
63
+ title: "All set",
64
+ body: (hostname: string) => `Fixed address: https://${hostname}`,
65
+ close: "Close",
66
66
  },
67
67
  pending: {
68
- title: "Đã lưu đang chờ áp dụng",
69
- restartHint: "Chạy lệnh `ppm restart` để áp dụng ngay.",
70
- close: "Đóng",
68
+ title: "Savedwaiting to apply",
69
+ restartHint: "Run `ppm restart` to apply it now.",
70
+ close: "Close",
71
71
  },
72
72
  error: {
73
- title: " lỗi xảy ra",
74
- retry: "Thử lại",
75
- close: "Đóng",
73
+ title: "Something went wrong",
74
+ retry: "Retry",
75
+ close: "Close",
76
76
  },
77
77
  section: {
78
78
  title: "Named Tunnel",
79
79
  modeQuick: "quick",
80
80
  modeNamed: "named",
81
- hostnameLabel: "Địa chỉ",
81
+ hostnameLabel: "Address",
82
82
  tokenLabel: "Token",
83
- setup: "Thiết lập named tunnel",
84
- retry: "Thử lại",
85
- relogin: "Đăng nhập lại",
86
- disable: "Chuyển về quick tunnel",
87
- disableConfirm: "Bấm lần nữa để xác nhận",
83
+ setup: "Set up named tunnel",
84
+ retry: "Retry",
85
+ relogin: "Sign in again",
86
+ disable: "Switch back to quick tunnel",
87
+ disableConfirm: "Press again to confirm",
88
88
  disableSelfCut:
89
- "Bạn đang mở PPM qua chính tên miền này tắt sẽ ngắt trang ngay bạn sẽ không kịp thấy link tạm. Mở PPM qua địa chỉ mạng nội bộ rồi tắt.",
90
- certInvalid: "Cần đăng nhập lại Cloudflare",
91
- certMismatch: "Chứng chỉ thuộc tài khoản Cloudflare kháccần đăng nhập lại",
92
- authDisabled: "Bật xác thực PPM để dùng tên miền riêng",
89
+ "You are viewing PPM through this very domainturning it off cuts this page immediately and you would never see the temporary link. Open PPM on your local network first, then turn it off.",
90
+ certInvalid: "Cloudflare sign-in needed",
91
+ certMismatch: "Certificate belongs to a different Cloudflare accountsign in again",
92
+ authDisabled: "Enable PPM authentication to use your own domain",
93
93
  /** Small note next to the live-mode badge when the configured mode hasn't landed yet. */
94
- configuredAs: (mode: "quick" | "named") => `đã cấu hình: ${mode}`,
94
+ configuredAs: (mode: "quick" | "named") => `configured: ${mode}`,
95
95
  },
96
96
  } as const;
@@ -52,10 +52,10 @@ export function NamedTunnelSection() {
52
52
  setDisabling(true);
53
53
  try {
54
54
  await namedTunnelApi.disable();
55
- toast.success("Đã chuyển về quick tunnel");
55
+ toast.success("Switched back to a quick tunnel");
56
56
  await t.refreshStatus();
57
57
  } catch (e) {
58
- toast.error(e instanceof Error ? e.message : "Không chuyển được về quick tunnel");
58
+ toast.error(e instanceof Error ? e.message : "Could not switch back to a quick tunnel");
59
59
  } finally {
60
60
  setDisabling(false);
61
61
  }
@@ -1,8 +1,8 @@
1
1
  import { useEffect, useRef } from "react";
2
- import { useNotificationStore, selectTotalUnread } from "@/stores/notification-store";
2
+ import { useNotificationStore, selectProjectUnread } from "@/stores/notification-store";
3
3
  import { useProjectStore } from "@/stores/project-store";
4
4
  import { useSettingsStore } from "@/stores/settings-store";
5
- import { useStreamingStore, selectAnyStreaming } from "@/stores/streaming-store";
5
+ import { useStreamingStore, selectProjectStreaming } from "@/stores/streaming-store";
6
6
  import { setFavicon, STREAM_FRAME_COUNT } from "@/lib/favicon";
7
7
 
8
8
  function buildTitle(unread: number, projectName?: string, deviceName?: string): string {
@@ -11,25 +11,33 @@ function buildTitle(unread: number, projectName?: string, deviceName?: string):
11
11
  }
12
12
 
13
13
  /** Syncs document.title and favicon with unread notification count + streaming state.
14
- * When any chat is streaming, favicon alternates between blue and amber every 800ms.
15
- * Uses direct Zustand subscription to update immediately even in background tabs. */
14
+ * When a chat in this window's project is streaming, favicon alternates between blue and
15
+ * amber every 800ms. Uses direct Zustand subscription to update immediately even in
16
+ * background tabs.
17
+ *
18
+ * Everything here is scoped to `activeProject`, because the title bar and the tab icon
19
+ * describe *this* window and a window shows one project. Both inputs used to be app-wide:
20
+ * `/ws/global` delivers phase and unread changes for every project, so opening three
21
+ * workspaces in three PWA windows gave all three the same count and the same streaming
22
+ * animation whenever any one of them was busy. */
16
23
  export function useNotificationBadge(): void {
17
24
  const activeProject = useProjectStore((s) => s.activeProject);
18
25
  const deviceName = useSettingsStore((s) => s.deviceName);
19
- const anyStreaming = useStreamingStore(selectAnyStreaming);
26
+ const projectName = activeProject?.name;
27
+ const projectStreaming = useStreamingStore(selectProjectStreaming(projectName));
20
28
  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
21
29
 
22
30
  useEffect(() => {
23
- const getHasBadge = () => selectTotalUnread(useNotificationStore.getState()) > 0;
31
+ const unreadHere = () => selectProjectUnread(projectName)(useNotificationStore.getState());
32
+ const getHasBadge = () => unreadHere() > 0;
24
33
 
25
34
  const updateTitle = () => {
26
- const unread = selectTotalUnread(useNotificationStore.getState());
27
- document.title = buildTitle(unread, activeProject?.name, deviceName ?? undefined);
35
+ document.title = buildTitle(unreadHere(), projectName, deviceName ?? undefined);
28
36
  };
29
37
 
30
38
  updateTitle();
31
39
 
32
- if (anyStreaming) {
40
+ if (projectStreaming) {
33
41
  // Cycle through typing-dots frames (3 dots + 1 rest frame, Messenger style) every 300ms
34
42
  let frame = 0;
35
43
  setFavicon(getHasBadge(), frame);
@@ -45,7 +53,7 @@ export function useNotificationBadge(): void {
45
53
  const unsub = useNotificationStore.subscribe(() => {
46
54
  updateTitle();
47
55
  // Static favicon update only when not streaming (interval handles streaming)
48
- if (!anyStreaming) setFavicon(getHasBadge());
56
+ if (!projectStreaming) setFavicon(getHasBadge());
49
57
  });
50
58
 
51
59
  return () => {
@@ -55,5 +63,5 @@ export function useNotificationBadge(): void {
55
63
  intervalRef.current = null;
56
64
  }
57
65
  };
58
- }, [activeProject?.name, deviceName, anyStreaming]);
66
+ }, [projectName, deviceName, projectStreaming]);
59
67
  }
@@ -12,6 +12,8 @@ export const FEATURE_BADGES = {
12
12
  teams: "beta",
13
13
  /** Floating OS-style file explorer window / mobile sheet, shipped in 0.18.0. */
14
14
  "os-explorer": "new",
15
+ /** Remote Desktop — stream + control the host desktop in a floating window. */
16
+ "remote-desktop": "beta",
15
17
  } as const satisfies Record<string, FeatureBadgeKind>;
16
18
 
17
19
  export type FeatureBadgeId = keyof typeof FEATURE_BADGES;
@@ -39,6 +39,9 @@ interface SettingsState {
39
39
  dockPosition: DockPosition;
40
40
  dbSidebarExpanded: DbSidebarExpanded;
41
41
  explorerSkin: ExplorerSkinPref;
42
+ /** Show/hide the small fps/KB-per-s/resolution overlay on the remote-desktop viewer
43
+ * (desktop window and mobile full-screen view both read this same flag). */
44
+ remoteDesktopStatsVisible: boolean;
42
45
  deviceName: string | null;
43
46
  version: string | null;
44
47
  tunnelActive: boolean;
@@ -63,6 +66,7 @@ interface SettingsState {
63
66
  setDockPosition: (position: DockPosition) => void;
64
67
  setDbSidebarExpanded: (next: DbSidebarExpanded) => void;
65
68
  setExplorerSkin: (pref: ExplorerSkinPref) => void;
69
+ toggleRemoteDesktopStatsVisible: () => void;
66
70
  fetchServerInfo: () => Promise<void>;
67
71
  /** Re-push the in-memory theme selection to the server (see the action for why). */
68
72
  syncThemeToServer: () => Promise<void>;
@@ -86,6 +90,7 @@ interface PersistedSettings {
86
90
  dockPosition?: DockPosition;
87
91
  dbSidebarExpanded?: DbSidebarExpanded;
88
92
  explorerSkin?: ExplorerSkinPref;
93
+ remoteDesktopStatsVisible?: boolean;
89
94
  }
90
95
 
91
96
  const VALID_STYLES: PpmThemeStyle[] = ["aurora", "slate", "precision", "custom"];
@@ -238,6 +243,7 @@ function applyServerUiPrefs(data: Record<string, unknown>) {
238
243
  if (data.explorerSkin === "auto" || data.explorerSkin === "windows" || data.explorerSkin === "macos") {
239
244
  patch.explorerSkin = data.explorerSkin;
240
245
  }
246
+ if (typeof data.remoteDesktopStatsVisible === "boolean") patch.remoteDesktopStatsVisible = data.remoteDesktopStatsVisible;
241
247
  const dbExpanded = sanitizeDbExpanded(data.dbSidebarExpanded);
242
248
  if (dbExpanded) patch.dbSidebarExpanded = dbExpanded;
243
249
  if (Object.keys(patch).length === 0) return;
@@ -265,6 +271,7 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
265
271
  dockPosition: (_initial.dockPosition === "left" || _initial.dockPosition === "right") ? _initial.dockPosition : "bottom",
266
272
  dbSidebarExpanded: sanitizeDbExpanded(_initial.dbSidebarExpanded) ?? DEFAULT_DB_EXPANDED,
267
273
  explorerSkin: (_initial.explorerSkin === "windows" || _initial.explorerSkin === "macos") ? _initial.explorerSkin : "auto",
274
+ remoteDesktopStatsVisible: _initial.remoteDesktopStatsVisible ?? false,
268
275
  deviceName: null,
269
276
  version: null,
270
277
  tunnelActive: false,
@@ -378,6 +385,12 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
378
385
  set({ tabWrap: next });
379
386
  },
380
387
 
388
+ toggleRemoteDesktopStatsVisible: () => {
389
+ const next = !get().remoteDesktopStatsVisible;
390
+ persistUiPref({ remoteDesktopStatsVisible: next });
391
+ set({ remoteDesktopStatsVisible: next });
392
+ },
393
+
381
394
  setEditorTabStyle: (style) => {
382
395
  persistUiPref({ editorTabStyle: style });
383
396
  set({ editorTabStyle: style });
@@ -41,5 +41,24 @@ export const useStreamingStore = create<StreamingStore>((set) => ({
41
41
  }),
42
42
  }));
43
43
 
44
- /** Selector: true if any session is streaming */
45
- export const selectAnyStreaming = (s: StreamingStore) => s.sessions.size > 0;
44
+ /**
45
+ * Selector: true if a session *belonging to this project* is streaming.
46
+ *
47
+ * Scoped, because the thing it drives — the favicon and the document title — belongs to one
48
+ * window, and a window shows one project. `/ws/global` carries `session:phase_changed` for
49
+ * every project, so an unscoped "is anything streaming" made every open workspace animate
50
+ * whenever any one of them was working: three PWA windows, one busy, three busy-looking
51
+ * icons, and no way to tell which.
52
+ *
53
+ * No new state is needed for this. The map already records the project per session so
54
+ * `replaceProjectStreaming` can reconcile one project without touching another's entries.
55
+ */
56
+ export const selectProjectStreaming =
57
+ (projectName: string | undefined) =>
58
+ (s: StreamingStore): boolean => {
59
+ if (!projectName) return false;
60
+ for (const project of s.sessions.values()) {
61
+ if (project === projectName) return true;
62
+ }
63
+ return false;
64
+ };
@@ -1 +0,0 @@
1
- import"./vendor-markdown-Ls5AcU91.js";import"./vendor-ui-CaeeFO0B.js";import{i as e,n as t}from"./api-client-oY1tC3tM.js";export{t as api,e as projectUrl};
@@ -1 +0,0 @@
1
- import"./vendor-markdown-Ls5AcU91.js";import"./vendor-ui-CaeeFO0B.js";import"./api-client-oY1tC3tM.js";import{v as e}from"./api-settings-B2iNXQ0c.js";export{e as updateDeviceName};
@@ -1 +0,0 @@
1
- import{K as e}from"./vendor-mermaid-999ksD45.js";export{e as createArchitectureServices};