@rubytech/create-maxy-code 0.1.419 → 0.1.427
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/neo4j/schema.cypher +13 -0
- package/payload/platform/package-lock.json +5158 -2922
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +5 -1
- package/payload/platform/plugins/admin/hooks/__tests__/datetime-inject.test.sh +119 -0
- package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-compliance.test.sh +22 -0
- package/payload/platform/plugins/admin/hooks/datetime-inject.sh +115 -0
- package/payload/platform/plugins/admin/hooks/prompt-optimiser-compliance.sh +14 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +62 -4
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +44 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +96 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
- package/payload/platform/plugins/admin/skills/datetime/SKILL.md +9 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +16 -2
- package/payload/platform/plugins/docs/references/cross-account-authority.md +8 -0
- package/payload/platform/plugins/docs/references/internals.md +4 -0
- package/payload/platform/plugins/docs/references/memory-guide.md +2 -0
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/email/PLUGIN.md +2 -2
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +73 -4
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/mailbox-resolve.test.js +42 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/mailbox-resolve.test.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/index.js +1 -0
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts +4 -0
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.js +5 -0
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +25 -3
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js +67 -12
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
- package/payload/platform/plugins/email/references/email-reference.md +8 -0
- package/payload/platform/plugins/memory/PLUGIN.md +3 -0
- package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +30 -1
- package/payload/platform/plugins/memory/skills/preference-audit/SKILL.md +50 -0
- package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +5 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js +50 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js +22 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts +35 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js +36 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts +11 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js +19 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +85 -3
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js +32 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +14 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +94 -4
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +23 -7
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js +30 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts +29 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +47 -2
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +5 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.d.ts +2 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.js +20 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.js.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/resolve-read-account.test.d.ts +2 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/resolve-read-account.test.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/resolve-read-account.test.js +15 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/resolve-read-account.test.js.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js +5 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.d.ts +9 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.js +18 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.js.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +17 -14
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/resolve-read-account.d.ts +7 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/resolve-read-account.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/resolve-read-account.js +13 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/resolve-read-account.js.map +1 -0
- package/payload/platform/plugins/work/PLUGIN.md +1 -1
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js +72 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.js +67 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-raised-by-env.test.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-raised-by-env.test.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-raised-by-env.test.js +66 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-raised-by-env.test.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/index.js +3 -0
- package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts +6 -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 +41 -1
- package/payload/platform/plugins/work/mcp/dist/tools/work-create.js.map +1 -1
- package/payload/platform/scripts/lib/provision-account-dir.sh +2 -1
- package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts +39 -0
- package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/account-admin-census.js +122 -0
- package/payload/platform/services/claude-session-manager/dist/account-admin-census.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/account-timezone.d.ts +40 -0
- package/payload/platform/services/claude-session-manager/dist/account-timezone.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/account-timezone.js +126 -0
- package/payload/platform/services/claude-session-manager/dist/account-timezone.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +53 -2
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +52 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/passive-dispatch-prune.d.ts +37 -0
- package/payload/platform/services/claude-session-manager/dist/passive-dispatch-prune.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/passive-dispatch-prune.js +80 -0
- package/payload/platform/services/claude-session-manager/dist/passive-dispatch-prune.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/passive-intake-audit.d.ts +70 -0
- package/payload/platform/services/claude-session-manager/dist/passive-intake-audit.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/passive-intake-audit.js +129 -0
- package/payload/platform/services/claude-session-manager/dist/passive-intake-audit.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +17 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +40 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.js +37 -50
- package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +22 -0
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +22 -1
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js +44 -78
- package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +22 -0
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +22 -1
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +42 -38
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +66 -82
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/templates/account.json +2 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +3 -2
- package/payload/platform/templates/specialists/agents/content-producer.md +4 -0
- package/payload/server/public/assets/{AdminLoginScreens-B1PkOF66.js → AdminLoginScreens-yAIhWcGc.js} +1 -1
- package/payload/server/public/assets/AdminShell-Bk1AFQ4D.js +2 -0
- package/payload/server/public/assets/{Checkbox-Bm9Er726.js → Checkbox-B_lfjsqd.js} +1 -1
- package/payload/server/public/assets/Transcript-D67OZnVM.js +2 -0
- package/payload/server/public/assets/admin-DuOhkvrZ.js +1 -0
- package/payload/server/public/assets/{arc-DyzjCWmw.js → arc-dVLpR-ec.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-CgeA3HPD.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-qWfElD16.js → architectureDiagram-Q4EWVU46-C6u_CVzb.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DO2fFHC3.js → blockDiagram-DXYQGD6D-Cy8F5b8O.js} +1 -1
- package/payload/server/public/assets/browser-CCWufeXr.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Ca-q5gDe.js → c4Diagram-AHTNJAMY-DRXrlepj.js} +1 -1
- package/payload/server/public/assets/calendar-CNk1iPrA.js +1 -0
- package/payload/server/public/assets/channel-B04VBWf7.js +1 -0
- package/payload/server/public/assets/chat-7qB-dwBq.js +1 -0
- package/payload/server/public/assets/chevron-left-CpcDbHIz.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-CX2PxuDw.js → chunk-2KRD3SAO-fEyfhRLz.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-D8l6U4Ne.js → chunk-336JU56O-NUWO4y7q.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-DZkHcXRA.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-CG32Lkbh.js → chunk-4BX2VUAB-BnfiNR3l.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BnAQbO-v.js → chunk-4TB4RGXK-Bj_aJOz8.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-ejqRH2M5.js → chunk-55IACEB6-aK0DNSKb.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-ClkicQ-T.js → chunk-5FUZZQ4R-DeqAkq5C.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-Be-mE_rx.js → chunk-5PVQY5BW-SShlujAQ.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-DPsemed2.js → chunk-67CJDMHE-CZpzQ0DL.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BQRQJETl.js → chunk-7N4EOEYR-COnjO6jy.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-B1wcAVCK.js → chunk-AA7GKIK3-C9V31L2z.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-DIua053h.js → chunk-BSJP7CBP-DSwnSGe3.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-C9GHSCS9.js → chunk-CIAEETIT-CnRUTuta.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-C1T3l1xj.js → chunk-EDXVE4YY-BexiL2LH.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-8kPcXEQC.js → chunk-ENJZ2VHE-aTklWdJQ.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-Bhoeq9sD.js → chunk-FMBD7UC4-svcEBQzs.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-BIBpJi8I.js → chunk-FOC6F5B3-CG7R7Xri.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DELXp6fj.js → chunk-ICPOFSXX-CGN7Z4x9.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-DdckXldP.js → chunk-K5T4RW27-CWBh78jw.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-BJhXejKT.js → chunk-KGLVRYIC-Ctiq4q-5.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-BSd8nyM2.js → chunk-LIHQZDEY-BII77Q7K.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-CBi55uxq.js → chunk-ORNJ4GCN-DT7R01H8.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-Dfbzl8xh.js → chunk-OYMX7WX6-y-Jkbd4C.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-D9Mwgzti.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-BN1w8_Cq.js → chunk-U2HBQHQK-DzFo6KbQ.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-CrRay1NJ.js → chunk-X2U36JSP-CYSwgtLV.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-C_ZE776O.js → chunk-XPW4576I-DHlM4tOn.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-CUSlqWBY.js → chunk-YZCP3GAM-B20rTmLl.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BdPUfSiD.js → chunk-ZZ45TVLE-C7hP4J8m.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CIo_TzfF.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-SzQYvAUZ.js +1 -0
- package/payload/server/public/assets/clone-BVjcjsBA.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-D4E9htTz.js → cose-bilkent-S5V4N54A-nKjTv9sR.js} +1 -1
- package/payload/server/public/assets/{dagre-D1B5TQL1.js → dagre-Cx8LiiUZ.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-ByuvYV7N.js → dagre-KV5264BT-BNJYTnls.js} +1 -1
- package/payload/server/public/assets/data-BnHcS27X.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-B-0KduTa.js → diagram-5BDNPKRD-CoAN5_f9.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-CSQmo3eB.js → diagram-G4DWMVQ6-pRmsN4_x.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DK0kWiB3.js → diagram-MMDJMWI5-CRoylyp4.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CYbK2reZ.js → diagram-TYMM5635-BT3ZtG5b.js} +1 -1
- package/payload/server/public/assets/{dist-CADCHk0t.js → dist-CRpLAnCP.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-C-JQHvJF.js → erDiagram-SMLLAGMA-DSKws1ZV.js} +1 -1
- package/payload/server/public/assets/file-download-Hf_UILaA.js +1 -0
- package/payload/server/public/assets/{flatten-ROVzlo1u.js → flatten-jn8bZgcI.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-OTOd2czg.js → flowDiagram-DWJPFMVM-C2L38ZE5.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BWJ778ou.js → ganttDiagram-T4ZO3ILL-Bm2h-vjm.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DzQ18i0T.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CkNcyISe.js → gitGraphDiagram-UUTBAWPF-BoowbF7u.js} +1 -1
- package/payload/server/public/assets/graph-klLugHEK.js +51 -0
- package/payload/server/public/assets/{graph-labels-BFG4bjXQ.js → graph-labels-BLx-0vyT.js} +1 -1
- package/payload/server/public/assets/{graphlib-8z59Ng6C.js → graphlib-BvT2s_o1.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-CwsoaVzV.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-ieNsH2bV.js +2 -0
- package/payload/server/public/assets/{isEmpty-DXf_sApt.js → isEmpty-Dkk6_L-B.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-Cg7pRRGp.js → ishikawaDiagram-UXIWVN3A-nxcmj-IX.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CZT_4r_Z.js → journeyDiagram-VCZTEJTY-q5SNIvmS.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Dp1Vd5YM.js → kanban-definition-6JOO6SKY-BugG9Q1o.js} +1 -1
- package/payload/server/public/assets/{line-UPAcwY66.js → line-MZCQLR-q.js} +1 -1
- package/payload/server/public/assets/{linear-BeeahLKw.js → linear-DmQGNk-g.js} +1 -1
- package/payload/server/public/assets/{maximize-2-DkZ40lSl.js → maximize-2-CnNQnj_v.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CLKle8df.js → mermaid-parser.core-DvoeqLxw.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-CwRj5rL5.js → mermaid.core-BLaw7iG4.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CNQUY9UJ.js → mindmap-definition-QFDTVHPH-DMkt10Vc.js} +1 -1
- package/payload/server/public/assets/operator-CRcySYv9.js +1 -0
- package/payload/server/public/assets/{ordinal-B2r5L1v4.js → ordinal-DuJYM7p1.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-DxB-bO4L.js +1 -0
- package/payload/server/public/assets/page-CVo3CWIY.js +1 -0
- package/payload/server/public/assets/page-DPTbZRwl.js +32 -0
- package/payload/server/public/assets/{pdf-render-m08Xm2Nm.js → pdf-render-riHufgrn.js} +1 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-PSdKvB8-.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-Scnq58FX.js → pieDiagram-DEJITSTG-DRp4lD2B.js} +1 -1
- package/payload/server/public/assets/play-yEkd7ouW.js +1 -0
- package/payload/server/public/assets/public-Fi6ccYaE.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-wPfZo_vs.js → quadrantDiagram-34T5L4WZ-DkT63Dn4.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-D8FqRiWq.js +1 -0
- package/payload/server/public/assets/{reduce-CFlDlJf5.js → reduce-COyotL2V.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-yYkH12K2.js → requirementDiagram-MS252O5E-65GGtDkc.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-xHksz9mr.js +1 -0
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-fVWRBzzV.js → sankeyDiagram-XADWPNL6-D1vRwLWd.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-Dbap3X6h.js → sequenceDiagram-FGHM5R23-Bp47ZSN2.js} +1 -1
- package/payload/server/public/assets/square-BZqaxg7D.js +1 -0
- package/payload/server/public/assets/{src-Bi0fLV9t.js → src-xN1oULc8.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DkPLAqIh.js → stateDiagram-FHFEXIEX-BZHHcP_e.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-qVtoGx56.js +1 -0
- package/payload/server/public/assets/tasks-COWmfts8.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DabKBJyd.js → timeline-definition-GMOUNBTQ-DZ1wUyj-.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-i-w4rJmQ.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-Dij6AlAj.js +1 -0
- package/payload/server/public/assets/useSubAccountSwitcher-DADvGnr1.js +9 -0
- package/payload/server/public/assets/useSubAccountSwitcher-ayajZz8T.css +1 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CaKT7c-c.js → vennDiagram-DHZGUBPP-CttBahsn.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-BJhOQVqW.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BZ5TTSOL.js → wardleyDiagram-NUSXRM2D-Y5tWieZg.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CLfeklJ9.js → xychartDiagram-5P7HB3ND-C78A9qbe.js} +1 -1
- package/payload/server/public/browser.html +7 -5
- package/payload/server/public/calendar.html +8 -6
- package/payload/server/public/chat.html +15 -12
- package/payload/server/public/data.html +11 -10
- package/payload/server/public/graph.html +12 -10
- package/payload/server/public/index.html +16 -14
- package/payload/server/public/operator.html +17 -14
- package/payload/server/public/public.html +15 -12
- package/payload/server/public/tasks.html +18 -0
- package/payload/server/server.js +775 -287
- package/payload/server/public/assets/AdminShell-D8wNArGQ.js +0 -2
- package/payload/server/public/assets/Transcript-CBIyQ8T5.js +0 -2
- package/payload/server/public/assets/admin-CWM9G_yA.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-XiVs-N7Z.js +0 -1
- package/payload/server/public/assets/browser-D8QhNffV.js +0 -1
- package/payload/server/public/assets/calendar-qob5K4t_.js +0 -1
- package/payload/server/public/assets/channel-CYBkRz7E.js +0 -1
- package/payload/server/public/assets/chat-BNrxVUF6.js +0 -1
- package/payload/server/public/assets/chevron-left-BQThFVrd.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-CPhOHriU.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CDnAAZVJ.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BdXUKVrS.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DAq-uJr_.js +0 -1
- package/payload/server/public/assets/clone-DQl28-jK.js +0 -1
- package/payload/server/public/assets/data-C-EqNbRi.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-BM-KaDZy.js +0 -1
- package/payload/server/public/assets/graph-DZ2HMpIB.js +0 -51
- package/payload/server/public/assets/info-OMHHGYJF-CtZajyAB.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-C-_WYlmI.js +0 -2
- package/payload/server/public/assets/operator-FrXrSsBj.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-T-SYedp7.js +0 -1
- package/payload/server/public/assets/page-CHWMI9Tm.js +0 -32
- package/payload/server/public/assets/page-CXKV01gT.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BWECFVVd.js +0 -1
- package/payload/server/public/assets/public-2p1pJ4WF.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-Dx0YUklX.js +0 -1
- package/payload/server/public/assets/rotate-ccw-D3o_bMBA.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DceWO1u6.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-C3197Rac.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-BPrpx29h.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-8dLvF3Ux.js +0 -9
- package/payload/server/public/assets/useSubAccountSwitcher-BUvlETHN.css +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-DW4Jlbhw.js +0 -1
- /package/payload/server/public/assets/{_baseFor-BVuIxZJh.js → _baseFor-Bjj9It3Q.js} +0 -0
- /package/payload/server/public/assets/{admin-types-hioowVct.js → admin-types-ClHBm0ni.js} +0 -0
- /package/payload/server/public/assets/{array-B9UHiPd-.js → array-BrrxEo12.js} +0 -0
- /package/payload/server/public/assets/{chunk-CAM3fms7.js → chunk-Ck5AOu5v.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-D5_TRwB-.js → cytoscape.esm-CTWJxUxo.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-5eAKkKJC.js → defaultLocale-CFDbRV4k.js} +0 -0
- /package/payload/server/public/assets/{init-DlZdxViB.js → init-dXCzGgLP.js} +0 -0
- /package/payload/server/public/assets/{katex-Xo0SyWvP.js → katex-CHA1JFYJ.js} +0 -0
- /package/payload/server/public/assets/{path-6uRLdFF7.js → path-CCRpdXhK.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-CvXuAEud.js → preload-helper-CH6UZRzu.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-Djo4Abte.js → rough.esm-Bud4g4fh.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -3006,6 +3006,22 @@ async function resolvePersonByPhone(accountId, phone) {
|
|
|
3006
3006
|
await session.close();
|
|
3007
3007
|
}
|
|
3008
3008
|
}
|
|
3009
|
+
async function ensureManagerPerson(accountId, phone) {
|
|
3010
|
+
const session = getSession2();
|
|
3011
|
+
const normalized = normalizeE164(phone) || phone;
|
|
3012
|
+
try {
|
|
3013
|
+
const result = await session.run(
|
|
3014
|
+
`MERGE (p:Person {accountId: $accountId, phone: $phone})
|
|
3015
|
+
ON CREATE SET p.source = 'wa-passive-manager'
|
|
3016
|
+
RETURN elementId(p) AS personId`,
|
|
3017
|
+
{ accountId, phone: normalized }
|
|
3018
|
+
);
|
|
3019
|
+
if (result.records.length === 0) return null;
|
|
3020
|
+
return result.records[0].get("personId");
|
|
3021
|
+
} finally {
|
|
3022
|
+
await session.close();
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3009
3025
|
async function enrolPerson(input) {
|
|
3010
3026
|
const session = getSession2();
|
|
3011
3027
|
const sliceToken = randomUUID2();
|
|
@@ -5894,8 +5910,8 @@ function webchatTurnTimeoutMs() {
|
|
|
5894
5910
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
5895
5911
|
}
|
|
5896
5912
|
function createChatRoutes(deps) {
|
|
5897
|
-
const
|
|
5898
|
-
|
|
5913
|
+
const app61 = new Hono();
|
|
5914
|
+
app61.post("/", async (c) => {
|
|
5899
5915
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
5900
5916
|
const contentType = c.req.header("content-type") ?? "";
|
|
5901
5917
|
const account = resolveAccount();
|
|
@@ -6158,7 +6174,7 @@ ${result.result.text}` : result.result.text;
|
|
|
6158
6174
|
}
|
|
6159
6175
|
});
|
|
6160
6176
|
});
|
|
6161
|
-
return
|
|
6177
|
+
return app61;
|
|
6162
6178
|
}
|
|
6163
6179
|
|
|
6164
6180
|
// app/lib/channel-pty-bridge/admin-session-id.ts
|
|
@@ -6173,14 +6189,28 @@ function adminSessionIdFor(accountId, senderId, personId) {
|
|
|
6173
6189
|
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
|
|
6174
6190
|
}
|
|
6175
6191
|
|
|
6192
|
+
// app/lib/channel-pty-bridge/schedule-provenance.ts
|
|
6193
|
+
function parseScheduleProvenance(v) {
|
|
6194
|
+
if (!v || typeof v !== "object") return void 0;
|
|
6195
|
+
const o = v;
|
|
6196
|
+
if (typeof o.accountId !== "string" || typeof o.eventId !== "string" || typeof o.dispatchedAt !== "string") {
|
|
6197
|
+
return void 0;
|
|
6198
|
+
}
|
|
6199
|
+
if (!Array.isArray(o.authoredBy)) return void 0;
|
|
6200
|
+
const authoredBy = o.authoredBy.filter((u) => typeof u === "string" && u.length > 0);
|
|
6201
|
+
const createdByTool = typeof o.createdByTool === "string" && o.createdByTool.length > 0 ? o.createdByTool : null;
|
|
6202
|
+
return { accountId: o.accountId, eventId: o.eventId, authoredBy, createdByTool, dispatchedAt: o.dispatchedAt };
|
|
6203
|
+
}
|
|
6204
|
+
|
|
6176
6205
|
// server/routes/channel/schedule-inject.ts
|
|
6177
6206
|
var TAG16 = "[schedule-inject]";
|
|
6207
|
+
var UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
6178
6208
|
function isLoopbackAddr(addr) {
|
|
6179
6209
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
6180
6210
|
}
|
|
6181
6211
|
function createScheduleInjectRoutes(deps) {
|
|
6182
|
-
const
|
|
6183
|
-
|
|
6212
|
+
const app61 = new Hono();
|
|
6213
|
+
app61.post("/", async (c) => {
|
|
6184
6214
|
const env = c.env;
|
|
6185
6215
|
const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
|
|
6186
6216
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
@@ -6206,6 +6236,8 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6206
6236
|
const destination = typeof body.destination === "string" ? body.destination : "";
|
|
6207
6237
|
const prompt = typeof body.prompt === "string" ? body.prompt : "";
|
|
6208
6238
|
const eventId = typeof body.eventId === "string" ? body.eventId : "";
|
|
6239
|
+
const scheduleProvenance = parseScheduleProvenance(body.scheduleProvenance);
|
|
6240
|
+
const overrideSessionId = typeof body.sessionId === "string" && UUID_V4.test(body.sessionId) ? body.sessionId : void 0;
|
|
6209
6241
|
if (channel !== "whatsapp" && channel !== "telegram" || !destination || !prompt) {
|
|
6210
6242
|
console.error(`${TAG16} reject reason=bad-request channel=${String(channel)} hasDestination=${Boolean(destination)} hasPrompt=${Boolean(prompt)}`);
|
|
6211
6243
|
return c.json({ ok: false, error: "schedule-inject-bad-request" }, 400);
|
|
@@ -6224,7 +6256,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6224
6256
|
return c.json({ ok: false, error: "account-manager-unresolved" }, 403);
|
|
6225
6257
|
}
|
|
6226
6258
|
console.error(`${TAG16} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount2}`);
|
|
6227
|
-
const sessionId2 = adminSessionIdFor(effectiveAccount2, destination);
|
|
6259
|
+
const sessionId2 = overrideSessionId ?? adminSessionIdFor(effectiveAccount2, destination);
|
|
6228
6260
|
const reply2 = (text) => deps.sendWhatsAppText(houseAccountId, destination, text);
|
|
6229
6261
|
try {
|
|
6230
6262
|
await deps.waHandleInbound({
|
|
@@ -6241,6 +6273,8 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6241
6273
|
text: prompt,
|
|
6242
6274
|
media: [],
|
|
6243
6275
|
source: "schedule",
|
|
6276
|
+
scheduleProvenance,
|
|
6277
|
+
scheduledSessionId: overrideSessionId,
|
|
6244
6278
|
reply: reply2
|
|
6245
6279
|
});
|
|
6246
6280
|
} catch (err) {
|
|
@@ -6258,7 +6292,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6258
6292
|
return c.json({ ok: false, error: "no-admin-bot-token" }, 400);
|
|
6259
6293
|
}
|
|
6260
6294
|
const chatId = Number(destination);
|
|
6261
|
-
const sessionId = adminSessionIdFor(effectiveAccount, destination);
|
|
6295
|
+
const sessionId = overrideSessionId ?? adminSessionIdFor(effectiveAccount, destination);
|
|
6262
6296
|
const reply = (text) => deps.sendTelegramText(botToken, chatId, text);
|
|
6263
6297
|
try {
|
|
6264
6298
|
await deps.tgHandleInbound({
|
|
@@ -6269,6 +6303,8 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6269
6303
|
personId: null,
|
|
6270
6304
|
text: prompt,
|
|
6271
6305
|
source: "schedule",
|
|
6306
|
+
scheduleProvenance,
|
|
6307
|
+
scheduledSessionId: overrideSessionId,
|
|
6272
6308
|
reply
|
|
6273
6309
|
});
|
|
6274
6310
|
} catch (err) {
|
|
@@ -6278,7 +6314,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6278
6314
|
console.error(`${TAG16} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
|
|
6279
6315
|
return c.json({ ok: true }, 200);
|
|
6280
6316
|
});
|
|
6281
|
-
return
|
|
6317
|
+
return app61;
|
|
6282
6318
|
}
|
|
6283
6319
|
|
|
6284
6320
|
// server/index.ts
|
|
@@ -7288,9 +7324,124 @@ function reconcileCredsOnDisk(opts) {
|
|
|
7288
7324
|
return entries;
|
|
7289
7325
|
}
|
|
7290
7326
|
|
|
7327
|
+
// app/lib/whatsapp-reader/select-sessions.ts
|
|
7328
|
+
function isReaderChannelSession(role, channel) {
|
|
7329
|
+
return role === "admin" && (channel === "whatsapp" || channel === "telegram") || role === "public" && (channel === "whatsapp" || channel === "webchat");
|
|
7330
|
+
}
|
|
7331
|
+
function selectReaderChannelSessions(rows) {
|
|
7332
|
+
return rows.filter((r) => isReaderChannelSession(r.role, r.channel)).sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
|
|
7333
|
+
sessionId: r.sessionId,
|
|
7334
|
+
projectDir: r.projectDir,
|
|
7335
|
+
title: r.title,
|
|
7336
|
+
senderId: r.senderId,
|
|
7337
|
+
startedAt: r.startedAt,
|
|
7338
|
+
channel: r.channel,
|
|
7339
|
+
role: r.role,
|
|
7340
|
+
operatorName: null,
|
|
7341
|
+
whatsappName: null,
|
|
7342
|
+
lastMessageAt: r.lastMessageAt,
|
|
7343
|
+
modelGated: r.modelGated,
|
|
7344
|
+
model: r.model,
|
|
7345
|
+
source: "session"
|
|
7346
|
+
}));
|
|
7347
|
+
}
|
|
7348
|
+
function conversationCounterpartyPhone(remoteJid, earliestSenderTelephone) {
|
|
7349
|
+
if (remoteJid.endsWith("@g.us")) return null;
|
|
7350
|
+
if (remoteJid.endsWith("@s.whatsapp.net")) return jidToE164(remoteJid) ?? earliestSenderTelephone;
|
|
7351
|
+
return earliestSenderTelephone;
|
|
7352
|
+
}
|
|
7353
|
+
function counterpartyBoundToSubAccount(managerPhones, counterpartyPhone) {
|
|
7354
|
+
return counterpartyPhone != null && managerPhones.some((mp) => phonesMatch(mp, counterpartyPhone));
|
|
7355
|
+
}
|
|
7356
|
+
function buildStoreConversationRows(accountId, summaries) {
|
|
7357
|
+
const rows = [];
|
|
7358
|
+
for (const [remoteJid, { first, last, firstNamedSender }] of summaries) {
|
|
7359
|
+
const scope = last.scope;
|
|
7360
|
+
const senderTelephone = conversationCounterpartyPhone(remoteJid, first.senderTelephone);
|
|
7361
|
+
rows.push({
|
|
7362
|
+
sessionId: "",
|
|
7363
|
+
projectDir: "",
|
|
7364
|
+
title: remoteJid,
|
|
7365
|
+
senderId: senderTelephone,
|
|
7366
|
+
startedAt: first.dateSent,
|
|
7367
|
+
channel: "whatsapp",
|
|
7368
|
+
role: scope === "admin" ? "admin" : "public",
|
|
7369
|
+
operatorName: null,
|
|
7370
|
+
whatsappName: firstNamedSender,
|
|
7371
|
+
lastMessageAt: last.dateSent,
|
|
7372
|
+
modelGated: false,
|
|
7373
|
+
model: null,
|
|
7374
|
+
source: "store",
|
|
7375
|
+
accountId,
|
|
7376
|
+
remoteJid,
|
|
7377
|
+
scope
|
|
7378
|
+
});
|
|
7379
|
+
}
|
|
7380
|
+
return rows.sort((a, b) => (b.lastMessageAt ?? "").localeCompare(a.lastMessageAt ?? ""));
|
|
7381
|
+
}
|
|
7382
|
+
|
|
7383
|
+
// app/lib/whatsapp/sub-account-recall.ts
|
|
7384
|
+
function resolveStoreProjection(params) {
|
|
7385
|
+
const { requestedAccountId, houseId, validAccountIds, houseAccountManagers } = params;
|
|
7386
|
+
const requestedIsValid = validAccountIds.includes(requestedAccountId);
|
|
7387
|
+
const isSubAccount = houseId !== null && validAccountIds.length > 1 && requestedIsValid && requestedAccountId !== houseId;
|
|
7388
|
+
if (!isSubAccount) return { storeAccountId: requestedAccountId, managerPhones: null };
|
|
7389
|
+
return {
|
|
7390
|
+
storeAccountId: houseId,
|
|
7391
|
+
managerPhones: managerPhonesForAccount(houseAccountManagers, requestedAccountId)
|
|
7392
|
+
};
|
|
7393
|
+
}
|
|
7394
|
+
function filterConversationsForSubAccount(conversations, managerPhones) {
|
|
7395
|
+
const out = /* @__PURE__ */ new Map();
|
|
7396
|
+
for (const [remoteJid, msgs] of conversations) {
|
|
7397
|
+
const counterparty = conversationCounterpartyPhone(remoteJid, msgs[0]?.senderTelephone ?? "");
|
|
7398
|
+
if (counterpartyBoundToSubAccount(managerPhones, counterparty)) out.set(remoteJid, msgs);
|
|
7399
|
+
}
|
|
7400
|
+
return out;
|
|
7401
|
+
}
|
|
7402
|
+
|
|
7403
|
+
// app/lib/whatsapp/authorize-recall-read.ts
|
|
7404
|
+
function authorizeRecallRead(input) {
|
|
7405
|
+
const { requestedAccountId } = input;
|
|
7406
|
+
const callerAccountId = input.callerAccountId && input.callerAccountId.length > 0 ? input.callerAccountId : null;
|
|
7407
|
+
const houseAdminScope = input.houseAdminScope && input.houseAdminScope.length > 0 ? input.houseAdminScope : null;
|
|
7408
|
+
if (houseAdminScope) return { authorized: true };
|
|
7409
|
+
if (callerAccountId && requestedAccountId === callerAccountId) return { authorized: true };
|
|
7410
|
+
return {
|
|
7411
|
+
authorized: false,
|
|
7412
|
+
reason: `Not authorized to read WhatsApp history for account "${requestedAccountId}". This session may only read its own account.`
|
|
7413
|
+
};
|
|
7414
|
+
}
|
|
7415
|
+
|
|
7291
7416
|
// server/routes/whatsapp.ts
|
|
7292
7417
|
var TAG21 = "[whatsapp:api]";
|
|
7293
7418
|
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
7419
|
+
function projectionFor(requestedAccountId) {
|
|
7420
|
+
const validAccounts = listValidAccounts();
|
|
7421
|
+
if (validAccounts.length <= 1) return { storeAccountId: requestedAccountId, managerPhones: null };
|
|
7422
|
+
let houseId = null;
|
|
7423
|
+
try {
|
|
7424
|
+
houseId = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
|
|
7425
|
+
} catch {
|
|
7426
|
+
houseId = null;
|
|
7427
|
+
}
|
|
7428
|
+
const houseAccount = houseId ? validAccounts.find((a) => a.accountId === houseId) : void 0;
|
|
7429
|
+
const houseAccountManagers = houseAccount ? readAccountManagers(houseAccount.accountDir) : {};
|
|
7430
|
+
return resolveStoreProjection({
|
|
7431
|
+
requestedAccountId,
|
|
7432
|
+
houseId,
|
|
7433
|
+
validAccountIds: validAccounts.map((a) => a.accountId),
|
|
7434
|
+
houseAccountManagers
|
|
7435
|
+
});
|
|
7436
|
+
}
|
|
7437
|
+
function callerScopeDenial(c, requestedAccountId) {
|
|
7438
|
+
const callerAccountId = c.req.header("x-maxy-caller-account")?.trim() || null;
|
|
7439
|
+
const houseAdminScope = c.req.header("x-maxy-house-admin-scope")?.trim() || null;
|
|
7440
|
+
const decision = authorizeRecallRead({ requestedAccountId, callerAccountId, houseAdminScope });
|
|
7441
|
+
if (decision.authorized) return null;
|
|
7442
|
+
console.error(`[whatsapp-read-tool] op=authz-deny requested=${requestedAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
|
|
7443
|
+
return c.json({ error: decision.reason }, 403);
|
|
7444
|
+
}
|
|
7294
7445
|
var app2 = new Hono();
|
|
7295
7446
|
app2.get("/status", (c) => {
|
|
7296
7447
|
try {
|
|
@@ -7595,6 +7746,8 @@ app2.get("/activity", (c) => {
|
|
|
7595
7746
|
app2.get("/conversations", (c) => {
|
|
7596
7747
|
try {
|
|
7597
7748
|
const accountId = validateAccountId(c.req.query("accountId") ?? null);
|
|
7749
|
+
const denial = callerScopeDenial(c, accountId);
|
|
7750
|
+
if (denial) return denial;
|
|
7598
7751
|
const jids = listConversationJids(accountId);
|
|
7599
7752
|
const conversations = jids.map((jid) => {
|
|
7600
7753
|
const messages = getMessages(accountId, jid);
|
|
@@ -7617,6 +7770,8 @@ app2.get("/conversations", (c) => {
|
|
|
7617
7770
|
app2.get("/messages", (c) => {
|
|
7618
7771
|
try {
|
|
7619
7772
|
const accountId = validateAccountId(c.req.query("accountId") ?? null);
|
|
7773
|
+
const denial = callerScopeDenial(c, accountId);
|
|
7774
|
+
if (denial) return denial;
|
|
7620
7775
|
const jid = c.req.query("jid");
|
|
7621
7776
|
if (!jid) {
|
|
7622
7777
|
return c.json({ error: "Missing required parameter: jid" }, 400);
|
|
@@ -7638,9 +7793,14 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
7638
7793
|
const jid = c.req.query("jid");
|
|
7639
7794
|
const accountIdQuery = c.req.query("accountId");
|
|
7640
7795
|
const t0 = Date.now();
|
|
7796
|
+
const denial = callerScopeDenial(c, validateAccountId(accountIdQuery ?? null));
|
|
7797
|
+
if (denial) return denial;
|
|
7641
7798
|
if (!directCacheKey && !jid) {
|
|
7642
|
-
const
|
|
7643
|
-
const
|
|
7799
|
+
const requestedAccountId = validateAccountId(accountIdQuery ?? null);
|
|
7800
|
+
const projection2 = projectionFor(requestedAccountId);
|
|
7801
|
+
const managerPhonesBound = projection2.managerPhones?.length ?? 0;
|
|
7802
|
+
const allConversations = readAllConversations(projection2.storeAccountId);
|
|
7803
|
+
const conversations = projection2.managerPhones ? filterConversationsForSubAccount(allConversations, projection2.managerPhones) : allConversations;
|
|
7644
7804
|
const rows2 = [];
|
|
7645
7805
|
const nameCache = /* @__PURE__ */ new Map();
|
|
7646
7806
|
let unresolvedSenders = 0;
|
|
@@ -7652,7 +7812,7 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
7652
7812
|
if (!nameCache.has(m.senderTelephone)) {
|
|
7653
7813
|
const result = await session.run(
|
|
7654
7814
|
`MATCH (p:Person {telephone: $telephone, accountId: $accountId}) RETURN p.givenName AS givenName, p.familyName AS familyName`,
|
|
7655
|
-
{ telephone: m.senderTelephone, accountId:
|
|
7815
|
+
{ telephone: m.senderTelephone, accountId: projection2.storeAccountId }
|
|
7656
7816
|
);
|
|
7657
7817
|
const rec = result.records[0];
|
|
7658
7818
|
const resolved = rec ? [rec.get("givenName"), rec.get("familyName")].filter(Boolean).join(" ") || null : null;
|
|
@@ -7674,8 +7834,8 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
7674
7834
|
if (session) await session.close();
|
|
7675
7835
|
}
|
|
7676
7836
|
const ms2 = Date.now() - t0;
|
|
7677
|
-
console.error(`[
|
|
7678
|
-
return c.json({ accountId:
|
|
7837
|
+
console.error(`[whatsapp-read-tool] op=query scope=${requestedAccountId} storeAccount=${projection2.storeAccountId} managerPhonesBound=${managerPhonesBound} resultCount=${rows2.length} unresolvedSenders=${unresolvedSenders} ms=${ms2}`);
|
|
7838
|
+
return c.json({ accountId: requestedAccountId, rows: rows2, unresolvedSenders, ms: ms2, managerPhonesBound });
|
|
7679
7839
|
}
|
|
7680
7840
|
let remoteJid;
|
|
7681
7841
|
let accountId;
|
|
@@ -7690,7 +7850,13 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
7690
7850
|
accountId = validateAccountId(accountIdQuery ?? null);
|
|
7691
7851
|
remoteJid = jid;
|
|
7692
7852
|
cacheKey = isGroupJid(remoteJid) ? deriveCacheKey({ agentType: "public", accountId, senderPhone: "", isGroup: true, groupJid: remoteJid }) : deriveCacheKey({ agentType: "public", accountId, senderPhone: remoteJid.replace(/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i, "$1"), isGroup: false });
|
|
7693
|
-
const
|
|
7853
|
+
const projection = projectionFor(accountId);
|
|
7854
|
+
const storeMessages = readConversation(projection.storeAccountId, remoteJid);
|
|
7855
|
+
const counterpartyBound = projection.managerPhones == null || counterpartyBoundToSubAccount(
|
|
7856
|
+
projection.managerPhones,
|
|
7857
|
+
conversationCounterpartyPhone(remoteJid, storeMessages[0]?.senderTelephone ?? "")
|
|
7858
|
+
);
|
|
7859
|
+
const messages = counterpartyBound ? storeMessages : [];
|
|
7694
7860
|
const sessionId = messages[0]?.sessionId ?? null;
|
|
7695
7861
|
const rows = messages.map((m) => ({
|
|
7696
7862
|
messageId: m.messageId,
|
|
@@ -7700,12 +7866,12 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
7700
7866
|
body: m.body
|
|
7701
7867
|
}));
|
|
7702
7868
|
const ms = Date.now() - t0;
|
|
7703
|
-
console.error(`[
|
|
7869
|
+
console.error(`[whatsapp-read-tool] op=query mode=single scope=${accountId} storeAccount=${projection.storeAccountId} graphRows=${rows.length} sessionId=${sessionId ?? "null"} ms=${ms}`);
|
|
7704
7870
|
return c.json({
|
|
7705
7871
|
cacheKey,
|
|
7706
7872
|
sessionId,
|
|
7707
7873
|
graphRows: rows,
|
|
7708
|
-
cypher: `on-disk read: ~/.<brand>/data/whatsapp-messages/${
|
|
7874
|
+
cypher: `on-disk read: ~/.<brand>/data/whatsapp-messages/${projection.storeAccountId}/${remoteJid}.jsonl`,
|
|
7709
7875
|
ms
|
|
7710
7876
|
});
|
|
7711
7877
|
} catch (err) {
|
|
@@ -7755,57 +7921,6 @@ import { basename as basename5, dirname as dirname4, isAbsolute, join as join14,
|
|
|
7755
7921
|
// server/routes/admin/sidebar-sessions.ts
|
|
7756
7922
|
import { readdirSync as readdirSync5, readFileSync as readFileSync12, statSync as statSync3 } from "fs";
|
|
7757
7923
|
import { basename as basename4, dirname as dirname3, join as join11, resolve as resolve11 } from "path";
|
|
7758
|
-
|
|
7759
|
-
// app/lib/whatsapp-reader/select-sessions.ts
|
|
7760
|
-
function isReaderChannelSession(role, channel) {
|
|
7761
|
-
return role === "admin" && (channel === "whatsapp" || channel === "telegram") || role === "public" && (channel === "whatsapp" || channel === "webchat");
|
|
7762
|
-
}
|
|
7763
|
-
function selectReaderChannelSessions(rows) {
|
|
7764
|
-
return rows.filter((r) => isReaderChannelSession(r.role, r.channel)).sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
|
|
7765
|
-
sessionId: r.sessionId,
|
|
7766
|
-
projectDir: r.projectDir,
|
|
7767
|
-
title: r.title,
|
|
7768
|
-
senderId: r.senderId,
|
|
7769
|
-
startedAt: r.startedAt,
|
|
7770
|
-
channel: r.channel,
|
|
7771
|
-
role: r.role,
|
|
7772
|
-
operatorName: null,
|
|
7773
|
-
whatsappName: null,
|
|
7774
|
-
lastMessageAt: r.lastMessageAt,
|
|
7775
|
-
modelGated: r.modelGated,
|
|
7776
|
-
model: r.model,
|
|
7777
|
-
source: "session"
|
|
7778
|
-
}));
|
|
7779
|
-
}
|
|
7780
|
-
function buildStoreConversationRows(accountId, summaries) {
|
|
7781
|
-
const rows = [];
|
|
7782
|
-
for (const [remoteJid, { first, last, firstNamedSender }] of summaries) {
|
|
7783
|
-
const scope = last.scope;
|
|
7784
|
-
const isGroup = remoteJid.endsWith("@g.us");
|
|
7785
|
-
const senderTelephone = isGroup ? null : remoteJid.endsWith("@s.whatsapp.net") ? jidToE164(remoteJid) ?? first.senderTelephone : first.senderTelephone;
|
|
7786
|
-
rows.push({
|
|
7787
|
-
sessionId: "",
|
|
7788
|
-
projectDir: "",
|
|
7789
|
-
title: remoteJid,
|
|
7790
|
-
senderId: senderTelephone,
|
|
7791
|
-
startedAt: first.dateSent,
|
|
7792
|
-
channel: "whatsapp",
|
|
7793
|
-
role: scope === "admin" ? "admin" : "public",
|
|
7794
|
-
operatorName: null,
|
|
7795
|
-
whatsappName: firstNamedSender,
|
|
7796
|
-
lastMessageAt: last.dateSent,
|
|
7797
|
-
modelGated: false,
|
|
7798
|
-
model: null,
|
|
7799
|
-
source: "store",
|
|
7800
|
-
accountId,
|
|
7801
|
-
remoteJid,
|
|
7802
|
-
scope
|
|
7803
|
-
});
|
|
7804
|
-
}
|
|
7805
|
-
return rows.sort((a, b) => (b.lastMessageAt ?? "").localeCompare(a.lastMessageAt ?? ""));
|
|
7806
|
-
}
|
|
7807
|
-
|
|
7808
|
-
// server/routes/admin/sidebar-sessions.ts
|
|
7809
7924
|
var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
|
|
7810
7925
|
function lastAssistantModel(body) {
|
|
7811
7926
|
const lines = body.split("\n");
|
|
@@ -8279,7 +8394,7 @@ function unwrapChannel(text) {
|
|
|
8279
8394
|
}
|
|
8280
8395
|
return source ? { text: inner, source } : { text: inner };
|
|
8281
8396
|
}
|
|
8282
|
-
var COMPOSED_ADMIN_FRAME =
|
|
8397
|
+
var COMPOSED_ADMIN_FRAME = /^(?:## Standing rules\n[\s\S]*?\n\n)?## Context\n([\s\S]*)\n\n## Instruction\n[\s\S]*$/;
|
|
8283
8398
|
var UPLOAD_ANNOTATION = /(?:\n\n)?\[The operator uploaded \d+ file\(s\): [\s\S]*\]$/;
|
|
8284
8399
|
function rawFromComposedAdminFrame(text) {
|
|
8285
8400
|
const context = text.match(COMPOSED_ADMIN_FRAME)?.[1];
|
|
@@ -8646,7 +8761,7 @@ app4.get("/conversations", requireAdminSession, async (c) => {
|
|
|
8646
8761
|
managerPhonesBound = managerPhones.length;
|
|
8647
8762
|
if (managerPhones.length > 0) {
|
|
8648
8763
|
managedRows = buildStoreConversationRows(houseId, readConversationSummaries(houseId)).filter(
|
|
8649
|
-
(r) =>
|
|
8764
|
+
(r) => counterpartyBoundToSubAccount(managerPhones, r.senderId)
|
|
8650
8765
|
);
|
|
8651
8766
|
}
|
|
8652
8767
|
}
|
|
@@ -9874,8 +9989,8 @@ async function reapplyLeversViaManager() {
|
|
|
9874
9989
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
9875
9990
|
var sendSeq = 0;
|
|
9876
9991
|
function createWebchatRoutes(deps) {
|
|
9877
|
-
const
|
|
9878
|
-
|
|
9992
|
+
const app61 = new Hono();
|
|
9993
|
+
app61.post("/send", requireAdminSession, async (c) => {
|
|
9879
9994
|
let accountId;
|
|
9880
9995
|
try {
|
|
9881
9996
|
accountId = resolvePlatformAccountId();
|
|
@@ -10075,7 +10190,7 @@ ${note}` : note;
|
|
|
10075
10190
|
if (turnTimer.unref) turnTimer.unref();
|
|
10076
10191
|
return c.json({ ok: true });
|
|
10077
10192
|
});
|
|
10078
|
-
|
|
10193
|
+
app61.post("/interrupt", requireAdminSession, async (c) => {
|
|
10079
10194
|
const cacheKey = c.get("cacheKey");
|
|
10080
10195
|
const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
|
|
10081
10196
|
const primaryUserId = resolvePrimaryAdminUserId();
|
|
@@ -10103,7 +10218,7 @@ ${note}` : note;
|
|
|
10103
10218
|
}
|
|
10104
10219
|
return c.json({ ok: true, stopped: outcome.stopped, intId: outcome.intId, deadChild: outcome.deadChild }, 200);
|
|
10105
10220
|
});
|
|
10106
|
-
|
|
10221
|
+
app61.post("/settings", requireAdminSession, async (c) => {
|
|
10107
10222
|
const body = await c.req.json().catch(() => null);
|
|
10108
10223
|
const op = body?.op;
|
|
10109
10224
|
const value = body?.value;
|
|
@@ -10143,7 +10258,7 @@ ${note}` : note;
|
|
|
10143
10258
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
10144
10259
|
return c.json({ ok: true, settingsApplied });
|
|
10145
10260
|
});
|
|
10146
|
-
|
|
10261
|
+
app61.get("/session", requireAdminSession, async (c) => {
|
|
10147
10262
|
let accountId;
|
|
10148
10263
|
try {
|
|
10149
10264
|
accountId = resolvePlatformAccountId();
|
|
@@ -10221,7 +10336,7 @@ ${note}` : note;
|
|
|
10221
10336
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
10222
10337
|
return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
|
|
10223
10338
|
});
|
|
10224
|
-
|
|
10339
|
+
app61.post("/permission-verdict", requireAdminSession, async (c) => {
|
|
10225
10340
|
const body = await c.req.json().catch(() => null);
|
|
10226
10341
|
const sessionId = body?.sessionId;
|
|
10227
10342
|
const requestId = body?.request_id;
|
|
@@ -10238,7 +10353,7 @@ ${note}` : note;
|
|
|
10238
10353
|
const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
|
|
10239
10354
|
return c.json({ ok });
|
|
10240
10355
|
});
|
|
10241
|
-
return
|
|
10356
|
+
return app61;
|
|
10242
10357
|
}
|
|
10243
10358
|
|
|
10244
10359
|
// server/routes/webchat-greeting.ts
|
|
@@ -13275,18 +13390,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
13275
13390
|
]);
|
|
13276
13391
|
var app20 = new Hono();
|
|
13277
13392
|
app20.post("/", async (c) => {
|
|
13278
|
-
const
|
|
13393
|
+
const TAG44 = "[admin:events]";
|
|
13279
13394
|
let body;
|
|
13280
13395
|
try {
|
|
13281
13396
|
body = await c.req.json();
|
|
13282
13397
|
} catch (err) {
|
|
13283
13398
|
const detail = err instanceof Error ? err.message : String(err);
|
|
13284
|
-
console.error(`${
|
|
13399
|
+
console.error(`${TAG44} reject reason=body-not-json detail=${detail}`);
|
|
13285
13400
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
13286
13401
|
}
|
|
13287
13402
|
const event = typeof body.event === "string" ? body.event : "";
|
|
13288
13403
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
13289
|
-
console.error(`${
|
|
13404
|
+
console.error(`${TAG44} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
13290
13405
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
13291
13406
|
}
|
|
13292
13407
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -19221,52 +19336,307 @@ app45.get("/booking-link", requireAdminSession, (c) => {
|
|
|
19221
19336
|
});
|
|
19222
19337
|
var calendar_default = app45;
|
|
19223
19338
|
|
|
19224
|
-
//
|
|
19339
|
+
// app/lib/time-entry-format.ts
|
|
19340
|
+
function secondsBetween(startIso, endIso) {
|
|
19341
|
+
const s = Date.parse(startIso);
|
|
19342
|
+
const e = Date.parse(endIso);
|
|
19343
|
+
if (!Number.isFinite(s) || !Number.isFinite(e)) return 0;
|
|
19344
|
+
return Math.max(0, Math.round((e - s) / 1e3));
|
|
19345
|
+
}
|
|
19346
|
+
function toNum(v) {
|
|
19347
|
+
if (v == null) return 0;
|
|
19348
|
+
if (typeof v === "number") return v;
|
|
19349
|
+
if (typeof v === "object" && typeof v.toNumber === "function") {
|
|
19350
|
+
return v.toNumber();
|
|
19351
|
+
}
|
|
19352
|
+
const n = Number(v);
|
|
19353
|
+
return Number.isFinite(n) ? n : 0;
|
|
19354
|
+
}
|
|
19355
|
+
|
|
19356
|
+
// server/routes/admin/tasks-list.ts
|
|
19357
|
+
var TAG33 = "[task-timer]";
|
|
19358
|
+
var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
|
|
19359
|
+
var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
|
|
19225
19360
|
var app46 = new Hono();
|
|
19226
|
-
app46.
|
|
19227
|
-
|
|
19228
|
-
|
|
19229
|
-
|
|
19230
|
-
|
|
19231
|
-
|
|
19232
|
-
|
|
19233
|
-
|
|
19234
|
-
|
|
19235
|
-
|
|
19236
|
-
|
|
19237
|
-
|
|
19238
|
-
|
|
19239
|
-
|
|
19240
|
-
|
|
19241
|
-
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
|
|
19245
|
-
|
|
19246
|
-
|
|
19247
|
-
|
|
19248
|
-
|
|
19249
|
-
|
|
19250
|
-
|
|
19251
|
-
|
|
19252
|
-
|
|
19253
|
-
|
|
19254
|
-
|
|
19255
|
-
|
|
19256
|
-
|
|
19257
|
-
|
|
19258
|
-
|
|
19259
|
-
|
|
19260
|
-
|
|
19261
|
-
|
|
19262
|
-
|
|
19361
|
+
app46.get("/", requireAdminSession, async (c) => {
|
|
19362
|
+
const cacheKey = c.var.cacheKey;
|
|
19363
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
19364
|
+
if (!accountId) {
|
|
19365
|
+
console.error(`${TAG33} op=list auth-rejected reason="no account for session"`);
|
|
19366
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
19367
|
+
}
|
|
19368
|
+
const session = getSession();
|
|
19369
|
+
try {
|
|
19370
|
+
const result = await session.run(
|
|
19371
|
+
`MATCH (t:Task {accountId: $accountId})
|
|
19372
|
+
OPTIONAL MATCH (te:TimeEntry {taskId: t.taskId, accountId: $accountId})
|
|
19373
|
+
WHERE te.endedAt IS NULL
|
|
19374
|
+
WITH t, te ORDER BY te.startedAt
|
|
19375
|
+
WITH t, head(collect(te)) AS openTe
|
|
19376
|
+
RETURN t.taskId AS taskId, t.name AS name, t.clientName AS clientName,
|
|
19377
|
+
t.propertyAddress AS propertyAddress, t.fee AS fee, t.status AS status,
|
|
19378
|
+
coalesce(t.secondsLogged, 0) AS secondsLogged,
|
|
19379
|
+
openTe.startedAt AS runningStartedAt
|
|
19380
|
+
ORDER BY t.createdAt DESC`,
|
|
19381
|
+
{ accountId }
|
|
19382
|
+
);
|
|
19383
|
+
const open = [];
|
|
19384
|
+
const completed = [];
|
|
19385
|
+
for (const rec of result.records) {
|
|
19386
|
+
const status = rec.get("status") ?? "pending";
|
|
19387
|
+
const runningStartedAt = rec.get("runningStartedAt") ?? null;
|
|
19388
|
+
const fee = rec.get("fee");
|
|
19389
|
+
const row = {
|
|
19390
|
+
taskId: rec.get("taskId"),
|
|
19391
|
+
name: rec.get("name") ?? "",
|
|
19392
|
+
clientName: rec.get("clientName") ?? null,
|
|
19393
|
+
propertyAddress: rec.get("propertyAddress") ?? null,
|
|
19394
|
+
fee: fee == null ? null : toNum(fee),
|
|
19395
|
+
status,
|
|
19396
|
+
secondsLogged: toNum(rec.get("secondsLogged")),
|
|
19397
|
+
running: runningStartedAt !== null,
|
|
19398
|
+
runningStartedAt
|
|
19399
|
+
};
|
|
19400
|
+
if (COMPLETED.has(status)) completed.push(row);
|
|
19401
|
+
else if (!HIDDEN_FROM_OPEN.has(status)) open.push(row);
|
|
19402
|
+
}
|
|
19403
|
+
console.log(`${TAG33} op=list account=${accountId} open=${open.length} completed=${completed.length}`);
|
|
19404
|
+
return c.json({ open, completed });
|
|
19405
|
+
} catch (err) {
|
|
19406
|
+
console.error(`${TAG33} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
19407
|
+
return c.json({ error: "tasks-list-failed" }, 500);
|
|
19408
|
+
} finally {
|
|
19409
|
+
await session.close();
|
|
19410
|
+
}
|
|
19411
|
+
});
|
|
19412
|
+
var tasks_list_default = app46;
|
|
19413
|
+
|
|
19414
|
+
// server/routes/admin/task-timer-start.ts
|
|
19415
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
19416
|
+
import neo4j5 from "neo4j-driver";
|
|
19417
|
+
var TAG34 = "[task-timer]";
|
|
19418
|
+
var app47 = new Hono();
|
|
19419
|
+
app47.post("/", requireAdminSession, async (c) => {
|
|
19420
|
+
const cacheKey = c.var.cacheKey;
|
|
19421
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
19422
|
+
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
19423
|
+
let body;
|
|
19424
|
+
try {
|
|
19425
|
+
body = await c.req.json();
|
|
19426
|
+
} catch {
|
|
19427
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
19428
|
+
}
|
|
19429
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
19430
|
+
if (!taskId) return c.json({ error: "taskId required" }, 400);
|
|
19431
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19432
|
+
const session = getSession();
|
|
19433
|
+
try {
|
|
19434
|
+
const target = await session.run(
|
|
19435
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId}) RETURN t.taskId AS taskId LIMIT 1`,
|
|
19436
|
+
{ taskId, accountId }
|
|
19437
|
+
);
|
|
19438
|
+
if (target.records.length === 0) {
|
|
19439
|
+
console.error(`${TAG34} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
|
|
19440
|
+
return c.json({ error: "task-not-found" }, 404);
|
|
19441
|
+
}
|
|
19442
|
+
const open = await session.run(
|
|
19443
|
+
`MATCH (te:TimeEntry {accountId: $accountId}) WHERE te.endedAt IS NULL
|
|
19444
|
+
RETURN te.entryId AS entryId, te.taskId AS taskId, te.startedAt AS startedAt
|
|
19445
|
+
ORDER BY te.startedAt LIMIT 1`,
|
|
19446
|
+
{ accountId }
|
|
19447
|
+
);
|
|
19448
|
+
const priorEntryId = open.records[0]?.get("entryId");
|
|
19449
|
+
const priorTaskId = open.records[0]?.get("taskId");
|
|
19450
|
+
const priorStartedAt = open.records[0]?.get("startedAt");
|
|
19451
|
+
console.log(`${TAG34} op=start taskId=${taskId} accountId=${accountId} priorOpen=${priorTaskId ?? "none"}`);
|
|
19452
|
+
if (priorEntryId && priorTaskId === taskId) {
|
|
19453
|
+
return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
|
|
19454
|
+
}
|
|
19455
|
+
if (priorEntryId && priorStartedAt && priorTaskId) {
|
|
19456
|
+
const seconds = secondsBetween(priorStartedAt, now);
|
|
19457
|
+
await session.run(
|
|
19458
|
+
`MATCH (te:TimeEntry {entryId: $priorEntryId}) WHERE te.endedAt IS NULL
|
|
19459
|
+
SET te.endedAt = $now, te.seconds = $seconds
|
|
19460
|
+
WITH te
|
|
19461
|
+
MATCH (t:Task {taskId: $priorTaskId, accountId: $accountId})
|
|
19462
|
+
SET t.secondsLogged = coalesce(t.secondsLogged, 0) + $seconds`,
|
|
19463
|
+
{ priorEntryId, priorTaskId, accountId, now, seconds: neo4j5.int(seconds) }
|
|
19464
|
+
);
|
|
19465
|
+
console.log(`${TAG34} op=autostop taskId=${priorTaskId} entryId=${priorEntryId} seconds=${seconds}`);
|
|
19466
|
+
}
|
|
19467
|
+
const entryId = randomUUID13();
|
|
19468
|
+
await session.run(
|
|
19469
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19470
|
+
CREATE (te:TimeEntry {entryId: $entryId, taskId: $taskId, accountId: $accountId, startedAt: $now, endedAt: null})
|
|
19471
|
+
CREATE (te)-[:LOGGED_AGAINST]->(t)`,
|
|
19472
|
+
{ taskId, accountId, entryId, now }
|
|
19473
|
+
);
|
|
19474
|
+
console.log(`${TAG34} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
|
|
19475
|
+
return c.json({ ok: true, running: true, entryId, startedAt: now });
|
|
19476
|
+
} catch (err) {
|
|
19477
|
+
console.error(`${TAG34} op=start error="${err instanceof Error ? err.message : String(err)}"`);
|
|
19478
|
+
return c.json({ error: "task-timer-start-failed" }, 500);
|
|
19479
|
+
} finally {
|
|
19480
|
+
await session.close();
|
|
19481
|
+
}
|
|
19482
|
+
});
|
|
19483
|
+
var task_timer_start_default = app47;
|
|
19484
|
+
|
|
19485
|
+
// server/routes/admin/task-timer-stop.ts
|
|
19486
|
+
import neo4j6 from "neo4j-driver";
|
|
19487
|
+
var TAG35 = "[task-timer]";
|
|
19488
|
+
var app48 = new Hono();
|
|
19489
|
+
app48.post("/", requireAdminSession, async (c) => {
|
|
19490
|
+
const cacheKey = c.var.cacheKey;
|
|
19491
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
19492
|
+
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
19493
|
+
let body;
|
|
19494
|
+
try {
|
|
19495
|
+
body = await c.req.json();
|
|
19496
|
+
} catch {
|
|
19497
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
19498
|
+
}
|
|
19499
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
19500
|
+
if (!taskId) return c.json({ error: "taskId required" }, 400);
|
|
19501
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19502
|
+
const session = getSession();
|
|
19503
|
+
try {
|
|
19504
|
+
const open = await session.run(
|
|
19505
|
+
`MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NULL
|
|
19506
|
+
RETURN te.entryId AS entryId, te.startedAt AS startedAt
|
|
19507
|
+
ORDER BY te.startedAt LIMIT 1`,
|
|
19508
|
+
{ taskId, accountId }
|
|
19509
|
+
);
|
|
19510
|
+
const entryId = open.records[0]?.get("entryId");
|
|
19511
|
+
const startedAt = open.records[0]?.get("startedAt");
|
|
19512
|
+
if (!entryId || !startedAt) {
|
|
19513
|
+
const cur = await session.run(
|
|
19514
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19515
|
+
RETURN coalesce(t.secondsLogged, 0) AS secondsLogged`,
|
|
19516
|
+
{ taskId, accountId }
|
|
19517
|
+
);
|
|
19518
|
+
const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
|
|
19519
|
+
console.log(`${TAG35} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
|
|
19520
|
+
return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
|
|
19521
|
+
}
|
|
19522
|
+
const seconds = secondsBetween(startedAt, now);
|
|
19523
|
+
await session.run(
|
|
19524
|
+
`MATCH (te:TimeEntry {entryId: $entryId}) WHERE te.endedAt IS NULL
|
|
19525
|
+
SET te.endedAt = $now, te.seconds = $seconds
|
|
19526
|
+
WITH te
|
|
19527
|
+
MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19528
|
+
SET t.secondsLogged = coalesce(t.secondsLogged, 0) + $seconds`,
|
|
19529
|
+
{ entryId, taskId, accountId, now, seconds: neo4j6.int(seconds) }
|
|
19530
|
+
);
|
|
19531
|
+
const verify = await session.run(
|
|
19532
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19533
|
+
OPTIONAL MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NOT NULL
|
|
19534
|
+
RETURN coalesce(sum(te.seconds), 0) AS sumEntries, coalesce(t.secondsLogged, 0) AS secondsLogged`,
|
|
19535
|
+
{ taskId, accountId }
|
|
19536
|
+
);
|
|
19537
|
+
const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
|
|
19538
|
+
const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
|
|
19539
|
+
console.log(`${TAG35} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
|
|
19540
|
+
console.log(`${TAG35} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} secondsLogged=${secondsLogged}`);
|
|
19541
|
+
return c.json({ ok: true, running: false, seconds, secondsLogged });
|
|
19542
|
+
} catch (err) {
|
|
19543
|
+
console.error(`${TAG35} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
|
|
19544
|
+
return c.json({ error: "task-timer-stop-failed" }, 500);
|
|
19545
|
+
} finally {
|
|
19546
|
+
await session.close();
|
|
19547
|
+
}
|
|
19548
|
+
});
|
|
19549
|
+
var task_timer_stop_default = app48;
|
|
19550
|
+
|
|
19551
|
+
// server/routes/admin/task-complete.ts
|
|
19552
|
+
var TAG36 = "[task-timer]";
|
|
19553
|
+
var app49 = new Hono();
|
|
19554
|
+
app49.post("/", requireAdminSession, async (c) => {
|
|
19555
|
+
const cacheKey = c.var.cacheKey;
|
|
19556
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
19557
|
+
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
19558
|
+
let body;
|
|
19559
|
+
try {
|
|
19560
|
+
body = await c.req.json();
|
|
19561
|
+
} catch {
|
|
19562
|
+
return c.json({ error: "invalid-json" }, 400);
|
|
19563
|
+
}
|
|
19564
|
+
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
19565
|
+
if (!taskId) return c.json({ error: "taskId required" }, 400);
|
|
19566
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19567
|
+
const session = getSession();
|
|
19568
|
+
try {
|
|
19569
|
+
const result = await session.run(
|
|
19570
|
+
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
19571
|
+
SET t.status = 'completed', t.updatedAt = $now
|
|
19572
|
+
RETURN t.taskId AS taskId, coalesce(t.secondsLogged, 0) AS secondsLogged`,
|
|
19573
|
+
{ taskId, accountId, now }
|
|
19574
|
+
);
|
|
19575
|
+
if (result.records.length === 0) {
|
|
19576
|
+
return c.json({ error: "task-not-found" }, 404);
|
|
19577
|
+
}
|
|
19578
|
+
const secondsLogged = toNum(result.records[0].get("secondsLogged"));
|
|
19579
|
+
console.log(`${TAG36} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
|
|
19580
|
+
return c.json({ ok: true, status: "completed", secondsLogged });
|
|
19581
|
+
} catch (err) {
|
|
19582
|
+
console.error(`${TAG36} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
|
|
19583
|
+
return c.json({ error: "task-complete-failed" }, 500);
|
|
19584
|
+
} finally {
|
|
19585
|
+
await session.close();
|
|
19586
|
+
}
|
|
19587
|
+
});
|
|
19588
|
+
var task_complete_default = app49;
|
|
19589
|
+
|
|
19590
|
+
// server/routes/admin/index.ts
|
|
19591
|
+
var app50 = new Hono();
|
|
19592
|
+
app50.route("/session", session_default);
|
|
19593
|
+
app50.route("/accounts", accounts_default);
|
|
19594
|
+
app50.route("/logs", logs_default);
|
|
19595
|
+
app50.route("/claude-info", claude_info_default);
|
|
19596
|
+
app50.route("/attachment", attachment_default);
|
|
19597
|
+
app50.route("/agents", agents_default);
|
|
19598
|
+
app50.route("/sessions", sessions_default);
|
|
19599
|
+
app50.route("/claude-sessions", claude_sessions_default);
|
|
19600
|
+
app50.route("/log-ingest", log_ingest_default);
|
|
19601
|
+
app50.route("/events", events_default);
|
|
19602
|
+
app50.route("/files", files_default);
|
|
19603
|
+
app50.route("/graph-search", graph_search_default);
|
|
19604
|
+
app50.route("/graph-subgraph", graph_subgraph_default);
|
|
19605
|
+
app50.route("/graph-delete", graph_delete_default);
|
|
19606
|
+
app50.route("/graph-restore", graph_restore_default);
|
|
19607
|
+
app50.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
19608
|
+
app50.route("/graph-default-view", graph_default_view_default);
|
|
19609
|
+
app50.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
19610
|
+
app50.route("/sidebar-sessions", sidebar_sessions_default);
|
|
19611
|
+
app50.route("/session-delete", session_delete_default);
|
|
19612
|
+
app50.route("/session-stop", session_stop_default);
|
|
19613
|
+
app50.route("/session-archive", session_archive_default);
|
|
19614
|
+
app50.route("/session-rename", session_rename_default);
|
|
19615
|
+
app50.route("/session-usage", session_usage_default);
|
|
19616
|
+
app50.route("/browser", browser_default);
|
|
19617
|
+
app50.route("/session-rc-spawn", session_rc_spawn_default);
|
|
19618
|
+
app50.route("/session-reseat", session_reseat_default);
|
|
19619
|
+
app50.route("/system-stats", system_stats_default);
|
|
19620
|
+
app50.route("/health-brand", health_default2);
|
|
19621
|
+
app50.route("/linkedin-ingest", linkedin_ingest_default);
|
|
19622
|
+
app50.route("/post-turn-context", post_turn_context_default);
|
|
19623
|
+
app50.route("/public-session-context", public_session_context_default);
|
|
19624
|
+
app50.route("/public-session-exit", public_session_exit_default);
|
|
19625
|
+
app50.route("/access-session-evict", access_session_evict_default);
|
|
19626
|
+
app50.route("/enrol-person", enrol_person_default);
|
|
19627
|
+
app50.route("/calendar", calendar_default);
|
|
19628
|
+
app50.route("/tasks-list", tasks_list_default);
|
|
19629
|
+
app50.route("/task-timer-start", task_timer_start_default);
|
|
19630
|
+
app50.route("/task-timer-stop", task_timer_stop_default);
|
|
19631
|
+
app50.route("/task-complete", task_complete_default);
|
|
19632
|
+
var admin_default = app50;
|
|
19263
19633
|
|
|
19264
19634
|
// server/routes/access/verify-token.ts
|
|
19265
|
-
var
|
|
19635
|
+
var TAG37 = "[access-verify]";
|
|
19266
19636
|
var MINT_TAG = "[access-session-mint]";
|
|
19267
19637
|
var COOKIE_NAME = "__access_session";
|
|
19268
|
-
var
|
|
19269
|
-
|
|
19638
|
+
var app51 = new Hono();
|
|
19639
|
+
app51.post("/", async (c) => {
|
|
19270
19640
|
const ip = c.var.clientIp || "unknown";
|
|
19271
19641
|
let body;
|
|
19272
19642
|
try {
|
|
@@ -19281,39 +19651,39 @@ app47.post("/", async (c) => {
|
|
|
19281
19651
|
}
|
|
19282
19652
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
19283
19653
|
if (rateMsg) {
|
|
19284
|
-
console.error(`${
|
|
19654
|
+
console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
19285
19655
|
return c.json({ error: rateMsg }, 429);
|
|
19286
19656
|
}
|
|
19287
19657
|
const grant = await findGrantByMagicToken(token);
|
|
19288
19658
|
if (!grant) {
|
|
19289
19659
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
19290
|
-
console.error(`${
|
|
19660
|
+
console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
19291
19661
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
19292
19662
|
}
|
|
19293
19663
|
if (grant.agentSlug !== agentSlug) {
|
|
19294
19664
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
19295
19665
|
console.error(
|
|
19296
|
-
`${
|
|
19666
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
19297
19667
|
);
|
|
19298
19668
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
19299
19669
|
}
|
|
19300
19670
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
19301
19671
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
19302
19672
|
console.error(
|
|
19303
|
-
`${
|
|
19673
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
19304
19674
|
);
|
|
19305
19675
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
19306
19676
|
}
|
|
19307
19677
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
19308
19678
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
19309
19679
|
console.error(
|
|
19310
|
-
`${
|
|
19680
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
19311
19681
|
);
|
|
19312
19682
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
19313
19683
|
}
|
|
19314
19684
|
if (!grant.sliceToken) {
|
|
19315
19685
|
console.error(
|
|
19316
|
-
`${
|
|
19686
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
19317
19687
|
);
|
|
19318
19688
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
19319
19689
|
}
|
|
@@ -19329,12 +19699,12 @@ app47.post("/", async (c) => {
|
|
|
19329
19699
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
19330
19700
|
} catch (err) {
|
|
19331
19701
|
console.error(
|
|
19332
|
-
`${
|
|
19702
|
+
`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
19333
19703
|
);
|
|
19334
19704
|
return c.json({ error: "verification-failed" }, 500);
|
|
19335
19705
|
}
|
|
19336
19706
|
clearAccessRateLimit(ip, agentSlug);
|
|
19337
|
-
console.log(`${
|
|
19707
|
+
console.log(`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
19338
19708
|
console.log(
|
|
19339
19709
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
19340
19710
|
);
|
|
@@ -19348,7 +19718,7 @@ app47.post("/", async (c) => {
|
|
|
19348
19718
|
displayName: grant.displayName
|
|
19349
19719
|
});
|
|
19350
19720
|
});
|
|
19351
|
-
var verify_token_default =
|
|
19721
|
+
var verify_token_default = app51;
|
|
19352
19722
|
|
|
19353
19723
|
// app/lib/access-email.ts
|
|
19354
19724
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -19410,10 +19780,10 @@ async function sendMagicLinkEmail(payload) {
|
|
|
19410
19780
|
}
|
|
19411
19781
|
|
|
19412
19782
|
// server/routes/access/request-magic-link.ts
|
|
19413
|
-
var
|
|
19414
|
-
var
|
|
19783
|
+
var TAG38 = "[access-request-link]";
|
|
19784
|
+
var app52 = new Hono();
|
|
19415
19785
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
19416
|
-
|
|
19786
|
+
app52.post("/", async (c) => {
|
|
19417
19787
|
let body;
|
|
19418
19788
|
try {
|
|
19419
19789
|
body = await c.req.json();
|
|
@@ -19427,18 +19797,18 @@ app48.post("/", async (c) => {
|
|
|
19427
19797
|
}
|
|
19428
19798
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
19429
19799
|
if (rateMsg) {
|
|
19430
|
-
console.error(`${
|
|
19800
|
+
console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
19431
19801
|
return c.json({ error: rateMsg }, 429);
|
|
19432
19802
|
}
|
|
19433
19803
|
recordRequestLinkAttempt(contactValue);
|
|
19434
19804
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
19435
19805
|
if (!accountId) {
|
|
19436
|
-
console.error(`${
|
|
19806
|
+
console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
19437
19807
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19438
19808
|
}
|
|
19439
19809
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
19440
19810
|
if (!grant) {
|
|
19441
|
-
console.log(`${
|
|
19811
|
+
console.log(`${TAG38} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
19442
19812
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19443
19813
|
}
|
|
19444
19814
|
let token;
|
|
@@ -19446,7 +19816,7 @@ app48.post("/", async (c) => {
|
|
|
19446
19816
|
token = await generateNewMagicToken(grant.grantId);
|
|
19447
19817
|
} catch (err) {
|
|
19448
19818
|
console.error(
|
|
19449
|
-
`${
|
|
19819
|
+
`${TAG38} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
19450
19820
|
);
|
|
19451
19821
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19452
19822
|
}
|
|
@@ -19478,22 +19848,22 @@ app48.post("/", async (c) => {
|
|
|
19478
19848
|
});
|
|
19479
19849
|
if (!sendResult.ok) {
|
|
19480
19850
|
console.error(
|
|
19481
|
-
`${
|
|
19851
|
+
`${TAG38} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
19482
19852
|
);
|
|
19483
19853
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19484
19854
|
}
|
|
19485
19855
|
console.log(
|
|
19486
|
-
`${
|
|
19856
|
+
`${TAG38} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
19487
19857
|
);
|
|
19488
19858
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
19489
19859
|
});
|
|
19490
|
-
var request_magic_link_default =
|
|
19860
|
+
var request_magic_link_default = app52;
|
|
19491
19861
|
|
|
19492
19862
|
// server/routes/access/index.ts
|
|
19493
|
-
var
|
|
19494
|
-
|
|
19495
|
-
|
|
19496
|
-
var access_default =
|
|
19863
|
+
var app53 = new Hono();
|
|
19864
|
+
app53.route("/verify-token", verify_token_default);
|
|
19865
|
+
app53.route("/request-magic-link", request_magic_link_default);
|
|
19866
|
+
var access_default = app53;
|
|
19497
19867
|
|
|
19498
19868
|
// server/routes/sites.ts
|
|
19499
19869
|
import { existsSync as existsSync28, readFileSync as readFileSync31, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
|
|
@@ -19528,8 +19898,8 @@ function getExt(p) {
|
|
|
19528
19898
|
if (idx < p.lastIndexOf("/")) return "";
|
|
19529
19899
|
return p.slice(idx).toLowerCase();
|
|
19530
19900
|
}
|
|
19531
|
-
var
|
|
19532
|
-
|
|
19901
|
+
var app54 = new Hono();
|
|
19902
|
+
app54.get("/:rel{.*}", (c) => {
|
|
19533
19903
|
const reqPath = c.req.path;
|
|
19534
19904
|
const rawRel = c.req.param("rel") ?? "";
|
|
19535
19905
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -19632,7 +20002,7 @@ app50.get("/:rel{.*}", (c) => {
|
|
|
19632
20002
|
"X-Content-Type-Options": "nosniff"
|
|
19633
20003
|
});
|
|
19634
20004
|
});
|
|
19635
|
-
var sites_default =
|
|
20005
|
+
var sites_default = app54;
|
|
19636
20006
|
|
|
19637
20007
|
// app/lib/visitor-token.ts
|
|
19638
20008
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
@@ -19732,7 +20102,7 @@ function readBrandConfig() {
|
|
|
19732
20102
|
}
|
|
19733
20103
|
|
|
19734
20104
|
// server/routes/visitor-consent.ts
|
|
19735
|
-
var
|
|
20105
|
+
var app55 = new Hono();
|
|
19736
20106
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
19737
20107
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
19738
20108
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -19777,17 +20147,17 @@ function siteSlugFromReferer(referer) {
|
|
|
19777
20147
|
return "";
|
|
19778
20148
|
}
|
|
19779
20149
|
}
|
|
19780
|
-
|
|
20150
|
+
app55.options("/consent", (c) => {
|
|
19781
20151
|
const origin = getOrigin(c);
|
|
19782
20152
|
setCorsHeaders(c, origin);
|
|
19783
20153
|
return c.body(null, 204);
|
|
19784
20154
|
});
|
|
19785
|
-
|
|
20155
|
+
app55.options("/brand-config", (c) => {
|
|
19786
20156
|
const origin = getOrigin(c);
|
|
19787
20157
|
setCorsHeaders(c, origin);
|
|
19788
20158
|
return c.body(null, 204);
|
|
19789
20159
|
});
|
|
19790
|
-
|
|
20160
|
+
app55.post("/consent", async (c) => {
|
|
19791
20161
|
const origin = getOrigin(c);
|
|
19792
20162
|
setCorsHeaders(c, origin);
|
|
19793
20163
|
let raw;
|
|
@@ -19827,7 +20197,7 @@ app51.post("/consent", async (c) => {
|
|
|
19827
20197
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
19828
20198
|
return c.body(null, 204);
|
|
19829
20199
|
});
|
|
19830
|
-
|
|
20200
|
+
app55.get("/brand-config", (c) => {
|
|
19831
20201
|
const origin = getOrigin(c);
|
|
19832
20202
|
setCorsHeaders(c, origin);
|
|
19833
20203
|
const brand = readBrandConfig();
|
|
@@ -19837,7 +20207,7 @@ app51.get("/brand-config", (c) => {
|
|
|
19837
20207
|
c.header("Cache-Control", "public, max-age=300");
|
|
19838
20208
|
return c.json({ consent: { copy, palette } });
|
|
19839
20209
|
});
|
|
19840
|
-
var visitor_consent_default =
|
|
20210
|
+
var visitor_consent_default = app55;
|
|
19841
20211
|
|
|
19842
20212
|
// server/routes/listings.ts
|
|
19843
20213
|
function getCookie(headerValue, name) {
|
|
@@ -19864,8 +20234,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
19864
20234
|
}
|
|
19865
20235
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
19866
20236
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
19867
|
-
var
|
|
19868
|
-
|
|
20237
|
+
var app56 = new Hono();
|
|
20238
|
+
app56.get("/:slug/click", async (c) => {
|
|
19869
20239
|
const slug = c.req.param("slug") ?? "";
|
|
19870
20240
|
const rawSession = c.req.query("session") ?? "";
|
|
19871
20241
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -19929,10 +20299,10 @@ app52.get("/:slug/click", async (c) => {
|
|
|
19929
20299
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
19930
20300
|
return c.redirect(redirectUrl, 302);
|
|
19931
20301
|
});
|
|
19932
|
-
var listings_default =
|
|
20302
|
+
var listings_default = app56;
|
|
19933
20303
|
|
|
19934
20304
|
// server/routes/visitor-event.ts
|
|
19935
|
-
var
|
|
20305
|
+
var app57 = new Hono();
|
|
19936
20306
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
19937
20307
|
var buckets = /* @__PURE__ */ new Map();
|
|
19938
20308
|
var RATE_LIMIT = 60;
|
|
@@ -19999,12 +20369,12 @@ function originAllowed(origin, allowlist) {
|
|
|
19999
20369
|
return false;
|
|
20000
20370
|
}
|
|
20001
20371
|
}
|
|
20002
|
-
|
|
20372
|
+
app57.options("/event", (c) => {
|
|
20003
20373
|
const origin = getOrigin2(c);
|
|
20004
20374
|
setCorsHeaders2(c, origin);
|
|
20005
20375
|
return c.body(null, 204);
|
|
20006
20376
|
});
|
|
20007
|
-
|
|
20377
|
+
app57.post("/event", async (c) => {
|
|
20008
20378
|
const origin = getOrigin2(c);
|
|
20009
20379
|
setCorsHeaders2(c, origin);
|
|
20010
20380
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -20209,7 +20579,7 @@ async function writeEvent(opts) {
|
|
|
20209
20579
|
);
|
|
20210
20580
|
}
|
|
20211
20581
|
}
|
|
20212
|
-
var visitor_event_default =
|
|
20582
|
+
var visitor_event_default = app57;
|
|
20213
20583
|
|
|
20214
20584
|
// server/routes/session.ts
|
|
20215
20585
|
import { resolve as resolve27 } from "path";
|
|
@@ -20255,8 +20625,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
20255
20625
|
headers
|
|
20256
20626
|
});
|
|
20257
20627
|
}
|
|
20258
|
-
var
|
|
20259
|
-
|
|
20628
|
+
var app58 = new Hono();
|
|
20629
|
+
app58.post("/", async (c) => {
|
|
20260
20630
|
let body;
|
|
20261
20631
|
try {
|
|
20262
20632
|
body = await c.req.json();
|
|
@@ -20403,7 +20773,7 @@ app54.post("/", async (c) => {
|
|
|
20403
20773
|
newVisitorId
|
|
20404
20774
|
);
|
|
20405
20775
|
});
|
|
20406
|
-
var session_default2 =
|
|
20776
|
+
var session_default2 = app58;
|
|
20407
20777
|
|
|
20408
20778
|
// server/lib/calendar-slots.ts
|
|
20409
20779
|
var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
@@ -20486,17 +20856,17 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
|
|
|
20486
20856
|
}
|
|
20487
20857
|
|
|
20488
20858
|
// server/routes/calendar-public.ts
|
|
20489
|
-
var
|
|
20859
|
+
var app59 = new Hono();
|
|
20490
20860
|
function setCors(c) {
|
|
20491
20861
|
c.header("Access-Control-Allow-Origin", "*");
|
|
20492
20862
|
c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
20493
20863
|
c.header("Access-Control-Allow-Headers", "content-type");
|
|
20494
20864
|
}
|
|
20495
|
-
|
|
20865
|
+
app59.options("/free-busy", (c) => {
|
|
20496
20866
|
setCors(c);
|
|
20497
20867
|
return c.body(null, 204);
|
|
20498
20868
|
});
|
|
20499
|
-
|
|
20869
|
+
app59.get("/free-busy", async (c) => {
|
|
20500
20870
|
setCors(c);
|
|
20501
20871
|
const from = c.req.query("from");
|
|
20502
20872
|
const to = c.req.query("to");
|
|
@@ -20538,7 +20908,79 @@ app55.get("/free-busy", async (c) => {
|
|
|
20538
20908
|
await session.close();
|
|
20539
20909
|
}
|
|
20540
20910
|
});
|
|
20541
|
-
var calendar_public_default =
|
|
20911
|
+
var calendar_public_default = app59;
|
|
20912
|
+
|
|
20913
|
+
// app/lib/timeentry-census.ts
|
|
20914
|
+
var TAG39 = "[timeentry-census]";
|
|
20915
|
+
function reconcileTimeEntries(rows, now, horizonMs) {
|
|
20916
|
+
const openEntries = rows.openEntries.length;
|
|
20917
|
+
let oldestOpenAgeMs = 0;
|
|
20918
|
+
const perAccount = /* @__PURE__ */ new Map();
|
|
20919
|
+
for (const e of rows.openEntries) {
|
|
20920
|
+
oldestOpenAgeMs = Math.max(oldestOpenAgeMs, now - e.startedAtMs);
|
|
20921
|
+
perAccount.set(e.accountId, (perAccount.get(e.accountId) ?? 0) + 1);
|
|
20922
|
+
}
|
|
20923
|
+
const maxOpenPerAccount = perAccount.size === 0 ? 0 : Math.max(...perAccount.values());
|
|
20924
|
+
const driftTasks = rows.taskSums.filter((t) => t.secondsLogged !== t.sumEntries).length;
|
|
20925
|
+
const oldestOpenAgeMin = Math.floor(oldestOpenAgeMs / 6e4);
|
|
20926
|
+
const alarm = oldestOpenAgeMs > horizonMs || maxOpenPerAccount > 1 || driftTasks > 0;
|
|
20927
|
+
return { openEntries, oldestOpenAgeMin, maxOpenPerAccount, driftTasks, alarm };
|
|
20928
|
+
}
|
|
20929
|
+
async function runTimeEntryCensusOnce(session, now, horizonMs) {
|
|
20930
|
+
try {
|
|
20931
|
+
const openRes = await session.run(
|
|
20932
|
+
`MATCH (te:TimeEntry) WHERE te.endedAt IS NULL
|
|
20933
|
+
RETURN te.accountId AS accountId, te.startedAt AS startedAt`
|
|
20934
|
+
);
|
|
20935
|
+
const openEntries = openRes.records.map((r) => ({
|
|
20936
|
+
accountId: r.get("accountId") ?? "unknown",
|
|
20937
|
+
startedAtMs: Date.parse(r.get("startedAt") ?? "") || now
|
|
20938
|
+
}));
|
|
20939
|
+
const sumRes = await session.run(
|
|
20940
|
+
`MATCH (t:Task) WHERE t.secondsLogged IS NOT NULL
|
|
20941
|
+
OPTIONAL MATCH (te:TimeEntry {taskId: t.taskId}) WHERE te.endedAt IS NOT NULL
|
|
20942
|
+
RETURN t.taskId AS taskId, coalesce(t.secondsLogged, 0) AS secondsLogged, coalesce(sum(te.seconds), 0) AS sumEntries`
|
|
20943
|
+
);
|
|
20944
|
+
const taskSums = sumRes.records.map((r) => ({
|
|
20945
|
+
taskId: r.get("taskId") ?? "",
|
|
20946
|
+
secondsLogged: toNum(r.get("secondsLogged")),
|
|
20947
|
+
sumEntries: toNum(r.get("sumEntries"))
|
|
20948
|
+
}));
|
|
20949
|
+
const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
|
|
20950
|
+
const line = `${TAG39} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
|
|
20951
|
+
if (finding.alarm) console.error(`${line} alarm=true`);
|
|
20952
|
+
else console.log(line);
|
|
20953
|
+
return finding;
|
|
20954
|
+
} catch (err) {
|
|
20955
|
+
console.error(`${TAG39} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
20956
|
+
return null;
|
|
20957
|
+
}
|
|
20958
|
+
}
|
|
20959
|
+
var DEFAULT_INTERVAL_MS = 15 * 60 * 1e3;
|
|
20960
|
+
var DEFAULT_HORIZON_MS = 8 * 60 * 60 * 1e3;
|
|
20961
|
+
function startTimeEntryCensus(openSession, opts = {}) {
|
|
20962
|
+
const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
20963
|
+
const horizonMs = opts.horizonMs ?? DEFAULT_HORIZON_MS;
|
|
20964
|
+
const tick = async () => {
|
|
20965
|
+
const session = openSession();
|
|
20966
|
+
try {
|
|
20967
|
+
await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
|
|
20968
|
+
} finally {
|
|
20969
|
+
try {
|
|
20970
|
+
await session.close();
|
|
20971
|
+
} catch {
|
|
20972
|
+
}
|
|
20973
|
+
}
|
|
20974
|
+
};
|
|
20975
|
+
void tick();
|
|
20976
|
+
const id = setInterval(() => {
|
|
20977
|
+
void tick();
|
|
20978
|
+
}, intervalMs);
|
|
20979
|
+
if (typeof id.unref === "function") {
|
|
20980
|
+
id.unref();
|
|
20981
|
+
}
|
|
20982
|
+
return () => clearInterval(id);
|
|
20983
|
+
}
|
|
20542
20984
|
|
|
20543
20985
|
// app/lib/graph-health.ts
|
|
20544
20986
|
var import_dist4 = __toESM(require_dist4(), 1);
|
|
@@ -21307,8 +21749,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
21307
21749
|
|
|
21308
21750
|
// app/lib/whatsapp/gateway/routes.ts
|
|
21309
21751
|
function createWaChannelRoutes(deps) {
|
|
21310
|
-
const
|
|
21311
|
-
|
|
21752
|
+
const app61 = new Hono();
|
|
21753
|
+
app61.get("/wa-channel/inbound", (c) => {
|
|
21312
21754
|
const senderId = c.req.query("senderId");
|
|
21313
21755
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
21314
21756
|
return streamSSE(c, async (stream2) => {
|
|
@@ -21326,7 +21768,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21326
21768
|
}
|
|
21327
21769
|
});
|
|
21328
21770
|
});
|
|
21329
|
-
|
|
21771
|
+
app61.post("/wa-channel/reply", async (c) => {
|
|
21330
21772
|
const body = await c.req.json().catch(() => null);
|
|
21331
21773
|
const senderId = body?.senderId;
|
|
21332
21774
|
const text = body?.text;
|
|
@@ -21347,7 +21789,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21347
21789
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
21348
21790
|
return c.json({ ok: true });
|
|
21349
21791
|
});
|
|
21350
|
-
|
|
21792
|
+
app61.post("/wa-channel/reply-document", async (c) => {
|
|
21351
21793
|
const body = await c.req.json().catch(() => null);
|
|
21352
21794
|
const senderId = body?.senderId;
|
|
21353
21795
|
const files = body?.files;
|
|
@@ -21386,7 +21828,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21386
21828
|
}
|
|
21387
21829
|
return c.json({ ok: true, results });
|
|
21388
21830
|
});
|
|
21389
|
-
|
|
21831
|
+
app61.post("/wa-channel/ready", async (c) => {
|
|
21390
21832
|
const body = await c.req.json().catch(() => null);
|
|
21391
21833
|
const senderId = body?.senderId;
|
|
21392
21834
|
if (typeof senderId !== "string") {
|
|
@@ -21395,7 +21837,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21395
21837
|
deps.onReady?.(senderId);
|
|
21396
21838
|
return c.json({ ok: true });
|
|
21397
21839
|
});
|
|
21398
|
-
|
|
21840
|
+
app61.post("/wa-channel/received", async (c) => {
|
|
21399
21841
|
const body = await c.req.json().catch(() => null);
|
|
21400
21842
|
const senderId = body?.senderId;
|
|
21401
21843
|
const waMessageId = body?.waMessageId;
|
|
@@ -21405,7 +21847,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21405
21847
|
deps.onReceived?.(senderId, waMessageId);
|
|
21406
21848
|
return c.json({ ok: true });
|
|
21407
21849
|
});
|
|
21408
|
-
|
|
21850
|
+
app61.post("/wa-channel/turn-end", async (c) => {
|
|
21409
21851
|
const body = await c.req.json().catch(() => null);
|
|
21410
21852
|
const senderId = body?.senderId;
|
|
21411
21853
|
const sessionId = body?.sessionId;
|
|
@@ -21421,7 +21863,7 @@ function createWaChannelRoutes(deps) {
|
|
|
21421
21863
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=none`);
|
|
21422
21864
|
return c.json({ ok: true, delivered: "none" });
|
|
21423
21865
|
});
|
|
21424
|
-
return
|
|
21866
|
+
return app61;
|
|
21425
21867
|
}
|
|
21426
21868
|
|
|
21427
21869
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -21526,7 +21968,8 @@ var WaGateway = class {
|
|
|
21526
21968
|
waMessageId: `wa-${++this.seq}`,
|
|
21527
21969
|
media: input.media,
|
|
21528
21970
|
source,
|
|
21529
|
-
standingRules
|
|
21971
|
+
standingRules,
|
|
21972
|
+
scheduleProvenance: input.scheduleProvenance
|
|
21530
21973
|
},
|
|
21531
21974
|
Date.now()
|
|
21532
21975
|
);
|
|
@@ -21544,7 +21987,9 @@ var WaGateway = class {
|
|
|
21544
21987
|
role: input.role ?? "admin",
|
|
21545
21988
|
personId: input.personId ?? null,
|
|
21546
21989
|
gatewayUrl: this.deps.gatewayUrl,
|
|
21547
|
-
serverPath: this.deps.serverPath
|
|
21990
|
+
serverPath: this.deps.serverPath,
|
|
21991
|
+
// Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
|
|
21992
|
+
sessionIdOverride: input.scheduledSessionId
|
|
21548
21993
|
});
|
|
21549
21994
|
} finally {
|
|
21550
21995
|
this.spawning.delete(input.senderId);
|
|
@@ -21570,7 +22015,7 @@ var WaGateway = class {
|
|
|
21570
22015
|
function buildWaSpawnRequest(input) {
|
|
21571
22016
|
const personId = input.role === "public" && input.personId ? input.personId : void 0;
|
|
21572
22017
|
return {
|
|
21573
|
-
sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
22018
|
+
sessionId: input.sessionIdOverride && input.sessionIdOverride.length > 0 ? input.sessionIdOverride : adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
21574
22019
|
role: input.role,
|
|
21575
22020
|
channel: "whatsapp",
|
|
21576
22021
|
personId,
|
|
@@ -21754,8 +22199,8 @@ var import_dist6 = __toESM(require_dist(), 1);
|
|
|
21754
22199
|
|
|
21755
22200
|
// app/lib/webchat/gateway/routes.ts
|
|
21756
22201
|
function createWebchatChannelRoutes(deps) {
|
|
21757
|
-
const
|
|
21758
|
-
|
|
22202
|
+
const app61 = new Hono();
|
|
22203
|
+
app61.get("/webchat-channel/inbound", (c) => {
|
|
21759
22204
|
const key = c.req.query("key");
|
|
21760
22205
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
21761
22206
|
return streamSSE(c, async (stream2) => {
|
|
@@ -21773,7 +22218,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21773
22218
|
}
|
|
21774
22219
|
});
|
|
21775
22220
|
});
|
|
21776
|
-
|
|
22221
|
+
app61.post("/webchat-channel/reply", async (c) => {
|
|
21777
22222
|
const body = await c.req.json().catch(() => null);
|
|
21778
22223
|
const key = body?.key;
|
|
21779
22224
|
const text = body?.text;
|
|
@@ -21783,7 +22228,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21783
22228
|
deps.onReply?.(key, text);
|
|
21784
22229
|
return c.json({ ok: true });
|
|
21785
22230
|
});
|
|
21786
|
-
|
|
22231
|
+
app61.post("/webchat-channel/connector-auth", async (c) => {
|
|
21787
22232
|
const body = await c.req.json().catch(() => null);
|
|
21788
22233
|
const key = body?.key;
|
|
21789
22234
|
const sessionId = body?.sessionId;
|
|
@@ -21796,7 +22241,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21796
22241
|
const result = await deps.onConnectorAuth({ key, sessionId, name, completed });
|
|
21797
22242
|
return c.json(result);
|
|
21798
22243
|
});
|
|
21799
|
-
|
|
22244
|
+
app61.post("/webchat-channel/ready", async (c) => {
|
|
21800
22245
|
const body = await c.req.json().catch(() => null);
|
|
21801
22246
|
const key = body?.key;
|
|
21802
22247
|
if (typeof key !== "string") {
|
|
@@ -21805,7 +22250,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21805
22250
|
deps.onReady?.(key);
|
|
21806
22251
|
return c.json({ ok: true });
|
|
21807
22252
|
});
|
|
21808
|
-
|
|
22253
|
+
app61.post("/webchat-channel/permission-request", async (c) => {
|
|
21809
22254
|
const body = await c.req.json().catch(() => null);
|
|
21810
22255
|
const key = body?.key;
|
|
21811
22256
|
const requestId = body?.request_id;
|
|
@@ -21819,7 +22264,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21819
22264
|
const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
|
|
21820
22265
|
return c.json(verdict);
|
|
21821
22266
|
});
|
|
21822
|
-
|
|
22267
|
+
app61.post("/webchat-channel/received", async (c) => {
|
|
21823
22268
|
const body = await c.req.json().catch(() => null);
|
|
21824
22269
|
const key = body?.key;
|
|
21825
22270
|
const messageId = body?.messageId;
|
|
@@ -21829,7 +22274,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21829
22274
|
deps.onReceived?.(key, messageId);
|
|
21830
22275
|
return c.json({ ok: true });
|
|
21831
22276
|
});
|
|
21832
|
-
|
|
22277
|
+
app61.post("/webchat-channel/turn-end", async (c) => {
|
|
21833
22278
|
const body = await c.req.json().catch(() => null);
|
|
21834
22279
|
const key = body?.key;
|
|
21835
22280
|
const sessionId = body?.sessionId;
|
|
@@ -21849,7 +22294,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
21849
22294
|
console.error(`[webchat-native] op=turn-undelivered channel=webchat key=${k} sessionId=${sid} bytes=${finalBytes}`);
|
|
21850
22295
|
return c.json({ ok: true, delivered: "undelivered" });
|
|
21851
22296
|
});
|
|
21852
|
-
return
|
|
22297
|
+
return app61;
|
|
21853
22298
|
}
|
|
21854
22299
|
|
|
21855
22300
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -22480,7 +22925,7 @@ function makeFileDelivery(opts) {
|
|
|
22480
22925
|
}
|
|
22481
22926
|
|
|
22482
22927
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
22483
|
-
var
|
|
22928
|
+
var TAG40 = "[whatsapp-adaptor]";
|
|
22484
22929
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
22485
22930
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
22486
22931
|
function platformRoot() {
|
|
@@ -22498,7 +22943,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
22498
22943
|
});
|
|
22499
22944
|
if (result.ok) return { ok: true };
|
|
22500
22945
|
console.error(
|
|
22501
|
-
`${
|
|
22946
|
+
`${TAG40} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
22502
22947
|
);
|
|
22503
22948
|
return { ok: false, error: result.error };
|
|
22504
22949
|
};
|
|
@@ -22506,7 +22951,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
22506
22951
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
22507
22952
|
const shared = makeFileDelivery({
|
|
22508
22953
|
entry,
|
|
22509
|
-
tag:
|
|
22954
|
+
tag: TAG40,
|
|
22510
22955
|
channel: "whatsapp",
|
|
22511
22956
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
22512
22957
|
});
|
|
@@ -22541,7 +22986,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
22541
22986
|
if (!delivered) {
|
|
22542
22987
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
22543
22988
|
console.error(
|
|
22544
|
-
`${
|
|
22989
|
+
`${TAG40} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
22545
22990
|
);
|
|
22546
22991
|
}
|
|
22547
22992
|
}
|
|
@@ -22718,8 +23163,8 @@ var import_dist7 = __toESM(require_dist(), 1);
|
|
|
22718
23163
|
|
|
22719
23164
|
// app/lib/telegram/gateway/routes.ts
|
|
22720
23165
|
function createTelegramChannelRoutes(deps) {
|
|
22721
|
-
const
|
|
22722
|
-
|
|
23166
|
+
const app61 = new Hono();
|
|
23167
|
+
app61.get("/tg-channel/inbound", (c) => {
|
|
22723
23168
|
const key = c.req.query("key");
|
|
22724
23169
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
22725
23170
|
return streamSSE(c, async (stream2) => {
|
|
@@ -22737,7 +23182,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22737
23182
|
}
|
|
22738
23183
|
});
|
|
22739
23184
|
});
|
|
22740
|
-
|
|
23185
|
+
app61.post("/tg-channel/reply", async (c) => {
|
|
22741
23186
|
const body = await c.req.json().catch(() => null);
|
|
22742
23187
|
const key = body?.key;
|
|
22743
23188
|
const text = body?.text;
|
|
@@ -22753,7 +23198,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22753
23198
|
console.error(`[telegram-native] op=reply key=${key} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
22754
23199
|
return c.json({ ok: true });
|
|
22755
23200
|
});
|
|
22756
|
-
|
|
23201
|
+
app61.post("/tg-channel/ready", async (c) => {
|
|
22757
23202
|
const body = await c.req.json().catch(() => null);
|
|
22758
23203
|
const key = body?.key;
|
|
22759
23204
|
if (typeof key !== "string") {
|
|
@@ -22762,7 +23207,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22762
23207
|
deps.onReady?.(key);
|
|
22763
23208
|
return c.json({ ok: true });
|
|
22764
23209
|
});
|
|
22765
|
-
|
|
23210
|
+
app61.post("/tg-channel/received", async (c) => {
|
|
22766
23211
|
const body = await c.req.json().catch(() => null);
|
|
22767
23212
|
const key = body?.key;
|
|
22768
23213
|
const messageId = body?.messageId;
|
|
@@ -22772,7 +23217,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22772
23217
|
deps.onReceived?.(key, messageId);
|
|
22773
23218
|
return c.json({ ok: true });
|
|
22774
23219
|
});
|
|
22775
|
-
|
|
23220
|
+
app61.post("/tg-channel/turn-end", async (c) => {
|
|
22776
23221
|
const body = await c.req.json().catch(() => null);
|
|
22777
23222
|
const key = body?.key;
|
|
22778
23223
|
const sessionId = body?.sessionId;
|
|
@@ -22788,7 +23233,7 @@ function createTelegramChannelRoutes(deps) {
|
|
|
22788
23233
|
console.error(`[telegram-native] op=turn-end key=${key} sessionId=${sid} replied=no delivered=none`);
|
|
22789
23234
|
return c.json({ ok: true, delivered: "none" });
|
|
22790
23235
|
});
|
|
22791
|
-
return
|
|
23236
|
+
return app61;
|
|
22792
23237
|
}
|
|
22793
23238
|
|
|
22794
23239
|
// app/lib/telegram/gateway/telegram-gateway.ts
|
|
@@ -22855,7 +23300,7 @@ var TelegramGateway = class {
|
|
|
22855
23300
|
);
|
|
22856
23301
|
}
|
|
22857
23302
|
this.hub.deliver(
|
|
22858
|
-
{ key: input.senderId, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules },
|
|
23303
|
+
{ key: input.senderId, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules, scheduleProvenance: input.scheduleProvenance },
|
|
22859
23304
|
Date.now()
|
|
22860
23305
|
);
|
|
22861
23306
|
console.error(
|
|
@@ -22872,7 +23317,9 @@ var TelegramGateway = class {
|
|
|
22872
23317
|
personId: input.personId ?? null,
|
|
22873
23318
|
chatId: input.chatId,
|
|
22874
23319
|
gatewayUrl: this.deps.gatewayUrl,
|
|
22875
|
-
serverPath: this.deps.serverPath
|
|
23320
|
+
serverPath: this.deps.serverPath,
|
|
23321
|
+
// Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
|
|
23322
|
+
sessionIdOverride: input.scheduledSessionId
|
|
22876
23323
|
});
|
|
22877
23324
|
} finally {
|
|
22878
23325
|
this.spawning.delete(input.senderId);
|
|
@@ -22890,7 +23337,7 @@ var TelegramGateway = class {
|
|
|
22890
23337
|
function buildTelegramSpawnRequest(input) {
|
|
22891
23338
|
const personId = input.role === "public" && input.personId ? input.personId : void 0;
|
|
22892
23339
|
return {
|
|
22893
|
-
sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
23340
|
+
sessionId: input.sessionIdOverride && input.sessionIdOverride.length > 0 ? input.sessionIdOverride : adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
22894
23341
|
role: input.role,
|
|
22895
23342
|
channel: "telegram",
|
|
22896
23343
|
personId,
|
|
@@ -22909,7 +23356,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
22909
23356
|
import { realpathSync as realpathSync7 } from "fs";
|
|
22910
23357
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
22911
23358
|
import { resolve as resolve30, basename as basename12 } from "path";
|
|
22912
|
-
var
|
|
23359
|
+
var TAG41 = "[telegram:outbound]";
|
|
22913
23360
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
22914
23361
|
async function sendTelegramDocument(input) {
|
|
22915
23362
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot3 } = input;
|
|
@@ -22925,16 +23372,16 @@ async function sendTelegramDocument(input) {
|
|
|
22925
23372
|
resolvedPath = realpathSync7(filePath);
|
|
22926
23373
|
const accountResolved = realpathSync7(accountDir);
|
|
22927
23374
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
22928
|
-
console.error(`${
|
|
23375
|
+
console.error(`${TAG41} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
22929
23376
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
22930
23377
|
}
|
|
22931
23378
|
} catch (err) {
|
|
22932
23379
|
const code = err.code;
|
|
22933
23380
|
if (code === "ENOENT") {
|
|
22934
|
-
console.error(`${
|
|
23381
|
+
console.error(`${TAG41} document ENOENT path=${filePath}`);
|
|
22935
23382
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
22936
23383
|
}
|
|
22937
|
-
console.error(`${
|
|
23384
|
+
console.error(`${TAG41} document path error: ${String(err)}`);
|
|
22938
23385
|
return { ok: false, status: 500, error: String(err) };
|
|
22939
23386
|
}
|
|
22940
23387
|
const fileStat = await stat7(resolvedPath);
|
|
@@ -22967,13 +23414,13 @@ async function sendTelegramDocument(input) {
|
|
|
22967
23414
|
error = e instanceof Error ? e.message : String(e);
|
|
22968
23415
|
}
|
|
22969
23416
|
console.error(
|
|
22970
|
-
`${
|
|
23417
|
+
`${TAG41} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
22971
23418
|
);
|
|
22972
23419
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
22973
23420
|
}
|
|
22974
23421
|
|
|
22975
23422
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
22976
|
-
var
|
|
23423
|
+
var TAG42 = "[telegram:outbound]";
|
|
22977
23424
|
function platformRoot2() {
|
|
22978
23425
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
22979
23426
|
}
|
|
@@ -22985,11 +23432,11 @@ function makeTelegramSendFile(entry) {
|
|
|
22985
23432
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
22986
23433
|
}
|
|
22987
23434
|
if (!botToken) {
|
|
22988
|
-
console.error(`${
|
|
23435
|
+
console.error(`${TAG42} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
22989
23436
|
return { ok: false, error: "no-bot-token" };
|
|
22990
23437
|
}
|
|
22991
23438
|
if (entry.replyTarget == null) {
|
|
22992
|
-
console.error(`${
|
|
23439
|
+
console.error(`${TAG42} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
22993
23440
|
return { ok: false, error: "no-reply-target" };
|
|
22994
23441
|
}
|
|
22995
23442
|
const result = await sendTelegramDocument({
|
|
@@ -23006,7 +23453,7 @@ function makeTelegramSendFile(entry) {
|
|
|
23006
23453
|
function makeTelegramFileDelivery(entry) {
|
|
23007
23454
|
return makeFileDelivery({
|
|
23008
23455
|
entry,
|
|
23009
|
-
tag:
|
|
23456
|
+
tag: TAG42,
|
|
23010
23457
|
channel: "telegram",
|
|
23011
23458
|
sendFile: makeTelegramSendFile(entry)
|
|
23012
23459
|
});
|
|
@@ -23055,8 +23502,8 @@ function telegramServerPath() {
|
|
|
23055
23502
|
}
|
|
23056
23503
|
|
|
23057
23504
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
23058
|
-
import { randomUUID as
|
|
23059
|
-
var
|
|
23505
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
23506
|
+
var TAG43 = "[public-session-review]";
|
|
23060
23507
|
var CONSUMED_CAP = 500;
|
|
23061
23508
|
var consumed = /* @__PURE__ */ new Set();
|
|
23062
23509
|
function consumeOnce(sessionId) {
|
|
@@ -23083,7 +23530,7 @@ async function fetchJsonl(sessionId) {
|
|
|
23083
23530
|
return await res.text();
|
|
23084
23531
|
} catch (err) {
|
|
23085
23532
|
console.error(
|
|
23086
|
-
`${
|
|
23533
|
+
`${TAG43} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
23087
23534
|
);
|
|
23088
23535
|
return null;
|
|
23089
23536
|
}
|
|
@@ -23107,7 +23554,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
23107
23554
|
const res = await fetch(url);
|
|
23108
23555
|
if (!res.ok) {
|
|
23109
23556
|
console.error(
|
|
23110
|
-
`${
|
|
23557
|
+
`${TAG43} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
23111
23558
|
);
|
|
23112
23559
|
return [];
|
|
23113
23560
|
}
|
|
@@ -23115,7 +23562,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
23115
23562
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
23116
23563
|
} catch (err) {
|
|
23117
23564
|
console.error(
|
|
23118
|
-
`${
|
|
23565
|
+
`${TAG43} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
23119
23566
|
);
|
|
23120
23567
|
return [];
|
|
23121
23568
|
}
|
|
@@ -23143,8 +23590,8 @@ function composeInitialMessage(input) {
|
|
|
23143
23590
|
].join("\n");
|
|
23144
23591
|
}
|
|
23145
23592
|
async function dispatchReviewer(input, initialMessage) {
|
|
23146
|
-
const sessionId =
|
|
23147
|
-
console.log(`${
|
|
23593
|
+
const sessionId = randomUUID14();
|
|
23594
|
+
console.log(`${TAG43} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
23148
23595
|
const spawned = await managerRcSpawn({
|
|
23149
23596
|
sessionId,
|
|
23150
23597
|
initialMessage,
|
|
@@ -23164,21 +23611,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
23164
23611
|
const dispatchedAt = Date.now();
|
|
23165
23612
|
if (consumed.has(input.sessionId)) {
|
|
23166
23613
|
console.log(
|
|
23167
|
-
`${
|
|
23614
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
23168
23615
|
);
|
|
23169
23616
|
return;
|
|
23170
23617
|
}
|
|
23171
23618
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
23172
23619
|
if (!jsonl) {
|
|
23173
23620
|
console.log(
|
|
23174
|
-
`${
|
|
23621
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
23175
23622
|
);
|
|
23176
23623
|
return;
|
|
23177
23624
|
}
|
|
23178
23625
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
23179
23626
|
if (operatorTurns === 0) {
|
|
23180
23627
|
console.log(
|
|
23181
|
-
`${
|
|
23628
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
23182
23629
|
);
|
|
23183
23630
|
return;
|
|
23184
23631
|
}
|
|
@@ -23192,19 +23639,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
23192
23639
|
});
|
|
23193
23640
|
if (!consumeOnce(input.sessionId)) {
|
|
23194
23641
|
console.log(
|
|
23195
|
-
`${
|
|
23642
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
23196
23643
|
);
|
|
23197
23644
|
return;
|
|
23198
23645
|
}
|
|
23199
23646
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
23200
23647
|
if (!dispatched.ok) {
|
|
23201
23648
|
console.error(
|
|
23202
|
-
`${
|
|
23649
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
23203
23650
|
);
|
|
23204
23651
|
return;
|
|
23205
23652
|
}
|
|
23206
23653
|
console.log(
|
|
23207
|
-
`${
|
|
23654
|
+
`${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
23208
23655
|
);
|
|
23209
23656
|
}
|
|
23210
23657
|
|
|
@@ -23619,7 +24066,7 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
23619
24066
|
function isPublicHost(host) {
|
|
23620
24067
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
23621
24068
|
}
|
|
23622
|
-
var
|
|
24069
|
+
var app60 = new Hono();
|
|
23623
24070
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
23624
24071
|
async function fetchAccountStandingRules(accountId) {
|
|
23625
24072
|
const session = getSession();
|
|
@@ -23635,6 +24082,26 @@ async function fetchAccountStandingRules(accountId) {
|
|
|
23635
24082
|
await session.close();
|
|
23636
24083
|
}
|
|
23637
24084
|
}
|
|
24085
|
+
async function recordPassiveDispatch(input) {
|
|
24086
|
+
const session = getSession();
|
|
24087
|
+
try {
|
|
24088
|
+
await session.run(
|
|
24089
|
+
`CREATE (d:PassiveDispatch {
|
|
24090
|
+
accountId: $accountId,
|
|
24091
|
+
sessionId: $sessionId,
|
|
24092
|
+
msgId: $msgId,
|
|
24093
|
+
dispatchedAt: $dispatchedAt
|
|
24094
|
+
})`,
|
|
24095
|
+
{ ...input, dispatchedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
24096
|
+
);
|
|
24097
|
+
} catch (err) {
|
|
24098
|
+
console.error(
|
|
24099
|
+
`[wa-passive] op=ledger-write-failed account=${input.accountId} sessionId=${input.sessionId} error=${err instanceof Error ? err.message : String(err)}`
|
|
24100
|
+
);
|
|
24101
|
+
} finally {
|
|
24102
|
+
await session.close();
|
|
24103
|
+
}
|
|
24104
|
+
}
|
|
23638
24105
|
var waGateway = new WaGateway({
|
|
23639
24106
|
fetchStandingRules: fetchAccountStandingRules,
|
|
23640
24107
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
@@ -23657,7 +24124,7 @@ var waGateway = new WaGateway({
|
|
|
23657
24124
|
});
|
|
23658
24125
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
23659
24126
|
},
|
|
23660
|
-
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId }) => {
|
|
24127
|
+
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, sessionIdOverride }) => {
|
|
23661
24128
|
if (passive) {
|
|
23662
24129
|
const phoneHash = createHash6("sha256").update(senderId).digest("hex").slice(0, 12);
|
|
23663
24130
|
const prompt = (text ?? "").trim();
|
|
@@ -23665,7 +24132,17 @@ var waGateway = new WaGateway({
|
|
|
23665
24132
|
console.error(`[wa-passive] op=dropped account=${effectiveAccountId} phoneHash=${phoneHash} msgId=${msgId ?? "none"} reason=empty-text`);
|
|
23666
24133
|
return;
|
|
23667
24134
|
}
|
|
23668
|
-
|
|
24135
|
+
let raisedByPersonId;
|
|
24136
|
+
try {
|
|
24137
|
+
raisedByPersonId = await ensureManagerPerson(effectiveAccountId, senderId) ?? void 0;
|
|
24138
|
+
} catch (err) {
|
|
24139
|
+
console.error(`[wa-passive] op=raised-by-error account=${effectiveAccountId} phoneHash=${phoneHash} msgId=${msgId ?? "none"} error=${err instanceof Error ? err.message : String(err)}`);
|
|
24140
|
+
}
|
|
24141
|
+
if (!raisedByPersonId) {
|
|
24142
|
+
console.error(`[wa-passive] op=dropped account=${effectiveAccountId} phoneHash=${phoneHash} msgId=${msgId ?? "none"} reason=raised-by-unresolved`);
|
|
24143
|
+
return;
|
|
24144
|
+
}
|
|
24145
|
+
console.error(`[wa-passive] op=dispatch account=${effectiveAccountId} phoneHash=${phoneHash} msgId=${msgId ?? "none"} raisedBy=${raisedByPersonId}`);
|
|
23669
24146
|
const result2 = await managerSpawn({
|
|
23670
24147
|
senderId,
|
|
23671
24148
|
role: "public",
|
|
@@ -23674,18 +24151,28 @@ var waGateway = new WaGateway({
|
|
|
23674
24151
|
targetAccountId: effectiveAccountId,
|
|
23675
24152
|
agentSlug: "passive",
|
|
23676
24153
|
initialMessage: prompt,
|
|
23677
|
-
passive: true
|
|
24154
|
+
passive: true,
|
|
24155
|
+
// Task 1493 — the manager's elementId rides the personId field
|
|
24156
|
+
// end-to-end (managerSpawn → /public-spawn → spawn args → work env as
|
|
24157
|
+
// RAISED_BY_PERSON_ID). It is also this passive session's identity.
|
|
24158
|
+
personId: raisedByPersonId
|
|
23678
24159
|
});
|
|
23679
24160
|
if ("error" in result2) {
|
|
23680
24161
|
console.error(`[wa-passive] op=dispatch-failed account=${effectiveAccountId} msgId=${msgId ?? "none"} error=${result2.error}`);
|
|
24162
|
+
return;
|
|
23681
24163
|
}
|
|
24164
|
+
await recordPassiveDispatch({
|
|
24165
|
+
accountId: effectiveAccountId,
|
|
24166
|
+
sessionId: result2.sessionId,
|
|
24167
|
+
msgId: msgId ?? ""
|
|
24168
|
+
});
|
|
23682
24169
|
return;
|
|
23683
24170
|
}
|
|
23684
24171
|
if (role === "admin") {
|
|
23685
24172
|
const managesAccount = effectiveAccountId !== accountId ? effectiveAccountId : "none";
|
|
23686
24173
|
console.error(`[whatsapp-native] op=account-manager-route senderId=${senderId} managesAccount=${managesAccount} effectiveAccount=${effectiveAccountId} source=gate`);
|
|
23687
24174
|
}
|
|
23688
|
-
const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath });
|
|
24175
|
+
const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, sessionIdOverride });
|
|
23689
24176
|
const userId = role === "admin" ? resolveAdminUserId({ accountId: effectiveAccountId, senderPhone: senderId }) ?? void 0 : void 0;
|
|
23690
24177
|
if (role === "admin") {
|
|
23691
24178
|
console.error(`[whatsapp-native] op=admin-identity senderId=${senderId} userId=${userId ?? "owner-fallback"}`);
|
|
@@ -23714,7 +24201,7 @@ var waGateway = new WaGateway({
|
|
|
23714
24201
|
nativeFileFollowers.set(senderId, ac);
|
|
23715
24202
|
}
|
|
23716
24203
|
});
|
|
23717
|
-
|
|
24204
|
+
app60.route("/", waGateway.routes());
|
|
23718
24205
|
waGateway.startSweeper();
|
|
23719
24206
|
var webchatGateway = new WebchatGateway({
|
|
23720
24207
|
fetchStandingRules: fetchAccountStandingRules,
|
|
@@ -23798,7 +24285,7 @@ var webchatGateway = new WebchatGateway({
|
|
|
23798
24285
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
23799
24286
|
});
|
|
23800
24287
|
setWebchatGateway(webchatGateway);
|
|
23801
|
-
|
|
24288
|
+
app60.route("/", webchatGateway.routes());
|
|
23802
24289
|
webchatGateway.startSweeper();
|
|
23803
24290
|
webchatGateway.startPublicReaper();
|
|
23804
24291
|
var telegramFileFollowers = /* @__PURE__ */ new Map();
|
|
@@ -23806,8 +24293,8 @@ var telegramGateway = new TelegramGateway({
|
|
|
23806
24293
|
fetchStandingRules: fetchAccountStandingRules,
|
|
23807
24294
|
gatewayUrl: telegramGatewayUrl(),
|
|
23808
24295
|
serverPath: telegramServerPath(),
|
|
23809
|
-
ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath }) => {
|
|
23810
|
-
const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath });
|
|
24296
|
+
ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath, sessionIdOverride }) => {
|
|
24297
|
+
const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath, sessionIdOverride });
|
|
23811
24298
|
const result = await managerRcSpawn(req);
|
|
23812
24299
|
if ("error" in result) {
|
|
23813
24300
|
console.error(`[telegram-native] spawn-failed senderId=${senderId} role=${role} error=${result.error} status=${result.status}`);
|
|
@@ -23832,7 +24319,7 @@ var telegramGateway = new TelegramGateway({
|
|
|
23832
24319
|
}
|
|
23833
24320
|
});
|
|
23834
24321
|
setTelegramGateway(telegramGateway);
|
|
23835
|
-
|
|
24322
|
+
app60.route("/", telegramGateway.routes());
|
|
23836
24323
|
telegramGateway.startSweeper();
|
|
23837
24324
|
var chatRoutes = createChatRoutes({
|
|
23838
24325
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
@@ -23865,19 +24352,19 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
23865
24352
|
return managed.account;
|
|
23866
24353
|
}
|
|
23867
24354
|
});
|
|
23868
|
-
|
|
23869
|
-
|
|
24355
|
+
app60.route("/api/channel/schedule-inject", scheduleInjectRoutes);
|
|
24356
|
+
app60.use("*", clientIpMiddleware);
|
|
23870
24357
|
function allowsSameOriginFraming(path2) {
|
|
23871
24358
|
return path2 === "/vnc-viewer.html" || path2.startsWith("/api/admin/attachment/") || path2.startsWith("/api/public-reader/attachment/") || path2 === "/api/admin/files/download";
|
|
23872
24359
|
}
|
|
23873
|
-
|
|
24360
|
+
app60.use("*", async (c, next) => {
|
|
23874
24361
|
await next();
|
|
23875
24362
|
c.header("X-Content-Type-Options", "nosniff");
|
|
23876
24363
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
23877
24364
|
c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
|
|
23878
24365
|
});
|
|
23879
24366
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
23880
|
-
|
|
24367
|
+
app60.use("*", async (c, next) => {
|
|
23881
24368
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
23882
24369
|
await next();
|
|
23883
24370
|
return;
|
|
@@ -23895,7 +24382,7 @@ app56.use("*", async (c, next) => {
|
|
|
23895
24382
|
});
|
|
23896
24383
|
}
|
|
23897
24384
|
});
|
|
23898
|
-
|
|
24385
|
+
app60.use("*", async (c, next) => {
|
|
23899
24386
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
23900
24387
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
23901
24388
|
await next();
|
|
@@ -23933,7 +24420,7 @@ function resolveRemoteAuthOpts(c) {
|
|
|
23933
24420
|
return { ...brandLoginOpts, origin };
|
|
23934
24421
|
}
|
|
23935
24422
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
23936
|
-
|
|
24423
|
+
app60.post("/__remote-auth/login", async (c) => {
|
|
23937
24424
|
const client = clientFrom(c);
|
|
23938
24425
|
const clientIp = client.ip || "unknown";
|
|
23939
24426
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -23978,7 +24465,7 @@ app56.post("/__remote-auth/login", async (c) => {
|
|
|
23978
24465
|
}
|
|
23979
24466
|
});
|
|
23980
24467
|
});
|
|
23981
|
-
|
|
24468
|
+
app60.get("/__remote-auth/logout", (c) => {
|
|
23982
24469
|
const client = clientFrom(c);
|
|
23983
24470
|
const clientIp = client.ip || "unknown";
|
|
23984
24471
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -23991,7 +24478,7 @@ app56.get("/__remote-auth/logout", (c) => {
|
|
|
23991
24478
|
}
|
|
23992
24479
|
});
|
|
23993
24480
|
});
|
|
23994
|
-
|
|
24481
|
+
app60.post("/__remote-auth/change-password", async (c) => {
|
|
23995
24482
|
const client = clientFrom(c);
|
|
23996
24483
|
const clientIp = client.ip || "unknown";
|
|
23997
24484
|
const rateLimited = checkRateLimit(client);
|
|
@@ -24050,13 +24537,13 @@ app56.post("/__remote-auth/change-password", async (c) => {
|
|
|
24050
24537
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
24051
24538
|
}
|
|
24052
24539
|
});
|
|
24053
|
-
|
|
24540
|
+
app60.get("/__remote-auth/setup", (c) => {
|
|
24054
24541
|
if (isRemoteAuthConfigured()) {
|
|
24055
24542
|
return c.redirect("/");
|
|
24056
24543
|
}
|
|
24057
24544
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
|
|
24058
24545
|
});
|
|
24059
|
-
|
|
24546
|
+
app60.post("/__remote-auth/set-initial-password", async (c) => {
|
|
24060
24547
|
if (isRemoteAuthConfigured()) {
|
|
24061
24548
|
return c.redirect("/");
|
|
24062
24549
|
}
|
|
@@ -24094,10 +24581,10 @@ app56.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
24094
24581
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
24095
24582
|
}
|
|
24096
24583
|
});
|
|
24097
|
-
|
|
24584
|
+
app60.get("/api/remote-auth/status", (c) => {
|
|
24098
24585
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
24099
24586
|
});
|
|
24100
|
-
|
|
24587
|
+
app60.post("/api/remote-auth/set-password", async (c) => {
|
|
24101
24588
|
let body;
|
|
24102
24589
|
try {
|
|
24103
24590
|
body = await c.req.json();
|
|
@@ -24136,10 +24623,10 @@ app56.post("/api/remote-auth/set-password", async (c) => {
|
|
|
24136
24623
|
return c.json({ error: "Failed to save password" }, 500);
|
|
24137
24624
|
}
|
|
24138
24625
|
});
|
|
24139
|
-
|
|
24626
|
+
app60.route("/api/_client-error", client_error_default);
|
|
24140
24627
|
console.log("[client-error-route] mounted");
|
|
24141
24628
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
24142
|
-
|
|
24629
|
+
app60.use("*", async (c, next) => {
|
|
24143
24630
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24144
24631
|
const path2 = c.req.path;
|
|
24145
24632
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
|
|
@@ -24183,26 +24670,26 @@ app56.use("*", async (c, next) => {
|
|
|
24183
24670
|
}
|
|
24184
24671
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path2 }), 200);
|
|
24185
24672
|
});
|
|
24186
|
-
|
|
24187
|
-
|
|
24188
|
-
|
|
24189
|
-
|
|
24190
|
-
|
|
24191
|
-
|
|
24673
|
+
app60.route("/api/health", health_default);
|
|
24674
|
+
app60.route("/api/chat", chatRoutes);
|
|
24675
|
+
app60.route("/api/whatsapp", whatsapp_default);
|
|
24676
|
+
app60.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
24677
|
+
app60.route("/api/public-reader", public_reader_default);
|
|
24678
|
+
app60.route("/api/webchat", createWebchatRoutes({
|
|
24192
24679
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
24193
24680
|
// Task 940 — the permission relay's pointer read + verdict write.
|
|
24194
24681
|
pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
|
|
24195
24682
|
deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
|
|
24196
24683
|
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
24197
24684
|
}));
|
|
24198
|
-
|
|
24199
|
-
|
|
24200
|
-
|
|
24201
|
-
|
|
24202
|
-
|
|
24203
|
-
|
|
24204
|
-
|
|
24205
|
-
|
|
24685
|
+
app60.route("/api/webchat/greeting", webchat_greeting_default);
|
|
24686
|
+
app60.route("/api/telegram", telegram_default);
|
|
24687
|
+
app60.route("/api/quickbooks", quickbooks_default);
|
|
24688
|
+
app60.route("/api/onboarding", onboarding_default);
|
|
24689
|
+
app60.route("/api/admin", admin_default);
|
|
24690
|
+
app60.route("/api/access", access_default);
|
|
24691
|
+
app60.route("/api/session", session_default2);
|
|
24692
|
+
app60.route("/api/calendar", calendar_public_default);
|
|
24206
24693
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
24207
24694
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
24208
24695
|
var IMAGE_MIME = {
|
|
@@ -24214,7 +24701,7 @@ var IMAGE_MIME = {
|
|
|
24214
24701
|
".svg": "image/svg+xml",
|
|
24215
24702
|
".ico": "image/x-icon"
|
|
24216
24703
|
};
|
|
24217
|
-
|
|
24704
|
+
app60.get("/agent-assets/:slug/:filename", (c) => {
|
|
24218
24705
|
const slug = c.req.param("slug");
|
|
24219
24706
|
const filename = c.req.param("filename");
|
|
24220
24707
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -24249,7 +24736,7 @@ app56.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
24249
24736
|
"Cache-Control": "public, max-age=3600"
|
|
24250
24737
|
});
|
|
24251
24738
|
});
|
|
24252
|
-
|
|
24739
|
+
app60.get("/generated/:filename", (c) => {
|
|
24253
24740
|
const filename = c.req.param("filename");
|
|
24254
24741
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
24255
24742
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -24279,10 +24766,10 @@ app56.get("/generated/:filename", (c) => {
|
|
|
24279
24766
|
"Cache-Control": "public, max-age=86400"
|
|
24280
24767
|
});
|
|
24281
24768
|
});
|
|
24282
|
-
|
|
24283
|
-
|
|
24284
|
-
|
|
24285
|
-
|
|
24769
|
+
app60.route("/sites", sites_default);
|
|
24770
|
+
app60.route("/listings", listings_default);
|
|
24771
|
+
app60.route("/v", visitor_event_default);
|
|
24772
|
+
app60.route("/v", visitor_consent_default);
|
|
24286
24773
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
24287
24774
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
24288
24775
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -24437,7 +24924,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
24437
24924
|
function agentUnavailableHtml() {
|
|
24438
24925
|
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>`;
|
|
24439
24926
|
}
|
|
24440
|
-
|
|
24927
|
+
app60.get("/", (c) => {
|
|
24441
24928
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24442
24929
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
24443
24930
|
if (klass === "operator") {
|
|
@@ -24459,12 +24946,12 @@ app56.get("/", (c) => {
|
|
|
24459
24946
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
24460
24947
|
return c.html(cachedHtml("index.html"));
|
|
24461
24948
|
});
|
|
24462
|
-
|
|
24949
|
+
app60.get("/public", (c) => {
|
|
24463
24950
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24464
24951
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24465
24952
|
return c.html(cachedHtml("public.html"));
|
|
24466
24953
|
});
|
|
24467
|
-
|
|
24954
|
+
app60.get("/public-chat", (c) => {
|
|
24468
24955
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24469
24956
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24470
24957
|
return c.html(cachedHtml("public.html"));
|
|
@@ -24483,9 +24970,9 @@ async function logViewerFetch(c, next) {
|
|
|
24483
24970
|
duration_ms: Date.now() - start
|
|
24484
24971
|
});
|
|
24485
24972
|
}
|
|
24486
|
-
|
|
24487
|
-
|
|
24488
|
-
|
|
24973
|
+
app60.use("/vnc-viewer.html", logViewerFetch);
|
|
24974
|
+
app60.use("/vnc-popout.html", logViewerFetch);
|
|
24975
|
+
app60.get("/vnc-popout.html", (c) => {
|
|
24489
24976
|
let html = htmlCache.get("vnc-popout.html");
|
|
24490
24977
|
if (!html) {
|
|
24491
24978
|
html = readFileSync35(resolve33(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
@@ -24498,7 +24985,7 @@ app56.get("/vnc-popout.html", (c) => {
|
|
|
24498
24985
|
}
|
|
24499
24986
|
return c.html(html);
|
|
24500
24987
|
});
|
|
24501
|
-
|
|
24988
|
+
app60.post("/api/vnc/client-event", async (c) => {
|
|
24502
24989
|
let body;
|
|
24503
24990
|
try {
|
|
24504
24991
|
body = await c.req.json();
|
|
@@ -24519,11 +25006,11 @@ app56.post("/api/vnc/client-event", async (c) => {
|
|
|
24519
25006
|
});
|
|
24520
25007
|
return c.json({ ok: true });
|
|
24521
25008
|
});
|
|
24522
|
-
|
|
25009
|
+
app60.get("/g/:slug", (c) => {
|
|
24523
25010
|
return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
|
|
24524
25011
|
});
|
|
24525
25012
|
for (const pwa of PWA_SURFACES) {
|
|
24526
|
-
|
|
25013
|
+
app60.get(pwa.manifestPath, (c) => {
|
|
24527
25014
|
const manifest = buildManifest(pwa, {
|
|
24528
25015
|
productName: BRAND.productName,
|
|
24529
25016
|
appIcon192: brandAppIcon192Path,
|
|
@@ -24539,7 +25026,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
24539
25026
|
return c.body(JSON.stringify(manifest));
|
|
24540
25027
|
});
|
|
24541
25028
|
}
|
|
24542
|
-
|
|
25029
|
+
app60.get("/sw.js", (c) => {
|
|
24543
25030
|
if (SW_SOURCE == null) {
|
|
24544
25031
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
24545
25032
|
return c.text("Service worker unavailable", 500);
|
|
@@ -24548,12 +25035,12 @@ app56.get("/sw.js", (c) => {
|
|
|
24548
25035
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
24549
25036
|
return c.body(SW_SOURCE);
|
|
24550
25037
|
});
|
|
24551
|
-
|
|
25038
|
+
app60.get("/graph", (c) => {
|
|
24552
25039
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24553
25040
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
24554
25041
|
return c.html(cachedHtml("graph.html"));
|
|
24555
25042
|
});
|
|
24556
|
-
|
|
25043
|
+
app60.get("/chat", (c) => {
|
|
24557
25044
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24558
25045
|
if (isOperatorHost(host, getOperatorDomains())) {
|
|
24559
25046
|
console.log(`[host-class] host=${host} class=operator served=operator.html`);
|
|
@@ -24562,22 +25049,22 @@ app56.get("/chat", (c) => {
|
|
|
24562
25049
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24563
25050
|
return c.html(cachedHtml("chat.html"));
|
|
24564
25051
|
});
|
|
24565
|
-
|
|
25052
|
+
app60.get("/data", (c) => {
|
|
24566
25053
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24567
25054
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24568
25055
|
return c.html(cachedHtml("data.html"));
|
|
24569
25056
|
});
|
|
24570
|
-
|
|
25057
|
+
app60.get("/calendar", (c) => {
|
|
24571
25058
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24572
25059
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
24573
25060
|
return c.html(cachedHtml("calendar.html"));
|
|
24574
25061
|
});
|
|
24575
|
-
|
|
25062
|
+
app60.get("/browser", (c) => {
|
|
24576
25063
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24577
25064
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
24578
25065
|
return c.html(cachedHtml("browser.html"));
|
|
24579
25066
|
});
|
|
24580
|
-
|
|
25067
|
+
app60.get("/:slug", async (c, next) => {
|
|
24581
25068
|
const slug = c.req.param("slug");
|
|
24582
25069
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
24583
25070
|
const account = resolveAccount();
|
|
@@ -24592,13 +25079,13 @@ app56.get("/:slug", async (c, next) => {
|
|
|
24592
25079
|
await next();
|
|
24593
25080
|
});
|
|
24594
25081
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
24595
|
-
|
|
25082
|
+
app60.get("/favicon.ico", (c) => {
|
|
24596
25083
|
c.header("Cache-Control", "public, max-age=300");
|
|
24597
25084
|
return c.redirect(brandFaviconPath, 302);
|
|
24598
25085
|
});
|
|
24599
25086
|
}
|
|
24600
|
-
|
|
24601
|
-
|
|
25087
|
+
app60.use("/*", serveStatic({ root: "./public" }));
|
|
25088
|
+
app60.all("*", (c) => {
|
|
24602
25089
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
24603
25090
|
const path2 = c.req.path;
|
|
24604
25091
|
if (isPublicHost(host)) {
|
|
@@ -24612,7 +25099,7 @@ app56.all("*", (c) => {
|
|
|
24612
25099
|
});
|
|
24613
25100
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
24614
25101
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
24615
|
-
var httpServer = serve({ fetch:
|
|
25102
|
+
var httpServer = serve({ fetch: app60.fetch, port, hostname });
|
|
24616
25103
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
24617
25104
|
{
|
|
24618
25105
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join35(__dirname, "..");
|
|
@@ -24636,6 +25123,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
24636
25123
|
const loop = setInterval(runReconcile, RECONCILE_INTERVAL_MS);
|
|
24637
25124
|
loop.unref();
|
|
24638
25125
|
}
|
|
25126
|
+
startTimeEntryCensus(() => getSession());
|
|
24639
25127
|
{
|
|
24640
25128
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join35(__dirname, "..");
|
|
24641
25129
|
const auditScript = resolve33(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
@@ -24712,7 +25200,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
24712
25200
|
}
|
|
24713
25201
|
try {
|
|
24714
25202
|
const registered = [];
|
|
24715
|
-
for (const r of
|
|
25203
|
+
for (const r of app60.routes ?? []) {
|
|
24716
25204
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
24717
25205
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
24718
25206
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|