@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
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What "install Whisper" downloads: one whisper.cpp build per platform, one
|
|
3
|
+
* speech model, and the VAD model that goes with every model.
|
|
4
|
+
*
|
|
5
|
+
* Pure and parameterised so the whole matrix is unit-testable without touching
|
|
6
|
+
* `process.*` or the network. Every entry is pinned by tag/revision AND by
|
|
7
|
+
* SHA-256, because this code downloads an executable onto the user's machine.
|
|
8
|
+
*
|
|
9
|
+
* The VAD model is not optional. Whisper invents speech out of silence, and in
|
|
10
|
+
* Vietnamese it invents the same YouTube outro every time — six seconds of
|
|
11
|
+
* digital silence transcribed as "Hãy subscribe cho kênh Ghiền Mì Gõ Để không
|
|
12
|
+
* bỏ lỡ những video hấp dẫn" on both `small` and `large-v3-turbo`, and pink
|
|
13
|
+
* noise as "Cảm ơn các bạn đã theo dõi và hẹn gặp lại." With Silero VAD in
|
|
14
|
+
* front, both come back empty (and in 0.3s instead of seconds).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** whisper.cpp release that the prebuilt binaries come from. */
|
|
18
|
+
export const WHISPER_BUILD = "b5130";
|
|
19
|
+
/** Whisper version inside that build, for display only. */
|
|
20
|
+
export const WHISPER_VERSION = "1.9.4";
|
|
21
|
+
|
|
22
|
+
const RELEASE_BASE = `https://github.com/ggml-org/whisper.cpp/releases/download/${WHISPER_BUILD}`;
|
|
23
|
+
|
|
24
|
+
/** Pinned commits of the Hugging Face repos the models are fetched from. */
|
|
25
|
+
const MODEL_REPO_REV = "5359861c739e955e79d9a303bcbc70fb988958b1";
|
|
26
|
+
const VAD_REPO_REV = "9ffd54a1e1ee413ddf265af9913beaf518d1639b";
|
|
27
|
+
|
|
28
|
+
export interface WhisperAsset {
|
|
29
|
+
/** Archive file name as published in the release. */
|
|
30
|
+
file: string;
|
|
31
|
+
url: string;
|
|
32
|
+
sha256: string;
|
|
33
|
+
ext: "tar.gz" | "zip";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Prebuilt whisper.cpp per platform.
|
|
38
|
+
*
|
|
39
|
+
* macOS is deliberately absent: the release ships an xcframework (a library for
|
|
40
|
+
* Swift apps), never a `whisper-cli`, so there is nothing to download and
|
|
41
|
+
* unpack. A Mac uses Homebrew's `whisper.cpp` formula instead — see
|
|
42
|
+
* `MACOS_INSTALL_HINT` — and PPM then finds `whisper-cli` on PATH.
|
|
43
|
+
*/
|
|
44
|
+
const ASSETS: Record<string, WhisperAsset> = {
|
|
45
|
+
"linux-x64": {
|
|
46
|
+
file: "whisper-bin-ubuntu-x64.tar.gz",
|
|
47
|
+
url: `${RELEASE_BASE}/whisper-bin-ubuntu-x64.tar.gz`,
|
|
48
|
+
sha256: "53e7fd8b5764edad916b8848dd0af6abb1ff1d3b86c899e79c78652412536c32",
|
|
49
|
+
ext: "tar.gz",
|
|
50
|
+
},
|
|
51
|
+
"linux-arm64": {
|
|
52
|
+
file: "whisper-bin-ubuntu-arm64.tar.gz",
|
|
53
|
+
url: `${RELEASE_BASE}/whisper-bin-ubuntu-arm64.tar.gz`,
|
|
54
|
+
sha256: "93532a0e3777f26f041ffa358ee77dd88b1a33a86847c1990745327ff335a5d6",
|
|
55
|
+
ext: "tar.gz",
|
|
56
|
+
},
|
|
57
|
+
"win32-x64": {
|
|
58
|
+
file: "whisper-bin-x64.zip",
|
|
59
|
+
url: `${RELEASE_BASE}/whisper-bin-x64.zip`,
|
|
60
|
+
sha256: "f9ec6c52a2e949b62ab51fa21d0d497958f9e41c3010c157c4e42932d5316f3c",
|
|
61
|
+
ext: "zip",
|
|
62
|
+
},
|
|
63
|
+
"win32-arm64": {
|
|
64
|
+
file: "whisper-bin-win-cpu-arm64.zip",
|
|
65
|
+
url: `${RELEASE_BASE}/whisper-bin-win-cpu-arm64.zip`,
|
|
66
|
+
sha256: "799543b926ab5b6c2d60cab269a2092e0ae8d27820e9e15429e59de3699546fc",
|
|
67
|
+
ext: "zip",
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const MACOS_INSTALL_HINT = "brew install whisper.cpp";
|
|
72
|
+
|
|
73
|
+
/** The published build for a platform/arch pair, or null when there is none. */
|
|
74
|
+
export function whisperAssetFor(platform: NodeJS.Platform, arch: string): WhisperAsset | null {
|
|
75
|
+
return ASSETS[`${platform}-${arch}`] ?? null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface WhisperModel {
|
|
79
|
+
id: string;
|
|
80
|
+
/** File name in the Hugging Face repo, and on disk. */
|
|
81
|
+
file: string;
|
|
82
|
+
label: string;
|
|
83
|
+
/** One line under the label in Settings. */
|
|
84
|
+
note: string;
|
|
85
|
+
bytes: number;
|
|
86
|
+
sha256: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Three rungs, measured on a 10s Vietnamese clip (i9-12900K, 16 threads):
|
|
91
|
+
* `base` 0.9s but "sửa giúp" came back "sửa dụp"; `small` 2.2s and readable;
|
|
92
|
+
* `large-v3-turbo` 5.5s and the only one that kept English identifiers
|
|
93
|
+
* ("handle ... toggle ... message input") intact. Quantized weights, since a
|
|
94
|
+
* q5 file is a third of the size for no accuracy difference anyone dictating a
|
|
95
|
+
* chat message would notice.
|
|
96
|
+
*/
|
|
97
|
+
export const WHISPER_MODELS: WhisperModel[] = [
|
|
98
|
+
{
|
|
99
|
+
id: "base-q5_1",
|
|
100
|
+
file: "ggml-base-q5_1.bin",
|
|
101
|
+
label: "Base",
|
|
102
|
+
note: "Fastest, weakest — usable for English, rough in Vietnamese",
|
|
103
|
+
bytes: 59_707_625,
|
|
104
|
+
sha256: "422f1ae452ade6f30a004d7e5c6a43195e4433bc370bf23fac9cc591f01a8898",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: "small-q5_1",
|
|
108
|
+
file: "ggml-small-q5_1.bin",
|
|
109
|
+
label: "Small",
|
|
110
|
+
note: "Middle ground — readable Vietnamese, garbles English words",
|
|
111
|
+
bytes: 190_085_487,
|
|
112
|
+
sha256: "ae85e4a935d7a567bd102fe55afc16bb595bdb618e11b2fc7591bc08120411bb",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: "large-v3-turbo-q5_0",
|
|
116
|
+
file: "ggml-large-v3-turbo-q5_0.bin",
|
|
117
|
+
label: "Large v3 Turbo",
|
|
118
|
+
note: "Best Vietnamese, keeps English terms — a few seconds per sentence",
|
|
119
|
+
bytes: 574_041_195,
|
|
120
|
+
sha256: "394221709cd5ad1f40c46e6031ca61bce88931e6e088c188294c6d5a55ffa7e2",
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
export const DEFAULT_MODEL_ID = "large-v3-turbo-q5_0";
|
|
125
|
+
|
|
126
|
+
export const VAD_MODEL = {
|
|
127
|
+
file: "ggml-silero-v5.1.2.bin",
|
|
128
|
+
bytes: 885_098,
|
|
129
|
+
sha256: "29940d98d42b91fbd05ce489f3ecf7c72f0a42f027e4875919a28fb4c04ea2cf",
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export function modelById(id: string): WhisperModel | null {
|
|
133
|
+
return WHISPER_MODELS.find((m) => m.id === id) ?? null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function modelUrl(model: WhisperModel): string {
|
|
137
|
+
return `https://huggingface.co/ggerganov/whisper.cpp/resolve/${MODEL_REPO_REV}/${model.file}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function vadModelUrl(): string {
|
|
141
|
+
return `https://huggingface.co/ggml-org/whisper-vad/resolve/${VAD_REPO_REV}/${VAD_MODEL.file}`;
|
|
142
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming download with a SHA-256 gate.
|
|
3
|
+
*
|
|
4
|
+
* A model is 574 MB, so it is hashed while it streams rather than read back
|
|
5
|
+
* afterwards, and it lands on a `.part` file that is only renamed once the hash
|
|
6
|
+
* matches: an interrupted or tampered download can never be mistaken for an
|
|
7
|
+
* installed one, and a retry starts clean.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import { mkdirSync, renameSync, rmSync } from "node:fs";
|
|
11
|
+
import { dirname } from "node:path";
|
|
12
|
+
|
|
13
|
+
export type FetchFn = typeof fetch;
|
|
14
|
+
|
|
15
|
+
export interface DownloadOptions {
|
|
16
|
+
url: string;
|
|
17
|
+
dest: string;
|
|
18
|
+
/** Lowercase hex. The download is discarded when the bytes hash to anything else. */
|
|
19
|
+
sha256: string;
|
|
20
|
+
/** Called as bytes arrive; `total` is 0 when the server sends no Content-Length. */
|
|
21
|
+
onProgress?: (received: number, total: number) => void;
|
|
22
|
+
fetchFn?: FetchFn;
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* How long the transfer may produce no bytes at all before it is abandoned.
|
|
28
|
+
*
|
|
29
|
+
* Idle rather than wall-clock: the largest model here is 574 MB, and any total-time
|
|
30
|
+
* bound that a slow line can exceed would abort a download that was working. What is
|
|
31
|
+
* never legitimate is silence — a half-open socket after a dropped wifi link or a
|
|
32
|
+
* tunnel that went away never errors and never yields, so without this the `for await`
|
|
33
|
+
* below simply never returns and the install never settles.
|
|
34
|
+
*/
|
|
35
|
+
const STALL_TIMEOUT_MS = 60_000;
|
|
36
|
+
|
|
37
|
+
export async function downloadVerified(opts: DownloadOptions): Promise<void> {
|
|
38
|
+
const { url, dest, sha256, onProgress, signal } = opts;
|
|
39
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
40
|
+
const part = `${dest}.part`;
|
|
41
|
+
|
|
42
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
43
|
+
rmSync(part, { force: true });
|
|
44
|
+
|
|
45
|
+
// The caller's signal and the stall timer both have to reach the body stream, and
|
|
46
|
+
// `fetch` takes one signal — so an internal controller carries both.
|
|
47
|
+
const stall = new AbortController();
|
|
48
|
+
const forwardAbort = () => stall.abort(signal?.reason);
|
|
49
|
+
signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
50
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
51
|
+
const armStallTimer = (): void => {
|
|
52
|
+
if (timer) clearTimeout(timer);
|
|
53
|
+
timer = setTimeout(
|
|
54
|
+
() => stall.abort(new Error(`download stalled: no bytes for ${STALL_TIMEOUT_MS}ms (${url})`)),
|
|
55
|
+
STALL_TIMEOUT_MS,
|
|
56
|
+
);
|
|
57
|
+
timer.unref?.();
|
|
58
|
+
};
|
|
59
|
+
const disarm = (): void => {
|
|
60
|
+
if (timer) clearTimeout(timer);
|
|
61
|
+
timer = null;
|
|
62
|
+
signal?.removeEventListener("abort", forwardAbort);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
let res: Response;
|
|
66
|
+
armStallTimer();
|
|
67
|
+
try {
|
|
68
|
+
res = await fetchFn(url, { redirect: "follow", signal: stall.signal });
|
|
69
|
+
} catch (e) {
|
|
70
|
+
disarm();
|
|
71
|
+
throw stall.signal.aborted && stall.signal.reason instanceof Error ? stall.signal.reason : e;
|
|
72
|
+
}
|
|
73
|
+
if (!res.ok) { disarm(); throw new Error(`download failed: HTTP ${res.status} (${url})`); }
|
|
74
|
+
if (!res.body) { disarm(); throw new Error(`download failed: empty body (${url})`); }
|
|
75
|
+
|
|
76
|
+
const total = Number(res.headers.get("content-length") ?? 0) || 0;
|
|
77
|
+
const hash = createHash("sha256");
|
|
78
|
+
const sink = Bun.file(part).writer();
|
|
79
|
+
let received = 0;
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
for await (const chunk of res.body as unknown as AsyncIterable<Uint8Array>) {
|
|
83
|
+
armStallTimer();
|
|
84
|
+
hash.update(chunk);
|
|
85
|
+
sink.write(chunk);
|
|
86
|
+
received += chunk.byteLength;
|
|
87
|
+
onProgress?.(received, total);
|
|
88
|
+
}
|
|
89
|
+
await sink.end();
|
|
90
|
+
disarm();
|
|
91
|
+
} catch (e) {
|
|
92
|
+
disarm();
|
|
93
|
+
try {
|
|
94
|
+
await sink.end();
|
|
95
|
+
} catch {
|
|
96
|
+
// Sink already torn down by the failure itself.
|
|
97
|
+
}
|
|
98
|
+
rmSync(part, { force: true });
|
|
99
|
+
// An abort raised by the stall timer carries the reason worth reporting; the
|
|
100
|
+
// stream's own `AbortError` says only that somebody cancelled.
|
|
101
|
+
throw stall.signal.aborted && stall.signal.reason instanceof Error ? stall.signal.reason : e;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const actual = hash.digest("hex");
|
|
105
|
+
if (actual !== sha256.toLowerCase()) {
|
|
106
|
+
rmSync(part, { force: true });
|
|
107
|
+
throw new Error(`checksum mismatch for ${url}: expected ${sha256}, got ${actual}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Windows refuses a rename onto an existing file, so clear the target first.
|
|
111
|
+
rmSync(dest, { force: true });
|
|
112
|
+
renameSync(part, dest);
|
|
113
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentences Whisper invents when it is handed audio with no speech in it.
|
|
3
|
+
*
|
|
4
|
+
* The model was trained on YouTube subtitles, so the likeliest continuation of
|
|
5
|
+
* "a Vietnamese clip with nothing being said" is that channel's sign-off — and
|
|
6
|
+
* it is not a rare edge case: with `--vad` off, *every* non-speech clip
|
|
7
|
+
* measured on large-v3-turbo (digital silence, white noise at four levels,
|
|
8
|
+
* 50 Hz hum, a 440 Hz tone, brown noise, keyboard clicks, a cough, a breath)
|
|
9
|
+
* came back as the same one sentence, byte for byte:
|
|
10
|
+
*
|
|
11
|
+
* silence/noise/hum/tone/typing/cough → "Hãy subscribe cho kênh Ghiền Mì
|
|
12
|
+
* Gõ Để không bỏ lỡ những video hấp dẫn"
|
|
13
|
+
* room tone → "Cảm ơn các bạn đã theo dõi và hẹn gặp lại."
|
|
14
|
+
*
|
|
15
|
+
* The VAD model is what normally stops this (those same clips come back empty
|
|
16
|
+
* with it on), so this list is the second line of defence for the audio VAD
|
|
17
|
+
* does let through — a fan, a distant TV, a word spoken too far from the mic.
|
|
18
|
+
* It is deliberately short and measured rather than guessed: add a sentence
|
|
19
|
+
* here only after seeing this model produce it from a clip with no speech.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** Same shape as the list: lowercased, punctuation dropped, spaces collapsed. */
|
|
23
|
+
function normalize(line: string): string {
|
|
24
|
+
return line
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
.replace(/[.,!?;:"'`*\-_()[\]…]/g, " ")
|
|
27
|
+
.replace(/\s+/g, " ")
|
|
28
|
+
.trim();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const INVENTED = [
|
|
32
|
+
"Hãy subscribe cho kênh Ghiền Mì Gõ Để không bỏ lỡ những video hấp dẫn",
|
|
33
|
+
"Cảm ơn các bạn đã theo dõi và hẹn gặp lại.",
|
|
34
|
+
].map(normalize);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The channel name is the fingerprint: the sign-off comes back with small
|
|
38
|
+
* wording changes, and nobody dictating into a chat box says it at all.
|
|
39
|
+
*/
|
|
40
|
+
const FINGERPRINT = normalize("Ghiền Mì Gõ");
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* True for a whole segment the model made up. Whole lines only — `-nt` prints
|
|
44
|
+
* one line per segment, so dropping a line drops exactly the invented
|
|
45
|
+
* sentence and leaves the real ones either side of it alone.
|
|
46
|
+
*/
|
|
47
|
+
export function isInventedLine(line: string): boolean {
|
|
48
|
+
const normalized = normalize(line);
|
|
49
|
+
if (normalized.length === 0) return false;
|
|
50
|
+
return INVENTED.includes(normalized) || normalized.includes(FINGERPRINT);
|
|
51
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installing Whisper on the host: download the prebuilt whisper.cpp for this
|
|
3
|
+
* platform, the chosen speech model, and the VAD model, then prove the binary
|
|
4
|
+
* actually runs here.
|
|
5
|
+
*
|
|
6
|
+
* That last step is not ceremony. The published Linux build needs glibc 2.34
|
|
7
|
+
* and libstdc++ from GCC 11, so on an older host (Ubuntu 20.04 ships glibc
|
|
8
|
+
* 2.31) every file downloads fine and the binary only fails when someone first
|
|
9
|
+
* speaks into the chat box. Running `--help` once at install time turns that
|
|
10
|
+
* into an install error naming the cause.
|
|
11
|
+
*
|
|
12
|
+
* One model is kept on disk at a time: they are 60–574 MB, and "which one is
|
|
13
|
+
* active" then has no state to drift — it is whichever file is there.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, mkdirSync, readdirSync, rmSync } from "node:fs";
|
|
16
|
+
import { resolve } from "node:path";
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_MODEL_ID,
|
|
19
|
+
MACOS_INSTALL_HINT,
|
|
20
|
+
VAD_MODEL,
|
|
21
|
+
WHISPER_MODELS,
|
|
22
|
+
WHISPER_VERSION,
|
|
23
|
+
modelById,
|
|
24
|
+
modelUrl,
|
|
25
|
+
vadModelUrl,
|
|
26
|
+
whisperAssetFor,
|
|
27
|
+
type WhisperAsset,
|
|
28
|
+
} from "./whisper-catalog.ts";
|
|
29
|
+
import { downloadVerified, type FetchFn } from "./whisper-download.ts";
|
|
30
|
+
import {
|
|
31
|
+
findWhisperBinary,
|
|
32
|
+
whisperBinDir,
|
|
33
|
+
whisperDir,
|
|
34
|
+
whisperModelDir,
|
|
35
|
+
whisperTmpDir,
|
|
36
|
+
type WhisperBinary,
|
|
37
|
+
} from "./whisper-paths.ts";
|
|
38
|
+
|
|
39
|
+
export type InstallPhase = "binary" | "model" | "vad" | "verify";
|
|
40
|
+
|
|
41
|
+
export interface InstallJobState {
|
|
42
|
+
modelId: string;
|
|
43
|
+
phase: InstallPhase;
|
|
44
|
+
receivedBytes: number;
|
|
45
|
+
totalBytes: number;
|
|
46
|
+
done: boolean;
|
|
47
|
+
error: string | null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface WhisperStatusModel {
|
|
51
|
+
id: string;
|
|
52
|
+
label: string;
|
|
53
|
+
note: string;
|
|
54
|
+
bytes: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface WhisperStatus {
|
|
58
|
+
/** False only when this platform has no prebuilt build AND no binary on the host. */
|
|
59
|
+
installable: boolean;
|
|
60
|
+
/** Manual command for a platform PPM cannot install for (macOS). */
|
|
61
|
+
installHint: string | null;
|
|
62
|
+
binary: WhisperBinary | null;
|
|
63
|
+
version: string;
|
|
64
|
+
/** Model currently on disk, if any. */
|
|
65
|
+
model: WhisperStatusModel | null;
|
|
66
|
+
/** Binary + model + VAD model all present — the mic can use it. */
|
|
67
|
+
ready: boolean;
|
|
68
|
+
models: WhisperStatusModel[];
|
|
69
|
+
install: InstallJobState | null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let currentJob: InstallJobState | null = null;
|
|
73
|
+
|
|
74
|
+
const publicModel = (m: (typeof WHISPER_MODELS)[number]): WhisperStatusModel => ({
|
|
75
|
+
id: m.id,
|
|
76
|
+
label: m.label,
|
|
77
|
+
note: m.note,
|
|
78
|
+
bytes: m.bytes,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
/** The installed model, found by which catalog file exists on disk. */
|
|
82
|
+
export function installedModel(): (typeof WHISPER_MODELS)[number] | null {
|
|
83
|
+
return WHISPER_MODELS.find((m) => existsSync(resolve(whisperModelDir(), m.file))) ?? null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function vadModelPath(): string {
|
|
87
|
+
return resolve(whisperModelDir(), VAD_MODEL.file);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function getWhisperStatus(
|
|
91
|
+
platform: NodeJS.Platform = process.platform,
|
|
92
|
+
arch: string = process.arch,
|
|
93
|
+
): WhisperStatus {
|
|
94
|
+
const binary = findWhisperBinary(platform);
|
|
95
|
+
const model = installedModel();
|
|
96
|
+
const hasAsset = whisperAssetFor(platform, arch) !== null;
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
installable: hasAsset || binary !== null,
|
|
100
|
+
installHint: !hasAsset && platform === "darwin" ? MACOS_INSTALL_HINT : null,
|
|
101
|
+
binary,
|
|
102
|
+
version: WHISPER_VERSION,
|
|
103
|
+
model: model ? publicModel(model) : null,
|
|
104
|
+
ready: binary !== null && model !== null && existsSync(vadModelPath()),
|
|
105
|
+
models: WHISPER_MODELS.map(publicModel),
|
|
106
|
+
install: currentJob,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function extractArchive(archive: string, asset: WhisperAsset, destDir: string, platform: NodeJS.Platform) {
|
|
111
|
+
const cmd =
|
|
112
|
+
asset.ext === "tar.gz"
|
|
113
|
+
? ["tar", "-xzf", archive, "-C", destDir]
|
|
114
|
+
: platform === "win32"
|
|
115
|
+
? // Windows 10+ ships bsdtar as tar.exe, which reads zip.
|
|
116
|
+
["tar", "-xf", archive, "-C", destDir]
|
|
117
|
+
: ["unzip", "-o", "-q", archive, "-d", destDir];
|
|
118
|
+
|
|
119
|
+
const proc = Bun.spawn({ cmd, stdout: "ignore", stderr: "pipe" });
|
|
120
|
+
const code = await proc.exited;
|
|
121
|
+
if (code !== 0) {
|
|
122
|
+
const stderr = await new Response(proc.stderr).text();
|
|
123
|
+
throw new Error(`extract failed (${cmd[0]} exit ${code}): ${stderr.slice(0, 200)}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Run the binary once so a host that cannot execute it fails here, not mid-sentence. */
|
|
128
|
+
async function verifyBinaryRuns(path: string): Promise<void> {
|
|
129
|
+
let proc;
|
|
130
|
+
try {
|
|
131
|
+
proc = Bun.spawn({ cmd: [path, "--help"], stdout: "ignore", stderr: "pipe", windowsHide: true });
|
|
132
|
+
} catch (e: any) {
|
|
133
|
+
throw new Error(`whisper-cli could not be started: ${e?.message ?? e}`);
|
|
134
|
+
}
|
|
135
|
+
const [code, stderr] = await Promise.all([proc.exited, new Response(proc.stderr).text()]);
|
|
136
|
+
if (code !== 0) {
|
|
137
|
+
const detail = stderr.trim().split("\n")[0] ?? `exit ${code}`;
|
|
138
|
+
throw new Error(`whisper-cli does not run on this host: ${detail}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Keep only the model just installed — the others are hundreds of MB of nothing. */
|
|
143
|
+
function pruneOtherModels(keepFile: string) {
|
|
144
|
+
for (const m of WHISPER_MODELS) {
|
|
145
|
+
if (m.file !== keepFile) rmSync(resolve(whisperModelDir(), m.file), { force: true });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function runInstall(modelId: string, platform: NodeJS.Platform, arch: string, fetchFn?: FetchFn) {
|
|
150
|
+
const model = modelById(modelId);
|
|
151
|
+
if (!model) throw new Error(`unknown model: ${modelId}`);
|
|
152
|
+
const job = currentJob!;
|
|
153
|
+
const progress = (received: number, total: number) => {
|
|
154
|
+
job.receivedBytes = received;
|
|
155
|
+
job.totalBytes = total || 0;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
mkdirSync(whisperModelDir(), { recursive: true });
|
|
159
|
+
|
|
160
|
+
// A host that already has whisper-cli (Homebrew, distro package) needs models only.
|
|
161
|
+
if (!findWhisperBinary(platform)) {
|
|
162
|
+
const asset = whisperAssetFor(platform, arch);
|
|
163
|
+
if (!asset) throw new Error(`no whisper.cpp build for ${platform}/${arch} — install it manually`);
|
|
164
|
+
job.phase = "binary";
|
|
165
|
+
mkdirSync(whisperBinDir(), { recursive: true });
|
|
166
|
+
mkdirSync(whisperTmpDir(), { recursive: true });
|
|
167
|
+
const archive = resolve(whisperTmpDir(), asset.file);
|
|
168
|
+
await downloadVerified({ url: asset.url, dest: archive, sha256: asset.sha256, onProgress: progress, fetchFn });
|
|
169
|
+
await extractArchive(archive, asset, whisperBinDir(), platform);
|
|
170
|
+
rmSync(archive, { force: true });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
job.phase = "model";
|
|
174
|
+
progress(0, model.bytes);
|
|
175
|
+
await downloadVerified({
|
|
176
|
+
url: modelUrl(model),
|
|
177
|
+
dest: resolve(whisperModelDir(), model.file),
|
|
178
|
+
sha256: model.sha256,
|
|
179
|
+
onProgress: progress,
|
|
180
|
+
fetchFn,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
job.phase = "vad";
|
|
184
|
+
progress(0, VAD_MODEL.bytes);
|
|
185
|
+
await downloadVerified({
|
|
186
|
+
url: vadModelUrl(),
|
|
187
|
+
dest: vadModelPath(),
|
|
188
|
+
sha256: VAD_MODEL.sha256,
|
|
189
|
+
onProgress: progress,
|
|
190
|
+
fetchFn,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
job.phase = "verify";
|
|
194
|
+
const binary = findWhisperBinary(platform);
|
|
195
|
+
if (!binary) throw new Error("whisper-cli missing after install");
|
|
196
|
+
await verifyBinaryRuns(binary.path);
|
|
197
|
+
|
|
198
|
+
pruneOtherModels(model.file);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Start an install in the background and return immediately — the UI polls
|
|
203
|
+
* `getWhisperStatus()`. One at a time: a second call while a job runs throws.
|
|
204
|
+
*/
|
|
205
|
+
export function startWhisperInstall(
|
|
206
|
+
modelId: string = DEFAULT_MODEL_ID,
|
|
207
|
+
opts: { platform?: NodeJS.Platform; arch?: string; fetchFn?: FetchFn } = {},
|
|
208
|
+
): InstallJobState {
|
|
209
|
+
if (currentJob && !currentJob.done) throw new Error("An install is already running");
|
|
210
|
+
const platform = opts.platform ?? process.platform;
|
|
211
|
+
const arch = opts.arch ?? process.arch;
|
|
212
|
+
if (!modelById(modelId)) throw new Error(`unknown model: ${modelId}`);
|
|
213
|
+
|
|
214
|
+
const job: InstallJobState = {
|
|
215
|
+
modelId,
|
|
216
|
+
phase: "binary",
|
|
217
|
+
receivedBytes: 0,
|
|
218
|
+
totalBytes: 0,
|
|
219
|
+
done: false,
|
|
220
|
+
error: null,
|
|
221
|
+
};
|
|
222
|
+
currentJob = job;
|
|
223
|
+
|
|
224
|
+
runInstall(modelId, platform, arch, opts.fetchFn)
|
|
225
|
+
.then(() => {
|
|
226
|
+
job.done = true;
|
|
227
|
+
})
|
|
228
|
+
.catch((e: any) => {
|
|
229
|
+
job.error = e?.message ?? String(e);
|
|
230
|
+
job.done = true;
|
|
231
|
+
console.error("[whisper] install failed:", job.error);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
return job;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Remove everything PPM downloaded. A system-installed whisper-cli is left alone. */
|
|
238
|
+
export function uninstallWhisper(): void {
|
|
239
|
+
if (currentJob && !currentJob.done) throw new Error("An install is running");
|
|
240
|
+
rmSync(whisperDir(), { recursive: true, force: true });
|
|
241
|
+
currentJob = null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Test seam: forget any finished job so a suite starts from a clean status. */
|
|
245
|
+
export function _resetWhisperInstallState(): void {
|
|
246
|
+
currentJob = null;
|
|
247
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the Whisper install lives, and how the binary is found.
|
|
3
|
+
*
|
|
4
|
+
* Everything PPM downloads sits under `<ppm dir>/whisper/` so uninstall is one
|
|
5
|
+
* `rm -rf` and an isolated `PPM_HOME` (tests) never touches a real install.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
8
|
+
import { resolve } from "node:path";
|
|
9
|
+
import { getPpmDir } from "../ppm-dir.ts";
|
|
10
|
+
|
|
11
|
+
export const whisperDir = () => resolve(getPpmDir(), "whisper");
|
|
12
|
+
export const whisperBinDir = () => resolve(whisperDir(), "bin");
|
|
13
|
+
export const whisperModelDir = () => resolve(whisperDir(), "models");
|
|
14
|
+
export const whisperTmpDir = () => resolve(whisperDir(), "tmp");
|
|
15
|
+
|
|
16
|
+
export const cliName = (platform: NodeJS.Platform = process.platform) =>
|
|
17
|
+
platform === "win32" ? "whisper-cli.exe" : "whisper-cli";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The extracted archive keeps its own top-level directory — `whisper-bin-ubuntu-x64/`
|
|
21
|
+
* on Linux, `Release/` on Windows — and those names carry the build tag, so the
|
|
22
|
+
* binary is located by looking one level down rather than assumed.
|
|
23
|
+
*/
|
|
24
|
+
export function findBundledBinary(platform: NodeJS.Platform = process.platform): string | null {
|
|
25
|
+
const root = whisperBinDir();
|
|
26
|
+
if (!existsSync(root)) return null;
|
|
27
|
+
const name = cliName(platform);
|
|
28
|
+
if (existsSync(resolve(root, name))) return resolve(root, name);
|
|
29
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
30
|
+
if (!entry.isDirectory()) continue;
|
|
31
|
+
const candidate = resolve(root, entry.name, name);
|
|
32
|
+
if (existsSync(candidate)) return candidate;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Homebrew's `whisper.cpp` is how a Mac gets a `whisper-cli` (the release has no
|
|
39
|
+
* macOS CLI to download), and a PPM started by launchd/systemd inherits a PATH
|
|
40
|
+
* that usually has neither Homebrew prefix in it — so both are checked directly
|
|
41
|
+
* rather than trusting `PATH` alone.
|
|
42
|
+
*/
|
|
43
|
+
const SYSTEM_PATHS = ["/opt/homebrew/bin/whisper-cli", "/usr/local/bin/whisper-cli", "/usr/bin/whisper-cli"];
|
|
44
|
+
|
|
45
|
+
export function findSystemBinary(): string | null {
|
|
46
|
+
const onPath = Bun.which("whisper-cli");
|
|
47
|
+
if (onPath) return onPath;
|
|
48
|
+
return SYSTEM_PATHS.find((p) => existsSync(p)) ?? null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface WhisperBinary {
|
|
52
|
+
path: string;
|
|
53
|
+
/** `bundled` = installed by PPM and removable from Settings; `system` = the host's own. */
|
|
54
|
+
source: "bundled" | "system";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function findWhisperBinary(platform: NodeJS.Platform = process.platform): WhisperBinary | null {
|
|
58
|
+
const bundled = findBundledBinary(platform);
|
|
59
|
+
if (bundled) return { path: bundled, source: "bundled" };
|
|
60
|
+
const system = findSystemBinary();
|
|
61
|
+
return system ? { path: system, source: "system" } : null;
|
|
62
|
+
}
|