@hienlh/ppm 0.19.2 → 0.19.4
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 +27 -0
- 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-CCFQV-RB.js +1 -0
- package/dist/web/assets/ai-resource-editor-BTWds-aC.js +1 -0
- package/dist/web/assets/ai-settings-section-CmoBsSpY.js +1 -0
- package/dist/web/assets/ai-settings-section-DjbYj4wK.js +1 -0
- package/dist/web/assets/{angular-html-BlcrLjUx.js → angular-html-BuHNQIbQ.js} +1 -1
- package/dist/web/assets/{angular-ts-BUjtceAJ.js → angular-ts-DHRWoLc-.js} +1 -1
- package/dist/web/assets/api-client-BogqsFna.js +1 -0
- package/dist/web/assets/api-settings-CTMdz_VF.js +1 -0
- package/dist/web/assets/{api-themes-YsZgf6Xj.js → api-themes-Cknp3Q-P.js} +1 -1
- package/dist/web/assets/{apl-B3g0v1pk.js → apl-C1VSWVei.js} +1 -1
- package/dist/web/assets/appearance-settings-section-vLmakLtA.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-FRnyn7cH.js → astro-RX-rChsZ.js} +1 -1
- package/dist/web/assets/{audio-preview-DWTRm4HC.js → audio-preview-CCd1jdje.js} +1 -1
- package/dist/web/assets/{blade-NLdOqUKw.js → blade-CZ6bxMbK.js} +1 -1
- package/dist/web/assets/{pencil-BlIIg6RH.js → brain-KDa9jFRq.js} +1 -1
- package/dist/web/assets/{bsl-CenHZfaU.js → bsl-BhgCXLWk.js} +1 -1
- package/dist/web/assets/{button-Cq8yixjf.js → button-BZtEJcUv.js} +1 -1
- package/dist/web/assets/{cairo-B_WR0aiQ.js → cairo-BrwygPkn.js} +1 -1
- package/dist/web/assets/calendar-clock-C1asT-gk.js +1 -0
- package/dist/web/assets/chat-tab-CLRlS8Jc.js +15 -0
- package/dist/web/assets/check-DN75Ucvz.js +1 -0
- package/dist/web/assets/chevron-up-8PbsNiJp.js +1 -0
- package/dist/web/assets/{cobol-DOynhWYj.js → cobol-C5TGW1Ir.js} +1 -1
- package/dist/web/assets/code-editor-CCwVu5F5.js +7 -0
- package/dist/web/assets/{coffee-Bn6dbw4P.js → coffee-CFgKlmgI.js} +1 -1
- package/dist/web/assets/{conflict-editor-Cgb-z12D.js → conflict-editor-CvWYcbwD.js} +1 -1
- package/dist/web/assets/context-menu-C13b1uT3.js +1 -0
- package/dist/web/assets/{cpp-CoZR9t8r.js → cpp-BhG5q3-d.js} +1 -1
- package/dist/web/assets/{crystal-BSheONSg.js → crystal-DvuI7_tY.js} +1 -1
- package/dist/web/assets/{csv-preview-BZMHfFH3.js → csv-preview-DzuDuyE_.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-gwPoVSCU.js → data-grid-overlay-editor-DP1xkog4.js} +1 -1
- package/dist/web/assets/database-viewer-D4XGEDHm.js +1 -0
- package/dist/web/assets/diff-viewer-B5N1X61R.js +4 -0
- package/dist/web/assets/{docx-preview-DqVDOMmv.js → docx-preview-CWIDVNZn.js} +1 -1
- package/dist/web/assets/{edge-DTtoslQu.js → edge-BSIEsmlI.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-CXSbSUBX.js → edit-diff-preview-DeHb85DN.js} +1 -1
- package/dist/web/assets/{elixir-CIBCZ3Zi.js → elixir-BF-lrGXM.js} +1 -1
- package/dist/web/assets/{elm-BLmb7K1H.js → elm-8mCsJOeN.js} +1 -1
- package/dist/web/assets/{erb-BBY8ApRd.js → erb-Dw5PUVKa.js} +1 -1
- package/dist/web/assets/{erlang-D5Zb5_P0.js → erlang-BvjBIA6O.js} +1 -1
- package/dist/web/assets/{esm-6F8v1jLL.js → esm-Bt9OwSnU.js} +1 -1
- package/dist/web/assets/explorer-body-BxLLjthF.js +2 -0
- package/dist/web/assets/explorer-window-content-CL1Cipj3.js +1 -0
- package/dist/web/assets/extension-manager-section-BpyGq15A.js +1 -0
- package/dist/web/assets/{extension-webview-BSh6KGd7.js → extension-webview-BM8FXhuN.js} +1 -1
- package/dist/web/assets/{plus-BR0qewJI.js → eye-gWwaF4Lg.js} +1 -1
- package/dist/web/assets/eye-off-GjXVuAOn.js +1 -0
- package/dist/web/assets/files-settings-section-B0_aR1nL.js +1 -0
- package/dist/web/assets/flask-conical-tp8gyZGh.js +1 -0
- package/dist/web/assets/{fortran-fixed-form-CBdwkEUJ.js → fortran-fixed-form-CRjUJe9K.js} +1 -1
- package/dist/web/assets/{fsharp-AT4XdVYH.js → fsharp-CjUIHIHp.js} +1 -1
- package/dist/web/assets/{gdresource-D852fWBR.js → gdresource-x_NUQFrZ.js} +1 -1
- package/dist/web/assets/general-settings-section-C1EJzjhU.js +1 -0
- package/dist/web/assets/{git-commit-DWfWAyxy.js → git-commit-BOpxSbns.js} +1 -1
- package/dist/web/assets/git-log-panel-D1yGTUE_.js +1 -0
- package/dist/web/assets/{git-rebase-C6opk8gr.js → git-rebase-BW4xlK7k.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-BloZfB0Q.js +1 -0
- package/dist/web/assets/{glide-data-grid-CICFjJon.js → glide-data-grid-Cu0STKML.js} +12 -12
- package/dist/web/assets/{glimmer-js-DLi5mWYO.js → glimmer-js-CT9jrmFj.js} +1 -1
- package/dist/web/assets/{glimmer-ts-D-scFX30.js → glimmer-ts-CjQT1lxK.js} +1 -1
- package/dist/web/assets/{glsl-dbQzF4iA.js → glsl-DsFJvtg5.js} +1 -1
- package/dist/web/assets/{graphql-D1m5Wen2.js → graphql-Dhlnmkn_.js} +1 -1
- package/dist/web/assets/group-chat-tab-BfcvkRX5.js +1 -0
- package/dist/web/assets/{hack-CqYmpO7u.js → hack-BKHbsJ7u.js} +1 -1
- package/dist/web/assets/{haml-BXzKWEag.js → haml-C1Ih25Y2.js} +1 -1
- package/dist/web/assets/{handlebars-DXnrtHtq.js → handlebars-CaFitvmC.js} +1 -1
- package/dist/web/assets/{html-DhgQJ-xL.js → html-BwpKIE6V.js} +1 -1
- package/dist/web/assets/{html-derivative-xZRft-YE.js → html-derivative-uuTEquZU.js} +1 -1
- package/dist/web/assets/{http-B53mSj14.js → http-Cv4Pg5cR.js} +1 -1
- package/dist/web/assets/{hurl-CsomVy04.js → hurl-DubkI6TG.js} +1 -1
- package/dist/web/assets/{hxml-LffjWwKA.js → hxml-B9OVZFAB.js} +1 -1
- package/dist/web/assets/{image-preview-CNA6XMNS.js → image-preview-DRbZ0FA2.js} +1 -1
- package/dist/web/assets/index-B1bzKRjJ.js +52 -0
- package/dist/web/assets/index-nP3uxXvR.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-c0W8wp5o.js +1 -0
- package/dist/web/assets/{jinja-CCHURl7V.js → jinja-BHb1jyl6.js} +1 -1
- package/dist/web/assets/jira-watcher-section-DZh-Z2MK.js +1 -0
- package/dist/web/assets/{jison-7qBd8dnR.js → jison-CtpfXDzp.js} +1 -1
- package/dist/web/assets/{julia-BY9pnTcy.js → julia-TYjgpazU.js} +1 -1
- package/dist/web/assets/{just-D7wRSNRr.js → just-D27bzZuW.js} +1 -1
- package/dist/web/assets/key-round-CQpDrDxg.js +1 -0
- package/dist/web/assets/keybindings-store-CFwgcnpZ.js +1 -0
- package/dist/web/assets/keyboard-shortcuts-section-JBtcJGM3.js +1 -0
- package/dist/web/assets/{latex-RgsCae55.js → latex-D_MzopTn.js} +1 -1
- package/dist/web/assets/{liquid-CnDFzvOZ.js → liquid-BG_FG0Pe.js} +1 -1
- package/dist/web/assets/{lua-0lj5W8sm.js → lua-Bl29oC2L.js} +1 -1
- package/dist/web/assets/{markdown-renderer-dbLIvU2M.js → markdown-renderer-Bo8GgGXl.js} +3 -3
- package/dist/web/assets/markdown-renderer-DY60UZNW.js +1 -0
- package/dist/web/assets/{marko-CQgqAhbV.js → marko-D-HI7dbm.js} +1 -1
- package/dist/web/assets/{mdc-BkIcTiIy.js → mdc-y444JQTQ.js} +1 -1
- package/dist/web/assets/{media-url-DDciwvLU.js → media-url-VzecHk9g.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-pjcHKorA.js → mobile-bottom-sheet-BD5b7KJF.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-C59rPw7Z.js +1 -0
- package/dist/web/assets/{nextflow-DvIW68DS.js → nextflow-C5sKcldC.js} +1 -1
- package/dist/web/assets/{nginx-O-hft0gG.js → nginx-bXnEC3wm.js} +1 -1
- package/dist/web/assets/{nim-BxrR4HwQ.js → nim-pevhf4WD.js} +1 -1
- package/dist/web/assets/notification-store-Bd6L0K_Q.js +1 -0
- package/dist/web/assets/notifications-settings-section-ARQlF-6E.js +1 -0
- package/dist/web/assets/{number-overlay-editor-BoLRYuZT.js → number-overlay-editor-B7WINIW4.js} +1 -1
- package/dist/web/assets/{overview-panel-l3g1gT5e.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-CRShdbBS.js +1 -0
- package/dist/web/assets/{perl-Da-uNqmL.js → perl-B1KUtMnW.js} +1 -1
- package/dist/web/assets/{php-JMu45mEx.js → php-BGmVZBAJ.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-BaLfuEf8.js +1 -0
- package/dist/web/assets/{postgres-viewer-DstZwUai.js → postgres-viewer-BNT-4yYl.js} +3 -3
- package/dist/web/assets/power-CriQkeK5.js +1 -0
- package/dist/web/assets/ppmbot-settings-section-Bq4YAcFW.js +1 -0
- package/dist/web/assets/{process-table-kmQ2-8qJ.js → process-table-CjiXW0rg.js} +1 -1
- package/dist/web/assets/{project-store-DTUCS65m.js → project-store-BuY7rxn_.js} +1 -1
- package/dist/web/assets/proxy-settings-section-wRbiyQiA.js +3 -0
- package/dist/web/assets/{pug-CLzyQhia.js → pug-BfN8CpEH.js} +1 -1
- package/dist/web/assets/{qml-BHXfGB1l.js → qml-D6fRdLZt.js} +1 -1
- package/dist/web/assets/query-audit-section-C5RmhRSu.js +1 -0
- package/dist/web/assets/radar-KQ55EAFF-DBIZEaIU.js +1 -0
- package/dist/web/assets/{razor-BqetJLN3.js → razor-fg-9AScR.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-BF-75_03.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-view-C9KR9I9G.js +1 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BnKJicB2.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-awXsNw_R.js +1 -0
- package/dist/web/assets/{rst-iQdJZ0BP.js → rst-BZgx076b.js} +1 -1
- package/dist/web/assets/{ruby-CNwzZGdH.js → ruby-iUkWDcLo.js} +1 -1
- package/dist/web/assets/{run-in-terminal-CBXmVGWa.js → run-in-terminal-bKRwuO2z.js} +1 -1
- package/dist/web/assets/{sas-BpBIT2eR.js → sas-CLXO0lZ6.js} +1 -1
- package/dist/web/assets/schedules-settings-section-BOecKJzl.js +1 -0
- package/dist/web/assets/{scss-D1MotuEp.js → scss-DQqteGaG.js} +1 -1
- package/dist/web/assets/send-Bb0jtcR6.js +1 -0
- package/dist/web/assets/{send-to-chat-DJAdlvJ8.js → send-to-chat-S8LCNX7V.js} +1 -1
- package/dist/web/assets/separator-DqGg3f9c.js +1 -0
- package/dist/web/assets/settings-body-DGi5DXY6.js +2 -0
- package/dist/web/assets/settings-store-Brjd0QnO.js +2 -0
- package/dist/web/assets/settings-tab-GM9zTRul.js +1 -0
- package/dist/web/assets/settings-window-content-Dvhxo4_H.js +1 -0
- package/dist/web/assets/{shaderlab-BNqmcPQi.js → shaderlab-CeMTqagR.js} +1 -1
- package/dist/web/assets/{shellsession-BBLOVOO-.js → shellsession-BAkquZAV.js} +1 -1
- package/dist/web/assets/{soy-BpTGo9uy.js → soy-Bxm9Ez55.js} +1 -1
- package/dist/web/assets/{sparql-D7A3yKob.js → sparql-C1phwdLc.js} +1 -1
- package/dist/web/assets/sql-query-editor-BmkGFzcL.js +1 -0
- package/dist/web/assets/sqlite-viewer-DbziVQXQ.js +1 -0
- package/dist/web/assets/{stata-B7N56ptS.js → stata-DGNMQdEb.js} +1 -1
- package/dist/web/assets/{surrealql-CTmnD-lv.js → surrealql-ByVrV320.js} +1 -1
- package/dist/web/assets/{svelte-BppwY9TR.js → svelte-CNWjIMhl.js} +1 -1
- package/dist/web/assets/system-monitor-body-CbHW5aYm.js +2 -0
- package/dist/web/assets/system-monitor-tab-C7EZLMIo.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-B9Y98UW6.js → system-monitor-window-content-C_w4w81e.js} +1 -1
- package/dist/web/assets/{tab-host-window-content-C1j8zr68.js → tab-host-window-content-BSP1SEXS.js} +1 -1
- package/dist/web/assets/{tab-store-DzYSsw5a.js → tab-store-PZsP5ZwG.js} +1 -1
- package/dist/web/assets/team-member-sheet-C9N0iA1-.js +2 -0
- package/dist/web/assets/team-member-window-content-CM2QFv-s.js +1 -0
- package/dist/web/assets/{templ-CvTMKKra.js → templ-Cf0gQL4I.js} +1 -1
- package/dist/web/assets/{terminal-tab-B9I_HlES.js → terminal-tab-jWYELm8y.js} +3 -3
- package/dist/web/assets/{tex--c4POEUE.js → tex-BTIqPw_R.js} +1 -1
- package/dist/web/assets/tool-cards-jefdOWVJ.js +9 -0
- package/dist/web/assets/treemap-KZPCXAKY-DFiG9UYW.js +1 -0
- package/dist/web/assets/{ts-tags--kx7D-Hw.js → ts-tags-B8dN_Yf6.js} +1 -1
- package/dist/web/assets/{twig-UG9uMHGd.js → twig-BgemonbJ.js} +1 -1
- package/dist/web/assets/use-accounts-data-MhMl0Y4Z.js +1 -0
- package/dist/web/assets/{use-blob-url-Bdxopwwc.js → use-blob-url-Gfi69PtP.js} +1 -1
- package/dist/web/assets/use-monaco-theme-BbAd7DXr.js +1 -0
- package/dist/web/assets/{use-open-team-member-D9EOB8-i.js → use-open-team-member-CruUTqzD.js} +1 -1
- package/dist/web/assets/use-remote-desktop-display-choice-DlfMIWq3.js +1 -0
- package/dist/web/assets/{use-websocket-xOOwBdwP.js → use-websocket-Bq8X_SUI.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-0Nt-ew76.js → vendor-mermaid-BKWscKt0.js} +1 -1
- package/dist/web/assets/video-preview-BGh3B0Lu.js +1 -0
- package/dist/web/assets/{vue-jjTomlbt.js → vue-D3D4lbXz.js} +1 -1
- package/dist/web/assets/{vue-html-8KEW6-I9.js → vue-html-DYEQFAiK.js} +1 -1
- package/dist/web/assets/{vue-vine-C5tohCkU.js → vue-vine-D0OPNscN.js} +1 -1
- package/dist/web/assets/{window-pip-registry-FdZdGF7h.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/{xml-ByFFosqL.js → xml-DHaWgpya.js} +1 -1
- package/dist/web/assets/{xsl-CZUwiLkj.js → xsl-DVRN8JsA.js} +1 -1
- package/dist/web/index.html +32 -55
- 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/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 +159 -17
- 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 +67 -9
- package/src/server/routes/codex-accounts.ts +9 -5
- package/src/server/ws/chat.ts +46 -1
- 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/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/proxy-agent-anthropic-bridge.ts +93 -0
- package/src/services/proxy-agent-bridge.ts +100 -0
- package/src/services/proxy-agent-turn.ts +161 -0
- package/src/services/proxy-anthropic-format.ts +157 -0
- package/src/services/proxy-openai-format.ts +148 -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/windows-process-tree.ts +351 -351
- package/src/types/chat.ts +7 -1
- package/src/web/app.tsx +1 -7
- package/src/web/components/chat/chat-history-bar.tsx +10 -1
- package/src/web/components/chat/chat-tab.tsx +17 -1
- package/src/web/components/chat/message-input.tsx +11 -4
- package/src/web/components/chat/message-list.tsx +14 -0
- 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 +59 -426
- 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 +151 -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 +113 -0
- package/src/web/components/settings/accounts/accounts-settings-section.tsx +80 -0
- package/src/web/components/settings/accounts/claude-accounts-section.tsx +169 -0
- package/src/web/components/settings/accounts/codex-accounts-section.tsx +144 -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 +38 -1
- 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/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-BbuRVTLn.js +0 -1
- package/dist/web/assets/ai-resource-editor-BCCOUzox.js +0 -1
- package/dist/web/assets/ai-settings-section-BEM1z7kp.js +0 -1
- package/dist/web/assets/api-client-D1CePgQ4.js +0 -1
- package/dist/web/assets/api-settings-CNtKkHqW.js +0 -1
- package/dist/web/assets/api-settings-Cubuqjsu.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-6konx-J1.js +0 -1
- package/dist/web/assets/chat-tab-CmXGsJGc.js +0 -15
- package/dist/web/assets/clipboard-B-gwJ8DF.js +0 -1
- package/dist/web/assets/code-editor-DtHXzNZ1.js +0 -7
- package/dist/web/assets/context-menu-DfWZAxQy.js +0 -1
- package/dist/web/assets/database-viewer-GVaQVMdb.js +0 -1
- package/dist/web/assets/dialog-BSfuiTkJ.js +0 -1
- package/dist/web/assets/diff-viewer-BG5_fH1E.js +0 -4
- package/dist/web/assets/explorer-body-BPFnjxYj.js +0 -2
- package/dist/web/assets/explorer-window-content-Da1T9uM4.js +0 -1
- package/dist/web/assets/extension-store-Bhu--fPX.js +0 -1
- package/dist/web/assets/external-link-B6Hl0U4X.js +0 -1
- package/dist/web/assets/eye-off-CUdzgmX8.js +0 -1
- package/dist/web/assets/file-store-6HW2Lfl4.js +0 -1
- package/dist/web/assets/git-log-panel-DNC9fV0M.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-ikUwsekd.js +0 -1
- package/dist/web/assets/group-chat-tab-DbUkcOaJ.js +0 -1
- package/dist/web/assets/index-DTqbMiVc.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-D0ol5jW0.js +0 -1
- package/dist/web/assets/keybindings-store-BGkB72gM.js +0 -1
- package/dist/web/assets/keybindings-store-Bq6VWl5X.js +0 -1
- package/dist/web/assets/lock-CNxUGpTk.js +0 -1
- package/dist/web/assets/markdown-renderer-DEAVpo0C.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-CD_kl-jA.js +0 -1
- package/dist/web/assets/monitor-smartphone-DLZ6Q05s.js +0 -1
- package/dist/web/assets/notification-store-Dgbsw9p9.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-RVlbbDRS.js +0 -1
- package/dist/web/assets/panel-store-UOV8wrfR.js +0 -1
- package/dist/web/assets/pdf-preview-B2CJ_EKv.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-ZWb4izpk.js +0 -1
- package/dist/web/assets/play-DpEEBJTT.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-bsP5x1Bx.js +0 -1
- package/dist/web/assets/refresh-cw-BQU5g2CY.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-KKTRNjOL.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-view-C1ST4-Fm.js +0 -1
- package/dist/web/assets/remote-desktop-readiness-gate-BH3BE5wA.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-BaZJQt_N.js +0 -1
- package/dist/web/assets/rotate-ccw-CpjRo90J.js +0 -1
- package/dist/web/assets/scroll-area-lc0ZHORr.js +0 -1
- package/dist/web/assets/send-C_sLFt56.js +0 -1
- package/dist/web/assets/settings-store-zbPkG7o-.js +0 -2
- package/dist/web/assets/settings-tab-Cn-AqUP_.js +0 -1
- package/dist/web/assets/settings-tab-xyRpt2gq.js +0 -3
- package/dist/web/assets/shallow-CmPMAPte.js +0 -1
- package/dist/web/assets/sql-query-editor-B86NiZHI.js +0 -1
- package/dist/web/assets/sqlite-viewer-DB775F6C.js +0 -1
- package/dist/web/assets/switch-BmjKoIpR.js +0 -1
- package/dist/web/assets/system-monitor-body-BDxHQvy9.js +0 -2
- package/dist/web/assets/system-monitor-tab-BoTHLx6B.js +0 -1
- package/dist/web/assets/team-member-sheet-Cxz6h5Ne.js +0 -2
- package/dist/web/assets/team-member-window-content-CUSuRHCB.js +0 -1
- package/dist/web/assets/tool-cards-D3KSzd2K.js +0 -8
- package/dist/web/assets/trash-2-By4VMbC4.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-Dh1oxNdQ.js +0 -1
- package/dist/web/assets/triangle-alert-CUTURFbG.js +0 -1
- package/dist/web/assets/upload-BNlX8D07.js +0 -1
- package/dist/web/assets/use-monaco-theme-CVCye2kq.js +0 -1
- package/dist/web/assets/use-remote-desktop-display-choice-neUqyE3p.js +0 -1
- package/dist/web/assets/video-preview-DvpgBDhM.js +0 -1
- package/dist/web/assets/window-store-D0x_fxr0.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-C5DFF0s3.js → abap-h3QyH8MW.js} +0 -0
- /package/dist/web/assets/{actionscript-3-B0qyRNbc.js → actionscript-3-mkxkq-FN.js} +0 -0
- /package/dist/web/assets/{ada-bAJzplug.js → ada-DhISK_EH.js} +0 -0
- /package/dist/web/assets/{andromeeda-DUCpISy6.js → andromeeda-DnlWWesX.js} +0 -0
- /package/dist/web/assets/{apache-BhAr84Z_.js → apache-P5AK3sfA.js} +0 -0
- /package/dist/web/assets/{apex-CRv8YnNq.js → apex-CJUPehg2.js} +0 -0
- /package/dist/web/assets/{api-client-BzWM7XPR.js → api-client-oY1tC3tM.js} +0 -0
- /package/dist/web/assets/{applescript-CD-Cw8bt.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-BUzeQYoG.js → ara-95Kx3qKb.js} +0 -0
- /package/dist/web/assets/{asciidoc-CT2hTg-v.js → asciidoc-Dp0RbIej.js} +0 -0
- /package/dist/web/assets/{asm-CAu35JeY.js → asm-C82coUjU.js} +0 -0
- /package/dist/web/assets/{aurora-x-BeFJoIA1.js → aurora-x-BFc3zeop.js} +0 -0
- /package/dist/web/assets/{awk-Vau-DrGN.js → awk-ChjC0icr.js} +0 -0
- /package/dist/web/assets/{ayu-dark-CLe-OTsQ.js → ayu-dark-DYfUf_PB.js} +0 -0
- /package/dist/web/assets/{ayu-light-CJbQfu4M.js → ayu-light-Bh6O0plO.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-GWaKwdrx.js → ayu-mirage-DlNhHTGq.js} +0 -0
- /package/dist/web/assets/{ballerina-DWu0USI5.js → ballerina-Ceoll3Sk.js} +0 -0
- /package/dist/web/assets/{bat-_07Huw7E.js → bat-C7QS6Lfq.js} +0 -0
- /package/dist/web/assets/{beancount-EcvogrcF.js → beancount-5NMEAZgs.js} +0 -0
- /package/dist/web/assets/{berry-BBB87SY7.js → berry-BBL83Vbk.js} +0 -0
- /package/dist/web/assets/{bibtex-DbueS87A.js → bibtex-L7rPkPSG.js} +0 -0
- /package/dist/web/assets/{bicep-tcmXnUo4.js → bicep-BOwHIINh.js} +0 -0
- /package/dist/web/assets/{bird2-B2qwilIR.js → bird2-CWLsMom2.js} +0 -0
- /package/dist/web/assets/{c-Z58oivSt.js → c-CD4Ku5Cr.js} +0 -0
- /package/dist/web/assets/{c3-U40cGT9p.js → c3-CpMl-w3G.js} +0 -0
- /package/dist/web/assets/{cadence-BFcD-LyM.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-RkC9AX6J.js → catppuccin-frappe-eo_dTm3F.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-Bsi4l-nO.js → catppuccin-latte-DoiMCU_7.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-B8JIdTW-.js → catppuccin-macchiato-UQxsK2Vh.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-oH8wwrDj.js → catppuccin-mocha-J0i-8RNy.js} +0 -0
- /package/dist/web/assets/{clarity-C3WNeRCR.js → clarity-DXYM8-SA.js} +0 -0
- /package/dist/web/assets/{clojure-CFoAz7u9.js → clojure-DzamsL69.js} +0 -0
- /package/dist/web/assets/{cmake-Bcsqp9yR.js → cmake-CR6RP_T_.js} +0 -0
- /package/dist/web/assets/{codeowners-DC2Z7heP.js → codeowners-D1s6-IyY.js} +0 -0
- /package/dist/web/assets/{codeql-BfG68Al5.js → codeql-DAqNWMkS.js} +0 -0
- /package/dist/web/assets/{common-lisp-Z5P-lKQe.js → common-lisp-8e-KtitB.js} +0 -0
- /package/dist/web/assets/{coq-BJslqrnv.js → coq-UEq0WUcO.js} +0 -0
- /package/dist/web/assets/{csharp-DhhZTOTs.js → csharp-wxJ0TuCm.js} +0 -0
- /package/dist/web/assets/{css-DiFIpMfE.js → css-Cerub-yB.js} +0 -0
- /package/dist/web/assets/{csv-DViLbHxI.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-CoG3mg2I.js → cue-rzM1ztqU.js} +0 -0
- /package/dist/web/assets/{cypher-jTxC8NAB.js → cypher-DGaTQ8m0.js} +0 -0
- /package/dist/web/assets/{d-6hKIUAbU.js → d-DbkZGuhB.js} +0 -0
- /package/dist/web/assets/{dark-plus-D_-np2Sr.js → dark-plus-BO2bzZcA.js} +0 -0
- /package/dist/web/assets/{dart-CVpxLpVn.js → dart-BDhCoqVg.js} +0 -0
- /package/dist/web/assets/{data-grid-types-Dq_H1IPa.js → data-grid-types-CdAg-4W1.js} +0 -0
- /package/dist/web/assets/{dax-BPqJ8qIY.js → dax-Bh03stWh.js} +0 -0
- /package/dist/web/assets/{desktop-u_y5_Hr5.js → desktop-BOdr_fwq.js} +0 -0
- /package/dist/web/assets/{diff-Duj1XMrd.js → diff-Bb_gTsS2.js} +0 -0
- /package/dist/web/assets/{dist-CEZ4plgH.js → dist-BUMDu0av.js} +0 -0
- /package/dist/web/assets/{dist-aDSxTR_v.js → dist-DonmFWG8.js} +0 -0
- /package/dist/web/assets/{docker-8UGSCc7N.js → docker-BDsTF5ce.js} +0 -0
- /package/dist/web/assets/{dotenv-DVnj8kyR.js → dotenv-CbCWp9Ti.js} +0 -0
- /package/dist/web/assets/{dracula-D0cEmSg7.js → dracula-Cd1fxvoX.js} +0 -0
- /package/dist/web/assets/{dracula-soft-DfGS5Yfr.js → dracula-soft-B7eXkfXG.js} +0 -0
- /package/dist/web/assets/{dream-maker-qG8kMGTF.js → dream-maker-XlzuS21R.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-iVqyMLyT.js → emacs-lisp-CXV1Ki_7.js} +0 -0
- /package/dist/web/assets/{everforest-dark-Cruygd5U.js → everforest-dark-DuqR60Dg.js} +0 -0
- /package/dist/web/assets/{everforest-light-BiJa8RHL.js → everforest-light-q4BPnenD.js} +0 -0
- /package/dist/web/assets/{fennel-H6XSEIoz.js → fennel-B-e0TX2Q.js} +0 -0
- /package/dist/web/assets/{fish-ho_7CxX6.js → fish-Bzb6-TtF.js} +0 -0
- /package/dist/web/assets/{fluent-1l5ssJTF.js → fluent-B-szH2-f.js} +0 -0
- /package/dist/web/assets/{folder-symlink-Dx1hOk8X.js → folder-symlink-fQRoG_rV.js} +0 -0
- /package/dist/web/assets/{format-bytes-gQw5wzqa.js → format-bytes-CKXk9k2d.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-Bo1x233A.js → fortran-free-form-OS6SGYC0.js} +0 -0
- /package/dist/web/assets/{gdscript-DffFMp_k.js → gdscript-FYq4OP2d.js} +0 -0
- /package/dist/web/assets/{gdshader-CvnpAiAF.js → gdshader-BpG6P8rw.js} +0 -0
- /package/dist/web/assets/{genie-2eOvAEzW.js → genie-BS9RLAna.js} +0 -0
- /package/dist/web/assets/{gherkin-DL-5OUlV.js → gherkin-B_9FdtGs.js} +0 -0
- /package/dist/web/assets/{github-dark-DrTZprgG.js → github-dark-cfaIlnBV.js} +0 -0
- /package/dist/web/assets/{github-dark-default-_mDH8IMP.js → github-dark-default-B2Wv65He.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-C48hJuLn.js → github-dark-dimmed-CtM9X76s.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-BQ-zGGNe.js → github-dark-high-contrast-DLHyk0tG.js} +0 -0
- /package/dist/web/assets/{github-light-BYc90Yx8.js → github-light-DWEI10iG.js} +0 -0
- /package/dist/web/assets/{github-light-default-Daecj4J5.js → github-light-default-DcJkK1YN.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-DoafCbsU.js → github-light-high-contrast-Bcx9iKDt.js} +0 -0
- /package/dist/web/assets/{gleam-hUWWjmnp.js → gleam-DVpiM6b2.js} +0 -0
- /package/dist/web/assets/{gn-7PJ3R70o.js → gn-B80DNc0i.js} +0 -0
- /package/dist/web/assets/{gnuplot-V-Pxck7b.js → gnuplot-D9i3MaT-.js} +0 -0
- /package/dist/web/assets/{go-ARF6DprD.js → go-CwCBf_Pt.js} +0 -0
- /package/dist/web/assets/{groovy-CKGBIPOz.js → groovy-D7mEfwmW.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-Cm9wqdI3.js → gruvbox-dark-hard-C4R4MOoH.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-Cmsd6dG8.js → gruvbox-dark-medium-CZnFC0s8.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-BBGlGGCz.js → gruvbox-dark-soft-DFcJlEBl.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-BCR7KmqG.js → gruvbox-light-hard-B6IF_1L-.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-CP32bga8.js → gruvbox-light-medium-C19AZJv2.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-qjxk8ps6.js → gruvbox-light-soft-BAnpDm9B.js} +0 -0
- /package/dist/web/assets/{haskell-C5DzwGRa.js → haskell-CsXSYXRG.js} +0 -0
- /package/dist/web/assets/{haxe-C8f_jCVv.js → haxe-B1uyiI9t.js} +0 -0
- /package/dist/web/assets/{hcl-DetJkf6E.js → hcl-DlYKn5q9.js} +0 -0
- /package/dist/web/assets/{hjson-DeZhwIdo.js → hjson-C_0VMGJJ.js} +0 -0
- /package/dist/web/assets/{hlsl-SMIDLRyX.js → hlsl-zt2PEzbg.js} +0 -0
- /package/dist/web/assets/{horizon-BMAVDxMx.js → horizon-6wQfyOK0.js} +0 -0
- /package/dist/web/assets/{horizon-bright-3BaV_VGD.js → horizon-bright-CqI2qTim.js} +0 -0
- /package/dist/web/assets/{houston-BWBbEPvb.js → houston-BljpHDoG.js} +0 -0
- /package/dist/web/assets/{hy-DcsmE-Nm.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-CnkgnYMf.js → imba-CqhhjBrP.js} +0 -0
- /package/dist/web/assets/{ini-BnvTdau7.js → ini-CiFDi6cY.js} +0 -0
- /package/dist/web/assets/{java-BLFACXat.js → java-OsQgTL5-.js} +0 -0
- /package/dist/web/assets/{javascript-BKcFWENk.js → javascript-qWAOScxl.js} +0 -0
- /package/dist/web/assets/{json-3AJtJADf.js → json-RiAKsaD1.js} +0 -0
- /package/dist/web/assets/{json5-DLyDVlwe.js → json5-BeCnS3H2.js} +0 -0
- /package/dist/web/assets/{jsonc-B5DgF1jW.js → jsonc-CbTW1Mka.js} +0 -0
- /package/dist/web/assets/{jsonl-CV_O71a2.js → jsonl-BLSi_669.js} +0 -0
- /package/dist/web/assets/{jsonnet-DZfPLgYz.js → jsonnet-C3xAggou.js} +0 -0
- /package/dist/web/assets/{jssm-Cr1zYOsY.js → jssm-CLdiagC9.js} +0 -0
- /package/dist/web/assets/{jsx-VN-JS2_q.js → jsx-lYE1lb50.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-D9CcT3xg.js → kanagawa-dragon-Cd1vcrpD.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-DLXsB8fr.js → kanagawa-lotus-Dw3QKtk9.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-weDs3Wjz.js → kanagawa-wave-DIq5Zv5G.js} +0 -0
- /package/dist/web/assets/{kdl-0XF56jnT.js → kdl-BfDV0825.js} +0 -0
- /package/dist/web/assets/{keyboard-DBBaoQSu.js → keyboard-DiOYrs6C.js} +0 -0
- /package/dist/web/assets/{kotlin-BPkH9vzk.js → kotlin-DONxR4wD.js} +0 -0
- /package/dist/web/assets/{kusto-DMVpADb9.js → kusto-BDP63Fh5.js} +0 -0
- /package/dist/web/assets/{laserwave-Cl6T2cGP.js → laserwave-BeBrWApL.js} +0 -0
- /package/dist/web/assets/{lean-BvwzQGl1.js → lean-DOZc0N1A.js} +0 -0
- /package/dist/web/assets/{less-DI_03xkC.js → less-C3H9NlDv.js} +0 -0
- /package/dist/web/assets/{lib-v9x_qXgI.js → lib-xrSJ4EZX.js} +0 -0
- /package/dist/web/assets/{libesm-dcbw4_18.js → libesm-DLBE59ul.js} +0 -0
- /package/dist/web/assets/{light-plus-hIiIsQN_.js → light-plus-C_kTL608.js} +0 -0
- /package/dist/web/assets/{llvm-B5hjjSWc.js → llvm-Dsp27U3P.js} +0 -0
- /package/dist/web/assets/{loader-circle-DouKgIXy.js → loader-circle-DPMrnLQ2.js} +0 -0
- /package/dist/web/assets/{log-D28raQiE.js → log-BywQaTCy.js} +0 -0
- /package/dist/web/assets/{logo-6Cdd4ASb.js → logo-BirJgciO.js} +0 -0
- /package/dist/web/assets/{luau-CK9nKpOX.js → luau-Btrz5kJB.js} +0 -0
- /package/dist/web/assets/{make-CVnxKCB6.js → make-Kl7nFQrS.js} +0 -0
- /package/dist/web/assets/{markdown-B9mMQzD5.js → markdown-qsC4P8S-.js} +0 -0
- /package/dist/web/assets/{material-theme-BZSs2o0j.js → material-theme-CC__ui3p.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-BeAQBzQ_.js → material-theme-darker-D4FxG2FZ.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-BAe0IXcs.js → material-theme-lighter-zGqiWcxn.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-CiPIf0Np.js → material-theme-ocean-CZIdTTB1.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-DJBb4_XN.js → material-theme-palenight-CEIs0GcK.js} +0 -0
- /package/dist/web/assets/{matlab-CY0dbp_s.js → matlab-Cf0aUjN9.js} +0 -0
- /package/dist/web/assets/{mdx-DU9zbF7h.js → mdx-CIsXjH86.js} +0 -0
- /package/dist/web/assets/{mermaid-UmmjGwdh.js → mermaid-B06WO9Qc.js} +0 -0
- /package/dist/web/assets/{min-dark-C59GkzOm.js → min-dark-z8fyp0FT.js} +0 -0
- /package/dist/web/assets/{min-light-B9QglrdQ.js → min-light-Dr-qesbW.js} +0 -0
- /package/dist/web/assets/{mipsasm-Dc6Jsr_D.js → mipsasm-CWHzYLcE.js} +0 -0
- /package/dist/web/assets/{mojo-D5ij-nGW.js → mojo-D9zXrKmv.js} +0 -0
- /package/dist/web/assets/{monitor-CxPV_fQI.js → monitor-C835ucWH.js} +0 -0
- /package/dist/web/assets/{monokai-QAtE_yCP.js → monokai-4b-AKOpX.js} +0 -0
- /package/dist/web/assets/{moonbit-BMtIdiTL.js → moonbit-Dl4dhOZJ.js} +0 -0
- /package/dist/web/assets/{move-BB_jMHYZ.js → move-DTYKJmXy.js} +0 -0
- /package/dist/web/assets/{narrat-BvvoKGVn.js → narrat-DnvXOS-o.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-CqxtAsnF.js → nextflow-groovy-Di8QnEXg.js} +0 -0
- /package/dist/web/assets/{night-owl-CLoE9kjt.js → night-owl-Czh0yq-H.js} +0 -0
- /package/dist/web/assets/{night-owl-light-BwIFT5Xd.js → night-owl-light-D_OpZqOR.js} +0 -0
- /package/dist/web/assets/{nix-BKlnVT9r.js → nix-2MvcjpK3.js} +0 -0
- /package/dist/web/assets/{nord-B7R1KRAK.js → nord-CG_r4cyk.js} +0 -0
- /package/dist/web/assets/{nushell-CzUme-NJ.js → nushell-DINskMcU.js} +0 -0
- /package/dist/web/assets/{objective-c-D-UKKiOc.js → objective-c-Dv7BIicR.js} +0 -0
- /package/dist/web/assets/{objective-cpp-BucWn4Fx.js → objective-cpp-CpqsCxPb.js} +0 -0
- /package/dist/web/assets/{ocaml-EJCNXMGo.js → ocaml-DwTsYSmW.js} +0 -0
- /package/dist/web/assets/{odin-CEjnRU_3.js → odin-G-4O4k4t.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-Bv469NX5.js → one-dark-pro-13Pv5SjI.js} +0 -0
- /package/dist/web/assets/{one-light-BlzO5RWI.js → one-light-Bi2e86mS.js} +0 -0
- /package/dist/web/assets/{openscad-Czl6alLw.js → openscad-D0WsOTij.js} +0 -0
- /package/dist/web/assets/{pascal-BI9fLvG4.js → pascal-DmDStuXr.js} +0 -0
- /package/dist/web/assets/{pkl-ChQLsyjU.js → pkl-Bl6Qjtuo.js} +0 -0
- /package/dist/web/assets/{plastic-DGL3mtdL.js → plastic-UeSVSjTI.js} +0 -0
- /package/dist/web/assets/{plsql-BJDjqcWp.js → plsql-DreFC689.js} +0 -0
- /package/dist/web/assets/{po-DK5O3OpF.js → po-ZIjccxsX.js} +0 -0
- /package/dist/web/assets/{poimandres-CnuqZT4T.js → poimandres-CvQHJPrI.js} +0 -0
- /package/dist/web/assets/{polar-DCsUxSsQ.js → polar-BrMB0Kgh.js} +0 -0
- /package/dist/web/assets/{portal-container-context-D-495m5C.js → portal-container-context-a399Hd9F.js} +0 -0
- /package/dist/web/assets/{postcss-8UjdFmis.js → postcss-pgUsil1T.js} +0 -0
- /package/dist/web/assets/{powerquery-CAp0CGQj.js → powerquery-CTsZkCg_.js} +0 -0
- /package/dist/web/assets/{powershell-CbBsKZJP.js → powershell-CcwVuBAp.js} +0 -0
- /package/dist/web/assets/{prisma-BnNpXCJN.js → prisma-spjnAI5W.js} +0 -0
- /package/dist/web/assets/{prolog-CC-l9E8Y.js → prolog-ChCkZpDO.js} +0 -0
- /package/dist/web/assets/{proto-CV_1k2rL.js → proto-wVGqK4gB.js} +0 -0
- /package/dist/web/assets/{puppet-2D8HU2bv.js → puppet-CED7iwPQ.js} +0 -0
- /package/dist/web/assets/{purescript-BEJAORgU.js → purescript-u9lGiQKV.js} +0 -0
- /package/dist/web/assets/{python-BBdbb7nn.js → python-DeqTx6ef.js} +0 -0
- /package/dist/web/assets/{qmldir-D5ZYI4Ie.js → qmldir-BH1uoPrX.js} +0 -0
- /package/dist/web/assets/{qss-BOJVGyXE.js → qss-CUVKA_13.js} +0 -0
- /package/dist/web/assets/{r-B5dlEtkj.js → r-BqdPzqYH.js} +0 -0
- /package/dist/web/assets/{racket-BUAEygJ6.js → racket-C2eTgPN3.js} +0 -0
- /package/dist/web/assets/{raku-BG0Ss0ID.js → raku-uAay1sWx.js} +0 -0
- /package/dist/web/assets/{react-B549sK_T.js → react-X4jUntEf.js} +0 -0
- /package/dist/web/assets/{red-C5yyQbtG.js → red-DTZP1ZfC.js} +0 -0
- /package/dist/web/assets/{reg-DHoBWtLf.js → reg-Cdk3YsxY.js} +0 -0
- /package/dist/web/assets/{regexp-DDtJrlKv.js → regexp-Bpa2aS7K.js} +0 -0
- /package/dist/web/assets/{rel-CR6WJDRD.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-2V9tC-nx.js → riscv-DSaubByW.js} +0 -0
- /package/dist/web/assets/{ron-QLTmqGUw.js → ron-DbQzYM6i.js} +0 -0
- /package/dist/web/assets/{rose-pine-be0__X3A.js → rose-pine-C7RsprTu.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-n_WQJwsW.js → rose-pine-dawn-VP976YzL.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-t2aLtzgB.js → rose-pine-moon-XHZNhOqd.js} +0 -0
- /package/dist/web/assets/{rosmsg-Ce1JD8vt.js → rosmsg-BVQlx0Lj.js} +0 -0
- /package/dist/web/assets/{rust-5fHH-ZoW.js → rust-VHaQ3rh3.js} +0 -0
- /package/dist/web/assets/{sass-DPmGFiOJ.js → sass-CO-kMkwD.js} +0 -0
- /package/dist/web/assets/{save-DYLiVzU8.js → save-CipGrG1k.js} +0 -0
- /package/dist/web/assets/{scala-BRMVFbZF.js → scala-cY0GXkiz.js} +0 -0
- /package/dist/web/assets/{scheme-BMSJWevF.js → scheme-D4LNZE0X.js} +0 -0
- /package/dist/web/assets/{sdbl-DTZ-pEHI.js → sdbl-Bh2Fd2cn.js} +0 -0
- /package/dist/web/assets/{shellscript-6-9yg5Cz.js → shellscript-KKclmCnt.js} +0 -0
- /package/dist/web/assets/{shield-check-CUI36aSc.js → shield-check-BsG3LV8i.js} +0 -0
- /package/dist/web/assets/{shield-off-GdkkVhb3.js → shield-off-7jKWpJBD.js} +0 -0
- /package/dist/web/assets/{slack-dark-DKJgiR7e.js → slack-dark-D6YQ-fqf.js} +0 -0
- /package/dist/web/assets/{slack-ochin-WjehVgyK.js → slack-ochin-CDf66CDj.js} +0 -0
- /package/dist/web/assets/{smalltalk-BChf4SN1.js → smalltalk-D2OH_QIl.js} +0 -0
- /package/dist/web/assets/{snazzy-light-C1WAwOx6.js → snazzy-light-CQeF8G1K.js} +0 -0
- /package/dist/web/assets/{solarized-dark-BxREZrGx.js → solarized-dark-LTPf1iLZ.js} +0 -0
- /package/dist/web/assets/{solarized-light-DG29B1pR.js → solarized-light-Ose1n88k.js} +0 -0
- /package/dist/web/assets/{solidity-bDbtGwdR.js → solidity-lFuOMHki.js} +0 -0
- /package/dist/web/assets/{splunk-Ceqx5njI.js → splunk-Bov-sB5S.js} +0 -0
- /package/dist/web/assets/{sql-OwMEKbz8.js → sql-BKyZ6wmk.js} +0 -0
- /package/dist/web/assets/{ssh-config-WAR3lu2k.js → ssh-config-CqJoMGMb.js} +0 -0
- /package/dist/web/assets/{stylus-Cjmoz3d8.js → stylus-Bf5pWRLI.js} +0 -0
- /package/dist/web/assets/{swift-S_ZSBG1q.js → swift-D5d1hn_u.js} +0 -0
- /package/dist/web/assets/{synthwave-84-DiUeWMSh.js → synthwave-84-B4c6YAgO.js} +0 -0
- /package/dist/web/assets/{system-verilog-RRjqPjUV.js → system-verilog-D7fXyDsI.js} +0 -0
- /package/dist/web/assets/{systemd-BD3SkXoU.js → systemd-oNagzlBK.js} +0 -0
- /package/dist/web/assets/{table-D5Q4ap4W.js → table-CRJsmfeg.js} +0 -0
- /package/dist/web/assets/{talonscript-DWefISOm.js → talonscript-C6Nqm9Dm.js} +0 -0
- /package/dist/web/assets/{tasl-DCjSS-09.js → tasl-CaWy-cBX.js} +0 -0
- /package/dist/web/assets/{tcl-DTYqT_66.js → tcl-C435P5Mq.js} +0 -0
- /package/dist/web/assets/{terraform-CkbP5QnR.js → terraform-CVDxqdPf.js} +0 -0
- /package/dist/web/assets/{text-wrap-DBvQD3kc.js → text-wrap-oiekm5SB.js} +0 -0
- /package/dist/web/assets/{tokyo-night-qVSqO9xy.js → tokyo-night-Uhs17tQ3.js} +0 -0
- /package/dist/web/assets/{toml-D9F5Osqs.js → toml-j6fPOJ6P.js} +0 -0
- /package/dist/web/assets/{tsv-C5tpHoxm.js → tsv-h78O6xrL.js} +0 -0
- /package/dist/web/assets/{tsx-CMWkGtGm.js → tsx-Bol-vCrQ.js} +0 -0
- /package/dist/web/assets/{turtle-Cn4z3xOi.js → turtle-Dw8eFf04.js} +0 -0
- /package/dist/web/assets/{typescript-DSyAEWsn.js → typescript-Dtz7DPci.js} +0 -0
- /package/dist/web/assets/{typespec-B93Qap7y.js → typespec-BIOQ7dMP.js} +0 -0
- /package/dist/web/assets/{typst-DtlOmFlX.js → typst-CoaGMjzu.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-B9UZNwSm.js → use-is-mobile-CYW3FJFE.js} +0 -0
- /package/dist/web/assets/{use-visual-viewport-Sfb6CZ80.js → use-visual-viewport-rnvuooQZ.js} +0 -0
- /package/dist/web/assets/{utils-QHe_Q6UF.js → utils-C9OjCrou.js} +0 -0
- /package/dist/web/assets/{v-Dfzf-szS.js → v-BoqFdpJ7.js} +0 -0
- /package/dist/web/assets/{vala-CyiQZQ9f.js → vala-COBpNnCC.js} +0 -0
- /package/dist/web/assets/{vb-C7DGSldd.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-kF-hClY2.js → verilog-DcTAamuQ.js} +0 -0
- /package/dist/web/assets/{vesper-BmKcADuz.js → vesper-DO298JSv.js} +0 -0
- /package/dist/web/assets/{vhdl-CDnb16KJ.js → vhdl-Dq-bDVSN.js} +0 -0
- /package/dist/web/assets/{viml-B8cs6Ady.js → viml-zHTRWuQh.js} +0 -0
- /package/dist/web/assets/{vitesse-black-BR6o9Gto.js → vitesse-black-jlYMJCBf.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-Dye14-KB.js → vitesse-dark-DS0sUlSZ.js} +0 -0
- /package/dist/web/assets/{vitesse-light-BLpswIxf.js → vitesse-light-HSeZ2YhG.js} +0 -0
- /package/dist/web/assets/{vyper-DU51Z97W.js → vyper-BQfKVO3M.js} +0 -0
- /package/dist/web/assets/{wasm-ChtccNfv.js → wasm-B1xp9bLp.js} +0 -0
- /package/dist/web/assets/{wasm-CVqlJAR2.js → wasm-B6mCuI8h.js} +0 -0
- /package/dist/web/assets/{wenyan-DhCa3hCn.js → wenyan-CfpS05sP.js} +0 -0
- /package/dist/web/assets/{wgsl-Bj1Ec4vv.js → wgsl-14GDsWRD.js} +0 -0
- /package/dist/web/assets/{wikitext-C90DHNa0.js → wikitext-Ccbq5EVX.js} +0 -0
- /package/dist/web/assets/{wit-DUgbOD7Z.js → wit-C19hb3R5.js} +0 -0
- /package/dist/web/assets/{wolfram-BgwUqD1I.js → wolfram-B-ZSwGwP.js} +0 -0
- /package/dist/web/assets/{x-DiOUR_mp.js → x-YDu4m2Iq.js} +0 -0
- /package/dist/web/assets/{yaml-DEQulj-8.js → yaml-mw_JUeio.js} +0 -0
- /package/dist/web/assets/{zenscript-C7Jp7TgT.js → zenscript-WbzDRjvF.js} +0 -0
- /package/dist/web/assets/{zig-9x4qXYLg.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,
|
|
@@ -34,12 +36,50 @@ import type {
|
|
|
34
36
|
ToolRequestUserInputResponse,
|
|
35
37
|
Thread,
|
|
36
38
|
UserInput,
|
|
39
|
+
CodexSkill,
|
|
37
40
|
} from "./codex-protocol.ts";
|
|
41
|
+
import { parseSkillList } from "./codex-skill-parser.ts";
|
|
38
42
|
|
|
39
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
|
+
}
|
|
40
79
|
const CLIENT_INFO = { name: "ppm", title: "PPM", version: "0.0.0" };
|
|
41
80
|
const CAPABILITIES = { experimentalApi: true, requestAttestation: false, optOutNotificationMethods: null };
|
|
42
81
|
const MODELS_CACHE_TTL = 5 * 60 * 1000;
|
|
82
|
+
const SKILLS_CACHE_TTL = 60 * 1000;
|
|
43
83
|
|
|
44
84
|
interface PendingApproval {
|
|
45
85
|
codexId: number | string;
|
|
@@ -165,6 +205,8 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
165
205
|
private sessions = new Map<string, Session>();
|
|
166
206
|
private live = new Map<string, LiveSession>();
|
|
167
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 }>();
|
|
168
210
|
|
|
169
211
|
private get config() {
|
|
170
212
|
try { return configService.get("ai").providers["codex"] ?? null; } catch { return null; }
|
|
@@ -208,10 +250,29 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
208
250
|
}
|
|
209
251
|
|
|
210
252
|
async listSessionsByDir(dir: string, opts?: { limit?: number; offset?: number }): Promise<SessionInfo[]> {
|
|
211
|
-
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
|
+
}
|
|
212
262
|
// Backfill provider ownership so reopening a pre-existing codex thread routes
|
|
213
263
|
// to codex (not the default provider) even after a restart.
|
|
214
|
-
|
|
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
|
+
}
|
|
215
276
|
return sessions;
|
|
216
277
|
}
|
|
217
278
|
|
|
@@ -301,13 +362,13 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
301
362
|
client.onClose(() => this.handleClose(live));
|
|
302
363
|
client.start({ cwd, codexHome: account?.home });
|
|
303
364
|
|
|
304
|
-
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
|
|
365
|
+
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
305
366
|
client.notify("initialized");
|
|
306
367
|
|
|
307
368
|
const resumeBase = { cwd, sandbox: permission.sandbox, approvalPolicy: permission.approvalPolicy, ...(model ? { model } : {}) };
|
|
308
369
|
// Only treat as a resume when a rollout for this id is attributable to THIS
|
|
309
370
|
// project (fail-closed cwd guard) — never resume another project's thread.
|
|
310
|
-
const isResume = !!findRolloutByThreadId(
|
|
371
|
+
const isResume = !!fromCodexSessionsDirs(sessionId, (d) => findRolloutByThreadId(d, sessionId, cwd));
|
|
311
372
|
const result = isResume
|
|
312
373
|
? await client.request("thread/resume", { threadId: sessionId, ...resumeBase })
|
|
313
374
|
: await client.request("thread/start", resumeBase);
|
|
@@ -331,7 +392,10 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
331
392
|
}
|
|
332
393
|
// Snapshot persisted history so live message ids continue the rollout-N
|
|
333
394
|
// numbering (empty for a brand-new thread; full prior transcript on resume).
|
|
334
|
-
live.history =
|
|
395
|
+
live.history = fromCodexSessionsDirs(threadId, (d) => {
|
|
396
|
+
const msgs = getRolloutMessages(d, threadId, cwd);
|
|
397
|
+
return msgs.length > 0 ? msgs : null;
|
|
398
|
+
}) ?? [];
|
|
335
399
|
return live;
|
|
336
400
|
}
|
|
337
401
|
|
|
@@ -366,7 +430,8 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
366
430
|
if (notif.method === "item/completed" && live.compactRequested
|
|
367
431
|
&& (notif.params as { item?: { type?: string } })?.item?.type === "contextCompaction") {
|
|
368
432
|
live.compactRequested = false;
|
|
369
|
-
const file =
|
|
433
|
+
const file = fromCodexSessionsDirs(live.threadId ?? undefined,
|
|
434
|
+
(d) => findRolloutByThreadId(d, live.threadId ?? "", live.cwd));
|
|
370
435
|
if (file) {
|
|
371
436
|
const content = `_Conversation compacted to save context._\n\nread the full transcript at: ${file}`;
|
|
372
437
|
live.channel.push({ type: "text", content });
|
|
@@ -473,7 +538,10 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
473
538
|
// Fail-closed: only return rollout messages attributable to this project's cwd.
|
|
474
539
|
const cwd = this.sessions.get(sessionId)?.projectPath || getSessionProjectPath(sessionId);
|
|
475
540
|
if (!cwd) return [];
|
|
476
|
-
return
|
|
541
|
+
return fromCodexSessionsDirs(sessionId, (d) => {
|
|
542
|
+
const msgs = getRolloutMessages(d, sessionId, cwd);
|
|
543
|
+
return msgs.length > 0 ? msgs : null;
|
|
544
|
+
}) ?? [];
|
|
477
545
|
}
|
|
478
546
|
|
|
479
547
|
/**
|
|
@@ -501,7 +569,7 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
501
569
|
try {
|
|
502
570
|
if (!reuse) {
|
|
503
571
|
client.start({ cwd });
|
|
504
|
-
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
|
|
572
|
+
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
505
573
|
client.notify("initialized");
|
|
506
574
|
}
|
|
507
575
|
const forkRes = await client.request<{ thread?: { id?: string; turns?: unknown[] } }>("thread/fork", { threadId: sessionId, cwd });
|
|
@@ -540,12 +608,12 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
540
608
|
const client = new CodexJsonRpcClient();
|
|
541
609
|
try {
|
|
542
610
|
client.start({ cwd: process.cwd() });
|
|
543
|
-
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
|
|
611
|
+
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
544
612
|
client.notify("initialized");
|
|
545
613
|
const all: unknown[] = [];
|
|
546
614
|
let cursor: string | null = null;
|
|
547
615
|
do {
|
|
548
|
-
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);
|
|
549
617
|
if (Array.isArray(res?.data)) all.push(...res.data);
|
|
550
618
|
cursor = res?.nextCursor ?? null;
|
|
551
619
|
} while (cursor);
|
|
@@ -559,8 +627,82 @@ export class CodexAppServerProvider implements AIProvider {
|
|
|
559
627
|
}
|
|
560
628
|
}
|
|
561
629
|
|
|
562
|
-
/**
|
|
563
|
-
|
|
564
|
-
|
|
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);
|
|
565
707
|
}
|
|
566
708
|
}
|