@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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.23.12] - 2026-10-02
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Open System Monitor from the command palette on phones and desktops.
|
|
7
|
+
- Record session runs and browser console events in a retained trace that can be read back.
|
|
8
|
+
- Stream Remote Desktop over HTTP through a WebRTC relay, with Wayland screen capture.
|
|
9
|
+
- Run and control an opt-in Android emulator from the browser.
|
|
10
|
+
|
|
11
|
+
### Improved
|
|
12
|
+
- Start a new Claude chat faster by preparing its CLI while the composer is open.
|
|
13
|
+
- Open tabs, floating windows, and Settings panes without a spinner once their code is loaded.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- File changes no longer freeze large projects or repeatedly download the file index.
|
|
17
|
+
- Large file indexes walk, compress, and search off the server event loop; content search uses ripgrep when available.
|
|
18
|
+
- Linux directory watching avoids per-directory descriptors and self-inflicted inotify queue overflows.
|
|
19
|
+
- Release binaries include both the extension host and file index workers.
|
|
20
|
+
|
|
3
21
|
## [0.23.11] - 2026-10-01
|
|
4
22
|
|
|
5
23
|
### Added
|
package/CLAUDE.md
CHANGED
|
@@ -82,6 +82,7 @@ Related: `configService.save()`/`set()` throw when `load()` has not run, because
|
|
|
82
82
|
|
|
83
83
|
- **SDK .env poisoning**: Projects with `ANTHROPIC_API_KEY` in `.env` break SDK tool execution. Provider neutralizes these vars. See `docs/lessons-learned.md`.
|
|
84
84
|
- **File watching**: never `fs.watch(dir, { recursive: true })` on a project root — on Linux that is one inotify watch per subdirectory, `node_modules` included (it once cost 359k watches). Ignored dirs must be pruned at registration time via `src/services/file-watcher/watch-tree.ts`.
|
|
85
|
+
- **A file change marks the flat file index stale, and must never make a request walk the project**: `buildIndex` used to walk with `readdirSync` on the main thread while every change dropped the cache and the explorer refetched `/files/index` 300 ms later. nxsys-workspace (181k entries, 22 MB of JSON) is a 6.2 s walk, so a session writing test artefacts into it kept the event loop stopped back to back until the supervisor's health check (5 s timeout, three strikes) killed the server — and every Claude session under it. Now the walk yields every 256 entries on `setTimeout(0)` (`setImmediate` costs 0.002 ms a yield against 1.09 ms, but starved HTTP to a 16 ms p50 against 1.4 ms), a stale list is rebuilt behind the one held, a request waits for that rebuild at most `REBUILD_GRACE_MS` (1 s — enough that an ordinary project answers fresh and a file just created is in the palette on its first open), and `files:index-changed` goes out only when the rebuilt paths differ. The browser does not refetch on a change either: `file:changed` and `files:index-changed` set `indexStale`, and `ensureIndex` refreshes when the palette, the compare picker or the @-picker opens. Two traps. A rebuild runs only when a request asks for one, so a change landing mid-walk is walked again only if a request saw it (`rewalk`) — rebuilding on a timer would keep a core busy for as long as a session keeps writing. And a first walk that no longer stops the server can outlast **Bun.serve's default 10 s idle timeout** (14 s on a busy scratch server), which cuts the request off with the list nearly built; the route calls `server.timeout(req, 30)` through `c.env`, the server `app.fetch(req, server)` passed.
|
|
85
86
|
- **Project Claude settings**: `.claude/settings.local.json` can restrict tools even with `bypassPermissions`. Provider overrides with empty settings.
|
|
86
87
|
- **Transcript images live in two places**: the base64 payload sits at `message.content[].content[]` inside a tool result, but Claude Code also writes an image-shaped record at the top-level `toolUseResult` field carrying no payload. An assertion like "no `"type":"image"` remains" must be scoped to the former, or it fails against correct code.
|
|
87
88
|
- **Plugin items are named by location, not frontmatter**: Claude Code registers a plugin's skills and commands as `<plugin>:<path>` (`ak-engineer:ak-debug`) and only honours the frontmatter `name` for agents. Kits that self-namespace instead — AgentKit ships `name: ak:debug` — publish a name nothing can resolve. `slash-discovery` mirrors that rule and keeps the declared name as an alias; `src/server/ws/chat.ts` rewrites the alias to the canonical name before the message reaches the SDK.
|
|
@@ -107,6 +108,7 @@ Related: `configService.save()`/`set()` throw when `load()` has not run, because
|
|
|
107
108
|
- **A button in a Monaco hover is a `command:` link in *trusted* markdown, and trust is all-or-nothing unless you narrow it**: a hover can only contain markdown, so the blame hover's actions are `[label](command:id?args)` links reaching ids registered with `monaco.editor.registerCommand`. The renderer *strips* those links unless the `IMarkdownString` is trusted — and `isTrusted: true` allows **every** command on the page's global registry. That hover embeds a commit message, so anyone who can land a commit could write `[click](command:...)` in one and have it render as a working button. Both defences are needed and both are in `blame-hover.ts`: `isTrusted: { enabledCommands: [...] }` (an array is honoured by `toAllowCommandsOption`), and escaping the message so it cannot form a link at all. `supportHtml` stays **off** — the avatar is ``, which renders inline at its intrinsic size, so no HTML has to be allowed for it. Escape `<` and `>` too: with `supportHtml` off the renderer does not leave an unknown tag alone, it drops the tag and keeps the text, so a message mentioning a literal `<script>alert(1)</script>` displayed as `alert(1)` — the message silently rewritten in the one view meant to show it verbatim.
|
|
108
109
|
- **Hovering injected text does reach the decoration under it, and Monaco has no `diff` language**: an `after` injected-text annotation sits past the line's last column, and `ContentHoverComputer._getLineDecorations` relaxes its column check by one character *only* for `showIfCollapsed` decorations — which is what makes the blame hover work at all, and why that flag is load-bearing rather than cosmetic. `editor.action.showHover` opens the same hover from the cursor, which is the touch path (gated on `hover: none`, not on a width breakpoint; the mouse target's `injectedText` would identify the tap exactly but is not in Monaco's public typings, so the handler goes by column). Separately: Monaco's 91 basic languages include no `diff` — VS Code's comes from a bundled extension — so a fenced diff block runs the tokenizer and comes back entirely `mtk1`, the theme's default foreground. `monaco-diff-language.ts` registers one and `theme/diff-token-rules.ts` colours it; a Monarch rule whose token name has no theme rule is the same silent no-op as an unmapped semantic token, and a test pairs the two so neither can be added without the other.
|
|
109
110
|
- **The service worker's precache can silently undo any download saving, and both compressions are needed**: `injectManifest` defaults to precaching *everything* in the build output, so the first visit fetched 488 files / 33.3 MB — including the 12.7 MB TypeScript worker that `monaco-builtin-typescript.ts` had just made unnecessary to ever load. A saving measured in the network tab of a warm page is not a saving; measure `precache N entries (X KiB)` in the build output too. `globPatterns` now lists only the boot shell (9 entries / 1.08 MB) with everything else on a runtime `CacheFirst`. Separately, `scripts/precompress-web.ts` writes **both** `.br` and `.gz` siblings and `static-encoding.ts` picks one: brotli alone is not enough, because browsers advertise `br` only on a **secure origin** and PPM is routinely reached over plain HTTP on a LAN. And Monaco is staged locally by `scripts/copy-monaco.ts` with `loader.config({ paths: { vs: "/assets/monaco/vs" } })` — the default is jsdelivr, which means no editor offline and a third party told which files are opened. `vite build` empties `dist/web`, so `copy-monaco` and `precompress-web` must run *after* `build:web` (running `build:web` alone leaves an installed PPM with no Monaco at all).
|
|
111
|
+
- **`FileSink.write()` consumes the whole chunk and returns a number that is not how much of it went in**: the careful-looking `while (off < buf.length) { off += await sink.write(buf.subarray(off)) }` is therefore a loop that re-sends the tail. Measured against `cat`, one 4,924,800-byte frame produced eleven `write()` calls each answering **475072** while everything had already been buffered, and the child received **28,043,840 bytes — 5.7x the frame**. Downstream the damage is silent and total: ffmpeg's rawvideo input is offset for good, so the *first* picture decodes perfectly and every one after it is drawn rolled, with no error from ffmpeg, from the sink, or from the encoder wrapper. One `write()` then `await flush()` is the whole correct form (`writeFrameToSink` in `android-video.ts`). Two things generalise. A frame **counter** cannot see this — every counter in the pipeline reported the right number while 5.7x the bytes left the process — so the test has to measure the bytes a real child receives (`tests/unit/android/android-video-frame-write.test.ts`), and it needs a chunk big enough that the sink buffers in pieces or the bug does not reproduce at all. And a capture that decodes correctly proves nothing if it holds one access unit: the first frame is always right.
|
|
110
112
|
- **A lazy chunk boundary is one static import away from not existing, and it is invisible**: `code-editor.tsx` reaches the language service only through `lazy(() => import("./editor-language-service"))`, which is what keeps the LSP client out of the editor's chunk and — the part that actually costs something — keeps the code that asks the host for a server unreachable until the setting is on. One `import { anything } from "@/hooks/use-lsp"` anywhere on that static path merges the chunk back in and nothing about the UI looks different, so `tests/unit/web/editor-lsp-lazy-boundary.test.ts` enumerates the offenders instead. Importing even a *constant* from the lazy module counts; `import type` does not. Related: `lspEnabled` and `mobileWordWrap` are written with `persistDevicePref` (localStorage only) rather than `persistUiPref`, because the server round-trip that makes prefs survive an origin change also means the last device to write wins everywhere — and a desktop must not start an 854 MB server process for a phone.
|
|
111
113
|
- **Escaping before matching lets a pattern rewrite the text it escaped**: the git graph escaped a commit message to HTML and *then* ran the issue-link rules over the result. The default rule is `#(\d+)`, an apostrophe escapes to `'`, so "Monaco's" rendered as a literal `'s` with `#39` styled as an issue link — every message with an apostrophe in it, which is most of them. `commit-message-html.ts` matches the raw text and escapes only what it emits; the same order matters for the URL and bare-hash rules, which otherwise link something *inside* a URL and split it. That file also shows the way to unit-test code that lives in a webview: write it as a real typed function and inject `fn.toString()`, which Bun returns type-stripped, rather than keeping a second copy inside a template literal where every regex backslash has to be doubled. And a backtick anywhere in a comment inside those template literals — including inside a CSS comment — ends the literal and reports as a syntax error hundreds of lines away; `webview-html.test.ts` now parses the whole injected script with `new Function` so that lands as a failing test instead of a blank panel.
|
|
112
114
|
- **`dateStyle`/`timeStyle` may not be combined with any other `Intl` option**: `toLocaleString(undefined, { dateStyle: "medium", timeStyle: "medium", timeZoneName: "short" })` does not ignore the third option, it *throws* `TypeError: dateStyle and timeStyle may not be used with other DateTimeFormat options`. Behind the `try/catch` that any date formatting picks up sooner or later, that is indistinguishable from a locale which simply has no timezone in its medium format — the commit details panel showed author and committer dates with no zone at all, and no test caught it because the fallback string is perfectly well-formed. A format that needs a companion option has to list every component explicitly (`year`/`month`/`day`/`hour`/`minute`/`second` + `timeZoneName`), and the test worth writing runs the options object through a real `Intl.DateTimeFormat` and asserts the *output* contains a zone.
|
|
@@ -121,8 +123,10 @@ Related: `configService.save()`/`set()` throw when `load()` has not run, because
|
|
|
121
123
|
- **Screen wake lock needs a secure context**: `navigator.wakeLock` does not exist at all over plain HTTP, so reaching PPM at `http://<lan-ip>:<port>` silently disables "keep screen awake" — the very setup (a tablet on the LAN) it was built for. Only HTTPS and `localhost` qualify. The lock is also released by the browser on *every* hide, so `src/web/hooks/use-wake-lock.ts` re-acquires on `visibilitychange` and drops its handle on hide rather than waiting for the `release` event, whose ordering against `visibilitychange` is undefined.
|
|
122
124
|
- **Remote desktop on macOS (avfoundation)**: address the screen by **name** (`-i "Capture screen 0"`), never by index — the device list reorders at runtime when a Continuity Camera joins (index 3 became the iPhone). `-framerate` is ignored (the screen input delivers at display refresh, 120–165 fps, with a stuck pts) → `-use_wallclock_as_timestamps 1` + `-vf fps=30`. ffmpeg-avfoundation ignores SIGTERM/SIGINT → `proc.kill("SIGKILL")` or it leaks one process per session. No Screen Recording grant = **black frames, no error**; no Accessibility grant = silent no-op input — both are pre-flighted in `remote-desktop-requirements.ts`, never inferred from failures. TCC keys the grant to the `bun` executable.
|
|
123
125
|
- **Remote desktop text injection on macOS**: `CGEventKeyboardSetUnicodeString` still carries a keycode, and IMEs that hook by key (OpenKey/EVKey) re-read keycode 0 as a literal "a" (`"日本"` → `"â"`); function/unassigned keycodes produce no text at all. The carrier is Space (`TEXT_CARRIER_KEYCODE`). Text is still subject to the host's active IME (Telex rewrote "World" → "ửold") on every OS.
|
|
124
|
-
- **Remote desktop on Linux is chosen per *session*, not per platform, and Wayland must win the tie**: `process.platform === "linux"` says nothing about how to capture or inject. A Wayland session almost always also runs XWayland, which sets `DISPLAY` and answers `x11grab` **successfully** — with a view of XWayland clients only, i.e. a black or half-empty screen rather than an error. So `remote-desktop-linux-session.ts` checks Wayland *before* X11, and `XDG_SESSION_TYPE` outranks both. It also has to *probe* rather than read the env: a PPM started by its systemd user unit has no `DISPLAY`/`XAUTHORITY` at all while a full desktop runs two feet away, so the fallbacks are the `X<N>` socket in `/tmp/.X11-unix`, the `wayland-N` socket in `$XDG_RUNTIME_DIR`, and for auth the `xauth_*` file Xorg was launched with (`-auth /run/user/1000/xauth_XXXXXX`) before `~/.Xauthority`. ffmpeg is then spawned with that env merged over `process.env`. Wayland
|
|
126
|
+
- **Remote desktop on Linux is chosen per *session*, not per platform, and Wayland must win the tie**: `process.platform === "linux"` says nothing about how to capture or inject. A Wayland session almost always also runs XWayland, which sets `DISPLAY` and answers `x11grab` **successfully** — with a view of XWayland clients only, i.e. a black or half-empty screen rather than an error. So `remote-desktop-linux-session.ts` checks Wayland *before* X11, and `XDG_SESSION_TYPE` outranks both. It also has to *probe* rather than read the env: a PPM started by its systemd user unit has no `DISPLAY`/`XAUTHORITY` at all while a full desktop runs two feet away, so the fallbacks are the `X<N>` socket in `/tmp/.X11-unix`, the `wayland-N` socket in `$XDG_RUNTIME_DIR`, and for auth the `xauth_*` file Xorg was launched with (`-auth /run/user/1000/xauth_XXXXXX`) before `~/.Xauthority`. ffmpeg is then spawned with that env merged over `process.env`. Wayland capture goes through a **different backend entirely** (`remote-desktop-capture-wayland.ts`) rather than another ffmpeg grabber — see the portal bullet below.
|
|
125
127
|
- **Key injection on Linux goes through evdev codes, never keysyms**: `XKeysymToKeycode(XK_a)` answers "which key currently *produces* an a", which on an AZERTY host is the physical Q key — so a keysym table silently transposes the whole keyboard for anyone not on a US layout. `remote-desktop-evdev-key-map.ts` maps `KeyboardEvent.code` → evdev code, which names the physical switch just as `code` does; X11 keycode = evdev + 8 (`X11_KEYCODE_OFFSET`), verified against a live server for all 50 spot-checked keys. The same table feeds uinput, which wants the raw code. X11 also has no "type this string" call: `text()` uses the real keymap when the character is in it (all ASCII, no round trip) and otherwise borrows a keycode with no keysyms, binds it to `0x01000000|codepoint`, and needs a real ~12ms delay after the remap — the server applies it at once but the focused *client* only learns from its `MappingNotify`, so a key pressed sooner is read with the old mapping.
|
|
128
|
+
- **Wayland capture is a portal session that must outlive the capture, and the three things that make it work were each measured**: a compositor shares the screen only through `org.freedesktop.portal.ScreenCast`, which is D-Bus, which Bun does not speak — so `remote-desktop-portal.ts` is `bun:ffi` against `libdbus-1.so.3` (present on any host with a session bus). Three findings turn this from impossible to routine. **`OpenPipeWireRemote` is never called**: the documented flow ends by receiving a PipeWire *file descriptor*, which no shell-out (`busctl`, `gdbus`) can hand to a separate process — and it turns out not to be needed, because the node lives in the user's own PipeWire daemon, so a bare `pipewiresrc path=<node>` reaches it through `$XDG_RUNTIME_DIR/pipewire-0` (measured: negotiated `BGRA 1920x1080` with no fd in the pipeline). **The D-Bus connection owns the session** — the node dies with it, so the handle is held for the capture's whole life and `dbus_bus_get_private` is used rather than the shared connection, which is refcounted process-wide. And **`persist_mode: 2` + a stored `restore_token`** (under `getPpmDir()`, 0600) is what stops a consent dialog appearing on the *host's* screen every session, which on a remote desktop is a prompt only someone sitting at the machine could answer; the first session still asks. ffmpeg is not the capture tool here at all: reading PipeWire needs `--enable-libpipewire`, which distributions do not do (Arch's own `ffmpeg 2:9.0.1-4.1` does not), so GStreamer does it — exactly as RustDesk does (`Depends On: gst-plugins-base gst-plugin-pipewire` + `libdbus-1.so.3` linked in; it is Rust, not magic). Four traps in the pipeline, each silent. **`videorate max-rate=30` does not cap** — measured 59 fps through it, and 133 fps at `max-rate=60`; only a capsfilter `video/x-raw,framerate=30/1` caps. That same capsfilter is also **what makes an idle desktop watchable**: a portal stream is damage-driven and a still screen pushed **14 frames in 60 seconds**, so a viewer joining a quiet host would see nothing at all — `videorate` duplicates the last frame and held **29.6 fps on a completely static screen**, which keeps keyframes flowing so a late joiner syncs within one GOP. **`vapostproc` + `video/x-raw(memory:VAMemory)` must pair with `vah264enc`** and not with `x264enc`, or every frame is downloaded back out of VA memory; the GPU path cost **14.9% of a core at 1080p30 against 52% for software conversion uncapped**. And the **portal stream dies under consumer churn** — it wants one long-lived `pipewiresrc`, so anything that reconnects per quality change must re-run the handshake rather than reattach. Measured end to end through `startCapture`: first access unit at **430 ms**, 28.8 fps, 3.2 Mbit/s, SPS parsed from GStreamer's bytes by the same `AccessUnitAssembler` ffmpeg's output feeds. `listDisplays()` still answers `[]` on Wayland and that is correct — the portal's own dialog chooses which output is shared, so PPM neither enumerates nor picks.
|
|
129
|
+
|
|
126
130
|
- **Xlib's default I/O error handler calls `exit()` on the PPM server**: a logout, a GPU reset or `systemctl restart sddm` makes libX11 print `XIO: fatal IO error` and terminate the *calling process* — every project, terminal and chat session gone because someone logged out of the desktop. `remote-desktop-x11.ts` replaces all three handlers (`XSetErrorHandler`, `XSetIOErrorHandler`, and libX11 ≥ 1.7's `XSetIOErrorExitHandler`, which cancels the exit that happens even when the first one returns) and holds the `JSCallback`s in module scope — a GC'd callback leaves Xlib calling a freed trampoline, i.e. a segfault instead of the crash it was installed to prevent. A connection that took an I/O error has no safe call left on it, not even `XCloseDisplay`, so it is dropped un-closed and the next caller reopens.
|
|
127
131
|
- **`xrandr` the binary and `libXrandr` the library are different packages**: this dev host has `libXrandr.so.2` and no `xrandr`, so anything that shells out to enumerate monitors reports "no displays" on a working desktop. `remote-desktop-displays.ts` reads `XRRGetMonitors` over FFI (`sizeof(XRRMonitorInfo)` = 56 on x86-64: name Atom at 0, primary at 8, x/y/w/h at 20/24/28/32) and falls back to one whole-root-window entry when the library is absent. X11 puts every monitor in one root coordinate space, so a per-monitor capture is a crop — `-video_size WxH -i :0.0+X,Y` — and `-i :0.0` alone grabs the union of all of them.
|
|
128
132
|
- **A uinput injector needs two devices, not one**: libinput classifies a device from the capabilities it declares, and one device advertising both a full keyboard and absolute axes is typically read as a *touchpad* — which then applies pointer acceleration and treats absolute coordinates as relative motion, so the pointer drifts instead of landing. `remote-desktop-input-uinput.ts` creates a pointer device (absolute axes + buttons + wheel + `INPUT_PROP_DIRECT`) and a keyboard device separately, declares every key it will ever send (`UI_SET_KEYBIT`; an undeclared key is dropped by the kernel silently), and `UI_DEV_DESTROY`s both on exit or they pile up in the compositor's device list on every restart. Derive the ioctl numbers from real headers — `_IOW` encodes the struct size, so a wrong `sizeof` yields a different request number and `ioctl` fails with `EINVAL` for no visible reason. uinput carries key *codes*, so there is no `text()` at all: a phone soft keyboard that reports no key codes cannot type on a Wayland host.
|
|
@@ -194,6 +198,12 @@ Related: `configService.save()`/`set()` throw when `load()` has not run, because
|
|
|
194
198
|
- **A streaming rollout parser cannot use whole-file look-ahead**: it commits to legacy vs `item_completed` format from the *first* `session_meta`'s `cli_version` (`item_completed` shipped in codex cli 0.154.0) and never revisits that choice mid-file — there is no later point at which re-reading the whole file to check is acceptable for a live tail. A `compacted` or `thread_rolled_back` record rewrites the file's *content*, not its format, so `codex-rollout-tail-parser.ts` resets its de-dupe state on those but keeps the format decision from the header.
|
|
195
199
|
- **`resolveSessionDir` falls back to scanning every Claude project on disk**: given a session id whose encoded project path does not resolve, it walks every `~/.claude/projects/*` looking for a matching `<sessionId>.jsonl` — useful for a session started outside PPM, unsafe if trusted before the caller is known to own that session. `src/services/agent-transcript/session-ownership.ts` is the gate every Agent-session transcript read goes through first instead; the `/ws/global` hub never accepts a client-supplied path for this reason.
|
|
196
200
|
|
|
201
|
+
- **WebCodecs is secure-context only, so Remote Desktop and the Android viewer cannot show a picture on a plain-HTTP LAN address** — which is how a phone or tablet normally reaches PPM. Measured in one browser at one moment: `VideoDecoder` is `undefined` on `http://192.168.98.96:3210` and present on `http://127.0.0.1:3210`, while `RTCPeerConnection` exists on both. Nothing warns; the viewer just reports "this browser has no WebCodecs" about a browser that is fine, which is why `missingDecoderReason()` branches on `window.isSecureContext` instead. The way out is WebRTC, and in Bun that means a **downloaded binary**: there is no WebRTC stack in the runtime, GStreamer's `webrtcbin` **segfaults PyGObject** on GStreamer 1.28.7 + Python 3.14 (`gst_webrtc_session_description_copy` → `gst_sdp_message_copy` → `g_strdup` on a malformed emails array — it dies just *reading* the offer, and rebuilding the description from SDP text does not help) *and* would put GStreamer + PyGObject on every Windows and macOS host, and `@roamhq/wrtc` only accepts raw i420, i.e. it would discard the hardware H.264 encode and re-encode in software. `mediamtx-*.ts` is the answer: MediaMTX repackages the H.264 ffmpeg already produced (verified — 1920x1080 Main@4.0 in, `video/H264` at the same size out) for 0.6% of a core and 55 MB RSS. Four traps in wiring it. Its **shipped `mediamtx.yml` must never be used**: it listens on every interface with RTMP/HLS/SRT/MoQ/API/metrics/pprof on, and MoQ writes `auto.crt`/`auto.key` beside itself on first start — PPM generates its own config and every switch is spelled out, because MediaMTX *rejects unknown keys* (`json: unknown field`), so a renamed key fails loudly instead of silently leaving a listener open. The **ICE/UDP port cannot be loopback** — WebRTC media is peer-to-peer, so confining it breaks every remote viewer while the page still connects; what protects it is the per-session ICE ufrag/password, which is why a test asserts the port is *not* loopback. `filesrc` **cannot read a FIFO** (it probes for seekability and closes it, so ffmpeg takes EPIPE) — open the FIFO yourself and hand over `fdsrc fd=N`. And the relay answers **404 until the publisher's first packet**, which a quality change re-creates by respawning ffmpeg, so the browser's WHEP handshake must retry rather than fail. Peer-to-peer also means a viewer on the **Cloudflare tunnel** has no route for the media at all: the handshake is proxied over HTTPS and succeeds, then nothing arrives, and Chromium takes **15 s** (measured, no candidate reachable) to call the connection `failed`. So `use-webrtc-canvas-video.ts` gives ICE `CONNECT_DEADLINE_MS` and the connection hook reconnects asking for the WebSocket stream, remembered for the tab in `sessionStorage` — but only where WebCodecs exists: behind the tunnel's HTTPS it does in any browser that ships it, on a plain-HTTP LAN origin it never does, and there the WebRTC error stands. Last: `startCapture` keeps `stdout: "pipe"` in both modes even though nothing reads it when publishing — making it conditional widens Bun's spawn type so `proc.stdout` is possibly-undefined everywhere below, the same family as the `ReturnType<typeof Bun.spawn>` trap above.
|
|
202
|
+
- **`Bun.spawn({ stdin: other.stdout })` is not a pipe between two children**: Bun reads every byte into PPM and writes it back out with a pump of its own (measured: piping 200 MB raised the Bun process's own `rchar` and `wchar` by 200 MB each). Two failures follow, both silent until the reader dies. Under a burst, that pump rejects with `EPIPE`s nothing can catch — 2–3 per remux death with keyframe-sized writes, and `handleFatalError` in `src/server/index.ts` exits the server at 3 in a minute. And a reader that stalls before dying leaves the writer running for good, because Bun is still reading it: gst-launch kept encoding with no `onExit` and the viewer sat on a frozen picture. `remote-desktop-capture-wayland.ts` therefore pumps gst into the remux itself (one awaited `write()` + `flush()` per chunk, the same shape as the `FileSink` entry above) and watches **both** processes, the first to die taking the other down. `wayland-capture-supervision.test.ts` drives it with shell stand-ins; under `bun test` an unhandled rejection is a failed test, which is what makes the burst case assertable at all.
|
|
203
|
+
|
|
204
|
+
- **`PRAGMA auto_vacuum` takes the write lock even when it changes nothing, so `busy_timeout` must be set first**: the session trace set it after `auto_vacuum`/`journal_mode` (copied from `query-audit-db.ts`, which still has that order), and a second process opening the file while another was mid-write got `SQLITE_BUSY` at once — measured: a lock held for 300 ms failed the open outright against a 2 s timeout. Only the full unit suite's server-plus-CLI race caught it. `journal_mode = WAL` on a file already in WAL does *not* wait on a writer, which is why `db.service.ts`'s order is harmless. Put `busy_timeout` first in any opener two processes share.
|
|
205
|
+
- **The Claude SDK interleaves a data-less `system/thinking_tokens` between every two thinking deltas**, so anything folding *consecutive* deltas folds nothing: the trace's coalescer turned one real turn into 92 rows, 84 of them single deltas and ticks. The provider forwards every SDK system message it does not special-case as a bare `{type, subtype}` (`claude-agent-sdk.ts`), and that shape is how to recognise a signal — `trace-coalescer.ts` counts one arriving inside a block on the block (`signals`) instead of closing it. A mock or scripted provider that never sends these hides the bug entirely, which is why the replay test's script now does.
|
|
206
|
+
|
|
197
207
|
## UI Rules
|
|
198
208
|
|
|
199
209
|
When creating or modifying any UI component, you MUST read and follow `docs/design-guidelines.md`, especially the **Mobile-First UI Rules** section. Key rules:
|
|
@@ -239,7 +249,8 @@ Before planning or implementing a new feature, read `docs/project-roadmap.md` to
|
|
|
239
249
|
- **`os.cpus()` cannot express a core that is blocked on I/O**, and the failure is a *confident wrong number* rather than a gap: libuv's Linux `uv_cpu_info` reads the `iowait`, `softirq` and `steal` columns of `/proc/stat` into a throwaway, so a core parked in iowait reports a tiny total delta with no idle in it and `(total-idle)/total` comes out **100%** — one bar of the Overview per-core strip drew solid red, every tick, for a thread that was 3% busy behind a 191 MB/s write. `cpu-memory-collector.ts` samples `/proc/stat` itself (`parseProcStatCores`) and keeps `os.cpus()` as the off-Linux fallback; iowait is folded into not-busy the way `top` and Mission Center both have it, and softirq is counted as kernel time rather than dropped from the total. Do **not** also add `guest`/`guest_nice`: the kernel already counts them inside `user`/`nice`, so summing them deflates every percentage on a host running VMs. The whole-machine `total` hid this — one core's 6-jiffy window barely moves a sum over 24 — so verify per-core figures against `/proc/stat` directly, never against the total.
|
|
240
250
|
- The contract everywhere here is **`undefined` = cannot measure**, and the UI renders that as an em dash. Never substitute `0`: "this GPU has no dedicated memory" and "this GPU has 0 MB of memory" are different claims, and `tests/unit/web/overview-gpu-card-vram.test.tsx` pins the difference.
|
|
241
251
|
- `src/services/db-backup/` — verified `VACUUM INTO` snapshots of `ppm.db` (hourly + at start + before every migration), GFS retention, `ppm backup` / `ppm restore`
|
|
242
|
-
- `src/services/
|
|
252
|
+
- `src/services/session-trace/` — the session trace ("every run is traceable"): its own `session-trace.db` (outside `db-backup` — a log, not state), one trace per run keyed by the PPM session id with `trace_aliases` for ids a provider migrated to. `ChatService` records every input it handles (`user_message`, `context_added`, `approval_resolved`, `turn_aborted`) and every provider event, text/thinking deltas coalesced per block (`trace-coalescer.ts`), through a batching writer that never throws into a chat (`trace-writer.ts`). Browser half: `src/web/lib/trace-client.ts` (every console level; errors carry the 50 lines before them) posting to `POST /api/trace` keyed by device id, plus the inline watchdog beacon in `index.html`. Read a session with `GET /api/trace/sessions/:id`; retention in `session-trace-cleanup.ts`. Design and as-built notes: `docs/architecture/plugins-and-tracing.md`
|
|
253
|
+
- `src/services/remote-desktop/` — Remote Desktop: one ffmpeg per WS session (`remote-desktop-capture.ts` + per-platform `remote-desktop-capture-input.ts` + `remote-desktop-encoder-args.ts`) → Annex-B H.264 access units → WebCodecs; input via `remote-desktop-input.ts` facade over `remote-desktop-input-{win32,darwin,linux,uinput}.ts` (bun:ffi, no helper binary); host checklist in `remote-desktop-requirements.ts` (ffmpeg install command, macOS TCC pre-flight, Linux session/XTEST/uinput rows); display list in `remote-desktop-displays.ts` (`CGGetActiveDisplayList` order = avfoundation `Capture screen N`, names/bounds via one JXA call; X11 monitors via `XRRGetMonitors`). Linux specifics: `remote-desktop-linux-session.ts` decides X11 vs Wayland and resolves `DISPLAY`/`XAUTHORITY` (a Wayland session then takes a separate capture backend: `remote-desktop-portal.ts` holds the `org.freedesktop.portal.ScreenCast` session over libdbus FFI and `remote-desktop-capture-wayland.ts` runs `gst-launch-1.0` against the PipeWire node it hands back, producing the same Annex-B stdout ffmpeg does), `remote-desktop-x11.ts` is the shared Xlib connection, `remote-desktop-evdev-key-map.ts` is the one key table both Linux backends use. Clipboard sync is `remote-desktop-clipboard.ts` (host side, one helper process per read/write) and `src/web/components/remote-desktop/remote-desktop-clipboard-client.ts` (which key combos mean copy/paste, plus the insecure-origin copy fallback). The in-session controls are `remote-desktop-toolbar.tsx` (desktop, RustDesk's grouped menus) and `remote-desktop-mobile-toolbar.tsx` + `remote-desktop-mobile-settings.tsx` (thumb zone), with the scale maths in `remote-desktop-view-style.ts`. Host audio is `remote-desktop-audio.ts` (a second ffmpeg, Opus in Ogg) demuxed by `remote-desktop-ogg-opus.ts` and played by `use-opus-audio-player.ts`; privacy mode is `remote-desktop-privacy.ts` (X grabs + DPMS); host resolution is `remote-desktop-resolution.ts` (XRandR FFI) with the menu collapse and the fit-local decision in `remote-desktop-resolution-list.ts`; the custom image-quality maths ported from RustDesk's `video_qos.rs` are `src/shared/remote-desktop-custom-quality.ts` behind `remote-desktop-custom-quality-dialog.tsx`; screenshot/recording are `remote-desktop-recording.ts` + `use-remote-desktop-recorder.ts` (client-side `MediaRecorder` over the canvas). The WebRTC transport is an optional downloaded relay: `mediamtx-catalog.ts` (pinned version + SHA-256 per platform), `mediamtx-install.service.ts`, `mediamtx-paths.ts`, `mediamtx-config.ts` (the generated config — the one place the relay's exposure is decided) and `mediamtx-process.ts` (one relay per session, free ports, waits until it is really listening); `buildCaptureArgs`'s last argument swaps `pipe:1` for an RTSP push, `remote-desktop-whep-registry.ts` + `POST /api/remote-desktop/whep/:ticket` are the authenticated, **ticket-addressed** handshake proxy, and `use-webrtc-canvas-video.ts` paints the track into the same canvas the WebCodecs path draws to. Settings pane `settings/remote-desktop-settings-section.tsx`. Codec choice comes from `workingEncoders()` in `media-transcode/ffmpeg-capabilities.ts`, which probes *every* candidate rather than short-circuiting. Routes `src/server/routes/remote-desktop.ts`, WS `src/server/ws/remote-desktop.ts`, UI `src/web/components/remote-desktop/`, e2e `tests/e2e/remote-desktop-e2e.mjs`
|
|
243
254
|
- `src/services/git-hunks/` — hunk/line-level stage, unstage and discard (`/api/projects/:name/git/{hunks,stage-hunks,unstage-hunks,discard-hunks}`). `unified-diff.ts` holds the patch surgery (recomputed `@@` counts, unselected deletions demoted to context); the UI is `src/web/components/git/hunk-stage-dialog.tsx`
|
|
244
255
|
- `src/services/git-repos/` — which repository a project's git surfaces run in, when the project folder is a container of checkouts rather than a repository itself. `git-repo-discovery.ts` walks the folder (`GET /git/repos`), the `?repo=` middleware in `src/server/routes/git.ts` scopes every git route to one of them, and the browser side is `src/web/lib/git-repo-scope.ts` (pure decisions and both directions of path rebasing), `src/web/stores/git-repo-store.ts` (the device-local choice), `src/web/hooks/use-git-repo.ts` (what every panel calls) and `src/web/components/git/git-repo-picker.tsx`. Extension panels are opened on the repository, so `packages/ext-git-graph/src/project-scope.ts` maps that path back to the containing project
|
|
245
256
|
- `src/web/lib/icons.ts` + `src/web/lib/icons.generated.tsx` + `src/web/lib/fluent-icon.tsx` — the product icons (Fluent System Icons 20px Regular, MIT, microsoft/fluentui-system-icons) for the app's own chrome. Every UI icon is imported from `@/lib/icons`; regenerate with `bun scripts/gen-product-icons.ts` after editing its `MAP`
|
|
@@ -71,4 +71,4 @@ This skill covers the `ppm` CLI, its HTTP API, and its config DB. It does **not*
|
|
|
71
71
|
- Third-party extensions (inspect via `ppm ext list`).
|
|
72
72
|
- The Claude Agent SDK internals (separate skill).
|
|
73
73
|
|
|
74
|
-
<!-- Generated for PPM v0.23.
|
|
74
|
+
<!-- Generated for PPM v0.23.12 at build time. Re-run `ppm export skill --install` to refresh. -->
|
|
@@ -781,7 +781,7 @@ Show recent runs for a schedule
|
|
|
781
781
|
Manage and inspect discovered skills & commands
|
|
782
782
|
|
|
783
783
|
**Options:**
|
|
784
|
-
- `--project <path>` — Project path (default: `"C:\\Users\\PC\\ppm-release-0.23.
|
|
784
|
+
- `--project <path>` — Project path (default: `"C:\\Users\\PC\\ppm-release-0.23.12"`)
|
|
785
785
|
|
|
786
786
|
**Usage:** `ppm skills [options] [command]`
|
|
787
787
|
|
|
@@ -791,7 +791,7 @@ List all discovered skills and commands
|
|
|
791
791
|
|
|
792
792
|
**Options:**
|
|
793
793
|
- `--json` — JSON output
|
|
794
|
-
- `--project <path>` — Project path (default: `"C:\\Users\\PC\\ppm-release-0.23.
|
|
794
|
+
- `--project <path>` — Project path (default: `"C:\\Users\\PC\\ppm-release-0.23.12"`)
|
|
795
795
|
|
|
796
796
|
### `ppm skills search`
|
|
797
797
|
|
|
@@ -799,7 +799,7 @@ Fuzzy search skills and commands
|
|
|
799
799
|
|
|
800
800
|
**Options:**
|
|
801
801
|
- `--json` — JSON output
|
|
802
|
-
- `--project <path>` — Project path (default: `"C:\\Users\\PC\\ppm-release-0.23.
|
|
802
|
+
- `--project <path>` — Project path (default: `"C:\\Users\\PC\\ppm-release-0.23.12"`)
|
|
803
803
|
|
|
804
804
|
**Usage:** `ppm skills search [options] <query>`
|
|
805
805
|
|
|
@@ -809,7 +809,7 @@ Show detailed info for a specific skill
|
|
|
809
809
|
|
|
810
810
|
**Options:**
|
|
811
811
|
- `--json` — JSON output
|
|
812
|
-
- `--project <path>` — Project path (default: `"C:\\Users\\PC\\ppm-release-0.23.
|
|
812
|
+
- `--project <path>` — Project path (default: `"C:\\Users\\PC\\ppm-release-0.23.12"`)
|
|
813
813
|
|
|
814
814
|
**Usage:** `ppm skills info [options] <name>`
|
|
815
815
|
|
|
@@ -42,6 +42,33 @@ _Base URL: `http://localhost:8080` (default; override via `ppm config set port <
|
|
|
42
42
|
- `POST /api/ai-resources/duplicate`
|
|
43
43
|
- `DELETE /api/ai-resources`
|
|
44
44
|
|
|
45
|
+
## /api/android
|
|
46
|
+
|
|
47
|
+
- `GET /api/android/android`
|
|
48
|
+
- `GET /api/android/auth`
|
|
49
|
+
- `GET /api/android/capabilities`
|
|
50
|
+
- `GET /api/android/auth`
|
|
51
|
+
- `GET /api/android/devices`
|
|
52
|
+
- `POST /api/android/avds/:avdId/start`
|
|
53
|
+
- `GET /api/android/operations/:id`
|
|
54
|
+
- `POST /api/android/devices/:deviceId/stop`
|
|
55
|
+
- `GET /api/android/devices/:deviceId/log`
|
|
56
|
+
- `POST /api/android/devices/:deviceId/sessions`
|
|
57
|
+
- `GET /api/android/devices/:deviceId/screenshot`
|
|
58
|
+
- `GET /api/android/devices/:deviceId/clipboard`
|
|
59
|
+
- `POST /api/android/devices/:deviceId/clipboard`
|
|
60
|
+
- `POST /api/android/operations/:id/cancel`
|
|
61
|
+
- `POST /api/android/devices/:deviceId/apk`
|
|
62
|
+
- `POST /api/android/devices/:deviceId/apk/project`
|
|
63
|
+
- `GET /api/android/projects`
|
|
64
|
+
- `GET /api/android/projects/:project/apks`
|
|
65
|
+
- `GET /api/android/projects`
|
|
66
|
+
- `GET /api/android/system-images`
|
|
67
|
+
- `GET /api/android/device-profiles`
|
|
68
|
+
- `POST /api/android/avds`
|
|
69
|
+
- `POST /api/android/avds/:avdId/wipe`
|
|
70
|
+
- `DELETE /api/android/avds/:avdId`
|
|
71
|
+
|
|
45
72
|
## /api/chat
|
|
46
73
|
|
|
47
74
|
- `GET /api/chat/sessions/running`
|
|
@@ -229,6 +256,10 @@ _Base URL: `http://localhost:8080` (default; override via `ppm config set port <
|
|
|
229
256
|
- `GET /api/remote-desktop/auth`
|
|
230
257
|
- `POST /api/remote-desktop/requirements/:id/:action`
|
|
231
258
|
- `POST /api/remote-desktop/session`
|
|
259
|
+
- `POST /api/remote-desktop/whep/:ticket`
|
|
260
|
+
- `GET /api/remote-desktop/relay`
|
|
261
|
+
- `POST /api/remote-desktop/relay/install`
|
|
262
|
+
- `POST /api/remote-desktop/relay/uninstall`
|
|
232
263
|
|
|
233
264
|
## /api/schedules
|
|
234
265
|
|
|
@@ -341,6 +372,11 @@ _Base URL: `http://localhost:8080` (default; override via `ppm config set port <
|
|
|
341
372
|
- `GET /api/teams/:name/members/:member/transcript`
|
|
342
373
|
- `DELETE /api/teams/:name`
|
|
343
374
|
|
|
375
|
+
## /api/trace
|
|
376
|
+
|
|
377
|
+
- `POST /api/trace`
|
|
378
|
+
- `GET /api/trace/sessions/:sessionId`
|
|
379
|
+
|
|
344
380
|
## /api/tunnel
|
|
345
381
|
|
|
346
382
|
- `GET /api/tunnel`
|
|
@@ -394,4 +430,4 @@ _Base URL: `http://localhost:8080` (default; override via `ppm config set port <
|
|
|
394
430
|
- `ws://<host>/ws/terminal` — PTY terminal multiplexer
|
|
395
431
|
- `ws://<host>/ws/extensions` — extension host channel
|
|
396
432
|
|
|
397
|
-
<!-- Generated from src/server/routes/ for PPM v0.23.
|
|
433
|
+
<!-- Generated from src/server/routes/ for PPM v0.23.12 -->
|
package/bun.lock
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
"@anthropic-ai/claude-agent-sdk": "0.3.280",
|
|
9
9
|
"@codemirror/lang-sql": "^6.10.0",
|
|
10
10
|
"@glideapps/glide-data-grid": "^6.0.3",
|
|
11
|
+
"@grpc/grpc-js": "1.14.0",
|
|
12
|
+
"@grpc/proto-loader": "0.7.15",
|
|
11
13
|
"@inquirer/prompts": "^8.3.0",
|
|
12
14
|
"@monaco-editor/react": "^4.7.0",
|
|
13
15
|
"@radix-ui/react-switch": "^1.2.6",
|
|
@@ -424,6 +426,10 @@
|
|
|
424
426
|
|
|
425
427
|
"@glideapps/glide-data-grid": ["@glideapps/glide-data-grid@6.0.3", "", { "dependencies": { "@linaria/react": "^4.5.3", "canvas-hypertxt": "^1.0.3", "react-number-format": "^5.0.0" }, "peerDependencies": { "lodash": "^4.17.19", "marked": "^4.0.10", "react": "^16.12.0 || 17.x || 18.x", "react-dom": "^16.12.0 || 17.x || 18.x", "react-responsive-carousel": "^3.2.7" } }, "sha512-YXKggiNOaEemf0jP0jORq2EQKz+zXms+6mGzZc+q0mLMjmgzzoGLOQC1uYcynXSj1R61bd27JcPFsoH+Gj37Vg=="],
|
|
426
428
|
|
|
429
|
+
"@grpc/grpc-js": ["@grpc/grpc-js@1.14.0", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-N8Jx6PaYzcTRNzirReJCtADVoq4z7+1KQ4E70jTg/koQiMoUSN1kbNjPOqpPbhMFhfU1/l7ixspPl8dNY+FoUg=="],
|
|
430
|
+
|
|
431
|
+
"@grpc/proto-loader": ["@grpc/proto-loader@0.7.15", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ=="],
|
|
432
|
+
|
|
427
433
|
"@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="],
|
|
428
434
|
|
|
429
435
|
"@iconify-json/fluent": ["@iconify-json/fluent@1.2.57", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-ecYjdYhwiQ+UNz94cOnYY8RCRbZ8+N54jzocxmfgRZgblM2IvG8RRGeI9Z52jxG8KhZcLftxyhvvk/rrqKSZLw=="],
|
|
@@ -480,6 +486,8 @@
|
|
|
480
486
|
|
|
481
487
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
|
482
488
|
|
|
489
|
+
"@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="],
|
|
490
|
+
|
|
483
491
|
"@kwsites/file-exists": ["@kwsites/file-exists@1.1.1", "", { "dependencies": { "debug": "^4.1.1" } }, "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw=="],
|
|
484
492
|
|
|
485
493
|
"@kwsites/promise-deferred": ["@kwsites/promise-deferred@1.1.1", "", {}, "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw=="],
|
|
@@ -524,6 +532,24 @@
|
|
|
524
532
|
|
|
525
533
|
"@profoundlogic/hogan": ["@profoundlogic/hogan@3.0.4", "", { "dependencies": { "nopt": "1.0.10" }, "bin": { "hulk": "bin/hulk" } }, "sha512-pmNVGuooS30Mm7YbZd5T7E5zYVO6D5Ct91sn4T39mUvMUc3sCGridcnhAufL1/Bz2QzAtzEn0agNrdk3+5yWzw=="],
|
|
526
534
|
|
|
535
|
+
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
|
|
536
|
+
|
|
537
|
+
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
|
|
538
|
+
|
|
539
|
+
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.5", "", {}, "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g=="],
|
|
540
|
+
|
|
541
|
+
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.1", "", {}, "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg=="],
|
|
542
|
+
|
|
543
|
+
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.1", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1" } }, "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw=="],
|
|
544
|
+
|
|
545
|
+
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
|
|
546
|
+
|
|
547
|
+
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
|
|
548
|
+
|
|
549
|
+
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
|
|
550
|
+
|
|
551
|
+
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.2", "", {}, "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug=="],
|
|
552
|
+
|
|
527
553
|
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
|
|
528
554
|
|
|
529
555
|
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
|
@@ -1530,10 +1556,14 @@
|
|
|
1530
1556
|
|
|
1531
1557
|
"lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="],
|
|
1532
1558
|
|
|
1559
|
+
"lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="],
|
|
1560
|
+
|
|
1533
1561
|
"lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="],
|
|
1534
1562
|
|
|
1535
1563
|
"lodash.sortby": ["lodash.sortby@4.7.0", "", {}, "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="],
|
|
1536
1564
|
|
|
1565
|
+
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
|
1566
|
+
|
|
1537
1567
|
"longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
|
|
1538
1568
|
|
|
1539
1569
|
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
|
|
@@ -1768,6 +1798,8 @@
|
|
|
1768
1798
|
|
|
1769
1799
|
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
|
1770
1800
|
|
|
1801
|
+
"protobufjs": ["protobufjs@7.6.6", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.3.2" } }, "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg=="],
|
|
1802
|
+
|
|
1771
1803
|
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
|
1772
1804
|
|
|
1773
1805
|
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
|
@@ -2212,6 +2244,8 @@
|
|
|
2212
2244
|
|
|
2213
2245
|
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
|
2214
2246
|
|
|
2247
|
+
"@grpc/grpc-js/@grpc/proto-loader": ["@grpc/proto-loader@0.8.1", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg=="],
|
|
2248
|
+
|
|
2215
2249
|
"@rollup/plugin-node-resolve/@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
|
|
2216
2250
|
|
|
2217
2251
|
"@rollup/plugin-replace/magic-string": ["magic-string@0.25.9", "", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{s as e}from"./rolldown-runtime-C5c2KzVm.js";import{C as t,S as n}from"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import{Jr as r,Lr as i,Mr as a,St as o,V as s,Zn as c,Zt as l,fn as u,fr as d,nt as f,st as p,un as m}from"./icons-CO_II6D-.js";import{a as h}from"./api-client-F5Zi1sR0.js";import{n as g}from"./utils-btZ8C8-R.js";import"./portal-container-context-NFSuymMu.js";import"./chat-preparation-cache-BUCR58h4.js";import{n as _}from"./use-is-mobile-BClDZJP5.js";import{n as v,t as y}from"./button-DeAyLH9U.js";import{a as b,i as x,n as S,o as C,r as w,t as T}from"./dialog-Bocc0Fgb.js";import{t as E}from"./mobile-bottom-sheet-D4UyOatB.js";import"./use-visual-viewport-BGpcMnIx.js";import{t as D}from"./input-CG8PS8mS.js";import{Ct as O,Et as k,Lt as A,St as j,Tt as M,Vn as N,_r as P,gr as F,rr as ee,vr as I,wt as te,xt as ne}from"./index-CyDLBddf.js";import{_ as re,a as ie,h as ae,m as oe,o as se,p as ce,r as le,v as ue,x as L,y as de}from"./api-settings-Cc_CpfmC.js";import{_ as fe,a as pe,b as me,c as he,d as ge,g as R,h as z,l as _e,m as ve,n as ye,o as be,p as B,r as xe,s as V,t as Se,u as Ce,x as H,y as U}from"./codex-reset-credit-button-DRhievFQ.js";var W=e(t(),1),G=n(),K=[`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`,`Sun`],q=Array.from({length:24},(e,t)=>t);function we(e,t){let n=Array.from({length:7},()=>Array.from({length:24},()=>({sum:0,count:0,avg:0})));for(let r of e){let e=t===`5h`?r.five_hour_util:r.weekly_util;if(e==null)continue;let i=new Date(r.recorded_at+(r.recorded_at.endsWith(`Z`)?``:`Z`)),a=(i.getDay()+6)%7,o=i.getHours();n[a][o].sum+=e,n[a][o].count+=1}for(let e of n)for(let t of e)t.avg=t.count>0?t.sum/t.count:0;return n}function Te(e){return e.map(e=>{let t=e.reduce((e,t)=>e+t.sum,0),n=e.reduce((e,t)=>e+t.count,0);return n>0?t/n:0})}function Ee(e){return q.map(t=>{let n=0,r=0;for(let i of e)n+=i[t].sum,r+=i[t].count;return r>0?n/r:0})}function J(e){return e===0?`bg-surface-elevated`:e<.3?`bg-success/30`:e<.5?`bg-success/60`:e<.7?`bg-warning/50`:e<.9?`bg-warning/80`:`bg-error/80`}function De(e){return e<.3?`bg-success`:e<.7?`bg-warning`:`bg-error`}function Oe({accountId:e}){let[t,n]=(0,W.useState)(null),[r,i]=(0,W.useState)(!0),[a,o]=(0,W.useState)(`5h`);(0,W.useEffect)(()=>{i(!0),ce(e).then(n).catch(()=>n([])).finally(()=>i(!1))},[e]);let s=(0,W.useMemo)(()=>t?we(t,a):null,[t,a]),c=(0,W.useMemo)(()=>s?Te(s):[],[s]),l=(0,W.useMemo)(()=>s?Ee(s):[],[s]),u=Math.max(...c,.01);if(Math.max(...l,.01),r)return(0,G.jsx)(`div`,{className:`flex items-center justify-center py-3`,children:(0,G.jsx)(m,{className:`size-3 animate-spin text-text-subtle`})});if(!t||t.length===0)return(0,G.jsx)(`div`,{className:`text-[10px] text-text-subtle py-2 text-center`,children:`No usage history yet`});let d=t.length,f=new Set(t.map(e=>new Date(e.recorded_at+(e.recorded_at.endsWith(`Z`)?``:`Z`)).toDateString())).size;return(0,G.jsxs)(`div`,{className:`mt-2 space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`span`,{className:`text-[10px] font-medium text-text-subtle`,children:`Usage Pattern (7d)`}),(0,G.jsxs)(`div`,{className:`flex gap-0.5 text-[9px]`,children:[(0,G.jsx)(`button`,{onClick:()=>o(`5h`),className:`px-1.5 py-0.5 rounded cursor-pointer transition-colors ${a===`5h`?`bg-primary/15 text-primary`:`text-text-subtle hover:text-text-secondary`}`,title:`5-hour rolling window limit — resets every 5 hours`,children:`5h`}),(0,G.jsx)(`button`,{onClick:()=>o(`weekly`),className:`px-1.5 py-0.5 rounded cursor-pointer transition-colors ${a===`weekly`?`bg-primary/15 text-primary`:`text-text-subtle hover:text-text-secondary`}`,title:`Weekly limit — resets every 7 days`,children:`Wk`})]})]}),(0,G.jsxs)(`p`,{className:`text-[9px] text-text-subtle leading-tight`,children:[`Avg `,a===`5h`?`5-hour`:`weekly`,` limit usage over `,f,`d (`,d,` samples). Higher % = closer to rate limit. Hover cells for details.`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{className:`text-[9px] text-text-subtle`,children:`Avg usage by day of week`}),(0,G.jsx)(`div`,{className:`flex flex-col gap-[2px] mt-0.5`,children:K.map((e,t)=>{let n=c[t]??0;return(0,G.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,G.jsx)(`span`,{className:`text-[8px] text-text-subtle w-5 shrink-0 text-right tabular-nums`,children:e}),(0,G.jsx)(`div`,{className:`flex-1 h-2.5 bg-surface-elevated rounded-sm overflow-hidden`,children:(0,G.jsx)(`div`,{className:`h-full rounded-sm transition-all ${De(n)}`,style:{width:`${Math.round(n/u*100)}%`}})}),(0,G.jsxs)(`span`,{className:`text-[8px] text-text-subtle w-6 shrink-0 text-right tabular-nums`,children:[Math.round(n*100),`%`]})]},e)})})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{className:`text-[9px] text-text-subtle`,children:`Avg usage by hour (0h-23h)`}),(0,G.jsx)(`div`,{className:`flex gap-[1px] mt-0.5`,children:q.map(e=>{let t=l[e]??0;return(0,G.jsxs)(`div`,{className:`flex-1 flex flex-col items-center gap-[1px]`,children:[(0,G.jsx)(`div`,{className:`w-full aspect-square rounded-[2px] ${J(t)}`,title:`${e}:00 — avg ${Math.round(t*100)}% usage`}),e%6==0&&(0,G.jsx)(`span`,{className:`text-[7px] text-text-subtle tabular-nums`,children:e})]},e)})})]}),s&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{className:`text-[9px] text-text-subtle`,children:`Day x Hour heatmap`}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-[1px] mt-0.5`,children:[K.map((e,t)=>(0,G.jsxs)(`div`,{className:`flex items-center gap-[1px]`,children:[(0,G.jsx)(`span`,{className:`text-[7px] text-text-subtle w-4 shrink-0 text-right`,children:e.charAt(0)}),q.map(n=>{let r=s[t][n];return(0,G.jsx)(`div`,{className:`flex-1 aspect-square rounded-[1px] ${J(r.avg)}`,title:`${e} ${n}:00 — ${r.count>0?`avg ${Math.round(r.avg*100)}% (${r.count} samples)`:`no data`}`},n)})]},e)),(0,G.jsxs)(`div`,{className:`flex items-center gap-[1px]`,children:[(0,G.jsx)(`span`,{className:`w-4 shrink-0`}),q.map(e=>(0,G.jsx)(`div`,{className:`flex-1 text-center`,children:e%6==0&&(0,G.jsx)(`span`,{className:`text-[7px] text-text-subtle tabular-nums`,children:e})},e))]})]})]}),(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[8px] text-text-subtle`,children:[(0,G.jsx)(`span`,{children:`Low`}),(0,G.jsxs)(`div`,{className:`flex gap-[2px]`,children:[(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-success/30`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-success/60`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-warning/50`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-warning/80`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-error/80`})]}),(0,G.jsx)(`span`,{children:`High`}),(0,G.jsx)(`span`,{className:`ml-1`,children:`|`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-surface-elevated border border-border/30`}),(0,G.jsx)(`span`,{children:`No data`})]})]})}function ke({profile:e,accountId:t,onClose:n}){let i=[[`Name`,e.account?.display_name],[`Email`,e.account?.email],[`Org`,e.organization?.name],[`Type`,e.organization?.organization_type],[`Tier`,e.organization?.rate_limit_tier],[`Status`,e.organization?.subscription_status]];return(0,G.jsxs)(`section`,{className:`space-y-2 border-t border-border pt-3`,"data-testid":`account-profile-panel`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium`,children:`Profile`}),(0,G.jsx)(`button`,{className:`p-2 text-muted-foreground hover:text-foreground cursor-pointer`,onClick:n,"aria-label":`Close profile`,children:(0,G.jsx)(r,{className:`size-4`})})]}),(0,G.jsx)(`div`,{className:`grid grid-cols-[80px_1fr] gap-x-3 gap-y-1 text-xs`,children:i.map(([e,t])=>t?(0,G.jsxs)(`span`,{className:`contents`,children:[(0,G.jsx)(`span`,{className:`text-muted-foreground`,children:e}),(0,G.jsx)(`span`,{className:`break-all`,children:t})]},e):null)}),(0,G.jsx)(Oe,{accountId:t})]})}function Ae({display:e,onConfirm:t,onCancel:n}){let r=_(),i=(0,G.jsxs)(`div`,{className:`space-y-4`,"data-testid":`account-delete-confirm`,children:[(0,G.jsxs)(`p`,{className:`text-sm`,children:[`Remove `,(0,G.jsx)(`span`,{className:`font-medium`,children:e}),`?`]}),(0,G.jsx)(`p`,{className:`text-xs text-text-subtle`,children:`The stored token is deleted from this machine. Any export you already made keeps working.`}),(0,G.jsxs)(`div`,{className:`flex flex-col-reverse md:flex-row gap-2 md:justify-end pt-2`,children:[(0,G.jsx)(y,{variant:`outline`,onClick:n,className:`min-h-11`,children:`Cancel`}),(0,G.jsx)(y,{variant:`destructive`,autoFocus:!1,onClick:t,className:`min-h-11`,children:`Remove account`})]})]});return r?(0,G.jsx)(E,{open:!0,onClose:n,children:(0,G.jsxs)(`div`,{className:`px-4 pb-4`,children:[(0,G.jsx)(`h2`,{className:`text-base font-semibold mb-3`,children:`Remove account`}),i]})}):(0,G.jsx)(T,{open:!0,onOpenChange:e=>{e||n()},children:(0,G.jsxs)(S,{className:`sm:max-w-sm`,children:[(0,G.jsx)(b,{children:(0,G.jsx)(C,{className:`text-sm`,children:`Remove account`})}),i]})})}function je(e){let t=new Blob([e],{type:`application/json`}),n=document.createElement(`a`);n.href=URL.createObjectURL(t),n.download=`ppm-accounts-backup.json`,n.click(),URL.revokeObjectURL(n.href)}function Me({open:e,onOpenChange:t,accounts:n,preselectId:r,onMessage:i}){let a=n.filter(e=>e.hasRefreshToken),[o,s]=(0,W.useState)(new Set),[c,l]=(0,W.useState)(``),[d,g]=(0,W.useState)(!1),[_,v]=(0,W.useState)(!1),[E,O]=(0,W.useState)(!1),[k,j]=(0,W.useState)(!1);e&&!k&&(s(r?new Set([r]):new Set(a.map(e=>e.id))),j(!0)),!e&&k&&j(!1);function M(){t(!1),l(``),g(!1),v(!1)}async function P(e){if(o.size===0)return;O(!0);let t=c.trim()||`ppm-hienlh`;try{let n={"Content-Type":`application/json`},r=h();r&&(n.Authorization=`Bearer ${r}`);let a=await fetch(`/api/accounts/export`,{method:`POST`,headers:n,body:JSON.stringify({password:t,accountIds:[...o],includeRefreshToken:d,refreshBeforeExport:_})});if(!a.ok){let e=await a.json();throw Error(e.error??`Export failed: ${a.status}`)}let s=await a.text();e&&await N(s)?i?.(`Backup copied to clipboard!`):(je(s),i?.(`Backup downloaded.`)),M()}catch{}O(!1)}let F=o.size>0&&!E;return(0,G.jsx)(T,{open:e,onOpenChange:e=>{e||M()},children:(0,G.jsxs)(S,{className:`sm:max-w-md`,children:[(0,G.jsxs)(b,{children:[(0,G.jsxs)(C,{className:`text-sm flex items-center gap-1.5`,children:[(0,G.jsx)(u,{className:`size-3.5`}),` Export Accounts`]}),(0,G.jsx)(w,{className:`text-xs`,children:`Select accounts and set a password to protect the backup.`})]}),(0,G.jsxs)(`div`,{className:`space-y-3`,children:[(0,G.jsxs)(`div`,{className:`space-y-1`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between mb-1`,children:[(0,G.jsx)(`p`,{className:`text-[11px] font-medium text-muted-foreground`,children:`Accounts to export`}),(0,G.jsx)(`button`,{className:`text-[10px] text-primary hover:underline cursor-pointer`,onClick:()=>s(o.size===a.length?new Set:new Set(a.map(e=>e.id))),children:o.size===a.length?`Deselect all`:`Select all`})]}),a.length===0?(0,G.jsx)(`p`,{className:`text-[10px] text-muted-foreground p-2 border rounded`,children:`No exportable accounts.`}):(0,G.jsx)(`div`,{className:`max-h-36 overflow-y-auto space-y-1 border rounded p-2`,children:a.map(e=>(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`input`,{type:`checkbox`,id:`exp-${e.id}`,checked:o.has(e.id),onChange:t=>{let n=new Set(o);t.target.checked?n.add(e.id):n.delete(e.id),s(n)},className:`size-3.5 accent-primary cursor-pointer`}),(0,G.jsx)(`label`,{htmlFor:`exp-${e.id}`,className:`text-xs cursor-pointer truncate`,children:e.label??e.email??e.id.slice(0,8)})]},e.id))})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsxs)(A,{className:`text-xs`,children:[`Password `,(0,G.jsx)(`span`,{className:`text-muted-foreground font-normal`,children:`(optional)`})]}),(0,G.jsx)(D,{type:`password`,placeholder:`Leave empty for default`,value:c,onChange:e=>l(e.target.value),className:`text-xs h-8`,autoComplete:`new-password`})]}),(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`input`,{type:`checkbox`,id:`exp-full`,checked:d,onChange:e=>g(e.target.checked),className:`size-3.5 accent-primary cursor-pointer`}),(0,G.jsx)(`label`,{htmlFor:`exp-full`,className:`text-[11px] cursor-pointer`,children:`Include refresh tokens (full transfer)`})]}),(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`input`,{type:`checkbox`,id:`exp-refresh`,checked:_,onChange:e=>v(e.target.checked),className:`size-3.5 accent-primary cursor-pointer`}),(0,G.jsx)(`label`,{htmlFor:`exp-refresh`,className:`text-[11px] cursor-pointer`,children:`Refresh tokens before export`})]}),d?(0,G.jsxs)(`div`,{className:`rounded-md border border-error/30 bg-error/5 p-2.5`,children:[(0,G.jsx)(`p`,{className:`text-[10px] font-medium text-error`,children:`Full transfer — source accounts will expire`}),(0,G.jsx)(`p`,{className:`text-[10px] text-muted-foreground`,children:`Refresh tokens included. Source machine expires in ~1h after target refreshes.`})]}):_?(0,G.jsx)(`div`,{className:`rounded-md border border-warning/30 bg-warning/5 p-2.5`,children:(0,G.jsx)(`p`,{className:`text-[10px] font-medium text-warning`,children:`Refresh before export — invalidates previous shares`})}):(0,G.jsx)(`div`,{className:`rounded-md border border-success/30 bg-success/5 p-2.5`,children:(0,G.jsx)(`p`,{className:`text-[10px] font-medium text-success`,children:`Share current token (safe)`})}),(0,G.jsx)(`p`,{className:`text-[10px] text-muted-foreground`,children:`Encrypted with AES-256-GCM + scrypt.`})]}),(0,G.jsxs)(x,{className:`gap-1.5 flex-col sm:flex-row`,children:[(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs h-7 cursor-pointer`,onClick:M,children:`Cancel`}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`text-xs h-7 cursor-pointer`,disabled:!F,onClick:()=>P(!0),children:[(0,G.jsx)(f,{className:`size-3 mr-1`}),` Copy`]}),(0,G.jsx)(y,{size:`sm`,className:`text-xs h-7 cursor-pointer`,disabled:!F,onClick:()=>P(!1),children:E?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(m,{className:`size-3 animate-spin mr-1`}),` Exporting...`]}):(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(p,{className:`size-3 mr-1`}),` Download`]})})]})]})})}function Ne({open:e,onOpenChange:t,onSuccess:n}){let[r,i]=(0,W.useState)(``),[a,o]=(0,W.useState)(``),[s,c]=(0,W.useState)(!1),[l,d]=(0,W.useState)(null);function f(){t(!1),i(``),o(``),d(null)}async function p(){if(r.trim()){c(!0),d(null);try{let e=await oe({data:r.trim(),password:a.trim()||`ppm-hienlh`});f(),n(`Imported ${e.imported} account(s)`)}catch(e){d(e.message||`Import failed`)}c(!1)}}return(0,G.jsx)(T,{open:e,onOpenChange:e=>{e||f()},children:(0,G.jsxs)(S,{className:`sm:max-w-md`,children:[(0,G.jsxs)(b,{children:[(0,G.jsxs)(C,{className:`text-sm flex items-center gap-1.5`,children:[(0,G.jsx)(u,{className:`size-3.5`}),` Import Accounts`]}),(0,G.jsx)(w,{className:`text-xs`,children:`Paste backup data and enter the export password. Imported accounts are temporary (~1h).`})]}),(0,G.jsxs)(`div`,{className:`space-y-3`,children:[(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsx)(A,{className:`text-xs`,children:`Backup data`}),(0,G.jsx)(`textarea`,{value:r,onChange:e=>i(e.target.value),placeholder:`Paste backup JSON here...`,rows:4,className:`w-full text-xs p-2 rounded border border-border bg-background font-mono resize-none focus:outline-none focus:ring-1 focus:ring-primary`})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsxs)(A,{className:`text-xs`,children:[`Password `,(0,G.jsx)(`span`,{className:`text-muted-foreground font-normal`,children:`(optional)`})]}),(0,G.jsx)(D,{type:`password`,placeholder:`Leave empty for default`,value:a,onChange:e=>o(e.target.value),className:`text-xs h-8`,autoComplete:`current-password`})]})]}),l&&(0,G.jsx)(`div`,{className:`text-[11px] p-2 rounded bg-error/10 text-error`,children:l}),(0,G.jsxs)(x,{children:[(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs h-7 cursor-pointer`,onClick:f,children:`Cancel`}),(0,G.jsx)(y,{size:`sm`,className:`text-xs h-7 cursor-pointer`,disabled:!r.trim()||s,onClick:p,children:s?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(m,{className:`size-3 animate-spin mr-1`}),` Importing...`]}):`Import`})]})]})})}var Y=typeof window<`u`?window.matchMedia(`(min-width: 768px)`):null;function Pe(e){return Y?.addEventListener(`change`,e),()=>Y?.removeEventListener(`change`,e)}function Fe(){return Y?.matches??!0}function X(){let[e,t]=(0,W.useState)(null),[n,r]=(0,W.useState)(!0);return(0,W.useEffect)(()=>{r(!0),se().then(t).finally(()=>r(!1))},[]),n?(0,G.jsx)(`p`,{className:`text-xs text-text-subtle py-4 text-center`,children:`Loading...`}):e?(0,G.jsxs)(`div`,{className:`space-y-4`,children:[(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsx)(`label`,{className:`text-xs font-medium text-text-primary`,children:`Rotation Strategy`}),(0,G.jsxs)(ne,{value:e.strategy,onValueChange:async e=>{t(await L({strategy:e}))},children:[(0,G.jsx)(te,{className:`w-full h-9 text-xs`,children:(0,G.jsx)(M,{})}),(0,G.jsxs)(j,{children:[(0,G.jsx)(O,{value:`round-robin`,children:`Round-robin`}),(0,G.jsx)(O,{value:`fill-first`,children:`Fill-first`}),(0,G.jsx)(O,{value:`lowest-usage`,children:`Lowest usage`})]})]}),(0,G.jsxs)(`p`,{className:`text-[10px] text-text-subtle`,children:[e.strategy===`round-robin`&&`Cycles through accounts evenly`,e.strategy===`fill-first`&&`Uses one account until its limit, then moves on`,e.strategy===`lowest-usage`&&`Picks the account with the lowest current usage`]})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsx)(`label`,{className:`text-xs font-medium text-text-primary`,children:`Max Retry`}),(0,G.jsx)(`input`,{type:`number`,min:0,value:e.maxRetry,className:`w-full h-9 text-xs border rounded-md px-3 bg-background`,onChange:async e=>{let n=parseInt(e.target.value,10);!isNaN(n)&&n>=0&&t(await L({maxRetry:n}))}}),(0,G.jsx)(`p`,{className:`text-[10px] text-text-subtle`,children:`How many accounts to try on failure. 0 = try all available accounts.`})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5 border-t border-border pt-3`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`label`,{className:`text-xs font-medium text-text-primary`,children:`Cooldown parking`}),(0,G.jsx)(k,{checked:e.cooldownEnabled,onCheckedChange:async e=>{t(await L({cooldownEnabled:e}))}})]}),(0,G.jsx)(`p`,{className:`text-[10px] text-text-subtle`,children:`Park a failing account (rate limit / usage limit / auth error) until it recovers. Off: accounts stay selectable — rotation still skips accounts already ≥95% on the 5-hour limit.`})]}),(0,G.jsxs)(`div`,{className:`flex items-center justify-between text-xs border-t border-border pt-3`,children:[(0,G.jsx)(`span`,{className:`text-text-subtle`,children:`Active accounts`}),(0,G.jsx)(`span`,{className:`font-medium text-text-primary`,children:e.activeCount})]})]}):(0,G.jsx)(`p`,{className:`text-xs text-text-subtle py-4 text-center`,children:`Failed to load settings`})}function Ie({open:e,onOpenChange:t}){let n=(0,W.useSyncExternalStore)(Pe,Fe);return e?n?(0,G.jsx)(T,{open:e,onOpenChange:t,children:(0,G.jsxs)(S,{className:`sm:max-w-sm`,children:[(0,G.jsx)(b,{children:(0,G.jsxs)(C,{className:`text-sm flex items-center gap-2`,children:[(0,G.jsx)(d,{className:`size-4`}),` Rotation & Retry`]})}),(0,G.jsx)(X,{})]})}):(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`fixed inset-0 z-50 transition-opacity duration-200 opacity-100`,onClick:()=>t(!1),style:{backgroundColor:`rgba(0,0,0,0.5)`}}),(0,G.jsxs)(`div`,{className:g(`fixed bottom-0 left-0 right-0 z-50 bg-background rounded-t-2xl border-t border-border shadow-2xl`,`transition-transform duration-300 ease-out max-h-[85vh] overflow-y-auto`,`translate-y-0`),children:[(0,G.jsx)(`div`,{className:`flex justify-center pt-3 pb-1`,children:(0,G.jsx)(`div`,{className:`w-10 h-1 rounded-full bg-border`})}),(0,G.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-2 border-b border-border`,children:[(0,G.jsxs)(`span`,{className:`text-sm font-semibold flex items-center gap-2`,children:[(0,G.jsx)(d,{className:`size-4`}),` Rotation & Retry`]}),(0,G.jsx)(`button`,{onClick:()=>t(!1),className:`flex items-center justify-center size-7 rounded-md hover:bg-surface-elevated transition-colors`,children:(0,G.jsx)(r,{className:`size-4`})})]}),(0,G.jsx)(`div`,{className:`px-4 py-4 pb-8`,children:(0,G.jsx)(X,{})})]})]}):null}var Le=v(`inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2`,{variants:{variant:{default:`border-transparent bg-primary text-primary-foreground shadow`,secondary:`border-transparent bg-secondary text-secondary-foreground`,destructive:`border-transparent bg-destructive text-destructive-foreground shadow`,outline:`text-foreground`}},defaultVariants:{variant:`default`}});function Z({className:e,variant:t,...n}){return(0,G.jsx)(`div`,{className:g(Le({variant:t}),e),...n})}function Re(e){let t=Math.floor(Date.now()/1e3);return e>t?`${Math.floor((e-t)/60)}m`:`exp`}function Q({accounts:e}){let[t,n]=(0,W.useState)([]),[r,i]=(0,W.useState)(!1),[a,o]=(0,W.useState)(!1),[s,c]=(0,W.useState)(new Map),l=e.filter(e=>e.hasRefreshToken);async function u(){if(l.length!==0){i(!0);try{let e=await ue(l.map(e=>e.id),a);n(t=>[...t,{round:t.length+1,time:new Date().toLocaleTimeString(),includeRefresh:a,items:e}])}catch{}i(!1)}}async function d(e,t){c(t=>new Map(t).set(e,{loading:!0}));try{let n=await de(t);c(t=>new Map(t).set(e,{loading:!1,...n}))}catch(t){c(n=>new Map(n).set(e,{loading:!1,status:`error`,error:t.message}))}}function f(e,t){return[{key:`r${e.round}-pre-${t.id}`,label:`Pre-export`,token:t.preExportTokenFull,preview:t.preExportToken,expires:t.preExportExpires},{key:`r${e.round}-exp-${t.id}`,label:`Exported`,token:t.exportedTokenFull,preview:t.exportedToken,expires:t.exportedExpires},{key:`r${e.round}-post-${t.id}`,label:`Post-export`,token:t.postExportTokenFull,preview:t.postExportToken,expires:t.postExportExpires}]}function p(){for(let e of t)for(let t of e.items)for(let n of f(e,t))n.token&&d(n.key,n.token)}return(0,G.jsxs)(`section`,{className:`border-t pt-4 space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,G.jsx)(`p`,{className:`text-xs font-medium`,children:`Simulate export`}),t.length>0&&(0,G.jsxs)(`span`,{className:`text-[10px] text-muted-foreground`,children:[t.length,` round(s)`]})]}),(0,G.jsx)(`p`,{className:`text-[11px] text-muted-foreground`,children:`Every run appends a round. Earlier rounds are kept so tokens can be compared across runs.`}),l.length===0?(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No OAuth account with a refresh token to export.`}):(0,G.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,G.jsx)(k,{id:`sim-include-refresh`,checked:a,onCheckedChange:o,className:`cursor-pointer`}),(0,G.jsx)(A,{htmlFor:`sim-include-refresh`,className:`text-[11px] cursor-pointer`,children:`Include refresh tokens`})]}),(0,G.jsx)(y,{size:`sm`,className:`h-7 text-xs cursor-pointer`,disabled:r,onClick:()=>void u(),children:r?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(m,{className:`size-3 animate-spin mr-1`}),` Exporting...`]}):`Run export #${t.length+1}`})]}),t.length>0&&(0,G.jsxs)(`div`,{className:`space-y-3`,children:[(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`w-full h-7 text-[11px] cursor-pointer`,onClick:p,children:[`Test all tokens (`,t.reduce((e,t)=>e+t.items.length*3,0),`)`]}),t.map(e=>(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsxs)(`p`,{className:`text-xs font-medium text-primary`,children:[`Round #`,e.round]}),(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:e.time}),(0,G.jsx)(Z,{variant:e.includeRefresh?`destructive`:`secondary`,className:`text-[9px] px-1 py-0`,children:e.includeRefresh?`with refresh`:`access only`})]}),e.items.map(t=>(0,G.jsxs)(`div`,{className:`p-2 rounded-lg border bg-card space-y-1.5`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`span`,{className:`text-[11px] font-medium`,children:t.label??t.email??t.id.slice(0,8)}),t.tokenChanged&&(0,G.jsx)(Z,{variant:`secondary`,className:`text-[9px] px-1 py-0`,children:`DB token changed`})]}),f(e,t).map(e=>{let t=s.get(e.key);return(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[11px]`,children:[(0,G.jsx)(`span`,{className:`w-20 shrink-0 text-muted-foreground text-[10px]`,children:e.label}),(0,G.jsx)(`code`,{className:`flex-1 truncate font-mono text-[10px] bg-muted px-1 rounded`,children:e.preview??`N/A`}),e.expires&&(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground shrink-0`,children:Re(e.expires)}),e.token?(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`h-6 text-[10px] px-1.5 cursor-pointer shrink-0`,disabled:t?.loading,onClick:()=>void d(e.key,e.token),children:t?.loading?(0,G.jsx)(m,{className:`size-3 animate-spin`}):`Test`}):(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:`-`}),t&&!t.loading&&(0,G.jsx)(`span`,{className:`text-[10px] font-medium shrink-0 ${t.status?.startsWith(`valid`)?`text-success`:`text-error`}`,children:t.status})]},e.key)})]},`r${e.round}-${t.id}`))]},e.round))]})]})}function ze(e){let t=Math.floor(Date.now()/1e3),n=Math.floor(Math.abs(e-t)/60);return e>t?`${n}m left`:`expired ${n}m ago`}function Be({open:e,onOpenChange:t,accounts:n}){let[r,i]=(0,W.useState)(new Map),[a,s]=(0,W.useState)(!1);async function c(e){i(t=>new Map(t).set(e,{loading:!0}));try{let t=await re(e,a);i(n=>new Map(n).set(e,{loading:!1,result:t}))}catch(t){i(n=>new Map(n).set(e,{loading:!1,error:t.message}))}}function l(){for(let e of n.filter(e=>e.expiresAt!==null))c(e.id)}return(0,G.jsx)(T,{open:e,onOpenChange:t,children:(0,G.jsxs)(S,{className:`sm:max-w-xl max-h-[85vh] flex flex-col`,children:[(0,G.jsxs)(b,{children:[(0,G.jsxs)(C,{className:`text-sm flex items-center gap-1.5`,children:[(0,G.jsx)(o,{className:`size-4`}),` Token Test`]}),(0,G.jsx)(w,{className:`text-xs`,children:`Probe stored tokens for validity. Nothing is modified.`})]}),(0,G.jsxs)(`div`,{className:`space-y-4 overflow-y-auto flex-1 pr-1`,children:[(0,G.jsxs)(`section`,{className:`space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,G.jsx)(`p`,{className:`text-xs font-medium`,children:`Current tokens`}),(0,G.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,G.jsx)(k,{id:`token-test-refresh`,checked:a,onCheckedChange:s,className:`cursor-pointer`}),(0,G.jsx)(A,{htmlFor:`token-test-refresh`,className:`text-[11px] cursor-pointer`,children:`Also test refresh`})]}),(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`h-7 text-xs cursor-pointer`,onClick:l,children:`Test all`})]})]}),n.length===0&&(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No accounts to test.`}),(0,G.jsx)(`div`,{className:`space-y-1.5`,children:n.map(e=>{let t=r.get(e.id),n=t?.result?.accessToken.status;return(0,G.jsxs)(`div`,{className:`p-2 rounded border bg-card space-y-1`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,G.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,G.jsx)(`span`,{className:`text-xs font-medium truncate block`,children:e.label??e.email??e.id.slice(0,8)}),e.expiresAt&&(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:ze(e.expiresAt)})]}),(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`h-7 text-xs cursor-pointer shrink-0`,disabled:t?.loading,onClick:()=>void c(e.id),children:t?.loading?(0,G.jsx)(m,{className:`size-3 animate-spin`}):`Test`})]}),t&&!t.loading&&(0,G.jsxs)(`div`,{className:`text-[11px] pl-2 border-l-2 border-muted`,children:[t.error&&(0,G.jsx)(`p`,{className:`text-error`,children:t.error}),n&&(0,G.jsxs)(`span`,{className:n.startsWith(`valid`)?`text-success`:`text-error`,children:[n,t.result?.accessToken.code?` (${t.result.accessToken.code})`:``]})]})]},e.id)})})]}),(0,G.jsx)(Q,{accounts:n})]}),(0,G.jsx)(x,{children:(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs cursor-pointer`,onClick:()=>t(!1),children:`Close`})})]})})}function Ve(){let{usages:e,accounts:t,activeAccountId:n,initialLoading:r,refreshing:a,flashIds:s,reload:u}=_e(),[f,h]=(0,W.useState)(null),[g,_]=(0,W.useState)(null),[v,b]=(0,W.useState)(null),[x,S]=(0,W.useState)(null),[C,w]=(0,W.useState)(null),[T,E]=(0,W.useState)(null),[D,O]=(0,W.useState)(void 0);function k(e){u(),e&&h(e)}async function A(e,t){_(e);try{await ae(e,{status:t===`disabled`?`active`:`disabled`})}catch(e){h(e.message)}_(null),u()}async function j(){if(v){try{await le(v.id),h(`Account "${v.display}" removed.`),u()}catch(e){h(`Failed to remove: ${e.message}`)}b(null)}}let M=new Map(t.map(e=>[e.id,e])),N=e[0]?.usage.lastFetchedAt;return(0,G.jsxs)(`div`,{className:`space-y-4`,children:[(0,G.jsx)(z,{description:`Connect multiple Claude accounts. PPM rotates between them automatically to avoid rate limits.`,onRefresh:()=>void u(),refreshing:a,disabled:r,actions:(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(y,{size:`sm`,className:`cursor-pointer gap-1.5`,onClick:()=>{O(void 0),E(`add`)},children:[(0,G.jsx)(c,{className:`size-4`}),` Add account`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>{w(null),E(`export`)},children:[(0,G.jsx)(p,{className:`size-4`}),` Export`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>E(`import`),children:[(0,G.jsx)(i,{className:`size-4`}),` Import`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>E(`rotation`),children:[(0,G.jsx)(d,{className:`size-4`}),` Rotation`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>E(`token-test`),children:[(0,G.jsx)(o,{className:`size-4`}),` Token test`]})]})}),(0,G.jsx)(R,{message:f,onDismiss:()=>h(null)}),(0,G.jsxs)(`section`,{className:`space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium`,children:`Accounts`}),N&&(0,G.jsxs)(`span`,{className:`text-[10px] text-muted-foreground`,children:[`usage `,me(new Date(N).getTime())]})]}),r?(0,G.jsxs)(`div`,{className:`flex items-center gap-2 py-6 text-xs text-muted-foreground`,children:[(0,G.jsx)(m,{className:`size-4 animate-spin`}),` Loading accounts...`]}):e.length===0?(0,G.jsxs)(`div`,{className:`flex flex-col items-center gap-2 py-8 text-center`,children:[(0,G.jsx)(l,{className:`size-5 text-muted-foreground`}),(0,G.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`No accounts connected yet.`}),(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Add one to start using PPM.`})]}):(0,G.jsx)(B,{children:e.map(e=>(0,G.jsx)(Ce,{layout:`strip`,entry:e,isActive:e.accountId===n,accountInfo:M.get(e.accountId),onToggle:A,toggling:g===e.accountId,onDelete:(e,t)=>b({id:e,display:t}),onExport:e=>{w(e),E(`export`)},onViewProfile:(e,t)=>S({profile:e,accountId:t}),onReauth:()=>{O(e.accountLabel??e.accountId.slice(0,8)),E(`add`)},flash:s.has(e.accountId)},e.accountId))})]}),x&&(0,G.jsx)(ke,{profile:x.profile,accountId:x.accountId,onClose:()=>S(null)}),v&&(0,G.jsx)(Ae,{display:v.display,onConfirm:()=>void j(),onCancel:()=>b(null)}),(0,G.jsx)(he,{open:T===`add`,onOpenChange:e=>{E(e?`add`:null),e||O(void 0)},onSuccess:k,signInAgainFor:D}),(0,G.jsx)(Me,{open:T===`export`,onOpenChange:e=>{E(e?`export`:null),e||w(null)},accounts:t,preselectId:C,onMessage:h}),(0,G.jsx)(Ne,{open:T===`import`,onOpenChange:e=>E(e?`import`:null),onSuccess:k}),(0,G.jsx)(Ie,{open:T===`rotation`,onOpenChange:e=>E(e?`rotation`:null)}),(0,G.jsx)(Be,{open:T===`token-test`,onOpenChange:e=>E(e?`token-test`:null),accounts:t})]})}function He({mode:e,onOpenChange:t,password:n,onPasswordChange:r,busy:a,onExport:o,onImport:s,error:c}){let l=(0,W.useRef)(null),d=e===`export`;return(0,G.jsx)(T,{open:e!==null,onOpenChange:t,children:(0,G.jsxs)(S,{className:`sm:max-w-md`,children:[(0,G.jsxs)(b,{children:[(0,G.jsxs)(C,{className:`text-sm flex items-center gap-1.5`,children:[(0,G.jsx)(u,{className:`size-4`}),` `,d?`Export Codex Accounts`:`Import Codex Accounts`]}),(0,G.jsx)(w,{className:`text-xs leading-relaxed`,children:d?`Writes a password-encrypted file containing each account's login.`:`Reads a backup file. The password must be the one it was exported with.`})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsx)(A,{htmlFor:`codex-backup-password`,className:`text-xs`,children:`Password`}),(0,G.jsx)(D,{id:`codex-backup-password`,type:`password`,placeholder:d?`Choose a password`:`Password used for the export`,value:n,onChange:e=>r(e.target.value),className:`text-xs`,autoComplete:d?`new-password`:`current-password`}),(0,G.jsx)(`p`,{className:`text-[10px] text-muted-foreground`,children:`A backup holds full logins — keep the file and its password together.`})]}),c&&(0,G.jsx)(`div`,{className:`text-[11px] p-2 rounded bg-error/10 text-error`,children:c}),(0,G.jsx)(`input`,{ref:l,type:`file`,accept:`application/json,.json`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];e.target.value=``,t&&s(t)}}),(0,G.jsxs)(x,{children:[(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs cursor-pointer`,onClick:()=>t(!1),children:`Cancel`}),(0,G.jsxs)(y,{size:`sm`,className:`text-xs cursor-pointer gap-1.5`,disabled:!n.trim()||a,onClick:()=>d?o():l.current?.click(),children:[a?(0,G.jsx)(m,{className:`size-3.5 animate-spin`}):d?(0,G.jsx)(p,{className:`size-3.5`}):(0,G.jsx)(i,{className:`size-3.5`}),d?`Download backup`:`Choose file`]})]})]})})}var Ue=[{value:`round-robin`,label:`Round-robin`,hint:`Take the next account each time.`},{value:`fill-first`,label:`Fill-first`,hint:`Stay on one account until it runs out.`},{value:`lowest-usage`,label:`Lowest usage`,hint:`Pick whichever has the most left.`}];function We({open:e,onOpenChange:t,strategy:n,onChange:r}){return(0,G.jsx)(T,{open:e,onOpenChange:t,children:(0,G.jsxs)(S,{className:`sm:max-w-md`,children:[(0,G.jsxs)(b,{children:[(0,G.jsx)(C,{className:`text-sm`,children:`Codex Rotation`}),(0,G.jsx)(w,{className:`text-xs leading-relaxed`,children:`How a new chat chooses among your Codex accounts.`})]}),(0,G.jsx)(`div`,{className:`space-y-2`,children:Ue.map(e=>(0,G.jsxs)(`button`,{type:`button`,onClick:()=>r(e.value),"aria-current":n===e.value?`true`:void 0,className:g(`w-full text-left rounded-md border px-3 py-2.5 min-h-11 cursor-pointer transition-colors`,n===e.value?`border-primary bg-primary/10`:`border-border hover:bg-accent/50 active:bg-accent`),children:[(0,G.jsx)(`p`,{className:`text-sm font-medium`,children:e.label}),(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e.hint})]},e.value))}),(0,G.jsx)(x,{children:(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs cursor-pointer`,onClick:()=>t(!1),children:`Done`})})]})})}function $(e){return e==null?null:Math.round(e*100)}function Ge({usage:e}){let t=e.session==null&&e.weekly==null;return(0,G.jsxs)(`div`,{className:`space-y-2`,children:[(t||e.session!=null)&&(0,G.jsx)(U,{label:`5-Hour Session`,pct:$(e.fiveHour),reset:H(e.session),resetsAt:e.session?.resetsAt}),(t||e.weekly!=null)&&(0,G.jsx)(U,{label:`Weekly`,pct:$(e.sevenDay),reset:H(e.weekly),resetsAt:e.weekly?.resetsAt})]})}function Ke(){let[e,t]=(0,W.useState)(null),n=pe(()=>t(null)),[r,o]=(0,W.useState)(null);return(0,G.jsxs)(`div`,{className:`space-y-4`,children:[(0,G.jsx)(z,{description:(0,G.jsxs)(G.Fragment,{children:[`Each Codex account keeps its own login (`,(0,G.jsx)(`code`,{children:`CODEX_HOME`}),`). One is picked per chat by the rotation setting.`]}),onRefresh:()=>void n.load(),refreshing:n.loading,actions:(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(y,{size:`sm`,className:`cursor-pointer gap-1.5`,onClick:()=>t(`add`),children:[(0,G.jsx)(c,{className:`size-4`}),` Add account`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>t(`export`),children:[(0,G.jsx)(p,{className:`size-4`}),` Export`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>t(`import`),children:[(0,G.jsx)(i,{className:`size-4`}),` Import`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>t(`rotation`),children:[(0,G.jsx)(d,{className:`size-4`}),` Rotation`]})]})}),(0,G.jsx)(R,{message:n.msg??n.err,onDismiss:()=>{n.setMsg(null),n.setErr(null)}}),(0,G.jsxs)(`section`,{className:`space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium`,children:`Codex Accounts`}),(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground capitalize`,children:n.strategy.replace(`-`,` `)})]}),n.loading&&n.accounts.length===0?(0,G.jsxs)(`div`,{className:`flex items-center gap-2 py-6 text-xs text-muted-foreground`,children:[(0,G.jsx)(m,{className:`size-4 animate-spin`}),` Loading accounts...`]}):n.accounts.length===0?(0,G.jsxs)(`div`,{className:`flex flex-col items-center gap-2 py-8 text-center`,children:[(0,G.jsx)(l,{className:`size-5 text-muted-foreground`}),(0,G.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`No Codex accounts yet.`}),(0,G.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Chats use your default `,(0,G.jsx)(`code`,{children:`~/.codex`}),` login until you add one.`]})]}):(0,G.jsx)(B,{children:n.accounts.map(e=>{let t=n.usages[e.id]??{};return(0,G.jsxs)(ve,{dense:!0,className:`min-w-[300px] shrink-0 snap-start${e.signedOut?` opacity-60`:``}`,"data-testid":`account-card`,"data-account-id":e.id,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`span`,{className:`text-sm font-medium truncate flex-1 min-w-0`,children:e.label}),e.signedOut&&(0,G.jsx)(fe,{className:`text-[10px] text-error shrink-0 font-medium`,hint:`Codex rejected this account's login (revoked or expired), so no turn can run on it and it is skipped. The usage shown is the last reading. Click to sign in again — the account keeps its settings and chats.`,onClick:e.type===`chatgpt`?()=>o(e):void 0,children:`Sign in again`}),(0,G.jsx)(`span`,{className:`text-[10px] uppercase tracking-wide text-text-subtle border border-border rounded px-1 shrink-0`,children:e.type}),V(e.planType)&&(0,G.jsx)(`span`,{className:`text-[10px] text-text-subtle shrink-0`,children:V(e.planType)}),(0,G.jsx)(k,{checked:e.status!==`disabled`,onCheckedChange:()=>void n.toggle(e.id,e.status??`active`),disabled:n.toggling.has(e.id),"aria-label":e.status===`disabled`?`Enable account`:`Disable account`,className:`cursor-pointer shrink-0`}),(0,G.jsxs)(F,{children:[(0,G.jsx)(I,{asChild:!0,children:(0,G.jsx)(`button`,{type:`button`,onClick:()=>void n.remove(e.id),"aria-label":`Remove account`,className:`p-2 rounded cursor-pointer text-text-subtle hover:text-error hover:bg-surface-elevated transition-colors shrink-0`,children:(0,G.jsx)(a,{className:`size-4`})})}),(0,G.jsx)(P,{side:`top`,children:`Remove account`})]})]}),(0,G.jsx)(Ge,{usage:t}),t.resetCredits&&(0,G.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap text-[10px] text-text-subtle`,children:[(0,G.jsx)(ge,{credits:t.resetCredits}),(0,G.jsx)(Se,{account:e,usage:t,onDone:e=>{n.setMsg(e),n.load()}})]}),t.session==null&&(()=>{let r=be(t.weekly);return r?(0,G.jsxs)(`div`,{className:`flex min-h-12 items-center justify-between gap-3 rounded-md border px-2.5 py-1.5 ${e.dailyGuardEnabled&&r.blocked?`border-error/40 bg-error/5`:`border-border/50 bg-surface/40`}`,children:[(0,G.jsxs)(`div`,{className:`min-w-0 space-y-0.5`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs font-medium ${e.dailyGuardEnabled&&r.blocked?`text-error`:`text-text-secondary`}`,children:[(0,G.jsx)(`span`,{children:`Daily guard`}),(0,G.jsxs)(F,{children:[(0,G.jsx)(I,{asChild:!0,children:(0,G.jsx)(`button`,{type:`button`,"aria-label":`About Daily guard`,className:`text-text-subtle hover:text-text-primary cursor-help`,children:(0,G.jsx)(s,{className:`size-3.5`})})}),(0,G.jsx)(P,{side:`top`,className:`max-w-64 text-xs leading-relaxed`,children:`Spreads the weekly quota across five weekdays, adding 20% per weekday. Weekend slots keep the previous cap; unused allowance carries forward. Daily slots start at the reset time and use UTC weekdays. Turn it off any time to use the remaining quota freely.`})]})]}),(0,G.jsx)(`p`,{className:`text-[10px] tabular-nums ${e.dailyGuardEnabled&&r.blocked?`text-error`:`text-text-subtle`}`,children:e.dailyGuardEnabled&&r.blocked?`${Math.round(r.used*100)}% used / ${Math.round(r.cap*100)}% daily cap. New turns paused.`:`Weekday ${r.day}/5, ${Math.round(r.cap*100)}% daily cap`})]}),(0,G.jsxs)(`span`,{className:`hidden`,title:`Weekday ${r.day}/5: hold weekly usage at or below ${Math.round(r.cap*100)}% to last until reset.`,children:[`Daily guard `,e.dailyGuardEnabled?`· Weekday ${r.day}/5 cap ${Math.round(r.cap*100)}%`:``]}),(0,G.jsx)(k,{checked:!!e.dailyGuardEnabled,onCheckedChange:()=>void n.toggleDailyGuard(e.id,!!e.dailyGuardEnabled),disabled:n.toggling.has(e.id),"aria-label":e.dailyGuardEnabled?`Disable Daily guard`:`Enable Daily guard`,className:`cursor-pointer shrink-0`})]}):null})()]},e.id)})})]}),(0,G.jsx)(xe,{open:e===`add`,onOpenChange:e=>{e||n.cancelLogin(),t(e?`add`:null)},label:n.label,onLabelChange:n.setLabel,apiKey:n.apiKey,onApiKeyChange:n.setApiKey,adding:n.adding,onAddApiKey:()=>void n.addApiKey(),deviceWaiting:n.deviceWaiting,onStartDevice:()=>void n.startDevice(),device:n.device,browser:n.browser,onStartBrowser:()=>void n.startBrowser(),loginStarting:n.loginStarting,callbackUrl:n.callbackUrl,onCallbackUrlChange:n.setCallbackUrl,submittingCallback:n.submittingCallback,onSubmitCallback:()=>void n.submitCallback(),error:n.err}),(0,G.jsx)(He,{mode:e===`export`?`export`:e===`import`?`import`:null,onOpenChange:e=>{e||t(null)},password:n.backupPassword,onPasswordChange:n.setBackupPassword,busy:n.exporting||n.importing,onExport:()=>void n.doExport(),onImport:e=>void n.doImport(e),error:n.err}),r&&(0,G.jsx)(ye,{account:r,onClose:()=>o(null),onDone:()=>void n.load()}),(0,G.jsx)(We,{open:e===`rotation`,onOpenChange:e=>t(e?`rotation`:null),strategy:n.strategy,onChange:e=>void n.changeStrategy(e)})]})}var qe=[{id:`claude`,label:`Claude`},{id:`codex`,label:`Codex`}];function Je(){let[e,t]=(0,W.useState)(null),[n,r]=(0,W.useState)(`claude`);(0,W.useEffect)(()=>{let e=!1;return ie().then(n=>{e||t(new Set(Object.keys(n.providers??{})))}).catch(()=>{e||t(new Set([`claude`]))}),()=>{e=!0}},[]);let i=qe.filter(t=>t.id===`claude`||e?.has(t.id)),a=i.length>1;return(0,G.jsxs)(`div`,{className:`space-y-4`,"data-testid":`accounts-pane`,"data-provider":n,children:[a&&(0,G.jsx)(`div`,{className:`flex gap-1 border-b border-border/50`,children:i.map(e=>(0,G.jsxs)(`button`,{onClick:()=>r(e.id),"data-testid":`accounts-tab-${e.id}`,"aria-current":n===e.id?`page`:void 0,className:`flex items-center gap-1.5 px-3 py-2 text-xs rounded-t transition-colors cursor-pointer ${n===e.id?`text-primary border-b-2 border-primary font-medium`:`text-text-subtle hover:text-text-secondary`}`,children:[(0,G.jsx)(ee,{providerId:e.id}),e.label]},e.id))}),e===null&&!a&&(0,G.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[(0,G.jsx)(m,{className:`size-3 animate-spin`}),` Checking configured providers...`]}),n===`claude`?(0,G.jsx)(Ve,{}):(0,G.jsx)(Ke,{})]})}export{Je as AccountsSettingsSection};
|
|
Binary file
|
|
Binary file
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/agent-session-window-content-
|
|
2
|
-
import{s as e}from"./rolldown-runtime-C5c2KzVm.js";import{C as t,S as n}from"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import{Jr as r}from"./icons-CO_II6D-.js";import{t as i}from"./preload-helper-BEFjQwLd.js";import"./portal-container-context-NFSuymMu.js";import{t as a}from"./mobile-bottom-sheet-D4UyOatB.js";import"./use-visual-viewport-BGpcMnIx.js";import{t as o}from"./agent-session-sheet-store-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/agent-session-window-content-BxIxDN5i.js","assets/rolldown-runtime-C5c2KzVm.js","assets/index-CyDLBddf.js","assets/preload-helper-BEFjQwLd.js","assets/vendor-ui-P9Ym7hCv.js","assets/vendor-markdown-QKPNiWEd.js","assets/button-DeAyLH9U.js","assets/utils-btZ8C8-R.js","assets/createLucideIcon-DBXq3G0e.js","assets/api-client-F5Zi1sR0.js","assets/react-CzUPVyyG.js","assets/file-store-Cm7-pHux.js","assets/panel-store-B6PoCwBA.js","assets/session-list-sync-triggers-ATvz-1g3.js","assets/project-store-CCimwgGF.js","assets/window-store-vo1N70nK.js","assets/settings-store-Cyuo8ceh.js","assets/window-pip-registry-9Y9LQQYS.js","assets/onboarding-quick-orientation-DPHYFMbA.js","assets/dialog-Bocc0Fgb.js","assets/portal-container-context-NFSuymMu.js","assets/icons-CO_II6D-.js","assets/use-is-mobile-BClDZJP5.js","assets/format-file-meta-Drxf2J-k.js","assets/fs-api-IX9SHt5k.js","assets/context-menu-7OX80HDB.js","assets/input-CG8PS8mS.js","assets/mobile-bottom-sheet-D4UyOatB.js","assets/use-visual-viewport-BGpcMnIx.js","assets/scroll-area-sjOeAfoD.js","assets/chat-preparation-cache-BUCR58h4.js","assets/file-icons-CK0J4QSy.js","assets/format-date-BMtvCeb9.js","assets/git-repo-store-B_u5RzIM.js","assets/ws-auth-Ytui7dXP.js","assets/tab-store-DCpc0g0Q.js","assets/apply-theme-Cc_cmrD5.js","assets/resolve-theme-STMsK2vc.js","assets/index-Dh5apC3I.css","assets/libesm-5wREk7JN.js","assets/tool-cards-rxLXbBSm.js","assets/agent-session-sheet-store-_OeezCXB.js","assets/image-preview-geometry-D4Ihz4UV.js","assets/use-blob-url-BC69n15x.js","assets/image-gallery-B16hO6Ab.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{s as e}from"./rolldown-runtime-C5c2KzVm.js";import{C as t,S as n}from"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import{Jr as r}from"./icons-CO_II6D-.js";import{t as i}from"./preload-helper-BEFjQwLd.js";import"./portal-container-context-NFSuymMu.js";import{t as a}from"./mobile-bottom-sheet-D4UyOatB.js";import"./use-visual-viewport-BGpcMnIx.js";import{t as o}from"./agent-session-sheet-store-_OeezCXB.js";var s=e(t(),1),c=n(),l=(0,s.lazy)(()=>i(()=>import(`./agent-session-window-content-BxIxDN5i.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44])));function u(){let e=o(e=>e.payload),t=o(e=>e.close);return e?(0,c.jsxs)(a,{open:!0,onClose:t,zIndex:45,className:`flex h-[var(--sheet-vh)] flex-col p-0`,children:[(0,c.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-border px-3 py-2 shrink-0`,children:[(0,c.jsx)(`span`,{className:`truncate text-sm font-medium text-text-primary`,children:e.title??`Agent session`}),(0,c.jsx)(`button`,{type:`button`,onClick:t,className:`ml-auto flex size-11 items-center justify-center rounded text-text-secondary hover:text-text-primary`,"aria-label":`Close`,children:(0,c.jsx)(r,{className:`size-5`})})]}),(0,c.jsx)(`div`,{className:`min-h-0 flex-1 overflow-auto`,children:(0,c.jsx)(s.Suspense,{fallback:(0,c.jsx)(`div`,{className:`p-4 text-sm text-text-2`,children:`Loading…`}),children:(0,c.jsx)(l,{id:`sheet-${e.sessionId}`,payload:e})})})]}):null}export{u as AgentSessionSheet};
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{s as e}from"./rolldown-runtime-C5c2KzVm.js";import{C as t,S as n}from"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import{O as r,j as i,un as a}from"./icons-CO_II6D-.js";import"./api-client-F5Zi1sR0.js";import{n as o}from"./utils-btZ8C8-R.js";import"./panel-store-
|
|
1
|
+
import{s as e}from"./rolldown-runtime-C5c2KzVm.js";import{C as t,S as n}from"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import{O as r,j as i,un as a}from"./icons-CO_II6D-.js";import"./api-client-F5Zi1sR0.js";import{n as o}from"./utils-btZ8C8-R.js";import"./panel-store-B6PoCwBA.js";import"./window-store-vo1N70nK.js";import"./project-store-CCimwgGF.js";import"./session-list-sync-triggers-ATvz-1g3.js";import"./tab-store-DCpc0g0Q.js";import"./use-is-mobile-BClDZJP5.js";import{b as s,en as c,y as l}from"./index-CyDLBddf.js";import"./agent-session-sheet-store-_OeezCXB.js";import"./libesm-5wREk7JN.js";import{c as u,s as d,t as f,u as p}from"./tool-cards-rxLXbBSm.js";import"./use-blob-url-BC69n15x.js";var m=e(t(),1),h=2e3;function g(e,t){let n=t.reset?[]:e.slice();for(let{ev:e,ts:r,k:i,replace:a}of t.events){let t=n.findIndex(e=>e.k===i);if(t!==-1){a&&(n[t]={k:i,ts:r,ev:e});continue}let o=n.length;for(;o>0&&n[o-1].ts>r;)o--;n.splice(o,0,{k:i,ts:r,ev:e})}return n.length>2e3?n.slice(n.length-h):n}function _(){return`ats-${Math.random().toString(36).slice(2,10)}`}function v(e){let{projectName:t,providerId:n,sessionId:r,source:i,fallbackEvents:a}=e,[o,c]=(0,m.useState)([]),[u,d]=(0,m.useState)(!1),[f,p]=(0,m.useState)(!1),[h,v]=(0,m.useState)(!0),[y,b]=(0,m.useState)(null);(0,m.useEffect)(()=>{let e=_(),a=[],o;c([]),d(!1),p(!1),v(!0),b(null);let u=()=>{s(JSON.stringify({type:`agent-transcript:subscribe`,subId:e,projectName:t,providerId:n,sessionId:r,source:i,...o?{cursor:o}:{}}))},f=t=>{let n=t.detail;n.subId===e&&(a=g(a,n),o=n.cursor,c(a),d(n.available),p(n.running),v(!1),b(null))},m=t=>{let n=t.detail;n.subId===e&&(d(!1),v(!1),b(n.code))};window.addEventListener(`agent-transcript:events`,f),window.addEventListener(`agent-transcript:error`,m);let h=l(u);return u(),()=>{window.removeEventListener(`agent-transcript:events`,f),window.removeEventListener(`agent-transcript:error`,m),h(),s(JSON.stringify({type:`agent-transcript:unsubscribe`,subId:e}))}},[JSON.stringify([t,n,r,i])]);let x=(0,m.useMemo)(()=>o.map(e=>e.ev),[o]);return{events:u?x:a??[],available:u,running:f,loading:h,error:y}}var y=n();function b(e){return e.filter(e=>e.type===`tool_use`).length}function x({status:e}){return e===`loading`?null:e===`running`?(0,y.jsxs)(`span`,{className:`flex items-center gap-1 text-[10px] text-primary shrink-0`,children:[(0,y.jsx)(a,{className:`size-2.5 animate-spin`}),` running`]}):e===`failed`?(0,y.jsx)(`span`,{className:`text-[10px] text-error shrink-0`,children:`failed`}):(0,y.jsx)(`span`,{className:`text-[10px] text-success shrink-0`,children:`done`})}function S({payload:e}){let t=e??{},n=t.sessionId?d(t.sessionId,t.source):``,s=u(e=>n?e.entries[n]:void 0),{events:l,available:h,running:g,loading:_,error:S}=v({projectName:t.projectName,providerId:t.providerId,sessionId:t.sessionId,source:t.source,fallbackEvents:s}),[C,w]=(0,m.useState)(!1),T=c(),E=(0,m.useMemo)(()=>b(l),[l]),D=l[l.length-1],O=!g&&!!D&&D.type===`tool_result`&&!!D.isError,k=_?`loading`:g?`running`:O?`failed`:`done`;return(0,y.jsxs)(`div`,{className:`flex flex-col h-full min-h-0 bg-surface @container`,children:[(0,y.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-1.5 border-b border-border/30 shrink-0`,children:[(0,y.jsx)(`span`,{className:`truncate text-xs font-medium`,children:t.title??`Agent session`}),l.length>0&&(0,y.jsx)(`span`,{className:`text-[10px] text-text-subtle shrink-0`,children:p(E)}),(0,y.jsx)(x,{status:k}),!h&&!_&&(0,y.jsx)(`span`,{className:`ml-auto text-[10px] text-text-subtle shrink-0`,title:`No live transcript for this session — showing steps already held in memory`,children:`offline`})]}),!!t.prompt&&(0,y.jsxs)(`div`,{className:`border-b border-border/30 shrink-0`,children:[(0,y.jsxs)(`button`,{type:`button`,onClick:()=>w(e=>!e),className:o(`flex w-full items-center gap-1.5 px-3 py-1.5 text-[11px] text-text-subtle hover:text-foreground`,T?`min-h-[44px]`:`min-h-[28px]`),children:[C?(0,y.jsx)(r,{className:`size-3`}):(0,y.jsx)(i,{className:`size-3`}),`Prompt`]}),C&&(0,y.jsx)(`div`,{className:`px-3 pb-2 text-[11px] text-text-secondary whitespace-pre-wrap select-text`,children:t.prompt})]}),_&&l.length===0?(0,y.jsxs)(`div`,{className:`flex-1 flex items-center justify-center gap-2 text-xs text-text-subtle`,children:[(0,y.jsx)(a,{className:`size-3 animate-spin`}),`Loading session…`]}):l.length===0?(0,y.jsx)(`div`,{className:`flex-1 flex items-center justify-center text-xs text-text-subtle px-4 text-center`,children:S?`Could not load this session`:`No recorded steps`}):(0,y.jsx)(f,{events:l,projectName:t.projectName,variant:`window`,className:`flex-1 min-h-0 overflow-y-auto px-3 py-2 space-y-1`})]})}export{S as default};
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{s as e}from"./rolldown-runtime-C5c2KzVm.js";import{C as t,S as n}from"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import{Fr as r,fn as i,r as a,sr as o,un as s}from"./icons-CO_II6D-.js";import{O as c}from"./api-client-F5Zi1sR0.js";import"./settings-store-
|
|
1
|
+
import{s as e}from"./rolldown-runtime-C5c2KzVm.js";import{C as t,S as n}from"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import{Fr as r,fn as i,r as a,sr as o,un as s}from"./icons-CO_II6D-.js";import{O as c}from"./api-client-F5Zi1sR0.js";import"./settings-store-Cyuo8ceh.js";import{n as l}from"./utils-btZ8C8-R.js";import{M as u,N as d,_t as f,bt as p,gt as m,vt as h,yt as g}from"./index-CyDLBddf.js";import{t as _}from"./use-monaco-theme-DvNGcCvz.js";var v=e(t(),1),y=n();function b({metadata:e}){let t=e?.filePath,n=e?.name,l=e?.resourceType??`skill`,b=e?.scope??`user`,S=e?.readOnly===!0,C=e?.shadowed===!0,w=e?.shadowedBy,T=e?.project??``,[E,D]=(0,v.useState)(``),[O,k]=(0,v.useState)(``),[A,j]=(0,v.useState)(!0),[M,N]=(0,v.useState)(null),[P,F]=(0,v.useState)(!1),I=_(),L=(0,v.useRef)(``),R=E!==O;(0,v.useEffect)(()=>{let e=!1;return j(!0),N(null),g(t,T).then(t=>{e||(D(t.content),k(t.content),L.current=t.content)}).catch(t=>{e||N(t.message)}).finally(()=>{e||j(!1)}),()=>{e=!0}},[t,T]);let z=(0,v.useCallback)(async()=>{if(S||P)return;let e=L.current;if(e!==O){F(!0);try{await p(t,e,T),k(e),D(e),c.success(`Saved`),h.getState().reload()}catch(e){c.error(e.message)}finally{F(!1)}}},[t,T,O,S,P]);(0,v.useEffect)(()=>{let e=e=>{(e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`s`&&(e.preventDefault(),z())};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[z]);let B=f[l];return(0,y.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,y.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-border px-3 py-2 shrink-0`,children:[(0,y.jsx)(B,{className:`size-4 text-text-subtle`}),(0,y.jsx)(`span`,{className:`text-sm font-semibold`,children:n}),(0,y.jsx)(m,{scope:b}),R&&!S&&(0,y.jsx)(`span`,{className:`size-1.5 rounded-full bg-primary`,title:`Unsaved changes`}),(0,y.jsx)(`div`,{className:`flex-1`}),(0,y.jsxs)(`span`,{className:`hidden sm:block text-[11px] text-text-subtle`,children:[l,` · markdown`]}),!S&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsxs)(`button`,{onClick:()=>D(O),disabled:!R||P,className:`flex items-center gap-1 rounded px-2 py-1 text-xs text-text-secondary hover:bg-surface-elevated disabled:opacity-40`,children:[(0,y.jsx)(r,{className:`size-3.5`}),` Revert`]}),(0,y.jsxs)(`button`,{onClick:()=>void z(),disabled:!R||P,className:`flex items-center gap-1 rounded bg-primary px-2.5 py-1 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-40`,children:[P?(0,y.jsx)(s,{className:`size-3.5 animate-spin`}):(0,y.jsx)(o,{className:`size-3.5`}),` Save`]})]})]}),S&&(0,y.jsx)(x,{icon:i,tone:`muted`,children:`Bundled resource — read-only. Duplicate it (from the AI Resources panel) to make an editable copy.`}),C&&w&&(0,y.jsxs)(x,{icon:a,tone:`warn`,children:[`This `,l,` is overridden by another “`,w.name,`” from a higher-priority source (`,w.source,`). It is currently inactive.`]}),(0,y.jsx)(`div`,{className:`min-h-0 flex-1`,children:A?(0,y.jsx)(`div`,{className:`flex h-full items-center justify-center`,children:(0,y.jsx)(s,{className:`size-5 animate-spin text-primary`})}):M?(0,y.jsx)(`div`,{className:`p-6 text-center text-sm text-destructive`,children:M}):(0,y.jsx)(d,{beforeMount:u,height:`100%`,language:`markdown`,theme:I,value:E,onChange:e=>{let t=e??``;L.current=t,D(t)},options:{readOnly:S,minimap:{enabled:!1},fontSize:13,wordWrap:`on`,scrollBeyondLastLine:!1,lineNumbers:`on`}})})]})}function x({icon:e,tone:t,children:n}){return(0,y.jsxs)(`div`,{className:l(`flex items-start gap-2 px-3 py-2 text-[12px] shrink-0 border-b border-border`,t===`warn`?`bg-amber-500/10 text-amber-300`:`bg-surface-elevated text-text-secondary`),children:[(0,y.jsx)(e,{className:`mt-0.5 size-3.5 shrink-0`}),(0,y.jsx)(`span`,{children:n})]})}export{b as AiResourceEditor};
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import"./icons-CO_II6D-.js";import"./api-client-F5Zi1sR0.js";import"./settings-store-
|
|
1
|
+
import"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import"./icons-CO_II6D-.js";import"./api-client-F5Zi1sR0.js";import"./settings-store-Cyuo8ceh.js";import"./portal-container-context-NFSuymMu.js";import"./panel-store-B6PoCwBA.js";import"./window-store-vo1N70nK.js";import"./project-store-CCimwgGF.js";import"./session-list-sync-triggers-ATvz-1g3.js";import"./tab-store-DCpc0g0Q.js";import"./chat-preparation-cache-BUCR58h4.js";import"./use-is-mobile-BClDZJP5.js";import"./button-DeAyLH9U.js";import"./dialog-Bocc0Fgb.js";import"./mobile-bottom-sheet-D4UyOatB.js";import"./use-visual-viewport-BGpcMnIx.js";import"./input-CG8PS8mS.js";import"./api-settings-Cc_CpfmC.js";import{t as e}from"./ai-settings-section-Ck8uN_Bw.js";export{e as AISettingsSection};
|