@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
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { ChatEvent } from "../provider.interface.ts";
|
|
2
|
+
import { redactTruncate } from "./codex-redact.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Rollout `item_completed` records → PPM chat events.
|
|
6
|
+
*
|
|
7
|
+
* Newer codex versions stopped writing `user_message` / `agent_message` events
|
|
8
|
+
* to the rollout and write one `item_completed` per finished item instead. The
|
|
9
|
+
* items are the same family the live app-server streams, but spelled
|
|
10
|
+
* differently: PascalCase types (`AgentMessage`, not `agentMessage`),
|
|
11
|
+
* snake_case fields (`aggregated_output`), a `command` array rather than a
|
|
12
|
+
* string, and image generation arriving as a generic `Extension` carrying a
|
|
13
|
+
* `kind`. Reading a rollout without this mapping yields nothing at all, which
|
|
14
|
+
* is why a codex conversation displayed while it was live and came back empty
|
|
15
|
+
* once it had to be read from disk.
|
|
16
|
+
*
|
|
17
|
+
* Kept separate from the rollout parser so the two spellings of the same item
|
|
18
|
+
* family do not interleave in one function.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
type Item = Record<string, unknown>;
|
|
22
|
+
|
|
23
|
+
/** What a rollout item contributes to the reconstructed transcript. */
|
|
24
|
+
export type RolloutItemMapping =
|
|
25
|
+
| { kind: "user"; text: string }
|
|
26
|
+
| { kind: "assistant"; text: string }
|
|
27
|
+
| { kind: "events"; events: ChatEvent[] }
|
|
28
|
+
| { kind: "ignore" };
|
|
29
|
+
|
|
30
|
+
const IGNORED_ITEM_TYPES = new Set([
|
|
31
|
+
// Reasoning is not persisted as a message anywhere else in PPM; showing it as
|
|
32
|
+
// one would put the model's private notes in the transcript.
|
|
33
|
+
"Reasoning",
|
|
34
|
+
// Injected instructions, not part of the conversation.
|
|
35
|
+
"DeveloperMessage",
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
function textFrom(content: unknown): string {
|
|
39
|
+
if (typeof content === "string") return content;
|
|
40
|
+
if (!Array.isArray(content)) return "";
|
|
41
|
+
return content
|
|
42
|
+
.map((c) => (c && typeof c === "object" && typeof (c as Item).text === "string" ? (c as Item).text as string : ""))
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.join("");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** `file:///C:/Users/...` → a path a person recognises. */
|
|
48
|
+
function plainCwd(cwd: unknown): string | undefined {
|
|
49
|
+
if (typeof cwd !== "string" || !cwd) return undefined;
|
|
50
|
+
if (!cwd.startsWith("file://")) return cwd;
|
|
51
|
+
try {
|
|
52
|
+
const path = decodeURIComponent(new URL(cwd).pathname);
|
|
53
|
+
// Windows paths come back as `/C:/…`.
|
|
54
|
+
return /^\/[A-Za-z]:/.test(path) ? path.slice(1) : path;
|
|
55
|
+
} catch {
|
|
56
|
+
return cwd;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The command text to show. `parsed_cmd[].cmd` is the unwrapped script; the raw
|
|
62
|
+
* `command` array is the interpreter plus its arguments, whose path arrives with
|
|
63
|
+
* doubled backslashes on Windows.
|
|
64
|
+
*/
|
|
65
|
+
function commandText(item: Item): string {
|
|
66
|
+
const parsed = Array.isArray(item.parsed_cmd) ? item.parsed_cmd : [];
|
|
67
|
+
const parts: string[] = [];
|
|
68
|
+
for (const entry of parsed) {
|
|
69
|
+
const cmd = (entry as Item)?.cmd;
|
|
70
|
+
if (typeof cmd === "string" && cmd.trim()) parts.push(cmd);
|
|
71
|
+
}
|
|
72
|
+
if (parts.length > 0) return parts.join("\n");
|
|
73
|
+
if (Array.isArray(item.command)) return item.command.filter((c) => typeof c === "string").join(" ");
|
|
74
|
+
return typeof item.command === "string" ? item.command : "";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function commandExecutionEvents(item: Item): ChatEvent[] {
|
|
78
|
+
const raw = Array.isArray(item.command) ? item.command.join(" ") : String(item.command ?? "");
|
|
79
|
+
const tool = /powershell|pwsh/i.test(raw) ? "PowerShell" : "Bash";
|
|
80
|
+
const toolUseId = typeof item.id === "string" ? item.id : undefined;
|
|
81
|
+
const exit = item.exit_code;
|
|
82
|
+
return [
|
|
83
|
+
{ type: "tool_use", tool, input: { command: commandText(item), cwd: plainCwd(item.cwd) }, toolUseId },
|
|
84
|
+
{
|
|
85
|
+
type: "tool_result",
|
|
86
|
+
output: redactTruncate(item.aggregated_output ?? item.stdout ?? ""),
|
|
87
|
+
isError: typeof exit === "number" && exit !== 0,
|
|
88
|
+
toolUseId,
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function imageGenerationEvents(item: Item): ChatEvent[] {
|
|
94
|
+
const toolUseId = typeof item.id === "string" ? item.id : undefined;
|
|
95
|
+
const failure = item.failure;
|
|
96
|
+
return [
|
|
97
|
+
{
|
|
98
|
+
// `file_path` matches what the chat's image preview already looks for, and
|
|
99
|
+
// `result` — the whole PNG as base64 — is deliberately dropped.
|
|
100
|
+
type: "tool_use",
|
|
101
|
+
tool: "ImageGen",
|
|
102
|
+
input: {
|
|
103
|
+
file_path: item.savedPath ?? null,
|
|
104
|
+
prompt: item.revisedPrompt ?? null,
|
|
105
|
+
transparentBackground: item.transparentBackground ?? false,
|
|
106
|
+
},
|
|
107
|
+
toolUseId,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: "tool_result",
|
|
111
|
+
output: failure != null ? redactTruncate(failure) : String(item.savedPath ?? "generated"),
|
|
112
|
+
isError: failure != null,
|
|
113
|
+
toolUseId,
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Everything the mapping does not know, shown rather than silently dropped. */
|
|
119
|
+
function genericEvents(item: Item): ChatEvent[] {
|
|
120
|
+
const toolUseId = typeof item.id === "string" ? item.id : undefined;
|
|
121
|
+
// A base64 payload would otherwise land in the transcript whole.
|
|
122
|
+
const { result: _result, ...rest } = item;
|
|
123
|
+
return [{ type: "tool_use", tool: String(item.type ?? "tool"), input: rest, toolUseId }];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function mapRolloutItem(item: unknown): RolloutItemMapping {
|
|
127
|
+
if (!item || typeof item !== "object") return { kind: "ignore" };
|
|
128
|
+
const it = item as Item;
|
|
129
|
+
const type = typeof it.type === "string" ? it.type : "";
|
|
130
|
+
|
|
131
|
+
if (IGNORED_ITEM_TYPES.has(type)) return { kind: "ignore" };
|
|
132
|
+
if (type === "UserMessage") {
|
|
133
|
+
const text = textFrom(it.content);
|
|
134
|
+
return text ? { kind: "user", text } : { kind: "ignore" };
|
|
135
|
+
}
|
|
136
|
+
if (type === "AgentMessage") {
|
|
137
|
+
const text = textFrom(it.content);
|
|
138
|
+
return text ? { kind: "assistant", text } : { kind: "ignore" };
|
|
139
|
+
}
|
|
140
|
+
if (type === "CommandExecution") return { kind: "events", events: commandExecutionEvents(it) };
|
|
141
|
+
if (type === "Extension") {
|
|
142
|
+
// `kind` names the extension; image generation is the one PPM renders specially.
|
|
143
|
+
if (String(it.kind ?? "").startsWith("image_gen")) {
|
|
144
|
+
return { kind: "events", events: imageGenerationEvents(it) };
|
|
145
|
+
}
|
|
146
|
+
return { kind: "events", events: genericEvents(it) };
|
|
147
|
+
}
|
|
148
|
+
return { kind: "events", events: genericEvents(it) };
|
|
149
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { CodexSkill, SkillListResponse } from "./codex-protocol.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure map of a `skills/list` response → the skills codex would actually run.
|
|
5
|
+
*
|
|
6
|
+
* The response groups skills by the cwd they were resolved for, because one
|
|
7
|
+
* app-server can hold several workspaces at once. PPM asks about a single cwd,
|
|
8
|
+
* so every group is flattened into one list.
|
|
9
|
+
*
|
|
10
|
+
* Disabled skills are dropped: codex will not run them, so offering them in the
|
|
11
|
+
* picker would produce a prompt that silently does nothing. Nameless entries
|
|
12
|
+
* are dropped for the same reason — the name is the only thing that invokes a
|
|
13
|
+
* skill.
|
|
14
|
+
*
|
|
15
|
+
* Duplicates are possible (a project-scope skill shadowing a user-scope one of
|
|
16
|
+
* the same name). First occurrence wins, matching the order codex returns.
|
|
17
|
+
*/
|
|
18
|
+
export function parseSkillList(res: unknown): CodexSkill[] {
|
|
19
|
+
const groups = (res as SkillListResponse | undefined)?.data;
|
|
20
|
+
if (!Array.isArray(groups)) return [];
|
|
21
|
+
const out: CodexSkill[] = [];
|
|
22
|
+
const seen = new Set<string>();
|
|
23
|
+
for (const group of groups) {
|
|
24
|
+
const skills = (group as { skills?: unknown })?.skills;
|
|
25
|
+
if (!Array.isArray(skills)) continue;
|
|
26
|
+
for (const raw of skills) {
|
|
27
|
+
if (!raw || typeof raw !== "object") continue;
|
|
28
|
+
const s = raw as Partial<CodexSkill>;
|
|
29
|
+
if (typeof s.name !== "string" || !s.name) continue;
|
|
30
|
+
if (s.enabled === false) continue;
|
|
31
|
+
if (seen.has(s.name)) continue;
|
|
32
|
+
seen.add(s.name);
|
|
33
|
+
out.push({
|
|
34
|
+
name: s.name,
|
|
35
|
+
description: typeof s.description === "string" ? s.description : undefined,
|
|
36
|
+
scope: typeof s.scope === "string" ? s.scope : undefined,
|
|
37
|
+
path: typeof s.path === "string" ? s.path : undefined,
|
|
38
|
+
// Disabled entries were skipped above, so anything reaching here is enabled.
|
|
39
|
+
enabled: true,
|
|
40
|
+
interface: parseInterface(s.interface),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The presentation block codex ships for its own skills — display name, one-line
|
|
49
|
+
* blurb, and icon files on disk. Every field is optional: a user-authored skill
|
|
50
|
+
* has no `interface` at all, so the caller must be able to fall back to `name`.
|
|
51
|
+
*/
|
|
52
|
+
function parseInterface(raw: unknown): CodexSkill["interface"] {
|
|
53
|
+
if (!raw || typeof raw !== "object") return undefined;
|
|
54
|
+
const i = raw as Record<string, unknown>;
|
|
55
|
+
const str = (v: unknown) => (typeof v === "string" && v ? v : undefined);
|
|
56
|
+
return {
|
|
57
|
+
displayName: str(i.displayName),
|
|
58
|
+
shortDescription: str(i.shortDescription),
|
|
59
|
+
iconSmall: str(i.iconSmall),
|
|
60
|
+
iconLarge: str(i.iconLarge),
|
|
61
|
+
defaultPrompt: str(i.defaultPrompt),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -1,37 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Codex quota reader: runs a short-lived app-server bound to a given CODEX_HOME
|
|
3
|
+
* and reads `account/rateLimits/read`.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately uncached and unguarded — one call, one answer, throws on failure.
|
|
6
|
+
* Caching, the background sweep, the timeout, and persistence belong to the
|
|
7
|
+
* shared provider-usage layer, which reaches this through `codex-usage-source`.
|
|
8
|
+
* It lives here rather than in the provider or the account service to avoid a
|
|
9
|
+
* provider↔account-service import cycle.
|
|
6
10
|
*/
|
|
7
11
|
import type { UsageInfo } from "../provider.interface.ts";
|
|
8
|
-
import { CodexJsonRpcClient } from "./codex-jsonrpc-client.ts";
|
|
12
|
+
import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS } from "./codex-jsonrpc-client.ts";
|
|
9
13
|
import { parseCodexUsage } from "./codex-usage-parser.ts";
|
|
10
14
|
import type { GetAccountRateLimitsResponse } from "./codex-protocol.ts";
|
|
11
15
|
|
|
12
16
|
const CLIENT_INFO = { name: "ppm", title: "PPM", version: "0.0.0" };
|
|
13
17
|
const CAPABILITIES = { experimentalApi: true, requestAttestation: false, optOutNotificationMethods: null };
|
|
14
|
-
const TTL = 60 * 1000;
|
|
15
|
-
|
|
16
|
-
const cache = new Map<string, { usage: UsageInfo; expiry: number }>();
|
|
17
|
-
|
|
18
|
-
export async function fetchCodexUsage(codexHome?: string): Promise<UsageInfo> {
|
|
19
|
-
const key = codexHome ?? "__default__";
|
|
20
|
-
const hit = cache.get(key);
|
|
21
|
-
if (hit && Date.now() < hit.expiry) return hit.usage;
|
|
22
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Read one codex login's quota, live.
|
|
21
|
+
*
|
|
22
|
+
* Throws on any failure — the caller distinguishes a failure from a login with
|
|
23
|
+
* nothing to report, and a swallowed error would be stored as the latter.
|
|
24
|
+
*/
|
|
25
|
+
export async function fetchCodexUsageLive(codexHome?: string): Promise<UsageInfo> {
|
|
23
26
|
const client = new CodexJsonRpcClient();
|
|
24
27
|
try {
|
|
25
28
|
client.start({ cwd: process.cwd(), codexHome });
|
|
26
|
-
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
|
|
29
|
+
await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
|
|
27
30
|
client.notify("initialized");
|
|
28
|
-
const res = await client.request<GetAccountRateLimitsResponse>("account/rateLimits/read", {});
|
|
29
|
-
|
|
30
|
-
cache.set(key, { usage, expiry: Date.now() + TTL });
|
|
31
|
-
return usage;
|
|
32
|
-
} catch {
|
|
33
|
-
return {};
|
|
31
|
+
const res = await client.request<GetAccountRateLimitsResponse>("account/rateLimits/read", {}, CONTROL_REQUEST_TIMEOUT_MS);
|
|
32
|
+
return parseCodexUsage(res);
|
|
34
33
|
} finally {
|
|
34
|
+
// Runs even when a request rejects on its own timeout, so a subprocess that
|
|
35
|
+
// accepted the spawn and then went silent is still killed rather than left
|
|
36
|
+
// behind. Before the client had a timeout, that was one orphan per attempt.
|
|
35
37
|
client.close();
|
|
36
38
|
}
|
|
37
39
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { UsageInfo } from "../../types/chat.ts";
|
|
2
|
+
import type { ProviderUsageSource } from "../../services/provider-usage/usage-source.ts";
|
|
3
|
+
import { AMBIENT_ACCOUNT_KEY } from "../../services/provider-usage/usage-source.ts";
|
|
4
|
+
import { listCodexAccounts, getCodexAccount } from "../../services/codex-account.service.ts";
|
|
5
|
+
import { fetchCodexUsageLive } from "./codex-usage-fetch.ts";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Codex's plug into the shared usage layer.
|
|
9
|
+
*
|
|
10
|
+
* All this has to say is which accounts exist and how to read one; the sweep,
|
|
11
|
+
* the timeout, the cache, and the snapshot persistence come from the layer.
|
|
12
|
+
* Before it existed, codex had a lazy 60-second memory cache and no sweep at
|
|
13
|
+
* all, so every read that missed spawned an app-server on the request path.
|
|
14
|
+
*/
|
|
15
|
+
export const codexUsageSource: ProviderUsageSource = {
|
|
16
|
+
providerId: "codex",
|
|
17
|
+
|
|
18
|
+
listAccountIds(): string[] {
|
|
19
|
+
return listCodexAccounts().map((a) => a.id);
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
async fetch(accountId: string): Promise<UsageInfo> {
|
|
23
|
+
// No managed accounts configured — read whatever login `~/.codex` holds.
|
|
24
|
+
if (accountId === AMBIENT_ACCOUNT_KEY) return fetchCodexUsageLive();
|
|
25
|
+
|
|
26
|
+
const account = getCodexAccount(accountId);
|
|
27
|
+
// The account was removed between the sweep listing it and this fetch.
|
|
28
|
+
// Throwing (rather than returning {}) keeps it out of the store: an empty
|
|
29
|
+
// object would be persisted as a real reading for an account that is gone.
|
|
30
|
+
if (!account) throw new Error(`codex account ${accountId} no longer exists`);
|
|
31
|
+
|
|
32
|
+
const usage = await fetchCodexUsageLive(account.home);
|
|
33
|
+
// The rate-limit payload carries the plan name, which the parser puts in
|
|
34
|
+
// activeAccountLabel; the account's own label is the truthful one.
|
|
35
|
+
return { ...usage, activeAccountId: account.id, activeAccountLabel: account.label };
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -8,8 +8,9 @@ import { draftService } from "../../services/draft.service.ts";
|
|
|
8
8
|
import { providerRegistry } from "../../providers/registry.ts";
|
|
9
9
|
import { renameSession as sdkRenameSession } from "@anthropic-ai/claude-agent-sdk";
|
|
10
10
|
import { listSlashItems, searchSlashItems, invalidateCache } from "../../services/slash-items.service.ts";
|
|
11
|
+
import type { SlashItem } from "../../services/slash-discovery/types.ts";
|
|
11
12
|
import { ensureSdkCommands, invalidateSdkCommands } from "../../services/slash-discovery/sdk-commands.ts";
|
|
12
|
-
import { upsertSlashRecent, getSlashRecents, setSessionClearedFrom, listTurnUsage, getSessionAccount } from "../../services/db.service.ts";
|
|
13
|
+
import { upsertSlashRecent, getSlashRecents, setSessionClearedFrom, listTurnUsage, getSessionAccount, getSessionProvider, resolveMigratedSession } from "../../services/db.service.ts";
|
|
13
14
|
import type { TurnUsage } from "../../shared/turn-usage.ts";
|
|
14
15
|
import { getCachedUsage, refreshUsageNow } from "../../services/claude-usage.service.ts";
|
|
15
16
|
import { getSessionLog } from "../../services/session-log.service.ts";
|
|
@@ -37,10 +38,14 @@ chatRoutes.get("/slash-items", async (c) => {
|
|
|
37
38
|
try {
|
|
38
39
|
const projectPath = c.get("projectPath");
|
|
39
40
|
const q = c.req.query("q");
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
const sessionId = c.req.query("sessionId") || undefined;
|
|
42
|
+
// A brand-new tab has no DB row yet, so the client's own view of which
|
|
43
|
+
// provider it is on wins; the stored value is the fallback for reloads.
|
|
44
|
+
const providerId = c.req.query("providerId")
|
|
45
|
+
|| (sessionId ? getSessionProvider(sessionId) : null)
|
|
46
|
+
|| undefined;
|
|
47
|
+
|
|
48
|
+
let items = await listSlashItemsForProvider(projectPath, providerId, sessionId);
|
|
44
49
|
const recentNames = getSlashRecents(projectPath);
|
|
45
50
|
if (q) items = searchSlashItems(items, q, 20, recentNames);
|
|
46
51
|
return c.json(ok({ items, recentNames }));
|
|
@@ -49,6 +54,41 @@ chatRoutes.get("/slash-items", async (c) => {
|
|
|
49
54
|
}
|
|
50
55
|
});
|
|
51
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Slash items a session can actually run.
|
|
59
|
+
*
|
|
60
|
+
* A provider that owns its own skill runtime answers for itself, and the
|
|
61
|
+
* disk-discovered Claude-side list is not merged in: a codex turn cannot
|
|
62
|
+
* execute a Claude skill, and a Claude turn cannot execute a codex one, so a
|
|
63
|
+
* combined list would offer entries that quietly do nothing when picked.
|
|
64
|
+
*
|
|
65
|
+
* PPM's host-level built-ins ARE kept, because they are intercepted before any
|
|
66
|
+
* provider runs and therefore work in every tab. Dropping them would have cost
|
|
67
|
+
* a codex tab `/clear`, `/skills`, and `/version` — commands that do work —
|
|
68
|
+
* which is a different thing from hiding ones that don't.
|
|
69
|
+
*
|
|
70
|
+
* When such a provider reports no skills — app-server failed to spawn, account
|
|
71
|
+
* not logged in — only the built-ins remain, rather than falling back to the
|
|
72
|
+
* Claude list; showing runnable-looking Claude entries in a codex tab is the
|
|
73
|
+
* very confusion this split exists to remove.
|
|
74
|
+
*/
|
|
75
|
+
async function listSlashItemsForProvider(
|
|
76
|
+
projectPath: string,
|
|
77
|
+
providerId: string | undefined,
|
|
78
|
+
sessionId: string | undefined,
|
|
79
|
+
): Promise<SlashItem[]> {
|
|
80
|
+
const provider = providerId ? providerRegistry.get(providerId) : null;
|
|
81
|
+
if (provider?.listSkills) {
|
|
82
|
+
const { codexSkillsToSlashItems } = await import("../../services/slash-discovery/codex-skill-items.ts");
|
|
83
|
+
const { getHostBuiltinSlashItems } = await import("../../services/slash-discovery/builtin-commands.ts");
|
|
84
|
+
return [...codexSkillsToSlashItems(await provider.listSkills(sessionId)), ...getHostBuiltinSlashItems()];
|
|
85
|
+
}
|
|
86
|
+
// Claude's own built-ins need a live SDK session to enumerate; cached 30 min,
|
|
87
|
+
// so only the first request per project pays for the CLI spawn.
|
|
88
|
+
await ensureSdkCommands(projectPath);
|
|
89
|
+
return listSlashItems(projectPath);
|
|
90
|
+
}
|
|
91
|
+
|
|
52
92
|
/** DELETE /chat/slash-items/cache — invalidate cached slash items for this project */
|
|
53
93
|
chatRoutes.delete("/slash-items/cache", (c) => {
|
|
54
94
|
try {
|
|
@@ -78,9 +118,16 @@ chatRoutes.get("/usage", async (c) => {
|
|
|
78
118
|
// Non-Claude providers expose their own quota via provider.getUsage().
|
|
79
119
|
const providerId = c.req.query("providerId");
|
|
80
120
|
if (providerId && providerId !== "claude") {
|
|
81
|
-
const provider = providerRegistry.get(providerId)
|
|
121
|
+
const provider = providerRegistry.get(providerId);
|
|
82
122
|
if (provider?.getUsage) {
|
|
83
|
-
|
|
123
|
+
// `?refresh=1` is the user pressing refresh, so drop the cached value
|
|
124
|
+
// first — otherwise getUsage answers from cache and the button does
|
|
125
|
+
// nothing visible. Claude's branch below does the same via a sweep.
|
|
126
|
+
if (c.req.query("refresh")) {
|
|
127
|
+
const { invalidateUsage } = await import("../../services/provider-usage/usage-registry.ts");
|
|
128
|
+
invalidateUsage(providerId);
|
|
129
|
+
}
|
|
130
|
+
try { return c.json(ok(await provider.getUsage(c.req.query("session")))); } catch { return c.json(ok({})); }
|
|
84
131
|
}
|
|
85
132
|
return c.json(ok({}));
|
|
86
133
|
}
|
|
@@ -270,7 +317,11 @@ chatRoutes.get("/search", async (c) => {
|
|
|
270
317
|
/** GET /chat/sessions/:id/messages — get message history */
|
|
271
318
|
chatRoutes.get("/sessions/:id/messages", async (c) => {
|
|
272
319
|
try {
|
|
273
|
-
const
|
|
320
|
+
const requestedId = c.req.param("id");
|
|
321
|
+
// A provider that mints its own session id leaves the id PPM created behind,
|
|
322
|
+
// owning no transcript. Follow the recorded move so a tab that still holds
|
|
323
|
+
// the old id reads the conversation instead of an empty list.
|
|
324
|
+
const id = resolveMigratedSession(requestedId);
|
|
274
325
|
const providerId = c.req.query("providerId") ?? "claude";
|
|
275
326
|
const messages = await chatService.getMessages(providerId, id);
|
|
276
327
|
// Forking re-timestamps the copied prefix (both the Claude SDK and codex
|
|
@@ -289,7 +340,14 @@ chatRoutes.get("/sessions/:id/messages", async (c) => {
|
|
|
289
340
|
}
|
|
290
341
|
// versionMap ships with the history so the `‹ n/m ›` switcher needs no
|
|
291
342
|
// per-message request. Ordinals absent from the map have no edited versions.
|
|
292
|
-
|
|
343
|
+
// Hand back the id that actually owns this transcript so the client can
|
|
344
|
+
// adopt it — otherwise every future read, and the next turn, still targets
|
|
345
|
+
// the abandoned one.
|
|
346
|
+
return c.json(ok({
|
|
347
|
+
messages,
|
|
348
|
+
versionMap: resolveVersionMap(id),
|
|
349
|
+
...(id !== requestedId ? { canonicalSessionId: id } : {}),
|
|
350
|
+
}));
|
|
293
351
|
} catch (e) {
|
|
294
352
|
return c.json(err((e as Error).message), 500);
|
|
295
353
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import { ok, err } from "../../types/api.ts";
|
|
3
3
|
import { listCodexAccounts, removeCodexAccount, getAllCodexUsages, getCodexStrategy, setCodexStrategy, type CodexStrategy } from "../../services/codex-account.service.ts";
|
|
4
|
-
import { addApiKeyAccount, startDeviceLogin,
|
|
4
|
+
import { addApiKeyAccount, startDeviceLogin, getDeviceLoginStatus, cancelDeviceLogin } from "../../services/codex-account-login.ts";
|
|
5
5
|
import { exportCodexEncrypted, importCodexEncrypted } from "../../services/codex-account-portability.ts";
|
|
6
6
|
|
|
7
7
|
/** Codex multi-account management. Mounted under /api/codex-accounts (auth-guarded). */
|
|
@@ -36,10 +36,14 @@ codexAccountsRoutes.post("/device-login", async (c) => {
|
|
|
36
36
|
catch (e) { return c.json(err((e as Error).message), 400); }
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
/** Poll a device login. Answers immediately: holding the connection open for the
|
|
40
|
+
* whole authorization made a dropped socket look like a failed login. */
|
|
41
|
+
codexAccountsRoutes.get("/device-login/:id/status", (c) => c.json(ok(getDeviceLoginStatus(c.req.param("id")))));
|
|
42
|
+
|
|
43
|
+
/** Abandon a device login the user closed out of. */
|
|
44
|
+
codexAccountsRoutes.delete("/device-login/:id", (c) => {
|
|
45
|
+
cancelDeviceLogin(c.req.param("id"));
|
|
46
|
+
return c.json(ok({ cancelled: true }));
|
|
43
47
|
});
|
|
44
48
|
|
|
45
49
|
/** Download a password-encrypted backup of codex accounts (auth.json + apiKey creds). */
|
package/src/server/ws/chat.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { providerRegistry } from "../../providers/registry.ts";
|
|
|
3
3
|
import { resolveProjectPath } from "../helpers/resolve-project.ts";
|
|
4
4
|
import { logSessionEvent } from "../../services/session-log.service.ts";
|
|
5
5
|
import { listSessions as sdkListSessions } from "@anthropic-ai/claude-agent-sdk";
|
|
6
|
-
import { getSessionTitle, incrementSessionUnread, clearSessionUnread, getSessionModel, setSessionModel, getSessionProvider, getSessionEffort, setSessionEffort, getSessionThinking, setSessionThinking } from "../../services/db.service.ts";
|
|
6
|
+
import { getSessionTitle, incrementSessionUnread, clearSessionUnread, getSessionModel, setSessionModel, getSessionProvider, getSessionEffort, setSessionEffort, getSessionThinking, setSessionThinking, setSessionMigratedTo } from "../../services/db.service.ts";
|
|
7
7
|
import { VALID_EFFORT_VALUES, THINKING_ADAPTIVE, isThinkingEnabled } from "../../providers/claude-agent-sdk-query-options.ts";
|
|
8
8
|
import type { ChatWsClientMessage, SessionPhase } from "../../types/api.ts";
|
|
9
9
|
// File watching and app-wide broadcasts are owned by the global WS (`./global.ts`)
|
|
@@ -397,6 +397,40 @@ async function detectImplicitTeam(sessionId: string): Promise<void> {
|
|
|
397
397
|
}
|
|
398
398
|
|
|
399
399
|
/** Transition session phase — guards same-phase, broadcasts phase_changed */
|
|
400
|
+
/**
|
|
401
|
+
* Rewrite a typed `/skill` to the sigil the session's provider recognises, in
|
|
402
|
+
* place on the parsed message.
|
|
403
|
+
*
|
|
404
|
+
* Only providers that own a skill runtime (`listSkills`) are affected, so a
|
|
405
|
+
* Claude session is left alone entirely. PPM's own built-ins are checked first
|
|
406
|
+
* and never rewritten: `/clear` and `/version` are handled by PPM regardless of
|
|
407
|
+
* which provider the tab is on, and must keep their slash to be intercepted.
|
|
408
|
+
*/
|
|
409
|
+
async function rewriteProviderSkillSigil(
|
|
410
|
+
parsed: { content: string },
|
|
411
|
+
providerId: string,
|
|
412
|
+
sessionId: string,
|
|
413
|
+
): Promise<void> {
|
|
414
|
+
const content = parsed.content.trimStart();
|
|
415
|
+
if (!content.startsWith("/")) return;
|
|
416
|
+
const provider = providerRegistry.get(providerId);
|
|
417
|
+
if (!provider?.listSkills) return;
|
|
418
|
+
|
|
419
|
+
const { isPpmHandled } = await import("../../services/slash-discovery/index.ts");
|
|
420
|
+
const name = content.match(/^\/(\S+)/)?.[1];
|
|
421
|
+
if (!name || isPpmHandled(name)) return;
|
|
422
|
+
|
|
423
|
+
try {
|
|
424
|
+
const { applySkillSigil } = await import("../../services/slash-discovery/provider-skill-sigil.ts");
|
|
425
|
+
const skills = await provider.listSkills(sessionId);
|
|
426
|
+
const rewritten = applySkillSigil(content, new Set(skills.map((s) => s.name)), "$");
|
|
427
|
+
if (rewritten !== content) parsed.content = rewritten;
|
|
428
|
+
} catch {
|
|
429
|
+
// Listing failed (app-server down, account not logged in). Send what the
|
|
430
|
+
// user typed rather than dropping their message.
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
400
434
|
function setPhase(sessionId: string, phase: SessionPhase, elapsed?: number): void {
|
|
401
435
|
const entry = activeSessions.get(sessionId);
|
|
402
436
|
if (!entry || entry.phase === phase) return;
|
|
@@ -802,6 +836,10 @@ async function startSessionConsumer(sessionId: string, providerId: string, conte
|
|
|
802
836
|
const newId = ev.newSessionId as string;
|
|
803
837
|
if (newId && newId !== sessionId) {
|
|
804
838
|
console.log(`[chat] session_migrated: ${sessionId} → ${newId}`);
|
|
839
|
+
// Persist the link before re-keying. A tab that opened under the old
|
|
840
|
+
// id keeps it in its own storage, so without this the conversation
|
|
841
|
+
// becomes unreachable from that tab the moment the turn ends.
|
|
842
|
+
setSessionMigratedTo(sessionId, newId);
|
|
805
843
|
// Stop spies tagged with old session ID before re-keying
|
|
806
844
|
bashOutputSpy.stopAllForSession(sessionId);
|
|
807
845
|
nestedSubagentSpy.stopAllForSession(sessionId);
|
|
@@ -1138,6 +1176,13 @@ export const chatWebSocket = {
|
|
|
1138
1176
|
if (canonical !== typedContent) parsed.content = canonical;
|
|
1139
1177
|
}
|
|
1140
1178
|
|
|
1179
|
+
// Providers with their own skill runtime may not use a leading slash.
|
|
1180
|
+
// Codex resolves a skill from a `$name` mention in the prompt; sent as
|
|
1181
|
+
// `/imagegen` it is inert prose, so the picked skill would silently not
|
|
1182
|
+
// run. Rewritten before the echo for the same reason as the alias above:
|
|
1183
|
+
// other devices and the stored transcript must show what actually ran.
|
|
1184
|
+
await rewriteProviderSkillSigil(parsed, providerId, sessionId);
|
|
1185
|
+
|
|
1141
1186
|
// Echo the user message to OTHER connected clients (second device/tab).
|
|
1142
1187
|
// The sender renders it optimistically; without this echo a live-connected
|
|
1143
1188
|
// second device only sees the assistant stream for this turn.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { UsageInfo } from "../types/chat.ts";
|
|
2
|
+
import type { ProviderUsageSource } from "./provider-usage/usage-source.ts";
|
|
3
|
+
import { AMBIENT_ACCOUNT_KEY } from "./provider-usage/usage-source.ts";
|
|
4
|
+
import { accountService } from "./account.service.ts";
|
|
5
|
+
import {
|
|
6
|
+
fetchClaudeAccountUsage,
|
|
7
|
+
fetchLegacyClaudeUsage,
|
|
8
|
+
shouldSkipClaudeAccount,
|
|
9
|
+
} from "./claude-usage.service.ts";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Claude's plug into the shared usage layer.
|
|
13
|
+
*
|
|
14
|
+
* Everything Claude-specific stays in `claude-usage.service`: OAuth token
|
|
15
|
+
* refresh, the post-429 cooldown, the Keychain fallback for installs that never
|
|
16
|
+
* added an account. What this adapter removes is the second copy of the generic
|
|
17
|
+
* machinery — Claude used to own its own poll timer, stagger, in-flight dedup,
|
|
18
|
+
* and persistence, all of which now come from the layer and are shared with
|
|
19
|
+
* codex.
|
|
20
|
+
*/
|
|
21
|
+
export const claudeUsageSource: ProviderUsageSource = {
|
|
22
|
+
providerId: "claude",
|
|
23
|
+
|
|
24
|
+
listAccountIds(): string[] {
|
|
25
|
+
// Empty means no account store, and the layer falls back to the ambient
|
|
26
|
+
// login — which is exactly the legacy single-login install.
|
|
27
|
+
return accountService.list().map((a) => a.id);
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
shouldSkip(accountId: string): Promise<boolean> {
|
|
31
|
+
// The ambient login has no account row to consult, so nothing to skip on.
|
|
32
|
+
if (accountId === AMBIENT_ACCOUNT_KEY) return Promise.resolve(false);
|
|
33
|
+
return shouldSkipClaudeAccount(accountId);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
async fetch(accountId: string): Promise<UsageInfo> {
|
|
37
|
+
if (accountId === AMBIENT_ACCOUNT_KEY) return fetchLegacyClaudeUsage();
|
|
38
|
+
return fetchClaudeAccountUsage(accountId);
|
|
39
|
+
},
|
|
40
|
+
};
|