@rubytech/create-maxy-code 0.1.545 → 0.1.547
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/mcp-spawn-tee/dist/index.js +11 -0
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-spawn-tee/src/__tests__/spawn-tee.test.ts +39 -0
- package/payload/platform/lib/mcp-spawn-tee/src/index.ts +12 -0
- package/payload/platform/plugins/admin/lib/mcp-spawn-tee/index.js +11 -0
- 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 +38 -25
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +9 -0
- package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/browser/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/connector/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +23 -0
- package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +14 -24
- package/payload/platform/plugins/email/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/filesystem/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/google/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/graph-viewer/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/ledger/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/memory/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/index.js +11 -0
- 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/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/scripts/reconcile-bookings.js +3 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
- package/payload/platform/plugins/storage-broker/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/voice-mirror/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/whatsapp/PLUGIN.md +0 -6
- package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/index.js +11 -0
- 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/plugins/work/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +0 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/channel-mcp.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/channel-mcp.js +16 -2
- package/payload/platform/services/claude-session-manager/dist/channel-mcp.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/channel-spawn-tee.d.ts +34 -0
- package/payload/platform/services/claude-session-manager/dist/channel-spawn-tee.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/channel-spawn-tee.js +41 -0
- package/payload/platform/services/claude-session-manager/dist/channel-spawn-tee.js.map +1 -0
- 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 +26 -1
- 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 +11 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.js +16 -2
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts +6 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js +17 -2
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +16 -2
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +45 -18
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +25 -20
- 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 +69 -13
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +15 -5
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.js +9 -5
- package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
- package/payload/server/{chunk-CVUSUNXM.js → chunk-MHNHG3GL.js} +2 -4
- package/payload/server/{chunk-X2RRMHVV.js → chunk-Q33KT7YJ.js} +1 -1
- package/payload/server/{chunk-DU7GPDJJ.js → chunk-WGMIUXXG.js} +4 -0
- package/payload/server/{manager-TI2YJQVZ.js → manager-W32LVPCT.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-Ds0yz7_C.js +2 -0
- package/payload/server/public/assets/routines-Ds0yz7_C.js.br +0 -0
- package/payload/server/public/assets/routines-Ds0yz7_C.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 +82 -355
- 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:27883a95ee231fb265b37617f71dfdf1a71e28fccf76d09f9e75c0726c777f48
|
|
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
|
|
@@ -3521,6 +3511,29 @@ render it through one `RoutineStatusDot`, which is what stops them drifting:
|
|
|
3521
3511
|
| `cancelled`, `completed` | solid grey (`--text-tertiary`) | deliberately stopped or finished |
|
|
3522
3512
|
| anything else, and `null` | grey ring, no fill | no reading taken |
|
|
3523
3513
|
|
|
3514
|
+
**The run recap.** Each card carries a history icon that opens that routine's
|
|
3515
|
+
run history; the detail modal's **Runs** button reaches the same view. A run
|
|
3516
|
+
shows what it sent — the message text itself, on the row and in full in the run
|
|
3517
|
+
dialog — and a run that finished having sent nothing says so, which is a
|
|
3518
|
+
different statement from a run whose outcome is not yet known. Both the routine
|
|
3519
|
+
list and the run list have a Refresh control, because a run is promoted from
|
|
3520
|
+
"accepted" to "finished" by a background sweep a couple of minutes later. The
|
|
3521
|
+
**Download all runs** file carries the message text as its last column, so an
|
|
3522
|
+
export of a customer-facing routine contains what was said to customers.
|
|
3523
|
+
|
|
3524
|
+
The run's own dot answers a different question from the routine's:
|
|
3525
|
+
|
|
3526
|
+
| run status | dot | meaning |
|
|
3527
|
+
|---|---|---|
|
|
3528
|
+
| `finished` | green (`--session-live`) | it ran and its output was seen |
|
|
3529
|
+
| `open`, `accepted`, `started` | activity (`--color-alias-status-activity`) | in flight, or accepted with nothing yet known |
|
|
3530
|
+
| `no-destination` | amber (`--color-alias-status-warning-solid`) | it had nowhere to send |
|
|
3531
|
+
| `failed` | red (`--color-alias-status-error-solid`) | the dispatch failed |
|
|
3532
|
+
| anything else, and `null` | grey ring, no fill | no reading taken |
|
|
3533
|
+
|
|
3534
|
+
`app/routines/types.ts` holds both mappings and `RunStatusDot` is the only thing
|
|
3535
|
+
that paints the run one, so the row and the dialog cannot drift.
|
|
3536
|
+
|
|
3524
3537
|
The unrecognised case is a state of its own, never a fallback into green: `GET
|
|
3525
3538
|
/api/admin/routines` projects `eventStatus` verbatim, so a value outside the set
|
|
3526
3539
|
can reach the card at any time, and a stood-down routine showing green is a
|
|
@@ -9,6 +9,15 @@ 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.547)
|
|
13
|
+
|
|
14
|
+
- 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.
|
|
15
|
+
- 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.
|
|
16
|
+
|
|
17
|
+
## 2026-08-02 (0.1.546)
|
|
18
|
+
|
|
19
|
+
- 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.
|
|
20
|
+
|
|
12
21
|
## 2026-08-02 (0.1.545)
|
|
13
22
|
|
|
14
23
|
- The assistant is now instructed differently depending on whether you messaged it directly or the turn was relayed from someone outside your team, so your own standing rules no longer ride along on a relayed turn.
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -126,6 +126,29 @@ render it through one `RoutineStatusDot`, which is what stops them drifting:
|
|
|
126
126
|
| `cancelled`, `completed` | solid grey (`--text-tertiary`) | deliberately stopped or finished |
|
|
127
127
|
| anything else, and `null` | grey ring, no fill | no reading taken |
|
|
128
128
|
|
|
129
|
+
**The run recap.** Each card carries a history icon that opens that routine's
|
|
130
|
+
run history; the detail modal's **Runs** button reaches the same view. A run
|
|
131
|
+
shows what it sent — the message text itself, on the row and in full in the run
|
|
132
|
+
dialog — and a run that finished having sent nothing says so, which is a
|
|
133
|
+
different statement from a run whose outcome is not yet known. Both the routine
|
|
134
|
+
list and the run list have a Refresh control, because a run is promoted from
|
|
135
|
+
"accepted" to "finished" by a background sweep a couple of minutes later. The
|
|
136
|
+
**Download all runs** file carries the message text as its last column, so an
|
|
137
|
+
export of a customer-facing routine contains what was said to customers.
|
|
138
|
+
|
|
139
|
+
The run's own dot answers a different question from the routine's:
|
|
140
|
+
|
|
141
|
+
| run status | dot | meaning |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| `finished` | green (`--session-live`) | it ran and its output was seen |
|
|
144
|
+
| `open`, `accepted`, `started` | activity (`--color-alias-status-activity`) | in flight, or accepted with nothing yet known |
|
|
145
|
+
| `no-destination` | amber (`--color-alias-status-warning-solid`) | it had nowhere to send |
|
|
146
|
+
| `failed` | red (`--color-alias-status-error-solid`) | the dispatch failed |
|
|
147
|
+
| anything else, and `null` | grey ring, no fill | no reading taken |
|
|
148
|
+
|
|
149
|
+
`app/routines/types.ts` holds both mappings and `RunStatusDot` is the only thing
|
|
150
|
+
that paints the run one, so the row and the dialog cannot drift.
|
|
151
|
+
|
|
129
152
|
The unrecognised case is a state of its own, never a fallback into green: `GET
|
|
130
153
|
/api/admin/routines` projects `eventStatus` verbatim, so a value outside the set
|
|
131
154
|
can reach the card at any time, and a stood-down routine showing green is a
|
|
@@ -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.
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|