@hienlh/ppm 0.23.11 → 0.23.12
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 +18 -0
- package/CLAUDE.md +13 -2
- 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 +37 -1
- package/bun.lock +34 -0
- package/dist/web/assets/accounts-settings-section-CGe5ikvs.js +1 -0
- package/dist/web/assets/accounts-settings-section-CGe5ikvs.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-CGe5ikvs.js.gz +0 -0
- package/dist/web/assets/{agent-session-sheet-CBMsnl_p.js → agent-session-sheet-vBhfHYrC.js} +2 -2
- package/dist/web/assets/agent-session-sheet-vBhfHYrC.js.br +0 -0
- package/dist/web/assets/agent-session-sheet-vBhfHYrC.js.gz +0 -0
- package/dist/web/assets/{agent-session-window-content-D9C9FA7E.js → agent-session-window-content-BxIxDN5i.js} +1 -1
- package/dist/web/assets/agent-session-window-content-BxIxDN5i.js.br +0 -0
- package/dist/web/assets/agent-session-window-content-BxIxDN5i.js.gz +0 -0
- package/dist/web/assets/{ai-resource-editor-DhUVgDEG.js → ai-resource-editor-Y8clBPRv.js} +1 -1
- package/dist/web/assets/ai-resource-editor-Y8clBPRv.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-Y8clBPRv.js.gz +0 -0
- package/dist/web/assets/{ai-settings-section-DOckWvp4.js → ai-settings-section-BB8vscte.js} +1 -1
- package/dist/web/assets/{ai-settings-section-CETpSpYd.js → ai-settings-section-Ck8uN_Bw.js} +1 -1
- package/dist/web/assets/ai-settings-section-Ck8uN_Bw.js.br +0 -0
- package/dist/web/assets/ai-settings-section-Ck8uN_Bw.js.gz +0 -0
- package/dist/web/assets/android-tab-BIOUVVoW.js +2 -0
- package/dist/web/assets/android-tab-BIOUVVoW.js.br +0 -0
- package/dist/web/assets/android-tab-BIOUVVoW.js.gz +0 -0
- package/dist/web/assets/{api-settings-JIgKfcCx.js → api-settings-D1axn9vm.js} +1 -1
- package/dist/web/assets/{appearance-settings-section-BJUiLUb7.js → appearance-settings-section-Bv5_n9lH.js} +1 -1
- package/dist/web/assets/appearance-settings-section-Bv5_n9lH.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-Bv5_n9lH.js.gz +0 -0
- package/dist/web/assets/{apps-panel-1VElRgV3.js → apps-panel-DXHF0QEv.js} +1 -1
- package/dist/web/assets/apps-panel-DXHF0QEv.js.br +0 -0
- package/dist/web/assets/apps-panel-DXHF0QEv.js.gz +0 -0
- package/dist/web/assets/{audio-preview-DYkyHu5X.js → audio-preview-DpjOKEm4.js} +1 -1
- package/dist/web/assets/audio-preview-DpjOKEm4.js.br +0 -0
- package/dist/web/assets/audio-preview-DpjOKEm4.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-4dgMNadQ.js +1 -0
- package/dist/web/assets/branch-review-tab-4dgMNadQ.js.br +0 -0
- package/dist/web/assets/branch-review-tab-4dgMNadQ.js.gz +0 -0
- package/dist/web/assets/chat-tab-Bbe_77oJ.js +15 -0
- package/dist/web/assets/chat-tab-Bbe_77oJ.js.br +0 -0
- package/dist/web/assets/chat-tab-Bbe_77oJ.js.gz +0 -0
- package/dist/web/assets/chat-tab-D3i5O3dO.js +1 -0
- package/dist/web/assets/chat-tab-D3i5O3dO.js.br +0 -0
- package/dist/web/assets/chat-tab-D3i5O3dO.js.gz +0 -0
- package/dist/web/assets/code-editor-DXsIWoQ1.js +7 -0
- package/dist/web/assets/code-editor-DXsIWoQ1.js.br +0 -0
- package/dist/web/assets/code-editor-DXsIWoQ1.js.gz +0 -0
- package/dist/web/assets/{codex-reset-credit-button-Fr45FUxi.js → codex-reset-credit-button-DRhievFQ.js} +1 -1
- package/dist/web/assets/codex-reset-credit-button-DRhievFQ.js.br +0 -0
- package/dist/web/assets/codex-reset-credit-button-DRhievFQ.js.gz +0 -0
- package/dist/web/assets/{conflict-editor-B-wdjSXI.js → conflict-editor-D_RImo_V.js} +3 -3
- package/dist/web/assets/conflict-editor-D_RImo_V.js.br +0 -0
- package/dist/web/assets/conflict-editor-D_RImo_V.js.gz +0 -0
- package/dist/web/assets/{csv-preview-B6RodObB.js → csv-preview-BuFdfLo3.js} +1 -1
- package/dist/web/assets/csv-preview-BuFdfLo3.js.br +0 -0
- package/dist/web/assets/csv-preview-BuFdfLo3.js.gz +0 -0
- package/dist/web/assets/{database-viewer-CdPBUQPY.js → database-viewer-ChcbYn9E.js} +1 -1
- package/dist/web/assets/database-viewer-ChcbYn9E.js.br +0 -0
- package/dist/web/assets/database-viewer-ChcbYn9E.js.gz +0 -0
- package/dist/web/assets/{design-settings-section-BpCpaBwL.js → design-settings-section-B_xOf51h.js} +1 -1
- package/dist/web/assets/design-settings-section-B_xOf51h.js.br +0 -0
- package/dist/web/assets/design-settings-section-B_xOf51h.js.gz +0 -0
- package/dist/web/assets/{design-skill-suggestion-DkT2E2IV.js → design-skill-suggestion-BbEDg15Z.js} +1 -1
- package/dist/web/assets/design-skill-suggestion-BbEDg15Z.js.br +0 -0
- package/dist/web/assets/design-skill-suggestion-BbEDg15Z.js.gz +0 -0
- package/dist/web/assets/{design-tab-BZb9eemI.js → design-tab-BQSYJ4cS.js} +6 -6
- package/dist/web/assets/design-tab-BQSYJ4cS.js.br +0 -0
- package/dist/web/assets/design-tab-BQSYJ4cS.js.gz +0 -0
- package/dist/web/assets/{designs-sidebar-panel-CF4tp6j-.js → designs-sidebar-panel-AiPaYfSU.js} +1 -1
- package/dist/web/assets/designs-sidebar-panel-AiPaYfSU.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-AiPaYfSU.js.gz +0 -0
- package/dist/web/assets/{diff-viewer-BqEqwSw6.js → diff-viewer-BZ6glGK-.js} +1 -1
- package/dist/web/assets/diff-viewer-BZ6glGK-.js.br +0 -0
- package/dist/web/assets/diff-viewer-BZ6glGK-.js.gz +0 -0
- package/dist/web/assets/{edit-diff-preview-DD4HayXY.js → edit-diff-preview-D-FNLOU2.js} +1 -1
- package/dist/web/assets/edit-diff-preview-D-FNLOU2.js.br +0 -0
- package/dist/web/assets/edit-diff-preview-D-FNLOU2.js.gz +0 -0
- package/dist/web/assets/{editor-language-service-CkA5sEdV.js → editor-language-service-4sbsdqBV.js} +1 -1
- package/dist/web/assets/editor-language-service-4sbsdqBV.js.br +0 -0
- package/dist/web/assets/editor-language-service-4sbsdqBV.js.gz +0 -0
- package/dist/web/assets/explorer-body-DbgrG1fe.js +2 -0
- package/dist/web/assets/explorer-body-DbgrG1fe.js.br +0 -0
- package/dist/web/assets/explorer-body-DbgrG1fe.js.gz +0 -0
- package/dist/web/assets/{explorer-window-content-CRJ2eMZ4.js → explorer-window-content-BCjWvHpp.js} +1 -1
- package/dist/web/assets/explorer-window-content-BCjWvHpp.js.br +0 -0
- package/dist/web/assets/explorer-window-content-BCjWvHpp.js.gz +0 -0
- package/dist/web/assets/{extension-manager-section-DwQTdCII.js → extension-manager-section-DiMF4RnT.js} +1 -1
- package/dist/web/assets/extension-manager-section-DiMF4RnT.js.br +0 -0
- package/dist/web/assets/extension-manager-section-DiMF4RnT.js.gz +0 -0
- package/dist/web/assets/{extension-webview-CMq-VTLu.js → extension-webview-Coti6Vfw.js} +1 -1
- package/dist/web/assets/extension-webview-Coti6Vfw.js.br +0 -0
- package/dist/web/assets/extension-webview-Coti6Vfw.js.gz +0 -0
- package/dist/web/assets/file-store-Cm7-pHux.js +1 -0
- package/dist/web/assets/file-store-Cm7-pHux.js.br +0 -0
- package/dist/web/assets/file-store-Cm7-pHux.js.gz +0 -0
- package/dist/web/assets/{files-settings-section-B2lcyh-6.js → files-settings-section-ZTVwOwx0.js} +1 -1
- package/dist/web/assets/files-settings-section-ZTVwOwx0.js.br +0 -0
- package/dist/web/assets/files-settings-section-ZTVwOwx0.js.gz +0 -0
- package/dist/web/assets/{general-settings-section-Doepm2sH.js → general-settings-section-B7Hjx_fb.js} +1 -1
- package/dist/web/assets/general-settings-section-B7Hjx_fb.js.br +0 -0
- package/dist/web/assets/general-settings-section-B7Hjx_fb.js.gz +0 -0
- package/dist/web/assets/{git-log-panel-CJakNMDc.js → git-log-panel-CbcJ_YEH.js} +1 -1
- package/dist/web/assets/git-log-panel-CbcJ_YEH.js.br +0 -0
- package/dist/web/assets/git-log-panel-CbcJ_YEH.js.gz +0 -0
- package/dist/web/assets/{glide-data-grid-C_SeOhSq.js → glide-data-grid-BfByGSf1.js} +3 -3
- package/dist/web/assets/glide-data-grid-BfByGSf1.js.br +0 -0
- package/dist/web/assets/glide-data-grid-BfByGSf1.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-DCo9OP3D.js +1 -0
- package/dist/web/assets/group-chat-tab-DCo9OP3D.js.br +0 -0
- package/dist/web/assets/group-chat-tab-DCo9OP3D.js.gz +0 -0
- package/dist/web/assets/{image-preview-C1Frlx22.js → image-preview-Cjlps7Pt.js} +1 -1
- package/dist/web/assets/index-CyDLBddf.js +52 -0
- package/dist/web/assets/index-CyDLBddf.js.br +0 -0
- package/dist/web/assets/index-CyDLBddf.js.gz +0 -0
- package/dist/web/assets/index-Dh5apC3I.css +1 -0
- package/dist/web/assets/index-Dh5apC3I.css.br +0 -0
- package/dist/web/assets/index-Dh5apC3I.css.gz +0 -0
- package/dist/web/assets/{jira-watcher-section-BmkIGQFV.js → jira-watcher-section-Dz_-sUC2.js} +1 -1
- package/dist/web/assets/keybindings-store-BTq5Z7XP.js +1 -0
- package/dist/web/assets/{keyboard-shortcuts-section-BgZe3QDr.js → keyboard-shortcuts-section-Ba5NYwlG.js} +1 -1
- package/dist/web/assets/keyboard-shortcuts-section-Ba5NYwlG.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-Ba5NYwlG.js.gz +0 -0
- package/dist/web/assets/{language-servers-section-CCMzgOaE.js → language-servers-section-DJJ7SFXo.js} +2 -2
- package/dist/web/assets/language-servers-section-DJJ7SFXo.js.br +0 -0
- package/dist/web/assets/language-servers-section-DJJ7SFXo.js.gz +0 -0
- package/dist/web/assets/{lsp-client-B10suuaZ.js → lsp-client-Dr3vQ1bb.js} +1 -1
- package/dist/web/assets/lsp-client-Dr3vQ1bb.js.br +0 -0
- package/dist/web/assets/lsp-client-Dr3vQ1bb.js.gz +0 -0
- package/dist/web/assets/{markdown-renderer-AHHFS3jc.js → markdown-renderer-CmnqFfTU.js} +3 -3
- package/dist/web/assets/markdown-renderer-CmnqFfTU.js.br +0 -0
- package/dist/web/assets/markdown-renderer-CmnqFfTU.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-LJdVMbGl.js +1 -0
- package/dist/web/assets/{mobile-explorer-sheet-CqCsLWSr.js → mobile-explorer-sheet-BiIhZtJ2.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-BiIhZtJ2.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-BiIhZtJ2.js.gz +0 -0
- package/dist/web/assets/new-design-dialog-DI_hxvFV.js +1 -0
- package/dist/web/assets/new-design-dialog-DI_hxvFV.js.br +0 -0
- package/dist/web/assets/new-design-dialog-DI_hxvFV.js.gz +0 -0
- package/dist/web/assets/notification-store-9lBSplOV.js +1 -0
- package/dist/web/assets/{notifications-settings-section-CXgzH_bK.js → notifications-settings-section-0s-2OKRv.js} +1 -1
- package/dist/web/assets/notifications-settings-section-0s-2OKRv.js.br +0 -0
- package/dist/web/assets/notifications-settings-section-0s-2OKRv.js.gz +0 -0
- package/dist/web/assets/{overview-panel-BYB8mgRE.js → overview-panel-3htxfZS2.js} +1 -1
- package/dist/web/assets/overview-panel-3htxfZS2.js.br +0 -0
- package/dist/web/assets/overview-panel-3htxfZS2.js.gz +0 -0
- package/dist/web/assets/panel-store-B6PoCwBA.js +1 -0
- package/dist/web/assets/panel-store-B6PoCwBA.js.br +0 -0
- package/dist/web/assets/panel-store-B6PoCwBA.js.gz +0 -0
- package/dist/web/assets/{performance-panel-Dpuq3g0W.js → performance-panel-V8gpnnf7.js} +2 -2
- package/dist/web/assets/performance-panel-V8gpnnf7.js.br +0 -0
- package/dist/web/assets/performance-panel-V8gpnnf7.js.gz +0 -0
- package/dist/web/assets/{postgres-viewer-DW0Gkmow.js → postgres-viewer-sWS-ogTC.js} +1 -1
- package/dist/web/assets/postgres-viewer-sWS-ogTC.js.br +0 -0
- package/dist/web/assets/postgres-viewer-sWS-ogTC.js.gz +0 -0
- package/dist/web/assets/{ppmbot-settings-section-DFtlGoW6.js → ppmbot-settings-section-CT8vvlzk.js} +1 -1
- package/dist/web/assets/ppmbot-settings-section-CT8vvlzk.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-CT8vvlzk.js.gz +0 -0
- package/dist/web/assets/{pptx-export-CNyG32Xr.js → pptx-export-Ugjv0hso.js} +4 -4
- package/dist/web/assets/pptx-export-Ugjv0hso.js.br +0 -0
- package/dist/web/assets/pptx-export-Ugjv0hso.js.gz +0 -0
- package/dist/web/assets/{problems-panel-V5zqpuXq.js → problems-panel-Gcy79pSS.js} +1 -1
- package/dist/web/assets/problems-panel-Gcy79pSS.js.br +0 -0
- package/dist/web/assets/problems-panel-Gcy79pSS.js.gz +0 -0
- package/dist/web/assets/{process-row-format-CiJJSf_V.js → process-row-format-u6y7lOee.js} +1 -1
- package/dist/web/assets/process-table-BUTIp9Oy.js +1 -0
- package/dist/web/assets/process-table-BUTIp9Oy.js.br +0 -0
- package/dist/web/assets/process-table-BUTIp9Oy.js.gz +0 -0
- package/dist/web/assets/{proxy-settings-section-B7AVlTfY.js → proxy-settings-section-Buv_8y54.js} +1 -1
- package/dist/web/assets/proxy-settings-section-Buv_8y54.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-Buv_8y54.js.gz +0 -0
- package/dist/web/assets/{query-audit-section-gHmRfWKr.js → query-audit-section-N2DQtgJx.js} +1 -1
- package/dist/web/assets/query-audit-section-N2DQtgJx.js.br +0 -0
- package/dist/web/assets/query-audit-section-N2DQtgJx.js.gz +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-CRvJqmaz.js +1 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-CRvJqmaz.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-CRvJqmaz.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BoYINLbJ.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BoYINLbJ.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BoYINLbJ.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DPdP0yYu.js +1 -0
- package/dist/web/assets/remote-desktop-mobile-view-DPdP0yYu.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DPdP0yYu.js.gz +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BeQ_Jrp7.js +1 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BeQ_Jrp7.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BeQ_Jrp7.js.gz +0 -0
- package/dist/web/assets/remote-desktop-settings-section-Bs4sHS3l.js +1 -0
- package/dist/web/assets/remote-desktop-settings-section-Bs4sHS3l.js.br +0 -0
- package/dist/web/assets/remote-desktop-settings-section-Bs4sHS3l.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-DDr__JxQ.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-DDr__JxQ.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-DDr__JxQ.js.gz +0 -0
- package/dist/web/assets/{run-in-terminal-DKBcEGVu.js → run-in-terminal-DCBNtYHQ.js} +1 -1
- package/dist/web/assets/{schedules-settings-section-sYDAsBMO.js → schedules-settings-section-_cHX2qOa.js} +1 -1
- package/dist/web/assets/schedules-settings-section-_cHX2qOa.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-_cHX2qOa.js.gz +0 -0
- package/dist/web/assets/{send-to-chat-CCdOrKc7.js → send-to-chat-dNqNV7Y4.js} +1 -1
- package/dist/web/assets/send-to-chat-dNqNV7Y4.js.br +0 -0
- package/dist/web/assets/send-to-chat-dNqNV7Y4.js.gz +0 -0
- package/dist/web/assets/{services-panel-CKa2aP1d.js → services-panel-Dm54cnW3.js} +1 -1
- package/dist/web/assets/services-panel-Dm54cnW3.js.br +0 -0
- package/dist/web/assets/services-panel-Dm54cnW3.js.gz +0 -0
- package/dist/web/assets/settings-body-DRRQNaDA.js +1 -0
- package/dist/web/assets/settings-body-DRRQNaDA.js.br +0 -0
- package/dist/web/assets/settings-body-DRRQNaDA.js.gz +0 -0
- package/dist/web/assets/settings-section-content-DRaHfvm8.js +1 -0
- package/dist/web/assets/settings-section-content-U3mIx6hF.js +2 -0
- package/dist/web/assets/settings-section-content-U3mIx6hF.js.br +0 -0
- package/dist/web/assets/settings-section-content-U3mIx6hF.js.gz +0 -0
- package/dist/web/assets/{settings-store-DfuiLq_9.js → settings-store-Cyuo8ceh.js} +2 -2
- package/dist/web/assets/settings-store-Cyuo8ceh.js.br +0 -0
- package/dist/web/assets/settings-store-Cyuo8ceh.js.gz +0 -0
- package/dist/web/assets/settings-tab-CB_BhHTK.js +1 -0
- package/dist/web/assets/settings-window-content-CgZIMNX8.js +1 -0
- package/dist/web/assets/{slash-command-picker-CLevA_Gf.js → slash-command-picker-CQlIqMW0.js} +1 -1
- package/dist/web/assets/slash-command-picker-CQlIqMW0.js.br +0 -0
- package/dist/web/assets/slash-command-picker-CQlIqMW0.js.gz +0 -0
- package/dist/web/assets/{sql-query-editor-Db8b0jEr.js → sql-query-editor--Z4bcqd8.js} +1 -1
- package/dist/web/assets/sql-query-editor--Z4bcqd8.js.br +0 -0
- package/dist/web/assets/sql-query-editor--Z4bcqd8.js.gz +0 -0
- package/dist/web/assets/{sqlite-viewer-VzYLMqkD.js → sqlite-viewer-CSmX3qaj.js} +1 -1
- package/dist/web/assets/sqlite-viewer-CSmX3qaj.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-CSmX3qaj.js.gz +0 -0
- package/dist/web/assets/{system-monitor-body-BR60W_mG.js → system-monitor-body-LannpU6H.js} +2 -2
- package/dist/web/assets/system-monitor-body-LannpU6H.js.br +0 -0
- package/dist/web/assets/system-monitor-body-LannpU6H.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-BfVucwEF.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-BLw1QBXo.js → system-monitor-window-content-kLNW9Ln3.js} +1 -1
- package/dist/web/assets/{tab-host-window-content-BL61SB5m.js → tab-host-window-content-II_FtOYM.js} +1 -1
- package/dist/web/assets/tab-host-window-content-II_FtOYM.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-II_FtOYM.js.gz +0 -0
- package/dist/web/assets/{tab-store-CbPh8CAX.js → tab-store-DCpc0g0Q.js} +1 -1
- package/dist/web/assets/{terminal-tab-B4y6at4h.js → terminal-tab-CTe2polt.js} +1 -1
- package/dist/web/assets/terminal-tab-CTe2polt.js.br +0 -0
- package/dist/web/assets/terminal-tab-CTe2polt.js.gz +0 -0
- package/dist/web/assets/{tool-cards-K0r_yxI0.js → tool-cards-rxLXbBSm.js} +5 -5
- package/dist/web/assets/tool-cards-rxLXbBSm.js.br +0 -0
- package/dist/web/assets/tool-cards-rxLXbBSm.js.gz +0 -0
- package/dist/web/assets/use-h264-canvas-decoder-BfO9QrlH.js +1 -0
- package/dist/web/assets/use-h264-canvas-decoder-BfO9QrlH.js.br +0 -0
- package/dist/web/assets/use-h264-canvas-decoder-BfO9QrlH.js.gz +0 -0
- package/dist/web/assets/{use-inline-blame-BK23icsE.js → use-inline-blame-CxZ_QWzS.js} +3 -3
- package/dist/web/assets/use-inline-blame-CxZ_QWzS.js.br +0 -0
- package/dist/web/assets/use-inline-blame-CxZ_QWzS.js.gz +0 -0
- package/dist/web/assets/{use-lsp-CRdCPCKW.js → use-lsp-gCNE5A9K.js} +1 -1
- package/dist/web/assets/use-lsp-gCNE5A9K.js.br +0 -0
- package/dist/web/assets/use-lsp-gCNE5A9K.js.gz +0 -0
- package/dist/web/assets/{use-monaco-theme-CpXT2uh3.js → use-monaco-theme-DvNGcCvz.js} +1 -1
- package/dist/web/assets/{use-process-kill-BWYX03KF.js → use-process-kill-Cbiu1mbY.js} +1 -1
- package/dist/web/assets/use-process-kill-Cbiu1mbY.js.br +0 -0
- package/dist/web/assets/use-process-kill-Cbiu1mbY.js.gz +0 -0
- package/dist/web/assets/{use-websocket-CiWQKhHr.js → use-websocket-AC7EG1LK.js} +1 -1
- package/dist/web/assets/video-preview-C2Y61WUE.js +1 -0
- package/dist/web/assets/video-preview-C2Y61WUE.js.br +0 -0
- package/dist/web/assets/video-preview-C2Y61WUE.js.gz +0 -0
- package/dist/web/assets/{voice-settings-section-Ceihggqf.js → voice-settings-section-DCXZeLYI.js} +1 -1
- package/dist/web/assets/voice-settings-section-DCXZeLYI.js.br +0 -0
- package/dist/web/assets/voice-settings-section-DCXZeLYI.js.gz +0 -0
- package/dist/web/assets/{window-pip-registry-mDgwpAwP.js → window-pip-registry-9Y9LQQYS.js} +1 -1
- package/dist/web/index.html +50 -7
- 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/architecture/android-emulator-phase0-report-260921.md +310 -0
- package/docs/architecture/android-emulator-phase2-report-260921.md +163 -0
- package/docs/architecture/android-emulator-phase3-report-260921.md +203 -0
- package/docs/architecture/android-emulator-phase4-report-260921.md +191 -0
- package/docs/architecture/android-emulator-plan-260920.md +376 -0
- package/docs/architecture/plugins-and-tracing.md +48 -7
- package/package.json +4 -2
- package/scripts/gen-android-proto.ts +37 -0
- package/scripts/release.sh +3 -1
- package/src/cli/commands/chat-cmd.ts +2 -2
- package/src/providers/claude-agent-sdk-query-options.ts +28 -0
- package/src/providers/claude-agent-sdk.ts +153 -71
- package/src/providers/claude-warm-spare.ts +176 -0
- package/src/providers/provider.interface.ts +1 -0
- package/src/server/index.ts +53 -0
- package/src/server/middleware/gzip-json.ts +13 -1
- package/src/server/routes/android.ts +616 -0
- package/src/server/routes/chat.ts +31 -0
- package/src/server/routes/files.ts +52 -5
- package/src/server/routes/remote-desktop.ts +95 -2
- package/src/server/routes/trace.ts +66 -0
- package/src/server/ws/android.ts +101 -0
- package/src/server/ws/chat.ts +12 -17
- package/src/server/ws/global.ts +13 -1
- package/src/server/ws/remote-desktop.ts +6 -1
- package/src/services/android/android-apk.ts +387 -0
- package/src/services/android/android-capabilities.ts +154 -0
- package/src/services/android/android-flag.ts +12 -0
- package/src/services/android/android-grpc.ts +124 -0
- package/src/services/android/android-input.ts +129 -0
- package/src/services/android/android-logcat.ts +169 -0
- package/src/services/android/android-nonce.ts +50 -0
- package/src/services/android/android-operations.ts +124 -0
- package/src/services/android/android-screenshot.ts +53 -0
- package/src/services/android/android-session.ts +510 -0
- package/src/services/android/android-video.ts +495 -0
- package/src/services/android/avd-list.ts +131 -0
- package/src/services/android/avd-manager.ts +397 -0
- package/src/services/android/device-registry.ts +223 -0
- package/src/services/android/emulator-discovery.ts +160 -0
- package/src/services/android/emulator-launcher.ts +290 -0
- package/src/services/android/proto/emulator-controller-descriptor.ts +10 -0
- package/src/services/android/proto/emulator_controller.proto +1791 -0
- package/src/services/android/sdk-discovery.ts +178 -0
- package/src/services/android/system-images.ts +124 -0
- package/src/services/chat.service.ts +81 -4
- package/src/services/config.service.ts +1 -1
- package/src/services/file-filter.service.ts +2 -61
- package/src/services/file-glob.ts +67 -0
- package/src/services/file-index/file-index-runner.ts +169 -0
- package/src/services/file-index/file-index-worker.ts +73 -0
- package/src/services/file-index/index-search.ts +152 -0
- package/src/services/file-index/index-walk.ts +109 -0
- package/src/services/file-list-index.service.ts +189 -70
- package/src/services/file-watcher/linux-inotify.ts +238 -0
- package/src/services/file-watcher/watch-tree.ts +37 -6
- package/src/services/file-watcher.service.ts +40 -8
- package/src/services/file.service.ts +17 -6
- package/src/services/group-chat/group-chat.service.ts +1 -1
- package/src/services/jira-debug-session.service.ts +1 -1
- package/src/services/ppmbot/ppmbot-delegation.ts +1 -1
- package/src/services/ppmbot/ppmbot-service.ts +1 -1
- package/src/services/project-content-search.service.ts +45 -11
- package/src/services/proxy-agent-turn.ts +7 -3
- package/src/services/remote-desktop/mediamtx-catalog.ts +89 -0
- package/src/services/remote-desktop/mediamtx-config.ts +91 -0
- package/src/services/remote-desktop/mediamtx-install.service.ts +191 -0
- package/src/services/remote-desktop/mediamtx-paths.ts +51 -0
- package/src/services/remote-desktop/mediamtx-process.ts +152 -0
- package/src/services/remote-desktop/remote-desktop-capture-wayland.ts +312 -0
- package/src/services/remote-desktop/remote-desktop-capture.ts +60 -4
- package/src/services/remote-desktop/remote-desktop-portal.ts +529 -0
- package/src/services/remote-desktop/remote-desktop-requirements.ts +56 -20
- package/src/services/remote-desktop/remote-desktop-session.ts +77 -3
- package/src/services/remote-desktop/remote-desktop-whep-registry.ts +36 -0
- package/src/services/scheduler-runner.ts +2 -3
- package/src/services/session-trace/browser-trace-ingest.ts +131 -0
- package/src/services/session-trace/session-trace-cleanup.ts +65 -0
- package/src/services/session-trace/session-trace-db.ts +89 -0
- package/src/services/session-trace/session-trace-store.ts +132 -0
- package/src/services/session-trace/trace-coalescer.ts +86 -0
- package/src/services/session-trace/trace-recorder.ts +304 -0
- package/src/services/session-trace/trace-writer.ts +83 -0
- package/src/shared/android-avd.ts +53 -0
- package/src/shared/android-protocol.ts +184 -0
- package/src/shared/file-index-limits.ts +17 -0
- package/src/shared/session-trace.ts +61 -0
- package/src/types/chat.ts +17 -0
- package/src/types/config.ts +27 -0
- package/src/types/project.ts +9 -0
- package/src/web/app.tsx +5 -0
- package/src/web/components/android/android-apk-upload.ts +75 -0
- package/src/web/components/android/android-avd-create-dialog.tsx +305 -0
- package/src/web/components/android/android-avd-destroy-dialog.tsx +151 -0
- package/src/web/components/android/android-clipboard-panel.tsx +94 -0
- package/src/web/components/android/android-controls.tsx +128 -0
- package/src/web/components/android/android-coords.ts +99 -0
- package/src/web/components/android/android-device-list.tsx +329 -0
- package/src/web/components/android/android-install-panel.tsx +280 -0
- package/src/web/components/android/android-log-filter.ts +75 -0
- package/src/web/components/android/android-logcat-panel.tsx +214 -0
- package/src/web/components/android/android-screenshot-download.ts +56 -0
- package/src/web/components/android/android-tab.tsx +66 -0
- package/src/web/components/android/android-tools-drawer.tsx +76 -0
- package/src/web/components/android/android-viewer.tsx +200 -0
- package/src/web/components/android/android-ws-url.ts +21 -0
- package/src/web/components/android/open-android.ts +21 -0
- package/src/web/components/android/use-android-available.ts +29 -0
- package/src/web/components/android/use-android-keyboard.ts +111 -0
- package/src/web/components/android/use-android-session.ts +277 -0
- package/src/web/components/android/use-android-touch.ts +123 -0
- package/src/web/components/chat/chat-tab.tsx +28 -2
- package/src/web/components/chat/message-input.tsx +3 -5
- package/src/web/components/editor/compare-picker.tsx +12 -2
- package/src/web/components/explorer/file-tree.tsx +6 -7
- package/src/web/components/explorer/use-tree-row-dnd.ts +0 -2
- package/src/web/components/floating-window/window-content-registry.ts +8 -8
- package/src/web/components/layout/command-palette.tsx +31 -9
- package/src/web/components/layout/mobile-drawer.tsx +8 -1
- package/src/web/components/layout/nav-section-rail.tsx +8 -1
- package/src/web/components/layout/reparenting-tab.tsx +2 -2
- package/src/web/components/layout/tab-content.tsx +5 -0
- package/src/web/components/layout/tab-pool.tsx +31 -20
- package/src/web/components/remote-desktop/use-h264-canvas-decoder.ts +23 -1
- package/src/web/components/remote-desktop/use-remote-desktop-connection.ts +64 -6
- package/src/web/components/remote-desktop/use-webrtc-canvas-video.ts +255 -0
- package/src/web/components/root-error-boundary.tsx +5 -0
- package/src/web/components/settings/remote-desktop-settings-section.tsx +176 -0
- package/src/web/components/settings/settings-categories.ts +3 -0
- package/src/web/components/settings/settings-section-content.tsx +25 -18
- package/src/web/hooks/use-chat-prewarm.ts +53 -0
- package/src/web/hooks/use-chat.ts +18 -4
- package/src/web/hooks/use-file-index-invalidation.ts +7 -5
- package/src/web/hooks/use-global-events.ts +12 -1
- package/src/web/hooks/use-remote-file-search.ts +39 -0
- package/src/web/hooks/use-ui-preload.ts +38 -0
- package/src/web/index.html +43 -0
- package/src/web/lib/chunk-recovery.ts +5 -1
- package/src/web/lib/device-id.ts +39 -0
- package/src/web/lib/feature-badges.ts +2 -0
- package/src/web/lib/lazy-with-preload.tsx +43 -0
- package/src/web/lib/preload-ui.ts +60 -0
- package/src/web/lib/score-file-search.ts +27 -14
- package/src/web/lib/tab-type-icons.ts +2 -1
- package/src/web/lib/trace-boot.ts +8 -0
- package/src/web/lib/trace-client.ts +516 -0
- package/src/web/main.tsx +12 -0
- package/src/web/stores/file-store.ts +124 -18
- package/src/web/stores/panel-utils.ts +3 -0
- package/src/web/stores/tab-store.ts +2 -1
- package/src/web/stores/window-panel-persistence.ts +3 -0
- package/vite.config.ts +3 -0
- package/dist/web/assets/accounts-settings-section-DEIm-W-D.js +0 -1
- package/dist/web/assets/accounts-settings-section-DEIm-W-D.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-DEIm-W-D.js.gz +0 -0
- package/dist/web/assets/agent-session-sheet-CBMsnl_p.js.br +0 -0
- package/dist/web/assets/agent-session-sheet-CBMsnl_p.js.gz +0 -0
- package/dist/web/assets/agent-session-window-content-D9C9FA7E.js.br +0 -0
- package/dist/web/assets/agent-session-window-content-D9C9FA7E.js.gz +0 -0
- package/dist/web/assets/ai-resource-editor-DhUVgDEG.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-DhUVgDEG.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-CETpSpYd.js.br +0 -0
- package/dist/web/assets/ai-settings-section-CETpSpYd.js.gz +0 -0
- package/dist/web/assets/appearance-settings-section-BJUiLUb7.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-BJUiLUb7.js.gz +0 -0
- package/dist/web/assets/apps-panel-1VElRgV3.js.br +0 -0
- package/dist/web/assets/apps-panel-1VElRgV3.js.gz +0 -0
- package/dist/web/assets/audio-preview-DYkyHu5X.js.br +0 -0
- package/dist/web/assets/audio-preview-DYkyHu5X.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-DhTMSpSU.js +0 -1
- package/dist/web/assets/branch-review-tab-DhTMSpSU.js.br +0 -0
- package/dist/web/assets/branch-review-tab-DhTMSpSU.js.gz +0 -0
- package/dist/web/assets/chat-tab-Cg3BKugo.js +0 -15
- package/dist/web/assets/chat-tab-Cg3BKugo.js.br +0 -0
- package/dist/web/assets/chat-tab-Cg3BKugo.js.gz +0 -0
- package/dist/web/assets/chat-tab-tbUDK__Y.js +0 -1
- package/dist/web/assets/chat-tab-tbUDK__Y.js.br +0 -0
- package/dist/web/assets/chat-tab-tbUDK__Y.js.gz +0 -0
- package/dist/web/assets/code-editor-6ZiQehbr.js +0 -7
- package/dist/web/assets/code-editor-6ZiQehbr.js.br +0 -0
- package/dist/web/assets/code-editor-6ZiQehbr.js.gz +0 -0
- package/dist/web/assets/codex-reset-credit-button-Fr45FUxi.js.br +0 -0
- package/dist/web/assets/codex-reset-credit-button-Fr45FUxi.js.gz +0 -0
- package/dist/web/assets/conflict-editor-B-wdjSXI.js.br +0 -0
- package/dist/web/assets/conflict-editor-B-wdjSXI.js.gz +0 -0
- package/dist/web/assets/csv-preview-B6RodObB.js.br +0 -0
- package/dist/web/assets/csv-preview-B6RodObB.js.gz +0 -0
- package/dist/web/assets/database-viewer-CdPBUQPY.js.br +0 -0
- package/dist/web/assets/database-viewer-CdPBUQPY.js.gz +0 -0
- package/dist/web/assets/design-settings-section-BpCpaBwL.js.br +0 -0
- package/dist/web/assets/design-settings-section-BpCpaBwL.js.gz +0 -0
- package/dist/web/assets/design-skill-suggestion-DkT2E2IV.js.br +0 -0
- package/dist/web/assets/design-skill-suggestion-DkT2E2IV.js.gz +0 -0
- package/dist/web/assets/design-tab-BZb9eemI.js.br +0 -0
- package/dist/web/assets/design-tab-BZb9eemI.js.gz +0 -0
- package/dist/web/assets/designs-sidebar-panel-CF4tp6j-.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-CF4tp6j-.js.gz +0 -0
- package/dist/web/assets/diff-viewer-BqEqwSw6.js.br +0 -0
- package/dist/web/assets/diff-viewer-BqEqwSw6.js.gz +0 -0
- package/dist/web/assets/edit-diff-preview-DD4HayXY.js.br +0 -0
- package/dist/web/assets/edit-diff-preview-DD4HayXY.js.gz +0 -0
- package/dist/web/assets/editor-language-service-CkA5sEdV.js.br +0 -0
- package/dist/web/assets/editor-language-service-CkA5sEdV.js.gz +0 -0
- package/dist/web/assets/explorer-body-Ds7oKuz7.js +0 -2
- package/dist/web/assets/explorer-body-Ds7oKuz7.js.br +0 -0
- package/dist/web/assets/explorer-body-Ds7oKuz7.js.gz +0 -0
- package/dist/web/assets/explorer-window-content-CRJ2eMZ4.js.br +0 -0
- package/dist/web/assets/explorer-window-content-CRJ2eMZ4.js.gz +0 -0
- package/dist/web/assets/extension-manager-section-DwQTdCII.js.br +0 -0
- package/dist/web/assets/extension-manager-section-DwQTdCII.js.gz +0 -0
- package/dist/web/assets/extension-webview-CMq-VTLu.js.br +0 -0
- package/dist/web/assets/extension-webview-CMq-VTLu.js.gz +0 -0
- package/dist/web/assets/file-store-DY1_0nzY.js +0 -1
- package/dist/web/assets/file-store-DY1_0nzY.js.br +0 -0
- package/dist/web/assets/file-store-DY1_0nzY.js.gz +0 -0
- package/dist/web/assets/files-settings-section-B2lcyh-6.js.br +0 -0
- package/dist/web/assets/files-settings-section-B2lcyh-6.js.gz +0 -0
- package/dist/web/assets/general-settings-section-Doepm2sH.js.br +0 -0
- package/dist/web/assets/general-settings-section-Doepm2sH.js.gz +0 -0
- package/dist/web/assets/git-log-panel-CJakNMDc.js.br +0 -0
- package/dist/web/assets/git-log-panel-CJakNMDc.js.gz +0 -0
- package/dist/web/assets/glide-data-grid-C_SeOhSq.js.br +0 -0
- package/dist/web/assets/glide-data-grid-C_SeOhSq.js.gz +0 -0
- package/dist/web/assets/group-chat-tab--by1xCQW.js +0 -1
- package/dist/web/assets/group-chat-tab--by1xCQW.js.br +0 -0
- package/dist/web/assets/group-chat-tab--by1xCQW.js.gz +0 -0
- package/dist/web/assets/index-DhWjx5iR.js +0 -52
- package/dist/web/assets/index-DhWjx5iR.js.br +0 -0
- package/dist/web/assets/index-DhWjx5iR.js.gz +0 -0
- package/dist/web/assets/index-oIvYSKTT.css +0 -1
- package/dist/web/assets/index-oIvYSKTT.css.br +0 -0
- package/dist/web/assets/index-oIvYSKTT.css.gz +0 -0
- package/dist/web/assets/keybindings-store-30LYZU0l.js +0 -1
- package/dist/web/assets/keyboard-shortcuts-section-BgZe3QDr.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-BgZe3QDr.js.gz +0 -0
- package/dist/web/assets/language-servers-section-CCMzgOaE.js.br +0 -0
- package/dist/web/assets/language-servers-section-CCMzgOaE.js.gz +0 -0
- package/dist/web/assets/lsp-client-B10suuaZ.js.br +0 -0
- package/dist/web/assets/lsp-client-B10suuaZ.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-AHHFS3jc.js.br +0 -0
- package/dist/web/assets/markdown-renderer-AHHFS3jc.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-DxnXtBoj.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-CqCsLWSr.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-CqCsLWSr.js.gz +0 -0
- package/dist/web/assets/new-design-dialog-B9tgnQXq.js +0 -1
- package/dist/web/assets/new-design-dialog-B9tgnQXq.js.br +0 -0
- package/dist/web/assets/new-design-dialog-B9tgnQXq.js.gz +0 -0
- package/dist/web/assets/notification-store-HUVzO_bp.js +0 -1
- package/dist/web/assets/notifications-settings-section-CXgzH_bK.js.br +0 -0
- package/dist/web/assets/notifications-settings-section-CXgzH_bK.js.gz +0 -0
- package/dist/web/assets/overview-panel-BYB8mgRE.js.br +0 -0
- package/dist/web/assets/overview-panel-BYB8mgRE.js.gz +0 -0
- package/dist/web/assets/panel-store-CWHPmHwj.js +0 -1
- package/dist/web/assets/panel-store-CWHPmHwj.js.br +0 -0
- package/dist/web/assets/panel-store-CWHPmHwj.js.gz +0 -0
- package/dist/web/assets/performance-panel-Dpuq3g0W.js.br +0 -0
- package/dist/web/assets/performance-panel-Dpuq3g0W.js.gz +0 -0
- package/dist/web/assets/postgres-viewer-DW0Gkmow.js.br +0 -0
- package/dist/web/assets/postgres-viewer-DW0Gkmow.js.gz +0 -0
- package/dist/web/assets/ppmbot-settings-section-DFtlGoW6.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-DFtlGoW6.js.gz +0 -0
- package/dist/web/assets/pptx-export-CNyG32Xr.js.br +0 -0
- package/dist/web/assets/pptx-export-CNyG32Xr.js.gz +0 -0
- package/dist/web/assets/problems-panel-V5zqpuXq.js.br +0 -0
- package/dist/web/assets/problems-panel-V5zqpuXq.js.gz +0 -0
- package/dist/web/assets/process-table-DAj46HIl.js +0 -1
- package/dist/web/assets/process-table-DAj46HIl.js.br +0 -0
- package/dist/web/assets/process-table-DAj46HIl.js.gz +0 -0
- package/dist/web/assets/proxy-settings-section-B7AVlTfY.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-B7AVlTfY.js.gz +0 -0
- package/dist/web/assets/query-audit-section-gHmRfWKr.js.br +0 -0
- package/dist/web/assets/query-audit-section-gHmRfWKr.js.gz +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-Cgoznh8L.js +0 -1
- package/dist/web/assets/remote-desktop-clipboard-notice-Cgoznh8L.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-Cgoznh8L.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-X12QbPhO.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-sheet-X12QbPhO.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-X12QbPhO.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DsSHawSK.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-view-DsSHawSK.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DsSHawSK.js.gz +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-CHiQEd9Q.js +0 -1
- package/dist/web/assets/remote-desktop-readiness-gate-CHiQEd9Q.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-CHiQEd9Q.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-BnznIby3.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-BnznIby3.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-BnznIby3.js.gz +0 -0
- package/dist/web/assets/schedules-settings-section-sYDAsBMO.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-sYDAsBMO.js.gz +0 -0
- package/dist/web/assets/send-to-chat-CCdOrKc7.js.br +0 -0
- package/dist/web/assets/send-to-chat-CCdOrKc7.js.gz +0 -0
- package/dist/web/assets/services-panel-CKa2aP1d.js.br +0 -0
- package/dist/web/assets/services-panel-CKa2aP1d.js.gz +0 -0
- package/dist/web/assets/settings-body-CEIF8lkl.js +0 -2
- package/dist/web/assets/settings-body-CEIF8lkl.js.br +0 -0
- package/dist/web/assets/settings-body-CEIF8lkl.js.gz +0 -0
- package/dist/web/assets/settings-store-DfuiLq_9.js.br +0 -0
- package/dist/web/assets/settings-store-DfuiLq_9.js.gz +0 -0
- package/dist/web/assets/settings-tab-Du5AUPni.js +0 -1
- package/dist/web/assets/settings-window-content-BTflfLez.js +0 -1
- package/dist/web/assets/slash-command-picker-CLevA_Gf.js.br +0 -0
- package/dist/web/assets/slash-command-picker-CLevA_Gf.js.gz +0 -0
- package/dist/web/assets/sql-query-editor-Db8b0jEr.js.br +0 -0
- package/dist/web/assets/sql-query-editor-Db8b0jEr.js.gz +0 -0
- package/dist/web/assets/sqlite-viewer-VzYLMqkD.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-VzYLMqkD.js.gz +0 -0
- package/dist/web/assets/system-monitor-body-BR60W_mG.js.br +0 -0
- package/dist/web/assets/system-monitor-body-BR60W_mG.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-BYpantE2.js +0 -1
- package/dist/web/assets/tab-host-window-content-BL61SB5m.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-BL61SB5m.js.gz +0 -0
- package/dist/web/assets/terminal-tab-B4y6at4h.js.br +0 -0
- package/dist/web/assets/terminal-tab-B4y6at4h.js.gz +0 -0
- package/dist/web/assets/tool-cards-K0r_yxI0.js.br +0 -0
- package/dist/web/assets/tool-cards-K0r_yxI0.js.gz +0 -0
- package/dist/web/assets/use-inline-blame-BK23icsE.js.br +0 -0
- package/dist/web/assets/use-inline-blame-BK23icsE.js.gz +0 -0
- package/dist/web/assets/use-lsp-CRdCPCKW.js.br +0 -0
- package/dist/web/assets/use-lsp-CRdCPCKW.js.gz +0 -0
- package/dist/web/assets/use-process-kill-BWYX03KF.js.br +0 -0
- package/dist/web/assets/use-process-kill-BWYX03KF.js.gz +0 -0
- package/dist/web/assets/video-preview-DugVkMB7.js +0 -1
- package/dist/web/assets/video-preview-DugVkMB7.js.br +0 -0
- package/dist/web/assets/video-preview-DugVkMB7.js.gz +0 -0
- package/dist/web/assets/voice-settings-section-Ceihggqf.js.br +0 -0
- package/dist/web/assets/voice-settings-section-Ceihggqf.js.gz +0 -0
- /package/dist/web/assets/{__vite-browser-external-B_XMEguz.js → __vite-browser-external-C5mXParC.js} +0 -0
- /package/dist/web/assets/{agent-session-sheet-store-DO682WSg.js → agent-session-sheet-store-_OeezCXB.js} +0 -0
- /package/dist/web/assets/{api-settings-CpO8SPk9.js → api-settings-Cc_CpfmC.js} +0 -0
- /package/dist/web/assets/{api-settings-CpO8SPk9.js.br → api-settings-Cc_CpfmC.js.br} +0 -0
- /package/dist/web/assets/{api-settings-CpO8SPk9.js.gz → api-settings-Cc_CpfmC.js.gz} +0 -0
- /package/dist/web/assets/{api-themes-CJipDH_l.js → api-themes-BtMBSjuM.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-Bw_xiOXX.js → can-open-in-ppm-DeE2-kd5.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-Bw_xiOXX.js.br → can-open-in-ppm-DeE2-kd5.js.br} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-Bw_xiOXX.js.gz → can-open-in-ppm-DeE2-kd5.js.gz} +0 -0
- /package/dist/web/assets/{csv-parser-DcRWxcNV.js → csv-parser-CoxPdyLw.js} +0 -0
- /package/dist/web/assets/{csv-parser-DcRWxcNV.js.br → csv-parser-CoxPdyLw.js.br} +0 -0
- /package/dist/web/assets/{csv-parser-DcRWxcNV.js.gz → csv-parser-CoxPdyLw.js.gz} +0 -0
- /package/dist/web/assets/{design-export-client-CHffN3DM.js → design-export-client-BfdZB7xK.js} +0 -0
- /package/dist/web/assets/{design-export-client-CHffN3DM.js.br → design-export-client-BfdZB7xK.js.br} +0 -0
- /package/dist/web/assets/{design-export-client-CHffN3DM.js.gz → design-export-client-BfdZB7xK.js.gz} +0 -0
- /package/dist/web/assets/{design-responsive-dialog-DSCpv6O1.js → design-responsive-dialog-BiYy3ibS.js} +0 -0
- /package/dist/web/assets/{design-responsive-dialog-DSCpv6O1.js.br → design-responsive-dialog-BiYy3ibS.js.br} +0 -0
- /package/dist/web/assets/{design-responsive-dialog-DSCpv6O1.js.gz → design-responsive-dialog-BiYy3ibS.js.gz} +0 -0
- /package/dist/web/assets/{design-system-status-label-B_0I_3a8.js → design-system-status-label-ekiLyjKn.js} +0 -0
- /package/dist/web/assets/{docx-preview-B3eJyY2y.js → docx-preview-Dt6RQpfA.js} +0 -0
- /package/dist/web/assets/{docx-preview-B3eJyY2y.js.br → docx-preview-Dt6RQpfA.js.br} +0 -0
- /package/dist/web/assets/{docx-preview-B3eJyY2y.js.gz → docx-preview-Dt6RQpfA.js.gz} +0 -0
- /package/dist/web/assets/{editor-font-BNwo7zo5.js → editor-font-CBszn6vt.js} +0 -0
- /package/dist/web/assets/{format-bytes-CRZfxO2J.js → format-bytes-FQmpZ25A.js} +0 -0
- /package/dist/web/assets/{image-gallery-DC3gRAqk.js → image-gallery-B16hO6Ab.js} +0 -0
- /package/dist/web/assets/{image-preview-geometry-DN3DZQp0.js → image-preview-geometry-D4Ihz4UV.js} +0 -0
- /package/dist/web/assets/{lib-B9k5tn9s.js → lib-6APiJkU3.js} +0 -0
- /package/dist/web/assets/{lib-B9k5tn9s.js.br → lib-6APiJkU3.js.br} +0 -0
- /package/dist/web/assets/{lib-B9k5tn9s.js.gz → lib-6APiJkU3.js.gz} +0 -0
- /package/dist/web/assets/{libesm-5f7T4AHA.js → libesm-5wREk7JN.js} +0 -0
- /package/dist/web/assets/{libesm-5f7T4AHA.js.br → libesm-5wREk7JN.js.br} +0 -0
- /package/dist/web/assets/{libesm-5f7T4AHA.js.gz → libesm-5wREk7JN.js.gz} +0 -0
- /package/dist/web/assets/{media-url-CCGOIxzS.js → media-url-CrT-qulZ.js} +0 -0
- /package/dist/web/assets/{metric-chart-canvas-CjFbZuhk.js → metric-chart-canvas-D7f-LQ8x.js} +0 -0
- /package/dist/web/assets/{metric-chart-canvas-CjFbZuhk.js.br → metric-chart-canvas-D7f-LQ8x.js.br} +0 -0
- /package/dist/web/assets/{metric-chart-canvas-CjFbZuhk.js.gz → metric-chart-canvas-D7f-LQ8x.js.gz} +0 -0
- /package/dist/web/assets/{monaco-dotenv-language-Bwq3gQsi.js → monaco-dotenv-language-DbSss7YR.js} +0 -0
- /package/dist/web/assets/{onboarding-entry-CuH1Kqwu.js → onboarding-entry-CGFdGLLP.js} +0 -0
- /package/dist/web/assets/{onboarding-entry-CuH1Kqwu.js.br → onboarding-entry-CGFdGLLP.js.br} +0 -0
- /package/dist/web/assets/{onboarding-entry-CuH1Kqwu.js.gz → onboarding-entry-CGFdGLLP.js.gz} +0 -0
- /package/dist/web/assets/{pdf-preview-X8bdpfE9.js → pdf-preview-B8A4T-ES.js} +0 -0
- /package/dist/web/assets/{pdf-preview-X8bdpfE9.js.br → pdf-preview-B8A4T-ES.js.br} +0 -0
- /package/dist/web/assets/{pdf-preview-X8bdpfE9.js.gz → pdf-preview-B8A4T-ES.js.gz} +0 -0
- /package/dist/web/assets/{separator-DMu7VFQa.js → separator-dHj3Km--.js} +0 -0
- /package/dist/web/assets/{sortable-header-CipIP7aH.js → sortable-header-BOa8o7NJ.js} +0 -0
- /package/dist/web/assets/{sortable-header-CipIP7aH.js.br → sortable-header-BOa8o7NJ.js.br} +0 -0
- /package/dist/web/assets/{sortable-header-CipIP7aH.js.gz → sortable-header-BOa8o7NJ.js.gz} +0 -0
- /package/dist/web/assets/{use-blob-url-DjuRQWnR.js → use-blob-url-BC69n15x.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-Be4L1NHd.js → vendor-xterm-CfasyE0m.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-Be4L1NHd.js.br → vendor-xterm-CfasyE0m.js.br} +0 -0
- /package/dist/web/assets/{vendor-xterm-Be4L1NHd.js.gz → vendor-xterm-CfasyE0m.js.gz} +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the Android SDK is, and which of its tools this host actually has.
|
|
3
|
+
*
|
|
4
|
+
* Resolution order (plan §5): the path the user configured -> the standard Android env vars ->
|
|
5
|
+
* the per-OS default location -> whatever is on PATH. Everything here is read-only and safe to
|
|
6
|
+
* call when no SDK exists; the answer then carries the reasons, which is what the setup screen
|
|
7
|
+
* renders instead of an indefinite spinner.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
+
import { homedir, platform } from "node:os";
|
|
11
|
+
import { join, resolve } from "node:path";
|
|
12
|
+
|
|
13
|
+
export interface SdkTool {
|
|
14
|
+
/** Absolute path to the binary, or null when this host does not have it. */
|
|
15
|
+
path: string | null;
|
|
16
|
+
/** Version string as the tool itself reports it, when it could be run. */
|
|
17
|
+
version: string | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AndroidSdk {
|
|
21
|
+
root: string | null;
|
|
22
|
+
/** Which step of the resolution order answered, for the setup screen to explain itself. */
|
|
23
|
+
source: "configured" | "env" | "default-location" | "path" | "not-found";
|
|
24
|
+
emulator: SdkTool;
|
|
25
|
+
adb: SdkTool;
|
|
26
|
+
avdmanager: SdkTool;
|
|
27
|
+
sdkmanager: SdkTool;
|
|
28
|
+
/** AVD home in force for this process, and whether it came from the environment. */
|
|
29
|
+
avdHome: string;
|
|
30
|
+
avdHomeFromEnv: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const exe = (name: string) => (platform() === "win32" ? `${name}.exe` : name);
|
|
34
|
+
const bat = (name: string) => (platform() === "win32" ? `${name}.bat` : name);
|
|
35
|
+
|
|
36
|
+
/** Per-OS default SDK locations, in the order Android's own tooling looks. */
|
|
37
|
+
function defaultSdkLocations(): string[] {
|
|
38
|
+
const home = homedir();
|
|
39
|
+
switch (platform()) {
|
|
40
|
+
case "darwin":
|
|
41
|
+
return [join(home, "Library", "Android", "sdk")];
|
|
42
|
+
case "win32":
|
|
43
|
+
return [
|
|
44
|
+
join(process.env.LOCALAPPDATA ?? join(home, "AppData", "Local"), "Android", "Sdk"),
|
|
45
|
+
];
|
|
46
|
+
default:
|
|
47
|
+
return [join(home, "Android", "Sdk"), join(home, "android-sdk")];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function looksLikeSdk(dir: string): boolean {
|
|
52
|
+
// An SDK root always has at least one of these; a bare directory that merely exists does not.
|
|
53
|
+
return existsSync(join(dir, "emulator")) || existsSync(join(dir, "platform-tools"));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The AVD home this process would use.
|
|
58
|
+
*
|
|
59
|
+
* `ANDROID_AVD_HOME` **replaces** the default rather than adding to it — measured: with it set,
|
|
60
|
+
* `emulator -list-avds` shows only the AVDs under it and the user's own disappear entirely. So
|
|
61
|
+
* PPM must never set it process-wide; it is read here only to report what is in force.
|
|
62
|
+
*/
|
|
63
|
+
export function resolveAvdHome(): { dir: string; fromEnv: boolean } {
|
|
64
|
+
const env = process.env.ANDROID_AVD_HOME?.trim();
|
|
65
|
+
if (env) return { dir: resolve(env), fromEnv: true };
|
|
66
|
+
return { dir: join(homedir(), ".android", "avd"), fromEnv: false };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The env an SDK **child process** needs to work in a given AVD home.
|
|
71
|
+
*
|
|
72
|
+
* `ANDROID_AVD_HOME` **replaces** the default rather than adding to it (measured in Phase 0), so
|
|
73
|
+
* PPM must never set it process-wide — but a child that is meant to act on a non-default home
|
|
74
|
+
* has no other way to be told. Measured the hard way: `avdmanager create avd` without this
|
|
75
|
+
* writes into **`~/.android/avd`**, i.e. straight into the user's own AVDs, whatever home PPM
|
|
76
|
+
* was asked to use.
|
|
77
|
+
*
|
|
78
|
+
* Left unset when the home already *is* the default, so the common case runs with the exact
|
|
79
|
+
* environment the tools expect.
|
|
80
|
+
*/
|
|
81
|
+
export function avdHomeEnv(avdHome: string): NodeJS.ProcessEnv {
|
|
82
|
+
const env = { ...process.env };
|
|
83
|
+
const defaultHome = join(homedir(), ".android", "avd");
|
|
84
|
+
if (avdHome && resolve(avdHome) !== defaultHome) env.ANDROID_AVD_HOME = resolve(avdHome);
|
|
85
|
+
return env;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function toolVersion(path: string, args: string[], pick: (out: string) => string | null): Promise<string | null> {
|
|
89
|
+
try {
|
|
90
|
+
const proc = Bun.spawn([path, ...args], { stdout: "pipe", stderr: "pipe", windowsHide: true });
|
|
91
|
+
const [out, errOut] = await Promise.all([
|
|
92
|
+
new Response(proc.stdout).text(),
|
|
93
|
+
new Response(proc.stderr).text(),
|
|
94
|
+
]);
|
|
95
|
+
await proc.exited;
|
|
96
|
+
return pick(`${out}\n${errOut}`);
|
|
97
|
+
} catch {
|
|
98
|
+
// Bun.spawn THROWS synchronously on a missing binary rather than reporting it (see
|
|
99
|
+
// `host-info/spawn-runner.ts`), and the throw escapes an awaited try placed further out.
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function firstLine(out: string): string | null {
|
|
105
|
+
const line = out.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
|
|
106
|
+
return line ?? null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function describeTool(
|
|
110
|
+
candidate: string | null,
|
|
111
|
+
args: string[],
|
|
112
|
+
pick: (out: string) => string | null,
|
|
113
|
+
): Promise<SdkTool> {
|
|
114
|
+
if (!candidate || !existsSync(candidate)) return { path: null, version: null };
|
|
115
|
+
return { path: candidate, version: await toolVersion(candidate, args, pick) };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Resolve the SDK and probe its tools. Never throws: a host with no SDK gets a populated shape. */
|
|
119
|
+
export async function discoverSdk(configuredRoot?: string | null): Promise<AndroidSdk> {
|
|
120
|
+
let root: string | null = null;
|
|
121
|
+
let source: AndroidSdk["source"] = "not-found";
|
|
122
|
+
|
|
123
|
+
const configured = configuredRoot?.trim();
|
|
124
|
+
if (configured && looksLikeSdk(configured)) {
|
|
125
|
+
root = resolve(configured);
|
|
126
|
+
source = "configured";
|
|
127
|
+
}
|
|
128
|
+
if (!root) {
|
|
129
|
+
for (const key of ["ANDROID_HOME", "ANDROID_SDK_ROOT"]) {
|
|
130
|
+
const v = process.env[key]?.trim();
|
|
131
|
+
if (v && looksLikeSdk(v)) { root = resolve(v); source = "env"; break; }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (!root) {
|
|
135
|
+
for (const dir of defaultSdkLocations()) {
|
|
136
|
+
if (looksLikeSdk(dir)) { root = dir; source = "default-location"; break; }
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// PATH is the last resort and only for adb: a loose `adb` on PATH (Linux distros package it
|
|
141
|
+
// separately from the SDK) is usable even when no SDK root exists.
|
|
142
|
+
const pathAdb = Bun.which("adb");
|
|
143
|
+
if (!root && pathAdb) source = "path";
|
|
144
|
+
|
|
145
|
+
const emulatorPath = root ? join(root, "emulator", exe("emulator")) : null;
|
|
146
|
+
const adbPath = root && existsSync(join(root, "platform-tools", exe("adb")))
|
|
147
|
+
? join(root, "platform-tools", exe("adb"))
|
|
148
|
+
: pathAdb;
|
|
149
|
+
const cmdlineBin = root ? join(root, "cmdline-tools", "latest", "bin") : null;
|
|
150
|
+
|
|
151
|
+
const [emulator, adb, avdmanager, sdkmanager] = await Promise.all([
|
|
152
|
+
describeTool(emulatorPath, ["-version"], (o) =>
|
|
153
|
+
o.split("\n").find((l) => l.includes("Android emulator version"))?.trim() ?? null),
|
|
154
|
+
describeTool(adbPath, ["version"], firstLine),
|
|
155
|
+
describeTool(cmdlineBin ? join(cmdlineBin, bat("avdmanager")) : null, ["list", "target"],
|
|
156
|
+
() => "present"),
|
|
157
|
+
describeTool(cmdlineBin ? join(cmdlineBin, bat("sdkmanager")) : null, ["--version"], firstLine),
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
const avdHome = resolveAvdHome();
|
|
161
|
+
return {
|
|
162
|
+
root, source, emulator, adb, avdmanager, sdkmanager,
|
|
163
|
+
avdHome: avdHome.dir, avdHomeFromEnv: avdHome.fromEnv,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Whether an AVD's config.ini enables the hardware keyboard. */
|
|
168
|
+
export function avdHasHardwareKeyboard(avdConfigIni: string): boolean {
|
|
169
|
+
try {
|
|
170
|
+
for (const line of readFileSync(avdConfigIni, "utf8").split("\n")) {
|
|
171
|
+
const t = line.trim();
|
|
172
|
+
if (t.startsWith("hw.keyboard=")) return t.slice("hw.keyboard=".length).trim() === "yes";
|
|
173
|
+
}
|
|
174
|
+
} catch {
|
|
175
|
+
// An unreadable config is reported as "no" so the UI warns rather than promising a keyboard.
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which Android system images this host already has.
|
|
3
|
+
*
|
|
4
|
+
* Read from **disk**, not from `sdkmanager --list_installed`. Three reasons, all measured:
|
|
5
|
+
*
|
|
6
|
+
* - `sdkmanager` takes seconds ("Loading local repository…") and prints a progress bar into
|
|
7
|
+
* stdout that any parser has to strip; a tab that lists images on open would stall on it.
|
|
8
|
+
* - Every installed image ships a `source.properties` carrying exactly what is needed — API
|
|
9
|
+
* level, ABI, tag, a display description — so the subprocess buys nothing.
|
|
10
|
+
* - A host with the images but no `cmdline-tools` (they are a separate SDK package) can still
|
|
11
|
+
* create an AVD, and going through `sdkmanager` would report "no images" there.
|
|
12
|
+
*
|
|
13
|
+
* Installing a *new* image is deliberately not here: the plan is explicit that PPM must not
|
|
14
|
+
* accept an SDK licence or start a multi-gigabyte download on its own.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
|
|
19
|
+
export interface SystemImage {
|
|
20
|
+
/** The sdkmanager package path, e.g. `system-images;android-35;google_apis_playstore;x86_64`. */
|
|
21
|
+
id: string;
|
|
22
|
+
apiLevel: number | null;
|
|
23
|
+
abi: string;
|
|
24
|
+
/** `google_apis_playstore`, `default`, `android-automotive`… */
|
|
25
|
+
tag: string;
|
|
26
|
+
/** What Google calls it, e.g. "Google APIs PlayStore,Tablet". */
|
|
27
|
+
tagDisplay: string;
|
|
28
|
+
description: string;
|
|
29
|
+
/** `image.sysdir.1` wants this exact relative form, trailing slash included. */
|
|
30
|
+
sysdir: string;
|
|
31
|
+
/** True when the image carries Play Store — such an AVD cannot be rooted. */
|
|
32
|
+
playStore: boolean;
|
|
33
|
+
bytes: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function parseProperties(text: string): Record<string, string> {
|
|
37
|
+
const out: Record<string, string> = {};
|
|
38
|
+
for (const line of text.split("\n")) {
|
|
39
|
+
const trimmed = line.trim();
|
|
40
|
+
if (trimmed.length === 0 || trimmed.startsWith("#")) continue;
|
|
41
|
+
const eq = trimmed.indexOf("=");
|
|
42
|
+
if (eq <= 0) continue;
|
|
43
|
+
out[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1).trim();
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Recursive size of an image directory, so the UI can say what a delete would free. */
|
|
49
|
+
function directoryBytes(dir: string, depth = 0): number {
|
|
50
|
+
if (depth > 4) return 0;
|
|
51
|
+
let total = 0;
|
|
52
|
+
let entries;
|
|
53
|
+
try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return 0; }
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
const full = join(dir, entry.name);
|
|
56
|
+
try {
|
|
57
|
+
if (entry.isDirectory()) total += directoryBytes(full, depth + 1);
|
|
58
|
+
else if (entry.isFile()) total += statSync(full).size;
|
|
59
|
+
} catch { /* it went away mid-walk */ }
|
|
60
|
+
}
|
|
61
|
+
return total;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The tree is `system-images/<api>/<tag>/<abi>/`, and only a directory with a
|
|
66
|
+
* `source.properties` counts — a half-deleted package leaves the directories behind.
|
|
67
|
+
*/
|
|
68
|
+
export function listSystemImages(sdkRoot: string | null): SystemImage[] {
|
|
69
|
+
if (!sdkRoot) return [];
|
|
70
|
+
const root = join(sdkRoot, "system-images");
|
|
71
|
+
if (!existsSync(root)) return [];
|
|
72
|
+
|
|
73
|
+
const images: SystemImage[] = [];
|
|
74
|
+
for (const api of safeList(root)) {
|
|
75
|
+
for (const tagDir of safeList(join(root, api))) {
|
|
76
|
+
for (const abi of safeList(join(root, api, tagDir))) {
|
|
77
|
+
const dir = join(root, api, tagDir, abi);
|
|
78
|
+
const propsPath = join(dir, "source.properties");
|
|
79
|
+
if (!existsSync(propsPath)) continue;
|
|
80
|
+
|
|
81
|
+
let props: Record<string, string>;
|
|
82
|
+
try { props = parseProperties(readFileSync(propsPath, "utf8")); } catch { continue; }
|
|
83
|
+
|
|
84
|
+
const apiLevel = Number(props["AndroidVersion.ApiLevel"]);
|
|
85
|
+
// `SystemImage.TagId` can be a comma list (`google_apis_playstore,tablet`); the first is
|
|
86
|
+
// the one the package path uses, and the rest are extra traits.
|
|
87
|
+
const tag = (props["SystemImage.TagId"] ?? tagDir).split(",")[0]!.trim();
|
|
88
|
+
images.push({
|
|
89
|
+
id: `system-images;${api};${tagDir};${abi}`,
|
|
90
|
+
apiLevel: Number.isFinite(apiLevel) ? apiLevel : null,
|
|
91
|
+
abi: props["SystemImage.Abi"] ?? abi,
|
|
92
|
+
tag,
|
|
93
|
+
tagDisplay: props["SystemImage.TagDisplay"] ?? tag,
|
|
94
|
+
description: props["Pkg.Desc"] ?? "",
|
|
95
|
+
sysdir: `system-images/${api}/${tagDir}/${abi}/`,
|
|
96
|
+
playStore: tagDir.includes("playstore") || tag.includes("playstore"),
|
|
97
|
+
bytes: directoryBytes(dir),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Newest API first: that is almost always the one being reached for.
|
|
103
|
+
return images.sort((a, b) => (b.apiLevel ?? 0) - (a.apiLevel ?? 0) || a.id.localeCompare(b.id));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function safeList(dir: string): string[] {
|
|
107
|
+
try {
|
|
108
|
+
return readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
109
|
+
} catch {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Whether an image can run on this host without full-system emulation.
|
|
116
|
+
*
|
|
117
|
+
* An arm64 image on an x86_64 host boots, and then takes minutes per screen — which reads as a
|
|
118
|
+
* broken emulator rather than the wrong ABI, so the picker says so before the AVD exists.
|
|
119
|
+
*/
|
|
120
|
+
export function abiMatchesHost(abi: string, hostArch = process.arch): boolean {
|
|
121
|
+
if (hostArch === "x64") return abi === "x86_64" || abi === "x86";
|
|
122
|
+
if (hostArch === "arm64") return abi === "arm64-v8a" || abi === "armeabi-v7a";
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
ChatEvent,
|
|
11
11
|
ChatMessage,
|
|
12
12
|
SendMessageOpts,
|
|
13
|
+
PrewarmInput,
|
|
13
14
|
} from "../providers/provider.interface.ts";
|
|
14
15
|
import { compareSessionsByActivity } from "../types/chat.ts";
|
|
15
16
|
import { buildDesignInstructions } from "./design/design-instructions.ts";
|
|
@@ -21,6 +22,11 @@ import { scheduleTurnSnapshot } from "./design/design-turn-snapshot.ts";
|
|
|
21
22
|
import { designMcpAccessFor } from "./design/mcp/design-mcp-access.ts";
|
|
22
23
|
import { designMcpTokens } from "./design/mcp/design-mcp-tokens.ts";
|
|
23
24
|
import { isTerminalAgentStatus } from "../shared/background-agent-status.ts";
|
|
25
|
+
import { TraceRun, traceAbort, traceApproval, traceFollowUp } from "./session-trace/trace-recorder.ts";
|
|
26
|
+
import type { TraceOrigin } from "../shared/session-trace.ts";
|
|
27
|
+
|
|
28
|
+
/** What a caller passes to send: the provider's options plus which door the run came through. */
|
|
29
|
+
export type ChatSendOpts = SendMessageOpts & { origin?: TraceOrigin };
|
|
24
30
|
|
|
25
31
|
/**
|
|
26
32
|
* Events after which a design session's files may have settled: the end of a turn, and a
|
|
@@ -65,6 +71,12 @@ class ChatService {
|
|
|
65
71
|
return session;
|
|
66
72
|
}
|
|
67
73
|
|
|
74
|
+
/** Start the process the next new chat in a project will run on, where the provider can. */
|
|
75
|
+
async prewarm(providerId: string | undefined, input: PrewarmInput): Promise<void> {
|
|
76
|
+
const provider = providerId ? providerRegistry.get(providerId) : providerRegistry.getDefault();
|
|
77
|
+
await provider?.prewarm?.(input);
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
async resumeSession(
|
|
69
81
|
providerId: string,
|
|
70
82
|
sessionId: string,
|
|
@@ -110,18 +122,48 @@ class ChatService {
|
|
|
110
122
|
return provider.deleteSession(sessionId);
|
|
111
123
|
}
|
|
112
124
|
|
|
125
|
+
/**
|
|
126
|
+
* The one door every run goes through — WebSocket, scheduler, bots, group chat, Jira, CLI —
|
|
127
|
+
* which is why it is also where a run is written to the session trace. The trace observes
|
|
128
|
+
* and never alters: every event is yielded exactly as the provider produced it.
|
|
129
|
+
*/
|
|
113
130
|
async *sendMessage(
|
|
114
131
|
providerId: string,
|
|
115
132
|
sessionId: string,
|
|
116
133
|
message: string,
|
|
117
|
-
opts?:
|
|
134
|
+
opts?: ChatSendOpts,
|
|
135
|
+
): AsyncIterable<ChatEvent> {
|
|
136
|
+
const { origin, ...sendOpts } = opts ?? {};
|
|
137
|
+
const run = new TraceRun({ sessionId, providerId, origin, message, opts: sendOpts });
|
|
138
|
+
let outcome: "completed" | "consumer_closed" | "failed" = "consumer_closed";
|
|
139
|
+
try {
|
|
140
|
+
yield* this.streamRun(run, providerId, sessionId, message, sendOpts);
|
|
141
|
+
outcome = "completed";
|
|
142
|
+
} catch (e) {
|
|
143
|
+
run.fail(e);
|
|
144
|
+
outcome = "failed";
|
|
145
|
+
throw e;
|
|
146
|
+
} finally {
|
|
147
|
+
run.end(outcome);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private async *streamRun(
|
|
152
|
+
run: TraceRun,
|
|
153
|
+
providerId: string,
|
|
154
|
+
sessionId: string,
|
|
155
|
+
message: string,
|
|
156
|
+
opts: SendMessageOpts,
|
|
118
157
|
): AsyncIterable<ChatEvent> {
|
|
119
158
|
const provider = providerRegistry.get(providerId);
|
|
120
159
|
if (!provider) {
|
|
121
|
-
|
|
160
|
+
const event: ChatEvent = { type: "error", message: `Provider "${providerId}" not found` };
|
|
161
|
+
run.observe(event);
|
|
162
|
+
yield event;
|
|
122
163
|
return;
|
|
123
164
|
}
|
|
124
165
|
const prepared = await this.prepareSendOptions(providerId, sessionId, message, opts);
|
|
166
|
+
run.contextAdded(prepared.sharedContext, provider.supportsSharedContext ? "provider" : "message");
|
|
125
167
|
this.rememberSharedContext(providerId, sessionId, prepared.sharedContext);
|
|
126
168
|
let finished = false;
|
|
127
169
|
let activeSessionId = sessionId;
|
|
@@ -156,6 +198,7 @@ class ChatService {
|
|
|
156
198
|
// Not awaited: the snapshot is debounced and must never hold up or fail the turn.
|
|
157
199
|
scheduleTurnSnapshot(activeSessionId, this.getSession(activeSessionId)?.projectPath);
|
|
158
200
|
}
|
|
201
|
+
run.observe(event);
|
|
159
202
|
yield event;
|
|
160
203
|
}
|
|
161
204
|
finished = true;
|
|
@@ -241,20 +284,54 @@ class ChatService {
|
|
|
241
284
|
}
|
|
242
285
|
|
|
243
286
|
/** Push a live follow-up through the same context policy as sendMessage. */
|
|
244
|
-
async pushMessage(providerId: string, sessionId: string, message: string, opts?:
|
|
287
|
+
async pushMessage(providerId: string, sessionId: string, message: string, opts?: ChatSendOpts): Promise<void> {
|
|
245
288
|
const provider = providerRegistry.get(providerId);
|
|
246
289
|
if (!provider) throw new Error(`Provider "${providerId}" not found`);
|
|
247
290
|
const streaming = provider as typeof provider & {
|
|
248
291
|
pushMessage?: (id: string, content: string, options: SendMessageOpts) => void;
|
|
249
292
|
};
|
|
250
293
|
if (!streaming.pushMessage) return;
|
|
251
|
-
const
|
|
294
|
+
const { origin, ...sendOpts } = opts ?? {};
|
|
295
|
+
const prepared = await this.prepareSendOptions(providerId, sessionId, message, sendOpts);
|
|
296
|
+
// Written before the push, so the input precedes every event it causes in the trace.
|
|
297
|
+
traceFollowUp(sessionId, providerId, message, {
|
|
298
|
+
...sendOpts,
|
|
299
|
+
origin,
|
|
300
|
+
sharedContext: prepared.sharedContext,
|
|
301
|
+
contextVia: provider.supportsSharedContext ? "provider" : "message",
|
|
302
|
+
});
|
|
252
303
|
streaming.pushMessage(sessionId,
|
|
253
304
|
provider.supportsSharedContext ? message : withSharedContext(message, prepared.sharedContext),
|
|
254
305
|
{ ...prepared, sharedContext: provider.supportsSharedContext ? prepared.sharedContext : undefined });
|
|
255
306
|
this.rememberSharedContext(providerId, sessionId, prepared.sharedContext);
|
|
256
307
|
}
|
|
257
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Stop a session's query. An input to the run like a message is, so it goes through here
|
|
311
|
+
* rather than straight to the provider — otherwise the trace shows a turn that just stops.
|
|
312
|
+
*/
|
|
313
|
+
abortQuery(providerId: string, sessionId: string, reason: string, origin?: TraceOrigin): void {
|
|
314
|
+
const provider = providerRegistry.get(providerId);
|
|
315
|
+
if (!provider?.abortQuery) return;
|
|
316
|
+
traceAbort(sessionId, providerId, reason, origin);
|
|
317
|
+
provider.abortQuery(sessionId, reason);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** Answer an approval request or a question, and record the answer in the trace. */
|
|
321
|
+
resolveApproval(
|
|
322
|
+
providerId: string,
|
|
323
|
+
sessionId: string,
|
|
324
|
+
requestId: string,
|
|
325
|
+
approved: boolean,
|
|
326
|
+
data?: unknown,
|
|
327
|
+
extra: { reason?: string; origin?: TraceOrigin } = {},
|
|
328
|
+
): void {
|
|
329
|
+
const provider = providerRegistry.get(providerId);
|
|
330
|
+
if (typeof provider?.resolveApproval !== "function") return;
|
|
331
|
+
traceApproval(sessionId, providerId, requestId, approved, { data, ...extra });
|
|
332
|
+
provider.resolveApproval(requestId, approved, data);
|
|
333
|
+
}
|
|
334
|
+
|
|
258
335
|
/** Look up a session across all providers (for WS handler) */
|
|
259
336
|
getSession(sessionId: string): Session | null {
|
|
260
337
|
for (const info of providerRegistry.listAll()) {
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
|
|
17
17
|
/** Top-level config keys stored in the config table (not projects) */
|
|
18
18
|
const CONFIG_TABLE_KEYS: (keyof PpmConfig)[] = [
|
|
19
|
-
"device_name", "port", "host", "theme", "auth", "ai", "telegram", "clawbot", "query_audit", "tunnel",
|
|
19
|
+
"device_name", "port", "host", "theme", "auth", "ai", "telegram", "clawbot", "query_audit", "session_trace", "tunnel",
|
|
20
20
|
];
|
|
21
21
|
|
|
22
22
|
/** File filter config keys stored in the config table */
|
|
@@ -71,64 +71,5 @@ function dedup(arr: string[]): string[] {
|
|
|
71
71
|
return [...new Set(arr)];
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
* Uses simple pattern-to-regex conversion (no external lib needed).
|
|
77
|
-
* Patterns follow VS Code glob semantics: ** crosses dirs, * stays in one segment.
|
|
78
|
-
*/
|
|
79
|
-
export function matchesGlob(relPath: string, patterns: string[]): boolean {
|
|
80
|
-
// Normalize path separators to forward slash
|
|
81
|
-
const normalized = relPath.split("\\").join("/");
|
|
82
|
-
return patterns.some((pattern) => matchSingleGlob(normalized, pattern));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function matchSingleGlob(relPath: string, pattern: string): boolean {
|
|
86
|
-
// Strip leading **/ for simpler matching — handled by regex
|
|
87
|
-
const re = globPatternToRegex(pattern);
|
|
88
|
-
return re.test(relPath);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Convert a VS Code-style glob pattern to a RegExp.
|
|
93
|
-
* Cached per unique pattern string for performance.
|
|
94
|
-
*/
|
|
95
|
-
const regexCache = new Map<string, RegExp>();
|
|
96
|
-
|
|
97
|
-
function globPatternToRegex(pattern: string): RegExp {
|
|
98
|
-
const cached = regexCache.get(pattern);
|
|
99
|
-
if (cached) return cached;
|
|
100
|
-
|
|
101
|
-
let p = pattern;
|
|
102
|
-
// Normalize path separators
|
|
103
|
-
p = p.split("\\").join("/");
|
|
104
|
-
// Strip leading ./
|
|
105
|
-
if (p.startsWith("./")) p = p.slice(2);
|
|
106
|
-
|
|
107
|
-
// Leading `**/` should match zero-or-more path segments, INCLUDING root.
|
|
108
|
-
// So `**/.git` matches both `.git` (at root) and `src/.git` (nested).
|
|
109
|
-
// Strip `**/` prefix here so it doesn't force a leading path; we handle it via optional group below.
|
|
110
|
-
const hasStarstarPrefix = p.startsWith("**/");
|
|
111
|
-
if (hasStarstarPrefix) p = p.slice(3);
|
|
112
|
-
|
|
113
|
-
const escaped = p
|
|
114
|
-
.replace(/[.+^${}()|[\]]/g, "\\$&") // escape regex special chars (not * ?)
|
|
115
|
-
.replace(/\*\*/g, "\x00") // temp: ** placeholder
|
|
116
|
-
.replace(/\*/g, "[^/]*") // * = within one path segment
|
|
117
|
-
.replace(/\x00/g, ".*") // ** = any path
|
|
118
|
-
.replace(/\?/g, "[^/]"); // ? = single non-slash char
|
|
119
|
-
|
|
120
|
-
let re: RegExp;
|
|
121
|
-
if (hasStarstarPrefix) {
|
|
122
|
-
// `**/X` → match X at any depth including root: `(^|.*/)X(/|$)`
|
|
123
|
-
re = new RegExp(`(^|.*/)${escaped}(/|$)`);
|
|
124
|
-
} else if (p.includes("/")) {
|
|
125
|
-
// Anchored pattern with explicit path
|
|
126
|
-
re = new RegExp(`^${escaped}(/|$)`);
|
|
127
|
-
} else {
|
|
128
|
-
// Pattern with no slash (e.g. *.log) → match at any depth
|
|
129
|
-
re = new RegExp(`(^|/)${escaped}(/|$)`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
regexCache.set(pattern, re);
|
|
133
|
-
return re;
|
|
134
|
-
}
|
|
74
|
+
// Matching lives in its own module so the file index worker can use it without the config store.
|
|
75
|
+
export { matchesGlob } from "./file-glob.ts";
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* file-glob.ts
|
|
3
|
+
* VS Code-style glob matching for file excludes. Kept free of any import that reaches the
|
|
4
|
+
* config store or the database, because the file index worker runs it on its own thread.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Check if a relative path matches any of the given glob patterns.
|
|
9
|
+
* Uses simple pattern-to-regex conversion (no external lib needed).
|
|
10
|
+
* Patterns follow VS Code glob semantics: ** crosses dirs, * stays in one segment.
|
|
11
|
+
*/
|
|
12
|
+
export function matchesGlob(relPath: string, patterns: string[]): boolean {
|
|
13
|
+
// Normalize path separators to forward slash
|
|
14
|
+
const normalized = relPath.split("\\").join("/");
|
|
15
|
+
return patterns.some((pattern) => matchSingleGlob(normalized, pattern));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function matchSingleGlob(relPath: string, pattern: string): boolean {
|
|
19
|
+
// Strip leading **/ for simpler matching — handled by regex
|
|
20
|
+
const re = globPatternToRegex(pattern);
|
|
21
|
+
return re.test(relPath);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Convert a VS Code-style glob pattern to a RegExp.
|
|
26
|
+
* Cached per unique pattern string for performance.
|
|
27
|
+
*/
|
|
28
|
+
const regexCache = new Map<string, RegExp>();
|
|
29
|
+
|
|
30
|
+
function globPatternToRegex(pattern: string): RegExp {
|
|
31
|
+
const cached = regexCache.get(pattern);
|
|
32
|
+
if (cached) return cached;
|
|
33
|
+
|
|
34
|
+
let p = pattern;
|
|
35
|
+
// Normalize path separators
|
|
36
|
+
p = p.split("\\").join("/");
|
|
37
|
+
// Strip leading ./
|
|
38
|
+
if (p.startsWith("./")) p = p.slice(2);
|
|
39
|
+
|
|
40
|
+
// Leading `**/` should match zero-or-more path segments, INCLUDING root.
|
|
41
|
+
// So `**/.git` matches both `.git` (at root) and `src/.git` (nested).
|
|
42
|
+
// Strip `**/` prefix here so it doesn't force a leading path; we handle it via optional group below.
|
|
43
|
+
const hasStarstarPrefix = p.startsWith("**/");
|
|
44
|
+
if (hasStarstarPrefix) p = p.slice(3);
|
|
45
|
+
|
|
46
|
+
const escaped = p
|
|
47
|
+
.replace(/[.+^${}()|[\]]/g, "\\$&") // escape regex special chars (not * ?)
|
|
48
|
+
.replace(/\*\*/g, "\x00") // temp: ** placeholder
|
|
49
|
+
.replace(/\*/g, "[^/]*") // * = within one path segment
|
|
50
|
+
.replace(/\x00/g, ".*") // ** = any path
|
|
51
|
+
.replace(/\?/g, "[^/]"); // ? = single non-slash char
|
|
52
|
+
|
|
53
|
+
let re: RegExp;
|
|
54
|
+
if (hasStarstarPrefix) {
|
|
55
|
+
// `**/X` → match X at any depth including root: `(^|.*/)X(/|$)`
|
|
56
|
+
re = new RegExp(`(^|.*/)${escaped}(/|$)`);
|
|
57
|
+
} else if (p.includes("/")) {
|
|
58
|
+
// Anchored pattern with explicit path
|
|
59
|
+
re = new RegExp(`^${escaped}(/|$)`);
|
|
60
|
+
} else {
|
|
61
|
+
// Pattern with no slash (e.g. *.log) → match at any depth
|
|
62
|
+
re = new RegExp(`(^|/)${escaped}(/|$)`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
regexCache.set(pattern, re);
|
|
66
|
+
return re;
|
|
67
|
+
}
|