@rubytech/create-realagent-code 0.1.397 → 0.1.400
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +22 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/graph.md +15 -0
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/connect-timeout-observability.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/connect-timeout-observability.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/connect-timeout-observability.test.js +123 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/connect-timeout-observability.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +9 -0
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js +36 -12
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +18 -1
- package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -1
- package/payload/platform/plugins/memory/references/schema-estate-agent.md +2 -0
- package/payload/platform/plugins/web-designer/.claude-plugin/plugin.json +8 -0
- package/payload/platform/plugins/web-designer/PLUGIN.md +46 -0
- package/payload/platform/plugins/web-designer/bin/resolve-cf.sh +56 -0
- package/payload/platform/plugins/web-designer/skills/brand-extract/SKILL.md +86 -0
- package/payload/platform/plugins/web-designer/skills/socials/SKILL.md +139 -0
- package/payload/platform/plugins/web-designer/skills/socials/references/pii-strip.md +64 -0
- package/payload/platform/plugins/web-designer/skills/socials/references/sources.md +66 -0
- package/payload/platform/plugins/web-designer/skills/socials/templates/og.html +92 -0
- package/payload/platform/plugins/web-designer/skills/socials/templates/social-posts.md +46 -0
- package/payload/platform/plugins/web-designer/skills/socials/templates/socials.html +87 -0
- package/payload/platform/plugins/web-designer/skills/web-design/SKILL.md +98 -0
- package/payload/platform/plugins/web-designer/skills/web-design/references/deploy.md +59 -0
- package/payload/platform/plugins/web-designer/skills/web-design/references/e-sign.md +39 -0
- package/payload/platform/plugins/web-designer/skills/web-design/references/gating.md +55 -0
- package/payload/platform/plugins/web-designer/skills/web-design/references/placeholders.md +110 -0
- package/payload/platform/plugins/web-designer/skills/web-design/references/sections.md +52 -0
- package/payload/platform/plugins/web-designer/skills/web-design/templates/index.html +1004 -0
- package/payload/platform/plugins/web-designer/skills/web-design/templates/llms.txt +32 -0
- package/payload/platform/plugins/web-designer/skills/web-intake/SKILL.md +107 -0
- package/payload/platform/plugins/web-designer/skills/web-intake/references/intake.md +103 -0
- package/payload/platform/plugins/whatsapp/PLUGIN.md +7 -1
- package/payload/platform/scripts/merge-whatsapp-split-conversations.mjs +264 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +22 -6
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/premium-plugins/real-agent/agents/listing-curator.md +23 -23
- package/payload/premium-plugins/real-agent/docs/references/real-agent-architecture.md +4 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-brochure/SKILL.md +1 -1
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-brochure/references/build.md +2 -2
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-brochure/references/images.md +1 -1
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-brochure/references/index-landing.md +4 -0
- package/payload/server/public/assets/{AdminLoginScreens-o2gMrtKC.js → AdminLoginScreens-rlk263u9.js} +1 -1
- package/payload/server/public/assets/{AdminShell-C7DK87-C.js → AdminShell-C5vWTy2n.js} +1 -1
- package/payload/server/public/assets/{Checkbox-DJyosZ-i.js → Checkbox-Chz6bfy-.js} +1 -1
- package/payload/server/public/assets/{Transcript-CVPKp2J9.js → Transcript-Bsx-bGgY.js} +2 -2
- package/payload/server/public/assets/{admin-V5sfLVtU.js → admin-BnZH758N.js} +1 -1
- package/payload/server/public/assets/{arc-C6-nr5UV.js → arc-DyzjCWmw.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-XiVs-N7Z.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DIdho_T6.js → architectureDiagram-Q4EWVU46-qWfElD16.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-D5rTTBSy.js → blockDiagram-DXYQGD6D-DO2fFHC3.js} +1 -1
- package/payload/server/public/assets/{browser-B95l7Hbc.js → browser-CIrfyZWe.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-pfUVHdmy.js → c4Diagram-AHTNJAMY-Ca-q5gDe.js} +1 -1
- package/payload/server/public/assets/{calendar-D1yHZg9_.js → calendar-D6Z8Kmrn.js} +1 -1
- package/payload/server/public/assets/channel-CYBkRz7E.js +1 -0
- package/payload/server/public/assets/chat-h7SytZHx.js +1 -0
- package/payload/server/public/assets/chevron-left-DSTeS1_g.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-EF6cdj8U.js → chunk-2KRD3SAO-CX2PxuDw.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-DE-lcZAc.js → chunk-336JU56O-D8l6U4Ne.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-CPhOHriU.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB--ANCzzyn.js → chunk-4BX2VUAB-CG32Lkbh.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-DTO_X80J.js → chunk-4TB4RGXK-BnAQbO-v.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-4J3nrz44.js → chunk-55IACEB6-ejqRH2M5.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-jH_eqAHL.js → chunk-5FUZZQ4R-ClkicQ-T.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-C-qU6p6k.js → chunk-5PVQY5BW-Be-mE_rx.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-DXxH9Snb.js → chunk-67CJDMHE-DPsemed2.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-CCkxuP7A.js → chunk-7N4EOEYR-BQRQJETl.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-CyItuM8d.js → chunk-AA7GKIK3-B1wcAVCK.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-Bg7gxYNf.js → chunk-BSJP7CBP-DIua053h.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-BAXbOqv5.js → chunk-CIAEETIT-C9GHSCS9.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-vdoErQoc.js → chunk-EDXVE4YY-C1T3l1xj.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-Cz_z_6GK.js → chunk-ENJZ2VHE-8kPcXEQC.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-Ck2jvOgW.js → chunk-FMBD7UC4-Bhoeq9sD.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-DucR0Qo8.js → chunk-FOC6F5B3-BIBpJi8I.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DolYDD7g.js → chunk-ICPOFSXX-DELXp6fj.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-FRzx7E5I.js → chunk-K5T4RW27-DdckXldP.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-Bb5S4Bmc.js → chunk-KGLVRYIC-BJhXejKT.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-c8VZJ-lU.js → chunk-LIHQZDEY-BSd8nyM2.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-BAeh-LZ1.js → chunk-ORNJ4GCN-CBi55uxq.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-BUg7Kysh.js → chunk-OYMX7WX6-Dfbzl8xh.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CDnAAZVJ.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-K4r17UTk.js → chunk-U2HBQHQK-BN1w8_Cq.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-Byh-CyxC.js → chunk-X2U36JSP-CrRay1NJ.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-DC7lhr93.js → chunk-XPW4576I-C_ZE776O.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-B2cu7AEP.js → chunk-YZCP3GAM-CUSlqWBY.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-DH_p8sFX.js → chunk-ZZ45TVLE-BdPUfSiD.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BdXUKVrS.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DAq-uJr_.js +1 -0
- package/payload/server/public/assets/clone-DQl28-jK.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-DeM6JI00.js → cose-bilkent-S5V4N54A-D4E9htTz.js} +1 -1
- package/payload/server/public/assets/{dagre-3drs3e4F.js → dagre-D1B5TQL1.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-C6S-VUtN.js → dagre-KV5264BT-ByuvYV7N.js} +1 -1
- package/payload/server/public/assets/data-CL7CyX1C.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-BkvA32I3.js → diagram-5BDNPKRD-B-0KduTa.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-CVwtRMPB.js → diagram-G4DWMVQ6-CSQmo3eB.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DJ1JVMbd.js → diagram-MMDJMWI5-DK0kWiB3.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-rfj-crtX.js → diagram-TYMM5635-CYbK2reZ.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-TJPuweS5.js → erDiagram-SMLLAGMA-C-JQHvJF.js} +1 -1
- package/payload/server/public/assets/{flatten-BZkoyJ4e.js → flatten-ROVzlo1u.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-LQWEUjbV.js → flowDiagram-DWJPFMVM-OTOd2czg.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DdYsxKRw.js → ganttDiagram-T4ZO3ILL-BWJ778ou.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-BM-KaDZy.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-sx8-fokM.js → gitGraphDiagram-UUTBAWPF-CkNcyISe.js} +1 -1
- package/payload/server/public/assets/graph-XZJZHzvv.js +51 -0
- package/payload/server/public/assets/{graph-labels-izqKLO2K.js → graph-labels-Cabqmf35.js} +1 -1
- package/payload/server/public/assets/{graphlib-DixeJdCf.js → graphlib-8z59Ng6C.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-CtZajyAB.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-C-_WYlmI.js +2 -0
- package/payload/server/public/assets/{isEmpty-VRKFml5R.js → isEmpty-DXf_sApt.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-BKUCuKhZ.js → ishikawaDiagram-UXIWVN3A-Cg7pRRGp.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-BafZP6pM.js → journeyDiagram-VCZTEJTY-CZT_4r_Z.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DQ4c6wRv.js → kanban-definition-6JOO6SKY-Dp1Vd5YM.js} +1 -1
- package/payload/server/public/assets/{line-0_x1Wivu.js → line-UPAcwY66.js} +1 -1
- package/payload/server/public/assets/{linear-CZrU-J2V.js → linear-BeeahLKw.js} +1 -1
- package/payload/server/public/assets/maximize-2-DPe-Noig.js +1 -0
- package/payload/server/public/assets/{mermaid-parser.core-DwJ1cyfO.js → mermaid-parser.core-CLKle8df.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-DnUst0He.js → mermaid.core-CwRj5rL5.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-oc-GwerE.js → mindmap-definition-QFDTVHPH-CNQUY9UJ.js} +1 -1
- package/payload/server/public/assets/{operator-DB3ClIK9.js → operator-BM_CDyCb.js} +1 -1
- package/payload/server/public/assets/{ordinal-v4prQcuq.js → ordinal-B2r5L1v4.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-T-SYedp7.js +1 -0
- package/payload/server/public/assets/{page-C_k7OZm-.js → page-CMIbXzSg.js} +11 -11
- package/payload/server/public/assets/{page-DMi67fnN.js → page-E7I5sEVt.js} +1 -1
- package/payload/server/public/assets/{pdf-render-NQmflZ7K.js → pdf-render-m08Xm2Nm.js} +1 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BWECFVVd.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-BnBtQNHM.js → pieDiagram-DEJITSTG-Scnq58FX.js} +1 -1
- package/payload/server/public/assets/{public-CM5RbAdA.js → public-CrdWCSk2.js} +1 -1
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CkNqtzHI.js → quadrantDiagram-34T5L4WZ-wPfZo_vs.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-Dx0YUklX.js +1 -0
- package/payload/server/public/assets/{reduce-0Mm1v1Rr.js → reduce-CFlDlJf5.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-D7qc27KT.js → requirementDiagram-MS252O5E-yYkH12K2.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-I-ze2s05.js → rotate-ccw-Dwtj0NJ7.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-2Y4sqRY7.js → sankeyDiagram-XADWPNL6-fVWRBzzV.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-hXOiSHuT.js → sequenceDiagram-FGHM5R23-Dbap3X6h.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Dq4hhkLA.js → stateDiagram-FHFEXIEX-DkPLAqIh.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DceWO1u6.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-Dn9wBUEw.js → timeline-definition-GMOUNBTQ-DabKBJyd.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-C3197Rac.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-BPrpx29h.js +1 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-F-4Pn1Xi.css → useSubAccountSwitcher-BH-YjP0H.css} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BKVHJiIt.js → vennDiagram-DHZGUBPP-CaKT7c-c.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-DW4Jlbhw.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-Bn9vvpdK.js → wardleyDiagram-NUSXRM2D-BZ5TTSOL.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-FIoMdPB3.js → xychartDiagram-5P7HB3ND-CLfeklJ9.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +5 -5
- package/payload/server/public/chat.html +10 -9
- package/payload/server/public/data.html +9 -8
- package/payload/server/public/graph.html +9 -8
- package/payload/server/public/index.html +12 -11
- package/payload/server/public/operator.html +12 -11
- package/payload/server/public/public.html +10 -9
- package/payload/server/server.js +41 -6
- package/payload/server/public/assets/architecture-YZFGNWBL-DdgmZ93B.js +0 -1
- package/payload/server/public/assets/channel-Da-UUyqx.js +0 -1
- package/payload/server/public/assets/chat-DlGzBbCN.js +0 -1
- package/payload/server/public/assets/chevron-left-XbRmpBBx.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-B1kFAxo1.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-BjE-Glwf.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-Dol3Ogeh.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-VUMj7gWH.js +0 -1
- package/payload/server/public/assets/clone-m7oGrdBC.js +0 -1
- package/payload/server/public/assets/data-D6oHTzqP.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-cJEaiQq4.js +0 -1
- package/payload/server/public/assets/graph-BbKOGyYu.js +0 -51
- package/payload/server/public/assets/info-OMHHGYJF-BUxfOTKa.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CD-d3Rgf.js +0 -2
- package/payload/server/public/assets/packet-4T2RLAQJ-B9U_2639.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-Glh-lJOT.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-CTSgob8w.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DTj9o2vZ.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CXApkW1l.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-DzvTXAcT.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-BExXV4oI.js +0 -1
- /package/payload/server/public/assets/{_baseFor-C0Y1mc3g.js → _baseFor-BVuIxZJh.js} +0 -0
- /package/payload/server/public/assets/{array-DqLCdDFv.js → array-B9UHiPd-.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-Cn5b4Cdu.js → cytoscape.esm-D5_TRwB-.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-CrJzLgRD.js → defaultLocale-5eAKkKJC.js} +0 -0
- /package/payload/server/public/assets/{dist-Dlks0Bfw.js → dist-CADCHk0t.js} +0 -0
- /package/payload/server/public/assets/{init-C0r9Gk5G.js → init-DlZdxViB.js} +0 -0
- /package/payload/server/public/assets/{katex-BFwFoEts.js → katex-Xo0SyWvP.js} +0 -0
- /package/payload/server/public/assets/{path-DIKpVbHL.js → path-6uRLdFF7.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-C5gCWwwF.js → preload-helper-CvXuAEud.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-DsHEmXUZ.js → rough.esm-Djo4Abte.js} +0 -0
- /package/payload/server/public/assets/{src-Bv7ZWAzF.js → src-Bi0fLV9t.js} +0 -0
- /package/payload/server/public/assets/{useSubAccountSwitcher-BxBlNMee.js → useSubAccountSwitcher-BVCMAnWK.js} +0 -0
|
@@ -77,10 +77,10 @@ The Loop CRM record format you receive (either piped in by the brief or fetched
|
|
|
77
77
|
|
|
78
78
|
### Zip-site / hosted-page directory → Listing
|
|
79
79
|
|
|
80
|
-
When a property site has been published from operator-supplied assets, the
|
|
80
|
+
When a property site has been published from operator-supplied assets, the canonical Cloudflare Pages source tree lives at `<accountDir>/pages/<slug>/` and follows the format produced by `property-brochure:property-extract`:
|
|
81
81
|
|
|
82
82
|
```
|
|
83
|
-
<accountDir>/
|
|
83
|
+
<accountDir>/pages/<slug>/
|
|
84
84
|
property.json # structured fields
|
|
85
85
|
description.md # full descriptive copy
|
|
86
86
|
index.html # the published page
|
|
@@ -92,13 +92,13 @@ When a property site has been published from operator-supplied assets, the direc
|
|
|
92
92
|
epc.{jpg|png}
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
The curator runs on the same Pi as the assets — image bytes are read with `Read` from the local file path, never fetched over HTTPS. Round-tripping through `https
|
|
95
|
+
The curator runs on the same Pi as the assets — image bytes are read with `Read` from the local file path, never fetched over HTTPS. Round-tripping through `https://<slug>.pages.dev/images/…` is wasted I/O and adds network failure modes the local read does not have.
|
|
96
96
|
|
|
97
97
|
#### Brand resolution
|
|
98
98
|
|
|
99
99
|
The brand `:Organization` parent is resolved from the `<brand>-logo-*.png` filenames the operator uploaded with the site. This is the highest-signal brand identifier — it is operator-confirmed metadata baked into the publish step, not an address-token heuristic.
|
|
100
100
|
|
|
101
|
-
1. `Glob` `<accountDir>/
|
|
101
|
+
1. `Glob` `<accountDir>/pages/<slug>/images/*-logo-*.{png,svg}` (also `Bash` `ls -1 <accountDir>/pages/<slug>/images/*-logo-*` when Glob is unavailable).
|
|
102
102
|
2. For each filename matching `^([a-z0-9-]+)-logo-(dark|light)\.(png|svg)$`, capture group 1 is the brand slug.
|
|
103
103
|
3. Reduce to the distinct set of brand slugs:
|
|
104
104
|
- exactly one → that is the brand
|
|
@@ -109,18 +109,18 @@ The resolved brand slug is the natural key for `MERGE (o:Organization {accountId
|
|
|
109
109
|
|
|
110
110
|
#### pageUrl and image URLs
|
|
111
111
|
|
|
112
|
-
The
|
|
112
|
+
The landing page is hosted on Cloudflare Pages. The Pages project name is the listing `slug`, so the deploy's production alias is deterministically `https://<slug>.pages.dev/`, which the curator composes from the `slug` alone. The alias serves `index.html` as the default document, so `pageUrl` is the root `https://<slug>.pages.dev/`. This URL stays up when the install device is offline, which the old device-tunnel `/sites/` path did not.
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
When the operator attaches a custom domain to the Pages project, reconciling `pageUrl` to that domain is a later step; until then the deterministic `.pages.dev` alias is the durable public URL the curator emits.
|
|
115
115
|
|
|
116
|
-
`imageUrls[i]` is composed as `https://<
|
|
116
|
+
`imageUrls[i]` is composed as `https://<slug>.pages.dev/images/<filename>`. The list is built from `Glob` `<accountDir>/pages/<slug>/images/*.{jpg,jpeg,png,webp}` ordered by filename, with brand-logo files (`*-logo-*.{png,svg}`) excluded — they are agency branding, not listing photos. `heroImageUrl` is the first non-logo image after that ordering.
|
|
117
117
|
|
|
118
118
|
#### brochureUrl and socialTileUrls — harvesting the published outputs
|
|
119
119
|
|
|
120
120
|
The published site carries more than the landing page and its photos. When the brochure pipeline produced a hosted brochure and social tiles, they are served from the same tree but, until harvested, carry no graph reference and are orphaned on disk (see `schema-estate-agent.md → Filesystem ↔ graph`). The curator harvests them the same way it composes `pageUrl` and `imageUrls` — read the on-disk publish, compose the hosted URL, never fetch over HTTPS:
|
|
121
121
|
|
|
122
|
-
- `brochureUrl` — when `<accountDir>/
|
|
123
|
-
- `socialTileUrls` — `Glob` `<accountDir>/
|
|
122
|
+
- `brochureUrl` — when `<accountDir>/pages/<slug>/brochure.html` exists, set `brochureUrl = https://<slug>.pages.dev/brochure.html`. When it does not exist, leave `brochureUrl` null. Reference the canonical `brochure.html`; the downloadable `<slug>-brochure.pdf` is the same artefact class and gets no separate property.
|
|
123
|
+
- `socialTileUrls` — `Glob` `<accountDir>/pages/<slug>/socials/og-*.jpg`, order by filename, compose each as `https://<slug>.pages.dev/socials/<filename>`. When the site was published without a `socials/` subtree the glob is empty and `socialTileUrls` is the empty array — not an error; many sites publish without social collateral.
|
|
124
124
|
|
|
125
125
|
These props are written on the same `MERGE (l:Listing {accountId, sourceSystem, sourceId})` as the rest of the zip-site mapping. They are unconstrained strings — no `:ImageObject` node is minted for a brochure page or a social tile (those nodes model visitor-pickable property photos only).
|
|
126
126
|
|
|
@@ -131,13 +131,13 @@ These props are written on the same `MERGE (l:Listing {accountId, sourceSystem,
|
|
|
131
131
|
| `slug` | the directory basename |
|
|
132
132
|
| `displayName`, `addressLine`, `town`, `postcode`, `priceGBP` (`→ price`), `priceQualifier`, `bedrooms`, `bathrooms`, `receptionRooms`, `floorAreaSqft`, `propertyType`, `tenure` | `property.json` keys with the same names (Schema.org camelCase already enforced upstream) |
|
|
133
133
|
| `description` | `description.md` body (`Read` the file) |
|
|
134
|
-
| `pageUrl` | `https://<
|
|
135
|
-
| `imageUrls` | URLs of `images/*.{jpg,jpeg,png,webp}` minus brand logos, ordered by filename, prefixed with `https://<
|
|
134
|
+
| `pageUrl` | `https://<slug>.pages.dev/` — the Pages production alias, composed by the curator from `slug` (the Pages project name is the slug) |
|
|
135
|
+
| `imageUrls` | URLs of `images/*.{jpg,jpeg,png,webp}` minus brand logos, ordered by filename, prefixed with `https://<slug>.pages.dev/images/` |
|
|
136
136
|
| `heroImageUrl` | `imageUrls[0]` |
|
|
137
137
|
| `floorplanUrls` | composed the same way for any image matching `*floorplan*.{jpg,png}` (case-insensitive) under `images/` |
|
|
138
138
|
| `epcUrl` | composed for any `epc.{jpg,png,pdf}` under `images/` or the site root |
|
|
139
|
-
| `brochureUrl` | `https://<
|
|
140
|
-
| `socialTileUrls` | URLs of `socials/og-*.jpg` under the site root, ordered by filename, prefixed with `https://<
|
|
139
|
+
| `brochureUrl` | `https://<slug>.pages.dev/brochure.html` when `brochure.html` exists at the site root; omitted (null) when it does not |
|
|
140
|
+
| `socialTileUrls` | URLs of `socials/og-*.jpg` under the site root, ordered by filename, prefixed with `https://<slug>.pages.dev/socials/`; empty array when no `socials/` subtree was published |
|
|
141
141
|
| `sourceSystem` | literal `"zip-upload"` |
|
|
142
142
|
| `sourceId` | the directory basename (the slug) — operator-chosen natural key |
|
|
143
143
|
| `blurb` | same LLM rule as the Loop path; same fallback |
|
|
@@ -164,7 +164,7 @@ Write a `no-op` (no Listing produced; admin agent informed) when:
|
|
|
164
164
|
|
|
165
165
|
- The source has no FACTS block AND no parseable address — there is no `slug` to derive and no `displayName`. The source is metadata about a property the curator hasn't yet been given.
|
|
166
166
|
- The source declares `status: "off-market"` AND no `pageUrl` is known. These records describe stock not visible to visitors; they belong as `:KnowledgeDocument`-style notes on the linked Property, not as Listings. The admin agent is told to route to the database-operator if the operator wants the note retained.
|
|
167
|
-
- The zip-site brand cannot be resolved from `<accountDir>/
|
|
167
|
+
- The zip-site brand cannot be resolved from `<accountDir>/pages/<slug>/images/*-logo-*.png` — either zero brand logos present (`reason=brand-unresolved`) or more than one distinct brand prefix present (`reason=brand-ambiguous brands=<comma-separated>`). Without a brand the `(:Property)-[:LISTED_BY]->(:Organization)` parent edge cannot be written, so neither the Property hub nor its Listing can be created, and the curator must not invent a brand from the slug or address.
|
|
168
168
|
- The source's `accountId` cannot be resolved from the session env. Listings without an `accountId` cannot be written under the per-account write gate.
|
|
169
169
|
|
|
170
170
|
`no-op` is loud — the curator returns a one-sentence explanation of which field was missing. Silent skips are defects.
|
|
@@ -179,12 +179,12 @@ There are two metadata sources, picked per Listing:
|
|
|
179
179
|
|
|
180
180
|
### Source A — brochure sidecar (the default on zip-site Listings)
|
|
181
181
|
|
|
182
|
-
The brochure pipeline that produced the published site already ran a deliberate vision pass over the same image bytes during slot verification and recorded the per-image semantics in `output/images.json`. The web bundle carries a byte-identical copy at the bundle root, and `
|
|
182
|
+
The brochure pipeline that produced the published site already ran a deliberate vision pass over the same image bytes during slot verification and recorded the per-image semantics in `output/images.json`. The web bundle carries a byte-identical copy at the bundle root, and `cloudflare:site-deploy` lands it at `<accountDir>/pages/<slug>/images.json`. The brochure's signal is strictly richer than a second per-image vision call would produce — slot semantics are operator-confirmed and the figcaptions are editorial sentences. Re-running vision over the same bytes is duplicate work that produces a worse output.
|
|
183
183
|
|
|
184
|
-
When `<accountDir>/
|
|
184
|
+
When `<accountDir>/pages/<slug>/images.json` exists, harvest from it for every image and **do not** `Read` any file under `<accountDir>/pages/<slug>/images/`:
|
|
185
185
|
|
|
186
|
-
1. **Parse the sidecar once.** `Read` `<accountDir>/
|
|
187
|
-
2. **Match each `imageUrls[i]` to a sidecar entry by filename.** The filename is the URL's basename (`https://<
|
|
186
|
+
1. **Parse the sidecar once.** `Read` `<accountDir>/pages/<slug>/images.json`; validate `schemaVersion === 1` and that `images` is a non-empty array. On parse failure or schema mismatch, log `[listing-curator] images-sidecar-invalid reason=<schema|parse> path=<…>` and fall through to Source B (vision) for the whole Listing.
|
|
187
|
+
2. **Match each `imageUrls[i]` to a sidecar entry by filename.** The filename is the URL's basename (`https://<slug>.pages.dev/images/griffin-house-01.webp` → `griffin-house-01.webp`). Each `floorplanUrls[i]` and the `epcUrl` matches the same way against entries whose `isFloorplan` / `isEpc` is `true`.
|
|
188
188
|
3. **Populate the ImageObject from the matched entry.**
|
|
189
189
|
- `description` ← the sidecar's `caption` if present, else `altText`. Truncate at 200 chars on a word boundary; if the result is empty or all whitespace, `description = ""`.
|
|
190
190
|
- `tags` ← `[room]` for the matched entry — a one-element array drawn from the closed set. The mapping is operator-confirmed in the brochure; do not second-guess it. For floorplans `tags = ["floorplan"]`, for the EPC `tags = ["epc"]`, regardless of the entry's `room` value (which is also `floorplan` / `epc` by sidecar contract).
|
|
@@ -193,13 +193,13 @@ When `<accountDir>/sites/<slug>/images.json` exists, harvest from it for every i
|
|
|
193
193
|
|
|
194
194
|
### Source B — vision fallback (sidecar absent)
|
|
195
195
|
|
|
196
|
-
When `<accountDir>/
|
|
196
|
+
When `<accountDir>/pages/<slug>/images.json` does not exist (legacy brochures published before the sidecar contract landed, manual zip uploads that bypassed the brochure skill, or any future zip path that hasn't adopted the sidecar), the curator falls back to a per-image vision pass. This is the only branch that runs vision on listing-photo bytes.
|
|
197
197
|
|
|
198
|
-
Image bytes are read with `Read` from the local file. Zip-site assets live at `<accountDir>/
|
|
198
|
+
Image bytes are read with `Read` from the local file. Zip-site assets live at `<accountDir>/pages/<slug>/images/<filename>`. The curator runs on the same Pi as the assets — never fetch via HTTPS.
|
|
199
199
|
|
|
200
200
|
For each image on the Listing:
|
|
201
201
|
|
|
202
|
-
1. **Vision tag pass.** `Read` the local image file at the path derived from the URL (zip-site: `<accountDir>/
|
|
202
|
+
1. **Vision tag pass.** `Read` the local image file at the path derived from the URL (zip-site: `<accountDir>/pages/<slug>/images/<filename>`). `Read` returns the bytes as an inline content block your model can see. Produce `{description, tags}` from what you see using the same single-call doctrine as the blurb step. The description is a single sentence (≤ 200 characters, plain English, no estate-agent clichés). The tags are up to four labels drawn from the closed set above. When no tag applies, `tags` is the empty array.
|
|
203
203
|
2. **Validate.** If `Read` fails (file missing), the JSON fails to parse, or `description` is empty / >200 chars, write the ImageObject anyway with `description: ""` and `tags: []`. Log `[listing-curator] image-tag-failed url=<url> reason=<read-error|json-parse|description-bounds>`. One image's tagging failure must not block the rest of the Listing's images — degraded room-pick on that image is the only consequence.
|
|
204
204
|
|
|
205
205
|
### Loop CRM CDN-hosted images
|
|
@@ -253,11 +253,11 @@ For a `no-op` outcome that didn't even reach the write step (brand-unresolved, b
|
|
|
253
253
|
|
|
254
254
|
`socialTilesRef` (`T`) is the number of URLs written to `socialTileUrls`, and `brochureRef` is `1` when `brochureUrl` was set, else `0`. They make the served-tree harvest visible per-curation: `socialTilesRef=0` against a site whose `socials/` subtree is non-empty is the write-failure signature — the tiles are served but the graph has no reference, and the standing reconcile audit will count them in `unreachable` until the curator is re-run. `brochureRef=0` on a site that published a `brochure.html` is the same signature for the brochure.
|
|
255
255
|
|
|
256
|
-
`imagesWritten` is the total `:ImageObject` count for the Listing after the run. `imagesTagged` is the count with non-empty `tags`. `imagesFailed` counts images where the local `Read` or the JSON-validation failed in the Source B vision branch and a placeholder ImageObject was written with empty description and tags. `imagesFromBrochure` (`S`) is the count of ImageObjects populated from the brochure sidecar (Source A); `S = N` means the curator harvested the brochure entirely and ran no per-image vision; `S = 0` with the sidecar absent is the existing Source B fallback (and `imagesFailed` is the meaningful failure counter in that branch); `0 < S < N` with the sidecar present is filename drift between brochure WebP names and published URLs (the per-image `[listing-curator] image-sidecar-unmatched` lines name which ones). A high `imagesFailed / imagesWritten` ratio on zip-site Listings still means images are missing from `<accountDir>/
|
|
256
|
+
`imagesWritten` is the total `:ImageObject` count for the Listing after the run. `imagesTagged` is the count with non-empty `tags`. `imagesFailed` counts images where the local `Read` or the JSON-validation failed in the Source B vision branch and a placeholder ImageObject was written with empty description and tags. `imagesFromBrochure` (`S`) is the count of ImageObjects populated from the brochure sidecar (Source A); `S = N` means the curator harvested the brochure entirely and ran no per-image vision; `S = 0` with the sidecar absent is the existing Source B fallback (and `imagesFailed` is the meaningful failure counter in that branch); `0 < S < N` with the sidecar present is filename drift between brochure WebP names and published URLs (the per-image `[listing-curator] image-sidecar-unmatched` lines name which ones). A high `imagesFailed / imagesWritten` ratio on zip-site Listings still means images are missing from `<accountDir>/pages/<slug>/images/` — investigate the publish step, not the vision prompt. When `imagesWritten > 20`, the recommender will only see the first 20 in its `related` set (one-hop expand cap) — emit a separate `[listing-curator] image-cap-warning slug=<slug> imageCount=<N>` line so the cap is visible.
|
|
257
257
|
|
|
258
258
|
## Out of scope
|
|
259
259
|
|
|
260
260
|
- Producing the visitor-facing markdown card from a `:Listing`. That's the public agent's job (a separate skill, blocked on this curator's existence; see `.tasks/`).
|
|
261
261
|
- Inferring missing market-data fields (sold-price comps, demand) — that's the `property-data` MCP, not curator.
|
|
262
262
|
- Inferring Property structural fields the source does not carry. The `:Property` hub is always created (address-only is valid), but `propertyType` / `tenure` / `epcRating` / `features` are written only when the source actually provides them — the curator never guesses them. A later curation run tops them up when richer source data arrives.
|
|
263
|
-
- An operator-built `tmp/site-listing-manifest.json` or any other pre-resolved JSON of slug → brand → URL mappings. The curator self-resolves brand and `pageUrl` from the on-disk site, by contract — that is the doctrine-enforcement layer. If an admin agent dispatches the curator over a batch, it does so by enumerating directories (`ls <accountDir>/
|
|
263
|
+
- An operator-built `tmp/site-listing-manifest.json` or any other pre-resolved JSON of slug → brand → URL mappings. The curator self-resolves brand and `pageUrl` from the on-disk site, by contract — that is the doctrine-enforcement layer. If an admin agent dispatches the curator over a batch, it does so by enumerating directories (`ls <accountDir>/pages/`) and calling the curator once per slug.
|
|
@@ -34,6 +34,10 @@ Five specialists ship with the bundle. Four (Negotiator, Valuer, Compliance, Lis
|
|
|
34
34
|
|
|
35
35
|
The admin-side specialists embed domain knowledge from the sub-plugins and operate against Loop CRM, the memory graph, and (for Compliance) live web search for current legislation. The public-side specialist runs on a restricted tool surface and answers only from the agency knowledge base.
|
|
36
36
|
|
|
37
|
+
## Landing-page hosting
|
|
38
|
+
|
|
39
|
+
A property's "for sale" landing page is hosted durably on Cloudflare Pages. The `property-brochure` pipeline emits the web bundle as the canonical Pages source tree at `<accountDir>/pages/<slug>/`, and admin deploys it with `cloudflare:site-deploy`; the page answers on `https://<slug>.pages.dev/` and stays up when the install device is offline. The Listing Curator writes that Pages URL to the `:Listing` the public agent renders, so a buyer is always sent to the durable page. This is the durable home for the landing page, replacing the earlier device-tunnel default (`admin:publish-site`), which went dark whenever the device or tunnel was down.
|
|
40
|
+
|
|
37
41
|
## Per-account customization
|
|
38
42
|
|
|
39
43
|
Each {{productName}} install carries its own customization profile: brand voice, knowledge-base spine, Loop CRM credentials, PropertyData API key, and the agent's territory. Profile changes happen through conversation with the admin agent, not through a settings UI.
|
package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-brochure/SKILL.md
CHANGED
|
@@ -195,7 +195,7 @@ If one or more candidates from the closed list exist, the operator confirmation
|
|
|
195
195
|
- **`scrollHeight > viewport budget` is ALWAYS a defect — never "negligible".** Landscape budget is **794px** (`min-height: 210mm` at 96dpi); portrait is **1123px**. Every `.page`'s `scrollHeight` must be `≤` the budget — strict, not "approximately equal". A 4px overflow IS a defect: `overflow: hidden` silently clips that excess, and on pages with absolute-positioned bottom chrome (`.folio`, `.back-disclaimer`) the clipped content paints over chrome that lives in the absolute layer. "It's only 4 pixels" is the rationalisation that ships defects — the rule does not have a tolerance band. If a page reports `scrollHeight > budget` even by 1px, the build halts until the operator addresses the content-volume mismatch (trim copy, shrink an image, reduce a row count, or split into a continuation page). Never paper over with `overflow: hidden`-as-clip; the warning sign is the deliverable's only signal that the content doesn't fit.
|
|
196
196
|
- **Material Information table has a hard row capacity — overflow is a content-volume defect, not a render bug.** At the default `.mi-row` sizing (9.5/11.5px fonts, 6px vertical padding, 18px `.mi-grid` row-gap), one column in the three-column MI grid fits **~13 rows** within the 22mm-clearance budget. A property with an unusually full table (e.g. 17+ rows in the tallest column, observed on a recent run) overruns by ~25mm / ~85px and clips into the folio zone. When MI's content volume exceeds the budget, the operator confirmation prompt MUST surface `mi.<column>.row_count` as an overflow item and ask the operator to either (a) trim the column to ≤ 13 rows by consolidating related disclosures (e.g. merge "easements" + "water/sewerage" + "rights of way" into one "Other matters" row that points at the seller's solicitor), or (b) opt into a continuation page (15a / 15b) — a separate skill-level decision that breaks the default 16-page contract and must be operator-confirmed. The build never silently truncates rows, never shrinks fonts to "make it fit", and never accepts a scrollHeight overflow as "negligible". The default `.mi-page` 22mm bottom-padding is sized for the typical property; properties outside the typical range MUST resolve via operator confirmation, not via the agent's judgement about which rows are "less important".
|
|
197
197
|
- **No `{{ token }}` may remain in rendered output** — `grep '{{' output/brochure.html` must return zero matches before PDFs are built.
|
|
198
|
-
- **`images.json` sidecar is mandatory.** After slot verification and before bundling, write `output/images.json` and `output/web/images.json` (byte-identical) per `references/images.md → images.json sidecar`. The downstream `:Listing` curator reads the bundle copy at `<accountDir>/
|
|
198
|
+
- **`images.json` sidecar is mandatory.** After slot verification and before bundling, write `output/images.json` and `output/web/images.json` (byte-identical) per `references/images.md → images.json sidecar`. The downstream `:Listing` curator reads the bundle copy at `<accountDir>/pages/<slug>/images.json` after the Cloudflare Pages deploy and uses it in place of running a second per-image vision pass. A bundle without `images.json` forces the curator into its fallback path and costs one vision call per photo — silent on the brochure side, observable as `imagesFromBrochure=0` on the curator's log line.
|
|
199
199
|
|
|
200
200
|
## Scope
|
|
201
201
|
|
|
@@ -230,7 +230,7 @@ cp output/<slug>-brochure-web.pdf output/web/<slug>-brochure.pdf
|
|
|
230
230
|
|
|
231
231
|
After the web bundle's `images/` is populated and the brochure HTML is copied in, write the sidecar file at **both** `output/images.json` and `output/web/images.json`. The contents are byte-identical — the canonical archive copy and the bundle copy. Source-of-truth is the slot-verification dict already in memory; never re-derive from disk.
|
|
232
232
|
|
|
233
|
-
Full schema, closed-set room vocabulary, slot → room mapping, and emission recipe live in [`images.md → images.json sidecar`](images.md). The downstream `:Listing` curator reads the bundle copy at `<accountDir>/
|
|
233
|
+
Full schema, closed-set room vocabulary, slot → room mapping, and emission recipe live in [`images.md → images.json sidecar`](images.md). The downstream `:Listing` curator reads the bundle copy at `<accountDir>/pages/<slug>/images.json` after `cloudflare:site-deploy` lands the tree on Cloudflare Pages.
|
|
234
234
|
|
|
235
235
|
The strip-unreferenced-images pass below scans `output/web/images/` only — `images.json` lives at the bundle root and is unaffected.
|
|
236
236
|
|
|
@@ -299,7 +299,7 @@ The brochure should render the same as the canonical preview, just lighter on th
|
|
|
299
299
|
| `<slug>-brochure.pdf` | — | ✓ identical bytes to `-web.pdf`; matches index.html / brochure.html link |
|
|
300
300
|
| `cover-print.png … backpage-print.png` | ✓ 300 dpi PNG (~4–7 MB each) — canonical snapshots | — bundle ships the PDF instead of per-page JPGs |
|
|
301
301
|
| `images/<slug>-NN.webp` | full-quality per Render-slot table | web-tier per the web table above |
|
|
302
|
-
| `images.json` | ✓ canonical sidecar (slot, room, alt, caption per image) — written after slot verification | ✓ byte-identical copy at bundle root; consumed by `:Listing` curator after
|
|
302
|
+
| `images.json` | ✓ canonical sidecar (slot, room, alt, caption per image) — written after slot verification | ✓ byte-identical copy at bundle root; consumed by `:Listing` curator after the Pages deploy |
|
|
303
303
|
| `images/qr-*.png`, `images/<brand>-logo-*.png` | ✓ | ✓ (copied unchanged — already small) |
|
|
304
304
|
| `.snapshots-web/*-print.png` | ✓ intermediate (192 dpi PNGs used by the web-PDF build; deletable after) | — |
|
|
305
305
|
|
|
@@ -79,7 +79,7 @@ Indexes 03, 11–12, 16–17, 20–23, 28+ are intentionally unused — leaving
|
|
|
79
79
|
|
|
80
80
|
After slot verification is complete (every WebP under `output/images/` has been read and assigned a slot by pixel content per the rule above), write `output/images.json` as the deterministic record of what the brochure resolved per image. The data is already in hand at this point — the slot table, the alt-text token values, and the figcaption token values are the same strings the brochure HTML carries. The downstream `:Listing` curator consumes this sidecar to populate `:ImageObject.description` and `:ImageObject.tags` without re-running vision against the same bytes. Without the sidecar the curator falls back to a per-image vision call, paying a second time for metadata the brochure has already produced.
|
|
81
81
|
|
|
82
|
-
Write a second copy at `output/web/images.json` immediately after copying the brochure into `output/web/`. The web bundle is
|
|
82
|
+
Write a second copy at `output/web/images.json` immediately after copying the brochure into `output/web/`. The web bundle is the canonical Cloudflare Pages source tree. It is emitted to `<accountDir>/pages/<slug>/` and deployed to Cloudflare Pages by `cloudflare:site-deploy`, so the landing page stays up when the install device is offline. The curator reads the sidecar at `<accountDir>/pages/<slug>/images.json`. The canonical copy at `output/images.json` is the archival twin and never gets re-derived from the bundle copy. Both copies must be byte-identical at write time; never write one without the other.
|
|
83
83
|
|
|
84
84
|
### Schema
|
|
85
85
|
|
|
@@ -371,6 +371,10 @@ done
|
|
|
371
371
|
|
|
372
372
|
Both pages must return 200 and render correctly. The landing page should not exhibit overflow on a 1440px-wide viewport at desktop sizes; on narrow mobile (<760px) it should reflow to single-column photo grids.
|
|
373
373
|
|
|
374
|
+
## Hosting — durable on Cloudflare Pages
|
|
375
|
+
|
|
376
|
+
The landing page's durable home is Cloudflare Pages, not the device tunnel. The web bundle is emitted as the canonical Pages source tree at `<accountDir>/pages/<slug>/`, and admin runs `cloudflare:site-deploy` to deploy it. The Pages project name is the property slug, so the page answers on the deterministic production alias `https://<slug>.pages.dev/`, which stays up when the install device is offline. This replaces the earlier device-tunnel default (`admin:publish-site` to `<accountDir>/sites/<slug>/`), which went dark whenever the device or tunnel was down. The build side is unchanged: the landing page still lives in `output/web/` and the zip; only its published home moved.
|
|
377
|
+
|
|
374
378
|
## When to regenerate
|
|
375
379
|
|
|
376
380
|
`index.html` is regenerated whenever the brochure's image set changes (new photos, swapped slot assignments) or whenever the brochure's chapter copy materially changes (the landing page mirrors the brochure's narrative). Cosmetic CSS-only changes to the brochure don't require a landing-page regenerate. The landing page is *not* part of the canonical print archive — it lives only in `output/web/` and the zip.
|
package/payload/server/public/assets/{AdminLoginScreens-o2gMrtKC.js → AdminLoginScreens-rlk263u9.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./chunk-CAM3fms7.js";import{A as t,L as n,M as r,N as i,O as a}from"./useSubAccountSwitcher-BxBlNMee.js";import{i as o}from"./admin-types-hioowVct.js";import{b as s,x as c}from"./AdminShell-C7DK87-C.js";import{t as l}from"./Checkbox-DJyosZ-i.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[t,n]=(0,p.useState)(`loading`),[r,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 r=await t.json();D(r.session_key),z(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=o(r.thinkingView);return H.current=i,V(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`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){n(`connect-claude`);return}}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,p.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,p.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(u)===`1`}catch{}if(f({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(u,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${d}`),window.location.replace(d)}},[t,e]);let Y=(0,p.useRef)(null);(0,p.useEffect)(()=>{if(t!==`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 t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){i(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),Y.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,p.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(K(!0),n(`enter-pin`))}).catch(()=>{})},[t]);async function X(e,t){y(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){let e=await r.json().catch(()=>({}));if(r.status===401&&e?.code===`remote-auth-required`){i(`enter-pin`,`/api/admin/session`);return}h(e.error||`Invalid PIN`);return}let s=await r.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(``),n(`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 t=s.trim();if(!t){h(`Please enter your name.`);return}if(r.length<4){h(`PIN must be at least 4 characters.`);return}let o=r;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===401&&t?.code===`remote-auth-required`){i(`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 r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):h(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await X(o);return}a(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[r,v,s]),Q=(0,p.useCallback)(async e=>{e.preventDefault(),h(``),await X(r)},[r]),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 n(`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(``),n(`enter-pin`)},[]);return(0,p.useEffect)(()=>{Y.current=$},[$]),{appState:t,setAppState:n,pin:r,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:n,setPin:r,showPin:i,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:t,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:n,onChange:r,onComplete:()=>{},showPin:i}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!n||!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:i,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function v(e){let{pin:n,setPin:r,showPin:i,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:t,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:n,onChange:r,onComplete:()=>{},showPin:i,autoFocus:!0}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!n,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:i,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function y(e){let{authPolling:n,setAuthPolling:r,authLoading:i,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){r(!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.`),r(!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`})}),r(!1),l(``)}return n||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:[n?(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:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,h.jsx)(`div`,{style:{marginTop:`12px`},children:(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:i,children:i?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),n&&_===`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:t,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:i,children:i?(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};
|
|
1
|
+
import{o as e}from"./chunk-CAM3fms7.js";import{A as t,L as n,M as r,N as i,O as a}from"./useSubAccountSwitcher-BVCMAnWK.js";import{i as o}from"./admin-types-hioowVct.js";import{b as s,x as c}from"./AdminShell-C5vWTy2n.js";import{t as l}from"./Checkbox-Chz6bfy-.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[t,n]=(0,p.useState)(`loading`),[r,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 r=await t.json();D(r.session_key),z(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=o(r.thinkingView);return H.current=i,V(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`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){n(`connect-claude`);return}}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,p.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,p.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(u)===`1`}catch{}if(f({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(u,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${d}`),window.location.replace(d)}},[t,e]);let Y=(0,p.useRef)(null);(0,p.useEffect)(()=>{if(t!==`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 t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){i(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),Y.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,p.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(K(!0),n(`enter-pin`))}).catch(()=>{})},[t]);async function X(e,t){y(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){let e=await r.json().catch(()=>({}));if(r.status===401&&e?.code===`remote-auth-required`){i(`enter-pin`,`/api/admin/session`);return}h(e.error||`Invalid PIN`);return}let s=await r.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(``),n(`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 t=s.trim();if(!t){h(`Please enter your name.`);return}if(r.length<4){h(`PIN must be at least 4 characters.`);return}let o=r;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===401&&t?.code===`remote-auth-required`){i(`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 r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):h(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await X(o);return}a(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[r,v,s]),Q=(0,p.useCallback)(async e=>{e.preventDefault(),h(``),await X(r)},[r]),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 n(`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(``),n(`enter-pin`)},[]);return(0,p.useEffect)(()=>{Y.current=$},[$]),{appState:t,setAppState:n,pin:r,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:n,setPin:r,showPin:i,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:t,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:n,onChange:r,onComplete:()=>{},showPin:i}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!n||!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:i,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function v(e){let{pin:n,setPin:r,showPin:i,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:t,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:n,onChange:r,onComplete:()=>{},showPin:i,autoFocus:!0}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!n,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:i,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function y(e){let{authPolling:n,setAuthPolling:r,authLoading:i,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){r(!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.`),r(!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`})}),r(!1),l(``)}return n||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:[n?(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:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,h.jsx)(`div`,{style:{marginTop:`12px`},children:(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:i,children:i?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),n&&_===`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:t,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:i,children:i?(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};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./chunk-CAM3fms7.js";import{C as t,D as n,I as r,L as i,M as a,O as o,S as s,T as c,_ as l,b as u,c as d,d as f,h as p,j as m,l as h,m as g,o as ee,p as te,r as ne,s as _,t as re,u as ie,v as ae,w as oe,y as se}from"./useSubAccountSwitcher-BxBlNMee.js";async function ce(){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 v=e(i(),1),y=a(),b={sm:14,md:16,lg:18},x={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=b[t],h={...e===`send`?{width:x[t],height:x[t]}:{},...u},g=Object.keys(h).length>0;return(0,y.jsxs)(`button`,{type:s,className:p,disabled:i||o,onClick:c,"aria-label":l,style:g?h:void 0,children:[(0,y.jsxs)(`span`,{className:`btn__content`,style:{visibility:i?`hidden`:`visible`},children:[n&&r===`leading`&&(0,y.jsx)(n,{size:m}),f,n&&r===`trailing`&&(0,y.jsx)(n,{size:m})]}),i&&(0,y.jsx)(`span`,{className:`btn__spinner`,children:`✱`})]})}var le=n(`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`}]]),ue=n(`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`}]]),de=n(`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`}]]),C=n(`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`}]]),w=n(`gauge`,[[`path`,{d:`m12 14 4-4`,key:`9kzdfg`}],[`path`,{d:`M3.34 19a10 10 0 1 1 17.32 0`,key:`19p75a`}]]),fe=n(`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`}]]),T=n(`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`}]]),pe=n(`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`}]]),me=n(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),he=n(`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`}]]),E=n(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),ge=n(`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`}]]),D=`maxy-shell-side-px`;function O(){if(typeof window>`u`)return 0;let e=document.querySelector(`.platform > .artefact`)?.getBoundingClientRect();return e&&e.width>0?Math.round(e.width):0}function k(e){if(typeof window>`u`)return e;let t=window.innerWidth,n=Math.max(248,t-480-O());return Math.min(Math.max(e,248),n)}function _e(){if(typeof window>`u`)return 264;try{let e=window.localStorage.getItem(D);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 k(t)}catch{}return 264}function ve({targetSelector:e=`.platform`}){let t=(0,v.useRef)(null),[n,r]=(0,v.useState)(()=>_e()),i=(0,v.useRef)(n);(0,v.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,v.useCallback)(()=>{r(e=>{let t=k(e);return t===e?e:t})},[]);(0,v.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(k(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(D,String(t))}catch{}console.info(`[admin-ui] sidebar-resize px=${t}`)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s)},s=()=>{let e=k(264);r(e);try{window.localStorage.removeItem(D)}catch{}console.info(`[admin-ui] sidebar-resize px=${e}`)};return(0,y.jsx)(`div`,{ref:t,className:`side-resize-handle`,role:`separator`,"aria-orientation":`vertical`,"aria-label":`Resize sidebar`,onPointerDown:o,onDoubleClick:s})}var A=r();function ye({anchorRef:e,onClose:t,className:n,role:r,ariaLabel:i,children:a}){let o=(0,v.useRef)(null),[s,c]=(0,v.useState)({position:`fixed`,visibility:`hidden`}),l=(0,v.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,v.useLayoutEffect)(()=>{if(l(),typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>l());return o.current&&e.observe(o.current),()=>e.disconnect()},[l]),(0,v.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,A.createPortal)((0,y.jsx)(`div`,{ref:o,className:n,role:r,"aria-label":i,style:s,children:a}),document.body)}function be({actions:e,disabled:t}){let[n,r]=(0,v.useState)(!1),[i,a]=(0,v.useState)(null),o=(0,v.useRef)(null),s=(0,v.useCallback)(()=>{r(!1),a(null)},[]);return(0,y.jsxs)(`div`,{className:`conv-actions`,children:[(0,y.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,y.jsx)(se,{size:12})}),n&&(0,y.jsx)(ye,{anchorRef:o,onClose:s,className:`conv-actions-menu`,role:`menu`,children:e.map(e=>e.panel?(0,y.jsxs)(`div`,{className:`conv-actions-menu-disclosure`,children:[(0,y.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,y.jsx)(`span`,{children:e.menuLabel})]}),i===e.key&&(0,y.jsx)(`div`,{className:`conv-actions-menu-panel`,children:e.panel()})]},e.key):(0,y.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,y.jsx)(`span`,{children:e.menuLabel})]},e.key))})]})}var j=`claude-opus-4-8[1m]`,M=`claude-sonnet-5`,N=`claude-haiku-4-5`,P={[j]:`Opus 4.8 (1M context)`,[M]:`Sonnet 5`,[N]:`Haiku 4.5`};function F(e){return P[e]??e}var I=[j,M,N];function L(e){return e.replace(/\[1m\]$/,``)}function xe(e){return I.find(t=>L(t)===L(e))??e}var Se=[`default`,`acceptEdits`,`plan`,`auto`,`bypassPermissions`],R=[`low`,`medium`,`high`,`xhigh`];[...Se],[...R],[...R];var Ce=[j,M,N],we={default:`Ask permissions`,acceptEdits:`Accept edits`,plan:`Plan mode`,auto:`Auto mode`,bypassPermissions:`Bypass permissions`},Te=Se.map(e=>({value:e,label:we[e]??e})),Ee={low:`Low`,medium:`Medium`,high:`High`,xhigh:`Highest`},De=R.map(e=>({value:e,label:Ee[e]??e}));function z(e){if(e){let t=Ce.find(t=>L(t)===L(e));if(t)return t}return j}function Oe({row:e,adminFetch:t,onError:n}){let[r,i]=(0,v.useState)(()=>z(e.model)),[a,o]=(0,v.useState)(``),[s,c]=(0,v.useState)(``),[l,d]=(0,v.useState)(!1),f=(0,v.useRef)(!1);(0,v.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}:{},...s?{effort:s}:{}})});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,y.jsxs)(y.Fragment,{children:[(0,y.jsxs)(`label`,{className:`reseat-field`,children:[(0,y.jsx)(`span`,{children:`Model`}),(0,y.jsx)(`select`,{"data-kind":`model`,value:r,disabled:l,onChange:e=>i(e.target.value),children:Ce.map(e=>(0,y.jsx)(`option`,{value:e,children:F(e)},e))})]}),(0,y.jsxs)(`label`,{className:`reseat-field`,children:[(0,y.jsx)(`span`,{children:`Mode`}),(0,y.jsxs)(`select`,{"data-kind":`mode`,value:a,disabled:l,onChange:e=>o(e.target.value),children:[(0,y.jsx)(`option`,{value:``,children:`Keep current`}),Te.map(e=>(0,y.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,y.jsxs)(`label`,{className:`reseat-field`,children:[(0,y.jsx)(`span`,{children:`Effort`}),(0,y.jsxs)(`select`,{"data-kind":`effort`,value:s,disabled:l,onChange:e=>c(e.target.value),children:[(0,y.jsx)(`option`,{value:``,children:`Keep current`}),De.map(e=>(0,y.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,y.jsx)(`button`,{type:`button`,className:`reseat-apply`,disabled:l,"aria-busy":l,onClick:()=>void p(),children:l?(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(u,{size:12,className:`spin`,"aria-hidden":`true`}),`Resetting…`]}):`Reset`})]})}function B(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 ke(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}async function V(e){if(navigator.clipboard)try{return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.opacity=`0`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}function Ae({target:e,onConfirm:t,onCancel:n}){return e?(0,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,y.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Confirm delete session`,children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsx)(`span`,{children:`Delete this conversation?`}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[`This permanently removes the transcript. It is not moved to Archive and cannot be recovered.`,e.live&&(0,y.jsx)(`div`,{style:{marginTop:`8px`},children:`This session is running; deleting stops it first.`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,style:{display:`flex`,gap:`8px`,padding:`10px 14px`},children:[(0,y.jsx)(S,{variant:`danger`,size:`sm`,style:{flex:1},onClick:t,children:`Delete`}),(0,y.jsx)(S,{variant:`secondary`,size:`sm`,style:{flex:1},onClick:n,children:`Cancel`})]})]})}):null}var je=`auth-refresh-failed`;function Me({error:e,onClose:t}){if(!e)return null;let n=e.reason===je,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,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,y.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Session could not be opened`,children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsx)(`span`,{children:r}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:`✕`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[i,(0,y.jsxs)(`div`,{className:`claude-info-row`,style:{marginTop:`8px`},children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Reason`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:e.reason})]}),e.sessionId&&(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,y.jsxs)(`span`,{className:`claude-info-value`,children:[e.sessionId.slice(0,8),`…`]})]})]})]})})}function Ne(e){let{show:t,onClose:n,claudeInfo:r,messages:i,sessionElapsed:a,sessionId:o,cacheKey:s}=e,[c,l]=(0,v.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,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,y.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`claude-info-icon`}),(0,y.jsx)(`span`,{children:`Claude Code`}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,children:[(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Version`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:r?r.version:`…`})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Email`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:r?.account?.email??`…`})]})]}),(g||m||h>0)&&(0,y.jsxs)(`div`,{className:`claude-info-section`,children:[g&&(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Plan`}),(0,y.jsx)(`span`,{className:`claude-info-value`,style:{textTransform:`capitalize`},children:g})]}),m&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Usage`}),(0,y.jsxs)(`span`,{className:`claude-info-value`,children:[Math.round(m.utilization*100),`%`]})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Resets in`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:ee(m.resetsAt)})]}),m.isUsingOverage&&(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Overage`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:`Active`})]})]}),h>0&&(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Session cost`}),(0,y.jsxs)(`span`,{className:`claude-info-value`,children:[`$`,h<.01?h.toFixed(4):h.toFixed(2)]})]})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,children:[(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Model`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:r?.model??`…`})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Context used`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:f>0?`${f}%`:`—`})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Tokens`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:p>0?ke(p):`—`})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:B(a)})]}),(o||s)&&(()=>{let e=o??s??``;return(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,y.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 V(e)?`copied`:`failed`),setTimeout(()=>l(null),1200)},children:c===`copied`?`copied ✓`:c===`failed`?`copy failed ✕`:`${e.slice(0,8)}…`})]})})()]})]})})}function Pe({open:e,onConnect:t,onClose:n}){return e?(0,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,y.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Claude is not connected`,children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsx)(`span`,{children:`Claude isn’t connected`}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`,display:`flex`,flexDirection:`column`,gap:`10px`},children:[(0,y.jsx)(`span`,{children:`This needs Claude, which is currently disconnected. Connect to continue — the rest of the dashboard stays available either way.`}),(0,y.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,alignItems:`center`},children:[(0,y.jsx)(S,{variant:`primary`,size:`sm`,onClick:t,children:`Connect Claude`}),(0,y.jsx)(`button`,{type:`button`,className:`claude-info-close`,style:{fontSize:`11px`},onClick:n,children:`Not now`})]})]})]})}):null}function H(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 Fe(e){return e.activeMs.thinking+e.activeMs.messaging+e.activeMs.toolUse}function U(e){return e.toLocaleString(`en-GB`)}function Ie(e){return`£${e.toFixed(2)}`}function W({label:e,d:t,bold:n}){let r=n?`th`:`td`;return(0,y.jsxs)(`tr`,{className:n?`usage-total-row`:void 0,children:[(0,y.jsx)(r,{className:`usage-day`,children:e}),(0,y.jsx)(r,{children:H(Fe(t))}),(0,y.jsx)(r,{children:U(t.tokens.output)}),(0,y.jsx)(r,{children:U(t.tokens.input)}),(0,y.jsx)(r,{children:U(t.tokens.cacheWrite)}),(0,y.jsx)(r,{children:U(t.tokens.cacheRead)}),(0,y.jsx)(r,{children:Ie(t.costGBP.opus)}),(0,y.jsx)(r,{children:Ie(t.costGBP.sonnet)})]})}function Le({show:e,onClose:t,sessionId:n,summary:r,loading:i,error:a}){return e?(0,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,y.jsxs)(`div`,{className:`claude-info-modal usage-modal`,onClick:e=>e.stopPropagation(),role:`dialog`,"aria-label":`Session usage and cost`,children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsxs)(`span`,{children:[`Usage & cost`,n?` · ${n.slice(0,8)}`:``]}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:(0,y.jsx)(g,{size:14})})]}),(0,y.jsxs)(`div`,{className:`claude-info-section usage-body`,children:[i&&(0,y.jsx)(`div`,{className:`usage-note`,children:`Computing usage…`}),!i&&a&&(0,y.jsx)(`div`,{className:`usage-note usage-error`,children:a}),!i&&!a&&r&&r.days.length===0&&(0,y.jsx)(`div`,{className:`usage-note`,children:`No usage recorded for this session yet.`}),!i&&!a&&r&&r.days.length>0&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(`div`,{className:`usage-table-scroll`,children:(0,y.jsxs)(`table`,{className:`usage-table`,children:[(0,y.jsx)(`thead`,{children:(0,y.jsxs)(`tr`,{children:[(0,y.jsx)(`th`,{className:`usage-day`,children:`Day`}),(0,y.jsx)(`th`,{children:`Active`}),(0,y.jsx)(`th`,{children:`Output tok`}),(0,y.jsx)(`th`,{children:`Input tok`}),(0,y.jsx)(`th`,{children:`Cache write`}),(0,y.jsx)(`th`,{children:`Cache read`}),(0,y.jsx)(`th`,{children:`Opus 4.8 (£)`}),(0,y.jsx)(`th`,{children:`Sonnet 4.6 (£)`})]})}),(0,y.jsxs)(`tbody`,{children:[r.days.map(e=>(0,y.jsx)(W,{label:e.date,d:e},e.date)),(0,y.jsx)(W,{label:`TOTAL (${r.days.length} d)`,d:r.totals,bold:!0})]})]})}),(0,y.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.`]})]})]})]})}):null}var Re=`https://claude.ai/code`,ze=200,Be=[500,1e3,1500,2e3,2500,3e3,3e3];function Ve(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:`${Re}/${r}`,sameOrigin:!1};let i=n.reason||n.error||`status ${t}`;return{kind:`error`,sessionId:n.sessionId??null,reason:i}}function He(e){if(!e)return``;let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:`medium`,timeStyle:`short`}):``}function Ue(e){let{businessName:n,cacheKey:r,onConnectClaude:i,role:a,userName:u,userAvatar:f,onSelectProjects:g,onSelectPeople:re,onSelectTasks:se,onSelectAgents:ce,onCloseMobileDrawer:b,collapsed:x,selectedWhatsappId:S,onSelectWhatsappConversation:D,initialWhatsappSurface:O=!1,onSelectData:k,onCloseData:_e,initialDataSurface:ve=!1}=e,A=te(r),ye=(0,v.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,y.jsx)(he,{size:12}),panelClassName:`reseat-panel`,panel:()=>(0,y.jsx)(Oe,{row:e,adminFetch:A,onError:e=>B({message:e,failed:!0})})}),[A]),j=o.productName,M=typeof u==`string`?u:u===null?`name unavailable`:n||j,N=(M.trim().charAt(0)||`?`).toUpperCase(),[P,F]=(0,v.useState)(ve?`data`:O?`whatsapp`:`sessions`),[I,L]=(0,v.useState)([]),[xe,Se]=(0,v.useState)(!1),[R,Ce]=(0,v.useState)(null),[we,Te]=(0,v.useState)(!1),[Ee,De]=(0,v.useState)(`file`),[z,B]=(0,v.useState)(null),[ke,V]=(0,v.useState)(null),[je,Ne]=(0,v.useState)(!1),[H,Fe]=(0,v.useState)([]),[U,Ie]=(0,v.useState)(!1),[W,Re]=(0,v.useState)(null),[Ue,We]=(0,v.useState)(!1),[G,Je]=(0,v.useState)(!1),[K,Ye]=(0,v.useState)(!1),[Xe,Ze]=(0,v.useState)(null),[q,Qe]=(0,v.useState)(new Set),[$e,et]=(0,v.useState)(null),[J,tt]=(0,v.useState)(new Set),[nt,rt]=(0,v.useState)(new Set),[it,at]=(0,v.useState)(new Set),[Y,ot]=(0,v.useState)(null),[st,X]=(0,v.useState)(``),[ct,lt]=(0,v.useState)(!1),[ut,dt]=(0,v.useState)(null),[ft,pt]=(0,v.useState)(null),[mt,ht]=(0,v.useState)(!1),[gt,_t]=(0,v.useState)(null),[Z,vt]=(0,v.useState)(!1),yt=(0,v.useRef)(0),[bt,xt]=(0,v.useState)([]),[St,Ct]=(0,v.useState)(!1),[wt,Tt]=(0,v.useState)(null),[Et,Dt]=(0,v.useState)(`whatsapp`),Ot=(0,v.useCallback)(e=>{if(b(),!r){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=no-cache-key`),B({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`),B({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}`),ne(r,e.downloadPath,e.downloadRoot??`data`),B({message:`Downloading ${e.name}`,failed:!1})},[r,b]);(0,v.useEffect)(()=>{if(!z)return;let e=setTimeout(()=>B(null),2500);return()=>clearTimeout(e)},[z]);let kt=(0,v.useCallback)(async()=>{if(r){Te(!0),Ce(null);try{let e=await A(`/api/admin/sidebar-artefacts`);if(!e.ok)throw Error(`status ${e.status}`);L((await e.json()).artefacts??[]),Se(!0)}catch(e){let t=e instanceof Error?e.message:String(e);Ce(`Failed to load artefacts: ${t}`),console.error(`[admin-ui] sidebar-artefacts fetch failed: ${t}`)}finally{Te(!1)}}},[r,A]),Q=(0,v.useCallback)(async()=>{if(!r)return null;let e=++yt.current;We(!0),Re(null);try{let t=await A(`/api/admin/sidebar-sessions`);if(!t.ok)throw Error(`status ${t.status}`);let n=await t.json(),r=n.sessions??[];return e===yt.current?(Fe(r),Ze(n.accountId??null),Ie(!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===yt.current&&Re(`Failed to load sessions: ${n}`),console.error(`[admin-ui] sidebar-sessions fetch failed: ${n}`),null}finally{e===yt.current&&We(!1)}},[r,A]),At=(0,v.useCallback)(async()=>{if(r){Tt(null);try{let e=await A(`/api/whatsapp-reader/conversations`);if(!e.ok)throw Error(`status ${e.status}`);xt((await e.json()).conversations??[]),Ct(!0)}catch(e){let t=e instanceof Error?e.message:String(e);Tt(`Couldn't load conversations.`),console.error(`[admin-ui] channel-convos fetch failed: ${t}`)}}},[r,A]);(0,v.useEffect)(()=>{!r||U||Q()},[r,U,Q]),(0,v.useEffect)(()=>{if(!r)return;let e=null;return At(),e=setInterval(()=>{At()},Ge),()=>{e!==null&&clearInterval(e)}},[r,At]),(0,v.useEffect)(()=>{if(!r)return;let e=null;function t(){console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=poll`),Q()}function n(){e===null&&(e=setInterval(t,Ke))}function i(){e!==null&&(clearInterval(e),e=null)}function a(){document.hidden?i():(t(),n())}return document.hidden||n(),document.addEventListener(`visibilitychange`,a),()=>{i(),document.removeEventListener(`visibilitychange`,a)}},[r,Q]);let jt=(0,v.useMemo)(()=>{let e=new Map;for(let t of _)e.set(t,[]);for(let t of bt)e.get(t.channel)?.push(t);for(let t of _)console.info(`[admin-ui] sidebar-nav surface=${t} count=${e.get(t).length}`);return e},[bt]),Mt={whatsapp:`WhatsApp`,telegram:`Telegram`,webchat:`Webchat`},Nt=()=>{D(null),F(`artefacts`),console.info(`[admin-ui] sidebar-nav surface=artefacts count=${xe?I.length:0} collapsed=${x}`),kt()},$=1.5,Pt=()=>{console.info(`[admin-ui] sidebar-refresh surface=artefacts`),kt()},Ft=()=>{D(null),F(`sessions`),console.info(`[admin-ui] sidebar-nav surface=sessions count=${U?H.length:0} collapsed=${x}`),U||Q()},It=()=>{console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=manual`),Q()},Lt=()=>{F(`data`),console.info(`[admin-ui] sidebar-nav surface=data collapsed=${x}`),k(),b()},Rt=e=>{_e?.(),F(`whatsapp`),Dt(e),console.info(`[admin-ui] sidebar-nav surface=${e} count=${jt.get(e)?.length??0} collapsed=${x}`)},zt=(0,v.useCallback)(async e=>{if(J.has(e.sessionId))return;tt(t=>{let n=new Set(t);return n.add(e.sessionId),n});let t=window.open(``,`_blank`);try{let n=await A(`/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=Ve(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`?(b(),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}`),V(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}`),V({sessionId:e.sessionId,reason:r})}finally{tt(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}},[A,b,J]),Bt=(0,v.useCallback)(async e=>{let t=e.slice(0,8);for(let n=1;n<=Be.length;n++){await new Promise(e=>setTimeout(e,Be[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]),Vt=(0,v.useCallback)(async()=>{if(!Z){vt(!0);try{let e=await A(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({})}),t=await e.json().catch(()=>({})),n=Ve(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?Bt(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`),Ne(!0)):(console.error(`[admin-ui] sidebar-new-session-failed status=${e.status} reason=${n.reason}`),V(n))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-new-session-failed error=${t}`),V({sessionId:null,reason:t})}finally{vt(!1)}}},[A,Z,Bt]),Ht=(0,v.useCallback)((e,t)=>{e.stopPropagation(),et(t)},[]),Ut=(0,v.useCallback)(async(e,t)=>{e.stopPropagation(),dt(t),pt(null),_t(null),ht(!0);try{let e=await A(`/api/admin/session-usage?sessionId=${encodeURIComponent(t.sessionId)}`),n=await e.json().catch(()=>({}));e.ok?pt(n):_t(n.error??`status ${e.status}`)}catch(e){_t(e instanceof Error?e.message:String(e))}finally{ht(!1)}},[A]),Wt=(0,v.useCallback)(async e=>{if(!q.has(e.sessionId)){Qe(t=>{let n=new Set(t);return n.add(e.sessionId),n});try{let t=await A(`/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(()=>({}));console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} status=${t.status} error=${n.error??`unknown`}`),B({message:`Delete failed: ${n.error??`status ${t.status}`}`,failed:!0});return}let n=await t.json();console.info(`[admin-ui] sidebar-session-delete sessionId=${e.sessionId} live=${e.live} confirmed=true pidKilled=${n.pidKilled??`?`} deleted=${n.deleted??`?`}`),Fe(t=>t.filter(t=>t.sessionId!==e.sessionId)),Q()}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} error=${n}`),B({message:`Delete failed: ${n}`,failed:!0})}finally{Qe(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}}},[A,q,Q]),Gt=(0,v.useCallback)(async(e,t)=>{if(e.stopPropagation(),!nt.has(t.sessionId)){rt(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await A(`/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`}`),B({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}`),B({message:`Stop failed: ${n}`,failed:!0})}finally{rt(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[A,nt,Q]),Kt=(0,v.useCallback)(async(e,t,n)=>{if(e.stopPropagation(),!it.has(t.sessionId)){at(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await A(`/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`}`),B({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}`),B({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${r}`,failed:!0})}finally{at(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[A,it,Q]),qt=(0,v.useCallback)(async e=>{let t=st.trim();if(!t){B({message:`Title can’t be empty`,failed:!0});return}if(t.length>ze){B({message:`Title too long (max ${ze})`,failed:!0});return}lt(!0);try{let n=await A(`/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}`),B({message:`Rename failed: ${r}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=ok`),ot(null),X(``),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}`),B({message:`Rename failed: ${n}`,failed:!0})}finally{lt(!1)}},[A,st,Q]);return(0,y.jsxs)(`aside`,{className:`side`,children:[(0,y.jsx)(`div`,{className:`side-new-session-row`,children:(0,y.jsxs)(`button`,{type:`button`,className:`side-new-session`,onClick:Vt,disabled:Z,"aria-busy":Z,children:[(0,y.jsx)(me,{size:14}),(0,y.jsx)(`span`,{children:Z?`Spawning…`:`New session`})]})}),(0,y.jsxs)(`nav`,{className:`side-nav`,children:[(0,y.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=people`),re(),b()},children:[(0,y.jsx)(ge,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`People`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=agents`),ce(),b()},children:[(0,y.jsx)(de,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Agents`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=projects`),g(),b()},children:[(0,y.jsx)(C,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:m().term}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=tasks`),se(),b()},children:[(0,y.jsx)(T,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Tasks`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row${P===`artefacts`?` active`:``}`,onClick:Nt,children:[(0,y.jsx)(s,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Artefacts`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row${P===`sessions`?` active`:``}`,onClick:Ft,children:[(0,y.jsx)(fe,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Sessions`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row${P===`data`?` active`:``}`,onClick:Lt,children:[(0,y.jsx)(c,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Data`}),(0,y.jsx)(`span`,{className:`kbd`})]}),St&&_.filter(e=>jt.get(e).length>0).map(e=>(0,y.jsxs)(`button`,{type:`button`,className:`nav-row${P===`whatsapp`&&Et===e?` active`:``}`,onClick:()=>Rt(e),children:[(0,y.jsx)(h,{channel:e,size:16}),(0,y.jsx)(`span`,{className:`label`,children:Mt[e]}),(0,y.jsx)(`span`,{className:`kbd`})]},e)),wt&&(0,y.jsx)(`div`,{className:`nav-row`,style:{color:`var(--text-tertiary)`,cursor:`default`},"aria-disabled":`true`,children:(0,y.jsx)(`span`,{className:`label`,children:wt})})]}),P===`artefacts`&&(0,y.jsxs)(`div`,{className:`side-list`,children:[(0,y.jsxs)(`div`,{className:`group-head`,children:[(0,y.jsx)(`span`,{children:`Artefacts`}),(0,y.jsxs)(`span`,{className:`group-head-meta`,children:[(0,y.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh artefacts`,"aria-label":`Refresh artefacts`,onClick:Pt,disabled:we,children:(0,y.jsx)(l,{size:12,className:we?`spinning`:void 0})}),(0,y.jsx)(`span`,{children:we?`…`:String(I.length)})]})]}),R&&(0,y.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:R}),xe&&!R&&I.length>0&&(()=>{let e=I.filter(e=>e.kind===`agent-template`).length,t=I.length-e;return(0,y.jsx)(`div`,{className:`artefact-filter-chips`,children:[{key:`all`,label:`All`,count:I.length},{key:`agent`,label:`Agents`,count:e},{key:`file`,label:`Files`,count:t}].map(e=>(0,y.jsxs)(`button`,{type:`button`,className:`artefact-filter-chip${Ee===e.key?` active`:``}`,onClick:()=>De(e.key),disabled:e.count===0&&e.key!==`all`,children:[e.label,(0,y.jsx)(`span`,{className:`artefact-filter-chip-count`,children:e.count})]},e.key))})})(),xe&&!R&&I.length===0&&(0,y.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No artefacts yet`}),I.filter(e=>Ee===`all`?!0:Ee===`agent`?e.kind===`agent-template`:e.kind!==`agent-template`).map(e=>{let t=e.kind===`agent-template`,n=t?de:s,r=He(e.updatedAt),i=e.downloadPath!==null;return(0,y.jsxs)(`button`,{type:`button`,className:`conv`,onClick:()=>Ot(e),disabled:!i,style:i?void 0:{cursor:`default`},title:i?`Download ${e.name}`:`${e.name} can’t be downloaded`,children:[(0,y.jsx)(n,{size:14,className:`conv-icon`,"data-kind":t?`agent`:`file`,"aria-label":t?`agent template`:`file`}),(0,y.jsxs)(`span`,{className:`conv-stack`,children:[(0,y.jsx)(`span`,{className:`conv-name-line`,children:(0,y.jsx)(`span`,{className:`conv-name`,children:e.name})}),r&&(0,y.jsx)(`span`,{className:`conv-timestamp`,children:r})]}),i&&(0,y.jsx)(oe,{size:12,className:`conv-rc-icon`,"aria-hidden":`true`})]},e.id)})]}),P===`sessions`&&(()=>{let e=H.filter(e=>G?!0:!e.isSubagent).filter(e=>K?!0:!e.archived),n=H.some(e=>e.isSubagent),r=H.some(e=>e.archived);return(0,y.jsxs)(`div`,{className:`side-list`,children:[(0,y.jsxs)(`div`,{className:`group-head`,children:[(0,y.jsx)(`span`,{children:`Sessions`}),(0,y.jsxs)(`span`,{className:`group-head-meta`,children:[(0,y.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh sessions`,"aria-label":`Refresh sessions`,onClick:It,disabled:Ue,children:(0,y.jsx)(l,{size:12,className:Ue?`spinning`:void 0})}),(0,y.jsx)(`span`,{children:Ue?`…`:String(e.length)})]})]}),Xe&&(0,y.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,y.jsx)(`code`,{children:Xe})}),(n||r)&&(0,y.jsxs)(`div`,{className:`artefact-filter-chips`,children:[n&&(0,y.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${G?` active`:``}`,"aria-pressed":G,onClick:()=>Je(e=>!e),title:G?`Hide subagent sessions`:`Show subagent sessions`,children:`Subagents`}),r&&(0,y.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${K?` active`:``}`,"aria-pressed":K,onClick:()=>Ye(e=>!e),title:K?`Hide archived sessions`:`Show archived sessions`,children:`Archived`})]}),W&&(0,y.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:W}),U&&!W&&e.length===0&&(0,y.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No sessions yet`}),e.map(e=>{let n=He(e.startedAt),r=J.has(e.sessionId),i=q.has(e.sessionId),a=nt.has(e.sessionId),o=it.has(e.sessionId),s=r||i||a||o,c=()=>{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,y.jsx)(t,{size:12}),busy:r,onClick:()=>{zt(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,y.jsx)(pe,{size:12}),onClick:()=>{c()}},{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,y.jsx)(w,{size:12}),onClick:t=>{Ut(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,y.jsx)(E,{size:12}),busy:a,onClick:t=>{Gt(t,e)}}]:[],e.archived?{key:`unarchive`,label:`Unarchive session ${e.title}`,menuLabel:`Unarchive`,title:`Unarchive (move back to the active list)`,icon:(0,y.jsx)(le,{size:12}),busy:o,onClick:t=>{Kt(t,e,`unarchive`)}}:{key:`archive`,label:`Archive session ${e.title}`,menuLabel:`Archive`,title:`Archive (hide from the list, keeps the conversation resumable)`,icon:(0,y.jsx)(ue,{size:12}),busy:o,onClick:t=>{Kt(t,e,`archive`)}},{key:`rename`,label:`Rename session ${e.title}`,menuLabel:`Rename`,title:`Rename this session`,icon:(0,y.jsx)(ae,{size:12}),busy:ct&&Y===e.sessionId,onClick:t=>{t.stopPropagation(),ot(e.sessionId),X(e.personName??e.title)}},{key:`delete`,label:`Delete session ${e.title}`,menuLabel:`Delete`,title:`Delete session (stops the process, removes the conversation)`,icon:(0,y.jsx)(p,{size:12}),danger:!0,busy:i,onClick:t=>{Ht(t,e)}},ye({sessionId:e.sessionId,model:e.model??null,title:e.personName??e.title})];return(0,y.jsxs)(`div`,{className:`conv conv-with-actions`,children:[(0,y.jsxs)(`div`,{className:`conv-main-static conv-main-clickable`,role:`button`,tabIndex:0,"aria-label":`Open ${e.personName??e.title} in webchat`,onClick:()=>{Y!==e.sessionId&&c()},onKeyDown:t=>{Y!==e.sessionId&&(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),c())},children:[(0,y.jsx)(`span`,{className:`conv-live-dot`,"data-live":e.live?`1`:`0`,"aria-label":e.live?`live session`:`ended session`}),(0,y.jsxs)(`span`,{className:`conv-stack`,children:[(0,y.jsxs)(`span`,{className:`conv-name-line`,children:[e.channel&&(0,y.jsx)(ie,{channel:e.channel,size:13}),Y===e.sessionId?(0,y.jsx)(`input`,{className:`conv-name conv-name-edit`,autoFocus:!0,value:st,disabled:ct,"aria-label":`New title for session ${e.title}`,onChange:e=>X(e.target.value),onClick:e=>e.stopPropagation(),onKeyDown:t=>{t.key===`Enter`?(t.preventDefault(),qt(e)):t.key===`Escape`&&(t.preventDefault(),ot(null),X(``))},onBlur:()=>{Y===e.sessionId&&!ct&&(ot(null),X(``))}}):(0,y.jsx)(`span`,{className:`conv-name`,title:e.personName??e.title,children:e.personName??e.title})]}),(0,y.jsxs)(`span`,{className:`conv-timestamp`,children:[(0,y.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)}),n&&(0,y.jsxs)(`span`,{children:[` · `,n]})]})]})]}),(0,y.jsx)(be,{actions:l,disabled:s})]},e.sessionId)})]})})(),P===`whatsapp`&&(0,y.jsxs)(`div`,{className:`side-list`,children:[(0,y.jsxs)(`div`,{className:`group-head`,children:[(0,y.jsx)(`span`,{children:Mt[Et]}),(0,y.jsxs)(`span`,{className:`group-head-meta`,children:[(0,y.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh conversations`,"aria-label":`Refresh conversations`,onClick:()=>{At()},children:(0,y.jsx)(l,{size:12})}),(0,y.jsx)(`span`,{children:String(jt.get(Et).length)})]})]}),jt.get(Et).map(e=>{let t=He(e.lastMessageAt),n=d(e);return(0,y.jsxs)(`div`,{className:`conv conv-with-actions${e.source===`store`?e.scope===`admin`?` conv-scope-admin`:` conv-scope-public`:``}${S===n?` active`:``}`,children:[(0,y.jsxs)(`button`,{type:`button`,className:`conv-main-static conv-main-btn`,onClick:()=>{D(e),b()},title:e.title,children:[(0,y.jsx)(h,{channel:e.channel,size:14}),(0,y.jsxs)(`span`,{className:`conv-stack`,children:[(0,y.jsx)(`span`,{className:`conv-name-line`,children:(0,y.jsx)(`span`,{className:`conv-name`,children:ee(e)})}),t&&(0,y.jsx)(`span`,{className:`conv-timestamp`,children:t})]})]}),e.source===`session`&&(0,y.jsx)(be,{actions:[ye({sessionId:e.sessionId,model:e.model,title:e.title})],disabled:!1})]},n)})]}),(0,y.jsx)(qe,{}),(0,y.jsxs)(`div`,{className:`side-foot`,children:[(0,y.jsx)(`div`,{className:`avatar`,children:f?(0,y.jsx)(`img`,{src:f,alt:M}):N}),(0,y.jsxs)(`div`,{className:`who`,children:[(0,y.jsx)(`span`,{className:`name`,children:M}),(0,y.jsx)(`span`,{className:`role`,children:a??`operator`})]})]}),z&&(0,y.jsx)(`div`,{className:`copy-toast${z.failed?` copy-toast-failed`:``}`,role:`status`,children:z.message}),(0,y.jsx)(Me,{error:ke,onClose:()=>V(null)}),(0,y.jsx)(Pe,{open:je,onConnect:()=>{Ne(!1),i?.()},onClose:()=>Ne(!1)}),(0,y.jsx)(Ae,{target:$e,onCancel:()=>et(null),onConfirm:()=>{let e=$e;et(null),e&&Wt(e)}}),(0,y.jsx)(Le,{show:ut!==null,onClose:()=>{dt(null),pt(null),_t(null)},sessionId:ut?.sessionId??null,summary:ft,loading:mt,error:gt})]})}var We=5e3,Ge=3e4,Ke=3e4;function qe(){let[e,t]=(0,v.useState)(null);if((0,v.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()},We))}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,y.jsxs)(`div`,{className:f.join(` `),role:`status`,"aria-label":`host CPU and RAM`,children:[(0,y.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,y.jsxs)(`span`,{className:i?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`CPU `,u(n)]}),(0,y.jsx)(`div`,{className:`system-stats__bar`,children:(0,y.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(n)})})]}),(0,y.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,y.jsxs)(`span`,{className:o?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`RAM `,u(r)]}),(0,y.jsx)(`div`,{className:`system-stats__bar`,children:(0,y.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(r)})})]})]})}var G=`admin-sidebar-collapsed`,Je=`admin-sidebar-drawer-open`;function K(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(G)===`1`}catch{return!1}}function Ye(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(G,`1`):window.sessionStorage.removeItem(G)}catch{}}function Xe(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(Je)===`1`}catch{return!1}}function Ze(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(Je,`1`):window.sessionStorage.removeItem(Je)}catch{}}var q=720;function Qe(e,t){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?wa=${encodeURIComponent(t.remoteJid??``)}&acct=${encodeURIComponent(t.accountId??``)}`}}function $e(e){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?data=1`}}function et(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 tt(e,t){return t===`operator`&&e===`chat`||e===`dashboard`?`/`:e===`data`?`/data`:e===`graph`?`/graph`:e===`calendar`?`/calendar`:e===`chat`?`/chat`:`/browser`}function nt(e){let{cacheKey:t,businessName:n,variant:r=`admin`,onLogout:i,onDisconnect:a,disconnecting:o,claudeConnected:s,onConnectClaude:c,userName:l,userAvatar:u,role:p,onOpenConversations:h,children:g,footer:ee}=e,{subAccounts:te,activeAccountId:ne,switching:_,switchAccount:ie}=re(t),[ae,oe]=(0,v.useState)(!0);(0,v.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||oe(n.auth_status!==`dead`&&n.auth_status!==`missing`)}catch{}};t();let n=setInterval(t,6e4);return()=>{e=!0,clearInterval(n)}},[s,r]);let se=s??ae,ce=c??(()=>{window.location.assign(`/?connect=claude`)}),[b,x]=(0,v.useState)(()=>K()),[S,le]=(0,v.useState)(()=>Xe()),[ue,de]=(0,v.useState)(()=>typeof window<`u`&&window.matchMedia(`(max-width: ${q}px)`).matches),[C,w]=(0,v.useState)(()=>typeof window>`u`||J(window.location.pathname,window.location.search)?null:et(window.location.pathname,window.location.search)),[fe]=(0,v.useState)(()=>C!==null),[T,pe]=(0,v.useState)(()=>typeof window>`u`?!1:J(window.location.pathname,window.location.search)),[me]=(0,v.useState)(()=>T);(0,v.useEffect)(()=>{if(typeof window>`u`)return;let e=window.matchMedia(`(max-width: ${q}px)`),t=e=>de(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let he=(0,v.useCallback)(e=>{Ye(e),x(e)},[]),E=(0,v.useCallback)(e=>{Ze(e),le(e)},[]);(0,v.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=${b} drawer=${S}`)},[]),(0,v.useEffect)(()=>{typeof window>`u`||!C||(console.info(`[admin-ui] wa-hydrate route=/ remoteJid=${C.remoteJid??``}`),window.history.replaceState(null,``,`/`))},[]),(0,v.useEffect)(()=>{typeof window>`u`||!T||(console.info(`[admin-ui] data-hydrate route=/`),window.history.replaceState(null,``,`/`))},[]);let ge=(0,v.useCallback)(e=>{if(pe(!1),e===null){w(null);return}let t=typeof window<`u`?window.location.pathname:`/`,n=Qe(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},[]),D=(0,v.useCallback)(()=>{let e=typeof window<`u`?window.location.pathname:`/`,t=$e(e);if(console.info(`[admin-ui] data-open route=${e} via=${t.via}`),t.via===`navigate`){window.location.href=t.href;return}w(null),pe(!0)},[]),O=ue?S:!b,k=(0,v.useCallback)(()=>{if(!(typeof window>`u`))if(window.matchMedia(`(max-width: ${q}px)`).matches){let e=S;console.info(`[admin-ui] header-sidebar-toggle from=${e?`open`:`closed`} mode=drawer`),E(!e)}else{let e=b;console.info(`[admin-ui] header-sidebar-toggle from=${e?`closed`:`open`} mode=collapse`),he(!e)}},[b,S,he,E]),_e=(0,v.useCallback)(e=>{let t=tt(e,r);console.info(`[admin-ui] header-menu-nav target=${e} dest=${t}`),window.location.href=t},[r]),A={collapsed:b,mobileDrawerOpen:S,sidebarOpen:O,onToggleSidebar:k,setMobileDrawerOpen:E,selectedWhatsapp:C,onClearWhatsapp:()=>w(null),dataOpen:T};return r===`operator`?(0,y.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,y.jsx)(f,{businessName:n,variant:r,onNavigate:_e,onOpenConversations:h,onToggleSidebar:k,sidebarOpen:O,onLogout:i,onDisconnect:a,disconnecting:o,cacheKey:t,subAccounts:te,activeAccountId:ne,switchingAccount:_,onSwitchAccount:ie}),(0,y.jsx)(`div`,{className:`platform platform-operator`,children:typeof g==`function`?g(A):g}),ee]}):(0,y.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,y.jsx)(f,{businessName:n,variant:r,onNavigate:_e,onOpenConversations:h,onToggleSidebar:k,sidebarOpen:O,onLogout:i,onDisconnect:a,disconnecting:o,claudeConnected:se,onConnectClaude:ce,cacheKey:t,subAccounts:te,activeAccountId:ne,switchingAccount:_,onSwitchAccount:ie}),(0,y.jsxs)(`div`,{className:`platform${S?` menu-open`:``}${b?` sidebar-collapsed`:``}`,"data-artefact":`closed`,children:[(0,y.jsx)(Ue,{businessName:n,cacheKey:t,onConnectClaude:ce,role:p??null,userName:l,userAvatar:u??null,onSelectProjects:()=>{window.location.href=`/graph?label=${m().label}`},onSelectPeople:()=>{window.location.href=`/graph?label=Person`},onSelectTasks:()=>{window.location.href=`/graph?label=Task`},onSelectAgents:()=>{window.location.href=`/graph?label=Agent`},onCloseMobileDrawer:()=>E(!1),collapsed:b,mobileDrawerOpen:S,selectedWhatsappId:C?d(C):null,onSelectWhatsappConversation:ge,initialWhatsappSurface:fe,onSelectData:D,onCloseData:()=>pe(!1),initialDataSurface:me}),!ue&&(0,y.jsx)(ve,{}),typeof g==`function`?g(A):g]}),S&&(0,y.jsx)(`div`,{className:`sidebar-backdrop menu-open`,"aria-hidden":`true`,onClick:()=>E(!1)}),ee]})}export{de as _,V as a,S as b,M as c,ge as d,E as f,w as g,T as h,Ne as i,xe as l,me as m,Ve as n,N as o,he as p,Pe as r,j as s,nt as t,F as u,ue as v,ce as x,le as y};
|
|
1
|
+
import{o as e}from"./chunk-CAM3fms7.js";import{C as t,D as n,I as r,L as i,M as a,O as o,S as s,T as c,_ as l,b as u,c as d,d as f,h as p,j as m,l as h,m as g,o as ee,p as te,r as ne,s as _,t as re,u as ie,v as ae,w as oe,y as se}from"./useSubAccountSwitcher-BVCMAnWK.js";async function ce(){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 v=e(i(),1),y=a(),b={sm:14,md:16,lg:18},x={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=b[t],h={...e===`send`?{width:x[t],height:x[t]}:{},...u},g=Object.keys(h).length>0;return(0,y.jsxs)(`button`,{type:s,className:p,disabled:i||o,onClick:c,"aria-label":l,style:g?h:void 0,children:[(0,y.jsxs)(`span`,{className:`btn__content`,style:{visibility:i?`hidden`:`visible`},children:[n&&r===`leading`&&(0,y.jsx)(n,{size:m}),f,n&&r===`trailing`&&(0,y.jsx)(n,{size:m})]}),i&&(0,y.jsx)(`span`,{className:`btn__spinner`,children:`✱`})]})}var le=n(`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`}]]),ue=n(`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`}]]),de=n(`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`}]]),C=n(`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`}]]),w=n(`gauge`,[[`path`,{d:`m12 14 4-4`,key:`9kzdfg`}],[`path`,{d:`M3.34 19a10 10 0 1 1 17.32 0`,key:`19p75a`}]]),fe=n(`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`}]]),T=n(`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`}]]),pe=n(`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`}]]),me=n(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),he=n(`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`}]]),E=n(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),ge=n(`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`}]]),D=`maxy-shell-side-px`;function O(){if(typeof window>`u`)return 0;let e=document.querySelector(`.platform > .artefact`)?.getBoundingClientRect();return e&&e.width>0?Math.round(e.width):0}function k(e){if(typeof window>`u`)return e;let t=window.innerWidth,n=Math.max(248,t-480-O());return Math.min(Math.max(e,248),n)}function _e(){if(typeof window>`u`)return 264;try{let e=window.localStorage.getItem(D);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 k(t)}catch{}return 264}function ve({targetSelector:e=`.platform`}){let t=(0,v.useRef)(null),[n,r]=(0,v.useState)(()=>_e()),i=(0,v.useRef)(n);(0,v.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,v.useCallback)(()=>{r(e=>{let t=k(e);return t===e?e:t})},[]);(0,v.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(k(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(D,String(t))}catch{}console.info(`[admin-ui] sidebar-resize px=${t}`)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s)},s=()=>{let e=k(264);r(e);try{window.localStorage.removeItem(D)}catch{}console.info(`[admin-ui] sidebar-resize px=${e}`)};return(0,y.jsx)(`div`,{ref:t,className:`side-resize-handle`,role:`separator`,"aria-orientation":`vertical`,"aria-label":`Resize sidebar`,onPointerDown:o,onDoubleClick:s})}var A=r();function ye({anchorRef:e,onClose:t,className:n,role:r,ariaLabel:i,children:a}){let o=(0,v.useRef)(null),[s,c]=(0,v.useState)({position:`fixed`,visibility:`hidden`}),l=(0,v.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,v.useLayoutEffect)(()=>{if(l(),typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>l());return o.current&&e.observe(o.current),()=>e.disconnect()},[l]),(0,v.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,A.createPortal)((0,y.jsx)(`div`,{ref:o,className:n,role:r,"aria-label":i,style:s,children:a}),document.body)}function be({actions:e,disabled:t}){let[n,r]=(0,v.useState)(!1),[i,a]=(0,v.useState)(null),o=(0,v.useRef)(null),s=(0,v.useCallback)(()=>{r(!1),a(null)},[]);return(0,y.jsxs)(`div`,{className:`conv-actions`,children:[(0,y.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,y.jsx)(se,{size:12})}),n&&(0,y.jsx)(ye,{anchorRef:o,onClose:s,className:`conv-actions-menu`,role:`menu`,children:e.map(e=>e.panel?(0,y.jsxs)(`div`,{className:`conv-actions-menu-disclosure`,children:[(0,y.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,y.jsx)(`span`,{children:e.menuLabel})]}),i===e.key&&(0,y.jsx)(`div`,{className:`conv-actions-menu-panel`,children:e.panel()})]},e.key):(0,y.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,y.jsx)(`span`,{children:e.menuLabel})]},e.key))})]})}var j=`claude-opus-4-8[1m]`,M=`claude-sonnet-5`,N=`claude-haiku-4-5`,P={[j]:`Opus 4.8 (1M context)`,[M]:`Sonnet 5`,[N]:`Haiku 4.5`};function F(e){return P[e]??e}var I=[j,M,N];function L(e){return e.replace(/\[1m\]$/,``)}function xe(e){return I.find(t=>L(t)===L(e))??e}var Se=[`default`,`acceptEdits`,`plan`,`auto`,`bypassPermissions`],R=[`low`,`medium`,`high`,`xhigh`];[...Se],[...R],[...R];var Ce=[j,M,N],we={default:`Ask permissions`,acceptEdits:`Accept edits`,plan:`Plan mode`,auto:`Auto mode`,bypassPermissions:`Bypass permissions`},Te=Se.map(e=>({value:e,label:we[e]??e})),Ee={low:`Low`,medium:`Medium`,high:`High`,xhigh:`Highest`},De=R.map(e=>({value:e,label:Ee[e]??e}));function z(e){if(e){let t=Ce.find(t=>L(t)===L(e));if(t)return t}return j}function Oe({row:e,adminFetch:t,onError:n}){let[r,i]=(0,v.useState)(()=>z(e.model)),[a,o]=(0,v.useState)(``),[s,c]=(0,v.useState)(``),[l,d]=(0,v.useState)(!1),f=(0,v.useRef)(!1);(0,v.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}:{},...s?{effort:s}:{}})});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,y.jsxs)(y.Fragment,{children:[(0,y.jsxs)(`label`,{className:`reseat-field`,children:[(0,y.jsx)(`span`,{children:`Model`}),(0,y.jsx)(`select`,{"data-kind":`model`,value:r,disabled:l,onChange:e=>i(e.target.value),children:Ce.map(e=>(0,y.jsx)(`option`,{value:e,children:F(e)},e))})]}),(0,y.jsxs)(`label`,{className:`reseat-field`,children:[(0,y.jsx)(`span`,{children:`Mode`}),(0,y.jsxs)(`select`,{"data-kind":`mode`,value:a,disabled:l,onChange:e=>o(e.target.value),children:[(0,y.jsx)(`option`,{value:``,children:`Keep current`}),Te.map(e=>(0,y.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,y.jsxs)(`label`,{className:`reseat-field`,children:[(0,y.jsx)(`span`,{children:`Effort`}),(0,y.jsxs)(`select`,{"data-kind":`effort`,value:s,disabled:l,onChange:e=>c(e.target.value),children:[(0,y.jsx)(`option`,{value:``,children:`Keep current`}),De.map(e=>(0,y.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,y.jsx)(`button`,{type:`button`,className:`reseat-apply`,disabled:l,"aria-busy":l,onClick:()=>void p(),children:l?(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(u,{size:12,className:`spin`,"aria-hidden":`true`}),`Resetting…`]}):`Reset`})]})}function B(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 ke(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}async function V(e){if(navigator.clipboard)try{return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.opacity=`0`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}function Ae({target:e,onConfirm:t,onCancel:n}){return e?(0,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,y.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Confirm delete session`,children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsx)(`span`,{children:`Delete this conversation?`}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[`This permanently removes the transcript. It is not moved to Archive and cannot be recovered.`,e.live&&(0,y.jsx)(`div`,{style:{marginTop:`8px`},children:`This session is running; deleting stops it first.`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,style:{display:`flex`,gap:`8px`,padding:`10px 14px`},children:[(0,y.jsx)(S,{variant:`danger`,size:`sm`,style:{flex:1},onClick:t,children:`Delete`}),(0,y.jsx)(S,{variant:`secondary`,size:`sm`,style:{flex:1},onClick:n,children:`Cancel`})]})]})}):null}var je=`auth-refresh-failed`;function Me({error:e,onClose:t}){if(!e)return null;let n=e.reason===je,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,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,y.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Session could not be opened`,children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsx)(`span`,{children:r}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:`✕`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[i,(0,y.jsxs)(`div`,{className:`claude-info-row`,style:{marginTop:`8px`},children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Reason`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:e.reason})]}),e.sessionId&&(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,y.jsxs)(`span`,{className:`claude-info-value`,children:[e.sessionId.slice(0,8),`…`]})]})]})]})})}function Ne(e){let{show:t,onClose:n,claudeInfo:r,messages:i,sessionElapsed:a,sessionId:o,cacheKey:s}=e,[c,l]=(0,v.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,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,y.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`claude-info-icon`}),(0,y.jsx)(`span`,{children:`Claude Code`}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,children:[(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Version`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:r?r.version:`…`})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Email`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:r?.account?.email??`…`})]})]}),(g||m||h>0)&&(0,y.jsxs)(`div`,{className:`claude-info-section`,children:[g&&(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Plan`}),(0,y.jsx)(`span`,{className:`claude-info-value`,style:{textTransform:`capitalize`},children:g})]}),m&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Usage`}),(0,y.jsxs)(`span`,{className:`claude-info-value`,children:[Math.round(m.utilization*100),`%`]})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Resets in`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:ee(m.resetsAt)})]}),m.isUsingOverage&&(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Overage`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:`Active`})]})]}),h>0&&(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Session cost`}),(0,y.jsxs)(`span`,{className:`claude-info-value`,children:[`$`,h<.01?h.toFixed(4):h.toFixed(2)]})]})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,children:[(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Model`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:r?.model??`…`})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Context used`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:f>0?`${f}%`:`—`})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Tokens`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:p>0?ke(p):`—`})]}),(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,y.jsx)(`span`,{className:`claude-info-value`,children:B(a)})]}),(o||s)&&(()=>{let e=o??s??``;return(0,y.jsxs)(`div`,{className:`claude-info-row`,children:[(0,y.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,y.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 V(e)?`copied`:`failed`),setTimeout(()=>l(null),1200)},children:c===`copied`?`copied ✓`:c===`failed`?`copy failed ✕`:`${e.slice(0,8)}…`})]})})()]})]})})}function Pe({open:e,onConnect:t,onClose:n}){return e?(0,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,y.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Claude is not connected`,children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsx)(`span`,{children:`Claude isn’t connected`}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,y.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`,display:`flex`,flexDirection:`column`,gap:`10px`},children:[(0,y.jsx)(`span`,{children:`This needs Claude, which is currently disconnected. Connect to continue — the rest of the dashboard stays available either way.`}),(0,y.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,alignItems:`center`},children:[(0,y.jsx)(S,{variant:`primary`,size:`sm`,onClick:t,children:`Connect Claude`}),(0,y.jsx)(`button`,{type:`button`,className:`claude-info-close`,style:{fontSize:`11px`},onClick:n,children:`Not now`})]})]})]})}):null}function H(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 Fe(e){return e.activeMs.thinking+e.activeMs.messaging+e.activeMs.toolUse}function U(e){return e.toLocaleString(`en-GB`)}function Ie(e){return`£${e.toFixed(2)}`}function W({label:e,d:t,bold:n}){let r=n?`th`:`td`;return(0,y.jsxs)(`tr`,{className:n?`usage-total-row`:void 0,children:[(0,y.jsx)(r,{className:`usage-day`,children:e}),(0,y.jsx)(r,{children:H(Fe(t))}),(0,y.jsx)(r,{children:U(t.tokens.output)}),(0,y.jsx)(r,{children:U(t.tokens.input)}),(0,y.jsx)(r,{children:U(t.tokens.cacheWrite)}),(0,y.jsx)(r,{children:U(t.tokens.cacheRead)}),(0,y.jsx)(r,{children:Ie(t.costGBP.opus)}),(0,y.jsx)(r,{children:Ie(t.costGBP.sonnet)})]})}function Le({show:e,onClose:t,sessionId:n,summary:r,loading:i,error:a}){return e?(0,y.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,y.jsxs)(`div`,{className:`claude-info-modal usage-modal`,onClick:e=>e.stopPropagation(),role:`dialog`,"aria-label":`Session usage and cost`,children:[(0,y.jsxs)(`div`,{className:`claude-info-header`,children:[(0,y.jsxs)(`span`,{children:[`Usage & cost`,n?` · ${n.slice(0,8)}`:``]}),(0,y.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:(0,y.jsx)(g,{size:14})})]}),(0,y.jsxs)(`div`,{className:`claude-info-section usage-body`,children:[i&&(0,y.jsx)(`div`,{className:`usage-note`,children:`Computing usage…`}),!i&&a&&(0,y.jsx)(`div`,{className:`usage-note usage-error`,children:a}),!i&&!a&&r&&r.days.length===0&&(0,y.jsx)(`div`,{className:`usage-note`,children:`No usage recorded for this session yet.`}),!i&&!a&&r&&r.days.length>0&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(`div`,{className:`usage-table-scroll`,children:(0,y.jsxs)(`table`,{className:`usage-table`,children:[(0,y.jsx)(`thead`,{children:(0,y.jsxs)(`tr`,{children:[(0,y.jsx)(`th`,{className:`usage-day`,children:`Day`}),(0,y.jsx)(`th`,{children:`Active`}),(0,y.jsx)(`th`,{children:`Output tok`}),(0,y.jsx)(`th`,{children:`Input tok`}),(0,y.jsx)(`th`,{children:`Cache write`}),(0,y.jsx)(`th`,{children:`Cache read`}),(0,y.jsx)(`th`,{children:`Opus 4.8 (£)`}),(0,y.jsx)(`th`,{children:`Sonnet 4.6 (£)`})]})}),(0,y.jsxs)(`tbody`,{children:[r.days.map(e=>(0,y.jsx)(W,{label:e.date,d:e},e.date)),(0,y.jsx)(W,{label:`TOTAL (${r.days.length} d)`,d:r.totals,bold:!0})]})]})}),(0,y.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.`]})]})]})]})}):null}var Re=`https://claude.ai/code`,ze=200,Be=[500,1e3,1500,2e3,2500,3e3,3e3];function Ve(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:`${Re}/${r}`,sameOrigin:!1};let i=n.reason||n.error||`status ${t}`;return{kind:`error`,sessionId:n.sessionId??null,reason:i}}function He(e){if(!e)return``;let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:`medium`,timeStyle:`short`}):``}function Ue(e){let{businessName:n,cacheKey:r,onConnectClaude:i,role:a,userName:u,userAvatar:f,onSelectProjects:g,onSelectPeople:re,onSelectTasks:se,onSelectAgents:ce,onCloseMobileDrawer:b,collapsed:x,selectedWhatsappId:S,onSelectWhatsappConversation:D,initialWhatsappSurface:O=!1,onSelectData:k,onCloseData:_e,initialDataSurface:ve=!1}=e,A=te(r),ye=(0,v.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,y.jsx)(he,{size:12}),panelClassName:`reseat-panel`,panel:()=>(0,y.jsx)(Oe,{row:e,adminFetch:A,onError:e=>B({message:e,failed:!0})})}),[A]),j=o.productName,M=typeof u==`string`?u:u===null?`name unavailable`:n||j,N=(M.trim().charAt(0)||`?`).toUpperCase(),[P,F]=(0,v.useState)(ve?`data`:O?`whatsapp`:`sessions`),[I,L]=(0,v.useState)([]),[xe,Se]=(0,v.useState)(!1),[R,Ce]=(0,v.useState)(null),[we,Te]=(0,v.useState)(!1),[Ee,De]=(0,v.useState)(`file`),[z,B]=(0,v.useState)(null),[ke,V]=(0,v.useState)(null),[je,Ne]=(0,v.useState)(!1),[H,Fe]=(0,v.useState)([]),[U,Ie]=(0,v.useState)(!1),[W,Re]=(0,v.useState)(null),[Ue,We]=(0,v.useState)(!1),[G,Je]=(0,v.useState)(!1),[K,Ye]=(0,v.useState)(!1),[Xe,Ze]=(0,v.useState)(null),[q,Qe]=(0,v.useState)(new Set),[$e,et]=(0,v.useState)(null),[J,tt]=(0,v.useState)(new Set),[nt,rt]=(0,v.useState)(new Set),[it,at]=(0,v.useState)(new Set),[Y,ot]=(0,v.useState)(null),[st,X]=(0,v.useState)(``),[ct,lt]=(0,v.useState)(!1),[ut,dt]=(0,v.useState)(null),[ft,pt]=(0,v.useState)(null),[mt,ht]=(0,v.useState)(!1),[gt,_t]=(0,v.useState)(null),[Z,vt]=(0,v.useState)(!1),yt=(0,v.useRef)(0),[bt,xt]=(0,v.useState)([]),[St,Ct]=(0,v.useState)(!1),[wt,Tt]=(0,v.useState)(null),[Et,Dt]=(0,v.useState)(`whatsapp`),Ot=(0,v.useCallback)(e=>{if(b(),!r){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=no-cache-key`),B({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`),B({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}`),ne(r,e.downloadPath,e.downloadRoot??`data`),B({message:`Downloading ${e.name}`,failed:!1})},[r,b]);(0,v.useEffect)(()=>{if(!z)return;let e=setTimeout(()=>B(null),2500);return()=>clearTimeout(e)},[z]);let kt=(0,v.useCallback)(async()=>{if(r){Te(!0),Ce(null);try{let e=await A(`/api/admin/sidebar-artefacts`);if(!e.ok)throw Error(`status ${e.status}`);L((await e.json()).artefacts??[]),Se(!0)}catch(e){let t=e instanceof Error?e.message:String(e);Ce(`Failed to load artefacts: ${t}`),console.error(`[admin-ui] sidebar-artefacts fetch failed: ${t}`)}finally{Te(!1)}}},[r,A]),Q=(0,v.useCallback)(async()=>{if(!r)return null;let e=++yt.current;We(!0),Re(null);try{let t=await A(`/api/admin/sidebar-sessions`);if(!t.ok)throw Error(`status ${t.status}`);let n=await t.json(),r=n.sessions??[];return e===yt.current?(Fe(r),Ze(n.accountId??null),Ie(!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===yt.current&&Re(`Failed to load sessions: ${n}`),console.error(`[admin-ui] sidebar-sessions fetch failed: ${n}`),null}finally{e===yt.current&&We(!1)}},[r,A]),At=(0,v.useCallback)(async()=>{if(r){Tt(null);try{let e=await A(`/api/whatsapp-reader/conversations`);if(!e.ok)throw Error(`status ${e.status}`);xt((await e.json()).conversations??[]),Ct(!0)}catch(e){let t=e instanceof Error?e.message:String(e);Tt(`Couldn't load conversations.`),console.error(`[admin-ui] channel-convos fetch failed: ${t}`)}}},[r,A]);(0,v.useEffect)(()=>{!r||U||Q()},[r,U,Q]),(0,v.useEffect)(()=>{if(!r)return;let e=null;return At(),e=setInterval(()=>{At()},Ge),()=>{e!==null&&clearInterval(e)}},[r,At]),(0,v.useEffect)(()=>{if(!r)return;let e=null;function t(){console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=poll`),Q()}function n(){e===null&&(e=setInterval(t,Ke))}function i(){e!==null&&(clearInterval(e),e=null)}function a(){document.hidden?i():(t(),n())}return document.hidden||n(),document.addEventListener(`visibilitychange`,a),()=>{i(),document.removeEventListener(`visibilitychange`,a)}},[r,Q]);let jt=(0,v.useMemo)(()=>{let e=new Map;for(let t of _)e.set(t,[]);for(let t of bt)e.get(t.channel)?.push(t);for(let t of _)console.info(`[admin-ui] sidebar-nav surface=${t} count=${e.get(t).length}`);return e},[bt]),Mt={whatsapp:`WhatsApp`,telegram:`Telegram`,webchat:`Webchat`},Nt=()=>{D(null),F(`artefacts`),console.info(`[admin-ui] sidebar-nav surface=artefacts count=${xe?I.length:0} collapsed=${x}`),kt()},$=1.5,Pt=()=>{console.info(`[admin-ui] sidebar-refresh surface=artefacts`),kt()},Ft=()=>{D(null),F(`sessions`),console.info(`[admin-ui] sidebar-nav surface=sessions count=${U?H.length:0} collapsed=${x}`),U||Q()},It=()=>{console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=manual`),Q()},Lt=()=>{F(`data`),console.info(`[admin-ui] sidebar-nav surface=data collapsed=${x}`),k(),b()},Rt=e=>{_e?.(),F(`whatsapp`),Dt(e),console.info(`[admin-ui] sidebar-nav surface=${e} count=${jt.get(e)?.length??0} collapsed=${x}`)},zt=(0,v.useCallback)(async e=>{if(J.has(e.sessionId))return;tt(t=>{let n=new Set(t);return n.add(e.sessionId),n});let t=window.open(``,`_blank`);try{let n=await A(`/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=Ve(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`?(b(),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}`),V(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}`),V({sessionId:e.sessionId,reason:r})}finally{tt(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}},[A,b,J]),Bt=(0,v.useCallback)(async e=>{let t=e.slice(0,8);for(let n=1;n<=Be.length;n++){await new Promise(e=>setTimeout(e,Be[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]),Vt=(0,v.useCallback)(async()=>{if(!Z){vt(!0);try{let e=await A(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({})}),t=await e.json().catch(()=>({})),n=Ve(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?Bt(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`),Ne(!0)):(console.error(`[admin-ui] sidebar-new-session-failed status=${e.status} reason=${n.reason}`),V(n))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-new-session-failed error=${t}`),V({sessionId:null,reason:t})}finally{vt(!1)}}},[A,Z,Bt]),Ht=(0,v.useCallback)((e,t)=>{e.stopPropagation(),et(t)},[]),Ut=(0,v.useCallback)(async(e,t)=>{e.stopPropagation(),dt(t),pt(null),_t(null),ht(!0);try{let e=await A(`/api/admin/session-usage?sessionId=${encodeURIComponent(t.sessionId)}`),n=await e.json().catch(()=>({}));e.ok?pt(n):_t(n.error??`status ${e.status}`)}catch(e){_t(e instanceof Error?e.message:String(e))}finally{ht(!1)}},[A]),Wt=(0,v.useCallback)(async e=>{if(!q.has(e.sessionId)){Qe(t=>{let n=new Set(t);return n.add(e.sessionId),n});try{let t=await A(`/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(()=>({}));console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} status=${t.status} error=${n.error??`unknown`}`),B({message:`Delete failed: ${n.error??`status ${t.status}`}`,failed:!0});return}let n=await t.json();console.info(`[admin-ui] sidebar-session-delete sessionId=${e.sessionId} live=${e.live} confirmed=true pidKilled=${n.pidKilled??`?`} deleted=${n.deleted??`?`}`),Fe(t=>t.filter(t=>t.sessionId!==e.sessionId)),Q()}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} error=${n}`),B({message:`Delete failed: ${n}`,failed:!0})}finally{Qe(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}}},[A,q,Q]),Gt=(0,v.useCallback)(async(e,t)=>{if(e.stopPropagation(),!nt.has(t.sessionId)){rt(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await A(`/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`}`),B({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}`),B({message:`Stop failed: ${n}`,failed:!0})}finally{rt(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[A,nt,Q]),Kt=(0,v.useCallback)(async(e,t,n)=>{if(e.stopPropagation(),!it.has(t.sessionId)){at(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await A(`/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`}`),B({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}`),B({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${r}`,failed:!0})}finally{at(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[A,it,Q]),qt=(0,v.useCallback)(async e=>{let t=st.trim();if(!t){B({message:`Title can’t be empty`,failed:!0});return}if(t.length>ze){B({message:`Title too long (max ${ze})`,failed:!0});return}lt(!0);try{let n=await A(`/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}`),B({message:`Rename failed: ${r}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=ok`),ot(null),X(``),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}`),B({message:`Rename failed: ${n}`,failed:!0})}finally{lt(!1)}},[A,st,Q]);return(0,y.jsxs)(`aside`,{className:`side`,children:[(0,y.jsx)(`div`,{className:`side-new-session-row`,children:(0,y.jsxs)(`button`,{type:`button`,className:`side-new-session`,onClick:Vt,disabled:Z,"aria-busy":Z,children:[(0,y.jsx)(me,{size:14}),(0,y.jsx)(`span`,{children:Z?`Spawning…`:`New session`})]})}),(0,y.jsxs)(`nav`,{className:`side-nav`,children:[(0,y.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=people`),re(),b()},children:[(0,y.jsx)(ge,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`People`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=agents`),ce(),b()},children:[(0,y.jsx)(de,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Agents`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=projects`),g(),b()},children:[(0,y.jsx)(C,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:m().term}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=tasks`),se(),b()},children:[(0,y.jsx)(T,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Tasks`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row${P===`artefacts`?` active`:``}`,onClick:Nt,children:[(0,y.jsx)(s,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Artefacts`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row${P===`sessions`?` active`:``}`,onClick:Ft,children:[(0,y.jsx)(fe,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Sessions`}),(0,y.jsx)(`span`,{className:`kbd`})]}),(0,y.jsxs)(`button`,{type:`button`,className:`nav-row${P===`data`?` active`:``}`,onClick:Lt,children:[(0,y.jsx)(c,{size:20,strokeWidth:$}),(0,y.jsx)(`span`,{className:`label`,children:`Data`}),(0,y.jsx)(`span`,{className:`kbd`})]}),St&&_.filter(e=>jt.get(e).length>0).map(e=>(0,y.jsxs)(`button`,{type:`button`,className:`nav-row${P===`whatsapp`&&Et===e?` active`:``}`,onClick:()=>Rt(e),children:[(0,y.jsx)(h,{channel:e,size:16}),(0,y.jsx)(`span`,{className:`label`,children:Mt[e]}),(0,y.jsx)(`span`,{className:`kbd`})]},e)),wt&&(0,y.jsx)(`div`,{className:`nav-row`,style:{color:`var(--text-tertiary)`,cursor:`default`},"aria-disabled":`true`,children:(0,y.jsx)(`span`,{className:`label`,children:wt})})]}),P===`artefacts`&&(0,y.jsxs)(`div`,{className:`side-list`,children:[(0,y.jsxs)(`div`,{className:`group-head`,children:[(0,y.jsx)(`span`,{children:`Artefacts`}),(0,y.jsxs)(`span`,{className:`group-head-meta`,children:[(0,y.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh artefacts`,"aria-label":`Refresh artefacts`,onClick:Pt,disabled:we,children:(0,y.jsx)(l,{size:12,className:we?`spinning`:void 0})}),(0,y.jsx)(`span`,{children:we?`…`:String(I.length)})]})]}),R&&(0,y.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:R}),xe&&!R&&I.length>0&&(()=>{let e=I.filter(e=>e.kind===`agent-template`).length,t=I.length-e;return(0,y.jsx)(`div`,{className:`artefact-filter-chips`,children:[{key:`all`,label:`All`,count:I.length},{key:`agent`,label:`Agents`,count:e},{key:`file`,label:`Files`,count:t}].map(e=>(0,y.jsxs)(`button`,{type:`button`,className:`artefact-filter-chip${Ee===e.key?` active`:``}`,onClick:()=>De(e.key),disabled:e.count===0&&e.key!==`all`,children:[e.label,(0,y.jsx)(`span`,{className:`artefact-filter-chip-count`,children:e.count})]},e.key))})})(),xe&&!R&&I.length===0&&(0,y.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No artefacts yet`}),I.filter(e=>Ee===`all`?!0:Ee===`agent`?e.kind===`agent-template`:e.kind!==`agent-template`).map(e=>{let t=e.kind===`agent-template`,n=t?de:s,r=He(e.updatedAt),i=e.downloadPath!==null;return(0,y.jsxs)(`button`,{type:`button`,className:`conv`,onClick:()=>Ot(e),disabled:!i,style:i?void 0:{cursor:`default`},title:i?`Download ${e.name}`:`${e.name} can’t be downloaded`,children:[(0,y.jsx)(n,{size:14,className:`conv-icon`,"data-kind":t?`agent`:`file`,"aria-label":t?`agent template`:`file`}),(0,y.jsxs)(`span`,{className:`conv-stack`,children:[(0,y.jsx)(`span`,{className:`conv-name-line`,children:(0,y.jsx)(`span`,{className:`conv-name`,children:e.name})}),r&&(0,y.jsx)(`span`,{className:`conv-timestamp`,children:r})]}),i&&(0,y.jsx)(oe,{size:12,className:`conv-rc-icon`,"aria-hidden":`true`})]},e.id)})]}),P===`sessions`&&(()=>{let e=H.filter(e=>G?!0:!e.isSubagent).filter(e=>K?!0:!e.archived),n=H.some(e=>e.isSubagent),r=H.some(e=>e.archived);return(0,y.jsxs)(`div`,{className:`side-list`,children:[(0,y.jsxs)(`div`,{className:`group-head`,children:[(0,y.jsx)(`span`,{children:`Sessions`}),(0,y.jsxs)(`span`,{className:`group-head-meta`,children:[(0,y.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh sessions`,"aria-label":`Refresh sessions`,onClick:It,disabled:Ue,children:(0,y.jsx)(l,{size:12,className:Ue?`spinning`:void 0})}),(0,y.jsx)(`span`,{children:Ue?`…`:String(e.length)})]})]}),Xe&&(0,y.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,y.jsx)(`code`,{children:Xe})}),(n||r)&&(0,y.jsxs)(`div`,{className:`artefact-filter-chips`,children:[n&&(0,y.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${G?` active`:``}`,"aria-pressed":G,onClick:()=>Je(e=>!e),title:G?`Hide subagent sessions`:`Show subagent sessions`,children:`Subagents`}),r&&(0,y.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${K?` active`:``}`,"aria-pressed":K,onClick:()=>Ye(e=>!e),title:K?`Hide archived sessions`:`Show archived sessions`,children:`Archived`})]}),W&&(0,y.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:W}),U&&!W&&e.length===0&&(0,y.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No sessions yet`}),e.map(e=>{let n=He(e.startedAt),r=J.has(e.sessionId),i=q.has(e.sessionId),a=nt.has(e.sessionId),o=it.has(e.sessionId),s=r||i||a||o,c=()=>{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,y.jsx)(t,{size:12}),busy:r,onClick:()=>{zt(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,y.jsx)(pe,{size:12}),onClick:()=>{c()}},{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,y.jsx)(w,{size:12}),onClick:t=>{Ut(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,y.jsx)(E,{size:12}),busy:a,onClick:t=>{Gt(t,e)}}]:[],e.archived?{key:`unarchive`,label:`Unarchive session ${e.title}`,menuLabel:`Unarchive`,title:`Unarchive (move back to the active list)`,icon:(0,y.jsx)(le,{size:12}),busy:o,onClick:t=>{Kt(t,e,`unarchive`)}}:{key:`archive`,label:`Archive session ${e.title}`,menuLabel:`Archive`,title:`Archive (hide from the list, keeps the conversation resumable)`,icon:(0,y.jsx)(ue,{size:12}),busy:o,onClick:t=>{Kt(t,e,`archive`)}},{key:`rename`,label:`Rename session ${e.title}`,menuLabel:`Rename`,title:`Rename this session`,icon:(0,y.jsx)(ae,{size:12}),busy:ct&&Y===e.sessionId,onClick:t=>{t.stopPropagation(),ot(e.sessionId),X(e.personName??e.title)}},{key:`delete`,label:`Delete session ${e.title}`,menuLabel:`Delete`,title:`Delete session (stops the process, removes the conversation)`,icon:(0,y.jsx)(p,{size:12}),danger:!0,busy:i,onClick:t=>{Ht(t,e)}},ye({sessionId:e.sessionId,model:e.model??null,title:e.personName??e.title})];return(0,y.jsxs)(`div`,{className:`conv conv-with-actions`,children:[(0,y.jsxs)(`div`,{className:`conv-main-static conv-main-clickable`,role:`button`,tabIndex:0,"aria-label":`Open ${e.personName??e.title} in webchat`,onClick:()=>{Y!==e.sessionId&&c()},onKeyDown:t=>{Y!==e.sessionId&&(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),c())},children:[(0,y.jsx)(`span`,{className:`conv-live-dot`,"data-live":e.live?`1`:`0`,"aria-label":e.live?`live session`:`ended session`}),(0,y.jsxs)(`span`,{className:`conv-stack`,children:[(0,y.jsxs)(`span`,{className:`conv-name-line`,children:[e.channel&&(0,y.jsx)(ie,{channel:e.channel,size:13}),Y===e.sessionId?(0,y.jsx)(`input`,{className:`conv-name conv-name-edit`,autoFocus:!0,value:st,disabled:ct,"aria-label":`New title for session ${e.title}`,onChange:e=>X(e.target.value),onClick:e=>e.stopPropagation(),onKeyDown:t=>{t.key===`Enter`?(t.preventDefault(),qt(e)):t.key===`Escape`&&(t.preventDefault(),ot(null),X(``))},onBlur:()=>{Y===e.sessionId&&!ct&&(ot(null),X(``))}}):(0,y.jsx)(`span`,{className:`conv-name`,title:e.personName??e.title,children:e.personName??e.title})]}),(0,y.jsxs)(`span`,{className:`conv-timestamp`,children:[(0,y.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)}),n&&(0,y.jsxs)(`span`,{children:[` · `,n]})]})]})]}),(0,y.jsx)(be,{actions:l,disabled:s})]},e.sessionId)})]})})(),P===`whatsapp`&&(0,y.jsxs)(`div`,{className:`side-list`,children:[(0,y.jsxs)(`div`,{className:`group-head`,children:[(0,y.jsx)(`span`,{children:Mt[Et]}),(0,y.jsxs)(`span`,{className:`group-head-meta`,children:[(0,y.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh conversations`,"aria-label":`Refresh conversations`,onClick:()=>{At()},children:(0,y.jsx)(l,{size:12})}),(0,y.jsx)(`span`,{children:String(jt.get(Et).length)})]})]}),jt.get(Et).map(e=>{let t=He(e.lastMessageAt),n=d(e);return(0,y.jsxs)(`div`,{className:`conv conv-with-actions${e.source===`store`?e.scope===`admin`?` conv-scope-admin`:` conv-scope-public`:``}${S===n?` active`:``}`,children:[(0,y.jsxs)(`button`,{type:`button`,className:`conv-main-static conv-main-btn`,onClick:()=>{D(e),b()},title:e.title,children:[(0,y.jsx)(h,{channel:e.channel,size:14}),(0,y.jsxs)(`span`,{className:`conv-stack`,children:[(0,y.jsx)(`span`,{className:`conv-name-line`,children:(0,y.jsx)(`span`,{className:`conv-name`,children:ee(e)})}),t&&(0,y.jsx)(`span`,{className:`conv-timestamp`,children:t})]})]}),e.source===`session`&&(0,y.jsx)(be,{actions:[ye({sessionId:e.sessionId,model:e.model,title:e.title})],disabled:!1})]},n)})]}),(0,y.jsx)(qe,{}),(0,y.jsxs)(`div`,{className:`side-foot`,children:[(0,y.jsx)(`div`,{className:`avatar`,children:f?(0,y.jsx)(`img`,{src:f,alt:M}):N}),(0,y.jsxs)(`div`,{className:`who`,children:[(0,y.jsx)(`span`,{className:`name`,children:M}),(0,y.jsx)(`span`,{className:`role`,children:a??`operator`})]})]}),z&&(0,y.jsx)(`div`,{className:`copy-toast${z.failed?` copy-toast-failed`:``}`,role:`status`,children:z.message}),(0,y.jsx)(Me,{error:ke,onClose:()=>V(null)}),(0,y.jsx)(Pe,{open:je,onConnect:()=>{Ne(!1),i?.()},onClose:()=>Ne(!1)}),(0,y.jsx)(Ae,{target:$e,onCancel:()=>et(null),onConfirm:()=>{let e=$e;et(null),e&&Wt(e)}}),(0,y.jsx)(Le,{show:ut!==null,onClose:()=>{dt(null),pt(null),_t(null)},sessionId:ut?.sessionId??null,summary:ft,loading:mt,error:gt})]})}var We=5e3,Ge=3e4,Ke=3e4;function qe(){let[e,t]=(0,v.useState)(null);if((0,v.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()},We))}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,y.jsxs)(`div`,{className:f.join(` `),role:`status`,"aria-label":`host CPU and RAM`,children:[(0,y.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,y.jsxs)(`span`,{className:i?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`CPU `,u(n)]}),(0,y.jsx)(`div`,{className:`system-stats__bar`,children:(0,y.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(n)})})]}),(0,y.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,y.jsxs)(`span`,{className:o?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`RAM `,u(r)]}),(0,y.jsx)(`div`,{className:`system-stats__bar`,children:(0,y.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(r)})})]})]})}var G=`admin-sidebar-collapsed`,Je=`admin-sidebar-drawer-open`;function K(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(G)===`1`}catch{return!1}}function Ye(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(G,`1`):window.sessionStorage.removeItem(G)}catch{}}function Xe(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(Je)===`1`}catch{return!1}}function Ze(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(Je,`1`):window.sessionStorage.removeItem(Je)}catch{}}var q=720;function Qe(e,t){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?wa=${encodeURIComponent(t.remoteJid??``)}&acct=${encodeURIComponent(t.accountId??``)}`}}function $e(e){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?data=1`}}function et(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 tt(e,t){return t===`operator`&&e===`chat`||e===`dashboard`?`/`:e===`data`?`/data`:e===`graph`?`/graph`:e===`calendar`?`/calendar`:e===`chat`?`/chat`:`/browser`}function nt(e){let{cacheKey:t,businessName:n,variant:r=`admin`,onLogout:i,onDisconnect:a,disconnecting:o,claudeConnected:s,onConnectClaude:c,userName:l,userAvatar:u,role:p,onOpenConversations:h,children:g,footer:ee}=e,{subAccounts:te,activeAccountId:ne,switching:_,switchAccount:ie}=re(t),[ae,oe]=(0,v.useState)(!0);(0,v.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||oe(n.auth_status!==`dead`&&n.auth_status!==`missing`)}catch{}};t();let n=setInterval(t,6e4);return()=>{e=!0,clearInterval(n)}},[s,r]);let se=s??ae,ce=c??(()=>{window.location.assign(`/?connect=claude`)}),[b,x]=(0,v.useState)(()=>K()),[S,le]=(0,v.useState)(()=>Xe()),[ue,de]=(0,v.useState)(()=>typeof window<`u`&&window.matchMedia(`(max-width: ${q}px)`).matches),[C,w]=(0,v.useState)(()=>typeof window>`u`||J(window.location.pathname,window.location.search)?null:et(window.location.pathname,window.location.search)),[fe]=(0,v.useState)(()=>C!==null),[T,pe]=(0,v.useState)(()=>typeof window>`u`?!1:J(window.location.pathname,window.location.search)),[me]=(0,v.useState)(()=>T);(0,v.useEffect)(()=>{if(typeof window>`u`)return;let e=window.matchMedia(`(max-width: ${q}px)`),t=e=>de(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let he=(0,v.useCallback)(e=>{Ye(e),x(e)},[]),E=(0,v.useCallback)(e=>{Ze(e),le(e)},[]);(0,v.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=${b} drawer=${S}`)},[]),(0,v.useEffect)(()=>{typeof window>`u`||!C||(console.info(`[admin-ui] wa-hydrate route=/ remoteJid=${C.remoteJid??``}`),window.history.replaceState(null,``,`/`))},[]),(0,v.useEffect)(()=>{typeof window>`u`||!T||(console.info(`[admin-ui] data-hydrate route=/`),window.history.replaceState(null,``,`/`))},[]);let ge=(0,v.useCallback)(e=>{if(pe(!1),e===null){w(null);return}let t=typeof window<`u`?window.location.pathname:`/`,n=Qe(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},[]),D=(0,v.useCallback)(()=>{let e=typeof window<`u`?window.location.pathname:`/`,t=$e(e);if(console.info(`[admin-ui] data-open route=${e} via=${t.via}`),t.via===`navigate`){window.location.href=t.href;return}w(null),pe(!0)},[]),O=ue?S:!b,k=(0,v.useCallback)(()=>{if(!(typeof window>`u`))if(window.matchMedia(`(max-width: ${q}px)`).matches){let e=S;console.info(`[admin-ui] header-sidebar-toggle from=${e?`open`:`closed`} mode=drawer`),E(!e)}else{let e=b;console.info(`[admin-ui] header-sidebar-toggle from=${e?`closed`:`open`} mode=collapse`),he(!e)}},[b,S,he,E]),_e=(0,v.useCallback)(e=>{let t=tt(e,r);console.info(`[admin-ui] header-menu-nav target=${e} dest=${t}`),window.location.href=t},[r]),A={collapsed:b,mobileDrawerOpen:S,sidebarOpen:O,onToggleSidebar:k,setMobileDrawerOpen:E,selectedWhatsapp:C,onClearWhatsapp:()=>w(null),dataOpen:T};return r===`operator`?(0,y.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,y.jsx)(f,{businessName:n,variant:r,onNavigate:_e,onOpenConversations:h,onToggleSidebar:k,sidebarOpen:O,onLogout:i,onDisconnect:a,disconnecting:o,cacheKey:t,subAccounts:te,activeAccountId:ne,switchingAccount:_,onSwitchAccount:ie}),(0,y.jsx)(`div`,{className:`platform platform-operator`,children:typeof g==`function`?g(A):g}),ee]}):(0,y.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,y.jsx)(f,{businessName:n,variant:r,onNavigate:_e,onOpenConversations:h,onToggleSidebar:k,sidebarOpen:O,onLogout:i,onDisconnect:a,disconnecting:o,claudeConnected:se,onConnectClaude:ce,cacheKey:t,subAccounts:te,activeAccountId:ne,switchingAccount:_,onSwitchAccount:ie}),(0,y.jsxs)(`div`,{className:`platform${S?` menu-open`:``}${b?` sidebar-collapsed`:``}`,"data-artefact":`closed`,children:[(0,y.jsx)(Ue,{businessName:n,cacheKey:t,onConnectClaude:ce,role:p??null,userName:l,userAvatar:u??null,onSelectProjects:()=>{window.location.href=`/graph?label=${m().label}`},onSelectPeople:()=>{window.location.href=`/graph?label=Person`},onSelectTasks:()=>{window.location.href=`/graph?label=Task`},onSelectAgents:()=>{window.location.href=`/graph?label=Agent`},onCloseMobileDrawer:()=>E(!1),collapsed:b,mobileDrawerOpen:S,selectedWhatsappId:C?d(C):null,onSelectWhatsappConversation:ge,initialWhatsappSurface:fe,onSelectData:D,onCloseData:()=>pe(!1),initialDataSurface:me}),!ue&&(0,y.jsx)(ve,{}),typeof g==`function`?g(A):g]}),S&&(0,y.jsx)(`div`,{className:`sidebar-backdrop menu-open`,"aria-hidden":`true`,onClick:()=>E(!1)}),ee]})}export{de as _,V as a,S as b,M as c,ge as d,E as f,w as g,T as h,Ne as i,xe as l,me as m,Ve as n,N as o,he as p,Pe as r,j as s,nt as t,F as u,ue as v,ce as x,le as y};
|