@rubytech/create-maxy-code 0.1.471 → 0.1.472

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 (183) hide show
  1. package/dist/__tests__/google-client-id-env.test.js +68 -0
  2. package/dist/index.js +26 -18
  3. package/dist/port-resolution.js +7 -1
  4. package/package.json +1 -1
  5. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js +41 -2
  6. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js.map +1 -1
  7. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts +17 -0
  8. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts.map +1 -1
  9. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js +32 -8
  10. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js.map +1 -1
  11. package/payload/server/public/activity.html +6 -4
  12. package/payload/server/public/assets/AdminLoginScreens-BfamGqS7.js +1 -0
  13. package/payload/server/public/assets/AdminShell-5nHOAzXO.js +2 -0
  14. package/payload/server/public/assets/Checkbox-CD6aHwac.js +1 -0
  15. package/payload/server/public/assets/activity-Dj2nJzPw.js +1 -0
  16. package/payload/server/public/assets/admin-Cpcw_YE-.js +1 -0
  17. package/payload/server/public/assets/{arc-CFMJyMm-.js → arc-BrHWN2Kr.js} +1 -1
  18. package/payload/server/public/assets/architecture-YZFGNWBL-CZQzGRSM.js +1 -0
  19. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-CmOpXLsH.js → architectureDiagram-Q4EWVU46-Clt9NOr0.js} +1 -1
  20. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CmS8f9YF.js → blockDiagram-DXYQGD6D-BOe_jmXi.js} +1 -1
  21. package/payload/server/public/assets/browser-0znOwk1W.js +1 -0
  22. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-BXIjMl6A.js → c4Diagram-AHTNJAMY-B64FaKMV.js} +1 -1
  23. package/payload/server/public/assets/calendar-CykigHdg.js +1 -0
  24. package/payload/server/public/assets/channel-zDUAN9Ks.js +1 -0
  25. package/payload/server/public/assets/chat-DIOJZ411.js +1 -0
  26. package/payload/server/public/assets/chevron-left-Cq7UvOI0.js +1 -0
  27. package/payload/server/public/assets/{chunk-2KRD3SAO-D4fktAwW.js → chunk-2KRD3SAO-BGAUfWvM.js} +1 -1
  28. package/payload/server/public/assets/{chunk-336JU56O-C2MKnRTj.js → chunk-336JU56O-PFi6uQZ0.js} +2 -2
  29. package/payload/server/public/assets/chunk-426QAEUC-iJnqNRug.js +1 -0
  30. package/payload/server/public/assets/{chunk-4BX2VUAB-C13Wz3zS.js → chunk-4BX2VUAB-CkxXXCiF.js} +1 -1
  31. package/payload/server/public/assets/{chunk-4TB4RGXK-CalYahTR.js → chunk-4TB4RGXK-B-7tN4IA.js} +1 -1
  32. package/payload/server/public/assets/{chunk-55IACEB6-TmOKdy8a.js → chunk-55IACEB6-CBkNmqrt.js} +1 -1
  33. package/payload/server/public/assets/{chunk-5FUZZQ4R-C-i0BVag.js → chunk-5FUZZQ4R-wa9ujn7i.js} +1 -1
  34. package/payload/server/public/assets/{chunk-5PVQY5BW-D6bJMLnf.js → chunk-5PVQY5BW-DIk-xBaE.js} +1 -1
  35. package/payload/server/public/assets/{chunk-67CJDMHE-Cif9Uu5C.js → chunk-67CJDMHE-BbMV1lgW.js} +1 -1
  36. package/payload/server/public/assets/{chunk-7N4EOEYR-WjTHCXnd.js → chunk-7N4EOEYR-C49Mv-nQ.js} +1 -1
  37. package/payload/server/public/assets/{chunk-AA7GKIK3-CwCfdQmb.js → chunk-AA7GKIK3-Dy_pJOp_.js} +1 -1
  38. package/payload/server/public/assets/{chunk-BSJP7CBP-9A67yXwT.js → chunk-BSJP7CBP-Ce-OmPqn.js} +1 -1
  39. package/payload/server/public/assets/{chunk-CIAEETIT-DPMiWSBi.js → chunk-CIAEETIT-tnjq-APC.js} +1 -1
  40. package/payload/server/public/assets/{chunk-EDXVE4YY-B9PBdwiT.js → chunk-EDXVE4YY-Bvv_deZ2.js} +1 -1
  41. package/payload/server/public/assets/{chunk-ENJZ2VHE-CM5OqcQ5.js → chunk-ENJZ2VHE-CmxCPKyU.js} +1 -1
  42. package/payload/server/public/assets/{chunk-FMBD7UC4-Bmt_ZRlV.js → chunk-FMBD7UC4-Top6y08S.js} +1 -1
  43. package/payload/server/public/assets/{chunk-FOC6F5B3-DfGJGxpX.js → chunk-FOC6F5B3-B9LPNCUS.js} +1 -1
  44. package/payload/server/public/assets/{chunk-ICPOFSXX-D6M89DA0.js → chunk-ICPOFSXX-Bi-_c351.js} +2 -2
  45. package/payload/server/public/assets/{chunk-K5T4RW27-DMpoaqw2.js → chunk-K5T4RW27-DAnRM04h.js} +1 -1
  46. package/payload/server/public/assets/{chunk-KGLVRYIC-DYUFgri2.js → chunk-KGLVRYIC-C0QYcbLe.js} +1 -1
  47. package/payload/server/public/assets/{chunk-LIHQZDEY-x3LmeKmx.js → chunk-LIHQZDEY-BjvA5ykt.js} +1 -1
  48. package/payload/server/public/assets/{chunk-ORNJ4GCN-BeuNAWkW.js → chunk-ORNJ4GCN-Cs46Gj7z.js} +1 -1
  49. package/payload/server/public/assets/{chunk-OYMX7WX6-Bv6gisQ6.js → chunk-OYMX7WX6-BBpimab5.js} +1 -1
  50. package/payload/server/public/assets/chunk-QZHKN3VN-Qlc2PFAj.js +1 -0
  51. package/payload/server/public/assets/{chunk-U2HBQHQK-C2iT9Av2.js → chunk-U2HBQHQK-CQUSBHoK.js} +1 -1
  52. package/payload/server/public/assets/{chunk-X2U36JSP-Bd6bv87A.js → chunk-X2U36JSP-Dm8TevG0.js} +1 -1
  53. package/payload/server/public/assets/{chunk-XPW4576I-ByFnN4JO.js → chunk-XPW4576I-B10QuxYb.js} +1 -1
  54. package/payload/server/public/assets/{chunk-YZCP3GAM-Bt8I6ZDb.js → chunk-YZCP3GAM-vaGsu4Wk.js} +1 -1
  55. package/payload/server/public/assets/{chunk-ZZ45TVLE-DBMPgZ_A.js → chunk-ZZ45TVLE-D1Qi22bL.js} +1 -1
  56. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CFsKL52p.js +1 -0
  57. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BWBUUCiO.js +1 -0
  58. package/payload/server/public/assets/clone-h5XhkDUL.js +1 -0
  59. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-DgLEaApT.js → cose-bilkent-S5V4N54A-CRDvLRXs.js} +1 -1
  60. package/payload/server/public/assets/{dagre-mSazqXgG.js → dagre-CEmqJTt3.js} +1 -1
  61. package/payload/server/public/assets/{dagre-KV5264BT-kWVPgmmL.js → dagre-KV5264BT-LXMTo7Fp.js} +1 -1
  62. package/payload/server/public/assets/data-lHgqlhmu.js +1 -0
  63. package/payload/server/public/assets/{diagram-5BDNPKRD-BHe_omJD.js → diagram-5BDNPKRD-zyis6nPt.js} +1 -1
  64. package/payload/server/public/assets/{diagram-G4DWMVQ6-fUFsmM3x.js → diagram-G4DWMVQ6-BiU0XAAD.js} +1 -1
  65. package/payload/server/public/assets/{diagram-MMDJMWI5-DmujPLlM.js → diagram-MMDJMWI5-rGFiz1SX.js} +1 -1
  66. package/payload/server/public/assets/{diagram-TYMM5635-B7Aoas89.js → diagram-TYMM5635-B0wak1ZJ.js} +1 -1
  67. package/payload/server/public/assets/{erDiagram-SMLLAGMA-6hS1rGiO.js → erDiagram-SMLLAGMA-D8AUxLyX.js} +1 -1
  68. package/payload/server/public/assets/{flatten-BXzaHgtL.js → flatten-naJ5PJ4f.js} +1 -1
  69. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-Bqhr_r5b.js → flowDiagram-DWJPFMVM-BtdUf68b.js} +1 -1
  70. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-B8kjyN4o.js → ganttDiagram-T4ZO3ILL-C-lkzDmf.js} +1 -1
  71. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CBZPQJLj.js +1 -0
  72. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF--TTRq4ir.js → gitGraphDiagram-UUTBAWPF-DRUKumq2.js} +1 -1
  73. package/payload/server/public/assets/{graph-C252ZHjp.js → graph-JV5_xF3V.js} +3 -3
  74. package/payload/server/public/assets/graph-labels-DPYORjBH.js +1 -0
  75. package/payload/server/public/assets/{graphlib-CWkjawc5.js → graphlib-zRsaoFEC.js} +1 -1
  76. package/payload/server/public/assets/info-OMHHGYJF-1vIoX-kP.js +1 -0
  77. package/payload/server/public/assets/infoDiagram-42DDH7IO-KHcXRaan.js +2 -0
  78. package/payload/server/public/assets/{isEmpty-uB1dEu_Z.js → isEmpty-Bnpg7b8f.js} +1 -1
  79. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CR8B7VzM.js → ishikawaDiagram-UXIWVN3A-BguMgoR8.js} +1 -1
  80. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-45lWAvtq.js → journeyDiagram-VCZTEJTY-CXhyK1n-.js} +1 -1
  81. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DkrPXLVb.js → kanban-definition-6JOO6SKY-C0UCWVx-.js} +1 -1
  82. package/payload/server/public/assets/{line-Db0H446a.js → line--uhS9YDE.js} +1 -1
  83. package/payload/server/public/assets/{linear-X3O7lwK3.js → linear-CAOWPodQ.js} +1 -1
  84. package/payload/server/public/assets/maximize-2-8vKr3h21.js +1 -0
  85. package/payload/server/public/assets/{mermaid-parser.core-CixBHOya.js → mermaid-parser.core-D6kPx7vc.js} +2 -2
  86. package/payload/server/public/assets/{mermaid.core-BGQq98L7.js → mermaid.core-CTd4DS6O.js} +3 -3
  87. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-v9cJl1mj.js → mindmap-definition-QFDTVHPH-_AyvyG8C.js} +1 -1
  88. package/payload/server/public/assets/operator-Liul1QEq.js +1 -0
  89. package/payload/server/public/assets/{ordinal-CZY9laxg.js → ordinal-Wx4m9zHk.js} +1 -1
  90. package/payload/server/public/assets/packet-4T2RLAQJ-CTU0gCGb.js +1 -0
  91. package/payload/server/public/assets/page-CYRA87CB.js +1 -0
  92. package/payload/server/public/assets/page-Cg7B1RQx.js +32 -0
  93. package/payload/server/public/assets/{pdf-render-7HZBTZ0_.js → pdf-render-CeX6d2v7.js} +1 -1
  94. package/payload/server/public/assets/pie-ZZUOXDRM-D-EEHxhC.js +1 -0
  95. package/payload/server/public/assets/{pieDiagram-DEJITSTG-DQ0b6edX.js → pieDiagram-DEJITSTG-6TsUDkkQ.js} +1 -1
  96. package/payload/server/public/assets/public-B4HMtpjt.js +1 -0
  97. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-B64mj7Ei.js → quadrantDiagram-34T5L4WZ-CWw9gOI4.js} +1 -1
  98. package/payload/server/public/assets/radar-PYXPWWZC-DHXATZGB.js +1 -0
  99. package/payload/server/public/assets/{reduce-BGQzAenn.js → reduce-BUmc8RDR.js} +1 -1
  100. package/payload/server/public/assets/{requirementDiagram-MS252O5E-CE2JIEWo.js → requirementDiagram-MS252O5E-DCOlxNvx.js} +1 -1
  101. package/payload/server/public/assets/rotate-ccw-sz5IQSnr.js +1 -0
  102. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-Cmt5cfCz.js → sankeyDiagram-XADWPNL6-CW4Xbir3.js} +1 -1
  103. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-B5vVn_sw.js → sequenceDiagram-FGHM5R23-vhb_pBLG.js} +1 -1
  104. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DiUEJ-RZ.js → stateDiagram-FHFEXIEX-Cb1WExEX.js} +1 -1
  105. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CxOIKvXh.js +1 -0
  106. package/payload/server/public/assets/tasks-D9oYgEzs.js +1 -0
  107. package/payload/server/public/assets/time-entry-format-CSuCexpM.js +1 -0
  108. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-C9jprDVw.js → timeline-definition-GMOUNBTQ-BAHTf_AF.js} +1 -1
  109. package/payload/server/public/assets/treeView-SZITEDCU-CC7ouMFd.js +1 -0
  110. package/payload/server/public/assets/treemap-W4RFUUIX-CaCg27im.js +1 -0
  111. package/payload/server/public/assets/triangle-alert-ClS81-CU.js +1 -0
  112. package/payload/server/public/assets/useCopyFeedback-Cn6YgeNx.js +1 -0
  113. package/payload/server/public/assets/useSelectionMode-BaD-ZZRk.js +1 -0
  114. package/payload/server/public/assets/{HeaderMenu-DtIEBHOU.css → useSubAccountSwitcher-CNZL3PKn.css} +1 -1
  115. package/payload/server/public/assets/useSubAccountSwitcher-CvjWJSGv.js +9 -0
  116. package/payload/server/public/assets/useVoiceRecorder-BOzHrDAU.js +2 -0
  117. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-DWqQJ9X0.js → vennDiagram-DHZGUBPP-DtEttvW4.js} +1 -1
  118. package/payload/server/public/assets/wardley-RL74JXVD-bMPsqQZ7.js +1 -0
  119. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-Dg6c2Voh.js → wardleyDiagram-NUSXRM2D-K06y6CVJ.js} +1 -1
  120. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-EhN-zeDj.js → xychartDiagram-5P7HB3ND-D66c40lp.js} +1 -1
  121. package/payload/server/public/browser.html +5 -6
  122. package/payload/server/public/calendar.html +6 -7
  123. package/payload/server/public/chat.html +13 -14
  124. package/payload/server/public/data.html +12 -13
  125. package/payload/server/public/graph.html +11 -12
  126. package/payload/server/public/index.html +15 -16
  127. package/payload/server/public/operator.html +15 -16
  128. package/payload/server/public/public.html +13 -14
  129. package/payload/server/public/tasks.html +5 -6
  130. package/payload/server/server.js +33 -16
  131. package/payload/server/public/assets/AdminLoginScreens-Rf94VD9w.js +0 -1
  132. package/payload/server/public/assets/AdminShell-CyGKg7MG.js +0 -2
  133. package/payload/server/public/assets/Checkbox-B0jmI2y2.js +0 -1
  134. package/payload/server/public/assets/HeaderMenu-BnTYGNaB.js +0 -9
  135. package/payload/server/public/assets/activity-BOBTWFr-.js +0 -1
  136. package/payload/server/public/assets/admin-HDLzwbLl.js +0 -1
  137. package/payload/server/public/assets/architecture-YZFGNWBL-Cypt5qHL.js +0 -1
  138. package/payload/server/public/assets/browser-D4_XLSSm.js +0 -1
  139. package/payload/server/public/assets/calendar-s5V_gbI7.js +0 -1
  140. package/payload/server/public/assets/channel-DhrFAm7m.js +0 -1
  141. package/payload/server/public/assets/chat-40WyKzGb.js +0 -1
  142. package/payload/server/public/assets/chevron-left-C35qGP5f.js +0 -1
  143. package/payload/server/public/assets/chunk-426QAEUC-BhU7-TyS.js +0 -1
  144. package/payload/server/public/assets/chunk-QZHKN3VN-7_kS3RBy.js +0 -1
  145. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BrWqm88p.js +0 -1
  146. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D0wzG5Fd.js +0 -1
  147. package/payload/server/public/assets/clone-DQA-nNrl.js +0 -1
  148. package/payload/server/public/assets/data-Bq0vU3qJ.js +0 -1
  149. package/payload/server/public/assets/gitGraph-7Q5UKJZL-C_-XjxLd.js +0 -1
  150. package/payload/server/public/assets/graph-labels-DzPbbhLc.js +0 -1
  151. package/payload/server/public/assets/info-OMHHGYJF-BH8yDCfL.js +0 -1
  152. package/payload/server/public/assets/infoDiagram-42DDH7IO-D8U4M0pK.js +0 -2
  153. package/payload/server/public/assets/maximize-2-CEbXFpQT.js +0 -1
  154. package/payload/server/public/assets/operator-zKk4HMdX.js +0 -1
  155. package/payload/server/public/assets/packet-4T2RLAQJ-Bajcns4r.js +0 -1
  156. package/payload/server/public/assets/page-BrmN_vzV.js +0 -1
  157. package/payload/server/public/assets/page-Cts-ESBe.js +0 -32
  158. package/payload/server/public/assets/pie-ZZUOXDRM-D7hjM5w1.js +0 -1
  159. package/payload/server/public/assets/public-BItzHBc0.js +0 -1
  160. package/payload/server/public/assets/radar-PYXPWWZC-B46d5x7a.js +0 -1
  161. package/payload/server/public/assets/rotate-ccw-B0EYGhGx.js +0 -1
  162. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DIm3XuAD.js +0 -1
  163. package/payload/server/public/assets/tasks-ClE8-be8.js +0 -1
  164. package/payload/server/public/assets/time-entry-format-BwjGLnXu.js +0 -1
  165. package/payload/server/public/assets/treeView-SZITEDCU-3XQh5xQ1.js +0 -1
  166. package/payload/server/public/assets/treemap-W4RFUUIX-DwR-_l5z.js +0 -1
  167. package/payload/server/public/assets/triangle-alert-DejWYn1x.js +0 -1
  168. package/payload/server/public/assets/useCopyFeedback-CpSgOavK.js +0 -1
  169. package/payload/server/public/assets/useSelectionMode-ZQZQUgze.js +0 -1
  170. package/payload/server/public/assets/useSubAccountSwitcher-DuRLvCfO.js +0 -1
  171. package/payload/server/public/assets/useVoiceRecorder-BTYYeUJW.js +0 -2
  172. package/payload/server/public/assets/wardley-RL74JXVD-DZp9oCGv.js +0 -1
  173. /package/payload/server/public/assets/{_baseFor-CMWvz0uA.js → _baseFor-k8hYPe-U.js} +0 -0
  174. /package/payload/server/public/assets/{array-Cny_NT6T.js → array-BFDiaBgf.js} +0 -0
  175. /package/payload/server/public/assets/{cytoscape.esm-De0CCmB2.js → cytoscape.esm-Ch0xptA4.js} +0 -0
  176. /package/payload/server/public/assets/{defaultLocale-BahRht8U.js → defaultLocale-ZeknFqNe.js} +0 -0
  177. /package/payload/server/public/assets/{dist-C9D_xz81.js → dist-B2N0v8hZ.js} +0 -0
  178. /package/payload/server/public/assets/{init-DoIvjoJ_.js → init-0VJVrkRJ.js} +0 -0
  179. /package/payload/server/public/assets/{katex-Bfn1OZEl.js → katex-Br7bH10N.js} +0 -0
  180. /package/payload/server/public/assets/{path-CTezU8L5.js → path-INs8XTPH.js} +0 -0
  181. /package/payload/server/public/assets/{preload-helper-CT1Z6Pdu.js → preload-helper-D_sPnjeL.js} +0 -0
  182. /package/payload/server/public/assets/{rough.esm-BJo4pvXu.js → rough.esm-DU9bZLvZ.js} +0 -0
  183. /package/payload/server/public/assets/{src-BTKk8KAG.js → src-DHSQDYx-.js} +0 -0
@@ -0,0 +1,68 @@
1
+ // acceptance gate for GOOGLE_CLIENT_ID / GOOGLE_PUBLIC_BASE stamping in the
2
+ // claude-session-manager systemd unit (Task 1761).
3
+ //
4
+ // This test exists because the first fix stamped only the darwin `.env` mirror
5
+ // and missed this Linux unit, so on the actual (Ubuntu) install the google
6
+ // plugin loaded with an empty GOOGLE_CLIENT_ID, registered nothing usable, and
7
+ // the agent fell back to claude.ai connector advice — the very behaviour the
8
+ // plugin was built to remove. The unit env is the ONLY path the value reaches
9
+ // the MCP server: google is `mcp-manifest: auto`, whose generator discards the
10
+ // declared mcp.env block.
11
+ //
12
+ // Three invariants:
13
+ // (a) a brand client id AND an install public base emit both Environment lines.
14
+ // (b) either one missing emits NEITHER line — a client id without a redirect
15
+ // origin builds a consent URL Google rejects on its byte-for-byte
16
+ // redirect_uri comparison, so a half-stamp is worse than no stamp.
17
+ // (c) stamping google never disturbs the outlook pair.
18
+ import test from "node:test";
19
+ import assert from "node:assert/strict";
20
+ import { buildClaudeSessionManagerUnitFile } from "../port-resolution.js";
21
+ const ACCOUNT_ID = "12345678-9abc-def0-1234-56789abcdef0";
22
+ const GOOGLE_ID = "1032860640027-p61l59fnog4mad5o7grginpaps9jnu8c.apps.googleusercontent.com";
23
+ const PUBLIC_BASE = "https://public.sitedesk.online";
24
+ const OUTLOOK_ID = "0fa68fe2-8bec-4007-a0c7-776636fbcf97";
25
+ function build(opts) {
26
+ return buildClaudeSessionManagerUnitFile({
27
+ productName: "SiteDesk",
28
+ brandHostname: "sitedesk-code",
29
+ installDir: "/home/me/sitedesk-code",
30
+ persistDir: "/home/me/.sitedesk-code",
31
+ claudeSessionManagerPort: 19402,
32
+ brandPort: 19300,
33
+ maxyUiInternalPort: 19301,
34
+ accountId: ACCOUNT_ID,
35
+ cdpPort: 9224,
36
+ ...opts,
37
+ });
38
+ }
39
+ test("both values present stamps both Environment lines", () => {
40
+ const unit = build({ googleClientId: GOOGLE_ID, googlePublicBase: PUBLIC_BASE });
41
+ assert.ok(unit.includes(`Environment=GOOGLE_CLIENT_ID=${GOOGLE_ID}`));
42
+ assert.ok(unit.includes(`Environment=GOOGLE_PUBLIC_BASE=${PUBLIC_BASE}`));
43
+ });
44
+ test("a client id with no public base stamps NEITHER line", () => {
45
+ const unit = build({ googleClientId: GOOGLE_ID });
46
+ assert.ok(!unit.includes("GOOGLE_CLIENT_ID"), "a half-stamp must not ship");
47
+ assert.ok(!unit.includes("GOOGLE_PUBLIC_BASE"));
48
+ });
49
+ test("a public base with no client id stamps NEITHER line", () => {
50
+ const unit = build({ googlePublicBase: PUBLIC_BASE });
51
+ assert.ok(!unit.includes("GOOGLE_CLIENT_ID"));
52
+ assert.ok(!unit.includes("GOOGLE_PUBLIC_BASE"));
53
+ });
54
+ test("a brand shipping no google app stamps neither line", () => {
55
+ const unit = build({});
56
+ assert.ok(!unit.includes("GOOGLE_CLIENT_ID"));
57
+ assert.ok(!unit.includes("GOOGLE_PUBLIC_BASE"));
58
+ });
59
+ test("google stamping leaves the outlook pair intact", () => {
60
+ const unit = build({
61
+ googleClientId: GOOGLE_ID,
62
+ googlePublicBase: PUBLIC_BASE,
63
+ outlookClientId: OUTLOOK_ID,
64
+ });
65
+ assert.ok(unit.includes(`Environment=OUTLOOK_CLIENT_ID=${OUTLOOK_ID}`));
66
+ assert.ok(unit.includes("Environment=OUTLOOK_TENANT_ID=common"));
67
+ assert.ok(unit.includes(`Environment=GOOGLE_CLIENT_ID=${GOOGLE_ID}`));
68
+ });
package/dist/index.js CHANGED
@@ -51,6 +51,26 @@ catch (err) {
51
51
  }
52
52
  const INSTALL_DIR = resolve(process.env.HOME ?? "/root", BRAND.installDir);
53
53
  const PERSIST_DIR = resolve(process.env.HOME ?? "/root", BRAND.configDir);
54
+ // Task 1761 — GOOGLE_PUBLIC_BASE is the https origin Google redirects back to
55
+ // after consent. It is a property of THIS INSTALL's tunnel, not of the brand,
56
+ // so it is read from the same cloudflared/tunnel.state the uninstaller reads.
57
+ // Defined once here because BOTH env paths need it: the darwin .env mirror and
58
+ // the Linux systemd unit. Absent tunnel → unset, and google-account-register
59
+ // refuses with an actionable message rather than minting a consent URL whose
60
+ // redirect_uri Google will reject on its byte-for-byte comparison.
61
+ const googlePublicBase = (() => {
62
+ try {
63
+ const tunnelState = join(PERSIST_DIR, "cloudflared/tunnel.state");
64
+ if (!existsSync(tunnelState))
65
+ return "";
66
+ const parsed = JSON.parse(readFileSync(tunnelState, "utf-8"));
67
+ return parsed.domain ? `https://public.${parsed.domain}` : "";
68
+ }
69
+ catch {
70
+ // Unreadable tunnel state is not fatal to the install; the value stays unset.
71
+ return "";
72
+ }
73
+ })();
54
74
  const LOG_DIR = join(PERSIST_DIR, "logs");
55
75
  const LOG_FILE = join(LOG_DIR, `install-${new Date().toISOString().replace(/[:.]/g, "-")}.log`);
56
76
  // every `claude plugin` shellout must read/write the per-brand
@@ -3724,24 +3744,6 @@ function installServiceDarwin() {
3724
3744
  // GOOGLE_PUBLIC_BASE is the https origin the consent redirect returns to;
3725
3745
  // it must match the authorized redirect URI on the vendor app byte-for-byte,
3726
3746
  // so it is derived from the brand's public host, not guessed at call time.
3727
- // GOOGLE_PUBLIC_BASE is the https origin Google redirects back to. It is a
3728
- // property of THIS INSTALL's tunnel, not of the brand, so it is read from
3729
- // the same tunnel.state the uninstaller reads. Absent tunnel → the var is
3730
- // stripped and google-account-register refuses with an actionable message,
3731
- // rather than a guessed host that would fail Google's byte-for-byte
3732
- // redirect_uri comparison at the token exchange.
3733
- let googlePublicBase = "";
3734
- try {
3735
- const tunnelState = join(PERSIST_DIR, "cloudflared/tunnel.state");
3736
- if (existsSync(tunnelState)) {
3737
- const parsed = JSON.parse(readFileSync(tunnelState, "utf-8"));
3738
- if (parsed.domain)
3739
- googlePublicBase = `https://public.${parsed.domain}`;
3740
- }
3741
- }
3742
- catch {
3743
- // Unreadable tunnel state is not fatal to the install; the var stays unset.
3744
- }
3745
3747
  if (BRAND.googleClientId) {
3746
3748
  for (const [key, value] of [
3747
3749
  ["GOOGLE_CLIENT_ID", BRAND.googleClientId],
@@ -4383,6 +4385,8 @@ function installService() {
4383
4385
  accountId: installAccountId,
4384
4386
  cdpPort: CDP_PORT_BRAND,
4385
4387
  outlookClientId: BRAND.outlookClientId,
4388
+ googleClientId: BRAND.googleClientId,
4389
+ googlePublicBase: googlePublicBase || undefined,
4386
4390
  });
4387
4391
  writeFileSync(join(serviceDir, claudeSessionManagerUnitName), claudeSessionManagerUnit);
4388
4392
  logFile(` ${claudeSessionManagerUnitName}: CLAUDE_SESSION_MANAGER_PORT=${CLAUDE_SESSION_MANAGER_PORT_BRAND} MAXY_UI_INTERNAL_PORT=${MAXY_UI_INTERNAL_PORT}`);
@@ -4390,6 +4394,10 @@ function installService() {
4390
4394
  // (a non-empty outlookClientId) against what the unit shipped. `stamped=false`
4391
4395
  // while the brand has a value is the mis-stamp signature.
4392
4396
  logFile(` [installer] op=outlook-client-id brand=${BRAND.hostname} stamped=${BRAND.outlookClientId ? "true" : "false"}`);
4397
+ // Task 1761 — the same standing signal for the Google vendor app. Both parts
4398
+ // are reported because a client id without a public base stamps NEITHER: a
4399
+ // consent URL built without the redirect origin is one Google rejects.
4400
+ logFile(` [installer] op=google-client-id brand=${BRAND.hostname} stamped=${BRAND.googleClientId && googlePublicBase ? "true" : "false"} clientId=${BRAND.googleClientId ? "set" : "unset"} publicBase=${googlePublicBase || "unset"}`);
4393
4401
  // Task 250 — write the brand-agnostic `claude-ptys.slice` unit. Every
4394
4402
  // brand's session manager drops its per-spawn scope units under this
4395
4403
  // slice. Writing it once per install is idempotent (the content is
@@ -135,6 +135,12 @@ export function buildClaudeSessionManagerUnitFile(o) {
135
135
  const outlookEnv = o.outlookClientId
136
136
  ? `\nEnvironment=OUTLOOK_CLIENT_ID=${o.outlookClientId}\nEnvironment=OUTLOOK_TENANT_ID=common`
137
137
  : "";
138
+ // Task 1761 — same contract for the Google vendor app. The client id and the
139
+ // install's public base land together: a client id without a redirect origin
140
+ // produces a consent URL Google rejects, so a half-stamp is worse than none.
141
+ const googleEnv = o.googleClientId && o.googlePublicBase
142
+ ? `\nEnvironment=GOOGLE_CLIENT_ID=${o.googleClientId}\nEnvironment=GOOGLE_PUBLIC_BASE=${o.googlePublicBase}`
143
+ : "";
138
144
  return `[Unit]
139
145
  Description=${o.productName} Claude Session Manager
140
146
  After=network.target
@@ -156,7 +162,7 @@ Environment=PLATFORM_ROOT=${o.installDir}/platform
156
162
  Environment=MAXY_BRAND_PORT=${o.brandPort}
157
163
  Environment=MAXY_UI_INTERNAL_PORT=${o.maxyUiInternalPort}
158
164
  Environment=PLATFORM_PORT=${o.maxyUiInternalPort}
159
- Environment=CDP_PORT=${o.cdpPort}${outlookEnv}
165
+ Environment=CDP_PORT=${o.cdpPort}${outlookEnv}${googleEnv}
160
166
  EnvironmentFile=-${o.persistDir}/.env
161
167
  StandardOutput=append:${o.persistDir}/logs/server.log
162
168
  StandardError=append:${o.persistDir}/logs/server.log
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.471",
3
+ "version": "0.1.472",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -4,7 +4,7 @@ import { createHash } from "node:crypto";
4
4
  import { mkdtempSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
6
6
  import { join } from "node:path";
7
- import { newPkce, buildConsentUrl, runAccountRegisterStart, runAccountRegisterPoll, listConnected, CALENDAR_SCOPE, } from "../tools/account-register.js";
7
+ import { newPkce, buildConsentUrl, runAccountRegisterStart, runAccountRegisterPoll, listConnected, CALENDAR_SCOPE, encodeState, decodeState, } from "../tools/account-register.js";
8
8
  import { TokenStore } from "../auth/token-store.js";
9
9
  function newDir() {
10
10
  return mkdtempSync(join(tmpdir(), "gcal-r-"));
@@ -27,7 +27,46 @@ test("consent URL carries offline access, forced consent, and the calendar scope
27
27
  assert.equal(url.searchParams.get("scope"), CALENDAR_SCOPE);
28
28
  assert.equal(url.searchParams.get("code_challenge_method"), "S256");
29
29
  assert.equal(url.searchParams.get("state"), "st");
30
- assert.equal(url.searchParams.get("redirect_uri"), "https://h/api/google/oauth/callback?account=acct1");
30
+ // NO query string: Google matches redirect_uri exactly against the registered
31
+ // value, so a per-request parameter here fails every request with
32
+ // redirect_uri_mismatch. The account rides in `state` instead.
33
+ assert.equal(url.searchParams.get("redirect_uri"), "https://h/api/google/oauth/callback");
34
+ });
35
+ test("redirect_uri carries no query string at all", () => {
36
+ const url = new URL(buildConsentUrl({
37
+ clientId: "cid",
38
+ redirectUri: "https://h/api/google/oauth/callback",
39
+ state: encodeState("acct1", "nonce"),
40
+ challenge: "ch",
41
+ accountId: "acct1",
42
+ }));
43
+ const redirect = url.searchParams.get("redirect_uri");
44
+ assert.ok(!redirect.includes("?"), `redirect_uri must have no query: ${redirect}`);
45
+ assert.ok(!redirect.includes("account="), "the account must not ride on redirect_uri");
46
+ });
47
+ test("state round-trips the account id and nonce", () => {
48
+ const st = encodeState("2078cb54-08e9-49e9-bf8e-e9f3ad76ca41", "deadbeef");
49
+ assert.deepEqual(decodeState(st), {
50
+ accountId: "2078cb54-08e9-49e9-bf8e-e9f3ad76ca41",
51
+ nonce: "deadbeef",
52
+ });
53
+ });
54
+ test("decodeState rejects malformed values", () => {
55
+ assert.equal(decodeState("nodot"), null);
56
+ assert.equal(decodeState(".leading"), null);
57
+ assert.equal(decodeState("trailing."), null);
58
+ });
59
+ test("register stores the nonce, and the consent state carries account plus nonce", async () => {
60
+ const dir = newDir();
61
+ const res = await runAccountRegisterStart({
62
+ accountId: "acct1", accountsDir: dir, clientId: "cid", publicBase: "https://h",
63
+ });
64
+ const sent = new URL(res.consentUrl).searchParams.get("state");
65
+ const parts = decodeState(sent);
66
+ assert.equal(parts.accountId, "acct1");
67
+ // The pending entry holds the bare nonce, which is what the callback compares.
68
+ const { PendingStore } = await import("../auth/pending-store.js");
69
+ assert.equal(new PendingStore("acct1", dir).read()?.state, parts.nonce);
31
70
  });
32
71
  test("a second register while one is live is refused as in-progress", async () => {
33
72
  const dir = newDir();
@@ -1 +1 @@
1
- {"version":3,"file":"account-register.test.js","sourceRoot":"","sources":["../../src/__tests__/account-register.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-register.test.js","sourceRoot":"","sources":["../../src/__tests__/account-register.test.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,23 @@ export declare function newPkce(): {
6
6
  verifier: string;
7
7
  challenge: string;
8
8
  };
9
+ /** The `state` value carries BOTH the account id and the nonce, as
10
+ * `<accountId>.<nonce>`.
11
+ *
12
+ * It cannot ride on the redirect_uri: Google requires redirect_uri to match a
13
+ * registered value EXACTLY, so a per-request query parameter makes every
14
+ * authorization request fail with redirect_uri_mismatch. Google's own guidance
15
+ * names `state` as the mechanism for per-request application state.
16
+ *
17
+ * Putting the account id in an attacker-visible field is safe because it is
18
+ * routing information, not authorisation: the callback still requires the
19
+ * nonce half to equal the one stored in that account's pending entry, and an
20
+ * attacker cannot produce a valid nonce for an account they do not control. */
21
+ export declare function encodeState(accountId: string, nonce: string): string;
22
+ export declare function decodeState(state: string): {
23
+ accountId: string;
24
+ nonce: string;
25
+ } | null;
9
26
  export declare function buildConsentUrl(args: {
10
27
  clientId: string;
11
28
  redirectUri: string;
@@ -1 +1 @@
1
- {"version":3,"file":"account-register.d.ts","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,cAAc,6CAA6C,CAAC;AAGzE;qDACqD;AACrD,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,wBAAgB,OAAO,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAGjE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAgBT;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,IAAI,GAAG,YAAY,CAAC;CAC7B;AAED;;6DAE6D;AAC7D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAaxF;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BvF;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACtD,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC,CAUD"}
1
+ {"version":3,"file":"account-register.d.ts","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,cAAc,6CAA6C,CAAC;AAGzE;qDACqD;AACrD,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,wBAAgB,OAAO,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAGjE;AAED;;;;;;;;;;;gFAWgF;AAChF,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAItF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAeT;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,IAAI,GAAG,YAAY,CAAC;CAC7B;AAED;;6DAE6D;AAC7D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAaxF;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCvF;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACtD,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC,CAUD"}
@@ -22,10 +22,30 @@ export function newPkce() {
22
22
  const verifier = randomBytes(48).toString("base64url");
23
23
  return { verifier, challenge: createHash("sha256").update(verifier).digest("base64url") };
24
24
  }
25
+ /** The `state` value carries BOTH the account id and the nonce, as
26
+ * `<accountId>.<nonce>`.
27
+ *
28
+ * It cannot ride on the redirect_uri: Google requires redirect_uri to match a
29
+ * registered value EXACTLY, so a per-request query parameter makes every
30
+ * authorization request fail with redirect_uri_mismatch. Google's own guidance
31
+ * names `state` as the mechanism for per-request application state.
32
+ *
33
+ * Putting the account id in an attacker-visible field is safe because it is
34
+ * routing information, not authorisation: the callback still requires the
35
+ * nonce half to equal the one stored in that account's pending entry, and an
36
+ * attacker cannot produce a valid nonce for an account they do not control. */
37
+ export function encodeState(accountId, nonce) {
38
+ return `${accountId}.${nonce}`;
39
+ }
40
+ export function decodeState(state) {
41
+ const idx = state.lastIndexOf(".");
42
+ if (idx <= 0 || idx === state.length - 1)
43
+ return null;
44
+ return { accountId: state.slice(0, idx), nonce: state.slice(idx + 1) };
45
+ }
25
46
  export function buildConsentUrl(args) {
26
- // `account` rides on the redirect_uri query so the callback knows which
27
- // account to write to without trusting `state` to carry it.
28
- const redirect = `${args.redirectUri}?account=${encodeURIComponent(args.accountId)}`;
47
+ // redirect_uri is sent VERBATIM no query string. See encodeState above.
48
+ const redirect = args.redirectUri;
29
49
  const q = new URLSearchParams({
30
50
  client_id: args.clientId,
31
51
  redirect_uri: redirect,
@@ -71,11 +91,15 @@ export async function runAccountRegisterStart(args) {
71
91
  });
72
92
  return { status: "in-progress", ageSec: age };
73
93
  }
74
- const state = randomBytes(16).toString("hex");
94
+ const nonce = randomBytes(16).toString("hex");
95
+ const state = encodeState(args.accountId, nonce);
75
96
  const { verifier, challenge } = newPkce();
76
- log({ tag: "[google-oauth]", op: "register", account: args.accountId, reg: state });
77
- pending.write({ state, verifier, createdAt: Date.now() });
78
- log({ tag: "[google-oauth]", op: "pending-write", reg: state, account: args.accountId });
97
+ log({ tag: "[google-oauth]", op: "register", account: args.accountId, reg: nonce });
98
+ // The pending entry stores the NONCE, not the composed state: the account is
99
+ // already implied by which account's store this is, and comparing the nonce
100
+ // alone keeps the check independent of the encoding.
101
+ pending.write({ state: nonce, verifier, createdAt: Date.now() });
102
+ log({ tag: "[google-oauth]", op: "pending-write", reg: nonce, account: args.accountId });
79
103
  const redirectUri = `${args.publicBase}/api/google/oauth/callback`;
80
104
  const consentUrl = buildConsentUrl({
81
105
  clientId: args.clientId,
@@ -84,7 +108,7 @@ export async function runAccountRegisterStart(args) {
84
108
  challenge,
85
109
  accountId: args.accountId,
86
110
  });
87
- log({ tag: "[google-oauth]", op: "consent-url", reg: state, scopes: CALENDAR_SCOPE, redirect: redirectUri });
111
+ log({ tag: "[google-oauth]", op: "consent-url", reg: nonce, scopes: CALENDAR_SCOPE, redirect: redirectUri });
88
112
  return { status: "pending", consentUrl };
89
113
  }
90
114
  export async function runAccountRegisterPoll(args) {
@@ -1 +1 @@
1
- {"version":3,"file":"account-register.js","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-register.js","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"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"}
@@ -5,11 +5,13 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Activity — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/activity-BOBTWFr-.js"></script>
8
+ <script type="module" crossorigin src="/assets/activity-Dj2nJzPw.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-TPjIAO9U.js">
10
- <link rel="modulepreload" crossorigin href="/assets/HeaderMenu-BnTYGNaB.js">
11
- <link rel="modulepreload" crossorigin href="/assets/triangle-alert-DejWYn1x.js">
12
- <link rel="stylesheet" crossorigin href="/assets/HeaderMenu-DtIEBHOU.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-CvjWJSGv.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/useSelectionMode-BaD-ZZRk.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-5nHOAzXO.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/triangle-alert-ClS81-CU.js">
14
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-CNZL3PKn.css">
13
15
  </head>
14
16
  <body>
15
17
  <div id="root"></div>
@@ -0,0 +1 @@
1
+ import{o as e}from"./chunk-TPjIAO9U.js";import{C as t,D as n,S as r,b as i,v as a}from"./useSubAccountSwitcher-CvjWJSGv.js";import{E as o}from"./useVoiceRecorder-BOzHrDAU.js";import{v as s,y as c}from"./AdminShell-5nHOAzXO.js";import{t as l}from"./Checkbox-CD6aHwac.js";var u=`admin-landing-redirected`,d=`/graph`;function f(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var p=e(n(),1);function m(e=`admin`){let[n,r]=(0,p.useState)(`loading`),[i,a]=(0,p.useState)(``),[s,l]=(0,p.useState)(``),[m,h]=(0,p.useState)(``),[g,_]=(0,p.useState)(!1),[v,y]=(0,p.useState)(!1),[b,x]=(0,p.useState)(!1),[S,C]=(0,p.useState)(!1),[w,T]=(0,p.useState)(!1),[E,D]=(0,p.useState)(null),[O,k]=(0,p.useState)(null),[A,j]=(0,p.useState)(void 0),[M,N]=(0,p.useState)(null),[P,F]=(0,p.useState)(void 0),[I,L]=(0,p.useState)(null),[R,z]=(0,p.useState)(null),[B,V]=(0,p.useState)(void 0),H=(0,p.useRef)(void 0),[U,W]=(0,p.useState)(!1),[G,K]=(0,p.useState)(!0);(0,p.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&W(!0)}).catch(()=>{})},[]);let q=(0,p.useRef)(null),J=(0,p.useRef)(null);(0,p.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let n=await t.json();D(n.session_key),z(n.sessionId??null),j(n.businessName),N(n.role??null),F(n.userName===void 0?null:n.userName),L(n.avatar??null);let i=o(n.thinkingView);return H.current=i,V(i),r(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(n=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check returned ${i.status} after retries`),r(`set-pin`);return}let a=await i.json();if(!a.pin_configured){r(`set-pin`);return}K(!!a.claude_authenticated);let o=!1;try{o=new URLSearchParams(window.location.search).get(`connect`)===`claude`}catch{}if(o){try{let e=new URL(window.location.href);e.searchParams.delete(`connect`),window.history.replaceState(null,``,e.pathname+e.search+e.hash)}catch{}if(!a.claude_authenticated){r(`connect-claude`);return}}if(await e())return;r(`enter-pin`)}catch(e){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check failed:`,e),r(`set-pin`)}}t()},[]),(0,p.useEffect)(()=>{n===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[n]),(0,p.useEffect)(()=>{if(typeof window>`u`)return;let t=!1;try{t=sessionStorage.getItem(u)===`1`}catch{}if(f({appState:n,alreadyRedirected:t,variant:e})){try{sessionStorage.setItem(u,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${d}`),window.location.replace(d)}},[n,e]);let Y=(0,p.useRef)(null);(0,p.useEffect)(()=>{if(n!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();K(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let n=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(n===`remote-auth-required`){t(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${n}`),Y.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[n,E]),(0,p.useEffect)(()=>{n===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(K(!0),r(`enter-pin`))}).catch(()=>{})},[n]);async function X(e,n){y(!0);try{let i=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...n?{accountId:n}:{}})});if(!i.ok){let e=await i.json().catch(()=>({}));if(i.status===401&&e?.code===`remote-auth-required`){t(`enter-pin`,`/api/admin/session`);return}h(e.error||`Invalid PIN`);return}let s=await i.json();D(s.session_key),z(s.sessionId??null),j(s.businessName),N(s.role??null),F(s.userName===void 0?null:s.userName),L(s.avatar??null);let c=o(s.thinkingView);H.current=c,V(c);try{sessionStorage.setItem(`maxy-admin-session-key`,s.session_key)}catch{}a(``),r(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}}let Z=(0,p.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let n=s.trim();if(!n){h(`Please enter your name.`);return}if(i.length<4){h(`PIN must be at least 4 characters.`);return}let o=i;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:n})});if(!e.ok){let n=await e.json().catch(()=>({}));if(e.status===401&&n?.code===`remote-auth-required`){t(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();t.pin_configured&&t.claude_authenticated?r(`enter-pin`):t.pin_configured?r(`connect-claude`):h(n.error||`Failed to set PIN.`)}else r(`enter-pin`)}catch{r(`enter-pin`)}return}h(n.error||`Failed to set PIN.`);return}let i=await fetch(`/api/health`);if((i.ok?await i.json():null)?.claude_authenticated){await X(o);return}a(``),r(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[i,v,s]),Q=(0,p.useCallback)(async e=>{e.preventDefault(),h(``),await X(i)},[i]),ee=(0,p.useCallback)(async()=>{T(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;K(!1),D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}return r(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,p.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}a(``),h(``),r(`enter-pin`)},[]);return(0,p.useEffect)(()=>{Y.current=$},[$]),{appState:n,setAppState:r,pin:i,setPin:a,operatorName:s,setOperatorName:l,pinError:m,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:R,setSessionId:z,expandAll:B,setExpandAll:V,expandAllDefaultRef:H,remoteAuthEnabled:U,claudeConnected:G,pinInputRef:q,setPinFormRef:J,handleSetPin:Z,handleLogin:Q,handleDisconnect:ee,handleLogout:$}}var h=r();function g({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,p.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,h.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,h.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function _(e){let{pin:t,setPin:n,showPin:r,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:_}=e;return(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:i,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,a.productName]}),(0,h.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,a.productName,` who you are, then choose a PIN.`]}),(0,h.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,h.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!t||!m.trim(),loading:c,"aria-label":`Set PIN`,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(l,{checked:r,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function v(e){let{pin:t,setPin:n,showPin:r,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:m}=e;return(0,h.jsxs)(`div`,{className:`connect-page`,children:[p&&m&&(0,h.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:m,children:`Sign out`}),(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:i,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`h1`,{className:`connect-title`,children:a.productName}),(0,h.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r,autoFocus:!0}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!t,loading:c,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(`div`,{className:`pin-options`,children:(0,h.jsx)(l,{checked:r,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function y(e){let{authPolling:t,setAuthPolling:n,authLoading:r,setAuthLoading:o,pinError:c,setPinError:l,setAppState:u}=e,[d,f]=(0,p.useState)(!1),[m,g]=(0,p.useState)(!1),[_,v]=(0,p.useState)(``),[y,b]=(0,p.useState)(``),[x,S]=(0,p.useState)(``);async function C(){S(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:y})})).json();e.accepted?(S(`Code submitted. Finishing sign-in…`),b(``)):S(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),S(`Could not submit code.`)}}async function w(){g(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}g(!1)}async function T(){o(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){n(!0),f(!0),o(!1),v(e.transport||``);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}l(`Timed out waiting for sign-in. Try again.`),n(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}o(!1)}async function E(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),n(!1),l(``)}return t||d?(0,h.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,h.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[t?(0,h.jsx)(`button`,{onClick:E,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,h.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,h.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,h.jsx)(`p`,{className:`chat-intro`,children:t?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!t&&(0,h.jsx)(`div`,{style:{marginTop:`12px`},children:(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:r,children:r?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),t&&_===`native`&&(0,h.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,h.jsx)(`label`,{style:{fontSize:`12px`,color:`#999`,lineHeight:1.4},children:`If the browser didn't finish sign-in, paste the code or full redirect URL from Claude's page:`}),(0,h.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,h.jsx)(`input`,{type:`text`,value:y,onChange:e=>b(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,h.jsx)(s,{variant:`primary`,onClick:C,disabled:!y.trim(),children:`Submit`})]}),x&&(0,h.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:x})]})]}),(0,h.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,h.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:c})]}):(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsxs)(`div`,{className:`connect-logos`,children:[(0,h.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,h.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,h.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,h.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,h.jsx)(`img`,{src:i,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`span`,{className:`connect-logo-label`,children:a.productName})]})]}),(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,a.productName]}),(0,h.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:r,children:r?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,h.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,h.jsx)(`button`,{onClick:w,disabled:m,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:m?`Launching…`:`Open browser first`}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function b({auth:e}){return e.appState===`loading`?(0,h.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,h.jsx)(_,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,h.jsx)(y,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,h.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):null}export{m as n,b as t};
@@ -0,0 +1,2 @@
1
+ import{o as e}from"./chunk-TPjIAO9U.js";import{D as t,E as n,S as r,_ as i,a,d as o,i as s,l as c,m as l,n as u,o as d,p as f,s as p,t as m,u as h,v as g,x as ee}from"./useSubAccountSwitcher-CvjWJSGv.js";import{c as te,d as ne,f as re,h as ie,m as ae,o as oe,p as se,r as ce,s as le,t as ue,u as _}from"./useSelectionMode-BaD-ZZRk.js";async function v(){try{let e=await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`logout`})});return e.ok?(await e.json().catch(()=>({})))?.logged_out===!0:(console.error(`[admin-ui] claude-logout http-status=${e.status}`),!1)}catch(e){return console.error(`[admin-ui] claude-logout fetch failed: ${e instanceof Error?e.message:String(e)}`),!1}}var y=e(t(),1),b=r(),x={sm:14,md:16,lg:18},de={sm:30,md:38,lg:46};function S({variant:e=`primary`,size:t=`md`,icon:n,iconPosition:r=`leading`,loading:i=!1,fullWidth:a=!1,disabled:o=!1,type:s=`button`,onClick:c,"aria-label":l,style:u,className:d,children:f}){let p=[`btn`,`btn--${e}`,t===`md`?``:`btn--${t}`,a?`btn--full`:``,d].filter(Boolean).join(` `),m=x[t],h={...e===`send`?{width:de[t],height:de[t]}:{},...u},g=Object.keys(h).length>0;return(0,b.jsxs)(`button`,{type:s,className:p,disabled:i||o,onClick:c,"aria-label":l,style:g?h:void 0,children:[(0,b.jsxs)(`span`,{className:`btn__content`,style:{visibility:i?`hidden`:`visible`},children:[n&&r===`leading`&&(0,b.jsx)(n,{size:m}),f,n&&r===`trailing`&&(0,b.jsx)(n,{size:m})]}),i&&(0,b.jsx)(`span`,{className:`btn__spinner`,children:`✱`})]})}var C=i(`archive-restore`,[[`rect`,{width:`20`,height:`5`,x:`2`,y:`3`,rx:`1`,key:`1wp1u1`}],[`path`,{d:`M4 8v11a2 2 0 0 0 2 2h2`,key:`tvwodi`}],[`path`,{d:`M20 8v11a2 2 0 0 1-2 2h-2`,key:`1gkqxj`}],[`path`,{d:`m9 15 3-3 3 3`,key:`1pd0qc`}],[`path`,{d:`M12 12v9`,key:`192myk`}]]),w=i(`archive`,[[`rect`,{width:`20`,height:`5`,x:`2`,y:`3`,rx:`1`,key:`1wp1u1`}],[`path`,{d:`M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8`,key:`1s80jp`}],[`path`,{d:`M10 12h4`,key:`a56b0p`}]]),fe=i(`bot`,[[`path`,{d:`M12 8V4H8`,key:`hb8ula`}],[`rect`,{width:`16`,height:`12`,x:`4`,y:`8`,rx:`2`,key:`enze0r`}],[`path`,{d:`M2 14h2`,key:`vft8re`}],[`path`,{d:`M20 14h2`,key:`4cs60a`}],[`path`,{d:`M15 13v2`,key:`1xurst`}],[`path`,{d:`M9 13v2`,key:`rq6x2g`}]]),pe=i(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),me=i(`gauge`,[[`path`,{d:`m12 14 4-4`,key:`9kzdfg`}],[`path`,{d:`M3.34 19a10 10 0 1 1 17.32 0`,key:`19p75a`}]]),he=i(`history`,[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}],[`path`,{d:`M12 7v5l4 2`,key:`1fdv2h`}]]),ge=i(`list-todo`,[[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}],[`path`,{d:`m3 17 2 2 4-4`,key:`1jhpwq`}],[`rect`,{x:`3`,y:`4`,width:`6`,height:`6`,rx:`1`,key:`cif1o7`}]]),T=i(`message-square`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}]]),_e=i(`sliders-horizontal`,[[`path`,{d:`M10 5H3`,key:`1qgfaw`}],[`path`,{d:`M12 19H3`,key:`yhmn1j`}],[`path`,{d:`M14 3v4`,key:`1sua03`}],[`path`,{d:`M16 17v4`,key:`1q0r14`}],[`path`,{d:`M21 12h-9`,key:`1o4lsq`}],[`path`,{d:`M21 19h-5`,key:`1rlt1p`}],[`path`,{d:`M21 5h-7`,key:`1oszz2`}],[`path`,{d:`M8 10v4`,key:`tgpxqk`}],[`path`,{d:`M8 12H3`,key:`a7s4jb`}]]),ve=i(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]),E=`maxy-shell-side-px`;function D(){if(typeof window>`u`)return 0;let e=document.querySelector(`.platform > .artefact`)?.getBoundingClientRect();return e&&e.width>0?Math.round(e.width):0}function O(e){if(typeof window>`u`)return e;let t=window.innerWidth,n=Math.max(248,t-480-D());return Math.min(Math.max(e,248),n)}function ye(){if(typeof window>`u`)return 264;try{let e=window.localStorage.getItem(E);if(!e)return 264;let t=parseInt(e,10);if(!Number.isFinite(t))return console.warn(`[admin-ui] sidebar-width-parse-failed stored=${JSON.stringify(e)} fallback=264`),264;if(t>=248)return O(t)}catch{}return 264}function k({targetSelector:e=`.platform`}){let t=(0,y.useRef)(null),[n,r]=(0,y.useState)(()=>ye()),i=(0,y.useRef)(n);(0,y.useLayoutEffect)(()=>{let t=document.querySelector(e);!t||!(t instanceof HTMLElement)||(t.style.setProperty(`--side-px`,`${n}px`),i.current=n)},[n,e]);let a=(0,y.useCallback)(()=>{r(e=>{let t=O(e);return t===e?e:t})},[]);(0,y.useEffect)(()=>{a(),window.addEventListener(`resize`,a);let t=document.querySelector(e),n=null;return t instanceof HTMLElement&&(n=new MutationObserver(a),n.observe(t,{attributes:!0,attributeFilter:[`data-artefact`,`class`]})),()=>{window.removeEventListener(`resize`,a),n?.disconnect()}},[a,e]);let o=e=>{e.preventDefault();let n=t.current;if(!n)return;n.setPointerCapture(e.pointerId),n.classList.add(`dragging`);let a=!1,o=e=>{a=!0,r(O(Math.round(e.clientX)))},s=()=>{if(n.releasePointerCapture(e.pointerId),n.classList.remove(`dragging`),window.removeEventListener(`pointermove`,o),window.removeEventListener(`pointerup`,s),!a)return;let t=i.current;try{window.localStorage.setItem(E,String(t))}catch{}console.info(`[admin-ui] sidebar-resize px=${t}`)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s)},s=()=>{let e=O(264);r(e);try{window.localStorage.removeItem(E)}catch{}console.info(`[admin-ui] sidebar-resize px=${e}`)};return(0,b.jsx)(`div`,{ref:t,className:`side-resize-handle`,role:`separator`,"aria-orientation":`vertical`,"aria-label":`Resize sidebar`,onPointerDown:o,onDoubleClick:s})}var be=n();function xe({anchorRef:e,onClose:t,className:n,role:r,ariaLabel:i,children:a}){let o=(0,y.useRef)(null),[s,c]=(0,y.useState)({position:`fixed`,visibility:`hidden`}),l=(0,y.useCallback)(()=>{let t=e.current,n=o.current;if(!t||!n)return;let r=t.getBoundingClientRect(),i=n.getBoundingClientRect(),a=r.right-i.width;a<4&&(a=4);let s=window.innerHeight-r.bottom<i.height+8&&r.top>i.height+8?r.top-i.height:r.bottom;c({position:`fixed`,left:a,top:s,visibility:`visible`})},[e]);return(0,y.useLayoutEffect)(()=>{if(l(),typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>l());return o.current&&e.observe(o.current),()=>e.disconnect()},[l]),(0,y.useEffect)(()=>{let n=e=>{e.key===`Escape`&&t()},r=n=>{let r=n.target;e.current?.contains(r)||o.current?.contains(r)||t()},i=n=>{let r=e.current;r&&n.target instanceof Node&&n.target.contains(r)&&t()},a=()=>t();return document.addEventListener(`keydown`,n),document.addEventListener(`pointerdown`,r),window.addEventListener(`scroll`,i,!0),window.addEventListener(`resize`,a),()=>{document.removeEventListener(`keydown`,n),document.removeEventListener(`pointerdown`,r),window.removeEventListener(`scroll`,i,!0),window.removeEventListener(`resize`,a)}},[e,t]),(0,be.createPortal)((0,b.jsx)(`div`,{ref:o,className:n,role:r,"aria-label":i,style:s,children:a}),document.body)}function Se({actions:e,disabled:t}){let[n,r]=(0,y.useState)(!1),[i,a]=(0,y.useState)(null),o=(0,y.useRef)(null),s=(0,y.useCallback)(()=>{r(!1),a(null)},[]);return(0,b.jsxs)(`div`,{className:`conv-actions`,children:[(0,b.jsx)(`button`,{ref:o,type:`button`,className:`conv-action conv-actions-overflow`,onClick:()=>r(e=>!e),disabled:t,"aria-haspopup":`menu`,"aria-expanded":n,"aria-label":`Session actions`,title:`Session actions`,children:(0,b.jsx)(h,{size:12})}),n&&(0,b.jsx)(xe,{anchorRef:o,onClose:s,className:`conv-actions-menu`,role:`menu`,children:e.map(e=>e.panel?(0,b.jsxs)(`div`,{className:`conv-actions-menu-disclosure`,children:[(0,b.jsxs)(`button`,{type:`button`,role:`menuitem`,"aria-haspopup":`dialog`,"aria-expanded":i===e.key,disabled:t,onClick:()=>a(t=>t===e.key?null:e.key),children:[e.icon,(0,b.jsx)(`span`,{children:e.menuLabel})]}),i===e.key&&(0,b.jsx)(`div`,{className:`conv-actions-menu-panel`,children:e.panel()})]},e.key):(0,b.jsxs)(`button`,{type:`button`,role:`menuitem`,className:e.danger?`conv-action-danger`:void 0,"aria-busy":e.busy,disabled:t,onClick:t=>{e.onClick?.(t),s()},children:[e.icon,(0,b.jsx)(`span`,{children:e.menuLabel})]},e.key))})]})}var A=`claude-opus-4-8[1m]`,j=`claude-sonnet-5`,M=`claude-haiku-4-5`,Ce={[A]:`Opus 4.8 (1M context)`,[j]:`Sonnet 5`,[M]:`Haiku 4.5`};function N(e){return Ce[e]??e}var we=[A,j,M];function P(e){return e.replace(/\[1m\]$/,``)}function Te(e){return we.find(t=>P(t)===P(e))??e}var F=[`default`,`acceptEdits`,`plan`,`auto`,`bypassPermissions`],I=[`low`,`medium`,`high`,`xhigh`];[...F],[...I],[...I];var L=[A,j,M],Ee={default:`Ask permissions`,acceptEdits:`Accept edits`,plan:`Plan mode`,auto:`Auto mode`,bypassPermissions:`Bypass permissions`},De=F.map(e=>({value:e,label:Ee[e]??e})),Oe={low:`Low`,medium:`Medium`,high:`High`,xhigh:`Highest`},R=I.map(e=>({value:e,label:Oe[e]??e}));function z(e){if(e){let t=L.find(t=>P(t)===P(e));if(t)return t}return A}function ke({row:e,adminFetch:t,onError:n}){let[r,i]=(0,y.useState)(()=>z(e.model)),[a,s]=(0,y.useState)(``),[c,l]=(0,y.useState)(``),[u,d]=(0,y.useState)(!1),f=(0,y.useRef)(!1);(0,y.useEffect)(()=>{i(z(e.model))},[e.model]);let p=async()=>{if(!f.current){f.current=!0,d(!0);try{let i=await t(`/api/admin/session-reseat`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({fromSessionId:e.sessionId,model:r,...a?{permissionMode:a}:{},...c?{effort:c}:{}})});if(!i.ok){n(`Could not reset ${e.title} (status ${i.status})`),console.error(`[admin-ui] dashboard-reseat-failed sessionId=${e.sessionId} status=${i.status}`),f.current=!1,d(!1);return}let o=await i.json().catch(()=>({}));o.target?window.location.assign(o.target):(n(`Reset of ${e.title} returned no target`),f.current=!1,d(!1))}catch(t){n(`Could not reset ${e.title} (network error)`),console.error(`[admin-ui] dashboard-reseat-failed sessionId=${e.sessionId} error=${t instanceof Error?t.message:String(t)}`),f.current=!1,d(!1)}}};return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`label`,{className:`reseat-field`,children:[(0,b.jsx)(`span`,{children:`Model`}),(0,b.jsx)(`select`,{"data-kind":`model`,value:r,disabled:u,onChange:e=>i(e.target.value),children:L.map(e=>(0,b.jsx)(`option`,{value:e,children:N(e)},e))})]}),(0,b.jsxs)(`label`,{className:`reseat-field`,children:[(0,b.jsx)(`span`,{children:`Mode`}),(0,b.jsxs)(`select`,{"data-kind":`mode`,value:a,disabled:u,onChange:e=>s(e.target.value),children:[(0,b.jsx)(`option`,{value:``,children:`Keep current`}),De.map(e=>(0,b.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,b.jsxs)(`label`,{className:`reseat-field`,children:[(0,b.jsx)(`span`,{children:`Effort`}),(0,b.jsxs)(`select`,{"data-kind":`effort`,value:c,disabled:u,onChange:e=>l(e.target.value),children:[(0,b.jsx)(`option`,{value:``,children:`Keep current`}),R.map(e=>(0,b.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,b.jsx)(`button`,{type:`button`,className:`reseat-apply`,disabled:u,"aria-busy":u,onClick:()=>void p(),children:u?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(o,{size:12,className:`spin`,"aria-hidden":`true`}),`Resetting…`]}):`Reset`})]})}function Ae(e){if(e<60)return`${e}s`;let t=Math.floor(e/60),n=e%60;return n>0?`${t}m ${n}s`:`${t}m`}function B(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function je({target:e,anchorEl:t,onConfirm:n,onCancel:r}){let i=(0,y.useRef)(null);return i.current=t,e?(0,b.jsxs)(xe,{anchorRef:i,onClose:r,className:`conv-delete-confirm`,role:`alertdialog`,ariaLabel:`Confirm delete session`,children:[(0,b.jsxs)(`div`,{className:`claude-info-header`,children:[(0,b.jsx)(`span`,{children:`Delete this conversation?`}),(0,b.jsx)(`button`,{className:`claude-info-close`,onClick:r,"aria-label":`Close`,children:`✕`})]}),(0,b.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[(0,b.jsxs)(`div`,{className:`conv-delete-target`,children:[(0,b.jsx)(`span`,{className:`conv-delete-label`,title:e.title,children:e.title||`Untitled session`}),(0,b.jsx)(`code`,{className:`conv-delete-id`,title:e.sessionId,children:e.sessionId.slice(0,8)})]}),(0,b.jsx)(`div`,{style:{marginTop:`8px`},children:`This permanently removes the transcript. It is not moved to Archive and cannot be recovered.`}),e.live&&(0,b.jsx)(`div`,{style:{marginTop:`8px`},children:`This session is running; deleting stops it first.`})]}),(0,b.jsxs)(`div`,{className:`claude-info-section`,style:{display:`flex`,gap:`8px`,padding:`10px 14px`},children:[(0,b.jsx)(S,{variant:`danger`,size:`sm`,style:{flex:1},onClick:n,children:`Delete`}),(0,b.jsx)(S,{variant:`secondary`,size:`sm`,style:{flex:1},onClick:r,children:`Cancel`})]})]}):null}function Me({open:e,count:t,liveCount:n,onConfirm:r,onCancel:i}){if(!e)return null;let a=t===1?``:`s`;return(0,b.jsx)(`div`,{className:`claude-info-overlay`,onClick:i,children:(0,b.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Confirm delete sessions`,children:[(0,b.jsxs)(`div`,{className:`claude-info-header`,children:[(0,b.jsxs)(`span`,{children:[`Delete `,t,` conversation`,a,`?`]}),(0,b.jsx)(`button`,{className:`claude-info-close`,onClick:i,"aria-label":`Close`,children:`✕`})]}),(0,b.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[`This permanently removes `,t,` transcript`,a,`. `,t===1?`It is`:`They are`,` not moved to Archive and cannot be recovered.`,n>0&&(0,b.jsxs)(`div`,{style:{marginTop:`8px`},children:[n,` `,n===1?`is`:`are`,` running and will be stopped first.`]})]}),(0,b.jsxs)(`div`,{className:`claude-info-section`,style:{display:`flex`,gap:`8px`,padding:`10px 14px`},children:[(0,b.jsxs)(S,{variant:`danger`,size:`sm`,style:{flex:1},onClick:r,children:[`Delete `,t]}),(0,b.jsx)(S,{variant:`secondary`,size:`sm`,style:{flex:1},onClick:i,children:`Cancel`})]})]})})}var Ne=`auth-refresh-failed`;function Pe({error:e,onClose:t}){if(!e)return null;let n=e.reason===Ne,r=n?`Claude sign-in expired`:`Session didn’t open`,i=n?`Your claude.ai login has expired. Re-authenticate to resume sessions.`:`The session did not bind within 60 seconds, so there is no live conversation to open.`;return(0,b.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,b.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Session could not be opened`,children:[(0,b.jsxs)(`div`,{className:`claude-info-header`,children:[(0,b.jsx)(`span`,{children:r}),(0,b.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:`✕`})]}),(0,b.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[i,(0,b.jsxs)(`div`,{className:`claude-info-row`,style:{marginTop:`8px`},children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Reason`}),(0,b.jsx)(`span`,{className:`claude-info-value`,children:e.reason})]}),e.sessionId&&(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,b.jsxs)(`span`,{className:`claude-info-value`,children:[e.sessionId.slice(0,8),`…`]})]})]})]})})}function Fe(e){let{show:t,onClose:n,claudeInfo:r,messages:i,sessionElapsed:a,sessionId:o,cacheKey:s}=e,[c,l]=(0,y.useState)(null);if(!t)return null;let u=i.flatMap(e=>e.events?.filter(e=>e.type===`usage`)??[]),d=u.at(-1),f=d?.peak_request_pct==null?d?.context_window?Math.round((d.input_tokens+d.cache_creation_tokens+d.cache_read_tokens)/d.context_window*100):0:Math.round(d.peak_request_pct*100),p=u.reduce((e,t)=>e+t.input_tokens+t.cache_creation_tokens+t.cache_read_tokens+t.output_tokens,0),m=i.flatMap(e=>e.events?.filter(e=>e.type===`rate_limit`)??[]).at(-1),h=u.reduce((e,t)=>e+(t.total_cost_usd??0),0),g=r?.account?.subscriptionType,ee=e=>{let t=e*1e3-Date.now();if(t<=0)return`now`;let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4);return n>0?`${n}h ${r}m`:`${r}m`};return(0,b.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,b.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),children:[(0,b.jsxs)(`div`,{className:`claude-info-header`,children:[(0,b.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`claude-info-icon`}),(0,b.jsx)(`span`,{children:`Claude Code`}),(0,b.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,b.jsxs)(`div`,{className:`claude-info-section`,children:[(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Version`}),(0,b.jsx)(`span`,{className:`claude-info-value`,children:r?r.version:`…`})]}),(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Email`}),(0,b.jsx)(`span`,{className:`claude-info-value`,children:r?.account?.email??`…`})]})]}),(g||m||h>0)&&(0,b.jsxs)(`div`,{className:`claude-info-section`,children:[g&&(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Plan`}),(0,b.jsx)(`span`,{className:`claude-info-value`,style:{textTransform:`capitalize`},children:g})]}),m&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Usage`}),(0,b.jsxs)(`span`,{className:`claude-info-value`,children:[Math.round(m.utilization*100),`%`]})]}),(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Resets in`}),(0,b.jsx)(`span`,{className:`claude-info-value`,children:ee(m.resetsAt)})]}),m.isUsingOverage&&(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Overage`}),(0,b.jsx)(`span`,{className:`claude-info-value`,children:`Active`})]})]}),h>0&&(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Session cost`}),(0,b.jsxs)(`span`,{className:`claude-info-value`,children:[`$`,h<.01?h.toFixed(4):h.toFixed(2)]})]})]}),(0,b.jsxs)(`div`,{className:`claude-info-section`,children:[(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Model`}),(0,b.jsx)(`span`,{className:`claude-info-value`,children:r?.model??`…`})]}),(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Context used`}),(0,b.jsx)(`span`,{className:`claude-info-value`,children:f>0?`${f}%`:`—`})]}),(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Tokens`}),(0,b.jsx)(`span`,{className:`claude-info-value`,children:p>0?B(p):`—`})]}),(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,b.jsx)(`span`,{className:`claude-info-value`,children:Ae(a)})]}),(o||s)&&(()=>{let e=o??s??``;return(0,b.jsxs)(`div`,{className:`claude-info-row`,children:[(0,b.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,b.jsx)(`button`,{type:`button`,className:`claude-info-value claude-info-id-copy`,title:`${e} (${o?`flushed`:`pre-flush`}) — click to copy`,onClick:async()=>{l(await ue(e)?`copied`:`failed`),setTimeout(()=>l(null),1200)},children:c===`copied`?`copied ✓`:c===`failed`?`copy failed ✕`:`${e.slice(0,8)}…`})]})})()]})]})})}function Ie({open:e,onConnect:t,onClose:n}){return e?(0,b.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,b.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Claude is not connected`,children:[(0,b.jsxs)(`div`,{className:`claude-info-header`,children:[(0,b.jsx)(`span`,{children:`Claude isn’t connected`}),(0,b.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,b.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`,display:`flex`,flexDirection:`column`,gap:`10px`},children:[(0,b.jsx)(`span`,{children:`This needs Claude, which is currently disconnected. Connect to continue — the rest of the dashboard stays available either way.`}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,alignItems:`center`},children:[(0,b.jsx)(S,{variant:`primary`,size:`sm`,onClick:t,children:`Connect Claude`}),(0,b.jsx)(`button`,{type:`button`,className:`claude-info-close`,style:{fontSize:`11px`},onClick:n,children:`Not now`})]})]})]})}):null}function V(e){let t=Math.round(e/6e4),n=Math.floor(t/60),r=t%60;return`${n}h ${String(r).padStart(2,`0`)}m`}function Le(e){return e.activeMs.thinking+e.activeMs.messaging+e.activeMs.toolUse}function H(e){return e.toLocaleString(`en-GB`)}function U(e){return`£${e.toFixed(2)}`}function Re(e){let t=[`Day`,`Active`,`Output tokens`,`Input tokens`,`Cache write`,`Cache read`,`Opus 4.8 (GBP)`,`Sonnet 4.6 (GBP)`],n=(e,t)=>[e,V(Le(t)),String(t.tokens.output),String(t.tokens.input),String(t.tokens.cacheWrite),String(t.tokens.cacheRead),t.costGBP.opus.toFixed(2),t.costGBP.sonnet.toFixed(2)];return[t,...e.days.map(e=>n(e.date,e)),n(`TOTAL (${e.days.length} d)`,e.totals)].map(e=>e.join(`,`)).join(`
2
+ `)}function ze({label:e,d:t,bold:n}){let r=n?`th`:`td`;return(0,b.jsxs)(`tr`,{className:n?`usage-total-row`:void 0,children:[(0,b.jsx)(r,{className:`usage-day`,children:e}),(0,b.jsx)(r,{children:V(Le(t))}),(0,b.jsx)(r,{children:H(t.tokens.output)}),(0,b.jsx)(r,{children:H(t.tokens.input)}),(0,b.jsx)(r,{children:H(t.tokens.cacheWrite)}),(0,b.jsx)(r,{children:H(t.tokens.cacheRead)}),(0,b.jsx)(r,{children:U(t.costGBP.opus)}),(0,b.jsx)(r,{children:U(t.costGBP.sonnet)})]})}function Be({show:e,onClose:t,sessionId:n,summary:r,loading:i,error:o}){if(!e)return null;let s=!!r&&r.days.length>0,c=()=>{if(!r)return;let e=new Blob([Re(r)],{type:`text/csv;charset=utf-8`}),t=URL.createObjectURL(e),i=document.createElement(`a`);i.href=t,i.download=`usage-${n?n.slice(0,8):`session`}.csv`,document.body.appendChild(i),i.click(),i.remove(),URL.revokeObjectURL(t)};return(0,b.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,b.jsxs)(`div`,{className:`claude-info-modal usage-modal`,onClick:e=>e.stopPropagation(),role:`dialog`,"aria-label":`Session usage and cost`,children:[(0,b.jsxs)(`div`,{className:`claude-info-header`,children:[(0,b.jsxs)(`span`,{children:[`Usage & cost`,n?` · ${n.slice(0,8)}`:``]}),s&&(0,b.jsx)(`button`,{className:`usage-download`,onClick:c,"aria-label":`Download as CSV`,title:`Download as CSV`,children:(0,b.jsx)(ie,{size:14})}),(0,b.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:(0,b.jsx)(a,{size:14})})]}),(0,b.jsxs)(`div`,{className:`claude-info-section usage-body`,children:[i&&(0,b.jsx)(`div`,{className:`usage-note`,children:`Computing usage…`}),!i&&o&&(0,b.jsx)(`div`,{className:`usage-note usage-error`,children:o}),!i&&!o&&r&&r.days.length===0&&(0,b.jsx)(`div`,{className:`usage-note`,children:`No usage recorded for this session yet.`}),!i&&!o&&r&&r.days.length>0&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`div`,{className:`usage-table-scroll`,children:(0,b.jsxs)(`table`,{className:`usage-table`,children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{className:`usage-day`,children:`Day`}),(0,b.jsx)(`th`,{children:`Active`}),(0,b.jsx)(`th`,{children:`Output tok`}),(0,b.jsx)(`th`,{children:`Input tok`}),(0,b.jsx)(`th`,{children:`Cache write`}),(0,b.jsx)(`th`,{children:`Cache read`}),(0,b.jsx)(`th`,{children:`Opus 4.8 (£)`}),(0,b.jsx)(`th`,{children:`Sonnet 4.6 (£)`})]})}),(0,b.jsxs)(`tbody`,{children:[r.days.map(e=>(0,b.jsx)(ze,{label:e.date,d:e},e.date)),(0,b.jsx)(ze,{label:`TOTAL (${r.days.length} d)`,d:r.totals,bold:!0})]})]})}),(0,b.jsxs)(`div`,{className:`usage-note usage-caveats`,children:[`Prices dated `,r.pricing.opusPriceDate,` · £/$ `,r.pricing.usdPerGbp,` · Sonnet tokenizer factor `,r.pricing.tokenizerFactor,`. Idle human-wait dominates the calendar span; cache-read tokens dominate cost; Sonnet is a tokenizer-adjusted estimate.`]})]})]})]})})}var Ve=`https://claude.ai/code`,He=200,Ue=[500,1e3,1500,2e3,2500,3e3,3e3];function We(e,t,n){if(e&&n.target)return{kind:`navigate`,url:n.target,sameOrigin:!0};let r=n.slug??n.bridgeSessionId??null;if(e&&r)return{kind:`navigate`,url:`${Ve}/${r}`,sameOrigin:!1};let i=n.reason||n.error||`status ${t}`;return{kind:`error`,sessionId:n.sessionId??null,reason:i}}function Ge(e){if(!e)return``;let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:`medium`,timeStyle:`short`}):``}function Ke(e){let{businessName:t,cacheKey:n,onConnectClaude:r,role:i,userName:a,userAvatar:o,onSelectProjects:u,onSelectPeople:m,onSelectTasks:h,onSelectAgents:ue,onCloseMobileDrawer:v,collapsed:x,selectedWhatsappId:de,onSelectWhatsappConversation:S,initialWhatsappSurface:E=!1,onSelectData:D,onCloseData:O,initialDataSurface:ye=!1}=e,k=s(n),be=(0,y.useCallback)(e=>({key:`reseat`,label:`Reset session ${e.title} (model, mode, effort)`,menuLabel:`Reset`,title:`Reset — move this session onto a chosen model, mode, and effort`,icon:(0,b.jsx)(_e,{size:12}),panel:()=>(0,b.jsx)(ke,{row:e,adminFetch:k,onError:e=>z({message:e,failed:!0})})}),[k]),xe=g.productName,A=typeof a==`string`?a:a===null?`name unavailable`:t||xe,j=(A.trim().charAt(0)||`?`).toUpperCase(),[M,Ce]=(0,y.useState)(ye?`data`:E?`whatsapp`:`sessions`),[N,we]=(0,y.useState)([]),[P,Te]=(0,y.useState)(!1),[F,I]=(0,y.useState)(null),[L,Ee]=(0,y.useState)(!1),[De,Oe]=(0,y.useState)(`file`),[R,z]=(0,y.useState)(null),[Ae,B]=(0,y.useState)(null),[Ne,Fe]=(0,y.useState)(!1),[V,Le]=(0,y.useState)([]),[H]=(0,y.useState)(()=>typeof window>`u`?null:new URLSearchParams(window.location.search).get(`session`)),[U,Re]=(0,y.useState)(!1),[ze,Ve]=(0,y.useState)(null),[Ke,qe]=(0,y.useState)(!1),[W,Ze]=(0,y.useState)(!1),[G,Qe]=(0,y.useState)(!1),[$e,et]=(0,y.useState)(null),[K,tt]=(0,y.useState)(new Set),nt=(0,y.useRef)(new Map),[q,rt]=(0,y.useState)(!1),[J,it]=(0,y.useState)(new Set),[at,ot]=(0,y.useState)(!1),[Y,st]=(0,y.useState)(null),[ct,lt]=(0,y.useState)(new Set),[ut,dt]=(0,y.useState)(new Set),[ft,pt]=(0,y.useState)(new Set),[X,mt]=(0,y.useState)(null),[ht,Z]=(0,y.useState)(``),[gt,_t]=(0,y.useState)(!1),[vt,yt]=(0,y.useState)(null),[bt,xt]=(0,y.useState)(null),[St,Ct]=(0,y.useState)(!1),[wt,Tt]=(0,y.useState)(null),[Et,Dt]=(0,y.useState)(!1),Ot=(0,y.useRef)(0),[kt,At]=(0,y.useState)([]),[jt,Mt]=(0,y.useState)(!1),[Nt,Pt]=(0,y.useState)(null),[Ft,It]=(0,y.useState)(`whatsapp`),Lt=(0,y.useCallback)(e=>{if(v(),!n){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=no-cache-key`),z({message:`Session not ready — try again`,failed:!0});return}if(!e.downloadPath){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=not-downloadable`),z({message:`${e.name} can’t be downloaded`,failed:!0});return}console.info(`[admin-ui] artefact-download id=${e.id} root=${e.downloadRoot??`data`} path=${e.downloadPath}`),ce(n,e.downloadPath,e.downloadRoot??`data`),z({message:`Downloading ${e.name}`,failed:!1})},[n,v]);(0,y.useEffect)(()=>{if(!R)return;let e=setTimeout(()=>z(null),2500);return()=>clearTimeout(e)},[R]);let Rt=H!=null&&V.some(e=>e.sessionId===H);(0,y.useEffect)(()=>{H==null||!U||console.info(`[sidebar-sessions] op=select-highlight session=${H.slice(0,8)} matched=${Rt}`)},[H,Rt,U]);let zt=(0,y.useCallback)(async()=>{if(n){Ee(!0),I(null);try{let e=await k(`/api/admin/sidebar-artefacts`);if(!e.ok)throw Error(`status ${e.status}`);we((await e.json()).artefacts??[]),Te(!0)}catch(e){let t=e instanceof Error?e.message:String(e);I(`Failed to load artefacts: ${t}`),console.error(`[admin-ui] sidebar-artefacts fetch failed: ${t}`)}finally{Ee(!1)}}},[n,k]),Q=(0,y.useCallback)(async()=>{if(!n)return null;let e=++Ot.current;qe(!0),Ve(null);try{let t=await k(`/api/admin/sidebar-sessions`);if(!t.ok)throw Error(`status ${t.status}`);let n=await t.json(),r=n.sessions??[];return e===Ot.current?(Le(r),et(n.accountId??null),Re(!0),r):(console.info(`[admin-ui] sidebar-sessions-stale-response-dropped token=${e}`),r)}catch(t){let n=t instanceof Error?t.message:String(t);return e===Ot.current&&Ve(`Failed to load sessions: ${n}`),console.error(`[admin-ui] sidebar-sessions fetch failed: ${n}`),null}finally{e===Ot.current&&qe(!1)}},[n,k]),Bt=(0,y.useCallback)(async()=>{if(n){Pt(null);try{let e=await k(`/api/whatsapp-reader/conversations`);if(!e.ok)throw Error(`status ${e.status}`);At((await e.json()).conversations??[]),Mt(!0)}catch(e){let t=e instanceof Error?e.message:String(e);Pt(`Couldn't load conversations.`),console.error(`[admin-ui] channel-convos fetch failed: ${t}`)}}},[n,k]);(0,y.useEffect)(()=>{!n||U||Q()},[n,U,Q]),(0,y.useEffect)(()=>{if(!n)return;let e=null;return Bt(),e=setInterval(()=>{Bt()},Je),()=>{e!==null&&clearInterval(e)}},[n,Bt]),(0,y.useEffect)(()=>{if(!n)return;let e=null;function t(){console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=poll`),Q()}function r(){e===null&&(e=setInterval(t,Ye))}function i(){e!==null&&(clearInterval(e),e=null)}function a(){document.hidden?i():(t(),r())}return document.hidden||r(),document.addEventListener(`visibilitychange`,a),()=>{i(),document.removeEventListener(`visibilitychange`,a)}},[n,Q]);let Vt=(0,y.useMemo)(()=>{let e=new Map;for(let t of le)e.set(t,[]);for(let t of kt)e.get(t.channel)?.push(t);for(let t of le)console.info(`[admin-ui] sidebar-nav surface=${t} count=${e.get(t).length}`);return e},[kt]),Ht={whatsapp:`WhatsApp`,telegram:`Telegram`,webchat:`Webchat`},Ut=()=>{S(null),Ce(`artefacts`),console.info(`[admin-ui] sidebar-nav surface=artefacts count=${P?N.length:0} collapsed=${x}`),zt()},$=1.5,Wt=()=>{console.info(`[admin-ui] sidebar-refresh surface=artefacts`),zt()},Gt=()=>{S(null),Ce(`sessions`),console.info(`[admin-ui] sidebar-nav surface=sessions count=${U?V.length:0} collapsed=${x}`),U||Q()},Kt=()=>{console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=manual`),Q()},qt=()=>{Ce(`data`),console.info(`[admin-ui] sidebar-nav surface=data collapsed=${x}`),D(),v()},Jt=e=>{O?.(),Ce(`whatsapp`),It(e),console.info(`[admin-ui] sidebar-nav surface=${e} count=${Vt.get(e)?.length??0} collapsed=${x}`)},Yt=(0,y.useCallback)(async e=>{if(ct.has(e.sessionId))return;lt(t=>{let n=new Set(t);return n.add(e.sessionId),n});let t=window.open(``,`_blank`);try{let n=await k(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId,name:e.title||e.sessionId,...e.accountId?{targetAccountId:e.accountId}:{}})}),r=await n.json().catch(()=>({})),i=We(n.ok,n.status,{...r,sessionId:r.sessionId??e.sessionId});console.info(`[admin-ui] sidebar-session-resume sessionId=${e.sessionId} status=${n.status} outcome=${i.kind} slug=${r.slug??r.bridgeSessionId??`none`}`),i.kind===`navigate`?(v(),t?t.location.href=i.url:window.open(i.url,`_blank`)):(t?.close(),console.error(`[admin-ui] sidebar-session-resume-failed sessionId=${e.sessionId} status=${n.status} reason=${i.reason}`),B(i))}catch(n){t?.close();let r=n instanceof Error?n.message:String(n);console.error(`[admin-ui] sidebar-session-resume-failed sessionId=${e.sessionId} error=${r}`),B({sessionId:e.sessionId,reason:r})}finally{lt(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}},[k,v,ct]),Xt=(0,y.useCallback)(async e=>{let t=e.slice(0,8);for(let n=1;n<=Ue.length;n++){await new Promise(e=>setTimeout(e,Ue[n-1]));let r=await Q();if(r&&r.some(t=>t.sessionId===e)){console.info(`[admin-ui] sidebar-new-session-converged sessionId=${t} via=retry attempts=${n}`);return}}console.error(`[admin-ui] sidebar-new-session-converge-timeout sessionId=${t}`)},[Q]),Zt=(0,y.useCallback)(async()=>{if(!Et){Dt(!0);try{let e=await k(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({})}),t=await e.json().catch(()=>({})),n=We(e.ok,e.status,t);console.info(`[admin-ui] sidebar-new-session-spawned status=${e.status} outcome=${n.kind} slug=${t.slug??t.bridgeSessionId??`none`}`),n.kind===`navigate`?n.sameOrigin?window.location.assign(n.url):(window.open(n.url,`_blank`),t.sessionId?Xt(t.sessionId):console.error(`[admin-ui] sidebar-new-session-converge-skipped reason=no-session-id`)):e.status===503||n.reason===`claude-auth-dead`?(console.info(`[admin-ui] op=llm-action-blocked action=spawn reason=claude-disconnected`),Fe(!0)):(console.error(`[admin-ui] sidebar-new-session-failed status=${e.status} reason=${n.reason}`),B(n))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-new-session-failed error=${t}`),B({sessionId:null,reason:t})}finally{Dt(!1)}}},[k,Et,Xt]),Qt=(0,y.useCallback)((e,t)=>{e.stopPropagation(),st(t)},[]),$t=(0,y.useCallback)(async(e,t)=>{e.stopPropagation(),yt(t),xt(null),Tt(null),Ct(!0);try{let e=await k(`/api/admin/session-usage?sessionId=${encodeURIComponent(t.sessionId)}`),n=await e.json().catch(()=>({}));e.ok?xt(n):Tt(n.error??`status ${e.status}`)}catch(e){Tt(e instanceof Error?e.message:String(e))}finally{Ct(!1)}},[k]),en=(0,y.useCallback)(async(e,t={})=>{let n=t.refresh??!0;if(K.has(e.sessionId))return!1;tt(t=>{let n=new Set(t);return n.add(e.sessionId),n});try{let t=await k(`/api/admin/session-delete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId})});if(!t.ok){let n=await t.json().catch(()=>({}));return console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} status=${t.status} error=${n.error??`unknown`}`),z({message:`Delete failed: ${n.error??`status ${t.status}`}`,failed:!0}),!1}let r=await t.json();return console.info(`[admin-ui] sidebar-session-delete sessionId=${e.sessionId} live=${e.live} confirmed=true pidKilled=${r.pidKilled??`?`} deleted=${r.deleted??`?`}`),Le(t=>t.filter(t=>t.sessionId!==e.sessionId)),n&&Q(),!0}catch(t){let n=t instanceof Error?t.message:String(t);return console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} error=${n}`),z({message:`Delete failed: ${n}`,failed:!0}),!1}finally{tt(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}},[k,K,Q]),tn=(0,y.useCallback)(e=>{it(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),nn=(0,y.useCallback)(()=>{rt(!1),it(new Set)},[]),rn=(0,y.useCallback)(async()=>{let e=[...J].map(e=>V.find(t=>t.sessionId===e)).filter(e=>!!e),t=e.filter(e=>e.live).length;console.info(`[admin-ui] sidebar-bulk-delete op=start count=${e.length} live=${t}`);let n=(await Promise.all(e.map(e=>en(e,{refresh:!1})))).filter(Boolean).length;console.info(`[admin-ui] sidebar-bulk-delete op=done requested=${e.length} ok=${n} failed=${e.length-n}`),Q(),nn()},[J,V,en,Q,nn]),an=(0,y.useCallback)(async(e,t)=>{if(e.stopPropagation(),!ut.has(t.sessionId)){dt(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await k(`/api/admin/session-stop`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:t.sessionId})});if(!e.ok){let n=await e.json().catch(()=>({}));console.error(`[admin-ui] sidebar-session-stop-failed sessionId=${t.sessionId} status=${e.status} error=${n.error??`unknown`}`),z({message:`Stop failed: ${n.error??`status ${e.status}`}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-stop sessionId=${t.sessionId}`),Q()}catch(e){let n=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-stop-failed sessionId=${t.sessionId} error=${n}`),z({message:`Stop failed: ${n}`,failed:!0})}finally{dt(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[k,ut,Q]),on=(0,y.useCallback)(async(e,t,n)=>{if(e.stopPropagation(),!ft.has(t.sessionId)){pt(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await k(`/api/admin/session-archive`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:t.sessionId,mode:n})});if(!e.ok){let r=await e.json().catch(()=>({})),i=r.detail??r.error??`status ${e.status}`;console.error(`[admin-ui] sidebar-session-archive-failed sessionId=${t.sessionId} mode=${n} status=${e.status} error=${r.error??`unknown`}`),z({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${i}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-archive sessionId=${t.sessionId} mode=${n}`),Q()}catch(e){let r=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-archive-failed sessionId=${t.sessionId} mode=${n} error=${r}`),z({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${r}`,failed:!0})}finally{pt(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[k,ft,Q]),sn=(0,y.useCallback)(async e=>{let t=ht.trim();if(!t){z({message:`Title can’t be empty`,failed:!0});return}if(t.length>He){z({message:`Title too long (max ${He})`,failed:!0});return}_t(!0);try{let n=await k(`/api/admin/session-rename`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId,title:t})});if(!n.ok){let t=await n.json().catch(()=>({})),r=t.reason??t.error??`status ${n.status}`;console.error(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=rejected reason=${r}`),z({message:`Rename failed: ${r}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=ok`),mt(null),Z(``),Q()}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=rejected reason=${n}`),z({message:`Rename failed: ${n}`,failed:!0})}finally{_t(!1)}},[k,ht,Q]);return(0,b.jsxs)(`aside`,{className:`side`,children:[(0,b.jsx)(`div`,{className:`side-new-session-row`,children:(0,b.jsxs)(`button`,{type:`button`,className:`side-new-session`,onClick:Zt,disabled:Et,"aria-busy":Et,children:[(0,b.jsx)(se,{size:14}),(0,b.jsx)(`span`,{children:Et?`Spawning…`:`New session`})]})}),(0,b.jsxs)(`nav`,{className:`side-nav`,children:[(0,b.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=people`),m(),v()},children:[(0,b.jsx)(ve,{size:20,strokeWidth:$}),(0,b.jsx)(`span`,{className:`label`,children:`People`}),(0,b.jsx)(`span`,{className:`kbd`})]}),(0,b.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=agents`),ue(),v()},children:[(0,b.jsx)(fe,{size:20,strokeWidth:$}),(0,b.jsx)(`span`,{className:`label`,children:`Agents`}),(0,b.jsx)(`span`,{className:`kbd`})]}),(0,b.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=projects`),u(),v()},children:[(0,b.jsx)(pe,{size:20,strokeWidth:$}),(0,b.jsx)(`span`,{className:`label`,children:ee().term}),(0,b.jsx)(`span`,{className:`kbd`})]}),(0,b.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=tasks`),h(),v()},children:[(0,b.jsx)(ge,{size:20,strokeWidth:$}),(0,b.jsx)(`span`,{className:`label`,children:`Tasks`}),(0,b.jsx)(`span`,{className:`kbd`})]}),(0,b.jsxs)(`button`,{type:`button`,className:`nav-row${M===`artefacts`?` active`:``}`,onClick:Ut,children:[(0,b.jsx)(ae,{size:20,strokeWidth:$}),(0,b.jsx)(`span`,{className:`label`,children:`Artefacts`}),(0,b.jsx)(`span`,{className:`kbd`})]}),(0,b.jsxs)(`button`,{type:`button`,className:`nav-row${M===`sessions`?` active`:``}`,onClick:Gt,children:[(0,b.jsx)(he,{size:20,strokeWidth:$}),(0,b.jsx)(`span`,{className:`label`,children:`Sessions`}),(0,b.jsx)(`span`,{className:`kbd`})]}),(0,b.jsxs)(`button`,{type:`button`,className:`nav-row${M===`data`?` active`:``}`,onClick:qt,children:[(0,b.jsx)(l,{size:20,strokeWidth:$}),(0,b.jsx)(`span`,{className:`label`,children:`Data`}),(0,b.jsx)(`span`,{className:`kbd`})]}),jt&&le.filter(e=>Vt.get(e).length>0).map(e=>(0,b.jsxs)(`button`,{type:`button`,className:`nav-row${M===`whatsapp`&&Ft===e?` active`:``}`,onClick:()=>Jt(e),children:[(0,b.jsx)(_,{channel:e,size:16}),(0,b.jsx)(`span`,{className:`label`,children:Ht[e]}),(0,b.jsx)(`span`,{className:`kbd`})]},e)),Nt&&(0,b.jsx)(`div`,{className:`nav-row`,style:{color:`var(--text-tertiary)`,cursor:`default`},"aria-disabled":`true`,children:(0,b.jsx)(`span`,{className:`label`,children:Nt})})]}),M===`artefacts`&&(0,b.jsxs)(`div`,{className:`side-list`,children:[(0,b.jsxs)(`div`,{className:`group-head`,children:[(0,b.jsx)(`span`,{children:`Artefacts`}),(0,b.jsxs)(`span`,{className:`group-head-meta`,children:[(0,b.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh artefacts`,"aria-label":`Refresh artefacts`,onClick:Wt,disabled:L,children:(0,b.jsx)(re,{size:12,className:L?`spinning`:void 0})}),(0,b.jsx)(`span`,{children:L?`…`:String(N.length)})]})]}),F&&(0,b.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:F}),P&&!F&&N.length>0&&(()=>{let e=N.filter(e=>e.kind===`agent-template`).length,t=N.length-e;return(0,b.jsx)(`div`,{className:`artefact-filter-chips`,children:[{key:`all`,label:`All`,count:N.length},{key:`agent`,label:`Agents`,count:e},{key:`file`,label:`Files`,count:t}].map(e=>(0,b.jsxs)(`button`,{type:`button`,className:`artefact-filter-chip${De===e.key?` active`:``}`,onClick:()=>Oe(e.key),disabled:e.count===0&&e.key!==`all`,children:[e.label,(0,b.jsx)(`span`,{className:`artefact-filter-chip-count`,children:e.count})]},e.key))})})(),P&&!F&&N.length===0&&(0,b.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No artefacts yet`}),N.filter(e=>De===`all`?!0:De===`agent`?e.kind===`agent-template`:e.kind!==`agent-template`).map(e=>{let t=e.kind===`agent-template`,n=t?fe:ae,r=Ge(e.updatedAt),i=e.downloadPath!==null;return(0,b.jsxs)(`button`,{type:`button`,className:`conv`,onClick:()=>Lt(e),disabled:!i,style:i?void 0:{cursor:`default`},title:i?`Download ${e.name}`:`${e.name} can’t be downloaded`,children:[(0,b.jsx)(n,{size:14,className:`conv-icon`,"data-kind":t?`agent`:`file`,"aria-label":t?`agent template`:`file`}),(0,b.jsxs)(`span`,{className:`conv-stack`,children:[(0,b.jsx)(`span`,{className:`conv-name-line`,children:(0,b.jsx)(`span`,{className:`conv-name`,children:e.name})}),r&&(0,b.jsx)(`span`,{className:`conv-timestamp`,children:r})]}),i&&(0,b.jsx)(ie,{size:12,className:`conv-rc-icon`,"aria-hidden":`true`})]},e.id)})]}),M===`sessions`&&(()=>{let e=V.filter(e=>W?!0:!e.isSubagent).filter(e=>G?!0:!e.archived),t=V.some(e=>e.isSubagent),n=V.some(e=>e.archived);return(0,b.jsxs)(`div`,{className:`side-list`,children:[(0,b.jsxs)(`div`,{className:`group-head`,children:[(0,b.jsx)(`span`,{children:`Sessions`}),(0,b.jsxs)(`span`,{className:`group-head-meta`,children:[(0,b.jsx)(`button`,{type:`button`,className:`group-head-select${q?` active`:``}`,"aria-pressed":q,title:q?`Exit select mode`:`Select multiple sessions to delete`,onClick:()=>{rt(e=>!e),it(new Set),mt(null),Z(``)},children:`Select`}),(0,b.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh sessions`,"aria-label":`Refresh sessions`,onClick:Kt,disabled:Ke,children:(0,b.jsx)(re,{size:12,className:Ke?`spinning`:void 0})}),(0,b.jsx)(`span`,{children:Ke?`…`:String(e.length)})]})]}),q&&(0,b.jsxs)(`div`,{className:`session-select-bar`,children:[(0,b.jsxs)(`span`,{className:`session-select-count`,children:[J.size,` selected`]}),(0,b.jsxs)(`button`,{type:`button`,className:`session-select-delete`,disabled:J.size===0,onClick:()=>ot(!0),children:[`Delete `,J.size]}),(0,b.jsx)(`button`,{type:`button`,className:`session-select-cancel`,onClick:nn,children:`Cancel`})]}),$e&&(0,b.jsx)(`div`,{className:`side-account-id`,title:`This install's accountId. The first 8 characters match the truncated UUID label on the live Remote Control daemon entry in claude.ai/code.`,children:(0,b.jsx)(`code`,{children:$e})}),(t||n)&&(0,b.jsxs)(`div`,{className:`artefact-filter-chips`,children:[t&&(0,b.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${W?` active`:``}`,"aria-pressed":W,onClick:()=>Ze(e=>!e),title:W?`Hide subagent sessions`:`Show subagent sessions`,children:`Subagents`}),n&&(0,b.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${G?` active`:``}`,"aria-pressed":G,onClick:()=>Qe(e=>!e),title:G?`Hide archived sessions`:`Show archived sessions`,children:`Archived`})]}),ze&&(0,b.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:ze}),U&&!ze&&e.length===0&&(0,b.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No sessions yet`}),e.map(e=>{let t=Ge(e.startedAt),n=ct.has(e.sessionId),r=K.has(e.sessionId),i=ut.has(e.sessionId),a=ft.has(e.sessionId),o=n||r||i||a,s=()=>{window.location.assign(`/chat?session=${e.sessionId}`)},l=[{key:`open`,label:`Resume session ${e.title} in claude.ai/code`,menuLabel:`Resume in claude.ai/code`,title:`Resume in a fresh local Remote Control PTY`,icon:(0,b.jsx)(f,{size:12}),busy:n,onClick:()=>{Yt(e)}},{key:`message`,label:`Open session ${e.title} in admin webchat`,menuLabel:`Open in webchat`,title:`Open in admin webchat (/chat) — sending resumes this session`,icon:(0,b.jsx)(T,{size:12}),onClick:()=>{s()}},{key:`usage`,label:`Usage and cost for session ${e.title}`,menuLabel:`Usage & cost`,title:`Per-day active time, tokens, and estimated GBP cost`,icon:(0,b.jsx)(me,{size:12}),onClick:t=>{$t(t,e)}},...e.live?[{key:`stop`,label:`Stop session ${e.title}`,menuLabel:`Stop`,title:`Stop session process (keeps the conversation, can resume later)`,icon:(0,b.jsx)(p,{size:12}),busy:i,onClick:t=>{an(t,e)}}]:[],e.archived?{key:`unarchive`,label:`Unarchive session ${e.title}`,menuLabel:`Unarchive`,title:`Unarchive (move back to the active list)`,icon:(0,b.jsx)(C,{size:12}),busy:a,onClick:t=>{on(t,e,`unarchive`)}}:{key:`archive`,label:`Archive session ${e.title}`,menuLabel:`Archive`,title:`Archive (hide from the list, keeps the conversation resumable)`,icon:(0,b.jsx)(w,{size:12}),busy:a,onClick:t=>{on(t,e,`archive`)}},{key:`rename`,label:`Rename session ${e.title}`,menuLabel:`Rename`,title:`Rename this session`,icon:(0,b.jsx)(c,{size:12}),busy:gt&&X===e.sessionId,onClick:t=>{t.stopPropagation(),mt(e.sessionId),Z(e.personName??e.title)}},{key:`delete`,label:`Delete session ${e.title}`,menuLabel:`Delete`,title:`Delete session (stops the process, removes the conversation)`,icon:(0,b.jsx)(d,{size:12}),danger:!0,busy:r,onClick:t=>{Qt(t,e)}},be({sessionId:e.sessionId,model:e.model??null,title:e.personName??e.title})],u=e.channel===`whatsapp`?` conv-channel-whatsapp`:e.channel===`telegram`?` conv-channel-telegram`:``,m=e.channel===`whatsapp`||e.channel===`telegram`||e.channel===`webchat`,h=le.includes(e.channel??``)&&e.senderId&&e.titleSource===`prefix`?oe({operatorName:e.personName??null,whatsappName:null,senderId:e.senderId,title:e.title}):e.personName??e.title;return(0,b.jsxs)(`div`,{ref:t=>{let n=nt.current;t?n.set(e.sessionId,t):n.delete(e.sessionId)},className:`conv conv-with-actions${u}${e.sessionId===H?` active`:``}`,children:[(0,b.jsxs)(`div`,{className:`conv-main-static conv-main-clickable`,role:`button`,tabIndex:0,"aria-label":`Open ${h} in webchat`,onClick:()=>{if(X!==e.sessionId){if(q){tn(e.sessionId);return}s()}},onKeyDown:t=>{X!==e.sessionId&&(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),q?tn(e.sessionId):s())},children:[q&&(0,b.jsx)(`input`,{type:`checkbox`,className:`conv-select-check`,checked:J.has(e.sessionId),"aria-label":`Select ${h}`,onChange:()=>tn(e.sessionId),onClick:e=>e.stopPropagation()}),(0,b.jsx)(`span`,{className:`conv-live-dot`,"data-live":e.live?`1`:`0`,"aria-label":e.live?`live session`:`ended session`}),(0,b.jsxs)(`span`,{className:`conv-stack`,children:[(0,b.jsxs)(`span`,{className:`conv-name-line`,children:[m&&(0,b.jsx)(ne,{channel:e.channel,size:13}),X===e.sessionId?(0,b.jsx)(`input`,{className:`conv-name conv-name-edit`,autoFocus:!0,onFocus:e=>e.currentTarget.select(),value:ht,disabled:gt,"aria-label":`New title for session ${e.title}`,onChange:e=>Z(e.target.value),onClick:e=>e.stopPropagation(),onKeyDown:t=>{t.key===`Enter`?(t.preventDefault(),sn(e)):t.key===`Escape`&&(t.preventDefault(),mt(null),Z(``))},onBlur:()=>{X===e.sessionId&&!gt&&(mt(null),Z(``))}}):(0,b.jsx)(`span`,{className:`conv-name`,title:h,children:h})]}),(0,b.jsxs)(`span`,{className:`conv-timestamp`,children:[(0,b.jsx)(`code`,{className:`conv-session-id`,title:`First 8 characters of this session's id — distinguishes rows with identical auto-titles. The resume/delete buttons act on the full id.`,children:e.sessionId.slice(0,8)}),t&&(0,b.jsxs)(`span`,{children:[` · `,t]})]})]})]}),!q&&(0,b.jsx)(Se,{actions:l,disabled:o})]},e.sessionId)})]})})(),M===`whatsapp`&&(0,b.jsxs)(`div`,{className:`side-list`,children:[(0,b.jsxs)(`div`,{className:`group-head`,children:[(0,b.jsx)(`span`,{children:Ht[Ft]}),(0,b.jsxs)(`span`,{className:`group-head-meta`,children:[(0,b.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh conversations`,"aria-label":`Refresh conversations`,onClick:()=>{Bt()},children:(0,b.jsx)(re,{size:12})}),(0,b.jsx)(`span`,{children:String(Vt.get(Ft).length)})]})]}),Vt.get(Ft).map(e=>{let t=Ge(e.lastMessageAt),n=te(e);return(0,b.jsxs)(`div`,{className:`conv conv-with-actions${e.source===`store`?e.scope===`admin`?` conv-scope-admin`:` conv-scope-public`:``}${de===n?` active`:``}`,children:[(0,b.jsxs)(`button`,{type:`button`,className:`conv-main-static conv-main-btn`,onClick:()=>{S(e),v()},title:e.title,children:[(0,b.jsx)(_,{channel:e.channel,size:14}),(0,b.jsxs)(`span`,{className:`conv-stack`,children:[(0,b.jsx)(`span`,{className:`conv-name-line`,children:(0,b.jsx)(`span`,{className:`conv-name`,children:oe(e)})}),t&&(0,b.jsx)(`span`,{className:`conv-timestamp`,children:t})]})]}),e.source===`session`&&(0,b.jsx)(Se,{actions:[be({sessionId:e.sessionId,model:e.model,title:e.title})],disabled:!1})]},n)})]}),(0,b.jsx)(Xe,{}),(0,b.jsxs)(`div`,{className:`side-foot`,children:[(0,b.jsx)(`div`,{className:`avatar`,children:o?(0,b.jsx)(`img`,{src:o,alt:A}):j}),(0,b.jsxs)(`div`,{className:`who`,children:[(0,b.jsx)(`span`,{className:`name`,children:A}),(0,b.jsx)(`span`,{className:`role`,children:i??`operator`})]})]}),R&&(0,b.jsx)(`div`,{className:`copy-toast${R.failed?` copy-toast-failed`:``}`,role:`status`,children:R.message}),(0,b.jsx)(Pe,{error:Ae,onClose:()=>B(null)}),(0,b.jsx)(Ie,{open:Ne,onConnect:()=>{Fe(!1),r?.()},onClose:()=>Fe(!1)}),(0,b.jsx)(je,{target:Y,anchorEl:Y?nt.current.get(Y.sessionId)??null:null,onCancel:()=>st(null),onConfirm:()=>{let e=Y;st(null),e&&en(e)}},Y?.sessionId??`none`),(0,b.jsx)(Me,{open:at,count:J.size,liveCount:V.filter(e=>J.has(e.sessionId)&&e.live).length,onConfirm:()=>{ot(!1),rn()},onCancel:()=>ot(!1)}),(0,b.jsx)(Be,{show:vt!==null,onClose:()=>{yt(null),xt(null),Tt(null)},sessionId:vt?.sessionId??null,summary:bt,loading:St,error:wt})]})}var qe=5e3,Je=3e4,Ye=3e4;function Xe(){let[e,t]=(0,y.useState)(null);if((0,y.useEffect)(()=>{let e=!1,n=null;async function r(){try{let n=await fetch(`/api/admin/system-stats`);if(!n.ok){console.error(`[admin-ui] system-stats-fetch-failed status=${n.status}`);return}let r=await n.json();e||t(r)}catch(e){console.error(`[admin-ui] system-stats-fetch-failed reason=${e instanceof Error?e.message:String(e)}`)}}function i(){n===null&&(r(),n=setInterval(()=>{r()},qe))}function a(){n!==null&&(clearInterval(n),n=null)}function o(){document.hidden?a():i()}return document.hidden||i(),document.addEventListener(`visibilitychange`,o),()=>{e=!0,a(),document.removeEventListener(`visibilitychange`,o)}},[]),!e||e.platform===`darwin`)return null;let n=e.cpuPct,r=e.memUsedPct,i=n!==null&&n>=.9,a=n!==null&&n>=.98,o=r!==null&&r>=.9,s=r!==null&&r>=.98,c=i||o,l=a||s,u=e=>e===null?`—`:`${Math.round(e*100)}%`,d=e=>{if(e===null)return{width:`0%`,background:`var(--text-tertiary)`};let t=Math.min(1,Math.max(0,e)),n=Math.round(140*(1-t));return{width:`${Math.round(t*100)}%`,background:`hsl(${n}, 65%, 45%)`}},f=[`system-stats`];return c&&f.push(`system-stats--warn`),l&&f.push(`system-stats--crit`),(0,b.jsxs)(`div`,{className:f.join(` `),role:`status`,"aria-label":`host CPU and RAM`,children:[(0,b.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,b.jsxs)(`span`,{className:i?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`CPU `,u(n)]}),(0,b.jsx)(`div`,{className:`system-stats__bar`,children:(0,b.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(n)})})]}),(0,b.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,b.jsxs)(`span`,{className:o?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`RAM `,u(r)]}),(0,b.jsx)(`div`,{className:`system-stats__bar`,children:(0,b.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(r)})})]})]})}var W=`admin-sidebar-collapsed`,Ze=`admin-sidebar-drawer-open`;function G(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(W)===`1`}catch{return!1}}function Qe(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(W,`1`):window.sessionStorage.removeItem(W)}catch{}}function $e(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(Ze)===`1`}catch{return!1}}function et(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(Ze,`1`):window.sessionStorage.removeItem(Ze)}catch{}}function K(e){let[t,n]=(0,y.useState)(()=>typeof window>`u`||typeof window.matchMedia!=`function`?!1:window.matchMedia(e).matches);return(0,y.useEffect)(()=>{if(typeof window>`u`||typeof window.matchMedia!=`function`)return;let t=window.matchMedia(e),r=()=>n(t.matches);return r(),t.addEventListener(`change`,r),()=>t.removeEventListener(`change`,r)},[e]),t}var tt=720;function nt(e,t){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?wa=${encodeURIComponent(t.remoteJid??``)}&acct=${encodeURIComponent(t.accountId??``)}`}}function q(e){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?data=1`}}function rt(e,t){if(e!==`/`)return null;let n=new URLSearchParams(t),r=n.get(`wa`),i=n.get(`acct`);return!r||!i?null:{sessionId:``,projectDir:``,title:``,senderId:null,startedAt:``,channel:`whatsapp`,role:`public`,operatorName:null,whatsappName:null,lastMessageAt:null,modelGated:!1,model:null,source:`store`,accountId:i,remoteJid:r}}function J(e,t){return e===`/`?new URLSearchParams(t).has(`data`):!1}function it(e,t){return t===`operator`&&e===`chat`||e===`dashboard`?`/`:e===`data`?`/data`:e===`graph`?`/graph`:e===`calendar`?`/calendar`:e===`chat`?`/chat`:e===`activity`?`/activity`:`/browser`}function at(e){let{cacheKey:t,businessName:n,variant:r=`admin`,onLogout:i,onDisconnect:a,disconnecting:o,claudeConnected:s,onConnectClaude:c,userName:l,userAvatar:d,role:f,onOpenConversations:p,children:h,footer:g}=e,{subAccounts:ne,activeAccountId:re,switching:ie,switchAccount:ae,refreshAccounts:oe}=m(t),[se,ce]=(0,y.useState)(!0);(0,y.useEffect)(()=>{if(s!==void 0||r!==`admin`)return;let e=!1,t=async()=>{try{let t=await fetch(`/api/health`);if(!t.ok)return;let n=await t.json();e||ce(n.auth_status!==`dead`&&n.auth_status!==`missing`)}catch{}};t();let n=setInterval(t,6e4);return()=>{e=!0,clearInterval(n)}},[s,r]);let le=s??se,ue=c??(()=>{window.location.assign(`/?connect=claude`)}),[_,v]=(0,y.useState)(()=>G()),[x,de]=(0,y.useState)(()=>$e()),S=K(`(max-width: ${tt}px)`),[C,w]=(0,y.useState)(()=>typeof window>`u`||J(window.location.pathname,window.location.search)?null:rt(window.location.pathname,window.location.search)),[fe]=(0,y.useState)(()=>C!==null),[pe,me]=(0,y.useState)(()=>typeof window>`u`?!1:J(window.location.pathname,window.location.search)),[he]=(0,y.useState)(()=>pe),ge=(0,y.useCallback)(e=>{Qe(e),v(e)},[]),T=(0,y.useCallback)(e=>{et(e),de(e)},[]);(0,y.useEffect)(()=>{if(typeof window>`u`)return;let e=window.location?.pathname??``;console.info(`[admin-ui] shell-mount route=${e} variant=${r} sidebar=${r===`operator`?`none`:`present`} collapsed=${_} drawer=${x}`)},[]),(0,y.useEffect)(()=>{typeof window>`u`||!C||(console.info(`[admin-ui] wa-hydrate route=/ remoteJid=${C.remoteJid??``}`),window.history.replaceState(null,``,`/`))},[]),(0,y.useEffect)(()=>{typeof window>`u`||!pe||(console.info(`[admin-ui] data-hydrate route=/`),window.history.replaceState(null,``,`/`))},[]);let _e=(0,y.useCallback)(e=>{if(me(!1),e===null){w(null);return}let t=typeof window<`u`?window.location.pathname:`/`,n=nt(t,e);console.info(`[admin-ui] wa-open route=${t} via=${n.via} sessionId=${e.sessionId.slice(0,8)}`),n.via===`in-place`?w(e):window.location.href=n.href},[]),ve=(0,y.useCallback)(()=>{let e=typeof window<`u`?window.location.pathname:`/`,t=q(e);if(console.info(`[admin-ui] data-open route=${e} via=${t.via}`),t.via===`navigate`){window.location.href=t.href;return}w(null),me(!0)},[]),E=S?x:!_,D=(0,y.useCallback)(()=>{if(!(typeof window>`u`))if(window.matchMedia(`(max-width: ${tt}px)`).matches){let e=x;console.info(`[admin-ui] header-sidebar-toggle from=${e?`open`:`closed`} mode=drawer`),T(!e)}else{let e=_;console.info(`[admin-ui] header-sidebar-toggle from=${e?`closed`:`open`} mode=collapse`),ge(!e)}},[_,x,ge,T]),O=(0,y.useCallback)(e=>{let t=it(e,r);console.info(`[admin-ui] header-menu-nav target=${e} dest=${t}`),window.location.href=t},[r]),ye={collapsed:_,mobileDrawerOpen:x,sidebarOpen:E,onToggleSidebar:D,setMobileDrawerOpen:T,selectedWhatsapp:C,onClearWhatsapp:()=>w(null),dataOpen:pe};return r===`operator`?(0,b.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,b.jsx)(u,{businessName:n,variant:r,onNavigate:O,onOpenConversations:p,onToggleSidebar:D,sidebarOpen:E,onLogout:i,onDisconnect:a,disconnecting:o,cacheKey:t,subAccounts:ne,activeAccountId:re,switchingAccount:ie,onSwitchAccount:ae,refreshAccounts:oe}),(0,b.jsx)(`div`,{className:`platform platform-operator`,children:typeof h==`function`?h(ye):h}),g]}):(0,b.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,b.jsx)(u,{businessName:n,variant:r,onNavigate:O,onOpenConversations:p,onToggleSidebar:D,sidebarOpen:E,onLogout:i,onDisconnect:a,disconnecting:o,claudeConnected:le,onConnectClaude:ue,cacheKey:t,subAccounts:ne,activeAccountId:re,switchingAccount:ie,onSwitchAccount:ae,refreshAccounts:oe}),(0,b.jsxs)(`div`,{className:`platform${x?` menu-open`:``}${_?` sidebar-collapsed`:``}`,"data-artefact":`closed`,children:[(0,b.jsx)(Ke,{businessName:n,cacheKey:t,onConnectClaude:ue,role:f??null,userName:l,userAvatar:d??null,onSelectProjects:()=>{window.location.href=`/graph?label=${ee().label}`},onSelectPeople:()=>{window.location.href=`/graph?label=Person`},onSelectTasks:()=>{window.location.href=`/tasks`},onSelectAgents:()=>{window.location.href=`/graph?label=Agent`},onCloseMobileDrawer:()=>T(!1),collapsed:_,mobileDrawerOpen:x,selectedWhatsappId:C?te(C):null,onSelectWhatsappConversation:_e,initialWhatsappSurface:fe,onSelectData:ve,onCloseData:()=>me(!1),initialDataSurface:he}),!S&&(0,b.jsx)(k,{}),typeof h==`function`?h(ye):h]}),x&&(0,b.jsx)(`div`,{className:`sidebar-backdrop menu-open`,"aria-hidden":`true`,onClick:()=>T(!1)}),g]})}export{C as _,Fe as a,j as c,ve as d,_e as f,w as g,fe as h,Ie as i,Te as l,me as m,K as n,M as o,ge as p,We as r,A as s,at as t,N as u,S as v,v as y};
@@ -0,0 +1 @@
1
+ import{S as e}from"./useSubAccountSwitcher-CvjWJSGv.js";var t=e();function n({checked:e,onChange:n,label:r,disabled:i}){return(0,t.jsxs)(`label`,{className:`maxy-checkbox${i?` maxy-checkbox--disabled`:``}`,children:[(0,t.jsx)(`input`,{type:`checkbox`,checked:e,onChange:e=>n(e.target.checked),disabled:i}),(0,t.jsx)(`span`,{className:`maxy-checkbox__box`,children:`✱`}),r&&(0,t.jsx)(`span`,{className:`maxy-checkbox__label`,children:r})]})}export{n as t};
@@ -0,0 +1 @@
1
+ import{o as e}from"./chunk-TPjIAO9U.js";import{D as t,S as n,T as r,_ as i,d as a,g as o,r as s,w as c}from"./useSubAccountSwitcher-CvjWJSGv.js";import{t as l,y as u}from"./AdminShell-5nHOAzXO.js";import"./useSelectionMode-BaD-ZZRk.js";import{t as d}from"./triangle-alert-ClS81-CU.js";var f=i(`arrow-down`,[[`path`,{d:`M12 5v14`,key:`s699le`}],[`path`,{d:`m19 12-7 7-7-7`,key:`1idqje`}]]),p=i(`arrow-up`,[[`path`,{d:`m5 12 7-7 7 7`,key:`hav0vg`}],[`path`,{d:`M12 19V5`,key:`x0mq9r`}]]),m=r(),h=e(t(),1),g=n(),_=`maxy-admin-session-key`;function v(e){switch(e.costUnavailable){case`metering-failed`:return`Cost could not be calculated: ${e.meteringError??`the transcript could not be read`}`;case`model-not-priced`:return`No published price for this model, so cost cannot be estimated.`;case`no-transcript`:return`This session has no transcript yet, so there is nothing to cost.`;default:return}}var y=[{key:`accountId`,label:`Account`,numeric:!1,help:`The business this session belongs to. "untagged" means the session records no account.`},{key:`title`,label:`Session`,numeric:!1,help:`The conversation name, or its short id when it has none yet.`},{key:`model`,label:`Model`,numeric:!1,help:`The model that answered the most recent turn.`},{key:`status`,label:`Status`,numeric:!1,help:`What the process is doing right now.`},{key:`ageMs`,label:`Age`,numeric:!0,help:`How long ago this conversation started.`},{key:`idleMs`,label:`Idle`,numeric:!0,help:`Time since the last message. A long idle on a live session is memory being held for nothing.`},{key:`turnCount`,label:`Turns`,numeric:!0,help:`Messages exchanged. A trailing + means the count is a minimum — the conversation is too long to count exactly.`},{key:`rssKb`,label:`RSS`,numeric:!0,help:`Memory held by this session and all its helper processes together.`},{key:`cpuPct`,label:`CPU`,numeric:!0,help:`Share of one processor core used since the last reading. Can exceed 100% because a session runs many processes at once.`},{key:`usedTokens`,label:`Tokens`,numeric:!0,help:`Size of the conversation the model currently reads back on every turn.`},{key:`costGbp`,label:`Cost`,numeric:!0,help:`Estimated spend on this conversation so far, at published prices for its model.`}],b=[`idleMs`,`turnCount`,`rssKb`,`cpuPct`];function x(e,t){let n=t?.[e];return n&&n.trim()!==``?n:e.slice(0,8)}var S=`—`;function C(e){if(e===null||!Number.isFinite(e)||e<0)return S;let t=Math.floor(e/1e3);if(t<60)return`${t}s`;let n=Math.floor(t/60);if(n<60)return`${n}m`;let r=Math.floor(n/60);return r<24?`${r}h ${n%60}m`:`${Math.floor(r/24)}d ${r%24}h`}function w(e){return e===null||!Number.isFinite(e)?S:`${Math.round(e/1024)} MB`}function T(e){return e===null||!Number.isFinite(e)?S:`${e.toFixed(1)}%`}function E(e){return e===null||!Number.isFinite(e)?S:e<1e3?String(e):e<1e6?`${(e/1e3).toFixed(1)}k`:`${(e/1e6).toFixed(2)}M`}function D(e){return e===null||!Number.isFinite(e)?S:`£${e.toFixed(2)}`}function O(e,t,n,r){let i=e[n],a=t[n];return i===null&&a===null?0:i===null?1:a===null?-1:typeof i==`number`&&typeof a==`number`?(i-a)*r:String(i).localeCompare(String(a))*r}function k({adminFetch:e}){let[t,n]=(0,h.useState)(null),[r,i]=(0,h.useState)(null),[s,c]=(0,h.useState)(!1),[l,u]=(0,h.useState)(`cpuPct`),[m,_]=(0,h.useState)(-1),k=(0,h.useRef)(!1),A=(0,h.useCallback)(async()=>{if(!k.current){k.current=!0;try{let t=await e(`/api/admin/activity`);if(t.status===403){i(`This view is available to the house account only.`),c(!0);return}if(!t.ok){i(`The session manager did not answer (status ${t.status}).`),c(!0);return}n(await t.json()),i(null)}catch(e){i(e instanceof Error?e.message:String(e))}finally{c(!0),k.current=!1}}},[e]);(0,h.useEffect)(()=>{A();let e=setInterval(()=>void A(),15e3);return()=>clearInterval(e)},[A]);let j=(0,h.useMemo)(()=>t?[...t.rows].sort((e,t)=>O(e,t,l,m)):[],[t,l,m]),M=e=>{e===l?_(e=>e===1?-1:1):(u(e),_(-1))};if(!s)return(0,g.jsxs)(`div`,{className:`activity-loading`,children:[(0,g.jsx)(a,{size:18,className:`spin`}),` Loading…`]});if(r)return(0,g.jsx)(`div`,{className:`activity-empty`,children:r});if(!t)return(0,g.jsx)(`div`,{className:`activity-empty`,children:`No response.`});let{accounts:N,census:P,censusAgeMs:F}=t,I=N.onDisk!==null&&N.onDisk>N.valid;return(0,g.jsxs)(`div`,{className:`activity-body`,children:[(0,g.jsxs)(`div`,{className:`activity-head`,children:[(0,g.jsxs)(`span`,{className:`activity-title`,children:[(0,g.jsx)(o,{size:16}),` Live sessions`]}),(0,g.jsxs)(`span`,{className:`activity-meta`,children:[j.length,` live · `,N.valid,` accounts`,N.untaggedCount>0?` · ${N.untaggedCount} untagged`:``]})]}),(0,g.jsx)(`div`,{className:`activity-census`,children:P===null?`No census collected yet, so memory and CPU are unavailable.`:`Census taken ${C(F)} ago · ${P.cpuNull} of ${P.live} without a CPU reading`}),I&&(0,g.jsxs)(`div`,{className:`activity-warning`,children:[(0,g.jsx)(d,{size:14}),` `,N.onDisk,` account folders on disk but only`,` `,N.valid,` are readable. Sessions belonging to the rest cannot be attributed.`]}),j.length===0?(0,g.jsx)(`div`,{className:`activity-empty`,children:`No sessions are running.`}):(0,g.jsx)(`div`,{className:`activity-scroll`,children:(0,g.jsxs)(`table`,{className:`activity-table`,children:[(0,g.jsx)(`thead`,{children:(0,g.jsx)(`tr`,{children:y.map(e=>(0,g.jsx)(`th`,{className:e.numeric?`activity-th activity-num`:`activity-th`,title:e.help,children:(0,g.jsxs)(`button`,{type:`button`,className:`activity-sort`,onClick:()=>M(e.key),children:[e.label,l===e.key&&(m===1?(0,g.jsx)(p,{size:11}):(0,g.jsx)(f,{size:11}))]})},e.key))})}),(0,g.jsx)(`tbody`,{children:j.map(e=>(0,g.jsxs)(`tr`,{className:`activity-row`,children:[(0,g.jsx)(`td`,{className:`activity-td`,title:e.accountId??void 0,children:e.accountId===null?(0,g.jsx)(`span`,{className:`activity-untagged`,title:`This session records no account, so it cannot be attributed to a business.`,children:`untagged`}):x(e.accountId,N.names)}),(0,g.jsx)(`td`,{className:`activity-td`,children:e.title??e.sessionId.slice(0,8)}),(0,g.jsx)(`td`,{className:`activity-td`,children:e.model??S}),(0,g.jsx)(`td`,{className:`activity-td`,children:e.status??S}),(0,g.jsx)(`td`,{className:`activity-td activity-num`,children:C(e.ageMs)}),(0,g.jsx)(`td`,{className:`activity-td activity-num`,children:C(e.idleMs)}),(0,g.jsx)(`td`,{className:`activity-td activity-num`,children:e.turnCount===null?S:`${e.turnCount}${e.turnCountCapped?`+`:``}`}),(0,g.jsx)(`td`,{className:`activity-td activity-num`,children:w(e.rssKb)}),(0,g.jsx)(`td`,{className:`activity-td activity-num`,children:T(e.cpuPct)}),(0,g.jsx)(`td`,{className:`activity-td activity-num`,children:E(e.usedTokens)}),(0,g.jsx)(`td`,{className:`activity-td activity-num`,title:v(e),children:D(e.costGbp)})]},e.sessionId))})]})}),j.length>0&&(0,g.jsxs)(`dl`,{className:`activity-legend`,children:[b.map(e=>{let t=y.find(t=>t.key===e);return(0,g.jsxs)(`div`,{className:`activity-legend-item`,children:[(0,g.jsx)(`dt`,{className:`activity-legend-term`,children:t.label}),(0,g.jsx)(`dd`,{className:`activity-legend-def`,children:t.help})]},e)}),(0,g.jsxs)(`div`,{className:`activity-legend-item`,children:[(0,g.jsx)(`dt`,{className:`activity-legend-term`,children:S}),(0,g.jsx)(`dd`,{className:`activity-legend-def`,children:`Not measured. It does not mean zero — hover the cell for the reason where one exists.`})]})]})]})}function A({cacheKey:e}){let{adminFetch:t}=c({initialCacheKey:e,surface:`activity`});return(0,g.jsx)(k,{adminFetch:t})}function j(){let[e,t]=(0,h.useState)(null),[n,r]=(0,h.useState)(!1),[i,o]=(0,h.useState)(void 0),[c,d]=(0,h.useState)(null),[f,p]=(0,h.useState)(null),[m,v]=(0,h.useState)(null),[y,b]=(0,h.useState)(null);(0,h.useEffect)(()=>{let e=!1,n=null;try{n=sessionStorage.getItem(_)}catch{}if(!n){t(null),r(!0);return}return fetch(`/api/admin/session?session_key=${encodeURIComponent(n)}`).then(async i=>{if(!e){if(i.status===401){try{sessionStorage.removeItem(_)}catch{}window.location.href=`/`;return}if(i.ok)try{let e=await i.json();typeof e.businessName==`string`&&o(e.businessName),e.sessionId!==void 0&&d(e.sessionId??null),p(e.role??null),v(e.userName===void 0?null:e.userName),b(e.avatar??null)}catch{}t(n),r(!0)}}).catch(()=>{e||(t(n),r(!0))}),()=>{e=!0}},[]);let x=(0,h.useCallback)(()=>{try{sessionStorage.removeItem(_)}catch{}window.location.href=`/`},[]),[S,C]=(0,h.useState)(!1),w=(0,h.useCallback)(async()=>{C(!0);try{let e=await u();if(e){try{sessionStorage.removeItem(_)}catch{}window.location.href=`/`}return e}finally{C(!1)}},[]);return n?e?(0,g.jsx)(s,{cacheKey:e,surface:`activity`,onSessionExpired:({code:e,path:t})=>{console.warn(`[admin-auth] outcome=session-expired-redirect code=${e} path=${t} surface=activity`);try{sessionStorage.removeItem(_)}catch{}window.location.href=`/`},children:(0,g.jsx)(l,{cacheKey:e,businessName:i,sessionId:c,onLogout:x,onDisconnect:w,disconnecting:S,userName:m,userAvatar:y,role:f,children:(0,g.jsx)(A,{cacheKey:e})})}):(0,g.jsx)(`div`,{className:`activity-page`,children:(0,g.jsxs)(`div`,{className:`activity-empty`,children:[(0,g.jsx)(`p`,{children:`You are not signed in.`}),(0,g.jsxs)(`p`,{children:[`Open the `,(0,g.jsx)(`a`,{href:`/`,className:`activity-link`,children:`main admin page`}),` and log in, then return here.`]})]})}):(0,g.jsx)(`div`,{className:`activity-page`,children:(0,g.jsxs)(`div`,{className:`activity-loading`,children:[(0,g.jsx)(a,{size:18,className:`spin`}),` Loading…`]})})}(0,m.createRoot)(document.getElementById(`root`)).render((0,g.jsx)(j,{}));