@hienlh/ppm 0.19.12 → 0.20.0

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.
Files changed (535) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/CLAUDE.md +8 -1
  3. package/assets/skills/ppm/SKILL.md +1 -1
  4. package/assets/skills/ppm/references/http-api.md +4 -1
  5. package/dist/web/assets/accounts-settings-section-BQyru31C.js +1 -0
  6. package/dist/web/assets/{ai-resource-editor-CqL-X2zu.js → ai-resource-editor-BgYIPGVP.js} +1 -1
  7. package/dist/web/assets/{ai-settings-section-CcqokdzF.js → ai-settings-section-Cywmtnps.js} +1 -1
  8. package/dist/web/assets/ai-settings-section-iBRCQvBR.js +1 -0
  9. package/dist/web/assets/{angular-html-C8nsn2VC.js → angular-html-BtJLNcMw.js} +1 -1
  10. package/dist/web/assets/{angular-ts-Caw9nRCH.js → angular-ts-CQiu5F_W.js} +1 -1
  11. package/dist/web/assets/api-client-QfreGirP.js +1 -0
  12. package/dist/web/assets/api-settings-D18Q4Ocp.js +1 -0
  13. package/dist/web/assets/{api-themes-BoOJPqwM.js → api-themes-sSv-6OLk.js} +1 -1
  14. package/dist/web/assets/{apl-Dhu1LORF.js → apl-CKZvgs-w.js} +1 -1
  15. package/dist/web/assets/{appearance-settings-section-2hZBnpPS.js → appearance-settings-section-mhu9T6Fk.js} +1 -1
  16. package/dist/web/assets/architecture-PBZL5I3N-DfR8k8Bc.js +1 -0
  17. package/dist/web/assets/{astro-DwkX9sLZ.js → astro-D0b8ssLD.js} +1 -1
  18. package/dist/web/assets/{audio-preview-CkGZO8Uy.js → audio-preview-B4E5_7TW.js} +1 -1
  19. package/dist/web/assets/{blade-D1fC9Osx.js → blade-DOIpINLw.js} +1 -1
  20. package/dist/web/assets/{bsl-pur-PRip.js → bsl-CJ7_JlQ8.js} +1 -1
  21. package/dist/web/assets/{button-2WCAS8dI.js → button-DX32ffge.js} +1 -1
  22. package/dist/web/assets/{cairo-DDJs9amR.js → cairo-5CpV2T1P.js} +1 -1
  23. package/dist/web/assets/chat-tab-Bs9OD6ss.js +15 -0
  24. package/dist/web/assets/{cobol-Bo0usdoM.js → cobol-BreMVrtc.js} +1 -1
  25. package/dist/web/assets/code-editor-Cv_pzHo7.js +7 -0
  26. package/dist/web/assets/{coffee-DBBsbX1e.js → coffee-D7DoKh5b.js} +1 -1
  27. package/dist/web/assets/{conflict-editor-NqFAJP47.js → conflict-editor-BnWaMSEa.js} +1 -1
  28. package/dist/web/assets/{context-menu-C13b1uT3.js → context-menu-CJL8L98s.js} +1 -1
  29. package/dist/web/assets/{cpp-6CTO78A-.js → cpp-BnWeWAoE.js} +1 -1
  30. package/dist/web/assets/{crystal-DAlvpAP7.js → crystal-D2pJbFUn.js} +1 -1
  31. package/dist/web/assets/{csv-preview-Dvriy18_.js → csv-preview-DG4YAabr.js} +1 -1
  32. package/dist/web/assets/{data-grid-overlay-editor-iRrpAV0e.js → data-grid-overlay-editor-CbBkhhJa.js} +1 -1
  33. package/dist/web/assets/{database-viewer-Bs2RMm5a.js → database-viewer-B-wA2qT-.js} +1 -1
  34. package/dist/web/assets/diff-viewer-DRtzdfXk.js +4 -0
  35. package/dist/web/assets/{docx-preview-Bgw838ry.js → docx-preview-Xy7SZ7Vf.js} +1 -1
  36. package/dist/web/assets/{edge-D0tZrpC7.js → edge-aqGMtbY3.js} +1 -1
  37. package/dist/web/assets/{edit-diff-preview-DUgmjNre.js → edit-diff-preview-6tzdk7Pn.js} +1 -1
  38. package/dist/web/assets/{elixir-C1E6-o4G.js → elixir-CsYMBLc5.js} +1 -1
  39. package/dist/web/assets/{elm-BKyTfeQX.js → elm-BU8C2gFp.js} +1 -1
  40. package/dist/web/assets/{erb-Cdnr4BMI.js → erb-Z_E49ab8.js} +1 -1
  41. package/dist/web/assets/{erlang-N1237mFq.js → erlang-BRqOjXH9.js} +1 -1
  42. package/dist/web/assets/{esm-ClNnmD9t.js → esm-B-vXxHUd.js} +1 -1
  43. package/dist/web/assets/{explorer-body-DfWunSf9.js → explorer-body-uh8oJp6J.js} +2 -2
  44. package/dist/web/assets/explorer-window-content-DLn_4egF.js +1 -0
  45. package/dist/web/assets/{extension-manager-section-Zc9yag2c.js → extension-manager-section-C_ZGYvWf.js} +1 -1
  46. package/dist/web/assets/{extension-webview-B5FayDPz.js → extension-webview-DbFWxJpj.js} +1 -1
  47. package/dist/web/assets/{files-settings-section-CxAtO3GL.js → files-settings-section-BrUbJglA.js} +1 -1
  48. package/dist/web/assets/{fortran-fixed-form-D_f9tVv0.js → fortran-fixed-form-CWbxmDGR.js} +1 -1
  49. package/dist/web/assets/{fsharp-DEJmdhc2.js → fsharp-DKMYbq6I.js} +1 -1
  50. package/dist/web/assets/{gdresource-Dmmrx2gP.js → gdresource-B3yFau4V.js} +1 -1
  51. package/dist/web/assets/{general-settings-section-9DfKrBns.js → general-settings-section-B9ZPZVso.js} +1 -1
  52. package/dist/web/assets/{git-commit-qwJ867ig.js → git-commit-BW0p3Ekk.js} +1 -1
  53. package/dist/web/assets/{git-log-panel-BsmDZurR.js → git-log-panel-C0jnhmgC.js} +1 -1
  54. package/dist/web/assets/{git-rebase-Dkv8Zw86.js → git-rebase-DrvmQCS7.js} +1 -1
  55. package/dist/web/assets/gitGraph-HDMCJU4V-CPd78aaT.js +1 -0
  56. package/dist/web/assets/{glide-data-grid-BuYwXIoS.js → glide-data-grid-CZVKIum-.js} +6 -6
  57. package/dist/web/assets/{glimmer-js-CcrXn8lQ.js → glimmer-js-BY1XApJJ.js} +1 -1
  58. package/dist/web/assets/{glimmer-ts-CLab3lU7.js → glimmer-ts-DPZtxF8N.js} +1 -1
  59. package/dist/web/assets/{glsl-DXhkG9dU.js → glsl-DZ8G_Hvf.js} +1 -1
  60. package/dist/web/assets/{graphql-Cuqsx8r3.js → graphql-Ck06uCZy.js} +1 -1
  61. package/dist/web/assets/group-chat-tab-DnPtmbPc.js +1 -0
  62. package/dist/web/assets/{hack-C_CBVdBc.js → hack-pLogDwAs.js} +1 -1
  63. package/dist/web/assets/{haml-CBWfzZpv.js → haml-CBqeCQ2A.js} +1 -1
  64. package/dist/web/assets/{handlebars-4e8OR-VI.js → handlebars-B66JmVtp.js} +1 -1
  65. package/dist/web/assets/{html-C5X4urn_.js → html-Dk4wmfwC.js} +1 -1
  66. package/dist/web/assets/{html-derivative-nH-jXfsL.js → html-derivative-CJWqfN51.js} +1 -1
  67. package/dist/web/assets/{http-CQgaG7eu.js → http-CexhotTh.js} +1 -1
  68. package/dist/web/assets/{hurl-B8gidJhu.js → hurl-BScKFk3Z.js} +1 -1
  69. package/dist/web/assets/{hxml-BAK94GX8.js → hxml-DAle7vtu.js} +1 -1
  70. package/dist/web/assets/{image-preview-1kGj4W9R.js → image-preview-fuU4h2nr.js} +1 -1
  71. package/dist/web/assets/index-CHQAPZIX.js +52 -0
  72. package/dist/web/assets/index-CoaVwAF6.css +2 -0
  73. package/dist/web/assets/info-3K5VOQVL-BciNds6R.js +1 -0
  74. package/dist/web/assets/{jinja-BuAjvj8M.js → jinja-yHpyD80t.js} +1 -1
  75. package/dist/web/assets/{jira-watcher-section-rJVz40wR.js → jira-watcher-section-Bjldyhru.js} +1 -1
  76. package/dist/web/assets/{jison-Dhhs26-L.js → jison-BY6WLJVu.js} +1 -1
  77. package/dist/web/assets/{julia-gZavIyll.js → julia-Dd_iYQDT.js} +1 -1
  78. package/dist/web/assets/{just-DDHrFReO.js → just-BTuUKpxF.js} +1 -1
  79. package/dist/web/assets/keybindings-store-DBVXZKp8.js +1 -0
  80. package/dist/web/assets/{keyboard-shortcuts-section-Dv4e3M8h.js → keyboard-shortcuts-section-D7jaCPrv.js} +1 -1
  81. package/dist/web/assets/{latex-BdGZa8ov.js → latex-Dt3OUlMZ.js} +1 -1
  82. package/dist/web/assets/{liquid-urFfd9Fr.js → liquid-BxPJU2ix.js} +1 -1
  83. package/dist/web/assets/{lua-CcS6tnB5.js → lua-DEGIvn7d.js} +1 -1
  84. package/dist/web/assets/{markdown-renderer-CEloCR06.js → markdown-renderer-B4B5oxQS.js} +3 -3
  85. package/dist/web/assets/markdown-renderer-DwHh-jd_.js +1 -0
  86. package/dist/web/assets/{marko-CSQqk4oG.js → marko-BDxwBJur.js} +1 -1
  87. package/dist/web/assets/{mdc-CYIe80m_.js → mdc-B8aXPTg7.js} +1 -1
  88. package/dist/web/assets/{media-url-DBmHJRft.js → media-url-BMeBaB0q.js} +1 -1
  89. package/dist/web/assets/{mobile-bottom-sheet-B3uDlD79.js → mobile-bottom-sheet-CmySDB6I.js} +1 -1
  90. package/dist/web/assets/mobile-explorer-sheet-JJxZYWkV.js +1 -0
  91. package/dist/web/assets/{nextflow-C-W8vX8I.js → nextflow-DBVZnnT_.js} +1 -1
  92. package/dist/web/assets/{nginx-COGi5you.js → nginx-Crpyd-Do.js} +1 -1
  93. package/dist/web/assets/{nim-CPitYGel.js → nim-BSqTBYDj.js} +1 -1
  94. package/dist/web/assets/notification-store-CCWNUHsS.js +1 -0
  95. package/dist/web/assets/{notifications-settings-section-B2GkfB0l.js → notifications-settings-section-DbbX7-Qp.js} +1 -1
  96. package/dist/web/assets/{number-overlay-editor-C_eD-Bdr.js → number-overlay-editor-DRjTIcPH.js} +1 -1
  97. package/dist/web/assets/{overview-panel-Cm2HRtEz.js → overview-panel-DiiA3B_Z.js} +1 -1
  98. package/dist/web/assets/packet-RMMSAZCW-ClD3l2Bs.js +1 -0
  99. package/dist/web/assets/{panel-store-BRrnDO_i.js → panel-store-BmdcSBNb.js} +1 -1
  100. package/dist/web/assets/{pdf-preview-Dmz8jkZZ.js → pdf-preview-DxNjWa1v.js} +1 -1
  101. package/dist/web/assets/{perl-B0yW3hbb.js → perl-BU0kbB-K.js} +1 -1
  102. package/dist/web/assets/{php-BNMYN5Jp.js → php-D9n1ikHN.js} +1 -1
  103. package/dist/web/assets/pie-UPGHQEXC-PU6kD0rW.js +1 -0
  104. package/dist/web/assets/{postgres-viewer-BtZbfC3f.js → postgres-viewer-BScvk5ev.js} +3 -3
  105. package/dist/web/assets/{ppmbot-settings-section-OYfVG5-l.js → ppmbot-settings-section-jFA9Ncgo.js} +1 -1
  106. package/dist/web/assets/{process-table-DRu3NyO_.js → process-table-BexeYWQm.js} +1 -1
  107. package/dist/web/assets/{project-store-BuY7rxn_.js → project-store-wWZ6bjwq.js} +1 -1
  108. package/dist/web/assets/{proxy-settings-section-xMbrcyr8.js → proxy-settings-section-C_seKq56.js} +1 -1
  109. package/dist/web/assets/{pug-CP5fxsxD.js → pug-BOpaczDr.js} +1 -1
  110. package/dist/web/assets/{qml-CHGpQosY.js → qml-B-cQXhrg.js} +1 -1
  111. package/dist/web/assets/{query-audit-section-CC5Mf6qp.js → query-audit-section-BWXJmPDV.js} +1 -1
  112. package/dist/web/assets/radar-KQ55EAFF-4LzjL0Zt.js +1 -0
  113. package/dist/web/assets/{razor-Cfe0AYo4.js → razor-DFB0pNCh.js} +1 -1
  114. package/dist/web/assets/remote-desktop-mobile-sheet-B--PeL5i.js +2 -0
  115. package/dist/web/assets/{remote-desktop-mobile-view-B4BSHIxU.js → remote-desktop-mobile-view-jgn8nmQa.js} +1 -1
  116. package/dist/web/assets/{remote-desktop-readiness-gate-C0d0PSX4.js → remote-desktop-readiness-gate-CjDth-W_.js} +1 -1
  117. package/dist/web/assets/{remote-desktop-window-content-DjeCZzqq.js → remote-desktop-window-content-CrHAUA03.js} +1 -1
  118. package/dist/web/assets/{rst-DxSSGshb.js → rst-DAXedsgm.js} +1 -1
  119. package/dist/web/assets/{ruby-rbK5SsJa.js → ruby-BCO4polC.js} +1 -1
  120. package/dist/web/assets/{run-in-terminal-DHAvC1AG.js → run-in-terminal-wHKwAnWP.js} +1 -1
  121. package/dist/web/assets/{sas-DDM28fbb.js → sas-DfB5dcFC.js} +1 -1
  122. package/dist/web/assets/schedules-settings-section-DMFn3mYL.js +1 -0
  123. package/dist/web/assets/{scss-TDl-6ro4.js → scss-BknIVgn7.js} +1 -1
  124. package/dist/web/assets/{send-to-chat-BOyUWNKw.js → send-to-chat-BI7-fFpG.js} +1 -1
  125. package/dist/web/assets/{separator-BzGoTlR7.js → separator-W_hJcXPk.js} +1 -1
  126. package/dist/web/assets/{settings-body-CXTQwhbM.js → settings-body-Dz2vPTEP.js} +2 -2
  127. package/dist/web/assets/settings-store-CzLnTR8p.js +2 -0
  128. package/dist/web/assets/settings-tab-B5QbsvS4.js +1 -0
  129. package/dist/web/assets/settings-window-content-iM2bPoX5.js +1 -0
  130. package/dist/web/assets/{shaderlab-CCvmDgGS.js → shaderlab-CPu31TpY.js} +1 -1
  131. package/dist/web/assets/{shellsession-BzKS9yKh.js → shellsession-CFX4c_TM.js} +1 -1
  132. package/dist/web/assets/{soy-QfO35nDh.js → soy-rz9hilgm.js} +1 -1
  133. package/dist/web/assets/{sparql-D29RDfp2.js → sparql-Bo8ZDeqE.js} +1 -1
  134. package/dist/web/assets/{sql-query-editor-B-VwfyTf.js → sql-query-editor-C0mGgLfX.js} +1 -1
  135. package/dist/web/assets/{sqlite-viewer-CpUhDEhN.js → sqlite-viewer-Bs3RKf1X.js} +1 -1
  136. package/dist/web/assets/{stata-Be6j_SNv.js → stata-B5J-QMyE.js} +1 -1
  137. package/dist/web/assets/{streaming-store-9_9j70zt.js → streaming-store-9XVmAMfV.js} +1 -1
  138. package/dist/web/assets/{surrealql-CykFjgNG.js → surrealql-Caw1ADnG.js} +1 -1
  139. package/dist/web/assets/{svelte-CdBF8z4-.js → svelte-D3oMVcxz.js} +1 -1
  140. package/dist/web/assets/{system-monitor-body-DzWXd1wM.js → system-monitor-body-DvUmEdNe.js} +2 -2
  141. package/dist/web/assets/system-monitor-tab-CHZ5F_ZE.js +1 -0
  142. package/dist/web/assets/{system-monitor-window-content-DIIP3dff.js → system-monitor-window-content-DjzqoeCN.js} +1 -1
  143. package/dist/web/assets/{tab-host-window-content-CLdcz84K.js → tab-host-window-content-DKeAr5mD.js} +1 -1
  144. package/dist/web/assets/{tab-store-PZsP5ZwG.js → tab-store-1xYJb0gM.js} +1 -1
  145. package/dist/web/assets/team-member-sheet-Cl9ZB3dl.js +2 -0
  146. package/dist/web/assets/team-member-window-content-DfP7WdFD.js +1 -0
  147. package/dist/web/assets/{templ-BVHE2CNb.js → templ-BAdNyIOL.js} +1 -1
  148. package/dist/web/assets/{terminal-tab-BeKLpaPM.js → terminal-tab-J1Fqa_rm.js} +2 -2
  149. package/dist/web/assets/{tex-C8XwrbBw.js → tex-IQ8mELOR.js} +1 -1
  150. package/dist/web/assets/tool-cards-DQghSuKX.js +9 -0
  151. package/dist/web/assets/treemap-KZPCXAKY-DiumLNMg.js +1 -0
  152. package/dist/web/assets/{ts-tags-BIHk5AM0.js → ts-tags-D1DDO2jl.js} +1 -1
  153. package/dist/web/assets/{twig-YcE6Q2Ox.js → twig-C8Fd5RvV.js} +1 -1
  154. package/dist/web/assets/use-accounts-data-KWcMgRlc.js +1 -0
  155. package/dist/web/assets/{use-blob-url-De-ZtcpX.js → use-blob-url-CrwoZJUJ.js} +1 -1
  156. package/dist/web/assets/use-inline-blame-C1G-_NjC.js +8 -0
  157. package/dist/web/assets/{use-monaco-theme-Kj2OGDlm.js → use-monaco-theme-aa4-wjKQ.js} +1 -1
  158. package/dist/web/assets/{use-open-team-member-DWhhWdmJ.js → use-open-team-member-CSUU7Z8N.js} +1 -1
  159. package/dist/web/assets/{use-remote-desktop-display-choice-8AkPpM_0.js → use-remote-desktop-display-choice-B-TpQ-Ua.js} +1 -1
  160. package/dist/web/assets/{use-websocket-kR1omKO1.js → use-websocket-BBslmv3D.js} +1 -1
  161. package/dist/web/assets/{vendor-mermaid-CKKtYuTV.js → vendor-mermaid-CfY1-PkA.js} +1 -1
  162. package/dist/web/assets/{video-preview-BdV7LjbZ.js → video-preview-Bd0lcK3d.js} +1 -1
  163. package/dist/web/assets/{vue-q7m01V0h.js → vue-EvccXlkP.js} +1 -1
  164. package/dist/web/assets/{vue-html-D1y9feOj.js → vue-html-Dg0xUJCh.js} +1 -1
  165. package/dist/web/assets/{vue-vine-DrIGs03v.js → vue-vine-BdrMg72k.js} +1 -1
  166. package/dist/web/assets/{window-pip-registry-CSLhJfpL.js → window-pip-registry-CrCYYTTf.js} +1 -1
  167. package/dist/web/assets/{window-store-DGKf9rPG.js → window-store-D0HbQ1pM.js} +1 -1
  168. package/dist/web/assets/ws-auth-D111jj32.js +1 -0
  169. package/dist/web/assets/{xml-oyvc1920.js → xml-MmDclzxK.js} +1 -1
  170. package/dist/web/assets/{xsl-BbIGdNPF.js → xsl-DQEFs6Dd.js} +1 -1
  171. package/dist/web/index.html +23 -23
  172. package/dist/web/sw.js +1 -1
  173. package/docs/extension-development-guide.md +47 -0
  174. package/docs/project-roadmap.md +3 -1
  175. package/package.json +2 -2
  176. package/packages/ext-git-graph/package.json +23 -5
  177. package/packages/ext-git-graph/src/blame-parser.test.ts +154 -0
  178. package/packages/ext-git-graph/src/blame-parser.ts +148 -0
  179. package/packages/ext-git-graph/src/blame-view.ts +389 -0
  180. package/packages/ext-git-graph/src/commit-search.test.ts +118 -0
  181. package/packages/ext-git-graph/src/commit-search.ts +102 -0
  182. package/packages/ext-git-graph/src/compare-args.test.ts +111 -0
  183. package/packages/ext-git-graph/src/compare-args.ts +109 -0
  184. package/packages/ext-git-graph/src/compare-view.ts +343 -0
  185. package/packages/ext-git-graph/src/extension-integration.test.ts +6 -3
  186. package/packages/ext-git-graph/src/extension.ts +202 -249
  187. package/packages/ext-git-graph/src/file-history-parser.test.ts +102 -0
  188. package/packages/ext-git-graph/src/file-history-parser.ts +89 -0
  189. package/packages/ext-git-graph/src/file-history-view.ts +386 -0
  190. package/packages/ext-git-graph/src/git-exec.ts +122 -0
  191. package/packages/ext-git-graph/src/git-state.ts +81 -0
  192. package/packages/ext-git-graph/src/panel-nav.ts +65 -0
  193. package/packages/ext-git-graph/src/panel-registry.ts +72 -0
  194. package/packages/ext-git-graph/src/ppm-api.ts +48 -0
  195. package/packages/ext-git-graph/src/rebase-todo.test.ts +196 -0
  196. package/packages/ext-git-graph/src/rebase-todo.ts +119 -0
  197. package/packages/ext-git-graph/src/rebase-view.ts +483 -0
  198. package/packages/ext-git-graph/src/reflog-parser.test.ts +93 -0
  199. package/packages/ext-git-graph/src/reflog-parser.ts +86 -0
  200. package/packages/ext-git-graph/src/reflog-view.ts +375 -0
  201. package/packages/ext-git-graph/src/register-view-command.ts +47 -0
  202. package/packages/ext-git-graph/src/submodule-parser.test.ts +79 -0
  203. package/packages/ext-git-graph/src/submodule-parser.ts +77 -0
  204. package/packages/ext-git-graph/src/types.ts +10 -1
  205. package/packages/ext-git-graph/src/webview-html.ts +438 -3
  206. package/packages/ext-git-graph/src/webview-shell.ts +236 -0
  207. package/src/providers/claude-agent-sdk.ts +7 -0
  208. package/src/providers/codex-app-server/codex-provider.ts +89 -1
  209. package/src/server/index.ts +1 -1
  210. package/src/server/routes/accounts.ts +25 -1
  211. package/src/server/routes/chat.ts +29 -1
  212. package/src/server/routes/codex-accounts.ts +41 -1
  213. package/src/server/routes/git.ts +97 -0
  214. package/src/server/routes/settings.ts +1 -0
  215. package/src/server/routes/teams.ts +14 -3
  216. package/src/services/account-selector.service.ts +125 -20
  217. package/src/services/account.service.ts +176 -54
  218. package/src/services/autostart-generator.ts +12 -1
  219. package/src/services/codex-account.service.ts +87 -13
  220. package/src/services/db.service.ts +58 -3
  221. package/src/services/extension.service.ts +55 -5
  222. package/src/services/git-blame/blame-porcelain.ts +89 -0
  223. package/src/services/git-blame/git-blame.service.ts +90 -0
  224. package/src/services/git-hunks/git-hunks.service.ts +264 -0
  225. package/src/services/git-hunks/unified-diff.ts +359 -0
  226. package/src/services/picked-account-binding.ts +57 -0
  227. package/src/services/team-member-activity/member-transcript-tail.ts +64 -0
  228. package/src/shared/blame.ts +79 -0
  229. package/src/web/components/chat/chat-history-bar.tsx +34 -5
  230. package/src/web/components/chat/chat-tab.tsx +120 -3
  231. package/src/web/components/chat/codex-usage-panel.tsx +132 -14
  232. package/src/web/components/chat/team-member-window-content.tsx +8 -39
  233. package/src/web/components/chat/usage-badge.tsx +176 -52
  234. package/src/web/components/editor/code-editor.tsx +33 -1
  235. package/src/web/components/editor/diff-viewer.tsx +83 -8
  236. package/src/web/components/editor/editor-toolbar.tsx +25 -1
  237. package/src/web/components/git/git-status-panel.tsx +46 -0
  238. package/src/web/components/git/hunk-selection.ts +132 -0
  239. package/src/web/components/git/hunk-stage-dialog.tsx +419 -0
  240. package/src/web/components/settings/accounts/account-bucket-row.tsx +19 -3
  241. package/src/web/components/settings/accounts/account-card.tsx +153 -33
  242. package/src/web/components/settings/accounts/account-hint.tsx +33 -0
  243. package/src/web/components/settings/accounts/account-usage-format.ts +26 -0
  244. package/src/web/components/settings/accounts/codex-accounts-section.tsx +24 -9
  245. package/src/web/components/settings/accounts/codex-usage-rows.tsx +2 -2
  246. package/src/web/components/settings/accounts/use-accounts-data.ts +32 -2
  247. package/src/web/components/settings/accounts/use-codex-accounts.ts +24 -2
  248. package/src/web/hooks/use-chat.ts +27 -0
  249. package/src/web/hooks/use-inline-blame.ts +175 -0
  250. package/src/web/hooks/use-member-transcript-tail.ts +95 -0
  251. package/src/web/lib/api-settings.ts +24 -0
  252. package/src/web/stores/settings-store.ts +12 -0
  253. package/dist/web/assets/accounts-settings-section-Cd1Nh04o.js +0 -1
  254. package/dist/web/assets/ai-settings-section-OaYGT5OF.js +0 -1
  255. package/dist/web/assets/api-client-BogqsFna.js +0 -1
  256. package/dist/web/assets/api-settings-BVfemzZW.js +0 -1
  257. package/dist/web/assets/architecture-PBZL5I3N-BZBxtErN.js +0 -1
  258. package/dist/web/assets/chat-tab-Cc1W2pTu.js +0 -15
  259. package/dist/web/assets/code-editor-gLRyCPWE.js +0 -7
  260. package/dist/web/assets/diff-viewer-ix1Ko0xk.js +0 -4
  261. package/dist/web/assets/explorer-window-content-B7HmteDI.js +0 -1
  262. package/dist/web/assets/gitGraph-HDMCJU4V-BHxJbXfV.js +0 -1
  263. package/dist/web/assets/group-chat-tab-DmZ1vLk-.js +0 -1
  264. package/dist/web/assets/index-N-pnuwFP.css +0 -2
  265. package/dist/web/assets/index-yV5RgBDh.js +0 -52
  266. package/dist/web/assets/info-3K5VOQVL-DI4p3vbH.js +0 -1
  267. package/dist/web/assets/keybindings-store-88_Zkn5F.js +0 -1
  268. package/dist/web/assets/markdown-renderer-UhszMWSn.js +0 -1
  269. package/dist/web/assets/mobile-explorer-sheet-D9cqcU3X.js +0 -1
  270. package/dist/web/assets/notification-store-B6X6RYqQ.js +0 -1
  271. package/dist/web/assets/packet-RMMSAZCW-YNQWTi_-.js +0 -1
  272. package/dist/web/assets/pie-UPGHQEXC-E3Wiw76n.js +0 -1
  273. package/dist/web/assets/radar-KQ55EAFF-BPQJUKON.js +0 -1
  274. package/dist/web/assets/remote-desktop-mobile-sheet-DefltAPl.js +0 -2
  275. package/dist/web/assets/schedules-settings-section-D76Ob6tI.js +0 -1
  276. package/dist/web/assets/settings-store-DWUx3865.js +0 -2
  277. package/dist/web/assets/settings-tab-DToHQXfC.js +0 -1
  278. package/dist/web/assets/settings-window-content-B2rlq-Dv.js +0 -1
  279. package/dist/web/assets/system-monitor-tab-CuDpwAZU.js +0 -1
  280. package/dist/web/assets/team-member-sheet-DLrT_Kxo.js +0 -2
  281. package/dist/web/assets/team-member-window-content-S8cdLcg3.js +0 -1
  282. package/dist/web/assets/tool-cards-CLxrQlUs.js +0 -9
  283. package/dist/web/assets/treemap-KZPCXAKY-C2CvKBQR.js +0 -1
  284. package/dist/web/assets/use-accounts-data-snYPJED_.js +0 -1
  285. package/dist/web/assets/ws-auth-ZSZkAT6p.js +0 -1
  286. /package/dist/web/assets/{abap-Cq9nYQyd.js → abap-D-o-bvtI.js} +0 -0
  287. /package/dist/web/assets/{actionscript-3-DL8rUIy0.js → actionscript-3-D2tIzAm8.js} +0 -0
  288. /package/dist/web/assets/{ada-BY8TLuhY.js → ada-DxatBcxS.js} +0 -0
  289. /package/dist/web/assets/{andromeeda-CyVfHsS0.js → andromeeda-D0LK9YJ3.js} +0 -0
  290. /package/dist/web/assets/{apache-DTQUy73x.js → apache-B7uMPNiW.js} +0 -0
  291. /package/dist/web/assets/{apex-CiSZngrZ.js → apex-B7GiXrAr.js} +0 -0
  292. /package/dist/web/assets/{api-client-oY1tC3tM.js → api-client-CEYCBt_0.js} +0 -0
  293. /package/dist/web/assets/{applescript-CzuRDd3h.js → applescript-D_SIFkKe.js} +0 -0
  294. /package/dist/web/assets/{apply-theme-r8tKDrCR.js → apply-theme-BVXAUYoN.js} +0 -0
  295. /package/dist/web/assets/{ara-CSFV93kR.js → ara-C3iECgdg.js} +0 -0
  296. /package/dist/web/assets/{asciidoc-hOQNnXhz.js → asciidoc-gc8z_MMY.js} +0 -0
  297. /package/dist/web/assets/{asm-DdG53NGR.js → asm-27qeoPOI.js} +0 -0
  298. /package/dist/web/assets/{aurora-x-DJ7ORZG6.js → aurora-x-C5J9fWe1.js} +0 -0
  299. /package/dist/web/assets/{awk-B3FFpX_J.js → awk-B7GBzF92.js} +0 -0
  300. /package/dist/web/assets/{ayu-dark-D_P1CfTe.js → ayu-dark-XlnQhuLL.js} +0 -0
  301. /package/dist/web/assets/{ayu-light-Cz3YLUqH.js → ayu-light-DKLLilkU.js} +0 -0
  302. /package/dist/web/assets/{ayu-mirage-JcMq5tgJ.js → ayu-mirage-Dv-XOprJ.js} +0 -0
  303. /package/dist/web/assets/{ballerina-7Hs4Rfpk.js → ballerina-DACRT-sT.js} +0 -0
  304. /package/dist/web/assets/{bat-COgQdnFA.js → bat-BlQCq2XE.js} +0 -0
  305. /package/dist/web/assets/{beancount-BJ3CutBG.js → beancount-DYDztRI0.js} +0 -0
  306. /package/dist/web/assets/{berry-D7so2Cui.js → berry-BE5YKqvx.js} +0 -0
  307. /package/dist/web/assets/{bibtex-Ct3acHa1.js → bibtex-CAm7mgEm.js} +0 -0
  308. /package/dist/web/assets/{bicep-jXDwCQcm.js → bicep-BKgAbfVa.js} +0 -0
  309. /package/dist/web/assets/{bird2-CjLD2cna.js → bird2-yrBNbW1G.js} +0 -0
  310. /package/dist/web/assets/{c-CdgZojnL.js → c-txZFr4RM.js} +0 -0
  311. /package/dist/web/assets/{c3-DtpZYego.js → c3-D_DrzBUd.js} +0 -0
  312. /package/dist/web/assets/{cadence-CPLkixoh.js → cadence-CUFCEgG9.js} +0 -0
  313. /package/dist/web/assets/{can-open-in-ppm-BntPywsy.js → can-open-in-ppm-_yqa69dV.js} +0 -0
  314. /package/dist/web/assets/{catppuccin-frappe-Xt0_qJa9.js → catppuccin-frappe-Dn32MuhA.js} +0 -0
  315. /package/dist/web/assets/{catppuccin-latte-CJnbLec5.js → catppuccin-latte-Dewo7yDf.js} +0 -0
  316. /package/dist/web/assets/{catppuccin-macchiato-BPHP1wYB.js → catppuccin-macchiato-D8WOWZeo.js} +0 -0
  317. /package/dist/web/assets/{catppuccin-mocha-ssWJodGc.js → catppuccin-mocha-b0md48XM.js} +0 -0
  318. /package/dist/web/assets/{clarity-DB0408F6.js → clarity-Ct3UqLBj.js} +0 -0
  319. /package/dist/web/assets/{clojure-dpRPlAO4.js → clojure-CwP5aPEo.js} +0 -0
  320. /package/dist/web/assets/{cmake-r2VkeX9y.js → cmake-D5RF49e5.js} +0 -0
  321. /package/dist/web/assets/{codeowners-v5nQqHiB.js → codeowners-Cl5897L_.js} +0 -0
  322. /package/dist/web/assets/{codeql-BSSEhKRR.js → codeql-BKh1RCg0.js} +0 -0
  323. /package/dist/web/assets/{common-lisp-BXb2MMMA.js → common-lisp-BhHuD6t0.js} +0 -0
  324. /package/dist/web/assets/{coq-BjBNi73X.js → coq-Dco3qwD8.js} +0 -0
  325. /package/dist/web/assets/{csharp-CdPjZRbV.js → csharp-Dpjw9ZA9.js} +0 -0
  326. /package/dist/web/assets/{css-BuxbQOHL.js → css-CPe4cabH.js} +0 -0
  327. /package/dist/web/assets/{csv-Dj-eoZwH.js → csv-BAcTN8Kt.js} +0 -0
  328. /package/dist/web/assets/{csv-parser-CBbALsFU.js → csv-parser-DbxGKdMG.js} +0 -0
  329. /package/dist/web/assets/{cue-Dz73VksN.js → cue-Cr6y60TA.js} +0 -0
  330. /package/dist/web/assets/{cypher-CkVkDywZ.js → cypher-DWtqXXFP.js} +0 -0
  331. /package/dist/web/assets/{d-oU51Pbpf.js → d-BASiTZk4.js} +0 -0
  332. /package/dist/web/assets/{dark-plus-DcwvjjfO.js → dark-plus-56kmnrcl.js} +0 -0
  333. /package/dist/web/assets/{dart-DGvu8mcX.js → dart-C5mZnjoE.js} +0 -0
  334. /package/dist/web/assets/{data-grid-types-B6kUrF-M.js → data-grid-types-DeY60CLU.js} +0 -0
  335. /package/dist/web/assets/{dax-BmbjKQ90.js → dax-B4I2e7d8.js} +0 -0
  336. /package/dist/web/assets/{desktop-IRBSiFfh.js → desktop-DekGg0BT.js} +0 -0
  337. /package/dist/web/assets/{diff-Bdik2JR8.js → diff-CWnJBd73.js} +0 -0
  338. /package/dist/web/assets/{dist-Bv4zQpS1.js → dist-B0J2eYBz.js} +0 -0
  339. /package/dist/web/assets/{dist-C8YPBIOb.js → dist-BKOM_AoT.js} +0 -0
  340. /package/dist/web/assets/{docker-Bgdl0H8I.js → docker-DevchDxK.js} +0 -0
  341. /package/dist/web/assets/{dotenv-COe5NdnA.js → dotenv-DCvtdaGJ.js} +0 -0
  342. /package/dist/web/assets/{dracula-DjURaSAa.js → dracula-8U6Vkk3l.js} +0 -0
  343. /package/dist/web/assets/{dracula-soft-Do7d0bo-.js → dracula-soft-Bfeew5Wg.js} +0 -0
  344. /package/dist/web/assets/{dream-maker-DYwQvJIj.js → dream-maker-DDTJVuoy.js} +0 -0
  345. /package/dist/web/assets/{emacs-lisp-BXjlHyDW.js → emacs-lisp-CEHJqI4m.js} +0 -0
  346. /package/dist/web/assets/{everforest-dark-h8Q2loiX.js → everforest-dark-CHHLt7cq.js} +0 -0
  347. /package/dist/web/assets/{everforest-light-CdsJiL-9.js → everforest-light-TcTbK1sM.js} +0 -0
  348. /package/dist/web/assets/{fennel-D0CBtOvY.js → fennel-Bh4vsA1A.js} +0 -0
  349. /package/dist/web/assets/{fish-DzayfrMj.js → fish-D0T0fILG.js} +0 -0
  350. /package/dist/web/assets/{fluent-CatjkUfx.js → fluent-CgXDXdyy.js} +0 -0
  351. /package/dist/web/assets/{format-bytes-BulRSULX.js → format-bytes-Bc6SqF7M.js} +0 -0
  352. /package/dist/web/assets/{fortran-free-form-DM04ud0b.js → fortran-free-form-CUg3Xhz4.js} +0 -0
  353. /package/dist/web/assets/{gdscript-BLN5iZwf.js → gdscript-Cx056p_k.js} +0 -0
  354. /package/dist/web/assets/{gdshader-BK-1iZQs.js → gdshader-Dj1qP4I5.js} +0 -0
  355. /package/dist/web/assets/{genie-BGPOFWDN.js → genie-SBt15wn7.js} +0 -0
  356. /package/dist/web/assets/{gherkin-CdVOJ_JY.js → gherkin-bTJiHIrB.js} +0 -0
  357. /package/dist/web/assets/{github-dark-B_xW8TaY.js → github-dark-BOPhyugs.js} +0 -0
  358. /package/dist/web/assets/{github-dark-default-h_iKq7CX.js → github-dark-default-Cktqe6NF.js} +0 -0
  359. /package/dist/web/assets/{github-dark-dimmed-nKDYE62T.js → github-dark-dimmed-CeWfII_B.js} +0 -0
  360. /package/dist/web/assets/{github-dark-high-contrast-l8I771QT.js → github-dark-high-contrast-CTx8LpdV.js} +0 -0
  361. /package/dist/web/assets/{github-light-DNhjkg8Z.js → github-light-DVsO5Un1.js} +0 -0
  362. /package/dist/web/assets/{github-light-default-DQ06uS3g.js → github-light-default-BiyPxicr.js} +0 -0
  363. /package/dist/web/assets/{github-light-high-contrast-qc2sZCVN.js → github-light-high-contrast-BPlnke0a.js} +0 -0
  364. /package/dist/web/assets/{gleam-DPPatkNH.js → gleam-CWSxvD0C.js} +0 -0
  365. /package/dist/web/assets/{gn-BnzGQTy5.js → gn-D7NUVJuv.js} +0 -0
  366. /package/dist/web/assets/{gnuplot-Ct1leoo3.js → gnuplot-c5uXmJKc.js} +0 -0
  367. /package/dist/web/assets/{go-qysCdbrn.js → go-CRsHi4Cw.js} +0 -0
  368. /package/dist/web/assets/{groovy-BkWIdrRQ.js → groovy-DpV0RA5r.js} +0 -0
  369. /package/dist/web/assets/{gruvbox-dark-hard-L6Iiybbl.js → gruvbox-dark-hard-DD9fguUN.js} +0 -0
  370. /package/dist/web/assets/{gruvbox-dark-medium-DbD3yl0b.js → gruvbox-dark-medium-BvcwpYJ-.js} +0 -0
  371. /package/dist/web/assets/{gruvbox-dark-soft-Ban2cHK3.js → gruvbox-dark-soft-48dCxX9M.js} +0 -0
  372. /package/dist/web/assets/{gruvbox-light-hard-CK_SjS3e.js → gruvbox-light-hard-CjJ994Ip.js} +0 -0
  373. /package/dist/web/assets/{gruvbox-light-medium-Bjgvhc2w.js → gruvbox-light-medium-DQJQZ_rV.js} +0 -0
  374. /package/dist/web/assets/{gruvbox-light-soft-EWnyYGUu.js → gruvbox-light-soft-AqsC9mKw.js} +0 -0
  375. /package/dist/web/assets/{haskell-rT1N9nYr.js → haskell-B5V7yvmh.js} +0 -0
  376. /package/dist/web/assets/{haxe-Bbc91axo.js → haxe-LWTKfPKr.js} +0 -0
  377. /package/dist/web/assets/{hcl-D-3qJA4v.js → hcl-QmNZdAtI.js} +0 -0
  378. /package/dist/web/assets/{hjson-DWtewcyQ.js → hjson-CboJsAzK.js} +0 -0
  379. /package/dist/web/assets/{hlsl-C7t6hCrO.js → hlsl-Bd-DO_WL.js} +0 -0
  380. /package/dist/web/assets/{horizon-zJAGUQ3j.js → horizon-CU8Bi_ss.js} +0 -0
  381. /package/dist/web/assets/{horizon-bright-CRNyrJy8.js → horizon-bright-iSQ3_3jP.js} +0 -0
  382. /package/dist/web/assets/{houston-BFKa4W1-.js → houston-CTXv3Puz.js} +0 -0
  383. /package/dist/web/assets/{hy-W1hNjMBM.js → hy-Cd4hTidD.js} +0 -0
  384. /package/dist/web/assets/{image-gallery-BycaVWOu.js → image-gallery-J8h8IY0c.js} +0 -0
  385. /package/dist/web/assets/{imba-CPphaV-V.js → imba-BipCHEY2.js} +0 -0
  386. /package/dist/web/assets/{ini-CayaZ4vW.js → ini-Dd1KkMrB.js} +0 -0
  387. /package/dist/web/assets/{java-BPAE_9Ej.js → java-rGr0OQD8.js} +0 -0
  388. /package/dist/web/assets/{javascript-C5SKIVqe.js → javascript-DHhCH2TN.js} +0 -0
  389. /package/dist/web/assets/{json-C-0EUYmu.js → json-CMMLBCUf.js} +0 -0
  390. /package/dist/web/assets/{json5-BqVetEZL.js → json5-mPOwTOsB.js} +0 -0
  391. /package/dist/web/assets/{jsonc-DnjIzkUB.js → jsonc-Bie0E6D3.js} +0 -0
  392. /package/dist/web/assets/{jsonl-rbV-3EqO.js → jsonl-CpqHmtC1.js} +0 -0
  393. /package/dist/web/assets/{jsonnet-9hvXw4qr.js → jsonnet-D21Ms51e.js} +0 -0
  394. /package/dist/web/assets/{jssm-1ifXyIhu.js → jssm-BXnl1nur.js} +0 -0
  395. /package/dist/web/assets/{jsx-hPumywTY.js → jsx-Chnii_vB.js} +0 -0
  396. /package/dist/web/assets/{kanagawa-dragon-BCPjmoMO.js → kanagawa-dragon-DhxR0UjL.js} +0 -0
  397. /package/dist/web/assets/{kanagawa-lotus-DN2VNjy7.js → kanagawa-lotus-fupRg5wp.js} +0 -0
  398. /package/dist/web/assets/{kanagawa-wave-B8RZEsgc.js → kanagawa-wave-DSWbRS9M.js} +0 -0
  399. /package/dist/web/assets/{kdl-CkvjWQIa.js → kdl-DirGHqUy.js} +0 -0
  400. /package/dist/web/assets/{kotlin-D8cnRi5o.js → kotlin-DkhUVMDC.js} +0 -0
  401. /package/dist/web/assets/{kusto-CmeeBEJG.js → kusto-DU7OpovF.js} +0 -0
  402. /package/dist/web/assets/{laserwave--rtV8Mv9.js → laserwave-iLKb1ZCT.js} +0 -0
  403. /package/dist/web/assets/{lean-CS-Pyi42.js → lean-Cuvh_QAP.js} +0 -0
  404. /package/dist/web/assets/{less-Ddi_7qGm.js → less-B5tQZOdI.js} +0 -0
  405. /package/dist/web/assets/{lib-DIrxSyLb.js → lib-el9rA30D.js} +0 -0
  406. /package/dist/web/assets/{libesm-CYLrAeW3.js → libesm-CdttTIAd.js} +0 -0
  407. /package/dist/web/assets/{light-plus-CrEjpkkX.js → light-plus-DiHU2KL5.js} +0 -0
  408. /package/dist/web/assets/{llvm-Cm7ZXmAO.js → llvm-sCBTKCKN.js} +0 -0
  409. /package/dist/web/assets/{log-lW2sYxtp.js → log-DtyR34Ie.js} +0 -0
  410. /package/dist/web/assets/{logo-B-PiRb53.js → logo-CP91aQyG.js} +0 -0
  411. /package/dist/web/assets/{luau-8St0pC-R.js → luau-nfGo2ulP.js} +0 -0
  412. /package/dist/web/assets/{make-DbNdhH54.js → make-XbDn9GHe.js} +0 -0
  413. /package/dist/web/assets/{markdown-CYocYSGd.js → markdown-BB1_3xLr.js} +0 -0
  414. /package/dist/web/assets/{material-theme-CVBF1Cbi.js → material-theme-CIx_sxAy.js} +0 -0
  415. /package/dist/web/assets/{material-theme-darker-HFrlNZD8.js → material-theme-darker-DsQeueDD.js} +0 -0
  416. /package/dist/web/assets/{material-theme-lighter-BM-uz2ft.js → material-theme-lighter-x_lMi74j.js} +0 -0
  417. /package/dist/web/assets/{material-theme-ocean-PbvUez8m.js → material-theme-ocean-Bkgh25P8.js} +0 -0
  418. /package/dist/web/assets/{material-theme-palenight-B22Ck6qd.js → material-theme-palenight-CoOjdbti.js} +0 -0
  419. /package/dist/web/assets/{matlab-GFFNzucw.js → matlab-D6xZas_8.js} +0 -0
  420. /package/dist/web/assets/{mdx-BVnJzMDx.js → mdx-Cl5_YNoz.js} +0 -0
  421. /package/dist/web/assets/{mermaid-BlCmSTCM.js → mermaid-8Eow4jz_.js} +0 -0
  422. /package/dist/web/assets/{min-dark-B0PwlAfC.js → min-dark-D4DhjgRE.js} +0 -0
  423. /package/dist/web/assets/{min-light-C_H2ABKu.js → min-light-DzAckd0t.js} +0 -0
  424. /package/dist/web/assets/{mipsasm-C3rf2fo6.js → mipsasm-zI_zu0tj.js} +0 -0
  425. /package/dist/web/assets/{mojo-CDRuzM3o.js → mojo-DQnGGPHf.js} +0 -0
  426. /package/dist/web/assets/{monokai-KiebNy_Y.js → monokai-CrFoD2VD.js} +0 -0
  427. /package/dist/web/assets/{moonbit-CdVUHoWl.js → moonbit-DdphIGs6.js} +0 -0
  428. /package/dist/web/assets/{move-Dq9iKZRY.js → move-BUlkn0xW.js} +0 -0
  429. /package/dist/web/assets/{narrat-7y5L5sGM.js → narrat-CbOBdtCn.js} +0 -0
  430. /package/dist/web/assets/{nextflow-groovy-Cwcbkcrx.js → nextflow-groovy-CeVLUTuQ.js} +0 -0
  431. /package/dist/web/assets/{night-owl-TBgLPzj4.js → night-owl-Bm4LhUR1.js} +0 -0
  432. /package/dist/web/assets/{night-owl-light-Dehb9My2.js → night-owl-light-DtcBiMEf.js} +0 -0
  433. /package/dist/web/assets/{nix-BKj-gzoX.js → nix-DrdwQ70g.js} +0 -0
  434. /package/dist/web/assets/{nord-BF_r8PeX.js → nord-B0Head1v.js} +0 -0
  435. /package/dist/web/assets/{nushell-CeAjk9_E.js → nushell-CmUdltKn.js} +0 -0
  436. /package/dist/web/assets/{objective-c-Xl1OMcDp.js → objective-c-BGDR33XN.js} +0 -0
  437. /package/dist/web/assets/{objective-cpp-C4ZgzrRq.js → objective-cpp-Buc1Zhd0.js} +0 -0
  438. /package/dist/web/assets/{ocaml-CGj8IYTq.js → ocaml-xdzl9rRD.js} +0 -0
  439. /package/dist/web/assets/{odin-C4veqvW2.js → odin-DiUFngnd.js} +0 -0
  440. /package/dist/web/assets/{one-dark-pro-gAcWejsV.js → one-dark-pro-BURxmIp3.js} +0 -0
  441. /package/dist/web/assets/{one-light-B7E-UUXy.js → one-light-BMRMInAj.js} +0 -0
  442. /package/dist/web/assets/{openscad-C-wN9BEv.js → openscad-DAgLA5J3.js} +0 -0
  443. /package/dist/web/assets/{pascal-C8WBtxMs.js → pascal-CoDZxcRB.js} +0 -0
  444. /package/dist/web/assets/{pkl-BBfF4G2A.js → pkl-DzKM6BuM.js} +0 -0
  445. /package/dist/web/assets/{plastic-DFOAb89P.js → plastic-vF15LmNS.js} +0 -0
  446. /package/dist/web/assets/{plsql-BS2CEMMV.js → plsql-C1v07teA.js} +0 -0
  447. /package/dist/web/assets/{po-BKJDtPmy.js → po-CLLC8BuA.js} +0 -0
  448. /package/dist/web/assets/{poimandres-Cg3hL13e.js → poimandres-Uq0xysxM.js} +0 -0
  449. /package/dist/web/assets/{polar-B9ebiXUU.js → polar-2-luY1Pc.js} +0 -0
  450. /package/dist/web/assets/{portal-container-context-a399Hd9F.js → portal-container-context-DKymYOY-.js} +0 -0
  451. /package/dist/web/assets/{postcss-B5REwNY_.js → postcss-lbFhe0rz.js} +0 -0
  452. /package/dist/web/assets/{powerquery-stc0Gzkf.js → powerquery-RL8O9Wie.js} +0 -0
  453. /package/dist/web/assets/{powershell-jgd0ahJN.js → powershell-upFWhb-b.js} +0 -0
  454. /package/dist/web/assets/{prisma-CWuZjRhI.js → prisma-DBtYaWFk.js} +0 -0
  455. /package/dist/web/assets/{prolog-D5zNFE63.js → prolog-D8jSMykJ.js} +0 -0
  456. /package/dist/web/assets/{proto-B-6RrU7n.js → proto-BM4eadF7.js} +0 -0
  457. /package/dist/web/assets/{puppet-DONP8TDR.js → puppet-BQDQ3Snu.js} +0 -0
  458. /package/dist/web/assets/{purescript-DDJITf-A.js → purescript-Cj2aTX4s.js} +0 -0
  459. /package/dist/web/assets/{python-bmWy9j1-.js → python-BYpqq6u4.js} +0 -0
  460. /package/dist/web/assets/{qmldir-CKDwMt7X.js → qmldir-4uiTcwAu.js} +0 -0
  461. /package/dist/web/assets/{qss-DptQQzBn.js → qss-D5xB-Mqo.js} +0 -0
  462. /package/dist/web/assets/{r-BorKpJ8r.js → r-P6Ujy8rf.js} +0 -0
  463. /package/dist/web/assets/{racket-BaHpYVsZ.js → racket-COKgCFuM.js} +0 -0
  464. /package/dist/web/assets/{raku-DFJIV4k_.js → raku-z14Q9i7K.js} +0 -0
  465. /package/dist/web/assets/{react-X4jUntEf.js → react-D1Yg256j.js} +0 -0
  466. /package/dist/web/assets/{red-70oJGrkb.js → red-ObAvgvQ5.js} +0 -0
  467. /package/dist/web/assets/{reg-C4g235Dv.js → reg-Qv4f0JFA.js} +0 -0
  468. /package/dist/web/assets/{regexp-Cw1UVmti.js → regexp-CEOVGIzy.js} +0 -0
  469. /package/dist/web/assets/{rel-DeLhIz5L.js → rel-cWOyTUwd.js} +0 -0
  470. /package/dist/web/assets/{resolve-theme-b_yGlUFQ.js → resolve-theme-CMp5xxCW.js} +0 -0
  471. /package/dist/web/assets/{riscv-ChnTiBRK.js → riscv-BZDwx-lv.js} +0 -0
  472. /package/dist/web/assets/{ron-C5IWeqDn.js → ron-BpjosPS0.js} +0 -0
  473. /package/dist/web/assets/{rose-pine-DCR0ohYW.js → rose-pine-DhxfJWcm.js} +0 -0
  474. /package/dist/web/assets/{rose-pine-dawn-DvGZs1PR.js → rose-pine-dawn-BbGt9Wy_.js} +0 -0
  475. /package/dist/web/assets/{rose-pine-moon-BWACHjeS.js → rose-pine-moon-dj4Zxgik.js} +0 -0
  476. /package/dist/web/assets/{rosmsg-CQlIVazE.js → rosmsg-EciOaHo2.js} +0 -0
  477. /package/dist/web/assets/{rust-DGGVzWI8.js → rust-C_eH59O_.js} +0 -0
  478. /package/dist/web/assets/{sass-bj1C0rFI.js → sass-Dos3R5lL.js} +0 -0
  479. /package/dist/web/assets/{scala-MU1tLKDi.js → scala-8lVKsTvf.js} +0 -0
  480. /package/dist/web/assets/{scheme-CeGXtv7t.js → scheme-Bd3VdaZj.js} +0 -0
  481. /package/dist/web/assets/{sdbl-D0HLSGKp.js → sdbl-C4Yrjlgh.js} +0 -0
  482. /package/dist/web/assets/{shellscript-DkYiDvh1.js → shellscript-OFZbPKZH.js} +0 -0
  483. /package/dist/web/assets/{slack-dark-YqeHiGWH.js → slack-dark-aL6vlxZs.js} +0 -0
  484. /package/dist/web/assets/{slack-ochin-9Oe0DljJ.js → slack-ochin-BKt1E7sL.js} +0 -0
  485. /package/dist/web/assets/{smalltalk-CaaxedR7.js → smalltalk-D6qVBL1U.js} +0 -0
  486. /package/dist/web/assets/{snazzy-light-C8s2FHNC.js → snazzy-light-BrWerT0t.js} +0 -0
  487. /package/dist/web/assets/{solarized-dark-0ryY6oN3.js → solarized-dark-CzxTJgVQ.js} +0 -0
  488. /package/dist/web/assets/{solarized-light-bltgZeNh.js → solarized-light-BecaDAnG.js} +0 -0
  489. /package/dist/web/assets/{solidity-DOf5HmLZ.js → solidity-C9t7pZ84.js} +0 -0
  490. /package/dist/web/assets/{splunk-D1u4WHDW.js → splunk-CtxfFKtF.js} +0 -0
  491. /package/dist/web/assets/{sql-G8uQZljX.js → sql-7FE_Duz0.js} +0 -0
  492. /package/dist/web/assets/{ssh-config-rbXvly7Q.js → ssh-config-3Fr37ACC.js} +0 -0
  493. /package/dist/web/assets/{stylus-Cii1iADy.js → stylus-BP4mE1sO.js} +0 -0
  494. /package/dist/web/assets/{swift-DpIgonN4.js → swift-0uqTFouD.js} +0 -0
  495. /package/dist/web/assets/{synthwave-84-DjGLzU2b.js → synthwave-84-DQaNM3DI.js} +0 -0
  496. /package/dist/web/assets/{system-verilog-_Z0M0Hs1.js → system-verilog-DUIVrZHZ.js} +0 -0
  497. /package/dist/web/assets/{systemd-BhyDCh9P.js → systemd-CtNo_WIh.js} +0 -0
  498. /package/dist/web/assets/{talonscript-CNchgCRD.js → talonscript-B0HXaCVT.js} +0 -0
  499. /package/dist/web/assets/{tasl-m--W7Pyr.js → tasl-Cb7RAl11.js} +0 -0
  500. /package/dist/web/assets/{tcl-gY-M_2BC.js → tcl-B79aC6l5.js} +0 -0
  501. /package/dist/web/assets/{terraform-CB6CzMwo.js → terraform-75jJDjpW.js} +0 -0
  502. /package/dist/web/assets/{tokyo-night-COh9oRYi.js → tokyo-night-Cz9Uh9qb.js} +0 -0
  503. /package/dist/web/assets/{toml-Bg2bsY-v.js → toml-CD6y9A-z.js} +0 -0
  504. /package/dist/web/assets/{tsv-DceGDiJC.js → tsv-CXJMbBrb.js} +0 -0
  505. /package/dist/web/assets/{tsx-EccDYa7i.js → tsx-BuYN0I2t.js} +0 -0
  506. /package/dist/web/assets/{turtle-C_l2JhvX.js → turtle-DWH-Rjse.js} +0 -0
  507. /package/dist/web/assets/{typescript-C1ytmMcr.js → typescript-BPd-hsrR.js} +0 -0
  508. /package/dist/web/assets/{typespec-De2ztzG5.js → typespec-B0wvVykx.js} +0 -0
  509. /package/dist/web/assets/{typst-DNcS7gSr.js → typst-DWG2c48-.js} +0 -0
  510. /package/dist/web/assets/{use-is-mobile-CYW3FJFE.js → use-is-mobile-D1weanbj.js} +0 -0
  511. /package/dist/web/assets/{use-visual-viewport-D9O48HQt.js → use-visual-viewport-Bfl3Bxxb.js} +0 -0
  512. /package/dist/web/assets/{utils-C9OjCrou.js → utils-IrnQujwR.js} +0 -0
  513. /package/dist/web/assets/{v-DSMUsdMO.js → v-Ch6E4Egd.js} +0 -0
  514. /package/dist/web/assets/{vala-BEazLpkO.js → vala-CGVKwbPx.js} +0 -0
  515. /package/dist/web/assets/{vb-CV9pEJzW.js → vb-BIEbSxyT.js} +0 -0
  516. /package/dist/web/assets/{vendor-xterm-cuGQmUjN.js → vendor-xterm-YQlzIWv2.js} +0 -0
  517. /package/dist/web/assets/{verilog-DhXkLVMk.js → verilog-A-3pYPad.js} +0 -0
  518. /package/dist/web/assets/{vesper-n4IltYq-.js → vesper-CK1naZAV.js} +0 -0
  519. /package/dist/web/assets/{vhdl-CePjFbvs.js → vhdl-CVawmgMg.js} +0 -0
  520. /package/dist/web/assets/{viml-ChndFsm5.js → viml-CiWjaqBY.js} +0 -0
  521. /package/dist/web/assets/{vitesse-black-BytVdvhC.js → vitesse-black-PYXW4-BO.js} +0 -0
  522. /package/dist/web/assets/{vitesse-dark-83Wech0N.js → vitesse-dark-BU5s4AuG.js} +0 -0
  523. /package/dist/web/assets/{vitesse-light-Xg4wbeMO.js → vitesse-light-DgkIT-N7.js} +0 -0
  524. /package/dist/web/assets/{vyper-eW1NC3FG.js → vyper-D8cRDPp3.js} +0 -0
  525. /package/dist/web/assets/{wasm-BucxKwBZ.js → wasm-C02wlRbP.js} +0 -0
  526. /package/dist/web/assets/{wasm-Bhucqu1z.js → wasm-ClFJgzmT.js} +0 -0
  527. /package/dist/web/assets/{wenyan-BJFBuXuH.js → wenyan-B8plxIr8.js} +0 -0
  528. /package/dist/web/assets/{wgsl-6z4FUyMK.js → wgsl-CVujtm3V.js} +0 -0
  529. /package/dist/web/assets/{wikitext-BoDU6teJ.js → wikitext-CmcG9B69.js} +0 -0
  530. /package/dist/web/assets/{wit-DerMPpgt.js → wit--gl2Jium.js} +0 -0
  531. /package/dist/web/assets/{wolfram-D78v0Ap-.js → wolfram-6T_1D-NS.js} +0 -0
  532. /package/dist/web/assets/{x-YDu4m2Iq.js → x-CxoBA0po.js} +0 -0
  533. /package/dist/web/assets/{yaml-C4TIgIw4.js → yaml-CIVV9uA1.js} +0 -0
  534. /package/dist/web/assets/{zenscript-BydW-dLC.js → zenscript-CoT4yNdA.js} +0 -0
  535. /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: { ...metadata, sessionId, providerId, permissionMode },
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
- <button
63
- onClick={reload}
64
- disabled={loading}
65
- className="text-text-subtle hover:text-text-primary px-1 cursor-pointer disabled:opacity-50"
66
- title="Refresh"
67
- >
68
- <RefreshCw className={`size-3 ${loading ? "animate-spin" : ""}`} />
69
- </button>
70
- <button onClick={onClose} className="text-text-subtle hover:text-text-primary px-1 cursor-pointer" title="Close">
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
- </div>
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 key={a.id} className="rounded-md border border-border/50 bg-surface/40 p-2.5 space-y-2">
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} />
@@ -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. Steps render through the same
7
- * `SubagentChildren` view the inline Agent card uses, so a teammate's session
8
- * looks identical wherever it is read.
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 type { ChatEvent } from "../../../types/chat";
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 [events, setEvents] = useState<ChatEvent[]>([]);
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={() => setReloadKey((k) => k + 1)}
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
  >