@hienlh/ppm 0.9.84 → 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/260413-1354-new-file-editor-tab/reports/code-reviewer-260413-1420-new-file-tab-review.md +210 -0
- package/CHANGELOG.md +23 -0
- package/bun.lock +259 -9
- package/dist/web/assets/{_basePickBy-5PGDJbfF.js → _basePickBy-Bj0dI1ei.js} +1 -1
- package/dist/web/assets/{_baseUniq-BT4Ow4Kk.js → _baseUniq-CyzdZeQH.js} +1 -1
- package/dist/web/assets/ai-settings-section-Bo9lCaTd.js +1 -0
- package/dist/web/assets/{api-settings-Bn-bIxD1.js → api-settings-CUxg9RE5.js} +1 -1
- package/dist/web/assets/{arc-BAOivWpI.js → arc-CxgHJ7Z4.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-DDFO_NKq.js +1 -0
- package/dist/web/assets/{architectureDiagram-2XIMDMQ5-Z-4eN4za.js → architectureDiagram-2XIMDMQ5-D16OotsC.js} +1 -1
- package/dist/web/assets/arrow-up-I9-21gkR.js +1 -0
- package/dist/web/assets/{blockDiagram-WCTKOSBZ-BCLqzhuZ.js → blockDiagram-WCTKOSBZ-Ct57Wtfk.js} +1 -1
- package/dist/web/assets/{c4Diagram-IC4MRINW-0Vp0Jeas.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-D4tOov49.js → chunk-4BX2VUAB-CENmY7Kw.js} +1 -1
- package/dist/web/assets/{chunk-55IACEB6-DJ6BynZ4.js → chunk-55IACEB6-DhZGI1l3.js} +1 -1
- package/dist/web/assets/{chunk-7E7YKBS2-CiyUJxNI.js → chunk-7E7YKBS2-DZcnC7Ow.js} +1 -1
- package/dist/web/assets/{chunk-7R4GIKGN-Dv-4cAYn.js → chunk-7R4GIKGN-y8bfHEy-.js} +2 -2
- package/dist/web/assets/{chunk-C72U2L5F-D21mS_6G.js → chunk-C72U2L5F-BHPkfQj2.js} +1 -1
- package/dist/web/assets/{chunk-EGIJ26TM-DzqmU2Z7.js → chunk-EGIJ26TM-nant2LXl.js} +1 -1
- package/dist/web/assets/{chunk-FMBD7UC4-DXncblvW.js → chunk-FMBD7UC4-Bog4cpN-.js} +1 -1
- package/dist/web/assets/{chunk-GEFDOKGD-D-pKjlVd.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-99JzIdPr.js → chunk-JSJVCQXG-23eG9mgt.js} +1 -1
- package/dist/web/assets/{chunk-KX2RTZJC-CRq1OBZv.js → chunk-KX2RTZJC-CHj8TnTB.js} +1 -1
- package/dist/web/assets/{chunk-KYZI473N-Bb0MCaIO.js → chunk-KYZI473N-gqRLpJ4w.js} +1 -1
- package/dist/web/assets/{chunk-L3YUKLVL-C7qGJrfV.js → chunk-L3YUKLVL-DnSMmNFC.js} +1 -1
- package/dist/web/assets/{chunk-MX3YWQON-BpS_PtKp.js → chunk-MX3YWQON-B6g1ZH9X.js} +1 -1
- package/dist/web/assets/{chunk-NQ4KR5QH-z_blpjxi.js → chunk-NQ4KR5QH-DX32345Y.js} +1 -1
- package/dist/web/assets/{chunk-O4XLMI2P-nDhi_cVu.js → chunk-O4XLMI2P-Vp_V4P-b.js} +1 -1
- package/dist/web/assets/{chunk-OZEHJAEY-BXhYx3nO.js → chunk-OZEHJAEY-lKq2SWjA.js} +1 -1
- package/dist/web/assets/{chunk-PQ6SQG4A-TF58UVMU.js → chunk-PQ6SQG4A-Bik13fTV.js} +1 -1
- package/dist/web/assets/{chunk-PU5JKC2W-ek7k4QVB.js → chunk-PU5JKC2W-DD95Rx35.js} +1 -1
- package/dist/web/assets/chunk-QZHKN3VN-N3VXx1VH.js +1 -0
- package/dist/web/assets/{chunk-R5LLSJPH-CFwSJijQ.js → chunk-R5LLSJPH-dRhXRnrb.js} +1 -1
- package/dist/web/assets/{chunk-WL4C6EOR-ByUrSRin.js → chunk-WL4C6EOR-B1iIvLOG.js} +1 -1
- package/dist/web/assets/{chunk-XIRO2GV7-Djlmrely.js → chunk-XIRO2GV7-DZBoNl1_.js} +1 -1
- package/dist/web/assets/{chunk-XPW4576I-BPQQBakK.js → chunk-XPW4576I-CgLyyW03.js} +1 -1
- package/dist/web/assets/{chunk-XZSTWKYB-DxAOx4hG.js → chunk-XZSTWKYB-DjV8xl5A.js} +1 -1
- package/dist/web/assets/{chunk-YBOYWFTD-rQG3QH5s.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-B_AWZsOP.js → cose-bilkent-S5V4N54A-BGNPFv3x.js} +1 -1
- package/dist/web/assets/{csv-preview-D2pJJj3K.js → csv-preview-CwQnOa3E.js} +2 -2
- package/dist/web/assets/{dagre-DHq9bhnd.js → dagre-CkhlMHnx.js} +1 -1
- package/dist/web/assets/{dagre-KLK3FWXG-BdJr7Byp.js → dagre-KLK3FWXG-Cnp996VG.js} +1 -1
- package/dist/web/assets/database-CgTomMxt.js +1 -0
- package/dist/web/assets/{database-viewer-Camu01H4.js → database-viewer-C1UHSgft.js} +2 -2
- package/dist/web/assets/{diagram-E7M64L7V-_db4pBVA.js → diagram-E7M64L7V-BZF0tSOr.js} +1 -1
- package/dist/web/assets/{diagram-IFDJBPK2-xKoeuiJx.js → diagram-IFDJBPK2-nUcO8sN8.js} +1 -1
- package/dist/web/assets/{diagram-P4PSJMXO-C8tjJsev.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-BSh2z9Df.js → erDiagram-INFDFZHY-DSkriYZ9.js} +1 -1
- package/dist/web/assets/extension-webview-CHVVpV34.js +3 -0
- package/dist/web/assets/{flowDiagram-PKNHOUZH-oYaovqyp.js → flowDiagram-PKNHOUZH-CFYAfZBx.js} +1 -1
- package/dist/web/assets/{ganttDiagram-A5KZAMGK-DmL26q2P.js → ganttDiagram-A5KZAMGK-KSn4XAU4.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-OkvBPi6H.js +1 -0
- package/dist/web/assets/{gitGraphDiagram-K3NZZRJ6-CMoukSrY.js → gitGraphDiagram-K3NZZRJ6-BMgjjVys.js} +1 -1
- package/dist/web/assets/{graphlib-BcsNnGcW.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-bnrF3Qbc.js → isEmpty-BfLnxq-B.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-PHBUUO56-D05_LyL7.js → ishikawaDiagram-PHBUUO56-CiVEvp8o.js} +1 -1
- package/dist/web/assets/{journeyDiagram-4ABVD52K-B_L20qMe.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-CZ535BbZ.js → kanban-definition-K7BYSVSG-miB0-_Zq.js} +1 -1
- package/dist/web/assets/keybindings-store-BQxgPV5o.js +1 -0
- package/dist/web/assets/{line-CVvo3dRu.js → line-CSuSrJ9J.js} +1 -1
- package/dist/web/assets/{linear-DP4mkX3m.js → linear-DFN_MPsw.js} +1 -1
- package/dist/web/assets/markdown-renderer-CRy8xw2B.js +306 -0
- package/dist/web/assets/{mermaid-parser.core-C7UwoIh6.js → mermaid-parser.core-CFdP1Z5_.js} +2 -2
- package/dist/web/assets/{mindmap-definition-YRQLILUH-x0MTutJp.js → mindmap-definition-YRQLILUH-pYPWwASE.js} +1 -1
- package/dist/web/assets/{ordinal-_K3x1fkz.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-C1Gjrtzy.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-BQdPMowm.js → postgres-viewer-BcVjCAl4.js} +3 -3
- package/dist/web/assets/{quadrantDiagram-337W2JSQ-C8bzJCjQ.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-pQyah6WB.js → requirementDiagram-Z7DCOOCP-CuiiuGS9.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-WA2Y5GQK-T6RgG-N8.js → sankeyDiagram-WA2Y5GQK-BbRmhv0t.js} +1 -1
- package/dist/web/assets/scroll-area-BpXCNme3.js +1 -0
- package/dist/web/assets/{sequenceDiagram-2WXFIKYE-BQDJ4CVs.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-CY61vWBg.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-66vhiIuk.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-TIJmxHl6.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-DwZqB3nn.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-BHn-LEm7.js → use-monaco-theme-CPaeSMAA.js} +1 -1
- package/dist/web/assets/{vennDiagram-LZ73GAT5-s9Z71fz-.js → vennDiagram-LZ73GAT5-C-rkIUbo.js} +1 -1
- package/dist/web/assets/x-Dw3TjeY_.js +1 -0
- package/dist/web/assets/{xychartDiagram-JWTSCODW-DRa_TH4B.js → xychartDiagram-JWTSCODW-CtpjAakO.js} +1 -1
- package/dist/web/index.html +18 -12
- 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 +9 -3
- 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/index.ts +1 -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 +83 -8
- package/src/web/components/editor/save-as-dialog.tsx +75 -0
- package/src/web/components/extensions/extension-webview.tsx +111 -12
- package/src/web/components/layout/command-palette.tsx +43 -17
- package/src/web/components/layout/draggable-tab.tsx +120 -67
- package/src/web/components/layout/editor-panel.tsx +15 -4
- package/src/web/components/layout/mobile-nav.tsx +74 -7
- package/src/web/components/layout/tab-bar.tsx +76 -4
- package/src/web/components/layout/tab-content.tsx +12 -5
- package/src/web/components/layout/upgrade-banner.tsx +3 -0
- package/src/web/components/settings/keyboard-shortcuts-section.tsx +46 -1
- package/src/web/components/shared/markdown-code-block.tsx +142 -0
- package/src/web/components/shared/markdown-context.ts +20 -0
- package/src/web/components/shared/markdown-renderer.tsx +113 -288
- package/src/web/hooks/use-extension-ws.ts +22 -4
- package/src/web/hooks/use-global-keybindings.ts +31 -2
- package/src/web/hooks/use-url-sync.ts +8 -3
- package/src/web/main.tsx +1 -0
- package/src/web/stores/keybindings-store.ts +3 -3
- package/src/web/stores/panel-store.ts +2 -2
- package/src/web/stores/panel-utils.ts +17 -2
- package/src/web/stores/tab-store.ts +17 -1
- package/src/web/styles/globals.css +6 -0
- package/.opencode/.env.example +0 -98
- package/.opencode/skills/ads-management/scripts/.env.example +0 -13
- package/.opencode/skills/ai-multimodal/.env.example +0 -230
- package/.opencode/skills/cip-design/.env.example +0 -6
- package/.opencode/skills/devops/.env.example +0 -76
- package/.opencode/skills/docs-seeker/.env.example +0 -15
- package/.opencode/skills/elevenlabs/.env.example +0 -3
- package/.opencode/skills/marketing-dashboard/.env.example +0 -15
- package/.opencode/skills/marketing-dashboard/app/.env.example +0 -2
- package/.opencode/skills/marketing-dashboard/server/.env.example +0 -2
- package/.opencode/skills/mcp-management/scripts/dist/analyze-tools.js +0 -70
- package/.opencode/skills/mcp-management/scripts/dist/cli.js +0 -160
- package/.opencode/skills/mcp-management/scripts/dist/mcp-client.js +0 -183
- package/.opencode/skills/payment-integration/scripts/.env.example +0 -20
- package/.opencode/skills/sequential-thinking/.env.example +0 -8
- package/dist/web/assets/architecture-PBZL5I3N-DEO2f3VD.js +0 -1
- package/dist/web/assets/arrow-up-BYhx9ckd.js +0 -1
- package/dist/web/assets/channel-By7bn0Yq.js +0 -1
- package/dist/web/assets/chat-tab-CT2XUgsc.js +0 -10
- package/dist/web/assets/chevron-right-4zq1jPv6.js +0 -1
- package/dist/web/assets/chunk-GLR3WWYH-DKikpoJM.js +0 -2
- package/dist/web/assets/chunk-HHEYEP7N-C7vxA5i9.js +0 -1
- package/dist/web/assets/chunk-QZHKN3VN-CYaTbeZf.js +0 -1
- package/dist/web/assets/classDiagram-VBA2DB6C-BA8Nj-_C.js +0 -1
- package/dist/web/assets/classDiagram-v2-RAHNMMFH-DjYu-6mn.js +0 -1
- package/dist/web/assets/clone-LRxlvnMj.js +0 -1
- package/dist/web/assets/code-editor-DQiPtcNd.js +0 -8
- package/dist/web/assets/columns-2-BoZAN-iw.js +0 -1
- package/dist/web/assets/createLucideIcon-PuMiQgHl.js +0 -1
- package/dist/web/assets/diff-viewer-CTwcVIP_.js +0 -4
- package/dist/web/assets/dist-DIV6WgAG.js +0 -41
- package/dist/web/assets/extension-webview-pU1xJyoc.js +0 -3
- package/dist/web/assets/git-graph-BnFbmpom.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-Bwna3and.js +0 -1
- package/dist/web/assets/index-CP9KnaGh.js +0 -30
- package/dist/web/assets/index-Cxz7oGXY.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-_vRxVNUm.js +0 -1
- package/dist/web/assets/infoDiagram-LFFYTUFH-DWwumDkq.js +0 -2
- package/dist/web/assets/jsx-runtime-kMwlnEGE.js +0 -1
- package/dist/web/assets/keybindings-store-DdhEeehv.js +0 -1
- package/dist/web/assets/markdown-renderer-BjYurPV4.js +0 -326
- package/dist/web/assets/packet-RMMSAZCW-DY5PNnZU.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-BHncZutv.js +0 -1
- package/dist/web/assets/port-forwarding-tab-Bgr8dmsw.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-DH0AOkUy.js +0 -1
- package/dist/web/assets/settings-tab-BNoboN6E.js +0 -1
- package/dist/web/assets/sqlite-viewer-srSbGg1D.js +0 -1
- package/dist/web/assets/square-oPKIkJiw.js +0 -1
- package/dist/web/assets/stateDiagram-v2-FVOUBMTO-BGVqj_g9.js +0 -1
- package/dist/web/assets/table-DFevCOMd.js +0 -1
- package/dist/web/assets/tag-CXMT0QB6.js +0 -1
- package/dist/web/assets/text-wrap-BWNOVswA.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-B2Xkyv-K.js +0 -1
- package/dist/web/assets/x-D2_KzIET.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-BfBM3I7n.js → api-client-BvxmRZUi.js} +0 -0
- /package/dist/web/assets/{array-B9UHiPd-.js → array-BFDiaBgf.js} +0 -0
- /package/dist/web/assets/{csv-parser-CNNw2RVA.js → csv-parser-i7fjqP2H.js} +0 -0
- /package/dist/web/assets/{cytoscape.esm-BW-DbntU.js → cytoscape.esm-C8i2jUzT.js} +0 -0
- /package/dist/web/assets/{defaultLocale-5eAKkKJC.js → defaultLocale-ZeknFqNe.js} +0 -0
- /package/dist/web/assets/{dist-CSJdAyA9.js → dist-DZmJeHOA.js} +0 -0
- /package/dist/web/assets/{init-DlZdxViB.js → init-0VJVrkRJ.js} +0 -0
- /package/dist/web/assets/{isArrayLikeObject-B_v2FtYn.js → isArrayLikeObject-ClzWCpcm.js} +0 -0
- /package/dist/web/assets/{katex-Bqvo_ZG0.js → katex-DR0kdMDv.js} +0 -0
- /package/dist/web/assets/{lib-DurwGtQO.js → lib-CeBVkQ-7.js} +0 -0
- /package/dist/web/assets/{math-069Z4SuC.js → math-CRc16Nj6.js} +0 -0
- /package/dist/web/assets/{path-6uRLdFF7.js → path-INs8XTPH.js} +0 -0
- /package/dist/web/assets/{preload-helper-Bf_JiD2A.js → preload-helper-mr3rCizq.js} +0 -0
- /package/dist/web/assets/{react-SKk5z-bm.js → react-0tkk-ztn.js} +0 -0
- /package/dist/web/assets/{rough.esm-JX0wREDd.js → rough.esm-eLccZ4OJ.js} +0 -0
- /package/dist/web/assets/{sql-completion-provider-DM9Qov6L.js → sql-completion-provider-B8uUWWej.js} +0 -0
- /package/dist/web/assets/{src-BqX54PbV.js → src-CqyWLlNZ.js} +0 -0
- /package/dist/web/assets/{utils-BNytJOb1.js → utils-DX8jb5qv.js} +0 -0
package/260413-1354-new-file-editor-tab/reports/code-reviewer-260413-1420-new-file-tab-review.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
## Code Review: New File Editor Tab Feature
|
|
2
|
+
|
|
3
|
+
### Scope
|
|
4
|
+
- Files: 8 (panel-utils.ts, tab-store.ts, code-editor.tsx, save-as-dialog.tsx, tab-bar.tsx, use-global-keybindings.ts, keybindings-store.ts, command-palette.tsx)
|
|
5
|
+
- Focus: New untitled tab lifecycle, Save As transition, entry points
|
|
6
|
+
- Scout findings: Race condition in metadata persistence, stale tab ID after Save As, Ctrl+S binding leak
|
|
7
|
+
|
|
8
|
+
### Overall Assessment
|
|
9
|
+
Feature is well-structured with clean separation between store logic, editor behavior, and UI entry points. The untitled number allocation via `getNextUntitledNumber()` scanning all panels is correct. However, the Save As transition has two critical issues that will cause user-visible bugs in production.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Critical Issues
|
|
14
|
+
|
|
15
|
+
#### 1. Race condition: debounced metadata persistence overwrites Save As transition
|
|
16
|
+
|
|
17
|
+
**File:** `src/web/components/editor/code-editor.tsx` lines 272-276
|
|
18
|
+
|
|
19
|
+
**Problem:** `handleChange` sets a 2-second debounced timer to persist `unsavedContent` to tab metadata. `handleSaveAs` does NOT clear `saveTimerRef`. If the user types, then triggers Save As within the 2s debounce window, the pending timeout fires after Save As and calls:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
updateTab(tabId, { metadata: { ...oldMetadata, unsavedContent: latestContent } })
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The `oldMetadata` closure captured at the time of the keystroke still has `isUntitled: true`. This **reverts** the Save As transition, restoring the tab to untitled state. The file is written to disk but the tab loses its file association.
|
|
26
|
+
|
|
27
|
+
**Fix:** Clear `saveTimerRef` at the start of `handleSaveAs`:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
const handleSaveAs = useCallback(async (targetPath: string, savedText: string) => {
|
|
31
|
+
// Cancel any pending metadata persistence to prevent race condition
|
|
32
|
+
if (saveTimerRef.current) {
|
|
33
|
+
clearTimeout(saveTimerRef.current);
|
|
34
|
+
saveTimerRef.current = null;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
await api.put("/api/fs/write", { path: targetPath, content: savedText });
|
|
38
|
+
// ... rest
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
#### 2. Tab ID not updated after Save As -- stale ID causes duplicate tabs
|
|
42
|
+
|
|
43
|
+
**File:** `src/web/components/editor/code-editor.tsx` lines 283-296
|
|
44
|
+
|
|
45
|
+
**Problem:** After Save As, `updateTab` changes the tab's metadata (filePath, removes isUntitled) but the tab ID remains `editor:untitled-N`. The `updateTab` API signature `Partial<Omit<Tab, "id">>` prevents changing the ID. Consequences:
|
|
46
|
+
|
|
47
|
+
- Opening the same file from explorer or command palette creates a **second tab** with ID `editor:/path/to/file` (dedup logic in `openTab` checks by ID)
|
|
48
|
+
- The `getNextUntitledNumber()` scanner still sees the old `editor:untitled-N` ID, so it considers number N as "taken" even though the tab is no longer untitled
|
|
49
|
+
- Tab persistence to localStorage/server keeps the stale ID
|
|
50
|
+
|
|
51
|
+
**Fix:** Replace the `updateTab` call with a close-then-open sequence:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const handleSaveAs = useCallback(async (targetPath: string, savedText: string) => {
|
|
55
|
+
if (saveTimerRef.current) { clearTimeout(saveTimerRef.current); saveTimerRef.current = null; }
|
|
56
|
+
try {
|
|
57
|
+
await api.put("/api/fs/write", { path: targetPath, content: savedText });
|
|
58
|
+
if (tabId) {
|
|
59
|
+
// Close the untitled tab and open as a proper file tab
|
|
60
|
+
const panelStore = usePanelStore.getState();
|
|
61
|
+
panelStore.closeTab(tabId);
|
|
62
|
+
panelStore.openTab({
|
|
63
|
+
type: "editor",
|
|
64
|
+
title: basename(targetPath),
|
|
65
|
+
projectId: null,
|
|
66
|
+
metadata: { filePath: targetPath },
|
|
67
|
+
closable: true,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
setShowSaveAs(false);
|
|
71
|
+
} catch { /* silent */ }
|
|
72
|
+
}, [tabId]);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Alternative (simpler but less clean):** Add a `replaceTabId` method to panel-store that atomically swaps a tab's ID.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### High Priority
|
|
80
|
+
|
|
81
|
+
#### 3. Ctrl+S Monaco binding leaks after Save As
|
|
82
|
+
|
|
83
|
+
**File:** `src/web/components/editor/code-editor.tsx` lines 315-320
|
|
84
|
+
|
|
85
|
+
**Problem:** `handleEditorMount` registers `Ctrl+S -> setShowSaveAs(true)` once when `isUntitled` is true. After Save As transitions the tab, the Monaco command is never removed. Pressing Ctrl+S re-opens the Save As dialog instead of doing nothing (the global `save-prevent` handler only `preventDefault()`s the browser dialog, it doesn't trigger actual file save).
|
|
86
|
+
|
|
87
|
+
**Impact:** After saving an untitled file, every subsequent Ctrl+S opens Save As again instead of silently auto-saving.
|
|
88
|
+
|
|
89
|
+
**Fix (combined with Issue #2):** If using the close-then-open approach from Issue #2, this is automatically resolved since the new editor instance mounts without the untitled binding. If keeping `updateTab`, add a `useEffect` that removes and re-registers commands when `isUntitled` changes, or guard the callback:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
editor.addCommand(
|
|
93
|
+
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS,
|
|
94
|
+
() => {
|
|
95
|
+
// Check current state at invocation time, not registration time
|
|
96
|
+
if (metadata?.isUntitled) setShowSaveAs(true);
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
However, this still requires `metadata` to be current. A better approach uses a ref:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const isUntitledRef = useRef(isUntitled);
|
|
105
|
+
isUntitledRef.current = isUntitled;
|
|
106
|
+
|
|
107
|
+
// In handleEditorMount:
|
|
108
|
+
editor.addCommand(
|
|
109
|
+
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS,
|
|
110
|
+
() => { if (isUntitledRef.current) setShowSaveAs(true); },
|
|
111
|
+
);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### 4. Metadata replacement (not merge) loses context in `handleChange`
|
|
115
|
+
|
|
116
|
+
**File:** `src/web/components/editor/code-editor.tsx` line 275
|
|
117
|
+
|
|
118
|
+
`updateTab` in panel-store does shallow spread: `{ ...t, ...updates }`. When `updates` contains `{ metadata: {...} }`, the entire `metadata` object is replaced, not deep-merged. Currently this is fine because untitled tabs only have `isUntitled`, `untitledNumber`, and `unsavedContent`. But if any code adds additional metadata keys to the tab between creation and the debounced save, they would be silently dropped.
|
|
119
|
+
|
|
120
|
+
**Recommendation:** Use explicit merge:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
updateTab(tabId, { metadata: { ...(ownTab?.metadata ?? {}), unsavedContent: latestContentRef.current } });
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Or better yet, read current metadata from the store at timeout fire time rather than closing over the render-time value.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### Medium Priority
|
|
131
|
+
|
|
132
|
+
#### 5. `handleEditorMount` has incomplete dependency array
|
|
133
|
+
|
|
134
|
+
**File:** `src/web/components/editor/code-editor.tsx` line 388
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
}, [sqlSchemaInfo]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The `useCallback` for `handleEditorMount` lists only `[sqlSchemaInfo]` as a dependency but uses `isUntitled`, `lineNumber`, `isSql`, and several refs. The eslint suppression hides stale closure bugs. Specifically, if `isUntitled` changes (impossible in practice for mount, but the lint suppression is risky for future changes).
|
|
141
|
+
|
|
142
|
+
**Recommendation:** This was pre-existing and the new code (`isUntitled` check inside) works because `handleEditorMount` only fires once per editor instance. No action needed now, but note for future.
|
|
143
|
+
|
|
144
|
+
#### 6. New tab dropdown menu: custom implementation vs existing dropdown component
|
|
145
|
+
|
|
146
|
+
**File:** `src/web/components/layout/tab-bar.tsx` lines 98-107, 240-262
|
|
147
|
+
|
|
148
|
+
The dropdown uses a manual `showNewMenu` state + `mousedown` outside click handler. This:
|
|
149
|
+
- Doesn't handle Escape key to close
|
|
150
|
+
- Doesn't handle focus management / trap
|
|
151
|
+
- Doesn't handle mobile touch events properly (no long-press activation)
|
|
152
|
+
|
|
153
|
+
Per the design guidelines ("Context menus -> long-press on mobile"), the tab bar dropdown is `hidden md:flex` so it only shows on desktop. No mobile issue, but missing Escape handling is a usability gap.
|
|
154
|
+
|
|
155
|
+
**Recommendation:** Use `DropdownMenu` from shadcn/ui for built-in keyboard navigation and accessibility.
|
|
156
|
+
|
|
157
|
+
#### 7. Save As dialog: `filename` validation allows path traversal characters
|
|
158
|
+
|
|
159
|
+
**File:** `src/web/components/editor/save-as-dialog.tsx` line 27
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
if (/[/\\]/.test(trimmed)) { setError("Filename cannot contain / or \\"); return; }
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
This blocks slashes but allows other potentially problematic characters (`..`, null bytes, colons on Windows, etc.). The server-side `writeSystemFile` has `isAllowedPath` guard which mitigates exploitation, but client-side validation could be more robust.
|
|
166
|
+
|
|
167
|
+
**Recommendation:** Also reject filenames starting with `.` (hidden files), containing `..`, or with special chars like `:`, `*`, `?`, `"`, `<`, `>`, `|` (Windows-unsafe).
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### Low Priority
|
|
172
|
+
|
|
173
|
+
#### 8. Tab bar dropdown shortcut labels are hardcoded
|
|
174
|
+
|
|
175
|
+
**File:** `src/web/components/layout/tab-bar.tsx` lines 251-256
|
|
176
|
+
|
|
177
|
+
Shortcuts are hardcoded as strings (`"⌘L"`, `"⌘N"`, etc.) instead of reading from the keybindings store. If a user customizes their keybindings, the dropdown would show wrong shortcuts.
|
|
178
|
+
|
|
179
|
+
**Recommendation:** Use `formatCombo(getBinding("new-file"))` etc., matching the command palette's approach.
|
|
180
|
+
|
|
181
|
+
#### 9. Minor: `getNextUntitledNumber` is O(all tabs) on every new file creation
|
|
182
|
+
|
|
183
|
+
**File:** `src/web/stores/panel-utils.ts` lines 77-86
|
|
184
|
+
|
|
185
|
+
Scans all tabs in all panels to find max untitled number. Negligible with normal tab counts (< 100), but worth noting.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Positive Observations
|
|
190
|
+
|
|
191
|
+
- Clean separation: untitled logic in store, persistence in editor, UI in dialog
|
|
192
|
+
- `getNextUntitledNumber` correctly scans all panels (multi-panel aware)
|
|
193
|
+
- Server-side `isAllowedPath` guard protects Save As writes
|
|
194
|
+
- `deriveTabId` correctly handles the untitled pattern
|
|
195
|
+
- Multiple entry points (dropdown, Ctrl+N, command palette) all route through `openNewFile()` -- single source of truth
|
|
196
|
+
- Keyboard shortcut added to keybindings store (customizable)
|
|
197
|
+
- The `isUntitled` check in the file load effect correctly skips API call and restores from metadata
|
|
198
|
+
|
|
199
|
+
### Recommended Actions (Priority Order)
|
|
200
|
+
|
|
201
|
+
1. **[CRITICAL]** Clear `saveTimerRef` in `handleSaveAs` to prevent metadata race condition
|
|
202
|
+
2. **[CRITICAL]** Fix tab ID persistence after Save As -- either close+reopen or add a `replaceTabId` store method
|
|
203
|
+
3. **[HIGH]** Fix Ctrl+S Monaco binding to check current untitled state via ref, not mount-time closure
|
|
204
|
+
4. **[MEDIUM]** Consider using shadcn DropdownMenu for the tab bar "+" menu
|
|
205
|
+
5. **[LOW]** Read shortcut labels from keybindings store in tab bar dropdown
|
|
206
|
+
|
|
207
|
+
### Unresolved Questions
|
|
208
|
+
|
|
209
|
+
- Should there be a "close without saving" confirmation for untitled tabs with content? Currently closing an untitled tab silently discards content (metadata is removed, localStorage entry is gone). This could surprise users.
|
|
210
|
+
- Should the Save As dialog support saving within a project (relative paths) or only absolute paths? Currently it always uses `/api/fs/write` which writes to absolute paths. After Save As, the file is treated as an "external file" even if it's inside the active project directory.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.86] - 2026-04-15
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **Git Graph worktree management**: Toolbar popover with full CRUD — list worktrees with branch/hash/status badges, create (existing or new branch), remove, and prune stale entries. "Create Worktree Here..." in commit context menu.
|
|
7
|
+
- **Project auto-add for worktrees**: Opening a worktree not registered as a project prompts to add it automatically, then switches to it.
|
|
8
|
+
- **Extension project switching API**: `window.switchProject()` in vscode-compat allows extensions to trigger project switches via `project:switch` WS message.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Branch-already-exists dialog**: Creating a branch that exists now shows replace/cancel dialog instead of a generic error toast.
|
|
12
|
+
|
|
13
|
+
## [0.9.85] - 2026-04-14
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **New file editor tabs**: Create untitled editor tabs (Untitled-1, Untitled-2...) via Ctrl+N or Command Palette. Content persists in localStorage across sessions. Save As dialog on first Ctrl+S using file browser picker.
|
|
17
|
+
- **Right-click context menu on tabs**: Copy path, download, rename, delete files directly from tab context menu.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- **Markdown rendering migrated to react-markdown**: Replaced `marked` with `react-markdown` for better extensibility and React integration.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- **Upgrade dismiss persisted to sessionStorage**: Dismissed upgrade banner no longer reappears during same session.
|
|
24
|
+
- **WebSocket project path decoded for Windows**: Paths with special characters now work on Windows.
|
|
25
|
+
|
|
3
26
|
## [0.9.84] - 2026-04-13
|
|
4
27
|
|
|
5
28
|
### Fixed
|