@rubytech/create-realagent-code 0.1.581 → 0.1.583
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/lib/routine-templates/dist/index.d.ts +1 -1
- package/payload/platform/lib/routine-templates/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/dist/index.js +5 -1
- package/payload/platform/lib/routine-templates/dist/index.js.map +1 -1
- package/payload/platform/lib/routine-templates/src/index.ts +4 -0
- package/payload/platform/lib/telegram-managed-bot/dist/index.d.ts +269 -0
- package/payload/platform/lib/telegram-managed-bot/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/telegram-managed-bot/dist/index.js +351 -0
- package/payload/platform/lib/telegram-managed-bot/dist/index.js.map +1 -0
- package/payload/platform/lib/telegram-managed-bot/src/__tests__/managed-bot.test.ts +251 -0
- package/payload/platform/lib/telegram-managed-bot/src/index.ts +529 -0
- package/payload/platform/lib/telegram-managed-bot/tsconfig.json +9 -0
- package/payload/platform/lib/telegram-managed-bot/vitest.config.ts +9 -0
- package/payload/platform/lib/telegram-reach/dist/index.d.ts +80 -0
- package/payload/platform/lib/telegram-reach/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/telegram-reach/dist/index.js +211 -0
- package/payload/platform/lib/telegram-reach/dist/index.js.map +1 -0
- package/payload/platform/lib/telegram-reach/src/__tests__/telegram-reach.test.ts +216 -0
- package/payload/platform/lib/telegram-reach/src/index.ts +262 -0
- package/payload/platform/lib/telegram-reach/tsconfig.json +9 -0
- package/payload/platform/lib/telegram-reach/vitest.config.ts +9 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/PLUGIN.md +1 -1
- package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh +9 -0
- package/payload/platform/plugins/admin/hooks/__tests__/preference-consult-directive.test.sh +26 -0
- package/payload/platform/plugins/admin/hooks/fs-schema-guard.sh +20 -3
- package/payload/platform/plugins/admin/hooks/preference-consult-directive.sh +50 -5
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +181 -9
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +17 -0
- package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.d.ts +2 -0
- package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.js +100 -0
- package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/index.js +11 -5
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +5 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +21 -4
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +5 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +29 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/vitest.config.ts +14 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +20 -4
- package/payload/platform/plugins/docs/references/calendar-booking.md +2 -0
- package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +15 -0
- package/payload/platform/plugins/docs/references/telegram-guide.md +143 -4
- package/payload/platform/plugins/filesystem/PLUGIN.md +2 -2
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.d.ts +2 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.js +108 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.d.ts +17 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.js +162 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.d.ts +2 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.js +116 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js +9 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js +10 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js +64 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts +5 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js +28 -6
- package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js.map +1 -1
- package/payload/platform/plugins/memory/references/schema-knowledge-work.md +1 -1
- package/payload/platform/plugins/scheduling/PLUGIN.md +19 -3
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +7 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js +53 -6
- 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 +38 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-uid-stamp.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-uid-stamp.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-uid-stamp.test.js +102 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-uid-stamp.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/schedule-audit.test.js +43 -9
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/schedule-audit.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +50 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +47 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts +5 -3
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +18 -3
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts +40 -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 +132 -41
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +14 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +61 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js +258 -8
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-trash-filter.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-trash-filter.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-trash-filter.test.js +67 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-trash-filter.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +206 -3
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +8 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +29 -21
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +94 -14
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js +6 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.js +7 -2
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +46 -3
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +30 -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 +69 -6
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +12 -0
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts +36 -5
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +103 -10
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +42 -4
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +19 -5
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +9 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +5 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.js +13 -0
- package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +40 -0
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +41 -4
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +52 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +64 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +14 -2
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/templates/account-schema/SCHEMA.md +17 -10
- package/payload/platform/templates/agents/admin/IDENTITY.md +5 -0
- package/payload/platform/templates/specialists/agents/data-manager.md +2 -2
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/{chunk-BFRB2U75.js → chunk-CV6AEMKH.js} +1 -0
- package/payload/server/{manager-CTVTF4YB.js → manager-FQSQSSJ3.js} +1 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/agents.html +5 -5
- package/payload/server/public/assets/{AdminLoginScreens-B1lu4-_F.js → AdminLoginScreens-BLsDYWVi.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-BLsDYWVi.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-BLsDYWVi.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-BMslfZxN.js → AdminShell-BZS8jzFA.js} +1 -1
- package/payload/server/public/assets/AdminShell-BZS8jzFA.js.br +0 -0
- package/payload/server/public/assets/AdminShell-BZS8jzFA.js.gz +0 -0
- package/payload/server/public/assets/{activity-kQ3w70LJ.js → activity-DOjvoLdd.js} +1 -1
- package/payload/server/public/assets/activity-DOjvoLdd.js.br +0 -0
- package/payload/server/public/assets/activity-DOjvoLdd.js.gz +0 -0
- package/payload/server/public/assets/{admin-CkASgYA7.js → admin-JrSNg29g.js} +1 -1
- package/payload/server/public/assets/admin-JrSNg29g.js.br +0 -0
- package/payload/server/public/assets/admin-JrSNg29g.js.gz +0 -0
- package/payload/server/public/assets/{agents-Cn_bZgnD.js → agents--9WMJVLC.js} +1 -1
- package/payload/server/public/assets/agents--9WMJVLC.js.br +0 -0
- package/payload/server/public/assets/agents--9WMJVLC.js.gz +0 -0
- package/payload/server/public/assets/{browser-BE-GDk5-.js → browser-DiiMmTrM.js} +1 -1
- package/payload/server/public/assets/browser-DiiMmTrM.js.br +0 -0
- package/payload/server/public/assets/browser-DiiMmTrM.js.gz +0 -0
- package/payload/server/public/assets/{calendar-Di7BEHHN.js → calendar-CazmCzgO.js} +1 -1
- package/payload/server/public/assets/calendar-CazmCzgO.js.br +0 -0
- package/payload/server/public/assets/calendar-CazmCzgO.js.gz +0 -0
- package/payload/server/public/assets/chat-CB0TcyXX.js +1 -0
- package/payload/server/public/assets/chat-CB0TcyXX.js.br +0 -0
- package/payload/server/public/assets/chat-CB0TcyXX.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-0tVo23Dh.js +1 -0
- package/payload/server/public/assets/chevron-left-0tVo23Dh.js.br +0 -0
- package/payload/server/public/assets/clock-D2cZ0sge.js +1 -0
- package/payload/server/public/assets/clock-D2cZ0sge.js.br +0 -0
- package/payload/server/public/assets/clock-D2cZ0sge.js.gz +0 -0
- package/payload/server/public/assets/{copy-nkxspu2J.js → copy-C87QIN_o.js} +1 -1
- package/payload/server/public/assets/copy-C87QIN_o.js.br +0 -0
- package/payload/server/public/assets/copy-C87QIN_o.js.gz +0 -0
- package/payload/server/public/assets/data-CK7AMxPt.js +1 -0
- package/payload/server/public/assets/data-CK7AMxPt.js.br +0 -0
- package/payload/server/public/assets/data-CK7AMxPt.js.gz +0 -0
- package/payload/server/public/assets/{field-2rIXxGMt.js → field-C3kQgGWE.js} +1 -1
- package/payload/server/public/assets/field-C3kQgGWE.js.br +0 -0
- package/payload/server/public/assets/field-C3kQgGWE.js.gz +0 -0
- package/payload/server/public/assets/{file-text-CdSqrscg.js → file-text-rWowl9RN.js} +1 -1
- package/payload/server/public/assets/file-text-rWowl9RN.js.br +0 -0
- package/payload/server/public/assets/file-text-rWowl9RN.js.gz +0 -0
- package/payload/server/public/assets/{graph-BfBHHXaC.js → graph-CVJKz1Uo.js} +1 -1
- package/payload/server/public/assets/graph-CVJKz1Uo.js.br +0 -0
- package/payload/server/public/assets/graph-CVJKz1Uo.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-CHW2aBke.js → graph-labels-kneGnsHB.js} +1 -1
- package/payload/server/public/assets/graph-labels-kneGnsHB.js.br +0 -0
- package/payload/server/public/assets/graph-labels-kneGnsHB.js.gz +0 -0
- package/payload/server/public/assets/{jsx-runtime-D43jgaWP.css → jsx-runtime-rMaiYjNu.css} +1 -1
- package/payload/server/public/assets/jsx-runtime-rMaiYjNu.css.br +0 -0
- package/payload/server/public/assets/{jsx-runtime-D43jgaWP.css.gz → jsx-runtime-rMaiYjNu.css.gz} +0 -0
- package/payload/server/public/assets/{operator-DRn9LITC.js → operator-BGvB4hu4.js} +1 -1
- package/payload/server/public/assets/operator-BGvB4hu4.js.br +0 -0
- package/payload/server/public/assets/operator-BGvB4hu4.js.gz +0 -0
- package/payload/server/public/assets/{page-D_9mPS6W.js → page-DBQLOasI.js} +1 -1
- package/payload/server/public/assets/page-DBQLOasI.js.br +0 -0
- package/payload/server/public/assets/page-DBQLOasI.js.gz +0 -0
- package/payload/server/public/assets/{page-BwqQsoU8.js → page-DyVAu7tm.js} +1 -1
- package/payload/server/public/assets/page-DyVAu7tm.js.br +0 -0
- package/payload/server/public/assets/page-DyVAu7tm.js.gz +0 -0
- package/payload/server/public/assets/play-DgP7vl0r.js +1 -0
- package/payload/server/public/assets/play-DgP7vl0r.js.br +0 -0
- package/payload/server/public/assets/play-DgP7vl0r.js.gz +0 -0
- package/payload/server/public/assets/{public-CrjZYpdW.js → public-BvUQR3hd.js} +1 -1
- package/payload/server/public/assets/public-BvUQR3hd.js.br +0 -0
- package/payload/server/public/assets/public-BvUQR3hd.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-J9f-GWjm.js → rotate-ccw-Dnn7gbPh.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-Dnn7gbPh.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-Dnn7gbPh.js.gz +0 -0
- package/payload/server/public/assets/{routines-C1AB-3FR.js → routines-N8NmxPOZ.js} +1 -1
- package/payload/server/public/assets/routines-N8NmxPOZ.js.br +0 -0
- package/payload/server/public/assets/routines-N8NmxPOZ.js.gz +0 -0
- package/payload/server/public/assets/{skills-C4EfNKEx.js → skills-B2CRgO-U.js} +1 -1
- package/payload/server/public/assets/skills-B2CRgO-U.js.br +0 -0
- package/payload/server/public/assets/skills-B2CRgO-U.js.gz +0 -0
- package/payload/server/public/assets/{tasks-DszD3aZl.js → tasks-8QLGtlSj.js} +1 -1
- package/payload/server/public/assets/tasks-8QLGtlSj.js.br +0 -0
- package/payload/server/public/assets/tasks-8QLGtlSj.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-B5WAyAkC.js → triangle-alert-el772yUQ.js} +1 -1
- package/payload/server/public/assets/triangle-alert-el772yUQ.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-el772yUQ.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-B2nuNNJw.js → useCopyFeedback-DfNAu8hQ.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-DfNAu8hQ.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-DfNAu8hQ.js.gz +0 -0
- package/payload/server/public/assets/{useMediaQuery-DUPJPHQt.js → useMediaQuery-B469O83-.js} +1 -1
- package/payload/server/public/assets/useMediaQuery-B469O83-.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-B469O83-.js.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-Bb-51cJv.js +2 -0
- package/payload/server/public/assets/useVoiceRecorder-Bb-51cJv.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-Bb-51cJv.js.gz +0 -0
- package/payload/server/public/assets/{wrench-DZJZm17j.js → wrench-Ck4phkdB.js} +1 -1
- package/payload/server/public/assets/wrench-Ck4phkdB.js.br +0 -0
- package/payload/server/public/assets/wrench-Ck4phkdB.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 +3777 -1258
- package/payload/server/public/assets/AdminLoginScreens-B1lu4-_F.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-B1lu4-_F.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-BMslfZxN.js.br +0 -0
- package/payload/server/public/assets/AdminShell-BMslfZxN.js.gz +0 -0
- package/payload/server/public/assets/activity-kQ3w70LJ.js.br +0 -0
- package/payload/server/public/assets/activity-kQ3w70LJ.js.gz +0 -0
- package/payload/server/public/assets/admin-CkASgYA7.js.br +0 -0
- package/payload/server/public/assets/admin-CkASgYA7.js.gz +0 -0
- package/payload/server/public/assets/agents-Cn_bZgnD.js.br +0 -0
- package/payload/server/public/assets/agents-Cn_bZgnD.js.gz +0 -0
- package/payload/server/public/assets/browser-BE-GDk5-.js.br +0 -0
- package/payload/server/public/assets/browser-BE-GDk5-.js.gz +0 -0
- package/payload/server/public/assets/calendar-Di7BEHHN.js.br +0 -0
- package/payload/server/public/assets/calendar-Di7BEHHN.js.gz +0 -0
- package/payload/server/public/assets/chat-CKyMT5Ai.js +0 -1
- package/payload/server/public/assets/chat-CKyMT5Ai.js.br +0 -1
- package/payload/server/public/assets/chat-CKyMT5Ai.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-Id9VAZAz.js +0 -1
- package/payload/server/public/assets/chevron-left-Id9VAZAz.js.br +0 -0
- package/payload/server/public/assets/clock-DKpWWJbJ.js +0 -1
- package/payload/server/public/assets/clock-DKpWWJbJ.js.br +0 -0
- package/payload/server/public/assets/copy-nkxspu2J.js.br +0 -0
- package/payload/server/public/assets/copy-nkxspu2J.js.gz +0 -0
- package/payload/server/public/assets/data-1c33cAHp.js +0 -1
- package/payload/server/public/assets/data-1c33cAHp.js.br +0 -2
- package/payload/server/public/assets/data-1c33cAHp.js.gz +0 -0
- package/payload/server/public/assets/field-2rIXxGMt.js.br +0 -0
- package/payload/server/public/assets/field-2rIXxGMt.js.gz +0 -0
- package/payload/server/public/assets/file-text-CdSqrscg.js.br +0 -0
- package/payload/server/public/assets/file-text-CdSqrscg.js.gz +0 -0
- package/payload/server/public/assets/graph-BfBHHXaC.js.br +0 -0
- package/payload/server/public/assets/graph-BfBHHXaC.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-CHW2aBke.js.br +0 -0
- package/payload/server/public/assets/graph-labels-CHW2aBke.js.gz +0 -0
- package/payload/server/public/assets/jsx-runtime-D43jgaWP.css.br +0 -0
- package/payload/server/public/assets/operator-DRn9LITC.js.br +0 -0
- package/payload/server/public/assets/operator-DRn9LITC.js.gz +0 -0
- package/payload/server/public/assets/page-BwqQsoU8.js.br +0 -0
- package/payload/server/public/assets/page-BwqQsoU8.js.gz +0 -0
- package/payload/server/public/assets/page-D_9mPS6W.js.br +0 -0
- package/payload/server/public/assets/page-D_9mPS6W.js.gz +0 -0
- package/payload/server/public/assets/play-7LTxCuLX.js +0 -1
- package/payload/server/public/assets/play-7LTxCuLX.js.br +0 -0
- package/payload/server/public/assets/play-7LTxCuLX.js.gz +0 -0
- package/payload/server/public/assets/public-CrjZYpdW.js.br +0 -0
- package/payload/server/public/assets/public-CrjZYpdW.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-J9f-GWjm.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-J9f-GWjm.js.gz +0 -0
- package/payload/server/public/assets/routines-C1AB-3FR.js.br +0 -0
- package/payload/server/public/assets/routines-C1AB-3FR.js.gz +0 -0
- package/payload/server/public/assets/skills-C4EfNKEx.js.br +0 -0
- package/payload/server/public/assets/skills-C4EfNKEx.js.gz +0 -0
- package/payload/server/public/assets/tasks-DszD3aZl.js.br +0 -0
- package/payload/server/public/assets/tasks-DszD3aZl.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-B5WAyAkC.js.br +0 -4
- package/payload/server/public/assets/triangle-alert-B5WAyAkC.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-B2nuNNJw.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-B2nuNNJw.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-DUPJPHQt.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-DUPJPHQt.js.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-CCK60d2i.js +0 -2
- package/payload/server/public/assets/useVoiceRecorder-CCK60d2i.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-CCK60d2i.js.gz +0 -0
- package/payload/server/public/assets/wrench-DZJZm17j.js.br +0 -0
- package/payload/server/public/assets/wrench-DZJZm17j.js.gz +0 -0
- /package/payload/server/public/assets/{jsx-runtime-Cjug_Cyb.js → jsx-runtime-BmNepPEn.js} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-Cjug_Cyb.js.br → jsx-runtime-BmNepPEn.js.br} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-Cjug_Cyb.js.gz → jsx-runtime-BmNepPEn.js.gz} +0 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task 2618 — Telegram's managed-bot surface, and the webhook registration that
|
|
3
|
+
* a newly provisioned bot needs.
|
|
4
|
+
*
|
|
5
|
+
* This is a shared lib rather than plugin code because BOTH sides need it. The
|
|
6
|
+
* `managed_bot` update lands on the UI webhook route, which must fetch the new
|
|
7
|
+
* bot's token, persist it and register its webhook; the `telegram-bot-provision`
|
|
8
|
+
* MCP tool needs the same four Bot API calls for its own actions. UI production
|
|
9
|
+
* code does not import plugin source, so the alternative was a second copy of
|
|
10
|
+
* `TELEGRAM_ALLOWED_UPDATES` on the UI side — and two lists that must agree, of
|
|
11
|
+
* a set where naming any class replaces Telegram's default, is exactly the drift
|
|
12
|
+
* Task 2612 spent a task fixing.
|
|
13
|
+
*
|
|
14
|
+
* `TELEGRAM_ALLOWED_UPDATES` and `setTelegramWebhook` MOVED here from
|
|
15
|
+
* `plugins/telegram/mcp/src/lib/telegram.ts`, which now re-exports both so every
|
|
16
|
+
* existing plugin import keeps its path.
|
|
17
|
+
*
|
|
18
|
+
* Every name below is quoted from core.telegram.org/bots/api, read 2026-08-09.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { randomBytes } from "node:crypto";
|
|
22
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
23
|
+
import { dirname, join } from "node:path";
|
|
24
|
+
|
|
25
|
+
const TELEGRAM_API = "https://api.telegram.org";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Task 2612 — the update classes this install asks Telegram for.
|
|
29
|
+
*
|
|
30
|
+
* The trap: naming ANY class replaces Telegram's default set, so a class that
|
|
31
|
+
* works today and is missing from this list stops arriving with no error
|
|
32
|
+
* anywhere. Telegram's default is every class except `chat_member`,
|
|
33
|
+
* `message_reaction` and `message_reaction_count`.
|
|
34
|
+
*
|
|
35
|
+
* Task 2618 — `managed_bot` is fifteenth. It IS in Telegram's default set, so it
|
|
36
|
+
* arrives on an install that names nothing; but this install names its list, so
|
|
37
|
+
* omitting it here is the difference between a tapped provisioning button that
|
|
38
|
+
* works and one that silently does nothing.
|
|
39
|
+
*
|
|
40
|
+
* The order is the one Task 2612 states, and the registration test asserts the
|
|
41
|
+
* whole array rather than membership — the failure guarded against is a name
|
|
42
|
+
* silently dropped, which a membership check cannot see.
|
|
43
|
+
*/
|
|
44
|
+
export const TELEGRAM_ALLOWED_UPDATES: readonly string[] = [
|
|
45
|
+
"message",
|
|
46
|
+
"edited_message",
|
|
47
|
+
"callback_query",
|
|
48
|
+
"poll_answer",
|
|
49
|
+
"poll",
|
|
50
|
+
"message_reaction",
|
|
51
|
+
"pre_checkout_query",
|
|
52
|
+
"shipping_query",
|
|
53
|
+
"subscription",
|
|
54
|
+
"my_chat_member",
|
|
55
|
+
"business_connection",
|
|
56
|
+
"business_message",
|
|
57
|
+
"edited_business_message",
|
|
58
|
+
"deleted_business_messages",
|
|
59
|
+
"managed_bot",
|
|
60
|
+
// Task 2616 — the group set. `chat_member` (another member's membership
|
|
61
|
+
// changed, as against `my_chat_member` for the bot's own) and
|
|
62
|
+
// `message_reaction_count` (the anonymous tally that pairs with
|
|
63
|
+
// `message_reaction`) are OUTSIDE Telegram's default, so neither arrives until
|
|
64
|
+
// a bot re-registers. `chat_join_request` and the two boost classes are inside
|
|
65
|
+
// it and are named so that making the list explicit is not itself a regression.
|
|
66
|
+
"chat_member",
|
|
67
|
+
"chat_join_request",
|
|
68
|
+
"message_reaction_count",
|
|
69
|
+
"chat_boost",
|
|
70
|
+
"removed_chat_boost",
|
|
71
|
+
// Task 2617 — the channel pair. Both are INSIDE Telegram's default set, so they
|
|
72
|
+
// would arrive on an install that names nothing; this install names its own
|
|
73
|
+
// list, so they are named here for the reason `chat_join_request` and the two
|
|
74
|
+
// boost classes are — making the list explicit must not itself be a regression.
|
|
75
|
+
//
|
|
76
|
+
// Without them a channel post never reaches the route at all, and the failure is
|
|
77
|
+
// silent: Telegram reports no error for a class it was not asked for.
|
|
78
|
+
"channel_post",
|
|
79
|
+
"edited_channel_post",
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Register a webhook URL with Telegram and generate a cryptographic secret.
|
|
84
|
+
*
|
|
85
|
+
* The secret is generated via crypto.randomBytes (64 hex chars), passed as
|
|
86
|
+
* `secret_token`, and written to disk ONLY after the API confirms success. That
|
|
87
|
+
* order prevents orphaned secret files when the call fails, and avoids
|
|
88
|
+
* overwriting a working secret during a failed re-registration.
|
|
89
|
+
*
|
|
90
|
+
* Telegram sends the secret in the X-Telegram-Bot-Api-Secret-Token header on
|
|
91
|
+
* every delivery; the webhook route validates it before processing.
|
|
92
|
+
*
|
|
93
|
+
* If secretFilePath is omitted, no secret is generated.
|
|
94
|
+
*/
|
|
95
|
+
export async function setTelegramWebhook(
|
|
96
|
+
botToken: string,
|
|
97
|
+
webhookUrl: string,
|
|
98
|
+
secretFilePath?: string,
|
|
99
|
+
fetchImpl: typeof fetch = fetch,
|
|
100
|
+
): Promise<{ ok: boolean; secret?: string; error?: string }> {
|
|
101
|
+
const secret = secretFilePath ? randomBytes(32).toString("hex") : undefined;
|
|
102
|
+
|
|
103
|
+
// Task 2612 — `allowed_updates` travels on every registration.
|
|
104
|
+
const body: Record<string, unknown> = {
|
|
105
|
+
url: webhookUrl,
|
|
106
|
+
allowed_updates: [...TELEGRAM_ALLOWED_UPDATES],
|
|
107
|
+
};
|
|
108
|
+
if (secret) {
|
|
109
|
+
body.secret_token = secret;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const res = await fetchImpl(`${TELEGRAM_API}/bot${botToken}/setWebhook`, {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: { "Content-Type": "application/json" },
|
|
115
|
+
body: JSON.stringify(body),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const data = (await res.json()) as { ok: boolean; description?: string };
|
|
119
|
+
|
|
120
|
+
if (!data.ok) {
|
|
121
|
+
return { ok: false, error: data.description ?? "Failed to set webhook" };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (secret && secretFilePath) {
|
|
125
|
+
mkdirSync(dirname(secretFilePath), { recursive: true });
|
|
126
|
+
writeFileSync(secretFilePath, secret, { mode: 0o600 });
|
|
127
|
+
console.error(
|
|
128
|
+
`[telegram] webhook secret written to ${secretFilePath} (${secret.length} chars)`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { ok: true, secret };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** One entry in an account's `telegram.bots[]`.
|
|
136
|
+
*
|
|
137
|
+
* Task 2618 adds the third role: a bot this install provisioned that nothing has
|
|
138
|
+
* bound to an agent yet. It carries no `agent` and no `adminUsers` because
|
|
139
|
+
* neither has an answer between the tap that created it and Task 2619's binding. */
|
|
140
|
+
export type TelegramBotEntryWrite =
|
|
141
|
+
| { id: string; token: string; role: "admin"; adminUsers?: number[]; managed?: boolean }
|
|
142
|
+
| {
|
|
143
|
+
id: string;
|
|
144
|
+
token: string;
|
|
145
|
+
role: "public";
|
|
146
|
+
agent: string;
|
|
147
|
+
dmPolicy?: "open" | "allowlist" | "disabled";
|
|
148
|
+
allowFrom?: number[];
|
|
149
|
+
managed?: boolean;
|
|
150
|
+
}
|
|
151
|
+
| { id: string; token: string; role: "unbound"; managed?: boolean }
|
|
152
|
+
// Task 2619 — a bot bound to one of the account's own specialist cards.
|
|
153
|
+
// `specialist` is a card FILE BASENAME, the only value `--agent` resolves.
|
|
154
|
+
// There is no `dmPolicy`: a specialist session carries the card's own tool
|
|
155
|
+
// surface rather than the zero-tool public ringfence, so an explicit list of
|
|
156
|
+
// ids is the only gate that holds, and the register tool requires a non-empty
|
|
157
|
+
// `allowFrom` even though the shape permits its absence (an absent list admits
|
|
158
|
+
// nobody, which is the safe reading for a config already on disk).
|
|
159
|
+
| {
|
|
160
|
+
id: string;
|
|
161
|
+
token: string;
|
|
162
|
+
role: "specialist";
|
|
163
|
+
specialist: string;
|
|
164
|
+
allowFrom?: number[];
|
|
165
|
+
managed?: boolean;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/** Merge one bot entry into an account's `telegram.bots[]`, replacing any entry
|
|
169
|
+
* with the same id and leaving every other entry and every other key
|
|
170
|
+
* byte-identical.
|
|
171
|
+
*
|
|
172
|
+
* THE single writer of that array. Two callers reach it: the plugin's
|
|
173
|
+
* `persistTelegramBot`, which adds the brand-containment assertion it needs
|
|
174
|
+
* because it resolves this directory from an untrusted `accountId`; and the UI
|
|
175
|
+
* webhook route, which already holds a directory that came from the platform's
|
|
176
|
+
* own account enumeration. A bot registry with two writers is one that
|
|
177
|
+
* eventually disagrees with itself about who is registered.
|
|
178
|
+
*
|
|
179
|
+
* Task 2368's invariant is carried unchanged: registering, re-pointing or
|
|
180
|
+
* rotating one bot cannot disturb another. */
|
|
181
|
+
export function writeTelegramBotEntry(
|
|
182
|
+
accountDir: string,
|
|
183
|
+
entry: TelegramBotEntryWrite,
|
|
184
|
+
): { ok: boolean; error?: string } {
|
|
185
|
+
const configPath = join(accountDir, "account.json");
|
|
186
|
+
if (!existsSync(configPath)) {
|
|
187
|
+
return { ok: false, error: `account.json not found at ${configPath}` };
|
|
188
|
+
}
|
|
189
|
+
let config: Record<string, unknown>;
|
|
190
|
+
try {
|
|
191
|
+
config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
192
|
+
} catch (e) {
|
|
193
|
+
// Refuse rather than overwrite. A file that will not parse holds state this
|
|
194
|
+
// merge cannot preserve, and replacing it would drop every other bot.
|
|
195
|
+
return { ok: false, error: `account.json parse failed: ${(e as Error).message}` };
|
|
196
|
+
}
|
|
197
|
+
const telegram = (config.telegram as Record<string, unknown>) ?? {};
|
|
198
|
+
const bots = Array.isArray(telegram.bots) ? (telegram.bots as TelegramBotEntryWrite[]) : [];
|
|
199
|
+
const at = bots.findIndex((b) => b && typeof b === "object" && b.id === entry.id);
|
|
200
|
+
if (at >= 0) bots[at] = entry;
|
|
201
|
+
else bots.push(entry);
|
|
202
|
+
telegram.bots = bots;
|
|
203
|
+
config.telegram = telegram;
|
|
204
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
205
|
+
return { ok: true };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface WebhookInfo {
|
|
209
|
+
url: string;
|
|
210
|
+
pendingUpdateCount: number;
|
|
211
|
+
/** Unix seconds of the most recent delivery error Telegram saw, 0 when it
|
|
212
|
+
* reports none. Telegram KEEPS this across a re-registration, which is why
|
|
213
|
+
* the verdict compares it against the moment we registered. */
|
|
214
|
+
lastErrorDate: number;
|
|
215
|
+
lastErrorMessage?: string;
|
|
216
|
+
/** Task 2612 — the classes Telegram says it will deliver. Telegram omits the
|
|
217
|
+
* field entirely when the registration uses its default set, which reads here
|
|
218
|
+
* as `[]` — and `[]` is exactly the pre-2612 state, so an empty list against a
|
|
219
|
+
* non-empty request is a real mismatch and not a missing field. */
|
|
220
|
+
allowedUpdates: string[];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** What Telegram says it is currently delivering for this bot.
|
|
224
|
+
*
|
|
225
|
+
* Task 2618 — MOVED here from the plugin, which re-exports it. Three callers
|
|
226
|
+
* now: the plugin's registration probe, the tool's rotate action reading the URL
|
|
227
|
+
* to restore, and the UI's hourly managed-bot census. */
|
|
228
|
+
export async function getTelegramWebhookInfo(
|
|
229
|
+
botToken: string,
|
|
230
|
+
fetchImpl: typeof fetch = fetch,
|
|
231
|
+
): Promise<WebhookInfo> {
|
|
232
|
+
const res = await fetchImpl(`${TELEGRAM_API}/bot${botToken}/getWebhookInfo`);
|
|
233
|
+
const data = (await res.json()) as {
|
|
234
|
+
result: {
|
|
235
|
+
url: string;
|
|
236
|
+
pending_update_count: number;
|
|
237
|
+
last_error_date?: number;
|
|
238
|
+
last_error_message?: string;
|
|
239
|
+
allowed_updates?: string[];
|
|
240
|
+
};
|
|
241
|
+
};
|
|
242
|
+
return {
|
|
243
|
+
url: data.result.url,
|
|
244
|
+
pendingUpdateCount: data.result.pending_update_count,
|
|
245
|
+
lastErrorDate: data.result.last_error_date ?? 0,
|
|
246
|
+
allowedUpdates: data.result.allowed_updates ?? [],
|
|
247
|
+
...(data.result.last_error_message !== undefined
|
|
248
|
+
? { lastErrorMessage: data.result.last_error_message }
|
|
249
|
+
: {}),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** One stored entry, whole, or null when the account holds no bot with that id.
|
|
254
|
+
*
|
|
255
|
+
* The point is "whole". `listRegisteredBots` returns `{ id, role, agent }` for
|
|
256
|
+
* the callers that only need to name a bot, and a rotation that spread THAT into
|
|
257
|
+
* the writer would silently drop `adminUsers`, `dmPolicy`, `allowFrom` and
|
|
258
|
+
* `managed` — replacing a token would quietly un-admit every admin on the bot.
|
|
259
|
+
* A rotation changes one field and must carry the rest through untouched. */
|
|
260
|
+
export function readTelegramBotEntry(
|
|
261
|
+
accountDir: string,
|
|
262
|
+
botId: string,
|
|
263
|
+
): TelegramBotEntryWrite | null {
|
|
264
|
+
const configPath = join(accountDir, "account.json");
|
|
265
|
+
if (!existsSync(configPath)) return null;
|
|
266
|
+
try {
|
|
267
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8")) as {
|
|
268
|
+
telegram?: { bots?: TelegramBotEntryWrite[] };
|
|
269
|
+
};
|
|
270
|
+
const bots = config.telegram?.bots;
|
|
271
|
+
if (!Array.isArray(bots)) return null;
|
|
272
|
+
return bots.find((b) => b && typeof b === "object" && b.id === botId) ?? null;
|
|
273
|
+
} catch {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Bot API `User`, as far as the managed-bot payloads use it. */
|
|
279
|
+
export interface TelegramManagedUser {
|
|
280
|
+
id?: number;
|
|
281
|
+
is_bot?: boolean;
|
|
282
|
+
first_name?: string;
|
|
283
|
+
username?: string;
|
|
284
|
+
/** "True, if other bots can be created to be controlled by the bot. Returned
|
|
285
|
+
* only in getMe." The managing bot needs this before a request button can be
|
|
286
|
+
* offered; it is switched on in the @BotFather Mini App, not by any API call. */
|
|
287
|
+
can_manage_bots?: boolean;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** Bot API `ManagedBotUpdated`, the `managed_bot` update's payload.
|
|
291
|
+
*
|
|
292
|
+
* Note what is NOT here: no event discriminator and no `request_id`. Telegram
|
|
293
|
+
* documents the update as "A new bot was created to be managed by the bot, or
|
|
294
|
+
* token or owner of a managed bot was changed" and sends the same two fields
|
|
295
|
+
* for all three. Which of them happened is derivable only from local state. */
|
|
296
|
+
export interface ManagedBotUpdated {
|
|
297
|
+
/** The user who created the bot. */
|
|
298
|
+
user?: TelegramManagedUser;
|
|
299
|
+
/** The bot itself. Its `id` is the value every managed-bot method keys on. */
|
|
300
|
+
bot?: TelegramManagedUser;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Bot API `ManagedBotCreated`, the `managed_bot_created` service message field. */
|
|
304
|
+
export interface ManagedBotCreated {
|
|
305
|
+
bot?: TelegramManagedUser;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** Bot API `KeyboardButtonRequestManagedBot`. `request_id` is a signed 32-bit
|
|
309
|
+
* integer, unique within the message. */
|
|
310
|
+
export interface KeyboardButtonRequestManagedBot {
|
|
311
|
+
request_id: number;
|
|
312
|
+
suggested_name?: string;
|
|
313
|
+
suggested_username?: string;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** The largest `request_id` Telegram accepts: it is a signed 32-bit integer. */
|
|
317
|
+
export const MANAGED_BOT_REQUEST_ID_MAX = 2_147_483_647;
|
|
318
|
+
|
|
319
|
+
/** Bot API `ReplyKeyboardMarkup`, narrowed to the fields this install sends.
|
|
320
|
+
*
|
|
321
|
+
* "Not supported in channels and for messages sent on behalf of a business
|
|
322
|
+
* account", and `request_managed_bot` is further "Available in private chats
|
|
323
|
+
* only" — both are the caller's constraint, not this type's. */
|
|
324
|
+
export interface TelegramReplyKeyboard {
|
|
325
|
+
keyboard: Array<Array<{ text: string; request_managed_bot?: KeyboardButtonRequestManagedBot }>>;
|
|
326
|
+
one_time_keyboard?: boolean;
|
|
327
|
+
resize_keyboard?: boolean;
|
|
328
|
+
is_persistent?: boolean;
|
|
329
|
+
input_field_placeholder?: string;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** The one reply keyboard this install builds: a single button asking the user to
|
|
333
|
+
* create a bot for this bot to manage.
|
|
334
|
+
*
|
|
335
|
+
* Shared because both doors send it — the MCP tool's `offer` action and, if a
|
|
336
|
+
* later caller needs it, the UI's own outbound. One builder, because a button
|
|
337
|
+
* whose `request_id` is built two ways is a button whose answer cannot be
|
|
338
|
+
* correlated.
|
|
339
|
+
*
|
|
340
|
+
* One button in one row: `request_id` must be "unique within the message" and
|
|
341
|
+
* nothing here has a reason to send two at once. `one_time_keyboard` so it
|
|
342
|
+
* disappears once tapped rather than sitting in the operator's chat. */
|
|
343
|
+
export function buildManagedBotRequestKeyboard(input: {
|
|
344
|
+
text: string;
|
|
345
|
+
requestId: number;
|
|
346
|
+
suggestedName?: string;
|
|
347
|
+
suggestedUsername?: string;
|
|
348
|
+
}): TelegramReplyKeyboard {
|
|
349
|
+
if (
|
|
350
|
+
!Number.isInteger(input.requestId) ||
|
|
351
|
+
input.requestId < 1 ||
|
|
352
|
+
input.requestId > MANAGED_BOT_REQUEST_ID_MAX
|
|
353
|
+
) {
|
|
354
|
+
// Refused here, not by Telegram: Telegram rejects the send with a description
|
|
355
|
+
// that never names the field, so the operator would see a failed offer and no
|
|
356
|
+
// reason for it.
|
|
357
|
+
throw new Error(
|
|
358
|
+
`request_id ${input.requestId} is not a positive signed 32-bit integer, which is what Telegram requires`,
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
keyboard: [
|
|
363
|
+
[
|
|
364
|
+
{
|
|
365
|
+
text: input.text,
|
|
366
|
+
request_managed_bot: {
|
|
367
|
+
request_id: input.requestId,
|
|
368
|
+
...(input.suggestedName !== undefined ? { suggested_name: input.suggestedName } : {}),
|
|
369
|
+
...(input.suggestedUsername !== undefined
|
|
370
|
+
? { suggested_username: input.suggestedUsername }
|
|
371
|
+
: {}),
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
],
|
|
376
|
+
one_time_keyboard: true,
|
|
377
|
+
resize_keyboard: true,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Telegram caps `added_user_ids` at ten. Refused locally so the cap is named,
|
|
382
|
+
* rather than surfacing as an opaque API error with no number in it. */
|
|
383
|
+
export const MAX_ADDED_USER_IDS = 10;
|
|
384
|
+
|
|
385
|
+
/** The four Bot API methods this module owns, keyed by the action that uses each.
|
|
386
|
+
* Read by the plugin's `OWNED_METHODS` census and by its `api-guard` refusals,
|
|
387
|
+
* so neither can disagree with this module about what it covers. */
|
|
388
|
+
export const MANAGED_BOT_METHODS = Object.freeze({
|
|
389
|
+
token: "getManagedBotToken",
|
|
390
|
+
rotate: "replaceManagedBotToken",
|
|
391
|
+
accessRead: "getManagedBotAccessSettings",
|
|
392
|
+
accessWrite: "setManagedBotAccessSettings",
|
|
393
|
+
} as const);
|
|
394
|
+
|
|
395
|
+
async function call(
|
|
396
|
+
botToken: string,
|
|
397
|
+
method: string,
|
|
398
|
+
body: Record<string, unknown>,
|
|
399
|
+
fetchImpl: typeof fetch,
|
|
400
|
+
): Promise<{ ok: true; result: unknown } | { ok: false; error: string }> {
|
|
401
|
+
try {
|
|
402
|
+
const res = await fetchImpl(`${TELEGRAM_API}/bot${botToken}/${method}`, {
|
|
403
|
+
method: "POST",
|
|
404
|
+
headers: { "Content-Type": "application/json" },
|
|
405
|
+
body: JSON.stringify(body),
|
|
406
|
+
});
|
|
407
|
+
const data = (await res.json()) as { ok: boolean; result?: unknown; description?: string };
|
|
408
|
+
if (!data.ok) return { ok: false, error: data.description ?? `${method} failed` };
|
|
409
|
+
return { ok: true, result: data.result };
|
|
410
|
+
} catch (e) {
|
|
411
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** "Use this method to get the token of a managed bot. Returns the token as
|
|
416
|
+
* String on success." `userId` is the MANAGED bot's own user id, which is also
|
|
417
|
+
* the numeric prefix of the token this returns.
|
|
418
|
+
*
|
|
419
|
+
* The token is a credential. Every caller persists it and nothing logs it. */
|
|
420
|
+
export async function getManagedBotToken(
|
|
421
|
+
managingBotToken: string,
|
|
422
|
+
userId: number,
|
|
423
|
+
fetchImpl: typeof fetch = fetch,
|
|
424
|
+
): Promise<{ ok: true; token: string } | { ok: false; error: string }> {
|
|
425
|
+
const r = await call(managingBotToken, MANAGED_BOT_METHODS.token, { user_id: userId }, fetchImpl);
|
|
426
|
+
if (!r.ok) return r;
|
|
427
|
+
return typeof r.result === "string"
|
|
428
|
+
? { ok: true, token: r.result }
|
|
429
|
+
: { ok: false, error: "no-token-in-result" };
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/** "Use this method to revoke the current token of a managed bot and generate a
|
|
433
|
+
* new one. Returns the new token as String on success."
|
|
434
|
+
*
|
|
435
|
+
* The bot's user id is unchanged by a rotation, so the new token has the same
|
|
436
|
+
* numeric prefix and the bot keys on nothing new. */
|
|
437
|
+
export async function replaceManagedBotToken(
|
|
438
|
+
managingBotToken: string,
|
|
439
|
+
userId: number,
|
|
440
|
+
fetchImpl: typeof fetch = fetch,
|
|
441
|
+
): Promise<{ ok: true; token: string } | { ok: false; error: string }> {
|
|
442
|
+
const r = await call(managingBotToken, MANAGED_BOT_METHODS.rotate, { user_id: userId }, fetchImpl);
|
|
443
|
+
if (!r.ok) return r;
|
|
444
|
+
return typeof r.result === "string"
|
|
445
|
+
? { ok: true, token: r.result }
|
|
446
|
+
: { ok: false, error: "no-token-in-result" };
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
export interface ManagedBotAccess {
|
|
450
|
+
isAccessRestricted: boolean;
|
|
451
|
+
/** The ids of users admitted BESIDES the owner, who "can always access it".
|
|
452
|
+
* An absent `added_users` reads as nobody, which is what Telegram means by
|
|
453
|
+
* omitting it, and not as unknown. */
|
|
454
|
+
addedUserIds: number[];
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/** "Returns a BotAccessSettings object on success." */
|
|
458
|
+
export async function getManagedBotAccessSettings(
|
|
459
|
+
managingBotToken: string,
|
|
460
|
+
userId: number,
|
|
461
|
+
fetchImpl: typeof fetch = fetch,
|
|
462
|
+
): Promise<({ ok: true } & ManagedBotAccess) | { ok: false; error: string }> {
|
|
463
|
+
const r = await call(
|
|
464
|
+
managingBotToken,
|
|
465
|
+
MANAGED_BOT_METHODS.accessRead,
|
|
466
|
+
{ user_id: userId },
|
|
467
|
+
fetchImpl,
|
|
468
|
+
);
|
|
469
|
+
if (!r.ok) return r;
|
|
470
|
+
const s = r.result as { is_access_restricted?: boolean; added_users?: TelegramManagedUser[] };
|
|
471
|
+
return {
|
|
472
|
+
ok: true,
|
|
473
|
+
isAccessRestricted: s?.is_access_restricted === true,
|
|
474
|
+
addedUserIds: (s?.added_users ?? [])
|
|
475
|
+
.map((u) => u?.id)
|
|
476
|
+
.filter((id): id is number => typeof id === "number"),
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/** "Use this method to change the access settings of a managed bot. Returns True
|
|
481
|
+
* on success." `addedUserIds` is "Ignored if is_access_restricted is False",
|
|
482
|
+
* which is Telegram's behaviour and is not re-implemented here. */
|
|
483
|
+
export async function setManagedBotAccessSettings(
|
|
484
|
+
managingBotToken: string,
|
|
485
|
+
userId: number,
|
|
486
|
+
isAccessRestricted: boolean,
|
|
487
|
+
addedUserIds: number[] | undefined,
|
|
488
|
+
fetchImpl: typeof fetch = fetch,
|
|
489
|
+
): Promise<{ ok: boolean; error?: string }> {
|
|
490
|
+
if (addedUserIds && addedUserIds.length > MAX_ADDED_USER_IDS) {
|
|
491
|
+
return { ok: false, error: "too-many-added-user-ids" };
|
|
492
|
+
}
|
|
493
|
+
const r = await call(
|
|
494
|
+
managingBotToken,
|
|
495
|
+
MANAGED_BOT_METHODS.accessWrite,
|
|
496
|
+
{
|
|
497
|
+
user_id: userId,
|
|
498
|
+
is_access_restricted: isAccessRestricted,
|
|
499
|
+
...(addedUserIds ? { added_user_ids: addedUserIds } : {}),
|
|
500
|
+
},
|
|
501
|
+
fetchImpl,
|
|
502
|
+
);
|
|
503
|
+
return r.ok ? { ok: true } : { ok: false, error: r.error };
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** The managing bot's own `getMe`, for the one field that gates provisioning.
|
|
507
|
+
* A bot without `can_manage_bots` cannot offer the request button at all, and
|
|
508
|
+
* the switch lives in the @BotFather Mini App rather than behind any API call. */
|
|
509
|
+
export async function botCanManageBots(
|
|
510
|
+
botToken: string,
|
|
511
|
+
fetchImpl: typeof fetch = fetch,
|
|
512
|
+
): Promise<{ ok: true; canManageBots: boolean; username: string } | { ok: false; error: string }> {
|
|
513
|
+
try {
|
|
514
|
+
const res = await fetchImpl(`${TELEGRAM_API}/bot${botToken}/getMe`);
|
|
515
|
+
const data = (await res.json()) as {
|
|
516
|
+
ok: boolean;
|
|
517
|
+
result?: TelegramManagedUser;
|
|
518
|
+
description?: string;
|
|
519
|
+
};
|
|
520
|
+
if (!data.ok) return { ok: false, error: data.description ?? "getMe failed" };
|
|
521
|
+
return {
|
|
522
|
+
ok: true,
|
|
523
|
+
canManageBots: data.result?.can_manage_bots === true,
|
|
524
|
+
username: data.result?.username ?? "unknown",
|
|
525
|
+
};
|
|
526
|
+
} catch (e) {
|
|
527
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
528
|
+
}
|
|
529
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is this a channel key that can safely become a path segment?
|
|
3
|
+
*
|
|
4
|
+
* Both halves of an admin key are Telegram numeric ids (a bot id is positive; a
|
|
5
|
+
* chat or sender id is an integer and is negative for groups), so requiring
|
|
6
|
+
* exactly that is both the truthful shape check and a complete traversal guard:
|
|
7
|
+
* no `.`, `/` or `\` can survive it.
|
|
8
|
+
*
|
|
9
|
+
* Task 2615 — the business shape `<botId>:biz:<senderId>` joins the guard rather
|
|
10
|
+
* than bypassing it. Both alternatives are anchored and admit only digits, an
|
|
11
|
+
* optional leading minus and the literal `biz`, so neither can carry a `.`, `/`
|
|
12
|
+
* or `\` either.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isStorableChannelKey(channelKey: string): boolean;
|
|
15
|
+
/** Task 2615 — is this the three-part business shape?
|
|
16
|
+
*
|
|
17
|
+
* Its own predicate rather than a `.includes(':biz:')` at each caller: a
|
|
18
|
+
* business conversation is reached through the business-connection send route
|
|
19
|
+
* and its 24-hour window, not by addressing a chat id, so anything that answers
|
|
20
|
+
* "can we message this person now" has to be able to tell the two apart. */
|
|
21
|
+
export declare function isBusinessChannelKey(channelKey: string): boolean;
|
|
22
|
+
/** The filename stem for a channel key.
|
|
23
|
+
*
|
|
24
|
+
* Throws on a key that is neither two numeric ids nor the business shape.
|
|
25
|
+
* Refusing loudly is correct here: every caller reaches this with a key it has
|
|
26
|
+
* already validated, so an unstorable key means a caller skipped its guard, and
|
|
27
|
+
* silently sanitising it would build a path nobody asked for. */
|
|
28
|
+
export declare function channelKeyToFileStem(channelKey: string): string;
|
|
29
|
+
/** The inverse of `channelKeyToFileStem`.
|
|
30
|
+
*
|
|
31
|
+
* Task 2615 — a stem whose second segment is exactly `biz` is a three-part
|
|
32
|
+
* business key. Otherwise only the FIRST `_` is a separator, because both halves
|
|
33
|
+
* of an admin key are numeric Telegram ids and nothing later in that stem is
|
|
34
|
+
* one. */
|
|
35
|
+
export declare function fileStemToChannelKey(stem: string): string;
|
|
36
|
+
/** One registered bot, as much of it as reachability needs. `adminUsers` is
|
|
37
|
+
* present on an admin entry only; absent reads as none. */
|
|
38
|
+
export interface ReachBotInput {
|
|
39
|
+
id: string;
|
|
40
|
+
role: string;
|
|
41
|
+
adminUsers?: number[];
|
|
42
|
+
}
|
|
43
|
+
export interface ReachChat {
|
|
44
|
+
/** Null for an adminUsers entry that has never messaged: there is no chat. */
|
|
45
|
+
chatId: string | null;
|
|
46
|
+
senderId: string;
|
|
47
|
+
/** From the newest inbound row. Null when that row carried no name, and null
|
|
48
|
+
* for a sender who has never messaged. */
|
|
49
|
+
displayName: string | null;
|
|
50
|
+
/** ISO 8601 of the newest inbound row; null means never messaged. */
|
|
51
|
+
lastInbound: string | null;
|
|
52
|
+
/** This sender is an adminUsers entry on this bot. Allowlisted is a DIFFERENT
|
|
53
|
+
* fact from having started the chat, which is why both are carried. */
|
|
54
|
+
admin: boolean;
|
|
55
|
+
/** True exactly when `lastInbound` is non-null. */
|
|
56
|
+
reachable: boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface ReachBot {
|
|
59
|
+
botId: string;
|
|
60
|
+
role: string;
|
|
61
|
+
adminUsers: number[];
|
|
62
|
+
/** Reachable chats newest first, then never-messaged admins in listed order. */
|
|
63
|
+
chats: ReachChat[];
|
|
64
|
+
}
|
|
65
|
+
export interface ReachResult {
|
|
66
|
+
bots: ReachBot[];
|
|
67
|
+
/** Message rows this call actually read, across EVERY conversation file in the
|
|
68
|
+
* directory — including files belonging to a bot the caller did not name.
|
|
69
|
+
* That is deliberate: `chats=0` with `storeRows>0` is then the signature of a
|
|
70
|
+
* wrong bot list or a wrong account scope, which is the failure this number
|
|
71
|
+
* exists to expose. */
|
|
72
|
+
storeRows: number;
|
|
73
|
+
}
|
|
74
|
+
/** Reachability for one account: every registered bot, the private chats that
|
|
75
|
+
* have messaged it, and the allowlisted people who have not. */
|
|
76
|
+
export declare function collectTelegramReach(input: {
|
|
77
|
+
storeDir: string;
|
|
78
|
+
bots: ReachBotInput[];
|
|
79
|
+
}): ReachResult;
|
|
80
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAwBA;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED;;;;;6EAK6E;AAC7E,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED;;;;;kEAKkE;AAClE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAQ/D;AAED;;;;;WAKW;AACX,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED;4DAC4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,8EAA8E;IAC9E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB;+CAC2C;IAC3C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,qEAAqE;IACrE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;4EACwE;IACxE,KAAK,EAAE,OAAO,CAAC;IACf,mDAAmD;IACnD,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,gFAAgF;IAChF,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB;;;;4BAIwB;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AA+FD;iEACiE;AACjE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,aAAa,EAAE,CAAC;CACvB,GAAG,WAAW,CAsCd"}
|