@rubytech/create-maxy-code 0.1.503 → 0.1.504
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +33 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +32 -0
- package/payload/platform/plugins/work/PLUGIN.md +3 -3
- package/payload/platform/plugins/work/mcp/dist/__tests__/assignable-admins.test.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/assignable-admins.test.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/assignable-admins.test.js +55 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/assignable-admins.test.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js +33 -1
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-update-assign.test.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-update-assign.test.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-update-assign.test.js +73 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-update-assign.test.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/index.js +4 -1
- package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/lib/assignable-admins.d.ts +13 -0
- package/payload/platform/plugins/work/mcp/dist/lib/assignable-admins.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/lib/assignable-admins.js +66 -0
- package/payload/platform/plugins/work/mcp/dist/lib/assignable-admins.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts +8 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.js +31 -13
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-list.d.ts +4 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-list.d.ts.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-list.js +3 -2
- package/payload/platform/plugins/work/mcp/dist/tools/work-list.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-update.d.ts +7 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-update.d.ts.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-update.js +31 -0
- package/payload/platform/plugins/work/mcp/dist/tools/work-update.js.map +1 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/agents.html +18 -0
- package/payload/server/public/assets/{AdminLoginScreens-Bv_bKKeL.js → AdminLoginScreens-DWMR4KtI.js} +1 -1
- package/payload/server/public/assets/AdminShell-C8hBpL9K.js +2 -0
- package/payload/server/public/assets/{activity-DZFYDHNA.js → activity-DH3z4cv3.js} +1 -1
- package/payload/server/public/assets/admin-aaGhd2Yh.js +1 -0
- package/payload/server/public/assets/agents-SPu-clsf.js +1 -0
- package/payload/server/public/assets/{arc-CvlzUHOf.js → arc-DaI5MLTq.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-DWZIX5aV.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-I1Hs0RJA.js → architectureDiagram-Q4EWVU46-CBGVUEN9.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-Df5jTGtl.js → blockDiagram-DXYQGD6D-DS6dS4GZ.js} +1 -1
- package/payload/server/public/assets/{browser-Bt4-LKLU.js → browser-C_MJYN5k.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-B6WY5IDv.js → c4Diagram-AHTNJAMY-hBSBUZPt.js} +1 -1
- package/payload/server/public/assets/calendar-DA0h7dqW.js +1 -0
- package/payload/server/public/assets/channel-BEokjAeE.js +1 -0
- package/payload/server/public/assets/chat-Bg7dlM0I.js +1 -0
- package/payload/server/public/assets/chevron-left-BoDA12H8.js +1 -0
- package/payload/server/public/assets/chevron-right-DXjrO6qA.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-BsIIFDkc.js → chunk-2KRD3SAO-B6koUoB7.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-j9z1VtyC.js → chunk-336JU56O-BF6BRh8u.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-pbQ4PWBU.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-C9i7prxq.js → chunk-4BX2VUAB-7sO95xR2.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-DH0QVGcv.js → chunk-4TB4RGXK-GCTndJYx.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-Dnd_YCPA.js → chunk-55IACEB6-ggIJf_TC.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-D5sSz3yN.js → chunk-5FUZZQ4R-DeGmkimt.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-CJrwWjAT.js → chunk-5PVQY5BW-aFIQKk_U.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-SjP6_hUw.js → chunk-67CJDMHE-LS8rUbii.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-fAuhVJD0.js → chunk-7N4EOEYR-JKOVngS0.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-DZxa7KVg.js → chunk-AA7GKIK3-CoXnTVK6.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-DjeG3eQ-.js → chunk-BSJP7CBP-CcsqObFg.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-RYQULNJm.js → chunk-CIAEETIT-CpsybR7q.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-Cahapnon.js → chunk-EDXVE4YY-BZ2I9PSq.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-1146X1L4.js → chunk-ENJZ2VHE-DbTwt6OZ.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-BCFumtcP.js → chunk-FMBD7UC4-D27VnSCa.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-CkrtX8Zt.js → chunk-FOC6F5B3-C0tU2UFl.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-Ba1y3DaW.js → chunk-ICPOFSXX-UPPu2OIq.js} +1 -1
- package/payload/server/public/assets/{chunk-K5T4RW27-CF-PI3uQ.js → chunk-K5T4RW27-DIKxqyYw.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-SFFC6ZC-.js → chunk-KGLVRYIC-CiL4YVLo.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-DbOLEP4R.js → chunk-LIHQZDEY-ejKezVlD.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-VB963bkN.js → chunk-ORNJ4GCN-Cc0vqc-D.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-DWYY1pQa.js → chunk-OYMX7WX6-Drxn1qG0.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-Dhlh7Pkk.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-DAH1diYP.js → chunk-U2HBQHQK-DnbQIkRP.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-Dmw9coXz.js → chunk-X2U36JSP-CauTSVWg.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-DaAUON1-.js → chunk-XPW4576I-DZqqB9Zi.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-BUcfkEef.js → chunk-YZCP3GAM-BGHo4Li-.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BLD-vFRO.js → chunk-ZZ45TVLE-DWGJKPd7.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-D2z_ZV1x.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BJwJoNEK.js +1 -0
- package/payload/server/public/assets/clock-BceBgZP1.js +1 -0
- package/payload/server/public/assets/clone-Bn7XXVhr.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-CoZX0uki.js → cose-bilkent-S5V4N54A-D-95BzXL.js} +1 -1
- package/payload/server/public/assets/{dagre-Bmjs8zJA.js → dagre-BZYNBHvT.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BZCP2wnq.js → dagre-KV5264BT-DyU4HQLQ.js} +1 -1
- package/payload/server/public/assets/data-rNLaurgY.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-8Nt9a4xX.js → diagram-5BDNPKRD-CCttJ9XA.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-vh5tcYqJ.js → diagram-G4DWMVQ6-DvkpgSLO.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DGf--jc8.js → diagram-MMDJMWI5-DHmW5Y9k.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CsO7TIdw.js → diagram-TYMM5635-C6T4hwzO.js} +1 -1
- package/payload/server/public/assets/{dist-cdnE4DqK.js → dist-QvbmK1IP.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-4a78yV8_.js → erDiagram-SMLLAGMA-5v_o7s3T.js} +1 -1
- package/payload/server/public/assets/{file-text-BpLcZKld.js → file-text-RCoSeOpD.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BoQBXs6t.js → flowDiagram-DWJPFMVM-3UhCDsjt.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-CvzqwCC8.js → ganttDiagram-T4ZO3ILL-F2zgHIIQ.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-C-FvNTHZ.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-D_nBxay_.js → gitGraphDiagram-UUTBAWPF-oQc1N3dT.js} +1 -1
- package/payload/server/public/assets/{graph-HB0199x-.js → graph-Dm-YZeNP.js} +12 -12
- package/payload/server/public/assets/{graph-labels-Bx19ZYvJ.js → graph-labels-DJV0aIG5.js} +1 -1
- package/payload/server/public/assets/{graphlib-D0NdsKJI.js → graphlib-DY4-AT2Q.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-BjLPgHAC.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CXNKLTui.js +2 -0
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-auW-s0i0.js → ishikawaDiagram-UXIWVN3A-wJhSOkuw.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-3Q6AWK4A.js → journeyDiagram-VCZTEJTY-DgadC6Pz.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-B4MPFp98.js → kanban-definition-6JOO6SKY-Bs4nQqXI.js} +1 -1
- package/payload/server/public/assets/{line-26MdeG5Z.js → line-Bnmxy1hO.js} +1 -1
- package/payload/server/public/assets/{linear-Dq9s_bDO.js → linear-RvwZxFzh.js} +1 -1
- package/payload/server/public/assets/{maximize-2-BhR-Ec21.js → maximize-2-DcESsKbu.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-vLEpOXgf.js → mermaid-parser.core-DeNV8RtA.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-Durk4m6D.js → mermaid.core-BU9IiSCP.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DOIg-TyG.js → mindmap-definition-QFDTVHPH-D1PMUxxm.js} +1 -1
- package/payload/server/public/assets/operator-Dlkw1sXJ.js +1 -0
- package/payload/server/public/assets/packet-4T2RLAQJ-BBAZASfb.js +1 -0
- package/payload/server/public/assets/page-Dl-mgQUu.js +32 -0
- package/payload/server/public/assets/page-DoyJrk8E.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-CCJUnMeG.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DtgBHZfi.js → pieDiagram-DEJITSTG-BzdNzoKA.js} +1 -1
- package/payload/server/public/assets/{public-DZHPsyKX.js → public-C-UHWk_S.js} +1 -1
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BTc5Qn2y.js → quadrantDiagram-34T5L4WZ-oFr1MJRO.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-BsRU8Aep.js +1 -0
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-BNgOO5YW.js → requirementDiagram-MS252O5E-C9QBQxDh.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-D9qOBLig.js → rotate-ccw-C1nRSAzP.js} +1 -1
- package/payload/server/public/assets/routines-qdAZ0sA4.js +1 -0
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-MyUATmVt.js → sankeyDiagram-XADWPNL6-c_y3bvVv.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CBJrF5Vi.js → sequenceDiagram-FGHM5R23-YwlCBPHE.js} +1 -1
- package/payload/server/public/assets/skills-B78wr822.js +1 -0
- package/payload/server/public/assets/{src-DekKlUCp.js → src-C2WwTWSY.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-6wbUjn1Q.js → stateDiagram-FHFEXIEX-BFE3e-FM.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CpjB4ykI.js +1 -0
- package/payload/server/public/assets/tasks-DbIsS-vW.js +1 -0
- package/payload/server/public/assets/{time-entry-format-RkCW7hKu.js → time-entry-format-BhlltPP8.js} +1 -1
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BHjTMCGY.js → timeline-definition-GMOUNBTQ-azqhmRwZ.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BDzhKA6v.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-epHpdeWa.js +1 -0
- package/payload/server/public/assets/{triangle-alert-k8ulav-N.js → triangle-alert-rEVGyIhi.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-DN1WA5vU.js → useCopyFeedback-DzpXjm9d.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-DVmWZxar.js +9 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-fvBunpOC.css → useSubAccountSwitcher-wP8cOzPj.css} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-v--TIxaM.js → useVoiceRecorder-CRRmPjYr.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-yo3-cf0U.js → vennDiagram-DHZGUBPP-Da2RfFs8.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-DNSZCrxV.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DZlyFzrg.js → wardleyDiagram-NUSXRM2D-HdrdBYES.js} +1 -1
- package/payload/server/public/assets/{wrench-CKhz8KnQ.js → wrench-oeLti270.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-B5HV5h80.js → xychartDiagram-5P7HB3ND-DMk6rTcQ.js} +1 -1
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +8 -8
- package/payload/server/public/chat.html +14 -15
- package/payload/server/public/data.html +12 -12
- package/payload/server/public/graph.html +10 -10
- package/payload/server/public/index.html +15 -16
- package/payload/server/public/operator.html +15 -16
- package/payload/server/public/public.html +14 -15
- package/payload/server/public/routines.html +7 -7
- package/payload/server/public/skills.html +6 -6
- package/payload/server/public/tasks.html +7 -7
- package/payload/server/server.js +696 -430
- package/payload/server/public/assets/AdminShell-Gq8DU_ig.js +0 -2
- package/payload/server/public/assets/admin-DLUOixl6.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-BQc779DH.js +0 -1
- package/payload/server/public/assets/bot-CrEhKW1l.js +0 -1
- package/payload/server/public/assets/calendar-B8ujkn_K.js +0 -1
- package/payload/server/public/assets/channel-AqnC3SHu.js +0 -1
- package/payload/server/public/assets/chat-lQXd6gsM.js +0 -1
- package/payload/server/public/assets/chevron-left-CQ8rcBoO.js +0 -1
- package/payload/server/public/assets/chevron-right-CSRSqblN.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-CO02gU5d.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-BiFMbK8t.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BdRqzScB.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-ChPLgHbS.js +0 -1
- package/payload/server/public/assets/clock-B7Ba8AZL.js +0 -1
- package/payload/server/public/assets/clone-TKtrjWBC.js +0 -1
- package/payload/server/public/assets/data-BdlGqjKM.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DfcaTE9L.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-CD-u6gw9.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-C6gPQCvO.js +0 -2
- package/payload/server/public/assets/operator-Bf3hP3qo.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-BaLYeIrU.js +0 -1
- package/payload/server/public/assets/page-Bs24tO-C.js +0 -32
- package/payload/server/public/assets/page-FnCmAeHc.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-CL-XJtk-.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-Cn-g6F_h.js +0 -1
- package/payload/server/public/assets/routines-lGiYaMiX.js +0 -1
- package/payload/server/public/assets/skills-y-h0P9rC.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BdMdfBeC.js +0 -1
- package/payload/server/public/assets/tasks-Cyc1EfLA.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CmZoOGlC.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-H27WFS-y.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-iQGqNJhI.js +0 -9
- package/payload/server/public/assets/wardley-RL74JXVD-DNpWIvU4.js +0 -1
- /package/payload/server/public/assets/{chunk-CCr-iYLO.js → chunk-CltuBf4Z.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -146,7 +146,7 @@ var require_dist = __commonJS({
|
|
|
146
146
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
147
147
|
exports.ACTIVE_CANDIDATE_FLOOR = exports.SAME_SUBJECT_COSINE = void 0;
|
|
148
148
|
exports.formatStandingRulesBlock = formatStandingRulesBlock2;
|
|
149
|
-
exports.resolveOwnerUserId =
|
|
149
|
+
exports.resolveOwnerUserId = resolveOwnerUserId3;
|
|
150
150
|
exports.queryActiveRuleCandidates = queryActiveRuleCandidates;
|
|
151
151
|
exports.resolveActiveRules = resolveActiveRules2;
|
|
152
152
|
exports.activeRuleSet = activeRuleSet;
|
|
@@ -159,7 +159,7 @@ var require_dist = __commonJS({
|
|
|
159
159
|
return `## Standing rules
|
|
160
160
|
${lines.join("\n")}`;
|
|
161
161
|
}
|
|
162
|
-
async function
|
|
162
|
+
async function resolveOwnerUserId3(session, accountId) {
|
|
163
163
|
const res = await session.run(`
|
|
164
164
|
MATCH (au:AdminUser {accountId: $accountId, role: 'owner'})
|
|
165
165
|
RETURN au.userId AS userId
|
|
@@ -194,7 +194,7 @@ ${lines.join("\n")}`;
|
|
|
194
194
|
async function resolveCandidates(session, accountId) {
|
|
195
195
|
let ownerUserId;
|
|
196
196
|
try {
|
|
197
|
-
ownerUserId = await
|
|
197
|
+
ownerUserId = await resolveOwnerUserId3(session, accountId);
|
|
198
198
|
} catch {
|
|
199
199
|
return { candidates: [], ownerUserId: null, source: "owner-error" };
|
|
200
200
|
}
|
|
@@ -1753,10 +1753,10 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1753
1753
|
};
|
|
1754
1754
|
|
|
1755
1755
|
// server/index.ts
|
|
1756
|
-
import { readFileSync as
|
|
1756
|
+
import { readFileSync as readFileSync47, existsSync as existsSync46, watchFile, readdirSync as readdirSync28, statSync as statSync20 } from "fs";
|
|
1757
1757
|
import { spawn as spawn3 } from "child_process";
|
|
1758
1758
|
import { createHash as createHash7 } from "crypto";
|
|
1759
|
-
import { resolve as
|
|
1759
|
+
import { resolve as resolve44, join as join47, basename as basename14 } from "path";
|
|
1760
1760
|
import { homedir as homedir4 } from "os";
|
|
1761
1761
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1762
1762
|
|
|
@@ -3030,7 +3030,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
3030
3030
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
3031
3031
|
console.error(`${TAG6} draining credential save queue\u2026`);
|
|
3032
3032
|
const timer = new Promise(
|
|
3033
|
-
(
|
|
3033
|
+
(resolve45) => setTimeout(() => resolve45("timeout"), timeoutMs)
|
|
3034
3034
|
);
|
|
3035
3035
|
const result = await Promise.race([
|
|
3036
3036
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -3207,11 +3207,11 @@ async function createWaSocket(opts) {
|
|
|
3207
3207
|
return sock;
|
|
3208
3208
|
}
|
|
3209
3209
|
async function waitForConnection(sock) {
|
|
3210
|
-
return new Promise((
|
|
3210
|
+
return new Promise((resolve45, reject) => {
|
|
3211
3211
|
const handler = (update) => {
|
|
3212
3212
|
if (update.connection === "open") {
|
|
3213
3213
|
sock.ev.off("connection.update", handler);
|
|
3214
|
-
|
|
3214
|
+
resolve45();
|
|
3215
3215
|
}
|
|
3216
3216
|
if (update.connection === "close") {
|
|
3217
3217
|
sock.ev.off("connection.update", handler);
|
|
@@ -3319,7 +3319,7 @@ function isTimeoutError(err) {
|
|
|
3319
3319
|
return Boolean(err?.__maxyTimeout);
|
|
3320
3320
|
}
|
|
3321
3321
|
function withTimeout(label, promise, timeoutMs) {
|
|
3322
|
-
return new Promise((
|
|
3322
|
+
return new Promise((resolve45, reject) => {
|
|
3323
3323
|
const timer = setTimeout(() => {
|
|
3324
3324
|
const err = new Error(`${label} timed out after ${timeoutMs}ms`);
|
|
3325
3325
|
err.__maxyTimeout = true;
|
|
@@ -3329,7 +3329,7 @@ function withTimeout(label, promise, timeoutMs) {
|
|
|
3329
3329
|
promise.then(
|
|
3330
3330
|
(value) => {
|
|
3331
3331
|
clearTimeout(timer);
|
|
3332
|
-
|
|
3332
|
+
resolve45(value);
|
|
3333
3333
|
},
|
|
3334
3334
|
(err) => {
|
|
3335
3335
|
clearTimeout(timer);
|
|
@@ -4394,8 +4394,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
4394
4394
|
const { givenName, familyName } = splitName(input.pushName);
|
|
4395
4395
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
4396
4396
|
let release;
|
|
4397
|
-
const mine = new Promise((
|
|
4398
|
-
release =
|
|
4397
|
+
const mine = new Promise((resolve45) => {
|
|
4398
|
+
release = resolve45;
|
|
4399
4399
|
});
|
|
4400
4400
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
4401
4401
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -6132,11 +6132,11 @@ async function connectWithReconnect(conn) {
|
|
|
6132
6132
|
console.error(
|
|
6133
6133
|
`${TAG17} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
6134
6134
|
);
|
|
6135
|
-
await new Promise((
|
|
6136
|
-
const timer = setTimeout(
|
|
6135
|
+
await new Promise((resolve45) => {
|
|
6136
|
+
const timer = setTimeout(resolve45, delay);
|
|
6137
6137
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
6138
6138
|
clearTimeout(timer);
|
|
6139
|
-
|
|
6139
|
+
resolve45();
|
|
6140
6140
|
}, { once: true });
|
|
6141
6141
|
});
|
|
6142
6142
|
}
|
|
@@ -6144,16 +6144,16 @@ async function connectWithReconnect(conn) {
|
|
|
6144
6144
|
}
|
|
6145
6145
|
}
|
|
6146
6146
|
function waitForDisconnectEvent(conn) {
|
|
6147
|
-
return new Promise((
|
|
6147
|
+
return new Promise((resolve45) => {
|
|
6148
6148
|
if (!conn.sock) {
|
|
6149
|
-
|
|
6149
|
+
resolve45();
|
|
6150
6150
|
return;
|
|
6151
6151
|
}
|
|
6152
6152
|
const sock = conn.sock;
|
|
6153
6153
|
const handler = (update) => {
|
|
6154
6154
|
if (update.connection === "close") {
|
|
6155
6155
|
sock.ev.off("connection.update", handler);
|
|
6156
|
-
|
|
6156
|
+
resolve45();
|
|
6157
6157
|
}
|
|
6158
6158
|
};
|
|
6159
6159
|
sock.ev.on("connection.update", handler);
|
|
@@ -6627,8 +6627,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
6627
6627
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
6628
6628
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
6629
6629
|
let resolvePending;
|
|
6630
|
-
const sttPending = new Promise((
|
|
6631
|
-
resolvePending =
|
|
6630
|
+
const sttPending = new Promise((resolve45) => {
|
|
6631
|
+
resolvePending = resolve45;
|
|
6632
6632
|
});
|
|
6633
6633
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
6634
6634
|
try {
|
|
@@ -7017,20 +7017,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
7017
7017
|
|
|
7018
7018
|
// server/routes/health.ts
|
|
7019
7019
|
function checkPort(port2, timeoutMs = 500) {
|
|
7020
|
-
return new Promise((
|
|
7020
|
+
return new Promise((resolve45) => {
|
|
7021
7021
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
7022
7022
|
socket.setTimeout(timeoutMs);
|
|
7023
7023
|
socket.once("connect", () => {
|
|
7024
7024
|
socket.destroy();
|
|
7025
|
-
|
|
7025
|
+
resolve45(true);
|
|
7026
7026
|
});
|
|
7027
7027
|
socket.once("error", () => {
|
|
7028
7028
|
socket.destroy();
|
|
7029
|
-
|
|
7029
|
+
resolve45(false);
|
|
7030
7030
|
});
|
|
7031
7031
|
socket.once("timeout", () => {
|
|
7032
7032
|
socket.destroy();
|
|
7033
|
-
|
|
7033
|
+
resolve45(false);
|
|
7034
7034
|
});
|
|
7035
7035
|
});
|
|
7036
7036
|
}
|
|
@@ -7285,8 +7285,8 @@ function webchatTurnTimeoutMs() {
|
|
|
7285
7285
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
7286
7286
|
}
|
|
7287
7287
|
function createChatRoutes(deps) {
|
|
7288
|
-
const
|
|
7289
|
-
|
|
7288
|
+
const app70 = new Hono();
|
|
7289
|
+
app70.post("/", async (c) => {
|
|
7290
7290
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
7291
7291
|
const contentType = c.req.header("content-type") ?? "";
|
|
7292
7292
|
const account = resolveAccount();
|
|
@@ -7550,7 +7550,7 @@ ${result.result.text}` : result.result.text;
|
|
|
7550
7550
|
}
|
|
7551
7551
|
});
|
|
7552
7552
|
});
|
|
7553
|
-
return
|
|
7553
|
+
return app70;
|
|
7554
7554
|
}
|
|
7555
7555
|
|
|
7556
7556
|
// app/lib/channel-pty-bridge/admin-session-id.ts
|
|
@@ -7584,8 +7584,8 @@ function isLoopbackAddr(addr) {
|
|
|
7584
7584
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
7585
7585
|
}
|
|
7586
7586
|
function createScheduleInjectRoutes(deps) {
|
|
7587
|
-
const
|
|
7588
|
-
|
|
7587
|
+
const app70 = new Hono();
|
|
7588
|
+
app70.post("/", async (c) => {
|
|
7589
7589
|
const env = c.env;
|
|
7590
7590
|
const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
|
|
7591
7591
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
@@ -7686,7 +7686,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
7686
7686
|
console.error(`${TAG20} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
|
|
7687
7687
|
return c.json({ ok: true }, 200);
|
|
7688
7688
|
});
|
|
7689
|
-
return
|
|
7689
|
+
return app70;
|
|
7690
7690
|
}
|
|
7691
7691
|
|
|
7692
7692
|
// server/index.ts
|
|
@@ -8369,8 +8369,8 @@ async function startLogin(opts) {
|
|
|
8369
8369
|
await clearAuth(authDir);
|
|
8370
8370
|
let resolveCode = null;
|
|
8371
8371
|
let rejectCode = null;
|
|
8372
|
-
const codePromise = new Promise((
|
|
8373
|
-
resolveCode =
|
|
8372
|
+
const codePromise = new Promise((resolve45, reject) => {
|
|
8373
|
+
resolveCode = resolve45;
|
|
8374
8374
|
rejectCode = reject;
|
|
8375
8375
|
});
|
|
8376
8376
|
const codeTimer = setTimeout(
|
|
@@ -13993,8 +13993,8 @@ async function reapplyLeversViaManager() {
|
|
|
13993
13993
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
13994
13994
|
var sendSeq = 0;
|
|
13995
13995
|
function createWebchatRoutes(deps) {
|
|
13996
|
-
const
|
|
13997
|
-
|
|
13996
|
+
const app70 = new Hono();
|
|
13997
|
+
app70.post("/send", requireAdminSession, async (c) => {
|
|
13998
13998
|
let accountId;
|
|
13999
13999
|
try {
|
|
14000
14000
|
accountId = resolvePlatformAccountId();
|
|
@@ -14197,7 +14197,7 @@ ${note}` : note;
|
|
|
14197
14197
|
if (turnTimer.unref) turnTimer.unref();
|
|
14198
14198
|
return c.json({ ok: true });
|
|
14199
14199
|
});
|
|
14200
|
-
|
|
14200
|
+
app70.post("/interrupt", requireAdminSession, async (c) => {
|
|
14201
14201
|
const cacheKey = c.get("cacheKey");
|
|
14202
14202
|
const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
|
|
14203
14203
|
const primaryUserId = resolvePrimaryAdminUserId();
|
|
@@ -14225,7 +14225,7 @@ ${note}` : note;
|
|
|
14225
14225
|
}
|
|
14226
14226
|
return c.json({ ok: true, stopped: outcome.stopped, intId: outcome.intId, deadChild: outcome.deadChild }, 200);
|
|
14227
14227
|
});
|
|
14228
|
-
|
|
14228
|
+
app70.post("/settings", requireAdminSession, async (c) => {
|
|
14229
14229
|
const body = await c.req.json().catch(() => null);
|
|
14230
14230
|
const op = body?.op;
|
|
14231
14231
|
const value = body?.value;
|
|
@@ -14265,7 +14265,7 @@ ${note}` : note;
|
|
|
14265
14265
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
14266
14266
|
return c.json({ ok: true, settingsApplied });
|
|
14267
14267
|
});
|
|
14268
|
-
|
|
14268
|
+
app70.get("/session", requireAdminSession, async (c) => {
|
|
14269
14269
|
let accountId;
|
|
14270
14270
|
try {
|
|
14271
14271
|
accountId = resolvePlatformAccountId();
|
|
@@ -14343,7 +14343,7 @@ ${note}` : note;
|
|
|
14343
14343
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
14344
14344
|
return c.json({ sessionId, projectDir, source, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
|
|
14345
14345
|
});
|
|
14346
|
-
|
|
14346
|
+
app70.post("/permission-verdict", requireAdminSession, async (c) => {
|
|
14347
14347
|
const body = await c.req.json().catch(() => null);
|
|
14348
14348
|
const sessionId = body?.sessionId;
|
|
14349
14349
|
const requestId = body?.request_id;
|
|
@@ -14360,7 +14360,7 @@ ${note}` : note;
|
|
|
14360
14360
|
const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
|
|
14361
14361
|
return c.json({ ok });
|
|
14362
14362
|
});
|
|
14363
|
-
return
|
|
14363
|
+
return app70;
|
|
14364
14364
|
}
|
|
14365
14365
|
|
|
14366
14366
|
// server/routes/webchat-greeting.ts
|
|
@@ -15716,15 +15716,15 @@ function operatorRoleFor(config, userId) {
|
|
|
15716
15716
|
async function buildAccountOptionList(accounts, userId) {
|
|
15717
15717
|
const houseAccount = accounts.find((a) => a.config.role === "house");
|
|
15718
15718
|
console.log(`[admin-accounts] op=list count=${accounts.length} house=${houseAccount?.accountId ?? "none"}`);
|
|
15719
|
-
const
|
|
15719
|
+
const resolve45 = async (a) => {
|
|
15720
15720
|
const businessName = await fetchAccountName(a.accountId) || void 0;
|
|
15721
15721
|
return { accountId: a.accountId, businessName, role: operatorRoleFor(a.config, userId), isHouse: a.config.role === "house" };
|
|
15722
15722
|
};
|
|
15723
15723
|
const houseOptions = await Promise.all(
|
|
15724
|
-
accounts.filter((a) => a.config.role === "house").map(
|
|
15724
|
+
accounts.filter((a) => a.config.role === "house").map(resolve45)
|
|
15725
15725
|
);
|
|
15726
15726
|
const nonHouseOptions = await Promise.all(
|
|
15727
|
-
accounts.filter((a) => a.config.role !== "house").map(
|
|
15727
|
+
accounts.filter((a) => a.config.role !== "house").map(resolve45)
|
|
15728
15728
|
);
|
|
15729
15729
|
const sortKey = (o) => (o.businessName || o.accountId).toLowerCase();
|
|
15730
15730
|
nonHouseOptions.sort((x, y) => {
|
|
@@ -16169,13 +16169,21 @@ var session_upload_default = app17;
|
|
|
16169
16169
|
// server/routes/admin/agents.ts
|
|
16170
16170
|
import { resolve as resolve22 } from "path";
|
|
16171
16171
|
import { readdirSync as readdirSync21, readFileSync as readFileSync32, existsSync as existsSync30, rmSync as rmSync2 } from "fs";
|
|
16172
|
+
var SLUG_UNSAFE = (s) => s.includes("/") || s.includes("..") || s.includes("\\");
|
|
16173
|
+
var OWNED_DOCS = [
|
|
16174
|
+
{ file: "IDENTITY.md", key: "identity" },
|
|
16175
|
+
{ file: "SOUL.md", key: "soul" },
|
|
16176
|
+
{ file: "KNOWLEDGE.md", key: "knowledge" },
|
|
16177
|
+
{ file: "KNOWLEDGE-SUMMARY.md", key: "knowledgeSummary" }
|
|
16178
|
+
];
|
|
16172
16179
|
var app18 = new Hono();
|
|
16173
16180
|
app18.get("/", (c) => {
|
|
16174
16181
|
const account = resolveAccount();
|
|
16175
|
-
if (!account) return c.json({ agents: [] });
|
|
16182
|
+
if (!account) return c.json({ agents: [], skipped: 0 });
|
|
16176
16183
|
const agentsDir = resolve22(account.accountDir, "agents");
|
|
16177
|
-
if (!existsSync30(agentsDir)) return c.json({ agents: [] });
|
|
16184
|
+
if (!existsSync30(agentsDir)) return c.json({ agents: [], skipped: 0 });
|
|
16178
16185
|
const agents = [];
|
|
16186
|
+
let skipped = 0;
|
|
16179
16187
|
try {
|
|
16180
16188
|
const entries = readdirSync21(agentsDir, { withFileTypes: true });
|
|
16181
16189
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
@@ -16191,14 +16199,66 @@ app18.get("/", (c) => {
|
|
|
16191
16199
|
status: config.status ?? "unknown"
|
|
16192
16200
|
});
|
|
16193
16201
|
} catch {
|
|
16202
|
+
skipped++;
|
|
16194
16203
|
console.error(`[admin/agents] failed to parse config.json for agent "${entry.name}" \u2014 skipping`);
|
|
16195
16204
|
}
|
|
16196
16205
|
}
|
|
16197
16206
|
} catch (err) {
|
|
16198
16207
|
console.error(`[admin/agents] failed to scan agents directory: ${err}`);
|
|
16199
|
-
return c.json({ agents: [] });
|
|
16208
|
+
return c.json({ agents: [], skipped: 0 });
|
|
16200
16209
|
}
|
|
16201
|
-
|
|
16210
|
+
console.log(`[admin/agents] op=list agents=${agents.length} skipped=${skipped}`);
|
|
16211
|
+
return c.json({ agents, skipped });
|
|
16212
|
+
});
|
|
16213
|
+
app18.get("/:slug", (c) => {
|
|
16214
|
+
const slug = c.req.param("slug");
|
|
16215
|
+
const account = resolveAccount();
|
|
16216
|
+
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
16217
|
+
if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
|
|
16218
|
+
const agentDir = resolve22(account.accountDir, "agents", slug);
|
|
16219
|
+
const configPath2 = resolve22(agentDir, "config.json");
|
|
16220
|
+
if (!existsSync30(configPath2)) return c.json({ error: "Agent not found" }, 404);
|
|
16221
|
+
let config;
|
|
16222
|
+
try {
|
|
16223
|
+
config = JSON.parse(readFileSync32(configPath2, "utf-8"));
|
|
16224
|
+
} catch {
|
|
16225
|
+
console.error(`[admin/agents] op=detail slug=${slug} error="config.json parse failed"`);
|
|
16226
|
+
return c.json({ error: "Agent config unreadable" }, 500);
|
|
16227
|
+
}
|
|
16228
|
+
const docs = {};
|
|
16229
|
+
const present = {};
|
|
16230
|
+
for (const { file, key } of OWNED_DOCS) {
|
|
16231
|
+
const p = resolve22(agentDir, file);
|
|
16232
|
+
try {
|
|
16233
|
+
if (existsSync30(p)) {
|
|
16234
|
+
docs[key] = readFileSync32(p, "utf-8");
|
|
16235
|
+
present[key] = true;
|
|
16236
|
+
} else {
|
|
16237
|
+
docs[key] = "";
|
|
16238
|
+
present[key] = false;
|
|
16239
|
+
}
|
|
16240
|
+
} catch {
|
|
16241
|
+
console.error(`[admin/agents] op=detail slug=${slug} doc=${file} error="read failed, treating as absent"`);
|
|
16242
|
+
docs[key] = "";
|
|
16243
|
+
present[key] = false;
|
|
16244
|
+
}
|
|
16245
|
+
}
|
|
16246
|
+
const found = Object.keys(present).filter((k) => present[k]);
|
|
16247
|
+
console.log(`[admin/agents] op=detail slug=${slug} present=${found.join(",") || "none"}`);
|
|
16248
|
+
return c.json({
|
|
16249
|
+
agent: {
|
|
16250
|
+
slug,
|
|
16251
|
+
displayName: config.displayName ?? slug,
|
|
16252
|
+
status: config.status ?? "unknown",
|
|
16253
|
+
model: config.model ?? null,
|
|
16254
|
+
knowledgeKeywords: config.knowledgeKeywords ?? [],
|
|
16255
|
+
identity: docs.identity,
|
|
16256
|
+
soul: docs.soul,
|
|
16257
|
+
knowledge: docs.knowledge,
|
|
16258
|
+
knowledgeSummary: docs.knowledgeSummary,
|
|
16259
|
+
present
|
|
16260
|
+
}
|
|
16261
|
+
});
|
|
16202
16262
|
});
|
|
16203
16263
|
app18.delete("/:slug", async (c) => {
|
|
16204
16264
|
const slug = c.req.param("slug");
|
|
@@ -16207,7 +16267,7 @@ app18.delete("/:slug", async (c) => {
|
|
|
16207
16267
|
if (slug === "admin") {
|
|
16208
16268
|
return c.json({ error: "Cannot delete the admin agent" }, 403);
|
|
16209
16269
|
}
|
|
16210
|
-
if (
|
|
16270
|
+
if (SLUG_UNSAFE(slug)) {
|
|
16211
16271
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
16212
16272
|
}
|
|
16213
16273
|
const agentDir = resolve22(account.accountDir, "agents", slug);
|
|
@@ -16237,7 +16297,7 @@ app18.post("/:slug/project", async (c) => {
|
|
|
16237
16297
|
if (slug === "admin") {
|
|
16238
16298
|
return c.json({ error: "Cannot project the admin agent" }, 403);
|
|
16239
16299
|
}
|
|
16240
|
-
if (
|
|
16300
|
+
if (SLUG_UNSAFE(slug)) {
|
|
16241
16301
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
16242
16302
|
}
|
|
16243
16303
|
const agentDir = resolve22(account.accountDir, "agents", slug);
|
|
@@ -17496,18 +17556,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
17496
17556
|
]);
|
|
17497
17557
|
var app22 = new Hono();
|
|
17498
17558
|
app22.post("/", async (c) => {
|
|
17499
|
-
const
|
|
17559
|
+
const TAG58 = "[admin:events]";
|
|
17500
17560
|
let body;
|
|
17501
17561
|
try {
|
|
17502
17562
|
body = await c.req.json();
|
|
17503
17563
|
} catch (err) {
|
|
17504
17564
|
const detail = err instanceof Error ? err.message : String(err);
|
|
17505
|
-
console.error(`${
|
|
17565
|
+
console.error(`${TAG58} reject reason=body-not-json detail=${detail}`);
|
|
17506
17566
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
17507
17567
|
}
|
|
17508
17568
|
const event = typeof body.event === "string" ? body.event : "";
|
|
17509
17569
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
17510
|
-
console.error(`${
|
|
17570
|
+
console.error(`${TAG58} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
17511
17571
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
17512
17572
|
}
|
|
17513
17573
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -24162,12 +24222,19 @@ app50.get("/", requireAdminSession, async (c) => {
|
|
|
24162
24222
|
// it: a second ASSIGNED_TO edge would fan the row out, duplicating
|
|
24163
24223
|
// rowKey and double-counting the assignee.
|
|
24164
24224
|
WITH t, openTe, head(collect(a)) AS assignee
|
|
24225
|
+
// The AdminUser carries no name property (Task 1570); the name lives on
|
|
24226
|
+
// its owned Person. Resolve it here so an assigned task shows a real name
|
|
24227
|
+
// rather than a userId slice (Task 1982).
|
|
24228
|
+
OPTIONAL MATCH (assignee)-[:OWNS]->(ap:Person) WHERE ap.accountId = assignee.accountId
|
|
24229
|
+
WITH t, openTe, assignee, head(collect(ap)) AS assigneePerson
|
|
24165
24230
|
RETURN t.taskId AS taskId, elementId(t) AS rowKey, t.name AS name, t.clientName AS clientName,
|
|
24166
24231
|
t.propertyAddress AS propertyAddress, t.fee AS fee, t.status AS status,
|
|
24167
24232
|
coalesce(t.secondsLogged, 0) AS secondsLogged,
|
|
24168
24233
|
openTe.startedAt AS runningStartedAt,
|
|
24169
24234
|
t.createdAt AS createdAt,
|
|
24170
|
-
assignee.userId AS assigneeUserId,
|
|
24235
|
+
assignee.userId AS assigneeUserId,
|
|
24236
|
+
assigneePerson.givenName AS assigneeGivenName,
|
|
24237
|
+
assigneePerson.familyName AS assigneeFamilyName
|
|
24171
24238
|
ORDER BY t.createdAt DESC`,
|
|
24172
24239
|
{ accountId }
|
|
24173
24240
|
);
|
|
@@ -24192,6 +24259,9 @@ app50.get("/", requireAdminSession, async (c) => {
|
|
|
24192
24259
|
if (createdAt === null) missingCreatedAt++;
|
|
24193
24260
|
const assigneeUserId = rec.get("assigneeUserId") ?? null;
|
|
24194
24261
|
if (assigneeUserId !== null) assigned++;
|
|
24262
|
+
const assigneeGivenName = rec.get("assigneeGivenName") ?? null;
|
|
24263
|
+
const assigneeFamilyName = rec.get("assigneeFamilyName") ?? null;
|
|
24264
|
+
const assigneeName = assigneeGivenName && assigneeGivenName.trim().length > 0 ? assigneeFamilyName && assigneeFamilyName.trim().length > 0 ? `${assigneeGivenName.trim()} ${assigneeFamilyName.trim()}` : assigneeGivenName.trim() : null;
|
|
24195
24265
|
const row = {
|
|
24196
24266
|
taskId,
|
|
24197
24267
|
rowKey: rec.get("rowKey"),
|
|
@@ -24205,7 +24275,7 @@ app50.get("/", requireAdminSession, async (c) => {
|
|
|
24205
24275
|
runningStartedAt,
|
|
24206
24276
|
createdAt,
|
|
24207
24277
|
assigneeUserId,
|
|
24208
|
-
assigneeName
|
|
24278
|
+
assigneeName
|
|
24209
24279
|
};
|
|
24210
24280
|
if (COMPLETED.has(status)) completed.push(row);
|
|
24211
24281
|
else if (!HIDDEN_FROM_OPEN.has(status)) open.push(row);
|
|
@@ -24487,10 +24557,199 @@ app54.post("/", requireAdminSession, async (c) => {
|
|
|
24487
24557
|
});
|
|
24488
24558
|
var task_time_adjust_default = app54;
|
|
24489
24559
|
|
|
24490
|
-
//
|
|
24491
|
-
import { readdirSync as readdirSync25 } from "fs";
|
|
24560
|
+
// app/lib/admin-roster.ts
|
|
24561
|
+
import { existsSync as existsSync39, readdirSync as readdirSync25, readFileSync as readFileSync40 } from "fs";
|
|
24562
|
+
import { resolve as resolve33 } from "path";
|
|
24563
|
+
function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
|
|
24564
|
+
let entries;
|
|
24565
|
+
try {
|
|
24566
|
+
entries = readdirSync25(accountsDir);
|
|
24567
|
+
} catch {
|
|
24568
|
+
return [];
|
|
24569
|
+
}
|
|
24570
|
+
for (const entry of entries) {
|
|
24571
|
+
const cfgPath = resolve33(accountsDir, entry, "account.json");
|
|
24572
|
+
if (!existsSync39(cfgPath)) continue;
|
|
24573
|
+
try {
|
|
24574
|
+
const cfg = JSON.parse(readFileSync40(cfgPath, "utf-8"));
|
|
24575
|
+
if (cfg.role !== "house") continue;
|
|
24576
|
+
if (!Array.isArray(cfg.admins)) return [];
|
|
24577
|
+
return cfg.admins.map(
|
|
24578
|
+
(a) => a && typeof a === "object" && typeof a.userId === "string" ? a.userId : null
|
|
24579
|
+
).filter((u) => u !== null && u.length > 0);
|
|
24580
|
+
} catch {
|
|
24581
|
+
}
|
|
24582
|
+
}
|
|
24583
|
+
return [];
|
|
24584
|
+
}
|
|
24585
|
+
async function resolveOwnerUserId2(accountId) {
|
|
24586
|
+
const session = getSession();
|
|
24587
|
+
try {
|
|
24588
|
+
const r = await session.run(
|
|
24589
|
+
`MATCH (au:AdminUser {accountId: $accountId, role: 'owner'})
|
|
24590
|
+
RETURN au.userId AS userId ORDER BY au.createdAt ASC LIMIT 1`,
|
|
24591
|
+
{ accountId }
|
|
24592
|
+
);
|
|
24593
|
+
return r.records.length > 0 ? r.records[0].get("userId") ?? null : null;
|
|
24594
|
+
} finally {
|
|
24595
|
+
await session.close();
|
|
24596
|
+
}
|
|
24597
|
+
}
|
|
24598
|
+
async function resolveAllowedAssigneeIds(accountId, accountsDir = ACCOUNTS_DIR) {
|
|
24599
|
+
const houseIds = readHouseAdminUserIds(accountsDir);
|
|
24600
|
+
const ownerId = await resolveOwnerUserId2(accountId);
|
|
24601
|
+
const ids = new Set(houseIds);
|
|
24602
|
+
if (ownerId) ids.add(ownerId);
|
|
24603
|
+
return { ids, ownerId, houseIds };
|
|
24604
|
+
}
|
|
24605
|
+
async function resolveAssignableAdmins(accountId, accountsDir = ACCOUNTS_DIR) {
|
|
24606
|
+
const { ownerId, houseIds } = await resolveAllowedAssigneeIds(accountId, accountsDir);
|
|
24607
|
+
const candidates = Array.from(/* @__PURE__ */ new Set([...ownerId ? [ownerId] : [], ...houseIds]));
|
|
24608
|
+
if (candidates.length === 0) return [];
|
|
24609
|
+
const session = getSession();
|
|
24610
|
+
try {
|
|
24611
|
+
const r = await session.run(
|
|
24612
|
+
`UNWIND $userIds AS uid
|
|
24613
|
+
MATCH (au:AdminUser {userId: uid})
|
|
24614
|
+
OPTIONAL MATCH (au)-[:OWNS]->(p:Person) WHERE p.accountId = au.accountId
|
|
24615
|
+
RETURN au.userId AS userId, p.givenName AS givenName, p.familyName AS familyName`,
|
|
24616
|
+
{ userIds: candidates }
|
|
24617
|
+
);
|
|
24618
|
+
const present = /* @__PURE__ */ new Set();
|
|
24619
|
+
const out = [];
|
|
24620
|
+
for (const rec of r.records) {
|
|
24621
|
+
const userId = rec.get("userId");
|
|
24622
|
+
present.add(userId);
|
|
24623
|
+
const given = rec.get("givenName") ?? null;
|
|
24624
|
+
const family = rec.get("familyName") ?? null;
|
|
24625
|
+
const name = given && given.trim().length > 0 ? family && family.trim().length > 0 ? `${given.trim()} ${family.trim()}` : given.trim() : null;
|
|
24626
|
+
out.push({ userId, name, kind: userId === ownerId ? "owner" : "house-admin" });
|
|
24627
|
+
}
|
|
24628
|
+
const dropped = candidates.filter((u) => !present.has(u));
|
|
24629
|
+
if (dropped.length > 0) {
|
|
24630
|
+
console.error(
|
|
24631
|
+
`[admin-roster] op=roster account=${accountId} dropped-no-adminuser=${dropped.length} ids=${dropped.map((u) => u.slice(0, 8)).join(",")}`
|
|
24632
|
+
);
|
|
24633
|
+
}
|
|
24634
|
+
out.sort((a, b) => {
|
|
24635
|
+
if (a.kind !== b.kind) return a.kind === "owner" ? -1 : 1;
|
|
24636
|
+
return (a.name ?? a.userId).localeCompare(b.name ?? b.userId);
|
|
24637
|
+
});
|
|
24638
|
+
return out;
|
|
24639
|
+
} finally {
|
|
24640
|
+
await session.close();
|
|
24641
|
+
}
|
|
24642
|
+
}
|
|
24643
|
+
|
|
24644
|
+
// server/routes/admin/task-assign.ts
|
|
24645
|
+
var TAG44 = "[task-assign]";
|
|
24492
24646
|
var app55 = new Hono();
|
|
24493
|
-
|
|
24647
|
+
app55.post("/", requireAdminSession, async (c) => {
|
|
24648
|
+
const cacheKey = c.var.cacheKey;
|
|
24649
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
24650
|
+
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
24651
|
+
let body;
|
|
24652
|
+
try {
|
|
24653
|
+
body = await c.req.json();
|
|
24654
|
+
} catch {
|
|
24655
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
24656
|
+
}
|
|
24657
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
24658
|
+
if (!taskId) {
|
|
24659
|
+
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
24660
|
+
console.error(`${TAG44} op=assign rejected reason=${reason} account=${accountId}`);
|
|
24661
|
+
return c.json({ error: "taskId required" }, 400);
|
|
24662
|
+
}
|
|
24663
|
+
const rawAssignee = body.assigneeUserId;
|
|
24664
|
+
if (rawAssignee !== null && rawAssignee !== void 0 && typeof rawAssignee !== "string") {
|
|
24665
|
+
return c.json({ error: "assigneeUserId must be a string or null" }, 400);
|
|
24666
|
+
}
|
|
24667
|
+
const assigneeUserId = typeof rawAssignee === "string" && rawAssignee.length > 0 ? rawAssignee : null;
|
|
24668
|
+
if (assigneeUserId !== null) {
|
|
24669
|
+
const { ids } = await resolveAllowedAssigneeIds(accountId);
|
|
24670
|
+
if (!ids.has(assigneeUserId)) {
|
|
24671
|
+
console.error(
|
|
24672
|
+
`${TAG44} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
|
|
24673
|
+
);
|
|
24674
|
+
return c.json({ error: "assignee-not-in-roster" }, 403);
|
|
24675
|
+
}
|
|
24676
|
+
}
|
|
24677
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
24678
|
+
const session = getSession();
|
|
24679
|
+
try {
|
|
24680
|
+
const cleared = await session.run(
|
|
24681
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
24682
|
+
OPTIONAL MATCH (t)-[r:ASSIGNED_TO]->(:AdminUser) DELETE r
|
|
24683
|
+
RETURN t.taskId AS taskId`,
|
|
24684
|
+
{ taskId, accountId, now }
|
|
24685
|
+
);
|
|
24686
|
+
if (cleared.records.length === 0) {
|
|
24687
|
+
return c.json({ error: "task-not-found" }, 404);
|
|
24688
|
+
}
|
|
24689
|
+
if (assigneeUserId === null) {
|
|
24690
|
+
await session.run(
|
|
24691
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId}) SET t.updatedAt = $now`,
|
|
24692
|
+
{ taskId, accountId, now }
|
|
24693
|
+
);
|
|
24694
|
+
console.log(`${TAG44} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
|
|
24695
|
+
return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
|
|
24696
|
+
}
|
|
24697
|
+
const set = await session.run(
|
|
24698
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
24699
|
+
MATCH (au:AdminUser {userId: $assigneeUserId})
|
|
24700
|
+
MERGE (t)-[:ASSIGNED_TO]->(au)
|
|
24701
|
+
SET t.updatedAt = $now
|
|
24702
|
+
OPTIONAL MATCH (au)-[:OWNS]->(p:Person) WHERE p.accountId = au.accountId
|
|
24703
|
+
RETURN au.userId AS userId, p.givenName AS givenName, p.familyName AS familyName`,
|
|
24704
|
+
{ taskId, accountId, assigneeUserId, now }
|
|
24705
|
+
);
|
|
24706
|
+
if (set.records.length === 0) {
|
|
24707
|
+
console.error(
|
|
24708
|
+
`${TAG44} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
|
|
24709
|
+
);
|
|
24710
|
+
return c.json({ error: "assignee-no-admin-node" }, 409);
|
|
24711
|
+
}
|
|
24712
|
+
const given = set.records[0].get("givenName") ?? null;
|
|
24713
|
+
const family = set.records[0].get("familyName") ?? null;
|
|
24714
|
+
const assigneeName = given && given.trim().length > 0 ? family && family.trim().length > 0 ? `${given.trim()} ${family.trim()}` : given.trim() : null;
|
|
24715
|
+
console.log(
|
|
24716
|
+
`${TAG44} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
|
|
24717
|
+
);
|
|
24718
|
+
return c.json({ ok: true, assigneeUserId, assigneeName });
|
|
24719
|
+
} catch (err) {
|
|
24720
|
+
console.error(`${TAG44} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
|
|
24721
|
+
return c.json({ error: "task-assign-failed" }, 500);
|
|
24722
|
+
} finally {
|
|
24723
|
+
await session.close();
|
|
24724
|
+
}
|
|
24725
|
+
});
|
|
24726
|
+
var task_assign_default = app55;
|
|
24727
|
+
|
|
24728
|
+
// server/routes/admin/admin-users-list.ts
|
|
24729
|
+
var TAG45 = "[admin-users]";
|
|
24730
|
+
var app56 = new Hono();
|
|
24731
|
+
app56.get("/", requireAdminSession, async (c) => {
|
|
24732
|
+
const cacheKey = c.var.cacheKey;
|
|
24733
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
24734
|
+
if (!accountId) {
|
|
24735
|
+
console.error(`${TAG45} op=list auth-rejected reason="no account for session"`);
|
|
24736
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
24737
|
+
}
|
|
24738
|
+
try {
|
|
24739
|
+
const users = await resolveAssignableAdmins(accountId);
|
|
24740
|
+
console.log(`${TAG45} op=list account=${accountId} count=${users.length}`);
|
|
24741
|
+
return c.json({ ok: true, users });
|
|
24742
|
+
} catch (err) {
|
|
24743
|
+
console.error(`${TAG45} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
24744
|
+
return c.json({ error: "admin-users-list-failed" }, 500);
|
|
24745
|
+
}
|
|
24746
|
+
});
|
|
24747
|
+
var admin_users_list_default = app56;
|
|
24748
|
+
|
|
24749
|
+
// server/routes/admin/activity.ts
|
|
24750
|
+
import { readdirSync as readdirSync26 } from "fs";
|
|
24751
|
+
var app57 = new Hono();
|
|
24752
|
+
var TAG46 = "[activity]";
|
|
24494
24753
|
function resolveHouseAccountId(accounts) {
|
|
24495
24754
|
const houses = accounts.filter((a) => a.config.role === "house");
|
|
24496
24755
|
if (houses.length === 1) return { accountId: houses[0].accountId, reason: "house" };
|
|
@@ -24504,14 +24763,14 @@ function requestToken() {
|
|
|
24504
24763
|
var short = (id) => id ? id.slice(0, 8) : "unset";
|
|
24505
24764
|
function countAccountDirsOnDisk() {
|
|
24506
24765
|
try {
|
|
24507
|
-
return
|
|
24766
|
+
return readdirSync26(ACCOUNTS_DIR, { withFileTypes: true }).filter(
|
|
24508
24767
|
(e) => e.isDirectory() && !e.name.startsWith(".")
|
|
24509
24768
|
).length;
|
|
24510
24769
|
} catch {
|
|
24511
24770
|
return null;
|
|
24512
24771
|
}
|
|
24513
24772
|
}
|
|
24514
|
-
|
|
24773
|
+
app57.get("/", requireAdminSession, async (c) => {
|
|
24515
24774
|
const req = requestToken();
|
|
24516
24775
|
const cacheKey = c.var.cacheKey;
|
|
24517
24776
|
const caller2 = getAccountIdForSession(cacheKey) ?? null;
|
|
@@ -24519,19 +24778,19 @@ app55.get("/", requireAdminSession, async (c) => {
|
|
|
24519
24778
|
const house = resolveHouseAccountId(valid);
|
|
24520
24779
|
const isHouse = caller2 !== null && house.accountId !== null && caller2 === house.accountId;
|
|
24521
24780
|
console.log(
|
|
24522
|
-
`${
|
|
24781
|
+
`${TAG46} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
|
|
24523
24782
|
);
|
|
24524
24783
|
if (!isHouse) {
|
|
24525
24784
|
const reason = house.accountId === null ? house.reason : "not-house";
|
|
24526
24785
|
console.error(
|
|
24527
|
-
`${
|
|
24786
|
+
`${TAG46} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
|
|
24528
24787
|
);
|
|
24529
24788
|
return c.json({ error: "house-only" }, 403);
|
|
24530
24789
|
}
|
|
24531
|
-
console.log(`${
|
|
24790
|
+
console.log(`${TAG46} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
|
|
24532
24791
|
const onDisk = countAccountDirsOnDisk();
|
|
24533
24792
|
console.log(
|
|
24534
|
-
`${
|
|
24793
|
+
`${TAG46} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
|
|
24535
24794
|
);
|
|
24536
24795
|
const start = Date.now();
|
|
24537
24796
|
let res;
|
|
@@ -24547,17 +24806,17 @@ app55.get("/", requireAdminSession, async (c) => {
|
|
|
24547
24806
|
});
|
|
24548
24807
|
} catch (err) {
|
|
24549
24808
|
console.error(
|
|
24550
|
-
`${
|
|
24809
|
+
`${TAG46} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
|
|
24551
24810
|
);
|
|
24552
24811
|
return c.json({ error: "manager-unreachable" }, 502);
|
|
24553
24812
|
}
|
|
24554
24813
|
if (res.status !== 200) {
|
|
24555
|
-
console.error(`${
|
|
24814
|
+
console.error(`${TAG46} op=manager-fail req=${req} reason=status status=${res.status}`);
|
|
24556
24815
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
24557
24816
|
}
|
|
24558
24817
|
const body = await res.json().catch(() => null);
|
|
24559
24818
|
if (!body || !Array.isArray(body.rows)) {
|
|
24560
|
-
console.error(`${
|
|
24819
|
+
console.error(`${TAG46} op=manager-fail req=${req} reason=bad-json`);
|
|
24561
24820
|
return c.json({ error: "manager-bad-json" }, 502);
|
|
24562
24821
|
}
|
|
24563
24822
|
const rows = body.rows;
|
|
@@ -24568,10 +24827,10 @@ app55.get("/", requireAdminSession, async (c) => {
|
|
|
24568
24827
|
const ageNull = rows.filter((r) => r.ageMs === null).length;
|
|
24569
24828
|
const sidecarNull = rows.filter((r) => r.sidecarMissing).length;
|
|
24570
24829
|
console.log(
|
|
24571
|
-
`${
|
|
24830
|
+
`${TAG46} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
|
|
24572
24831
|
);
|
|
24573
24832
|
console.log(
|
|
24574
|
-
`${
|
|
24833
|
+
`${TAG46} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
|
|
24575
24834
|
);
|
|
24576
24835
|
const names = {};
|
|
24577
24836
|
await Promise.all(
|
|
@@ -24590,7 +24849,7 @@ app55.get("/", requireAdminSession, async (c) => {
|
|
|
24590
24849
|
return acc;
|
|
24591
24850
|
}, {});
|
|
24592
24851
|
console.log(
|
|
24593
|
-
`${
|
|
24852
|
+
`${TAG46} op=loops req=${req} armed=${armed2} rendered=${loopRows.length} procPct=${cpu.processPct?.toFixed(1) ?? "null"} attributedPct=${cpu.attributedPct?.toFixed(1) ?? "null"} ` + Object.entries(byState).map(([s, n]) => `${s}=${n}`).join(" ")
|
|
24594
24853
|
);
|
|
24595
24854
|
return c.json({
|
|
24596
24855
|
rows,
|
|
@@ -24620,63 +24879,65 @@ app55.get("/", requireAdminSession, async (c) => {
|
|
|
24620
24879
|
}
|
|
24621
24880
|
});
|
|
24622
24881
|
});
|
|
24623
|
-
var activity_default =
|
|
24882
|
+
var activity_default = app57;
|
|
24624
24883
|
|
|
24625
24884
|
// server/routes/admin/index.ts
|
|
24626
|
-
var
|
|
24627
|
-
|
|
24628
|
-
|
|
24629
|
-
|
|
24630
|
-
|
|
24631
|
-
|
|
24632
|
-
|
|
24633
|
-
|
|
24634
|
-
|
|
24635
|
-
|
|
24636
|
-
|
|
24637
|
-
|
|
24638
|
-
|
|
24639
|
-
|
|
24640
|
-
|
|
24641
|
-
|
|
24642
|
-
|
|
24643
|
-
|
|
24644
|
-
|
|
24645
|
-
|
|
24646
|
-
|
|
24647
|
-
|
|
24648
|
-
|
|
24649
|
-
|
|
24650
|
-
|
|
24651
|
-
|
|
24652
|
-
|
|
24653
|
-
|
|
24654
|
-
|
|
24655
|
-
|
|
24656
|
-
|
|
24657
|
-
|
|
24658
|
-
|
|
24659
|
-
|
|
24660
|
-
|
|
24661
|
-
|
|
24662
|
-
|
|
24663
|
-
|
|
24664
|
-
|
|
24665
|
-
|
|
24666
|
-
|
|
24667
|
-
|
|
24668
|
-
|
|
24669
|
-
|
|
24670
|
-
|
|
24671
|
-
|
|
24672
|
-
|
|
24885
|
+
var app58 = new Hono();
|
|
24886
|
+
app58.route("/session", session_default);
|
|
24887
|
+
app58.route("/accounts", accounts_default);
|
|
24888
|
+
app58.route("/logs", logs_default);
|
|
24889
|
+
app58.route("/claude-info", claude_info_default);
|
|
24890
|
+
app58.route("/attachment", attachment_default);
|
|
24891
|
+
app58.route("/session-upload", session_upload_default);
|
|
24892
|
+
app58.route("/agents", agents_default);
|
|
24893
|
+
app58.route("/sessions", sessions_default);
|
|
24894
|
+
app58.route("/claude-sessions", claude_sessions_default);
|
|
24895
|
+
app58.route("/log-ingest", log_ingest_default);
|
|
24896
|
+
app58.route("/events", events_default);
|
|
24897
|
+
app58.route("/files", files_default);
|
|
24898
|
+
app58.route("/graph-search", graph_search_default);
|
|
24899
|
+
app58.route("/graph-subgraph", graph_subgraph_default);
|
|
24900
|
+
app58.route("/graph-delete", graph_delete_default);
|
|
24901
|
+
app58.route("/graph-restore", graph_restore_default);
|
|
24902
|
+
app58.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
24903
|
+
app58.route("/graph-default-view", graph_default_view_default);
|
|
24904
|
+
app58.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
24905
|
+
app58.route("/sidebar-sessions", sidebar_sessions_default);
|
|
24906
|
+
app58.route("/session-delete", session_delete_default);
|
|
24907
|
+
app58.route("/session-stop", session_stop_default);
|
|
24908
|
+
app58.route("/session-archive", session_archive_default);
|
|
24909
|
+
app58.route("/session-rename", session_rename_default);
|
|
24910
|
+
app58.route("/session-usage", session_usage_default);
|
|
24911
|
+
app58.route("/browser", browser_default);
|
|
24912
|
+
app58.route("/session-rc-spawn", session_rc_spawn_default);
|
|
24913
|
+
app58.route("/session-reseat", session_reseat_default);
|
|
24914
|
+
app58.route("/system-stats", system_stats_default);
|
|
24915
|
+
app58.route("/health-brand", health_default2);
|
|
24916
|
+
app58.route("/linkedin-ingest", linkedin_ingest_default);
|
|
24917
|
+
app58.route("/post-turn-context", post_turn_context_default);
|
|
24918
|
+
app58.route("/public-session-context", public_session_context_default);
|
|
24919
|
+
app58.route("/public-session-exit", public_session_exit_default);
|
|
24920
|
+
app58.route("/access-session-evict", access_session_evict_default);
|
|
24921
|
+
app58.route("/enrol-person", enrol_person_default);
|
|
24922
|
+
app58.route("/calendar", calendar_default);
|
|
24923
|
+
app58.route("/routines", routines_default);
|
|
24924
|
+
app58.route("/skills", skills_default);
|
|
24925
|
+
app58.route("/tasks-list", tasks_list_default);
|
|
24926
|
+
app58.route("/task-timer-start", task_timer_start_default);
|
|
24927
|
+
app58.route("/task-timer-stop", task_timer_stop_default);
|
|
24928
|
+
app58.route("/task-complete", task_complete_default);
|
|
24929
|
+
app58.route("/task-time-adjust", task_time_adjust_default);
|
|
24930
|
+
app58.route("/task-assign", task_assign_default);
|
|
24931
|
+
app58.route("/admin-users-list", admin_users_list_default);
|
|
24932
|
+
app58.route("/activity", activity_default);
|
|
24933
|
+
var admin_default = app58;
|
|
24673
24934
|
|
|
24674
24935
|
// server/routes/access/verify-token.ts
|
|
24675
|
-
var
|
|
24936
|
+
var TAG47 = "[access-verify]";
|
|
24676
24937
|
var MINT_TAG = "[access-session-mint]";
|
|
24677
24938
|
var COOKIE_NAME = "__access_session";
|
|
24678
|
-
var
|
|
24679
|
-
|
|
24939
|
+
var app59 = new Hono();
|
|
24940
|
+
app59.post("/", async (c) => {
|
|
24680
24941
|
const ip = c.var.clientIp || "unknown";
|
|
24681
24942
|
let body;
|
|
24682
24943
|
try {
|
|
@@ -24691,39 +24952,39 @@ app57.post("/", async (c) => {
|
|
|
24691
24952
|
}
|
|
24692
24953
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
24693
24954
|
if (rateMsg) {
|
|
24694
|
-
console.error(`${
|
|
24955
|
+
console.error(`${TAG47} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
24695
24956
|
return c.json({ error: rateMsg }, 429);
|
|
24696
24957
|
}
|
|
24697
24958
|
const grant = await findGrantByMagicToken(token);
|
|
24698
24959
|
if (!grant) {
|
|
24699
24960
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
24700
|
-
console.error(`${
|
|
24961
|
+
console.error(`${TAG47} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
24701
24962
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
24702
24963
|
}
|
|
24703
24964
|
if (grant.agentSlug !== agentSlug) {
|
|
24704
24965
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
24705
24966
|
console.error(
|
|
24706
|
-
`${
|
|
24967
|
+
`${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
24707
24968
|
);
|
|
24708
24969
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
24709
24970
|
}
|
|
24710
24971
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
24711
24972
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
24712
24973
|
console.error(
|
|
24713
|
-
`${
|
|
24974
|
+
`${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
24714
24975
|
);
|
|
24715
24976
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
24716
24977
|
}
|
|
24717
24978
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
24718
24979
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
24719
24980
|
console.error(
|
|
24720
|
-
`${
|
|
24981
|
+
`${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
24721
24982
|
);
|
|
24722
24983
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
24723
24984
|
}
|
|
24724
24985
|
if (!grant.sliceToken) {
|
|
24725
24986
|
console.error(
|
|
24726
|
-
`${
|
|
24987
|
+
`${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
24727
24988
|
);
|
|
24728
24989
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
24729
24990
|
}
|
|
@@ -24739,12 +25000,12 @@ app57.post("/", async (c) => {
|
|
|
24739
25000
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
24740
25001
|
} catch (err) {
|
|
24741
25002
|
console.error(
|
|
24742
|
-
`${
|
|
25003
|
+
`${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
24743
25004
|
);
|
|
24744
25005
|
return c.json({ error: "verification-failed" }, 500);
|
|
24745
25006
|
}
|
|
24746
25007
|
clearAccessRateLimit(ip, agentSlug);
|
|
24747
|
-
console.log(`${
|
|
25008
|
+
console.log(`${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
24748
25009
|
console.log(
|
|
24749
25010
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
24750
25011
|
);
|
|
@@ -24758,13 +25019,13 @@ app57.post("/", async (c) => {
|
|
|
24758
25019
|
displayName: grant.displayName
|
|
24759
25020
|
});
|
|
24760
25021
|
});
|
|
24761
|
-
var verify_token_default =
|
|
25022
|
+
var verify_token_default = app59;
|
|
24762
25023
|
|
|
24763
25024
|
// app/lib/access-email.ts
|
|
24764
25025
|
import { spawn as spawn2 } from "child_process";
|
|
24765
|
-
import { resolve as
|
|
24766
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
24767
|
-
var SEND_SCRIPT =
|
|
25026
|
+
import { resolve as resolve34 } from "path";
|
|
25027
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve34(process.cwd(), "..");
|
|
25028
|
+
var SEND_SCRIPT = resolve34(
|
|
24768
25029
|
PLATFORM_ROOT7,
|
|
24769
25030
|
"plugins",
|
|
24770
25031
|
"email",
|
|
@@ -24820,10 +25081,10 @@ async function sendMagicLinkEmail(payload) {
|
|
|
24820
25081
|
}
|
|
24821
25082
|
|
|
24822
25083
|
// server/routes/access/request-magic-link.ts
|
|
24823
|
-
var
|
|
24824
|
-
var
|
|
25084
|
+
var TAG48 = "[access-request-link]";
|
|
25085
|
+
var app60 = new Hono();
|
|
24825
25086
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
24826
|
-
|
|
25087
|
+
app60.post("/", async (c) => {
|
|
24827
25088
|
let body;
|
|
24828
25089
|
try {
|
|
24829
25090
|
body = await c.req.json();
|
|
@@ -24837,18 +25098,18 @@ app58.post("/", async (c) => {
|
|
|
24837
25098
|
}
|
|
24838
25099
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
24839
25100
|
if (rateMsg) {
|
|
24840
|
-
console.error(`${
|
|
25101
|
+
console.error(`${TAG48} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
24841
25102
|
return c.json({ error: rateMsg }, 429);
|
|
24842
25103
|
}
|
|
24843
25104
|
recordRequestLinkAttempt(contactValue);
|
|
24844
25105
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
24845
25106
|
if (!accountId) {
|
|
24846
|
-
console.error(`${
|
|
25107
|
+
console.error(`${TAG48} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
24847
25108
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
24848
25109
|
}
|
|
24849
25110
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
24850
25111
|
if (!grant) {
|
|
24851
|
-
console.log(`${
|
|
25112
|
+
console.log(`${TAG48} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
24852
25113
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
24853
25114
|
}
|
|
24854
25115
|
let token;
|
|
@@ -24856,7 +25117,7 @@ app58.post("/", async (c) => {
|
|
|
24856
25117
|
token = await generateNewMagicToken(grant.grantId);
|
|
24857
25118
|
} catch (err) {
|
|
24858
25119
|
console.error(
|
|
24859
|
-
`${
|
|
25120
|
+
`${TAG48} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
24860
25121
|
);
|
|
24861
25122
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
24862
25123
|
}
|
|
@@ -24888,26 +25149,26 @@ app58.post("/", async (c) => {
|
|
|
24888
25149
|
});
|
|
24889
25150
|
if (!sendResult.ok) {
|
|
24890
25151
|
console.error(
|
|
24891
|
-
`${
|
|
25152
|
+
`${TAG48} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
24892
25153
|
);
|
|
24893
25154
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
24894
25155
|
}
|
|
24895
25156
|
console.log(
|
|
24896
|
-
`${
|
|
25157
|
+
`${TAG48} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
24897
25158
|
);
|
|
24898
25159
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
24899
25160
|
});
|
|
24900
|
-
var request_magic_link_default =
|
|
25161
|
+
var request_magic_link_default = app60;
|
|
24901
25162
|
|
|
24902
25163
|
// server/routes/access/index.ts
|
|
24903
|
-
var
|
|
24904
|
-
|
|
24905
|
-
|
|
24906
|
-
var access_default =
|
|
25164
|
+
var app61 = new Hono();
|
|
25165
|
+
app61.route("/verify-token", verify_token_default);
|
|
25166
|
+
app61.route("/request-magic-link", request_magic_link_default);
|
|
25167
|
+
var access_default = app61;
|
|
24907
25168
|
|
|
24908
25169
|
// server/routes/sites.ts
|
|
24909
|
-
import { existsSync as
|
|
24910
|
-
import { resolve as
|
|
25170
|
+
import { existsSync as existsSync40, readFileSync as readFileSync41, realpathSync as realpathSync8, statSync as statSync17 } from "fs";
|
|
25171
|
+
import { resolve as resolve35 } from "path";
|
|
24911
25172
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
24912
25173
|
var MIME = {
|
|
24913
25174
|
".html": "text/html; charset=utf-8",
|
|
@@ -24938,8 +25199,8 @@ function getExt(p) {
|
|
|
24938
25199
|
if (idx < p.lastIndexOf("/")) return "";
|
|
24939
25200
|
return p.slice(idx).toLowerCase();
|
|
24940
25201
|
}
|
|
24941
|
-
var
|
|
24942
|
-
|
|
25202
|
+
var app62 = new Hono();
|
|
25203
|
+
app62.get("/:rel{.*}", (c) => {
|
|
24943
25204
|
const reqPath = c.req.path;
|
|
24944
25205
|
const rawRel = c.req.param("rel") ?? "";
|
|
24945
25206
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -24964,15 +25225,15 @@ app60.get("/:rel{.*}", (c) => {
|
|
|
24964
25225
|
}
|
|
24965
25226
|
segments.push(seg);
|
|
24966
25227
|
}
|
|
24967
|
-
const rootDir =
|
|
24968
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
25228
|
+
const rootDir = resolve35(account.accountDir, "sites");
|
|
25229
|
+
let filePath = segments.length === 0 ? rootDir : resolve35(rootDir, ...segments);
|
|
24969
25230
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
24970
25231
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
24971
25232
|
return c.text("Forbidden", 403);
|
|
24972
25233
|
}
|
|
24973
25234
|
let stat11;
|
|
24974
25235
|
try {
|
|
24975
|
-
stat11 =
|
|
25236
|
+
stat11 = existsSync40(filePath) ? statSync17(filePath) : null;
|
|
24976
25237
|
} catch {
|
|
24977
25238
|
stat11 = null;
|
|
24978
25239
|
}
|
|
@@ -24985,13 +25246,13 @@ app60.get("/:rel{.*}", (c) => {
|
|
|
24985
25246
|
return c.redirect(target, 301);
|
|
24986
25247
|
}
|
|
24987
25248
|
if (stat11?.isDirectory()) {
|
|
24988
|
-
filePath =
|
|
25249
|
+
filePath = resolve35(filePath, "index.html");
|
|
24989
25250
|
}
|
|
24990
25251
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
24991
25252
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
24992
25253
|
return c.text("Forbidden", 403);
|
|
24993
25254
|
}
|
|
24994
|
-
if (!
|
|
25255
|
+
if (!existsSync40(filePath)) {
|
|
24995
25256
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
24996
25257
|
return c.text("Not found", 404);
|
|
24997
25258
|
}
|
|
@@ -25010,7 +25271,7 @@ app60.get("/:rel{.*}", (c) => {
|
|
|
25010
25271
|
}
|
|
25011
25272
|
let body;
|
|
25012
25273
|
try {
|
|
25013
|
-
body =
|
|
25274
|
+
body = readFileSync41(realPath);
|
|
25014
25275
|
} catch (err) {
|
|
25015
25276
|
const code = err?.code;
|
|
25016
25277
|
if (code === "EISDIR") {
|
|
@@ -25042,11 +25303,11 @@ app60.get("/:rel{.*}", (c) => {
|
|
|
25042
25303
|
"X-Content-Type-Options": "nosniff"
|
|
25043
25304
|
});
|
|
25044
25305
|
});
|
|
25045
|
-
var sites_default =
|
|
25306
|
+
var sites_default = app62;
|
|
25046
25307
|
|
|
25047
25308
|
// app/lib/visitor-token.ts
|
|
25048
25309
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
25049
|
-
import { mkdirSync as mkdirSync8, readFileSync as
|
|
25310
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync42, writeFileSync as writeFileSync14 } from "fs";
|
|
25050
25311
|
import { dirname as dirname14 } from "path";
|
|
25051
25312
|
var TOKEN_PREFIX = "v1.";
|
|
25052
25313
|
var SECRET_BYTES = 32;
|
|
@@ -25055,7 +25316,7 @@ var cachedSecret = null;
|
|
|
25055
25316
|
function getSecret() {
|
|
25056
25317
|
if (cachedSecret) return cachedSecret;
|
|
25057
25318
|
try {
|
|
25058
|
-
const hex2 =
|
|
25319
|
+
const hex2 = readFileSync42(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
25059
25320
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
25060
25321
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
25061
25322
|
return cachedSecret;
|
|
@@ -25069,7 +25330,7 @@ function getSecret() {
|
|
|
25069
25330
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
25070
25331
|
} catch {
|
|
25071
25332
|
}
|
|
25072
|
-
const hex =
|
|
25333
|
+
const hex = readFileSync42(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
25073
25334
|
cachedSecret = Buffer.from(hex, "hex");
|
|
25074
25335
|
return cachedSecret;
|
|
25075
25336
|
}
|
|
@@ -25122,7 +25383,7 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
25122
25383
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
25123
25384
|
|
|
25124
25385
|
// app/lib/brand-config.ts
|
|
25125
|
-
import { existsSync as
|
|
25386
|
+
import { existsSync as existsSync41, readFileSync as readFileSync43 } from "fs";
|
|
25126
25387
|
import { join as join43 } from "path";
|
|
25127
25388
|
var cached2 = null;
|
|
25128
25389
|
var cachedAttempted = false;
|
|
@@ -25132,9 +25393,9 @@ function readBrandConfig() {
|
|
|
25132
25393
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
25133
25394
|
if (!platformRoot5) return null;
|
|
25134
25395
|
const brandPath = join43(platformRoot5, "config", "brand.json");
|
|
25135
|
-
if (!
|
|
25396
|
+
if (!existsSync41(brandPath)) return null;
|
|
25136
25397
|
try {
|
|
25137
|
-
cached2 = JSON.parse(
|
|
25398
|
+
cached2 = JSON.parse(readFileSync43(brandPath, "utf-8"));
|
|
25138
25399
|
return cached2;
|
|
25139
25400
|
} catch {
|
|
25140
25401
|
return null;
|
|
@@ -25142,7 +25403,7 @@ function readBrandConfig() {
|
|
|
25142
25403
|
}
|
|
25143
25404
|
|
|
25144
25405
|
// server/routes/visitor-consent.ts
|
|
25145
|
-
var
|
|
25406
|
+
var app63 = new Hono();
|
|
25146
25407
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
25147
25408
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
25148
25409
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -25187,17 +25448,17 @@ function siteSlugFromReferer(referer) {
|
|
|
25187
25448
|
return "";
|
|
25188
25449
|
}
|
|
25189
25450
|
}
|
|
25190
|
-
|
|
25451
|
+
app63.options("/consent", (c) => {
|
|
25191
25452
|
const origin = getOrigin(c);
|
|
25192
25453
|
setCorsHeaders(c, origin);
|
|
25193
25454
|
return c.body(null, 204);
|
|
25194
25455
|
});
|
|
25195
|
-
|
|
25456
|
+
app63.options("/brand-config", (c) => {
|
|
25196
25457
|
const origin = getOrigin(c);
|
|
25197
25458
|
setCorsHeaders(c, origin);
|
|
25198
25459
|
return c.body(null, 204);
|
|
25199
25460
|
});
|
|
25200
|
-
|
|
25461
|
+
app63.post("/consent", async (c) => {
|
|
25201
25462
|
const origin = getOrigin(c);
|
|
25202
25463
|
setCorsHeaders(c, origin);
|
|
25203
25464
|
let raw;
|
|
@@ -25237,7 +25498,7 @@ app61.post("/consent", async (c) => {
|
|
|
25237
25498
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
25238
25499
|
return c.body(null, 204);
|
|
25239
25500
|
});
|
|
25240
|
-
|
|
25501
|
+
app63.get("/brand-config", (c) => {
|
|
25241
25502
|
const origin = getOrigin(c);
|
|
25242
25503
|
setCorsHeaders(c, origin);
|
|
25243
25504
|
const brand = readBrandConfig();
|
|
@@ -25247,7 +25508,7 @@ app61.get("/brand-config", (c) => {
|
|
|
25247
25508
|
c.header("Cache-Control", "public, max-age=300");
|
|
25248
25509
|
return c.json({ consent: { copy, palette } });
|
|
25249
25510
|
});
|
|
25250
|
-
var visitor_consent_default =
|
|
25511
|
+
var visitor_consent_default = app63;
|
|
25251
25512
|
|
|
25252
25513
|
// server/routes/listings.ts
|
|
25253
25514
|
function getCookie(headerValue, name) {
|
|
@@ -25274,8 +25535,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
25274
25535
|
}
|
|
25275
25536
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
25276
25537
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
25277
|
-
var
|
|
25278
|
-
|
|
25538
|
+
var app64 = new Hono();
|
|
25539
|
+
app64.get("/:slug/click", async (c) => {
|
|
25279
25540
|
const slug = c.req.param("slug") ?? "";
|
|
25280
25541
|
const rawSession = c.req.query("session") ?? "";
|
|
25281
25542
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -25339,10 +25600,10 @@ app62.get("/:slug/click", async (c) => {
|
|
|
25339
25600
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
25340
25601
|
return c.redirect(redirectUrl, 302);
|
|
25341
25602
|
});
|
|
25342
|
-
var listings_default =
|
|
25603
|
+
var listings_default = app64;
|
|
25343
25604
|
|
|
25344
25605
|
// server/routes/visitor-event.ts
|
|
25345
|
-
var
|
|
25606
|
+
var app65 = new Hono();
|
|
25346
25607
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
25347
25608
|
var buckets = /* @__PURE__ */ new Map();
|
|
25348
25609
|
var RATE_LIMIT = 60;
|
|
@@ -25418,12 +25679,12 @@ function originAllowed(origin, allowlist) {
|
|
|
25418
25679
|
return false;
|
|
25419
25680
|
}
|
|
25420
25681
|
}
|
|
25421
|
-
|
|
25682
|
+
app65.options("/event", (c) => {
|
|
25422
25683
|
const origin = getOrigin2(c);
|
|
25423
25684
|
setCorsHeaders2(c, origin);
|
|
25424
25685
|
return c.body(null, 204);
|
|
25425
25686
|
});
|
|
25426
|
-
|
|
25687
|
+
app65.post("/event", async (c) => {
|
|
25427
25688
|
const origin = getOrigin2(c);
|
|
25428
25689
|
setCorsHeaders2(c, origin);
|
|
25429
25690
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -25628,17 +25889,17 @@ async function writeEvent(opts) {
|
|
|
25628
25889
|
);
|
|
25629
25890
|
}
|
|
25630
25891
|
}
|
|
25631
|
-
var visitor_event_default =
|
|
25892
|
+
var visitor_event_default = app65;
|
|
25632
25893
|
|
|
25633
25894
|
// server/routes/session.ts
|
|
25634
|
-
import { resolve as
|
|
25635
|
-
import { existsSync as
|
|
25895
|
+
import { resolve as resolve36 } from "path";
|
|
25896
|
+
import { existsSync as existsSync42, writeFileSync as writeFileSync15, mkdirSync as mkdirSync9 } from "fs";
|
|
25636
25897
|
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
25637
25898
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
25638
25899
|
try {
|
|
25639
|
-
const cacheDir =
|
|
25900
|
+
const cacheDir = resolve36(MAXY_DIR, "branding-cache", accountId);
|
|
25640
25901
|
mkdirSync9(cacheDir, { recursive: true });
|
|
25641
|
-
writeFileSync15(
|
|
25902
|
+
writeFileSync15(resolve36(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
25642
25903
|
} catch (err) {
|
|
25643
25904
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
25644
25905
|
}
|
|
@@ -25674,8 +25935,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
25674
25935
|
headers
|
|
25675
25936
|
});
|
|
25676
25937
|
}
|
|
25677
|
-
var
|
|
25678
|
-
|
|
25938
|
+
var app66 = new Hono();
|
|
25939
|
+
app66.post("/", async (c) => {
|
|
25679
25940
|
let body;
|
|
25680
25941
|
try {
|
|
25681
25942
|
body = await c.req.json();
|
|
@@ -25715,8 +25976,8 @@ app64.post("/", async (c) => {
|
|
|
25715
25976
|
}
|
|
25716
25977
|
let agentConfig = null;
|
|
25717
25978
|
if (account) {
|
|
25718
|
-
const agentDir =
|
|
25719
|
-
if (!
|
|
25979
|
+
const agentDir = resolve36(account.accountDir, "agents", agentSlug);
|
|
25980
|
+
if (!existsSync42(agentDir) || !existsSync42(resolve36(agentDir, "config.json"))) {
|
|
25720
25981
|
return c.json({ error: "Agent not found" }, 404);
|
|
25721
25982
|
}
|
|
25722
25983
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -25822,7 +26083,7 @@ app64.post("/", async (c) => {
|
|
|
25822
26083
|
newVisitorId
|
|
25823
26084
|
);
|
|
25824
26085
|
});
|
|
25825
|
-
var session_default2 =
|
|
26086
|
+
var session_default2 = app66;
|
|
25826
26087
|
|
|
25827
26088
|
// server/lib/calendar-slots.ts
|
|
25828
26089
|
var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
@@ -25905,17 +26166,17 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
|
|
|
25905
26166
|
}
|
|
25906
26167
|
|
|
25907
26168
|
// server/routes/calendar-public.ts
|
|
25908
|
-
var
|
|
26169
|
+
var app67 = new Hono();
|
|
25909
26170
|
function setCors(c) {
|
|
25910
26171
|
c.header("Access-Control-Allow-Origin", "*");
|
|
25911
26172
|
c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
25912
26173
|
c.header("Access-Control-Allow-Headers", "content-type");
|
|
25913
26174
|
}
|
|
25914
|
-
|
|
26175
|
+
app67.options("/free-busy", (c) => {
|
|
25915
26176
|
setCors(c);
|
|
25916
26177
|
return c.body(null, 204);
|
|
25917
26178
|
});
|
|
25918
|
-
|
|
26179
|
+
app67.get("/free-busy", async (c) => {
|
|
25919
26180
|
setCors(c);
|
|
25920
26181
|
const from = c.req.query("from");
|
|
25921
26182
|
const to = c.req.query("to");
|
|
@@ -25971,15 +26232,15 @@ app65.get("/free-busy", async (c) => {
|
|
|
25971
26232
|
await session.close();
|
|
25972
26233
|
}
|
|
25973
26234
|
});
|
|
25974
|
-
var calendar_public_default =
|
|
26235
|
+
var calendar_public_default = app67;
|
|
25975
26236
|
|
|
25976
26237
|
// server/routes/portal-fetch.ts
|
|
25977
26238
|
import { createReadStream as createReadStream3 } from "fs";
|
|
25978
26239
|
import { stat as stat8, readFile as readFile9, realpath } from "fs/promises";
|
|
25979
|
-
import { join as join44, resolve as
|
|
26240
|
+
import { join as join44, resolve as resolve37, sep as sep10 } from "path";
|
|
25980
26241
|
import { Readable as Readable3 } from "stream";
|
|
25981
|
-
var
|
|
25982
|
-
var
|
|
26242
|
+
var app68 = new Hono();
|
|
26243
|
+
var TAG49 = "[portal-fetch]";
|
|
25983
26244
|
async function verifySignature(secret, accountId, relPath, expiresAtMs, signature, nowMs) {
|
|
25984
26245
|
if (!secret || !signature) return false;
|
|
25985
26246
|
if (!Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs) return false;
|
|
@@ -26029,19 +26290,19 @@ ${expiresAtMs}`)
|
|
|
26029
26290
|
return diff === 0;
|
|
26030
26291
|
}
|
|
26031
26292
|
async function readAccountSecret(accountId) {
|
|
26032
|
-
const path3 =
|
|
26293
|
+
const path3 = resolve37(DATA_ROOT, "accounts", accountId, "secrets", "data-portal.env");
|
|
26033
26294
|
let text;
|
|
26034
26295
|
try {
|
|
26035
26296
|
text = await readFile9(path3, "utf8");
|
|
26036
26297
|
} catch {
|
|
26037
|
-
console.error(`${
|
|
26298
|
+
console.error(`${TAG49} op=no-secret account="${accountId}" path="${path3}"`);
|
|
26038
26299
|
return "";
|
|
26039
26300
|
}
|
|
26040
26301
|
for (const line of text.split("\n")) {
|
|
26041
26302
|
const m = line.match(/^PORTAL_FETCH_SECRET=(.*)$/);
|
|
26042
26303
|
if (m) return m[1].trim();
|
|
26043
26304
|
}
|
|
26044
|
-
console.error(`${
|
|
26305
|
+
console.error(`${TAG49} op=no-secret account="${accountId}" reason=key-absent path="${path3}"`);
|
|
26045
26306
|
return "";
|
|
26046
26307
|
}
|
|
26047
26308
|
function isValidAccountId2(value) {
|
|
@@ -26065,7 +26326,7 @@ async function resolveFetchTarget(accountDir, relPath, ownerId) {
|
|
|
26065
26326
|
const exposeFolders = await readExposeFolders2(accountDir);
|
|
26066
26327
|
const { exposed } = resolveExposedDirs(schemaText, exposeFolders);
|
|
26067
26328
|
if (exposed.length === 0 && !ownerId) return { ok: false, reason: "not-exposed" };
|
|
26068
|
-
const lexical =
|
|
26329
|
+
const lexical = resolve37(accountDir, relPath);
|
|
26069
26330
|
let root;
|
|
26070
26331
|
let absolute;
|
|
26071
26332
|
try {
|
|
@@ -26101,33 +26362,33 @@ async function handle(c, headOnly) {
|
|
|
26101
26362
|
const sig = c.req.query("sig") ?? "";
|
|
26102
26363
|
const owner = c.req.query("owner") ?? "";
|
|
26103
26364
|
console.log(
|
|
26104
|
-
`${
|
|
26365
|
+
`${TAG49} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
|
|
26105
26366
|
);
|
|
26106
26367
|
if (!isValidAccountId2(accountId)) {
|
|
26107
|
-
console.error(`${
|
|
26368
|
+
console.error(`${TAG49} op=denied account=${q(accountId)} reason=account-id`);
|
|
26108
26369
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
26109
26370
|
}
|
|
26110
26371
|
const secret = await readAccountSecret(accountId);
|
|
26111
26372
|
const verified = owner ? await verifyOwnUploadSignature(secret, accountId, owner, relPath, exp, sig, Date.now()) : await verifySignature(secret, accountId, relPath, exp, sig, Date.now());
|
|
26112
26373
|
if (!verified) {
|
|
26113
|
-
console.error(`${
|
|
26374
|
+
console.error(`${TAG49} op=denied account=${q(accountId)} reason=secret`);
|
|
26114
26375
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
26115
26376
|
}
|
|
26116
26377
|
const target = await resolveFetchTarget(
|
|
26117
|
-
|
|
26378
|
+
resolve37(DATA_ROOT, "accounts", accountId),
|
|
26118
26379
|
relPath,
|
|
26119
26380
|
owner || void 0
|
|
26120
26381
|
);
|
|
26121
26382
|
if (!target.ok) {
|
|
26122
26383
|
const op = target.reason === "enoent" ? "miss" : "denied";
|
|
26123
|
-
console.error(`${
|
|
26384
|
+
console.error(`${TAG49} op=${op} account=${accountId} reason=${target.reason}`);
|
|
26124
26385
|
return c.json({ ok: false, error: "not found" }, 404);
|
|
26125
26386
|
}
|
|
26126
26387
|
if (headOnly) {
|
|
26127
|
-
console.log(`${
|
|
26388
|
+
console.log(`${TAG49} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
|
|
26128
26389
|
return c.body(null, 200);
|
|
26129
26390
|
}
|
|
26130
|
-
console.log(`${
|
|
26391
|
+
console.log(`${TAG49} op=served account=${accountId} bytes=${target.sizeBytes}`);
|
|
26131
26392
|
return new Response(Readable3.toWeb(createReadStream3(target.absolute)), {
|
|
26132
26393
|
status: 200,
|
|
26133
26394
|
headers: {
|
|
@@ -26141,12 +26402,12 @@ async function handle(c, headOnly) {
|
|
|
26141
26402
|
}
|
|
26142
26403
|
});
|
|
26143
26404
|
}
|
|
26144
|
-
|
|
26145
|
-
|
|
26146
|
-
var portal_fetch_default =
|
|
26405
|
+
app68.get("/fetch", (c) => handle(c, false));
|
|
26406
|
+
app68.on("HEAD", "/fetch", (c) => handle(c, true));
|
|
26407
|
+
var portal_fetch_default = app68;
|
|
26147
26408
|
|
|
26148
26409
|
// app/lib/timeentry-census.ts
|
|
26149
|
-
var
|
|
26410
|
+
var TAG50 = "[timeentry-census]";
|
|
26150
26411
|
function reconcileTimeEntries(rows, now, horizonMs) {
|
|
26151
26412
|
const openEntries = rows.openEntries.length;
|
|
26152
26413
|
let oldestOpenAgeMs = 0;
|
|
@@ -26186,12 +26447,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
|
|
|
26186
26447
|
sumAdjustments: toNum(r.get("sumAdjustments"))
|
|
26187
26448
|
}));
|
|
26188
26449
|
const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
|
|
26189
|
-
const line = `${
|
|
26450
|
+
const line = `${TAG50} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
|
|
26190
26451
|
if (finding.alarm) console.error(`${line} alarm=true`);
|
|
26191
26452
|
else console.log(line);
|
|
26192
26453
|
return finding;
|
|
26193
26454
|
} catch (err) {
|
|
26194
|
-
console.error(`${
|
|
26455
|
+
console.error(`${TAG50} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
26195
26456
|
return null;
|
|
26196
26457
|
}
|
|
26197
26458
|
}
|
|
@@ -26205,13 +26466,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
26205
26466
|
try {
|
|
26206
26467
|
session = openSession();
|
|
26207
26468
|
} catch (err) {
|
|
26208
|
-
console.error(`${
|
|
26469
|
+
console.error(`${TAG50} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
26209
26470
|
return;
|
|
26210
26471
|
}
|
|
26211
26472
|
try {
|
|
26212
26473
|
await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
|
|
26213
26474
|
} catch (err) {
|
|
26214
|
-
console.error(`${
|
|
26475
|
+
console.error(`${TAG50} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
26215
26476
|
} finally {
|
|
26216
26477
|
try {
|
|
26217
26478
|
await session.close();
|
|
@@ -26228,7 +26489,7 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
26228
26489
|
}
|
|
26229
26490
|
|
|
26230
26491
|
// app/lib/ledger-census.ts
|
|
26231
|
-
import { readdirSync as
|
|
26492
|
+
import { readdirSync as readdirSync27, readFileSync as readFileSync44, statSync as statSync18 } from "fs";
|
|
26232
26493
|
import { join as join45 } from "path";
|
|
26233
26494
|
|
|
26234
26495
|
// ../lib/ledger-core/dist/reconcile.js
|
|
@@ -26272,12 +26533,12 @@ function formatCensusLine(f) {
|
|
|
26272
26533
|
}
|
|
26273
26534
|
|
|
26274
26535
|
// app/lib/ledger-census.ts
|
|
26275
|
-
var
|
|
26536
|
+
var TAG51 = "[ledger-census]";
|
|
26276
26537
|
var DAY_MS = 864e5;
|
|
26277
26538
|
function countWriteRejects24h(logDir, now) {
|
|
26278
26539
|
let entries;
|
|
26279
26540
|
try {
|
|
26280
|
-
entries =
|
|
26541
|
+
entries = readdirSync27(logDir).filter((f) => f.startsWith("mcp-ledger-") && f.endsWith(".log"));
|
|
26281
26542
|
} catch {
|
|
26282
26543
|
return 0;
|
|
26283
26544
|
}
|
|
@@ -26286,7 +26547,7 @@ function countWriteRejects24h(logDir, now) {
|
|
|
26286
26547
|
const path3 = join45(logDir, name);
|
|
26287
26548
|
try {
|
|
26288
26549
|
if (now - statSync18(path3).mtimeMs > DAY_MS) continue;
|
|
26289
|
-
for (const line of
|
|
26550
|
+
for (const line of readFileSync44(path3, "utf8").split("\n")) {
|
|
26290
26551
|
if (line.includes("[graph-write] reject")) total += 1;
|
|
26291
26552
|
}
|
|
26292
26553
|
} catch {
|
|
@@ -26348,7 +26609,7 @@ async function runLedgerCensusOnce(session, now) {
|
|
|
26348
26609
|
else console.log(line);
|
|
26349
26610
|
return finding;
|
|
26350
26611
|
} catch (err) {
|
|
26351
|
-
console.error(`${
|
|
26612
|
+
console.error(`${TAG51} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
26352
26613
|
return null;
|
|
26353
26614
|
}
|
|
26354
26615
|
}
|
|
@@ -26361,7 +26622,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
26361
26622
|
session = openSession();
|
|
26362
26623
|
} catch (err) {
|
|
26363
26624
|
console.error(
|
|
26364
|
-
`${
|
|
26625
|
+
`${TAG51} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
26365
26626
|
);
|
|
26366
26627
|
return;
|
|
26367
26628
|
}
|
|
@@ -26369,7 +26630,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
26369
26630
|
await runLedgerCensusOnce(session, Date.now());
|
|
26370
26631
|
} catch (err) {
|
|
26371
26632
|
console.error(
|
|
26372
|
-
`${
|
|
26633
|
+
`${TAG51} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
26373
26634
|
);
|
|
26374
26635
|
} finally {
|
|
26375
26636
|
try {
|
|
@@ -26387,7 +26648,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
26387
26648
|
}
|
|
26388
26649
|
|
|
26389
26650
|
// app/lib/conversation-audit.ts
|
|
26390
|
-
var
|
|
26651
|
+
var TAG52 = "[conversation-audit]";
|
|
26391
26652
|
async function runConversationAudit() {
|
|
26392
26653
|
const session = getSession();
|
|
26393
26654
|
try {
|
|
@@ -26424,12 +26685,12 @@ async function runConversationAudit() {
|
|
|
26424
26685
|
multiAnchored: Number(multiRec?.get("multiAnchored") ?? 0)
|
|
26425
26686
|
};
|
|
26426
26687
|
console.error(
|
|
26427
|
-
`${
|
|
26688
|
+
`${TAG52} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
|
|
26428
26689
|
);
|
|
26429
26690
|
return result;
|
|
26430
26691
|
} catch (err) {
|
|
26431
26692
|
const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
|
|
26432
|
-
console.error(`${
|
|
26693
|
+
console.error(`${TAG52} op=failed reason=${reason}`);
|
|
26433
26694
|
return null;
|
|
26434
26695
|
} finally {
|
|
26435
26696
|
await session.close();
|
|
@@ -26555,7 +26816,7 @@ function startGraphHealthTimer() {
|
|
|
26555
26816
|
|
|
26556
26817
|
// app/lib/file-watcher.ts
|
|
26557
26818
|
import * as fsp2 from "fs/promises";
|
|
26558
|
-
import { resolve as
|
|
26819
|
+
import { resolve as resolve38, sep as sep11 } from "path";
|
|
26559
26820
|
var ACCOUNT_UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
26560
26821
|
var DEFAULT_COALESCE_MS = 500;
|
|
26561
26822
|
var ROOTS = ["accounts"];
|
|
@@ -26574,7 +26835,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
26574
26835
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
26575
26836
|
for (const r of ROOTS) {
|
|
26576
26837
|
try {
|
|
26577
|
-
await fsp2.mkdir(
|
|
26838
|
+
await fsp2.mkdir(resolve38(dataRoot, r), { recursive: true });
|
|
26578
26839
|
} catch (err) {
|
|
26579
26840
|
console.error(
|
|
26580
26841
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -26595,7 +26856,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
26595
26856
|
timers.set(relativePath, t);
|
|
26596
26857
|
}
|
|
26597
26858
|
async function runHook(relativePath, accountId) {
|
|
26598
|
-
const absolute =
|
|
26859
|
+
const absolute = resolve38(dataRoot, relativePath);
|
|
26599
26860
|
let exists = false;
|
|
26600
26861
|
try {
|
|
26601
26862
|
const st = await fsp2.stat(absolute);
|
|
@@ -26619,7 +26880,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
26619
26880
|
}
|
|
26620
26881
|
}
|
|
26621
26882
|
async function watchRoot(rootName) {
|
|
26622
|
-
const absRoot =
|
|
26883
|
+
const absRoot = resolve38(dataRoot, rootName);
|
|
26623
26884
|
try {
|
|
26624
26885
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
26625
26886
|
for await (const event of iter) {
|
|
@@ -26658,7 +26919,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
26658
26919
|
|
|
26659
26920
|
// app/lib/migrate-uploads.ts
|
|
26660
26921
|
import { mkdir as mkdir6, readdir as readdir6, rename as rename3, rm as rm3 } from "fs/promises";
|
|
26661
|
-
import { dirname as dirname15, relative as relative7, resolve as
|
|
26922
|
+
import { dirname as dirname15, relative as relative7, resolve as resolve39 } from "path";
|
|
26662
26923
|
var ACCOUNT_UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
26663
26924
|
async function walkFiles(dir) {
|
|
26664
26925
|
const out = [];
|
|
@@ -26669,7 +26930,7 @@ async function walkFiles(dir) {
|
|
|
26669
26930
|
return out;
|
|
26670
26931
|
}
|
|
26671
26932
|
for (const e of entries) {
|
|
26672
|
-
const abs =
|
|
26933
|
+
const abs = resolve39(dir, e.name);
|
|
26673
26934
|
if (e.isDirectory()) {
|
|
26674
26935
|
out.push(...await walkFiles(abs));
|
|
26675
26936
|
} else if (e.isFile()) {
|
|
@@ -26689,7 +26950,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
26689
26950
|
let moved = 0;
|
|
26690
26951
|
for (const oldAbs of files) {
|
|
26691
26952
|
const suffix = relative7(srcDir, oldAbs);
|
|
26692
|
-
const newAbs =
|
|
26953
|
+
const newAbs = resolve39(destDir, suffix);
|
|
26693
26954
|
await mkdir6(dirname15(newAbs), { recursive: true });
|
|
26694
26955
|
await rename3(oldAbs, newAbs);
|
|
26695
26956
|
moved++;
|
|
@@ -26716,7 +26977,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
26716
26977
|
}
|
|
26717
26978
|
async function migrateUploads(opts = {}) {
|
|
26718
26979
|
const dataRoot = opts.dataRoot ?? DATA_ROOT;
|
|
26719
|
-
const oldRoot =
|
|
26980
|
+
const oldRoot = resolve39(dataRoot, "uploads");
|
|
26720
26981
|
let topEntries;
|
|
26721
26982
|
try {
|
|
26722
26983
|
topEntries = await readdir6(oldRoot, { withFileTypes: true });
|
|
@@ -26737,8 +26998,8 @@ async function migrateUploads(opts = {}) {
|
|
|
26737
26998
|
const name = entry.name;
|
|
26738
26999
|
if (ACCOUNT_UUID_RE5.test(name)) {
|
|
26739
27000
|
moved += await relocateTree(
|
|
26740
|
-
|
|
26741
|
-
|
|
27001
|
+
resolve39(oldRoot, name),
|
|
27002
|
+
resolve39(dataRoot, "accounts", name, "uploads"),
|
|
26742
27003
|
dataRoot,
|
|
26743
27004
|
name,
|
|
26744
27005
|
session
|
|
@@ -26750,8 +27011,8 @@ async function migrateUploads(opts = {}) {
|
|
|
26750
27011
|
continue;
|
|
26751
27012
|
}
|
|
26752
27013
|
moved += await relocateTree(
|
|
26753
|
-
|
|
26754
|
-
|
|
27014
|
+
resolve39(oldRoot, "public"),
|
|
27015
|
+
resolve39(dataRoot, "accounts", installAccountId, "uploads", "public"),
|
|
26755
27016
|
dataRoot,
|
|
26756
27017
|
null,
|
|
26757
27018
|
// public uploads carry no graph nodes
|
|
@@ -26781,7 +27042,7 @@ async function migrateUploads(opts = {}) {
|
|
|
26781
27042
|
|
|
26782
27043
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
26783
27044
|
import { readdir as readdir7, readFile as readFile10, rename as rename4, writeFile as writeFile5, unlink as unlink4 } from "fs/promises";
|
|
26784
|
-
import { existsSync as
|
|
27045
|
+
import { existsSync as existsSync43 } from "fs";
|
|
26785
27046
|
import { join as join46 } from "path";
|
|
26786
27047
|
var ADMIN_ROLE2 = "admin";
|
|
26787
27048
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
@@ -26811,7 +27072,7 @@ async function writeRaw(path3, obj) {
|
|
|
26811
27072
|
await rename4(tmp, path3);
|
|
26812
27073
|
} catch (err) {
|
|
26813
27074
|
try {
|
|
26814
|
-
if (
|
|
27075
|
+
if (existsSync43(tmp)) await unlink4(tmp);
|
|
26815
27076
|
} catch {
|
|
26816
27077
|
}
|
|
26817
27078
|
throw err;
|
|
@@ -27200,8 +27461,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
27200
27461
|
|
|
27201
27462
|
// app/lib/whatsapp/gateway/routes.ts
|
|
27202
27463
|
function createWaChannelRoutes(deps) {
|
|
27203
|
-
const
|
|
27204
|
-
|
|
27464
|
+
const app70 = new Hono();
|
|
27465
|
+
app70.get("/wa-channel/inbound", (c) => {
|
|
27205
27466
|
const senderId = c.req.query("senderId");
|
|
27206
27467
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
27207
27468
|
return streamSSE(c, async (stream2) => {
|
|
@@ -27219,7 +27480,7 @@ function createWaChannelRoutes(deps) {
|
|
|
27219
27480
|
}
|
|
27220
27481
|
});
|
|
27221
27482
|
});
|
|
27222
|
-
|
|
27483
|
+
app70.post("/wa-channel/reply", async (c) => {
|
|
27223
27484
|
const body = await c.req.json().catch(() => null);
|
|
27224
27485
|
const senderId = body?.senderId;
|
|
27225
27486
|
const text = body?.text;
|
|
@@ -27240,7 +27501,7 @@ function createWaChannelRoutes(deps) {
|
|
|
27240
27501
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
27241
27502
|
return c.json({ ok: true });
|
|
27242
27503
|
});
|
|
27243
|
-
|
|
27504
|
+
app70.post("/wa-channel/reply-document", async (c) => {
|
|
27244
27505
|
const body = await c.req.json().catch(() => null);
|
|
27245
27506
|
const senderId = body?.senderId;
|
|
27246
27507
|
const files = body?.files;
|
|
@@ -27279,7 +27540,7 @@ function createWaChannelRoutes(deps) {
|
|
|
27279
27540
|
}
|
|
27280
27541
|
return c.json({ ok: true, results });
|
|
27281
27542
|
});
|
|
27282
|
-
|
|
27543
|
+
app70.post("/wa-channel/ready", async (c) => {
|
|
27283
27544
|
const body = await c.req.json().catch(() => null);
|
|
27284
27545
|
const senderId = body?.senderId;
|
|
27285
27546
|
if (typeof senderId !== "string") {
|
|
@@ -27288,7 +27549,7 @@ function createWaChannelRoutes(deps) {
|
|
|
27288
27549
|
deps.onReady?.(senderId);
|
|
27289
27550
|
return c.json({ ok: true });
|
|
27290
27551
|
});
|
|
27291
|
-
|
|
27552
|
+
app70.post("/wa-channel/received", async (c) => {
|
|
27292
27553
|
const body = await c.req.json().catch(() => null);
|
|
27293
27554
|
const senderId = body?.senderId;
|
|
27294
27555
|
const waMessageId = body?.waMessageId;
|
|
@@ -27298,7 +27559,7 @@ function createWaChannelRoutes(deps) {
|
|
|
27298
27559
|
deps.onReceived?.(senderId, waMessageId);
|
|
27299
27560
|
return c.json({ ok: true });
|
|
27300
27561
|
});
|
|
27301
|
-
|
|
27562
|
+
app70.post("/wa-channel/turn-end", async (c) => {
|
|
27302
27563
|
const body = await c.req.json().catch(() => null);
|
|
27303
27564
|
const senderId = body?.senderId;
|
|
27304
27565
|
const sessionId = body?.sessionId;
|
|
@@ -27331,7 +27592,7 @@ function createWaChannelRoutes(deps) {
|
|
|
27331
27592
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=none`);
|
|
27332
27593
|
return c.json({ ok: true, delivered: "none" });
|
|
27333
27594
|
});
|
|
27334
|
-
return
|
|
27595
|
+
return app70;
|
|
27335
27596
|
}
|
|
27336
27597
|
|
|
27337
27598
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -27746,8 +28007,8 @@ var InboundHub2 = class {
|
|
|
27746
28007
|
|
|
27747
28008
|
// app/lib/webchat/gateway/routes.ts
|
|
27748
28009
|
function createWebchatChannelRoutes(deps) {
|
|
27749
|
-
const
|
|
27750
|
-
|
|
28010
|
+
const app70 = new Hono();
|
|
28011
|
+
app70.get("/webchat-channel/inbound", (c) => {
|
|
27751
28012
|
const key = c.req.query("key");
|
|
27752
28013
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
27753
28014
|
return streamSSE(c, async (stream2) => {
|
|
@@ -27765,7 +28026,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
27765
28026
|
}
|
|
27766
28027
|
});
|
|
27767
28028
|
});
|
|
27768
|
-
|
|
28029
|
+
app70.post("/webchat-channel/reply", async (c) => {
|
|
27769
28030
|
const body = await c.req.json().catch(() => null);
|
|
27770
28031
|
const key = body?.key;
|
|
27771
28032
|
const text = body?.text;
|
|
@@ -27775,7 +28036,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
27775
28036
|
deps.onReply?.(key, text);
|
|
27776
28037
|
return c.json({ ok: true });
|
|
27777
28038
|
});
|
|
27778
|
-
|
|
28039
|
+
app70.post("/webchat-channel/connector-auth", async (c) => {
|
|
27779
28040
|
const body = await c.req.json().catch(() => null);
|
|
27780
28041
|
const key = body?.key;
|
|
27781
28042
|
const sessionId = body?.sessionId;
|
|
@@ -27788,7 +28049,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
27788
28049
|
const result = await deps.onConnectorAuth({ key, sessionId, name, completed });
|
|
27789
28050
|
return c.json(result);
|
|
27790
28051
|
});
|
|
27791
|
-
|
|
28052
|
+
app70.post("/webchat-channel/ready", async (c) => {
|
|
27792
28053
|
const body = await c.req.json().catch(() => null);
|
|
27793
28054
|
const key = body?.key;
|
|
27794
28055
|
if (typeof key !== "string") {
|
|
@@ -27797,7 +28058,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
27797
28058
|
deps.onReady?.(key);
|
|
27798
28059
|
return c.json({ ok: true });
|
|
27799
28060
|
});
|
|
27800
|
-
|
|
28061
|
+
app70.post("/webchat-channel/permission-request", async (c) => {
|
|
27801
28062
|
const body = await c.req.json().catch(() => null);
|
|
27802
28063
|
const key = body?.key;
|
|
27803
28064
|
const requestId = body?.request_id;
|
|
@@ -27811,7 +28072,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
27811
28072
|
const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
|
|
27812
28073
|
return c.json(verdict);
|
|
27813
28074
|
});
|
|
27814
|
-
|
|
28075
|
+
app70.post("/webchat-channel/received", async (c) => {
|
|
27815
28076
|
const body = await c.req.json().catch(() => null);
|
|
27816
28077
|
const key = body?.key;
|
|
27817
28078
|
const messageId = body?.messageId;
|
|
@@ -27821,7 +28082,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
27821
28082
|
deps.onReceived?.(key, messageId);
|
|
27822
28083
|
return c.json({ ok: true });
|
|
27823
28084
|
});
|
|
27824
|
-
|
|
28085
|
+
app70.post("/webchat-channel/turn-end", async (c) => {
|
|
27825
28086
|
const body = await c.req.json().catch(() => null);
|
|
27826
28087
|
const key = body?.key;
|
|
27827
28088
|
const sessionId = body?.sessionId;
|
|
@@ -27835,7 +28096,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
27835
28096
|
console.error(`[webchat-native] op=turn-end channel=webchat key=${k} sessionId=${sid} replied=${replied ? "yes" : "no"} trailing=${finalBytes}`);
|
|
27836
28097
|
return c.json({ ok: true });
|
|
27837
28098
|
});
|
|
27838
|
-
return
|
|
28099
|
+
return app70;
|
|
27839
28100
|
}
|
|
27840
28101
|
|
|
27841
28102
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -27893,16 +28154,16 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
27893
28154
|
* The public /api/chat route awaits this to return the reply on the same SSE
|
|
27894
28155
|
* response, preserving the pre-756 POST→single-blob browser contract. */
|
|
27895
28156
|
awaitReply(key, timeoutMs) {
|
|
27896
|
-
return new Promise((
|
|
28157
|
+
return new Promise((resolve45) => {
|
|
27897
28158
|
const timer = setTimeout(() => {
|
|
27898
28159
|
this.replyAwaiters.delete(key);
|
|
27899
|
-
|
|
28160
|
+
resolve45({ timeout: true });
|
|
27900
28161
|
}, timeoutMs);
|
|
27901
28162
|
if (timer.unref) timer.unref();
|
|
27902
28163
|
this.replyAwaiters.set(key, (r) => {
|
|
27903
28164
|
clearTimeout(timer);
|
|
27904
28165
|
this.replyAwaiters.delete(key);
|
|
27905
|
-
|
|
28166
|
+
resolve45(r);
|
|
27906
28167
|
});
|
|
27907
28168
|
});
|
|
27908
28169
|
}
|
|
@@ -27913,11 +28174,11 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
27913
28174
|
* terminal dialog stays answerable). */
|
|
27914
28175
|
awaitPermissionVerdict(p, timeoutMs) {
|
|
27915
28176
|
const k = _WebchatGateway.promptKey(p.key, p.requestId);
|
|
27916
|
-
return new Promise((
|
|
28177
|
+
return new Promise((resolve45) => {
|
|
27917
28178
|
this.pendingPrompts.get(k)?.resolve({ timeout: true });
|
|
27918
28179
|
const timer = setTimeout(() => {
|
|
27919
28180
|
this.pendingPrompts.delete(k);
|
|
27920
|
-
|
|
28181
|
+
resolve45({ timeout: true });
|
|
27921
28182
|
}, timeoutMs);
|
|
27922
28183
|
if (timer.unref) timer.unref();
|
|
27923
28184
|
this.pendingPrompts.set(k, {
|
|
@@ -27926,7 +28187,7 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
27926
28187
|
resolve: (r) => {
|
|
27927
28188
|
clearTimeout(timer);
|
|
27928
28189
|
this.pendingPrompts.delete(k);
|
|
27929
|
-
|
|
28190
|
+
resolve45(r);
|
|
27930
28191
|
}
|
|
27931
28192
|
});
|
|
27932
28193
|
console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
|
|
@@ -28491,7 +28752,7 @@ async function fanOut(subscribers, text, onError, tag) {
|
|
|
28491
28752
|
|
|
28492
28753
|
// app/lib/webchat/file-delivery.ts
|
|
28493
28754
|
import { realpathSync as realpathSync9 } from "fs";
|
|
28494
|
-
import { resolve as
|
|
28755
|
+
import { resolve as resolve40 } from "path";
|
|
28495
28756
|
|
|
28496
28757
|
// app/lib/channel-pty-bridge/file-delivery.ts
|
|
28497
28758
|
var SEND_USER_FILE = "SendUserFile";
|
|
@@ -28582,29 +28843,29 @@ function makeFileDelivery(opts) {
|
|
|
28582
28843
|
}
|
|
28583
28844
|
|
|
28584
28845
|
// app/lib/webchat/file-delivery.ts
|
|
28585
|
-
var
|
|
28846
|
+
var TAG53 = "[webchat-adaptor]";
|
|
28586
28847
|
function platformRoot2() {
|
|
28587
28848
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
28588
28849
|
}
|
|
28589
28850
|
function makeWebchatSendFile(entry) {
|
|
28590
28851
|
return async (filePath) => {
|
|
28591
28852
|
if (!entry.accountId) {
|
|
28592
|
-
console.error(`${
|
|
28853
|
+
console.error(`${TAG53} file-delivery reject reason=no-account sender=${entry.senderId}`);
|
|
28593
28854
|
return { ok: false, error: "no-account" };
|
|
28594
28855
|
}
|
|
28595
|
-
const accountDir =
|
|
28856
|
+
const accountDir = resolve40(platformRoot2(), "..", "data/accounts", entry.accountId);
|
|
28596
28857
|
try {
|
|
28597
28858
|
const resolved = realpathSync9(filePath);
|
|
28598
28859
|
const accountResolved = realpathSync9(accountDir);
|
|
28599
28860
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
28600
|
-
console.error(`${
|
|
28861
|
+
console.error(`${TAG53} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
|
|
28601
28862
|
return { ok: false, error: "outside-account" };
|
|
28602
28863
|
}
|
|
28603
28864
|
return { ok: true };
|
|
28604
28865
|
} catch (err) {
|
|
28605
28866
|
const code = err.code;
|
|
28606
28867
|
console.error(
|
|
28607
|
-
`${
|
|
28868
|
+
`${TAG53} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
|
|
28608
28869
|
);
|
|
28609
28870
|
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
28610
28871
|
}
|
|
@@ -28613,7 +28874,7 @@ function makeWebchatSendFile(entry) {
|
|
|
28613
28874
|
function makeWebchatFileDelivery(entry) {
|
|
28614
28875
|
return makeFileDelivery({
|
|
28615
28876
|
entry,
|
|
28616
|
-
tag:
|
|
28877
|
+
tag: TAG53,
|
|
28617
28878
|
channel: "webchat",
|
|
28618
28879
|
sendFile: makeWebchatSendFile(entry),
|
|
28619
28880
|
deferUntilVerdict: true
|
|
@@ -28675,7 +28936,7 @@ function buildPublicWebchatSpawnRequest(input) {
|
|
|
28675
28936
|
}
|
|
28676
28937
|
|
|
28677
28938
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
28678
|
-
var
|
|
28939
|
+
var TAG54 = "[whatsapp-adaptor]";
|
|
28679
28940
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
28680
28941
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
28681
28942
|
function platformRoot3() {
|
|
@@ -28693,7 +28954,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
28693
28954
|
});
|
|
28694
28955
|
if (result.ok) return { ok: true };
|
|
28695
28956
|
console.error(
|
|
28696
|
-
`${
|
|
28957
|
+
`${TAG54} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
28697
28958
|
);
|
|
28698
28959
|
return { ok: false, error: result.error };
|
|
28699
28960
|
};
|
|
@@ -28701,7 +28962,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
28701
28962
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
28702
28963
|
const shared = makeFileDelivery({
|
|
28703
28964
|
entry,
|
|
28704
|
-
tag:
|
|
28965
|
+
tag: TAG54,
|
|
28705
28966
|
channel: "whatsapp",
|
|
28706
28967
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
28707
28968
|
});
|
|
@@ -28736,7 +28997,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
28736
28997
|
if (!delivered) {
|
|
28737
28998
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
28738
28999
|
console.error(
|
|
28739
|
-
`${
|
|
29000
|
+
`${TAG54} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
28740
29001
|
);
|
|
28741
29002
|
}
|
|
28742
29003
|
}
|
|
@@ -28919,8 +29180,8 @@ var InboundHub3 = class {
|
|
|
28919
29180
|
|
|
28920
29181
|
// app/lib/telegram/gateway/routes.ts
|
|
28921
29182
|
function createTelegramChannelRoutes(deps) {
|
|
28922
|
-
const
|
|
28923
|
-
|
|
29183
|
+
const app70 = new Hono();
|
|
29184
|
+
app70.get("/tg-channel/inbound", (c) => {
|
|
28924
29185
|
const key = c.req.query("key");
|
|
28925
29186
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
28926
29187
|
return streamSSE(c, async (stream2) => {
|
|
@@ -28938,7 +29199,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
28938
29199
|
}
|
|
28939
29200
|
});
|
|
28940
29201
|
});
|
|
28941
|
-
|
|
29202
|
+
app70.post("/tg-channel/reply", async (c) => {
|
|
28942
29203
|
const body = await c.req.json().catch(() => null);
|
|
28943
29204
|
const key = body?.key;
|
|
28944
29205
|
const text = body?.text;
|
|
@@ -28954,7 +29215,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
28954
29215
|
console.error(`[telegram-native] op=reply key=${key} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
28955
29216
|
return c.json({ ok: true });
|
|
28956
29217
|
});
|
|
28957
|
-
|
|
29218
|
+
app70.post("/tg-channel/ready", async (c) => {
|
|
28958
29219
|
const body = await c.req.json().catch(() => null);
|
|
28959
29220
|
const key = body?.key;
|
|
28960
29221
|
if (typeof key !== "string") {
|
|
@@ -28963,7 +29224,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
28963
29224
|
deps.onReady?.(key);
|
|
28964
29225
|
return c.json({ ok: true });
|
|
28965
29226
|
});
|
|
28966
|
-
|
|
29227
|
+
app70.post("/tg-channel/received", async (c) => {
|
|
28967
29228
|
const body = await c.req.json().catch(() => null);
|
|
28968
29229
|
const key = body?.key;
|
|
28969
29230
|
const messageId = body?.messageId;
|
|
@@ -28973,7 +29234,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
28973
29234
|
deps.onReceived?.(key, messageId);
|
|
28974
29235
|
return c.json({ ok: true });
|
|
28975
29236
|
});
|
|
28976
|
-
|
|
29237
|
+
app70.post("/tg-channel/turn-end", async (c) => {
|
|
28977
29238
|
const body = await c.req.json().catch(() => null);
|
|
28978
29239
|
const key = body?.key;
|
|
28979
29240
|
const sessionId = body?.sessionId;
|
|
@@ -29006,7 +29267,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
29006
29267
|
console.error(`[telegram-native] op=turn-end key=${key} sessionId=${sid} replied=no delivered=none`);
|
|
29007
29268
|
return c.json({ ok: true, delivered: "none" });
|
|
29008
29269
|
});
|
|
29009
|
-
return
|
|
29270
|
+
return app70;
|
|
29010
29271
|
}
|
|
29011
29272
|
|
|
29012
29273
|
// app/lib/telegram/gateway/telegram-gateway.ts
|
|
@@ -29156,8 +29417,8 @@ function buildTelegramSpawnRequest(input) {
|
|
|
29156
29417
|
// app/lib/telegram/outbound/send-document.ts
|
|
29157
29418
|
import { realpathSync as realpathSync10 } from "fs";
|
|
29158
29419
|
import { readFile as readFile11, stat as stat10 } from "fs/promises";
|
|
29159
|
-
import { resolve as
|
|
29160
|
-
var
|
|
29420
|
+
import { resolve as resolve41, basename as basename13 } from "path";
|
|
29421
|
+
var TAG55 = "[telegram:outbound]";
|
|
29161
29422
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
29162
29423
|
async function sendTelegramDocument(input) {
|
|
29163
29424
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
@@ -29167,17 +29428,17 @@ async function sendTelegramDocument(input) {
|
|
|
29167
29428
|
if (!maxyAccountId || !platformRoot5) {
|
|
29168
29429
|
return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
|
|
29169
29430
|
}
|
|
29170
|
-
const accountDir =
|
|
29431
|
+
const accountDir = resolve41(platformRoot5, "..", "data/accounts", maxyAccountId);
|
|
29171
29432
|
let accountResolved;
|
|
29172
29433
|
try {
|
|
29173
29434
|
accountResolved = realpathSync10(accountDir);
|
|
29174
29435
|
} catch (err) {
|
|
29175
29436
|
const code = err.code;
|
|
29176
29437
|
if (code === "ENOENT") {
|
|
29177
|
-
console.error(`${
|
|
29438
|
+
console.error(`${TAG55} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
|
|
29178
29439
|
return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
|
|
29179
29440
|
}
|
|
29180
|
-
console.error(`${
|
|
29441
|
+
console.error(`${TAG55} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
29181
29442
|
return { ok: false, status: 500, error: String(err) };
|
|
29182
29443
|
}
|
|
29183
29444
|
let resolvedPath;
|
|
@@ -29186,14 +29447,14 @@ async function sendTelegramDocument(input) {
|
|
|
29186
29447
|
} catch (err) {
|
|
29187
29448
|
const code = err.code;
|
|
29188
29449
|
if (code === "ENOENT") {
|
|
29189
|
-
console.error(`${
|
|
29450
|
+
console.error(`${TAG55} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
|
|
29190
29451
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
29191
29452
|
}
|
|
29192
|
-
console.error(`${
|
|
29453
|
+
console.error(`${TAG55} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
29193
29454
|
return { ok: false, status: 500, error: String(err) };
|
|
29194
29455
|
}
|
|
29195
29456
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
29196
|
-
console.error(`${
|
|
29457
|
+
console.error(`${TAG55} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
29197
29458
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
29198
29459
|
}
|
|
29199
29460
|
const fileStat = await stat10(resolvedPath);
|
|
@@ -29226,13 +29487,13 @@ async function sendTelegramDocument(input) {
|
|
|
29226
29487
|
error = e instanceof Error ? e.message : String(e);
|
|
29227
29488
|
}
|
|
29228
29489
|
console.error(
|
|
29229
|
-
`${
|
|
29490
|
+
`${TAG55} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
29230
29491
|
);
|
|
29231
29492
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
29232
29493
|
}
|
|
29233
29494
|
|
|
29234
29495
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
29235
|
-
var
|
|
29496
|
+
var TAG56 = "[telegram:outbound]";
|
|
29236
29497
|
function platformRoot4() {
|
|
29237
29498
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
29238
29499
|
}
|
|
@@ -29244,11 +29505,11 @@ function makeTelegramSendFile(entry) {
|
|
|
29244
29505
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
29245
29506
|
}
|
|
29246
29507
|
if (!botToken) {
|
|
29247
|
-
console.error(`${
|
|
29508
|
+
console.error(`${TAG56} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
29248
29509
|
return { ok: false, error: "no-bot-token" };
|
|
29249
29510
|
}
|
|
29250
29511
|
if (entry.replyTarget == null) {
|
|
29251
|
-
console.error(`${
|
|
29512
|
+
console.error(`${TAG56} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
29252
29513
|
return { ok: false, error: "no-reply-target" };
|
|
29253
29514
|
}
|
|
29254
29515
|
const result = await sendTelegramDocument({
|
|
@@ -29265,7 +29526,7 @@ function makeTelegramSendFile(entry) {
|
|
|
29265
29526
|
function makeTelegramFileDelivery(entry) {
|
|
29266
29527
|
return makeFileDelivery({
|
|
29267
29528
|
entry,
|
|
29268
|
-
tag:
|
|
29529
|
+
tag: TAG56,
|
|
29269
29530
|
channel: "telegram",
|
|
29270
29531
|
sendFile: makeTelegramSendFile(entry)
|
|
29271
29532
|
});
|
|
@@ -29306,7 +29567,7 @@ function startTelegramNativeFileFollower(input) {
|
|
|
29306
29567
|
|
|
29307
29568
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
29308
29569
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
29309
|
-
var
|
|
29570
|
+
var TAG57 = "[public-session-review]";
|
|
29310
29571
|
var CONSUMED_CAP = 500;
|
|
29311
29572
|
var consumed = /* @__PURE__ */ new Set();
|
|
29312
29573
|
function consumeOnce(sessionId) {
|
|
@@ -29333,7 +29594,7 @@ async function fetchJsonl(sessionId) {
|
|
|
29333
29594
|
return await res.text();
|
|
29334
29595
|
} catch (err) {
|
|
29335
29596
|
console.error(
|
|
29336
|
-
`${
|
|
29597
|
+
`${TAG57} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
29337
29598
|
);
|
|
29338
29599
|
return null;
|
|
29339
29600
|
}
|
|
@@ -29357,7 +29618,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
29357
29618
|
const res = await fetch(url);
|
|
29358
29619
|
if (!res.ok) {
|
|
29359
29620
|
console.error(
|
|
29360
|
-
`${
|
|
29621
|
+
`${TAG57} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
29361
29622
|
);
|
|
29362
29623
|
return [];
|
|
29363
29624
|
}
|
|
@@ -29365,7 +29626,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
29365
29626
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
29366
29627
|
} catch (err) {
|
|
29367
29628
|
console.error(
|
|
29368
|
-
`${
|
|
29629
|
+
`${TAG57} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
29369
29630
|
);
|
|
29370
29631
|
return [];
|
|
29371
29632
|
}
|
|
@@ -29394,7 +29655,7 @@ function composeInitialMessage(input) {
|
|
|
29394
29655
|
}
|
|
29395
29656
|
async function dispatchReviewer(input, initialMessage) {
|
|
29396
29657
|
const sessionId = randomUUID16();
|
|
29397
|
-
console.log(`${
|
|
29658
|
+
console.log(`${TAG57} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
29398
29659
|
const spawned = await managerRcSpawn({
|
|
29399
29660
|
sessionId,
|
|
29400
29661
|
initialMessage,
|
|
@@ -29414,21 +29675,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
29414
29675
|
const dispatchedAt = Date.now();
|
|
29415
29676
|
if (consumed.has(input.sessionId)) {
|
|
29416
29677
|
console.log(
|
|
29417
|
-
`${
|
|
29678
|
+
`${TAG57} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
29418
29679
|
);
|
|
29419
29680
|
return;
|
|
29420
29681
|
}
|
|
29421
29682
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
29422
29683
|
if (!jsonl) {
|
|
29423
29684
|
console.log(
|
|
29424
|
-
`${
|
|
29685
|
+
`${TAG57} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
29425
29686
|
);
|
|
29426
29687
|
return;
|
|
29427
29688
|
}
|
|
29428
29689
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
29429
29690
|
if (operatorTurns === 0) {
|
|
29430
29691
|
console.log(
|
|
29431
|
-
`${
|
|
29692
|
+
`${TAG57} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
29432
29693
|
);
|
|
29433
29694
|
return;
|
|
29434
29695
|
}
|
|
@@ -29442,19 +29703,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
29442
29703
|
});
|
|
29443
29704
|
if (!consumeOnce(input.sessionId)) {
|
|
29444
29705
|
console.log(
|
|
29445
|
-
`${
|
|
29706
|
+
`${TAG57} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
29446
29707
|
);
|
|
29447
29708
|
return;
|
|
29448
29709
|
}
|
|
29449
29710
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
29450
29711
|
if (!dispatched.ok) {
|
|
29451
29712
|
console.error(
|
|
29452
|
-
`${
|
|
29713
|
+
`${TAG57} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
29453
29714
|
);
|
|
29454
29715
|
return;
|
|
29455
29716
|
}
|
|
29456
29717
|
console.log(
|
|
29457
|
-
`${
|
|
29718
|
+
`${TAG57} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
29458
29719
|
);
|
|
29459
29720
|
}
|
|
29460
29721
|
|
|
@@ -29559,14 +29820,14 @@ function warnOnChannelAdminBindingDrift() {
|
|
|
29559
29820
|
}
|
|
29560
29821
|
|
|
29561
29822
|
// server/lib/booking-site-accounts.ts
|
|
29562
|
-
import { existsSync as
|
|
29563
|
-
import { resolve as
|
|
29823
|
+
import { existsSync as existsSync44, readFileSync as readFileSync45 } from "fs";
|
|
29824
|
+
import { resolve as resolve42 } from "path";
|
|
29564
29825
|
function listBookingSiteAccounts(accounts) {
|
|
29565
29826
|
return accounts.filter((a) => {
|
|
29566
|
-
const availPath =
|
|
29567
|
-
if (!
|
|
29827
|
+
const availPath = resolve42(a.accountDir, "calendar-availability.json");
|
|
29828
|
+
if (!existsSync44(availPath)) return false;
|
|
29568
29829
|
try {
|
|
29569
|
-
const cfg = JSON.parse(
|
|
29830
|
+
const cfg = JSON.parse(readFileSync45(availPath, "utf-8"));
|
|
29570
29831
|
return typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
29571
29832
|
} catch {
|
|
29572
29833
|
return false;
|
|
@@ -29604,8 +29865,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
29604
29865
|
|
|
29605
29866
|
// ../lib/entitlement/src/index.ts
|
|
29606
29867
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
29607
|
-
import { existsSync as
|
|
29608
|
-
import { resolve as
|
|
29868
|
+
import { existsSync as existsSync45, readFileSync as readFileSync46, statSync as statSync19 } from "fs";
|
|
29869
|
+
import { resolve as resolve43 } from "path";
|
|
29609
29870
|
|
|
29610
29871
|
// ../lib/entitlement/src/canonicalize.ts
|
|
29611
29872
|
function canonicalize(value) {
|
|
@@ -29640,7 +29901,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
29640
29901
|
var GRACE_DAYS = 7;
|
|
29641
29902
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
29642
29903
|
function pubkeyPath(brand) {
|
|
29643
|
-
return
|
|
29904
|
+
return resolve43(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
29644
29905
|
}
|
|
29645
29906
|
var memo = null;
|
|
29646
29907
|
function memoKey(mtimeMs, account) {
|
|
@@ -29652,8 +29913,8 @@ function resolveEntitlement(brand, account) {
|
|
|
29652
29913
|
if (brand.commercialMode !== true) {
|
|
29653
29914
|
return logResolved(implicitTrust(account), null);
|
|
29654
29915
|
}
|
|
29655
|
-
const entitlementPath =
|
|
29656
|
-
if (!
|
|
29916
|
+
const entitlementPath = resolve43(brand.configDir, "entitlement.json");
|
|
29917
|
+
if (!existsSync45(entitlementPath)) {
|
|
29657
29918
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
29658
29919
|
}
|
|
29659
29920
|
const stat11 = statSync19(entitlementPath);
|
|
@@ -29668,7 +29929,7 @@ function resolveEntitlement(brand, account) {
|
|
|
29668
29929
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
29669
29930
|
let pubkeyPem;
|
|
29670
29931
|
try {
|
|
29671
|
-
pubkeyPem =
|
|
29932
|
+
pubkeyPem = readFileSync46(pubkeyPath(brand), "utf-8");
|
|
29672
29933
|
} catch (err) {
|
|
29673
29934
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
29674
29935
|
reason: "pubkey-missing"
|
|
@@ -29682,7 +29943,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
29682
29943
|
}
|
|
29683
29944
|
let envelope;
|
|
29684
29945
|
try {
|
|
29685
|
-
envelope = JSON.parse(
|
|
29946
|
+
envelope = JSON.parse(readFileSync46(entitlementPath, "utf-8"));
|
|
29686
29947
|
} catch {
|
|
29687
29948
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
29688
29949
|
}
|
|
@@ -29846,12 +30107,12 @@ installMediaDownloadGuard();
|
|
|
29846
30107
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
29847
30108
|
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join47(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
29848
30109
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
29849
|
-
if (BRAND_JSON_PATH && !
|
|
30110
|
+
if (BRAND_JSON_PATH && !existsSync46(BRAND_JSON_PATH)) {
|
|
29850
30111
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
29851
30112
|
}
|
|
29852
|
-
if (BRAND_JSON_PATH &&
|
|
30113
|
+
if (BRAND_JSON_PATH && existsSync46(BRAND_JSON_PATH)) {
|
|
29853
30114
|
try {
|
|
29854
|
-
const parsed = JSON.parse(
|
|
30115
|
+
const parsed = JSON.parse(readFileSync47(BRAND_JSON_PATH, "utf-8"));
|
|
29855
30116
|
BRAND = { ...BRAND, ...parsed };
|
|
29856
30117
|
} catch (err) {
|
|
29857
30118
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -29886,8 +30147,8 @@ var brandLoginOpts = {
|
|
|
29886
30147
|
var ALIAS_DOMAINS_PATH = join47(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
29887
30148
|
function loadAliasDomains() {
|
|
29888
30149
|
try {
|
|
29889
|
-
if (!
|
|
29890
|
-
const parsed = JSON.parse(
|
|
30150
|
+
if (!existsSync46(ALIAS_DOMAINS_PATH)) return null;
|
|
30151
|
+
const parsed = JSON.parse(readFileSync47(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
29891
30152
|
if (!Array.isArray(parsed)) {
|
|
29892
30153
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
29893
30154
|
return null;
|
|
@@ -29911,7 +30172,7 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
29911
30172
|
function isPublicHost(host) {
|
|
29912
30173
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
29913
30174
|
}
|
|
29914
|
-
var
|
|
30175
|
+
var app69 = new Hono();
|
|
29915
30176
|
function resolveChannelOverride(accountId, channel, senderId) {
|
|
29916
30177
|
try {
|
|
29917
30178
|
const dir = listValidAccounts().find((a) => a.accountId === accountId)?.accountDir;
|
|
@@ -29960,7 +30221,7 @@ var waGateway = new WaGateway({
|
|
|
29960
30221
|
fetchStandingRules: fetchAccountStandingRules,
|
|
29961
30222
|
resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
|
|
29962
30223
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
29963
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
30224
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve44(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
29964
30225
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
29965
30226
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
29966
30227
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -29975,7 +30236,7 @@ var waGateway = new WaGateway({
|
|
|
29975
30236
|
caption,
|
|
29976
30237
|
accountId,
|
|
29977
30238
|
maxyAccountId,
|
|
29978
|
-
platformRoot:
|
|
30239
|
+
platformRoot: resolve44(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."))
|
|
29979
30240
|
});
|
|
29980
30241
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
29981
30242
|
},
|
|
@@ -30087,7 +30348,7 @@ var waGateway = new WaGateway({
|
|
|
30087
30348
|
nativeFileFollowers.set(senderId, ac);
|
|
30088
30349
|
}
|
|
30089
30350
|
});
|
|
30090
|
-
|
|
30351
|
+
app69.route("/", waGateway.routes());
|
|
30091
30352
|
waGateway.startSweeper();
|
|
30092
30353
|
function runDuplicateSenderAudit() {
|
|
30093
30354
|
try {
|
|
@@ -30210,7 +30471,7 @@ var webchatGateway = new WebchatGateway({
|
|
|
30210
30471
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
30211
30472
|
});
|
|
30212
30473
|
setWebchatGateway(webchatGateway);
|
|
30213
|
-
|
|
30474
|
+
app69.route("/", webchatGateway.routes());
|
|
30214
30475
|
webchatGateway.startSweeper();
|
|
30215
30476
|
webchatGateway.startPublicReaper();
|
|
30216
30477
|
var telegramFileFollowers = /* @__PURE__ */ new Map();
|
|
@@ -30254,7 +30515,7 @@ var telegramGateway = new TelegramGateway({
|
|
|
30254
30515
|
}
|
|
30255
30516
|
});
|
|
30256
30517
|
setTelegramGateway(telegramGateway);
|
|
30257
|
-
|
|
30518
|
+
app69.route("/", telegramGateway.routes());
|
|
30258
30519
|
telegramGateway.startSweeper();
|
|
30259
30520
|
var chatRoutes = createChatRoutes({
|
|
30260
30521
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
@@ -30288,19 +30549,19 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
30288
30549
|
return managed.account;
|
|
30289
30550
|
}
|
|
30290
30551
|
});
|
|
30291
|
-
|
|
30292
|
-
|
|
30552
|
+
app69.route("/api/channel/schedule-inject", scheduleInjectRoutes);
|
|
30553
|
+
app69.use("*", clientIpMiddleware);
|
|
30293
30554
|
function allowsSameOriginFraming(path3) {
|
|
30294
30555
|
return path3 === "/vnc-viewer.html" || path3.startsWith("/api/admin/attachment/") || path3.startsWith("/api/public-reader/attachment/") || path3 === "/api/admin/files/download" || path3 === "/api/admin/session-upload";
|
|
30295
30556
|
}
|
|
30296
|
-
|
|
30557
|
+
app69.use("*", async (c, next) => {
|
|
30297
30558
|
await next();
|
|
30298
30559
|
c.header("X-Content-Type-Options", "nosniff");
|
|
30299
30560
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
30300
30561
|
c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
|
|
30301
30562
|
});
|
|
30302
30563
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
30303
|
-
|
|
30564
|
+
app69.use("*", async (c, next) => {
|
|
30304
30565
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
30305
30566
|
await next();
|
|
30306
30567
|
return;
|
|
@@ -30318,7 +30579,7 @@ app67.use("*", async (c, next) => {
|
|
|
30318
30579
|
});
|
|
30319
30580
|
}
|
|
30320
30581
|
});
|
|
30321
|
-
|
|
30582
|
+
app69.use("*", async (c, next) => {
|
|
30322
30583
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
30323
30584
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
30324
30585
|
await next();
|
|
@@ -30356,7 +30617,7 @@ function resolveRemoteAuthOpts(c) {
|
|
|
30356
30617
|
return { ...brandLoginOpts, origin };
|
|
30357
30618
|
}
|
|
30358
30619
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
30359
|
-
|
|
30620
|
+
app69.post("/__remote-auth/login", async (c) => {
|
|
30360
30621
|
const client = clientFrom(c);
|
|
30361
30622
|
const clientIp = client.ip || "unknown";
|
|
30362
30623
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -30401,7 +30662,7 @@ app67.post("/__remote-auth/login", async (c) => {
|
|
|
30401
30662
|
}
|
|
30402
30663
|
});
|
|
30403
30664
|
});
|
|
30404
|
-
|
|
30665
|
+
app69.get("/__remote-auth/logout", (c) => {
|
|
30405
30666
|
const client = clientFrom(c);
|
|
30406
30667
|
const clientIp = client.ip || "unknown";
|
|
30407
30668
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -30414,7 +30675,7 @@ app67.get("/__remote-auth/logout", (c) => {
|
|
|
30414
30675
|
}
|
|
30415
30676
|
});
|
|
30416
30677
|
});
|
|
30417
|
-
|
|
30678
|
+
app69.post("/__remote-auth/change-password", async (c) => {
|
|
30418
30679
|
const client = clientFrom(c);
|
|
30419
30680
|
const clientIp = client.ip || "unknown";
|
|
30420
30681
|
const rateLimited = checkRateLimit(client);
|
|
@@ -30473,13 +30734,13 @@ app67.post("/__remote-auth/change-password", async (c) => {
|
|
|
30473
30734
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
30474
30735
|
}
|
|
30475
30736
|
});
|
|
30476
|
-
|
|
30737
|
+
app69.get("/__remote-auth/setup", (c) => {
|
|
30477
30738
|
if (isRemoteAuthConfigured()) {
|
|
30478
30739
|
return c.redirect("/");
|
|
30479
30740
|
}
|
|
30480
30741
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
|
|
30481
30742
|
});
|
|
30482
|
-
|
|
30743
|
+
app69.post("/__remote-auth/set-initial-password", async (c) => {
|
|
30483
30744
|
if (isRemoteAuthConfigured()) {
|
|
30484
30745
|
return c.redirect("/");
|
|
30485
30746
|
}
|
|
@@ -30517,10 +30778,10 @@ app67.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
30517
30778
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
30518
30779
|
}
|
|
30519
30780
|
});
|
|
30520
|
-
|
|
30781
|
+
app69.get("/api/remote-auth/status", (c) => {
|
|
30521
30782
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
30522
30783
|
});
|
|
30523
|
-
|
|
30784
|
+
app69.post("/api/remote-auth/set-password", async (c) => {
|
|
30524
30785
|
let body;
|
|
30525
30786
|
try {
|
|
30526
30787
|
body = await c.req.json();
|
|
@@ -30559,10 +30820,10 @@ app67.post("/api/remote-auth/set-password", async (c) => {
|
|
|
30559
30820
|
return c.json({ error: "Failed to save password" }, 500);
|
|
30560
30821
|
}
|
|
30561
30822
|
});
|
|
30562
|
-
|
|
30823
|
+
app69.route("/api/_client-error", client_error_default);
|
|
30563
30824
|
console.log("[client-error-route] mounted");
|
|
30564
30825
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
30565
|
-
|
|
30826
|
+
app69.use("*", async (c, next) => {
|
|
30566
30827
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
30567
30828
|
const path3 = c.req.path;
|
|
30568
30829
|
if (path3 === "/favicon.ico" || path3.startsWith("/assets/") || path3.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
|
|
@@ -30606,28 +30867,28 @@ app67.use("*", async (c, next) => {
|
|
|
30606
30867
|
}
|
|
30607
30868
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path3 }), 200);
|
|
30608
30869
|
});
|
|
30609
|
-
|
|
30610
|
-
|
|
30611
|
-
|
|
30612
|
-
|
|
30613
|
-
|
|
30614
|
-
|
|
30615
|
-
|
|
30870
|
+
app69.route("/api/health", health_default);
|
|
30871
|
+
app69.route("/api/chat", chatRoutes);
|
|
30872
|
+
app69.route("/api/whatsapp", whatsapp_default);
|
|
30873
|
+
app69.route("/api/storage", storage_broker_default);
|
|
30874
|
+
app69.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
30875
|
+
app69.route("/api/public-reader", public_reader_default);
|
|
30876
|
+
app69.route("/api/webchat", createWebchatRoutes({
|
|
30616
30877
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
30617
30878
|
// Task 940 — the permission relay's pointer read + verdict write.
|
|
30618
30879
|
pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
|
|
30619
30880
|
deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
|
|
30620
30881
|
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
30621
30882
|
}));
|
|
30622
|
-
|
|
30623
|
-
|
|
30624
|
-
|
|
30625
|
-
|
|
30626
|
-
|
|
30627
|
-
|
|
30628
|
-
|
|
30629
|
-
|
|
30630
|
-
|
|
30883
|
+
app69.route("/api/webchat/greeting", webchat_greeting_default);
|
|
30884
|
+
app69.route("/api/telegram", telegram_default);
|
|
30885
|
+
app69.route("/api/quickbooks", quickbooks_default);
|
|
30886
|
+
app69.route("/api/onboarding", onboarding_default);
|
|
30887
|
+
app69.route("/api/admin", admin_default);
|
|
30888
|
+
app69.route("/api/access", access_default);
|
|
30889
|
+
app69.route("/api/session", session_default2);
|
|
30890
|
+
app69.route("/api/calendar", calendar_public_default);
|
|
30891
|
+
app69.route("/api/portal", portal_fetch_default);
|
|
30631
30892
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
30632
30893
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
30633
30894
|
var IMAGE_MIME = {
|
|
@@ -30639,7 +30900,7 @@ var IMAGE_MIME = {
|
|
|
30639
30900
|
".svg": "image/svg+xml",
|
|
30640
30901
|
".ico": "image/x-icon"
|
|
30641
30902
|
};
|
|
30642
|
-
|
|
30903
|
+
app69.get("/agent-assets/:slug/:filename", (c) => {
|
|
30643
30904
|
const slug = c.req.param("slug");
|
|
30644
30905
|
const filename = c.req.param("filename");
|
|
30645
30906
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -30655,26 +30916,26 @@ app67.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
30655
30916
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
30656
30917
|
return c.text("Not found", 404);
|
|
30657
30918
|
}
|
|
30658
|
-
const filePath =
|
|
30659
|
-
const expectedDir =
|
|
30919
|
+
const filePath = resolve44(account.accountDir, "agents", slug, "assets", filename);
|
|
30920
|
+
const expectedDir = resolve44(account.accountDir, "agents", slug, "assets");
|
|
30660
30921
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
30661
30922
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
30662
30923
|
return c.text("Forbidden", 403);
|
|
30663
30924
|
}
|
|
30664
|
-
if (!
|
|
30925
|
+
if (!existsSync46(filePath)) {
|
|
30665
30926
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
30666
30927
|
return c.text("Not found", 404);
|
|
30667
30928
|
}
|
|
30668
30929
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
30669
30930
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
30670
30931
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
30671
|
-
const body =
|
|
30932
|
+
const body = readFileSync47(filePath);
|
|
30672
30933
|
return c.body(body, 200, {
|
|
30673
30934
|
"Content-Type": contentType,
|
|
30674
30935
|
"Cache-Control": "public, max-age=3600"
|
|
30675
30936
|
});
|
|
30676
30937
|
});
|
|
30677
|
-
|
|
30938
|
+
app69.get("/generated/:filename", (c) => {
|
|
30678
30939
|
const filename = c.req.param("filename");
|
|
30679
30940
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
30680
30941
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -30685,35 +30946,35 @@ app67.get("/generated/:filename", (c) => {
|
|
|
30685
30946
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
30686
30947
|
return c.text("Not found", 404);
|
|
30687
30948
|
}
|
|
30688
|
-
const filePath =
|
|
30689
|
-
const expectedDir =
|
|
30949
|
+
const filePath = resolve44(account.accountDir, "generated", filename);
|
|
30950
|
+
const expectedDir = resolve44(account.accountDir, "generated");
|
|
30690
30951
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
30691
30952
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
30692
30953
|
return c.text("Forbidden", 403);
|
|
30693
30954
|
}
|
|
30694
|
-
if (!
|
|
30955
|
+
if (!existsSync46(filePath)) {
|
|
30695
30956
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
30696
30957
|
return c.text("Not found", 404);
|
|
30697
30958
|
}
|
|
30698
30959
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
30699
30960
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
30700
30961
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
30701
|
-
const body =
|
|
30962
|
+
const body = readFileSync47(filePath);
|
|
30702
30963
|
return c.body(body, 200, {
|
|
30703
30964
|
"Content-Type": contentType,
|
|
30704
30965
|
"Cache-Control": "public, max-age=86400"
|
|
30705
30966
|
});
|
|
30706
30967
|
});
|
|
30707
|
-
|
|
30708
|
-
|
|
30709
|
-
|
|
30710
|
-
|
|
30968
|
+
app69.route("/sites", sites_default);
|
|
30969
|
+
app69.route("/listings", listings_default);
|
|
30970
|
+
app69.route("/v", visitor_event_default);
|
|
30971
|
+
app69.route("/v", visitor_consent_default);
|
|
30711
30972
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
30712
30973
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
30713
30974
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
30714
|
-
if (BRAND_JSON_PATH &&
|
|
30975
|
+
if (BRAND_JSON_PATH && existsSync46(BRAND_JSON_PATH)) {
|
|
30715
30976
|
try {
|
|
30716
|
-
const fullBrand = JSON.parse(
|
|
30977
|
+
const fullBrand = JSON.parse(readFileSync47(BRAND_JSON_PATH, "utf-8"));
|
|
30717
30978
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
30718
30979
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
30719
30980
|
} catch {
|
|
@@ -30740,11 +31001,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
30740
31001
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
30741
31002
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
30742
31003
|
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
30743
|
-
(p) =>
|
|
31004
|
+
(p) => existsSync46(resolve44(process.cwd(), "public", p.replace(/^\//, "")))
|
|
30744
31005
|
);
|
|
30745
31006
|
var SW_SOURCE = (() => {
|
|
30746
31007
|
try {
|
|
30747
|
-
return
|
|
31008
|
+
return readFileSync47(resolve44(process.cwd(), "public", "sw.js"), "utf-8");
|
|
30748
31009
|
} catch {
|
|
30749
31010
|
return null;
|
|
30750
31011
|
}
|
|
@@ -30753,8 +31014,8 @@ function readInstalledVersion() {
|
|
|
30753
31014
|
try {
|
|
30754
31015
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
30755
31016
|
const versionFile = join47(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
30756
|
-
if (!
|
|
30757
|
-
const content =
|
|
31017
|
+
if (!existsSync46(versionFile)) return "unknown";
|
|
31018
|
+
const content = readFileSync47(versionFile, "utf-8").trim();
|
|
30758
31019
|
return content || "unknown";
|
|
30759
31020
|
} catch {
|
|
30760
31021
|
return "unknown";
|
|
@@ -30795,7 +31056,7 @@ var clientErrorReporterScript = `<script>
|
|
|
30795
31056
|
function cachedHtml(file) {
|
|
30796
31057
|
let html = htmlCache.get(file);
|
|
30797
31058
|
if (!html) {
|
|
30798
|
-
html =
|
|
31059
|
+
html = readFileSync47(resolve44(process.cwd(), "public", file), "utf-8");
|
|
30799
31060
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
30800
31061
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
30801
31062
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -30817,8 +31078,8 @@ function loadBrandingCache(agentSlug) {
|
|
|
30817
31078
|
const accountId = getDefaultAccountId();
|
|
30818
31079
|
if (!accountId) return null;
|
|
30819
31080
|
const cachePath = join47(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
30820
|
-
if (!
|
|
30821
|
-
return JSON.parse(
|
|
31081
|
+
if (!existsSync46(cachePath)) return null;
|
|
31082
|
+
return JSON.parse(readFileSync47(cachePath, "utf-8"));
|
|
30822
31083
|
} catch {
|
|
30823
31084
|
return null;
|
|
30824
31085
|
}
|
|
@@ -30862,7 +31123,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
30862
31123
|
function agentUnavailableHtml() {
|
|
30863
31124
|
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>`;
|
|
30864
31125
|
}
|
|
30865
|
-
|
|
31126
|
+
app69.get("/", (c) => {
|
|
30866
31127
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
30867
31128
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
30868
31129
|
if (klass === "operator") {
|
|
@@ -30884,12 +31145,12 @@ app67.get("/", (c) => {
|
|
|
30884
31145
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
30885
31146
|
return c.html(cachedHtml("index.html"));
|
|
30886
31147
|
});
|
|
30887
|
-
|
|
31148
|
+
app69.get("/public", (c) => {
|
|
30888
31149
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
30889
31150
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
30890
31151
|
return c.html(cachedHtml("public.html"));
|
|
30891
31152
|
});
|
|
30892
|
-
|
|
31153
|
+
app69.get("/public-chat", (c) => {
|
|
30893
31154
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
30894
31155
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
30895
31156
|
return c.html(cachedHtml("public.html"));
|
|
@@ -30908,12 +31169,12 @@ async function logViewerFetch(c, next) {
|
|
|
30908
31169
|
duration_ms: Date.now() - start
|
|
30909
31170
|
});
|
|
30910
31171
|
}
|
|
30911
|
-
|
|
30912
|
-
|
|
30913
|
-
|
|
31172
|
+
app69.use("/vnc-viewer.html", logViewerFetch);
|
|
31173
|
+
app69.use("/vnc-popout.html", logViewerFetch);
|
|
31174
|
+
app69.get("/vnc-popout.html", (c) => {
|
|
30914
31175
|
let html = htmlCache.get("vnc-popout.html");
|
|
30915
31176
|
if (!html) {
|
|
30916
|
-
html =
|
|
31177
|
+
html = readFileSync47(resolve44(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
30917
31178
|
const name = escapeHtml(BRAND.productName);
|
|
30918
31179
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
30919
31180
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -30923,7 +31184,7 @@ app67.get("/vnc-popout.html", (c) => {
|
|
|
30923
31184
|
}
|
|
30924
31185
|
return c.html(html);
|
|
30925
31186
|
});
|
|
30926
|
-
|
|
31187
|
+
app69.post("/api/vnc/client-event", async (c) => {
|
|
30927
31188
|
let body;
|
|
30928
31189
|
try {
|
|
30929
31190
|
body = await c.req.json();
|
|
@@ -30944,11 +31205,11 @@ app67.post("/api/vnc/client-event", async (c) => {
|
|
|
30944
31205
|
});
|
|
30945
31206
|
return c.json({ ok: true });
|
|
30946
31207
|
});
|
|
30947
|
-
|
|
31208
|
+
app69.get("/g/:slug", (c) => {
|
|
30948
31209
|
return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
|
|
30949
31210
|
});
|
|
30950
31211
|
for (const pwa of PWA_SURFACES) {
|
|
30951
|
-
|
|
31212
|
+
app69.get(pwa.manifestPath, (c) => {
|
|
30952
31213
|
const manifest = buildManifest(pwa, {
|
|
30953
31214
|
productName: BRAND.productName,
|
|
30954
31215
|
appIcon192: brandAppIcon192Path,
|
|
@@ -30964,7 +31225,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
30964
31225
|
return c.body(JSON.stringify(manifest));
|
|
30965
31226
|
});
|
|
30966
31227
|
}
|
|
30967
|
-
|
|
31228
|
+
app69.get("/sw.js", (c) => {
|
|
30968
31229
|
if (SW_SOURCE == null) {
|
|
30969
31230
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
30970
31231
|
return c.text("Service worker unavailable", 500);
|
|
@@ -30973,12 +31234,12 @@ app67.get("/sw.js", (c) => {
|
|
|
30973
31234
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
30974
31235
|
return c.body(SW_SOURCE);
|
|
30975
31236
|
});
|
|
30976
|
-
|
|
31237
|
+
app69.get("/graph", (c) => {
|
|
30977
31238
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
30978
31239
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
30979
31240
|
return c.html(cachedHtml("graph.html"));
|
|
30980
31241
|
});
|
|
30981
|
-
|
|
31242
|
+
app69.get("/chat", (c) => {
|
|
30982
31243
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
30983
31244
|
if (isOperatorHost(host, getOperatorDomains())) {
|
|
30984
31245
|
console.log(`[host-class] host=${host} class=operator served=operator.html`);
|
|
@@ -30987,42 +31248,47 @@ app67.get("/chat", (c) => {
|
|
|
30987
31248
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
30988
31249
|
return c.html(cachedHtml("chat.html"));
|
|
30989
31250
|
});
|
|
30990
|
-
|
|
31251
|
+
app69.get("/data", (c) => {
|
|
30991
31252
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
30992
31253
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
30993
31254
|
return c.html(cachedHtml("data.html"));
|
|
30994
31255
|
});
|
|
30995
|
-
|
|
31256
|
+
app69.get("/tasks", (c) => {
|
|
30996
31257
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
30997
31258
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
30998
31259
|
return c.html(cachedHtml("tasks.html"));
|
|
30999
31260
|
});
|
|
31000
|
-
|
|
31261
|
+
app69.get("/activity", (c) => {
|
|
31001
31262
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
31002
31263
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
31003
31264
|
return c.html(cachedHtml("activity.html"));
|
|
31004
31265
|
});
|
|
31005
|
-
|
|
31266
|
+
app69.get("/calendar", (c) => {
|
|
31006
31267
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
31007
31268
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
31008
31269
|
return c.html(cachedHtml("calendar.html"));
|
|
31009
31270
|
});
|
|
31010
|
-
|
|
31271
|
+
app69.get("/routines", (c) => {
|
|
31011
31272
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
31012
31273
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
31013
31274
|
return c.html(cachedHtml("routines.html"));
|
|
31014
31275
|
});
|
|
31015
|
-
|
|
31276
|
+
app69.get("/skills", (c) => {
|
|
31016
31277
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
31017
31278
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
31018
31279
|
return c.html(cachedHtml("skills.html"));
|
|
31019
31280
|
});
|
|
31020
|
-
|
|
31281
|
+
app69.get("/agents", (c) => {
|
|
31282
|
+
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
31283
|
+
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
31284
|
+
return c.html(cachedHtml("agents.html"));
|
|
31285
|
+
});
|
|
31286
|
+
app69.get("/browser", (c) => {
|
|
31021
31287
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
31022
31288
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
31023
31289
|
return c.html(cachedHtml("browser.html"));
|
|
31024
31290
|
});
|
|
31025
|
-
|
|
31291
|
+
app69.get("/:slug", async (c, next) => {
|
|
31026
31292
|
const slug = c.req.param("slug");
|
|
31027
31293
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
31028
31294
|
const account = resolveAccount();
|
|
@@ -31037,13 +31303,13 @@ app67.get("/:slug", async (c, next) => {
|
|
|
31037
31303
|
await next();
|
|
31038
31304
|
});
|
|
31039
31305
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
31040
|
-
|
|
31306
|
+
app69.get("/favicon.ico", (c) => {
|
|
31041
31307
|
c.header("Cache-Control", "public, max-age=300");
|
|
31042
31308
|
return c.redirect(brandFaviconPath, 302);
|
|
31043
31309
|
});
|
|
31044
31310
|
}
|
|
31045
|
-
|
|
31046
|
-
|
|
31311
|
+
app69.use("/*", serveStatic({ root: "./public" }));
|
|
31312
|
+
app69.all("*", (c) => {
|
|
31047
31313
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
31048
31314
|
const path3 = c.req.path;
|
|
31049
31315
|
if (isPublicHost(host)) {
|
|
@@ -31057,13 +31323,13 @@ app67.all("*", (c) => {
|
|
|
31057
31323
|
});
|
|
31058
31324
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
31059
31325
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
31060
|
-
var httpServer = serve({ fetch:
|
|
31326
|
+
var httpServer = serve({ fetch: app69.fetch, port, hostname });
|
|
31061
31327
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
31062
31328
|
{
|
|
31063
31329
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
|
|
31064
|
-
const reconcileScript =
|
|
31330
|
+
const reconcileScript = resolve44(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
31065
31331
|
const runReconcile = (ctx) => {
|
|
31066
|
-
if (!
|
|
31332
|
+
if (!existsSync46(reconcileScript)) return;
|
|
31067
31333
|
try {
|
|
31068
31334
|
const child = spawn3(process.execPath, [reconcileScript], {
|
|
31069
31335
|
env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
|
|
@@ -31102,14 +31368,14 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
31102
31368
|
{
|
|
31103
31369
|
const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
|
|
31104
31370
|
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
|
|
31105
|
-
const dreamSweepScript =
|
|
31371
|
+
const dreamSweepScript = resolve44(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
|
|
31106
31372
|
registerLoop({
|
|
31107
31373
|
name: "dream-cycle-sweep",
|
|
31108
31374
|
intervalMs: DREAM_CYCLE_SWEEP_INTERVAL_MS,
|
|
31109
31375
|
firstRunDelayMs: 3e4,
|
|
31110
31376
|
detached: true,
|
|
31111
31377
|
run: (ctx) => {
|
|
31112
|
-
if (!
|
|
31378
|
+
if (!existsSync46(dreamSweepScript)) return;
|
|
31113
31379
|
try {
|
|
31114
31380
|
const child = spawn3(process.execPath, [dreamSweepScript], {
|
|
31115
31381
|
env: { ...process.env, PLATFORM_ROOT: dreamPlatformRoot },
|
|
@@ -31126,10 +31392,10 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
31126
31392
|
}
|
|
31127
31393
|
{
|
|
31128
31394
|
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
|
|
31129
|
-
const outlookScript =
|
|
31395
|
+
const outlookScript = resolve44(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
31130
31396
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
31131
31397
|
const runOutlookComplete = (ctx) => {
|
|
31132
|
-
if (!
|
|
31398
|
+
if (!existsSync46(outlookScript)) return;
|
|
31133
31399
|
try {
|
|
31134
31400
|
const child = spawn3(process.execPath, [outlookScript], {
|
|
31135
31401
|
env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
|
|
@@ -31152,18 +31418,18 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
31152
31418
|
}
|
|
31153
31419
|
{
|
|
31154
31420
|
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
|
|
31155
|
-
const strandedAccountsDir =
|
|
31421
|
+
const strandedAccountsDir = resolve44(auditRoot, "..", "data/accounts");
|
|
31156
31422
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
31157
31423
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
31158
31424
|
const STRANDED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
31159
31425
|
const runStrandedAudit = () => {
|
|
31160
31426
|
try {
|
|
31161
|
-
if (!
|
|
31427
|
+
if (!existsSync46(strandedAccountsDir)) return;
|
|
31162
31428
|
const now = Date.now();
|
|
31163
|
-
for (const name of
|
|
31429
|
+
for (const name of readdirSync28(strandedAccountsDir)) {
|
|
31164
31430
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
31165
|
-
const pendingPath2 =
|
|
31166
|
-
if (!
|
|
31431
|
+
const pendingPath2 = resolve44(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
31432
|
+
if (!existsSync46(pendingPath2)) continue;
|
|
31167
31433
|
const ageMs2 = now - statSync20(pendingPath2).mtimeMs;
|
|
31168
31434
|
if (ageMs2 > STRANDED_AGE_MS) {
|
|
31169
31435
|
console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs2 / 1e3)}`);
|
|
@@ -31182,7 +31448,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
31182
31448
|
}
|
|
31183
31449
|
{
|
|
31184
31450
|
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
|
|
31185
|
-
const googleAccountsDir =
|
|
31451
|
+
const googleAccountsDir = resolve44(googleRoot, "..", "data/accounts");
|
|
31186
31452
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
31187
31453
|
const runGooglePendingAuditSafe = () => {
|
|
31188
31454
|
try {
|
|
@@ -31197,10 +31463,10 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
31197
31463
|
firstRunDelayMs: 27e3,
|
|
31198
31464
|
run: runGooglePendingAuditSafe
|
|
31199
31465
|
});
|
|
31200
|
-
const googleAuditScript =
|
|
31466
|
+
const googleAuditScript = resolve44(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
|
|
31201
31467
|
const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
|
|
31202
31468
|
const runGoogleAccountAudit = (ctx) => {
|
|
31203
|
-
if (!
|
|
31469
|
+
if (!existsSync46(googleAuditScript)) return;
|
|
31204
31470
|
try {
|
|
31205
31471
|
const child = spawn3(process.execPath, [googleAuditScript], {
|
|
31206
31472
|
env: { ...process.env, PLATFORM_ROOT: googleRoot },
|
|
@@ -31272,7 +31538,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
31272
31538
|
}
|
|
31273
31539
|
{
|
|
31274
31540
|
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
|
|
31275
|
-
const publishScript =
|
|
31541
|
+
const publishScript = resolve44(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
31276
31542
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
31277
31543
|
const bookingAccounts = () => {
|
|
31278
31544
|
try {
|
|
@@ -31283,7 +31549,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
31283
31549
|
}
|
|
31284
31550
|
};
|
|
31285
31551
|
const spawnPublish = (account, ctx) => {
|
|
31286
|
-
if (!
|
|
31552
|
+
if (!existsSync46(publishScript)) return;
|
|
31287
31553
|
try {
|
|
31288
31554
|
const child = spawn3(process.execPath, [publishScript], {
|
|
31289
31555
|
env: {
|
|
@@ -31302,21 +31568,21 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
31302
31568
|
}
|
|
31303
31569
|
};
|
|
31304
31570
|
const auditSnapshotAge = (account) => {
|
|
31305
|
-
const availPath =
|
|
31571
|
+
const availPath = resolve44(account.accountDir, "calendar-availability.json");
|
|
31306
31572
|
let hasBookingSite = false;
|
|
31307
31573
|
try {
|
|
31308
|
-
if (
|
|
31309
|
-
const cfg = JSON.parse(
|
|
31574
|
+
if (existsSync46(availPath)) {
|
|
31575
|
+
const cfg = JSON.parse(readFileSync47(availPath, "utf-8"));
|
|
31310
31576
|
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
31311
31577
|
}
|
|
31312
31578
|
} catch {
|
|
31313
31579
|
}
|
|
31314
31580
|
if (!hasBookingSite) return;
|
|
31315
|
-
const statePath =
|
|
31581
|
+
const statePath = resolve44(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
31316
31582
|
let lastSuccessAt = null;
|
|
31317
|
-
if (
|
|
31583
|
+
if (existsSync46(statePath)) {
|
|
31318
31584
|
try {
|
|
31319
|
-
const rec = JSON.parse(
|
|
31585
|
+
const rec = JSON.parse(readFileSync47(statePath, "utf-8"));
|
|
31320
31586
|
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
31321
31587
|
} catch {
|
|
31322
31588
|
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
|
|
@@ -31349,11 +31615,11 @@ startTimeEntryCensus(() => getSession());
|
|
|
31349
31615
|
startLedgerCensus(() => getSession());
|
|
31350
31616
|
{
|
|
31351
31617
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
|
|
31352
|
-
const auditScript =
|
|
31618
|
+
const auditScript = resolve44(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
31353
31619
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
31354
31620
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
31355
31621
|
const runConnectorAudit = (ctx) => {
|
|
31356
|
-
if (!
|
|
31622
|
+
if (!existsSync46(auditScript)) return;
|
|
31357
31623
|
try {
|
|
31358
31624
|
const child = spawn3(process.execPath, [auditScript], {
|
|
31359
31625
|
env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
|
|
@@ -31433,7 +31699,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
31433
31699
|
}
|
|
31434
31700
|
try {
|
|
31435
31701
|
const registered = [];
|
|
31436
|
-
for (const r of
|
|
31702
|
+
for (const r of app69.routes ?? []) {
|
|
31437
31703
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
31438
31704
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
31439
31705
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -31473,11 +31739,11 @@ try {
|
|
|
31473
31739
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
31474
31740
|
async function runAdminUserReconcileTick() {
|
|
31475
31741
|
try {
|
|
31476
|
-
if (!
|
|
31742
|
+
if (!existsSync46(USERS_FILE)) {
|
|
31477
31743
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
31478
31744
|
return;
|
|
31479
31745
|
}
|
|
31480
|
-
const usersRaw =
|
|
31746
|
+
const usersRaw = readFileSync47(USERS_FILE, "utf-8").trim();
|
|
31481
31747
|
if (!usersRaw) {
|
|
31482
31748
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
31483
31749
|
return;
|
|
@@ -31524,8 +31790,8 @@ registerLoop({
|
|
|
31524
31790
|
});
|
|
31525
31791
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
31526
31792
|
function countUsersRows() {
|
|
31527
|
-
if (!
|
|
31528
|
-
const raw =
|
|
31793
|
+
if (!existsSync46(USERS_FILE)) return 0;
|
|
31794
|
+
const raw = readFileSync47(USERS_FILE, "utf-8").trim();
|
|
31529
31795
|
if (!raw) return 0;
|
|
31530
31796
|
const users = JSON.parse(raw);
|
|
31531
31797
|
return users.filter((u) => typeof u.userId === "string").length;
|
|
@@ -31658,7 +31924,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
31658
31924
|
}
|
|
31659
31925
|
init({
|
|
31660
31926
|
configDir: configDirForWhatsApp,
|
|
31661
|
-
platformRoot:
|
|
31927
|
+
platformRoot: resolve44(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..")),
|
|
31662
31928
|
accountConfig: bootAccountConfig,
|
|
31663
31929
|
onMessage: async (msg) => {
|
|
31664
31930
|
if (isObserveAccount(msg.accountId)) {
|