@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
|
@@ -27,6 +27,35 @@ function asObj(v: unknown): Record<string, unknown> {
|
|
|
27
27
|
return (v && typeof v === "object") ? (v as Record<string, unknown>) : {};
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* The command text to SHOW for a commandExecution item.
|
|
32
|
+
*
|
|
33
|
+
* A commandExecution carries the same command twice. `command` is what codex
|
|
34
|
+
* hands its exec layer: the interpreter wrapped around the script, with every
|
|
35
|
+
* backslash in the interpreter path doubled (`C:\\Windows\\System32\\…`), so
|
|
36
|
+
* rendering it puts `\\` in front of the user. `commandActions[].command` is
|
|
37
|
+
* the unwrapped script — single backslashes, no interpreter prefix — which is
|
|
38
|
+
* the part a reader actually cares about.
|
|
39
|
+
*
|
|
40
|
+
* Un-escaping `command` instead would be wrong: a legitimate bash script can
|
|
41
|
+
* contain a real `\\` (regex, escaped path), and rewriting that corrupts the
|
|
42
|
+
* command the user is being shown.
|
|
43
|
+
*
|
|
44
|
+
* Multiple actions are joined by newline; an item with none (or with blank
|
|
45
|
+
* ones) falls back to the wrapped form, because showing the doubled path still
|
|
46
|
+
* beats showing an empty card.
|
|
47
|
+
*/
|
|
48
|
+
export function commandDisplayText(item: Item): string {
|
|
49
|
+
const raw = String(item.command ?? "");
|
|
50
|
+
const actions = Array.isArray(item.commandActions) ? item.commandActions : [];
|
|
51
|
+
const parts: string[] = [];
|
|
52
|
+
for (const a of actions) {
|
|
53
|
+
const cmd = asObj(a).command;
|
|
54
|
+
if (typeof cmd === "string" && cmd.trim()) parts.push(cmd);
|
|
55
|
+
}
|
|
56
|
+
return parts.length > 0 ? parts.join("\n") : raw;
|
|
57
|
+
}
|
|
58
|
+
|
|
30
59
|
/** Build the tool_use input payload from a ThreadItem (per-variant fields). */
|
|
31
60
|
export function itemToToolUse(item: Item): ChatEvent {
|
|
32
61
|
const type = item.type ?? "tool";
|
|
@@ -35,10 +64,11 @@ export function itemToToolUse(item: Item): ChatEvent {
|
|
|
35
64
|
switch (type) {
|
|
36
65
|
case "commandExecution": {
|
|
37
66
|
// Map to PPM's canonical shell tools so the chat UI renders the command
|
|
38
|
-
// (not a raw `commandExecution` JSON blob). Sniff PowerShell vs Bash
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
67
|
+
// (not a raw `commandExecution` JSON blob). Sniff PowerShell vs Bash from
|
|
68
|
+
// the WRAPPED form — the interpreter only appears there, never in the
|
|
69
|
+
// unwrapped script that gets displayed.
|
|
70
|
+
tool = /powershell|pwsh/i.test(String(item.command ?? "")) ? "PowerShell" : "Bash";
|
|
71
|
+
input = { command: commandDisplayText(item), cwd: item.cwd };
|
|
42
72
|
break;
|
|
43
73
|
}
|
|
44
74
|
case "fileChange": {
|
|
@@ -65,6 +95,24 @@ export function itemToToolUse(item: Item): ChatEvent {
|
|
|
65
95
|
tool = "WebSearch";
|
|
66
96
|
input = { query: item.query };
|
|
67
97
|
break;
|
|
98
|
+
case "imageGeneration":
|
|
99
|
+
// The item carries the finished PNG twice: `result` is the whole file as
|
|
100
|
+
// base64 (~1.2 MB for a 917 KB image) and `savedPath` points at the copy
|
|
101
|
+
// codex already wrote to disk. Only the path is kept. `result` must never
|
|
102
|
+
// reach a ChatEvent — the event is held in the in-RAM turnEvents buffer,
|
|
103
|
+
// appended to the session JSONL, and broadcast to every connected client,
|
|
104
|
+
// so carrying the payload would cost all three that megabyte per image
|
|
105
|
+
// to display a picture that is already readable from `savedPath`.
|
|
106
|
+
//
|
|
107
|
+
// `file_path` (not `savedPath`) is deliberate: it is the key the chat's
|
|
108
|
+
// image-preview path check already reads, so the thumbnail comes for free.
|
|
109
|
+
tool = "ImageGen";
|
|
110
|
+
input = {
|
|
111
|
+
file_path: item.savedPath ?? null,
|
|
112
|
+
prompt: item.revisedPrompt ?? null,
|
|
113
|
+
transparentBackground: item.transparentBackground ?? false,
|
|
114
|
+
};
|
|
115
|
+
break;
|
|
68
116
|
default:
|
|
69
117
|
input = item;
|
|
70
118
|
}
|
|
@@ -92,6 +140,13 @@ export function itemToToolResult(item: Item): ChatEvent {
|
|
|
92
140
|
} else if (type === "dynamicToolCall") {
|
|
93
141
|
output = redactTruncate(item.contentItems ?? "");
|
|
94
142
|
isError = item.success === false;
|
|
143
|
+
} else if (type === "imageGeneration") {
|
|
144
|
+
// Same reason as the tool_use side: never let the base64 `result` through.
|
|
145
|
+
// Falling to the generic branch below would emit 8 KB of truncated base64
|
|
146
|
+
// as the visible result text.
|
|
147
|
+
const failure = item.failure;
|
|
148
|
+
isError = failure != null;
|
|
149
|
+
output = isError ? redactTruncate(failure) : String(item.savedPath ?? "generated");
|
|
95
150
|
} else {
|
|
96
151
|
output = redactTruncate(item);
|
|
97
152
|
}
|
|
@@ -127,7 +182,17 @@ export function mapCodexEvent(notif: Notif, sessionId: string): ChatEvent[] {
|
|
|
127
182
|
case "item/completed": {
|
|
128
183
|
const item = asObj(p.item) as Item;
|
|
129
184
|
if (item.type === "contextCompaction") return [{ type: "system", subtype: "compact_done" }];
|
|
130
|
-
if (item.type && !NON_TOOL_ITEM_TYPES.has(item.type))
|
|
185
|
+
if (item.type && !NON_TOOL_ITEM_TYPES.has(item.type)) {
|
|
186
|
+
// Image generation is announced before the picture exists: at `started`
|
|
187
|
+
// there is no saved file and no revised prompt, so the call it produced
|
|
188
|
+
// can show neither. The finished item carries both, so re-emit the call
|
|
189
|
+
// alongside its result — the chat replaces the card by tool-use id.
|
|
190
|
+
// Other tools describe themselves fully at `started`; re-sending those
|
|
191
|
+
// would only cost a second event in the buffer, the log and every
|
|
192
|
+
// client's socket.
|
|
193
|
+
if (item.type === "imageGeneration") return [itemToToolUse(item), itemToToolResult(item)];
|
|
194
|
+
return [itemToToolResult(item)];
|
|
195
|
+
}
|
|
131
196
|
return [];
|
|
132
197
|
}
|
|
133
198
|
|
|
@@ -4,6 +4,7 @@ import { join, resolve } from "node:path";
|
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { redactTruncate } from "./codex-redact.ts";
|
|
6
6
|
import { parseApplyPatch, changeToToolUse } from "./codex-patch.ts";
|
|
7
|
+
import { mapRolloutItem } from "./codex-rollout-items.ts";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Independent parser for Codex rollout JSONL transcripts
|
|
@@ -110,6 +111,15 @@ export function parseRolloutJsonl(text: string, opts?: { preCompact?: boolean })
|
|
|
110
111
|
let i = 0;
|
|
111
112
|
let pendingEvents: ChatEvent[] = [];
|
|
112
113
|
|
|
114
|
+
// Newer codex records every finished step as an `item_completed` event AND
|
|
115
|
+
// keeps the raw model exchange in `response_item` records. Both describe the
|
|
116
|
+
// same tool calls, so taking both renders every command twice — and the
|
|
117
|
+
// response_item copy of an image generation carries the whole PNG as base64,
|
|
118
|
+
// which would land in the transcript. When the item events are present they
|
|
119
|
+
// are the better source: already assembled, already named the way the live
|
|
120
|
+
// stream names them.
|
|
121
|
+
const hasItemEvents = text.includes('"item_completed"');
|
|
122
|
+
|
|
113
123
|
const flushAssistant = (content: string, ts: string) => {
|
|
114
124
|
if (!content && pendingEvents.length === 0) return;
|
|
115
125
|
const events = pendingEvents.length
|
|
@@ -131,6 +141,19 @@ export function parseRolloutJsonl(text: string, opts?: { preCompact?: boolean })
|
|
|
131
141
|
messages.push({ id: `rollout-${i++}`, role: "user", content: p.message, timestamp: ts });
|
|
132
142
|
} else if (p.type === "agent_message" && typeof p.message === "string") {
|
|
133
143
|
flushAssistant(p.message, ts);
|
|
144
|
+
} else if (p.type === "item_completed") {
|
|
145
|
+
// Newer codex writes one item per finished step instead of the
|
|
146
|
+
// user_message/agent_message pair above. Same conversation, different
|
|
147
|
+
// spelling — see codex-rollout-items.
|
|
148
|
+
const mapped = mapRolloutItem(p.item);
|
|
149
|
+
if (mapped.kind === "user") {
|
|
150
|
+
if (pendingEvents.length) flushAssistant("", ts);
|
|
151
|
+
messages.push({ id: `rollout-${i++}`, role: "user", content: mapped.text, timestamp: ts });
|
|
152
|
+
} else if (mapped.kind === "assistant") {
|
|
153
|
+
flushAssistant(mapped.text, ts);
|
|
154
|
+
} else if (mapped.kind === "events") {
|
|
155
|
+
pendingEvents.push(...mapped.events);
|
|
156
|
+
}
|
|
134
157
|
} else if (p.type === "thread_rolled_back") {
|
|
135
158
|
// codex doesn't truncate the rollout file on rollback/fork — it appends this
|
|
136
159
|
// marker. Drop the last `num_turns` turns (by user-message turn-start) so a
|
|
@@ -144,6 +167,7 @@ export function parseRolloutJsonl(text: string, opts?: { preCompact?: boolean })
|
|
|
144
167
|
}
|
|
145
168
|
}
|
|
146
169
|
} else if (rec.type === "response_item") {
|
|
170
|
+
if (hasItemEvents) continue; // item_completed already carried these
|
|
147
171
|
if (p.type === "function_call") pendingEvents.push(fnCallToToolUse(p));
|
|
148
172
|
else if (p.type === "function_call_output") pendingEvents.push(fnOutputToToolResult(p));
|
|
149
173
|
// File edits are recorded as custom_tool_call (name=apply_patch) + output.
|
|
@@ -19,6 +19,14 @@ const ENV_ALLOWLIST = [
|
|
|
19
19
|
/** Prefixes kept (codex/XDG own their auth + config). */
|
|
20
20
|
const ENV_PREFIX_ALLOWLIST = ["CODEX_", "XDG_", "RUST_"];
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Bound for short control calls — handshake, model list, skill list, quota read.
|
|
24
|
+
* These answer in about a second when the app-server is healthy; anything past
|
|
25
|
+
* this is a subprocess that will never answer, not a slow one. A turn is NOT a
|
|
26
|
+
* control call and must never be given this bound.
|
|
27
|
+
*/
|
|
28
|
+
export const CONTROL_REQUEST_TIMEOUT_MS = 15_000;
|
|
29
|
+
|
|
22
30
|
function buildSpawnEnv(): NodeJS.ProcessEnv {
|
|
23
31
|
const out: NodeJS.ProcessEnv = {};
|
|
24
32
|
for (const [k, v] of Object.entries(process.env)) {
|
|
@@ -120,12 +128,41 @@ export class CodexJsonRpcClient {
|
|
|
120
128
|
}
|
|
121
129
|
}
|
|
122
130
|
|
|
123
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Send a request and wait for its reply.
|
|
133
|
+
*
|
|
134
|
+
* `timeoutMs` bounds the wait. It is opt-in because a turn legitimately runs
|
|
135
|
+
* for many minutes, but every short control call should pass one: the
|
|
136
|
+
* app-server has been observed to accept a spawn and then never answer even
|
|
137
|
+
* `initialize`. Without a bound, the promise never settles, so the caller's
|
|
138
|
+
* `finally` never runs, the subprocess is never closed, and any HTTP route
|
|
139
|
+
* waiting on it hangs until the client gives up — one orphaned app-server per
|
|
140
|
+
* attempt, and a blank reading at the other end.
|
|
141
|
+
*
|
|
142
|
+
* A timeout rejects and drops the pending entry, so a late reply is ignored
|
|
143
|
+
* rather than resolving a promise the caller already abandoned.
|
|
144
|
+
*/
|
|
145
|
+
request<T = unknown>(method: string, params?: unknown, timeoutMs?: number): Promise<T> {
|
|
124
146
|
if (this.closed) return Promise.reject(new Error("codex client closed"));
|
|
125
147
|
const id = this.nextId++;
|
|
126
148
|
const line = JSON.stringify({ id, method, params }) + "\n";
|
|
127
149
|
return new Promise<T>((resolve, reject) => {
|
|
128
|
-
|
|
150
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
151
|
+
const settle = <A extends unknown[]>(fn: (...args: A) => void) => (...args: A) => {
|
|
152
|
+
if (timer) clearTimeout(timer);
|
|
153
|
+
fn(...args);
|
|
154
|
+
};
|
|
155
|
+
const wrapped = {
|
|
156
|
+
resolve: settle(resolve as (v: unknown) => void),
|
|
157
|
+
reject: settle(reject),
|
|
158
|
+
};
|
|
159
|
+
if (timeoutMs != null) {
|
|
160
|
+
timer = setTimeout(() => {
|
|
161
|
+
this.pending.delete(id);
|
|
162
|
+
reject(new Error(`codex ${method} timed out after ${timeoutMs}ms`));
|
|
163
|
+
}, timeoutMs);
|
|
164
|
+
}
|
|
165
|
+
this.pending.set(id, wrapped);
|
|
129
166
|
this.write(line);
|
|
130
167
|
});
|
|
131
168
|
}
|
|
@@ -90,6 +90,30 @@ export interface ModelListResponse {
|
|
|
90
90
|
nextCursor: string | null;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
// ── Skills ──
|
|
94
|
+
/** Presentation block codex ships for its own system skills. All fields optional. */
|
|
95
|
+
export interface CodexSkillInterface {
|
|
96
|
+
displayName?: string;
|
|
97
|
+
shortDescription?: string;
|
|
98
|
+
/** Absolute path to an icon file inside the skill directory, not a URL. */
|
|
99
|
+
iconSmall?: string;
|
|
100
|
+
iconLarge?: string;
|
|
101
|
+
defaultPrompt?: string;
|
|
102
|
+
}
|
|
103
|
+
export interface CodexSkill {
|
|
104
|
+
name: string;
|
|
105
|
+
description?: string;
|
|
106
|
+
/** "system" for codex's built-ins; project/user scopes for authored ones. */
|
|
107
|
+
scope?: string;
|
|
108
|
+
path?: string;
|
|
109
|
+
enabled?: boolean;
|
|
110
|
+
interface?: CodexSkillInterface;
|
|
111
|
+
}
|
|
112
|
+
/** `skills/list` groups its results by the cwd each set was resolved for. */
|
|
113
|
+
export interface SkillListResponse {
|
|
114
|
+
data: { cwd?: string; skills?: CodexSkill[] }[];
|
|
115
|
+
}
|
|
116
|
+
|
|
93
117
|
// ── Account rate limits / usage ──
|
|
94
118
|
export interface RateLimitWindow {
|
|
95
119
|
usedPercent: number;
|
|
@@ -10,17 +10,19 @@ import type {
|
|
|
10
10
|
UsageInfo,
|
|
11
11
|
} from "../provider.interface.ts";
|
|
12
12
|
import { configService } from "../../services/config.service.ts";
|
|
13
|
-
import { setSessionMetadata, getSessionProjectPath, setSessionProvider, setSessionCodexAccount } from "../../services/db.service.ts";
|
|
14
|
-
import { resolveCodexAccountForSession } from "../../services/codex-account.service.ts";
|
|
13
|
+
import { setSessionMetadata, getSessionProjectPath, setSessionProvider, setSessionCodexAccount, getSessionCodexAccount } from "../../services/db.service.ts";
|
|
14
|
+
import { resolveCodexAccountForSession, getCodexAccount, listCodexAccounts, peekCodexAccount } from "../../services/codex-account.service.ts";
|
|
15
15
|
import { killProcessTree } from "../../services/windows-process-tree.ts";
|
|
16
16
|
import { homedir } from "node:os";
|
|
17
17
|
import { join } from "node:path";
|
|
18
|
-
import { CodexJsonRpcClient } from "./codex-jsonrpc-client.ts";
|
|
18
|
+
import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS } from "./codex-jsonrpc-client.ts";
|
|
19
19
|
import { permissionModeToCodex, type CodexPermission } from "./codex-permission-map.ts";
|
|
20
20
|
import { mapCodexEvent } from "./codex-event-mapper.ts";
|
|
21
21
|
import { decisionFor, isApprovalMethod, type ApprovalMethod } from "./codex-approval-decision.ts";
|
|
22
22
|
import { parseModelList } from "./codex-model-parser.ts";
|
|
23
|
-
import {
|
|
23
|
+
import { getOrFetchUsage, registerUsageSource } from "../../services/provider-usage/usage-registry.ts";
|
|
24
|
+
import { codexUsageSource } from "./codex-usage-source.ts";
|
|
25
|
+
import { AMBIENT_ACCOUNT_KEY } from "../../services/provider-usage/usage-source.ts";
|
|
24
26
|
import { redactTruncate } from "./codex-redact.ts";
|
|
25
27
|
import {
|
|
26
28
|
listCodexRollouts,
|
|
@@ -33,12 +35,51 @@ import type {
|
|
|
33
35
|
JsonRpcNotification,
|
|
34
36
|
ToolRequestUserInputResponse,
|
|
35
37
|
Thread,
|
|
38
|
+
UserInput,
|
|
39
|
+
CodexSkill,
|
|
36
40
|
} from "./codex-protocol.ts";
|
|
41
|
+
import { parseSkillList } from "./codex-skill-parser.ts";
|
|
37
42
|
|
|
38
43
|
const CODEX_SESSIONS_DIR = join(homedir(), ".codex", "sessions");
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Every directory a codex rollout for this install could be in, most specific
|
|
47
|
+
* first.
|
|
48
|
+
*
|
|
49
|
+
* `~/.codex/sessions` is only the ambient login's. PPM gives each managed
|
|
50
|
+
* account its own CODEX_HOME, and the app-server writes that account's
|
|
51
|
+
* transcripts under it — so a session bound to an account has its history
|
|
52
|
+
* nowhere near the default directory. Reading only the default is why such a
|
|
53
|
+
* conversation came back empty once it was no longer live in memory: it was
|
|
54
|
+
* being served from the in-process transcript, and nothing on disk was ever
|
|
55
|
+
* found for it.
|
|
56
|
+
*
|
|
57
|
+
* `sessionId` narrows to the bound account when there is one; without it the
|
|
58
|
+
* caller gets every account, which is what listing a project's sessions needs.
|
|
59
|
+
*/
|
|
60
|
+
function codexSessionsDirs(sessionId?: string): string[] {
|
|
61
|
+
const dirs: string[] = [];
|
|
62
|
+
const boundId = sessionId ? getSessionCodexAccount(sessionId) : null;
|
|
63
|
+
const accounts = boundId
|
|
64
|
+
? [getCodexAccount(boundId)].filter((a): a is NonNullable<typeof a> => a != null)
|
|
65
|
+
: listCodexAccounts();
|
|
66
|
+
for (const account of accounts) dirs.push(join(account.home, "sessions"));
|
|
67
|
+
dirs.push(CODEX_SESSIONS_DIR);
|
|
68
|
+
return dirs;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** First non-empty result across the candidate directories. */
|
|
72
|
+
function fromCodexSessionsDirs<T>(sessionId: string | undefined, read: (dir: string) => T | null): T | null {
|
|
73
|
+
for (const dir of codexSessionsDirs(sessionId)) {
|
|
74
|
+
const found = read(dir);
|
|
75
|
+
if (found != null) return found;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
39
79
|
const CLIENT_INFO = { name: "ppm", title: "PPM", version: "0.0.0" };
|
|
40
80
|
const CAPABILITIES = { experimentalApi: true, requestAttestation: false, optOutNotificationMethods: null };
|
|
41
81
|
const MODELS_CACHE_TTL = 5 * 60 * 1000;
|
|
82
|
+
const SKILLS_CACHE_TTL = 60 * 1000;
|
|
42
83
|
|
|
43
84
|
interface PendingApproval {
|
|
44
85
|
codexId: number | string;
|
|
@@ -164,6 +205,8 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
164
205
|
private sessions = new Map<string, Session>();
|
|
165
206
|
private live = new Map<string, LiveSession>();
|
|
166
207
|
private modelsCache: { models: ModelOption[]; expiry: number } | null = null;
|
|
208
|
+
/** Keyed by `cwd\0codexHome` — skills differ per workspace AND per account. */
|
|
209
|
+
private skillsCache = new Map<string, { skills: CodexSkill[]; expiry: number }>();
|
|
167
210
|
|
|
168
211
|
private get config() {
|
|
169
212
|
try { return configService.get("ai").providers["codex"] ?? null; } catch { return null; }
|
|
@@ -207,10 +250,29 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
207
250
|
}
|
|
208
251
|
|
|
209
252
|
async listSessionsByDir(dir: string, opts?: { limit?: number; offset?: number }): Promise<SessionInfo[]> {
|
|
210
|
-
const
|
|
253
|
+
const seen = new Set<string>();
|
|
254
|
+
const sessions: SessionInfo[] = [];
|
|
255
|
+
for (const sessionsDir of codexSessionsDirs()) {
|
|
256
|
+
for (const s of listCodexRollouts(sessionsDir, dir, this.id, opts)) {
|
|
257
|
+
if (seen.has(s.id)) continue;
|
|
258
|
+
seen.add(s.id);
|
|
259
|
+
sessions.push(s);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
211
262
|
// Backfill provider ownership so reopening a pre-existing codex thread routes
|
|
212
263
|
// to codex (not the default provider) even after a restart.
|
|
213
|
-
|
|
264
|
+
//
|
|
265
|
+
// The project path is recorded in the same pass, and it has to be: reading a
|
|
266
|
+
// session is fail-closed on cwd, so a row registered here without one can
|
|
267
|
+
// never be read back and the conversation opens blank. `dir` is exactly that
|
|
268
|
+
// cwd — every rollout listed above matched it — so the attribution is the
|
|
269
|
+
// one already proven, not a guess.
|
|
270
|
+
for (const s of sessions) {
|
|
271
|
+
try {
|
|
272
|
+
setSessionProvider(s.id, this.id);
|
|
273
|
+
setSessionMetadata(s.id, s.projectName, dir);
|
|
274
|
+
} catch { /* non-fatal */ }
|
|
275
|
+
}
|
|
214
276
|
return sessions;
|
|
215
277
|
}
|
|
216
278
|
|
|
@@ -260,7 +322,12 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
260
322
|
live.transcript.push({ id: nextRolloutId(live), role: "user", content: message, timestamp: new Date().toISOString() });
|
|
261
323
|
live.currentAssistant = "";
|
|
262
324
|
live.currentEvents = [];
|
|
263
|
-
|
|
325
|
+
// Codex takes an image as a path, never as a payload, so the uploaded copy is what it
|
|
326
|
+
// gets. Images lead: the text usually refers to them ("what is this?").
|
|
327
|
+
const input: UserInput[] = [
|
|
328
|
+
...(opts?.imagePaths ?? []).map((path) => ({ type: "localImage" as const, path })),
|
|
329
|
+
{ type: "text" as const, text: message, text_elements: [] },
|
|
330
|
+
];
|
|
264
331
|
const turnModel = codexModel(opts?.model);
|
|
265
332
|
live.client.request("turn/start", {
|
|
266
333
|
threadId: live.threadId,
|
|
@@ -295,13 +362,13 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
295
362
|
client.onClose(() => this.handleClose(live));
|
|
296
363
|
client.start({ cwd, codexHome: account?.home });
|
|
297
364
|
|
|
298
|
-
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
|
|
365
|
+
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
299
366
|
client.notify("initialized");
|
|
300
367
|
|
|
301
368
|
const resumeBase = { cwd, sandbox: permission.sandbox, approvalPolicy: permission.approvalPolicy, ...(model ? { model } : {}) };
|
|
302
369
|
// Only treat as a resume when a rollout for this id is attributable to THIS
|
|
303
370
|
// project (fail-closed cwd guard) — never resume another project's thread.
|
|
304
|
-
const isResume = !!findRolloutByThreadId(
|
|
371
|
+
const isResume = !!fromCodexSessionsDirs(sessionId, (d) => findRolloutByThreadId(d, sessionId, cwd));
|
|
305
372
|
const result = isResume
|
|
306
373
|
? await client.request("thread/resume", { threadId: sessionId, ...resumeBase })
|
|
307
374
|
: await client.request("thread/start", resumeBase);
|
|
@@ -325,7 +392,10 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
325
392
|
}
|
|
326
393
|
// Snapshot persisted history so live message ids continue the rollout-N
|
|
327
394
|
// numbering (empty for a brand-new thread; full prior transcript on resume).
|
|
328
|
-
live.history =
|
|
395
|
+
live.history = fromCodexSessionsDirs(threadId, (d) => {
|
|
396
|
+
const msgs = getRolloutMessages(d, threadId, cwd);
|
|
397
|
+
return msgs.length > 0 ? msgs : null;
|
|
398
|
+
}) ?? [];
|
|
329
399
|
return live;
|
|
330
400
|
}
|
|
331
401
|
|
|
@@ -360,7 +430,8 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
360
430
|
if (notif.method === "item/completed" && live.compactRequested
|
|
361
431
|
&& (notif.params as { item?: { type?: string } })?.item?.type === "contextCompaction") {
|
|
362
432
|
live.compactRequested = false;
|
|
363
|
-
const file =
|
|
433
|
+
const file = fromCodexSessionsDirs(live.threadId ?? undefined,
|
|
434
|
+
(d) => findRolloutByThreadId(d, live.threadId ?? "", live.cwd));
|
|
364
435
|
if (file) {
|
|
365
436
|
const content = `_Conversation compacted to save context._\n\nread the full transcript at: ${file}`;
|
|
366
437
|
live.channel.push({ type: "text", content });
|
|
@@ -467,7 +538,10 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
467
538
|
// Fail-closed: only return rollout messages attributable to this project's cwd.
|
|
468
539
|
const cwd = this.sessions.get(sessionId)?.projectPath || getSessionProjectPath(sessionId);
|
|
469
540
|
if (!cwd) return [];
|
|
470
|
-
return
|
|
541
|
+
return fromCodexSessionsDirs(sessionId, (d) => {
|
|
542
|
+
const msgs = getRolloutMessages(d, sessionId, cwd);
|
|
543
|
+
return msgs.length > 0 ? msgs : null;
|
|
544
|
+
}) ?? [];
|
|
471
545
|
}
|
|
472
546
|
|
|
473
547
|
/**
|
|
@@ -495,7 +569,7 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
495
569
|
try {
|
|
496
570
|
if (!reuse) {
|
|
497
571
|
client.start({ cwd });
|
|
498
|
-
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
|
|
572
|
+
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
499
573
|
client.notify("initialized");
|
|
500
574
|
}
|
|
501
575
|
const forkRes = await client.request<{ thread?: { id?: string; turns?: unknown[] } }>("thread/fork", { threadId: sessionId, cwd });
|
|
@@ -534,12 +608,12 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
534
608
|
const client = new CodexJsonRpcClient();
|
|
535
609
|
try {
|
|
536
610
|
client.start({ cwd: process.cwd() });
|
|
537
|
-
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
|
|
611
|
+
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
538
612
|
client.notify("initialized");
|
|
539
613
|
const all: unknown[] = [];
|
|
540
614
|
let cursor: string | null = null;
|
|
541
615
|
do {
|
|
542
|
-
const res: ModelListResponse = await client.request<ModelListResponse>("model/list", { cursor });
|
|
616
|
+
const res: ModelListResponse = await client.request<ModelListResponse>("model/list", { cursor }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
543
617
|
if (Array.isArray(res?.data)) all.push(...res.data);
|
|
544
618
|
cursor = res?.nextCursor ?? null;
|
|
545
619
|
} while (cursor);
|
|
@@ -553,8 +627,82 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
553
627
|
}
|
|
554
628
|
}
|
|
555
629
|
|
|
556
|
-
/**
|
|
557
|
-
|
|
558
|
-
|
|
630
|
+
/**
|
|
631
|
+
* The skills codex itself would resolve for `cwd`, asked of codex rather than
|
|
632
|
+
* discovered from disk.
|
|
633
|
+
*
|
|
634
|
+
* Two reasons it has to come from the app-server. Codex's built-ins live under
|
|
635
|
+
* `$CODEX_HOME/skills/.system/`, and PPM points CODEX_HOME at a per-account
|
|
636
|
+
* directory — so scanning the ambient `~/.codex` reads a different, possibly
|
|
637
|
+
* stale set than the session will actually run. And the app-server is the only
|
|
638
|
+
* source of `enabled` and of the `interface` block (display name, icons) that
|
|
639
|
+
* the picker shows.
|
|
640
|
+
*
|
|
641
|
+
* Cached briefly per (cwd, account): the list changes when the user installs a
|
|
642
|
+
* skill, which should show up without a restart, but a picker keystroke must
|
|
643
|
+
* not spawn an app-server.
|
|
644
|
+
*/
|
|
645
|
+
async listSkills(sessionId?: string): Promise<CodexSkill[]> {
|
|
646
|
+
const cwd = (sessionId ? getSessionProjectPath(sessionId) : null) || process.cwd();
|
|
647
|
+
// Reuse the account already bound to the session; resolving afresh here
|
|
648
|
+
// would advance a round-robin strategy for a mere UI listing.
|
|
649
|
+
const accountId = sessionId ? getSessionCodexAccount(sessionId) : null;
|
|
650
|
+
const home = (accountId ? getCodexAccount(accountId)?.home : null) ?? undefined;
|
|
651
|
+
|
|
652
|
+
const key = `${cwd}\0${home ?? ""}`;
|
|
653
|
+
const hit = this.skillsCache.get(key);
|
|
654
|
+
if (hit && Date.now() < hit.expiry) return hit.skills;
|
|
655
|
+
|
|
656
|
+
const client = new CodexJsonRpcClient();
|
|
657
|
+
try {
|
|
658
|
+
client.start({ cwd, codexHome: home });
|
|
659
|
+
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
660
|
+
client.notify("initialized");
|
|
661
|
+
const skills = parseSkillList(await client.request("skills/list", {}, CONTROL_REQUEST_TIMEOUT_MS));
|
|
662
|
+
if (skills.length > 0) this.skillsCache.set(key, { skills, expiry: Date.now() + SKILLS_CACHE_TTL });
|
|
663
|
+
return skills;
|
|
664
|
+
} catch {
|
|
665
|
+
return [];
|
|
666
|
+
} finally {
|
|
667
|
+
client.close();
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/** Read the session's account without advancing the account-selection strategy. */
|
|
672
|
+
async getUsage(sessionId?: string): Promise<UsageInfo> {
|
|
673
|
+
// Idempotent, and needed because a caller can reach the provider before the
|
|
674
|
+
// server has started background polling — an unregistered source would make
|
|
675
|
+
// the shared layer answer {} instead of reading codex.
|
|
676
|
+
registerUsageSource(codexUsageSource);
|
|
677
|
+
const accountId = sessionId ? getSessionCodexAccount(sessionId) : null;
|
|
678
|
+
const bound = accountId ? getCodexAccount(accountId) : null;
|
|
679
|
+
if (bound) {
|
|
680
|
+
// Through the shared layer, so this answers from the cache or the stored
|
|
681
|
+
// snapshot and only reaches codex when nothing is known yet — the same
|
|
682
|
+
// path Claude's usage takes. It used to spawn an app-server inline on
|
|
683
|
+
// every miss, on the HTTP request's own thread of control.
|
|
684
|
+
return {
|
|
685
|
+
...await getOrFetchUsage(this.id, bound.id),
|
|
686
|
+
activeAccountId: bound.id,
|
|
687
|
+
activeAccountLabel: bound.label,
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Nothing bound yet — a session binds on its first send. Name the account
|
|
692
|
+
// that will serve it, but do NOT read its quota: that spawns an app-server
|
|
693
|
+
// against a login which is not yet this session's, and which a round-robin
|
|
694
|
+
// or lowest-usage pick may never hand it. So the toolbar can say WHO will
|
|
695
|
+
// answer without PPM touching that account on a session's behalf before
|
|
696
|
+
// the session owns it. The numbers arrive with the first turn.
|
|
697
|
+
//
|
|
698
|
+
// Skipped when the session names an account that no longer exists: naming
|
|
699
|
+
// a different one there would be a lie about a binding that already failed.
|
|
700
|
+
const pending = accountId ? null : peekCodexAccount();
|
|
701
|
+
if (pending) return { activeAccountId: pending.id, activeAccountLabel: pending.label };
|
|
702
|
+
|
|
703
|
+
// Managed accounts are assigned on first send; don't show an unrelated
|
|
704
|
+
// ambient login while that assignment is pending or the binding is missing.
|
|
705
|
+
if (accountId || listCodexAccounts().length > 0) return {};
|
|
706
|
+
return getOrFetchUsage(this.id, AMBIENT_ACCOUNT_KEY);
|
|
559
707
|
}
|
|
560
708
|
}
|