@rubytech/create-maxy-code 0.1.601 → 0.1.603
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 +7 -0
- package/payload/platform/plugins/admin/hooks/video-frames-inject.sh +141 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +19 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +12 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
- package/payload/platform/plugins/docs/references/telegram-guide.md +16 -0
- package/payload/platform/plugins/scheduling/PLUGIN.md +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js +67 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js +89 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.js +160 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js +16 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts +31 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +42 -4
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.d.ts +101 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.js +130 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts +10 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts +24 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js +89 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +67 -1
- 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__/gate-dispatch-wiring.test.js +31 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +10 -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 +46 -1
- 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 +72 -4
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +81 -4
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +50 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +48 -7
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
- package/payload/platform/plugins/telegram/PLUGIN.md +4 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.js +33 -1
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.js +166 -1
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/index.js +39 -14
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.d.ts +95 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.d.ts.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.js +125 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.js.map +1 -1
- package/payload/platform/plugins/telegram/skills/configure/SKILL.md +15 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +6 -0
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +12 -5
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +5 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +9 -3
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/templates/account-settings.json +6 -0
- package/payload/server/chunk-CYU75QAV.js +377 -0
- package/payload/server/{chunk-34FPJYHN.js → chunk-GI5AVCRG.js} +87 -146
- package/payload/server/chunk-KUVNCAE4.js +77 -0
- package/payload/server/{manager-7BXVB76I.js → manager-VDHT3YYI.js} +2 -1
- package/payload/server/maxy-edge.js +33 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/agents.html +5 -5
- package/payload/server/public/assets/{AdminLoginScreens-B3W6J6Bl.js → AdminLoginScreens-DI5bNlX8.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-C3R-vMZ5.js → AdminShell-B-iX9ahJ.js} +1 -1
- package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.br +0 -0
- package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.gz +0 -0
- package/payload/server/public/assets/{activity-tzv68iBs.js → activity-CqgFwANo.js} +1 -1
- package/payload/server/public/assets/activity-CqgFwANo.js.br +0 -0
- package/payload/server/public/assets/activity-CqgFwANo.js.gz +0 -0
- package/payload/server/public/assets/admin-K63n6ybW.js +1 -0
- package/payload/server/public/assets/admin-K63n6ybW.js.br +0 -0
- package/payload/server/public/assets/admin-K63n6ybW.js.gz +0 -0
- package/payload/server/public/assets/{agents-DUZfeY3X.js → agents-cue5Zf8X.js} +1 -1
- package/payload/server/public/assets/agents-cue5Zf8X.js.br +0 -0
- package/payload/server/public/assets/agents-cue5Zf8X.js.gz +0 -0
- package/payload/server/public/assets/{browser-DwLaXqjO.js → browser-CqDBcKwU.js} +1 -1
- package/payload/server/public/assets/browser-CqDBcKwU.js.br +0 -0
- package/payload/server/public/assets/browser-CqDBcKwU.js.gz +0 -0
- package/payload/server/public/assets/{calendar-Cli8Qjl9.js → calendar-BgzuW5Rt.js} +1 -1
- package/payload/server/public/assets/calendar-BgzuW5Rt.js.br +0 -0
- package/payload/server/public/assets/calendar-BgzuW5Rt.js.gz +0 -0
- package/payload/server/public/assets/chat-HYZViu2u.js +1 -0
- package/payload/server/public/assets/chat-HYZViu2u.js.br +3 -0
- package/payload/server/public/assets/chat-HYZViu2u.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-C5FXH9r_.js +1 -0
- package/payload/server/public/assets/chevron-left-C5FXH9r_.js.br +0 -0
- package/payload/server/public/assets/clock-DxPtyejC.js +1 -0
- package/payload/server/public/assets/clock-DxPtyejC.js.br +0 -0
- package/payload/server/public/assets/clock-DxPtyejC.js.gz +0 -0
- package/payload/server/public/assets/{copy-yhhwfEbQ.js → copy-BNhZ0flH.js} +1 -1
- package/payload/server/public/assets/copy-BNhZ0flH.js.br +0 -0
- package/payload/server/public/assets/copy-BNhZ0flH.js.gz +0 -0
- package/payload/server/public/assets/data-kCBB8Z4Z.js +1 -0
- package/payload/server/public/assets/data-kCBB8Z4Z.js.br +0 -0
- package/payload/server/public/assets/data-kCBB8Z4Z.js.gz +0 -0
- package/payload/server/public/assets/{field-jg0YQNDy.js → field-X4OVA3vx.js} +1 -1
- package/payload/server/public/assets/field-X4OVA3vx.js.br +0 -0
- package/payload/server/public/assets/field-X4OVA3vx.js.gz +0 -0
- package/payload/server/public/assets/{file-text-D0EdW7h4.js → file-text-BddO_2EI.js} +1 -1
- package/payload/server/public/assets/file-text-BddO_2EI.js.br +0 -0
- package/payload/server/public/assets/file-text-BddO_2EI.js.gz +0 -0
- package/payload/server/public/assets/{graph--AUr4uBc.js → graph-l7tzHqvm.js} +1 -1
- package/payload/server/public/assets/graph-l7tzHqvm.js.br +0 -0
- package/payload/server/public/assets/graph-l7tzHqvm.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-DM0CiAX1.js → graph-labels-CtFFq5W2.js} +1 -1
- package/payload/server/public/assets/graph-labels-CtFFq5W2.js.br +0 -0
- package/payload/server/public/assets/graph-labels-CtFFq5W2.js.gz +0 -0
- package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css +1 -0
- package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css.br +0 -0
- package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css.gz +0 -0
- package/payload/server/public/assets/{operator-CNYKStFX.js → operator-Dg-dwf7a.js} +1 -1
- package/payload/server/public/assets/operator-Dg-dwf7a.js.br +7 -0
- package/payload/server/public/assets/operator-Dg-dwf7a.js.gz +0 -0
- package/payload/server/public/assets/page-Ci1bfIbs.js +1 -0
- package/payload/server/public/assets/page-Ci1bfIbs.js.br +0 -0
- package/payload/server/public/assets/page-Ci1bfIbs.js.gz +0 -0
- package/payload/server/public/assets/page-Y9JmFq0Q.js +32 -0
- package/payload/server/public/assets/page-Y9JmFq0Q.js.br +0 -0
- package/payload/server/public/assets/page-Y9JmFq0Q.js.gz +0 -0
- package/payload/server/public/assets/play-BSZVGpQT.js +1 -0
- package/payload/server/public/assets/play-BSZVGpQT.js.br +0 -0
- package/payload/server/public/assets/play-BSZVGpQT.js.gz +0 -0
- package/payload/server/public/assets/{public-7gXDqCog.js → public-m66FAza_.js} +1 -1
- package/payload/server/public/assets/public-m66FAza_.js.br +0 -0
- package/payload/server/public/assets/public-m66FAza_.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-DhqNTPpo.js → rotate-ccw-DTOJmOxB.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.gz +0 -0
- package/payload/server/public/assets/{routines-DN_yDtEj.js → routines-6fxZNacQ.js} +1 -1
- package/payload/server/public/assets/routines-6fxZNacQ.js.br +0 -0
- package/payload/server/public/assets/routines-6fxZNacQ.js.gz +0 -0
- package/payload/server/public/assets/{skills-pb_3BdOl.js → skills-51mqx-s5.js} +1 -1
- package/payload/server/public/assets/skills-51mqx-s5.js.br +0 -0
- package/payload/server/public/assets/skills-51mqx-s5.js.gz +0 -0
- package/payload/server/public/assets/{tasks-BQm4boat.js → tasks-D4y-Cwa3.js} +1 -1
- package/payload/server/public/assets/tasks-D4y-Cwa3.js.br +0 -0
- package/payload/server/public/assets/tasks-D4y-Cwa3.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-d7yjaIqv.js → triangle-alert-BzCjDFts.js} +1 -1
- package/payload/server/public/assets/triangle-alert-BzCjDFts.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-BzCjDFts.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-CZ6Qhfkj.js → useCopyFeedback-BG7h37Rx.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.br +2 -0
- package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.gz +0 -0
- package/payload/server/public/assets/{useMediaQuery-R1smYLx4.js → useMediaQuery-CqwktQr_.js} +1 -1
- package/payload/server/public/assets/useMediaQuery-CqwktQr_.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-CqwktQr_.js.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js +2 -0
- package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.gz +0 -0
- package/payload/server/public/assets/{wrench-DL1pbaCs.js → wrench-B2WKLLQG.js} +1 -1
- package/payload/server/public/assets/wrench-B2WKLLQG.js.br +0 -0
- package/payload/server/public/assets/wrench-B2WKLLQG.js.gz +0 -0
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +8 -8
- package/payload/server/public/chat.html +14 -14
- package/payload/server/public/data.html +12 -12
- package/payload/server/public/field.html +3 -3
- package/payload/server/public/graph.html +10 -10
- package/payload/server/public/index.html +14 -14
- package/payload/server/public/operator.html +15 -15
- package/payload/server/public/public.html +14 -14
- package/payload/server/public/routines.html +8 -8
- package/payload/server/public/skills.html +6 -6
- package/payload/server/public/tasks.html +7 -7
- package/payload/server/server.js +1067 -783
- package/payload/server/video-extract.js +36 -0
- package/payload/server/public/assets/AdminLoginScreens-B3W6J6Bl.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-B3W6J6Bl.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-C3R-vMZ5.js.br +0 -0
- package/payload/server/public/assets/AdminShell-C3R-vMZ5.js.gz +0 -0
- package/payload/server/public/assets/activity-tzv68iBs.js.br +0 -0
- package/payload/server/public/assets/activity-tzv68iBs.js.gz +0 -0
- package/payload/server/public/assets/admin-CzW_9jm3.js +0 -1
- package/payload/server/public/assets/admin-CzW_9jm3.js.br +0 -0
- package/payload/server/public/assets/admin-CzW_9jm3.js.gz +0 -0
- package/payload/server/public/assets/agents-DUZfeY3X.js.br +0 -0
- package/payload/server/public/assets/agents-DUZfeY3X.js.gz +0 -0
- package/payload/server/public/assets/browser-DwLaXqjO.js.br +0 -0
- package/payload/server/public/assets/browser-DwLaXqjO.js.gz +0 -0
- package/payload/server/public/assets/calendar-Cli8Qjl9.js.br +0 -0
- package/payload/server/public/assets/calendar-Cli8Qjl9.js.gz +0 -0
- package/payload/server/public/assets/chat-ByAgBgm1.js +0 -1
- package/payload/server/public/assets/chat-ByAgBgm1.js.br +0 -1
- package/payload/server/public/assets/chat-ByAgBgm1.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-BIYVnwvk.js +0 -1
- package/payload/server/public/assets/chevron-left-BIYVnwvk.js.br +0 -0
- package/payload/server/public/assets/clock-Dzy79hq3.js +0 -1
- package/payload/server/public/assets/clock-Dzy79hq3.js.br +0 -0
- package/payload/server/public/assets/clock-Dzy79hq3.js.gz +0 -0
- package/payload/server/public/assets/copy-yhhwfEbQ.js.br +0 -0
- package/payload/server/public/assets/copy-yhhwfEbQ.js.gz +0 -0
- package/payload/server/public/assets/data-CsMMki2A.js +0 -1
- package/payload/server/public/assets/data-CsMMki2A.js.br +0 -0
- package/payload/server/public/assets/data-CsMMki2A.js.gz +0 -0
- package/payload/server/public/assets/field-jg0YQNDy.js.br +0 -0
- package/payload/server/public/assets/field-jg0YQNDy.js.gz +0 -0
- package/payload/server/public/assets/file-text-D0EdW7h4.js.br +0 -0
- package/payload/server/public/assets/file-text-D0EdW7h4.js.gz +0 -0
- package/payload/server/public/assets/graph--AUr4uBc.js.br +0 -0
- package/payload/server/public/assets/graph--AUr4uBc.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-DM0CiAX1.js.br +0 -0
- package/payload/server/public/assets/graph-labels-DM0CiAX1.js.gz +0 -0
- package/payload/server/public/assets/jsx-runtime-lfcjzaWi.css +0 -1
- package/payload/server/public/assets/jsx-runtime-lfcjzaWi.css.br +0 -0
- package/payload/server/public/assets/jsx-runtime-lfcjzaWi.css.gz +0 -0
- package/payload/server/public/assets/operator-CNYKStFX.js.br +0 -0
- package/payload/server/public/assets/operator-CNYKStFX.js.gz +0 -0
- package/payload/server/public/assets/page-DSsEpl8J.js +0 -32
- package/payload/server/public/assets/page-DSsEpl8J.js.br +0 -0
- package/payload/server/public/assets/page-DSsEpl8J.js.gz +0 -0
- package/payload/server/public/assets/page-DjhmwxnY.js +0 -1
- package/payload/server/public/assets/page-DjhmwxnY.js.br +0 -0
- package/payload/server/public/assets/page-DjhmwxnY.js.gz +0 -0
- package/payload/server/public/assets/play-DhZlml5b.js +0 -1
- package/payload/server/public/assets/play-DhZlml5b.js.br +0 -0
- package/payload/server/public/assets/play-DhZlml5b.js.gz +0 -0
- package/payload/server/public/assets/public-7gXDqCog.js.br +0 -0
- package/payload/server/public/assets/public-7gXDqCog.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-DhqNTPpo.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-DhqNTPpo.js.gz +0 -0
- package/payload/server/public/assets/routines-DN_yDtEj.js.br +0 -0
- package/payload/server/public/assets/routines-DN_yDtEj.js.gz +0 -0
- package/payload/server/public/assets/skills-pb_3BdOl.js.br +0 -0
- package/payload/server/public/assets/skills-pb_3BdOl.js.gz +0 -0
- package/payload/server/public/assets/tasks-BQm4boat.js.br +0 -0
- package/payload/server/public/assets/tasks-BQm4boat.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-d7yjaIqv.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-d7yjaIqv.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-CZ6Qhfkj.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-CZ6Qhfkj.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-R1smYLx4.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-R1smYLx4.js.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DM1v6sRa.js +0 -2
- package/payload/server/public/assets/useVoiceRecorder-DM1v6sRa.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DM1v6sRa.js.gz +0 -0
- package/payload/server/public/assets/wrench-DL1pbaCs.js.br +0 -0
- package/payload/server/public/assets/wrench-DL1pbaCs.js.gz +0 -0
- /package/payload/server/public/assets/{jsx-runtime-BtDK2X5t.js → jsx-runtime-UK6hgBWO.js} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-BtDK2X5t.js.br → jsx-runtime-UK6hgBWO.js.br} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-BtDK2X5t.js.gz → jsx-runtime-UK6hgBWO.js.gz} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -71,6 +71,11 @@ import {
|
|
|
71
71
|
vncLog,
|
|
72
72
|
walkPremiumBundles
|
|
73
73
|
} from "./chunk-MNN2RWJR.js";
|
|
74
|
+
import {
|
|
75
|
+
audioExtension,
|
|
76
|
+
isAudioMime,
|
|
77
|
+
isVideoMime
|
|
78
|
+
} from "./chunk-KUVNCAE4.js";
|
|
74
79
|
import {
|
|
75
80
|
ACCOUNTS_ROOT,
|
|
76
81
|
DATA_ROOT,
|
|
@@ -210,13 +215,12 @@ import {
|
|
|
210
215
|
storeMediaBuffer,
|
|
211
216
|
storePublicAttachment,
|
|
212
217
|
toWhatsappJid,
|
|
213
|
-
transcribe,
|
|
214
218
|
validateAccountIdEnv,
|
|
215
219
|
validateFilePathInAccount,
|
|
216
220
|
waitForConnection,
|
|
217
221
|
warnNonUuidAccount,
|
|
218
222
|
writeChatMetadataMerged
|
|
219
|
-
} from "./chunk-
|
|
223
|
+
} from "./chunk-GI5AVCRG.js";
|
|
220
224
|
import {
|
|
221
225
|
ACCOUNTS_DIR,
|
|
222
226
|
AGENT_SLUG_PATTERN,
|
|
@@ -282,6 +286,10 @@ import {
|
|
|
282
286
|
verifyConversationOwnership,
|
|
283
287
|
writeAdminUserAndPerson
|
|
284
288
|
} from "./chunk-6AQYMT6C.js";
|
|
289
|
+
import {
|
|
290
|
+
extractVideo,
|
|
291
|
+
transcribe
|
|
292
|
+
} from "./chunk-CYU75QAV.js";
|
|
285
293
|
import {
|
|
286
294
|
D1_MAX_SQL_STATEMENT_BYTES,
|
|
287
295
|
D1_QUERY_MAX_BODY_BYTES,
|
|
@@ -604,8 +612,289 @@ var require_dist4 = __commonJS({
|
|
|
604
612
|
}
|
|
605
613
|
});
|
|
606
614
|
|
|
607
|
-
// ../lib/
|
|
615
|
+
// ../lib/graph-trash/dist/index.js
|
|
608
616
|
var require_dist5 = __commonJS({
|
|
617
|
+
"../lib/graph-trash/dist/index.js"(exports) {
|
|
618
|
+
"use strict";
|
|
619
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
620
|
+
exports.TRASH_METADATA_PROPS = void 0;
|
|
621
|
+
exports.trashNode = trashNode2;
|
|
622
|
+
exports.restoreNode = restoreNode2;
|
|
623
|
+
exports.emptyTrash = emptyTrash;
|
|
624
|
+
exports.notTrashed = notTrashed4;
|
|
625
|
+
exports.uniqueKeysForLabels = uniqueKeysForLabels;
|
|
626
|
+
var UNIQUE_KEYS_BY_LABEL2 = {
|
|
627
|
+
Person: ["email", "telephone"],
|
|
628
|
+
Service: ["serviceId"],
|
|
629
|
+
LocalBusiness: ["accountId"],
|
|
630
|
+
Task: ["taskId"],
|
|
631
|
+
Event: ["eventId"],
|
|
632
|
+
// :KnowledgeDocument is keyed on `attachmentId` (document writer path —
|
|
633
|
+
// file/URL/obsidian/contract attachment + legacy Gmail-thread shape under
|
|
634
|
+
// `source:'email'`). Task 397 split the conversation transcripts off into
|
|
635
|
+
// `:ConversationArchive`, which carries `conversationIdentity`.
|
|
636
|
+
KnowledgeDocument: ["attachmentId"],
|
|
637
|
+
ConversationArchive: ["conversationIdentity"],
|
|
638
|
+
DigitalDocument: ["attachmentId"],
|
|
639
|
+
Conversation: ["sessionId"],
|
|
640
|
+
Message: ["messageId"],
|
|
641
|
+
Workflow: ["workflowId"],
|
|
642
|
+
WorkflowStep: ["stepId"],
|
|
643
|
+
WorkflowRun: ["runId"],
|
|
644
|
+
Preference: ["preferenceId"],
|
|
645
|
+
Email: ["emailId", "messageId"],
|
|
646
|
+
AdminUser: ["userId"],
|
|
647
|
+
ToolCall: ["callId"],
|
|
648
|
+
// Composite component nulls — frees the composite constraint:
|
|
649
|
+
AccessGrant: ["contactValue"],
|
|
650
|
+
// composite (contactValue, agentSlug, accountId)
|
|
651
|
+
UserProfile: ["userId"]
|
|
652
|
+
// composite (accountId, userId)
|
|
653
|
+
};
|
|
654
|
+
var TRASH_PROP_NAMES = [
|
|
655
|
+
"trashedAt",
|
|
656
|
+
"trashedBy",
|
|
657
|
+
"trashReason",
|
|
658
|
+
"_trashedKeys"
|
|
659
|
+
];
|
|
660
|
+
async function trashNode2(params) {
|
|
661
|
+
const { session, accountId, elementId, by, reason } = params;
|
|
662
|
+
const lookup = await session.run(`MATCH (n) WHERE elementId(n) = $eid AND n.accountId = $accountId
|
|
663
|
+
RETURN labels(n) AS labels, properties(n) AS props`, { eid: elementId, accountId });
|
|
664
|
+
if (lookup.records.length === 0) {
|
|
665
|
+
throw new Error(`trashNode: node not found (elementId=${elementId} accountId=${accountId.slice(0, 8)}\u2026)`);
|
|
666
|
+
}
|
|
667
|
+
const allLabels = lookup.records[0].get("labels");
|
|
668
|
+
const props = lookup.records[0].get("props");
|
|
669
|
+
const baseLabels = allLabels.filter((l) => l !== "Trashed");
|
|
670
|
+
if (allLabels.includes("Trashed")) {
|
|
671
|
+
return {
|
|
672
|
+
trashed: false,
|
|
673
|
+
alreadyTrashed: true,
|
|
674
|
+
nodeId: elementId,
|
|
675
|
+
labels: baseLabels,
|
|
676
|
+
trashedAt: String(props.trashedAt ?? ""),
|
|
677
|
+
originalKeys: {}
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
681
|
+
for (const label of baseLabels) {
|
|
682
|
+
for (const key2 of UNIQUE_KEYS_BY_LABEL2[label] ?? [])
|
|
683
|
+
uniqueKeys.add(key2);
|
|
684
|
+
}
|
|
685
|
+
const originalKeys = {};
|
|
686
|
+
for (const k of uniqueKeys) {
|
|
687
|
+
if (props[k] !== void 0 && props[k] !== null)
|
|
688
|
+
originalKeys[k] = props[k];
|
|
689
|
+
}
|
|
690
|
+
const setNullClauses = Object.keys(originalKeys).map((k) => `n.\`${k}\` = null`).join(", ");
|
|
691
|
+
const setNullSuffix = setNullClauses ? `, ${setNullClauses}` : "";
|
|
692
|
+
const trashedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
693
|
+
const isConversation = baseLabels.includes("Conversation");
|
|
694
|
+
const messageUniqueKeys = UNIQUE_KEYS_BY_LABEL2["Message"] ?? [];
|
|
695
|
+
let cascadedMessageCount = 0;
|
|
696
|
+
await session.executeWrite(async (tx) => {
|
|
697
|
+
await tx.run(`MATCH (n) WHERE elementId(n) = $eid
|
|
698
|
+
SET n:Trashed,
|
|
699
|
+
n.trashedAt = datetime($trashedAt),
|
|
700
|
+
n.trashedBy = $by,
|
|
701
|
+
n.trashReason = $reason,
|
|
702
|
+
n._trashedKeys = $trashedKeysJson${setNullSuffix}`, {
|
|
703
|
+
eid: elementId,
|
|
704
|
+
trashedAt,
|
|
705
|
+
by,
|
|
706
|
+
reason: reason ?? null,
|
|
707
|
+
trashedKeysJson: JSON.stringify(originalKeys)
|
|
708
|
+
});
|
|
709
|
+
if (isConversation) {
|
|
710
|
+
const collectKeys = messageUniqueKeys.length > 0 ? messageUniqueKeys.map((k) => `\`${k}\`: m.\`${k}\``).join(", ") : "";
|
|
711
|
+
const collectMsgProps = collectKeys ? `, {${collectKeys}}` : ", {}";
|
|
712
|
+
const collected = await tx.run(`MATCH (c) WHERE elementId(c) = $eid
|
|
713
|
+
MATCH (m:Message)-[:PART_OF]->(c)
|
|
714
|
+
WHERE NOT m:Trashed
|
|
715
|
+
RETURN elementId(m) AS meid${collectMsgProps} AS keys`, { eid: elementId });
|
|
716
|
+
for (const rec of collected.records) {
|
|
717
|
+
const meid = rec.get("meid");
|
|
718
|
+
const keys = rec.get("keys");
|
|
719
|
+
const liveKeys = {};
|
|
720
|
+
for (const k of messageUniqueKeys) {
|
|
721
|
+
if (keys[k] !== void 0 && keys[k] !== null)
|
|
722
|
+
liveKeys[k] = keys[k];
|
|
723
|
+
}
|
|
724
|
+
const msgSetNulls = Object.keys(liveKeys).length > 0 ? ", " + Object.keys(liveKeys).map((k) => `m.\`${k}\` = null`).join(", ") : "";
|
|
725
|
+
await tx.run(`MATCH (m) WHERE elementId(m) = $meid
|
|
726
|
+
SET m:Trashed,
|
|
727
|
+
m.trashedAt = datetime($trashedAt),
|
|
728
|
+
m.trashedBy = $by,
|
|
729
|
+
m.trashReason = $reason,
|
|
730
|
+
m._trashedKeys = $trashedKeysJson${msgSetNulls}`, {
|
|
731
|
+
meid,
|
|
732
|
+
trashedAt,
|
|
733
|
+
by: `${by}:cascade-from-conversation`,
|
|
734
|
+
reason: reason ?? `cascade from Conversation ${elementId}`,
|
|
735
|
+
trashedKeysJson: JSON.stringify(liveKeys)
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
cascadedMessageCount = collected.records.length;
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
process.stderr.write(`[trash:marked] accountId=${accountId} elementId=${elementId} labels=${baseLabels.join(",")} by=${by} reason=${reason ?? "null"}
|
|
742
|
+
`);
|
|
743
|
+
if (isConversation) {
|
|
744
|
+
process.stderr.write(`[trash:cascaded] accountId=${accountId} conversationElementId=${elementId} messageCount=${cascadedMessageCount} by=${by}
|
|
745
|
+
`);
|
|
746
|
+
}
|
|
747
|
+
return {
|
|
748
|
+
trashed: true,
|
|
749
|
+
alreadyTrashed: false,
|
|
750
|
+
nodeId: elementId,
|
|
751
|
+
labels: baseLabels,
|
|
752
|
+
trashedAt,
|
|
753
|
+
originalKeys
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
async function restoreNode2(params) {
|
|
757
|
+
const { session, accountId, elementId } = params;
|
|
758
|
+
const lookup = await session.run(`MATCH (n:Trashed) WHERE elementId(n) = $eid
|
|
759
|
+
RETURN labels(n) AS labels, n._trashedKeys AS keysJson`, { eid: elementId });
|
|
760
|
+
if (lookup.records.length === 0) {
|
|
761
|
+
throw new Error(`restoreNode: trashed node not found (elementId=${elementId})`);
|
|
762
|
+
}
|
|
763
|
+
const allLabels = lookup.records[0].get("labels");
|
|
764
|
+
const baseLabels = allLabels.filter((l) => l !== "Trashed");
|
|
765
|
+
const keysJson = lookup.records[0].get("keysJson");
|
|
766
|
+
const originalKeys = keysJson ? JSON.parse(keysJson) : {};
|
|
767
|
+
for (const label of baseLabels) {
|
|
768
|
+
const uniqueKeys = UNIQUE_KEYS_BY_LABEL2[label] ?? [];
|
|
769
|
+
for (const k of uniqueKeys) {
|
|
770
|
+
const v = originalKeys[k];
|
|
771
|
+
if (v === void 0 || v === null)
|
|
772
|
+
continue;
|
|
773
|
+
const conflict = await session.run(`MATCH (other:\`${label}\`)
|
|
774
|
+
WHERE elementId(other) <> $eid
|
|
775
|
+
AND NOT other:Trashed
|
|
776
|
+
AND other.\`${k}\` = $val
|
|
777
|
+
RETURN elementId(other) AS otherId LIMIT 1`, { eid: elementId, val: v });
|
|
778
|
+
if (conflict.records.length > 0) {
|
|
779
|
+
const otherId = conflict.records[0].get("otherId");
|
|
780
|
+
throw new Error(`restoreNode: cannot restore ${label} elementId=${elementId} \u2014 active node elementId=${otherId} already holds ${k}=${JSON.stringify(v)}`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
const setClauses = Object.keys(originalKeys).map((k) => `n.\`${k}\` = $val_${k}`).join(", ");
|
|
785
|
+
const setSuffix = setClauses ? `, ${setClauses}` : "";
|
|
786
|
+
const setParams = { eid: elementId };
|
|
787
|
+
for (const [k, v] of Object.entries(originalKeys))
|
|
788
|
+
setParams[`val_${k}`] = v;
|
|
789
|
+
const isConversation = baseLabels.includes("Conversation");
|
|
790
|
+
let cascadedMessageCount = 0;
|
|
791
|
+
await session.executeWrite(async (tx) => {
|
|
792
|
+
await tx.run(`MATCH (n:Trashed) WHERE elementId(n) = $eid
|
|
793
|
+
REMOVE n:Trashed, n.trashedAt, n.trashedBy, n.trashReason, n._trashedKeys
|
|
794
|
+
SET n.restoredAt = datetime()${setSuffix}`, setParams);
|
|
795
|
+
if (isConversation) {
|
|
796
|
+
const collected = await tx.run(`MATCH (c) WHERE elementId(c) = $eid
|
|
797
|
+
MATCH (m:Trashed:Message)-[:PART_OF]->(c)
|
|
798
|
+
WHERE m.trashedBy ENDS WITH ':cascade-from-conversation'
|
|
799
|
+
RETURN elementId(m) AS meid, m._trashedKeys AS keysJson`, { eid: elementId });
|
|
800
|
+
for (const rec of collected.records) {
|
|
801
|
+
const meid = rec.get("meid");
|
|
802
|
+
const keysJson2 = rec.get("keysJson");
|
|
803
|
+
const keys = keysJson2 ? JSON.parse(keysJson2) : {};
|
|
804
|
+
const setClause = Object.keys(keys).length > 0 ? ", " + Object.keys(keys).map((k) => `m.\`${k}\` = $val_${k}`).join(", ") : "";
|
|
805
|
+
const msgParams = { meid };
|
|
806
|
+
for (const [k, v] of Object.entries(keys))
|
|
807
|
+
msgParams[`val_${k}`] = v;
|
|
808
|
+
await tx.run(`MATCH (m) WHERE elementId(m) = $meid
|
|
809
|
+
REMOVE m:Trashed, m.trashedAt, m.trashedBy, m.trashReason, m._trashedKeys
|
|
810
|
+
SET m.restoredAt = datetime()${setClause}`, msgParams);
|
|
811
|
+
}
|
|
812
|
+
cascadedMessageCount = collected.records.length;
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
process.stderr.write(`[trash:restored] accountId=${accountId} elementId=${elementId} labels=${baseLabels.join(",")}
|
|
816
|
+
`);
|
|
817
|
+
if (isConversation) {
|
|
818
|
+
process.stderr.write(`[trash:cascade-restored] accountId=${accountId} conversationElementId=${elementId} messageCount=${cascadedMessageCount}
|
|
819
|
+
`);
|
|
820
|
+
}
|
|
821
|
+
return {
|
|
822
|
+
restored: true,
|
|
823
|
+
nodeId: elementId,
|
|
824
|
+
labels: baseLabels,
|
|
825
|
+
restoredKeys: originalKeys
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
async function emptyTrash(params) {
|
|
829
|
+
const t0 = Date.now();
|
|
830
|
+
const { session, accountId, graceDays = 30, dryRun = false, labels: labelFilter, onEmpty } = params;
|
|
831
|
+
const cutoff = new Date(Date.now() - graceDays * 24 * 60 * 60 * 1e3).toISOString();
|
|
832
|
+
const labelClause = labelFilter && labelFilter.length > 0 ? `AND ANY(l IN labels(n) WHERE l IN $labelFilter)` : "";
|
|
833
|
+
const candidatesResult = await session.run(`MATCH (n:Trashed)
|
|
834
|
+
WHERE n.trashedAt < datetime($cutoff)
|
|
835
|
+
${labelClause}
|
|
836
|
+
RETURN elementId(n) AS eid,
|
|
837
|
+
labels(n) AS labels,
|
|
838
|
+
toString(n.trashedAt) AS trashedAt,
|
|
839
|
+
n.trashedBy AS trashedBy,
|
|
840
|
+
n._trashedKeys AS keysJson
|
|
841
|
+
ORDER BY n.trashedAt ASC`, { cutoff, ...labelFilter ? { labelFilter } : {} });
|
|
842
|
+
const candidates = candidatesResult.records.map((r) => {
|
|
843
|
+
const keysJson = r.get("keysJson");
|
|
844
|
+
return {
|
|
845
|
+
elementId: r.get("eid"),
|
|
846
|
+
labels: r.get("labels").filter((l) => l !== "Trashed"),
|
|
847
|
+
trashedAt: String(r.get("trashedAt")),
|
|
848
|
+
trashedBy: r.get("trashedBy") ?? null,
|
|
849
|
+
trashedKeys: keysJson ? JSON.parse(keysJson) : {}
|
|
850
|
+
};
|
|
851
|
+
});
|
|
852
|
+
process.stderr.write(`[trash:empty-run] accountId=${accountId} graceDays=${graceDays} dryRun=${dryRun} candidates=${candidates.length}
|
|
853
|
+
`);
|
|
854
|
+
if (dryRun || candidates.length === 0) {
|
|
855
|
+
process.stderr.write(`[graph:trash:summary] accountId=${accountId} trashedNow=0 emptiedThisRun=0 graceDays=${graceDays} dryRun=${dryRun} elapsedMs=${Date.now() - t0}
|
|
856
|
+
`);
|
|
857
|
+
return { graceDays, dryRun, candidates, emptied: 0 };
|
|
858
|
+
}
|
|
859
|
+
let emptied = 0;
|
|
860
|
+
for (const c of candidates) {
|
|
861
|
+
if (onEmpty) {
|
|
862
|
+
try {
|
|
863
|
+
await onEmpty(c);
|
|
864
|
+
} catch (err) {
|
|
865
|
+
const id83 = c.elementId.slice(0, 8);
|
|
866
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
867
|
+
process.stderr.write(`[trash:empty-run] reason=onEmpty-failed elementId=${id83} labels=${c.labels.join(",")} message=${message}
|
|
868
|
+
`);
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
await session.run(`MATCH (n) WHERE elementId(n) = $eid DETACH DELETE n`, { eid: c.elementId });
|
|
873
|
+
const ageDays = Math.floor((Date.now() - new Date(c.trashedAt).getTime()) / (24 * 60 * 60 * 1e3));
|
|
874
|
+
process.stderr.write(`[trash:emptied] accountId=${accountId} elementId=${c.elementId} labels=${c.labels.join(",")} trashedAt=${c.trashedAt} ageDays=${ageDays}
|
|
875
|
+
`);
|
|
876
|
+
emptied++;
|
|
877
|
+
}
|
|
878
|
+
process.stderr.write(`[graph:trash:summary] accountId=${accountId} trashedNow=0 emptiedThisRun=${emptied} graceDays=${graceDays} dryRun=${dryRun} elapsedMs=${Date.now() - t0}
|
|
879
|
+
`);
|
|
880
|
+
return { graceDays, dryRun, candidates, emptied };
|
|
881
|
+
}
|
|
882
|
+
function notTrashed4(alias) {
|
|
883
|
+
return `(NOT \`${alias}\`:Trashed AND \`${alias}\`.deletedAt IS NULL)`;
|
|
884
|
+
}
|
|
885
|
+
function uniqueKeysForLabels(labels) {
|
|
886
|
+
const out = /* @__PURE__ */ new Set();
|
|
887
|
+
for (const l of labels)
|
|
888
|
+
for (const k of UNIQUE_KEYS_BY_LABEL2[l] ?? [])
|
|
889
|
+
out.add(k);
|
|
890
|
+
return [...out];
|
|
891
|
+
}
|
|
892
|
+
exports.TRASH_METADATA_PROPS = TRASH_PROP_NAMES;
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
// ../lib/telegram-button-labels/dist/index.js
|
|
897
|
+
var require_dist6 = __commonJS({
|
|
609
898
|
"../lib/telegram-button-labels/dist/index.js"(exports) {
|
|
610
899
|
"use strict";
|
|
611
900
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1575,7 +1864,7 @@ var require_geo = __commonJS({
|
|
|
1575
1864
|
});
|
|
1576
1865
|
|
|
1577
1866
|
// ../lib/dispatch-read/dist/index.js
|
|
1578
|
-
var
|
|
1867
|
+
var require_dist7 = __commonJS({
|
|
1579
1868
|
"../lib/dispatch-read/dist/index.js"(exports) {
|
|
1580
1869
|
"use strict";
|
|
1581
1870
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1734,7 +2023,7 @@ var require_dist6 = __commonJS({
|
|
|
1734
2023
|
});
|
|
1735
2024
|
|
|
1736
2025
|
// ../lib/account-schema-regions/dist/index.js
|
|
1737
|
-
var
|
|
2026
|
+
var require_dist8 = __commonJS({
|
|
1738
2027
|
"../lib/account-schema-regions/dist/index.js"(exports) {
|
|
1739
2028
|
"use strict";
|
|
1740
2029
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1803,287 +2092,6 @@ var require_dist7 = __commonJS({
|
|
|
1803
2092
|
}
|
|
1804
2093
|
});
|
|
1805
2094
|
|
|
1806
|
-
// ../lib/graph-trash/dist/index.js
|
|
1807
|
-
var require_dist8 = __commonJS({
|
|
1808
|
-
"../lib/graph-trash/dist/index.js"(exports) {
|
|
1809
|
-
"use strict";
|
|
1810
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1811
|
-
exports.TRASH_METADATA_PROPS = void 0;
|
|
1812
|
-
exports.trashNode = trashNode2;
|
|
1813
|
-
exports.restoreNode = restoreNode2;
|
|
1814
|
-
exports.emptyTrash = emptyTrash;
|
|
1815
|
-
exports.notTrashed = notTrashed2;
|
|
1816
|
-
exports.uniqueKeysForLabels = uniqueKeysForLabels;
|
|
1817
|
-
var UNIQUE_KEYS_BY_LABEL2 = {
|
|
1818
|
-
Person: ["email", "telephone"],
|
|
1819
|
-
Service: ["serviceId"],
|
|
1820
|
-
LocalBusiness: ["accountId"],
|
|
1821
|
-
Task: ["taskId"],
|
|
1822
|
-
Event: ["eventId"],
|
|
1823
|
-
// :KnowledgeDocument is keyed on `attachmentId` (document writer path —
|
|
1824
|
-
// file/URL/obsidian/contract attachment + legacy Gmail-thread shape under
|
|
1825
|
-
// `source:'email'`). Task 397 split the conversation transcripts off into
|
|
1826
|
-
// `:ConversationArchive`, which carries `conversationIdentity`.
|
|
1827
|
-
KnowledgeDocument: ["attachmentId"],
|
|
1828
|
-
ConversationArchive: ["conversationIdentity"],
|
|
1829
|
-
DigitalDocument: ["attachmentId"],
|
|
1830
|
-
Conversation: ["sessionId"],
|
|
1831
|
-
Message: ["messageId"],
|
|
1832
|
-
Workflow: ["workflowId"],
|
|
1833
|
-
WorkflowStep: ["stepId"],
|
|
1834
|
-
WorkflowRun: ["runId"],
|
|
1835
|
-
Preference: ["preferenceId"],
|
|
1836
|
-
Email: ["emailId", "messageId"],
|
|
1837
|
-
AdminUser: ["userId"],
|
|
1838
|
-
ToolCall: ["callId"],
|
|
1839
|
-
// Composite component nulls — frees the composite constraint:
|
|
1840
|
-
AccessGrant: ["contactValue"],
|
|
1841
|
-
// composite (contactValue, agentSlug, accountId)
|
|
1842
|
-
UserProfile: ["userId"]
|
|
1843
|
-
// composite (accountId, userId)
|
|
1844
|
-
};
|
|
1845
|
-
var TRASH_PROP_NAMES = [
|
|
1846
|
-
"trashedAt",
|
|
1847
|
-
"trashedBy",
|
|
1848
|
-
"trashReason",
|
|
1849
|
-
"_trashedKeys"
|
|
1850
|
-
];
|
|
1851
|
-
async function trashNode2(params) {
|
|
1852
|
-
const { session, accountId, elementId, by, reason } = params;
|
|
1853
|
-
const lookup = await session.run(`MATCH (n) WHERE elementId(n) = $eid AND n.accountId = $accountId
|
|
1854
|
-
RETURN labels(n) AS labels, properties(n) AS props`, { eid: elementId, accountId });
|
|
1855
|
-
if (lookup.records.length === 0) {
|
|
1856
|
-
throw new Error(`trashNode: node not found (elementId=${elementId} accountId=${accountId.slice(0, 8)}\u2026)`);
|
|
1857
|
-
}
|
|
1858
|
-
const allLabels = lookup.records[0].get("labels");
|
|
1859
|
-
const props = lookup.records[0].get("props");
|
|
1860
|
-
const baseLabels = allLabels.filter((l) => l !== "Trashed");
|
|
1861
|
-
if (allLabels.includes("Trashed")) {
|
|
1862
|
-
return {
|
|
1863
|
-
trashed: false,
|
|
1864
|
-
alreadyTrashed: true,
|
|
1865
|
-
nodeId: elementId,
|
|
1866
|
-
labels: baseLabels,
|
|
1867
|
-
trashedAt: String(props.trashedAt ?? ""),
|
|
1868
|
-
originalKeys: {}
|
|
1869
|
-
};
|
|
1870
|
-
}
|
|
1871
|
-
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
1872
|
-
for (const label of baseLabels) {
|
|
1873
|
-
for (const key2 of UNIQUE_KEYS_BY_LABEL2[label] ?? [])
|
|
1874
|
-
uniqueKeys.add(key2);
|
|
1875
|
-
}
|
|
1876
|
-
const originalKeys = {};
|
|
1877
|
-
for (const k of uniqueKeys) {
|
|
1878
|
-
if (props[k] !== void 0 && props[k] !== null)
|
|
1879
|
-
originalKeys[k] = props[k];
|
|
1880
|
-
}
|
|
1881
|
-
const setNullClauses = Object.keys(originalKeys).map((k) => `n.\`${k}\` = null`).join(", ");
|
|
1882
|
-
const setNullSuffix = setNullClauses ? `, ${setNullClauses}` : "";
|
|
1883
|
-
const trashedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1884
|
-
const isConversation = baseLabels.includes("Conversation");
|
|
1885
|
-
const messageUniqueKeys = UNIQUE_KEYS_BY_LABEL2["Message"] ?? [];
|
|
1886
|
-
let cascadedMessageCount = 0;
|
|
1887
|
-
await session.executeWrite(async (tx) => {
|
|
1888
|
-
await tx.run(`MATCH (n) WHERE elementId(n) = $eid
|
|
1889
|
-
SET n:Trashed,
|
|
1890
|
-
n.trashedAt = datetime($trashedAt),
|
|
1891
|
-
n.trashedBy = $by,
|
|
1892
|
-
n.trashReason = $reason,
|
|
1893
|
-
n._trashedKeys = $trashedKeysJson${setNullSuffix}`, {
|
|
1894
|
-
eid: elementId,
|
|
1895
|
-
trashedAt,
|
|
1896
|
-
by,
|
|
1897
|
-
reason: reason ?? null,
|
|
1898
|
-
trashedKeysJson: JSON.stringify(originalKeys)
|
|
1899
|
-
});
|
|
1900
|
-
if (isConversation) {
|
|
1901
|
-
const collectKeys = messageUniqueKeys.length > 0 ? messageUniqueKeys.map((k) => `\`${k}\`: m.\`${k}\``).join(", ") : "";
|
|
1902
|
-
const collectMsgProps = collectKeys ? `, {${collectKeys}}` : ", {}";
|
|
1903
|
-
const collected = await tx.run(`MATCH (c) WHERE elementId(c) = $eid
|
|
1904
|
-
MATCH (m:Message)-[:PART_OF]->(c)
|
|
1905
|
-
WHERE NOT m:Trashed
|
|
1906
|
-
RETURN elementId(m) AS meid${collectMsgProps} AS keys`, { eid: elementId });
|
|
1907
|
-
for (const rec of collected.records) {
|
|
1908
|
-
const meid = rec.get("meid");
|
|
1909
|
-
const keys = rec.get("keys");
|
|
1910
|
-
const liveKeys = {};
|
|
1911
|
-
for (const k of messageUniqueKeys) {
|
|
1912
|
-
if (keys[k] !== void 0 && keys[k] !== null)
|
|
1913
|
-
liveKeys[k] = keys[k];
|
|
1914
|
-
}
|
|
1915
|
-
const msgSetNulls = Object.keys(liveKeys).length > 0 ? ", " + Object.keys(liveKeys).map((k) => `m.\`${k}\` = null`).join(", ") : "";
|
|
1916
|
-
await tx.run(`MATCH (m) WHERE elementId(m) = $meid
|
|
1917
|
-
SET m:Trashed,
|
|
1918
|
-
m.trashedAt = datetime($trashedAt),
|
|
1919
|
-
m.trashedBy = $by,
|
|
1920
|
-
m.trashReason = $reason,
|
|
1921
|
-
m._trashedKeys = $trashedKeysJson${msgSetNulls}`, {
|
|
1922
|
-
meid,
|
|
1923
|
-
trashedAt,
|
|
1924
|
-
by: `${by}:cascade-from-conversation`,
|
|
1925
|
-
reason: reason ?? `cascade from Conversation ${elementId}`,
|
|
1926
|
-
trashedKeysJson: JSON.stringify(liveKeys)
|
|
1927
|
-
});
|
|
1928
|
-
}
|
|
1929
|
-
cascadedMessageCount = collected.records.length;
|
|
1930
|
-
}
|
|
1931
|
-
});
|
|
1932
|
-
process.stderr.write(`[trash:marked] accountId=${accountId} elementId=${elementId} labels=${baseLabels.join(",")} by=${by} reason=${reason ?? "null"}
|
|
1933
|
-
`);
|
|
1934
|
-
if (isConversation) {
|
|
1935
|
-
process.stderr.write(`[trash:cascaded] accountId=${accountId} conversationElementId=${elementId} messageCount=${cascadedMessageCount} by=${by}
|
|
1936
|
-
`);
|
|
1937
|
-
}
|
|
1938
|
-
return {
|
|
1939
|
-
trashed: true,
|
|
1940
|
-
alreadyTrashed: false,
|
|
1941
|
-
nodeId: elementId,
|
|
1942
|
-
labels: baseLabels,
|
|
1943
|
-
trashedAt,
|
|
1944
|
-
originalKeys
|
|
1945
|
-
};
|
|
1946
|
-
}
|
|
1947
|
-
async function restoreNode2(params) {
|
|
1948
|
-
const { session, accountId, elementId } = params;
|
|
1949
|
-
const lookup = await session.run(`MATCH (n:Trashed) WHERE elementId(n) = $eid
|
|
1950
|
-
RETURN labels(n) AS labels, n._trashedKeys AS keysJson`, { eid: elementId });
|
|
1951
|
-
if (lookup.records.length === 0) {
|
|
1952
|
-
throw new Error(`restoreNode: trashed node not found (elementId=${elementId})`);
|
|
1953
|
-
}
|
|
1954
|
-
const allLabels = lookup.records[0].get("labels");
|
|
1955
|
-
const baseLabels = allLabels.filter((l) => l !== "Trashed");
|
|
1956
|
-
const keysJson = lookup.records[0].get("keysJson");
|
|
1957
|
-
const originalKeys = keysJson ? JSON.parse(keysJson) : {};
|
|
1958
|
-
for (const label of baseLabels) {
|
|
1959
|
-
const uniqueKeys = UNIQUE_KEYS_BY_LABEL2[label] ?? [];
|
|
1960
|
-
for (const k of uniqueKeys) {
|
|
1961
|
-
const v = originalKeys[k];
|
|
1962
|
-
if (v === void 0 || v === null)
|
|
1963
|
-
continue;
|
|
1964
|
-
const conflict = await session.run(`MATCH (other:\`${label}\`)
|
|
1965
|
-
WHERE elementId(other) <> $eid
|
|
1966
|
-
AND NOT other:Trashed
|
|
1967
|
-
AND other.\`${k}\` = $val
|
|
1968
|
-
RETURN elementId(other) AS otherId LIMIT 1`, { eid: elementId, val: v });
|
|
1969
|
-
if (conflict.records.length > 0) {
|
|
1970
|
-
const otherId = conflict.records[0].get("otherId");
|
|
1971
|
-
throw new Error(`restoreNode: cannot restore ${label} elementId=${elementId} \u2014 active node elementId=${otherId} already holds ${k}=${JSON.stringify(v)}`);
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
}
|
|
1975
|
-
const setClauses = Object.keys(originalKeys).map((k) => `n.\`${k}\` = $val_${k}`).join(", ");
|
|
1976
|
-
const setSuffix = setClauses ? `, ${setClauses}` : "";
|
|
1977
|
-
const setParams = { eid: elementId };
|
|
1978
|
-
for (const [k, v] of Object.entries(originalKeys))
|
|
1979
|
-
setParams[`val_${k}`] = v;
|
|
1980
|
-
const isConversation = baseLabels.includes("Conversation");
|
|
1981
|
-
let cascadedMessageCount = 0;
|
|
1982
|
-
await session.executeWrite(async (tx) => {
|
|
1983
|
-
await tx.run(`MATCH (n:Trashed) WHERE elementId(n) = $eid
|
|
1984
|
-
REMOVE n:Trashed, n.trashedAt, n.trashedBy, n.trashReason, n._trashedKeys
|
|
1985
|
-
SET n.restoredAt = datetime()${setSuffix}`, setParams);
|
|
1986
|
-
if (isConversation) {
|
|
1987
|
-
const collected = await tx.run(`MATCH (c) WHERE elementId(c) = $eid
|
|
1988
|
-
MATCH (m:Trashed:Message)-[:PART_OF]->(c)
|
|
1989
|
-
WHERE m.trashedBy ENDS WITH ':cascade-from-conversation'
|
|
1990
|
-
RETURN elementId(m) AS meid, m._trashedKeys AS keysJson`, { eid: elementId });
|
|
1991
|
-
for (const rec of collected.records) {
|
|
1992
|
-
const meid = rec.get("meid");
|
|
1993
|
-
const keysJson2 = rec.get("keysJson");
|
|
1994
|
-
const keys = keysJson2 ? JSON.parse(keysJson2) : {};
|
|
1995
|
-
const setClause = Object.keys(keys).length > 0 ? ", " + Object.keys(keys).map((k) => `m.\`${k}\` = $val_${k}`).join(", ") : "";
|
|
1996
|
-
const msgParams = { meid };
|
|
1997
|
-
for (const [k, v] of Object.entries(keys))
|
|
1998
|
-
msgParams[`val_${k}`] = v;
|
|
1999
|
-
await tx.run(`MATCH (m) WHERE elementId(m) = $meid
|
|
2000
|
-
REMOVE m:Trashed, m.trashedAt, m.trashedBy, m.trashReason, m._trashedKeys
|
|
2001
|
-
SET m.restoredAt = datetime()${setClause}`, msgParams);
|
|
2002
|
-
}
|
|
2003
|
-
cascadedMessageCount = collected.records.length;
|
|
2004
|
-
}
|
|
2005
|
-
});
|
|
2006
|
-
process.stderr.write(`[trash:restored] accountId=${accountId} elementId=${elementId} labels=${baseLabels.join(",")}
|
|
2007
|
-
`);
|
|
2008
|
-
if (isConversation) {
|
|
2009
|
-
process.stderr.write(`[trash:cascade-restored] accountId=${accountId} conversationElementId=${elementId} messageCount=${cascadedMessageCount}
|
|
2010
|
-
`);
|
|
2011
|
-
}
|
|
2012
|
-
return {
|
|
2013
|
-
restored: true,
|
|
2014
|
-
nodeId: elementId,
|
|
2015
|
-
labels: baseLabels,
|
|
2016
|
-
restoredKeys: originalKeys
|
|
2017
|
-
};
|
|
2018
|
-
}
|
|
2019
|
-
async function emptyTrash(params) {
|
|
2020
|
-
const t0 = Date.now();
|
|
2021
|
-
const { session, accountId, graceDays = 30, dryRun = false, labels: labelFilter, onEmpty } = params;
|
|
2022
|
-
const cutoff = new Date(Date.now() - graceDays * 24 * 60 * 60 * 1e3).toISOString();
|
|
2023
|
-
const labelClause = labelFilter && labelFilter.length > 0 ? `AND ANY(l IN labels(n) WHERE l IN $labelFilter)` : "";
|
|
2024
|
-
const candidatesResult = await session.run(`MATCH (n:Trashed)
|
|
2025
|
-
WHERE n.trashedAt < datetime($cutoff)
|
|
2026
|
-
${labelClause}
|
|
2027
|
-
RETURN elementId(n) AS eid,
|
|
2028
|
-
labels(n) AS labels,
|
|
2029
|
-
toString(n.trashedAt) AS trashedAt,
|
|
2030
|
-
n.trashedBy AS trashedBy,
|
|
2031
|
-
n._trashedKeys AS keysJson
|
|
2032
|
-
ORDER BY n.trashedAt ASC`, { cutoff, ...labelFilter ? { labelFilter } : {} });
|
|
2033
|
-
const candidates = candidatesResult.records.map((r) => {
|
|
2034
|
-
const keysJson = r.get("keysJson");
|
|
2035
|
-
return {
|
|
2036
|
-
elementId: r.get("eid"),
|
|
2037
|
-
labels: r.get("labels").filter((l) => l !== "Trashed"),
|
|
2038
|
-
trashedAt: String(r.get("trashedAt")),
|
|
2039
|
-
trashedBy: r.get("trashedBy") ?? null,
|
|
2040
|
-
trashedKeys: keysJson ? JSON.parse(keysJson) : {}
|
|
2041
|
-
};
|
|
2042
|
-
});
|
|
2043
|
-
process.stderr.write(`[trash:empty-run] accountId=${accountId} graceDays=${graceDays} dryRun=${dryRun} candidates=${candidates.length}
|
|
2044
|
-
`);
|
|
2045
|
-
if (dryRun || candidates.length === 0) {
|
|
2046
|
-
process.stderr.write(`[graph:trash:summary] accountId=${accountId} trashedNow=0 emptiedThisRun=0 graceDays=${graceDays} dryRun=${dryRun} elapsedMs=${Date.now() - t0}
|
|
2047
|
-
`);
|
|
2048
|
-
return { graceDays, dryRun, candidates, emptied: 0 };
|
|
2049
|
-
}
|
|
2050
|
-
let emptied = 0;
|
|
2051
|
-
for (const c of candidates) {
|
|
2052
|
-
if (onEmpty) {
|
|
2053
|
-
try {
|
|
2054
|
-
await onEmpty(c);
|
|
2055
|
-
} catch (err) {
|
|
2056
|
-
const id83 = c.elementId.slice(0, 8);
|
|
2057
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2058
|
-
process.stderr.write(`[trash:empty-run] reason=onEmpty-failed elementId=${id83} labels=${c.labels.join(",")} message=${message}
|
|
2059
|
-
`);
|
|
2060
|
-
continue;
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
await session.run(`MATCH (n) WHERE elementId(n) = $eid DETACH DELETE n`, { eid: c.elementId });
|
|
2064
|
-
const ageDays = Math.floor((Date.now() - new Date(c.trashedAt).getTime()) / (24 * 60 * 60 * 1e3));
|
|
2065
|
-
process.stderr.write(`[trash:emptied] accountId=${accountId} elementId=${c.elementId} labels=${c.labels.join(",")} trashedAt=${c.trashedAt} ageDays=${ageDays}
|
|
2066
|
-
`);
|
|
2067
|
-
emptied++;
|
|
2068
|
-
}
|
|
2069
|
-
process.stderr.write(`[graph:trash:summary] accountId=${accountId} trashedNow=0 emptiedThisRun=${emptied} graceDays=${graceDays} dryRun=${dryRun} elapsedMs=${Date.now() - t0}
|
|
2070
|
-
`);
|
|
2071
|
-
return { graceDays, dryRun, candidates, emptied };
|
|
2072
|
-
}
|
|
2073
|
-
function notTrashed2(alias) {
|
|
2074
|
-
return `(NOT \`${alias}\`:Trashed AND \`${alias}\`.deletedAt IS NULL)`;
|
|
2075
|
-
}
|
|
2076
|
-
function uniqueKeysForLabels(labels) {
|
|
2077
|
-
const out = /* @__PURE__ */ new Set();
|
|
2078
|
-
for (const l of labels)
|
|
2079
|
-
for (const k of UNIQUE_KEYS_BY_LABEL2[l] ?? [])
|
|
2080
|
-
out.add(k);
|
|
2081
|
-
return [...out];
|
|
2082
|
-
}
|
|
2083
|
-
exports.TRASH_METADATA_PROPS = TRASH_PROP_NAMES;
|
|
2084
|
-
}
|
|
2085
|
-
});
|
|
2086
|
-
|
|
2087
2095
|
// ../lib/graph-style/dist/index.js
|
|
2088
2096
|
var require_dist9 = __commonJS({
|
|
2089
2097
|
"../lib/graph-style/dist/index.js"(exports) {
|
|
@@ -4252,6 +4260,74 @@ var TELEGRAM_CARD_TOOLS = /* @__PURE__ */ new Set([
|
|
|
4252
4260
|
"mcp__telegram__telegram-card",
|
|
4253
4261
|
"mcp__plugin_telegram_telegram__telegram-card"
|
|
4254
4262
|
]);
|
|
4263
|
+
var TELEGRAM_MEDIA_SEND_TOOLS = /* @__PURE__ */ new Set([
|
|
4264
|
+
"mcp__telegram__telegram-media-send",
|
|
4265
|
+
"mcp__plugin_telegram_telegram__telegram-media-send"
|
|
4266
|
+
]);
|
|
4267
|
+
var TELEGRAM_ASK_TOOLS = /* @__PURE__ */ new Set([
|
|
4268
|
+
"mcp__telegram__telegram-ask",
|
|
4269
|
+
"mcp__plugin_telegram_telegram__telegram-ask"
|
|
4270
|
+
]);
|
|
4271
|
+
var TELEGRAM_API_TOOLS = /* @__PURE__ */ new Set([
|
|
4272
|
+
"mcp__telegram__telegram-api",
|
|
4273
|
+
"mcp__plugin_telegram_telegram__telegram-api"
|
|
4274
|
+
]);
|
|
4275
|
+
var TELEGRAM_API_TRANSMIT_METHODS = /* @__PURE__ */ new Set(["sendMessage", "editMessageText"]);
|
|
4276
|
+
var TELEGRAM_SEND_TOOLS = /* @__PURE__ */ new Set([
|
|
4277
|
+
...TELEGRAM_CARD_TOOLS,
|
|
4278
|
+
...TELEGRAM_MEDIA_SEND_TOOLS,
|
|
4279
|
+
...TELEGRAM_ASK_TOOLS,
|
|
4280
|
+
...TELEGRAM_API_TOOLS
|
|
4281
|
+
]);
|
|
4282
|
+
function chatIdOf(value) {
|
|
4283
|
+
if (typeof value === "string") return value;
|
|
4284
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
4285
|
+
return "";
|
|
4286
|
+
}
|
|
4287
|
+
function cardOutcome(text, isError) {
|
|
4288
|
+
const v = /card-result: outcome=(\w+)/.exec(text)?.[1];
|
|
4289
|
+
if (v === "edited" || v === "unchanged" || v === "sent") return v;
|
|
4290
|
+
if (v === "none") return "failed";
|
|
4291
|
+
return isError ? "failed" : "sent";
|
|
4292
|
+
}
|
|
4293
|
+
function pendingSendOf(name, input) {
|
|
4294
|
+
const i = input ?? {};
|
|
4295
|
+
if (TELEGRAM_CARD_TOOLS.has(name)) {
|
|
4296
|
+
return {
|
|
4297
|
+
kind: "telegram-card",
|
|
4298
|
+
text: typeof i.text === "string" ? i.text : "",
|
|
4299
|
+
buttons: parseCardButtonsFromInput(input),
|
|
4300
|
+
chatId: chatIdOf(i.chatId),
|
|
4301
|
+
ts: null
|
|
4302
|
+
};
|
|
4303
|
+
}
|
|
4304
|
+
if (TELEGRAM_MEDIA_SEND_TOOLS.has(name) || TELEGRAM_ASK_TOOLS.has(name)) {
|
|
4305
|
+
const kind = typeof i.kind === "string" ? i.kind : "";
|
|
4306
|
+
const text = TELEGRAM_MEDIA_SEND_TOOLS.has(name) ? typeof i.caption === "string" ? i.caption : "" : typeof i.question === "string" ? i.question : "";
|
|
4307
|
+
return {
|
|
4308
|
+
kind: "telegram-send",
|
|
4309
|
+
label: kind,
|
|
4310
|
+
text,
|
|
4311
|
+
chatId: chatIdOf(i.chatId),
|
|
4312
|
+
edit: kind.startsWith("edit") || kind.startsWith("stop"),
|
|
4313
|
+
ts: null
|
|
4314
|
+
};
|
|
4315
|
+
}
|
|
4316
|
+
if (TELEGRAM_API_TOOLS.has(name)) {
|
|
4317
|
+
const method = typeof i.method === "string" ? i.method : "";
|
|
4318
|
+
if (!TELEGRAM_API_TRANSMIT_METHODS.has(method)) return null;
|
|
4319
|
+
const params = i.params ?? {};
|
|
4320
|
+
return {
|
|
4321
|
+
kind: "telegram-send",
|
|
4322
|
+
label: method,
|
|
4323
|
+
text: typeof params.text === "string" ? params.text : "",
|
|
4324
|
+
chatId: chatIdOf(params.chat_id),
|
|
4325
|
+
edit: method === "editMessageText",
|
|
4326
|
+
ts: null
|
|
4327
|
+
};
|
|
4328
|
+
}
|
|
4329
|
+
return null;
|
|
4330
|
+
}
|
|
4255
4331
|
function parseCardButtonsFromInput(input) {
|
|
4256
4332
|
const rows = input?.buttons;
|
|
4257
4333
|
if (!Array.isArray(rows)) return [];
|
|
@@ -4396,7 +4472,29 @@ function erroredToolUseIds(lines) {
|
|
|
4396
4472
|
}
|
|
4397
4473
|
return ids;
|
|
4398
4474
|
}
|
|
4399
|
-
function
|
|
4475
|
+
function answeredToolUseIds(lines) {
|
|
4476
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4477
|
+
for (const line of lines) {
|
|
4478
|
+
if (!line || line[0] !== "{" || !line.includes("tool_use_id")) continue;
|
|
4479
|
+
let row;
|
|
4480
|
+
try {
|
|
4481
|
+
const parsed = JSON.parse(line);
|
|
4482
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
4483
|
+
row = parsed;
|
|
4484
|
+
} catch {
|
|
4485
|
+
continue;
|
|
4486
|
+
}
|
|
4487
|
+
const content = row.message?.content;
|
|
4488
|
+
if (!Array.isArray(content)) continue;
|
|
4489
|
+
for (const block of content) {
|
|
4490
|
+
if (!block || typeof block !== "object") continue;
|
|
4491
|
+
const b = block;
|
|
4492
|
+
if (b.type === "tool_result" && typeof b.tool_use_id === "string") ids.add(b.tool_use_id);
|
|
4493
|
+
}
|
|
4494
|
+
}
|
|
4495
|
+
return ids;
|
|
4496
|
+
}
|
|
4497
|
+
function assistantTurns(content, ts, promoteFinal = false, erroredIds = /* @__PURE__ */ new Set(), uuid, answeredIds = /* @__PURE__ */ new Set(), pending = /* @__PURE__ */ new Map(), fullRead = true) {
|
|
4400
4498
|
if (!Array.isArray(content)) return [];
|
|
4401
4499
|
const out = [];
|
|
4402
4500
|
for (const block of content) {
|
|
@@ -4430,21 +4528,21 @@ function assistantTurns(content, ts, promoteFinal = false, erroredIds = /* @__PU
|
|
|
4430
4528
|
} else {
|
|
4431
4529
|
out.push({ kind: "agent-file", files, caption, ts });
|
|
4432
4530
|
}
|
|
4433
|
-
} else if (b.type === "tool_use" && typeof b.name === "string" &&
|
|
4434
|
-
const
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
ts
|
|
4440
|
-
}
|
|
4531
|
+
} else if (b.type === "tool_use" && typeof b.name === "string" && TELEGRAM_SEND_TOOLS.has(b.name)) {
|
|
4532
|
+
const send = pendingSendOf(b.name, b.input);
|
|
4533
|
+
const id = typeof b.id === "string" ? b.id : null;
|
|
4534
|
+
if (send !== null && id !== null && (answeredIds.has(id) || !fullRead)) {
|
|
4535
|
+
pending.set(id, { ...send, ts });
|
|
4536
|
+
} else {
|
|
4537
|
+
out.push({ kind: "tool-call", name: b.name, input: b.input ?? null, ts });
|
|
4538
|
+
}
|
|
4441
4539
|
} else if (b.type === "tool_use" && typeof b.name === "string") {
|
|
4442
4540
|
out.push({ kind: "tool-call", name: b.name, input: b.input ?? null, ts });
|
|
4443
4541
|
}
|
|
4444
4542
|
}
|
|
4445
4543
|
return out;
|
|
4446
4544
|
}
|
|
4447
|
-
function toolResultTurns(content, ts) {
|
|
4545
|
+
function toolResultTurns(content, ts, pending = /* @__PURE__ */ new Map()) {
|
|
4448
4546
|
if (!Array.isArray(content)) return [];
|
|
4449
4547
|
const out = [];
|
|
4450
4548
|
for (const block of content) {
|
|
@@ -4455,6 +4553,15 @@ function toolResultTurns(content, ts) {
|
|
|
4455
4553
|
(c) => c && typeof c === "object" && typeof c.text === "string" ? c.text : ""
|
|
4456
4554
|
).join("") : "";
|
|
4457
4555
|
out.push({ kind: "tool-result", text, isError: b.is_error === true, ts });
|
|
4556
|
+
const id = b.tool_use_id;
|
|
4557
|
+
if (typeof id !== "string") continue;
|
|
4558
|
+
const send = pending.get(id);
|
|
4559
|
+
if (send === void 0) continue;
|
|
4560
|
+
pending.delete(id);
|
|
4561
|
+
const outcome = send.kind === "telegram-card" ? cardOutcome(text, b.is_error === true) : b.is_error === true ? "failed" : send.edit ? "edited" : "sent";
|
|
4562
|
+
out.push(
|
|
4563
|
+
send.kind === "telegram-card" ? { kind: "telegram-card", text: send.text, buttons: send.buttons, chatId: send.chatId, outcome, ts: send.ts } : { kind: "telegram-send", label: send.label, text: send.text, chatId: send.chatId, outcome, ts: send.ts }
|
|
4564
|
+
);
|
|
4458
4565
|
}
|
|
4459
4566
|
return out;
|
|
4460
4567
|
}
|
|
@@ -4479,9 +4586,11 @@ function renderOrSuppressChannelInbound(u, ts, out, queuedPendingSuppress, uuid,
|
|
|
4479
4586
|
out.push(operatorInboundTurn(u, ts, uuid, census));
|
|
4480
4587
|
}
|
|
4481
4588
|
}
|
|
4482
|
-
function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(), turnCtx = {}) {
|
|
4589
|
+
function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(), turnCtx = {}, fullRead = true) {
|
|
4483
4590
|
const out = [];
|
|
4591
|
+
const pendingSends = turnCtx.pendingTelegramSends ??= /* @__PURE__ */ new Map();
|
|
4484
4592
|
const erroredIds = erroredToolUseIds(lines);
|
|
4593
|
+
const answeredIds = lines.some((l) => l.includes("telegram-")) ? answeredToolUseIds(lines) : /* @__PURE__ */ new Set();
|
|
4485
4594
|
for (const line of lines) {
|
|
4486
4595
|
if (!line || line[0] !== "{") continue;
|
|
4487
4596
|
let row;
|
|
@@ -4505,7 +4614,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
4505
4614
|
}
|
|
4506
4615
|
const isEnd = msg?.stop_reason === "end_turn";
|
|
4507
4616
|
const promoteFinal = isEnd && turnCtx.lastChannelSource !== void 0;
|
|
4508
|
-
out.push(...assistantTurns(msg?.content, ts, promoteFinal, erroredIds, asString(row.uuid) ?? void 0));
|
|
4617
|
+
out.push(...assistantTurns(msg?.content, ts, promoteFinal, erroredIds, asString(row.uuid) ?? void 0, answeredIds, pendingSends, fullRead));
|
|
4509
4618
|
continue;
|
|
4510
4619
|
}
|
|
4511
4620
|
if (row.type === "queue-operation" && row.operation === "enqueue") {
|
|
@@ -4538,7 +4647,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
4538
4647
|
continue;
|
|
4539
4648
|
}
|
|
4540
4649
|
if (Array.isArray(msg.content)) {
|
|
4541
|
-
out.push(...toolResultTurns(msg.content, ts));
|
|
4650
|
+
out.push(...toolResultTurns(msg.content, ts, pendingSends));
|
|
4542
4651
|
continue;
|
|
4543
4652
|
}
|
|
4544
4653
|
const text = asString(msg.content);
|
|
@@ -5650,48 +5759,6 @@ function logPublicAddress(slug, verdict) {
|
|
|
5650
5759
|
import { writeFile, mkdtemp, rm } from "fs/promises";
|
|
5651
5760
|
import { tmpdir as tmpdir2 } from "os";
|
|
5652
5761
|
import { join as join7 } from "path";
|
|
5653
|
-
|
|
5654
|
-
// app/lib/stt/audio-mime.ts
|
|
5655
|
-
var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
5656
|
-
"audio/ogg",
|
|
5657
|
-
"audio/opus",
|
|
5658
|
-
"audio/webm",
|
|
5659
|
-
"audio/mp4",
|
|
5660
|
-
"audio/x-m4a",
|
|
5661
|
-
"audio/mpeg",
|
|
5662
|
-
"audio/wav",
|
|
5663
|
-
"video/mp4"
|
|
5664
|
-
]);
|
|
5665
|
-
function normalizeMime(mimeType) {
|
|
5666
|
-
return mimeType.split(";")[0].trim().toLowerCase();
|
|
5667
|
-
}
|
|
5668
|
-
function isAudioMime(mimeType) {
|
|
5669
|
-
return AUDIO_MIME_TYPES.has(normalizeMime(mimeType));
|
|
5670
|
-
}
|
|
5671
|
-
function audioExtension(mimeType) {
|
|
5672
|
-
switch (normalizeMime(mimeType)) {
|
|
5673
|
-
case "audio/ogg":
|
|
5674
|
-
return ".ogg";
|
|
5675
|
-
case "audio/opus":
|
|
5676
|
-
return ".opus";
|
|
5677
|
-
case "audio/webm":
|
|
5678
|
-
return ".webm";
|
|
5679
|
-
case "audio/mp4":
|
|
5680
|
-
return ".m4a";
|
|
5681
|
-
case "audio/x-m4a":
|
|
5682
|
-
return ".m4a";
|
|
5683
|
-
case "audio/mpeg":
|
|
5684
|
-
return ".mp3";
|
|
5685
|
-
case "audio/wav":
|
|
5686
|
-
return ".wav";
|
|
5687
|
-
case "video/mp4":
|
|
5688
|
-
return ".mp4";
|
|
5689
|
-
default:
|
|
5690
|
-
return ".audio";
|
|
5691
|
-
}
|
|
5692
|
-
}
|
|
5693
|
-
|
|
5694
|
-
// app/lib/stt/voice-note.ts
|
|
5695
5762
|
var TAG4 = "[voice]";
|
|
5696
5763
|
async function transcribeVoiceNote(file, source) {
|
|
5697
5764
|
const startMs = Date.now();
|
|
@@ -7385,7 +7452,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
7385
7452
|
}
|
|
7386
7453
|
|
|
7387
7454
|
// server/index.ts
|
|
7388
|
-
var
|
|
7455
|
+
var import_dist19 = __toESM(require_dist3(), 1);
|
|
7389
7456
|
|
|
7390
7457
|
// app/lib/whatsapp/avatar-store.ts
|
|
7391
7458
|
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync4, readdirSync as readdirSync6, statSync as statSync8, rmSync as rmSync3 } from "fs";
|
|
@@ -7487,7 +7554,7 @@ async function defaultHttpGet(url) {
|
|
|
7487
7554
|
}
|
|
7488
7555
|
}
|
|
7489
7556
|
async function defaultResolve(accountId) {
|
|
7490
|
-
const { resolveSocket: resolveSocket2 } = await import("./manager-
|
|
7557
|
+
const { resolveSocket: resolveSocket2 } = await import("./manager-VDHT3YYI.js");
|
|
7491
7558
|
return resolveSocket2(accountId);
|
|
7492
7559
|
}
|
|
7493
7560
|
async function fetchAvatar(accountId, jid, deps = {}) {
|
|
@@ -15841,7 +15908,7 @@ data: ${JSON.stringify(obj)}
|
|
|
15841
15908
|
const { lines, nextOffset } = splitNewLines(buf, offset);
|
|
15842
15909
|
offset = nextOffset;
|
|
15843
15910
|
let n = 0;
|
|
15844
|
-
for (const turn of parseTranscript(lines, queuedPendingSuppress, turnCtx)) {
|
|
15911
|
+
for (const turn of parseTranscript(lines, queuedPendingSuppress, turnCtx, false)) {
|
|
15845
15912
|
send(controller, enrichAdminAttachments(enrichDownloads(turn, scratchpadRoot), sessionId), offset);
|
|
15846
15913
|
actx.lastParentTurns.push(turn);
|
|
15847
15914
|
if (turn.kind === "agent-error") {
|
|
@@ -16987,6 +17054,19 @@ async function authorizeAccountWrite(c, accountId) {
|
|
|
16987
17054
|
return { ok: true, via: "session" };
|
|
16988
17055
|
}
|
|
16989
17056
|
|
|
17057
|
+
// app/lib/video/webchat-video.ts
|
|
17058
|
+
var TAG26 = "[video]";
|
|
17059
|
+
async function extractWebchatVideo(file, extractImpl = extractVideo) {
|
|
17060
|
+
if (!isVideoMime(file.mimeType)) return void 0;
|
|
17061
|
+
try {
|
|
17062
|
+
return await extractImpl(file.storagePath, file.mimeType);
|
|
17063
|
+
} catch (err) {
|
|
17064
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
17065
|
+
console.error(`${TAG26} webchat extract failed error=${reason} path=${file.storagePath}`);
|
|
17066
|
+
return void 0;
|
|
17067
|
+
}
|
|
17068
|
+
}
|
|
17069
|
+
|
|
16990
17070
|
// ../lib/models/src/index.ts
|
|
16991
17071
|
var OPUS_MODEL = "claude-opus-5[1m]";
|
|
16992
17072
|
var SONNET_MODEL = "claude-sonnet-5";
|
|
@@ -17422,6 +17502,18 @@ async function reapplyLeversViaManager() {
|
|
|
17422
17502
|
}
|
|
17423
17503
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
17424
17504
|
var sendSeq = 0;
|
|
17505
|
+
var transcribingKeys = /* @__PURE__ */ new Map();
|
|
17506
|
+
function markTranscribing(key2) {
|
|
17507
|
+
transcribingKeys.set(key2, (transcribingKeys.get(key2) ?? 0) + 1);
|
|
17508
|
+
}
|
|
17509
|
+
function clearTranscribing(key2) {
|
|
17510
|
+
const left = (transcribingKeys.get(key2) ?? 1) - 1;
|
|
17511
|
+
if (left > 0) transcribingKeys.set(key2, left);
|
|
17512
|
+
else transcribingKeys.delete(key2);
|
|
17513
|
+
}
|
|
17514
|
+
function isTranscribing(key2) {
|
|
17515
|
+
return (transcribingKeys.get(key2) ?? 0) > 0;
|
|
17516
|
+
}
|
|
17425
17517
|
function createWebchatRoutes(deps) {
|
|
17426
17518
|
const app81 = new Hono();
|
|
17427
17519
|
app81.post("/send", requireAdminSession, async (c) => {
|
|
@@ -17532,13 +17624,17 @@ function createWebchatRoutes(deps) {
|
|
|
17532
17624
|
deliveryKey = `session:${deliverySessionId}`;
|
|
17533
17625
|
deliveryAccountId = bootstrapAccountId;
|
|
17534
17626
|
}
|
|
17627
|
+
let audioFile;
|
|
17628
|
+
let kind = "files";
|
|
17629
|
+
const stored = [];
|
|
17630
|
+
const sendId = sendIdFromResolve ?? ++sendSeq;
|
|
17535
17631
|
if (isMultipart) {
|
|
17536
|
-
|
|
17632
|
+
kind = files.some((f) => isAudioMime(f.type)) ? "voice" : "files";
|
|
17537
17633
|
if (files.length > MAX_FILES_PER_MESSAGE) {
|
|
17538
17634
|
console.error(`[webchat:inbound] op=send-refused kind=${kind} reason=too-many-files count=${files.length}`);
|
|
17539
17635
|
return c.json({ error: `Maximum ${MAX_FILES_PER_MESSAGE} files per message.` }, 422);
|
|
17540
17636
|
}
|
|
17541
|
-
|
|
17637
|
+
audioFile = files.find((f) => isAudioMime(f.type));
|
|
17542
17638
|
const regularFiles = files.filter((f) => !isAudioMime(f.type));
|
|
17543
17639
|
for (const file of regularFiles) {
|
|
17544
17640
|
try {
|
|
@@ -17552,7 +17648,6 @@ function createWebchatRoutes(deps) {
|
|
|
17552
17648
|
return c.json({ error: detail }, 422);
|
|
17553
17649
|
}
|
|
17554
17650
|
}
|
|
17555
|
-
const stored = [];
|
|
17556
17651
|
if (audioFile) {
|
|
17557
17652
|
if (audioFile.size > MAX_FILE_SIZE_BYTES) {
|
|
17558
17653
|
console.error(`[webchat:inbound] op=send-refused kind=voice reason=oversize bytes=${audioFile.size}`);
|
|
@@ -17565,14 +17660,6 @@ function createWebchatRoutes(deps) {
|
|
|
17565
17660
|
console.error(`[webchat:inbound] op=send-refused kind=voice reason=audio-store-failed detail=${detail}`);
|
|
17566
17661
|
return c.json({ error: "failed to store voice recording" }, 500);
|
|
17567
17662
|
}
|
|
17568
|
-
const result = await transcribeVoiceNote(audioFile, "admin");
|
|
17569
|
-
if (result.ok) {
|
|
17570
|
-
text = text.length > 0 ? `${text}
|
|
17571
|
-
|
|
17572
|
-
${result.result.text}` : result.result.text;
|
|
17573
|
-
} else {
|
|
17574
|
-
console.error(`[webchat:inbound] op=stt-failed kind=voice detail=${result.error}`);
|
|
17575
|
-
}
|
|
17576
17663
|
}
|
|
17577
17664
|
try {
|
|
17578
17665
|
for (const file of regularFiles) {
|
|
@@ -17588,51 +17675,87 @@ ${result.result.text}` : result.result.text;
|
|
|
17588
17675
|
const ext = dot >= 0 ? s.filename.slice(dot).toLowerCase() : "";
|
|
17589
17676
|
console.log(`[attach-ingest] mime=${s.mimeType} ext=${ext} converted=${!!s.readableTextPath} path=${s.storagePath}`);
|
|
17590
17677
|
}
|
|
17591
|
-
if (stored.length
|
|
17592
|
-
const listing = stored.map((s) => `${s.filename} (${s.readableTextPath ?? s.storagePath})`).join(", ");
|
|
17593
|
-
const note = `[The operator uploaded ${stored.length} file(s): ${listing}]`;
|
|
17594
|
-
text = text.length > 0 ? `${text}
|
|
17595
|
-
|
|
17596
|
-
${note}` : note;
|
|
17597
|
-
}
|
|
17598
|
-
if (text.length === 0) {
|
|
17678
|
+
if (text.length === 0 && stored.length === 0) {
|
|
17599
17679
|
console.error(`[webchat:inbound] op=send-refused kind=${kind} reason=empty-text`);
|
|
17600
17680
|
return c.json({ error: "text required" }, 400);
|
|
17601
17681
|
}
|
|
17602
|
-
console.log(`[webchat:inbound] op=send-parsed kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
17603
|
-
}
|
|
17604
|
-
if (target !== void 0 && await managerActivity(deliverySessionId) === "busy") {
|
|
17605
|
-
console.log(`[webchat:inbound] op=queued-busy sessionId=${deliverySessionId.slice(0, 8)} key=${deliveryKey}`);
|
|
17606
17682
|
}
|
|
17607
|
-
const adminUserId = requesterUserId ?? void 0;
|
|
17608
|
-
const inboundStartedAt = Date.now();
|
|
17609
|
-
const sendId = sendIdFromResolve ?? ++sendSeq;
|
|
17610
|
-
const replyContext = resolveQuoted(deliverySessionId, quotedUuid, sendId);
|
|
17611
|
-
const inbound = await deps.handleInbound({
|
|
17612
|
-
role: "admin",
|
|
17613
|
-
accountId: deliveryAccountId,
|
|
17614
|
-
key: deliveryKey,
|
|
17615
|
-
text,
|
|
17616
|
-
sessionId: deliverySessionId,
|
|
17617
|
-
adminUserId,
|
|
17618
|
-
...replyContext ? { replyContext } : {}
|
|
17619
|
-
});
|
|
17620
|
-
const turnSessionId = deliverySessionId;
|
|
17621
17683
|
const keyDisplay2 = deliveryKey.slice(0, "session:".length + 8);
|
|
17622
|
-
const
|
|
17623
|
-
|
|
17624
|
-
|
|
17625
|
-
|
|
17626
|
-
|
|
17627
|
-
|
|
17628
|
-
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
|
|
17684
|
+
const completeSend = async () => {
|
|
17685
|
+
if (isMultipart) {
|
|
17686
|
+
if (audioFile) {
|
|
17687
|
+
const result = await transcribeVoiceNote(audioFile, "admin");
|
|
17688
|
+
if (result.ok) {
|
|
17689
|
+
text = text.length > 0 ? `${text}
|
|
17690
|
+
|
|
17691
|
+
${result.result.text}` : result.result.text;
|
|
17692
|
+
} else {
|
|
17693
|
+
console.error(`[webchat:inbound] op=stt-failed kind=voice detail=${result.error}`);
|
|
17694
|
+
}
|
|
17695
|
+
}
|
|
17696
|
+
if (stored.length > 0) {
|
|
17697
|
+
const listing = stored.map((s) => `${s.filename} (${s.readableTextPath ?? s.storagePath})`).join(", ");
|
|
17698
|
+
const note = `[The operator uploaded ${stored.length} file(s): ${listing}]`;
|
|
17699
|
+
text = text.length > 0 ? `${text}
|
|
17700
|
+
|
|
17701
|
+
${note}` : note;
|
|
17702
|
+
}
|
|
17703
|
+
for (const s of stored) {
|
|
17704
|
+
const timeline = await extractWebchatVideo(s);
|
|
17705
|
+
if (timeline) text = `${text}
|
|
17706
|
+
|
|
17707
|
+
${timeline}`;
|
|
17708
|
+
}
|
|
17709
|
+
console.log(`[webchat:inbound] op=send-parsed kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
17633
17710
|
}
|
|
17634
|
-
|
|
17635
|
-
|
|
17711
|
+
if (target !== void 0 && await managerActivity(deliverySessionId) === "busy") {
|
|
17712
|
+
console.log(`[webchat:inbound] op=queued-busy sessionId=${deliverySessionId.slice(0, 8)} key=${deliveryKey}`);
|
|
17713
|
+
}
|
|
17714
|
+
const adminUserId = requesterUserId ?? void 0;
|
|
17715
|
+
const inboundStartedAt = Date.now();
|
|
17716
|
+
const replyContext = resolveQuoted(deliverySessionId, quotedUuid, sendId);
|
|
17717
|
+
const inbound = await deps.handleInbound({
|
|
17718
|
+
role: "admin",
|
|
17719
|
+
accountId: deliveryAccountId,
|
|
17720
|
+
key: deliveryKey,
|
|
17721
|
+
text,
|
|
17722
|
+
sessionId: deliverySessionId,
|
|
17723
|
+
adminUserId,
|
|
17724
|
+
...replyContext ? { replyContext } : {}
|
|
17725
|
+
});
|
|
17726
|
+
const turnSessionId = deliverySessionId;
|
|
17727
|
+
const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
|
|
17728
|
+
console.error(
|
|
17729
|
+
`[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"} acceptMs=${Date.now() - inboundStartedAt} spawn=${inbound.spawn !== null ? "triggered" : "none"}`
|
|
17730
|
+
);
|
|
17731
|
+
const turnTimer = setTimeout(() => {
|
|
17732
|
+
const now = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
|
|
17733
|
+
const grew = now !== null && (baseline === null || now > baseline);
|
|
17734
|
+
if (grew) {
|
|
17735
|
+
console.error(`[webchat:inbound] op=send-turned key=${keyDisplay2} sendId=${sendId} bytes=${now}`);
|
|
17736
|
+
} else {
|
|
17737
|
+
console.error(`[webchat:inbound] op=send-no-turn key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
|
|
17738
|
+
}
|
|
17739
|
+
}, WEBCHAT_SEND_TURN_WINDOW_MS);
|
|
17740
|
+
if (turnTimer.unref) turnTimer.unref();
|
|
17741
|
+
};
|
|
17742
|
+
const deferred = audioFile !== void 0 || stored.some((s) => isVideoMime(s.mimeType));
|
|
17743
|
+
if (deferred) {
|
|
17744
|
+
markTranscribing(deliveryKey);
|
|
17745
|
+
notify("webchat-pointer", deliveryAccountId);
|
|
17746
|
+
const stagedBytes = stored.reduce((n, s) => n + s.sizeBytes, 0);
|
|
17747
|
+
console.log(`[webchat:inbound] op=send-staged kind=${kind} key=${keyDisplay2} bytes=${stagedBytes}`);
|
|
17748
|
+
void completeSend().catch((err) => {
|
|
17749
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
17750
|
+
console.error(`[webchat:inbound] op=send-continuation-failed key=${keyDisplay2} detail=${detail}`);
|
|
17751
|
+
deps.markDeliveryFailure?.(deliveryKey, `send-${sendId}`);
|
|
17752
|
+
}).finally(() => {
|
|
17753
|
+
clearTranscribing(deliveryKey);
|
|
17754
|
+
notify("webchat-pointer", deliveryAccountId);
|
|
17755
|
+
});
|
|
17756
|
+
return c.json({ ok: true, transcribing: true });
|
|
17757
|
+
}
|
|
17758
|
+
await completeSend();
|
|
17636
17759
|
return c.json({ ok: true });
|
|
17637
17760
|
});
|
|
17638
17761
|
app81.post("/interrupt", requireAdminSession, async (c) => {
|
|
@@ -17742,7 +17865,7 @@ ${note}` : note;
|
|
|
17742
17865
|
}
|
|
17743
17866
|
const known = resolvedProjectDir !== null || sessionSidecarExists(target);
|
|
17744
17867
|
const indicators2 = await fetchComposerIndicators(target);
|
|
17745
|
-
return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${target}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${target}`) ?? null, ...indicators2, ...readLevers(scopeAccountId ? validateAccountId2(scopeAccountId) : null) });
|
|
17868
|
+
return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${target}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${target}`) ?? null, transcribing: isTranscribing(`session:${target}`), ...indicators2, ...readLevers(scopeAccountId ? validateAccountId2(scopeAccountId) : null) });
|
|
17746
17869
|
}
|
|
17747
17870
|
const account = scopeAccountId ? validateAccountId2(scopeAccountId) : null;
|
|
17748
17871
|
const { sessionId, source } = resolveCanonical(accountId, account?.accountDir ?? null, requesterUserId, primaryUserId, scopeAccountId, multiAccount);
|
|
@@ -17770,7 +17893,7 @@ ${note}` : note;
|
|
|
17770
17893
|
}
|
|
17771
17894
|
}
|
|
17772
17895
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
17773
|
-
return c.json({ sessionId, projectDir, source, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
|
|
17896
|
+
return c.json({ sessionId, projectDir, source, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, transcribing: isTranscribing(`session:${sessionId}`), ...indicators, ...readLevers(account) });
|
|
17774
17897
|
});
|
|
17775
17898
|
app81.post("/permission-verdict", requireAdminSession, async (c) => {
|
|
17776
17899
|
const body = await c.req.json().catch(() => null);
|
|
@@ -18997,7 +19120,7 @@ function routeTelegramUpdate(input) {
|
|
|
18997
19120
|
// app/lib/telegram/inbound/media.ts
|
|
18998
19121
|
var import_dist5 = __toESM(require_dist4(), 1);
|
|
18999
19122
|
import { join as join37 } from "path";
|
|
19000
|
-
var
|
|
19123
|
+
var TAG27 = "[telegram-inbound]";
|
|
19001
19124
|
var TELEGRAM_MEDIA_DIR = "/tmp/maxy-media";
|
|
19002
19125
|
var DOWNLOAD_TIMEOUT_MS = 45e3;
|
|
19003
19126
|
async function downloadTelegramMedia(input) {
|
|
@@ -19046,17 +19169,55 @@ async function downloadTelegramMedia(input) {
|
|
|
19046
19169
|
result = { ...base, failure: err instanceof Error ? err.message : String(err) };
|
|
19047
19170
|
}
|
|
19048
19171
|
console.error(
|
|
19049
|
-
`${
|
|
19172
|
+
`${TAG27} op=media-download botId=${input.botId} type=${item.type} ok=${result.path ? "yes" : "no"} bytes=${bytes} path=${result.path ?? "-"} reason=${result.failure ?? "-"}`
|
|
19050
19173
|
);
|
|
19051
19174
|
out.push(result);
|
|
19052
19175
|
}
|
|
19053
19176
|
return out;
|
|
19054
19177
|
}
|
|
19055
19178
|
|
|
19179
|
+
// app/lib/telegram/resolve-sender-name.ts
|
|
19180
|
+
var import_dist6 = __toESM(require_dist5(), 1);
|
|
19181
|
+
function composeName(row) {
|
|
19182
|
+
return [row.givenName ?? "", row.familyName ?? ""].join(" ").trim().replace(/\s+/g, " ");
|
|
19183
|
+
}
|
|
19184
|
+
function classifySenderName(rows) {
|
|
19185
|
+
if (rows.length > 1) return { kind: "ambiguous", count: rows.length };
|
|
19186
|
+
const first = rows[0];
|
|
19187
|
+
if (!first) return { kind: "none" };
|
|
19188
|
+
const display = composeName(first);
|
|
19189
|
+
return display.length > 0 ? { kind: "resolved", display } : { kind: "none" };
|
|
19190
|
+
}
|
|
19191
|
+
async function resolveTelegramSenderName(params) {
|
|
19192
|
+
if (!/^\d+$/.test(params.senderId)) return { verdict: { kind: "none" } };
|
|
19193
|
+
const telegramUserId = Number(params.senderId);
|
|
19194
|
+
if (!Number.isSafeInteger(telegramUserId)) return { verdict: { kind: "none" } };
|
|
19195
|
+
let session;
|
|
19196
|
+
try {
|
|
19197
|
+
session = getSession();
|
|
19198
|
+
const result = await session.run(
|
|
19199
|
+
`MATCH (p:Person {accountId: $accountId})
|
|
19200
|
+
WHERE p.telegramUserId = $telegramUserId AND ${(0, import_dist6.notTrashed)("p")}
|
|
19201
|
+
RETURN p.givenName AS givenName, p.familyName AS familyName`,
|
|
19202
|
+
{ accountId: params.accountId, telegramUserId },
|
|
19203
|
+
{ timeout: 2e3 }
|
|
19204
|
+
);
|
|
19205
|
+
const rows = result.records.map((r) => ({
|
|
19206
|
+
givenName: r.get("givenName") ?? null,
|
|
19207
|
+
familyName: r.get("familyName") ?? null
|
|
19208
|
+
}));
|
|
19209
|
+
return { verdict: classifySenderName(rows) };
|
|
19210
|
+
} catch (err) {
|
|
19211
|
+
return { verdict: { kind: "none" }, error: err instanceof Error ? err.message : String(err) };
|
|
19212
|
+
} finally {
|
|
19213
|
+
await session?.close();
|
|
19214
|
+
}
|
|
19215
|
+
}
|
|
19216
|
+
|
|
19056
19217
|
// app/lib/telegram/inbound/servable.ts
|
|
19057
19218
|
import { readFile as readFile6 } from "fs/promises";
|
|
19058
19219
|
import { basename as basename12 } from "path";
|
|
19059
|
-
var
|
|
19220
|
+
var TAG28 = "[telegram-inbound]";
|
|
19060
19221
|
async function storeTelegramServable(input) {
|
|
19061
19222
|
const out = [];
|
|
19062
19223
|
for (const [index, item] of input.media.entries()) {
|
|
@@ -19070,12 +19231,12 @@ async function storeTelegramServable(input) {
|
|
|
19070
19231
|
}
|
|
19071
19232
|
out.push(attachmentId);
|
|
19072
19233
|
console.error(
|
|
19073
|
-
`${
|
|
19234
|
+
`${TAG28} op=servable-store ok=true type=${item.type} id=${attachmentId}`
|
|
19074
19235
|
);
|
|
19075
19236
|
} catch (err) {
|
|
19076
19237
|
const reason = err instanceof Error ? err.message : String(err);
|
|
19077
19238
|
console.error(
|
|
19078
|
-
`${
|
|
19239
|
+
`${TAG28} op=servable-store ok=false type=${item.type} id=${attachmentId} reason=${reason.slice(0, 100)}`
|
|
19079
19240
|
);
|
|
19080
19241
|
}
|
|
19081
19242
|
}
|
|
@@ -19083,7 +19244,7 @@ async function storeTelegramServable(input) {
|
|
|
19083
19244
|
}
|
|
19084
19245
|
|
|
19085
19246
|
// app/lib/telegram/inbound/transcribe.ts
|
|
19086
|
-
var
|
|
19247
|
+
var TAG29 = "[telegram-inbound]";
|
|
19087
19248
|
async function transcribeTelegramAudio(input) {
|
|
19088
19249
|
const doTranscribe = input.transcribeImpl ?? transcribe;
|
|
19089
19250
|
const out = [];
|
|
@@ -19095,7 +19256,7 @@ async function transcribeTelegramAudio(input) {
|
|
|
19095
19256
|
}
|
|
19096
19257
|
if (!m.path) {
|
|
19097
19258
|
console.error(
|
|
19098
|
-
`${
|
|
19259
|
+
`${TAG29} op=transcribe botId=${input.botId} ok=no chars=0 ms=0 reason=${m.failure ?? "no local file"}`
|
|
19099
19260
|
);
|
|
19100
19261
|
out.push(m);
|
|
19101
19262
|
continue;
|
|
@@ -19112,7 +19273,7 @@ async function transcribeTelegramAudio(input) {
|
|
|
19112
19273
|
reason = err instanceof Error ? err.message : String(err);
|
|
19113
19274
|
}
|
|
19114
19275
|
console.error(
|
|
19115
|
-
`${
|
|
19276
|
+
`${TAG29} op=transcribe botId=${input.botId} ok=${heard ? "yes" : "no"} chars=${heard?.length ?? 0} ms=${Date.now() - startedMs} reason=${reason}`
|
|
19116
19277
|
);
|
|
19117
19278
|
if (heard) {
|
|
19118
19279
|
transcripts.push(heard);
|
|
@@ -19129,6 +19290,33 @@ async function transcribeTelegramAudio(input) {
|
|
|
19129
19290
|
${body}` : body, media: out };
|
|
19130
19291
|
}
|
|
19131
19292
|
|
|
19293
|
+
// app/lib/telegram/inbound/video.ts
|
|
19294
|
+
var TAG30 = "[telegram-inbound]";
|
|
19295
|
+
async function extractTelegramVideo(input) {
|
|
19296
|
+
const doExtract = input.extractImpl ?? extractVideo;
|
|
19297
|
+
const out = [];
|
|
19298
|
+
for (const m of input.media) {
|
|
19299
|
+
if (m.type !== "video" || !m.path) {
|
|
19300
|
+
out.push(m);
|
|
19301
|
+
continue;
|
|
19302
|
+
}
|
|
19303
|
+
const startedMs = Date.now();
|
|
19304
|
+
let timeline;
|
|
19305
|
+
let reason = "-";
|
|
19306
|
+
try {
|
|
19307
|
+
timeline = await doExtract(m.path, m.mimetype ?? "");
|
|
19308
|
+
if (!timeline) reason = "no timeline returned";
|
|
19309
|
+
} catch (err) {
|
|
19310
|
+
reason = err instanceof Error ? err.message : String(err);
|
|
19311
|
+
}
|
|
19312
|
+
console.error(
|
|
19313
|
+
`${TAG30} op=video-extract botId=${input.botId} ok=${timeline ? "yes" : "no"} chars=${timeline?.length ?? 0} ms=${Date.now() - startedMs} reason=${reason}`
|
|
19314
|
+
);
|
|
19315
|
+
out.push(timeline ? { ...m, timeline } : m);
|
|
19316
|
+
}
|
|
19317
|
+
return { media: out };
|
|
19318
|
+
}
|
|
19319
|
+
|
|
19132
19320
|
// app/lib/telegram/gateway/telegram-inbound-census.ts
|
|
19133
19321
|
var ANSWER_THRESHOLD_MS = 3e4;
|
|
19134
19322
|
var GAP_NAME_LIMIT2 = 10;
|
|
@@ -19195,7 +19383,7 @@ function runTelegramNotifyReconcile(now) {
|
|
|
19195
19383
|
}
|
|
19196
19384
|
|
|
19197
19385
|
// server/routes/telegram.ts
|
|
19198
|
-
var
|
|
19386
|
+
var import_dist9 = __toESM(require_dist6(), 1);
|
|
19199
19387
|
|
|
19200
19388
|
// app/lib/telegram/outbound/answer-callback.ts
|
|
19201
19389
|
async function answerTelegramCallback(botToken, callbackQueryId, text) {
|
|
@@ -19289,7 +19477,7 @@ function runTelegramNotifyPublishCensus(now) {
|
|
|
19289
19477
|
}
|
|
19290
19478
|
|
|
19291
19479
|
// ../lib/dispatch-write/src/lifecycle.ts
|
|
19292
|
-
var
|
|
19480
|
+
var import_dist7 = __toESM(require_dist7());
|
|
19293
19481
|
function checkTransition(kind, from, to, cfg) {
|
|
19294
19482
|
const edges = kind === "job" ? cfg.statuses.jobTransitions : cfg.statuses.visitTransitions;
|
|
19295
19483
|
const legal = edges.some(([f, t]) => f === from && t === to);
|
|
@@ -19319,7 +19507,7 @@ function firstMissingRequiredField(toStatus, cfg, state) {
|
|
|
19319
19507
|
const required = cfg.records.requiredBeforeTerminal[toStatus];
|
|
19320
19508
|
if (!required) return null;
|
|
19321
19509
|
for (const field2 of required) {
|
|
19322
|
-
if (!
|
|
19510
|
+
if (!import_dist7.RECORDABLE_FIELDS.includes(field2)) continue;
|
|
19323
19511
|
if (!fieldSatisfied(field2, state)) {
|
|
19324
19512
|
return field2;
|
|
19325
19513
|
}
|
|
@@ -19331,12 +19519,12 @@ function formatTransitionRefused(p) {
|
|
|
19331
19519
|
}
|
|
19332
19520
|
|
|
19333
19521
|
// ../lib/dispatch-write/src/write.ts
|
|
19334
|
-
var
|
|
19522
|
+
var import_dist8 = __toESM(require_dist7());
|
|
19335
19523
|
function refuse(reason, message) {
|
|
19336
19524
|
return { ok: false, reason, message };
|
|
19337
19525
|
}
|
|
19338
19526
|
async function visitRecord(p) {
|
|
19339
|
-
const visit = await (0,
|
|
19527
|
+
const visit = await (0, import_dist8.readVisit)(p.session, p.accountId, p.visitId);
|
|
19340
19528
|
if (!visit) {
|
|
19341
19529
|
return refuse(
|
|
19342
19530
|
"not-found",
|
|
@@ -19433,7 +19621,7 @@ async function visitRecord(p) {
|
|
|
19433
19621
|
arrivalParams
|
|
19434
19622
|
);
|
|
19435
19623
|
}
|
|
19436
|
-
const state = await (0,
|
|
19624
|
+
const state = await (0, import_dist8.readVisitRecordState)(p.session, p.accountId, p.visitId);
|
|
19437
19625
|
p.emit(
|
|
19438
19626
|
`[dispatch] op=visit-record visitId=${p.visitId} notes=${state.notes} media=${state.media} parts=${state.parts} checklist=${state.checklistDone}/${state.checklistTotal} signatures=${state.signatures}`
|
|
19439
19627
|
);
|
|
@@ -19446,7 +19634,7 @@ async function visitRecord(p) {
|
|
|
19446
19634
|
`[dispatch] op=arrival-observed visitId=${p.visitId} distanceM=${p.arrivedObservedDistanceM ?? "none"} observedAt=${p.arrivedObservedAt} pressedAt=${pressedAt ?? "none"} deltaS=${deltaS ?? "none"}`
|
|
19447
19635
|
);
|
|
19448
19636
|
}
|
|
19449
|
-
const after = await (0,
|
|
19637
|
+
const after = await (0, import_dist8.readVisit)(p.session, p.accountId, p.visitId);
|
|
19450
19638
|
return {
|
|
19451
19639
|
ok: true,
|
|
19452
19640
|
value: {
|
|
@@ -19461,7 +19649,7 @@ async function visitRecord(p) {
|
|
|
19461
19649
|
};
|
|
19462
19650
|
}
|
|
19463
19651
|
async function visitStatusSet(p) {
|
|
19464
|
-
const visit = await (0,
|
|
19652
|
+
const visit = await (0, import_dist8.readVisit)(p.session, p.accountId, p.visitId);
|
|
19465
19653
|
if (!visit) {
|
|
19466
19654
|
return refuse(
|
|
19467
19655
|
"not-found",
|
|
@@ -19501,7 +19689,7 @@ async function visitStatusSet(p) {
|
|
|
19501
19689
|
`This account allows no move from "${visit.status}" to "${p.to}". From "${visit.status}" it allows: ${legalNext.join(", ") || "nothing"}.`
|
|
19502
19690
|
);
|
|
19503
19691
|
}
|
|
19504
|
-
const state = await (0,
|
|
19692
|
+
const state = await (0, import_dist8.readVisitRecordState)(p.session, p.accountId, p.visitId);
|
|
19505
19693
|
const missing = firstMissingRequiredField(p.to, p.cfg, state);
|
|
19506
19694
|
if (missing) {
|
|
19507
19695
|
p.emit(
|
|
@@ -19530,7 +19718,7 @@ async function visitStatusSet(p) {
|
|
|
19530
19718
|
);
|
|
19531
19719
|
let jobClosed = null;
|
|
19532
19720
|
if (terminal && visit.jobId) {
|
|
19533
|
-
const siblings = await (0,
|
|
19721
|
+
const siblings = await (0, import_dist8.readVisitsForJob)(p.session, p.accountId, visit.jobId);
|
|
19534
19722
|
const allTerminal = siblings.every(
|
|
19535
19723
|
(v) => v.visitId === p.visitId || isTerminal("visit", v.status, p.cfg)
|
|
19536
19724
|
);
|
|
@@ -19571,7 +19759,7 @@ async function visitStatusSet(p) {
|
|
|
19571
19759
|
}
|
|
19572
19760
|
|
|
19573
19761
|
// app/lib/telegram/dispatch/press.ts
|
|
19574
|
-
var
|
|
19762
|
+
var TAG31 = "[dispatch-tg]";
|
|
19575
19763
|
function logValue(v) {
|
|
19576
19764
|
return v.replace(/[\r\n]+/g, " ");
|
|
19577
19765
|
}
|
|
@@ -19632,12 +19820,12 @@ async function handleDispatchPress(p) {
|
|
|
19632
19820
|
status: ${status}`;
|
|
19633
19821
|
const done = await p.edit(p.token, p.chatId, p.messageId, text, toBotApiKeyboard(kb.rows));
|
|
19634
19822
|
p.emit(
|
|
19635
|
-
`${
|
|
19823
|
+
`${TAG31} op=card-redrawn visitId=${logVisitId} messageId=${p.messageId} buttons=${kb.rows.flat().length} drawnFor=${logValue(status)}` + (done.ok ? "" : ` editError="${logValue(done.error ?? "unknown")}"`)
|
|
19636
19824
|
);
|
|
19637
19825
|
};
|
|
19638
19826
|
if (visit.status !== parsed.drawnFor) {
|
|
19639
19827
|
p.emit(
|
|
19640
|
-
`${
|
|
19828
|
+
`${TAG31} op=callback-stale updateId=${u} visitId=${logVisitId} expected=${logDrawnFor} actual=${logValue(visit.status)}`
|
|
19641
19829
|
);
|
|
19642
19830
|
await redraw(visit.status);
|
|
19643
19831
|
return {
|
|
@@ -19664,7 +19852,7 @@ status: ${status}`;
|
|
|
19664
19852
|
return { kind: "refused", reason: out.reason, answer: out.message };
|
|
19665
19853
|
}
|
|
19666
19854
|
p.emit(
|
|
19667
|
-
`${
|
|
19855
|
+
`${TAG31} op=callback-applied updateId=${u} visitId=${logVisitId} from=${logValue(out.value.from)} to=${logValue(out.value.to)} tool=dispatch-visit-status-set ms=${Date.now() - startedAt}`
|
|
19668
19856
|
);
|
|
19669
19857
|
await redraw(out.value.to);
|
|
19670
19858
|
return {
|
|
@@ -19691,7 +19879,7 @@ async function bindChatToVisit(p) {
|
|
|
19691
19879
|
}
|
|
19692
19880
|
|
|
19693
19881
|
// app/lib/telegram/dispatch/location.ts
|
|
19694
|
-
var
|
|
19882
|
+
var TAG32 = "[dispatch-tg]";
|
|
19695
19883
|
async function handleDispatchLocation(p) {
|
|
19696
19884
|
const bound = await bindChatToVisit({
|
|
19697
19885
|
session: p.session,
|
|
@@ -19708,7 +19896,7 @@ async function handleDispatchLocation(p) {
|
|
|
19708
19896
|
at: { latitude: p.latitude, longitude: p.longitude }
|
|
19709
19897
|
});
|
|
19710
19898
|
p.emit(
|
|
19711
|
-
`${
|
|
19899
|
+
`${TAG32} op=location-update visitId=${bound.visit.visitId} workerId=${bound.worker.workerId} distanceM=${v.distanceM ?? "none"} inside=${v.inside} siteHasCoords=${v.siteHasCoords} radiusM=${v.radiusM ?? "none"}`
|
|
19712
19900
|
);
|
|
19713
19901
|
if (!v.siteHasCoords) return { kind: "no-coords" };
|
|
19714
19902
|
if (v.radiusM === null) return { kind: "no-radius" };
|
|
@@ -19726,12 +19914,12 @@ async function handleDispatchLocation(p) {
|
|
|
19726
19914
|
});
|
|
19727
19915
|
if (!rec.ok) {
|
|
19728
19916
|
p.emit(
|
|
19729
|
-
`${
|
|
19917
|
+
`${TAG32} op=geofence-refused visitId=${bound.visit.visitId} workerId=${bound.worker.workerId} distanceM=${v.distanceM} reason=${rec.reason}`
|
|
19730
19918
|
);
|
|
19731
19919
|
return { kind: "not-recorded" };
|
|
19732
19920
|
}
|
|
19733
19921
|
p.emit(
|
|
19734
|
-
`${
|
|
19922
|
+
`${TAG32} op=geofence-enter visitId=${bound.visit.visitId} observedAt=${observedAt} distanceM=${v.distanceM} pressedAt=${bound.visit.arrivedPressedAt ?? "none"}`
|
|
19735
19923
|
);
|
|
19736
19924
|
return { kind: "recorded" };
|
|
19737
19925
|
}
|
|
@@ -19763,7 +19951,7 @@ function readTgActivity(accountId) {
|
|
|
19763
19951
|
}
|
|
19764
19952
|
|
|
19765
19953
|
// app/lib/telegram/dispatch/media.ts
|
|
19766
|
-
var
|
|
19954
|
+
var TAG33 = "[dispatch-tg]";
|
|
19767
19955
|
async function handleDispatchMedia(p) {
|
|
19768
19956
|
const bound = await bindChatToVisit({
|
|
19769
19957
|
session: p.session,
|
|
@@ -19774,14 +19962,14 @@ async function handleDispatchMedia(p) {
|
|
|
19774
19962
|
if (bound.kind !== "bound") {
|
|
19775
19963
|
const tell = bound.kind === "no-open-visit" ? `You have no open ${p.cfg.vocabulary.visit}, so I have kept this in the chat. Open one and send it again.` : bound.kind === "many-open-visits" ? `You have ${bound.visits.length} open ${p.cfg.vocabulary.visit}s, so I have kept this in the chat rather than guessing. Open the one you mean in the job sheet and send it there.` : null;
|
|
19776
19964
|
p.emit(
|
|
19777
|
-
`${
|
|
19965
|
+
`${TAG33} op=unbound-inbound chatId=${p.telegramUserId} kind=${p.kind} reason=${bound.kind} told=${tell !== null}`
|
|
19778
19966
|
);
|
|
19779
19967
|
return { kind: "unattached", reason: bound.kind, tell };
|
|
19780
19968
|
}
|
|
19781
19969
|
const visitId = bound.visit.visitId;
|
|
19782
19970
|
if (p.kind === "voice") {
|
|
19783
19971
|
p.emit(
|
|
19784
|
-
`${
|
|
19972
|
+
`${TAG33} op=voice-received visitId=${visitId} durationS=${p.durationS ?? "none"} bytes=${p.bytes ?? "none"}`
|
|
19785
19973
|
);
|
|
19786
19974
|
noteVoiceReceived(p.accountId, visitId);
|
|
19787
19975
|
if (p.transcript === null || p.transcript.length === 0) {
|
|
@@ -19801,7 +19989,7 @@ async function handleDispatchMedia(p) {
|
|
|
19801
19989
|
note: p.transcript
|
|
19802
19990
|
});
|
|
19803
19991
|
p.emit(
|
|
19804
|
-
`${
|
|
19992
|
+
`${TAG33} op=voice-transcribed visitId=${visitId} chars=${p.transcript.length} ms=${Date.now() - startedAt}`
|
|
19805
19993
|
);
|
|
19806
19994
|
noteVoiceTranscribed(p.accountId, visitId);
|
|
19807
19995
|
return { kind: "note", visitId };
|
|
@@ -19821,14 +20009,14 @@ async function handleDispatchMedia(p) {
|
|
|
19821
20009
|
visitId,
|
|
19822
20010
|
mediaRef: p.path
|
|
19823
20011
|
});
|
|
19824
|
-
p.emit(`${
|
|
20012
|
+
p.emit(`${TAG33} op=media-attached visitId=${visitId} kind=${p.kind} path=${p.path}`);
|
|
19825
20013
|
return { kind: "media", visitId };
|
|
19826
20014
|
}
|
|
19827
20015
|
|
|
19828
20016
|
// app/lib/telegram/live-location.ts
|
|
19829
20017
|
import { existsSync as existsSync26, mkdirSync as mkdirSync6, readFileSync as readFileSync30, readdirSync as readdirSync20, statSync as statSync19, writeFileSync as writeFileSync13 } from "fs";
|
|
19830
20018
|
import { join as join38 } from "path";
|
|
19831
|
-
var
|
|
20019
|
+
var TAG34 = "[telegram-inbound]";
|
|
19832
20020
|
var LIVE_LOCATION_FILE = "telegram-live-location.json";
|
|
19833
20021
|
var LIVE_LOCATION_CENSUS_TAG = "[telegram-live-location-census]";
|
|
19834
20022
|
function liveLocationKey(botId, senderId) {
|
|
@@ -19864,12 +20052,12 @@ function writeLiveLocation(input) {
|
|
|
19864
20052
|
const livePeriodS = input.livePeriodS ?? stored[key2]?.livePeriodS ?? null;
|
|
19865
20053
|
if (livePeriodS === null) {
|
|
19866
20054
|
emit(
|
|
19867
|
-
`${
|
|
20055
|
+
`${TAG34} op=live-location op=skipped-write senderId=${senderId} botId=${botId} reason=no-live-period`
|
|
19868
20056
|
);
|
|
19869
20057
|
return { written: false, reason: "no-live-period" };
|
|
19870
20058
|
}
|
|
19871
20059
|
if (input.atS === null) {
|
|
19872
|
-
emit(`${
|
|
20060
|
+
emit(`${TAG34} op=live-location op=skipped-write senderId=${senderId} botId=${botId} reason=no-date`);
|
|
19873
20061
|
return { written: false, reason: "no-date" };
|
|
19874
20062
|
}
|
|
19875
20063
|
const next = {
|
|
@@ -19887,7 +20075,7 @@ function writeLiveLocation(input) {
|
|
|
19887
20075
|
mkdirSync6(accountDir, { recursive: true });
|
|
19888
20076
|
writeFileSync13(path, JSON.stringify(kept, null, 2) + "\n", "utf-8");
|
|
19889
20077
|
emit(
|
|
19890
|
-
`${
|
|
20078
|
+
`${TAG34} op=live-location op=updated senderId=${senderId} botId=${botId} ageMs=${now - next.at} livePeriodS=${livePeriodS}`
|
|
19891
20079
|
);
|
|
19892
20080
|
return { written: true };
|
|
19893
20081
|
}
|
|
@@ -19931,7 +20119,7 @@ function liveLocationCensusLine(accountsRoot, now) {
|
|
|
19931
20119
|
// app/lib/telegram/business-connection.ts
|
|
19932
20120
|
import { existsSync as existsSync27, mkdirSync as mkdirSync7, readFileSync as readFileSync31, writeFileSync as writeFileSync14 } from "fs";
|
|
19933
20121
|
import { join as join39 } from "path";
|
|
19934
|
-
var
|
|
20122
|
+
var TAG35 = "[telegram-inbound]";
|
|
19935
20123
|
var BUSINESS_CONNECTION_FILE = "telegram-business-connection.json";
|
|
19936
20124
|
function truncateConnectionId(id) {
|
|
19937
20125
|
return `${id.slice(0, 6)}\u2026`;
|
|
@@ -19964,7 +20152,7 @@ function writeBusinessConnection(input) {
|
|
|
19964
20152
|
const canReply = rights?.can_reply === true;
|
|
19965
20153
|
const say = (stored, reason) => {
|
|
19966
20154
|
emit(
|
|
19967
|
-
`${
|
|
20155
|
+
`${TAG35} op=business-connection botId=${botId} connectionId=${id === null ? "none" : truncateConnectionId(id)} userId=${userId ?? "none"} isEnabled=${isEnabled} canReply=${canReply} stored=${stored} reason=${reason}`
|
|
19968
20156
|
);
|
|
19969
20157
|
};
|
|
19970
20158
|
if (id === null) {
|
|
@@ -20043,7 +20231,7 @@ async function editTelegramMessage(botToken, chatId, messageId, text, keyboard)
|
|
|
20043
20231
|
}
|
|
20044
20232
|
|
|
20045
20233
|
// server/routes/telegram.ts
|
|
20046
|
-
var
|
|
20234
|
+
var TAG36 = "[telegram-inbound]";
|
|
20047
20235
|
var PROVISION_TAG = "[telegram-provision]";
|
|
20048
20236
|
function entryActive(entry3, accountDir, botId, noteSpecialist) {
|
|
20049
20237
|
if (entry3.role === "admin") return true;
|
|
@@ -20053,7 +20241,7 @@ function entryActive(entry3, accountDir, botId, noteSpecialist) {
|
|
|
20053
20241
|
noteSpecialist?.(rosterValid);
|
|
20054
20242
|
if (rosterValid) return true;
|
|
20055
20243
|
console.error(
|
|
20056
|
-
`${
|
|
20244
|
+
`${TAG36} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=specialist-unknown`
|
|
20057
20245
|
);
|
|
20058
20246
|
return false;
|
|
20059
20247
|
}
|
|
@@ -20104,13 +20292,13 @@ function accountConfig(accountDir) {
|
|
|
20104
20292
|
function raiseChannelTurn(input) {
|
|
20105
20293
|
if (!input.active) {
|
|
20106
20294
|
console.error(
|
|
20107
|
-
`${
|
|
20295
|
+
`${TAG36} op=reject reason=agent-inactive botId=${input.botId} agent=${input.agentSlug}`
|
|
20108
20296
|
);
|
|
20109
20297
|
return;
|
|
20110
20298
|
}
|
|
20111
20299
|
const gateway = getTelegramGateway();
|
|
20112
20300
|
if (!gateway) {
|
|
20113
|
-
console.error(`${
|
|
20301
|
+
console.error(`${TAG36} op=reply-dropped botId=${input.botId} reason=gateway-not-ready`);
|
|
20114
20302
|
return;
|
|
20115
20303
|
}
|
|
20116
20304
|
const reply = async (replyText) => {
|
|
@@ -20131,8 +20319,8 @@ function raiseChannelTurn(input) {
|
|
|
20131
20319
|
origin: "agent",
|
|
20132
20320
|
createdAt: at
|
|
20133
20321
|
});
|
|
20134
|
-
console.error(`${
|
|
20135
|
-
} else console.error(`${
|
|
20322
|
+
console.error(`${TAG36} op=reply-sent botId=${input.botId} ok=true`);
|
|
20323
|
+
} else console.error(`${TAG36} op=reply-dropped botId=${input.botId} reason=${sent.error}`);
|
|
20136
20324
|
};
|
|
20137
20325
|
void gateway.handleInbound({
|
|
20138
20326
|
accountId: input.accountId,
|
|
@@ -20157,34 +20345,34 @@ var app11 = new Hono();
|
|
|
20157
20345
|
app11.post("/", async (c) => {
|
|
20158
20346
|
const botId = c.req.query("bot");
|
|
20159
20347
|
if (!botId) {
|
|
20160
|
-
console.error(`${
|
|
20348
|
+
console.error(`${TAG36} op=reject reason=missing-bot-param`);
|
|
20161
20349
|
return c.json({ ok: false }, 400);
|
|
20162
20350
|
}
|
|
20163
|
-
console.error(`${
|
|
20351
|
+
console.error(`${TAG36} op=received botId=${botId} path=/api/telegram/`);
|
|
20164
20352
|
const resolved = resolveBotEntry(listValidAccounts(), botId);
|
|
20165
20353
|
if (resolved.kind === "none") {
|
|
20166
|
-
console.error(`${
|
|
20354
|
+
console.error(`${TAG36} op=reject reason=unknown-bot botId=${botId}`);
|
|
20167
20355
|
return c.json({ ok: false }, 401);
|
|
20168
20356
|
}
|
|
20169
20357
|
if (resolved.kind === "duplicate") {
|
|
20170
|
-
console.error(`${
|
|
20358
|
+
console.error(`${TAG36} op=reject reason=duplicate-bot-id botId=${botId} accounts=${resolved.count}`);
|
|
20171
20359
|
return c.json({ ok: false }, 401);
|
|
20172
20360
|
}
|
|
20173
20361
|
const { accountId, accountDir, entry: entry3 } = resolved;
|
|
20174
20362
|
const agentSlug = entryAgentSlug(entry3);
|
|
20175
|
-
console.error(`${
|
|
20363
|
+
console.error(`${TAG36} op=entry botId=${botId} accountId=${accountId} role=${entry3.role} agent=${agentSlug}`);
|
|
20176
20364
|
const sp = secretPath(botId);
|
|
20177
20365
|
if (!existsSync28(sp)) {
|
|
20178
|
-
console.error(`${
|
|
20366
|
+
console.error(`${TAG36} op=secret botId=${botId} result=missing-file`);
|
|
20179
20367
|
return c.json({ ok: false }, 401);
|
|
20180
20368
|
}
|
|
20181
20369
|
const expected = readFileSync32(sp, "utf-8").trim();
|
|
20182
20370
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
20183
20371
|
if (got !== expected) {
|
|
20184
|
-
console.error(`${
|
|
20372
|
+
console.error(`${TAG36} op=secret botId=${botId} result=mismatch`);
|
|
20185
20373
|
return c.json({ ok: false }, 401);
|
|
20186
20374
|
}
|
|
20187
|
-
console.error(`${
|
|
20375
|
+
console.error(`${TAG36} op=secret botId=${botId} result=ok`);
|
|
20188
20376
|
let update;
|
|
20189
20377
|
try {
|
|
20190
20378
|
update = await c.req.json();
|
|
@@ -20193,7 +20381,7 @@ app11.post("/", async (c) => {
|
|
|
20193
20381
|
}
|
|
20194
20382
|
const shape = describeTelegramUpdate(update);
|
|
20195
20383
|
console.error(
|
|
20196
|
-
`${
|
|
20384
|
+
`${TAG36} op=inbound-kind botId=${botId} update=${shape.envelope} content=${shape.content} chatType=${shape.chatType} isEdit=${shape.isEdit ? "yes" : "no"}`
|
|
20197
20385
|
);
|
|
20198
20386
|
if (update.business_connection) {
|
|
20199
20387
|
writeBusinessConnection({
|
|
@@ -20207,13 +20395,13 @@ app11.post("/", async (c) => {
|
|
|
20207
20395
|
if (shape.chatType === "group" || shape.chatType === "supergroup") {
|
|
20208
20396
|
const allowlisted = entry3.role === "public" && (entry3.groupPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry3.allowGroups ?? []).includes(shape.chatId);
|
|
20209
20397
|
console.error(
|
|
20210
|
-
`${
|
|
20398
|
+
`${TAG36} op=group-inbound botId=${botId} chatType=${shape.chatType} chatId=${shape.chatId ?? "none"} senderId=${shape.senderId ?? "none"} threadId=${shape.threadId ?? "none"} allowlisted=${allowlisted ? "yes" : "no"}`
|
|
20211
20399
|
);
|
|
20212
20400
|
}
|
|
20213
20401
|
if (shape.chatType === "channel") {
|
|
20214
20402
|
const allowlisted = entry3.role === "public" && (entry3.channelPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry3.allowChannels ?? []).includes(shape.chatId);
|
|
20215
20403
|
console.error(
|
|
20216
|
-
`${
|
|
20404
|
+
`${TAG36} op=channel-post botId=${botId} chatId=${shape.chatId ?? "none"} messageId=${shape.messageId ?? "none"} senderChat=${shape.senderChat ?? "none"} isEdit=${shape.isEdit ? "yes" : "no"} allowlisted=${allowlisted ? "yes" : "no"}`
|
|
20217
20405
|
);
|
|
20218
20406
|
}
|
|
20219
20407
|
const hostBots = update.managed_bot ? listBotEntries(accountConfig(accountDir).telegram) : [];
|
|
@@ -20234,56 +20422,68 @@ app11.post("/", async (c) => {
|
|
|
20234
20422
|
decision.kind === "managed-bot" && decision.authorised && decision.event === "created";
|
|
20235
20423
|
noteInboundKind(shape.primaryKind, raisesTurn, shape.envelope);
|
|
20236
20424
|
if (decision.kind === "ignore") {
|
|
20237
|
-
console.error(`${
|
|
20425
|
+
console.error(`${TAG36} op=ignore botId=${botId} reason=${decision.reason}`);
|
|
20238
20426
|
return c.json({ ok: true }, 200);
|
|
20239
20427
|
}
|
|
20240
20428
|
if (decision.kind === "denied") {
|
|
20241
20429
|
if (decision.reason === "admin-entry-no-groups" || decision.reason === "not-in-allowGroups" || decision.reason === "group-policy-disabled") {
|
|
20242
20430
|
console.error(
|
|
20243
|
-
`${
|
|
20431
|
+
`${TAG36} op=group-refused botId=${botId} chatId=${shape.chatId ?? "none"} reason=${decision.reason}`
|
|
20244
20432
|
);
|
|
20245
20433
|
}
|
|
20246
20434
|
if (decision.reason === "admin-entry-no-channels" || decision.reason === "specialist-entry-no-channels" || decision.reason === "unbound-entry-no-channels" || decision.reason === "not-in-allowChannels" || decision.reason === "channel-policy-disabled") {
|
|
20247
20435
|
console.error(
|
|
20248
|
-
`${
|
|
20436
|
+
`${TAG36} op=channel-refused botId=${botId} chatId=${shape.chatId ?? "none"} reason=${decision.reason}`
|
|
20249
20437
|
);
|
|
20250
20438
|
}
|
|
20251
|
-
console.error(`${
|
|
20439
|
+
console.error(`${TAG36} op=access botId=${botId} senderId=- allowed=false reason=${decision.reason}`);
|
|
20252
20440
|
if (entry3.role === "specialist") {
|
|
20253
20441
|
console.error(
|
|
20254
|
-
`${
|
|
20442
|
+
`${TAG36} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=${decision.reason}`
|
|
20255
20443
|
);
|
|
20256
20444
|
}
|
|
20257
20445
|
return c.json({ ok: true }, 200);
|
|
20258
20446
|
}
|
|
20259
20447
|
if (!isBindableEntry(entry3)) {
|
|
20260
|
-
console.error(`${
|
|
20448
|
+
console.error(`${TAG36} op=ignore botId=${botId} reason=bot-unbound`);
|
|
20261
20449
|
return c.json({ ok: true }, 200);
|
|
20262
20450
|
}
|
|
20451
|
+
const decisionSenderId = "senderId" in decision ? decision.senderId : void 0;
|
|
20452
|
+
const decisionSenderDisplay = "senderDisplay" in decision ? decision.senderDisplay : void 0;
|
|
20453
|
+
let provenanceDisplay = decisionSenderDisplay;
|
|
20454
|
+
if (entry3.role === "admin" && typeof decisionSenderId === "string" && decisionSenderId.length > 0) {
|
|
20455
|
+
const startedMs = Date.now();
|
|
20456
|
+
const { verdict, error } = await resolveTelegramSenderName({ accountId, senderId: decisionSenderId });
|
|
20457
|
+
const source = verdict.kind === "resolved" ? "contact" : typeof decisionSenderDisplay === "string" && decisionSenderDisplay.length > 0 ? "profile" : "id";
|
|
20458
|
+
if (verdict.kind === "resolved") provenanceDisplay = verdict.display;
|
|
20459
|
+
console.error(
|
|
20460
|
+
`[telegram:reframe] op=sender-name senderId=${decisionSenderId} accountId=${accountId.slice(0, 8)} source=${source} resolvedMs=${Date.now() - startedMs}` + (verdict.kind === "ambiguous" ? ` reason=ambiguous count=${verdict.count}` : "") + (error ? ` error=${error}` : "")
|
|
20461
|
+
);
|
|
20462
|
+
}
|
|
20263
20463
|
if (decision.kind === "chat-member") {
|
|
20264
20464
|
console.error(
|
|
20265
|
-
`${
|
|
20465
|
+
`${TAG36} op=chat-member-group botId=${botId} chatId=${decision.chatId} userId=${decision.userId || "none"} status=${logValue2(decision.status)}`
|
|
20266
20466
|
);
|
|
20267
20467
|
return c.json({ ok: true }, 200);
|
|
20268
20468
|
}
|
|
20269
20469
|
if (decision.kind === "recorded") {
|
|
20270
20470
|
console.error(
|
|
20271
|
-
`${
|
|
20471
|
+
`${TAG36} op=recorded botId=${botId} envelope=${decision.envelope} chatId=${decision.chatId ?? "none"} messageId=${decision.messageId ?? "none"}`
|
|
20272
20472
|
);
|
|
20273
20473
|
return c.json({ ok: true }, 200);
|
|
20274
20474
|
}
|
|
20275
20475
|
if (decision.kind === "comment-root") {
|
|
20276
20476
|
console.error(
|
|
20277
|
-
`${
|
|
20477
|
+
`${TAG36} op=channel-comment-root botId=${botId} groupChatId=${decision.groupChatId} rootMessageId=${decision.rootMessageId} channelChatId=${decision.channelChatId}`
|
|
20278
20478
|
);
|
|
20279
20479
|
return c.json({ ok: true }, 200);
|
|
20280
20480
|
}
|
|
20281
20481
|
if (decision.kind === "callback") {
|
|
20282
20482
|
console.error(
|
|
20283
|
-
`${
|
|
20483
|
+
`${TAG36} op=callback-received botId=${botId} callbackId=${decision.callbackId} chatId=${decision.chatId} messageId=${decision.messageId ?? "none"} data=${decision.data === null ? "none" : logValue2(decision.data)}`
|
|
20284
20484
|
);
|
|
20285
20485
|
console.error(
|
|
20286
|
-
`${
|
|
20486
|
+
`${TAG36} op=callback-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
|
|
20287
20487
|
);
|
|
20288
20488
|
const cbSubject = telegramConversationSubject(decision.chatType, decision.chatId, decision.senderId);
|
|
20289
20489
|
if (decision.allowed) {
|
|
@@ -20291,12 +20491,12 @@ app11.post("/", async (c) => {
|
|
|
20291
20491
|
const cbAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20292
20492
|
let cbBody = `[button: ${decision.data ?? "no-data"}]`;
|
|
20293
20493
|
if (decision.data !== null) {
|
|
20294
|
-
const label = (0,
|
|
20494
|
+
const label = (0, import_dist9.readButtonLabel)(accountDir, (0, import_dist9.buttonLabelKey)(botId, decision.chatId, decision.data));
|
|
20295
20495
|
if (label !== null) {
|
|
20296
20496
|
cbBody = label;
|
|
20297
20497
|
} else {
|
|
20298
20498
|
console.error(
|
|
20299
|
-
`${
|
|
20499
|
+
`${TAG36} op=button-label-miss botId=${botId} chatId=${decision.chatId} data=${logValue2(decision.data)}`
|
|
20300
20500
|
);
|
|
20301
20501
|
}
|
|
20302
20502
|
}
|
|
@@ -20357,11 +20557,11 @@ app11.post("/", async (c) => {
|
|
|
20357
20557
|
const answered4 = await answerTelegramCallback(entry3.token, decision.callbackId, answerText);
|
|
20358
20558
|
const outcome = !answered4.ok ? "error" : decision.allowed ? "stored" : "refused";
|
|
20359
20559
|
console.error(
|
|
20360
|
-
`${
|
|
20560
|
+
`${TAG36} op=callback-answered botId=${botId} callbackId=${decision.callbackId} ms=${Date.now() - answerStartedAt} outcome=${outcome}${answered4.error ? ` error=${logValue2(answered4.error)}` : ""}`
|
|
20361
20561
|
);
|
|
20362
20562
|
if (decision.allowed && parseDispatchCallback(decision.data) === null) {
|
|
20363
20563
|
const cbActive = entryActive(entry3, accountDir, botId);
|
|
20364
|
-
console.error(`${
|
|
20564
|
+
console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${cbActive}`);
|
|
20365
20565
|
raiseChannelTurn({
|
|
20366
20566
|
accountId,
|
|
20367
20567
|
accountDir,
|
|
@@ -20372,7 +20572,7 @@ app11.post("/", async (c) => {
|
|
|
20372
20572
|
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20373
20573
|
active: cbActive,
|
|
20374
20574
|
senderId: decision.senderId,
|
|
20375
|
-
senderDisplay:
|
|
20575
|
+
senderDisplay: provenanceDisplay,
|
|
20376
20576
|
chatId: decision.chatId,
|
|
20377
20577
|
// The same body the store row above carries, so the operator's reader and
|
|
20378
20578
|
// the agent's turn say the same thing about one press.
|
|
@@ -20388,10 +20588,10 @@ app11.post("/", async (c) => {
|
|
|
20388
20588
|
if (decision.kind === "poll") {
|
|
20389
20589
|
const options = decision.optionIds.length > 0 ? decision.optionIds.join(",") : "retracted";
|
|
20390
20590
|
console.error(
|
|
20391
|
-
`${
|
|
20591
|
+
`${TAG36} op=poll-received botId=${botId} updateId=${decision.updateId ?? "none"} senderId=${decision.senderId} pollId=${logValue2(decision.pollId)} options=${options}`
|
|
20392
20592
|
);
|
|
20393
20593
|
console.error(
|
|
20394
|
-
`${
|
|
20594
|
+
`${TAG36} op=poll-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
|
|
20395
20595
|
);
|
|
20396
20596
|
if (!decision.allowed) return c.json({ ok: true }, 200);
|
|
20397
20597
|
const pollKey = telegramChannelKey(botId, decision.senderId);
|
|
@@ -20414,7 +20614,7 @@ app11.post("/", async (c) => {
|
|
|
20414
20614
|
createdAt: pollAt
|
|
20415
20615
|
});
|
|
20416
20616
|
const pollActive = entryActive(entry3, accountDir, botId);
|
|
20417
|
-
console.error(`${
|
|
20617
|
+
console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${pollActive}`);
|
|
20418
20618
|
raiseChannelTurn({
|
|
20419
20619
|
accountId,
|
|
20420
20620
|
accountDir,
|
|
@@ -20425,7 +20625,7 @@ app11.post("/", async (c) => {
|
|
|
20425
20625
|
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20426
20626
|
active: pollActive,
|
|
20427
20627
|
senderId: decision.senderId,
|
|
20428
|
-
senderDisplay:
|
|
20628
|
+
senderDisplay: provenanceDisplay,
|
|
20429
20629
|
chatId: decision.chatId,
|
|
20430
20630
|
text: pollBody,
|
|
20431
20631
|
channelKey: pollKey,
|
|
@@ -20440,10 +20640,10 @@ app11.post("/", async (c) => {
|
|
|
20440
20640
|
const quotedBody = findInboundBody(accountId, rKey, decision.messageId);
|
|
20441
20641
|
const shown = decision.newReaction.length > 0 ? decision.newReaction.join(",") : "none";
|
|
20442
20642
|
console.error(
|
|
20443
|
-
`${
|
|
20643
|
+
`${TAG36} op=reaction-received botId=${botId} chatId=${decision.chatId} messageId=${decision.messageId} senderId=${decision.senderId} old=${decision.oldReaction.join(",") || "none"} new=${shown} targetHeld=${quotedBody === null ? "no" : "yes"}`
|
|
20444
20644
|
);
|
|
20445
20645
|
console.error(
|
|
20446
|
-
`${
|
|
20646
|
+
`${TAG36} op=reaction-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
|
|
20447
20647
|
);
|
|
20448
20648
|
if (!decision.allowed) return c.json({ ok: true }, 200);
|
|
20449
20649
|
const rScope = entry3.role === "admin" ? "admin" : "public";
|
|
@@ -20466,7 +20666,7 @@ app11.post("/", async (c) => {
|
|
|
20466
20666
|
createdAt: rAt
|
|
20467
20667
|
});
|
|
20468
20668
|
const rActive = entryActive(entry3, accountDir, botId);
|
|
20469
|
-
console.error(`${
|
|
20669
|
+
console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${rActive}`);
|
|
20470
20670
|
raiseChannelTurn({
|
|
20471
20671
|
accountId,
|
|
20472
20672
|
accountDir,
|
|
@@ -20477,7 +20677,7 @@ app11.post("/", async (c) => {
|
|
|
20477
20677
|
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20478
20678
|
active: rActive,
|
|
20479
20679
|
senderId: decision.senderId,
|
|
20480
|
-
senderDisplay:
|
|
20680
|
+
senderDisplay: provenanceDisplay,
|
|
20481
20681
|
chatId: decision.chatId,
|
|
20482
20682
|
text: rBody,
|
|
20483
20683
|
channelKey: rKey,
|
|
@@ -20490,25 +20690,25 @@ app11.post("/", async (c) => {
|
|
|
20490
20690
|
if (decision.kind === "checkout") {
|
|
20491
20691
|
if (decision.query === "pre-checkout") {
|
|
20492
20692
|
console.error(
|
|
20493
|
-
`${
|
|
20693
|
+
`${TAG36} op=precheckout-received botId=${botId} queryId=${decision.queryId} payload=${logValue2(decision.payload)} amount=${decision.amount ?? "none"} currency=${decision.currency ?? "none"}`
|
|
20494
20694
|
);
|
|
20495
20695
|
noteCheckoutArrived(botId, decision.queryId, Date.now());
|
|
20496
20696
|
} else {
|
|
20497
20697
|
console.error(
|
|
20498
|
-
`${
|
|
20698
|
+
`${TAG36} op=shipping-received botId=${botId} queryId=${decision.queryId} payload=${logValue2(decision.payload)}`
|
|
20499
20699
|
);
|
|
20500
20700
|
}
|
|
20501
20701
|
console.error(
|
|
20502
|
-
`${
|
|
20702
|
+
`${TAG36} op=checkout-ignored botId=${botId} senderId=${decision.senderId} queryId=${decision.queryId} query=${decision.query} allowed=${decision.allowed} reason=payments-removed`
|
|
20503
20703
|
);
|
|
20504
20704
|
return c.json({ ok: true }, 200);
|
|
20505
20705
|
}
|
|
20506
20706
|
if (decision.kind === "subscription") {
|
|
20507
20707
|
console.error(
|
|
20508
|
-
`${
|
|
20708
|
+
`${TAG36} op=subscription botId=${botId} userId=${decision.senderId} payload=${logValue2(decision.payload)} state=${decision.state}`
|
|
20509
20709
|
);
|
|
20510
20710
|
console.error(
|
|
20511
|
-
`${
|
|
20711
|
+
`${TAG36} op=subscription-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
|
|
20512
20712
|
);
|
|
20513
20713
|
if (!decision.allowed) return c.json({ ok: true }, 200);
|
|
20514
20714
|
const sKey = telegramChannelKey(botId, decision.senderId);
|
|
@@ -20531,7 +20731,7 @@ app11.post("/", async (c) => {
|
|
|
20531
20731
|
createdAt: sAt
|
|
20532
20732
|
});
|
|
20533
20733
|
const sActive = entryActive(entry3, accountDir, botId);
|
|
20534
|
-
console.error(`${
|
|
20734
|
+
console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${sActive}`);
|
|
20535
20735
|
raiseChannelTurn({
|
|
20536
20736
|
accountId,
|
|
20537
20737
|
accountDir,
|
|
@@ -20542,7 +20742,7 @@ app11.post("/", async (c) => {
|
|
|
20542
20742
|
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20543
20743
|
active: sActive,
|
|
20544
20744
|
senderId: decision.senderId,
|
|
20545
|
-
senderDisplay:
|
|
20745
|
+
senderDisplay: provenanceDisplay,
|
|
20546
20746
|
chatId: decision.chatId,
|
|
20547
20747
|
text: sBody,
|
|
20548
20748
|
channelKey: sKey,
|
|
@@ -20555,7 +20755,7 @@ app11.post("/", async (c) => {
|
|
|
20555
20755
|
if (!decision.isClosed) return c.json({ ok: true }, 200);
|
|
20556
20756
|
const where = findPollConversation(accountId, decision.pollId);
|
|
20557
20757
|
console.error(
|
|
20558
|
-
`${
|
|
20758
|
+
`${TAG36} op=poll-closed botId=${botId} pollId=${logValue2(decision.pollId)} options=${decision.options.length} totalVotes=${decision.totalVotes} targetHeld=${where === null ? "no" : "yes"}`
|
|
20559
20759
|
);
|
|
20560
20760
|
if (where === null) return c.json({ ok: true }, 200);
|
|
20561
20761
|
const plScope = entry3.role === "admin" ? "admin" : "public";
|
|
@@ -20578,7 +20778,7 @@ app11.post("/", async (c) => {
|
|
|
20578
20778
|
createdAt: plAt
|
|
20579
20779
|
});
|
|
20580
20780
|
const plActive = entryActive(entry3, accountDir, botId);
|
|
20581
|
-
console.error(`${
|
|
20781
|
+
console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${plActive}`);
|
|
20582
20782
|
raiseChannelTurn({
|
|
20583
20783
|
accountId,
|
|
20584
20784
|
accountDir,
|
|
@@ -20599,7 +20799,7 @@ app11.post("/", async (c) => {
|
|
|
20599
20799
|
}
|
|
20600
20800
|
if (decision.kind === "member") {
|
|
20601
20801
|
console.error(
|
|
20602
|
-
`${
|
|
20802
|
+
`${TAG36} op=chat-member botId=${botId} chatId=${decision.chatId} status=${decision.status}`
|
|
20603
20803
|
);
|
|
20604
20804
|
return c.json({ ok: true }, 200);
|
|
20605
20805
|
}
|
|
@@ -20607,13 +20807,13 @@ app11.post("/", async (c) => {
|
|
|
20607
20807
|
const { newBotId } = decision;
|
|
20608
20808
|
if (!decision.authorised) {
|
|
20609
20809
|
console.error(
|
|
20610
|
-
`${
|
|
20810
|
+
`${TAG36} op=managed-bot botId=${botId} event=${decision.event} newBotId=${newBotId} result=refused reason=public-entry-no-provision`
|
|
20611
20811
|
);
|
|
20612
20812
|
return c.json({ ok: true }, 200);
|
|
20613
20813
|
}
|
|
20614
20814
|
const { event } = decision;
|
|
20615
20815
|
console.error(
|
|
20616
|
-
`${
|
|
20816
|
+
`${TAG36} op=managed-bot botId=${botId} event=${event} newBotId=${newBotId} creator=${decision.creatorId ?? "none"}`
|
|
20617
20817
|
);
|
|
20618
20818
|
const fetched = await getManagedBotToken(entry3.token, Number(newBotId));
|
|
20619
20819
|
console.error(
|
|
@@ -20669,11 +20869,11 @@ app11.post("/", async (c) => {
|
|
|
20669
20869
|
const matched = bizStored !== null && bizStored.id === decision.businessConnectionId;
|
|
20670
20870
|
const bizNowS = Math.floor(Date.now() / 1e3);
|
|
20671
20871
|
console.error(
|
|
20672
|
-
`${
|
|
20872
|
+
`${TAG36} op=business-message botId=${botId} connectionId=${truncateConnectionId(decision.businessConnectionId)} chatId=${decision.chatId} senderId=${decision.senderId} messageId=${decision.messageId ?? "none"} kind=${shape.primaryKind} ageS=${decision.date === null ? "none" : bizNowS - decision.date} matched=${matched ? "yes" : "no"}`
|
|
20673
20873
|
);
|
|
20674
20874
|
if (!matched) {
|
|
20675
20875
|
console.error(
|
|
20676
|
-
`${
|
|
20876
|
+
`${TAG36} op=business-refused botId=${botId} connectionId=${truncateConnectionId(decision.businessConnectionId)} reason=${bizStored === null ? "no-record" : "mismatch"}`
|
|
20677
20877
|
);
|
|
20678
20878
|
return c.json({ ok: true }, 200);
|
|
20679
20879
|
}
|
|
@@ -20735,7 +20935,7 @@ app11.post("/", async (c) => {
|
|
|
20735
20935
|
}
|
|
20736
20936
|
const bizGateway = getTelegramGateway();
|
|
20737
20937
|
if (!bizGateway) {
|
|
20738
|
-
console.error(`${
|
|
20938
|
+
console.error(`${TAG36} op=reply-dropped botId=${botId} reason=gateway-not-ready`);
|
|
20739
20939
|
return c.json({ ok: true }, 200);
|
|
20740
20940
|
}
|
|
20741
20941
|
const bizConnectionId = bizStored.id;
|
|
@@ -20749,7 +20949,7 @@ app11.post("/", async (c) => {
|
|
|
20749
20949
|
);
|
|
20750
20950
|
if (!verdict.allowed) {
|
|
20751
20951
|
console.error(
|
|
20752
|
-
`${
|
|
20952
|
+
`${TAG36} op=reply-dropped botId=${botId} reason=business-window-${verdict.reason} detail="${logValue2(businessWindowRefusal(decision.chatId, verdict.ageS))}"`
|
|
20753
20953
|
);
|
|
20754
20954
|
return;
|
|
20755
20955
|
}
|
|
@@ -20776,8 +20976,8 @@ app11.post("/", async (c) => {
|
|
|
20776
20976
|
origin: "agent",
|
|
20777
20977
|
createdAt: outAt
|
|
20778
20978
|
});
|
|
20779
|
-
console.error(`${
|
|
20780
|
-
} else console.error(`${
|
|
20979
|
+
console.error(`${TAG36} op=reply-sent botId=${botId} ok=true`);
|
|
20980
|
+
} else console.error(`${TAG36} op=reply-dropped botId=${botId} reason=${sent.error}`);
|
|
20781
20981
|
};
|
|
20782
20982
|
void bizGateway.handleInbound({
|
|
20783
20983
|
accountId,
|
|
@@ -20808,7 +21008,7 @@ app11.post("/", async (c) => {
|
|
|
20808
21008
|
const delStored = readBusinessConnection(accountDir, botId);
|
|
20809
21009
|
if (delStored === null || delStored.id !== decision.businessConnectionId) {
|
|
20810
21010
|
console.error(
|
|
20811
|
-
`${
|
|
21011
|
+
`${TAG36} op=business-refused botId=${botId} connectionId=${truncateConnectionId(decision.businessConnectionId)} reason=${delStored === null ? "no-record" : "mismatch"}`
|
|
20812
21012
|
);
|
|
20813
21013
|
return c.json({ ok: true }, 200);
|
|
20814
21014
|
}
|
|
@@ -20825,12 +21025,12 @@ app11.post("/", async (c) => {
|
|
|
20825
21025
|
if (res.created) marked += 1;
|
|
20826
21026
|
}
|
|
20827
21027
|
console.error(
|
|
20828
|
-
`${
|
|
21028
|
+
`${TAG36} op=business-deleted botId=${botId} chatId=${decision.chatId} ids=${decision.messageIds.length} marked=${marked}`
|
|
20829
21029
|
);
|
|
20830
21030
|
return c.json({ ok: true }, 200);
|
|
20831
21031
|
}
|
|
20832
21032
|
const { senderId, chatId, text } = decision;
|
|
20833
|
-
console.error(`${
|
|
21033
|
+
console.error(`${TAG36} op=access botId=${botId} senderId=${senderId} allowed=true reason=${decision.reason}`);
|
|
20834
21034
|
const subject = telegramConversationSubject(decision.chatType, chatId, senderId);
|
|
20835
21035
|
const channelKey = telegramChannelKey(botId, subject);
|
|
20836
21036
|
const scope = entry3.role === "public" ? "public" : "admin";
|
|
@@ -20917,17 +21117,17 @@ app11.post("/", async (c) => {
|
|
|
20917
21117
|
const active = entryActive(entry3, accountDir, botId, (rosterValid) => {
|
|
20918
21118
|
if (entry3.role !== "specialist") return;
|
|
20919
21119
|
console.error(
|
|
20920
|
-
`${
|
|
21120
|
+
`${TAG36} op=specialist-inbound botId=${botId} specialist=${logValue2(entry3.specialist)} senderId=${senderId} sessionId=${sessionId} rosterValid=${rosterValid ? "yes" : "no"}`
|
|
20921
21121
|
);
|
|
20922
21122
|
});
|
|
20923
|
-
console.error(`${
|
|
21123
|
+
console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${active}`);
|
|
20924
21124
|
if (!active) {
|
|
20925
|
-
console.error(`${
|
|
21125
|
+
console.error(`${TAG36} op=reject reason=agent-inactive botId=${botId} agent=${agentSlug}`);
|
|
20926
21126
|
return c.json({ ok: true }, 200);
|
|
20927
21127
|
}
|
|
20928
21128
|
const gateway = getTelegramGateway();
|
|
20929
21129
|
if (!gateway) {
|
|
20930
|
-
console.error(`${
|
|
21130
|
+
console.error(`${TAG36} op=reply-dropped botId=${botId} reason=gateway-not-ready`);
|
|
20931
21131
|
return c.json({ ok: true }, 200);
|
|
20932
21132
|
}
|
|
20933
21133
|
const replyThreadId = decision.threadId ?? void 0;
|
|
@@ -20949,8 +21149,8 @@ app11.post("/", async (c) => {
|
|
|
20949
21149
|
origin: "agent",
|
|
20950
21150
|
createdAt: at
|
|
20951
21151
|
});
|
|
20952
|
-
console.error(`${
|
|
20953
|
-
} else console.error(`${
|
|
21152
|
+
console.error(`${TAG36} op=reply-sent botId=${botId} ok=true`);
|
|
21153
|
+
} else console.error(`${TAG36} op=reply-dropped botId=${botId} reason=${sent.error}`);
|
|
20954
21154
|
};
|
|
20955
21155
|
const media = await downloadTelegramMedia({ token: entry3.token, botId, items: decision.media });
|
|
20956
21156
|
if (media.length > 0) {
|
|
@@ -21010,7 +21210,7 @@ app11.post("/", async (c) => {
|
|
|
21010
21210
|
if (written.written && !decision.isEdit) noteShareStarted();
|
|
21011
21211
|
} catch (err) {
|
|
21012
21212
|
console.error(
|
|
21013
|
-
`${
|
|
21213
|
+
`${TAG36} op=live-location op=write-failed botId=${botId} senderId=${senderId} detail="${logValue2(err instanceof Error ? err.message : String(err))}"`
|
|
21014
21214
|
);
|
|
21015
21215
|
}
|
|
21016
21216
|
}
|
|
@@ -21022,6 +21222,8 @@ app11.post("/", async (c) => {
|
|
|
21022
21222
|
textIsPlaceholder: decision.textIsPlaceholder,
|
|
21023
21223
|
media
|
|
21024
21224
|
});
|
|
21225
|
+
const seen = await extractTelegramVideo({ botId, media: heard.media });
|
|
21226
|
+
heard.media = seen.media;
|
|
21025
21227
|
if (heard.text !== text) {
|
|
21026
21228
|
const patched = appendUpdate(accountId, channelKey, {
|
|
21027
21229
|
kind: "update",
|
|
@@ -21030,7 +21232,7 @@ app11.post("/", async (c) => {
|
|
|
21030
21232
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21031
21233
|
});
|
|
21032
21234
|
console.error(
|
|
21033
|
-
`${
|
|
21235
|
+
`${TAG36} op=transcript-patch botId=${botId} target=${inboundMessageId} ok=${patched.created}`
|
|
21034
21236
|
);
|
|
21035
21237
|
}
|
|
21036
21238
|
{
|
|
@@ -21066,7 +21268,7 @@ app11.post("/", async (c) => {
|
|
|
21066
21268
|
}
|
|
21067
21269
|
if (decision.isEdit && decision.location) {
|
|
21068
21270
|
console.error(
|
|
21069
|
-
`${
|
|
21271
|
+
`${TAG36} op=live-location op=suppressed-turn botId=${botId} senderId=${senderId} reason=live-edit`
|
|
21070
21272
|
);
|
|
21071
21273
|
return;
|
|
21072
21274
|
}
|
|
@@ -21082,7 +21284,8 @@ app11.post("/", async (c) => {
|
|
|
21082
21284
|
agentSlug,
|
|
21083
21285
|
senderId,
|
|
21084
21286
|
// Task 2616 — the name beside the id on the turn's provenance line.
|
|
21085
|
-
|
|
21287
|
+
// Task 2705 — the account's own contact name when one holds this id.
|
|
21288
|
+
senderDisplay: provenanceDisplay,
|
|
21086
21289
|
// Task 2616 — a group is ONE conversation. The gateway's hub key, reply
|
|
21087
21290
|
// map, spawn guard and session id all take this, so five members of one
|
|
21088
21291
|
// room reach one channel server rather than opening five sessions whose
|
|
@@ -21117,7 +21320,7 @@ function mountTelegramRoutes(app81, telegramRoutes) {
|
|
|
21117
21320
|
// server/routes/quickbooks.ts
|
|
21118
21321
|
import { join as join41 } from "path";
|
|
21119
21322
|
import { existsSync as existsSync29, readFileSync as readFileSync33, writeFileSync as writeFileSync15, mkdirSync as mkdirSync8, rmSync as rmSync4, renameSync as renameSync5 } from "fs";
|
|
21120
|
-
var
|
|
21323
|
+
var TAG37 = "[quickbooks]";
|
|
21121
21324
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
21122
21325
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
21123
21326
|
function pendingPath(accountDir, state) {
|
|
@@ -21130,14 +21333,14 @@ async function completeConsent(args) {
|
|
|
21130
21333
|
const { accountDir, code, realmId } = args;
|
|
21131
21334
|
const state = args.state;
|
|
21132
21335
|
if (!state || !STATE_RE.test(state) || !existsSync29(pendingPath(accountDir, state))) {
|
|
21133
|
-
console.error(`${
|
|
21336
|
+
console.error(`${TAG37} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
|
|
21134
21337
|
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
21135
21338
|
}
|
|
21136
21339
|
const claimFile = `${pendingPath(accountDir, state)}.claimed`;
|
|
21137
21340
|
try {
|
|
21138
21341
|
renameSync5(pendingPath(accountDir, state), claimFile);
|
|
21139
21342
|
} catch {
|
|
21140
|
-
console.error(`${
|
|
21343
|
+
console.error(`${TAG37} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
21141
21344
|
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
21142
21345
|
}
|
|
21143
21346
|
try {
|
|
@@ -21145,14 +21348,14 @@ async function completeConsent(args) {
|
|
|
21145
21348
|
try {
|
|
21146
21349
|
pending = JSON.parse(readFileSync33(claimFile, "utf-8"));
|
|
21147
21350
|
} catch {
|
|
21148
|
-
console.error(`${
|
|
21351
|
+
console.error(`${TAG37} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
21149
21352
|
return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
|
|
21150
21353
|
}
|
|
21151
21354
|
if (Date.now() > pending.expiresAt) {
|
|
21152
|
-
console.error(`${
|
|
21355
|
+
console.error(`${TAG37} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
21153
21356
|
return { ok: false, status: 400, message: "Authorization request expired. Generate a new consent link.", stateValid: false };
|
|
21154
21357
|
}
|
|
21155
|
-
console.error(`${
|
|
21358
|
+
console.error(`${TAG37} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
|
|
21156
21359
|
if (!code || !realmId) {
|
|
21157
21360
|
return { ok: false, status: 400, message: "Missing code or realmId in the callback.", stateValid: true };
|
|
21158
21361
|
}
|
|
@@ -21176,12 +21379,12 @@ async function completeConsent(args) {
|
|
|
21176
21379
|
});
|
|
21177
21380
|
const text = await res.text();
|
|
21178
21381
|
if (!res.ok) {
|
|
21179
|
-
console.error(`${
|
|
21382
|
+
console.error(`${TAG37} op=token-exchange realmId=${realmId} persisted=false`);
|
|
21180
21383
|
return { ok: false, status: 502, message: `Token exchange failed (${res.status}). Generate a new consent link to retry.`, stateValid: true };
|
|
21181
21384
|
}
|
|
21182
21385
|
const body = JSON.parse(text);
|
|
21183
21386
|
if (!body.refresh_token) {
|
|
21184
|
-
console.error(`${
|
|
21387
|
+
console.error(`${TAG37} op=token-exchange realmId=${realmId} persisted=false`);
|
|
21185
21388
|
return { ok: false, status: 502, message: "Token exchange returned no refresh token.", stateValid: true };
|
|
21186
21389
|
}
|
|
21187
21390
|
const now = Date.now();
|
|
@@ -21194,7 +21397,7 @@ async function completeConsent(args) {
|
|
|
21194
21397
|
mkdirSync8(join41(accountDir, "secrets"), { recursive: true });
|
|
21195
21398
|
writeFileSync15(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
21196
21399
|
const persisted = JSON.parse(readFileSync33(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
21197
|
-
console.error(`${
|
|
21400
|
+
console.error(`${TAG37} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
21198
21401
|
return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
|
|
21199
21402
|
} finally {
|
|
21200
21403
|
rmSync4(claimFile, { force: true });
|
|
@@ -21207,7 +21410,7 @@ var app12 = new Hono();
|
|
|
21207
21410
|
app12.get("/callback", async (c) => {
|
|
21208
21411
|
const account = resolveAccount();
|
|
21209
21412
|
if (!account) {
|
|
21210
|
-
console.error(`${
|
|
21413
|
+
console.error(`${TAG37} op=callback stateValid=false realmId= reason=no-account`);
|
|
21211
21414
|
return c.html(page("QuickBooks", "This install has no account configured."), 500);
|
|
21212
21415
|
}
|
|
21213
21416
|
const result = await completeConsent({
|
|
@@ -22172,7 +22375,7 @@ function startDispatchFieldCensus(getSession3, intervalMs = FIFTEEN_MIN_MS) {
|
|
|
22172
22375
|
}
|
|
22173
22376
|
|
|
22174
22377
|
// server/routes/field.ts
|
|
22175
|
-
var
|
|
22378
|
+
var TAG38 = "[dispatch-field]";
|
|
22176
22379
|
var MAX_INITDATA_AGE_S = 3600;
|
|
22177
22380
|
var ZONE_FALLBACK2 = "UTC";
|
|
22178
22381
|
var SITE_HISTORY_LIMIT = 20;
|
|
@@ -22221,7 +22424,7 @@ function gate(c) {
|
|
|
22221
22424
|
Date.now()
|
|
22222
22425
|
);
|
|
22223
22426
|
console.log(
|
|
22224
|
-
`${
|
|
22427
|
+
`${TAG38} op=initdata-verify workerId=${auth.ok ? auth.worker.workerId : "none"} ok=${auth.ok} reason=${auth.ok ? "ok" : auth.reason} ageS=${auth.ageS}`
|
|
22225
22428
|
);
|
|
22226
22429
|
if (auth.ok) {
|
|
22227
22430
|
noteFieldContact(auth.accountId, auth.worker.workerId, Date.now());
|
|
@@ -22243,7 +22446,7 @@ async function loadSheet(auth, visitId) {
|
|
|
22243
22446
|
if (!visit) return { ok: false, status: 404, reason: "not-found" };
|
|
22244
22447
|
if (visit.workerId !== auth.worker.workerId) {
|
|
22245
22448
|
console.error(
|
|
22246
|
-
`${
|
|
22449
|
+
`${TAG38} op=visit-refused visitId=${visitId} workerId=${auth.worker.workerId} reason=not-assigned`
|
|
22247
22450
|
);
|
|
22248
22451
|
return { ok: false, status: 403, reason: "not-assigned" };
|
|
22249
22452
|
}
|
|
@@ -22264,7 +22467,7 @@ async function loadSheet(auth, visitId) {
|
|
|
22264
22467
|
}
|
|
22265
22468
|
function readFailed(reason, err, ctx) {
|
|
22266
22469
|
console.error(
|
|
22267
|
-
`${
|
|
22470
|
+
`${TAG38} op=read-failed ${ctx} error="${err instanceof Error ? err.message : String(err)}" reason=${reason}`
|
|
22268
22471
|
);
|
|
22269
22472
|
}
|
|
22270
22473
|
var app14 = new Hono();
|
|
@@ -22280,7 +22483,7 @@ app14.get("/session", async (c) => {
|
|
|
22280
22483
|
return c.json({ reason: "read-failed" }, 503);
|
|
22281
22484
|
}
|
|
22282
22485
|
console.log(
|
|
22283
|
-
`${
|
|
22486
|
+
`${TAG38} op=session-open workerId=${auth.worker.workerId} visits=${visits} source=network`
|
|
22284
22487
|
);
|
|
22285
22488
|
return c.json({
|
|
22286
22489
|
worker: { workerId: auth.worker.workerId, name: auth.worker.name },
|
|
@@ -22316,7 +22519,7 @@ app14.get("/visit/:visitId", async (c) => {
|
|
|
22316
22519
|
const loaded = await loadSheet(auth, visitId);
|
|
22317
22520
|
if (!loaded.ok) return c.json({ reason: loaded.reason }, loaded.status);
|
|
22318
22521
|
console.log(
|
|
22319
|
-
`${
|
|
22522
|
+
`${TAG38} op=sheet-open visitId=${visitId} workerId=${auth.worker.workerId} historyVisits=${loaded.history.length} source=network`
|
|
22320
22523
|
);
|
|
22321
22524
|
return c.json({
|
|
22322
22525
|
visit: loaded.visit,
|
|
@@ -22352,7 +22555,7 @@ app14.post("/visit/:visitId/record", async (c) => {
|
|
|
22352
22555
|
);
|
|
22353
22556
|
if (!out.ok) return c.json({ reason: out.reason, detail: out.message }, 400);
|
|
22354
22557
|
const kind = body.checklistItem !== void 0 ? "checklist" : body.partId !== void 0 ? "part" : body.signature !== void 0 ? "signature" : body.mediaRef !== void 0 ? "media" : "note";
|
|
22355
|
-
console.log(`${
|
|
22558
|
+
console.log(`${TAG38} op=edit-recorded visitId=${visitId} workerId=${auth.worker.workerId} kind=${kind}`);
|
|
22356
22559
|
return c.json(out.value);
|
|
22357
22560
|
});
|
|
22358
22561
|
app14.post("/visit/:visitId/status", async (c) => {
|
|
@@ -22379,7 +22582,7 @@ app14.post("/visit/:visitId/status", async (c) => {
|
|
|
22379
22582
|
const prefix = "missing-required-field:";
|
|
22380
22583
|
if (out.reason.startsWith(prefix)) {
|
|
22381
22584
|
const missing = out.reason.slice(prefix.length);
|
|
22382
|
-
console.error(`${
|
|
22585
|
+
console.error(`${TAG38} op=complete-refused visitId=${visitId} missing=${missing}`);
|
|
22383
22586
|
return c.json({ reason: "missing-required-field", missing, detail: out.message }, 409);
|
|
22384
22587
|
}
|
|
22385
22588
|
return c.json({ reason: out.reason, detail: out.message }, 409);
|
|
@@ -22391,7 +22594,7 @@ app14.post("/visit/:visitId/status", async (c) => {
|
|
|
22391
22594
|
Math.round((Date.parse(out.value.at) - Date.parse(dueToLeaveAt)) / 1e3)
|
|
22392
22595
|
);
|
|
22393
22596
|
console.log(
|
|
22394
|
-
`${
|
|
22597
|
+
`${TAG38} op=complete visitId=${visitId} checklist=${state.checklistDone}/${state.checklistTotal} notes=${state.notes} media=${state.media} parts=${state.parts} signatures=${state.signatures} lagS=${lagS}`
|
|
22395
22598
|
);
|
|
22396
22599
|
return c.json(out.value);
|
|
22397
22600
|
});
|
|
@@ -22400,10 +22603,10 @@ app14.post("/probe", async (c) => {
|
|
|
22400
22603
|
if (!auth.ok) return c.json({ reason: auth.reason }, auth.status);
|
|
22401
22604
|
const p = await c.req.json();
|
|
22402
22605
|
console.log(
|
|
22403
|
-
`${
|
|
22606
|
+
`${TAG38} op=storage-probe platform=${p.platform} indexedDB=${p.indexedDB} localStorage=${p.localStorage} cacheStorage=${p.cacheStorage} serviceWorker=${p.serviceWorker} persisted=${p.persisted} workerId=${auth.worker.workerId}`
|
|
22404
22607
|
);
|
|
22405
22608
|
console.log(
|
|
22406
|
-
`${
|
|
22609
|
+
`${TAG38} op=launch-params workerId=${auth.worker.workerId} keys=${(p.launchKeys ?? []).join(",") || "none"}`
|
|
22407
22610
|
);
|
|
22408
22611
|
const anyUsable = p.indexedDB || p.localStorage || p.cacheStorage;
|
|
22409
22612
|
noteFieldStorage(auth.accountId, auth.worker.workerId, anyUsable, Date.now());
|
|
@@ -22530,6 +22733,14 @@ app15.post("/", async (c) => {
|
|
|
22530
22733
|
// the standard fields.
|
|
22531
22734
|
"graph-fullscreen-not-covering",
|
|
22532
22735
|
"graph-fullscreen-canvas-mismatch",
|
|
22736
|
+
// Task 2439 — the admin composer's own send failure. The inline reporter in
|
|
22737
|
+
// server/index.ts hooks only `error` and `unhandledrejection`, so a caught
|
|
22738
|
+
// fetch rejection in send() reached no sink at all. Without this entry the
|
|
22739
|
+
// POST collapses to kind=unknown and the log loses the source, which is the
|
|
22740
|
+
// whole point of the report. Deliberately NOT in ERROR_KINDS: it fires at
|
|
22741
|
+
// most once per send press, so it cannot exhaust a budget, and leaving it in
|
|
22742
|
+
// the telemetry class keeps the protected error budget for uncaught errors.
|
|
22743
|
+
"webchat-send-failed",
|
|
22533
22744
|
"event"
|
|
22534
22745
|
]);
|
|
22535
22746
|
const kind = allowedKinds.has(kindRaw) ? kindRaw : "unknown";
|
|
@@ -25309,7 +25520,7 @@ function resolveTunnelUrl() {
|
|
|
25309
25520
|
if (!state) return null;
|
|
25310
25521
|
return `https://${hostname2}.${state.domain}`;
|
|
25311
25522
|
}
|
|
25312
|
-
var
|
|
25523
|
+
var TAG39 = "[claude-session-manager:wrapper]";
|
|
25313
25524
|
async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
25314
25525
|
const auth = await ensureAuth();
|
|
25315
25526
|
if (auth.status !== "dead" && auth.status !== "missing") return null;
|
|
@@ -25327,12 +25538,12 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
25327
25538
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
25328
25539
|
const ownerMs = Date.now() - ownerStart;
|
|
25329
25540
|
const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
|
|
25330
|
-
console.log(`${
|
|
25541
|
+
console.log(`${TAG39} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
|
|
25331
25542
|
const dormantPlugins = computeDormantPlugins(args.senderId);
|
|
25332
25543
|
const activePlugins = computeActivePlugins(args.senderId);
|
|
25333
25544
|
const specialistDomains = computeSpecialistDomains(args.senderId);
|
|
25334
25545
|
const tunnelUrl = resolveTunnelUrl();
|
|
25335
|
-
console.log(`${
|
|
25546
|
+
console.log(`${TAG39} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
|
|
25336
25547
|
const upstreamPayload = JSON.stringify({
|
|
25337
25548
|
senderId: args.senderId,
|
|
25338
25549
|
// Task 205 — pass userId through to the manager so it lands as
|
|
@@ -25359,24 +25570,24 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
25359
25570
|
// unshapely values.
|
|
25360
25571
|
conversationNodeId: args.conversationNodeId
|
|
25361
25572
|
});
|
|
25362
|
-
console.log(`${
|
|
25573
|
+
console.log(`${TAG39} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
|
|
25363
25574
|
const forwardStart = Date.now();
|
|
25364
25575
|
const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
|
|
25365
25576
|
method: "POST",
|
|
25366
25577
|
headers: { "content-type": "application/json" },
|
|
25367
25578
|
body: upstreamPayload
|
|
25368
25579
|
}).catch((err) => {
|
|
25369
|
-
console.error(`${
|
|
25580
|
+
console.error(`${TAG39} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
|
|
25370
25581
|
return null;
|
|
25371
25582
|
});
|
|
25372
25583
|
if (!upstream) return {
|
|
25373
25584
|
response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
|
|
25374
25585
|
claudeSessionId: null
|
|
25375
25586
|
};
|
|
25376
|
-
console.log(`${
|
|
25587
|
+
console.log(`${TAG39} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
|
|
25377
25588
|
if (args.initialMessage) {
|
|
25378
25589
|
const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
|
|
25379
|
-
console.log(`${
|
|
25590
|
+
console.log(`${TAG39} initial-message-inlined bytes=${inputBytes}`);
|
|
25380
25591
|
}
|
|
25381
25592
|
const bodyText = await upstream.text().catch(() => "");
|
|
25382
25593
|
let claudeSessionId = null;
|
|
@@ -25411,7 +25622,7 @@ app24.post("/", async (c) => {
|
|
|
25411
25622
|
if (refusal) return refusal;
|
|
25412
25623
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
25413
25624
|
if (!senderId) {
|
|
25414
|
-
console.error(`${
|
|
25625
|
+
console.error(`${TAG39} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
|
|
25415
25626
|
return c.json({ error: "admin-account-not-resolved" }, 500);
|
|
25416
25627
|
}
|
|
25417
25628
|
const userId = getUserIdForSession(cacheKey) ?? void 0;
|
|
@@ -25420,7 +25631,7 @@ app24.post("/", async (c) => {
|
|
|
25420
25631
|
const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
|
|
25421
25632
|
const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
|
|
25422
25633
|
const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
|
|
25423
|
-
console.log(`${
|
|
25634
|
+
console.log(`${TAG39} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
|
|
25424
25635
|
const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
|
|
25425
25636
|
const { response, claudeSessionId } = await performSpawnWithInitialMessage({
|
|
25426
25637
|
senderId,
|
|
@@ -25439,13 +25650,13 @@ app24.post("/", async (c) => {
|
|
|
25439
25650
|
claudeSessionId,
|
|
25440
25651
|
senderId
|
|
25441
25652
|
);
|
|
25442
|
-
console.log(`${
|
|
25653
|
+
console.log(`${TAG39} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
25443
25654
|
return response;
|
|
25444
25655
|
});
|
|
25445
25656
|
var claude_sessions_default = app24;
|
|
25446
25657
|
|
|
25447
25658
|
// server/routes/admin/log-ingest.ts
|
|
25448
|
-
var
|
|
25659
|
+
var TAG40 = "[log-ingest]";
|
|
25449
25660
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
25450
25661
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
25451
25662
|
var MAX_LINE_BYTES = 4096;
|
|
@@ -25456,7 +25667,7 @@ function isLoopbackAddr2(addr) {
|
|
|
25456
25667
|
app25.post("/", async (c) => {
|
|
25457
25668
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
25458
25669
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
25459
|
-
console.error(`${
|
|
25670
|
+
console.error(`${TAG40} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
25460
25671
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
25461
25672
|
}
|
|
25462
25673
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -25465,7 +25676,7 @@ app25.post("/", async (c) => {
|
|
|
25465
25676
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
25466
25677
|
const offender = tokens.find((t) => !isLoopbackAddr2(t));
|
|
25467
25678
|
if (offender !== void 0) {
|
|
25468
|
-
console.error(`${
|
|
25679
|
+
console.error(`${TAG40} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
25469
25680
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
25470
25681
|
}
|
|
25471
25682
|
}
|
|
@@ -25500,7 +25711,7 @@ var log_ingest_default = app25;
|
|
|
25500
25711
|
|
|
25501
25712
|
// server/routes/admin/session-blocked.ts
|
|
25502
25713
|
import { join as join48 } from "path";
|
|
25503
|
-
var
|
|
25714
|
+
var TAG41 = "[blocked-tool-notify]";
|
|
25504
25715
|
function isLoopbackAddr3(addr) {
|
|
25505
25716
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
25506
25717
|
}
|
|
@@ -25518,18 +25729,18 @@ Answer the permission card in the session's PTY or in Claude Desktop. Some check
|
|
|
25518
25729
|
async function sendWhatsApp(account, to, text) {
|
|
25519
25730
|
const res = resolveSocket(account.accountId);
|
|
25520
25731
|
if (!res.ok) {
|
|
25521
|
-
console.error(`${
|
|
25732
|
+
console.error(`${TAG41} op=socket-unavailable accountId=${account.accountId} reason=${res.reason}`);
|
|
25522
25733
|
return false;
|
|
25523
25734
|
}
|
|
25524
25735
|
const sent = await sendTextMessage(res.sock, to, text, { accountId: res.accountId });
|
|
25525
|
-
if (!sent.success) console.error(`${
|
|
25736
|
+
if (!sent.success) console.error(`${TAG41} op=send-failed to=${to} error=${sent.error ?? "unknown"}`);
|
|
25526
25737
|
return sent.success === true;
|
|
25527
25738
|
}
|
|
25528
25739
|
var app26 = new Hono();
|
|
25529
25740
|
app26.post("/", async (c) => {
|
|
25530
25741
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
25531
25742
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
25532
|
-
console.error(`${
|
|
25743
|
+
console.error(`${TAG41} op=reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
25533
25744
|
return c.json({ error: "session-blocked-loopback-only" }, 403);
|
|
25534
25745
|
}
|
|
25535
25746
|
let body = {};
|
|
@@ -25550,13 +25761,13 @@ app26.post("/", async (c) => {
|
|
|
25550
25761
|
const account = validateAccountId2(meta.accountId ?? "");
|
|
25551
25762
|
if (!account) {
|
|
25552
25763
|
console.error(
|
|
25553
|
-
`${
|
|
25764
|
+
`${TAG41} op=account-unresolved sessionId=${sessionId.slice(0, 8)} sidecarAccountId=${meta.accountId ?? "none"}`
|
|
25554
25765
|
);
|
|
25555
25766
|
return c.json({ delivered: false, channel: "none" }, 200);
|
|
25556
25767
|
}
|
|
25557
25768
|
if (meta.role === "admin" && meta.channel === "whatsapp" && meta.senderId) {
|
|
25558
25769
|
const delivered2 = await sendWhatsApp(account, meta.senderId, text);
|
|
25559
|
-
console.error(`${
|
|
25770
|
+
console.error(`${TAG41} op=notify sessionId=${sessionId.slice(0, 8)} channel=whatsapp delivered=${delivered2}`);
|
|
25560
25771
|
return c.json({ delivered: delivered2, channel: "whatsapp" }, 200);
|
|
25561
25772
|
}
|
|
25562
25773
|
if (meta.role === "admin" && meta.channel === "telegram" && meta.senderId) {
|
|
@@ -25566,11 +25777,11 @@ app26.post("/", async (c) => {
|
|
|
25566
25777
|
const chatId = Number(parsed.senderId);
|
|
25567
25778
|
if (resolved.kind === "one" && Number.isFinite(chatId)) {
|
|
25568
25779
|
const res = await sendTelegramText(resolved.entry.token, chatId, text);
|
|
25569
|
-
console.error(`${
|
|
25780
|
+
console.error(`${TAG41} op=notify sessionId=${sessionId.slice(0, 8)} channel=telegram delivered=${res.ok}`);
|
|
25570
25781
|
return c.json({ delivered: res.ok, channel: "telegram" }, 200);
|
|
25571
25782
|
}
|
|
25572
25783
|
console.error(
|
|
25573
|
-
`${
|
|
25784
|
+
`${TAG41} op=telegram-unresolved sessionId=${sessionId.slice(0, 8)} botId=${parsed.botId} kind=${resolved.kind}`
|
|
25574
25785
|
);
|
|
25575
25786
|
}
|
|
25576
25787
|
}
|
|
@@ -25580,7 +25791,7 @@ app26.post("/", async (c) => {
|
|
|
25580
25791
|
if (await sendWhatsApp(account, phone, text)) delivered = true;
|
|
25581
25792
|
}
|
|
25582
25793
|
console.error(
|
|
25583
|
-
`${
|
|
25794
|
+
`${TAG41} op=notify sessionId=${sessionId.slice(0, 8)} channel=house-admin phones=${phones.length} delivered=${delivered}`
|
|
25584
25795
|
);
|
|
25585
25796
|
return c.json({ delivered, channel: "house-admin" }, 200);
|
|
25586
25797
|
});
|
|
@@ -25613,18 +25824,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
25613
25824
|
]);
|
|
25614
25825
|
var app27 = new Hono();
|
|
25615
25826
|
app27.post("/", async (c) => {
|
|
25616
|
-
const
|
|
25827
|
+
const TAG78 = "[admin:events]";
|
|
25617
25828
|
let body;
|
|
25618
25829
|
try {
|
|
25619
25830
|
body = await c.req.json();
|
|
25620
25831
|
} catch (err) {
|
|
25621
25832
|
const detail = err instanceof Error ? err.message : String(err);
|
|
25622
|
-
console.error(`${
|
|
25833
|
+
console.error(`${TAG78} reject reason=body-not-json detail=${detail}`);
|
|
25623
25834
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
25624
25835
|
}
|
|
25625
25836
|
const event = typeof body.event === "string" ? body.event : "";
|
|
25626
25837
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
25627
|
-
console.error(`${
|
|
25838
|
+
console.error(`${TAG78} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
25628
25839
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
25629
25840
|
}
|
|
25630
25841
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -26580,13 +26791,13 @@ function buildZip(entries2) {
|
|
|
26580
26791
|
}
|
|
26581
26792
|
|
|
26582
26793
|
// server/lib/account-root-groups.ts
|
|
26583
|
-
var
|
|
26794
|
+
var import_dist10 = __toESM(require_dist8(), 1);
|
|
26584
26795
|
function classifyAccountRoot(schemaMd, rootEntries) {
|
|
26585
|
-
const regions = (0,
|
|
26796
|
+
const regions = (0, import_dist10.parseSchemaRegions)(schemaMd);
|
|
26586
26797
|
if (!regions.parsed) {
|
|
26587
26798
|
return { home: [], system: [...rootEntries], unknown: [], parsed: false, reason: regions.reason };
|
|
26588
26799
|
}
|
|
26589
|
-
const homeOrder = [...regions.ontologyRoots, ...
|
|
26800
|
+
const homeOrder = [...regions.ontologyRoots, ...import_dist10.HOME_FIXED].filter((d, i, a) => a.indexOf(d) === i);
|
|
26590
26801
|
const homeSet = new Set(homeOrder);
|
|
26591
26802
|
const present = new Set(rootEntries);
|
|
26592
26803
|
const home = homeOrder.filter((d) => present.has(d));
|
|
@@ -27729,7 +27940,7 @@ app28.post("/rename", requireAdminSession, async (c) => {
|
|
|
27729
27940
|
var files_default = app28;
|
|
27730
27941
|
|
|
27731
27942
|
// ../lib/graph-search/src/index.ts
|
|
27732
|
-
var
|
|
27943
|
+
var import_dist11 = __toESM(require_dist5());
|
|
27733
27944
|
import { int } from "neo4j-driver";
|
|
27734
27945
|
|
|
27735
27946
|
// ../lib/graph-search/src/rrf-fusion.ts
|
|
@@ -27979,7 +28190,7 @@ async function bm25Only(session, params) {
|
|
|
27979
28190
|
${scopeClause}
|
|
27980
28191
|
${agentClause}
|
|
27981
28192
|
${labelClause}
|
|
27982
|
-
AND ${(0,
|
|
28193
|
+
AND ${(0, import_dist11.notTrashed)("node")}
|
|
27983
28194
|
${kwClause}
|
|
27984
28195
|
RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
|
|
27985
28196
|
ORDER BY score DESC
|
|
@@ -28141,7 +28352,7 @@ async function hybrid(session, embed2, params) {
|
|
|
28141
28352
|
WHERE node.accountId = $accountId
|
|
28142
28353
|
${scopeClause}
|
|
28143
28354
|
${agentClause}
|
|
28144
|
-
AND ${(0,
|
|
28355
|
+
AND ${(0, import_dist11.notTrashed)("node")}
|
|
28145
28356
|
${keywordClause}
|
|
28146
28357
|
RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
|
|
28147
28358
|
ORDER BY score DESC
|
|
@@ -28240,7 +28451,7 @@ async function hybrid(session, embed2, params) {
|
|
|
28240
28451
|
const propResult = await session.run(
|
|
28241
28452
|
`MATCH (node)
|
|
28242
28453
|
WHERE node.accountId = $accountId
|
|
28243
|
-
AND ${(0,
|
|
28454
|
+
AND ${(0, import_dist11.notTrashed)("node")}
|
|
28244
28455
|
AND node.keywords IS NOT NULL
|
|
28245
28456
|
AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
|
|
28246
28457
|
${propScope.clause}
|
|
@@ -28292,7 +28503,7 @@ async function hybrid(session, embed2, params) {
|
|
|
28292
28503
|
const propResult = await session.run(
|
|
28293
28504
|
`MATCH (node)
|
|
28294
28505
|
WHERE node.accountId = $accountId
|
|
28295
|
-
AND ${(0,
|
|
28506
|
+
AND ${(0, import_dist11.notTrashed)("node")}
|
|
28296
28507
|
AND node.keywords IS NOT NULL
|
|
28297
28508
|
AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
|
|
28298
28509
|
${propScope.clause}
|
|
@@ -28399,7 +28610,7 @@ async function hybrid(session, embed2, params) {
|
|
|
28399
28610
|
`UNWIND $nodeIds AS nid
|
|
28400
28611
|
MATCH (n)-[r]-(related)
|
|
28401
28612
|
WHERE elementId(n) = nid
|
|
28402
|
-
AND ${(0,
|
|
28613
|
+
AND ${(0, import_dist11.notTrashed)("related")}
|
|
28403
28614
|
${expandScopeClause}
|
|
28404
28615
|
${expandAgentClause}
|
|
28405
28616
|
WITH nid, n, r, related
|
|
@@ -28627,8 +28838,8 @@ var graph_search_default = app29;
|
|
|
28627
28838
|
import neo4j2 from "neo4j-driver";
|
|
28628
28839
|
|
|
28629
28840
|
// app/lib/graph-labels.ts
|
|
28630
|
-
var import_dist11 = __toESM(require_dist9(), 1);
|
|
28631
28841
|
var import_dist12 = __toESM(require_dist9(), 1);
|
|
28842
|
+
var import_dist13 = __toESM(require_dist9(), 1);
|
|
28632
28843
|
var HIDDEN_BY_DEFAULT_LABELS = Object.freeze(
|
|
28633
28844
|
/* @__PURE__ */ new Set(["Chunk", "GraphPreference"])
|
|
28634
28845
|
);
|
|
@@ -28712,14 +28923,14 @@ var EXCLUDED_EDGE_TYPES = Object.freeze(
|
|
|
28712
28923
|
])
|
|
28713
28924
|
);
|
|
28714
28925
|
function isKnownLabel(label) {
|
|
28715
|
-
return Object.prototype.hasOwnProperty.call(
|
|
28926
|
+
return Object.prototype.hasOwnProperty.call(import_dist13.GRAPH_LABEL_COLOURS, label);
|
|
28716
28927
|
}
|
|
28717
28928
|
function isHiddenByDefault(label) {
|
|
28718
28929
|
return HIDDEN_BY_DEFAULT_LABELS.has(label);
|
|
28719
28930
|
}
|
|
28720
28931
|
|
|
28721
28932
|
// server/lib/top-level-labels.ts
|
|
28722
|
-
var
|
|
28933
|
+
var import_dist14 = __toESM(require_dist9(), 1);
|
|
28723
28934
|
import { readdirSync as readdirSync26, readFileSync as readFileSync41 } from "fs";
|
|
28724
28935
|
import { join as join51, resolve as resolve33 } from "path";
|
|
28725
28936
|
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
@@ -28856,7 +29067,7 @@ function getTopLevelLabelAllowlist(opts = {}) {
|
|
|
28856
29067
|
const referencesDir = opts.referencesDir ?? resolveReferencesDir();
|
|
28857
29068
|
const { labels: derived, contributingFiles } = parseTableTopLevelLabels(referencesDir);
|
|
28858
29069
|
const excluded = [];
|
|
28859
|
-
for (const label of
|
|
29070
|
+
for (const label of import_dist14.ADDITIONAL_BASE_LABELS) {
|
|
28860
29071
|
if (derived.delete(label)) excluded.push(label);
|
|
28861
29072
|
}
|
|
28862
29073
|
const derivedCount = derived.size;
|
|
@@ -31189,7 +31400,7 @@ function managerLogFollowUrl(sessionId, opts) {
|
|
|
31189
31400
|
}
|
|
31190
31401
|
|
|
31191
31402
|
// server/routes/admin/linkedin-ingest.ts
|
|
31192
|
-
var
|
|
31403
|
+
var TAG42 = "[linkedin-ingest-route]";
|
|
31193
31404
|
var UUID4 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
31194
31405
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
31195
31406
|
var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
|
|
@@ -31314,28 +31525,28 @@ app45.post("/", requireIngestToken, async (c) => {
|
|
|
31314
31525
|
try {
|
|
31315
31526
|
body = await c.req.json();
|
|
31316
31527
|
} catch {
|
|
31317
|
-
console.error(
|
|
31528
|
+
console.error(TAG42 + " rejected status=400 reason=schema:body-not-json");
|
|
31318
31529
|
return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
|
|
31319
31530
|
}
|
|
31320
31531
|
const v = validate2(body);
|
|
31321
31532
|
if (!v.ok) {
|
|
31322
|
-
console.error(
|
|
31533
|
+
console.error(TAG42 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
|
|
31323
31534
|
return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
|
|
31324
31535
|
}
|
|
31325
31536
|
const envelope = v.envelope;
|
|
31326
31537
|
const senderId = c.var.ingestAccountId ?? "";
|
|
31327
31538
|
if (!senderId) {
|
|
31328
|
-
console.error(
|
|
31539
|
+
console.error(TAG42 + " rejected status=500 reason=admin-account-not-resolved");
|
|
31329
31540
|
return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
|
|
31330
31541
|
}
|
|
31331
31542
|
const payloadBytes = JSON.stringify(envelope).length;
|
|
31332
31543
|
console.log(
|
|
31333
|
-
|
|
31544
|
+
TAG42 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
|
|
31334
31545
|
);
|
|
31335
31546
|
const initialMessage = buildInitialMessage(envelope);
|
|
31336
31547
|
const spawnStart = Date.now();
|
|
31337
31548
|
const sessionId = randomUUID9();
|
|
31338
|
-
console.log(
|
|
31549
|
+
console.log(TAG42 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
31339
31550
|
const spawned = await managerRcSpawn({
|
|
31340
31551
|
sessionId,
|
|
31341
31552
|
initialMessage,
|
|
@@ -31348,12 +31559,12 @@ app45.post("/", requireIngestToken, async (c) => {
|
|
|
31348
31559
|
});
|
|
31349
31560
|
if ("error" in spawned) {
|
|
31350
31561
|
console.error(
|
|
31351
|
-
|
|
31562
|
+
TAG42 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
|
|
31352
31563
|
);
|
|
31353
31564
|
return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
|
|
31354
31565
|
}
|
|
31355
31566
|
console.log(
|
|
31356
|
-
|
|
31567
|
+
TAG42 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
|
|
31357
31568
|
);
|
|
31358
31569
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
31359
31570
|
});
|
|
@@ -31361,7 +31572,7 @@ var linkedin_ingest_default = app45;
|
|
|
31361
31572
|
|
|
31362
31573
|
// server/routes/admin/post-turn-context.ts
|
|
31363
31574
|
import neo4j3 from "neo4j-driver";
|
|
31364
|
-
var
|
|
31575
|
+
var TAG43 = "[post-turn-context]";
|
|
31365
31576
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
31366
31577
|
"embedding",
|
|
31367
31578
|
"passwordHash",
|
|
@@ -31403,7 +31614,7 @@ var app46 = new Hono();
|
|
|
31403
31614
|
app46.get("/", async (c) => {
|
|
31404
31615
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
31405
31616
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
31406
|
-
console.error(`${
|
|
31617
|
+
console.error(`${TAG43} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
31407
31618
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
31408
31619
|
}
|
|
31409
31620
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -31412,7 +31623,7 @@ app46.get("/", async (c) => {
|
|
|
31412
31623
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
31413
31624
|
const offender = tokens.find((t) => !isLoopbackAddr4(t));
|
|
31414
31625
|
if (offender !== void 0) {
|
|
31415
|
-
console.error(`${
|
|
31626
|
+
console.error(`${TAG43} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
31416
31627
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
31417
31628
|
}
|
|
31418
31629
|
}
|
|
@@ -31444,7 +31655,7 @@ app46.get("/", async (c) => {
|
|
|
31444
31655
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
31445
31656
|
const total = Date.now() - started2;
|
|
31446
31657
|
console.log(
|
|
31447
|
-
`${
|
|
31658
|
+
`${TAG43} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
|
|
31448
31659
|
);
|
|
31449
31660
|
return c.json({
|
|
31450
31661
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -31453,7 +31664,7 @@ app46.get("/", async (c) => {
|
|
|
31453
31664
|
const elapsed = Date.now() - started2;
|
|
31454
31665
|
const message = err instanceof Error ? err.message : String(err);
|
|
31455
31666
|
console.error(
|
|
31456
|
-
`${
|
|
31667
|
+
`${TAG43} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
|
|
31457
31668
|
);
|
|
31458
31669
|
return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
|
|
31459
31670
|
} finally {
|
|
@@ -31566,7 +31777,7 @@ function formatPreviousContext(writes) {
|
|
|
31566
31777
|
}
|
|
31567
31778
|
|
|
31568
31779
|
// server/routes/admin/public-session-context.ts
|
|
31569
|
-
var
|
|
31780
|
+
var TAG44 = "[public-session-context]";
|
|
31570
31781
|
function isLoopbackAddr5(addr) {
|
|
31571
31782
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
31572
31783
|
}
|
|
@@ -31574,7 +31785,7 @@ var app47 = new Hono();
|
|
|
31574
31785
|
app47.get("/", async (c) => {
|
|
31575
31786
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
31576
31787
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
31577
|
-
console.error(`${
|
|
31788
|
+
console.error(`${TAG44} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
31578
31789
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
31579
31790
|
}
|
|
31580
31791
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -31583,7 +31794,7 @@ app47.get("/", async (c) => {
|
|
|
31583
31794
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
31584
31795
|
const offender = tokens.find((t) => !isLoopbackAddr5(t));
|
|
31585
31796
|
if (offender !== void 0) {
|
|
31586
|
-
console.error(`${
|
|
31797
|
+
console.error(`${TAG44} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
31587
31798
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
31588
31799
|
}
|
|
31589
31800
|
}
|
|
@@ -31597,14 +31808,14 @@ app47.get("/", async (c) => {
|
|
|
31597
31808
|
const writes = await fetchSliceWrites(session, sliceToken, accountId);
|
|
31598
31809
|
const total = Date.now() - started2;
|
|
31599
31810
|
console.log(
|
|
31600
|
-
`${
|
|
31811
|
+
`${TAG44} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
31601
31812
|
);
|
|
31602
31813
|
return c.json({ writes });
|
|
31603
31814
|
} catch (err) {
|
|
31604
31815
|
const elapsed = Date.now() - started2;
|
|
31605
31816
|
const message = err instanceof Error ? err.message : String(err);
|
|
31606
31817
|
console.error(
|
|
31607
|
-
`${
|
|
31818
|
+
`${TAG44} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
|
|
31608
31819
|
);
|
|
31609
31820
|
return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
|
|
31610
31821
|
} finally {
|
|
@@ -31623,7 +31834,7 @@ function getWebchatGateway() {
|
|
|
31623
31834
|
}
|
|
31624
31835
|
|
|
31625
31836
|
// server/routes/admin/public-session-exit.ts
|
|
31626
|
-
var
|
|
31837
|
+
var TAG45 = "[public-session-exit-route]";
|
|
31627
31838
|
function isLoopbackAddr6(addr) {
|
|
31628
31839
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
31629
31840
|
}
|
|
@@ -31631,7 +31842,7 @@ var app48 = new Hono();
|
|
|
31631
31842
|
app48.post("/", async (c) => {
|
|
31632
31843
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
31633
31844
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
31634
|
-
console.error(`${
|
|
31845
|
+
console.error(`${TAG45} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
31635
31846
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
31636
31847
|
}
|
|
31637
31848
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -31640,7 +31851,7 @@ app48.post("/", async (c) => {
|
|
|
31640
31851
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
31641
31852
|
const offender = tokens.find((t) => !isLoopbackAddr6(t));
|
|
31642
31853
|
if (offender !== void 0) {
|
|
31643
|
-
console.error(`${
|
|
31854
|
+
console.error(`${TAG45} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
31644
31855
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
31645
31856
|
}
|
|
31646
31857
|
}
|
|
@@ -31654,7 +31865,7 @@ app48.post("/", async (c) => {
|
|
|
31654
31865
|
if (!sessionId) return c.json({ error: "sessionId required" }, 400);
|
|
31655
31866
|
const gateway = getWebchatGateway();
|
|
31656
31867
|
if (!gateway) {
|
|
31657
|
-
console.error(`${
|
|
31868
|
+
console.error(`${TAG45} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
|
|
31658
31869
|
return c.json({ error: "webchat-gateway-unset" }, 503);
|
|
31659
31870
|
}
|
|
31660
31871
|
gateway.handlePublicSessionExit(sessionId);
|
|
@@ -31663,7 +31874,7 @@ app48.post("/", async (c) => {
|
|
|
31663
31874
|
var public_session_exit_default = app48;
|
|
31664
31875
|
|
|
31665
31876
|
// server/routes/admin/access-session-evict.ts
|
|
31666
|
-
var
|
|
31877
|
+
var TAG46 = "[access-session-evict]";
|
|
31667
31878
|
function isLoopbackAddr7(addr) {
|
|
31668
31879
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
31669
31880
|
}
|
|
@@ -31671,7 +31882,7 @@ var app49 = new Hono();
|
|
|
31671
31882
|
app49.post("/", async (c) => {
|
|
31672
31883
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
31673
31884
|
if (!isLoopbackAddr7(remoteAddr)) {
|
|
31674
|
-
console.error(`${
|
|
31885
|
+
console.error(`${TAG46} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
31675
31886
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
31676
31887
|
}
|
|
31677
31888
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -31680,7 +31891,7 @@ app49.post("/", async (c) => {
|
|
|
31680
31891
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
31681
31892
|
const offender = tokens.find((t) => !isLoopbackAddr7(t));
|
|
31682
31893
|
if (offender !== void 0) {
|
|
31683
|
-
console.error(`${
|
|
31894
|
+
console.error(`${TAG46} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
31684
31895
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
31685
31896
|
}
|
|
31686
31897
|
}
|
|
@@ -31693,13 +31904,13 @@ app49.post("/", async (c) => {
|
|
|
31693
31904
|
const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
|
|
31694
31905
|
if (!grantId) return c.json({ error: "grantId required" }, 400);
|
|
31695
31906
|
const dropped = evictAccessSessionsByGrant(grantId);
|
|
31696
|
-
console.log(`${
|
|
31907
|
+
console.log(`${TAG46} grantId=${grantId} dropped=${dropped}`);
|
|
31697
31908
|
return c.json({ ok: true, dropped });
|
|
31698
31909
|
});
|
|
31699
31910
|
var access_session_evict_default = app49;
|
|
31700
31911
|
|
|
31701
31912
|
// server/routes/admin/enrol-person.ts
|
|
31702
|
-
var
|
|
31913
|
+
var TAG47 = "[enrol]";
|
|
31703
31914
|
function isLoopbackAddr8(addr) {
|
|
31704
31915
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
31705
31916
|
}
|
|
@@ -31708,7 +31919,7 @@ var app50 = new Hono();
|
|
|
31708
31919
|
app50.post("/", async (c) => {
|
|
31709
31920
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
31710
31921
|
if (!isLoopbackAddr8(remoteAddr)) {
|
|
31711
|
-
console.error(`${
|
|
31922
|
+
console.error(`${TAG47} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
31712
31923
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
31713
31924
|
}
|
|
31714
31925
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -31717,7 +31928,7 @@ app50.post("/", async (c) => {
|
|
|
31717
31928
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
31718
31929
|
const offender = tokens.find((t) => !isLoopbackAddr8(t));
|
|
31719
31930
|
if (offender !== void 0) {
|
|
31720
|
-
console.error(`${
|
|
31931
|
+
console.error(`${TAG47} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
31721
31932
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
31722
31933
|
}
|
|
31723
31934
|
}
|
|
@@ -31742,7 +31953,7 @@ app50.post("/", async (c) => {
|
|
|
31742
31953
|
}
|
|
31743
31954
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
31744
31955
|
if (!accountId) {
|
|
31745
|
-
console.error(`${
|
|
31956
|
+
console.error(`${TAG47} op=person result=no-account-id`);
|
|
31746
31957
|
return c.json({ error: "no-account-id" }, 500);
|
|
31747
31958
|
}
|
|
31748
31959
|
let personId;
|
|
@@ -31750,7 +31961,7 @@ app50.post("/", async (c) => {
|
|
|
31750
31961
|
personId = await enrolPerson({ accountId, phone, email, agentSlug });
|
|
31751
31962
|
} catch (err) {
|
|
31752
31963
|
console.error(
|
|
31753
|
-
`${
|
|
31964
|
+
`${TAG47} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
31754
31965
|
);
|
|
31755
31966
|
return c.json({ error: "enrol-failed" }, 500);
|
|
31756
31967
|
}
|
|
@@ -31760,11 +31971,11 @@ app50.post("/", async (c) => {
|
|
|
31760
31971
|
if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
|
|
31761
31972
|
} catch (err) {
|
|
31762
31973
|
console.error(
|
|
31763
|
-
`${
|
|
31974
|
+
`${TAG47} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
31764
31975
|
);
|
|
31765
31976
|
}
|
|
31766
31977
|
console.log(
|
|
31767
|
-
`${
|
|
31978
|
+
`${TAG47} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
|
|
31768
31979
|
);
|
|
31769
31980
|
return c.json({ personId, grant }, 200);
|
|
31770
31981
|
});
|
|
@@ -33832,7 +34043,7 @@ function toNum(v) {
|
|
|
33832
34043
|
}
|
|
33833
34044
|
|
|
33834
34045
|
// server/routes/admin/tasks-list.ts
|
|
33835
|
-
var
|
|
34046
|
+
var TAG48 = "[task-timer]";
|
|
33836
34047
|
var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
|
|
33837
34048
|
var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
|
|
33838
34049
|
var app57 = new Hono();
|
|
@@ -33840,12 +34051,12 @@ app57.get("/", requireAdminSession, async (c) => {
|
|
|
33840
34051
|
const cacheKey = c.var.cacheKey;
|
|
33841
34052
|
const accountId = getAccountIdForSession(cacheKey);
|
|
33842
34053
|
if (!accountId) {
|
|
33843
|
-
console.error(`${
|
|
34054
|
+
console.error(`${TAG48} op=list auth-rejected reason="no account for session"`);
|
|
33844
34055
|
return c.json({ error: "Account not found for session" }, 401);
|
|
33845
34056
|
}
|
|
33846
34057
|
const cacheStart = Date.now();
|
|
33847
34058
|
const cached3 = await getOrCompute("tasks-list", accountId, () => computeTaskList(accountId));
|
|
33848
|
-
console.log(`${
|
|
34059
|
+
console.log(`${TAG48} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
|
|
33849
34060
|
if (cached3.value === null) {
|
|
33850
34061
|
return c.json({ error: "tasks-list-failed" }, 500);
|
|
33851
34062
|
}
|
|
@@ -33946,13 +34157,13 @@ async function computeTaskList(accountId) {
|
|
|
33946
34157
|
orphans = orphanResult.records.length > 0 ? toNum(orphanResult.records[0].get("orphans")) : 0;
|
|
33947
34158
|
} catch (err) {
|
|
33948
34159
|
console.error(
|
|
33949
|
-
`${
|
|
34160
|
+
`${TAG48} op=session-orphans-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
33950
34161
|
);
|
|
33951
34162
|
orphans = -1;
|
|
33952
34163
|
}
|
|
33953
34164
|
if (orphans > 0) {
|
|
33954
34165
|
console.error(
|
|
33955
|
-
`${
|
|
34166
|
+
`${TAG48} op=session-orphans account=${accountId} orphans=${orphans} detail="task marked for a session spawn that never linked; the spawned session is unreachable from its row"`
|
|
33956
34167
|
);
|
|
33957
34168
|
}
|
|
33958
34169
|
let orphanEntries = 0;
|
|
@@ -33971,14 +34182,14 @@ async function computeTaskList(accountId) {
|
|
|
33971
34182
|
orphanAdjustments = orphanTime.records.length > 0 ? toNum(orphanTime.records[0].get("orphanAdjustments")) : 0;
|
|
33972
34183
|
} catch (err) {
|
|
33973
34184
|
console.error(
|
|
33974
|
-
`${
|
|
34185
|
+
`${TAG48} op=orphan-time-records-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
33975
34186
|
);
|
|
33976
34187
|
orphanEntries = -1;
|
|
33977
34188
|
orphanAdjustments = -1;
|
|
33978
34189
|
}
|
|
33979
34190
|
if (orphanEntries > 0 || orphanAdjustments > 0) {
|
|
33980
34191
|
console.error(
|
|
33981
|
-
`${
|
|
34192
|
+
`${TAG48} op=orphan-time-records account=${accountId} orphanEntries=${orphanEntries} orphanAdjustments=${orphanAdjustments} detail="time records whose task no longer exists; something removed the task without its records"`
|
|
33982
34193
|
);
|
|
33983
34194
|
}
|
|
33984
34195
|
const linkedIds = [...open3, ...completed].map((r) => r.sessionId).filter((s) => s !== null);
|
|
@@ -33991,7 +34202,7 @@ async function computeTaskList(accountId) {
|
|
|
33991
34202
|
const walk = enumerateJsonlsWithSkips(join60(cfg, "projects"));
|
|
33992
34203
|
if (walk.skipped > 0) {
|
|
33993
34204
|
console.error(
|
|
33994
|
-
`${
|
|
34205
|
+
`${TAG48} op=session-dangling-census-incomplete account=${accountId} skipped=${walk.skipped} detail="a slug the walk could not read contributes no session ids, so its links cannot be judged"`
|
|
33995
34206
|
);
|
|
33996
34207
|
dangling = null;
|
|
33997
34208
|
} else {
|
|
@@ -34000,28 +34211,28 @@ async function computeTaskList(accountId) {
|
|
|
34000
34211
|
}
|
|
34001
34212
|
} catch (err) {
|
|
34002
34213
|
console.error(
|
|
34003
|
-
`${
|
|
34214
|
+
`${TAG48} op=session-dangling-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
34004
34215
|
);
|
|
34005
34216
|
dangling = null;
|
|
34006
34217
|
}
|
|
34007
34218
|
}
|
|
34008
34219
|
if (dangling !== null && dangling > 0) {
|
|
34009
34220
|
console.error(
|
|
34010
|
-
`${
|
|
34221
|
+
`${TAG48} op=session-dangling account=${accountId} dangling=${dangling} linked=${linkedIds.length} detail="a task links a session with no JSONL on disk; clicking it will not resume"`
|
|
34011
34222
|
);
|
|
34012
34223
|
}
|
|
34013
34224
|
const returned = result.records.length;
|
|
34014
34225
|
if (returned < graphTotal) {
|
|
34015
34226
|
console.error(
|
|
34016
|
-
`${
|
|
34227
|
+
`${TAG48} op=list row-count-shortfall account=${accountId} returned=${returned} graphTotal=${graphTotal} missing=${graphTotal - returned}`
|
|
34017
34228
|
);
|
|
34018
34229
|
}
|
|
34019
34230
|
console.log(
|
|
34020
|
-
`${
|
|
34231
|
+
`${TAG48} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned} sessionLinked=${sessionLinked} sessionOrphans=${orphans < 0 ? "n/a" : orphans} sessionDangling=${dangling === null ? "n/a" : dangling}`
|
|
34021
34232
|
);
|
|
34022
34233
|
return { open: open3, completed };
|
|
34023
34234
|
} catch (err) {
|
|
34024
|
-
console.error(`${
|
|
34235
|
+
console.error(`${TAG48} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
34025
34236
|
return null;
|
|
34026
34237
|
} finally {
|
|
34027
34238
|
await session.close();
|
|
@@ -34031,7 +34242,7 @@ var tasks_list_default = app57;
|
|
|
34031
34242
|
|
|
34032
34243
|
// server/routes/admin/task-timer-start.ts
|
|
34033
34244
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
34034
|
-
var
|
|
34245
|
+
var TAG49 = "[task-timer]";
|
|
34035
34246
|
var app58 = new Hono();
|
|
34036
34247
|
app58.post("/", requireAdminSession, async (c) => {
|
|
34037
34248
|
const cacheKey = c.var.cacheKey;
|
|
@@ -34046,7 +34257,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
34046
34257
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
34047
34258
|
if (!taskId) {
|
|
34048
34259
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
34049
|
-
console.error(`${
|
|
34260
|
+
console.error(`${TAG49} op=timer-start rejected reason=${reason} account=${accountId}`);
|
|
34050
34261
|
return c.json({ error: "taskId required" }, 400);
|
|
34051
34262
|
}
|
|
34052
34263
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -34057,7 +34268,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
34057
34268
|
{ taskId, accountId }
|
|
34058
34269
|
);
|
|
34059
34270
|
if (target.records.length === 0) {
|
|
34060
|
-
console.error(`${
|
|
34271
|
+
console.error(`${TAG49} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
|
|
34061
34272
|
return c.json({ error: "task-not-found" }, 404);
|
|
34062
34273
|
}
|
|
34063
34274
|
const open3 = await session.run(
|
|
@@ -34069,7 +34280,7 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
34069
34280
|
const priorEntryId = open3.records[0]?.get("entryId");
|
|
34070
34281
|
const priorStartedAt = open3.records[0]?.get("startedAt");
|
|
34071
34282
|
if (priorEntryId) {
|
|
34072
|
-
console.log(`${
|
|
34283
|
+
console.log(`${TAG49} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
|
|
34073
34284
|
invalidate("tasks-list", accountId);
|
|
34074
34285
|
return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
|
|
34075
34286
|
}
|
|
@@ -34080,11 +34291,11 @@ app58.post("/", requireAdminSession, async (c) => {
|
|
|
34080
34291
|
CREATE (te)-[:LOGGED_AGAINST]->(t)`,
|
|
34081
34292
|
{ taskId, accountId, entryId, now }
|
|
34082
34293
|
);
|
|
34083
|
-
console.log(`${
|
|
34294
|
+
console.log(`${TAG49} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
|
|
34084
34295
|
invalidate("tasks-list", accountId);
|
|
34085
34296
|
return c.json({ ok: true, running: true, entryId, startedAt: now });
|
|
34086
34297
|
} catch (err) {
|
|
34087
|
-
console.error(`${
|
|
34298
|
+
console.error(`${TAG49} op=start error="${err instanceof Error ? err.message : String(err)}"`);
|
|
34088
34299
|
return c.json({ error: "task-timer-start-failed" }, 500);
|
|
34089
34300
|
} finally {
|
|
34090
34301
|
await session.close();
|
|
@@ -34094,7 +34305,7 @@ var task_timer_start_default = app58;
|
|
|
34094
34305
|
|
|
34095
34306
|
// server/routes/admin/task-timer-stop.ts
|
|
34096
34307
|
import neo4j5 from "neo4j-driver";
|
|
34097
|
-
var
|
|
34308
|
+
var TAG50 = "[task-timer]";
|
|
34098
34309
|
var app59 = new Hono();
|
|
34099
34310
|
app59.post("/", requireAdminSession, async (c) => {
|
|
34100
34311
|
const cacheKey = c.var.cacheKey;
|
|
@@ -34109,7 +34320,7 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
34109
34320
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
34110
34321
|
if (!taskId) {
|
|
34111
34322
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
34112
|
-
console.error(`${
|
|
34323
|
+
console.error(`${TAG50} op=timer-stop rejected reason=${reason} account=${accountId}`);
|
|
34113
34324
|
return c.json({ error: "taskId required" }, 400);
|
|
34114
34325
|
}
|
|
34115
34326
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -34130,7 +34341,7 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
34130
34341
|
{ taskId, accountId }
|
|
34131
34342
|
);
|
|
34132
34343
|
const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
|
|
34133
|
-
console.log(`${
|
|
34344
|
+
console.log(`${TAG50} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
|
|
34134
34345
|
invalidate("tasks-list", accountId);
|
|
34135
34346
|
return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
|
|
34136
34347
|
}
|
|
@@ -34154,12 +34365,12 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
34154
34365
|
const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
|
|
34155
34366
|
const sumAdjustments = toNum(verify.records[0]?.get("sumAdjustments"));
|
|
34156
34367
|
const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
|
|
34157
|
-
console.log(`${
|
|
34158
|
-
console.log(`${
|
|
34368
|
+
console.log(`${TAG50} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
|
|
34369
|
+
console.log(`${TAG50} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
|
|
34159
34370
|
invalidate("tasks-list", accountId);
|
|
34160
34371
|
return c.json({ ok: true, running: false, seconds, secondsLogged });
|
|
34161
34372
|
} catch (err) {
|
|
34162
|
-
console.error(`${
|
|
34373
|
+
console.error(`${TAG50} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
|
|
34163
34374
|
return c.json({ error: "task-timer-stop-failed" }, 500);
|
|
34164
34375
|
} finally {
|
|
34165
34376
|
await session.close();
|
|
@@ -34168,7 +34379,7 @@ app59.post("/", requireAdminSession, async (c) => {
|
|
|
34168
34379
|
var task_timer_stop_default = app59;
|
|
34169
34380
|
|
|
34170
34381
|
// server/routes/admin/task-complete.ts
|
|
34171
|
-
var
|
|
34382
|
+
var TAG51 = "[task-timer]";
|
|
34172
34383
|
var app60 = new Hono();
|
|
34173
34384
|
app60.post("/", requireAdminSession, async (c) => {
|
|
34174
34385
|
const cacheKey = c.var.cacheKey;
|
|
@@ -34183,7 +34394,7 @@ app60.post("/", requireAdminSession, async (c) => {
|
|
|
34183
34394
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
34184
34395
|
if (!taskId) {
|
|
34185
34396
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
34186
|
-
console.error(`${
|
|
34397
|
+
console.error(`${TAG51} op=complete rejected reason=${reason} account=${accountId}`);
|
|
34187
34398
|
return c.json({ error: "taskId required" }, 400);
|
|
34188
34399
|
}
|
|
34189
34400
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -34199,11 +34410,11 @@ app60.post("/", requireAdminSession, async (c) => {
|
|
|
34199
34410
|
return c.json({ error: "task-not-found" }, 404);
|
|
34200
34411
|
}
|
|
34201
34412
|
const secondsLogged = toNum(result.records[0].get("secondsLogged"));
|
|
34202
|
-
console.log(`${
|
|
34413
|
+
console.log(`${TAG51} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
|
|
34203
34414
|
invalidate("tasks-list", accountId);
|
|
34204
34415
|
return c.json({ ok: true, status: "completed", secondsLogged });
|
|
34205
34416
|
} catch (err) {
|
|
34206
|
-
console.error(`${
|
|
34417
|
+
console.error(`${TAG51} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
|
|
34207
34418
|
return c.json({ error: "task-complete-failed" }, 500);
|
|
34208
34419
|
} finally {
|
|
34209
34420
|
await session.close();
|
|
@@ -34214,7 +34425,7 @@ var task_complete_default = app60;
|
|
|
34214
34425
|
// server/routes/admin/task-time-adjust.ts
|
|
34215
34426
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
34216
34427
|
import neo4j6 from "neo4j-driver";
|
|
34217
|
-
var
|
|
34428
|
+
var TAG52 = "[task-time-adjust]";
|
|
34218
34429
|
var app61 = new Hono();
|
|
34219
34430
|
app61.post("/", requireAdminSession, async (c) => {
|
|
34220
34431
|
const cacheKey = c.var.cacheKey;
|
|
@@ -34224,23 +34435,23 @@ app61.post("/", requireAdminSession, async (c) => {
|
|
|
34224
34435
|
try {
|
|
34225
34436
|
body = await c.req.json();
|
|
34226
34437
|
} catch {
|
|
34227
|
-
console.error(`${
|
|
34438
|
+
console.error(`${TAG52} op=reject reason=bad-json`);
|
|
34228
34439
|
return c.json({ error: "invalid-json" }, 400);
|
|
34229
34440
|
}
|
|
34230
34441
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
34231
34442
|
if (!taskId) {
|
|
34232
34443
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
34233
|
-
console.error(`${
|
|
34444
|
+
console.error(`${TAG52} op=time-adjust rejected reason=${reason} account=${accountId}`);
|
|
34234
34445
|
return c.json({ error: "taskId required" }, 400);
|
|
34235
34446
|
}
|
|
34236
34447
|
const newSeconds = body.newSeconds;
|
|
34237
34448
|
if (typeof newSeconds !== "number" || !Number.isInteger(newSeconds) || newSeconds < 0) {
|
|
34238
|
-
console.error(`${
|
|
34449
|
+
console.error(`${TAG52} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
|
|
34239
34450
|
return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
|
|
34240
34451
|
}
|
|
34241
34452
|
const adjustmentId = randomUUID12();
|
|
34242
34453
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
34243
|
-
console.log(`${
|
|
34454
|
+
console.log(`${TAG52} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
|
|
34244
34455
|
const session = getSession();
|
|
34245
34456
|
try {
|
|
34246
34457
|
const guard = await session.run(
|
|
@@ -34250,12 +34461,12 @@ app61.post("/", requireAdminSession, async (c) => {
|
|
|
34250
34461
|
{ taskId, accountId }
|
|
34251
34462
|
);
|
|
34252
34463
|
if (guard.records.length === 0) {
|
|
34253
|
-
console.error(`${
|
|
34464
|
+
console.error(`${TAG52} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
34254
34465
|
return c.json({ error: "task-not-found" }, 404);
|
|
34255
34466
|
}
|
|
34256
34467
|
const openCount = toNum(guard.records[0].get("openCount"));
|
|
34257
34468
|
if (openCount > 0) {
|
|
34258
|
-
console.error(`${
|
|
34469
|
+
console.error(`${TAG52} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
34259
34470
|
return c.json({ error: "task-timer-running" }, 409);
|
|
34260
34471
|
}
|
|
34261
34472
|
const previousSeconds = toNum(guard.records[0].get("previousSeconds"));
|
|
@@ -34281,11 +34492,11 @@ app61.post("/", requireAdminSession, async (c) => {
|
|
|
34281
34492
|
}
|
|
34282
34493
|
);
|
|
34283
34494
|
const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
|
|
34284
|
-
console.log(`${
|
|
34495
|
+
console.log(`${TAG52} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
|
|
34285
34496
|
invalidate("tasks-list", accountId);
|
|
34286
34497
|
return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
|
|
34287
34498
|
} catch (err) {
|
|
34288
|
-
console.error(`${
|
|
34499
|
+
console.error(`${TAG52} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
34289
34500
|
return c.json({ error: "task-time-adjust-failed" }, 500);
|
|
34290
34501
|
} finally {
|
|
34291
34502
|
await session.close();
|
|
@@ -34295,7 +34506,7 @@ var task_time_adjust_default = app61;
|
|
|
34295
34506
|
|
|
34296
34507
|
// server/routes/admin/task-delete.ts
|
|
34297
34508
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
34298
|
-
var
|
|
34509
|
+
var TAG53 = "[task-delete]";
|
|
34299
34510
|
var app62 = new Hono();
|
|
34300
34511
|
app62.post("/", requireAdminSession, async (c) => {
|
|
34301
34512
|
const cacheKey = c.var.cacheKey;
|
|
@@ -34305,18 +34516,18 @@ app62.post("/", requireAdminSession, async (c) => {
|
|
|
34305
34516
|
try {
|
|
34306
34517
|
body = await c.req.json();
|
|
34307
34518
|
} catch {
|
|
34308
|
-
console.error(`${
|
|
34519
|
+
console.error(`${TAG53} op=reject reason=bad-json`);
|
|
34309
34520
|
return c.json({ error: "invalid-json" }, 400);
|
|
34310
34521
|
}
|
|
34311
34522
|
const deletionId = randomUUID13();
|
|
34312
34523
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
34313
34524
|
if (!taskId) {
|
|
34314
34525
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
34315
|
-
console.error(`${
|
|
34526
|
+
console.error(`${TAG53} op=reject reason=${reason} deletionId=${deletionId} accountId=${accountId}`);
|
|
34316
34527
|
return c.json({ error: "taskId required" }, 400);
|
|
34317
34528
|
}
|
|
34318
34529
|
console.log(
|
|
34319
|
-
`${
|
|
34530
|
+
`${TAG53} op=request deletionId=${deletionId} taskId=${taskId} accountId=${accountId} confirmed=${body.confirmed === true}`
|
|
34320
34531
|
);
|
|
34321
34532
|
const session = getSession();
|
|
34322
34533
|
try {
|
|
@@ -34332,18 +34543,18 @@ app62.post("/", requireAdminSession, async (c) => {
|
|
|
34332
34543
|
{ taskId, accountId }
|
|
34333
34544
|
);
|
|
34334
34545
|
if (guard.records.length === 0) {
|
|
34335
|
-
console.error(`${
|
|
34546
|
+
console.error(`${TAG53} op=reject reason=no-task deletionId=${deletionId} taskId=${taskId} accountId=${accountId}`);
|
|
34336
34547
|
return c.json({ error: "task-not-found" }, 404);
|
|
34337
34548
|
}
|
|
34338
34549
|
const timeEntries = toNum(guard.records[0].get("timeEntries"));
|
|
34339
34550
|
const openCount = toNum(guard.records[0].get("openCount"));
|
|
34340
34551
|
const adjustments = toNum(guard.records[0].get("adjustments"));
|
|
34341
34552
|
console.log(
|
|
34342
|
-
`${
|
|
34553
|
+
`${TAG53} op=guard deletionId=${deletionId} taskId=${taskId} openCount=${openCount} timeEntries=${timeEntries} adjustments=${adjustments}`
|
|
34343
34554
|
);
|
|
34344
34555
|
if (openCount > 0) {
|
|
34345
34556
|
console.error(
|
|
34346
|
-
`${
|
|
34557
|
+
`${TAG53} op=reject reason=running deletionId=${deletionId} taskId=${taskId} openCount=${openCount}`
|
|
34347
34558
|
);
|
|
34348
34559
|
return c.json({ error: "task-timer-running" }, 409);
|
|
34349
34560
|
}
|
|
@@ -34379,18 +34590,18 @@ app62.post("/", requireAdminSession, async (c) => {
|
|
|
34379
34590
|
const adjustmentsLeft = toNum(after.records[0]?.get("adjustmentsLeft"));
|
|
34380
34591
|
const remaining = taskLeft + entriesLeft + adjustmentsLeft;
|
|
34381
34592
|
console.log(
|
|
34382
|
-
`${
|
|
34593
|
+
`${TAG53} op=persisted deletionId=${deletionId} taskId=${taskId} tasksDeleted=${tasksDeleted} timeEntriesDeleted=${timeEntriesDeleted} adjustmentsDeleted=${adjustmentsDeleted} remaining=${remaining}`
|
|
34383
34594
|
);
|
|
34384
34595
|
if (remaining > 0) {
|
|
34385
34596
|
console.error(
|
|
34386
|
-
`${
|
|
34597
|
+
`${TAG53} op=incomplete deletionId=${deletionId} taskId=${taskId} taskLeft=${taskLeft} entriesLeft=${entriesLeft} adjustmentsLeft=${adjustmentsLeft} detail="the delete returned but rows for this taskId survive"`
|
|
34387
34598
|
);
|
|
34388
34599
|
}
|
|
34389
34600
|
invalidate("tasks-list", accountId);
|
|
34390
34601
|
return c.json({ ok: true, tasksDeleted, timeEntriesDeleted, adjustmentsDeleted, remaining });
|
|
34391
34602
|
} catch (err) {
|
|
34392
34603
|
console.error(
|
|
34393
|
-
`${
|
|
34604
|
+
`${TAG53} op=error deletionId=${deletionId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`
|
|
34394
34605
|
);
|
|
34395
34606
|
return c.json({ error: "task-delete-failed" }, 500);
|
|
34396
34607
|
} finally {
|
|
@@ -34484,7 +34695,7 @@ async function resolveAssignableAdmins(accountId, accountsDir = ACCOUNTS_DIR) {
|
|
|
34484
34695
|
}
|
|
34485
34696
|
|
|
34486
34697
|
// server/routes/admin/task-assign.ts
|
|
34487
|
-
var
|
|
34698
|
+
var TAG54 = "[task-assign]";
|
|
34488
34699
|
var app63 = new Hono();
|
|
34489
34700
|
app63.post("/", requireAdminSession, async (c) => {
|
|
34490
34701
|
const cacheKey = c.var.cacheKey;
|
|
@@ -34499,7 +34710,7 @@ app63.post("/", requireAdminSession, async (c) => {
|
|
|
34499
34710
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
34500
34711
|
if (!taskId) {
|
|
34501
34712
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
34502
|
-
console.error(`${
|
|
34713
|
+
console.error(`${TAG54} op=assign rejected reason=${reason} account=${accountId}`);
|
|
34503
34714
|
return c.json({ error: "taskId required" }, 400);
|
|
34504
34715
|
}
|
|
34505
34716
|
const rawAssignee = body.assigneeUserId;
|
|
@@ -34511,7 +34722,7 @@ app63.post("/", requireAdminSession, async (c) => {
|
|
|
34511
34722
|
const { ids } = await resolveAllowedAssigneeIds(accountId);
|
|
34512
34723
|
if (!ids.has(assigneeUserId)) {
|
|
34513
34724
|
console.error(
|
|
34514
|
-
`${
|
|
34725
|
+
`${TAG54} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
|
|
34515
34726
|
);
|
|
34516
34727
|
return c.json({ error: "assignee-not-in-roster" }, 403);
|
|
34517
34728
|
}
|
|
@@ -34533,7 +34744,7 @@ app63.post("/", requireAdminSession, async (c) => {
|
|
|
34533
34744
|
`MATCH (t:Task {taskId: $taskId, accountId: $accountId}) SET t.updatedAt = $now`,
|
|
34534
34745
|
{ taskId, accountId, now }
|
|
34535
34746
|
);
|
|
34536
|
-
console.log(`${
|
|
34747
|
+
console.log(`${TAG54} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
|
|
34537
34748
|
invalidate("tasks-list", accountId);
|
|
34538
34749
|
return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
|
|
34539
34750
|
}
|
|
@@ -34549,7 +34760,7 @@ app63.post("/", requireAdminSession, async (c) => {
|
|
|
34549
34760
|
);
|
|
34550
34761
|
if (set.records.length === 0) {
|
|
34551
34762
|
console.error(
|
|
34552
|
-
`${
|
|
34763
|
+
`${TAG54} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
|
|
34553
34764
|
);
|
|
34554
34765
|
return c.json({ error: "assignee-no-admin-node" }, 409);
|
|
34555
34766
|
}
|
|
@@ -34557,12 +34768,12 @@ app63.post("/", requireAdminSession, async (c) => {
|
|
|
34557
34768
|
const family = set.records[0].get("familyName") ?? null;
|
|
34558
34769
|
const assigneeName = given && given.trim().length > 0 ? family && family.trim().length > 0 ? `${given.trim()} ${family.trim()}` : given.trim() : null;
|
|
34559
34770
|
console.log(
|
|
34560
|
-
`${
|
|
34771
|
+
`${TAG54} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
|
|
34561
34772
|
);
|
|
34562
34773
|
invalidate("tasks-list", accountId);
|
|
34563
34774
|
return c.json({ ok: true, assigneeUserId, assigneeName });
|
|
34564
34775
|
} catch (err) {
|
|
34565
|
-
console.error(`${
|
|
34776
|
+
console.error(`${TAG54} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
|
|
34566
34777
|
return c.json({ error: "task-assign-failed" }, 500);
|
|
34567
34778
|
} finally {
|
|
34568
34779
|
await session.close();
|
|
@@ -34571,13 +34782,13 @@ app63.post("/", requireAdminSession, async (c) => {
|
|
|
34571
34782
|
var task_assign_default = app63;
|
|
34572
34783
|
|
|
34573
34784
|
// server/routes/admin/task-session-open.ts
|
|
34574
|
-
var
|
|
34785
|
+
var TAG55 = "[task-session]";
|
|
34575
34786
|
var app64 = new Hono();
|
|
34576
34787
|
app64.post("/", requireAdminSession, async (c) => {
|
|
34577
34788
|
const cacheKey = c.var.cacheKey;
|
|
34578
34789
|
const accountId = getAccountIdForSession(cacheKey);
|
|
34579
34790
|
if (!accountId) {
|
|
34580
|
-
console.error(`${
|
|
34791
|
+
console.error(`${TAG55} op=request auth-rejected reason="no account for session"`);
|
|
34581
34792
|
return c.json({ error: "Account not found for session" }, 401);
|
|
34582
34793
|
}
|
|
34583
34794
|
let body;
|
|
@@ -34589,7 +34800,7 @@ app64.post("/", requireAdminSession, async (c) => {
|
|
|
34589
34800
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
34590
34801
|
if (!taskId) {
|
|
34591
34802
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
34592
|
-
console.error(`${
|
|
34803
|
+
console.error(`${TAG55} op=request rejected reason=${reason} account=${accountId}`);
|
|
34593
34804
|
return c.json({ error: "taskId required" }, 400);
|
|
34594
34805
|
}
|
|
34595
34806
|
const session = getSession();
|
|
@@ -34603,14 +34814,14 @@ app64.post("/", requireAdminSession, async (c) => {
|
|
|
34603
34814
|
{ taskId, accountId }
|
|
34604
34815
|
);
|
|
34605
34816
|
if (found.records.length === 0) {
|
|
34606
|
-
console.error(`${
|
|
34817
|
+
console.error(`${TAG55} op=request taskId=${taskId} account=${accountId} result=task-not-found`);
|
|
34607
34818
|
return c.json({ error: "task-not-found" }, 404);
|
|
34608
34819
|
}
|
|
34609
34820
|
const title = found.records[0].get("name") ?? "";
|
|
34610
34821
|
const sessionId = found.records[0].get("sessionId") ?? null;
|
|
34611
34822
|
const description = found.records[0].get("description") ?? "";
|
|
34612
34823
|
const notes = found.records[0].get("notes") ?? "";
|
|
34613
|
-
console.log(`${
|
|
34824
|
+
console.log(`${TAG55} op=request taskId=${taskId} account=${accountId} linked=${sessionId ?? "none"}`);
|
|
34614
34825
|
if (sessionId !== null) return c.json({ sessionId, title, description, notes });
|
|
34615
34826
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
34616
34827
|
const stamped = await session.run(
|
|
@@ -34620,10 +34831,10 @@ app64.post("/", requireAdminSession, async (c) => {
|
|
|
34620
34831
|
{ taskId, accountId, now }
|
|
34621
34832
|
);
|
|
34622
34833
|
const at = stamped.records[0]?.get("at") ?? void 0;
|
|
34623
|
-
console.log(`${
|
|
34834
|
+
console.log(`${TAG55} op=marker taskId=${taskId} stamped=${at !== void 0}`);
|
|
34624
34835
|
return c.json({ sessionId: null, title, description, notes });
|
|
34625
34836
|
} catch (err) {
|
|
34626
|
-
console.error(`${
|
|
34837
|
+
console.error(`${TAG55} op=request taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
34627
34838
|
return c.json({ error: "task-session-open-failed" }, 500);
|
|
34628
34839
|
} finally {
|
|
34629
34840
|
await session.close();
|
|
@@ -34632,13 +34843,13 @@ app64.post("/", requireAdminSession, async (c) => {
|
|
|
34632
34843
|
var task_session_open_default = app64;
|
|
34633
34844
|
|
|
34634
34845
|
// server/routes/admin/task-session-link.ts
|
|
34635
|
-
var
|
|
34846
|
+
var TAG56 = "[task-session]";
|
|
34636
34847
|
var app65 = new Hono();
|
|
34637
34848
|
app65.post("/", requireAdminSession, async (c) => {
|
|
34638
34849
|
const cacheKey = c.var.cacheKey;
|
|
34639
34850
|
const accountId = getAccountIdForSession(cacheKey);
|
|
34640
34851
|
if (!accountId) {
|
|
34641
|
-
console.error(`${
|
|
34852
|
+
console.error(`${TAG56} op=link auth-rejected reason="no account for session"`);
|
|
34642
34853
|
return c.json({ error: "Account not found for session" }, 401);
|
|
34643
34854
|
}
|
|
34644
34855
|
let body;
|
|
@@ -34650,12 +34861,12 @@ app65.post("/", requireAdminSession, async (c) => {
|
|
|
34650
34861
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
34651
34862
|
if (!taskId) {
|
|
34652
34863
|
const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
|
|
34653
|
-
console.error(`${
|
|
34864
|
+
console.error(`${TAG56} op=link rejected reason=${reason} account=${accountId}`);
|
|
34654
34865
|
return c.json({ error: "taskId required" }, 400);
|
|
34655
34866
|
}
|
|
34656
34867
|
const sessionId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : "";
|
|
34657
34868
|
if (!sessionId) {
|
|
34658
|
-
console.error(`${
|
|
34869
|
+
console.error(`${TAG56} op=link rejected reason=missing-sessionId taskId=${taskId} account=${accountId}`);
|
|
34659
34870
|
return c.json({ error: "sessionId required" }, 400);
|
|
34660
34871
|
}
|
|
34661
34872
|
const session = getSession();
|
|
@@ -34669,13 +34880,13 @@ app65.post("/", requireAdminSession, async (c) => {
|
|
|
34669
34880
|
{ taskId, accountId, sessionId }
|
|
34670
34881
|
);
|
|
34671
34882
|
if (state.records.length === 0) {
|
|
34672
|
-
console.error(`${
|
|
34883
|
+
console.error(`${TAG56} op=link taskId=${taskId} account=${accountId} result=task-not-found`);
|
|
34673
34884
|
return c.json({ error: "task-not-found" }, 404);
|
|
34674
34885
|
}
|
|
34675
34886
|
const conversationExists = state.records[0].get("conversationExists") === true;
|
|
34676
34887
|
const priorSessionIds = (state.records[0].get("priorSessionIds") ?? []).filter((s) => typeof s === "string");
|
|
34677
34888
|
if (!conversationExists) {
|
|
34678
|
-
console.error(`${
|
|
34889
|
+
console.error(`${TAG56} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=conversation-absent`);
|
|
34679
34890
|
return c.json({ linked: false, created: false, repointedFrom: null });
|
|
34680
34891
|
}
|
|
34681
34892
|
const stale = priorSessionIds.filter((s) => s !== sessionId);
|
|
@@ -34701,18 +34912,18 @@ app65.post("/", requireAdminSession, async (c) => {
|
|
|
34701
34912
|
const repointedFrom = stale.length > 0 ? stale[0] : null;
|
|
34702
34913
|
if (!linked) {
|
|
34703
34914
|
console.error(
|
|
34704
|
-
`${
|
|
34915
|
+
`${TAG56} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=edge-absent-after-merge linkedTo=${linkedTo ?? "none"}`
|
|
34705
34916
|
);
|
|
34706
34917
|
return c.json({ linked: false, created: false, repointedFrom });
|
|
34707
34918
|
}
|
|
34708
34919
|
console.log(
|
|
34709
|
-
`${
|
|
34920
|
+
`${TAG56} op=link taskId=${taskId} sessionId=${sessionId} created=${created} repointedFrom=${repointedFrom ?? "none"}`
|
|
34710
34921
|
);
|
|
34711
34922
|
invalidate("tasks-list", accountId);
|
|
34712
34923
|
return c.json({ linked: true, created, repointedFrom });
|
|
34713
34924
|
} catch (err) {
|
|
34714
34925
|
console.error(
|
|
34715
|
-
`${
|
|
34926
|
+
`${TAG56} op=link-failed taskId=${taskId} sessionId=${sessionId} reason="${err instanceof Error ? err.message : String(err)}"`
|
|
34716
34927
|
);
|
|
34717
34928
|
return c.json({ error: "task-session-link-failed" }, 500);
|
|
34718
34929
|
} finally {
|
|
@@ -34722,21 +34933,21 @@ app65.post("/", requireAdminSession, async (c) => {
|
|
|
34722
34933
|
var task_session_link_default = app65;
|
|
34723
34934
|
|
|
34724
34935
|
// server/routes/admin/admin-users-list.ts
|
|
34725
|
-
var
|
|
34936
|
+
var TAG57 = "[admin-users]";
|
|
34726
34937
|
var app66 = new Hono();
|
|
34727
34938
|
app66.get("/", requireAdminSession, async (c) => {
|
|
34728
34939
|
const cacheKey = c.var.cacheKey;
|
|
34729
34940
|
const accountId = getAccountIdForSession(cacheKey);
|
|
34730
34941
|
if (!accountId) {
|
|
34731
|
-
console.error(`${
|
|
34942
|
+
console.error(`${TAG57} op=list auth-rejected reason="no account for session"`);
|
|
34732
34943
|
return c.json({ error: "Account not found for session" }, 401);
|
|
34733
34944
|
}
|
|
34734
34945
|
try {
|
|
34735
34946
|
const users = await resolveAssignableAdmins(accountId);
|
|
34736
|
-
console.log(`${
|
|
34947
|
+
console.log(`${TAG57} op=list account=${accountId} count=${users.length}`);
|
|
34737
34948
|
return c.json({ ok: true, users });
|
|
34738
34949
|
} catch (err) {
|
|
34739
|
-
console.error(`${
|
|
34950
|
+
console.error(`${TAG57} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
34740
34951
|
return c.json({ error: "admin-users-list-failed" }, 500);
|
|
34741
34952
|
}
|
|
34742
34953
|
});
|
|
@@ -34744,7 +34955,7 @@ var admin_users_list_default = app66;
|
|
|
34744
34955
|
|
|
34745
34956
|
// server/routes/admin/dispatch-destinations.ts
|
|
34746
34957
|
import { resolve as resolve43 } from "path";
|
|
34747
|
-
var
|
|
34958
|
+
var TAG58 = "[admin:routines]";
|
|
34748
34959
|
function scopeFor(d, houseDir, houseAccountId) {
|
|
34749
34960
|
if (d.channel !== "whatsapp") return null;
|
|
34750
34961
|
if (d.label === "Account manager") return boundSubAccountFor(houseDir, d.destination);
|
|
@@ -34762,7 +34973,7 @@ var app67 = new Hono();
|
|
|
34762
34973
|
app67.get("/", requireAdminSession, async (c) => {
|
|
34763
34974
|
const accountId = getAccountIdForSession(c.var.cacheKey);
|
|
34764
34975
|
if (!accountId) {
|
|
34765
|
-
console.error(`${
|
|
34976
|
+
console.error(`${TAG58} op=destinations auth-rejected reason="no account for session"`);
|
|
34766
34977
|
return c.json({ error: "Account not found for session" }, 401);
|
|
34767
34978
|
}
|
|
34768
34979
|
let houseAccountId = null;
|
|
@@ -34770,7 +34981,7 @@ app67.get("/", requireAdminSession, async (c) => {
|
|
|
34770
34981
|
houseAccountId = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
|
|
34771
34982
|
} catch (err) {
|
|
34772
34983
|
const message = err instanceof Error ? err.message : String(err);
|
|
34773
|
-
console.error(`${
|
|
34984
|
+
console.error(`${TAG58} op=destinations account=${accountId.slice(0, 8)} outcome=house-unresolved reason="${message}"`);
|
|
34774
34985
|
}
|
|
34775
34986
|
const destinations = listDispatchDestinations({ accountsDir: ACCOUNTS_DIR, houseAccountId, accountId });
|
|
34776
34987
|
const houseDir = houseAccountId === null ? null : resolve43(ACCOUNTS_DIR, houseAccountId);
|
|
@@ -34821,7 +35032,7 @@ app67.get("/", requireAdminSession, async (c) => {
|
|
|
34821
35032
|
const scopes = [...byScope.keys()];
|
|
34822
35033
|
const nameScope = scopes.length === 0 ? "none" : scopes.every((s) => s === houseAccountId) ? "house" : scopes.some((s) => s === houseAccountId) ? "mixed" : "account";
|
|
34823
35034
|
console.log(
|
|
34824
|
-
`${
|
|
35035
|
+
`${TAG58} op=destinations account=${accountId.slice(0, 8)} count=${destinations.length} named=${named} unnamed=${destinations.length - named} nameScope=${nameScope}` + (houseAccountId === null ? " outcome=house-unresolved" : "") + (namesUnresolved === null ? "" : ` outcome=names-unresolved reason="${namesUnresolved}"`)
|
|
34825
35036
|
);
|
|
34826
35037
|
return c.json({ destinations });
|
|
34827
35038
|
});
|
|
@@ -34830,7 +35041,7 @@ var dispatch_destinations_default = app67;
|
|
|
34830
35041
|
// server/routes/admin/activity.ts
|
|
34831
35042
|
import { readdirSync as readdirSync30 } from "fs";
|
|
34832
35043
|
var app68 = new Hono();
|
|
34833
|
-
var
|
|
35044
|
+
var TAG59 = "[activity]";
|
|
34834
35045
|
function resolveHouseAccountId2(accounts) {
|
|
34835
35046
|
const houses = accounts.filter((a) => a.config.role === "house");
|
|
34836
35047
|
if (houses.length === 1) return { accountId: houses[0].accountId, reason: "house" };
|
|
@@ -34859,19 +35070,19 @@ app68.get("/", requireAdminSession, async (c) => {
|
|
|
34859
35070
|
const house = resolveHouseAccountId2(valid);
|
|
34860
35071
|
const isHouse = caller2 !== null && house.accountId !== null && caller2 === house.accountId;
|
|
34861
35072
|
console.log(
|
|
34862
|
-
`${
|
|
35073
|
+
`${TAG59} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
|
|
34863
35074
|
);
|
|
34864
35075
|
if (!isHouse) {
|
|
34865
35076
|
const reason = house.accountId === null ? house.reason : "not-house";
|
|
34866
35077
|
console.error(
|
|
34867
|
-
`${
|
|
35078
|
+
`${TAG59} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
|
|
34868
35079
|
);
|
|
34869
35080
|
return c.json({ error: "house-only" }, 403);
|
|
34870
35081
|
}
|
|
34871
|
-
console.log(`${
|
|
35082
|
+
console.log(`${TAG59} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
|
|
34872
35083
|
const onDisk = countAccountDirsOnDisk();
|
|
34873
35084
|
console.log(
|
|
34874
|
-
`${
|
|
35085
|
+
`${TAG59} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
|
|
34875
35086
|
);
|
|
34876
35087
|
const start = Date.now();
|
|
34877
35088
|
let res;
|
|
@@ -34887,17 +35098,17 @@ app68.get("/", requireAdminSession, async (c) => {
|
|
|
34887
35098
|
});
|
|
34888
35099
|
} catch (err) {
|
|
34889
35100
|
console.error(
|
|
34890
|
-
`${
|
|
35101
|
+
`${TAG59} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
|
|
34891
35102
|
);
|
|
34892
35103
|
return c.json({ error: "manager-unreachable" }, 502);
|
|
34893
35104
|
}
|
|
34894
35105
|
if (res.status !== 200) {
|
|
34895
|
-
console.error(`${
|
|
35106
|
+
console.error(`${TAG59} op=manager-fail req=${req} reason=status status=${res.status}`);
|
|
34896
35107
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
34897
35108
|
}
|
|
34898
35109
|
const body = await res.json().catch(() => null);
|
|
34899
35110
|
if (!body || !Array.isArray(body.rows)) {
|
|
34900
|
-
console.error(`${
|
|
35111
|
+
console.error(`${TAG59} op=manager-fail req=${req} reason=bad-json`);
|
|
34901
35112
|
return c.json({ error: "manager-bad-json" }, 502);
|
|
34902
35113
|
}
|
|
34903
35114
|
const rows = body.rows;
|
|
@@ -34908,10 +35119,10 @@ app68.get("/", requireAdminSession, async (c) => {
|
|
|
34908
35119
|
const ageNull = rows.filter((r) => r.ageMs === null).length;
|
|
34909
35120
|
const sidecarNull = rows.filter((r) => r.sidecarMissing).length;
|
|
34910
35121
|
console.log(
|
|
34911
|
-
`${
|
|
35122
|
+
`${TAG59} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
|
|
34912
35123
|
);
|
|
34913
35124
|
console.log(
|
|
34914
|
-
`${
|
|
35125
|
+
`${TAG59} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
|
|
34915
35126
|
);
|
|
34916
35127
|
const names = {};
|
|
34917
35128
|
await Promise.all(
|
|
@@ -34930,7 +35141,7 @@ app68.get("/", requireAdminSession, async (c) => {
|
|
|
34930
35141
|
return acc;
|
|
34931
35142
|
}, {});
|
|
34932
35143
|
console.log(
|
|
34933
|
-
`${
|
|
35144
|
+
`${TAG59} op=loops req=${req} armed=${armed2} rendered=${loopRows.length} procPct=${cpu.processPct?.toFixed(1) ?? "null"} attributedPct=${cpu.attributedPct?.toFixed(1) ?? "null"} ` + Object.entries(byState).map(([s, n]) => `${s}=${n}`).join(" ")
|
|
34934
35145
|
);
|
|
34935
35146
|
return c.json({
|
|
34936
35147
|
rows,
|
|
@@ -35021,7 +35232,7 @@ app69.route("/activity", activity_default);
|
|
|
35021
35232
|
var admin_default = app69;
|
|
35022
35233
|
|
|
35023
35234
|
// server/routes/access/verify-token.ts
|
|
35024
|
-
var
|
|
35235
|
+
var TAG60 = "[access-verify]";
|
|
35025
35236
|
var MINT_TAG = "[access-session-mint]";
|
|
35026
35237
|
var COOKIE_NAME = "__access_session";
|
|
35027
35238
|
var app70 = new Hono();
|
|
@@ -35040,39 +35251,39 @@ app70.post("/", async (c) => {
|
|
|
35040
35251
|
}
|
|
35041
35252
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
35042
35253
|
if (rateMsg) {
|
|
35043
|
-
console.error(`${
|
|
35254
|
+
console.error(`${TAG60} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
35044
35255
|
return c.json({ error: rateMsg }, 429);
|
|
35045
35256
|
}
|
|
35046
35257
|
const grant = await findGrantByMagicToken(token);
|
|
35047
35258
|
if (!grant) {
|
|
35048
35259
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
35049
|
-
console.error(`${
|
|
35260
|
+
console.error(`${TAG60} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
35050
35261
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
35051
35262
|
}
|
|
35052
35263
|
if (grant.agentSlug !== agentSlug) {
|
|
35053
35264
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
35054
35265
|
console.error(
|
|
35055
|
-
`${
|
|
35266
|
+
`${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
35056
35267
|
);
|
|
35057
35268
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
35058
35269
|
}
|
|
35059
35270
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
35060
35271
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
35061
35272
|
console.error(
|
|
35062
|
-
`${
|
|
35273
|
+
`${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
35063
35274
|
);
|
|
35064
35275
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
35065
35276
|
}
|
|
35066
35277
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
35067
35278
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
35068
35279
|
console.error(
|
|
35069
|
-
`${
|
|
35280
|
+
`${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
35070
35281
|
);
|
|
35071
35282
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
35072
35283
|
}
|
|
35073
35284
|
if (!grant.sliceToken) {
|
|
35074
35285
|
console.error(
|
|
35075
|
-
`${
|
|
35286
|
+
`${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
35076
35287
|
);
|
|
35077
35288
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
35078
35289
|
}
|
|
@@ -35088,12 +35299,12 @@ app70.post("/", async (c) => {
|
|
|
35088
35299
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
35089
35300
|
} catch (err) {
|
|
35090
35301
|
console.error(
|
|
35091
|
-
`${
|
|
35302
|
+
`${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
35092
35303
|
);
|
|
35093
35304
|
return c.json({ error: "verification-failed" }, 500);
|
|
35094
35305
|
}
|
|
35095
35306
|
clearAccessRateLimit(ip, agentSlug);
|
|
35096
|
-
console.log(`${
|
|
35307
|
+
console.log(`${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
35097
35308
|
console.log(
|
|
35098
35309
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
35099
35310
|
);
|
|
@@ -35169,7 +35380,7 @@ async function sendMagicLinkEmail(payload) {
|
|
|
35169
35380
|
}
|
|
35170
35381
|
|
|
35171
35382
|
// server/routes/access/request-magic-link.ts
|
|
35172
|
-
var
|
|
35383
|
+
var TAG61 = "[access-request-link]";
|
|
35173
35384
|
var app71 = new Hono();
|
|
35174
35385
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
35175
35386
|
app71.post("/", async (c) => {
|
|
@@ -35186,18 +35397,18 @@ app71.post("/", async (c) => {
|
|
|
35186
35397
|
}
|
|
35187
35398
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
35188
35399
|
if (rateMsg) {
|
|
35189
|
-
console.error(`${
|
|
35400
|
+
console.error(`${TAG61} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
35190
35401
|
return c.json({ error: rateMsg }, 429);
|
|
35191
35402
|
}
|
|
35192
35403
|
recordRequestLinkAttempt(contactValue);
|
|
35193
35404
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
35194
35405
|
if (!accountId) {
|
|
35195
|
-
console.error(`${
|
|
35406
|
+
console.error(`${TAG61} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
35196
35407
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
35197
35408
|
}
|
|
35198
35409
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
35199
35410
|
if (!grant) {
|
|
35200
|
-
console.log(`${
|
|
35411
|
+
console.log(`${TAG61} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
35201
35412
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
35202
35413
|
}
|
|
35203
35414
|
let token;
|
|
@@ -35205,7 +35416,7 @@ app71.post("/", async (c) => {
|
|
|
35205
35416
|
token = await generateNewMagicToken(grant.grantId);
|
|
35206
35417
|
} catch (err) {
|
|
35207
35418
|
console.error(
|
|
35208
|
-
`${
|
|
35419
|
+
`${TAG61} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
35209
35420
|
);
|
|
35210
35421
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
35211
35422
|
}
|
|
@@ -35237,12 +35448,12 @@ app71.post("/", async (c) => {
|
|
|
35237
35448
|
});
|
|
35238
35449
|
if (!sendResult.ok) {
|
|
35239
35450
|
console.error(
|
|
35240
|
-
`${
|
|
35451
|
+
`${TAG61} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
35241
35452
|
);
|
|
35242
35453
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
35243
35454
|
}
|
|
35244
35455
|
console.log(
|
|
35245
|
-
`${
|
|
35456
|
+
`${TAG61} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
35246
35457
|
);
|
|
35247
35458
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
35248
35459
|
});
|
|
@@ -36252,7 +36463,7 @@ import { stat as stat8, readFile as readFile12, realpath } from "fs/promises";
|
|
|
36252
36463
|
import { join as join62, resolve as resolve47, sep as sep11 } from "path";
|
|
36253
36464
|
import { Readable as Readable3 } from "stream";
|
|
36254
36465
|
var app79 = new Hono();
|
|
36255
|
-
var
|
|
36466
|
+
var TAG62 = "[portal-fetch]";
|
|
36256
36467
|
async function verifySignature(secret, accountId, relPath, expiresAtMs, signature, nowMs) {
|
|
36257
36468
|
if (!secret || !signature) return false;
|
|
36258
36469
|
if (!Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs) return false;
|
|
@@ -36307,14 +36518,14 @@ async function readAccountSecret(accountId) {
|
|
|
36307
36518
|
try {
|
|
36308
36519
|
text = await readFile12(path, "utf8");
|
|
36309
36520
|
} catch {
|
|
36310
|
-
console.error(`${
|
|
36521
|
+
console.error(`${TAG62} op=no-secret account="${accountId}" path="${path}"`);
|
|
36311
36522
|
return "";
|
|
36312
36523
|
}
|
|
36313
36524
|
for (const line of text.split("\n")) {
|
|
36314
36525
|
const m = line.match(/^PORTAL_FETCH_SECRET=(.*)$/);
|
|
36315
36526
|
if (m) return m[1].trim();
|
|
36316
36527
|
}
|
|
36317
|
-
console.error(`${
|
|
36528
|
+
console.error(`${TAG62} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
|
|
36318
36529
|
return "";
|
|
36319
36530
|
}
|
|
36320
36531
|
function isValidAccountId2(value) {
|
|
@@ -36374,16 +36585,16 @@ async function handle(c, headOnly) {
|
|
|
36374
36585
|
const sig = c.req.query("sig") ?? "";
|
|
36375
36586
|
const owner = c.req.query("owner") ?? "";
|
|
36376
36587
|
console.log(
|
|
36377
|
-
`${
|
|
36588
|
+
`${TAG62} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
|
|
36378
36589
|
);
|
|
36379
36590
|
if (!isValidAccountId2(accountId)) {
|
|
36380
|
-
console.error(`${
|
|
36591
|
+
console.error(`${TAG62} op=denied account=${q(accountId)} reason=account-id`);
|
|
36381
36592
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
36382
36593
|
}
|
|
36383
36594
|
const secret = await readAccountSecret(accountId);
|
|
36384
36595
|
const verified = owner ? await verifyOwnUploadSignature(secret, accountId, owner, relPath, exp, sig, Date.now()) : await verifySignature(secret, accountId, relPath, exp, sig, Date.now());
|
|
36385
36596
|
if (!verified) {
|
|
36386
|
-
console.error(`${
|
|
36597
|
+
console.error(`${TAG62} op=denied account=${q(accountId)} reason=secret`);
|
|
36387
36598
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
36388
36599
|
}
|
|
36389
36600
|
const target = await resolveFetchTarget(
|
|
@@ -36393,14 +36604,14 @@ async function handle(c, headOnly) {
|
|
|
36393
36604
|
);
|
|
36394
36605
|
if (!target.ok) {
|
|
36395
36606
|
const op = target.reason === "enoent" ? "miss" : "denied";
|
|
36396
|
-
console.error(`${
|
|
36607
|
+
console.error(`${TAG62} op=${op} account=${accountId} reason=${target.reason}`);
|
|
36397
36608
|
return c.json({ ok: false, error: "not found" }, 404);
|
|
36398
36609
|
}
|
|
36399
36610
|
if (headOnly) {
|
|
36400
|
-
console.log(`${
|
|
36611
|
+
console.log(`${TAG62} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
|
|
36401
36612
|
return c.body(null, 200);
|
|
36402
36613
|
}
|
|
36403
|
-
console.log(`${
|
|
36614
|
+
console.log(`${TAG62} op=served account=${accountId} bytes=${target.sizeBytes}`);
|
|
36404
36615
|
return new Response(Readable3.toWeb(createReadStream3(target.absolute)), {
|
|
36405
36616
|
status: 200,
|
|
36406
36617
|
headers: {
|
|
@@ -36419,7 +36630,7 @@ app79.on("HEAD", "/fetch", (c) => handle(c, true));
|
|
|
36419
36630
|
var portal_fetch_default = app79;
|
|
36420
36631
|
|
|
36421
36632
|
// app/lib/timeentry-census.ts
|
|
36422
|
-
var
|
|
36633
|
+
var TAG63 = "[timeentry-census]";
|
|
36423
36634
|
function reconcileTimeEntries(rows, now, horizonMs) {
|
|
36424
36635
|
const openEntries = rows.openEntries.length;
|
|
36425
36636
|
let oldestOpenAgeMs = 0;
|
|
@@ -36459,12 +36670,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
|
|
|
36459
36670
|
sumAdjustments: toNum(r.get("sumAdjustments"))
|
|
36460
36671
|
}));
|
|
36461
36672
|
const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
|
|
36462
|
-
const line = `${
|
|
36673
|
+
const line = `${TAG63} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
|
|
36463
36674
|
if (finding.alarm) console.error(`${line} alarm=true`);
|
|
36464
36675
|
else console.log(line);
|
|
36465
36676
|
return finding;
|
|
36466
36677
|
} catch (err) {
|
|
36467
|
-
console.error(`${
|
|
36678
|
+
console.error(`${TAG63} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
36468
36679
|
return null;
|
|
36469
36680
|
}
|
|
36470
36681
|
}
|
|
@@ -36478,13 +36689,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
36478
36689
|
try {
|
|
36479
36690
|
session = openSession();
|
|
36480
36691
|
} catch (err) {
|
|
36481
|
-
console.error(`${
|
|
36692
|
+
console.error(`${TAG63} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
36482
36693
|
return;
|
|
36483
36694
|
}
|
|
36484
36695
|
try {
|
|
36485
36696
|
await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
|
|
36486
36697
|
} catch (err) {
|
|
36487
|
-
console.error(`${
|
|
36698
|
+
console.error(`${TAG63} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
36488
36699
|
} finally {
|
|
36489
36700
|
try {
|
|
36490
36701
|
await session.close();
|
|
@@ -36545,7 +36756,7 @@ function formatCensusLine(f) {
|
|
|
36545
36756
|
}
|
|
36546
36757
|
|
|
36547
36758
|
// app/lib/ledger-census.ts
|
|
36548
|
-
var
|
|
36759
|
+
var TAG64 = "[ledger-census]";
|
|
36549
36760
|
var DAY_MS = 864e5;
|
|
36550
36761
|
function countWriteRejects24h(logDir, now) {
|
|
36551
36762
|
let entries2;
|
|
@@ -36621,7 +36832,7 @@ async function runLedgerCensusOnce(session, now) {
|
|
|
36621
36832
|
else console.log(line);
|
|
36622
36833
|
return finding;
|
|
36623
36834
|
} catch (err) {
|
|
36624
|
-
console.error(`${
|
|
36835
|
+
console.error(`${TAG64} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
36625
36836
|
return null;
|
|
36626
36837
|
}
|
|
36627
36838
|
}
|
|
@@ -36634,7 +36845,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
36634
36845
|
session = openSession();
|
|
36635
36846
|
} catch (err) {
|
|
36636
36847
|
console.error(
|
|
36637
|
-
`${
|
|
36848
|
+
`${TAG64} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
36638
36849
|
);
|
|
36639
36850
|
return;
|
|
36640
36851
|
}
|
|
@@ -36642,7 +36853,7 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
36642
36853
|
await runLedgerCensusOnce(session, Date.now());
|
|
36643
36854
|
} catch (err) {
|
|
36644
36855
|
console.error(
|
|
36645
|
-
`${
|
|
36856
|
+
`${TAG64} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
|
|
36646
36857
|
);
|
|
36647
36858
|
} finally {
|
|
36648
36859
|
try {
|
|
@@ -36987,7 +37198,7 @@ function startDispatchTgCensus(getSession3, intervalMs = FIFTEEN_MIN_MS3) {
|
|
|
36987
37198
|
}
|
|
36988
37199
|
|
|
36989
37200
|
// app/lib/conversation-audit.ts
|
|
36990
|
-
var
|
|
37201
|
+
var TAG65 = "[conversation-audit]";
|
|
36991
37202
|
async function runConversationAudit() {
|
|
36992
37203
|
const session = getSession();
|
|
36993
37204
|
try {
|
|
@@ -37024,12 +37235,12 @@ async function runConversationAudit() {
|
|
|
37024
37235
|
multiAnchored: Number(multiRec?.get("multiAnchored") ?? 0)
|
|
37025
37236
|
};
|
|
37026
37237
|
console.error(
|
|
37027
|
-
`${
|
|
37238
|
+
`${TAG65} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
|
|
37028
37239
|
);
|
|
37029
37240
|
return result;
|
|
37030
37241
|
} catch (err) {
|
|
37031
37242
|
const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
|
|
37032
|
-
console.error(`${
|
|
37243
|
+
console.error(`${TAG65} op=failed reason=${reason}`);
|
|
37033
37244
|
return null;
|
|
37034
37245
|
} finally {
|
|
37035
37246
|
await session.close();
|
|
@@ -37037,7 +37248,7 @@ async function runConversationAudit() {
|
|
|
37037
37248
|
}
|
|
37038
37249
|
|
|
37039
37250
|
// app/lib/graph-health.ts
|
|
37040
|
-
var
|
|
37251
|
+
var import_dist16 = __toESM(require_dist10(), 1);
|
|
37041
37252
|
var HOUR_MS2 = 60 * 60 * 1e3;
|
|
37042
37253
|
function renderLabelTop(rows) {
|
|
37043
37254
|
return rows.map((b) => {
|
|
@@ -37082,7 +37293,7 @@ async function runGraphHealthTick() {
|
|
|
37082
37293
|
console.error(
|
|
37083
37294
|
`[graph-health] userprofile-multi accounts=${upAccounts} top=${upTop.length > 0 ? upTop.join(",") : "none"}`
|
|
37084
37295
|
);
|
|
37085
|
-
const indexed = [...
|
|
37296
|
+
const indexed = [...import_dist16.VECTOR_INDEXED_LABELS];
|
|
37086
37297
|
const embCount = await session.run(
|
|
37087
37298
|
`MATCH (n) WHERE n.embedding IS NULL AND any(l IN labels(n) WHERE l IN $indexed)
|
|
37088
37299
|
RETURN count(n) AS total`,
|
|
@@ -37156,8 +37367,8 @@ function startGraphHealthTimer() {
|
|
|
37156
37367
|
// app/lib/shared-folder-census.ts
|
|
37157
37368
|
import { existsSync as existsSync54, statSync as statSync29, readdirSync as readdirSync32 } from "fs";
|
|
37158
37369
|
import { join as join65 } from "path";
|
|
37159
|
-
var
|
|
37160
|
-
var
|
|
37370
|
+
var import_dist17 = __toESM(require_dist(), 1);
|
|
37371
|
+
var TAG66 = "[shared-census]";
|
|
37161
37372
|
var WIRED_SURFACES = 3;
|
|
37162
37373
|
function countFiles(dir) {
|
|
37163
37374
|
let n = 0;
|
|
@@ -37174,7 +37385,7 @@ function countFiles(dir) {
|
|
|
37174
37385
|
return n;
|
|
37175
37386
|
}
|
|
37176
37387
|
function runSharedFolderCensus(dataRoot = DATA_ROOT) {
|
|
37177
|
-
const root = (0,
|
|
37388
|
+
const root = (0, import_dist17.sharedRoot)(dataRoot);
|
|
37178
37389
|
const exists = existsSync54(root);
|
|
37179
37390
|
let isDir = false;
|
|
37180
37391
|
if (exists) {
|
|
@@ -37185,8 +37396,8 @@ function runSharedFolderCensus(dataRoot = DATA_ROOT) {
|
|
|
37185
37396
|
}
|
|
37186
37397
|
}
|
|
37187
37398
|
const files = isDir ? countFiles(root) : 0;
|
|
37188
|
-
console.error(`${
|
|
37189
|
-
console.error(`${
|
|
37399
|
+
console.error(`${TAG66} op=root exists=${exists} isDir=${isDir} files=${files}`);
|
|
37400
|
+
console.error(`${TAG66} op=wiring surfaces=${WIRED_SURFACES}/3`);
|
|
37190
37401
|
return `shared root ${exists ? "present" : "ABSENT"}, ${files} file(s)`;
|
|
37191
37402
|
}
|
|
37192
37403
|
function startSharedFolderCensus() {
|
|
@@ -37202,7 +37413,7 @@ function startSharedFolderCensus() {
|
|
|
37202
37413
|
import { readdirSync as readdirSync33, readFileSync as readFileSync57 } from "fs";
|
|
37203
37414
|
import { homedir as homedir4 } from "os";
|
|
37204
37415
|
import { join as join66 } from "path";
|
|
37205
|
-
var
|
|
37416
|
+
var TAG67 = "[claude-auth]";
|
|
37206
37417
|
function refreshTokenLength(raw) {
|
|
37207
37418
|
let data;
|
|
37208
37419
|
try {
|
|
@@ -37246,7 +37457,7 @@ function runCredRefreshCensus(home = homedir4()) {
|
|
|
37246
37457
|
const blank = rows.filter(isBlank).length;
|
|
37247
37458
|
const detail = rows.map((r) => `${r.brand}:${r.refreshTokenLen === null ? "unreadable" : r.refreshTokenLen}`).join(",");
|
|
37248
37459
|
console.log(
|
|
37249
|
-
`${
|
|
37460
|
+
`${TAG67} op=cred-refresh-census result=${censusResult(rows)} brands=${rows.length} blank=${blank} detail=${detail}`
|
|
37250
37461
|
);
|
|
37251
37462
|
return `${rows.length} brand(s), ${blank} blank`;
|
|
37252
37463
|
}
|
|
@@ -39745,6 +39956,16 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
39745
39956
|
clearDeliveryFailure(key2) {
|
|
39746
39957
|
this.deliveryFailures.delete(key2);
|
|
39747
39958
|
}
|
|
39959
|
+
/** Task 2439 — mark a key undelivered from OUTSIDE the drain path. Every other
|
|
39960
|
+
* writer above fires because a message the hub already holds could not be
|
|
39961
|
+
* delivered. The send route's deferred continuation is the one case where no
|
|
39962
|
+
* message ever reached the hub: it dies before handleInbound runs, so nothing
|
|
39963
|
+
* is queued, nothing can go stale, and no drain can fail. Without this the
|
|
39964
|
+
* client's pending window (Task 2465 reads exactly this marker) never gets a
|
|
39965
|
+
* verdict and the composer stays disabled until the page is reloaded. */
|
|
39966
|
+
markDeliveryFailure(key2, messageId) {
|
|
39967
|
+
this.deliveryFailures.set(key2, { messageId, at: Date.now() });
|
|
39968
|
+
}
|
|
39748
39969
|
/** Task 2465 — record which session a conversation key's child is running.
|
|
39749
39970
|
* Public so the audit below can be driven directly in tests without standing
|
|
39750
39971
|
* up the channel-server HTTP surface; production writes come from runSpawn and
|
|
@@ -40437,14 +40658,14 @@ function makeFileDelivery(opts) {
|
|
|
40437
40658
|
}
|
|
40438
40659
|
|
|
40439
40660
|
// app/lib/webchat/file-delivery.ts
|
|
40440
|
-
var
|
|
40661
|
+
var TAG68 = "[webchat-adaptor]";
|
|
40441
40662
|
function platformRoot2() {
|
|
40442
40663
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
40443
40664
|
}
|
|
40444
40665
|
function makeWebchatSendFile(entry3) {
|
|
40445
40666
|
return async (filePath) => {
|
|
40446
40667
|
if (!entry3.accountId) {
|
|
40447
|
-
console.error(`${
|
|
40668
|
+
console.error(`${TAG68} file-delivery reject reason=no-account sender=${entry3.senderId}`);
|
|
40448
40669
|
return { ok: false, error: "no-account" };
|
|
40449
40670
|
}
|
|
40450
40671
|
const accountDir = resolve50(platformRoot2(), "..", "data/accounts", entry3.accountId);
|
|
@@ -40452,14 +40673,14 @@ function makeWebchatSendFile(entry3) {
|
|
|
40452
40673
|
const resolved = realpathSync9(filePath);
|
|
40453
40674
|
const accountResolved = realpathSync9(accountDir);
|
|
40454
40675
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
40455
|
-
console.error(`${
|
|
40676
|
+
console.error(`${TAG68} file-delivery reject reason=outside_account_directory sender=${entry3.senderId}`);
|
|
40456
40677
|
return { ok: false, error: "outside-account" };
|
|
40457
40678
|
}
|
|
40458
40679
|
return { ok: true };
|
|
40459
40680
|
} catch (err) {
|
|
40460
40681
|
const code = err.code;
|
|
40461
40682
|
console.error(
|
|
40462
|
-
`${
|
|
40683
|
+
`${TAG68} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry3.senderId}`
|
|
40463
40684
|
);
|
|
40464
40685
|
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
40465
40686
|
}
|
|
@@ -40468,7 +40689,7 @@ function makeWebchatSendFile(entry3) {
|
|
|
40468
40689
|
function makeWebchatFileDelivery(entry3) {
|
|
40469
40690
|
return makeFileDelivery({
|
|
40470
40691
|
entry: entry3,
|
|
40471
|
-
tag:
|
|
40692
|
+
tag: TAG68,
|
|
40472
40693
|
channel: "webchat",
|
|
40473
40694
|
sendFile: makeWebchatSendFile(entry3),
|
|
40474
40695
|
deferUntilVerdict: true
|
|
@@ -40547,7 +40768,7 @@ function buildPublicWebchatSpawnRequest(input) {
|
|
|
40547
40768
|
}
|
|
40548
40769
|
|
|
40549
40770
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
40550
|
-
var
|
|
40771
|
+
var TAG69 = "[whatsapp-adaptor]";
|
|
40551
40772
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
40552
40773
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
40553
40774
|
function platformRoot3() {
|
|
@@ -40565,7 +40786,7 @@ function makeWhatsAppSendFile(entry3, maxyAccountId) {
|
|
|
40565
40786
|
});
|
|
40566
40787
|
if (result.ok) return { ok: true };
|
|
40567
40788
|
console.error(
|
|
40568
|
-
`${
|
|
40789
|
+
`${TAG69} file-delivery reject reason=send-failed sender=${entry3.senderId} status=${result.status} message=${result.error}`
|
|
40569
40790
|
);
|
|
40570
40791
|
return { ok: false, error: result.error };
|
|
40571
40792
|
};
|
|
@@ -40573,7 +40794,7 @@ function makeWhatsAppSendFile(entry3, maxyAccountId) {
|
|
|
40573
40794
|
function makeWhatsAppFileDelivery(entry3, maxyAccountId) {
|
|
40574
40795
|
const shared = makeFileDelivery({
|
|
40575
40796
|
entry: entry3,
|
|
40576
|
-
tag:
|
|
40797
|
+
tag: TAG69,
|
|
40577
40798
|
channel: "whatsapp",
|
|
40578
40799
|
sendFile: makeWhatsAppSendFile(entry3, maxyAccountId)
|
|
40579
40800
|
});
|
|
@@ -40608,7 +40829,7 @@ function makeWhatsAppFileDelivery(entry3, maxyAccountId) {
|
|
|
40608
40829
|
if (!delivered) {
|
|
40609
40830
|
const fileField = call2.filePath !== void 0 ? ` file=${call2.filePath}` : "";
|
|
40610
40831
|
console.error(
|
|
40611
|
-
`${
|
|
40832
|
+
`${TAG69} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
40612
40833
|
);
|
|
40613
40834
|
}
|
|
40614
40835
|
}
|
|
@@ -40774,7 +40995,7 @@ function whatsappDoorLabel(doorId) {
|
|
|
40774
40995
|
}
|
|
40775
40996
|
|
|
40776
40997
|
// app/lib/channel-delivery/refusal-notice.ts
|
|
40777
|
-
var
|
|
40998
|
+
var TAG70 = "[channel-delivery]";
|
|
40778
40999
|
var notified = /* @__PURE__ */ new Set();
|
|
40779
41000
|
function refusalNoticeText(reason) {
|
|
40780
41001
|
return reason === "claude-auth-dead" ? "Your message arrived but no assistant could be started: the Claude sign-in on this install is not active. An operator has to sign in again; send this again once they have." : `Your message arrived but no assistant could be started (${reason}). Nothing was lost; try again shortly.`;
|
|
@@ -40783,19 +41004,19 @@ async function sendRefusalNotice(input) {
|
|
|
40783
41004
|
if (notified.has(input.doorId)) return;
|
|
40784
41005
|
const fields = `channel=${input.channel} sender=${input.sender} reason=${input.reason}`;
|
|
40785
41006
|
if (!input.send) {
|
|
40786
|
-
console.error(`${
|
|
41007
|
+
console.error(`${TAG70} op=refusal-notice-failed ${fields} error=no-target`);
|
|
40787
41008
|
return;
|
|
40788
41009
|
}
|
|
40789
41010
|
try {
|
|
40790
41011
|
await input.send(guardOutbound(input.sender, refusalNoticeText(input.reason)));
|
|
40791
41012
|
} catch (e) {
|
|
40792
41013
|
console.error(
|
|
40793
|
-
`${
|
|
41014
|
+
`${TAG70} op=refusal-notice-failed ${fields} error=${e instanceof Error ? e.message : String(e)}`
|
|
40794
41015
|
);
|
|
40795
41016
|
return;
|
|
40796
41017
|
}
|
|
40797
41018
|
notified.add(input.doorId);
|
|
40798
|
-
console.error(`${
|
|
41019
|
+
console.error(`${TAG70} op=refusal-notice ${fields} status=${input.status}`);
|
|
40799
41020
|
}
|
|
40800
41021
|
function clearRefusalNotice(doorId) {
|
|
40801
41022
|
notified.delete(doorId);
|
|
@@ -41455,10 +41676,10 @@ function buildTelegramSpawnRequest(input) {
|
|
|
41455
41676
|
}
|
|
41456
41677
|
|
|
41457
41678
|
// server/telegram-ensure-session.ts
|
|
41458
|
-
var
|
|
41679
|
+
var TAG71 = "[telegram-inbound]";
|
|
41459
41680
|
function reportReused(botId, channelKey, result) {
|
|
41460
41681
|
if (!result.reused) return;
|
|
41461
|
-
console.error(`${
|
|
41682
|
+
console.error(`${TAG71} op=spawn-reused botId=${botId} key=${channelKey} sessionId=${result.sessionId}`);
|
|
41462
41683
|
}
|
|
41463
41684
|
function buildTelegramEnsureSession(deps) {
|
|
41464
41685
|
return async (input) => {
|
|
@@ -41522,10 +41743,10 @@ function buildTelegramEnsureSession(deps) {
|
|
|
41522
41743
|
return;
|
|
41523
41744
|
}
|
|
41524
41745
|
console.error(
|
|
41525
|
-
`${
|
|
41746
|
+
`${TAG71} op=telegram-spawn-door botId=${input.botId} role=specialist door=rc specialist=${input.specialist}`
|
|
41526
41747
|
);
|
|
41527
41748
|
console.error(
|
|
41528
|
-
`${
|
|
41749
|
+
`${TAG71} op=spawn botId=${input.botId} sessionId=${req.sessionId} targetAccountId=${input.accountId} role=specialist specialist=${input.specialist}`
|
|
41529
41750
|
);
|
|
41530
41751
|
reportReused(input.botId, req.channelKey, result2);
|
|
41531
41752
|
noteSpawnOk2(input.botId);
|
|
@@ -41560,10 +41781,10 @@ function buildTelegramEnsureSession(deps) {
|
|
|
41560
41781
|
return;
|
|
41561
41782
|
}
|
|
41562
41783
|
console.error(
|
|
41563
|
-
`${
|
|
41784
|
+
`${TAG71} op=telegram-spawn-door botId=${input.botId} role=public door=rc agent=${input.agentSlug}`
|
|
41564
41785
|
);
|
|
41565
41786
|
console.error(
|
|
41566
|
-
`${
|
|
41787
|
+
`${TAG71} op=spawn botId=${input.botId} sessionId=${result2.sessionId} targetAccountId=${input.accountId} role=public`
|
|
41567
41788
|
);
|
|
41568
41789
|
reportReused(input.botId, req.channelKey, result2);
|
|
41569
41790
|
noteSpawnOk2(input.botId);
|
|
@@ -41587,7 +41808,7 @@ function buildTelegramEnsureSession(deps) {
|
|
|
41587
41808
|
return;
|
|
41588
41809
|
}
|
|
41589
41810
|
console.error(
|
|
41590
|
-
`${
|
|
41811
|
+
`${TAG71} op=spawn botId=${input.botId} sessionId=${req.sessionId} targetAccountId=${input.accountId} role=admin`
|
|
41591
41812
|
);
|
|
41592
41813
|
reportReused(input.botId, req.channelKey, result);
|
|
41593
41814
|
noteSpawnOk2(input.botId);
|
|
@@ -41606,7 +41827,7 @@ function buildTelegramEnsureSession(deps) {
|
|
|
41606
41827
|
import { realpathSync as realpathSync10 } from "fs";
|
|
41607
41828
|
import { readFile as readFile15, stat as stat10 } from "fs/promises";
|
|
41608
41829
|
import { resolve as resolve51, basename as basename18 } from "path";
|
|
41609
|
-
var
|
|
41830
|
+
var TAG72 = "[telegram:outbound]";
|
|
41610
41831
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
41611
41832
|
async function sendTelegramDocument(input) {
|
|
41612
41833
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
@@ -41623,10 +41844,10 @@ async function sendTelegramDocument(input) {
|
|
|
41623
41844
|
} catch (err) {
|
|
41624
41845
|
const code = err.code;
|
|
41625
41846
|
if (code === "ENOENT") {
|
|
41626
|
-
console.error(`${
|
|
41847
|
+
console.error(`${TAG72} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
|
|
41627
41848
|
return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
|
|
41628
41849
|
}
|
|
41629
|
-
console.error(`${
|
|
41850
|
+
console.error(`${TAG72} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
41630
41851
|
return { ok: false, status: 500, error: String(err) };
|
|
41631
41852
|
}
|
|
41632
41853
|
let resolvedPath;
|
|
@@ -41635,14 +41856,14 @@ async function sendTelegramDocument(input) {
|
|
|
41635
41856
|
} catch (err) {
|
|
41636
41857
|
const code = err.code;
|
|
41637
41858
|
if (code === "ENOENT") {
|
|
41638
|
-
console.error(`${
|
|
41859
|
+
console.error(`${TAG72} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
|
|
41639
41860
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
41640
41861
|
}
|
|
41641
|
-
console.error(`${
|
|
41862
|
+
console.error(`${TAG72} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
|
|
41642
41863
|
return { ok: false, status: 500, error: String(err) };
|
|
41643
41864
|
}
|
|
41644
41865
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
41645
|
-
console.error(`${
|
|
41866
|
+
console.error(`${TAG72} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
41646
41867
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
41647
41868
|
}
|
|
41648
41869
|
const fileStat = await stat10(resolvedPath);
|
|
@@ -41675,24 +41896,24 @@ async function sendTelegramDocument(input) {
|
|
|
41675
41896
|
error = e instanceof Error ? e.message : String(e);
|
|
41676
41897
|
}
|
|
41677
41898
|
console.error(
|
|
41678
|
-
`${
|
|
41899
|
+
`${TAG72} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok2}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
41679
41900
|
);
|
|
41680
41901
|
return ok2 ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
41681
41902
|
}
|
|
41682
41903
|
|
|
41683
41904
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
41684
|
-
var
|
|
41905
|
+
var TAG73 = "[telegram:outbound]";
|
|
41685
41906
|
function platformRoot4() {
|
|
41686
41907
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
41687
41908
|
}
|
|
41688
41909
|
function makeTelegramSendFile(entry3, botToken) {
|
|
41689
41910
|
return async (filePath, caption) => {
|
|
41690
41911
|
if (!botToken) {
|
|
41691
|
-
console.error(`${
|
|
41912
|
+
console.error(`${TAG73} file-delivery reject reason=no-bot-token sender=${entry3.senderId} role=${entry3.role}`);
|
|
41692
41913
|
return { ok: false, error: "no-bot-token" };
|
|
41693
41914
|
}
|
|
41694
41915
|
if (entry3.replyTarget == null) {
|
|
41695
|
-
console.error(`${
|
|
41916
|
+
console.error(`${TAG73} file-delivery reject reason=no-reply-target sender=${entry3.senderId} role=${entry3.role}`);
|
|
41696
41917
|
return { ok: false, error: "no-reply-target" };
|
|
41697
41918
|
}
|
|
41698
41919
|
const result = await sendTelegramDocument({
|
|
@@ -41709,7 +41930,7 @@ function makeTelegramSendFile(entry3, botToken) {
|
|
|
41709
41930
|
function makeTelegramFileDelivery(entry3, botToken) {
|
|
41710
41931
|
return makeFileDelivery({
|
|
41711
41932
|
entry: entry3,
|
|
41712
|
-
tag:
|
|
41933
|
+
tag: TAG73,
|
|
41713
41934
|
channel: "telegram",
|
|
41714
41935
|
sendFile: makeTelegramSendFile(entry3, botToken)
|
|
41715
41936
|
});
|
|
@@ -42120,7 +42341,7 @@ function adminFanTargets(p) {
|
|
|
42120
42341
|
|
|
42121
42342
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
42122
42343
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
42123
|
-
var
|
|
42344
|
+
var TAG74 = "[public-session-review]";
|
|
42124
42345
|
var CONSUMED_CAP = 500;
|
|
42125
42346
|
var consumed = /* @__PURE__ */ new Set();
|
|
42126
42347
|
function consumeOnce(sessionId) {
|
|
@@ -42147,7 +42368,7 @@ async function fetchJsonl(sessionId) {
|
|
|
42147
42368
|
return await res.text();
|
|
42148
42369
|
} catch (err) {
|
|
42149
42370
|
console.error(
|
|
42150
|
-
`${
|
|
42371
|
+
`${TAG74} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
42151
42372
|
);
|
|
42152
42373
|
return null;
|
|
42153
42374
|
}
|
|
@@ -42171,7 +42392,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
42171
42392
|
const res = await fetch(url);
|
|
42172
42393
|
if (!res.ok) {
|
|
42173
42394
|
console.error(
|
|
42174
|
-
`${
|
|
42395
|
+
`${TAG74} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
42175
42396
|
);
|
|
42176
42397
|
return [];
|
|
42177
42398
|
}
|
|
@@ -42179,7 +42400,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
42179
42400
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
42180
42401
|
} catch (err) {
|
|
42181
42402
|
console.error(
|
|
42182
|
-
`${
|
|
42403
|
+
`${TAG74} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
42183
42404
|
);
|
|
42184
42405
|
return [];
|
|
42185
42406
|
}
|
|
@@ -42208,7 +42429,7 @@ function composeInitialMessage(input) {
|
|
|
42208
42429
|
}
|
|
42209
42430
|
async function dispatchReviewer(input, initialMessage) {
|
|
42210
42431
|
const sessionId = randomUUID14();
|
|
42211
|
-
console.log(`${
|
|
42432
|
+
console.log(`${TAG74} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
42212
42433
|
const spawned = await managerRcSpawn({
|
|
42213
42434
|
sessionId,
|
|
42214
42435
|
initialMessage,
|
|
@@ -42232,21 +42453,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
42232
42453
|
const dispatchedAt = Date.now();
|
|
42233
42454
|
if (consumed.has(input.sessionId)) {
|
|
42234
42455
|
console.log(
|
|
42235
|
-
`${
|
|
42456
|
+
`${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
42236
42457
|
);
|
|
42237
42458
|
return;
|
|
42238
42459
|
}
|
|
42239
42460
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
42240
42461
|
if (!jsonl) {
|
|
42241
42462
|
console.log(
|
|
42242
|
-
`${
|
|
42463
|
+
`${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
42243
42464
|
);
|
|
42244
42465
|
return;
|
|
42245
42466
|
}
|
|
42246
42467
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
42247
42468
|
if (operatorTurns === 0) {
|
|
42248
42469
|
console.log(
|
|
42249
|
-
`${
|
|
42470
|
+
`${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
42250
42471
|
);
|
|
42251
42472
|
return;
|
|
42252
42473
|
}
|
|
@@ -42260,28 +42481,28 @@ async function firePublicSessionEndReview(input) {
|
|
|
42260
42481
|
});
|
|
42261
42482
|
if (!consumeOnce(input.sessionId)) {
|
|
42262
42483
|
console.log(
|
|
42263
|
-
`${
|
|
42484
|
+
`${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
42264
42485
|
);
|
|
42265
42486
|
return;
|
|
42266
42487
|
}
|
|
42267
42488
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
42268
42489
|
if (!dispatched.ok) {
|
|
42269
42490
|
console.error(
|
|
42270
|
-
`${
|
|
42491
|
+
`${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
42271
42492
|
);
|
|
42272
42493
|
return;
|
|
42273
42494
|
}
|
|
42274
42495
|
console.log(
|
|
42275
|
-
`${
|
|
42496
|
+
`${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
42276
42497
|
);
|
|
42277
42498
|
}
|
|
42278
42499
|
|
|
42279
42500
|
// app/lib/whatsapp/inbound/resolve-client-graph-owner.ts
|
|
42280
|
-
var
|
|
42501
|
+
var import_dist18 = __toESM(require_dist3(), 1);
|
|
42281
42502
|
async function resolveClientOwnerUserId(accountId, deps = {}) {
|
|
42282
42503
|
const listAccounts = deps.listAccounts ?? listValidAccounts;
|
|
42283
42504
|
const getSession3 = deps.getSession ?? getSession;
|
|
42284
|
-
const resolveOwner2 = deps.resolveOwner ??
|
|
42505
|
+
const resolveOwner2 = deps.resolveOwner ?? import_dist18.resolveOwnerUserId;
|
|
42285
42506
|
const role = listAccounts().find((a) => a.accountId === accountId)?.config.role;
|
|
42286
42507
|
if (role !== "client") return null;
|
|
42287
42508
|
const session = getSession3();
|
|
@@ -42541,10 +42762,10 @@ function* walkTelegramSidecars() {
|
|
|
42541
42762
|
}
|
|
42542
42763
|
|
|
42543
42764
|
// server/telegram-group-census.ts
|
|
42544
|
-
var
|
|
42765
|
+
var TAG75 = "[telegram-audit]";
|
|
42545
42766
|
var PRESENT_STATUSES = /* @__PURE__ */ new Set(["member", "administrator", "creator"]);
|
|
42546
42767
|
function buildGroupCensusLine(c) {
|
|
42547
|
-
return `${
|
|
42768
|
+
return `${TAG75} op=group-census bots=${c.bots} groups=${c.groups} present=${c.present} absent=${c.absent} privacyOff=${c.privacyOff}`;
|
|
42548
42769
|
}
|
|
42549
42770
|
async function runTelegramGroupCensus(accounts, deps) {
|
|
42550
42771
|
const counts = { bots: 0, groups: 0, present: 0, absent: 0, privacyOff: 0 };
|
|
@@ -42575,10 +42796,10 @@ async function runTelegramGroupCensus(accounts, deps) {
|
|
|
42575
42796
|
}
|
|
42576
42797
|
|
|
42577
42798
|
// server/telegram-channel-census.ts
|
|
42578
|
-
var
|
|
42799
|
+
var TAG76 = "[telegram-audit]";
|
|
42579
42800
|
var ADMIN_STATUSES = /* @__PURE__ */ new Set(["administrator", "creator"]);
|
|
42580
42801
|
function buildChannelCensusLine(c) {
|
|
42581
|
-
return `${
|
|
42802
|
+
return `${TAG76} op=channel-census bots=${c.bots} channels=${c.channels} admin=${c.admin} notAdmin=${c.notAdmin} noPostRight=${c.noPostRight}`;
|
|
42582
42803
|
}
|
|
42583
42804
|
async function runTelegramChannelCensus(accounts, deps) {
|
|
42584
42805
|
const counts = { bots: 0, channels: 0, admin: 0, notAdmin: 0, noPostRight: 0 };
|
|
@@ -42609,6 +42830,41 @@ async function runTelegramChannelCensus(accounts, deps) {
|
|
|
42609
42830
|
return [buildChannelCensusLine(counts)];
|
|
42610
42831
|
}
|
|
42611
42832
|
|
|
42833
|
+
// server/telegram-identity-census.ts
|
|
42834
|
+
var TAG77 = "[telegram-audit]";
|
|
42835
|
+
function buildIdentityCensusLine(c) {
|
|
42836
|
+
return `${TAG77} op=identity-census bots=${c.bots} ids=${c.ids} bound=${c.bound} unbound=${c.unbound} ambiguous=${c.ambiguous}`;
|
|
42837
|
+
}
|
|
42838
|
+
async function runTelegramIdentityCensus(accounts, deps) {
|
|
42839
|
+
const counts = { bots: 0, ids: 0, bound: 0, unbound: 0, ambiguous: 0 };
|
|
42840
|
+
for (const account of accounts) {
|
|
42841
|
+
const adminEntries = listBotEntries(account.telegram).filter((e) => e.role === "admin");
|
|
42842
|
+
if (adminEntries.length === 0) continue;
|
|
42843
|
+
counts.bots += adminEntries.length;
|
|
42844
|
+
const ids = adminEntries.flatMap((e) => e.adminUsers ?? []);
|
|
42845
|
+
counts.ids += ids.length;
|
|
42846
|
+
if (ids.length === 0) continue;
|
|
42847
|
+
let found;
|
|
42848
|
+
try {
|
|
42849
|
+
found = await deps.boundIds(account.accountId, [...new Set(ids)]);
|
|
42850
|
+
} catch {
|
|
42851
|
+
counts.unbound += ids.length;
|
|
42852
|
+
continue;
|
|
42853
|
+
}
|
|
42854
|
+
for (const id of ids) {
|
|
42855
|
+
const n = found.get(id) ?? 0;
|
|
42856
|
+
if (n === 1) counts.bound += 1;
|
|
42857
|
+
else if (n > 1) counts.ambiguous += 1;
|
|
42858
|
+
else counts.unbound += 1;
|
|
42859
|
+
}
|
|
42860
|
+
}
|
|
42861
|
+
if (counts.bots === 0) return [];
|
|
42862
|
+
return [buildIdentityCensusLine(counts)];
|
|
42863
|
+
}
|
|
42864
|
+
|
|
42865
|
+
// server/index.ts
|
|
42866
|
+
var import_dist20 = __toESM(require_dist5(), 1);
|
|
42867
|
+
|
|
42612
42868
|
// app/lib/telegram/gateway/origin-target.ts
|
|
42613
42869
|
function answeringOriginTarget(send, key2, noteAnswered3) {
|
|
42614
42870
|
if (!send) return null;
|
|
@@ -43282,8 +43538,8 @@ var webchatFileFollowers = /* @__PURE__ */ new Map();
|
|
|
43282
43538
|
async function fetchAccountStandingRules(accountId) {
|
|
43283
43539
|
const session = getSession();
|
|
43284
43540
|
try {
|
|
43285
|
-
const res = await (0,
|
|
43286
|
-
return { block: (0,
|
|
43541
|
+
const res = await (0, import_dist19.resolveActiveRules)(session, accountId);
|
|
43542
|
+
return { block: (0, import_dist19.formatStandingRulesBlock)(res.rules), ownerUserId: res.ownerUserId, source: res.source };
|
|
43287
43543
|
} catch (err) {
|
|
43288
43544
|
console.error(
|
|
43289
43545
|
`[preference-inject] op=fetch-failed accountId=${accountId} error=${err instanceof Error ? err.message : String(err)}`
|
|
@@ -44204,6 +44460,9 @@ app80.route("/api/webchat", createWebchatRoutes({
|
|
|
44204
44460
|
// Task 940 — the permission relay's pointer read + verdict write.
|
|
44205
44461
|
pendingPromptFor: (key2) => webchatGateway.pendingPromptFor(key2),
|
|
44206
44462
|
deliveryFailureFor: (key2) => webchatGateway.deliveryFailureFor(key2),
|
|
44463
|
+
// Task 2439 — the deferred send continuation's only way to report that a
|
|
44464
|
+
// staged upload will never produce a turn.
|
|
44465
|
+
markDeliveryFailure: (key2, messageId) => webchatGateway.markDeliveryFailure(key2, messageId),
|
|
44207
44466
|
resolvePermissionVerdict: (key2, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key2, requestId, behavior)
|
|
44208
44467
|
}));
|
|
44209
44468
|
app80.route("/api/webchat/greeting", webchat_greeting_default);
|
|
@@ -44909,6 +45168,31 @@ registerLoop({
|
|
|
44909
45168
|
`[telegram-native] op=telegram-spawn-census-rejected detail=${err instanceof Error ? err.message : String(err)}`
|
|
44910
45169
|
);
|
|
44911
45170
|
}
|
|
45171
|
+
try {
|
|
45172
|
+
for (const line of await runTelegramIdentityCensus(accounts, {
|
|
45173
|
+
boundIds: async (accountId, ids) => {
|
|
45174
|
+
const session = getSession();
|
|
45175
|
+
try {
|
|
45176
|
+
const result = await session.run(
|
|
45177
|
+
`MATCH (p:Person {accountId: $accountId})
|
|
45178
|
+
WHERE p.telegramUserId IN $ids AND ${(0, import_dist20.notTrashed)("p")}
|
|
45179
|
+
RETURN p.telegramUserId AS id, count(*) AS n`,
|
|
45180
|
+
{ accountId, ids },
|
|
45181
|
+
{ timeout: 5e3 }
|
|
45182
|
+
);
|
|
45183
|
+
return new Map(result.records.map((r) => [Number(r.get("id")), Number(r.get("n"))]));
|
|
45184
|
+
} finally {
|
|
45185
|
+
await session.close();
|
|
45186
|
+
}
|
|
45187
|
+
}
|
|
45188
|
+
})) {
|
|
45189
|
+
console.error(line);
|
|
45190
|
+
}
|
|
45191
|
+
} catch (err) {
|
|
45192
|
+
console.error(
|
|
45193
|
+
`[telegram-native] op=identity-census-rejected detail=${err instanceof Error ? err.message : String(err)}`
|
|
45194
|
+
);
|
|
45195
|
+
}
|
|
44912
45196
|
};
|
|
44913
45197
|
registerLoop({
|
|
44914
45198
|
name: "telegram-audit",
|