@rubytech/create-maxy-code 0.1.315 → 0.1.317
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/payload/platform/lib/mcp-eager/dist/index.d.ts +0 -20
- package/payload/platform/lib/mcp-eager/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/mcp-eager/dist/index.js +2 -1
- package/payload/platform/lib/mcp-eager/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-eager/src/index.ts +3 -1
- package/payload/platform/lib/mcp-lifeline/dist/index.d.ts +8 -0
- package/payload/platform/lib/mcp-lifeline/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/mcp-lifeline/dist/index.js +71 -0
- package/payload/platform/lib/mcp-lifeline/dist/index.js.map +1 -0
- package/payload/platform/lib/mcp-lifeline/package.json +7 -0
- package/payload/platform/lib/mcp-lifeline/src/__tests__/lifeline.test.ts +146 -0
- package/payload/platform/lib/mcp-lifeline/src/index.ts +78 -0
- package/payload/platform/lib/mcp-lifeline/tsconfig.json +9 -0
- package/payload/platform/lib/mcp-lifeline/vitest.config.ts +9 -0
- package/payload/platform/lib/models/dist/index.d.ts +8 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +20 -1
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +22 -0
- package/payload/platform/package.json +5 -2
- package/payload/platform/plugins/admin/mcp/dist/index.js +11 -10
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +20 -11
- package/payload/platform/plugins/docs/references/admin-session.md +1 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +5 -3
- package/payload/platform/plugins/docs/references/internals.md +14 -7
- package/payload/platform/plugins/memory/mcp/dist/index.js +32 -31
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/references/schema-estate-agent.md +32 -0
- package/payload/platform/plugins/outlook/mcp/dist/index.js +8 -7
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/quickbooks/mcp/dist/index.js +12 -11
- package/payload/platform/plugins/quickbooks/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/replicate/mcp/dist/index.js +4 -3
- package/payload/platform/plugins/replicate/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +11 -10
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/scripts/__tests__/check-no-raw-mcp-registrations.test.sh +57 -0
- package/payload/platform/scripts/check-no-raw-mcp-registrations.mjs +70 -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 +71 -14
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +3 -12
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +8 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +9 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +15 -0
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/permission.d.ts +46 -0
- package/payload/platform/services/webchat-channel/dist/permission.d.ts.map +1 -0
- package/payload/platform/services/webchat-channel/dist/permission.js +56 -0
- package/payload/platform/services/webchat-channel/dist/permission.js.map +1 -0
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +47 -1
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/templates/specialists/agents/data-manager.md +3 -1
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.d.ts +8 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.d.ts.map +1 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.js +71 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.js.map +1 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/package.json +7 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js +6 -5
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/src/index.ts +6 -5
- package/payload/server/{chunk-Q7EWROVN.js → chunk-NCRJQEZ3.js} +0 -101
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AdminLoginScreens-CrdmA3KA.js +1 -0
- package/payload/server/public/assets/AdminShell-0meAFBva.js +1 -0
- package/payload/server/public/assets/Checkbox-DXisJRUK.js +1 -0
- package/payload/server/public/assets/OperatorConversations-DBy2G8q3.js +9 -0
- package/payload/server/public/assets/OperatorConversations-DvRXfq3q.css +1 -0
- package/payload/server/public/assets/admin-DX5lZxWt.js +1 -0
- package/payload/server/public/assets/{arc-J2g2u5Xv.js → arc-CxLB9WCE.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-DN-MYxff.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-CN0BXxpE.js → architectureDiagram-Q4EWVU46-D-EdJPSY.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-HX-8wF2p.js → blockDiagram-DXYQGD6D-CXx9RgCm.js} +1 -1
- package/payload/server/public/assets/browser-Bxx8w8BA.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-wIuarKF5.js → c4Diagram-AHTNJAMY-RFBXEe0B.js} +1 -1
- package/payload/server/public/assets/channel-y27xl53N.js +1 -0
- package/payload/server/public/assets/chat-CT9YrNtI.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-Buz7egJZ.js → chunk-2KRD3SAO-DBqAFwK9.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-_JcFXJqc.js → chunk-336JU56O-DdnFEz6R.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-D8Iwaegm.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-DUR5Dg3M.js → chunk-4BX2VUAB-cnw-3Gbs.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BRIqQ9st.js → chunk-4TB4RGXK-BnqJ0bDc.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-CezTHWXL.js → chunk-55IACEB6-BwyHvvzo.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-DHYUPzF1.js → chunk-5FUZZQ4R-DXA9U02I.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BVn4_fI5.js → chunk-5PVQY5BW-D78bZ_8D.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-BBLA8Mbi.js → chunk-67CJDMHE-CtE_Mgv7.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-CdWfEI5c.js → chunk-7N4EOEYR-CUZDaySl.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-tS11knCR.js → chunk-AA7GKIK3-CYQ3jO4X.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-GEu1OOZ6.js → chunk-BSJP7CBP-BbA_HyTR.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-DKrNbbp_.js → chunk-CIAEETIT-D7_YqRhG.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-B0InXNyr.js → chunk-EDXVE4YY-B23LrtSw.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CO7lkHdm.js → chunk-ENJZ2VHE-D3fTHYKN.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-CMj74lWo.js → chunk-FMBD7UC4-DFAA2tyh.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-CLnKQoXw.js → chunk-FOC6F5B3-BF4IHvlI.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-CdiEKIaz.js → chunk-ICPOFSXX-DBUGemHy.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-B6LA3fiv.js → chunk-K5T4RW27-rMMs08Eh.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-DrhRrb8Q.js → chunk-KGLVRYIC-BD2r8R2G.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-DVQukevB.js → chunk-LIHQZDEY-D4sYTTwM.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-ZMLkoDhP.js → chunk-ORNJ4GCN-CAs_uFzb.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-C0dJkynG.js → chunk-OYMX7WX6-Fkp-2ORc.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-qHqDpwz3.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-BQ9BPIFZ.js → chunk-U2HBQHQK-D_pxZh25.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-CAonGMOd.js → chunk-X2U36JSP-CeVmvvRf.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-D5C_WNlk.js → chunk-XPW4576I-iWP54fKp.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Ecdvzekb.js → chunk-YZCP3GAM-CNtbWJNN.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BsFZd1cN.js → chunk-ZZ45TVLE-BmlFjU_9.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DgVoYWhO.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-C0WNP3uN.js +1 -0
- package/payload/server/public/assets/clone-D50F_pvg.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-DBWHaIwm.js → cose-bilkent-S5V4N54A-C7YmF1Pg.js} +1 -1
- package/payload/server/public/assets/{dagre-Dr7ZJYeS.js → dagre-BAmiDDtR.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-oIJddk7m.js → dagre-KV5264BT-Ca3ESJhc.js} +1 -1
- package/payload/server/public/assets/data-B9NtsXgF.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-CEVxqOZ4.js → diagram-5BDNPKRD-BgT1ORf2.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BovF7Rjx.js → diagram-G4DWMVQ6-BTaUIiem.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-BhrF8zoF.js → diagram-MMDJMWI5-Bdb2g6Uo.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-DCUYwxtR.js → diagram-TYMM5635-CkLGC0zZ.js} +1 -1
- package/payload/server/public/assets/{dist-DSsFp0Qd.js → dist-Bkbhs3jw.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-BS2-HdCg.js → erDiagram-SMLLAGMA-D_sj4DMg.js} +1 -1
- package/payload/server/public/assets/{flatten-BZMXCpLh.js → flatten-E2Sr0FeD.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BzSFLoea.js → flowDiagram-DWJPFMVM-iLERoZTe.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-1-3QU7mT.js → ganttDiagram-T4ZO3ILL-D60hjMBy.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-D-L2yzYf.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-fTrJ35Wk.js → gitGraphDiagram-UUTBAWPF-Di0XM6fi.js} +1 -1
- package/payload/server/public/assets/{graph-Dx2a6vGB.js → graph-B59N222f.js} +3 -3
- package/payload/server/public/assets/graph-labels-70w-1ov0.js +1 -0
- package/payload/server/public/assets/{graphlib-rlEzI2qD.js → graphlib-C8fUP7uV.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-BQn6jndO.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-BwMdbiXg.js +2 -0
- package/payload/server/public/assets/{isEmpty-DaYIrHay.js → isEmpty-CLz-UprQ.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-0eU_UtlT.js → ishikawaDiagram-UXIWVN3A-CwgI4B5Z.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-BKLeZohp.js → journeyDiagram-VCZTEJTY-CxBu-tze.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Dq72xyaN.js → kanban-definition-6JOO6SKY-D2qlheA5.js} +1 -1
- package/payload/server/public/assets/{line-LQhmDT8k.js → line-Bdod7uzQ.js} +1 -1
- package/payload/server/public/assets/{linear-BGotDbGs.js → linear-BiVe6QzC.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-DoLdho1V.js → mermaid-parser.core-xZN7hC6M.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-C1RRyHGm.js → mermaid.core-D0IylAac.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-vUVVVyV1.js → mindmap-definition-QFDTVHPH-J_Szhwf1.js} +1 -1
- package/payload/server/public/assets/operator-DpRAhwQN.js +1 -0
- package/payload/server/public/assets/{ordinal-BqEhkPyh.js → ordinal-5RtyPJVt.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-DmkQBx4h.js +1 -0
- package/payload/server/public/assets/page-Ehjc9b9V.js +30 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-DDnxYUBm.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-B9Pl6Qhc.js → pieDiagram-DEJITSTG-CV5DxUVx.js} +1 -1
- package/payload/server/public/assets/public-BcqXGSaE.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-Drn9T81A.js → quadrantDiagram-34T5L4WZ-BsFMVizF.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-7H4k0ChM.js +1 -0
- package/payload/server/public/assets/{reduce-T2IuntYP.js → reduce-B3Mw_0s1.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-C0PAItJm.js → requirementDiagram-MS252O5E-C5eRRvGc.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BR42Mtwd.js → sankeyDiagram-XADWPNL6-CJYv5gpw.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-c2lR9UOS.js → sequenceDiagram-FGHM5R23-B25563_2.js} +1 -1
- package/payload/server/public/assets/{src-DXUM2BJo.js → src-BKOAoFQc.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-BcHhtqsZ.js → stateDiagram-FHFEXIEX-BLyNJYOA.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BSVuxZxz.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-Ax32c10H.js → timeline-definition-GMOUNBTQ-D-HgOM6Q.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BLXWTQtW.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-DiePDF5d.js +1 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BxePewPq.js → vennDiagram-DHZGUBPP-Cw1JElYp.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-OSUWK5LN.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DmJwZ2f5.js → wardleyDiagram-NUSXRM2D-BqMWzEko.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-YjHomudv.js → xychartDiagram-5P7HB3ND-DBp71TLT.js} +1 -1
- package/payload/server/public/browser.html +5 -8
- package/payload/server/public/chat.html +8 -12
- package/payload/server/public/data.html +5 -7
- package/payload/server/public/graph.html +7 -10
- package/payload/server/public/index.html +8 -11
- package/payload/server/public/operator.html +10 -14
- package/payload/server/public/public.html +8 -10
- package/payload/server/server.js +376 -226
- package/payload/server/public/assets/AccessGate-B0sCa0QJ.js +0 -1
- package/payload/server/public/assets/AdminLoginScreens-C7Oaqpr6.js +0 -1
- package/payload/server/public/assets/AdminShell-DgK7TWCI.js +0 -1
- package/payload/server/public/assets/Checkbox-C4m1jfdP.js +0 -1
- package/payload/server/public/assets/OperatorConversations-qc_xy7Az.css +0 -1
- package/payload/server/public/assets/OperatorConversations-z2mSY_eQ.js +0 -1
- package/payload/server/public/assets/admin-DxYk1Ghu.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-C6nkAxzW.js +0 -1
- package/payload/server/public/assets/audio-attachment-mime-BXj3DB3Y.js +0 -30
- package/payload/server/public/assets/brand-BwWvCHLs.css +0 -1
- package/payload/server/public/assets/brand-DOgCGEoD.js +0 -9
- package/payload/server/public/assets/browser-NzxOujfD.js +0 -1
- package/payload/server/public/assets/channel-Q39xIXyT.js +0 -1
- package/payload/server/public/assets/chat-CEQTEN5z.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-CCYjp9C2.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-BNBxnHZh.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BShusfby.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D4ivPLFF.js +0 -1
- package/payload/server/public/assets/clone-CjEM8LwB.js +0 -1
- package/payload/server/public/assets/data-CTROHvif.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-Btp3PwZh.js +0 -1
- package/payload/server/public/assets/graph-labels-Dxqq08v6.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-CPt2y6_L.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CpXNTMgd.js +0 -2
- package/payload/server/public/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- package/payload/server/public/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- package/payload/server/public/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- package/payload/server/public/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- package/payload/server/public/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- package/payload/server/public/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- package/payload/server/public/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- package/payload/server/public/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- package/payload/server/public/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- package/payload/server/public/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/payload/server/public/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/payload/server/public/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- package/payload/server/public/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- package/payload/server/public/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- package/payload/server/public/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- package/payload/server/public/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- package/payload/server/public/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- package/payload/server/public/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-300-normal-AOSWdb_s.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-300-normal-FGBQ0wlI.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-400-normal-BFBkh4jY.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-400-normal-gRTjlS2D.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-500-normal-B66TYsaK.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-500-normal-DFwuUcdu.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-300-normal-CFtw49Zd.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-300-normal-DRMzurxT.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-400-normal-DYA1XoQK.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-400-normal-svq1FPys.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-500-normal-BNHmvKvI.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-500-normal-CZruMFou.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-300-normal-CsrIkm-V.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-300-normal-D3VHEe81.woff2 +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-400-normal-BekUZro8.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-400-normal-DdKr49mV.woff2 +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-500-normal-BEAbKU8A.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-500-normal-CL6a8tp2.woff2 +0 -0
- package/payload/server/public/assets/operator-BTHMTwNI.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Cwc-j_AI.js +0 -1
- package/payload/server/public/assets/page-B9fQp1g9.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BZ9fjD1_.js +0 -1
- package/payload/server/public/assets/public-cuggl7du.js +0 -6
- package/payload/server/public/assets/public-next-apqAebbA.js +0 -1
- package/payload/server/public/assets/public-vnj7OhQj.css +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-BNz5Rt9V.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BUQ_F4eP.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-DcVCQgp1.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-Bm12mwGd.js +0 -1
- package/payload/server/public/assets/useSelectionMode-DlgEcMtA.js +0 -5
- package/payload/server/public/assets/wardley-RL74JXVD-47Z3ymtK.js +0 -1
- package/payload/server/public/public-next.html +0 -25
- /package/payload/server/public/assets/{_baseFor-Y5mTRiRv.js → _baseFor-DVaNaTfF.js} +0 -0
- /package/payload/server/public/assets/{admin-types-D2qTXuCg.js → admin-types-CJrGd46U.js} +0 -0
- /package/payload/server/public/assets/{array-BwJyW1Dp.js → array-8_H1156C.js} +0 -0
- /package/payload/server/public/assets/{chunk-CAM3fms7.js → chunk-Pqm5yXtL.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-D95TtHqz.js → cytoscape.esm-h10p_6j-.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-kiwRz9Au.js → defaultLocale-pD7tFa1r.js} +0 -0
- /package/payload/server/public/assets/{init-CKZirZ49.js → init-CwJ4b81e.js} +0 -0
- /package/payload/server/public/assets/{katex-8mXVa4k3.js → katex-DJPjIBAI.js} +0 -0
- /package/payload/server/public/assets/{path-B0d9ncVi.js → path-CK8wrAxY.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-C5gCWwwF.js → preload-helper-Bf_JiD2A.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-BWqoIFNR.js → rough.esm-Dwml_la6.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -27,9 +27,7 @@ import {
|
|
|
27
27
|
WEBSOCKIFY_PORT,
|
|
28
28
|
accessPasswordCollides,
|
|
29
29
|
autoDeliverPremiumPlugins,
|
|
30
|
-
bindVisitorToGroup,
|
|
31
30
|
canAccessAdmin,
|
|
32
|
-
checkGroupMembership,
|
|
33
31
|
checkRateLimit,
|
|
34
32
|
classifyHost,
|
|
35
33
|
cleanupLeakedPremiumSubs,
|
|
@@ -42,7 +40,6 @@ import {
|
|
|
42
40
|
emitMissingOnResolve,
|
|
43
41
|
ensureConversation,
|
|
44
42
|
fetchBranding,
|
|
45
|
-
findGroupBySlug,
|
|
46
43
|
findMissingPlugins,
|
|
47
44
|
findRecentConversation,
|
|
48
45
|
fingerprintSessionKey,
|
|
@@ -50,7 +47,6 @@ import {
|
|
|
50
47
|
getAgentSessionIdForConversation,
|
|
51
48
|
getConversationClaudeSessionIds,
|
|
52
49
|
getDefaultAccountId,
|
|
53
|
-
getGroupParticipants,
|
|
54
50
|
getOperatorDomains,
|
|
55
51
|
getRecentMessages,
|
|
56
52
|
getRoleForSession,
|
|
@@ -110,7 +106,7 @@ import {
|
|
|
110
106
|
vncLog,
|
|
111
107
|
walkPremiumBundles,
|
|
112
108
|
writeAdminUserAndPerson
|
|
113
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-NCRJQEZ3.js";
|
|
114
110
|
import {
|
|
115
111
|
__commonJS,
|
|
116
112
|
__toESM
|
|
@@ -532,63 +528,63 @@ var require_dist2 = __commonJS({
|
|
|
532
528
|
}
|
|
533
529
|
function pickShortLabel(node) {
|
|
534
530
|
const props = node.properties;
|
|
535
|
-
const
|
|
536
|
-
if (
|
|
531
|
+
const primaryLabel2 = node.labels[0];
|
|
532
|
+
if (primaryLabel2 === "ToolCall") {
|
|
537
533
|
const v = props.toolName;
|
|
538
534
|
if (typeof v === "string" && v.length > 0) {
|
|
539
535
|
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
540
536
|
}
|
|
541
|
-
} else if (
|
|
537
|
+
} else if (primaryLabel2 === "WorkflowRun") {
|
|
542
538
|
const v = props.startedAt;
|
|
543
539
|
if (typeof v === "string" && v.length > 0) {
|
|
544
540
|
const ts = formatRunTimestamp(v);
|
|
545
541
|
if (ts)
|
|
546
542
|
return ts;
|
|
547
543
|
}
|
|
548
|
-
} else if (
|
|
544
|
+
} else if (primaryLabel2 === "WorkflowStep") {
|
|
549
545
|
const v = props.label;
|
|
550
546
|
if (typeof v === "string" && v.length > 0) {
|
|
551
547
|
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
552
548
|
}
|
|
553
|
-
} else if (
|
|
549
|
+
} else if (primaryLabel2 === "Person") {
|
|
554
550
|
const given = typeof props.givenName === "string" ? props.givenName : "";
|
|
555
551
|
const family = typeof props.familyName === "string" ? props.familyName : "";
|
|
556
552
|
const full = [given, family].filter((s) => s.length > 0).join(" ");
|
|
557
553
|
if (full.length > 0) {
|
|
558
554
|
return full.length > 24 ? full.slice(0, 24) + "\u2026" : full;
|
|
559
555
|
}
|
|
560
|
-
} else if (
|
|
556
|
+
} else if (primaryLabel2 === "Agent") {
|
|
561
557
|
const dn = typeof props.displayName === "string" ? props.displayName : "";
|
|
562
558
|
const slug = typeof props.slug === "string" ? props.slug : "";
|
|
563
559
|
const v = dn.length > 0 ? dn : slug;
|
|
564
560
|
if (v.length > 0) {
|
|
565
561
|
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
566
562
|
}
|
|
567
|
-
} else if (
|
|
563
|
+
} else if (primaryLabel2 === "Job") {
|
|
568
564
|
const client = typeof props.client === "string" ? props.client : "";
|
|
569
565
|
const jobId = typeof props.jobId === "string" ? props.jobId : "";
|
|
570
566
|
const composed = [client, jobId.length > 0 ? `#${jobId}` : ""].filter((s) => s.length > 0).join(" ");
|
|
571
567
|
if (composed.length > 0) {
|
|
572
568
|
return composed.length > 24 ? composed.slice(0, 24) + "\u2026" : composed;
|
|
573
569
|
}
|
|
574
|
-
} else if (
|
|
570
|
+
} else if (primaryLabel2 === "QuoteDocument") {
|
|
575
571
|
const ref = typeof props.ref === "string" ? props.ref : "";
|
|
576
572
|
if (ref.length > 0) {
|
|
577
573
|
return ref.length > 24 ? ref.slice(0, 24) + "\u2026" : ref;
|
|
578
574
|
}
|
|
579
|
-
} else if (
|
|
575
|
+
} else if (primaryLabel2 === "InboundInvoice") {
|
|
580
576
|
const supplier = typeof props.supplier === "string" ? props.supplier : "";
|
|
581
577
|
const conf = typeof props.confirmationNumber === "string" ? props.confirmationNumber : "";
|
|
582
578
|
const composed = [supplier, conf.length > 0 ? `#${conf}` : ""].filter((s) => s.length > 0).join(" ");
|
|
583
579
|
if (composed.length > 0) {
|
|
584
580
|
return composed.length > 24 ? composed.slice(0, 24) + "\u2026" : composed;
|
|
585
581
|
}
|
|
586
|
-
} else if (
|
|
582
|
+
} else if (primaryLabel2 === "WhatsAppGroup") {
|
|
587
583
|
const clientName = typeof props.clientName === "string" ? props.clientName : "";
|
|
588
584
|
if (clientName.length > 0) {
|
|
589
585
|
return clientName.length > 24 ? clientName.slice(0, 24) + "\u2026" : clientName;
|
|
590
586
|
}
|
|
591
|
-
} else if (
|
|
587
|
+
} else if (primaryLabel2 === "Message") {
|
|
592
588
|
const role = typeof props.role === "string" ? props.role : "";
|
|
593
589
|
const roleShort = role === "user" ? "user" : role === "assistant" ? "asst" : role === "system" ? "sys" : role === "tool" ? "tool" : null;
|
|
594
590
|
const createdAt = typeof props.createdAt === "string" ? props.createdAt : "";
|
|
@@ -604,60 +600,60 @@ var require_dist2 = __commonJS({
|
|
|
604
600
|
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
605
601
|
}
|
|
606
602
|
}
|
|
607
|
-
if (
|
|
603
|
+
if (primaryLabel2 === "Conversation") {
|
|
608
604
|
const id = typeof props.sessionId === "string" ? props.sessionId : null;
|
|
609
605
|
if (id)
|
|
610
606
|
return `Conv ${id.slice(0, 8)}`;
|
|
611
607
|
}
|
|
612
|
-
return
|
|
608
|
+
return primaryLabel2 ?? "\u2026";
|
|
613
609
|
}
|
|
614
610
|
function pickDisplayName(node) {
|
|
615
611
|
const props = node.properties;
|
|
616
|
-
const
|
|
617
|
-
if (
|
|
612
|
+
const primaryLabel2 = node.labels[0];
|
|
613
|
+
if (primaryLabel2 === "ToolCall") {
|
|
618
614
|
const v = props.toolName;
|
|
619
615
|
if (typeof v === "string" && v.length > 0)
|
|
620
616
|
return v;
|
|
621
|
-
} else if (
|
|
617
|
+
} else if (primaryLabel2 === "WorkflowRun") {
|
|
622
618
|
const v = props.startedAt;
|
|
623
619
|
if (typeof v === "string" && v.length > 0) {
|
|
624
620
|
const ts = formatRunTimestamp(v);
|
|
625
621
|
if (ts)
|
|
626
622
|
return ts;
|
|
627
623
|
}
|
|
628
|
-
} else if (
|
|
624
|
+
} else if (primaryLabel2 === "WorkflowStep") {
|
|
629
625
|
const v = props.label;
|
|
630
626
|
if (typeof v === "string" && v.length > 0)
|
|
631
627
|
return v;
|
|
632
|
-
} else if (
|
|
628
|
+
} else if (primaryLabel2 === "Person") {
|
|
633
629
|
const given = typeof props.givenName === "string" ? props.givenName : "";
|
|
634
630
|
const family = typeof props.familyName === "string" ? props.familyName : "";
|
|
635
631
|
const full = [given, family].filter((s) => s.length > 0).join(" ");
|
|
636
632
|
if (full.length > 0)
|
|
637
633
|
return full;
|
|
638
|
-
} else if (
|
|
634
|
+
} else if (primaryLabel2 === "Agent") {
|
|
639
635
|
const dn = typeof props.displayName === "string" ? props.displayName : "";
|
|
640
636
|
const slug = typeof props.slug === "string" ? props.slug : "";
|
|
641
637
|
const v = dn.length > 0 ? dn : slug;
|
|
642
638
|
if (v.length > 0)
|
|
643
639
|
return v;
|
|
644
|
-
} else if (
|
|
640
|
+
} else if (primaryLabel2 === "Job") {
|
|
645
641
|
const client = typeof props.client === "string" ? props.client : "";
|
|
646
642
|
const jobId = typeof props.jobId === "string" ? props.jobId : "";
|
|
647
643
|
const composed = [client, jobId.length > 0 ? `#${jobId}` : ""].filter((s) => s.length > 0).join(" ");
|
|
648
644
|
if (composed.length > 0)
|
|
649
645
|
return composed;
|
|
650
|
-
} else if (
|
|
646
|
+
} else if (primaryLabel2 === "QuoteDocument") {
|
|
651
647
|
const ref = typeof props.ref === "string" ? props.ref : "";
|
|
652
648
|
if (ref.length > 0)
|
|
653
649
|
return ref;
|
|
654
|
-
} else if (
|
|
650
|
+
} else if (primaryLabel2 === "InboundInvoice") {
|
|
655
651
|
const supplier = typeof props.supplier === "string" ? props.supplier : "";
|
|
656
652
|
const conf = typeof props.confirmationNumber === "string" ? props.confirmationNumber : "";
|
|
657
653
|
const composed = [supplier, conf.length > 0 ? `#${conf}` : ""].filter((s) => s.length > 0).join(" ");
|
|
658
654
|
if (composed.length > 0)
|
|
659
655
|
return composed;
|
|
660
|
-
} else if (
|
|
656
|
+
} else if (primaryLabel2 === "WhatsAppGroup") {
|
|
661
657
|
const clientName = typeof props.clientName === "string" ? props.clientName : "";
|
|
662
658
|
if (clientName.length > 0)
|
|
663
659
|
return clientName;
|
|
@@ -667,12 +663,12 @@ var require_dist2 = __commonJS({
|
|
|
667
663
|
if (typeof v === "string" && v.length > 0)
|
|
668
664
|
return v;
|
|
669
665
|
}
|
|
670
|
-
if (
|
|
666
|
+
if (primaryLabel2 === "Conversation") {
|
|
671
667
|
const id = typeof props.sessionId === "string" ? props.sessionId : null;
|
|
672
668
|
if (id)
|
|
673
669
|
return `Conv ${id.slice(0, 8)}`;
|
|
674
670
|
}
|
|
675
|
-
return
|
|
671
|
+
return primaryLabel2 ?? "\u2026";
|
|
676
672
|
}
|
|
677
673
|
}
|
|
678
674
|
});
|
|
@@ -6891,7 +6887,6 @@ function resolveTitle(body, sessionId, userTitles) {
|
|
|
6891
6887
|
const channel = stripped.channel;
|
|
6892
6888
|
if (userTitle) return { title: trimToTitle(userTitle), source: "user", channel };
|
|
6893
6889
|
if (aiTitle) return { title: trimToTitle(aiTitle), source: "ai", channel };
|
|
6894
|
-
if (stripped.inner) return { title: trimToTitle(stripped.inner), source: "first-message", channel };
|
|
6895
6890
|
return { title: sessionId.slice(0, 8), source: "prefix", channel };
|
|
6896
6891
|
}
|
|
6897
6892
|
app3.get("/", requireAdminSession, async (c) => {
|
|
@@ -6971,7 +6966,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6971
6966
|
if (accountId) {
|
|
6972
6967
|
await Promise.all(
|
|
6973
6968
|
rows.map(async (row) => {
|
|
6974
|
-
if (row.titleSource !== "
|
|
6969
|
+
if (row.titleSource !== "prefix") return;
|
|
6975
6970
|
const pid = personIdBySession.get(row.sessionId);
|
|
6976
6971
|
if (pid) {
|
|
6977
6972
|
const name = await loadPersonNameByElementId(accountId, pid);
|
|
@@ -7954,18 +7949,37 @@ var UUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-f
|
|
|
7954
7949
|
function canonicalOverridePath(accountDir) {
|
|
7955
7950
|
return join13(accountDir, FILE);
|
|
7956
7951
|
}
|
|
7957
|
-
function
|
|
7952
|
+
function readRaw(accountDir) {
|
|
7958
7953
|
try {
|
|
7959
|
-
|
|
7960
|
-
return typeof raw.sessionId === "string" && UUID.test(raw.sessionId) ? raw.sessionId : null;
|
|
7954
|
+
return JSON.parse(readFileSync14(canonicalOverridePath(accountDir), "utf8"));
|
|
7961
7955
|
} catch {
|
|
7962
7956
|
return null;
|
|
7963
7957
|
}
|
|
7964
7958
|
}
|
|
7965
|
-
function
|
|
7959
|
+
function readCanonicalOverrideId(accountDir, userId, primaryUserId) {
|
|
7960
|
+
const raw = readRaw(accountDir);
|
|
7961
|
+
if (!raw) return null;
|
|
7962
|
+
if (raw.byAdmin && typeof raw.byAdmin === "object") {
|
|
7963
|
+
const v = raw.byAdmin[userId];
|
|
7964
|
+
return typeof v === "string" && UUID.test(v) ? v : null;
|
|
7965
|
+
}
|
|
7966
|
+
if (typeof raw.sessionId === "string" && UUID.test(raw.sessionId) && primaryUserId !== null && userId === primaryUserId) {
|
|
7967
|
+
return raw.sessionId;
|
|
7968
|
+
}
|
|
7969
|
+
return null;
|
|
7970
|
+
}
|
|
7971
|
+
function writeCanonicalOverrideId(accountDir, userId, sessionId) {
|
|
7972
|
+
const raw = readRaw(accountDir);
|
|
7973
|
+
const byAdmin = {};
|
|
7974
|
+
if (raw?.byAdmin && typeof raw.byAdmin === "object") {
|
|
7975
|
+
for (const [k, v] of Object.entries(raw.byAdmin)) {
|
|
7976
|
+
if (typeof v === "string") byAdmin[k] = v;
|
|
7977
|
+
}
|
|
7978
|
+
}
|
|
7979
|
+
byAdmin[userId] = sessionId;
|
|
7966
7980
|
const path2 = canonicalOverridePath(accountDir);
|
|
7967
7981
|
const tmp = `${path2}.${process.pid}.tmp`;
|
|
7968
|
-
writeFileSync5(tmp, JSON.stringify({
|
|
7982
|
+
writeFileSync5(tmp, JSON.stringify({ byAdmin }, null, 2), "utf8");
|
|
7969
7983
|
renameSync(tmp, path2);
|
|
7970
7984
|
}
|
|
7971
7985
|
|
|
@@ -7981,6 +7995,33 @@ function adminSessionIdFor(accountId, senderId, personId) {
|
|
|
7981
7995
|
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
|
|
7982
7996
|
}
|
|
7983
7997
|
|
|
7998
|
+
// ../lib/models/src/index.ts
|
|
7999
|
+
var OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
8000
|
+
var SONNET_MODEL = "claude-sonnet-4-6";
|
|
8001
|
+
var HAIKU_MODEL = "claude-haiku-4-5";
|
|
8002
|
+
var MODEL_CONTEXT_WINDOW = {
|
|
8003
|
+
[OPUS_MODEL]: 1e6,
|
|
8004
|
+
[SONNET_MODEL]: 2e5,
|
|
8005
|
+
[HAIKU_MODEL]: 2e5
|
|
8006
|
+
};
|
|
8007
|
+
var MODEL_DISPLAY_NAMES = {
|
|
8008
|
+
[OPUS_MODEL]: "Opus 4.8 (1M context)",
|
|
8009
|
+
[SONNET_MODEL]: "Sonnet 4.6",
|
|
8010
|
+
[HAIKU_MODEL]: "Haiku 4.5"
|
|
8011
|
+
};
|
|
8012
|
+
var SELECTABLE_MODELS = [OPUS_MODEL, SONNET_MODEL, HAIKU_MODEL];
|
|
8013
|
+
function isSelectableModel(id) {
|
|
8014
|
+
return SELECTABLE_MODELS.includes(id);
|
|
8015
|
+
}
|
|
8016
|
+
var PERMISSION_MODES = ["default", "acceptEdits", "plan", "auto", "bypassPermissions"];
|
|
8017
|
+
function isPermissionMode(value) {
|
|
8018
|
+
return PERMISSION_MODES.includes(value);
|
|
8019
|
+
}
|
|
8020
|
+
var EFFORT_LEVELS = ["low", "medium", "high", "xhigh"];
|
|
8021
|
+
function isEffortLevel(value) {
|
|
8022
|
+
return EFFORT_LEVELS.includes(value);
|
|
8023
|
+
}
|
|
8024
|
+
|
|
7984
8025
|
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
7985
8026
|
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync as readdirSync9, readFileSync as readFileSync15, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
|
|
7986
8027
|
import { join as join14 } from "path";
|
|
@@ -8134,11 +8175,25 @@ function locateSidecar(sessionId) {
|
|
|
8134
8175
|
for (const slug of slugs) {
|
|
8135
8176
|
const metaPath = join15(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
8136
8177
|
if (existsSync9(metaPath)) {
|
|
8137
|
-
|
|
8178
|
+
const meta = readSidecarMeta(metaPath);
|
|
8179
|
+
return { channel: meta.channel, adminUserId: meta.adminUserId };
|
|
8138
8180
|
}
|
|
8139
8181
|
}
|
|
8140
8182
|
return null;
|
|
8141
8183
|
}
|
|
8184
|
+
function readTargetOwner(sessionId) {
|
|
8185
|
+
const sidecar = locateSidecar(sessionId);
|
|
8186
|
+
if (sidecar !== null) return { found: true, owner: sidecar.adminUserId };
|
|
8187
|
+
const { projectDir } = locateSession(sessionId);
|
|
8188
|
+
if (projectDir !== null) {
|
|
8189
|
+
return { found: true, owner: readSidecarMeta(join15(projectDir, `${sessionId}.meta.json`)).adminUserId };
|
|
8190
|
+
}
|
|
8191
|
+
return { found: false, owner: null };
|
|
8192
|
+
}
|
|
8193
|
+
function ownedByRequester(owner, requesterUserId, primaryUserId) {
|
|
8194
|
+
if (requesterUserId === null) return false;
|
|
8195
|
+
return owner === requesterUserId || owner === null && requesterUserId === primaryUserId;
|
|
8196
|
+
}
|
|
8142
8197
|
function sessionSidecarExists(sessionId) {
|
|
8143
8198
|
return locateSidecar(sessionId) !== null;
|
|
8144
8199
|
}
|
|
@@ -8189,8 +8244,6 @@ async function fetchComposerIndicators(sessionId) {
|
|
|
8189
8244
|
}
|
|
8190
8245
|
}
|
|
8191
8246
|
var MODEL_ID_PATTERN = /^claude-[a-z0-9][a-z0-9.-]*(\[1m\])?$/;
|
|
8192
|
-
var EFFORT_LEVELS = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh"]);
|
|
8193
|
-
var PERMISSION_MODE_VALUES = /* @__PURE__ */ new Set(["default", "acceptEdits", "plan", "auto", "bypassPermissions"]);
|
|
8194
8247
|
function readLevers(preResolved) {
|
|
8195
8248
|
let account = preResolved;
|
|
8196
8249
|
if (account === void 0) {
|
|
@@ -8206,11 +8259,20 @@ function readLevers(preResolved) {
|
|
|
8206
8259
|
const mode = account.config.adminPermissionMode;
|
|
8207
8260
|
return {
|
|
8208
8261
|
leverModel: typeof model === "string" && MODEL_ID_PATTERN.test(model) ? model : null,
|
|
8209
|
-
leverEffort: typeof effort === "string" &&
|
|
8210
|
-
leverMode: typeof mode === "string" &&
|
|
8262
|
+
leverEffort: typeof effort === "string" && isEffortLevel(effort) ? effort : null,
|
|
8263
|
+
leverMode: typeof mode === "string" && isPermissionMode(mode) ? mode : null
|
|
8211
8264
|
};
|
|
8212
8265
|
}
|
|
8213
|
-
function
|
|
8266
|
+
function resolvePrimaryAdminUserId() {
|
|
8267
|
+
try {
|
|
8268
|
+
const users = readUsersFile(USERS_FILE);
|
|
8269
|
+
return users && users.length > 0 ? users[0].userId : null;
|
|
8270
|
+
} catch {
|
|
8271
|
+
return null;
|
|
8272
|
+
}
|
|
8273
|
+
}
|
|
8274
|
+
function latestAdminWebchatSessionId(requesterUserId, primaryUserId) {
|
|
8275
|
+
if (requesterUserId === null) return null;
|
|
8214
8276
|
const cfg = claudeConfigDir();
|
|
8215
8277
|
if (!cfg) return null;
|
|
8216
8278
|
let best = null;
|
|
@@ -8225,6 +8287,13 @@ function latestAdminWebchatSessionId() {
|
|
|
8225
8287
|
} catch {
|
|
8226
8288
|
continue;
|
|
8227
8289
|
}
|
|
8290
|
+
const owned = meta.adminUserId === requesterUserId || meta.adminUserId === null && requesterUserId === primaryUserId;
|
|
8291
|
+
if (!owned) {
|
|
8292
|
+
if (best === null || mtimeMs > best.mtimeMs) {
|
|
8293
|
+
console.error(`[webchat:inbound] op=owner-skip candidate=${id.slice(0, 8)} owner=${meta.adminUserId ? meta.adminUserId.slice(0, 8) : "none"} requester=${requesterUserId.slice(0, 8)}`);
|
|
8294
|
+
}
|
|
8295
|
+
continue;
|
|
8296
|
+
}
|
|
8228
8297
|
if (best === null || mtimeMs > best.mtimeMs) best = { id, mtimeMs };
|
|
8229
8298
|
}
|
|
8230
8299
|
return best === null ? null : best.id;
|
|
@@ -8234,14 +8303,17 @@ function overrideKnownNonArchived(id) {
|
|
|
8234
8303
|
if (projectDir === null) return sessionSidecarExists(id);
|
|
8235
8304
|
return basename4(projectDir) !== "archive";
|
|
8236
8305
|
}
|
|
8237
|
-
function resolveCanonical(accountId, accountDir) {
|
|
8238
|
-
|
|
8306
|
+
function resolveCanonical(accountId, accountDir, requesterUserId, primaryUserId) {
|
|
8307
|
+
if (requesterUserId === null) {
|
|
8308
|
+
return { sessionId: adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY), source: "canonical-empty" };
|
|
8309
|
+
}
|
|
8310
|
+
const latest = latestAdminWebchatSessionId(requesterUserId, primaryUserId);
|
|
8239
8311
|
if (latest !== null) return { sessionId: latest, source: "latest" };
|
|
8240
8312
|
if (accountDir) {
|
|
8241
|
-
const override = readCanonicalOverrideId(accountDir);
|
|
8313
|
+
const override = readCanonicalOverrideId(accountDir, requesterUserId, primaryUserId);
|
|
8242
8314
|
if (override && overrideKnownNonArchived(override)) return { sessionId: override, source: "override" };
|
|
8243
8315
|
}
|
|
8244
|
-
return { sessionId: adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY), source: "canonical-empty" };
|
|
8316
|
+
return { sessionId: adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY, requesterUserId), source: "canonical-empty" };
|
|
8245
8317
|
}
|
|
8246
8318
|
var REAPPLY_TIMEOUT_MS = 1500;
|
|
8247
8319
|
async function reapplyLeversViaManager() {
|
|
@@ -8274,6 +8346,9 @@ function createWebchatRoutes(deps) {
|
|
|
8274
8346
|
console.error(`[webchat:inbound] op=send-refused reason=account-unresolved detail=${detail}`);
|
|
8275
8347
|
return c.json({ error: "account unresolved" }, 503);
|
|
8276
8348
|
}
|
|
8349
|
+
const cacheKey = c.get("cacheKey");
|
|
8350
|
+
const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
|
|
8351
|
+
const primaryUserId = resolvePrimaryAdminUserId();
|
|
8277
8352
|
let text;
|
|
8278
8353
|
let target;
|
|
8279
8354
|
let files = [];
|
|
@@ -8314,10 +8389,18 @@ function createWebchatRoutes(deps) {
|
|
|
8314
8389
|
}
|
|
8315
8390
|
let deliveryKey = WEBCHAT_ADMIN_KEY;
|
|
8316
8391
|
let deliverySessionId;
|
|
8392
|
+
const explicitTarget = target !== void 0;
|
|
8317
8393
|
if (target === void 0) {
|
|
8318
|
-
const latest = latestAdminWebchatSessionId();
|
|
8394
|
+
const latest = latestAdminWebchatSessionId(requesterUserId, primaryUserId);
|
|
8319
8395
|
if (latest !== null) target = latest;
|
|
8320
8396
|
}
|
|
8397
|
+
if (explicitTarget && target !== void 0) {
|
|
8398
|
+
const t = readTargetOwner(target);
|
|
8399
|
+
if (t.found && !ownedByRequester(t.owner, requesterUserId, primaryUserId)) {
|
|
8400
|
+
console.error(`[webchat:inbound] op=send-refused key=session:${target.slice(0, 8)} reason=foreign-target requester=${requesterUserId ? requesterUserId.slice(0, 8) : "none"}`);
|
|
8401
|
+
return c.json({ error: "session not found" }, 404);
|
|
8402
|
+
}
|
|
8403
|
+
}
|
|
8321
8404
|
if (target !== void 0) {
|
|
8322
8405
|
let { projectDir, channel } = locateSession(target);
|
|
8323
8406
|
if (projectDir === null) {
|
|
@@ -8393,10 +8476,11 @@ ${note}` : note;
|
|
|
8393
8476
|
}
|
|
8394
8477
|
console.log(`[webchat:inbound] op=send-accepted kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
8395
8478
|
}
|
|
8479
|
+
const adminUserId = requesterUserId ?? void 0;
|
|
8396
8480
|
if (deliverySessionId !== void 0) {
|
|
8397
|
-
await deps.handleInbound({ role: "admin", accountId, key: deliveryKey, text, sessionId: deliverySessionId });
|
|
8481
|
+
await deps.handleInbound({ role: "admin", accountId, key: deliveryKey, text, sessionId: deliverySessionId, adminUserId });
|
|
8398
8482
|
} else {
|
|
8399
|
-
await deps.handleInbound({ role: "admin", accountId, key: deliveryKey, text });
|
|
8483
|
+
await deps.handleInbound({ role: "admin", accountId, key: deliveryKey, text, adminUserId });
|
|
8400
8484
|
}
|
|
8401
8485
|
const sendId = ++sendSeq;
|
|
8402
8486
|
let turnSessionId = deliverySessionId;
|
|
@@ -8407,7 +8491,7 @@ ${note}` : note;
|
|
|
8407
8491
|
} catch {
|
|
8408
8492
|
canonAccount = null;
|
|
8409
8493
|
}
|
|
8410
|
-
turnSessionId = resolveCanonical(accountId, canonAccount?.accountDir ?? null).sessionId;
|
|
8494
|
+
turnSessionId = resolveCanonical(accountId, canonAccount?.accountDir ?? null, requesterUserId, primaryUserId).sessionId;
|
|
8411
8495
|
}
|
|
8412
8496
|
const keyDisplay2 = deliveryKey.startsWith("session:") ? deliveryKey.slice(0, "session:".length + 8) : WEBCHAT_ADMIN_KEY;
|
|
8413
8497
|
const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
|
|
@@ -8432,7 +8516,7 @@ ${note}` : note;
|
|
|
8432
8516
|
console.error(`[webchat:settings] op=${String(op)} outcome=refused reason=unknown-op`);
|
|
8433
8517
|
return c.json({ error: "op must be model, effort, or mode" }, 400);
|
|
8434
8518
|
}
|
|
8435
|
-
if (typeof value !== "string" || op === "model" && !MODEL_ID_PATTERN.test(value) || op === "effort" && !
|
|
8519
|
+
if (typeof value !== "string" || op === "model" && !MODEL_ID_PATTERN.test(value) || op === "effort" && !isEffortLevel(value) || op === "mode" && !isPermissionMode(value)) {
|
|
8436
8520
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${JSON.stringify(value)} reason=invalid-value`);
|
|
8437
8521
|
return c.json({ error: `invalid ${op} value` }, 400);
|
|
8438
8522
|
}
|
|
@@ -8473,11 +8557,19 @@ ${note}` : note;
|
|
|
8473
8557
|
console.error(`[webchat:inbound] op=session-refused reason=account-unresolved detail=${detail}`);
|
|
8474
8558
|
return c.json({ error: "account unresolved" }, 503);
|
|
8475
8559
|
}
|
|
8560
|
+
const cacheKey = c.get("cacheKey");
|
|
8561
|
+
const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
|
|
8562
|
+
const primaryUserId = resolvePrimaryAdminUserId();
|
|
8476
8563
|
const target = c.req.query("session");
|
|
8477
8564
|
if (target !== void 0) {
|
|
8478
8565
|
if (!UUID_PATTERN.test(target)) {
|
|
8479
8566
|
return c.json({ error: "invalid session id" }, 400);
|
|
8480
8567
|
}
|
|
8568
|
+
const owned = readTargetOwner(target);
|
|
8569
|
+
if (owned.found && !ownedByRequester(owned.owner, requesterUserId, primaryUserId)) {
|
|
8570
|
+
console.error(`[webchat:inbound] op=session-target-foreign key=session:${target.slice(0, 8)} requester=${requesterUserId ? requesterUserId.slice(0, 8) : "none"}`);
|
|
8571
|
+
return c.json({ error: "session not found" }, 404);
|
|
8572
|
+
}
|
|
8481
8573
|
const { projectDir: projectDir2, channel } = locateSession(target);
|
|
8482
8574
|
let resolvedProjectDir = projectDir2;
|
|
8483
8575
|
let transcriptSessionId = target;
|
|
@@ -8498,7 +8590,7 @@ ${note}` : note;
|
|
|
8498
8590
|
}
|
|
8499
8591
|
const known = resolvedProjectDir !== null || sessionSidecarExists(target);
|
|
8500
8592
|
const indicators2 = await fetchComposerIndicators(target);
|
|
8501
|
-
return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), ...indicators2, ...readLevers() });
|
|
8593
|
+
return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${target}`) ?? null, ...indicators2, ...readLevers() });
|
|
8502
8594
|
}
|
|
8503
8595
|
let account;
|
|
8504
8596
|
try {
|
|
@@ -8506,11 +8598,14 @@ ${note}` : note;
|
|
|
8506
8598
|
} catch {
|
|
8507
8599
|
account = null;
|
|
8508
8600
|
}
|
|
8509
|
-
const { sessionId, source } = resolveCanonical(accountId, account?.accountDir ?? null);
|
|
8510
|
-
if (
|
|
8511
|
-
|
|
8601
|
+
const { sessionId, source } = resolveCanonical(accountId, account?.accountDir ?? null, requesterUserId, primaryUserId);
|
|
8602
|
+
if (requesterUserId === null) {
|
|
8603
|
+
console.error(`[webchat:inbound] op=session-resolve-no-identity key=${sessionId.slice(0, 8)}`);
|
|
8604
|
+
}
|
|
8605
|
+
if (source === "latest" && account?.accountDir && requesterUserId !== null) {
|
|
8606
|
+
writeCanonicalOverrideId(account.accountDir, requesterUserId, sessionId);
|
|
8512
8607
|
}
|
|
8513
|
-
console.log(`[webchat:inbound] op=session-resolve key=${sessionId.slice(0, 8)} source=${source}`);
|
|
8608
|
+
console.log(`[webchat:inbound] op=session-resolve key=${sessionId.slice(0, 8)} source=${source} admin=${requesterUserId ? requesterUserId.slice(0, 8) : "none"}`);
|
|
8514
8609
|
const cfg = claudeConfigDir();
|
|
8515
8610
|
let projectDir = null;
|
|
8516
8611
|
if (cfg) {
|
|
@@ -8521,8 +8616,31 @@ ${note}` : note;
|
|
|
8521
8616
|
}
|
|
8522
8617
|
}
|
|
8523
8618
|
}
|
|
8619
|
+
if (source === "latest" && requesterUserId !== null) {
|
|
8620
|
+
const owner = readSidecarMeta(join15(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
|
|
8621
|
+
if (owner !== null && owner !== requesterUserId && requesterUserId !== primaryUserId) {
|
|
8622
|
+
console.error(`[webchat:inbound] op=session-resolve-foreign key=${sessionId.slice(0, 8)} owner=${owner.slice(0, 8)} requester=${requesterUserId.slice(0, 8)}`);
|
|
8623
|
+
}
|
|
8624
|
+
}
|
|
8524
8625
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
8525
|
-
return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), ...indicators, ...readLevers(account) });
|
|
8626
|
+
return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
|
|
8627
|
+
});
|
|
8628
|
+
app53.post("/permission-verdict", requireAdminSession, async (c) => {
|
|
8629
|
+
const body = await c.req.json().catch(() => null);
|
|
8630
|
+
const sessionId = body?.sessionId;
|
|
8631
|
+
const requestId = body?.request_id;
|
|
8632
|
+
const behavior = body?.behavior;
|
|
8633
|
+
if (typeof sessionId !== "string" || !UUID_PATTERN.test(sessionId)) {
|
|
8634
|
+
return c.json({ error: "invalid session id" }, 400);
|
|
8635
|
+
}
|
|
8636
|
+
if (typeof requestId !== "string" || requestId.length === 0) {
|
|
8637
|
+
return c.json({ error: "request_id required" }, 400);
|
|
8638
|
+
}
|
|
8639
|
+
if (behavior !== "allow" && behavior !== "deny") {
|
|
8640
|
+
return c.json({ error: "behavior must be allow or deny" }, 400);
|
|
8641
|
+
}
|
|
8642
|
+
const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
|
|
8643
|
+
return c.json({ ok });
|
|
8526
8644
|
});
|
|
8527
8645
|
return app53;
|
|
8528
8646
|
}
|
|
@@ -8705,7 +8823,8 @@ async function managerSpawn(opts) {
|
|
|
8705
8823
|
personId: opts.personId,
|
|
8706
8824
|
visitorId: opts.visitorId,
|
|
8707
8825
|
name: opts.name,
|
|
8708
|
-
webchatChannel: opts.webchatChannel
|
|
8826
|
+
webchatChannel: opts.webchatChannel,
|
|
8827
|
+
previousContext: opts.previousContext
|
|
8709
8828
|
})
|
|
8710
8829
|
}).catch((err) => ({ __throw: err instanceof Error ? err.message : String(err) }));
|
|
8711
8830
|
if ("__throw" in res) {
|
|
@@ -8732,6 +8851,7 @@ async function managerRcSpawn(opts) {
|
|
|
8732
8851
|
sliceToken: opts.sliceToken,
|
|
8733
8852
|
personId: opts.personId,
|
|
8734
8853
|
userId: opts.userId,
|
|
8854
|
+
adminUserId: opts.adminUserId,
|
|
8735
8855
|
waChannel: opts.waChannel,
|
|
8736
8856
|
webchatChannel: opts.webchatChannel,
|
|
8737
8857
|
role: opts.role,
|
|
@@ -16086,29 +16206,6 @@ var session_rc_spawn_default = app32;
|
|
|
16086
16206
|
|
|
16087
16207
|
// server/routes/admin/session-reseat.ts
|
|
16088
16208
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
16089
|
-
|
|
16090
|
-
// ../lib/models/src/index.ts
|
|
16091
|
-
var OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
16092
|
-
var SONNET_MODEL = "claude-sonnet-4-6";
|
|
16093
|
-
var HAIKU_MODEL = "claude-haiku-4-5";
|
|
16094
|
-
var MODEL_CONTEXT_WINDOW = {
|
|
16095
|
-
[OPUS_MODEL]: 1e6,
|
|
16096
|
-
[SONNET_MODEL]: 2e5,
|
|
16097
|
-
[HAIKU_MODEL]: 2e5
|
|
16098
|
-
};
|
|
16099
|
-
var MODEL_DISPLAY_NAMES = {
|
|
16100
|
-
[OPUS_MODEL]: "Opus 4.8 (1M context)",
|
|
16101
|
-
[SONNET_MODEL]: "Sonnet 4.6",
|
|
16102
|
-
[HAIKU_MODEL]: "Haiku 4.5"
|
|
16103
|
-
};
|
|
16104
|
-
var SELECTABLE_MODELS = [OPUS_MODEL, SONNET_MODEL, HAIKU_MODEL];
|
|
16105
|
-
function isSelectableModel(id) {
|
|
16106
|
-
return SELECTABLE_MODELS.includes(id);
|
|
16107
|
-
}
|
|
16108
|
-
|
|
16109
|
-
// server/routes/admin/session-reseat.ts
|
|
16110
|
-
var RESEAT_PERMISSION_MODES = /* @__PURE__ */ new Set(["default", "acceptEdits", "plan", "auto", "bypassPermissions"]);
|
|
16111
|
-
var RESEAT_EFFORT_LEVELS = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh"]);
|
|
16112
16209
|
function resolveReseatPlan(body, mintId = randomUUID12, adminUserId, authenticatedName) {
|
|
16113
16210
|
const sessionId = mintId();
|
|
16114
16211
|
const key = `session:${sessionId}`;
|
|
@@ -16141,8 +16238,8 @@ app33.post("/", requireAdminSession, async (c) => {
|
|
|
16141
16238
|
const model = typeof body.model === "string" && isSelectableModel(body.model) ? body.model : null;
|
|
16142
16239
|
if (fromSessionId === null) return c.json({ error: "fromSessionId must be a valid session id" }, 400);
|
|
16143
16240
|
if (model === null) return c.json({ error: "model must be a selectable model" }, 400);
|
|
16144
|
-
const permissionMode = typeof body.permissionMode === "string" ?
|
|
16145
|
-
const effort = typeof body.effort === "string" ?
|
|
16241
|
+
const permissionMode = typeof body.permissionMode === "string" ? isPermissionMode(body.permissionMode) ? body.permissionMode : null : void 0;
|
|
16242
|
+
const effort = typeof body.effort === "string" ? isEffortLevel(body.effort) ? body.effort : null : void 0;
|
|
16146
16243
|
if (permissionMode === null) return c.json({ error: "permissionMode must be a composer-writable mode" }, 400);
|
|
16147
16244
|
if (effort === null) return c.json({ error: "effort must be an accepted level" }, 400);
|
|
16148
16245
|
if (reseatsInFlight.has(fromSessionId)) {
|
|
@@ -16152,6 +16249,13 @@ app33.post("/", requireAdminSession, async (c) => {
|
|
|
16152
16249
|
try {
|
|
16153
16250
|
const cacheKey = c.get("cacheKey");
|
|
16154
16251
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
16252
|
+
{
|
|
16253
|
+
const ownerInfo = readTargetOwner(fromSessionId);
|
|
16254
|
+
if (!(ownerInfo.found && ownedByRequester(ownerInfo.owner, adminUserId ?? null, resolvePrimaryAdminUserId()))) {
|
|
16255
|
+
console.error(`[chat-reseat] op=reseat-refused from=${fromSessionId.slice(0, 8)} reason=foreign-source requester=${adminUserId ? adminUserId.slice(0, 8) : "none"}`);
|
|
16256
|
+
return c.json({ error: "session not found" }, 404);
|
|
16257
|
+
}
|
|
16258
|
+
}
|
|
16155
16259
|
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
16156
16260
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
16157
16261
|
const plan = resolveReseatPlan(
|
|
@@ -16188,12 +16292,13 @@ app33.post("/", requireAdminSession, async (c) => {
|
|
|
16188
16292
|
}
|
|
16189
16293
|
try {
|
|
16190
16294
|
const account = resolveAccount();
|
|
16191
|
-
if (account) {
|
|
16295
|
+
if (account && adminUserId) {
|
|
16192
16296
|
const accountId2 = resolvePlatformAccountId();
|
|
16193
|
-
const
|
|
16194
|
-
const
|
|
16297
|
+
const primaryUserId = resolvePrimaryAdminUserId();
|
|
16298
|
+
const canonicalId = adminSessionIdFor(accountId2, WEBCHAT_ADMIN_KEY, adminUserId);
|
|
16299
|
+
const currentOverride = readCanonicalOverrideId(account.accountDir, adminUserId, primaryUserId);
|
|
16195
16300
|
if (fromSessionId === canonicalId || fromSessionId === currentOverride) {
|
|
16196
|
-
writeCanonicalOverrideId(account.accountDir, plan.sessionId);
|
|
16301
|
+
writeCanonicalOverrideId(account.accountDir, adminUserId, plan.sessionId);
|
|
16197
16302
|
console.log(`[chat-reseat] op=canonical-forward reseatReqId=${reseatReqId} from=${fromSessionId} to=${plan.sessionId}`);
|
|
16198
16303
|
}
|
|
16199
16304
|
}
|
|
@@ -16652,9 +16757,8 @@ app37.get("/", async (c) => {
|
|
|
16652
16757
|
});
|
|
16653
16758
|
var post_turn_context_default = app37;
|
|
16654
16759
|
|
|
16655
|
-
//
|
|
16760
|
+
// app/lib/slice-writes.ts
|
|
16656
16761
|
import neo4j4 from "neo4j-driver";
|
|
16657
|
-
var TAG32 = "[public-session-context]";
|
|
16658
16762
|
var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
|
|
16659
16763
|
"embedding",
|
|
16660
16764
|
"passwordHash",
|
|
@@ -16662,9 +16766,6 @@ var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
|
|
|
16662
16766
|
"otpCode",
|
|
16663
16767
|
"cacheKey"
|
|
16664
16768
|
]);
|
|
16665
|
-
function isLoopbackAddr3(addr) {
|
|
16666
|
-
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
16667
|
-
}
|
|
16668
16769
|
function convertValue2(value) {
|
|
16669
16770
|
if (neo4j4.isDateTime(value) || neo4j4.isDate(value) || neo4j4.isLocalDateTime(value) || neo4j4.isLocalTime(value) || neo4j4.isTime(value) || neo4j4.isDuration(value)) {
|
|
16670
16771
|
return value.toString();
|
|
@@ -16692,6 +16793,78 @@ function pruneProperties2(raw) {
|
|
|
16692
16793
|
}
|
|
16693
16794
|
return out;
|
|
16694
16795
|
}
|
|
16796
|
+
async function fetchSliceWrites(session, sliceToken, accountId) {
|
|
16797
|
+
const cypher = `
|
|
16798
|
+
MATCH (n)
|
|
16799
|
+
WHERE n.sliceToken = $sliceToken AND n.accountId = $accountId
|
|
16800
|
+
RETURN elementId(n) AS elementId,
|
|
16801
|
+
labels(n) AS labels,
|
|
16802
|
+
properties(n) AS properties,
|
|
16803
|
+
coalesce(n.createdAt, n.observedAt, '') AS sortKey
|
|
16804
|
+
`;
|
|
16805
|
+
const res = await session.executeRead((tx) => tx.run(cypher, { sliceToken, accountId }));
|
|
16806
|
+
const writes = res.records.map((r) => ({
|
|
16807
|
+
elementId: r.get("elementId"),
|
|
16808
|
+
labels: r.get("labels"),
|
|
16809
|
+
properties: pruneProperties2(r.get("properties")),
|
|
16810
|
+
sortKey: String(r.get("sortKey") ?? "")
|
|
16811
|
+
}));
|
|
16812
|
+
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
16813
|
+
return writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }));
|
|
16814
|
+
}
|
|
16815
|
+
var STRUCTURAL_KEYS = /* @__PURE__ */ new Set([
|
|
16816
|
+
"accountId",
|
|
16817
|
+
"scope",
|
|
16818
|
+
"sliceToken",
|
|
16819
|
+
"preferenceId",
|
|
16820
|
+
"ideaId",
|
|
16821
|
+
"createdAt",
|
|
16822
|
+
"updatedAt",
|
|
16823
|
+
"observedAt",
|
|
16824
|
+
"sessionId",
|
|
16825
|
+
"createdByAgent",
|
|
16826
|
+
"createdBySession",
|
|
16827
|
+
"confidence",
|
|
16828
|
+
"notApplicable"
|
|
16829
|
+
]);
|
|
16830
|
+
function primaryLabel(labels) {
|
|
16831
|
+
return labels.find((l) => l.length > 0) ?? "Node";
|
|
16832
|
+
}
|
|
16833
|
+
function renderWrite(write) {
|
|
16834
|
+
const label = primaryLabel(write.labels);
|
|
16835
|
+
const props = write.properties;
|
|
16836
|
+
const parts = [];
|
|
16837
|
+
if (label === "Person") {
|
|
16838
|
+
const name = [props.givenName, props.familyName].filter((v) => typeof v === "string" && v.length > 0).join(" ");
|
|
16839
|
+
if (name) parts.push(name);
|
|
16840
|
+
}
|
|
16841
|
+
const kv = [];
|
|
16842
|
+
for (const [k, v] of Object.entries(props)) {
|
|
16843
|
+
if (STRUCTURAL_KEYS.has(k)) continue;
|
|
16844
|
+
if (label === "Person" && (k === "givenName" || k === "familyName")) continue;
|
|
16845
|
+
if (v === null || v === void 0 || v === "") continue;
|
|
16846
|
+
const val = String(v).slice(0, 200);
|
|
16847
|
+
kv.push(`${k}=${val}`);
|
|
16848
|
+
}
|
|
16849
|
+
const tail = [parts.join(" "), kv.join("; ")].filter((s) => s.length > 0).join(" \u2014 ");
|
|
16850
|
+
if (tail.length === 0) return null;
|
|
16851
|
+
return `- ${label}: ${tail}`;
|
|
16852
|
+
}
|
|
16853
|
+
function formatPreviousContext(writes) {
|
|
16854
|
+
if (writes.length === 0) return null;
|
|
16855
|
+
const lines = writes.filter((w) => w.properties.scope === "user").map(renderWrite).filter((l) => l !== null);
|
|
16856
|
+
if (lines.length === 0) return null;
|
|
16857
|
+
return [
|
|
16858
|
+
"What you already know about this visitor from earlier conversations:",
|
|
16859
|
+
...lines
|
|
16860
|
+
].join("\n");
|
|
16861
|
+
}
|
|
16862
|
+
|
|
16863
|
+
// server/routes/admin/public-session-context.ts
|
|
16864
|
+
var TAG32 = "[public-session-context]";
|
|
16865
|
+
function isLoopbackAddr3(addr) {
|
|
16866
|
+
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
16867
|
+
}
|
|
16695
16868
|
var app38 = new Hono();
|
|
16696
16869
|
app38.get("/", async (c) => {
|
|
16697
16870
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
@@ -16716,31 +16889,12 @@ app38.get("/", async (c) => {
|
|
|
16716
16889
|
const session = getSession();
|
|
16717
16890
|
const started = Date.now();
|
|
16718
16891
|
try {
|
|
16719
|
-
const
|
|
16720
|
-
MATCH (n)
|
|
16721
|
-
WHERE n.sliceToken = $sliceToken AND n.accountId = $accountId
|
|
16722
|
-
RETURN elementId(n) AS elementId,
|
|
16723
|
-
labels(n) AS labels,
|
|
16724
|
-
properties(n) AS properties,
|
|
16725
|
-
coalesce(n.createdAt, n.observedAt, '') AS sortKey
|
|
16726
|
-
`;
|
|
16727
|
-
const res = await session.executeRead(
|
|
16728
|
-
(tx) => tx.run(cypher, { sliceToken, accountId })
|
|
16729
|
-
);
|
|
16730
|
-
const writes = res.records.map((r) => ({
|
|
16731
|
-
elementId: r.get("elementId"),
|
|
16732
|
-
labels: r.get("labels"),
|
|
16733
|
-
properties: pruneProperties2(r.get("properties")),
|
|
16734
|
-
sortKey: String(r.get("sortKey") ?? "")
|
|
16735
|
-
}));
|
|
16736
|
-
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
16892
|
+
const writes = await fetchSliceWrites(session, sliceToken, accountId);
|
|
16737
16893
|
const total = Date.now() - started;
|
|
16738
16894
|
console.log(
|
|
16739
16895
|
`${TAG32} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
16740
16896
|
);
|
|
16741
|
-
return c.json({
|
|
16742
|
-
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
16743
|
-
});
|
|
16897
|
+
return c.json({ writes });
|
|
16744
16898
|
} catch (err) {
|
|
16745
16899
|
const elapsed = Date.now() - started;
|
|
16746
16900
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -17979,19 +18133,8 @@ app51.post("/", async (c) => {
|
|
|
17979
18133
|
const account = resolveAccount();
|
|
17980
18134
|
const cookieHeader = c.req.header("cookie");
|
|
17981
18135
|
const visitorId = parseVisitorCookie2(cookieHeader);
|
|
17982
|
-
const groupSlug = body.group_slug && typeof body.group_slug === "string" ? body.group_slug : null;
|
|
17983
|
-
let groupInfo = null;
|
|
17984
|
-
if (groupSlug) {
|
|
17985
|
-
groupInfo = await findGroupBySlug(groupSlug, accountId).catch(() => null);
|
|
17986
|
-
if (!groupInfo) {
|
|
17987
|
-
console.error(`[session] group not found: slug=${groupSlug} account=${accountId.slice(0, 8)}\u2026`);
|
|
17988
|
-
return c.json({ error: "Group not found" }, 404);
|
|
17989
|
-
}
|
|
17990
|
-
}
|
|
17991
18136
|
let agentSlug = null;
|
|
17992
|
-
if (
|
|
17993
|
-
agentSlug = groupInfo.agentSlug;
|
|
17994
|
-
} else if (body.agent) {
|
|
18137
|
+
if (body.agent) {
|
|
17995
18138
|
if (!validateAgentSlug(body.agent)) {
|
|
17996
18139
|
return c.json({ error: "Invalid agent name" }, 400);
|
|
17997
18140
|
}
|
|
@@ -18024,11 +18167,6 @@ app51.post("/", async (c) => {
|
|
|
18024
18167
|
...agentConfig.imageShape ? { agentImageShape: agentConfig.imageShape } : {},
|
|
18025
18168
|
...agentConfig.showAgentName ? { showAgentName: agentConfig.showAgentName } : {}
|
|
18026
18169
|
} : {};
|
|
18027
|
-
const groupFields = groupInfo ? {
|
|
18028
|
-
group: true,
|
|
18029
|
-
groupName: groupInfo.groupName,
|
|
18030
|
-
groupSlug
|
|
18031
|
-
} : {};
|
|
18032
18170
|
const branding = await fetchBranding(accountId).catch(() => null);
|
|
18033
18171
|
if (branding) writeBrandingCache(accountId, agentSlug, branding);
|
|
18034
18172
|
let accessSession = null;
|
|
@@ -18041,7 +18179,6 @@ app51.post("/", async (c) => {
|
|
|
18041
18179
|
Response.json({
|
|
18042
18180
|
auth_required: true,
|
|
18043
18181
|
agent_id: agentSlug,
|
|
18044
|
-
...groupFields,
|
|
18045
18182
|
...branding ? { branding } : {},
|
|
18046
18183
|
...agentIdentity
|
|
18047
18184
|
}),
|
|
@@ -18066,7 +18203,6 @@ app51.post("/", async (c) => {
|
|
|
18066
18203
|
agent_id: agentSlug,
|
|
18067
18204
|
resumed,
|
|
18068
18205
|
...resumed ? { messages: uiMessages } : {},
|
|
18069
|
-
...groupFields,
|
|
18070
18206
|
...branding ? { branding } : {},
|
|
18071
18207
|
...agentIdentity
|
|
18072
18208
|
});
|
|
@@ -18077,56 +18213,10 @@ app51.post("/", async (c) => {
|
|
|
18077
18213
|
session_key: body.session_key,
|
|
18078
18214
|
agent_id: agentSlug,
|
|
18079
18215
|
resumed: false,
|
|
18080
|
-
...groupFields,
|
|
18081
18216
|
...branding ? { branding } : {},
|
|
18082
18217
|
...agentIdentity
|
|
18083
18218
|
});
|
|
18084
18219
|
}
|
|
18085
|
-
if (groupInfo && visitorId) {
|
|
18086
|
-
let memberName = await checkGroupMembership(groupInfo.sessionId, visitorId).catch(() => null);
|
|
18087
|
-
if (!memberName && accessSession) {
|
|
18088
|
-
const contactValue = accessSession.contactValue;
|
|
18089
|
-
const isEmail = contactValue?.includes("@");
|
|
18090
|
-
const bindResult = await bindVisitorToGroup(
|
|
18091
|
-
groupInfo.sessionId,
|
|
18092
|
-
visitorId,
|
|
18093
|
-
isEmail ? contactValue : void 0,
|
|
18094
|
-
!isEmail ? contactValue : void 0
|
|
18095
|
-
).catch(() => null);
|
|
18096
|
-
memberName = bindResult?.displayName ?? null;
|
|
18097
|
-
}
|
|
18098
|
-
if (memberName) {
|
|
18099
|
-
const neo4jMessages = await getRecentMessages(groupInfo.sessionId).catch(() => []);
|
|
18100
|
-
const uiMessages = neo4jMessages.filter((m) => m.content !== GREETING_DIRECTIVE).map((m) => ({
|
|
18101
|
-
role: m.role === "user" ? "visitor" : "maxy",
|
|
18102
|
-
content: m.content,
|
|
18103
|
-
timestamp: new Date(m.createdAt).getTime() || Date.now()
|
|
18104
|
-
}));
|
|
18105
|
-
const participants = await getGroupParticipants(groupInfo.sessionId).catch(() => []);
|
|
18106
|
-
const cacheKey2 = crypto.randomUUID();
|
|
18107
|
-
const resumed = uiMessages.length > 0;
|
|
18108
|
-
console.log(`[session] cold-resume group=${groupSlug} visitor=${visitorId.slice(0, 8)}\u2026 messages=${uiMessages.length}`);
|
|
18109
|
-
return withVisitorCookie(
|
|
18110
|
-
Response.json({
|
|
18111
|
-
session_key: cacheKey2,
|
|
18112
|
-
agent_id: agentSlug,
|
|
18113
|
-
resumed,
|
|
18114
|
-
...resumed ? { messages: uiMessages } : {},
|
|
18115
|
-
...groupFields,
|
|
18116
|
-
participants: participants.map((p) => ({ displayName: p.displayName, joinedAt: p.joinedAt })),
|
|
18117
|
-
...branding ? { branding } : {},
|
|
18118
|
-
...agentIdentity
|
|
18119
|
-
}),
|
|
18120
|
-
visitorId
|
|
18121
|
-
);
|
|
18122
|
-
}
|
|
18123
|
-
console.log(`[session] group cold-resume denied: visitor=${visitorId.slice(0, 8)}\u2026 not a member of group=${groupSlug}`);
|
|
18124
|
-
return c.json({ error: "Not a member of this group" }, 403);
|
|
18125
|
-
}
|
|
18126
|
-
if (groupInfo) {
|
|
18127
|
-
console.error(`[session] group=${groupSlug} requires visitor cookie`);
|
|
18128
|
-
return c.json({ error: "Groups require member authentication" }, 400);
|
|
18129
|
-
}
|
|
18130
18220
|
if (visitorId) {
|
|
18131
18221
|
const recent = await findRecentConversation(visitorId, accountId, agentSlug).catch(() => null);
|
|
18132
18222
|
if (recent) {
|
|
@@ -18528,7 +18618,7 @@ var defaultResolveName = async (accountId, userId) => {
|
|
|
18528
18618
|
const res = await loadAdminUserName(accountId, userId);
|
|
18529
18619
|
return res.source === "neo4j" && res.joined.length > 0 ? res.joined : null;
|
|
18530
18620
|
};
|
|
18531
|
-
async function
|
|
18621
|
+
async function readRaw2(path2) {
|
|
18532
18622
|
let raw;
|
|
18533
18623
|
try {
|
|
18534
18624
|
raw = await readFile7(path2, "utf8");
|
|
@@ -18636,7 +18726,7 @@ async function migrateAdminWebchatSidecars(opts = {}) {
|
|
|
18636
18726
|
};
|
|
18637
18727
|
const sidecars = await collectLiveSidecars(projectsRoot);
|
|
18638
18728
|
for (const path2 of sidecars) {
|
|
18639
|
-
const raw = await
|
|
18729
|
+
const raw = await readRaw2(path2);
|
|
18640
18730
|
if (!raw) continue;
|
|
18641
18731
|
if (raw.role !== ADMIN_ROLE2 || raw.channel !== WEBCHAT_CHANNEL2) continue;
|
|
18642
18732
|
result.scanned++;
|
|
@@ -18654,7 +18744,7 @@ async function migrateAdminWebchatSidecars(opts = {}) {
|
|
|
18654
18744
|
await writeRaw(path2, raw);
|
|
18655
18745
|
result.backfilled++;
|
|
18656
18746
|
await resolveAdminName();
|
|
18657
|
-
const back = await
|
|
18747
|
+
const back = await readRaw2(path2);
|
|
18658
18748
|
const wrote = back && back.adminUserId === soleAdminUserId;
|
|
18659
18749
|
if (wrote && resolvedNameForAdmin) {
|
|
18660
18750
|
result.resolvedName++;
|
|
@@ -19358,6 +19448,20 @@ function createWebchatChannelRoutes(deps) {
|
|
|
19358
19448
|
deps.onReady?.(key);
|
|
19359
19449
|
return c.json({ ok: true });
|
|
19360
19450
|
});
|
|
19451
|
+
app53.post("/webchat-channel/permission-request", async (c) => {
|
|
19452
|
+
const body = await c.req.json().catch(() => null);
|
|
19453
|
+
const key = body?.key;
|
|
19454
|
+
const requestId = body?.request_id;
|
|
19455
|
+
const toolName = body?.tool_name;
|
|
19456
|
+
const description = body?.description;
|
|
19457
|
+
const inputPreview = body?.input_preview;
|
|
19458
|
+
if (typeof key !== "string" || typeof requestId !== "string" || typeof toolName !== "string" || typeof description !== "string" || typeof inputPreview !== "string") {
|
|
19459
|
+
return c.json({ error: "key, request_id, tool_name, description, input_preview required" }, 400);
|
|
19460
|
+
}
|
|
19461
|
+
if (!deps.awaitPermissionVerdict) return c.json({ timeout: true });
|
|
19462
|
+
const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
|
|
19463
|
+
return c.json(verdict);
|
|
19464
|
+
});
|
|
19361
19465
|
app53.post("/webchat-channel/received", async (c) => {
|
|
19362
19466
|
const body = await c.req.json().catch(() => null);
|
|
19363
19467
|
const key = body?.key;
|
|
@@ -19378,10 +19482,13 @@ var SWEEP_INTERVAL_MS2 = 15e3;
|
|
|
19378
19482
|
function channelIdleMs() {
|
|
19379
19483
|
return Number(process.env.CHANNEL_PTY_IDLE_MS ?? String(5 * 6e4));
|
|
19380
19484
|
}
|
|
19485
|
+
function permissionVerdictTtlMs() {
|
|
19486
|
+
return Number(process.env.WEBCHAT_PERMISSION_TTL_MS ?? String(5 * 6e4));
|
|
19487
|
+
}
|
|
19381
19488
|
function keyDisplay(key) {
|
|
19382
19489
|
return key.startsWith("session:") ? key.slice(0, "session:".length + 8) : key.slice(0, 8);
|
|
19383
19490
|
}
|
|
19384
|
-
var WebchatGateway = class {
|
|
19491
|
+
var WebchatGateway = class _WebchatGateway {
|
|
19385
19492
|
constructor(deps) {
|
|
19386
19493
|
this.deps = deps;
|
|
19387
19494
|
}
|
|
@@ -19394,6 +19501,12 @@ var WebchatGateway = class {
|
|
|
19394
19501
|
* /webchat-channel/reply resolves it. Admin webchat registers none (its
|
|
19395
19502
|
* browser reader tails the JSONL), so handleReply is a no-op there. */
|
|
19396
19503
|
replyAwaiters = /* @__PURE__ */ new Map();
|
|
19504
|
+
/** Task 940 — open permission prompts awaiting an operator verdict, keyed
|
|
19505
|
+
* `${key}::${requestId}`. The channel server registers one via a held-open
|
|
19506
|
+
* POST (awaitPermissionVerdict); the /chat Allow/Deny button resolves it
|
|
19507
|
+
* (resolvePermissionVerdict); the session pointer surfaces the oldest open
|
|
19508
|
+
* one for that key (pendingPromptFor). */
|
|
19509
|
+
pendingPrompts = /* @__PURE__ */ new Map();
|
|
19397
19510
|
/** Task 756 — live public sessions, for the idle reaper + session-end review.
|
|
19398
19511
|
* Admin sessions are never recorded here (they never reap). */
|
|
19399
19512
|
publicSessions = /* @__PURE__ */ new Map();
|
|
@@ -19416,6 +19529,54 @@ var WebchatGateway = class {
|
|
|
19416
19529
|
});
|
|
19417
19530
|
});
|
|
19418
19531
|
}
|
|
19532
|
+
/** Task 940 — register an open permission prompt and hold for the operator's
|
|
19533
|
+
* verdict. Resolves with `{behavior}` when resolvePermissionVerdict fires for
|
|
19534
|
+
* this key+id, or `{timeout:true}` after `timeoutMs` (the channel server's
|
|
19535
|
+
* held-open POST returns either; on timeout it emits no verdict and the local
|
|
19536
|
+
* terminal dialog stays answerable). */
|
|
19537
|
+
awaitPermissionVerdict(p, timeoutMs) {
|
|
19538
|
+
const k = _WebchatGateway.promptKey(p.key, p.requestId);
|
|
19539
|
+
return new Promise((resolve34) => {
|
|
19540
|
+
this.pendingPrompts.get(k)?.resolve({ timeout: true });
|
|
19541
|
+
const timer2 = setTimeout(() => {
|
|
19542
|
+
this.pendingPrompts.delete(k);
|
|
19543
|
+
resolve34({ timeout: true });
|
|
19544
|
+
}, timeoutMs);
|
|
19545
|
+
if (timer2.unref) timer2.unref();
|
|
19546
|
+
this.pendingPrompts.set(k, {
|
|
19547
|
+
...p,
|
|
19548
|
+
at: Date.now(),
|
|
19549
|
+
resolve: (r) => {
|
|
19550
|
+
clearTimeout(timer2);
|
|
19551
|
+
this.pendingPrompts.delete(k);
|
|
19552
|
+
resolve34(r);
|
|
19553
|
+
}
|
|
19554
|
+
});
|
|
19555
|
+
console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
|
|
19556
|
+
});
|
|
19557
|
+
}
|
|
19558
|
+
/** Task 940 — the operator's Allow/Deny answer for an open prompt. Returns
|
|
19559
|
+
* false (and is a no-op) when no prompt with this key+id is open — a late or
|
|
19560
|
+
* duplicate click. */
|
|
19561
|
+
resolvePermissionVerdict(key, requestId, behavior) {
|
|
19562
|
+
const entry = this.pendingPrompts.get(_WebchatGateway.promptKey(key, requestId));
|
|
19563
|
+
if (!entry) return false;
|
|
19564
|
+
entry.resolve({ behavior });
|
|
19565
|
+
console.error(`[webchat:perm] op=verdict key=${keyDisplay(key)} id=${requestId} behavior=${behavior}`);
|
|
19566
|
+
return true;
|
|
19567
|
+
}
|
|
19568
|
+
/** Task 940 — the oldest open prompt for `key`, for the session pointer's
|
|
19569
|
+
* Allow/Deny card. null when none is open. */
|
|
19570
|
+
pendingPromptFor(key) {
|
|
19571
|
+
let oldest = null;
|
|
19572
|
+
for (const p of this.pendingPrompts.values()) {
|
|
19573
|
+
if (p.key === key && (!oldest || p.at < oldest.at)) oldest = p;
|
|
19574
|
+
}
|
|
19575
|
+
return oldest ? { requestId: oldest.requestId, toolName: oldest.toolName, description: oldest.description, inputPreview: oldest.inputPreview } : null;
|
|
19576
|
+
}
|
|
19577
|
+
static promptKey(key, requestId) {
|
|
19578
|
+
return `${key}::${requestId}`;
|
|
19579
|
+
}
|
|
19419
19580
|
/** Stamp the op=reply lifeline and resolve any held-open awaiter for `key`.
|
|
19420
19581
|
* Called by the /reply route's onReply. The first reply after registration
|
|
19421
19582
|
* wins; a later reply for the same key finds no awaiter and only logs. */
|
|
@@ -19478,7 +19639,8 @@ var WebchatGateway = class {
|
|
|
19478
19639
|
`[webchat:inbound] op=channel-received key=${key} messageId=${messageId}${found ? "" : " note=unknown"}`
|
|
19479
19640
|
);
|
|
19480
19641
|
},
|
|
19481
|
-
onReply: (key, text) => this.handleReply(key, text)
|
|
19642
|
+
onReply: (key, text) => this.handleReply(key, text),
|
|
19643
|
+
awaitPermissionVerdict: (p) => this.awaitPermissionVerdict(p, permissionVerdictTtlMs())
|
|
19482
19644
|
});
|
|
19483
19645
|
}
|
|
19484
19646
|
/** Run one reconciliation pass: log every terminal delivery event the sweep
|
|
@@ -19526,6 +19688,9 @@ var WebchatGateway = class {
|
|
|
19526
19688
|
// Task 800 — only present on a session-targeted launch, so the
|
|
19527
19689
|
// default-path call shape stays byte-identical.
|
|
19528
19690
|
...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {},
|
|
19691
|
+
// The authenticated admin's userId on an admin bootstrap inbound; the
|
|
19692
|
+
// default-path call shape stays byte-identical when absent.
|
|
19693
|
+
...input.adminUserId !== void 0 ? { adminUserId: input.adminUserId } : {},
|
|
19529
19694
|
// Task 756 — public spawn params on a role:'public' inbound.
|
|
19530
19695
|
...input.public !== void 0 ? { public: input.public } : {}
|
|
19531
19696
|
});
|
|
@@ -19560,6 +19725,7 @@ function buildPublicWebchatSpawnRequest(input) {
|
|
|
19560
19725
|
...sliceToken ? { sliceToken } : {},
|
|
19561
19726
|
...personId ? { personId } : {},
|
|
19562
19727
|
...visitorId ? { visitorId } : {},
|
|
19728
|
+
...input.previousContext ? { previousContext: input.previousContext } : {},
|
|
19563
19729
|
name,
|
|
19564
19730
|
webchatChannel: { key: input.key, gatewayUrl: input.gatewayUrl, serverPath: input.serverPath }
|
|
19565
19731
|
};
|
|
@@ -20032,14 +20198,27 @@ waGateway.startSweeper();
|
|
|
20032
20198
|
var webchatGateway = new WebchatGateway({
|
|
20033
20199
|
gatewayUrl: webchatGatewayUrl(),
|
|
20034
20200
|
serverPath: webchatServerPath(),
|
|
20035
|
-
ensureChannelSession: async ({ accountId, key, role, gatewayUrl, serverPath, sessionId, public: pub }) => {
|
|
20201
|
+
ensureChannelSession: async ({ accountId, key, role, adminUserId, gatewayUrl, serverPath, sessionId, public: pub }) => {
|
|
20036
20202
|
if (role === "public") {
|
|
20037
20203
|
if (!pub) {
|
|
20038
20204
|
console.error(`[webchat:inbound] op=spawn-refused key=${key} role=public reason=missing-public-params`);
|
|
20039
20205
|
return;
|
|
20040
20206
|
}
|
|
20207
|
+
let previousContext;
|
|
20208
|
+
if (pub.sliceToken) {
|
|
20209
|
+
const session = getSession();
|
|
20210
|
+
try {
|
|
20211
|
+
const writes = await fetchSliceWrites(session, pub.sliceToken, accountId);
|
|
20212
|
+
previousContext = formatPreviousContext(writes) ?? void 0;
|
|
20213
|
+
console.log(`[webchat:inbound] op=slice-readback key=${key} writes=${writes.length} injected=${previousContext ? "yes" : "no"}`);
|
|
20214
|
+
} catch (err) {
|
|
20215
|
+
console.error(`[webchat:inbound] op=slice-readback-failed key=${key} err=${err instanceof Error ? err.message : String(err)}`);
|
|
20216
|
+
} finally {
|
|
20217
|
+
await session.close();
|
|
20218
|
+
}
|
|
20219
|
+
}
|
|
20041
20220
|
const result2 = await managerSpawn(
|
|
20042
|
-
buildPublicWebchatSpawnRequest({ accountId, key, gatewayUrl, serverPath, public: pub })
|
|
20221
|
+
buildPublicWebchatSpawnRequest({ accountId, key, gatewayUrl, serverPath, previousContext, public: pub })
|
|
20043
20222
|
);
|
|
20044
20223
|
if ("error" in result2) {
|
|
20045
20224
|
console.error(`[webchat:inbound] op=spawn-failed key=${key} role=public error=${result2.error} status=${result2.status}`);
|
|
@@ -20048,10 +20227,11 @@ var webchatGateway = new WebchatGateway({
|
|
|
20048
20227
|
return { sessionId: result2.sessionId };
|
|
20049
20228
|
}
|
|
20050
20229
|
const result = await managerRcSpawn({
|
|
20051
|
-
sessionId: sessionId ?? adminSessionIdFor(accountId, key),
|
|
20230
|
+
sessionId: sessionId ?? adminSessionIdFor(accountId, key, adminUserId),
|
|
20052
20231
|
role: "admin",
|
|
20053
20232
|
channel: "webchat",
|
|
20054
20233
|
senderId: key,
|
|
20234
|
+
adminUserId,
|
|
20055
20235
|
webchatChannel: { key, gatewayUrl, serverPath },
|
|
20056
20236
|
logContext: `channel=webchat key=${key} role=${role}`
|
|
20057
20237
|
});
|
|
@@ -20385,7 +20565,12 @@ app52.route("/api/chat", chatRoutes);
|
|
|
20385
20565
|
app52.route("/api/whatsapp", whatsapp_default);
|
|
20386
20566
|
app52.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
20387
20567
|
app52.route("/api/public-reader", public_reader_default);
|
|
20388
|
-
app52.route("/api/webchat", createWebchatRoutes({
|
|
20568
|
+
app52.route("/api/webchat", createWebchatRoutes({
|
|
20569
|
+
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
20570
|
+
// Task 940 — the permission relay's pointer read + verdict write.
|
|
20571
|
+
pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
|
|
20572
|
+
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
20573
|
+
}));
|
|
20389
20574
|
app52.route("/api/webchat/greeting", webchat_greeting_default);
|
|
20390
20575
|
app52.route("/api/telegram", telegram_default);
|
|
20391
20576
|
app52.route("/api/quickbooks", quickbooks_default);
|
|
@@ -20565,7 +20750,6 @@ ${clientErrorReporterScript}
|
|
|
20565
20750
|
}
|
|
20566
20751
|
return html;
|
|
20567
20752
|
}
|
|
20568
|
-
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
20569
20753
|
function loadBrandingCache(agentSlug) {
|
|
20570
20754
|
const configDir2 = join28(homedir3(), BRAND.configDir);
|
|
20571
20755
|
try {
|
|
@@ -20583,36 +20767,6 @@ function resolveDefaultSlug() {
|
|
|
20583
20767
|
if (!account) return null;
|
|
20584
20768
|
return resolveDefaultAgentSlug(account.accountDir);
|
|
20585
20769
|
}
|
|
20586
|
-
function wantsNextSurface(c) {
|
|
20587
|
-
return c.req.query("surface") === "next";
|
|
20588
|
-
}
|
|
20589
|
-
function brandedPublicHtml(agentSlug) {
|
|
20590
|
-
const baseHtml = cachedHtml("public.html");
|
|
20591
|
-
if (!agentSlug) return baseHtml;
|
|
20592
|
-
const cached3 = brandedHtmlCache.get(agentSlug);
|
|
20593
|
-
const branding = loadBrandingCache(agentSlug);
|
|
20594
|
-
if (!branding) return baseHtml;
|
|
20595
|
-
const brandHash = JSON.stringify(branding).length;
|
|
20596
|
-
if (cached3 && cached3.mtime === brandHash) return cached3.html;
|
|
20597
|
-
const title = escapeHtml(branding.name);
|
|
20598
|
-
const description = branding.tagline ? escapeHtml(branding.tagline) : "";
|
|
20599
|
-
const themeColor = branding.primaryColor || "";
|
|
20600
|
-
const ogImage = branding.logoUrl || "";
|
|
20601
|
-
const favicon = branding.faviconUrl || "";
|
|
20602
|
-
const metaTags = [
|
|
20603
|
-
` <title>${title}</title>`,
|
|
20604
|
-
favicon ? ` <link rel="icon" href="${escapeHtml(favicon)}">` : ` <link rel="icon" href="${escapeHtml(brandFaviconPath)}">`,
|
|
20605
|
-
themeColor ? ` <meta name="theme-color" content="${escapeHtml(themeColor)}">` : "",
|
|
20606
|
-
` <meta property="og:title" content="${title}">`,
|
|
20607
|
-
description ? ` <meta property="og:description" content="${description}">` : "",
|
|
20608
|
-
ogImage ? ` <meta property="og:image" content="${escapeHtml(ogImage)}">` : "",
|
|
20609
|
-
' <meta property="og:type" content="website">'
|
|
20610
|
-
].filter(Boolean).join("\n");
|
|
20611
|
-
const html = baseHtml.replace(` <title>${escapeHtml(BRAND.productName)}</title>
|
|
20612
|
-
<link rel="icon" href="${escapeHtml(brandFaviconPath)}">`, metaTags);
|
|
20613
|
-
brandedHtmlCache.set(agentSlug, { html, mtime: brandHash });
|
|
20614
|
-
return html;
|
|
20615
|
-
}
|
|
20616
20770
|
function escapeHtml(s) {
|
|
20617
20771
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
20618
20772
|
}
|
|
@@ -20636,8 +20790,7 @@ app52.get("/", (c) => {
|
|
|
20636
20790
|
);
|
|
20637
20791
|
}
|
|
20638
20792
|
console.error(`[public-root] op=serve-default slug=${defaultSlug}`);
|
|
20639
|
-
|
|
20640
|
-
return c.html(brandedPublicHtml(defaultSlug));
|
|
20793
|
+
return c.html(cachedHtml("public.html"));
|
|
20641
20794
|
}
|
|
20642
20795
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
20643
20796
|
return c.html(cachedHtml("index.html"));
|
|
@@ -20645,13 +20798,11 @@ app52.get("/", (c) => {
|
|
|
20645
20798
|
app52.get("/public", (c) => {
|
|
20646
20799
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
20647
20800
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
20648
|
-
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
20649
20801
|
return c.html(cachedHtml("public.html"));
|
|
20650
20802
|
});
|
|
20651
20803
|
app52.get("/public-chat", (c) => {
|
|
20652
20804
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
20653
20805
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
20654
|
-
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
20655
20806
|
return c.html(cachedHtml("public.html"));
|
|
20656
20807
|
});
|
|
20657
20808
|
async function logViewerFetch(c, next) {
|
|
@@ -20705,7 +20856,7 @@ app52.post("/api/vnc/client-event", async (c) => {
|
|
|
20705
20856
|
return c.json({ ok: true });
|
|
20706
20857
|
});
|
|
20707
20858
|
app52.get("/g/:slug", (c) => {
|
|
20708
|
-
return c.html(
|
|
20859
|
+
return c.html(cachedHtml("public.html"));
|
|
20709
20860
|
});
|
|
20710
20861
|
for (const pwa of PWA_SURFACES) {
|
|
20711
20862
|
app52.get(pwa.manifestPath, (c) => {
|
|
@@ -20761,8 +20912,7 @@ app52.get("/:slug", async (c, next) => {
|
|
|
20761
20912
|
}
|
|
20762
20913
|
const branding = loadBrandingCache(slug);
|
|
20763
20914
|
console.error(`[public-catchall] served path=/${slug} slug=${slug} branding=${branding ? "hit" : "miss"}`);
|
|
20764
|
-
|
|
20765
|
-
return c.html(brandedPublicHtml(slug));
|
|
20915
|
+
return c.html(cachedHtml("public.html"));
|
|
20766
20916
|
}
|
|
20767
20917
|
await next();
|
|
20768
20918
|
});
|