@hienlh/ppm 0.21.0 → 0.22.0

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 (606) hide show
  1. package/CHANGELOG.md +41 -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/http-api.md +1 -1
  6. package/bun.lock +16 -1
  7. package/dist/web/assets/accounts-settings-section-BVr9-FZJ.js +1 -0
  8. package/dist/web/assets/{ai-resource-editor-F09pf8Hd.js → ai-resource-editor-CdDpOwjh.js} +1 -1
  9. package/dist/web/assets/ai-settings-section-B1hQyjAd.js +1 -0
  10. package/dist/web/assets/ai-settings-section-X2UOfSaS.js +1 -0
  11. package/dist/web/assets/{angular-html-DkR4iCth.js → angular-html-G66FNlyn.js} +1 -1
  12. package/dist/web/assets/{angular-ts-DcyL4Chx.js → angular-ts-B-PnUMyt.js} +1 -1
  13. package/dist/web/assets/{api-client-bfB7cXRM.js → api-client-C1ZwRL4Y.js} +1 -1
  14. package/dist/web/assets/api-client-pQL53cDQ.js +1 -0
  15. package/dist/web/assets/{api-settings-BcNjZIvG.js → api-settings-_7Q-ULxp.js} +1 -1
  16. package/dist/web/assets/{api-themes-DBfyVUtX.js → api-themes-DRAERo4Q.js} +1 -1
  17. package/dist/web/assets/{apl-BVlrVtjt.js → apl-BmDqqwE8.js} +1 -1
  18. package/dist/web/assets/{appearance-settings-section-whgnq3ss.js → appearance-settings-section-DLoPK0LD.js} +1 -1
  19. package/dist/web/assets/architecture-PBZL5I3N-Dx6nBEKT.js +1 -0
  20. package/dist/web/assets/{astro-MjJlozLj.js → astro-BfwMNfxr.js} +1 -1
  21. package/dist/web/assets/{audio-preview-Bc54GCAV.js → audio-preview-DsYvgKqj.js} +1 -1
  22. package/dist/web/assets/{blade-DnJWi1fz.js → blade-BsFV4pnN.js} +1 -1
  23. package/dist/web/assets/branch-review-tab-G84Ojzae.js +1 -0
  24. package/dist/web/assets/{bsl-DCmJxSIz.js → bsl-Cw9Outng.js} +1 -1
  25. package/dist/web/assets/{button-VW4QGKCn.js → button-B9CTrsEf.js} +1 -1
  26. package/dist/web/assets/{cairo-C8dDenub.js → cairo-DOK5Wqnd.js} +1 -1
  27. package/dist/web/assets/chat-tab-DQJfjm8E.js +15 -0
  28. package/dist/web/assets/{cobol-DPx_nifl.js → cobol-DRaRy4FK.js} +1 -1
  29. package/dist/web/assets/code-editor-D04iUPsZ.js +7 -0
  30. package/dist/web/assets/{codex-daily-guard-CfybHv_c.js → codex-daily-guard-BSccLRGT.js} +1 -1
  31. package/dist/web/assets/{coffee-DvFzqhgN.js → coffee-DvXuBmEJ.js} +1 -1
  32. package/dist/web/assets/{conflict-editor-DenQUOT2.js → conflict-editor-C4ay676e.js} +2 -2
  33. package/dist/web/assets/context-menu-C6pIsf83.js +1 -0
  34. package/dist/web/assets/{cpp-BLJN0umi.js → cpp-zCmm8rKA.js} +1 -1
  35. package/dist/web/assets/{crystal-BXR-9fGw.js → crystal-CdQx6lB6.js} +1 -1
  36. package/dist/web/assets/{csv-preview-CClrJOuR.js → csv-preview-DbwEmG7o.js} +1 -1
  37. package/dist/web/assets/{data-grid-overlay-editor-D4fhcMfT.js → data-grid-overlay-editor-6xUCeLHh.js} +1 -1
  38. package/dist/web/assets/{database-viewer-DItjm8wB.js → database-viewer-S6LsALjX.js} +1 -1
  39. package/dist/web/assets/{dialog-DQTn55Mt.js → dialog-B84_DJQ8.js} +1 -1
  40. package/dist/web/assets/diff-viewer-3oBA7vgQ.js +4 -0
  41. package/dist/web/assets/{docx-preview-DYBkiUaE.js → docx-preview-CXuk-emm.js} +1 -1
  42. package/dist/web/assets/{edge-rWOlCmXT.js → edge-E8QLt7oi.js} +1 -1
  43. package/dist/web/assets/{edit-diff-preview-COtmo54G.js → edit-diff-preview-BGGGecVw.js} +1 -1
  44. package/dist/web/assets/{editor-language-service-DxkZ51E5.js → editor-language-service-DJmaKVY0.js} +1 -1
  45. package/dist/web/assets/{elixir-E7Y82okW.js → elixir-DPb_-72P.js} +1 -1
  46. package/dist/web/assets/{elm-DTPGbc-w.js → elm-BMzJY5b0.js} +1 -1
  47. package/dist/web/assets/{erb-DHqLHrE6.js → erb-AABQNtMK.js} +1 -1
  48. package/dist/web/assets/{erlang-Byg0nNiV.js → erlang-CEIKOkfP.js} +1 -1
  49. package/dist/web/assets/{esm-D_DmOM7n.js → esm-B9RVMpwV.js} +1 -1
  50. package/dist/web/assets/explorer-body-BQ0jyAGv.js +2 -0
  51. package/dist/web/assets/explorer-window-content-jdkWt34J.js +1 -0
  52. package/dist/web/assets/{extension-manager-section-BhwB6nqr.js → extension-manager-section-DG1guILi.js} +1 -1
  53. package/dist/web/assets/{extension-webview-DI4VL2tJ.js → extension-webview-BGSDUbdK.js} +1 -1
  54. package/dist/web/assets/file-icons-BXdvggK2.js +1 -0
  55. package/dist/web/assets/file-icons.generated-BtBErEwb.css +1 -0
  56. package/dist/web/assets/file-store-ojgMXgAw.js +1 -0
  57. package/dist/web/assets/files-settings-section-Gnyd7han.js +1 -0
  58. package/dist/web/assets/{format-file-meta-DOpzJJhS.js → format-file-meta-C77h04cZ.js} +1 -1
  59. package/dist/web/assets/{fortran-fixed-form-CY1n0Xf6.js → fortran-fixed-form-CrXvLHyi.js} +1 -1
  60. package/dist/web/assets/{fsharp-_vEDSCJz.js → fsharp-DCI4qAz_.js} +1 -1
  61. package/dist/web/assets/{gdresource-B6XT0wAC.js → gdresource-Vb2kO1MG.js} +1 -1
  62. package/dist/web/assets/{general-settings-section-BcxwiZ0X.js → general-settings-section-V6Khh15V.js} +1 -1
  63. package/dist/web/assets/{git-commit-Wk9ovq59.js → git-commit-BMI_OWn-.js} +1 -1
  64. package/dist/web/assets/git-log-panel-Bi513qjT.js +1 -0
  65. package/dist/web/assets/{git-rebase-DSarGPvK.js → git-rebase-D-d_2iqZ.js} +1 -1
  66. package/dist/web/assets/{git-repo-store-Dy69YCHN.js → git-repo-store-88Z8v-pF.js} +1 -1
  67. package/dist/web/assets/gitGraph-HDMCJU4V-C6qRruHI.js +1 -0
  68. package/dist/web/assets/{glide-data-grid-BvgAqSUr.js → glide-data-grid-DnQwYSmQ.js} +7 -7
  69. package/dist/web/assets/{glimmer-js-CkYI35_P.js → glimmer-js-BmNNiR0Z.js} +1 -1
  70. package/dist/web/assets/{glimmer-ts-BqmIZcds.js → glimmer-ts-DQE2Ufha.js} +1 -1
  71. package/dist/web/assets/{glsl-Be-yBCF5.js → glsl-BcIDsxRJ.js} +1 -1
  72. package/dist/web/assets/{graphql-a5DrENHY.js → graphql-DGKSLmGH.js} +1 -1
  73. package/dist/web/assets/group-chat-tab-DpczdwyV.js +1 -0
  74. package/dist/web/assets/{hack-BLAg20aD.js → hack-YiC8bEIb.js} +1 -1
  75. package/dist/web/assets/{haml-Dj6bGOQH.js → haml-DjblxAsz.js} +1 -1
  76. package/dist/web/assets/{handlebars-dmEa36Oh.js → handlebars-BQepOXaU.js} +1 -1
  77. package/dist/web/assets/{html-yacZYzSE.js → html-Cayj_2GP.js} +1 -1
  78. package/dist/web/assets/{html-derivative-lLi3-RNT.js → html-derivative-Weq79bL6.js} +1 -1
  79. package/dist/web/assets/{http-1KaxcE4e.js → http-BeLfdGdz.js} +1 -1
  80. package/dist/web/assets/{hurl-ST-dEEZR.js → hurl-D9rypCLK.js} +1 -1
  81. package/dist/web/assets/{hxml-CpDtuq__.js → hxml-clG8mmSH.js} +1 -1
  82. package/dist/web/assets/{image-preview-CJVxL0uH.js → image-preview-CzCc4_Do.js} +1 -1
  83. package/dist/web/assets/image-preview-geometry-9lgeLYB3.js +1 -0
  84. package/dist/web/assets/index-BH99TIE0.css +1 -0
  85. package/dist/web/assets/index-DU68xk06.js +52 -0
  86. package/dist/web/assets/info-3K5VOQVL-BOSpdwlz.js +1 -0
  87. package/dist/web/assets/{jinja-Cjw-evAn.js → jinja-BShBWfs5.js} +1 -1
  88. package/dist/web/assets/{jira-watcher-section-DIC1yIV3.js → jira-watcher-section-f2HUbGDY.js} +1 -1
  89. package/dist/web/assets/{jison-DfATMYoY.js → jison-dN2Nf_Dr.js} +1 -1
  90. package/dist/web/assets/{julia-DDCaxiqT.js → julia-5U0vR-uJ.js} +1 -1
  91. package/dist/web/assets/{just-CJL529u6.js → just-BMppVRy6.js} +1 -1
  92. package/dist/web/assets/keybindings-store-DCRsnKg5.js +1 -0
  93. package/dist/web/assets/{keyboard-shortcuts-section-BW03P3AF.js → keyboard-shortcuts-section-BpvVEw_Y.js} +1 -1
  94. package/dist/web/assets/{latex-Zc4EpLpW.js → latex-DSSOKjis.js} +1 -1
  95. package/dist/web/assets/{liquid-B_6KMNYS.js → liquid-C24dKoyI.js} +1 -1
  96. package/dist/web/assets/{lua-BtS2idK7.js → lua-DNOsnyhn.js} +1 -1
  97. package/dist/web/assets/markdown-renderer-Bcaf9_bA.js +1 -0
  98. package/dist/web/assets/markdown-renderer-DGJp8HC3.js +3 -0
  99. package/dist/web/assets/{marko-Wk6LBnck.js → marko-26MHO_Q9.js} +1 -1
  100. package/dist/web/assets/{mdc-cRaXBrzL.js → mdc-Dhw9mGrC.js} +1 -1
  101. package/dist/web/assets/{media-url-DL8OCGGg.js → media-url-yfqHpPz0.js} +1 -1
  102. package/dist/web/assets/{mobile-bottom-sheet-CoUauvLF.js → mobile-bottom-sheet-C3TniEP-.js} +1 -1
  103. package/dist/web/assets/mobile-explorer-sheet-Bol3XAO1.js +1 -0
  104. package/dist/web/assets/{nextflow-Bos2wvDV.js → nextflow-xH4oJTex.js} +1 -1
  105. package/dist/web/assets/{nginx-DMlOwzdr.js → nginx-CMz4w0M8.js} +1 -1
  106. package/dist/web/assets/{nim-D2dZQA88.js → nim-D8FnIYsx.js} +1 -1
  107. package/dist/web/assets/notification-store-BXt54VIn.js +1 -0
  108. package/dist/web/assets/{notifications-settings-section-DPUROMw-.js → notifications-settings-section-DqlPDfNX.js} +1 -1
  109. package/dist/web/assets/{number-overlay-editor-DZ2i_Bnb.js → number-overlay-editor-CRGwULhR.js} +1 -1
  110. package/dist/web/assets/{overview-panel-R146OIom.js → overview-panel-Di-3aV9p.js} +1 -1
  111. package/dist/web/assets/packet-RMMSAZCW-BGIE1QdU.js +1 -0
  112. package/dist/web/assets/panel-store-CboGJAwh.js +1 -0
  113. package/dist/web/assets/{pdf-preview-BWUPGLp6.js → pdf-preview-CmBI6E7d.js} +1 -1
  114. package/dist/web/assets/{perl-C5-Z6fPn.js → perl-D9iNWYwb.js} +1 -1
  115. package/dist/web/assets/{php-BXNNhkMH.js → php-Bw3Qo0Zv.js} +1 -1
  116. package/dist/web/assets/pie-UPGHQEXC-Dg-QTbXX.js +1 -0
  117. package/dist/web/assets/{postgres-viewer-CjOvaruz.js → postgres-viewer-8ZAqEALv.js} +3 -3
  118. package/dist/web/assets/{ppmbot-settings-section-DrvWh8l8.js → ppmbot-settings-section-DKJUA3Kq.js} +1 -1
  119. package/dist/web/assets/problems-panel-CFcoUx8h.js +1 -0
  120. package/dist/web/assets/{process-table-BRMS1MrX.js → process-table-EKr2dqG6.js} +1 -1
  121. package/dist/web/assets/project-framework-store-B70Q3dNM.js +1 -0
  122. package/dist/web/assets/project-store-B87hLRSk.js +1 -0
  123. package/dist/web/assets/{proxy-settings-section-Bv0Ny-Yy.js → proxy-settings-section-B7qRVl8w.js} +1 -1
  124. package/dist/web/assets/{pug-C1zf1yWy.js → pug-fT5JC6Vm.js} +1 -1
  125. package/dist/web/assets/{qml-OW58jGpD.js → qml-P_wEDB1w.js} +1 -1
  126. package/dist/web/assets/{query-audit-section-BcHJZcVC.js → query-audit-section-By6qyqdB.js} +1 -1
  127. package/dist/web/assets/radar-KQ55EAFF-DZ6IVu2s.js +1 -0
  128. package/dist/web/assets/{razor-DzjSaobM.js → razor-Drrt2_Ph.js} +1 -1
  129. package/dist/web/assets/remote-desktop-clipboard-notice-0WDYsyCA.js +1 -0
  130. package/dist/web/assets/remote-desktop-mobile-sheet-COYDg16H.js +2 -0
  131. package/dist/web/assets/remote-desktop-mobile-view-2DqSuS2U.js +1 -0
  132. package/dist/web/assets/{remote-desktop-readiness-gate-BTzss2wX.js → remote-desktop-readiness-gate-Dm_qMJMH.js} +1 -1
  133. package/dist/web/assets/remote-desktop-window-content-UodhsF7W.js +1 -0
  134. package/dist/web/assets/{rst-RfuihOUW.js → rst-Dr2mW4-h.js} +1 -1
  135. package/dist/web/assets/{ruby-CNO3pli1.js → ruby-C6EpUsTY.js} +1 -1
  136. package/dist/web/assets/{run-in-terminal-Cb_hVU8x.js → run-in-terminal-CdefEe_R.js} +1 -1
  137. package/dist/web/assets/{sas-DZY5BtXx.js → sas-D8ZEeP6v.js} +1 -1
  138. package/dist/web/assets/{schedules-settings-section-DO8xAOVj.js → schedules-settings-section-bG2lYfGv.js} +1 -1
  139. package/dist/web/assets/{scroll-area-LtNV8g5o.js → scroll-area-BzeiOd-B.js} +1 -1
  140. package/dist/web/assets/{scss--4g-REcN.js → scss-ITL7jQ1f.js} +1 -1
  141. package/dist/web/assets/{send-to-chat-Cnpru1M0.js → send-to-chat-F207yH3u.js} +1 -1
  142. package/dist/web/assets/{separator-Cds1yxy8.js → separator-TRMsJUYe.js} +1 -1
  143. package/dist/web/assets/settings-body-C06bFarv.js +2 -0
  144. package/dist/web/assets/settings-store-krC6bc79.js +2 -0
  145. package/dist/web/assets/settings-tab-34RSaASd.js +1 -0
  146. package/dist/web/assets/settings-window-content-Dr_2lmHH.js +1 -0
  147. package/dist/web/assets/{shaderlab-Cu4sBiVn.js → shaderlab-mW-IIlhk.js} +1 -1
  148. package/dist/web/assets/{shellsession-DWzJfEv7.js → shellsession-DhNl5STt.js} +1 -1
  149. package/dist/web/assets/{soy-BnqE-5Ff.js → soy-SdY0Qjtr.js} +1 -1
  150. package/dist/web/assets/{sparql-Ctg__NhZ.js → sparql-ftqZo2i-.js} +1 -1
  151. package/dist/web/assets/{sql-query-editor-D9k19T_M.js → sql-query-editor-BgRH0cHD.js} +1 -1
  152. package/dist/web/assets/{sqlite-viewer-DoV9hnWJ.js → sqlite-viewer-DUxGslpa.js} +1 -1
  153. package/dist/web/assets/{stata-Qk2h66XW.js → stata-Bj7Yjb4b.js} +1 -1
  154. package/dist/web/assets/{surrealql-8QEX7EfH.js → surrealql-CLhYGAfB.js} +1 -1
  155. package/dist/web/assets/{svelte-D_mubC5-.js → svelte-DTAlRHhK.js} +1 -1
  156. package/dist/web/assets/system-monitor-body-IZuLn7Qh.js +2 -0
  157. package/dist/web/assets/system-monitor-tab-DiSA490Z.js +1 -0
  158. package/dist/web/assets/{system-monitor-window-content-qXLcicFM.js → system-monitor-window-content-CEaFISgj.js} +1 -1
  159. package/dist/web/assets/{tab-host-window-content-7fPZNEni.js → tab-host-window-content-D0TN8Wrq.js} +1 -1
  160. package/dist/web/assets/{tab-store-DGJGnbwv.js → tab-store-OJa1GPCq.js} +1 -1
  161. package/dist/web/assets/team-member-sheet-DDPNcCjd.js +2 -0
  162. package/dist/web/assets/{team-member-window-content-BgvJFypM.js → team-member-window-content-DCiW_1-E.js} +1 -1
  163. package/dist/web/assets/{templ-C1jV0fsO.js → templ-BMfhACxb.js} +1 -1
  164. package/dist/web/assets/{terminal-tab-Cs0sGljx.js → terminal-tab-4ypP0NDY.js} +3 -3
  165. package/dist/web/assets/{tex-D_StFXy_.js → tex-BcssM-QA.js} +1 -1
  166. package/dist/web/assets/tool-cards-Dd6E7Q3k.js +9 -0
  167. package/dist/web/assets/treemap-KZPCXAKY-CE30wCXa.js +1 -0
  168. package/dist/web/assets/{ts-tags-B5m47rEm.js → ts-tags-CrR5IYI8.js} +1 -1
  169. package/dist/web/assets/{twig-C_br6GIl.js → twig-DchfUmyI.js} +1 -1
  170. package/dist/web/assets/{use-blob-url-C-SGi_Hb.js → use-blob-url-CPtCcY3i.js} +1 -1
  171. package/dist/web/assets/{use-inline-blame-B4trxGcR.js → use-inline-blame-vrfFHuaR.js} +1 -1
  172. package/dist/web/assets/{use-lsp-CV0vzILO.js → use-lsp-CsuZu49X.js} +1 -1
  173. package/dist/web/assets/{use-monaco-theme-DBqbWjWX.js → use-monaco-theme-BIVYJBIn.js} +1 -1
  174. package/dist/web/assets/{use-open-team-member-DENsjp0s.js → use-open-team-member-C3mrUzIC.js} +1 -1
  175. package/dist/web/assets/{use-websocket-LgXiX1qN.js → use-websocket-BMbufhX7.js} +1 -1
  176. package/dist/web/assets/{vendor-mermaid-Cbig5zA6.js → vendor-mermaid-BitiXJlL.js} +1 -1
  177. package/dist/web/assets/{vendor-ui-BBdkypKW.js → vendor-ui-DmZ-Mb-H.js} +1 -1
  178. package/dist/web/assets/video-preview-Byj8P_jA.js +1 -0
  179. package/dist/web/assets/{vue-DQwCnLdr.js → vue-1EL6Pw1h.js} +1 -1
  180. package/dist/web/assets/{vue-html-T_EoGpPJ.js → vue-html-BPQNwPC6.js} +1 -1
  181. package/dist/web/assets/{vue-vine-DmxLqX50.js → vue-vine-Bb_dsWLt.js} +1 -1
  182. package/dist/web/assets/{window-pip-registry-3l4hoxuD.js → window-pip-registry-yD6esSju.js} +1 -1
  183. package/dist/web/assets/ws-auth-CEYVQ8NH.js +1 -0
  184. package/dist/web/assets/{xml-Bs6Bw8is.js → xml-dxkLNA0K.js} +1 -1
  185. package/dist/web/assets/{xsl-f5ZNhRCc.js → xsl-Bw2adwrl.js} +1 -1
  186. package/dist/web/index.html +27 -26
  187. package/dist/web/sw.js +1 -1
  188. package/docs/architecture/plugins-and-tracing.md +285 -0
  189. package/docs/lessons-learned.md +31 -0
  190. package/docs/system-architecture.md +1 -0
  191. package/package.json +2 -1
  192. package/packages/ext-git-graph/src/compare-diff-base.test.ts +173 -0
  193. package/packages/ext-git-graph/src/compare-view.ts +22 -3
  194. package/packages/ext-git-graph/src/extension.ts +6 -0
  195. package/packages/ext-git-graph/src/types.ts +19 -0
  196. package/packages/ext-git-graph/src/webview-html.test.ts +134 -1
  197. package/packages/ext-git-graph/src/webview-html.ts +277 -27
  198. package/scripts/gen-file-icons.ts +493 -242
  199. package/src/providers/claude-agent-sdk.ts +42 -1
  200. package/src/providers/codex-app-server/codex-history.ts +77 -23
  201. package/src/server/index.ts +42 -7
  202. package/src/server/routes/chat.ts +15 -11
  203. package/src/server/routes/git.ts +83 -3
  204. package/src/server/routes/remote-desktop.ts +7 -2
  205. package/src/server/ws/global.ts +1 -1
  206. package/src/server/ws/remote-desktop.ts +12 -5
  207. package/src/services/binary-content.ts +25 -0
  208. package/src/services/chat-search.service.ts +1 -1
  209. package/src/services/chat.service.ts +9 -0
  210. package/src/services/event-loop-lag.ts +208 -0
  211. package/src/services/file-lines.ts +114 -0
  212. package/src/services/file-watcher/recreated-dir-poller.ts +108 -6
  213. package/src/services/file-watcher/watch-tree.ts +131 -10
  214. package/src/services/file-watcher.service.ts +73 -23
  215. package/src/services/git-branch-diff/branch-diff-parse.ts +151 -0
  216. package/src/services/git-branch-diff/branch-diff.service.ts +79 -0
  217. package/src/services/git-hunks/git-hunks.service.ts +26 -11
  218. package/src/services/git-hunks/unified-diff.ts +15 -1
  219. package/src/services/git.service.ts +74 -24
  220. package/src/services/jsonl-transcript-parser.ts +138 -6
  221. package/src/services/log-rotate.ts +142 -0
  222. package/src/services/media-transcode/ffmpeg-capabilities.ts +72 -2
  223. package/src/services/remote-desktop/remote-desktop-audio.ts +193 -0
  224. package/src/services/remote-desktop/remote-desktop-capture-input.ts +87 -14
  225. package/src/services/remote-desktop/remote-desktop-capture.ts +40 -7
  226. package/src/services/remote-desktop/remote-desktop-clipboard.ts +166 -0
  227. package/src/services/remote-desktop/remote-desktop-displays.ts +77 -1
  228. package/src/services/remote-desktop/remote-desktop-encoder-args.ts +25 -6
  229. package/src/services/remote-desktop/remote-desktop-evdev-key-map.ts +69 -0
  230. package/src/services/remote-desktop/remote-desktop-input-linux.ts +253 -0
  231. package/src/services/remote-desktop/remote-desktop-input-uinput.ts +242 -0
  232. package/src/services/remote-desktop/remote-desktop-input.ts +40 -8
  233. package/src/services/remote-desktop/remote-desktop-linux-session.ts +146 -0
  234. package/src/services/remote-desktop/remote-desktop-ogg-opus.ts +144 -0
  235. package/src/services/remote-desktop/remote-desktop-privacy.ts +163 -0
  236. package/src/services/remote-desktop/remote-desktop-quality.ts +138 -0
  237. package/src/services/remote-desktop/remote-desktop-requirements.ts +158 -5
  238. package/src/services/remote-desktop/remote-desktop-resolution.ts +302 -0
  239. package/src/services/remote-desktop/remote-desktop-session.ts +523 -21
  240. package/src/services/remote-desktop/remote-desktop-x11.ts +250 -0
  241. package/src/services/supervisor.ts +47 -4
  242. package/src/shared/remote-desktop-custom-quality.ts +117 -0
  243. package/src/shared/remote-desktop-quality.ts +127 -0
  244. package/src/types/chat.ts +4 -0
  245. package/src/types/git.ts +52 -0
  246. package/src/web/components/branch-review/branch-review-tab.tsx +360 -0
  247. package/src/web/components/branch-review/branch-review-tree-row.tsx +138 -0
  248. package/src/web/components/chat/attachment-chips.tsx +30 -6
  249. package/src/web/components/chat/chat-tab.tsx +12 -1
  250. package/src/web/components/chat/message-events.tsx +273 -0
  251. package/src/web/components/chat/message-list.tsx +107 -861
  252. package/src/web/components/chat/message-markdown.tsx +34 -0
  253. package/src/web/components/chat/message-media.tsx +174 -0
  254. package/src/web/components/chat/message-user-bubble.tsx +399 -0
  255. package/src/web/components/chat/provider-selector.tsx +30 -22
  256. package/src/web/components/chat/session-history-list.tsx +2 -2
  257. package/src/web/components/chat/session-list-panel.tsx +3 -2
  258. package/src/web/components/editor/binary-diff-view.tsx +212 -0
  259. package/src/web/components/editor/diff-viewer.tsx +76 -3
  260. package/src/web/components/explorer/file-tree.tsx +235 -134
  261. package/src/web/components/explorer/flatten-visible-tree.ts +35 -40
  262. package/src/web/components/explorer/tree-node.tsx +69 -69
  263. package/src/web/components/explorer/use-tree-row-dnd.ts +3 -4
  264. package/src/web/components/git/git-status-panel.tsx +25 -0
  265. package/src/web/components/layout/draggable-tab.tsx +4 -2
  266. package/src/web/components/layout/nav-section-rail.tsx +12 -3
  267. package/src/web/components/layout/status-bar.tsx +10 -6
  268. package/src/web/components/layout/tab-content.tsx +5 -0
  269. package/src/web/components/layout/tab-pool.tsx +1 -0
  270. package/src/web/components/layout/upgrade-button.tsx +5 -1
  271. package/src/web/components/remote-desktop/remote-desktop-clipboard-client.ts +67 -0
  272. package/src/web/components/remote-desktop/remote-desktop-clipboard-notice.tsx +127 -0
  273. package/src/web/components/remote-desktop/remote-desktop-codec-labels.ts +28 -0
  274. package/src/web/components/remote-desktop/remote-desktop-custom-quality-dialog.tsx +144 -0
  275. package/src/web/components/remote-desktop/remote-desktop-mobile-key-bar.tsx +13 -2
  276. package/src/web/components/remote-desktop/remote-desktop-mobile-settings.tsx +232 -0
  277. package/src/web/components/remote-desktop/remote-desktop-mobile-toolbar.tsx +21 -8
  278. package/src/web/components/remote-desktop/remote-desktop-mobile-view.tsx +82 -3
  279. package/src/web/components/remote-desktop/remote-desktop-recording.ts +76 -0
  280. package/src/web/components/remote-desktop/remote-desktop-resolution-list.ts +100 -0
  281. package/src/web/components/remote-desktop/remote-desktop-toolbar.tsx +497 -0
  282. package/src/web/components/remote-desktop/remote-desktop-view-style.ts +145 -0
  283. package/src/web/components/remote-desktop/remote-desktop-window-content.tsx +126 -35
  284. package/src/web/components/remote-desktop/use-h264-canvas-decoder.ts +11 -0
  285. package/src/web/components/remote-desktop/use-opus-audio-player.ts +148 -0
  286. package/src/web/components/remote-desktop/use-remote-desktop-connection.ts +284 -1
  287. package/src/web/components/remote-desktop/use-remote-desktop-readiness.ts +75 -1
  288. package/src/web/components/remote-desktop/use-remote-desktop-recorder.ts +103 -0
  289. package/src/web/components/remote-desktop/use-remote-desktop-virtual-keyboard.ts +19 -2
  290. package/src/web/components/remote-desktop/use-remote-input-capture.ts +39 -3
  291. package/src/web/components/settings/theme-picker.tsx +2 -1
  292. package/src/web/components/ui/tooltip.tsx +15 -2
  293. package/src/web/hooks/use-delayed-flag.ts +35 -0
  294. package/src/web/lib/branch-review-state.ts +175 -0
  295. package/src/web/lib/file-icon-name.ts +62 -0
  296. package/src/web/lib/file-icons.generated.ts +3287 -25
  297. package/src/web/lib/file-icons.tsx +71 -73
  298. package/src/web/lib/flatten-expansions.ts +18 -5
  299. package/src/web/lib/message-ordinals.ts +23 -0
  300. package/src/web/lib/provider-logos.tsx +143 -0
  301. package/src/web/lib/tab-type-icons.ts +11 -0
  302. package/src/web/stores/file-store.ts +73 -35
  303. package/src/web/stores/panel-utils.ts +5 -0
  304. package/src/web/stores/project-framework-store.ts +82 -0
  305. package/src/web/stores/project-store.ts +7 -1
  306. package/src/web/stores/settings-store.ts +128 -0
  307. package/src/web/stores/tab-store.ts +1 -0
  308. package/src/web/stores/window-panel-persistence.ts +1 -0
  309. package/src/web/styles/file-icons.generated.css +3282 -234
  310. package/src/web/styles/globals.css +26 -0
  311. package/dist/web/assets/accounts-settings-section-BuxD9zH3.js +0 -1
  312. package/dist/web/assets/ai-settings-section-Dd9tOUp0.js +0 -1
  313. package/dist/web/assets/ai-settings-section-FrU2X8Fu.js +0 -1
  314. package/dist/web/assets/api-client-BUCo1lms.js +0 -1
  315. package/dist/web/assets/architecture-PBZL5I3N-5K0wEkAn.js +0 -1
  316. package/dist/web/assets/chat-tab-Cr6_KSGO.js +0 -15
  317. package/dist/web/assets/code-editor-DfmlGamv.js +0 -7
  318. package/dist/web/assets/context-menu-DOODKZdF.js +0 -1
  319. package/dist/web/assets/diff-viewer-BpNj7pN9.js +0 -4
  320. package/dist/web/assets/explorer-body-D-5z464e.js +0 -2
  321. package/dist/web/assets/explorer-window-content-7-1wuRul.js +0 -1
  322. package/dist/web/assets/file-icons-EzPL0q-k.js +0 -1
  323. package/dist/web/assets/file-icons.generated-CfaJuvZu.css +0 -1
  324. package/dist/web/assets/file-store-DMABxOkV.js +0 -1
  325. package/dist/web/assets/files-settings-section-CZzABuKz.js +0 -1
  326. package/dist/web/assets/git-log-panel-CRN4JVOx.js +0 -1
  327. package/dist/web/assets/gitGraph-HDMCJU4V-DkVT2MAM.js +0 -1
  328. package/dist/web/assets/group-chat-tab-DFa5mAx5.js +0 -1
  329. package/dist/web/assets/index-D7DbXD3G.css +0 -1
  330. package/dist/web/assets/index-ZtfxZOyb.js +0 -52
  331. package/dist/web/assets/info-3K5VOQVL-BBsmKGzA.js +0 -1
  332. package/dist/web/assets/keybindings-store-tVfhPANS.js +0 -1
  333. package/dist/web/assets/markdown-renderer-CvL1pWeK.js +0 -3
  334. package/dist/web/assets/markdown-renderer-sJNNVhlS.js +0 -1
  335. package/dist/web/assets/mobile-explorer-sheet-CZ0HZ2E_.js +0 -1
  336. package/dist/web/assets/notification-store-BZbsPnW0.js +0 -1
  337. package/dist/web/assets/packet-RMMSAZCW-DwmYPOlx.js +0 -1
  338. package/dist/web/assets/panel-store-BVLBRn6M.js +0 -1
  339. package/dist/web/assets/pie-UPGHQEXC-D0oogIFi.js +0 -1
  340. package/dist/web/assets/problems-panel-B7BWVhdy.js +0 -1
  341. package/dist/web/assets/project-store-BhMbVln3.js +0 -1
  342. package/dist/web/assets/radar-KQ55EAFF-CQIJOQGa.js +0 -1
  343. package/dist/web/assets/remote-desktop-mobile-sheet-ByjaeZKX.js +0 -2
  344. package/dist/web/assets/remote-desktop-mobile-view-D13mtr9F.js +0 -1
  345. package/dist/web/assets/remote-desktop-window-content-CbqTCaC6.js +0 -1
  346. package/dist/web/assets/settings-body-Rnu-FcX-.js +0 -2
  347. package/dist/web/assets/settings-store-DZPgPtEA.js +0 -2
  348. package/dist/web/assets/settings-tab-C6PHxs0Z.js +0 -1
  349. package/dist/web/assets/settings-window-content-CQ4gT2qj.js +0 -1
  350. package/dist/web/assets/system-monitor-body-2vQ1kMxE.js +0 -2
  351. package/dist/web/assets/system-monitor-tab-krAcvwF7.js +0 -1
  352. package/dist/web/assets/team-member-sheet-2FnRmk1a.js +0 -2
  353. package/dist/web/assets/tool-cards-DU_S2o51.js +0 -9
  354. package/dist/web/assets/treemap-KZPCXAKY-BhEtjljr.js +0 -1
  355. package/dist/web/assets/use-remote-desktop-display-choice-BK_f787P.js +0 -1
  356. package/dist/web/assets/video-preview-BDNwumbW.js +0 -1
  357. package/dist/web/assets/ws-auth-DEAJiGCR.js +0 -1
  358. /package/dist/web/assets/{abap-tkptwpsK.js → abap-IN2yINdN.js} +0 -0
  359. /package/dist/web/assets/{actionscript-3-Di9TMGwg.js → actionscript-3-C_t772eR.js} +0 -0
  360. /package/dist/web/assets/{ada-CB9F079D.js → ada-DPme3emm.js} +0 -0
  361. /package/dist/web/assets/{andromeeda-Dcl8jpb7.js → andromeeda-DSV4i4mZ.js} +0 -0
  362. /package/dist/web/assets/{apache-D0Nk0qsH.js → apache-CWr8s8I8.js} +0 -0
  363. /package/dist/web/assets/{apex-mQIoWncD.js → apex-Z20JnDF5.js} +0 -0
  364. /package/dist/web/assets/{applescript-C6ljbcsI.js → applescript-BKNPu3ga.js} +0 -0
  365. /package/dist/web/assets/{apply-theme-BwIMNXyX.js → apply-theme-CbR31K6I.js} +0 -0
  366. /package/dist/web/assets/{ara-WFqRPGPe.js → ara-hWdY3O96.js} +0 -0
  367. /package/dist/web/assets/{asciidoc-bNd8w4nf.js → asciidoc-eynhq496.js} +0 -0
  368. /package/dist/web/assets/{asm-BQ1_F580.js → asm-Bu02Kq4P.js} +0 -0
  369. /package/dist/web/assets/{aurora-x-Ciqs_Dbu.js → aurora-x-BHBGXbIZ.js} +0 -0
  370. /package/dist/web/assets/{awk-GCR-6KZV.js → awk-B4ojezyv.js} +0 -0
  371. /package/dist/web/assets/{ayu-dark-DxJXuj99.js → ayu-dark-D0GQzFi9.js} +0 -0
  372. /package/dist/web/assets/{ayu-light-jvSyJWDV.js → ayu-light-BVYb5Yn8.js} +0 -0
  373. /package/dist/web/assets/{ayu-mirage-Cg3BPO6H.js → ayu-mirage-BGFW6oNb.js} +0 -0
  374. /package/dist/web/assets/{ballerina-BPz4CrX6.js → ballerina-B6Og3IKT.js} +0 -0
  375. /package/dist/web/assets/{bat-CSTs2hIG.js → bat-D8YFILfx.js} +0 -0
  376. /package/dist/web/assets/{beancount-DMateAZX.js → beancount-BjlbBBuX.js} +0 -0
  377. /package/dist/web/assets/{berry-9lXg0GRM.js → berry-Cz1ygeoj.js} +0 -0
  378. /package/dist/web/assets/{bibtex-DIbqmvFg.js → bibtex-CVkJceJh.js} +0 -0
  379. /package/dist/web/assets/{bicep-02WGsoJ8.js → bicep-DrhYI5GX.js} +0 -0
  380. /package/dist/web/assets/{bird2-BY0tbu3k.js → bird2-BV-KJtmc.js} +0 -0
  381. /package/dist/web/assets/{c-jMBX_9Je.js → c-CuLlvxbG.js} +0 -0
  382. /package/dist/web/assets/{c3-B8JVbNjW.js → c3-CI7-1CJ0.js} +0 -0
  383. /package/dist/web/assets/{cadence-DUIf1tvL.js → cadence-DjxhNP3Q.js} +0 -0
  384. /package/dist/web/assets/{can-open-in-ppm-DGEc0s4P.js → can-open-in-ppm-cv5--yHX.js} +0 -0
  385. /package/dist/web/assets/{catppuccin-frappe-FhUCVxex.js → catppuccin-frappe-CEozpJRh.js} +0 -0
  386. /package/dist/web/assets/{catppuccin-latte-CzfrtmgL.js → catppuccin-latte-C4sXQFMc.js} +0 -0
  387. /package/dist/web/assets/{catppuccin-macchiato-6xL0lOtj.js → catppuccin-macchiato-Ci-fDhXy.js} +0 -0
  388. /package/dist/web/assets/{catppuccin-mocha-D39-xS3P.js → catppuccin-mocha-CH7YXw8d.js} +0 -0
  389. /package/dist/web/assets/{clarity-D8TeGvoT.js → clarity-BWrJ7UmT.js} +0 -0
  390. /package/dist/web/assets/{clojure-Dx_acSX7.js → clojure-C94fh2hb.js} +0 -0
  391. /package/dist/web/assets/{cmake-CyeYPq8o.js → cmake-CtvCkMsG.js} +0 -0
  392. /package/dist/web/assets/{codeowners-DrTI0lmI.js → codeowners-CJnubqzH.js} +0 -0
  393. /package/dist/web/assets/{codeql-CPkFxVW-.js → codeql-BOoP5HY2.js} +0 -0
  394. /package/dist/web/assets/{common-lisp-B0k-3LTj.js → common-lisp-B9nlMFJd.js} +0 -0
  395. /package/dist/web/assets/{coq-uygpo7to.js → coq-CgzIQiSH.js} +0 -0
  396. /package/dist/web/assets/{csharp-DKUYGfSp.js → csharp-4xAIx3jw.js} +0 -0
  397. /package/dist/web/assets/{css-DoOUp7v4.js → css-D4YoLYGn.js} +0 -0
  398. /package/dist/web/assets/{csv-B3YE13gi.js → csv-C2v-ZakW.js} +0 -0
  399. /package/dist/web/assets/{csv-parser-DXePqmXe.js → csv-parser-_oDBUkwQ.js} +0 -0
  400. /package/dist/web/assets/{cue-DViO2wvn.js → cue-Bbznh_an.js} +0 -0
  401. /package/dist/web/assets/{cypher-4BMCIW5N.js → cypher-BKhVEARF.js} +0 -0
  402. /package/dist/web/assets/{d-BT_sTHas.js → d-D6IhWopl.js} +0 -0
  403. /package/dist/web/assets/{dark-plus-DVVXu-1N.js → dark-plus-xAWu790O.js} +0 -0
  404. /package/dist/web/assets/{dart-DHz6f6_6.js → dart-Bj6S9O1j.js} +0 -0
  405. /package/dist/web/assets/{data-grid-types-OgUxMLdQ.js → data-grid-types-C5bthITf.js} +0 -0
  406. /package/dist/web/assets/{dax-ChYCjweK.js → dax-CF2zvaqq.js} +0 -0
  407. /package/dist/web/assets/{desktop-D6Lt4p04.js → desktop-CnmyxMKE.js} +0 -0
  408. /package/dist/web/assets/{diff-D8TDe4hP.js → diff-Qi8WuJsI.js} +0 -0
  409. /package/dist/web/assets/{dist-DOTlFQJA.js → dist-Bjseolz4.js} +0 -0
  410. /package/dist/web/assets/{dist-CrBOCtCW.js → dist-Czq7BUMy.js} +0 -0
  411. /package/dist/web/assets/{docker-Bsp0YbPx.js → docker-vLbbNP5d.js} +0 -0
  412. /package/dist/web/assets/{dotenv-B_7giSY_.js → dotenv-DJMvvNzn.js} +0 -0
  413. /package/dist/web/assets/{dracula-TrQL2iB5.js → dracula-CtAh2rhB.js} +0 -0
  414. /package/dist/web/assets/{dracula-soft-n2XOlgh-.js → dracula-soft-CXtuAAf6.js} +0 -0
  415. /package/dist/web/assets/{dream-maker-CdIEdhpT.js → dream-maker-D5YQyK49.js} +0 -0
  416. /package/dist/web/assets/{editor-font-BDrdiGf1.js → editor-font-ClTC9gaD.js} +0 -0
  417. /package/dist/web/assets/{emacs-lisp-CSbixs6u.js → emacs-lisp-CGTjbiqF.js} +0 -0
  418. /package/dist/web/assets/{everforest-dark-BuZahZYp.js → everforest-dark-D59p7vAQ.js} +0 -0
  419. /package/dist/web/assets/{everforest-light-DPH53z5H.js → everforest-light-B3Qtud3V.js} +0 -0
  420. /package/dist/web/assets/{fennel-B1-K_hlJ.js → fennel-BCyHNUwf.js} +0 -0
  421. /package/dist/web/assets/{fish-Cy12Dbua.js → fish-DDDlLV2G.js} +0 -0
  422. /package/dist/web/assets/{fluent-B_82ys8E.js → fluent-By54R9tl.js} +0 -0
  423. /package/dist/web/assets/{format-bytes-D5sBgIqU.js → format-bytes-D1AQyUCt.js} +0 -0
  424. /package/dist/web/assets/{fortran-free-form-BRQdNzZF.js → fortran-free-form-tP8mRym_.js} +0 -0
  425. /package/dist/web/assets/{gdscript-XBDmLUm9.js → gdscript-nHC2z6Te.js} +0 -0
  426. /package/dist/web/assets/{gdshader-DhVfB3u4.js → gdshader-K-cSmPlW.js} +0 -0
  427. /package/dist/web/assets/{genie-X3K29Y49.js → genie-BAcRhvEe.js} +0 -0
  428. /package/dist/web/assets/{gherkin-DKIx-6cX.js → gherkin-CcifxMLb.js} +0 -0
  429. /package/dist/web/assets/{github-dark-Bf7zdp5s.js → github-dark-67KKlMdB.js} +0 -0
  430. /package/dist/web/assets/{github-dark-default-DqsBBV11.js → github-dark-default-tja8pidR.js} +0 -0
  431. /package/dist/web/assets/{github-dark-dimmed-X2gqRz6w.js → github-dark-dimmed-CtjhYQtx.js} +0 -0
  432. /package/dist/web/assets/{github-dark-high-contrast-Z7tvbGX4.js → github-dark-high-contrast-Bf-LPFgn.js} +0 -0
  433. /package/dist/web/assets/{github-light-BKxt-7zZ.js → github-light-CbJxE7n3.js} +0 -0
  434. /package/dist/web/assets/{github-light-default-B0liF4d4.js → github-light-default-DRQmdHxt.js} +0 -0
  435. /package/dist/web/assets/{github-light-high-contrast-F4encJwr.js → github-light-high-contrast-CJkDgTeM.js} +0 -0
  436. /package/dist/web/assets/{gleam-Pz2bHgBB.js → gleam-D4LCl2ri.js} +0 -0
  437. /package/dist/web/assets/{gn-CgmdNsPU.js → gn-COY8zZmC.js} +0 -0
  438. /package/dist/web/assets/{gnuplot-qLNF5yZ9.js → gnuplot-ROk1VitR.js} +0 -0
  439. /package/dist/web/assets/{go-CSDUNhE7.js → go-H30c3p0C.js} +0 -0
  440. /package/dist/web/assets/{groovy-B3NEnOHF.js → groovy-DBLCaelV.js} +0 -0
  441. /package/dist/web/assets/{gruvbox-dark-hard-DcoftiUX.js → gruvbox-dark-hard-DJy4irps.js} +0 -0
  442. /package/dist/web/assets/{gruvbox-dark-medium-D1wVSuD8.js → gruvbox-dark-medium-Dhfw1QTO.js} +0 -0
  443. /package/dist/web/assets/{gruvbox-dark-soft-DWpunymH.js → gruvbox-dark-soft-BncJU-8w.js} +0 -0
  444. /package/dist/web/assets/{gruvbox-light-hard-rHMvyUdS.js → gruvbox-light-hard-Cq12_YvM.js} +0 -0
  445. /package/dist/web/assets/{gruvbox-light-medium-3O2KiXO7.js → gruvbox-light-medium-DqVja5_v.js} +0 -0
  446. /package/dist/web/assets/{gruvbox-light-soft-lNlXJPwH.js → gruvbox-light-soft-IvwhveGF.js} +0 -0
  447. /package/dist/web/assets/{haskell-aaG3aC0h.js → haskell-DA1JV-MC.js} +0 -0
  448. /package/dist/web/assets/{haxe-CPcHhUDd.js → haxe-V9RTRc5E.js} +0 -0
  449. /package/dist/web/assets/{hcl-CMQNlR_4.js → hcl-hr1lyZ10.js} +0 -0
  450. /package/dist/web/assets/{hjson-DeuklPFj.js → hjson-D3vW3i7X.js} +0 -0
  451. /package/dist/web/assets/{hlsl-BI3hlsaM.js → hlsl-BB85gfJT.js} +0 -0
  452. /package/dist/web/assets/{horizon-C7-gOcjs.js → horizon-DU8OOnj8.js} +0 -0
  453. /package/dist/web/assets/{horizon-bright-Cxt9bRW7.js → horizon-bright-DNMUclW6.js} +0 -0
  454. /package/dist/web/assets/{houston-DbF2G7iD.js → houston-DAiZKf6T.js} +0 -0
  455. /package/dist/web/assets/{hy-DRG6Hs2I.js → hy-C6Zv0LMe.js} +0 -0
  456. /package/dist/web/assets/{image-gallery-CObzTisL.js → image-gallery-CGvlv8zR.js} +0 -0
  457. /package/dist/web/assets/{imba-CxKv_2TW.js → imba-Didnp6Y-.js} +0 -0
  458. /package/dist/web/assets/{ini-BiHsyCdO.js → ini-m0T7q4gQ.js} +0 -0
  459. /package/dist/web/assets/{input-D-dR8RI6.js → input-C7Q8FxeL.js} +0 -0
  460. /package/dist/web/assets/{java-D3RZzgDB.js → java-Buy07jGn.js} +0 -0
  461. /package/dist/web/assets/{javascript-4FmSqG-T.js → javascript-Cjq3CbRL.js} +0 -0
  462. /package/dist/web/assets/{json-CjB236_E.js → json-BSVu8IqD.js} +0 -0
  463. /package/dist/web/assets/{json5-bkfO-Rco.js → json5-NN_Vb7e6.js} +0 -0
  464. /package/dist/web/assets/{jsonc-BwaTeLyv.js → jsonc-BdyZhBUw.js} +0 -0
  465. /package/dist/web/assets/{jsonl-CfxNSwGd.js → jsonl-BsDSNvwi.js} +0 -0
  466. /package/dist/web/assets/{jsonnet-CQETCYrp.js → jsonnet-Gm963F-U.js} +0 -0
  467. /package/dist/web/assets/{jssm-D5o3Zzdz.js → jssm-Ds3bKWgJ.js} +0 -0
  468. /package/dist/web/assets/{jsx-BAMILPLo.js → jsx-BT5mW58X.js} +0 -0
  469. /package/dist/web/assets/{kanagawa-dragon-BhGVxu3R.js → kanagawa-dragon-BvNvf7xd.js} +0 -0
  470. /package/dist/web/assets/{kanagawa-lotus-FH4Y59ro.js → kanagawa-lotus-CuSiliSn.js} +0 -0
  471. /package/dist/web/assets/{kanagawa-wave-eilvP9MB.js → kanagawa-wave-C6g-d6jT.js} +0 -0
  472. /package/dist/web/assets/{kdl-BQ-yvXUK.js → kdl-Bx4kZef-.js} +0 -0
  473. /package/dist/web/assets/{kotlin-BuCx0-VT.js → kotlin-qvaVvCcm.js} +0 -0
  474. /package/dist/web/assets/{kusto-DAN_n_Cy.js → kusto-BPLyNCN6.js} +0 -0
  475. /package/dist/web/assets/{laserwave-Cq2BlxrT.js → laserwave-Sf8ZEhWP.js} +0 -0
  476. /package/dist/web/assets/{lean-Dhq7uXKw.js → lean-DGe6uqgk.js} +0 -0
  477. /package/dist/web/assets/{less-CxaMQb8j.js → less-CqM85x-9.js} +0 -0
  478. /package/dist/web/assets/{lib-BVwmtv2i.js → lib-CD6pOS4u.js} +0 -0
  479. /package/dist/web/assets/{libesm-DdtEjhIi.js → libesm-CPh1Av0r.js} +0 -0
  480. /package/dist/web/assets/{light-plus-B4sMAend.js → light-plus-DBtKwhFA.js} +0 -0
  481. /package/dist/web/assets/{llvm-DQ6-B_6Y.js → llvm-Dpbq3gky.js} +0 -0
  482. /package/dist/web/assets/{log-Bb_vqvu7.js → log-qKMcPm9S.js} +0 -0
  483. /package/dist/web/assets/{logo-BzfYv3A_.js → logo-DFo7i5KH.js} +0 -0
  484. /package/dist/web/assets/{luau-BnAeNR77.js → luau-DGlqWFyL.js} +0 -0
  485. /package/dist/web/assets/{make-B6IFuxpC.js → make-CixdvUQe.js} +0 -0
  486. /package/dist/web/assets/{markdown-Z0xi77Fn.js → markdown-CmRnbngE.js} +0 -0
  487. /package/dist/web/assets/{material-theme-1scy1SYn.js → material-theme-WDUbafB-.js} +0 -0
  488. /package/dist/web/assets/{material-theme-darker-G-JykXQP.js → material-theme-darker-u8y2xpOk.js} +0 -0
  489. /package/dist/web/assets/{material-theme-lighter-BtKkCMVq.js → material-theme-lighter-cyQZK3Tg.js} +0 -0
  490. /package/dist/web/assets/{material-theme-ocean-irrDC89L.js → material-theme-ocean-LBAVvw7k.js} +0 -0
  491. /package/dist/web/assets/{material-theme-palenight-Eq5_K4LM.js → material-theme-palenight-BJqhBxL0.js} +0 -0
  492. /package/dist/web/assets/{matlab-BE3oCXZC.js → matlab-B38sOJee.js} +0 -0
  493. /package/dist/web/assets/{mdx-DYiuFTGw.js → mdx-C8QrE_IW.js} +0 -0
  494. /package/dist/web/assets/{mermaid-DVlaEvtw.js → mermaid-BQ-eeU8A.js} +0 -0
  495. /package/dist/web/assets/{min-dark-DSkeTpQa.js → min-dark-D4gNa5tv.js} +0 -0
  496. /package/dist/web/assets/{min-light-CFv2Q0uF.js → min-light-Dfbhn_PL.js} +0 -0
  497. /package/dist/web/assets/{mipsasm-CiAFuZQ2.js → mipsasm-bLOhJkdm.js} +0 -0
  498. /package/dist/web/assets/{mojo-ARshcaSQ.js → mojo-B0BCOMQW.js} +0 -0
  499. /package/dist/web/assets/{monaco-dotenv-language-BDYnKcnr.js → monaco-dotenv-language-uB-wok6C.js} +0 -0
  500. /package/dist/web/assets/{monokai-CPTV-SOg.js → monokai-Bdw_07OM.js} +0 -0
  501. /package/dist/web/assets/{moonbit-D57B0dZr.js → moonbit-BFdGaeuk.js} +0 -0
  502. /package/dist/web/assets/{move-qgy3G_o9.js → move-CyXQFGPM.js} +0 -0
  503. /package/dist/web/assets/{narrat-CZ3rC-oc.js → narrat-9DvTD3_3.js} +0 -0
  504. /package/dist/web/assets/{nextflow-groovy-BxxIOcI4.js → nextflow-groovy-C4VY3kNY.js} +0 -0
  505. /package/dist/web/assets/{night-owl-B1ryGCda.js → night-owl-feYm66V0.js} +0 -0
  506. /package/dist/web/assets/{night-owl-light-BZvNnvMF.js → night-owl-light-DALqFjvx.js} +0 -0
  507. /package/dist/web/assets/{nix-BVBQi8yv.js → nix-C1kPA9Sw.js} +0 -0
  508. /package/dist/web/assets/{nord-3NXw613h.js → nord-1dvrj1Al.js} +0 -0
  509. /package/dist/web/assets/{nushell-BMOLRalb.js → nushell-DSQ_9Uqj.js} +0 -0
  510. /package/dist/web/assets/{objective-c-AxruEUgh.js → objective-c-Dhcn5ZK8.js} +0 -0
  511. /package/dist/web/assets/{objective-cpp-cFT0qRsD.js → objective-cpp-CGVYCSrp.js} +0 -0
  512. /package/dist/web/assets/{ocaml-_8JH6O8J.js → ocaml-rxXW21An.js} +0 -0
  513. /package/dist/web/assets/{odin-nwYvR0O6.js → odin-ClSJX2DE.js} +0 -0
  514. /package/dist/web/assets/{one-dark-pro-C1LaYJaH.js → one-dark-pro-3gbWDfFW.js} +0 -0
  515. /package/dist/web/assets/{one-light-B7rMc__c.js → one-light-C2q5ZZAw.js} +0 -0
  516. /package/dist/web/assets/{openscad-Cwes8bKO.js → openscad-eHXeafBl.js} +0 -0
  517. /package/dist/web/assets/{pascal-DMt-6tdZ.js → pascal-kKha3Txs.js} +0 -0
  518. /package/dist/web/assets/{pkl-QBTyYQmB.js → pkl-CTiPytg-.js} +0 -0
  519. /package/dist/web/assets/{plastic-BTSUp8Fk.js → plastic-D1Ygezi4.js} +0 -0
  520. /package/dist/web/assets/{plsql-DQv3IFXP.js → plsql-D_gbgZIr.js} +0 -0
  521. /package/dist/web/assets/{po-CNwZx4tW.js → po-BkhbDUnq.js} +0 -0
  522. /package/dist/web/assets/{poimandres-8Os7Qequ.js → poimandres-Do6NywrA.js} +0 -0
  523. /package/dist/web/assets/{polar-b4yK8oD8.js → polar-B3B23wca.js} +0 -0
  524. /package/dist/web/assets/{postcss-sFctwpxx.js → postcss-Dv_YBvWd.js} +0 -0
  525. /package/dist/web/assets/{powerquery-Cg_WrtuN.js → powerquery-fKJWI-Sh.js} +0 -0
  526. /package/dist/web/assets/{powershell-C7Ifz95h.js → powershell-B4Y7KIgx.js} +0 -0
  527. /package/dist/web/assets/{prisma-Z52HUJzQ.js → prisma-J--XdTXX.js} +0 -0
  528. /package/dist/web/assets/{prolog-DLqW-zR1.js → prolog-BBTg4Vb3.js} +0 -0
  529. /package/dist/web/assets/{proto-BOIzxCCJ.js → proto-DWlum3T8.js} +0 -0
  530. /package/dist/web/assets/{puppet-De7TjZIf.js → puppet-ZiUfc9JV.js} +0 -0
  531. /package/dist/web/assets/{purescript-R76ou1WT.js → purescript-CmT8SCHB.js} +0 -0
  532. /package/dist/web/assets/{python-Dprm0tNP.js → python-BURpj-fq.js} +0 -0
  533. /package/dist/web/assets/{qmldir-Clp_jpNw.js → qmldir-CpaiJywQ.js} +0 -0
  534. /package/dist/web/assets/{qss-eQPYYzSo.js → qss-C-zdz0i5.js} +0 -0
  535. /package/dist/web/assets/{r-CCcRHIf5.js → r-K56BeS-s.js} +0 -0
  536. /package/dist/web/assets/{racket-CzE472yp.js → racket-gkn6Z_Jw.js} +0 -0
  537. /package/dist/web/assets/{raku-DQwXrTSi.js → raku-C0ZBuKlx.js} +0 -0
  538. /package/dist/web/assets/{red-KCS6wyop.js → red-BWZ6x-3p.js} +0 -0
  539. /package/dist/web/assets/{reg-CcrAddUh.js → reg-Dt_EsyGR.js} +0 -0
  540. /package/dist/web/assets/{regexp-DDbud-Ri.js → regexp-CT6BLG2C.js} +0 -0
  541. /package/dist/web/assets/{rel-99GDgaHp.js → rel-MJ2LcyzJ.js} +0 -0
  542. /package/dist/web/assets/{resolve-theme-CW2niGV2.js → resolve-theme-B_ukrg_8.js} +0 -0
  543. /package/dist/web/assets/{riscv-Dm2eNv0R.js → riscv-BZYWzMAA.js} +0 -0
  544. /package/dist/web/assets/{ron-CzFt0ygH.js → ron-CLbwHWMn.js} +0 -0
  545. /package/dist/web/assets/{rose-pine-Ck6lCrCP.js → rose-pine-BPiI_daR.js} +0 -0
  546. /package/dist/web/assets/{rose-pine-dawn-vtALRJNj.js → rose-pine-dawn-BjkJc7dW.js} +0 -0
  547. /package/dist/web/assets/{rose-pine-moon-DPto8qXw.js → rose-pine-moon-BQSxkt7g.js} +0 -0
  548. /package/dist/web/assets/{rosmsg-NtS6429H.js → rosmsg-yt4151pJ.js} +0 -0
  549. /package/dist/web/assets/{rust-BjIXvF9h.js → rust-1dAcengL.js} +0 -0
  550. /package/dist/web/assets/{sass-CQ23wf5E.js → sass-DUgtQJsg.js} +0 -0
  551. /package/dist/web/assets/{scala-LfKLM143.js → scala-CxoGYpS0.js} +0 -0
  552. /package/dist/web/assets/{scheme-D3SLBXlF.js → scheme-B2K3u9e3.js} +0 -0
  553. /package/dist/web/assets/{sdbl-ODRd2rGN.js → sdbl-C0Ygk0n6.js} +0 -0
  554. /package/dist/web/assets/{shellscript-3KB1G_oA.js → shellscript-C2CvhqMk.js} +0 -0
  555. /package/dist/web/assets/{slack-dark-DTtyWmIy.js → slack-dark-DYdgzRGj.js} +0 -0
  556. /package/dist/web/assets/{slack-ochin-Bu0PApk3.js → slack-ochin-X-WD0WCg.js} +0 -0
  557. /package/dist/web/assets/{smalltalk-haMT-Sbe.js → smalltalk-Dp7g_zb9.js} +0 -0
  558. /package/dist/web/assets/{snazzy-light-DXJzefE9.js → snazzy-light-DWHWr-a6.js} +0 -0
  559. /package/dist/web/assets/{solarized-dark-B6LyYa18.js → solarized-dark-CxdLsjvb.js} +0 -0
  560. /package/dist/web/assets/{solarized-light-QLADebkv.js → solarized-light-Cz9rAvG5.js} +0 -0
  561. /package/dist/web/assets/{solidity-mzfq1aDc.js → solidity-D33gHHdn.js} +0 -0
  562. /package/dist/web/assets/{splunk-CyH4RWBp.js → splunk-BFbOroYw.js} +0 -0
  563. /package/dist/web/assets/{sql-CWVlT5D3.js → sql-ChpxvmdY.js} +0 -0
  564. /package/dist/web/assets/{ssh-config-DNvQJ1Qx.js → ssh-config-CUuSQ6JG.js} +0 -0
  565. /package/dist/web/assets/{streaming-store-uDu3PoN1.js → streaming-store-BYukdB56.js} +0 -0
  566. /package/dist/web/assets/{stylus-ByQQdtmf.js → stylus-DDihP0_W.js} +0 -0
  567. /package/dist/web/assets/{swift-D1cpY4ow.js → swift-XoalUn4x.js} +0 -0
  568. /package/dist/web/assets/{synthwave-84-BDF_-QiW.js → synthwave-84-DjkG0Bff.js} +0 -0
  569. /package/dist/web/assets/{system-verilog-BYrkMydC.js → system-verilog-f_pLKMYd.js} +0 -0
  570. /package/dist/web/assets/{systemd-CQm3zyK0.js → systemd-DjDcLfxp.js} +0 -0
  571. /package/dist/web/assets/{talonscript-DMW5CzE1.js → talonscript-BpUzYcDl.js} +0 -0
  572. /package/dist/web/assets/{tasl-BhFzMCr2.js → tasl-DP-cUbg8.js} +0 -0
  573. /package/dist/web/assets/{tcl-D7VEAF-9.js → tcl-BHoy-dfE.js} +0 -0
  574. /package/dist/web/assets/{terraform-DdT5A0Vy.js → terraform-vCVxN25B.js} +0 -0
  575. /package/dist/web/assets/{tokyo-night-WGLMM6Q9.js → tokyo-night-D0u4xZba.js} +0 -0
  576. /package/dist/web/assets/{toml-CZ7ipXHZ.js → toml-BS8D0__A.js} +0 -0
  577. /package/dist/web/assets/{tsv-B1zVvoTr.js → tsv-DCb-NQh3.js} +0 -0
  578. /package/dist/web/assets/{tsx-D4HwRUBq.js → tsx-DF8YeRgG.js} +0 -0
  579. /package/dist/web/assets/{turtle-B4r8KEJH.js → turtle-Bhx1GlIy.js} +0 -0
  580. /package/dist/web/assets/{typescript-BnHhxMtp.js → typescript-CAVD2Wb6.js} +0 -0
  581. /package/dist/web/assets/{typespec-DP2q46GT.js → typespec-D7mchdY_.js} +0 -0
  582. /package/dist/web/assets/{typst-DFsD_yaD.js → typst-CeXzq6Yw.js} +0 -0
  583. /package/dist/web/assets/{use-is-mobile-BQ9Bv5Ga.js → use-is-mobile-TkcwP1Gx.js} +0 -0
  584. /package/dist/web/assets/{use-visual-viewport-CbwnktSG.js → use-visual-viewport-Lp878uzs.js} +0 -0
  585. /package/dist/web/assets/{v-Bji8hSVT.js → v-DhzO54je.js} +0 -0
  586. /package/dist/web/assets/{vala-D3TIgGmU.js → vala-Dw_RAk3E.js} +0 -0
  587. /package/dist/web/assets/{vb-DvcxFS2q.js → vb-CiXdNh2Y.js} +0 -0
  588. /package/dist/web/assets/{vendor-xterm-BqPDsE9b.js → vendor-xterm-BHEY6Ctu.js} +0 -0
  589. /package/dist/web/assets/{verilog-Dy7cF35d.js → verilog-fITdxqwV.js} +0 -0
  590. /package/dist/web/assets/{vesper-BzjwUv9J.js → vesper-B1wm_At7.js} +0 -0
  591. /package/dist/web/assets/{vhdl-DuFnFNmW.js → vhdl-ebHjqKp9.js} +0 -0
  592. /package/dist/web/assets/{viml-yAPgKlbz.js → viml-Dgmnoxoo.js} +0 -0
  593. /package/dist/web/assets/{vitesse-black-oSSQdyIZ.js → vitesse-black-BZ5gMb7l.js} +0 -0
  594. /package/dist/web/assets/{vitesse-dark-BZxwPihB.js → vitesse-dark-Lij7kkOt.js} +0 -0
  595. /package/dist/web/assets/{vitesse-light-uIigycvt.js → vitesse-light-DW6Wq7VC.js} +0 -0
  596. /package/dist/web/assets/{vyper-CX3NAxm5.js → vyper-6FxDnVNg.js} +0 -0
  597. /package/dist/web/assets/{wasm-6mEOOvVa.js → wasm-BDxaNPCj.js} +0 -0
  598. /package/dist/web/assets/{wasm-D9td37qO.js → wasm-DKhAtzfe.js} +0 -0
  599. /package/dist/web/assets/{wenyan-lwNIHgk6.js → wenyan-C0k0DYG_.js} +0 -0
  600. /package/dist/web/assets/{wgsl-DQAzCfog.js → wgsl-Y2zagbdn.js} +0 -0
  601. /package/dist/web/assets/{wikitext-DTXmt5NE.js → wikitext-C4QGWzkY.js} +0 -0
  602. /package/dist/web/assets/{wit-Bdw_7WDH.js → wit-CQESzjHy.js} +0 -0
  603. /package/dist/web/assets/{wolfram-DqyHDZ07.js → wolfram-B-ia69Ia.js} +0 -0
  604. /package/dist/web/assets/{yaml-CPXhdByd.js → yaml-CEYYTQPm.js} +0 -0
  605. /package/dist/web/assets/{zenscript-6s_i5zek.js → zenscript-BggWXIeJ.js} +0 -0
  606. /package/dist/web/assets/{zig-B2htezJ_.js → zig-CbaUfBQe.js} +0 -0
@@ -0,0 +1,173 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "bun:test";
2
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { openCompareView } from "./compare-view.ts";
6
+ import { _resetPanelRegistry } from "./panel-registry.ts";
7
+ import type { ExtensionContext } from "@ppm/vscode-compat";
8
+
9
+ /**
10
+ * The compare panel lists files for a whole range but opens one file at a time,
11
+ * and those two have to agree on the base.
12
+ *
13
+ * In three-dot mode the list comes from `git diff ref1...ref2`, i.e. against the
14
+ * merge base. Handing the tab `ref1` itself is a two-dot diff, so every commit
15
+ * ref1 gained since the branch point renders as a deletion inside a review of
16
+ * ref2 — with numbers that contradict the row that was clicked.
17
+ */
18
+
19
+ const GIT_ENV = {
20
+ GIT_AUTHOR_NAME: "Test Author",
21
+ GIT_AUTHOR_EMAIL: "test@example.com",
22
+ GIT_COMMITTER_NAME: "Test Committer",
23
+ GIT_COMMITTER_EMAIL: "committer@example.com",
24
+ GIT_CONFIG_GLOBAL: "/dev/null",
25
+ GIT_CONFIG_SYSTEM: "/dev/null",
26
+ };
27
+
28
+ let repo: string;
29
+
30
+ async function git(args: string[], cwd = repo) {
31
+ const proc = Bun.spawn(["git", ...args], { cwd, env: GIT_ENV, stdout: "pipe", stderr: "pipe" });
32
+ const stdout = await new Response(proc.stdout).text();
33
+ const stderr = await new Response(proc.stderr).text();
34
+ const exitCode = await proc.exited;
35
+ return { stdout, stderr, exitCode };
36
+ }
37
+
38
+ interface OpenedTab {
39
+ tabType: string;
40
+ title: string;
41
+ metadata: Record<string, unknown>;
42
+ }
43
+
44
+ function createFakeVscode() {
45
+ const opened: OpenedTab[] = [];
46
+ let listener: ((msg: unknown) => void) | null = null;
47
+
48
+ const vscode = {
49
+ commands: { registerCommand: () => ({ dispose() {} }) },
50
+ window: {
51
+ async showErrorMessage() { return undefined; },
52
+ async showInformationMessage() { return undefined; },
53
+ async openTab(tabType: string, title: string, _projectId: string | null, metadata?: Record<string, unknown>) {
54
+ opened.push({ tabType, title, metadata: metadata ?? {} });
55
+ },
56
+ async switchProject() {},
57
+ createWebviewPanel() {
58
+ return {
59
+ webview: {
60
+ html: "",
61
+ onDidReceiveMessage(l: (msg: unknown) => void) {
62
+ listener = l;
63
+ return { dispose() {} };
64
+ },
65
+ postMessage: async () => true,
66
+ },
67
+ onDidDispose: () => ({ dispose() {} }),
68
+ dispose() {},
69
+ };
70
+ },
71
+ },
72
+ process: {
73
+ async spawn(cmd: string, args: string[], cwd: string) {
74
+ const proc = Bun.spawn([cmd, ...args], { cwd, env: GIT_ENV, stdout: "pipe", stderr: "pipe" });
75
+ const stdout = await new Response(proc.stdout).text();
76
+ const stderr = await new Response(proc.stderr).text();
77
+ const exitCode = await proc.exited;
78
+ return { stdout, stderr, exitCode };
79
+ },
80
+ },
81
+ ViewColumn: { Active: 1 },
82
+ };
83
+
84
+ return { vscode, opened, send: (msg: unknown) => listener?.(msg) };
85
+ }
86
+
87
+ /** `onMessage` is dispatched with `void`, so the result has to be polled for. */
88
+ async function waitFor<T>(read: () => T | undefined, label: string): Promise<T> {
89
+ for (let i = 0; i < 200; i++) {
90
+ const value = read();
91
+ if (value !== undefined) return value;
92
+ await Bun.sleep(10);
93
+ }
94
+ throw new Error(`Timed out waiting for ${label}`);
95
+ }
96
+
97
+ describe("compare panel diff base", () => {
98
+ beforeEach(async () => {
99
+ _resetPanelRegistry();
100
+ repo = mkdtempSync(join(tmpdir(), "ppm-compare-base-"));
101
+ await git(["init", "-b", "main"]);
102
+ writeFileSync(join(repo, "README.md"), "base\n");
103
+ await git(["add", "."]);
104
+ await git(["commit", "-m", "initial"]);
105
+
106
+ // The feature branch: one file, added after the branch point.
107
+ await git(["checkout", "-b", "feature"]);
108
+ writeFileSync(join(repo, "feature.txt"), "feature work\n");
109
+ await git(["add", "."]);
110
+ await git(["commit", "-m", "add feature"]);
111
+
112
+ // main moves on afterwards — this is what makes the two modes differ.
113
+ await git(["checkout", "main"]);
114
+ writeFileSync(join(repo, "README.md"), "base\nchanged on main\n");
115
+ writeFileSync(join(repo, "other.txt"), "unrelated\n");
116
+ await git(["add", "."]);
117
+ await git(["commit", "-m", "move main ahead"]);
118
+ await git(["checkout", "feature"]);
119
+ });
120
+
121
+ afterEach(() => {
122
+ rmSync(repo, { recursive: true, force: true });
123
+ });
124
+
125
+ it("opens a three-dot row against the merge base, not ref1's tip", async () => {
126
+ const { vscode, opened, send } = createFakeVscode();
127
+ openCompareView(vscode as any, {} as ExtensionContext, repo);
128
+
129
+ send({ command: "openDiff", filePath: "feature.txt", ref1: "main", ref2: "feature", mode: "three-dot" });
130
+ const tab = await waitFor(() => opened[0], "the diff tab");
131
+
132
+ const base = (await git(["merge-base", "main", "feature"])).stdout.trim();
133
+ const mainTip = (await git(["rev-parse", "main"])).stdout.trim();
134
+
135
+ expect(base).not.toBe(mainTip); // the setup is only meaningful while these differ
136
+ expect(tab.tabType).toBe("git-diff");
137
+ expect(tab.metadata.ref1).toBe(base);
138
+ expect(tab.metadata.ref2).toBe("feature");
139
+ expect(tab.title).toContain("main...feature");
140
+ });
141
+
142
+ it("leaves ref1 alone in two-dot mode", async () => {
143
+ const { vscode, opened, send } = createFakeVscode();
144
+ openCompareView(vscode as any, {} as ExtensionContext, repo);
145
+
146
+ send({ command: "openDiff", filePath: "feature.txt", ref1: "main", ref2: "feature", mode: "two-dot" });
147
+ const tab = await waitFor(() => opened[0], "the diff tab");
148
+
149
+ expect(tab.metadata.ref1).toBe("main");
150
+ expect(tab.title).toContain("main..feature");
151
+ });
152
+
153
+ it("the base it opens reproduces the counts the file list showed", async () => {
154
+ const { vscode, opened, send } = createFakeVscode();
155
+ openCompareView(vscode as any, {} as ExtensionContext, repo);
156
+
157
+ send({ command: "openDiff", filePath: "README.md", ref1: "main", ref2: "feature", mode: "three-dot" });
158
+ const tab = await waitFor(() => opened[0], "the diff tab");
159
+
160
+ // What the panel listed: README.md is untouched by the feature branch, so
161
+ // three-dot reports nothing for it at all.
162
+ const listed = (await git(["diff", "--numstat", "main...feature"])).stdout;
163
+ expect(listed).not.toContain("README.md");
164
+
165
+ // What the tab now shows for the same file: equally nothing.
166
+ const shown = (await git(["diff", "--numstat", `${tab.metadata.ref1}`, "feature", "--", "README.md"])).stdout;
167
+ expect(shown.trim()).toBe("");
168
+
169
+ // And what it showed before the fix: main's own commit, backwards.
170
+ const twoDot = (await git(["diff", "--numstat", "main", "feature", "--", "README.md"])).stdout;
171
+ expect(twoDot).toContain("README.md");
172
+ });
173
+ });
@@ -78,11 +78,19 @@ export function openCompareView(
78
78
  assertSafeFilePaths([filePath], projectPath);
79
79
  const ref1 = assertValidRef(msg.ref1, "ref1");
80
80
  const ref2 = assertValidRef(msg.ref2, "ref2");
81
+ const mode: CompareMode = msg.mode === "two-dot" ? "two-dot" : "three-dot";
82
+ // The row was listed by a diff against `base`, so the tab it opens
83
+ // has to use the same base — in three-dot mode that is the merge
84
+ // base, not ref1's tip. With ref1 advanced past the branch point,
85
+ // ref1's own commits otherwise render as deletions in a review of
86
+ // ref2, and the +/- counts disagree with the row that was clicked.
87
+ const base = mode === "three-dot" ? await mergeBase(ref1, ref2) : ref1;
81
88
  const fileName = filePath.split(/[\\/]/).pop() || filePath;
82
89
  const target = await resolveFileTab(projectPath, filePath);
83
- await vscode.window.openTab("git-diff", `${fileName} (${ref1}→${ref2})`, target.projectName, {
90
+ const range = `${ref1}${mode === "three-dot" ? "..." : ".."}${ref2}`;
91
+ await vscode.window.openTab("git-diff", `${fileName} (${range})`, target.projectName, {
84
92
  ...target,
85
- ref1,
93
+ ref1: base,
86
94
  ref2,
87
95
  });
88
96
  break;
@@ -108,6 +116,17 @@ export function openCompareView(
108
116
  return res.exitCode === 0 ? parseRefList(res.stdout) : [];
109
117
  }
110
118
 
119
+ /**
120
+ * Where the two refs diverged. Falls back to ref1 when git reports none:
121
+ * `git diff a...b` fails outright on unrelated histories, so the compare that
122
+ * listed the file would already have shown that error.
123
+ */
124
+ async function mergeBase(ref1: string, ref2: string): Promise<string> {
125
+ const res = await spawnGit(vscode, ["merge-base", ref1, ref2], projectPath, 60_000);
126
+ const base = res.stdout.trim();
127
+ return res.exitCode === 0 && base ? base : ref1;
128
+ }
129
+
111
130
  async function loadCompare(rawRef1: unknown, rawRef2: unknown, mode: CompareMode): Promise<void> {
112
131
  const ref1 = assertValidRef(rawRef1, "ref1");
113
132
  const ref2 = assertValidRef(rawRef2, "ref2");
@@ -257,7 +276,7 @@ document.getElementById('btn-swap').addEventListener('click', () => {
257
276
  el.files.addEventListener('click', (e) => {
258
277
  const row = e.target.closest('.f-row');
259
278
  if (!row) return;
260
- vscode.postMessage({ command: 'openDiff', filePath: row.dataset.path, ref1: state.ref1, ref2: state.ref2 });
279
+ vscode.postMessage({ command: 'openDiff', filePath: row.dataset.path, ref1: state.ref1, ref2: state.ref2, mode: state.mode });
261
280
  });
262
281
 
263
282
  function renderCommits(commits, truncated) {
@@ -31,6 +31,7 @@ const VALID_SETTING_KEYS = new Set<string>([
31
31
  "maxCommits", "showTags", "showStashes", "showRemoteBranches", "graphStyle",
32
32
  "firstParentOnly", "dateFormat", "commitOrdering", "issueLinkingRules", "prCreation",
33
33
  "autoFetchInterval",
34
+ "colRefs", "colChanges", "colAuthor", "colDate", "colHash",
34
35
  ]);
35
36
 
36
37
  async function saveSetting(context: ExtensionContext, key: string, value: unknown): Promise<GitGraphSettings> {
@@ -95,6 +96,11 @@ function openGitGraph(
95
96
  try {
96
97
  switch (msg.command) {
97
98
  case "ready":
99
+ // Before anything is drawn: the settings say which columns the table
100
+ // has, and until this arrived they were only fetched when the
101
+ // settings panel was opened — so a saved choice took effect on the
102
+ // second look at the panel rather than the first.
103
+ await panel.webview.postMessage({ command: "loadSettings", data: getSettings(context) });
98
104
  await handleRepoInfo(vscode, panel, pp);
99
105
  await handleRequestCommits(vscode, panel, pp, context);
100
106
  handleUncommittedStatus(vscode, panel, pp); // fire-and-forget
@@ -134,6 +134,20 @@ export interface GitGraphSettings {
134
134
  issueLinkingRules: IssueLinkingRule[];
135
135
  prCreation: PrCreationConfig | null;
136
136
  autoFetchInterval: number;
137
+ /*
138
+ * Which columns the commit table shows. Flat keys rather than one nested
139
+ * object, because the stored settings are merged over the defaults one level
140
+ * deep: a nested object saved by an older version would keep its own shape
141
+ * and any key added later would arrive undefined.
142
+ *
143
+ * A narrow panel drops columns of its own accord regardless of these — they
144
+ * say what to show when there is room for it.
145
+ */
146
+ colRefs: boolean;
147
+ colChanges: boolean;
148
+ colAuthor: boolean;
149
+ colDate: boolean;
150
+ colHash: boolean;
137
151
  }
138
152
 
139
153
  export const DEFAULT_SETTINGS: GitGraphSettings = {
@@ -148,6 +162,11 @@ export const DEFAULT_SETTINGS: GitGraphSettings = {
148
162
  issueLinkingRules: [{ pattern: "#(\\d+)", url: "" }],
149
163
  prCreation: null,
150
164
  autoFetchInterval: 0,
165
+ colRefs: true,
166
+ colChanges: true,
167
+ colAuthor: true,
168
+ colDate: true,
169
+ colHash: true,
151
170
  };
152
171
 
153
172
  // --- Extension → Webview messages ---
@@ -177,7 +177,12 @@ describe("webview-html: the injected script", () => {
177
177
  it("offsets the graph overlay by the branch column's width", () => {
178
178
  // The SVG is one absolutely-positioned overlay: if its left edge does not
179
179
  // track the column in front of it, every node is drawn off its row's dot.
180
- expect(getWebviewHtml()).toContain("left: calc(var(--refs-col-w, 170px) + 8px)");
180
+ // The 6px is the row's own padding, which is where the graph cell starts;
181
+ // the 2px the drawing sits in from there is on the SVG inside the clip box,
182
+ // because a box offset by both ends 2px past the column it clips to.
183
+ const html = getWebviewHtml();
184
+ expect(html).toContain("left: calc(var(--refs-col-w, 170px) + 6px)");
185
+ expect(html).toMatch(/#graph-svg-container \{[^}]*left: 2px/);
181
186
  });
182
187
  });
183
188
 
@@ -547,3 +552,131 @@ describe("getWebviewHtml commit details", () => {
547
552
  expect(actions.slice(0, actions.indexOf("}"))).not.toContain("margin-left: auto");
548
553
  });
549
554
  });
555
+
556
+ describe("webview-html: a panel narrower than the table", () => {
557
+ const html = getWebviewHtml();
558
+
559
+ it("caps the graph column instead of letting it take the row", () => {
560
+ // The column used to be set to whatever the lanes needed. The message is
561
+ // the only column that can shrink, so from about twenty parallel branches
562
+ // on it was the message that paid for the graph — all of it, down to zero.
563
+ expect(html).not.toContain("setProperty('--graph-col-w', gw + 'px')");
564
+ expect(html).toContain("function graphColCap()");
565
+ expect(html).toContain("area.clientWidth - fixed - rowPadding - MESSAGE_MIN_W");
566
+ expect(html).toContain("Math.min(want || GRAPH_MIN_W, cap)");
567
+ });
568
+
569
+ it("measures what the columns take rather than listing them", () => {
570
+ // Hiding a column has to give its pixels to the graph. A table of constants
571
+ // here would need editing every time a column is added or hidden, and the
572
+ // way that shows is a cap that is quietly too small.
573
+ expect(html).toContain(".col-refs, .col-changes, .col-author, .col-date, .col-hash')");
574
+ expect(html).toContain("fixed += cell.offsetWidth");
575
+ });
576
+
577
+ it("recomputes the cap when the panel changes size", () => {
578
+ // Nothing re-renders the graph when a window is dragged, so without this
579
+ // the cap stays at whatever the width was when the commits last arrived.
580
+ expect(html).toContain("new ResizeObserver(() => applyGraphColWidth())");
581
+ });
582
+
583
+ it("clips the overlay to the column it belongs to", () => {
584
+ // The overlay is positioned and the rows are not, so it paints above them:
585
+ // capping the column without clipping only replaces a missing message with
586
+ // one that has branch lines drawn through it.
587
+ expect(html).toMatch(/#graph-clip \{[^}]*width: var\(--graph-col-w/);
588
+ expect(html).toMatch(/#graph-clip \{[^}]*overflow: hidden/);
589
+ expect(html).toContain('<div id="graph-clip"><div id="graph-svg-container"></div></div>');
590
+ });
591
+
592
+ it("puts the graph's scrollbar in the header, not on the graph", () => {
593
+ // The overlay is as tall as the whole history, so a scrollbar along its
594
+ // bottom edge would sit thousands of pixels below the viewport.
595
+ const header = html.slice(html.indexOf('id="graph-header"'), html.indexOf('id="commit-list-wrapper"'));
596
+ expect(header).toContain('id="graph-hscroll"');
597
+ expect(html).toContain("transform: translateX(calc(-1 * var(--graph-pan-x, 0px)))");
598
+ });
599
+
600
+ it("agrees between the message column's floor and the cap that respects it", () => {
601
+ // Two numbers for one thing: a CSS floor wider than the JS cap allows for
602
+ // is a row that overflows its own box instead of one that fits.
603
+ const cssFloor = html.match(/\.col-message \{[^}]*min-width: (\d+)px/);
604
+ const jsFloor = html.match(/const MESSAGE_MIN_W = (\d+);/);
605
+ expect(cssFloor?.[1]).toBeDefined();
606
+ expect(cssFloor?.[1]).toBe(jsFloor?.[1]);
607
+ });
608
+
609
+ it("drops the message's floor on a phone, where the row is the message", () => {
610
+ // A floor wider than the panel is what makes a row overflow its own box.
611
+ const phone = html.slice(html.indexOf("@media (max-width: 640px)"));
612
+ expect(phone.slice(0, phone.indexOf("\n}"))).toContain(".col-message { min-width: 0; }");
613
+ });
614
+
615
+ it("sheds the columns that carry least, in order, before anything is crushed", () => {
616
+ expect(html).toMatch(/@media \(max-width: 900px\) \{\s*\.col-date, \.col-hash \{ display: none; \}/);
617
+ expect(html).toMatch(/@media \(max-width: 760px\) \{\s*\.col-changes \{ display: none; \}/);
618
+ });
619
+
620
+ it("lets those tiers apply to a tablet too", () => {
621
+ // The coarse block used to hold the table open at 880px and scroll it
622
+ // sideways, which cancels every tier below that width.
623
+ const coarse = html.slice(html.indexOf("@media (pointer: coarse)"));
624
+ expect(coarse.slice(0, coarse.indexOf("\n}"))).not.toContain("min-width: 880px");
625
+ expect(html).not.toContain("#commit-list-wrapper { min-width: 880px; }");
626
+ });
627
+
628
+ it("declares the tiers after the coarse block and before the phone one", () => {
629
+ const coarse = html.indexOf("@media (pointer: coarse)");
630
+ const tier = html.indexOf("@media (max-width: 900px)");
631
+ const phone = html.indexOf("@media (max-width: 640px)");
632
+ expect(coarse).toBeLessThan(tier);
633
+ expect(tier).toBeLessThan(phone);
634
+ });
635
+ });
636
+
637
+ describe("webview-html: column visibility", () => {
638
+ const html = getWebviewHtml();
639
+ const columns = [
640
+ { key: "colRefs", cls: "cols-no-refs", col: "col-refs" },
641
+ { key: "colChanges", cls: "cols-no-changes", col: "col-changes" },
642
+ { key: "colAuthor", cls: "cols-no-author", col: "col-author" },
643
+ { key: "colDate", cls: "cols-no-date", col: "col-date" },
644
+ { key: "colHash", cls: "cols-no-hash", col: "col-hash" },
645
+ ];
646
+
647
+ it("offers every optional column in Settings, in the script, and in CSS", () => {
648
+ for (const c of columns) {
649
+ expect(html).toContain(`id="s-${c.key}"`);
650
+ expect(html).toContain(`{ key: '${c.key}', cls: '${c.cls}'`);
651
+ expect(html).toContain(`.${c.cls} .${c.col} { display: none; }`);
652
+ }
653
+ });
654
+
655
+ it("zeroes the refs variable when that column goes, not just the cell", () => {
656
+ // The variable is where the graph overlay starts, so hiding the cell alone
657
+ // would leave every node drawn 170px to the right of its row's dot.
658
+ expect(html).toContain(".cols-no-refs { --refs-col-w: 0px; }");
659
+ });
660
+
661
+ it("opens the same list from the header as from Settings", () => {
662
+ expect(html).toContain("header.addEventListener('contextmenu'");
663
+ expect(html).toContain("setupLongPress(header, (x, y) => showColumnMenu(x, y))");
664
+ expect(html).toContain("setColumnVisible(col.key, e.target.checked)");
665
+ });
666
+
667
+ it("marks what the panel's width has already taken away", () => {
668
+ // A tick that does nothing, with nothing to say why, is worse than an item
669
+ // that says it needs more room.
670
+ expect(html).toContain("columnBlockedByWidth");
671
+ expect(html).toContain("needs a wider panel");
672
+ expect(html).toContain("window.matchMedia('(max-width: 900px)').matches");
673
+ expect(html).toContain("window.matchMedia('(max-width: 760px)').matches");
674
+ });
675
+
676
+ it("hands the freed width to the graph", () => {
677
+ // No resize fires for a column that was hidden, so the cap would otherwise
678
+ // keep reserving room for a column that is no longer there.
679
+ const apply = html.slice(html.indexOf("function applyColumnVisibility()"));
680
+ expect(apply.slice(0, apply.indexOf("\n}"))).toContain("applyGraphColWidth()");
681
+ });
682
+ });