@hienlh/ppm 0.9.85 → 0.9.87

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 (243) hide show
  1. package/260415-0932-git-graph-stash-rebase-conflicts/reports/code-reviewer-260415-1020-stash-rebase-conflicts.md +288 -0
  2. package/260415-0932-git-graph-stash-rebase-conflicts/reports/tester-260415-1020-build-check.md +117 -0
  3. package/260415-1150-ext-silent-failure-debugging/reports/code-reviewer-260415-1159-ext-error-reporting-review.md +205 -0
  4. package/260415-1150-ext-silent-failure-debugging/reports/docs-manager-260415-1206-ext-error-reporting.md +99 -0
  5. package/260415-1150-ext-silent-failure-debugging/reports/tester-260415-1159-extension-error-reporting.md +174 -0
  6. package/CHANGELOG.md +24 -0
  7. package/dist/web/assets/{_basePickBy-D-bUmjma.js → _basePickBy-Bj0dI1ei.js} +1 -1
  8. package/dist/web/assets/{_baseUniq-BnXXIfRB.js → _baseUniq-CyzdZeQH.js} +1 -1
  9. package/dist/web/assets/ai-settings-section-Bo9lCaTd.js +1 -0
  10. package/dist/web/assets/{api-settings-Qi2xRiHa.js → api-settings-CUxg9RE5.js} +1 -1
  11. package/dist/web/assets/{arc-DB9vXGzd.js → arc-CxgHJ7Z4.js} +1 -1
  12. package/dist/web/assets/architecture-PBZL5I3N-DDFO_NKq.js +1 -0
  13. package/dist/web/assets/{architectureDiagram-2XIMDMQ5-BBV25747.js → architectureDiagram-2XIMDMQ5-D16OotsC.js} +1 -1
  14. package/dist/web/assets/arrow-up-I9-21gkR.js +1 -0
  15. package/dist/web/assets/{blockDiagram-WCTKOSBZ-BOTnY2Lq.js → blockDiagram-WCTKOSBZ-Ct57Wtfk.js} +1 -1
  16. package/dist/web/assets/{c4Diagram-IC4MRINW-D7QAUdHD.js → c4Diagram-IC4MRINW-BIymcNsg.js} +1 -1
  17. package/dist/web/assets/channel-wumTB1if.js +1 -0
  18. package/dist/web/assets/chat-tab-R4gKsnxD.js +10 -0
  19. package/dist/web/assets/chevron-right-DY_wImxB.js +1 -0
  20. package/dist/web/assets/{chunk-4BX2VUAB-BnOVw77D.js → chunk-4BX2VUAB-CENmY7Kw.js} +1 -1
  21. package/dist/web/assets/{chunk-55IACEB6-BftA8DxR.js → chunk-55IACEB6-DhZGI1l3.js} +1 -1
  22. package/dist/web/assets/{chunk-7E7YKBS2-B0vnP8v3.js → chunk-7E7YKBS2-DZcnC7Ow.js} +1 -1
  23. package/dist/web/assets/{chunk-7R4GIKGN-Czlaj26D.js → chunk-7R4GIKGN-y8bfHEy-.js} +2 -2
  24. package/dist/web/assets/{chunk-C72U2L5F-DpEbDtMo.js → chunk-C72U2L5F-BHPkfQj2.js} +1 -1
  25. package/dist/web/assets/{chunk-EGIJ26TM-BWXe6lkx.js → chunk-EGIJ26TM-nant2LXl.js} +1 -1
  26. package/dist/web/assets/{chunk-FMBD7UC4-DspqhPfk.js → chunk-FMBD7UC4-Bog4cpN-.js} +1 -1
  27. package/dist/web/assets/{chunk-GEFDOKGD-D6HHRbYk.js → chunk-GEFDOKGD-86LFbsAC.js} +1 -1
  28. package/dist/web/assets/chunk-GLR3WWYH-Re-5eSlQ.js +2 -0
  29. package/dist/web/assets/chunk-HHEYEP7N-C45i5G_3.js +1 -0
  30. package/dist/web/assets/{chunk-JSJVCQXG-BC8wnMwf.js → chunk-JSJVCQXG-23eG9mgt.js} +1 -1
  31. package/dist/web/assets/{chunk-KX2RTZJC-D3VDtyvX.js → chunk-KX2RTZJC-CHj8TnTB.js} +1 -1
  32. package/dist/web/assets/{chunk-KYZI473N-Z-NBw_HS.js → chunk-KYZI473N-gqRLpJ4w.js} +1 -1
  33. package/dist/web/assets/{chunk-L3YUKLVL--RGkEh__.js → chunk-L3YUKLVL-DnSMmNFC.js} +1 -1
  34. package/dist/web/assets/{chunk-MX3YWQON-2B76t_Kx.js → chunk-MX3YWQON-B6g1ZH9X.js} +1 -1
  35. package/dist/web/assets/{chunk-NQ4KR5QH-BekY3tEi.js → chunk-NQ4KR5QH-DX32345Y.js} +1 -1
  36. package/dist/web/assets/{chunk-O4XLMI2P-2CJLfx_1.js → chunk-O4XLMI2P-Vp_V4P-b.js} +1 -1
  37. package/dist/web/assets/{chunk-OZEHJAEY-sug_L09P.js → chunk-OZEHJAEY-lKq2SWjA.js} +1 -1
  38. package/dist/web/assets/{chunk-PQ6SQG4A-_fwPRLQy.js → chunk-PQ6SQG4A-Bik13fTV.js} +1 -1
  39. package/dist/web/assets/{chunk-PU5JKC2W-BUaTFJVQ.js → chunk-PU5JKC2W-DD95Rx35.js} +1 -1
  40. package/dist/web/assets/chunk-QZHKN3VN-N3VXx1VH.js +1 -0
  41. package/dist/web/assets/{chunk-R5LLSJPH-C37xW0vj.js → chunk-R5LLSJPH-dRhXRnrb.js} +1 -1
  42. package/dist/web/assets/{chunk-WL4C6EOR-CCkt_MT6.js → chunk-WL4C6EOR-B1iIvLOG.js} +1 -1
  43. package/dist/web/assets/{chunk-XIRO2GV7-Dz2LBq7Y.js → chunk-XIRO2GV7-DZBoNl1_.js} +1 -1
  44. package/dist/web/assets/{chunk-XPW4576I-DenTbBuj.js → chunk-XPW4576I-CgLyyW03.js} +1 -1
  45. package/dist/web/assets/{chunk-XZSTWKYB-Dbp1nUSQ.js → chunk-XZSTWKYB-DjV8xl5A.js} +1 -1
  46. package/dist/web/assets/{chunk-YBOYWFTD-3OTKowjE.js → chunk-YBOYWFTD-D_ILLe6_.js} +1 -1
  47. package/dist/web/assets/classDiagram-VBA2DB6C-mr-Cb1me.js +1 -0
  48. package/dist/web/assets/classDiagram-v2-RAHNMMFH-BKe8_uda.js +1 -0
  49. package/dist/web/assets/clone--z5KLAuR.js +1 -0
  50. package/dist/web/assets/code-editor-Br0vzTOy.js +8 -0
  51. package/dist/web/assets/columns-2-IeETSfON.js +1 -0
  52. package/dist/web/assets/conflict-editor-BPgCjnNz.js +19 -0
  53. package/dist/web/assets/{cose-bilkent-S5V4N54A-MbmGZnt0.js → cose-bilkent-S5V4N54A-BGNPFv3x.js} +1 -1
  54. package/dist/web/assets/{csv-preview-uZ_7b8I7.js → csv-preview-BZRICDP0.js} +2 -2
  55. package/dist/web/assets/{dagre-CPhI6v-K.js → dagre-CkhlMHnx.js} +1 -1
  56. package/dist/web/assets/{dagre-KLK3FWXG-CmSE-oNj.js → dagre-KLK3FWXG-Cnp996VG.js} +1 -1
  57. package/dist/web/assets/database-CgTomMxt.js +1 -0
  58. package/dist/web/assets/{database-viewer-5xljX0JI.js → database-viewer-DaUoQ-oR.js} +2 -2
  59. package/dist/web/assets/{diagram-E7M64L7V-B5XG3ZT7.js → diagram-E7M64L7V-BZF0tSOr.js} +1 -1
  60. package/dist/web/assets/{diagram-IFDJBPK2-BsP248aX.js → diagram-IFDJBPK2-nUcO8sN8.js} +1 -1
  61. package/dist/web/assets/{diagram-P4PSJMXO-Cna3408N.js → diagram-P4PSJMXO-CW0eCkwC.js} +1 -1
  62. package/dist/web/assets/diff-viewer-BzvK3gAE.js +4 -0
  63. package/dist/web/assets/dist-CM0oD8tQ.js +1 -0
  64. package/dist/web/assets/{erDiagram-INFDFZHY-B7SgktiR.js → erDiagram-INFDFZHY-DSkriYZ9.js} +1 -1
  65. package/dist/web/assets/extension-webview-CGepEw-b.js +3 -0
  66. package/dist/web/assets/{flowDiagram-PKNHOUZH-FOYZZ1OB.js → flowDiagram-PKNHOUZH-CFYAfZBx.js} +1 -1
  67. package/dist/web/assets/{ganttDiagram-A5KZAMGK-CnHVYh9v.js → ganttDiagram-A5KZAMGK-KSn4XAU4.js} +1 -1
  68. package/dist/web/assets/gitGraph-HDMCJU4V-OkvBPi6H.js +1 -0
  69. package/dist/web/assets/{gitGraphDiagram-K3NZZRJ6-0G9XxZay.js → gitGraphDiagram-K3NZZRJ6-BMgjjVys.js} +1 -1
  70. package/dist/web/assets/{graphlib-CNiBwlg_.js → graphlib-BWe1iK_s.js} +1 -1
  71. package/dist/web/assets/index-CKsEzQ4f.js +26 -0
  72. package/dist/web/assets/index-Chf0otez.css +2 -0
  73. package/dist/web/assets/info-3K5VOQVL-BDU2_bYD.js +1 -0
  74. package/dist/web/assets/infoDiagram-LFFYTUFH-Diq4Cyc3.js +2 -0
  75. package/dist/web/assets/input-BHj0veau.js +45 -0
  76. package/dist/web/assets/{isEmpty-CcCb5n2-.js → isEmpty-BfLnxq-B.js} +1 -1
  77. package/dist/web/assets/{ishikawaDiagram-PHBUUO56-D4QCzh5J.js → ishikawaDiagram-PHBUUO56-CiVEvp8o.js} +1 -1
  78. package/dist/web/assets/{journeyDiagram-4ABVD52K-CnHYNfKW.js → journeyDiagram-4ABVD52K-CG_v5Aho.js} +1 -1
  79. package/dist/web/assets/jsx-runtime-BRW_vwa9.js +1 -0
  80. package/dist/web/assets/{kanban-definition-K7BYSVSG-Bh_g3EVu.js → kanban-definition-K7BYSVSG-miB0-_Zq.js} +1 -1
  81. package/dist/web/assets/keybindings-store-D5zgHod8.js +1 -0
  82. package/dist/web/assets/{line-6d3eBADm.js → line-CSuSrJ9J.js} +1 -1
  83. package/dist/web/assets/{linear-cA_2lQy7.js → linear-DFN_MPsw.js} +1 -1
  84. package/dist/web/assets/{markdown-renderer-CZ07F7T6.js → markdown-renderer-DSYnGywb.js} +6 -6
  85. package/dist/web/assets/{mermaid-parser.core-C3kd7JXM.js → mermaid-parser.core-CFdP1Z5_.js} +2 -2
  86. package/dist/web/assets/{mindmap-definition-YRQLILUH-CYiUwhr_.js → mindmap-definition-YRQLILUH-pYPWwASE.js} +1 -1
  87. package/dist/web/assets/{ordinal-XHK5vIzZ.js → ordinal-DpFn432U.js} +1 -1
  88. package/dist/web/assets/packet-RMMSAZCW-BwpIpYB3.js +1 -0
  89. package/dist/web/assets/pie-UPGHQEXC-BPgAfmes.js +1 -0
  90. package/dist/web/assets/{pieDiagram-SKSYHLDU-D0S7jeZA.js → pieDiagram-SKSYHLDU-Dovdlvhu.js} +1 -1
  91. package/dist/web/assets/plus-DQGIb4mQ.js +1 -0
  92. package/dist/web/assets/port-forwarding-tab-vmqDKmk2.js +1 -0
  93. package/dist/web/assets/{postgres-viewer-RldlAO_m.js → postgres-viewer-0lIAosrr.js} +3 -3
  94. package/dist/web/assets/{quadrantDiagram-337W2JSQ-0hNP63hW.js → quadrantDiagram-337W2JSQ-TXe6cU_F.js} +1 -1
  95. package/dist/web/assets/radar-KQ55EAFF-TqxBkWx-.js +1 -0
  96. package/dist/web/assets/refresh-cw-Clk8fdUD.js +1 -0
  97. package/dist/web/assets/{requirementDiagram-Z7DCOOCP-BVnmqFbL.js → requirementDiagram-Z7DCOOCP-CuiiuGS9.js} +1 -1
  98. package/dist/web/assets/{sankeyDiagram-WA2Y5GQK-DVkYdCJb.js → sankeyDiagram-WA2Y5GQK-BbRmhv0t.js} +1 -1
  99. package/dist/web/assets/scroll-area-BpXCNme3.js +1 -0
  100. package/dist/web/assets/{sequenceDiagram-2WXFIKYE-B80s7sOg.js → sequenceDiagram-2WXFIKYE-B2D8IQDb.js} +1 -1
  101. package/dist/web/assets/settings-tab-CMnv1fce.js +1 -0
  102. package/dist/web/assets/{sql-query-editor-CjZ7Z6XL.js → sql-query-editor-Bc2hAwqT.js} +1 -1
  103. package/dist/web/assets/sqlite-viewer-B60MS2Dy.js +1 -0
  104. package/dist/web/assets/square-vBdqj0bF.js +1 -0
  105. package/dist/web/assets/{stateDiagram-RAJIS63D-BPLXgXRR.js → stateDiagram-RAJIS63D-ylr4HxPu.js} +1 -1
  106. package/dist/web/assets/stateDiagram-v2-FVOUBMTO-D6zvxf3M.js +1 -0
  107. package/dist/web/assets/table-Bi27fEaN.js +1 -0
  108. package/dist/web/assets/{terminal-tab-DjzD8GLn.js → terminal-tab-CCJoLstH.js} +2 -2
  109. package/dist/web/assets/text-wrap-D_OmSzhp.js +1 -0
  110. package/dist/web/assets/{timeline-definition-YZTLITO2-fa_51u1X.js → timeline-definition-YZTLITO2-pMv1grvM.js} +1 -1
  111. package/dist/web/assets/trash-2-CNuB-htI.js +1 -0
  112. package/dist/web/assets/treemap-KZPCXAKY-Kck06FKU.js +1 -0
  113. package/dist/web/assets/{use-monaco-theme-D9XFxQuU.js → use-monaco-theme-BJK48EmK.js} +1 -1
  114. package/dist/web/assets/{vennDiagram-LZ73GAT5-kX4jJn6W.js → vennDiagram-LZ73GAT5-C-rkIUbo.js} +1 -1
  115. package/dist/web/assets/x-Dw3TjeY_.js +1 -0
  116. package/dist/web/assets/{xychartDiagram-JWTSCODW-Bzm5lZBs.js → xychartDiagram-JWTSCODW-CtpjAakO.js} +1 -1
  117. package/dist/web/index.html +18 -22
  118. package/dist/web/sw.js +1 -1
  119. package/docs/codebase-summary.md +169 -13
  120. package/docs/extension-development-guide.md +98 -1
  121. package/docs/journals/260414-1400-ext-git-graph-port-complete.md +147 -0
  122. package/docs/journals/260414-1452-git-graph-faithful-port.md +144 -0
  123. package/docs/journals/260414-1810-git-graph-ui-improvements-complete.md +261 -0
  124. package/docs/journals/260414-2001-bundled-extensions.md +219 -0
  125. package/docs/project-changelog.md +123 -21
  126. package/docs/project-roadmap.md +4 -2
  127. package/docs/system-architecture.md +77 -6
  128. package/package.json +1 -1
  129. package/packages/ext-git-graph/package.json +30 -0
  130. package/packages/ext-git-graph/src/extension-integration.test.ts +230 -0
  131. package/packages/ext-git-graph/src/extension-parsers.test.ts +193 -0
  132. package/packages/ext-git-graph/src/extension.ts +921 -0
  133. package/packages/ext-git-graph/src/git-log-parser.test.ts +271 -0
  134. package/packages/ext-git-graph/src/git-log-parser.ts +38 -0
  135. package/packages/ext-git-graph/src/types.ts +192 -0
  136. package/packages/ext-git-graph/src/webview-html.test.ts +142 -0
  137. package/packages/ext-git-graph/src/webview-html.ts +2417 -0
  138. package/packages/vscode-compat/src/index.ts +4 -0
  139. package/packages/vscode-compat/src/process.ts +25 -0
  140. package/packages/vscode-compat/src/window.ts +10 -0
  141. package/src/cli/commands/ext-cmd.ts +3 -1
  142. package/src/server/ws/extensions.ts +34 -4
  143. package/src/services/contribution-registry.ts +14 -1
  144. package/src/services/extension-host-worker.ts +12 -3
  145. package/src/services/extension-manifest.ts +18 -1
  146. package/src/services/extension-rpc-handlers.ts +68 -2
  147. package/src/services/extension.service.ts +63 -9
  148. package/src/types/extension-messages.ts +3 -1
  149. package/src/types/extension.ts +8 -0
  150. package/src/web/components/editor/code-editor.tsx +16 -4
  151. package/src/web/components/editor/conflict-editor.tsx +368 -0
  152. package/src/web/components/extensions/extension-webview.tsx +153 -12
  153. package/src/web/components/layout/command-palette.tsx +41 -17
  154. package/src/web/components/layout/editor-panel.tsx +16 -4
  155. package/src/web/components/layout/mobile-nav.tsx +6 -5
  156. package/src/web/components/layout/tab-bar.tsx +3 -3
  157. package/src/web/components/layout/tab-content.tsx +17 -5
  158. package/src/web/components/settings/keyboard-shortcuts-section.tsx +46 -1
  159. package/src/web/hooks/use-extension-ws.ts +30 -4
  160. package/src/web/hooks/use-global-keybindings.ts +24 -2
  161. package/src/web/hooks/use-url-sync.ts +8 -3
  162. package/src/web/stores/extension-store.ts +8 -0
  163. package/src/web/stores/keybindings-store.ts +2 -3
  164. package/src/web/stores/panel-store.ts +2 -2
  165. package/src/web/stores/panel-utils.ts +6 -2
  166. package/src/web/stores/tab-store.ts +3 -2
  167. package/dist/web/assets/ai-settings-section-D6d-RmR6.js +0 -1
  168. package/dist/web/assets/architecture-PBZL5I3N-DpVzOETR.js +0 -1
  169. package/dist/web/assets/arrow-up-BigIMx-e.js +0 -1
  170. package/dist/web/assets/channel-Cgy1thYT.js +0 -1
  171. package/dist/web/assets/chat-tab-DXBb9Y3U.js +0 -10
  172. package/dist/web/assets/check-ePA3ZvK4.js +0 -1
  173. package/dist/web/assets/chevron-down-EQA06nR-.js +0 -1
  174. package/dist/web/assets/chevron-right-CXzzT44u.js +0 -1
  175. package/dist/web/assets/chunk-GLR3WWYH-CxUl1sdz.js +0 -2
  176. package/dist/web/assets/chunk-HHEYEP7N-DN7ebS2Y.js +0 -1
  177. package/dist/web/assets/chunk-QZHKN3VN-C4La7oLj.js +0 -1
  178. package/dist/web/assets/classDiagram-VBA2DB6C-C3IyfqG-.js +0 -1
  179. package/dist/web/assets/classDiagram-v2-RAHNMMFH-Dcvhz2pb.js +0 -1
  180. package/dist/web/assets/clone--C7Tby8z.js +0 -1
  181. package/dist/web/assets/code-editor-Cr7JrBKC.js +0 -8
  182. package/dist/web/assets/columns-2-BZ9uqssV.js +0 -1
  183. package/dist/web/assets/createLucideIcon-PuMiQgHl.js +0 -1
  184. package/dist/web/assets/database-D1ToEV9d.js +0 -1
  185. package/dist/web/assets/diff-viewer-BBr6e_gb.js +0 -4
  186. package/dist/web/assets/dist-KUoHa6tg.js +0 -1
  187. package/dist/web/assets/extension-webview-B0klBip8.js +0 -3
  188. package/dist/web/assets/eye-CNcBU6Tx.js +0 -1
  189. package/dist/web/assets/git-graph-CDiwGa0g.js +0 -1
  190. package/dist/web/assets/gitGraph-HDMCJU4V-DcPyMEIJ.js +0 -1
  191. package/dist/web/assets/index-CkaCzNgO.css +0 -2
  192. package/dist/web/assets/index-Ic5uTu20.js +0 -26
  193. package/dist/web/assets/info-3K5VOQVL-Dw4O15cw.js +0 -1
  194. package/dist/web/assets/infoDiagram-LFFYTUFH-DFhmsucr.js +0 -2
  195. package/dist/web/assets/input-CcbTF6ih.js +0 -45
  196. package/dist/web/assets/jsx-runtime-R_NjdZtX.js +0 -1
  197. package/dist/web/assets/keybindings-store-CxE6BlG2.js +0 -1
  198. package/dist/web/assets/packet-RMMSAZCW-o3LmdL8H.js +0 -1
  199. package/dist/web/assets/pie-UPGHQEXC-BjNP0M3B.js +0 -1
  200. package/dist/web/assets/plus-Iso5r9vD.js +0 -1
  201. package/dist/web/assets/port-forwarding-tab-BPuSc6pI.js +0 -1
  202. package/dist/web/assets/radar-KQ55EAFF-gDgOiaME.js +0 -1
  203. package/dist/web/assets/refresh-cw-BgQzFNaG.js +0 -1
  204. package/dist/web/assets/scroll-area-i4EZlOl_.js +0 -1
  205. package/dist/web/assets/settings-tab-BzSSN2BQ.js +0 -1
  206. package/dist/web/assets/sqlite-viewer-CoyZOM_Y.js +0 -1
  207. package/dist/web/assets/square-pfn_LYYy.js +0 -1
  208. package/dist/web/assets/stateDiagram-v2-FVOUBMTO-DksQJ7es.js +0 -1
  209. package/dist/web/assets/table-CHv2x_qg.js +0 -1
  210. package/dist/web/assets/tag-Bb_UFXt0.js +0 -1
  211. package/dist/web/assets/text-wrap-D8BbQYTx.js +0 -1
  212. package/dist/web/assets/trash-2-DYCa06CV.js +0 -1
  213. package/dist/web/assets/treemap-KZPCXAKY-DwFqAvnj.js +0 -1
  214. package/dist/web/assets/x-BXecj-16.js +0 -1
  215. package/src/web/components/git/git-graph-branch-label.tsx +0 -124
  216. package/src/web/components/git/git-graph-constants.ts +0 -185
  217. package/src/web/components/git/git-graph-detail.tsx +0 -107
  218. package/src/web/components/git/git-graph-dialog.tsx +0 -72
  219. package/src/web/components/git/git-graph-row.tsx +0 -167
  220. package/src/web/components/git/git-graph-settings-dialog.tsx +0 -104
  221. package/src/web/components/git/git-graph-svg.tsx +0 -54
  222. package/src/web/components/git/git-graph-toolbar.tsx +0 -195
  223. package/src/web/components/git/git-graph.tsx +0 -193
  224. package/src/web/components/git/use-column-resize.ts +0 -33
  225. package/src/web/components/git/use-git-graph.ts +0 -201
  226. /package/dist/web/assets/{api-client-wQbeUyeh.js → api-client-BvxmRZUi.js} +0 -0
  227. /package/dist/web/assets/{array-X0JlPOfd.js → array-BFDiaBgf.js} +0 -0
  228. /package/dist/web/assets/{csv-parser-CElqio6o.js → csv-parser-i7fjqP2H.js} +0 -0
  229. /package/dist/web/assets/{cytoscape.esm-BfIOPvwt.js → cytoscape.esm-C8i2jUzT.js} +0 -0
  230. /package/dist/web/assets/{defaultLocale-B6RGN4id.js → defaultLocale-ZeknFqNe.js} +0 -0
  231. /package/dist/web/assets/{dist-CK1enexV.js → dist-DZmJeHOA.js} +0 -0
  232. /package/dist/web/assets/{init-BmUWJJHz.js → init-0VJVrkRJ.js} +0 -0
  233. /package/dist/web/assets/{isArrayLikeObject-BrCM-iA1.js → isArrayLikeObject-ClzWCpcm.js} +0 -0
  234. /package/dist/web/assets/{katex-xQS_6bNb.js → katex-DR0kdMDv.js} +0 -0
  235. /package/dist/web/assets/{lib-CfWBrYll.js → lib-DSLzfeW0.js} +0 -0
  236. /package/dist/web/assets/{math-CpLFzrfV.js → math-CRc16Nj6.js} +0 -0
  237. /package/dist/web/assets/{path-CoPyR7c2.js → path-INs8XTPH.js} +0 -0
  238. /package/dist/web/assets/{preload-helper-CH6UZRzu.js → preload-helper-mr3rCizq.js} +0 -0
  239. /package/dist/web/assets/{react-j5zqhEum.js → react-0tkk-ztn.js} +0 -0
  240. /package/dist/web/assets/{rough.esm-D5NinLFK.js → rough.esm-eLccZ4OJ.js} +0 -0
  241. /package/dist/web/assets/{sql-completion-provider-D0xutVaK.js → sql-completion-provider-B8uUWWej.js} +0 -0
  242. /package/dist/web/assets/{src-j04igtQ5.js → src-CqyWLlNZ.js} +0 -0
  243. /package/dist/web/assets/{utils-CSCvNZxE.js → utils-DX8jb5qv.js} +0 -0
@@ -1,13 +1,13 @@
1
1
  # PPM Codebase Summary
2
2
 
3
- **Last Updated:** 2026-04-06
4
- **Version:** 0.9.10
3
+ **Last Updated:** 2026-04-15
4
+ **Version:** 0.9.86
5
5
  **Repository:** PPM (Project & Process Manager) — Multi-provider web IDE/project manager with Claude Agent SDK
6
6
 
7
7
  **Core Statistics:**
8
- - **303 files** across CLI, server, web, and test layers
9
- - **490,667 tokens** total codebase size
10
- - **492 passing tests** (13 new tests for provider models API)
8
+ - **366 files** across CLI, server, web, packages, and test layers
9
+ - **885,308 tokens** total codebase size (repomix)
10
+ - **500+ passing tests**
11
11
  - **Tech Stack:** Bun (runtime), Hono (HTTP), React (UI), Claude Agent SDK (AI)
12
12
 
13
13
  ---
@@ -60,9 +60,9 @@ src/
60
60
  │ ├── account.service.ts # Account CRUD & encryption
61
61
  │ ├── upgrade.service.ts # Version checking, installation
62
62
  │ ├── mcp-config.service.ts # MCP server CRUD (list, get, set, remove, import)
63
- │ ├── extension.service.ts # Extension lifecycle, activation, state management
63
+ │ ├── extension.service.ts # Extension lifecycle, activation, state management (bundled + user discovery)
64
64
  │ ├── extension-installer.ts # npm install, symlink, removal
65
- │ ├── extension-manifest.ts # Parse + discover manifests
65
+ │ ├── extension-manifest.ts # Parse manifests + bundled discovery from packages/ext-*
66
66
  │ ├── extension-rpc.ts # RPC channel (request/response/events)
67
67
  │ ├── extension-host-worker.ts # Worker-side extension loading
68
68
  │ ├── contribution-registry.ts # Central registry for commands, views, config
@@ -166,9 +166,10 @@ src/
166
166
  │ │ ├── usage-badge.tsx # Token usage display
167
167
  │ │ ├── attachment-chips.tsx # Display attached files
168
168
  │ │ └── chat-placeholder.tsx # Empty state
169
- │ ├── editor/ # Code editor (800+ LOC, 6 files)
169
+ │ ├── editor/ # Code editor (900+ LOC, 7 files)
170
170
  │ │ ├── code-editor.tsx # Monaco Editor integration (@monaco-editor/react, v2.0+)
171
171
  │ │ ├── diff-viewer.tsx # Monaco diff viewer for git diffs (v2.0+)
172
+ │ │ ├── conflict-editor.tsx # Inline conflict resolution (3-way markers, visual highlighting, v0.9.86+)
172
173
  │ │ ├── editor-breadcrumb.tsx # VSCode-style breadcrumb with nested dropdown
173
174
  │ │ ├── editor-toolbar.tsx # File-type contextual toolbar
174
175
  │ │ ├── csv-preview.tsx # CSV table viewer with @tanstack/react-table
@@ -182,17 +183,17 @@ src/
182
183
  │ │ └── git-placeholder.tsx
183
184
  │ ├── layout/ # Layout components (13 files)
184
185
  │ │ ├── panel-layout.tsx # Main grid layout (react-resizable-panels)
185
- │ │ ├── editor-panel.tsx # Wrapper for tab content within a panel
186
+ │ │ ├── editor-panel.tsx # Wrapper for tab content within a panel (v0.9.85+: fallback guards)
186
187
  │ │ ├── project-bar.tsx # 52px sidebar with project avatars, share popover
187
188
  │ │ ├── project-bottom-sheet.tsx # Mobile project switcher
188
189
  │ │ ├── sidebar.tsx # Left sidebar (Explorer/Git/Database/Settings tabs)
189
- │ │ ├── tab-bar.tsx # Tab bar with icons, connection color display
190
+ │ │ ├── tab-bar.tsx # Tab bar with icons, connection color display (v0.9.85+: fallback guards)
190
191
  │ │ ├── draggable-tab.tsx # Draggable tab with context menu, rename, connection color
191
- │ │ ├── tab-content.tsx # Router for tab content
192
+ │ │ ├── tab-content.tsx # Router for tab content (v0.9.85+: fallback guards)
192
193
  │ │ ├── split-drop-overlay.tsx # Drop zone for tab splitting
193
194
  │ │ ├── command-palette.tsx # Global command palette (Shift+Shift, DB table search)
194
195
  │ │ ├── add-project-form.tsx # Modal form to add projects
195
- │ │ ├── mobile-nav.tsx # Bottom navigation for mobile
196
+ │ │ ├── mobile-nav.tsx # Bottom navigation for mobile (v0.9.85+: fallback guards)
196
197
  │ │ └── mobile-drawer.tsx # Mobile overlay drawer
197
198
  │ ├── database/ # Database management (5 files, 300+ LOC)
198
199
  │ │ ├── database-sidebar.tsx # Sidebar tab container (connection list, form)
@@ -377,6 +378,56 @@ GitStatusPanel refreshes: GET /api/project/:name/git/status
377
378
  UI updates staged/unstaged lists
378
379
  ```
379
380
 
381
+ ### Git Workflow Enhancements (v0.9.86+)
382
+
383
+ **Stash Management:**
384
+ - Toolbar popover lists all stashes (index, abbreviated hash, message)
385
+ - Apply/Pop/Drop actions per stash with visual feedback
386
+ - "Stash Changes" button saves uncommitted work to stash list
387
+ - Stash state integrated into RepoInfo and refreshed on status changes
388
+
389
+ **Conflict Detection & Resolution:**
390
+ - Detects merge/rebase/cherry-pick state from .git sentinel files (MERGE_HEAD, rebase-merge/, CHERRY_PICK_HEAD)
391
+ - Parses git status UU/AA/DD/AU/UA/DU/UD codes for unmerged entries
392
+ - Conflict state banner shows state type, progress (e.g., "3/5" for rebase), and Continue/Skip/Abort actions
393
+ - New `conflict-editor` tab type with Monaco-based visual conflict resolution
394
+ - Parses 3-way conflict markers (<<<<<<, =======, >>>>>>>)
395
+ - Highlights current (green), incoming (blue), and marker lines (gray)
396
+ - Accept buttons for Current / Incoming / Both with automatic save
397
+ - Real-time conflict counter: "N conflicts remaining" → "All resolved"
398
+
399
+ **Rebase from Context Menu:**
400
+ - Right-click commits to open rebase menu
401
+ - Confirmation dialog with branch/target selection
402
+ - Rebase state tracking and progress display during operation
403
+
404
+ **Worktree Management:**
405
+ - Popover UI for listing, creating, removing, pruning worktrees
406
+ - Current worktree highlighted with active badge
407
+ - "Create Worktree Here..." option in commit context menu
408
+ - Auto-add unregistered worktrees as projects with confirmation
409
+ - Branch-already-exists handling with force-replace option
410
+
411
+ ### Tab System Safety (v0.9.85+)
412
+
413
+ All tab routing and rendering components now include fallback guards for unknown tab types:
414
+
415
+ **Components Updated:**
416
+ - `tab-bar.tsx` — Tab item rendering with fallback icon/label
417
+ - `mobile-nav.tsx` — Mobile tab selection with fallback handling
418
+ - `tab-content.tsx` — Content router with "Unknown tab type" fallback
419
+ - `editor-panel.tsx` — Panel wrapper with graceful unknown type handling
420
+
421
+ **Behavior:**
422
+ - Unknown tab types no longer crash the UI
423
+ - Fallback displays icon + tab identifier
424
+ - Users can still close/manage unknown tabs
425
+ - Enables safe extension tab additions without core UI changes
426
+
427
+ **Motivation:** Support future extension-contributed tab types without requiring core UI updates.
428
+
429
+ ---
430
+
380
431
  ## Critical Types
381
432
 
382
433
  | Type | Location | Purpose |
@@ -384,9 +435,11 @@ UI updates staged/unstaged lists
384
435
  | `ApiResponse<T>` | types/api.ts | Standard envelope for all REST responses |
385
436
  | `AIProvider` | providers/provider.interface.ts | Interface for AI model adapters |
386
437
  | `ChatEvent` | types/chat.ts | Union of streaming message types |
387
- | `GitStatus` | types/git.ts | Current branch, staged, unstaged, untracked files |
438
+ | `GitStatus` | types/git.ts | Current branch, staged, unstaged, untracked files (includes conflicted field v0.9.86+) |
388
439
  | `Session` | types/chat.ts | Chat session with ID, projectName, title, createdAt |
389
440
  | `Project` | types/project.ts | Project config (name, path) |
441
+ | `MergeState` | ext-git-graph/src/types.ts | Merge/rebase/cherry-pick state with progress tracking (v0.9.86+) |
442
+ | `TabType` | web/stores/tab-store.ts | "editor" \| "chat" \| "terminal" \| "database" \| "git-graph" \| "conflict-editor" \| "settings" (v0.9.86+) |
390
443
 
391
444
  ## External Dependencies
392
445
 
@@ -624,6 +677,109 @@ ppm ext disable @ppm/ext-db # Disable
624
677
  ppm ext dev /path/to/src # Dev symlink
625
678
  ```
626
679
 
680
+ ### Bundled Extensions (v0.9.85+)
681
+
682
+ PPM ships with pre-built extensions in `packages/ext-*` that are auto-discovered and available out-of-the-box:
683
+
684
+ **Discovery:**
685
+ - `discoverBundledManifests()` scans `packages/` for directories matching `ext-*`
686
+ - Bundled extensions loaded during `discover()` before user-installed extensions
687
+ - User-installed extensions override bundled if same ID (user takes precedence)
688
+
689
+ **Behavior:**
690
+ - `ppm ext list` shows "Source" column: `bundled` (cyan) vs `user`
691
+ - Bundled extensions cannot be removed (`ppm ext remove` rejected with helpful message)
692
+ - Use `ppm ext disable` to turn off bundled extensions
693
+ - Removal protection prevents accidental deletion of core extensions
694
+
695
+ **Current Bundled Extensions:**
696
+ - `@ppm/ext-git-graph` — Interactive git history visualization with workflow actions
697
+
698
+ **Architecture:**
699
+ - Extension paths tracked in `extensionService.extensionPaths` (ID → directory)
700
+ - Bundled IDs tracked in `extensionService.bundledIds` Set
701
+ - `isBundled(id)` public method for checking extension source
702
+
703
+ ---
704
+
705
+ ## ext-git-graph Extension (Git History Visualization)
706
+
707
+ ### Overview
708
+ The git-graph extension provides an interactive SVG visualization of repository commit history with comprehensive git workflow support. Implements the vscode-git-graph deterministic layout algorithm with faithful branch path rendering.
709
+
710
+ ### Key Features
711
+
712
+ **Graph Visualization:**
713
+ - Single SVG model with continuous Bézier branch paths for smooth merge visualization
714
+ - Deterministic lane assignment algorithm with greedy color reuse for branch lanes
715
+ - Shadow lines for visual depth and branch continuity
716
+ - Proper HEAD/stash node rendering (hollow circle for HEAD, nested circles for stash)
717
+ - Mobile SVG alignment: gridY matches 44px CSS row height for responsive layouts
718
+
719
+ **Git Workflow Actions:**
720
+ - **File Operations:** Stage/unstage files, open in editor, discard changes
721
+ - **Commits:** Create commits directly from webview with message and file selection
722
+ - **Branch Operations:** Stash/reset/clean with context menu and safety warnings
723
+ - **Repository:** Auto-fetch with configurable interval, manual fetch button
724
+ - **Filters:** Branch/tag/remote filters, tree/list view toggle
725
+
726
+ **UI Components:**
727
+ - Resizable graph column for flexible workspace adjustment
728
+ - Branch filter dropdown for quick navigation
729
+ - Tree/list view toggle for different visualization modes
730
+ - Commit detail panel with file diffs and action buttons
731
+ - Context menus with destructive operation warnings
732
+
733
+ ### Architecture
734
+
735
+ **Location:** `packages/ext-git-graph/`
736
+
737
+ **Files:**
738
+ - `extension.ts` (370 LOC) — RPC handlers, git operations, settings management
739
+ - `webview-html.ts` (443 additions) — Faithful SVG graph rendering with deterministic layout
740
+ - `types.ts` — Extension settings, message types, git operation definitions
741
+ - `git-log-parser.ts` — Parse git log with branches, tags, remotes, stashes
742
+ - `extension.test.ts` (230+ lines) — Integration tests for RPC handlers
743
+ - `webview-html.test.ts` — Graph rendering and layout tests
744
+
745
+ **RPC Protocol:**
746
+ - `gitStatus()` — Get current repo state
747
+ - `gitLog()` — Fetch commit history
748
+ - `stage(path)` / `unstage(path)` — File staging
749
+ - `commit(message, files)` — Create commit
750
+ - `stash()` / `reset(ref)` / `clean()` — Branch operations
751
+ - `openFile(path)` — Open in editor (IPC to main window)
752
+
753
+ **Settings:**
754
+ - `autoFetchInterval: number` — Seconds between auto-fetches (0 = disabled)
755
+
756
+ ### Security
757
+
758
+ **Path Validation:**
759
+ - `assertSafePath()` in extension-rpc-handlers ensures git operations only on registered project paths
760
+ - Prevents directory traversal attacks
761
+ - Cross-project workspace safety via RPC sandboxing
762
+
763
+ **XSS Prevention:**
764
+ - `escHtml()` applied to parent hashes and file status in detail panel
765
+ - Sanitized commit messages and metadata display
766
+
767
+ ### Mobile & Responsive
768
+
769
+ - Long-press support for context menus on touch devices
770
+ - Responsive CSS with flexible column sizing
771
+ - Dark/light theme support via CSS variables
772
+ - Touch-friendly button sizing (44px minimum)
773
+
774
+ ### Testing
775
+
776
+ **62 unit tests** covering:
777
+ - Git log parsing (commits, branches, tags, stashes)
778
+ - Parser edge cases (merge commits, rebases, detached HEAD)
779
+ - RPC handler validation and error cases
780
+ - Webview HTML rendering and layout algorithms
781
+ - Integration with main extension lifecycle
782
+
627
783
  ---
628
784
 
629
785
  ## Slash-Discovery Module (Modular Command Engine)
@@ -279,6 +279,78 @@ const value = context.globalState.get("key");
279
279
  await context.workspaceState.update("project", "data");
280
280
  ```
281
281
 
282
+ ### Process Spawning (Subprocess Execution)
283
+
284
+ Extensions needing to run external commands use the RPC `process:spawn` handler. This is essential for extensions that interact with CLIs (git, docker, node, etc.).
285
+
286
+ ```typescript
287
+ // Inside your extension (via RPC)
288
+ const rpc = (context as any).rpc;
289
+
290
+ const result = await rpc.request("process:spawn", [
291
+ "git", // command (must be in allowlist)
292
+ ["log", "--oneline", "-n", "10"], // args array
293
+ { cwd: process.cwd() } // options: { cwd?: string, timeout?: number }
294
+ ]);
295
+
296
+ // Result structure
297
+ if (!result.error) {
298
+ const { code, stdout, stderr } = result;
299
+ console.log("Exit code:", code);
300
+ console.log("Output:", stdout);
301
+ } else {
302
+ console.error("Command failed:", result.error);
303
+ }
304
+ ```
305
+
306
+ **Allowed Commands** (security allowlist):
307
+ - `git` — Version control operations
308
+ - `node`, `bun` — JavaScript runtimes
309
+ - `npm`, `yarn`, `pnpm` — Package managers
310
+ - `docker` — Container operations
311
+ - `psql` — PostgreSQL CLI
312
+ - `sqlite3` — SQLite CLI
313
+ - `python3`, `python` — Python runtime
314
+
315
+ **Restrictions:**
316
+ - CWD limited to current project root (no path escaping)
317
+ - 30-second timeout by default
318
+ - Stdout/stderr captured as strings
319
+ - Non-zero exit codes returned as error
320
+
321
+ **Example: Git Graph Extension**
322
+
323
+ ```typescript
324
+ // In ext-git-graph, spawn git to fetch log
325
+ export async function activate(context: ExtensionContext, vscode: any) {
326
+ const rpc = (context as any).rpc;
327
+
328
+ context.subscriptions.push(
329
+ vscode.commands.registerCommand("git-graph.view", async () => {
330
+ try {
331
+ const result = await rpc.request("process:spawn", [
332
+ "git",
333
+ ["log", "--all", "--oneline", "--graph"],
334
+ { cwd: process.cwd() }
335
+ ]);
336
+
337
+ if (result.error) {
338
+ await vscode.window.showErrorMessage(`Git error: ${result.error}`);
339
+ return;
340
+ }
341
+
342
+ // Parse result.stdout and render graph in webview
343
+ const commits = parseGitLog(result.stdout);
344
+ const panel = vscode.window.createWebviewPanel("git-graph", "Git Graph", vscode.ViewColumn.Active);
345
+ panel.webview.html = renderSvgGraph(commits);
346
+ } catch (e) {
347
+ await vscode.window.showErrorMessage(`Failed to load git graph: ${e}`);
348
+ }
349
+ })
350
+ );
351
+ }
352
+ ```
353
+
282
354
  ### Utilities
283
355
 
284
356
  ```typescript
@@ -313,6 +385,7 @@ emitter.fire("event data"); // Notify listeners
313
385
  | **Webview Panel** | ✅ Supported | Sandboxed iframe, 2-way messaging |
314
386
  | **Workspace Config** | ✅ Supported | Read/write user & workspace settings |
315
387
  | **Workspace FS** | ⚠️ Partial | Read, write, stat, readDirectory (no watch) |
388
+ | **Process Spawn** | ✅ Supported | Run external commands (git, npm, etc.) |
316
389
  | **Storage (Memento)** | ✅ Supported | Global & workspace state, auto-persisted |
317
390
  | **Uri** | ✅ Supported | File/webview URI utilities |
318
391
  | **EventEmitter** | ✅ Supported | Custom event streams |
@@ -439,7 +512,9 @@ ppm ext dev ./path/to/extension
439
512
 
440
513
  ---
441
514
 
442
- ## Example: Database Viewer
515
+ ## Examples
516
+
517
+ ### Database Viewer
443
518
 
444
519
  See `packages/ext-database/` in the PPM repo for a complete reference extension:
445
520
 
@@ -490,6 +565,28 @@ export function activate(context: ExtensionContext, vscode: any) {
490
565
  }
491
566
  ```
492
567
 
568
+ ### Git Graph
569
+
570
+ See `packages/ext-git-graph/` for an extension using **process:spawn** to run git commands:
571
+
572
+ - **Process spawning** via RPC to execute `git log` across any registered project
573
+ - **SVG graph rendering** faithful port of vscode-git-graph algorithm:
574
+ - Single SVG overlay with continuous branch paths (Bézier curves)
575
+ - Shadow lines for visual depth
576
+ - HEAD and stash node indicators
577
+ - Color-coded column tracking for branch visualization
578
+ - **Webview panel** for interactive visualization with scrolling commit list
579
+ - **Commit details** panel with author, date, message, and file changes
580
+ - **Context menu** for actions (checkout, cherry-pick, etc.)
581
+ - **Search/find** widget with navigation within the graph
582
+
583
+ Key patterns:
584
+ - Use `process:spawn` RPC to safely run git commands from any registered project root
585
+ - Parse git log output and compute graph coordinates (row, column, edge routing)
586
+ - Render single SVG overlay synchronized with commit list rows
587
+ - Implement custom graph rendering algorithm (path computation, Bézier curves, node placement)
588
+ - Two-way messaging between extension and webview for interactions and detail panel updates
589
+
493
590
  ---
494
591
 
495
592
  ## Best Practices
@@ -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