@rubytech/create-maxy-code 0.1.308 → 0.1.310
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/dist/__tests__/claude-ptys-slice.test.js +1 -1
- package/dist/__tests__/cloudflared-slice.test.js +1 -1
- package/dist/__tests__/macos-darwin-branch.test.js +4 -6
- package/package.json +1 -1
- package/payload/platform/lib/admin-access-password/__tests__/index.test.ts +28 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts +9 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/admin-access-password/dist/index.js +26 -0
- package/payload/platform/lib/admin-access-password/dist/index.js.map +1 -1
- package/payload/platform/lib/admin-access-password/src/index.ts +24 -0
- package/payload/platform/lib/models/dist/index.d.ts +7 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +10 -0
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +10 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +4 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +21 -1
- package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/specialist-management/SKILL.md +1 -1
- package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +1 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +20 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +2 -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 +50 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts +1 -0
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js +31 -0
- package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +8 -3
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +25 -9
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +5 -3
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +8 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +10 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/server/{chunk-FBGIHWWM.js → chunk-J6WDAWFJ.js} +20 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AccessGate-BOqUU-za.js +1 -0
- package/payload/server/public/assets/AdminLoginScreens-WvRuaNIg.js +1 -0
- package/payload/server/public/assets/AdminShell-DHv6_SZ4.js +1 -0
- package/payload/server/public/assets/{Checkbox-8elc7oXU.js → Checkbox-DjM6aYP_.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-CDY0jUMb.js +1 -0
- package/payload/server/public/assets/admin-XbVTsU2q.js +1 -0
- package/payload/server/public/assets/admin-types-D2qTXuCg.js +1 -0
- package/payload/server/public/assets/{arc-DxSm8tli.js → arc-J2g2u5Xv.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-C6nkAxzW.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-7JSAh0vL.js → architectureDiagram-Q4EWVU46-CN0BXxpE.js} +1 -1
- package/payload/server/public/assets/audio-attachment-mime-CVxjPN8V.js +30 -0
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DLoVmHKD.js → blockDiagram-DXYQGD6D-HX-8wF2p.js} +1 -1
- package/payload/server/public/assets/brand-N-Hi3IPA.css +1 -0
- package/payload/server/public/assets/{brand-Dh5UlVO2.js → brand-zL3tAdql.js} +1 -1
- package/payload/server/public/assets/browser-Ct5Kwlmk.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Nv1G0o9P.js → c4Diagram-AHTNJAMY-wIuarKF5.js} +1 -1
- package/payload/server/public/assets/channel-Q39xIXyT.js +1 -0
- package/payload/server/public/assets/chat-CEde1CLX.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-BpqPMhoA.js → chunk-2KRD3SAO-Buz7egJZ.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-DgXHlVU_.js → chunk-336JU56O-_JcFXJqc.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-CCYjp9C2.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-nwyZSZH8.js → chunk-4BX2VUAB-DUR5Dg3M.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-Tfxz9LHX.js → chunk-4TB4RGXK-BRIqQ9st.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-6FMJQGXG.js → chunk-55IACEB6-CezTHWXL.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-g2FgZF3D.js → chunk-5FUZZQ4R-DHYUPzF1.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-DtLwXsPH.js → chunk-5PVQY5BW-BVn4_fI5.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-K91CP5ZU.js → chunk-67CJDMHE-BBLA8Mbi.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BGpCQhqK.js → chunk-7N4EOEYR-CdWfEI5c.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-jkDbInck.js → chunk-AA7GKIK3-tS11knCR.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-mDosdzGs.js → chunk-BSJP7CBP-GEu1OOZ6.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-DhBxewpQ.js → chunk-CIAEETIT-DKrNbbp_.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-B7c-9Emg.js → chunk-EDXVE4YY-B0InXNyr.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-Cqhhncox.js → chunk-ENJZ2VHE-CO7lkHdm.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-BpDq6wj1.js → chunk-FMBD7UC4-CMj74lWo.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-Ds02-ktu.js → chunk-FOC6F5B3-CLnKQoXw.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BTX5POFr.js → chunk-ICPOFSXX-CdiEKIaz.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-Du1PXXBU.js → chunk-K5T4RW27-B6LA3fiv.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-siasOAf8.js → chunk-KGLVRYIC-DrhRrb8Q.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-xf1rbZtf.js → chunk-LIHQZDEY-DVQukevB.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-DeTLQ_LD.js → chunk-ORNJ4GCN-ZMLkoDhP.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-DQ7_oVJn.js → chunk-OYMX7WX6-C0dJkynG.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-BNBxnHZh.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-CXmFUKgn.js → chunk-U2HBQHQK-BQ9BPIFZ.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-Bj8-8Wkz.js → chunk-X2U36JSP-CAonGMOd.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-Con3TXqt.js → chunk-XPW4576I-D5C_WNlk.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Dx8BHGWf.js → chunk-YZCP3GAM-Ecdvzekb.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Dp4Q5Y-f.js → chunk-ZZ45TVLE-BsFZd1cN.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BShusfby.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D4ivPLFF.js +1 -0
- package/payload/server/public/assets/clone-CjEM8LwB.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-pZiCv69E.js → cose-bilkent-S5V4N54A-DBWHaIwm.js} +1 -1
- package/payload/server/public/assets/{dagre-CLqhEgbL.js → dagre-Dr7ZJYeS.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BCxE8iyk.js → dagre-KV5264BT-oIJddk7m.js} +1 -1
- package/payload/server/public/assets/data-TZOmA1Qg.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-slUEdZzz.js → diagram-5BDNPKRD-CEVxqOZ4.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DPcraMfu.js → diagram-G4DWMVQ6-BovF7Rjx.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DR6luhGK.js → diagram-MMDJMWI5-BhrF8zoF.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-Jap1B4wA.js → diagram-TYMM5635-DCUYwxtR.js} +1 -1
- package/payload/server/public/assets/{dist-Dbh7HrZX.js → dist-DSsFp0Qd.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-DJKUs2hO.js → erDiagram-SMLLAGMA-BS2-HdCg.js} +1 -1
- package/payload/server/public/assets/{flatten-Cl1Bc3dR.js → flatten-BZMXCpLh.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-C8W-ZZ9W.js → flowDiagram-DWJPFMVM-BzSFLoea.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DYCX4Xu2.js → ganttDiagram-T4ZO3ILL-1-3QU7mT.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-Btp3PwZh.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CZu_fpgS.js → gitGraphDiagram-UUTBAWPF-fTrJ35Wk.js} +1 -1
- package/payload/server/public/assets/{graph-DKSjcpmR.js → graph-DWT1rhy9.js} +2 -2
- package/payload/server/public/assets/{graph-labels-CVWPQgBV.js → graph-labels-OBadNo54.js} +1 -1
- package/payload/server/public/assets/{graphlib-Bdp7TA4y.js → graphlib-rlEzI2qD.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-CPt2y6_L.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CpXNTMgd.js +2 -0
- package/payload/server/public/assets/{isEmpty-D1pGOD1J.js → isEmpty-DaYIrHay.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-B7KfIX6z.js → ishikawaDiagram-UXIWVN3A-0eU_UtlT.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CSDwBfhF.js → journeyDiagram-VCZTEJTY-BKLeZohp.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CWzcEKTr.js → kanban-definition-6JOO6SKY-Dq72xyaN.js} +1 -1
- package/payload/server/public/assets/{line-BNQSlbYn.js → line-LQhmDT8k.js} +1 -1
- package/payload/server/public/assets/{linear-BN6kGN93.js → linear-BGotDbGs.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CcFhkElq.js → mermaid-parser.core-DoLdho1V.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-BsIeJ7Cc.js → mermaid.core-C1RRyHGm.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CQVzj6D_.js → mindmap-definition-QFDTVHPH-vUVVVyV1.js} +1 -1
- package/payload/server/public/assets/operator-BpzQ9Ezb.js +1 -0
- package/payload/server/public/assets/{ordinal-CBZeH4Yp.js → ordinal-BqEhkPyh.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Cwc-j_AI.js +1 -0
- package/payload/server/public/assets/page-Dts8u8MD.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-BZ9fjD1_.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DnrQ9fyn.js → pieDiagram-DEJITSTG-B9Pl6Qhc.js} +1 -1
- package/payload/server/public/assets/public-next-ClQwtyeC.js +1 -0
- package/payload/server/public/assets/public-owWW-MIA.js +6 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BQWlCyWi.js → quadrantDiagram-34T5L4WZ-Drn9T81A.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-BNz5Rt9V.js +1 -0
- package/payload/server/public/assets/{reduce-PuPlFPRX.js → reduce-T2IuntYP.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-Du_vZhU1.js → requirementDiagram-MS252O5E-C0PAItJm.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-Cf6Z8GPQ.js → sankeyDiagram-XADWPNL6-BR42Mtwd.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CS8GVol8.js → sequenceDiagram-FGHM5R23-c2lR9UOS.js} +1 -1
- package/payload/server/public/assets/{src-BoaldmnP.js → src-DXUM2BJo.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Bv1NW2F1.js → stateDiagram-FHFEXIEX-BcHhtqsZ.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BUQ_F4eP.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-ClGYAsr0.js → timeline-definition-GMOUNBTQ-Ax32c10H.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-DcVCQgp1.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-Bm12mwGd.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-FIodJKzS.js → useSelectionMode-BZsJuUm-.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-C2wTcxQT.js → vennDiagram-DHZGUBPP-BxePewPq.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-47Z3ymtK.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-D86-ivEx.js → wardleyDiagram-NUSXRM2D-DmJwZ2f5.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-Ba5WAN8P.js → xychartDiagram-5P7HB3ND-YjHomudv.js} +1 -1
- package/payload/server/public/browser.html +8 -8
- package/payload/server/public/chat.html +12 -11
- package/payload/server/public/data.html +7 -7
- package/payload/server/public/graph.html +10 -10
- package/payload/server/public/index.html +11 -10
- package/payload/server/public/operator.html +14 -13
- package/payload/server/public/public-next.html +25 -0
- package/payload/server/public/public.html +9 -8
- package/payload/server/server.js +890 -641
- package/dist/__tests__/onboarding-state-readback.test.js +0 -61
- package/dist/__tests__/rss-sampler-installer.test.js +0 -27
- package/dist/onboarding-readback.js +0 -27
- package/payload/server/public/assets/AdminLoginScreens-BZIA9Z6o.js +0 -1
- package/payload/server/public/assets/AdminShell-iazLHsk7.js +0 -1
- package/payload/server/public/assets/admin-BEx6o3fa.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-6g9jRVgc.js +0 -1
- package/payload/server/public/assets/audio-attachment-mime-DzbKNqbH.js +0 -30
- package/payload/server/public/assets/brand-CmMZe4RK.css +0 -1
- package/payload/server/public/assets/browser-D16sPVkI.js +0 -1
- package/payload/server/public/assets/channel-BgQLJanG.js +0 -1
- package/payload/server/public/assets/chat-x4PnXhkd.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-Dr_XVuUq.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DF4o9HRJ.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DAbPKU6u.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BKuFQLcv.js +0 -1
- package/payload/server/public/assets/clone-DnNHGhNe.js +0 -1
- package/payload/server/public/assets/data-DqG45sq0.js +0 -1
- package/payload/server/public/assets/file-download-BvGS7Qmi.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-g7mvu6IY.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-DZqJuIkB.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-cGfGccHz.js +0 -2
- package/payload/server/public/assets/operator-Cnzbhdh2.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Hn8rlHpy.js +0 -1
- package/payload/server/public/assets/page-CH8JQkQN.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BPGWVqBm.js +0 -1
- package/payload/server/public/assets/public-CA90VhI9.js +0 -6
- package/payload/server/public/assets/radar-PYXPWWZC-DMdLrj3E.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BGUCxPmp.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CWxofUbI.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-Cfgb_ZG0.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-B45olYjj.js +0 -1
- /package/payload/server/public/assets/{file-download-qc_xy7Az.css → OperatorConversations-qc_xy7Az.css} +0 -0
- /package/payload/server/public/assets/{_baseFor-brRjpUOX.js → _baseFor-Y5mTRiRv.js} +0 -0
- /package/payload/server/public/assets/{array-BGFCBI0e.js → array-BwJyW1Dp.js} +0 -0
- /package/payload/server/public/assets/{chunk-Pqm5yXtL.js → chunk-CAM3fms7.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-TvRJ2tGX.js → cytoscape.esm-D95TtHqz.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-CRZydyG6.js → defaultLocale-kiwRz9Au.js} +0 -0
- /package/payload/server/public/assets/{init-B8gtcn7T.js → init-CKZirZ49.js} +0 -0
- /package/payload/server/public/assets/{katex-RxgSu_dy.js → katex-8mXVa4k3.js} +0 -0
- /package/payload/server/public/assets/{path-DZF-JdEe.js → path-B0d9ncVi.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-CQ36nxok.js → preload-helper-C5gCWwwF.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-6CnTHTkH.js → rough.esm-BWqoIFNR.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
VISITOR_TOKEN_SECRET_FILE,
|
|
26
26
|
VNC_DISPLAY,
|
|
27
27
|
WEBSOCKIFY_PORT,
|
|
28
|
+
accessPasswordCollides,
|
|
28
29
|
autoDeliverPremiumPlugins,
|
|
29
30
|
bindVisitorToGroup,
|
|
30
31
|
canAccessAdmin,
|
|
@@ -109,7 +110,7 @@ import {
|
|
|
109
110
|
vncLog,
|
|
110
111
|
walkPremiumBundles,
|
|
111
112
|
writeAdminUserAndPerson
|
|
112
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-J6WDAWFJ.js";
|
|
113
114
|
import {
|
|
114
115
|
__commonJS,
|
|
115
116
|
__toESM
|
|
@@ -1227,7 +1228,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1227
1228
|
|
|
1228
1229
|
// server/index.ts
|
|
1229
1230
|
import { readFileSync as readFileSync27, existsSync as existsSync28, watchFile } from "fs";
|
|
1230
|
-
import { resolve as
|
|
1231
|
+
import { resolve as resolve31, join as join25, basename as basename9 } from "path";
|
|
1231
1232
|
import { homedir as homedir3 } from "os";
|
|
1232
1233
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1233
1234
|
|
|
@@ -1875,7 +1876,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1875
1876
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1876
1877
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1877
1878
|
const timer2 = new Promise(
|
|
1878
|
-
(
|
|
1879
|
+
(resolve32) => setTimeout(() => resolve32("timeout"), timeoutMs)
|
|
1879
1880
|
);
|
|
1880
1881
|
const result = await Promise.race([
|
|
1881
1882
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -2003,11 +2004,11 @@ async function createWaSocket(opts) {
|
|
|
2003
2004
|
return sock;
|
|
2004
2005
|
}
|
|
2005
2006
|
async function waitForConnection(sock) {
|
|
2006
|
-
return new Promise((
|
|
2007
|
+
return new Promise((resolve32, reject) => {
|
|
2007
2008
|
const handler = (update) => {
|
|
2008
2009
|
if (update.connection === "open") {
|
|
2009
2010
|
sock.ev.off("connection.update", handler);
|
|
2010
|
-
|
|
2011
|
+
resolve32();
|
|
2011
2012
|
}
|
|
2012
2013
|
if (update.connection === "close") {
|
|
2013
2014
|
sock.ev.off("connection.update", handler);
|
|
@@ -2121,14 +2122,14 @@ ${inspected}`;
|
|
|
2121
2122
|
return inspect2(err, INSPECT_OPTS2);
|
|
2122
2123
|
}
|
|
2123
2124
|
function withTimeout(label, promise, timeoutMs) {
|
|
2124
|
-
return new Promise((
|
|
2125
|
+
return new Promise((resolve32, reject) => {
|
|
2125
2126
|
const timer2 = setTimeout(() => {
|
|
2126
2127
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2127
2128
|
}, timeoutMs);
|
|
2128
2129
|
promise.then(
|
|
2129
2130
|
(value) => {
|
|
2130
2131
|
clearTimeout(timer2);
|
|
2131
|
-
|
|
2132
|
+
resolve32(value);
|
|
2132
2133
|
},
|
|
2133
2134
|
(err) => {
|
|
2134
2135
|
clearTimeout(timer2);
|
|
@@ -3012,8 +3013,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
3012
3013
|
const { givenName, familyName } = splitName(input.pushName);
|
|
3013
3014
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
3014
3015
|
let release;
|
|
3015
|
-
const mine = new Promise((
|
|
3016
|
-
release =
|
|
3016
|
+
const mine = new Promise((resolve32) => {
|
|
3017
|
+
release = resolve32;
|
|
3017
3018
|
});
|
|
3018
3019
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
3019
3020
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -4093,11 +4094,11 @@ async function connectWithReconnect(conn) {
|
|
|
4093
4094
|
console.error(
|
|
4094
4095
|
`${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
4095
4096
|
);
|
|
4096
|
-
await new Promise((
|
|
4097
|
-
const timer2 = setTimeout(
|
|
4097
|
+
await new Promise((resolve32) => {
|
|
4098
|
+
const timer2 = setTimeout(resolve32, delay);
|
|
4098
4099
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
4099
4100
|
clearTimeout(timer2);
|
|
4100
|
-
|
|
4101
|
+
resolve32();
|
|
4101
4102
|
}, { once: true });
|
|
4102
4103
|
});
|
|
4103
4104
|
}
|
|
@@ -4105,16 +4106,16 @@ async function connectWithReconnect(conn) {
|
|
|
4105
4106
|
}
|
|
4106
4107
|
}
|
|
4107
4108
|
function waitForDisconnectEvent(conn) {
|
|
4108
|
-
return new Promise((
|
|
4109
|
+
return new Promise((resolve32) => {
|
|
4109
4110
|
if (!conn.sock) {
|
|
4110
|
-
|
|
4111
|
+
resolve32();
|
|
4111
4112
|
return;
|
|
4112
4113
|
}
|
|
4113
4114
|
const sock = conn.sock;
|
|
4114
4115
|
const handler = (update) => {
|
|
4115
4116
|
if (update.connection === "close") {
|
|
4116
4117
|
sock.ev.off("connection.update", handler);
|
|
4117
|
-
|
|
4118
|
+
resolve32();
|
|
4118
4119
|
}
|
|
4119
4120
|
};
|
|
4120
4121
|
sock.ev.on("connection.update", handler);
|
|
@@ -4374,8 +4375,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4374
4375
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
4375
4376
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
4376
4377
|
let resolvePending;
|
|
4377
|
-
const sttPending = new Promise((
|
|
4378
|
-
resolvePending =
|
|
4378
|
+
const sttPending = new Promise((resolve32) => {
|
|
4379
|
+
resolvePending = resolve32;
|
|
4379
4380
|
});
|
|
4380
4381
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
4381
4382
|
try {
|
|
@@ -4769,20 +4770,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
4769
4770
|
|
|
4770
4771
|
// server/routes/health.ts
|
|
4771
4772
|
function checkPort(port2, timeoutMs = 500) {
|
|
4772
|
-
return new Promise((
|
|
4773
|
+
return new Promise((resolve32) => {
|
|
4773
4774
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
4774
4775
|
socket.setTimeout(timeoutMs);
|
|
4775
4776
|
socket.once("connect", () => {
|
|
4776
4777
|
socket.destroy();
|
|
4777
|
-
|
|
4778
|
+
resolve32(true);
|
|
4778
4779
|
});
|
|
4779
4780
|
socket.once("error", () => {
|
|
4780
4781
|
socket.destroy();
|
|
4781
|
-
|
|
4782
|
+
resolve32(false);
|
|
4782
4783
|
});
|
|
4783
4784
|
socket.once("timeout", () => {
|
|
4784
4785
|
socket.destroy();
|
|
4785
|
-
|
|
4786
|
+
resolve32(false);
|
|
4786
4787
|
});
|
|
4787
4788
|
});
|
|
4788
4789
|
}
|
|
@@ -5175,8 +5176,8 @@ function webchatTurnTimeoutMs() {
|
|
|
5175
5176
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
5176
5177
|
}
|
|
5177
5178
|
function createChatRoutes(deps) {
|
|
5178
|
-
const
|
|
5179
|
-
|
|
5179
|
+
const app51 = new Hono();
|
|
5180
|
+
app51.post("/", async (c) => {
|
|
5180
5181
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
5181
5182
|
const contentType = c.req.header("content-type") ?? "";
|
|
5182
5183
|
const account = resolveAccount();
|
|
@@ -5399,7 +5400,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5399
5400
|
}
|
|
5400
5401
|
});
|
|
5401
5402
|
});
|
|
5402
|
-
return
|
|
5403
|
+
return app51;
|
|
5403
5404
|
}
|
|
5404
5405
|
|
|
5405
5406
|
// server/routes/whatsapp.ts
|
|
@@ -5821,8 +5822,8 @@ async function startLogin(opts) {
|
|
|
5821
5822
|
await clearAuth(authDir);
|
|
5822
5823
|
let resolveCode = null;
|
|
5823
5824
|
let rejectCode = null;
|
|
5824
|
-
const codePromise = new Promise((
|
|
5825
|
-
resolveCode =
|
|
5825
|
+
const codePromise = new Promise((resolve32, reject) => {
|
|
5826
|
+
resolveCode = resolve32;
|
|
5826
5827
|
rejectCode = reject;
|
|
5827
5828
|
});
|
|
5828
5829
|
const codeTimer = setTimeout(
|
|
@@ -6590,6 +6591,28 @@ import { basename as basename2, dirname, join as join10, resolve as resolve11, s
|
|
|
6590
6591
|
// server/routes/admin/sidebar-sessions.ts
|
|
6591
6592
|
import { readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync2 } from "fs";
|
|
6592
6593
|
import { join as join8, resolve as resolve10 } from "path";
|
|
6594
|
+
|
|
6595
|
+
// app/lib/whatsapp-reader/select-sessions.ts
|
|
6596
|
+
function isReaderChannelSession(role, channel) {
|
|
6597
|
+
return role === "admin" && (channel === "whatsapp" || channel === "telegram") || role === "public" && (channel === "whatsapp" || channel === "webchat");
|
|
6598
|
+
}
|
|
6599
|
+
function selectReaderChannelSessions(rows) {
|
|
6600
|
+
return rows.filter((r) => isReaderChannelSession(r.role, r.channel)).sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
|
|
6601
|
+
sessionId: r.sessionId,
|
|
6602
|
+
projectDir: r.projectDir,
|
|
6603
|
+
title: r.title,
|
|
6604
|
+
senderId: r.senderId,
|
|
6605
|
+
startedAt: r.startedAt,
|
|
6606
|
+
channel: r.channel,
|
|
6607
|
+
role: r.role,
|
|
6608
|
+
operatorName: null,
|
|
6609
|
+
whatsappName: null,
|
|
6610
|
+
lastMessageAt: r.lastMessageAt,
|
|
6611
|
+
modelGated: r.modelGated
|
|
6612
|
+
}));
|
|
6613
|
+
}
|
|
6614
|
+
|
|
6615
|
+
// server/routes/admin/sidebar-sessions.ts
|
|
6593
6616
|
var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
|
|
6594
6617
|
var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
|
|
6595
6618
|
var PUBLIC_ROLE = "public";
|
|
@@ -6815,6 +6838,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6815
6838
|
let subagentCount = 0;
|
|
6816
6839
|
let nonResumableCount = 0;
|
|
6817
6840
|
let archivedCount = 0;
|
|
6841
|
+
let excludedChannelCount = 0;
|
|
6818
6842
|
const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
|
|
6819
6843
|
const personIdBySession = /* @__PURE__ */ new Map();
|
|
6820
6844
|
const adminUserIdBySession = /* @__PURE__ */ new Map();
|
|
@@ -6842,6 +6866,10 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6842
6866
|
titleSourceCounts[resolved.source] += 1;
|
|
6843
6867
|
const metaPath = join8(projectDir, `${sessionId}.meta.json`);
|
|
6844
6868
|
const { bridgeIds, role, channel: sidecarChannel, personId, adminUserId } = readSidecarMeta(metaPath);
|
|
6869
|
+
if (isReaderChannelSession(role, sidecarChannel)) {
|
|
6870
|
+
excludedChannelCount += 1;
|
|
6871
|
+
continue;
|
|
6872
|
+
}
|
|
6845
6873
|
const resumable = !(role === PUBLIC_ROLE && (sidecarChannel === WEBCHAT_CHANNEL || sidecarChannel === WHATSAPP_CHANNEL));
|
|
6846
6874
|
if (personId) personIdBySession.set(sessionId, personId);
|
|
6847
6875
|
if (adminUserId && role === ADMIN_ROLE && sidecarChannel === WEBCHAT_CHANNEL) {
|
|
@@ -6895,29 +6923,12 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6895
6923
|
}
|
|
6896
6924
|
rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
6897
6925
|
console.log(
|
|
6898
|
-
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} nonResumable=${nonResumableCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
|
|
6926
|
+
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} nonResumable=${nonResumableCount} excludedChannel=${excludedChannelCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
|
|
6899
6927
|
);
|
|
6900
6928
|
return c.json({ sessions: rows, accountId });
|
|
6901
6929
|
});
|
|
6902
6930
|
var sidebar_sessions_default = app3;
|
|
6903
6931
|
|
|
6904
|
-
// app/lib/whatsapp-reader/select-sessions.ts
|
|
6905
|
-
function selectReaderChannelSessions(rows) {
|
|
6906
|
-
return rows.filter((r) => r.role === "admin" && (r.channel === "whatsapp" || r.channel === "telegram") || r.role === "public" && (r.channel === "whatsapp" || r.channel === "webchat")).sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
|
|
6907
|
-
sessionId: r.sessionId,
|
|
6908
|
-
projectDir: r.projectDir,
|
|
6909
|
-
title: r.title,
|
|
6910
|
-
senderId: r.senderId,
|
|
6911
|
-
startedAt: r.startedAt,
|
|
6912
|
-
channel: r.channel,
|
|
6913
|
-
role: r.role,
|
|
6914
|
-
operatorName: null,
|
|
6915
|
-
whatsappName: null,
|
|
6916
|
-
lastMessageAt: r.lastMessageAt,
|
|
6917
|
-
modelGated: r.modelGated
|
|
6918
|
-
}));
|
|
6919
|
-
}
|
|
6920
|
-
|
|
6921
6932
|
// app/lib/admin-identity/pin-validator.ts
|
|
6922
6933
|
import { createHash } from "crypto";
|
|
6923
6934
|
import { existsSync as existsSync6, readFileSync as readFileSync10, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
@@ -7120,6 +7131,7 @@ function isModelGated(turns) {
|
|
|
7120
7131
|
}
|
|
7121
7132
|
function parseTranscript(lines) {
|
|
7122
7133
|
const out = [];
|
|
7134
|
+
const queuedPendingSuppress = /* @__PURE__ */ new Map();
|
|
7123
7135
|
for (const line of lines) {
|
|
7124
7136
|
if (!line || line[0] !== "{") continue;
|
|
7125
7137
|
let row;
|
|
@@ -7144,12 +7156,26 @@ function parseTranscript(lines) {
|
|
|
7144
7156
|
out.push(...assistantTurns(msg?.content, ts));
|
|
7145
7157
|
continue;
|
|
7146
7158
|
}
|
|
7159
|
+
if (row.type === "queue-operation" && row.operation === "enqueue") {
|
|
7160
|
+
const content = asString(row.content);
|
|
7161
|
+
if (content !== null && CHANNEL_WRAPPER2.test(content)) {
|
|
7162
|
+
const u = unwrapChannel(content);
|
|
7163
|
+
out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
|
|
7164
|
+
queuedPendingSuppress.set(u.text, (queuedPendingSuppress.get(u.text) ?? 0) + 1);
|
|
7165
|
+
}
|
|
7166
|
+
continue;
|
|
7167
|
+
}
|
|
7147
7168
|
if (row.type === "attachment") {
|
|
7148
7169
|
const att = row.attachment;
|
|
7149
7170
|
const isChannelQueued = att?.type === "queued_command" && att.isMeta === true && typeof att.origin === "object" && att.origin !== null && att.origin.kind === "channel" && typeof att.prompt === "string";
|
|
7150
7171
|
if (isChannelQueued) {
|
|
7151
7172
|
const u = unwrapChannel(att.prompt);
|
|
7152
|
-
|
|
7173
|
+
const armed = queuedPendingSuppress.get(u.text) ?? 0;
|
|
7174
|
+
if (armed > 0) {
|
|
7175
|
+
queuedPendingSuppress.set(u.text, armed - 1);
|
|
7176
|
+
} else {
|
|
7177
|
+
out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
|
|
7178
|
+
}
|
|
7153
7179
|
}
|
|
7154
7180
|
continue;
|
|
7155
7181
|
}
|
|
@@ -7207,9 +7233,7 @@ app4.get("/conversations", requireAdminSession, async (c) => {
|
|
|
7207
7233
|
const sessionId = basename2(path2).replace(/\.jsonl$/, "");
|
|
7208
7234
|
const projectDir = dirname(path2);
|
|
7209
7235
|
const meta = readSidecarMeta(join10(projectDir, `${sessionId}.meta.json`));
|
|
7210
|
-
|
|
7211
|
-
const isPublicChannel = meta.role === "public" && (meta.channel === "whatsapp" || meta.channel === "webchat");
|
|
7212
|
-
if (!isAdminChannel && !isPublicChannel) continue;
|
|
7236
|
+
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
7213
7237
|
let body = "";
|
|
7214
7238
|
try {
|
|
7215
7239
|
body = readFileSync11(path2, "utf8");
|
|
@@ -7442,18 +7466,202 @@ app4.get("/directive", requireAdminSession, (c) => {
|
|
|
7442
7466
|
});
|
|
7443
7467
|
var whatsapp_reader_default = app4;
|
|
7444
7468
|
|
|
7469
|
+
// server/routes/public-reader.ts
|
|
7470
|
+
import { statSync as statSync5, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2 } from "fs";
|
|
7471
|
+
import { basename as basename3, dirname as dirname2, join as join11, resolve as resolve12, sep as sep4 } from "path";
|
|
7472
|
+
|
|
7473
|
+
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
7474
|
+
var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
|
|
7475
|
+
"operator-inbound",
|
|
7476
|
+
"agent-reply",
|
|
7477
|
+
"agent-reply-document",
|
|
7478
|
+
"agent-error"
|
|
7479
|
+
]);
|
|
7480
|
+
function isDeliveredKind(kind, set) {
|
|
7481
|
+
return set.has(kind);
|
|
7482
|
+
}
|
|
7483
|
+
|
|
7484
|
+
// app/lib/public-reader/filter-delivered.ts
|
|
7485
|
+
function filterDeliveredFrames(lines) {
|
|
7486
|
+
const turns = [];
|
|
7487
|
+
let dropped = 0;
|
|
7488
|
+
for (const turn of parseTranscript(lines)) {
|
|
7489
|
+
if (!isDeliveredKind(turn.kind, PUBLIC_DELIVERED_KINDS)) {
|
|
7490
|
+
dropped++;
|
|
7491
|
+
continue;
|
|
7492
|
+
}
|
|
7493
|
+
turns.push(turn.kind === "agent-error" ? { ...turn, raw: "" } : turn);
|
|
7494
|
+
}
|
|
7495
|
+
return { turns, dropped };
|
|
7496
|
+
}
|
|
7497
|
+
|
|
7498
|
+
// app/lib/public-reader/resolve-visitor-session.ts
|
|
7499
|
+
function resolveVisitorSession(rows, visitorPersonId) {
|
|
7500
|
+
const matches = rows.filter(
|
|
7501
|
+
(r) => r.role === "public" && r.channel === "webchat" && r.personId === visitorPersonId
|
|
7502
|
+
);
|
|
7503
|
+
if (matches.length === 0) return null;
|
|
7504
|
+
return matches.reduce(
|
|
7505
|
+
(best, r) => (r.startedAt ?? "") > (best.startedAt ?? "") ? r : best
|
|
7506
|
+
);
|
|
7507
|
+
}
|
|
7508
|
+
|
|
7509
|
+
// server/routes/public-reader.ts
|
|
7510
|
+
var app5 = new Hono();
|
|
7511
|
+
var TAG20 = "[public-webchat]";
|
|
7512
|
+
function parseAccessSessionId(cookieHeader) {
|
|
7513
|
+
if (!cookieHeader) return null;
|
|
7514
|
+
const part = cookieHeader.split(";").map((p) => p.trim()).find((p) => p.startsWith("__access_session="));
|
|
7515
|
+
return part ? part.slice("__access_session=".length) : null;
|
|
7516
|
+
}
|
|
7517
|
+
function resolveVisitor(c) {
|
|
7518
|
+
const id = parseAccessSessionId(c.req.header("cookie"));
|
|
7519
|
+
const session = id ? getAccessSession(id) : null;
|
|
7520
|
+
return session && session.personId ? { personId: session.personId } : null;
|
|
7521
|
+
}
|
|
7522
|
+
function enumeratePublicRows() {
|
|
7523
|
+
const cfg = claudeConfigDir();
|
|
7524
|
+
if (!cfg) return [];
|
|
7525
|
+
const rows = [];
|
|
7526
|
+
for (const { path: path2 } of enumerateJsonls(join11(cfg, "projects"))) {
|
|
7527
|
+
const sessionId = basename3(path2).replace(/\.jsonl$/, "");
|
|
7528
|
+
const projectDir = dirname2(path2);
|
|
7529
|
+
const meta = readSidecarMeta(join11(projectDir, `${sessionId}.meta.json`));
|
|
7530
|
+
rows.push({
|
|
7531
|
+
sessionId,
|
|
7532
|
+
projectDir,
|
|
7533
|
+
role: meta.role,
|
|
7534
|
+
channel: meta.channel,
|
|
7535
|
+
personId: meta.personId,
|
|
7536
|
+
senderId: meta.senderId,
|
|
7537
|
+
startedAt: meta.startedAt
|
|
7538
|
+
});
|
|
7539
|
+
}
|
|
7540
|
+
return rows;
|
|
7541
|
+
}
|
|
7542
|
+
app5.get("/session", (c) => {
|
|
7543
|
+
const visitor = resolveVisitor(c);
|
|
7544
|
+
if (!visitor) {
|
|
7545
|
+
console.error(`${TAG20} op=reader-refused reason=no-grant path=/session`);
|
|
7546
|
+
return c.json({ error: "gate-required" }, 401);
|
|
7547
|
+
}
|
|
7548
|
+
const found = resolveVisitorSession(enumeratePublicRows(), visitor.personId);
|
|
7549
|
+
if (found) {
|
|
7550
|
+
console.log(`${TAG20} op=session-resume key=${(found.senderId ?? "").slice(0, 8)} sessionId=${found.sessionId.slice(0, 8)}`);
|
|
7551
|
+
return c.json({ sessionId: found.sessionId, projectDir: found.projectDir, sessionKey: found.senderId });
|
|
7552
|
+
}
|
|
7553
|
+
const sessionKey = crypto.randomUUID();
|
|
7554
|
+
console.log(`${TAG20} op=session-new key=${sessionKey.slice(0, 8)}`);
|
|
7555
|
+
return c.json({ sessionId: null, projectDir: null, sessionKey });
|
|
7556
|
+
});
|
|
7557
|
+
function readFrom2(path2, from) {
|
|
7558
|
+
const end = statSync5(path2).size;
|
|
7559
|
+
if (end <= from) return { buf: Buffer.alloc(0), end: from };
|
|
7560
|
+
const fd = openSync2(path2, "r");
|
|
7561
|
+
try {
|
|
7562
|
+
const buf = Buffer.alloc(end - from);
|
|
7563
|
+
readSync2(fd, buf, 0, buf.length, from);
|
|
7564
|
+
return { buf, end };
|
|
7565
|
+
} finally {
|
|
7566
|
+
closeSync2(fd);
|
|
7567
|
+
}
|
|
7568
|
+
}
|
|
7569
|
+
app5.get("/stream", (c) => {
|
|
7570
|
+
const visitor = resolveVisitor(c);
|
|
7571
|
+
if (!visitor) {
|
|
7572
|
+
console.error(`${TAG20} op=reader-refused reason=no-grant path=/stream`);
|
|
7573
|
+
return c.json({ error: "gate-required" }, 401);
|
|
7574
|
+
}
|
|
7575
|
+
const sessionId = c.req.query("sessionId") ?? "";
|
|
7576
|
+
const projectDir = c.req.query("projectDir") ?? "";
|
|
7577
|
+
const cfg = claudeConfigDir();
|
|
7578
|
+
const projectsRoot = cfg ? resolve12(join11(cfg, "projects")) : null;
|
|
7579
|
+
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7580
|
+
return c.json({ error: "bad session reference" }, 400);
|
|
7581
|
+
}
|
|
7582
|
+
const jsonlPath = resolve12(join11(projectDir, `${sessionId}.jsonl`));
|
|
7583
|
+
if (!jsonlPath.startsWith(projectsRoot + sep4)) {
|
|
7584
|
+
return c.json({ error: "bad session reference" }, 400);
|
|
7585
|
+
}
|
|
7586
|
+
const meta = readSidecarMeta(join11(projectDir, `${sessionId}.meta.json`));
|
|
7587
|
+
if (!(meta.role === "public" && meta.channel === "webchat" && meta.personId === visitor.personId)) {
|
|
7588
|
+
console.error(`${TAG20} op=reader-refused reason=not-owner sessionId=${sessionId.slice(0, 8)}`);
|
|
7589
|
+
return c.json({ error: "forbidden" }, 403);
|
|
7590
|
+
}
|
|
7591
|
+
const senderShort = (meta.senderId ?? "").slice(0, 8);
|
|
7592
|
+
const encoder = new TextEncoder();
|
|
7593
|
+
console.log(`${TAG20} op=reader-open key=${senderShort} mode=delivered-only sessionId=${sessionId.slice(0, 8)}`);
|
|
7594
|
+
const send = (controller, turn, id) => controller.enqueue(encoder.encode(`id: ${id}
|
|
7595
|
+
data: ${JSON.stringify(turn)}
|
|
7596
|
+
|
|
7597
|
+
`));
|
|
7598
|
+
const readable = new ReadableStream({
|
|
7599
|
+
start(controller) {
|
|
7600
|
+
let offset = 0;
|
|
7601
|
+
const emit = (lines) => {
|
|
7602
|
+
const { turns, dropped } = filterDeliveredFrames(lines);
|
|
7603
|
+
for (const turn of turns) send(controller, turn, offset);
|
|
7604
|
+
if (dropped > 0) console.log(`${TAG20} op=reader-filtered key=${senderShort} dropped=${dropped}`);
|
|
7605
|
+
};
|
|
7606
|
+
try {
|
|
7607
|
+
const { buf, end } = readFrom2(jsonlPath, 0);
|
|
7608
|
+
offset = end;
|
|
7609
|
+
emit(buf.toString("utf8").split("\n"));
|
|
7610
|
+
} catch {
|
|
7611
|
+
controller.enqueue(encoder.encode('event: error\ndata: "read-failed"\n\n'));
|
|
7612
|
+
}
|
|
7613
|
+
const drain = () => {
|
|
7614
|
+
try {
|
|
7615
|
+
const { buf, end } = readFrom2(jsonlPath, offset);
|
|
7616
|
+
if (end <= offset) return;
|
|
7617
|
+
const { lines, nextOffset } = splitNewLines(buf, offset);
|
|
7618
|
+
offset = nextOffset;
|
|
7619
|
+
emit(lines);
|
|
7620
|
+
} catch {
|
|
7621
|
+
}
|
|
7622
|
+
};
|
|
7623
|
+
let watcher = null;
|
|
7624
|
+
try {
|
|
7625
|
+
watcher = watch2(jsonlPath, drain);
|
|
7626
|
+
} catch {
|
|
7627
|
+
}
|
|
7628
|
+
const poll = setInterval(drain, 1e3);
|
|
7629
|
+
const heartbeat = setInterval(() => {
|
|
7630
|
+
try {
|
|
7631
|
+
controller.enqueue(encoder.encode(": ping\n\n"));
|
|
7632
|
+
} catch {
|
|
7633
|
+
}
|
|
7634
|
+
}, 2e4);
|
|
7635
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
7636
|
+
watcher?.close();
|
|
7637
|
+
clearInterval(poll);
|
|
7638
|
+
clearInterval(heartbeat);
|
|
7639
|
+
console.log(`${TAG20} op=reader-close key=${senderShort}`);
|
|
7640
|
+
try {
|
|
7641
|
+
controller.close();
|
|
7642
|
+
} catch {
|
|
7643
|
+
}
|
|
7644
|
+
});
|
|
7645
|
+
}
|
|
7646
|
+
});
|
|
7647
|
+
return new Response(readable, {
|
|
7648
|
+
headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" }
|
|
7649
|
+
});
|
|
7650
|
+
});
|
|
7651
|
+
var public_reader_default = app5;
|
|
7652
|
+
|
|
7445
7653
|
// server/routes/webchat.ts
|
|
7446
|
-
import { basename as
|
|
7447
|
-
import { join as
|
|
7654
|
+
import { basename as basename4, dirname as dirname3 } from "path";
|
|
7655
|
+
import { join as join13 } from "path";
|
|
7448
7656
|
import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync13, renameSync as renameSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
7449
7657
|
|
|
7450
7658
|
// server/canonical-webchat-override.ts
|
|
7451
7659
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync5, renameSync } from "fs";
|
|
7452
|
-
import { join as
|
|
7660
|
+
import { join as join12 } from "path";
|
|
7453
7661
|
var FILE = "canonical-webchat-session.json";
|
|
7454
7662
|
var UUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
7455
7663
|
function canonicalOverridePath(accountDir) {
|
|
7456
|
-
return
|
|
7664
|
+
return join12(accountDir, FILE);
|
|
7457
7665
|
}
|
|
7458
7666
|
function readCanonicalOverrideId(accountDir) {
|
|
7459
7667
|
try {
|
|
@@ -7488,10 +7696,10 @@ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9
|
|
|
7488
7696
|
function locateSession(sessionId) {
|
|
7489
7697
|
const cfg = claudeConfigDir();
|
|
7490
7698
|
if (!cfg) return { projectDir: null, channel: null };
|
|
7491
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
7492
|
-
if (
|
|
7493
|
-
const dir =
|
|
7494
|
-
const meta = readSidecarMeta(
|
|
7699
|
+
for (const { path: path2 } of enumerateJsonls(join13(cfg, "projects"))) {
|
|
7700
|
+
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
7701
|
+
const dir = dirname3(path2);
|
|
7702
|
+
const meta = readSidecarMeta(join13(dir, `${sessionId}.meta.json`));
|
|
7495
7703
|
return { projectDir: dir, channel: meta.channel };
|
|
7496
7704
|
}
|
|
7497
7705
|
}
|
|
@@ -7500,7 +7708,7 @@ function locateSession(sessionId) {
|
|
|
7500
7708
|
function locateSidecar(sessionId) {
|
|
7501
7709
|
const cfg = claudeConfigDir();
|
|
7502
7710
|
if (!cfg) return null;
|
|
7503
|
-
const projectsRoot =
|
|
7711
|
+
const projectsRoot = join13(cfg, "projects");
|
|
7504
7712
|
let slugs;
|
|
7505
7713
|
try {
|
|
7506
7714
|
slugs = readdirSync7(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -7508,7 +7716,7 @@ function locateSidecar(sessionId) {
|
|
|
7508
7716
|
return null;
|
|
7509
7717
|
}
|
|
7510
7718
|
for (const slug of slugs) {
|
|
7511
|
-
const metaPath =
|
|
7719
|
+
const metaPath = join13(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
7512
7720
|
if (existsSync8(metaPath)) {
|
|
7513
7721
|
return { channel: readSidecarMeta(metaPath).channel };
|
|
7514
7722
|
}
|
|
@@ -7606,8 +7814,8 @@ async function reapplyLeversViaManager() {
|
|
|
7606
7814
|
}
|
|
7607
7815
|
}
|
|
7608
7816
|
function createWebchatRoutes(deps) {
|
|
7609
|
-
const
|
|
7610
|
-
|
|
7817
|
+
const app51 = new Hono();
|
|
7818
|
+
app51.post("/send", requireAdminSession, async (c) => {
|
|
7611
7819
|
let accountId;
|
|
7612
7820
|
try {
|
|
7613
7821
|
accountId = resolvePlatformAccountId();
|
|
@@ -7738,7 +7946,7 @@ ${note}` : note;
|
|
|
7738
7946
|
}
|
|
7739
7947
|
return c.json({ ok: true });
|
|
7740
7948
|
});
|
|
7741
|
-
|
|
7949
|
+
app51.post("/settings", requireAdminSession, async (c) => {
|
|
7742
7950
|
const body = await c.req.json().catch(() => null);
|
|
7743
7951
|
const op = body?.op;
|
|
7744
7952
|
const value = body?.value;
|
|
@@ -7760,7 +7968,7 @@ ${note}` : note;
|
|
|
7760
7968
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
7761
7969
|
return c.json({ error: "account unresolved" }, 503);
|
|
7762
7970
|
}
|
|
7763
|
-
const accountJsonPath =
|
|
7971
|
+
const accountJsonPath = join13(account.accountDir, "account.json");
|
|
7764
7972
|
try {
|
|
7765
7973
|
const parsed = JSON.parse(readFileSync13(accountJsonPath, "utf8"));
|
|
7766
7974
|
if (op === "model") parsed.adminModel = value;
|
|
@@ -7778,7 +7986,7 @@ ${note}` : note;
|
|
|
7778
7986
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
7779
7987
|
return c.json({ ok: true, settingsApplied });
|
|
7780
7988
|
});
|
|
7781
|
-
|
|
7989
|
+
app51.get("/session", requireAdminSession, async (c) => {
|
|
7782
7990
|
let accountId;
|
|
7783
7991
|
try {
|
|
7784
7992
|
accountId = resolvePlatformAccountId();
|
|
@@ -7807,9 +8015,9 @@ ${note}` : note;
|
|
|
7807
8015
|
const cfg = claudeConfigDir();
|
|
7808
8016
|
let projectDir = null;
|
|
7809
8017
|
if (cfg) {
|
|
7810
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
7811
|
-
if (
|
|
7812
|
-
projectDir =
|
|
8018
|
+
for (const { path: path2 } of enumerateJsonls(join13(cfg, "projects"))) {
|
|
8019
|
+
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
8020
|
+
projectDir = dirname3(path2);
|
|
7813
8021
|
break;
|
|
7814
8022
|
}
|
|
7815
8023
|
}
|
|
@@ -7817,15 +8025,15 @@ ${note}` : note;
|
|
|
7817
8025
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
7818
8026
|
return c.json({ sessionId, projectDir, ...indicators, ...readLevers(account) });
|
|
7819
8027
|
});
|
|
7820
|
-
return
|
|
8028
|
+
return app51;
|
|
7821
8029
|
}
|
|
7822
8030
|
|
|
7823
8031
|
// server/routes/webchat-greeting.ts
|
|
7824
|
-
import { resolve as
|
|
8032
|
+
import { resolve as resolve13 } from "path";
|
|
7825
8033
|
|
|
7826
8034
|
// app/lib/claude-agent/specialist-roster.ts
|
|
7827
8035
|
import { existsSync as existsSync9, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "fs";
|
|
7828
|
-
import { join as
|
|
8036
|
+
import { join as join14 } from "path";
|
|
7829
8037
|
function field(fm, name) {
|
|
7830
8038
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
7831
8039
|
if (!m) return null;
|
|
@@ -7844,7 +8052,7 @@ function readSpecialistRoster(specialistsDir) {
|
|
|
7844
8052
|
if (!file.endsWith(".md")) continue;
|
|
7845
8053
|
let raw;
|
|
7846
8054
|
try {
|
|
7847
|
-
raw = readFileSync14(
|
|
8055
|
+
raw = readFileSync14(join14(specialistsDir, file), "utf-8");
|
|
7848
8056
|
} catch (err) {
|
|
7849
8057
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
7850
8058
|
continue;
|
|
@@ -7885,8 +8093,8 @@ var TASKS_CYPHER = `
|
|
|
7885
8093
|
WITH t ORDER BY coalesce(t.createdAt, '') ASC
|
|
7886
8094
|
WITH collect({ taskId: t.taskId, name: t.name, status: t.status }) AS all
|
|
7887
8095
|
RETURN all[0..${TASK_ITEMS_CAP}] AS items, size(all) AS total`;
|
|
7888
|
-
var
|
|
7889
|
-
|
|
8096
|
+
var app6 = new Hono();
|
|
8097
|
+
app6.get("/", requireAdminSession, async (c) => {
|
|
7890
8098
|
const cacheKey = c.var.cacheKey;
|
|
7891
8099
|
const accountId = getAccountIdForSession(cacheKey);
|
|
7892
8100
|
if (!accountId) {
|
|
@@ -7926,7 +8134,7 @@ app5.get("/", requireAdminSession, async (c) => {
|
|
|
7926
8134
|
let specialists = [];
|
|
7927
8135
|
try {
|
|
7928
8136
|
const roster = readSpecialistRoster(
|
|
7929
|
-
|
|
8137
|
+
resolve13(ACCOUNTS_DIR, accountId, "specialists", "agents")
|
|
7930
8138
|
);
|
|
7931
8139
|
specialists = roster.specialists;
|
|
7932
8140
|
for (const s of roster.skipped) {
|
|
@@ -7957,15 +8165,15 @@ function r2n(value) {
|
|
|
7957
8165
|
}
|
|
7958
8166
|
return Number(value ?? 0);
|
|
7959
8167
|
}
|
|
7960
|
-
var webchat_greeting_default =
|
|
8168
|
+
var webchat_greeting_default = app6;
|
|
7961
8169
|
|
|
7962
8170
|
// server/routes/telegram.ts
|
|
7963
8171
|
import { homedir } from "os";
|
|
7964
|
-
import { resolve as
|
|
8172
|
+
import { resolve as resolve15, join as join15 } from "path";
|
|
7965
8173
|
import { existsSync as existsSync10, readFileSync as readFileSync15 } from "fs";
|
|
7966
8174
|
|
|
7967
8175
|
// app/lib/channel-pty-bridge/bridge.ts
|
|
7968
|
-
import { resolve as
|
|
8176
|
+
import { resolve as resolve14 } from "path";
|
|
7969
8177
|
|
|
7970
8178
|
// app/lib/channel-pty-bridge/manager-client.ts
|
|
7971
8179
|
function managerBase2() {
|
|
@@ -8086,7 +8294,7 @@ function classifyTimeout(ndjson, writeAtMs) {
|
|
|
8086
8294
|
|
|
8087
8295
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
8088
8296
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
8089
|
-
var
|
|
8297
|
+
var TAG21 = "[public-session-review]";
|
|
8090
8298
|
var CONSUMED_CAP = 500;
|
|
8091
8299
|
var consumed = /* @__PURE__ */ new Set();
|
|
8092
8300
|
function consumeOnce(sessionId) {
|
|
@@ -8113,7 +8321,7 @@ async function fetchJsonl(sessionId) {
|
|
|
8113
8321
|
return await res.text();
|
|
8114
8322
|
} catch (err) {
|
|
8115
8323
|
console.error(
|
|
8116
|
-
`${
|
|
8324
|
+
`${TAG21} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
8117
8325
|
);
|
|
8118
8326
|
return null;
|
|
8119
8327
|
}
|
|
@@ -8137,7 +8345,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
8137
8345
|
const res = await fetch(url);
|
|
8138
8346
|
if (!res.ok) {
|
|
8139
8347
|
console.error(
|
|
8140
|
-
`${
|
|
8348
|
+
`${TAG21} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
8141
8349
|
);
|
|
8142
8350
|
return [];
|
|
8143
8351
|
}
|
|
@@ -8145,7 +8353,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
8145
8353
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
8146
8354
|
} catch (err) {
|
|
8147
8355
|
console.error(
|
|
8148
|
-
`${
|
|
8356
|
+
`${TAG21} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
8149
8357
|
);
|
|
8150
8358
|
return [];
|
|
8151
8359
|
}
|
|
@@ -8174,7 +8382,7 @@ function composeInitialMessage(input) {
|
|
|
8174
8382
|
}
|
|
8175
8383
|
async function dispatchReviewer(input, initialMessage) {
|
|
8176
8384
|
const sessionId = randomUUID7();
|
|
8177
|
-
console.log(`${
|
|
8385
|
+
console.log(`${TAG21} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
8178
8386
|
const spawned = await managerRcSpawn({
|
|
8179
8387
|
sessionId,
|
|
8180
8388
|
initialMessage,
|
|
@@ -8194,21 +8402,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
8194
8402
|
const dispatchedAt = Date.now();
|
|
8195
8403
|
if (consumed.has(input.sessionId)) {
|
|
8196
8404
|
console.log(
|
|
8197
|
-
`${
|
|
8405
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
8198
8406
|
);
|
|
8199
8407
|
return;
|
|
8200
8408
|
}
|
|
8201
8409
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
8202
8410
|
if (!jsonl) {
|
|
8203
8411
|
console.log(
|
|
8204
|
-
`${
|
|
8412
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
8205
8413
|
);
|
|
8206
8414
|
return;
|
|
8207
8415
|
}
|
|
8208
8416
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
8209
8417
|
if (operatorTurns === 0) {
|
|
8210
8418
|
console.log(
|
|
8211
|
-
`${
|
|
8419
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
8212
8420
|
);
|
|
8213
8421
|
return;
|
|
8214
8422
|
}
|
|
@@ -8222,19 +8430,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
8222
8430
|
});
|
|
8223
8431
|
if (!consumeOnce(input.sessionId)) {
|
|
8224
8432
|
console.log(
|
|
8225
|
-
`${
|
|
8433
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
8226
8434
|
);
|
|
8227
8435
|
return;
|
|
8228
8436
|
}
|
|
8229
8437
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
8230
8438
|
if (!dispatched.ok) {
|
|
8231
8439
|
console.error(
|
|
8232
|
-
`${
|
|
8440
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
8233
8441
|
);
|
|
8234
8442
|
return;
|
|
8235
8443
|
}
|
|
8236
8444
|
console.log(
|
|
8237
|
-
`${
|
|
8445
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
8238
8446
|
);
|
|
8239
8447
|
}
|
|
8240
8448
|
|
|
@@ -8405,7 +8613,7 @@ async function fanOut(subscribers, text, onError, tag) {
|
|
|
8405
8613
|
}
|
|
8406
8614
|
|
|
8407
8615
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
8408
|
-
var
|
|
8616
|
+
var TAG22 = "[whatsapp-adaptor]";
|
|
8409
8617
|
var SEND_USER_FILE = "SendUserFile";
|
|
8410
8618
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
8411
8619
|
function platformRoot() {
|
|
@@ -8440,7 +8648,7 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
8440
8648
|
maxyAccountId = resolvePlatformAccountId();
|
|
8441
8649
|
} catch (err) {
|
|
8442
8650
|
console.error(
|
|
8443
|
-
`${
|
|
8651
|
+
`${TAG22} file-delivery reject reason=account-unresolved sender=${entry.senderId} message=${err instanceof Error ? err.message : String(err)}`
|
|
8444
8652
|
);
|
|
8445
8653
|
return;
|
|
8446
8654
|
}
|
|
@@ -8457,7 +8665,7 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
8457
8665
|
if (!result.ok) {
|
|
8458
8666
|
failedFiles.push(files[i]);
|
|
8459
8667
|
console.error(
|
|
8460
|
-
`${
|
|
8668
|
+
`${TAG22} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
8461
8669
|
);
|
|
8462
8670
|
}
|
|
8463
8671
|
}
|
|
@@ -8474,7 +8682,7 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
8474
8682
|
const sid = entry.sessionId.slice(0, 8);
|
|
8475
8683
|
for (const file of failed) {
|
|
8476
8684
|
console.error(
|
|
8477
|
-
`${
|
|
8685
|
+
`${TAG22} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${SEND_USER_FILE} file=${file}`
|
|
8478
8686
|
);
|
|
8479
8687
|
}
|
|
8480
8688
|
const okAt = documentOutboundAt(entry.senderId);
|
|
@@ -8485,13 +8693,13 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
8485
8693
|
if (!delivered) {
|
|
8486
8694
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
8487
8695
|
console.error(
|
|
8488
|
-
`${
|
|
8696
|
+
`${TAG22} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
8489
8697
|
);
|
|
8490
8698
|
}
|
|
8491
8699
|
}
|
|
8492
8700
|
if (firedTools.includes(SEND_USER_FILE) && attempts === 0 && !documentWentOut) {
|
|
8493
8701
|
console.error(
|
|
8494
|
-
`${
|
|
8702
|
+
`${TAG22} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${SEND_USER_FILE}`
|
|
8495
8703
|
);
|
|
8496
8704
|
}
|
|
8497
8705
|
}
|
|
@@ -8562,7 +8770,7 @@ async function ensureEntry(input) {
|
|
|
8562
8770
|
});
|
|
8563
8771
|
} else {
|
|
8564
8772
|
console.error(`${tag} route role=${input.role} target=public-spawn senderId=${input.senderId}`);
|
|
8565
|
-
const attachmentDir =
|
|
8773
|
+
const attachmentDir = resolve14(DATA_ROOT, "accounts", input.accountId, "uploads", "public", input.senderId);
|
|
8566
8774
|
spawned = await managerSpawn({
|
|
8567
8775
|
senderId: input.senderId,
|
|
8568
8776
|
role: input.role,
|
|
@@ -8694,12 +8902,12 @@ async function dispatchOnce(input) {
|
|
|
8694
8902
|
});
|
|
8695
8903
|
if (!entry) return { error: "spawn-failed" };
|
|
8696
8904
|
entry.lastInboundAt = Date.now();
|
|
8697
|
-
let
|
|
8905
|
+
let resolve32;
|
|
8698
8906
|
const turnPromise = new Promise((r) => {
|
|
8699
|
-
|
|
8907
|
+
resolve32 = r;
|
|
8700
8908
|
});
|
|
8701
8909
|
const listener = (text) => {
|
|
8702
|
-
|
|
8910
|
+
resolve32(text);
|
|
8703
8911
|
};
|
|
8704
8912
|
entry.subscribers.add(listener);
|
|
8705
8913
|
const writeAtMs = Date.now();
|
|
@@ -8846,11 +9054,11 @@ function routeTelegramUpdate(input) {
|
|
|
8846
9054
|
}
|
|
8847
9055
|
|
|
8848
9056
|
// server/routes/telegram.ts
|
|
8849
|
-
var
|
|
9057
|
+
var TAG23 = "[telegram-inbound]";
|
|
8850
9058
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
8851
9059
|
function configDirName() {
|
|
8852
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ??
|
|
8853
|
-
const brandPath =
|
|
9060
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "..");
|
|
9061
|
+
const brandPath = join15(platformRoot2, "config", "brand.json");
|
|
8854
9062
|
if (existsSync10(brandPath)) {
|
|
8855
9063
|
try {
|
|
8856
9064
|
return JSON.parse(readFileSync15(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
@@ -8861,7 +9069,7 @@ function configDirName() {
|
|
|
8861
9069
|
}
|
|
8862
9070
|
function secretPath(botType) {
|
|
8863
9071
|
const filename = botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret";
|
|
8864
|
-
return
|
|
9072
|
+
return resolve15(homedir(), configDirName(), filename);
|
|
8865
9073
|
}
|
|
8866
9074
|
async function sendTelegram(botToken, chatId, text) {
|
|
8867
9075
|
try {
|
|
@@ -8876,23 +9084,23 @@ async function sendTelegram(botToken, chatId, text) {
|
|
|
8876
9084
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
8877
9085
|
}
|
|
8878
9086
|
}
|
|
8879
|
-
var
|
|
8880
|
-
|
|
9087
|
+
var app7 = new Hono();
|
|
9088
|
+
app7.post("/", async (c) => {
|
|
8881
9089
|
const botParam = c.req.query("bot");
|
|
8882
9090
|
const botType = botParam === "admin" ? "admin" : botParam === "public" ? "public" : null;
|
|
8883
9091
|
if (!botType) {
|
|
8884
|
-
console.error(`${
|
|
9092
|
+
console.error(`${TAG23} op=reject reason=missing-bot-param`);
|
|
8885
9093
|
return c.json({ ok: false }, 400);
|
|
8886
9094
|
}
|
|
8887
9095
|
const sp = secretPath(botType);
|
|
8888
9096
|
if (!existsSync10(sp)) {
|
|
8889
|
-
console.error(`${
|
|
9097
|
+
console.error(`${TAG23} op=reject reason=no-secret-file botType=${botType}`);
|
|
8890
9098
|
return c.json({ ok: false }, 401);
|
|
8891
9099
|
}
|
|
8892
9100
|
const expected = readFileSync15(sp, "utf-8").trim();
|
|
8893
9101
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
8894
9102
|
if (got !== expected) {
|
|
8895
|
-
console.error(`${
|
|
9103
|
+
console.error(`${TAG23} op=reject reason=bad-secret botType=${botType}`);
|
|
8896
9104
|
return c.json({ ok: false }, 401);
|
|
8897
9105
|
}
|
|
8898
9106
|
let update;
|
|
@@ -8903,25 +9111,25 @@ app6.post("/", async (c) => {
|
|
|
8903
9111
|
}
|
|
8904
9112
|
const account = resolveAccount();
|
|
8905
9113
|
if (!account) {
|
|
8906
|
-
console.error(`${
|
|
9114
|
+
console.error(`${TAG23} op=reject reason=no-account`);
|
|
8907
9115
|
return c.json({ ok: true }, 200);
|
|
8908
9116
|
}
|
|
8909
9117
|
const decision = routeTelegramUpdate({ update, botType, config: account.config.telegram ?? {} });
|
|
8910
9118
|
if (decision.kind === "ignore") {
|
|
8911
|
-
console.error(`${
|
|
9119
|
+
console.error(`${TAG23} op=ignore reason=${decision.reason}`);
|
|
8912
9120
|
return c.json({ ok: true }, 200);
|
|
8913
9121
|
}
|
|
8914
9122
|
if (decision.kind === "denied") {
|
|
8915
|
-
console.error(`${
|
|
9123
|
+
console.error(`${TAG23} op=denied reason=${decision.reason} agentType=${decision.agentType}`);
|
|
8916
9124
|
return c.json({ ok: true }, 200);
|
|
8917
9125
|
}
|
|
8918
9126
|
const role = decision.agentType === "admin" ? "admin" : "public";
|
|
8919
9127
|
const agentSlug = role === "admin" ? "admin" : resolveDefaultAgentSlug(account.accountDir);
|
|
8920
9128
|
if (!agentSlug) {
|
|
8921
|
-
console.error(`${
|
|
9129
|
+
console.error(`${TAG23} op=reject reason=no-default-agent`);
|
|
8922
9130
|
return c.json({ ok: true }, 200);
|
|
8923
9131
|
}
|
|
8924
|
-
console.error(`${
|
|
9132
|
+
console.error(`${TAG23} op=update accountId=${account.accountId} from=${decision.senderId}`);
|
|
8925
9133
|
const botToken = botType === "admin" ? account.config.telegram?.adminBotToken : account.config.telegram?.publicBotToken;
|
|
8926
9134
|
const { senderId, chatId, text } = decision;
|
|
8927
9135
|
void (async () => {
|
|
@@ -8935,29 +9143,29 @@ app6.post("/", async (c) => {
|
|
|
8935
9143
|
timeoutMs: DISPATCH_TIMEOUT_MS
|
|
8936
9144
|
});
|
|
8937
9145
|
if ("error" in result) {
|
|
8938
|
-
console.error(`${
|
|
9146
|
+
console.error(`${TAG23} op=dispatch-failed from=${senderId} error=${result.error}`);
|
|
8939
9147
|
return;
|
|
8940
9148
|
}
|
|
8941
9149
|
if (!botToken) {
|
|
8942
9150
|
const reason = account.config.telegram ? "no-bot-token" : "no-telegram-config";
|
|
8943
|
-
console.error(`${
|
|
9151
|
+
console.error(`${TAG23} op=reply-dropped reason=${reason} botType=${botType}`);
|
|
8944
9152
|
return;
|
|
8945
9153
|
}
|
|
8946
9154
|
const sent = await sendTelegram(botToken, chatId, result.turnText);
|
|
8947
|
-
console.error(`${
|
|
9155
|
+
console.error(`${TAG23} op=reply-sent from=${senderId} ok=${sent.ok}${sent.ok ? "" : ` error=${sent.error}`}`);
|
|
8948
9156
|
})();
|
|
8949
9157
|
return c.json({ ok: true }, 200);
|
|
8950
9158
|
});
|
|
8951
|
-
var telegram_default =
|
|
9159
|
+
var telegram_default = app7;
|
|
8952
9160
|
|
|
8953
9161
|
// server/routes/onboarding.ts
|
|
8954
9162
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
8955
|
-
import { openSync as
|
|
9163
|
+
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync8, writeSync, existsSync as existsSync12, readFileSync as readFileSync17, unlinkSync } from "fs";
|
|
8956
9164
|
import { createHash as createHash3, randomUUID as randomUUID8 } from "crypto";
|
|
8957
9165
|
|
|
8958
9166
|
// ../lib/admins-write/src/index.ts
|
|
8959
|
-
import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync7, renameSync as renameSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync9, statSync as
|
|
8960
|
-
import { dirname as
|
|
9167
|
+
import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync7, renameSync as renameSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync9, statSync as statSync6 } from "fs";
|
|
9168
|
+
import { dirname as dirname4, join as join16 } from "path";
|
|
8961
9169
|
function logLine(input, result) {
|
|
8962
9170
|
const userIdShort = input.userId.slice(0, 8);
|
|
8963
9171
|
console.error(
|
|
@@ -8965,7 +9173,7 @@ function logLine(input, result) {
|
|
|
8965
9173
|
);
|
|
8966
9174
|
}
|
|
8967
9175
|
function writeFileAtomic(filePath, contents, mode) {
|
|
8968
|
-
mkdirSync2(
|
|
9176
|
+
mkdirSync2(dirname4(filePath), { recursive: true });
|
|
8969
9177
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
8970
9178
|
writeFileSync7(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
8971
9179
|
renameSync3(tempPath, filePath);
|
|
@@ -8999,7 +9207,7 @@ function writeAdminEntry(input) {
|
|
|
8999
9207
|
return result;
|
|
9000
9208
|
}
|
|
9001
9209
|
try {
|
|
9002
|
-
const accountJsonPath =
|
|
9210
|
+
const accountJsonPath = join16(input.accountDir, "account.json");
|
|
9003
9211
|
if (!existsSync11(accountJsonPath)) {
|
|
9004
9212
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
9005
9213
|
}
|
|
@@ -9054,13 +9262,13 @@ function checkAdminAuthInvariant(input) {
|
|
|
9054
9262
|
}
|
|
9055
9263
|
for (const entry of entries) {
|
|
9056
9264
|
if (entry.startsWith(".")) continue;
|
|
9057
|
-
const accountDir =
|
|
9265
|
+
const accountDir = join16(input.accountsDir, entry);
|
|
9058
9266
|
try {
|
|
9059
|
-
if (!
|
|
9267
|
+
if (!statSync6(accountDir).isDirectory()) continue;
|
|
9060
9268
|
} catch {
|
|
9061
9269
|
continue;
|
|
9062
9270
|
}
|
|
9063
|
-
const accountJsonPath =
|
|
9271
|
+
const accountJsonPath = join16(accountDir, "account.json");
|
|
9064
9272
|
if (!existsSync11(accountJsonPath)) continue;
|
|
9065
9273
|
let admins = [];
|
|
9066
9274
|
try {
|
|
@@ -9135,11 +9343,11 @@ async function waitForAuthPage(timeoutMs = 2e4) {
|
|
|
9135
9343
|
}
|
|
9136
9344
|
return false;
|
|
9137
9345
|
}
|
|
9138
|
-
var
|
|
9139
|
-
|
|
9346
|
+
var app8 = new Hono();
|
|
9347
|
+
app8.get("/claude-auth", async (c) => {
|
|
9140
9348
|
return c.json({ authenticated: await checkAuthStatus() });
|
|
9141
9349
|
});
|
|
9142
|
-
|
|
9350
|
+
app8.post("/claude-auth", async (c) => {
|
|
9143
9351
|
let body = {};
|
|
9144
9352
|
try {
|
|
9145
9353
|
body = await c.req.json();
|
|
@@ -9177,7 +9385,7 @@ app7.post("/claude-auth", async (c) => {
|
|
|
9177
9385
|
}
|
|
9178
9386
|
ensureLogDir();
|
|
9179
9387
|
writeFileSync8(logPath("claude-auth"), "");
|
|
9180
|
-
const claudeAuthLogFd =
|
|
9388
|
+
const claudeAuthLogFd = openSync3(logPath("claude-auth"), "a");
|
|
9181
9389
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
9182
9390
|
if (process.platform === "darwin") {
|
|
9183
9391
|
vncLog("claude-auth", { action: "start", transport: "native", platform: "darwin" });
|
|
@@ -9187,7 +9395,7 @@ app7.post("/claude-auth", async (c) => {
|
|
|
9187
9395
|
claudeProc2.unref();
|
|
9188
9396
|
claudeProc2.stdout?.on("data", onClaudeOutput);
|
|
9189
9397
|
claudeProc2.stderr?.on("data", onClaudeOutput);
|
|
9190
|
-
claudeProc2.once("close", () =>
|
|
9398
|
+
claudeProc2.once("close", () => closeSync3(claudeAuthLogFd));
|
|
9191
9399
|
return c.json({ started: true, transport: "native" });
|
|
9192
9400
|
}
|
|
9193
9401
|
if (transport === "vnc") {
|
|
@@ -9205,11 +9413,11 @@ app7.post("/claude-auth", async (c) => {
|
|
|
9205
9413
|
claudeProc.unref();
|
|
9206
9414
|
claudeProc.stdout?.on("data", onClaudeOutput);
|
|
9207
9415
|
claudeProc.stderr?.on("data", onClaudeOutput);
|
|
9208
|
-
claudeProc.once("close", () =>
|
|
9416
|
+
claudeProc.once("close", () => closeSync3(claudeAuthLogFd));
|
|
9209
9417
|
await waitForAuthPage(2e4);
|
|
9210
9418
|
return c.json({ started: true, transport });
|
|
9211
9419
|
});
|
|
9212
|
-
|
|
9420
|
+
app8.post("/set-pin", async (c) => {
|
|
9213
9421
|
let existingUsers = null;
|
|
9214
9422
|
try {
|
|
9215
9423
|
existingUsers = readUsersFile2();
|
|
@@ -9311,7 +9519,7 @@ ${body.pin}
|
|
|
9311
9519
|
}
|
|
9312
9520
|
return c.json({ ok: true });
|
|
9313
9521
|
});
|
|
9314
|
-
|
|
9522
|
+
app8.delete("/set-pin", async (c) => {
|
|
9315
9523
|
let users = null;
|
|
9316
9524
|
try {
|
|
9317
9525
|
users = readUsersFile2();
|
|
@@ -9345,12 +9553,12 @@ app7.delete("/set-pin", async (c) => {
|
|
|
9345
9553
|
}
|
|
9346
9554
|
return c.json({ ok: true });
|
|
9347
9555
|
});
|
|
9348
|
-
var onboarding_default =
|
|
9556
|
+
var onboarding_default = app8;
|
|
9349
9557
|
|
|
9350
9558
|
// server/routes/client-error.ts
|
|
9351
|
-
import { appendFileSync, existsSync as existsSync13, renameSync as renameSync4, statSync as
|
|
9352
|
-
import { join as
|
|
9353
|
-
var CLIENT_ERRORS_LOG =
|
|
9559
|
+
import { appendFileSync, existsSync as existsSync13, renameSync as renameSync4, statSync as statSync7 } from "fs";
|
|
9560
|
+
import { join as join17 } from "path";
|
|
9561
|
+
var CLIENT_ERRORS_LOG = join17(LOG_DIR, "client-errors.log");
|
|
9354
9562
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
9355
9563
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
9356
9564
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -9394,15 +9602,15 @@ function stackHead(stack) {
|
|
|
9394
9602
|
function rotateIfNeeded() {
|
|
9395
9603
|
try {
|
|
9396
9604
|
if (!existsSync13(CLIENT_ERRORS_LOG)) return;
|
|
9397
|
-
const stats =
|
|
9605
|
+
const stats = statSync7(CLIENT_ERRORS_LOG);
|
|
9398
9606
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
9399
9607
|
renameSync4(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
9400
9608
|
} catch (err) {
|
|
9401
9609
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
9402
9610
|
}
|
|
9403
9611
|
}
|
|
9404
|
-
var
|
|
9405
|
-
|
|
9612
|
+
var app9 = new Hono();
|
|
9613
|
+
app9.post("/", async (c) => {
|
|
9406
9614
|
const client = resolveClientIp(
|
|
9407
9615
|
c.env?.incoming?.socket?.remoteAddress,
|
|
9408
9616
|
c.req.header("x-forwarded-for")
|
|
@@ -9504,7 +9712,7 @@ app8.post("/", async (c) => {
|
|
|
9504
9712
|
}
|
|
9505
9713
|
return c.json({ ok: true });
|
|
9506
9714
|
});
|
|
9507
|
-
var client_error_default =
|
|
9715
|
+
var client_error_default = app9;
|
|
9508
9716
|
|
|
9509
9717
|
// server/routes/admin/session.ts
|
|
9510
9718
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
@@ -9562,8 +9770,8 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
|
|
|
9562
9770
|
sessionId: initialSessionId
|
|
9563
9771
|
};
|
|
9564
9772
|
}
|
|
9565
|
-
var
|
|
9566
|
-
|
|
9773
|
+
var app10 = new Hono();
|
|
9774
|
+
app10.get("/", async (c) => {
|
|
9567
9775
|
const signedSessionToken = c.req.query("session_key");
|
|
9568
9776
|
if (!signedSessionToken) {
|
|
9569
9777
|
return c.json({ error: "Invalid or expired admin session" }, 401);
|
|
@@ -9609,7 +9817,7 @@ app9.get("/", async (c) => {
|
|
|
9609
9817
|
sessionId: getSessionIdForSession(cacheKey) ?? null
|
|
9610
9818
|
});
|
|
9611
9819
|
});
|
|
9612
|
-
|
|
9820
|
+
app10.post("/", async (c) => {
|
|
9613
9821
|
let body;
|
|
9614
9822
|
try {
|
|
9615
9823
|
body = await c.req.json();
|
|
@@ -9672,20 +9880,20 @@ app9.post("/", async (c) => {
|
|
|
9672
9880
|
const payload = await createAdminSession(selected.accountId, selected.config.thinkingView, userId, userName, selected.role, avatar);
|
|
9673
9881
|
return c.json(payload);
|
|
9674
9882
|
});
|
|
9675
|
-
var session_default =
|
|
9883
|
+
var session_default = app10;
|
|
9676
9884
|
|
|
9677
9885
|
// server/routes/admin/logs.ts
|
|
9678
|
-
import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync18, statSync as
|
|
9679
|
-
import { resolve as
|
|
9886
|
+
import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync18, statSync as statSync8 } from "fs";
|
|
9887
|
+
import { resolve as resolve16, basename as basename5 } from "path";
|
|
9680
9888
|
|
|
9681
9889
|
// app/lib/logs-read-resolve.ts
|
|
9682
9890
|
import { existsSync as existsSync14 } from "fs";
|
|
9683
|
-
import { join as
|
|
9891
|
+
import { join as join18 } from "path";
|
|
9684
9892
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
9685
9893
|
const tried = [filename];
|
|
9686
9894
|
const hits = [];
|
|
9687
9895
|
for (const dir of logDirs) {
|
|
9688
|
-
const fullPath =
|
|
9896
|
+
const fullPath = join18(dir, filename);
|
|
9689
9897
|
if (existsSync14(fullPath)) {
|
|
9690
9898
|
hits.push({ path: fullPath, dir });
|
|
9691
9899
|
}
|
|
@@ -9695,27 +9903,27 @@ function resolveSessionLogPaths(filename, logDirs) {
|
|
|
9695
9903
|
|
|
9696
9904
|
// server/routes/admin/logs.ts
|
|
9697
9905
|
var TAIL_BYTES = 8192;
|
|
9698
|
-
var
|
|
9699
|
-
|
|
9906
|
+
var app11 = new Hono();
|
|
9907
|
+
app11.get("/", async (c) => {
|
|
9700
9908
|
const fileParam = c.req.query("file");
|
|
9701
9909
|
const typeParam = c.req.query("type");
|
|
9702
9910
|
const sessionIdParam = c.req.query("sessionId");
|
|
9703
9911
|
const cacheKeyParam = c.req.query("cacheKey");
|
|
9704
9912
|
const download = c.req.query("download") === "1";
|
|
9705
9913
|
const account = resolveAccount();
|
|
9706
|
-
const accountLogDir = account ?
|
|
9914
|
+
const accountLogDir = account ? resolve16(account.accountDir, "logs") : null;
|
|
9707
9915
|
const logDirs = [];
|
|
9708
9916
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
9709
9917
|
logDirs.push(LOG_DIR);
|
|
9710
9918
|
if (fileParam) {
|
|
9711
|
-
const safe =
|
|
9919
|
+
const safe = basename5(fileParam);
|
|
9712
9920
|
const searched = [];
|
|
9713
9921
|
for (const dir of logDirs) {
|
|
9714
|
-
const filePath =
|
|
9922
|
+
const filePath = resolve16(dir, safe);
|
|
9715
9923
|
searched.push(filePath);
|
|
9716
9924
|
try {
|
|
9717
9925
|
const buffer = readFileSync18(filePath);
|
|
9718
|
-
const onDiskBytes =
|
|
9926
|
+
const onDiskBytes = statSync8(filePath).size;
|
|
9719
9927
|
const headers = {
|
|
9720
9928
|
"Content-Type": "text/plain; charset=utf-8",
|
|
9721
9929
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -9778,9 +9986,9 @@ app10.get("/", async (c) => {
|
|
|
9778
9986
|
if (hit) {
|
|
9779
9987
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
9780
9988
|
try {
|
|
9781
|
-
const filename =
|
|
9989
|
+
const filename = basename5(hit.path);
|
|
9782
9990
|
const buffer = readFileSync18(hit.path);
|
|
9783
|
-
const onDiskBytes =
|
|
9991
|
+
const onDiskBytes = statSync8(hit.path).size;
|
|
9784
9992
|
const headers = {
|
|
9785
9993
|
"Content-Type": "text/plain; charset=utf-8",
|
|
9786
9994
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -9823,10 +10031,10 @@ app10.get("/", async (c) => {
|
|
|
9823
10031
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
9824
10032
|
continue;
|
|
9825
10033
|
}
|
|
9826
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime:
|
|
10034
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync8(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
9827
10035
|
seen.add(name);
|
|
9828
10036
|
try {
|
|
9829
|
-
const content = readFileSync18(
|
|
10037
|
+
const content = readFileSync18(resolve16(dir, name));
|
|
9830
10038
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
9831
10039
|
logs[name] = tail.trim() || "(empty)";
|
|
9832
10040
|
} catch (err) {
|
|
@@ -9838,12 +10046,12 @@ app10.get("/", async (c) => {
|
|
|
9838
10046
|
}
|
|
9839
10047
|
return c.json({ logs });
|
|
9840
10048
|
});
|
|
9841
|
-
var logs_default =
|
|
10049
|
+
var logs_default = app11;
|
|
9842
10050
|
|
|
9843
10051
|
// server/routes/admin/claude-info.ts
|
|
9844
10052
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
9845
|
-
var
|
|
9846
|
-
|
|
10053
|
+
var app12 = new Hono();
|
|
10054
|
+
app12.get("/", (c) => {
|
|
9847
10055
|
let version = "unknown";
|
|
9848
10056
|
try {
|
|
9849
10057
|
const raw = execFileSync3("claude", ["--version"], { encoding: "utf-8", timeout: 5e3 });
|
|
@@ -9861,14 +10069,14 @@ app11.get("/", (c) => {
|
|
|
9861
10069
|
const thinkingView = resolvedAccount?.config.thinkingView ?? "default";
|
|
9862
10070
|
return c.json({ version, account, model, thinkingView });
|
|
9863
10071
|
});
|
|
9864
|
-
var claude_info_default =
|
|
10072
|
+
var claude_info_default = app12;
|
|
9865
10073
|
|
|
9866
10074
|
// server/routes/admin/attachment.ts
|
|
9867
10075
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
9868
10076
|
import { existsSync as existsSync16 } from "fs";
|
|
9869
|
-
import { resolve as
|
|
9870
|
-
var
|
|
9871
|
-
|
|
10077
|
+
import { resolve as resolve17 } from "path";
|
|
10078
|
+
var app13 = new Hono();
|
|
10079
|
+
app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
9872
10080
|
const attachmentId = c.req.param("attachmentId");
|
|
9873
10081
|
const cacheKey = c.var.cacheKey;
|
|
9874
10082
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -9878,11 +10086,11 @@ app12.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9878
10086
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
|
|
9879
10087
|
return new Response("Not found", { status: 404 });
|
|
9880
10088
|
}
|
|
9881
|
-
const dir =
|
|
10089
|
+
const dir = resolve17(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
9882
10090
|
if (!existsSync16(dir)) {
|
|
9883
10091
|
return new Response("Not found", { status: 404 });
|
|
9884
10092
|
}
|
|
9885
|
-
const metaPath =
|
|
10093
|
+
const metaPath = resolve17(dir, `${attachmentId}.meta.json`);
|
|
9886
10094
|
if (!existsSync16(metaPath)) {
|
|
9887
10095
|
return new Response("Not found", { status: 404 });
|
|
9888
10096
|
}
|
|
@@ -9897,7 +10105,7 @@ app12.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9897
10105
|
if (!dataFile) {
|
|
9898
10106
|
return new Response("Not found", { status: 404 });
|
|
9899
10107
|
}
|
|
9900
|
-
const filePath =
|
|
10108
|
+
const filePath = resolve17(dir, dataFile);
|
|
9901
10109
|
const buffer = await readFile2(filePath);
|
|
9902
10110
|
return new Response(new Uint8Array(buffer), {
|
|
9903
10111
|
headers: {
|
|
@@ -9907,16 +10115,16 @@ app12.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9907
10115
|
}
|
|
9908
10116
|
});
|
|
9909
10117
|
});
|
|
9910
|
-
var attachment_default =
|
|
10118
|
+
var attachment_default = app13;
|
|
9911
10119
|
|
|
9912
10120
|
// server/routes/admin/agents.ts
|
|
9913
|
-
import { resolve as
|
|
10121
|
+
import { resolve as resolve18 } from "path";
|
|
9914
10122
|
import { readdirSync as readdirSync11, readFileSync as readFileSync19, existsSync as existsSync17, rmSync } from "fs";
|
|
9915
|
-
var
|
|
9916
|
-
|
|
10123
|
+
var app14 = new Hono();
|
|
10124
|
+
app14.get("/", (c) => {
|
|
9917
10125
|
const account = resolveAccount();
|
|
9918
10126
|
if (!account) return c.json({ agents: [] });
|
|
9919
|
-
const agentsDir =
|
|
10127
|
+
const agentsDir = resolve18(account.accountDir, "agents");
|
|
9920
10128
|
if (!existsSync17(agentsDir)) return c.json({ agents: [] });
|
|
9921
10129
|
const agents = [];
|
|
9922
10130
|
try {
|
|
@@ -9924,7 +10132,7 @@ app13.get("/", (c) => {
|
|
|
9924
10132
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
9925
10133
|
if (!entry.isDirectory()) continue;
|
|
9926
10134
|
if (entry.name === "admin") continue;
|
|
9927
|
-
const configPath2 =
|
|
10135
|
+
const configPath2 = resolve18(agentsDir, entry.name, "config.json");
|
|
9928
10136
|
if (!existsSync17(configPath2)) continue;
|
|
9929
10137
|
try {
|
|
9930
10138
|
const config = JSON.parse(readFileSync19(configPath2, "utf-8"));
|
|
@@ -9943,7 +10151,7 @@ app13.get("/", (c) => {
|
|
|
9943
10151
|
}
|
|
9944
10152
|
return c.json({ agents });
|
|
9945
10153
|
});
|
|
9946
|
-
|
|
10154
|
+
app14.delete("/:slug", async (c) => {
|
|
9947
10155
|
const slug = c.req.param("slug");
|
|
9948
10156
|
const account = resolveAccount();
|
|
9949
10157
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -9953,7 +10161,7 @@ app13.delete("/:slug", async (c) => {
|
|
|
9953
10161
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9954
10162
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9955
10163
|
}
|
|
9956
|
-
const agentDir =
|
|
10164
|
+
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
9957
10165
|
if (!existsSync17(agentDir)) {
|
|
9958
10166
|
return c.json({ error: "Agent not found" }, 404);
|
|
9959
10167
|
}
|
|
@@ -9973,7 +10181,7 @@ app13.delete("/:slug", async (c) => {
|
|
|
9973
10181
|
return c.json({ error: "Failed to delete agent" }, 500);
|
|
9974
10182
|
}
|
|
9975
10183
|
});
|
|
9976
|
-
|
|
10184
|
+
app14.post("/:slug/project", async (c) => {
|
|
9977
10185
|
const slug = c.req.param("slug");
|
|
9978
10186
|
const account = resolveAccount();
|
|
9979
10187
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -9983,7 +10191,7 @@ app13.post("/:slug/project", async (c) => {
|
|
|
9983
10191
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9984
10192
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9985
10193
|
}
|
|
9986
|
-
const agentDir =
|
|
10194
|
+
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
9987
10195
|
if (!existsSync17(agentDir)) {
|
|
9988
10196
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
9989
10197
|
}
|
|
@@ -9995,7 +10203,7 @@ app13.post("/:slug/project", async (c) => {
|
|
|
9995
10203
|
return c.json({ error: `Projection failed: ${msg}` }, 500);
|
|
9996
10204
|
}
|
|
9997
10205
|
});
|
|
9998
|
-
var agents_default =
|
|
10206
|
+
var agents_default = app14;
|
|
9999
10207
|
|
|
10000
10208
|
// server/routes/admin/sessions.ts
|
|
10001
10209
|
import crypto2 from "crypto";
|
|
@@ -10267,8 +10475,8 @@ function formatAge(updatedAtStr) {
|
|
|
10267
10475
|
return "unknown";
|
|
10268
10476
|
}
|
|
10269
10477
|
}
|
|
10270
|
-
var
|
|
10271
|
-
|
|
10478
|
+
var app15 = new Hono();
|
|
10479
|
+
app15.get("/", requireAdminSession, async (c) => {
|
|
10272
10480
|
const cacheKey = c.var.cacheKey;
|
|
10273
10481
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10274
10482
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -10298,7 +10506,7 @@ app14.get("/", requireAdminSession, async (c) => {
|
|
|
10298
10506
|
return c.json({ error: "Failed to fetch sessions" }, 500);
|
|
10299
10507
|
}
|
|
10300
10508
|
});
|
|
10301
|
-
|
|
10509
|
+
app15.post("/new", requireAdminSession, async (c) => {
|
|
10302
10510
|
const oldCacheKey = c.var.cacheKey;
|
|
10303
10511
|
console.log(`[admin-chat] new-conversation outcome=ingress cacheKey=${oldCacheKey.slice(0, 8)}`);
|
|
10304
10512
|
const accountId = getAccountIdForSession(oldCacheKey);
|
|
@@ -10315,7 +10523,7 @@ app14.post("/new", requireAdminSession, async (c) => {
|
|
|
10315
10523
|
console.log(`[admin-chat] new-conversation outcome=ok oldKey=${oldCacheKey.slice(0, 8)} newKey=${newCacheKey.slice(0, 8)}`);
|
|
10316
10524
|
return c.json({ session_key: newSignedSessionToken, sessionId: null });
|
|
10317
10525
|
});
|
|
10318
|
-
|
|
10526
|
+
app15.post("/switch", requireAdminSession, async (c) => {
|
|
10319
10527
|
const cacheKey = c.var.cacheKey;
|
|
10320
10528
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10321
10529
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -10343,7 +10551,7 @@ app14.post("/switch", requireAdminSession, async (c) => {
|
|
|
10343
10551
|
console.log(`[session-switch] from=${cacheKey.slice(0, 8)} to=${targetCacheKey.slice(0, 8)} targetConvId=${targetSessionId?.slice(0, 8) ?? "none"} accountId=${accountId.slice(0, 8)}`);
|
|
10344
10552
|
return c.json({ session_key: targetSignedSessionToken, sessionId: targetSessionId });
|
|
10345
10553
|
});
|
|
10346
|
-
|
|
10554
|
+
app15.delete("/:id", requireAdminSession, async (c) => {
|
|
10347
10555
|
const sessionId = c.req.param("id");
|
|
10348
10556
|
const cacheKey = c.var.cacheKey;
|
|
10349
10557
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -10388,7 +10596,7 @@ app14.delete("/:id", requireAdminSession, async (c) => {
|
|
|
10388
10596
|
500
|
|
10389
10597
|
);
|
|
10390
10598
|
});
|
|
10391
|
-
|
|
10599
|
+
app15.post("/:id/resume", async (c) => {
|
|
10392
10600
|
const sessionId = c.req.param("id");
|
|
10393
10601
|
const t0 = Date.now();
|
|
10394
10602
|
const signedSessionToken = c.req.query("session_key") ?? "";
|
|
@@ -10657,7 +10865,7 @@ app14.post("/:id/resume", async (c) => {
|
|
|
10657
10865
|
}
|
|
10658
10866
|
});
|
|
10659
10867
|
});
|
|
10660
|
-
|
|
10868
|
+
app15.put("/:id/label", requireAdminSession, async (c) => {
|
|
10661
10869
|
const sessionId = c.req.param("id");
|
|
10662
10870
|
const cacheKey = c.var.cacheKey;
|
|
10663
10871
|
let body;
|
|
@@ -10683,11 +10891,11 @@ app14.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
10683
10891
|
return c.json({ error: "Failed to rename session" }, 500);
|
|
10684
10892
|
}
|
|
10685
10893
|
});
|
|
10686
|
-
var sessions_default =
|
|
10894
|
+
var sessions_default = app15;
|
|
10687
10895
|
|
|
10688
10896
|
// app/lib/claude-agent/spawn-context.ts
|
|
10689
|
-
import { existsSync as existsSync19, readFileSync as readFileSync20, readdirSync as readdirSync12, statSync as
|
|
10690
|
-
import { dirname as
|
|
10897
|
+
import { existsSync as existsSync19, readFileSync as readFileSync20, readdirSync as readdirSync12, statSync as statSync9 } from "fs";
|
|
10898
|
+
import { dirname as dirname5, resolve as resolve19, join as join19 } from "path";
|
|
10691
10899
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
10692
10900
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
10693
10901
|
try {
|
|
@@ -10701,6 +10909,18 @@ async function resolveOwnerProfileBlock(accountId, userId) {
|
|
|
10701
10909
|
return { ok: false, reason: "neo4j-unreachable" };
|
|
10702
10910
|
}
|
|
10703
10911
|
}
|
|
10912
|
+
async function resolveAuthenticatedName(accountId, userId) {
|
|
10913
|
+
if (!userId) return void 0;
|
|
10914
|
+
try {
|
|
10915
|
+
const res = await loadAdminUserName(accountId, userId);
|
|
10916
|
+
return res.source === "neo4j" ? res.joined : void 0;
|
|
10917
|
+
} catch (err) {
|
|
10918
|
+
console.error(
|
|
10919
|
+
`[spawn-context] resolveAuthenticatedName failed: ${err instanceof Error ? err.message : String(err)}`
|
|
10920
|
+
);
|
|
10921
|
+
return void 0;
|
|
10922
|
+
}
|
|
10923
|
+
}
|
|
10704
10924
|
function frontmatterField(manifest, field2) {
|
|
10705
10925
|
const fm = manifest.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
10706
10926
|
if (!fm) return null;
|
|
@@ -10716,8 +10936,8 @@ function frontmatterField(manifest, field2) {
|
|
|
10716
10936
|
function extractPluginToolDescriptions(pluginDir) {
|
|
10717
10937
|
const out = /* @__PURE__ */ new Map();
|
|
10718
10938
|
const candidates = [
|
|
10719
|
-
|
|
10720
|
-
|
|
10939
|
+
join19(pluginDir, "mcp/dist/index.js"),
|
|
10940
|
+
join19(pluginDir, "mcp/src/index.ts")
|
|
10721
10941
|
];
|
|
10722
10942
|
let raw = null;
|
|
10723
10943
|
for (const path2 of candidates) {
|
|
@@ -10772,26 +10992,26 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
10772
10992
|
}
|
|
10773
10993
|
function listPluginDirs() {
|
|
10774
10994
|
const out = /* @__PURE__ */ new Map();
|
|
10775
|
-
const platformPlugins =
|
|
10995
|
+
const platformPlugins = resolve19(PLATFORM_ROOT, "plugins");
|
|
10776
10996
|
if (existsSync19(platformPlugins)) {
|
|
10777
10997
|
for (const name of readdirSync12(platformPlugins)) {
|
|
10778
|
-
const dir =
|
|
10998
|
+
const dir = join19(platformPlugins, name);
|
|
10779
10999
|
try {
|
|
10780
|
-
if (
|
|
11000
|
+
if (statSync9(dir).isDirectory()) out.set(name, dir);
|
|
10781
11001
|
} catch {
|
|
10782
11002
|
}
|
|
10783
11003
|
}
|
|
10784
11004
|
}
|
|
10785
|
-
const premiumRoot =
|
|
11005
|
+
const premiumRoot = resolve19(dirname5(PLATFORM_ROOT), "premium-plugins");
|
|
10786
11006
|
if (existsSync19(premiumRoot)) {
|
|
10787
11007
|
for (const bundle of readdirSync12(premiumRoot)) {
|
|
10788
|
-
const bundlePlugins =
|
|
11008
|
+
const bundlePlugins = join19(premiumRoot, bundle, "plugins");
|
|
10789
11009
|
if (!existsSync19(bundlePlugins)) continue;
|
|
10790
11010
|
try {
|
|
10791
11011
|
for (const name of readdirSync12(bundlePlugins)) {
|
|
10792
|
-
const dir =
|
|
11012
|
+
const dir = join19(bundlePlugins, name);
|
|
10793
11013
|
try {
|
|
10794
|
-
if (
|
|
11014
|
+
if (statSync9(dir).isDirectory()) out.set(name, dir);
|
|
10795
11015
|
} catch {
|
|
10796
11016
|
}
|
|
10797
11017
|
}
|
|
@@ -10802,7 +11022,7 @@ function listPluginDirs() {
|
|
|
10802
11022
|
return out;
|
|
10803
11023
|
}
|
|
10804
11024
|
function readEnabledPlugins(accountId) {
|
|
10805
|
-
const accountFile =
|
|
11025
|
+
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10806
11026
|
if (!existsSync19(accountFile)) return /* @__PURE__ */ new Set();
|
|
10807
11027
|
try {
|
|
10808
11028
|
const parsed = JSON.parse(readFileSync20(accountFile, "utf-8"));
|
|
@@ -10832,7 +11052,7 @@ function computeActivePlugins(accountId) {
|
|
|
10832
11052
|
for (const name of Array.from(enabled).sort()) {
|
|
10833
11053
|
const dir = pluginDirs.get(name);
|
|
10834
11054
|
if (!dir) continue;
|
|
10835
|
-
const fm = readFrontmatter(
|
|
11055
|
+
const fm = readFrontmatter(join19(dir, "PLUGIN.md"));
|
|
10836
11056
|
if (!fm) continue;
|
|
10837
11057
|
const description = frontmatterField(`---
|
|
10838
11058
|
${fm}
|
|
@@ -10849,7 +11069,7 @@ ${fm}
|
|
|
10849
11069
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
10850
11070
|
);
|
|
10851
11071
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
10852
|
-
const hasSource = existsSync19(
|
|
11072
|
+
const hasSource = existsSync19(join19(dir, "mcp/dist/index.js")) || existsSync19(join19(dir, "mcp/src/index.ts"));
|
|
10853
11073
|
if (hasSource) {
|
|
10854
11074
|
console.warn(
|
|
10855
11075
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -10859,7 +11079,7 @@ ${fm}
|
|
|
10859
11079
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
10860
11080
|
const skills = [];
|
|
10861
11081
|
for (const relPath of skillPaths) {
|
|
10862
|
-
const skillPath =
|
|
11082
|
+
const skillPath = join19(dir, relPath);
|
|
10863
11083
|
const skillFm = readFrontmatter(skillPath);
|
|
10864
11084
|
if (!skillFm) continue;
|
|
10865
11085
|
const skillName = frontmatterField(`---
|
|
@@ -10875,7 +11095,7 @@ ${skillFm}
|
|
|
10875
11095
|
return out;
|
|
10876
11096
|
}
|
|
10877
11097
|
function computeSpecialistDomains(accountId) {
|
|
10878
|
-
const specialistsDir =
|
|
11098
|
+
const specialistsDir = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
10879
11099
|
if (!existsSync19(specialistsDir)) return [];
|
|
10880
11100
|
let entries;
|
|
10881
11101
|
try {
|
|
@@ -10888,10 +11108,10 @@ function computeSpecialistDomains(accountId) {
|
|
|
10888
11108
|
const resolveDesc = (qualified) => {
|
|
10889
11109
|
if (!qualified.startsWith("mcp__")) return void 0;
|
|
10890
11110
|
const rest = qualified.slice(5);
|
|
10891
|
-
const
|
|
10892
|
-
if (
|
|
10893
|
-
const plugin = rest.slice(0,
|
|
10894
|
-
const tool = rest.slice(
|
|
11111
|
+
const sep9 = rest.indexOf("__");
|
|
11112
|
+
if (sep9 < 0) return void 0;
|
|
11113
|
+
const plugin = rest.slice(0, sep9);
|
|
11114
|
+
const tool = rest.slice(sep9 + 2);
|
|
10895
11115
|
let map = descByPlugin.get(plugin);
|
|
10896
11116
|
if (!map) {
|
|
10897
11117
|
const dir = pluginDirs.get(plugin);
|
|
@@ -10903,7 +11123,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
10903
11123
|
const out = [];
|
|
10904
11124
|
for (const file of entries.sort()) {
|
|
10905
11125
|
if (!file.endsWith(".md")) continue;
|
|
10906
|
-
const fm = readFrontmatter(
|
|
11126
|
+
const fm = readFrontmatter(join19(specialistsDir, file));
|
|
10907
11127
|
if (!fm) continue;
|
|
10908
11128
|
const wrapped = `---
|
|
10909
11129
|
${fm}
|
|
@@ -10921,7 +11141,7 @@ ${fm}
|
|
|
10921
11141
|
return out;
|
|
10922
11142
|
}
|
|
10923
11143
|
function computeDormantPlugins(accountId) {
|
|
10924
|
-
const accountFile =
|
|
11144
|
+
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10925
11145
|
if (!existsSync19(accountFile)) return [];
|
|
10926
11146
|
let enabled;
|
|
10927
11147
|
try {
|
|
@@ -10936,7 +11156,7 @@ function computeDormantPlugins(accountId) {
|
|
|
10936
11156
|
);
|
|
10937
11157
|
return [];
|
|
10938
11158
|
}
|
|
10939
|
-
const pluginsDir =
|
|
11159
|
+
const pluginsDir = resolve19(PLATFORM_ROOT, "plugins");
|
|
10940
11160
|
if (!existsSync19(pluginsDir)) return [];
|
|
10941
11161
|
let entries;
|
|
10942
11162
|
try {
|
|
@@ -10947,7 +11167,7 @@ function computeDormantPlugins(accountId) {
|
|
|
10947
11167
|
const out = [];
|
|
10948
11168
|
for (const name of entries) {
|
|
10949
11169
|
if (enabled.has(name)) continue;
|
|
10950
|
-
const manifestPath =
|
|
11170
|
+
const manifestPath = resolve19(pluginsDir, name, "PLUGIN.md");
|
|
10951
11171
|
if (!existsSync19(manifestPath)) continue;
|
|
10952
11172
|
let manifest;
|
|
10953
11173
|
try {
|
|
@@ -10966,7 +11186,7 @@ function computeDormantPlugins(accountId) {
|
|
|
10966
11186
|
|
|
10967
11187
|
// server/routes/admin/claude-sessions.ts
|
|
10968
11188
|
import { existsSync as existsSync20, readFileSync as readFileSync21 } from "fs";
|
|
10969
|
-
import { resolve as
|
|
11189
|
+
import { resolve as resolve20 } from "path";
|
|
10970
11190
|
function readTunnelState(brandConfigDir) {
|
|
10971
11191
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
10972
11192
|
if (!existsSync20(statePath)) return null;
|
|
@@ -10982,10 +11202,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
10982
11202
|
}
|
|
10983
11203
|
}
|
|
10984
11204
|
function resolveTunnelUrl() {
|
|
10985
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ??
|
|
11205
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
10986
11206
|
let brand;
|
|
10987
11207
|
try {
|
|
10988
|
-
brand = JSON.parse(readFileSync21(
|
|
11208
|
+
brand = JSON.parse(readFileSync21(resolve20(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
10989
11209
|
} catch {
|
|
10990
11210
|
return null;
|
|
10991
11211
|
}
|
|
@@ -10996,7 +11216,7 @@ function resolveTunnelUrl() {
|
|
|
10996
11216
|
if (!state) return null;
|
|
10997
11217
|
return `https://${hostname2}.${state.domain}`;
|
|
10998
11218
|
}
|
|
10999
|
-
var
|
|
11219
|
+
var TAG24 = "[claude-session-manager:wrapper]";
|
|
11000
11220
|
async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
11001
11221
|
const auth = await ensureAuth();
|
|
11002
11222
|
if (auth.status !== "dead" && auth.status !== "missing") return null;
|
|
@@ -11008,18 +11228,18 @@ async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
|
11008
11228
|
503
|
|
11009
11229
|
);
|
|
11010
11230
|
}
|
|
11011
|
-
var
|
|
11231
|
+
var app16 = new Hono();
|
|
11012
11232
|
async function performSpawnWithInitialMessage(args) {
|
|
11013
11233
|
const ownerStart = Date.now();
|
|
11014
11234
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
11015
11235
|
const ownerMs = Date.now() - ownerStart;
|
|
11016
11236
|
const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
|
|
11017
|
-
console.log(`${
|
|
11237
|
+
console.log(`${TAG24} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
|
|
11018
11238
|
const dormantPlugins = computeDormantPlugins(args.senderId);
|
|
11019
11239
|
const activePlugins = computeActivePlugins(args.senderId);
|
|
11020
11240
|
const specialistDomains = computeSpecialistDomains(args.senderId);
|
|
11021
11241
|
const tunnelUrl = resolveTunnelUrl();
|
|
11022
|
-
console.log(`${
|
|
11242
|
+
console.log(`${TAG24} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
|
|
11023
11243
|
const upstreamPayload = JSON.stringify({
|
|
11024
11244
|
senderId: args.senderId,
|
|
11025
11245
|
// Task 205 — pass userId through to the manager so it lands as
|
|
@@ -11046,24 +11266,24 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
11046
11266
|
// unshapely values.
|
|
11047
11267
|
conversationNodeId: args.conversationNodeId
|
|
11048
11268
|
});
|
|
11049
|
-
console.log(`${
|
|
11269
|
+
console.log(`${TAG24} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
|
|
11050
11270
|
const forwardStart = Date.now();
|
|
11051
11271
|
const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
|
|
11052
11272
|
method: "POST",
|
|
11053
11273
|
headers: { "content-type": "application/json" },
|
|
11054
11274
|
body: upstreamPayload
|
|
11055
11275
|
}).catch((err) => {
|
|
11056
|
-
console.error(`${
|
|
11276
|
+
console.error(`${TAG24} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
|
|
11057
11277
|
return null;
|
|
11058
11278
|
});
|
|
11059
11279
|
if (!upstream) return {
|
|
11060
11280
|
response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
|
|
11061
11281
|
claudeSessionId: null
|
|
11062
11282
|
};
|
|
11063
|
-
console.log(`${
|
|
11283
|
+
console.log(`${TAG24} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
|
|
11064
11284
|
if (args.initialMessage) {
|
|
11065
11285
|
const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
|
|
11066
|
-
console.log(`${
|
|
11286
|
+
console.log(`${TAG24} initial-message-inlined bytes=${inputBytes}`);
|
|
11067
11287
|
}
|
|
11068
11288
|
const bodyText = await upstream.text().catch(() => "");
|
|
11069
11289
|
let claudeSessionId = null;
|
|
@@ -11085,8 +11305,8 @@ function mintTranscriptEdge(sessionId, claudeSessionId, accountId) {
|
|
|
11085
11305
|
if (!sessionId || !claudeSessionId) return;
|
|
11086
11306
|
void linkConversationTranscript(sessionId, claudeSessionId, accountId);
|
|
11087
11307
|
}
|
|
11088
|
-
|
|
11089
|
-
|
|
11308
|
+
app16.use("*", requireAdminSession);
|
|
11309
|
+
app16.post("/", async (c) => {
|
|
11090
11310
|
const routeStart = Date.now();
|
|
11091
11311
|
const cacheKey = c.get("cacheKey") ?? "";
|
|
11092
11312
|
let body = {};
|
|
@@ -11098,7 +11318,7 @@ app15.post("/", async (c) => {
|
|
|
11098
11318
|
if (refusal) return refusal;
|
|
11099
11319
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
11100
11320
|
if (!senderId) {
|
|
11101
|
-
console.error(`${
|
|
11321
|
+
console.error(`${TAG24} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
|
|
11102
11322
|
return c.json({ error: "admin-account-not-resolved" }, 500);
|
|
11103
11323
|
}
|
|
11104
11324
|
const userId = getUserIdForSession(cacheKey) ?? void 0;
|
|
@@ -11107,7 +11327,7 @@ app15.post("/", async (c) => {
|
|
|
11107
11327
|
const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
|
|
11108
11328
|
const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
|
|
11109
11329
|
const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
|
|
11110
|
-
console.log(`${
|
|
11330
|
+
console.log(`${TAG24} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
|
|
11111
11331
|
const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
|
|
11112
11332
|
const { response, claudeSessionId } = await performSpawnWithInitialMessage({
|
|
11113
11333
|
senderId,
|
|
@@ -11126,24 +11346,24 @@ app15.post("/", async (c) => {
|
|
|
11126
11346
|
claudeSessionId,
|
|
11127
11347
|
senderId
|
|
11128
11348
|
);
|
|
11129
|
-
console.log(`${
|
|
11349
|
+
console.log(`${TAG24} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
11130
11350
|
return response;
|
|
11131
11351
|
});
|
|
11132
|
-
var claude_sessions_default =
|
|
11352
|
+
var claude_sessions_default = app16;
|
|
11133
11353
|
|
|
11134
11354
|
// server/routes/admin/log-ingest.ts
|
|
11135
|
-
var
|
|
11355
|
+
var TAG25 = "[log-ingest]";
|
|
11136
11356
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
11137
11357
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
11138
11358
|
var MAX_LINE_BYTES = 4096;
|
|
11139
|
-
var
|
|
11359
|
+
var app17 = new Hono();
|
|
11140
11360
|
function isLoopbackAddr(addr) {
|
|
11141
11361
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
11142
11362
|
}
|
|
11143
|
-
|
|
11363
|
+
app17.post("/", async (c) => {
|
|
11144
11364
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
11145
11365
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
11146
|
-
console.error(`${
|
|
11366
|
+
console.error(`${TAG25} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
11147
11367
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
11148
11368
|
}
|
|
11149
11369
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -11152,7 +11372,7 @@ app16.post("/", async (c) => {
|
|
|
11152
11372
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
11153
11373
|
const offender = tokens.find((t) => !isLoopbackAddr(t));
|
|
11154
11374
|
if (offender !== void 0) {
|
|
11155
|
-
console.error(`${
|
|
11375
|
+
console.error(`${TAG25} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
11156
11376
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
11157
11377
|
}
|
|
11158
11378
|
}
|
|
@@ -11183,7 +11403,7 @@ app16.post("/", async (c) => {
|
|
|
11183
11403
|
else console.log(formatted);
|
|
11184
11404
|
return c.json({ ok: true }, 200);
|
|
11185
11405
|
});
|
|
11186
|
-
var log_ingest_default =
|
|
11406
|
+
var log_ingest_default = app17;
|
|
11187
11407
|
|
|
11188
11408
|
// server/routes/admin/events.ts
|
|
11189
11409
|
var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
@@ -11192,20 +11412,20 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
11192
11412
|
"device-url:vnc-surface-shown",
|
|
11193
11413
|
"device-url:malformed"
|
|
11194
11414
|
]);
|
|
11195
|
-
var
|
|
11196
|
-
|
|
11197
|
-
const
|
|
11415
|
+
var app18 = new Hono();
|
|
11416
|
+
app18.post("/", async (c) => {
|
|
11417
|
+
const TAG34 = "[admin:events]";
|
|
11198
11418
|
let body;
|
|
11199
11419
|
try {
|
|
11200
11420
|
body = await c.req.json();
|
|
11201
11421
|
} catch (err) {
|
|
11202
11422
|
const detail = err instanceof Error ? err.message : String(err);
|
|
11203
|
-
console.error(`${
|
|
11423
|
+
console.error(`${TAG34} reject reason=body-not-json detail=${detail}`);
|
|
11204
11424
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
11205
11425
|
}
|
|
11206
11426
|
const event = typeof body.event === "string" ? body.event : "";
|
|
11207
11427
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
11208
|
-
console.error(`${
|
|
11428
|
+
console.error(`${TAG34} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
11209
11429
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
11210
11430
|
}
|
|
11211
11431
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -11224,13 +11444,13 @@ app17.post("/", async (c) => {
|
|
|
11224
11444
|
console.error(`[${event}] ${formatted}`);
|
|
11225
11445
|
return c.json({ ok: true });
|
|
11226
11446
|
});
|
|
11227
|
-
var events_default =
|
|
11447
|
+
var events_default = app18;
|
|
11228
11448
|
|
|
11229
11449
|
// server/routes/admin/files.ts
|
|
11230
11450
|
import { createReadStream as createReadStream2 } from "fs";
|
|
11231
11451
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
11232
11452
|
import { realpathSync as realpathSync4 } from "fs";
|
|
11233
|
-
import { basename as
|
|
11453
|
+
import { basename as basename7, dirname as dirname6, join as join21, resolve as resolve22, sep as sep6 } from "path";
|
|
11234
11454
|
import { Readable as Readable2 } from "stream";
|
|
11235
11455
|
|
|
11236
11456
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -11548,7 +11768,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
11548
11768
|
|
|
11549
11769
|
// app/lib/file-index.ts
|
|
11550
11770
|
import * as fsp from "fs/promises";
|
|
11551
|
-
import { resolve as
|
|
11771
|
+
import { resolve as resolve21, relative as relative2, join as join20, basename as basename6, extname as extname2, sep as sep5 } from "path";
|
|
11552
11772
|
import { tmpdir as tmpdir2 } from "os";
|
|
11553
11773
|
import { execFile as execFile2 } from "child_process";
|
|
11554
11774
|
import { promisify as promisify2 } from "util";
|
|
@@ -11630,7 +11850,7 @@ async function extractPdf(absolute) {
|
|
|
11630
11850
|
return stdout.trim();
|
|
11631
11851
|
}
|
|
11632
11852
|
async function ocrPdf(absolute) {
|
|
11633
|
-
const outPdf =
|
|
11853
|
+
const outPdf = join20(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
11634
11854
|
try {
|
|
11635
11855
|
await execFileAsync2(
|
|
11636
11856
|
"ocrmypdf",
|
|
@@ -11686,13 +11906,13 @@ async function extractFileContent(absolute) {
|
|
|
11686
11906
|
}
|
|
11687
11907
|
}
|
|
11688
11908
|
async function readDisplayName(absolute) {
|
|
11689
|
-
const dir = absolute.slice(0, absolute.length -
|
|
11690
|
-
const base =
|
|
11909
|
+
const dir = absolute.slice(0, absolute.length - basename6(absolute).length);
|
|
11910
|
+
const base = basename6(absolute);
|
|
11691
11911
|
const dot = base.lastIndexOf(".");
|
|
11692
11912
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11693
11913
|
if (base === `${stem}.meta.json`) return null;
|
|
11694
11914
|
try {
|
|
11695
|
-
const raw = await fsp.readFile(
|
|
11915
|
+
const raw = await fsp.readFile(join20(dir, `${stem}.meta.json`), "utf-8");
|
|
11696
11916
|
const meta = JSON.parse(raw);
|
|
11697
11917
|
const dn = meta.displayName ?? meta.filename;
|
|
11698
11918
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -11712,7 +11932,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
11712
11932
|
let clean = true;
|
|
11713
11933
|
for (const entry of entries) {
|
|
11714
11934
|
if (entry.isSymbolicLink()) continue;
|
|
11715
|
-
const abs =
|
|
11935
|
+
const abs = join20(root, entry.name);
|
|
11716
11936
|
if (entry.isDirectory()) {
|
|
11717
11937
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
11718
11938
|
if (!sub.clean) clean = false;
|
|
@@ -11721,7 +11941,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
11721
11941
|
const st = await fsp.stat(abs);
|
|
11722
11942
|
out.push({
|
|
11723
11943
|
absolute: abs,
|
|
11724
|
-
relativePath: relative2(dataRoot, abs).split(
|
|
11944
|
+
relativePath: relative2(dataRoot, abs).split(sep5).join("/"),
|
|
11725
11945
|
sizeBytes: st.size,
|
|
11726
11946
|
modifiedAt: st.mtime.toISOString()
|
|
11727
11947
|
});
|
|
@@ -11824,7 +12044,7 @@ async function cascadeTrashLinkedKnowledgeDocs(session, accountId, relativePaths
|
|
|
11824
12044
|
return { kds, sections, chunks };
|
|
11825
12045
|
}
|
|
11826
12046
|
async function buildArtifact(accountId, wf, embed2) {
|
|
11827
|
-
const name =
|
|
12047
|
+
const name = basename6(wf.absolute);
|
|
11828
12048
|
const { content, route } = await extractFileContent(wf.absolute);
|
|
11829
12049
|
const displayName = await readDisplayName(wf.absolute);
|
|
11830
12050
|
const embedInput = `${name}
|
|
@@ -11867,7 +12087,7 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
11867
12087
|
return withSession(opts, async (session) => {
|
|
11868
12088
|
const walked = [];
|
|
11869
12089
|
const subtreeRoots = [
|
|
11870
|
-
|
|
12090
|
+
resolve21(dataRoot, "accounts", accountId)
|
|
11871
12091
|
];
|
|
11872
12092
|
let clean = true;
|
|
11873
12093
|
for (const root of subtreeRoots) {
|
|
@@ -11950,7 +12170,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
|
|
|
11950
12170
|
async function indexFile(accountId, relativePath, opts) {
|
|
11951
12171
|
const dataRoot = opts?.dataRoot ?? DATA_ROOT;
|
|
11952
12172
|
const embed2 = opts?.embed ?? embed;
|
|
11953
|
-
const absolute =
|
|
12173
|
+
const absolute = resolve21(dataRoot, relativePath);
|
|
11954
12174
|
await withSession(opts, async (session) => {
|
|
11955
12175
|
const st = await fsp.stat(absolute);
|
|
11956
12176
|
const wf = {
|
|
@@ -11984,7 +12204,7 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
11984
12204
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11985
12205
|
async function readMeta(absDir, baseName) {
|
|
11986
12206
|
try {
|
|
11987
|
-
const raw = await readFile4(
|
|
12207
|
+
const raw = await readFile4(join21(absDir, `${baseName}.meta.json`), "utf8");
|
|
11988
12208
|
const parsed = JSON.parse(raw);
|
|
11989
12209
|
if (typeof parsed?.filename === "string") {
|
|
11990
12210
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -11995,7 +12215,7 @@ async function readMeta(absDir, baseName) {
|
|
|
11995
12215
|
}
|
|
11996
12216
|
async function readAccountNames() {
|
|
11997
12217
|
const map = /* @__PURE__ */ new Map();
|
|
11998
|
-
const accountsDir =
|
|
12218
|
+
const accountsDir = resolve22(DATA_ROOT, "accounts");
|
|
11999
12219
|
let names;
|
|
12000
12220
|
try {
|
|
12001
12221
|
names = await readdir3(accountsDir);
|
|
@@ -12004,7 +12224,7 @@ async function readAccountNames() {
|
|
|
12004
12224
|
}
|
|
12005
12225
|
for (const name of names) {
|
|
12006
12226
|
if (!UUID_RE3.test(name)) continue;
|
|
12007
|
-
const configPath2 =
|
|
12227
|
+
const configPath2 = resolve22(accountsDir, name, "account.json");
|
|
12008
12228
|
try {
|
|
12009
12229
|
const raw = await readFile4(configPath2, "utf8");
|
|
12010
12230
|
const parsed = JSON.parse(raw);
|
|
@@ -12022,7 +12242,7 @@ async function readAccountNames() {
|
|
|
12022
12242
|
}
|
|
12023
12243
|
async function enrich(absolute, entry, accountNames) {
|
|
12024
12244
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
12025
|
-
const meta = await readMeta(
|
|
12245
|
+
const meta = await readMeta(join21(absolute, entry.name), entry.name);
|
|
12026
12246
|
if (meta?.filename) {
|
|
12027
12247
|
entry.displayName = meta.filename;
|
|
12028
12248
|
entry.mimeType = meta.mimeType;
|
|
@@ -12108,8 +12328,8 @@ async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
|
|
|
12108
12328
|
await session.close();
|
|
12109
12329
|
}
|
|
12110
12330
|
}
|
|
12111
|
-
var
|
|
12112
|
-
|
|
12331
|
+
var app19 = new Hono();
|
|
12332
|
+
app19.get("/", requireAdminSession, async (c) => {
|
|
12113
12333
|
const cacheKey = c.var.cacheKey;
|
|
12114
12334
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12115
12335
|
if (!accountId) {
|
|
@@ -12148,7 +12368,7 @@ app18.get("/", requireAdminSession, async (c) => {
|
|
|
12148
12368
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
12149
12369
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
12150
12370
|
try {
|
|
12151
|
-
const entryPath =
|
|
12371
|
+
const entryPath = join21(absolute, name);
|
|
12152
12372
|
const s = await stat4(entryPath);
|
|
12153
12373
|
entries.push({
|
|
12154
12374
|
name,
|
|
@@ -12178,7 +12398,7 @@ app18.get("/", requireAdminSession, async (c) => {
|
|
|
12178
12398
|
return c.json({ error: message }, 500);
|
|
12179
12399
|
}
|
|
12180
12400
|
});
|
|
12181
|
-
|
|
12401
|
+
app19.get("/download", requireAdminSession, async (c) => {
|
|
12182
12402
|
const cacheKey = c.var.cacheKey;
|
|
12183
12403
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12184
12404
|
if (!accountId) {
|
|
@@ -12215,7 +12435,7 @@ app18.get("/download", requireAdminSession, async (c) => {
|
|
|
12215
12435
|
if (!info.isFile()) {
|
|
12216
12436
|
return c.json({ error: "Path is not a file" }, 400);
|
|
12217
12437
|
}
|
|
12218
|
-
const filename =
|
|
12438
|
+
const filename = basename7(absolute);
|
|
12219
12439
|
const mimeType = detectMimeType(absolute);
|
|
12220
12440
|
const nodeStream = createReadStream2(absolute);
|
|
12221
12441
|
const webStream = Readable2.toWeb(nodeStream);
|
|
@@ -12242,7 +12462,7 @@ app18.get("/download", requireAdminSession, async (c) => {
|
|
|
12242
12462
|
return c.json({ error: message }, 500);
|
|
12243
12463
|
}
|
|
12244
12464
|
});
|
|
12245
|
-
|
|
12465
|
+
app19.post("/upload", requireAdminSession, async (c) => {
|
|
12246
12466
|
const cacheKey = c.var.cacheKey;
|
|
12247
12467
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12248
12468
|
if (!accountId) {
|
|
@@ -12272,15 +12492,15 @@ app18.post("/upload", requireAdminSession, async (c) => {
|
|
|
12272
12492
|
error: `Unsupported file type: "${file.type}". Supported: ${[...SUPPORTED_MIME_TYPES].join(", ")}.`
|
|
12273
12493
|
}, 422);
|
|
12274
12494
|
}
|
|
12275
|
-
const safeName =
|
|
12495
|
+
const safeName = basename7(file.name).replace(/[\0/\\]/g, "_");
|
|
12276
12496
|
const finalName = `${Date.now()}-${safeName}`;
|
|
12277
|
-
const destDir =
|
|
12278
|
-
const destPath =
|
|
12497
|
+
const destDir = resolve22(DATA_ROOT, "accounts", accountId, "uploads");
|
|
12498
|
+
const destPath = resolve22(destDir, finalName);
|
|
12279
12499
|
try {
|
|
12280
12500
|
await mkdir3(destDir, { recursive: true });
|
|
12281
12501
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
12282
12502
|
const destDirReal = realpathSync4(destDir);
|
|
12283
|
-
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal +
|
|
12503
|
+
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
|
|
12284
12504
|
console.error(`[data] path-traversal-blocked requested="accounts/${accountId}/uploads" resolved="${destDirReal}"`);
|
|
12285
12505
|
return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
|
|
12286
12506
|
}
|
|
@@ -12303,7 +12523,7 @@ app18.post("/upload", requireAdminSession, async (c) => {
|
|
|
12303
12523
|
mimeType: file.type
|
|
12304
12524
|
});
|
|
12305
12525
|
});
|
|
12306
|
-
|
|
12526
|
+
app19.delete("/", requireAdminSession, async (c) => {
|
|
12307
12527
|
const cacheKey = c.var.cacheKey;
|
|
12308
12528
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12309
12529
|
if (!accountId) {
|
|
@@ -12324,7 +12544,7 @@ app18.delete("/", requireAdminSession, async (c) => {
|
|
|
12324
12544
|
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
12325
12545
|
return c.json({ error: "Not found" }, 404);
|
|
12326
12546
|
}
|
|
12327
|
-
const base =
|
|
12547
|
+
const base = basename7(absolute);
|
|
12328
12548
|
const protection = isProtectedFromDeletion(relPath);
|
|
12329
12549
|
if (protection.protected) {
|
|
12330
12550
|
console.error(`[data] file-delete blocked path="${relPath}" reason="protected" rule="${protection.rule}"`);
|
|
@@ -12340,7 +12560,7 @@ app18.delete("/", requireAdminSession, async (c) => {
|
|
|
12340
12560
|
}
|
|
12341
12561
|
const dot = base.lastIndexOf(".");
|
|
12342
12562
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
12343
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
12563
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join21(dirname6(absolute), `${stem}.meta.json`) : null;
|
|
12344
12564
|
await unlink2(absolute);
|
|
12345
12565
|
if (sidecarPath) {
|
|
12346
12566
|
try {
|
|
@@ -12379,7 +12599,7 @@ app18.delete("/", requireAdminSession, async (c) => {
|
|
|
12379
12599
|
return c.json({ error: message }, 500);
|
|
12380
12600
|
}
|
|
12381
12601
|
});
|
|
12382
|
-
var files_default =
|
|
12602
|
+
var files_default = app19;
|
|
12383
12603
|
|
|
12384
12604
|
// ../lib/graph-search/src/index.ts
|
|
12385
12605
|
var import_dist = __toESM(require_dist());
|
|
@@ -13144,8 +13364,8 @@ var DEFAULT_LIMIT = 20;
|
|
|
13144
13364
|
var MAX_LIMIT = 2e3;
|
|
13145
13365
|
var MESSAGE_FAMILY_LABELS = ["Message", "UserMessage", "AssistantMessage", "WhatsAppMessage"];
|
|
13146
13366
|
var CONVERSATION_PARENT_LABELS = /* @__PURE__ */ new Set(["AdminConversation", "PublicConversation"]);
|
|
13147
|
-
var
|
|
13148
|
-
|
|
13367
|
+
var app20 = new Hono();
|
|
13368
|
+
app20.get("/", requireAdminSession, async (c) => {
|
|
13149
13369
|
const cacheKey = c.var.cacheKey;
|
|
13150
13370
|
const q = (c.req.query("q") ?? "").trim();
|
|
13151
13371
|
const rawLimit = c.req.query("limit");
|
|
@@ -13281,7 +13501,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
13281
13501
|
await session.close();
|
|
13282
13502
|
}
|
|
13283
13503
|
});
|
|
13284
|
-
var graph_search_default =
|
|
13504
|
+
var graph_search_default = app20;
|
|
13285
13505
|
|
|
13286
13506
|
// server/routes/admin/graph-subgraph.ts
|
|
13287
13507
|
import neo4j2 from "neo4j-driver";
|
|
@@ -13365,8 +13585,8 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
|
13365
13585
|
"otpCode",
|
|
13366
13586
|
"cacheKey"
|
|
13367
13587
|
]);
|
|
13368
|
-
var
|
|
13369
|
-
|
|
13588
|
+
var app21 = new Hono();
|
|
13589
|
+
app21.get("/", requireAdminSession, async (c) => {
|
|
13370
13590
|
const cacheKey = c.var.cacheKey;
|
|
13371
13591
|
const accountId = getAccountIdForSession(cacheKey);
|
|
13372
13592
|
if (!accountId) {
|
|
@@ -13949,12 +14169,12 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
|
|
|
13949
14169
|
}
|
|
13950
14170
|
return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
|
|
13951
14171
|
}
|
|
13952
|
-
var graph_subgraph_default =
|
|
14172
|
+
var graph_subgraph_default = app21;
|
|
13953
14173
|
|
|
13954
14174
|
// server/routes/admin/graph-delete.ts
|
|
13955
14175
|
var ALLOWED_BY = ["graph-page", "graph-drag-trash", "graph-side-panel-trash"];
|
|
13956
|
-
var
|
|
13957
|
-
|
|
14176
|
+
var app22 = new Hono();
|
|
14177
|
+
app22.post("/", requireAdminSession, async (c) => {
|
|
13958
14178
|
const cacheKey = c.var.cacheKey;
|
|
13959
14179
|
const accountId = getAccountIdForSession(cacheKey);
|
|
13960
14180
|
if (!accountId) {
|
|
@@ -14116,11 +14336,11 @@ app21.post("/", requireAdminSession, async (c) => {
|
|
|
14116
14336
|
}
|
|
14117
14337
|
}
|
|
14118
14338
|
});
|
|
14119
|
-
var graph_delete_default =
|
|
14339
|
+
var graph_delete_default = app22;
|
|
14120
14340
|
|
|
14121
14341
|
// server/routes/admin/graph-restore.ts
|
|
14122
|
-
var
|
|
14123
|
-
|
|
14342
|
+
var app23 = new Hono();
|
|
14343
|
+
app23.post("/", requireAdminSession, async (c) => {
|
|
14124
14344
|
const cacheKey = c.var.cacheKey;
|
|
14125
14345
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14126
14346
|
if (!accountId) {
|
|
@@ -14184,11 +14404,11 @@ app22.post("/", requireAdminSession, async (c) => {
|
|
|
14184
14404
|
}
|
|
14185
14405
|
}
|
|
14186
14406
|
});
|
|
14187
|
-
var graph_restore_default =
|
|
14407
|
+
var graph_restore_default = app23;
|
|
14188
14408
|
|
|
14189
14409
|
// server/routes/admin/graph-labels-in-graph.ts
|
|
14190
|
-
var
|
|
14191
|
-
|
|
14410
|
+
var app24 = new Hono();
|
|
14411
|
+
app24.get("/", requireAdminSession, async (c) => {
|
|
14192
14412
|
const cacheKey = c.var.cacheKey;
|
|
14193
14413
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14194
14414
|
if (!accountId) {
|
|
@@ -14254,11 +14474,11 @@ var LABELS_IN_GRAPH_CYPHER = `
|
|
|
14254
14474
|
sum(halfEdges) AS relDegree
|
|
14255
14475
|
RETURN label, nodeCount, relDegree
|
|
14256
14476
|
`;
|
|
14257
|
-
var graph_labels_in_graph_default =
|
|
14477
|
+
var graph_labels_in_graph_default = app24;
|
|
14258
14478
|
|
|
14259
14479
|
// server/routes/admin/graph-default-view.ts
|
|
14260
|
-
var
|
|
14261
|
-
|
|
14480
|
+
var app25 = new Hono();
|
|
14481
|
+
app25.get("/", requireAdminSession, async (c) => {
|
|
14262
14482
|
const cacheKey = c.var.cacheKey;
|
|
14263
14483
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14264
14484
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -14296,7 +14516,7 @@ app24.get("/", requireAdminSession, async (c) => {
|
|
|
14296
14516
|
}
|
|
14297
14517
|
}
|
|
14298
14518
|
});
|
|
14299
|
-
|
|
14519
|
+
app25.put("/", requireAdminSession, async (c) => {
|
|
14300
14520
|
const cacheKey = c.var.cacheKey;
|
|
14301
14521
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14302
14522
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -14385,20 +14605,20 @@ var WRITE_CYPHER = `
|
|
|
14385
14605
|
p.updatedAt = $updatedAt
|
|
14386
14606
|
RETURN p.labels AS labels
|
|
14387
14607
|
`;
|
|
14388
|
-
var graph_default_view_default =
|
|
14608
|
+
var graph_default_view_default = app25;
|
|
14389
14609
|
|
|
14390
14610
|
// server/routes/admin/sidebar-artefacts.ts
|
|
14391
14611
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
14392
|
-
import { resolve as
|
|
14612
|
+
import { resolve as resolve23, relative as relative3, isAbsolute, sep as sep7, basename as basename8 } from "path";
|
|
14393
14613
|
import { existsSync as existsSync21 } from "fs";
|
|
14394
14614
|
var LIMIT = 50;
|
|
14395
14615
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
14396
14616
|
function toDataRootRelPath(absPath) {
|
|
14397
|
-
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT +
|
|
14617
|
+
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep7)) return null;
|
|
14398
14618
|
return relative3(DATA_ROOT, absPath);
|
|
14399
14619
|
}
|
|
14400
|
-
var
|
|
14401
|
-
|
|
14620
|
+
var app26 = new Hono();
|
|
14621
|
+
app26.get("/", requireAdminSession, async (c) => {
|
|
14402
14622
|
const cacheKey = c.var.cacheKey;
|
|
14403
14623
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14404
14624
|
if (!accountId) {
|
|
@@ -14409,7 +14629,7 @@ app25.get("/", requireAdminSession, async (c) => {
|
|
|
14409
14629
|
if (accountFiles === null) {
|
|
14410
14630
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
14411
14631
|
}
|
|
14412
|
-
const accountDir =
|
|
14632
|
+
const accountDir = resolve23(ACCOUNTS_DIR, accountId);
|
|
14413
14633
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
14414
14634
|
const artefacts = [...accountFiles, ...agents].sort(
|
|
14415
14635
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -14442,7 +14662,7 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
14442
14662
|
const modifiedAt = r.get("modifiedAt") ?? "";
|
|
14443
14663
|
return {
|
|
14444
14664
|
id: `account-file:${relativePath}`,
|
|
14445
|
-
name: displayName ??
|
|
14665
|
+
name: displayName ?? basename8(relativePath),
|
|
14446
14666
|
kind: "account-file",
|
|
14447
14667
|
updatedAt: modifiedAt,
|
|
14448
14668
|
mimeType,
|
|
@@ -14461,8 +14681,8 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
14461
14681
|
async function fetchAgentTemplateRows(accountDir) {
|
|
14462
14682
|
const rows = [];
|
|
14463
14683
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
14464
|
-
const overridePath =
|
|
14465
|
-
const bundledPath =
|
|
14684
|
+
const overridePath = resolve23(accountDir, "agents", "admin", filename);
|
|
14685
|
+
const bundledPath = resolve23(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
14466
14686
|
const labelStem = filename.replace(/\.md$/, "");
|
|
14467
14687
|
const row = await readAgentTemplateRow({
|
|
14468
14688
|
id: `agent-template:admin:${filename}`,
|
|
@@ -14475,12 +14695,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
14475
14695
|
});
|
|
14476
14696
|
if (row) rows.push(row);
|
|
14477
14697
|
}
|
|
14478
|
-
const overrideDir =
|
|
14479
|
-
const bundledDir =
|
|
14698
|
+
const overrideDir = resolve23(accountDir, "specialists", "agents");
|
|
14699
|
+
const bundledDir = resolve23(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
14480
14700
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
14481
14701
|
for (const filename of specialistNames) {
|
|
14482
|
-
const overridePath =
|
|
14483
|
-
const bundledPath =
|
|
14702
|
+
const overridePath = resolve23(overrideDir, filename);
|
|
14703
|
+
const bundledPath = resolve23(bundledDir, filename);
|
|
14484
14704
|
const row = await readAgentTemplateRow({
|
|
14485
14705
|
id: `agent-template:specialist:${filename}`,
|
|
14486
14706
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -14562,11 +14782,11 @@ function isWithin(target, root) {
|
|
|
14562
14782
|
const rel = relative3(root, target);
|
|
14563
14783
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
14564
14784
|
}
|
|
14565
|
-
var sidebar_artefacts_default =
|
|
14785
|
+
var sidebar_artefacts_default = app26;
|
|
14566
14786
|
|
|
14567
14787
|
// server/routes/admin/session-delete.ts
|
|
14568
|
-
var
|
|
14569
|
-
|
|
14788
|
+
var app27 = new Hono();
|
|
14789
|
+
app27.post("/", requireAdminSession, async (c) => {
|
|
14570
14790
|
let body;
|
|
14571
14791
|
try {
|
|
14572
14792
|
body = await c.req.json();
|
|
@@ -14604,11 +14824,11 @@ app26.post("/", requireAdminSession, async (c) => {
|
|
|
14604
14824
|
console.error(`[session-delete] sessionId=${sessionId} delete-status=${del.status}`);
|
|
14605
14825
|
return c.json({ error: `manager-status-${del.status}` }, 502);
|
|
14606
14826
|
});
|
|
14607
|
-
var session_delete_default =
|
|
14827
|
+
var session_delete_default = app27;
|
|
14608
14828
|
|
|
14609
14829
|
// server/routes/admin/session-stop.ts
|
|
14610
|
-
var
|
|
14611
|
-
|
|
14830
|
+
var app28 = new Hono();
|
|
14831
|
+
app28.post("/", requireAdminSession, async (c) => {
|
|
14612
14832
|
let body;
|
|
14613
14833
|
try {
|
|
14614
14834
|
body = await c.req.json();
|
|
@@ -14633,11 +14853,11 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
14633
14853
|
console.error(`[session-stop] sessionId=${sessionId} manager-status=${res.status}`);
|
|
14634
14854
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
14635
14855
|
});
|
|
14636
|
-
var session_stop_default =
|
|
14856
|
+
var session_stop_default = app28;
|
|
14637
14857
|
|
|
14638
14858
|
// server/routes/admin/session-archive.ts
|
|
14639
|
-
var
|
|
14640
|
-
|
|
14859
|
+
var app29 = new Hono();
|
|
14860
|
+
app29.post("/", requireAdminSession, async (c) => {
|
|
14641
14861
|
let body;
|
|
14642
14862
|
try {
|
|
14643
14863
|
body = await c.req.json();
|
|
@@ -14685,11 +14905,11 @@ app28.post("/", requireAdminSession, async (c) => {
|
|
|
14685
14905
|
console.error(`[session-archive] sessionId=${sessionId.slice(0, 8)} manager-status=${res.status}`);
|
|
14686
14906
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
14687
14907
|
});
|
|
14688
|
-
var session_archive_default =
|
|
14908
|
+
var session_archive_default = app29;
|
|
14689
14909
|
|
|
14690
14910
|
// server/routes/admin/session-rc-spawn.ts
|
|
14691
14911
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
14692
|
-
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, adminUserId) {
|
|
14912
|
+
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, adminUserId, authenticatedName) {
|
|
14693
14913
|
const operator = isOperatorHost(host, operatorDomains);
|
|
14694
14914
|
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
14695
14915
|
const name = typeof body.name === "string" && body.name.length > 0 ? body.name : void 0;
|
|
@@ -14708,6 +14928,7 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, ad
|
|
|
14708
14928
|
payload.webchatChannel = webchatChannelDescriptor(key);
|
|
14709
14929
|
if (name) payload.name = name;
|
|
14710
14930
|
if (adminUserId) payload.adminUserId = adminUserId;
|
|
14931
|
+
if (authenticatedName) payload.authenticatedName = authenticatedName;
|
|
14711
14932
|
} else {
|
|
14712
14933
|
sessionId = resumeId;
|
|
14713
14934
|
payload.sessionId = resumeId;
|
|
@@ -14719,8 +14940,8 @@ function shapeWebchatResponse(sessionId, manager) {
|
|
|
14719
14940
|
const outcome = typeof manager?.outcome === "string" ? manager.outcome : "bound";
|
|
14720
14941
|
return { sessionId, outcome, target: `/chat?session=${sessionId}` };
|
|
14721
14942
|
}
|
|
14722
|
-
var
|
|
14723
|
-
|
|
14943
|
+
var app30 = new Hono();
|
|
14944
|
+
app30.post("/", requireAdminSession, async (c) => {
|
|
14724
14945
|
let body;
|
|
14725
14946
|
try {
|
|
14726
14947
|
body = await c.req.json();
|
|
@@ -14730,7 +14951,9 @@ app29.post("/", requireAdminSession, async (c) => {
|
|
|
14730
14951
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14731
14952
|
const cacheKey = c.get("cacheKey");
|
|
14732
14953
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
14733
|
-
const
|
|
14954
|
+
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
14955
|
+
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
14956
|
+
const plan = resolveSpawnPlan(host, getOperatorDomains(), body, randomUUID10, adminUserId, authenticatedName);
|
|
14734
14957
|
const spawnReqId = randomUUID10();
|
|
14735
14958
|
console.log(
|
|
14736
14959
|
`[chat-spawn] op=request spawnReqId=${spawnReqId} origin=${plan.origin} kind=${plan.kind} sessionId=${plan.kind === "new" ? "new" : plan.sessionId}`
|
|
@@ -14773,7 +14996,7 @@ app29.post("/", requireAdminSession, async (c) => {
|
|
|
14773
14996
|
}
|
|
14774
14997
|
return c.json(parsed ?? {});
|
|
14775
14998
|
});
|
|
14776
|
-
var session_rc_spawn_default =
|
|
14999
|
+
var session_rc_spawn_default = app30;
|
|
14777
15000
|
|
|
14778
15001
|
// server/routes/admin/session-reseat.ts
|
|
14779
15002
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
@@ -14798,7 +15021,7 @@ function isSelectableModel(id) {
|
|
|
14798
15021
|
}
|
|
14799
15022
|
|
|
14800
15023
|
// server/routes/admin/session-reseat.ts
|
|
14801
|
-
function resolveReseatPlan(body, mintId = randomUUID11, adminUserId) {
|
|
15024
|
+
function resolveReseatPlan(body, mintId = randomUUID11, adminUserId, authenticatedName) {
|
|
14802
15025
|
const sessionId = mintId();
|
|
14803
15026
|
const key = `session:${sessionId}`;
|
|
14804
15027
|
const payload = {
|
|
@@ -14812,10 +15035,12 @@ function resolveReseatPlan(body, mintId = randomUUID11, adminUserId) {
|
|
|
14812
15035
|
};
|
|
14813
15036
|
if (body.name) payload.name = body.name;
|
|
14814
15037
|
if (adminUserId) payload.adminUserId = adminUserId;
|
|
15038
|
+
if (authenticatedName) payload.authenticatedName = authenticatedName;
|
|
14815
15039
|
return { sessionId, payload };
|
|
14816
15040
|
}
|
|
14817
|
-
var
|
|
14818
|
-
|
|
15041
|
+
var app31 = new Hono();
|
|
15042
|
+
var reseatsInFlight = /* @__PURE__ */ new Set();
|
|
15043
|
+
app31.post("/", requireAdminSession, async (c) => {
|
|
14819
15044
|
let body;
|
|
14820
15045
|
try {
|
|
14821
15046
|
body = await c.req.json();
|
|
@@ -14826,57 +15051,67 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
14826
15051
|
const model = typeof body.model === "string" && isSelectableModel(body.model) ? body.model : null;
|
|
14827
15052
|
if (fromSessionId === null) return c.json({ error: "fromSessionId must be a valid session id" }, 400);
|
|
14828
15053
|
if (model === null) return c.json({ error: "model must be a selectable model" }, 400);
|
|
14829
|
-
|
|
14830
|
-
|
|
14831
|
-
|
|
14832
|
-
|
|
14833
|
-
|
|
14834
|
-
|
|
14835
|
-
|
|
14836
|
-
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
|
|
14840
|
-
});
|
|
14841
|
-
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
|
|
14847
|
-
|
|
14848
|
-
|
|
14849
|
-
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14858
|
-
|
|
14859
|
-
|
|
14860
|
-
if (
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14865
|
-
|
|
14866
|
-
|
|
15054
|
+
if (reseatsInFlight.has(fromSessionId)) {
|
|
15055
|
+
return c.json({ error: "re-seat already in progress for this session" }, 409);
|
|
15056
|
+
}
|
|
15057
|
+
reseatsInFlight.add(fromSessionId);
|
|
15058
|
+
try {
|
|
15059
|
+
const cacheKey = c.get("cacheKey");
|
|
15060
|
+
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
15061
|
+
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
15062
|
+
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
15063
|
+
const plan = resolveReseatPlan({ fromSessionId, model }, randomUUID11, adminUserId, authenticatedName);
|
|
15064
|
+
const reseatReqId = randomUUID11();
|
|
15065
|
+
console.log(`[chat-reseat] op=request reseatReqId=${reseatReqId} from=${fromSessionId} to-model=${model} new=${plan.sessionId}`);
|
|
15066
|
+
let res;
|
|
15067
|
+
try {
|
|
15068
|
+
res = await fetch(`${managerBase("session-reseat:wrapper")}/rc-spawn`, {
|
|
15069
|
+
method: "POST",
|
|
15070
|
+
headers: { "content-type": "application/json" },
|
|
15071
|
+
body: JSON.stringify(plan.payload)
|
|
15072
|
+
});
|
|
15073
|
+
} catch (err) {
|
|
15074
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
15075
|
+
console.error(`[session-reseat] manager-unreachable err=${msg}`);
|
|
15076
|
+
console.log(`[chat-reseat] op=exit reseatReqId=${reseatReqId} outcome=reseat-failed`);
|
|
15077
|
+
return c.json({ error: `session manager unreachable: ${msg}` }, 502);
|
|
15078
|
+
}
|
|
15079
|
+
const text = await res.text();
|
|
15080
|
+
let parsed = null;
|
|
15081
|
+
try {
|
|
15082
|
+
parsed = JSON.parse(text);
|
|
15083
|
+
} catch {
|
|
15084
|
+
}
|
|
15085
|
+
if (!res.ok) {
|
|
15086
|
+
console.error(`[session-reseat] manager-error status=${res.status} body=${text.slice(0, 200)}`);
|
|
15087
|
+
console.log(`[chat-reseat] op=exit reseatReqId=${reseatReqId} outcome=reseat-failed`);
|
|
15088
|
+
return c.json(parsed ?? { error: text }, res.status);
|
|
15089
|
+
}
|
|
15090
|
+
try {
|
|
15091
|
+
const account = resolveAccount();
|
|
15092
|
+
if (account) {
|
|
15093
|
+
const accountId2 = resolvePlatformAccountId();
|
|
15094
|
+
const canonicalId = adminSessionIdFor(accountId2, WEBCHAT_ADMIN_KEY);
|
|
15095
|
+
const currentOverride = readCanonicalOverrideId(account.accountDir);
|
|
15096
|
+
if (fromSessionId === canonicalId || fromSessionId === currentOverride) {
|
|
15097
|
+
writeCanonicalOverrideId(account.accountDir, plan.sessionId);
|
|
15098
|
+
console.log(`[chat-reseat] op=canonical-forward reseatReqId=${reseatReqId} from=${fromSessionId} to=${plan.sessionId}`);
|
|
15099
|
+
}
|
|
14867
15100
|
}
|
|
15101
|
+
} catch (err) {
|
|
15102
|
+
console.error(`[session-reseat] canonical-forward-failed err=${err instanceof Error ? err.message : String(err)}`);
|
|
14868
15103
|
}
|
|
14869
|
-
|
|
14870
|
-
console.
|
|
14871
|
-
|
|
14872
|
-
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
15104
|
+
const target = `/chat?session=${plan.sessionId}`;
|
|
15105
|
+
console.log(`[chat-reseat] op=acquired reseatReqId=${reseatReqId} pid=${parsed?.spawnedPid ?? "none"} new=${plan.sessionId}`);
|
|
15106
|
+
console.log(`[chat-reseat] op=navigate reseatReqId=${reseatReqId} target=${target}`);
|
|
15107
|
+
console.log(`[chat-reseat] op=exit reseatReqId=${reseatReqId} outcome=bound`);
|
|
15108
|
+
const outcome = typeof parsed?.outcome === "string" ? parsed.outcome : "bound";
|
|
15109
|
+
return c.json({ sessionId: plan.sessionId, outcome, target });
|
|
15110
|
+
} finally {
|
|
15111
|
+
reseatsInFlight.delete(fromSessionId);
|
|
15112
|
+
}
|
|
14878
15113
|
});
|
|
14879
|
-
var session_reseat_default =
|
|
15114
|
+
var session_reseat_default = app31;
|
|
14880
15115
|
|
|
14881
15116
|
// server/routes/admin/system-stats.ts
|
|
14882
15117
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -14973,8 +15208,8 @@ async function sample() {
|
|
|
14973
15208
|
if (process.platform === "linux") return sampleLinux();
|
|
14974
15209
|
return sampleOsFallback();
|
|
14975
15210
|
}
|
|
14976
|
-
var
|
|
14977
|
-
|
|
15211
|
+
var app32 = new Hono();
|
|
15212
|
+
app32.get("/", async (c) => {
|
|
14978
15213
|
const started = Date.now();
|
|
14979
15214
|
if (!inflight) {
|
|
14980
15215
|
inflight = sample().finally(() => {
|
|
@@ -14997,14 +15232,14 @@ app31.get("/", async (c) => {
|
|
|
14997
15232
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
14998
15233
|
}
|
|
14999
15234
|
});
|
|
15000
|
-
var system_stats_default =
|
|
15235
|
+
var system_stats_default = app32;
|
|
15001
15236
|
|
|
15002
15237
|
// server/routes/admin/health.ts
|
|
15003
15238
|
import { existsSync as existsSync22, readFileSync as readFileSync22 } from "fs";
|
|
15004
|
-
import { resolve as
|
|
15005
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
15239
|
+
import { resolve as resolve24, join as join22 } from "path";
|
|
15240
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
|
|
15006
15241
|
var brandHostname = "maxy";
|
|
15007
|
-
var brandJsonPath =
|
|
15242
|
+
var brandJsonPath = join22(PLATFORM_ROOT6, "config", "brand.json");
|
|
15008
15243
|
if (existsSync22(brandJsonPath)) {
|
|
15009
15244
|
try {
|
|
15010
15245
|
const brand = JSON.parse(readFileSync22(brandJsonPath, "utf-8"));
|
|
@@ -15012,7 +15247,7 @@ if (existsSync22(brandJsonPath)) {
|
|
|
15012
15247
|
} catch {
|
|
15013
15248
|
}
|
|
15014
15249
|
}
|
|
15015
|
-
var VERSION_FILE =
|
|
15250
|
+
var VERSION_FILE = resolve24(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
15016
15251
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
15017
15252
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
15018
15253
|
function readVersion() {
|
|
@@ -15042,8 +15277,8 @@ async function probeConversationDb() {
|
|
|
15042
15277
|
});
|
|
15043
15278
|
}
|
|
15044
15279
|
}
|
|
15045
|
-
var
|
|
15046
|
-
|
|
15280
|
+
var app33 = new Hono();
|
|
15281
|
+
app33.get("/", async (c) => {
|
|
15047
15282
|
const version = readVersion();
|
|
15048
15283
|
const probe = await probeConversationDb();
|
|
15049
15284
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -15065,11 +15300,11 @@ app32.get("/", async (c) => {
|
|
|
15065
15300
|
uptimeMs
|
|
15066
15301
|
});
|
|
15067
15302
|
});
|
|
15068
|
-
var health_default2 =
|
|
15303
|
+
var health_default2 = app33;
|
|
15069
15304
|
|
|
15070
15305
|
// server/routes/admin/linkedin-ingest.ts
|
|
15071
15306
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
15072
|
-
var
|
|
15307
|
+
var TAG26 = "[linkedin-ingest-route]";
|
|
15073
15308
|
var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
15074
15309
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
15075
15310
|
var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
|
|
@@ -15167,35 +15402,35 @@ function buildInitialMessage(env) {
|
|
|
15167
15402
|
}
|
|
15168
15403
|
return header;
|
|
15169
15404
|
}
|
|
15170
|
-
var
|
|
15171
|
-
|
|
15405
|
+
var app34 = new Hono();
|
|
15406
|
+
app34.post("/", requireAdminSession, async (c) => {
|
|
15172
15407
|
let body;
|
|
15173
15408
|
try {
|
|
15174
15409
|
body = await c.req.json();
|
|
15175
15410
|
} catch {
|
|
15176
|
-
console.error(
|
|
15411
|
+
console.error(TAG26 + " rejected status=400 reason=schema:body-not-json");
|
|
15177
15412
|
return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
|
|
15178
15413
|
}
|
|
15179
15414
|
const v = validate(body);
|
|
15180
15415
|
if (!v.ok) {
|
|
15181
|
-
console.error(
|
|
15416
|
+
console.error(TAG26 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
|
|
15182
15417
|
return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
|
|
15183
15418
|
}
|
|
15184
15419
|
const envelope = v.envelope;
|
|
15185
15420
|
const cacheKey = c.var.cacheKey ?? "";
|
|
15186
15421
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
15187
15422
|
if (!senderId) {
|
|
15188
|
-
console.error(
|
|
15423
|
+
console.error(TAG26 + " rejected status=500 reason=admin-account-not-resolved");
|
|
15189
15424
|
return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
|
|
15190
15425
|
}
|
|
15191
15426
|
const payloadBytes = JSON.stringify(envelope).length;
|
|
15192
15427
|
console.log(
|
|
15193
|
-
|
|
15428
|
+
TAG26 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
|
|
15194
15429
|
);
|
|
15195
15430
|
const initialMessage = buildInitialMessage(envelope);
|
|
15196
15431
|
const spawnStart = Date.now();
|
|
15197
15432
|
const sessionId = randomUUID12();
|
|
15198
|
-
console.log(
|
|
15433
|
+
console.log(TAG26 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
15199
15434
|
const spawned = await managerRcSpawn({
|
|
15200
15435
|
sessionId,
|
|
15201
15436
|
initialMessage,
|
|
@@ -15204,20 +15439,20 @@ app33.post("/", requireAdminSession, async (c) => {
|
|
|
15204
15439
|
});
|
|
15205
15440
|
if ("error" in spawned) {
|
|
15206
15441
|
console.error(
|
|
15207
|
-
|
|
15442
|
+
TAG26 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
|
|
15208
15443
|
);
|
|
15209
15444
|
return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
|
|
15210
15445
|
}
|
|
15211
15446
|
console.log(
|
|
15212
|
-
|
|
15447
|
+
TAG26 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
|
|
15213
15448
|
);
|
|
15214
15449
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
15215
15450
|
});
|
|
15216
|
-
var linkedin_ingest_default =
|
|
15451
|
+
var linkedin_ingest_default = app34;
|
|
15217
15452
|
|
|
15218
15453
|
// server/routes/admin/post-turn-context.ts
|
|
15219
15454
|
import neo4j3 from "neo4j-driver";
|
|
15220
|
-
var
|
|
15455
|
+
var TAG27 = "[post-turn-context]";
|
|
15221
15456
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
15222
15457
|
"embedding",
|
|
15223
15458
|
"passwordHash",
|
|
@@ -15255,11 +15490,11 @@ function pruneProperties(raw) {
|
|
|
15255
15490
|
}
|
|
15256
15491
|
return out;
|
|
15257
15492
|
}
|
|
15258
|
-
var
|
|
15259
|
-
|
|
15493
|
+
var app35 = new Hono();
|
|
15494
|
+
app35.get("/", async (c) => {
|
|
15260
15495
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15261
15496
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
15262
|
-
console.error(`${
|
|
15497
|
+
console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15263
15498
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
15264
15499
|
}
|
|
15265
15500
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15268,7 +15503,7 @@ app34.get("/", async (c) => {
|
|
|
15268
15503
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15269
15504
|
const offender = tokens.find((t) => !isLoopbackAddr2(t));
|
|
15270
15505
|
if (offender !== void 0) {
|
|
15271
|
-
console.error(`${
|
|
15506
|
+
console.error(`${TAG27} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15272
15507
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
15273
15508
|
}
|
|
15274
15509
|
}
|
|
@@ -15300,7 +15535,7 @@ app34.get("/", async (c) => {
|
|
|
15300
15535
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
15301
15536
|
const total = Date.now() - started;
|
|
15302
15537
|
console.log(
|
|
15303
|
-
`${
|
|
15538
|
+
`${TAG27} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
|
|
15304
15539
|
);
|
|
15305
15540
|
return c.json({
|
|
15306
15541
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -15309,18 +15544,18 @@ app34.get("/", async (c) => {
|
|
|
15309
15544
|
const elapsed = Date.now() - started;
|
|
15310
15545
|
const message = err instanceof Error ? err.message : String(err);
|
|
15311
15546
|
console.error(
|
|
15312
|
-
`${
|
|
15547
|
+
`${TAG27} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
|
|
15313
15548
|
);
|
|
15314
15549
|
return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
|
|
15315
15550
|
} finally {
|
|
15316
15551
|
await session.close();
|
|
15317
15552
|
}
|
|
15318
15553
|
});
|
|
15319
|
-
var post_turn_context_default =
|
|
15554
|
+
var post_turn_context_default = app35;
|
|
15320
15555
|
|
|
15321
15556
|
// server/routes/admin/public-session-context.ts
|
|
15322
15557
|
import neo4j4 from "neo4j-driver";
|
|
15323
|
-
var
|
|
15558
|
+
var TAG28 = "[public-session-context]";
|
|
15324
15559
|
var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
|
|
15325
15560
|
"embedding",
|
|
15326
15561
|
"passwordHash",
|
|
@@ -15358,11 +15593,11 @@ function pruneProperties2(raw) {
|
|
|
15358
15593
|
}
|
|
15359
15594
|
return out;
|
|
15360
15595
|
}
|
|
15361
|
-
var
|
|
15362
|
-
|
|
15596
|
+
var app36 = new Hono();
|
|
15597
|
+
app36.get("/", async (c) => {
|
|
15363
15598
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15364
15599
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
15365
|
-
console.error(`${
|
|
15600
|
+
console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15366
15601
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
15367
15602
|
}
|
|
15368
15603
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15371,7 +15606,7 @@ app35.get("/", async (c) => {
|
|
|
15371
15606
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15372
15607
|
const offender = tokens.find((t) => !isLoopbackAddr3(t));
|
|
15373
15608
|
if (offender !== void 0) {
|
|
15374
|
-
console.error(`${
|
|
15609
|
+
console.error(`${TAG28} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15375
15610
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
15376
15611
|
}
|
|
15377
15612
|
}
|
|
@@ -15402,7 +15637,7 @@ app35.get("/", async (c) => {
|
|
|
15402
15637
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
15403
15638
|
const total = Date.now() - started;
|
|
15404
15639
|
console.log(
|
|
15405
|
-
`${
|
|
15640
|
+
`${TAG28} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
15406
15641
|
);
|
|
15407
15642
|
return c.json({
|
|
15408
15643
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -15411,25 +15646,25 @@ app35.get("/", async (c) => {
|
|
|
15411
15646
|
const elapsed = Date.now() - started;
|
|
15412
15647
|
const message = err instanceof Error ? err.message : String(err);
|
|
15413
15648
|
console.error(
|
|
15414
|
-
`${
|
|
15649
|
+
`${TAG28} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
|
|
15415
15650
|
);
|
|
15416
15651
|
return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
|
|
15417
15652
|
} finally {
|
|
15418
15653
|
await session.close();
|
|
15419
15654
|
}
|
|
15420
15655
|
});
|
|
15421
|
-
var public_session_context_default =
|
|
15656
|
+
var public_session_context_default = app36;
|
|
15422
15657
|
|
|
15423
15658
|
// server/routes/admin/public-session-exit.ts
|
|
15424
|
-
var
|
|
15659
|
+
var TAG29 = "[public-session-exit-route]";
|
|
15425
15660
|
function isLoopbackAddr4(addr) {
|
|
15426
15661
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15427
15662
|
}
|
|
15428
|
-
var
|
|
15429
|
-
|
|
15663
|
+
var app37 = new Hono();
|
|
15664
|
+
app37.post("/", async (c) => {
|
|
15430
15665
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15431
15666
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
15432
|
-
console.error(`${
|
|
15667
|
+
console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15433
15668
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
15434
15669
|
}
|
|
15435
15670
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15438,7 +15673,7 @@ app36.post("/", async (c) => {
|
|
|
15438
15673
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15439
15674
|
const offender = tokens.find((t) => !isLoopbackAddr4(t));
|
|
15440
15675
|
if (offender !== void 0) {
|
|
15441
|
-
console.error(`${
|
|
15676
|
+
console.error(`${TAG29} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15442
15677
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
15443
15678
|
}
|
|
15444
15679
|
}
|
|
@@ -15453,18 +15688,18 @@ app36.post("/", async (c) => {
|
|
|
15453
15688
|
handlePublicSessionExit(sessionId);
|
|
15454
15689
|
return c.json({ ok: true });
|
|
15455
15690
|
});
|
|
15456
|
-
var public_session_exit_default =
|
|
15691
|
+
var public_session_exit_default = app37;
|
|
15457
15692
|
|
|
15458
15693
|
// server/routes/admin/access-session-evict.ts
|
|
15459
|
-
var
|
|
15694
|
+
var TAG30 = "[access-session-evict]";
|
|
15460
15695
|
function isLoopbackAddr5(addr) {
|
|
15461
15696
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15462
15697
|
}
|
|
15463
|
-
var
|
|
15464
|
-
|
|
15698
|
+
var app38 = new Hono();
|
|
15699
|
+
app38.post("/", async (c) => {
|
|
15465
15700
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15466
15701
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
15467
|
-
console.error(`${
|
|
15702
|
+
console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15468
15703
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
15469
15704
|
}
|
|
15470
15705
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15473,7 +15708,7 @@ app37.post("/", async (c) => {
|
|
|
15473
15708
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15474
15709
|
const offender = tokens.find((t) => !isLoopbackAddr5(t));
|
|
15475
15710
|
if (offender !== void 0) {
|
|
15476
|
-
console.error(`${
|
|
15711
|
+
console.error(`${TAG30} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15477
15712
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
15478
15713
|
}
|
|
15479
15714
|
}
|
|
@@ -15486,22 +15721,22 @@ app37.post("/", async (c) => {
|
|
|
15486
15721
|
const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
|
|
15487
15722
|
if (!grantId) return c.json({ error: "grantId required" }, 400);
|
|
15488
15723
|
const dropped = evictAccessSessionsByGrant(grantId);
|
|
15489
|
-
console.log(`${
|
|
15724
|
+
console.log(`${TAG30} grantId=${grantId} dropped=${dropped}`);
|
|
15490
15725
|
return c.json({ ok: true, dropped });
|
|
15491
15726
|
});
|
|
15492
|
-
var access_session_evict_default =
|
|
15727
|
+
var access_session_evict_default = app38;
|
|
15493
15728
|
|
|
15494
15729
|
// server/routes/admin/enrol-person.ts
|
|
15495
|
-
var
|
|
15730
|
+
var TAG31 = "[enrol]";
|
|
15496
15731
|
function isLoopbackAddr6(addr) {
|
|
15497
15732
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15498
15733
|
}
|
|
15499
15734
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15500
|
-
var
|
|
15501
|
-
|
|
15735
|
+
var app39 = new Hono();
|
|
15736
|
+
app39.post("/", async (c) => {
|
|
15502
15737
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15503
15738
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
15504
|
-
console.error(`${
|
|
15739
|
+
console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15505
15740
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
15506
15741
|
}
|
|
15507
15742
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15510,7 +15745,7 @@ app38.post("/", async (c) => {
|
|
|
15510
15745
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15511
15746
|
const offender = tokens.find((t) => !isLoopbackAddr6(t));
|
|
15512
15747
|
if (offender !== void 0) {
|
|
15513
|
-
console.error(`${
|
|
15748
|
+
console.error(`${TAG31} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15514
15749
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
15515
15750
|
}
|
|
15516
15751
|
}
|
|
@@ -15535,7 +15770,7 @@ app38.post("/", async (c) => {
|
|
|
15535
15770
|
}
|
|
15536
15771
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
15537
15772
|
if (!accountId) {
|
|
15538
|
-
console.error(`${
|
|
15773
|
+
console.error(`${TAG31} op=person result=no-account-id`);
|
|
15539
15774
|
return c.json({ error: "no-account-id" }, 500);
|
|
15540
15775
|
}
|
|
15541
15776
|
let personId;
|
|
@@ -15543,7 +15778,7 @@ app38.post("/", async (c) => {
|
|
|
15543
15778
|
personId = await enrolPerson({ accountId, phone, email, agentSlug });
|
|
15544
15779
|
} catch (err) {
|
|
15545
15780
|
console.error(
|
|
15546
|
-
`${
|
|
15781
|
+
`${TAG31} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
15547
15782
|
);
|
|
15548
15783
|
return c.json({ error: "enrol-failed" }, 500);
|
|
15549
15784
|
}
|
|
@@ -15553,19 +15788,19 @@ app38.post("/", async (c) => {
|
|
|
15553
15788
|
if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
|
|
15554
15789
|
} catch (err) {
|
|
15555
15790
|
console.error(
|
|
15556
|
-
`${
|
|
15791
|
+
`${TAG31} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
15557
15792
|
);
|
|
15558
15793
|
}
|
|
15559
15794
|
console.log(
|
|
15560
|
-
`${
|
|
15795
|
+
`${TAG31} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
|
|
15561
15796
|
);
|
|
15562
15797
|
return c.json({ personId, grant }, 200);
|
|
15563
15798
|
});
|
|
15564
|
-
var enrol_person_default =
|
|
15799
|
+
var enrol_person_default = app39;
|
|
15565
15800
|
|
|
15566
15801
|
// server/routes/admin/browser.ts
|
|
15567
|
-
var
|
|
15568
|
-
|
|
15802
|
+
var app40 = new Hono();
|
|
15803
|
+
app40.post("/launch", requireAdminSession, async (c) => {
|
|
15569
15804
|
try {
|
|
15570
15805
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
15571
15806
|
console.error(`[admin/browser/launch] op=request transport=${transport}`);
|
|
@@ -15593,50 +15828,50 @@ app39.post("/launch", requireAdminSession, async (c) => {
|
|
|
15593
15828
|
);
|
|
15594
15829
|
}
|
|
15595
15830
|
});
|
|
15596
|
-
var browser_default =
|
|
15831
|
+
var browser_default = app40;
|
|
15597
15832
|
|
|
15598
15833
|
// server/routes/admin/index.ts
|
|
15599
|
-
var
|
|
15600
|
-
|
|
15601
|
-
|
|
15602
|
-
|
|
15603
|
-
|
|
15604
|
-
|
|
15605
|
-
|
|
15606
|
-
|
|
15607
|
-
|
|
15608
|
-
|
|
15609
|
-
|
|
15610
|
-
|
|
15611
|
-
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
|
|
15618
|
-
|
|
15619
|
-
|
|
15620
|
-
|
|
15621
|
-
|
|
15622
|
-
|
|
15623
|
-
|
|
15624
|
-
|
|
15625
|
-
|
|
15626
|
-
|
|
15627
|
-
|
|
15628
|
-
|
|
15629
|
-
|
|
15630
|
-
|
|
15631
|
-
|
|
15632
|
-
var admin_default =
|
|
15834
|
+
var app41 = new Hono();
|
|
15835
|
+
app41.route("/session", session_default);
|
|
15836
|
+
app41.route("/logs", logs_default);
|
|
15837
|
+
app41.route("/claude-info", claude_info_default);
|
|
15838
|
+
app41.route("/attachment", attachment_default);
|
|
15839
|
+
app41.route("/agents", agents_default);
|
|
15840
|
+
app41.route("/sessions", sessions_default);
|
|
15841
|
+
app41.route("/claude-sessions", claude_sessions_default);
|
|
15842
|
+
app41.route("/log-ingest", log_ingest_default);
|
|
15843
|
+
app41.route("/events", events_default);
|
|
15844
|
+
app41.route("/files", files_default);
|
|
15845
|
+
app41.route("/graph-search", graph_search_default);
|
|
15846
|
+
app41.route("/graph-subgraph", graph_subgraph_default);
|
|
15847
|
+
app41.route("/graph-delete", graph_delete_default);
|
|
15848
|
+
app41.route("/graph-restore", graph_restore_default);
|
|
15849
|
+
app41.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
15850
|
+
app41.route("/graph-default-view", graph_default_view_default);
|
|
15851
|
+
app41.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
15852
|
+
app41.route("/sidebar-sessions", sidebar_sessions_default);
|
|
15853
|
+
app41.route("/session-delete", session_delete_default);
|
|
15854
|
+
app41.route("/session-stop", session_stop_default);
|
|
15855
|
+
app41.route("/session-archive", session_archive_default);
|
|
15856
|
+
app41.route("/browser", browser_default);
|
|
15857
|
+
app41.route("/session-rc-spawn", session_rc_spawn_default);
|
|
15858
|
+
app41.route("/session-reseat", session_reseat_default);
|
|
15859
|
+
app41.route("/system-stats", system_stats_default);
|
|
15860
|
+
app41.route("/health-brand", health_default2);
|
|
15861
|
+
app41.route("/linkedin-ingest", linkedin_ingest_default);
|
|
15862
|
+
app41.route("/post-turn-context", post_turn_context_default);
|
|
15863
|
+
app41.route("/public-session-context", public_session_context_default);
|
|
15864
|
+
app41.route("/public-session-exit", public_session_exit_default);
|
|
15865
|
+
app41.route("/access-session-evict", access_session_evict_default);
|
|
15866
|
+
app41.route("/enrol-person", enrol_person_default);
|
|
15867
|
+
var admin_default = app41;
|
|
15633
15868
|
|
|
15634
15869
|
// server/routes/access/verify-token.ts
|
|
15635
|
-
var
|
|
15870
|
+
var TAG32 = "[access-verify]";
|
|
15636
15871
|
var MINT_TAG = "[access-session-mint]";
|
|
15637
15872
|
var COOKIE_NAME = "__access_session";
|
|
15638
|
-
var
|
|
15639
|
-
|
|
15873
|
+
var app42 = new Hono();
|
|
15874
|
+
app42.post("/", async (c) => {
|
|
15640
15875
|
const ip = c.var.clientIp || "unknown";
|
|
15641
15876
|
let body;
|
|
15642
15877
|
try {
|
|
@@ -15651,39 +15886,39 @@ app41.post("/", async (c) => {
|
|
|
15651
15886
|
}
|
|
15652
15887
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
15653
15888
|
if (rateMsg) {
|
|
15654
|
-
console.error(`${
|
|
15889
|
+
console.error(`${TAG32} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
15655
15890
|
return c.json({ error: rateMsg }, 429);
|
|
15656
15891
|
}
|
|
15657
15892
|
const grant = await findGrantByMagicToken(token);
|
|
15658
15893
|
if (!grant) {
|
|
15659
15894
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
15660
|
-
console.error(`${
|
|
15895
|
+
console.error(`${TAG32} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
15661
15896
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
15662
15897
|
}
|
|
15663
15898
|
if (grant.agentSlug !== agentSlug) {
|
|
15664
15899
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
15665
15900
|
console.error(
|
|
15666
|
-
`${
|
|
15901
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
15667
15902
|
);
|
|
15668
15903
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
15669
15904
|
}
|
|
15670
15905
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
15671
15906
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
15672
15907
|
console.error(
|
|
15673
|
-
`${
|
|
15908
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
15674
15909
|
);
|
|
15675
15910
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
15676
15911
|
}
|
|
15677
15912
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
15678
15913
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
15679
15914
|
console.error(
|
|
15680
|
-
`${
|
|
15915
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
15681
15916
|
);
|
|
15682
15917
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
15683
15918
|
}
|
|
15684
15919
|
if (!grant.sliceToken) {
|
|
15685
15920
|
console.error(
|
|
15686
|
-
`${
|
|
15921
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
15687
15922
|
);
|
|
15688
15923
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
15689
15924
|
}
|
|
@@ -15699,12 +15934,12 @@ app41.post("/", async (c) => {
|
|
|
15699
15934
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
15700
15935
|
} catch (err) {
|
|
15701
15936
|
console.error(
|
|
15702
|
-
`${
|
|
15937
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
15703
15938
|
);
|
|
15704
15939
|
return c.json({ error: "verification-failed" }, 500);
|
|
15705
15940
|
}
|
|
15706
15941
|
clearAccessRateLimit(ip, agentSlug);
|
|
15707
|
-
console.log(`${
|
|
15942
|
+
console.log(`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
15708
15943
|
console.log(
|
|
15709
15944
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
15710
15945
|
);
|
|
@@ -15718,13 +15953,13 @@ app41.post("/", async (c) => {
|
|
|
15718
15953
|
displayName: grant.displayName
|
|
15719
15954
|
});
|
|
15720
15955
|
});
|
|
15721
|
-
var verify_token_default =
|
|
15956
|
+
var verify_token_default = app42;
|
|
15722
15957
|
|
|
15723
15958
|
// app/lib/access-email.ts
|
|
15724
15959
|
import { spawn as spawn2 } from "child_process";
|
|
15725
|
-
import { resolve as
|
|
15726
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
15727
|
-
var SEND_SCRIPT =
|
|
15960
|
+
import { resolve as resolve25 } from "path";
|
|
15961
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
|
|
15962
|
+
var SEND_SCRIPT = resolve25(
|
|
15728
15963
|
PLATFORM_ROOT7,
|
|
15729
15964
|
"plugins",
|
|
15730
15965
|
"email",
|
|
@@ -15780,10 +16015,10 @@ async function sendMagicLinkEmail(payload) {
|
|
|
15780
16015
|
}
|
|
15781
16016
|
|
|
15782
16017
|
// server/routes/access/request-magic-link.ts
|
|
15783
|
-
var
|
|
15784
|
-
var
|
|
16018
|
+
var TAG33 = "[access-request-link]";
|
|
16019
|
+
var app43 = new Hono();
|
|
15785
16020
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
15786
|
-
|
|
16021
|
+
app43.post("/", async (c) => {
|
|
15787
16022
|
let body;
|
|
15788
16023
|
try {
|
|
15789
16024
|
body = await c.req.json();
|
|
@@ -15797,18 +16032,18 @@ app42.post("/", async (c) => {
|
|
|
15797
16032
|
}
|
|
15798
16033
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
15799
16034
|
if (rateMsg) {
|
|
15800
|
-
console.error(`${
|
|
16035
|
+
console.error(`${TAG33} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
15801
16036
|
return c.json({ error: rateMsg }, 429);
|
|
15802
16037
|
}
|
|
15803
16038
|
recordRequestLinkAttempt(contactValue);
|
|
15804
16039
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
15805
16040
|
if (!accountId) {
|
|
15806
|
-
console.error(`${
|
|
16041
|
+
console.error(`${TAG33} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
15807
16042
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15808
16043
|
}
|
|
15809
16044
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
15810
16045
|
if (!grant) {
|
|
15811
|
-
console.log(`${
|
|
16046
|
+
console.log(`${TAG33} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
15812
16047
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15813
16048
|
}
|
|
15814
16049
|
let token;
|
|
@@ -15816,7 +16051,7 @@ app42.post("/", async (c) => {
|
|
|
15816
16051
|
token = await generateNewMagicToken(grant.grantId);
|
|
15817
16052
|
} catch (err) {
|
|
15818
16053
|
console.error(
|
|
15819
|
-
`${
|
|
16054
|
+
`${TAG33} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
15820
16055
|
);
|
|
15821
16056
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15822
16057
|
}
|
|
@@ -15848,26 +16083,26 @@ app42.post("/", async (c) => {
|
|
|
15848
16083
|
});
|
|
15849
16084
|
if (!sendResult.ok) {
|
|
15850
16085
|
console.error(
|
|
15851
|
-
`${
|
|
16086
|
+
`${TAG33} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
15852
16087
|
);
|
|
15853
16088
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15854
16089
|
}
|
|
15855
16090
|
console.log(
|
|
15856
|
-
`${
|
|
16091
|
+
`${TAG33} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
15857
16092
|
);
|
|
15858
16093
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15859
16094
|
});
|
|
15860
|
-
var request_magic_link_default =
|
|
16095
|
+
var request_magic_link_default = app43;
|
|
15861
16096
|
|
|
15862
16097
|
// server/routes/access/index.ts
|
|
15863
|
-
var
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
var access_default =
|
|
16098
|
+
var app44 = new Hono();
|
|
16099
|
+
app44.route("/verify-token", verify_token_default);
|
|
16100
|
+
app44.route("/request-magic-link", request_magic_link_default);
|
|
16101
|
+
var access_default = app44;
|
|
15867
16102
|
|
|
15868
16103
|
// server/routes/sites.ts
|
|
15869
|
-
import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync5, statSync as
|
|
15870
|
-
import { resolve as
|
|
16104
|
+
import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync5, statSync as statSync10 } from "fs";
|
|
16105
|
+
import { resolve as resolve26 } from "path";
|
|
15871
16106
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
15872
16107
|
var MIME = {
|
|
15873
16108
|
".html": "text/html; charset=utf-8",
|
|
@@ -15898,8 +16133,8 @@ function getExt(p) {
|
|
|
15898
16133
|
if (idx < p.lastIndexOf("/")) return "";
|
|
15899
16134
|
return p.slice(idx).toLowerCase();
|
|
15900
16135
|
}
|
|
15901
|
-
var
|
|
15902
|
-
|
|
16136
|
+
var app45 = new Hono();
|
|
16137
|
+
app45.get("/:rel{.*}", (c) => {
|
|
15903
16138
|
const reqPath = c.req.path;
|
|
15904
16139
|
const rawRel = c.req.param("rel") ?? "";
|
|
15905
16140
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -15924,15 +16159,15 @@ app44.get("/:rel{.*}", (c) => {
|
|
|
15924
16159
|
}
|
|
15925
16160
|
segments.push(seg);
|
|
15926
16161
|
}
|
|
15927
|
-
const rootDir =
|
|
15928
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
16162
|
+
const rootDir = resolve26(account.accountDir, "sites");
|
|
16163
|
+
let filePath = segments.length === 0 ? rootDir : resolve26(rootDir, ...segments);
|
|
15929
16164
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
15930
16165
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
15931
16166
|
return c.text("Forbidden", 403);
|
|
15932
16167
|
}
|
|
15933
16168
|
let stat7;
|
|
15934
16169
|
try {
|
|
15935
|
-
stat7 = existsSync23(filePath) ?
|
|
16170
|
+
stat7 = existsSync23(filePath) ? statSync10(filePath) : null;
|
|
15936
16171
|
} catch {
|
|
15937
16172
|
stat7 = null;
|
|
15938
16173
|
}
|
|
@@ -15945,7 +16180,7 @@ app44.get("/:rel{.*}", (c) => {
|
|
|
15945
16180
|
return c.redirect(target, 301);
|
|
15946
16181
|
}
|
|
15947
16182
|
if (stat7?.isDirectory()) {
|
|
15948
|
-
filePath =
|
|
16183
|
+
filePath = resolve26(filePath, "index.html");
|
|
15949
16184
|
}
|
|
15950
16185
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
15951
16186
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
@@ -16002,12 +16237,12 @@ app44.get("/:rel{.*}", (c) => {
|
|
|
16002
16237
|
"X-Content-Type-Options": "nosniff"
|
|
16003
16238
|
});
|
|
16004
16239
|
});
|
|
16005
|
-
var sites_default =
|
|
16240
|
+
var sites_default = app45;
|
|
16006
16241
|
|
|
16007
16242
|
// app/lib/visitor-token.ts
|
|
16008
16243
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
16009
16244
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync24, writeFileSync as writeFileSync9 } from "fs";
|
|
16010
|
-
import { dirname as
|
|
16245
|
+
import { dirname as dirname7 } from "path";
|
|
16011
16246
|
var TOKEN_PREFIX = "v1.";
|
|
16012
16247
|
var SECRET_BYTES = 32;
|
|
16013
16248
|
var DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -16024,7 +16259,7 @@ function getSecret() {
|
|
|
16024
16259
|
}
|
|
16025
16260
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
16026
16261
|
try {
|
|
16027
|
-
mkdirSync4(
|
|
16262
|
+
mkdirSync4(dirname7(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
16028
16263
|
writeFileSync9(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
16029
16264
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
16030
16265
|
} catch {
|
|
@@ -16083,7 +16318,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
|
16083
16318
|
|
|
16084
16319
|
// app/lib/brand-config.ts
|
|
16085
16320
|
import { existsSync as existsSync24, readFileSync as readFileSync25 } from "fs";
|
|
16086
|
-
import { join as
|
|
16321
|
+
import { join as join23 } from "path";
|
|
16087
16322
|
var cached2 = null;
|
|
16088
16323
|
var cachedAttempted = false;
|
|
16089
16324
|
function readBrandConfig() {
|
|
@@ -16091,7 +16326,7 @@ function readBrandConfig() {
|
|
|
16091
16326
|
cachedAttempted = true;
|
|
16092
16327
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
|
|
16093
16328
|
if (!platformRoot2) return null;
|
|
16094
|
-
const brandPath =
|
|
16329
|
+
const brandPath = join23(platformRoot2, "config", "brand.json");
|
|
16095
16330
|
if (!existsSync24(brandPath)) return null;
|
|
16096
16331
|
try {
|
|
16097
16332
|
cached2 = JSON.parse(readFileSync25(brandPath, "utf-8"));
|
|
@@ -16102,7 +16337,7 @@ function readBrandConfig() {
|
|
|
16102
16337
|
}
|
|
16103
16338
|
|
|
16104
16339
|
// server/routes/visitor-consent.ts
|
|
16105
|
-
var
|
|
16340
|
+
var app46 = new Hono();
|
|
16106
16341
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
16107
16342
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
16108
16343
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -16147,17 +16382,17 @@ function siteSlugFromReferer(referer) {
|
|
|
16147
16382
|
return "";
|
|
16148
16383
|
}
|
|
16149
16384
|
}
|
|
16150
|
-
|
|
16385
|
+
app46.options("/consent", (c) => {
|
|
16151
16386
|
const origin = getOrigin(c);
|
|
16152
16387
|
setCorsHeaders(c, origin);
|
|
16153
16388
|
return c.body(null, 204);
|
|
16154
16389
|
});
|
|
16155
|
-
|
|
16390
|
+
app46.options("/brand-config", (c) => {
|
|
16156
16391
|
const origin = getOrigin(c);
|
|
16157
16392
|
setCorsHeaders(c, origin);
|
|
16158
16393
|
return c.body(null, 204);
|
|
16159
16394
|
});
|
|
16160
|
-
|
|
16395
|
+
app46.post("/consent", async (c) => {
|
|
16161
16396
|
const origin = getOrigin(c);
|
|
16162
16397
|
setCorsHeaders(c, origin);
|
|
16163
16398
|
let raw;
|
|
@@ -16197,7 +16432,7 @@ app45.post("/consent", async (c) => {
|
|
|
16197
16432
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
16198
16433
|
return c.body(null, 204);
|
|
16199
16434
|
});
|
|
16200
|
-
|
|
16435
|
+
app46.get("/brand-config", (c) => {
|
|
16201
16436
|
const origin = getOrigin(c);
|
|
16202
16437
|
setCorsHeaders(c, origin);
|
|
16203
16438
|
const brand = readBrandConfig();
|
|
@@ -16207,7 +16442,7 @@ app45.get("/brand-config", (c) => {
|
|
|
16207
16442
|
c.header("Cache-Control", "public, max-age=300");
|
|
16208
16443
|
return c.json({ consent: { copy, palette } });
|
|
16209
16444
|
});
|
|
16210
|
-
var visitor_consent_default =
|
|
16445
|
+
var visitor_consent_default = app46;
|
|
16211
16446
|
|
|
16212
16447
|
// server/routes/listings.ts
|
|
16213
16448
|
function getCookie(headerValue, name) {
|
|
@@ -16228,14 +16463,14 @@ function appendConsentParams(pageUrl, token) {
|
|
|
16228
16463
|
const hashIdx = pageUrl.indexOf("#");
|
|
16229
16464
|
const hash = hashIdx >= 0 ? pageUrl.slice(hashIdx) : "";
|
|
16230
16465
|
const base = hashIdx >= 0 ? pageUrl.slice(0, hashIdx) : pageUrl;
|
|
16231
|
-
const
|
|
16232
|
-
return base +
|
|
16466
|
+
const sep9 = base.indexOf("?") >= 0 ? "&" : "?";
|
|
16467
|
+
return base + sep9 + `consent=needed&v=${encodeURIComponent(token)}` + hash;
|
|
16233
16468
|
}
|
|
16234
16469
|
}
|
|
16235
16470
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
16236
16471
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
16237
|
-
var
|
|
16238
|
-
|
|
16472
|
+
var app47 = new Hono();
|
|
16473
|
+
app47.get("/:slug/click", async (c) => {
|
|
16239
16474
|
const slug = c.req.param("slug") ?? "";
|
|
16240
16475
|
const rawSession = c.req.query("session") ?? "";
|
|
16241
16476
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -16299,10 +16534,10 @@ app46.get("/:slug/click", async (c) => {
|
|
|
16299
16534
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
16300
16535
|
return c.redirect(redirectUrl, 302);
|
|
16301
16536
|
});
|
|
16302
|
-
var listings_default =
|
|
16537
|
+
var listings_default = app47;
|
|
16303
16538
|
|
|
16304
16539
|
// server/routes/visitor-event.ts
|
|
16305
|
-
var
|
|
16540
|
+
var app48 = new Hono();
|
|
16306
16541
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
16307
16542
|
var buckets = /* @__PURE__ */ new Map();
|
|
16308
16543
|
var RATE_LIMIT = 60;
|
|
@@ -16369,12 +16604,12 @@ function originAllowed(origin, allowlist) {
|
|
|
16369
16604
|
return false;
|
|
16370
16605
|
}
|
|
16371
16606
|
}
|
|
16372
|
-
|
|
16607
|
+
app48.options("/event", (c) => {
|
|
16373
16608
|
const origin = getOrigin2(c);
|
|
16374
16609
|
setCorsHeaders2(c, origin);
|
|
16375
16610
|
return c.body(null, 204);
|
|
16376
16611
|
});
|
|
16377
|
-
|
|
16612
|
+
app48.post("/event", async (c) => {
|
|
16378
16613
|
const origin = getOrigin2(c);
|
|
16379
16614
|
setCorsHeaders2(c, origin);
|
|
16380
16615
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -16579,17 +16814,17 @@ async function writeEvent(opts) {
|
|
|
16579
16814
|
);
|
|
16580
16815
|
}
|
|
16581
16816
|
}
|
|
16582
|
-
var visitor_event_default =
|
|
16817
|
+
var visitor_event_default = app48;
|
|
16583
16818
|
|
|
16584
16819
|
// server/routes/session.ts
|
|
16585
|
-
import { resolve as
|
|
16820
|
+
import { resolve as resolve27 } from "path";
|
|
16586
16821
|
import { existsSync as existsSync25, writeFileSync as writeFileSync10, mkdirSync as mkdirSync5 } from "fs";
|
|
16587
16822
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16588
16823
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
16589
16824
|
try {
|
|
16590
|
-
const cacheDir =
|
|
16825
|
+
const cacheDir = resolve27(MAXY_DIR, "branding-cache", accountId);
|
|
16591
16826
|
mkdirSync5(cacheDir, { recursive: true });
|
|
16592
|
-
writeFileSync10(
|
|
16827
|
+
writeFileSync10(resolve27(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
16593
16828
|
} catch (err) {
|
|
16594
16829
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
16595
16830
|
}
|
|
@@ -16601,7 +16836,7 @@ function parseVisitorCookie(cookieHeader) {
|
|
|
16601
16836
|
const value = decodeURIComponent(match[1]).trim();
|
|
16602
16837
|
return UUID_RE4.test(value) ? value : null;
|
|
16603
16838
|
}
|
|
16604
|
-
function
|
|
16839
|
+
function parseAccessSessionId2(cookieHeader) {
|
|
16605
16840
|
if (!cookieHeader) return null;
|
|
16606
16841
|
const part = cookieHeader.split(";").map((p) => p.trim()).find((p) => p.startsWith("__access_session="));
|
|
16607
16842
|
return part ? part.slice("__access_session=".length) : null;
|
|
@@ -16625,8 +16860,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
16625
16860
|
headers
|
|
16626
16861
|
});
|
|
16627
16862
|
}
|
|
16628
|
-
var
|
|
16629
|
-
|
|
16863
|
+
var app49 = new Hono();
|
|
16864
|
+
app49.post("/", async (c) => {
|
|
16630
16865
|
let body;
|
|
16631
16866
|
try {
|
|
16632
16867
|
body = await c.req.json();
|
|
@@ -16677,8 +16912,8 @@ app48.post("/", async (c) => {
|
|
|
16677
16912
|
}
|
|
16678
16913
|
let agentConfig = null;
|
|
16679
16914
|
if (account) {
|
|
16680
|
-
const agentDir =
|
|
16681
|
-
if (!existsSync25(agentDir) || !existsSync25(
|
|
16915
|
+
const agentDir = resolve27(account.accountDir, "agents", agentSlug);
|
|
16916
|
+
if (!existsSync25(agentDir) || !existsSync25(resolve27(agentDir, "config.json"))) {
|
|
16682
16917
|
return c.json({ error: "Agent not found" }, 404);
|
|
16683
16918
|
}
|
|
16684
16919
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -16698,7 +16933,7 @@ app48.post("/", async (c) => {
|
|
|
16698
16933
|
if (branding) writeBrandingCache(accountId, agentSlug, branding);
|
|
16699
16934
|
let accessSession = null;
|
|
16700
16935
|
if (agentConfig && agentConfig.accessMode !== "open") {
|
|
16701
|
-
const accessSessionId =
|
|
16936
|
+
const accessSessionId = parseAccessSessionId2(cookieHeader);
|
|
16702
16937
|
accessSession = accessSessionId ? getAccessSession(accessSessionId) : null;
|
|
16703
16938
|
if (!accessSession || accessSession.agentSlug !== agentSlug) {
|
|
16704
16939
|
console.log(`[session] agent=${agentSlug} accessMode=${agentConfig.accessMode} \u2014 auth required`);
|
|
@@ -16837,7 +17072,7 @@ app48.post("/", async (c) => {
|
|
|
16837
17072
|
newVisitorId
|
|
16838
17073
|
);
|
|
16839
17074
|
});
|
|
16840
|
-
var session_default2 =
|
|
17075
|
+
var session_default2 = app49;
|
|
16841
17076
|
|
|
16842
17077
|
// app/lib/graph-health.ts
|
|
16843
17078
|
var import_dist4 = __toESM(require_dist3(), 1);
|
|
@@ -16958,13 +17193,13 @@ function startGraphHealthTimer() {
|
|
|
16958
17193
|
|
|
16959
17194
|
// app/lib/file-watcher.ts
|
|
16960
17195
|
import * as fsp2 from "fs/promises";
|
|
16961
|
-
import { resolve as
|
|
17196
|
+
import { resolve as resolve28, sep as sep8 } from "path";
|
|
16962
17197
|
var ACCOUNT_UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16963
17198
|
var DEFAULT_COALESCE_MS = 500;
|
|
16964
17199
|
var ROOTS = ["accounts"];
|
|
16965
17200
|
function _routeEvent(rootName, filename) {
|
|
16966
17201
|
if (!filename) return null;
|
|
16967
|
-
const segs = filename.split(
|
|
17202
|
+
const segs = filename.split(sep8).filter(Boolean);
|
|
16968
17203
|
if (segs.length < 2) return null;
|
|
16969
17204
|
const accountId = segs[0];
|
|
16970
17205
|
if (!ACCOUNT_UUID_RE2.test(accountId)) return null;
|
|
@@ -16977,7 +17212,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16977
17212
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
16978
17213
|
for (const r of ROOTS) {
|
|
16979
17214
|
try {
|
|
16980
|
-
await fsp2.mkdir(
|
|
17215
|
+
await fsp2.mkdir(resolve28(dataRoot, r), { recursive: true });
|
|
16981
17216
|
} catch (err) {
|
|
16982
17217
|
console.error(
|
|
16983
17218
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -16998,7 +17233,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16998
17233
|
timers.set(relativePath, t);
|
|
16999
17234
|
}
|
|
17000
17235
|
async function runHook(relativePath, accountId) {
|
|
17001
|
-
const absolute =
|
|
17236
|
+
const absolute = resolve28(dataRoot, relativePath);
|
|
17002
17237
|
let exists = false;
|
|
17003
17238
|
try {
|
|
17004
17239
|
const st = await fsp2.stat(absolute);
|
|
@@ -17022,7 +17257,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
17022
17257
|
}
|
|
17023
17258
|
}
|
|
17024
17259
|
async function watchRoot(rootName) {
|
|
17025
|
-
const absRoot =
|
|
17260
|
+
const absRoot = resolve28(dataRoot, rootName);
|
|
17026
17261
|
try {
|
|
17027
17262
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
17028
17263
|
for await (const event of iter) {
|
|
@@ -17061,7 +17296,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
17061
17296
|
|
|
17062
17297
|
// app/lib/migrate-uploads.ts
|
|
17063
17298
|
import { mkdir as mkdir5, readdir as readdir5, rename, rm as rm3 } from "fs/promises";
|
|
17064
|
-
import { dirname as
|
|
17299
|
+
import { dirname as dirname8, relative as relative4, resolve as resolve29 } from "path";
|
|
17065
17300
|
var ACCOUNT_UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
17066
17301
|
async function walkFiles(dir) {
|
|
17067
17302
|
const out = [];
|
|
@@ -17072,7 +17307,7 @@ async function walkFiles(dir) {
|
|
|
17072
17307
|
return out;
|
|
17073
17308
|
}
|
|
17074
17309
|
for (const e of entries) {
|
|
17075
|
-
const abs =
|
|
17310
|
+
const abs = resolve29(dir, e.name);
|
|
17076
17311
|
if (e.isDirectory()) {
|
|
17077
17312
|
out.push(...await walkFiles(abs));
|
|
17078
17313
|
} else if (e.isFile()) {
|
|
@@ -17092,8 +17327,8 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
17092
17327
|
let moved = 0;
|
|
17093
17328
|
for (const oldAbs of files) {
|
|
17094
17329
|
const suffix = relative4(srcDir, oldAbs);
|
|
17095
|
-
const newAbs =
|
|
17096
|
-
await mkdir5(
|
|
17330
|
+
const newAbs = resolve29(destDir, suffix);
|
|
17331
|
+
await mkdir5(dirname8(newAbs), { recursive: true });
|
|
17097
17332
|
await rename(oldAbs, newAbs);
|
|
17098
17333
|
moved++;
|
|
17099
17334
|
const oldRel = relative4(dataRoot, oldAbs);
|
|
@@ -17119,7 +17354,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
17119
17354
|
}
|
|
17120
17355
|
async function migrateUploads(opts = {}) {
|
|
17121
17356
|
const dataRoot = opts.dataRoot ?? DATA_ROOT;
|
|
17122
|
-
const oldRoot =
|
|
17357
|
+
const oldRoot = resolve29(dataRoot, "uploads");
|
|
17123
17358
|
let topEntries;
|
|
17124
17359
|
try {
|
|
17125
17360
|
topEntries = await readdir5(oldRoot, { withFileTypes: true });
|
|
@@ -17140,8 +17375,8 @@ async function migrateUploads(opts = {}) {
|
|
|
17140
17375
|
const name = entry.name;
|
|
17141
17376
|
if (ACCOUNT_UUID_RE3.test(name)) {
|
|
17142
17377
|
moved += await relocateTree(
|
|
17143
|
-
|
|
17144
|
-
|
|
17378
|
+
resolve29(oldRoot, name),
|
|
17379
|
+
resolve29(dataRoot, "accounts", name, "uploads"),
|
|
17145
17380
|
dataRoot,
|
|
17146
17381
|
name,
|
|
17147
17382
|
session
|
|
@@ -17153,8 +17388,8 @@ async function migrateUploads(opts = {}) {
|
|
|
17153
17388
|
continue;
|
|
17154
17389
|
}
|
|
17155
17390
|
moved += await relocateTree(
|
|
17156
|
-
|
|
17157
|
-
|
|
17391
|
+
resolve29(oldRoot, "public"),
|
|
17392
|
+
resolve29(dataRoot, "accounts", installAccountId, "uploads", "public"),
|
|
17158
17393
|
dataRoot,
|
|
17159
17394
|
null,
|
|
17160
17395
|
// public uploads carry no graph nodes
|
|
@@ -17185,7 +17420,7 @@ async function migrateUploads(opts = {}) {
|
|
|
17185
17420
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
17186
17421
|
import { readdir as readdir6, readFile as readFile6, rename as rename2, writeFile as writeFile5, unlink as unlink3 } from "fs/promises";
|
|
17187
17422
|
import { existsSync as existsSync26 } from "fs";
|
|
17188
|
-
import { join as
|
|
17423
|
+
import { join as join24 } from "path";
|
|
17189
17424
|
var ADMIN_ROLE2 = "admin";
|
|
17190
17425
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
17191
17426
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -17230,7 +17465,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17230
17465
|
}
|
|
17231
17466
|
for (const slug of slugs) {
|
|
17232
17467
|
if (!slug.isDirectory()) continue;
|
|
17233
|
-
const slugDir =
|
|
17468
|
+
const slugDir = join24(projectsRoot, slug.name);
|
|
17234
17469
|
let entries;
|
|
17235
17470
|
try {
|
|
17236
17471
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -17239,9 +17474,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17239
17474
|
}
|
|
17240
17475
|
for (const entry of entries) {
|
|
17241
17476
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
17242
|
-
out.push(
|
|
17477
|
+
out.push(join24(slugDir, entry.name));
|
|
17243
17478
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
17244
|
-
const subDir =
|
|
17479
|
+
const subDir = join24(slugDir, entry.name);
|
|
17245
17480
|
let subs;
|
|
17246
17481
|
try {
|
|
17247
17482
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -17249,7 +17484,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17249
17484
|
continue;
|
|
17250
17485
|
}
|
|
17251
17486
|
for (const s of subs) {
|
|
17252
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
17487
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join24(subDir, s.name));
|
|
17253
17488
|
}
|
|
17254
17489
|
}
|
|
17255
17490
|
}
|
|
@@ -17261,7 +17496,7 @@ function shortId(path2) {
|
|
|
17261
17496
|
return base.slice(0, 8);
|
|
17262
17497
|
}
|
|
17263
17498
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
17264
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
17499
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join24(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
17265
17500
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
17266
17501
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
17267
17502
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -17603,8 +17838,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
17603
17838
|
|
|
17604
17839
|
// app/lib/whatsapp/gateway/routes.ts
|
|
17605
17840
|
function createWaChannelRoutes(deps) {
|
|
17606
|
-
const
|
|
17607
|
-
|
|
17841
|
+
const app51 = new Hono();
|
|
17842
|
+
app51.get("/wa-channel/inbound", (c) => {
|
|
17608
17843
|
const senderId = c.req.query("senderId");
|
|
17609
17844
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
17610
17845
|
return streamSSE(c, async (stream2) => {
|
|
@@ -17622,7 +17857,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17622
17857
|
}
|
|
17623
17858
|
});
|
|
17624
17859
|
});
|
|
17625
|
-
|
|
17860
|
+
app51.post("/wa-channel/reply", async (c) => {
|
|
17626
17861
|
const body = await c.req.json().catch(() => null);
|
|
17627
17862
|
const senderId = body?.senderId;
|
|
17628
17863
|
const text = body?.text;
|
|
@@ -17643,7 +17878,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17643
17878
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
17644
17879
|
return c.json({ ok: true });
|
|
17645
17880
|
});
|
|
17646
|
-
|
|
17881
|
+
app51.post("/wa-channel/reply-document", async (c) => {
|
|
17647
17882
|
const body = await c.req.json().catch(() => null);
|
|
17648
17883
|
const senderId = body?.senderId;
|
|
17649
17884
|
const files = body?.files;
|
|
@@ -17682,7 +17917,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17682
17917
|
}
|
|
17683
17918
|
return c.json({ ok: true, results });
|
|
17684
17919
|
});
|
|
17685
|
-
|
|
17920
|
+
app51.post("/wa-channel/ready", async (c) => {
|
|
17686
17921
|
const body = await c.req.json().catch(() => null);
|
|
17687
17922
|
const senderId = body?.senderId;
|
|
17688
17923
|
if (typeof senderId !== "string") {
|
|
@@ -17691,7 +17926,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17691
17926
|
deps.onReady?.(senderId);
|
|
17692
17927
|
return c.json({ ok: true });
|
|
17693
17928
|
});
|
|
17694
|
-
|
|
17929
|
+
app51.post("/wa-channel/received", async (c) => {
|
|
17695
17930
|
const body = await c.req.json().catch(() => null);
|
|
17696
17931
|
const senderId = body?.senderId;
|
|
17697
17932
|
const waMessageId = body?.waMessageId;
|
|
@@ -17701,7 +17936,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17701
17936
|
deps.onReceived?.(senderId, waMessageId);
|
|
17702
17937
|
return c.json({ ok: true });
|
|
17703
17938
|
});
|
|
17704
|
-
|
|
17939
|
+
app51.post("/wa-channel/turn-end", async (c) => {
|
|
17705
17940
|
const body = await c.req.json().catch(() => null);
|
|
17706
17941
|
const senderId = body?.senderId;
|
|
17707
17942
|
const sessionId = body?.sessionId;
|
|
@@ -17732,7 +17967,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17732
17967
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=fallback bytes=${bytes}`);
|
|
17733
17968
|
return c.json({ ok: true, delivered: "fallback" });
|
|
17734
17969
|
});
|
|
17735
|
-
return
|
|
17970
|
+
return app51;
|
|
17736
17971
|
}
|
|
17737
17972
|
|
|
17738
17973
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -17985,8 +18220,8 @@ var InboundHub2 = class {
|
|
|
17985
18220
|
|
|
17986
18221
|
// app/lib/webchat/gateway/routes.ts
|
|
17987
18222
|
function createWebchatChannelRoutes(deps) {
|
|
17988
|
-
const
|
|
17989
|
-
|
|
18223
|
+
const app51 = new Hono();
|
|
18224
|
+
app51.get("/webchat-channel/inbound", (c) => {
|
|
17990
18225
|
const key = c.req.query("key");
|
|
17991
18226
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
17992
18227
|
return streamSSE(c, async (stream2) => {
|
|
@@ -18004,7 +18239,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18004
18239
|
}
|
|
18005
18240
|
});
|
|
18006
18241
|
});
|
|
18007
|
-
|
|
18242
|
+
app51.post("/webchat-channel/reply", async (c) => {
|
|
18008
18243
|
const body = await c.req.json().catch(() => null);
|
|
18009
18244
|
const key = body?.key;
|
|
18010
18245
|
const text = body?.text;
|
|
@@ -18014,7 +18249,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18014
18249
|
deps.onReply?.(key, text);
|
|
18015
18250
|
return c.json({ ok: true });
|
|
18016
18251
|
});
|
|
18017
|
-
|
|
18252
|
+
app51.post("/webchat-channel/ready", async (c) => {
|
|
18018
18253
|
const body = await c.req.json().catch(() => null);
|
|
18019
18254
|
const key = body?.key;
|
|
18020
18255
|
if (typeof key !== "string") {
|
|
@@ -18023,7 +18258,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18023
18258
|
deps.onReady?.(key);
|
|
18024
18259
|
return c.json({ ok: true });
|
|
18025
18260
|
});
|
|
18026
|
-
|
|
18261
|
+
app51.post("/webchat-channel/received", async (c) => {
|
|
18027
18262
|
const body = await c.req.json().catch(() => null);
|
|
18028
18263
|
const key = body?.key;
|
|
18029
18264
|
const messageId = body?.messageId;
|
|
@@ -18033,7 +18268,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18033
18268
|
deps.onReceived?.(key, messageId);
|
|
18034
18269
|
return c.json({ ok: true });
|
|
18035
18270
|
});
|
|
18036
|
-
return
|
|
18271
|
+
return app51;
|
|
18037
18272
|
}
|
|
18038
18273
|
|
|
18039
18274
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -18068,16 +18303,16 @@ var WebchatGateway = class {
|
|
|
18068
18303
|
* The public /api/chat route awaits this to return the reply on the same SSE
|
|
18069
18304
|
* response, preserving the pre-756 POST→single-blob browser contract. */
|
|
18070
18305
|
awaitReply(key, timeoutMs) {
|
|
18071
|
-
return new Promise((
|
|
18306
|
+
return new Promise((resolve32) => {
|
|
18072
18307
|
const timer2 = setTimeout(() => {
|
|
18073
18308
|
this.replyAwaiters.delete(key);
|
|
18074
|
-
|
|
18309
|
+
resolve32({ timeout: true });
|
|
18075
18310
|
}, timeoutMs);
|
|
18076
18311
|
if (timer2.unref) timer2.unref();
|
|
18077
18312
|
this.replyAwaiters.set(key, (r) => {
|
|
18078
18313
|
clearTimeout(timer2);
|
|
18079
18314
|
this.replyAwaiters.delete(key);
|
|
18080
|
-
|
|
18315
|
+
resolve32(r);
|
|
18081
18316
|
});
|
|
18082
18317
|
});
|
|
18083
18318
|
}
|
|
@@ -18346,8 +18581,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
18346
18581
|
|
|
18347
18582
|
// ../lib/entitlement/src/index.ts
|
|
18348
18583
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
18349
|
-
import { existsSync as existsSync27, readFileSync as readFileSync26, statSync as
|
|
18350
|
-
import { resolve as
|
|
18584
|
+
import { existsSync as existsSync27, readFileSync as readFileSync26, statSync as statSync11 } from "fs";
|
|
18585
|
+
import { resolve as resolve30 } from "path";
|
|
18351
18586
|
|
|
18352
18587
|
// ../lib/entitlement/src/canonicalize.ts
|
|
18353
18588
|
function canonicalize(value) {
|
|
@@ -18382,7 +18617,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
18382
18617
|
var GRACE_DAYS = 7;
|
|
18383
18618
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
18384
18619
|
function pubkeyPath(brand) {
|
|
18385
|
-
return
|
|
18620
|
+
return resolve30(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
18386
18621
|
}
|
|
18387
18622
|
var memo = null;
|
|
18388
18623
|
function memoKey(mtimeMs, account) {
|
|
@@ -18394,11 +18629,11 @@ function resolveEntitlement(brand, account) {
|
|
|
18394
18629
|
if (brand.commercialMode !== true) {
|
|
18395
18630
|
return logResolved(implicitTrust(account), null);
|
|
18396
18631
|
}
|
|
18397
|
-
const entitlementPath =
|
|
18632
|
+
const entitlementPath = resolve30(brand.configDir, "entitlement.json");
|
|
18398
18633
|
if (!existsSync27(entitlementPath)) {
|
|
18399
18634
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
18400
18635
|
}
|
|
18401
|
-
const stat7 =
|
|
18636
|
+
const stat7 = statSync11(entitlementPath);
|
|
18402
18637
|
const key = memoKey(stat7.mtimeMs, account);
|
|
18403
18638
|
if (memo && memo.key === key) {
|
|
18404
18639
|
return memo.result;
|
|
@@ -18585,7 +18820,7 @@ function clientFrom(c) {
|
|
|
18585
18820
|
);
|
|
18586
18821
|
}
|
|
18587
18822
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
18588
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
18823
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join25(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
18589
18824
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
18590
18825
|
if (BRAND_JSON_PATH && !existsSync28(BRAND_JSON_PATH)) {
|
|
18591
18826
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -18611,7 +18846,7 @@ var brandLoginOpts = {
|
|
|
18611
18846
|
bodyFont: BRAND.defaultFonts?.body,
|
|
18612
18847
|
logoContainsName: !!BRAND.logoContainsName
|
|
18613
18848
|
};
|
|
18614
|
-
var ALIAS_DOMAINS_PATH =
|
|
18849
|
+
var ALIAS_DOMAINS_PATH = join25(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
18615
18850
|
function loadAliasDomains() {
|
|
18616
18851
|
try {
|
|
18617
18852
|
if (!existsSync28(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -18639,11 +18874,11 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
18639
18874
|
function isPublicHost(host) {
|
|
18640
18875
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
18641
18876
|
}
|
|
18642
|
-
var
|
|
18877
|
+
var app50 = new Hono();
|
|
18643
18878
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
18644
18879
|
var waGateway = new WaGateway({
|
|
18645
18880
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
18646
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
18881
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join25(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
18647
18882
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
18648
18883
|
// account + path validation here and funnel through the shared send core.
|
|
18649
18884
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -18659,7 +18894,7 @@ var waGateway = new WaGateway({
|
|
|
18659
18894
|
caption,
|
|
18660
18895
|
accountId,
|
|
18661
18896
|
maxyAccountId,
|
|
18662
|
-
platformRoot:
|
|
18897
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join25(__dirname, ".."))
|
|
18663
18898
|
});
|
|
18664
18899
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
18665
18900
|
},
|
|
@@ -18689,7 +18924,7 @@ var waGateway = new WaGateway({
|
|
|
18689
18924
|
nativeFileFollowers.set(senderId, ac);
|
|
18690
18925
|
}
|
|
18691
18926
|
});
|
|
18692
|
-
|
|
18927
|
+
app50.route("/", waGateway.routes());
|
|
18693
18928
|
waGateway.startSweeper();
|
|
18694
18929
|
var webchatGateway = new WebchatGateway({
|
|
18695
18930
|
gatewayUrl: webchatGatewayUrl(),
|
|
@@ -18729,15 +18964,15 @@ var webchatGateway = new WebchatGateway({
|
|
|
18729
18964
|
deleteSession: (sessionId) => managerDelete(sessionId),
|
|
18730
18965
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
18731
18966
|
});
|
|
18732
|
-
|
|
18967
|
+
app50.route("/", webchatGateway.routes());
|
|
18733
18968
|
webchatGateway.startSweeper();
|
|
18734
18969
|
webchatGateway.startPublicReaper();
|
|
18735
18970
|
var chatRoutes = createChatRoutes({
|
|
18736
18971
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
18737
18972
|
awaitReply: (key, timeoutMs) => webchatGateway.awaitReply(key, timeoutMs)
|
|
18738
18973
|
});
|
|
18739
|
-
|
|
18740
|
-
|
|
18974
|
+
app50.use("*", clientIpMiddleware);
|
|
18975
|
+
app50.use("*", async (c, next) => {
|
|
18741
18976
|
await next();
|
|
18742
18977
|
c.header("X-Content-Type-Options", "nosniff");
|
|
18743
18978
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -18747,7 +18982,7 @@ app49.use("*", async (c, next) => {
|
|
|
18747
18982
|
);
|
|
18748
18983
|
});
|
|
18749
18984
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
18750
|
-
|
|
18985
|
+
app50.use("*", async (c, next) => {
|
|
18751
18986
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
18752
18987
|
await next();
|
|
18753
18988
|
return;
|
|
@@ -18765,7 +19000,7 @@ app49.use("*", async (c, next) => {
|
|
|
18765
19000
|
});
|
|
18766
19001
|
}
|
|
18767
19002
|
});
|
|
18768
|
-
|
|
19003
|
+
app50.use("*", async (c, next) => {
|
|
18769
19004
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
18770
19005
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
18771
19006
|
await next();
|
|
@@ -18796,7 +19031,7 @@ function resolveRemoteAuthOpts() {
|
|
|
18796
19031
|
return brandLoginOpts;
|
|
18797
19032
|
}
|
|
18798
19033
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
18799
|
-
|
|
19034
|
+
app50.post("/__remote-auth/login", async (c) => {
|
|
18800
19035
|
const client = clientFrom(c);
|
|
18801
19036
|
const clientIp = client.ip || "unknown";
|
|
18802
19037
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -18841,7 +19076,7 @@ app49.post("/__remote-auth/login", async (c) => {
|
|
|
18841
19076
|
}
|
|
18842
19077
|
});
|
|
18843
19078
|
});
|
|
18844
|
-
|
|
19079
|
+
app50.get("/__remote-auth/logout", (c) => {
|
|
18845
19080
|
const client = clientFrom(c);
|
|
18846
19081
|
const clientIp = client.ip || "unknown";
|
|
18847
19082
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -18854,7 +19089,7 @@ app49.get("/__remote-auth/logout", (c) => {
|
|
|
18854
19089
|
}
|
|
18855
19090
|
});
|
|
18856
19091
|
});
|
|
18857
|
-
|
|
19092
|
+
app50.post("/__remote-auth/change-password", async (c) => {
|
|
18858
19093
|
const client = clientFrom(c);
|
|
18859
19094
|
const clientIp = client.ip || "unknown";
|
|
18860
19095
|
const rateLimited = checkRateLimit(client);
|
|
@@ -18896,6 +19131,9 @@ app49.post("/__remote-auth/change-password", async (c) => {
|
|
|
18896
19131
|
redirect
|
|
18897
19132
|
}), 200);
|
|
18898
19133
|
}
|
|
19134
|
+
if (targetUserId && await accessPasswordCollides(newPassword, USERS_FILE, targetUserId)) {
|
|
19135
|
+
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "That password is already in use by another admin. Choose a different one.", redirect }), 200);
|
|
19136
|
+
}
|
|
18899
19137
|
try {
|
|
18900
19138
|
if (targetUserId) {
|
|
18901
19139
|
await setAccessPassword(targetUserId, newPassword, USERS_FILE);
|
|
@@ -18910,13 +19148,13 @@ app49.post("/__remote-auth/change-password", async (c) => {
|
|
|
18910
19148
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
18911
19149
|
}
|
|
18912
19150
|
});
|
|
18913
|
-
|
|
19151
|
+
app50.get("/__remote-auth/setup", (c) => {
|
|
18914
19152
|
if (isRemoteAuthConfigured()) {
|
|
18915
19153
|
return c.redirect("/");
|
|
18916
19154
|
}
|
|
18917
19155
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
18918
19156
|
});
|
|
18919
|
-
|
|
19157
|
+
app50.post("/__remote-auth/set-initial-password", async (c) => {
|
|
18920
19158
|
if (isRemoteAuthConfigured()) {
|
|
18921
19159
|
return c.redirect("/");
|
|
18922
19160
|
}
|
|
@@ -18954,10 +19192,10 @@ app49.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
18954
19192
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
18955
19193
|
}
|
|
18956
19194
|
});
|
|
18957
|
-
|
|
19195
|
+
app50.get("/api/remote-auth/status", (c) => {
|
|
18958
19196
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
18959
19197
|
});
|
|
18960
|
-
|
|
19198
|
+
app50.post("/api/remote-auth/set-password", async (c) => {
|
|
18961
19199
|
let body;
|
|
18962
19200
|
try {
|
|
18963
19201
|
body = await c.req.json();
|
|
@@ -18980,6 +19218,9 @@ app49.post("/api/remote-auth/set-password", async (c) => {
|
|
|
18980
19218
|
requirements
|
|
18981
19219
|
}, 400);
|
|
18982
19220
|
}
|
|
19221
|
+
if (sessionUserId && await accessPasswordCollides(body.password, USERS_FILE, sessionUserId)) {
|
|
19222
|
+
return c.json({ error: "That password is already in use by another admin. Choose a different one." }, 400);
|
|
19223
|
+
}
|
|
18983
19224
|
try {
|
|
18984
19225
|
if (sessionUserId) {
|
|
18985
19226
|
await setAccessPassword(sessionUserId, body.password, USERS_FILE);
|
|
@@ -18993,10 +19234,10 @@ app49.post("/api/remote-auth/set-password", async (c) => {
|
|
|
18993
19234
|
return c.json({ error: "Failed to save password" }, 500);
|
|
18994
19235
|
}
|
|
18995
19236
|
});
|
|
18996
|
-
|
|
19237
|
+
app50.route("/api/_client-error", client_error_default);
|
|
18997
19238
|
console.log("[client-error-route] mounted");
|
|
18998
19239
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
18999
|
-
|
|
19240
|
+
app50.use("*", async (c, next) => {
|
|
19000
19241
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19001
19242
|
const path2 = c.req.path;
|
|
19002
19243
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || PWA_PUBLIC_PATHS.has(path2)) {
|
|
@@ -19036,17 +19277,18 @@ app49.use("*", async (c, next) => {
|
|
|
19036
19277
|
}
|
|
19037
19278
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
19038
19279
|
});
|
|
19039
|
-
|
|
19040
|
-
|
|
19041
|
-
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19280
|
+
app50.route("/api/health", health_default);
|
|
19281
|
+
app50.route("/api/chat", chatRoutes);
|
|
19282
|
+
app50.route("/api/whatsapp", whatsapp_default);
|
|
19283
|
+
app50.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
19284
|
+
app50.route("/api/public-reader", public_reader_default);
|
|
19285
|
+
app50.route("/api/webchat", createWebchatRoutes({ handleInbound: (input) => webchatGateway.handleInbound(input) }));
|
|
19286
|
+
app50.route("/api/webchat/greeting", webchat_greeting_default);
|
|
19287
|
+
app50.route("/api/telegram", telegram_default);
|
|
19288
|
+
app50.route("/api/onboarding", onboarding_default);
|
|
19289
|
+
app50.route("/api/admin", admin_default);
|
|
19290
|
+
app50.route("/api/access", access_default);
|
|
19291
|
+
app50.route("/api/session", session_default2);
|
|
19050
19292
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
19051
19293
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
19052
19294
|
var IMAGE_MIME = {
|
|
@@ -19058,7 +19300,7 @@ var IMAGE_MIME = {
|
|
|
19058
19300
|
".svg": "image/svg+xml",
|
|
19059
19301
|
".ico": "image/x-icon"
|
|
19060
19302
|
};
|
|
19061
|
-
|
|
19303
|
+
app50.get("/agent-assets/:slug/:filename", (c) => {
|
|
19062
19304
|
const slug = c.req.param("slug");
|
|
19063
19305
|
const filename = c.req.param("filename");
|
|
19064
19306
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -19074,8 +19316,8 @@ app49.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
19074
19316
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
19075
19317
|
return c.text("Not found", 404);
|
|
19076
19318
|
}
|
|
19077
|
-
const filePath =
|
|
19078
|
-
const expectedDir =
|
|
19319
|
+
const filePath = resolve31(account.accountDir, "agents", slug, "assets", filename);
|
|
19320
|
+
const expectedDir = resolve31(account.accountDir, "agents", slug, "assets");
|
|
19079
19321
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
19080
19322
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
19081
19323
|
return c.text("Forbidden", 403);
|
|
@@ -19093,7 +19335,7 @@ app49.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
19093
19335
|
"Cache-Control": "public, max-age=3600"
|
|
19094
19336
|
});
|
|
19095
19337
|
});
|
|
19096
|
-
|
|
19338
|
+
app50.get("/generated/:filename", (c) => {
|
|
19097
19339
|
const filename = c.req.param("filename");
|
|
19098
19340
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
19099
19341
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -19104,8 +19346,8 @@ app49.get("/generated/:filename", (c) => {
|
|
|
19104
19346
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
19105
19347
|
return c.text("Not found", 404);
|
|
19106
19348
|
}
|
|
19107
|
-
const filePath =
|
|
19108
|
-
const expectedDir =
|
|
19349
|
+
const filePath = resolve31(account.accountDir, "generated", filename);
|
|
19350
|
+
const expectedDir = resolve31(account.accountDir, "generated");
|
|
19109
19351
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
19110
19352
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
19111
19353
|
return c.text("Forbidden", 403);
|
|
@@ -19123,10 +19365,10 @@ app49.get("/generated/:filename", (c) => {
|
|
|
19123
19365
|
"Cache-Control": "public, max-age=86400"
|
|
19124
19366
|
});
|
|
19125
19367
|
});
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
|
|
19368
|
+
app50.route("/sites", sites_default);
|
|
19369
|
+
app50.route("/listings", listings_default);
|
|
19370
|
+
app50.route("/v", visitor_event_default);
|
|
19371
|
+
app50.route("/v", visitor_consent_default);
|
|
19130
19372
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
19131
19373
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
19132
19374
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -19148,11 +19390,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
19148
19390
|
})}</script>`;
|
|
19149
19391
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
19150
19392
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
19151
|
-
var brandIconFsPath =
|
|
19393
|
+
var brandIconFsPath = resolve31(process.cwd(), "public", brandIconPath.replace(/^\//, ""));
|
|
19152
19394
|
var brandIconExists = existsSync28(brandIconFsPath);
|
|
19153
19395
|
var SW_SOURCE = (() => {
|
|
19154
19396
|
try {
|
|
19155
|
-
return readFileSync27(
|
|
19397
|
+
return readFileSync27(resolve31(process.cwd(), "public", "sw.js"), "utf-8");
|
|
19156
19398
|
} catch {
|
|
19157
19399
|
return null;
|
|
19158
19400
|
}
|
|
@@ -19160,7 +19402,7 @@ var SW_SOURCE = (() => {
|
|
|
19160
19402
|
function readInstalledVersion() {
|
|
19161
19403
|
try {
|
|
19162
19404
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
19163
|
-
const versionFile =
|
|
19405
|
+
const versionFile = join25(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
19164
19406
|
if (!existsSync28(versionFile)) return "unknown";
|
|
19165
19407
|
const content = readFileSync27(versionFile, "utf-8").trim();
|
|
19166
19408
|
return content || "unknown";
|
|
@@ -19203,7 +19445,7 @@ var clientErrorReporterScript = `<script>
|
|
|
19203
19445
|
function cachedHtml(file) {
|
|
19204
19446
|
let html = htmlCache.get(file);
|
|
19205
19447
|
if (!html) {
|
|
19206
|
-
html = readFileSync27(
|
|
19448
|
+
html = readFileSync27(resolve31(process.cwd(), "public", file), "utf-8");
|
|
19207
19449
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
19208
19450
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
19209
19451
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -19221,11 +19463,11 @@ ${clientErrorReporterScript}
|
|
|
19221
19463
|
}
|
|
19222
19464
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
19223
19465
|
function loadBrandingCache(agentSlug) {
|
|
19224
|
-
const configDir2 =
|
|
19466
|
+
const configDir2 = join25(homedir3(), BRAND.configDir);
|
|
19225
19467
|
try {
|
|
19226
19468
|
const accountId = getDefaultAccountId();
|
|
19227
19469
|
if (!accountId) return null;
|
|
19228
|
-
const cachePath =
|
|
19470
|
+
const cachePath = join25(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
19229
19471
|
if (!existsSync28(cachePath)) return null;
|
|
19230
19472
|
return JSON.parse(readFileSync27(cachePath, "utf-8"));
|
|
19231
19473
|
} catch {
|
|
@@ -19237,6 +19479,9 @@ function resolveDefaultSlug() {
|
|
|
19237
19479
|
if (!account) return null;
|
|
19238
19480
|
return resolveDefaultAgentSlug(account.accountDir);
|
|
19239
19481
|
}
|
|
19482
|
+
function wantsNextSurface(c) {
|
|
19483
|
+
return c.req.query("surface") === "next";
|
|
19484
|
+
}
|
|
19240
19485
|
function brandedPublicHtml(agentSlug) {
|
|
19241
19486
|
const baseHtml = cachedHtml("public.html");
|
|
19242
19487
|
if (!agentSlug) return baseHtml;
|
|
@@ -19270,7 +19515,7 @@ function escapeHtml(s) {
|
|
|
19270
19515
|
function agentUnavailableHtml() {
|
|
19271
19516
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
|
|
19272
19517
|
}
|
|
19273
|
-
|
|
19518
|
+
app50.get("/", (c) => {
|
|
19274
19519
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19275
19520
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
19276
19521
|
if (klass === "operator") {
|
|
@@ -19287,19 +19532,22 @@ app49.get("/", (c) => {
|
|
|
19287
19532
|
);
|
|
19288
19533
|
}
|
|
19289
19534
|
console.error(`[public-root] op=serve-default slug=${defaultSlug}`);
|
|
19535
|
+
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19290
19536
|
return c.html(brandedPublicHtml(defaultSlug));
|
|
19291
19537
|
}
|
|
19292
19538
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
19293
19539
|
return c.html(cachedHtml("index.html"));
|
|
19294
19540
|
});
|
|
19295
|
-
|
|
19541
|
+
app50.get("/public", (c) => {
|
|
19296
19542
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19297
19543
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19544
|
+
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19298
19545
|
return c.html(cachedHtml("public.html"));
|
|
19299
19546
|
});
|
|
19300
|
-
|
|
19547
|
+
app50.get("/public-chat", (c) => {
|
|
19301
19548
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19302
19549
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19550
|
+
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19303
19551
|
return c.html(cachedHtml("public.html"));
|
|
19304
19552
|
});
|
|
19305
19553
|
async function logViewerFetch(c, next) {
|
|
@@ -19316,12 +19564,12 @@ async function logViewerFetch(c, next) {
|
|
|
19316
19564
|
duration_ms: Date.now() - start
|
|
19317
19565
|
});
|
|
19318
19566
|
}
|
|
19319
|
-
|
|
19320
|
-
|
|
19321
|
-
|
|
19567
|
+
app50.use("/vnc-viewer.html", logViewerFetch);
|
|
19568
|
+
app50.use("/vnc-popout.html", logViewerFetch);
|
|
19569
|
+
app50.get("/vnc-popout.html", (c) => {
|
|
19322
19570
|
let html = htmlCache.get("vnc-popout.html");
|
|
19323
19571
|
if (!html) {
|
|
19324
|
-
html = readFileSync27(
|
|
19572
|
+
html = readFileSync27(resolve31(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
19325
19573
|
const name = escapeHtml(BRAND.productName);
|
|
19326
19574
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
19327
19575
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -19331,7 +19579,7 @@ app49.get("/vnc-popout.html", (c) => {
|
|
|
19331
19579
|
}
|
|
19332
19580
|
return c.html(html);
|
|
19333
19581
|
});
|
|
19334
|
-
|
|
19582
|
+
app50.post("/api/vnc/client-event", async (c) => {
|
|
19335
19583
|
let body;
|
|
19336
19584
|
try {
|
|
19337
19585
|
body = await c.req.json();
|
|
@@ -19352,11 +19600,11 @@ app49.post("/api/vnc/client-event", async (c) => {
|
|
|
19352
19600
|
});
|
|
19353
19601
|
return c.json({ ok: true });
|
|
19354
19602
|
});
|
|
19355
|
-
|
|
19603
|
+
app50.get("/g/:slug", (c) => {
|
|
19356
19604
|
return c.html(brandedPublicHtml());
|
|
19357
19605
|
});
|
|
19358
19606
|
for (const pwa of PWA_SURFACES) {
|
|
19359
|
-
|
|
19607
|
+
app50.get(pwa.manifestPath, (c) => {
|
|
19360
19608
|
const manifest = buildManifest(pwa, {
|
|
19361
19609
|
productName: BRAND.productName,
|
|
19362
19610
|
iconPath: brandIconPath,
|
|
@@ -19370,7 +19618,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
19370
19618
|
return c.body(JSON.stringify(manifest));
|
|
19371
19619
|
});
|
|
19372
19620
|
}
|
|
19373
|
-
|
|
19621
|
+
app50.get("/sw.js", (c) => {
|
|
19374
19622
|
if (SW_SOURCE == null) {
|
|
19375
19623
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
19376
19624
|
return c.text("Service worker unavailable", 500);
|
|
@@ -19379,27 +19627,27 @@ app49.get("/sw.js", (c) => {
|
|
|
19379
19627
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
19380
19628
|
return c.body(SW_SOURCE);
|
|
19381
19629
|
});
|
|
19382
|
-
|
|
19630
|
+
app50.get("/graph", (c) => {
|
|
19383
19631
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19384
19632
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19385
19633
|
return c.html(cachedHtml("graph.html"));
|
|
19386
19634
|
});
|
|
19387
|
-
|
|
19635
|
+
app50.get("/chat", (c) => {
|
|
19388
19636
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19389
19637
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19390
19638
|
return c.html(cachedHtml("chat.html"));
|
|
19391
19639
|
});
|
|
19392
|
-
|
|
19640
|
+
app50.get("/data", (c) => {
|
|
19393
19641
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19394
19642
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19395
19643
|
return c.html(cachedHtml("data.html"));
|
|
19396
19644
|
});
|
|
19397
|
-
|
|
19645
|
+
app50.get("/browser", (c) => {
|
|
19398
19646
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19399
19647
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19400
19648
|
return c.html(cachedHtml("browser.html"));
|
|
19401
19649
|
});
|
|
19402
|
-
|
|
19650
|
+
app50.get("/:slug", async (c, next) => {
|
|
19403
19651
|
const slug = c.req.param("slug");
|
|
19404
19652
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
19405
19653
|
const account = resolveAccount();
|
|
@@ -19409,18 +19657,19 @@ app49.get("/:slug", async (c, next) => {
|
|
|
19409
19657
|
}
|
|
19410
19658
|
const branding = loadBrandingCache(slug);
|
|
19411
19659
|
console.error(`[public-catchall] served path=/${slug} slug=${slug} branding=${branding ? "hit" : "miss"}`);
|
|
19660
|
+
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19412
19661
|
return c.html(brandedPublicHtml(slug));
|
|
19413
19662
|
}
|
|
19414
19663
|
await next();
|
|
19415
19664
|
});
|
|
19416
19665
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
19417
|
-
|
|
19666
|
+
app50.get("/favicon.ico", (c) => {
|
|
19418
19667
|
c.header("Cache-Control", "public, max-age=300");
|
|
19419
19668
|
return c.redirect(brandFaviconPath, 302);
|
|
19420
19669
|
});
|
|
19421
19670
|
}
|
|
19422
|
-
|
|
19423
|
-
|
|
19671
|
+
app50.use("/*", serveStatic({ root: "./public" }));
|
|
19672
|
+
app50.all("*", (c) => {
|
|
19424
19673
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19425
19674
|
const path2 = c.req.path;
|
|
19426
19675
|
if (isPublicHost(host)) {
|
|
@@ -19434,7 +19683,7 @@ app49.all("*", (c) => {
|
|
|
19434
19683
|
});
|
|
19435
19684
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
19436
19685
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
19437
|
-
var httpServer = serve({ fetch:
|
|
19686
|
+
var httpServer = serve({ fetch: app50.fetch, port, hostname });
|
|
19438
19687
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
19439
19688
|
{
|
|
19440
19689
|
const census = pwaCensus({
|
|
@@ -19488,7 +19737,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
19488
19737
|
}
|
|
19489
19738
|
try {
|
|
19490
19739
|
const registered = [];
|
|
19491
|
-
for (const r of
|
|
19740
|
+
for (const r of app50.routes ?? []) {
|
|
19492
19741
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
19493
19742
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
19494
19743
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -19583,7 +19832,7 @@ try {
|
|
|
19583
19832
|
} catch (err) {
|
|
19584
19833
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
19585
19834
|
}
|
|
19586
|
-
var configDirForWhatsApp =
|
|
19835
|
+
var configDirForWhatsApp = basename9(MAXY_DIR) || ".maxy";
|
|
19587
19836
|
var bootAccount = resolveAccount();
|
|
19588
19837
|
if (bootAccount) {
|
|
19589
19838
|
migrateRemovedConfigKeys(bootAccount.accountDir);
|
|
@@ -19645,7 +19894,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
19645
19894
|
}
|
|
19646
19895
|
init({
|
|
19647
19896
|
configDir: configDirForWhatsApp,
|
|
19648
|
-
platformRoot:
|
|
19897
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join25(__dirname, "..")),
|
|
19649
19898
|
accountConfig: bootAccountConfig,
|
|
19650
19899
|
onMessage: async (msg) => {
|
|
19651
19900
|
if (msg.isOwnerMirror) {
|