@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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-image dimension ceiling the API applies, and the arithmetic for staying under it.
|
|
3
|
+
*
|
|
4
|
+
* Shared because both ends of the pipeline need the same number: the browser downscales an
|
|
5
|
+
* attachment before it is ever uploaded, and the transcript tooling reports on images that
|
|
6
|
+
* slipped in from elsewhere (another client, an older build) still carrying the full size.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Longest side, in pixels, at which the API starts refusing an image once a request carries
|
|
11
|
+
* several of them. The value is a ceiling, so an image measuring exactly this is already over
|
|
12
|
+
* it — comparisons are `>=`, and a downscale targets strictly below.
|
|
13
|
+
*/
|
|
14
|
+
export const MAX_IMAGE_DIMENSION = 2000;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Dimensions that bring an image under the cap, or null when it is already small enough.
|
|
18
|
+
*
|
|
19
|
+
* Scales the longest side to one pixel below the cap and takes the other side with it, so the
|
|
20
|
+
* aspect ratio survives and the result cannot land back on the boundary through rounding.
|
|
21
|
+
*/
|
|
22
|
+
export function fitWithin(
|
|
23
|
+
width: number,
|
|
24
|
+
height: number,
|
|
25
|
+
max: number = MAX_IMAGE_DIMENSION,
|
|
26
|
+
): { width: number; height: number } | null {
|
|
27
|
+
if (!(width > 0) || !(height > 0)) return null;
|
|
28
|
+
const longest = Math.max(width, height);
|
|
29
|
+
if (longest < max) return null;
|
|
30
|
+
|
|
31
|
+
const target = max - 1;
|
|
32
|
+
const scale = target / longest;
|
|
33
|
+
return {
|
|
34
|
+
width: width >= height ? target : Math.max(1, Math.round(width * scale)),
|
|
35
|
+
height: height > width ? target : Math.max(1, Math.round(height * scale)),
|
|
36
|
+
};
|
|
37
|
+
}
|
package/src/types/api.ts
CHANGED
|
@@ -23,7 +23,9 @@ export type TerminalWsMessage =
|
|
|
23
23
|
|
|
24
24
|
/** WebSocket message types (chat) */
|
|
25
25
|
export type ChatWsClientMessage =
|
|
26
|
-
| { type: "message"; content: string; permissionMode?: string; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }>;
|
|
26
|
+
| { type: "message"; content: string; permissionMode?: string; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }>;
|
|
27
|
+
/** Uploaded paths for the same images, for providers that take a file not a payload. */
|
|
28
|
+
imagePaths?: string[]; model?: string; effort?: string; thinking?: boolean }
|
|
27
29
|
| { type: "cancel" }
|
|
28
30
|
| { type: "set_model"; model: string }
|
|
29
31
|
| { type: "set_effort"; effort: string }
|
package/src/types/chat.ts
CHANGED
|
@@ -2,6 +2,12 @@ export interface SendMessageOpts {
|
|
|
2
2
|
permissionMode?: import("./config").PermissionMode | string;
|
|
3
3
|
priority?: 'now' | 'next' | 'later';
|
|
4
4
|
images?: Array<{ data: string; mediaType: string }>;
|
|
5
|
+
/**
|
|
6
|
+
* Uploaded paths for the same attachments, for providers that take a file rather than a
|
|
7
|
+
* payload. Codex's turn input accepts `localImage` by path and has no base64 form, so an
|
|
8
|
+
* image reaches it this way or not at all.
|
|
9
|
+
*/
|
|
10
|
+
imagePaths?: string[];
|
|
5
11
|
/** Per-session model override; falls back to provider config model when absent */
|
|
6
12
|
model?: string;
|
|
7
13
|
/** Override the provider's 1M-context setting for this call (false = never add the
|
|
@@ -45,8 +51,14 @@ export interface AIProvider {
|
|
|
45
51
|
markAsResumed?(sessionId: string): void;
|
|
46
52
|
isAvailable?(): Promise<boolean>;
|
|
47
53
|
listModels?(): Promise<ModelOption[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Skills the provider's own runtime would resolve for this session, for
|
|
56
|
+
* providers that own a skill system PPM cannot read off disk. Implemented by
|
|
57
|
+
* codex; absent for Claude, whose skills come from the shared disk discovery.
|
|
58
|
+
*/
|
|
59
|
+
listSkills?(sessionId?: string): Promise<import("../providers/codex-app-server/codex-protocol").CodexSkill[]>;
|
|
48
60
|
/** Provider-specific usage/quota (rate limits). Used by GET /chat/usage. */
|
|
49
|
-
getUsage?(): Promise<UsageInfo>;
|
|
61
|
+
getUsage?(sessionId?: string): Promise<UsageInfo>;
|
|
50
62
|
/** True when a live streaming subprocess exists for this session */
|
|
51
63
|
hasStreamingSession?(sessionId: string): boolean;
|
|
52
64
|
/** Prompt-cache lifetime for this session, in ms — how long holding its subprocess pays. */
|
|
@@ -22,6 +22,8 @@ export interface TreeItemMsg {
|
|
|
22
22
|
description?: string;
|
|
23
23
|
tooltip?: string;
|
|
24
24
|
icon?: string;
|
|
25
|
+
/** Label wraps instead of truncating — for rows whose text is the content. */
|
|
26
|
+
wrap?: boolean;
|
|
25
27
|
collapsibleState: "none" | "collapsed" | "expanded";
|
|
26
28
|
command?: string;
|
|
27
29
|
children?: TreeItemMsg[];
|
package/src/web/app.tsx
CHANGED
|
@@ -58,15 +58,9 @@ export function App() {
|
|
|
58
58
|
const [authState, setAuthState] = useState<AuthState>("checking");
|
|
59
59
|
const isMobileViewport = useIsMobile();
|
|
60
60
|
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
61
|
-
const [drawerTab, setDrawerTab] = useState<"explorer" | "git" |
|
|
61
|
+
const [drawerTab, setDrawerTab] = useState<"explorer" | "git" | undefined>();
|
|
62
62
|
const [projectSheetOpen, setProjectSheetOpen] = useState(false);
|
|
63
63
|
|
|
64
|
-
// Listen for "open-mobile-settings" event (from project bottom sheet)
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
const handler = () => { setDrawerTab("settings"); setDrawerOpen(true); };
|
|
67
|
-
window.addEventListener("open-mobile-settings", handler);
|
|
68
|
-
return () => window.removeEventListener("open-mobile-settings", handler);
|
|
69
|
-
}, []);
|
|
70
64
|
const [mountedProjects, setMountedProjects] = useState<Set<string>>(
|
|
71
65
|
() => new Set(["__global__"]),
|
|
72
66
|
);
|
|
@@ -52,6 +52,16 @@ export function AttachmentChips({ attachments, onRemove }: AttachmentChipsProps)
|
|
|
52
52
|
<Loader2 className="size-3 shrink-0 animate-spin text-text-subtle" />
|
|
53
53
|
) : att.status === "error" ? (
|
|
54
54
|
<span className="text-error shrink-0" title="Upload failed">!</span>
|
|
55
|
+
) : att.resized ? (
|
|
56
|
+
// Says what happened to the image. A screenshot arriving at the model smaller
|
|
57
|
+
// than the one that was pasted is worth stating rather than leaving to be
|
|
58
|
+
// discovered, and the measurement was already being recorded for nothing.
|
|
59
|
+
<span
|
|
60
|
+
className="shrink-0 text-[10px] text-text-subtle"
|
|
61
|
+
title={`Shrunk from ${att.resized.from.width}x${att.resized.from.height} to ${att.resized.to.width}x${att.resized.to.height}`}
|
|
62
|
+
>
|
|
63
|
+
{att.resized.to.width}×{att.resized.to.height}
|
|
64
|
+
</span>
|
|
55
65
|
) : null}
|
|
56
66
|
|
|
57
67
|
{/* Remove button */}
|
|
@@ -325,7 +325,16 @@ export function ChatHistoryBar({
|
|
|
325
325
|
>
|
|
326
326
|
<Activity className="size-3" />
|
|
327
327
|
{usageInfo.activeAccountLabel && (
|
|
328
|
-
|
|
328
|
+
// Which account is serving this session, per provider. An email
|
|
329
|
+
// label is unreadable cut to 60px ("hienlh1298@…"), and the
|
|
330
|
+
// account is the thing a multi-account user checks here, so it
|
|
331
|
+
// gets the room and the full string on hover.
|
|
332
|
+
<span
|
|
333
|
+
className="text-text-secondary font-normal truncate max-w-[110px]"
|
|
334
|
+
title={usageInfo.activeAccountLabel}
|
|
335
|
+
>
|
|
336
|
+
[{usageInfo.activeAccountLabel}]
|
|
337
|
+
</span>
|
|
329
338
|
)}
|
|
330
339
|
<span>5h:{fiveHourPct != null ? `${fiveHourPct}%` : "--%"}</span>
|
|
331
340
|
<span className="text-text-subtle">·</span>
|
|
@@ -2,6 +2,8 @@ import { useState, useCallback, useRef, useEffect } from "react";
|
|
|
2
2
|
import { Loader2, Upload, X } from "lucide-react";
|
|
3
3
|
import { toast } from "sonner";
|
|
4
4
|
import { api, projectUrl } from "@/lib/api-client";
|
|
5
|
+
import { selectInlineImages } from "@/lib/image-resize-limits";
|
|
6
|
+
import { splitAttachmentMarkers } from "@/lib/attachment-marker-split";
|
|
5
7
|
import { useChat } from "@/hooks/use-chat";
|
|
6
8
|
import { useUsage } from "@/hooks/use-usage";
|
|
7
9
|
import { useTabStore } from "@/stores/tab-store";
|
|
@@ -33,6 +35,21 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
33
35
|
const [sessionId, setSessionId] = useState<string | null>(
|
|
34
36
|
(metadata?.sessionId as string) ?? null,
|
|
35
37
|
);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Follow the session id when the provider adopts its own.
|
|
41
|
+
*
|
|
42
|
+
* PPM creates a session under a uuid it mints, then codex (or the Claude SDK)
|
|
43
|
+
* reports the real id and the server re-keys to it. Everything written from
|
|
44
|
+
* that point — transcript, title, account binding — lands under the new id, so
|
|
45
|
+
* a tab left holding the original would reopen into an empty conversation even
|
|
46
|
+
* though the history is on disk. Setting it here also persists it to the tab's
|
|
47
|
+
* metadata through the effect below, which is what makes the fix survive a
|
|
48
|
+
* reload rather than only lasting the turn.
|
|
49
|
+
*/
|
|
50
|
+
const handleSessionMigrated = useCallback((newSessionId: string) => {
|
|
51
|
+
setSessionId(newSessionId);
|
|
52
|
+
}, []);
|
|
36
53
|
const [providerId, setProviderId] = useState<string>(
|
|
37
54
|
(metadata?.providerId as string) ?? "claude",
|
|
38
55
|
);
|
|
@@ -56,7 +73,7 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
56
73
|
);
|
|
57
74
|
|
|
58
75
|
// Pending message to send after WS connects (replaces unreliable setTimeout)
|
|
59
|
-
const pendingSendRef = useRef<{ content: string; permissionMode?: string } | null>(null);
|
|
76
|
+
const pendingSendRef = useRef<{ content: string; permissionMode?: string; images?: Array<{ data: string; mediaType: string }>; imagePaths?: string[] } | null>(null);
|
|
60
77
|
|
|
61
78
|
// Drag-and-drop state
|
|
62
79
|
const [isDragging, setIsDragging] = useState(false);
|
|
@@ -131,7 +148,7 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
131
148
|
bashPartialOutput,
|
|
132
149
|
backgroundShells,
|
|
133
150
|
killBackgroundShell,
|
|
134
|
-
} = useChat(sessionId, providerId, projectName);
|
|
151
|
+
} = useChat(sessionId, providerId, projectName, handleSessionMigrated);
|
|
135
152
|
|
|
136
153
|
// Teammates keep working long after their spawn card scrolled away — a resume
|
|
137
154
|
// arrives by SendMessage and writes no card at all. Poll the roster whenever this
|
|
@@ -142,9 +159,9 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
142
159
|
// Flush pending message once WS connects (replaces unreliable setTimeout)
|
|
143
160
|
useEffect(() => {
|
|
144
161
|
if (isConnected && pendingSendRef.current) {
|
|
145
|
-
const { content, permissionMode: pm } = pendingSendRef.current;
|
|
162
|
+
const { content, permissionMode: pm, images: pendingImages, imagePaths: pendingPaths } = pendingSendRef.current;
|
|
146
163
|
pendingSendRef.current = null;
|
|
147
|
-
sendMessage(content, { permissionMode: pm });
|
|
164
|
+
sendMessage(content, { permissionMode: pm, ...(pendingImages?.length && { images: pendingImages }), ...(pendingPaths?.length && { imagePaths: pendingPaths }) });
|
|
148
165
|
}
|
|
149
166
|
}, [isConnected, sendMessage]);
|
|
150
167
|
|
|
@@ -350,7 +367,11 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
350
367
|
|
|
351
368
|
/** Build message content with file references and inline text snippets prepended */
|
|
352
369
|
const buildMessageWithAttachments = useCallback(
|
|
353
|
-
(
|
|
370
|
+
(
|
|
371
|
+
content: string,
|
|
372
|
+
attachments: ChatAttachment[],
|
|
373
|
+
inlineImages: Array<{ data: string; mediaType: string }> = [],
|
|
374
|
+
): string => {
|
|
354
375
|
if (attachments.length === 0) return content;
|
|
355
376
|
|
|
356
377
|
const parts: string[] = [];
|
|
@@ -360,12 +381,27 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
360
381
|
if (att.textContent) parts.push(att.textContent);
|
|
361
382
|
}
|
|
362
383
|
|
|
363
|
-
// Server-uploaded file references
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
384
|
+
// Server-uploaded file references. An image keeps its path even when the payload rides
|
|
385
|
+
// along with the message, because the transcript is what the chat re-renders from and
|
|
386
|
+
// the path is the only thing in it a thumbnail can be drawn from.
|
|
387
|
+
//
|
|
388
|
+
// An image sent inline says so in the marker. A bare path in a user message reads as an
|
|
389
|
+
// invitation to open it, and a model that takes it pays for the same picture twice —
|
|
390
|
+
// once inline, once as a tool result, both replayed on every later turn.
|
|
391
|
+
//
|
|
392
|
+
// Which marker an image gets follows the payloads that are actually going out, not
|
|
393
|
+
// `imageData` alone: the per-message caps can leave one behind, and announcing that its
|
|
394
|
+
// contents are included would hand the model neither the picture nor a reason to open
|
|
395
|
+
// the file. `inlineImages` defaults to none, so a caller that sends no payloads at all
|
|
396
|
+
// (the edit-fork path takes only text) gets the plain markers throughout.
|
|
397
|
+
const { inlineImagePaths, pathOnlyPaths } = splitAttachmentMarkers(attachments, inlineImages);
|
|
398
|
+
for (const path of inlineImagePaths) {
|
|
399
|
+
parts.push(`[Attached image (contents included in this message): ${path}]`);
|
|
400
|
+
}
|
|
401
|
+
if (pathOnlyPaths.length > 0) {
|
|
402
|
+
const fileRefs = pathOnlyPaths.join("\n");
|
|
367
403
|
parts.push(
|
|
368
|
-
|
|
404
|
+
pathOnlyPaths.length === 1
|
|
369
405
|
? `[Attached file: ${fileRefs}]`
|
|
370
406
|
: `[Attached files:\n${fileRefs}\n]`,
|
|
371
407
|
);
|
|
@@ -379,8 +415,11 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
379
415
|
|
|
380
416
|
const handleSend = useCallback(
|
|
381
417
|
async (content: string, attachments: ChatAttachment[] = [], priority?: MessagePriority) => {
|
|
382
|
-
const
|
|
383
|
-
|
|
418
|
+
const images = selectInlineImages(attachments);
|
|
419
|
+
const fullContent = buildMessageWithAttachments(content, attachments, images);
|
|
420
|
+
// Providers that take a file rather than a payload (codex) read these instead.
|
|
421
|
+
const imagePaths = attachments.filter((a) => a.isImage && a.serverPath).map((a) => a.serverPath!);
|
|
422
|
+
if (!fullContent.trim() && images.length === 0) return;
|
|
384
423
|
|
|
385
424
|
if (!sessionId) {
|
|
386
425
|
try {
|
|
@@ -394,14 +433,14 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
394
433
|
setSessionId(session.id);
|
|
395
434
|
setProviderId(session.providerId);
|
|
396
435
|
// Queue message — will be sent by effect when WS reports isConnected
|
|
397
|
-
pendingSendRef.current = { content: fullContent, permissionMode };
|
|
436
|
+
pendingSendRef.current = { content: fullContent, permissionMode, images, imagePaths };
|
|
398
437
|
return;
|
|
399
438
|
} catch (e) {
|
|
400
439
|
console.error("Failed to create session:", e);
|
|
401
440
|
return;
|
|
402
441
|
}
|
|
403
442
|
}
|
|
404
|
-
sendMessage(fullContent, { permissionMode, priority });
|
|
443
|
+
sendMessage(fullContent, { permissionMode, priority, ...(images.length > 0 && { images }), ...(imagePaths.length > 0 && { imagePaths }) });
|
|
405
444
|
},
|
|
406
445
|
[sessionId, providerId, projectName, sendMessage, buildMessageWithAttachments, permissionMode, metadata],
|
|
407
446
|
);
|
|
@@ -730,6 +769,7 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
730
769
|
permissionMode={permissionMode}
|
|
731
770
|
onModeChange={setPermissionMode}
|
|
732
771
|
providerId={providerId}
|
|
772
|
+
sessionId={sessionId ?? undefined}
|
|
733
773
|
onProviderChange={!sessionId ? setProviderId : undefined}
|
|
734
774
|
model={model}
|
|
735
775
|
onModelChange={setModel}
|
|
@@ -2,6 +2,8 @@ import { useState, useRef, useCallback, useEffect, memo, type KeyboardEvent, typ
|
|
|
2
2
|
import { ArrowUp, Square, Paperclip, Loader2, Mic, MicOff, Zap, ListOrdered, Clock, Bot, X } from "lucide-react";
|
|
3
3
|
import { useVoiceInput } from "@/hooks/use-voice-input";
|
|
4
4
|
import { api, projectUrl, getAuthToken } from "@/lib/api-client";
|
|
5
|
+
import { downscaleImage } from "@/lib/image-resize";
|
|
6
|
+
import { INLINE_IMAGE_LIMITS } from "@/lib/image-resize-limits";
|
|
5
7
|
import { randomId } from "@/lib/utils";
|
|
6
8
|
import { ownsGlobalShortcut } from "@/lib/owns-global-shortcut";
|
|
7
9
|
import { SEND_TO_CHAT_EVENT, SEND_TO_CHAT_ACK_EVENT, type SendToChatDetail } from "@/lib/send-to-chat";
|
|
@@ -17,6 +19,29 @@ import { fetchSlashItems, clearSlashItemsCache } from "@/lib/slash-items-cache";
|
|
|
17
19
|
import type { FileNode } from "../../../types/project";
|
|
18
20
|
import { useFileStore } from "@/stores/file-store";
|
|
19
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Base64 payload for an image file, or undefined when it cannot be read.
|
|
24
|
+
*
|
|
25
|
+
* Reads through FileReader rather than assembling the string by hand: a phone photo is
|
|
26
|
+
* millions of characters, and building it in chunks on the main thread freezes the composer
|
|
27
|
+
* for as long as it takes.
|
|
28
|
+
*/
|
|
29
|
+
async function readImageData(file: File): Promise<{ data: string; mediaType: string } | undefined> {
|
|
30
|
+
try {
|
|
31
|
+
const dataUrl = await new Promise<string>((resolve, reject) => {
|
|
32
|
+
const reader = new FileReader();
|
|
33
|
+
reader.onload = () => resolve(String(reader.result ?? ""));
|
|
34
|
+
reader.onerror = () => reject(reader.error);
|
|
35
|
+
reader.readAsDataURL(file);
|
|
36
|
+
});
|
|
37
|
+
const comma = dataUrl.indexOf(",");
|
|
38
|
+
const data = comma >= 0 ? dataUrl.slice(comma + 1) : "";
|
|
39
|
+
return data ? { data, mediaType: file.type || "image/png" } : undefined;
|
|
40
|
+
} catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
20
45
|
export interface ChatAttachment {
|
|
21
46
|
id: string;
|
|
22
47
|
name: string;
|
|
@@ -27,6 +52,16 @@ export interface ChatAttachment {
|
|
|
27
52
|
serverPath?: string;
|
|
28
53
|
/** Inline text content (e.g. terminal output) — no upload needed */
|
|
29
54
|
textContent?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Base64 payload for an image, sent as part of the message itself.
|
|
57
|
+
*
|
|
58
|
+
* Passing the path instead would make the model spend a whole extra round trip calling Read
|
|
59
|
+
* to fetch it, and every round trip re-sends the entire transcript. The uploaded copy is
|
|
60
|
+
* still kept, so removing the payload from a transcript later stays recoverable.
|
|
61
|
+
*/
|
|
62
|
+
imageData?: { data: string; mediaType: string };
|
|
63
|
+
/** Dimensions before and after downscaling, when one happened — surfaced in the chip. */
|
|
64
|
+
resized?: { from: { width: number; height: number }; to: { width: number; height: number } };
|
|
30
65
|
status: "uploading" | "ready" | "error";
|
|
31
66
|
}
|
|
32
67
|
|
|
@@ -72,6 +107,9 @@ interface MessageInputProps {
|
|
|
72
107
|
onModeChange?: (mode: string) => void;
|
|
73
108
|
/** Current provider ID */
|
|
74
109
|
providerId?: string;
|
|
110
|
+
/** Live session id, when the tab has one. Scopes the slash list to the session's
|
|
111
|
+
* own skill runtime (codex resolves skills per account home + project cwd). */
|
|
112
|
+
sessionId?: string;
|
|
75
113
|
/** Provider change handler — undefined when session is active (locked) */
|
|
76
114
|
onProviderChange?: (providerId: string) => void;
|
|
77
115
|
/** Current per-session model (null = provider default) */
|
|
@@ -112,6 +150,7 @@ export const MessageInput = memo(function MessageInput({
|
|
|
112
150
|
permissionMode,
|
|
113
151
|
onModeChange,
|
|
114
152
|
providerId,
|
|
153
|
+
sessionId,
|
|
115
154
|
onProviderChange,
|
|
116
155
|
model,
|
|
117
156
|
onModelChange,
|
|
@@ -293,7 +332,7 @@ export const MessageInput = memo(function MessageInput({
|
|
|
293
332
|
onSlashItemsLoaded?.([], []);
|
|
294
333
|
return;
|
|
295
334
|
}
|
|
296
|
-
fetchSlashItems(projectName)
|
|
335
|
+
fetchSlashItems(projectName, providerId, sessionId)
|
|
297
336
|
.then((data) => {
|
|
298
337
|
slashItemsRef.current = data.items;
|
|
299
338
|
onSlashItemsLoaded?.(data.items, data.recentNames);
|
|
@@ -302,7 +341,7 @@ export const MessageInput = memo(function MessageInput({
|
|
|
302
341
|
slashItemsRef.current = [];
|
|
303
342
|
onSlashItemsLoaded?.([], []);
|
|
304
343
|
});
|
|
305
|
-
}, [projectName, onSlashItemsLoaded]);
|
|
344
|
+
}, [projectName, providerId, sessionId, onSlashItemsLoaded]);
|
|
306
345
|
|
|
307
346
|
// Load when projectName changes (cache hit after the first tab in a project)
|
|
308
347
|
useEffect(() => { loadSlashItems(); }, [loadSlashItems]);
|
|
@@ -369,10 +408,13 @@ export const MessageInput = memo(function MessageInput({
|
|
|
369
408
|
return;
|
|
370
409
|
}
|
|
371
410
|
|
|
372
|
-
// Find the /query pattern before cursor and replace it with the command name
|
|
411
|
+
// Find the /query pattern before cursor and replace it with the command name.
|
|
412
|
+
// The item's own sigil is used, not a hardcoded `/`: a codex skill is invoked
|
|
413
|
+
// as `$imagegen`, so the composer must show the text that will actually be
|
|
414
|
+
// sent rather than leaving the server to silently rewrite it.
|
|
373
415
|
const replaced = textBefore.replace(/(?:^|\s)\/\S*$/, (match) => {
|
|
374
416
|
const prefix = stripTrigger(match);
|
|
375
|
-
return `${prefix}
|
|
417
|
+
return `${prefix}${slashSelected.invokeSigil ?? "/"}${slashSelected.name} `;
|
|
376
418
|
});
|
|
377
419
|
writeTextareas(replaced + textAfter);
|
|
378
420
|
onSlashStateChange?.(false, "");
|
|
@@ -436,6 +478,27 @@ export const MessageInput = memo(function MessageInput({
|
|
|
436
478
|
onExternalPathsConsumed?.();
|
|
437
479
|
}, [externalPaths]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
438
480
|
|
|
481
|
+
/** Delete an upload the user removed before sending. Best effort — nothing depends on it. */
|
|
482
|
+
const discardUpload = useCallback(
|
|
483
|
+
async (serverPath: string) => {
|
|
484
|
+
if (!projectName) return;
|
|
485
|
+
const filename = serverPath.split(/[\\/]/).pop();
|
|
486
|
+
if (!filename) return;
|
|
487
|
+
try {
|
|
488
|
+
const headers: HeadersInit = {};
|
|
489
|
+
const token = getAuthToken();
|
|
490
|
+
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
491
|
+
await fetch(`${projectUrl(projectName)}/chat/uploads/${encodeURIComponent(filename)}`, {
|
|
492
|
+
method: "DELETE",
|
|
493
|
+
headers,
|
|
494
|
+
});
|
|
495
|
+
} catch {
|
|
496
|
+
// An orphaned file is not worth surfacing to the user.
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
[projectName],
|
|
500
|
+
);
|
|
501
|
+
|
|
439
502
|
/** Upload a single file to the server, return server path */
|
|
440
503
|
const uploadFile = useCallback(
|
|
441
504
|
async (file: File): Promise<string | null> => {
|
|
@@ -466,32 +529,64 @@ export const MessageInput = memo(function MessageInput({
|
|
|
466
529
|
/** Process files — always uploads to server. Path resolution only happens via @ picker. */
|
|
467
530
|
const processFiles = useCallback(
|
|
468
531
|
async (files: File[]) => {
|
|
469
|
-
for (const
|
|
532
|
+
for (const original of files) {
|
|
470
533
|
const id = randomId();
|
|
471
|
-
const isImg = isImageFile(
|
|
472
|
-
const previewUrl = isImg ? URL.createObjectURL(file) : undefined;
|
|
534
|
+
const isImg = isImageFile(original);
|
|
473
535
|
|
|
474
536
|
const att: ChatAttachment = {
|
|
475
537
|
id,
|
|
476
|
-
name:
|
|
477
|
-
file,
|
|
538
|
+
name: original.name,
|
|
539
|
+
file: original,
|
|
478
540
|
isImage: isImg,
|
|
479
|
-
previewUrl,
|
|
541
|
+
previewUrl: isImg ? URL.createObjectURL(original) : undefined,
|
|
480
542
|
status: "uploading",
|
|
481
543
|
};
|
|
482
544
|
|
|
483
545
|
setAttachments((prev) => [...prev, att]);
|
|
484
546
|
|
|
485
|
-
//
|
|
486
|
-
|
|
547
|
+
// Shrink first, so the upload, the preview and the message all carry the same
|
|
548
|
+
// already-reduced image — an oversized original must not reach the transcript.
|
|
549
|
+
//
|
|
550
|
+
// Only a `scaled` or `inlineable` result is attached inline. An image that could not
|
|
551
|
+
// be measured or re-encoded travels by path alone: sending unverified dimensions
|
|
552
|
+
// inline risks a payload the API refuses, and that refusal outlives the turn, since
|
|
553
|
+
// the transcript replays it into every later one.
|
|
554
|
+
try {
|
|
555
|
+
const outcome = isImg ? await downscaleImage(original) : null;
|
|
556
|
+
const file = outcome?.file ?? original;
|
|
557
|
+
// Point the thumbnail at the reduced file and let the original go. It is the larger
|
|
558
|
+
// of the two and nothing needs it once the resize is done, but it stayed alive until
|
|
559
|
+
// the message was sent because the preview still referenced it.
|
|
560
|
+
const previewUrl = isImg && file !== original ? URL.createObjectURL(file) : undefined;
|
|
561
|
+
const serverPath = await uploadFile(file);
|
|
562
|
+
const inlineable = outcome ? outcome.kind !== "asis" : false;
|
|
563
|
+
const imageData = inlineable ? await readImageData(file) : undefined;
|
|
564
|
+
const withinPayloadCap =
|
|
565
|
+
!!imageData && imageData.data.length <= INLINE_IMAGE_LIMITS.maxBase64PerImage;
|
|
566
|
+
|
|
567
|
+
if (previewUrl && att.previewUrl) URL.revokeObjectURL(att.previewUrl);
|
|
487
568
|
setAttachments((prev) =>
|
|
488
569
|
prev.map((a) =>
|
|
489
570
|
a.id === id
|
|
490
|
-
? {
|
|
571
|
+
? {
|
|
572
|
+
...a,
|
|
573
|
+
file,
|
|
574
|
+
...(previewUrl && { previewUrl }),
|
|
575
|
+
serverPath: serverPath ?? undefined,
|
|
576
|
+
imageData: withinPayloadCap ? imageData : undefined,
|
|
577
|
+
resized: outcome?.to ? { from: outcome.from!, to: outcome.to } : undefined,
|
|
578
|
+
// An image can still be sent inline when the upload failed; anything
|
|
579
|
+
// else has nothing left to send without its path.
|
|
580
|
+
status: serverPath || withinPayloadCap ? "ready" : "error",
|
|
581
|
+
}
|
|
491
582
|
: a,
|
|
492
583
|
),
|
|
493
584
|
);
|
|
494
|
-
}
|
|
585
|
+
} catch {
|
|
586
|
+
// Nothing here may leave an attachment stuck on "uploading" — both the send button
|
|
587
|
+
// and the auto-send effect wait on that state, so a swallowed throw hangs the composer.
|
|
588
|
+
setAttachments((prev) => prev.map((a) => (a.id === id ? { ...a, status: "error" } : a)));
|
|
589
|
+
}
|
|
495
590
|
}
|
|
496
591
|
(mobileTextareaRef.current ?? textareaRef.current)?.focus();
|
|
497
592
|
},
|
|
@@ -502,9 +597,12 @@ export const MessageInput = memo(function MessageInput({
|
|
|
502
597
|
setAttachments((prev) => {
|
|
503
598
|
const att = prev.find((a) => a.id === id);
|
|
504
599
|
if (att?.previewUrl) URL.revokeObjectURL(att.previewUrl);
|
|
600
|
+
// Uploads are never swept, because chat history points at them indefinitely, so one
|
|
601
|
+
// abandoned before it was ever sent would sit there with nothing referencing it.
|
|
602
|
+
if (att?.serverPath) void discardUpload(att.serverPath);
|
|
505
603
|
return prev.filter((a) => a.id !== id);
|
|
506
604
|
});
|
|
507
|
-
}, []);
|
|
605
|
+
}, [discardUpload]);
|
|
508
606
|
|
|
509
607
|
/** Execute the actual send (called directly or after uploads complete) */
|
|
510
608
|
const executeSend = useCallback(() => {
|
|
@@ -1115,6 +1115,20 @@ function InterleavedEvents({ events, isStreaming, projectName, bashPartialOutput
|
|
|
1115
1115
|
if (event.type === "text") {
|
|
1116
1116
|
textBuffer += event.content;
|
|
1117
1117
|
} else if (event.type === "tool_use") {
|
|
1118
|
+
// A call may be announced before it has anything to show and re-announced
|
|
1119
|
+
// once it does — image generation starts with no file and no prompt, and
|
|
1120
|
+
// only learns both when it finishes. The later event describes the same
|
|
1121
|
+
// call, so it replaces the card rather than adding a second one.
|
|
1122
|
+
const useId = (event as any).toolUseId;
|
|
1123
|
+
const existing = useId
|
|
1124
|
+
? groups.find(
|
|
1125
|
+
(g) => g.kind === "tool" && g.tool.type === "tool_use" && (g.tool as any).toolUseId === useId,
|
|
1126
|
+
) as (EventGroup & { kind: "tool" }) | undefined
|
|
1127
|
+
: undefined;
|
|
1128
|
+
if (existing) {
|
|
1129
|
+
existing.tool = event;
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1118
1132
|
if (textBuffer) {
|
|
1119
1133
|
groups.push({ kind: "text", content: textBuffer });
|
|
1120
1134
|
textBuffer = "";
|
|
@@ -147,7 +147,8 @@ function TranscriptImages({ sessionId, projectName }: { sessionId: string; proje
|
|
|
147
147
|
{audit.oversizedAttachments} of those {audit.oversizedAttachments === 1 ? "is an image you" : "are images you"}
|
|
148
148
|
{" "}attached yourself, so the buttons below leave {audit.oversizedAttachments === 1 ? "it" : "them"} in place.
|
|
149
149
|
While {audit.oversizedAttachments === 1 ? "it stays" : "they stay"}, every turn in this session keeps failing.
|
|
150
|
-
|
|
150
|
+
Removing {audit.oversizedAttachments === 1 ? "it" : "them"} cannot be undone: an attachment PPM sent keeps
|
|
151
|
+
a copy on disk with its path still in the message, but one from another client does not.
|
|
151
152
|
</span>
|
|
152
153
|
</div>
|
|
153
154
|
<Button
|
|
@@ -15,6 +15,12 @@ export interface SlashItem {
|
|
|
15
15
|
model?: string;
|
|
16
16
|
/** Built-in only: which layer executes the command */
|
|
17
17
|
handler?: "ppm" | "sdk" | "client";
|
|
18
|
+
/** Sigil the runtime needs; absent means `/`. Codex skills carry `$`. */
|
|
19
|
+
invokeSigil?: "/" | "$";
|
|
20
|
+
/** Pretty label the runtime supplies for itself (codex system skills). */
|
|
21
|
+
displayName?: string;
|
|
22
|
+
/** Runtime-supplied icon, inlined as a data URI by the server. */
|
|
23
|
+
iconDataUri?: string;
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
interface SlashCommandPickerProps {
|
|
@@ -181,7 +187,11 @@ export function SlashCommandPicker({
|
|
|
181
187
|
onClick={() => onSelect(item)}
|
|
182
188
|
>
|
|
183
189
|
<span className="shrink-0 mt-0.5">
|
|
184
|
-
{item.
|
|
190
|
+
{item.iconDataUri ? (
|
|
191
|
+
// The runtime shipped its own artwork (codex system skills).
|
|
192
|
+
// Decorative: the name beside it already labels the row.
|
|
193
|
+
<img src={item.iconDataUri} alt="" className="size-4 object-contain" />
|
|
194
|
+
) : item.type === "builtin" ? (
|
|
185
195
|
<Zap className="size-4 text-emerald-500" />
|
|
186
196
|
) : item.type === "skill" ? (
|
|
187
197
|
<Sparkles className="size-4 text-warning" />
|
|
@@ -193,12 +203,21 @@ export function SlashCommandPicker({
|
|
|
193
203
|
</span>
|
|
194
204
|
<div className="min-w-0 flex-1">
|
|
195
205
|
<div className="flex items-baseline gap-2 min-w-0">
|
|
196
|
-
|
|
206
|
+
{/* Invocation string, shown with the sigil that will actually be
|
|
207
|
+
sent — codex resolves its skills from `$name`, not `/name`. */}
|
|
208
|
+
<span className="font-medium text-sm truncate">
|
|
209
|
+
{item.invokeSigil ?? "/"}{item.name}
|
|
210
|
+
</span>
|
|
211
|
+
{item.displayName && item.displayName !== item.name && (
|
|
212
|
+
<span className="text-xs text-text-2 truncate">{item.displayName}</span>
|
|
213
|
+
)}
|
|
197
214
|
{item.argumentHint && (
|
|
198
215
|
<span className="text-xs text-text-subtle truncate">{item.argumentHint}</span>
|
|
199
216
|
)}
|
|
200
217
|
<span className="text-xs text-text-subtle capitalize ml-auto shrink-0 whitespace-nowrap">
|
|
201
|
-
{item.
|
|
218
|
+
{item.invokeSigil === "$"
|
|
219
|
+
? "Codex"
|
|
220
|
+
: item.scope === "bundled" ? "PPM" : item.scope === "user" ? "global" : item.type}
|
|
202
221
|
</span>
|
|
203
222
|
</div>
|
|
204
223
|
{item.description && (
|