@hienlh/ppm 0.20.9 → 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 +114 -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/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-CTx8qAkv.js → angular-html-DkR4iCth.js} +1 -1
- package/dist/web/assets/{angular-ts-BhBGUAnu.js → angular-ts-DcyL4Chx.js} +1 -1
- package/dist/web/assets/api-client-BUCo1lms.js +1 -0
- package/dist/web/assets/{api-settings-CqiVKFUX.js → api-settings-BcNjZIvG.js} +1 -1
- package/dist/web/assets/{api-themes-DtLXqXpC.js → api-themes-DBfyVUtX.js} +1 -1
- package/dist/web/assets/{apl-Dec3pSzF.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-Cb_3-S86.js → astro-MjJlozLj.js} +1 -1
- package/dist/web/assets/audio-preview-Bc54GCAV.js +1 -0
- package/dist/web/assets/{blade-1QMj5JxI.js → blade-DnJWi1fz.js} +1 -1
- package/dist/web/assets/{bsl-D0bT3Wjp.js → bsl-DCmJxSIz.js} +1 -1
- package/dist/web/assets/{button-DhnNoqpV.js → button-VW4QGKCn.js} +1 -1
- package/dist/web/assets/{cairo-DTuGb2w7.js → cairo-C8dDenub.js} +1 -1
- package/dist/web/assets/chat-tab-Cr6_KSGO.js +15 -0
- package/dist/web/assets/{cobol-DSx_Nb7T.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-DBcQ7DKB.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-Bj1azGr-.js → cpp-BLJN0umi.js} +1 -1
- package/dist/web/assets/{crystal-CCgkDI0i.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-C2NAQ-88.js → data-grid-overlay-editor-D4fhcMfT.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/docx-preview-DYBkiUaE.js +12 -0
- package/dist/web/assets/{edge-ClBfeO7z.js → edge-rWOlCmXT.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-CRjufuw_.js → edit-diff-preview-COtmo54G.js} +1 -1
- 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-ir__-3kt.js → elixir-E7Y82okW.js} +1 -1
- package/dist/web/assets/{elm-CUv-xMuU.js → elm-DTPGbc-w.js} +1 -1
- package/dist/web/assets/{erb-DcRwHyUq.js → erb-DHqLHrE6.js} +1 -1
- package/dist/web/assets/{erlang-DW-GAdmv.js → erlang-Byg0nNiV.js} +1 -1
- package/dist/web/assets/{esm-DBm5LSCw.js → esm-D_DmOM7n.js} +1 -1
- 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-DrQbMSkt.js → fortran-fixed-form-CY1n0Xf6.js} +1 -1
- package/dist/web/assets/{fsharp-DvDj84Ys.js → fsharp-_vEDSCJz.js} +1 -1
- package/dist/web/assets/{gdresource-CPgY7R2s.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-NJ9iGbTd.js → git-commit-Wk9ovq59.js} +1 -1
- package/dist/web/assets/git-log-panel-CRN4JVOx.js +1 -0
- package/dist/web/assets/{git-rebase-DBSy9OKE.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-EGWSSdwJ.js → glimmer-js-CkYI35_P.js} +1 -1
- package/dist/web/assets/{glimmer-ts-BpfXRYRV.js → glimmer-ts-BqmIZcds.js} +1 -1
- package/dist/web/assets/{glsl-BtWQ4j8X.js → glsl-Be-yBCF5.js} +1 -1
- package/dist/web/assets/{graphql-DHR5AO2c.js → graphql-a5DrENHY.js} +1 -1
- package/dist/web/assets/group-chat-tab-DFa5mAx5.js +1 -0
- package/dist/web/assets/{hack-A3iOItmC.js → hack-BLAg20aD.js} +1 -1
- package/dist/web/assets/{haml-DXA8NXfZ.js → haml-Dj6bGOQH.js} +1 -1
- package/dist/web/assets/{handlebars-BdIFK4pP.js → handlebars-dmEa36Oh.js} +1 -1
- package/dist/web/assets/{html-derivative-Cd_vDV4L.js → html-derivative-lLi3-RNT.js} +1 -1
- package/dist/web/assets/{html-BTA4eRkb.js → html-yacZYzSE.js} +1 -1
- package/dist/web/assets/{http-CMY5fp9k.js → http-1KaxcE4e.js} +1 -1
- package/dist/web/assets/{hurl-DJZLRi6K.js → hurl-ST-dEEZR.js} +1 -1
- package/dist/web/assets/{hxml-C2EdtM37.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-DWU92jHm.js → jinja-Cjw-evAn.js} +1 -1
- package/dist/web/assets/{jira-watcher-section-BhQzWJ3r.js → jira-watcher-section-DIC1yIV3.js} +1 -1
- package/dist/web/assets/{jison-Bt3f5-S6.js → jison-DfATMYoY.js} +1 -1
- package/dist/web/assets/{julia-BS-e0jQg.js → julia-DDCaxiqT.js} +1 -1
- package/dist/web/assets/{just-OU89Ot3I.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-Bt5mTs31.js → latex-Zc4EpLpW.js} +1 -1
- package/dist/web/assets/{liquid-C03IGCJ6.js → liquid-B_6KMNYS.js} +1 -1
- package/dist/web/assets/{lua-Dl4zPu0P.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-BEnkIoHY.js → marko-Wk6LBnck.js} +1 -1
- package/dist/web/assets/{mdc-DGglct19.js → mdc-cRaXBrzL.js} +1 -1
- package/dist/web/assets/{media-url-LiPp2UsV.js → media-url-DL8OCGGg.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-BizNfPAu.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-DKFYidyC.js → nextflow-Bos2wvDV.js} +1 -1
- package/dist/web/assets/{nginx-Bhq0tzlh.js → nginx-DMlOwzdr.js} +1 -1
- package/dist/web/assets/{nim-CSuBzart.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-CYHlP43e.js → number-overlay-editor-DZ2i_Bnb.js} +1 -1
- package/dist/web/assets/{overview-panel-xn2BYvn6.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-uDVR7Ceh.js → perl-C5-Z6fPn.js} +1 -1
- package/dist/web/assets/{php-Bby8J3zk.js → php-BXNNhkMH.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-D0oogIFi.js +1 -0
- package/dist/web/assets/{postgres-viewer-CJbHLcGE.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-Dy3A3LJT.js → project-store-BhMbVln3.js} +1 -1
- package/dist/web/assets/proxy-settings-section-Bv0Ny-Yy.js +1 -0
- package/dist/web/assets/{pug-EapfojTW.js → pug-C1zf1yWy.js} +1 -1
- package/dist/web/assets/{qml-DiR6J5_C.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-B2QvlGNY.js → razor-DzjSaobM.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-D2eJ0kH4.js → rst-RfuihOUW.js} +1 -1
- package/dist/web/assets/{ruby-DzpnBpz-.js → ruby-CNO3pli1.js} +1 -1
- package/dist/web/assets/{run-in-terminal-DisO5HC-.js → run-in-terminal-Cb_hVU8x.js} +1 -1
- package/dist/web/assets/{sas-WDAKsX0U.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-Ci6PdscL.js → scss--4g-REcN.js} +1 -1
- package/dist/web/assets/{send-to-chat-DDFdKWNf.js → send-to-chat-Cnpru1M0.js} +1 -1
- package/dist/web/assets/{separator-CyisF27O.js → separator-Cds1yxy8.js} +1 -1
- 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-Cv3mWofL.js → shaderlab-Cu4sBiVn.js} +1 -1
- package/dist/web/assets/{shellsession-D1KVtQa1.js → shellsession-DWzJfEv7.js} +1 -1
- package/dist/web/assets/{soy-BGLBwFZT.js → soy-BnqE-5Ff.js} +1 -1
- package/dist/web/assets/{sparql-TvnQmFDh.js → sparql-Ctg__NhZ.js} +1 -1
- package/dist/web/assets/{sql-query-editor-DaQqRBNA.js → sql-query-editor-D9k19T_M.js} +1 -1
- package/dist/web/assets/sqlite-viewer-DoV9hnWJ.js +1 -0
- package/dist/web/assets/{stata-Gi-BKyEv.js → stata-Qk2h66XW.js} +1 -1
- package/dist/web/assets/{streaming-store-DAbnOfLu.js → streaming-store-uDu3PoN1.js} +1 -1
- package/dist/web/assets/{surrealql-BVXs6tkz.js → surrealql-8QEX7EfH.js} +1 -1
- package/dist/web/assets/{svelte-BlnFpLWV.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-B7BksLr-.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-YJYH5r1A.js → templ-C1jV0fsO.js} +1 -1
- package/dist/web/assets/terminal-tab-Cs0sGljx.js +3 -0
- package/dist/web/assets/{tex-IVZLDIeh.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-DBd321I-.js → ts-tags-B5m47rEm.js} +1 -1
- package/dist/web/assets/{twig-DQENQjEn.js → twig-C_br6GIl.js} +1 -1
- package/dist/web/assets/{use-blob-url-CGChX4vi.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-lsp-CV0vzILO.js +6 -0
- package/dist/web/assets/use-monaco-theme-DBqbWjWX.js +1 -0
- package/dist/web/assets/{use-open-team-member-kmNnlzDD.js → use-open-team-member-DENsjp0s.js} +1 -1
- package/dist/web/assets/use-remote-desktop-display-choice-BK_f787P.js +1 -0
- package/dist/web/assets/{use-websocket-D8OGBwH8.js → use-websocket-LgXiX1qN.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-BoRFiriK.js → vendor-mermaid-Cbig5zA6.js} +1 -1
- package/dist/web/assets/video-preview-BDNwumbW.js +1 -0
- package/dist/web/assets/{vue-Do2JXEwi.js → vue-DQwCnLdr.js} +1 -1
- package/dist/web/assets/{vue-html-Bse0CwSC.js → vue-html-T_EoGpPJ.js} +1 -1
- package/dist/web/assets/{vue-vine-C8JSXu5Z.js → vue-vine-DmxLqX50.js} +1 -1
- package/dist/web/assets/{window-pip-registry-C2dcY0pE.js → window-pip-registry-3l4hoxuD.js} +1 -1
- package/dist/web/assets/{window-store-2z4t5YAt.js → window-store-UC1jJeLM.js} +1 -1
- package/dist/web/assets/ws-auth-DEAJiGCR.js +1 -0
- package/dist/web/assets/{xml-OX6YmzGK.js → xml-Bs6Bw8is.js} +1 -1
- package/dist/web/assets/{xsl-RQUQgcgy.js → xsl-f5ZNhRCc.js} +1 -1
- package/dist/web/index.html +105 -71
- 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/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/monaco-staging.ts +32 -0
- package/scripts/precompress-web.ts +77 -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/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/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-copy.ts +1 -0
- 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 +9 -3
- package/src/web/components/tunnels/named-tunnel/named-tunnel-setup-popup.tsx +1 -1
- package/src/web/components/tunnels/named-tunnel/named-tunnel-step-reducer.ts +14 -2
- 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-ByM99C7p.js +0 -1
- package/dist/web/assets/ai-resource-editor-BsB9wa0z.js +0 -1
- package/dist/web/assets/ai-settings-section-BT-QVUBa.js +0 -1
- package/dist/web/assets/ai-settings-section-BUPOINaw.js +0 -1
- package/dist/web/assets/api-client-C6VTn7cG.js +0 -1
- package/dist/web/assets/appearance-settings-section-DJEoECoJ.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-D55g5j-p.js +0 -1
- package/dist/web/assets/arrow-left-DpXaakMC.js +0 -1
- package/dist/web/assets/arrow-right-BqNSIscF.js +0 -1
- package/dist/web/assets/audio-preview-CF4tTFv_.js +0 -1
- package/dist/web/assets/bot-D3-n2i31.js +0 -1
- package/dist/web/assets/brain-CuAQMSBE.js +0 -1
- package/dist/web/assets/calendar-clock-CDP7AVjA.js +0 -1
- package/dist/web/assets/chat-tab-fD2vWwj2.js +0 -15
- package/dist/web/assets/check-BQKbhtoA.js +0 -1
- package/dist/web/assets/chevron-down-B9puixxZ.js +0 -1
- package/dist/web/assets/chevron-right-DK_HbYZC.js +0 -1
- package/dist/web/assets/chevron-up-BPAINgoK.js +0 -1
- package/dist/web/assets/circle-BpGTLAas.js +0 -1
- package/dist/web/assets/circle-question-mark-DUaySkoB.js +0 -1
- package/dist/web/assets/clock-Dqq0H9yH.js +0 -1
- package/dist/web/assets/code-CX6640Tv.js +0 -1
- package/dist/web/assets/code-editor-CyFLXCsD.js +0 -7
- package/dist/web/assets/codex-daily-guard-Cg19EWxk.js +0 -1
- package/dist/web/assets/conflict-editor-DSjo2FRy.js +0 -19
- package/dist/web/assets/context-menu-DchAkdnL.js +0 -1
- package/dist/web/assets/copy-Bt_1tjoJ.js +0 -1
- package/dist/web/assets/csv-preview-BIE3Wpww.js +0 -2
- package/dist/web/assets/database-9_p74TtY.js +0 -1
- package/dist/web/assets/database-viewer-CMvIORcM.js +0 -1
- package/dist/web/assets/diff-viewer-BQQ6fUr6.js +0 -4
- package/dist/web/assets/docx-preview-DcCh59Oe.js +0 -12
- package/dist/web/assets/download-CEPFebri.js +0 -1
- package/dist/web/assets/explorer-body-DRo2JHP9.js +0 -2
- package/dist/web/assets/explorer-window-content-7mnRpSqn.js +0 -1
- package/dist/web/assets/extension-manager-section-CEfr7-Kv.js +0 -1
- package/dist/web/assets/extension-webview-D7HqqdTv.js +0 -3
- package/dist/web/assets/eye-BQaWPI4P.js +0 -1
- package/dist/web/assets/eye-off-BlB3QV90.js +0 -1
- package/dist/web/assets/file-exclamation-point-BDmSZbxs.js +0 -1
- package/dist/web/assets/files-settings-section-h6a-WpSO.js +0 -1
- package/dist/web/assets/flask-conical-Cj-J6cxs.js +0 -1
- package/dist/web/assets/folder-symlink-BSYalAHC.js +0 -1
- package/dist/web/assets/general-settings-section-Bt3KNcyM.js +0 -1
- package/dist/web/assets/git-log-panel-H-Bg9p7m.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-At-P8hlA.js +0 -1
- package/dist/web/assets/glide-data-grid-D3Xc_WGh.js +0 -141
- package/dist/web/assets/group-chat-tab-BkLt7J_s.js +0 -1
- package/dist/web/assets/hand-BkDyLfcc.js +0 -1
- package/dist/web/assets/image-preview-D_6-FhZP.js +0 -1
- package/dist/web/assets/index-BV_sFdHY.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-Cv4z7_KG.js +0 -1
- package/dist/web/assets/keybindings-store-alreySno.js +0 -1
- package/dist/web/assets/keyboard-HG0BUtuN.js +0 -1
- package/dist/web/assets/keyboard-shortcuts-section-B_D0FamP.js +0 -1
- package/dist/web/assets/loader-circle-H81ywCuQ.js +0 -1
- package/dist/web/assets/markdown-renderer-CG_nGh7k.js +0 -3
- package/dist/web/assets/markdown-renderer-CgbqvSuc.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-DAZTzi1k.js +0 -1
- package/dist/web/assets/monitor-CKcYUoAV.js +0 -1
- package/dist/web/assets/notification-store-HCg5Shw9.js +0 -1
- package/dist/web/assets/notifications-settings-section-BAs_p_ai.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-B20_sIFd.js +0 -1
- package/dist/web/assets/panel-store-XhAruR6D.js +0 -1
- package/dist/web/assets/pdf-preview-BJjqU3AX.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-nzfJdXCC.js +0 -1
- package/dist/web/assets/power-D_wlLkC0.js +0 -1
- package/dist/web/assets/ppmbot-settings-section-5U0a58oj.js +0 -1
- package/dist/web/assets/process-table-CqGL0Bcj.js +0 -1
- package/dist/web/assets/proxy-settings-section-B1LDpGSc.js +0 -1
- package/dist/web/assets/query-audit-section-DfCvY94_.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-CS4sHKD5.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-_LH4uCcA.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-view-C5TUPDh_.js +0 -1
- package/dist/web/assets/remote-desktop-readiness-gate-DuT4A893.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-B4V-1aJn.js +0 -1
- package/dist/web/assets/save-BehCuMf4.js +0 -1
- package/dist/web/assets/schedules-settings-section-C2SjwWFB.js +0 -1
- package/dist/web/assets/send-CtXcGcsk.js +0 -1
- package/dist/web/assets/settings-body-CdFauCAU.js +0 -2
- package/dist/web/assets/settings-store-BkNrLdjk.js +0 -2
- package/dist/web/assets/settings-tab-DGUlmMbc.js +0 -1
- package/dist/web/assets/settings-window-content-CIH5sihe.js +0 -1
- package/dist/web/assets/shield-check-z9PX8HVZ.js +0 -1
- package/dist/web/assets/shield-off-Du0U5dVI.js +0 -1
- package/dist/web/assets/sparkles-CO9zx1f-.js +0 -1
- package/dist/web/assets/sqlite-viewer-Bpz7QnBk.js +0 -1
- package/dist/web/assets/system-monitor-body-BBJOWFCa.js +0 -2
- package/dist/web/assets/system-monitor-tab-D7RIwhmg.js +0 -1
- package/dist/web/assets/system-monitor-window-content-CH0UmMP9.js +0 -1
- package/dist/web/assets/tab-host-window-content-C_yU5MH_.js +0 -1
- package/dist/web/assets/table-BK4h8E7u.js +0 -1
- package/dist/web/assets/team-member-sheet-CopMME1E.js +0 -2
- package/dist/web/assets/team-member-window-content-CUDQ6oX7.js +0 -1
- package/dist/web/assets/terminal-tab-BjI95uG5.js +0 -3
- package/dist/web/assets/text-wrap-DLtVgSnU.js +0 -1
- package/dist/web/assets/tool-cards-I71v1w5Z.js +0 -9
- package/dist/web/assets/treemap-KZPCXAKY-BBrhTPZk.js +0 -1
- package/dist/web/assets/use-coarse-long-press-XrJ4Upuv.js +0 -1
- package/dist/web/assets/use-inline-blame-CRUwd6FF.js +0 -8
- package/dist/web/assets/use-monaco-theme-qzMbRfCW.js +0 -1
- package/dist/web/assets/use-remote-desktop-display-choice-0zDkCmsK.js +0 -1
- package/dist/web/assets/video-preview-Mlgl7hGr.js +0 -1
- package/dist/web/assets/ws-auth-DI1E6Fe7.js +0 -1
- package/dist/web/assets/x-DlnNFF2t.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-BIHt2d9F.js → abap-tkptwpsK.js} +0 -0
- /package/dist/web/assets/{actionscript-3-rbCNRHFj.js → actionscript-3-Di9TMGwg.js} +0 -0
- /package/dist/web/assets/{ada-CN94LQTJ.js → ada-CB9F079D.js} +0 -0
- /package/dist/web/assets/{andromeeda-BsmcoXuQ.js → andromeeda-Dcl8jpb7.js} +0 -0
- /package/dist/web/assets/{apache-pRQmqcVZ.js → apache-D0Nk0qsH.js} +0 -0
- /package/dist/web/assets/{apex-CNEumC1X.js → apex-mQIoWncD.js} +0 -0
- /package/dist/web/assets/{api-client-DKvkxuDr.js → api-client-bfB7cXRM.js} +0 -0
- /package/dist/web/assets/{applescript-DjEVsS-3.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-DbhZRlTL.js → ara-WFqRPGPe.js} +0 -0
- /package/dist/web/assets/{asciidoc-BsfbAXIK.js → asciidoc-bNd8w4nf.js} +0 -0
- /package/dist/web/assets/{asm-Vw5NMXjI.js → asm-BQ1_F580.js} +0 -0
- /package/dist/web/assets/{aurora-x-CoahU6sR.js → aurora-x-Ciqs_Dbu.js} +0 -0
- /package/dist/web/assets/{awk-ChKjCxHz.js → awk-GCR-6KZV.js} +0 -0
- /package/dist/web/assets/{ayu-dark-By9RKxTf.js → ayu-dark-DxJXuj99.js} +0 -0
- /package/dist/web/assets/{ayu-light-CEsgeLON.js → ayu-light-jvSyJWDV.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-CYrtwSLW.js → ayu-mirage-Cg3BPO6H.js} +0 -0
- /package/dist/web/assets/{ballerina-CCSVz22W.js → ballerina-BPz4CrX6.js} +0 -0
- /package/dist/web/assets/{bat-DU4--CMj.js → bat-CSTs2hIG.js} +0 -0
- /package/dist/web/assets/{beancount-DF_tlRlF.js → beancount-DMateAZX.js} +0 -0
- /package/dist/web/assets/{berry-CZTnatvO.js → berry-9lXg0GRM.js} +0 -0
- /package/dist/web/assets/{bibtex-BSpXy8jk.js → bibtex-DIbqmvFg.js} +0 -0
- /package/dist/web/assets/{bicep-yv1Ydq5Z.js → bicep-02WGsoJ8.js} +0 -0
- /package/dist/web/assets/{bird2-Db7Z7SMN.js → bird2-BY0tbu3k.js} +0 -0
- /package/dist/web/assets/{c-C3ivhwA4.js → c-jMBX_9Je.js} +0 -0
- /package/dist/web/assets/{c3-N4mKyst9.js → c3-B8JVbNjW.js} +0 -0
- /package/dist/web/assets/{cadence-BYK8tFFk.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-BK9Tv2XG.js → catppuccin-frappe-FhUCVxex.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-De4mVCp3.js → catppuccin-latte-CzfrtmgL.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-Bxt_D7cs.js → catppuccin-macchiato-6xL0lOtj.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-Dz2o8gN7.js → catppuccin-mocha-D39-xS3P.js} +0 -0
- /package/dist/web/assets/{clarity-BJdh0Pw-.js → clarity-D8TeGvoT.js} +0 -0
- /package/dist/web/assets/{clojure-DG-FYGzn.js → clojure-Dx_acSX7.js} +0 -0
- /package/dist/web/assets/{cmake-D1imEXan.js → cmake-CyeYPq8o.js} +0 -0
- /package/dist/web/assets/{codeowners-YpylTFB5.js → codeowners-DrTI0lmI.js} +0 -0
- /package/dist/web/assets/{codeql-ajDEPgqi.js → codeql-CPkFxVW-.js} +0 -0
- /package/dist/web/assets/{common-lisp-C2sCrd-m.js → common-lisp-B0k-3LTj.js} +0 -0
- /package/dist/web/assets/{coq-BqybyDc9.js → coq-uygpo7to.js} +0 -0
- /package/dist/web/assets/{createLucideIcon-D6fVXe3s.js → createLucideIcon-DoiEKeJ_.js} +0 -0
- /package/dist/web/assets/{csharp-nKCEiujy.js → csharp-DKUYGfSp.js} +0 -0
- /package/dist/web/assets/{css-CJSp2CsD.js → css-DoOUp7v4.js} +0 -0
- /package/dist/web/assets/{csv-Nh9vQwQm.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-Ch79RPsU.js → cue-DViO2wvn.js} +0 -0
- /package/dist/web/assets/{cypher-CgiOQ6hs.js → cypher-4BMCIW5N.js} +0 -0
- /package/dist/web/assets/{d-CmBcySpH.js → d-BT_sTHas.js} +0 -0
- /package/dist/web/assets/{dark-plus-COLEX2ui.js → dark-plus-DVVXu-1N.js} +0 -0
- /package/dist/web/assets/{dart-BTAArMcJ.js → dart-DHz6f6_6.js} +0 -0
- /package/dist/web/assets/{data-grid-types-tNj9zuRV.js → data-grid-types-OgUxMLdQ.js} +0 -0
- /package/dist/web/assets/{dax-BbZzRY9i.js → dax-ChYCjweK.js} +0 -0
- /package/dist/web/assets/{desktop-OmQvU3-J.js → desktop-D6Lt4p04.js} +0 -0
- /package/dist/web/assets/{diff-BEPnb9Fb.js → diff-D8TDe4hP.js} +0 -0
- /package/dist/web/assets/{dist-BiqPfYiP.js → dist-CrBOCtCW.js} +0 -0
- /package/dist/web/assets/{dist-BDpuZ376.js → dist-DOTlFQJA.js} +0 -0
- /package/dist/web/assets/{docker-Cg17HgTD.js → docker-Bsp0YbPx.js} +0 -0
- /package/dist/web/assets/{dotenv-DEMIaY7V.js → dotenv-B_7giSY_.js} +0 -0
- /package/dist/web/assets/{dracula-BkCFq8SO.js → dracula-TrQL2iB5.js} +0 -0
- /package/dist/web/assets/{dracula-soft-Cjp6-ltF.js → dracula-soft-n2XOlgh-.js} +0 -0
- /package/dist/web/assets/{dream-maker-Ce7Y_UKj.js → dream-maker-CdIEdhpT.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-BjpyfTbN.js → emacs-lisp-CSbixs6u.js} +0 -0
- /package/dist/web/assets/{everforest-dark-9r4okw1s.js → everforest-dark-BuZahZYp.js} +0 -0
- /package/dist/web/assets/{everforest-light-GCQTZ3Ju.js → everforest-light-DPH53z5H.js} +0 -0
- /package/dist/web/assets/{fennel-ITjY5Z6u.js → fennel-B1-K_hlJ.js} +0 -0
- /package/dist/web/assets/{fish-DP2uEzyg.js → fish-Cy12Dbua.js} +0 -0
- /package/dist/web/assets/{fluent-irzaP1f6.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-BAPoainr.js → fortran-free-form-BRQdNzZF.js} +0 -0
- /package/dist/web/assets/{gdscript-DJ098V1z.js → gdscript-XBDmLUm9.js} +0 -0
- /package/dist/web/assets/{gdshader-DS2Jfy-K.js → gdshader-DhVfB3u4.js} +0 -0
- /package/dist/web/assets/{genie-CqfOaFFx.js → genie-X3K29Y49.js} +0 -0
- /package/dist/web/assets/{gherkin-CoZ2ucDH.js → gherkin-DKIx-6cX.js} +0 -0
- /package/dist/web/assets/{github-dark-BNLgnSO9.js → github-dark-Bf7zdp5s.js} +0 -0
- /package/dist/web/assets/{github-dark-default-CYlSggwi.js → github-dark-default-DqsBBV11.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-DumUysDk.js → github-dark-dimmed-X2gqRz6w.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-TKrcDJ2I.js → github-dark-high-contrast-Z7tvbGX4.js} +0 -0
- /package/dist/web/assets/{github-light-DVENFHLJ.js → github-light-BKxt-7zZ.js} +0 -0
- /package/dist/web/assets/{github-light-default-DtN8AGcE.js → github-light-default-B0liF4d4.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-NSyF37x4.js → github-light-high-contrast-F4encJwr.js} +0 -0
- /package/dist/web/assets/{gleam-hp4NMSb5.js → gleam-Pz2bHgBB.js} +0 -0
- /package/dist/web/assets/{gn-Dptw2PEu.js → gn-CgmdNsPU.js} +0 -0
- /package/dist/web/assets/{gnuplot-9juRzjwv.js → gnuplot-qLNF5yZ9.js} +0 -0
- /package/dist/web/assets/{go-D-QLCda0.js → go-CSDUNhE7.js} +0 -0
- /package/dist/web/assets/{groovy-DHKNy6Eh.js → groovy-B3NEnOHF.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-BFD6aQdB.js → gruvbox-dark-hard-DcoftiUX.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-D5llYBNp.js → gruvbox-dark-medium-D1wVSuD8.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-DOztQmNR.js → gruvbox-dark-soft-DWpunymH.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-BFGD-8Pd.js → gruvbox-light-hard-rHMvyUdS.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-DzoyXgT7.js → gruvbox-light-medium-3O2KiXO7.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-B1Ix2zLN.js → gruvbox-light-soft-lNlXJPwH.js} +0 -0
- /package/dist/web/assets/{haskell-BnrJ0k7G.js → haskell-aaG3aC0h.js} +0 -0
- /package/dist/web/assets/{haxe-DwShHT_-.js → haxe-CPcHhUDd.js} +0 -0
- /package/dist/web/assets/{hcl-VOjEibVB.js → hcl-CMQNlR_4.js} +0 -0
- /package/dist/web/assets/{hjson-BHEn7pNn.js → hjson-DeuklPFj.js} +0 -0
- /package/dist/web/assets/{hlsl-CrvxlGii.js → hlsl-BI3hlsaM.js} +0 -0
- /package/dist/web/assets/{horizon-D3T-P0u6.js → horizon-C7-gOcjs.js} +0 -0
- /package/dist/web/assets/{horizon-bright-vifGsEdk.js → horizon-bright-Cxt9bRW7.js} +0 -0
- /package/dist/web/assets/{houston-IrOgT7r4.js → houston-DbF2G7iD.js} +0 -0
- /package/dist/web/assets/{hy-5eSgTJ8G.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-Dp0I4DVl.js → imba-CxKv_2TW.js} +0 -0
- /package/dist/web/assets/{ini-CHDKad9O.js → ini-BiHsyCdO.js} +0 -0
- /package/dist/web/assets/{java-YLv7IDJ1.js → java-D3RZzgDB.js} +0 -0
- /package/dist/web/assets/{javascript-jr4kIdgl.js → javascript-4FmSqG-T.js} +0 -0
- /package/dist/web/assets/{json-EJWSOZfp.js → json-CjB236_E.js} +0 -0
- /package/dist/web/assets/{json5-D6f_uNwJ.js → json5-bkfO-Rco.js} +0 -0
- /package/dist/web/assets/{jsonc-DrHCdmos.js → jsonc-BwaTeLyv.js} +0 -0
- /package/dist/web/assets/{jsonl-Cwc3cXEL.js → jsonl-CfxNSwGd.js} +0 -0
- /package/dist/web/assets/{jsonnet-BwZfaIFT.js → jsonnet-CQETCYrp.js} +0 -0
- /package/dist/web/assets/{jssm-BpEmg_MT.js → jssm-D5o3Zzdz.js} +0 -0
- /package/dist/web/assets/{jsx-DBGPwcr4.js → jsx-BAMILPLo.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-DRfVaGIX.js → kanagawa-dragon-BhGVxu3R.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-CjOlny0Q.js → kanagawa-lotus-FH4Y59ro.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-DvdM88a4.js → kanagawa-wave-eilvP9MB.js} +0 -0
- /package/dist/web/assets/{kdl-DSo3PvM0.js → kdl-BQ-yvXUK.js} +0 -0
- /package/dist/web/assets/{kotlin-BV8TwCGu.js → kotlin-BuCx0-VT.js} +0 -0
- /package/dist/web/assets/{kusto-DCo1Fdmm.js → kusto-DAN_n_Cy.js} +0 -0
- /package/dist/web/assets/{laserwave-DPX9FvD9.js → laserwave-Cq2BlxrT.js} +0 -0
- /package/dist/web/assets/{lean-Cya8dqZu.js → lean-Dhq7uXKw.js} +0 -0
- /package/dist/web/assets/{less-CJUPgkIs.js → less-CxaMQb8j.js} +0 -0
- /package/dist/web/assets/{lib-DUBAP_Gd.js → lib-BVwmtv2i.js} +0 -0
- /package/dist/web/assets/{libesm-CcPYXCKp.js → libesm-DdtEjhIi.js} +0 -0
- /package/dist/web/assets/{light-plus-BXXrlFJH.js → light-plus-B4sMAend.js} +0 -0
- /package/dist/web/assets/{llvm-CUbQanZr.js → llvm-DQ6-B_6Y.js} +0 -0
- /package/dist/web/assets/{log-B3fFlSMd.js → log-Bb_vqvu7.js} +0 -0
- /package/dist/web/assets/{logo-ucAyw6zf.js → logo-BzfYv3A_.js} +0 -0
- /package/dist/web/assets/{luau-C4l6TSTB.js → luau-BnAeNR77.js} +0 -0
- /package/dist/web/assets/{make-CDtGIVc7.js → make-B6IFuxpC.js} +0 -0
- /package/dist/web/assets/{markdown-CH1zKu2p.js → markdown-Z0xi77Fn.js} +0 -0
- /package/dist/web/assets/{material-theme-CEuGVTmh.js → material-theme-1scy1SYn.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-CUZ3MoIr.js → material-theme-darker-G-JykXQP.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-DxAqJSid.js → material-theme-lighter-BtKkCMVq.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-BSvvHJp6.js → material-theme-ocean-irrDC89L.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-QVOl50_m.js → material-theme-palenight-Eq5_K4LM.js} +0 -0
- /package/dist/web/assets/{matlab-CZLQLwUp.js → matlab-BE3oCXZC.js} +0 -0
- /package/dist/web/assets/{mdx-DO4NJsOo.js → mdx-DYiuFTGw.js} +0 -0
- /package/dist/web/assets/{mermaid-CIwzg1uO.js → mermaid-DVlaEvtw.js} +0 -0
- /package/dist/web/assets/{min-dark-BdIgslXy.js → min-dark-DSkeTpQa.js} +0 -0
- /package/dist/web/assets/{min-light-DyU-T1r2.js → min-light-CFv2Q0uF.js} +0 -0
- /package/dist/web/assets/{mipsasm-DRad-Klm.js → mipsasm-CiAFuZQ2.js} +0 -0
- /package/dist/web/assets/{mojo-DXp5LDOc.js → mojo-ARshcaSQ.js} +0 -0
- /package/dist/web/assets/{monokai-BiKX3qby.js → monokai-CPTV-SOg.js} +0 -0
- /package/dist/web/assets/{moonbit-BOUoLF5r.js → moonbit-D57B0dZr.js} +0 -0
- /package/dist/web/assets/{move-Dlk64FWK.js → move-qgy3G_o9.js} +0 -0
- /package/dist/web/assets/{narrat-B-qd2Lh0.js → narrat-CZ3rC-oc.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-iAMYas0F.js → nextflow-groovy-BxxIOcI4.js} +0 -0
- /package/dist/web/assets/{night-owl-3YNqjftR.js → night-owl-B1ryGCda.js} +0 -0
- /package/dist/web/assets/{night-owl-light-GIncHb5w.js → night-owl-light-BZvNnvMF.js} +0 -0
- /package/dist/web/assets/{nix-xjlEb3uw.js → nix-BVBQi8yv.js} +0 -0
- /package/dist/web/assets/{nord-C8tvWx7P.js → nord-3NXw613h.js} +0 -0
- /package/dist/web/assets/{nushell-BqBb4pU6.js → nushell-BMOLRalb.js} +0 -0
- /package/dist/web/assets/{objective-c-Bk6s0Cn5.js → objective-c-AxruEUgh.js} +0 -0
- /package/dist/web/assets/{objective-cpp-DGTVWQ3V.js → objective-cpp-cFT0qRsD.js} +0 -0
- /package/dist/web/assets/{ocaml-D6wPQ4kw.js → ocaml-_8JH6O8J.js} +0 -0
- /package/dist/web/assets/{odin-C9mw2xRN.js → odin-nwYvR0O6.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-SMBlneFb.js → one-dark-pro-C1LaYJaH.js} +0 -0
- /package/dist/web/assets/{one-light-C9JMU1Cx.js → one-light-B7rMc__c.js} +0 -0
- /package/dist/web/assets/{openscad-C0I9CtuA.js → openscad-Cwes8bKO.js} +0 -0
- /package/dist/web/assets/{pascal-D0z4DJnY.js → pascal-DMt-6tdZ.js} +0 -0
- /package/dist/web/assets/{pkl-CITYNGVz.js → pkl-QBTyYQmB.js} +0 -0
- /package/dist/web/assets/{plastic-Bf0T6rmg.js → plastic-BTSUp8Fk.js} +0 -0
- /package/dist/web/assets/{plsql-Chr907pu.js → plsql-DQv3IFXP.js} +0 -0
- /package/dist/web/assets/{po-07U75CYV.js → po-CNwZx4tW.js} +0 -0
- /package/dist/web/assets/{poimandres-B0T4qwXY.js → poimandres-8Os7Qequ.js} +0 -0
- /package/dist/web/assets/{polar-BvNJMMV5.js → polar-b4yK8oD8.js} +0 -0
- /package/dist/web/assets/{portal-container-context-Bqn516X4.js → portal-container-context-BarKmT4S.js} +0 -0
- /package/dist/web/assets/{postcss-BSdf-zzo.js → postcss-sFctwpxx.js} +0 -0
- /package/dist/web/assets/{powerquery-B2Ad_HK8.js → powerquery-Cg_WrtuN.js} +0 -0
- /package/dist/web/assets/{powershell-DO5WY2v2.js → powershell-C7Ifz95h.js} +0 -0
- /package/dist/web/assets/{prisma-BfaRPYzs.js → prisma-Z52HUJzQ.js} +0 -0
- /package/dist/web/assets/{prolog-Cz0Nue9e.js → prolog-DLqW-zR1.js} +0 -0
- /package/dist/web/assets/{proto-FVleUZJO.js → proto-BOIzxCCJ.js} +0 -0
- /package/dist/web/assets/{puppet-BEX5o7hE.js → puppet-De7TjZIf.js} +0 -0
- /package/dist/web/assets/{purescript-BZX6Kw4j.js → purescript-R76ou1WT.js} +0 -0
- /package/dist/web/assets/{python-CO89UIxE.js → python-Dprm0tNP.js} +0 -0
- /package/dist/web/assets/{qmldir-DH526DWB.js → qmldir-Clp_jpNw.js} +0 -0
- /package/dist/web/assets/{qss-wp8im4Iz.js → qss-eQPYYzSo.js} +0 -0
- /package/dist/web/assets/{r-F9n--bvq.js → r-CCcRHIf5.js} +0 -0
- /package/dist/web/assets/{racket-BQvbOE5D.js → racket-CzE472yp.js} +0 -0
- /package/dist/web/assets/{raku-B0iWSynj.js → raku-DQwXrTSi.js} +0 -0
- /package/dist/web/assets/{react-Bcm1Oab0.js → react-Bghu0NUO.js} +0 -0
- /package/dist/web/assets/{red-Cm00r9eI.js → red-KCS6wyop.js} +0 -0
- /package/dist/web/assets/{reg-CBuhna22.js → reg-CcrAddUh.js} +0 -0
- /package/dist/web/assets/{regexp-C9j1_6oU.js → regexp-DDbud-Ri.js} +0 -0
- /package/dist/web/assets/{rel-BYzlBhbq.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-CQQP0Ro9.js → riscv-Dm2eNv0R.js} +0 -0
- /package/dist/web/assets/{ron-j1ON9YzM.js → ron-CzFt0ygH.js} +0 -0
- /package/dist/web/assets/{rose-pine-Cbri3jon.js → rose-pine-Ck6lCrCP.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-BMuvKrGo.js → rose-pine-dawn-vtALRJNj.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-4biZzaYD.js → rose-pine-moon-DPto8qXw.js} +0 -0
- /package/dist/web/assets/{rosmsg-CXx22rtz.js → rosmsg-NtS6429H.js} +0 -0
- /package/dist/web/assets/{rust-D28cFIhL.js → rust-BjIXvF9h.js} +0 -0
- /package/dist/web/assets/{sass-DtNw4V28.js → sass-CQ23wf5E.js} +0 -0
- /package/dist/web/assets/{scala-hv69_YQC.js → scala-LfKLM143.js} +0 -0
- /package/dist/web/assets/{scheme-Dtp9B_ng.js → scheme-D3SLBXlF.js} +0 -0
- /package/dist/web/assets/{sdbl-DEwEngAE.js → sdbl-ODRd2rGN.js} +0 -0
- /package/dist/web/assets/{shellscript-CCOF9tox.js → shellscript-3KB1G_oA.js} +0 -0
- /package/dist/web/assets/{slack-dark-DT0E0ABt.js → slack-dark-DTtyWmIy.js} +0 -0
- /package/dist/web/assets/{slack-ochin-DHHiQnxo.js → slack-ochin-Bu0PApk3.js} +0 -0
- /package/dist/web/assets/{smalltalk-BF_I35xJ.js → smalltalk-haMT-Sbe.js} +0 -0
- /package/dist/web/assets/{snazzy-light-Cv7tIZo9.js → snazzy-light-DXJzefE9.js} +0 -0
- /package/dist/web/assets/{solarized-dark-wZ5YPCys.js → solarized-dark-B6LyYa18.js} +0 -0
- /package/dist/web/assets/{solarized-light-DGDOr1AS.js → solarized-light-QLADebkv.js} +0 -0
- /package/dist/web/assets/{solidity-BJknuPqJ.js → solidity-mzfq1aDc.js} +0 -0
- /package/dist/web/assets/{splunk-B1ClO_KU.js → splunk-CyH4RWBp.js} +0 -0
- /package/dist/web/assets/{sql-CXZ66NtF.js → sql-CWVlT5D3.js} +0 -0
- /package/dist/web/assets/{ssh-config-kgM67Sf6.js → ssh-config-DNvQJ1Qx.js} +0 -0
- /package/dist/web/assets/{stylus-RcVaInR-.js → stylus-ByQQdtmf.js} +0 -0
- /package/dist/web/assets/{swift-Cm0fh2lX.js → swift-D1cpY4ow.js} +0 -0
- /package/dist/web/assets/{synthwave-84-CwLiazxr.js → synthwave-84-BDF_-QiW.js} +0 -0
- /package/dist/web/assets/{system-verilog-CzYaDVLH.js → system-verilog-BYrkMydC.js} +0 -0
- /package/dist/web/assets/{systemd-DbSagfLw.js → systemd-CQm3zyK0.js} +0 -0
- /package/dist/web/assets/{talonscript-BCFnWejL.js → talonscript-DMW5CzE1.js} +0 -0
- /package/dist/web/assets/{tasl-BUdqtEe1.js → tasl-BhFzMCr2.js} +0 -0
- /package/dist/web/assets/{tcl-CR_lTV9N.js → tcl-D7VEAF-9.js} +0 -0
- /package/dist/web/assets/{terraform-Bqsha-xe.js → terraform-DdT5A0Vy.js} +0 -0
- /package/dist/web/assets/{tokyo-night-Cnuo6JB6.js → tokyo-night-WGLMM6Q9.js} +0 -0
- /package/dist/web/assets/{toml-CLFdhT22.js → toml-CZ7ipXHZ.js} +0 -0
- /package/dist/web/assets/{tsv-Dw3tLrZN.js → tsv-B1zVvoTr.js} +0 -0
- /package/dist/web/assets/{tsx-B8k1sFqw.js → tsx-D4HwRUBq.js} +0 -0
- /package/dist/web/assets/{turtle-BMKMfTrj.js → turtle-B4r8KEJH.js} +0 -0
- /package/dist/web/assets/{typescript-D38LfGSl.js → typescript-BnHhxMtp.js} +0 -0
- /package/dist/web/assets/{typespec-EbgGJHV_.js → typespec-DP2q46GT.js} +0 -0
- /package/dist/web/assets/{typst-CQXV2SzX.js → typst-DFsD_yaD.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-Dypg-2ZO.js → use-is-mobile-BQ9Bv5Ga.js} +0 -0
- /package/dist/web/assets/{use-visual-viewport-Bj3QHRkF.js → use-visual-viewport-CbwnktSG.js} +0 -0
- /package/dist/web/assets/{utils-CwNUra6_.js → utils-Bmf_8h7Y.js} +0 -0
- /package/dist/web/assets/{v-Ci1jObJJ.js → v-Bji8hSVT.js} +0 -0
- /package/dist/web/assets/{vala-C_NdfqrY.js → vala-D3TIgGmU.js} +0 -0
- /package/dist/web/assets/{vb-K_r_h_s8.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-DQPYLsZI.js → verilog-Dy7cF35d.js} +0 -0
- /package/dist/web/assets/{vesper-BrmzEV8s.js → vesper-BzjwUv9J.js} +0 -0
- /package/dist/web/assets/{vhdl-CjxQGaH2.js → vhdl-DuFnFNmW.js} +0 -0
- /package/dist/web/assets/{viml-CTKJNQH1.js → viml-yAPgKlbz.js} +0 -0
- /package/dist/web/assets/{vitesse-black-i-H_3p1i.js → vitesse-black-oSSQdyIZ.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-DZC_Yy3_.js → vitesse-dark-BZxwPihB.js} +0 -0
- /package/dist/web/assets/{vitesse-light-rf4kpmk8.js → vitesse-light-uIigycvt.js} +0 -0
- /package/dist/web/assets/{vyper-BLnOw4Nf.js → vyper-CX3NAxm5.js} +0 -0
- /package/dist/web/assets/{wasm-DbLMmiW0.js → wasm-6mEOOvVa.js} +0 -0
- /package/dist/web/assets/{wasm-CWeHvGNG.js → wasm-D9td37qO.js} +0 -0
- /package/dist/web/assets/{wenyan-CLwdRuzd.js → wenyan-lwNIHgk6.js} +0 -0
- /package/dist/web/assets/{wgsl-CBTDMVJR.js → wgsl-DQAzCfog.js} +0 -0
- /package/dist/web/assets/{wikitext-CQHrF84e.js → wikitext-DTXmt5NE.js} +0 -0
- /package/dist/web/assets/{wit-8xdbdipU.js → wit-Bdw_7WDH.js} +0 -0
- /package/dist/web/assets/{wolfram-tFwx32a_.js → wolfram-DqyHDZ07.js} +0 -0
- /package/dist/web/assets/{yaml-BP8N91fU.js → yaml-CPXhdByd.js} +0 -0
- /package/dist/web/assets/{zenscript-B10Pj7JT.js → zenscript-6s_i5zek.js} +0 -0
- /package/dist/web/assets/{zig-BZKcTtrK.js → zig-B2htezJ_.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,120 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.21.0] - 2026-09-17
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Env files are highlighted, so a commented-out setting looks like one.** `.env`, `.env.local`, `.env.test.example` and every other variant opened as plain text — one colour for the whole file — which meant a line switched off with a `#` was indistinguishable from a live one. In a file whose entire purpose is "which of these are on", that was the only distinction the editor had to make and it made none. Comments are now dimmed, keys, values, `export` and `${INTERPOLATIONS}` each get their own colour, and `Ctrl+/` comments a line out.
|
|
9
|
+
- Monaco ships 82 languages and none of them is `.env` — VS Code has none either, it comes from an extension — so this is a grammar PPM registers itself, in the editor, the diff viewer and the conflict resolver alike. It takes its colours from whichever theme is applied rather than a palette of its own, so it matches all six built-in themes and any custom one.
|
|
10
|
+
- The awkward lines were checked against real Monaco rather than reasoned about, and four of them were wrong at first: `#KEY=value` with no space, `export KEY=value`, a `#` inside a quoted value (not a comment), and `${VAR}` inside single quotes (literal, so not an interpolation). A fifth was worse — every line after the first assignment was being read as a value, including the commented ones.
|
|
11
|
+
|
|
12
|
+
- **An attached image can be opened before you send it.** The composer showed a 20px thumbnail and the filename, and clicking it did nothing — so the one attachment you would most want to check, a screenshot that was pasted and then silently downscaled, was the only thing in the composer that could not be looked at. The thumbnail is now a button that opens the same viewer the transcript uses: zoom, pan, rotate, flip, copy, download, and the arrow keys to walk a batch of pasted images without closing and reopening. It is reachable by keyboard, and on a touch screen the tap area is the full 44px while the thumbnail itself stays the size it was, so nothing in the composer moves.
|
|
13
|
+
|
|
14
|
+
- **Language servers in the editor** — real completions, hover types, go to definition, find references, rename, quick fixes, formatting, document symbols and inlay hints, from the same language server binaries VS Code drives. PPM's server hosts the language server processes and the browser talks a thin bridge to them, which is the seam VS Code puts between its renderer and its extension host. Ships support for TypeScript/JavaScript (including the `.tsx` and `.jsx` variants), Python, Go, Rust, C/C++, JSON, HTML, CSS/SCSS/LESS, YAML, Bash, PHP, Ruby, Lua, Vue and Svelte.
|
|
15
|
+
- Nothing is installed for you. A missing server is reported in the editor toolbar with the one command that installs it, because an editor that fetches and runs a binary because you opened a file is doing something you did not ask for. A project that ships its own server in `node_modules/.bin` is preferred over a global one, the way VS Code's "Use Workspace Version" works.
|
|
16
|
+
- One server process is shared by every tab on the same project root, and a monorepo package with its own `tsconfig.json` gets its own — that is a different root and a different set of types. A released server stays up for five minutes, because closing and reopening a tab is the commonest thing anyone does and a cold rust-analyzer start is expensive.
|
|
17
|
+
- Monaco's built-in TypeScript validation stays off. It sees one file with no `tsconfig.json` and no `node_modules`, so it reports "Cannot find module" for every real import; the diagnostics now come from a server that can actually see the project.
|
|
18
|
+
- **A Problems panel**, in the dock under the editor and opened from the error and warning counts at the left of the status bar — where VS Code puts both. Every diagnostic across the files you have open, grouped by file and ordered by position, with the rule that produced it (`ts(2322)`) and a click to jump to the line. On a phone, where there is no status bar, it opens from the row that already appears above the editor when something is wrong. It lists the files that are open, because that is what a language server has told us about — a file never opened has never been checked, and the empty state says so rather than implying the project is clean.
|
|
19
|
+
- **Semantic highlighting** — a name is coloured by what it *is* rather than by what it looks like, so a class, a type parameter, a parameter and a read-only local are told apart where Monaco's regular expressions see four identifiers. The server's own legend is read from its initialize result and the provider registered against it, because a token is an index into that table: decoding with the wrong one does not fail, it colours the file confidently and wrongly.
|
|
20
|
+
|
|
21
|
+
- **A GitLens-style hover on the inline blame annotation** — hovering the dimmed "Ada, 3 days ago • fix the parser" opens the whole commit: an initials avatar, both readings of the date ("9 months ago (December 2nd, 2025 4:17 PM)"), the full commit message rather than just its subject, and the diff of *that line* at that commit, coloured. Plus buttons to copy the hash and to open the file's history, its blame or the graph. On a phone, where there is no hover, a tap on the annotation opens the same thing.
|
|
22
|
+
- The line's diff comes from one `git show --unified=0` per commit and line, fetched as the cursor moves rather than when the hover opens, because Monaco reads a hover's content synchronously — fetching lazily would put the answer behind a spinner, which is a mistake this editor has already made once.
|
|
23
|
+
- Monaco ships no `diff` language, so a fenced diff block rendered as plain text: registering one is what makes removals red and additions green.
|
|
24
|
+
- A commit message is not trusted input. Monaco strips `command:` links from untrusted markdown, so a hover needs trust for its own buttons to work — and blanket trust would let anyone who can land a commit put a working button in a hover. The trust is narrowed to this hover's own four commands, and the message is escaped besides.
|
|
25
|
+
|
|
26
|
+
- **The commit graph, rebuilt to look like one.** Every commit's node is now its author's avatar ringed in that lane's colour, so a run of commits reads as *who* rather than as a column of identical dots — initials drawn as SVG, never a fetched image, because an avatar service would mean handing every committer's email address to a third party. Branches and tags moved into a **Branch / Tag** column of their own, which is what gives every message the same left edge instead of one that jumps by however long the branch name was. Rows are taller and banded and carry a tick of their lane's colour where the eye starts reading, and the selected row is unmistakable rather than a shade apart from the row above it.
|
|
27
|
+
- On a phone the six columns collapse to one: the graph, the subject, and the author, date and hash on a second line under it, in a 44px row. Six columns of fragments on a 390px screen was not a list of commits — and the alternative already in place, scrolling the whole table sideways, is right for a tablet and wrong for a phone.
|
|
28
|
+
- **A Changes column**, added lines in green and removed in red, the way GitLens shows them. It is a second `git log --shortstat` after the commits have already been drawn: asking the first log for it makes git diff every commit in the window (~100ms for 300 commits here, far more on a large repository) and that wait would land before anything appeared at all. A merge commit has no diffstat, so its cell is empty rather than claiming it changed nothing.
|
|
29
|
+
- **Scroll markers** down the right edge — where the checked-out commit, the selected row and every search match are in the whole loaded history, so a match twenty screens down is visible instead of only reachable. Searching also stopped washing the list yellow: a 15% tint over half the rows on screen buried the thing it was annotating, so a match is now a faint tint plus a bar, and the row you clicked looks selected even when it is also a match.
|
|
30
|
+
- **The commit details panel, rebuilt.** It was a stack of labelled lines under a heading, then the message in a bordered monospace box. A commit message is hard-wrapped by whoever wrote it, so on a wide panel that box filled half the width and left the rest of the row empty. Now it reads the commit twice over: a header bar answering who and how long ago, with the hash and each parent as chips that copy the *whole* hash when clicked (and say that they did) — then, in full, the forty-character hash, every parent, both names with their emails and **both dates with their timezone**. Author date and commit date are always shown separately once they disagree, which is exactly what a rebase or an amend does to them. Every one of those values copies on a click too. A forty-character hash is unreadable as one run of hex, so the eight characters you would actually quote are bright and the remaining thirty-two are dimmed behind them; the dates get a column of their own, so the author's and the committer's line up under each other instead of trailing whatever length the two names happen to be. The subject is set apart from the body, and the body is then read a paragraph at a time: one that was hard-wrapped at somebody's 72 columns is reflowed to the pane in the UI font, while a list, a table, a fence or anything indented keeps every break its author typed and stays in mono. Doing either to the whole message is what fails — verbatim leaves the ragged half-filled column this entry started with, and reflowing everything runs the bullet points together into one line. And on a panel with room, the file list moved into the space beside the message instead of below the fold. Each file shows its name before the directory it sits in, so a narrow column truncates the path and not the name. The two panes carry **a scrollbar each**: a message and a file list are two lists of unrelated length, and scrolling the pair as one meant reaching the twentieth file by pushing the message off the screen. Below the breakpoint they go back to stacking and the panel scrolls as a whole — two scrollers inside one short panel is a trap for a thumb.
|
|
31
|
+
|
|
32
|
+
- **A workspace folder whose *children* are the git repositories now works.** Point PPM at a folder of checkouts — a folder of services, a set of unrelated clones — and Source Control lists the repositories it found and asks which one to work in, instead of reporting "not a git repository" and leaving every git feature dead. The choice sticks per device and a quiet switcher in the panel header changes it; a single repository is chosen without asking, and a project folder that *is* a repository never sees any of this. Everything git-shaped follows the choice: status, staging by file or by hunk or by line, commit, push, pull, fetch, worktrees, the log, the diff viewer, inline blame and its hover, and the Git Graph extension's own panels — graph, blame, file history, compare, interactive rebase and reflog.
|
|
33
|
+
- Discovery walks two levels down, skips `node_modules` and the other well-known caches, and does not descend into a repository once it has found one. A `.git` *file* counts as well as a directory, so a worktree or a submodule is listed rather than missed.
|
|
34
|
+
- The scope is one query parameter resolved in a middleware, so every URL an ordinary single-repository project builds is byte-identical to what it was — the common case cannot regress on this path. It is validated against the project root: a path outside it is refused, never quietly replaced by the project folder, because that would answer with *a* history rather than with an error.
|
|
35
|
+
- Paths cross the boundary in both directions. Git run inside the repository calls the file `src/a.ts`, while the tab that opens it calls the same file `frontend/src/a.ts` — so the file tree's decorations are moved into the project's terms while the panel's own list stays exactly as git reported it, since that list is what stage, unstage, discard and the hunk picker send straight back.
|
|
36
|
+
- The Git Graph panels are opened on the repository, which means the extension can no longer find its project by matching that path exactly: it now resolves the innermost registered project *containing* the panel's root and rebases the file path before opening a tab. Without both halves, a diff opened from the graph named a project that does not exist and pointed at a file one directory too high — a spinner over an empty pane, with nothing to say why.
|
|
37
|
+
|
|
38
|
+
- **Real file icons, from the `vscode-icons` theme.** Every surface that lists a file — the explorer tree, the tab strip, Source Control, search results, the Problems panel, the command palette, the file picker and the OS file browser — now draws the same glyph VS Code draws for that file, resolved by whole filename first (`package.json`, `Dockerfile`, `bunfig.toml`), then double extension (`.spec.ts`, `.d.ts`), then extension. What it replaces looked deliberate but told you nothing: one lucide `FileCode` glyph tinted a different colour per language, so twenty languages were the same shape in twenty shades. A file icon's whole job is to be recognised before the name is read.
|
|
39
|
+
- The tab strip and the dock, mobile tab switcher and mobile nav all label a file tab with *that file's* icon rather than a per-tab-type one. A strip of eight identical `FileCode` glyphs does not say which tab is which.
|
|
40
|
+
- The artwork is vendored at build time (`bun scripts/gen-file-icons.ts`) rather than resolved at run time, which would mean shipping 1.3 MB of icon bodies and the extension's four lookup tables to draw a tree showing perhaps forty distinct glyphs. 224 glyphs come to 76 KiB brotli in a stylesheet of their own, because these are full-colour drawings with no `currentColor` to inherit and nothing to gain from putting the paths in the DOM — a tree of 500 rows would otherwise carry a few thousand extra nodes for React to reconcile on every expand. It is also how VS Code draws its own icon themes.
|
|
41
|
+
- The theme draws some glyphs twice, and the mapping tables only ever answer with the *light-theme* one. Those are darker: the TOML glyph has no fill at all, so it was black on black on every dark PPM theme. Both drawings ship and the applied theme picks — which costs almost nothing compressed, since the two differ by a colour.
|
|
42
|
+
|
|
43
|
+
- **Fluent product icons for the app's own chrome.** The rail, toolbars, buttons, menus, status bar and mobile nav now draw Fluent System Icons at 20px Regular — the set `miguelsolorio.fluent-icons` puts over VS Code's product icons — instead of lucide. 207 of the 222 names the app uses have a Fluent equivalent; the other 15 stay on lucide and that is deliberate, because a *wrong* glyph is worse than an inconsistent one: there is no Fluent `git-commit`, no brand mark, and nothing that reads as "match case" or "use regular expression" for the search widget's toggles.
|
|
44
|
+
- The two sets barely share a vocabulary, which is why this is a table and not a rename: lucide's `X` is Fluent's `dismiss`, `Check` is `checkmark`, `Trash2` is `delete`, `Plus` is `add`, `RefreshCw` is `arrow-sync`. Only 72 of the 222 names kebab-case straight across.
|
|
45
|
+
- Icons are imported from `@/lib/icons` now, and a test fails if any file goes back to `lucide-react` — one file that does renders a stroked outline beside a filled one at the same size, which reads as "this button looks slightly off" rather than as an error.
|
|
46
|
+
- The bundle got *smaller*: 953.7 kB → 933.7 kB (gzip 276.5 → 270.4), because 207 per-icon React components collapsed into 173 shared path strings behind one component. Glyphs stay in their native 20px box rather than being re-boxed to lucide's 24, which is what keeps an icon set from looking soft next to its own labels.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
- **PPM ships its own typefaces: Geist for text, Monaspace for code.** Every stack in the app named fonts and then got none of them. `-apple-system`, `BlinkMacSystemFont` and `Segoe UI` all miss on Linux — the platform PPM is most often self-hosted on — and the generic fallbacks resolve through fontconfig to Liberation Sans, or for a bare `sans-serif` to Liberation *Serif*. So the interface was set in an Arial clone and the editor in whatever `fc-match monospace` happened to answer. `Geist` had been named in the stack since the theme engine landed and was never bundled.
|
|
50
|
+
- **The editor, the diff panes and the conflict resolver are Monaspace Argon at 14px**, with `calt`, `liga` and `ss01`–`ss09` on: the ligatures turn `=>` into an arrow and `!==` into a not-identical sign, and the stylistic sets are where Monaspace's texture healing lives — the part that narrows an `i` beside an `m` so a run like `www.mmm.iii` stops looking like a picket fence.
|
|
51
|
+
- **Inline suggestions are Monaspace Krypton**, a different face at the same metrics. That last part is what makes it safe: Monaco places every character at column times character width, so a ghost-text font with a different advance would slide out of the grid the editor measured with. Monaco has no `inlineSuggest.fontFamily` option, and its own ghost-text rule is loaded *after* the app's stylesheet, so the override has to outweigh it rather than merely match it.
|
|
52
|
+
- **The terminal asks for MesloLGM Nerd Font first** — a shell prompt is full of powerline separators and devicons that only a patched font has — and where that is not installed it now falls back to a bundled set of the icons alone (see *The terminal prompt was a row of boxes on a phone*, below). A terminal that opens during the first paint used to keep whatever fallback was resolved then for the whole session, because xterm bakes the cell size and its glyph atlas from `ctx.font` at `open()`; it now re-measures once the face lands.
|
|
53
|
+
- **The extension panels ask for the same typefaces by name.** A panel is a sandboxed iframe with an opaque origin, so it cannot use the faces the app bundles: a `@font-face` pointing at `/assets/` is a cross-origin fetch the font would need CORS headers to answer, and the file name carries the build's content hash the extension has no way to know. Naming them instead means the git graph and the app match exactly on a host where the fonts are installed, and fall back to the desktop's own UI font where they are not — which is still an improvement on the Arial clone it was getting. One token block, shared by the graph and every panel opened from it.
|
|
54
|
+
- **First paint costs 37 KB for this**: Geist's Latin and Vietnamese ranges are separate files and only the ones a page actually uses are fetched, the code faces wait until an editor or terminal is on screen, and none of them enter the service worker's precache — which stays at 9 entries. The `woff2` files are not re-compressed, because they already are.
|
|
55
|
+
- **The language server is off until you ask for it, and a phone never starts one.** It is a real process on the host — one `typescript-language-server` on one project was **854 MB** resident — so it now waits to be asked instead of starting because a file was opened. Turn it on from the chip in the editor's breadcrumb bar, from Settings, or from the command palette; turn it off again from the panel that chip opens. The setting is per device, which is the point: a desktop switching it on must not start a server for your phone.
|
|
56
|
+
- The browser half is behind a dynamic import, so a session that never turns it on never downloads it either — 17.8 KB of client, providers and conversions (5.3 KB compressed) left the chunk that opening a file pulls in. A single static `import` from the editor would merge it back with nothing about the UI looking different, so a test asserts the boundary rather than a comment asking for it.
|
|
57
|
+
- **With the setting off, Monaco's own TypeScript service answers** — completion, hover, signature help — instead of nothing at all. It was unregistered unconditionally, which is right beside a real server (two answers, and the slower one holds the hover widget on "Loading…") and wrong with no server at all: a fresh desktop install and *every* phone had no TypeScript IntelliSense and no setting that could restore it. Its diagnostics stay off, because one file with no `tsconfig.json` and no `node_modules` reports "Cannot find module" for every real import.
|
|
58
|
+
- **A TypeScript server ships with PPM**, so the setting works on a fresh install with nothing else done. A copy in the project's own `node_modules/.bin` still wins, and so does one on `PATH` — the bundled one is the floor, never a preference, or a repository pinned to TypeScript 4 would be analysed by the wrong compiler.
|
|
59
|
+
- **Code wraps by default on a phone.** The wrap toggle lived in a toolbar that is hidden below the `md` breakpoint, so a phone could not reach it and the pref defaulted to off — reading any real file meant scrolling sideways line by line. Wrap is now on by default on a phone-sized screen and has a toggle you can reach: in the editor's mobile toolbar, in the diff viewer's toolbar, in Settings and in the command palette. It is a per-device pref, so turning wrap off on a 27-inch monitor does not turn it off on a 6-inch screen.
|
|
60
|
+
- **Inline blame is off on a phone.** The annotation on the cursor's line costs a `git blame` for every file opened and a `git show` for every hover, on the device least able to pay for either. It stays available on a tablet and up.
|
|
61
|
+
- **A first load of 1 MB instead of 33, and an editor that works offline.** Four things were each undoing the others:
|
|
62
|
+
- The service worker was precaching **488 files / 33.3 MB** on first visit — every language grammar, every theme, and a TypeScript worker most sessions never instantiate. It now precaches the shell it actually needs to boot: **9 files / 1.08 MB**, with everything else cached as it is used.
|
|
63
|
+
- Nothing was compressed. Every `.js`, `.css`, `.html`, `.json`, `.svg` and source map is now built with brotli and gzip siblings and served with the right `Content-Encoding` and `Vary`: **22.4 MB → 4.33 MB brotli, 5.40 MB gzip (81% smaller)**. Both, not just brotli, because browsers only offer `br` on a secure origin and PPM is routinely reached over plain HTTP on a LAN.
|
|
64
|
+
- Monaco was loaded from the jsdelivr CDN, so the editor did not work offline, did not work on an air-gapped machine, and told a third party which files you open. It is now staged into the bundle (13.3 MB of the 14.97 MB on disk — the 14 locale bundles are skipped) and served from PPM itself. The 6.7 MB TypeScript worker is 1.2 MB brotli on the wire and is fetched once, on first use, only by a session with no language server running.
|
|
65
|
+
- Measured after: a cold load of a TypeScript file fetches 23 files / 865 KB, with no failed requests and no fallback to running a worker on the main thread.
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
- **The Git Graph's commit details panel could not be closed on a touch screen.** Tapping a commit opens a panel over a third of the graph, and the only ways out were the Escape key — which a phone does not have — and tapping the same commit row again, which by then is behind the panel. The two hash chips at the right of its header are now a close button. Nothing is lost by dropping them: the metadata grid two lines below carries the commit and its parents in full and copies either on a click, and the chips were hidden on a phone anyway, where two of them took half the header and left the author's name as "t." with an ellipsis — so that corner of the header now has something in it at the width where closing matters most. Escape still works, and both go through the same dismissal, which also clears the row's highlight and its mark in the scroll bar.
|
|
69
|
+
- **The Source Control file tree told you almost nothing about which files had changed.** Names were cut at the *end*, and these names are distinguished by their suffix: `remote-desktop-capture.ts`, `remote-desktop-capture-input.ts` and `remote-desktop-encoder-args.ts` are identical for their first 23 characters, so seven rows in a row read `remote-desktop-…` and the panel could not tell you what it was listing. The names now ellipsize from the *start* — `…p-capture-input.ts`, `…esktop-capture.ts`, `…p-encoder-args.ts` — which is the part that differs, and the full path is still on the row's tooltip.
|
|
70
|
+
- **A chain of directories with one child each is one row**, the way VS Code's explorer folds them: `src` → `services` → `remote-desktop` cost three rows and 36px of the width the filenames needed to convey a single path, and is now `src/services/remote-desktop` on one line with the leading part dimmed so the specific directory stands out. Staging or discarding that row still acts on the deepest directory, not the outermost one.
|
|
71
|
+
- **The tree's connector lines are drawn per level instead of per row.** They had been an elbow positioned by hand inside each row — one offset for a file, another for a folder, against rows of two different heights — so the pieces never met and the result read as scattered dashes rather than as a tree. One continuous rail per level now runs the height of its children.
|
|
72
|
+
- Rows are 44px tall on a touch screen and compact where there is a mouse, and a filename is set at the body text size rather than the size used for labels and metadata.
|
|
73
|
+
|
|
74
|
+
- **The typing indicator on a streaming chat tab was a smudge, not an animation.** A tab whose reply is still arriving draws three bouncing dots inside its chat-bubble icon, Messenger style. That was written against the old icon set, whose speech bubble is hollow. The bubble PPM ships now draws **two message lines of its own** inside itself — and the dots are laid over the same 16px box in the same colour, so they landed on top of the upper line and the three of them fused into one lumpy bar. At the size a tab actually renders it read as a static blob: the dots were still bouncing, but there was nothing legible left to move.
|
|
75
|
+
- The streaming state now uses the empty bubble from the same icon family — the identical outline with nothing in it — so the dots have the inside of the bubble to themselves. The resting icon is unchanged, and the two are the same shape, so a tab does not appear to swap icons when a reply starts.
|
|
76
|
+
- Checked by freezing the animation at five points across its cycle and rendering both: the old glyph barely changes shape between them, the new one shows three dots plainly rising and falling. A test now asserts the glyph behind the dots contributes nothing but the bubble's outline and its hole, so an icon with its own contents cannot quietly end up back there.
|
|
77
|
+
|
|
78
|
+
- **Half the shell prompt was invisible on a light theme.** A terminal palette has sixteen colour slots and a background, and two of those slots are *defined* to sit at the extremes — so on a light theme `white` and `brightWhite` land right on top of the background (measured: **1.09:1** and **1.07:1**), and on a dark theme `black` does (**1.10:1**). That is not low contrast, it is nothing at all. oh-my-posh writes its second prompt line in plain ANSI white, which is correct on the dark terminal it was written for, so on a light PPM theme that whole line — the clock, the folder, the path — simply was not on the screen.
|
|
79
|
+
- Recolouring those slots would have been the wrong fix, because the same `white` is *also* the text on a coloured powerline segment, where white is exactly what it should be. The terminal now asks xterm to hold a minimum contrast ratio of 4.5 (WCAG AA, and VS Code's own default), which adjusts the foreground per cell against whatever is actually behind it: every coloured segment renders identically, and only the text that had the bare background behind it moves. Checked by rendering the real prompt in both themes side by side.
|
|
80
|
+
|
|
81
|
+
- **The Source Control panel's row menus, on a phone.** Long-pressing a changed file opened a desktop dropdown: a small popper anchored to a 20px row, with items sized for a mouse pointer. It is now the same bottom sheet every other long-press in PPM opens — anchored to the bottom of the screen where the thumb is, with a backdrop, 44px rows, and Discard Changes set apart in red below a divider. On a desktop the same menu is on right-click, which the panel did not have at all before.
|
|
82
|
+
- **A folder row could not be expanded on a phone.** Its menu was a plain dropdown whose trigger was the whole row, and a dropdown trigger opens on *tap* — so tapping a folder opened a menu over it instead of expanding it, and nothing else would. Tap now expands and long-press opens the menu, which is the gesture the rest of the app already used.
|
|
83
|
+
- Tapping a file still opens its diff, but the filename is a real button doing it rather than a hand-rolled "was that a tap or a press?" timer — so it is reachable by keyboard, and a press that the browser turned into a scroll can no longer be mistaken for a tap. Both menus are one definition now instead of a desktop copy and a mobile copy.
|
|
84
|
+
|
|
85
|
+
- **The terminal prompt was a row of boxes on a phone.** A themed prompt — oh-my-posh, powerlevel10k, starship — draws its segment separators, its git status and its language badges from Private Use Area codepoints that only a *patched* font has. PPM named three of those fonts and shipped none, so on any machine without one installed every icon in the prompt was a box or a question mark, while the `↑39 ↓15` sitting between them rendered perfectly — because those two arrows are real Unicode and everything around them was not. Desktops mostly got away with it, since a machine with a Nerd Font installed supplies the glyphs itself; a phone has nothing to fall back to.
|
|
86
|
+
- The icons are now bundled, and only the icons: no letters, no digits, so ordinary text falls straight through to the code face and only the icon codepoints stop at the new one. A fully patched font installed on the host still wins, because it draws the icons *and* the letters in one typeface at metrics fitted together.
|
|
87
|
+
- The whole set is 1.14 MB, which is why it ships as **fourteen** files split along the icon-set boundaries — Powerline, Codicons, Devicons, Font Awesome, Material Design and so on — each declaring the exact range of characters it covers. A browser fetches one only when it actually lays out a character inside it, so a powerline prompt costs **7 KiB**, a prompt with git and language segments about 210 KiB, and the 492 KiB of Material Design icons is downloaded by whoever draws one and by nobody else. Nothing enters the service worker's precache, and the boot shell in fact got 9 KiB *smaller*: the bundler had been quietly base64-ing the four smallest faces into the one file that is precached, which turned the rarest icon sets into an unconditional download for everybody.
|
|
88
|
+
- A face arriving late had to be made to draw. The fetch does not start until something renders one of those characters, which for a prompt is long after the page has settled — and measured in a real terminal, the tofu it drew first is *permanent*: the renderer bakes glyphs into a texture atlas, and nothing repaints it, so the prompt stays wrong for the rest of the session with the correct font sitting loaded in the page. The atlas is now discarded and the screen redrawn whenever a font finishes loading.
|
|
89
|
+
- The font is vendored by a script that pins the upstream version and checks the file against a digest before subsetting it, because a moved tag or a replaced release asset would shift every glyph in the terminal with nothing to point at.
|
|
90
|
+
|
|
91
|
+
- **Context menus that opened by themselves while you were scrolling on a phone.** Scroll the list of changed files, the tab switcher, or the project list, and a menu would appear over it — nothing you did asked for one, and the list was still moving under your finger. A press that opens a menu is a timer started when the finger lands and cancelled when it moves or lifts, which reads as complete and is not: once the browser decides the gesture belongs to a scroll it *cancels* the touch and stops reporting it, so the timer was never told and finished on its own. It is now cancelled on that event too, in all seven places that hold a press open — the file rows, the shared context menu, the file explorer's rows, the tab strip's drag, the drawer tab bar, the tab switcher and the project sheet. The press is also dropped if what you pressed disappears first, which the git panel does on every file save.
|
|
92
|
+
|
|
93
|
+
- **The occasional white screen.** Sometimes a page — a file you opened, a session you came back to — rendered nothing at all: no message, nothing to click, just the background. It was always the same thing underneath. PPM's frontend is split into content-hashed files, an upgrade replaces every one of them, and a tab that was open across the upgrade goes on asking for the names it was built with. Four separate faults turned that into a blank page instead of a hiccup.
|
|
94
|
+
- **The server answered a missing script with the app's own HTML.** Any path it could not find fell back to `index.html`, which is right for a page address and wrong for a file the running app is fetching: the browser refuses to run HTML as a module, so the load failed with a message about MIME types that named nothing recognisable. Missing files now come back as a plain 404. The test cannot be the file extension — PPM's addresses contain file paths, so `/project/x/editor/src/main.js` is a page and not a script — so it is the browser's own statement of what the request is for, with the two build-output directories as a backstop for the connections where that statement is not sent.
|
|
95
|
+
- **One failure took the whole app down with it.** A tab type that will not load throws while React is rendering it, and with nothing above it to catch that, React unmounts everything — which is exactly a blank page. There is now a boundary at the root, so the same failure reads "PPM has been updated" with a Reload button, and one attempt at recovering silently happens first: this app's caches are dropped and the page reloads itself once, which in practice fixes it before you notice. Once, not repeatedly — a page that reloads forever is worse than one that explains itself.
|
|
96
|
+
- **Some failures happen before any of PPM's code runs.** The app's startup depends on around forty of those hashed files, and if one is missing the browser never executes any of it — so no boundary, no handler and no message is possible, because nothing that could show one has loaded. That case is now caught by a few lines built into the page itself, which say what happened and offer the same Reload. It stands down the moment the app starts normally, so a slow phone never sees it.
|
|
97
|
+
- **The service worker made all of it permanent.** It had cached that HTML response under the script's own address, and since these files are treated as never-changing, it kept serving it: putting the file back on the server changed nothing, and the tab stayed broken until its storage was cleared by hand. It now refuses to store — or to keep serving — a page where a script belongs, drops superseded caches instead of accumulating them, and an updated PPM takes effect on the next load rather than waiting for every tab to close, which is what had let a tab run last week's code for a week.
|
|
98
|
+
- Separately, a mistyped or truncated address with a stray `%` in it crashed the app on load instead of simply not opening anything.
|
|
99
|
+
|
|
100
|
+
- **Chat search could not find a session by the name you gave it, and never looked inside the turns that only used tools.** Two unrelated faults behind one symptom: searching for a session's own title returned nothing, and searching for something a tool had done returned nothing either.
|
|
101
|
+
- Only the 50 most recent sessions were listed under their real name. PPM asked the SDK for a single page of sessions, and everything past it fell through to the recovery scan meant for transcripts the SDK cannot parse — which can only rebuild a title by scraping the first 512 bytes of the file. So 165 of 228 sessions in one workspace were listed under their opening prompt ("/recap") instead of the name they had been given, and a search for that name could not match them. A project-scoped listing with no explicit limit now pages the SDK until it is exhausted, leaving the scan the exception path it was written to be; the paginated session list is untouched.
|
|
102
|
+
- A turn that only used tools was dropped from the index entirely. Tool calls and their results are carried separately from a message's prose, and the indexer read the prose alone — so the turns that commit and open a pull request, the most tool-heavy there are, were the least searchable part of a session rather than the most. Two sessions measured here went from 33 and 17 indexed messages to 122 and 76. Tool names, their arguments, their output and nested agent events are all indexed now, capped per event because a single file read can be hundreds of KB. The model's thinking stays out: bulky, and it reads as noise in a result snippet.
|
|
103
|
+
- Neither fix would have reached a transcript already indexed. Staleness was the transcript's modification time and nothing else, so every session was stamped as fresh and a better indexer would never have been asked to re-read one. The index now records which indexer wrote each session and treats a change of indexer as stale, which re-reads all 256 already on this machine.
|
|
104
|
+
- Still missing, and not PPM's to fix: the Claude Agent SDK returns only part of a long transcript, so a session's earliest messages remain unsearchable — one here spans 02/09 11:16 to 03/09 11:03 in the file and is answered from 03/09 05:09 onwards.
|
|
105
|
+
- **A light theme no longer shows dark extension panels.** A webview is a sandboxed iframe with its own document, so it inherits none of the app's CSS variables and cannot see which theme is on — the only question it could ask was `prefers-color-scheme`, which is the *operating system's* setting. So the git graph, blame, file history, compare and rebase panels all rendered dark inside a light app on any machine whose desktop was dark. PPM now hands each panel the theme it has actually applied, both as a mode and as its own token values, so a panel matches the app rather than the desktop — including the imported VS Code themes and the mobile overrides, because the values are read from the live document rather than mapped a second time.
|
|
106
|
+
- The panels' own palette is still there for the case where nothing is injected, and its dark half moved off near-black onto a charcoal, so the toolbar, the list and the banded rows read as three surfaces instead of one slab. Rows also band harder in dark than in light: the same percentage is not equally visible in the two directions, and a 3.5% lift of near-white over a near-black row is not.
|
|
107
|
+
- A theme change is posted into the panel rather than rewritten into its HTML, because replacing the HTML reloads it — a graph would refetch every commit and lose its scroll position because you switched to light.
|
|
108
|
+
- **Commit messages in the graph are no longer rewritten by their own issue links.** The default rule links `#123`, and it was applied *after* the message had been escaped for HTML — so an apostrophe, which escapes to `'`, had its `39` turned into an issue link, and the row rendered a literal `'` with `#39` in link blue. Every message containing an apostrophe was affected, which was most of them. Patterns now match the raw message and escaping happens as the answer is emitted, so an entity can never be formed and then matched; a URL is also claimed before anything inside it can be linked separately and split it in half.
|
|
109
|
+
- **Inlay hints were switched on and never appeared.** tsserver returns hints per *kind*, each off unless asked for, so the editor requested them, the server answered "none", and a feature that looked enabled produced nothing — measured as 0 hints across a 2233-line file, now 462. Parameter names only, which is what makes a bare `true` or a positional index readable at a call site; the type hints VS Code also ships off stay off, because they restate what the line already says.
|
|
110
|
+
- **The editor was not using a font that exists.** All three Monaco surfaces asked for `Menlo, Monaco, Consolas` — none of which is present on Linux — so they fell through to whatever generic `monospace` resolves to. The terminal already carried a platform-complete stack; all four now share one, so they cannot drift apart again and render in different fonts on the same machine.
|
|
111
|
+
- **A hover in a TypeScript file sat on "Loading…" for seconds** after showing the right answer. Monaco's hover widget merges every registered provider and waits for the slowest; PPM had silenced the bundled TypeScript worker's diagnostics but left its other twelve providers registered, and that worker cannot answer anything before fetching the whole TypeScript compiler. So the language server's answer arrived in milliseconds and then waited behind a download. Monaco's TypeScript service is now unregistered **while a language server is running** — which is what VS Code's renderer does, having no TypeScript worker in it at all — so completions in `.ts` files stop being two merged lists, one of which only ever knew the current file. With no server running it is the only answer there is, so it stays registered, with its diagnostics off: one file with no `tsconfig.json` reports "Cannot find module" for every real import.
|
|
112
|
+
|
|
113
|
+
## [0.20.10] - 2026-09-17
|
|
114
|
+
|
|
115
|
+
### Fixed
|
|
116
|
+
- **"Set up named tunnel" no longer falls back to the button after a spinner** — on an install that had dismissed the first-run popup, the status refresh following an already-valid Cloudflare sign-in closed the flow before the zone step could open it.
|
|
117
|
+
- **A failed setup now offers "Sign in again"** — retrying reuses the existing certificate, so a certificate whose zone no longer exists could only ever repeat the same error.
|
|
118
|
+
|
|
5
119
|
## [0.20.9] - 2026-09-16
|
|
6
120
|
|
|
7
121
|
### Added
|
package/CLAUDE.md
CHANGED
|
@@ -92,12 +92,44 @@ Related: `configService.save()`/`set()` throw when `load()` has not run, because
|
|
|
92
92
|
|
|
93
93
|
- **An extension panel only gets a tab if a browser tab asked for it**: `use-extension-ws.ts` creates a tab for `webview:create` only when `locallyDispatchedViews` holds a matching entry, i.e. when *this* client dispatched the command. A panel the extension opens on its own initiative exists server-side with no tab to show it. To open one panel from another, call `window.openTab("extension", …, { viewType })` instead — `extension-webview.tsx` then sees a tab with no panel and dispatches the command itself, which *is* a local dispatch. The recovery dispatch forwards only the project path, so any other argument has to be stashed for the target panel to pick up (`packages/ext-git-graph/src/panel-nav.ts`). The command id and the viewType must also be identical: both are turned into a tab slug by stripping a trailing `.view`, and a mismatch silently yields no tab.
|
|
94
94
|
- **Extensions may only spawn `git`, `node`, `bun`, `npx`, `sqlite3`** (`ALLOWED_SPAWN_COMMANDS` in `extension-rpc-handlers.ts`) and the call *throws* for anything else. Reaching for `test`, `cat` or any other coreutil looks fine in review and fails only at runtime — where a surrounding `catch` can turn it into silently missing data rather than an error. `env` is merged over `process.env` (so `PATH` survives) except for `BLOCKED_ENV_KEYS`; `GIT_SEQUENCE_EDITOR` and `GIT_EDITOR` are not blocked, which is what makes a non-interactive `git rebase -i` possible.
|
|
95
|
+
- **A webview inherits nothing from the app, including which theme is on**: the iframe is `sandbox="allow-scripts"` with its own document, so none of the CSS vars `apply-theme.ts` writes to `<html>` reach it and there is no `.dark` class to read. The only question the panel can ask by itself is `prefers-color-scheme` — the *OS* setting — which is why every extension panel rendered dark inside a light app on a dark desktop. `webview-theme.ts` stamps `data-ppm-theme` on the panel's own `<html>` and appends the app's tokens as a `:root[data-ppm-theme]` block, and the panels' dark rules are written as `:root[data-ppm-theme="dark"]` plus `@media (prefers-color-scheme: dark) { :root:not([data-ppm-theme="light"]) }` — a bare `:root` inside that media query is the bug, because it cannot lose to an explicit light. Three things are load-bearing: the injected block is *appended last* and ties on specificity, so a panel rule more specific than one attribute silently wins over the app's colours; the seed goes into `srcDoc` (later changes are `postMessage`d, because rewriting `srcDoc` reloads the panel and a graph would refetch every commit); and `--surface-hover` is derived from `--text` rather than injected, because some app themes give `--panel` and `--panel-2` the same value and a hover mapped from either would be invisible in exactly those themes.
|
|
95
96
|
- **A webview panel has no `prompt`/`confirm`/`alert`**: `extension-webview.tsx` mounts the iframe with `sandbox="allow-scripts"` and nothing else, and a sandboxed `prompt()` returns `null` silently — no exception, no console warning. Any answer a panel needs has to be collected by markup it renders itself (`confirmHtml` in `reflog-view.ts`). The same string is a TypeScript template literal, so a backtick anywhere inside it — a `` `code span` `` in a comment is the usual one — ends the literal early and reports as a syntax error at some unrelated token far below.
|
|
97
|
+
- **A Monaco model in PPM is not named after its file**: the editor mounts `<Editor value=... />` with no `path`, so Monaco names models `inmemory://model/N`. A language server has never heard of that, and the `file:` URIs it answers with match no model — so an unrewritten request makes the server answer about a document it was never given, and an unrewritten response makes Monaco treat the open file as a different one (go-to-definition inside the current file tries to *open* it, and diagnostics attach to nothing and never appear). `src/server/ws/lsp.ts` rewrites both directions, including URIs used as object *keys* in a workspace edit's `changes`.
|
|
98
|
+
- **Standalone Monaco's F12 into another file hijacks the current editor**: its default editor service, once a model exists for the target, swaps that model into the editor you are in. The tab keeps its old title and its old dirty state while showing another file's contents. `lsp-navigation.ts` replaces the binding and opens a real tab instead. Peek and find-references are left on Monaco's bindings — they render in place and never navigate — but they need a model to exist for the target, which is what the shadow models in `lsp-shadow-models.ts` are for; there is no public way to give standalone Monaco a model *resolver*, so providers create the models before returning locations.
|
|
99
|
+
- **`Content-Length` in the LSP framing counts bytes, not characters**: one multi-byte character anywhere in a payload — a curly quote in a hover, a Vietnamese identifier, an emoji in a doc comment — makes a character-counting decoder cut the body short, fail to parse, then read the next message's header as body. The stream never recovers and it only happens for some files. Also bound the header search (`MAX_HEADER_BYTES`): a server writing a panic trace to stdout has no `\r\n\r\n` to find, so without a bound the decoder buffers forever and the session looks healthy while serving nothing.
|
|
100
|
+
- **`typescript-language-server` needs TypeScript 5.x**: the 7.x line is the native port and ships no `tsserver.js`, so the server exits at `initialize` with "provides no tsserver". It reads like a broken install rather than the wrong major version, so the registry's install hint pins `typescript@5`.
|
|
101
|
+
- **Standalone Monaco can never turn semantic highlighting on from a theme**: `StandaloneTheme` hardcodes `semanticHighlighting = false` and never reads it from the `defineTheme` data (`IStandaloneThemeData` has no such field), while the `semanticHighlighting.enabled` option defaults to `'configuredByTheme'` — so tokens are fetched, decoded, and change nothing. The only switch is the editor option set to `true` (`code-editor.tsx`). Colours then resolve through the *same* rule trie as TextMate scopes: `getTokenStyleMetadata` joins the type and its modifiers with dots (`variable.readonly.local`) and `ThemeTrieElement.match` falls back segment by segment, so a type with no rule lands on the theme's default foreground — i.e. plain text where the regex tokenizer had colour. `src/web/theme/semantic-token-rules.ts` is that table, and it must cover names outside the specification: `typescript-language-server` sends **`member`** for methods, one of the most common tokens in a TS file.
|
|
102
|
+
- **Monaco's bundled TypeScript service is off entirely, and `setDiagnosticsOptions` is not what does it**: that call silences the validator but leaves all **thirteen** providers in `modeConfigurationDefault` registered, so every `.ts` file had two completion lists and two hovers — the second from a worker that sees one file with no `tsconfig.json` and no `node_modules`. It also cost a *visible* stall: answering a hover at all means fetching `ts.worker.bundle.js` (**13 MB**, the whole TypeScript compiler), and Monaco's hover widget merges every provider and shows "Loading…" until the last one replies — so the real server's answer rendered in milliseconds and then sat behind a spinner. `setModeConfiguration` is the call that unregisters them (`monaco-builtin-typescript.ts`, asserted against Monaco's own default list so an upgrade adding a provider fails a test). Consequence, accepted: a buffer the LSP cannot serve — untitled, external, inline — falls back to word-based suggestions only.
|
|
103
|
+
- **A button in a Monaco hover is a `command:` link in *trusted* markdown, and trust is all-or-nothing unless you narrow it**: a hover can only contain markdown, so the blame hover's actions are `[label](command:id?args)` links reaching ids registered with `monaco.editor.registerCommand`. The renderer *strips* those links unless the `IMarkdownString` is trusted — and `isTrusted: true` allows **every** command on the page's global registry. That hover embeds a commit message, so anyone who can land a commit could write `[click](command:...)` in one and have it render as a working button. Both defences are needed and both are in `blame-hover.ts`: `isTrusted: { enabledCommands: [...] }` (an array is honoured by `toAllowCommandsOption`), and escaping the message so it cannot form a link at all. `supportHtml` stays **off** — the avatar is ``, which renders inline at its intrinsic size, so no HTML has to be allowed for it. Escape `<` and `>` too: with `supportHtml` off the renderer does not leave an unknown tag alone, it drops the tag and keeps the text, so a message mentioning a literal `<script>alert(1)</script>` displayed as `alert(1)` — the message silently rewritten in the one view meant to show it verbatim.
|
|
104
|
+
- **Hovering injected text does reach the decoration under it, and Monaco has no `diff` language**: an `after` injected-text annotation sits past the line's last column, and `ContentHoverComputer._getLineDecorations` relaxes its column check by one character *only* for `showIfCollapsed` decorations — which is what makes the blame hover work at all, and why that flag is load-bearing rather than cosmetic. `editor.action.showHover` opens the same hover from the cursor, which is the touch path (gated on `hover: none`, not on a width breakpoint; the mouse target's `injectedText` would identify the tap exactly but is not in Monaco's public typings, so the handler goes by column). Separately: Monaco's 91 basic languages include no `diff` — VS Code's comes from a bundled extension — so a fenced diff block runs the tokenizer and comes back entirely `mtk1`, the theme's default foreground. `monaco-diff-language.ts` registers one and `theme/diff-token-rules.ts` colours it; a Monarch rule whose token name has no theme rule is the same silent no-op as an unmapped semantic token, and a test pairs the two so neither can be added without the other.
|
|
105
|
+
- **The service worker's precache can silently undo any download saving, and both compressions are needed**: `injectManifest` defaults to precaching *everything* in the build output, so the first visit fetched 488 files / 33.3 MB — including the 12.7 MB TypeScript worker that `monaco-builtin-typescript.ts` had just made unnecessary to ever load. A saving measured in the network tab of a warm page is not a saving; measure `precache N entries (X KiB)` in the build output too. `globPatterns` now lists only the boot shell (9 entries / 1.08 MB) with everything else on a runtime `CacheFirst`. Separately, `scripts/precompress-web.ts` writes **both** `.br` and `.gz` siblings and `static-encoding.ts` picks one: brotli alone is not enough, because browsers advertise `br` only on a **secure origin** and PPM is routinely reached over plain HTTP on a LAN. And Monaco is staged locally by `scripts/copy-monaco.ts` with `loader.config({ paths: { vs: "/assets/monaco/vs" } })` — the default is jsdelivr, which means no editor offline and a third party told which files are opened. `vite build` empties `dist/web`, so `copy-monaco` and `precompress-web` must run *after* `build:web` (running `build:web` alone leaves an installed PPM with no Monaco at all).
|
|
106
|
+
- **A lazy chunk boundary is one static import away from not existing, and it is invisible**: `code-editor.tsx` reaches the language service only through `lazy(() => import("./editor-language-service"))`, which is what keeps the LSP client out of the editor's chunk and — the part that actually costs something — keeps the code that asks the host for a server unreachable until the setting is on. One `import { anything } from "@/hooks/use-lsp"` anywhere on that static path merges the chunk back in and nothing about the UI looks different, so `tests/unit/web/editor-lsp-lazy-boundary.test.ts` enumerates the offenders instead. Importing even a *constant* from the lazy module counts; `import type` does not. Related: `lspEnabled` and `mobileWordWrap` are written with `persistDevicePref` (localStorage only) rather than `persistUiPref`, because the server round-trip that makes prefs survive an origin change also means the last device to write wins everywhere — and a desktop must not start an 854 MB server process for a phone.
|
|
107
|
+
- **Escaping before matching lets a pattern rewrite the text it escaped**: the git graph escaped a commit message to HTML and *then* ran the issue-link rules over the result. The default rule is `#(\d+)`, an apostrophe escapes to `'`, so "Monaco's" rendered as a literal `'s` with `#39` styled as an issue link — every message with an apostrophe in it, which is most of them. `commit-message-html.ts` matches the raw text and escapes only what it emits; the same order matters for the URL and bare-hash rules, which otherwise link something *inside* a URL and split it. That file also shows the way to unit-test code that lives in a webview: write it as a real typed function and inject `fn.toString()`, which Bun returns type-stripped, rather than keeping a second copy inside a template literal where every regex backslash has to be doubled. And a backtick anywhere in a comment inside those template literals — including inside a CSS comment — ends the literal and reports as a syntax error hundreds of lines away; `webview-html.test.ts` now parses the whole injected script with `new Function` so that lands as a failing test instead of a blank panel.
|
|
108
|
+
- **`dateStyle`/`timeStyle` may not be combined with any other `Intl` option**: `toLocaleString(undefined, { dateStyle: "medium", timeStyle: "medium", timeZoneName: "short" })` does not ignore the third option, it *throws* `TypeError: dateStyle and timeStyle may not be used with other DateTimeFormat options`. Behind the `try/catch` that any date formatting picks up sooner or later, that is indistinguishable from a locale which simply has no timezone in its medium format — the commit details panel showed author and committer dates with no zone at all, and no test caught it because the fallback string is perfectly well-formed. A format that needs a companion option has to list every component explicitly (`year`/`month`/`day`/`hour`/`minute`/`second` + `timeZoneName`), and the test worth writing runs the options object through a real `Intl.DateTimeFormat` and asserts the *output* contains a zone.
|
|
109
|
+
- **A font stack is a wish list, and on Linux it usually loses**: `-apple-system`, `BlinkMacSystemFont` and `Segoe UI` all miss there, `Menlo, Monaco, Consolas` misses too, and the generic fallbacks resolve through fontconfig to Liberation Sans — or, for a bare `sans-serif`, to Liberation *Serif*. Nothing errors: the app was simply set in an Arial clone and the editor in whatever `fc-match monospace` answered, on the platform PPM is most often self-hosted on. The first entry of every stack is now a face `main.tsx` actually imports (Geist, Monaspace Argon, Monaspace Krypton via `@fontsource*`), and `tests/unit/web/editor-font.test.ts` pairs the two, because a stack naming a font nothing ships reads identically to the fixed version in review. Four things are load-bearing: ghost text may only use a *different Monaspace family*, never a different typeface, because Monaco places every character at column times character width and a family with another advance slides out of the grid; that override needs `!important`, since Monaco's own `.monaco-editor .ghost-text-decoration` rule is the same specificity and its stylesheet is appended by the AMD loader after the bundle; xterm bakes the cell size and glyph atlas from `ctx.font` at `open()`, so a terminal opened during the first paint keeps the fallback resolved then for the whole session unless it re-measures on `document.fonts.ready`; and the Nerd Font the terminal asks for first is now bundled as icons only, per block (the bullet below). Fonts cost nothing until used (`@font-face` is fetched per `unicode-range`, on demand), stay out of the SW `globPatterns`, and must stay out of `COMPRESSIBLE` in `precompress-web.ts` — `woff2` is already compressed.
|
|
110
|
+
- **A project folder is often not the repository, and every git surface has to agree on which one is**: a workspace folder can be a container whose children are the checkouts, and `simple-git` in a directory with no `.git` does not report "wrong directory" — it fails with git's own wording, which the UI renders as "not a git repository" for every panel at once. The scope is one `?repo=` parameter resolved in a middleware in `src/server/routes/git.ts` and one hook, `src/web/hooks/use-git-repo.ts`, on the browser side; `GET /git/repos` is the discovery. Four things are load-bearing. The parameter is **omitted** when the repository *is* the project root, so every URL an ordinary project builds stays byte-identical and the common case cannot regress on this path. A `repo=` outside the project must be a **400, never a fallback** to the project folder — a fallback runs the command one directory up and answers with *a* history, which is indistinguishable from a working feature until somebody acts on it. Paths cross in **both** directions: git run inside the repository reports and expects repository-relative paths while a tab's `filePath` is project-relative, so `rebaseStatusPaths` moves the *tree decorations* into the project's terms and the panel's own copy stays as git reported it, because that copy is what stage/unstage/discard/hunks send straight back. And `useGitRepo`'s return value is `useMemo`d: call sites name `gitRepo` in a dependency array, so a fresh object literal per render turns one `useCallback` into an effect that refetches forever. Watch the panel's own early returns too — `fetchStatus` deliberately does nothing until a repository is resolved, so a spinner gated only on `loading && !status` waits for a fetch that will never run and the chooser never renders.
|
|
111
|
+
- **An extension is handed a path, and it resolves the PPM project by matching that path exactly**: open a git-graph panel on a sub-repository and `resolveProjectName` falls through to the directory's basename, which names no registered project — so the tab it opens builds `/api/project/<basename>/…` and 404s, while the file path it carries is repository-relative where a tab's is project-relative. `packages/ext-git-graph/src/project-scope.ts` picks the innermost project *containing* the path and rebases the file onto it, and `resolveFileTab` does both at once because resolving them separately is how one of them gets forgotten. The spawn allowlist is not in the way: `assertSafePath` accepts any directory under a registered project, so a sub-repository is a legal cwd. Related trap when testing this: the extension host's `fetch` base URL is `http://localhost:${configService.get("port")}`, **not** the port the server was actually started on, so a dev instance whose config port disagrees has every extension `fetch` fail silently into its fallback.
|
|
112
|
+
- **A file icon theme is four separate traps, and every one of them fails silently**: PPM draws the real `vscode-icons` artwork, vendored at build time by `bun scripts/gen-file-icons.ts` into `src/web/lib/file-icons.generated.ts` (the name → glyph tables) and `src/web/styles/file-icons.generated.css` (one `background-image` class per glyph). Both are committed; re-run the script after editing its lists, and `tests/unit/web/file-icons.test.ts` fails if the two files drift, because a name with no class renders a correctly-sized span of nothing. First trap: `width`/`height` **do not apply to a non-replaced inline element**, so the icon span needs `inline-block` — the trees are flex rows and blockify it for free, while the tab strip wraps its icon in a `<span class="relative">` for the notification dot and there the icon measured 0×0 and simply was not there. An inline `<svg>` would have worked without saying so, which is why this only broke in one place. Second: `vscode-icons-js` answers with the **light-theme** drawing for 143 glyphs and offers no way to ask for the other one (`getIconForFile("a.json")` is `file_type_light_json`, full stop), and those are darker ink meant for a light workbench — `file-type-light-toml` has no `fill` at all, i.e. black on black. The generator canonicalises the class to the theme-independent name and emits the light drawing as a `:root.light` override, which costs +1.2 KiB brotli for +100 KiB raw because the two bodies differ by a colour and brotli collapses the duplication. Third: the mapping package is versioned apart from the artwork and lags it, so `Dockerfile`, `bun.lock`, `.env.local`, `Rakefile` and every `.mts` file drew the blank-page default while the right glyph sat unused in the bundle — hence `OVERRIDES`, checked against the collection at generation time. Fourth: a byte budget cuts by weight, not by worth. At 1800 bytes it dropped `file-type-reactts` (1833) and with it every `.tsx` file in a TypeScript repository, plus `.jsx`, `.go` and `.rs`. And measure the right number: the generated stylesheet is big enough that the bundler gives it its own chunk (`assets/file-icons-*.css`, 76 KiB brotli), which is outside the service worker's `globPatterns` — so it never shows up in `precache N entries` and only `precompress-web.ts`'s `.br` sibling tells you what it costs.
|
|
113
|
+
- **Icons come from `@/lib/icons`, never from `lucide-react`, and mixing the two is invisible until you look twice**: the app's chrome is Fluent System Icons at 20px Regular (the set `miguelsolorio.fluent-icons` puts over VS Code's product icons), vendored by `bun scripts/gen-product-icons.ts` into `src/web/lib/icons.generated.tsx` and built on the one component in `src/web/lib/fluent-icon.tsx`. 207 of the 222 names resolve; the other 15 stay on lucide on purpose and `tests/unit/web/product-icons.test.ts` pins that list, because "fix the missing icon by falling back" is how an icon set stops being one. Four things to know. The two sets share almost no vocabulary — lucide's `X` is Fluent's `dismiss`, `Check` is `checkmark`, `Trash2` is `delete`, `Plus` is `add`, `RefreshCw` is `arrow-sync`, and only 72 names kebab-case straight across — so `MAP` in the script is a hand-checked table, and every entry is verified against the collection at generation time rather than trusted. The glyphs keep their **20px** viewBox rather than being re-boxed to lucide's 24: Fluent's outlines are drawn for that grid, and the app sizes icons with Tailwind `size-*` classes anyway, which beat the width/height attributes because they are CSS. `strokeWidth` is accepted and *dropped* — these are filled outlines with nothing to weight, and spreading it would put a dead attribute in the DOM and make React warn about `absoluteStrokeWidth` on every render. And the identifying hook is `data-icon="<name>"`, not a class: lucide put the same information in `class="lucide lucide-circle-check"`, which is what let a tool-card test assert "this card is spinning" by string-matching the markup — an attribute keeps that possible without offering stylesheets a class name to start depending on. Related and separate: the *file* icons are a different system (`@/lib/file-icons`, the entry above), because those are full-colour artwork with no `currentColor` to inherit.
|
|
114
|
+
- **A banding rule qualified with an id outranks hover and selection**: `#commit-list .commit-row:nth-child(even)` is (1,2,0) against `.commit-row:hover` and `.commit-row.selected` at (0,2,0), so every *other* row silently stopped highlighting on hover and when selected — the kind of thing that reads as "sometimes it doesn't work". Zebra striping has to be written at the same specificity and earlier in the file, and a test asserts both. In the same stylesheet, the graph column's `@media (max-width: 640px)` block must come after the `@media (pointer: coarse)` block, which keeps all six columns and scrolls them sideways — correct for a tablet and wrong for a phone.
|
|
96
115
|
- **`vscode.languages` and every editor API are absent for extensions**: no `activeTextEditor`, no `setDecorations`, no hover providers. Anything GitLens-shaped that wants to annotate code has to render its own view in a webview panel.
|
|
97
116
|
- **Screen wake lock needs a secure context**: `navigator.wakeLock` does not exist at all over plain HTTP, so reaching PPM at `http://<lan-ip>:<port>` silently disables "keep screen awake" — the very setup (a tablet on the LAN) it was built for. Only HTTPS and `localhost` qualify. The lock is also released by the browser on *every* hide, so `src/web/hooks/use-wake-lock.ts` re-acquires on `visibilitychange` and drops its handle on hide rather than waiting for the `release` event, whose ordering against `visibilitychange` is undefined.
|
|
98
117
|
- **Remote desktop on macOS (avfoundation)**: address the screen by **name** (`-i "Capture screen 0"`), never by index — the device list reorders at runtime when a Continuity Camera joins (index 3 became the iPhone). `-framerate` is ignored (the screen input delivers at display refresh, 120–165 fps, with a stuck pts) → `-use_wallclock_as_timestamps 1` + `-vf fps=30`. ffmpeg-avfoundation ignores SIGTERM/SIGINT → `proc.kill("SIGKILL")` or it leaks one process per session. No Screen Recording grant = **black frames, no error**; no Accessibility grant = silent no-op input — both are pre-flighted in `remote-desktop-requirements.ts`, never inferred from failures. TCC keys the grant to the `bun` executable.
|
|
99
118
|
- **Remote desktop text injection on macOS**: `CGEventKeyboardSetUnicodeString` still carries a keycode, and IMEs that hook by key (OpenKey/EVKey) re-read keycode 0 as a literal "a" (`"日本"` → `"â"`); function/unassigned keycodes produce no text at all. The carrier is Space (`TEXT_CARRIER_KEYCODE`). Text is still subject to the host's active IME (Telex rewrote "World" → "ửold") on every OS.
|
|
119
|
+
- **A white screen has two causes and only one of them is catchable**: both start with a hashed chunk the browser asks for and the server does not have — `vite build` runs with `emptyOutDir`, so an upgrade deletes every previous hash while a tab is still naming them. `static.ts` used to SPA-fall-back on *any* missing path, so that request came back as **`200 text/html`**, which a module load refuses on its strict MIME check; `static-fallback.ts` now decides by `Sec-Fetch-Dest` (plus `/assets/` and `/monacoeditorwork/` as the prefix, because browsers omit Fetch Metadata on an insecure origin and PPM is usually reached over plain HTTP on a LAN). The path's *shape* cannot be the test: PPM's routes embed file paths, so `/project/x/editor/src/main.js` is a navigation whose extension is `.js`. Then: a **lazy** chunk failing throws inside `React.lazy`, and a throw past the last boundary unmounts the entire tree — `main.tsx` had no root boundary, so `#root` simply emptied. But the entry's own graph is **39 separately-hashed chunks** (rolldown names one of them `settings-tab-*` while the entry statically imports it, so the name says nothing), and one of those missing means the entry module *never executes*: no React, no boundary, no listener, nothing bundled to report it. That is what the inline watchdog in `index.html` is for, gated on the `__ppmEntryRan` flag `main.tsx` sets so the two can never both fire. The service worker made either one **permanent**: `CacheFirst` on `/assets/` had stored that `text/html` under the chunk's URL and content-hashed assets are never revalidated, so restoring the file on the server fixed nothing and only `caches.delete("ppm-assets")` did — hence the plugin refusing to store *or* serve HTML on both runtime caches, `cleanupOutdatedCaches()`, and the `skipWaiting`/`clients.claim()` that `registerType: "autoUpdate"` never actually implemented in `injectManifest` mode. Two things will hide the bug while you try to reproduce it: `Cache-Control: immutable` means a chunk already in the HTTP cache is served from disk however hard the server 404s, and `CacheFirst` means one already in `ppm-assets` is too — a cold origin (a different port) is the only reliable reproduction.
|
|
120
|
+
- **A long-press must be disarmed on `touchcancel`, and leaving it out looks like nothing**: the pattern is a timer armed on `touchstart` and cleared on `touchmove`/`touchend`, which reads as complete. It is not — once the browser decides the gesture belongs to a scroll it fires **`touchcancel`** and then delivers *no further* `touchmove` or `touchend` to that element, so the timer survives the scroll and fires into it: a context menu over a list the finger is already moving, or a tab strip entering drag mode by itself. A movement tolerance cannot save it either, because the moves it would have measured are never delivered. It reproduces on a phone and nowhere else (a mouse has no touch events, and device emulation dispatches move/end faithfully), which is how it stayed live in **seven** separate hand-rolled long-presses at once — `git-status-panel.tsx`, `ui/adaptive-context-menu.tsx`, `os-explorer/use-coarse-long-press.ts`, `hooks/use-touch-tab-drag.ts`, `layout/mobile-drawer-tab-bar.tsx`, `layout/mobile-tab-switcher-sheet.tsx`, `layout/project-bottom-sheet.tsx`. `tests/unit/web/long-press-touchcancel.test.ts` fails any file that arms a timer from `onTouchStart` without naming `onTouchCancel`. Two related traps in the same shape: a hook that returns handlers has to *return* the cancel one and every forwarding component in between has to pass it on (`use-touch-tab-drag` → `tab-bar` → `draggable-tab` is three files for one prop), and the timer needs clearing on unmount — the git panel refreshes its file list on every save, so a row can vanish mid-press and open a menu belonging to no row.
|
|
121
|
+
- **A blob URL is not stable for the life of the thing it previews**: the composer creates one from the image as pasted, downscales, then revokes the first and points the chip at the reduced copy — and `URL.revokeObjectURL` makes an open viewer render a *broken image* with no error, no console warning and nothing to say why. So `attachment-chips.tsx` keeps a `Map` of every preview URL it has handed to the lightbox against the attachment it belongs to: a URL that was replaced is followed, and one whose attachment is gone closes the viewer. Keyed by URL rather than by remembering one "currently viewing" id, because the overlay's arrow keys move between images without telling the component, and an id stops describing what is on screen the moment they are used. Related: the lightbox's gallery is collected from the **DOM** (`collectGallery`), so a row of thumbnails needs `GALLERY_ROOT_ATTR` on the container *and* `GALLERY_ITEM_ATTR` on each `<img>` — miss either and the viewer opens with dead arrows and no sign a second image was ever attached.
|
|
100
122
|
|
|
123
|
+
- **A prompt's icons are Private Use Area codepoints, and a font that arrives late draws nothing at all**: a themed shell prompt takes its separators, git status and language badges from the PUA, so on a machine with no patched font every one of them was tofu while the `↑39 ↓15` between them rendered — those two are real Unicode, and that asymmetry is the whole diagnosis. `scripts/gen-nerd-font.ts` vendors the symbols-only face (version and SHA-256 both pinned; the single file from the repository tree is byte-identical to the one inside the release tarball, so no `tar`/`xz` is needed) and splits it into **fourteen** `@font-face`s, one per icon set. The split *is* the optimisation and it is load-bearing three times over: a face with no `unicode-range` is a candidate for all text and downloads unconditionally — all 1.14 MB of it; two faces claiming one codepoint fetch a second 500 KiB file to draw a glyph already in hand; and Vite's 4 KB `assetsInlineLimit` base64'd the four *smallest* faces straight into the entry CSS, which is the one file the SW precaches, so the rarest sets became an unconditional download for everyone (hence the function form excluding `woff2`, which made the boot shell 9 KiB smaller than before the font was added at all). The family name is PPM's own rather than `Symbols Nerd Font Mono` because a `@font-face` shadows a same-named system font *completely* — naming the real one would replace a full local install's 10,624 glyphs with this subset's — and it sits behind the installed names but ahead of Monaspace, which is safe only because it contains no letters or digits for ordinary text to stop at. Then the timing, measured rather than assumed: a canvas `fillText` **does** start the fetch (0 → 1 request; setting `ctx.font` alone does not), the load **does** fire `FontFaceSet`'s `loadingdone`, and the tofu it drew first is **permanent** — xterm bakes glyphs into a texture atlas and nothing repaints it, so ink was byte-identical 1.8 s after the face finished loading and only changed on a redraw. `use-terminal.ts` hangs `clearTextureAtlas()` + `refresh()` on `loadingdone` for the terminal's whole life; `document.fonts.ready` cannot do it, because it resolves long before a prompt first draws a PUA character and triggers the fetch. With the listener's body removed the glyph rasterisations after a face landed were +0, with it +14. Last trap, and it is the one that makes this untestable locally: after the stack is exhausted the browser asks **fontconfig** for any font with the codepoint, and a dev box with Nerd Fonts installed answers for all of them — so the webfont is never requested, a local screenshot proves nothing, and the bug reproduces only where no such font exists. Verify by forcing each face with `document.fonts.load()` and asserting the request that follows is that block's file.
|
|
124
|
+
|
|
125
|
+
- **A `DropdownMenu` used as a row's context menu takes the row's tap away, and the adaptive one gives no tap back**: a dropdown trigger opens on *click*, so on a touch screen the gesture that opens it is the same one that would have activated the row — the Source Control panel's folder rows could not be expanded on a phone at all, because tapping one opened a menu over it. `@/components/ui/adaptive-context-menu` is the fix (bottom sheet + long-press below `md`, radix right-click above), but it only *suppresses* the click that follows a press: it has no tap handler of its own, so whatever the tap should do has to be a real button inside the trigger. That is also what removes the hand-rolled "was that a tap or a press?" timer, which is where the `touchcancel` class of bug lives. Two details when converting: mark a destructive item with `variant="destructive"` rather than a `text-destructive` class, because the class only reaches the radix half and the sheet takes its colour from the variant; and put `select-none` on the trigger's child, or a long press starts a text selection under the sheet it opens.
|
|
126
|
+
|
|
127
|
+
- **An ANSI palette's neutral ends sit on top of the background, and the fix is not in the palette**: two of the sixteen slots are *defined* to be extremes, so a light theme's `white`/`brightWhite` and a dark theme's `black` land on the background — 1.03–1.18:1 across PPM's six built-in themes, i.e. invisible rather than merely dim. It is not a theoretical slot either: oh-my-posh writes its second prompt line in plain **SGR 37**, correct on the dark terminal it was designed for, and that line was absent on every light theme. Recolouring the slot cannot fix it, because the same `white` is also the text *on* a coloured powerline segment where white is right — only a per-cell decision can tell the two uses apart. `minimumContrastRatio` is xterm's, it defaults to **1 (do nothing)**, and VS Code ships 4.5; it adjusts the foreground against each cell's real background, so segments render byte-identically and only text on the bare background moves. Set it as a *terminal* option, not via a renderer: the WebGL addon is skipped on touch devices, which is where this was reported from. Two traps when measuring a prompt: parse `38;5;`/`37`/`97` as well as `38;2;` truecolor, or plain-ANSI runs read as "no colour set" and the real culprit is invisible to the tooling too — and a `%{`…`%}`-quoted zsh prompt has to have those markers stripped before it is written to a terminal, since the shell normally eats them. `tests/unit/web/terminal-contrast.test.ts` pins the hazard and the mitigation together.
|
|
128
|
+
|
|
129
|
+
- **An overlay on a vendored glyph assumes that glyph is empty, and an icon set migration silently breaks that**: the streaming chat tab draws three bouncing dots absolutely positioned over its 16px bubble icon, which was correct against lucide's hollow `MessageSquare`. Fluent's `chat` is the same bubble with **two message lines drawn inside it**, so after the migration the dots landed on the upper line in the same `currentColor` and the three fused into one lumpy bar — a static-looking smudge at the size a tab renders, reported as a broken animation rather than a wrong glyph, because the dots really were still bouncing. The fix is `chat-empty` (exported as `MessageCircle`), whose two subpaths are byte-identical to `chat`'s first two: same outline, nothing in it. Two things generalise. A glyph's *subpath count* is the cheap test for "does this draw anything inside itself" — `tests/unit/web/tab-streaming-indicator.test.ts` asserts the host glyph contributes exactly the outer edge and its hole, so a MAP edit or a regeneration cannot put a lined glyph back under the dots; and freezing a CSS animation with `animation-play-state: paused` plus a *negative* `animation-delay` renders any phase of its cycle, which is how a bounce this small is compared before and after at all. Note also that `isStreaming` is safe to branch an icon on only because both call sites read `sessionId` exclusively for `type === "chat"`.
|
|
130
|
+
|
|
131
|
+
- **A Monarch `/$/` rule never runs, so a line-oriented grammar may not use states at all**: Monarch's per-line loop ends the moment the position reaches the end of the line, which means the idiomatic-looking `[/$/, { token: "", next: "@popall" }]` is dead code — the state entered mid-line is *never* left, and it carries into every following line. The `dotenv` grammar (`src/web/lib/monaco-dotenv-language.ts`, since Monaco ships no `.env` language and neither does VS Code) first used a `@value` state entered on `=`; from the first assignment on, the whole file tokenized as a value, so `#KEY=off` came back `string` — the one case the language existed for, still broken while every line *looked* coloured. Everything has to happen in `root`, the way Monaco's own `ini` does, and the test forbids a `next:` outright. Two consequences of statelessness worth knowing: a quoted value must be matched **whole** (`/"(?:[^"\\]|\\.)*"/`), which is the only way a `#` inside it is not read as a comment — at the cost of not colouring an interpolation inside quotes; and an unterminated quote falls through to the bare-value rule instead of swallowing the rest of the file. Separately, this grammar needs **no** `*-token-rules.ts` beside `diff-token-rules.ts`: its token names are Monaco's own (`comment`, `key`, `string`, `variable`, `keyword`, `delimiter`) and `monaco-adapter.ts` defines every PPM theme with `inherit: true`, so the colours arrive from the `vs`/`vs-dark` base and cannot drift from the app's themes — the test reads that pairing out of Monaco's own theme table rather than trusting it. Last trap, when verifying any of this in a browser: a standalone Monaco has **one global theme**, so two editors cannot show two themes at once (the second `create` silently retints the first), and sampling colours right after `setTheme` reads the *old* `mtk` class indices against the new palette — `string` measured as `#FF0000`. One editor, one reload per theme. Do not be misled by a `dotenv-*.js` chunk in the build output: that is shiki's TextMate grammar for a fenced `dotenv` block in markdown (`@shikijs/langs`, reached from `markdown-code-block.tsx`), a separate pipeline Monaco cannot read — there is no TextMate bridge in the editor, which is why a Monarch grammar had to be written even though the repository already ships a dotenv grammar.
|
|
132
|
+
- **A filename column has to ellipsize from its *start*, and only `dir="rtl"` + `<bdi>` does it without leaving a mark**: `text-overflow: ellipsis` cuts the end, which in a list of source files is the only part that differs — `remote-desktop-capture.ts`, `remote-desktop-capture-input.ts` and `remote-desktop-encoder-args.ts` agree for **23 characters**, so seven Source Control rows all rendered as `remote-desktop-…` and the panel could not say which file it was listing. Three approaches fail before the fourth, and none of them fails loudly: splitting the name and pinning the tail beside an ellipsized head opens a ragged gap mid-row, because flex hands the head a fractional width while the ellipsis lands on a whole character — and `text-align` does **not** close it (measured; alignment does not apply to overflowing content); a fixed-length tail cuts mid-word into fragments that mean nothing (`…rgs.test.ts`); and the U+2066/U+2069 isolate *characters* render correctly but land in `textContent`, so a copied filename carries invisible codepoints. `<bdi>` inside a `dir="rtl"` box is the one that leaves the text clean (`StartEllipsis` in `git-status-panel.tsx`), and the isolate is load-bearing rather than tidy: outside one, the `.` of `.gitignore` is a neutral character at a run boundary, takes the paragraph's direction and renders as `gitignore.`. A dimmed path prefix in the same box has to be **one inline flow** inside the `<bdi>`, not two flex children, or the row's `gap` opens a space inside the path (`web/ components`). Related: the tree's own pure functions live in `src/web/lib/git-file-tree.ts` rather than in the panel, because importing the component reaches the zustand stores, which read `localStorage` at module scope and throw under `bun:test` — logic embedded in a component file here is untestable by construction, not merely awkward.
|
|
101
133
|
## UI Rules
|
|
102
134
|
|
|
103
135
|
When creating or modifying any UI component, you MUST read and follow `docs/design-guidelines.md`, especially the **Mobile-First UI Rules** section. Key rules:
|
|
@@ -136,5 +168,14 @@ Before planning or implementing a new feature, read `docs/project-roadmap.md` to
|
|
|
136
168
|
- `src/services/db-backup/` — verified `VACUUM INTO` snapshots of `ppm.db` (hourly + at start + before every migration), GFS retention, `ppm backup` / `ppm restore`
|
|
137
169
|
- `src/services/remote-desktop/` — Remote Desktop: one ffmpeg per WS session (`remote-desktop-capture.ts` + per-platform `remote-desktop-capture-input.ts` + `remote-desktop-encoder-args.ts`) → Annex-B H.264 access units → WebCodecs; input via `remote-desktop-input.ts` facade over `remote-desktop-input-{win32,darwin}.ts` (bun:ffi, no helper binary); host checklist in `remote-desktop-requirements.ts` (ffmpeg install command, macOS TCC pre-flight); display list in `remote-desktop-displays.ts` (`CGGetActiveDisplayList` order = avfoundation `Capture screen N`, names/bounds via one JXA call). Routes `src/server/routes/remote-desktop.ts`, WS `src/server/ws/remote-desktop.ts`, UI `src/web/components/remote-desktop/`, e2e `tests/e2e/remote-desktop-e2e.mjs`
|
|
138
170
|
- `src/services/git-hunks/` — hunk/line-level stage, unstage and discard (`/api/projects/:name/git/{hunks,stage-hunks,unstage-hunks,discard-hunks}`). `unified-diff.ts` holds the patch surgery (recomputed `@@` counts, unselected deletions demoted to context); the UI is `src/web/components/git/hunk-stage-dialog.tsx`
|
|
139
|
-
- `src/services/git-
|
|
171
|
+
- `src/services/git-repos/` — which repository a project's git surfaces run in, when the project folder is a container of checkouts rather than a repository itself. `git-repo-discovery.ts` walks the folder (`GET /git/repos`), the `?repo=` middleware in `src/server/routes/git.ts` scopes every git route to one of them, and the browser side is `src/web/lib/git-repo-scope.ts` (pure decisions and both directions of path rebasing), `src/web/stores/git-repo-store.ts` (the device-local choice), `src/web/hooks/use-git-repo.ts` (what every panel calls) and `src/web/components/git/git-repo-picker.tsx`. Extension panels are opened on the repository, so `packages/ext-git-graph/src/project-scope.ts` maps that path back to the containing project
|
|
172
|
+
- `src/web/lib/icons.ts` + `src/web/lib/icons.generated.tsx` + `src/web/lib/fluent-icon.tsx` — the product icons (Fluent System Icons 20px Regular, MIT, microsoft/fluentui-system-icons) for the app's own chrome. Every UI icon is imported from `@/lib/icons`; regenerate with `bun scripts/gen-product-icons.ts` after editing its `MAP`
|
|
173
|
+
- `src/server/routes/static-fallback.ts` + `src/web/components/root-error-boundary.tsx` + `src/web/lib/chunk-recovery.ts` + the inline watchdog in `src/web/index.html` — the four halves of not going blank when a chunk is missing: 404 instead of the shell, a boundary above `App`, one guarded purge-and-reload on `vite:preloadError`, and a dependency-free last resort for when the entry never ran at all
|
|
174
|
+
- `src/web/lib/file-icons.tsx` + `src/web/lib/file-icons.generated.ts` + `src/web/styles/file-icons.generated.css` — the file icon theme (real `vscode-icons` artwork, MIT). `FileIcon` for a component slot, `fileIconElement` for the `icon: ElementType` slots (tab bar, command palette, both through `src/web/lib/tab-type-icons.ts`). Regenerate with `bun scripts/gen-file-icons.ts`
|
|
175
|
+
- `src/services/lsp/` — language servers for the editor. `server-registry.ts` says which binary serves which language and how to find it (project `node_modules/.bin` before PATH), `lsp-protocol.ts` is the `Content-Length` framing, `lsp-session.ts` owns one child process, `lsp-manager.ts` decides how many exist and shares them by *server + root directory*. Bridge at `src/server/ws/lsp.ts` on `/ws/project/:name/lsp`, status at `/api/projects/:name/lsp/status`. Browser side in `src/web/lib/lsp/` (client, Monaco conversions, providers, shadow models, F12 navigation) driven by `src/web/hooks/use-lsp.ts`. All of it is behind the `lspEnabled` setting — off by default, per device, never on below the `md` breakpoint — and mounted by `src/web/components/editor/editor-language-service.tsx`, which `code-editor.tsx` may only reach through `lazy()`. Real-server check: `bun tests/e2e/lsp-e2e.ts`
|
|
176
|
+
- `src/web/components/problems/` + `src/web/stores/problems-store.ts` — the Problems panel: a dock tab (`DOCK_ALLOWED_TAB_TYPES`) fed by every mounted editor's `useLsp`, opened from the status bar counts on desktop and the editor's LSP row on mobile. Scoped to the active project because `tab-pool` keeps other projects' editors mounted for keep-alive, so their servers keep publishing
|
|
177
|
+
- `src/services/git-blame/` — `git blame --porcelain` for the editor's inline annotation (`/api/projects/:name/git/blame`); shared shape and formatting in `src/shared/blame.ts`, editor wiring in `src/web/hooks/use-inline-blame.ts`. The annotation's GitLens-style hover adds one `git show --unified=0` per commit *and line* (`/git/commit-line`, parsed by `commit-line-diff.ts`), with the markdown built in `src/web/lib/blame-hover.ts` and its buttons registered in `blame-hover-commands.ts`, which hand off to the Git Graph extension's own views over `ext:command:execute`
|
|
178
|
+
- `dist/web` asset pipeline — `scripts/copy-monaco.ts` stages `monaco-editor/min/vs` under `dist/web/assets/monaco/` (inside `assets/` so it inherits the immutable cache header, the SW runtime cache and the compressed siblings), `scripts/precompress-web.ts` writes `.br`/`.gz` siblings, and `src/server/routes/static-encoding.ts` chooses one per request (honouring `q=0` and `*`, keeping the original MIME, adding `Vary: Accept-Encoding` and the encoding in the ETag). Both scripts run after `build:web` in the `build` chain
|
|
179
|
+
- `src/web/components/extensions/` — the webview host. `extension-webview.tsx` matches a panel to a tab and mounts its HTML as a sandboxed `srcDoc`; `webview-theme.ts` injects PPM's applied theme into it (mode attribute + token block) and forwards later theme changes by `postMessage`
|
|
180
|
+
- `scripts/gen-nerd-font.ts` + `src/web/styles/nerd-font.generated.css` + `src/web/styles/fonts/` — the terminal's icon glyphs (Nerd Fonts symbols-only, MIT, ryanoasis/nerd-fonts), subset per icon set so each `@font-face` is fetched only when something draws a character in its range. Regenerate with `bun scripts/gen-nerd-font.ts` after editing its `BLOCKS`; `TERMINAL_FONT_FAMILY` in `src/web/lib/editor-font.ts` is what names the family, and `use-terminal.ts` is what invalidates xterm's glyph atlas when a face lands
|
|
140
181
|
- `src/services/named-tunnel/` — Named tunnel (stable `https://<prefix>.<zone>` URL via Cloudflare login), orchestrated from `src/server/routes/named-tunnel.ts`, spawned/probed by the supervisor; UI in `src/web/components/tunnels/named-tunnel/`
|
package/LICENSE
CHANGED
|
@@ -4,6 +4,11 @@ Copyright (c) 2026 hienlh
|
|
|
4
4
|
|
|
5
5
|
URL: https://www.elastic.co/licensing/elastic-license
|
|
6
6
|
|
|
7
|
+
These terms cover PPM itself. PPM also redistributes third-party components —
|
|
8
|
+
icon artwork and font subsets — each under its own licence, which continues to
|
|
9
|
+
apply to that component and is unaffected by anything below. They are listed in
|
|
10
|
+
THIRD-PARTY-NOTICES.md, with the full licence texts under licenses/.
|
|
11
|
+
|
|
7
12
|
## Acceptance
|
|
8
13
|
|
|
9
14
|
By using the software, you agree to all of the terms and conditions below.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
PPM itself is licensed under the Elastic License 2.0 (see `LICENSE`). It also
|
|
4
|
+
redistributes the components below, each under its own terms, which continue to
|
|
5
|
+
apply to those components.
|
|
6
|
+
|
|
7
|
+
Every section here is emitted by the generator that vendors the component —
|
|
8
|
+
edit that generator, not this file. Re-run:
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
bun scripts/gen-product-icons.ts
|
|
12
|
+
bun scripts/gen-file-icons.ts
|
|
13
|
+
bun scripts/gen-nerd-font.ts
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
<!-- BEGIN product-icons -->
|
|
17
|
+
|
|
18
|
+
## Product icons
|
|
19
|
+
|
|
20
|
+
`src/web/lib/icons.generated.tsx` holds the path data for 175 glyphs, emitted by
|
|
21
|
+
`scripts/gen-product-icons.ts` at 20px Regular. The outlines are reproduced unchanged;
|
|
22
|
+
only the surrounding component is PPM's. The 15 names Fluent has no glyph for stay on
|
|
23
|
+
`lucide-react`, which is a dependency rather than something vendored here.
|
|
24
|
+
|
|
25
|
+
| Component | Upstream | Version | Licence | Copyright |
|
|
26
|
+
| --- | --- | --- | --- | --- |
|
|
27
|
+
| Fluent UI System Icons | [github.com/microsoft/fluentui-system-icons](https://github.com/microsoft/fluentui-system-icons) | 1.1.338 | [MIT](licenses/MIT.txt) | © Microsoft Corporation |
|
|
28
|
+
|
|
29
|
+
- **Fluent UI System Icons** — vendored through `@iconify-json/fluent`.
|
|
30
|
+
|
|
31
|
+
<!-- END product-icons -->
|
|
32
|
+
|
|
33
|
+
<!-- BEGIN file-icons -->
|
|
34
|
+
|
|
35
|
+
## File icons
|
|
36
|
+
|
|
37
|
+
`src/web/styles/file-icons.generated.css` inlines 224 SVG drawings as data URIs and
|
|
38
|
+
`src/web/lib/file-icons.generated.ts` holds the name-to-glyph tables. Both are emitted by
|
|
39
|
+
`scripts/gen-file-icons.ts` from the packages below: the artwork comes from the icon
|
|
40
|
+
collection, the extension-to-name mapping from `vscode-icons-js`. The drawings are
|
|
41
|
+
reproduced unchanged apart from being minified into a URI.
|
|
42
|
+
|
|
43
|
+
| Component | Upstream | Version | Licence | Copyright |
|
|
44
|
+
| --- | --- | --- | --- | --- |
|
|
45
|
+
| vscode-icons (artwork) | [github.com/vscode-icons/vscode-icons](https://github.com/vscode-icons/vscode-icons) | 12.19.0 | [MIT](licenses/MIT.txt) | © Roberto Huertas |
|
|
46
|
+
| vscode-icons-js (name mapping) | [github.com/dderevjanik/vscode-icons-js](https://github.com/dderevjanik/vscode-icons-js) | 11.6.1 | [MIT](licenses/MIT.txt) | © Daniel Derevjanik |
|
|
47
|
+
|
|
48
|
+
- **vscode-icons (artwork)** — vendored through `@iconify-json/vscode-icons`.
|
|
49
|
+
|
|
50
|
+
<!-- END file-icons -->
|
|
51
|
+
|
|
52
|
+
<!-- BEGIN nerd-font -->
|
|
53
|
+
|
|
54
|
+
## Terminal icon glyphs
|
|
55
|
+
|
|
56
|
+
`src/web/styles/fonts/nerd-symbols-*.woff2` (14 files) are subsets of the
|
|
57
|
+
symbols-only face from [Nerd Fonts v3.5.1](https://raw.githubusercontent.com/ryanoasis/nerd-fonts/v3.5.1/patched-fonts/NerdFontsSymbolsOnly/SymbolsNerdFontMono-Regular.ttf), cut per icon set by
|
|
58
|
+
`scripts/gen-nerd-font.ts`. Nerd Fonts assembles them from the projects below; the
|
|
59
|
+
subsetting reproduces their outlines unchanged.
|
|
60
|
+
|
|
61
|
+
The `@font-face` family is `PPM Nerd Symbols`, not any upstream family name. That is there so
|
|
62
|
+
a local install of the real font is not shadowed, and it also satisfies the Reserved
|
|
63
|
+
Font Name clause the SIL OFL sets on Pomicons: no PPM face is offered under a
|
|
64
|
+
reserved name.
|
|
65
|
+
|
|
66
|
+
| Component | Upstream | Version | Licence | Copyright |
|
|
67
|
+
| --- | --- | --- | --- | --- |
|
|
68
|
+
| Codicons | [github.com/microsoft/vscode-codicons](https://github.com/microsoft/vscode-codicons) | 0.0.45 | [CC-BY-4.0](licenses/CC-BY-4.0.txt) | © Microsoft Corporation |
|
|
69
|
+
| Devicons | [github.com/devicons/devicon](https://github.com/devicons/devicon) | 2.17.0 | [MIT](licenses/MIT.txt) | © konpa |
|
|
70
|
+
| Font Awesome Free | [github.com/FortAwesome/Font-Awesome](https://github.com/FortAwesome/Font-Awesome) | 6.5.1 | [CC-BY-4.0](licenses/CC-BY-4.0.txt) (icons), [OFL-1.1](licenses/OFL-1.1.txt) (fonts) | © Fonticons, Inc. |
|
|
71
|
+
| Font Awesome Extension | [github.com/AndreLZGava/font-awesome-extension](https://github.com/AndreLZGava/font-awesome-extension) | 0.0.3 | [MIT](licenses/MIT.txt) | © André Luiz Gava |
|
|
72
|
+
| Font Logos | [github.com/Lukas-W/font-logos](https://github.com/Lukas-W/font-logos) | 1.3.0 | [Unlicense](licenses/Unlicense.txt) | © Lukas W |
|
|
73
|
+
| Unicode Power Symbols | [github.com/jloughry/Unicode](https://github.com/jloughry/Unicode) | Feb 2015 | [MIT](licenses/MIT.txt) | © Joe Loughry |
|
|
74
|
+
| Material Design Icons | [github.com/Templarian/MaterialDesign-Font](https://github.com/Templarian/MaterialDesign-Font) | Oct 6, 2022 | [Apache-2.0](licenses/Apache-2.0.txt) | © Pictogrammers |
|
|
75
|
+
| Nerd Fonts (patcher and its own Custom glyphs) | [github.com/ryanoasis/nerd-fonts](https://github.com/ryanoasis/nerd-fonts) | v3.5.1 | [MIT](licenses/MIT.txt) | © Ryan L McIntyre |
|
|
76
|
+
| Octicons | [github.com/primer/octicons](https://github.com/primer/octicons) | 18.3.0 | [MIT](licenses/MIT.txt) | © GitHub Inc. |
|
|
77
|
+
| Pomicons | [github.com/gabrielelana/pomicons](https://github.com/gabrielelana/pomicons) | 1.001 | [OFL-1.1](licenses/OFL-1.1.txt) | © Gabriele Lana |
|
|
78
|
+
| Powerline Symbols | [github.com/powerline/powerline](https://github.com/powerline/powerline) | 1.000 | [MIT](licenses/MIT.txt) | © Kim Silkebækken and other contributors |
|
|
79
|
+
| Powerline Extra Symbols | [github.com/ryanoasis/powerline-extra-symbols](https://github.com/ryanoasis/powerline-extra-symbols) | 1.200 | [MIT](licenses/MIT.txt) | © Ryan L McIntyre |
|
|
80
|
+
| Seti UI | [github.com/jesseweed/seti-ui](https://github.com/jesseweed/seti-ui) | 0.8.1 | [MIT](licenses/MIT.txt) | © Jesse Weed |
|
|
81
|
+
| Weather Icons | [github.com/erikflowers/weather-icons](https://github.com/erikflowers/weather-icons) | 2.0.10 | [OFL-1.1](licenses/OFL-1.1.txt) | © Erik Flowers, artwork by Lukas Bischoff |
|
|
82
|
+
|
|
83
|
+
<!-- END nerd-font -->
|
|
@@ -71,4 +71,4 @@ This skill covers the `ppm` CLI, its HTTP API, and its config DB. It does **not*
|
|
|
71
71
|
- Third-party extensions (inspect via `ppm ext list`).
|
|
72
72
|
- The Claude Agent SDK internals (separate skill).
|
|
73
73
|
|
|
74
|
-
<!-- Generated for PPM v0.
|
|
74
|
+
<!-- Generated for PPM v0.21.0 at build time. Re-run `ppm export skill --install` to refresh. -->
|
|
@@ -349,4 +349,4 @@ _Base URL: `http://localhost:8080` (default; override via `ppm config set port <
|
|
|
349
349
|
- `ws://<host>/ws/terminal` — PTY terminal multiplexer
|
|
350
350
|
- `ws://<host>/ws/extensions` — extension host channel
|
|
351
351
|
|
|
352
|
-
<!-- Generated from src/server/routes/ for PPM v0.
|
|
352
|
+
<!-- Generated from src/server/routes/ for PPM v0.21.0 -->
|