@hienlh/ppm 0.9.85 → 0.9.86
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.
- package/CHANGELOG.md +10 -0
- package/dist/web/assets/{_basePickBy-D-bUmjma.js → _basePickBy-Bj0dI1ei.js} +1 -1
- package/dist/web/assets/{_baseUniq-BnXXIfRB.js → _baseUniq-CyzdZeQH.js} +1 -1
- package/dist/web/assets/ai-settings-section-Bo9lCaTd.js +1 -0
- package/dist/web/assets/{api-settings-Qi2xRiHa.js → api-settings-CUxg9RE5.js} +1 -1
- package/dist/web/assets/{arc-DB9vXGzd.js → arc-CxgHJ7Z4.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-DDFO_NKq.js +1 -0
- package/dist/web/assets/{architectureDiagram-2XIMDMQ5-BBV25747.js → architectureDiagram-2XIMDMQ5-D16OotsC.js} +1 -1
- package/dist/web/assets/arrow-up-I9-21gkR.js +1 -0
- package/dist/web/assets/{blockDiagram-WCTKOSBZ-BOTnY2Lq.js → blockDiagram-WCTKOSBZ-Ct57Wtfk.js} +1 -1
- package/dist/web/assets/{c4Diagram-IC4MRINW-D7QAUdHD.js → c4Diagram-IC4MRINW-BIymcNsg.js} +1 -1
- package/dist/web/assets/channel-wumTB1if.js +1 -0
- package/dist/web/assets/chat-tab-BEEd-Km4.js +10 -0
- package/dist/web/assets/chevron-right-DY_wImxB.js +1 -0
- package/dist/web/assets/{chunk-4BX2VUAB-BnOVw77D.js → chunk-4BX2VUAB-CENmY7Kw.js} +1 -1
- package/dist/web/assets/{chunk-55IACEB6-BftA8DxR.js → chunk-55IACEB6-DhZGI1l3.js} +1 -1
- package/dist/web/assets/{chunk-7E7YKBS2-B0vnP8v3.js → chunk-7E7YKBS2-DZcnC7Ow.js} +1 -1
- package/dist/web/assets/{chunk-7R4GIKGN-Czlaj26D.js → chunk-7R4GIKGN-y8bfHEy-.js} +2 -2
- package/dist/web/assets/{chunk-C72U2L5F-DpEbDtMo.js → chunk-C72U2L5F-BHPkfQj2.js} +1 -1
- package/dist/web/assets/{chunk-EGIJ26TM-BWXe6lkx.js → chunk-EGIJ26TM-nant2LXl.js} +1 -1
- package/dist/web/assets/{chunk-FMBD7UC4-DspqhPfk.js → chunk-FMBD7UC4-Bog4cpN-.js} +1 -1
- package/dist/web/assets/{chunk-GEFDOKGD-D6HHRbYk.js → chunk-GEFDOKGD-86LFbsAC.js} +1 -1
- package/dist/web/assets/chunk-GLR3WWYH-Re-5eSlQ.js +2 -0
- package/dist/web/assets/chunk-HHEYEP7N-C45i5G_3.js +1 -0
- package/dist/web/assets/{chunk-JSJVCQXG-BC8wnMwf.js → chunk-JSJVCQXG-23eG9mgt.js} +1 -1
- package/dist/web/assets/{chunk-KX2RTZJC-D3VDtyvX.js → chunk-KX2RTZJC-CHj8TnTB.js} +1 -1
- package/dist/web/assets/{chunk-KYZI473N-Z-NBw_HS.js → chunk-KYZI473N-gqRLpJ4w.js} +1 -1
- package/dist/web/assets/{chunk-L3YUKLVL--RGkEh__.js → chunk-L3YUKLVL-DnSMmNFC.js} +1 -1
- package/dist/web/assets/{chunk-MX3YWQON-2B76t_Kx.js → chunk-MX3YWQON-B6g1ZH9X.js} +1 -1
- package/dist/web/assets/{chunk-NQ4KR5QH-BekY3tEi.js → chunk-NQ4KR5QH-DX32345Y.js} +1 -1
- package/dist/web/assets/{chunk-O4XLMI2P-2CJLfx_1.js → chunk-O4XLMI2P-Vp_V4P-b.js} +1 -1
- package/dist/web/assets/{chunk-OZEHJAEY-sug_L09P.js → chunk-OZEHJAEY-lKq2SWjA.js} +1 -1
- package/dist/web/assets/{chunk-PQ6SQG4A-_fwPRLQy.js → chunk-PQ6SQG4A-Bik13fTV.js} +1 -1
- package/dist/web/assets/{chunk-PU5JKC2W-BUaTFJVQ.js → chunk-PU5JKC2W-DD95Rx35.js} +1 -1
- package/dist/web/assets/chunk-QZHKN3VN-N3VXx1VH.js +1 -0
- package/dist/web/assets/{chunk-R5LLSJPH-C37xW0vj.js → chunk-R5LLSJPH-dRhXRnrb.js} +1 -1
- package/dist/web/assets/{chunk-WL4C6EOR-CCkt_MT6.js → chunk-WL4C6EOR-B1iIvLOG.js} +1 -1
- package/dist/web/assets/{chunk-XIRO2GV7-Dz2LBq7Y.js → chunk-XIRO2GV7-DZBoNl1_.js} +1 -1
- package/dist/web/assets/{chunk-XPW4576I-DenTbBuj.js → chunk-XPW4576I-CgLyyW03.js} +1 -1
- package/dist/web/assets/{chunk-XZSTWKYB-Dbp1nUSQ.js → chunk-XZSTWKYB-DjV8xl5A.js} +1 -1
- package/dist/web/assets/{chunk-YBOYWFTD-3OTKowjE.js → chunk-YBOYWFTD-D_ILLe6_.js} +1 -1
- package/dist/web/assets/classDiagram-VBA2DB6C-mr-Cb1me.js +1 -0
- package/dist/web/assets/classDiagram-v2-RAHNMMFH-BKe8_uda.js +1 -0
- package/dist/web/assets/clone--z5KLAuR.js +1 -0
- package/dist/web/assets/code-editor-Ij4p30cr.js +8 -0
- package/dist/web/assets/columns-2-IeETSfON.js +1 -0
- package/dist/web/assets/{cose-bilkent-S5V4N54A-MbmGZnt0.js → cose-bilkent-S5V4N54A-BGNPFv3x.js} +1 -1
- package/dist/web/assets/{csv-preview-uZ_7b8I7.js → csv-preview-CwQnOa3E.js} +2 -2
- package/dist/web/assets/{dagre-CPhI6v-K.js → dagre-CkhlMHnx.js} +1 -1
- package/dist/web/assets/{dagre-KLK3FWXG-CmSE-oNj.js → dagre-KLK3FWXG-Cnp996VG.js} +1 -1
- package/dist/web/assets/database-CgTomMxt.js +1 -0
- package/dist/web/assets/{database-viewer-5xljX0JI.js → database-viewer-C1UHSgft.js} +2 -2
- package/dist/web/assets/{diagram-E7M64L7V-B5XG3ZT7.js → diagram-E7M64L7V-BZF0tSOr.js} +1 -1
- package/dist/web/assets/{diagram-IFDJBPK2-BsP248aX.js → diagram-IFDJBPK2-nUcO8sN8.js} +1 -1
- package/dist/web/assets/{diagram-P4PSJMXO-Cna3408N.js → diagram-P4PSJMXO-CW0eCkwC.js} +1 -1
- package/dist/web/assets/diff-viewer-CVx5naBA.js +4 -0
- package/dist/web/assets/dist-CM0oD8tQ.js +1 -0
- package/dist/web/assets/{erDiagram-INFDFZHY-B7SgktiR.js → erDiagram-INFDFZHY-DSkriYZ9.js} +1 -1
- package/dist/web/assets/extension-webview-CHVVpV34.js +3 -0
- package/dist/web/assets/{flowDiagram-PKNHOUZH-FOYZZ1OB.js → flowDiagram-PKNHOUZH-CFYAfZBx.js} +1 -1
- package/dist/web/assets/{ganttDiagram-A5KZAMGK-CnHVYh9v.js → ganttDiagram-A5KZAMGK-KSn4XAU4.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-OkvBPi6H.js +1 -0
- package/dist/web/assets/{gitGraphDiagram-K3NZZRJ6-0G9XxZay.js → gitGraphDiagram-K3NZZRJ6-BMgjjVys.js} +1 -1
- package/dist/web/assets/{graphlib-CNiBwlg_.js → graphlib-BWe1iK_s.js} +1 -1
- package/dist/web/assets/index-OqgGFmh8.js +26 -0
- package/dist/web/assets/index-vA7juDri.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-BDU2_bYD.js +1 -0
- package/dist/web/assets/infoDiagram-LFFYTUFH-Diq4Cyc3.js +2 -0
- package/dist/web/assets/input-BHj0veau.js +45 -0
- package/dist/web/assets/{isEmpty-CcCb5n2-.js → isEmpty-BfLnxq-B.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-PHBUUO56-D4QCzh5J.js → ishikawaDiagram-PHBUUO56-CiVEvp8o.js} +1 -1
- package/dist/web/assets/{journeyDiagram-4ABVD52K-CnHYNfKW.js → journeyDiagram-4ABVD52K-CG_v5Aho.js} +1 -1
- package/dist/web/assets/jsx-runtime-BRW_vwa9.js +1 -0
- package/dist/web/assets/{kanban-definition-K7BYSVSG-Bh_g3EVu.js → kanban-definition-K7BYSVSG-miB0-_Zq.js} +1 -1
- package/dist/web/assets/keybindings-store-BQxgPV5o.js +1 -0
- package/dist/web/assets/{line-6d3eBADm.js → line-CSuSrJ9J.js} +1 -1
- package/dist/web/assets/{linear-cA_2lQy7.js → linear-DFN_MPsw.js} +1 -1
- package/dist/web/assets/{markdown-renderer-CZ07F7T6.js → markdown-renderer-CRy8xw2B.js} +6 -6
- package/dist/web/assets/{mermaid-parser.core-C3kd7JXM.js → mermaid-parser.core-CFdP1Z5_.js} +2 -2
- package/dist/web/assets/{mindmap-definition-YRQLILUH-CYiUwhr_.js → mindmap-definition-YRQLILUH-pYPWwASE.js} +1 -1
- package/dist/web/assets/{ordinal-XHK5vIzZ.js → ordinal-DpFn432U.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-BwpIpYB3.js +1 -0
- package/dist/web/assets/pie-UPGHQEXC-BPgAfmes.js +1 -0
- package/dist/web/assets/{pieDiagram-SKSYHLDU-D0S7jeZA.js → pieDiagram-SKSYHLDU-Dovdlvhu.js} +1 -1
- package/dist/web/assets/plus-DQGIb4mQ.js +1 -0
- package/dist/web/assets/port-forwarding-tab-Biua8ov5.js +1 -0
- package/dist/web/assets/{postgres-viewer-RldlAO_m.js → postgres-viewer-BcVjCAl4.js} +3 -3
- package/dist/web/assets/{quadrantDiagram-337W2JSQ-0hNP63hW.js → quadrantDiagram-337W2JSQ-TXe6cU_F.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-TqxBkWx-.js +1 -0
- package/dist/web/assets/refresh-cw-Clk8fdUD.js +1 -0
- package/dist/web/assets/{requirementDiagram-Z7DCOOCP-BVnmqFbL.js → requirementDiagram-Z7DCOOCP-CuiiuGS9.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-WA2Y5GQK-DVkYdCJb.js → sankeyDiagram-WA2Y5GQK-BbRmhv0t.js} +1 -1
- package/dist/web/assets/scroll-area-BpXCNme3.js +1 -0
- package/dist/web/assets/{sequenceDiagram-2WXFIKYE-B80s7sOg.js → sequenceDiagram-2WXFIKYE-B2D8IQDb.js} +1 -1
- package/dist/web/assets/settings-tab-C9X-N8hE.js +1 -0
- package/dist/web/assets/{sql-query-editor-CjZ7Z6XL.js → sql-query-editor-BFvRvJn0.js} +1 -1
- package/dist/web/assets/sqlite-viewer-CPfvwFl4.js +1 -0
- package/dist/web/assets/square-vBdqj0bF.js +1 -0
- package/dist/web/assets/{stateDiagram-RAJIS63D-BPLXgXRR.js → stateDiagram-RAJIS63D-ylr4HxPu.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-FVOUBMTO-D6zvxf3M.js +1 -0
- package/dist/web/assets/table-Bi27fEaN.js +1 -0
- package/dist/web/assets/{terminal-tab-DjzD8GLn.js → terminal-tab-mWwk_weB.js} +2 -2
- package/dist/web/assets/text-wrap-D_OmSzhp.js +1 -0
- package/dist/web/assets/{timeline-definition-YZTLITO2-fa_51u1X.js → timeline-definition-YZTLITO2-pMv1grvM.js} +1 -1
- package/dist/web/assets/trash-2-CNuB-htI.js +1 -0
- package/dist/web/assets/treemap-KZPCXAKY-Kck06FKU.js +1 -0
- package/dist/web/assets/{use-monaco-theme-D9XFxQuU.js → use-monaco-theme-CPaeSMAA.js} +1 -1
- package/dist/web/assets/{vennDiagram-LZ73GAT5-kX4jJn6W.js → vennDiagram-LZ73GAT5-C-rkIUbo.js} +1 -1
- package/dist/web/assets/x-Dw3TjeY_.js +1 -0
- package/dist/web/assets/{xychartDiagram-JWTSCODW-Bzm5lZBs.js → xychartDiagram-JWTSCODW-CtpjAakO.js} +1 -1
- package/dist/web/index.html +18 -22
- package/dist/web/sw.js +1 -1
- package/docs/codebase-summary.md +134 -11
- package/docs/extension-development-guide.md +98 -1
- package/docs/journals/260414-1400-ext-git-graph-port-complete.md +147 -0
- package/docs/journals/260414-1452-git-graph-faithful-port.md +144 -0
- package/docs/journals/260414-1810-git-graph-ui-improvements-complete.md +261 -0
- package/docs/journals/260414-2001-bundled-extensions.md +219 -0
- package/docs/project-changelog.md +63 -22
- package/docs/project-roadmap.md +1 -0
- package/docs/system-architecture.md +33 -5
- package/package.json +1 -1
- package/packages/ext-git-graph/package.json +30 -0
- package/packages/ext-git-graph/src/extension-integration.test.ts +230 -0
- package/packages/ext-git-graph/src/extension-parsers.test.ts +193 -0
- package/packages/ext-git-graph/src/extension.ts +800 -0
- package/packages/ext-git-graph/src/git-log-parser.test.ts +271 -0
- package/packages/ext-git-graph/src/git-log-parser.ts +38 -0
- package/packages/ext-git-graph/src/types.ts +181 -0
- package/packages/ext-git-graph/src/webview-html.test.ts +142 -0
- package/packages/ext-git-graph/src/webview-html.ts +2199 -0
- package/packages/vscode-compat/src/index.ts +4 -0
- package/packages/vscode-compat/src/process.ts +25 -0
- package/packages/vscode-compat/src/window.ts +10 -0
- package/src/cli/commands/ext-cmd.ts +3 -1
- package/src/server/ws/extensions.ts +6 -2
- package/src/services/contribution-registry.ts +14 -1
- package/src/services/extension-host-worker.ts +7 -3
- package/src/services/extension-manifest.ts +18 -1
- package/src/services/extension-rpc-handlers.ts +68 -2
- package/src/services/extension.service.ts +46 -6
- package/src/types/extension-messages.ts +2 -0
- package/src/types/extension.ts +8 -0
- package/src/web/components/editor/code-editor.tsx +16 -4
- package/src/web/components/extensions/extension-webview.tsx +111 -12
- package/src/web/components/layout/command-palette.tsx +41 -17
- package/src/web/components/layout/editor-panel.tsx +15 -4
- package/src/web/components/layout/mobile-nav.tsx +5 -5
- package/src/web/components/layout/tab-bar.tsx +2 -3
- package/src/web/components/layout/tab-content.tsx +12 -5
- package/src/web/components/settings/keyboard-shortcuts-section.tsx +46 -1
- package/src/web/hooks/use-extension-ws.ts +22 -4
- package/src/web/hooks/use-global-keybindings.ts +24 -2
- package/src/web/hooks/use-url-sync.ts +8 -3
- package/src/web/stores/keybindings-store.ts +2 -3
- package/src/web/stores/panel-store.ts +2 -2
- package/src/web/stores/panel-utils.ts +4 -2
- package/src/web/stores/tab-store.ts +1 -1
- package/dist/web/assets/ai-settings-section-D6d-RmR6.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-DpVzOETR.js +0 -1
- package/dist/web/assets/arrow-up-BigIMx-e.js +0 -1
- package/dist/web/assets/channel-Cgy1thYT.js +0 -1
- package/dist/web/assets/chat-tab-DXBb9Y3U.js +0 -10
- package/dist/web/assets/check-ePA3ZvK4.js +0 -1
- package/dist/web/assets/chevron-down-EQA06nR-.js +0 -1
- package/dist/web/assets/chevron-right-CXzzT44u.js +0 -1
- package/dist/web/assets/chunk-GLR3WWYH-CxUl1sdz.js +0 -2
- package/dist/web/assets/chunk-HHEYEP7N-DN7ebS2Y.js +0 -1
- package/dist/web/assets/chunk-QZHKN3VN-C4La7oLj.js +0 -1
- package/dist/web/assets/classDiagram-VBA2DB6C-C3IyfqG-.js +0 -1
- package/dist/web/assets/classDiagram-v2-RAHNMMFH-Dcvhz2pb.js +0 -1
- package/dist/web/assets/clone--C7Tby8z.js +0 -1
- package/dist/web/assets/code-editor-Cr7JrBKC.js +0 -8
- package/dist/web/assets/columns-2-BZ9uqssV.js +0 -1
- package/dist/web/assets/createLucideIcon-PuMiQgHl.js +0 -1
- package/dist/web/assets/database-D1ToEV9d.js +0 -1
- package/dist/web/assets/diff-viewer-BBr6e_gb.js +0 -4
- package/dist/web/assets/dist-KUoHa6tg.js +0 -1
- package/dist/web/assets/extension-webview-B0klBip8.js +0 -3
- package/dist/web/assets/eye-CNcBU6Tx.js +0 -1
- package/dist/web/assets/git-graph-CDiwGa0g.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-DcPyMEIJ.js +0 -1
- package/dist/web/assets/index-CkaCzNgO.css +0 -2
- package/dist/web/assets/index-Ic5uTu20.js +0 -26
- package/dist/web/assets/info-3K5VOQVL-Dw4O15cw.js +0 -1
- package/dist/web/assets/infoDiagram-LFFYTUFH-DFhmsucr.js +0 -2
- package/dist/web/assets/input-CcbTF6ih.js +0 -45
- package/dist/web/assets/jsx-runtime-R_NjdZtX.js +0 -1
- package/dist/web/assets/keybindings-store-CxE6BlG2.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-o3LmdL8H.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-BjNP0M3B.js +0 -1
- package/dist/web/assets/plus-Iso5r9vD.js +0 -1
- package/dist/web/assets/port-forwarding-tab-BPuSc6pI.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-gDgOiaME.js +0 -1
- package/dist/web/assets/refresh-cw-BgQzFNaG.js +0 -1
- package/dist/web/assets/scroll-area-i4EZlOl_.js +0 -1
- package/dist/web/assets/settings-tab-BzSSN2BQ.js +0 -1
- package/dist/web/assets/sqlite-viewer-CoyZOM_Y.js +0 -1
- package/dist/web/assets/square-pfn_LYYy.js +0 -1
- package/dist/web/assets/stateDiagram-v2-FVOUBMTO-DksQJ7es.js +0 -1
- package/dist/web/assets/table-CHv2x_qg.js +0 -1
- package/dist/web/assets/tag-Bb_UFXt0.js +0 -1
- package/dist/web/assets/text-wrap-D8BbQYTx.js +0 -1
- package/dist/web/assets/trash-2-DYCa06CV.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-DwFqAvnj.js +0 -1
- package/dist/web/assets/x-BXecj-16.js +0 -1
- package/src/web/components/git/git-graph-branch-label.tsx +0 -124
- package/src/web/components/git/git-graph-constants.ts +0 -185
- package/src/web/components/git/git-graph-detail.tsx +0 -107
- package/src/web/components/git/git-graph-dialog.tsx +0 -72
- package/src/web/components/git/git-graph-row.tsx +0 -167
- package/src/web/components/git/git-graph-settings-dialog.tsx +0 -104
- package/src/web/components/git/git-graph-svg.tsx +0 -54
- package/src/web/components/git/git-graph-toolbar.tsx +0 -195
- package/src/web/components/git/git-graph.tsx +0 -193
- package/src/web/components/git/use-column-resize.ts +0 -33
- package/src/web/components/git/use-git-graph.ts +0 -201
- /package/dist/web/assets/{api-client-wQbeUyeh.js → api-client-BvxmRZUi.js} +0 -0
- /package/dist/web/assets/{array-X0JlPOfd.js → array-BFDiaBgf.js} +0 -0
- /package/dist/web/assets/{csv-parser-CElqio6o.js → csv-parser-i7fjqP2H.js} +0 -0
- /package/dist/web/assets/{cytoscape.esm-BfIOPvwt.js → cytoscape.esm-C8i2jUzT.js} +0 -0
- /package/dist/web/assets/{defaultLocale-B6RGN4id.js → defaultLocale-ZeknFqNe.js} +0 -0
- /package/dist/web/assets/{dist-CK1enexV.js → dist-DZmJeHOA.js} +0 -0
- /package/dist/web/assets/{init-BmUWJJHz.js → init-0VJVrkRJ.js} +0 -0
- /package/dist/web/assets/{isArrayLikeObject-BrCM-iA1.js → isArrayLikeObject-ClzWCpcm.js} +0 -0
- /package/dist/web/assets/{katex-xQS_6bNb.js → katex-DR0kdMDv.js} +0 -0
- /package/dist/web/assets/{lib-CfWBrYll.js → lib-CeBVkQ-7.js} +0 -0
- /package/dist/web/assets/{math-CpLFzrfV.js → math-CRc16Nj6.js} +0 -0
- /package/dist/web/assets/{path-CoPyR7c2.js → path-INs8XTPH.js} +0 -0
- /package/dist/web/assets/{preload-helper-CH6UZRzu.js → preload-helper-mr3rCizq.js} +0 -0
- /package/dist/web/assets/{react-j5zqhEum.js → react-0tkk-ztn.js} +0 -0
- /package/dist/web/assets/{rough.esm-D5NinLFK.js → rough.esm-eLccZ4OJ.js} +0 -0
- /package/dist/web/assets/{sql-completion-provider-D0xutVaK.js → sql-completion-provider-B8uUWWej.js} +0 -0
- /package/dist/web/assets/{src-j04igtQ5.js → src-CqyWLlNZ.js} +0 -0
- /package/dist/web/assets/{utils-CSCvNZxE.js → utils-DX8jb5qv.js} +0 -0
|
@@ -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
|
-
##
|
|
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
|