@hienlh/ppm 0.19.12 → 0.20.1
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 +36 -0
- package/CLAUDE.md +8 -1
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +4 -1
- package/dist/web/assets/accounts-settings-section-_sG1AqtH.js +1 -0
- package/dist/web/assets/{ai-resource-editor-CqL-X2zu.js → ai-resource-editor-BLctP1Pr.js} +1 -1
- package/dist/web/assets/ai-settings-section-0hSDp7xx.js +1 -0
- package/dist/web/assets/{ai-settings-section-CcqokdzF.js → ai-settings-section-CTEU2uGa.js} +1 -1
- package/dist/web/assets/{angular-html-C8nsn2VC.js → angular-html-BtJLNcMw.js} +1 -1
- package/dist/web/assets/{angular-ts-Caw9nRCH.js → angular-ts-CQiu5F_W.js} +1 -1
- package/dist/web/assets/api-client-QfreGirP.js +1 -0
- package/dist/web/assets/api-settings-D18Q4Ocp.js +1 -0
- package/dist/web/assets/{api-themes-BoOJPqwM.js → api-themes-sSv-6OLk.js} +1 -1
- package/dist/web/assets/{apl-Dhu1LORF.js → apl-CKZvgs-w.js} +1 -1
- package/dist/web/assets/{appearance-settings-section-2hZBnpPS.js → appearance-settings-section-BkcoSV0E.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-DfR8k8Bc.js +1 -0
- package/dist/web/assets/{astro-DwkX9sLZ.js → astro-D0b8ssLD.js} +1 -1
- package/dist/web/assets/{audio-preview-CkGZO8Uy.js → audio-preview-B4E5_7TW.js} +1 -1
- package/dist/web/assets/{blade-D1fC9Osx.js → blade-DOIpINLw.js} +1 -1
- package/dist/web/assets/{bsl-pur-PRip.js → bsl-CJ7_JlQ8.js} +1 -1
- package/dist/web/assets/{button-2WCAS8dI.js → button-DX32ffge.js} +1 -1
- package/dist/web/assets/{cairo-DDJs9amR.js → cairo-5CpV2T1P.js} +1 -1
- package/dist/web/assets/chat-tab-CJi4uYb9.js +15 -0
- package/dist/web/assets/{cobol-Bo0usdoM.js → cobol-BreMVrtc.js} +1 -1
- package/dist/web/assets/code-editor-C4kKhamq.js +7 -0
- package/dist/web/assets/{coffee-DBBsbX1e.js → coffee-D7DoKh5b.js} +1 -1
- package/dist/web/assets/{conflict-editor-NqFAJP47.js → conflict-editor-BEULKwHk.js} +1 -1
- package/dist/web/assets/{context-menu-C13b1uT3.js → context-menu-CJL8L98s.js} +1 -1
- package/dist/web/assets/{cpp-6CTO78A-.js → cpp-BnWeWAoE.js} +1 -1
- package/dist/web/assets/{crystal-DAlvpAP7.js → crystal-D2pJbFUn.js} +1 -1
- package/dist/web/assets/{csv-preview-Dvriy18_.js → csv-preview-k3eM8nFf.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-iRrpAV0e.js → data-grid-overlay-editor-CbBkhhJa.js} +1 -1
- package/dist/web/assets/{database-viewer-Bs2RMm5a.js → database-viewer-Cslir1dr.js} +1 -1
- package/dist/web/assets/diff-viewer-DzAIvBbn.js +4 -0
- package/dist/web/assets/{docx-preview-Bgw838ry.js → docx-preview-Xy7SZ7Vf.js} +1 -1
- package/dist/web/assets/{edge-D0tZrpC7.js → edge-aqGMtbY3.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-DUgmjNre.js → edit-diff-preview-xdDQvPhs.js} +2 -2
- package/dist/web/assets/{elixir-C1E6-o4G.js → elixir-CsYMBLc5.js} +1 -1
- package/dist/web/assets/{elm-BKyTfeQX.js → elm-BU8C2gFp.js} +1 -1
- package/dist/web/assets/{erb-Cdnr4BMI.js → erb-Z_E49ab8.js} +1 -1
- package/dist/web/assets/{erlang-N1237mFq.js → erlang-BRqOjXH9.js} +1 -1
- package/dist/web/assets/{esm-ClNnmD9t.js → esm-B-vXxHUd.js} +1 -1
- package/dist/web/assets/{explorer-body-DfWunSf9.js → explorer-body-D6H-4cz9.js} +2 -2
- package/dist/web/assets/explorer-window-content-C5W_JzCz.js +1 -0
- package/dist/web/assets/{extension-manager-section-Zc9yag2c.js → extension-manager-section-DwicI3CA.js} +1 -1
- package/dist/web/assets/{extension-webview-B5FayDPz.js → extension-webview-Z3HhC8Pd.js} +1 -1
- package/dist/web/assets/{files-settings-section-CxAtO3GL.js → files-settings-section-ByV7bRbB.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-D_f9tVv0.js → fortran-fixed-form-CWbxmDGR.js} +1 -1
- package/dist/web/assets/{fsharp-DEJmdhc2.js → fsharp-DKMYbq6I.js} +1 -1
- package/dist/web/assets/{gdresource-Dmmrx2gP.js → gdresource-B3yFau4V.js} +1 -1
- package/dist/web/assets/{general-settings-section-9DfKrBns.js → general-settings-section-nLksKHur.js} +1 -1
- package/dist/web/assets/{git-commit-qwJ867ig.js → git-commit-BW0p3Ekk.js} +1 -1
- package/dist/web/assets/{git-log-panel-BsmDZurR.js → git-log-panel-iUXltiTB.js} +1 -1
- package/dist/web/assets/{git-rebase-Dkv8Zw86.js → git-rebase-DrvmQCS7.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-CPd78aaT.js +1 -0
- package/dist/web/assets/{glide-data-grid-BuYwXIoS.js → glide-data-grid-C1QB4DHt.js} +6 -6
- package/dist/web/assets/{glimmer-js-CcrXn8lQ.js → glimmer-js-BY1XApJJ.js} +1 -1
- package/dist/web/assets/{glimmer-ts-CLab3lU7.js → glimmer-ts-DPZtxF8N.js} +1 -1
- package/dist/web/assets/{glsl-DXhkG9dU.js → glsl-DZ8G_Hvf.js} +1 -1
- package/dist/web/assets/{graphql-Cuqsx8r3.js → graphql-Ck06uCZy.js} +1 -1
- package/dist/web/assets/group-chat-tab-ezXKVVpg.js +1 -0
- package/dist/web/assets/{hack-C_CBVdBc.js → hack-pLogDwAs.js} +1 -1
- package/dist/web/assets/{haml-CBWfzZpv.js → haml-CBqeCQ2A.js} +1 -1
- package/dist/web/assets/{handlebars-4e8OR-VI.js → handlebars-B66JmVtp.js} +1 -1
- package/dist/web/assets/{html-C5X4urn_.js → html-Dk4wmfwC.js} +1 -1
- package/dist/web/assets/{html-derivative-nH-jXfsL.js → html-derivative-CJWqfN51.js} +1 -1
- package/dist/web/assets/{http-CQgaG7eu.js → http-CexhotTh.js} +1 -1
- package/dist/web/assets/{hurl-B8gidJhu.js → hurl-BScKFk3Z.js} +1 -1
- package/dist/web/assets/{hxml-BAK94GX8.js → hxml-DAle7vtu.js} +1 -1
- package/dist/web/assets/{image-preview-1kGj4W9R.js → image-preview-fuU4h2nr.js} +1 -1
- package/dist/web/assets/index-CJWbFurD.js +52 -0
- package/dist/web/assets/index-CoaVwAF6.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-BciNds6R.js +1 -0
- package/dist/web/assets/{jinja-BuAjvj8M.js → jinja-yHpyD80t.js} +1 -1
- package/dist/web/assets/{jira-watcher-section-rJVz40wR.js → jira-watcher-section-DwARwskB.js} +1 -1
- package/dist/web/assets/{jison-Dhhs26-L.js → jison-BY6WLJVu.js} +1 -1
- package/dist/web/assets/{julia-gZavIyll.js → julia-Dd_iYQDT.js} +1 -1
- package/dist/web/assets/{just-DDHrFReO.js → just-BTuUKpxF.js} +1 -1
- package/dist/web/assets/keybindings-store-S7YLGd8B.js +1 -0
- package/dist/web/assets/{keyboard-shortcuts-section-Dv4e3M8h.js → keyboard-shortcuts-section-BoUDvdDy.js} +1 -1
- package/dist/web/assets/{latex-BdGZa8ov.js → latex-Dt3OUlMZ.js} +1 -1
- package/dist/web/assets/{liquid-urFfd9Fr.js → liquid-BxPJU2ix.js} +1 -1
- package/dist/web/assets/{lua-CcS6tnB5.js → lua-DEGIvn7d.js} +1 -1
- package/dist/web/assets/{markdown-renderer-CEloCR06.js → markdown-renderer-DKdfiSIX.js} +3 -3
- package/dist/web/assets/markdown-renderer-DYFmMC_8.js +1 -0
- package/dist/web/assets/{marko-CSQqk4oG.js → marko-BDxwBJur.js} +1 -1
- package/dist/web/assets/{mdc-CYIe80m_.js → mdc-B8aXPTg7.js} +1 -1
- package/dist/web/assets/{media-url-DBmHJRft.js → media-url-BMeBaB0q.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-B3uDlD79.js → mobile-bottom-sheet-CmySDB6I.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-CMdqLCV-.js +1 -0
- package/dist/web/assets/{nextflow-C-W8vX8I.js → nextflow-DBVZnnT_.js} +1 -1
- package/dist/web/assets/{nginx-COGi5you.js → nginx-Crpyd-Do.js} +1 -1
- package/dist/web/assets/{nim-CPitYGel.js → nim-BSqTBYDj.js} +1 -1
- package/dist/web/assets/notification-store-DpSYFj36.js +1 -0
- package/dist/web/assets/{notifications-settings-section-B2GkfB0l.js → notifications-settings-section-CIf3-3xd.js} +1 -1
- package/dist/web/assets/{number-overlay-editor-C_eD-Bdr.js → number-overlay-editor-DRjTIcPH.js} +1 -1
- package/dist/web/assets/{overview-panel-Cm2HRtEz.js → overview-panel-DiiA3B_Z.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-ClD3l2Bs.js +1 -0
- package/dist/web/assets/{panel-store-BRrnDO_i.js → panel-store-BmdcSBNb.js} +1 -1
- package/dist/web/assets/{pdf-preview-Dmz8jkZZ.js → pdf-preview-C-7IdkIK.js} +1 -1
- package/dist/web/assets/{perl-B0yW3hbb.js → perl-BU0kbB-K.js} +1 -1
- package/dist/web/assets/{php-BNMYN5Jp.js → php-D9n1ikHN.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-PU6kD0rW.js +1 -0
- package/dist/web/assets/{postgres-viewer-BtZbfC3f.js → postgres-viewer-BYXFYlLg.js} +3 -3
- package/dist/web/assets/{ppmbot-settings-section-OYfVG5-l.js → ppmbot-settings-section-B9dXvQ6p.js} +1 -1
- package/dist/web/assets/{process-table-DRu3NyO_.js → process-table-B6NeTWt8.js} +1 -1
- package/dist/web/assets/{project-store-BuY7rxn_.js → project-store-wWZ6bjwq.js} +1 -1
- package/dist/web/assets/{proxy-settings-section-xMbrcyr8.js → proxy-settings-section-CUqq7pdU.js} +1 -1
- package/dist/web/assets/{pug-CP5fxsxD.js → pug-BOpaczDr.js} +1 -1
- package/dist/web/assets/{qml-CHGpQosY.js → qml-B-cQXhrg.js} +1 -1
- package/dist/web/assets/{query-audit-section-CC5Mf6qp.js → query-audit-section-C1TYrPIp.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-4LzjL0Zt.js +1 -0
- package/dist/web/assets/{razor-Cfe0AYo4.js → razor-DFB0pNCh.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-DuKwKe5F.js +2 -0
- package/dist/web/assets/{remote-desktop-mobile-view-B4BSHIxU.js → remote-desktop-mobile-view-DxMTtsa6.js} +1 -1
- package/dist/web/assets/{remote-desktop-readiness-gate-C0d0PSX4.js → remote-desktop-readiness-gate-BwjfLWqg.js} +1 -1
- package/dist/web/assets/{remote-desktop-window-content-DjeCZzqq.js → remote-desktop-window-content-BIl4N5Hn.js} +1 -1
- package/dist/web/assets/{rst-DxSSGshb.js → rst-DAXedsgm.js} +1 -1
- package/dist/web/assets/{ruby-rbK5SsJa.js → ruby-BCO4polC.js} +1 -1
- package/dist/web/assets/{run-in-terminal-DHAvC1AG.js → run-in-terminal-wHKwAnWP.js} +1 -1
- package/dist/web/assets/{sas-DDM28fbb.js → sas-DfB5dcFC.js} +1 -1
- package/dist/web/assets/schedules-settings-section-C0qOb7GI.js +1 -0
- package/dist/web/assets/{scss-TDl-6ro4.js → scss-BknIVgn7.js} +1 -1
- package/dist/web/assets/{send-to-chat-BOyUWNKw.js → send-to-chat-BI7-fFpG.js} +1 -1
- package/dist/web/assets/{separator-BzGoTlR7.js → separator-W_hJcXPk.js} +1 -1
- package/dist/web/assets/{settings-body-CXTQwhbM.js → settings-body-qbrJXX_A.js} +2 -2
- package/dist/web/assets/settings-store-CzLnTR8p.js +2 -0
- package/dist/web/assets/settings-tab-BKRgYVxf.js +1 -0
- package/dist/web/assets/settings-window-content-DWsxJDu-.js +1 -0
- package/dist/web/assets/{shaderlab-CCvmDgGS.js → shaderlab-CPu31TpY.js} +1 -1
- package/dist/web/assets/{shellsession-BzKS9yKh.js → shellsession-CFX4c_TM.js} +1 -1
- package/dist/web/assets/{soy-QfO35nDh.js → soy-rz9hilgm.js} +1 -1
- package/dist/web/assets/{sparql-D29RDfp2.js → sparql-Bo8ZDeqE.js} +1 -1
- package/dist/web/assets/{sql-query-editor-B-VwfyTf.js → sql-query-editor-CsZOpCW3.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-CpUhDEhN.js → sqlite-viewer-DUrnCaP7.js} +1 -1
- package/dist/web/assets/{stata-Be6j_SNv.js → stata-B5J-QMyE.js} +1 -1
- package/dist/web/assets/{streaming-store-9_9j70zt.js → streaming-store-9XVmAMfV.js} +1 -1
- package/dist/web/assets/{surrealql-CykFjgNG.js → surrealql-Caw1ADnG.js} +1 -1
- package/dist/web/assets/{svelte-CdBF8z4-.js → svelte-D3oMVcxz.js} +1 -1
- package/dist/web/assets/{system-monitor-body-DzWXd1wM.js → system-monitor-body-C5cMpg7I.js} +2 -2
- package/dist/web/assets/system-monitor-tab-C66ywbVZ.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-DIIP3dff.js → system-monitor-window-content-CENaXYJ-.js} +1 -1
- package/dist/web/assets/{tab-host-window-content-CLdcz84K.js → tab-host-window-content-HViABGoS.js} +1 -1
- package/dist/web/assets/{tab-store-PZsP5ZwG.js → tab-store-1xYJb0gM.js} +1 -1
- package/dist/web/assets/team-member-sheet-CK6eyBRL.js +2 -0
- package/dist/web/assets/team-member-window-content-D6wxg37P.js +1 -0
- package/dist/web/assets/{templ-BVHE2CNb.js → templ-BAdNyIOL.js} +1 -1
- package/dist/web/assets/{terminal-tab-BeKLpaPM.js → terminal-tab-BmyTawmN.js} +2 -2
- package/dist/web/assets/{tex-C8XwrbBw.js → tex-IQ8mELOR.js} +1 -1
- package/dist/web/assets/tool-cards-y-XJcJHo.js +9 -0
- package/dist/web/assets/treemap-KZPCXAKY-DiumLNMg.js +1 -0
- package/dist/web/assets/{ts-tags-BIHk5AM0.js → ts-tags-D1DDO2jl.js} +1 -1
- package/dist/web/assets/{twig-YcE6Q2Ox.js → twig-C8Fd5RvV.js} +1 -1
- package/dist/web/assets/use-accounts-data-BbOb2QNP.js +1 -0
- package/dist/web/assets/{use-blob-url-De-ZtcpX.js → use-blob-url-CrwoZJUJ.js} +1 -1
- package/dist/web/assets/use-inline-blame-C1G-_NjC.js +8 -0
- package/dist/web/assets/{use-monaco-theme-Kj2OGDlm.js → use-monaco-theme-BkM5rMgL.js} +1 -1
- package/dist/web/assets/{use-open-team-member-DWhhWdmJ.js → use-open-team-member-CSUU7Z8N.js} +1 -1
- package/dist/web/assets/{use-remote-desktop-display-choice-8AkPpM_0.js → use-remote-desktop-display-choice-BT2r1td1.js} +1 -1
- package/dist/web/assets/{use-websocket-kR1omKO1.js → use-websocket-BvVTwMjI.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-CKKtYuTV.js → vendor-mermaid-CfY1-PkA.js} +1 -1
- package/dist/web/assets/{video-preview-BdV7LjbZ.js → video-preview-BEaofjN7.js} +1 -1
- package/dist/web/assets/{vue-q7m01V0h.js → vue-EvccXlkP.js} +1 -1
- package/dist/web/assets/{vue-html-D1y9feOj.js → vue-html-Dg0xUJCh.js} +1 -1
- package/dist/web/assets/{vue-vine-DrIGs03v.js → vue-vine-BdrMg72k.js} +1 -1
- package/dist/web/assets/{window-pip-registry-CSLhJfpL.js → window-pip-registry-CrCYYTTf.js} +1 -1
- package/dist/web/assets/{window-store-DGKf9rPG.js → window-store-D0HbQ1pM.js} +1 -1
- package/dist/web/assets/ws-auth-D111jj32.js +1 -0
- package/dist/web/assets/{xml-oyvc1920.js → xml-MmDclzxK.js} +1 -1
- package/dist/web/assets/{xsl-BbIGdNPF.js → xsl-DQEFs6Dd.js} +1 -1
- package/dist/web/index.html +23 -23
- package/dist/web/sw.js +1 -1
- package/docs/extension-development-guide.md +47 -0
- package/docs/project-roadmap.md +3 -1
- package/package.json +2 -2
- package/packages/ext-git-graph/package.json +23 -5
- package/packages/ext-git-graph/src/blame-parser.test.ts +154 -0
- package/packages/ext-git-graph/src/blame-parser.ts +148 -0
- package/packages/ext-git-graph/src/blame-view.ts +389 -0
- package/packages/ext-git-graph/src/commit-search.test.ts +118 -0
- package/packages/ext-git-graph/src/commit-search.ts +102 -0
- package/packages/ext-git-graph/src/compare-args.test.ts +111 -0
- package/packages/ext-git-graph/src/compare-args.ts +109 -0
- package/packages/ext-git-graph/src/compare-view.ts +343 -0
- package/packages/ext-git-graph/src/extension-integration.test.ts +6 -3
- package/packages/ext-git-graph/src/extension.ts +202 -249
- package/packages/ext-git-graph/src/file-history-parser.test.ts +102 -0
- package/packages/ext-git-graph/src/file-history-parser.ts +89 -0
- package/packages/ext-git-graph/src/file-history-view.ts +386 -0
- package/packages/ext-git-graph/src/git-exec.ts +122 -0
- package/packages/ext-git-graph/src/git-state.ts +81 -0
- package/packages/ext-git-graph/src/panel-nav.ts +65 -0
- package/packages/ext-git-graph/src/panel-registry.ts +72 -0
- package/packages/ext-git-graph/src/ppm-api.ts +48 -0
- package/packages/ext-git-graph/src/rebase-todo.test.ts +196 -0
- package/packages/ext-git-graph/src/rebase-todo.ts +119 -0
- package/packages/ext-git-graph/src/rebase-view.ts +483 -0
- package/packages/ext-git-graph/src/reflog-parser.test.ts +93 -0
- package/packages/ext-git-graph/src/reflog-parser.ts +86 -0
- package/packages/ext-git-graph/src/reflog-view.ts +375 -0
- package/packages/ext-git-graph/src/register-view-command.ts +47 -0
- package/packages/ext-git-graph/src/submodule-parser.test.ts +79 -0
- package/packages/ext-git-graph/src/submodule-parser.ts +77 -0
- package/packages/ext-git-graph/src/types.ts +10 -1
- package/packages/ext-git-graph/src/webview-html.ts +438 -3
- package/packages/ext-git-graph/src/webview-shell.ts +236 -0
- package/src/providers/claude-agent-sdk.ts +7 -0
- package/src/providers/codex-app-server/codex-provider.ts +89 -1
- package/src/server/index.ts +1 -1
- package/src/server/routes/accounts.ts +25 -1
- package/src/server/routes/chat.ts +29 -1
- package/src/server/routes/codex-accounts.ts +41 -1
- package/src/server/routes/git.ts +97 -0
- package/src/server/routes/settings.ts +1 -0
- package/src/server/routes/teams.ts +14 -3
- package/src/services/account-selector.service.ts +125 -20
- package/src/services/account.service.ts +176 -54
- package/src/services/autostart-generator.ts +12 -1
- package/src/services/codex-account.service.ts +87 -13
- package/src/services/db.service.ts +58 -3
- package/src/services/extension.service.ts +55 -5
- package/src/services/git-blame/blame-porcelain.ts +89 -0
- package/src/services/git-blame/git-blame.service.ts +90 -0
- package/src/services/git-hunks/git-hunks.service.ts +264 -0
- package/src/services/git-hunks/unified-diff.ts +359 -0
- package/src/services/picked-account-binding.ts +57 -0
- package/src/services/team-member-activity/member-transcript-tail.ts +64 -0
- package/src/shared/blame.ts +79 -0
- package/src/web/components/chat/chat-history-bar.tsx +34 -5
- package/src/web/components/chat/chat-tab.tsx +120 -3
- package/src/web/components/chat/codex-usage-panel.tsx +132 -14
- package/src/web/components/chat/edit-diff-preview.tsx +14 -7
- package/src/web/components/chat/team-member-window-content.tsx +8 -39
- package/src/web/components/chat/usage-badge.tsx +176 -52
- package/src/web/components/editor/code-editor.tsx +33 -1
- package/src/web/components/editor/diff-viewer.tsx +83 -8
- package/src/web/components/editor/editor-toolbar.tsx +25 -1
- package/src/web/components/git/git-status-panel.tsx +46 -0
- package/src/web/components/git/hunk-selection.ts +132 -0
- package/src/web/components/git/hunk-stage-dialog.tsx +419 -0
- package/src/web/components/settings/accounts/account-bucket-row.tsx +19 -3
- package/src/web/components/settings/accounts/account-card.tsx +153 -33
- package/src/web/components/settings/accounts/account-hint.tsx +33 -0
- package/src/web/components/settings/accounts/account-usage-format.ts +26 -0
- package/src/web/components/settings/accounts/codex-accounts-section.tsx +24 -9
- package/src/web/components/settings/accounts/codex-usage-rows.tsx +2 -2
- package/src/web/components/settings/accounts/use-accounts-data.ts +32 -2
- package/src/web/components/settings/accounts/use-codex-accounts.ts +24 -2
- package/src/web/components/shared/markdown-code-block.tsx +10 -5
- package/src/web/hooks/use-chat.ts +27 -0
- package/src/web/hooks/use-inline-blame.ts +175 -0
- package/src/web/hooks/use-member-transcript-tail.ts +95 -0
- package/src/web/lib/api-settings.ts +24 -0
- package/src/web/stores/settings-store.ts +12 -0
- package/dist/web/assets/accounts-settings-section-Cd1Nh04o.js +0 -1
- package/dist/web/assets/ai-settings-section-OaYGT5OF.js +0 -1
- package/dist/web/assets/api-client-BogqsFna.js +0 -1
- package/dist/web/assets/api-settings-BVfemzZW.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-BZBxtErN.js +0 -1
- package/dist/web/assets/chat-tab-Cc1W2pTu.js +0 -15
- package/dist/web/assets/code-editor-gLRyCPWE.js +0 -7
- package/dist/web/assets/diff-viewer-ix1Ko0xk.js +0 -4
- package/dist/web/assets/explorer-window-content-B7HmteDI.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-BHxJbXfV.js +0 -1
- package/dist/web/assets/group-chat-tab-DmZ1vLk-.js +0 -1
- package/dist/web/assets/index-N-pnuwFP.css +0 -2
- package/dist/web/assets/index-yV5RgBDh.js +0 -52
- package/dist/web/assets/info-3K5VOQVL-DI4p3vbH.js +0 -1
- package/dist/web/assets/keybindings-store-88_Zkn5F.js +0 -1
- package/dist/web/assets/markdown-renderer-UhszMWSn.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-D9cqcU3X.js +0 -1
- package/dist/web/assets/notification-store-B6X6RYqQ.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-YNQWTi_-.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-E3Wiw76n.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-BPQJUKON.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-DefltAPl.js +0 -2
- package/dist/web/assets/schedules-settings-section-D76Ob6tI.js +0 -1
- package/dist/web/assets/settings-store-DWUx3865.js +0 -2
- package/dist/web/assets/settings-tab-DToHQXfC.js +0 -1
- package/dist/web/assets/settings-window-content-B2rlq-Dv.js +0 -1
- package/dist/web/assets/system-monitor-tab-CuDpwAZU.js +0 -1
- package/dist/web/assets/team-member-sheet-DLrT_Kxo.js +0 -2
- package/dist/web/assets/team-member-window-content-S8cdLcg3.js +0 -1
- package/dist/web/assets/tool-cards-CLxrQlUs.js +0 -9
- package/dist/web/assets/treemap-KZPCXAKY-C2CvKBQR.js +0 -1
- package/dist/web/assets/use-accounts-data-snYPJED_.js +0 -1
- package/dist/web/assets/ws-auth-ZSZkAT6p.js +0 -1
- /package/dist/web/assets/{abap-Cq9nYQyd.js → abap-D-o-bvtI.js} +0 -0
- /package/dist/web/assets/{actionscript-3-DL8rUIy0.js → actionscript-3-D2tIzAm8.js} +0 -0
- /package/dist/web/assets/{ada-BY8TLuhY.js → ada-DxatBcxS.js} +0 -0
- /package/dist/web/assets/{andromeeda-CyVfHsS0.js → andromeeda-D0LK9YJ3.js} +0 -0
- /package/dist/web/assets/{apache-DTQUy73x.js → apache-B7uMPNiW.js} +0 -0
- /package/dist/web/assets/{apex-CiSZngrZ.js → apex-B7GiXrAr.js} +0 -0
- /package/dist/web/assets/{api-client-oY1tC3tM.js → api-client-CEYCBt_0.js} +0 -0
- /package/dist/web/assets/{applescript-CzuRDd3h.js → applescript-D_SIFkKe.js} +0 -0
- /package/dist/web/assets/{apply-theme-r8tKDrCR.js → apply-theme-BVXAUYoN.js} +0 -0
- /package/dist/web/assets/{ara-CSFV93kR.js → ara-C3iECgdg.js} +0 -0
- /package/dist/web/assets/{asciidoc-hOQNnXhz.js → asciidoc-gc8z_MMY.js} +0 -0
- /package/dist/web/assets/{asm-DdG53NGR.js → asm-27qeoPOI.js} +0 -0
- /package/dist/web/assets/{aurora-x-DJ7ORZG6.js → aurora-x-C5J9fWe1.js} +0 -0
- /package/dist/web/assets/{awk-B3FFpX_J.js → awk-B7GBzF92.js} +0 -0
- /package/dist/web/assets/{ayu-dark-D_P1CfTe.js → ayu-dark-XlnQhuLL.js} +0 -0
- /package/dist/web/assets/{ayu-light-Cz3YLUqH.js → ayu-light-DKLLilkU.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-JcMq5tgJ.js → ayu-mirage-Dv-XOprJ.js} +0 -0
- /package/dist/web/assets/{ballerina-7Hs4Rfpk.js → ballerina-DACRT-sT.js} +0 -0
- /package/dist/web/assets/{bat-COgQdnFA.js → bat-BlQCq2XE.js} +0 -0
- /package/dist/web/assets/{beancount-BJ3CutBG.js → beancount-DYDztRI0.js} +0 -0
- /package/dist/web/assets/{berry-D7so2Cui.js → berry-BE5YKqvx.js} +0 -0
- /package/dist/web/assets/{bibtex-Ct3acHa1.js → bibtex-CAm7mgEm.js} +0 -0
- /package/dist/web/assets/{bicep-jXDwCQcm.js → bicep-BKgAbfVa.js} +0 -0
- /package/dist/web/assets/{bird2-CjLD2cna.js → bird2-yrBNbW1G.js} +0 -0
- /package/dist/web/assets/{c-CdgZojnL.js → c-txZFr4RM.js} +0 -0
- /package/dist/web/assets/{c3-DtpZYego.js → c3-D_DrzBUd.js} +0 -0
- /package/dist/web/assets/{cadence-CPLkixoh.js → cadence-CUFCEgG9.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-BntPywsy.js → can-open-in-ppm-_yqa69dV.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-Xt0_qJa9.js → catppuccin-frappe-Dn32MuhA.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-CJnbLec5.js → catppuccin-latte-Dewo7yDf.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-BPHP1wYB.js → catppuccin-macchiato-D8WOWZeo.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-ssWJodGc.js → catppuccin-mocha-b0md48XM.js} +0 -0
- /package/dist/web/assets/{clarity-DB0408F6.js → clarity-Ct3UqLBj.js} +0 -0
- /package/dist/web/assets/{clojure-dpRPlAO4.js → clojure-CwP5aPEo.js} +0 -0
- /package/dist/web/assets/{cmake-r2VkeX9y.js → cmake-D5RF49e5.js} +0 -0
- /package/dist/web/assets/{codeowners-v5nQqHiB.js → codeowners-Cl5897L_.js} +0 -0
- /package/dist/web/assets/{codeql-BSSEhKRR.js → codeql-BKh1RCg0.js} +0 -0
- /package/dist/web/assets/{common-lisp-BXb2MMMA.js → common-lisp-BhHuD6t0.js} +0 -0
- /package/dist/web/assets/{coq-BjBNi73X.js → coq-Dco3qwD8.js} +0 -0
- /package/dist/web/assets/{csharp-CdPjZRbV.js → csharp-Dpjw9ZA9.js} +0 -0
- /package/dist/web/assets/{css-BuxbQOHL.js → css-CPe4cabH.js} +0 -0
- /package/dist/web/assets/{csv-Dj-eoZwH.js → csv-BAcTN8Kt.js} +0 -0
- /package/dist/web/assets/{csv-parser-CBbALsFU.js → csv-parser-DbxGKdMG.js} +0 -0
- /package/dist/web/assets/{cue-Dz73VksN.js → cue-Cr6y60TA.js} +0 -0
- /package/dist/web/assets/{cypher-CkVkDywZ.js → cypher-DWtqXXFP.js} +0 -0
- /package/dist/web/assets/{d-oU51Pbpf.js → d-BASiTZk4.js} +0 -0
- /package/dist/web/assets/{dark-plus-DcwvjjfO.js → dark-plus-56kmnrcl.js} +0 -0
- /package/dist/web/assets/{dart-DGvu8mcX.js → dart-C5mZnjoE.js} +0 -0
- /package/dist/web/assets/{data-grid-types-B6kUrF-M.js → data-grid-types-DeY60CLU.js} +0 -0
- /package/dist/web/assets/{dax-BmbjKQ90.js → dax-B4I2e7d8.js} +0 -0
- /package/dist/web/assets/{desktop-IRBSiFfh.js → desktop-DekGg0BT.js} +0 -0
- /package/dist/web/assets/{diff-Bdik2JR8.js → diff-CWnJBd73.js} +0 -0
- /package/dist/web/assets/{dist-Bv4zQpS1.js → dist-B0J2eYBz.js} +0 -0
- /package/dist/web/assets/{dist-C8YPBIOb.js → dist-BKOM_AoT.js} +0 -0
- /package/dist/web/assets/{docker-Bgdl0H8I.js → docker-DevchDxK.js} +0 -0
- /package/dist/web/assets/{dotenv-COe5NdnA.js → dotenv-DCvtdaGJ.js} +0 -0
- /package/dist/web/assets/{dracula-DjURaSAa.js → dracula-8U6Vkk3l.js} +0 -0
- /package/dist/web/assets/{dracula-soft-Do7d0bo-.js → dracula-soft-Bfeew5Wg.js} +0 -0
- /package/dist/web/assets/{dream-maker-DYwQvJIj.js → dream-maker-DDTJVuoy.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-BXjlHyDW.js → emacs-lisp-CEHJqI4m.js} +0 -0
- /package/dist/web/assets/{everforest-dark-h8Q2loiX.js → everforest-dark-CHHLt7cq.js} +0 -0
- /package/dist/web/assets/{everforest-light-CdsJiL-9.js → everforest-light-TcTbK1sM.js} +0 -0
- /package/dist/web/assets/{fennel-D0CBtOvY.js → fennel-Bh4vsA1A.js} +0 -0
- /package/dist/web/assets/{fish-DzayfrMj.js → fish-D0T0fILG.js} +0 -0
- /package/dist/web/assets/{fluent-CatjkUfx.js → fluent-CgXDXdyy.js} +0 -0
- /package/dist/web/assets/{format-bytes-BulRSULX.js → format-bytes-Bc6SqF7M.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-DM04ud0b.js → fortran-free-form-CUg3Xhz4.js} +0 -0
- /package/dist/web/assets/{gdscript-BLN5iZwf.js → gdscript-Cx056p_k.js} +0 -0
- /package/dist/web/assets/{gdshader-BK-1iZQs.js → gdshader-Dj1qP4I5.js} +0 -0
- /package/dist/web/assets/{genie-BGPOFWDN.js → genie-SBt15wn7.js} +0 -0
- /package/dist/web/assets/{gherkin-CdVOJ_JY.js → gherkin-bTJiHIrB.js} +0 -0
- /package/dist/web/assets/{github-dark-B_xW8TaY.js → github-dark-BOPhyugs.js} +0 -0
- /package/dist/web/assets/{github-dark-default-h_iKq7CX.js → github-dark-default-Cktqe6NF.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-nKDYE62T.js → github-dark-dimmed-CeWfII_B.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-l8I771QT.js → github-dark-high-contrast-CTx8LpdV.js} +0 -0
- /package/dist/web/assets/{github-light-DNhjkg8Z.js → github-light-DVsO5Un1.js} +0 -0
- /package/dist/web/assets/{github-light-default-DQ06uS3g.js → github-light-default-BiyPxicr.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-qc2sZCVN.js → github-light-high-contrast-BPlnke0a.js} +0 -0
- /package/dist/web/assets/{gleam-DPPatkNH.js → gleam-CWSxvD0C.js} +0 -0
- /package/dist/web/assets/{gn-BnzGQTy5.js → gn-D7NUVJuv.js} +0 -0
- /package/dist/web/assets/{gnuplot-Ct1leoo3.js → gnuplot-c5uXmJKc.js} +0 -0
- /package/dist/web/assets/{go-qysCdbrn.js → go-CRsHi4Cw.js} +0 -0
- /package/dist/web/assets/{groovy-BkWIdrRQ.js → groovy-DpV0RA5r.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-L6Iiybbl.js → gruvbox-dark-hard-DD9fguUN.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-DbD3yl0b.js → gruvbox-dark-medium-BvcwpYJ-.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-Ban2cHK3.js → gruvbox-dark-soft-48dCxX9M.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-CK_SjS3e.js → gruvbox-light-hard-CjJ994Ip.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-Bjgvhc2w.js → gruvbox-light-medium-DQJQZ_rV.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-EWnyYGUu.js → gruvbox-light-soft-AqsC9mKw.js} +0 -0
- /package/dist/web/assets/{haskell-rT1N9nYr.js → haskell-B5V7yvmh.js} +0 -0
- /package/dist/web/assets/{haxe-Bbc91axo.js → haxe-LWTKfPKr.js} +0 -0
- /package/dist/web/assets/{hcl-D-3qJA4v.js → hcl-QmNZdAtI.js} +0 -0
- /package/dist/web/assets/{hjson-DWtewcyQ.js → hjson-CboJsAzK.js} +0 -0
- /package/dist/web/assets/{hlsl-C7t6hCrO.js → hlsl-Bd-DO_WL.js} +0 -0
- /package/dist/web/assets/{horizon-zJAGUQ3j.js → horizon-CU8Bi_ss.js} +0 -0
- /package/dist/web/assets/{horizon-bright-CRNyrJy8.js → horizon-bright-iSQ3_3jP.js} +0 -0
- /package/dist/web/assets/{houston-BFKa4W1-.js → houston-CTXv3Puz.js} +0 -0
- /package/dist/web/assets/{hy-W1hNjMBM.js → hy-Cd4hTidD.js} +0 -0
- /package/dist/web/assets/{image-gallery-BycaVWOu.js → image-gallery-J8h8IY0c.js} +0 -0
- /package/dist/web/assets/{imba-CPphaV-V.js → imba-BipCHEY2.js} +0 -0
- /package/dist/web/assets/{ini-CayaZ4vW.js → ini-Dd1KkMrB.js} +0 -0
- /package/dist/web/assets/{java-BPAE_9Ej.js → java-rGr0OQD8.js} +0 -0
- /package/dist/web/assets/{javascript-C5SKIVqe.js → javascript-DHhCH2TN.js} +0 -0
- /package/dist/web/assets/{json-C-0EUYmu.js → json-CMMLBCUf.js} +0 -0
- /package/dist/web/assets/{json5-BqVetEZL.js → json5-mPOwTOsB.js} +0 -0
- /package/dist/web/assets/{jsonc-DnjIzkUB.js → jsonc-Bie0E6D3.js} +0 -0
- /package/dist/web/assets/{jsonl-rbV-3EqO.js → jsonl-CpqHmtC1.js} +0 -0
- /package/dist/web/assets/{jsonnet-9hvXw4qr.js → jsonnet-D21Ms51e.js} +0 -0
- /package/dist/web/assets/{jssm-1ifXyIhu.js → jssm-BXnl1nur.js} +0 -0
- /package/dist/web/assets/{jsx-hPumywTY.js → jsx-Chnii_vB.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-BCPjmoMO.js → kanagawa-dragon-DhxR0UjL.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-DN2VNjy7.js → kanagawa-lotus-fupRg5wp.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-B8RZEsgc.js → kanagawa-wave-DSWbRS9M.js} +0 -0
- /package/dist/web/assets/{kdl-CkvjWQIa.js → kdl-DirGHqUy.js} +0 -0
- /package/dist/web/assets/{kotlin-D8cnRi5o.js → kotlin-DkhUVMDC.js} +0 -0
- /package/dist/web/assets/{kusto-CmeeBEJG.js → kusto-DU7OpovF.js} +0 -0
- /package/dist/web/assets/{laserwave--rtV8Mv9.js → laserwave-iLKb1ZCT.js} +0 -0
- /package/dist/web/assets/{lean-CS-Pyi42.js → lean-Cuvh_QAP.js} +0 -0
- /package/dist/web/assets/{less-Ddi_7qGm.js → less-B5tQZOdI.js} +0 -0
- /package/dist/web/assets/{lib-DIrxSyLb.js → lib-el9rA30D.js} +0 -0
- /package/dist/web/assets/{libesm-CYLrAeW3.js → libesm-CdttTIAd.js} +0 -0
- /package/dist/web/assets/{light-plus-CrEjpkkX.js → light-plus-DiHU2KL5.js} +0 -0
- /package/dist/web/assets/{llvm-Cm7ZXmAO.js → llvm-sCBTKCKN.js} +0 -0
- /package/dist/web/assets/{log-lW2sYxtp.js → log-DtyR34Ie.js} +0 -0
- /package/dist/web/assets/{logo-B-PiRb53.js → logo-CP91aQyG.js} +0 -0
- /package/dist/web/assets/{luau-8St0pC-R.js → luau-nfGo2ulP.js} +0 -0
- /package/dist/web/assets/{make-DbNdhH54.js → make-XbDn9GHe.js} +0 -0
- /package/dist/web/assets/{markdown-CYocYSGd.js → markdown-BB1_3xLr.js} +0 -0
- /package/dist/web/assets/{material-theme-CVBF1Cbi.js → material-theme-CIx_sxAy.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-HFrlNZD8.js → material-theme-darker-DsQeueDD.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-BM-uz2ft.js → material-theme-lighter-x_lMi74j.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-PbvUez8m.js → material-theme-ocean-Bkgh25P8.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-B22Ck6qd.js → material-theme-palenight-CoOjdbti.js} +0 -0
- /package/dist/web/assets/{matlab-GFFNzucw.js → matlab-D6xZas_8.js} +0 -0
- /package/dist/web/assets/{mdx-BVnJzMDx.js → mdx-Cl5_YNoz.js} +0 -0
- /package/dist/web/assets/{mermaid-BlCmSTCM.js → mermaid-8Eow4jz_.js} +0 -0
- /package/dist/web/assets/{min-dark-B0PwlAfC.js → min-dark-D4DhjgRE.js} +0 -0
- /package/dist/web/assets/{min-light-C_H2ABKu.js → min-light-DzAckd0t.js} +0 -0
- /package/dist/web/assets/{mipsasm-C3rf2fo6.js → mipsasm-zI_zu0tj.js} +0 -0
- /package/dist/web/assets/{mojo-CDRuzM3o.js → mojo-DQnGGPHf.js} +0 -0
- /package/dist/web/assets/{monokai-KiebNy_Y.js → monokai-CrFoD2VD.js} +0 -0
- /package/dist/web/assets/{moonbit-CdVUHoWl.js → moonbit-DdphIGs6.js} +0 -0
- /package/dist/web/assets/{move-Dq9iKZRY.js → move-BUlkn0xW.js} +0 -0
- /package/dist/web/assets/{narrat-7y5L5sGM.js → narrat-CbOBdtCn.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-Cwcbkcrx.js → nextflow-groovy-CeVLUTuQ.js} +0 -0
- /package/dist/web/assets/{night-owl-TBgLPzj4.js → night-owl-Bm4LhUR1.js} +0 -0
- /package/dist/web/assets/{night-owl-light-Dehb9My2.js → night-owl-light-DtcBiMEf.js} +0 -0
- /package/dist/web/assets/{nix-BKj-gzoX.js → nix-DrdwQ70g.js} +0 -0
- /package/dist/web/assets/{nord-BF_r8PeX.js → nord-B0Head1v.js} +0 -0
- /package/dist/web/assets/{nushell-CeAjk9_E.js → nushell-CmUdltKn.js} +0 -0
- /package/dist/web/assets/{objective-c-Xl1OMcDp.js → objective-c-BGDR33XN.js} +0 -0
- /package/dist/web/assets/{objective-cpp-C4ZgzrRq.js → objective-cpp-Buc1Zhd0.js} +0 -0
- /package/dist/web/assets/{ocaml-CGj8IYTq.js → ocaml-xdzl9rRD.js} +0 -0
- /package/dist/web/assets/{odin-C4veqvW2.js → odin-DiUFngnd.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-gAcWejsV.js → one-dark-pro-BURxmIp3.js} +0 -0
- /package/dist/web/assets/{one-light-B7E-UUXy.js → one-light-BMRMInAj.js} +0 -0
- /package/dist/web/assets/{openscad-C-wN9BEv.js → openscad-DAgLA5J3.js} +0 -0
- /package/dist/web/assets/{pascal-C8WBtxMs.js → pascal-CoDZxcRB.js} +0 -0
- /package/dist/web/assets/{pkl-BBfF4G2A.js → pkl-DzKM6BuM.js} +0 -0
- /package/dist/web/assets/{plastic-DFOAb89P.js → plastic-vF15LmNS.js} +0 -0
- /package/dist/web/assets/{plsql-BS2CEMMV.js → plsql-C1v07teA.js} +0 -0
- /package/dist/web/assets/{po-BKJDtPmy.js → po-CLLC8BuA.js} +0 -0
- /package/dist/web/assets/{poimandres-Cg3hL13e.js → poimandres-Uq0xysxM.js} +0 -0
- /package/dist/web/assets/{polar-B9ebiXUU.js → polar-2-luY1Pc.js} +0 -0
- /package/dist/web/assets/{portal-container-context-a399Hd9F.js → portal-container-context-DKymYOY-.js} +0 -0
- /package/dist/web/assets/{postcss-B5REwNY_.js → postcss-lbFhe0rz.js} +0 -0
- /package/dist/web/assets/{powerquery-stc0Gzkf.js → powerquery-RL8O9Wie.js} +0 -0
- /package/dist/web/assets/{powershell-jgd0ahJN.js → powershell-upFWhb-b.js} +0 -0
- /package/dist/web/assets/{prisma-CWuZjRhI.js → prisma-DBtYaWFk.js} +0 -0
- /package/dist/web/assets/{prolog-D5zNFE63.js → prolog-D8jSMykJ.js} +0 -0
- /package/dist/web/assets/{proto-B-6RrU7n.js → proto-BM4eadF7.js} +0 -0
- /package/dist/web/assets/{puppet-DONP8TDR.js → puppet-BQDQ3Snu.js} +0 -0
- /package/dist/web/assets/{purescript-DDJITf-A.js → purescript-Cj2aTX4s.js} +0 -0
- /package/dist/web/assets/{python-bmWy9j1-.js → python-BYpqq6u4.js} +0 -0
- /package/dist/web/assets/{qmldir-CKDwMt7X.js → qmldir-4uiTcwAu.js} +0 -0
- /package/dist/web/assets/{qss-DptQQzBn.js → qss-D5xB-Mqo.js} +0 -0
- /package/dist/web/assets/{r-BorKpJ8r.js → r-P6Ujy8rf.js} +0 -0
- /package/dist/web/assets/{racket-BaHpYVsZ.js → racket-COKgCFuM.js} +0 -0
- /package/dist/web/assets/{raku-DFJIV4k_.js → raku-z14Q9i7K.js} +0 -0
- /package/dist/web/assets/{react-X4jUntEf.js → react-D1Yg256j.js} +0 -0
- /package/dist/web/assets/{red-70oJGrkb.js → red-ObAvgvQ5.js} +0 -0
- /package/dist/web/assets/{reg-C4g235Dv.js → reg-Qv4f0JFA.js} +0 -0
- /package/dist/web/assets/{regexp-Cw1UVmti.js → regexp-CEOVGIzy.js} +0 -0
- /package/dist/web/assets/{rel-DeLhIz5L.js → rel-cWOyTUwd.js} +0 -0
- /package/dist/web/assets/{resolve-theme-b_yGlUFQ.js → resolve-theme-CMp5xxCW.js} +0 -0
- /package/dist/web/assets/{riscv-ChnTiBRK.js → riscv-BZDwx-lv.js} +0 -0
- /package/dist/web/assets/{ron-C5IWeqDn.js → ron-BpjosPS0.js} +0 -0
- /package/dist/web/assets/{rose-pine-DCR0ohYW.js → rose-pine-DhxfJWcm.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-DvGZs1PR.js → rose-pine-dawn-BbGt9Wy_.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-BWACHjeS.js → rose-pine-moon-dj4Zxgik.js} +0 -0
- /package/dist/web/assets/{rosmsg-CQlIVazE.js → rosmsg-EciOaHo2.js} +0 -0
- /package/dist/web/assets/{rust-DGGVzWI8.js → rust-C_eH59O_.js} +0 -0
- /package/dist/web/assets/{sass-bj1C0rFI.js → sass-Dos3R5lL.js} +0 -0
- /package/dist/web/assets/{scala-MU1tLKDi.js → scala-8lVKsTvf.js} +0 -0
- /package/dist/web/assets/{scheme-CeGXtv7t.js → scheme-Bd3VdaZj.js} +0 -0
- /package/dist/web/assets/{sdbl-D0HLSGKp.js → sdbl-C4Yrjlgh.js} +0 -0
- /package/dist/web/assets/{shellscript-DkYiDvh1.js → shellscript-OFZbPKZH.js} +0 -0
- /package/dist/web/assets/{slack-dark-YqeHiGWH.js → slack-dark-aL6vlxZs.js} +0 -0
- /package/dist/web/assets/{slack-ochin-9Oe0DljJ.js → slack-ochin-BKt1E7sL.js} +0 -0
- /package/dist/web/assets/{smalltalk-CaaxedR7.js → smalltalk-D6qVBL1U.js} +0 -0
- /package/dist/web/assets/{snazzy-light-C8s2FHNC.js → snazzy-light-BrWerT0t.js} +0 -0
- /package/dist/web/assets/{solarized-dark-0ryY6oN3.js → solarized-dark-CzxTJgVQ.js} +0 -0
- /package/dist/web/assets/{solarized-light-bltgZeNh.js → solarized-light-BecaDAnG.js} +0 -0
- /package/dist/web/assets/{solidity-DOf5HmLZ.js → solidity-C9t7pZ84.js} +0 -0
- /package/dist/web/assets/{splunk-D1u4WHDW.js → splunk-CtxfFKtF.js} +0 -0
- /package/dist/web/assets/{sql-G8uQZljX.js → sql-7FE_Duz0.js} +0 -0
- /package/dist/web/assets/{ssh-config-rbXvly7Q.js → ssh-config-3Fr37ACC.js} +0 -0
- /package/dist/web/assets/{stylus-Cii1iADy.js → stylus-BP4mE1sO.js} +0 -0
- /package/dist/web/assets/{swift-DpIgonN4.js → swift-0uqTFouD.js} +0 -0
- /package/dist/web/assets/{synthwave-84-DjGLzU2b.js → synthwave-84-DQaNM3DI.js} +0 -0
- /package/dist/web/assets/{system-verilog-_Z0M0Hs1.js → system-verilog-DUIVrZHZ.js} +0 -0
- /package/dist/web/assets/{systemd-BhyDCh9P.js → systemd-CtNo_WIh.js} +0 -0
- /package/dist/web/assets/{talonscript-CNchgCRD.js → talonscript-B0HXaCVT.js} +0 -0
- /package/dist/web/assets/{tasl-m--W7Pyr.js → tasl-Cb7RAl11.js} +0 -0
- /package/dist/web/assets/{tcl-gY-M_2BC.js → tcl-B79aC6l5.js} +0 -0
- /package/dist/web/assets/{terraform-CB6CzMwo.js → terraform-75jJDjpW.js} +0 -0
- /package/dist/web/assets/{tokyo-night-COh9oRYi.js → tokyo-night-Cz9Uh9qb.js} +0 -0
- /package/dist/web/assets/{toml-Bg2bsY-v.js → toml-CD6y9A-z.js} +0 -0
- /package/dist/web/assets/{tsv-DceGDiJC.js → tsv-CXJMbBrb.js} +0 -0
- /package/dist/web/assets/{tsx-EccDYa7i.js → tsx-BuYN0I2t.js} +0 -0
- /package/dist/web/assets/{turtle-C_l2JhvX.js → turtle-DWH-Rjse.js} +0 -0
- /package/dist/web/assets/{typescript-C1ytmMcr.js → typescript-BPd-hsrR.js} +0 -0
- /package/dist/web/assets/{typespec-De2ztzG5.js → typespec-B0wvVykx.js} +0 -0
- /package/dist/web/assets/{typst-DNcS7gSr.js → typst-DWG2c48-.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-CYW3FJFE.js → use-is-mobile-D1weanbj.js} +0 -0
- /package/dist/web/assets/{use-visual-viewport-D9O48HQt.js → use-visual-viewport-Bfl3Bxxb.js} +0 -0
- /package/dist/web/assets/{utils-C9OjCrou.js → utils-IrnQujwR.js} +0 -0
- /package/dist/web/assets/{v-DSMUsdMO.js → v-Ch6E4Egd.js} +0 -0
- /package/dist/web/assets/{vala-BEazLpkO.js → vala-CGVKwbPx.js} +0 -0
- /package/dist/web/assets/{vb-CV9pEJzW.js → vb-BIEbSxyT.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-cuGQmUjN.js → vendor-xterm-YQlzIWv2.js} +0 -0
- /package/dist/web/assets/{verilog-DhXkLVMk.js → verilog-A-3pYPad.js} +0 -0
- /package/dist/web/assets/{vesper-n4IltYq-.js → vesper-CK1naZAV.js} +0 -0
- /package/dist/web/assets/{vhdl-CePjFbvs.js → vhdl-CVawmgMg.js} +0 -0
- /package/dist/web/assets/{viml-ChndFsm5.js → viml-CiWjaqBY.js} +0 -0
- /package/dist/web/assets/{vitesse-black-BytVdvhC.js → vitesse-black-PYXW4-BO.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-83Wech0N.js → vitesse-dark-BU5s4AuG.js} +0 -0
- /package/dist/web/assets/{vitesse-light-Xg4wbeMO.js → vitesse-light-DgkIT-N7.js} +0 -0
- /package/dist/web/assets/{vyper-eW1NC3FG.js → vyper-D8cRDPp3.js} +0 -0
- /package/dist/web/assets/{wasm-BucxKwBZ.js → wasm-C02wlRbP.js} +0 -0
- /package/dist/web/assets/{wasm-Bhucqu1z.js → wasm-ClFJgzmT.js} +0 -0
- /package/dist/web/assets/{wenyan-BJFBuXuH.js → wenyan-B8plxIr8.js} +0 -0
- /package/dist/web/assets/{wgsl-6z4FUyMK.js → wgsl-CVujtm3V.js} +0 -0
- /package/dist/web/assets/{wikitext-BoDU6teJ.js → wikitext-CmcG9B69.js} +0 -0
- /package/dist/web/assets/{wit-DerMPpgt.js → wit--gl2Jium.js} +0 -0
- /package/dist/web/assets/{wolfram-D78v0Ap-.js → wolfram-6T_1D-NS.js} +0 -0
- /package/dist/web/assets/{x-YDu4m2Iq.js → x-CxoBA0po.js} +0 -0
- /package/dist/web/assets/{yaml-C4TIgIw4.js → yaml-CIVV9uA1.js} +0 -0
- /package/dist/web/assets/{zenscript-BydW-dLC.js → zenscript-CoT4yNdA.js} +0 -0
- /package/dist/web/assets/{zig-b9lTqL5E.js → zig-BWs2Qo3G.js} +0 -0
|
@@ -11,7 +11,7 @@ import { useSettingsStore } from "@/stores/settings-store";
|
|
|
11
11
|
import { usePanelStore } from "@/stores/panel-store";
|
|
12
12
|
import { useNotificationStore } from "@/stores/notification-store";
|
|
13
13
|
import { openBugReportPopup } from "@/lib/report-bug";
|
|
14
|
-
import { getAISettings } from "@/lib/api-settings";
|
|
14
|
+
import { getAISettings, pickAccountForTab } from "@/lib/api-settings";
|
|
15
15
|
import { MessageList } from "./message-list";
|
|
16
16
|
import { BackgroundCommandBar } from "./background-command-bar";
|
|
17
17
|
import { TeamWorkingBar } from "./team-working-bar";
|
|
@@ -104,14 +104,113 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
104
104
|
}).catch(() => {});
|
|
105
105
|
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
106
106
|
|
|
107
|
-
// Persist sessionId, providerId, and permissionMode to tab metadata
|
|
107
|
+
// Persist sessionId, providerId, and permissionMode to tab metadata.
|
|
108
|
+
//
|
|
109
|
+
// The claimed account is dropped at the same moment: once a session exists, its binding
|
|
110
|
+
// is the only account that matters, and it is the one the server re-routes when an
|
|
111
|
+
// account goes bad. Keeping the tab's copy alongside it would give the chip a second,
|
|
112
|
+
// staler answer to the same question.
|
|
108
113
|
useEffect(() => {
|
|
109
114
|
if (!tabId || !sessionId) return;
|
|
110
115
|
updateTab(tabId, {
|
|
111
|
-
metadata: {
|
|
116
|
+
metadata: {
|
|
117
|
+
...metadata,
|
|
118
|
+
sessionId,
|
|
119
|
+
providerId,
|
|
120
|
+
permissionMode,
|
|
121
|
+
pickedAccountId: undefined,
|
|
122
|
+
pickedAccountLabel: undefined,
|
|
123
|
+
pickedAccountProvider: undefined,
|
|
124
|
+
},
|
|
112
125
|
});
|
|
113
126
|
}, [sessionId, providerId, permissionMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
114
127
|
|
|
128
|
+
/** The account this tab claimed while it had no session yet, and who it was claimed from. */
|
|
129
|
+
const pickedAccountId = metadata?.pickedAccountId as string | undefined;
|
|
130
|
+
const pickedAccountLabel = metadata?.pickedAccountLabel as string | undefined;
|
|
131
|
+
const pickedAccountProvider = metadata?.pickedAccountProvider as string | undefined;
|
|
132
|
+
// A tab with no session can still switch provider, and accounts do not cross that line.
|
|
133
|
+
// Without this the claim from the old provider survives the switch and the chip names a
|
|
134
|
+
// Codex account on a Claude chat — confidently, and wrongly.
|
|
135
|
+
const claimMatchesProvider = Boolean(pickedAccountId) && pickedAccountProvider === providerId;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Claim an account the moment the tab opens, instead of at the first message.
|
|
139
|
+
*
|
|
140
|
+
* A tab with no session has no WebSocket and no row anywhere, so there is nothing
|
|
141
|
+
* server-side to hang this on. The tab's own metadata is the natural home: it is
|
|
142
|
+
* persisted with the panel layout, so the claim survives a reload, and it is discarded
|
|
143
|
+
* with the tab, which is exactly the lifetime asked for.
|
|
144
|
+
*
|
|
145
|
+
* Guarded on `pickedAccountId` being absent, not merely on having no session. Without
|
|
146
|
+
* that, every reload would claim a fresh account and the tab would keep changing its
|
|
147
|
+
* mind about who is answering. The claim is consumed — several tabs opened in a row
|
|
148
|
+
* deliberately spread across the pool, and are allowed to collide.
|
|
149
|
+
*/
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (!tabId || sessionId || claimMatchesProvider) return;
|
|
152
|
+
let cancelled = false;
|
|
153
|
+
pickAccountForTab(providerId)
|
|
154
|
+
.then((picked) => {
|
|
155
|
+
if (cancelled || !picked) return;
|
|
156
|
+
updateTab(tabId, {
|
|
157
|
+
metadata: {
|
|
158
|
+
...metadata,
|
|
159
|
+
pickedAccountId: picked.id,
|
|
160
|
+
pickedAccountLabel: picked.label,
|
|
161
|
+
pickedAccountProvider: providerId,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
})
|
|
165
|
+
.catch(() => { /* leave the chip blank rather than naming an account we did not get */ });
|
|
166
|
+
return () => { cancelled = true; };
|
|
167
|
+
}, [tabId, sessionId, providerId, claimMatchesProvider]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Move this chat onto an account the user picked in the panel.
|
|
171
|
+
*
|
|
172
|
+
* Two destinations, one for each half of a tab's life. Before the first message there is
|
|
173
|
+
* no session, so the choice replaces the tab's claim and is redeemed when the session is
|
|
174
|
+
* created. After that the session's binding is the only thing that decides, so it is
|
|
175
|
+
* written directly. Both end up in the same place — this is the same path the automatic
|
|
176
|
+
* route uses, not a parallel one.
|
|
177
|
+
*/
|
|
178
|
+
const handleSelectAccount = useCallback(async (accountId: string, label: string | null): Promise<string | null> => {
|
|
179
|
+
if (sessionId) {
|
|
180
|
+
try {
|
|
181
|
+
await api.put(`${projectUrl(projectName)}/chat/sessions/${sessionId}/account`, { accountId });
|
|
182
|
+
// Say it locally too. The panel marks the serving card from this state, and the only
|
|
183
|
+
// other source is the usage endpoint on a two-minute poll — so without this the badge
|
|
184
|
+
// sits on the old account long after the switch, which reads as the button not working.
|
|
185
|
+
setServingAccount({ id: accountId, label });
|
|
186
|
+
// Switching costs a full prompt-cache write, so it is worth saying out loud rather
|
|
187
|
+
// than letting the chip quietly change.
|
|
188
|
+
toast.success("This chat will use the selected account from the next message.");
|
|
189
|
+
} catch (e) {
|
|
190
|
+
// Returned rather than toasted: the panel shows it beside the cards, which is where
|
|
191
|
+
// the user just clicked and where the account they picked is still on screen.
|
|
192
|
+
return (e as Error).message || "Could not switch account";
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
if (!tabId) return null;
|
|
197
|
+
updateTab(tabId, {
|
|
198
|
+
metadata: { ...metadata, pickedAccountId: accountId, pickedAccountLabel: label, pickedAccountProvider: providerId },
|
|
199
|
+
});
|
|
200
|
+
return null;
|
|
201
|
+
}, [sessionId, projectName, tabId, metadata, providerId, updateTab]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* The account this chat is on, as far as the UI can tell.
|
|
205
|
+
*
|
|
206
|
+
* One piece of state with two writers, and last write wins — which is the right answer
|
|
207
|
+
* chronologically. The stream writes it whenever a turn reports who served (including a
|
|
208
|
+
* forced switch), and the manual picker writes it the moment the server accepts a choice.
|
|
209
|
+
* Deriving it instead from the polled usage endpoint is what made the badge lag two
|
|
210
|
+
* minutes behind a switch the user had just made.
|
|
211
|
+
*/
|
|
212
|
+
const [servingAccount, setServingAccount] = useState<{ id: string; label: string | null } | null>(null);
|
|
213
|
+
|
|
115
214
|
const {
|
|
116
215
|
messages,
|
|
117
216
|
renderedMessages,
|
|
@@ -130,6 +229,7 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
130
229
|
compactStatus,
|
|
131
230
|
statusMessage,
|
|
132
231
|
sessionTitle,
|
|
232
|
+
liveAccount,
|
|
133
233
|
model,
|
|
134
234
|
setModel,
|
|
135
235
|
effort,
|
|
@@ -150,6 +250,17 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
150
250
|
killBackgroundShell,
|
|
151
251
|
} = useChat(sessionId, providerId, projectName, handleSessionMigrated);
|
|
152
252
|
|
|
253
|
+
// The stream's report is the second writer. A turn that ran — or was forced onto another
|
|
254
|
+
// account mid-flight — is ground truth, and it arrives after whatever the picker last said.
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (liveAccount) setServingAccount(liveAccount);
|
|
257
|
+
}, [liveAccount]);
|
|
258
|
+
|
|
259
|
+
// A different conversation has a different account; carrying this one's over would label
|
|
260
|
+
// it wrongly until the next turn corrected it.
|
|
261
|
+
useEffect(() => { setServingAccount(null); }, [sessionId]);
|
|
262
|
+
|
|
263
|
+
|
|
153
264
|
// Teammates keep working long after their spawn card scrolled away — a resume
|
|
154
265
|
// arrives by SendMessage and writes no card at all. Poll the roster whenever this
|
|
155
266
|
// session has a team so the working bar below the conversation stays truthful.
|
|
@@ -429,6 +540,9 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
429
540
|
title: content.slice(0, 50),
|
|
430
541
|
// Set by /clear — the session only exists now, so persist the lineage here.
|
|
431
542
|
clearedFrom: metadata?.clearedFrom as string | undefined,
|
|
543
|
+
// The account this tab claimed on open and has been displaying since. Redeeming
|
|
544
|
+
// it here is what makes that display true rather than a guess.
|
|
545
|
+
accountId: pickedAccountId,
|
|
432
546
|
});
|
|
433
547
|
setSessionId(session.id);
|
|
434
548
|
setProviderId(session.providerId);
|
|
@@ -688,6 +802,9 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
688
802
|
lastFetchedAt={lastFetchedAt}
|
|
689
803
|
sessionId={sessionId}
|
|
690
804
|
providerId={providerId}
|
|
805
|
+
pickedAccountLabel={servingAccount?.label ?? (claimMatchesProvider ? pickedAccountLabel : null)}
|
|
806
|
+
pickedAccountId={servingAccount?.id ?? (claimMatchesProvider ? pickedAccountId ?? null : null)}
|
|
807
|
+
onSelectAccount={handleSelectAccount}
|
|
691
808
|
onSelectSession={handleSelectSession}
|
|
692
809
|
onBugReport={sessionId ? () => openBugReportPopup(version, { sessionId, projectName }) : undefined}
|
|
693
810
|
isConnected={isConnected}
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback } from "react";
|
|
2
2
|
import { X, Loader2, RefreshCw } from "lucide-react";
|
|
3
3
|
import { api } from "@/lib/api-client";
|
|
4
|
+
import { Switch } from "@/components/ui/switch";
|
|
5
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
|
4
6
|
import { AccountUsageBar } from "@/components/settings/accounts/account-bucket-row";
|
|
5
7
|
import { formatResetTime } from "@/components/settings/accounts/account-usage-format";
|
|
6
8
|
import type { UsageInfo } from "../../../types/chat";
|
|
7
9
|
|
|
8
|
-
interface CodexAccount { id: string; label: string; type: string; planType?: string | null }
|
|
10
|
+
interface CodexAccount { id: string; label: string; type: string; planType?: string | null; status?: "active" | "disabled" }
|
|
9
11
|
type Usage = Pick<UsageInfo, "fiveHour" | "sevenDay" | "session" | "weekly">;
|
|
10
12
|
|
|
13
|
+
/** Matches the whole-percent figure the bars show, so a refusal agrees with the card. */
|
|
14
|
+
function atCap(util: number | null | undefined): boolean {
|
|
15
|
+
return Math.round((util ?? 0) * 100) >= 100;
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
function UsageBar({ label, frac, bucket }: {
|
|
12
19
|
label: string;
|
|
13
20
|
frac?: number;
|
|
14
21
|
bucket?: UsageInfo["session"];
|
|
15
22
|
}) {
|
|
16
23
|
const pct = frac != null ? Math.round(frac * 100) : null;
|
|
17
|
-
return <AccountUsageBar label={label} pct={pct} reset={formatResetTime(bucket)} />;
|
|
24
|
+
return <AccountUsageBar label={label} pct={pct} reset={formatResetTime(bucket)} resetsAt={bucket?.resetsAt} />;
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
/** Read-only usage panel opened from the chat toolbar badge (Claude parity).
|
|
@@ -22,15 +29,58 @@ function UsageBar({ label, frac, bucket }: {
|
|
|
22
29
|
* accounts exist, chats run on the ambient ~/.codex login — its usage comes
|
|
23
30
|
* from the session `usage` prop. Login/management lives in Settings → AI
|
|
24
31
|
* Provider → Codex. */
|
|
25
|
-
export function CodexUsagePanel({ onClose, usage, onReload }: {
|
|
32
|
+
export function CodexUsagePanel({ onClose, usage, onReload, onSelectAccount, selectedAccountId }: {
|
|
26
33
|
onClose: () => void;
|
|
27
34
|
usage: UsageInfo;
|
|
28
35
|
/** Forces the chat usage endpoint to bypass its provider-usage cache. */
|
|
29
36
|
onReload?: () => void | Promise<void>;
|
|
37
|
+
/** Route this chat onto another Codex account. */
|
|
38
|
+
onSelectAccount?: (accountId: string, label: string | null) => Promise<string | null>;
|
|
39
|
+
/** Account currently claimed or bound for this chat. */
|
|
40
|
+
selectedAccountId?: string | null;
|
|
30
41
|
}) {
|
|
31
42
|
const [accounts, setAccounts] = useState<CodexAccount[]>([]);
|
|
32
43
|
const [usages, setUsages] = useState<Record<string, Usage>>({});
|
|
33
44
|
const [loading, setLoading] = useState(false);
|
|
45
|
+
const [selectingId, setSelectingId] = useState<string | null>(null);
|
|
46
|
+
const [togglingId, setTogglingId] = useState<string | null>(null);
|
|
47
|
+
const [toggleError, setToggleError] = useState<string | null>(null);
|
|
48
|
+
|
|
49
|
+
// This panel draws its own cards rather than reusing Settings' AccountCard, so the
|
|
50
|
+
// selection control is rebuilt here. Kept visually the same as the Claude panel's on
|
|
51
|
+
// purpose — the two sub-tabs drifting apart is the thing the shared Settings layout was
|
|
52
|
+
// introduced to stop, and a differently-shaped button here would start it again.
|
|
53
|
+
const select = useCallback(async (id: string, label: string, refused: string | null) => {
|
|
54
|
+
if (!onSelectAccount) return;
|
|
55
|
+
// Refuse here rather than leaving the button inert: the user pressed something and is
|
|
56
|
+
// owed the reason. The server checks again, which catches an account that became
|
|
57
|
+
// unusable between this render and the click.
|
|
58
|
+
if (refused) { setToggleError(`Cannot switch to this account — ${refused}`); return; }
|
|
59
|
+
setSelectingId(id);
|
|
60
|
+
setToggleError(null);
|
|
61
|
+
try { setToggleError((await onSelectAccount(id, label)) ?? null); } finally { setSelectingId(null); }
|
|
62
|
+
}, [onSelectAccount]);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Switch a Codex account on or off without leaving the chat.
|
|
66
|
+
*
|
|
67
|
+
* No pending-token dance like the Claude side: the Codex route answers immediately because
|
|
68
|
+
* there is no refresh token to prove. The pending id is still tracked so the switch cannot
|
|
69
|
+
* be double-fired on a slow connection.
|
|
70
|
+
*/
|
|
71
|
+
const toggle = useCallback(async (id: string, status: string) => {
|
|
72
|
+
setTogglingId(id);
|
|
73
|
+
setToggleError(null);
|
|
74
|
+
try {
|
|
75
|
+
await api.patch(`/api/codex-accounts/${id}`, { status: status === "disabled" ? "active" : "disabled" });
|
|
76
|
+
const d = await api.get<{ accounts: CodexAccount[] }>("/api/codex-accounts");
|
|
77
|
+
setAccounts(d.accounts);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
setToggleError((e as Error).message || "Could not change the account");
|
|
80
|
+
} finally {
|
|
81
|
+
setTogglingId(null);
|
|
82
|
+
}
|
|
83
|
+
}, []);
|
|
34
84
|
|
|
35
85
|
const load = useCallback(async () => {
|
|
36
86
|
setLoading(true);
|
|
@@ -59,19 +109,42 @@ export function CodexUsagePanel({ onClose, usage, onReload }: {
|
|
|
59
109
|
<div className="flex items-center justify-between">
|
|
60
110
|
<span className="text-xs font-semibold text-text-primary">Codex Usage</span>
|
|
61
111
|
<div className="flex items-center gap-1">
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
112
|
+
<Tooltip>
|
|
113
|
+
<TooltipTrigger asChild>
|
|
114
|
+
<button
|
|
115
|
+
onClick={reload}
|
|
116
|
+
disabled={loading}
|
|
117
|
+
className="text-text-subtle hover:text-text-primary px-1 cursor-pointer disabled:opacity-50"
|
|
118
|
+
aria-label="Refresh usage"
|
|
119
|
+
>
|
|
120
|
+
<RefreshCw className={`size-3 ${loading ? "animate-spin" : ""}`} />
|
|
121
|
+
</button>
|
|
122
|
+
</TooltipTrigger>
|
|
123
|
+
<TooltipContent side="top">Refresh</TooltipContent>
|
|
124
|
+
</Tooltip>
|
|
125
|
+
<Tooltip>
|
|
126
|
+
<TooltipTrigger asChild>
|
|
127
|
+
<button
|
|
128
|
+
onClick={onClose}
|
|
129
|
+
className="text-text-subtle hover:text-text-primary px-1 cursor-pointer"
|
|
130
|
+
aria-label="Close usage panel"
|
|
131
|
+
>
|
|
132
|
+
<X className="size-3" />
|
|
133
|
+
</button>
|
|
134
|
+
</TooltipTrigger>
|
|
135
|
+
<TooltipContent side="top">Close</TooltipContent>
|
|
136
|
+
</Tooltip>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
{toggleError && (
|
|
141
|
+
<div className="flex items-start gap-2 rounded border border-error/40 bg-error/10 px-2 py-1.5 text-[11px] text-error">
|
|
142
|
+
<span className="flex-1">{toggleError}</span>
|
|
143
|
+
<button onClick={() => setToggleError(null)} className="shrink-0 text-error/70 hover:text-error cursor-pointer" aria-label="Dismiss">
|
|
71
144
|
<X className="size-3" />
|
|
72
145
|
</button>
|
|
73
146
|
</div>
|
|
74
|
-
|
|
147
|
+
)}
|
|
75
148
|
|
|
76
149
|
{loading && accounts.length === 0 && (
|
|
77
150
|
<div className="text-xs text-text-subtle flex items-center gap-2"><Loader2 className="size-3 animate-spin" /> Loading…</div>
|
|
@@ -94,12 +167,57 @@ export function CodexUsagePanel({ onClose, usage, onReload }: {
|
|
|
94
167
|
|
|
95
168
|
{accounts.map((a) => {
|
|
96
169
|
const u = usages[a.id] ?? {};
|
|
170
|
+
const isServing = a.id === (selectedAccountId ?? usage.activeAccountId);
|
|
171
|
+
// Reached, not approaching: an account at 96% still answers, one at 100% does not.
|
|
172
|
+
const refused = a.status === "disabled"
|
|
173
|
+
? "it is switched off."
|
|
174
|
+
: atCap(u.fiveHour)
|
|
175
|
+
? "it has reached its 5-hour limit."
|
|
176
|
+
: atCap(u.sevenDay)
|
|
177
|
+
? "it has reached its weekly limit."
|
|
178
|
+
: null;
|
|
97
179
|
return (
|
|
98
|
-
<div
|
|
180
|
+
<div
|
|
181
|
+
key={a.id}
|
|
182
|
+
className={`rounded-md border bg-surface/40 p-2.5 space-y-2 ${isServing ? "border-primary/30 bg-primary/5" : "border-border/50"}`}
|
|
183
|
+
>
|
|
99
184
|
<div className="flex items-center gap-2">
|
|
100
185
|
<span className="text-sm text-text-primary truncate flex-1 min-w-0">{a.label}</span>
|
|
186
|
+
{isServing && <span className="text-[10px] text-primary shrink-0 font-medium">Active</span>}
|
|
187
|
+
{/* Same slot as the Active badge, so every card keeps one header row and the
|
|
188
|
+
panel does not grow taller just to carry a button. */}
|
|
189
|
+
{onSelectAccount && !isServing && (
|
|
190
|
+
<Tooltip>
|
|
191
|
+
<TooltipTrigger asChild>
|
|
192
|
+
<button
|
|
193
|
+
type="button"
|
|
194
|
+
onClick={() => select(a.id, a.label, refused)}
|
|
195
|
+
disabled={selectingId === a.id}
|
|
196
|
+
className={[
|
|
197
|
+
"shrink-0 rounded px-1.5 py-0.5 text-[10px] font-medium transition-colors cursor-pointer disabled:cursor-wait",
|
|
198
|
+
refused
|
|
199
|
+
? "text-text-subtle hover:text-error hover:bg-error/10"
|
|
200
|
+
: "text-text-secondary hover:text-foreground hover:bg-surface-elevated",
|
|
201
|
+
].join(" ")}
|
|
202
|
+
>
|
|
203
|
+
{selectingId === a.id ? "Switching…" : "Use"}
|
|
204
|
+
</button>
|
|
205
|
+
</TooltipTrigger>
|
|
206
|
+
<TooltipContent side="top">
|
|
207
|
+
{refused ? `Cannot use this account — ${refused}` : "Use this account for this chat"}
|
|
208
|
+
</TooltipContent>
|
|
209
|
+
</Tooltip>
|
|
210
|
+
)}
|
|
211
|
+
{a.status === "disabled" && <span className="text-[10px] text-text-subtle shrink-0">Off</span>}
|
|
101
212
|
<span className="text-[10px] uppercase tracking-wide text-text-subtle border border-border rounded px-1">{a.type}</span>
|
|
102
213
|
{a.planType && <span className="text-[10px] text-text-subtle">{a.planType}</span>}
|
|
214
|
+
<Switch
|
|
215
|
+
checked={a.status !== "disabled"}
|
|
216
|
+
onCheckedChange={() => void toggle(a.id, a.status ?? "active")}
|
|
217
|
+
disabled={togglingId === a.id}
|
|
218
|
+
aria-label={a.status === "disabled" ? "Enable account" : "Disable account"}
|
|
219
|
+
className="cursor-pointer shrink-0"
|
|
220
|
+
/>
|
|
103
221
|
</div>
|
|
104
222
|
<UsageBar label="5-Hour" frac={u.fiveHour} bucket={u.session} />
|
|
105
223
|
<UsageBar label="Weekly" frac={u.sevenDay} bucket={u.weekly} />
|
|
@@ -22,16 +22,23 @@ export default function EditDiffPreview({ oldStr, newStr, filePath, maxLines = 1
|
|
|
22
22
|
[oldStr, newStr, maxLines],
|
|
23
23
|
);
|
|
24
24
|
|
|
25
|
+
// The `{ __html }` objects live inside the memo on purpose. React 19 compares that prop by
|
|
26
|
+
// identity, not by the string inside, so an inline `{{ __html: html }}` re-parses and
|
|
27
|
+
// rebuilds every line's subtree on every render of this card — and a card re-renders on
|
|
28
|
+
// each flush of the streaming turn it sits in. Measured at ~20 identical rewrites per line
|
|
29
|
+
// per turn (tests/e2e/chat-dom-leak-trace.mjs), all of it garbage for the DOM allocator.
|
|
25
30
|
const lines = useMemo(
|
|
26
31
|
() =>
|
|
27
32
|
rows.map((row) => ({
|
|
28
33
|
row,
|
|
29
|
-
html:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
html: {
|
|
35
|
+
__html: renderLine(
|
|
36
|
+
row.text,
|
|
37
|
+
language,
|
|
38
|
+
row.kind === "equal" ? [] : row.ranges,
|
|
39
|
+
row.kind === "del" ? "bg-diff-removed-word" : "bg-diff-added-word",
|
|
40
|
+
),
|
|
41
|
+
},
|
|
35
42
|
})),
|
|
36
43
|
[rows, language],
|
|
37
44
|
);
|
|
@@ -51,7 +58,7 @@ export default function EditDiffPreview({ oldStr, newStr, filePath, maxLines = 1
|
|
|
51
58
|
<span className={`select-none shrink-0 w-3 pl-1.5 ${s.gutter}`}>{s.prefix}</span>
|
|
52
59
|
<code
|
|
53
60
|
className="whitespace-pre-wrap break-all text-text-primary pr-1.5"
|
|
54
|
-
dangerouslySetInnerHTML={
|
|
61
|
+
dangerouslySetInnerHTML={html}
|
|
55
62
|
/>
|
|
56
63
|
</div>
|
|
57
64
|
);
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Floating-window body replaying one teammate's whole work session.
|
|
2
|
+
* Floating-window body replaying one teammate's whole work session, live.
|
|
3
3
|
*
|
|
4
4
|
* The transcript is fetched on demand and only for the member being opened —
|
|
5
5
|
* a single teammate transcript reaches several MB, so loading all of a team's
|
|
6
|
-
* transcripts up front is not an option
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* transcripts up front is not an option, and following one means tailing it by
|
|
7
|
+
* byte offset rather than re-reading it (`useMemberTranscriptTail`). Steps
|
|
8
|
+
* render through the same `SubagentChildren` view the inline Agent card uses,
|
|
9
|
+
* so a teammate's session looks identical wherever it is read.
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
|
-
import { useEffect, useState } from "react";
|
|
12
12
|
import { Loader2, RefreshCw } from "lucide-react";
|
|
13
|
-
import { api } from "@/lib/api-client";
|
|
14
13
|
import { cn } from "@/lib/utils";
|
|
15
|
-
import
|
|
14
|
+
import { useMemberTranscriptTail } from "@/hooks/use-member-transcript-tail";
|
|
16
15
|
import type { WindowContentProps } from "@/components/floating-window/window-content-registry";
|
|
17
16
|
import { SubagentChildren } from "./tool-cards";
|
|
18
17
|
|
|
@@ -25,37 +24,7 @@ export interface TeamMemberWindowPayload {
|
|
|
25
24
|
|
|
26
25
|
export default function TeamMemberWindowContent({ payload }: WindowContentProps) {
|
|
27
26
|
const { teamName, memberName, projectName } = (payload ?? {}) as unknown as TeamMemberWindowPayload;
|
|
28
|
-
const
|
|
29
|
-
const [loading, setLoading] = useState(true);
|
|
30
|
-
const [error, setError] = useState<string | null>(null);
|
|
31
|
-
// Bumped by the refresh button; a working teammate keeps appending steps.
|
|
32
|
-
const [reloadKey, setReloadKey] = useState(0);
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
if (!teamName || !memberName) {
|
|
36
|
-
setError("Missing team or member");
|
|
37
|
-
setLoading(false);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
let cancelled = false;
|
|
41
|
-
setLoading(true);
|
|
42
|
-
setError(null);
|
|
43
|
-
api
|
|
44
|
-
.get<{ events?: ChatEvent[] }>(
|
|
45
|
-
`/api/teams/${encodeURIComponent(teamName)}/members/${encodeURIComponent(memberName)}/transcript`,
|
|
46
|
-
)
|
|
47
|
-
.then((res) => {
|
|
48
|
-
if (cancelled) return;
|
|
49
|
-
setEvents(res?.events ?? []);
|
|
50
|
-
})
|
|
51
|
-
.catch(() => {
|
|
52
|
-
if (!cancelled) setError("Could not read this member's session");
|
|
53
|
-
})
|
|
54
|
-
.finally(() => {
|
|
55
|
-
if (!cancelled) setLoading(false);
|
|
56
|
-
});
|
|
57
|
-
return () => { cancelled = true; };
|
|
58
|
-
}, [teamName, memberName, reloadKey]);
|
|
27
|
+
const { events, loading, error, refresh } = useMemberTranscriptTail(teamName, memberName);
|
|
59
28
|
|
|
60
29
|
return (
|
|
61
30
|
<div className="flex flex-col h-full min-h-0 bg-surface">
|
|
@@ -66,7 +35,7 @@ export default function TeamMemberWindowContent({ payload }: WindowContentProps)
|
|
|
66
35
|
</span>
|
|
67
36
|
<button
|
|
68
37
|
type="button"
|
|
69
|
-
onClick={
|
|
38
|
+
onClick={refresh}
|
|
70
39
|
className="ml-auto text-text-subtle hover:text-foreground p-1 shrink-0"
|
|
71
40
|
aria-label="Reload session"
|
|
72
41
|
>
|