@hienlh/ppm 0.17.16 → 0.17.18

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 (464) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/cli-reference.md +4 -4
  4. package/assets/skills/ppm/references/http-api.md +5 -1
  5. package/dist/web/assets/{ai-resource-editor-CsossqDO.js → ai-resource-editor-BgWg-ty8.js} +1 -1
  6. package/dist/web/assets/{angular-html-CkxY2iBQ.js → angular-html-2g8YGiJY.js} +1 -1
  7. package/dist/web/assets/{angular-ts-BePeGkkC.js → angular-ts-BwSmoLfh.js} +1 -1
  8. package/dist/web/assets/{api-settings-DAk7D-NP.js → api-settings-BJTjIG4U.js} +1 -1
  9. package/dist/web/assets/{api-themes-84MT-XqR.js → api-themes-DuLpbQFV.js} +1 -1
  10. package/dist/web/assets/{apl-DBS7PWvB.js → apl-B44SMKHp.js} +1 -1
  11. package/dist/web/assets/architecture-PBZL5I3N-gLlhsjM9.js +1 -0
  12. package/dist/web/assets/{astro-Clbk1k4h.js → astro-E5620wek.js} +1 -1
  13. package/dist/web/assets/{audio-preview-DIkokvPM.js → audio-preview-CLn1LTxc.js} +1 -1
  14. package/dist/web/assets/{blade-BeBsBuGS.js → blade-D-VQWAHB.js} +1 -1
  15. package/dist/web/assets/{bsl-DYigT3JZ.js → bsl-Bq5qFzpU.js} +1 -1
  16. package/dist/web/assets/{cairo-BjpO78wI.js → cairo-Cn9-ZKRa.js} +1 -1
  17. package/dist/web/assets/chat-tab-tTUVo4G3.js +13 -0
  18. package/dist/web/assets/{cobol-CpuUx69s.js → cobol-IM3E3iCH.js} +1 -1
  19. package/dist/web/assets/code-editor-DMfUjdk5.js +10 -0
  20. package/dist/web/assets/{coffee-FoFd2Cxo.js → coffee-24wG7ekn.js} +1 -1
  21. package/dist/web/assets/{conflict-editor-Dqm1bkyL.js → conflict-editor-BosR4PW3.js} +3 -3
  22. package/dist/web/assets/{cpp-CO_nPfdr.js → cpp-DH9Cqt4g.js} +1 -1
  23. package/dist/web/assets/{crystal-D-UygAAF.js → crystal-4nZYHhdi.js} +1 -1
  24. package/dist/web/assets/{csv-preview-CvP4xzug.js → csv-preview-BqszurHp.js} +1 -1
  25. package/dist/web/assets/data-grid-overlay-editor-DxdOKRAY.js +1 -0
  26. package/dist/web/assets/data-grid-types-CzEQU9PJ.js +1 -0
  27. package/dist/web/assets/database-viewer-CiomoOU6.js +1 -0
  28. package/dist/web/assets/dialog-BpkAWOy8.js +1 -0
  29. package/dist/web/assets/{diff-viewer-BfWixe_z.js → diff-viewer-aOrOaGWx.js} +1 -1
  30. package/dist/web/assets/dist-Bn3E6I4R.js +11 -0
  31. package/dist/web/assets/{docx-preview-CguUoTKe.js → docx-preview-BAzpJdua.js} +1 -1
  32. package/dist/web/assets/{edge-BSzxzX11.js → edge-DTI9d2Qi.js} +1 -1
  33. package/dist/web/assets/{elixir-DH1-Mrep.js → elixir-Ys0wioho.js} +1 -1
  34. package/dist/web/assets/{elm-B0ln5J70.js → elm-Cihc9TAz.js} +1 -1
  35. package/dist/web/assets/{erb-GIz6NnlZ.js → erb-BwYBWK2-.js} +1 -1
  36. package/dist/web/assets/{erlang-B8MgYhib.js → erlang-CzlD_Joo.js} +1 -1
  37. package/dist/web/assets/esm-JLkfN0k-.js +2 -0
  38. package/dist/web/assets/{extension-webview-DTpFt1eL.js → extension-webview-CKUUvgOr.js} +1 -1
  39. package/dist/web/assets/{fortran-fixed-form-D_-TrK6U.js → fortran-fixed-form-CT90EtSp.js} +1 -1
  40. package/dist/web/assets/{fsharp-C9cLCk2b.js → fsharp-LasxezlU.js} +1 -1
  41. package/dist/web/assets/{gdresource-CsZ3lXwY.js → gdresource-XqgPdfiE.js} +1 -1
  42. package/dist/web/assets/{git-commit-xmq0KqrA.js → git-commit-CZBgPolw.js} +1 -1
  43. package/dist/web/assets/{git-log-panel-DUX7N5tN.js → git-log-panel-B6GFWhj4.js} +1 -1
  44. package/dist/web/assets/{git-rebase-D3O-jsSX.js → git-rebase-C2VzKDB1.js} +1 -1
  45. package/dist/web/assets/gitGraph-HDMCJU4V-BKGq--Jw.js +1 -0
  46. package/dist/web/assets/glide-data-grid-z9FPvRBG.js +138 -0
  47. package/dist/web/assets/{glimmer-js-g74gESrC.js → glimmer-js-DfjWcOLD.js} +1 -1
  48. package/dist/web/assets/{glimmer-ts-DF4aDWHT.js → glimmer-ts-DBldQATc.js} +1 -1
  49. package/dist/web/assets/{glsl-D5LmfW7l.js → glsl-CzNv1NPP.js} +1 -1
  50. package/dist/web/assets/{graphql-_KI4RuXL.js → graphql-DDyLtQb4.js} +1 -1
  51. package/dist/web/assets/group-chat-tab-Bu31mwmF.js +1 -0
  52. package/dist/web/assets/{hack-B1NaTC39.js → hack-CtoYNYkC.js} +1 -1
  53. package/dist/web/assets/{haml-DDFXadZ4.js → haml-CnBVap7G.js} +1 -1
  54. package/dist/web/assets/{handlebars-Bp-Jq3K9.js → handlebars-Dg51esUH.js} +1 -1
  55. package/dist/web/assets/{html-DyB9_5Tj.js → html-Ec2_evSy.js} +1 -1
  56. package/dist/web/assets/{html-derivative-CC60wi-3.js → html-derivative-Cy-F7ZqL.js} +1 -1
  57. package/dist/web/assets/{http-C-9qngH4.js → http-C236v8Tg.js} +1 -1
  58. package/dist/web/assets/{hurl-BtxgpNDs.js → hurl-0rMD2gPU.js} +1 -1
  59. package/dist/web/assets/{hxml-DOoOS9op.js → hxml-e5uS5jTD.js} +1 -1
  60. package/dist/web/assets/{image-preview-CZg6FQ3w.js → image-preview-CaX4gpN6.js} +1 -1
  61. package/dist/web/assets/index-4M24PSHW.js +50 -0
  62. package/dist/web/assets/index-BYFXiFsa.css +2 -0
  63. package/dist/web/assets/info-3K5VOQVL-BOhGriBF.js +1 -0
  64. package/dist/web/assets/{jinja-cN-150ao.js → jinja-DybFmhfq.js} +1 -1
  65. package/dist/web/assets/{jison-CqjsqPq5.js → jison-hkHbixdZ.js} +1 -1
  66. package/dist/web/assets/{julia-C-I5m8W4.js → julia-QnxY6sRE.js} +1 -1
  67. package/dist/web/assets/{just-CgsSW9zs.js → just-1Rs-nm8g.js} +1 -1
  68. package/dist/web/assets/keybindings-store-Cv-U85V6.js +1 -0
  69. package/dist/web/assets/{latex-BFzR9N2d.js → latex-jEBQqA7u.js} +1 -1
  70. package/dist/web/assets/{liquid-BWfr-_iC.js → liquid-DfJaZpxG.js} +1 -1
  71. package/dist/web/assets/{lua-DsXVun6g.js → lua-ti0Jr6-C.js} +1 -1
  72. package/dist/web/assets/{markdown-renderer-CiQkvWP_.js → markdown-renderer-BNXJygz9.js} +3 -3
  73. package/dist/web/assets/markdown-renderer-DCsEEdo7.js +1 -0
  74. package/dist/web/assets/{marko-DWBbo09n.js → marko-DNj4AhPg.js} +1 -1
  75. package/dist/web/assets/{mdc-CUMe9LOG.js → mdc-DPFwQFe4.js} +1 -1
  76. package/dist/web/assets/mobile-bottom-sheet--5_YEewV.js +1 -0
  77. package/dist/web/assets/{nextflow-CoYbADOm.js → nextflow-BUrFV5aB.js} +1 -1
  78. package/dist/web/assets/{nginx-z-JRZREw.js → nginx-BrW9NdOb.js} +1 -1
  79. package/dist/web/assets/{nim-Ci4LHyBm.js → nim-DS_6PF2p.js} +1 -1
  80. package/dist/web/assets/notification-store-DADt1gJH.js +1 -0
  81. package/dist/web/assets/{number-overlay-editor-lnnuUpPI.js → number-overlay-editor-CReXWiQ1.js} +1 -1
  82. package/dist/web/assets/packet-RMMSAZCW-CdLFnL8a.js +1 -0
  83. package/dist/web/assets/{panel-store-D6RV_ztx.js → panel-store-DnbT1c8L.js} +1 -1
  84. package/dist/web/assets/{pdf-preview-B6ZqANpw.js → pdf-preview-DZzbm9A4.js} +1 -1
  85. package/dist/web/assets/{perl-pbDimKOO.js → perl-ytm9vKO_.js} +1 -1
  86. package/dist/web/assets/{php-B003E5v7.js → php-DWTD1Usw.js} +1 -1
  87. package/dist/web/assets/pie-UPGHQEXC-COC-h0zz.js +1 -0
  88. package/dist/web/assets/{trash-2-CbbD5QF1.js → plus-DcuJuDC3.js} +1 -1
  89. package/dist/web/assets/postgres-viewer-BxpeiVkt.js +3 -0
  90. package/dist/web/assets/{project-store-Cekcjcom.js → project-store-Sbnqc41N.js} +1 -1
  91. package/dist/web/assets/{pug-AoueAWJo.js → pug-Bt7KL3_r.js} +1 -1
  92. package/dist/web/assets/{qml-CepxioQA.js → qml-Dexdon5J.js} +1 -1
  93. package/dist/web/assets/radar-KQ55EAFF-CiCfdJNL.js +1 -0
  94. package/dist/web/assets/{razor-lIvU-Gu-.js → razor-DnYCSl0G.js} +1 -1
  95. package/dist/web/assets/{rst-Dn-dwElE.js → rst-BEFYzwF8.js} +1 -1
  96. package/dist/web/assets/{ruby-DmsD1Iz5.js → ruby-BPaXFEjN.js} +1 -1
  97. package/dist/web/assets/{sas-6IM2P4YP.js → sas-CywiNBp8.js} +1 -1
  98. package/dist/web/assets/{scss-RgYEZQqh.js → scss-CGk0L6hN.js} +1 -1
  99. package/dist/web/assets/{settings-store-BkSf4SPQ.js → settings-store-DkRZhj-g.js} +2 -2
  100. package/dist/web/assets/settings-tab-DJOhpW09.js +1 -0
  101. package/dist/web/assets/{shaderlab-B0MNEwt4.js → shaderlab-Byjk0kH7.js} +1 -1
  102. package/dist/web/assets/{shellsession-F8S4LrQI.js → shellsession-DbA70QB6.js} +1 -1
  103. package/dist/web/assets/{soy-DDlMbX7u.js → soy-Bm97kWiA.js} +1 -1
  104. package/dist/web/assets/sparkles-B3DmG8PJ.js +1 -0
  105. package/dist/web/assets/{sparql-kthmGAAe.js → sparql-CawLnniT.js} +1 -1
  106. package/dist/web/assets/{sql-query-editor-BYNM0RRl.js → sql-query-editor-9TwIPvRj.js} +1 -1
  107. package/dist/web/assets/sqlite-viewer-D-3i_x28.js +1 -0
  108. package/dist/web/assets/{stata-Tfbew8La.js → stata-RifEDtNO.js} +1 -1
  109. package/dist/web/assets/{surrealql-C0LIGqRx.js → surrealql-DGRQa5Lm.js} +1 -1
  110. package/dist/web/assets/{svelte-CfTy8CGF.js → svelte-w9Hb12aM.js} +1 -1
  111. package/dist/web/assets/system-monitor-tab-CuVVp2wt.js +1 -0
  112. package/dist/web/assets/{tab-store-CcLQfu8H.js → tab-store-vn0viMOP.js} +1 -1
  113. package/dist/web/assets/{templ-V5H1Sbfy.js → templ-BpUwjJXV.js} +1 -1
  114. package/dist/web/assets/{terminal-tab-CK3lX-0Y.js → terminal-tab-DrSqSrdX.js} +2 -2
  115. package/dist/web/assets/{tex-C3H3uMZf.js → tex-DJFSsuTD.js} +1 -1
  116. package/dist/web/assets/tool-cards-CtE_JnF-.js +7 -0
  117. package/dist/web/assets/treemap-KZPCXAKY-CZwuSCtA.js +1 -0
  118. package/dist/web/assets/{ts-tags-7AXgG5YS.js → ts-tags-vp9Qvx2O.js} +1 -1
  119. package/dist/web/assets/{twig-BSyS38T3.js → twig-CoazxjRB.js} +1 -1
  120. package/dist/web/assets/{use-blob-url-CpyRr7Cx.js → use-blob-url-DdXgVqfz.js} +1 -1
  121. package/dist/web/assets/use-is-mobile-CE6AamG6.js +1 -0
  122. package/dist/web/assets/{use-monaco-theme-Jj2OxkAE.js → use-monaco-theme-BvzqffqR.js} +1 -1
  123. package/dist/web/assets/{vendor-mermaid-DGOXKrJC.js → vendor-mermaid-DPpYkrMf.js} +193 -193
  124. package/dist/web/assets/{video-preview-BOHxkwKG.js → video-preview-DxdyVATR.js} +1 -1
  125. package/dist/web/assets/{vue-C4d_br9u.js → vue-CnshsiXd.js} +1 -1
  126. package/dist/web/assets/{vue-html-CGdoz4vW.js → vue-html-CZshynFp.js} +1 -1
  127. package/dist/web/assets/{vue-vine-CqNolQlN.js → vue-vine-C5gtp_T1.js} +1 -1
  128. package/dist/web/assets/{xml-UmCmu-Od.js → xml-BEGJasgj.js} +1 -1
  129. package/dist/web/assets/{xsl-DJG6USGh.js → xsl-DXpRLjYk.js} +1 -1
  130. package/dist/web/index.html +22 -20
  131. package/dist/web/monacoeditorwork/css.worker.bundle.js +122 -122
  132. package/dist/web/monacoeditorwork/editor.worker.bundle.js +78 -78
  133. package/dist/web/monacoeditorwork/html.worker.bundle.js +110 -110
  134. package/dist/web/monacoeditorwork/json.worker.bundle.js +108 -108
  135. package/dist/web/monacoeditorwork/ts.worker.bundle.js +81 -81
  136. package/dist/web/sw.js +1 -1
  137. package/docs/journal/binary-self-upgrade-260724.md +66 -0
  138. package/nul/docs/claude-agent-sdk-reference.md +780 -0
  139. package/nul/docs/code-standards.md +1080 -0
  140. package/nul/docs/codebase-summary.md +916 -0
  141. package/nul/docs/deployment-guide.md +702 -0
  142. package/nul/docs/design-guidelines.md +767 -0
  143. package/nul/docs/extension-development-guide.md +629 -0
  144. package/nul/docs/journals/260414-1400-ext-git-graph-port-complete.md +147 -0
  145. package/nul/docs/journals/260414-1452-git-graph-faithful-port.md +144 -0
  146. package/nul/docs/journals/260414-1810-git-graph-ui-improvements-complete.md +261 -0
  147. package/nul/docs/journals/260414-2001-bundled-extensions.md +219 -0
  148. package/nul/docs/journals/260415-frontend-memory-optimization.md +73 -0
  149. package/nul/docs/lessons-learned.md +70 -0
  150. package/nul/docs/project-changelog.md +574 -0
  151. package/nul/docs/project-overview-pdr.md +205 -0
  152. package/nul/docs/project-roadmap.md +222 -0
  153. package/nul/docs/system-architecture.md +1961 -0
  154. package/package.json +1 -1
  155. package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
  156. package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
  157. package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
  158. package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
  159. package/spike-group-channel.mjs +156 -0
  160. package/spike-group-chat.mjs +181 -0
  161. package/src/server/routes/group-chat.ts +118 -9
  162. package/src/services/group-chat/agent-runner.ts +15 -2
  163. package/src/services/group-chat/context-window.ts +15 -0
  164. package/src/services/group-chat/group-chat.service.ts +178 -79
  165. package/src/services/group-chat/group-chat.store.ts +30 -0
  166. package/src/services/group-chat/responder-router.ts +110 -0
  167. package/src/services/group-chat/transcript-archive.ts +18 -0
  168. package/src/services/group-chat/turn-engine.ts +183 -105
  169. package/src/services/jsonl-transcript-parser.ts +36 -0
  170. package/src/types/group-chat-ws.ts +2 -2
  171. package/src/types/group-chat.ts +33 -4
  172. package/src/web/components/group-chat/group-chat-tab.tsx +109 -14
  173. package/src/web/components/group-chat/group-create-dialog.tsx +10 -3
  174. package/src/web/components/group-chat/group-full-transcript-view.tsx +9 -8
  175. package/src/web/components/group-chat/group-member-edit-dialog.tsx +108 -0
  176. package/src/web/components/group-chat/group-member-roster.tsx +51 -23
  177. package/src/web/components/group-chat/group-message-item.tsx +45 -26
  178. package/src/web/components/group-chat/group-transcript-messages.tsx +126 -0
  179. package/src/web/components/layout/cloud-share-popover.tsx +10 -2
  180. package/src/web/components/layout/mobile-drawer-tab-bar.tsx +10 -0
  181. package/src/web/components/layout/mobile-drawer.tsx +26 -9
  182. package/src/web/components/layout/nav-section-rail.tsx +8 -2
  183. package/src/web/components/layout/upgrade-button.tsx +33 -11
  184. package/src/web/hooks/use-group-chat.ts +8 -1
  185. package/src/web/lib/api-group-chat.ts +47 -4
  186. package/src/web/lib/sidebar-tabs/tab-registry.ts +3 -1
  187. package/dist/web/assets/architecture-PBZL5I3N-NAS99xy0.js +0 -1
  188. package/dist/web/assets/chat-tab-Bh6l253v.js +0 -18
  189. package/dist/web/assets/click-outside-container-DXZVmhaX.js +0 -1
  190. package/dist/web/assets/code-editor-B7F-d4DK.js +0 -10
  191. package/dist/web/assets/data-grid-overlay-editor-CUlFsD-D.js +0 -1
  192. package/dist/web/assets/database-viewer-5oNTPgjF.js +0 -1
  193. package/dist/web/assets/dist-BsziT-tR.js +0 -11
  194. package/dist/web/assets/esm-CjVeOTNQ.js +0 -2
  195. package/dist/web/assets/gitGraph-HDMCJU4V-B4I3L4Sf.js +0 -1
  196. package/dist/web/assets/glide-data-grid-7vB1SNne.js +0 -138
  197. package/dist/web/assets/group-chat-tab-CNECY-zg.js +0 -1
  198. package/dist/web/assets/index-D2G6kmTs.js +0 -50
  199. package/dist/web/assets/index-DCmrZnq0.css +0 -2
  200. package/dist/web/assets/info-3K5VOQVL-CBbbOe3C.js +0 -1
  201. package/dist/web/assets/input-24Nf_edC.js +0 -1
  202. package/dist/web/assets/keybindings-store-D8Cppv4w.js +0 -1
  203. package/dist/web/assets/notification-store-DOGxkWih.js +0 -1
  204. package/dist/web/assets/packet-RMMSAZCW-fr8-QSTF.js +0 -1
  205. package/dist/web/assets/pie-UPGHQEXC-Biu7_Pbb.js +0 -1
  206. package/dist/web/assets/postgres-viewer-B23xTCSs.js +0 -3
  207. package/dist/web/assets/radar-KQ55EAFF-CMtNRpK6.js +0 -1
  208. package/dist/web/assets/settings-tab-D5hAA1bY.js +0 -1
  209. package/dist/web/assets/sparkles-2ii4lR7b.js +0 -1
  210. package/dist/web/assets/sqlite-viewer-DW9f2Hqj.js +0 -1
  211. package/dist/web/assets/system-monitor-tab-B5f4pgdX.js +0 -1
  212. package/dist/web/assets/treemap-KZPCXAKY-ZYVFjoaN.js +0 -1
  213. package/dist/web/assets/use-websocket-DrDBgIWU.js +0 -1
  214. /package/dist/web/assets/{abap-BZ3J5hF3.js → abap-wT6fgqwv.js} +0 -0
  215. /package/dist/web/assets/{actionscript-3-CkyGfT-8.js → actionscript-3-CqcHpPYj.js} +0 -0
  216. /package/dist/web/assets/{ada-CxNLBoe7.js → ada-DWE3Hn4E.js} +0 -0
  217. /package/dist/web/assets/{andromeeda-BPN5rsDz.js → andromeeda-DpQ-y-Jt.js} +0 -0
  218. /package/dist/web/assets/{apache-C1F5wHL6.js → apache-LRTUP4r3.js} +0 -0
  219. /package/dist/web/assets/{apex-BaNixdO-.js → apex-DwVeH5_h.js} +0 -0
  220. /package/dist/web/assets/{api-client-Dvzcc_EO.js → api-client-BK4NPNoY.js} +0 -0
  221. /package/dist/web/assets/{applescript-Cl_pdcch.js → applescript-DyQiO9JU.js} +0 -0
  222. /package/dist/web/assets/{apply-theme-ORrEdHKT.js → apply-theme-DxKsrDLA.js} +0 -0
  223. /package/dist/web/assets/{ara-B6UAE7M2.js → ara-Cf-OWd2S.js} +0 -0
  224. /package/dist/web/assets/{asciidoc-D9c9Twki.js → asciidoc-gocbKcVK.js} +0 -0
  225. /package/dist/web/assets/{asm-CNmtv7Y9.js → asm-C3meb5HY.js} +0 -0
  226. /package/dist/web/assets/{aurora-x-C9z-NyzR.js → aurora-x-BYcXaCIg.js} +0 -0
  227. /package/dist/web/assets/{awk-BfLHEnKa.js → awk-BcT6nIdN.js} +0 -0
  228. /package/dist/web/assets/{ayu-dark-Bn7trkt_.js → ayu-dark-CLZPoccg.js} +0 -0
  229. /package/dist/web/assets/{ayu-light-Dpya9hPf.js → ayu-light-CTyRQdS2.js} +0 -0
  230. /package/dist/web/assets/{ayu-mirage-Cc0jfABD.js → ayu-mirage-DjqfqZdo.js} +0 -0
  231. /package/dist/web/assets/{ballerina-BtiCmN7T.js → ballerina-BCARR-zK.js} +0 -0
  232. /package/dist/web/assets/{bat-tmFM76zR.js → bat-_yaRjWOb.js} +0 -0
  233. /package/dist/web/assets/{beancount-BjPqRrcH.js → beancount-BPESBMS9.js} +0 -0
  234. /package/dist/web/assets/{berry-D0SQBxN2.js → berry-BSLE-Sf8.js} +0 -0
  235. /package/dist/web/assets/{bibtex-CkjRWQKr.js → bibtex-CvUWWCVx.js} +0 -0
  236. /package/dist/web/assets/{bicep-Bhq28Cxc.js → bicep--vcqqALZ.js} +0 -0
  237. /package/dist/web/assets/{bird2-DFGInYb3.js → bird2-Clclqgh6.js} +0 -0
  238. /package/dist/web/assets/{c-CP8cB4k_.js → c-CSC2LwTp.js} +0 -0
  239. /package/dist/web/assets/{c3-oRytyeWo.js → c3-Cl1_jUnm.js} +0 -0
  240. /package/dist/web/assets/{cadence-Inf1rGb7.js → cadence-BwAD7vSC.js} +0 -0
  241. /package/dist/web/assets/{catppuccin-frappe-DAzribQo.js → catppuccin-frappe-hr0HKoFX.js} +0 -0
  242. /package/dist/web/assets/{catppuccin-latte-B6Y_mCCQ.js → catppuccin-latte-DXEIYlFO.js} +0 -0
  243. /package/dist/web/assets/{catppuccin-macchiato-COLbYqVL.js → catppuccin-macchiato-B2zST7sA.js} +0 -0
  244. /package/dist/web/assets/{catppuccin-mocha-DKWaML1B.js → catppuccin-mocha-CvrdnYv9.js} +0 -0
  245. /package/dist/web/assets/{chevron-right-BBc6ATtm.js → chevron-right-DeUue2aK.js} +0 -0
  246. /package/dist/web/assets/{circle-question-mark-CveWaCux.js → circle-question-mark-PaJgx-3d.js} +0 -0
  247. /package/dist/web/assets/{clarity-_ZLLrrsX.js → clarity-BeQd5TQD.js} +0 -0
  248. /package/dist/web/assets/{clojure-DWGVCg_P.js → clojure-Csdo0vb_.js} +0 -0
  249. /package/dist/web/assets/{cmake-Cwh3mug7.js → cmake-Cf0q7ddg.js} +0 -0
  250. /package/dist/web/assets/{code-7ZAlTvsm.js → code-TekEnDFM.js} +0 -0
  251. /package/dist/web/assets/{codeowners-BdV6CFYi.js → codeowners-CUEzlC7R.js} +0 -0
  252. /package/dist/web/assets/{codeql-NvupDIDf.js → codeql-DxHyogQt.js} +0 -0
  253. /package/dist/web/assets/{common-lisp-B-vtBh5k.js → common-lisp-WLb-tAda.js} +0 -0
  254. /package/dist/web/assets/{coq-M8-FTfiZ.js → coq-DFtMD6Wn.js} +0 -0
  255. /package/dist/web/assets/{csharp-B7Ugdtd-.js → csharp-DEnvXVjs.js} +0 -0
  256. /package/dist/web/assets/{css-86k3Z-YA.js → css-DMPpCfkZ.js} +0 -0
  257. /package/dist/web/assets/{csv-BX5XYhfH.js → csv-DTSgNSaP.js} +0 -0
  258. /package/dist/web/assets/{csv-parser-d56Fzpwc.js → csv-parser-B_xNn07y.js} +0 -0
  259. /package/dist/web/assets/{cue-B7099gQa.js → cue-BEmVIZmd.js} +0 -0
  260. /package/dist/web/assets/{cypher-D99mWVIu.js → cypher-CncQVhvU.js} +0 -0
  261. /package/dist/web/assets/{d-CFE8oQwh.js → d-BzUSBVex.js} +0 -0
  262. /package/dist/web/assets/{dark-plus-BEeeDwdg.js → dark-plus-mysFNRq2.js} +0 -0
  263. /package/dist/web/assets/{dart-HVSWGnI5.js → dart-BBu3nkcE.js} +0 -0
  264. /package/dist/web/assets/{database-BLht7BVM.js → database-COYAMZaw.js} +0 -0
  265. /package/dist/web/assets/{dax-DjDgSJkh.js → dax-DcLVz9_9.js} +0 -0
  266. /package/dist/web/assets/{desktop-B5A3i7J1.js → desktop-DS2PdvoU.js} +0 -0
  267. /package/dist/web/assets/{diff-CpTrlaE9.js → diff-aUYk5Qys.js} +0 -0
  268. /package/dist/web/assets/{dist-BSCgJs-V.js → dist-Dxl3dqhC.js} +0 -0
  269. /package/dist/web/assets/{docker-xBhmJeHj.js → docker-12Lj1QUD.js} +0 -0
  270. /package/dist/web/assets/{dotenv-DKKhLEv5.js → dotenv-D-P4bzvl.js} +0 -0
  271. /package/dist/web/assets/{dracula-CVwQuzra.js → dracula-C-eRNn4o.js} +0 -0
  272. /package/dist/web/assets/{dracula-soft-CG6mB-lf.js → dracula-soft-CBB1BI7O.js} +0 -0
  273. /package/dist/web/assets/{dream-maker-SC-IdYY3.js → dream-maker-C_j5A0r7.js} +0 -0
  274. /package/dist/web/assets/{edit-diff-preview-C50i1H63.js → edit-diff-preview-CRMu-6r1.js} +0 -0
  275. /package/dist/web/assets/{emacs-lisp-CIBFq6W8.js → emacs-lisp-W54LT7rh.js} +0 -0
  276. /package/dist/web/assets/{everforest-dark-odRT_lec.js → everforest-dark-B_ISUDeh.js} +0 -0
  277. /package/dist/web/assets/{everforest-light-or1Voqjl.js → everforest-light-CNUYa354.js} +0 -0
  278. /package/dist/web/assets/{fennel-tQd1z3iu.js → fennel-DK82-oso.js} +0 -0
  279. /package/dist/web/assets/{file-exclamation-point-C-lL0g_E.js → file-exclamation-point-DBEC-Kst.js} +0 -0
  280. /package/dist/web/assets/{fish-DSuZQG0k.js → fish-CbJVJzQj.js} +0 -0
  281. /package/dist/web/assets/{fluent-D7xI8a8e.js → fluent-Cug5cOL1.js} +0 -0
  282. /package/dist/web/assets/{fortran-free-form-BlAtcPd3.js → fortran-free-form-amHz32Zw.js} +0 -0
  283. /package/dist/web/assets/{gdscript-VsEQXBPm.js → gdscript-t_G6VYpv.js} +0 -0
  284. /package/dist/web/assets/{gdshader-iqHMOdwW.js → gdshader-DqZaHh4E.js} +0 -0
  285. /package/dist/web/assets/{genie-C4XU4g1a.js → genie-CIJtFlZK.js} +0 -0
  286. /package/dist/web/assets/{gherkin-C4nfQzAB.js → gherkin-CalidqLY.js} +0 -0
  287. /package/dist/web/assets/{github-dark-B_pbG3CC.js → github-dark-BG2xX0wa.js} +0 -0
  288. /package/dist/web/assets/{github-dark-default-kFbx7C95.js → github-dark-default-tDp_EOBs.js} +0 -0
  289. /package/dist/web/assets/{github-dark-dimmed-CpVfQEqs.js → github-dark-dimmed-DlSfPwW2.js} +0 -0
  290. /package/dist/web/assets/{github-dark-high-contrast-DYKqQwZh.js → github-dark-high-contrast-qZM7j5KB.js} +0 -0
  291. /package/dist/web/assets/{github-light-gEYBmKaj.js → github-light-CnvWTiyb.js} +0 -0
  292. /package/dist/web/assets/{github-light-default-DVHfMPQ2.js → github-light-default-Dy6OAt2Q.js} +0 -0
  293. /package/dist/web/assets/{github-light-high-contrast-ClVJDu-q.js → github-light-high-contrast-1BHQCOPl.js} +0 -0
  294. /package/dist/web/assets/{gleam-BLaPu7ft.js → gleam-D-2cpXVX.js} +0 -0
  295. /package/dist/web/assets/{gn-BKgerUyI.js → gn-C1cC4xLc.js} +0 -0
  296. /package/dist/web/assets/{gnuplot-cqJuEFb-.js → gnuplot-2Gp459mV.js} +0 -0
  297. /package/dist/web/assets/{go-B2EHdyD8.js → go-BA1q0q8h.js} +0 -0
  298. /package/dist/web/assets/{groovy-DdImoj8s.js → groovy-BlIa-VfI.js} +0 -0
  299. /package/dist/web/assets/{gruvbox-dark-hard-DlwstAds.js → gruvbox-dark-hard-BMIwVwaJ.js} +0 -0
  300. /package/dist/web/assets/{gruvbox-dark-medium-CiYEd1vd.js → gruvbox-dark-medium-DxfuBW3n.js} +0 -0
  301. /package/dist/web/assets/{gruvbox-dark-soft-C-wEa4h4.js → gruvbox-dark-soft-_NSslDDi.js} +0 -0
  302. /package/dist/web/assets/{gruvbox-light-hard-BqYmfna-.js → gruvbox-light-hard-CP5MIsL9.js} +0 -0
  303. /package/dist/web/assets/{gruvbox-light-medium-CxmfalT2.js → gruvbox-light-medium-BTMursH0.js} +0 -0
  304. /package/dist/web/assets/{gruvbox-light-soft-DGWXXMCB.js → gruvbox-light-soft-Bv6zFoVX.js} +0 -0
  305. /package/dist/web/assets/{haskell-H_C_IuVb.js → haskell-Da8UeSv-.js} +0 -0
  306. /package/dist/web/assets/{haxe-CGNSMpeZ.js → haxe-mcKlcxBa.js} +0 -0
  307. /package/dist/web/assets/{hcl-B7bSTSQf.js → hcl-BdZcx5JX.js} +0 -0
  308. /package/dist/web/assets/{hjson-DlJ-glQZ.js → hjson-pFXYbN4t.js} +0 -0
  309. /package/dist/web/assets/{hlsl-CehW5SJN.js → hlsl-Z0II0KR8.js} +0 -0
  310. /package/dist/web/assets/{horizon-Beabcz2d.js → horizon-CufN8DyP.js} +0 -0
  311. /package/dist/web/assets/{horizon-bright-BC87RXPa.js → horizon-bright-5qoQVyIY.js} +0 -0
  312. /package/dist/web/assets/{houston-Da7RFwUy.js → houston-DOFkQwep.js} +0 -0
  313. /package/dist/web/assets/{hy-m1H70w19.js → hy-BVbDMDcG.js} +0 -0
  314. /package/dist/web/assets/{imba-MExFsdAA.js → imba-DRM6LLS5.js} +0 -0
  315. /package/dist/web/assets/{ini-CJy_zmwy.js → ini-2KCnNvmz.js} +0 -0
  316. /package/dist/web/assets/{java-DqDFvJBH.js → java-BmvH-Ou1.js} +0 -0
  317. /package/dist/web/assets/{javascript-C3Wyv22X.js → javascript-B7VhU1Yc.js} +0 -0
  318. /package/dist/web/assets/{json-DnGBw_DZ.js → json-X1pNk0n7.js} +0 -0
  319. /package/dist/web/assets/{json5-CRN-zoN4.js → json5-CJeEJPTg.js} +0 -0
  320. /package/dist/web/assets/{jsonc-CKRUZNRo.js → jsonc-C1haTBsf.js} +0 -0
  321. /package/dist/web/assets/{jsonl-CGfD6FrH.js → jsonl-wQ8-AJgs.js} +0 -0
  322. /package/dist/web/assets/{jsonnet-nbFuDj0o.js → jsonnet-BrEjY3Xh.js} +0 -0
  323. /package/dist/web/assets/{jssm-D0ShzIqD.js → jssm-C6LgYbOs.js} +0 -0
  324. /package/dist/web/assets/{jsx-D27hbRbs.js → jsx-B2cfD_Fb.js} +0 -0
  325. /package/dist/web/assets/{kanagawa-dragon-Ov3f8K0T.js → kanagawa-dragon-6UCcJpLw.js} +0 -0
  326. /package/dist/web/assets/{kanagawa-lotus-CLyOqh-g.js → kanagawa-lotus-DOmfpsRg.js} +0 -0
  327. /package/dist/web/assets/{kanagawa-wave-Kj3dzabH.js → kanagawa-wave-CpxmPE7N.js} +0 -0
  328. /package/dist/web/assets/{kdl-DFF58Gu4.js → kdl-BrLEivmb.js} +0 -0
  329. /package/dist/web/assets/{kotlin-BM4PKaB4.js → kotlin-BO2FUnDB.js} +0 -0
  330. /package/dist/web/assets/{kusto-DrvHLCv5.js → kusto-Cev1yiq9.js} +0 -0
  331. /package/dist/web/assets/{laserwave-Db6i6ZkO.js → laserwave-BlEkf-eH.js} +0 -0
  332. /package/dist/web/assets/{lean-D0hEjzwk.js → lean-BLS3Xk2w.js} +0 -0
  333. /package/dist/web/assets/{less-BEj4npGG.js → less-BXmcsqcq.js} +0 -0
  334. /package/dist/web/assets/{lib-CBdlQ75W.js → lib-CxSBdrd7.js} +0 -0
  335. /package/dist/web/assets/{light-plus-DLIIbDea.js → light-plus-DS6zriYl.js} +0 -0
  336. /package/dist/web/assets/{llvm-DMt6umsO.js → llvm-C_wLnJgX.js} +0 -0
  337. /package/dist/web/assets/{log-BopvdtPW.js → log-Cg8pvmWi.js} +0 -0
  338. /package/dist/web/assets/{logo-CYSUFPFR.js → logo-C9-kEvPW.js} +0 -0
  339. /package/dist/web/assets/{luau-XC611HNO.js → luau-NwaGugfZ.js} +0 -0
  340. /package/dist/web/assets/{make-BMYZIfBj.js → make-DBpJE-Z8.js} +0 -0
  341. /package/dist/web/assets/{markdown-BLza5nvF.js → markdown-B7ZTAu7B.js} +0 -0
  342. /package/dist/web/assets/{material-theme-Uw27UfJW.js → material-theme-BsXH-Mss.js} +0 -0
  343. /package/dist/web/assets/{material-theme-darker-dfqt8XBY.js → material-theme-darker-CW9OlIeY.js} +0 -0
  344. /package/dist/web/assets/{material-theme-lighter-CPtBTblV.js → material-theme-lighter-D2PAh0Kw.js} +0 -0
  345. /package/dist/web/assets/{material-theme-ocean-BfZgVqC-.js → material-theme-ocean-Vz6DBVi3.js} +0 -0
  346. /package/dist/web/assets/{material-theme-palenight-DAZoVYg8.js → material-theme-palenight-D-GleP3G.js} +0 -0
  347. /package/dist/web/assets/{matlab-cSzmquiW.js → matlab-C7MYlMSn.js} +0 -0
  348. /package/dist/web/assets/{mdx-Dq0kW5VM.js → mdx-FkOOX3Dq.js} +0 -0
  349. /package/dist/web/assets/{mermaid-DoIKF0yS.js → mermaid-C_9qw5it.js} +0 -0
  350. /package/dist/web/assets/{min-dark-DyraimDU.js → min-dark-BowNvxk2.js} +0 -0
  351. /package/dist/web/assets/{min-light-Co9cbcUv.js → min-light-x8oWUmbL.js} +0 -0
  352. /package/dist/web/assets/{mipsasm-ph6cKgHn.js → mipsasm-Dmi1AZOT.js} +0 -0
  353. /package/dist/web/assets/{mojo-BBT0XwmY.js → mojo-C6z7mry2.js} +0 -0
  354. /package/dist/web/assets/{monokai-IP0T5Rtg.js → monokai-BQ4e_Hn0.js} +0 -0
  355. /package/dist/web/assets/{moonbit-B8cogNXl.js → moonbit-CEeNIoB4.js} +0 -0
  356. /package/dist/web/assets/{move-DkY26NtM.js → move-bALfKUa7.js} +0 -0
  357. /package/dist/web/assets/{narrat-rBs3byG0.js → narrat-DX4JlAWT.js} +0 -0
  358. /package/dist/web/assets/{nextflow-groovy-DkO9wMLP.js → nextflow-groovy-CKQWtRkO.js} +0 -0
  359. /package/dist/web/assets/{night-owl-jVR4lFji.js → night-owl-D4PQd726.js} +0 -0
  360. /package/dist/web/assets/{night-owl-light-fBYJ7s3U.js → night-owl-light-BQo_YHll.js} +0 -0
  361. /package/dist/web/assets/{nix-WX9oavu6.js → nix-B1jThkGj.js} +0 -0
  362. /package/dist/web/assets/{nord-Cf7G21Pu.js → nord-35quHUKo.js} +0 -0
  363. /package/dist/web/assets/{nushell-DQdzcJ1H.js → nushell-L6DbJTuL.js} +0 -0
  364. /package/dist/web/assets/{objective-c-JSO2uvZ-.js → objective-c-CTZ4bR2U.js} +0 -0
  365. /package/dist/web/assets/{objective-cpp-CZMGJ9Fb.js → objective-cpp-Dm1YDIdA.js} +0 -0
  366. /package/dist/web/assets/{ocaml-C4S4NSDo.js → ocaml-B3n__LGy.js} +0 -0
  367. /package/dist/web/assets/{odin-Y2jXCgVq.js → odin-DmqZ8n3i.js} +0 -0
  368. /package/dist/web/assets/{one-dark-pro-dVIxuoJY.js → one-dark-pro-16_UaUig.js} +0 -0
  369. /package/dist/web/assets/{one-light-BQ1IKfD1.js → one-light-B-GGjWn5.js} +0 -0
  370. /package/dist/web/assets/{openscad-Bddw4I3z.js → openscad-DTFB9Sj6.js} +0 -0
  371. /package/dist/web/assets/{pascal-BKVXrzC1.js → pascal-RcT1dQYN.js} +0 -0
  372. /package/dist/web/assets/{pkl-BTd-YRsO.js → pkl-Dr4yLQ_o.js} +0 -0
  373. /package/dist/web/assets/{plastic-eiGvBIxV.js → plastic-hp2Nry0R.js} +0 -0
  374. /package/dist/web/assets/{plsql-C290tieP.js → plsql-pFcO4WZ0.js} +0 -0
  375. /package/dist/web/assets/{po-DyDwh0tx.js → po-BkZ0_HvY.js} +0 -0
  376. /package/dist/web/assets/{poimandres-B87zc_g-.js → poimandres-BcTrxj7f.js} +0 -0
  377. /package/dist/web/assets/{polar-Cdub1YMT.js → polar-DHK3q8FF.js} +0 -0
  378. /package/dist/web/assets/{postcss-BcI_3K0v.js → postcss-Bv7WzijA.js} +0 -0
  379. /package/dist/web/assets/{powerquery-OdMrkJSe.js → powerquery-DpaU_hW9.js} +0 -0
  380. /package/dist/web/assets/{powershell-C8auT6xg.js → powershell-_Rqc0MGP.js} +0 -0
  381. /package/dist/web/assets/{prisma-DIbVv8PA.js → prisma-wyegE8us.js} +0 -0
  382. /package/dist/web/assets/{prolog-DbTOH3Ld.js → prolog-DspHCURv.js} +0 -0
  383. /package/dist/web/assets/{proto-C4Cq2dCD.js → proto-BOBiNGf5.js} +0 -0
  384. /package/dist/web/assets/{puppet-DJp3uqum.js → puppet-DfLvV8h2.js} +0 -0
  385. /package/dist/web/assets/{purescript-CLsV4rPU.js → purescript-BY5ZSOZy.js} +0 -0
  386. /package/dist/web/assets/{python-2gBtEza2.js → python-B758mMeg.js} +0 -0
  387. /package/dist/web/assets/{qmldir-DfhULcua.js → qmldir-C75bpHvy.js} +0 -0
  388. /package/dist/web/assets/{qss-DK--VTTV.js → qss-DcLTlbLd.js} +0 -0
  389. /package/dist/web/assets/{r-BArBO2Sa.js → r-D0G_Y1P5.js} +0 -0
  390. /package/dist/web/assets/{racket-5mijHsVy.js → racket-DTye_5qn.js} +0 -0
  391. /package/dist/web/assets/{raku-ir0suElk.js → raku-uJXBXkV0.js} +0 -0
  392. /package/dist/web/assets/{react-J9g6e3Rq.js → react-CorNPdie.js} +0 -0
  393. /package/dist/web/assets/{red-DSecpIOT.js → red-rs3HE3re.js} +0 -0
  394. /package/dist/web/assets/{reg-Dp30FusS.js → reg-DkTIaX7a.js} +0 -0
  395. /package/dist/web/assets/{regexp-DXJnEM_6.js → regexp-4TLSs4_m.js} +0 -0
  396. /package/dist/web/assets/{rel-Dr483ozj.js → rel-B0jumCjt.js} +0 -0
  397. /package/dist/web/assets/{resolve-theme-DJORYzKu.js → resolve-theme-CCoakF2E.js} +0 -0
  398. /package/dist/web/assets/{riscv-ZfBy5IA1.js → riscv-DtaWMlo0.js} +0 -0
  399. /package/dist/web/assets/{ron-ZJ_CljGP.js → ron-BCPxwJD6.js} +0 -0
  400. /package/dist/web/assets/{rose-pine-CcW_eJ6G.js → rose-pine-CNryoqGi.js} +0 -0
  401. /package/dist/web/assets/{rose-pine-dawn-v2l_UF-j.js → rose-pine-dawn-C-gJOQVP.js} +0 -0
  402. /package/dist/web/assets/{rose-pine-moon-CNXkwf3D.js → rose-pine-moon-BdXSXpZh.js} +0 -0
  403. /package/dist/web/assets/{rosmsg-BMYMVW84.js → rosmsg-CPG8X-D5.js} +0 -0
  404. /package/dist/web/assets/{rust-BR-zJh5q.js → rust-CxfW3ePx.js} +0 -0
  405. /package/dist/web/assets/{sass-BukPOBFz.js → sass-D-7bxo_L.js} +0 -0
  406. /package/dist/web/assets/{save-DO5xjW95.js → save-BM4p9_9n.js} +0 -0
  407. /package/dist/web/assets/{scala-DUFY7D6D.js → scala-DyUsfHNc.js} +0 -0
  408. /package/dist/web/assets/{scheme-Dl-dNNxQ.js → scheme-ROgrwiO-.js} +0 -0
  409. /package/dist/web/assets/{sdbl-DdmlQhia.js → sdbl-B1EAQWpp.js} +0 -0
  410. /package/dist/web/assets/{shellscript-UyhrvGcd.js → shellscript-HhmB_Ufy.js} +0 -0
  411. /package/dist/web/assets/{shield-check-m2QzZTuZ.js → shield-check-C3qYSU8a.js} +0 -0
  412. /package/dist/web/assets/{shield-off-DNn7VzJe.js → shield-off-D5tU7gQT.js} +0 -0
  413. /package/dist/web/assets/{slack-dark-Cv6Szr-q.js → slack-dark-DnmSY72G.js} +0 -0
  414. /package/dist/web/assets/{slack-ochin-V6Ii3lAm.js → slack-ochin-q97gHjcd.js} +0 -0
  415. /package/dist/web/assets/{smalltalk-BUCv5G91.js → smalltalk-B-1waXvA.js} +0 -0
  416. /package/dist/web/assets/{snazzy-light-B67a78qi.js → snazzy-light-C8yWDN2g.js} +0 -0
  417. /package/dist/web/assets/{solarized-dark-ccWnfYyA.js → solarized-dark-ClVDEMJZ.js} +0 -0
  418. /package/dist/web/assets/{solarized-light-C3WyRO5I.js → solarized-light-Bts6CUIP.js} +0 -0
  419. /package/dist/web/assets/{solidity-BFbRPNi_.js → solidity-DYxwp0om.js} +0 -0
  420. /package/dist/web/assets/{splunk-zdpwCJLE.js → splunk-jK6-Sr06.js} +0 -0
  421. /package/dist/web/assets/{sql-B2IPUsfz.js → sql-DPpd8aUS.js} +0 -0
  422. /package/dist/web/assets/{ssh-config-Co4cXifq.js → ssh-config-Bimb9LVr.js} +0 -0
  423. /package/dist/web/assets/{stylus-CmI75XY8.js → stylus-B2DgJRJw.js} +0 -0
  424. /package/dist/web/assets/{swift-Dfks9YQI.js → swift-ChEH2nFL.js} +0 -0
  425. /package/dist/web/assets/{synthwave-84-B3LERzNS.js → synthwave-84-DwSLbgAm.js} +0 -0
  426. /package/dist/web/assets/{system-verilog-BFvldiwl.js → system-verilog-DoVBMhJ8.js} +0 -0
  427. /package/dist/web/assets/{systemd-Cu4Vvgbu.js → systemd--Ux4VAYD.js} +0 -0
  428. /package/dist/web/assets/{table-CAVmgQMT.js → table-Di8pv2Y_.js} +0 -0
  429. /package/dist/web/assets/{talonscript-Bnq32pUB.js → talonscript-DQNx9nak.js} +0 -0
  430. /package/dist/web/assets/{tasl-Nwe2K3J1.js → tasl-Bwy_Y9uD.js} +0 -0
  431. /package/dist/web/assets/{tcl-zOnpywrl.js → tcl-Drea-2jA.js} +0 -0
  432. /package/dist/web/assets/{terraform-Bc9Vj-n3.js → terraform-4rS5HoFk.js} +0 -0
  433. /package/dist/web/assets/{tokyo-night-9_KyM8M2.js → tokyo-night-C9MqaxIn.js} +0 -0
  434. /package/dist/web/assets/{toml-ByH-fxOY.js → toml-tSgOSv42.js} +0 -0
  435. /package/dist/web/assets/{tsv-DrCnDClP.js → tsv-BmL4O1Zx.js} +0 -0
  436. /package/dist/web/assets/{tsx-B8LafSYr.js → tsx-BwzeA880.js} +0 -0
  437. /package/dist/web/assets/{turtle-DuyP_QCJ.js → turtle-2DYvssFL.js} +0 -0
  438. /package/dist/web/assets/{typescript-BTBJb5RD.js → typescript-ZC-vonSh.js} +0 -0
  439. /package/dist/web/assets/{typespec-DdOFo7M5.js → typespec-DkCEO45F.js} +0 -0
  440. /package/dist/web/assets/{typst-LYvnBWQu.js → typst-DAZdb2n6.js} +0 -0
  441. /package/dist/web/assets/{utils-CTg5uAYR.js → utils-CSCvNZxE.js} +0 -0
  442. /package/dist/web/assets/{v-BuBYA1_x.js → v-B_wsb4C1.js} +0 -0
  443. /package/dist/web/assets/{vala-vRIBYYe3.js → vala-BDBNS784.js} +0 -0
  444. /package/dist/web/assets/{vb-DwGi-IYM.js → vb-CuOoJSSa.js} +0 -0
  445. /package/dist/web/assets/{vendor-xterm-i6SHFTfU.js → vendor-xterm-CImj6i6Z.js} +0 -0
  446. /package/dist/web/assets/{verilog-6B1X4G2-.js → verilog-BCcOvOcc.js} +0 -0
  447. /package/dist/web/assets/{vesper-Dw1y_Ae7.js → vesper-vN8CREK5.js} +0 -0
  448. /package/dist/web/assets/{vhdl-DK8JwBzJ.js → vhdl-CI8PoqeM.js} +0 -0
  449. /package/dist/web/assets/{viml-BTKIEIqm.js → viml-B66dNP1B.js} +0 -0
  450. /package/dist/web/assets/{vitesse-black-BqqolhEg.js → vitesse-black-0bGIaCfD.js} +0 -0
  451. /package/dist/web/assets/{vitesse-dark-B9JL5WQA.js → vitesse-dark-Dk-RSXq-.js} +0 -0
  452. /package/dist/web/assets/{vitesse-light-DYJKj2se.js → vitesse-light-BUsA5RhG.js} +0 -0
  453. /package/dist/web/assets/{vyper-D-jDI3WH.js → vyper-dNodzEa8.js} +0 -0
  454. /package/dist/web/assets/{wasm-1-GlNdpk.js → wasm-BDxaNPCj.js} +0 -0
  455. /package/dist/web/assets/{wasm-BBW4WmT2.js → wasm-d6SE2_qm.js} +0 -0
  456. /package/dist/web/assets/{wenyan-B6cM7sDO.js → wenyan-D0h8Uz55.js} +0 -0
  457. /package/dist/web/assets/{wgsl-FaHGQgko.js → wgsl-vKs_vsvQ.js} +0 -0
  458. /package/dist/web/assets/{wikitext-DtIyPUrk.js → wikitext-BIWsPJit.js} +0 -0
  459. /package/dist/web/assets/{wit-BMVRif5Y.js → wit-6vmKi2H3.js} +0 -0
  460. /package/dist/web/assets/{wolfram-DQsCGohn.js → wolfram-zoNg6F1a.js} +0 -0
  461. /package/dist/web/assets/{x-C2VSAp7O.js → x-BsFLg-T8.js} +0 -0
  462. /package/dist/web/assets/{yaml-C-Va56Gt.js → yaml-W95qP6-B.js} +0 -0
  463. /package/dist/web/assets/{zenscript-DdobKGI-.js → zenscript-BxircxDx.js} +0 -0
  464. /package/dist/web/assets/{zig-vqDFwj6q.js → zig-DD79WQtz.js} +0 -0
@@ -0,0 +1,147 @@
1
+ # Git-Graph Extension Port — Phase 1-4 Complete
2
+
3
+ **Date**: 2026-04-14 14:00
4
+ **Severity**: Medium (architectural pattern addition)
5
+ **Component**: @ppm/ext-git-graph (new extension), process:spawn RPC handler, extension RPC security
6
+ **Status**: Resolved (phases 1-4), Phase 5 deferred to v0.2
7
+
8
+ ## What Happened
9
+
10
+ Completed port of vscode-git-graph concepts to PPM as a self-contained extension. Full implementation of phases 1-4 per plan at `plans/260414-1132-ext-git-graph-port/plan.md`:
11
+
12
+ 1. **Extension scaffold** — Created `packages/ext-git-graph/` with clean-room rewrite (not copy-paste from vscode-git-graph)
13
+ 2. **Git log parsing** — Implemented `GitLogParser` to parse `git log --pretty=fuller --numstat` into SVG-compatible commit graph (7 source files)
14
+ 3. **RPC infrastructure** — Added `process:spawn` handler to PPM core enabling extensions to execute subprocesses from Worker threads
15
+ 4. **Security hardening** — Fixed critical vulnerability in process:spawn with command allowlist + CWD sandboxing + env var filtering
16
+ 5. **Tests** — 62 new tests, all 1269 suite passing, zero TypeScript regressions
17
+
18
+ Committed as `451811c` with 2304 lines across 14 files.
19
+
20
+ ## The Brutal Truth
21
+
22
+ This was **exciting but risky**. We shipped a brand-new capability (process spawning from extensions) and initially did it with zero security guardrails. The security review caught it immediately, but that's a pattern we need to kill: **never add execution capabilities without threat modeling first.**
23
+
24
+ The temptation to just make git work from the webview was strong enough that we cut corners on the design phase. We got lucky the code reviewer was paranoid. Next time it won't be.
25
+
26
+ ## Technical Details
27
+
28
+ ### Process Spawn Handler (src/services/extension-rpc-handlers.ts)
29
+
30
+ Added `process:spawn` RPC handler enabling extensions to execute commands. Initial implementation had **no restrictions** — any command, any args, any env.
31
+
32
+ ```typescript
33
+ // BEFORE: Wide open execution
34
+ const { command, args, options } = message.payload;
35
+ const process = spawn(command, args, options);
36
+
37
+ // AFTER: Allowlist + constraints
38
+ const ALLOWED_COMMANDS = new Set(['git', 'node', 'bun', 'npx', 'sqlite3']);
39
+ if (!ALLOWED_COMMANDS.has(command)) {
40
+ throw new Error(`Command not allowed: ${command}`);
41
+ }
42
+ // CWD sandboxed to project directory
43
+ // ANTHROPIC_API_KEY and auth env vars filtered
44
+ ```
45
+
46
+ ### Git Log Parsing (packages/ext-git-graph/src/git-log-parser.ts)
47
+
48
+ Switched from `--stat` to `--numstat` for reliable file change counts. `--stat` produces human-readable output that varies by terminal width; `--numstat` is machine-parseable and deterministic.
49
+
50
+ ```bash
51
+ # Used:
52
+ git log --pretty=fuller --numstat --graph
53
+
54
+ # Output: additions<tab>deletions<tab>filename
55
+ 1 0 src/app.ts
56
+ 14 2 package.json
57
+ ```
58
+
59
+ ### Security Fixes
60
+
61
+ **Root cause**: Added new capability without threat model. Extensions running in Worker threads got full subprocess execution permission.
62
+
63
+ **Fix**:
64
+ - Command allowlist (git, node, bun, npx, sqlite3 only)
65
+ - CWD constrained to project directory (no filesystem escape)
66
+ - Env var blocklist (ANTHROPIC_API_KEY, OPENAI_API_KEY, GITHUB_TOKEN, etc.)
67
+ - No shell interpolation (`{ shell: false }`)
68
+ - Timeout enforced (30s default)
69
+
70
+ ## What We Tried
71
+
72
+ 1. **Direct webview subprocess execution** — Blocked by Bun WebSocket limitations, webviews can't spawn processes
73
+ 2. **Defer to v0.2** — Initial plan (phases 1-4 in one sprint was ambitious)
74
+ 3. **Generic "any command" RPC** — Code review rejected immediately, security concern
75
+ 4. **Allowlist approach** — Accepted, provides extension developers clear expectations
76
+
77
+ ## Root Cause Analysis
78
+
79
+ **Why did we design process:spawn without security guardrails?**
80
+
81
+ 1. **Pressure to ship**: Phase 4 (webview integration) drove implementation speed over design
82
+ 2. **Assumption of trust**: Thought "extensions are trusted code," forgot that extensions can be community-written
83
+ 3. **No threat model**: Skipped asking "what can go wrong?" before coding
84
+ 4. **Copy-paste instinct**: Wanted to make it "work like vscode," forgot PPM runs user code differently (in Workers, not main thread)
85
+
86
+ We got lucky. The code reviewer (rightfully paranoid) caught it. But this is a pattern we need to break: **new capabilities require threat modeling before implementation, not after.**
87
+
88
+ ## Lessons Learned
89
+
90
+ 1. **New execution paths need threat model before code**
91
+ - process:spawn is the second execution handler (after tool execution in SDK provider)
92
+ - Both need documented threat models and allowlist rationale
93
+ - Code review should include security architect, not just functionality check
94
+
95
+ 2. **Allowlist is better than blocklist for subprocess execution**
96
+ - `{ shell: false }` is good but not sufficient (can still exec arbitrary binaries)
97
+ - Command allowlist is explicit and auditable
98
+ - Future: move allowlist to config for self-hosted extensions
99
+
100
+ 3. **--numstat vs --stat for parsing**
101
+ - Machine-readable output first, always
102
+ - Human formatting should be applied on render, not parsing
103
+ - This decision unblocks future work (avatars, statistics)
104
+
105
+ 4. **Phases should be strict — defer aggressively**
106
+ - Phase 5 (avatars, auto-refresh, settings, GPG, multi-repo) deferred to v0.2
107
+ - Shipping 4 phases in one sprint was tight; no time for complexity
108
+ - v0.2 roadmap is now clear (these are committed features)
109
+
110
+ ## Next Steps
111
+
112
+ 1. **Document process:spawn threat model** — Add to `docs/system-architecture.md` (extension security section)
113
+ - Allowed commands and rationale
114
+ - Environment filtering rules
115
+ - Timeout behavior
116
+ - Future: community extension sandboxing
117
+
118
+ 2. **Phase 5 for v0.2** — Deferred features:
119
+ - Avatar rendering in commit nodes (requires image caching)
120
+ - Auto-refresh on file watch (requires debounced git log polling)
121
+ - User preferences (dark mode, node size, graph direction)
122
+ - GPG signature verification (requires gpg in allowlist)
123
+ - Multi-repository support (requires RPC batching)
124
+
125
+ 3. **Extension RPC security audit** — Review other RPC handlers for similar gaps
126
+ - `file:read`, `file:write`, `git:*` handlers
127
+ - Document allowlist for each
128
+ - Add to security review checklist
129
+
130
+ 4. **Extension marketplace trust model** — When we ship ext marketplace (v1.0), need:
131
+ - Permission declaration (like Android APKs)
132
+ - Audit log of extension subprocess calls
133
+ - User warning on suspicious commands
134
+
135
+ ## Files Changed
136
+
137
+ - `packages/ext-git-graph/` — 7 source files (2047 lines)
138
+ - `src/services/extension-rpc-handlers.ts` — Added process:spawn handler
139
+ - `packages/vscode-compat/src/process.ts` — ProcessService API
140
+ - 4 new test files, 62 new tests
141
+ - `packages/ext-git-graph/tests/git-log-parser.test.ts` — 28 parsing tests
142
+
143
+ **Commit**: `451811c` | **Lines**: +2304 / -12 | **Tests**: 1269 passing (62 new)
144
+
145
+ ---
146
+
147
+ **Written by**: Engineering diarist | **Next review**: Before Phase 5 planning (v0.2 scope meeting)
@@ -0,0 +1,144 @@
1
+ # Git Graph Algorithm Port: SVG Rendering Faithful to vscode-git-graph
2
+
3
+ **Date**: 2026-04-14 14:52
4
+ **Severity**: High
5
+ **Component**: ext-git-graph WebView
6
+ **Status**: Resolved
7
+
8
+ ## What Happened
9
+
10
+ Completed faithful port of vscode-git-graph `graph.ts` SVG rendering algorithm into PPM's ext-git-graph extension. Previous implementation was a from-scratch rewrite that stripped out critical features entirely: no continuous lines between commits, no merge routing logic, no HEAD/stash styling, no shadow lines for depth.
11
+
12
+ The port restored full feature parity with the original while adapting for PPM's commit model and mobile layout requirements.
13
+
14
+ ## The Brutal Truth
15
+
16
+ This was frustrating because the previous implementation _looked_ functional at first glance — it rendered some boxes and lines — but fundamentally misunderstood how git graph visualization works. When you have multiple branches interleaving, you can't just draw independent vertical lines per commit. You need intelligent path routing to:
17
+ - Avoid visual collisions at merge points
18
+ - Reuse column assignments across the graph
19
+ - Transition smoothly between lane positions with curves
20
+ - Visually distinguish shadow (background) vs active (foreground) paths
21
+
22
+ Spending days on a rewrite that missed all this was inefficient. Should have deconstructed vscode-git-graph from day one instead of guessing.
23
+
24
+ The real kick is that the algorithm's complexity made sense only after reading the original code. No amount of visual inspection of the original output would have revealed why it worked — the graph determinism is in the column allocation and path-finding, not just drawing code.
25
+
26
+ ## Technical Details
27
+
28
+ ### Porting Scope
29
+
30
+ **Implemented faithfully:**
31
+ - `GBranch`, `GVertex`, `GEdge` data structures
32
+ - `determinePath(from, to, availableColours)` — core routing algorithm
33
+ - `graphGetAvailableColour(graph, row, col)` — column reuse across rows
34
+ - Bézier curve transitions with `d = 0.8 × gridY` control point offset
35
+ - Shadow lines: thicker, semi-transparent paths behind colored paths
36
+ - HEAD node: hollow circle with branch label
37
+ - Stash node: nested circles (outer for stash, inner for commit)
38
+ - Commit dot centering in column with optional border ring
39
+
40
+ **Intentionally skipped (not needed for PPM):**
41
+ - `onlyFollowFirstParent` filter mode
42
+ - `UNCOMMITTED` virtual commit node
43
+ - Circle-at-checkout indicator (PPM uses different HEAD semantics)
44
+ - `--all` ref filtering (PPM loads fixed commit range)
45
+
46
+ **Adapted for PPM:**
47
+ - Stash detection: `state.stashes` Set instead of `commit.stash` boolean (PPM model)
48
+ - Grid config: `{ x: 16, y: 28, gridX: 8, gridY: 14 }` — compact for table row height
49
+ - Mobile SVG: viewport width detection, gridY 28→44px on mobile for touch targets
50
+
51
+ ### Bugs Fixed During Implementation
52
+
53
+ **Critical: Dot Misalignment (1px per row cumulative)**
54
+
55
+ `.col-graph` had explicit `height: 28px` styling. Parent had `box-sizing: border-box` with `1px border`. This created:
56
+ ```
57
+ Parent min-height: 28px (includes border)
58
+ → Content box: 27px (28 - 1px border)
59
+ Row parent expanded to 29px to fit
60
+ SVG used 28px intervals
61
+ Result: 1px drift cumulative, visible misalignment by row 10+
62
+ ```
63
+
64
+ Fix: Removed explicit `height`, let flexbox handle alignment. SVG uses computed row height.
65
+
66
+ **High: Path Scope Rejection**
67
+
68
+ Extensions couldn't execute git in user project directories. `assertSafePath` in `extension-rpc-handlers.ts` only allowed CWD and `~/.ppm/extensions/`. User projects were rejected.
69
+
70
+ ```typescript
71
+ // Before
72
+ if (cwd !== CWD && !cwd.startsWith(PPM_EXTENSIONS_DIR)) {
73
+ throw new Error("Path not allowed");
74
+ }
75
+
76
+ // After
77
+ if (!isAllowedPath(cwd, [CWD, PPM_EXTENSIONS_DIR, ...registeredProjectPaths])) {
78
+ throw new Error("Path not allowed");
79
+ }
80
+ ```
81
+
82
+ **Medium: XSS in Detail Panel**
83
+
84
+ Parent hashes and file status inserted into innerHTML without escaping. User with special chars in file path (e.g., `test<img onerror="alert('xss')">`) would execute.
85
+
86
+ Fix: Used `textContent` for data, `innerHTML` for formatted markup only.
87
+
88
+ **Medium: Regex Ordering in formatCommitMessage**
89
+
90
+ URL regex ran before hash regex. URLs like `https://github.com/user/repo/commit/abc123` would partially match hash pattern, creating nested HTML tags.
91
+
92
+ ```typescript
93
+ // Before: [urlRegex, hashRegex]
94
+ // "https://github.com/.../commit/abc123" → hash regex matched "abc123" inside URL match
95
+
96
+ // After: [hashRegex, urlRegex]
97
+ // Hash captured first, URL captures remaining text
98
+ ```
99
+
100
+ ## What We Tried
101
+
102
+ 1. **Incremental line-by-line port** — too manual, errors in transcription
103
+ 2. **Type-driven porting** — created interfaces matching vscode-git-graph `GVertex`, `GBranch` — this worked; types guided implementation
104
+ 3. **Test-driven validation** — wrote tests for `determinePath` against known graph structures from vscode-git-graph repo — caught routing bugs early
105
+ 4. **Visual diff** — side-by-side video of original vs PPM output, frame-by-frame comparison at merge points — identified misaligned dots
106
+
107
+ ## Root Cause Analysis
108
+
109
+ The previous rewrite failed because:
110
+ 1. **Assumed simplicity** — git graph looked like "connect the dots" instead of a constrained layout problem
111
+ 2. **No algorithm study** — didn't read vscode-git-graph source before coding; reverse-engineered from output only
112
+ 3. **Incomplete feature list** — shadow lines, HEAD styling, merge routing logic were invisible until you needed them
113
+ 4. **No test fixtures** — built without reference commits to validate against
114
+
115
+ The SVG dot misalignment was a cascade: explicit height forcing a mismatch between CSS row size and SVG coordinate system. `box-sizing: border-box` made the issue subtle — 28px height looked right until it didn't.
116
+
117
+ Path scope was security-by-assumption — extending permissions to extensions should have been part of original design, not a bandage.
118
+
119
+ ## Lessons Learned
120
+
121
+ 1. **Port, don't rewrite** — When reimplementing an algorithm from proven code, read the original first. Guessing costs more than transcription.
122
+
123
+ 2. **Constrained layout problems need algorithm study** — Graph layout, routing, and column allocation aren't intuitive. Trace through examples before coding.
124
+
125
+ 3. **CSS height mismatches are invisible at first** — When CSS-defined height meets SVG coordinate system, they must align explicitly. Don't rely on browser rendering to fix 1px errors; they compound.
126
+
127
+ 4. **Security permissions evolve with features** — Extensions need project access; this wasn't a later concern, it was a design gap. Build permission model upfront.
128
+
129
+ 5. **Test against canonical output** — Generate test cases from the original algorithm, not from guessed behavior. Side-by-side comparison is necessary, not optional.
130
+
131
+ ## Next Steps
132
+
133
+ 1. **Monitor visual regression** — Run vscode-git-graph test repo against PPM output quarterly to catch algorithm drift
134
+ 2. **Document grid config** — Add comments explaining `gridY: 28` choice and mobile override, so future maintainers understand dependencies
135
+ 3. **Consider performance** — Profile SVG rendering with 500+ commits; may need canvas or virtualization for large repos
136
+ 4. **Security audit** — Review all extension RPC handlers for similar path scope issues
137
+
138
+ ---
139
+
140
+ **Commit**: `24ad424` feat(ext-git-graph): port vscode-git-graph algorithm with faithful SVG rendering
141
+
142
+ **Tests**: 62/62 passing (4 test files)
143
+
144
+ **Review**: 3 critical, 2 high, 4 medium findings — all critical/high addressed before merge
@@ -0,0 +1,261 @@
1
+ # Git Graph UI Improvements: Five Phases of Refinement Complete
2
+
3
+ **Date**: 2026-04-14 18:15
4
+ **Severity**: High
5
+ **Component**: ext-git-graph WebView UI, tab rendering
6
+ **Status**: Resolved
7
+
8
+ ## What Happened
9
+
10
+ Completed a comprehensive 5-phase UI improvement cycle for the ext-git-graph extension, plus discovered and fixed critical cross-cutting issues in tab rendering. The work spans 1600+ lines of webview HTML/CSS/JS and 600+ lines of extension host TypeScript.
11
+
12
+ **Phases completed:**
13
+ 1. CSS alignment with PPM design system (button styles, removed visual cruft)
14
+ 2. Resizable graph columns and custom branch filtering
15
+ 3. Tree/list toggle for file hierarchy visualization
16
+ 4. Fetch button + auto-fetch with configurable intervals
17
+ 5. Uncommitted changes workflow (per-file stage/unstage/discard + inline commit)
18
+
19
+ **Additional fixes discovered during integration:**
20
+ - Fallback guards for unknown DraggableTab types preventing React crashes
21
+ - Path traversal validation in webview file operations
22
+ - Exit code checking in discard operations
23
+ - Search offset handling for virtual uncommitted row
24
+
25
+ Total modified files: 9 (webview-html.ts, extension.ts, types.ts, 4 layout components, 1 test file)
26
+ Test suite: 1551/1569 passing (5 pre-existing failures unrelated to changes)
27
+
28
+ ## The Brutal Truth
29
+
30
+ This work felt like piecing together a puzzle with half the picture in JavaScript and half in TypeScript. The webview is a complete HTML/CSS/JS sandbox isolated in an iframe — all 1600+ lines of UI code live inline in `getWebviewHtml()`. Every interaction—resize, filter, toggle, fetch, commit—has to round-trip through `postMessage` to the extension host, which spawns git processes and posts results back.
31
+
32
+ The frustrating part: the webview and extension host speak different languages semantically. The webview cares about immediate visual feedback and "did this feel responsive?" The host cares about exit codes and process stderr. We crossed this boundary at least 20 times, and small mismatches (like not checking exit codes in discard, or not handling virtual row offsets in search) went unnoticed until code review.
33
+
34
+ The React crashes from unknown tab types felt particularly stupid in hindsight. The tab system has a discriminated union (`type: "file" | "webview"`) but the 4 layout components used loose `if (tab.type === "file")` checks. Add a new webview type (like `"git-graph"`) and 3 of 4 components silently fall through. No TypeScript error, no runtime warning—just a mysterious "Cannot read property X" in the console.
35
+
36
+ The security issue (path traversal in webview file operations) was a reminder that sandboxing doesn't mean permissionless. The webview could request arbitrary files from the system if given a malicious path. We added `assertSafeFilePaths()` to validate that paths don't escape the project root, but this should have been the initial design, not a code review catch.
37
+
38
+ ## Technical Details
39
+
40
+ ### Phase 1: CSS Quick Fixes
41
+ - **Button styles**: Matched PPM design system (6px border-radius, CSS transitions, active press states). Previously buttons had 4px radius and no feedback.
42
+ - **Row dividers removed**: Commit list had subtle 1px borders between rows. Removed for cleaner table feel.
43
+ - **Graph line shadows removed**: SVG lines had `drop-shadow(0 1px 2px rgba(0,0,0,0.1))` creating visual noise. Removed.
44
+
45
+ **Files**: webview-html.ts (CSS section, ~50 lines)
46
+
47
+ ### Phase 2: Resize & Filter
48
+ - **Resizable graph column**: Added `pointer-based` drag handle on graph/details boundary. Column width stored in webview state and persisted to `globalState` (VSCode Memento API).
49
+ ```typescript
50
+ onPointerDown on resize handle → track pointer move → clamp width to [200, 60vw] → postMessage to extension
51
+ ```
52
+ - **Custom branch filter**: Replaced native `<select>` with dropdown component. Allows searching/filtering branches, updates commit list in real-time.
53
+
54
+ **Files**: webview-html.ts (drag handler, filter UI, ~120 lines)
55
+
56
+ ### Phase 3: Tree/List Toggle
57
+ - **Toggle button** in file list header switches between tree view (hierarchical) and list view (flat).
58
+ - **buildFileTree()** algorithm: Reconstructs directory hierarchy from flat file list. Time complexity O(n log n) with Set lookups.
59
+ ```
60
+ Input: ["src/app.ts", "src/util/helper.ts", "src/util/types.ts"]
61
+ Output: {
62
+ type: "dir", name: "src", children: [
63
+ {type: "file", name: "app.ts", ...},
64
+ {type: "dir", name: "util", children: [...]}
65
+ ]
66
+ }
67
+ ```
68
+ - **State caching**: Remembers last viewed commit detail and restores tree/list toggle state when viewing same commit again.
69
+
70
+ **Files**: webview-html.ts (buildFileTree + state cache, ~180 lines)
71
+
72
+ ### Phase 4: Fetch & Auto-fetch
73
+ - **Fetch button**: Manual git fetch in toolbar. Shows spinner, displays result count ("Fetched 3 new commits").
74
+ - **Auto-fetch setting**: Toggle + interval config (default 60s). Implemented via VSCode `setInterval` in extension host. Persisted via `globalState.update()`.
75
+ ```typescript
76
+ if (autoFetchEnabled && autoFetchInterval > 0) {
77
+ setInterval(() => spawnGit(["fetch"]), autoFetchInterval * 1000);
78
+ }
79
+ ```
80
+
81
+ **Files**: extension.ts (auto-fetch loop, ~60 lines), webview-html.ts (fetch button UI, ~30 lines)
82
+
83
+ ### Phase 5: Uncommitted Changes Workflow
84
+ The most complex phase. Added full staging, unstaging, discard, and inline commit workflow:
85
+
86
+ - **Per-file actions**: Buttons for stage, unstage, discard, open (open file in editor). Uses `git add`, `git rm`, `git checkout --` commands.
87
+ - **Section-level batch actions**: "Stage All Unstaged" / "Unstage All Staged" in section headers.
88
+ - **Inline commit textarea + button**: Commit message input directly in webview. Posts to extension host which runs `git commit -m "..."`.
89
+ - **Right-click context menu** on uncommitted row:
90
+ - Stash: `git stash push -- <file>`
91
+ - Reset: `git reset HEAD -- <file>`
92
+ - Clean: `git clean -f -- <file>` (untracked only)
93
+ - Open: Opens file in editor
94
+
95
+ **Files**: webview-html.ts (40-line event handler for context menu, 80-line per-file action handlers, 50-line commit UI)
96
+
97
+ ### Critical Cross-Cutting Fixes
98
+
99
+ **1. DraggableTab React Crash**
100
+
101
+ Symptom: Opening a webview (like git-graph) crashes the tab bar component.
102
+
103
+ Root cause: 4 layout components (`tab-bar.tsx`, `mobile-nav.tsx`, `tab-content.tsx`, `editor-panel.tsx`) assumed all tabs are either type `"file"` or `"webview"`. Added a new webview type (`"git-graph"`) broke this assumption.
104
+
105
+ ```typescript
106
+ // Before (tab-bar.tsx)
107
+ if (tab.type === "file") { return <FileTabLabel /> }
108
+ if (tab.type === "webview") { return <WebviewTabLabel /> }
109
+ // Missing: "git-graph" type falls through → returns undefined → React crash
110
+
111
+ // After
112
+ if (tab.type === "file") { return <FileTabLabel /> }
113
+ if (tab.type === "webview") { return <WebviewTabLabel /> }
114
+ return <GenericTabLabel icon={tab.icon} /> // Fallback
115
+ ```
116
+
117
+ **Impact**: Any new webview type instantly breaks 3 components. Fixed by adding discriminated union validation at type level + runtime fallback.
118
+
119
+ **Files**: tab-bar.tsx, mobile-nav.tsx, tab-content.tsx, editor-panel.tsx (1 line fallback each)
120
+
121
+ **2. Path Traversal in Webview File Operations**
122
+
123
+ Symptom: Code review flagged that webview could request arbitrary files via postMessage.
124
+
125
+ Example attack: `{ command: "openFile", path: "../../../../etc/passwd" }`
126
+
127
+ Fix: Added `assertSafeFilePaths()` in extension RPC handler:
128
+ ```typescript
129
+ function assertSafeFilePaths(paths: string[], projectRoot: string) {
130
+ paths.forEach(p => {
131
+ const resolved = resolve(projectRoot, p);
132
+ if (!resolved.startsWith(projectRoot)) {
133
+ throw new Error(`Path escape detected: ${p}`);
134
+ }
135
+ });
136
+ }
137
+ ```
138
+
139
+ **Impact**: Webview now validates all paths before sending. Extension host validates again for defense-in-depth.
140
+
141
+ **Files**: src/services/extension-rpc-handlers.ts (~20 lines validation), webview-html.ts (call site)
142
+
143
+ **3. handleDiscard Exit Code Checking**
144
+
145
+ Symptom: Git discard (checkout/clean) fails silently. User discards file expecting change, nothing happens. No error displayed.
146
+
147
+ Root cause: Command handler didn't check `process.exitCode`. Treated failed command as success.
148
+
149
+ ```typescript
150
+ // Before
151
+ const { stderr } = await spawnGit(["checkout", "--", filePath]);
152
+ if (!stderr) postMessage({ command: "discardSuccess", filePath }); // Bug: stderr empty !== success
153
+
154
+ // After
155
+ const { exitCode, stderr } = await spawnGit(["checkout", "--", filePath]);
156
+ if (exitCode !== 0) {
157
+ postMessage({ command: "discardFailed", error: stderr });
158
+ } else {
159
+ postMessage({ command: "discardSuccess", filePath });
160
+ }
161
+ ```
162
+
163
+ **Impact**: Discard now correctly reports errors (permission denied, file locked, etc.).
164
+
165
+ **Files**: extension.ts (handleDiscard method, ~8 lines)
166
+
167
+ **4. Search Offset Handling**
168
+
169
+ Symptom: Filtering commits by hash offset when viewing uncommitted changes. Search finds wrong commit because the virtual "Uncommitted" row shifts indices.
170
+
171
+ Root cause: Commit list has optional virtual row at index 0 if `state.hasUncommitted`. Search didn't account for this.
172
+
173
+ ```typescript
174
+ const displayCommits = getDisplayCommits(state); // Includes virtual row if uncommitted
175
+ const searchIndex = displayCommits.findIndex(c => c.hash === searchQuery);
176
+ // searchIndex now correct for display, maps back to actual commit list via offset
177
+ ```
178
+
179
+ **Impact**: Search now finds correct commit even when uncommitted row is present.
180
+
181
+ **Files**: webview-html.ts (search handler, ~12 lines)
182
+
183
+ ## What We Tried
184
+
185
+ 1. **Incremental phase rollout** — Completed each phase fully before starting next (5 separate code reviews) — this worked; isolated scope made each review manageable.
186
+
187
+ 2. **Webview state machine** — Initially tried Redux-like pattern for webview state; too heavy. Switched to simple `{ ...state, field: newValue }` mutations — faster to implement.
188
+
189
+ 3. **Resize debouncing** — First attempt throttled resize events; felt sluggish. Changed to immediate visual update (visual feedback), debounced persistence (save to globalState) — users perceived smooth interaction.
190
+
191
+ 4. **Tree building optimization** — First buildFileTree() was O(n²) with nested array searches. Switched to Set-based parent lookup — O(n log n).
192
+
193
+ 5. **Context menu library vs inline** — Evaluated using `@radix-ui/context-menu` for right-click menu; too heavy for webview bundle size. Built inline context menu with event listeners (~80 lines) — acceptable.
194
+
195
+ ## Root Cause Analysis
196
+
197
+ The work was comprehensive but scattered across two distinct domains (webview HTML/JS vs extension TypeScript), making cross-boundary bugs invisible until integration testing.
198
+
199
+ **Why did 4 components need identical fallback fixes?**
200
+ The tab system was designed with a closed type set (`"file" | "webview"`). Adding new webview variants required changes in 4 places. This suggests the abstraction is too granular; should have a single `renderTabLabel(tab)` function, not per-component logic.
201
+
202
+ **Why did path traversal make it past initial review?**
203
+ The webview's file operations felt internal/safe (only used for opening files in detail panel). But the principle of "never trust webview input" got lost during Phase 3 feature work. Security checks should be architectural, not features.
204
+
205
+ **Why didn't exit code checking exist from the start?**
206
+ The discard operation was added late, after fetch (which was more obviously success/failure). The assumption was "if we got here, git ran successfully" — wrong. Any system command needs exit code validation.
207
+
208
+ ## Lessons Learned
209
+
210
+ 1. **Webview + extension host is a two-language problem** — Changes can't be purely "UI" or purely "backend". Validate assumptions at the boundary early (phase 1, not phase 5).
211
+
212
+ 2. **Closed type unions have a scalability limit** — After N variants, a discriminated union becomes a liability. Consider open-ended dispatch:
213
+ ```typescript
214
+ // Better: single handler function, routes on tab.type
215
+ function renderTabLabel(tab: Tab) { ... }
216
+ ```
217
+
218
+ 3. **Security boundaries must be explicit in architecture** — Don't embed path validation in handlers; define it at the webview/host boundary upfront. One `assertSafeFilePaths` call, not scattered checks.
219
+
220
+ 4. **State machine ≠ complex state** — Simple object spread mutations are fine for webview local state. Redux-like patterns are over-engineering unless you have time-travel debugging needs.
221
+
222
+ 5. **Visual feedback beats semantic correctness** — Users prefer smooth resize + debounced save over semantically "pure" delayed feedback. Responsive ≠ instantaneous, but responsiveness > consistency.
223
+
224
+ 6. **Inline context menus are viable in sandboxed environments** — No need to pull in Radix UI for webview; DOM event handlers are fast enough for right-click menus.
225
+
226
+ ## Next Steps
227
+
228
+ 1. **Refactor tab rendering** (next sprint) — Extract `renderTabLabel(tab)` function to eliminate duplicate fallback logic. File ownership: renderer team.
229
+
230
+ 2. **Security audit on all webview handlers** (this week) — Review 8 other webviews in ext-* extensions for similar path traversal risks. File ownership: security reviewer.
231
+
232
+ 3. **Add exit code tests** (next sprint) — Test suite should validate that git command failures propagate to UI. Currently no tests for failed git operations.
233
+
234
+ 4. **Monitor auto-fetch impact** — 60s default interval may cause performance issues on slow connections. Telemetry point: auto-fetch battery drain on mobile (add to release notes for v0.9.86).
235
+
236
+ 5. **Document webview<->host protocol** (next sprint) — PostMessage API is ad-hoc; needs a schema. Currently each webview reinvents message types. Candidate for shared `WebviewMessage` union type in `src/types/webview-messages.ts`.
237
+
238
+ ---
239
+
240
+ **Commits**:
241
+ - `451811c` feat(ext): add git-graph extension with SVG commit visualization
242
+ - `24ad424` feat(ext-git-graph): port vscode-git-graph algorithm with faithful SVG rendering
243
+ - (UI improvements included in pending changes, awaiting final review)
244
+
245
+ **Tests**: 1551/1569 passing (5 pre-existing failures in unrelated feature tests)
246
+
247
+ **Code Review**: Passed with 3 issues found and fixed:
248
+ - C1: Path traversal — added `assertSafeFilePaths()`
249
+ - H3: Exit code checking — added `exitCode` validation in discard
250
+ - H5: Search offset — fixed virtual row handling in search filter
251
+
252
+ **Files Modified**:
253
+ - `/Users/hienlh/Projects/ppm/packages/ext-git-graph/src/webview-html.ts` (1600+ lines)
254
+ - `/Users/hienlh/Projects/ppm/packages/ext-git-graph/src/extension.ts` (600+ lines)
255
+ - `/Users/hienlh/Projects/ppm/packages/ext-git-graph/src/types.ts`
256
+ - `/Users/hienlh/Projects/ppm/src/web/components/layout/tab-bar.tsx`
257
+ - `/Users/hienlh/Projects/ppm/src/web/components/layout/mobile-nav.tsx`
258
+ - `/Users/hienlh/Projects/ppm/src/web/components/layout/tab-content.tsx`
259
+ - `/Users/hienlh/Projects/ppm/src/web/components/layout/editor-panel.tsx`
260
+ - `/Users/hienlh/Projects/ppm/src/services/extension-rpc-handlers.ts`
261
+ - `/Users/hienlh/Projects/ppm/src/types/extension-messages.ts`