@hienlh/ppm 0.23.8 → 0.23.10

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 (448) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/CLAUDE.md +4 -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 +1 -1
  6. package/dist/web/assets/accounts-settings-section-BOBJbG7i.js +1 -0
  7. package/dist/web/assets/accounts-settings-section-BOBJbG7i.js.br +0 -0
  8. package/dist/web/assets/accounts-settings-section-BOBJbG7i.js.gz +0 -0
  9. package/dist/web/assets/agent-session-sheet-CjD4hBZV.js +2 -0
  10. package/dist/web/assets/agent-session-sheet-CjD4hBZV.js.br +0 -0
  11. package/dist/web/assets/agent-session-sheet-CjD4hBZV.js.gz +0 -0
  12. package/dist/web/assets/agent-session-sheet-store-BcQbnaV2.js +1 -0
  13. package/dist/web/assets/agent-session-window-content-Drm1HsSn.js +1 -0
  14. package/dist/web/assets/agent-session-window-content-Drm1HsSn.js.br +0 -0
  15. package/dist/web/assets/agent-session-window-content-Drm1HsSn.js.gz +0 -0
  16. package/dist/web/assets/{ai-resource-editor-DfVRMUHS.js → ai-resource-editor-M1Eax2Hc.js} +1 -1
  17. package/dist/web/assets/ai-resource-editor-M1Eax2Hc.js.br +0 -0
  18. package/dist/web/assets/ai-resource-editor-M1Eax2Hc.js.gz +0 -0
  19. package/dist/web/assets/ai-settings-section-B73t9SXm.js +1 -0
  20. package/dist/web/assets/{ai-settings-section-Ezhw4Fef.js → ai-settings-section-H173dm1k.js} +1 -1
  21. package/dist/web/assets/ai-settings-section-H173dm1k.js.br +0 -0
  22. package/dist/web/assets/ai-settings-section-H173dm1k.js.gz +0 -0
  23. package/dist/web/assets/{api-settings-tYKJ5Fqk.js → api-settings-BA_n8cPt.js} +1 -1
  24. package/dist/web/assets/{appearance-settings-section-CPOAp0fY.js → appearance-settings-section-Dqu20pt8.js} +1 -1
  25. package/dist/web/assets/appearance-settings-section-Dqu20pt8.js.br +0 -0
  26. package/dist/web/assets/appearance-settings-section-Dqu20pt8.js.gz +0 -0
  27. package/dist/web/assets/{apps-panel-Cz7_o-M4.js → apps-panel-mkrzY7K0.js} +1 -1
  28. package/dist/web/assets/apps-panel-mkrzY7K0.js.br +0 -0
  29. package/dist/web/assets/apps-panel-mkrzY7K0.js.gz +0 -0
  30. package/dist/web/assets/branch-review-tab-Dw3bNixU.js +1 -0
  31. package/dist/web/assets/branch-review-tab-Dw3bNixU.js.br +0 -0
  32. package/dist/web/assets/branch-review-tab-Dw3bNixU.js.gz +0 -0
  33. package/dist/web/assets/chat-tab-BAbcVFzD.js +15 -0
  34. package/dist/web/assets/chat-tab-BAbcVFzD.js.br +0 -0
  35. package/dist/web/assets/chat-tab-BAbcVFzD.js.gz +0 -0
  36. package/dist/web/assets/chat-tab-BaXGaBEC.js +1 -0
  37. package/dist/web/assets/chat-tab-BaXGaBEC.js.br +4 -0
  38. package/dist/web/assets/chat-tab-BaXGaBEC.js.gz +0 -0
  39. package/dist/web/assets/code-editor-CXLANXnI.js +7 -0
  40. package/dist/web/assets/code-editor-CXLANXnI.js.br +0 -0
  41. package/dist/web/assets/code-editor-CXLANXnI.js.gz +0 -0
  42. package/dist/web/assets/{codex-reset-credit-button-D2hal4bG.js → codex-reset-credit-button-CB8Dfhki.js} +1 -1
  43. package/dist/web/assets/codex-reset-credit-button-CB8Dfhki.js.br +0 -0
  44. package/dist/web/assets/codex-reset-credit-button-CB8Dfhki.js.gz +0 -0
  45. package/dist/web/assets/{conflict-editor-Cj_gUncw.js → conflict-editor-CKsxIw3v.js} +2 -2
  46. package/dist/web/assets/conflict-editor-CKsxIw3v.js.br +0 -0
  47. package/dist/web/assets/conflict-editor-CKsxIw3v.js.gz +0 -0
  48. package/dist/web/assets/{csv-preview-Be3ODNj0.js → csv-preview-U0v_r_-7.js} +1 -1
  49. package/dist/web/assets/csv-preview-U0v_r_-7.js.br +0 -0
  50. package/dist/web/assets/csv-preview-U0v_r_-7.js.gz +0 -0
  51. package/dist/web/assets/{database-viewer-B1b--4y8.js → database-viewer-xQyUcBoL.js} +1 -1
  52. package/dist/web/assets/database-viewer-xQyUcBoL.js.br +0 -0
  53. package/dist/web/assets/database-viewer-xQyUcBoL.js.gz +0 -0
  54. package/dist/web/assets/{design-tab-8wi0IHss.js → design-tab-aaAt2_QE.js} +4 -4
  55. package/dist/web/assets/design-tab-aaAt2_QE.js.br +0 -0
  56. package/dist/web/assets/design-tab-aaAt2_QE.js.gz +0 -0
  57. package/dist/web/assets/{designs-sidebar-panel-D5-1Q8zQ.js → designs-sidebar-panel-CTzO4Thu.js} +1 -1
  58. package/dist/web/assets/designs-sidebar-panel-CTzO4Thu.js.br +0 -0
  59. package/dist/web/assets/designs-sidebar-panel-CTzO4Thu.js.gz +0 -0
  60. package/dist/web/assets/{diff-viewer-Dcxk6UTG.js → diff-viewer-CSE2-OE7.js} +1 -1
  61. package/dist/web/assets/diff-viewer-CSE2-OE7.js.br +0 -0
  62. package/dist/web/assets/diff-viewer-CSE2-OE7.js.gz +0 -0
  63. package/dist/web/assets/{edit-diff-preview-DxDAtYhi.js → edit-diff-preview-gH6pRk4S.js} +1 -1
  64. package/dist/web/assets/edit-diff-preview-gH6pRk4S.js.br +0 -0
  65. package/dist/web/assets/{edit-diff-preview-DxDAtYhi.js.gz → edit-diff-preview-gH6pRk4S.js.gz} +0 -0
  66. package/dist/web/assets/{editor-language-service-BVJQnTSV.js → editor-language-service-CYl04pUy.js} +1 -1
  67. package/dist/web/assets/editor-language-service-CYl04pUy.js.br +0 -0
  68. package/dist/web/assets/editor-language-service-CYl04pUy.js.gz +0 -0
  69. package/dist/web/assets/explorer-body-BBOcvwmV.js +2 -0
  70. package/dist/web/assets/explorer-body-BBOcvwmV.js.br +0 -0
  71. package/dist/web/assets/explorer-body-BBOcvwmV.js.gz +0 -0
  72. package/dist/web/assets/{explorer-window-content-DH5AD3Ng.js → explorer-window-content-juCGcrkc.js} +1 -1
  73. package/dist/web/assets/explorer-window-content-juCGcrkc.js.br +0 -0
  74. package/dist/web/assets/explorer-window-content-juCGcrkc.js.gz +0 -0
  75. package/dist/web/assets/{extension-manager-section-BJr6ccWw.js → extension-manager-section-poMRmwvg.js} +1 -1
  76. package/dist/web/assets/extension-manager-section-poMRmwvg.js.br +0 -0
  77. package/dist/web/assets/extension-manager-section-poMRmwvg.js.gz +0 -0
  78. package/dist/web/assets/{extension-webview-CYNXHd8D.js → extension-webview-0QfzTI6s.js} +1 -1
  79. package/dist/web/assets/extension-webview-0QfzTI6s.js.br +0 -0
  80. package/dist/web/assets/extension-webview-0QfzTI6s.js.gz +0 -0
  81. package/dist/web/assets/{files-settings-section-JX7o4lex.js → files-settings-section-DJptxRgH.js} +1 -1
  82. package/dist/web/assets/files-settings-section-DJptxRgH.js.br +0 -0
  83. package/dist/web/assets/files-settings-section-DJptxRgH.js.gz +0 -0
  84. package/dist/web/assets/{general-settings-section-kF94Mz5q.js → general-settings-section-BFNbdDNv.js} +1 -1
  85. package/dist/web/assets/general-settings-section-BFNbdDNv.js.br +0 -0
  86. package/dist/web/assets/general-settings-section-BFNbdDNv.js.gz +0 -0
  87. package/dist/web/assets/{git-log-panel-Crlp9ofM.js → git-log-panel-SMMIbjSe.js} +1 -1
  88. package/dist/web/assets/git-log-panel-SMMIbjSe.js.br +0 -0
  89. package/dist/web/assets/git-log-panel-SMMIbjSe.js.gz +0 -0
  90. package/dist/web/assets/{glide-data-grid-O6MO5dKU.js → glide-data-grid-DZVmgu0T.js} +3 -3
  91. package/dist/web/assets/glide-data-grid-DZVmgu0T.js.br +0 -0
  92. package/dist/web/assets/glide-data-grid-DZVmgu0T.js.gz +0 -0
  93. package/dist/web/assets/group-chat-tab-d_aaYuK_.js +1 -0
  94. package/dist/web/assets/group-chat-tab-d_aaYuK_.js.br +0 -0
  95. package/dist/web/assets/group-chat-tab-d_aaYuK_.js.gz +0 -0
  96. package/dist/web/assets/{index-DQCw6d-2.js → index-CIscPw4g.js} +6 -6
  97. package/dist/web/assets/index-CIscPw4g.js.br +0 -0
  98. package/dist/web/assets/index-CIscPw4g.js.gz +0 -0
  99. package/dist/web/assets/{jira-watcher-section-DwM7gqHT.js → jira-watcher-section-CsbhnLLn.js} +1 -1
  100. package/dist/web/assets/keybindings-store-BPs0pM0r.js +1 -0
  101. package/dist/web/assets/{keyboard-shortcuts-section-CewWGwiF.js → keyboard-shortcuts-section-CXqc2OtM.js} +1 -1
  102. package/dist/web/assets/keyboard-shortcuts-section-CXqc2OtM.js.br +0 -0
  103. package/dist/web/assets/keyboard-shortcuts-section-CXqc2OtM.js.gz +0 -0
  104. package/dist/web/assets/{language-servers-section-nricdxke.js → language-servers-section-B4FsBVvZ.js} +2 -2
  105. package/dist/web/assets/language-servers-section-B4FsBVvZ.js.br +0 -0
  106. package/dist/web/assets/language-servers-section-B4FsBVvZ.js.gz +0 -0
  107. package/dist/web/assets/{lsp-client-DRMEWb-z.js → lsp-client-MQ4mjDfT.js} +1 -1
  108. package/dist/web/assets/lsp-client-MQ4mjDfT.js.br +0 -0
  109. package/dist/web/assets/lsp-client-MQ4mjDfT.js.gz +0 -0
  110. package/dist/web/assets/markdown-renderer-BvCZZlue.js +1 -0
  111. package/dist/web/assets/{markdown-renderer-Dab9Us6u.js → markdown-renderer-CjPb5pns.js} +3 -3
  112. package/dist/web/assets/markdown-renderer-CjPb5pns.js.br +0 -0
  113. package/dist/web/assets/markdown-renderer-CjPb5pns.js.gz +0 -0
  114. package/dist/web/assets/{mobile-explorer-sheet-DtgdpvJ9.js → mobile-explorer-sheet-0aGhVQtI.js} +1 -1
  115. package/dist/web/assets/mobile-explorer-sheet-0aGhVQtI.js.br +0 -0
  116. package/dist/web/assets/mobile-explorer-sheet-0aGhVQtI.js.gz +0 -0
  117. package/dist/web/assets/{new-design-dialog-Dd5KDB_p.js → new-design-dialog-2oT2oc_F.js} +1 -1
  118. package/dist/web/assets/new-design-dialog-2oT2oc_F.js.br +0 -0
  119. package/dist/web/assets/new-design-dialog-2oT2oc_F.js.gz +0 -0
  120. package/dist/web/assets/notification-store-Dd25PMPQ.js +1 -0
  121. package/dist/web/assets/{panel-store-DrSH3Nhp.js → panel-store-1X6yM3XZ.js} +1 -1
  122. package/dist/web/assets/panel-store-1X6yM3XZ.js.br +0 -0
  123. package/dist/web/assets/panel-store-1X6yM3XZ.js.gz +0 -0
  124. package/dist/web/assets/performance-panel-Ub96qrEH.js +3 -0
  125. package/dist/web/assets/performance-panel-Ub96qrEH.js.br +0 -0
  126. package/dist/web/assets/performance-panel-Ub96qrEH.js.gz +0 -0
  127. package/dist/web/assets/{ppmbot-settings-section-D67u6gPi.js → ppmbot-settings-section-CPMGP66g.js} +1 -1
  128. package/dist/web/assets/ppmbot-settings-section-CPMGP66g.js.br +0 -0
  129. package/dist/web/assets/ppmbot-settings-section-CPMGP66g.js.gz +0 -0
  130. package/dist/web/assets/{problems-panel-DKgIw4uZ.js → problems-panel-CWwzZIP3.js} +1 -1
  131. package/dist/web/assets/problems-panel-CWwzZIP3.js.br +0 -0
  132. package/dist/web/assets/problems-panel-CWwzZIP3.js.gz +0 -0
  133. package/dist/web/assets/process-table-BwPws3zS.js +1 -0
  134. package/dist/web/assets/process-table-BwPws3zS.js.br +0 -0
  135. package/dist/web/assets/process-table-BwPws3zS.js.gz +0 -0
  136. package/dist/web/assets/{proxy-settings-section-CFiYcTBA.js → proxy-settings-section-nS8VbxI_.js} +1 -1
  137. package/dist/web/assets/proxy-settings-section-nS8VbxI_.js.br +0 -0
  138. package/dist/web/assets/proxy-settings-section-nS8VbxI_.js.gz +0 -0
  139. package/dist/web/assets/{query-audit-section-BybgiPsc.js → query-audit-section-Dv5Pxn-w.js} +1 -1
  140. package/dist/web/assets/query-audit-section-Dv5Pxn-w.js.br +0 -0
  141. package/dist/web/assets/query-audit-section-Dv5Pxn-w.js.gz +0 -0
  142. package/dist/web/assets/{remote-desktop-clipboard-notice-Bs3fZSRw.js → remote-desktop-clipboard-notice-DEbdu0hC.js} +1 -1
  143. package/dist/web/assets/remote-desktop-clipboard-notice-DEbdu0hC.js.br +0 -0
  144. package/dist/web/assets/remote-desktop-clipboard-notice-DEbdu0hC.js.gz +0 -0
  145. package/dist/web/assets/remote-desktop-mobile-sheet-BJm-akVY.js +2 -0
  146. package/dist/web/assets/remote-desktop-mobile-sheet-BJm-akVY.js.br +0 -0
  147. package/dist/web/assets/remote-desktop-mobile-sheet-BJm-akVY.js.gz +0 -0
  148. package/dist/web/assets/{remote-desktop-mobile-view-DgGOfPVY.js → remote-desktop-mobile-view-DPdGFD6C.js} +1 -1
  149. package/dist/web/assets/remote-desktop-mobile-view-DPdGFD6C.js.br +0 -0
  150. package/dist/web/assets/remote-desktop-mobile-view-DPdGFD6C.js.gz +0 -0
  151. package/dist/web/assets/{remote-desktop-readiness-gate-DOWryrQx.js → remote-desktop-readiness-gate-DV7YgSpP.js} +1 -1
  152. package/dist/web/assets/remote-desktop-readiness-gate-DV7YgSpP.js.br +0 -0
  153. package/dist/web/assets/remote-desktop-readiness-gate-DV7YgSpP.js.gz +0 -0
  154. package/dist/web/assets/remote-desktop-window-content-BktcWMjD.js +1 -0
  155. package/dist/web/assets/remote-desktop-window-content-BktcWMjD.js.br +0 -0
  156. package/dist/web/assets/remote-desktop-window-content-BktcWMjD.js.gz +0 -0
  157. package/dist/web/assets/{run-in-terminal-Cdn9PaAl.js → run-in-terminal-B_PCeBqG.js} +1 -1
  158. package/dist/web/assets/{schedules-settings-section-DGhG-b5O.js → schedules-settings-section-B3HYKSVh.js} +1 -1
  159. package/dist/web/assets/schedules-settings-section-B3HYKSVh.js.br +0 -0
  160. package/dist/web/assets/schedules-settings-section-B3HYKSVh.js.gz +0 -0
  161. package/dist/web/assets/{send-to-chat-B09VjsB5.js → send-to-chat-Bjg6c8Ld.js} +1 -1
  162. package/dist/web/assets/send-to-chat-Bjg6c8Ld.js.br +0 -0
  163. package/dist/web/assets/send-to-chat-Bjg6c8Ld.js.gz +0 -0
  164. package/dist/web/assets/{services-panel-0klE3O4g.js → services-panel-D6k6AVS4.js} +1 -1
  165. package/dist/web/assets/services-panel-D6k6AVS4.js.br +0 -0
  166. package/dist/web/assets/services-panel-D6k6AVS4.js.gz +0 -0
  167. package/dist/web/assets/{settings-body-CfqpqFfq.js → settings-body-Cu0mNA5x.js} +2 -2
  168. package/dist/web/assets/settings-body-Cu0mNA5x.js.br +0 -0
  169. package/dist/web/assets/settings-body-Cu0mNA5x.js.gz +0 -0
  170. package/dist/web/assets/{settings-store-3jIBB8gx.js → settings-store-DIV25PM_.js} +2 -2
  171. package/dist/web/assets/settings-store-DIV25PM_.js.br +0 -0
  172. package/dist/web/assets/settings-store-DIV25PM_.js.gz +0 -0
  173. package/dist/web/assets/{settings-tab-CHweH5Nh.js → settings-tab-C-A6RNQ3.js} +1 -1
  174. package/dist/web/assets/{settings-window-content-C6Od3qV7.js → settings-window-content-48e5FJAq.js} +1 -1
  175. package/dist/web/assets/{sql-query-editor-ALQ5_X0j.js → sql-query-editor-CgGWYu9K.js} +1 -1
  176. package/dist/web/assets/sql-query-editor-CgGWYu9K.js.br +0 -0
  177. package/dist/web/assets/sql-query-editor-CgGWYu9K.js.gz +0 -0
  178. package/dist/web/assets/{sqlite-viewer-DKTty_jR.js → sqlite-viewer-Co1Oi3dv.js} +1 -1
  179. package/dist/web/assets/sqlite-viewer-Co1Oi3dv.js.br +0 -0
  180. package/dist/web/assets/sqlite-viewer-Co1Oi3dv.js.gz +0 -0
  181. package/dist/web/assets/{system-monitor-body-D6J6lq7-.js → system-monitor-body-DxPKVa-W.js} +2 -2
  182. package/dist/web/assets/system-monitor-body-DxPKVa-W.js.br +0 -0
  183. package/dist/web/assets/system-monitor-body-DxPKVa-W.js.gz +0 -0
  184. package/dist/web/assets/system-monitor-tab-4miOZuQQ.js +1 -0
  185. package/dist/web/assets/{system-monitor-window-content-D1t30f32.js → system-monitor-window-content-B-A7DdML.js} +1 -1
  186. package/dist/web/assets/{tab-host-window-content-DTcx2D0O.js → tab-host-window-content-CChcpg1v.js} +1 -1
  187. package/dist/web/assets/tab-host-window-content-CChcpg1v.js.br +0 -0
  188. package/dist/web/assets/tab-host-window-content-CChcpg1v.js.gz +0 -0
  189. package/dist/web/assets/{tab-store-CUPgQIQz.js → tab-store-D33icgdA.js} +1 -1
  190. package/dist/web/assets/{terminal-tab-DgTfQKBI.js → terminal-tab-BDqlyBLK.js} +2 -2
  191. package/dist/web/assets/terminal-tab-BDqlyBLK.js.br +0 -0
  192. package/dist/web/assets/terminal-tab-BDqlyBLK.js.gz +0 -0
  193. package/dist/web/assets/tool-cards-iJ8tyrLq.js +9 -0
  194. package/dist/web/assets/tool-cards-iJ8tyrLq.js.br +0 -0
  195. package/dist/web/assets/tool-cards-iJ8tyrLq.js.gz +0 -0
  196. package/dist/web/assets/{use-inline-blame-Dv111BKY.js → use-inline-blame-D9js570a.js} +4 -4
  197. package/dist/web/assets/use-inline-blame-D9js570a.js.br +0 -0
  198. package/dist/web/assets/use-inline-blame-D9js570a.js.gz +0 -0
  199. package/dist/web/assets/{use-lsp-CZTFJIXX.js → use-lsp-BYtylZId.js} +1 -1
  200. package/dist/web/assets/use-lsp-BYtylZId.js.br +0 -0
  201. package/dist/web/assets/use-lsp-BYtylZId.js.gz +0 -0
  202. package/dist/web/assets/{use-monaco-theme-DL2dIG5L.js → use-monaco-theme-DJ8y_7IZ.js} +1 -1
  203. package/dist/web/assets/{use-process-kill-D7D9QvJG.js → use-process-kill-BS84S-kD.js} +1 -1
  204. package/dist/web/assets/use-process-kill-BS84S-kD.js.br +0 -0
  205. package/dist/web/assets/use-process-kill-BS84S-kD.js.gz +0 -0
  206. package/dist/web/assets/{use-websocket-ziY-Gz_B.js → use-websocket-Mqj27umG.js} +1 -1
  207. package/dist/web/assets/{video-preview-DzwY3q9W.js → video-preview-BuzUAIma.js} +1 -1
  208. package/dist/web/assets/video-preview-BuzUAIma.js.br +0 -0
  209. package/dist/web/assets/video-preview-BuzUAIma.js.gz +0 -0
  210. package/dist/web/assets/{voice-settings-section-B7zMHsuz.js → voice-settings-section-DnwQjBbw.js} +1 -1
  211. package/dist/web/assets/voice-settings-section-DnwQjBbw.js.br +0 -0
  212. package/dist/web/assets/voice-settings-section-DnwQjBbw.js.gz +0 -0
  213. package/dist/web/assets/{window-pip-registry-dxrBFfkP.js → window-pip-registry-Bl--fK8-.js} +1 -1
  214. package/dist/web/assets/window-store-vo1N70nK.js +1 -0
  215. package/dist/web/assets/window-store-vo1N70nK.js.br +0 -0
  216. package/dist/web/assets/window-store-vo1N70nK.js.gz +0 -0
  217. package/dist/web/index.html +6 -6
  218. package/dist/web/index.html.br +0 -0
  219. package/dist/web/index.html.gz +0 -0
  220. package/dist/web/sw.js +1 -1
  221. package/dist/web/sw.js.br +0 -0
  222. package/dist/web/sw.js.gz +0 -0
  223. package/docs/architecture/ai-chat-and-providers.md +66 -0
  224. package/docs/architecture/workspace-and-ui.md +15 -3
  225. package/docs/design-guidelines.md +6 -1
  226. package/package.json +1 -1
  227. package/src/providers/codex-app-server/codex-history.ts +4 -4
  228. package/src/providers/codex-app-server/codex-provider.ts +1 -1
  229. package/src/providers/codex-app-server/codex-rollout-tail-parser.ts +203 -0
  230. package/src/providers/codex-app-server/codex-subagent-thread.ts +7 -1
  231. package/src/server/index.ts +7 -2
  232. package/src/server/routes/chat.ts +12 -4
  233. package/src/server/ws/global.ts +19 -3
  234. package/src/services/agent-transcript/agent-transcript-activity.ts +72 -0
  235. package/src/services/agent-transcript/agent-transcript-codex-activity.ts +161 -0
  236. package/src/services/agent-transcript/agent-transcript-codex-tail-cache.ts +85 -0
  237. package/src/services/agent-transcript/agent-transcript-envelope.ts +86 -0
  238. package/src/services/agent-transcript/agent-transcript-error-map.ts +33 -0
  239. package/src/services/agent-transcript/agent-transcript-file-tail-feed.ts +180 -0
  240. package/src/services/agent-transcript/agent-transcript-file-tail-state.ts +100 -0
  241. package/src/services/agent-transcript/agent-transcript-fs-io.ts +79 -0
  242. package/src/services/agent-transcript/agent-transcript-hub-clock.ts +37 -0
  243. package/src/services/agent-transcript/agent-transcript-hub-registry.ts +153 -0
  244. package/src/services/agent-transcript/agent-transcript-hub.ts +103 -0
  245. package/src/services/agent-transcript/agent-transcript-index-cache.ts +85 -0
  246. package/src/services/agent-transcript/agent-transcript-session-hub-activity.ts +103 -0
  247. package/src/services/agent-transcript/agent-transcript-session-hub-read.ts +194 -0
  248. package/src/services/agent-transcript/agent-transcript-session-hub-types.ts +81 -0
  249. package/src/services/agent-transcript/agent-transcript-session-hub.ts +196 -0
  250. package/src/services/agent-transcript/agent-transcript-sources.ts +199 -0
  251. package/src/services/agent-transcript/agent-transcript-ws-like.ts +19 -0
  252. package/src/services/agent-transcript/claude-projects-root.ts +21 -0
  253. package/src/services/agent-transcript/session-ownership.ts +152 -0
  254. package/src/services/nested-subagent-spy.ts +3 -3
  255. package/src/services/subagent-transcript-merger.ts +21 -7
  256. package/src/shared/agent-transcript-protocol.ts +158 -0
  257. package/src/types/chat.ts +27 -3
  258. package/src/web/app.tsx +5 -5
  259. package/src/web/components/chat/agent-card-summary.tsx +73 -0
  260. package/src/web/components/chat/agent-session-context.ts +34 -0
  261. package/src/web/components/chat/agent-session-fallback-store.ts +60 -0
  262. package/src/web/components/chat/agent-session-sheet-store.ts +23 -0
  263. package/src/web/components/chat/{team-member-sheet.tsx → agent-session-sheet.tsx} +12 -12
  264. package/src/web/components/chat/agent-session-window-content.tsx +133 -0
  265. package/src/web/components/chat/chat-history-bar.tsx +1 -0
  266. package/src/web/components/chat/chat-tab.tsx +21 -4
  267. package/src/web/components/chat/codex-usage-panel.tsx +26 -8
  268. package/src/web/components/chat/running-agents-bar.tsx +93 -0
  269. package/src/web/components/chat/team-activity-panel.tsx +19 -5
  270. package/src/web/components/chat/tool-cards.tsx +73 -4
  271. package/src/web/components/chat/use-open-agent-session.ts +83 -0
  272. package/src/web/components/floating-window/window-content-registry.ts +4 -5
  273. package/src/web/components/floating-window/window-geometry.ts +18 -0
  274. package/src/web/components/floating-window/window-persistence.ts +5 -4
  275. package/src/web/components/floating-window/window-store-types.ts +1 -1
  276. package/src/web/components/settings/resolve-open-settings-action.ts +1 -1
  277. package/src/web/components/system/resolve-open-system-monitor-action.ts +1 -1
  278. package/src/web/hooks/use-agent-activity.ts +65 -0
  279. package/src/web/hooks/use-agent-session-stream.ts +134 -0
  280. package/src/web/hooks/use-chat.ts +12 -18
  281. package/src/web/hooks/use-global-events.ts +35 -2
  282. package/src/web/lib/agent-session-stream-merge.ts +48 -0
  283. package/src/web/lib/agent-step-summary.ts +331 -0
  284. package/src/web/lib/global-ws-channel.ts +41 -0
  285. package/src/web/lib/running-agent-rows.ts +115 -0
  286. package/dist/web/assets/accounts-settings-section-BNcPvEq1.js +0 -1
  287. package/dist/web/assets/accounts-settings-section-BNcPvEq1.js.br +0 -0
  288. package/dist/web/assets/accounts-settings-section-BNcPvEq1.js.gz +0 -0
  289. package/dist/web/assets/ai-resource-editor-DfVRMUHS.js.br +0 -0
  290. package/dist/web/assets/ai-resource-editor-DfVRMUHS.js.gz +0 -0
  291. package/dist/web/assets/ai-settings-section-B_0-P8jx.js +0 -1
  292. package/dist/web/assets/ai-settings-section-Ezhw4Fef.js.br +0 -0
  293. package/dist/web/assets/ai-settings-section-Ezhw4Fef.js.gz +0 -0
  294. package/dist/web/assets/appearance-settings-section-CPOAp0fY.js.br +0 -0
  295. package/dist/web/assets/appearance-settings-section-CPOAp0fY.js.gz +0 -0
  296. package/dist/web/assets/apps-panel-Cz7_o-M4.js.br +0 -0
  297. package/dist/web/assets/apps-panel-Cz7_o-M4.js.gz +0 -0
  298. package/dist/web/assets/branch-review-tab-BPx3kHrM.js +0 -1
  299. package/dist/web/assets/branch-review-tab-BPx3kHrM.js.br +0 -0
  300. package/dist/web/assets/branch-review-tab-BPx3kHrM.js.gz +0 -0
  301. package/dist/web/assets/chat-tab-BadDM_j8.js +0 -1
  302. package/dist/web/assets/chat-tab-BadDM_j8.js.br +0 -0
  303. package/dist/web/assets/chat-tab-BadDM_j8.js.gz +0 -0
  304. package/dist/web/assets/chat-tab-IqAY4c7p.js +0 -15
  305. package/dist/web/assets/chat-tab-IqAY4c7p.js.br +0 -0
  306. package/dist/web/assets/chat-tab-IqAY4c7p.js.gz +0 -0
  307. package/dist/web/assets/code-editor-Dmitw9QS.js +0 -7
  308. package/dist/web/assets/code-editor-Dmitw9QS.js.br +0 -0
  309. package/dist/web/assets/code-editor-Dmitw9QS.js.gz +0 -0
  310. package/dist/web/assets/codex-reset-credit-button-D2hal4bG.js.br +0 -0
  311. package/dist/web/assets/codex-reset-credit-button-D2hal4bG.js.gz +0 -0
  312. package/dist/web/assets/conflict-editor-Cj_gUncw.js.br +0 -0
  313. package/dist/web/assets/conflict-editor-Cj_gUncw.js.gz +0 -0
  314. package/dist/web/assets/csv-preview-Be3ODNj0.js.br +0 -0
  315. package/dist/web/assets/csv-preview-Be3ODNj0.js.gz +0 -0
  316. package/dist/web/assets/database-viewer-B1b--4y8.js.br +0 -0
  317. package/dist/web/assets/database-viewer-B1b--4y8.js.gz +0 -0
  318. package/dist/web/assets/design-tab-8wi0IHss.js.br +0 -0
  319. package/dist/web/assets/design-tab-8wi0IHss.js.gz +0 -0
  320. package/dist/web/assets/designs-sidebar-panel-D5-1Q8zQ.js.br +0 -0
  321. package/dist/web/assets/designs-sidebar-panel-D5-1Q8zQ.js.gz +0 -0
  322. package/dist/web/assets/diff-viewer-Dcxk6UTG.js.br +0 -0
  323. package/dist/web/assets/diff-viewer-Dcxk6UTG.js.gz +0 -0
  324. package/dist/web/assets/edit-diff-preview-DxDAtYhi.js.br +0 -0
  325. package/dist/web/assets/editor-language-service-BVJQnTSV.js.br +0 -0
  326. package/dist/web/assets/editor-language-service-BVJQnTSV.js.gz +0 -0
  327. package/dist/web/assets/explorer-body-CTkrlrI3.js +0 -2
  328. package/dist/web/assets/explorer-body-CTkrlrI3.js.br +0 -0
  329. package/dist/web/assets/explorer-body-CTkrlrI3.js.gz +0 -0
  330. package/dist/web/assets/explorer-window-content-DH5AD3Ng.js.br +0 -0
  331. package/dist/web/assets/explorer-window-content-DH5AD3Ng.js.gz +0 -0
  332. package/dist/web/assets/extension-manager-section-BJr6ccWw.js.br +0 -0
  333. package/dist/web/assets/extension-manager-section-BJr6ccWw.js.gz +0 -0
  334. package/dist/web/assets/extension-webview-CYNXHd8D.js.br +0 -0
  335. package/dist/web/assets/extension-webview-CYNXHd8D.js.gz +0 -0
  336. package/dist/web/assets/files-settings-section-JX7o4lex.js.br +0 -0
  337. package/dist/web/assets/files-settings-section-JX7o4lex.js.gz +0 -0
  338. package/dist/web/assets/general-settings-section-kF94Mz5q.js.br +0 -0
  339. package/dist/web/assets/general-settings-section-kF94Mz5q.js.gz +0 -0
  340. package/dist/web/assets/git-log-panel-Crlp9ofM.js.br +0 -0
  341. package/dist/web/assets/git-log-panel-Crlp9ofM.js.gz +0 -0
  342. package/dist/web/assets/glide-data-grid-O6MO5dKU.js.br +0 -0
  343. package/dist/web/assets/glide-data-grid-O6MO5dKU.js.gz +0 -0
  344. package/dist/web/assets/group-chat-tab-DGLSGf37.js +0 -1
  345. package/dist/web/assets/group-chat-tab-DGLSGf37.js.br +0 -0
  346. package/dist/web/assets/group-chat-tab-DGLSGf37.js.gz +0 -0
  347. package/dist/web/assets/index-DQCw6d-2.js.br +0 -0
  348. package/dist/web/assets/index-DQCw6d-2.js.gz +0 -0
  349. package/dist/web/assets/keybindings-store-CJtEHFIQ.js +0 -1
  350. package/dist/web/assets/keyboard-shortcuts-section-CewWGwiF.js.br +0 -0
  351. package/dist/web/assets/keyboard-shortcuts-section-CewWGwiF.js.gz +0 -0
  352. package/dist/web/assets/language-servers-section-nricdxke.js.br +0 -0
  353. package/dist/web/assets/language-servers-section-nricdxke.js.gz +0 -0
  354. package/dist/web/assets/lsp-client-DRMEWb-z.js.br +0 -0
  355. package/dist/web/assets/lsp-client-DRMEWb-z.js.gz +0 -0
  356. package/dist/web/assets/markdown-renderer-D5-xliE9.js +0 -1
  357. package/dist/web/assets/markdown-renderer-Dab9Us6u.js.br +0 -0
  358. package/dist/web/assets/markdown-renderer-Dab9Us6u.js.gz +0 -0
  359. package/dist/web/assets/mobile-explorer-sheet-DtgdpvJ9.js.br +0 -0
  360. package/dist/web/assets/mobile-explorer-sheet-DtgdpvJ9.js.gz +0 -0
  361. package/dist/web/assets/new-design-dialog-Dd5KDB_p.js.br +0 -0
  362. package/dist/web/assets/new-design-dialog-Dd5KDB_p.js.gz +0 -0
  363. package/dist/web/assets/notification-store-D2vTyp_Q.js +0 -1
  364. package/dist/web/assets/panel-store-DrSH3Nhp.js.br +0 -0
  365. package/dist/web/assets/panel-store-DrSH3Nhp.js.gz +0 -0
  366. package/dist/web/assets/performance-panel-LMGefOQ2.js +0 -3
  367. package/dist/web/assets/performance-panel-LMGefOQ2.js.br +0 -0
  368. package/dist/web/assets/performance-panel-LMGefOQ2.js.gz +0 -0
  369. package/dist/web/assets/ppmbot-settings-section-D67u6gPi.js.br +0 -0
  370. package/dist/web/assets/ppmbot-settings-section-D67u6gPi.js.gz +0 -0
  371. package/dist/web/assets/problems-panel-DKgIw4uZ.js.br +0 -0
  372. package/dist/web/assets/problems-panel-DKgIw4uZ.js.gz +0 -0
  373. package/dist/web/assets/process-table-BIAgC_jG.js +0 -1
  374. package/dist/web/assets/process-table-BIAgC_jG.js.br +0 -0
  375. package/dist/web/assets/process-table-BIAgC_jG.js.gz +0 -0
  376. package/dist/web/assets/proxy-settings-section-CFiYcTBA.js.br +0 -0
  377. package/dist/web/assets/proxy-settings-section-CFiYcTBA.js.gz +0 -0
  378. package/dist/web/assets/query-audit-section-BybgiPsc.js.br +0 -0
  379. package/dist/web/assets/query-audit-section-BybgiPsc.js.gz +0 -0
  380. package/dist/web/assets/remote-desktop-clipboard-notice-Bs3fZSRw.js.br +0 -0
  381. package/dist/web/assets/remote-desktop-clipboard-notice-Bs3fZSRw.js.gz +0 -0
  382. package/dist/web/assets/remote-desktop-mobile-sheet-DgxTdWMh.js +0 -2
  383. package/dist/web/assets/remote-desktop-mobile-sheet-DgxTdWMh.js.br +0 -0
  384. package/dist/web/assets/remote-desktop-mobile-sheet-DgxTdWMh.js.gz +0 -0
  385. package/dist/web/assets/remote-desktop-mobile-view-DgGOfPVY.js.br +0 -0
  386. package/dist/web/assets/remote-desktop-mobile-view-DgGOfPVY.js.gz +0 -0
  387. package/dist/web/assets/remote-desktop-readiness-gate-DOWryrQx.js.br +0 -0
  388. package/dist/web/assets/remote-desktop-readiness-gate-DOWryrQx.js.gz +0 -0
  389. package/dist/web/assets/remote-desktop-window-content-7t0wQsHx.js +0 -1
  390. package/dist/web/assets/remote-desktop-window-content-7t0wQsHx.js.br +0 -0
  391. package/dist/web/assets/remote-desktop-window-content-7t0wQsHx.js.gz +0 -0
  392. package/dist/web/assets/schedules-settings-section-DGhG-b5O.js.br +0 -0
  393. package/dist/web/assets/schedules-settings-section-DGhG-b5O.js.gz +0 -0
  394. package/dist/web/assets/send-to-chat-B09VjsB5.js.br +0 -0
  395. package/dist/web/assets/send-to-chat-B09VjsB5.js.gz +0 -0
  396. package/dist/web/assets/services-panel-0klE3O4g.js.br +0 -0
  397. package/dist/web/assets/services-panel-0klE3O4g.js.gz +0 -0
  398. package/dist/web/assets/settings-body-CfqpqFfq.js.br +0 -0
  399. package/dist/web/assets/settings-body-CfqpqFfq.js.gz +0 -0
  400. package/dist/web/assets/settings-store-3jIBB8gx.js.br +0 -0
  401. package/dist/web/assets/settings-store-3jIBB8gx.js.gz +0 -0
  402. package/dist/web/assets/sql-query-editor-ALQ5_X0j.js.br +0 -0
  403. package/dist/web/assets/sql-query-editor-ALQ5_X0j.js.gz +0 -0
  404. package/dist/web/assets/sqlite-viewer-DKTty_jR.js.br +0 -0
  405. package/dist/web/assets/sqlite-viewer-DKTty_jR.js.gz +0 -0
  406. package/dist/web/assets/system-monitor-body-D6J6lq7-.js.br +0 -0
  407. package/dist/web/assets/system-monitor-body-D6J6lq7-.js.gz +0 -0
  408. package/dist/web/assets/system-monitor-tab-Di18zNNS.js +0 -1
  409. package/dist/web/assets/tab-host-window-content-DTcx2D0O.js.br +0 -0
  410. package/dist/web/assets/tab-host-window-content-DTcx2D0O.js.gz +0 -0
  411. package/dist/web/assets/team-member-sheet-CFSbPG6n.js +0 -2
  412. package/dist/web/assets/team-member-sheet-CFSbPG6n.js.br +0 -0
  413. package/dist/web/assets/team-member-sheet-CFSbPG6n.js.gz +0 -0
  414. package/dist/web/assets/team-member-window-content-VeI6DGeM.js +0 -1
  415. package/dist/web/assets/team-member-window-content-VeI6DGeM.js.br +0 -0
  416. package/dist/web/assets/team-member-window-content-VeI6DGeM.js.gz +0 -0
  417. package/dist/web/assets/terminal-tab-DgTfQKBI.js.br +0 -0
  418. package/dist/web/assets/terminal-tab-DgTfQKBI.js.gz +0 -0
  419. package/dist/web/assets/tool-cards-_fpYI1hB.js +0 -9
  420. package/dist/web/assets/tool-cards-_fpYI1hB.js.br +0 -0
  421. package/dist/web/assets/tool-cards-_fpYI1hB.js.gz +0 -0
  422. package/dist/web/assets/use-inline-blame-Dv111BKY.js.br +0 -0
  423. package/dist/web/assets/use-inline-blame-Dv111BKY.js.gz +0 -0
  424. package/dist/web/assets/use-lsp-CZTFJIXX.js.br +0 -0
  425. package/dist/web/assets/use-lsp-CZTFJIXX.js.gz +0 -0
  426. package/dist/web/assets/use-open-team-member-ElN3KmCI.js +0 -1
  427. package/dist/web/assets/use-process-kill-D7D9QvJG.js.br +0 -0
  428. package/dist/web/assets/use-process-kill-D7D9QvJG.js.gz +0 -0
  429. package/dist/web/assets/video-preview-DzwY3q9W.js.br +0 -0
  430. package/dist/web/assets/video-preview-DzwY3q9W.js.gz +0 -0
  431. package/dist/web/assets/voice-settings-section-B7zMHsuz.js.br +0 -0
  432. package/dist/web/assets/voice-settings-section-B7zMHsuz.js.gz +0 -0
  433. package/dist/web/assets/window-store-B4cbZ5rr.js +0 -1
  434. package/dist/web/assets/window-store-B4cbZ5rr.js.br +0 -0
  435. package/dist/web/assets/window-store-B4cbZ5rr.js.gz +0 -0
  436. package/src/web/components/chat/team-member-window-content.tsx +0 -66
  437. package/src/web/components/chat/team-working-bar.tsx +0 -62
  438. package/src/web/components/chat/use-open-team-member.ts +0 -41
  439. package/src/web/hooks/use-member-transcript-tail.ts +0 -95
  440. /package/dist/web/assets/{api-settings-BeINN5Dy.js → api-settings-BWgfXl7o.js} +0 -0
  441. /package/dist/web/assets/{api-settings-BeINN5Dy.js.br → api-settings-BWgfXl7o.js.br} +0 -0
  442. /package/dist/web/assets/{api-settings-BeINN5Dy.js.gz → api-settings-BWgfXl7o.js.gz} +0 -0
  443. /package/dist/web/assets/{libesm-CxeQSM3t.js → libesm-DAF5_F99.js} +0 -0
  444. /package/dist/web/assets/{libesm-CxeQSM3t.js.br → libesm-DAF5_F99.js.br} +0 -0
  445. /package/dist/web/assets/{libesm-CxeQSM3t.js.gz → libesm-DAF5_F99.js.gz} +0 -0
  446. /package/dist/web/assets/{onboarding-entry-DD3QSDiz.js → onboarding-entry-Bh-WE3vq.js} +0 -0
  447. /package/dist/web/assets/{onboarding-entry-DD3QSDiz.js.br → onboarding-entry-Bh-WE3vq.js.br} +0 -0
  448. /package/dist/web/assets/{onboarding-entry-DD3QSDiz.js.gz → onboarding-entry-Bh-WE3vq.js.gz} +0 -0
@@ -0,0 +1,331 @@
1
+ /**
2
+ * Pure helpers behind the Agent/Task card's one-line summary and the chat's
3
+ * slimmed in-memory record of a subagent's work — no React, so this is directly
4
+ * unit-testable and reusable from `use-chat.ts`'s live routing.
5
+ *
6
+ * A "step" is a distinct child `tool_use` id. A card's own direct children count
7
+ * one step each — including a nested Agent/Task call, which counts once for
8
+ * spawning it — and that nested call's *own* subtree is then summed in on top
9
+ * (`recursiveStepCount`), so the number shown on a one-line card equals the
10
+ * live session window's flat count of every `tool_use` in the whole on-disk
11
+ * transcript, not just this card's immediate children. `stepIds` is a Set-like
12
+ * array of ids so a WS replay re-delivering the same `tool_use` never
13
+ * double-counts — the one thing today's `children.length` badge could not
14
+ * guarantee.
15
+ *
16
+ * "Kept children" are what stays in memory once the full list is gone: nested
17
+ * Agent/Task stubs (recursively slimmed the same way, so a further-nested card
18
+ * still routes and lists correctly) and file-mutation tool_use/tool_result
19
+ * pairs (the change tray reads these). Everything else that would otherwise be
20
+ * silently dropped goes into a bounded ring buffer instead — the fallback shown
21
+ * when no on-disk transcript exists to stream from.
22
+ */
23
+ import type { ChatEvent } from "../../types/chat";
24
+ import { basename } from "./utils";
25
+ import { FILE_MUTATION_TOOLS } from "./aggregate-turn-file-changes";
26
+
27
+ /** Live cards keep at most this many "other" (not kept) child events. */
28
+ export const MAX_RECENT_CHILDREN = 200;
29
+
30
+ /** Ring buffer also evicts oldest-first once its serialized size passes this — a handful of
31
+ * multi-MB tool outputs would otherwise fit comfortably under the 200-entry count cap while
32
+ * still holding many megabytes per live card. */
33
+ export const MAX_RECENT_BYTES = 256 * 1024;
34
+
35
+ function str(v: unknown): string {
36
+ return typeof v === "string" ? v : "";
37
+ }
38
+
39
+ /** "1 step" / "N steps" — every place a card shows its step count uses this instead of
40
+ * hardcoding the plural, which read as "1 steps" for a single-step agent. */
41
+ export function formatStepCount(count: number): string {
42
+ return `${count} step${count === 1 ? "" : "s"}`;
43
+ }
44
+
45
+ function truncate(value: string, max: number): string {
46
+ return value.length > max ? value.slice(0, max) + "…" : value;
47
+ }
48
+
49
+ /** Plain-text one-line description of a `tool_use` step — the same wording as
50
+ * the JSX `ToolSummary` in `tool-cards.tsx`, minus the markup, so it fits the
51
+ * card's "current step" line and is usable from a DOM-free test. */
52
+ export function describeStep(ev: ChatEvent): string {
53
+ if (ev.type !== "tool_use") return "";
54
+ const tool = ev.tool;
55
+ const input = ev.input && typeof ev.input === "object" ? (ev.input as Record<string, unknown>) : {};
56
+ switch (tool) {
57
+ case "Read":
58
+ case "Write":
59
+ case "Edit":
60
+ case "MultiEdit":
61
+ case "NotebookEdit": {
62
+ const path = str(input.notebook_path || input.file_path);
63
+ return path ? `${tool} ${basename(path)}` : tool;
64
+ }
65
+ case "Bash":
66
+ case "PowerShell": {
67
+ const preview = input.description ? str(input.description) : str(input.command);
68
+ return truncate(preview, 60) || tool;
69
+ }
70
+ case "Glob":
71
+ return `Glob ${str(input.pattern)}`;
72
+ case "Grep":
73
+ return `Grep ${truncate(str(input.pattern), 40)}`;
74
+ case "WebSearch":
75
+ return `Search ${truncate(str(input.query), 50)}`;
76
+ case "WebFetch":
77
+ return `Fetch ${truncate(str(input.url), 50)}`;
78
+ case "ToolSearch":
79
+ return `Search ${truncate(str(input.query), 50)}`;
80
+ case "Agent":
81
+ case "Task": {
82
+ const name = typeof input.name === "string" && input.name.trim() ? input.name.trim() : null;
83
+ const task = truncate(str(input.description || input.prompt), 44);
84
+ if (name) return task ? `${name} · ${task}` : name;
85
+ return task || tool;
86
+ }
87
+ case "SendMessage":
88
+ return `Message ${truncate(str(input.to), 30)}`.trim();
89
+ case "TodoWrite":
90
+ return "Todo update";
91
+ case "AskUserQuestion":
92
+ return "Question";
93
+ case "ScheduleWakeup":
94
+ return "Scheduled wakeup";
95
+ case "TaskCreate":
96
+ return truncate(str(input.subject), 60) || tool;
97
+ case "TaskUpdate":
98
+ return `Task #${str(input.taskId)} → ${str(input.status)}`;
99
+ case "TaskStop":
100
+ return `Task #${str(input.taskId)} stopped`;
101
+ case "ImageGen":
102
+ return "Image generation";
103
+ default:
104
+ return tool;
105
+ }
106
+ }
107
+
108
+ /** A `tool_use` child that survives slimming on its own account. */
109
+ function isKeptToolUse(tool: string): boolean {
110
+ return tool === "Agent" || tool === "Task" || FILE_MUTATION_TOOLS.has(tool);
111
+ }
112
+
113
+ export interface SlimAgentChildren {
114
+ /** Distinct child `tool_use` ids counted as steps, in arrival order. */
115
+ stepIds: string[];
116
+ /** Plain-text description of the most recent step, if any arrived. */
117
+ lastStep?: string;
118
+ /** Nested Agent/Task stubs (recursively slimmed) + file-mutation tool_use/result pairs. */
119
+ kept: ChatEvent[];
120
+ }
121
+
122
+ /**
123
+ * Recompute a subagent's `{stepIds, lastStep, kept}` from its full child list —
124
+ * used for a from-scratch reduction (history load for a card whose provider
125
+ * stamped `transcriptAvailable`, or any caller that only has the raw array and
126
+ * no running per-card state to update incrementally).
127
+ */
128
+ export function slimAgentChildren(children: ChatEvent[] | undefined): SlimAgentChildren {
129
+ const stepIds: string[] = [];
130
+ const kept: ChatEvent[] = [];
131
+ const keptToolUseIds = new Set<string>();
132
+ let lastStep: string | undefined;
133
+
134
+ (children ?? []).forEach((ev, i) => {
135
+ if (ev.type === "tool_use") {
136
+ stepIds.push(ev.toolUseId ?? `idx:${i}`);
137
+ const desc = describeStep(ev);
138
+ if (desc) lastStep = desc;
139
+ if (isKeptToolUse(ev.tool)) {
140
+ const isAgent = ev.tool === "Agent" || ev.tool === "Task";
141
+ if (isAgent) {
142
+ const nested = slimAgentChildren(ev.children);
143
+ kept.push({
144
+ ...ev,
145
+ children: nested.kept,
146
+ stepIds: nested.stepIds,
147
+ stepCount: nested.stepIds.length,
148
+ lastStep: nested.lastStep,
149
+ });
150
+ } else {
151
+ kept.push(ev);
152
+ }
153
+ if (ev.toolUseId) keptToolUseIds.add(ev.toolUseId);
154
+ }
155
+ } else if (ev.type === "tool_result") {
156
+ if (ev.toolUseId && keptToolUseIds.has(ev.toolUseId)) kept.push(ev);
157
+ }
158
+ // text/thinking/other event kinds are never kept in the slimmed set.
159
+ });
160
+
161
+ return { stepIds, lastStep, kept };
162
+ }
163
+
164
+ /**
165
+ * Recursive count of every `tool_use` across a card's whole subtree: this card's own direct
166
+ * steps (a nested Agent/Task counted once, for spawning it) plus, for each such nested card,
167
+ * everything further inside it. A nested Agent/Task stub is always kept in `.children` (never
168
+ * the ring buffer — see `isKeptToolUse`), so its own `stepCount`/`stepIds` is always the latest
169
+ * value live-routed into it, and summing over `.children` here never revisits the same id
170
+ * twice: the nested card's own direct count already excludes its own id.
171
+ */
172
+ export function recursiveStepCount(tool: Extract<ChatEvent, { type: "tool_use" }>): number {
173
+ const direct = tool.stepCount ?? tool.stepIds?.length ?? slimAgentChildren(tool.children).stepIds.length;
174
+ let total = direct;
175
+ for (const child of tool.children ?? []) {
176
+ if (child.type === "tool_use" && (child.tool === "Agent" || child.tool === "Task")) {
177
+ total += recursiveStepCount(child);
178
+ }
179
+ }
180
+ return total;
181
+ }
182
+
183
+ /** `{stepCount, lastStep}` for the one-line card: `stepCount` is always the recursive total
184
+ * (see `recursiveStepCount`) so it equals the session window's flat count; `lastStep` prefers
185
+ * the field a live card or a slimmed history card already carries, and only falls back to
186
+ * recomputing from `children` when unset (e.g. a card rendered straight from a server search
187
+ * result, or an unstamped history card that kept its full list). */
188
+ export function agentStepInfo(tool: Extract<ChatEvent, { type: "tool_use" }>): { stepCount: number; lastStep?: string } {
189
+ const stepCount = recursiveStepCount(tool);
190
+ if (tool.stepCount != null) return { stepCount, lastStep: tool.lastStep };
191
+ const { lastStep } = slimAgentChildren(tool.children);
192
+ return { stepCount, lastStep };
193
+ }
194
+
195
+ function approxByteSize(ev: ChatEvent): number {
196
+ try { return JSON.stringify(ev).length; } catch { return 0; }
197
+ }
198
+
199
+ /** Drop oldest entries (keeping at least one) while the buffer's approximate serialized
200
+ * size exceeds `MAX_RECENT_BYTES` — a count cap alone lets a handful of huge tool outputs
201
+ * through untouched. */
202
+ function capByBytes(buffer: ChatEvent[]): ChatEvent[] {
203
+ let total = buffer.reduce((sum, e) => sum + approxByteSize(e), 0);
204
+ let start = 0;
205
+ while (total > MAX_RECENT_BYTES && start < buffer.length - 1) {
206
+ total -= approxByteSize(buffer[start]!);
207
+ start++;
208
+ }
209
+ return start > 0 ? buffer.slice(start) : buffer;
210
+ }
211
+
212
+ /**
213
+ * Upsert `ev` into a bounded ring buffer: a WS replay re-delivering the same
214
+ * `toolUseId` replaces the existing entry in place instead of growing the
215
+ * buffer, and anything past `MAX_RECENT_CHILDREN` (count) or `MAX_RECENT_BYTES`
216
+ * (approximate serialized size) is dropped from the front.
217
+ *
218
+ * `seq` stamps the entry's `arrivalSeq` for `mergeFallbackEvents` to later
219
+ * interleave this buffer back together with the kept `children` list in the
220
+ * order events actually arrived — omitted by direct/standalone callers that
221
+ * have no parent-level counter to hand it a value.
222
+ */
223
+ export function pushRecentChild(buffer: ChatEvent[], ev: ChatEvent, seq?: number): ChatEvent[] {
224
+ const id = (ev as { toolUseId?: string }).toolUseId;
225
+ if (id) {
226
+ const idx = buffer.findIndex((e) => e.type === ev.type && (e as { toolUseId?: string }).toolUseId === id);
227
+ if (idx !== -1) {
228
+ const preserved = (buffer[idx] as { arrivalSeq?: number }).arrivalSeq;
229
+ const next = [...buffer];
230
+ next[idx] = (seq != null ? { ...ev, arrivalSeq: preserved } : ev) as ChatEvent;
231
+ return next;
232
+ }
233
+ }
234
+ const stamped = seq != null ? ({ ...ev, arrivalSeq: seq } as ChatEvent) : ev;
235
+ const next = [...buffer, stamped];
236
+ const capped = next.length > MAX_RECENT_CHILDREN ? next.slice(next.length - MAX_RECENT_CHILDREN) : next;
237
+ return capByBytes(capped);
238
+ }
239
+
240
+ /**
241
+ * Merge kept `children` with the bounded "other" ring buffer back into the order events
242
+ * actually arrived in: splitting live arrivals into a kept list and a ring buffer by
243
+ * kind (nested-agent/file-mutation vs everything else) loses the interleaving between them —
244
+ * a plain concatenation showed every edit before the reads that actually preceded it. Each
245
+ * entry's `arrivalSeq` (stamped by `applyChildToParent`/`pushRecentChild`) says where it
246
+ * really sorts; an entry with none (never live-routed, e.g. a history-loaded card, which
247
+ * never populates both lists at once) keeps its position within its own list.
248
+ */
249
+ export function mergeFallbackEvents(kept: ChatEvent[], recent: ChatEvent[]): ChatEvent[] {
250
+ const tag = (list: ChatEvent[]) =>
251
+ list.map((ev, i) => ({ ev, seq: (ev as { arrivalSeq?: number }).arrivalSeq ?? i }));
252
+ return [...tag(kept), ...tag(recent)]
253
+ .sort((a, b) => a.seq - b.seq)
254
+ .map((e) => e.ev);
255
+ }
256
+
257
+ /**
258
+ * Apply one newly-arrived child event to its Agent/Task parent, updating
259
+ * `stepIds`/`stepCount`/`lastStep` and routing the child into either the kept
260
+ * `children` (nested stub or file mutation, upserted by id the same way the
261
+ * pre-slimming code deduped a replay) or the `recentChildren` ring buffer.
262
+ *
263
+ * Every routed child is stamped with the parent's monotonic `childSeq` (preserved rather
264
+ * than reassigned when the upsert is an update-in-place, e.g. a tool_result arriving for an
265
+ * already-kept tool_use) — the arrival order `mergeFallbackEvents` needs to interleave
266
+ * `children` and `recentChildren` back together correctly.
267
+ */
268
+ export function applyChildToParent(parent: ChatEvent, childEvent: ChatEvent): ChatEvent {
269
+ if (parent.type !== "tool_use") return parent;
270
+
271
+ let stepIds = parent.stepIds;
272
+ let lastStep = parent.lastStep;
273
+ if (childEvent.type === "tool_use") {
274
+ const id = childEvent.toolUseId;
275
+ if (!id || !stepIds?.includes(id)) stepIds = [...(stepIds ?? []), id ?? `idx:${stepIds?.length ?? 0}`];
276
+ const desc = describeStep(childEvent);
277
+ if (desc) lastStep = desc;
278
+ }
279
+
280
+ const seq = parent.childSeq ?? 0;
281
+
282
+ const upsertKept = (list: ChatEvent[]): ChatEvent[] => {
283
+ const id = (childEvent as { toolUseId?: string }).toolUseId;
284
+ const idx = id ? list.findIndex((c) => c.type === childEvent.type && (c as { toolUseId?: string }).toolUseId === id) : -1;
285
+ if (idx !== -1) {
286
+ const preserved = (list[idx] as { arrivalSeq?: number }).arrivalSeq;
287
+ const next = [...list];
288
+ next[idx] = { ...childEvent, arrivalSeq: preserved } as ChatEvent;
289
+ return next;
290
+ }
291
+ return [...list, { ...childEvent, arrivalSeq: seq } as ChatEvent];
292
+ };
293
+
294
+ const children = parent.children ?? [];
295
+ const recentChildren = parent.recentChildren ?? [];
296
+ const isKeptToolUseChild = childEvent.type === "tool_use" && isKeptToolUse(childEvent.tool);
297
+ const matchesKeptToolUse = (id: string | undefined) =>
298
+ !!id && children.some((c) => c.type === "tool_use" && c.toolUseId === id);
299
+
300
+ let nextChildren = children;
301
+ let nextRecent = recentChildren;
302
+ if (isKeptToolUseChild) {
303
+ nextChildren = upsertKept(children);
304
+ } else if (childEvent.type === "tool_result" && matchesKeptToolUse(childEvent.toolUseId)) {
305
+ nextChildren = upsertKept(children);
306
+ } else {
307
+ nextRecent = pushRecentChild(recentChildren, childEvent, seq);
308
+ }
309
+
310
+ return {
311
+ ...parent,
312
+ children: nextChildren,
313
+ recentChildren: nextRecent,
314
+ stepIds,
315
+ stepCount: stepIds?.length,
316
+ lastStep,
317
+ childSeq: seq + 1,
318
+ };
319
+ }
320
+
321
+ /** Walk a history message tree, slimming every Agent/Task card a provider
322
+ * stamped `transcriptAvailable` on; an unstamped card keeps its full children
323
+ * (there is no disk source to fall back to, so it stays the fallback itself). */
324
+ export function slimHistoryEvents(events: ChatEvent[] | undefined): ChatEvent[] | undefined {
325
+ if (!events) return events;
326
+ return events.map((ev) => {
327
+ if (ev.type !== "tool_use" || (ev.tool !== "Agent" && ev.tool !== "Task") || !ev.transcriptAvailable) return ev;
328
+ const { stepIds, lastStep, kept } = slimAgentChildren(ev.children);
329
+ return { ...ev, children: kept, stepIds, stepCount: stepIds.length, lastStep };
330
+ });
331
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Tiny synchronisation point between `useGlobalEvents`'s socket and every other hook that
3
+ * needs to send on `/ws/global` without holding a `WsClient` reference of its own.
4
+ *
5
+ * Deliberately not a queue: `WsClient.send` already queues a message while the socket is
6
+ * still connecting and flushes it on open, which is exactly wrong for a subscription —
7
+ * flushing a stale `agent-transcript:subscribe` after the fact would resume from whatever
8
+ * cursor it was built with, not the latest one the caller has since applied. `sendIfOpen`
9
+ * drops instead, and every caller re-sends explicitly from `onGlobalReady` using whatever
10
+ * cursor it holds at that moment.
11
+ */
12
+ import type { WsClient } from "./ws-client";
13
+
14
+ type ReadyListener = () => void;
15
+
16
+ let client: WsClient | null = null;
17
+ const readyListeners = new Set<ReadyListener>();
18
+
19
+ /** Called by `useGlobalEvents` to register (or clear, on teardown) the socket every other
20
+ * hook sends through. */
21
+ export function setGlobalWsClient(next: WsClient | null): void {
22
+ client = next;
23
+ }
24
+
25
+ /** Send now, or drop — never queue. Returns whether the message actually went out. */
26
+ export function sendIfOpen(message: string): boolean {
27
+ if (!client?.isConnected) return false;
28
+ client.send(message);
29
+ return true;
30
+ }
31
+
32
+ /** Fires on every `global_ready` (initial connect and every reconnect). */
33
+ export function onGlobalReady(listener: ReadyListener): () => void {
34
+ readyListeners.add(listener);
35
+ return () => readyListeners.delete(listener);
36
+ }
37
+
38
+ /** Called by `useGlobalEvents` when the server confirms the socket is ready. */
39
+ export function notifyGlobalReady(): void {
40
+ for (const listener of readyListeners) listener();
41
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Pure row-building for the running-agents bar — merges the transcript hub's
3
+ * liveness feed (`agent-activity`, disk-derived: card or teammate, last write
4
+ * time, last step) with the team panel's own richer poll (`useTeamActivityFeed`:
5
+ * agent type, started-at) and the chat's own in-memory state (a known card's
6
+ * description/handle beats a bare id). Kept free of React so the merge and the
7
+ * label lookup are directly unit-testable.
8
+ */
9
+ import type { ChatEvent, ChatMessage } from "../../types/chat";
10
+ import type { TeamMemberActivity } from "../hooks/use-team-activity-feed";
11
+ import type { AgentTranscriptRunningEntry } from "../../shared/agent-transcript-protocol";
12
+
13
+ export interface RunningAgentRow {
14
+ key: string;
15
+ cardId?: string;
16
+ memberName?: string;
17
+ lastStep?: string;
18
+ agentType?: string;
19
+ /** ISO timestamp — only known for a teammate the team panel has already polled. */
20
+ startedAt?: string;
21
+ lastWriteAt?: number;
22
+ }
23
+
24
+ /**
25
+ * Combine the hub feed with the team panel's poll. The hub decides *who is
26
+ * running* (disk mtime within its activity window); the team poll only ever
27
+ * adds metadata (agent type, started-at) for a name the hub already reported —
28
+ * except when the poll is ahead of the hub's few-second cadence, in which case
29
+ * a `workState === "working"` member the hub hasn't caught up to yet is added
30
+ * too, so a teammate never visibly drops out of the bar between polls.
31
+ */
32
+ export function buildRunningRows(
33
+ running: AgentTranscriptRunningEntry[],
34
+ teamMembers: TeamMemberActivity[],
35
+ ): RunningAgentRow[] {
36
+ const byMemberName = new Map(teamMembers.map((m) => [m.name, m]));
37
+ const seenMembers = new Set<string>();
38
+ const rows: RunningAgentRow[] = [];
39
+
40
+ for (const entry of running) {
41
+ if (entry.cardId) {
42
+ rows.push({ key: `card:${entry.cardId}`, cardId: entry.cardId, lastStep: entry.lastStep, lastWriteAt: entry.lastWriteAt });
43
+ continue;
44
+ }
45
+ if (entry.memberName) {
46
+ seenMembers.add(entry.memberName);
47
+ const member = byMemberName.get(entry.memberName);
48
+ rows.push({
49
+ key: `member:${entry.memberName}`,
50
+ memberName: entry.memberName,
51
+ lastStep: entry.lastStep ?? (member ? currentStepOf(member) : undefined),
52
+ agentType: member?.agentType,
53
+ startedAt: member?.startedAt,
54
+ lastWriteAt: entry.lastWriteAt,
55
+ });
56
+ }
57
+ }
58
+
59
+ for (const member of teamMembers) {
60
+ if (member.workState !== "working" || seenMembers.has(member.name)) continue;
61
+ rows.push({
62
+ key: `member:${member.name}`,
63
+ memberName: member.name,
64
+ lastStep: currentStepOf(member),
65
+ agentType: member.agentType,
66
+ startedAt: member.startedAt,
67
+ });
68
+ }
69
+
70
+ return rows;
71
+ }
72
+
73
+ function currentStepOf(member: TeamMemberActivity): string | undefined {
74
+ if (member.lastTool) return member.lastToolArg ? `${member.lastTool}: ${member.lastToolArg}` : member.lastTool;
75
+ return member.lastNarrative ?? member.description;
76
+ }
77
+
78
+ /** A known card's label, read straight from the chat's own in-memory events —
79
+ * beats a bare id when the card is still in this tab's history. */
80
+ export interface CardLabel {
81
+ handle: string | null;
82
+ description: string;
83
+ }
84
+
85
+ function addressableName(input: unknown): string | null {
86
+ const name = input && typeof input === "object" ? (input as Record<string, unknown>).name : undefined;
87
+ return typeof name === "string" && name.trim() ? name.trim() : null;
88
+ }
89
+
90
+ function findInEvents(events: ChatEvent[] | undefined, cardId: string): ChatEvent | undefined {
91
+ if (!events) return undefined;
92
+ for (const ev of events) {
93
+ if (ev.type === "tool_use" && (ev.tool === "Agent" || ev.tool === "Task") && ev.toolUseId === cardId) return ev;
94
+ if (ev.type === "tool_use" && ev.children?.length) {
95
+ const nested = findInEvents(ev.children, cardId);
96
+ if (nested) return nested;
97
+ }
98
+ }
99
+ return undefined;
100
+ }
101
+
102
+ export function findCardLabel(messages: ChatMessage[], cardId: string): CardLabel | null {
103
+ for (let i = messages.length - 1; i >= 0; i--) {
104
+ const found = findInEvents(messages[i]!.events, cardId);
105
+ if (found && found.type === "tool_use") {
106
+ const input = found.input && typeof found.input === "object" ? (found.input as Record<string, unknown>) : {};
107
+ return {
108
+ handle: addressableName(input),
109
+ description: typeof input.description === "string" ? input.description
110
+ : typeof input.prompt === "string" ? input.prompt : "",
111
+ };
112
+ }
113
+ }
114
+ return null;
115
+ }
@@ -1 +0,0 @@
1
- import{s as e}from"./rolldown-runtime-C5c2KzVm.js";import{C as t,S as n}from"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import{Jr as r,Lr as i,Mr as a,St as o,V as s,Zn as c,Zt as l,fn as u,fr as d,nt as f,st as p,un as m}from"./icons-CO_II6D-.js";import{a as h}from"./api-client-F5Zi1sR0.js";import{n as g}from"./utils-btZ8C8-R.js";import"./portal-container-context-NFSuymMu.js";import"./chat-preparation-cache-DoS7sdal.js";import{n as _}from"./use-is-mobile-CkO33jqU.js";import{n as v,t as y}from"./button-CsmGH5xa.js";import{a as b,i as x,n as S,o as C,r as w,t as T}from"./dialog-z8PLkL8n.js";import{t as E}from"./mobile-bottom-sheet-CLic9ovp.js";import"./use-visual-viewport-C307OVeV.js";import{t as D}from"./input-CP31LZnN.js";import{Ct as O,In as k,Nt as A,Qn as j,St as M,bt as N,dr as P,fr as F,pr as I,vt as ee,xt as te,yt as ne}from"./index-DQCw6d-2.js";import{_ as re,a as ie,h as ae,m as oe,o as se,p as ce,r as le,v as ue,x as L,y as de}from"./api-settings-BeINN5Dy.js";import{_ as fe,a as pe,b as me,c as he,d as ge,g as R,h as z,l as _e,m as ve,n as ye,o as be,p as B,r as xe,s as V,t as Se,u as Ce,x as H,y as U}from"./codex-reset-credit-button-D2hal4bG.js";var W=e(t(),1),G=n(),K=[`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`,`Sun`],q=Array.from({length:24},(e,t)=>t);function we(e,t){let n=Array.from({length:7},()=>Array.from({length:24},()=>({sum:0,count:0,avg:0})));for(let r of e){let e=t===`5h`?r.five_hour_util:r.weekly_util;if(e==null)continue;let i=new Date(r.recorded_at+(r.recorded_at.endsWith(`Z`)?``:`Z`)),a=(i.getDay()+6)%7,o=i.getHours();n[a][o].sum+=e,n[a][o].count+=1}for(let e of n)for(let t of e)t.avg=t.count>0?t.sum/t.count:0;return n}function Te(e){return e.map(e=>{let t=e.reduce((e,t)=>e+t.sum,0),n=e.reduce((e,t)=>e+t.count,0);return n>0?t/n:0})}function Ee(e){return q.map(t=>{let n=0,r=0;for(let i of e)n+=i[t].sum,r+=i[t].count;return r>0?n/r:0})}function J(e){return e===0?`bg-surface-elevated`:e<.3?`bg-success/30`:e<.5?`bg-success/60`:e<.7?`bg-warning/50`:e<.9?`bg-warning/80`:`bg-error/80`}function De(e){return e<.3?`bg-success`:e<.7?`bg-warning`:`bg-error`}function Oe({accountId:e}){let[t,n]=(0,W.useState)(null),[r,i]=(0,W.useState)(!0),[a,o]=(0,W.useState)(`5h`);(0,W.useEffect)(()=>{i(!0),ce(e).then(n).catch(()=>n([])).finally(()=>i(!1))},[e]);let s=(0,W.useMemo)(()=>t?we(t,a):null,[t,a]),c=(0,W.useMemo)(()=>s?Te(s):[],[s]),l=(0,W.useMemo)(()=>s?Ee(s):[],[s]),u=Math.max(...c,.01);if(Math.max(...l,.01),r)return(0,G.jsx)(`div`,{className:`flex items-center justify-center py-3`,children:(0,G.jsx)(m,{className:`size-3 animate-spin text-text-subtle`})});if(!t||t.length===0)return(0,G.jsx)(`div`,{className:`text-[10px] text-text-subtle py-2 text-center`,children:`No usage history yet`});let d=t.length,f=new Set(t.map(e=>new Date(e.recorded_at+(e.recorded_at.endsWith(`Z`)?``:`Z`)).toDateString())).size;return(0,G.jsxs)(`div`,{className:`mt-2 space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`span`,{className:`text-[10px] font-medium text-text-subtle`,children:`Usage Pattern (7d)`}),(0,G.jsxs)(`div`,{className:`flex gap-0.5 text-[9px]`,children:[(0,G.jsx)(`button`,{onClick:()=>o(`5h`),className:`px-1.5 py-0.5 rounded cursor-pointer transition-colors ${a===`5h`?`bg-primary/15 text-primary`:`text-text-subtle hover:text-text-secondary`}`,title:`5-hour rolling window limit — resets every 5 hours`,children:`5h`}),(0,G.jsx)(`button`,{onClick:()=>o(`weekly`),className:`px-1.5 py-0.5 rounded cursor-pointer transition-colors ${a===`weekly`?`bg-primary/15 text-primary`:`text-text-subtle hover:text-text-secondary`}`,title:`Weekly limit — resets every 7 days`,children:`Wk`})]})]}),(0,G.jsxs)(`p`,{className:`text-[9px] text-text-subtle leading-tight`,children:[`Avg `,a===`5h`?`5-hour`:`weekly`,` limit usage over `,f,`d (`,d,` samples). Higher % = closer to rate limit. Hover cells for details.`]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{className:`text-[9px] text-text-subtle`,children:`Avg usage by day of week`}),(0,G.jsx)(`div`,{className:`flex flex-col gap-[2px] mt-0.5`,children:K.map((e,t)=>{let n=c[t]??0;return(0,G.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,G.jsx)(`span`,{className:`text-[8px] text-text-subtle w-5 shrink-0 text-right tabular-nums`,children:e}),(0,G.jsx)(`div`,{className:`flex-1 h-2.5 bg-surface-elevated rounded-sm overflow-hidden`,children:(0,G.jsx)(`div`,{className:`h-full rounded-sm transition-all ${De(n)}`,style:{width:`${Math.round(n/u*100)}%`}})}),(0,G.jsxs)(`span`,{className:`text-[8px] text-text-subtle w-6 shrink-0 text-right tabular-nums`,children:[Math.round(n*100),`%`]})]},e)})})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{className:`text-[9px] text-text-subtle`,children:`Avg usage by hour (0h-23h)`}),(0,G.jsx)(`div`,{className:`flex gap-[1px] mt-0.5`,children:q.map(e=>{let t=l[e]??0;return(0,G.jsxs)(`div`,{className:`flex-1 flex flex-col items-center gap-[1px]`,children:[(0,G.jsx)(`div`,{className:`w-full aspect-square rounded-[2px] ${J(t)}`,title:`${e}:00 — avg ${Math.round(t*100)}% usage`}),e%6==0&&(0,G.jsx)(`span`,{className:`text-[7px] text-text-subtle tabular-nums`,children:e})]},e)})})]}),s&&(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{className:`text-[9px] text-text-subtle`,children:`Day x Hour heatmap`}),(0,G.jsxs)(`div`,{className:`flex flex-col gap-[1px] mt-0.5`,children:[K.map((e,t)=>(0,G.jsxs)(`div`,{className:`flex items-center gap-[1px]`,children:[(0,G.jsx)(`span`,{className:`text-[7px] text-text-subtle w-4 shrink-0 text-right`,children:e.charAt(0)}),q.map(n=>{let r=s[t][n];return(0,G.jsx)(`div`,{className:`flex-1 aspect-square rounded-[1px] ${J(r.avg)}`,title:`${e} ${n}:00 — ${r.count>0?`avg ${Math.round(r.avg*100)}% (${r.count} samples)`:`no data`}`},n)})]},e)),(0,G.jsxs)(`div`,{className:`flex items-center gap-[1px]`,children:[(0,G.jsx)(`span`,{className:`w-4 shrink-0`}),q.map(e=>(0,G.jsx)(`div`,{className:`flex-1 text-center`,children:e%6==0&&(0,G.jsx)(`span`,{className:`text-[7px] text-text-subtle tabular-nums`,children:e})},e))]})]})]}),(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[8px] text-text-subtle`,children:[(0,G.jsx)(`span`,{children:`Low`}),(0,G.jsxs)(`div`,{className:`flex gap-[2px]`,children:[(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-success/30`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-success/60`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-warning/50`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-warning/80`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-error/80`})]}),(0,G.jsx)(`span`,{children:`High`}),(0,G.jsx)(`span`,{className:`ml-1`,children:`|`}),(0,G.jsx)(`div`,{className:`size-2 rounded-[1px] bg-surface-elevated border border-border/30`}),(0,G.jsx)(`span`,{children:`No data`})]})]})}function ke({profile:e,accountId:t,onClose:n}){let i=[[`Name`,e.account?.display_name],[`Email`,e.account?.email],[`Org`,e.organization?.name],[`Type`,e.organization?.organization_type],[`Tier`,e.organization?.rate_limit_tier],[`Status`,e.organization?.subscription_status]];return(0,G.jsxs)(`section`,{className:`space-y-2 border-t border-border pt-3`,"data-testid":`account-profile-panel`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium`,children:`Profile`}),(0,G.jsx)(`button`,{className:`p-2 text-muted-foreground hover:text-foreground cursor-pointer`,onClick:n,"aria-label":`Close profile`,children:(0,G.jsx)(r,{className:`size-4`})})]}),(0,G.jsx)(`div`,{className:`grid grid-cols-[80px_1fr] gap-x-3 gap-y-1 text-xs`,children:i.map(([e,t])=>t?(0,G.jsxs)(`span`,{className:`contents`,children:[(0,G.jsx)(`span`,{className:`text-muted-foreground`,children:e}),(0,G.jsx)(`span`,{className:`break-all`,children:t})]},e):null)}),(0,G.jsx)(Oe,{accountId:t})]})}function Ae({display:e,onConfirm:t,onCancel:n}){let r=_(),i=(0,G.jsxs)(`div`,{className:`space-y-4`,"data-testid":`account-delete-confirm`,children:[(0,G.jsxs)(`p`,{className:`text-sm`,children:[`Remove `,(0,G.jsx)(`span`,{className:`font-medium`,children:e}),`?`]}),(0,G.jsx)(`p`,{className:`text-xs text-text-subtle`,children:`The stored token is deleted from this machine. Any export you already made keeps working.`}),(0,G.jsxs)(`div`,{className:`flex flex-col-reverse md:flex-row gap-2 md:justify-end pt-2`,children:[(0,G.jsx)(y,{variant:`outline`,onClick:n,className:`min-h-11`,children:`Cancel`}),(0,G.jsx)(y,{variant:`destructive`,autoFocus:!1,onClick:t,className:`min-h-11`,children:`Remove account`})]})]});return r?(0,G.jsx)(E,{open:!0,onClose:n,children:(0,G.jsxs)(`div`,{className:`px-4 pb-4`,children:[(0,G.jsx)(`h2`,{className:`text-base font-semibold mb-3`,children:`Remove account`}),i]})}):(0,G.jsx)(T,{open:!0,onOpenChange:e=>{e||n()},children:(0,G.jsxs)(S,{className:`sm:max-w-sm`,children:[(0,G.jsx)(b,{children:(0,G.jsx)(C,{className:`text-sm`,children:`Remove account`})}),i]})})}function je(e){let t=new Blob([e],{type:`application/json`}),n=document.createElement(`a`);n.href=URL.createObjectURL(t),n.download=`ppm-accounts-backup.json`,n.click(),URL.revokeObjectURL(n.href)}function Me({open:e,onOpenChange:t,accounts:n,preselectId:r,onMessage:i}){let a=n.filter(e=>e.hasRefreshToken),[o,s]=(0,W.useState)(new Set),[c,l]=(0,W.useState)(``),[d,g]=(0,W.useState)(!1),[_,v]=(0,W.useState)(!1),[E,O]=(0,W.useState)(!1),[j,M]=(0,W.useState)(!1);e&&!j&&(s(r?new Set([r]):new Set(a.map(e=>e.id))),M(!0)),!e&&j&&M(!1);function N(){t(!1),l(``),g(!1),v(!1)}async function P(e){if(o.size===0)return;O(!0);let t=c.trim()||`ppm-hienlh`;try{let n={"Content-Type":`application/json`},r=h();r&&(n.Authorization=`Bearer ${r}`);let a=await fetch(`/api/accounts/export`,{method:`POST`,headers:n,body:JSON.stringify({password:t,accountIds:[...o],includeRefreshToken:d,refreshBeforeExport:_})});if(!a.ok){let e=await a.json();throw Error(e.error??`Export failed: ${a.status}`)}let s=await a.text();e&&await k(s)?i?.(`Backup copied to clipboard!`):(je(s),i?.(`Backup downloaded.`)),N()}catch{}O(!1)}let F=o.size>0&&!E;return(0,G.jsx)(T,{open:e,onOpenChange:e=>{e||N()},children:(0,G.jsxs)(S,{className:`sm:max-w-md`,children:[(0,G.jsxs)(b,{children:[(0,G.jsxs)(C,{className:`text-sm flex items-center gap-1.5`,children:[(0,G.jsx)(u,{className:`size-3.5`}),` Export Accounts`]}),(0,G.jsx)(w,{className:`text-xs`,children:`Select accounts and set a password to protect the backup.`})]}),(0,G.jsxs)(`div`,{className:`space-y-3`,children:[(0,G.jsxs)(`div`,{className:`space-y-1`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between mb-1`,children:[(0,G.jsx)(`p`,{className:`text-[11px] font-medium text-muted-foreground`,children:`Accounts to export`}),(0,G.jsx)(`button`,{className:`text-[10px] text-primary hover:underline cursor-pointer`,onClick:()=>s(o.size===a.length?new Set:new Set(a.map(e=>e.id))),children:o.size===a.length?`Deselect all`:`Select all`})]}),a.length===0?(0,G.jsx)(`p`,{className:`text-[10px] text-muted-foreground p-2 border rounded`,children:`No exportable accounts.`}):(0,G.jsx)(`div`,{className:`max-h-36 overflow-y-auto space-y-1 border rounded p-2`,children:a.map(e=>(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`input`,{type:`checkbox`,id:`exp-${e.id}`,checked:o.has(e.id),onChange:t=>{let n=new Set(o);t.target.checked?n.add(e.id):n.delete(e.id),s(n)},className:`size-3.5 accent-primary cursor-pointer`}),(0,G.jsx)(`label`,{htmlFor:`exp-${e.id}`,className:`text-xs cursor-pointer truncate`,children:e.label??e.email??e.id.slice(0,8)})]},e.id))})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsxs)(A,{className:`text-xs`,children:[`Password `,(0,G.jsx)(`span`,{className:`text-muted-foreground font-normal`,children:`(optional)`})]}),(0,G.jsx)(D,{type:`password`,placeholder:`Leave empty for default`,value:c,onChange:e=>l(e.target.value),className:`text-xs h-8`,autoComplete:`new-password`})]}),(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`input`,{type:`checkbox`,id:`exp-full`,checked:d,onChange:e=>g(e.target.checked),className:`size-3.5 accent-primary cursor-pointer`}),(0,G.jsx)(`label`,{htmlFor:`exp-full`,className:`text-[11px] cursor-pointer`,children:`Include refresh tokens (full transfer)`})]}),(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`input`,{type:`checkbox`,id:`exp-refresh`,checked:_,onChange:e=>v(e.target.checked),className:`size-3.5 accent-primary cursor-pointer`}),(0,G.jsx)(`label`,{htmlFor:`exp-refresh`,className:`text-[11px] cursor-pointer`,children:`Refresh tokens before export`})]}),d?(0,G.jsxs)(`div`,{className:`rounded-md border border-error/30 bg-error/5 p-2.5`,children:[(0,G.jsx)(`p`,{className:`text-[10px] font-medium text-error`,children:`Full transfer — source accounts will expire`}),(0,G.jsx)(`p`,{className:`text-[10px] text-muted-foreground`,children:`Refresh tokens included. Source machine expires in ~1h after target refreshes.`})]}):_?(0,G.jsx)(`div`,{className:`rounded-md border border-warning/30 bg-warning/5 p-2.5`,children:(0,G.jsx)(`p`,{className:`text-[10px] font-medium text-warning`,children:`Refresh before export — invalidates previous shares`})}):(0,G.jsx)(`div`,{className:`rounded-md border border-success/30 bg-success/5 p-2.5`,children:(0,G.jsx)(`p`,{className:`text-[10px] font-medium text-success`,children:`Share current token (safe)`})}),(0,G.jsx)(`p`,{className:`text-[10px] text-muted-foreground`,children:`Encrypted with AES-256-GCM + scrypt.`})]}),(0,G.jsxs)(x,{className:`gap-1.5 flex-col sm:flex-row`,children:[(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs h-7 cursor-pointer`,onClick:N,children:`Cancel`}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`text-xs h-7 cursor-pointer`,disabled:!F,onClick:()=>P(!0),children:[(0,G.jsx)(f,{className:`size-3 mr-1`}),` Copy`]}),(0,G.jsx)(y,{size:`sm`,className:`text-xs h-7 cursor-pointer`,disabled:!F,onClick:()=>P(!1),children:E?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(m,{className:`size-3 animate-spin mr-1`}),` Exporting...`]}):(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(p,{className:`size-3 mr-1`}),` Download`]})})]})]})})}function Ne({open:e,onOpenChange:t,onSuccess:n}){let[r,i]=(0,W.useState)(``),[a,o]=(0,W.useState)(``),[s,c]=(0,W.useState)(!1),[l,d]=(0,W.useState)(null);function f(){t(!1),i(``),o(``),d(null)}async function p(){if(r.trim()){c(!0),d(null);try{let e=await oe({data:r.trim(),password:a.trim()||`ppm-hienlh`});f(),n(`Imported ${e.imported} account(s)`)}catch(e){d(e.message||`Import failed`)}c(!1)}}return(0,G.jsx)(T,{open:e,onOpenChange:e=>{e||f()},children:(0,G.jsxs)(S,{className:`sm:max-w-md`,children:[(0,G.jsxs)(b,{children:[(0,G.jsxs)(C,{className:`text-sm flex items-center gap-1.5`,children:[(0,G.jsx)(u,{className:`size-3.5`}),` Import Accounts`]}),(0,G.jsx)(w,{className:`text-xs`,children:`Paste backup data and enter the export password. Imported accounts are temporary (~1h).`})]}),(0,G.jsxs)(`div`,{className:`space-y-3`,children:[(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsx)(A,{className:`text-xs`,children:`Backup data`}),(0,G.jsx)(`textarea`,{value:r,onChange:e=>i(e.target.value),placeholder:`Paste backup JSON here...`,rows:4,className:`w-full text-xs p-2 rounded border border-border bg-background font-mono resize-none focus:outline-none focus:ring-1 focus:ring-primary`})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsxs)(A,{className:`text-xs`,children:[`Password `,(0,G.jsx)(`span`,{className:`text-muted-foreground font-normal`,children:`(optional)`})]}),(0,G.jsx)(D,{type:`password`,placeholder:`Leave empty for default`,value:a,onChange:e=>o(e.target.value),className:`text-xs h-8`,autoComplete:`current-password`})]})]}),l&&(0,G.jsx)(`div`,{className:`text-[11px] p-2 rounded bg-error/10 text-error`,children:l}),(0,G.jsxs)(x,{children:[(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs h-7 cursor-pointer`,onClick:f,children:`Cancel`}),(0,G.jsx)(y,{size:`sm`,className:`text-xs h-7 cursor-pointer`,disabled:!r.trim()||s,onClick:p,children:s?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(m,{className:`size-3 animate-spin mr-1`}),` Importing...`]}):`Import`})]})]})})}var Y=typeof window<`u`?window.matchMedia(`(min-width: 768px)`):null;function Pe(e){return Y?.addEventListener(`change`,e),()=>Y?.removeEventListener(`change`,e)}function Fe(){return Y?.matches??!0}function X(){let[e,t]=(0,W.useState)(null),[n,r]=(0,W.useState)(!0);return(0,W.useEffect)(()=>{r(!0),se().then(t).finally(()=>r(!1))},[]),n?(0,G.jsx)(`p`,{className:`text-xs text-text-subtle py-4 text-center`,children:`Loading...`}):e?(0,G.jsxs)(`div`,{className:`space-y-4`,children:[(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsx)(`label`,{className:`text-xs font-medium text-text-primary`,children:`Rotation Strategy`}),(0,G.jsxs)(ee,{value:e.strategy,onValueChange:async e=>{t(await L({strategy:e}))},children:[(0,G.jsx)(te,{className:`w-full h-9 text-xs`,children:(0,G.jsx)(M,{})}),(0,G.jsxs)(ne,{children:[(0,G.jsx)(N,{value:`round-robin`,children:`Round-robin`}),(0,G.jsx)(N,{value:`fill-first`,children:`Fill-first`}),(0,G.jsx)(N,{value:`lowest-usage`,children:`Lowest usage`})]})]}),(0,G.jsxs)(`p`,{className:`text-[10px] text-text-subtle`,children:[e.strategy===`round-robin`&&`Cycles through accounts evenly`,e.strategy===`fill-first`&&`Uses one account until its limit, then moves on`,e.strategy===`lowest-usage`&&`Picks the account with the lowest current usage`]})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsx)(`label`,{className:`text-xs font-medium text-text-primary`,children:`Max Retry`}),(0,G.jsx)(`input`,{type:`number`,min:0,value:e.maxRetry,className:`w-full h-9 text-xs border rounded-md px-3 bg-background`,onChange:async e=>{let n=parseInt(e.target.value,10);!isNaN(n)&&n>=0&&t(await L({maxRetry:n}))}}),(0,G.jsx)(`p`,{className:`text-[10px] text-text-subtle`,children:`How many accounts to try on failure. 0 = try all available accounts.`})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5 border-t border-border pt-3`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`label`,{className:`text-xs font-medium text-text-primary`,children:`Cooldown parking`}),(0,G.jsx)(O,{checked:e.cooldownEnabled,onCheckedChange:async e=>{t(await L({cooldownEnabled:e}))}})]}),(0,G.jsx)(`p`,{className:`text-[10px] text-text-subtle`,children:`Park a failing account (rate limit / usage limit / auth error) until it recovers. Off: accounts stay selectable — rotation still skips accounts already ≥95% on the 5-hour limit.`})]}),(0,G.jsxs)(`div`,{className:`flex items-center justify-between text-xs border-t border-border pt-3`,children:[(0,G.jsx)(`span`,{className:`text-text-subtle`,children:`Active accounts`}),(0,G.jsx)(`span`,{className:`font-medium text-text-primary`,children:e.activeCount})]})]}):(0,G.jsx)(`p`,{className:`text-xs text-text-subtle py-4 text-center`,children:`Failed to load settings`})}function Ie({open:e,onOpenChange:t}){let n=(0,W.useSyncExternalStore)(Pe,Fe);return e?n?(0,G.jsx)(T,{open:e,onOpenChange:t,children:(0,G.jsxs)(S,{className:`sm:max-w-sm`,children:[(0,G.jsx)(b,{children:(0,G.jsxs)(C,{className:`text-sm flex items-center gap-2`,children:[(0,G.jsx)(d,{className:`size-4`}),` Rotation & Retry`]})}),(0,G.jsx)(X,{})]})}):(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`fixed inset-0 z-50 transition-opacity duration-200 opacity-100`,onClick:()=>t(!1),style:{backgroundColor:`rgba(0,0,0,0.5)`}}),(0,G.jsxs)(`div`,{className:g(`fixed bottom-0 left-0 right-0 z-50 bg-background rounded-t-2xl border-t border-border shadow-2xl`,`transition-transform duration-300 ease-out max-h-[85vh] overflow-y-auto`,`translate-y-0`),children:[(0,G.jsx)(`div`,{className:`flex justify-center pt-3 pb-1`,children:(0,G.jsx)(`div`,{className:`w-10 h-1 rounded-full bg-border`})}),(0,G.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-2 border-b border-border`,children:[(0,G.jsxs)(`span`,{className:`text-sm font-semibold flex items-center gap-2`,children:[(0,G.jsx)(d,{className:`size-4`}),` Rotation & Retry`]}),(0,G.jsx)(`button`,{onClick:()=>t(!1),className:`flex items-center justify-center size-7 rounded-md hover:bg-surface-elevated transition-colors`,children:(0,G.jsx)(r,{className:`size-4`})})]}),(0,G.jsx)(`div`,{className:`px-4 py-4 pb-8`,children:(0,G.jsx)(X,{})})]})]}):null}var Le=v(`inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2`,{variants:{variant:{default:`border-transparent bg-primary text-primary-foreground shadow`,secondary:`border-transparent bg-secondary text-secondary-foreground`,destructive:`border-transparent bg-destructive text-destructive-foreground shadow`,outline:`text-foreground`}},defaultVariants:{variant:`default`}});function Z({className:e,variant:t,...n}){return(0,G.jsx)(`div`,{className:g(Le({variant:t}),e),...n})}function Re(e){let t=Math.floor(Date.now()/1e3);return e>t?`${Math.floor((e-t)/60)}m`:`exp`}function Q({accounts:e}){let[t,n]=(0,W.useState)([]),[r,i]=(0,W.useState)(!1),[a,o]=(0,W.useState)(!1),[s,c]=(0,W.useState)(new Map),l=e.filter(e=>e.hasRefreshToken);async function u(){if(l.length!==0){i(!0);try{let e=await ue(l.map(e=>e.id),a);n(t=>[...t,{round:t.length+1,time:new Date().toLocaleTimeString(),includeRefresh:a,items:e}])}catch{}i(!1)}}async function d(e,t){c(t=>new Map(t).set(e,{loading:!0}));try{let n=await de(t);c(t=>new Map(t).set(e,{loading:!1,...n}))}catch(t){c(n=>new Map(n).set(e,{loading:!1,status:`error`,error:t.message}))}}function f(e,t){return[{key:`r${e.round}-pre-${t.id}`,label:`Pre-export`,token:t.preExportTokenFull,preview:t.preExportToken,expires:t.preExportExpires},{key:`r${e.round}-exp-${t.id}`,label:`Exported`,token:t.exportedTokenFull,preview:t.exportedToken,expires:t.exportedExpires},{key:`r${e.round}-post-${t.id}`,label:`Post-export`,token:t.postExportTokenFull,preview:t.postExportToken,expires:t.postExportExpires}]}function p(){for(let e of t)for(let t of e.items)for(let n of f(e,t))n.token&&d(n.key,n.token)}return(0,G.jsxs)(`section`,{className:`border-t pt-4 space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,G.jsx)(`p`,{className:`text-xs font-medium`,children:`Simulate export`}),t.length>0&&(0,G.jsxs)(`span`,{className:`text-[10px] text-muted-foreground`,children:[t.length,` round(s)`]})]}),(0,G.jsx)(`p`,{className:`text-[11px] text-muted-foreground`,children:`Every run appends a round. Earlier rounds are kept so tokens can be compared across runs.`}),l.length===0?(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No OAuth account with a refresh token to export.`}):(0,G.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,G.jsx)(O,{id:`sim-include-refresh`,checked:a,onCheckedChange:o,className:`cursor-pointer`}),(0,G.jsx)(A,{htmlFor:`sim-include-refresh`,className:`text-[11px] cursor-pointer`,children:`Include refresh tokens`})]}),(0,G.jsx)(y,{size:`sm`,className:`h-7 text-xs cursor-pointer`,disabled:r,onClick:()=>void u(),children:r?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(m,{className:`size-3 animate-spin mr-1`}),` Exporting...`]}):`Run export #${t.length+1}`})]}),t.length>0&&(0,G.jsxs)(`div`,{className:`space-y-3`,children:[(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`w-full h-7 text-[11px] cursor-pointer`,onClick:p,children:[`Test all tokens (`,t.reduce((e,t)=>e+t.items.length*3,0),`)`]}),t.map(e=>(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsxs)(`p`,{className:`text-xs font-medium text-primary`,children:[`Round #`,e.round]}),(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:e.time}),(0,G.jsx)(Z,{variant:e.includeRefresh?`destructive`:`secondary`,className:`text-[9px] px-1 py-0`,children:e.includeRefresh?`with refresh`:`access only`})]}),e.items.map(t=>(0,G.jsxs)(`div`,{className:`p-2 rounded-lg border bg-card space-y-1.5`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`span`,{className:`text-[11px] font-medium`,children:t.label??t.email??t.id.slice(0,8)}),t.tokenChanged&&(0,G.jsx)(Z,{variant:`secondary`,className:`text-[9px] px-1 py-0`,children:`DB token changed`})]}),f(e,t).map(e=>{let t=s.get(e.key);return(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[11px]`,children:[(0,G.jsx)(`span`,{className:`w-20 shrink-0 text-muted-foreground text-[10px]`,children:e.label}),(0,G.jsx)(`code`,{className:`flex-1 truncate font-mono text-[10px] bg-muted px-1 rounded`,children:e.preview??`N/A`}),e.expires&&(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground shrink-0`,children:Re(e.expires)}),e.token?(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`h-6 text-[10px] px-1.5 cursor-pointer shrink-0`,disabled:t?.loading,onClick:()=>void d(e.key,e.token),children:t?.loading?(0,G.jsx)(m,{className:`size-3 animate-spin`}):`Test`}):(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:`-`}),t&&!t.loading&&(0,G.jsx)(`span`,{className:`text-[10px] font-medium shrink-0 ${t.status?.startsWith(`valid`)?`text-success`:`text-error`}`,children:t.status})]},e.key)})]},`r${e.round}-${t.id}`))]},e.round))]})]})}function ze(e){let t=Math.floor(Date.now()/1e3),n=Math.floor(Math.abs(e-t)/60);return e>t?`${n}m left`:`expired ${n}m ago`}function Be({open:e,onOpenChange:t,accounts:n}){let[r,i]=(0,W.useState)(new Map),[a,s]=(0,W.useState)(!1);async function c(e){i(t=>new Map(t).set(e,{loading:!0}));try{let t=await re(e,a);i(n=>new Map(n).set(e,{loading:!1,result:t}))}catch(t){i(n=>new Map(n).set(e,{loading:!1,error:t.message}))}}function l(){for(let e of n.filter(e=>e.expiresAt!==null))c(e.id)}return(0,G.jsx)(T,{open:e,onOpenChange:t,children:(0,G.jsxs)(S,{className:`sm:max-w-xl max-h-[85vh] flex flex-col`,children:[(0,G.jsxs)(b,{children:[(0,G.jsxs)(C,{className:`text-sm flex items-center gap-1.5`,children:[(0,G.jsx)(o,{className:`size-4`}),` Token Test`]}),(0,G.jsx)(w,{className:`text-xs`,children:`Probe stored tokens for validity. Nothing is modified.`})]}),(0,G.jsxs)(`div`,{className:`space-y-4 overflow-y-auto flex-1 pr-1`,children:[(0,G.jsxs)(`section`,{className:`space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,G.jsx)(`p`,{className:`text-xs font-medium`,children:`Current tokens`}),(0,G.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,G.jsx)(O,{id:`token-test-refresh`,checked:a,onCheckedChange:s,className:`cursor-pointer`}),(0,G.jsx)(A,{htmlFor:`token-test-refresh`,className:`text-[11px] cursor-pointer`,children:`Also test refresh`})]}),(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`h-7 text-xs cursor-pointer`,onClick:l,children:`Test all`})]})]}),n.length===0&&(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`No accounts to test.`}),(0,G.jsx)(`div`,{className:`space-y-1.5`,children:n.map(e=>{let t=r.get(e.id),n=t?.result?.accessToken.status;return(0,G.jsxs)(`div`,{className:`p-2 rounded border bg-card space-y-1`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,G.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,G.jsx)(`span`,{className:`text-xs font-medium truncate block`,children:e.label??e.email??e.id.slice(0,8)}),e.expiresAt&&(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:ze(e.expiresAt)})]}),(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`h-7 text-xs cursor-pointer shrink-0`,disabled:t?.loading,onClick:()=>void c(e.id),children:t?.loading?(0,G.jsx)(m,{className:`size-3 animate-spin`}):`Test`})]}),t&&!t.loading&&(0,G.jsxs)(`div`,{className:`text-[11px] pl-2 border-l-2 border-muted`,children:[t.error&&(0,G.jsx)(`p`,{className:`text-error`,children:t.error}),n&&(0,G.jsxs)(`span`,{className:n.startsWith(`valid`)?`text-success`:`text-error`,children:[n,t.result?.accessToken.code?` (${t.result.accessToken.code})`:``]})]})]},e.id)})})]}),(0,G.jsx)(Q,{accounts:n})]}),(0,G.jsx)(x,{children:(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs cursor-pointer`,onClick:()=>t(!1),children:`Close`})})]})})}function Ve(){let{usages:e,accounts:t,activeAccountId:n,initialLoading:r,refreshing:a,flashIds:s,reload:u}=_e(),[f,h]=(0,W.useState)(null),[g,_]=(0,W.useState)(null),[v,b]=(0,W.useState)(null),[x,S]=(0,W.useState)(null),[C,w]=(0,W.useState)(null),[T,E]=(0,W.useState)(null),[D,O]=(0,W.useState)(void 0);function k(e){u(),e&&h(e)}async function A(e,t){_(e);try{await ae(e,{status:t===`disabled`?`active`:`disabled`})}catch(e){h(e.message)}_(null),u()}async function j(){if(v){try{await le(v.id),h(`Account "${v.display}" removed.`),u()}catch(e){h(`Failed to remove: ${e.message}`)}b(null)}}let M=new Map(t.map(e=>[e.id,e])),N=e[0]?.usage.lastFetchedAt;return(0,G.jsxs)(`div`,{className:`space-y-4`,children:[(0,G.jsx)(z,{description:`Connect multiple Claude accounts. PPM rotates between them automatically to avoid rate limits.`,onRefresh:()=>void u(),refreshing:a,disabled:r,actions:(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(y,{size:`sm`,className:`cursor-pointer gap-1.5`,onClick:()=>{O(void 0),E(`add`)},children:[(0,G.jsx)(c,{className:`size-4`}),` Add account`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>{w(null),E(`export`)},children:[(0,G.jsx)(p,{className:`size-4`}),` Export`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>E(`import`),children:[(0,G.jsx)(i,{className:`size-4`}),` Import`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>E(`rotation`),children:[(0,G.jsx)(d,{className:`size-4`}),` Rotation`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>E(`token-test`),children:[(0,G.jsx)(o,{className:`size-4`}),` Token test`]})]})}),(0,G.jsx)(R,{message:f,onDismiss:()=>h(null)}),(0,G.jsxs)(`section`,{className:`space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium`,children:`Accounts`}),N&&(0,G.jsxs)(`span`,{className:`text-[10px] text-muted-foreground`,children:[`usage `,me(new Date(N).getTime())]})]}),r?(0,G.jsxs)(`div`,{className:`flex items-center gap-2 py-6 text-xs text-muted-foreground`,children:[(0,G.jsx)(m,{className:`size-4 animate-spin`}),` Loading accounts...`]}):e.length===0?(0,G.jsxs)(`div`,{className:`flex flex-col items-center gap-2 py-8 text-center`,children:[(0,G.jsx)(l,{className:`size-5 text-muted-foreground`}),(0,G.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`No accounts connected yet.`}),(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Add one to start using PPM.`})]}):(0,G.jsx)(B,{children:e.map(e=>(0,G.jsx)(Ce,{layout:`strip`,entry:e,isActive:e.accountId===n,accountInfo:M.get(e.accountId),onToggle:A,toggling:g===e.accountId,onDelete:(e,t)=>b({id:e,display:t}),onExport:e=>{w(e),E(`export`)},onViewProfile:(e,t)=>S({profile:e,accountId:t}),onReauth:()=>{O(e.accountLabel??e.accountId.slice(0,8)),E(`add`)},flash:s.has(e.accountId)},e.accountId))})]}),x&&(0,G.jsx)(ke,{profile:x.profile,accountId:x.accountId,onClose:()=>S(null)}),v&&(0,G.jsx)(Ae,{display:v.display,onConfirm:()=>void j(),onCancel:()=>b(null)}),(0,G.jsx)(he,{open:T===`add`,onOpenChange:e=>{E(e?`add`:null),e||O(void 0)},onSuccess:k,signInAgainFor:D}),(0,G.jsx)(Me,{open:T===`export`,onOpenChange:e=>{E(e?`export`:null),e||w(null)},accounts:t,preselectId:C,onMessage:h}),(0,G.jsx)(Ne,{open:T===`import`,onOpenChange:e=>E(e?`import`:null),onSuccess:k}),(0,G.jsx)(Ie,{open:T===`rotation`,onOpenChange:e=>E(e?`rotation`:null)}),(0,G.jsx)(Be,{open:T===`token-test`,onOpenChange:e=>E(e?`token-test`:null),accounts:t})]})}function He({mode:e,onOpenChange:t,password:n,onPasswordChange:r,busy:a,onExport:o,onImport:s,error:c}){let l=(0,W.useRef)(null),d=e===`export`;return(0,G.jsx)(T,{open:e!==null,onOpenChange:t,children:(0,G.jsxs)(S,{className:`sm:max-w-md`,children:[(0,G.jsxs)(b,{children:[(0,G.jsxs)(C,{className:`text-sm flex items-center gap-1.5`,children:[(0,G.jsx)(u,{className:`size-4`}),` `,d?`Export Codex Accounts`:`Import Codex Accounts`]}),(0,G.jsx)(w,{className:`text-xs leading-relaxed`,children:d?`Writes a password-encrypted file containing each account's login.`:`Reads a backup file. The password must be the one it was exported with.`})]}),(0,G.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,G.jsx)(A,{htmlFor:`codex-backup-password`,className:`text-xs`,children:`Password`}),(0,G.jsx)(D,{id:`codex-backup-password`,type:`password`,placeholder:d?`Choose a password`:`Password used for the export`,value:n,onChange:e=>r(e.target.value),className:`text-xs`,autoComplete:d?`new-password`:`current-password`}),(0,G.jsx)(`p`,{className:`text-[10px] text-muted-foreground`,children:`A backup holds full logins — keep the file and its password together.`})]}),c&&(0,G.jsx)(`div`,{className:`text-[11px] p-2 rounded bg-error/10 text-error`,children:c}),(0,G.jsx)(`input`,{ref:l,type:`file`,accept:`application/json,.json`,className:`hidden`,onChange:e=>{let t=e.target.files?.[0];e.target.value=``,t&&s(t)}}),(0,G.jsxs)(x,{children:[(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs cursor-pointer`,onClick:()=>t(!1),children:`Cancel`}),(0,G.jsxs)(y,{size:`sm`,className:`text-xs cursor-pointer gap-1.5`,disabled:!n.trim()||a,onClick:()=>d?o():l.current?.click(),children:[a?(0,G.jsx)(m,{className:`size-3.5 animate-spin`}):d?(0,G.jsx)(p,{className:`size-3.5`}):(0,G.jsx)(i,{className:`size-3.5`}),d?`Download backup`:`Choose file`]})]})]})})}var Ue=[{value:`round-robin`,label:`Round-robin`,hint:`Take the next account each time.`},{value:`fill-first`,label:`Fill-first`,hint:`Stay on one account until it runs out.`},{value:`lowest-usage`,label:`Lowest usage`,hint:`Pick whichever has the most left.`}];function We({open:e,onOpenChange:t,strategy:n,onChange:r}){return(0,G.jsx)(T,{open:e,onOpenChange:t,children:(0,G.jsxs)(S,{className:`sm:max-w-md`,children:[(0,G.jsxs)(b,{children:[(0,G.jsx)(C,{className:`text-sm`,children:`Codex Rotation`}),(0,G.jsx)(w,{className:`text-xs leading-relaxed`,children:`How a new chat chooses among your Codex accounts.`})]}),(0,G.jsx)(`div`,{className:`space-y-2`,children:Ue.map(e=>(0,G.jsxs)(`button`,{type:`button`,onClick:()=>r(e.value),"aria-current":n===e.value?`true`:void 0,className:g(`w-full text-left rounded-md border px-3 py-2.5 min-h-11 cursor-pointer transition-colors`,n===e.value?`border-primary bg-primary/10`:`border-border hover:bg-accent/50 active:bg-accent`),children:[(0,G.jsx)(`p`,{className:`text-sm font-medium`,children:e.label}),(0,G.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e.hint})]},e.value))}),(0,G.jsx)(x,{children:(0,G.jsx)(y,{size:`sm`,variant:`outline`,className:`text-xs cursor-pointer`,onClick:()=>t(!1),children:`Done`})})]})})}function $(e){return e==null?null:Math.round(e*100)}function Ge({usage:e}){let t=e.session==null&&e.weekly==null;return(0,G.jsxs)(`div`,{className:`space-y-2`,children:[(t||e.session!=null)&&(0,G.jsx)(U,{label:`5-Hour Session`,pct:$(e.fiveHour),reset:H(e.session),resetsAt:e.session?.resetsAt}),(t||e.weekly!=null)&&(0,G.jsx)(U,{label:`Weekly`,pct:$(e.sevenDay),reset:H(e.weekly),resetsAt:e.weekly?.resetsAt})]})}function Ke(){let[e,t]=(0,W.useState)(null),n=pe(()=>t(null)),[r,o]=(0,W.useState)(null);return(0,G.jsxs)(`div`,{className:`space-y-4`,children:[(0,G.jsx)(z,{description:(0,G.jsxs)(G.Fragment,{children:[`Each Codex account keeps its own login (`,(0,G.jsx)(`code`,{children:`CODEX_HOME`}),`). One is picked per chat by the rotation setting.`]}),onRefresh:()=>void n.load(),refreshing:n.loading,actions:(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(y,{size:`sm`,className:`cursor-pointer gap-1.5`,onClick:()=>t(`add`),children:[(0,G.jsx)(c,{className:`size-4`}),` Add account`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>t(`export`),children:[(0,G.jsx)(p,{className:`size-4`}),` Export`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>t(`import`),children:[(0,G.jsx)(i,{className:`size-4`}),` Import`]}),(0,G.jsxs)(y,{size:`sm`,variant:`outline`,className:`cursor-pointer gap-1.5`,onClick:()=>t(`rotation`),children:[(0,G.jsx)(d,{className:`size-4`}),` Rotation`]})]})}),(0,G.jsx)(R,{message:n.msg??n.err,onDismiss:()=>{n.setMsg(null),n.setErr(null)}}),(0,G.jsxs)(`section`,{className:`space-y-2`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium`,children:`Codex Accounts`}),(0,G.jsx)(`span`,{className:`text-[10px] text-muted-foreground capitalize`,children:n.strategy.replace(`-`,` `)})]}),n.loading&&n.accounts.length===0?(0,G.jsxs)(`div`,{className:`flex items-center gap-2 py-6 text-xs text-muted-foreground`,children:[(0,G.jsx)(m,{className:`size-4 animate-spin`}),` Loading accounts...`]}):n.accounts.length===0?(0,G.jsxs)(`div`,{className:`flex flex-col items-center gap-2 py-8 text-center`,children:[(0,G.jsx)(l,{className:`size-5 text-muted-foreground`}),(0,G.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`No Codex accounts yet.`}),(0,G.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Chats use your default `,(0,G.jsx)(`code`,{children:`~/.codex`}),` login until you add one.`]})]}):(0,G.jsx)(B,{children:n.accounts.map(e=>{let t=n.usages[e.id]??{};return(0,G.jsxs)(ve,{dense:!0,className:`min-w-[300px] shrink-0 snap-start${e.signedOut?` opacity-60`:``}`,"data-testid":`account-card`,"data-account-id":e.id,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,G.jsx)(`span`,{className:`text-sm font-medium truncate flex-1 min-w-0`,children:e.label}),e.signedOut&&(0,G.jsx)(fe,{className:`text-[10px] text-error shrink-0 font-medium`,hint:`Codex rejected this account's login (revoked or expired), so no turn can run on it and it is skipped. The usage shown is the last reading. Click to sign in again — the account keeps its settings and chats.`,onClick:e.type===`chatgpt`?()=>o(e):void 0,children:`Sign in again`}),(0,G.jsx)(`span`,{className:`text-[10px] uppercase tracking-wide text-text-subtle border border-border rounded px-1 shrink-0`,children:e.type}),V(e.planType)&&(0,G.jsx)(`span`,{className:`text-[10px] text-text-subtle shrink-0`,children:V(e.planType)}),(0,G.jsx)(O,{checked:e.status!==`disabled`,onCheckedChange:()=>void n.toggle(e.id,e.status??`active`),disabled:n.toggling.has(e.id),"aria-label":e.status===`disabled`?`Enable account`:`Disable account`,className:`cursor-pointer shrink-0`}),(0,G.jsxs)(P,{children:[(0,G.jsx)(I,{asChild:!0,children:(0,G.jsx)(`button`,{type:`button`,onClick:()=>void n.remove(e.id),"aria-label":`Remove account`,className:`p-2 rounded cursor-pointer text-text-subtle hover:text-error hover:bg-surface-elevated transition-colors shrink-0`,children:(0,G.jsx)(a,{className:`size-4`})})}),(0,G.jsx)(F,{side:`top`,children:`Remove account`})]})]}),(0,G.jsx)(Ge,{usage:t}),t.resetCredits&&(0,G.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap text-[10px] text-text-subtle`,children:[(0,G.jsx)(ge,{credits:t.resetCredits}),(0,G.jsx)(Se,{account:e,usage:t,onDone:e=>{n.setMsg(e),n.load()}})]}),t.session==null&&(()=>{let r=be(t.weekly);return r?(0,G.jsxs)(`div`,{className:`flex min-h-12 items-center justify-between gap-3 rounded-md border px-2.5 py-1.5 ${e.dailyGuardEnabled&&r.blocked?`border-error/40 bg-error/5`:`border-border/50 bg-surface/40`}`,children:[(0,G.jsxs)(`div`,{className:`min-w-0 space-y-0.5`,children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs font-medium ${e.dailyGuardEnabled&&r.blocked?`text-error`:`text-text-secondary`}`,children:[(0,G.jsx)(`span`,{children:`Daily guard`}),(0,G.jsxs)(P,{children:[(0,G.jsx)(I,{asChild:!0,children:(0,G.jsx)(`button`,{type:`button`,"aria-label":`About Daily guard`,className:`text-text-subtle hover:text-text-primary cursor-help`,children:(0,G.jsx)(s,{className:`size-3.5`})})}),(0,G.jsx)(F,{side:`top`,className:`max-w-64 text-xs leading-relaxed`,children:`Spreads the weekly quota across five weekdays, adding 20% per weekday. Weekend slots keep the previous cap; unused allowance carries forward. Daily slots start at the reset time and use UTC weekdays. Turn it off any time to use the remaining quota freely.`})]})]}),(0,G.jsx)(`p`,{className:`text-[10px] tabular-nums ${e.dailyGuardEnabled&&r.blocked?`text-error`:`text-text-subtle`}`,children:e.dailyGuardEnabled&&r.blocked?`${Math.round(r.used*100)}% used / ${Math.round(r.cap*100)}% daily cap. New turns paused.`:`Weekday ${r.day}/5, ${Math.round(r.cap*100)}% daily cap`})]}),(0,G.jsxs)(`span`,{className:`hidden`,title:`Weekday ${r.day}/5: hold weekly usage at or below ${Math.round(r.cap*100)}% to last until reset.`,children:[`Daily guard `,e.dailyGuardEnabled?`· Weekday ${r.day}/5 cap ${Math.round(r.cap*100)}%`:``]}),(0,G.jsx)(O,{checked:!!e.dailyGuardEnabled,onCheckedChange:()=>void n.toggleDailyGuard(e.id,!!e.dailyGuardEnabled),disabled:n.toggling.has(e.id),"aria-label":e.dailyGuardEnabled?`Disable Daily guard`:`Enable Daily guard`,className:`cursor-pointer shrink-0`})]}):null})()]},e.id)})})]}),(0,G.jsx)(xe,{open:e===`add`,onOpenChange:e=>{e||n.cancelLogin(),t(e?`add`:null)},label:n.label,onLabelChange:n.setLabel,apiKey:n.apiKey,onApiKeyChange:n.setApiKey,adding:n.adding,onAddApiKey:()=>void n.addApiKey(),deviceWaiting:n.deviceWaiting,onStartDevice:()=>void n.startDevice(),device:n.device,browser:n.browser,onStartBrowser:()=>void n.startBrowser(),loginStarting:n.loginStarting,callbackUrl:n.callbackUrl,onCallbackUrlChange:n.setCallbackUrl,submittingCallback:n.submittingCallback,onSubmitCallback:()=>void n.submitCallback(),error:n.err}),(0,G.jsx)(He,{mode:e===`export`?`export`:e===`import`?`import`:null,onOpenChange:e=>{e||t(null)},password:n.backupPassword,onPasswordChange:n.setBackupPassword,busy:n.exporting||n.importing,onExport:()=>void n.doExport(),onImport:e=>void n.doImport(e),error:n.err}),r&&(0,G.jsx)(ye,{account:r,onClose:()=>o(null),onDone:()=>void n.load()}),(0,G.jsx)(We,{open:e===`rotation`,onOpenChange:e=>t(e?`rotation`:null),strategy:n.strategy,onChange:e=>void n.changeStrategy(e)})]})}var qe=[{id:`claude`,label:`Claude`},{id:`codex`,label:`Codex`}];function Je(){let[e,t]=(0,W.useState)(null),[n,r]=(0,W.useState)(`claude`);(0,W.useEffect)(()=>{let e=!1;return ie().then(n=>{e||t(new Set(Object.keys(n.providers??{})))}).catch(()=>{e||t(new Set([`claude`]))}),()=>{e=!0}},[]);let i=qe.filter(t=>t.id===`claude`||e?.has(t.id)),a=i.length>1;return(0,G.jsxs)(`div`,{className:`space-y-4`,"data-testid":`accounts-pane`,"data-provider":n,children:[a&&(0,G.jsx)(`div`,{className:`flex gap-1 border-b border-border/50`,children:i.map(e=>(0,G.jsxs)(`button`,{onClick:()=>r(e.id),"data-testid":`accounts-tab-${e.id}`,"aria-current":n===e.id?`page`:void 0,className:`flex items-center gap-1.5 px-3 py-2 text-xs rounded-t transition-colors cursor-pointer ${n===e.id?`text-primary border-b-2 border-primary font-medium`:`text-text-subtle hover:text-text-secondary`}`,children:[(0,G.jsx)(j,{providerId:e.id}),e.label]},e.id))}),e===null&&!a&&(0,G.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[(0,G.jsx)(m,{className:`size-3 animate-spin`}),` Checking configured providers...`]}),n===`claude`?(0,G.jsx)(Ve,{}):(0,G.jsx)(Ke,{})]})}export{Je as AccountsSettingsSection};
@@ -1 +0,0 @@
1
- import"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import"./icons-CO_II6D-.js";import"./api-client-F5Zi1sR0.js";import"./settings-store-3jIBB8gx.js";import"./portal-container-context-NFSuymMu.js";import"./panel-store-DrSH3Nhp.js";import"./window-store-B4cbZ5rr.js";import"./project-store-CCimwgGF.js";import"./tab-store-CUPgQIQz.js";import"./chat-preparation-cache-DoS7sdal.js";import"./use-is-mobile-CkO33jqU.js";import"./button-CsmGH5xa.js";import"./dialog-z8PLkL8n.js";import"./mobile-bottom-sheet-CLic9ovp.js";import"./use-visual-viewport-C307OVeV.js";import"./input-CP31LZnN.js";import"./api-settings-BeINN5Dy.js";import{t as e}from"./ai-settings-section-Ezhw4Fef.js";export{e as AISettingsSection};
@@ -1 +0,0 @@
1
- import{s as e}from"./rolldown-runtime-C5c2KzVm.js";import{C as t,S as n}from"./vendor-markdown-QKPNiWEd.js";import"./vendor-ui-P9Ym7hCv.js";import{O as r,ir as i,j as a,on as o,u as s,un as c,vt as l,w as u}from"./icons-CO_II6D-.js";import{r as d}from"./api-client-F5Zi1sR0.js";import"./settings-store-3jIBB8gx.js";import"./portal-container-context-NFSuymMu.js";import"./project-store-CCimwgGF.js";import{n as f}from"./use-is-mobile-CkO33jqU.js";import"./git-repo-store-CdoOpvmf.js";import{t as p}from"./button-CsmGH5xa.js";import{t as m}from"./file-icons-Ed_yLyef.js";import{t as h}from"./mobile-bottom-sheet-CLic9ovp.js";import"./use-visual-viewport-C307OVeV.js";import{t as g}from"./scroll-area-Dp-P38kg.js";import{At as ee,Dt as te,Et as ne,Mt as _,Ot as re,in as ie,jt as v,kt as ae}from"./index-DQCw6d-2.js";import"./use-monaco-theme-DL2dIG5L.js";import"./use-inline-blame-Dv111BKY.js";import{DiffViewer as y}from"./diff-viewer-Dcxk6UTG.js";var b=e(t(),1),x=`ppm:branch-review`,S=`${x}:recent`,C=20;function w(e,t,n){return`${x}:${e}:${t}:${n}`}function T(e,t){return e[t.path]===t.blob}function E(e,t){let n={...e};return T(e,t)?delete n[t.path]:n[t.path]=t.blob,n}function oe(e,t,n){if(!n)return{};let r={...e};for(let e of t)r[e.path]=e.blob;return r}function se(e,t){return t.reduce((t,n)=>t+(T(e,n)?1:0),0)}function D(e,t){let n=new Set(t.map(e=>e.path)),r={};for(let[t,i]of Object.entries(e))n.has(t)&&(r[t]=i);return r}function ce(e){return e.find(e=>!e.binary)??e[0]??null}function le(e,t,n){if(t.length===0)return null;let r=n?t.findIndex(e=>e.path===n)+1:0;for(let n=0;n<t.length;n++){let i=t[(r+n)%t.length];if(i&&!T(e,i))return i}return null}function ue(e){try{let t=localStorage.getItem(e);if(!t)return{};let n=JSON.parse(t);if(!n||typeof n!=`object`||Array.isArray(n))return{};let r={};for(let[e,t]of Object.entries(n))typeof t==`string`&&(r[e]=t);return r}catch{return{}}}function O(e,t,n=C){let r=[t,...e.filter(e=>e!==t)];return{recent:r.slice(0,n),evicted:r.slice(n)}}function k(){try{let e=JSON.parse(localStorage.getItem(S)??`[]`);return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}catch{return[]}}function A(e,t){try{if(Object.keys(t).length===0){localStorage.removeItem(e);let t=k().filter(t=>t!==e);localStorage.setItem(S,JSON.stringify(t));return}localStorage.setItem(e,JSON.stringify(t));let{recent:n,evicted:r}=O(k(),e);for(let e of r)localStorage.removeItem(e);localStorage.setItem(S,JSON.stringify(n))}catch{}}var j=n(),M={M:`text-warning`,A:`text-success`,D:`text-error`,R:`text-primary`,C:`text-accent-2`,T:`text-text-3`};function N(e){let{node:t,depth:n,byPath:i,reviewed:o,selectedPath:s,collapsed:c,onToggleCollapse:l,onSelect:d,onToggleReviewed:f}=e,p=t.file?i.get(t.fullPath):void 0;if(!p){let i=c.has(t.fullPath);return(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(`button`,{type:`button`,"data-testid":`branch-review-folder`,className:`w-full flex items-center gap-1 px-2 py-1 text-xs min-h-11 md:min-h-0 hover:bg-surface-hover text-left`,style:{paddingLeft:n*14+8},onClick:()=>l(t.fullPath),children:[i?(0,j.jsx)(a,{className:`size-3 shrink-0`}):(0,j.jsx)(r,{className:`size-3 shrink-0`}),(0,j.jsx)(`span`,{className:`truncate text-text-2`,children:t.name})]}),!i&&t.children.map(t=>(0,j.jsx)(N,{...e,node:t,depth:n+1},t.fullPath))]})}let h=T(o,p),g=s===p.path;return(0,j.jsxs)(`div`,{className:`flex items-center gap-1.5 pr-2 py-1 text-xs cursor-pointer border-l-2 min-h-11 md:min-h-0 hover:bg-surface-hover ${g?`bg-primary/10 border-primary`:`border-transparent`}`,style:{paddingLeft:n*14+6},onClick:()=>d(p.path),"aria-current":g?`true`:void 0,"data-testid":`branch-review-file`,"data-path":p.path,"data-selected":g?`true`:`false`,"data-reviewed":h?`true`:`false`,children:[(0,j.jsx)(`button`,{type:`button`,"aria-label":h?`Mark ${p.path} unreviewed`:`Mark ${p.path} reviewed`,"data-testid":`branch-review-check`,className:`size-11 md:size-4 shrink-0 flex items-center justify-center`,onClick:e=>{e.stopPropagation(),f(p)},children:(0,j.jsx)(`span`,{"data-testid":`branch-review-check-box`,className:`size-4 rounded border flex items-center justify-center ${h?`bg-primary border-primary text-primary-foreground`:`border-border`}`,children:h&&(0,j.jsx)(u,{className:`size-3`})})}),(0,j.jsx)(m,{name:t.name,className:`size-3.5 shrink-0`}),(0,j.jsx)(_,{children:t.name}),(0,j.jsx)(`span`,{className:`shrink-0 font-mono ${M[p.status]}`,children:p.status}),p.binary?(0,j.jsx)(`span`,{className:`shrink-0 text-text-3 italic`,children:`bin`}):(0,j.jsxs)(`span`,{className:`shrink-0 tabular-nums text-[10px]`,children:[(0,j.jsxs)(`span`,{className:`text-success`,children:[`+`,p.additions]}),` `,(0,j.jsxs)(`span`,{className:`text-error`,children:[`-`,p.deletions]})]})]})}function P(e,t){let n=e.filter(e=>!e.remote&&e.name!==t);return n.find(e=>e.name===`main`)?.name??n.find(e=>e.name===`master`)?.name??n[0]?.name??``}function F({metadata:e}){let t=e?.projectName,n=ie(t),r=f(),[a,u]=(0,b.useState)([]),[m,x]=(0,b.useState)(``),[S,C]=(0,b.useState)(``),[T,O]=(0,b.useState)(null),[k,M]=(0,b.useState)(null),[F,I]=(0,b.useState)({}),[de,L]=(0,b.useState)(new Set),[R,z]=(0,b.useState)(!1),[B,V]=(0,b.useState)(null),[fe,H]=(0,b.useState)(!1);(0,b.useEffect)(()=>{if(!t||!n.repo)return;let e=!1;return d.get(n.gitUrl(`/branches`)).then(t=>{if(e)return;u(t);let n=t.find(e=>e.current)?.name;C(e=>e||n||``),x(e=>e||P(t,n))}).catch(t=>!e&&V(t instanceof Error?t.message:`Could not list branches`)),()=>{e=!0}},[t,n]);let U=(0,b.useRef)(null),W=(0,b.useCallback)(async()=>{if(!t||!n.repo||!m||!S)return;U.current?.abort();let e=new AbortController;U.current=e,z(!0),V(null);try{let t=new URLSearchParams({base:m,head:S}),r=await d.get(n.gitUrl(`/branch-diff?${t}`),{signal:e.signal});if(e.signal.aborted)return;O(r),M(e=>e&&r.files.some(t=>t.path===e)?e:ce(r.files)?.path??null)}catch(t){if(e.signal.aborted)return;O(null),V(t instanceof Error?t.message:`Could not compare these branches`)}finally{e.signal.aborted||z(!1)}},[t,n,m,S]);(0,b.useEffect)(()=>(W(),()=>U.current?.abort()),[W]);let G=t&&m&&S?w(t,m,S):null;(0,b.useEffect)(()=>{L(new Set)},[G]),(0,b.useEffect)(()=>{I(G?ue(G):{})},[G]);let K=T&&T.base===m&&T.head===S?T:null;(0,b.useEffect)(()=>{!G||!K||I(e=>{let t=D(e,K.files);return Object.keys(t).length!==Object.keys(e).length&&A(G,t),t})},[G,K]);let q=(0,b.useCallback)(e=>{I(e),G&&A(G,e)},[G]),J=K?.files??[],Y=(0,b.useMemo)(()=>new Map(J.map(e=>[e.path,e])),[J]),X=(0,b.useMemo)(()=>se(F,J),[F,J]),pe=(0,b.useMemo)(()=>te(ne(J.map(e=>({path:e.path,status:e.status===`T`?`M`:e.status})))),[J]),Z=k?Y.get(k)??null:null,Q=(0,b.useCallback)(()=>{let e=le(F,J,k);e&&(M(e.path),H(!1))},[F,J,k]);if(n.noRepo)return(0,j.jsx)(re,{onReload:n.reload});if(n.needsPick)return(0,j.jsx)(ee,{repos:n.repos,onChoose:n.choose});let $=(0,j.jsx)(g,{className:`h-full`,children:(0,j.jsxs)(`div`,{className:`py-1`,children:[J.length===0&&!R&&(0,j.jsx)(`div`,{className:`px-3 py-6 text-center text-xs text-text-3`,children:B?`—`:`These branches have identical trees.`}),pe.map(e=>(0,j.jsx)(N,{node:e,depth:0,byPath:Y,reviewed:F,selectedPath:k,collapsed:de,onToggleCollapse:e=>L(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n}),onSelect:e=>{M(e),H(!1)},onToggleReviewed:e=>q(E(F,e))},e.fullPath)),!!K?.omitted&&(0,j.jsxs)(`div`,{className:`px-3 py-3 text-center text-xs text-text-3`,children:[K.omitted.toLocaleString(),` more `,K.omitted===1?`file`:`files`,` not listed.`]})]})});return(0,j.jsxs)(`div`,{className:`flex flex-col h-full overflow-hidden bg-bg`,children:[n.isNested&&n.repo&&(0,j.jsx)(ae,{repo:n.repo,repos:n.repos,onChoose:n.choose}),(0,j.jsxs)(`div`,{className:`flex items-center gap-2 px-2 py-1.5 border-b border-border shrink-0 flex-wrap`,children:[(0,j.jsx)(v,{value:m,branches:a,onChange:x,label:`Base branch`,testId:`branch-review-base`,className:`max-w-[38%]`}),(0,j.jsx)(s,{className:`size-3.5 text-text-3 shrink-0`}),(0,j.jsx)(v,{value:S,branches:a,onChange:C,label:`Branch to review`,testId:`branch-review-head`,className:`max-w-[38%]`}),(0,j.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[(0,j.jsxs)(`span`,{className:`text-xs text-text-2 tabular-nums`,"data-testid":`branch-review-progress`,children:[X,`/`,J.length,` reviewed`]}),(0,j.jsx)(p,{variant:`ghost`,size:`icon-xs`,title:X===J.length&&J.length>0?`Clear all`:`Mark all reviewed`,disabled:J.length===0,onClick:()=>q(oe(F,J,X!==J.length)),children:(0,j.jsx)(o,{className:`size-3.5`})}),(0,j.jsx)(p,{variant:`ghost`,size:`icon-xs`,title:`Reload`,onClick:()=>void W(),children:(0,j.jsx)(i,{className:R?`animate-spin`:``})})]})]}),B&&(0,j.jsx)(`div`,{className:`px-3 py-1.5 text-xs text-destructive bg-destructive/10 shrink-0`,children:B}),(0,j.jsxs)(`div`,{className:`flex-1 flex min-h-0`,children:[!r&&(0,j.jsx)(`div`,{className:`w-72 shrink-0 border-r border-border flex flex-col min-h-0`,children:$}),(0,j.jsx)(`div`,{className:`flex-1 min-w-0 flex flex-col`,children:Z?(0,j.jsx)(y,{metadata:{filePath:n.projectFile(Z.path),projectName:t,ref1:K?.mergeBase,ref2:K?.headCommit}},`${Z.path}:${K?.mergeBase}:${K?.headCommit}`):(0,j.jsx)(`div`,{className:`flex-1 flex items-center justify-center text-xs text-text-3`,children:R?(0,j.jsx)(c,{className:`size-4 animate-spin`}):`Nothing to review.`})})]}),r&&(0,j.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border p-2 shrink-0`,children:[(0,j.jsxs)(p,{variant:`secondary`,size:`sm`,className:`flex-1 min-h-11`,onClick:()=>H(!0),children:[(0,j.jsx)(l,{className:`size-4`}),J.length,` files`]}),(0,j.jsx)(p,{variant:`secondary`,size:`sm`,className:`flex-1 min-h-11`,onClick:Q,children:`Next unreviewed`})]}),r&&(0,j.jsx)(h,{open:fe,onClose:()=>H(!1),children:(0,j.jsx)(`div`,{className:`max-h-[70vh] overflow-hidden flex flex-col`,children:$})}),!r&&Z&&(0,j.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border px-2 py-1 shrink-0`,children:[(0,j.jsx)(_,{children:Z.path}),(0,j.jsx)(p,{variant:`ghost`,size:`xs`,onClick:Q,children:`Next unreviewed`})]})]})}export{F as BranchReviewTab};