@hienlh/ppm 0.19.2 → 0.19.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (617) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/CLAUDE.md +1 -0
  3. package/assets/skills/ppm/SKILL.md +1 -1
  4. package/assets/skills/ppm/references/cli-reference.md +4 -4
  5. package/assets/skills/ppm/references/http-api.md +3 -2
  6. package/dist/web/assets/accounts-settings-section-LtSVxNNp.js +1 -0
  7. package/dist/web/assets/ai-resource-editor-BqFT1EUB.js +1 -0
  8. package/dist/web/assets/ai-settings-section-CY6spbEx.js +1 -0
  9. package/dist/web/assets/ai-settings-section-Po3K8j-g.js +1 -0
  10. package/dist/web/assets/{angular-html-BlcrLjUx.js → angular-html-BuHNQIbQ.js} +1 -1
  11. package/dist/web/assets/{angular-ts-BUjtceAJ.js → angular-ts-DHRWoLc-.js} +1 -1
  12. package/dist/web/assets/api-client-BogqsFna.js +1 -0
  13. package/dist/web/assets/api-settings-CTMdz_VF.js +1 -0
  14. package/dist/web/assets/{api-themes-YsZgf6Xj.js → api-themes-Cknp3Q-P.js} +1 -1
  15. package/dist/web/assets/{apl-B3g0v1pk.js → apl-C1VSWVei.js} +1 -1
  16. package/dist/web/assets/appearance-settings-section-L9Z-nej_.js +1 -0
  17. package/dist/web/assets/architecture-PBZL5I3N-Ca5IpdzP.js +1 -0
  18. package/dist/web/assets/arrow-left-CyFcsyzD.js +1 -0
  19. package/dist/web/assets/{astro-FRnyn7cH.js → astro-RX-rChsZ.js} +1 -1
  20. package/dist/web/assets/{audio-preview-DWTRm4HC.js → audio-preview-CCd1jdje.js} +1 -1
  21. package/dist/web/assets/{blade-NLdOqUKw.js → blade-CZ6bxMbK.js} +1 -1
  22. package/dist/web/assets/{pencil-BlIIg6RH.js → brain-KDa9jFRq.js} +1 -1
  23. package/dist/web/assets/{bsl-CenHZfaU.js → bsl-BhgCXLWk.js} +1 -1
  24. package/dist/web/assets/{button-Cq8yixjf.js → button-BZtEJcUv.js} +1 -1
  25. package/dist/web/assets/{cairo-B_WR0aiQ.js → cairo-BrwygPkn.js} +1 -1
  26. package/dist/web/assets/calendar-clock-C1asT-gk.js +1 -0
  27. package/dist/web/assets/chat-tab-BIO-VhWT.js +15 -0
  28. package/dist/web/assets/check-DN75Ucvz.js +1 -0
  29. package/dist/web/assets/chevron-up-8PbsNiJp.js +1 -0
  30. package/dist/web/assets/{cobol-DOynhWYj.js → cobol-C5TGW1Ir.js} +1 -1
  31. package/dist/web/assets/code-editor-B9lVjElM.js +7 -0
  32. package/dist/web/assets/{coffee-Bn6dbw4P.js → coffee-CFgKlmgI.js} +1 -1
  33. package/dist/web/assets/{conflict-editor-Cgb-z12D.js → conflict-editor-BoRPwL3L.js} +1 -1
  34. package/dist/web/assets/context-menu-C13b1uT3.js +1 -0
  35. package/dist/web/assets/{cpp-CoZR9t8r.js → cpp-BhG5q3-d.js} +1 -1
  36. package/dist/web/assets/{crystal-BSheONSg.js → crystal-DvuI7_tY.js} +1 -1
  37. package/dist/web/assets/{csv-preview-BZMHfFH3.js → csv-preview-BpoJqZQi.js} +1 -1
  38. package/dist/web/assets/{data-grid-overlay-editor-gwPoVSCU.js → data-grid-overlay-editor-DP1xkog4.js} +1 -1
  39. package/dist/web/assets/database-viewer-I-9cER1L.js +1 -0
  40. package/dist/web/assets/diff-viewer-_xHZsxvr.js +4 -0
  41. package/dist/web/assets/{docx-preview-DqVDOMmv.js → docx-preview-CWIDVNZn.js} +1 -1
  42. package/dist/web/assets/{edge-DTtoslQu.js → edge-BSIEsmlI.js} +1 -1
  43. package/dist/web/assets/{edit-diff-preview-CXSbSUBX.js → edit-diff-preview-DeHb85DN.js} +1 -1
  44. package/dist/web/assets/{elixir-CIBCZ3Zi.js → elixir-BF-lrGXM.js} +1 -1
  45. package/dist/web/assets/{elm-BLmb7K1H.js → elm-8mCsJOeN.js} +1 -1
  46. package/dist/web/assets/{erb-BBY8ApRd.js → erb-Dw5PUVKa.js} +1 -1
  47. package/dist/web/assets/{erlang-D5Zb5_P0.js → erlang-BvjBIA6O.js} +1 -1
  48. package/dist/web/assets/{esm-6F8v1jLL.js → esm-Bt9OwSnU.js} +1 -1
  49. package/dist/web/assets/explorer-body-DapwsOnp.js +2 -0
  50. package/dist/web/assets/explorer-window-content-DD6Z15pm.js +1 -0
  51. package/dist/web/assets/extension-manager-section-Cu9D9Udt.js +1 -0
  52. package/dist/web/assets/{extension-webview-BSh6KGd7.js → extension-webview-Diz2OzVq.js} +1 -1
  53. package/dist/web/assets/{plus-BR0qewJI.js → eye-gWwaF4Lg.js} +1 -1
  54. package/dist/web/assets/eye-off-GjXVuAOn.js +1 -0
  55. package/dist/web/assets/files-settings-section-B1e7BgKQ.js +1 -0
  56. package/dist/web/assets/flask-conical-tp8gyZGh.js +1 -0
  57. package/dist/web/assets/{fortran-fixed-form-CBdwkEUJ.js → fortran-fixed-form-CRjUJe9K.js} +1 -1
  58. package/dist/web/assets/{fsharp-AT4XdVYH.js → fsharp-CjUIHIHp.js} +1 -1
  59. package/dist/web/assets/{gdresource-D852fWBR.js → gdresource-x_NUQFrZ.js} +1 -1
  60. package/dist/web/assets/general-settings-section-DWdHHRDy.js +1 -0
  61. package/dist/web/assets/{git-commit-DWfWAyxy.js → git-commit-BOpxSbns.js} +1 -1
  62. package/dist/web/assets/git-log-panel-CMMsvU64.js +1 -0
  63. package/dist/web/assets/{git-rebase-C6opk8gr.js → git-rebase-BW4xlK7k.js} +1 -1
  64. package/dist/web/assets/gitGraph-HDMCJU4V-BloZfB0Q.js +1 -0
  65. package/dist/web/assets/{glide-data-grid-CICFjJon.js → glide-data-grid-pKQuyYFj.js} +8 -8
  66. package/dist/web/assets/{glimmer-js-DLi5mWYO.js → glimmer-js-CT9jrmFj.js} +1 -1
  67. package/dist/web/assets/{glimmer-ts-D-scFX30.js → glimmer-ts-CjQT1lxK.js} +1 -1
  68. package/dist/web/assets/{glsl-dbQzF4iA.js → glsl-DsFJvtg5.js} +1 -1
  69. package/dist/web/assets/{graphql-D1m5Wen2.js → graphql-Dhlnmkn_.js} +1 -1
  70. package/dist/web/assets/group-chat-tab-U5u0Loii.js +1 -0
  71. package/dist/web/assets/{hack-CqYmpO7u.js → hack-BKHbsJ7u.js} +1 -1
  72. package/dist/web/assets/{haml-BXzKWEag.js → haml-C1Ih25Y2.js} +1 -1
  73. package/dist/web/assets/{handlebars-DXnrtHtq.js → handlebars-CaFitvmC.js} +1 -1
  74. package/dist/web/assets/{html-DhgQJ-xL.js → html-BwpKIE6V.js} +1 -1
  75. package/dist/web/assets/{html-derivative-xZRft-YE.js → html-derivative-uuTEquZU.js} +1 -1
  76. package/dist/web/assets/{http-B53mSj14.js → http-Cv4Pg5cR.js} +1 -1
  77. package/dist/web/assets/{hurl-CsomVy04.js → hurl-DubkI6TG.js} +1 -1
  78. package/dist/web/assets/{hxml-LffjWwKA.js → hxml-B9OVZFAB.js} +1 -1
  79. package/dist/web/assets/{image-preview-CNA6XMNS.js → image-preview-DRbZ0FA2.js} +1 -1
  80. package/dist/web/assets/index--KWVW-Ga.js +52 -0
  81. package/dist/web/assets/index-CvGx7wBQ.css +2 -0
  82. package/dist/web/assets/info-3K5VOQVL-c0W8wp5o.js +1 -0
  83. package/dist/web/assets/{jinja-CCHURl7V.js → jinja-BHb1jyl6.js} +1 -1
  84. package/dist/web/assets/jira-watcher-section-uA5oyB8s.js +1 -0
  85. package/dist/web/assets/{jison-7qBd8dnR.js → jison-CtpfXDzp.js} +1 -1
  86. package/dist/web/assets/{julia-BY9pnTcy.js → julia-TYjgpazU.js} +1 -1
  87. package/dist/web/assets/{just-D7wRSNRr.js → just-D27bzZuW.js} +1 -1
  88. package/dist/web/assets/key-round-CQpDrDxg.js +1 -0
  89. package/dist/web/assets/keybindings-store-Ccf0etMJ.js +1 -0
  90. package/dist/web/assets/keyboard-shortcuts-section-B7IxJHiI.js +1 -0
  91. package/dist/web/assets/{latex-RgsCae55.js → latex-D_MzopTn.js} +1 -1
  92. package/dist/web/assets/{liquid-CnDFzvOZ.js → liquid-BG_FG0Pe.js} +1 -1
  93. package/dist/web/assets/{lua-0lj5W8sm.js → lua-Bl29oC2L.js} +1 -1
  94. package/dist/web/assets/markdown-renderer-CY1epGRc.js +1 -0
  95. package/dist/web/assets/{markdown-renderer-dbLIvU2M.js → markdown-renderer-DDcIGQEd.js} +3 -3
  96. package/dist/web/assets/{marko-CQgqAhbV.js → marko-D-HI7dbm.js} +1 -1
  97. package/dist/web/assets/{mdc-BkIcTiIy.js → mdc-y444JQTQ.js} +1 -1
  98. package/dist/web/assets/{media-url-DDciwvLU.js → media-url-VzecHk9g.js} +1 -1
  99. package/dist/web/assets/{mobile-bottom-sheet-pjcHKorA.js → mobile-bottom-sheet-BD5b7KJF.js} +1 -1
  100. package/dist/web/assets/mobile-explorer-sheet-CqkwbCRl.js +1 -0
  101. package/dist/web/assets/{nextflow-DvIW68DS.js → nextflow-C5sKcldC.js} +1 -1
  102. package/dist/web/assets/{nginx-O-hft0gG.js → nginx-bXnEC3wm.js} +1 -1
  103. package/dist/web/assets/{nim-BxrR4HwQ.js → nim-pevhf4WD.js} +1 -1
  104. package/dist/web/assets/notification-store-BNSYk3E7.js +1 -0
  105. package/dist/web/assets/notifications-settings-section-v_628h4B.js +1 -0
  106. package/dist/web/assets/{number-overlay-editor-BoLRYuZT.js → number-overlay-editor-B7WINIW4.js} +1 -1
  107. package/dist/web/assets/{overview-panel-l3g1gT5e.js → overview-panel-mhN0qw6Q.js} +1 -1
  108. package/dist/web/assets/packet-RMMSAZCW-D_BoHr_M.js +1 -0
  109. package/dist/web/assets/panel-store-BRrnDO_i.js +1 -0
  110. package/dist/web/assets/pdf-preview-CI3q1MnH.js +1 -0
  111. package/dist/web/assets/{perl-Da-uNqmL.js → perl-B1KUtMnW.js} +1 -1
  112. package/dist/web/assets/{php-JMu45mEx.js → php-BGmVZBAJ.js} +1 -1
  113. package/dist/web/assets/pie-UPGHQEXC-BaLfuEf8.js +1 -0
  114. package/dist/web/assets/{postgres-viewer-DstZwUai.js → postgres-viewer-jaR0FYJ_.js} +3 -3
  115. package/dist/web/assets/power-CriQkeK5.js +1 -0
  116. package/dist/web/assets/ppmbot-settings-section-BET4VmKb.js +1 -0
  117. package/dist/web/assets/{process-table-kmQ2-8qJ.js → process-table-D1r-Gupi.js} +1 -1
  118. package/dist/web/assets/{project-store-DTUCS65m.js → project-store-BuY7rxn_.js} +1 -1
  119. package/dist/web/assets/proxy-settings-section-0DvNh1B-.js +3 -0
  120. package/dist/web/assets/{pug-CLzyQhia.js → pug-BfN8CpEH.js} +1 -1
  121. package/dist/web/assets/{qml-BHXfGB1l.js → qml-D6fRdLZt.js} +1 -1
  122. package/dist/web/assets/query-audit-section-BA5rT6Sh.js +1 -0
  123. package/dist/web/assets/radar-KQ55EAFF-DBIZEaIU.js +1 -0
  124. package/dist/web/assets/{razor-BqetJLN3.js → razor-fg-9AScR.js} +1 -1
  125. package/dist/web/assets/remote-desktop-mobile-sheet-CPa3XElX.js +2 -0
  126. package/dist/web/assets/remote-desktop-mobile-view-De_a4skd.js +1 -0
  127. package/dist/web/assets/remote-desktop-readiness-gate-CPrDIv2d.js +1 -0
  128. package/dist/web/assets/remote-desktop-window-content-CG1StfCE.js +1 -0
  129. package/dist/web/assets/{rst-iQdJZ0BP.js → rst-BZgx076b.js} +1 -1
  130. package/dist/web/assets/{ruby-CNwzZGdH.js → ruby-iUkWDcLo.js} +1 -1
  131. package/dist/web/assets/{run-in-terminal-CBXmVGWa.js → run-in-terminal-bKRwuO2z.js} +1 -1
  132. package/dist/web/assets/{sas-BpBIT2eR.js → sas-CLXO0lZ6.js} +1 -1
  133. package/dist/web/assets/schedules-settings-section-B2f7V7Xr.js +1 -0
  134. package/dist/web/assets/{scss-D1MotuEp.js → scss-DQqteGaG.js} +1 -1
  135. package/dist/web/assets/send-Bb0jtcR6.js +1 -0
  136. package/dist/web/assets/{send-to-chat-DJAdlvJ8.js → send-to-chat-S8LCNX7V.js} +1 -1
  137. package/dist/web/assets/separator-DqGg3f9c.js +1 -0
  138. package/dist/web/assets/settings-body-omv04jbb.js +2 -0
  139. package/dist/web/assets/settings-store-Brjd0QnO.js +2 -0
  140. package/dist/web/assets/settings-tab-NdnBTqyj.js +1 -0
  141. package/dist/web/assets/settings-window-content-Chou1JGa.js +1 -0
  142. package/dist/web/assets/{shaderlab-BNqmcPQi.js → shaderlab-CeMTqagR.js} +1 -1
  143. package/dist/web/assets/{shellsession-BBLOVOO-.js → shellsession-BAkquZAV.js} +1 -1
  144. package/dist/web/assets/{soy-BpTGo9uy.js → soy-Bxm9Ez55.js} +1 -1
  145. package/dist/web/assets/{sparql-D7A3yKob.js → sparql-C1phwdLc.js} +1 -1
  146. package/dist/web/assets/sql-query-editor-Dk9y3jqy.js +1 -0
  147. package/dist/web/assets/sqlite-viewer-4xFhkLYy.js +1 -0
  148. package/dist/web/assets/{stata-B7N56ptS.js → stata-DGNMQdEb.js} +1 -1
  149. package/dist/web/assets/{surrealql-CTmnD-lv.js → surrealql-ByVrV320.js} +1 -1
  150. package/dist/web/assets/{svelte-BppwY9TR.js → svelte-CNWjIMhl.js} +1 -1
  151. package/dist/web/assets/system-monitor-body-B_1iMVOI.js +2 -0
  152. package/dist/web/assets/system-monitor-tab-B2j9mWBW.js +1 -0
  153. package/dist/web/assets/{system-monitor-window-content-B9Y98UW6.js → system-monitor-window-content-BOjq53uU.js} +1 -1
  154. package/dist/web/assets/{tab-host-window-content-C1j8zr68.js → tab-host-window-content-CW_dlYlW.js} +1 -1
  155. package/dist/web/assets/{tab-store-DzYSsw5a.js → tab-store-PZsP5ZwG.js} +1 -1
  156. package/dist/web/assets/team-member-sheet-CkR4qO7V.js +2 -0
  157. package/dist/web/assets/team-member-window-content-CmF5ia3n.js +1 -0
  158. package/dist/web/assets/{templ-CvTMKKra.js → templ-Cf0gQL4I.js} +1 -1
  159. package/dist/web/assets/{terminal-tab-B9I_HlES.js → terminal-tab-HXZkicIc.js} +3 -3
  160. package/dist/web/assets/{tex--c4POEUE.js → tex-BTIqPw_R.js} +1 -1
  161. package/dist/web/assets/tool-cards-jA1BTLZj.js +9 -0
  162. package/dist/web/assets/treemap-KZPCXAKY-DFiG9UYW.js +1 -0
  163. package/dist/web/assets/{ts-tags--kx7D-Hw.js → ts-tags-B8dN_Yf6.js} +1 -1
  164. package/dist/web/assets/{twig-UG9uMHGd.js → twig-BgemonbJ.js} +1 -1
  165. package/dist/web/assets/use-accounts-data-BI_5qNvr.js +1 -0
  166. package/dist/web/assets/{use-blob-url-Bdxopwwc.js → use-blob-url-Gfi69PtP.js} +1 -1
  167. package/dist/web/assets/use-monaco-theme-BcQqKVbE.js +1 -0
  168. package/dist/web/assets/{use-open-team-member-D9EOB8-i.js → use-open-team-member-CruUTqzD.js} +1 -1
  169. package/dist/web/assets/use-remote-desktop-display-choice-DY5BWRTo.js +1 -0
  170. package/dist/web/assets/{use-websocket-xOOwBdwP.js → use-websocket-DetaY8OI.js} +1 -1
  171. package/dist/web/assets/{vendor-mermaid-0Nt-ew76.js → vendor-mermaid-BKWscKt0.js} +1 -1
  172. package/dist/web/assets/video-preview-C0uH2228.js +1 -0
  173. package/dist/web/assets/{vue-jjTomlbt.js → vue-D3D4lbXz.js} +1 -1
  174. package/dist/web/assets/{vue-html-8KEW6-I9.js → vue-html-DYEQFAiK.js} +1 -1
  175. package/dist/web/assets/{vue-vine-C5tohCkU.js → vue-vine-D0OPNscN.js} +1 -1
  176. package/dist/web/assets/{window-pip-registry-FdZdGF7h.js → window-pip-registry-BEN0QNSW.js} +1 -1
  177. package/dist/web/assets/window-store-DGKf9rPG.js +1 -0
  178. package/dist/web/assets/ws-auth-Dawx17PM.js +1 -0
  179. package/dist/web/assets/{xml-ByFFosqL.js → xml-DHaWgpya.js} +1 -1
  180. package/dist/web/assets/{xsl-CZUwiLkj.js → xsl-DVRN8JsA.js} +1 -1
  181. package/dist/web/index.html +32 -55
  182. package/dist/web/sw.js +1 -1
  183. package/docs/codebase-summary.md +9 -5
  184. package/docs/lessons-learned.md +11 -0
  185. package/package.json +2 -2
  186. package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
  187. package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
  188. package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
  189. package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
  190. package/src/providers/codex-app-server/codex-event-mapper.ts +70 -5
  191. package/src/providers/codex-app-server/codex-history.ts +24 -0
  192. package/src/providers/codex-app-server/codex-jsonrpc-client.ts +39 -2
  193. package/src/providers/codex-app-server/codex-protocol.ts +24 -0
  194. package/src/providers/codex-app-server/codex-provider.ts +159 -17
  195. package/src/providers/codex-app-server/codex-rollout-items.ts +149 -0
  196. package/src/providers/codex-app-server/codex-skill-parser.ts +63 -0
  197. package/src/providers/codex-app-server/codex-usage-fetch.ts +22 -20
  198. package/src/providers/codex-app-server/codex-usage-source.ts +37 -0
  199. package/src/server/routes/chat.ts +67 -9
  200. package/src/server/routes/codex-accounts.ts +9 -5
  201. package/src/server/ws/chat.ts +46 -1
  202. package/src/services/claude-usage-source.ts +40 -0
  203. package/src/services/claude-usage.service.ts +77 -146
  204. package/src/services/codex-account-login.ts +123 -55
  205. package/src/services/codex-account.service.ts +27 -4
  206. package/src/services/db.service.ts +161 -20
  207. package/src/services/edge-forwarder.ts +191 -191
  208. package/src/services/fs-credential-path-guard.ts +35 -8
  209. package/src/services/fs-path-guard.service.ts +1 -0
  210. package/src/services/postgres.service.ts +144 -72
  211. package/src/services/provider-usage/index.ts +63 -0
  212. package/src/services/provider-usage/register-usage-sources.ts +18 -0
  213. package/src/services/provider-usage/usage-memory-cache.ts +71 -0
  214. package/src/services/provider-usage/usage-registry.ts +157 -0
  215. package/src/services/provider-usage/usage-scheduler.ts +117 -0
  216. package/src/services/provider-usage/usage-snapshot-store.ts +126 -0
  217. package/src/services/provider-usage/usage-source.ts +82 -0
  218. package/src/services/slash-discovery/builtin-commands.ts +13 -0
  219. package/src/services/slash-discovery/codex-skill-items.ts +57 -0
  220. package/src/services/slash-discovery/provider-skill-sigil.ts +19 -0
  221. package/src/services/slash-discovery/types.ts +19 -0
  222. package/src/services/windows-process-tree.ts +351 -351
  223. package/src/types/chat.ts +7 -1
  224. package/src/web/app.tsx +1 -7
  225. package/src/web/components/chat/chat-history-bar.tsx +10 -1
  226. package/src/web/components/chat/chat-tab.tsx +17 -1
  227. package/src/web/components/chat/message-input.tsx +11 -4
  228. package/src/web/components/chat/message-list.tsx +14 -0
  229. package/src/web/components/chat/slash-command-picker.tsx +22 -3
  230. package/src/web/components/chat/tool-cards.tsx +47 -4
  231. package/src/web/components/chat/usage-badge.tsx +43 -447
  232. package/src/web/components/floating-window/window-content-registry.ts +2 -0
  233. package/src/web/components/floating-window/window-store-types.ts +1 -1
  234. package/src/web/components/layout/command-palette.tsx +2 -2
  235. package/src/web/components/layout/mobile-drawer.tsx +5 -4
  236. package/src/web/components/layout/mobile-nav.tsx +5 -1
  237. package/src/web/components/layout/nav-section-rail.tsx +2 -1
  238. package/src/web/components/layout/project-bottom-sheet.tsx +3 -9
  239. package/src/web/components/layout/sidebar.tsx +0 -2
  240. package/src/web/components/layout/tab-pop-out-menu-item.tsx +3 -2
  241. package/src/web/components/settings/accounts/account-add-dialog.tsx +155 -0
  242. package/src/web/components/settings/accounts/account-backup-format.ts +19 -0
  243. package/src/web/components/settings/accounts/account-bucket-row.tsx +55 -0
  244. package/src/web/components/settings/accounts/account-card.tsx +127 -0
  245. package/src/web/components/settings/accounts/account-delete-confirm.tsx +62 -0
  246. package/src/web/components/settings/accounts/account-export-dialog.tsx +154 -0
  247. package/src/web/components/settings/accounts/account-export-simulation.tsx +196 -0
  248. package/src/web/components/settings/accounts/account-import-dialog.tsx +72 -0
  249. package/src/web/components/settings/accounts/account-profile-panel.tsx +52 -0
  250. package/src/web/components/{chat → settings/accounts}/account-rotation-settings.tsx +1 -1
  251. package/src/web/components/settings/accounts/account-token-test-dialog.tsx +147 -0
  252. package/src/web/components/settings/accounts/account-usage-format.ts +92 -0
  253. package/src/web/components/{chat/usage-pattern-chart.tsx → settings/accounts/account-usage-pattern-chart.tsx} +1 -1
  254. package/src/web/components/settings/accounts/accounts-pane-header.tsx +93 -0
  255. package/src/web/components/settings/accounts/accounts-settings-section.tsx +80 -0
  256. package/src/web/components/settings/accounts/claude-accounts-section.tsx +168 -0
  257. package/src/web/components/settings/accounts/codex-accounts-section.tsx +137 -0
  258. package/src/web/components/settings/accounts/codex-add-account-dialog.tsx +130 -0
  259. package/src/web/components/settings/accounts/codex-backup-dialog.tsx +101 -0
  260. package/src/web/components/settings/accounts/codex-rotation-dialog.tsx +65 -0
  261. package/src/web/components/settings/accounts/use-accounts-data.ts +81 -0
  262. package/src/web/components/settings/accounts/use-codex-accounts.ts +151 -0
  263. package/src/web/components/settings/ai-settings-section.tsx +14 -4
  264. package/src/web/components/settings/appearance-settings-section.tsx +125 -0
  265. package/src/web/components/settings/general-settings-section.tsx +87 -0
  266. package/src/web/components/settings/jira-watcher-section.tsx +34 -0
  267. package/src/web/components/settings/notifications-settings-section.tsx +37 -0
  268. package/src/web/components/settings/open-settings.ts +42 -0
  269. package/src/web/components/settings/resolve-open-settings-action.ts +45 -0
  270. package/src/web/components/settings/settings-body.tsx +110 -0
  271. package/src/web/components/settings/settings-categories.ts +102 -0
  272. package/src/web/components/settings/settings-category-list.tsx +56 -0
  273. package/src/web/components/settings/settings-category-rail.tsx +62 -0
  274. package/src/web/components/settings/settings-section-content.tsx +43 -0
  275. package/src/web/components/settings/settings-tab.tsx +15 -329
  276. package/src/web/components/settings/settings-window-content.tsx +24 -0
  277. package/src/web/hooks/use-chat.ts +38 -1
  278. package/src/web/hooks/use-global-keybindings.ts +3 -4
  279. package/src/web/hooks/use-url-sync.ts +30 -0
  280. package/src/web/hooks/use-usage.ts +23 -11
  281. package/src/web/lib/sidebar-tabs/tab-registry.ts +9 -9
  282. package/src/web/lib/slash-items-cache.ts +27 -7
  283. package/src/web/stores/panel-utils.ts +11 -0
  284. package/src/web/stores/settings-store.ts +4 -2
  285. package/src/web/stores/window-panel-actions.ts +1 -3
  286. package/src/web/stores/window-panel-persistence.ts +9 -4
  287. package/dist/web/assets/adaptive-context-menu-BbuRVTLn.js +0 -1
  288. package/dist/web/assets/ai-resource-editor-BCCOUzox.js +0 -1
  289. package/dist/web/assets/ai-settings-section-BEM1z7kp.js +0 -1
  290. package/dist/web/assets/api-client-D1CePgQ4.js +0 -1
  291. package/dist/web/assets/api-settings-CNtKkHqW.js +0 -1
  292. package/dist/web/assets/api-settings-Cubuqjsu.js +0 -1
  293. package/dist/web/assets/architecture-PBZL5I3N-6konx-J1.js +0 -1
  294. package/dist/web/assets/chat-tab-CmXGsJGc.js +0 -15
  295. package/dist/web/assets/clipboard-B-gwJ8DF.js +0 -1
  296. package/dist/web/assets/code-editor-DtHXzNZ1.js +0 -7
  297. package/dist/web/assets/context-menu-DfWZAxQy.js +0 -1
  298. package/dist/web/assets/database-viewer-GVaQVMdb.js +0 -1
  299. package/dist/web/assets/dialog-BSfuiTkJ.js +0 -1
  300. package/dist/web/assets/diff-viewer-BG5_fH1E.js +0 -4
  301. package/dist/web/assets/explorer-body-BPFnjxYj.js +0 -2
  302. package/dist/web/assets/explorer-window-content-Da1T9uM4.js +0 -1
  303. package/dist/web/assets/extension-store-Bhu--fPX.js +0 -1
  304. package/dist/web/assets/external-link-B6Hl0U4X.js +0 -1
  305. package/dist/web/assets/eye-off-CUdzgmX8.js +0 -1
  306. package/dist/web/assets/file-store-6HW2Lfl4.js +0 -1
  307. package/dist/web/assets/git-log-panel-DNC9fV0M.js +0 -1
  308. package/dist/web/assets/gitGraph-HDMCJU4V-ikUwsekd.js +0 -1
  309. package/dist/web/assets/group-chat-tab-DbUkcOaJ.js +0 -1
  310. package/dist/web/assets/index-DTqbMiVc.js +0 -52
  311. package/dist/web/assets/index-SFFv2-VM.css +0 -2
  312. package/dist/web/assets/info-3K5VOQVL-BAgmboBp.js +0 -1
  313. package/dist/web/assets/input-D0ol5jW0.js +0 -1
  314. package/dist/web/assets/keybindings-store-BGkB72gM.js +0 -1
  315. package/dist/web/assets/keybindings-store-Bq6VWl5X.js +0 -1
  316. package/dist/web/assets/lock-CNxUGpTk.js +0 -1
  317. package/dist/web/assets/markdown-renderer-DEAVpo0C.js +0 -1
  318. package/dist/web/assets/mobile-explorer-sheet-CD_kl-jA.js +0 -1
  319. package/dist/web/assets/monitor-smartphone-DLZ6Q05s.js +0 -1
  320. package/dist/web/assets/notification-store-Dgbsw9p9.js +0 -1
  321. package/dist/web/assets/packet-RMMSAZCW-RVlbbDRS.js +0 -1
  322. package/dist/web/assets/panel-store-UOV8wrfR.js +0 -1
  323. package/dist/web/assets/pdf-preview-B2CJ_EKv.js +0 -1
  324. package/dist/web/assets/pie-UPGHQEXC-ZWb4izpk.js +0 -1
  325. package/dist/web/assets/play-DpEEBJTT.js +0 -1
  326. package/dist/web/assets/radar-KQ55EAFF-bsP5x1Bx.js +0 -1
  327. package/dist/web/assets/refresh-cw-BQU5g2CY.js +0 -1
  328. package/dist/web/assets/remote-desktop-mobile-sheet-KKTRNjOL.js +0 -2
  329. package/dist/web/assets/remote-desktop-mobile-view-C1ST4-Fm.js +0 -1
  330. package/dist/web/assets/remote-desktop-readiness-gate-BH3BE5wA.js +0 -1
  331. package/dist/web/assets/remote-desktop-window-content-BaZJQt_N.js +0 -1
  332. package/dist/web/assets/rotate-ccw-CpjRo90J.js +0 -1
  333. package/dist/web/assets/scroll-area-lc0ZHORr.js +0 -1
  334. package/dist/web/assets/send-C_sLFt56.js +0 -1
  335. package/dist/web/assets/settings-store-zbPkG7o-.js +0 -2
  336. package/dist/web/assets/settings-tab-Cn-AqUP_.js +0 -1
  337. package/dist/web/assets/settings-tab-xyRpt2gq.js +0 -3
  338. package/dist/web/assets/shallow-CmPMAPte.js +0 -1
  339. package/dist/web/assets/sql-query-editor-B86NiZHI.js +0 -1
  340. package/dist/web/assets/sqlite-viewer-DB775F6C.js +0 -1
  341. package/dist/web/assets/switch-BmjKoIpR.js +0 -1
  342. package/dist/web/assets/system-monitor-body-BDxHQvy9.js +0 -2
  343. package/dist/web/assets/system-monitor-tab-BoTHLx6B.js +0 -1
  344. package/dist/web/assets/team-member-sheet-Cxz6h5Ne.js +0 -2
  345. package/dist/web/assets/team-member-window-content-CUSuRHCB.js +0 -1
  346. package/dist/web/assets/tool-cards-D3KSzd2K.js +0 -8
  347. package/dist/web/assets/trash-2-By4VMbC4.js +0 -1
  348. package/dist/web/assets/treemap-KZPCXAKY-Dh1oxNdQ.js +0 -1
  349. package/dist/web/assets/triangle-alert-CUTURFbG.js +0 -1
  350. package/dist/web/assets/upload-BNlX8D07.js +0 -1
  351. package/dist/web/assets/use-monaco-theme-CVCye2kq.js +0 -1
  352. package/dist/web/assets/use-remote-desktop-display-choice-neUqyE3p.js +0 -1
  353. package/dist/web/assets/video-preview-DvpgBDhM.js +0 -1
  354. package/dist/web/assets/window-store-D0x_fxr0.js +0 -1
  355. package/src/web/components/chat/account-dialogs.tsx +0 -384
  356. package/src/web/components/settings/accounts-settings-section.tsx +0 -1090
  357. package/src/web/components/settings/codex-accounts-section.tsx +0 -198
  358. package/src/web/components/settings/telegram-settings-section.tsx +0 -113
  359. /package/dist/web/assets/{abap-C5DFF0s3.js → abap-h3QyH8MW.js} +0 -0
  360. /package/dist/web/assets/{actionscript-3-B0qyRNbc.js → actionscript-3-mkxkq-FN.js} +0 -0
  361. /package/dist/web/assets/{ada-bAJzplug.js → ada-DhISK_EH.js} +0 -0
  362. /package/dist/web/assets/{andromeeda-DUCpISy6.js → andromeeda-DnlWWesX.js} +0 -0
  363. /package/dist/web/assets/{apache-BhAr84Z_.js → apache-P5AK3sfA.js} +0 -0
  364. /package/dist/web/assets/{apex-CRv8YnNq.js → apex-CJUPehg2.js} +0 -0
  365. /package/dist/web/assets/{api-client-BzWM7XPR.js → api-client-oY1tC3tM.js} +0 -0
  366. /package/dist/web/assets/{applescript-CD-Cw8bt.js → applescript-Dx6GGbay.js} +0 -0
  367. /package/dist/web/assets/{apply-theme-DJ794zSQ.js → apply-theme-DxTXOAcV.js} +0 -0
  368. /package/dist/web/assets/{ara-BUzeQYoG.js → ara-95Kx3qKb.js} +0 -0
  369. /package/dist/web/assets/{asciidoc-CT2hTg-v.js → asciidoc-Dp0RbIej.js} +0 -0
  370. /package/dist/web/assets/{asm-CAu35JeY.js → asm-C82coUjU.js} +0 -0
  371. /package/dist/web/assets/{aurora-x-BeFJoIA1.js → aurora-x-BFc3zeop.js} +0 -0
  372. /package/dist/web/assets/{awk-Vau-DrGN.js → awk-ChjC0icr.js} +0 -0
  373. /package/dist/web/assets/{ayu-dark-CLe-OTsQ.js → ayu-dark-DYfUf_PB.js} +0 -0
  374. /package/dist/web/assets/{ayu-light-CJbQfu4M.js → ayu-light-Bh6O0plO.js} +0 -0
  375. /package/dist/web/assets/{ayu-mirage-GWaKwdrx.js → ayu-mirage-DlNhHTGq.js} +0 -0
  376. /package/dist/web/assets/{ballerina-DWu0USI5.js → ballerina-Ceoll3Sk.js} +0 -0
  377. /package/dist/web/assets/{bat-_07Huw7E.js → bat-C7QS6Lfq.js} +0 -0
  378. /package/dist/web/assets/{beancount-EcvogrcF.js → beancount-5NMEAZgs.js} +0 -0
  379. /package/dist/web/assets/{berry-BBB87SY7.js → berry-BBL83Vbk.js} +0 -0
  380. /package/dist/web/assets/{bibtex-DbueS87A.js → bibtex-L7rPkPSG.js} +0 -0
  381. /package/dist/web/assets/{bicep-tcmXnUo4.js → bicep-BOwHIINh.js} +0 -0
  382. /package/dist/web/assets/{bird2-B2qwilIR.js → bird2-CWLsMom2.js} +0 -0
  383. /package/dist/web/assets/{c-Z58oivSt.js → c-CD4Ku5Cr.js} +0 -0
  384. /package/dist/web/assets/{c3-U40cGT9p.js → c3-CpMl-w3G.js} +0 -0
  385. /package/dist/web/assets/{cadence-BFcD-LyM.js → cadence-CvgF6ehN.js} +0 -0
  386. /package/dist/web/assets/{can-open-in-ppm-CdCK2c2a.js → can-open-in-ppm-j3jh7fUo.js} +0 -0
  387. /package/dist/web/assets/{catppuccin-frappe-RkC9AX6J.js → catppuccin-frappe-eo_dTm3F.js} +0 -0
  388. /package/dist/web/assets/{catppuccin-latte-Bsi4l-nO.js → catppuccin-latte-DoiMCU_7.js} +0 -0
  389. /package/dist/web/assets/{catppuccin-macchiato-B8JIdTW-.js → catppuccin-macchiato-UQxsK2Vh.js} +0 -0
  390. /package/dist/web/assets/{catppuccin-mocha-oH8wwrDj.js → catppuccin-mocha-J0i-8RNy.js} +0 -0
  391. /package/dist/web/assets/{clarity-C3WNeRCR.js → clarity-DXYM8-SA.js} +0 -0
  392. /package/dist/web/assets/{clojure-CFoAz7u9.js → clojure-DzamsL69.js} +0 -0
  393. /package/dist/web/assets/{cmake-Bcsqp9yR.js → cmake-CR6RP_T_.js} +0 -0
  394. /package/dist/web/assets/{codeowners-DC2Z7heP.js → codeowners-D1s6-IyY.js} +0 -0
  395. /package/dist/web/assets/{codeql-BfG68Al5.js → codeql-DAqNWMkS.js} +0 -0
  396. /package/dist/web/assets/{common-lisp-Z5P-lKQe.js → common-lisp-8e-KtitB.js} +0 -0
  397. /package/dist/web/assets/{coq-BJslqrnv.js → coq-UEq0WUcO.js} +0 -0
  398. /package/dist/web/assets/{csharp-DhhZTOTs.js → csharp-wxJ0TuCm.js} +0 -0
  399. /package/dist/web/assets/{css-DiFIpMfE.js → css-Cerub-yB.js} +0 -0
  400. /package/dist/web/assets/{csv-DViLbHxI.js → csv-Bh9_WD_h.js} +0 -0
  401. /package/dist/web/assets/{csv-parser-B2v8MoUy.js → csv-parser-BPIDt6ni.js} +0 -0
  402. /package/dist/web/assets/{cue-CoG3mg2I.js → cue-rzM1ztqU.js} +0 -0
  403. /package/dist/web/assets/{cypher-jTxC8NAB.js → cypher-DGaTQ8m0.js} +0 -0
  404. /package/dist/web/assets/{d-6hKIUAbU.js → d-DbkZGuhB.js} +0 -0
  405. /package/dist/web/assets/{dark-plus-D_-np2Sr.js → dark-plus-BO2bzZcA.js} +0 -0
  406. /package/dist/web/assets/{dart-CVpxLpVn.js → dart-BDhCoqVg.js} +0 -0
  407. /package/dist/web/assets/{data-grid-types-Dq_H1IPa.js → data-grid-types-CdAg-4W1.js} +0 -0
  408. /package/dist/web/assets/{dax-BPqJ8qIY.js → dax-Bh03stWh.js} +0 -0
  409. /package/dist/web/assets/{desktop-u_y5_Hr5.js → desktop-BOdr_fwq.js} +0 -0
  410. /package/dist/web/assets/{diff-Duj1XMrd.js → diff-Bb_gTsS2.js} +0 -0
  411. /package/dist/web/assets/{dist-CEZ4plgH.js → dist-BUMDu0av.js} +0 -0
  412. /package/dist/web/assets/{dist-aDSxTR_v.js → dist-DonmFWG8.js} +0 -0
  413. /package/dist/web/assets/{docker-8UGSCc7N.js → docker-BDsTF5ce.js} +0 -0
  414. /package/dist/web/assets/{dotenv-DVnj8kyR.js → dotenv-CbCWp9Ti.js} +0 -0
  415. /package/dist/web/assets/{dracula-D0cEmSg7.js → dracula-Cd1fxvoX.js} +0 -0
  416. /package/dist/web/assets/{dracula-soft-DfGS5Yfr.js → dracula-soft-B7eXkfXG.js} +0 -0
  417. /package/dist/web/assets/{dream-maker-qG8kMGTF.js → dream-maker-XlzuS21R.js} +0 -0
  418. /package/dist/web/assets/{emacs-lisp-iVqyMLyT.js → emacs-lisp-CXV1Ki_7.js} +0 -0
  419. /package/dist/web/assets/{everforest-dark-Cruygd5U.js → everforest-dark-DuqR60Dg.js} +0 -0
  420. /package/dist/web/assets/{everforest-light-BiJa8RHL.js → everforest-light-q4BPnenD.js} +0 -0
  421. /package/dist/web/assets/{fennel-H6XSEIoz.js → fennel-B-e0TX2Q.js} +0 -0
  422. /package/dist/web/assets/{fish-ho_7CxX6.js → fish-Bzb6-TtF.js} +0 -0
  423. /package/dist/web/assets/{fluent-1l5ssJTF.js → fluent-B-szH2-f.js} +0 -0
  424. /package/dist/web/assets/{folder-symlink-Dx1hOk8X.js → folder-symlink-fQRoG_rV.js} +0 -0
  425. /package/dist/web/assets/{format-bytes-gQw5wzqa.js → format-bytes-CKXk9k2d.js} +0 -0
  426. /package/dist/web/assets/{fortran-free-form-Bo1x233A.js → fortran-free-form-OS6SGYC0.js} +0 -0
  427. /package/dist/web/assets/{gdscript-DffFMp_k.js → gdscript-FYq4OP2d.js} +0 -0
  428. /package/dist/web/assets/{gdshader-CvnpAiAF.js → gdshader-BpG6P8rw.js} +0 -0
  429. /package/dist/web/assets/{genie-2eOvAEzW.js → genie-BS9RLAna.js} +0 -0
  430. /package/dist/web/assets/{gherkin-DL-5OUlV.js → gherkin-B_9FdtGs.js} +0 -0
  431. /package/dist/web/assets/{github-dark-DrTZprgG.js → github-dark-cfaIlnBV.js} +0 -0
  432. /package/dist/web/assets/{github-dark-default-_mDH8IMP.js → github-dark-default-B2Wv65He.js} +0 -0
  433. /package/dist/web/assets/{github-dark-dimmed-C48hJuLn.js → github-dark-dimmed-CtM9X76s.js} +0 -0
  434. /package/dist/web/assets/{github-dark-high-contrast-BQ-zGGNe.js → github-dark-high-contrast-DLHyk0tG.js} +0 -0
  435. /package/dist/web/assets/{github-light-BYc90Yx8.js → github-light-DWEI10iG.js} +0 -0
  436. /package/dist/web/assets/{github-light-default-Daecj4J5.js → github-light-default-DcJkK1YN.js} +0 -0
  437. /package/dist/web/assets/{github-light-high-contrast-DoafCbsU.js → github-light-high-contrast-Bcx9iKDt.js} +0 -0
  438. /package/dist/web/assets/{gleam-hUWWjmnp.js → gleam-DVpiM6b2.js} +0 -0
  439. /package/dist/web/assets/{gn-7PJ3R70o.js → gn-B80DNc0i.js} +0 -0
  440. /package/dist/web/assets/{gnuplot-V-Pxck7b.js → gnuplot-D9i3MaT-.js} +0 -0
  441. /package/dist/web/assets/{go-ARF6DprD.js → go-CwCBf_Pt.js} +0 -0
  442. /package/dist/web/assets/{groovy-CKGBIPOz.js → groovy-D7mEfwmW.js} +0 -0
  443. /package/dist/web/assets/{gruvbox-dark-hard-Cm9wqdI3.js → gruvbox-dark-hard-C4R4MOoH.js} +0 -0
  444. /package/dist/web/assets/{gruvbox-dark-medium-Cmsd6dG8.js → gruvbox-dark-medium-CZnFC0s8.js} +0 -0
  445. /package/dist/web/assets/{gruvbox-dark-soft-BBGlGGCz.js → gruvbox-dark-soft-DFcJlEBl.js} +0 -0
  446. /package/dist/web/assets/{gruvbox-light-hard-BCR7KmqG.js → gruvbox-light-hard-B6IF_1L-.js} +0 -0
  447. /package/dist/web/assets/{gruvbox-light-medium-CP32bga8.js → gruvbox-light-medium-C19AZJv2.js} +0 -0
  448. /package/dist/web/assets/{gruvbox-light-soft-qjxk8ps6.js → gruvbox-light-soft-BAnpDm9B.js} +0 -0
  449. /package/dist/web/assets/{haskell-C5DzwGRa.js → haskell-CsXSYXRG.js} +0 -0
  450. /package/dist/web/assets/{haxe-C8f_jCVv.js → haxe-B1uyiI9t.js} +0 -0
  451. /package/dist/web/assets/{hcl-DetJkf6E.js → hcl-DlYKn5q9.js} +0 -0
  452. /package/dist/web/assets/{hjson-DeZhwIdo.js → hjson-C_0VMGJJ.js} +0 -0
  453. /package/dist/web/assets/{hlsl-SMIDLRyX.js → hlsl-zt2PEzbg.js} +0 -0
  454. /package/dist/web/assets/{horizon-BMAVDxMx.js → horizon-6wQfyOK0.js} +0 -0
  455. /package/dist/web/assets/{horizon-bright-3BaV_VGD.js → horizon-bright-CqI2qTim.js} +0 -0
  456. /package/dist/web/assets/{houston-BWBbEPvb.js → houston-BljpHDoG.js} +0 -0
  457. /package/dist/web/assets/{hy-DcsmE-Nm.js → hy-XzuL55dw.js} +0 -0
  458. /package/dist/web/assets/{image-gallery-Bqb-wjNw.js → image-gallery-Cj8nd4xW.js} +0 -0
  459. /package/dist/web/assets/{imba-CnkgnYMf.js → imba-CqhhjBrP.js} +0 -0
  460. /package/dist/web/assets/{ini-BnvTdau7.js → ini-CiFDi6cY.js} +0 -0
  461. /package/dist/web/assets/{java-BLFACXat.js → java-OsQgTL5-.js} +0 -0
  462. /package/dist/web/assets/{javascript-BKcFWENk.js → javascript-qWAOScxl.js} +0 -0
  463. /package/dist/web/assets/{json-3AJtJADf.js → json-RiAKsaD1.js} +0 -0
  464. /package/dist/web/assets/{json5-DLyDVlwe.js → json5-BeCnS3H2.js} +0 -0
  465. /package/dist/web/assets/{jsonc-B5DgF1jW.js → jsonc-CbTW1Mka.js} +0 -0
  466. /package/dist/web/assets/{jsonl-CV_O71a2.js → jsonl-BLSi_669.js} +0 -0
  467. /package/dist/web/assets/{jsonnet-DZfPLgYz.js → jsonnet-C3xAggou.js} +0 -0
  468. /package/dist/web/assets/{jssm-Cr1zYOsY.js → jssm-CLdiagC9.js} +0 -0
  469. /package/dist/web/assets/{jsx-VN-JS2_q.js → jsx-lYE1lb50.js} +0 -0
  470. /package/dist/web/assets/{kanagawa-dragon-D9CcT3xg.js → kanagawa-dragon-Cd1vcrpD.js} +0 -0
  471. /package/dist/web/assets/{kanagawa-lotus-DLXsB8fr.js → kanagawa-lotus-Dw3QKtk9.js} +0 -0
  472. /package/dist/web/assets/{kanagawa-wave-weDs3Wjz.js → kanagawa-wave-DIq5Zv5G.js} +0 -0
  473. /package/dist/web/assets/{kdl-0XF56jnT.js → kdl-BfDV0825.js} +0 -0
  474. /package/dist/web/assets/{keyboard-DBBaoQSu.js → keyboard-DiOYrs6C.js} +0 -0
  475. /package/dist/web/assets/{kotlin-BPkH9vzk.js → kotlin-DONxR4wD.js} +0 -0
  476. /package/dist/web/assets/{kusto-DMVpADb9.js → kusto-BDP63Fh5.js} +0 -0
  477. /package/dist/web/assets/{laserwave-Cl6T2cGP.js → laserwave-BeBrWApL.js} +0 -0
  478. /package/dist/web/assets/{lean-BvwzQGl1.js → lean-DOZc0N1A.js} +0 -0
  479. /package/dist/web/assets/{less-DI_03xkC.js → less-C3H9NlDv.js} +0 -0
  480. /package/dist/web/assets/{lib-v9x_qXgI.js → lib-xrSJ4EZX.js} +0 -0
  481. /package/dist/web/assets/{libesm-dcbw4_18.js → libesm-DLBE59ul.js} +0 -0
  482. /package/dist/web/assets/{light-plus-hIiIsQN_.js → light-plus-C_kTL608.js} +0 -0
  483. /package/dist/web/assets/{llvm-B5hjjSWc.js → llvm-Dsp27U3P.js} +0 -0
  484. /package/dist/web/assets/{loader-circle-DouKgIXy.js → loader-circle-DPMrnLQ2.js} +0 -0
  485. /package/dist/web/assets/{log-D28raQiE.js → log-BywQaTCy.js} +0 -0
  486. /package/dist/web/assets/{logo-6Cdd4ASb.js → logo-BirJgciO.js} +0 -0
  487. /package/dist/web/assets/{luau-CK9nKpOX.js → luau-Btrz5kJB.js} +0 -0
  488. /package/dist/web/assets/{make-CVnxKCB6.js → make-Kl7nFQrS.js} +0 -0
  489. /package/dist/web/assets/{markdown-B9mMQzD5.js → markdown-qsC4P8S-.js} +0 -0
  490. /package/dist/web/assets/{material-theme-BZSs2o0j.js → material-theme-CC__ui3p.js} +0 -0
  491. /package/dist/web/assets/{material-theme-darker-BeAQBzQ_.js → material-theme-darker-D4FxG2FZ.js} +0 -0
  492. /package/dist/web/assets/{material-theme-lighter-BAe0IXcs.js → material-theme-lighter-zGqiWcxn.js} +0 -0
  493. /package/dist/web/assets/{material-theme-ocean-CiPIf0Np.js → material-theme-ocean-CZIdTTB1.js} +0 -0
  494. /package/dist/web/assets/{material-theme-palenight-DJBb4_XN.js → material-theme-palenight-CEIs0GcK.js} +0 -0
  495. /package/dist/web/assets/{matlab-CY0dbp_s.js → matlab-Cf0aUjN9.js} +0 -0
  496. /package/dist/web/assets/{mdx-DU9zbF7h.js → mdx-CIsXjH86.js} +0 -0
  497. /package/dist/web/assets/{mermaid-UmmjGwdh.js → mermaid-B06WO9Qc.js} +0 -0
  498. /package/dist/web/assets/{min-dark-C59GkzOm.js → min-dark-z8fyp0FT.js} +0 -0
  499. /package/dist/web/assets/{min-light-B9QglrdQ.js → min-light-Dr-qesbW.js} +0 -0
  500. /package/dist/web/assets/{mipsasm-Dc6Jsr_D.js → mipsasm-CWHzYLcE.js} +0 -0
  501. /package/dist/web/assets/{mojo-D5ij-nGW.js → mojo-D9zXrKmv.js} +0 -0
  502. /package/dist/web/assets/{monitor-CxPV_fQI.js → monitor-C835ucWH.js} +0 -0
  503. /package/dist/web/assets/{monokai-QAtE_yCP.js → monokai-4b-AKOpX.js} +0 -0
  504. /package/dist/web/assets/{moonbit-BMtIdiTL.js → moonbit-Dl4dhOZJ.js} +0 -0
  505. /package/dist/web/assets/{move-BB_jMHYZ.js → move-DTYKJmXy.js} +0 -0
  506. /package/dist/web/assets/{narrat-BvvoKGVn.js → narrat-DnvXOS-o.js} +0 -0
  507. /package/dist/web/assets/{nextflow-groovy-CqxtAsnF.js → nextflow-groovy-Di8QnEXg.js} +0 -0
  508. /package/dist/web/assets/{night-owl-CLoE9kjt.js → night-owl-Czh0yq-H.js} +0 -0
  509. /package/dist/web/assets/{night-owl-light-BwIFT5Xd.js → night-owl-light-D_OpZqOR.js} +0 -0
  510. /package/dist/web/assets/{nix-BKlnVT9r.js → nix-2MvcjpK3.js} +0 -0
  511. /package/dist/web/assets/{nord-B7R1KRAK.js → nord-CG_r4cyk.js} +0 -0
  512. /package/dist/web/assets/{nushell-CzUme-NJ.js → nushell-DINskMcU.js} +0 -0
  513. /package/dist/web/assets/{objective-c-D-UKKiOc.js → objective-c-Dv7BIicR.js} +0 -0
  514. /package/dist/web/assets/{objective-cpp-BucWn4Fx.js → objective-cpp-CpqsCxPb.js} +0 -0
  515. /package/dist/web/assets/{ocaml-EJCNXMGo.js → ocaml-DwTsYSmW.js} +0 -0
  516. /package/dist/web/assets/{odin-CEjnRU_3.js → odin-G-4O4k4t.js} +0 -0
  517. /package/dist/web/assets/{one-dark-pro-Bv469NX5.js → one-dark-pro-13Pv5SjI.js} +0 -0
  518. /package/dist/web/assets/{one-light-BlzO5RWI.js → one-light-Bi2e86mS.js} +0 -0
  519. /package/dist/web/assets/{openscad-Czl6alLw.js → openscad-D0WsOTij.js} +0 -0
  520. /package/dist/web/assets/{pascal-BI9fLvG4.js → pascal-DmDStuXr.js} +0 -0
  521. /package/dist/web/assets/{pkl-ChQLsyjU.js → pkl-Bl6Qjtuo.js} +0 -0
  522. /package/dist/web/assets/{plastic-DGL3mtdL.js → plastic-UeSVSjTI.js} +0 -0
  523. /package/dist/web/assets/{plsql-BJDjqcWp.js → plsql-DreFC689.js} +0 -0
  524. /package/dist/web/assets/{po-DK5O3OpF.js → po-ZIjccxsX.js} +0 -0
  525. /package/dist/web/assets/{poimandres-CnuqZT4T.js → poimandres-CvQHJPrI.js} +0 -0
  526. /package/dist/web/assets/{polar-DCsUxSsQ.js → polar-BrMB0Kgh.js} +0 -0
  527. /package/dist/web/assets/{portal-container-context-D-495m5C.js → portal-container-context-a399Hd9F.js} +0 -0
  528. /package/dist/web/assets/{postcss-8UjdFmis.js → postcss-pgUsil1T.js} +0 -0
  529. /package/dist/web/assets/{powerquery-CAp0CGQj.js → powerquery-CTsZkCg_.js} +0 -0
  530. /package/dist/web/assets/{powershell-CbBsKZJP.js → powershell-CcwVuBAp.js} +0 -0
  531. /package/dist/web/assets/{prisma-BnNpXCJN.js → prisma-spjnAI5W.js} +0 -0
  532. /package/dist/web/assets/{prolog-CC-l9E8Y.js → prolog-ChCkZpDO.js} +0 -0
  533. /package/dist/web/assets/{proto-CV_1k2rL.js → proto-wVGqK4gB.js} +0 -0
  534. /package/dist/web/assets/{puppet-2D8HU2bv.js → puppet-CED7iwPQ.js} +0 -0
  535. /package/dist/web/assets/{purescript-BEJAORgU.js → purescript-u9lGiQKV.js} +0 -0
  536. /package/dist/web/assets/{python-BBdbb7nn.js → python-DeqTx6ef.js} +0 -0
  537. /package/dist/web/assets/{qmldir-D5ZYI4Ie.js → qmldir-BH1uoPrX.js} +0 -0
  538. /package/dist/web/assets/{qss-BOJVGyXE.js → qss-CUVKA_13.js} +0 -0
  539. /package/dist/web/assets/{r-B5dlEtkj.js → r-BqdPzqYH.js} +0 -0
  540. /package/dist/web/assets/{racket-BUAEygJ6.js → racket-C2eTgPN3.js} +0 -0
  541. /package/dist/web/assets/{raku-BG0Ss0ID.js → raku-uAay1sWx.js} +0 -0
  542. /package/dist/web/assets/{react-B549sK_T.js → react-X4jUntEf.js} +0 -0
  543. /package/dist/web/assets/{red-C5yyQbtG.js → red-DTZP1ZfC.js} +0 -0
  544. /package/dist/web/assets/{reg-DHoBWtLf.js → reg-Cdk3YsxY.js} +0 -0
  545. /package/dist/web/assets/{regexp-DDtJrlKv.js → regexp-Bpa2aS7K.js} +0 -0
  546. /package/dist/web/assets/{rel-CR6WJDRD.js → rel-bNsb1-3L.js} +0 -0
  547. /package/dist/web/assets/{resolve-theme-4fexHWl6.js → resolve-theme-DQk_YcsT.js} +0 -0
  548. /package/dist/web/assets/{riscv-2V9tC-nx.js → riscv-DSaubByW.js} +0 -0
  549. /package/dist/web/assets/{ron-QLTmqGUw.js → ron-DbQzYM6i.js} +0 -0
  550. /package/dist/web/assets/{rose-pine-be0__X3A.js → rose-pine-C7RsprTu.js} +0 -0
  551. /package/dist/web/assets/{rose-pine-dawn-n_WQJwsW.js → rose-pine-dawn-VP976YzL.js} +0 -0
  552. /package/dist/web/assets/{rose-pine-moon-t2aLtzgB.js → rose-pine-moon-XHZNhOqd.js} +0 -0
  553. /package/dist/web/assets/{rosmsg-Ce1JD8vt.js → rosmsg-BVQlx0Lj.js} +0 -0
  554. /package/dist/web/assets/{rust-5fHH-ZoW.js → rust-VHaQ3rh3.js} +0 -0
  555. /package/dist/web/assets/{sass-DPmGFiOJ.js → sass-CO-kMkwD.js} +0 -0
  556. /package/dist/web/assets/{save-DYLiVzU8.js → save-CipGrG1k.js} +0 -0
  557. /package/dist/web/assets/{scala-BRMVFbZF.js → scala-cY0GXkiz.js} +0 -0
  558. /package/dist/web/assets/{scheme-BMSJWevF.js → scheme-D4LNZE0X.js} +0 -0
  559. /package/dist/web/assets/{sdbl-DTZ-pEHI.js → sdbl-Bh2Fd2cn.js} +0 -0
  560. /package/dist/web/assets/{shellscript-6-9yg5Cz.js → shellscript-KKclmCnt.js} +0 -0
  561. /package/dist/web/assets/{shield-check-CUI36aSc.js → shield-check-BsG3LV8i.js} +0 -0
  562. /package/dist/web/assets/{shield-off-GdkkVhb3.js → shield-off-7jKWpJBD.js} +0 -0
  563. /package/dist/web/assets/{slack-dark-DKJgiR7e.js → slack-dark-D6YQ-fqf.js} +0 -0
  564. /package/dist/web/assets/{slack-ochin-WjehVgyK.js → slack-ochin-CDf66CDj.js} +0 -0
  565. /package/dist/web/assets/{smalltalk-BChf4SN1.js → smalltalk-D2OH_QIl.js} +0 -0
  566. /package/dist/web/assets/{snazzy-light-C1WAwOx6.js → snazzy-light-CQeF8G1K.js} +0 -0
  567. /package/dist/web/assets/{solarized-dark-BxREZrGx.js → solarized-dark-LTPf1iLZ.js} +0 -0
  568. /package/dist/web/assets/{solarized-light-DG29B1pR.js → solarized-light-Ose1n88k.js} +0 -0
  569. /package/dist/web/assets/{solidity-bDbtGwdR.js → solidity-lFuOMHki.js} +0 -0
  570. /package/dist/web/assets/{splunk-Ceqx5njI.js → splunk-Bov-sB5S.js} +0 -0
  571. /package/dist/web/assets/{sql-OwMEKbz8.js → sql-BKyZ6wmk.js} +0 -0
  572. /package/dist/web/assets/{ssh-config-WAR3lu2k.js → ssh-config-CqJoMGMb.js} +0 -0
  573. /package/dist/web/assets/{stylus-Cjmoz3d8.js → stylus-Bf5pWRLI.js} +0 -0
  574. /package/dist/web/assets/{swift-S_ZSBG1q.js → swift-D5d1hn_u.js} +0 -0
  575. /package/dist/web/assets/{synthwave-84-DiUeWMSh.js → synthwave-84-B4c6YAgO.js} +0 -0
  576. /package/dist/web/assets/{system-verilog-RRjqPjUV.js → system-verilog-D7fXyDsI.js} +0 -0
  577. /package/dist/web/assets/{systemd-BD3SkXoU.js → systemd-oNagzlBK.js} +0 -0
  578. /package/dist/web/assets/{table-D5Q4ap4W.js → table-CRJsmfeg.js} +0 -0
  579. /package/dist/web/assets/{talonscript-DWefISOm.js → talonscript-C6Nqm9Dm.js} +0 -0
  580. /package/dist/web/assets/{tasl-DCjSS-09.js → tasl-CaWy-cBX.js} +0 -0
  581. /package/dist/web/assets/{tcl-DTYqT_66.js → tcl-C435P5Mq.js} +0 -0
  582. /package/dist/web/assets/{terraform-CkbP5QnR.js → terraform-CVDxqdPf.js} +0 -0
  583. /package/dist/web/assets/{text-wrap-DBvQD3kc.js → text-wrap-oiekm5SB.js} +0 -0
  584. /package/dist/web/assets/{tokyo-night-qVSqO9xy.js → tokyo-night-Uhs17tQ3.js} +0 -0
  585. /package/dist/web/assets/{toml-D9F5Osqs.js → toml-j6fPOJ6P.js} +0 -0
  586. /package/dist/web/assets/{tsv-C5tpHoxm.js → tsv-h78O6xrL.js} +0 -0
  587. /package/dist/web/assets/{tsx-CMWkGtGm.js → tsx-Bol-vCrQ.js} +0 -0
  588. /package/dist/web/assets/{turtle-Cn4z3xOi.js → turtle-Dw8eFf04.js} +0 -0
  589. /package/dist/web/assets/{typescript-DSyAEWsn.js → typescript-Dtz7DPci.js} +0 -0
  590. /package/dist/web/assets/{typespec-B93Qap7y.js → typespec-BIOQ7dMP.js} +0 -0
  591. /package/dist/web/assets/{typst-DtlOmFlX.js → typst-CoaGMjzu.js} +0 -0
  592. /package/dist/web/assets/{use-is-mobile-B9UZNwSm.js → use-is-mobile-CYW3FJFE.js} +0 -0
  593. /package/dist/web/assets/{use-visual-viewport-Sfb6CZ80.js → use-visual-viewport-rnvuooQZ.js} +0 -0
  594. /package/dist/web/assets/{utils-QHe_Q6UF.js → utils-C9OjCrou.js} +0 -0
  595. /package/dist/web/assets/{v-Dfzf-szS.js → v-BoqFdpJ7.js} +0 -0
  596. /package/dist/web/assets/{vala-CyiQZQ9f.js → vala-COBpNnCC.js} +0 -0
  597. /package/dist/web/assets/{vb-C7DGSldd.js → vb-DxI86znh.js} +0 -0
  598. /package/dist/web/assets/{vendor-xterm-BHKF_Nsf.js → vendor-xterm-BaMOj65g.js} +0 -0
  599. /package/dist/web/assets/{verilog-kF-hClY2.js → verilog-DcTAamuQ.js} +0 -0
  600. /package/dist/web/assets/{vesper-BmKcADuz.js → vesper-DO298JSv.js} +0 -0
  601. /package/dist/web/assets/{vhdl-CDnb16KJ.js → vhdl-Dq-bDVSN.js} +0 -0
  602. /package/dist/web/assets/{viml-B8cs6Ady.js → viml-zHTRWuQh.js} +0 -0
  603. /package/dist/web/assets/{vitesse-black-BR6o9Gto.js → vitesse-black-jlYMJCBf.js} +0 -0
  604. /package/dist/web/assets/{vitesse-dark-Dye14-KB.js → vitesse-dark-DS0sUlSZ.js} +0 -0
  605. /package/dist/web/assets/{vitesse-light-BLpswIxf.js → vitesse-light-HSeZ2YhG.js} +0 -0
  606. /package/dist/web/assets/{vyper-DU51Z97W.js → vyper-BQfKVO3M.js} +0 -0
  607. /package/dist/web/assets/{wasm-ChtccNfv.js → wasm-B1xp9bLp.js} +0 -0
  608. /package/dist/web/assets/{wasm-CVqlJAR2.js → wasm-B6mCuI8h.js} +0 -0
  609. /package/dist/web/assets/{wenyan-DhCa3hCn.js → wenyan-CfpS05sP.js} +0 -0
  610. /package/dist/web/assets/{wgsl-Bj1Ec4vv.js → wgsl-14GDsWRD.js} +0 -0
  611. /package/dist/web/assets/{wikitext-C90DHNa0.js → wikitext-Ccbq5EVX.js} +0 -0
  612. /package/dist/web/assets/{wit-DUgbOD7Z.js → wit-C19hb3R5.js} +0 -0
  613. /package/dist/web/assets/{wolfram-BgwUqD1I.js → wolfram-B-ZSwGwP.js} +0 -0
  614. /package/dist/web/assets/{x-DiOUR_mp.js → x-YDu4m2Iq.js} +0 -0
  615. /package/dist/web/assets/{yaml-DEQulj-8.js → yaml-mw_JUeio.js} +0 -0
  616. /package/dist/web/assets/{zenscript-C7Jp7TgT.js → zenscript-WbzDRjvF.js} +0 -0
  617. /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
- * Shared codex quota fetcher: runs a short-lived app-server bound to a given
3
- * CODEX_HOME and reads account/rateLimits/read → UsageInfo. Cached per home
4
- * (60s) so the provider badge and the multi-account list don't spawn per call.
5
- * Lives here (not the provider/service) to avoid a provider↔account-service cycle.
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
- const usage = parseCodexUsage(res);
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
- // Claude's own built-ins need a live SDK session to enumerate; cached 30 min,
41
- // so only the first request per project pays for the CLI spawn.
42
- await ensureSdkCommands(projectPath);
43
- let items = listSlashItems(projectPath);
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) as { getUsage?: () => Promise<unknown> } | undefined;
121
+ const provider = providerRegistry.get(providerId);
82
122
  if (provider?.getUsage) {
83
- try { return c.json(ok(await provider.getUsage())); } catch { return c.json(ok({})); }
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 id = c.req.param("id");
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
- return c.json(ok({ messages, versionMap: resolveVersionMap(id) }));
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, awaitDeviceLogin } from "../../services/codex-account-login.ts";
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
- /** Long-poll until the device login completes; persists the account on success. */
40
- codexAccountsRoutes.post("/device-login/:id/await", async (c) => {
41
- try { return c.json(ok(await awaitDeviceLogin(c.req.param("id"))), 201); }
42
- catch (e) { return c.json(err((e as Error).message), 400); }
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). */
@@ -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
+ };