@hienlh/ppm 0.19.2 → 0.19.3

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 (617) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/CLAUDE.md +1 -0
  3. package/assets/skills/ppm/SKILL.md +1 -1
  4. package/assets/skills/ppm/references/cli-reference.md +4 -4
  5. package/assets/skills/ppm/references/http-api.md +3 -2
  6. package/dist/web/assets/accounts-settings-section-LtSVxNNp.js +1 -0
  7. package/dist/web/assets/ai-resource-editor-BqFT1EUB.js +1 -0
  8. package/dist/web/assets/ai-settings-section-CY6spbEx.js +1 -0
  9. package/dist/web/assets/ai-settings-section-Po3K8j-g.js +1 -0
  10. package/dist/web/assets/{angular-html-BlcrLjUx.js → angular-html-BuHNQIbQ.js} +1 -1
  11. package/dist/web/assets/{angular-ts-BUjtceAJ.js → angular-ts-DHRWoLc-.js} +1 -1
  12. package/dist/web/assets/api-client-BogqsFna.js +1 -0
  13. package/dist/web/assets/api-settings-CTMdz_VF.js +1 -0
  14. package/dist/web/assets/{api-themes-YsZgf6Xj.js → api-themes-Cknp3Q-P.js} +1 -1
  15. package/dist/web/assets/{apl-B3g0v1pk.js → apl-C1VSWVei.js} +1 -1
  16. package/dist/web/assets/appearance-settings-section-L9Z-nej_.js +1 -0
  17. package/dist/web/assets/architecture-PBZL5I3N-Ca5IpdzP.js +1 -0
  18. package/dist/web/assets/arrow-left-CyFcsyzD.js +1 -0
  19. package/dist/web/assets/{astro-FRnyn7cH.js → astro-RX-rChsZ.js} +1 -1
  20. package/dist/web/assets/{audio-preview-DWTRm4HC.js → audio-preview-CCd1jdje.js} +1 -1
  21. package/dist/web/assets/{blade-NLdOqUKw.js → blade-CZ6bxMbK.js} +1 -1
  22. package/dist/web/assets/{pencil-BlIIg6RH.js → brain-KDa9jFRq.js} +1 -1
  23. package/dist/web/assets/{bsl-CenHZfaU.js → bsl-BhgCXLWk.js} +1 -1
  24. package/dist/web/assets/{button-Cq8yixjf.js → button-BZtEJcUv.js} +1 -1
  25. package/dist/web/assets/{cairo-B_WR0aiQ.js → cairo-BrwygPkn.js} +1 -1
  26. package/dist/web/assets/calendar-clock-C1asT-gk.js +1 -0
  27. package/dist/web/assets/chat-tab-BIO-VhWT.js +15 -0
  28. package/dist/web/assets/check-DN75Ucvz.js +1 -0
  29. package/dist/web/assets/chevron-up-8PbsNiJp.js +1 -0
  30. package/dist/web/assets/{cobol-DOynhWYj.js → cobol-C5TGW1Ir.js} +1 -1
  31. package/dist/web/assets/code-editor-B9lVjElM.js +7 -0
  32. package/dist/web/assets/{coffee-Bn6dbw4P.js → coffee-CFgKlmgI.js} +1 -1
  33. package/dist/web/assets/{conflict-editor-Cgb-z12D.js → conflict-editor-BoRPwL3L.js} +1 -1
  34. package/dist/web/assets/context-menu-C13b1uT3.js +1 -0
  35. package/dist/web/assets/{cpp-CoZR9t8r.js → cpp-BhG5q3-d.js} +1 -1
  36. package/dist/web/assets/{crystal-BSheONSg.js → crystal-DvuI7_tY.js} +1 -1
  37. package/dist/web/assets/{csv-preview-BZMHfFH3.js → csv-preview-BpoJqZQi.js} +1 -1
  38. package/dist/web/assets/{data-grid-overlay-editor-gwPoVSCU.js → data-grid-overlay-editor-DP1xkog4.js} +1 -1
  39. package/dist/web/assets/database-viewer-I-9cER1L.js +1 -0
  40. package/dist/web/assets/diff-viewer-_xHZsxvr.js +4 -0
  41. package/dist/web/assets/{docx-preview-DqVDOMmv.js → docx-preview-CWIDVNZn.js} +1 -1
  42. package/dist/web/assets/{edge-DTtoslQu.js → edge-BSIEsmlI.js} +1 -1
  43. package/dist/web/assets/{edit-diff-preview-CXSbSUBX.js → edit-diff-preview-DeHb85DN.js} +1 -1
  44. package/dist/web/assets/{elixir-CIBCZ3Zi.js → elixir-BF-lrGXM.js} +1 -1
  45. package/dist/web/assets/{elm-BLmb7K1H.js → elm-8mCsJOeN.js} +1 -1
  46. package/dist/web/assets/{erb-BBY8ApRd.js → erb-Dw5PUVKa.js} +1 -1
  47. package/dist/web/assets/{erlang-D5Zb5_P0.js → erlang-BvjBIA6O.js} +1 -1
  48. package/dist/web/assets/{esm-6F8v1jLL.js → esm-Bt9OwSnU.js} +1 -1
  49. package/dist/web/assets/explorer-body-DapwsOnp.js +2 -0
  50. package/dist/web/assets/explorer-window-content-DD6Z15pm.js +1 -0
  51. package/dist/web/assets/extension-manager-section-Cu9D9Udt.js +1 -0
  52. package/dist/web/assets/{extension-webview-BSh6KGd7.js → extension-webview-Diz2OzVq.js} +1 -1
  53. package/dist/web/assets/{plus-BR0qewJI.js → eye-gWwaF4Lg.js} +1 -1
  54. package/dist/web/assets/eye-off-GjXVuAOn.js +1 -0
  55. package/dist/web/assets/files-settings-section-B1e7BgKQ.js +1 -0
  56. package/dist/web/assets/flask-conical-tp8gyZGh.js +1 -0
  57. package/dist/web/assets/{fortran-fixed-form-CBdwkEUJ.js → fortran-fixed-form-CRjUJe9K.js} +1 -1
  58. package/dist/web/assets/{fsharp-AT4XdVYH.js → fsharp-CjUIHIHp.js} +1 -1
  59. package/dist/web/assets/{gdresource-D852fWBR.js → gdresource-x_NUQFrZ.js} +1 -1
  60. package/dist/web/assets/general-settings-section-DWdHHRDy.js +1 -0
  61. package/dist/web/assets/{git-commit-DWfWAyxy.js → git-commit-BOpxSbns.js} +1 -1
  62. package/dist/web/assets/git-log-panel-CMMsvU64.js +1 -0
  63. package/dist/web/assets/{git-rebase-C6opk8gr.js → git-rebase-BW4xlK7k.js} +1 -1
  64. package/dist/web/assets/gitGraph-HDMCJU4V-BloZfB0Q.js +1 -0
  65. package/dist/web/assets/{glide-data-grid-CICFjJon.js → glide-data-grid-pKQuyYFj.js} +8 -8
  66. package/dist/web/assets/{glimmer-js-DLi5mWYO.js → glimmer-js-CT9jrmFj.js} +1 -1
  67. package/dist/web/assets/{glimmer-ts-D-scFX30.js → glimmer-ts-CjQT1lxK.js} +1 -1
  68. package/dist/web/assets/{glsl-dbQzF4iA.js → glsl-DsFJvtg5.js} +1 -1
  69. package/dist/web/assets/{graphql-D1m5Wen2.js → graphql-Dhlnmkn_.js} +1 -1
  70. package/dist/web/assets/group-chat-tab-U5u0Loii.js +1 -0
  71. package/dist/web/assets/{hack-CqYmpO7u.js → hack-BKHbsJ7u.js} +1 -1
  72. package/dist/web/assets/{haml-BXzKWEag.js → haml-C1Ih25Y2.js} +1 -1
  73. package/dist/web/assets/{handlebars-DXnrtHtq.js → handlebars-CaFitvmC.js} +1 -1
  74. package/dist/web/assets/{html-DhgQJ-xL.js → html-BwpKIE6V.js} +1 -1
  75. package/dist/web/assets/{html-derivative-xZRft-YE.js → html-derivative-uuTEquZU.js} +1 -1
  76. package/dist/web/assets/{http-B53mSj14.js → http-Cv4Pg5cR.js} +1 -1
  77. package/dist/web/assets/{hurl-CsomVy04.js → hurl-DubkI6TG.js} +1 -1
  78. package/dist/web/assets/{hxml-LffjWwKA.js → hxml-B9OVZFAB.js} +1 -1
  79. package/dist/web/assets/{image-preview-CNA6XMNS.js → image-preview-DRbZ0FA2.js} +1 -1
  80. package/dist/web/assets/index--KWVW-Ga.js +52 -0
  81. package/dist/web/assets/index-CvGx7wBQ.css +2 -0
  82. package/dist/web/assets/info-3K5VOQVL-c0W8wp5o.js +1 -0
  83. package/dist/web/assets/{jinja-CCHURl7V.js → jinja-BHb1jyl6.js} +1 -1
  84. package/dist/web/assets/jira-watcher-section-uA5oyB8s.js +1 -0
  85. package/dist/web/assets/{jison-7qBd8dnR.js → jison-CtpfXDzp.js} +1 -1
  86. package/dist/web/assets/{julia-BY9pnTcy.js → julia-TYjgpazU.js} +1 -1
  87. package/dist/web/assets/{just-D7wRSNRr.js → just-D27bzZuW.js} +1 -1
  88. package/dist/web/assets/key-round-CQpDrDxg.js +1 -0
  89. package/dist/web/assets/keybindings-store-Ccf0etMJ.js +1 -0
  90. package/dist/web/assets/keyboard-shortcuts-section-B7IxJHiI.js +1 -0
  91. package/dist/web/assets/{latex-RgsCae55.js → latex-D_MzopTn.js} +1 -1
  92. package/dist/web/assets/{liquid-CnDFzvOZ.js → liquid-BG_FG0Pe.js} +1 -1
  93. package/dist/web/assets/{lua-0lj5W8sm.js → lua-Bl29oC2L.js} +1 -1
  94. package/dist/web/assets/markdown-renderer-CY1epGRc.js +1 -0
  95. package/dist/web/assets/{markdown-renderer-dbLIvU2M.js → markdown-renderer-DDcIGQEd.js} +3 -3
  96. package/dist/web/assets/{marko-CQgqAhbV.js → marko-D-HI7dbm.js} +1 -1
  97. package/dist/web/assets/{mdc-BkIcTiIy.js → mdc-y444JQTQ.js} +1 -1
  98. package/dist/web/assets/{media-url-DDciwvLU.js → media-url-VzecHk9g.js} +1 -1
  99. package/dist/web/assets/{mobile-bottom-sheet-pjcHKorA.js → mobile-bottom-sheet-BD5b7KJF.js} +1 -1
  100. package/dist/web/assets/mobile-explorer-sheet-CqkwbCRl.js +1 -0
  101. package/dist/web/assets/{nextflow-DvIW68DS.js → nextflow-C5sKcldC.js} +1 -1
  102. package/dist/web/assets/{nginx-O-hft0gG.js → nginx-bXnEC3wm.js} +1 -1
  103. package/dist/web/assets/{nim-BxrR4HwQ.js → nim-pevhf4WD.js} +1 -1
  104. package/dist/web/assets/notification-store-BNSYk3E7.js +1 -0
  105. package/dist/web/assets/notifications-settings-section-v_628h4B.js +1 -0
  106. package/dist/web/assets/{number-overlay-editor-BoLRYuZT.js → number-overlay-editor-B7WINIW4.js} +1 -1
  107. package/dist/web/assets/{overview-panel-l3g1gT5e.js → overview-panel-mhN0qw6Q.js} +1 -1
  108. package/dist/web/assets/packet-RMMSAZCW-D_BoHr_M.js +1 -0
  109. package/dist/web/assets/panel-store-BRrnDO_i.js +1 -0
  110. package/dist/web/assets/pdf-preview-CI3q1MnH.js +1 -0
  111. package/dist/web/assets/{perl-Da-uNqmL.js → perl-B1KUtMnW.js} +1 -1
  112. package/dist/web/assets/{php-JMu45mEx.js → php-BGmVZBAJ.js} +1 -1
  113. package/dist/web/assets/pie-UPGHQEXC-BaLfuEf8.js +1 -0
  114. package/dist/web/assets/{postgres-viewer-DstZwUai.js → postgres-viewer-jaR0FYJ_.js} +3 -3
  115. package/dist/web/assets/power-CriQkeK5.js +1 -0
  116. package/dist/web/assets/ppmbot-settings-section-BET4VmKb.js +1 -0
  117. package/dist/web/assets/{process-table-kmQ2-8qJ.js → process-table-D1r-Gupi.js} +1 -1
  118. package/dist/web/assets/{project-store-DTUCS65m.js → project-store-BuY7rxn_.js} +1 -1
  119. package/dist/web/assets/proxy-settings-section-0DvNh1B-.js +3 -0
  120. package/dist/web/assets/{pug-CLzyQhia.js → pug-BfN8CpEH.js} +1 -1
  121. package/dist/web/assets/{qml-BHXfGB1l.js → qml-D6fRdLZt.js} +1 -1
  122. package/dist/web/assets/query-audit-section-BA5rT6Sh.js +1 -0
  123. package/dist/web/assets/radar-KQ55EAFF-DBIZEaIU.js +1 -0
  124. package/dist/web/assets/{razor-BqetJLN3.js → razor-fg-9AScR.js} +1 -1
  125. package/dist/web/assets/remote-desktop-mobile-sheet-CPa3XElX.js +2 -0
  126. package/dist/web/assets/remote-desktop-mobile-view-De_a4skd.js +1 -0
  127. package/dist/web/assets/remote-desktop-readiness-gate-CPrDIv2d.js +1 -0
  128. package/dist/web/assets/remote-desktop-window-content-CG1StfCE.js +1 -0
  129. package/dist/web/assets/{rst-iQdJZ0BP.js → rst-BZgx076b.js} +1 -1
  130. package/dist/web/assets/{ruby-CNwzZGdH.js → ruby-iUkWDcLo.js} +1 -1
  131. package/dist/web/assets/{run-in-terminal-CBXmVGWa.js → run-in-terminal-bKRwuO2z.js} +1 -1
  132. package/dist/web/assets/{sas-BpBIT2eR.js → sas-CLXO0lZ6.js} +1 -1
  133. package/dist/web/assets/schedules-settings-section-B2f7V7Xr.js +1 -0
  134. package/dist/web/assets/{scss-D1MotuEp.js → scss-DQqteGaG.js} +1 -1
  135. package/dist/web/assets/send-Bb0jtcR6.js +1 -0
  136. package/dist/web/assets/{send-to-chat-DJAdlvJ8.js → send-to-chat-S8LCNX7V.js} +1 -1
  137. package/dist/web/assets/separator-DqGg3f9c.js +1 -0
  138. package/dist/web/assets/settings-body-omv04jbb.js +2 -0
  139. package/dist/web/assets/settings-store-Brjd0QnO.js +2 -0
  140. package/dist/web/assets/settings-tab-NdnBTqyj.js +1 -0
  141. package/dist/web/assets/settings-window-content-Chou1JGa.js +1 -0
  142. package/dist/web/assets/{shaderlab-BNqmcPQi.js → shaderlab-CeMTqagR.js} +1 -1
  143. package/dist/web/assets/{shellsession-BBLOVOO-.js → shellsession-BAkquZAV.js} +1 -1
  144. package/dist/web/assets/{soy-BpTGo9uy.js → soy-Bxm9Ez55.js} +1 -1
  145. package/dist/web/assets/{sparql-D7A3yKob.js → sparql-C1phwdLc.js} +1 -1
  146. package/dist/web/assets/sql-query-editor-Dk9y3jqy.js +1 -0
  147. package/dist/web/assets/sqlite-viewer-4xFhkLYy.js +1 -0
  148. package/dist/web/assets/{stata-B7N56ptS.js → stata-DGNMQdEb.js} +1 -1
  149. package/dist/web/assets/{surrealql-CTmnD-lv.js → surrealql-ByVrV320.js} +1 -1
  150. package/dist/web/assets/{svelte-BppwY9TR.js → svelte-CNWjIMhl.js} +1 -1
  151. package/dist/web/assets/system-monitor-body-B_1iMVOI.js +2 -0
  152. package/dist/web/assets/system-monitor-tab-B2j9mWBW.js +1 -0
  153. package/dist/web/assets/{system-monitor-window-content-B9Y98UW6.js → system-monitor-window-content-BOjq53uU.js} +1 -1
  154. package/dist/web/assets/{tab-host-window-content-C1j8zr68.js → tab-host-window-content-CW_dlYlW.js} +1 -1
  155. package/dist/web/assets/{tab-store-DzYSsw5a.js → tab-store-PZsP5ZwG.js} +1 -1
  156. package/dist/web/assets/team-member-sheet-CkR4qO7V.js +2 -0
  157. package/dist/web/assets/team-member-window-content-CmF5ia3n.js +1 -0
  158. package/dist/web/assets/{templ-CvTMKKra.js → templ-Cf0gQL4I.js} +1 -1
  159. package/dist/web/assets/{terminal-tab-B9I_HlES.js → terminal-tab-HXZkicIc.js} +3 -3
  160. package/dist/web/assets/{tex--c4POEUE.js → tex-BTIqPw_R.js} +1 -1
  161. package/dist/web/assets/tool-cards-jA1BTLZj.js +9 -0
  162. package/dist/web/assets/treemap-KZPCXAKY-DFiG9UYW.js +1 -0
  163. package/dist/web/assets/{ts-tags--kx7D-Hw.js → ts-tags-B8dN_Yf6.js} +1 -1
  164. package/dist/web/assets/{twig-UG9uMHGd.js → twig-BgemonbJ.js} +1 -1
  165. package/dist/web/assets/use-accounts-data-BI_5qNvr.js +1 -0
  166. package/dist/web/assets/{use-blob-url-Bdxopwwc.js → use-blob-url-Gfi69PtP.js} +1 -1
  167. package/dist/web/assets/use-monaco-theme-BcQqKVbE.js +1 -0
  168. package/dist/web/assets/{use-open-team-member-D9EOB8-i.js → use-open-team-member-CruUTqzD.js} +1 -1
  169. package/dist/web/assets/use-remote-desktop-display-choice-DY5BWRTo.js +1 -0
  170. package/dist/web/assets/{use-websocket-xOOwBdwP.js → use-websocket-DetaY8OI.js} +1 -1
  171. package/dist/web/assets/{vendor-mermaid-0Nt-ew76.js → vendor-mermaid-BKWscKt0.js} +1 -1
  172. package/dist/web/assets/video-preview-C0uH2228.js +1 -0
  173. package/dist/web/assets/{vue-jjTomlbt.js → vue-D3D4lbXz.js} +1 -1
  174. package/dist/web/assets/{vue-html-8KEW6-I9.js → vue-html-DYEQFAiK.js} +1 -1
  175. package/dist/web/assets/{vue-vine-C5tohCkU.js → vue-vine-D0OPNscN.js} +1 -1
  176. package/dist/web/assets/{window-pip-registry-FdZdGF7h.js → window-pip-registry-BEN0QNSW.js} +1 -1
  177. package/dist/web/assets/window-store-DGKf9rPG.js +1 -0
  178. package/dist/web/assets/ws-auth-Dawx17PM.js +1 -0
  179. package/dist/web/assets/{xml-ByFFosqL.js → xml-DHaWgpya.js} +1 -1
  180. package/dist/web/assets/{xsl-CZUwiLkj.js → xsl-DVRN8JsA.js} +1 -1
  181. package/dist/web/index.html +32 -55
  182. package/dist/web/sw.js +1 -1
  183. package/docs/codebase-summary.md +9 -5
  184. package/docs/lessons-learned.md +11 -0
  185. package/package.json +2 -2
  186. package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
  187. package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
  188. package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
  189. package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
  190. package/src/providers/codex-app-server/codex-event-mapper.ts +70 -5
  191. package/src/providers/codex-app-server/codex-history.ts +24 -0
  192. package/src/providers/codex-app-server/codex-jsonrpc-client.ts +39 -2
  193. package/src/providers/codex-app-server/codex-protocol.ts +24 -0
  194. package/src/providers/codex-app-server/codex-provider.ts +159 -17
  195. package/src/providers/codex-app-server/codex-rollout-items.ts +149 -0
  196. package/src/providers/codex-app-server/codex-skill-parser.ts +63 -0
  197. package/src/providers/codex-app-server/codex-usage-fetch.ts +22 -20
  198. package/src/providers/codex-app-server/codex-usage-source.ts +37 -0
  199. package/src/server/routes/chat.ts +67 -9
  200. package/src/server/routes/codex-accounts.ts +9 -5
  201. package/src/server/ws/chat.ts +46 -1
  202. package/src/services/claude-usage-source.ts +40 -0
  203. package/src/services/claude-usage.service.ts +77 -146
  204. package/src/services/codex-account-login.ts +123 -55
  205. package/src/services/codex-account.service.ts +27 -4
  206. package/src/services/db.service.ts +161 -20
  207. package/src/services/edge-forwarder.ts +191 -191
  208. package/src/services/fs-credential-path-guard.ts +35 -8
  209. package/src/services/fs-path-guard.service.ts +1 -0
  210. package/src/services/postgres.service.ts +144 -72
  211. package/src/services/provider-usage/index.ts +63 -0
  212. package/src/services/provider-usage/register-usage-sources.ts +18 -0
  213. package/src/services/provider-usage/usage-memory-cache.ts +71 -0
  214. package/src/services/provider-usage/usage-registry.ts +157 -0
  215. package/src/services/provider-usage/usage-scheduler.ts +117 -0
  216. package/src/services/provider-usage/usage-snapshot-store.ts +126 -0
  217. package/src/services/provider-usage/usage-source.ts +82 -0
  218. package/src/services/slash-discovery/builtin-commands.ts +13 -0
  219. package/src/services/slash-discovery/codex-skill-items.ts +57 -0
  220. package/src/services/slash-discovery/provider-skill-sigil.ts +19 -0
  221. package/src/services/slash-discovery/types.ts +19 -0
  222. package/src/services/windows-process-tree.ts +351 -351
  223. package/src/types/chat.ts +7 -1
  224. package/src/web/app.tsx +1 -7
  225. package/src/web/components/chat/chat-history-bar.tsx +10 -1
  226. package/src/web/components/chat/chat-tab.tsx +17 -1
  227. package/src/web/components/chat/message-input.tsx +11 -4
  228. package/src/web/components/chat/message-list.tsx +14 -0
  229. package/src/web/components/chat/slash-command-picker.tsx +22 -3
  230. package/src/web/components/chat/tool-cards.tsx +47 -4
  231. package/src/web/components/chat/usage-badge.tsx +43 -447
  232. package/src/web/components/floating-window/window-content-registry.ts +2 -0
  233. package/src/web/components/floating-window/window-store-types.ts +1 -1
  234. package/src/web/components/layout/command-palette.tsx +2 -2
  235. package/src/web/components/layout/mobile-drawer.tsx +5 -4
  236. package/src/web/components/layout/mobile-nav.tsx +5 -1
  237. package/src/web/components/layout/nav-section-rail.tsx +2 -1
  238. package/src/web/components/layout/project-bottom-sheet.tsx +3 -9
  239. package/src/web/components/layout/sidebar.tsx +0 -2
  240. package/src/web/components/layout/tab-pop-out-menu-item.tsx +3 -2
  241. package/src/web/components/settings/accounts/account-add-dialog.tsx +155 -0
  242. package/src/web/components/settings/accounts/account-backup-format.ts +19 -0
  243. package/src/web/components/settings/accounts/account-bucket-row.tsx +55 -0
  244. package/src/web/components/settings/accounts/account-card.tsx +127 -0
  245. package/src/web/components/settings/accounts/account-delete-confirm.tsx +62 -0
  246. package/src/web/components/settings/accounts/account-export-dialog.tsx +154 -0
  247. package/src/web/components/settings/accounts/account-export-simulation.tsx +196 -0
  248. package/src/web/components/settings/accounts/account-import-dialog.tsx +72 -0
  249. package/src/web/components/settings/accounts/account-profile-panel.tsx +52 -0
  250. package/src/web/components/{chat → settings/accounts}/account-rotation-settings.tsx +1 -1
  251. package/src/web/components/settings/accounts/account-token-test-dialog.tsx +147 -0
  252. package/src/web/components/settings/accounts/account-usage-format.ts +92 -0
  253. package/src/web/components/{chat/usage-pattern-chart.tsx → settings/accounts/account-usage-pattern-chart.tsx} +1 -1
  254. package/src/web/components/settings/accounts/accounts-pane-header.tsx +93 -0
  255. package/src/web/components/settings/accounts/accounts-settings-section.tsx +80 -0
  256. package/src/web/components/settings/accounts/claude-accounts-section.tsx +168 -0
  257. package/src/web/components/settings/accounts/codex-accounts-section.tsx +137 -0
  258. package/src/web/components/settings/accounts/codex-add-account-dialog.tsx +130 -0
  259. package/src/web/components/settings/accounts/codex-backup-dialog.tsx +101 -0
  260. package/src/web/components/settings/accounts/codex-rotation-dialog.tsx +65 -0
  261. package/src/web/components/settings/accounts/use-accounts-data.ts +81 -0
  262. package/src/web/components/settings/accounts/use-codex-accounts.ts +151 -0
  263. package/src/web/components/settings/ai-settings-section.tsx +14 -4
  264. package/src/web/components/settings/appearance-settings-section.tsx +125 -0
  265. package/src/web/components/settings/general-settings-section.tsx +87 -0
  266. package/src/web/components/settings/jira-watcher-section.tsx +34 -0
  267. package/src/web/components/settings/notifications-settings-section.tsx +37 -0
  268. package/src/web/components/settings/open-settings.ts +42 -0
  269. package/src/web/components/settings/resolve-open-settings-action.ts +45 -0
  270. package/src/web/components/settings/settings-body.tsx +110 -0
  271. package/src/web/components/settings/settings-categories.ts +102 -0
  272. package/src/web/components/settings/settings-category-list.tsx +56 -0
  273. package/src/web/components/settings/settings-category-rail.tsx +62 -0
  274. package/src/web/components/settings/settings-section-content.tsx +43 -0
  275. package/src/web/components/settings/settings-tab.tsx +15 -329
  276. package/src/web/components/settings/settings-window-content.tsx +24 -0
  277. package/src/web/hooks/use-chat.ts +38 -1
  278. package/src/web/hooks/use-global-keybindings.ts +3 -4
  279. package/src/web/hooks/use-url-sync.ts +30 -0
  280. package/src/web/hooks/use-usage.ts +23 -11
  281. package/src/web/lib/sidebar-tabs/tab-registry.ts +9 -9
  282. package/src/web/lib/slash-items-cache.ts +27 -7
  283. package/src/web/stores/panel-utils.ts +11 -0
  284. package/src/web/stores/settings-store.ts +4 -2
  285. package/src/web/stores/window-panel-actions.ts +1 -3
  286. package/src/web/stores/window-panel-persistence.ts +9 -4
  287. package/dist/web/assets/adaptive-context-menu-BbuRVTLn.js +0 -1
  288. package/dist/web/assets/ai-resource-editor-BCCOUzox.js +0 -1
  289. package/dist/web/assets/ai-settings-section-BEM1z7kp.js +0 -1
  290. package/dist/web/assets/api-client-D1CePgQ4.js +0 -1
  291. package/dist/web/assets/api-settings-CNtKkHqW.js +0 -1
  292. package/dist/web/assets/api-settings-Cubuqjsu.js +0 -1
  293. package/dist/web/assets/architecture-PBZL5I3N-6konx-J1.js +0 -1
  294. package/dist/web/assets/chat-tab-CmXGsJGc.js +0 -15
  295. package/dist/web/assets/clipboard-B-gwJ8DF.js +0 -1
  296. package/dist/web/assets/code-editor-DtHXzNZ1.js +0 -7
  297. package/dist/web/assets/context-menu-DfWZAxQy.js +0 -1
  298. package/dist/web/assets/database-viewer-GVaQVMdb.js +0 -1
  299. package/dist/web/assets/dialog-BSfuiTkJ.js +0 -1
  300. package/dist/web/assets/diff-viewer-BG5_fH1E.js +0 -4
  301. package/dist/web/assets/explorer-body-BPFnjxYj.js +0 -2
  302. package/dist/web/assets/explorer-window-content-Da1T9uM4.js +0 -1
  303. package/dist/web/assets/extension-store-Bhu--fPX.js +0 -1
  304. package/dist/web/assets/external-link-B6Hl0U4X.js +0 -1
  305. package/dist/web/assets/eye-off-CUdzgmX8.js +0 -1
  306. package/dist/web/assets/file-store-6HW2Lfl4.js +0 -1
  307. package/dist/web/assets/git-log-panel-DNC9fV0M.js +0 -1
  308. package/dist/web/assets/gitGraph-HDMCJU4V-ikUwsekd.js +0 -1
  309. package/dist/web/assets/group-chat-tab-DbUkcOaJ.js +0 -1
  310. package/dist/web/assets/index-DTqbMiVc.js +0 -52
  311. package/dist/web/assets/index-SFFv2-VM.css +0 -2
  312. package/dist/web/assets/info-3K5VOQVL-BAgmboBp.js +0 -1
  313. package/dist/web/assets/input-D0ol5jW0.js +0 -1
  314. package/dist/web/assets/keybindings-store-BGkB72gM.js +0 -1
  315. package/dist/web/assets/keybindings-store-Bq6VWl5X.js +0 -1
  316. package/dist/web/assets/lock-CNxUGpTk.js +0 -1
  317. package/dist/web/assets/markdown-renderer-DEAVpo0C.js +0 -1
  318. package/dist/web/assets/mobile-explorer-sheet-CD_kl-jA.js +0 -1
  319. package/dist/web/assets/monitor-smartphone-DLZ6Q05s.js +0 -1
  320. package/dist/web/assets/notification-store-Dgbsw9p9.js +0 -1
  321. package/dist/web/assets/packet-RMMSAZCW-RVlbbDRS.js +0 -1
  322. package/dist/web/assets/panel-store-UOV8wrfR.js +0 -1
  323. package/dist/web/assets/pdf-preview-B2CJ_EKv.js +0 -1
  324. package/dist/web/assets/pie-UPGHQEXC-ZWb4izpk.js +0 -1
  325. package/dist/web/assets/play-DpEEBJTT.js +0 -1
  326. package/dist/web/assets/radar-KQ55EAFF-bsP5x1Bx.js +0 -1
  327. package/dist/web/assets/refresh-cw-BQU5g2CY.js +0 -1
  328. package/dist/web/assets/remote-desktop-mobile-sheet-KKTRNjOL.js +0 -2
  329. package/dist/web/assets/remote-desktop-mobile-view-C1ST4-Fm.js +0 -1
  330. package/dist/web/assets/remote-desktop-readiness-gate-BH3BE5wA.js +0 -1
  331. package/dist/web/assets/remote-desktop-window-content-BaZJQt_N.js +0 -1
  332. package/dist/web/assets/rotate-ccw-CpjRo90J.js +0 -1
  333. package/dist/web/assets/scroll-area-lc0ZHORr.js +0 -1
  334. package/dist/web/assets/send-C_sLFt56.js +0 -1
  335. package/dist/web/assets/settings-store-zbPkG7o-.js +0 -2
  336. package/dist/web/assets/settings-tab-Cn-AqUP_.js +0 -1
  337. package/dist/web/assets/settings-tab-xyRpt2gq.js +0 -3
  338. package/dist/web/assets/shallow-CmPMAPte.js +0 -1
  339. package/dist/web/assets/sql-query-editor-B86NiZHI.js +0 -1
  340. package/dist/web/assets/sqlite-viewer-DB775F6C.js +0 -1
  341. package/dist/web/assets/switch-BmjKoIpR.js +0 -1
  342. package/dist/web/assets/system-monitor-body-BDxHQvy9.js +0 -2
  343. package/dist/web/assets/system-monitor-tab-BoTHLx6B.js +0 -1
  344. package/dist/web/assets/team-member-sheet-Cxz6h5Ne.js +0 -2
  345. package/dist/web/assets/team-member-window-content-CUSuRHCB.js +0 -1
  346. package/dist/web/assets/tool-cards-D3KSzd2K.js +0 -8
  347. package/dist/web/assets/trash-2-By4VMbC4.js +0 -1
  348. package/dist/web/assets/treemap-KZPCXAKY-Dh1oxNdQ.js +0 -1
  349. package/dist/web/assets/triangle-alert-CUTURFbG.js +0 -1
  350. package/dist/web/assets/upload-BNlX8D07.js +0 -1
  351. package/dist/web/assets/use-monaco-theme-CVCye2kq.js +0 -1
  352. package/dist/web/assets/use-remote-desktop-display-choice-neUqyE3p.js +0 -1
  353. package/dist/web/assets/video-preview-DvpgBDhM.js +0 -1
  354. package/dist/web/assets/window-store-D0x_fxr0.js +0 -1
  355. package/src/web/components/chat/account-dialogs.tsx +0 -384
  356. package/src/web/components/settings/accounts-settings-section.tsx +0 -1090
  357. package/src/web/components/settings/codex-accounts-section.tsx +0 -198
  358. package/src/web/components/settings/telegram-settings-section.tsx +0 -113
  359. /package/dist/web/assets/{abap-C5DFF0s3.js → abap-h3QyH8MW.js} +0 -0
  360. /package/dist/web/assets/{actionscript-3-B0qyRNbc.js → actionscript-3-mkxkq-FN.js} +0 -0
  361. /package/dist/web/assets/{ada-bAJzplug.js → ada-DhISK_EH.js} +0 -0
  362. /package/dist/web/assets/{andromeeda-DUCpISy6.js → andromeeda-DnlWWesX.js} +0 -0
  363. /package/dist/web/assets/{apache-BhAr84Z_.js → apache-P5AK3sfA.js} +0 -0
  364. /package/dist/web/assets/{apex-CRv8YnNq.js → apex-CJUPehg2.js} +0 -0
  365. /package/dist/web/assets/{api-client-BzWM7XPR.js → api-client-oY1tC3tM.js} +0 -0
  366. /package/dist/web/assets/{applescript-CD-Cw8bt.js → applescript-Dx6GGbay.js} +0 -0
  367. /package/dist/web/assets/{apply-theme-DJ794zSQ.js → apply-theme-DxTXOAcV.js} +0 -0
  368. /package/dist/web/assets/{ara-BUzeQYoG.js → ara-95Kx3qKb.js} +0 -0
  369. /package/dist/web/assets/{asciidoc-CT2hTg-v.js → asciidoc-Dp0RbIej.js} +0 -0
  370. /package/dist/web/assets/{asm-CAu35JeY.js → asm-C82coUjU.js} +0 -0
  371. /package/dist/web/assets/{aurora-x-BeFJoIA1.js → aurora-x-BFc3zeop.js} +0 -0
  372. /package/dist/web/assets/{awk-Vau-DrGN.js → awk-ChjC0icr.js} +0 -0
  373. /package/dist/web/assets/{ayu-dark-CLe-OTsQ.js → ayu-dark-DYfUf_PB.js} +0 -0
  374. /package/dist/web/assets/{ayu-light-CJbQfu4M.js → ayu-light-Bh6O0plO.js} +0 -0
  375. /package/dist/web/assets/{ayu-mirage-GWaKwdrx.js → ayu-mirage-DlNhHTGq.js} +0 -0
  376. /package/dist/web/assets/{ballerina-DWu0USI5.js → ballerina-Ceoll3Sk.js} +0 -0
  377. /package/dist/web/assets/{bat-_07Huw7E.js → bat-C7QS6Lfq.js} +0 -0
  378. /package/dist/web/assets/{beancount-EcvogrcF.js → beancount-5NMEAZgs.js} +0 -0
  379. /package/dist/web/assets/{berry-BBB87SY7.js → berry-BBL83Vbk.js} +0 -0
  380. /package/dist/web/assets/{bibtex-DbueS87A.js → bibtex-L7rPkPSG.js} +0 -0
  381. /package/dist/web/assets/{bicep-tcmXnUo4.js → bicep-BOwHIINh.js} +0 -0
  382. /package/dist/web/assets/{bird2-B2qwilIR.js → bird2-CWLsMom2.js} +0 -0
  383. /package/dist/web/assets/{c-Z58oivSt.js → c-CD4Ku5Cr.js} +0 -0
  384. /package/dist/web/assets/{c3-U40cGT9p.js → c3-CpMl-w3G.js} +0 -0
  385. /package/dist/web/assets/{cadence-BFcD-LyM.js → cadence-CvgF6ehN.js} +0 -0
  386. /package/dist/web/assets/{can-open-in-ppm-CdCK2c2a.js → can-open-in-ppm-j3jh7fUo.js} +0 -0
  387. /package/dist/web/assets/{catppuccin-frappe-RkC9AX6J.js → catppuccin-frappe-eo_dTm3F.js} +0 -0
  388. /package/dist/web/assets/{catppuccin-latte-Bsi4l-nO.js → catppuccin-latte-DoiMCU_7.js} +0 -0
  389. /package/dist/web/assets/{catppuccin-macchiato-B8JIdTW-.js → catppuccin-macchiato-UQxsK2Vh.js} +0 -0
  390. /package/dist/web/assets/{catppuccin-mocha-oH8wwrDj.js → catppuccin-mocha-J0i-8RNy.js} +0 -0
  391. /package/dist/web/assets/{clarity-C3WNeRCR.js → clarity-DXYM8-SA.js} +0 -0
  392. /package/dist/web/assets/{clojure-CFoAz7u9.js → clojure-DzamsL69.js} +0 -0
  393. /package/dist/web/assets/{cmake-Bcsqp9yR.js → cmake-CR6RP_T_.js} +0 -0
  394. /package/dist/web/assets/{codeowners-DC2Z7heP.js → codeowners-D1s6-IyY.js} +0 -0
  395. /package/dist/web/assets/{codeql-BfG68Al5.js → codeql-DAqNWMkS.js} +0 -0
  396. /package/dist/web/assets/{common-lisp-Z5P-lKQe.js → common-lisp-8e-KtitB.js} +0 -0
  397. /package/dist/web/assets/{coq-BJslqrnv.js → coq-UEq0WUcO.js} +0 -0
  398. /package/dist/web/assets/{csharp-DhhZTOTs.js → csharp-wxJ0TuCm.js} +0 -0
  399. /package/dist/web/assets/{css-DiFIpMfE.js → css-Cerub-yB.js} +0 -0
  400. /package/dist/web/assets/{csv-DViLbHxI.js → csv-Bh9_WD_h.js} +0 -0
  401. /package/dist/web/assets/{csv-parser-B2v8MoUy.js → csv-parser-BPIDt6ni.js} +0 -0
  402. /package/dist/web/assets/{cue-CoG3mg2I.js → cue-rzM1ztqU.js} +0 -0
  403. /package/dist/web/assets/{cypher-jTxC8NAB.js → cypher-DGaTQ8m0.js} +0 -0
  404. /package/dist/web/assets/{d-6hKIUAbU.js → d-DbkZGuhB.js} +0 -0
  405. /package/dist/web/assets/{dark-plus-D_-np2Sr.js → dark-plus-BO2bzZcA.js} +0 -0
  406. /package/dist/web/assets/{dart-CVpxLpVn.js → dart-BDhCoqVg.js} +0 -0
  407. /package/dist/web/assets/{data-grid-types-Dq_H1IPa.js → data-grid-types-CdAg-4W1.js} +0 -0
  408. /package/dist/web/assets/{dax-BPqJ8qIY.js → dax-Bh03stWh.js} +0 -0
  409. /package/dist/web/assets/{desktop-u_y5_Hr5.js → desktop-BOdr_fwq.js} +0 -0
  410. /package/dist/web/assets/{diff-Duj1XMrd.js → diff-Bb_gTsS2.js} +0 -0
  411. /package/dist/web/assets/{dist-CEZ4plgH.js → dist-BUMDu0av.js} +0 -0
  412. /package/dist/web/assets/{dist-aDSxTR_v.js → dist-DonmFWG8.js} +0 -0
  413. /package/dist/web/assets/{docker-8UGSCc7N.js → docker-BDsTF5ce.js} +0 -0
  414. /package/dist/web/assets/{dotenv-DVnj8kyR.js → dotenv-CbCWp9Ti.js} +0 -0
  415. /package/dist/web/assets/{dracula-D0cEmSg7.js → dracula-Cd1fxvoX.js} +0 -0
  416. /package/dist/web/assets/{dracula-soft-DfGS5Yfr.js → dracula-soft-B7eXkfXG.js} +0 -0
  417. /package/dist/web/assets/{dream-maker-qG8kMGTF.js → dream-maker-XlzuS21R.js} +0 -0
  418. /package/dist/web/assets/{emacs-lisp-iVqyMLyT.js → emacs-lisp-CXV1Ki_7.js} +0 -0
  419. /package/dist/web/assets/{everforest-dark-Cruygd5U.js → everforest-dark-DuqR60Dg.js} +0 -0
  420. /package/dist/web/assets/{everforest-light-BiJa8RHL.js → everforest-light-q4BPnenD.js} +0 -0
  421. /package/dist/web/assets/{fennel-H6XSEIoz.js → fennel-B-e0TX2Q.js} +0 -0
  422. /package/dist/web/assets/{fish-ho_7CxX6.js → fish-Bzb6-TtF.js} +0 -0
  423. /package/dist/web/assets/{fluent-1l5ssJTF.js → fluent-B-szH2-f.js} +0 -0
  424. /package/dist/web/assets/{folder-symlink-Dx1hOk8X.js → folder-symlink-fQRoG_rV.js} +0 -0
  425. /package/dist/web/assets/{format-bytes-gQw5wzqa.js → format-bytes-CKXk9k2d.js} +0 -0
  426. /package/dist/web/assets/{fortran-free-form-Bo1x233A.js → fortran-free-form-OS6SGYC0.js} +0 -0
  427. /package/dist/web/assets/{gdscript-DffFMp_k.js → gdscript-FYq4OP2d.js} +0 -0
  428. /package/dist/web/assets/{gdshader-CvnpAiAF.js → gdshader-BpG6P8rw.js} +0 -0
  429. /package/dist/web/assets/{genie-2eOvAEzW.js → genie-BS9RLAna.js} +0 -0
  430. /package/dist/web/assets/{gherkin-DL-5OUlV.js → gherkin-B_9FdtGs.js} +0 -0
  431. /package/dist/web/assets/{github-dark-DrTZprgG.js → github-dark-cfaIlnBV.js} +0 -0
  432. /package/dist/web/assets/{github-dark-default-_mDH8IMP.js → github-dark-default-B2Wv65He.js} +0 -0
  433. /package/dist/web/assets/{github-dark-dimmed-C48hJuLn.js → github-dark-dimmed-CtM9X76s.js} +0 -0
  434. /package/dist/web/assets/{github-dark-high-contrast-BQ-zGGNe.js → github-dark-high-contrast-DLHyk0tG.js} +0 -0
  435. /package/dist/web/assets/{github-light-BYc90Yx8.js → github-light-DWEI10iG.js} +0 -0
  436. /package/dist/web/assets/{github-light-default-Daecj4J5.js → github-light-default-DcJkK1YN.js} +0 -0
  437. /package/dist/web/assets/{github-light-high-contrast-DoafCbsU.js → github-light-high-contrast-Bcx9iKDt.js} +0 -0
  438. /package/dist/web/assets/{gleam-hUWWjmnp.js → gleam-DVpiM6b2.js} +0 -0
  439. /package/dist/web/assets/{gn-7PJ3R70o.js → gn-B80DNc0i.js} +0 -0
  440. /package/dist/web/assets/{gnuplot-V-Pxck7b.js → gnuplot-D9i3MaT-.js} +0 -0
  441. /package/dist/web/assets/{go-ARF6DprD.js → go-CwCBf_Pt.js} +0 -0
  442. /package/dist/web/assets/{groovy-CKGBIPOz.js → groovy-D7mEfwmW.js} +0 -0
  443. /package/dist/web/assets/{gruvbox-dark-hard-Cm9wqdI3.js → gruvbox-dark-hard-C4R4MOoH.js} +0 -0
  444. /package/dist/web/assets/{gruvbox-dark-medium-Cmsd6dG8.js → gruvbox-dark-medium-CZnFC0s8.js} +0 -0
  445. /package/dist/web/assets/{gruvbox-dark-soft-BBGlGGCz.js → gruvbox-dark-soft-DFcJlEBl.js} +0 -0
  446. /package/dist/web/assets/{gruvbox-light-hard-BCR7KmqG.js → gruvbox-light-hard-B6IF_1L-.js} +0 -0
  447. /package/dist/web/assets/{gruvbox-light-medium-CP32bga8.js → gruvbox-light-medium-C19AZJv2.js} +0 -0
  448. /package/dist/web/assets/{gruvbox-light-soft-qjxk8ps6.js → gruvbox-light-soft-BAnpDm9B.js} +0 -0
  449. /package/dist/web/assets/{haskell-C5DzwGRa.js → haskell-CsXSYXRG.js} +0 -0
  450. /package/dist/web/assets/{haxe-C8f_jCVv.js → haxe-B1uyiI9t.js} +0 -0
  451. /package/dist/web/assets/{hcl-DetJkf6E.js → hcl-DlYKn5q9.js} +0 -0
  452. /package/dist/web/assets/{hjson-DeZhwIdo.js → hjson-C_0VMGJJ.js} +0 -0
  453. /package/dist/web/assets/{hlsl-SMIDLRyX.js → hlsl-zt2PEzbg.js} +0 -0
  454. /package/dist/web/assets/{horizon-BMAVDxMx.js → horizon-6wQfyOK0.js} +0 -0
  455. /package/dist/web/assets/{horizon-bright-3BaV_VGD.js → horizon-bright-CqI2qTim.js} +0 -0
  456. /package/dist/web/assets/{houston-BWBbEPvb.js → houston-BljpHDoG.js} +0 -0
  457. /package/dist/web/assets/{hy-DcsmE-Nm.js → hy-XzuL55dw.js} +0 -0
  458. /package/dist/web/assets/{image-gallery-Bqb-wjNw.js → image-gallery-Cj8nd4xW.js} +0 -0
  459. /package/dist/web/assets/{imba-CnkgnYMf.js → imba-CqhhjBrP.js} +0 -0
  460. /package/dist/web/assets/{ini-BnvTdau7.js → ini-CiFDi6cY.js} +0 -0
  461. /package/dist/web/assets/{java-BLFACXat.js → java-OsQgTL5-.js} +0 -0
  462. /package/dist/web/assets/{javascript-BKcFWENk.js → javascript-qWAOScxl.js} +0 -0
  463. /package/dist/web/assets/{json-3AJtJADf.js → json-RiAKsaD1.js} +0 -0
  464. /package/dist/web/assets/{json5-DLyDVlwe.js → json5-BeCnS3H2.js} +0 -0
  465. /package/dist/web/assets/{jsonc-B5DgF1jW.js → jsonc-CbTW1Mka.js} +0 -0
  466. /package/dist/web/assets/{jsonl-CV_O71a2.js → jsonl-BLSi_669.js} +0 -0
  467. /package/dist/web/assets/{jsonnet-DZfPLgYz.js → jsonnet-C3xAggou.js} +0 -0
  468. /package/dist/web/assets/{jssm-Cr1zYOsY.js → jssm-CLdiagC9.js} +0 -0
  469. /package/dist/web/assets/{jsx-VN-JS2_q.js → jsx-lYE1lb50.js} +0 -0
  470. /package/dist/web/assets/{kanagawa-dragon-D9CcT3xg.js → kanagawa-dragon-Cd1vcrpD.js} +0 -0
  471. /package/dist/web/assets/{kanagawa-lotus-DLXsB8fr.js → kanagawa-lotus-Dw3QKtk9.js} +0 -0
  472. /package/dist/web/assets/{kanagawa-wave-weDs3Wjz.js → kanagawa-wave-DIq5Zv5G.js} +0 -0
  473. /package/dist/web/assets/{kdl-0XF56jnT.js → kdl-BfDV0825.js} +0 -0
  474. /package/dist/web/assets/{keyboard-DBBaoQSu.js → keyboard-DiOYrs6C.js} +0 -0
  475. /package/dist/web/assets/{kotlin-BPkH9vzk.js → kotlin-DONxR4wD.js} +0 -0
  476. /package/dist/web/assets/{kusto-DMVpADb9.js → kusto-BDP63Fh5.js} +0 -0
  477. /package/dist/web/assets/{laserwave-Cl6T2cGP.js → laserwave-BeBrWApL.js} +0 -0
  478. /package/dist/web/assets/{lean-BvwzQGl1.js → lean-DOZc0N1A.js} +0 -0
  479. /package/dist/web/assets/{less-DI_03xkC.js → less-C3H9NlDv.js} +0 -0
  480. /package/dist/web/assets/{lib-v9x_qXgI.js → lib-xrSJ4EZX.js} +0 -0
  481. /package/dist/web/assets/{libesm-dcbw4_18.js → libesm-DLBE59ul.js} +0 -0
  482. /package/dist/web/assets/{light-plus-hIiIsQN_.js → light-plus-C_kTL608.js} +0 -0
  483. /package/dist/web/assets/{llvm-B5hjjSWc.js → llvm-Dsp27U3P.js} +0 -0
  484. /package/dist/web/assets/{loader-circle-DouKgIXy.js → loader-circle-DPMrnLQ2.js} +0 -0
  485. /package/dist/web/assets/{log-D28raQiE.js → log-BywQaTCy.js} +0 -0
  486. /package/dist/web/assets/{logo-6Cdd4ASb.js → logo-BirJgciO.js} +0 -0
  487. /package/dist/web/assets/{luau-CK9nKpOX.js → luau-Btrz5kJB.js} +0 -0
  488. /package/dist/web/assets/{make-CVnxKCB6.js → make-Kl7nFQrS.js} +0 -0
  489. /package/dist/web/assets/{markdown-B9mMQzD5.js → markdown-qsC4P8S-.js} +0 -0
  490. /package/dist/web/assets/{material-theme-BZSs2o0j.js → material-theme-CC__ui3p.js} +0 -0
  491. /package/dist/web/assets/{material-theme-darker-BeAQBzQ_.js → material-theme-darker-D4FxG2FZ.js} +0 -0
  492. /package/dist/web/assets/{material-theme-lighter-BAe0IXcs.js → material-theme-lighter-zGqiWcxn.js} +0 -0
  493. /package/dist/web/assets/{material-theme-ocean-CiPIf0Np.js → material-theme-ocean-CZIdTTB1.js} +0 -0
  494. /package/dist/web/assets/{material-theme-palenight-DJBb4_XN.js → material-theme-palenight-CEIs0GcK.js} +0 -0
  495. /package/dist/web/assets/{matlab-CY0dbp_s.js → matlab-Cf0aUjN9.js} +0 -0
  496. /package/dist/web/assets/{mdx-DU9zbF7h.js → mdx-CIsXjH86.js} +0 -0
  497. /package/dist/web/assets/{mermaid-UmmjGwdh.js → mermaid-B06WO9Qc.js} +0 -0
  498. /package/dist/web/assets/{min-dark-C59GkzOm.js → min-dark-z8fyp0FT.js} +0 -0
  499. /package/dist/web/assets/{min-light-B9QglrdQ.js → min-light-Dr-qesbW.js} +0 -0
  500. /package/dist/web/assets/{mipsasm-Dc6Jsr_D.js → mipsasm-CWHzYLcE.js} +0 -0
  501. /package/dist/web/assets/{mojo-D5ij-nGW.js → mojo-D9zXrKmv.js} +0 -0
  502. /package/dist/web/assets/{monitor-CxPV_fQI.js → monitor-C835ucWH.js} +0 -0
  503. /package/dist/web/assets/{monokai-QAtE_yCP.js → monokai-4b-AKOpX.js} +0 -0
  504. /package/dist/web/assets/{moonbit-BMtIdiTL.js → moonbit-Dl4dhOZJ.js} +0 -0
  505. /package/dist/web/assets/{move-BB_jMHYZ.js → move-DTYKJmXy.js} +0 -0
  506. /package/dist/web/assets/{narrat-BvvoKGVn.js → narrat-DnvXOS-o.js} +0 -0
  507. /package/dist/web/assets/{nextflow-groovy-CqxtAsnF.js → nextflow-groovy-Di8QnEXg.js} +0 -0
  508. /package/dist/web/assets/{night-owl-CLoE9kjt.js → night-owl-Czh0yq-H.js} +0 -0
  509. /package/dist/web/assets/{night-owl-light-BwIFT5Xd.js → night-owl-light-D_OpZqOR.js} +0 -0
  510. /package/dist/web/assets/{nix-BKlnVT9r.js → nix-2MvcjpK3.js} +0 -0
  511. /package/dist/web/assets/{nord-B7R1KRAK.js → nord-CG_r4cyk.js} +0 -0
  512. /package/dist/web/assets/{nushell-CzUme-NJ.js → nushell-DINskMcU.js} +0 -0
  513. /package/dist/web/assets/{objective-c-D-UKKiOc.js → objective-c-Dv7BIicR.js} +0 -0
  514. /package/dist/web/assets/{objective-cpp-BucWn4Fx.js → objective-cpp-CpqsCxPb.js} +0 -0
  515. /package/dist/web/assets/{ocaml-EJCNXMGo.js → ocaml-DwTsYSmW.js} +0 -0
  516. /package/dist/web/assets/{odin-CEjnRU_3.js → odin-G-4O4k4t.js} +0 -0
  517. /package/dist/web/assets/{one-dark-pro-Bv469NX5.js → one-dark-pro-13Pv5SjI.js} +0 -0
  518. /package/dist/web/assets/{one-light-BlzO5RWI.js → one-light-Bi2e86mS.js} +0 -0
  519. /package/dist/web/assets/{openscad-Czl6alLw.js → openscad-D0WsOTij.js} +0 -0
  520. /package/dist/web/assets/{pascal-BI9fLvG4.js → pascal-DmDStuXr.js} +0 -0
  521. /package/dist/web/assets/{pkl-ChQLsyjU.js → pkl-Bl6Qjtuo.js} +0 -0
  522. /package/dist/web/assets/{plastic-DGL3mtdL.js → plastic-UeSVSjTI.js} +0 -0
  523. /package/dist/web/assets/{plsql-BJDjqcWp.js → plsql-DreFC689.js} +0 -0
  524. /package/dist/web/assets/{po-DK5O3OpF.js → po-ZIjccxsX.js} +0 -0
  525. /package/dist/web/assets/{poimandres-CnuqZT4T.js → poimandres-CvQHJPrI.js} +0 -0
  526. /package/dist/web/assets/{polar-DCsUxSsQ.js → polar-BrMB0Kgh.js} +0 -0
  527. /package/dist/web/assets/{portal-container-context-D-495m5C.js → portal-container-context-a399Hd9F.js} +0 -0
  528. /package/dist/web/assets/{postcss-8UjdFmis.js → postcss-pgUsil1T.js} +0 -0
  529. /package/dist/web/assets/{powerquery-CAp0CGQj.js → powerquery-CTsZkCg_.js} +0 -0
  530. /package/dist/web/assets/{powershell-CbBsKZJP.js → powershell-CcwVuBAp.js} +0 -0
  531. /package/dist/web/assets/{prisma-BnNpXCJN.js → prisma-spjnAI5W.js} +0 -0
  532. /package/dist/web/assets/{prolog-CC-l9E8Y.js → prolog-ChCkZpDO.js} +0 -0
  533. /package/dist/web/assets/{proto-CV_1k2rL.js → proto-wVGqK4gB.js} +0 -0
  534. /package/dist/web/assets/{puppet-2D8HU2bv.js → puppet-CED7iwPQ.js} +0 -0
  535. /package/dist/web/assets/{purescript-BEJAORgU.js → purescript-u9lGiQKV.js} +0 -0
  536. /package/dist/web/assets/{python-BBdbb7nn.js → python-DeqTx6ef.js} +0 -0
  537. /package/dist/web/assets/{qmldir-D5ZYI4Ie.js → qmldir-BH1uoPrX.js} +0 -0
  538. /package/dist/web/assets/{qss-BOJVGyXE.js → qss-CUVKA_13.js} +0 -0
  539. /package/dist/web/assets/{r-B5dlEtkj.js → r-BqdPzqYH.js} +0 -0
  540. /package/dist/web/assets/{racket-BUAEygJ6.js → racket-C2eTgPN3.js} +0 -0
  541. /package/dist/web/assets/{raku-BG0Ss0ID.js → raku-uAay1sWx.js} +0 -0
  542. /package/dist/web/assets/{react-B549sK_T.js → react-X4jUntEf.js} +0 -0
  543. /package/dist/web/assets/{red-C5yyQbtG.js → red-DTZP1ZfC.js} +0 -0
  544. /package/dist/web/assets/{reg-DHoBWtLf.js → reg-Cdk3YsxY.js} +0 -0
  545. /package/dist/web/assets/{regexp-DDtJrlKv.js → regexp-Bpa2aS7K.js} +0 -0
  546. /package/dist/web/assets/{rel-CR6WJDRD.js → rel-bNsb1-3L.js} +0 -0
  547. /package/dist/web/assets/{resolve-theme-4fexHWl6.js → resolve-theme-DQk_YcsT.js} +0 -0
  548. /package/dist/web/assets/{riscv-2V9tC-nx.js → riscv-DSaubByW.js} +0 -0
  549. /package/dist/web/assets/{ron-QLTmqGUw.js → ron-DbQzYM6i.js} +0 -0
  550. /package/dist/web/assets/{rose-pine-be0__X3A.js → rose-pine-C7RsprTu.js} +0 -0
  551. /package/dist/web/assets/{rose-pine-dawn-n_WQJwsW.js → rose-pine-dawn-VP976YzL.js} +0 -0
  552. /package/dist/web/assets/{rose-pine-moon-t2aLtzgB.js → rose-pine-moon-XHZNhOqd.js} +0 -0
  553. /package/dist/web/assets/{rosmsg-Ce1JD8vt.js → rosmsg-BVQlx0Lj.js} +0 -0
  554. /package/dist/web/assets/{rust-5fHH-ZoW.js → rust-VHaQ3rh3.js} +0 -0
  555. /package/dist/web/assets/{sass-DPmGFiOJ.js → sass-CO-kMkwD.js} +0 -0
  556. /package/dist/web/assets/{save-DYLiVzU8.js → save-CipGrG1k.js} +0 -0
  557. /package/dist/web/assets/{scala-BRMVFbZF.js → scala-cY0GXkiz.js} +0 -0
  558. /package/dist/web/assets/{scheme-BMSJWevF.js → scheme-D4LNZE0X.js} +0 -0
  559. /package/dist/web/assets/{sdbl-DTZ-pEHI.js → sdbl-Bh2Fd2cn.js} +0 -0
  560. /package/dist/web/assets/{shellscript-6-9yg5Cz.js → shellscript-KKclmCnt.js} +0 -0
  561. /package/dist/web/assets/{shield-check-CUI36aSc.js → shield-check-BsG3LV8i.js} +0 -0
  562. /package/dist/web/assets/{shield-off-GdkkVhb3.js → shield-off-7jKWpJBD.js} +0 -0
  563. /package/dist/web/assets/{slack-dark-DKJgiR7e.js → slack-dark-D6YQ-fqf.js} +0 -0
  564. /package/dist/web/assets/{slack-ochin-WjehVgyK.js → slack-ochin-CDf66CDj.js} +0 -0
  565. /package/dist/web/assets/{smalltalk-BChf4SN1.js → smalltalk-D2OH_QIl.js} +0 -0
  566. /package/dist/web/assets/{snazzy-light-C1WAwOx6.js → snazzy-light-CQeF8G1K.js} +0 -0
  567. /package/dist/web/assets/{solarized-dark-BxREZrGx.js → solarized-dark-LTPf1iLZ.js} +0 -0
  568. /package/dist/web/assets/{solarized-light-DG29B1pR.js → solarized-light-Ose1n88k.js} +0 -0
  569. /package/dist/web/assets/{solidity-bDbtGwdR.js → solidity-lFuOMHki.js} +0 -0
  570. /package/dist/web/assets/{splunk-Ceqx5njI.js → splunk-Bov-sB5S.js} +0 -0
  571. /package/dist/web/assets/{sql-OwMEKbz8.js → sql-BKyZ6wmk.js} +0 -0
  572. /package/dist/web/assets/{ssh-config-WAR3lu2k.js → ssh-config-CqJoMGMb.js} +0 -0
  573. /package/dist/web/assets/{stylus-Cjmoz3d8.js → stylus-Bf5pWRLI.js} +0 -0
  574. /package/dist/web/assets/{swift-S_ZSBG1q.js → swift-D5d1hn_u.js} +0 -0
  575. /package/dist/web/assets/{synthwave-84-DiUeWMSh.js → synthwave-84-B4c6YAgO.js} +0 -0
  576. /package/dist/web/assets/{system-verilog-RRjqPjUV.js → system-verilog-D7fXyDsI.js} +0 -0
  577. /package/dist/web/assets/{systemd-BD3SkXoU.js → systemd-oNagzlBK.js} +0 -0
  578. /package/dist/web/assets/{table-D5Q4ap4W.js → table-CRJsmfeg.js} +0 -0
  579. /package/dist/web/assets/{talonscript-DWefISOm.js → talonscript-C6Nqm9Dm.js} +0 -0
  580. /package/dist/web/assets/{tasl-DCjSS-09.js → tasl-CaWy-cBX.js} +0 -0
  581. /package/dist/web/assets/{tcl-DTYqT_66.js → tcl-C435P5Mq.js} +0 -0
  582. /package/dist/web/assets/{terraform-CkbP5QnR.js → terraform-CVDxqdPf.js} +0 -0
  583. /package/dist/web/assets/{text-wrap-DBvQD3kc.js → text-wrap-oiekm5SB.js} +0 -0
  584. /package/dist/web/assets/{tokyo-night-qVSqO9xy.js → tokyo-night-Uhs17tQ3.js} +0 -0
  585. /package/dist/web/assets/{toml-D9F5Osqs.js → toml-j6fPOJ6P.js} +0 -0
  586. /package/dist/web/assets/{tsv-C5tpHoxm.js → tsv-h78O6xrL.js} +0 -0
  587. /package/dist/web/assets/{tsx-CMWkGtGm.js → tsx-Bol-vCrQ.js} +0 -0
  588. /package/dist/web/assets/{turtle-Cn4z3xOi.js → turtle-Dw8eFf04.js} +0 -0
  589. /package/dist/web/assets/{typescript-DSyAEWsn.js → typescript-Dtz7DPci.js} +0 -0
  590. /package/dist/web/assets/{typespec-B93Qap7y.js → typespec-BIOQ7dMP.js} +0 -0
  591. /package/dist/web/assets/{typst-DtlOmFlX.js → typst-CoaGMjzu.js} +0 -0
  592. /package/dist/web/assets/{use-is-mobile-B9UZNwSm.js → use-is-mobile-CYW3FJFE.js} +0 -0
  593. /package/dist/web/assets/{use-visual-viewport-Sfb6CZ80.js → use-visual-viewport-rnvuooQZ.js} +0 -0
  594. /package/dist/web/assets/{utils-QHe_Q6UF.js → utils-C9OjCrou.js} +0 -0
  595. /package/dist/web/assets/{v-Dfzf-szS.js → v-BoqFdpJ7.js} +0 -0
  596. /package/dist/web/assets/{vala-CyiQZQ9f.js → vala-COBpNnCC.js} +0 -0
  597. /package/dist/web/assets/{vb-C7DGSldd.js → vb-DxI86znh.js} +0 -0
  598. /package/dist/web/assets/{vendor-xterm-BHKF_Nsf.js → vendor-xterm-BaMOj65g.js} +0 -0
  599. /package/dist/web/assets/{verilog-kF-hClY2.js → verilog-DcTAamuQ.js} +0 -0
  600. /package/dist/web/assets/{vesper-BmKcADuz.js → vesper-DO298JSv.js} +0 -0
  601. /package/dist/web/assets/{vhdl-CDnb16KJ.js → vhdl-Dq-bDVSN.js} +0 -0
  602. /package/dist/web/assets/{viml-B8cs6Ady.js → viml-zHTRWuQh.js} +0 -0
  603. /package/dist/web/assets/{vitesse-black-BR6o9Gto.js → vitesse-black-jlYMJCBf.js} +0 -0
  604. /package/dist/web/assets/{vitesse-dark-Dye14-KB.js → vitesse-dark-DS0sUlSZ.js} +0 -0
  605. /package/dist/web/assets/{vitesse-light-BLpswIxf.js → vitesse-light-HSeZ2YhG.js} +0 -0
  606. /package/dist/web/assets/{vyper-DU51Z97W.js → vyper-BQfKVO3M.js} +0 -0
  607. /package/dist/web/assets/{wasm-ChtccNfv.js → wasm-B1xp9bLp.js} +0 -0
  608. /package/dist/web/assets/{wasm-CVqlJAR2.js → wasm-B6mCuI8h.js} +0 -0
  609. /package/dist/web/assets/{wenyan-DhCa3hCn.js → wenyan-CfpS05sP.js} +0 -0
  610. /package/dist/web/assets/{wgsl-Bj1Ec4vv.js → wgsl-14GDsWRD.js} +0 -0
  611. /package/dist/web/assets/{wikitext-C90DHNa0.js → wikitext-Ccbq5EVX.js} +0 -0
  612. /package/dist/web/assets/{wit-DUgbOD7Z.js → wit-C19hb3R5.js} +0 -0
  613. /package/dist/web/assets/{wolfram-BgwUqD1I.js → wolfram-B-ZSwGwP.js} +0 -0
  614. /package/dist/web/assets/{x-DiOUR_mp.js → x-YDu4m2Iq.js} +0 -0
  615. /package/dist/web/assets/{yaml-DEQulj-8.js → yaml-mw_JUeio.js} +0 -0
  616. /package/dist/web/assets/{zenscript-C7Jp7TgT.js → zenscript-WbzDRjvF.js} +0 -0
  617. /package/dist/web/assets/{zig-9x4qXYLg.js → zig-F0vvImTJ.js} +0 -0
@@ -1,20 +1,20 @@
1
- import { useState, useEffect, useRef } from "react";
2
- import { Activity, RefreshCw, Eye, Download, Upload, Plus, X, Settings, Trash2, Maximize2, Minimize2 } from "lucide-react";
3
- import { Switch } from "@/components/ui/switch";
4
- import type { UsageInfo, LimitBucket } from "../../../types/chat";
5
- import {
6
- getAccounts,
7
- getActiveAccount,
8
- getAllAccountUsages,
9
- patchAccount,
10
- deleteAccount,
11
- type AccountInfo,
12
- type AccountUsageEntry,
13
- type OAuthProfileData,
14
- } from "../../lib/api-settings";
15
- import { AddAccountDialog, ExportAccountsDialog, ImportAccountsDialog } from "./account-dialogs";
16
- import { AccountRotationSettings } from "./account-rotation-settings";
17
- import { UsagePatternChart } from "./usage-pattern-chart";
1
+ /**
2
+ * The chat header's usage chip and the panel it opens.
3
+ *
4
+ * Display only. Adding, removing, enabling, exporting and rotating accounts all live in
5
+ * Settings → Accounts; this panel links there instead of carrying its own copy of those
6
+ * controls, which is what let the two drift apart. The account cards are the same component
7
+ * the Settings pane renders — passing no action callbacks is what makes them read-only, so
8
+ * there is one card implementation rather than a display twin.
9
+ */
10
+
11
+ import { Activity, ExternalLink, RefreshCw, X } from "lucide-react";
12
+ import type { UsageInfo } from "../../../types/chat";
13
+ import { openSettings } from "@/components/settings/open-settings";
14
+ import { AccountCard } from "@/components/settings/accounts/account-card";
15
+ import { AccountBucketRow } from "@/components/settings/accounts/account-bucket-row";
16
+ import { useAccountsData } from "@/components/settings/accounts/use-accounts-data";
17
+ import { formatLastUpdated, pctColor } from "@/components/settings/accounts/account-usage-format";
18
18
 
19
19
  interface UsageBadgeProps {
20
20
  usage: UsageInfo;
@@ -22,18 +22,6 @@ interface UsageBadgeProps {
22
22
  onClick?: () => void;
23
23
  }
24
24
 
25
- function pctColor(pct: number): string {
26
- if (pct >= 90) return "text-error";
27
- if (pct >= 70) return "text-warning";
28
- return "text-success";
29
- }
30
-
31
- function barColor(pct: number): string {
32
- if (pct >= 90) return "bg-error";
33
- if (pct >= 70) return "bg-warning";
34
- return "bg-success";
35
- }
36
-
37
25
  export function UsageBadge({ usage, loading, onClick }: UsageBadgeProps) {
38
26
  const fiveHourPct = usage.fiveHour != null ? Math.round(usage.fiveHour * 100) : null;
39
27
  const sevenDayPct = usage.sevenDay != null ? Math.round(usage.sevenDay * 100) : null;
@@ -69,413 +57,80 @@ interface UsageDetailPanelProps {
69
57
  lastFetchedAt?: string | null;
70
58
  }
71
59
 
72
- function formatResetTime(bucket?: LimitBucket): string | null {
73
- if (!bucket) return null;
74
- let totalMins: number | null = null;
75
- if (bucket.resetsInMinutes != null) {
76
- totalMins = bucket.resetsInMinutes;
77
- } else if (bucket.resetsInHours != null) {
78
- totalMins = Math.round(bucket.resetsInHours * 60);
79
- } else if (bucket.resetsAt) {
80
- const diff = new Date(bucket.resetsAt).getTime() - Date.now();
81
- totalMins = diff > 0 ? Math.ceil(diff / 60_000) : 0;
82
- }
83
- if (totalMins == null) return null;
84
- if (totalMins <= 0) return "now";
85
- const d = Math.floor(totalMins / 1440);
86
- const h = Math.floor((totalMins % 1440) / 60);
87
- const m = totalMins % 60;
88
- if (d > 0) return m > 0 ? `${d}d ${h}h ${m}m` : h > 0 ? `${d}d ${h}h` : `${d}d`;
89
- if (h > 0) return m > 0 ? `${h}h ${m}m` : `${h}h`;
90
- return `${m}m`;
91
- }
92
-
93
- function BucketRow({ label, bucket }: { label: string; bucket?: LimitBucket }) {
94
- if (!bucket) return null;
95
- const pct = Math.round(bucket.utilization * 100);
96
- const reset = formatResetTime(bucket);
97
-
98
- return (
99
- <div className="space-y-1">
100
- <div className="flex items-center justify-between">
101
- <span className="text-xs font-medium text-text-primary">{label}</span>
102
- {reset && (
103
- <span className="text-[10px] text-text-subtle" title="Resets in">↻ {reset}</span>
104
- )}
105
- </div>
106
- <div className="flex items-center gap-2">
107
- <div className="flex-1 h-2 rounded-full bg-border overflow-hidden">
108
- <div
109
- className={`h-full rounded-full transition-all ${barColor(pct)}`}
110
- style={{ width: `${Math.min(pct, 100)}%` }}
111
- />
112
- </div>
113
- <span className={`text-xs font-medium tabular-nums w-10 text-right ${pctColor(pct)}`}>
114
- {pct}%
115
- </span>
116
- </div>
117
- </div>
118
- );
119
- }
120
-
121
- function formatExpiry(expiresAt: number): string {
122
- const diff = expiresAt - Date.now();
123
- if (diff <= 0) return "expired";
124
- const mins = Math.ceil(diff / 60_000);
125
- const h = Math.floor(mins / 60);
126
- const d = Math.floor(h / 24);
127
- if (d > 0) return `${d}d ${h % 24}h`;
128
- if (h > 0) return `${h}h ${mins % 60}m`;
129
- return `${mins}m`;
130
- }
131
-
132
- /** Derive a human-readable token status from account info */
133
- function tokenStatus(info?: AccountInfo): { label: string; tip: string; color: string } {
134
- if (!info) return { label: "unknown", tip: "No account info available", color: "text-text-subtle" };
135
- if (!info.expiresAt) return { label: "key", tip: "API key (no expiry)", color: "text-text-subtle" };
136
- const expired = info.expiresAt * 1000 < Date.now(); // expiresAt is seconds
137
- if (expired && info.hasRefreshToken) return { label: "expired", tip: "Token expired but has refresh token — will auto-renew", color: "text-warning" };
138
- if (expired) return { label: "expired", tip: "Token expired, no refresh token", color: "text-error" };
139
- if (info.hasRefreshToken) return { label: "long-lived", tip: "OAuth token with refresh — long-lived", color: "text-success" };
140
- return { label: "temp", tip: "Temporary token without refresh — will expire", color: "text-warning" };
141
- }
142
-
143
- function formatLastUpdated(ts: number | null | undefined): string | null {
144
- if (!ts) return null;
145
- const secs = Math.round((Date.now() - ts) / 1000);
146
- if (secs < 5) return "just now";
147
- if (secs < 60) return `${secs}s ago`;
148
- const mins = Math.floor(secs / 60);
149
- if (mins < 60) return `${mins}m ago`;
150
- const hrs = Math.floor(mins / 60);
151
- const remainMins = mins % 60;
152
- if (hrs < 24) return remainMins > 0 ? `${hrs}h ${remainMins}m ago` : `${hrs}h ago`;
153
- const days = Math.floor(hrs / 24);
154
- return `${days}d ago`;
155
- }
156
-
157
- function AccountUsageCard({ entry, isActive, accountInfo, onToggle, toggling, onDelete, onExport, onViewProfile, flash, fullscreen }: {
158
- entry: AccountUsageEntry;
159
- isActive: boolean;
160
- accountInfo?: AccountInfo;
161
- onToggle?: (id: string, status: string) => void;
162
- toggling?: boolean;
163
- onDelete?: (id: string, display: string) => void;
164
- onExport?: (id: string) => void;
165
- onViewProfile?: (profile: OAuthProfileData, accountId: string) => void;
166
- flash?: boolean;
167
- fullscreen?: boolean;
168
- }) {
169
- const { usage } = entry;
170
- const hasBuckets = usage.session || usage.weekly || usage.weeklyOpus || usage.weeklySonnet;
171
- const status = accountInfo?.status ?? entry.accountStatus;
172
- // Expired: has expiresAt in the past AND no refresh token to auto-renew
173
- const isExpired = !!(accountInfo && !accountInfo.hasRefreshToken && accountInfo.expiresAt && accountInfo.expiresAt < Math.floor(Date.now() / 1000));
174
-
175
- return (
176
- <div className={`rounded-md border p-2 transition-colors duration-500 ${fullscreen ? "flex flex-col gap-1.5 overflow-hidden" : "space-y-1.5 min-w-[200px] shrink-0 snap-start"} ${isExpired ? "opacity-50" : ""} ${flash ? "bg-primary/10 border-primary/40" : ""} ${isActive ? "border-primary/30 bg-primary/5" : "border-border/50"}`}>
177
- <div className="flex items-center gap-1.5">
178
- <span className="text-xs font-medium truncate flex-1 min-w-0">
179
- {entry.accountLabel ?? entry.accountId.slice(0, 8)}
180
- </span>
181
- {isExpired && (
182
- <span className="text-[9px] text-error shrink-0 font-medium">Expired</span>
183
- )}
184
- {!entry.isOAuth && !isExpired && (
185
- <span className="text-[9px] text-text-subtle shrink-0">API key</span>
186
- )}
187
- {/* Account controls */}
188
- <div className="flex items-center gap-0.5 shrink-0">
189
- {!isExpired && onViewProfile && accountInfo?.profileData && (
190
- <button
191
- className="p-1 rounded cursor-pointer text-text-subtle hover:text-foreground hover:bg-surface-elevated transition-colors"
192
- onClick={() => onViewProfile(accountInfo.profileData!, entry.accountId)}
193
- title="View profile"
194
- >
195
- <Eye className="size-3" />
196
- </button>
197
- )}
198
- {!isExpired && onExport && entry.isOAuth && (
199
- <button
200
- className="p-1 rounded cursor-pointer text-text-subtle hover:text-primary hover:bg-surface-elevated transition-colors"
201
- onClick={() => onExport(entry.accountId)}
202
- title="Export this account"
203
- >
204
- <Download className="size-3" />
205
- </button>
206
- )}
207
- {!isExpired && onToggle && (
208
- <Switch
209
- checked={status !== "disabled"}
210
- onCheckedChange={() => onToggle(entry.accountId, status)}
211
- disabled={toggling || status === "cooldown"}
212
- className="scale-[0.6] cursor-pointer"
213
- />
214
- )}
215
- {onDelete && (
216
- <button
217
- className="p-1 rounded cursor-pointer text-text-subtle hover:text-error hover:bg-surface-elevated transition-colors"
218
- onClick={() => onDelete(entry.accountId, entry.accountLabel ?? entry.accountId.slice(0, 8))}
219
- title="Remove account"
220
- >
221
- <Trash2 className="size-3" />
222
- </button>
223
- )}
224
- </div>
225
- </div>
226
- {hasBuckets ? (
227
- <div className={fullscreen ? "flex-1 flex flex-col justify-evenly min-h-0" : "space-y-1.5"}>
228
- <BucketRow label="5-Hour Session" bucket={usage.session} />
229
- <BucketRow label="Weekly" bucket={usage.weekly} />
230
- <BucketRow label="Weekly (Opus)" bucket={usage.weeklyOpus} />
231
- <BucketRow label="Weekly (Sonnet)" bucket={usage.weeklySonnet} />
232
- </div>
233
- ) : (
234
- <p className="text-[10px] text-text-subtle">
235
- {entry.isOAuth ? "No usage data yet" : "Usage tracking not available for API keys"}
236
- </p>
237
- )}
238
- {/* Footer: updated · expires · type */}
239
- {(() => {
240
- const ts = tokenStatus(accountInfo);
241
- return (
242
- <div className="flex items-center gap-1.5 text-[9px] text-text-subtle flex-wrap">
243
- {usage.lastFetchedAt && (
244
- <span title="Last usage data update">↻ {formatLastUpdated(new Date(usage.lastFetchedAt).getTime())}</span>
245
- )}
246
- {accountInfo?.expiresAt && accountInfo.expiresAt * 1000 > Date.now() && (
247
- <span title="Token expires in">⏱ {formatExpiry(accountInfo.expiresAt * 1000)}</span>
248
- )}
249
- <span className={ts.color} title={ts.tip}>© {ts.label}</span>
250
- </div>
251
- );
252
- })()}
253
- </div>
254
- );
255
- }
256
-
257
60
  export function UsageDetailPanel({ usage, visible, onClose, onReload, loading, lastFetchedAt }: UsageDetailPanelProps) {
258
- const [allUsages, setAllUsages] = useState<AccountUsageEntry[]>([]);
259
- const [accounts, setAccounts] = useState<AccountInfo[]>([]);
260
- const [activeAccountId, setActiveAccountId] = useState<string | null>(null);
261
- const [initialLoading, setInitialLoading] = useState(true);
262
- const [refreshing, setRefreshing] = useState(false);
263
- const [flashIds, setFlashIds] = useState<Set<string>>(new Set());
264
- const [profileView, setProfileView] = useState<{ profile: OAuthProfileData; accountId: string } | null>(null);
265
- const [showAddDialog, setShowAddDialog] = useState(false);
266
- const [showExportDialog, setShowExportDialog] = useState(false);
267
- const [showImportDialog, setShowImportDialog] = useState(false);
268
- const [showRotationSettings, setShowRotationSettings] = useState(false);
269
- const [deleteTarget, setDeleteTarget] = useState<{ id: string; display: string } | null>(null);
270
- const [exportPreselect, setExportPreselect] = useState<string | null>(null);
271
- const [isFullscreen, setIsFullscreen] = useState(false);
272
- const [message, setMessage] = useState<string | null>(null);
273
- const [togglingId, setTogglingId] = useState<string | null>(null);
274
- const msgTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
275
- const prevUsagesRef = useRef<AccountUsageEntry[]>([]);
276
-
277
- function showMessage(msg: string) {
278
- if (msgTimer.current) clearTimeout(msgTimer.current);
279
- setMessage(msg);
280
- msgTimer.current = setTimeout(() => setMessage(null), 4000);
281
- }
282
-
283
- function handleSuccess(msg?: string) {
284
- loadAll();
285
- if (msg) showMessage(msg);
286
- }
287
-
288
- async function loadAll() {
289
- const isRefresh = allUsages.length > 0;
290
- if (isRefresh) setRefreshing(true); else setInitialLoading(true);
291
-
292
- const [usages, accs, active] = await Promise.allSettled([
293
- getAllAccountUsages(), getAccounts(), getActiveAccount(),
294
- ]);
295
-
296
- if (usages.status === "fulfilled") {
297
- const newUsages = usages.value;
298
- // Detect which accounts changed usage values
299
- if (isRefresh && prevUsagesRef.current.length > 0) {
300
- const changed = new Set<string>();
301
- const prevMap = new Map(prevUsagesRef.current.map(u => [u.accountId, u]));
302
- for (const nu of newUsages) {
303
- const prev = prevMap.get(nu.accountId);
304
- if (!prev) { changed.add(nu.accountId); continue; }
305
- const pu = prev.usage, cu = nu.usage;
306
- if (pu.session?.utilization !== cu.session?.utilization
307
- || pu.weekly?.utilization !== cu.weekly?.utilization
308
- || pu.weeklyOpus?.utilization !== cu.weeklyOpus?.utilization
309
- || pu.weeklySonnet?.utilization !== cu.weeklySonnet?.utilization) {
310
- changed.add(nu.accountId);
311
- }
312
- }
313
- if (changed.size > 0) {
314
- setFlashIds(changed);
315
- setTimeout(() => setFlashIds(new Set()), 1500);
316
- }
317
- }
318
- prevUsagesRef.current = newUsages;
319
- setAllUsages(newUsages);
320
- }
321
- if (accs.status === "fulfilled") setAccounts(accs.value);
322
- if (active.status === "fulfilled") setActiveAccountId(active.value?.id ?? null);
323
- setInitialLoading(false);
324
- setRefreshing(false);
325
- }
326
-
327
- useEffect(() => {
328
- if (!visible) return;
329
- loadAll();
330
- }, [visible]);
331
-
332
- // Re-fetch account usages after parent refreshes from Anthropic API
333
- useEffect(() => {
334
- if (!visible || !lastFetchedAt) return;
335
- loadAll();
336
- }, [lastFetchedAt]); // eslint-disable-line react-hooks/exhaustive-deps
61
+ // Fetching is gated on visibility: the panel is collapsed most of the time, and its
62
+ // usage endpoint is the expensive one.
63
+ const { usages, accounts, activeAccountId, initialLoading, refreshing, flashIds, reload } = useAccountsData(visible);
337
64
 
338
65
  if (!visible) return null;
339
66
 
340
67
  const accountMap = new Map(accounts.map((a) => [a.id, a]));
341
68
  const hasCost = usage.queryCostUsd != null || usage.totalCostUsd != null;
342
- const hasMultipleAccounts = allUsages.length > 0;
343
-
344
- // Grid dimensions for fullscreen: cards fill viewport without scroll
345
- const fsCount = allUsages.length || 1;
346
- const fsCols = Math.ceil(Math.sqrt(fsCount));
347
- const fsRows = Math.ceil(fsCount / fsCols);
348
-
349
- async function handleToggle(id: string, status: string) {
350
- // Enabling a parked account proves its token server-side first, which is a network
351
- // round trip that can come back 400 — and patchAccount throws on that. Without the
352
- // catch the message the server takes care to write reaches nobody: unhandled
353
- // rejection, no toast, no reload, and the Switch silently snaps back. The pending
354
- // flag is because that round trip can take most of a minute in the worst case.
355
- setTogglingId(id);
356
- try {
357
- await patchAccount(id, { status: status === "disabled" ? "active" : "disabled" });
358
- } catch (e) {
359
- showMessage((e as Error).message);
360
- }
361
- setTogglingId(null);
362
- loadAll();
363
- onReload?.();
364
- }
365
-
366
- async function confirmDeleteAccount() {
367
- if (!deleteTarget) return;
368
- try {
369
- await deleteAccount(deleteTarget.id);
370
- showMessage(`Account "${deleteTarget.display}" removed.`);
371
- loadAll();
372
- onReload?.();
373
- } catch (e) {
374
- showMessage(`Failed to remove: ${(e as Error).message}`);
375
- }
376
- setDeleteTarget(null);
377
- }
378
-
379
- function openExportAll() {
380
- setExportPreselect(null);
381
- setShowExportDialog(true);
382
- }
69
+ const hasPerAccountUsage = usages.length > 0;
383
70
 
384
71
  return (
385
- <div className={`relative border-b border-border bg-surface px-3 py-2.5 ${isFullscreen ? "fixed inset-0 z-50 flex flex-col gap-2.5 overflow-hidden" : "space-y-2.5 max-h-[350px] overflow-y-auto"}`}>
72
+ <div className="relative border-b border-border bg-surface px-3 py-2.5 space-y-2.5 max-h-[350px] overflow-y-auto">
386
73
  <div className="flex items-center justify-between shrink-0">
387
74
  <div className="flex items-center gap-2">
388
- <span className="text-xs font-semibold text-text-primary">Usage & Accounts</span>
75
+ <span className="text-xs font-semibold text-text-primary">Usage</span>
389
76
  {lastFetchedAt && (
390
77
  <span className="text-[10px] text-text-subtle">{formatLastUpdated(new Date(lastFetchedAt).getTime())}</span>
391
78
  )}
392
79
  </div>
393
80
  <div className="flex items-center gap-1">
394
81
  <button
395
- onClick={() => setShowRotationSettings(true)}
396
- className="text-xs text-text-subtle hover:text-text-primary px-1 cursor-pointer"
397
- title="Rotation & retry settings"
82
+ onClick={() => openSettings("accounts")}
83
+ className="flex items-center gap-1 text-[10px] text-text-subtle hover:text-text-primary px-1 cursor-pointer"
84
+ title="Add, remove or rotate accounts"
398
85
  >
399
- <Settings className="size-3" />
86
+ Manage accounts <ExternalLink className="size-3" />
400
87
  </button>
401
- {hasMultipleAccounts && (
402
- <button
403
- onClick={() => setIsFullscreen((v) => !v)}
404
- className="text-xs text-text-subtle hover:text-text-primary px-1 cursor-pointer"
405
- title={isFullscreen ? "Exit fullscreen" : "Fullscreen view"}
406
- >
407
- {isFullscreen ? <Minimize2 className="size-3" /> : <Maximize2 className="size-3" />}
408
- </button>
409
- )}
410
88
  {onReload && (
411
89
  <button
412
- onClick={() => { onReload(); loadAll(); }}
90
+ onClick={() => { onReload(); void reload(); }}
413
91
  disabled={loading || refreshing}
414
92
  className="text-xs text-text-subtle hover:text-text-primary px-1 disabled:opacity-50 cursor-pointer"
415
93
  title="Refresh"
94
+ aria-label="Refresh usage"
416
95
  >
417
96
  <RefreshCw className={`size-3 ${(loading || refreshing) ? "animate-spin" : ""}`} />
418
97
  </button>
419
98
  )}
420
99
  <button
421
- onClick={() => { setIsFullscreen(false); onClose(); }}
100
+ onClick={onClose}
422
101
  className="text-xs text-text-subtle hover:text-text-primary px-1 cursor-pointer"
102
+ aria-label="Close usage panel"
423
103
  >
424
104
  <X className="size-3" />
425
105
  </button>
426
106
  </div>
427
107
  </div>
428
108
 
429
- {message && (
430
- <div className="text-[11px] p-1.5 rounded bg-success/10 text-success text-center animate-in fade-in duration-200">
431
- {message}
432
- </div>
433
- )}
434
-
435
- {(hasMultipleAccounts || initialLoading) ? (
436
- <div
437
- className={isFullscreen
438
- ? "flex-1 min-h-0 grid gap-2 overflow-hidden"
439
- : "flex gap-1.5 overflow-x-auto pb-1 -mx-3 px-3 snap-x snap-mandatory scrollbar-thin"
440
- }
441
- style={isFullscreen ? {
442
- gridTemplateColumns: `repeat(${fsCols}, minmax(0, 1fr))`,
443
- gridTemplateRows: `repeat(${fsRows}, minmax(0, 1fr))`,
444
- } : undefined}
445
- >
109
+ {hasPerAccountUsage || initialLoading ? (
110
+ <div className="space-y-1.5">
446
111
  {initialLoading ? (
447
112
  <p className="text-[10px] text-text-subtle">Loading...</p>
448
113
  ) : (
449
- allUsages.map((entry) => (
450
- <AccountUsageCard
114
+ usages.map((entry) => (
115
+ <AccountCard
451
116
  key={entry.accountId}
452
117
  entry={entry}
453
118
  isActive={entry.accountId === (activeAccountId ?? usage.activeAccountId)}
454
119
  accountInfo={accountMap.get(entry.accountId)}
455
- onToggle={handleToggle}
456
- toggling={togglingId === entry.accountId}
457
- onDelete={(id, display) => setDeleteTarget({ id, display })}
458
- onExport={(id) => { setExportPreselect(id); setShowExportDialog(true); }}
459
- onViewProfile={(profile, accountId) => setProfileView({ profile, accountId })}
460
120
  flash={flashIds.has(entry.accountId)}
461
- fullscreen={isFullscreen}
462
121
  />
463
122
  ))
464
123
  )}
465
124
  </div>
125
+ ) : usage.session || usage.weekly || usage.weeklyOpus || usage.weeklySonnet ? (
126
+ <div className="space-y-2.5">
127
+ <AccountBucketRow label="5-Hour Session" bucket={usage.session} />
128
+ <AccountBucketRow label="Weekly" bucket={usage.weekly} />
129
+ <AccountBucketRow label="Weekly (Opus)" bucket={usage.weeklyOpus} />
130
+ <AccountBucketRow label="Weekly (Sonnet)" bucket={usage.weeklySonnet} />
131
+ </div>
466
132
  ) : (
467
- <>
468
- {usage.session || usage.weekly || usage.weeklyOpus || usage.weeklySonnet ? (
469
- <div className="space-y-2.5">
470
- <BucketRow label="5-Hour Session" bucket={usage.session} />
471
- <BucketRow label="Weekly" bucket={usage.weekly} />
472
- <BucketRow label="Weekly (Opus)" bucket={usage.weeklyOpus} />
473
- <BucketRow label="Weekly (Sonnet)" bucket={usage.weeklySonnet} />
474
- </div>
475
- ) : (
476
- <p className="text-xs text-text-subtle">No usage data available</p>
477
- )}
478
- </>
133
+ <p className="text-xs text-text-subtle">No usage data available</p>
479
134
  )}
480
135
 
481
136
  {hasCost && (
@@ -498,65 +153,6 @@ export function UsageDetailPanel({ usage, visible, onClose, onReload, loading, l
498
153
  )}
499
154
  </div>
500
155
  )}
501
-
502
- {/* Inline profile popup */}
503
- {profileView && (
504
- <div className="border-t border-border pt-2">
505
- <div className="flex items-center justify-between mb-1">
506
- <span className="text-[10px] font-medium text-text-subtle">Profile</span>
507
- <button className="text-text-subtle hover:text-foreground cursor-pointer" onClick={() => setProfileView(null)}>
508
- <X className="size-3" />
509
- </button>
510
- </div>
511
- <div className="grid grid-cols-[70px_1fr] gap-x-2 gap-y-0.5 text-[10px]">
512
- {profileView.profile.account?.display_name && <><span className="text-text-subtle">Name</span><span>{profileView.profile.account.display_name}</span></>}
513
- {profileView.profile.account?.email && <><span className="text-text-subtle">Email</span><span>{profileView.profile.account.email}</span></>}
514
- {profileView.profile.organization?.name && <><span className="text-text-subtle">Org</span><span>{profileView.profile.organization.name}</span></>}
515
- {profileView.profile.organization?.organization_type && <><span className="text-text-subtle">Type</span><span>{profileView.profile.organization.organization_type}</span></>}
516
- {profileView.profile.organization?.rate_limit_tier && <><span className="text-text-subtle">Tier</span><span>{profileView.profile.organization.rate_limit_tier}</span></>}
517
- {profileView.profile.organization?.subscription_status && <><span className="text-text-subtle">Status</span><span>{profileView.profile.organization.subscription_status}</span></>}
518
- </div>
519
- <UsagePatternChart accountId={profileView.accountId} />
520
- </div>
521
- )}
522
-
523
- {/* Action buttons */}
524
- <div className="border-t border-border pt-2 flex gap-1.5 shrink-0">
525
- <button onClick={() => setShowAddDialog(true)} className="flex-1 flex items-center justify-center gap-1 rounded-md border border-border px-2 py-1 text-[11px] text-text-secondary hover:bg-surface-hover transition-colors cursor-pointer">
526
- <Plus className="size-3" /> Add
527
- </button>
528
- <button onClick={openExportAll} className="flex-1 flex items-center justify-center gap-1 rounded-md border border-border px-2 py-1 text-[11px] text-text-secondary hover:bg-surface-hover transition-colors cursor-pointer">
529
- <Download className="size-3" /> Export
530
- </button>
531
- <button onClick={() => setShowImportDialog(true)} className="flex-1 flex items-center justify-center gap-1 rounded-md border border-border px-2 py-1 text-[11px] text-text-secondary hover:bg-surface-hover transition-colors cursor-pointer">
532
- <Upload className="size-3" /> Import
533
- </button>
534
- </div>
535
-
536
- {/* Delete confirmation overlay */}
537
- {deleteTarget && (
538
- <div className="absolute inset-0 z-10 flex items-center justify-center bg-background/80 backdrop-blur-sm rounded-md">
539
- <div className="bg-surface border border-border rounded-lg shadow-lg p-4 mx-4 max-w-[280px] w-full space-y-3">
540
- <p className="text-xs text-text-primary text-center">
541
- Remove <strong className="text-foreground">{deleteTarget.display}</strong>?
542
- </p>
543
- <div className="flex gap-2">
544
- <button onClick={() => setDeleteTarget(null)} className="flex-1 px-3 py-1.5 rounded-md text-xs border border-border text-text-secondary hover:bg-surface-hover cursor-pointer transition-colors">
545
- Cancel
546
- </button>
547
- <button onClick={confirmDeleteAccount} className="flex-1 px-3 py-1.5 rounded-md text-xs bg-error text-white hover:bg-error/80 cursor-pointer transition-colors">
548
- Remove
549
- </button>
550
- </div>
551
- </div>
552
- </div>
553
- )}
554
-
555
- {/* Account dialogs */}
556
- <AddAccountDialog open={showAddDialog} onOpenChange={setShowAddDialog} onSuccess={handleSuccess} />
557
- <ExportAccountsDialog open={showExportDialog} onOpenChange={(v) => { setShowExportDialog(v); if (!v) setExportPreselect(null); }} accounts={accounts} preselectId={exportPreselect} onMessage={showMessage} />
558
- <ImportAccountsDialog open={showImportDialog} onOpenChange={setShowImportDialog} onSuccess={handleSuccess} />
559
- <AccountRotationSettings open={showRotationSettings} onOpenChange={setShowRotationSettings} />
560
156
  </div>
561
157
  );
562
158
  }
@@ -23,6 +23,7 @@ export const WINDOW_CONTENT: Record<WindowKind, LazyExoticComponent<ComponentTyp
23
23
  "system-monitor": lazy(() => import("@/components/system/system-monitor-window-content")),
24
24
  "tab-host": lazy(() => import("./tab-host-window-content")),
25
25
  "remote-desktop": lazy(() => import("@/components/remote-desktop/remote-desktop-window-content")),
26
+ settings: lazy(() => import("@/components/settings/settings-window-content")),
26
27
  };
27
28
 
28
29
  /** Titlebar text for a window. Falls back to the kind's generic name. */
@@ -35,6 +36,7 @@ export function windowTitle(kind: WindowKind, payload?: Record<string, unknown>)
35
36
  }
36
37
  if (kind === "system-monitor") return "System Monitor";
37
38
  if (kind === "remote-desktop") return "Remote Desktop";
39
+ if (kind === "settings") return "Settings";
38
40
  // A detached tab carries its title in the payload; the generic name only shows for a
39
41
  // window whose tab has not been resolved yet (restore before the layout is loaded).
40
42
  if (kind === "tab-host") return "Tab";
@@ -7,7 +7,7 @@ import type { Rect } from "./window-geometry";
7
7
  * Single source of truth: the persistence layer filters this list instead of repeating it,
8
8
  * so a new kind can never be silently dropped on reload.
9
9
  */
10
- export const WINDOW_KINDS = ["explorer", "team-member", "system-monitor", "tab-host", "remote-desktop"] as const;
10
+ export const WINDOW_KINDS = ["explorer", "team-member", "system-monitor", "tab-host", "remote-desktop", "settings"] as const;
11
11
 
12
12
  export type WindowKind = (typeof WINDOW_KINDS)[number];
13
13
 
@@ -21,6 +21,7 @@ import {
21
21
  AppWindow,
22
22
  } from "lucide-react";
23
23
  import { openExplorer } from "@/components/os-explorer/open-explorer";
24
+ import { openSettings } from "@/components/settings/open-settings";
24
25
  import { useTabStore, type TabType } from "@/stores/tab-store";
25
26
  import { useProjectStore } from "@/stores/project-store";
26
27
  import { useSettingsStore } from "@/stores/settings-store";
@@ -226,8 +227,7 @@ export function CommandPalette({ open, onClose, initialQuery = "" }: { open: boo
226
227
  {
227
228
  id: "settings", label: "Settings", icon: Settings,
228
229
  action: () => {
229
- if (sidebarCollapsed) toggleSidebar();
230
- setSidebarActiveTab("settings");
230
+ openSettings();
231
231
  onClose();
232
232
  },
233
233
  keywords: "config preferences theme",
@@ -1,12 +1,11 @@
1
1
  import { useState, useCallback, useEffect, useMemo } from "react";
2
- import { X, Bug as BugIcon, Cloud, FolderTree, MonitorSmartphone } from "lucide-react";
2
+ import { X, Bug as BugIcon, Cloud, FolderTree, MonitorSmartphone, Settings } from "lucide-react";
3
3
  import { useShallow } from "zustand/react/shallow";
4
4
  import { useProjectStore } from "@/stores/project-store";
5
5
  import { useSettingsStore, type SidebarActiveTab } from "@/stores/settings-store";
6
6
  import { useExtensionStore } from "@/stores/extension-store";
7
7
  import { FileTree } from "@/components/explorer/file-tree";
8
8
  import { GitStatusPanel } from "@/components/git/git-status-panel";
9
- import { SettingsTab } from "@/components/settings/settings-tab";
10
9
  import { DatabaseSidebar } from "@/components/database/database-sidebar";
11
10
  import { JiraPanel } from "@/components/jira/jira-panel";
12
11
  import { AiResourcesPanel } from "@/components/ai-resources/ai-resources-panel";
@@ -25,6 +24,7 @@ import { isMobileDevice } from "@/hooks/use-is-mobile";
25
24
  import { openExplorer } from "@/components/os-explorer/open-explorer";
26
25
  import { useOpenRemoteDesktop } from "@/components/remote-desktop/open-remote-desktop";
27
26
  import { useRemoteDesktopAvailable } from "@/components/remote-desktop/use-remote-desktop-available";
27
+ import { openSettings } from "@/components/settings/open-settings";
28
28
  import { FeatureBadge } from "@/components/ui/feature-badge";
29
29
  import type { FeatureBadgeId } from "@/lib/feature-badges";
30
30
  import { cn } from "@/lib/utils";
@@ -32,7 +32,7 @@ import { cn } from "@/lib/utils";
32
32
  // Tab ids the mobile drawer can render content for. `search` is desktop-only for now;
33
33
  // ext views are supported via the `ext:` prefix.
34
34
  const MOBILE_SUPPORTED = new Set<string>([
35
- "history", "teams", "explorer", "git", "database", "tunnels", "ai-resources", "settings", "jira",
35
+ "history", "teams", "explorer", "git", "database", "tunnels", "ai-resources", "jira",
36
36
  ]);
37
37
  const isMobileSupported = (id: SidebarActiveTab) => MOBILE_SUPPORTED.has(id) || id.startsWith("ext:");
38
38
 
@@ -148,7 +148,6 @@ export function MobileDrawer({ isOpen, onClose, initialTab }: MobileDrawerProps)
148
148
  {activeTab === "tunnels" && <TunnelManagerTab />}
149
149
  {activeTab === "jira" && <JiraPanel />}
150
150
  {activeTab === "ai-resources" && <AiResourcesPanel />}
151
- {activeTab === "settings" && <SettingsTab />}
152
151
  {activeTab.startsWith("ext:") && <ExtensionTreeView viewId={activeTab.slice(4)} className="h-full" />}
153
152
  </div>
154
153
 
@@ -171,6 +170,8 @@ export function MobileDrawer({ isOpen, onClose, initialTab }: MobileDrawerProps)
171
170
  <FooterTile icon={MonitorSmartphone} label="Remote" badge="remote-desktop" onClick={() => { onClose(); openRemoteDesktop(); }} />
172
171
  )}
173
172
  <FooterTile icon={Cloud} label="Cloud" onClick={() => setCloudOpen(true)} />
173
+ {/* Also not a sidebar tab — settings open as their own tab here, window on desktop. */}
174
+ <FooterTile icon={Settings} label="Settings" onClick={() => { onClose(); openSettings(); }} />
174
175
  <FooterTile icon={BugIcon} label="Bug" onClick={handleReportBug} />
175
176
  </div>
176
177
  {/* Version / upgrade pinned at the very bottom, under a divider. */}