@hienlh/ppm 0.19.1 → 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.
- package/CHANGELOG.md +29 -1
- package/CLAUDE.md +1 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +3 -2
- package/dist/web/assets/accounts-settings-section-LtSVxNNp.js +1 -0
- package/dist/web/assets/ai-resource-editor-BqFT1EUB.js +1 -0
- package/dist/web/assets/ai-settings-section-CY6spbEx.js +1 -0
- package/dist/web/assets/ai-settings-section-Po3K8j-g.js +1 -0
- package/dist/web/assets/{angular-html-VzxSzTCy.js → angular-html-BuHNQIbQ.js} +1 -1
- package/dist/web/assets/{angular-ts-CmJ4bmzM.js → angular-ts-DHRWoLc-.js} +1 -1
- package/dist/web/assets/api-client-BogqsFna.js +1 -0
- package/dist/web/assets/{api-client-qRWu6_s5.js → api-client-oY1tC3tM.js} +1 -1
- package/dist/web/assets/api-settings-CTMdz_VF.js +1 -0
- package/dist/web/assets/{api-themes-DsAp8m7m.js → api-themes-Cknp3Q-P.js} +1 -1
- package/dist/web/assets/{apl-do17bnVx.js → apl-C1VSWVei.js} +1 -1
- package/dist/web/assets/appearance-settings-section-L9Z-nej_.js +1 -0
- package/dist/web/assets/architecture-PBZL5I3N-Ca5IpdzP.js +1 -0
- package/dist/web/assets/arrow-left-CyFcsyzD.js +1 -0
- package/dist/web/assets/{astro-ClY0e0OA.js → astro-RX-rChsZ.js} +1 -1
- package/dist/web/assets/{audio-preview-Fw935Mok.js → audio-preview-CCd1jdje.js} +1 -1
- package/dist/web/assets/{blade-BXSdXDGq.js → blade-CZ6bxMbK.js} +1 -1
- package/dist/web/assets/{bot-CWZAuloY.js → bot-D6sx11y0.js} +1 -1
- package/dist/web/assets/{pencil-CHKLOgLs.js → brain-KDa9jFRq.js} +1 -1
- package/dist/web/assets/{bsl-MxsMKDUZ.js → bsl-BhgCXLWk.js} +1 -1
- package/dist/web/assets/{button-CrwgGd1y.js → button-BZtEJcUv.js} +1 -1
- package/dist/web/assets/{cairo-4CIrzX_p.js → cairo-BrwygPkn.js} +1 -1
- package/dist/web/assets/calendar-clock-C1asT-gk.js +1 -0
- package/dist/web/assets/chat-tab-BIO-VhWT.js +15 -0
- package/dist/web/assets/check-DN75Ucvz.js +1 -0
- package/dist/web/assets/{chevron-down-D7CbB5f6.js → chevron-down-Dp0rpHb8.js} +1 -1
- package/dist/web/assets/chevron-right-De-Wz5Lz.js +1 -0
- package/dist/web/assets/chevron-up-8PbsNiJp.js +1 -0
- package/dist/web/assets/circle-BCy0AUCo.js +1 -0
- package/dist/web/assets/{circle-question-mark-BBzFZrNh.js → circle-question-mark-CzR7YRc-.js} +1 -1
- package/dist/web/assets/clock-C1CQUQPZ.js +1 -0
- package/dist/web/assets/{cobol-phPOE89d.js → cobol-C5TGW1Ir.js} +1 -1
- package/dist/web/assets/code-DJgYrFzm.js +1 -0
- package/dist/web/assets/code-editor-B9lVjElM.js +7 -0
- package/dist/web/assets/{coffee-Cjuukfz3.js → coffee-CFgKlmgI.js} +1 -1
- package/dist/web/assets/{conflict-editor-Ni0PPsKu.js → conflict-editor-BoRPwL3L.js} +1 -1
- package/dist/web/assets/context-menu-C13b1uT3.js +1 -0
- package/dist/web/assets/{copy-CbPdNp7E.js → copy-BewHj66E.js} +1 -1
- package/dist/web/assets/{cpp-CT7tGBC3.js → cpp-BhG5q3-d.js} +1 -1
- package/dist/web/assets/{createLucideIcon-ConhwJnb.js → createLucideIcon-D8pyde1A.js} +1 -1
- package/dist/web/assets/{crystal-D8U1Qnqh.js → crystal-DvuI7_tY.js} +1 -1
- package/dist/web/assets/{csv-preview-Coc2oed1.js → csv-preview-BpoJqZQi.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-B8WQkZDB.js → data-grid-overlay-editor-DP1xkog4.js} +1 -1
- package/dist/web/assets/{data-grid-types-KpjaKAci.js → data-grid-types-CdAg-4W1.js} +1 -1
- package/dist/web/assets/{database-BqyeGogo.js → database-Y3ESDK4-.js} +1 -1
- package/dist/web/assets/database-viewer-I-9cER1L.js +1 -0
- package/dist/web/assets/diff-viewer-_xHZsxvr.js +4 -0
- package/dist/web/assets/{dist-C2_dKAa_.js → dist-DonmFWG8.js} +1 -1
- package/dist/web/assets/{docx-preview-76KDw1eE.js → docx-preview-CWIDVNZn.js} +1 -1
- package/dist/web/assets/{download-DAF7SXcf.js → download-DG3_9xXy.js} +1 -1
- package/dist/web/assets/{edge-Db4ze6bw.js → edge-BSIEsmlI.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-DyC_-4My.js → edit-diff-preview-DeHb85DN.js} +1 -1
- package/dist/web/assets/{elixir-RZPZ0472.js → elixir-BF-lrGXM.js} +1 -1
- package/dist/web/assets/{elm-DNZcQt_7.js → elm-8mCsJOeN.js} +1 -1
- package/dist/web/assets/{erb-DRONsZXs.js → erb-Dw5PUVKa.js} +1 -1
- package/dist/web/assets/{erlang-DeG0-QwJ.js → erlang-BvjBIA6O.js} +1 -1
- package/dist/web/assets/{esm-CZy-sSoK.js → esm-Bt9OwSnU.js} +1 -1
- package/dist/web/assets/explorer-body-DapwsOnp.js +2 -0
- package/dist/web/assets/explorer-window-content-DD6Z15pm.js +1 -0
- package/dist/web/assets/extension-manager-section-Cu9D9Udt.js +1 -0
- package/dist/web/assets/{extension-webview-BW5GuBnH.js → extension-webview-Diz2OzVq.js} +1 -1
- package/dist/web/assets/eye-gWwaF4Lg.js +1 -0
- package/dist/web/assets/eye-off-GjXVuAOn.js +1 -0
- package/dist/web/assets/{file-exclamation-point-Bpg-zDPP.js → file-exclamation-point-JzhTU2TX.js} +1 -1
- package/dist/web/assets/files-settings-section-B1e7BgKQ.js +1 -0
- package/dist/web/assets/flask-conical-tp8gyZGh.js +1 -0
- package/dist/web/assets/{folder-symlink-LD-mr54V.js → folder-symlink-fQRoG_rV.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-CK5VRJNd.js → fortran-fixed-form-CRjUJe9K.js} +1 -1
- package/dist/web/assets/{fsharp-TVVgzHWp.js → fsharp-CjUIHIHp.js} +1 -1
- package/dist/web/assets/{gdresource-DiUcyewI.js → gdresource-x_NUQFrZ.js} +1 -1
- package/dist/web/assets/general-settings-section-DWdHHRDy.js +1 -0
- package/dist/web/assets/{git-commit-CfOruFrg.js → git-commit-BOpxSbns.js} +1 -1
- package/dist/web/assets/git-log-panel-CMMsvU64.js +1 -0
- package/dist/web/assets/{git-rebase-Bxyr24oc.js → git-rebase-BW4xlK7k.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-BloZfB0Q.js +1 -0
- package/dist/web/assets/glide-data-grid-pKQuyYFj.js +141 -0
- package/dist/web/assets/{glimmer-js-CT5aJxz_.js → glimmer-js-CT9jrmFj.js} +1 -1
- package/dist/web/assets/{glimmer-ts-CRjP9Yey.js → glimmer-ts-CjQT1lxK.js} +1 -1
- package/dist/web/assets/{glsl-BX2--oI_.js → glsl-DsFJvtg5.js} +1 -1
- package/dist/web/assets/{graphql-BIQsvBxQ.js → graphql-Dhlnmkn_.js} +1 -1
- package/dist/web/assets/group-chat-tab-U5u0Loii.js +1 -0
- package/dist/web/assets/{hack-CTWk0k1m.js → hack-BKHbsJ7u.js} +1 -1
- package/dist/web/assets/{haml-DGh27hXc.js → haml-C1Ih25Y2.js} +1 -1
- package/dist/web/assets/{hand-DKSxDa5c.js → hand-x0ejq3fS.js} +1 -1
- package/dist/web/assets/{handlebars-BJL1jNrG.js → handlebars-CaFitvmC.js} +1 -1
- package/dist/web/assets/{html-DALyDNqU.js → html-BwpKIE6V.js} +1 -1
- package/dist/web/assets/{html-derivative-B4XcU57e.js → html-derivative-uuTEquZU.js} +1 -1
- package/dist/web/assets/{http-DfMo7nNu.js → http-Cv4Pg5cR.js} +1 -1
- package/dist/web/assets/{hurl-CGc_n2Qf.js → hurl-DubkI6TG.js} +1 -1
- package/dist/web/assets/{hxml-40zZ1t4x.js → hxml-B9OVZFAB.js} +1 -1
- package/dist/web/assets/{image-preview-Cp3XB8UO.js → image-preview-DRbZ0FA2.js} +1 -1
- package/dist/web/assets/index--KWVW-Ga.js +52 -0
- package/dist/web/assets/index-CvGx7wBQ.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-c0W8wp5o.js +1 -0
- package/dist/web/assets/{jinja-D5zuIn9u.js → jinja-BHb1jyl6.js} +1 -1
- package/dist/web/assets/jira-watcher-section-uA5oyB8s.js +1 -0
- package/dist/web/assets/{jison-Dxut9QwA.js → jison-CtpfXDzp.js} +1 -1
- package/dist/web/assets/{julia-Cu85tTPo.js → julia-TYjgpazU.js} +1 -1
- package/dist/web/assets/{just-CctM4uLa.js → just-D27bzZuW.js} +1 -1
- package/dist/web/assets/key-round-CQpDrDxg.js +1 -0
- package/dist/web/assets/keybindings-store-Ccf0etMJ.js +1 -0
- package/dist/web/assets/{keyboard-AdwmYDSu.js → keyboard-DiOYrs6C.js} +1 -1
- package/dist/web/assets/keyboard-shortcuts-section-B7IxJHiI.js +1 -0
- package/dist/web/assets/{latex-kpwS_CC7.js → latex-D_MzopTn.js} +1 -1
- package/dist/web/assets/{lib-Ca7ai8xa.js → lib-xrSJ4EZX.js} +1 -1
- package/dist/web/assets/{liquid-B8Rr0xue.js → liquid-BG_FG0Pe.js} +1 -1
- package/dist/web/assets/loader-circle-DPMrnLQ2.js +1 -0
- package/dist/web/assets/{lua-C_3gixwM.js → lua-Bl29oC2L.js} +1 -1
- package/dist/web/assets/markdown-renderer-CY1epGRc.js +1 -0
- package/dist/web/assets/markdown-renderer-DDcIGQEd.js +3 -0
- package/dist/web/assets/{marko-B28rvNL-.js → marko-D-HI7dbm.js} +1 -1
- package/dist/web/assets/{mdc-DQ6-STFO.js → mdc-y444JQTQ.js} +1 -1
- package/dist/web/assets/{media-url-BjvbfTTl.js → media-url-VzecHk9g.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-DXn5g2LB.js → mobile-bottom-sheet-BD5b7KJF.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-CqkwbCRl.js +1 -0
- package/dist/web/assets/{monitor-CXI_XpWJ.js → monitor-C835ucWH.js} +1 -1
- package/dist/web/assets/{nextflow-B1xq2O8L.js → nextflow-C5sKcldC.js} +1 -1
- package/dist/web/assets/{nginx-xsLxRGxO.js → nginx-bXnEC3wm.js} +1 -1
- package/dist/web/assets/{nim-wqcek3WO.js → nim-pevhf4WD.js} +1 -1
- package/dist/web/assets/notification-store-BNSYk3E7.js +1 -0
- package/dist/web/assets/notifications-settings-section-v_628h4B.js +1 -0
- package/dist/web/assets/{number-overlay-editor-1c4sgZJt.js → number-overlay-editor-B7WINIW4.js} +1 -1
- package/dist/web/assets/{overview-panel-Cr2xsHc6.js → overview-panel-mhN0qw6Q.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-D_BoHr_M.js +1 -0
- package/dist/web/assets/panel-store-BRrnDO_i.js +1 -0
- package/dist/web/assets/pdf-preview-CI3q1MnH.js +1 -0
- package/dist/web/assets/{perl-BH54gN9q.js → perl-B1KUtMnW.js} +1 -1
- package/dist/web/assets/{php-Br5ZrEZm.js → php-BGmVZBAJ.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-BaLfuEf8.js +1 -0
- package/dist/web/assets/portal-container-context-a399Hd9F.js +1 -0
- package/dist/web/assets/{postgres-viewer-BJPr_FYL.js → postgres-viewer-jaR0FYJ_.js} +3 -3
- package/dist/web/assets/power-CriQkeK5.js +1 -0
- package/dist/web/assets/ppmbot-settings-section-BET4VmKb.js +1 -0
- package/dist/web/assets/{process-table-BqTcAJ-h.js → process-table-D1r-Gupi.js} +1 -1
- package/dist/web/assets/{project-store-KHjFTCxf.js → project-store-BuY7rxn_.js} +1 -1
- package/dist/web/assets/proxy-settings-section-0DvNh1B-.js +3 -0
- package/dist/web/assets/{pug-8VCubZ3H.js → pug-BfN8CpEH.js} +1 -1
- package/dist/web/assets/{qml-D8AF1RZ6.js → qml-D6fRdLZt.js} +1 -1
- package/dist/web/assets/query-audit-section-BA5rT6Sh.js +1 -0
- package/dist/web/assets/radar-KQ55EAFF-DBIZEaIU.js +1 -0
- package/dist/web/assets/{razor-6v042IJW.js → razor-fg-9AScR.js} +1 -1
- package/dist/web/assets/{react-DHs6efqI.js → react-X4jUntEf.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-CPa3XElX.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-view-De_a4skd.js +1 -0
- package/dist/web/assets/remote-desktop-readiness-gate-CPrDIv2d.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-CG1StfCE.js +1 -0
- package/dist/web/assets/{rst-mTGFo4AQ.js → rst-BZgx076b.js} +1 -1
- package/dist/web/assets/{ruby-BBaOP636.js → ruby-iUkWDcLo.js} +1 -1
- package/dist/web/assets/{run-in-terminal-Zl5iIx-B.js → run-in-terminal-bKRwuO2z.js} +1 -1
- package/dist/web/assets/{sas-D5QEkIH2.js → sas-CLXO0lZ6.js} +1 -1
- package/dist/web/assets/{save-Dxq-Zepc.js → save-CipGrG1k.js} +1 -1
- package/dist/web/assets/schedules-settings-section-B2f7V7Xr.js +1 -0
- package/dist/web/assets/{scss-C5Mu6y2u.js → scss-DQqteGaG.js} +1 -1
- package/dist/web/assets/send-Bb0jtcR6.js +1 -0
- package/dist/web/assets/{send-to-chat-Cv7ikFUC.js → send-to-chat-S8LCNX7V.js} +1 -1
- package/dist/web/assets/separator-DqGg3f9c.js +1 -0
- package/dist/web/assets/settings-body-omv04jbb.js +2 -0
- package/dist/web/assets/settings-store-Brjd0QnO.js +2 -0
- package/dist/web/assets/settings-tab-NdnBTqyj.js +1 -0
- package/dist/web/assets/settings-window-content-Chou1JGa.js +1 -0
- package/dist/web/assets/{shaderlab-mLnpMpN3.js → shaderlab-CeMTqagR.js} +1 -1
- package/dist/web/assets/{shellsession-qdcDfUuk.js → shellsession-BAkquZAV.js} +1 -1
- package/dist/web/assets/{shield-check-CH7F1P7m.js → shield-check-BsG3LV8i.js} +1 -1
- package/dist/web/assets/{shield-off-C9HiF0-6.js → shield-off-7jKWpJBD.js} +1 -1
- package/dist/web/assets/{soy-CGGf1G43.js → soy-Bxm9Ez55.js} +1 -1
- package/dist/web/assets/{sparkles-BnuLH6Ck.js → sparkles-Dh-_J2Rd.js} +1 -1
- package/dist/web/assets/{sparql-tQHB50VD.js → sparql-C1phwdLc.js} +1 -1
- package/dist/web/assets/sql-query-editor-Dk9y3jqy.js +1 -0
- package/dist/web/assets/sqlite-viewer-4xFhkLYy.js +1 -0
- package/dist/web/assets/{stata-DVQNLMcR.js → stata-DGNMQdEb.js} +1 -1
- package/dist/web/assets/{surrealql-lu576tBi.js → surrealql-ByVrV320.js} +1 -1
- package/dist/web/assets/{svelte-CSCrOBjT.js → svelte-CNWjIMhl.js} +1 -1
- package/dist/web/assets/system-monitor-body-B_1iMVOI.js +2 -0
- package/dist/web/assets/system-monitor-tab-B2j9mWBW.js +1 -0
- package/dist/web/assets/system-monitor-window-content-BOjq53uU.js +1 -0
- package/dist/web/assets/{tab-host-window-content-C5kYP0-z.js → tab-host-window-content-CW_dlYlW.js} +1 -1
- package/dist/web/assets/{tab-store-DS3YlUwR.js → tab-store-PZsP5ZwG.js} +1 -1
- package/dist/web/assets/{table-BXDyImqk.js → table-CRJsmfeg.js} +1 -1
- package/dist/web/assets/team-member-sheet-CkR4qO7V.js +2 -0
- package/dist/web/assets/team-member-window-content-CmF5ia3n.js +1 -0
- package/dist/web/assets/{templ-CPt8AS4Q.js → templ-Cf0gQL4I.js} +1 -1
- package/dist/web/assets/{terminal-tab-8bKQ3CWR.js → terminal-tab-HXZkicIc.js} +3 -3
- package/dist/web/assets/{tex-BrTByT7i.js → tex-BTIqPw_R.js} +1 -1
- package/dist/web/assets/{text-wrap-CzMjB6GD.js → text-wrap-oiekm5SB.js} +1 -1
- package/dist/web/assets/tool-cards-jA1BTLZj.js +9 -0
- package/dist/web/assets/treemap-KZPCXAKY-DFiG9UYW.js +1 -0
- package/dist/web/assets/{ts-tags-DSqEZ7A8.js → ts-tags-B8dN_Yf6.js} +1 -1
- package/dist/web/assets/{twig-DW9qc1bf.js → twig-BgemonbJ.js} +1 -1
- package/dist/web/assets/use-accounts-data-BI_5qNvr.js +1 -0
- package/dist/web/assets/{use-blob-url-DKbV7PM_.js → use-blob-url-Gfi69PtP.js} +1 -1
- package/dist/web/assets/{use-coarse-long-press-DGyC48NF.js → use-coarse-long-press-BmI_GVW5.js} +1 -1
- package/dist/web/assets/{use-is-mobile-ClE-UcPF.js → use-is-mobile-CYW3FJFE.js} +1 -1
- package/dist/web/assets/use-monaco-theme-BcQqKVbE.js +1 -0
- package/dist/web/assets/use-open-team-member-CruUTqzD.js +1 -0
- package/dist/web/assets/use-remote-desktop-display-choice-DY5BWRTo.js +1 -0
- package/dist/web/assets/{use-visual-viewport-CCX21c9w.js → use-visual-viewport-rnvuooQZ.js} +1 -1
- package/dist/web/assets/{use-websocket-CWpG7PWN.js → use-websocket-DetaY8OI.js} +1 -1
- package/dist/web/assets/vendor-markdown-Ls5AcU91.js +291 -0
- package/dist/web/assets/{vendor-mermaid-0Nt-ew76.js → vendor-mermaid-BKWscKt0.js} +1 -1
- package/dist/web/assets/{vendor-ui-CXJtBULr.js → vendor-ui-CaeeFO0B.js} +1 -1
- package/dist/web/assets/video-preview-C0uH2228.js +1 -0
- package/dist/web/assets/{vue-CJNDL1g-.js → vue-D3D4lbXz.js} +1 -1
- package/dist/web/assets/{vue-html-CG5BKtq1.js → vue-html-DYEQFAiK.js} +1 -1
- package/dist/web/assets/{vue-vine-Dd5HZ7T5.js → vue-vine-D0OPNscN.js} +1 -1
- package/dist/web/assets/{window-pip-registry-9H6Y-HqR.js → window-pip-registry-BEN0QNSW.js} +1 -1
- package/dist/web/assets/window-store-DGKf9rPG.js +1 -0
- package/dist/web/assets/ws-auth-Dawx17PM.js +1 -0
- package/dist/web/assets/x-YDu4m2Iq.js +1 -0
- package/dist/web/assets/{xml-DTOm5niz.js → xml-DHaWgpya.js} +1 -1
- package/dist/web/assets/{xsl-BD_kBC04.js → xsl-DVRN8JsA.js} +1 -1
- package/dist/web/index.html +42 -65
- package/dist/web/monacoeditorwork/css.worker.bundle.js +122 -122
- package/dist/web/monacoeditorwork/editor.worker.bundle.js +78 -78
- package/dist/web/monacoeditorwork/html.worker.bundle.js +110 -110
- package/dist/web/monacoeditorwork/json.worker.bundle.js +108 -108
- package/dist/web/monacoeditorwork/ts.worker.bundle.js +81 -81
- package/dist/web/sw.js +1 -1
- package/docs/codebase-summary.md +9 -5
- package/docs/lessons-learned.md +11 -0
- package/package.json +2 -2
- package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
- package/scripts/check-ppm-dir-usage.sh +0 -0
- package/scripts/install.sh +0 -0
- package/scripts/release.sh +0 -0
- package/src/providers/claude-agent-sdk.ts +51 -43
- package/src/providers/codex-app-server/codex-event-mapper.ts +70 -5
- package/src/providers/codex-app-server/codex-history.ts +24 -0
- package/src/providers/codex-app-server/codex-jsonrpc-client.ts +39 -2
- package/src/providers/codex-app-server/codex-protocol.ts +24 -0
- package/src/providers/codex-app-server/codex-provider.ts +166 -18
- package/src/providers/codex-app-server/codex-rollout-items.ts +149 -0
- package/src/providers/codex-app-server/codex-skill-parser.ts +63 -0
- package/src/providers/codex-app-server/codex-usage-fetch.ts +22 -20
- package/src/providers/codex-app-server/codex-usage-source.ts +37 -0
- package/src/server/routes/chat.ts +95 -12
- package/src/server/routes/codex-accounts.ts +9 -5
- package/src/server/ws/chat.ts +55 -5
- package/src/services/claude-usage-source.ts +40 -0
- package/src/services/claude-usage.service.ts +77 -146
- package/src/services/codex-account-login.ts +123 -55
- package/src/services/codex-account.service.ts +27 -4
- package/src/services/db.service.ts +161 -20
- package/src/services/edge-forwarder.ts +191 -191
- package/src/services/fs-credential-path-guard.ts +35 -8
- package/src/services/fs-path-guard.service.ts +1 -0
- package/src/services/named-tunnel/named-tunnel-retry.ts +26 -0
- package/src/services/named-tunnel/network-ready.ts +63 -0
- package/src/services/postgres.service.ts +144 -72
- package/src/services/provider-usage/index.ts +63 -0
- package/src/services/provider-usage/register-usage-sources.ts +18 -0
- package/src/services/provider-usage/usage-memory-cache.ts +71 -0
- package/src/services/provider-usage/usage-registry.ts +157 -0
- package/src/services/provider-usage/usage-scheduler.ts +117 -0
- package/src/services/provider-usage/usage-snapshot-store.ts +126 -0
- package/src/services/provider-usage/usage-source.ts +82 -0
- package/src/services/slash-discovery/builtin-commands.ts +13 -0
- package/src/services/slash-discovery/codex-skill-items.ts +57 -0
- package/src/services/slash-discovery/provider-skill-sigil.ts +19 -0
- package/src/services/slash-discovery/types.ts +19 -0
- package/src/services/supervisor.ts +98 -0
- package/src/services/transcript-images.ts +14 -7
- package/src/services/upgrade.service.ts +7 -2
- package/src/services/windows-process-tree.ts +351 -351
- package/src/shared/image-limits.ts +37 -0
- package/src/types/api.ts +3 -1
- package/src/types/chat.ts +13 -1
- package/src/types/extension-messages.ts +2 -0
- package/src/web/app.tsx +1 -7
- package/src/web/components/chat/attachment-chips.tsx +10 -0
- package/src/web/components/chat/chat-history-bar.tsx +10 -1
- package/src/web/components/chat/chat-tab.tsx +54 -14
- package/src/web/components/chat/message-input.tsx +113 -15
- package/src/web/components/chat/message-list.tsx +14 -0
- package/src/web/components/chat/session-debug-dialog.tsx +2 -1
- package/src/web/components/chat/slash-command-picker.tsx +22 -3
- package/src/web/components/chat/tool-cards.tsx +47 -4
- package/src/web/components/chat/usage-badge.tsx +43 -447
- package/src/web/components/chat/user-message-parse.ts +33 -11
- package/src/web/components/database/database-viewer.tsx +34 -11
- package/src/web/components/database/extract-query-table.ts +24 -0
- package/src/web/components/database/glide-data-grid.tsx +11 -4
- package/src/web/components/database/glide-grid-types.ts +4 -0
- package/src/web/components/database/split-sql-statements.ts +116 -0
- package/src/web/components/database/sql-completion-provider.ts +1 -26
- package/src/web/components/database/sql-query-editor.tsx +2 -1
- package/src/web/components/database/use-database.ts +16 -1
- package/src/web/components/database/use-glide-cell-content.ts +11 -6
- package/src/web/components/editor/code-editor.tsx +30 -56
- package/src/web/components/floating-window/window-content-registry.ts +2 -0
- package/src/web/components/floating-window/window-store-types.ts +1 -1
- package/src/web/components/layout/command-palette.tsx +2 -2
- package/src/web/components/layout/mobile-drawer.tsx +5 -4
- package/src/web/components/layout/mobile-nav.tsx +5 -1
- package/src/web/components/layout/nav-section-rail.tsx +2 -1
- package/src/web/components/layout/project-bottom-sheet.tsx +3 -9
- package/src/web/components/layout/sidebar.tsx +0 -2
- package/src/web/components/layout/tab-pop-out-menu-item.tsx +3 -2
- package/src/web/components/settings/accounts/account-add-dialog.tsx +155 -0
- package/src/web/components/settings/accounts/account-backup-format.ts +19 -0
- package/src/web/components/settings/accounts/account-bucket-row.tsx +55 -0
- package/src/web/components/settings/accounts/account-card.tsx +127 -0
- package/src/web/components/settings/accounts/account-delete-confirm.tsx +62 -0
- package/src/web/components/settings/accounts/account-export-dialog.tsx +154 -0
- package/src/web/components/settings/accounts/account-export-simulation.tsx +196 -0
- package/src/web/components/settings/accounts/account-import-dialog.tsx +72 -0
- package/src/web/components/settings/accounts/account-profile-panel.tsx +52 -0
- package/src/web/components/{chat → settings/accounts}/account-rotation-settings.tsx +1 -1
- package/src/web/components/settings/accounts/account-token-test-dialog.tsx +147 -0
- package/src/web/components/settings/accounts/account-usage-format.ts +92 -0
- package/src/web/components/{chat/usage-pattern-chart.tsx → settings/accounts/account-usage-pattern-chart.tsx} +1 -1
- package/src/web/components/settings/accounts/accounts-pane-header.tsx +93 -0
- package/src/web/components/settings/accounts/accounts-settings-section.tsx +80 -0
- package/src/web/components/settings/accounts/claude-accounts-section.tsx +168 -0
- package/src/web/components/settings/accounts/codex-accounts-section.tsx +137 -0
- package/src/web/components/settings/accounts/codex-add-account-dialog.tsx +130 -0
- package/src/web/components/settings/accounts/codex-backup-dialog.tsx +101 -0
- package/src/web/components/settings/accounts/codex-rotation-dialog.tsx +65 -0
- package/src/web/components/settings/accounts/use-accounts-data.ts +81 -0
- package/src/web/components/settings/accounts/use-codex-accounts.ts +151 -0
- package/src/web/components/settings/ai-settings-section.tsx +14 -4
- package/src/web/components/settings/appearance-settings-section.tsx +125 -0
- package/src/web/components/settings/general-settings-section.tsx +87 -0
- package/src/web/components/settings/jira-watcher-section.tsx +34 -0
- package/src/web/components/settings/notifications-settings-section.tsx +37 -0
- package/src/web/components/settings/open-settings.ts +42 -0
- package/src/web/components/settings/resolve-open-settings-action.ts +45 -0
- package/src/web/components/settings/settings-body.tsx +110 -0
- package/src/web/components/settings/settings-categories.ts +102 -0
- package/src/web/components/settings/settings-category-list.tsx +56 -0
- package/src/web/components/settings/settings-category-rail.tsx +62 -0
- package/src/web/components/settings/settings-section-content.tsx +43 -0
- package/src/web/components/settings/settings-tab.tsx +15 -329
- package/src/web/components/settings/settings-window-content.tsx +24 -0
- package/src/web/hooks/use-chat.ts +44 -4
- package/src/web/hooks/use-global-keybindings.ts +3 -4
- package/src/web/hooks/use-url-sync.ts +30 -0
- package/src/web/hooks/use-usage.ts +23 -11
- package/src/web/lib/attachment-marker-split.ts +44 -0
- package/src/web/lib/image-animation.ts +51 -0
- package/src/web/lib/image-resize-limits.ts +47 -0
- package/src/web/lib/image-resize.ts +133 -0
- package/src/web/lib/sidebar-tabs/tab-registry.ts +9 -9
- package/src/web/lib/slash-items-cache.ts +27 -7
- package/src/web/stores/panel-utils.ts +11 -0
- package/src/web/stores/settings-store.ts +4 -2
- package/src/web/stores/window-panel-actions.ts +1 -3
- package/src/web/stores/window-panel-persistence.ts +9 -4
- package/dist/web/assets/adaptive-context-menu-JfuUSqbe.js +0 -1
- package/dist/web/assets/ai-resource-editor-MfdJKVM5.js +0 -1
- package/dist/web/assets/ai-settings-section-CJE7jFsj.js +0 -1
- package/dist/web/assets/api-client-DLWwuUkJ.js +0 -1
- package/dist/web/assets/api-settings-BFuaZrNC.js +0 -1
- package/dist/web/assets/api-settings-CPg4yGvS.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-6konx-J1.js +0 -1
- package/dist/web/assets/chat-tab-bSOVoC5N.js +0 -15
- package/dist/web/assets/chevron-right-D7Pn5agw.js +0 -1
- package/dist/web/assets/circle-4g2coECH.js +0 -1
- package/dist/web/assets/clipboard-B-gwJ8DF.js +0 -1
- package/dist/web/assets/clock-DbiNiwCG.js +0 -1
- package/dist/web/assets/code-DdKXqtf_.js +0 -1
- package/dist/web/assets/code-editor-COTa37oe.js +0 -10
- package/dist/web/assets/context-menu-BEAa1qhd.js +0 -1
- package/dist/web/assets/database-viewer-Dta7lSSk.js +0 -1
- package/dist/web/assets/dialog-DrL3WEXd.js +0 -1
- package/dist/web/assets/diff-viewer-CT0lmDc9.js +0 -4
- package/dist/web/assets/explorer-body-BGjR2Gbt.js +0 -2
- package/dist/web/assets/explorer-window-content-DAhHh5EQ.js +0 -1
- package/dist/web/assets/extension-store-ClQpnxQr.js +0 -1
- package/dist/web/assets/external-link-ojDHcQxQ.js +0 -1
- package/dist/web/assets/eye-off-Rq1n2-oe.js +0 -1
- package/dist/web/assets/file-store-28e44KP3.js +0 -1
- package/dist/web/assets/git-log-panel-D1-YXZ0O.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-ikUwsekd.js +0 -1
- package/dist/web/assets/glide-data-grid-BSsqxe2v.js +0 -138
- package/dist/web/assets/group-chat-tab-CMtzoaFc.js +0 -1
- package/dist/web/assets/index-BkHlMfPD.js +0 -52
- package/dist/web/assets/index-SFFv2-VM.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-BAgmboBp.js +0 -1
- package/dist/web/assets/input-DTmI80l2.js +0 -1
- package/dist/web/assets/keybindings-store-Bi0q9x4Q.js +0 -1
- package/dist/web/assets/keybindings-store-_KfovSz7.js +0 -1
- package/dist/web/assets/loader-circle-DD65e9-7.js +0 -1
- package/dist/web/assets/lock-BEtt_eTO.js +0 -1
- package/dist/web/assets/markdown-renderer-DroTmKbJ.js +0 -1
- package/dist/web/assets/markdown-renderer-ntDi3Tx-.js +0 -3
- package/dist/web/assets/mobile-explorer-sheet-BP6iU4ma.js +0 -1
- package/dist/web/assets/monitor-smartphone-C1wUPOSg.js +0 -1
- package/dist/web/assets/notification-store-II5Kw9rD.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-RVlbbDRS.js +0 -1
- package/dist/web/assets/panel-store-Dv28vz3L.js +0 -1
- package/dist/web/assets/pdf-preview-DKeIIJTv.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-ZWb4izpk.js +0 -1
- package/dist/web/assets/play-CPbVzGgq.js +0 -1
- package/dist/web/assets/plus-BxqD2FIZ.js +0 -1
- package/dist/web/assets/portal-container-context-BmG4--I-.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-bsP5x1Bx.js +0 -1
- package/dist/web/assets/refresh-cw-BALzw7L3.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-CYZUjYTO.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-view-DaoB49k4.js +0 -1
- package/dist/web/assets/remote-desktop-readiness-gate--LJgsuoj.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-Cihx4PNZ.js +0 -1
- package/dist/web/assets/rotate-ccw-CuvNBM80.js +0 -1
- package/dist/web/assets/scroll-area-B5yhPpZo.js +0 -1
- package/dist/web/assets/send-Cits8q0l.js +0 -1
- package/dist/web/assets/settings-store-Dp4i8zeA.js +0 -2
- package/dist/web/assets/settings-tab-BtMvvKAF.js +0 -3
- package/dist/web/assets/settings-tab-UPPycGRF.js +0 -1
- package/dist/web/assets/shallow-BBJ_qoEF.js +0 -1
- package/dist/web/assets/sql-query-editor-DZqnYIB7.js +0 -1
- package/dist/web/assets/sqlite-viewer-DXutos0e.js +0 -1
- package/dist/web/assets/switch-BPol3BFC.js +0 -1
- package/dist/web/assets/system-monitor-body-Ct8_GX_f.js +0 -2
- package/dist/web/assets/system-monitor-tab-DC_EerdI.js +0 -1
- package/dist/web/assets/system-monitor-window-content-D25DMNpw.js +0 -1
- package/dist/web/assets/team-member-sheet-DvmioeQL.js +0 -2
- package/dist/web/assets/team-member-window-content-BJ_XFw8-.js +0 -1
- package/dist/web/assets/tool-cards-pIu_cmEL.js +0 -8
- package/dist/web/assets/trash-2-BjShZ7if.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-Dh1oxNdQ.js +0 -1
- package/dist/web/assets/triangle-alert-qQ6Plydp.js +0 -1
- package/dist/web/assets/upload-7Zs6oaK5.js +0 -1
- package/dist/web/assets/use-monaco-theme-DaxAk3gB.js +0 -1
- package/dist/web/assets/use-open-team-member-CopUuDHG.js +0 -1
- package/dist/web/assets/use-remote-desktop-display-choice-BUA_1eaH.js +0 -1
- package/dist/web/assets/vendor-markdown-CKTlmXbz.js +0 -291
- package/dist/web/assets/video-preview-C2_fdunE.js +0 -1
- package/dist/web/assets/window-store-CNzkeUyO.js +0 -1
- package/dist/web/assets/x-Dzu9ecti.js +0 -1
- package/src/web/components/chat/account-dialogs.tsx +0 -384
- package/src/web/components/settings/accounts-settings-section.tsx +0 -1090
- package/src/web/components/settings/codex-accounts-section.tsx +0 -198
- package/src/web/components/settings/telegram-settings-section.tsx +0 -113
- /package/dist/web/assets/{abap-Cjj2olMr.js → abap-h3QyH8MW.js} +0 -0
- /package/dist/web/assets/{actionscript-3-DCkW7kWC.js → actionscript-3-mkxkq-FN.js} +0 -0
- /package/dist/web/assets/{ada-AEWvZXuX.js → ada-DhISK_EH.js} +0 -0
- /package/dist/web/assets/{andromeeda-D7cSpME6.js → andromeeda-DnlWWesX.js} +0 -0
- /package/dist/web/assets/{apache-DjvX0RSe.js → apache-P5AK3sfA.js} +0 -0
- /package/dist/web/assets/{apex-70xIZ0pH.js → apex-CJUPehg2.js} +0 -0
- /package/dist/web/assets/{applescript-C3qKqxmA.js → applescript-Dx6GGbay.js} +0 -0
- /package/dist/web/assets/{apply-theme-DJ794zSQ.js → apply-theme-DxTXOAcV.js} +0 -0
- /package/dist/web/assets/{ara-iGt2zixk.js → ara-95Kx3qKb.js} +0 -0
- /package/dist/web/assets/{asciidoc-Bs2t-06W.js → asciidoc-Dp0RbIej.js} +0 -0
- /package/dist/web/assets/{asm-B-T0eqhE.js → asm-C82coUjU.js} +0 -0
- /package/dist/web/assets/{aurora-x-D3h_9M3E.js → aurora-x-BFc3zeop.js} +0 -0
- /package/dist/web/assets/{awk-CZwfwpPi.js → awk-ChjC0icr.js} +0 -0
- /package/dist/web/assets/{ayu-dark-DulkglEA.js → ayu-dark-DYfUf_PB.js} +0 -0
- /package/dist/web/assets/{ayu-light-DyNQiRpn.js → ayu-light-Bh6O0plO.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-CcEt4xkI.js → ayu-mirage-DlNhHTGq.js} +0 -0
- /package/dist/web/assets/{ballerina-OhQPjyHS.js → ballerina-Ceoll3Sk.js} +0 -0
- /package/dist/web/assets/{bat-DqKcJTUn.js → bat-C7QS6Lfq.js} +0 -0
- /package/dist/web/assets/{beancount-BdXlMi8T.js → beancount-5NMEAZgs.js} +0 -0
- /package/dist/web/assets/{berry-DvgY6BkY.js → berry-BBL83Vbk.js} +0 -0
- /package/dist/web/assets/{bibtex-BSRJq0yM.js → bibtex-L7rPkPSG.js} +0 -0
- /package/dist/web/assets/{bicep-DpAdumKt.js → bicep-BOwHIINh.js} +0 -0
- /package/dist/web/assets/{bird2-rlbtp8di.js → bird2-CWLsMom2.js} +0 -0
- /package/dist/web/assets/{c-AjOLBXIs.js → c-CD4Ku5Cr.js} +0 -0
- /package/dist/web/assets/{c3-DqIXz4Ia.js → c3-CpMl-w3G.js} +0 -0
- /package/dist/web/assets/{cadence-DAJtUpOE.js → cadence-CvgF6ehN.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-CdCK2c2a.js → can-open-in-ppm-j3jh7fUo.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-DUPoeZfb.js → catppuccin-frappe-eo_dTm3F.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-CK3U68Ql.js → catppuccin-latte-DoiMCU_7.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-BzteLnIX.js → catppuccin-macchiato-UQxsK2Vh.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-ozLd0aBR.js → catppuccin-mocha-J0i-8RNy.js} +0 -0
- /package/dist/web/assets/{clarity-6KqEoBfz.js → clarity-DXYM8-SA.js} +0 -0
- /package/dist/web/assets/{clojure-B_uBL5C7.js → clojure-DzamsL69.js} +0 -0
- /package/dist/web/assets/{cmake-B3nxBNmj.js → cmake-CR6RP_T_.js} +0 -0
- /package/dist/web/assets/{codeowners-DkS-51at.js → codeowners-D1s6-IyY.js} +0 -0
- /package/dist/web/assets/{codeql-rpr1z_mR.js → codeql-DAqNWMkS.js} +0 -0
- /package/dist/web/assets/{common-lisp-BfNbv_W6.js → common-lisp-8e-KtitB.js} +0 -0
- /package/dist/web/assets/{coq-EAW-1nw0.js → coq-UEq0WUcO.js} +0 -0
- /package/dist/web/assets/{csharp-BE3Gn5bq.js → csharp-wxJ0TuCm.js} +0 -0
- /package/dist/web/assets/{css-Cr27CfPY.js → css-Cerub-yB.js} +0 -0
- /package/dist/web/assets/{csv-B5VtaPtH.js → csv-Bh9_WD_h.js} +0 -0
- /package/dist/web/assets/{csv-parser-B2v8MoUy.js → csv-parser-BPIDt6ni.js} +0 -0
- /package/dist/web/assets/{cue-jm6lYNrx.js → cue-rzM1ztqU.js} +0 -0
- /package/dist/web/assets/{cypher-DXkvK-pn.js → cypher-DGaTQ8m0.js} +0 -0
- /package/dist/web/assets/{d-CgG1_yzd.js → d-DbkZGuhB.js} +0 -0
- /package/dist/web/assets/{dark-plus-CALzcIVB.js → dark-plus-BO2bzZcA.js} +0 -0
- /package/dist/web/assets/{dart-BEVoLlWg.js → dart-BDhCoqVg.js} +0 -0
- /package/dist/web/assets/{dax-H0BW3Q_P.js → dax-Bh03stWh.js} +0 -0
- /package/dist/web/assets/{desktop-BtYq1l_0.js → desktop-BOdr_fwq.js} +0 -0
- /package/dist/web/assets/{diff-CnBYdfTg.js → diff-Bb_gTsS2.js} +0 -0
- /package/dist/web/assets/{dist-CJJKpgR7.js → dist-BUMDu0av.js} +0 -0
- /package/dist/web/assets/{docker-COBitpld.js → docker-BDsTF5ce.js} +0 -0
- /package/dist/web/assets/{dotenv-CG0x1m7c.js → dotenv-CbCWp9Ti.js} +0 -0
- /package/dist/web/assets/{dracula-CLCi47X-.js → dracula-Cd1fxvoX.js} +0 -0
- /package/dist/web/assets/{dracula-soft-BMv5cCAV.js → dracula-soft-B7eXkfXG.js} +0 -0
- /package/dist/web/assets/{dream-maker-1Bd4OSww.js → dream-maker-XlzuS21R.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-B-2zKLn-.js → emacs-lisp-CXV1Ki_7.js} +0 -0
- /package/dist/web/assets/{everforest-dark-BGVynCbV.js → everforest-dark-DuqR60Dg.js} +0 -0
- /package/dist/web/assets/{everforest-light--rn3R7Cm.js → everforest-light-q4BPnenD.js} +0 -0
- /package/dist/web/assets/{fennel-SWg9Us_u.js → fennel-B-e0TX2Q.js} +0 -0
- /package/dist/web/assets/{fish-B04oqgKk.js → fish-Bzb6-TtF.js} +0 -0
- /package/dist/web/assets/{fluent-BefzAGMN.js → fluent-B-szH2-f.js} +0 -0
- /package/dist/web/assets/{format-bytes-gQw5wzqa.js → format-bytes-CKXk9k2d.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-alw7jMxb.js → fortran-free-form-OS6SGYC0.js} +0 -0
- /package/dist/web/assets/{gdscript-BAyhvjCx.js → gdscript-FYq4OP2d.js} +0 -0
- /package/dist/web/assets/{gdshader-Crl09X-B.js → gdshader-BpG6P8rw.js} +0 -0
- /package/dist/web/assets/{genie-BSIGRHu7.js → genie-BS9RLAna.js} +0 -0
- /package/dist/web/assets/{gherkin-DJhSnSWH.js → gherkin-B_9FdtGs.js} +0 -0
- /package/dist/web/assets/{github-dark-r8C6qwug.js → github-dark-cfaIlnBV.js} +0 -0
- /package/dist/web/assets/{github-dark-default-FVtXjcm8.js → github-dark-default-B2Wv65He.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-CzrUPgSb.js → github-dark-dimmed-CtM9X76s.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-1s9rF5EB.js → github-dark-high-contrast-DLHyk0tG.js} +0 -0
- /package/dist/web/assets/{github-light-BvIWCkl7.js → github-light-DWEI10iG.js} +0 -0
- /package/dist/web/assets/{github-light-default-CVdhzrxV.js → github-light-default-DcJkK1YN.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-CBAf6hjF.js → github-light-high-contrast-Bcx9iKDt.js} +0 -0
- /package/dist/web/assets/{gleam-DvL1q7aa.js → gleam-DVpiM6b2.js} +0 -0
- /package/dist/web/assets/{gn-BG5NvwAf.js → gn-B80DNc0i.js} +0 -0
- /package/dist/web/assets/{gnuplot-BARnM-zG.js → gnuplot-D9i3MaT-.js} +0 -0
- /package/dist/web/assets/{go-DXvjjq4q.js → go-CwCBf_Pt.js} +0 -0
- /package/dist/web/assets/{groovy-CRylSKhr.js → groovy-D7mEfwmW.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-BVPjnqm7.js → gruvbox-dark-hard-C4R4MOoH.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-U_PDgq0a.js → gruvbox-dark-medium-CZnFC0s8.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-CkzNtpbr.js → gruvbox-dark-soft-DFcJlEBl.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-DfMmR2G8.js → gruvbox-light-hard-B6IF_1L-.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-BGCak-dd.js → gruvbox-light-medium-C19AZJv2.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-DnpM3fkN.js → gruvbox-light-soft-BAnpDm9B.js} +0 -0
- /package/dist/web/assets/{haskell-DXgGIDD_.js → haskell-CsXSYXRG.js} +0 -0
- /package/dist/web/assets/{haxe-B7qlTpRz.js → haxe-B1uyiI9t.js} +0 -0
- /package/dist/web/assets/{hcl-ADWfVe_Q.js → hcl-DlYKn5q9.js} +0 -0
- /package/dist/web/assets/{hjson-BaM9gLbq.js → hjson-C_0VMGJJ.js} +0 -0
- /package/dist/web/assets/{hlsl-iqaRA4MG.js → hlsl-zt2PEzbg.js} +0 -0
- /package/dist/web/assets/{horizon-BPpTnhB9.js → horizon-6wQfyOK0.js} +0 -0
- /package/dist/web/assets/{horizon-bright-yBLg3QbE.js → horizon-bright-CqI2qTim.js} +0 -0
- /package/dist/web/assets/{houston-eFOp0ySL.js → houston-BljpHDoG.js} +0 -0
- /package/dist/web/assets/{hy-BALeMn3i.js → hy-XzuL55dw.js} +0 -0
- /package/dist/web/assets/{image-gallery-Bqb-wjNw.js → image-gallery-Cj8nd4xW.js} +0 -0
- /package/dist/web/assets/{imba-CdGUm_GD.js → imba-CqhhjBrP.js} +0 -0
- /package/dist/web/assets/{ini-DG7imsqe.js → ini-CiFDi6cY.js} +0 -0
- /package/dist/web/assets/{java-D5GTT474.js → java-OsQgTL5-.js} +0 -0
- /package/dist/web/assets/{javascript-V7WwJvRm.js → javascript-qWAOScxl.js} +0 -0
- /package/dist/web/assets/{json-B9FhwAgR.js → json-RiAKsaD1.js} +0 -0
- /package/dist/web/assets/{json5--Abk7MUy.js → json5-BeCnS3H2.js} +0 -0
- /package/dist/web/assets/{jsonc-C8jb-Z6x.js → jsonc-CbTW1Mka.js} +0 -0
- /package/dist/web/assets/{jsonl-CaJNxfkm.js → jsonl-BLSi_669.js} +0 -0
- /package/dist/web/assets/{jsonnet-CPrKMSCU.js → jsonnet-C3xAggou.js} +0 -0
- /package/dist/web/assets/{jssm-DEu-9_uo.js → jssm-CLdiagC9.js} +0 -0
- /package/dist/web/assets/{jsx-MfAsCWDW.js → jsx-lYE1lb50.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-DnbcAduF.js → kanagawa-dragon-Cd1vcrpD.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-yxsY3ew8.js → kanagawa-lotus-Dw3QKtk9.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-C2RyvZaM.js → kanagawa-wave-DIq5Zv5G.js} +0 -0
- /package/dist/web/assets/{kdl-CvssmvcU.js → kdl-BfDV0825.js} +0 -0
- /package/dist/web/assets/{kotlin-jufO49mU.js → kotlin-DONxR4wD.js} +0 -0
- /package/dist/web/assets/{kusto-BAFnylR7.js → kusto-BDP63Fh5.js} +0 -0
- /package/dist/web/assets/{laserwave-BgxFC4Ge.js → laserwave-BeBrWApL.js} +0 -0
- /package/dist/web/assets/{lean-Bgt24V1D.js → lean-DOZc0N1A.js} +0 -0
- /package/dist/web/assets/{less-Bk_UaqsM.js → less-C3H9NlDv.js} +0 -0
- /package/dist/web/assets/{libesm-dcbw4_18.js → libesm-DLBE59ul.js} +0 -0
- /package/dist/web/assets/{light-plus-nMxFfInN.js → light-plus-C_kTL608.js} +0 -0
- /package/dist/web/assets/{llvm-3_PASDOO.js → llvm-Dsp27U3P.js} +0 -0
- /package/dist/web/assets/{log-CKm0CxB1.js → log-BywQaTCy.js} +0 -0
- /package/dist/web/assets/{logo-DFP1_5U6.js → logo-BirJgciO.js} +0 -0
- /package/dist/web/assets/{luau-BcZnoyh3.js → luau-Btrz5kJB.js} +0 -0
- /package/dist/web/assets/{make-CpNSwgwT.js → make-Kl7nFQrS.js} +0 -0
- /package/dist/web/assets/{markdown-DhU3Djpv.js → markdown-qsC4P8S-.js} +0 -0
- /package/dist/web/assets/{material-theme-DD5L3OqF.js → material-theme-CC__ui3p.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-CG2_tD3R.js → material-theme-darker-D4FxG2FZ.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-CzNkUc9Y.js → material-theme-lighter-zGqiWcxn.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-BtLiAaF_.js → material-theme-ocean-CZIdTTB1.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-Brvjz035.js → material-theme-palenight-CEIs0GcK.js} +0 -0
- /package/dist/web/assets/{matlab-CCY0KtMD.js → matlab-Cf0aUjN9.js} +0 -0
- /package/dist/web/assets/{mdx-CH6YY0aS.js → mdx-CIsXjH86.js} +0 -0
- /package/dist/web/assets/{mermaid-Bqh3gFI0.js → mermaid-B06WO9Qc.js} +0 -0
- /package/dist/web/assets/{min-dark-BUwfTzI6.js → min-dark-z8fyp0FT.js} +0 -0
- /package/dist/web/assets/{min-light-oLanXCOk.js → min-light-Dr-qesbW.js} +0 -0
- /package/dist/web/assets/{mipsasm-CTh3hPWK.js → mipsasm-CWHzYLcE.js} +0 -0
- /package/dist/web/assets/{mojo-DXdszZKa.js → mojo-D9zXrKmv.js} +0 -0
- /package/dist/web/assets/{monokai-TNE_tRxc.js → monokai-4b-AKOpX.js} +0 -0
- /package/dist/web/assets/{moonbit-jrk-Gx1X.js → moonbit-Dl4dhOZJ.js} +0 -0
- /package/dist/web/assets/{move-DItn61bH.js → move-DTYKJmXy.js} +0 -0
- /package/dist/web/assets/{narrat-3kB4dkh0.js → narrat-DnvXOS-o.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-CSKtwETr.js → nextflow-groovy-Di8QnEXg.js} +0 -0
- /package/dist/web/assets/{night-owl-Dm91nSIq.js → night-owl-Czh0yq-H.js} +0 -0
- /package/dist/web/assets/{night-owl-light-riwrcPRg.js → night-owl-light-D_OpZqOR.js} +0 -0
- /package/dist/web/assets/{nix-sLgl9zGF.js → nix-2MvcjpK3.js} +0 -0
- /package/dist/web/assets/{nord-TWkJPI6M.js → nord-CG_r4cyk.js} +0 -0
- /package/dist/web/assets/{nushell-CDZi4-Gf.js → nushell-DINskMcU.js} +0 -0
- /package/dist/web/assets/{objective-c-DW9PboNp.js → objective-c-Dv7BIicR.js} +0 -0
- /package/dist/web/assets/{objective-cpp-2XCCX6q1.js → objective-cpp-CpqsCxPb.js} +0 -0
- /package/dist/web/assets/{ocaml-CxPdnjrh.js → ocaml-DwTsYSmW.js} +0 -0
- /package/dist/web/assets/{odin-BJjlKpkM.js → odin-G-4O4k4t.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-K1KOmBZ7.js → one-dark-pro-13Pv5SjI.js} +0 -0
- /package/dist/web/assets/{one-light-DQB-vUyZ.js → one-light-Bi2e86mS.js} +0 -0
- /package/dist/web/assets/{openscad-DCoLwn4j.js → openscad-D0WsOTij.js} +0 -0
- /package/dist/web/assets/{pascal-z2ktbbWp.js → pascal-DmDStuXr.js} +0 -0
- /package/dist/web/assets/{pkl-Dyq4-v6z.js → pkl-Bl6Qjtuo.js} +0 -0
- /package/dist/web/assets/{plastic-C4Rq5PnD.js → plastic-UeSVSjTI.js} +0 -0
- /package/dist/web/assets/{plsql-BCIjO63y.js → plsql-DreFC689.js} +0 -0
- /package/dist/web/assets/{po-_kXpd_0n.js → po-ZIjccxsX.js} +0 -0
- /package/dist/web/assets/{poimandres-C9XggjB3.js → poimandres-CvQHJPrI.js} +0 -0
- /package/dist/web/assets/{polar-DV_1L04z.js → polar-BrMB0Kgh.js} +0 -0
- /package/dist/web/assets/{postcss-BuqS91mQ.js → postcss-pgUsil1T.js} +0 -0
- /package/dist/web/assets/{powerquery-DK13B2Dc.js → powerquery-CTsZkCg_.js} +0 -0
- /package/dist/web/assets/{powershell-tkuhhtuP.js → powershell-CcwVuBAp.js} +0 -0
- /package/dist/web/assets/{prisma-WNXfBtpr.js → prisma-spjnAI5W.js} +0 -0
- /package/dist/web/assets/{prolog-BzEdNKfO.js → prolog-ChCkZpDO.js} +0 -0
- /package/dist/web/assets/{proto-B5meVsrA.js → proto-wVGqK4gB.js} +0 -0
- /package/dist/web/assets/{puppet-C7h_p4r2.js → puppet-CED7iwPQ.js} +0 -0
- /package/dist/web/assets/{purescript-qH1KxAs6.js → purescript-u9lGiQKV.js} +0 -0
- /package/dist/web/assets/{python-DeTIYd5V.js → python-DeqTx6ef.js} +0 -0
- /package/dist/web/assets/{qmldir-4Rm5AvD3.js → qmldir-BH1uoPrX.js} +0 -0
- /package/dist/web/assets/{qss-YRbeNtr0.js → qss-CUVKA_13.js} +0 -0
- /package/dist/web/assets/{r-DHwHK0Jh.js → r-BqdPzqYH.js} +0 -0
- /package/dist/web/assets/{racket-gKn4SFLQ.js → racket-C2eTgPN3.js} +0 -0
- /package/dist/web/assets/{raku-DWTmAj3A.js → raku-uAay1sWx.js} +0 -0
- /package/dist/web/assets/{red-BFuHRZFS.js → red-DTZP1ZfC.js} +0 -0
- /package/dist/web/assets/{reg-DYoOF5tH.js → reg-Cdk3YsxY.js} +0 -0
- /package/dist/web/assets/{regexp-6rXQHD2-.js → regexp-Bpa2aS7K.js} +0 -0
- /package/dist/web/assets/{rel-Z_tTruCU.js → rel-bNsb1-3L.js} +0 -0
- /package/dist/web/assets/{resolve-theme-4fexHWl6.js → resolve-theme-DQk_YcsT.js} +0 -0
- /package/dist/web/assets/{riscv-DfTfKuvU.js → riscv-DSaubByW.js} +0 -0
- /package/dist/web/assets/{ron-CsUtW8gQ.js → ron-DbQzYM6i.js} +0 -0
- /package/dist/web/assets/{rose-pine-Dng_vCo6.js → rose-pine-C7RsprTu.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-Ds88Nezf.js → rose-pine-dawn-VP976YzL.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-DWpzrqNz.js → rose-pine-moon-XHZNhOqd.js} +0 -0
- /package/dist/web/assets/{rosmsg-h2sO84oD.js → rosmsg-BVQlx0Lj.js} +0 -0
- /package/dist/web/assets/{rust-Dx86yfCi.js → rust-VHaQ3rh3.js} +0 -0
- /package/dist/web/assets/{sass-BwwVhdT9.js → sass-CO-kMkwD.js} +0 -0
- /package/dist/web/assets/{scala-WJqNEN-w.js → scala-cY0GXkiz.js} +0 -0
- /package/dist/web/assets/{scheme-uwj-t1Rp.js → scheme-D4LNZE0X.js} +0 -0
- /package/dist/web/assets/{sdbl-BYy5hgEz.js → sdbl-Bh2Fd2cn.js} +0 -0
- /package/dist/web/assets/{shellscript-DWTW_w2K.js → shellscript-KKclmCnt.js} +0 -0
- /package/dist/web/assets/{slack-dark-BvhGq5vQ.js → slack-dark-D6YQ-fqf.js} +0 -0
- /package/dist/web/assets/{slack-ochin-C9g0ZRFr.js → slack-ochin-CDf66CDj.js} +0 -0
- /package/dist/web/assets/{smalltalk-ZEiZ6i7U.js → smalltalk-D2OH_QIl.js} +0 -0
- /package/dist/web/assets/{snazzy-light-29OA24q5.js → snazzy-light-CQeF8G1K.js} +0 -0
- /package/dist/web/assets/{solarized-dark-Bnq9IOn_.js → solarized-dark-LTPf1iLZ.js} +0 -0
- /package/dist/web/assets/{solarized-light-CYdI7T5g.js → solarized-light-Ose1n88k.js} +0 -0
- /package/dist/web/assets/{solidity-DcuIDB-_.js → solidity-lFuOMHki.js} +0 -0
- /package/dist/web/assets/{splunk-D5ONE91g.js → splunk-Bov-sB5S.js} +0 -0
- /package/dist/web/assets/{sql-DIwJJDU-.js → sql-BKyZ6wmk.js} +0 -0
- /package/dist/web/assets/{ssh-config-D8717tLI.js → ssh-config-CqJoMGMb.js} +0 -0
- /package/dist/web/assets/{stylus-Cm1lO4Y6.js → stylus-Bf5pWRLI.js} +0 -0
- /package/dist/web/assets/{swift-X8oWpSeU.js → swift-D5d1hn_u.js} +0 -0
- /package/dist/web/assets/{synthwave-84-DF-t1UKY.js → synthwave-84-B4c6YAgO.js} +0 -0
- /package/dist/web/assets/{system-verilog-JYyHFpPf.js → system-verilog-D7fXyDsI.js} +0 -0
- /package/dist/web/assets/{systemd-Da-5Ma_c.js → systemd-oNagzlBK.js} +0 -0
- /package/dist/web/assets/{talonscript-CXraVPho.js → talonscript-C6Nqm9Dm.js} +0 -0
- /package/dist/web/assets/{tasl-BCmWezH9.js → tasl-CaWy-cBX.js} +0 -0
- /package/dist/web/assets/{tcl-BTufzfbf.js → tcl-C435P5Mq.js} +0 -0
- /package/dist/web/assets/{terraform-CtUA9c8W.js → terraform-CVDxqdPf.js} +0 -0
- /package/dist/web/assets/{tokyo-night-BCThYXmz.js → tokyo-night-Uhs17tQ3.js} +0 -0
- /package/dist/web/assets/{toml-D5YlDr6Y.js → toml-j6fPOJ6P.js} +0 -0
- /package/dist/web/assets/{tsv-CBB-P_Sl.js → tsv-h78O6xrL.js} +0 -0
- /package/dist/web/assets/{tsx-D5B4juDp.js → tsx-Bol-vCrQ.js} +0 -0
- /package/dist/web/assets/{turtle-D8PCeJ-v.js → turtle-Dw8eFf04.js} +0 -0
- /package/dist/web/assets/{typescript-CMPnTawp.js → typescript-Dtz7DPci.js} +0 -0
- /package/dist/web/assets/{typespec-CHxldxIW.js → typespec-BIOQ7dMP.js} +0 -0
- /package/dist/web/assets/{typst-Q8CqX5OR.js → typst-CoaGMjzu.js} +0 -0
- /package/dist/web/assets/{utils-QHe_Q6UF.js → utils-C9OjCrou.js} +0 -0
- /package/dist/web/assets/{v-Bf2hKAMu.js → v-BoqFdpJ7.js} +0 -0
- /package/dist/web/assets/{vala-Cbete-UE.js → vala-COBpNnCC.js} +0 -0
- /package/dist/web/assets/{vb-CA-xWAcX.js → vb-DxI86znh.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-BHKF_Nsf.js → vendor-xterm-BaMOj65g.js} +0 -0
- /package/dist/web/assets/{verilog-B3wb8CfT.js → verilog-DcTAamuQ.js} +0 -0
- /package/dist/web/assets/{vesper-D6r3VJq_.js → vesper-DO298JSv.js} +0 -0
- /package/dist/web/assets/{vhdl-C42S_797.js → vhdl-Dq-bDVSN.js} +0 -0
- /package/dist/web/assets/{viml-BePrIAs8.js → viml-zHTRWuQh.js} +0 -0
- /package/dist/web/assets/{vitesse-black-DRqn61Ck.js → vitesse-black-jlYMJCBf.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-39_8UE-w.js → vitesse-dark-DS0sUlSZ.js} +0 -0
- /package/dist/web/assets/{vitesse-light-B1jwrxDm.js → vitesse-light-HSeZ2YhG.js} +0 -0
- /package/dist/web/assets/{vyper-tDJv3imF.js → vyper-BQfKVO3M.js} +0 -0
- /package/dist/web/assets/{wasm-ChtccNfv.js → wasm-B1xp9bLp.js} +0 -0
- /package/dist/web/assets/{wasm-DR7eskZH.js → wasm-B6mCuI8h.js} +0 -0
- /package/dist/web/assets/{wenyan-CezVfqN3.js → wenyan-CfpS05sP.js} +0 -0
- /package/dist/web/assets/{wgsl-CwOcIiIG.js → wgsl-14GDsWRD.js} +0 -0
- /package/dist/web/assets/{wikitext-C5coomYc.js → wikitext-Ccbq5EVX.js} +0 -0
- /package/dist/web/assets/{wit-C9yyX6-U.js → wit-C19hb3R5.js} +0 -0
- /package/dist/web/assets/{wolfram-BWi0rMAa.js → wolfram-B-ZSwGwP.js} +0 -0
- /package/dist/web/assets/{yaml-CGXhKUtT.js → yaml-mw_JUeio.js} +0 -0
- /package/dist/web/assets/{zenscript-Do7WLoJh.js → zenscript-WbzDRjvF.js} +0 -0
- /package/dist/web/assets/{zig-Cr80Qrru.js → zig-F0vvImTJ.js} +0 -0
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
Clock,
|
|
37
37
|
Send,
|
|
38
38
|
Users,
|
|
39
|
+
ImagePlus,
|
|
39
40
|
} from "lucide-react";
|
|
40
41
|
|
|
41
42
|
/**
|
|
@@ -86,6 +87,8 @@ function toolChip(
|
|
|
86
87
|
return { Icon: ClipboardList, cls: "bg-accent-wash text-primary" };
|
|
87
88
|
case "Skill":
|
|
88
89
|
return { Icon: Sparkles, cls: "bg-accent-2/15 text-accent-2" };
|
|
90
|
+
case "ImageGen":
|
|
91
|
+
return { Icon: ImagePlus, cls: "bg-accent-2/15 text-accent-2" };
|
|
89
92
|
default:
|
|
90
93
|
return { Icon: Code, cls: "bg-panel-2 text-text-2" };
|
|
91
94
|
}
|
|
@@ -115,13 +118,21 @@ function extractToolInfo(tool: ChatEvent): { toolName: string; input: Record<str
|
|
|
115
118
|
return { toolName, input };
|
|
116
119
|
}
|
|
117
120
|
|
|
121
|
+
/** Tools whose `file_path` names an image the card should render inline. */
|
|
122
|
+
const IMAGE_PATH_TOOLS = new Set([
|
|
123
|
+
"Read",
|
|
124
|
+
// Codex image generation. The picture it just wrote is the whole point of the
|
|
125
|
+
// card, so it is previewed exactly like a Read of that same file.
|
|
126
|
+
"ImageGen",
|
|
127
|
+
]);
|
|
128
|
+
|
|
118
129
|
/**
|
|
119
|
-
* Path of the image a
|
|
130
|
+
* Path of the image a call targeted, or null when it is not a displayable image.
|
|
120
131
|
* Only absolute paths qualify, matching what useBlobUrl can resolve to the external
|
|
121
|
-
* raw-file endpoint — and what
|
|
132
|
+
* raw-file endpoint — and what both Read and ImageGen always supply.
|
|
122
133
|
*/
|
|
123
134
|
function imageReadPath(tool: ChatEvent): string | null {
|
|
124
|
-
if (tool.type !== "tool_use" || tool.tool
|
|
135
|
+
if (tool.type !== "tool_use" || !IMAGE_PATH_TOOLS.has(tool.tool)) return null;
|
|
125
136
|
const path = (tool.input as Record<string, unknown> | undefined)?.file_path;
|
|
126
137
|
if (typeof path !== "string" || !/^(\/|[A-Za-z]:[/\\])/.test(path)) return null;
|
|
127
138
|
return isImageExtension(path) ? path : null;
|
|
@@ -187,6 +198,9 @@ export function ToolCard({
|
|
|
187
198
|
// Hide the text output only when the result really carried an image. Extension is not
|
|
188
199
|
// enough: an SVG or an undecodable format comes back as text that must stay visible.
|
|
189
200
|
const resultIsImage = hasResult && resultHasImagePlaceholder(String((result as any).output ?? ""));
|
|
201
|
+
// When the card renders the picture, the preview below it already names the
|
|
202
|
+
// file, so echoing the path as result text just prints it a second time.
|
|
203
|
+
const previewIsTheResult = !!imagePath;
|
|
190
204
|
|
|
191
205
|
// Read partial output for streaming Bash/PowerShell tools
|
|
192
206
|
const toolUseId = tool.type === "tool_use" ? (tool as any).toolUseId as string | undefined : undefined;
|
|
@@ -264,7 +278,8 @@ export function ToolCard({
|
|
|
264
278
|
{imagePath && (
|
|
265
279
|
<ToolImagePreview filePath={imagePath} projectName={projectName ?? ""} />
|
|
266
280
|
)}
|
|
267
|
-
{hasResult && !(isFileMutation && !isError) && !(resultIsImage && !isError)
|
|
281
|
+
{hasResult && !(isFileMutation && !isError) && !(resultIsImage && !isError)
|
|
282
|
+
&& !(previewIsTheResult && !isError) && (
|
|
268
283
|
<ToolResultView toolName={toolName} output={(result as any).output} />
|
|
269
284
|
)}
|
|
270
285
|
</div>
|
|
@@ -298,6 +313,19 @@ function ToolSummary({ name, input }: { name: string; input: Record<string, unkn
|
|
|
298
313
|
return <><Globe className="size-3 inline" /> {name} <span className="text-text-subtle">{truncate(s(input.url), 50)}</span></>;
|
|
299
314
|
case "ToolSearch":
|
|
300
315
|
return <><Search className="size-3 inline" /> {name} <span className="text-text-subtle">{truncate(s(input.query), 50)}</span></>;
|
|
316
|
+
case "ImageGen": {
|
|
317
|
+
// The revised prompt codex generated is long and multi-line ("Use case:…
|
|
318
|
+
// Subject:… Lighting:…"); its first line is the useful label. The
|
|
319
|
+
// thumbnail below carries the actual result, so the header stays short.
|
|
320
|
+
const firstLine = s(input.prompt).split("\n").find((l) => l.trim()) ?? "";
|
|
321
|
+
const label = firstLine || basename(s(input.file_path));
|
|
322
|
+
return (
|
|
323
|
+
<>
|
|
324
|
+
<ImagePlus className="size-3 inline" /> Image
|
|
325
|
+
<span className="text-text-subtle"> {truncate(label, 50)}</span>
|
|
326
|
+
</>
|
|
327
|
+
);
|
|
328
|
+
}
|
|
301
329
|
case "Agent":
|
|
302
330
|
case "Task": {
|
|
303
331
|
// Lead with the handle when there is one: it is both the identity of the
|
|
@@ -564,6 +592,21 @@ function ToolDetails({
|
|
|
564
592
|
<TaskStatusBadge status="stopped" />
|
|
565
593
|
</div>
|
|
566
594
|
);
|
|
595
|
+
case "ImageGen":
|
|
596
|
+
// The picture is the card. Dumping the input as JSON put the file path on
|
|
597
|
+
// screen a third time — the thumbnail and the result line already carry
|
|
598
|
+
// it — and buried the one part worth reading, the prompt, inside quoting
|
|
599
|
+
// and escaped newlines.
|
|
600
|
+
return (
|
|
601
|
+
<div className="space-y-1">
|
|
602
|
+
{!!input.prompt && (
|
|
603
|
+
<p className="text-text-secondary whitespace-pre-wrap">{s(input.prompt)}</p>
|
|
604
|
+
)}
|
|
605
|
+
{input.transparentBackground === true && (
|
|
606
|
+
<p className="text-text-subtle">Transparent background</p>
|
|
607
|
+
)}
|
|
608
|
+
</div>
|
|
609
|
+
);
|
|
567
610
|
default:
|
|
568
611
|
return (
|
|
569
612
|
<pre className="overflow-x-auto text-text-secondary font-mono whitespace-pre-wrap break-all">
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from "
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
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
|
-
|
|
259
|
-
|
|
260
|
-
const
|
|
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
|
|
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=
|
|
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
|
|
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={() =>
|
|
396
|
-
className="text-
|
|
397
|
-
title="
|
|
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
|
-
<
|
|
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();
|
|
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={
|
|
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
|
-
{
|
|
430
|
-
<div className="
|
|
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
|
-
|
|
450
|
-
<
|
|
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
|
}
|