@hienlh/ppm 0.23.5 → 0.23.7
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 +89 -0
- package/CLAUDE.md +21 -1
- package/Dockerfile.test +8 -1
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +30 -1
- package/dist/web/assets/accounts-settings-section-BYWnY9hH.js +1 -0
- package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.gz +0 -0
- package/dist/web/assets/{ai-resource-editor-DKcsVDle.js → ai-resource-editor-CY4n_Ccv.js} +1 -1
- package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-Bs3iUW4j.js +1 -0
- package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.br +0 -0
- package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-DDs11XV4.js +1 -0
- package/dist/web/assets/api-client-CJPnCOG-.js +1 -0
- package/dist/web/assets/{api-client-c8YOpTlT.js → api-client-D-SMbdiH.js} +1 -1
- package/dist/web/assets/api-client-D-SMbdiH.js.br +0 -0
- package/dist/web/assets/api-client-D-SMbdiH.js.gz +0 -0
- package/dist/web/assets/api-settings-BDkkhFMq.js +1 -0
- package/dist/web/assets/{api-settings-BmvNoCbn.js → api-settings-Bv9mLCty.js} +1 -1
- package/dist/web/assets/api-settings-Bv9mLCty.js.br +0 -0
- package/dist/web/assets/api-settings-Bv9mLCty.js.gz +0 -0
- package/dist/web/assets/{api-themes-6fOQJgM9.js → api-themes-3wW-zLzU.js} +1 -1
- package/dist/web/assets/appearance-settings-section-C0BoIBmz.js +1 -0
- package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.gz +0 -0
- package/dist/web/assets/apps-panel-DXAFsveZ.js +1 -0
- package/dist/web/assets/apps-panel-DXAFsveZ.js.br +0 -0
- package/dist/web/assets/apps-panel-DXAFsveZ.js.gz +0 -0
- package/dist/web/assets/{audio-preview-vaG2cB-k.js → audio-preview-BfES4Cx5.js} +1 -1
- package/dist/web/assets/audio-preview-BfES4Cx5.js.br +0 -0
- package/dist/web/assets/audio-preview-BfES4Cx5.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-CA8hPSX9.js +1 -0
- package/dist/web/assets/branch-review-tab-CA8hPSX9.js.br +0 -0
- package/dist/web/assets/branch-review-tab-CA8hPSX9.js.gz +0 -0
- package/dist/web/assets/{button-Ci9EUgqd.js → button-DeAyLH9U.js} +1 -1
- package/dist/web/assets/button-DeAyLH9U.js.br +0 -0
- package/dist/web/assets/button-DeAyLH9U.js.gz +0 -0
- package/dist/web/assets/{chat-preparation-cache-BSIQGiWx.js → chat-preparation-cache-CcCd2g7A.js} +1 -1
- package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.br +0 -0
- package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.gz +0 -0
- package/dist/web/assets/chat-tab-BWi_bUzA.js +1 -0
- package/dist/web/assets/chat-tab-BWi_bUzA.js.br +0 -0
- package/dist/web/assets/chat-tab-BWi_bUzA.js.gz +0 -0
- package/dist/web/assets/chat-tab-BvJhIaVE.js +15 -0
- package/dist/web/assets/chat-tab-BvJhIaVE.js.br +0 -0
- package/dist/web/assets/chat-tab-BvJhIaVE.js.gz +0 -0
- package/dist/web/assets/code-editor-OJUdLVnn.js +7 -0
- package/dist/web/assets/code-editor-OJUdLVnn.js.br +0 -0
- package/dist/web/assets/code-editor-OJUdLVnn.js.gz +0 -0
- package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js +1 -0
- package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.br +0 -0
- package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.gz +0 -0
- package/dist/web/assets/{conflict-editor-qMGJH0Bx.js → conflict-editor-BpKW_vbL.js} +1 -1
- package/dist/web/assets/conflict-editor-BpKW_vbL.js.br +0 -0
- package/dist/web/assets/conflict-editor-BpKW_vbL.js.gz +0 -0
- package/dist/web/assets/context-menu-7OX80HDB.js +1 -0
- package/dist/web/assets/context-menu-7OX80HDB.js.br +0 -0
- package/dist/web/assets/context-menu-7OX80HDB.js.gz +0 -0
- package/dist/web/assets/{csv-preview-D2I742dl.js → csv-preview-COYdTABa.js} +1 -1
- package/dist/web/assets/csv-preview-COYdTABa.js.br +0 -0
- package/dist/web/assets/csv-preview-COYdTABa.js.gz +0 -0
- package/dist/web/assets/{data-grid-overlay-editor-CQRVKr7y.js → data-grid-overlay-editor-CeZoduke.js} +1 -1
- package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.br +0 -0
- package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.gz +0 -0
- package/dist/web/assets/{database-viewer-Bz4LjgIa.js → database-viewer-BQcBqCKm.js} +1 -1
- package/dist/web/assets/database-viewer-BQcBqCKm.js.br +0 -0
- package/dist/web/assets/database-viewer-BQcBqCKm.js.gz +0 -0
- package/dist/web/assets/{design-export-client-ChMcMoqW.js → design-export-client-OrnGCSwu.js} +1 -1
- package/dist/web/assets/design-export-client-OrnGCSwu.js.br +0 -0
- package/dist/web/assets/design-export-client-OrnGCSwu.js.gz +0 -0
- package/dist/web/assets/{design-responsive-dialog-DNBhJJLf.js → design-responsive-dialog-vJjQrC4n.js} +1 -1
- package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.br +0 -0
- package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.gz +0 -0
- package/dist/web/assets/design-tab-BbmFk38H.js +33 -0
- package/dist/web/assets/design-tab-BbmFk38H.js.br +0 -0
- package/dist/web/assets/design-tab-BbmFk38H.js.gz +0 -0
- package/dist/web/assets/{designs-sidebar-panel-CapP1yXq.js → designs-sidebar-panel-D2kXwB8B.js} +1 -1
- package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.gz +0 -0
- package/dist/web/assets/dialog-Bocc0Fgb.js +1 -0
- package/dist/web/assets/dialog-Bocc0Fgb.js.br +0 -0
- package/dist/web/assets/dialog-Bocc0Fgb.js.gz +0 -0
- package/dist/web/assets/{diff-viewer-CdXi7cZN.js → diff-viewer-Bj4DT6Mj.js} +1 -1
- package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.br +0 -0
- package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.gz +0 -0
- package/dist/web/assets/{docx-preview-C9XdKEj1.js → docx-preview-C2QqNGRE.js} +1 -1
- package/dist/web/assets/docx-preview-C2QqNGRE.js.br +0 -0
- package/dist/web/assets/docx-preview-C2QqNGRE.js.gz +0 -0
- package/dist/web/assets/editor-language-service-COqB2tuv.js +1 -0
- package/dist/web/assets/editor-language-service-COqB2tuv.js.br +3 -0
- package/dist/web/assets/editor-language-service-COqB2tuv.js.gz +0 -0
- package/dist/web/assets/explorer-body-DGrYajDN.js +2 -0
- package/dist/web/assets/explorer-body-DGrYajDN.js.br +0 -0
- package/dist/web/assets/explorer-body-DGrYajDN.js.gz +0 -0
- package/dist/web/assets/explorer-window-content-DLzkODTP.js +1 -0
- package/dist/web/assets/explorer-window-content-DLzkODTP.js.br +0 -0
- package/dist/web/assets/explorer-window-content-DLzkODTP.js.gz +0 -0
- package/dist/web/assets/{extension-manager-section-B2nZzJ2b.js → extension-manager-section-Bu0qcB2i.js} +1 -1
- package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.br +0 -0
- package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.gz +0 -0
- package/dist/web/assets/{extension-webview-BGoDxkdF.js → extension-webview-G_WJ0N52.js} +1 -1
- package/dist/web/assets/extension-webview-G_WJ0N52.js.br +0 -0
- package/dist/web/assets/extension-webview-G_WJ0N52.js.gz +0 -0
- package/dist/web/assets/{file-icons-gx_FBOXY.js → file-icons-l7fNOmdS.js} +1 -1
- package/dist/web/assets/file-icons-l7fNOmdS.js.br +0 -0
- package/dist/web/assets/file-icons-l7fNOmdS.js.gz +0 -0
- package/dist/web/assets/{file-store-D9KE0kQC.js → file-store-B0e7sLag.js} +1 -1
- package/dist/web/assets/file-store-B0e7sLag.js.br +0 -0
- package/dist/web/assets/file-store-B0e7sLag.js.gz +0 -0
- package/dist/web/assets/{files-settings-section-DC3OzzOl.js → files-settings-section-ChZ_CynX.js} +1 -1
- package/dist/web/assets/files-settings-section-ChZ_CynX.js.br +0 -0
- package/dist/web/assets/files-settings-section-ChZ_CynX.js.gz +0 -0
- package/dist/web/assets/format-bytes-__396eCN.js +1 -0
- package/dist/web/assets/{format-file-meta-mQwA6SuY.js → format-file-meta-o1XBuoKS.js} +1 -1
- package/dist/web/assets/format-file-meta-o1XBuoKS.js.br +0 -0
- package/dist/web/assets/format-file-meta-o1XBuoKS.js.gz +0 -0
- package/dist/web/assets/{fs-api-DL36slbd.js → fs-api-CeHKwx95.js} +1 -1
- package/dist/web/assets/fs-api-CeHKwx95.js.br +0 -0
- package/dist/web/assets/fs-api-CeHKwx95.js.gz +0 -0
- package/dist/web/assets/{general-settings-section-i41W43ER.js → general-settings-section-MSvDEbFa.js} +1 -1
- package/dist/web/assets/general-settings-section-MSvDEbFa.js.br +0 -0
- package/dist/web/assets/general-settings-section-MSvDEbFa.js.gz +0 -0
- package/dist/web/assets/{git-log-panel-DHzPIkJg.js → git-log-panel-gw5_a6j3.js} +1 -1
- package/dist/web/assets/git-log-panel-gw5_a6j3.js.br +0 -0
- package/dist/web/assets/git-log-panel-gw5_a6j3.js.gz +0 -0
- package/dist/web/assets/{git-repo-store-DSypNj19.js → git-repo-store-BpPnah5l.js} +1 -1
- package/dist/web/assets/git-repo-store-BpPnah5l.js.br +0 -0
- package/dist/web/assets/git-repo-store-BpPnah5l.js.gz +0 -0
- package/dist/web/assets/{glide-data-grid-Dj4vrDvj.js → glide-data-grid-Db2Cl26B.js} +5 -5
- package/dist/web/assets/glide-data-grid-Db2Cl26B.js.br +0 -0
- package/dist/web/assets/glide-data-grid-Db2Cl26B.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-B4etmYTR.js +1 -0
- package/dist/web/assets/group-chat-tab-B4etmYTR.js.br +0 -0
- package/dist/web/assets/group-chat-tab-B4etmYTR.js.gz +0 -0
- package/dist/web/assets/{image-preview-CGdZrmLo.js → image-preview-CjNhpfWw.js} +1 -1
- package/dist/web/assets/index-CtAvmybi.js +52 -0
- package/dist/web/assets/index-CtAvmybi.js.br +0 -0
- package/dist/web/assets/index-CtAvmybi.js.gz +0 -0
- package/dist/web/assets/index-DeCJasyy.css +1 -0
- package/dist/web/assets/index-DeCJasyy.css.br +0 -0
- package/dist/web/assets/index-DeCJasyy.css.gz +0 -0
- package/dist/web/assets/{jira-watcher-section-BJ9edGEP.js → jira-watcher-section-CKSI1Alo.js} +1 -1
- package/dist/web/assets/keybindings-store-C4_yyU4u.js +1 -0
- package/dist/web/assets/{keyboard-shortcuts-section-CxdGSNGr.js → keyboard-shortcuts-section-CEaVUc9a.js} +1 -1
- package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.gz +0 -0
- package/dist/web/assets/language-servers-section-ePtEpnDc.js +2 -0
- package/dist/web/assets/language-servers-section-ePtEpnDc.js.br +0 -0
- package/dist/web/assets/language-servers-section-ePtEpnDc.js.gz +0 -0
- package/dist/web/assets/lsp-client-XzmR3Brr.js +1 -0
- package/dist/web/assets/lsp-client-XzmR3Brr.js.br +0 -0
- package/dist/web/assets/lsp-client-XzmR3Brr.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-CTtDap-l.js +1 -0
- package/dist/web/assets/{markdown-renderer-ok96IgnS.js → markdown-renderer-D05fAr57.js} +2 -2
- package/dist/web/assets/markdown-renderer-D05fAr57.js.br +0 -0
- package/dist/web/assets/markdown-renderer-D05fAr57.js.gz +0 -0
- package/dist/web/assets/{media-url-CzUJrREv.js → media-url-C6NumuN5.js} +1 -1
- package/dist/web/assets/metric-chart-canvas-DHJe0VER.js +1 -0
- package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.br +0 -0
- package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.gz +0 -0
- package/dist/web/assets/{mobile-bottom-sheet-CuNi2FRv.js → mobile-bottom-sheet-D4UyOatB.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.br +0 -0
- package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.gz +0 -0
- package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js +1 -0
- package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.gz +0 -0
- package/dist/web/assets/{new-design-dialog-Drkjb_LI.js → new-design-dialog-BgmQopJM.js} +1 -1
- package/dist/web/assets/new-design-dialog-BgmQopJM.js.br +0 -0
- package/dist/web/assets/new-design-dialog-BgmQopJM.js.gz +0 -0
- package/dist/web/assets/notification-store-q5QBklKA.js +1 -0
- package/dist/web/assets/{notifications-settings-section-C05WYqcE.js → notifications-settings-section-BBJ0r9OS.js} +1 -1
- package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.br +0 -0
- package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.gz +0 -0
- package/dist/web/assets/{onboarding-entry-CmUqv1kl.js → onboarding-entry-BYOYswsi.js} +1 -1
- package/dist/web/assets/onboarding-entry-BYOYswsi.js.br +0 -0
- package/dist/web/assets/onboarding-entry-BYOYswsi.js.gz +0 -0
- package/dist/web/assets/{onboarding-quick-orientation-DIhWv1CN.js → onboarding-quick-orientation-DPHYFMbA.js} +1 -1
- package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.br +0 -0
- package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.gz +0 -0
- package/dist/web/assets/overview-panel-pkPs44Tv.js +1 -0
- package/dist/web/assets/overview-panel-pkPs44Tv.js.br +0 -0
- package/dist/web/assets/overview-panel-pkPs44Tv.js.gz +0 -0
- package/dist/web/assets/{pdf-preview-qdXmMkOR.js → pdf-preview-c-L_kDAs.js} +1 -1
- package/dist/web/assets/pdf-preview-c-L_kDAs.js.br +0 -0
- package/dist/web/assets/pdf-preview-c-L_kDAs.js.gz +0 -0
- package/dist/web/assets/performance-panel-yPrq0DJV.js +3 -0
- package/dist/web/assets/performance-panel-yPrq0DJV.js.br +0 -0
- package/dist/web/assets/performance-panel-yPrq0DJV.js.gz +0 -0
- package/dist/web/assets/{postgres-viewer-Xvlun_n5.js → postgres-viewer-CnwDCMNd.js} +1 -1
- package/dist/web/assets/postgres-viewer-CnwDCMNd.js.br +0 -0
- package/dist/web/assets/postgres-viewer-CnwDCMNd.js.gz +0 -0
- package/dist/web/assets/{ppmbot-settings-section-C8PFlvaq.js → ppmbot-settings-section-BDXoSIDp.js} +1 -1
- package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.gz +0 -0
- package/dist/web/assets/{pptx-export-CG6MRNok.js → pptx-export-D0RDY48h.js} +4 -4
- package/dist/web/assets/pptx-export-D0RDY48h.js.br +0 -0
- package/dist/web/assets/pptx-export-D0RDY48h.js.gz +0 -0
- package/dist/web/assets/{problems-panel-CFYO0Ro3.js → problems-panel-BgY8oyo9.js} +1 -1
- package/dist/web/assets/problems-panel-BgY8oyo9.js.br +0 -0
- package/dist/web/assets/problems-panel-BgY8oyo9.js.gz +0 -0
- package/dist/web/assets/process-row-format-CaaMcHzn.js +1 -0
- package/dist/web/assets/process-table-BOwDtXuG.js +1 -0
- package/dist/web/assets/process-table-BOwDtXuG.js.br +0 -0
- package/dist/web/assets/process-table-BOwDtXuG.js.gz +0 -0
- package/dist/web/assets/{project-framework-store-XxFXcUpb.js → project-framework-store-UDEMu28U.js} +1 -1
- package/dist/web/assets/{project-store-C5gJXkvb.js → project-store-DGa31y5B.js} +1 -1
- package/dist/web/assets/project-store-DGa31y5B.js.br +0 -0
- package/dist/web/assets/project-store-DGa31y5B.js.gz +0 -0
- package/dist/web/assets/{proxy-settings-section-BcHIEANE.js → proxy-settings-section-Db6Kc6xG.js} +1 -1
- package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.gz +0 -0
- package/dist/web/assets/{query-audit-section-UKG_smyt.js → query-audit-section-C0PAXhfT.js} +1 -1
- package/dist/web/assets/query-audit-section-C0PAXhfT.js.br +0 -0
- package/dist/web/assets/query-audit-section-C0PAXhfT.js.gz +0 -0
- package/dist/web/assets/{remote-desktop-clipboard-notice-BGsp0edA.js → remote-desktop-clipboard-notice-DOVtobj_.js} +1 -1
- package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js +1 -0
- package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.gz +0 -0
- package/dist/web/assets/{remote-desktop-readiness-gate-CsZCCRJI.js → remote-desktop-readiness-gate-BsfoJzdc.js} +1 -1
- package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.gz +0 -0
- package/dist/web/assets/{schedules-settings-section-Ci0O2Ng6.js → schedules-settings-section-CvbjQM8z.js} +1 -1
- package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.gz +0 -0
- package/dist/web/assets/{scroll-area-XonvWYn_.js → scroll-area-sjOeAfoD.js} +1 -1
- package/dist/web/assets/scroll-area-sjOeAfoD.js.br +0 -0
- package/dist/web/assets/scroll-area-sjOeAfoD.js.gz +0 -0
- package/dist/web/assets/{separator-sQj04Ari.js → separator-9A3PCG1t.js} +1 -1
- package/dist/web/assets/services-panel-CimW47P8.js +1 -0
- package/dist/web/assets/services-panel-CimW47P8.js.br +0 -0
- package/dist/web/assets/services-panel-CimW47P8.js.gz +0 -0
- package/dist/web/assets/settings-body-BTXNtpWL.js +2 -0
- package/dist/web/assets/settings-body-BTXNtpWL.js.br +0 -0
- package/dist/web/assets/settings-body-BTXNtpWL.js.gz +0 -0
- package/dist/web/assets/settings-store-DvftLqzy.js +2 -0
- package/dist/web/assets/settings-store-DvftLqzy.js.br +0 -0
- package/dist/web/assets/settings-store-DvftLqzy.js.gz +0 -0
- package/dist/web/assets/settings-tab-CGhaRXjs.js +1 -0
- package/dist/web/assets/settings-window-content--Uyg_Psr.js +1 -0
- package/dist/web/assets/sortable-header-DUW9T1Hz.js +1 -0
- package/dist/web/assets/sortable-header-DUW9T1Hz.js.br +0 -0
- package/dist/web/assets/sortable-header-DUW9T1Hz.js.gz +0 -0
- package/dist/web/assets/{sql-query-editor-4iCGE4h2.js → sql-query-editor-Dn-cgDrW.js} +1 -1
- package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.br +0 -0
- package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.gz +0 -0
- package/dist/web/assets/{sqlite-viewer-CK6DulYk.js → sqlite-viewer-B0NfaMjq.js} +1 -1
- package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.gz +0 -0
- package/dist/web/assets/system-monitor-body-CxCfRQFb.js +2 -0
- package/dist/web/assets/system-monitor-body-CxCfRQFb.js.br +0 -0
- package/dist/web/assets/system-monitor-body-CxCfRQFb.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-Cb3EZUdp.js +1 -0
- package/dist/web/assets/system-monitor-window-content-51CA-2PH.js +1 -0
- package/dist/web/assets/{tab-host-window-content-CWBaWKjA.js → tab-host-window-content-CSrcmKNG.js} +1 -1
- package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.gz +0 -0
- package/dist/web/assets/{team-member-sheet-Br6mrxrw.js → team-member-sheet-D4X6nh-x.js} +2 -2
- package/dist/web/assets/team-member-sheet-D4X6nh-x.js.br +0 -0
- package/dist/web/assets/team-member-sheet-D4X6nh-x.js.gz +0 -0
- package/dist/web/assets/{team-member-window-content-CwCy7ZWf.js → team-member-window-content-BxkbGVIL.js} +1 -1
- package/dist/web/assets/team-member-window-content-BxkbGVIL.js.br +0 -0
- package/dist/web/assets/team-member-window-content-BxkbGVIL.js.gz +0 -0
- package/dist/web/assets/{terminal-tab-BW14RpCb.js → terminal-tab-BYo34IqU.js} +3 -3
- package/dist/web/assets/terminal-tab-BYo34IqU.js.br +0 -0
- package/dist/web/assets/terminal-tab-BYo34IqU.js.gz +0 -0
- package/dist/web/assets/{tool-cards-CgOBEUnb.js → tool-cards-DvXjOped.js} +4 -4
- package/dist/web/assets/tool-cards-DvXjOped.js.br +0 -0
- package/dist/web/assets/tool-cards-DvXjOped.js.gz +0 -0
- package/dist/web/assets/{use-blob-url-CmavyEP8.js → use-blob-url-CISBWKG5.js} +1 -1
- package/dist/web/assets/use-inline-blame-Br6mheS4.js +16 -0
- package/dist/web/assets/use-inline-blame-Br6mheS4.js.br +0 -0
- package/dist/web/assets/use-inline-blame-Br6mheS4.js.gz +0 -0
- package/dist/web/assets/use-lsp-BpJmvQ0n.js +6 -0
- package/dist/web/assets/use-lsp-BpJmvQ0n.js.br +0 -0
- package/dist/web/assets/use-lsp-BpJmvQ0n.js.gz +0 -0
- package/dist/web/assets/{use-monaco-theme-rH6epJYA.js → use-monaco-theme-UGOzyIhv.js} +1 -1
- package/dist/web/assets/use-process-kill-CyiiUD1E.js +1 -0
- package/dist/web/assets/use-process-kill-CyiiUD1E.js.br +0 -0
- package/dist/web/assets/use-process-kill-CyiiUD1E.js.gz +0 -0
- package/dist/web/assets/{use-websocket-QwURkjpV.js → use-websocket-Dpl21cHG.js} +1 -1
- package/dist/web/assets/{vendor-ui-BHh12_0v.js → vendor-ui-P9Ym7hCv.js} +1 -1
- package/dist/web/assets/vendor-ui-P9Ym7hCv.js.br +0 -0
- package/dist/web/assets/vendor-ui-P9Ym7hCv.js.gz +0 -0
- package/dist/web/assets/video-preview-D6Jw-IZK.js +1 -0
- package/dist/web/assets/video-preview-D6Jw-IZK.js.br +0 -0
- package/dist/web/assets/video-preview-D6Jw-IZK.js.gz +0 -0
- package/dist/web/assets/voice-settings-section-CcHQDYzN.js +1 -0
- package/dist/web/assets/voice-settings-section-CcHQDYzN.js.br +0 -0
- package/dist/web/assets/voice-settings-section-CcHQDYzN.js.gz +0 -0
- package/dist/web/assets/ws-auth-CqI8-aoA.js +1 -0
- package/dist/web/index.html +20 -20
- package/dist/web/index.html.br +0 -0
- package/dist/web/index.html.gz +0 -0
- package/dist/web/sw.js +1 -1
- package/dist/web/sw.js.br +0 -0
- package/dist/web/sw.js.gz +0 -0
- package/docs/deployment-guide.md +23 -0
- package/package.json +1 -1
- package/release-from-worktree.sh +224 -0
- package/src/cli/commands/config-cmd.ts +12 -0
- package/src/providers/claude-agent-sdk.ts +65 -2
- package/src/providers/codex-app-server/codex-jsonrpc-client.ts +16 -1
- package/src/providers/codex-app-server/codex-provider.ts +39 -7
- package/src/providers/codex-app-server/codex-reset-credit.ts +49 -0
- package/src/providers/provider-probe.ts +63 -0
- package/src/providers/registry.ts +109 -29
- package/src/server/index.ts +9 -0
- package/src/server/middleware/auth.ts +5 -1
- package/src/server/routes/codex-accounts.ts +14 -0
- package/src/server/routes/cross-origin-guard.ts +20 -0
- package/src/server/routes/git.ts +40 -4
- package/src/server/routes/lsp.ts +97 -4
- package/src/server/routes/resources.ts +72 -9
- package/src/server/routes/settings.ts +19 -1
- package/src/server/routes/speech.ts +66 -0
- package/src/server/routes/system-services.ts +76 -0
- package/src/server/routes/tunnel.ts +33 -1
- package/src/server/ws/chat.ts +74 -3
- package/src/services/codex-account-login.ts +26 -2
- package/src/services/codex-reset-credit.service.ts +83 -0
- package/src/services/compaction-savings.ts +127 -0
- package/src/services/db.service.ts +123 -8
- package/src/services/edge-forwarder.ts +191 -191
- package/src/services/fs-ops/fs-ops-trash.service.ts +22 -9
- package/src/services/git-refs/for-each-ref.ts +118 -0
- package/src/services/git.service.ts +25 -2
- package/src/services/host-info/spawn-runner.ts +48 -4
- package/src/services/jsonl-transcript-parser.ts +7 -42
- package/src/services/lsp/lsp-install.ts +289 -0
- package/src/services/lsp/lsp-manager.ts +160 -29
- package/src/services/lsp/server-registry.ts +120 -4
- package/src/services/named-tunnel/named-tunnel-config.ts +8 -2
- package/src/services/named-tunnel/named-tunnel-setup.service.ts +4 -0
- package/src/services/read-lines.ts +54 -0
- package/src/services/speech-to-text/whisper-catalog.ts +142 -0
- package/src/services/speech-to-text/whisper-download.ts +113 -0
- package/src/services/speech-to-text/whisper-hallucinations.ts +51 -0
- package/src/services/speech-to-text/whisper-install.service.ts +247 -0
- package/src/services/speech-to-text/whisper-paths.ts +62 -0
- package/src/services/speech-to-text/whisper-transcribe.service.ts +117 -0
- package/src/services/supervisor.ts +94 -11
- package/src/services/system-metrics/cpu-details-linux.ts +252 -0
- package/src/services/system-metrics/cpu-memory-collector.ts +140 -18
- package/src/services/system-metrics/device-collector-linux.ts +31 -0
- package/src/services/system-metrics/device-collector-types.ts +40 -0
- package/src/services/system-metrics/disk-devices-linux.ts +156 -0
- package/src/services/system-metrics/disk-inventory-linux.ts +150 -0
- package/src/services/system-metrics/fans-linux.ts +51 -0
- package/src/services/system-metrics/gpu-api-versions.ts +120 -0
- package/src/services/system-metrics/gpu-devices-linux.ts +370 -0
- package/src/services/system-metrics/gpu-fdinfo-linux.ts +253 -0
- package/src/services/system-metrics/hardware-inventory.ts +50 -0
- package/src/services/system-metrics/linux-fs.ts +43 -0
- package/src/services/system-metrics/memory-darwin.ts +91 -0
- package/src/services/system-metrics/memory-linux.ts +156 -0
- package/src/services/system-metrics/net-devices-linux.ts +114 -0
- package/src/services/system-metrics/net-inventory-linux.ts +100 -0
- package/src/services/system-metrics/partitions-linux.ts +158 -0
- package/src/services/system-metrics/process-collector-linux.ts +58 -6
- package/src/services/system-metrics/process-collector-types.ts +8 -1
- package/src/services/system-metrics/process-details-darwin.ts +166 -0
- package/src/services/system-metrics/process-details-linux.ts +150 -0
- package/src/services/system-metrics/process-grouping.ts +2 -1
- package/src/services/system-metrics/process-rows-builder.ts +2 -0
- package/src/services/system-metrics/process-swap-linux.ts +37 -0
- package/src/services/system-metrics/signal-executor.ts +84 -0
- package/src/services/system-metrics/signal-request-handler.ts +92 -0
- package/src/services/system-metrics/system-metrics-platform.ts +30 -4
- package/src/services/system-metrics/system-metrics-tick.ts +73 -4
- package/src/services/system-metrics/system-metrics.service.ts +87 -2
- package/src/services/system-metrics/udev-db.ts +40 -0
- package/src/services/system-services/app-cgroup-linux.ts +115 -0
- package/src/services/system-services/app-icon-service.ts +31 -0
- package/src/services/system-services/app-icons-linux.ts +124 -0
- package/src/services/system-services/apps-linux.ts +174 -0
- package/src/services/system-services/desktop-entry.ts +103 -0
- package/src/services/system-services/service-guard.ts +124 -0
- package/src/services/system-services/systemd-collector.ts +203 -0
- package/src/services/system-services/systemd-parse.ts +162 -0
- package/src/services/windows-process-tree.ts +351 -351
- package/src/shared/prompt-cache-idle.ts +197 -0
- package/src/shared/turn-usage.ts +85 -1
- package/src/shared/usage-extra.ts +19 -0
- package/src/types/chat.ts +29 -0
- package/src/types/config.ts +14 -0
- package/src/types/git.ts +41 -0
- package/src/types/system-hardware.ts +137 -0
- package/src/types/system-metrics.ts +231 -2
- package/src/types/system-services.ts +73 -0
- package/src/web/components/branch-review/branch-review-tab.tsx +20 -20
- package/src/web/components/branch-review/branch-review-tree-row.tsx +1 -13
- package/src/web/components/chat/chat-tab.tsx +3 -0
- package/src/web/components/chat/codex-usage-panel.tsx +4 -0
- package/src/web/components/chat/compaction-divider.tsx +48 -0
- package/src/web/components/chat/idle-cache-notice.tsx +67 -0
- package/src/web/components/chat/message-input.tsx +48 -13
- package/src/web/components/chat/message-list.tsx +15 -0
- package/src/web/components/chat/prompt-cache-chip.tsx +74 -0
- package/src/web/components/editor/code-editor.tsx +1 -0
- package/src/web/components/editor/editor-language-service.tsx +11 -3
- package/src/web/components/editor/lsp-status.tsx +115 -13
- package/src/web/components/git/branch-picker.tsx +419 -0
- package/src/web/components/git/branch-select.tsx +34 -0
- package/src/web/components/git/create-worktree-dialog.tsx +17 -16
- package/src/web/components/git/git-repo-picker.tsx +28 -40
- package/src/web/components/layout/status-bar.tsx +42 -19
- package/src/web/components/settings/accounts/account-card.tsx +10 -2
- package/src/web/components/settings/accounts/account-usage-extras.tsx +3 -2
- package/src/web/components/settings/accounts/codex-accounts-section.tsx +3 -1
- package/src/web/components/settings/accounts/codex-reset-credit-button.tsx +120 -0
- package/src/web/components/settings/ai-settings-section.tsx +67 -3
- package/src/web/components/settings/appearance-settings-section.tsx +2 -28
- package/src/web/components/settings/language-servers-section.tsx +362 -0
- package/src/web/components/settings/settings-categories.ts +8 -3
- package/src/web/components/settings/settings-section-content.tsx +2 -0
- package/src/web/components/settings/voice-settings-section.tsx +283 -0
- package/src/web/components/system/apps/app-row.tsx +110 -0
- package/src/web/components/system/apps/app-rows.ts +140 -0
- package/src/web/components/system/apps/apps-panel.tsx +129 -0
- package/src/web/components/system/metric-chart-canvas.tsx +79 -3
- package/src/web/components/system/overview-cards/card-shell.tsx +54 -0
- package/src/web/components/system/overview-cards/cpu-card.tsx +11 -6
- package/src/web/components/system/overview-cards/disk-card.tsx +11 -6
- package/src/web/components/system/overview-cards/gpu-card.tsx +16 -6
- package/src/web/components/system/overview-cards/mem-card.tsx +11 -6
- package/src/web/components/system/overview-cards/net-card.tsx +11 -6
- package/src/web/components/system/overview-device-target.ts +69 -0
- package/src/web/components/system/overview-panel.tsx +15 -1
- package/src/web/components/system/performance/cpu-core-grid.tsx +74 -0
- package/src/web/components/system/performance/cpu-detail.tsx +220 -0
- package/src/web/components/system/performance/detail-parts.tsx +149 -0
- package/src/web/components/system/performance/device-list.ts +139 -0
- package/src/web/components/system/performance/disk-detail.tsx +64 -0
- package/src/web/components/system/performance/fans-detail.tsx +35 -0
- package/src/web/components/system/performance/gpu-detail.tsx +116 -0
- package/src/web/components/system/performance/memory-detail.tsx +109 -0
- package/src/web/components/system/performance/nic-detail.tsx +55 -0
- package/src/web/components/system/performance/partition-list.tsx +79 -0
- package/src/web/components/system/performance/performance-panel.tsx +206 -0
- package/src/web/components/system/performance/use-hardware-inventory.ts +48 -0
- package/src/web/components/system/process-columns-grid.ts +5 -3
- package/src/web/components/system/process-details-dialog.tsx +116 -0
- package/src/web/components/system/process-group-row.tsx +6 -1
- package/src/web/components/system/process-row-format.ts +6 -0
- package/src/web/components/system/process-row-menu.tsx +72 -0
- package/src/web/components/system/process-row.tsx +7 -1
- package/src/web/components/system/process-table-model.ts +1 -1
- package/src/web/components/system/process-table-sort.ts +8 -4
- package/src/web/components/system/process-table-toolbar.tsx +10 -2
- package/src/web/components/system/process-table-totals.ts +3 -0
- package/src/web/components/system/process-table.tsx +25 -2
- package/src/web/components/system/services/service-action-confirm.tsx +100 -0
- package/src/web/components/system/services/service-columns.ts +103 -0
- package/src/web/components/system/services/service-details-sheet.tsx +97 -0
- package/src/web/components/system/services/service-resources.ts +105 -0
- package/src/web/components/system/services/service-row.tsx +146 -0
- package/src/web/components/system/services/service-rows.ts +92 -0
- package/src/web/components/system/services/service-sort.ts +90 -0
- package/src/web/components/system/services/services-header.tsx +51 -0
- package/src/web/components/system/services/services-panel.tsx +207 -0
- package/src/web/components/system/services/use-services.ts +92 -0
- package/src/web/components/system/sortable-header.tsx +13 -8
- package/src/web/components/system/sysmon-preferences.tsx +85 -0
- package/src/web/components/system/system-monitor-body.tsx +101 -43
- package/src/web/components/system/system-monitor-window-content.tsx +2 -3
- package/src/web/components/system/use-process-signal.ts +87 -0
- package/src/web/components/tunnels/public-tunnel-switch.tsx +82 -0
- package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
- package/src/web/components/ui/dialog.tsx +14 -1
- package/src/web/components/ui/search-select.tsx +279 -0
- package/src/web/components/ui/start-ellipsis.tsx +18 -0
- package/src/web/hooks/use-chat.ts +28 -0
- package/src/web/hooks/use-global-keybindings.ts +7 -5
- package/src/web/hooks/use-lsp.ts +23 -2
- package/src/web/hooks/use-minute-clock.ts +20 -0
- package/src/web/hooks/use-whisper-voice-input.ts +113 -0
- package/src/web/lib/api-tunnels.ts +19 -0
- package/src/web/lib/branch-select-items.ts +29 -0
- package/src/web/lib/cpu-graph-mode.ts +90 -0
- package/src/web/lib/format-bytes.ts +14 -0
- package/src/web/lib/git-ref-picker.ts +120 -0
- package/src/web/lib/lsp/lsp-client.ts +32 -0
- package/src/web/lib/search-select-rows.ts +55 -0
- package/src/web/lib/temperature.ts +27 -0
- package/src/web/lib/voice-wav.ts +69 -0
- package/src/web/stores/git-status-store.ts +31 -17
- package/src/web/stores/keybindings-store.ts +14 -1
- package/src/web/stores/settings-store.ts +65 -0
- package/src/web/styles/globals.css +11 -0
- package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js +0 -1
- package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js.gz +0 -0
- package/dist/web/assets/ai-resource-editor-DKcsVDle.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-DKcsVDle.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-D7zJ-hCO.js +0 -1
- package/dist/web/assets/ai-settings-section-D7zJ-hCO.js.br +0 -0
- package/dist/web/assets/ai-settings-section-D7zJ-hCO.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-OPqC2bYG.js +0 -1
- package/dist/web/assets/api-client-BgedDTvo.js +0 -1
- package/dist/web/assets/api-client-c8YOpTlT.js.br +0 -0
- package/dist/web/assets/api-client-c8YOpTlT.js.gz +0 -0
- package/dist/web/assets/api-settings-BmvNoCbn.js.br +0 -0
- package/dist/web/assets/api-settings-BmvNoCbn.js.gz +0 -0
- package/dist/web/assets/api-settings-Bti1-Zn3.js +0 -1
- package/dist/web/assets/appearance-settings-section-DL466x83.js +0 -1
- package/dist/web/assets/appearance-settings-section-DL466x83.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-DL466x83.js.gz +0 -0
- package/dist/web/assets/audio-preview-vaG2cB-k.js.br +0 -0
- package/dist/web/assets/audio-preview-vaG2cB-k.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-Dag86n_R.js +0 -1
- package/dist/web/assets/branch-review-tab-Dag86n_R.js.br +0 -0
- package/dist/web/assets/branch-review-tab-Dag86n_R.js.gz +0 -0
- package/dist/web/assets/button-Ci9EUgqd.js.br +0 -0
- package/dist/web/assets/button-Ci9EUgqd.js.gz +0 -0
- package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.br +0 -0
- package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.gz +0 -0
- package/dist/web/assets/chat-tab-CcYZLXls.js +0 -15
- package/dist/web/assets/chat-tab-CcYZLXls.js.br +0 -0
- package/dist/web/assets/chat-tab-CcYZLXls.js.gz +0 -0
- package/dist/web/assets/chat-tab-QFDhzzBZ.js +0 -1
- package/dist/web/assets/chat-tab-QFDhzzBZ.js.br +0 -0
- package/dist/web/assets/chat-tab-QFDhzzBZ.js.gz +0 -0
- package/dist/web/assets/code-editor-K-IN8VwJ.js +0 -7
- package/dist/web/assets/code-editor-K-IN8VwJ.js.br +0 -0
- package/dist/web/assets/code-editor-K-IN8VwJ.js.gz +0 -0
- package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js +0 -1
- package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js.br +0 -0
- package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js.gz +0 -0
- package/dist/web/assets/conflict-editor-qMGJH0Bx.js.br +0 -0
- package/dist/web/assets/conflict-editor-qMGJH0Bx.js.gz +0 -0
- package/dist/web/assets/context-menu-CjYTq8DI.js +0 -1
- package/dist/web/assets/context-menu-CjYTq8DI.js.br +0 -0
- package/dist/web/assets/context-menu-CjYTq8DI.js.gz +0 -0
- package/dist/web/assets/csv-preview-D2I742dl.js.br +0 -0
- package/dist/web/assets/csv-preview-D2I742dl.js.gz +0 -0
- package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.br +0 -0
- package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.gz +0 -0
- package/dist/web/assets/database-viewer-Bz4LjgIa.js.br +0 -0
- package/dist/web/assets/database-viewer-Bz4LjgIa.js.gz +0 -0
- package/dist/web/assets/design-export-client-ChMcMoqW.js.br +0 -0
- package/dist/web/assets/design-export-client-ChMcMoqW.js.gz +0 -0
- package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.br +0 -0
- package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.gz +0 -0
- package/dist/web/assets/design-tab-C987MtMR.js +0 -33
- package/dist/web/assets/design-tab-C987MtMR.js.br +0 -0
- package/dist/web/assets/design-tab-C987MtMR.js.gz +0 -0
- package/dist/web/assets/designs-sidebar-panel-CapP1yXq.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-CapP1yXq.js.gz +0 -0
- package/dist/web/assets/dialog-B8clVkyi.js +0 -1
- package/dist/web/assets/dialog-B8clVkyi.js.br +0 -0
- package/dist/web/assets/dialog-B8clVkyi.js.gz +0 -0
- package/dist/web/assets/diff-viewer-CdXi7cZN.js.br +0 -0
- package/dist/web/assets/diff-viewer-CdXi7cZN.js.gz +0 -0
- package/dist/web/assets/docx-preview-C9XdKEj1.js.br +0 -0
- package/dist/web/assets/docx-preview-C9XdKEj1.js.gz +0 -0
- package/dist/web/assets/editor-language-service-Zle_PZV8.js +0 -1
- package/dist/web/assets/editor-language-service-Zle_PZV8.js.br +0 -0
- package/dist/web/assets/editor-language-service-Zle_PZV8.js.gz +0 -0
- package/dist/web/assets/explorer-body-DHMQR1Rk.js +0 -2
- package/dist/web/assets/explorer-body-DHMQR1Rk.js.br +0 -0
- package/dist/web/assets/explorer-body-DHMQR1Rk.js.gz +0 -0
- package/dist/web/assets/explorer-window-content-Df40nQBk.js +0 -1
- package/dist/web/assets/explorer-window-content-Df40nQBk.js.br +0 -0
- package/dist/web/assets/explorer-window-content-Df40nQBk.js.gz +0 -0
- package/dist/web/assets/extension-manager-section-B2nZzJ2b.js.br +0 -0
- package/dist/web/assets/extension-manager-section-B2nZzJ2b.js.gz +0 -0
- package/dist/web/assets/extension-webview-BGoDxkdF.js.br +0 -0
- package/dist/web/assets/extension-webview-BGoDxkdF.js.gz +0 -0
- package/dist/web/assets/file-icons-gx_FBOXY.js.br +0 -0
- package/dist/web/assets/file-icons-gx_FBOXY.js.gz +0 -0
- package/dist/web/assets/file-store-D9KE0kQC.js.br +0 -0
- package/dist/web/assets/file-store-D9KE0kQC.js.gz +0 -0
- package/dist/web/assets/files-settings-section-DC3OzzOl.js.br +0 -0
- package/dist/web/assets/files-settings-section-DC3OzzOl.js.gz +0 -0
- package/dist/web/assets/format-bytes-DmSHAKFe.js +0 -1
- package/dist/web/assets/format-file-meta-mQwA6SuY.js.br +0 -0
- package/dist/web/assets/format-file-meta-mQwA6SuY.js.gz +0 -0
- package/dist/web/assets/fs-api-DL36slbd.js.br +0 -0
- package/dist/web/assets/fs-api-DL36slbd.js.gz +0 -0
- package/dist/web/assets/general-settings-section-i41W43ER.js.br +0 -0
- package/dist/web/assets/general-settings-section-i41W43ER.js.gz +0 -0
- package/dist/web/assets/git-log-panel-DHzPIkJg.js.br +0 -0
- package/dist/web/assets/git-log-panel-DHzPIkJg.js.gz +0 -0
- package/dist/web/assets/git-repo-store-DSypNj19.js.br +0 -0
- package/dist/web/assets/git-repo-store-DSypNj19.js.gz +0 -0
- package/dist/web/assets/glide-data-grid-Dj4vrDvj.js.br +0 -0
- package/dist/web/assets/glide-data-grid-Dj4vrDvj.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-DfwZb-fI.js +0 -1
- package/dist/web/assets/group-chat-tab-DfwZb-fI.js.br +0 -0
- package/dist/web/assets/group-chat-tab-DfwZb-fI.js.gz +0 -0
- package/dist/web/assets/index-DMA-So69.css +0 -1
- package/dist/web/assets/index-DMA-So69.css.br +0 -0
- package/dist/web/assets/index-DMA-So69.css.gz +0 -0
- package/dist/web/assets/index-jG9mLs-J.js +0 -52
- package/dist/web/assets/index-jG9mLs-J.js.br +0 -0
- package/dist/web/assets/index-jG9mLs-J.js.gz +0 -0
- package/dist/web/assets/keybindings-store-BlapkC6O.js +0 -1
- package/dist/web/assets/keyboard-shortcuts-section-CxdGSNGr.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-CxdGSNGr.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-DJ9EVU1B.js +0 -1
- package/dist/web/assets/markdown-renderer-ok96IgnS.js.br +0 -0
- package/dist/web/assets/markdown-renderer-ok96IgnS.js.gz +0 -0
- package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.br +0 -0
- package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.gz +0 -0
- package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js.gz +0 -0
- package/dist/web/assets/new-design-dialog-Drkjb_LI.js.br +0 -0
- package/dist/web/assets/new-design-dialog-Drkjb_LI.js.gz +0 -0
- package/dist/web/assets/notification-store-DCyxho0O.js +0 -1
- package/dist/web/assets/notifications-settings-section-C05WYqcE.js.br +0 -0
- package/dist/web/assets/notifications-settings-section-C05WYqcE.js.gz +0 -0
- package/dist/web/assets/onboarding-entry-CmUqv1kl.js.br +0 -0
- package/dist/web/assets/onboarding-entry-CmUqv1kl.js.gz +0 -0
- package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.br +0 -0
- package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.gz +0 -0
- package/dist/web/assets/overview-panel-BZAW_nag.js +0 -1
- package/dist/web/assets/overview-panel-BZAW_nag.js.br +0 -0
- package/dist/web/assets/overview-panel-BZAW_nag.js.gz +0 -0
- package/dist/web/assets/pdf-preview-qdXmMkOR.js.br +0 -0
- package/dist/web/assets/pdf-preview-qdXmMkOR.js.gz +0 -0
- package/dist/web/assets/postgres-viewer-Xvlun_n5.js.br +0 -0
- package/dist/web/assets/postgres-viewer-Xvlun_n5.js.gz +0 -0
- package/dist/web/assets/ppmbot-settings-section-C8PFlvaq.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-C8PFlvaq.js.gz +0 -0
- package/dist/web/assets/pptx-export-CG6MRNok.js.br +0 -0
- package/dist/web/assets/pptx-export-CG6MRNok.js.gz +0 -0
- package/dist/web/assets/problems-panel-CFYO0Ro3.js.br +0 -0
- package/dist/web/assets/problems-panel-CFYO0Ro3.js.gz +0 -0
- package/dist/web/assets/process-table-BVeRguFg.js +0 -1
- package/dist/web/assets/process-table-BVeRguFg.js.br +0 -0
- package/dist/web/assets/process-table-BVeRguFg.js.gz +0 -0
- package/dist/web/assets/project-store-C5gJXkvb.js.br +0 -0
- package/dist/web/assets/project-store-C5gJXkvb.js.gz +0 -0
- package/dist/web/assets/proxy-settings-section-BcHIEANE.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-BcHIEANE.js.gz +0 -0
- package/dist/web/assets/query-audit-section-UKG_smyt.js.br +0 -0
- package/dist/web/assets/query-audit-section-UKG_smyt.js.gz +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-BGsp0edA.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-BGsp0edA.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js.gz +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-CsZCCRJI.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-CsZCCRJI.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js.gz +0 -0
- package/dist/web/assets/schedules-settings-section-Ci0O2Ng6.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-Ci0O2Ng6.js.gz +0 -0
- package/dist/web/assets/scroll-area-XonvWYn_.js.br +0 -0
- package/dist/web/assets/scroll-area-XonvWYn_.js.gz +0 -0
- package/dist/web/assets/settings-body-B6JGOIYb.js +0 -2
- package/dist/web/assets/settings-body-B6JGOIYb.js.br +0 -0
- package/dist/web/assets/settings-body-B6JGOIYb.js.gz +0 -0
- package/dist/web/assets/settings-store-Br5c1efC.js +0 -2
- package/dist/web/assets/settings-store-Br5c1efC.js.br +0 -0
- package/dist/web/assets/settings-store-Br5c1efC.js.gz +0 -0
- package/dist/web/assets/settings-tab-CIQM4fNE.js +0 -1
- package/dist/web/assets/settings-window-content-BGNNz-E5.js +0 -1
- package/dist/web/assets/sql-query-editor-4iCGE4h2.js.br +0 -3
- package/dist/web/assets/sql-query-editor-4iCGE4h2.js.gz +0 -0
- package/dist/web/assets/sqlite-viewer-CK6DulYk.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-CK6DulYk.js.gz +0 -0
- package/dist/web/assets/system-monitor-body-J9JtvAWV.js +0 -2
- package/dist/web/assets/system-monitor-body-J9JtvAWV.js.br +0 -0
- package/dist/web/assets/system-monitor-body-J9JtvAWV.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-DjBeRE81.js +0 -1
- package/dist/web/assets/system-monitor-window-content-BT7-ugFx.js +0 -1
- package/dist/web/assets/tab-host-window-content-CWBaWKjA.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-CWBaWKjA.js.gz +0 -0
- package/dist/web/assets/team-member-sheet-Br6mrxrw.js.br +0 -0
- package/dist/web/assets/team-member-sheet-Br6mrxrw.js.gz +0 -0
- package/dist/web/assets/team-member-window-content-CwCy7ZWf.js.br +0 -0
- package/dist/web/assets/team-member-window-content-CwCy7ZWf.js.gz +0 -0
- package/dist/web/assets/terminal-tab-BW14RpCb.js.br +0 -0
- package/dist/web/assets/terminal-tab-BW14RpCb.js.gz +0 -0
- package/dist/web/assets/tool-cards-CgOBEUnb.js.br +0 -0
- package/dist/web/assets/tool-cards-CgOBEUnb.js.gz +0 -0
- package/dist/web/assets/use-inline-blame-Bzjfru4n.js +0 -16
- package/dist/web/assets/use-inline-blame-Bzjfru4n.js.br +0 -0
- package/dist/web/assets/use-inline-blame-Bzjfru4n.js.gz +0 -0
- package/dist/web/assets/use-lsp-hGdjL2hV.js +0 -6
- package/dist/web/assets/use-lsp-hGdjL2hV.js.br +0 -0
- package/dist/web/assets/use-lsp-hGdjL2hV.js.gz +0 -0
- package/dist/web/assets/vendor-ui-BHh12_0v.js.br +0 -0
- package/dist/web/assets/vendor-ui-BHh12_0v.js.gz +0 -0
- package/dist/web/assets/video-preview-P9T-ZVdN.js +0 -1
- package/dist/web/assets/video-preview-P9T-ZVdN.js.br +0 -0
- package/dist/web/assets/video-preview-P9T-ZVdN.js.gz +0 -0
- package/dist/web/assets/ws-auth-kXgsX2Js.js +0 -1
- package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
- /package/dist/web/assets/{__vite-browser-external-BpSQWxcq.js → __vite-browser-external-BILfYaAs.js} +0 -0
- /package/dist/web/assets/{run-in-terminal-HIdNgYim.js → run-in-terminal-2pSiup8e.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-DLDtzLib.js → vendor-xterm-DF1JTfsy.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.br → vendor-xterm-DF1JTfsy.js.br} +0 -0
- /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.gz → vendor-xterm-DF1JTfsy.js.gz} +0 -0
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
SendMessageOpts,
|
|
10
10
|
UsageInfo,
|
|
11
11
|
} from "../provider.interface.ts";
|
|
12
|
+
import { stderrReason, type ProviderProbeResult } from "../provider-probe.ts";
|
|
12
13
|
import { configService } from "../../services/config.service.ts";
|
|
13
14
|
import { withSharedContext } from "../../shared/provider-context.ts";
|
|
14
15
|
import { setSessionMetadata, getSessionProjectPath, setSessionProvider, setSessionCodexAccount, getSessionCodexAccount, getSessionTitles, insertTurnUsage } from "../../services/db.service.ts";
|
|
@@ -33,7 +34,7 @@ import {
|
|
|
33
34
|
import { killProcessTree } from "../../services/windows-process-tree.ts";
|
|
34
35
|
import { homedir } from "node:os";
|
|
35
36
|
import { join } from "node:path";
|
|
36
|
-
import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS } from "./codex-jsonrpc-client.ts";
|
|
37
|
+
import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS, codexCommand } from "./codex-jsonrpc-client.ts";
|
|
37
38
|
import { permissionModeToCodex, type CodexPermission } from "./codex-permission-map.ts";
|
|
38
39
|
import { buildThreadParams, designMcpEnv, requestWithInstructionsFallback, type CodexThreadParams } from "./codex-thread-params.ts";
|
|
39
40
|
import type { DesignMcpAccess } from "../../services/design/mcp/design-mcp-tool.ts";
|
|
@@ -1243,22 +1244,53 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
1243
1244
|
}
|
|
1244
1245
|
|
|
1245
1246
|
// ── Capability probes ──
|
|
1246
|
-
|
|
1247
|
+
/**
|
|
1248
|
+
* Whether `bun x @openai/codex` runs here, and when it does not, why.
|
|
1249
|
+
*
|
|
1250
|
+
* The reason is the point: a failure is rarely "codex is not installed" —
|
|
1251
|
+
* bun fetches the package on demand — it is usually the manifest refresh
|
|
1252
|
+
* failing on a host whose network is not up yet. `retryable` is what tells
|
|
1253
|
+
* the registry to ask again instead of hiding the provider until the next
|
|
1254
|
+
* restart; only a missing bun is hopeless, since nothing can run without it.
|
|
1255
|
+
*/
|
|
1256
|
+
async probe(): Promise<ProviderProbeResult> {
|
|
1257
|
+
let cmd: string[];
|
|
1258
|
+
try {
|
|
1259
|
+
cmd = codexCommand("--version");
|
|
1260
|
+
} catch (e) {
|
|
1261
|
+
return { ok: false, reason: (e as Error).message, retryable: false };
|
|
1262
|
+
}
|
|
1247
1263
|
try {
|
|
1248
|
-
const proc = Bun.spawn(
|
|
1264
|
+
const proc = Bun.spawn(cmd, {
|
|
1249
1265
|
stdout: "pipe", stderr: "pipe",
|
|
1250
1266
|
});
|
|
1251
1267
|
// 30s: a cold `bun x` may download the package, and the probe runs during
|
|
1252
1268
|
// heavy concurrent server startup where process spawn can be starved.
|
|
1253
|
-
|
|
1269
|
+
let timedOut = false;
|
|
1270
|
+
const timeout = setTimeout(() => {
|
|
1271
|
+
timedOut = true;
|
|
1272
|
+
try { proc.kill(); } catch { /* ignore */ }
|
|
1273
|
+
}, 30_000);
|
|
1254
1274
|
await proc.exited;
|
|
1255
1275
|
clearTimeout(timeout);
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
return
|
|
1276
|
+
if (proc.exitCode === 0) return { ok: true };
|
|
1277
|
+
const stderr = timedOut ? "" : await new Response(proc.stderr).text();
|
|
1278
|
+
return {
|
|
1279
|
+
ok: false,
|
|
1280
|
+
retryable: true,
|
|
1281
|
+
reason: timedOut
|
|
1282
|
+
? "`bun x @openai/codex --version` timed out after 30s"
|
|
1283
|
+
: redactTruncate(stderrReason(stderr), 200) || `\`bun x @openai/codex --version\` exited ${proc.exitCode}`,
|
|
1284
|
+
};
|
|
1285
|
+
} catch (e) {
|
|
1286
|
+
return { ok: false, reason: (e as Error).message, retryable: true };
|
|
1259
1287
|
}
|
|
1260
1288
|
}
|
|
1261
1289
|
|
|
1290
|
+
async isAvailable(): Promise<boolean> {
|
|
1291
|
+
return (await this.probe()).ok;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1262
1294
|
async listModels(): Promise<ModelOption[]> {
|
|
1263
1295
|
if (this.modelsCache && Date.now() < this.modelsCache.expiry) return this.modelsCache.models;
|
|
1264
1296
|
if (!this.modelsPending) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spend one of Codex's free rate-limit resets, through the app-server's own
|
|
3
|
+
* `account/rateLimitResetCredit/consume` (codex ≥ 0.157).
|
|
4
|
+
*
|
|
5
|
+
* Deliberately thin: one short-lived app-server on the account's CODEX_HOME, one call, the
|
|
6
|
+
* outcome back. Whether a reset *should* be spent is decided by the caller
|
|
7
|
+
* (`codex-reset-credit.service.ts`), never here.
|
|
8
|
+
*/
|
|
9
|
+
import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS } from "./codex-jsonrpc-client.ts";
|
|
10
|
+
|
|
11
|
+
const CLIENT_INFO = { name: "ppm", title: "PPM", version: "0.0.0" };
|
|
12
|
+
const CAPABILITIES = { experimentalApi: true, requestAttestation: false, optOutNotificationMethods: null };
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* What Codex did. Straight from its protocol: `nothingToReset` means no window was refreshed and
|
|
16
|
+
* the credit is kept (OpenAI: "If there is nothing eligible to reset, the benefit remains
|
|
17
|
+
* available"); `alreadyRedeemed` answers a retry of an attempt that already went through.
|
|
18
|
+
*/
|
|
19
|
+
export type ResetCreditOutcome = "reset" | "nothingToReset" | "noCredit" | "alreadyRedeemed";
|
|
20
|
+
|
|
21
|
+
const OUTCOMES = new Set<ResetCreditOutcome>(["reset", "nothingToReset", "noCredit", "alreadyRedeemed"]);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param idempotencyKey one logical attempt; Codex treats a repeat of the same key as the same
|
|
25
|
+
* attempt, so a retried request cannot spend a second credit.
|
|
26
|
+
* @param creditId which credit to spend; omitted lets Codex pick the next available one.
|
|
27
|
+
*/
|
|
28
|
+
export async function consumeCodexResetCredit(
|
|
29
|
+
codexHome: string,
|
|
30
|
+
idempotencyKey: string,
|
|
31
|
+
creditId?: string,
|
|
32
|
+
): Promise<ResetCreditOutcome> {
|
|
33
|
+
const client = new CodexJsonRpcClient();
|
|
34
|
+
try {
|
|
35
|
+
client.start({ cwd: process.cwd(), codexHome });
|
|
36
|
+
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
37
|
+
client.notify("initialized");
|
|
38
|
+
const res = await client.request<{ outcome?: string }>(
|
|
39
|
+
"account/rateLimitResetCredit/consume",
|
|
40
|
+
{ idempotencyKey, ...(creditId ? { creditId } : {}) },
|
|
41
|
+
CONTROL_REQUEST_TIMEOUT_MS,
|
|
42
|
+
);
|
|
43
|
+
const outcome = res?.outcome as ResetCreditOutcome | undefined;
|
|
44
|
+
if (!outcome || !OUTCOMES.has(outcome)) throw new Error(`Codex answered the reset with an unknown outcome: ${String(res?.outcome)}`);
|
|
45
|
+
return outcome;
|
|
46
|
+
} finally {
|
|
47
|
+
client.close();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why a CLI provider is not registered, and whether asking again could change it.
|
|
3
|
+
*
|
|
4
|
+
* The probe that decides whether Codex exists is `bun x @openai/codex --version`,
|
|
5
|
+
* and bun re-fetches the npm manifest whenever its cached copy has gone stale —
|
|
6
|
+
* so a server restarting during a network blip probes a perfectly good install
|
|
7
|
+
* and is told `ConnectionRefused downloading package manifest @openai/codex`.
|
|
8
|
+
* Registration only ever happened at startup, so that one bad second hid Codex
|
|
9
|
+
* from the chat composer for the whole life of the process, with nothing but a
|
|
10
|
+
* log line to say why (the composer's provider chip is hidden while only one
|
|
11
|
+
* provider is registered, so the option does not even render greyed out).
|
|
12
|
+
*
|
|
13
|
+
* Everything except a missing bun is therefore `retryable`: with `bun x` there
|
|
14
|
+
* is no real "not installed" state — the package is fetched on demand — so a
|
|
15
|
+
* failure is almost always the network, not the host.
|
|
16
|
+
*/
|
|
17
|
+
export type ProviderProbeResult =
|
|
18
|
+
| { ok: true }
|
|
19
|
+
| { ok: false; reason: string; retryable: boolean };
|
|
20
|
+
|
|
21
|
+
/** What the last probe of a provider concluded — rendered in Settings → AI. */
|
|
22
|
+
export interface ProviderProbeStatus {
|
|
23
|
+
id: string;
|
|
24
|
+
registered: boolean;
|
|
25
|
+
/** Absent while registered. */
|
|
26
|
+
reason?: string;
|
|
27
|
+
/** Probes made so far in this process, successful or not. */
|
|
28
|
+
attempts: number;
|
|
29
|
+
lastProbeAt: string;
|
|
30
|
+
/** Absent when nothing is scheduled: registered, or a failure retrying cannot fix. */
|
|
31
|
+
nextProbeAt?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Backoff between probes: 30s, 1m, 2m, 5m, then every 15 minutes.
|
|
36
|
+
*
|
|
37
|
+
* It never gives up. The case this exists for is a host that starts PPM before
|
|
38
|
+
* its network is up and is not looked at again for hours — a bounded set of
|
|
39
|
+
* attempts puts that user back in front of the same silent gap. A warm probe is
|
|
40
|
+
* one ~20ms spawn against bun's cache, so the 15-minute ceiling costs nothing
|
|
41
|
+
* measurable, and it stops the moment the provider registers.
|
|
42
|
+
*/
|
|
43
|
+
const BACKOFF_MS = [30_000, 60_000, 120_000, 300_000, 900_000];
|
|
44
|
+
|
|
45
|
+
/** Delay before the next probe, given how many have already failed (1 = the first). */
|
|
46
|
+
export function nextProbeDelayMs(failedAttempts: number): number {
|
|
47
|
+
const index = Math.min(Math.max(failedAttempts, 1), BACKOFF_MS.length) - 1;
|
|
48
|
+
return BACKOFF_MS[index]!;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The one line of a failed probe's stderr worth showing a user.
|
|
53
|
+
*
|
|
54
|
+
* bun narrates its work before it fails: a cold `bun x` writes "Resolving
|
|
55
|
+
* dependencies" and "Resolved, downloaded and extracted [6]" ahead of
|
|
56
|
+
* `error: ConnectionRefused downloading package manifest @openai/codex`.
|
|
57
|
+
* Handing all three to a settings strip buries the only sentence that says
|
|
58
|
+
* what went wrong.
|
|
59
|
+
*/
|
|
60
|
+
export function stderrReason(stderr: string): string {
|
|
61
|
+
const lines = stderr.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
62
|
+
return lines.find((line) => line.toLowerCase().startsWith("error:")) ?? lines.at(-1) ?? "";
|
|
63
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { AIProvider } from "./provider.interface.ts";
|
|
|
2
2
|
import { MockProvider } from "./mock-provider.ts";
|
|
3
3
|
import { ClaudeAgentSdkProvider } from "./claude-agent-sdk.ts";
|
|
4
4
|
import { configService } from "../services/config.service.ts";
|
|
5
|
+
import { nextProbeDelayMs, type ProviderProbeStatus } from "./provider-probe.ts";
|
|
5
6
|
import { CODEX_DEFAULT_MODEL } from "../types/config.ts";
|
|
6
7
|
|
|
7
8
|
export interface ProviderInfo {
|
|
@@ -56,6 +57,10 @@ providerRegistry.register(new MockProvider()); // testing only
|
|
|
56
57
|
* Bootstrap CLI providers asynchronously.
|
|
57
58
|
* Checks isAvailable() before registering — call at server startup.
|
|
58
59
|
*
|
|
60
|
+
* Cursor's probe is a local `which`, so it answers the same at every restart.
|
|
61
|
+
* Codex's reaches the network, so its failure is retried rather than final —
|
|
62
|
+
* see probeCodexProvider() below.
|
|
63
|
+
*
|
|
59
64
|
* Persists provider entries with set() only, never save(): set() writes just the
|
|
60
65
|
* "ai" row, while save() rewrites every config key and re-syncs the projects
|
|
61
66
|
* table from this process's in-memory config. A caller that bootstraps without
|
|
@@ -87,36 +92,111 @@ export async function bootstrapProviders(): Promise<void> {
|
|
|
87
92
|
console.warn("[registry] Failed to load Cursor provider:", (e as Error).message);
|
|
88
93
|
}
|
|
89
94
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
95
|
+
await probeCodexProvider();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ── Codex availability: probed, remembered, and retried ──────────────────
|
|
99
|
+
|
|
100
|
+
const probeStatuses = new Map<string, ProviderProbeStatus>();
|
|
101
|
+
let codexRetryTimer: ReturnType<typeof setTimeout> | null = null;
|
|
102
|
+
let codexProbeInFlight: Promise<ProviderProbeStatus> | null = null;
|
|
103
|
+
|
|
104
|
+
/** What the last probe of each CLI provider concluded. Empty before bootstrap. */
|
|
105
|
+
export function providerProbeStatuses(): ProviderProbeStatus[] {
|
|
106
|
+
return Array.from(probeStatuses.values());
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Probe again now, ahead of whatever the backoff had scheduled (Settings' Retry). */
|
|
110
|
+
export function retryProviderProbe(id: string): Promise<ProviderProbeStatus> {
|
|
111
|
+
if (id !== "codex") throw new Error(`Provider "${id}" has no retryable probe`);
|
|
112
|
+
return probeCodexProvider();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Give codex a config entry, but only when it has never had one. An absent
|
|
117
|
+
* `model` is a real choice — the settings picker writes it for "Auto (default)",
|
|
118
|
+
* which hands model selection back to codex — so filling one in on every probe
|
|
119
|
+
* would undo that choice. Existing installs are given the default once, by
|
|
120
|
+
* migration.
|
|
121
|
+
*/
|
|
122
|
+
function ensureCodexConfigEntry(): void {
|
|
123
|
+
const ai = configService.get("ai");
|
|
124
|
+
if (ai.providers["codex"]) return;
|
|
125
|
+
configService.set("ai", {
|
|
126
|
+
...ai,
|
|
127
|
+
providers: {
|
|
128
|
+
...ai.providers,
|
|
129
|
+
codex: {
|
|
130
|
+
type: "cli",
|
|
131
|
+
cli_command: "codex",
|
|
132
|
+
permission_mode: "bypassPermissions",
|
|
133
|
+
model: CODEX_DEFAULT_MODEL,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Arm the next probe. The timer is unref'd so it never holds the process open. */
|
|
140
|
+
function scheduleCodexRetry(failedAttempts: number): string {
|
|
141
|
+
const delay = nextProbeDelayMs(failedAttempts);
|
|
142
|
+
codexRetryTimer = setTimeout(() => {
|
|
143
|
+
codexRetryTimer = null;
|
|
144
|
+
void probeCodexProvider();
|
|
145
|
+
}, delay);
|
|
146
|
+
codexRetryTimer.unref?.();
|
|
147
|
+
return new Date(Date.now() + delay).toISOString();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Probe codex and register it if it answers. On a retryable failure — which is
|
|
152
|
+
* nearly every failure, see `provider-probe.ts` — arm the next attempt instead
|
|
153
|
+
* of leaving the provider missing until someone restarts PPM.
|
|
154
|
+
*/
|
|
155
|
+
async function probeCodexProvider(): Promise<ProviderProbeStatus> {
|
|
156
|
+
// Probing again once it serves would put a fresh instance in the registry and
|
|
157
|
+
// orphan the live app-server clients the old one holds — every open codex
|
|
158
|
+
// session, and the cleanup handle the server shuts down through.
|
|
159
|
+
const current = probeStatuses.get("codex");
|
|
160
|
+
if (current?.registered) return current;
|
|
161
|
+
if (codexProbeInFlight) return codexProbeInFlight;
|
|
162
|
+
if (codexRetryTimer) {
|
|
163
|
+
clearTimeout(codexRetryTimer);
|
|
164
|
+
codexRetryTimer = null;
|
|
165
|
+
}
|
|
166
|
+
codexProbeInFlight = (async (): Promise<ProviderProbeStatus> => {
|
|
167
|
+
const attempts = (probeStatuses.get("codex")?.attempts ?? 0) + 1;
|
|
168
|
+
const lastProbeAt = new Date().toISOString();
|
|
169
|
+
let status: ProviderProbeStatus;
|
|
170
|
+
try {
|
|
171
|
+
const { CodexAppServerProvider } = await import("./codex-app-server/codex-provider.ts");
|
|
172
|
+
const codex = new CodexAppServerProvider();
|
|
173
|
+
const result = await codex.probe();
|
|
174
|
+
if (result.ok) {
|
|
175
|
+
providerRegistry.register(codex);
|
|
176
|
+
ensureCodexConfigEntry();
|
|
177
|
+
console.log("[registry] Codex provider registered (@openai/codex found)");
|
|
178
|
+
status = { id: "codex", registered: true, attempts, lastProbeAt };
|
|
179
|
+
} else {
|
|
180
|
+
status = { id: "codex", registered: false, attempts, lastProbeAt, reason: result.reason };
|
|
181
|
+
if (result.retryable) status.nextProbeAt = scheduleCodexRetry(attempts);
|
|
182
|
+
console.log(
|
|
183
|
+
`[registry] Codex provider unavailable: ${result.reason}` +
|
|
184
|
+
(status.nextProbeAt ? ` — retrying at ${status.nextProbeAt}` : ""),
|
|
185
|
+
);
|
|
114
186
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
187
|
+
} catch (e) {
|
|
188
|
+
// A broken import is a bug, not a flat host — but it is still worth
|
|
189
|
+
// retrying, since the alternative is silence until the next restart.
|
|
190
|
+
status = { id: "codex", registered: false, attempts, lastProbeAt, reason: (e as Error).message };
|
|
191
|
+
status.nextProbeAt = scheduleCodexRetry(attempts);
|
|
192
|
+
console.warn("[registry] Failed to load Codex provider:", (e as Error).message);
|
|
118
193
|
}
|
|
119
|
-
|
|
120
|
-
|
|
194
|
+
probeStatuses.set("codex", status);
|
|
195
|
+
return status;
|
|
196
|
+
})();
|
|
197
|
+
try {
|
|
198
|
+
return await codexProbeInFlight;
|
|
199
|
+
} finally {
|
|
200
|
+
codexProbeInFlight = null;
|
|
121
201
|
}
|
|
122
202
|
}
|
package/src/server/index.ts
CHANGED
|
@@ -218,7 +218,9 @@ app.route("/api/fs/sqlite", fsSqliteRoutes);
|
|
|
218
218
|
|
|
219
219
|
// System resource monitoring (SSE + JSON)
|
|
220
220
|
import { resourceRoutes } from "./routes/resources.ts";
|
|
221
|
+
import { systemServiceRoutes } from "./routes/system-services.ts";
|
|
221
222
|
app.route("/api/system", resourceRoutes);
|
|
223
|
+
app.route("/api/system", systemServiceRoutes);
|
|
222
224
|
|
|
223
225
|
// Host OS facts for the file explorer (platform, drives, known + pinned folders)
|
|
224
226
|
import { hostInfoRoutes } from "./routes/host-info.ts";
|
|
@@ -290,6 +292,13 @@ app.route("/api/upgrade", upgradeRoutes);
|
|
|
290
292
|
import { cloudRoutes } from "./routes/cloud.ts";
|
|
291
293
|
app.route("/api/cloud", cloudRoutes);
|
|
292
294
|
|
|
295
|
+
// Speech-to-text (Whisper on the host) for the chat mic
|
|
296
|
+
import { speechRoutes } from "./routes/speech.ts";
|
|
297
|
+
app.route("/api/speech", speechRoutes);
|
|
298
|
+
// Language servers, machine-wide (the Settings pane). The per-project half is project-scoped.
|
|
299
|
+
import { lspGlobalRoutes } from "./routes/lsp.ts";
|
|
300
|
+
app.route("/api/lsp", lspGlobalRoutes);
|
|
301
|
+
|
|
293
302
|
// Static files / SPA fallback (non-API routes)
|
|
294
303
|
app.route("/", staticRoutes);
|
|
295
304
|
|
|
@@ -30,7 +30,11 @@ export async function authMiddleware(c: Context, next: Next) {
|
|
|
30
30
|
if (c.req.method === "GET") {
|
|
31
31
|
const p = c.req.path;
|
|
32
32
|
const isMediaPath = p.endsWith("/files/raw") || p.endsWith("/files/transcode") || p === "/api/fs/raw" || p === "/api/fs/transcode";
|
|
33
|
-
|
|
33
|
+
// An <img> cannot send an Authorization header either. This one route is safe
|
|
34
|
+
// to widen to: it takes an APP ID, not a path, and answers only with the icon
|
|
35
|
+
// that app's own desktop entry already points at.
|
|
36
|
+
const isAppIcon = p.startsWith("/api/system/app-icon/");
|
|
37
|
+
if (p.endsWith("/stream") || isMediaPath || isAppIcon || p.endsWith("/image")) {
|
|
34
38
|
const queryToken = c.req.query("token");
|
|
35
39
|
if (queryToken && queryToken === authConfig.token) {
|
|
36
40
|
return next();
|
|
@@ -4,6 +4,7 @@ import { listCodexAccounts, removeCodexAccount, getAllCodexUsages, getCodexStrat
|
|
|
4
4
|
import { addApiKeyAccount, startDeviceLogin, getDeviceLoginStatus, cancelDeviceLogin, startBrowserLogin, submitBrowserCallback, getBrowserLoginStatus, cancelBrowserLogin } from "../../services/codex-account-login.ts";
|
|
5
5
|
import { exportCodexEncrypted, importCodexEncrypted } from "../../services/codex-account-portability.ts";
|
|
6
6
|
import { isCodexAccountAuthFailed } from "../../services/codex-account-auth-state.ts";
|
|
7
|
+
import { ResetCreditRefusedError, spendCodexResetCredit } from "../../services/codex-reset-credit.service.ts";
|
|
7
8
|
|
|
8
9
|
/** Codex multi-account management. Mounted under /api/codex-accounts (auth-guarded). */
|
|
9
10
|
export const codexAccountsRoutes = new Hono();
|
|
@@ -65,6 +66,19 @@ codexAccountsRoutes.patch("/:id", async (c) => {
|
|
|
65
66
|
return c.json(ok(updated));
|
|
66
67
|
});
|
|
67
68
|
|
|
69
|
+
/**
|
|
70
|
+
* POST /api/codex-accounts/:id/reset-credit — spend one free rate-limit reset.
|
|
71
|
+
* Refused with 409 unless a limit is reached right now (checked live) and a credit is left.
|
|
72
|
+
*/
|
|
73
|
+
codexAccountsRoutes.post("/:id/reset-credit", async (c) => {
|
|
74
|
+
try {
|
|
75
|
+
return c.json(ok(await spendCodexResetCredit(c.req.param("id"))));
|
|
76
|
+
} catch (e) {
|
|
77
|
+
if (e instanceof ResetCreditRefusedError) return c.json(err(e.message), e.status);
|
|
78
|
+
return c.json(err((e as Error).message), 502);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
68
82
|
/** Set the selection strategy. */
|
|
69
83
|
codexAccountsRoutes.put("/strategy", async (c) => {
|
|
70
84
|
const body = await c.req.json<{ strategy?: CodexStrategy }>().catch(() => ({} as { strategy?: CodexStrategy }));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The header pair every state-changing system route requires.
|
|
3
|
+
*
|
|
4
|
+
* PPM can be configured with auth disabled on a LAN, and a page on any other
|
|
5
|
+
* origin can submit an HTML form to this server. Such a form can set neither a
|
|
6
|
+
* JSON content type nor a custom header, so demanding BOTH forces a CORS
|
|
7
|
+
* preflight the browser will refuse to make on its behalf.
|
|
8
|
+
*
|
|
9
|
+
* One function, so the kill, signal and service-action routes cannot drift into
|
|
10
|
+
* three slightly different ideas of what a same-origin request looks like. A
|
|
11
|
+
* bodyless action still sends `{}` rather than being granted an exception here.
|
|
12
|
+
*/
|
|
13
|
+
import type { Context } from "hono";
|
|
14
|
+
|
|
15
|
+
export function crossOriginRefusal(c: Context): string | null {
|
|
16
|
+
const contentType = c.req.header("content-type") ?? "";
|
|
17
|
+
if (!contentType.toLowerCase().startsWith("application/json")) return "Content-Type must be application/json";
|
|
18
|
+
if (c.req.header("x-ppm-request") !== "1") return "Missing X-PPM-Request header";
|
|
19
|
+
return null;
|
|
20
|
+
}
|
package/src/server/routes/git.ts
CHANGED
|
@@ -4,9 +4,11 @@ import { gitService } from "../../services/git.service.ts";
|
|
|
4
4
|
import { gitHunksService, type HunkRequest, type HunkScope } from "../../services/git-hunks/git-hunks.service.ts";
|
|
5
5
|
import { assertSafeRev, gitBlameService } from "../../services/git-blame/git-blame.service.ts";
|
|
6
6
|
import { branchDiff } from "../../services/git-branch-diff/branch-diff.service.ts";
|
|
7
|
+
import { assertRef } from "../../services/git-branch-diff/branch-diff-parse.ts";
|
|
7
8
|
import { discoverGitRepos, isGitRepo } from "../../services/git-repos/git-repo-discovery.ts";
|
|
8
9
|
import { isInsideDir, realPathOrSelfSync } from "../../services/fs-ops/fs-real-path.ts";
|
|
9
10
|
import { ok, err } from "../../types/api.ts";
|
|
11
|
+
import type { CheckoutMode } from "../../types/git.ts";
|
|
10
12
|
|
|
11
13
|
type Env = { Variables: { projectPath: string; projectName: string } };
|
|
12
14
|
|
|
@@ -267,6 +269,22 @@ gitRoutes.get("/branches", async (c) => {
|
|
|
267
269
|
}
|
|
268
270
|
});
|
|
269
271
|
|
|
272
|
+
/**
|
|
273
|
+
* GET /git/refs — every checkout target the branch picker offers.
|
|
274
|
+
*
|
|
275
|
+
* Separate from `/branches` rather than an enrichment of it: this answer costs
|
|
276
|
+
* one `for-each-ref` over *three* namespaces and carries a commit per row,
|
|
277
|
+
* where `/branches` is the cheap list the graph and the review pickers read on
|
|
278
|
+
* mount.
|
|
279
|
+
*/
|
|
280
|
+
gitRoutes.get("/refs", async (c) => {
|
|
281
|
+
try {
|
|
282
|
+
return c.json(ok(await gitService.refs(c.get("projectPath"))));
|
|
283
|
+
} catch (e) {
|
|
284
|
+
return c.json(err((e as Error).message), 500);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
270
288
|
/** GET /git/pr-url?branch= */
|
|
271
289
|
gitRoutes.get("/pr-url", async (c) => {
|
|
272
290
|
try {
|
|
@@ -495,20 +513,38 @@ gitRoutes.post("/branch/create", async (c) => {
|
|
|
495
513
|
const projectPath = c.get("projectPath");
|
|
496
514
|
const { name, from } = await c.req.json<{ name: string; from?: string }>();
|
|
497
515
|
if (!name) return c.json(err("Missing: name"), 400);
|
|
498
|
-
|
|
516
|
+
// Both land as arguments of `git checkout -b`, so neither may open with a dash.
|
|
517
|
+
await gitService.createBranch(
|
|
518
|
+
projectPath,
|
|
519
|
+
assertRef(name, "name"),
|
|
520
|
+
from ? assertRef(from, "from") : undefined,
|
|
521
|
+
);
|
|
499
522
|
return c.json(ok({ created: name }));
|
|
500
523
|
} catch (e) {
|
|
501
524
|
return c.json(err((e as Error).message), 500);
|
|
502
525
|
}
|
|
503
526
|
});
|
|
504
527
|
|
|
505
|
-
/**
|
|
528
|
+
/**
|
|
529
|
+
* POST /git/checkout { ref, mode? }
|
|
530
|
+
*
|
|
531
|
+
* `mode` is `checkout` (the default), `detach` or `track` — see
|
|
532
|
+
* `GitService.checkout`. It is validated rather than passed through because it
|
|
533
|
+
* decides which flag precedes the ref, and `assertRef` is what stops the ref
|
|
534
|
+
* itself from *being* a flag: an unchecked `-f` here is a forced checkout that
|
|
535
|
+
* discards the working tree.
|
|
536
|
+
*/
|
|
537
|
+
const CHECKOUT_MODES = new Set<CheckoutMode>(["checkout", "detach", "track"]);
|
|
538
|
+
|
|
506
539
|
gitRoutes.post("/checkout", async (c) => {
|
|
507
540
|
try {
|
|
508
541
|
const projectPath = c.get("projectPath");
|
|
509
|
-
const { ref } = await c.req.json<{ ref: string }>();
|
|
542
|
+
const { ref, mode } = await c.req.json<{ ref: string; mode?: CheckoutMode }>();
|
|
510
543
|
if (!ref) return c.json(err("Missing: ref"), 400);
|
|
511
|
-
|
|
544
|
+
if (mode && !CHECKOUT_MODES.has(mode)) {
|
|
545
|
+
return c.json(err(`Unknown checkout mode: "${mode}"`), 400);
|
|
546
|
+
}
|
|
547
|
+
await gitService.checkout(projectPath, assertRef(ref, "ref"), mode);
|
|
512
548
|
return c.json(ok({ checkedOut: ref }));
|
|
513
549
|
} catch (e) {
|
|
514
550
|
return c.json(err((e as Error).message), 500);
|
package/src/server/routes/lsp.ts
CHANGED
|
@@ -6,13 +6,19 @@
|
|
|
6
6
|
* at all, which is indistinguishable from a broken feature unless something
|
|
7
7
|
* says so — hence the install hint travelling with the availability.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Installing is a POST, and nothing else here triggers one. A network install because a file
|
|
10
|
+
* was opened is not a thing an editor should do on the user's behalf; pressing Install is.
|
|
11
|
+
*
|
|
12
|
+
* There are two routers because there are two questions. The editor asks about *this project*
|
|
13
|
+
* — its `node_modules/.bin` counts, and a rustup component belongs in the toolchain that
|
|
14
|
+
* project selects. Settings asks about *this machine*, with no project open at all. They share
|
|
15
|
+
* the install handler, so neither can drift into accepting a package name.
|
|
11
16
|
*/
|
|
12
|
-
import { Hono } from "hono";
|
|
17
|
+
import { Hono, type Context } from "hono";
|
|
13
18
|
import { sep } from "node:path";
|
|
14
19
|
import { lspManager } from "../../services/lsp/lsp-manager.ts";
|
|
15
|
-
import {
|
|
20
|
+
import { installLanguageServer, lspInstallDir, uninstallLanguageServer } from "../../services/lsp/lsp-install.ts";
|
|
21
|
+
import { lspLanguageForPath, serverById, serversSharingInstall } from "../../services/lsp/server-registry.ts";
|
|
16
22
|
import { ok, err } from "../../types/api.ts";
|
|
17
23
|
|
|
18
24
|
type Env = { Variables: { projectPath: string; projectName: string } };
|
|
@@ -55,4 +61,91 @@ lspRoutes.get("/status", async (c) => {
|
|
|
55
61
|
}
|
|
56
62
|
});
|
|
57
63
|
|
|
64
|
+
/**
|
|
65
|
+
* POST /lsp/install — install the missing server, because someone pressed Install.
|
|
66
|
+
*
|
|
67
|
+
* The project, because `rustup component add` acts on the toolchain that directory selects.
|
|
68
|
+
*/
|
|
69
|
+
lspRoutes.post("/install", (c) => installServer(c, c.get("projectPath")));
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The machine-wide pair, for the Settings pane: `/api/lsp/*`.
|
|
73
|
+
*
|
|
74
|
+
* Settings is not open on a project, so there is no `node_modules/.bin` to consider and
|
|
75
|
+
* `rustup component add` lands in whichever toolchain PPM's own directory selects — the
|
|
76
|
+
* default one. That is the honest answer to "install rust-analyzer on this machine", and the
|
|
77
|
+
* pane says so; a project pinning its own toolchain still gets it from the editor's button.
|
|
78
|
+
*/
|
|
79
|
+
export const lspGlobalRoutes = new Hono();
|
|
80
|
+
|
|
81
|
+
/** GET /api/lsp/servers — every registered server, whether the machine has it, and where installs go. */
|
|
82
|
+
lspGlobalRoutes.get("/servers", async (c) => {
|
|
83
|
+
try {
|
|
84
|
+
return c.json(ok({
|
|
85
|
+
servers: await lspManager.availability(),
|
|
86
|
+
installDir: lspInstallDir(),
|
|
87
|
+
running: lspManager.running(),
|
|
88
|
+
}));
|
|
89
|
+
} catch (e) {
|
|
90
|
+
return c.json(err((e as Error).message), 500);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
lspGlobalRoutes.post("/install", (c) => installServer(c, undefined));
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* POST /api/lsp/uninstall — remove a server, from the Settings pane.
|
|
98
|
+
*
|
|
99
|
+
* Only here, and not on the editor's router: that dialog is only ever shown for a server that
|
|
100
|
+
* is *missing*, so it has nothing to remove. The gate is `removable`, which comes from where
|
|
101
|
+
* the server was found rather than from what the browser claims — a copy on `PATH` is the
|
|
102
|
+
* user's, and PPM has no business deleting it.
|
|
103
|
+
*/
|
|
104
|
+
lspGlobalRoutes.post("/uninstall", async (c) => {
|
|
105
|
+
const body = await c.req.json().catch(() => ({}) as Record<string, unknown>);
|
|
106
|
+
const definition = serverById(String(body.serverId ?? ""));
|
|
107
|
+
if (!definition) return c.json(err("No such language server"), 400);
|
|
108
|
+
|
|
109
|
+
const row = (await lspManager.availability()).find((s) => s.id === definition.id);
|
|
110
|
+
if (!row?.removable) {
|
|
111
|
+
return c.json(err(`PPM did not install ${definition.displayName}, so there is nothing for it to remove.`), 400);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
// The idle sessions first: the files are about to go, and on Windows a running binary
|
|
116
|
+
// cannot be unlinked at all. Every server the package serves, not just the row that was
|
|
117
|
+
// clicked — `vscode-langservers-extracted` is JSON, HTML and CSS, so removing the JSON
|
|
118
|
+
// row deletes files an open `.html` buffer is still running out of.
|
|
119
|
+
for (const id of new Set([definition.id, ...serversSharingInstall(definition).map((s) => s.id)])) {
|
|
120
|
+
await lspManager.stopIdle(id);
|
|
121
|
+
}
|
|
122
|
+
await uninstallLanguageServer(definition);
|
|
123
|
+
return c.json(ok({ id: definition.id, displayName: definition.displayName }));
|
|
124
|
+
} catch (e) {
|
|
125
|
+
return c.json(err((e as Error).message), 500);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The one install handler, shared by both routers.
|
|
131
|
+
*
|
|
132
|
+
* The body carries a server **id** and nothing else: the packages are the registry's, so no
|
|
133
|
+
* part of the command being run was chosen by the browser.
|
|
134
|
+
*/
|
|
135
|
+
async function installServer(c: Context, projectPath: string | undefined): Promise<Response> {
|
|
136
|
+
const body = await c.req.json().catch(() => ({}) as Record<string, unknown>);
|
|
137
|
+
const definition = serverById(String(body.serverId ?? ""));
|
|
138
|
+
if (!definition) return c.json(err("No such language server"), 400);
|
|
139
|
+
if (!definition.install) {
|
|
140
|
+
return c.json(err(`PPM cannot install ${definition.displayName}. Install it yourself: ${definition.installHint}`), 400);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
await installLanguageServer(definition, { projectPath });
|
|
145
|
+
return c.json(ok({ id: definition.id, displayName: definition.displayName }));
|
|
146
|
+
} catch (e) {
|
|
147
|
+
return c.json(err((e as Error).message), 500);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
58
151
|
export default lspRoutes;
|