@hienlh/ppm 0.20.10 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +108 -0
- package/CLAUDE.md +42 -1
- package/LICENSE +5 -0
- package/THIRD-PARTY-NOTICES.md +83 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/bun.lock +38 -7
- package/dist/web/assets/KaTeX_Size3-Regular-gV2CO0n9.woff2 +0 -0
- package/dist/web/assets/accounts-settings-section-BuxD9zH3.js +1 -0
- package/dist/web/assets/ai-resource-editor-F09pf8Hd.js +1 -0
- package/dist/web/assets/ai-settings-section-Dd9tOUp0.js +1 -0
- package/dist/web/assets/ai-settings-section-FrU2X8Fu.js +1 -0
- package/dist/web/assets/{angular-html-D4qjt-75.js → angular-html-DkR4iCth.js} +1 -1
- package/dist/web/assets/{angular-ts-DvLn04T8.js → angular-ts-DcyL4Chx.js} +1 -1
- package/dist/web/assets/api-client-BUCo1lms.js +1 -0
- package/dist/web/assets/{api-client-DCzgxFNY.js → api-client-bfB7cXRM.js} +1 -1
- package/dist/web/assets/{api-settings-t5xLrBkQ.js → api-settings-BcNjZIvG.js} +1 -1
- package/dist/web/assets/{api-themes-CJmyQeMk.js → api-themes-DBfyVUtX.js} +1 -1
- package/dist/web/assets/{apl-DQOoPzqd.js → apl-BVlrVtjt.js} +1 -1
- package/dist/web/assets/appearance-settings-section-whgnq3ss.js +1 -0
- package/dist/web/assets/architecture-PBZL5I3N-5K0wEkAn.js +1 -0
- package/dist/web/assets/{astro-C2zFJ1Er.js → astro-MjJlozLj.js} +1 -1
- package/dist/web/assets/audio-preview-Bc54GCAV.js +1 -0
- package/dist/web/assets/{blade-CBD8sEa1.js → blade-DnJWi1fz.js} +1 -1
- package/dist/web/assets/{bsl-bs2JpeTQ.js → bsl-DCmJxSIz.js} +1 -1
- package/dist/web/assets/{button-DHI8IY_N.js → button-VW4QGKCn.js} +1 -1
- package/dist/web/assets/{cairo-DT2g4i_6.js → cairo-C8dDenub.js} +1 -1
- package/dist/web/assets/chat-tab-Cr6_KSGO.js +15 -0
- package/dist/web/assets/{cobol-B2rp6LA1.js → cobol-DPx_nifl.js} +1 -1
- package/dist/web/assets/code-editor-DfmlGamv.js +7 -0
- package/dist/web/assets/codex-daily-guard-CfybHv_c.js +1 -0
- package/dist/web/assets/{coffee-D5ShQC08.js → coffee-DvFzqhgN.js} +1 -1
- package/dist/web/assets/conflict-editor-DenQUOT2.js +19 -0
- package/dist/web/assets/context-menu-DOODKZdF.js +1 -0
- package/dist/web/assets/{cpp-BmKOH-E0.js → cpp-BLJN0umi.js} +1 -1
- package/dist/web/assets/{createLucideIcon-CLMdC3Kl.js → createLucideIcon-DoiEKeJ_.js} +1 -1
- package/dist/web/assets/{crystal-B7u_ZTpu.js → crystal-BXR-9fGw.js} +1 -1
- package/dist/web/assets/csv-preview-CClrJOuR.js +2 -0
- package/dist/web/assets/{data-grid-overlay-editor-DJWgclot.js → data-grid-overlay-editor-D4fhcMfT.js} +1 -1
- package/dist/web/assets/{data-grid-types-Uu77aFvI.js → data-grid-types-OgUxMLdQ.js} +1 -1
- package/dist/web/assets/database-viewer-DItjm8wB.js +1 -0
- package/dist/web/assets/dialog-DQTn55Mt.js +1 -0
- package/dist/web/assets/diff-viewer-BpNj7pN9.js +4 -0
- package/dist/web/assets/{dist-BTdRgQig.js → dist-CrBOCtCW.js} +1 -1
- package/dist/web/assets/docx-preview-DYBkiUaE.js +12 -0
- package/dist/web/assets/{edge--MpXROh5.js → edge-rWOlCmXT.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-ESj6hMoD.js → edit-diff-preview-COtmo54G.js} +3 -3
- package/dist/web/assets/editor-font-BDrdiGf1.js +1 -0
- package/dist/web/assets/editor-language-service-DxkZ51E5.js +1 -0
- package/dist/web/assets/{elixir-DL8mOfzH.js → elixir-E7Y82okW.js} +1 -1
- package/dist/web/assets/{elm-eVlzIFEZ.js → elm-DTPGbc-w.js} +1 -1
- package/dist/web/assets/{erb-BgvaH9l0.js → erb-DHqLHrE6.js} +1 -1
- package/dist/web/assets/{erlang-CEf8Sfhs.js → erlang-Byg0nNiV.js} +1 -1
- package/dist/web/assets/{esm-C5xqy163.js → esm-D_DmOM7n.js} +2 -2
- package/dist/web/assets/explorer-body-D-5z464e.js +2 -0
- package/dist/web/assets/explorer-window-content-7-1wuRul.js +1 -0
- package/dist/web/assets/extension-manager-section-BhwB6nqr.js +1 -0
- package/dist/web/assets/extension-webview-DI4VL2tJ.js +12 -0
- package/dist/web/assets/file-icons-EzPL0q-k.js +1 -0
- package/dist/web/assets/file-icons.generated-CfaJuvZu.css +1 -0
- package/dist/web/assets/file-store-DMABxOkV.js +1 -0
- package/dist/web/assets/files-settings-section-CZzABuKz.js +1 -0
- package/dist/web/assets/format-file-meta-DOpzJJhS.js +1 -0
- package/dist/web/assets/{fortran-fixed-form-yAUsSjab.js → fortran-fixed-form-CY1n0Xf6.js} +1 -1
- package/dist/web/assets/{fsharp-BEWvY_ZR.js → fsharp-_vEDSCJz.js} +1 -1
- package/dist/web/assets/{gdresource-CYZFZ057.js → gdresource-B6XT0wAC.js} +1 -1
- package/dist/web/assets/geist-cyrillic-ext-wght-italic-BYAq_K0C.woff2 +0 -0
- package/dist/web/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/web/assets/geist-cyrillic-wght-italic-Da0gXVk3.woff2 +0 -0
- package/dist/web/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/web/assets/geist-latin-ext-wght-italic-XgKbg5n7.woff2 +0 -0
- package/dist/web/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/web/assets/geist-latin-wght-italic-dTnRTFFJ.woff2 +0 -0
- package/dist/web/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/web/assets/geist-vietnamese-wght-italic-0fly6zkB.woff2 +0 -0
- package/dist/web/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/web/assets/general-settings-section-BcxwiZ0X.js +1 -0
- package/dist/web/assets/{git-commit-DedchUJ6.js → git-commit-Wk9ovq59.js} +1 -1
- package/dist/web/assets/git-log-panel-CRN4JVOx.js +1 -0
- package/dist/web/assets/{git-rebase-DPvHNzQr.js → git-rebase-DSarGPvK.js} +1 -1
- package/dist/web/assets/git-repo-store-Dy69YCHN.js +1 -0
- package/dist/web/assets/gitGraph-HDMCJU4V-DkVT2MAM.js +1 -0
- package/dist/web/assets/glide-data-grid-BvgAqSUr.js +141 -0
- package/dist/web/assets/{glimmer-js-B4hPYBMX.js → glimmer-js-CkYI35_P.js} +1 -1
- package/dist/web/assets/{glimmer-ts-C0WfcQnO.js → glimmer-ts-BqmIZcds.js} +1 -1
- package/dist/web/assets/{glsl-DHW88hTv.js → glsl-Be-yBCF5.js} +1 -1
- package/dist/web/assets/{graphql-CEvXbo6e.js → graphql-a5DrENHY.js} +1 -1
- package/dist/web/assets/group-chat-tab-DFa5mAx5.js +1 -0
- package/dist/web/assets/{hack-lKfhn1vw.js → hack-BLAg20aD.js} +1 -1
- package/dist/web/assets/{haml-AjKlANaB.js → haml-Dj6bGOQH.js} +1 -1
- package/dist/web/assets/{handlebars-B8fZzj2G.js → handlebars-dmEa36Oh.js} +1 -1
- package/dist/web/assets/{html-derivative-VZmoMdQD.js → html-derivative-lLi3-RNT.js} +1 -1
- package/dist/web/assets/{html-H_S3FJMj.js → html-yacZYzSE.js} +1 -1
- package/dist/web/assets/{http-DBxROFKc.js → http-1KaxcE4e.js} +1 -1
- package/dist/web/assets/{hurl-Hf7XWQHN.js → hurl-ST-dEEZR.js} +1 -1
- package/dist/web/assets/{hxml-BRhRKwSo.js → hxml-CpDtuq__.js} +1 -1
- package/dist/web/assets/icons-DQjqk0lJ.js +1 -0
- package/dist/web/assets/image-preview-CJVxL0uH.js +1 -0
- package/dist/web/assets/index-D7DbXD3G.css +1 -0
- package/dist/web/assets/index-ZtfxZOyb.js +52 -0
- package/dist/web/assets/info-3K5VOQVL-BBsmKGzA.js +1 -0
- package/dist/web/assets/input-D-dR8RI6.js +1 -0
- package/dist/web/assets/{jinja-D3jMH0jG.js → jinja-Cjw-evAn.js} +1 -1
- package/dist/web/assets/{jira-watcher-section-DZvWeUAW.js → jira-watcher-section-DIC1yIV3.js} +1 -1
- package/dist/web/assets/{jison-CZtpkLiY.js → jison-DfATMYoY.js} +1 -1
- package/dist/web/assets/{julia-DwFjOpos.js → julia-DDCaxiqT.js} +1 -1
- package/dist/web/assets/{just-BEfj8dHN.js → just-CJL529u6.js} +1 -1
- package/dist/web/assets/keybindings-store-tVfhPANS.js +1 -0
- package/dist/web/assets/keyboard-shortcuts-section-BW03P3AF.js +1 -0
- package/dist/web/assets/{latex-C6Rb_zGG.js → latex-Zc4EpLpW.js} +1 -1
- package/dist/web/assets/{lib-CFTK00ux.js → lib-BVwmtv2i.js} +1 -1
- package/dist/web/assets/{liquid-DTVs9cD3.js → liquid-B_6KMNYS.js} +1 -1
- package/dist/web/assets/{lua-C1zfiqhG.js → lua-BtS2idK7.js} +1 -1
- package/dist/web/assets/markdown-renderer-CvL1pWeK.js +3 -0
- package/dist/web/assets/markdown-renderer-sJNNVhlS.js +1 -0
- package/dist/web/assets/{marko-_hrXozl2.js → marko-Wk6LBnck.js} +1 -1
- package/dist/web/assets/{mdc-AX9XWu8K.js → mdc-cRaXBrzL.js} +1 -1
- package/dist/web/assets/{media-url-D43IHXnP.js → media-url-DL8OCGGg.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-GSto0_0m.js → mobile-bottom-sheet-CoUauvLF.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-CZ0HZ2E_.js +1 -0
- package/dist/web/assets/monaco-dotenv-language-BDYnKcnr.js +1 -0
- package/dist/web/assets/monaspace-argon-latin-400-italic-DHf095HZ.woff2 +0 -0
- package/dist/web/assets/monaspace-argon-latin-400-italic-DZMiIHEH.woff +0 -0
- package/dist/web/assets/monaspace-argon-latin-400-normal-DZUN4ACH.woff +0 -0
- package/dist/web/assets/monaspace-argon-latin-400-normal-RS-2TGNg.woff2 +0 -0
- package/dist/web/assets/monaspace-argon-latin-700-normal-4y--rLW1.woff +0 -0
- package/dist/web/assets/monaspace-argon-latin-700-normal-D9kWRRK5.woff2 +0 -0
- package/dist/web/assets/monaspace-krypton-latin-400-italic-BoBCEexI.woff2 +0 -0
- package/dist/web/assets/monaspace-krypton-latin-400-italic-LWEicbvC.woff +0 -0
- package/dist/web/assets/monaspace-krypton-latin-400-normal-D9XlxC9R.woff +0 -0
- package/dist/web/assets/monaspace-krypton-latin-400-normal-DsuVXUab.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-codicons-DSvMY_FK.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-devicons-BBab8P54.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-font-awesome-BzNW1pRA.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-font-awesome-ext-D30e--UY.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-font-awesome-legacy-D_qekXx9.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-font-logos-gdu3INfy.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-iec-power-Cw6TNeDf.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-material-l-CXi9Ay.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-misc-BaVfdyeB.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-octicons-CJLTTzKm.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-pomicons-D7T3Ya3H.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-powerline-Cgg0sdGS.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-seti-DYiUFq6z.woff2 +0 -0
- package/dist/web/assets/nerd-symbols-weather-D4Jrp5XD.woff2 +0 -0
- package/dist/web/assets/{nextflow-xJ5dkaQ2.js → nextflow-Bos2wvDV.js} +1 -1
- package/dist/web/assets/{nginx-BfbjvmIV.js → nginx-DMlOwzdr.js} +1 -1
- package/dist/web/assets/{nim-KrUnNSwZ.js → nim-D2dZQA88.js} +1 -1
- package/dist/web/assets/notification-store-BZbsPnW0.js +1 -0
- package/dist/web/assets/notifications-settings-section-DPUROMw-.js +1 -0
- package/dist/web/assets/{number-overlay-editor-CGZ1ObrN.js → number-overlay-editor-DZ2i_Bnb.js} +1 -1
- package/dist/web/assets/{overview-panel-Ni1Wqr3E.js → overview-panel-R146OIom.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-DwmYPOlx.js +1 -0
- package/dist/web/assets/panel-store-BVLBRn6M.js +1 -0
- package/dist/web/assets/pdf-preview-BWUPGLp6.js +1 -0
- package/dist/web/assets/{perl-DAexWIeo.js → perl-C5-Z6fPn.js} +1 -1
- package/dist/web/assets/{php-DXc7GdU9.js → php-BXNNhkMH.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-D0oogIFi.js +1 -0
- package/dist/web/assets/portal-container-context-BarKmT4S.js +1 -0
- package/dist/web/assets/{postgres-viewer-DmbVhmJ8.js → postgres-viewer-CjOvaruz.js} +3 -3
- package/dist/web/assets/ppmbot-settings-section-DrvWh8l8.js +1 -0
- package/dist/web/assets/problems-panel-B7BWVhdy.js +1 -0
- package/dist/web/assets/process-table-BRMS1MrX.js +1 -0
- package/dist/web/assets/{project-store-DCDLF-x3.js → project-store-BhMbVln3.js} +1 -1
- package/dist/web/assets/proxy-settings-section-Bv0Ny-Yy.js +1 -0
- package/dist/web/assets/{pug-CHds8FDl.js → pug-C1zf1yWy.js} +1 -1
- package/dist/web/assets/{qml-DBt6oNnU.js → qml-OW58jGpD.js} +1 -1
- package/dist/web/assets/query-audit-section-BcHJZcVC.js +1 -0
- package/dist/web/assets/radar-KQ55EAFF-CQIJOQGa.js +1 -0
- package/dist/web/assets/{razor-DVDe2z8Z.js → razor-DzjSaobM.js} +1 -1
- package/dist/web/assets/{react-Bf5xrFLG.js → react-Bghu0NUO.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-ByjaeZKX.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-view-D13mtr9F.js +1 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BTzss2wX.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-CbqTCaC6.js +1 -0
- package/dist/web/assets/{rst-s3rP0H8p.js → rst-RfuihOUW.js} +1 -1
- package/dist/web/assets/{ruby-sRcfbjlr.js → ruby-CNO3pli1.js} +1 -1
- package/dist/web/assets/{run-in-terminal-Yt_lq4T9.js → run-in-terminal-Cb_hVU8x.js} +1 -1
- package/dist/web/assets/{sas-CuyZeQJw.js → sas-DZY5BtXx.js} +1 -1
- package/dist/web/assets/schedules-settings-section-DO8xAOVj.js +1 -0
- package/dist/web/assets/scroll-area-LtNV8g5o.js +1 -0
- package/dist/web/assets/{scss-B9m4FneT.js → scss--4g-REcN.js} +1 -1
- package/dist/web/assets/{send-to-chat-01eMNs3j.js → send-to-chat-Cnpru1M0.js} +1 -1
- package/dist/web/assets/separator-Cds1yxy8.js +1 -0
- package/dist/web/assets/settings-body-Rnu-FcX-.js +2 -0
- package/dist/web/assets/settings-store-DZPgPtEA.js +2 -0
- package/dist/web/assets/settings-tab-C6PHxs0Z.js +1 -0
- package/dist/web/assets/settings-window-content-CQ4gT2qj.js +1 -0
- package/dist/web/assets/{shaderlab-BuCltaXx.js → shaderlab-Cu4sBiVn.js} +1 -1
- package/dist/web/assets/{shellsession-DG_WIFRW.js → shellsession-DWzJfEv7.js} +1 -1
- package/dist/web/assets/{soy-CKNCwmqR.js → soy-BnqE-5Ff.js} +1 -1
- package/dist/web/assets/{sparql-BEH92-9e.js → sparql-Ctg__NhZ.js} +1 -1
- package/dist/web/assets/{sql-query-editor-BTMEy88p.js → sql-query-editor-D9k19T_M.js} +1 -1
- package/dist/web/assets/sqlite-viewer-DoV9hnWJ.js +1 -0
- package/dist/web/assets/{stata-Bt5IUWCl.js → stata-Qk2h66XW.js} +1 -1
- package/dist/web/assets/{streaming-store-Dw3ZR1E4.js → streaming-store-uDu3PoN1.js} +1 -1
- package/dist/web/assets/{surrealql-B5M94PT2.js → surrealql-8QEX7EfH.js} +1 -1
- package/dist/web/assets/{svelte-BqLoF5fB.js → svelte-D_mubC5-.js} +1 -1
- package/dist/web/assets/system-monitor-body-2vQ1kMxE.js +2 -0
- package/dist/web/assets/system-monitor-tab-krAcvwF7.js +1 -0
- package/dist/web/assets/system-monitor-window-content-qXLcicFM.js +1 -0
- package/dist/web/assets/tab-host-window-content-7fPZNEni.js +1 -0
- package/dist/web/assets/{tab-store-Dsk4jnlN.js → tab-store-DGJGnbwv.js} +1 -1
- package/dist/web/assets/team-member-sheet-2FnRmk1a.js +2 -0
- package/dist/web/assets/team-member-window-content-BgvJFypM.js +1 -0
- package/dist/web/assets/{templ-BxGWIwYz.js → templ-C1jV0fsO.js} +1 -1
- package/dist/web/assets/terminal-tab-Cs0sGljx.js +3 -0
- package/dist/web/assets/{tex-B9CPrNBA.js → tex-D_StFXy_.js} +1 -1
- package/dist/web/assets/tool-cards-DU_S2o51.js +9 -0
- package/dist/web/assets/treemap-KZPCXAKY-BhEtjljr.js +1 -0
- package/dist/web/assets/{ts-tags-CObhnP_s.js → ts-tags-B5m47rEm.js} +1 -1
- package/dist/web/assets/{twig-ZcDaz0E8.js → twig-C_br6GIl.js} +1 -1
- package/dist/web/assets/{use-blob-url-D-NnFGAr.js → use-blob-url-C-SGi_Hb.js} +1 -1
- package/dist/web/assets/use-inline-blame-B4trxGcR.js +16 -0
- package/dist/web/assets/{use-is-mobile-BsqeOLv4.js → use-is-mobile-BQ9Bv5Ga.js} +1 -1
- package/dist/web/assets/use-lsp-CV0vzILO.js +6 -0
- package/dist/web/assets/use-monaco-theme-DBqbWjWX.js +1 -0
- package/dist/web/assets/use-open-team-member-DENsjp0s.js +1 -0
- package/dist/web/assets/use-remote-desktop-display-choice-BK_f787P.js +1 -0
- package/dist/web/assets/{use-visual-viewport-hdC_hRtB.js → use-visual-viewport-CbwnktSG.js} +1 -1
- package/dist/web/assets/{use-websocket-CUKjQFAl.js → use-websocket-LgXiX1qN.js} +1 -1
- package/dist/web/assets/vendor-markdown-CuWCHIVb.js +291 -0
- package/dist/web/assets/{vendor-mermaid-BoRFiriK.js → vendor-mermaid-Cbig5zA6.js} +1 -1
- package/dist/web/assets/{vendor-ui-D1NQnrtd.js → vendor-ui-BBdkypKW.js} +1 -1
- package/dist/web/assets/video-preview-BDNwumbW.js +1 -0
- package/dist/web/assets/{vue-TgfQfAF8.js → vue-DQwCnLdr.js} +1 -1
- package/dist/web/assets/{vue-html-DbAh9aHW.js → vue-html-T_EoGpPJ.js} +1 -1
- package/dist/web/assets/{vue-vine-DQ8US6vO.js → vue-vine-DmxLqX50.js} +1 -1
- package/dist/web/assets/{window-pip-registry-DfPfSFQg.js → window-pip-registry-3l4hoxuD.js} +1 -1
- package/dist/web/assets/{window-store-BSXqIkwB.js → window-store-UC1jJeLM.js} +1 -1
- package/dist/web/assets/ws-auth-DEAJiGCR.js +1 -0
- package/dist/web/assets/{xml-CXzUNYMl.js → xml-Bs6Bw8is.js} +1 -1
- package/dist/web/assets/{xsl-CdnFww1s.js → xsl-f5ZNhRCc.js} +1 -1
- package/dist/web/index.html +107 -73
- package/dist/web/sw.js +1 -1
- package/docs/project-roadmap.md +2 -0
- package/licenses/Apache-2.0.txt +73 -0
- package/licenses/CC-BY-4.0.txt +156 -0
- package/licenses/MIT.txt +18 -0
- package/licenses/OFL-1.1.txt +43 -0
- package/licenses/Unlicense.txt +10 -0
- package/package.json +14 -7
- package/packages/ext-git-graph/src/blame-view.ts +4 -5
- package/packages/ext-git-graph/src/commit-detail-escaping.test.ts +205 -0
- package/packages/ext-git-graph/src/commit-detail-file-cap.test.ts +65 -0
- package/packages/ext-git-graph/src/commit-message-html.test.ts +214 -0
- package/packages/ext-git-graph/src/commit-message-html.ts +190 -0
- package/packages/ext-git-graph/src/commit-request-generation.test.ts +57 -0
- package/packages/ext-git-graph/src/compare-view.ts +4 -5
- package/packages/ext-git-graph/src/extension.ts +148 -36
- package/packages/ext-git-graph/src/file-history-view.ts +4 -5
- package/packages/ext-git-graph/src/log-args.test.ts +57 -0
- package/packages/ext-git-graph/src/ppm-api.ts +39 -6
- package/packages/ext-git-graph/src/project-scope.test.ts +77 -0
- package/packages/ext-git-graph/src/project-scope.ts +69 -0
- package/packages/ext-git-graph/src/shortstat-parser.test.ts +53 -0
- package/packages/ext-git-graph/src/shortstat-parser.ts +45 -0
- package/packages/ext-git-graph/src/types.ts +2 -0
- package/packages/ext-git-graph/src/webview-html.test.ts +407 -0
- package/packages/ext-git-graph/src/webview-html.ts +631 -108
- package/packages/ext-git-graph/src/webview-shell.test.ts +63 -0
- package/packages/ext-git-graph/src/webview-shell.ts +48 -7
- package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
- package/scripts/check-ppm-dir-usage.sh +0 -0
- package/scripts/copy-monaco.ts +63 -0
- package/scripts/gen-file-icons.ts +485 -0
- package/scripts/gen-nerd-font.ts +311 -0
- package/scripts/gen-product-icons.ts +442 -0
- package/scripts/install.sh +0 -0
- package/scripts/monaco-staging.ts +32 -0
- package/scripts/precompress-web.ts +77 -0
- package/scripts/release.sh +0 -0
- package/scripts/third-party-notices.ts +160 -0
- package/scripts/vite-monaco-dev-assets.ts +63 -0
- package/src/providers/claude-agent-sdk.ts +32 -2
- package/src/server/index.ts +17 -0
- package/src/server/routes/chat.ts +16 -6
- package/src/server/routes/git.ts +113 -1
- package/src/server/routes/lsp.ts +58 -0
- package/src/server/routes/project-scoped.ts +2 -0
- package/src/server/routes/static-encoding.ts +73 -0
- package/src/server/routes/static-fallback.ts +51 -0
- package/src/server/routes/static.ts +41 -5
- package/src/server/ws/lsp.ts +433 -0
- package/src/services/chat-search.service.ts +211 -26
- package/src/services/edge-forwarder.ts +191 -191
- package/src/services/fs-ops/fs-real-path.ts +23 -0
- package/src/services/git-blame/commit-line-diff.ts +124 -0
- package/src/services/git-blame/git-blame.service.ts +96 -1
- package/src/services/git-repos/git-repo-discovery.ts +152 -0
- package/src/services/lsp/lsp-capabilities.ts +160 -0
- package/src/services/lsp/lsp-manager.ts +442 -0
- package/src/services/lsp/lsp-protocol.ts +170 -0
- package/src/services/lsp/lsp-session.ts +466 -0
- package/src/services/lsp/server-registry.ts +401 -0
- package/src/services/search-index-db.service.ts +10 -2
- package/src/services/windows-process-tree.ts +351 -351
- package/src/shared/blame.ts +51 -0
- package/src/shared/lsp-uri.ts +108 -0
- package/src/web/app.tsx +6 -0
- package/src/web/components/ai-resources/ai-resource-editor.tsx +1 -1
- package/src/web/components/ai-resources/ai-resources-panel.tsx +1 -1
- package/src/web/components/ai-resources/mcp-group.tsx +1 -1
- package/src/web/components/ai-resources/new-resource-menu.tsx +1 -1
- package/src/web/components/ai-resources/resource-visuals.tsx +1 -1
- package/src/web/components/auth/login-screen.tsx +1 -1
- package/src/web/components/auth/support-dialog.tsx +1 -1
- package/src/web/components/chat/attachment-chips.tsx +113 -5
- package/src/web/components/chat/background-command-bar.tsx +1 -1
- package/src/web/components/chat/background-output-panel.tsx +1 -1
- package/src/web/components/chat/change-edit-list.tsx +1 -1
- package/src/web/components/chat/change-file-row.tsx +1 -1
- package/src/web/components/chat/chat-history-bar.tsx +2 -2
- package/src/web/components/chat/chat-history-panel.tsx +1 -1
- package/src/web/components/chat/chat-placeholder.tsx +1 -1
- package/src/web/components/chat/chat-scroll-nav.tsx +1 -1
- package/src/web/components/chat/chat-tab.tsx +1 -1
- package/src/web/components/chat/chat-toolbar-overflow-menu.tsx +1 -1
- package/src/web/components/chat/chat-welcome.tsx +1 -1
- package/src/web/components/chat/codex-usage-panel.tsx +1 -1
- package/src/web/components/chat/file-picker.tsx +1 -1
- package/src/web/components/chat/image-preview-states.tsx +1 -1
- package/src/web/components/chat/message-action-bar.tsx +1 -1
- package/src/web/components/chat/message-input.tsx +1 -1
- package/src/web/components/chat/message-list.tsx +1 -1
- package/src/web/components/chat/mode-selector.tsx +1 -1
- package/src/web/components/chat/model-selector.tsx +1 -1
- package/src/web/components/chat/model-thinking-selector.tsx +1 -1
- package/src/web/components/chat/pre-compact-button.tsx +1 -1
- package/src/web/components/chat/provider-selector.tsx +1 -1
- package/src/web/components/chat/send-message-card.tsx +1 -1
- package/src/web/components/chat/session-context-menu.tsx +1 -1
- package/src/web/components/chat/session-debug-dialog.tsx +1 -1
- package/src/web/components/chat/session-history-list.tsx +1 -1
- package/src/web/components/chat/session-list-panel.tsx +1 -1
- package/src/web/components/chat/session-picker.tsx +1 -1
- package/src/web/components/chat/slash-command-picker.tsx +1 -1
- package/src/web/components/chat/task-tracker.tsx +1 -1
- package/src/web/components/chat/team-activity-panel.tsx +1 -1
- package/src/web/components/chat/team-member-activity-row.tsx +1 -1
- package/src/web/components/chat/team-member-list.tsx +1 -1
- package/src/web/components/chat/team-member-sheet.tsx +1 -1
- package/src/web/components/chat/team-member-window-content.tsx +1 -1
- package/src/web/components/chat/team-working-bar.tsx +1 -1
- package/src/web/components/chat/tool-cards.tsx +2 -2
- package/src/web/components/chat/turn-change-sheet.tsx +1 -1
- package/src/web/components/chat/turn-change-tray.tsx +1 -1
- package/src/web/components/chat/turn-cost-warning.tsx +1 -1
- package/src/web/components/chat/usage-badge.tsx +1 -1
- package/src/web/components/chat/usage-panel-shell.tsx +1 -1
- package/src/web/components/chat/version-switcher.tsx +1 -1
- package/src/web/components/database/connection-import-export.tsx +1 -1
- package/src/web/components/database/connection-list.tsx +1 -1
- package/src/web/components/database/connection-row.tsx +1 -1
- package/src/web/components/database/database-sidebar.tsx +1 -1
- package/src/web/components/database/database-viewer.tsx +1 -1
- package/src/web/components/database/export-button.tsx +1 -1
- package/src/web/components/database/glide-context-menu.tsx +1 -1
- package/src/web/components/database/glide-data-grid.tsx +1 -1
- package/src/web/components/database/glide-data-preview-panel.tsx +2 -2
- package/src/web/components/database/glide-grid-pagination.tsx +1 -1
- package/src/web/components/database/glide-grid-toolbar.tsx +1 -1
- package/src/web/components/database/glide-header-menu.tsx +1 -1
- package/src/web/components/database/glide-save-bar.tsx +1 -1
- package/src/web/components/database/schema-table-tree.tsx +1 -1
- package/src/web/components/editor/audio-preview.tsx +1 -1
- package/src/web/components/editor/code-editor.tsx +167 -21
- package/src/web/components/editor/compare-picker.tsx +1 -1
- package/src/web/components/editor/conflict-editor.tsx +15 -6
- package/src/web/components/editor/csv-preview.tsx +1 -1
- package/src/web/components/editor/diff-viewer.tsx +59 -37
- package/src/web/components/editor/docx-preview.tsx +1 -1
- package/src/web/components/editor/editor-breadcrumb-external.tsx +1 -1
- package/src/web/components/editor/editor-breadcrumb.tsx +1 -1
- package/src/web/components/editor/editor-language-picker.tsx +3 -1
- package/src/web/components/editor/editor-language-service.tsx +77 -0
- package/src/web/components/editor/editor-mobile-toolbar.tsx +13 -2
- package/src/web/components/editor/editor-placeholder.tsx +1 -1
- package/src/web/components/editor/editor-toolbar.tsx +1 -1
- package/src/web/components/editor/image-preview.tsx +1 -1
- package/src/web/components/editor/lsp-status.tsx +241 -0
- package/src/web/components/editor/pdf-preview.tsx +1 -1
- package/src/web/components/editor/video-player/video-player-controls.tsx +1 -1
- package/src/web/components/editor/video-player/video-player.tsx +1 -1
- package/src/web/components/editor/video-player/video-settings-menu.tsx +1 -1
- package/src/web/components/editor/video-preview.tsx +1 -1
- package/src/web/components/explorer/file-tree.tsx +1 -1
- package/src/web/components/explorer/inline-tree-input.tsx +1 -1
- package/src/web/components/explorer/search-panel.tsx +3 -2
- package/src/web/components/explorer/tree-node-context-menu.tsx +1 -1
- package/src/web/components/explorer/tree-node.tsx +5 -12
- package/src/web/components/extensions/extension-quickpick.tsx +1 -1
- package/src/web/components/extensions/extension-tree-view.tsx +1 -1
- package/src/web/components/extensions/extension-webview.tsx +53 -20
- package/src/web/components/extensions/webview-theme.ts +121 -0
- package/src/web/components/floating-window/pip/pip-caption-button.tsx +1 -1
- package/src/web/components/git/create-worktree-dialog.tsx +5 -3
- package/src/web/components/git/git-log-panel.tsx +4 -2
- package/src/web/components/git/git-placeholder.tsx +1 -1
- package/src/web/components/git/git-ref-badge.tsx +1 -1
- package/src/web/components/git/git-repo-picker.tsx +145 -0
- package/src/web/components/git/git-status-panel.tsx +231 -250
- package/src/web/components/git/git-worktree-panel.tsx +6 -4
- package/src/web/components/git/hunk-stage-dialog.tsx +5 -3
- package/src/web/components/group-chat/group-chat-tab.tsx +1 -1
- package/src/web/components/group-chat/group-create-dialog.tsx +1 -1
- package/src/web/components/group-chat/group-full-transcript-view.tsx +1 -1
- package/src/web/components/group-chat/group-list.tsx +1 -1
- package/src/web/components/group-chat/group-member-edit-dialog.tsx +1 -1
- package/src/web/components/group-chat/group-member-roster.tsx +1 -1
- package/src/web/components/group-chat/group-message-item.tsx +1 -1
- package/src/web/components/group-chat/group-transcript-messages.tsx +1 -1
- package/src/web/components/jira/jira-config-form.tsx +1 -1
- package/src/web/components/jira/jira-filter-builder.tsx +1 -1
- package/src/web/components/jira/jira-panel.tsx +1 -1
- package/src/web/components/jira/jira-results-panel.tsx +1 -1
- package/src/web/components/jira/jira-ticket-card.tsx +1 -1
- package/src/web/components/jira/jira-ticket-detail.tsx +1 -1
- package/src/web/components/jira/jira-watcher-form.tsx +1 -1
- package/src/web/components/jira/jira-watcher-list.tsx +1 -1
- package/src/web/components/layout/add-project-form.tsx +1 -1
- package/src/web/components/layout/cloud-alias-row.tsx +1 -1
- package/src/web/components/layout/cloud-share-named-tunnel-row.tsx +1 -1
- package/src/web/components/layout/cloud-share-popover.tsx +1 -1
- package/src/web/components/layout/command-palette-filter-chips.tsx +1 -1
- package/src/web/components/layout/command-palette.tsx +46 -8
- package/src/web/components/layout/dock-header.tsx +4 -4
- package/src/web/components/layout/dock-panel.tsx +3 -3
- package/src/web/components/layout/draggable-tab.tsx +20 -3
- package/src/web/components/layout/editor-panel.tsx +1 -1
- package/src/web/components/layout/mobile-drawer-tab-bar.tsx +10 -1
- package/src/web/components/layout/mobile-drawer.tsx +1 -1
- package/src/web/components/layout/mobile-nav.tsx +3 -3
- package/src/web/components/layout/mobile-tab-switcher-sheet.tsx +13 -4
- package/src/web/components/layout/nav-section-rail.tsx +1 -1
- package/src/web/components/layout/notification-bell-popover.tsx +1 -1
- package/src/web/components/layout/panel-layout.tsx +1 -1
- package/src/web/components/layout/project-bottom-sheet.tsx +4 -1
- package/src/web/components/layout/project-sort.ts +1 -1
- package/src/web/components/layout/project-switcher.tsx +1 -1
- package/src/web/components/layout/reparenting-tab.tsx +1 -1
- package/src/web/components/layout/sidebar.tsx +1 -1
- package/src/web/components/layout/status-bar.tsx +4 -1
- package/src/web/components/layout/tab-bar.tsx +9 -23
- package/src/web/components/layout/tab-content.tsx +6 -1
- package/src/web/components/layout/tab-pool.tsx +1 -0
- package/src/web/components/layout/tab-pop-out-menu-item.tsx +1 -1
- package/src/web/components/layout/upgrade-button.tsx +1 -1
- package/src/web/components/layout/wake-lock-indicator.tsx +1 -1
- package/src/web/components/os-explorer/explorer-body.tsx +1 -1
- package/src/web/components/os-explorer/explorer-breadcrumb.tsx +1 -1
- package/src/web/components/os-explorer/explorer-sidebar.tsx +1 -1
- package/src/web/components/os-explorer/explorer-sort-menu.tsx +1 -1
- package/src/web/components/os-explorer/explorer-toolbar.tsx +1 -1
- package/src/web/components/os-explorer/icons/file-type-icon-map.ts +10 -94
- package/src/web/components/os-explorer/icons/file-type-icon.tsx +17 -13
- package/src/web/components/os-explorer/mobile/mobile-bottom-toolbar.tsx +1 -1
- package/src/web/components/os-explorer/mobile/mobile-explorer-top-bar.tsx +1 -1
- package/src/web/components/os-explorer/mobile/mobile-more-sheet.tsx +1 -1
- package/src/web/components/os-explorer/mobile/mobile-places-sheet.tsx +1 -1
- package/src/web/components/os-explorer/mobile/mobile-places-strip.tsx +1 -1
- package/src/web/components/os-explorer/properties-dialog.tsx +1 -1
- package/src/web/components/os-explorer/skins/macos-window-chrome.tsx +1 -1
- package/src/web/components/os-explorer/skins/windows-window-chrome.tsx +1 -1
- package/src/web/components/os-explorer/upload/upload-batch-card.tsx +1 -1
- package/src/web/components/os-explorer/upload/upload-batch-row.tsx +1 -1
- package/src/web/components/os-explorer/use-coarse-long-press.ts +8 -0
- package/src/web/components/os-explorer/views/column-view-mobile.tsx +1 -1
- package/src/web/components/os-explorer/views/icons-view-tile.tsx +1 -1
- package/src/web/components/os-explorer/views/list-row.tsx +1 -1
- package/src/web/components/os-explorer/views/list-view.tsx +1 -1
- package/src/web/components/postgres/postgres-viewer.tsx +1 -1
- package/src/web/components/problems/problems-panel.tsx +230 -0
- package/src/web/components/problems/problems-status.tsx +53 -0
- package/src/web/components/projects/dir-suggest.tsx +1 -1
- package/src/web/components/projects/project-list.tsx +1 -1
- package/src/web/components/remote-desktop/remote-desktop-mobile-toolbar.tsx +1 -1
- package/src/web/components/remote-desktop/remote-desktop-mobile-view.tsx +1 -1
- package/src/web/components/remote-desktop/remote-desktop-readiness-gate.tsx +1 -1
- package/src/web/components/remote-desktop/remote-desktop-warning-gate.tsx +1 -1
- package/src/web/components/remote-desktop/remote-desktop-window-content.tsx +1 -1
- package/src/web/components/root-error-boundary.tsx +116 -0
- package/src/web/components/settings/accounts/account-add-dialog.tsx +1 -1
- package/src/web/components/settings/accounts/account-card.tsx +1 -1
- package/src/web/components/settings/accounts/account-export-dialog.tsx +1 -1
- package/src/web/components/settings/accounts/account-export-simulation.tsx +1 -1
- package/src/web/components/settings/accounts/account-import-dialog.tsx +1 -1
- package/src/web/components/settings/accounts/account-profile-panel.tsx +1 -1
- package/src/web/components/settings/accounts/account-rotation-settings.tsx +1 -1
- package/src/web/components/settings/accounts/account-token-test-dialog.tsx +1 -1
- package/src/web/components/settings/accounts/account-usage-pattern-chart.tsx +1 -1
- package/src/web/components/settings/accounts/accounts-pane-header.tsx +1 -1
- package/src/web/components/settings/accounts/accounts-settings-section.tsx +1 -1
- package/src/web/components/settings/accounts/claude-accounts-section.tsx +9 -1
- package/src/web/components/settings/accounts/codex-accounts-section.tsx +10 -1
- package/src/web/components/settings/accounts/codex-add-account-dialog.tsx +1 -1
- package/src/web/components/settings/accounts/codex-backup-dialog.tsx +1 -1
- package/src/web/components/settings/ai-settings-section.tsx +1 -1
- package/src/web/components/settings/appearance-settings-section.tsx +56 -1
- package/src/web/components/settings/change-password-section.tsx +1 -1
- package/src/web/components/settings/extension-manager-section.tsx +1 -1
- package/src/web/components/settings/general-settings-section.tsx +1 -1
- package/src/web/components/settings/glob-list-editor.tsx +1 -1
- package/src/web/components/settings/keyboard-shortcuts-section.tsx +1 -1
- package/src/web/components/settings/mcp-server-dialog.tsx +1 -1
- package/src/web/components/settings/notifications-settings-section.tsx +1 -1
- package/src/web/components/settings/ppmbot-settings-section.tsx +1 -1
- package/src/web/components/settings/proxy-settings-section.tsx +1 -1
- package/src/web/components/settings/proxy-test-section.tsx +1 -1
- package/src/web/components/settings/query-audit-section.tsx +1 -1
- package/src/web/components/settings/schedules/schedule-row.tsx +1 -1
- package/src/web/components/settings/schedules/schedules-settings-section.tsx +1 -1
- package/src/web/components/settings/settings-body.tsx +1 -1
- package/src/web/components/settings/settings-categories.ts +14 -3
- package/src/web/components/settings/settings-category-list.tsx +1 -1
- package/src/web/components/settings/settings-section-content.tsx +1 -1
- package/src/web/components/settings/tag-settings-section.tsx +1 -1
- package/src/web/components/settings/theme-grid.tsx +1 -1
- package/src/web/components/settings/theme-manager-section.tsx +1 -1
- package/src/web/components/settings/theme-picker.tsx +1 -1
- package/src/web/components/shared/bug-report-popup.tsx +1 -1
- package/src/web/components/shared/connection-lost-overlay.tsx +1 -1
- package/src/web/components/shared/diagram-overlay.tsx +1 -1
- package/src/web/components/shared/image-overlay.tsx +1 -1
- package/src/web/components/shared/theme-mode-menu.tsx +1 -1
- package/src/web/components/sqlite/sqlite-data-grid.tsx +1 -1
- package/src/web/components/sqlite/sqlite-table-list.tsx +1 -1
- package/src/web/components/sqlite/sqlite-viewer.tsx +1 -1
- package/src/web/components/system/process-group-row.tsx +1 -1
- package/src/web/components/system/process-row.tsx +1 -1
- package/src/web/components/system/process-table-toolbar.tsx +1 -1
- package/src/web/components/system/resource-status-bar.tsx +1 -1
- package/src/web/components/system/sortable-header.tsx +1 -1
- package/src/web/components/system/system-monitor-body.tsx +1 -1
- package/src/web/components/terminal/terminal-finish-login.tsx +1 -1
- package/src/web/components/terminal/terminal-links-sheet.tsx +1 -1
- package/src/web/components/terminal/terminal-mobile-toolbar.tsx +1 -1
- package/src/web/components/terminal/terminal-placeholder.tsx +1 -1
- package/src/web/components/terminal/terminal-tab.tsx +1 -1
- package/src/web/components/tunnels/named-tunnel/named-tunnel-login-step.tsx +1 -1
- package/src/web/components/tunnels/named-tunnel/named-tunnel-section.tsx +1 -1
- package/src/web/components/tunnels/named-tunnel/named-tunnel-setup-content.tsx +1 -1
- package/src/web/components/tunnels/named-tunnel/named-tunnel-setup-popup.tsx +1 -1
- package/src/web/components/tunnels/tunnel-manager-tab.tsx +1 -1
- package/src/web/components/ui/accordion.tsx +1 -1
- package/src/web/components/ui/adaptive-context-menu.tsx +9 -2
- package/src/web/components/ui/browse-button.tsx +1 -1
- package/src/web/components/ui/context-menu.tsx +1 -1
- package/src/web/components/ui/dialog.tsx +1 -1
- package/src/web/components/ui/dropdown-menu.tsx +1 -1
- package/src/web/components/ui/file-browser-picker.tsx +4 -6
- package/src/web/components/ui/select.tsx +1 -1
- package/src/web/components/ui/sidebar-header.tsx +1 -1
- package/src/web/components/ui/sonner.tsx +1 -1
- package/src/web/hooks/use-git-repo.ts +124 -0
- package/src/web/hooks/use-global-keybindings.ts +11 -6
- package/src/web/hooks/use-inline-blame.ts +161 -11
- package/src/web/hooks/use-is-touch-only.ts +46 -0
- package/src/web/hooks/use-lsp.ts +182 -0
- package/src/web/hooks/use-terminal.ts +60 -2
- package/src/web/hooks/use-touch-tab-drag.ts +18 -2
- package/src/web/hooks/use-url-sync.ts +15 -1
- package/src/web/index.html +74 -0
- package/src/web/lib/blame-hover-commands.ts +82 -0
- package/src/web/lib/blame-hover.ts +199 -0
- package/src/web/lib/chunk-recovery.ts +113 -0
- package/src/web/lib/editor-font.ts +70 -0
- package/src/web/lib/ext-command-dispatch.ts +24 -0
- package/src/web/lib/file-icons.generated.ts +408 -0
- package/src/web/lib/file-icons.tsx +192 -0
- package/src/web/lib/fluent-icon.tsx +62 -0
- package/src/web/lib/git-file-tree.ts +83 -0
- package/src/web/lib/git-repo-scope.ts +157 -0
- package/src/web/lib/icons.generated.tsx +428 -0
- package/src/web/lib/icons.ts +17 -0
- package/src/web/lib/lsp/lsp-client.ts +321 -0
- package/src/web/lib/lsp/lsp-documents.ts +39 -0
- package/src/web/lib/lsp/lsp-monaco.ts +214 -0
- package/src/web/lib/lsp/lsp-navigation.ts +129 -0
- package/src/web/lib/lsp/lsp-responses.ts +244 -0
- package/src/web/lib/lsp/lsp-semantic-tokens.ts +180 -0
- package/src/web/lib/lsp/lsp-shadow-models.ts +254 -0
- package/src/web/lib/lsp/monaco-builtin-typescript.ts +149 -0
- package/src/web/lib/lsp/register-providers.ts +458 -0
- package/src/web/lib/monaco-diff-language.ts +62 -0
- package/src/web/lib/monaco-dotenv-language.ts +134 -0
- package/src/web/lib/sidebar-tabs/tab-registry.ts +11 -2
- package/src/web/lib/tab-type-icons.ts +32 -4
- package/src/web/main.tsx +30 -1
- package/src/web/stores/git-repo-store.ts +117 -0
- package/src/web/stores/git-status-store.ts +10 -7
- package/src/web/stores/keybindings-store.ts +1 -0
- package/src/web/stores/panel-utils.ts +5 -2
- package/src/web/stores/problems-store.ts +116 -0
- package/src/web/stores/settings-store.ts +40 -0
- package/src/web/stores/tab-store.ts +2 -1
- package/src/web/stores/window-panel-persistence.ts +1 -0
- package/src/web/styles/file-icons.generated.css +1007 -0
- package/src/web/styles/fonts/nerd-symbols-codicons.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-devicons.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-font-awesome-ext.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-font-awesome-legacy.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-font-awesome.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-font-logos.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-iec-power.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-material.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-misc.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-octicons.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-pomicons.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-powerline.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-seti.woff2 +0 -0
- package/src/web/styles/fonts/nerd-symbols-weather.woff2 +0 -0
- package/src/web/styles/globals.css +30 -3
- package/src/web/styles/nerd-font.generated.css +153 -0
- package/src/web/sw.ts +69 -2
- package/src/web/theme/adapters/monaco-adapter.ts +20 -1
- package/src/web/theme/diff-token-rules.ts +34 -0
- package/src/web/theme/semantic-token-rules.ts +103 -0
- package/src/web/theme/theme-mode-options.ts +1 -1
- package/vite.config.ts +24 -7
- package/dist/web/assets/accounts-settings-section-DC2A6FhQ.js +0 -1
- package/dist/web/assets/ai-resource-editor-DDhuy_AR.js +0 -1
- package/dist/web/assets/ai-settings-section-J9Rbs26g.js +0 -1
- package/dist/web/assets/ai-settings-section-OrhLykA2.js +0 -1
- package/dist/web/assets/api-client-PMwZQ4iC.js +0 -1
- package/dist/web/assets/appearance-settings-section-BQ1dH29t.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-D55g5j-p.js +0 -1
- package/dist/web/assets/arrow-left-y44wEZrw.js +0 -1
- package/dist/web/assets/arrow-right-SQ8KJIvE.js +0 -1
- package/dist/web/assets/audio-preview-CAVqEwDi.js +0 -1
- package/dist/web/assets/bot-BNu2OM_S.js +0 -1
- package/dist/web/assets/brain-BsjvCk4k.js +0 -1
- package/dist/web/assets/calendar-clock-Zydwzvp7.js +0 -1
- package/dist/web/assets/chat-tab-D2le8LxY.js +0 -15
- package/dist/web/assets/check-DczxQ5UD.js +0 -1
- package/dist/web/assets/chevron-down-BCt_kn-R.js +0 -1
- package/dist/web/assets/chevron-right-Lt-y9H_e.js +0 -1
- package/dist/web/assets/chevron-up-CRl1AF4q.js +0 -1
- package/dist/web/assets/circle-D4vp8Yky.js +0 -1
- package/dist/web/assets/circle-question-mark-BGbDcz7E.js +0 -1
- package/dist/web/assets/clock-BBIE-uf3.js +0 -1
- package/dist/web/assets/code-CvgQViOi.js +0 -1
- package/dist/web/assets/code-editor-D-8oqMBM.js +0 -7
- package/dist/web/assets/codex-daily-guard-h4ZpEemV.js +0 -1
- package/dist/web/assets/conflict-editor-B0Mj8pYR.js +0 -19
- package/dist/web/assets/context-menu-I07Ld1Yr.js +0 -1
- package/dist/web/assets/copy-Bqr2VxN5.js +0 -1
- package/dist/web/assets/csv-preview-Ds2oCW6U.js +0 -2
- package/dist/web/assets/database-BHxcoKlT.js +0 -1
- package/dist/web/assets/database-viewer-CiwQ6spt.js +0 -1
- package/dist/web/assets/diff-viewer-BomFSnpH.js +0 -4
- package/dist/web/assets/docx-preview-PsyMM8SN.js +0 -12
- package/dist/web/assets/download-hiDsGuxx.js +0 -1
- package/dist/web/assets/explorer-body-CExMoOiW.js +0 -2
- package/dist/web/assets/explorer-window-content-Hy9kB6Q7.js +0 -1
- package/dist/web/assets/extension-manager-section-DMb56aut.js +0 -1
- package/dist/web/assets/extension-webview-CQB0Uvdo.js +0 -3
- package/dist/web/assets/eye-DYS5JBeU.js +0 -1
- package/dist/web/assets/eye-off-YWCuob9F.js +0 -1
- package/dist/web/assets/file-exclamation-point-DpdJqj9-.js +0 -1
- package/dist/web/assets/files-settings-section-CVHPO3N9.js +0 -1
- package/dist/web/assets/flask-conical-BUxpYe-g.js +0 -1
- package/dist/web/assets/folder-symlink-DKTEop0L.js +0 -1
- package/dist/web/assets/general-settings-section-CWYR9F5y.js +0 -1
- package/dist/web/assets/git-log-panel-DYLF-XSq.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-At-P8hlA.js +0 -1
- package/dist/web/assets/glide-data-grid-BxFN-Z6F.js +0 -141
- package/dist/web/assets/group-chat-tab-Ch6OGMKj.js +0 -1
- package/dist/web/assets/hand-BomFk_WG.js +0 -1
- package/dist/web/assets/image-preview-DjT5Xb2L.js +0 -1
- package/dist/web/assets/index-BfDJvjH9.js +0 -52
- package/dist/web/assets/index-Di9nVG3y.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-btSsuixb.js +0 -1
- package/dist/web/assets/key-round-BhkPzOjZ.js +0 -1
- package/dist/web/assets/keybindings-store-CNqxSJxv.js +0 -1
- package/dist/web/assets/keyboard-IQMXPNIE.js +0 -1
- package/dist/web/assets/keyboard-shortcuts-section-DAFNxA49.js +0 -1
- package/dist/web/assets/loader-circle-Bm-Dq_wA.js +0 -1
- package/dist/web/assets/markdown-renderer-BSiaxWjE.js +0 -1
- package/dist/web/assets/markdown-renderer-CMNnYOPG.js +0 -3
- package/dist/web/assets/mobile-explorer-sheet-BMg4Q9Bm.js +0 -1
- package/dist/web/assets/monitor-DEoVYSPl.js +0 -1
- package/dist/web/assets/notification-store-CRlOB9I9.js +0 -1
- package/dist/web/assets/notifications-settings-section-Cci_OOHx.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-B20_sIFd.js +0 -1
- package/dist/web/assets/panel-store-BcgZsiXU.js +0 -1
- package/dist/web/assets/pdf-preview-C28MEOND.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-nzfJdXCC.js +0 -1
- package/dist/web/assets/portal-container-context-DO44JpXO.js +0 -1
- package/dist/web/assets/power-BMdSjXYW.js +0 -1
- package/dist/web/assets/ppmbot-settings-section-Cef8FSS6.js +0 -1
- package/dist/web/assets/process-table-BfixzY3r.js +0 -1
- package/dist/web/assets/proxy-settings-section-BlLWfinY.js +0 -1
- package/dist/web/assets/query-audit-section-qnSL15x8.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-CS4sHKD5.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-CG6h4OL2.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-view-D__2WLV5.js +0 -1
- package/dist/web/assets/remote-desktop-readiness-gate-rL48PCUH.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-DlGUCbxq.js +0 -1
- package/dist/web/assets/save-CIuK3QI4.js +0 -1
- package/dist/web/assets/schedules-settings-section-BUqf3KTd.js +0 -1
- package/dist/web/assets/send-DQz3yIWM.js +0 -1
- package/dist/web/assets/separator-CE0YEyaB.js +0 -1
- package/dist/web/assets/settings-body-Baw2komX.js +0 -2
- package/dist/web/assets/settings-store-CuQlVCIe.js +0 -2
- package/dist/web/assets/settings-tab-DCW-3C38.js +0 -1
- package/dist/web/assets/settings-window-content-CVxOGqPV.js +0 -1
- package/dist/web/assets/shield-check-46EViZ6-.js +0 -1
- package/dist/web/assets/shield-off-Dx5mw3le.js +0 -1
- package/dist/web/assets/sparkles-Bay_CedB.js +0 -1
- package/dist/web/assets/sqlite-viewer-BWLSC3VJ.js +0 -1
- package/dist/web/assets/system-monitor-body-BqPyB0CY.js +0 -2
- package/dist/web/assets/system-monitor-tab-BXRvCThe.js +0 -1
- package/dist/web/assets/system-monitor-window-content-CvvwXkmW.js +0 -1
- package/dist/web/assets/tab-host-window-content-23IR3qzu.js +0 -1
- package/dist/web/assets/table-BbD_HNPU.js +0 -1
- package/dist/web/assets/team-member-sheet-BXJtrQAB.js +0 -2
- package/dist/web/assets/team-member-window-content-CBWnzwZ1.js +0 -1
- package/dist/web/assets/terminal-tab-uNw7Yvwg.js +0 -3
- package/dist/web/assets/text-wrap-97GXZlav.js +0 -1
- package/dist/web/assets/tool-cards-CjirOQfx.js +0 -9
- package/dist/web/assets/treemap-KZPCXAKY-BBrhTPZk.js +0 -1
- package/dist/web/assets/use-coarse-long-press-CynaAB7m.js +0 -1
- package/dist/web/assets/use-inline-blame-BLPCADZ8.js +0 -8
- package/dist/web/assets/use-monaco-theme-D2ETCHji.js +0 -1
- package/dist/web/assets/use-open-team-member-BlUqTp-l.js +0 -1
- package/dist/web/assets/use-remote-desktop-display-choice-B4O11KIj.js +0 -1
- package/dist/web/assets/vendor-markdown-3-bej77C.js +0 -291
- package/dist/web/assets/video-preview-BlD1DNP8.js +0 -1
- package/dist/web/assets/ws-auth-ZB8jvzhM.js +0 -1
- package/dist/web/assets/x-TEI-uJYo.js +0 -1
- package/dist/web/monacoeditorwork/css.worker.bundle.js +0 -54268
- package/dist/web/monacoeditorwork/editor.worker.bundle.js +0 -14316
- package/dist/web/monacoeditorwork/html.worker.bundle.js +0 -30452
- package/dist/web/monacoeditorwork/json.worker.bundle.js +0 -22095
- package/dist/web/monacoeditorwork/ts.worker.bundle.js +0 -225957
- package/src/web/components/explorer/file-icon-map.ts +0 -69
- /package/dist/web/assets/{abap-Dbc91hEB.js → abap-tkptwpsK.js} +0 -0
- /package/dist/web/assets/{actionscript-3-C14d4O5M.js → actionscript-3-Di9TMGwg.js} +0 -0
- /package/dist/web/assets/{ada-n8mPGtZF.js → ada-CB9F079D.js} +0 -0
- /package/dist/web/assets/{andromeeda-DAKL0TFq.js → andromeeda-Dcl8jpb7.js} +0 -0
- /package/dist/web/assets/{apache-BDCV8YqE.js → apache-D0Nk0qsH.js} +0 -0
- /package/dist/web/assets/{apex-BphlFNA_.js → apex-mQIoWncD.js} +0 -0
- /package/dist/web/assets/{applescript-F2pJar76.js → applescript-C6ljbcsI.js} +0 -0
- /package/dist/web/assets/{apply-theme-Abd1TNqE.js → apply-theme-BwIMNXyX.js} +0 -0
- /package/dist/web/assets/{ara-B32t5JRb.js → ara-WFqRPGPe.js} +0 -0
- /package/dist/web/assets/{asciidoc-DenFyKu-.js → asciidoc-bNd8w4nf.js} +0 -0
- /package/dist/web/assets/{asm-D5mJz41u.js → asm-BQ1_F580.js} +0 -0
- /package/dist/web/assets/{aurora-x-CUyAXiXM.js → aurora-x-Ciqs_Dbu.js} +0 -0
- /package/dist/web/assets/{awk-CUwaf-l-.js → awk-GCR-6KZV.js} +0 -0
- /package/dist/web/assets/{ayu-dark-Cgg8W7cK.js → ayu-dark-DxJXuj99.js} +0 -0
- /package/dist/web/assets/{ayu-light-B1c04Bhg.js → ayu-light-jvSyJWDV.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-CdWbuzp5.js → ayu-mirage-Cg3BPO6H.js} +0 -0
- /package/dist/web/assets/{ballerina-B2-GPRG0.js → ballerina-BPz4CrX6.js} +0 -0
- /package/dist/web/assets/{bat-Nss7Yr-0.js → bat-CSTs2hIG.js} +0 -0
- /package/dist/web/assets/{beancount-CgaWuvpQ.js → beancount-DMateAZX.js} +0 -0
- /package/dist/web/assets/{berry-DCFF4Zj1.js → berry-9lXg0GRM.js} +0 -0
- /package/dist/web/assets/{bibtex-BPNI-Gig.js → bibtex-DIbqmvFg.js} +0 -0
- /package/dist/web/assets/{bicep-qCj6DX1x.js → bicep-02WGsoJ8.js} +0 -0
- /package/dist/web/assets/{bird2-DYDjG-B_.js → bird2-BY0tbu3k.js} +0 -0
- /package/dist/web/assets/{c-CZV8SiOL.js → c-jMBX_9Je.js} +0 -0
- /package/dist/web/assets/{c3-BG7R2A4x.js → c3-B8JVbNjW.js} +0 -0
- /package/dist/web/assets/{cadence-BuiQVST4.js → cadence-DUIf1tvL.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-DU5MH6XF.js → can-open-in-ppm-DGEc0s4P.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-C-nwrEbb.js → catppuccin-frappe-FhUCVxex.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-nRLBO6vg.js → catppuccin-latte-CzfrtmgL.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-42eAAqCw.js → catppuccin-macchiato-6xL0lOtj.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-4lH0_4tX.js → catppuccin-mocha-D39-xS3P.js} +0 -0
- /package/dist/web/assets/{clarity-BCPLN5zJ.js → clarity-D8TeGvoT.js} +0 -0
- /package/dist/web/assets/{clojure-Btb509Z6.js → clojure-Dx_acSX7.js} +0 -0
- /package/dist/web/assets/{cmake-CGLZgJL3.js → cmake-CyeYPq8o.js} +0 -0
- /package/dist/web/assets/{codeowners-Dgqmdm5J.js → codeowners-DrTI0lmI.js} +0 -0
- /package/dist/web/assets/{codeql-DDUO6ZHS.js → codeql-CPkFxVW-.js} +0 -0
- /package/dist/web/assets/{common-lisp-DlhZ-mM8.js → common-lisp-B0k-3LTj.js} +0 -0
- /package/dist/web/assets/{coq-CVz-5qYC.js → coq-uygpo7to.js} +0 -0
- /package/dist/web/assets/{csharp-CXL6GcvM.js → csharp-DKUYGfSp.js} +0 -0
- /package/dist/web/assets/{css-CthwUm0E.js → css-DoOUp7v4.js} +0 -0
- /package/dist/web/assets/{csv-Bsal3rDr.js → csv-B3YE13gi.js} +0 -0
- /package/dist/web/assets/{csv-parser-iow1WWML.js → csv-parser-DXePqmXe.js} +0 -0
- /package/dist/web/assets/{cue-D2bSqa4C.js → cue-DViO2wvn.js} +0 -0
- /package/dist/web/assets/{cypher-u-EM8HmU.js → cypher-4BMCIW5N.js} +0 -0
- /package/dist/web/assets/{d-BFVkgfjO.js → d-BT_sTHas.js} +0 -0
- /package/dist/web/assets/{dark-plus-BXlM9uFB.js → dark-plus-DVVXu-1N.js} +0 -0
- /package/dist/web/assets/{dart-Hxx4mUdp.js → dart-DHz6f6_6.js} +0 -0
- /package/dist/web/assets/{dax-DQwsaFe_.js → dax-ChYCjweK.js} +0 -0
- /package/dist/web/assets/{desktop-CAHGHZLk.js → desktop-D6Lt4p04.js} +0 -0
- /package/dist/web/assets/{diff-CAbIXu6l.js → diff-D8TDe4hP.js} +0 -0
- /package/dist/web/assets/{dist-C_bG2Tku.js → dist-DOTlFQJA.js} +0 -0
- /package/dist/web/assets/{docker-51FhFKmM.js → docker-Bsp0YbPx.js} +0 -0
- /package/dist/web/assets/{dotenv-C4fc3fLK.js → dotenv-B_7giSY_.js} +0 -0
- /package/dist/web/assets/{dracula-CTtuacPO.js → dracula-TrQL2iB5.js} +0 -0
- /package/dist/web/assets/{dracula-soft-B-95hu1J.js → dracula-soft-n2XOlgh-.js} +0 -0
- /package/dist/web/assets/{dream-maker-Di3hAOzX.js → dream-maker-CdIEdhpT.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-C6btr6QV.js → emacs-lisp-CSbixs6u.js} +0 -0
- /package/dist/web/assets/{everforest-dark-CDQGzEiq.js → everforest-dark-BuZahZYp.js} +0 -0
- /package/dist/web/assets/{everforest-light-DRZC8v3w.js → everforest-light-DPH53z5H.js} +0 -0
- /package/dist/web/assets/{fennel-BZz92X8f.js → fennel-B1-K_hlJ.js} +0 -0
- /package/dist/web/assets/{fish-qpLXUfGf.js → fish-Cy12Dbua.js} +0 -0
- /package/dist/web/assets/{fluent-B3F6P-xc.js → fluent-B_82ys8E.js} +0 -0
- /package/dist/web/assets/{format-bytes-B9Dbme9a.js → format-bytes-D5sBgIqU.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-DjGQrmKa.js → fortran-free-form-BRQdNzZF.js} +0 -0
- /package/dist/web/assets/{gdscript-DToF1duE.js → gdscript-XBDmLUm9.js} +0 -0
- /package/dist/web/assets/{gdshader-FZCS76-j.js → gdshader-DhVfB3u4.js} +0 -0
- /package/dist/web/assets/{genie-CN3-FS9S.js → genie-X3K29Y49.js} +0 -0
- /package/dist/web/assets/{gherkin-DT66zHzt.js → gherkin-DKIx-6cX.js} +0 -0
- /package/dist/web/assets/{github-dark-5S2AJM2m.js → github-dark-Bf7zdp5s.js} +0 -0
- /package/dist/web/assets/{github-dark-default-DNEUWmc8.js → github-dark-default-DqsBBV11.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-BVgm_raB.js → github-dark-dimmed-X2gqRz6w.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-Dai8qNkr.js → github-dark-high-contrast-Z7tvbGX4.js} +0 -0
- /package/dist/web/assets/{github-light-C49nlhDa.js → github-light-BKxt-7zZ.js} +0 -0
- /package/dist/web/assets/{github-light-default-BLQcyxQl.js → github-light-default-B0liF4d4.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-BH3u_hMd.js → github-light-high-contrast-F4encJwr.js} +0 -0
- /package/dist/web/assets/{gleam-G2907CEQ.js → gleam-Pz2bHgBB.js} +0 -0
- /package/dist/web/assets/{gn-fxgN7J9Q.js → gn-CgmdNsPU.js} +0 -0
- /package/dist/web/assets/{gnuplot-a1TK_67n.js → gnuplot-qLNF5yZ9.js} +0 -0
- /package/dist/web/assets/{go-DLqnNJpz.js → go-CSDUNhE7.js} +0 -0
- /package/dist/web/assets/{groovy-D8U-plxc.js → groovy-B3NEnOHF.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-DRYdA7rg.js → gruvbox-dark-hard-DcoftiUX.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-CJgayBQH.js → gruvbox-dark-medium-D1wVSuD8.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-spQNOlQ2.js → gruvbox-dark-soft-DWpunymH.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-FoElS0Wo.js → gruvbox-light-hard-rHMvyUdS.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-9E1Brisc.js → gruvbox-light-medium-3O2KiXO7.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-Coyp7RRB.js → gruvbox-light-soft-lNlXJPwH.js} +0 -0
- /package/dist/web/assets/{haskell-D1twJpgj.js → haskell-aaG3aC0h.js} +0 -0
- /package/dist/web/assets/{haxe-CppquubK.js → haxe-CPcHhUDd.js} +0 -0
- /package/dist/web/assets/{hcl-BWfTkyhR.js → hcl-CMQNlR_4.js} +0 -0
- /package/dist/web/assets/{hjson-fgd7F6t5.js → hjson-DeuklPFj.js} +0 -0
- /package/dist/web/assets/{hlsl-Ua1j-4aZ.js → hlsl-BI3hlsaM.js} +0 -0
- /package/dist/web/assets/{horizon-CTFgrxGb.js → horizon-C7-gOcjs.js} +0 -0
- /package/dist/web/assets/{horizon-bright-C4eTVZPB.js → horizon-bright-Cxt9bRW7.js} +0 -0
- /package/dist/web/assets/{houston-BeYbWPdk.js → houston-DbF2G7iD.js} +0 -0
- /package/dist/web/assets/{hy-BposFX9Q.js → hy-DRG6Hs2I.js} +0 -0
- /package/dist/web/assets/{image-gallery-COea0nSk.js → image-gallery-CObzTisL.js} +0 -0
- /package/dist/web/assets/{imba-D11-b73t.js → imba-CxKv_2TW.js} +0 -0
- /package/dist/web/assets/{ini-BCYCXf0w.js → ini-BiHsyCdO.js} +0 -0
- /package/dist/web/assets/{java-BqKIPPzY.js → java-D3RZzgDB.js} +0 -0
- /package/dist/web/assets/{javascript-CxvTx_wu.js → javascript-4FmSqG-T.js} +0 -0
- /package/dist/web/assets/{json-DiknJGdj.js → json-CjB236_E.js} +0 -0
- /package/dist/web/assets/{json5--8nFeehk.js → json5-bkfO-Rco.js} +0 -0
- /package/dist/web/assets/{jsonc-BFcq-Nx-.js → jsonc-BwaTeLyv.js} +0 -0
- /package/dist/web/assets/{jsonl-DKItgfTA.js → jsonl-CfxNSwGd.js} +0 -0
- /package/dist/web/assets/{jsonnet-sNz5wf7H.js → jsonnet-CQETCYrp.js} +0 -0
- /package/dist/web/assets/{jssm-BALAIF_E.js → jssm-D5o3Zzdz.js} +0 -0
- /package/dist/web/assets/{jsx-fXHHDCVl.js → jsx-BAMILPLo.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-nywk9qzg.js → kanagawa-dragon-BhGVxu3R.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-BmYPLC4f.js → kanagawa-lotus-FH4Y59ro.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-624mOWgc.js → kanagawa-wave-eilvP9MB.js} +0 -0
- /package/dist/web/assets/{kdl-DT8Argim.js → kdl-BQ-yvXUK.js} +0 -0
- /package/dist/web/assets/{kotlin-BvUjvPz2.js → kotlin-BuCx0-VT.js} +0 -0
- /package/dist/web/assets/{kusto-B0PONVdx.js → kusto-DAN_n_Cy.js} +0 -0
- /package/dist/web/assets/{laserwave-ByV7LuzT.js → laserwave-Cq2BlxrT.js} +0 -0
- /package/dist/web/assets/{lean-DQtq2qQC.js → lean-Dhq7uXKw.js} +0 -0
- /package/dist/web/assets/{less-DZeD4ccP.js → less-CxaMQb8j.js} +0 -0
- /package/dist/web/assets/{libesm-CcPYXCKp.js → libesm-DdtEjhIi.js} +0 -0
- /package/dist/web/assets/{light-plus-BCaKDxvd.js → light-plus-B4sMAend.js} +0 -0
- /package/dist/web/assets/{llvm-Dzok661y.js → llvm-DQ6-B_6Y.js} +0 -0
- /package/dist/web/assets/{log-C32HpwgI.js → log-Bb_vqvu7.js} +0 -0
- /package/dist/web/assets/{logo-Dtjk3XHO.js → logo-BzfYv3A_.js} +0 -0
- /package/dist/web/assets/{luau-BMbN7IqN.js → luau-BnAeNR77.js} +0 -0
- /package/dist/web/assets/{make-DIVSnx7D.js → make-B6IFuxpC.js} +0 -0
- /package/dist/web/assets/{markdown-B1JzcsJb.js → markdown-Z0xi77Fn.js} +0 -0
- /package/dist/web/assets/{material-theme-XMfEph9O.js → material-theme-1scy1SYn.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-CRGzh4Ox.js → material-theme-darker-G-JykXQP.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-D6esgP3h.js → material-theme-lighter-BtKkCMVq.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-CGbfRrFG.js → material-theme-ocean-irrDC89L.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-DFW4xdPI.js → material-theme-palenight-Eq5_K4LM.js} +0 -0
- /package/dist/web/assets/{matlab-Zpc8hvmI.js → matlab-BE3oCXZC.js} +0 -0
- /package/dist/web/assets/{mdx-DLlDpnjI.js → mdx-DYiuFTGw.js} +0 -0
- /package/dist/web/assets/{mermaid-q_sEDHYr.js → mermaid-DVlaEvtw.js} +0 -0
- /package/dist/web/assets/{min-dark-DUklXai3.js → min-dark-DSkeTpQa.js} +0 -0
- /package/dist/web/assets/{min-light-Ps7CV3R0.js → min-light-CFv2Q0uF.js} +0 -0
- /package/dist/web/assets/{mipsasm-anKs0TGD.js → mipsasm-CiAFuZQ2.js} +0 -0
- /package/dist/web/assets/{mojo-CWTvit9D.js → mojo-ARshcaSQ.js} +0 -0
- /package/dist/web/assets/{monokai-DOSMe3B9.js → monokai-CPTV-SOg.js} +0 -0
- /package/dist/web/assets/{moonbit-zOAryA05.js → moonbit-D57B0dZr.js} +0 -0
- /package/dist/web/assets/{move-CA6YZdSC.js → move-qgy3G_o9.js} +0 -0
- /package/dist/web/assets/{narrat-CyMxkfZJ.js → narrat-CZ3rC-oc.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-D5beSS3L.js → nextflow-groovy-BxxIOcI4.js} +0 -0
- /package/dist/web/assets/{night-owl-3ALu1K6e.js → night-owl-B1ryGCda.js} +0 -0
- /package/dist/web/assets/{night-owl-light-_NLbQQrl.js → night-owl-light-BZvNnvMF.js} +0 -0
- /package/dist/web/assets/{nix-C_KqthNc.js → nix-BVBQi8yv.js} +0 -0
- /package/dist/web/assets/{nord-VG8J_Wfy.js → nord-3NXw613h.js} +0 -0
- /package/dist/web/assets/{nushell-Dx7K7YNI.js → nushell-BMOLRalb.js} +0 -0
- /package/dist/web/assets/{objective-c-DrEbGERB.js → objective-c-AxruEUgh.js} +0 -0
- /package/dist/web/assets/{objective-cpp-DpiXqKhj.js → objective-cpp-cFT0qRsD.js} +0 -0
- /package/dist/web/assets/{ocaml-G6x51MAm.js → ocaml-_8JH6O8J.js} +0 -0
- /package/dist/web/assets/{odin-tK6CU-OU.js → odin-nwYvR0O6.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-581te-yF.js → one-dark-pro-C1LaYJaH.js} +0 -0
- /package/dist/web/assets/{one-light-DpYva-U1.js → one-light-B7rMc__c.js} +0 -0
- /package/dist/web/assets/{openscad-C7LYrrI4.js → openscad-Cwes8bKO.js} +0 -0
- /package/dist/web/assets/{pascal-ChqM3eJD.js → pascal-DMt-6tdZ.js} +0 -0
- /package/dist/web/assets/{pkl-BlIRJsyQ.js → pkl-QBTyYQmB.js} +0 -0
- /package/dist/web/assets/{plastic-DxceXlOD.js → plastic-BTSUp8Fk.js} +0 -0
- /package/dist/web/assets/{plsql-CVikvjWK.js → plsql-DQv3IFXP.js} +0 -0
- /package/dist/web/assets/{po-BN9bpeJD.js → po-CNwZx4tW.js} +0 -0
- /package/dist/web/assets/{poimandres-NeQA7ZSh.js → poimandres-8Os7Qequ.js} +0 -0
- /package/dist/web/assets/{polar-DtRx-uzO.js → polar-b4yK8oD8.js} +0 -0
- /package/dist/web/assets/{postcss-EDnOs84S.js → postcss-sFctwpxx.js} +0 -0
- /package/dist/web/assets/{powerquery-mc-bbl3v.js → powerquery-Cg_WrtuN.js} +0 -0
- /package/dist/web/assets/{powershell-ZqZF93a-.js → powershell-C7Ifz95h.js} +0 -0
- /package/dist/web/assets/{prisma-vhORN1Sx.js → prisma-Z52HUJzQ.js} +0 -0
- /package/dist/web/assets/{prolog-DfIbN_m8.js → prolog-DLqW-zR1.js} +0 -0
- /package/dist/web/assets/{proto-BHcnh-Db.js → proto-BOIzxCCJ.js} +0 -0
- /package/dist/web/assets/{puppet-oLpQOx2h.js → puppet-De7TjZIf.js} +0 -0
- /package/dist/web/assets/{purescript-HbM4Dt8M.js → purescript-R76ou1WT.js} +0 -0
- /package/dist/web/assets/{python-Dlxo2z6Q.js → python-Dprm0tNP.js} +0 -0
- /package/dist/web/assets/{qmldir-B5ox9idu.js → qmldir-Clp_jpNw.js} +0 -0
- /package/dist/web/assets/{qss-CyegwBrl.js → qss-eQPYYzSo.js} +0 -0
- /package/dist/web/assets/{r-CxE2X3lg.js → r-CCcRHIf5.js} +0 -0
- /package/dist/web/assets/{racket-CpguQMOj.js → racket-CzE472yp.js} +0 -0
- /package/dist/web/assets/{raku-DDf8ASYE.js → raku-DQwXrTSi.js} +0 -0
- /package/dist/web/assets/{red-C634f6x3.js → red-KCS6wyop.js} +0 -0
- /package/dist/web/assets/{reg-4gnm7BOP.js → reg-CcrAddUh.js} +0 -0
- /package/dist/web/assets/{regexp-Cs-hPAru.js → regexp-DDbud-Ri.js} +0 -0
- /package/dist/web/assets/{rel-CrGcWbwM.js → rel-99GDgaHp.js} +0 -0
- /package/dist/web/assets/{resolve-theme-Dm8ehbOv.js → resolve-theme-CW2niGV2.js} +0 -0
- /package/dist/web/assets/{riscv-B2P26ROS.js → riscv-Dm2eNv0R.js} +0 -0
- /package/dist/web/assets/{ron-DDHGmvxW.js → ron-CzFt0ygH.js} +0 -0
- /package/dist/web/assets/{rose-pine-CUYRoYal.js → rose-pine-Ck6lCrCP.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-C9JfuUh8.js → rose-pine-dawn-vtALRJNj.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-CrYHzRJm.js → rose-pine-moon-DPto8qXw.js} +0 -0
- /package/dist/web/assets/{rosmsg-iqzz1U38.js → rosmsg-NtS6429H.js} +0 -0
- /package/dist/web/assets/{rust-DVeWF3Is.js → rust-BjIXvF9h.js} +0 -0
- /package/dist/web/assets/{sass-CbVwBbUd.js → sass-CQ23wf5E.js} +0 -0
- /package/dist/web/assets/{scala-gZhcvPGv.js → scala-LfKLM143.js} +0 -0
- /package/dist/web/assets/{scheme-Z-DWgvmB.js → scheme-D3SLBXlF.js} +0 -0
- /package/dist/web/assets/{sdbl-wn_BtpSz.js → sdbl-ODRd2rGN.js} +0 -0
- /package/dist/web/assets/{shellscript-C09f889h.js → shellscript-3KB1G_oA.js} +0 -0
- /package/dist/web/assets/{slack-dark-D63Fbr3l.js → slack-dark-DTtyWmIy.js} +0 -0
- /package/dist/web/assets/{slack-ochin--Yu-v0r6.js → slack-ochin-Bu0PApk3.js} +0 -0
- /package/dist/web/assets/{smalltalk-LQDcL_tW.js → smalltalk-haMT-Sbe.js} +0 -0
- /package/dist/web/assets/{snazzy-light-bo9fX83t.js → snazzy-light-DXJzefE9.js} +0 -0
- /package/dist/web/assets/{solarized-dark-zSs85XH6.js → solarized-dark-B6LyYa18.js} +0 -0
- /package/dist/web/assets/{solarized-light-B6Q4CXBt.js → solarized-light-QLADebkv.js} +0 -0
- /package/dist/web/assets/{solidity-uUJPOjGx.js → solidity-mzfq1aDc.js} +0 -0
- /package/dist/web/assets/{splunk-C6oWgmrC.js → splunk-CyH4RWBp.js} +0 -0
- /package/dist/web/assets/{sql-DyUvXbLi.js → sql-CWVlT5D3.js} +0 -0
- /package/dist/web/assets/{ssh-config-62Vrd_7v.js → ssh-config-DNvQJ1Qx.js} +0 -0
- /package/dist/web/assets/{stylus-CmLQe7Fq.js → stylus-ByQQdtmf.js} +0 -0
- /package/dist/web/assets/{swift-DJwuT1eZ.js → swift-D1cpY4ow.js} +0 -0
- /package/dist/web/assets/{synthwave-84-CEeyTLD7.js → synthwave-84-BDF_-QiW.js} +0 -0
- /package/dist/web/assets/{system-verilog-DMqtAclw.js → system-verilog-BYrkMydC.js} +0 -0
- /package/dist/web/assets/{systemd-XnScP_8M.js → systemd-CQm3zyK0.js} +0 -0
- /package/dist/web/assets/{talonscript-CDoODzml.js → talonscript-DMW5CzE1.js} +0 -0
- /package/dist/web/assets/{tasl-DycI0-Tf.js → tasl-BhFzMCr2.js} +0 -0
- /package/dist/web/assets/{tcl-Dt8iP0sw.js → tcl-D7VEAF-9.js} +0 -0
- /package/dist/web/assets/{terraform-DXzABgqQ.js → terraform-DdT5A0Vy.js} +0 -0
- /package/dist/web/assets/{tokyo-night-DHB1Yc-3.js → tokyo-night-WGLMM6Q9.js} +0 -0
- /package/dist/web/assets/{toml-BkejsZF3.js → toml-CZ7ipXHZ.js} +0 -0
- /package/dist/web/assets/{tsv-ClmhsiiR.js → tsv-B1zVvoTr.js} +0 -0
- /package/dist/web/assets/{tsx-Cp-c_JHF.js → tsx-D4HwRUBq.js} +0 -0
- /package/dist/web/assets/{turtle-BbwC417u.js → turtle-B4r8KEJH.js} +0 -0
- /package/dist/web/assets/{typescript-DbwnrRKJ.js → typescript-BnHhxMtp.js} +0 -0
- /package/dist/web/assets/{typespec-DLL0LoZj.js → typespec-DP2q46GT.js} +0 -0
- /package/dist/web/assets/{typst-BmEouVT1.js → typst-DFsD_yaD.js} +0 -0
- /package/dist/web/assets/{utils-CwNUra6_.js → utils-Bmf_8h7Y.js} +0 -0
- /package/dist/web/assets/{v-C5rFgF81.js → v-Bji8hSVT.js} +0 -0
- /package/dist/web/assets/{vala-rBXMujLw.js → vala-D3TIgGmU.js} +0 -0
- /package/dist/web/assets/{vb-mxG_YZv2.js → vb-DvcxFS2q.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-BtjgHRUe.js → vendor-xterm-BqPDsE9b.js} +0 -0
- /package/dist/web/assets/{verilog-uQ-oJRKp.js → verilog-Dy7cF35d.js} +0 -0
- /package/dist/web/assets/{vesper-SO5Hw_2X.js → vesper-BzjwUv9J.js} +0 -0
- /package/dist/web/assets/{vhdl-8IeO85hx.js → vhdl-DuFnFNmW.js} +0 -0
- /package/dist/web/assets/{viml-De-Hm57y.js → viml-yAPgKlbz.js} +0 -0
- /package/dist/web/assets/{vitesse-black-BVm23GJE.js → vitesse-black-oSSQdyIZ.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-CR0XeT-h.js → vitesse-dark-BZxwPihB.js} +0 -0
- /package/dist/web/assets/{vitesse-light-CXIFICUA.js → vitesse-light-uIigycvt.js} +0 -0
- /package/dist/web/assets/{vyper-dUuvAUFJ.js → vyper-CX3NAxm5.js} +0 -0
- /package/dist/web/assets/{wasm-DbLMmiW0.js → wasm-6mEOOvVa.js} +0 -0
- /package/dist/web/assets/{wasm-D5Vd7qV1.js → wasm-D9td37qO.js} +0 -0
- /package/dist/web/assets/{wenyan-BafBYCBu.js → wenyan-lwNIHgk6.js} +0 -0
- /package/dist/web/assets/{wgsl-DY5sHamz.js → wgsl-DQAzCfog.js} +0 -0
- /package/dist/web/assets/{wikitext-QkQQVra5.js → wikitext-DTXmt5NE.js} +0 -0
- /package/dist/web/assets/{wit-BZjaDTy9.js → wit-Bdw_7WDH.js} +0 -0
- /package/dist/web/assets/{wolfram-vrjPFD7R.js → wolfram-DqyHDZ07.js} +0 -0
- /package/dist/web/assets/{yaml-D1as76NB.js → yaml-CPXhdByd.js} +0 -0
- /package/dist/web/assets/{zenscript-D31myxQh.js → zenscript-6s_i5zek.js} +0 -0
- /package/dist/web/assets/{zig-BbLb6ieN.js → zig-B2htezJ_.js} +0 -0
|
@@ -10,7 +10,7 @@ import type { VscodeApi } from "./git-exec.ts";
|
|
|
10
10
|
import {
|
|
11
11
|
assertSafeFilePaths, assertValidHash, assertValidRef, assertValidRemote, spawnGit,
|
|
12
12
|
} from "./git-exec.ts";
|
|
13
|
-
import { authHeaders, getBaseUrl, initPpmApi,
|
|
13
|
+
import { authHeaders, getBaseUrl, initPpmApi, resolveFileTab } from "./ppm-api.ts";
|
|
14
14
|
import { registerBlameView } from "./blame-view.ts";
|
|
15
15
|
import { registerFileHistoryView } from "./file-history-view.ts";
|
|
16
16
|
import { registerCompareView } from "./compare-view.ts";
|
|
@@ -117,10 +117,9 @@ function openGitGraph(
|
|
|
117
117
|
case "openDiff": {
|
|
118
118
|
assertSafeFilePaths([msg.filePath], pp);
|
|
119
119
|
const fileName = msg.filePath.split(/[\\/]/).pop() || msg.filePath;
|
|
120
|
-
const
|
|
121
|
-
await vscode.window.openTab("git-diff", `${fileName} (${msg.hash.substring(0, 7)})`, projectName, {
|
|
122
|
-
|
|
123
|
-
filePath: msg.filePath,
|
|
120
|
+
const target = await resolveFileTab(pp, msg.filePath);
|
|
121
|
+
await vscode.window.openTab("git-diff", `${fileName} (${msg.hash.substring(0, 7)})`, target.projectName, {
|
|
122
|
+
...target,
|
|
124
123
|
...(msg.parentHash ? { ref1: msg.parentHash } : {}),
|
|
125
124
|
...(msg.hash !== "uncommitted" && msg.hash !== "staged" ? { ref2: msg.hash } : {}),
|
|
126
125
|
});
|
|
@@ -198,11 +197,8 @@ function openGitGraph(
|
|
|
198
197
|
break;
|
|
199
198
|
case "openFile": {
|
|
200
199
|
assertSafeFilePaths([msg.filePath], pp);
|
|
201
|
-
const
|
|
202
|
-
await vscode.window.openTab("editor", msg.filePath, projectName,
|
|
203
|
-
projectName,
|
|
204
|
-
filePath: msg.filePath,
|
|
205
|
-
});
|
|
200
|
+
const target = await resolveFileTab(pp, msg.filePath);
|
|
201
|
+
await vscode.window.openTab("editor", msg.filePath, target.projectName, target);
|
|
206
202
|
break;
|
|
207
203
|
}
|
|
208
204
|
case "requestWorktrees":
|
|
@@ -348,12 +344,9 @@ function openGitGraph(
|
|
|
348
344
|
break;
|
|
349
345
|
case "openConflictFile": {
|
|
350
346
|
assertSafeFilePaths([msg.filePath], pp);
|
|
351
|
-
const
|
|
347
|
+
const target = await resolveFileTab(pp, msg.filePath);
|
|
352
348
|
// Opens as conflict-editor tab (Phase 4 will wire this properly)
|
|
353
|
-
await vscode.window.openTab("conflict-editor", `Conflict: ${msg.filePath.split(/[\\/]/).pop()}`, projectName,
|
|
354
|
-
projectName,
|
|
355
|
-
filePath: msg.filePath,
|
|
356
|
-
});
|
|
349
|
+
await vscode.window.openTab("conflict-editor", `Conflict: ${msg.filePath.split(/[\\/]/).pop()}`, target.projectName, target);
|
|
357
350
|
break;
|
|
358
351
|
}
|
|
359
352
|
case "openSourceControl": {
|
|
@@ -402,6 +395,41 @@ async function handleRepoInfo(
|
|
|
402
395
|
});
|
|
403
396
|
}
|
|
404
397
|
|
|
398
|
+
/**
|
|
399
|
+
* Which commit-window requests a panel still wants the answers to.
|
|
400
|
+
*
|
|
401
|
+
* Scrolling fires one `requestCommits` per page and each one spawns two git
|
|
402
|
+
* processes — the log and the lines-changed pass — with nothing stopping the
|
|
403
|
+
* previous pair. Pages are additive, so a late *append* is still wanted; what
|
|
404
|
+
* is not is anything from before the list was last thrown away. Switching
|
|
405
|
+
* branch or refreshing sends `skip: 0`, which replaces the list, and an
|
|
406
|
+
* in-flight page-two append landing after that appends the old branch's
|
|
407
|
+
* commits to the new branch's first page.
|
|
408
|
+
*
|
|
409
|
+
* So responses are dropped by generation rather than cancelled — there is no
|
|
410
|
+
* abort to reach for through the extension spawn API — and the second pass is
|
|
411
|
+
* skipped outright when it is already stale, which is also what keeps the
|
|
412
|
+
* process count down while somebody scrolls.
|
|
413
|
+
*/
|
|
414
|
+
export interface CommitRequestState {
|
|
415
|
+
latest: number;
|
|
416
|
+
lastReset: number;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** Record a new request and return its generation. */
|
|
420
|
+
export function beginCommitRequest(state: CommitRequestState, skip: number): number {
|
|
421
|
+
state.latest += 1;
|
|
422
|
+
if (skip === 0) state.lastReset = state.latest;
|
|
423
|
+
return state.latest;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** True when the list this request was answering has since been replaced. */
|
|
427
|
+
export function isStaleCommitRequest(state: CommitRequestState, generation: number): boolean {
|
|
428
|
+
return generation < state.lastReset;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const commitRequests = new WeakMap<object, CommitRequestState>();
|
|
432
|
+
|
|
405
433
|
async function handleRequestCommits(
|
|
406
434
|
vscode: VscodeApi,
|
|
407
435
|
panel: ReturnType<VscodeApi["window"]["createWebviewPanel"]>,
|
|
@@ -413,25 +441,22 @@ async function handleRequestCommits(
|
|
|
413
441
|
): Promise<void> {
|
|
414
442
|
const { parseGitLog } = await import("./git-log-parser.ts");
|
|
415
443
|
const settings = context ? getSettings(context) : DEFAULT_SETTINGS;
|
|
416
|
-
const
|
|
417
|
-
: settings.commitOrdering
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
`-n`, String(maxCommits),
|
|
424
|
-
];
|
|
425
|
-
if (settings.firstParentOnly) args.push("--first-parent");
|
|
426
|
-
if (skip > 0) args.push(`--skip=${skip}`);
|
|
427
|
-
if (branch && branch !== "all") {
|
|
428
|
-
args.push(branch);
|
|
429
|
-
} else {
|
|
430
|
-
// Exclude stash refs — stashes are loaded separately via handleStashes
|
|
431
|
-
args.push("--exclude=refs/stash", "--all");
|
|
444
|
+
const window = { maxCommits, skip, branch, firstParentOnly: settings.firstParentOnly,
|
|
445
|
+
ordering: settings.commitOrdering };
|
|
446
|
+
|
|
447
|
+
let requests = commitRequests.get(panel);
|
|
448
|
+
if (!requests) {
|
|
449
|
+
requests = { latest: 0, lastReset: 0 };
|
|
450
|
+
commitRequests.set(panel, requests);
|
|
432
451
|
}
|
|
452
|
+
const generation = beginCommitRequest(requests, skip);
|
|
433
453
|
|
|
434
|
-
const result = await spawnGit(
|
|
454
|
+
const result = await spawnGit(
|
|
455
|
+
vscode,
|
|
456
|
+
logArgs(window, `--format=%H%n%P%n%an%n%ae%n%at%n%cn%n%ce%n%ct%n%D%n%s%n<END_COMMIT>`),
|
|
457
|
+
projectPath,
|
|
458
|
+
);
|
|
459
|
+
if (isStaleCommitRequest(requests, generation)) return;
|
|
435
460
|
const commits = parseGitLog(result.stdout);
|
|
436
461
|
|
|
437
462
|
await panel.webview.postMessage({
|
|
@@ -439,14 +464,66 @@ async function handleRequestCommits(
|
|
|
439
464
|
data: commits,
|
|
440
465
|
append: skip > 0,
|
|
441
466
|
});
|
|
467
|
+
|
|
468
|
+
// Lines changed, in a second pass. Asking the first log for --shortstat makes
|
|
469
|
+
// git diff every commit in the window, and that cost would land before the
|
|
470
|
+
// graph could be drawn at all; this way the numbers fill into their column a
|
|
471
|
+
// moment after the rows are already on screen.
|
|
472
|
+
try {
|
|
473
|
+
const { parseShortstat } = await import("./shortstat-parser.ts");
|
|
474
|
+
const stats = await spawnGit(vscode, logArgs(window, "--format=%H", "--shortstat"), projectPath);
|
|
475
|
+
if (isStaleCommitRequest(requests, generation)) return;
|
|
476
|
+
await panel.webview.postMessage({
|
|
477
|
+
command: "loadCommitStats",
|
|
478
|
+
data: parseShortstat(stats.stdout),
|
|
479
|
+
});
|
|
480
|
+
} catch {
|
|
481
|
+
// A column of numbers is not worth an error banner over the graph.
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export interface LogWindow {
|
|
486
|
+
maxCommits: number;
|
|
487
|
+
skip: number;
|
|
488
|
+
branch?: string;
|
|
489
|
+
firstParentOnly?: boolean;
|
|
490
|
+
ordering?: string;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* The commit window, as git arguments.
|
|
495
|
+
*
|
|
496
|
+
* Shared so the stats pass sees exactly the same commits as the graph: the two
|
|
497
|
+
* are joined by hash, so a different window would silently leave rows blank.
|
|
498
|
+
* Exported for its own test — the branch in it comes from a webview.
|
|
499
|
+
*/
|
|
500
|
+
export function logArgs(window: LogWindow, ...format: string[]): string[] {
|
|
501
|
+
const orderFlag = window.ordering === "date" ? "--date-order"
|
|
502
|
+
: window.ordering === "author-date" ? "--author-date-order"
|
|
503
|
+
: "--topo-order";
|
|
504
|
+
const args = ["log", ...format, orderFlag, "-n", String(window.maxCommits)];
|
|
505
|
+
if (window.firstParentOnly) args.push("--first-parent");
|
|
506
|
+
if (window.skip > 0) args.push(`--skip=${window.skip}`);
|
|
507
|
+
if (window.branch && window.branch !== "all") {
|
|
508
|
+
// The branch came from a webview. git happens to reject a dash-leading
|
|
509
|
+
// refname on its own, but that is a coincidence rather than a design, and
|
|
510
|
+
// this window is now spawned twice per request — once for the graph and
|
|
511
|
+
// once for the stats — so the value reaches git on two paths.
|
|
512
|
+
args.push(assertValidRef(window.branch, "branch"));
|
|
513
|
+
} else {
|
|
514
|
+
// Exclude stash refs — stashes are loaded separately via handleStashes
|
|
515
|
+
args.push("--exclude=refs/stash", "--all");
|
|
516
|
+
}
|
|
517
|
+
return args;
|
|
442
518
|
}
|
|
443
519
|
|
|
444
520
|
async function handleCommitDetails(
|
|
445
521
|
vscode: VscodeApi,
|
|
446
522
|
panel: ReturnType<VscodeApi["window"]["createWebviewPanel"]>,
|
|
447
523
|
projectPath: string,
|
|
448
|
-
|
|
524
|
+
rawHash: string,
|
|
449
525
|
): Promise<void> {
|
|
526
|
+
const hash = assertValidHash(rawHash);
|
|
450
527
|
const result = await spawnGit(vscode, [
|
|
451
528
|
"show", "--numstat", "--format=%H%n%P%n%an%n%ae%n%at%n%cn%n%ce%n%ct%n%B%n<END_MSG>", hash,
|
|
452
529
|
], projectPath);
|
|
@@ -749,7 +826,32 @@ function parseStashes(stdout: string): import("./types.ts").Stash[] {
|
|
|
749
826
|
});
|
|
750
827
|
}
|
|
751
828
|
|
|
752
|
-
|
|
829
|
+
/**
|
|
830
|
+
* Files listed for one commit. The uncommitted-status handler two functions
|
|
831
|
+
* away already caps at the same number; this one capped at nothing, and a
|
|
832
|
+
* commit touching ten thousand files became ten thousand objects across
|
|
833
|
+
* `postMessage` and ten thousand rows in one `innerHTML`. A repository you
|
|
834
|
+
* clone can ship that commit.
|
|
835
|
+
*
|
|
836
|
+
* The cap has to be *said*, not just applied: a truncated list rendered as
|
|
837
|
+
* "500 files changed" is a wrong number presented as a fact, which is worse
|
|
838
|
+
* than a slow panel. `filesOmitted` carries what was dropped, the way the
|
|
839
|
+
* message cap appends its own `[… N more characters]`.
|
|
840
|
+
*/
|
|
841
|
+
export const MAX_DETAIL_FILES = 500;
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Characters of commit message the panel will render.
|
|
845
|
+
*
|
|
846
|
+
* `%B` is whatever the author wrote and is not bounded by anything — and the
|
|
847
|
+
* message then goes through the issue-link matcher, whose span-overlap check is
|
|
848
|
+
* quadratic in the number of matches. `\b[0-9a-f]{7,40}\b` matches once per
|
|
849
|
+
* hex-looking word, so a body of them is ~n² comparisons. 100 KB is longer than
|
|
850
|
+
* any message anyone reads and short enough that the worst case stays cheap.
|
|
851
|
+
*/
|
|
852
|
+
const MAX_MESSAGE_CHARS = 100_000;
|
|
853
|
+
|
|
854
|
+
export function parseCommitDetail(stdout: string): import("./types.ts").CommitDetail {
|
|
753
855
|
const [headerBlock, rest] = stdout.split("<END_MSG>");
|
|
754
856
|
const lines = headerBlock.trim().split("\n");
|
|
755
857
|
const hash = lines[0];
|
|
@@ -760,14 +862,24 @@ function parseCommitDetail(stdout: string): import("./types.ts").CommitDetail {
|
|
|
760
862
|
const committer = lines[5];
|
|
761
863
|
const committerEmail = lines[6];
|
|
762
864
|
const commitDate = parseInt(lines[7], 10);
|
|
763
|
-
const
|
|
865
|
+
const full = lines.slice(8).join("\n").trim();
|
|
866
|
+
const message = full.length > MAX_MESSAGE_CHARS
|
|
867
|
+
? `${full.slice(0, MAX_MESSAGE_CHARS)}\n\n[… ${full.length - MAX_MESSAGE_CHARS} more characters]`
|
|
868
|
+
: full;
|
|
764
869
|
|
|
765
870
|
// Parse --numstat output for file changes (format: "adds\tdels\tpath")
|
|
766
871
|
const fileChanges: import("./types.ts").FileChange[] = [];
|
|
872
|
+
let filesOmitted = 0;
|
|
767
873
|
if (rest) {
|
|
768
874
|
for (const line of rest.trim().split("\n").filter(Boolean)) {
|
|
769
875
|
const numstatMatch = line.match(/^(\d+|-)\t(\d+|-)\t(.+)$/);
|
|
770
876
|
if (numstatMatch) {
|
|
877
|
+
// Past the cap the rest of the walk is only counting, so that the panel
|
|
878
|
+
// can say how many files it is not showing.
|
|
879
|
+
if (fileChanges.length >= MAX_DETAIL_FILES) {
|
|
880
|
+
filesOmitted++;
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
771
883
|
const additions = numstatMatch[1] === "-" ? 0 : parseInt(numstatMatch[1], 10);
|
|
772
884
|
const deletions = numstatMatch[2] === "-" ? 0 : parseInt(numstatMatch[2], 10);
|
|
773
885
|
let filePath = numstatMatch[3];
|
|
@@ -794,7 +906,7 @@ function parseCommitDetail(stdout: string): import("./types.ts").CommitDetail {
|
|
|
794
906
|
}
|
|
795
907
|
}
|
|
796
908
|
|
|
797
|
-
return { hash, parents, author, authorEmail, authorDate, committer, committerEmail, commitDate, message, fileChanges };
|
|
909
|
+
return { hash, parents, author, authorEmail, authorDate, committer, committerEmail, commitDate, message, fileChanges, filesOmitted };
|
|
798
910
|
}
|
|
799
911
|
|
|
800
912
|
function buildGitActionArgs(action: string, args: Record<string, unknown>): string[] {
|
|
@@ -12,7 +12,7 @@ import { assertSafeFilePaths, assertValidHash, assertValidLineNumber, spawnGit }
|
|
|
12
12
|
import { openPanel } from "./panel-registry.ts";
|
|
13
13
|
import { registerViewCommand } from "./register-view-command.ts";
|
|
14
14
|
import { navigateToPanel, takePendingTarget } from "./panel-nav.ts";
|
|
15
|
-
import {
|
|
15
|
+
import { resolveFileTab } from "./ppm-api.ts";
|
|
16
16
|
import { FILE_HISTORY_FORMAT, buildLineRangeArg, parseFileHistory } from "./file-history-parser.ts";
|
|
17
17
|
import { FILE_PICKER_CSS, FILE_PICKER_HTML, FILE_PICKER_JS, shellHtml } from "./webview-shell.ts";
|
|
18
18
|
|
|
@@ -99,11 +99,10 @@ export function openFileHistoryView(
|
|
|
99
99
|
assertSafeFilePaths([filePath], projectPath);
|
|
100
100
|
const hash = assertValidHash(msg.hash);
|
|
101
101
|
const fileName = filePath.split(/[\\/]/).pop() || filePath;
|
|
102
|
-
const
|
|
102
|
+
const target = await resolveFileTab(projectPath, filePath);
|
|
103
103
|
const parent = await spawnGit(vscode, ["rev-parse", `${hash}^`], projectPath);
|
|
104
|
-
await vscode.window.openTab("git-diff", `${fileName} (${hash.slice(0, 7)})`, projectName, {
|
|
105
|
-
|
|
106
|
-
filePath,
|
|
104
|
+
await vscode.window.openTab("git-diff", `${fileName} (${hash.slice(0, 7)})`, target.projectName, {
|
|
105
|
+
...target,
|
|
107
106
|
...(parent.exitCode === 0 ? { ref1: parent.stdout.trim() } : {}),
|
|
108
107
|
ref2: hash,
|
|
109
108
|
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `git-exec.ts` opens with the rule this file enforces: every git argument that
|
|
3
|
+
* originates in a webview passes through one of its `assert*` guards before it
|
|
4
|
+
* reaches `spawn`. The branch in a commit window did not — and since the stats
|
|
5
|
+
* pass was split out, that window is built twice per request, so the value
|
|
6
|
+
* reached git on two paths instead of one.
|
|
7
|
+
*
|
|
8
|
+
* git does reject a dash-leading refname by itself, so nothing was exploitable.
|
|
9
|
+
* The guard is what makes that a property of this code rather than a property
|
|
10
|
+
* of whichever git happens to be installed.
|
|
11
|
+
*/
|
|
12
|
+
import { describe, it, expect } from "bun:test";
|
|
13
|
+
import { logArgs } from "./extension.ts";
|
|
14
|
+
|
|
15
|
+
describe("logArgs", () => {
|
|
16
|
+
it("puts a real branch at the end of the arguments", () => {
|
|
17
|
+
const args = logArgs({ maxCommits: 50, skip: 0, branch: "feature/x" }, "--format=%H");
|
|
18
|
+
|
|
19
|
+
expect(args).toEqual(["log", "--format=%H", "--topo-order", "-n", "50", "feature/x"]);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("asks for every ref but the stashes when no branch is named", () => {
|
|
23
|
+
for (const window of [{ maxCommits: 10, skip: 0 }, { maxCommits: 10, skip: 0, branch: "all" }]) {
|
|
24
|
+
expect(logArgs(window, "--format=%H")).toEqual([
|
|
25
|
+
"log", "--format=%H", "--topo-order", "-n", "10", "--exclude=refs/stash", "--all",
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("carries the window's paging and ordering", () => {
|
|
31
|
+
expect(logArgs({ maxCommits: 20, skip: 40, ordering: "date", firstParentOnly: true }, "--format=%H"))
|
|
32
|
+
.toEqual([
|
|
33
|
+
"log", "--format=%H", "--date-order", "-n", "20", "--first-parent", "--skip=40",
|
|
34
|
+
"--exclude=refs/stash", "--all",
|
|
35
|
+
]);
|
|
36
|
+
expect(logArgs({ maxCommits: 20, skip: 0, ordering: "author-date" }, "--format=%H"))
|
|
37
|
+
.toContain("--author-date-order");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("refuses a branch git would read as an option", () => {
|
|
41
|
+
expect(() => logArgs({ maxCommits: 10, skip: 0, branch: "--upload-pack=sh" }, "--format=%H"))
|
|
42
|
+
.toThrow(/Invalid git ref/);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("refuses a branch that is really a range", () => {
|
|
46
|
+
// `a..b` is two commits, not one ref: it would silently change which
|
|
47
|
+
// commits the graph and the stats pass are asking about.
|
|
48
|
+
expect(() => logArgs({ maxCommits: 10, skip: 0, branch: "main..evil" }, "--format=%H"))
|
|
49
|
+
.toThrow(/Invalid git ref/);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("refuses a branch with a control character or a revision operator in it", () => {
|
|
53
|
+
for (const branch of ["main\u0000", "main^{tree}", "main:path", "ma in\n--all"]) {
|
|
54
|
+
expect(() => logArgs({ maxCommits: 10, skip: 0, branch }, "--format=%H")).toThrow(/Invalid git ref/);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Thin client for the PPM HTTP API, used to map a project path to the project
|
|
3
3
|
* name that `window.openTab` needs. Initialised once from `activate`.
|
|
4
4
|
*/
|
|
5
|
+
import { pickProject, toProjectRelative, type ProjectRef } from "./project-scope.ts";
|
|
5
6
|
let baseUrl = "";
|
|
6
7
|
let authToken = "";
|
|
7
8
|
|
|
@@ -33,16 +34,48 @@ export async function resolveProjectPath(): Promise<string | null> {
|
|
|
33
34
|
return null;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
/**
|
|
37
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the registered project owning `dirPath` via the PPM API.
|
|
39
|
+
*
|
|
40
|
+
* `dirPath` is the panel's git root, which for a container workspace is a
|
|
41
|
+
* *subfolder* of the project — so an exact match is not enough. The basename
|
|
42
|
+
* fallback is kept for the case where the API cannot be reached at all, but it
|
|
43
|
+
* is a guess: it names no registered project, so anything built from it will
|
|
44
|
+
* 404.
|
|
45
|
+
*/
|
|
46
|
+
export async function resolveProject(dirPath: string): Promise<ProjectRef> {
|
|
38
47
|
try {
|
|
39
48
|
const res = await fetch(`${baseUrl}/api/projects`, authHeaders());
|
|
40
|
-
const json = await res.json() as { ok: boolean; data?:
|
|
49
|
+
const json = await res.json() as { ok: boolean; data?: ProjectRef[] };
|
|
41
50
|
if (json.ok && json.data) {
|
|
42
|
-
const match = json.data
|
|
43
|
-
if (match) return match
|
|
51
|
+
const match = pickProject(json.data, dirPath);
|
|
52
|
+
if (match) return match;
|
|
44
53
|
}
|
|
45
54
|
} catch {}
|
|
46
55
|
// Fallback to directory name
|
|
47
|
-
return
|
|
56
|
+
return { name: dirPath.split(/[\\/]/).filter(Boolean).pop() || "project", path: dirPath };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Resolve project name from path via PPM API */
|
|
60
|
+
export async function resolveProjectName(dirPath: string): Promise<string> {
|
|
61
|
+
return (await resolveProject(dirPath)).name;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* What a tab needs to open a file git named: the project it belongs to, and the
|
|
66
|
+
* path expressed relative to *that* rather than to the repository git ran in.
|
|
67
|
+
*
|
|
68
|
+
* Both come from one lookup on purpose — the name and the rebasing depend on
|
|
69
|
+
* the same answer, and resolving them separately is how one of them gets
|
|
70
|
+
* forgotten.
|
|
71
|
+
*/
|
|
72
|
+
export async function resolveFileTab(
|
|
73
|
+
gitRoot: string,
|
|
74
|
+
filePath: string,
|
|
75
|
+
): Promise<{ projectName: string; filePath: string }> {
|
|
76
|
+
const project = await resolveProject(gitRoot);
|
|
77
|
+
return {
|
|
78
|
+
projectName: project.name,
|
|
79
|
+
filePath: toProjectRelative(project.path, gitRoot, filePath),
|
|
80
|
+
};
|
|
48
81
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { pickProject, toProjectRelative } from "./project-scope.ts";
|
|
3
|
+
|
|
4
|
+
const projects = [
|
|
5
|
+
{ name: "workspace", path: "/home/me/work" },
|
|
6
|
+
{ name: "inner", path: "/home/me/work/inner" },
|
|
7
|
+
{ name: "other", path: "/home/me/other" },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
describe("pickProject", () => {
|
|
11
|
+
test("matches a project by its own path", () => {
|
|
12
|
+
expect(pickProject(projects, "/home/me/other")?.name).toBe("other");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("finds the project containing a repository one level down", () => {
|
|
16
|
+
// The whole point: a panel is opened on the repository, and the project it
|
|
17
|
+
// belongs to is what every API route and tab is keyed by.
|
|
18
|
+
expect(pickProject(projects, "/home/me/work/service-a")?.name).toBe("workspace");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("prefers the innermost project when they nest", () => {
|
|
22
|
+
expect(pickProject(projects, "/home/me/work/inner/pkg")?.name).toBe("inner");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("does not match a sibling that merely shares a prefix", () => {
|
|
26
|
+
expect(pickProject(projects, "/home/me/work-evil/repo")).toBeNull();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("ignores a trailing separator on either side", () => {
|
|
30
|
+
expect(pickProject([{ name: "w", path: "/home/me/work/" }], "/home/me/work")?.name).toBe("w");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("treats a Windows path the same as a POSIX one", () => {
|
|
34
|
+
const win = [{ name: "w", path: "C:\\Users\\me\\work" }];
|
|
35
|
+
expect(pickProject(win, "C:\\Users\\me\\work\\service-a")?.name).toBe("w");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("answers null when nothing owns the path", () => {
|
|
39
|
+
expect(pickProject(projects, "/tmp/elsewhere")).toBeNull();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("toProjectRelative", () => {
|
|
44
|
+
test("is the identity when the repository is the project", () => {
|
|
45
|
+
// Every ordinary project takes this path, so it must not be able to change.
|
|
46
|
+
expect(toProjectRelative("/home/me/work", "/home/me/work", "src/index.ts")).toBe("src/index.ts");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("prefixes the repository's own directory when it is nested", () => {
|
|
50
|
+
expect(toProjectRelative("/home/me/work", "/home/me/work/service-a", "src/index.ts")).toBe(
|
|
51
|
+
"service-a/src/index.ts",
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("keeps a repository two levels down whole", () => {
|
|
56
|
+
expect(toProjectRelative("/home/me/work", "/home/me/work/apps/api", "main.go")).toBe(
|
|
57
|
+
"apps/api/main.go",
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("strips a leading ./ and normalises separators", () => {
|
|
62
|
+
expect(toProjectRelative("/home/me/work", "/home/me/work/svc", "./src\\a.ts")).toBe(
|
|
63
|
+
"svc/src/a.ts",
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("leaves the path alone when the repository is not inside the project", () => {
|
|
68
|
+
// A worktree opened from outside the project: there is no prefix that would
|
|
69
|
+
// make the path meaningful, and inventing one would name a file that is not
|
|
70
|
+
// there.
|
|
71
|
+
expect(toProjectRelative("/home/me/work", "/tmp/wt", "src/index.ts")).toBe("src/index.ts");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("answers the repository directory itself for an empty path", () => {
|
|
75
|
+
expect(toProjectRelative("/home/me/work", "/home/me/work/svc", "")).toBe("svc");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which PPM project a panel's git root belongs to, and how to address a file
|
|
3
|
+
* inside it.
|
|
4
|
+
*
|
|
5
|
+
* A panel is opened on the *repository*. For nearly every project that is the
|
|
6
|
+
* project folder itself, but a workspace folder can be a container whose
|
|
7
|
+
* children are the repositories — so the path a panel was handed is often a
|
|
8
|
+
* subfolder of the project. Two things follow, and both are silent failures
|
|
9
|
+
* otherwise:
|
|
10
|
+
*
|
|
11
|
+
* - The project name is not the basename of that path. It is the name of the
|
|
12
|
+
* registered project *containing* it, because that is what `/api/projects/:name`
|
|
13
|
+
* and `window.openTab` are keyed by; the basename fallback would build URLs
|
|
14
|
+
* for a project that does not exist and 404.
|
|
15
|
+
* - A file path git reported is relative to the repository, while a tab's
|
|
16
|
+
* `filePath` is relative to the project. Opening a diff without rebasing it
|
|
17
|
+
* lands one or more directories too high and shows an empty buffer for a file
|
|
18
|
+
* that plainly exists.
|
|
19
|
+
*
|
|
20
|
+
* Pure on purpose: the fetch-backed wrappers live in `ppm-api.ts`.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export interface ProjectRef {
|
|
24
|
+
name: string;
|
|
25
|
+
path: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Trailing separators off, backslashes to forward slashes. */
|
|
29
|
+
function normalizeDir(path: string): string {
|
|
30
|
+
return path.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The registered project that owns `dirPath`, or null when none does.
|
|
35
|
+
*
|
|
36
|
+
* Longest match wins: a project nested inside another one is the more specific
|
|
37
|
+
* answer, and taking the first hit would attribute its repositories to the
|
|
38
|
+
* outer project.
|
|
39
|
+
*/
|
|
40
|
+
export function pickProject(projects: ProjectRef[], dirPath: string): ProjectRef | null {
|
|
41
|
+
const target = normalizeDir(dirPath);
|
|
42
|
+
let best: ProjectRef | null = null;
|
|
43
|
+
let bestLength = -1;
|
|
44
|
+
for (const project of projects) {
|
|
45
|
+
const root = normalizeDir(project.path);
|
|
46
|
+
if (target !== root && !target.startsWith(`${root}/`)) continue;
|
|
47
|
+
if (root.length > bestLength) {
|
|
48
|
+
best = project;
|
|
49
|
+
bestLength = root.length;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return best;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A repository-relative file path, expressed relative to the project root.
|
|
57
|
+
*
|
|
58
|
+
* The identity when the repository *is* the project — which is the case worth
|
|
59
|
+
* protecting, since it is every ordinary project.
|
|
60
|
+
*/
|
|
61
|
+
export function toProjectRelative(projectPath: string, gitRoot: string, filePath: string): string {
|
|
62
|
+
const root = normalizeDir(projectPath);
|
|
63
|
+
const repo = normalizeDir(gitRoot);
|
|
64
|
+
const file = filePath.replace(/\\/g, "/").replace(/^\.?\//, "");
|
|
65
|
+
if (repo === root) return file;
|
|
66
|
+
if (!repo.startsWith(`${root}/`)) return file;
|
|
67
|
+
const prefix = repo.slice(root.length + 1);
|
|
68
|
+
return file ? `${prefix}/${file}` : prefix;
|
|
69
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import { parseShortstat } from "./shortstat-parser.ts";
|
|
3
|
+
|
|
4
|
+
const A = "a".repeat(40);
|
|
5
|
+
const B = "b".repeat(40);
|
|
6
|
+
const C = "c".repeat(40);
|
|
7
|
+
|
|
8
|
+
describe("parseShortstat", () => {
|
|
9
|
+
it("reads insertions and deletions", () => {
|
|
10
|
+
const out = parseShortstat(`${A}\n 3 files changed, 12 insertions(+), 4 deletions(-)\n`);
|
|
11
|
+
expect(out[A]).toEqual({ files: 3, insertions: 12, deletions: 4 });
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("handles a commit that only adds, and one that only deletes", () => {
|
|
15
|
+
const out = parseShortstat(
|
|
16
|
+
`${A}\n 1 file changed, 2 insertions(+)\n\n${B}\n 1 file changed, 7 deletions(-)\n`,
|
|
17
|
+
);
|
|
18
|
+
expect(out[A]).toEqual({ files: 1, insertions: 2, deletions: 0 });
|
|
19
|
+
expect(out[B]).toEqual({ files: 1, insertions: 0, deletions: 7 });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("leaves a merge commit out rather than giving it zeroes", () => {
|
|
23
|
+
// git prints no diffstat for a merge by default. Absent and 0/0 are
|
|
24
|
+
// different things: one is "not computed", the other is "changed nothing".
|
|
25
|
+
const out = parseShortstat(`${A}\n\n${B}\n 2 files changed, 1 insertion(+)\n`);
|
|
26
|
+
expect(out[A]).toBeUndefined();
|
|
27
|
+
expect(out[B]).toEqual({ files: 2, insertions: 1, deletions: 0 });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("keeps each stat with the hash printed before it", () => {
|
|
31
|
+
const out = parseShortstat(
|
|
32
|
+
`${A}\n 1 file changed, 1 insertion(+)\n\n${B}\n 2 files changed, 2 insertions(+)\n\n${C}\n 3 files changed, 3 deletions(-)\n`,
|
|
33
|
+
);
|
|
34
|
+
expect(out[A]!.insertions).toBe(1);
|
|
35
|
+
expect(out[B]!.insertions).toBe(2);
|
|
36
|
+
expect(out[C]!.deletions).toBe(3);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("ignores a stat line with no hash before it", () => {
|
|
40
|
+
const out = parseShortstat(" 9 files changed, 9 insertions(+)\n");
|
|
41
|
+
expect(Object.keys(out)).toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("ignores anything that is not a full hash", () => {
|
|
45
|
+
// A short hash in a commit message must not be mistaken for a record start.
|
|
46
|
+
const out = parseShortstat(`8abb115\n 1 file changed, 1 insertion(+)\n`);
|
|
47
|
+
expect(Object.keys(out)).toEqual([]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("is empty for empty output", () => {
|
|
51
|
+
expect(parseShortstat("")).toEqual({});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `git log --format=%H --shortstat` into a hash → lines-changed map.
|
|
3
|
+
*
|
|
4
|
+
* A second pass rather than `--shortstat` on the main log: adding it there costs
|
|
5
|
+
* git a diff per commit (~100ms for 300 commits on a 2k-commit repository, and
|
|
6
|
+
* far more on a large one) and that cost would land *before* the graph could be
|
|
7
|
+
* drawn at all. This runs after the commits have already been sent, so the
|
|
8
|
+
* numbers fill in a moment later and nothing waits for them.
|
|
9
|
+
*
|
|
10
|
+
* A merge commit produces no diffstat at all, which is git's default and not an
|
|
11
|
+
* error — it is simply absent from the map, and the column stays blank for it.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export interface CommitStat {
|
|
15
|
+
files: number;
|
|
16
|
+
insertions: number;
|
|
17
|
+
deletions: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** " 3 files changed, 12 insertions(+), 4 deletions(-)" — any of the three clauses may be missing. */
|
|
21
|
+
const SHORTSTAT = /^\s*(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/;
|
|
22
|
+
const FULL_HASH = /^[0-9a-f]{40}$/;
|
|
23
|
+
|
|
24
|
+
export function parseShortstat(stdout: string): Record<string, CommitStat> {
|
|
25
|
+
const stats: Record<string, CommitStat> = {};
|
|
26
|
+
let hash: string | null = null;
|
|
27
|
+
|
|
28
|
+
for (const line of stdout.split("\n")) {
|
|
29
|
+
if (FULL_HASH.test(line.trim())) {
|
|
30
|
+
hash = line.trim();
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const match = SHORTSTAT.exec(line);
|
|
34
|
+
// The stat follows the hash it belongs to, so a stat with no hash before it
|
|
35
|
+
// is not ours — better to drop it than to attach it to the wrong commit.
|
|
36
|
+
if (!match || !hash) continue;
|
|
37
|
+
stats[hash] = {
|
|
38
|
+
files: Number(match[1]),
|
|
39
|
+
insertions: match[2] ? Number(match[2]) : 0,
|
|
40
|
+
deletions: match[3] ? Number(match[3]) : 0,
|
|
41
|
+
};
|
|
42
|
+
hash = null;
|
|
43
|
+
}
|
|
44
|
+
return stats;
|
|
45
|
+
}
|