@rubytech/create-maxy-code 0.1.542 → 0.1.544
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/__tests__/public-instruction-seed.test.js +102 -0
- package/dist/index.js +47 -0
- package/dist/public-instruction-seed.js +70 -0
- package/package.json +1 -1
- package/payload/platform/lib/shared-folder/dist/index.d.ts +47 -0
- package/payload/platform/lib/shared-folder/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/shared-folder/dist/index.js +93 -0
- package/payload/platform/lib/shared-folder/dist/index.js.map +1 -0
- package/payload/platform/lib/shared-folder/src/index.ts +92 -0
- package/payload/platform/lib/shared-folder/tsconfig.json +5 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/PLUGIN.md +2 -0
- package/payload/platform/plugins/admin/hooks/__tests__/public-tool-surface.test.sh +173 -0
- package/payload/platform/plugins/admin/hooks/public-tool-surface.sh +123 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.js +13 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.js.map +1 -1
- package/payload/platform/plugins/admin/skills/channel-instruction/SKILL.md +46 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +18 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +15 -0
- package/payload/platform/plugins/docs/references/access-control.md +14 -0
- package/payload/platform/plugins/docs/references/internals.md +2 -0
- package/payload/platform/plugins/docs/references/platform.md +1 -0
- package/payload/platform/plugins/filesystem/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/filesystem/PLUGIN.md +11 -1
- package/payload/platform/plugins/filesystem/mcp/dist/index.js +23 -7
- package/payload/platform/plugins/filesystem/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/scope.test.js +104 -4
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/scope.test.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/shared-folder.test.d.ts +2 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/shared-folder.test.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/shared-folder.test.js +67 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/shared-folder.test.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.d.ts +16 -2
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.js +54 -1
- package/payload/platform/plugins/filesystem/mcp/dist/lib/scope.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/handlers.test.js +76 -2
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/handlers.test.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.d.ts +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js +3 -3
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-glob.d.ts +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-glob.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-glob.js +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-glob.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-grep.d.ts +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-grep.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-grep.js +3 -3
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-grep.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-list.d.ts +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-list.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-list.js +3 -3
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-list.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-read.d.ts +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-read.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-read.js +3 -3
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-read.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.d.ts +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js +3 -3
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +81 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +22 -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 +80 -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/whatsapp/PLUGIN.md +2 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +1 -1
- package/payload/platform/scripts/__tests__/public-surface-registered.test.sh +102 -0
- package/payload/platform/scripts/check-no-esm-require.mjs +5 -0
- package/payload/platform/scripts/lib/__tests__/account-settings-public-surface.test.sh +109 -0
- package/payload/platform/scripts/lib/account-settings-public-surface.sh +109 -0
- package/payload/platform/scripts/lib/provision-account-dir.sh +6 -3
- package/payload/platform/scripts/setup-account.sh +14 -0
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts +8 -4
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js +27 -7
- package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.d.ts +11 -6
- package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.js +8 -4
- package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts +24 -2
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +23 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +35 -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 +286 -25
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +169 -51
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +24 -12
- 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 +194 -28
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +4 -0
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-surface-audit.d.ts +24 -3
- package/payload/platform/services/claude-session-manager/dist/public-surface-audit.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-surface-audit.js +29 -3
- package/payload/platform/services/claude-session-manager/dist/public-surface-audit.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.d.ts +27 -0
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.js +32 -0
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/role-census.d.ts +24 -0
- package/payload/platform/services/claude-session-manager/dist/role-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/role-census.js +50 -0
- package/payload/platform/services/claude-session-manager/dist/role-census.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +24 -2
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +21 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-recover.d.ts +76 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-recover.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-recover.js +110 -19
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-recover.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-respawn.d.ts +60 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-respawn.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-respawn.js +93 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-respawn.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.d.ts +31 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.js +72 -9
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +9 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/types.d.ts +9 -3
- package/payload/platform/services/claude-session-manager/dist/types.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts +0 -1
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.js +0 -46
- package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +16 -4
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +27 -14
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/server.js +10 -0
- package/payload/platform/services/telegram-channel/dist/server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts +0 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js +0 -60
- package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +14 -2
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +28 -12
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +10 -0
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +97 -33
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +98 -76
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts +18 -0
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +87 -5
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +41 -9
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.js +42 -7
- package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
- package/payload/platform/templates/agents/admin/INSTRUCTION.md +0 -0
- package/payload/server/{adminuser-self-heal-LC7HZAC6.js → adminuser-self-heal-ZHFNDKJK.js} +1 -1
- package/payload/server/{chunk-HZP7BKBF.js → chunk-CVUSUNXM.js} +128 -4
- package/payload/server/{chunk-CKTHAHL4.js → chunk-DU7GPDJJ.js} +4 -2
- package/payload/server/{chunk-PFF6I7KP.js → chunk-HYQNUVGO.js} +8 -1
- package/payload/server/{chunk-ERIM3EFB.js → chunk-X2RRMHVV.js} +1 -1
- package/payload/server/{manager-CM55K4J2.js → manager-TI2YJQVZ.js} +3 -3
- package/payload/server/maxy-edge.js +3 -3
- package/payload/server/public/activity.html +5 -5
- package/payload/server/public/agents.html +4 -4
- package/payload/server/public/assets/AdminLoginScreens-BGKtDqAk.js +1 -0
- 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 +2 -0
- package/payload/server/public/assets/AdminShell-DnfgsAQl.js.br +0 -0
- package/payload/server/public/assets/AdminShell-DnfgsAQl.js.gz +0 -0
- package/payload/server/public/assets/activity-ByJSut0Q.js +1 -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 +1 -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 +1 -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 +1 -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 +1 -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 +1 -0
- 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 +1 -0
- package/payload/server/public/assets/chevron-left-DFK18xVX.js.br +0 -0
- package/payload/server/public/assets/chevron-right-DJ4oaHoN.js +1 -0
- package/payload/server/public/assets/chevron-right-DJ4oaHoN.js.br +0 -0
- package/payload/server/public/assets/clock-wHIan2DW.js +1 -0
- package/payload/server/public/assets/clock-wHIan2DW.js.br +0 -0
- package/payload/server/public/assets/{copy-3kj9Oaoc.js → copy-lFFhXRGk.js} +1 -1
- 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 +1 -0
- 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-CBaewT76.js → file-text-D2Y-bkNy.js} +1 -1
- 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-B8-e2_Z-.js → graph-C-3yN6JD.js} +3 -3
- 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-Bsc23eZU.js → graph-labels-DiaPLP27.js} +1 -1
- 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 +1 -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 +1 -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 +32 -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 +1 -0
- 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 +1 -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-FZW7c8p8.js → rotate-ccw-rTRuTqei.js} +1 -1
- 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 +2 -0
- 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 +1 -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 +3 -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-CR-jRJdI.js → triangle-alert-DtWUg6jR.js} +1 -1
- 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 +1 -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-BYIHo-xL.js +14 -0
- package/payload/server/public/assets/useMediaQuery-BYIHo-xL.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-BYIHo-xL.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-DlOWP56H.css +1 -0
- package/payload/server/public/assets/useMediaQuery-DlOWP56H.css.br +0 -0
- package/payload/server/public/assets/useMediaQuery-DlOWP56H.css.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BKFAYuzz.js +2 -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-CpCOYUBc.js → wrench-Ct4kf-uv.js} +1 -1
- 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/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 +537 -263
- package/payload/server/{src-JN6PIAJN.js → src-MM64CYYZ.js} +1 -1
- package/payload/server/{userprofile-reconcile-QHVLY2AH.js → userprofile-reconcile-TL4JKBPG.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-DuFCjbz2.js +0 -1
- package/payload/server/public/assets/AdminLoginScreens-DuFCjbz2.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-DuFCjbz2.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-DJL5DzRX.js +0 -2
- package/payload/server/public/assets/AdminShell-DJL5DzRX.js.br +0 -0
- package/payload/server/public/assets/AdminShell-DJL5DzRX.js.gz +0 -0
- package/payload/server/public/assets/activity-CpMnNr5c.js +0 -1
- package/payload/server/public/assets/activity-CpMnNr5c.js.br +0 -0
- package/payload/server/public/assets/activity-CpMnNr5c.js.gz +0 -0
- package/payload/server/public/assets/admin-CBwKIfaI.js +0 -1
- package/payload/server/public/assets/admin-CBwKIfaI.js.br +0 -0
- package/payload/server/public/assets/admin-CBwKIfaI.js.gz +0 -0
- package/payload/server/public/assets/agents-C4LmSKjb.js +0 -1
- package/payload/server/public/assets/agents-C4LmSKjb.js.br +0 -0
- package/payload/server/public/assets/agents-C4LmSKjb.js.gz +0 -0
- package/payload/server/public/assets/browser-Bm9xm_yc.js +0 -1
- package/payload/server/public/assets/browser-Bm9xm_yc.js.br +0 -0
- package/payload/server/public/assets/browser-Bm9xm_yc.js.gz +0 -0
- package/payload/server/public/assets/calendar-CNY9FTWe.js +0 -1
- package/payload/server/public/assets/calendar-CNY9FTWe.js.br +0 -0
- package/payload/server/public/assets/calendar-CNY9FTWe.js.gz +0 -0
- package/payload/server/public/assets/chat-3WoUGCTd.js +0 -1
- package/payload/server/public/assets/chat-3WoUGCTd.js.br +0 -0
- package/payload/server/public/assets/chat-3WoUGCTd.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-BE16BJnw.js +0 -1
- package/payload/server/public/assets/chevron-left-BE16BJnw.js.br +0 -0
- package/payload/server/public/assets/chevron-right-Bu2VKpeU.js +0 -1
- package/payload/server/public/assets/chevron-right-Bu2VKpeU.js.br +0 -0
- package/payload/server/public/assets/clock-C4Nu2aRV.js +0 -1
- package/payload/server/public/assets/clock-C4Nu2aRV.js.br +0 -0
- package/payload/server/public/assets/copy-3kj9Oaoc.js.br +0 -0
- package/payload/server/public/assets/copy-3kj9Oaoc.js.gz +0 -0
- package/payload/server/public/assets/data-C-x5EHyi.js +0 -1
- package/payload/server/public/assets/data-C-x5EHyi.js.br +0 -1
- package/payload/server/public/assets/data-C-x5EHyi.js.gz +0 -0
- package/payload/server/public/assets/file-text-CBaewT76.js.br +0 -0
- package/payload/server/public/assets/file-text-CBaewT76.js.gz +0 -0
- package/payload/server/public/assets/graph-B8-e2_Z-.js.br +0 -0
- package/payload/server/public/assets/graph-B8-e2_Z-.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-Bsc23eZU.js.br +0 -0
- package/payload/server/public/assets/graph-labels-Bsc23eZU.js.gz +0 -0
- package/payload/server/public/assets/operator-Cve0-qfO.js +0 -1
- package/payload/server/public/assets/operator-Cve0-qfO.js.br +0 -0
- package/payload/server/public/assets/operator-Cve0-qfO.js.gz +0 -0
- package/payload/server/public/assets/page-BgVMs6Vf.js +0 -1
- package/payload/server/public/assets/page-BgVMs6Vf.js.br +0 -0
- package/payload/server/public/assets/page-BgVMs6Vf.js.gz +0 -0
- package/payload/server/public/assets/page-fABub-w8.js +0 -32
- package/payload/server/public/assets/page-fABub-w8.js.br +0 -0
- package/payload/server/public/assets/page-fABub-w8.js.gz +0 -0
- package/payload/server/public/assets/play-B6zXB9K7.js +0 -1
- package/payload/server/public/assets/play-B6zXB9K7.js.br +0 -0
- package/payload/server/public/assets/play-B6zXB9K7.js.gz +0 -0
- package/payload/server/public/assets/public--R2DbdWs.js +0 -1
- package/payload/server/public/assets/public--R2DbdWs.js.br +0 -0
- package/payload/server/public/assets/public--R2DbdWs.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-FZW7c8p8.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-FZW7c8p8.js.gz +0 -0
- package/payload/server/public/assets/routines-BpZs2SaT.js +0 -2
- package/payload/server/public/assets/routines-BpZs2SaT.js.br +0 -0
- package/payload/server/public/assets/routines-BpZs2SaT.js.gz +0 -0
- package/payload/server/public/assets/skills-DF7uyEEz.js +0 -1
- package/payload/server/public/assets/skills-DF7uyEEz.js.br +0 -0
- package/payload/server/public/assets/skills-DF7uyEEz.js.gz +0 -0
- package/payload/server/public/assets/tasks-BfJJmoWO.js +0 -3
- package/payload/server/public/assets/tasks-BfJJmoWO.js.br +0 -0
- package/payload/server/public/assets/tasks-BfJJmoWO.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-CR-jRJdI.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-CR-jRJdI.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-IOuPUAHY.js +0 -1
- package/payload/server/public/assets/useCopyFeedback-IOuPUAHY.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-IOuPUAHY.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-CA6dR5iz.js +0 -14
- package/payload/server/public/assets/useMediaQuery-CA6dR5iz.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-CA6dR5iz.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-DpwgV1Da.css +0 -1
- package/payload/server/public/assets/useMediaQuery-DpwgV1Da.css.br +0 -0
- package/payload/server/public/assets/useMediaQuery-DpwgV1Da.css.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DGhsN7nV.js +0 -2
- package/payload/server/public/assets/useVoiceRecorder-DGhsN7nV.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DGhsN7nV.js.gz +0 -0
- package/payload/server/public/assets/wrench-CpCOYUBc.js.br +0 -0
- package/payload/server/public/assets/wrench-CpCOYUBc.js.gz +0 -0
|
@@ -27,7 +27,7 @@ import { parseWaChannelBody, sessionIdFieldsFor } from './public-spawn-session.j
|
|
|
27
27
|
import { buildWebchatChannelMcpServers, buildWebchatChannelArgv, webchatChannelMcpConfigPath, WEBCHAT_CHANNEL_SERVER_NAME } from './webchat-channel-mcp.js';
|
|
28
28
|
import { buildTelegramChannelMcpServers, buildTelegramChannelArgv, telegramChannelMcpConfigPath, TELEGRAM_CHANNEL_SERVER_NAME } from './telegram-channel-mcp.js';
|
|
29
29
|
import { buildChannelMcpServers, buildChannelArgv, channelMcpConfigPath, CHANNEL_SERVER_NAME } from './channel-mcp.js';
|
|
30
|
-
import { buildRcPublicLockdownArgv, formatToolAllowlistLine } from './rc-public-lockdown.js';
|
|
30
|
+
import { buildRcPublicLockdownArgv, formatToolAllowlistLine, PUBLIC_ALLOWED_TOOLS_ENV, allowedToolsFromArgv, formatRoleResolutionLine, } from './rc-public-lockdown.js';
|
|
31
31
|
import { mergeTarget, isMultiTarget, targetKinds } from './channel-targets.js';
|
|
32
32
|
import { randomUUID, createHash } from 'node:crypto';
|
|
33
33
|
import { execFile, execFileSync } from 'node:child_process';
|
|
@@ -59,7 +59,40 @@ import { claudeStateRoot, projectSlugForCwd, jsonlPathForSessionId, sidecarPathF
|
|
|
59
59
|
import { basename, dirname, join } from 'node:path';
|
|
60
60
|
import { validateUserTitle } from './user-title-store.js';
|
|
61
61
|
import { credentialsPathForConfigDir, snapshotAuthForFailureReason } from './auth-snapshot.js';
|
|
62
|
+
// Task 2325 — the wire subset of AgentRole. `passive` is a persona role
|
|
63
|
+
// resolved at the /public-spawn boundary from role:'public' plus the passive
|
|
64
|
+
// flag; it is deliberately absent here so no client can POST it directly.
|
|
62
65
|
const ROLES = ['admin', 'public'];
|
|
66
|
+
/** Task 2325 — the rc-spawn role, as supplied by the request body. Task 1468
|
|
67
|
+
* widened this position to allow `undefined` because rc-spawn's role was
|
|
68
|
+
* absent for a non-admin/non-public request; null now means "the body named
|
|
69
|
+
* none", and the handler resolves it against the prior sidecar before
|
|
70
|
+
* deciding whether that is an error. `passive` is not accepted here:
|
|
71
|
+
* rc-spawn composes no persona at all (its --append-system-prompt segments
|
|
72
|
+
* are reseat / voice / specialist-domains / authenticated-identity
|
|
73
|
+
* fragments, never composeAppendSystemPrompt). */
|
|
74
|
+
export function parseRcSpawnRole(body) {
|
|
75
|
+
return body.role === 'admin' || body.role === 'public' ? body.role : null;
|
|
76
|
+
}
|
|
77
|
+
/** Task 2325 — the single place a /public-spawn wire role becomes a typed one.
|
|
78
|
+
* Returns the wire role (always 'admin' or 'public', narrowed by the ROLES
|
|
79
|
+
* allowlist above) and the persona role the spawn composes from. They differ
|
|
80
|
+
* only for a passive spawn. Anything the allowlist does not name returns null
|
|
81
|
+
* and the caller refuses; nothing falls through to 'admin'.
|
|
82
|
+
*
|
|
83
|
+
* The passive condition reproduces the Task 1483 invariant exactly, moved
|
|
84
|
+
* here from pty-spawner: a passive spawn rides `role:'public'` on the wire
|
|
85
|
+
* and is never a specialist, so a passive flag on any other role or on a
|
|
86
|
+
* specialist is ignored rather than silently registering a different (e.g.
|
|
87
|
+
* full-admin) server surface while the allowlist locks to work-create. */
|
|
88
|
+
export function parseSpawnRole(body, specialist) {
|
|
89
|
+
const raw = body.role;
|
|
90
|
+
if (typeof raw !== 'string' || !ROLES.includes(raw))
|
|
91
|
+
return null;
|
|
92
|
+
const role = raw;
|
|
93
|
+
const agentRole = body.passive === true && role === 'public' && specialist === undefined ? 'passive' : role;
|
|
94
|
+
return { role, agentRole };
|
|
95
|
+
}
|
|
63
96
|
const CHANNELS = ['browser', 'whatsapp', 'telegram', 'webchat', 'email'];
|
|
64
97
|
// Task 382 — body.conversationNodeId shape gate. The value is the
|
|
65
98
|
// sessionId UUID (v4) minted by createNewAdminConversation in
|
|
@@ -1037,12 +1070,21 @@ export function buildHttpApp(deps) {
|
|
|
1037
1070
|
const userId = typeof body.userId === 'string' && body.userId.length > 0 && body.userId.length <= 128
|
|
1038
1071
|
? body.userId
|
|
1039
1072
|
: undefined;
|
|
1040
|
-
const role = typeof body.role === 'string' ? body.role : '';
|
|
1041
1073
|
const channel = typeof body.channel === 'string' ? body.channel : '';
|
|
1042
1074
|
const hidden = body.hidden === true;
|
|
1043
1075
|
const specialist = typeof body.specialist === 'string' && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist)
|
|
1044
1076
|
? body.specialist
|
|
1045
1077
|
: undefined;
|
|
1078
|
+
// Task 2325 — one parse, before any other use of the role. `role` is what
|
|
1079
|
+
// arrived on the wire; `agentRole` is which persona it resolves to. They
|
|
1080
|
+
// differ only for a passive spawn. `role` keeps its string-or-empty shape
|
|
1081
|
+
// so every existing read of it, including the spawn-request log line's
|
|
1082
|
+
// `role=${role || 'missing'}`, is unchanged.
|
|
1083
|
+
const parsedRole = parseSpawnRole(body, specialist);
|
|
1084
|
+
const role = parsedRole?.role ?? '';
|
|
1085
|
+
const agentRole = parsedRole?.agentRole ?? null;
|
|
1086
|
+
// Task 2325 — recorded before the guard so a refused spawn is counted.
|
|
1087
|
+
deps.roleCensus?.record(agentRole);
|
|
1046
1088
|
// Task 956 — public sessions are pinned to Sonnet 5 (operator decision:
|
|
1047
1089
|
// admin-only Bypass/Opus; public stays Sonnet + fail-closed dontAsk). The
|
|
1048
1090
|
// role==='public' force is the chokepoint covering every public spawn
|
|
@@ -1128,6 +1170,13 @@ export function buildHttpApp(deps) {
|
|
|
1128
1170
|
// webchatChannel above. This door could attach webchat but never WhatsApp,
|
|
1129
1171
|
// which is why the public WhatsApp route had nowhere to land before.
|
|
1130
1172
|
const waChannel = parseWaChannelBody(body.waChannel);
|
|
1173
|
+
// Task 2338 — the telegram twin. `parseWaChannelBody` is shape-identical
|
|
1174
|
+
// for telegram (senderId + http gateway + absolute server path), so it is
|
|
1175
|
+
// reused rather than duplicated. pty-spawner has accepted a
|
|
1176
|
+
// `telegramChannel` arg since the public allowlist gained its telegram arm
|
|
1177
|
+
// (pty-spawner.ts:844, public-allowlist.ts:24); this route could not supply
|
|
1178
|
+
// one, so a public telegram spawn fell through to the deny-basis allowlist.
|
|
1179
|
+
const telegramChannel = parseWaChannelBody(body.telegramChannel);
|
|
1131
1180
|
// Task 2262 — the caller's deterministic per-sender id, so a public visitor
|
|
1132
1181
|
// keeps one conversation across cold starts instead of meeting a fresh agent
|
|
1133
1182
|
// every time. Shape-gated to the same UUID v4 pattern the other id fields on
|
|
@@ -1152,10 +1201,42 @@ export function buildHttpApp(deps) {
|
|
|
1152
1201
|
: body.dormantPlugins == null ? 'absent' : typeof body.dormantPlugins;
|
|
1153
1202
|
const initialMessageBytes = typeof body.initialMessage === 'string' ? Buffer.byteLength(body.initialMessage, 'utf8') : 0;
|
|
1154
1203
|
deps.logger(`spawn-request senderId=${senderId || 'missing'} userId=${userId ? userId.slice(0, 8) : 'absent'} role=${role || 'missing'} channel=${channel || 'missing'} permissionMode=${typeof body.permissionMode === 'string' ? body.permissionMode : 'default'} channels=${Array.isArray(body.channels) ? body.channels.length : 0} attachmentDir=${typeof body.attachmentDir === 'string' ? 'set' : 'absent'} aboutOwner=${aboutOwnerShape} dormantPlugins=${dormantPluginsShape} tunnelUrl=${typeof body.tunnelUrl === 'string' ? 'set' : (body.tunnelUrl === null ? 'null' : 'absent')} initialMessageBytes=${initialMessageBytes}`);
|
|
1155
|
-
if (!senderId ||
|
|
1204
|
+
if (!senderId || parsedRole === null || agentRole === null || !CHANNELS.includes(channel)) {
|
|
1205
|
+
// Task 2325 — emitted only when the ROLE is what failed. The guard also
|
|
1206
|
+
// covers a missing senderId and a bad channel, and naming those
|
|
1207
|
+
// `role-unresolved` would make the line lie about its own cause, which
|
|
1208
|
+
// is the exact defect class this task exists to remove. The 400 body
|
|
1209
|
+
// below still reports all three fields.
|
|
1210
|
+
if (parsedRole === null) {
|
|
1211
|
+
deps.logger(`[spawn] op=role-unresolved sessionId=new role=${typeof body.role === 'string' ? body.role : String(body.role)} site=public-spawn`);
|
|
1212
|
+
}
|
|
1156
1213
|
timed(deps.logger, 'POST', '/public-spawn', 400, Date.now() - start);
|
|
1157
1214
|
return c.json({ error: 'invalid-arguments', detail: { senderId: !!senderId, role, channel } }, 400);
|
|
1158
1215
|
}
|
|
1216
|
+
// Task 2274 — a public spawn may not name a specialist. `isPublic` and
|
|
1217
|
+
// `isSpecialistSpawn` are independent in pty-spawner and the specialist
|
|
1218
|
+
// branch wins at two of the four lockdown levers: the `--allowed-tools` push
|
|
1219
|
+
// is skipped entirely, and `effectiveMode` resolves the caller-supplied mode
|
|
1220
|
+
// (defaulting to `bypassPermissions`) instead of the fail-closed `dontAsk`.
|
|
1221
|
+
// The `permissionMode` this body may also carry is parsed further down and
|
|
1222
|
+
// would be honoured on that branch, which is why the refusal sits above the
|
|
1223
|
+
// parse rather than beside it.
|
|
1224
|
+
//
|
|
1225
|
+
// Neither production issuer sends the combination: the channel bridge
|
|
1226
|
+
// (`manager-client.ts`) is the only one whose role can be 'public' and it
|
|
1227
|
+
// carries no `specialist` field, while the cookie-auth wrapper
|
|
1228
|
+
// (`claude-sessions.ts`) types its role as the literal 'admin'. Refusing
|
|
1229
|
+
// states that invariant at the door; `spawnClaudeSession` refuses the same
|
|
1230
|
+
// pairing again at the chokepoint, so a future route cannot reinherit it.
|
|
1231
|
+
//
|
|
1232
|
+
// `specialist` here is the shape-gated value, so a body whose field failed
|
|
1233
|
+
// the slug pattern resolved to undefined and is an ordinary public spawn —
|
|
1234
|
+
// the same value the spawner would have seen.
|
|
1235
|
+
if (role === 'public' && specialist !== undefined) {
|
|
1236
|
+
deps.logger(`[spawn] op=public-specialist-refused site=public-spawn specialist=${specialist} channel=${channel} senderId=${senderId}`);
|
|
1237
|
+
timed(deps.logger, 'POST', '/public-spawn', 400, Date.now() - start);
|
|
1238
|
+
return c.json({ error: 'specialist-not-permitted-on-public', detail: { specialist } }, 400);
|
|
1239
|
+
}
|
|
1159
1240
|
// Task 1489 — a passive intake spawn rides role:'public' on this path but is
|
|
1160
1241
|
// a trusted, sub-account-bound account manager, not an anonymous visitor. It
|
|
1161
1242
|
// is exempt from the anonymous-visitor limiter: `!passive` keeps a manager's
|
|
@@ -1266,6 +1347,22 @@ export function buildHttpApp(deps) {
|
|
|
1266
1347
|
deps.logger(`[spawn] op=agent-account-scope route=public-spawn account=${agentAccountId} applied=true`);
|
|
1267
1348
|
}
|
|
1268
1349
|
}
|
|
1350
|
+
// Task 2338 — the write-through /rc-spawn has always made (:3336, :3346,
|
|
1351
|
+
// :3355) and this route never did. Without it a session first spawned here
|
|
1352
|
+
// has no binding on disk, so the stuck-turn recycler has nothing to re-post
|
|
1353
|
+
// and the respawn loses the visitor's reply transport. A public spawn is
|
|
1354
|
+
// wa XOR webchat XOR telegram (pty-spawner.ts:1893), so at most one of
|
|
1355
|
+
// these fires. Gated on a caller-supplied sessionId because that is the
|
|
1356
|
+
// only id that exists before the spawn returns; a route that mints its own
|
|
1357
|
+
// id has no session to key on and no recycler re-post to serve.
|
|
1358
|
+
if (callerSessionId) {
|
|
1359
|
+
if (waChannel)
|
|
1360
|
+
deps.waChannelStore.set(callerSessionId, waChannel);
|
|
1361
|
+
if (webchatChannel)
|
|
1362
|
+
deps.webchatChannelStore?.set(callerSessionId, webchatChannel);
|
|
1363
|
+
if (telegramChannel)
|
|
1364
|
+
deps.telegramChannelStore?.set(callerSessionId, telegramChannel);
|
|
1365
|
+
}
|
|
1269
1366
|
const result = await spawnClaudeSession({
|
|
1270
1367
|
...deps,
|
|
1271
1368
|
spawnCwd,
|
|
@@ -1282,7 +1379,7 @@ export function buildHttpApp(deps) {
|
|
|
1282
1379
|
if (!passive) {
|
|
1283
1380
|
// Task 2271 — `spawnCwd` here is the re-scoped value, so the audit
|
|
1284
1381
|
// follows a public-agent session into its own account's slug.
|
|
1285
|
-
attachPublicAudit(deps, tracker.sessionId, role, spawnCwd);
|
|
1382
|
+
attachPublicAudit(deps, tracker.sessionId, parsedRole.role, spawnCwd);
|
|
1286
1383
|
// Task 2262 — the exit notify is webchat machinery: the route it
|
|
1287
1384
|
// calls resolves the sessionId against the WEBCHAT gateway's
|
|
1288
1385
|
// publicSessions map to fire a slice-review, so a WhatsApp public
|
|
@@ -1292,7 +1389,7 @@ export function buildHttpApp(deps) {
|
|
|
1292
1389
|
// because a WhatsApp visitor's realised tool surface is exactly what
|
|
1293
1390
|
// Task 2260 wants audited.
|
|
1294
1391
|
if (channel !== 'whatsapp') {
|
|
1295
|
-
attachPublicExitNotify(tracker.sessionId, role, deps.logger);
|
|
1392
|
+
attachPublicExitNotify(tracker.sessionId, parsedRole.role, deps.logger);
|
|
1296
1393
|
}
|
|
1297
1394
|
}
|
|
1298
1395
|
attachSpecialistEndTurnAutoArchive(deps, tracker.sessionId, tracker.specialist);
|
|
@@ -1304,7 +1401,10 @@ export function buildHttpApp(deps) {
|
|
|
1304
1401
|
}, {
|
|
1305
1402
|
senderId,
|
|
1306
1403
|
userId,
|
|
1307
|
-
role
|
|
1404
|
+
// Task 2325 — the PERSONA role the spawn composes from, resolved by
|
|
1405
|
+
// the boundary parse above. No cast: `agentRole` is non-null past the
|
|
1406
|
+
// guard. The wire role stays on the sidecar (pty-spawner maps it back).
|
|
1407
|
+
role: agentRole,
|
|
1308
1408
|
channel: channel,
|
|
1309
1409
|
channels,
|
|
1310
1410
|
permissionMode,
|
|
@@ -1324,9 +1424,9 @@ export function buildHttpApp(deps) {
|
|
|
1324
1424
|
visitorId,
|
|
1325
1425
|
webchatChannel,
|
|
1326
1426
|
waChannel,
|
|
1427
|
+
telegramChannel,
|
|
1327
1428
|
...sessionIdFields,
|
|
1328
1429
|
previousContext,
|
|
1329
|
-
passive,
|
|
1330
1430
|
targetAccountId,
|
|
1331
1431
|
// Task 2271 — the RESOLVED variable, not the parsed field: when the
|
|
1332
1432
|
// same-slug rule declines the re-scope, the sidecar stays at the house
|
|
@@ -2692,7 +2792,11 @@ export function buildHttpApp(deps) {
|
|
|
2692
2792
|
// session-end review) supply no channel and get no sidecar. Task 852 widens
|
|
2693
2793
|
// the accepted role to 'public' (authenticated-public WhatsApp person) and
|
|
2694
2794
|
// the sidecar records the actual role.
|
|
2695
|
-
|
|
2795
|
+
// Task 2325 — the BODY's role. Null when absent or unrecognised. A
|
|
2796
|
+
// channel-bound resume legitimately omits it and inherits from its prior
|
|
2797
|
+
// sidecar, so the refusal is not here; it is where both sources have been
|
|
2798
|
+
// consulted, just below `priorSidecar`.
|
|
2799
|
+
const rcRole = parseRcSpawnRole(body);
|
|
2696
2800
|
const adminChannel = typeof body.channel === 'string' && CHANNELS.includes(body.channel)
|
|
2697
2801
|
? body.channel
|
|
2698
2802
|
: undefined;
|
|
@@ -3035,11 +3139,67 @@ export function buildHttpApp(deps) {
|
|
|
3035
3139
|
// yields null; the gate degrades to the not-resolvable identity form.
|
|
3036
3140
|
// Task 1214 — widened from webchat-only to any channel-bound session so the
|
|
3037
3141
|
// admin-role signal resolves for WhatsApp/Telegram resumes that omit role
|
|
3038
|
-
// too (the voice-contract gate below keys on `adminBinding`).
|
|
3039
|
-
// channel-
|
|
3040
|
-
|
|
3041
|
-
|
|
3142
|
+
// too (the voice-contract gate below keys on `adminBinding`).
|
|
3143
|
+
// Task 2325 — widened again to EVERY resume, channel-bound or not, so the
|
|
3144
|
+
// role can be inherited from disk before the refusal below. The dropped
|
|
3145
|
+
// "channel-less resumes skip the disk touch" optimisation cost one small
|
|
3146
|
+
// readFileSync on a path that then spawns a PTY. Without it, the bare
|
|
3147
|
+
// `{ sessionId }` resumes that wedged-session recovery (index.ts, the
|
|
3148
|
+
// recoverWedgedSession resumeSpawn) and the re-seat route send would be
|
|
3149
|
+
// refused for carrying no role, when their role has been on disk all along.
|
|
3150
|
+
// Task 2267 — the whole read outcome, not just the sidecar. `readSidecar`
|
|
3151
|
+
// returns `ok` | `missing` | `parse-failed` and both failure verdicts yield
|
|
3152
|
+
// a null sidecar, so collapsing to `.sidecar` here made a damaged file
|
|
3153
|
+
// indistinguishable from a session that legitimately has none. The lockdown
|
|
3154
|
+
// gate below and the resolution line both read the verdict.
|
|
3155
|
+
const priorSidecarRead = sessionId
|
|
3156
|
+
? readSidecar(sidecarPathForSessionId(effectiveAccountDir, sessionId), deps.logger)
|
|
3042
3157
|
: null;
|
|
3158
|
+
const priorSidecar = priorSidecarRead?.sidecar ?? null;
|
|
3159
|
+
// Task 2325 — the session's role, from the body or inherited from disk.
|
|
3160
|
+
// The refusal sits here rather than at the body parse because an absent
|
|
3161
|
+
// `role` has THREE legitimate readings and only one of them is an error:
|
|
3162
|
+
// 1. a channel-bound resume, which inherits from `priorSidecar` (Task
|
|
3163
|
+
// 2260's own words: "a resume omits `role` in the body");
|
|
3164
|
+
// 2. a one-shot admin job, which is not a channel conversation — those
|
|
3165
|
+
// now pass role:'admin' and are told apart by their absent `channel`,
|
|
3166
|
+
// which is what the classification-sidecar gate below reads;
|
|
3167
|
+
// 3. a caller that simply supplied none on a FRESH spawn, which is the
|
|
3168
|
+
// error. Before this it became `undefined` and rode on, and
|
|
3169
|
+
// `sessionRole=undefined` was documented (Task 1468) as a value to
|
|
3170
|
+
// preserve rather than treated as a fault.
|
|
3171
|
+
//
|
|
3172
|
+
// The `mode === 'fresh'` half of the gate is load-bearing, not caution. A
|
|
3173
|
+
// resume that inherits nothing is the claude.ai/code bridge: the bare
|
|
3174
|
+
// admin-host branch of session-rc-spawn.ts posts `{ sessionId, name }`
|
|
3175
|
+
// with no role and no channel, and wedged-session recovery posts
|
|
3176
|
+
// `{ sessionId }`. Both resume a session whose role predates the request.
|
|
3177
|
+
// Refusing them would take out a core operator surface to close a hole
|
|
3178
|
+
// that only a fresh spawn can open: a resume composes no new persona,
|
|
3179
|
+
// and rc-spawn composes none at all.
|
|
3180
|
+
const effectiveRcRole = rcRole ?? priorSidecar?.role ?? null;
|
|
3181
|
+
// Task 2325 — recorded before the refusal so a refused spawn is counted.
|
|
3182
|
+
deps.roleCensus?.record(effectiveRcRole);
|
|
3183
|
+
if (effectiveRcRole === null && mode === 'fresh') {
|
|
3184
|
+
deps.logger(`[rc-spawn] op=role-unresolved sessionId=${sessionId ? sessionId.slice(0, 8) : 'new'} role=${String(body.role)} site=rc-spawn`);
|
|
3185
|
+
timed(deps.logger, 'POST', '/rc-spawn', 400, Date.now() - start);
|
|
3186
|
+
return c.json({ error: 'invalid-arguments', detail: { role: body.role ?? null } }, 400);
|
|
3187
|
+
}
|
|
3188
|
+
// Task 2267 — one line per channel-bound rc-spawn naming where the role came
|
|
3189
|
+
// from. Emitted only for a channel-bound spawn: a one-shot admin job has no
|
|
3190
|
+
// channel and no sidecar, so a line on every rc-spawn would be dominated by
|
|
3191
|
+
// that benign case. `source=unresolved` is the fail-closed spawn, and the
|
|
3192
|
+
// outcome behind it separates a deleted sidecar from a corrupted one.
|
|
3193
|
+
// Hoisted from the Task 1214 voice gate below, which reads the same value
|
|
3194
|
+
// and now shares this one binding.
|
|
3195
|
+
const channelBound = !!(effectiveWebchatChannel || effectiveWaChannel || effectiveTelegramChannel);
|
|
3196
|
+
if (sessionId && channelBound) {
|
|
3197
|
+
deps.logger(formatRoleResolutionLine({
|
|
3198
|
+
sessionId,
|
|
3199
|
+
source: rcRole ? 'body' : priorSidecar?.role ? 'sidecar' : 'unresolved',
|
|
3200
|
+
outcome: priorSidecarRead?.outcome ?? 'missing',
|
|
3201
|
+
}));
|
|
3202
|
+
}
|
|
3043
3203
|
// Task 850 — assemble the bound target set and choose the channel server:
|
|
3044
3204
|
// - ≥2 kinds: ONE unified `channel` server (one reply tool fanning to every
|
|
3045
3205
|
// target's existing gateway endpoint). The mature per-kind servers are
|
|
@@ -3136,7 +3296,9 @@ export function buildHttpApp(deps) {
|
|
|
3136
3296
|
gatewayUrl: effectiveTelegramChannel.gatewayUrl,
|
|
3137
3297
|
serverPath: effectiveTelegramChannel.serverPath,
|
|
3138
3298
|
nodeBin: deps.nodeBin,
|
|
3139
|
-
role
|
|
3299
|
+
// Task 2325 — the body role, unchanged in meaning; `?? undefined`
|
|
3300
|
+
// only bridges null to the optional parameter this builder declares.
|
|
3301
|
+
role: rcRole ?? undefined,
|
|
3140
3302
|
});
|
|
3141
3303
|
telegramPath = telegramChannelMcpConfigPath(sessionId, tmpdir());
|
|
3142
3304
|
try {
|
|
@@ -3158,9 +3320,28 @@ export function buildHttpApp(deps) {
|
|
|
3158
3320
|
// the first. `priorSidecar` is already read for any channel-bound session,
|
|
3159
3321
|
// which is every public spawn that can reply. Pushed after the channel argv
|
|
3160
3322
|
// so `--strict-mcp-config` leaves exactly the per-spawn channel server
|
|
3161
|
-
// registered; `admin`
|
|
3162
|
-
|
|
3163
|
-
|
|
3323
|
+
// registered; an `admin` spawn produces byte-identical argv.
|
|
3324
|
+
// Task 2325 — resolved once, above, beside the refusal.
|
|
3325
|
+
//
|
|
3326
|
+
// Task 2267 — a null role on a channel-bound spawn takes the lockdown too.
|
|
3327
|
+
// `effectiveRcRole` is null when neither the body nor the sidecar produced a
|
|
3328
|
+
// role, and a live public session always had a sidecar written at spawn
|
|
3329
|
+
// (pty-spawner kills the PTY when that write throws), so null on a
|
|
3330
|
+
// channel-bound session means the file was damaged after the spawn
|
|
3331
|
+
// succeeded, not that the session is legitimately roleless. Reaching here
|
|
3332
|
+
// with null is always a resume: a fresh spawn with no resolvable role is
|
|
3333
|
+
// refused with a 400 above, so no mode test is added. A roleless spawn with
|
|
3334
|
+
// NO channel binding — the one-shot admin jobs and the bare claude.ai/code
|
|
3335
|
+
// bridge resume — still produces byte-identical argv.
|
|
3336
|
+
//
|
|
3337
|
+
// The cost is stated rather than hidden. A channel-bound ADMIN resume whose
|
|
3338
|
+
// sidecar is unreadable comes back holding only its channel reply tool, and
|
|
3339
|
+
// stays that way on every later resume, because the sidecar write below is
|
|
3340
|
+
// itself gated on a non-null role and so never repairs the file. The
|
|
3341
|
+
// `op=role-resolution` line above is what makes that state greppable.
|
|
3342
|
+
const publicLockdown = effectiveRcRole === 'public' || (effectiveRcRole === null && channelBound)
|
|
3343
|
+
? buildRcPublicLockdownArgv(channelServerName)
|
|
3344
|
+
: null;
|
|
3164
3345
|
if (publicLockdown) {
|
|
3165
3346
|
// A re-seat fork pushes its own caller-picked --permission-mode above,
|
|
3166
3347
|
// before the role is known. Two conflicting flags do not reliably
|
|
@@ -3202,7 +3383,9 @@ export function buildHttpApp(deps) {
|
|
|
3202
3383
|
// overlay: a missing/empty/headingless file degrades to no voice segment and
|
|
3203
3384
|
// never fails the spawn. `voiceBytes` rides the op=argv line as the
|
|
3204
3385
|
// at-a-glance present/absent signal whose absence hid this bug.
|
|
3205
|
-
|
|
3386
|
+
// Task 2267 — `channelBound` was declared here; it is now resolved once,
|
|
3387
|
+
// beside the role resolution above, because the public lockdown gate needs
|
|
3388
|
+
// the same value earlier. Same expression, same meaning.
|
|
3206
3389
|
let voiceBytes = 0;
|
|
3207
3390
|
if (adminBinding && channelBound) {
|
|
3208
3391
|
let voice = null;
|
|
@@ -3279,7 +3462,25 @@ export function buildHttpApp(deps) {
|
|
|
3279
3462
|
// (effectiveAccountId !== house) spawns — fail-closed, no escalation.
|
|
3280
3463
|
const acctIsHouse = isHouseAccount(deps.platformRoot, effectiveAccountId);
|
|
3281
3464
|
const rcHouseAdminScope = houseAdminScopeFor({
|
|
3282
|
-
role
|
|
3465
|
+
// Task 2335 — the SESSION's role (body, else prior sidecar), not the
|
|
3466
|
+
// body's `rcRole` alone. A resume that omits the role — the stuck-turn
|
|
3467
|
+
// recycler posts `{ sessionId, targetAccountId }` — used to fail the
|
|
3468
|
+
// `role === 'admin'` test and come back with no cross-account authority
|
|
3469
|
+
// while the same session's fresh spawn carried it. That divergence was
|
|
3470
|
+
// measured on one house session as a single `inject=false` line between
|
|
3471
|
+
// four `inject=true` lines, on the recycle resume 21s after a wedge kill.
|
|
3472
|
+
// Inheriting is not a widening, for two reasons that hold together. The
|
|
3473
|
+
// sidecar is read from `sidecarPathForSessionId(effectiveAccountDir, …)`
|
|
3474
|
+
// above — the SAME account that decides `isHouse` — so an inherited role
|
|
3475
|
+
// can only come from the resolved account's own record of this session;
|
|
3476
|
+
// a sub-account session resumed against the house account finds no
|
|
3477
|
+
// sidecar there and resolves null. And that record is read back through
|
|
3478
|
+
// the `['admin','public']` allowlist in `parseSidecar`, which rejects the
|
|
3479
|
+
// whole row on anything else, so the only role that can arrive here from
|
|
3480
|
+
// disk and open the gate is the `admin` this session's own fresh spawn
|
|
3481
|
+
// asserted on this account. `isHouse` still excludes every sub-account
|
|
3482
|
+
// resume on top of that.
|
|
3483
|
+
role: effectiveRcRole,
|
|
3283
3484
|
accountId: effectiveAccountId,
|
|
3284
3485
|
isHouse: acctIsHouse,
|
|
3285
3486
|
isSpecialist: false,
|
|
@@ -3290,7 +3491,12 @@ export function buildHttpApp(deps) {
|
|
|
3290
3491
|
// line makes the rc-spawn decision greppable per spawn.
|
|
3291
3492
|
deps.logger(formatHouseScopeInjectLine({
|
|
3292
3493
|
sessionId,
|
|
3293
|
-
|
|
3494
|
+
// Task 2325 — the session's role, so this line can no longer render
|
|
3495
|
+
// `sessionRole=undefined`. A resume that inherits no role renders the
|
|
3496
|
+
// explicit token `none`, matching the idiom this handler already uses
|
|
3497
|
+
// for the same value below. A stringified absence read as a formatting
|
|
3498
|
+
// artefact, which is how an unnamed role stayed invisible for two tasks.
|
|
3499
|
+
sessionRole: effectiveRcRole ?? 'none',
|
|
3294
3500
|
acctIsHouse,
|
|
3295
3501
|
inject: rcHouseAdminScope !== null,
|
|
3296
3502
|
}));
|
|
@@ -3424,6 +3630,15 @@ export function buildHttpApp(deps) {
|
|
|
3424
3630
|
strictMcp: publicLockdown !== null,
|
|
3425
3631
|
mode: effectiveRcPermissionMode,
|
|
3426
3632
|
}));
|
|
3633
|
+
// Task 2339 — the realised-surface hook's only input. `tool-allowlist` above
|
|
3634
|
+
// records the surface this spawn was GIVEN; nothing recorded the surface it
|
|
3635
|
+
// REALISES, so five tools ran under a one-tool allowlist and produced no
|
|
3636
|
+
// line. Stamped here rather than inside buildRcChildEnv so it lands after
|
|
3637
|
+
// the last argv push and the value is this spawn's final `--allowed-tools`
|
|
3638
|
+
// set. Public spawns only; its presence is the signal the hook keys on.
|
|
3639
|
+
if (publicLockdown) {
|
|
3640
|
+
env[PUBLIC_ALLOWED_TOOLS_ENV] = allowedToolsFromArgv(argv).join(',');
|
|
3641
|
+
}
|
|
3427
3642
|
deps.logger(`[rc-spawn] op=argv unitToken=${unitToken} cwd=${effectiveAccountDir} permissionMode=${effectiveRcPermissionMode} model=${effectiveRcModel ?? 'unset'} effort=${effectiveRcEffort ?? 'unset'} positionalBytes=${positionalBytes} voiceBytes=${voiceBytes} argv=${JSON.stringify([deps.claudeBin, ...argv])}`);
|
|
3428
3643
|
emitRcLife(deps.logger, 'argv', 'rc-spawn', 'node-pty', rcLifeMode, unitToken, {
|
|
3429
3644
|
cwd: effectiveAccountDir,
|
|
@@ -3509,18 +3724,31 @@ export function buildHttpApp(deps) {
|
|
|
3509
3724
|
// when one exists. Non-fatal: the PTY here is already serving a live thread —
|
|
3510
3725
|
// a failed classification sidecar must not tear it down, so it logs and the
|
|
3511
3726
|
// session keeps running (the pre-fix reader-blind behaviour, no worse).
|
|
3512
|
-
|
|
3727
|
+
// Task 2325 — the sidecar is written for a channel conversation. What
|
|
3728
|
+
// distinguishes one from a one-shot admin job is the CHANNEL, not whether
|
|
3729
|
+
// a role was supplied: the LinkedIn ingest and the public session-end
|
|
3730
|
+
// review are role:'admin' and pass no channel, and they still get no
|
|
3731
|
+
// sidecar. Before this the absent role carried both meanings at once.
|
|
3732
|
+
const classifyChannel = adminChannel;
|
|
3513
3733
|
const classifySenderId = adminSenderId ?? effectiveWaChannel?.senderId ?? effectiveWebchatChannel?.key ?? effectiveTelegramChannel?.senderId;
|
|
3514
|
-
|
|
3734
|
+
// Task 2325 — `effectiveRcRole !== null` joins the guard rather than being
|
|
3735
|
+
// cast away. The sidecar's `role` is read back through an allowlist that
|
|
3736
|
+
// rejects the whole row on a bad value, so a session with no resolvable
|
|
3737
|
+
// role gets NO sidecar rather than one recording an absence.
|
|
3738
|
+
if (sessionId && classifyChannel && classifySenderId && effectiveRcRole !== null) {
|
|
3515
3739
|
const classifySidecarPath = sidecarPathForSessionId(effectiveAccountDir, sessionId);
|
|
3516
3740
|
if (!existsSync(classifySidecarPath)) {
|
|
3517
3741
|
try {
|
|
3518
3742
|
writeSidecar(classifySidecarPath, {
|
|
3519
3743
|
senderId: classifySenderId,
|
|
3520
|
-
// Task 852 — the actual role
|
|
3521
|
-
//
|
|
3522
|
-
//
|
|
3523
|
-
|
|
3744
|
+
// Task 852 — the actual role, not a hardcoded 'admin'. Task 2325
|
|
3745
|
+
// — the effective role (body, else inherited from disk),
|
|
3746
|
+
// non-null by the guard above. The old
|
|
3747
|
+
// `rcRole as 'admin' | 'public'` relied on this gate being
|
|
3748
|
+
// role-derived; the gate now reads the channel, so without the
|
|
3749
|
+
// guard a resume with a channel and no body role would have
|
|
3750
|
+
// written a cast `undefined` into the sidecar.
|
|
3751
|
+
role: effectiveRcRole,
|
|
3524
3752
|
channel: classifyChannel,
|
|
3525
3753
|
url: null,
|
|
3526
3754
|
startedAt: new Date().toISOString(),
|
|
@@ -3562,6 +3790,11 @@ export function buildHttpApp(deps) {
|
|
|
3562
3790
|
// into the child env above (rcHouseAdminScope), so env and sidecar
|
|
3563
3791
|
// are one decision with two consumers and can never drift again.
|
|
3564
3792
|
houseAdminScope: rcHouseAdminScope,
|
|
3793
|
+
// Task 2338 — the route that produced this process. Only
|
|
3794
|
+
// /public-spawn composes a persona, so a `public` role recorded
|
|
3795
|
+
// here with route `rc-spawn` is a session running without its
|
|
3796
|
+
// soul file, which is what the persona audit counts.
|
|
3797
|
+
spawnRoute: 'rc-spawn',
|
|
3565
3798
|
}, deps.logger);
|
|
3566
3799
|
deps.watcher.refreshSidecar?.(sessionId);
|
|
3567
3800
|
}
|
|
@@ -3578,6 +3811,34 @@ export function buildHttpApp(deps) {
|
|
|
3578
3811
|
deps.watcher.refreshSidecar?.(sessionId);
|
|
3579
3812
|
}
|
|
3580
3813
|
}
|
|
3814
|
+
// Task 2338 — the route stamp sits OUTSIDE the classification block above,
|
|
3815
|
+
// and that placement is the whole point. That block is gated on a channel
|
|
3816
|
+
// in the request BODY (`adminChannel`, :3037), and the resume shapes that
|
|
3817
|
+
// matter here carry none: the claude.ai/code bridge posts
|
|
3818
|
+
// `{ sessionId, name }` and wedged-session recovery posts `{ sessionId }`
|
|
3819
|
+
// (see the note at :3390). Inside the block, a bare resume of a public
|
|
3820
|
+
// session would leave `spawnRoute` reading `public-spawn` and the persona
|
|
3821
|
+
// audit would report zero through a live defect — which is exactly the
|
|
3822
|
+
// 2026-08-01 sequence this task exists to make visible.
|
|
3823
|
+
//
|
|
3824
|
+
// Patched, never written fresh: with no prior sidecar there is no row to
|
|
3825
|
+
// record a route on, and inventing one here would bypass the role/channel
|
|
3826
|
+
// allowlist the write above enforces. Patched only when the value would
|
|
3827
|
+
// change, so a repeated rc-spawn resume does not rewrite the file each turn.
|
|
3828
|
+
if (sessionId && priorSidecar && priorSidecar.spawnRoute !== 'rc-spawn') {
|
|
3829
|
+
const routeSidecarPath = sidecarPathForSessionId(effectiveAccountDir, sessionId);
|
|
3830
|
+
try {
|
|
3831
|
+
const patched = updateSidecar(routeSidecarPath, { spawnRoute: 'rc-spawn' }, deps.logger);
|
|
3832
|
+
if (patched)
|
|
3833
|
+
deps.watcher.refreshSidecar?.(sessionId);
|
|
3834
|
+
}
|
|
3835
|
+
catch (err) {
|
|
3836
|
+
// Non-fatal, same contract as the classification write: the PTY here is
|
|
3837
|
+
// already serving a live thread and a diagnostic write must not tear it
|
|
3838
|
+
// down.
|
|
3839
|
+
deps.logger(`[rc-spawn] op=spawn-route-patch-failed sessionId=${sessionId.slice(0, 8)} err=${JSON.stringify(err instanceof Error ? err.message : String(err))}`);
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3581
3842
|
// Task 626 — one-shot job (LinkedIn ingest, public session-end review):
|
|
3582
3843
|
// stop the PTY once its single assistant turn lands `end_turn`. closeAfterTurn
|
|
3583
3844
|
// implies a sessionId (validated above), so trackerKey === sessionId and the
|