@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.
Files changed (622) hide show
  1. package/CHANGELOG.md +27 -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-CCFQV-RB.js +1 -0
  7. package/dist/web/assets/ai-resource-editor-BTWds-aC.js +1 -0
  8. package/dist/web/assets/ai-settings-section-CmoBsSpY.js +1 -0
  9. package/dist/web/assets/ai-settings-section-DjbYj4wK.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-vLmakLtA.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-CLRlS8Jc.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-CCwVu5F5.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-CvWYcbwD.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-DzuDuyE_.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-D4XGEDHm.js +1 -0
  40. package/dist/web/assets/diff-viewer-B5N1X61R.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-BxLLjthF.js +2 -0
  50. package/dist/web/assets/explorer-window-content-CL1Cipj3.js +1 -0
  51. package/dist/web/assets/extension-manager-section-BpyGq15A.js +1 -0
  52. package/dist/web/assets/{extension-webview-BSh6KGd7.js → extension-webview-BM8FXhuN.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-B0_aR1nL.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-C1EJzjhU.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-D1yGTUE_.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-Cu0STKML.js} +12 -12
  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-BfcvkRX5.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-B1bzKRjJ.js +52 -0
  81. package/dist/web/assets/index-nP3uxXvR.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-DZh-Z2MK.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-CFwgcnpZ.js +1 -0
  90. package/dist/web/assets/keyboard-shortcuts-section-JBtcJGM3.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-dbLIvU2M.js → markdown-renderer-Bo8GgGXl.js} +3 -3
  95. package/dist/web/assets/markdown-renderer-DY60UZNW.js +1 -0
  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-C59rPw7Z.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-Bd6L0K_Q.js +1 -0
  105. package/dist/web/assets/notifications-settings-section-ARQlF-6E.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-CRShdbBS.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-BNT-4yYl.js} +3 -3
  115. package/dist/web/assets/power-CriQkeK5.js +1 -0
  116. package/dist/web/assets/ppmbot-settings-section-Bq4YAcFW.js +1 -0
  117. package/dist/web/assets/{process-table-kmQ2-8qJ.js → process-table-CjiXW0rg.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-wRbiyQiA.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-C5RmhRSu.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-BF-75_03.js +2 -0
  126. package/dist/web/assets/remote-desktop-mobile-view-C9KR9I9G.js +1 -0
  127. package/dist/web/assets/remote-desktop-readiness-gate-BnKJicB2.js +1 -0
  128. package/dist/web/assets/remote-desktop-window-content-awXsNw_R.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-BOecKJzl.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-DGi5DXY6.js +2 -0
  139. package/dist/web/assets/settings-store-Brjd0QnO.js +2 -0
  140. package/dist/web/assets/settings-tab-GM9zTRul.js +1 -0
  141. package/dist/web/assets/settings-window-content-Dvhxo4_H.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-BmkGFzcL.js +1 -0
  147. package/dist/web/assets/sqlite-viewer-DbziVQXQ.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-CbHW5aYm.js +2 -0
  152. package/dist/web/assets/system-monitor-tab-C7EZLMIo.js +1 -0
  153. package/dist/web/assets/{system-monitor-window-content-B9Y98UW6.js → system-monitor-window-content-C_w4w81e.js} +1 -1
  154. package/dist/web/assets/{tab-host-window-content-C1j8zr68.js → tab-host-window-content-BSP1SEXS.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-C9N0iA1-.js +2 -0
  157. package/dist/web/assets/team-member-window-content-CM2QFv-s.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-jWYELm8y.js} +3 -3
  160. package/dist/web/assets/{tex--c4POEUE.js → tex-BTIqPw_R.js} +1 -1
  161. package/dist/web/assets/tool-cards-jefdOWVJ.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-MhMl0Y4Z.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-BbAd7DXr.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-DlfMIWq3.js +1 -0
  170. package/dist/web/assets/{use-websocket-xOOwBdwP.js → use-websocket-Bq8X_SUI.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-BGh3B0Lu.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/proxy-agent-anthropic-bridge.ts +93 -0
  219. package/src/services/proxy-agent-bridge.ts +100 -0
  220. package/src/services/proxy-agent-turn.ts +161 -0
  221. package/src/services/proxy-anthropic-format.ts +157 -0
  222. package/src/services/proxy-openai-format.ts +148 -0
  223. package/src/services/slash-discovery/builtin-commands.ts +13 -0
  224. package/src/services/slash-discovery/codex-skill-items.ts +57 -0
  225. package/src/services/slash-discovery/provider-skill-sigil.ts +19 -0
  226. package/src/services/slash-discovery/types.ts +19 -0
  227. package/src/services/windows-process-tree.ts +351 -351
  228. package/src/types/chat.ts +7 -1
  229. package/src/web/app.tsx +1 -7
  230. package/src/web/components/chat/chat-history-bar.tsx +10 -1
  231. package/src/web/components/chat/chat-tab.tsx +17 -1
  232. package/src/web/components/chat/message-input.tsx +11 -4
  233. package/src/web/components/chat/message-list.tsx +14 -0
  234. package/src/web/components/chat/slash-command-picker.tsx +22 -3
  235. package/src/web/components/chat/tool-cards.tsx +47 -4
  236. package/src/web/components/chat/usage-badge.tsx +59 -426
  237. package/src/web/components/floating-window/window-content-registry.ts +2 -0
  238. package/src/web/components/floating-window/window-store-types.ts +1 -1
  239. package/src/web/components/layout/command-palette.tsx +2 -2
  240. package/src/web/components/layout/mobile-drawer.tsx +5 -4
  241. package/src/web/components/layout/mobile-nav.tsx +5 -1
  242. package/src/web/components/layout/nav-section-rail.tsx +2 -1
  243. package/src/web/components/layout/project-bottom-sheet.tsx +3 -9
  244. package/src/web/components/layout/sidebar.tsx +0 -2
  245. package/src/web/components/layout/tab-pop-out-menu-item.tsx +3 -2
  246. package/src/web/components/settings/accounts/account-add-dialog.tsx +155 -0
  247. package/src/web/components/settings/accounts/account-backup-format.ts +19 -0
  248. package/src/web/components/settings/accounts/account-bucket-row.tsx +55 -0
  249. package/src/web/components/settings/accounts/account-card.tsx +151 -0
  250. package/src/web/components/settings/accounts/account-delete-confirm.tsx +62 -0
  251. package/src/web/components/settings/accounts/account-export-dialog.tsx +154 -0
  252. package/src/web/components/settings/accounts/account-export-simulation.tsx +196 -0
  253. package/src/web/components/settings/accounts/account-import-dialog.tsx +72 -0
  254. package/src/web/components/settings/accounts/account-profile-panel.tsx +52 -0
  255. package/src/web/components/{chat → settings/accounts}/account-rotation-settings.tsx +1 -1
  256. package/src/web/components/settings/accounts/account-token-test-dialog.tsx +147 -0
  257. package/src/web/components/settings/accounts/account-usage-format.ts +92 -0
  258. package/src/web/components/{chat/usage-pattern-chart.tsx → settings/accounts/account-usage-pattern-chart.tsx} +1 -1
  259. package/src/web/components/settings/accounts/accounts-pane-header.tsx +113 -0
  260. package/src/web/components/settings/accounts/accounts-settings-section.tsx +80 -0
  261. package/src/web/components/settings/accounts/claude-accounts-section.tsx +169 -0
  262. package/src/web/components/settings/accounts/codex-accounts-section.tsx +144 -0
  263. package/src/web/components/settings/accounts/codex-add-account-dialog.tsx +130 -0
  264. package/src/web/components/settings/accounts/codex-backup-dialog.tsx +101 -0
  265. package/src/web/components/settings/accounts/codex-rotation-dialog.tsx +65 -0
  266. package/src/web/components/settings/accounts/use-accounts-data.ts +81 -0
  267. package/src/web/components/settings/accounts/use-codex-accounts.ts +151 -0
  268. package/src/web/components/settings/ai-settings-section.tsx +14 -4
  269. package/src/web/components/settings/appearance-settings-section.tsx +125 -0
  270. package/src/web/components/settings/general-settings-section.tsx +87 -0
  271. package/src/web/components/settings/jira-watcher-section.tsx +34 -0
  272. package/src/web/components/settings/notifications-settings-section.tsx +37 -0
  273. package/src/web/components/settings/open-settings.ts +42 -0
  274. package/src/web/components/settings/resolve-open-settings-action.ts +45 -0
  275. package/src/web/components/settings/settings-body.tsx +110 -0
  276. package/src/web/components/settings/settings-categories.ts +102 -0
  277. package/src/web/components/settings/settings-category-list.tsx +56 -0
  278. package/src/web/components/settings/settings-category-rail.tsx +62 -0
  279. package/src/web/components/settings/settings-section-content.tsx +43 -0
  280. package/src/web/components/settings/settings-tab.tsx +15 -329
  281. package/src/web/components/settings/settings-window-content.tsx +24 -0
  282. package/src/web/hooks/use-chat.ts +38 -1
  283. package/src/web/hooks/use-global-keybindings.ts +3 -4
  284. package/src/web/hooks/use-url-sync.ts +30 -0
  285. package/src/web/hooks/use-usage.ts +23 -11
  286. package/src/web/lib/sidebar-tabs/tab-registry.ts +9 -9
  287. package/src/web/lib/slash-items-cache.ts +27 -7
  288. package/src/web/stores/panel-utils.ts +11 -0
  289. package/src/web/stores/settings-store.ts +4 -2
  290. package/src/web/stores/window-panel-actions.ts +1 -3
  291. package/src/web/stores/window-panel-persistence.ts +9 -4
  292. package/dist/web/assets/adaptive-context-menu-BbuRVTLn.js +0 -1
  293. package/dist/web/assets/ai-resource-editor-BCCOUzox.js +0 -1
  294. package/dist/web/assets/ai-settings-section-BEM1z7kp.js +0 -1
  295. package/dist/web/assets/api-client-D1CePgQ4.js +0 -1
  296. package/dist/web/assets/api-settings-CNtKkHqW.js +0 -1
  297. package/dist/web/assets/api-settings-Cubuqjsu.js +0 -1
  298. package/dist/web/assets/architecture-PBZL5I3N-6konx-J1.js +0 -1
  299. package/dist/web/assets/chat-tab-CmXGsJGc.js +0 -15
  300. package/dist/web/assets/clipboard-B-gwJ8DF.js +0 -1
  301. package/dist/web/assets/code-editor-DtHXzNZ1.js +0 -7
  302. package/dist/web/assets/context-menu-DfWZAxQy.js +0 -1
  303. package/dist/web/assets/database-viewer-GVaQVMdb.js +0 -1
  304. package/dist/web/assets/dialog-BSfuiTkJ.js +0 -1
  305. package/dist/web/assets/diff-viewer-BG5_fH1E.js +0 -4
  306. package/dist/web/assets/explorer-body-BPFnjxYj.js +0 -2
  307. package/dist/web/assets/explorer-window-content-Da1T9uM4.js +0 -1
  308. package/dist/web/assets/extension-store-Bhu--fPX.js +0 -1
  309. package/dist/web/assets/external-link-B6Hl0U4X.js +0 -1
  310. package/dist/web/assets/eye-off-CUdzgmX8.js +0 -1
  311. package/dist/web/assets/file-store-6HW2Lfl4.js +0 -1
  312. package/dist/web/assets/git-log-panel-DNC9fV0M.js +0 -1
  313. package/dist/web/assets/gitGraph-HDMCJU4V-ikUwsekd.js +0 -1
  314. package/dist/web/assets/group-chat-tab-DbUkcOaJ.js +0 -1
  315. package/dist/web/assets/index-DTqbMiVc.js +0 -52
  316. package/dist/web/assets/index-SFFv2-VM.css +0 -2
  317. package/dist/web/assets/info-3K5VOQVL-BAgmboBp.js +0 -1
  318. package/dist/web/assets/input-D0ol5jW0.js +0 -1
  319. package/dist/web/assets/keybindings-store-BGkB72gM.js +0 -1
  320. package/dist/web/assets/keybindings-store-Bq6VWl5X.js +0 -1
  321. package/dist/web/assets/lock-CNxUGpTk.js +0 -1
  322. package/dist/web/assets/markdown-renderer-DEAVpo0C.js +0 -1
  323. package/dist/web/assets/mobile-explorer-sheet-CD_kl-jA.js +0 -1
  324. package/dist/web/assets/monitor-smartphone-DLZ6Q05s.js +0 -1
  325. package/dist/web/assets/notification-store-Dgbsw9p9.js +0 -1
  326. package/dist/web/assets/packet-RMMSAZCW-RVlbbDRS.js +0 -1
  327. package/dist/web/assets/panel-store-UOV8wrfR.js +0 -1
  328. package/dist/web/assets/pdf-preview-B2CJ_EKv.js +0 -1
  329. package/dist/web/assets/pie-UPGHQEXC-ZWb4izpk.js +0 -1
  330. package/dist/web/assets/play-DpEEBJTT.js +0 -1
  331. package/dist/web/assets/radar-KQ55EAFF-bsP5x1Bx.js +0 -1
  332. package/dist/web/assets/refresh-cw-BQU5g2CY.js +0 -1
  333. package/dist/web/assets/remote-desktop-mobile-sheet-KKTRNjOL.js +0 -2
  334. package/dist/web/assets/remote-desktop-mobile-view-C1ST4-Fm.js +0 -1
  335. package/dist/web/assets/remote-desktop-readiness-gate-BH3BE5wA.js +0 -1
  336. package/dist/web/assets/remote-desktop-window-content-BaZJQt_N.js +0 -1
  337. package/dist/web/assets/rotate-ccw-CpjRo90J.js +0 -1
  338. package/dist/web/assets/scroll-area-lc0ZHORr.js +0 -1
  339. package/dist/web/assets/send-C_sLFt56.js +0 -1
  340. package/dist/web/assets/settings-store-zbPkG7o-.js +0 -2
  341. package/dist/web/assets/settings-tab-Cn-AqUP_.js +0 -1
  342. package/dist/web/assets/settings-tab-xyRpt2gq.js +0 -3
  343. package/dist/web/assets/shallow-CmPMAPte.js +0 -1
  344. package/dist/web/assets/sql-query-editor-B86NiZHI.js +0 -1
  345. package/dist/web/assets/sqlite-viewer-DB775F6C.js +0 -1
  346. package/dist/web/assets/switch-BmjKoIpR.js +0 -1
  347. package/dist/web/assets/system-monitor-body-BDxHQvy9.js +0 -2
  348. package/dist/web/assets/system-monitor-tab-BoTHLx6B.js +0 -1
  349. package/dist/web/assets/team-member-sheet-Cxz6h5Ne.js +0 -2
  350. package/dist/web/assets/team-member-window-content-CUSuRHCB.js +0 -1
  351. package/dist/web/assets/tool-cards-D3KSzd2K.js +0 -8
  352. package/dist/web/assets/trash-2-By4VMbC4.js +0 -1
  353. package/dist/web/assets/treemap-KZPCXAKY-Dh1oxNdQ.js +0 -1
  354. package/dist/web/assets/triangle-alert-CUTURFbG.js +0 -1
  355. package/dist/web/assets/upload-BNlX8D07.js +0 -1
  356. package/dist/web/assets/use-monaco-theme-CVCye2kq.js +0 -1
  357. package/dist/web/assets/use-remote-desktop-display-choice-neUqyE3p.js +0 -1
  358. package/dist/web/assets/video-preview-DvpgBDhM.js +0 -1
  359. package/dist/web/assets/window-store-D0x_fxr0.js +0 -1
  360. package/src/web/components/chat/account-dialogs.tsx +0 -384
  361. package/src/web/components/settings/accounts-settings-section.tsx +0 -1090
  362. package/src/web/components/settings/codex-accounts-section.tsx +0 -198
  363. package/src/web/components/settings/telegram-settings-section.tsx +0 -113
  364. /package/dist/web/assets/{abap-C5DFF0s3.js → abap-h3QyH8MW.js} +0 -0
  365. /package/dist/web/assets/{actionscript-3-B0qyRNbc.js → actionscript-3-mkxkq-FN.js} +0 -0
  366. /package/dist/web/assets/{ada-bAJzplug.js → ada-DhISK_EH.js} +0 -0
  367. /package/dist/web/assets/{andromeeda-DUCpISy6.js → andromeeda-DnlWWesX.js} +0 -0
  368. /package/dist/web/assets/{apache-BhAr84Z_.js → apache-P5AK3sfA.js} +0 -0
  369. /package/dist/web/assets/{apex-CRv8YnNq.js → apex-CJUPehg2.js} +0 -0
  370. /package/dist/web/assets/{api-client-BzWM7XPR.js → api-client-oY1tC3tM.js} +0 -0
  371. /package/dist/web/assets/{applescript-CD-Cw8bt.js → applescript-Dx6GGbay.js} +0 -0
  372. /package/dist/web/assets/{apply-theme-DJ794zSQ.js → apply-theme-DxTXOAcV.js} +0 -0
  373. /package/dist/web/assets/{ara-BUzeQYoG.js → ara-95Kx3qKb.js} +0 -0
  374. /package/dist/web/assets/{asciidoc-CT2hTg-v.js → asciidoc-Dp0RbIej.js} +0 -0
  375. /package/dist/web/assets/{asm-CAu35JeY.js → asm-C82coUjU.js} +0 -0
  376. /package/dist/web/assets/{aurora-x-BeFJoIA1.js → aurora-x-BFc3zeop.js} +0 -0
  377. /package/dist/web/assets/{awk-Vau-DrGN.js → awk-ChjC0icr.js} +0 -0
  378. /package/dist/web/assets/{ayu-dark-CLe-OTsQ.js → ayu-dark-DYfUf_PB.js} +0 -0
  379. /package/dist/web/assets/{ayu-light-CJbQfu4M.js → ayu-light-Bh6O0plO.js} +0 -0
  380. /package/dist/web/assets/{ayu-mirage-GWaKwdrx.js → ayu-mirage-DlNhHTGq.js} +0 -0
  381. /package/dist/web/assets/{ballerina-DWu0USI5.js → ballerina-Ceoll3Sk.js} +0 -0
  382. /package/dist/web/assets/{bat-_07Huw7E.js → bat-C7QS6Lfq.js} +0 -0
  383. /package/dist/web/assets/{beancount-EcvogrcF.js → beancount-5NMEAZgs.js} +0 -0
  384. /package/dist/web/assets/{berry-BBB87SY7.js → berry-BBL83Vbk.js} +0 -0
  385. /package/dist/web/assets/{bibtex-DbueS87A.js → bibtex-L7rPkPSG.js} +0 -0
  386. /package/dist/web/assets/{bicep-tcmXnUo4.js → bicep-BOwHIINh.js} +0 -0
  387. /package/dist/web/assets/{bird2-B2qwilIR.js → bird2-CWLsMom2.js} +0 -0
  388. /package/dist/web/assets/{c-Z58oivSt.js → c-CD4Ku5Cr.js} +0 -0
  389. /package/dist/web/assets/{c3-U40cGT9p.js → c3-CpMl-w3G.js} +0 -0
  390. /package/dist/web/assets/{cadence-BFcD-LyM.js → cadence-CvgF6ehN.js} +0 -0
  391. /package/dist/web/assets/{can-open-in-ppm-CdCK2c2a.js → can-open-in-ppm-j3jh7fUo.js} +0 -0
  392. /package/dist/web/assets/{catppuccin-frappe-RkC9AX6J.js → catppuccin-frappe-eo_dTm3F.js} +0 -0
  393. /package/dist/web/assets/{catppuccin-latte-Bsi4l-nO.js → catppuccin-latte-DoiMCU_7.js} +0 -0
  394. /package/dist/web/assets/{catppuccin-macchiato-B8JIdTW-.js → catppuccin-macchiato-UQxsK2Vh.js} +0 -0
  395. /package/dist/web/assets/{catppuccin-mocha-oH8wwrDj.js → catppuccin-mocha-J0i-8RNy.js} +0 -0
  396. /package/dist/web/assets/{clarity-C3WNeRCR.js → clarity-DXYM8-SA.js} +0 -0
  397. /package/dist/web/assets/{clojure-CFoAz7u9.js → clojure-DzamsL69.js} +0 -0
  398. /package/dist/web/assets/{cmake-Bcsqp9yR.js → cmake-CR6RP_T_.js} +0 -0
  399. /package/dist/web/assets/{codeowners-DC2Z7heP.js → codeowners-D1s6-IyY.js} +0 -0
  400. /package/dist/web/assets/{codeql-BfG68Al5.js → codeql-DAqNWMkS.js} +0 -0
  401. /package/dist/web/assets/{common-lisp-Z5P-lKQe.js → common-lisp-8e-KtitB.js} +0 -0
  402. /package/dist/web/assets/{coq-BJslqrnv.js → coq-UEq0WUcO.js} +0 -0
  403. /package/dist/web/assets/{csharp-DhhZTOTs.js → csharp-wxJ0TuCm.js} +0 -0
  404. /package/dist/web/assets/{css-DiFIpMfE.js → css-Cerub-yB.js} +0 -0
  405. /package/dist/web/assets/{csv-DViLbHxI.js → csv-Bh9_WD_h.js} +0 -0
  406. /package/dist/web/assets/{csv-parser-B2v8MoUy.js → csv-parser-BPIDt6ni.js} +0 -0
  407. /package/dist/web/assets/{cue-CoG3mg2I.js → cue-rzM1ztqU.js} +0 -0
  408. /package/dist/web/assets/{cypher-jTxC8NAB.js → cypher-DGaTQ8m0.js} +0 -0
  409. /package/dist/web/assets/{d-6hKIUAbU.js → d-DbkZGuhB.js} +0 -0
  410. /package/dist/web/assets/{dark-plus-D_-np2Sr.js → dark-plus-BO2bzZcA.js} +0 -0
  411. /package/dist/web/assets/{dart-CVpxLpVn.js → dart-BDhCoqVg.js} +0 -0
  412. /package/dist/web/assets/{data-grid-types-Dq_H1IPa.js → data-grid-types-CdAg-4W1.js} +0 -0
  413. /package/dist/web/assets/{dax-BPqJ8qIY.js → dax-Bh03stWh.js} +0 -0
  414. /package/dist/web/assets/{desktop-u_y5_Hr5.js → desktop-BOdr_fwq.js} +0 -0
  415. /package/dist/web/assets/{diff-Duj1XMrd.js → diff-Bb_gTsS2.js} +0 -0
  416. /package/dist/web/assets/{dist-CEZ4plgH.js → dist-BUMDu0av.js} +0 -0
  417. /package/dist/web/assets/{dist-aDSxTR_v.js → dist-DonmFWG8.js} +0 -0
  418. /package/dist/web/assets/{docker-8UGSCc7N.js → docker-BDsTF5ce.js} +0 -0
  419. /package/dist/web/assets/{dotenv-DVnj8kyR.js → dotenv-CbCWp9Ti.js} +0 -0
  420. /package/dist/web/assets/{dracula-D0cEmSg7.js → dracula-Cd1fxvoX.js} +0 -0
  421. /package/dist/web/assets/{dracula-soft-DfGS5Yfr.js → dracula-soft-B7eXkfXG.js} +0 -0
  422. /package/dist/web/assets/{dream-maker-qG8kMGTF.js → dream-maker-XlzuS21R.js} +0 -0
  423. /package/dist/web/assets/{emacs-lisp-iVqyMLyT.js → emacs-lisp-CXV1Ki_7.js} +0 -0
  424. /package/dist/web/assets/{everforest-dark-Cruygd5U.js → everforest-dark-DuqR60Dg.js} +0 -0
  425. /package/dist/web/assets/{everforest-light-BiJa8RHL.js → everforest-light-q4BPnenD.js} +0 -0
  426. /package/dist/web/assets/{fennel-H6XSEIoz.js → fennel-B-e0TX2Q.js} +0 -0
  427. /package/dist/web/assets/{fish-ho_7CxX6.js → fish-Bzb6-TtF.js} +0 -0
  428. /package/dist/web/assets/{fluent-1l5ssJTF.js → fluent-B-szH2-f.js} +0 -0
  429. /package/dist/web/assets/{folder-symlink-Dx1hOk8X.js → folder-symlink-fQRoG_rV.js} +0 -0
  430. /package/dist/web/assets/{format-bytes-gQw5wzqa.js → format-bytes-CKXk9k2d.js} +0 -0
  431. /package/dist/web/assets/{fortran-free-form-Bo1x233A.js → fortran-free-form-OS6SGYC0.js} +0 -0
  432. /package/dist/web/assets/{gdscript-DffFMp_k.js → gdscript-FYq4OP2d.js} +0 -0
  433. /package/dist/web/assets/{gdshader-CvnpAiAF.js → gdshader-BpG6P8rw.js} +0 -0
  434. /package/dist/web/assets/{genie-2eOvAEzW.js → genie-BS9RLAna.js} +0 -0
  435. /package/dist/web/assets/{gherkin-DL-5OUlV.js → gherkin-B_9FdtGs.js} +0 -0
  436. /package/dist/web/assets/{github-dark-DrTZprgG.js → github-dark-cfaIlnBV.js} +0 -0
  437. /package/dist/web/assets/{github-dark-default-_mDH8IMP.js → github-dark-default-B2Wv65He.js} +0 -0
  438. /package/dist/web/assets/{github-dark-dimmed-C48hJuLn.js → github-dark-dimmed-CtM9X76s.js} +0 -0
  439. /package/dist/web/assets/{github-dark-high-contrast-BQ-zGGNe.js → github-dark-high-contrast-DLHyk0tG.js} +0 -0
  440. /package/dist/web/assets/{github-light-BYc90Yx8.js → github-light-DWEI10iG.js} +0 -0
  441. /package/dist/web/assets/{github-light-default-Daecj4J5.js → github-light-default-DcJkK1YN.js} +0 -0
  442. /package/dist/web/assets/{github-light-high-contrast-DoafCbsU.js → github-light-high-contrast-Bcx9iKDt.js} +0 -0
  443. /package/dist/web/assets/{gleam-hUWWjmnp.js → gleam-DVpiM6b2.js} +0 -0
  444. /package/dist/web/assets/{gn-7PJ3R70o.js → gn-B80DNc0i.js} +0 -0
  445. /package/dist/web/assets/{gnuplot-V-Pxck7b.js → gnuplot-D9i3MaT-.js} +0 -0
  446. /package/dist/web/assets/{go-ARF6DprD.js → go-CwCBf_Pt.js} +0 -0
  447. /package/dist/web/assets/{groovy-CKGBIPOz.js → groovy-D7mEfwmW.js} +0 -0
  448. /package/dist/web/assets/{gruvbox-dark-hard-Cm9wqdI3.js → gruvbox-dark-hard-C4R4MOoH.js} +0 -0
  449. /package/dist/web/assets/{gruvbox-dark-medium-Cmsd6dG8.js → gruvbox-dark-medium-CZnFC0s8.js} +0 -0
  450. /package/dist/web/assets/{gruvbox-dark-soft-BBGlGGCz.js → gruvbox-dark-soft-DFcJlEBl.js} +0 -0
  451. /package/dist/web/assets/{gruvbox-light-hard-BCR7KmqG.js → gruvbox-light-hard-B6IF_1L-.js} +0 -0
  452. /package/dist/web/assets/{gruvbox-light-medium-CP32bga8.js → gruvbox-light-medium-C19AZJv2.js} +0 -0
  453. /package/dist/web/assets/{gruvbox-light-soft-qjxk8ps6.js → gruvbox-light-soft-BAnpDm9B.js} +0 -0
  454. /package/dist/web/assets/{haskell-C5DzwGRa.js → haskell-CsXSYXRG.js} +0 -0
  455. /package/dist/web/assets/{haxe-C8f_jCVv.js → haxe-B1uyiI9t.js} +0 -0
  456. /package/dist/web/assets/{hcl-DetJkf6E.js → hcl-DlYKn5q9.js} +0 -0
  457. /package/dist/web/assets/{hjson-DeZhwIdo.js → hjson-C_0VMGJJ.js} +0 -0
  458. /package/dist/web/assets/{hlsl-SMIDLRyX.js → hlsl-zt2PEzbg.js} +0 -0
  459. /package/dist/web/assets/{horizon-BMAVDxMx.js → horizon-6wQfyOK0.js} +0 -0
  460. /package/dist/web/assets/{horizon-bright-3BaV_VGD.js → horizon-bright-CqI2qTim.js} +0 -0
  461. /package/dist/web/assets/{houston-BWBbEPvb.js → houston-BljpHDoG.js} +0 -0
  462. /package/dist/web/assets/{hy-DcsmE-Nm.js → hy-XzuL55dw.js} +0 -0
  463. /package/dist/web/assets/{image-gallery-Bqb-wjNw.js → image-gallery-Cj8nd4xW.js} +0 -0
  464. /package/dist/web/assets/{imba-CnkgnYMf.js → imba-CqhhjBrP.js} +0 -0
  465. /package/dist/web/assets/{ini-BnvTdau7.js → ini-CiFDi6cY.js} +0 -0
  466. /package/dist/web/assets/{java-BLFACXat.js → java-OsQgTL5-.js} +0 -0
  467. /package/dist/web/assets/{javascript-BKcFWENk.js → javascript-qWAOScxl.js} +0 -0
  468. /package/dist/web/assets/{json-3AJtJADf.js → json-RiAKsaD1.js} +0 -0
  469. /package/dist/web/assets/{json5-DLyDVlwe.js → json5-BeCnS3H2.js} +0 -0
  470. /package/dist/web/assets/{jsonc-B5DgF1jW.js → jsonc-CbTW1Mka.js} +0 -0
  471. /package/dist/web/assets/{jsonl-CV_O71a2.js → jsonl-BLSi_669.js} +0 -0
  472. /package/dist/web/assets/{jsonnet-DZfPLgYz.js → jsonnet-C3xAggou.js} +0 -0
  473. /package/dist/web/assets/{jssm-Cr1zYOsY.js → jssm-CLdiagC9.js} +0 -0
  474. /package/dist/web/assets/{jsx-VN-JS2_q.js → jsx-lYE1lb50.js} +0 -0
  475. /package/dist/web/assets/{kanagawa-dragon-D9CcT3xg.js → kanagawa-dragon-Cd1vcrpD.js} +0 -0
  476. /package/dist/web/assets/{kanagawa-lotus-DLXsB8fr.js → kanagawa-lotus-Dw3QKtk9.js} +0 -0
  477. /package/dist/web/assets/{kanagawa-wave-weDs3Wjz.js → kanagawa-wave-DIq5Zv5G.js} +0 -0
  478. /package/dist/web/assets/{kdl-0XF56jnT.js → kdl-BfDV0825.js} +0 -0
  479. /package/dist/web/assets/{keyboard-DBBaoQSu.js → keyboard-DiOYrs6C.js} +0 -0
  480. /package/dist/web/assets/{kotlin-BPkH9vzk.js → kotlin-DONxR4wD.js} +0 -0
  481. /package/dist/web/assets/{kusto-DMVpADb9.js → kusto-BDP63Fh5.js} +0 -0
  482. /package/dist/web/assets/{laserwave-Cl6T2cGP.js → laserwave-BeBrWApL.js} +0 -0
  483. /package/dist/web/assets/{lean-BvwzQGl1.js → lean-DOZc0N1A.js} +0 -0
  484. /package/dist/web/assets/{less-DI_03xkC.js → less-C3H9NlDv.js} +0 -0
  485. /package/dist/web/assets/{lib-v9x_qXgI.js → lib-xrSJ4EZX.js} +0 -0
  486. /package/dist/web/assets/{libesm-dcbw4_18.js → libesm-DLBE59ul.js} +0 -0
  487. /package/dist/web/assets/{light-plus-hIiIsQN_.js → light-plus-C_kTL608.js} +0 -0
  488. /package/dist/web/assets/{llvm-B5hjjSWc.js → llvm-Dsp27U3P.js} +0 -0
  489. /package/dist/web/assets/{loader-circle-DouKgIXy.js → loader-circle-DPMrnLQ2.js} +0 -0
  490. /package/dist/web/assets/{log-D28raQiE.js → log-BywQaTCy.js} +0 -0
  491. /package/dist/web/assets/{logo-6Cdd4ASb.js → logo-BirJgciO.js} +0 -0
  492. /package/dist/web/assets/{luau-CK9nKpOX.js → luau-Btrz5kJB.js} +0 -0
  493. /package/dist/web/assets/{make-CVnxKCB6.js → make-Kl7nFQrS.js} +0 -0
  494. /package/dist/web/assets/{markdown-B9mMQzD5.js → markdown-qsC4P8S-.js} +0 -0
  495. /package/dist/web/assets/{material-theme-BZSs2o0j.js → material-theme-CC__ui3p.js} +0 -0
  496. /package/dist/web/assets/{material-theme-darker-BeAQBzQ_.js → material-theme-darker-D4FxG2FZ.js} +0 -0
  497. /package/dist/web/assets/{material-theme-lighter-BAe0IXcs.js → material-theme-lighter-zGqiWcxn.js} +0 -0
  498. /package/dist/web/assets/{material-theme-ocean-CiPIf0Np.js → material-theme-ocean-CZIdTTB1.js} +0 -0
  499. /package/dist/web/assets/{material-theme-palenight-DJBb4_XN.js → material-theme-palenight-CEIs0GcK.js} +0 -0
  500. /package/dist/web/assets/{matlab-CY0dbp_s.js → matlab-Cf0aUjN9.js} +0 -0
  501. /package/dist/web/assets/{mdx-DU9zbF7h.js → mdx-CIsXjH86.js} +0 -0
  502. /package/dist/web/assets/{mermaid-UmmjGwdh.js → mermaid-B06WO9Qc.js} +0 -0
  503. /package/dist/web/assets/{min-dark-C59GkzOm.js → min-dark-z8fyp0FT.js} +0 -0
  504. /package/dist/web/assets/{min-light-B9QglrdQ.js → min-light-Dr-qesbW.js} +0 -0
  505. /package/dist/web/assets/{mipsasm-Dc6Jsr_D.js → mipsasm-CWHzYLcE.js} +0 -0
  506. /package/dist/web/assets/{mojo-D5ij-nGW.js → mojo-D9zXrKmv.js} +0 -0
  507. /package/dist/web/assets/{monitor-CxPV_fQI.js → monitor-C835ucWH.js} +0 -0
  508. /package/dist/web/assets/{monokai-QAtE_yCP.js → monokai-4b-AKOpX.js} +0 -0
  509. /package/dist/web/assets/{moonbit-BMtIdiTL.js → moonbit-Dl4dhOZJ.js} +0 -0
  510. /package/dist/web/assets/{move-BB_jMHYZ.js → move-DTYKJmXy.js} +0 -0
  511. /package/dist/web/assets/{narrat-BvvoKGVn.js → narrat-DnvXOS-o.js} +0 -0
  512. /package/dist/web/assets/{nextflow-groovy-CqxtAsnF.js → nextflow-groovy-Di8QnEXg.js} +0 -0
  513. /package/dist/web/assets/{night-owl-CLoE9kjt.js → night-owl-Czh0yq-H.js} +0 -0
  514. /package/dist/web/assets/{night-owl-light-BwIFT5Xd.js → night-owl-light-D_OpZqOR.js} +0 -0
  515. /package/dist/web/assets/{nix-BKlnVT9r.js → nix-2MvcjpK3.js} +0 -0
  516. /package/dist/web/assets/{nord-B7R1KRAK.js → nord-CG_r4cyk.js} +0 -0
  517. /package/dist/web/assets/{nushell-CzUme-NJ.js → nushell-DINskMcU.js} +0 -0
  518. /package/dist/web/assets/{objective-c-D-UKKiOc.js → objective-c-Dv7BIicR.js} +0 -0
  519. /package/dist/web/assets/{objective-cpp-BucWn4Fx.js → objective-cpp-CpqsCxPb.js} +0 -0
  520. /package/dist/web/assets/{ocaml-EJCNXMGo.js → ocaml-DwTsYSmW.js} +0 -0
  521. /package/dist/web/assets/{odin-CEjnRU_3.js → odin-G-4O4k4t.js} +0 -0
  522. /package/dist/web/assets/{one-dark-pro-Bv469NX5.js → one-dark-pro-13Pv5SjI.js} +0 -0
  523. /package/dist/web/assets/{one-light-BlzO5RWI.js → one-light-Bi2e86mS.js} +0 -0
  524. /package/dist/web/assets/{openscad-Czl6alLw.js → openscad-D0WsOTij.js} +0 -0
  525. /package/dist/web/assets/{pascal-BI9fLvG4.js → pascal-DmDStuXr.js} +0 -0
  526. /package/dist/web/assets/{pkl-ChQLsyjU.js → pkl-Bl6Qjtuo.js} +0 -0
  527. /package/dist/web/assets/{plastic-DGL3mtdL.js → plastic-UeSVSjTI.js} +0 -0
  528. /package/dist/web/assets/{plsql-BJDjqcWp.js → plsql-DreFC689.js} +0 -0
  529. /package/dist/web/assets/{po-DK5O3OpF.js → po-ZIjccxsX.js} +0 -0
  530. /package/dist/web/assets/{poimandres-CnuqZT4T.js → poimandres-CvQHJPrI.js} +0 -0
  531. /package/dist/web/assets/{polar-DCsUxSsQ.js → polar-BrMB0Kgh.js} +0 -0
  532. /package/dist/web/assets/{portal-container-context-D-495m5C.js → portal-container-context-a399Hd9F.js} +0 -0
  533. /package/dist/web/assets/{postcss-8UjdFmis.js → postcss-pgUsil1T.js} +0 -0
  534. /package/dist/web/assets/{powerquery-CAp0CGQj.js → powerquery-CTsZkCg_.js} +0 -0
  535. /package/dist/web/assets/{powershell-CbBsKZJP.js → powershell-CcwVuBAp.js} +0 -0
  536. /package/dist/web/assets/{prisma-BnNpXCJN.js → prisma-spjnAI5W.js} +0 -0
  537. /package/dist/web/assets/{prolog-CC-l9E8Y.js → prolog-ChCkZpDO.js} +0 -0
  538. /package/dist/web/assets/{proto-CV_1k2rL.js → proto-wVGqK4gB.js} +0 -0
  539. /package/dist/web/assets/{puppet-2D8HU2bv.js → puppet-CED7iwPQ.js} +0 -0
  540. /package/dist/web/assets/{purescript-BEJAORgU.js → purescript-u9lGiQKV.js} +0 -0
  541. /package/dist/web/assets/{python-BBdbb7nn.js → python-DeqTx6ef.js} +0 -0
  542. /package/dist/web/assets/{qmldir-D5ZYI4Ie.js → qmldir-BH1uoPrX.js} +0 -0
  543. /package/dist/web/assets/{qss-BOJVGyXE.js → qss-CUVKA_13.js} +0 -0
  544. /package/dist/web/assets/{r-B5dlEtkj.js → r-BqdPzqYH.js} +0 -0
  545. /package/dist/web/assets/{racket-BUAEygJ6.js → racket-C2eTgPN3.js} +0 -0
  546. /package/dist/web/assets/{raku-BG0Ss0ID.js → raku-uAay1sWx.js} +0 -0
  547. /package/dist/web/assets/{react-B549sK_T.js → react-X4jUntEf.js} +0 -0
  548. /package/dist/web/assets/{red-C5yyQbtG.js → red-DTZP1ZfC.js} +0 -0
  549. /package/dist/web/assets/{reg-DHoBWtLf.js → reg-Cdk3YsxY.js} +0 -0
  550. /package/dist/web/assets/{regexp-DDtJrlKv.js → regexp-Bpa2aS7K.js} +0 -0
  551. /package/dist/web/assets/{rel-CR6WJDRD.js → rel-bNsb1-3L.js} +0 -0
  552. /package/dist/web/assets/{resolve-theme-4fexHWl6.js → resolve-theme-DQk_YcsT.js} +0 -0
  553. /package/dist/web/assets/{riscv-2V9tC-nx.js → riscv-DSaubByW.js} +0 -0
  554. /package/dist/web/assets/{ron-QLTmqGUw.js → ron-DbQzYM6i.js} +0 -0
  555. /package/dist/web/assets/{rose-pine-be0__X3A.js → rose-pine-C7RsprTu.js} +0 -0
  556. /package/dist/web/assets/{rose-pine-dawn-n_WQJwsW.js → rose-pine-dawn-VP976YzL.js} +0 -0
  557. /package/dist/web/assets/{rose-pine-moon-t2aLtzgB.js → rose-pine-moon-XHZNhOqd.js} +0 -0
  558. /package/dist/web/assets/{rosmsg-Ce1JD8vt.js → rosmsg-BVQlx0Lj.js} +0 -0
  559. /package/dist/web/assets/{rust-5fHH-ZoW.js → rust-VHaQ3rh3.js} +0 -0
  560. /package/dist/web/assets/{sass-DPmGFiOJ.js → sass-CO-kMkwD.js} +0 -0
  561. /package/dist/web/assets/{save-DYLiVzU8.js → save-CipGrG1k.js} +0 -0
  562. /package/dist/web/assets/{scala-BRMVFbZF.js → scala-cY0GXkiz.js} +0 -0
  563. /package/dist/web/assets/{scheme-BMSJWevF.js → scheme-D4LNZE0X.js} +0 -0
  564. /package/dist/web/assets/{sdbl-DTZ-pEHI.js → sdbl-Bh2Fd2cn.js} +0 -0
  565. /package/dist/web/assets/{shellscript-6-9yg5Cz.js → shellscript-KKclmCnt.js} +0 -0
  566. /package/dist/web/assets/{shield-check-CUI36aSc.js → shield-check-BsG3LV8i.js} +0 -0
  567. /package/dist/web/assets/{shield-off-GdkkVhb3.js → shield-off-7jKWpJBD.js} +0 -0
  568. /package/dist/web/assets/{slack-dark-DKJgiR7e.js → slack-dark-D6YQ-fqf.js} +0 -0
  569. /package/dist/web/assets/{slack-ochin-WjehVgyK.js → slack-ochin-CDf66CDj.js} +0 -0
  570. /package/dist/web/assets/{smalltalk-BChf4SN1.js → smalltalk-D2OH_QIl.js} +0 -0
  571. /package/dist/web/assets/{snazzy-light-C1WAwOx6.js → snazzy-light-CQeF8G1K.js} +0 -0
  572. /package/dist/web/assets/{solarized-dark-BxREZrGx.js → solarized-dark-LTPf1iLZ.js} +0 -0
  573. /package/dist/web/assets/{solarized-light-DG29B1pR.js → solarized-light-Ose1n88k.js} +0 -0
  574. /package/dist/web/assets/{solidity-bDbtGwdR.js → solidity-lFuOMHki.js} +0 -0
  575. /package/dist/web/assets/{splunk-Ceqx5njI.js → splunk-Bov-sB5S.js} +0 -0
  576. /package/dist/web/assets/{sql-OwMEKbz8.js → sql-BKyZ6wmk.js} +0 -0
  577. /package/dist/web/assets/{ssh-config-WAR3lu2k.js → ssh-config-CqJoMGMb.js} +0 -0
  578. /package/dist/web/assets/{stylus-Cjmoz3d8.js → stylus-Bf5pWRLI.js} +0 -0
  579. /package/dist/web/assets/{swift-S_ZSBG1q.js → swift-D5d1hn_u.js} +0 -0
  580. /package/dist/web/assets/{synthwave-84-DiUeWMSh.js → synthwave-84-B4c6YAgO.js} +0 -0
  581. /package/dist/web/assets/{system-verilog-RRjqPjUV.js → system-verilog-D7fXyDsI.js} +0 -0
  582. /package/dist/web/assets/{systemd-BD3SkXoU.js → systemd-oNagzlBK.js} +0 -0
  583. /package/dist/web/assets/{table-D5Q4ap4W.js → table-CRJsmfeg.js} +0 -0
  584. /package/dist/web/assets/{talonscript-DWefISOm.js → talonscript-C6Nqm9Dm.js} +0 -0
  585. /package/dist/web/assets/{tasl-DCjSS-09.js → tasl-CaWy-cBX.js} +0 -0
  586. /package/dist/web/assets/{tcl-DTYqT_66.js → tcl-C435P5Mq.js} +0 -0
  587. /package/dist/web/assets/{terraform-CkbP5QnR.js → terraform-CVDxqdPf.js} +0 -0
  588. /package/dist/web/assets/{text-wrap-DBvQD3kc.js → text-wrap-oiekm5SB.js} +0 -0
  589. /package/dist/web/assets/{tokyo-night-qVSqO9xy.js → tokyo-night-Uhs17tQ3.js} +0 -0
  590. /package/dist/web/assets/{toml-D9F5Osqs.js → toml-j6fPOJ6P.js} +0 -0
  591. /package/dist/web/assets/{tsv-C5tpHoxm.js → tsv-h78O6xrL.js} +0 -0
  592. /package/dist/web/assets/{tsx-CMWkGtGm.js → tsx-Bol-vCrQ.js} +0 -0
  593. /package/dist/web/assets/{turtle-Cn4z3xOi.js → turtle-Dw8eFf04.js} +0 -0
  594. /package/dist/web/assets/{typescript-DSyAEWsn.js → typescript-Dtz7DPci.js} +0 -0
  595. /package/dist/web/assets/{typespec-B93Qap7y.js → typespec-BIOQ7dMP.js} +0 -0
  596. /package/dist/web/assets/{typst-DtlOmFlX.js → typst-CoaGMjzu.js} +0 -0
  597. /package/dist/web/assets/{use-is-mobile-B9UZNwSm.js → use-is-mobile-CYW3FJFE.js} +0 -0
  598. /package/dist/web/assets/{use-visual-viewport-Sfb6CZ80.js → use-visual-viewport-rnvuooQZ.js} +0 -0
  599. /package/dist/web/assets/{utils-QHe_Q6UF.js → utils-C9OjCrou.js} +0 -0
  600. /package/dist/web/assets/{v-Dfzf-szS.js → v-BoqFdpJ7.js} +0 -0
  601. /package/dist/web/assets/{vala-CyiQZQ9f.js → vala-COBpNnCC.js} +0 -0
  602. /package/dist/web/assets/{vb-C7DGSldd.js → vb-DxI86znh.js} +0 -0
  603. /package/dist/web/assets/{vendor-xterm-BHKF_Nsf.js → vendor-xterm-BaMOj65g.js} +0 -0
  604. /package/dist/web/assets/{verilog-kF-hClY2.js → verilog-DcTAamuQ.js} +0 -0
  605. /package/dist/web/assets/{vesper-BmKcADuz.js → vesper-DO298JSv.js} +0 -0
  606. /package/dist/web/assets/{vhdl-CDnb16KJ.js → vhdl-Dq-bDVSN.js} +0 -0
  607. /package/dist/web/assets/{viml-B8cs6Ady.js → viml-zHTRWuQh.js} +0 -0
  608. /package/dist/web/assets/{vitesse-black-BR6o9Gto.js → vitesse-black-jlYMJCBf.js} +0 -0
  609. /package/dist/web/assets/{vitesse-dark-Dye14-KB.js → vitesse-dark-DS0sUlSZ.js} +0 -0
  610. /package/dist/web/assets/{vitesse-light-BLpswIxf.js → vitesse-light-HSeZ2YhG.js} +0 -0
  611. /package/dist/web/assets/{vyper-DU51Z97W.js → vyper-BQfKVO3M.js} +0 -0
  612. /package/dist/web/assets/{wasm-ChtccNfv.js → wasm-B1xp9bLp.js} +0 -0
  613. /package/dist/web/assets/{wasm-CVqlJAR2.js → wasm-B6mCuI8h.js} +0 -0
  614. /package/dist/web/assets/{wenyan-DhCa3hCn.js → wenyan-CfpS05sP.js} +0 -0
  615. /package/dist/web/assets/{wgsl-Bj1Ec4vv.js → wgsl-14GDsWRD.js} +0 -0
  616. /package/dist/web/assets/{wikitext-C90DHNa0.js → wikitext-Ccbq5EVX.js} +0 -0
  617. /package/dist/web/assets/{wit-DUgbOD7Z.js → wit-C19hb3R5.js} +0 -0
  618. /package/dist/web/assets/{wolfram-BgwUqD1I.js → wolfram-B-ZSwGwP.js} +0 -0
  619. /package/dist/web/assets/{x-DiOUR_mp.js → x-YDu4m2Iq.js} +0 -0
  620. /package/dist/web/assets/{yaml-DEQulj-8.js → yaml-mw_JUeio.js} +0 -0
  621. /package/dist/web/assets/{zenscript-C7Jp7TgT.js → zenscript-WbzDRjvF.js} +0 -0
  622. /package/dist/web/assets/{zig-9x4qXYLg.js → zig-F0vvImTJ.js} +0 -0
@@ -27,6 +27,35 @@ function asObj(v: unknown): Record<string, unknown> {
27
27
  return (v && typeof v === "object") ? (v as Record<string, unknown>) : {};
28
28
  }
29
29
 
30
+ /**
31
+ * The command text to SHOW for a commandExecution item.
32
+ *
33
+ * A commandExecution carries the same command twice. `command` is what codex
34
+ * hands its exec layer: the interpreter wrapped around the script, with every
35
+ * backslash in the interpreter path doubled (`C:\\Windows\\System32\\…`), so
36
+ * rendering it puts `\\` in front of the user. `commandActions[].command` is
37
+ * the unwrapped script — single backslashes, no interpreter prefix — which is
38
+ * the part a reader actually cares about.
39
+ *
40
+ * Un-escaping `command` instead would be wrong: a legitimate bash script can
41
+ * contain a real `\\` (regex, escaped path), and rewriting that corrupts the
42
+ * command the user is being shown.
43
+ *
44
+ * Multiple actions are joined by newline; an item with none (or with blank
45
+ * ones) falls back to the wrapped form, because showing the doubled path still
46
+ * beats showing an empty card.
47
+ */
48
+ export function commandDisplayText(item: Item): string {
49
+ const raw = String(item.command ?? "");
50
+ const actions = Array.isArray(item.commandActions) ? item.commandActions : [];
51
+ const parts: string[] = [];
52
+ for (const a of actions) {
53
+ const cmd = asObj(a).command;
54
+ if (typeof cmd === "string" && cmd.trim()) parts.push(cmd);
55
+ }
56
+ return parts.length > 0 ? parts.join("\n") : raw;
57
+ }
58
+
30
59
  /** Build the tool_use input payload from a ThreadItem (per-variant fields). */
31
60
  export function itemToToolUse(item: Item): ChatEvent {
32
61
  const type = item.type ?? "tool";
@@ -35,10 +64,11 @@ export function itemToToolUse(item: Item): ChatEvent {
35
64
  switch (type) {
36
65
  case "commandExecution": {
37
66
  // Map to PPM's canonical shell tools so the chat UI renders the command
38
- // (not a raw `commandExecution` JSON blob). Sniff PowerShell vs Bash.
39
- const command = String(item.command ?? "");
40
- tool = /powershell|pwsh/i.test(command) ? "PowerShell" : "Bash";
41
- input = { command, cwd: item.cwd };
67
+ // (not a raw `commandExecution` JSON blob). Sniff PowerShell vs Bash from
68
+ // the WRAPPED form the interpreter only appears there, never in the
69
+ // unwrapped script that gets displayed.
70
+ tool = /powershell|pwsh/i.test(String(item.command ?? "")) ? "PowerShell" : "Bash";
71
+ input = { command: commandDisplayText(item), cwd: item.cwd };
42
72
  break;
43
73
  }
44
74
  case "fileChange": {
@@ -65,6 +95,24 @@ export function itemToToolUse(item: Item): ChatEvent {
65
95
  tool = "WebSearch";
66
96
  input = { query: item.query };
67
97
  break;
98
+ case "imageGeneration":
99
+ // The item carries the finished PNG twice: `result` is the whole file as
100
+ // base64 (~1.2 MB for a 917 KB image) and `savedPath` points at the copy
101
+ // codex already wrote to disk. Only the path is kept. `result` must never
102
+ // reach a ChatEvent — the event is held in the in-RAM turnEvents buffer,
103
+ // appended to the session JSONL, and broadcast to every connected client,
104
+ // so carrying the payload would cost all three that megabyte per image
105
+ // to display a picture that is already readable from `savedPath`.
106
+ //
107
+ // `file_path` (not `savedPath`) is deliberate: it is the key the chat's
108
+ // image-preview path check already reads, so the thumbnail comes for free.
109
+ tool = "ImageGen";
110
+ input = {
111
+ file_path: item.savedPath ?? null,
112
+ prompt: item.revisedPrompt ?? null,
113
+ transparentBackground: item.transparentBackground ?? false,
114
+ };
115
+ break;
68
116
  default:
69
117
  input = item;
70
118
  }
@@ -92,6 +140,13 @@ export function itemToToolResult(item: Item): ChatEvent {
92
140
  } else if (type === "dynamicToolCall") {
93
141
  output = redactTruncate(item.contentItems ?? "");
94
142
  isError = item.success === false;
143
+ } else if (type === "imageGeneration") {
144
+ // Same reason as the tool_use side: never let the base64 `result` through.
145
+ // Falling to the generic branch below would emit 8 KB of truncated base64
146
+ // as the visible result text.
147
+ const failure = item.failure;
148
+ isError = failure != null;
149
+ output = isError ? redactTruncate(failure) : String(item.savedPath ?? "generated");
95
150
  } else {
96
151
  output = redactTruncate(item);
97
152
  }
@@ -127,7 +182,17 @@ export function mapCodexEvent(notif: Notif, sessionId: string): ChatEvent[] {
127
182
  case "item/completed": {
128
183
  const item = asObj(p.item) as Item;
129
184
  if (item.type === "contextCompaction") return [{ type: "system", subtype: "compact_done" }];
130
- if (item.type && !NON_TOOL_ITEM_TYPES.has(item.type)) return [itemToToolResult(item)];
185
+ if (item.type && !NON_TOOL_ITEM_TYPES.has(item.type)) {
186
+ // Image generation is announced before the picture exists: at `started`
187
+ // there is no saved file and no revised prompt, so the call it produced
188
+ // can show neither. The finished item carries both, so re-emit the call
189
+ // alongside its result — the chat replaces the card by tool-use id.
190
+ // Other tools describe themselves fully at `started`; re-sending those
191
+ // would only cost a second event in the buffer, the log and every
192
+ // client's socket.
193
+ if (item.type === "imageGeneration") return [itemToToolUse(item), itemToToolResult(item)];
194
+ return [itemToToolResult(item)];
195
+ }
131
196
  return [];
132
197
  }
133
198
 
@@ -4,6 +4,7 @@ import { join, resolve } from "node:path";
4
4
  import { homedir } from "node:os";
5
5
  import { redactTruncate } from "./codex-redact.ts";
6
6
  import { parseApplyPatch, changeToToolUse } from "./codex-patch.ts";
7
+ import { mapRolloutItem } from "./codex-rollout-items.ts";
7
8
 
8
9
  /**
9
10
  * Independent parser for Codex rollout JSONL transcripts
@@ -110,6 +111,15 @@ export function parseRolloutJsonl(text: string, opts?: { preCompact?: boolean })
110
111
  let i = 0;
111
112
  let pendingEvents: ChatEvent[] = [];
112
113
 
114
+ // Newer codex records every finished step as an `item_completed` event AND
115
+ // keeps the raw model exchange in `response_item` records. Both describe the
116
+ // same tool calls, so taking both renders every command twice — and the
117
+ // response_item copy of an image generation carries the whole PNG as base64,
118
+ // which would land in the transcript. When the item events are present they
119
+ // are the better source: already assembled, already named the way the live
120
+ // stream names them.
121
+ const hasItemEvents = text.includes('"item_completed"');
122
+
113
123
  const flushAssistant = (content: string, ts: string) => {
114
124
  if (!content && pendingEvents.length === 0) return;
115
125
  const events = pendingEvents.length
@@ -131,6 +141,19 @@ export function parseRolloutJsonl(text: string, opts?: { preCompact?: boolean })
131
141
  messages.push({ id: `rollout-${i++}`, role: "user", content: p.message, timestamp: ts });
132
142
  } else if (p.type === "agent_message" && typeof p.message === "string") {
133
143
  flushAssistant(p.message, ts);
144
+ } else if (p.type === "item_completed") {
145
+ // Newer codex writes one item per finished step instead of the
146
+ // user_message/agent_message pair above. Same conversation, different
147
+ // spelling — see codex-rollout-items.
148
+ const mapped = mapRolloutItem(p.item);
149
+ if (mapped.kind === "user") {
150
+ if (pendingEvents.length) flushAssistant("", ts);
151
+ messages.push({ id: `rollout-${i++}`, role: "user", content: mapped.text, timestamp: ts });
152
+ } else if (mapped.kind === "assistant") {
153
+ flushAssistant(mapped.text, ts);
154
+ } else if (mapped.kind === "events") {
155
+ pendingEvents.push(...mapped.events);
156
+ }
134
157
  } else if (p.type === "thread_rolled_back") {
135
158
  // codex doesn't truncate the rollout file on rollback/fork — it appends this
136
159
  // marker. Drop the last `num_turns` turns (by user-message turn-start) so a
@@ -144,6 +167,7 @@ export function parseRolloutJsonl(text: string, opts?: { preCompact?: boolean })
144
167
  }
145
168
  }
146
169
  } else if (rec.type === "response_item") {
170
+ if (hasItemEvents) continue; // item_completed already carried these
147
171
  if (p.type === "function_call") pendingEvents.push(fnCallToToolUse(p));
148
172
  else if (p.type === "function_call_output") pendingEvents.push(fnOutputToToolResult(p));
149
173
  // File edits are recorded as custom_tool_call (name=apply_patch) + output.
@@ -19,6 +19,14 @@ const ENV_ALLOWLIST = [
19
19
  /** Prefixes kept (codex/XDG own their auth + config). */
20
20
  const ENV_PREFIX_ALLOWLIST = ["CODEX_", "XDG_", "RUST_"];
21
21
 
22
+ /**
23
+ * Bound for short control calls — handshake, model list, skill list, quota read.
24
+ * These answer in about a second when the app-server is healthy; anything past
25
+ * this is a subprocess that will never answer, not a slow one. A turn is NOT a
26
+ * control call and must never be given this bound.
27
+ */
28
+ export const CONTROL_REQUEST_TIMEOUT_MS = 15_000;
29
+
22
30
  function buildSpawnEnv(): NodeJS.ProcessEnv {
23
31
  const out: NodeJS.ProcessEnv = {};
24
32
  for (const [k, v] of Object.entries(process.env)) {
@@ -120,12 +128,41 @@ export class CodexJsonRpcClient {
120
128
  }
121
129
  }
122
130
 
123
- request<T = unknown>(method: string, params?: unknown): Promise<T> {
131
+ /**
132
+ * Send a request and wait for its reply.
133
+ *
134
+ * `timeoutMs` bounds the wait. It is opt-in because a turn legitimately runs
135
+ * for many minutes, but every short control call should pass one: the
136
+ * app-server has been observed to accept a spawn and then never answer even
137
+ * `initialize`. Without a bound, the promise never settles, so the caller's
138
+ * `finally` never runs, the subprocess is never closed, and any HTTP route
139
+ * waiting on it hangs until the client gives up — one orphaned app-server per
140
+ * attempt, and a blank reading at the other end.
141
+ *
142
+ * A timeout rejects and drops the pending entry, so a late reply is ignored
143
+ * rather than resolving a promise the caller already abandoned.
144
+ */
145
+ request<T = unknown>(method: string, params?: unknown, timeoutMs?: number): Promise<T> {
124
146
  if (this.closed) return Promise.reject(new Error("codex client closed"));
125
147
  const id = this.nextId++;
126
148
  const line = JSON.stringify({ id, method, params }) + "\n";
127
149
  return new Promise<T>((resolve, reject) => {
128
- this.pending.set(id, { resolve: resolve as (v: unknown) => void, reject });
150
+ let timer: ReturnType<typeof setTimeout> | undefined;
151
+ const settle = <A extends unknown[]>(fn: (...args: A) => void) => (...args: A) => {
152
+ if (timer) clearTimeout(timer);
153
+ fn(...args);
154
+ };
155
+ const wrapped = {
156
+ resolve: settle(resolve as (v: unknown) => void),
157
+ reject: settle(reject),
158
+ };
159
+ if (timeoutMs != null) {
160
+ timer = setTimeout(() => {
161
+ this.pending.delete(id);
162
+ reject(new Error(`codex ${method} timed out after ${timeoutMs}ms`));
163
+ }, timeoutMs);
164
+ }
165
+ this.pending.set(id, wrapped);
129
166
  this.write(line);
130
167
  });
131
168
  }
@@ -90,6 +90,30 @@ export interface ModelListResponse {
90
90
  nextCursor: string | null;
91
91
  }
92
92
 
93
+ // ── Skills ──
94
+ /** Presentation block codex ships for its own system skills. All fields optional. */
95
+ export interface CodexSkillInterface {
96
+ displayName?: string;
97
+ shortDescription?: string;
98
+ /** Absolute path to an icon file inside the skill directory, not a URL. */
99
+ iconSmall?: string;
100
+ iconLarge?: string;
101
+ defaultPrompt?: string;
102
+ }
103
+ export interface CodexSkill {
104
+ name: string;
105
+ description?: string;
106
+ /** "system" for codex's built-ins; project/user scopes for authored ones. */
107
+ scope?: string;
108
+ path?: string;
109
+ enabled?: boolean;
110
+ interface?: CodexSkillInterface;
111
+ }
112
+ /** `skills/list` groups its results by the cwd each set was resolved for. */
113
+ export interface SkillListResponse {
114
+ data: { cwd?: string; skills?: CodexSkill[] }[];
115
+ }
116
+
93
117
  // ── Account rate limits / usage ──
94
118
  export interface RateLimitWindow {
95
119
  usedPercent: number;
@@ -10,17 +10,19 @@ import type {
10
10
  UsageInfo,
11
11
  } from "../provider.interface.ts";
12
12
  import { configService } from "../../services/config.service.ts";
13
- import { setSessionMetadata, getSessionProjectPath, setSessionProvider, setSessionCodexAccount } from "../../services/db.service.ts";
14
- import { resolveCodexAccountForSession } from "../../services/codex-account.service.ts";
13
+ import { setSessionMetadata, getSessionProjectPath, setSessionProvider, setSessionCodexAccount, getSessionCodexAccount } from "../../services/db.service.ts";
14
+ import { resolveCodexAccountForSession, getCodexAccount, listCodexAccounts, peekCodexAccount } from "../../services/codex-account.service.ts";
15
15
  import { killProcessTree } from "../../services/windows-process-tree.ts";
16
16
  import { homedir } from "node:os";
17
17
  import { join } from "node:path";
18
- import { CodexJsonRpcClient } from "./codex-jsonrpc-client.ts";
18
+ import { CodexJsonRpcClient, CONTROL_REQUEST_TIMEOUT_MS } from "./codex-jsonrpc-client.ts";
19
19
  import { permissionModeToCodex, type CodexPermission } from "./codex-permission-map.ts";
20
20
  import { mapCodexEvent } from "./codex-event-mapper.ts";
21
21
  import { decisionFor, isApprovalMethod, type ApprovalMethod } from "./codex-approval-decision.ts";
22
22
  import { parseModelList } from "./codex-model-parser.ts";
23
- import { fetchCodexUsage } from "./codex-usage-fetch.ts";
23
+ import { getOrFetchUsage, registerUsageSource } from "../../services/provider-usage/usage-registry.ts";
24
+ import { codexUsageSource } from "./codex-usage-source.ts";
25
+ import { AMBIENT_ACCOUNT_KEY } from "../../services/provider-usage/usage-source.ts";
24
26
  import { redactTruncate } from "./codex-redact.ts";
25
27
  import {
26
28
  listCodexRollouts,
@@ -34,12 +36,50 @@ import type {
34
36
  ToolRequestUserInputResponse,
35
37
  Thread,
36
38
  UserInput,
39
+ CodexSkill,
37
40
  } from "./codex-protocol.ts";
41
+ import { parseSkillList } from "./codex-skill-parser.ts";
38
42
 
39
43
  const CODEX_SESSIONS_DIR = join(homedir(), ".codex", "sessions");
44
+
45
+ /**
46
+ * Every directory a codex rollout for this install could be in, most specific
47
+ * first.
48
+ *
49
+ * `~/.codex/sessions` is only the ambient login's. PPM gives each managed
50
+ * account its own CODEX_HOME, and the app-server writes that account's
51
+ * transcripts under it — so a session bound to an account has its history
52
+ * nowhere near the default directory. Reading only the default is why such a
53
+ * conversation came back empty once it was no longer live in memory: it was
54
+ * being served from the in-process transcript, and nothing on disk was ever
55
+ * found for it.
56
+ *
57
+ * `sessionId` narrows to the bound account when there is one; without it the
58
+ * caller gets every account, which is what listing a project's sessions needs.
59
+ */
60
+ function codexSessionsDirs(sessionId?: string): string[] {
61
+ const dirs: string[] = [];
62
+ const boundId = sessionId ? getSessionCodexAccount(sessionId) : null;
63
+ const accounts = boundId
64
+ ? [getCodexAccount(boundId)].filter((a): a is NonNullable<typeof a> => a != null)
65
+ : listCodexAccounts();
66
+ for (const account of accounts) dirs.push(join(account.home, "sessions"));
67
+ dirs.push(CODEX_SESSIONS_DIR);
68
+ return dirs;
69
+ }
70
+
71
+ /** First non-empty result across the candidate directories. */
72
+ function fromCodexSessionsDirs<T>(sessionId: string | undefined, read: (dir: string) => T | null): T | null {
73
+ for (const dir of codexSessionsDirs(sessionId)) {
74
+ const found = read(dir);
75
+ if (found != null) return found;
76
+ }
77
+ return null;
78
+ }
40
79
  const CLIENT_INFO = { name: "ppm", title: "PPM", version: "0.0.0" };
41
80
  const CAPABILITIES = { experimentalApi: true, requestAttestation: false, optOutNotificationMethods: null };
42
81
  const MODELS_CACHE_TTL = 5 * 60 * 1000;
82
+ const SKILLS_CACHE_TTL = 60 * 1000;
43
83
 
44
84
  interface PendingApproval {
45
85
  codexId: number | string;
@@ -165,6 +205,8 @@ export class CodexAppServerProvider implements AIProvider {
165
205
  private sessions = new Map<string, Session>();
166
206
  private live = new Map<string, LiveSession>();
167
207
  private modelsCache: { models: ModelOption[]; expiry: number } | null = null;
208
+ /** Keyed by `cwd\0codexHome` — skills differ per workspace AND per account. */
209
+ private skillsCache = new Map<string, { skills: CodexSkill[]; expiry: number }>();
168
210
 
169
211
  private get config() {
170
212
  try { return configService.get("ai").providers["codex"] ?? null; } catch { return null; }
@@ -208,10 +250,29 @@ export class CodexAppServerProvider implements AIProvider {
208
250
  }
209
251
 
210
252
  async listSessionsByDir(dir: string, opts?: { limit?: number; offset?: number }): Promise<SessionInfo[]> {
211
- const sessions = listCodexRollouts(CODEX_SESSIONS_DIR, dir, this.id, opts);
253
+ const seen = new Set<string>();
254
+ const sessions: SessionInfo[] = [];
255
+ for (const sessionsDir of codexSessionsDirs()) {
256
+ for (const s of listCodexRollouts(sessionsDir, dir, this.id, opts)) {
257
+ if (seen.has(s.id)) continue;
258
+ seen.add(s.id);
259
+ sessions.push(s);
260
+ }
261
+ }
212
262
  // Backfill provider ownership so reopening a pre-existing codex thread routes
213
263
  // to codex (not the default provider) even after a restart.
214
- for (const s of sessions) { try { setSessionProvider(s.id, this.id); } catch { /* non-fatal */ } }
264
+ //
265
+ // The project path is recorded in the same pass, and it has to be: reading a
266
+ // session is fail-closed on cwd, so a row registered here without one can
267
+ // never be read back and the conversation opens blank. `dir` is exactly that
268
+ // cwd — every rollout listed above matched it — so the attribution is the
269
+ // one already proven, not a guess.
270
+ for (const s of sessions) {
271
+ try {
272
+ setSessionProvider(s.id, this.id);
273
+ setSessionMetadata(s.id, s.projectName, dir);
274
+ } catch { /* non-fatal */ }
275
+ }
215
276
  return sessions;
216
277
  }
217
278
 
@@ -301,13 +362,13 @@ export class CodexAppServerProvider implements AIProvider {
301
362
  client.onClose(() => this.handleClose(live));
302
363
  client.start({ cwd, codexHome: account?.home });
303
364
 
304
- await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
365
+ await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
305
366
  client.notify("initialized");
306
367
 
307
368
  const resumeBase = { cwd, sandbox: permission.sandbox, approvalPolicy: permission.approvalPolicy, ...(model ? { model } : {}) };
308
369
  // Only treat as a resume when a rollout for this id is attributable to THIS
309
370
  // project (fail-closed cwd guard) — never resume another project's thread.
310
- const isResume = !!findRolloutByThreadId(CODEX_SESSIONS_DIR, sessionId, cwd);
371
+ const isResume = !!fromCodexSessionsDirs(sessionId, (d) => findRolloutByThreadId(d, sessionId, cwd));
311
372
  const result = isResume
312
373
  ? await client.request("thread/resume", { threadId: sessionId, ...resumeBase })
313
374
  : await client.request("thread/start", resumeBase);
@@ -331,7 +392,10 @@ export class CodexAppServerProvider implements AIProvider {
331
392
  }
332
393
  // Snapshot persisted history so live message ids continue the rollout-N
333
394
  // numbering (empty for a brand-new thread; full prior transcript on resume).
334
- live.history = getRolloutMessages(CODEX_SESSIONS_DIR, threadId, cwd);
395
+ live.history = fromCodexSessionsDirs(threadId, (d) => {
396
+ const msgs = getRolloutMessages(d, threadId, cwd);
397
+ return msgs.length > 0 ? msgs : null;
398
+ }) ?? [];
335
399
  return live;
336
400
  }
337
401
 
@@ -366,7 +430,8 @@ export class CodexAppServerProvider implements AIProvider {
366
430
  if (notif.method === "item/completed" && live.compactRequested
367
431
  && (notif.params as { item?: { type?: string } })?.item?.type === "contextCompaction") {
368
432
  live.compactRequested = false;
369
- const file = findRolloutByThreadId(CODEX_SESSIONS_DIR, live.threadId ?? "", live.cwd);
433
+ const file = fromCodexSessionsDirs(live.threadId ?? undefined,
434
+ (d) => findRolloutByThreadId(d, live.threadId ?? "", live.cwd));
370
435
  if (file) {
371
436
  const content = `_Conversation compacted to save context._\n\nread the full transcript at: ${file}`;
372
437
  live.channel.push({ type: "text", content });
@@ -473,7 +538,10 @@ export class CodexAppServerProvider implements AIProvider {
473
538
  // Fail-closed: only return rollout messages attributable to this project's cwd.
474
539
  const cwd = this.sessions.get(sessionId)?.projectPath || getSessionProjectPath(sessionId);
475
540
  if (!cwd) return [];
476
- return getRolloutMessages(CODEX_SESSIONS_DIR, sessionId, cwd);
541
+ return fromCodexSessionsDirs(sessionId, (d) => {
542
+ const msgs = getRolloutMessages(d, sessionId, cwd);
543
+ return msgs.length > 0 ? msgs : null;
544
+ }) ?? [];
477
545
  }
478
546
 
479
547
  /**
@@ -501,7 +569,7 @@ export class CodexAppServerProvider implements AIProvider {
501
569
  try {
502
570
  if (!reuse) {
503
571
  client.start({ cwd });
504
- await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
572
+ await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
505
573
  client.notify("initialized");
506
574
  }
507
575
  const forkRes = await client.request<{ thread?: { id?: string; turns?: unknown[] } }>("thread/fork", { threadId: sessionId, cwd });
@@ -540,12 +608,12 @@ export class CodexAppServerProvider implements AIProvider {
540
608
  const client = new CodexJsonRpcClient();
541
609
  try {
542
610
  client.start({ cwd: process.cwd() });
543
- await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES });
611
+ await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
544
612
  client.notify("initialized");
545
613
  const all: unknown[] = [];
546
614
  let cursor: string | null = null;
547
615
  do {
548
- const res: ModelListResponse = await client.request<ModelListResponse>("model/list", { cursor });
616
+ const res: ModelListResponse = await client.request<ModelListResponse>("model/list", { cursor }, CONTROL_REQUEST_TIMEOUT_MS);
549
617
  if (Array.isArray(res?.data)) all.push(...res.data);
550
618
  cursor = res?.nextCursor ?? null;
551
619
  } while (cursor);
@@ -559,8 +627,82 @@ export class CodexAppServerProvider implements AIProvider {
559
627
  }
560
628
  }
561
629
 
562
- /** Codex quota for the default account (account/rateLimits/read, 60s cache). */
563
- async getUsage(): Promise<UsageInfo> {
564
- return fetchCodexUsage();
630
+ /**
631
+ * The skills codex itself would resolve for `cwd`, asked of codex rather than
632
+ * discovered from disk.
633
+ *
634
+ * Two reasons it has to come from the app-server. Codex's built-ins live under
635
+ * `$CODEX_HOME/skills/.system/`, and PPM points CODEX_HOME at a per-account
636
+ * directory — so scanning the ambient `~/.codex` reads a different, possibly
637
+ * stale set than the session will actually run. And the app-server is the only
638
+ * source of `enabled` and of the `interface` block (display name, icons) that
639
+ * the picker shows.
640
+ *
641
+ * Cached briefly per (cwd, account): the list changes when the user installs a
642
+ * skill, which should show up without a restart, but a picker keystroke must
643
+ * not spawn an app-server.
644
+ */
645
+ async listSkills(sessionId?: string): Promise<CodexSkill[]> {
646
+ const cwd = (sessionId ? getSessionProjectPath(sessionId) : null) || process.cwd();
647
+ // Reuse the account already bound to the session; resolving afresh here
648
+ // would advance a round-robin strategy for a mere UI listing.
649
+ const accountId = sessionId ? getSessionCodexAccount(sessionId) : null;
650
+ const home = (accountId ? getCodexAccount(accountId)?.home : null) ?? undefined;
651
+
652
+ const key = `${cwd}\0${home ?? ""}`;
653
+ const hit = this.skillsCache.get(key);
654
+ if (hit && Date.now() < hit.expiry) return hit.skills;
655
+
656
+ const client = new CodexJsonRpcClient();
657
+ try {
658
+ client.start({ cwd, codexHome: home });
659
+ await client.request("initialize", { clientInfo: CLIENT_INFO, capabilities: CAPABILITIES }, CONTROL_REQUEST_TIMEOUT_MS);
660
+ client.notify("initialized");
661
+ const skills = parseSkillList(await client.request("skills/list", {}, CONTROL_REQUEST_TIMEOUT_MS));
662
+ if (skills.length > 0) this.skillsCache.set(key, { skills, expiry: Date.now() + SKILLS_CACHE_TTL });
663
+ return skills;
664
+ } catch {
665
+ return [];
666
+ } finally {
667
+ client.close();
668
+ }
669
+ }
670
+
671
+ /** Read the session's account without advancing the account-selection strategy. */
672
+ async getUsage(sessionId?: string): Promise<UsageInfo> {
673
+ // Idempotent, and needed because a caller can reach the provider before the
674
+ // server has started background polling — an unregistered source would make
675
+ // the shared layer answer {} instead of reading codex.
676
+ registerUsageSource(codexUsageSource);
677
+ const accountId = sessionId ? getSessionCodexAccount(sessionId) : null;
678
+ const bound = accountId ? getCodexAccount(accountId) : null;
679
+ if (bound) {
680
+ // Through the shared layer, so this answers from the cache or the stored
681
+ // snapshot and only reaches codex when nothing is known yet — the same
682
+ // path Claude's usage takes. It used to spawn an app-server inline on
683
+ // every miss, on the HTTP request's own thread of control.
684
+ return {
685
+ ...await getOrFetchUsage(this.id, bound.id),
686
+ activeAccountId: bound.id,
687
+ activeAccountLabel: bound.label,
688
+ };
689
+ }
690
+
691
+ // Nothing bound yet — a session binds on its first send. Name the account
692
+ // that will serve it, but do NOT read its quota: that spawns an app-server
693
+ // against a login which is not yet this session's, and which a round-robin
694
+ // or lowest-usage pick may never hand it. So the toolbar can say WHO will
695
+ // answer without PPM touching that account on a session's behalf before
696
+ // the session owns it. The numbers arrive with the first turn.
697
+ //
698
+ // Skipped when the session names an account that no longer exists: naming
699
+ // a different one there would be a lie about a binding that already failed.
700
+ const pending = accountId ? null : peekCodexAccount();
701
+ if (pending) return { activeAccountId: pending.id, activeAccountLabel: pending.label };
702
+
703
+ // Managed accounts are assigned on first send; don't show an unrelated
704
+ // ambient login while that assignment is pending or the binding is missing.
705
+ if (accountId || listCodexAccounts().length > 0) return {};
706
+ return getOrFetchUsage(this.id, AMBIENT_ACCOUNT_KEY);
565
707
  }
566
708
  }