@rubytech/create-maxy-code 0.1.546 → 0.1.548
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/dist/index.js +14 -0
- package/package.json +1 -1
- package/payload/platform/lib/routine-templates/dist/index.d.ts +22 -16
- package/payload/platform/lib/routine-templates/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/dist/index.js +15 -10
- package/payload/platform/lib/routine-templates/dist/index.js.map +1 -1
- package/payload/platform/lib/routine-templates/dist/roster.d.ts +3 -3
- package/payload/platform/lib/routine-templates/dist/roster.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/src/__tests__/seed.test.ts +15 -11
- package/payload/platform/lib/routine-templates/src/index.ts +23 -17
- package/payload/platform/lib/routine-templates/src/roster.ts +3 -3
- package/payload/platform/plugins/admin/mcp/dist/index.js +32 -16
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-default-agent.d.ts +16 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-default-agent.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-default-agent.js +21 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-default-agent.js.map +1 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +78 -33
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +11 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +63 -8
- package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +14 -24
- package/payload/platform/plugins/scheduling/PLUGIN.md +6 -0
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +6 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js +109 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.js +54 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts +31 -0
- 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 +116 -2
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.d.ts +17 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.js +43 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.js +87 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.js +123 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +36 -0
- 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 +89 -0
- 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 +13 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.d.ts +35 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.js +56 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +3 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.js +80 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts +2 -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 +19 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
- package/payload/platform/plugins/telegram/PLUGIN.md +2 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js +47 -47
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.d.ts +16 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.js +50 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.d.ts +8 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.js +12 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.js.map +1 -0
- package/payload/platform/plugins/telegram/references/setup-guide.md +2 -0
- package/payload/platform/plugins/telegram/skills/configure/SKILL.md +6 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +0 -6
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +2 -34
- package/payload/platform/plugins/whatsapp/mcp/dist/index.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 +0 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +8 -3
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +10 -3
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/server.js +1 -1
- package/payload/platform/services/telegram-channel/dist/server.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/turn-follow.js +33 -1
- package/payload/platform/services/telegram-channel/dist/turn-follow.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +8 -3
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +10 -3
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.js +33 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +42 -20
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +44 -27
- 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 +13 -5
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +6 -4
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.js +17 -6
- package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.js +34 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.js.map +1 -1
- package/payload/server/{chunk-CVUSUNXM.js → chunk-G6ULACHG.js} +2 -4
- package/payload/server/{chunk-X2RRMHVV.js → chunk-JOVREC6E.js} +117 -1
- package/payload/server/{chunk-DU7GPDJJ.js → chunk-SKYZG6OT.js} +15 -0
- package/payload/server/{manager-TI2YJQVZ.js → manager-2VEJKVEO.js} +2 -2
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/public/activity.html +5 -5
- package/payload/server/public/agents.html +4 -4
- package/payload/server/public/assets/{AdminLoginScreens-BGKtDqAk.js → AdminLoginScreens-Bjcs9ta9.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-Bjcs9ta9.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-Bjcs9ta9.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-DnfgsAQl.js → AdminShell-DVBAMUCy.js} +1 -1
- package/payload/server/public/assets/AdminShell-DVBAMUCy.js.br +0 -0
- package/payload/server/public/assets/{AdminShell-DnfgsAQl.js.gz → AdminShell-DVBAMUCy.js.gz} +0 -0
- package/payload/server/public/assets/{activity-ByJSut0Q.js → activity-C8E8-EwQ.js} +1 -1
- package/payload/server/public/assets/activity-C8E8-EwQ.js.br +0 -0
- package/payload/server/public/assets/activity-C8E8-EwQ.js.gz +0 -0
- package/payload/server/public/assets/{admin-CkeJO6kA.js → admin-CeWAlpRS.js} +1 -1
- package/payload/server/public/assets/admin-CeWAlpRS.js.br +0 -0
- package/payload/server/public/assets/admin-CeWAlpRS.js.gz +0 -0
- package/payload/server/public/assets/{agents-D8phtRX5.js → agents-DuN92iFb.js} +1 -1
- package/payload/server/public/assets/agents-DuN92iFb.js.br +0 -0
- package/payload/server/public/assets/agents-DuN92iFb.js.gz +0 -0
- package/payload/server/public/assets/{browser-DQSTjdom.js → browser-BxebdKbh.js} +1 -1
- package/payload/server/public/assets/browser-BxebdKbh.js.br +0 -0
- package/payload/server/public/assets/browser-BxebdKbh.js.gz +0 -0
- package/payload/server/public/assets/{calendar-DFJu1XjP.js → calendar-BtFZQ5Np.js} +1 -1
- package/payload/server/public/assets/calendar-BtFZQ5Np.js.br +0 -0
- package/payload/server/public/assets/calendar-BtFZQ5Np.js.gz +0 -0
- package/payload/server/public/assets/chat-CGIwynaH.js +1 -0
- package/payload/server/public/assets/chat-CGIwynaH.js.br +3 -0
- package/payload/server/public/assets/chat-CGIwynaH.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-DaNP1zDb.js +1 -0
- package/payload/server/public/assets/chevron-left-DaNP1zDb.js.br +0 -0
- package/payload/server/public/assets/chevron-right-BbbuTUnt.js +1 -0
- package/payload/server/public/assets/chevron-right-BbbuTUnt.js.br +0 -0
- package/payload/server/public/assets/clock-CfDdatjp.js +1 -0
- package/payload/server/public/assets/clock-CfDdatjp.js.br +0 -0
- package/payload/server/public/assets/clock-CfDdatjp.js.gz +0 -0
- package/payload/server/public/assets/{copy-lFFhXRGk.js → copy-DCDHXq3O.js} +1 -1
- package/payload/server/public/assets/copy-DCDHXq3O.js.br +0 -0
- package/payload/server/public/assets/copy-DCDHXq3O.js.gz +0 -0
- package/payload/server/public/assets/data-BchSWOju.js +1 -0
- package/payload/server/public/assets/data-BchSWOju.js.br +1 -0
- package/payload/server/public/assets/data-BchSWOju.js.gz +0 -0
- package/payload/server/public/assets/{file-text-D2Y-bkNy.js → file-text-zQgEQWCF.js} +1 -1
- package/payload/server/public/assets/file-text-zQgEQWCF.js.br +0 -0
- package/payload/server/public/assets/file-text-zQgEQWCF.js.gz +0 -0
- package/payload/server/public/assets/{graph-C-3yN6JD.js → graph-CFCEh_YI.js} +1 -1
- package/payload/server/public/assets/graph-CFCEh_YI.js.br +0 -0
- package/payload/server/public/assets/graph-CFCEh_YI.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-DiaPLP27.js → graph-labels-CA1UcDuS.js} +1 -1
- package/payload/server/public/assets/graph-labels-CA1UcDuS.js.br +0 -0
- package/payload/server/public/assets/graph-labels-CA1UcDuS.js.gz +0 -0
- package/payload/server/public/assets/{operator-KuGPvSa9.js → operator-hFXPDc2X.js} +1 -1
- package/payload/server/public/assets/operator-hFXPDc2X.js.br +0 -0
- package/payload/server/public/assets/operator-hFXPDc2X.js.gz +0 -0
- package/payload/server/public/assets/{page-BhGeFXWA.js → page-C8jyPH_3.js} +1 -1
- package/payload/server/public/assets/page-C8jyPH_3.js.br +0 -0
- package/payload/server/public/assets/page-C8jyPH_3.js.gz +0 -0
- package/payload/server/public/assets/{page-EnbVC-yM.js → page-ne7I_r9L.js} +1 -1
- package/payload/server/public/assets/page-ne7I_r9L.js.br +0 -0
- package/payload/server/public/assets/page-ne7I_r9L.js.gz +0 -0
- package/payload/server/public/assets/play-Ep0SZTbr.js +1 -0
- package/payload/server/public/assets/play-Ep0SZTbr.js.br +0 -0
- package/payload/server/public/assets/play-Ep0SZTbr.js.gz +0 -0
- package/payload/server/public/assets/{public-CdSgMNC7.js → public-BgnqjAal.js} +1 -1
- package/payload/server/public/assets/public-BgnqjAal.js.br +0 -0
- package/payload/server/public/assets/public-BgnqjAal.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-rTRuTqei.js → rotate-ccw-DfJWjXAg.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-DfJWjXAg.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-DfJWjXAg.js.gz +0 -0
- package/payload/server/public/assets/routines-OGFXwTFO.js +2 -0
- package/payload/server/public/assets/routines-OGFXwTFO.js.br +0 -0
- package/payload/server/public/assets/routines-OGFXwTFO.js.gz +0 -0
- package/payload/server/public/assets/{skills-DFWtZNkW.js → skills-D-6EbgfP.js} +1 -1
- package/payload/server/public/assets/skills-D-6EbgfP.js.br +0 -0
- package/payload/server/public/assets/skills-D-6EbgfP.js.gz +0 -0
- package/payload/server/public/assets/{tasks-B94AuKSy.js → tasks-DnN5Fyds.js} +1 -1
- package/payload/server/public/assets/tasks-DnN5Fyds.js.br +0 -0
- package/payload/server/public/assets/tasks-DnN5Fyds.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-DtWUg6jR.js → triangle-alert-eh9UOKDT.js} +1 -1
- package/payload/server/public/assets/triangle-alert-eh9UOKDT.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-eh9UOKDT.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-CjKYO-Qf.js → useCopyFeedback-Bz9OJHBb.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-Bz9OJHBb.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-Bz9OJHBb.js.gz +0 -0
- package/payload/server/public/assets/{useMediaQuery-DlOWP56H.css → useMediaQuery-CNxsjKZp.css} +1 -1
- package/payload/server/public/assets/useMediaQuery-CNxsjKZp.css.br +0 -0
- package/payload/server/public/assets/{useMediaQuery-DlOWP56H.css.gz → useMediaQuery-CNxsjKZp.css.gz} +0 -0
- package/payload/server/public/assets/{useVoiceRecorder-BKFAYuzz.js → useVoiceRecorder-BaDpMYxX.js} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-BaDpMYxX.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BaDpMYxX.js.gz +0 -0
- package/payload/server/public/assets/{wrench-Ct4kf-uv.js → wrench-BO-l46rF.js} +1 -1
- package/payload/server/public/assets/wrench-BO-l46rF.js.br +0 -0
- package/payload/server/public/assets/wrench-BO-l46rF.js.gz +0 -0
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +8 -8
- package/payload/server/public/chat.html +13 -13
- package/payload/server/public/data.html +11 -11
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +14 -14
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/routines.html +6 -6
- package/payload/server/public/skills.html +5 -5
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +330 -520
- package/payload/server/public/assets/AdminLoginScreens-BGKtDqAk.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-BGKtDqAk.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-DnfgsAQl.js.br +0 -0
- package/payload/server/public/assets/activity-ByJSut0Q.js.br +0 -0
- package/payload/server/public/assets/activity-ByJSut0Q.js.gz +0 -0
- package/payload/server/public/assets/admin-CkeJO6kA.js.br +0 -0
- package/payload/server/public/assets/admin-CkeJO6kA.js.gz +0 -0
- package/payload/server/public/assets/agents-D8phtRX5.js.br +0 -0
- package/payload/server/public/assets/agents-D8phtRX5.js.gz +0 -0
- package/payload/server/public/assets/browser-DQSTjdom.js.br +0 -0
- package/payload/server/public/assets/browser-DQSTjdom.js.gz +0 -0
- package/payload/server/public/assets/calendar-DFJu1XjP.js.br +0 -0
- package/payload/server/public/assets/calendar-DFJu1XjP.js.gz +0 -0
- package/payload/server/public/assets/chat-DUqtIsOt.js +0 -1
- package/payload/server/public/assets/chat-DUqtIsOt.js.br +0 -0
- package/payload/server/public/assets/chat-DUqtIsOt.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-DFK18xVX.js +0 -1
- package/payload/server/public/assets/chevron-left-DFK18xVX.js.br +0 -0
- package/payload/server/public/assets/chevron-right-DJ4oaHoN.js +0 -1
- package/payload/server/public/assets/chevron-right-DJ4oaHoN.js.br +0 -0
- package/payload/server/public/assets/clock-wHIan2DW.js +0 -1
- package/payload/server/public/assets/clock-wHIan2DW.js.br +0 -0
- package/payload/server/public/assets/copy-lFFhXRGk.js.br +0 -0
- package/payload/server/public/assets/copy-lFFhXRGk.js.gz +0 -0
- package/payload/server/public/assets/data-Cxv97ARy.js +0 -1
- package/payload/server/public/assets/data-Cxv97ARy.js.br +0 -0
- package/payload/server/public/assets/data-Cxv97ARy.js.gz +0 -0
- package/payload/server/public/assets/file-text-D2Y-bkNy.js.br +0 -0
- package/payload/server/public/assets/file-text-D2Y-bkNy.js.gz +0 -0
- package/payload/server/public/assets/graph-C-3yN6JD.js.br +0 -0
- package/payload/server/public/assets/graph-C-3yN6JD.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-DiaPLP27.js.br +0 -0
- package/payload/server/public/assets/graph-labels-DiaPLP27.js.gz +0 -0
- package/payload/server/public/assets/operator-KuGPvSa9.js.br +0 -0
- package/payload/server/public/assets/operator-KuGPvSa9.js.gz +0 -0
- package/payload/server/public/assets/page-BhGeFXWA.js.br +0 -0
- package/payload/server/public/assets/page-BhGeFXWA.js.gz +0 -0
- package/payload/server/public/assets/page-EnbVC-yM.js.br +0 -0
- package/payload/server/public/assets/page-EnbVC-yM.js.gz +0 -0
- package/payload/server/public/assets/play-jZFZAG-t.js +0 -1
- package/payload/server/public/assets/play-jZFZAG-t.js.br +0 -0
- package/payload/server/public/assets/play-jZFZAG-t.js.gz +0 -0
- package/payload/server/public/assets/public-CdSgMNC7.js.br +0 -0
- package/payload/server/public/assets/public-CdSgMNC7.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-rTRuTqei.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-rTRuTqei.js.gz +0 -0
- package/payload/server/public/assets/routines-DNRxNRSQ.js +0 -2
- package/payload/server/public/assets/routines-DNRxNRSQ.js.br +0 -0
- package/payload/server/public/assets/routines-DNRxNRSQ.js.gz +0 -0
- package/payload/server/public/assets/skills-DFWtZNkW.js.br +0 -0
- package/payload/server/public/assets/skills-DFWtZNkW.js.gz +0 -0
- package/payload/server/public/assets/tasks-B94AuKSy.js.br +0 -0
- package/payload/server/public/assets/tasks-B94AuKSy.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-DtWUg6jR.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-DtWUg6jR.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-CjKYO-Qf.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-CjKYO-Qf.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-DlOWP56H.css.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BKFAYuzz.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BKFAYuzz.js.gz +0 -0
- package/payload/server/public/assets/wrench-Ct4kf-uv.js.br +0 -0
- package/payload/server/public/assets/wrench-Ct4kf-uv.js.gz +0 -0
- /package/payload/server/public/assets/{useMediaQuery-BYIHo-xL.js → useMediaQuery-_mMln3Fu.js} +0 -0
- /package/payload/server/public/assets/{useMediaQuery-BYIHo-xL.js.br → useMediaQuery-_mMln3Fu.js.br} +0 -0
- /package/payload/server/public/assets/{useMediaQuery-BYIHo-xL.js.gz → useMediaQuery-_mMln3Fu.js.gz} +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type DefaultAgentRefusal = "shape" | "not-found";
|
|
2
|
+
export type DefaultAgentVerdict = {
|
|
3
|
+
ok: true;
|
|
4
|
+
slug: string;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
reason: DefaultAgentRefusal;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Decide whether a submitted `defaultAgent` value may be stored. An empty or
|
|
11
|
+
* whitespace-only value is the clear operation and is accepted as `slug: ""`.
|
|
12
|
+
* Shape is decided before existence, so a traversal value is refused as
|
|
13
|
+
* `shape` however many real files sit at the end of it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function checkDefaultAgent(accountDir: string, value: string): DefaultAgentVerdict;
|
|
16
|
+
//# sourceMappingURL=account-default-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-default-agent.d.ts","sourceRoot":"","sources":["../../src/tools/account-default-agent.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,WAAW,CAAC;AAExD,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,mBAAmB,CAQxF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { AGENT_SLUG_PATTERN } from "../../../../../lib/agent-slug/dist/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Decide whether a submitted `defaultAgent` value may be stored. An empty or
|
|
6
|
+
* whitespace-only value is the clear operation and is accepted as `slug: ""`.
|
|
7
|
+
* Shape is decided before existence, so a traversal value is refused as
|
|
8
|
+
* `shape` however many real files sit at the end of it.
|
|
9
|
+
*/
|
|
10
|
+
export function checkDefaultAgent(accountDir, value) {
|
|
11
|
+
const slug = value.trim();
|
|
12
|
+
if (!slug)
|
|
13
|
+
return { ok: true, slug: "" };
|
|
14
|
+
if (!AGENT_SLUG_PATTERN.test(slug))
|
|
15
|
+
return { ok: false, reason: "shape" };
|
|
16
|
+
if (!existsSync(join(accountDir, "agents", slug, "config.json"))) {
|
|
17
|
+
return { ok: false, reason: "not-found" };
|
|
18
|
+
}
|
|
19
|
+
return { ok: true, slug };
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=account-default-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-default-agent.js","sourceRoot":"","sources":["../../src/tools/account-default-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AAqBjF;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB,EAAE,KAAa;IACjE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACzC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC1E,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC;QACjE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
-
content-hash: sha256:
|
|
4
|
+
content-hash: sha256:db7c14326a115e7d05b687b72bef0ba3892f1614ee46484e0e90414bf2c16f27
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -1686,15 +1686,13 @@ Two questions an agent cannot answer from inside itself, and both have caused re
|
|
|
1686
1686
|
|
|
1687
1687
|
## What wakes a session
|
|
1688
1688
|
|
|
1689
|
-
|
|
1689
|
+
Four things start or resume a WhatsApp session. They are distinguishable, and the distinction matters, because one of them is written by the platform rather than by the person named as the sender.
|
|
1690
1690
|
|
|
1691
1691
|
**An admin phone or an account manager messages the line.** This resumes that person's own admin session. There is no per-account admin session: the session id is a hash of the account plus the person, so one person messaging from two channels resumes one thread, and two managers on one account have two threads.
|
|
1692
1692
|
|
|
1693
|
-
**A public sender messages the line.**
|
|
1693
|
+
**A public sender messages the line.** One thing follows: the account's public agent answers the visitor, if the account has one and has enabled it. If not, the message is stored and labelled and the visitor receives nothing at all.
|
|
1694
1694
|
|
|
1695
|
-
|
|
1696
|
-
2. Every bound manager's own admin session is woken with a `public-relay` turn carrying the sender's message as fenced content. This is the carrier for anything the account needs to do about the visitor: translate, put a request to a registered counterparty, carry the answer back.
|
|
1697
|
-
3. The account's public agent answers the visitor, if the account has one and has enabled it. If not, the visitor receives nothing at all, and steps 1 and 2 have already happened regardless.
|
|
1695
|
+
Nobody is told the visitor wrote. The platform used to notify the registered managers and to wake each of them with a relay turn; both were retired, because telling the operator a stranger wrote in is a scheduled routine's job. A routine chooses its own recipient, its own wording and its own transport, and an account that wants no such message simply does not run one.
|
|
1698
1696
|
|
|
1699
1697
|
**The scheduler fires a due event.** This raises a `schedule` turn on the destination's own session, carrying the event's prompt.
|
|
1700
1698
|
|
|
@@ -1702,19 +1700,16 @@ Five things start or resume a WhatsApp session. They are distinguishable, and th
|
|
|
1702
1700
|
|
|
1703
1701
|
## Reading why you woke
|
|
1704
1702
|
|
|
1705
|
-
Every turn carries a `source`.
|
|
1703
|
+
Every turn carries a `source`. Two values exist:
|
|
1706
1704
|
|
|
1707
1705
|
| `source` | Meaning |
|
|
1708
1706
|
|---|---|
|
|
1709
1707
|
| `user` | A real person sent this message to the line. Also the value when the field is absent. |
|
|
1710
1708
|
| `schedule` | The scheduler wrote this turn. The named destination did not send it. |
|
|
1711
|
-
| `public-relay` | The platform wrote this turn because a public visitor messaged the account. The named sender is a manager being told, not someone who wrote to you. |
|
|
1712
1709
|
|
|
1713
|
-
**A
|
|
1710
|
+
**A public visitor's turn is the one turn whose `## Instruction` block is the account's own.** Its body is `agents/<slug>/INSTRUCTION.md`, written by the account owner, where `<slug>` is the public agent answering. If that file is missing the turn is refused outright, so the visitor is not answered rather than being handed platform prose the account cannot edit. Every turn you authored, from your own handset or through the scheduler, takes the platform's own directive and never reads that file, so it can never be refused over a file it does not use.
|
|
1714
1711
|
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
**On a `public-relay` turn the reply tool is the only way to reach anyone.** On an ordinary turn the platform forwards your closing text to the sender when you called no reply tool. On a relay-woken turn it does not, because the relay carries its own reply path. So whatever you decide the manager should receive has to go through the reply tool; text you merely write at the end of the turn reaches nobody, and a decision not to reply is silence rather than a message.
|
|
1712
|
+
On every turn on this line the platform forwards your closing text to the sender when you called no reply tool, so a turn that ends with an answer written but no tool called still reaches the person waiting.
|
|
1718
1713
|
|
|
1719
1714
|
## Which files compose the prompt
|
|
1720
1715
|
|
|
@@ -1725,25 +1720,22 @@ The system prompt is assembled per spawn from one agent directory, and **which d
|
|
|
1725
1720
|
|
|
1726
1721
|
From that one directory it takes `IDENTITY.md` and `SOUL.md`, verbatim.
|
|
1727
1722
|
|
|
1728
|
-
The consequence catches people out: **an instruction written into `agents/admin/SOUL.md` is never read by a public spawn**, and an instruction written into a public agent's `SOUL.md` is never read by an admin turn. Before writing an instruction into a role file, decide which role will actually be running when it needs to apply.
|
|
1723
|
+
The consequence catches people out: **an instruction written into `agents/admin/SOUL.md` is never read by a public spawn**, and an instruction written into a public agent's `SOUL.md` is never read by an admin turn. Before writing an instruction into a role file, decide which role will actually be running when it needs to apply. A stranger's message wakes the public agent and nothing else, so an instruction meant to govern what happens when a stranger writes belongs in that agent's own files, never in `agents/admin/`.
|
|
1729
1724
|
|
|
1730
1725
|
A public agent's directory also carries `KNOWLEDGE.md` and `config.json`. An account can hold as many public agents as it likes; only one is bound to WhatsApp at a time, and that binding is per account.
|
|
1731
1726
|
|
|
1732
1727
|
## The switches, and what each one stops
|
|
1733
1728
|
|
|
1734
|
-
|
|
1729
|
+
Four settings sit on this path. They are not interchangeable, and reaching for the wrong one is how an operator ends up silencing more than they meant.
|
|
1735
1730
|
|
|
1736
1731
|
| Setting | What it stops | What it leaves running |
|
|
1737
1732
|
|---|---|---|
|
|
1738
1733
|
| `dmPolicy: disabled` | Public senders are refused at the gate. | Admin and manager inbound. |
|
|
1739
|
-
| `publicAgentEnabled: false` | The visitor gets no reply. |
|
|
1740
|
-
| `managerNotifyEnabled: false` | The verbatim copy of the visitor's message. | The relay, and any reply the woken turn sends. |
|
|
1734
|
+
| `publicAgentEnabled: false` | The visitor gets no reply. | Storage and labelling of what the visitor sent. |
|
|
1741
1735
|
| `dispatchInbound: false` | Every agent turn on that account's socket. | Storage: messages are still stored and readable. |
|
|
1742
|
-
| `dispatch: false` on one registered party | The public-agent turn for that one phone. | Everything else: storage, the label,
|
|
1743
|
-
|
|
1744
|
-
`managerNotifyEnabled` is the fine-grained one, and the one to reach for when the notifications are unwanted but the work is not. Unbinding a manager is not a substitute: the manager registry is shared by the notification, the relay and `whatsapp-notify-manager`, so unbinding silences all three.
|
|
1736
|
+
| `dispatch: false` on one registered party | The public-agent turn for that one phone. | Everything else: storage, the label, and every other sender on the line. |
|
|
1745
1737
|
|
|
1746
|
-
|
|
1738
|
+
None of these governs whether the operator hears about a visitor, because no setting does: that is a scheduled routine's job, and the way to stop it is to stop the routine. The manager registry is read by nothing on this path at all, so unbinding a manager changes nothing a visitor's message does.
|
|
1747
1739
|
|
|
1748
1740
|
## When the answer is not here
|
|
1749
1741
|
|
|
@@ -1753,16 +1745,14 @@ Read the current value with `whatsapp-config {action:'get-manager-notify-enabled
|
|
|
1753
1745
|
[whatsapp:wire] op=stanza msgId=<id>
|
|
1754
1746
|
[wa-notify] op=eligible msgId=<id> reason=<how the sender was admitted>
|
|
1755
1747
|
[whatsapp:route] op=routed inboundId=<id> msgIds=<the stanzas this payload covers>
|
|
1756
|
-
[whatsapp:notify] op=public-inbound inboundId=<id> enabled=0|1 outcome=sent|failed|no-recipients|disabled
|
|
1757
|
-
[whatsapp:relay] op=dispatch inboundId=<id> outcome=sent|failed|no-recipients
|
|
1758
1748
|
[whatsapp:party] op=dispatch-decision inboundId=<id> party=… dispatch=true|false spawned=0|1 (labelled senders only)
|
|
1759
1749
|
[whatsapp:public-agent] op=route inboundId=<id> enabled=… slug=… spawned=0|1
|
|
1760
1750
|
[whatsapp:public-agent] op=spawn-ok | op=spawn-failed inboundId=<id>
|
|
1761
1751
|
```
|
|
1762
1752
|
|
|
1763
|
-
Follow one inbound by its `inboundId`. That selects the last
|
|
1753
|
+
Follow one inbound by its `inboundId`. That selects the last four lines and nothing else, however many visitors messaged in the same window. For the first two, read `msgIds=` off the `op=routed` line and grep one of those ids. Two greps rather than one, because the debouncer merges stanzas into a single routed payload and the two halves are keyed either side of that merge.
|
|
1764
1754
|
|
|
1765
|
-
Anything that failed carries the same id: the drop lines
|
|
1755
|
+
Anything that failed carries the same id: the drop lines and `op=spawn-failed`. Fewer lines than expected, with none of them a failure, means a step emitted nothing at all — which is what the standing audits below are for.
|
|
1766
1756
|
|
|
1767
1757
|
Do not try to follow an inbound by its sender. `sender=` appears on two of these lines, and the same visitor is a LID on `op=stanza` and an E.164 on `op=routed`, so no sender-based filter spans the merge.
|
|
1768
1758
|
|
|
@@ -1777,7 +1767,7 @@ op=startup-watch state=disposed
|
|
|
1777
1767
|
|
|
1778
1768
|
The first-run dialog is answered for the session, and the watcher that guards against an *unanswered* one drops what it saw before that answer. `bufferCleared=false` means the confirm fired and the drop did not, which is the shape that killed a resumed spawn on 2026-08-01: the answered dialog's own footer stayed in the buffer, the replayed transcript slid past it, and the spawn was blocked by a line the agent itself had written the day before.
|
|
1779
1769
|
|
|
1780
|
-
|
|
1770
|
+
Two standing audits reconcile that chain rather than waiting for someone to notice. `op=public-notify-reconcile` reports `routed` against `answered`, so a visitor routed to an agent that never replied shows as `answerGap`. `op=spawn-census` reports attempts against successes. A non-zero gap, or attempts with no successes, is a fault even when nothing has been reported.
|
|
1781
1771
|
|
|
1782
1772
|
---
|
|
1783
1773
|
# Settings
|
|
@@ -3494,13 +3484,27 @@ The Routines surface (`/routines`) is the admin view of the account's
|
|
|
3494
3484
|
automation `:Event` nodes — the device's scheduled agent turns and tool
|
|
3495
3485
|
dispatches, which the Calendar surface deliberately excludes (`calendar.ts`
|
|
3496
3486
|
unions only appointment events, `actionPlugin IS NULL`). It renders one card per
|
|
3497
|
-
routine (title,
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3487
|
+
routine (title, its one-line description where it has one, human-readable
|
|
3488
|
+
schedule, next run, channel/destination or tool, status); a card opens a detail
|
|
3489
|
+
modal modeled on the calendar `EventDetailModal`. A shipped routine is seeded with
|
|
3490
|
+
a description and the operator can rewrite it from the modal; a routine nobody has
|
|
3491
|
+
captioned renders with no line and no placeholder. Editing it stamps the row
|
|
3492
|
+
operator-owned, so the next roster refresh leaves the operator's wording alone,
|
|
3493
|
+
and recomputes the row's search vector, which is built from the name and the
|
|
3494
|
+
description. A description is never dispatched: `agentPrompt` is the only text a
|
|
3495
|
+
fire sends.
|
|
3496
|
+
The read-only view shows two prose blocks, each under its own heading, in the
|
|
3497
|
+
order **Description** then **Instruction sent to the agent**. Both use the same
|
|
3498
|
+
header-above-prose shape, so neither reads as a different kind of thing from the
|
|
3499
|
+
other. Before this the modal showed one unheaded block, so the caption and the
|
|
3500
|
+
multi-KB prompt that actually fires were indistinguishable. The instruction
|
|
3501
|
+
heading never reads the bare word "Instruction", in either mode: that collides
|
|
3502
|
+
with the `## Instruction` block the platform appends to every dispatched channel
|
|
3503
|
+
turn, and an agent read the two as the same field. The Description block renders
|
|
3504
|
+
on every kind of routine, including a tool-action routine and a bare trigger,
|
|
3505
|
+
because both already show it on the card; the instruction block belongs to an
|
|
3506
|
+
agent routine, the only kind that has one. The modal edits the description, the
|
|
3507
|
+
prose instruction (`agentPrompt`), the dispatch binding
|
|
3504
3508
|
(`agentChannel` and `agentDestination`, chosen from a server-supplied roster
|
|
3505
3509
|
rather than typed), and the schedule via a friendly builder (frequency
|
|
3506
3510
|
daily/weekly/monthly, day-of-week, day-of-month, time) that falls back to a
|
|
@@ -3521,6 +3525,29 @@ render it through one `RoutineStatusDot`, which is what stops them drifting:
|
|
|
3521
3525
|
| `cancelled`, `completed` | solid grey (`--text-tertiary`) | deliberately stopped or finished |
|
|
3522
3526
|
| anything else, and `null` | grey ring, no fill | no reading taken |
|
|
3523
3527
|
|
|
3528
|
+
**The run recap.** Each card carries a history icon that opens that routine's
|
|
3529
|
+
run history; the detail modal's **Runs** button reaches the same view. A run
|
|
3530
|
+
shows what it sent — the message text itself, on the row and in full in the run
|
|
3531
|
+
dialog — and a run that finished having sent nothing says so, which is a
|
|
3532
|
+
different statement from a run whose outcome is not yet known. Both the routine
|
|
3533
|
+
list and the run list have a Refresh control, because a run is promoted from
|
|
3534
|
+
"accepted" to "finished" by a background sweep a couple of minutes later. The
|
|
3535
|
+
**Download all runs** file carries the message text as its last column, so an
|
|
3536
|
+
export of a customer-facing routine contains what was said to customers.
|
|
3537
|
+
|
|
3538
|
+
The run's own dot answers a different question from the routine's:
|
|
3539
|
+
|
|
3540
|
+
| run status | dot | meaning |
|
|
3541
|
+
|---|---|---|
|
|
3542
|
+
| `finished` | green (`--session-live`) | it ran and its output was seen |
|
|
3543
|
+
| `open`, `accepted`, `started` | activity (`--color-alias-status-activity`) | in flight, or accepted with nothing yet known |
|
|
3544
|
+
| `no-destination` | amber (`--color-alias-status-warning-solid`) | it had nowhere to send |
|
|
3545
|
+
| `failed` | red (`--color-alias-status-error-solid`) | the dispatch failed |
|
|
3546
|
+
| anything else, and `null` | grey ring, no fill | no reading taken |
|
|
3547
|
+
|
|
3548
|
+
`app/routines/types.ts` holds both mappings and `RunStatusDot` is the only thing
|
|
3549
|
+
that paints the run one, so the row and the dialog cannot drift.
|
|
3550
|
+
|
|
3524
3551
|
The unrecognised case is a state of its own, never a fallback into green: `GET
|
|
3525
3552
|
/api/admin/routines` projects `eventStatus` verbatim, so a value outside the set
|
|
3526
3553
|
can reach the card at any time, and a stood-down routine showing green is a
|
|
@@ -3538,7 +3565,7 @@ The route (`server/routes/admin/routines.ts`) is account-scoped like `calendar.t
|
|
|
3538
3565
|
| `GET /api/admin/routines/:eventId` | One routine, same automation+account guard. |
|
|
3539
3566
|
| `GET /api/admin/routines/:eventId/runs` | One routine's `:RoutineRun` history, newest first. `limit` clamps to 1..500 and defaults to 50, so a caller that wants the full page must ask for it. |
|
|
3540
3567
|
| `GET /api/admin/routines/:eventId/runs.csv` | The same projection as a `text/csv` attachment with `Content-Disposition`, and **no** limit, so it is not the same row set as a clamped `/runs` call. Re-parses its own output and returns 500 rather than serving a document with fewer rows than the query returned. Zero rows is 404, not a header-only file: the query cannot tell a routine with no runs from an `eventId` on another account. |
|
|
3541
|
-
| `PATCH /api/admin/routines/:eventId` | Edits `agentPrompt`, `recurrence`, and the `agentChannel`/`agentDestination` pair. Cron validation and the timezone-aware `nextRun` recompute copy the scheduling plugin's `schedule-update` tool. The binding is revalidated against the same house-authority rule, shared as `platform/lib/agent-dispatch-rule`; it is refused `partial-binding`, `invalid-channel`, `no-prompt`, `not-registered`, `cross-account`, `action-routine` (a routine that runs a tool keeps it — an agent binding outranks the action at fire time) or `clear-would-orphan` (clearing the only field holding a one-time routine inside the automation filter would hide it from every routines surface), and no refusal writes. Both fields as `null` clears the binding. An invalid cron is rejected 400 with no write. Only creation and deletion stay agent-only (`schedule-event`/`schedule-cancel`). |
|
|
3568
|
+
| `PATCH /api/admin/routines/:eventId` | Edits `agentPrompt`, `description`, `recurrence`, and the `agentChannel`/`agentDestination` pair. A `description` write stamps `operatorEdited` and recomputes the row's `embedding` from `Event: <name>` plus the new text, reading the name from the row rather than the request body; the embedder returning nothing leaves the previous vector in place and the save still succeeds. A whitespace-only `description` is stored as null, so "no caption" is one state in the graph. Cron validation and the timezone-aware `nextRun` recompute copy the scheduling plugin's `schedule-update` tool. The binding is revalidated against the same house-authority rule, shared as `platform/lib/agent-dispatch-rule`; it is refused `partial-binding`, `invalid-channel`, `no-prompt`, `not-registered`, `cross-account`, `action-routine` (a routine that runs a tool keeps it — an agent binding outranks the action at fire time) or `clear-would-orphan` (clearing the only field holding a one-time routine inside the automation filter would hide it from every routines surface), and no refusal writes. Both fields as `null` clears the binding. An invalid cron is rejected 400 with no write. Only creation and deletion stay agent-only (`schedule-event`/`schedule-cancel`). |
|
|
3542
3569
|
| `GET /api/admin/dispatch-destinations` | Every destination the session's account may bind a routine to, across both channels, each labelled by the authoritative list it came from (`House admin`, `Account manager`, `Telegram admin`), plus an optional `name`: a display-only person name resolved from `:Person` in the row's own account scope — the house for a `House admin` row, the managed sub-account for an `Account manager` row, and never for Telegram, whose destinations are chat ids. Computed from the same lists the validator reads and filtered by the same rule, so the picker cannot offer what the save refuses; `name` is never part of what Save posts, and a graph outage returns an unnamed roster rather than an error. |
|
|
3543
3570
|
| `POST /api/admin/routines/:eventId/suspend` | Writes `eventStatus = 'suspended'` on a routine currently `'scheduled'`. 404s otherwise, so a second suspend is not a silent no-op. |
|
|
3544
3571
|
| `POST /api/admin/routines/:eventId/resume` | Returns a suspended routine to `'scheduled'`. 404s if it is not suspended, 409s if it cannot be resumed. |
|
|
@@ -3619,6 +3646,24 @@ would say so. `completed` gets its own bucket even though no code path writes it
|
|
|
3619
3646
|
today, because it remains part of the shipped enum and one row carrying it would
|
|
3620
3647
|
otherwise pin `other` above zero forever and kill the alarm.
|
|
3621
3648
|
|
|
3649
|
+
`[schedule-audit] op=description-coverage acct=<8> routines=<n>
|
|
3650
|
+
withDescription=<n> withInstruction=<n> toolActions=<n>` is the pair behind the
|
|
3651
|
+
two prose blocks the modal shows. A routine carrying an instruction and no
|
|
3652
|
+
description is a card whose title is all the operator gets; one carrying a
|
|
3653
|
+
description and no instruction is worse, because it looks explained, fires on
|
|
3654
|
+
schedule and sends nothing. Neither state writes an event of its own, so only a
|
|
3655
|
+
periodic count reveals them, and the counts sit on one line beside the total
|
|
3656
|
+
because any one of them alone answers the wrong question. `toolActions` is on the
|
|
3657
|
+
line because `withInstruction` is otherwise comparable to nothing: a tool-action
|
|
3658
|
+
routine has no instruction and is not silent, it runs a tool, so an account
|
|
3659
|
+
holding one would sit at `routines > withInstruction` for ever and the alarm
|
|
3660
|
+
would be dead from that point on. The genuinely silent count is `routines -
|
|
3661
|
+
toolActions - withInstruction`, the same reconciliation `other` performs in the
|
|
3662
|
+
suspension census. Emitted per account on every sweep tick including a healthy
|
|
3663
|
+
one, over the same automation set the routes list. The roster seed's own
|
|
3664
|
+
`descNull` counter is its narrow twin, scoped to seeded rows and so blind to
|
|
3665
|
+
exactly the operator-created ones most likely to carry no caption.
|
|
3666
|
+
|
|
3622
3667
|
**The shipped roster.** Every account starts with eleven routines —
|
|
3623
3668
|
`start-of-day`, `inbound-check`, `end-of-day`, `appointment-reminder`,
|
|
3624
3669
|
`commitment-chase`, `calendar-reconcile`, `contact-reconcile`, `crm-reconcile`,
|
|
@@ -9,6 +9,17 @@ Invoked by the admin agent directly.
|
|
|
9
9
|
|
|
10
10
|
This is the platform's release timeline, newest first. Each entry shows the date it shipped and the version it shipped in, so you can tell the operator how current their install is. To compare, read the installed version from `capabilities-here` and match it against the versions below. Keep answers high level and in plain English; this is a summary, not a full commit log.
|
|
11
11
|
|
|
12
|
+
## 2026-08-02 (0.1.548)
|
|
13
|
+
|
|
14
|
+
- Telegram now works per account: each bot has its own address and secret, a scheduled message goes to the right account, and a check reports any bot that is set up but never delivers.
|
|
15
|
+
- Every WhatsApp reply and document send now names the account it belongs to, and a send whose account does not match its conversation is refused.
|
|
16
|
+
- Each turn now records how much the assistant actually had to work with, so a turn that came back thin can be told apart from one that failed.
|
|
17
|
+
|
|
18
|
+
## 2026-08-02 (0.1.547)
|
|
19
|
+
|
|
20
|
+
- A routine's past runs now read as cards showing status, channel and the message actually sent, with a refresh and a way back in. Runs with no captured output are flagged.
|
|
21
|
+
- The separate notification and relay that fired when someone outside your team messaged you have been retired. The public agent's own reply is now the record, and the count of routed and answered messages comes from it.
|
|
22
|
+
|
|
12
23
|
## 2026-08-02 (0.1.546)
|
|
13
24
|
|
|
14
25
|
- When the assistant notifies you on a channel, the outcome of that notification is now recorded, so a message that never arrived can be traced rather than guessed at.
|
|
@@ -99,13 +99,27 @@ The Routines surface (`/routines`) is the admin view of the account's
|
|
|
99
99
|
automation `:Event` nodes — the device's scheduled agent turns and tool
|
|
100
100
|
dispatches, which the Calendar surface deliberately excludes (`calendar.ts`
|
|
101
101
|
unions only appointment events, `actionPlugin IS NULL`). It renders one card per
|
|
102
|
-
routine (title,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
102
|
+
routine (title, its one-line description where it has one, human-readable
|
|
103
|
+
schedule, next run, channel/destination or tool, status); a card opens a detail
|
|
104
|
+
modal modeled on the calendar `EventDetailModal`. A shipped routine is seeded with
|
|
105
|
+
a description and the operator can rewrite it from the modal; a routine nobody has
|
|
106
|
+
captioned renders with no line and no placeholder. Editing it stamps the row
|
|
107
|
+
operator-owned, so the next roster refresh leaves the operator's wording alone,
|
|
108
|
+
and recomputes the row's search vector, which is built from the name and the
|
|
109
|
+
description. A description is never dispatched: `agentPrompt` is the only text a
|
|
110
|
+
fire sends.
|
|
111
|
+
The read-only view shows two prose blocks, each under its own heading, in the
|
|
112
|
+
order **Description** then **Instruction sent to the agent**. Both use the same
|
|
113
|
+
header-above-prose shape, so neither reads as a different kind of thing from the
|
|
114
|
+
other. Before this the modal showed one unheaded block, so the caption and the
|
|
115
|
+
multi-KB prompt that actually fires were indistinguishable. The instruction
|
|
116
|
+
heading never reads the bare word "Instruction", in either mode: that collides
|
|
117
|
+
with the `## Instruction` block the platform appends to every dispatched channel
|
|
118
|
+
turn, and an agent read the two as the same field. The Description block renders
|
|
119
|
+
on every kind of routine, including a tool-action routine and a bare trigger,
|
|
120
|
+
because both already show it on the card; the instruction block belongs to an
|
|
121
|
+
agent routine, the only kind that has one. The modal edits the description, the
|
|
122
|
+
prose instruction (`agentPrompt`), the dispatch binding
|
|
109
123
|
(`agentChannel` and `agentDestination`, chosen from a server-supplied roster
|
|
110
124
|
rather than typed), and the schedule via a friendly builder (frequency
|
|
111
125
|
daily/weekly/monthly, day-of-week, day-of-month, time) that falls back to a
|
|
@@ -126,6 +140,29 @@ render it through one `RoutineStatusDot`, which is what stops them drifting:
|
|
|
126
140
|
| `cancelled`, `completed` | solid grey (`--text-tertiary`) | deliberately stopped or finished |
|
|
127
141
|
| anything else, and `null` | grey ring, no fill | no reading taken |
|
|
128
142
|
|
|
143
|
+
**The run recap.** Each card carries a history icon that opens that routine's
|
|
144
|
+
run history; the detail modal's **Runs** button reaches the same view. A run
|
|
145
|
+
shows what it sent — the message text itself, on the row and in full in the run
|
|
146
|
+
dialog — and a run that finished having sent nothing says so, which is a
|
|
147
|
+
different statement from a run whose outcome is not yet known. Both the routine
|
|
148
|
+
list and the run list have a Refresh control, because a run is promoted from
|
|
149
|
+
"accepted" to "finished" by a background sweep a couple of minutes later. The
|
|
150
|
+
**Download all runs** file carries the message text as its last column, so an
|
|
151
|
+
export of a customer-facing routine contains what was said to customers.
|
|
152
|
+
|
|
153
|
+
The run's own dot answers a different question from the routine's:
|
|
154
|
+
|
|
155
|
+
| run status | dot | meaning |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `finished` | green (`--session-live`) | it ran and its output was seen |
|
|
158
|
+
| `open`, `accepted`, `started` | activity (`--color-alias-status-activity`) | in flight, or accepted with nothing yet known |
|
|
159
|
+
| `no-destination` | amber (`--color-alias-status-warning-solid`) | it had nowhere to send |
|
|
160
|
+
| `failed` | red (`--color-alias-status-error-solid`) | the dispatch failed |
|
|
161
|
+
| anything else, and `null` | grey ring, no fill | no reading taken |
|
|
162
|
+
|
|
163
|
+
`app/routines/types.ts` holds both mappings and `RunStatusDot` is the only thing
|
|
164
|
+
that paints the run one, so the row and the dialog cannot drift.
|
|
165
|
+
|
|
129
166
|
The unrecognised case is a state of its own, never a fallback into green: `GET
|
|
130
167
|
/api/admin/routines` projects `eventStatus` verbatim, so a value outside the set
|
|
131
168
|
can reach the card at any time, and a stood-down routine showing green is a
|
|
@@ -143,7 +180,7 @@ The route (`server/routes/admin/routines.ts`) is account-scoped like `calendar.t
|
|
|
143
180
|
| `GET /api/admin/routines/:eventId` | One routine, same automation+account guard. |
|
|
144
181
|
| `GET /api/admin/routines/:eventId/runs` | One routine's `:RoutineRun` history, newest first. `limit` clamps to 1..500 and defaults to 50, so a caller that wants the full page must ask for it. |
|
|
145
182
|
| `GET /api/admin/routines/:eventId/runs.csv` | The same projection as a `text/csv` attachment with `Content-Disposition`, and **no** limit, so it is not the same row set as a clamped `/runs` call. Re-parses its own output and returns 500 rather than serving a document with fewer rows than the query returned. Zero rows is 404, not a header-only file: the query cannot tell a routine with no runs from an `eventId` on another account. |
|
|
146
|
-
| `PATCH /api/admin/routines/:eventId` | Edits `agentPrompt`, `recurrence`, and the `agentChannel`/`agentDestination` pair. Cron validation and the timezone-aware `nextRun` recompute copy the scheduling plugin's `schedule-update` tool. The binding is revalidated against the same house-authority rule, shared as `platform/lib/agent-dispatch-rule`; it is refused `partial-binding`, `invalid-channel`, `no-prompt`, `not-registered`, `cross-account`, `action-routine` (a routine that runs a tool keeps it — an agent binding outranks the action at fire time) or `clear-would-orphan` (clearing the only field holding a one-time routine inside the automation filter would hide it from every routines surface), and no refusal writes. Both fields as `null` clears the binding. An invalid cron is rejected 400 with no write. Only creation and deletion stay agent-only (`schedule-event`/`schedule-cancel`). |
|
|
183
|
+
| `PATCH /api/admin/routines/:eventId` | Edits `agentPrompt`, `description`, `recurrence`, and the `agentChannel`/`agentDestination` pair. A `description` write stamps `operatorEdited` and recomputes the row's `embedding` from `Event: <name>` plus the new text, reading the name from the row rather than the request body; the embedder returning nothing leaves the previous vector in place and the save still succeeds. A whitespace-only `description` is stored as null, so "no caption" is one state in the graph. Cron validation and the timezone-aware `nextRun` recompute copy the scheduling plugin's `schedule-update` tool. The binding is revalidated against the same house-authority rule, shared as `platform/lib/agent-dispatch-rule`; it is refused `partial-binding`, `invalid-channel`, `no-prompt`, `not-registered`, `cross-account`, `action-routine` (a routine that runs a tool keeps it — an agent binding outranks the action at fire time) or `clear-would-orphan` (clearing the only field holding a one-time routine inside the automation filter would hide it from every routines surface), and no refusal writes. Both fields as `null` clears the binding. An invalid cron is rejected 400 with no write. Only creation and deletion stay agent-only (`schedule-event`/`schedule-cancel`). |
|
|
147
184
|
| `GET /api/admin/dispatch-destinations` | Every destination the session's account may bind a routine to, across both channels, each labelled by the authoritative list it came from (`House admin`, `Account manager`, `Telegram admin`), plus an optional `name`: a display-only person name resolved from `:Person` in the row's own account scope — the house for a `House admin` row, the managed sub-account for an `Account manager` row, and never for Telegram, whose destinations are chat ids. Computed from the same lists the validator reads and filtered by the same rule, so the picker cannot offer what the save refuses; `name` is never part of what Save posts, and a graph outage returns an unnamed roster rather than an error. |
|
|
148
185
|
| `POST /api/admin/routines/:eventId/suspend` | Writes `eventStatus = 'suspended'` on a routine currently `'scheduled'`. 404s otherwise, so a second suspend is not a silent no-op. |
|
|
149
186
|
| `POST /api/admin/routines/:eventId/resume` | Returns a suspended routine to `'scheduled'`. 404s if it is not suspended, 409s if it cannot be resumed. |
|
|
@@ -224,6 +261,24 @@ would say so. `completed` gets its own bucket even though no code path writes it
|
|
|
224
261
|
today, because it remains part of the shipped enum and one row carrying it would
|
|
225
262
|
otherwise pin `other` above zero forever and kill the alarm.
|
|
226
263
|
|
|
264
|
+
`[schedule-audit] op=description-coverage acct=<8> routines=<n>
|
|
265
|
+
withDescription=<n> withInstruction=<n> toolActions=<n>` is the pair behind the
|
|
266
|
+
two prose blocks the modal shows. A routine carrying an instruction and no
|
|
267
|
+
description is a card whose title is all the operator gets; one carrying a
|
|
268
|
+
description and no instruction is worse, because it looks explained, fires on
|
|
269
|
+
schedule and sends nothing. Neither state writes an event of its own, so only a
|
|
270
|
+
periodic count reveals them, and the counts sit on one line beside the total
|
|
271
|
+
because any one of them alone answers the wrong question. `toolActions` is on the
|
|
272
|
+
line because `withInstruction` is otherwise comparable to nothing: a tool-action
|
|
273
|
+
routine has no instruction and is not silent, it runs a tool, so an account
|
|
274
|
+
holding one would sit at `routines > withInstruction` for ever and the alarm
|
|
275
|
+
would be dead from that point on. The genuinely silent count is `routines -
|
|
276
|
+
toolActions - withInstruction`, the same reconciliation `other` performs in the
|
|
277
|
+
suspension census. Emitted per account on every sweep tick including a healthy
|
|
278
|
+
one, over the same automation set the routes list. The roster seed's own
|
|
279
|
+
`descNull` counter is its narrow twin, scoped to seeded rows and so blind to
|
|
280
|
+
exactly the operator-created ones most likely to carry no caption.
|
|
281
|
+
|
|
227
282
|
**The shipped roster.** Every account starts with eleven routines —
|
|
228
283
|
`start-of-day`, `inbound-check`, `end-of-day`, `appointment-reminder`,
|
|
229
284
|
`commitment-chase`, `calendar-reconcile`, `contact-reconcile`, `crm-reconcile`,
|
|
@@ -4,15 +4,13 @@ Two questions an agent cannot answer from inside itself, and both have caused re
|
|
|
4
4
|
|
|
5
5
|
## What wakes a session
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Four things start or resume a WhatsApp session. They are distinguishable, and the distinction matters, because one of them is written by the platform rather than by the person named as the sender.
|
|
8
8
|
|
|
9
9
|
**An admin phone or an account manager messages the line.** This resumes that person's own admin session. There is no per-account admin session: the session id is a hash of the account plus the person, so one person messaging from two channels resumes one thread, and two managers on one account have two threads.
|
|
10
10
|
|
|
11
|
-
**A public sender messages the line.**
|
|
11
|
+
**A public sender messages the line.** One thing follows: the account's public agent answers the visitor, if the account has one and has enabled it. If not, the message is stored and labelled and the visitor receives nothing at all.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
2. Every bound manager's own admin session is woken with a `public-relay` turn carrying the sender's message as fenced content. This is the carrier for anything the account needs to do about the visitor: translate, put a request to a registered counterparty, carry the answer back.
|
|
15
|
-
3. The account's public agent answers the visitor, if the account has one and has enabled it. If not, the visitor receives nothing at all, and steps 1 and 2 have already happened regardless.
|
|
13
|
+
Nobody is told the visitor wrote. The platform used to notify the registered managers and to wake each of them with a relay turn; both were retired, because telling the operator a stranger wrote in is a scheduled routine's job. A routine chooses its own recipient, its own wording and its own transport, and an account that wants no such message simply does not run one.
|
|
16
14
|
|
|
17
15
|
**The scheduler fires a due event.** This raises a `schedule` turn on the destination's own session, carrying the event's prompt.
|
|
18
16
|
|
|
@@ -20,19 +18,16 @@ Five things start or resume a WhatsApp session. They are distinguishable, and th
|
|
|
20
18
|
|
|
21
19
|
## Reading why you woke
|
|
22
20
|
|
|
23
|
-
Every turn carries a `source`.
|
|
21
|
+
Every turn carries a `source`. Two values exist:
|
|
24
22
|
|
|
25
23
|
| `source` | Meaning |
|
|
26
24
|
|---|---|
|
|
27
25
|
| `user` | A real person sent this message to the line. Also the value when the field is absent. |
|
|
28
26
|
| `schedule` | The scheduler wrote this turn. The named destination did not send it. |
|
|
29
|
-
| `public-relay` | The platform wrote this turn because a public visitor messaged the account. The named sender is a manager being told, not someone who wrote to you. |
|
|
30
27
|
|
|
31
|
-
**A
|
|
28
|
+
**A public visitor's turn is the one turn whose `## Instruction` block is the account's own.** Its body is `agents/<slug>/INSTRUCTION.md`, written by the account owner, where `<slug>` is the public agent answering. If that file is missing the turn is refused outright, so the visitor is not answered rather than being handed platform prose the account cannot edit. Every turn you authored, from your own handset or through the scheduler, takes the platform's own directive and never reads that file, so it can never be refused over a file it does not use.
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
**On a `public-relay` turn the reply tool is the only way to reach anyone.** On an ordinary turn the platform forwards your closing text to the sender when you called no reply tool. On a relay-woken turn it does not, because the relay carries its own reply path. So whatever you decide the manager should receive has to go through the reply tool; text you merely write at the end of the turn reaches nobody, and a decision not to reply is silence rather than a message.
|
|
30
|
+
On every turn on this line the platform forwards your closing text to the sender when you called no reply tool, so a turn that ends with an answer written but no tool called still reaches the person waiting.
|
|
36
31
|
|
|
37
32
|
## Which files compose the prompt
|
|
38
33
|
|
|
@@ -43,25 +38,22 @@ The system prompt is assembled per spawn from one agent directory, and **which d
|
|
|
43
38
|
|
|
44
39
|
From that one directory it takes `IDENTITY.md` and `SOUL.md`, verbatim.
|
|
45
40
|
|
|
46
|
-
The consequence catches people out: **an instruction written into `agents/admin/SOUL.md` is never read by a public spawn**, and an instruction written into a public agent's `SOUL.md` is never read by an admin turn. Before writing an instruction into a role file, decide which role will actually be running when it needs to apply.
|
|
41
|
+
The consequence catches people out: **an instruction written into `agents/admin/SOUL.md` is never read by a public spawn**, and an instruction written into a public agent's `SOUL.md` is never read by an admin turn. Before writing an instruction into a role file, decide which role will actually be running when it needs to apply. A stranger's message wakes the public agent and nothing else, so an instruction meant to govern what happens when a stranger writes belongs in that agent's own files, never in `agents/admin/`.
|
|
47
42
|
|
|
48
43
|
A public agent's directory also carries `KNOWLEDGE.md` and `config.json`. An account can hold as many public agents as it likes; only one is bound to WhatsApp at a time, and that binding is per account.
|
|
49
44
|
|
|
50
45
|
## The switches, and what each one stops
|
|
51
46
|
|
|
52
|
-
|
|
47
|
+
Four settings sit on this path. They are not interchangeable, and reaching for the wrong one is how an operator ends up silencing more than they meant.
|
|
53
48
|
|
|
54
49
|
| Setting | What it stops | What it leaves running |
|
|
55
50
|
|---|---|---|
|
|
56
51
|
| `dmPolicy: disabled` | Public senders are refused at the gate. | Admin and manager inbound. |
|
|
57
|
-
| `publicAgentEnabled: false` | The visitor gets no reply. |
|
|
58
|
-
| `managerNotifyEnabled: false` | The verbatim copy of the visitor's message. | The relay, and any reply the woken turn sends. |
|
|
52
|
+
| `publicAgentEnabled: false` | The visitor gets no reply. | Storage and labelling of what the visitor sent. |
|
|
59
53
|
| `dispatchInbound: false` | Every agent turn on that account's socket. | Storage: messages are still stored and readable. |
|
|
60
|
-
| `dispatch: false` on one registered party | The public-agent turn for that one phone. | Everything else: storage, the label,
|
|
61
|
-
|
|
62
|
-
`managerNotifyEnabled` is the fine-grained one, and the one to reach for when the notifications are unwanted but the work is not. Unbinding a manager is not a substitute: the manager registry is shared by the notification, the relay and `whatsapp-notify-manager`, so unbinding silences all three.
|
|
54
|
+
| `dispatch: false` on one registered party | The public-agent turn for that one phone. | Everything else: storage, the label, and every other sender on the line. |
|
|
63
55
|
|
|
64
|
-
|
|
56
|
+
None of these governs whether the operator hears about a visitor, because no setting does: that is a scheduled routine's job, and the way to stop it is to stop the routine. The manager registry is read by nothing on this path at all, so unbinding a manager changes nothing a visitor's message does.
|
|
65
57
|
|
|
66
58
|
## When the answer is not here
|
|
67
59
|
|
|
@@ -71,16 +63,14 @@ Read the current value with `whatsapp-config {action:'get-manager-notify-enabled
|
|
|
71
63
|
[whatsapp:wire] op=stanza msgId=<id>
|
|
72
64
|
[wa-notify] op=eligible msgId=<id> reason=<how the sender was admitted>
|
|
73
65
|
[whatsapp:route] op=routed inboundId=<id> msgIds=<the stanzas this payload covers>
|
|
74
|
-
[whatsapp:notify] op=public-inbound inboundId=<id> enabled=0|1 outcome=sent|failed|no-recipients|disabled
|
|
75
|
-
[whatsapp:relay] op=dispatch inboundId=<id> outcome=sent|failed|no-recipients
|
|
76
66
|
[whatsapp:party] op=dispatch-decision inboundId=<id> party=… dispatch=true|false spawned=0|1 (labelled senders only)
|
|
77
67
|
[whatsapp:public-agent] op=route inboundId=<id> enabled=… slug=… spawned=0|1
|
|
78
68
|
[whatsapp:public-agent] op=spawn-ok | op=spawn-failed inboundId=<id>
|
|
79
69
|
```
|
|
80
70
|
|
|
81
|
-
Follow one inbound by its `inboundId`. That selects the last
|
|
71
|
+
Follow one inbound by its `inboundId`. That selects the last four lines and nothing else, however many visitors messaged in the same window. For the first two, read `msgIds=` off the `op=routed` line and grep one of those ids. Two greps rather than one, because the debouncer merges stanzas into a single routed payload and the two halves are keyed either side of that merge.
|
|
82
72
|
|
|
83
|
-
Anything that failed carries the same id: the drop lines
|
|
73
|
+
Anything that failed carries the same id: the drop lines and `op=spawn-failed`. Fewer lines than expected, with none of them a failure, means a step emitted nothing at all — which is what the standing audits below are for.
|
|
84
74
|
|
|
85
75
|
Do not try to follow an inbound by its sender. `sender=` appears on two of these lines, and the same visitor is a LID on `op=stanza` and an E.164 on `op=routed`, so no sender-based filter spans the merge.
|
|
86
76
|
|
|
@@ -95,4 +85,4 @@ op=startup-watch state=disposed
|
|
|
95
85
|
|
|
96
86
|
The first-run dialog is answered for the session, and the watcher that guards against an *unanswered* one drops what it saw before that answer. `bufferCleared=false` means the confirm fired and the drop did not, which is the shape that killed a resumed spawn on 2026-08-01: the answered dialog's own footer stayed in the buffer, the replayed transcript slid past it, and the spawn was blocked by a line the agent itself had written the day before.
|
|
97
87
|
|
|
98
|
-
|
|
88
|
+
Two standing audits reconcile that chain rather than waiting for someone to notice. `op=public-notify-reconcile` reports `routed` against `answered`, so a visitor routed to an agent that never replied shows as `answerGap`. `op=spawn-census` reports attempts against successes. A non-zero gap, or attempts with no successes, is a fault even when nothing has been reported.
|
|
@@ -204,6 +204,12 @@ Use standard 5-field cron syntax: `minute hour day-of-month month day-of-week`.
|
|
|
204
204
|
| `0 0 1 * *` | First of each month at midnight |
|
|
205
205
|
| `*/30 * * * *` | Every 30 minutes |
|
|
206
206
|
|
|
207
|
+
## What an update confirms
|
|
208
|
+
|
|
209
|
+
`schedule-update` returns the properties it wrote: `Event updated: <id> — fields: description, recurrence`. Companions count — changing `recurrence` also writes `nextRun`, changing `eventStatus` also writes `suspendedInBulk`, and setting an `agentDispatch` also clears `actionPlugin`, `actionTool` and `actionArgs`. Four properties are never named: `updatedAt` and `operatorEdited` are stamps, `embedding` is a derived search vector, and `notes` is reported as `note appended` instead, and only when the caller supplied one that was not empty.
|
|
210
|
+
|
|
211
|
+
When `agentPrompt` is not among the fields, the line ends `(the instruction sent to the agent was not changed)`. That clause is the answer to "did my prompt rewrite land" — a confirmation without it means the dispatch prompt was written. Editing a meeting opens `Meeting updated:` and names the caller's own field names, not the stored `title`/`startsAt`/`endsAt`.
|
|
212
|
+
|
|
207
213
|
## Skip next
|
|
208
214
|
|
|
209
215
|
For recurring events, `schedule-update` with `skipNext: true` advances `nextRun` by one cycle without triggering. Use when the user says "skip tomorrow's briefing" or similar.
|
|
@@ -7,6 +7,7 @@ import { scheduleList } from "./tools/schedule-list.js";
|
|
|
7
7
|
import { scheduleGet } from "./tools/schedule-get.js";
|
|
8
8
|
import { scheduleRuns } from "./tools/schedule-runs.js";
|
|
9
9
|
import { scheduleUpdate, EVENT_STATUSES } from "./tools/schedule-update.js";
|
|
10
|
+
import { describeUpdate } from "./lib/update-summary.js";
|
|
10
11
|
import { scheduleCancel } from "./tools/schedule-cancel.js";
|
|
11
12
|
import { scheduleExportIcs } from "./tools/schedule-export-ics.js";
|
|
12
13
|
import { scheduleImportIcs } from "./tools/schedule-import-ics.js";
|
|
@@ -328,11 +329,14 @@ eagerTool(server, "schedule-update", "Update an event's properties or append a n
|
|
|
328
329
|
if (!accountId)
|
|
329
330
|
return refuseNoAccount("schedule-update");
|
|
330
331
|
try {
|
|
331
|
-
await scheduleUpdate({ ...params, accountId });
|
|
332
|
+
const written = await scheduleUpdate({ ...params, accountId });
|
|
332
333
|
if (params.skipNext) {
|
|
333
334
|
return { content: [{ type: "text", text: `Skipped next occurrence of event: ${params.eventId}` }] };
|
|
334
335
|
}
|
|
335
|
-
|
|
336
|
+
// Task 2362 — name the properties written. The flat `Event updated: <id>` this replaced read
|
|
337
|
+
// identically for a description edit and for a dispatch-prompt rewrite, and an agent read it
|
|
338
|
+
// as proof its own successful rewrite had not landed.
|
|
339
|
+
return { content: [{ type: "text", text: describeUpdate(params.eventId, written) }] };
|
|
336
340
|
}
|
|
337
341
|
catch (err) {
|
|
338
342
|
return {
|