@rubytech/create-maxy-code 0.1.539 → 0.1.541
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/agent-slug/dist/index.d.ts +31 -0
- package/payload/platform/lib/agent-slug/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/agent-slug/dist/index.js +53 -0
- package/payload/platform/lib/agent-slug/dist/index.js.map +1 -0
- package/payload/platform/lib/agent-slug/src/index.ts +53 -0
- package/payload/platform/lib/agent-slug/tsconfig.json +8 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +33 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +136 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-config-schema.d.ts +9 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-config-schema.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-config-schema.js +49 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-config-schema.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.d.ts +64 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.js +151 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.js.map +1 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +81 -13
- package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +36 -20
- package/payload/platform/plugins/admin/skills/update-knowledge/SKILL.md +4 -3
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +12 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +47 -0
- package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +31 -10
- package/payload/platform/plugins/docs/references/internals.md +2 -2
- package/payload/platform/plugins/whatsapp/PLUGIN.md +2 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/config-forwards-every-declared-field.test.d.ts +2 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/config-forwards-every-declared-field.test.d.ts.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/config-forwards-every-declared-field.test.js +57 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/config-forwards-every-declared-field.test.js.map +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/deliverability-grounding.test.js +9 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/deliverability-grounding.test.js.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +8 -3
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +3 -3
- package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +3 -1
- package/payload/platform/scripts/__tests__/check-plugin-tool-declarations.test.ts +51 -0
- package/payload/platform/scripts/check-no-live-location-claims.mjs +73 -0
- package/payload/platform/scripts/check-plugin-tool-declarations.mjs +97 -0
- package/payload/platform/scripts/check-risk-class.mjs +5 -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 +8 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/channel-targets.d.ts +3 -0
- package/payload/platform/services/claude-session-manager/dist/channel-targets.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/channel-targets.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +20 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +76 -46
- 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.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +57 -8
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-knowledge-audit.d.ts +58 -0
- package/payload/platform/services/claude-session-manager/dist/public-knowledge-audit.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/public-knowledge-audit.js +152 -0
- package/payload/platform/services/claude-session-manager/dist/public-knowledge-audit.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts +4 -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 +3 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +40 -3
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +43 -4
- 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 +41 -25
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +1 -0
- 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-BP7LH7MC.js → chunk-CKTHAHL4.js} +26 -16
- package/payload/server/{chunk-IALJPXIO.js → chunk-ERIM3EFB.js} +1 -1
- package/payload/server/{chunk-S4FIEM3L.js → chunk-HZP7BKBF.js} +64 -98
- package/payload/server/{manager-5QV2EAZ2.js → manager-CM55K4J2.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-DuFCjbz2.js +1 -0
- 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 +2 -0
- 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 +1 -0
- 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 +1 -0
- 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 +1 -0
- 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 +1 -0
- 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 +1 -0
- 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 +1 -0
- 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 +1 -0
- package/payload/server/public/assets/chevron-left-BE16BJnw.js.br +0 -0
- package/payload/server/public/assets/chevron-right-Bu2VKpeU.js +1 -0
- package/payload/server/public/assets/chevron-right-Bu2VKpeU.js.br +0 -0
- package/payload/server/public/assets/clock-C4Nu2aRV.js +1 -0
- package/payload/server/public/assets/clock-C4Nu2aRV.js.br +0 -0
- package/payload/server/public/assets/copy-3kj9Oaoc.js +1 -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 +1 -0
- package/payload/server/public/assets/data-C-x5EHyi.js.br +1 -0
- package/payload/server/public/assets/data-C-x5EHyi.js.gz +0 -0
- package/payload/server/public/assets/file-text-CBaewT76.js +1 -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-C8cQ6Nqf.js → graph-B8-e2_Z-.js} +3 -3
- 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 +1 -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 +1 -0
- 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 +1 -0
- 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 +32 -0
- 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 +1 -0
- 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 +1 -0
- 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 +1 -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 +2 -0
- 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 +1 -0
- 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 +3 -0
- 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 +1 -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 +1 -0
- 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/{useSubAccountSwitcher-C7TtIbR3.js → useMediaQuery-CA6dR5iz.js} +1 -1
- package/payload/server/public/assets/useMediaQuery-CA6dR5iz.js.br +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-C7TtIbR3.js.gz → useMediaQuery-CA6dR5iz.js.gz} +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-DCkivCBS.css → useMediaQuery-DpwgV1Da.css} +1 -1
- package/payload/server/public/assets/useMediaQuery-DpwgV1Da.css.br +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-DCkivCBS.css.gz → useMediaQuery-DpwgV1Da.css.gz} +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DGhsN7nV.js +2 -0
- 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 +1 -0
- package/payload/server/public/assets/wrench-CpCOYUBc.js.br +0 -0
- package/payload/server/public/assets/wrench-CpCOYUBc.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 +329 -104
- package/payload/server/public/assets/AdminLoginScreens-BpHnjHp_.js +0 -1
- package/payload/server/public/assets/AdminLoginScreens-BpHnjHp_.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-BpHnjHp_.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-D24evn4t.js +0 -2
- package/payload/server/public/assets/AdminShell-D24evn4t.js.br +0 -0
- package/payload/server/public/assets/AdminShell-D24evn4t.js.gz +0 -0
- package/payload/server/public/assets/activity-ZVUTB5uZ.js +0 -1
- package/payload/server/public/assets/activity-ZVUTB5uZ.js.br +0 -0
- package/payload/server/public/assets/activity-ZVUTB5uZ.js.gz +0 -0
- package/payload/server/public/assets/admin-XJqQz3QJ.js +0 -1
- package/payload/server/public/assets/admin-XJqQz3QJ.js.br +0 -0
- package/payload/server/public/assets/admin-XJqQz3QJ.js.gz +0 -0
- package/payload/server/public/assets/agents-Dc9SNC9N.js +0 -1
- package/payload/server/public/assets/agents-Dc9SNC9N.js.br +0 -0
- package/payload/server/public/assets/agents-Dc9SNC9N.js.gz +0 -0
- package/payload/server/public/assets/browser-CCedMIga.js +0 -1
- package/payload/server/public/assets/browser-CCedMIga.js.br +0 -0
- package/payload/server/public/assets/browser-CCedMIga.js.gz +0 -0
- package/payload/server/public/assets/calendar-BDoMLP2j.js +0 -1
- package/payload/server/public/assets/calendar-BDoMLP2j.js.br +0 -0
- package/payload/server/public/assets/calendar-BDoMLP2j.js.gz +0 -0
- package/payload/server/public/assets/chat-BAhoqTY9.js +0 -1
- package/payload/server/public/assets/chat-BAhoqTY9.js.br +0 -0
- package/payload/server/public/assets/chat-BAhoqTY9.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-NGLHgPjF.js +0 -1
- package/payload/server/public/assets/chevron-right-B4B7OkG8.js +0 -1
- package/payload/server/public/assets/chevron-right-B4B7OkG8.js.br +0 -0
- package/payload/server/public/assets/clock-7IMwxJdH.js +0 -1
- package/payload/server/public/assets/clock-7IMwxJdH.js.br +0 -0
- package/payload/server/public/assets/clock-7IMwxJdH.js.gz +0 -0
- package/payload/server/public/assets/copy-PkR4EFD6.js +0 -1
- package/payload/server/public/assets/copy-PkR4EFD6.js.br +0 -0
- package/payload/server/public/assets/copy-PkR4EFD6.js.gz +0 -0
- package/payload/server/public/assets/data-yQYhw2IR.js +0 -1
- package/payload/server/public/assets/data-yQYhw2IR.js.br +0 -1
- package/payload/server/public/assets/data-yQYhw2IR.js.gz +0 -0
- package/payload/server/public/assets/file-text-BA9p7TLU.js +0 -1
- package/payload/server/public/assets/file-text-BA9p7TLU.js.br +0 -0
- package/payload/server/public/assets/file-text-BA9p7TLU.js.gz +0 -0
- package/payload/server/public/assets/graph-C8cQ6Nqf.js.br +0 -0
- package/payload/server/public/assets/graph-C8cQ6Nqf.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-CiK412vE.js +0 -1
- package/payload/server/public/assets/graph-labels-CiK412vE.js.br +0 -0
- package/payload/server/public/assets/graph-labels-CiK412vE.js.gz +0 -0
- package/payload/server/public/assets/operator-CaQAEUBu.js +0 -1
- package/payload/server/public/assets/operator-CaQAEUBu.js.br +0 -0
- package/payload/server/public/assets/operator-CaQAEUBu.js.gz +0 -0
- package/payload/server/public/assets/page-CpJpyoPS.js +0 -32
- package/payload/server/public/assets/page-CpJpyoPS.js.br +0 -0
- package/payload/server/public/assets/page-CpJpyoPS.js.gz +0 -0
- package/payload/server/public/assets/page-D0ShNyGE.js +0 -1
- package/payload/server/public/assets/page-D0ShNyGE.js.br +0 -0
- package/payload/server/public/assets/page-D0ShNyGE.js.gz +0 -0
- package/payload/server/public/assets/play-huZpq9ra.js +0 -1
- package/payload/server/public/assets/play-huZpq9ra.js.br +0 -0
- package/payload/server/public/assets/play-huZpq9ra.js.gz +0 -0
- package/payload/server/public/assets/public--8RWWGjF.js +0 -1
- package/payload/server/public/assets/public--8RWWGjF.js.br +0 -0
- package/payload/server/public/assets/public--8RWWGjF.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-g7l4ZSR3.js +0 -1
- package/payload/server/public/assets/rotate-ccw-g7l4ZSR3.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-g7l4ZSR3.js.gz +0 -0
- package/payload/server/public/assets/routines-DzFcPNMb.js +0 -2
- package/payload/server/public/assets/routines-DzFcPNMb.js.br +0 -0
- package/payload/server/public/assets/routines-DzFcPNMb.js.gz +0 -0
- package/payload/server/public/assets/skills-5vl_Bt9U.js +0 -1
- package/payload/server/public/assets/skills-5vl_Bt9U.js.br +0 -0
- package/payload/server/public/assets/skills-5vl_Bt9U.js.gz +0 -0
- package/payload/server/public/assets/tasks-DQHtJ8Pq.js +0 -3
- package/payload/server/public/assets/tasks-DQHtJ8Pq.js.br +0 -0
- package/payload/server/public/assets/tasks-DQHtJ8Pq.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-Cy4Z0uFv.js +0 -1
- package/payload/server/public/assets/triangle-alert-Cy4Z0uFv.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-Cy4Z0uFv.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-BwK1RhmF.js +0 -1
- package/payload/server/public/assets/useCopyFeedback-BwK1RhmF.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-BwK1RhmF.js.gz +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-C7TtIbR3.js.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-DCkivCBS.css.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DgyAGgmF.js +0 -2
- package/payload/server/public/assets/useVoiceRecorder-DgyAGgmF.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DgyAGgmF.js.gz +0 -0
- package/payload/server/public/assets/wrench-CICORrSc.js +0 -1
- package/payload/server/public/assets/wrench-CICORrSc.js.br +0 -0
- package/payload/server/public/assets/wrench-CICORrSc.js.gz +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static routes registered BEFORE the `/:slug` catch-all in
|
|
3
|
+
* `platform/ui/server/index.ts`. An agent slug equal to one of these is
|
|
4
|
+
* shadowed by the static route and 404s at `/{slug}` (only the bare root can
|
|
5
|
+
* reach such an agent, and only when it is the defaultAgent). This is the
|
|
6
|
+
* single source of truth for the shadowed set: the boot canary in
|
|
7
|
+
* `server/index.ts` reconciles it against the live `app.routes` registry
|
|
8
|
+
* (drift → `[route-shadow] drift` log), and the claude-session-manager
|
|
9
|
+
* reachability audit asserts its own copy equals this list via a cross-package
|
|
10
|
+
* test (the manager cannot import ui modules at build time). Edit this list
|
|
11
|
+
* only in lockstep with the static route registrations.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SYSTEM_PATH_SLUGS: readonly ["public", "public-chat", "chat", "graph", "data", "browser"];
|
|
14
|
+
/** Slugs the platform owns at the account root, independent of route order. */
|
|
15
|
+
export declare const RESERVED_AGENT_SLUGS: readonly string[];
|
|
16
|
+
/** Lowercase, starts with a letter, 3 to 50 characters, hyphens allowed. */
|
|
17
|
+
export declare const AGENT_SLUG_PATTERN: RegExp;
|
|
18
|
+
export type AgentSlugRefusal = "shape" | "reserved" | "shadowed";
|
|
19
|
+
export type AgentSlugVerdict = {
|
|
20
|
+
ok: true;
|
|
21
|
+
} | {
|
|
22
|
+
ok: false;
|
|
23
|
+
reason: AgentSlugRefusal;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Which of the three rules a slug breaks, so a caller can report the cause
|
|
27
|
+
* rather than a bare "invalid". The serve path collapses this to a boolean;
|
|
28
|
+
* the write tools surface the reason to the operator.
|
|
29
|
+
*/
|
|
30
|
+
export declare function checkAgentSlug(slug: string): AgentSlugVerdict;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,wEAAyE,CAAC;AAExG,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAQjD,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,QAA2B,CAAC;AAE3D,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC;AAEjE,MAAM,MAAM,gBAAgB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEtF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAK7D"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// The one rule that decides whether a string may be a public-agent slug.
|
|
3
|
+
//
|
|
4
|
+
// It has two consumers that must never disagree: the serve path
|
|
5
|
+
// (`platform/ui/app/lib/claude-agent/account.ts`, which decides whether a
|
|
6
|
+
// request for `/{slug}` can reach an agent) and the write path (the admin MCP
|
|
7
|
+
// agent-create / agent-update tools, which decide whether an agent may be
|
|
8
|
+
// created under that slug). Before Task 2286 only the serve path applied it, so
|
|
9
|
+
// an agent could be created under a slug its own router would refuse — written
|
|
10
|
+
// to disk successfully, then 404ing at its own URL.
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AGENT_SLUG_PATTERN = exports.RESERVED_AGENT_SLUGS = exports.SYSTEM_PATH_SLUGS = void 0;
|
|
13
|
+
exports.checkAgentSlug = checkAgentSlug;
|
|
14
|
+
/**
|
|
15
|
+
* Static routes registered BEFORE the `/:slug` catch-all in
|
|
16
|
+
* `platform/ui/server/index.ts`. An agent slug equal to one of these is
|
|
17
|
+
* shadowed by the static route and 404s at `/{slug}` (only the bare root can
|
|
18
|
+
* reach such an agent, and only when it is the defaultAgent). This is the
|
|
19
|
+
* single source of truth for the shadowed set: the boot canary in
|
|
20
|
+
* `server/index.ts` reconciles it against the live `app.routes` registry
|
|
21
|
+
* (drift → `[route-shadow] drift` log), and the claude-session-manager
|
|
22
|
+
* reachability audit asserts its own copy equals this list via a cross-package
|
|
23
|
+
* test (the manager cannot import ui modules at build time). Edit this list
|
|
24
|
+
* only in lockstep with the static route registrations.
|
|
25
|
+
*/
|
|
26
|
+
exports.SYSTEM_PATH_SLUGS = ["public", "public-chat", "chat", "graph", "data", "browser"];
|
|
27
|
+
/** Slugs the platform owns at the account root, independent of route order. */
|
|
28
|
+
exports.RESERVED_AGENT_SLUGS = [
|
|
29
|
+
"admin",
|
|
30
|
+
"api",
|
|
31
|
+
"assets",
|
|
32
|
+
"agent-assets",
|
|
33
|
+
"brand",
|
|
34
|
+
"bot",
|
|
35
|
+
"privacy",
|
|
36
|
+
];
|
|
37
|
+
/** Lowercase, starts with a letter, 3 to 50 characters, hyphens allowed. */
|
|
38
|
+
exports.AGENT_SLUG_PATTERN = /^[a-z][a-z0-9-]{2,49}$/;
|
|
39
|
+
/**
|
|
40
|
+
* Which of the three rules a slug breaks, so a caller can report the cause
|
|
41
|
+
* rather than a bare "invalid". The serve path collapses this to a boolean;
|
|
42
|
+
* the write tools surface the reason to the operator.
|
|
43
|
+
*/
|
|
44
|
+
function checkAgentSlug(slug) {
|
|
45
|
+
if (!exports.AGENT_SLUG_PATTERN.test(slug))
|
|
46
|
+
return { ok: false, reason: "shape" };
|
|
47
|
+
if (exports.RESERVED_AGENT_SLUGS.includes(slug))
|
|
48
|
+
return { ok: false, reason: "reserved" };
|
|
49
|
+
if (exports.SYSTEM_PATH_SLUGS.includes(slug))
|
|
50
|
+
return { ok: false, reason: "shadowed" };
|
|
51
|
+
return { ok: true };
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,yEAAyE;AACzE,EAAE;AACF,gEAAgE;AAChE,0EAA0E;AAC1E,8EAA8E;AAC9E,0EAA0E;AAC1E,gFAAgF;AAChF,+EAA+E;AAC/E,oDAAoD;;;AAuCpD,wCAKC;AA1CD;;;;;;;;;;;GAWG;AACU,QAAA,iBAAiB,GAAG,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAU,CAAC;AAExG,+EAA+E;AAClE,QAAA,oBAAoB,GAAsB;IACrD,OAAO;IACP,KAAK;IACL,QAAQ;IACR,cAAc;IACd,OAAO;IACP,KAAK;IACL,SAAS;CACV,CAAC;AAEF,4EAA4E;AAC/D,QAAA,kBAAkB,GAAG,wBAAwB,CAAC;AAM3D;;;;GAIG;AACH,SAAgB,cAAc,CAAC,IAAY;IACzC,IAAI,CAAC,0BAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC1E,IAAI,4BAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAClF,IAAK,yBAAuC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACtG,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// The one rule that decides whether a string may be a public-agent slug.
|
|
2
|
+
//
|
|
3
|
+
// It has two consumers that must never disagree: the serve path
|
|
4
|
+
// (`platform/ui/app/lib/claude-agent/account.ts`, which decides whether a
|
|
5
|
+
// request for `/{slug}` can reach an agent) and the write path (the admin MCP
|
|
6
|
+
// agent-create / agent-update tools, which decide whether an agent may be
|
|
7
|
+
// created under that slug). Before Task 2286 only the serve path applied it, so
|
|
8
|
+
// an agent could be created under a slug its own router would refuse — written
|
|
9
|
+
// to disk successfully, then 404ing at its own URL.
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Static routes registered BEFORE the `/:slug` catch-all in
|
|
13
|
+
* `platform/ui/server/index.ts`. An agent slug equal to one of these is
|
|
14
|
+
* shadowed by the static route and 404s at `/{slug}` (only the bare root can
|
|
15
|
+
* reach such an agent, and only when it is the defaultAgent). This is the
|
|
16
|
+
* single source of truth for the shadowed set: the boot canary in
|
|
17
|
+
* `server/index.ts` reconciles it against the live `app.routes` registry
|
|
18
|
+
* (drift → `[route-shadow] drift` log), and the claude-session-manager
|
|
19
|
+
* reachability audit asserts its own copy equals this list via a cross-package
|
|
20
|
+
* test (the manager cannot import ui modules at build time). Edit this list
|
|
21
|
+
* only in lockstep with the static route registrations.
|
|
22
|
+
*/
|
|
23
|
+
export const SYSTEM_PATH_SLUGS = ["public", "public-chat", "chat", "graph", "data", "browser"] as const;
|
|
24
|
+
|
|
25
|
+
/** Slugs the platform owns at the account root, independent of route order. */
|
|
26
|
+
export const RESERVED_AGENT_SLUGS: readonly string[] = [
|
|
27
|
+
"admin",
|
|
28
|
+
"api",
|
|
29
|
+
"assets",
|
|
30
|
+
"agent-assets",
|
|
31
|
+
"brand",
|
|
32
|
+
"bot",
|
|
33
|
+
"privacy",
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
/** Lowercase, starts with a letter, 3 to 50 characters, hyphens allowed. */
|
|
37
|
+
export const AGENT_SLUG_PATTERN = /^[a-z][a-z0-9-]{2,49}$/;
|
|
38
|
+
|
|
39
|
+
export type AgentSlugRefusal = "shape" | "reserved" | "shadowed";
|
|
40
|
+
|
|
41
|
+
export type AgentSlugVerdict = { ok: true } | { ok: false; reason: AgentSlugRefusal };
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Which of the three rules a slug breaks, so a caller can report the cause
|
|
45
|
+
* rather than a bare "invalid". The serve path collapses this to a boolean;
|
|
46
|
+
* the write tools surface the reason to the operator.
|
|
47
|
+
*/
|
|
48
|
+
export function checkAgentSlug(slug: string): AgentSlugVerdict {
|
|
49
|
+
if (!AGENT_SLUG_PATTERN.test(slug)) return { ok: false, reason: "shape" };
|
|
50
|
+
if (RESERVED_AGENT_SLUGS.includes(slug)) return { ok: false, reason: "reserved" };
|
|
51
|
+
if ((SYSTEM_PATH_SLUGS as readonly string[]).includes(slug)) return { ok: false, reason: "shadowed" };
|
|
52
|
+
return { ok: true };
|
|
53
|
+
}
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"pdf-lib": "^1.17.1"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "tsc -p lib/account-schema-regions/tsconfig.json && tsc -p lib/account-ingest-token/tsconfig.json && tsc -p lib/models/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p lib/routine-templates/tsconfig.json && tsc -p lib/agent-dispatch-rule/tsconfig.json && tsc -p lib/learning-constants/tsconfig.json && tsc -p services/claude-session-manager/tsconfig.json && tsc -p services/whatsapp-channel/tsconfig.json && tsc -p services/webchat-channel/tsconfig.json && tsc -p services/telegram-channel/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
|
|
14
|
-
"build:lib": "tsc -p lib/account-schema-regions/tsconfig.json && tsc -p lib/account-ingest-token/tsconfig.json && tsc -p lib/models/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p lib/routine-templates/tsconfig.json && tsc -p lib/agent-dispatch-rule/tsconfig.json",
|
|
13
|
+
"build": "tsc -p lib/account-schema-regions/tsconfig.json && tsc -p lib/account-ingest-token/tsconfig.json && tsc -p lib/models/tsconfig.json && tsc -p lib/agent-slug/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p lib/routine-templates/tsconfig.json && tsc -p lib/agent-dispatch-rule/tsconfig.json && tsc -p lib/learning-constants/tsconfig.json && tsc -p services/claude-session-manager/tsconfig.json && tsc -p services/whatsapp-channel/tsconfig.json && tsc -p services/webchat-channel/tsconfig.json && tsc -p services/telegram-channel/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
|
|
14
|
+
"build:lib": "tsc -p lib/account-schema-regions/tsconfig.json && tsc -p lib/account-ingest-token/tsconfig.json && tsc -p lib/models/tsconfig.json && tsc -p lib/agent-slug/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p lib/routine-templates/tsconfig.json && tsc -p lib/agent-dispatch-rule/tsconfig.json",
|
|
15
15
|
"gen:canonical-tools": "node scripts/generate-canonical-tool-names.mjs",
|
|
16
16
|
"build:memory": "tsc -p plugins/memory/mcp/tsconfig.json",
|
|
17
17
|
"build:contacts": "tsc -p plugins/contacts/mcp/tsconfig.json",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "admin",
|
|
3
|
-
"description": "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), linkedin-ingest-token (returns the account's durable LinkedIn ingest token — the one credential the Maxy LinkedIn Ingest Chrome extension needs in its options page; minted on first call then stable across restarts and new chat sessions, and never a conversation session key nor the admin browser's session_key, which the ingest route rejects; action='rotate' replaces it and invalidates every existing extension install), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires the client business owner's real name (ownerName), refusing a blank or the placeholder \"Owner\" and seeding it onto the sub-account's owner AdminUser and owner Person, and requires the owner's IANA timezone (timezone) — refusing a blank or a non-IANA value — seeding it onto the owner UserProfile marked owner-set so scheduling reads the owner's real zone from the start rather than the box's server default, while a managing house admin (its userId) is optional — when supplied it is validated as a live house admin and recorded as the sub-account's managingAdminUserId, and when omitted the sub-account is unmanaged and its passive-intake tasks route to the install's primary admin; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId, or to record one on an unmanaged account); account_roster is the canonical per-account identity view — one row per sub-account giving business name, role, the managing house admin resolved to a name with status (assigned/absent/dangling), the business owner from the graph with status (named/nameless), and the WhatsApp account-manager binding if any, each field carrying what it means and does not (managing admin is the responsible house team member not the owner; account manager is WhatsApp routing only with no admin rights), so the agent never stitches admin-list + account.json + whatsapp-config; account_set_owner_name names (or corrects) a client sub-account's business owner by writing the owned Person — the canonical name source — refusing a blank or the placeholder \"Owner\", the guarded repair for a nameless owner (the standing identity-audit op=nameless-owned-person detector); account_channel_routing_set repoints the house-paired WhatsApp/Telegram inbound stream to a different sub-account, and does not affect a sub-account's own separately paired WhatsApp number), admin-add (refuses on a client sub-account, where admin access is already install-wide so a per-operator seat grants nothing — the sub-account's one identity, its business owner, is set at account creation; the house account, where operators hold PIN logins and admins[] rows, is unchanged), admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, cpu-triage-start and cpu-triage-read (the two-call device CPU diagnostic — start spawns a detached sampling run across at least one full 120s reconcile cycle and returns a run handle immediately, read returns running/complete/failed with the per-core distribution; no admin tool blocks through a sampling window, and no spot reading is obtainable), plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform.",
|
|
3
|
+
"description": "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), linkedin-ingest-token (returns the account's durable LinkedIn ingest token — the one credential the Maxy LinkedIn Ingest Chrome extension needs in its options page; minted on first call then stable across restarts and new chat sessions, and never a conversation session key nor the admin browser's session_key, which the ingest route rejects; action='rotate' replaces it and invalidates every existing extension install), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires the client business owner's real name (ownerName), refusing a blank or the placeholder \"Owner\" and seeding it onto the sub-account's owner AdminUser and owner Person, and requires the owner's IANA timezone (timezone) — refusing a blank or a non-IANA value — seeding it onto the owner UserProfile marked owner-set so scheduling reads the owner's real zone from the start rather than the box's server default, while a managing house admin (its userId) is optional — when supplied it is validated as a live house admin and recorded as the sub-account's managingAdminUserId, and when omitted the sub-account is unmanaged and its passive-intake tasks route to the install's primary admin; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId, or to record one on an unmanaged account); account_roster is the canonical per-account identity view — one row per sub-account giving business name, role, the managing house admin resolved to a name with status (assigned/absent/dangling), the business owner from the graph with status (named/nameless), and the WhatsApp account-manager binding if any, each field carrying what it means and does not (managing admin is the responsible house team member not the owner; account manager is WhatsApp routing only with no admin rights), so the agent never stitches admin-list + account.json + whatsapp-config; account_set_owner_name names (or corrects) a client sub-account's business owner by writing the owned Person — the canonical name source — refusing a blank or the placeholder \"Owner\", the guarded repair for a nameless owner (the standing identity-audit op=nameless-owned-person detector); account_channel_routing_set repoints the house-paired WhatsApp/Telegram inbound stream to a different sub-account, and does not affect a sub-account's own separately paired WhatsApp number), admin-add (refuses on a client sub-account, where admin access is already install-wide so a per-operator seat grants nothing — the sub-account's one identity, its business owner, is set at account creation; the house account, where operators hold PIN logins and admins[] rows, is unchanged), admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, the public-agent write tools (agent-create is the only supported way to create a public agent: it validates the slug against the same rule the router serves by, validates config.json against the servable schema, refuses an empty KNOWLEDGE, writes the four files with IDENTITY.md copied verbatim from the platform template, and projects the agent into the graph in the same call, reporting the verified projected count rather than assuming it; agent-update applies the same validation to a merged config, writes only the fields supplied, and re-projects, so the graph cannot fall behind the files; agent-delete removes the :Agent node and its owned knowledge projections before the directory and refuses the admin agent — writing these files by hand reaches none of those checks, which is what left an agent on disk and absent from the graph for a day), agent-image, plugin-toggle-enabled, premium-list, premium-deliver, skill-find, logs-read, cpu-triage-start and cpu-triage-read (the two-call device CPU diagnostic — start spawns a detached sampling run across at least one full 120s reconcile cycle and returns a run handle immediately, read returns running/complete/failed with the per-core distribution; no admin tool blocks through a sampling window, and no spot reading is obtainable), plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform.",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Rubytech LLC"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: admin
|
|
3
3
|
surface: platform
|
|
4
|
-
description: "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), linkedin-ingest-token (returns the account's durable LinkedIn ingest token — the one credential the Maxy LinkedIn Ingest Chrome extension needs in its options page; minted on first call then stable across restarts and new chat sessions, and never a conversation session key nor the admin browser's session_key, which the ingest route rejects; action='rotate' replaces it and invalidates every existing extension install), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires the client business owner's real name (ownerName), refusing a blank or the placeholder "Owner" and seeding it onto the sub-account's owner AdminUser and owner Person, and requires the owner's IANA timezone (timezone) — refusing a blank or a non-IANA value — seeding it onto the owner UserProfile marked owner-set so scheduling reads the owner's real zone from the start rather than the box's server default, while a managing house admin (its userId) is optional — when supplied it is validated as a live house admin and recorded as the sub-account's managingAdminUserId, and when omitted the sub-account is unmanaged and its passive-intake tasks route to the install's primary admin; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId, or to record one on an unmanaged account); account_roster is the canonical per-account identity view — one row per sub-account giving business name, role, the managing house admin resolved to a name with status (assigned/absent/dangling), the business owner from the graph with status (named/nameless), and the WhatsApp account-manager binding if any, each field carrying what it means and does not (managing admin is the responsible house team member not the owner; account manager is WhatsApp routing only with no admin rights), so the agent never stitches admin-list + account.json + whatsapp-config; account_set_owner_name names (or corrects) a client sub-account's business owner by writing the owned Person — the canonical name source — refusing a blank or the placeholder "Owner", the guarded repair for a nameless owner (the standing identity-audit op=nameless-owned-person detector); account_channel_routing_set repoints the house-paired WhatsApp/Telegram inbound stream to a different sub-account, and does not affect a sub-account's own separately paired WhatsApp number), admin-add (refuses on a client sub-account, where admin access is already install-wide so a per-operator seat grants nothing — the sub-account's one identity, its business owner, is set at account creation; the house account, where operators hold PIN logins and admins[] rows, is unchanged), admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, cpu-triage-start and cpu-triage-read (the two-call device CPU diagnostic — start spawns a detached sampling run across at least one full 120s reconcile cycle and returns a run handle immediately, read returns running/complete/failed with the per-core distribution; no admin tool blocks through a sampling window, and no spot reading is obtainable), plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform."
|
|
4
|
+
description: "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), linkedin-ingest-token (returns the account's durable LinkedIn ingest token — the one credential the Maxy LinkedIn Ingest Chrome extension needs in its options page; minted on first call then stable across restarts and new chat sessions, and never a conversation session key nor the admin browser's session_key, which the ingest route rejects; action='rotate' replaces it and invalidates every existing extension install), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires the client business owner's real name (ownerName), refusing a blank or the placeholder "Owner" and seeding it onto the sub-account's owner AdminUser and owner Person, and requires the owner's IANA timezone (timezone) — refusing a blank or a non-IANA value — seeding it onto the owner UserProfile marked owner-set so scheduling reads the owner's real zone from the start rather than the box's server default, while a managing house admin (its userId) is optional — when supplied it is validated as a live house admin and recorded as the sub-account's managingAdminUserId, and when omitted the sub-account is unmanaged and its passive-intake tasks route to the install's primary admin; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId, or to record one on an unmanaged account); account_roster is the canonical per-account identity view — one row per sub-account giving business name, role, the managing house admin resolved to a name with status (assigned/absent/dangling), the business owner from the graph with status (named/nameless), and the WhatsApp account-manager binding if any, each field carrying what it means and does not (managing admin is the responsible house team member not the owner; account manager is WhatsApp routing only with no admin rights), so the agent never stitches admin-list + account.json + whatsapp-config; account_set_owner_name names (or corrects) a client sub-account's business owner by writing the owned Person — the canonical name source — refusing a blank or the placeholder "Owner", the guarded repair for a nameless owner (the standing identity-audit op=nameless-owned-person detector); account_channel_routing_set repoints the house-paired WhatsApp/Telegram inbound stream to a different sub-account, and does not affect a sub-account's own separately paired WhatsApp number), admin-add (refuses on a client sub-account, where admin access is already install-wide so a per-operator seat grants nothing — the sub-account's one identity, its business owner, is set at account creation; the house account, where operators hold PIN logins and admins[] rows, is unchanged), admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, the public-agent write tools (agent-create is the only supported way to create a public agent: it validates the slug against the same rule the router serves by, validates config.json against the servable schema, refuses an empty KNOWLEDGE, writes the four files with IDENTITY.md copied verbatim from the platform template, and projects the agent into the graph in the same call, reporting the verified projected count rather than assuming it; agent-update applies the same validation to a merged config, writes only the fields supplied, and re-projects, so the graph cannot fall behind the files; agent-delete removes the :Agent node and its owned knowledge projections before the directory and refuses the admin agent — writing these files by hand reaches none of those checks, which is what left an agent on disk and absent from the graph for a day), agent-image, plugin-toggle-enabled, premium-list, premium-deliver, skill-find, logs-read, cpu-triage-start and cpu-triage-read (the two-call device CPU diagnostic — start spawns a detached sampling run across at least one full 120s reconcile cycle and returns a run handle immediately, read returns running/complete/failed with the per-core distribution; no admin tool blocks through a sampling window, and no spot reading is obtainable), plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform."
|
|
5
5
|
account-owned-files: [{"file": "webchat-channel-bindings.json", "description": "Routes this account's inbound admin webchat messages. Written by the session manager's webchat-channel-store."}, {"file": "wa-channel-bindings.json", "description": "Routes this account's inbound WhatsApp messages. Written by the session manager's wa-channel-store, which runs on every brand whether or not the whatsapp plugin ships."}, {"file": "telegram-channel-bindings.json", "description": "Routes this account's inbound Telegram messages. Written by the session manager's telegram-channel-store, which runs on every brand whether or not the telegram plugin ships."}, {"file": "canonical-webchat-session.json", "description": "Pins the account's canonical webchat session. Written by the admin UI server."}, {"file": "session-titles.json", "description": "Operator renames of sessions. Written by the session manager's title stores."}, {"file": "agents-disabled.json", "description": "Names the agents the operator switched off. Written by the admin agents route; provision reads it to re-apply the disables and never creates it."}]
|
|
6
6
|
tools:
|
|
7
7
|
- name: system-status
|
|
@@ -100,6 +100,38 @@ tools:
|
|
|
100
100
|
publicAllowlist: false
|
|
101
101
|
adminAllowlist: true
|
|
102
102
|
riskClass: read
|
|
103
|
+
- name: agent-create
|
|
104
|
+
publicAllowlist: false
|
|
105
|
+
adminAllowlist: true
|
|
106
|
+
riskClass: write_local
|
|
107
|
+
- name: agent-update
|
|
108
|
+
publicAllowlist: false
|
|
109
|
+
adminAllowlist: true
|
|
110
|
+
riskClass: write_local
|
|
111
|
+
- name: agent-delete
|
|
112
|
+
publicAllowlist: false
|
|
113
|
+
adminAllowlist: true
|
|
114
|
+
riskClass: write_local
|
|
115
|
+
- name: agent-image
|
|
116
|
+
publicAllowlist: false
|
|
117
|
+
adminAllowlist: true
|
|
118
|
+
riskClass: write_local
|
|
119
|
+
- name: plugin-toggle-enabled
|
|
120
|
+
publicAllowlist: false
|
|
121
|
+
adminAllowlist: true
|
|
122
|
+
riskClass: write_local
|
|
123
|
+
- name: premium-list
|
|
124
|
+
publicAllowlist: false
|
|
125
|
+
adminAllowlist: true
|
|
126
|
+
riskClass: read
|
|
127
|
+
- name: premium-deliver
|
|
128
|
+
publicAllowlist: false
|
|
129
|
+
adminAllowlist: true
|
|
130
|
+
riskClass: write_local
|
|
131
|
+
- name: skill-find
|
|
132
|
+
publicAllowlist: false
|
|
133
|
+
adminAllowlist: true
|
|
134
|
+
riskClass: read
|
|
103
135
|
- name: logs-read
|
|
104
136
|
publicAllowlist: false
|
|
105
137
|
adminAllowlist: false
|
|
@@ -25,6 +25,7 @@ import { classifySpecialists } from "./specialist-registry.js";
|
|
|
25
25
|
import { resolvePublicHostname } from "./lib/public-hostname.js";
|
|
26
26
|
import { resolveAdminHostname } from "./lib/admin-hostname.js";
|
|
27
27
|
import { publishSite } from "./tools/publish-site.js";
|
|
28
|
+
import { createAgent, updateAgent, projectAgentViaPlatform } from "./tools/agent-write.js";
|
|
28
29
|
import { resolveCapabilitiesHere } from "./tools/capabilities-here.js";
|
|
29
30
|
import { resolveIngestToken } from "./tools/linkedin-ingest-token.js";
|
|
30
31
|
import { startCpuTriage, readCpuTriage } from "./tools/cpu-triage.js";
|
|
@@ -1541,6 +1542,141 @@ lifelineTool(server, "agent-list", "List all public (non-admin) agents with thei
|
|
|
1541
1542
|
};
|
|
1542
1543
|
}
|
|
1543
1544
|
});
|
|
1545
|
+
// Task 2286 — public-agent CRUD. Before these tools existed there was no write
|
|
1546
|
+
// path at any layer, so an agent creating an agent wrote the four files by hand
|
|
1547
|
+
// and hand-rolled the projection POST. That reached no slug rule, no config
|
|
1548
|
+
// schema and no non-empty-knowledge check, and it is what left the `beagle`
|
|
1549
|
+
// agent on disk and absent from the graph for a day.
|
|
1550
|
+
const AGENT_WRITE_TAG = "[admin/agents]";
|
|
1551
|
+
/** One line per write. `projected` is the verified post-condition read from the
|
|
1552
|
+
* projection response, not the intention.
|
|
1553
|
+
*
|
|
1554
|
+
* `projected` is meaningful for create and update only. A successful delete
|
|
1555
|
+
* logs `projected=0` because it removed the projection, so the
|
|
1556
|
+
* disk-without-graph failure signature is `action=create|update outcome=ok
|
|
1557
|
+
* projected=0` — grepping `outcome=ok projected=0` alone matches every
|
|
1558
|
+
* successful delete. */
|
|
1559
|
+
function logAgentWrite(action, slug, outcome, reason, detail, projected) {
|
|
1560
|
+
console.error(`${AGENT_WRITE_TAG} op=agent-write action=${action} slug=${slug} accountId=${(ACCOUNT_ID ?? "").slice(0, 8)} ` +
|
|
1561
|
+
`outcome=${outcome} reason=${reason} detail=${detail} projected=${projected}`);
|
|
1562
|
+
}
|
|
1563
|
+
lifelineTool(server, "agent-create", "Create a public agent: writes IDENTITY.md (copied verbatim from the platform template), SOUL.md, KNOWLEDGE.md and config.json, then projects the agent into the graph in the same call. Refuses a slug the router would not serve, a config that would not spawn, and an empty KNOWLEDGE, before writing anything. This is the only supported way to create a public agent — writing the files directly reaches none of these checks.", {
|
|
1564
|
+
agentSlug: z.string().describe("Agent slug: lowercase, starts with a letter, 3-50 chars, hyphens allowed"),
|
|
1565
|
+
displayName: z.string().describe("Name shown in the chat header"),
|
|
1566
|
+
model: z.string().describe("Model id: claude-haiku-4-5, claude-sonnet-5, or claude-opus-5[1m]"),
|
|
1567
|
+
soul: z.string().describe("SOUL.md body: personality and the operator-defined role"),
|
|
1568
|
+
knowledge: z.string().describe("KNOWLEDGE.md body: the agent's only knowledge source. Must be non-empty"),
|
|
1569
|
+
knowledgeKeywords: z.array(z.string()).optional().describe("Up to 5 keyword subscriptions"),
|
|
1570
|
+
status: z.enum(["active", "inactive"]).optional().describe("Defaults to active"),
|
|
1571
|
+
showAgentName: z.union([z.boolean(), z.literal("none")]).optional().describe("Chat header title: false for the business name, true for the agent display name, 'none' for logo only"),
|
|
1572
|
+
accessMode: z.enum(["open", "gated", "paid"]).optional().describe("Defaults to open"),
|
|
1573
|
+
}, async ({ agentSlug, ...rest }) => {
|
|
1574
|
+
if (!ACCOUNT_ID)
|
|
1575
|
+
return refuseNoAccount("agent-create");
|
|
1576
|
+
// getAccountDir throws on an unresolvable account dir and createAgent
|
|
1577
|
+
// rethrows an I/O error after cleaning up. wrapWithLifeline re-throws, so
|
|
1578
|
+
// without this catch the failure leaves NO op=agent-write line — the
|
|
1579
|
+
// unobservable-failure class this tool exists to close.
|
|
1580
|
+
try {
|
|
1581
|
+
const res = createAgent({ ...rest, slug: agentSlug, accountDir: getAccountDir(), platformRoot: PLATFORM_ROOT });
|
|
1582
|
+
if (!res.ok) {
|
|
1583
|
+
logAgentWrite("create", agentSlug, "refused", res.reason, res.detail, 0);
|
|
1584
|
+
return { content: [{ type: "text", text: `Refused: ${res.reason} — ${res.detail}` }], isError: true };
|
|
1585
|
+
}
|
|
1586
|
+
const proj = await projectAgentViaPlatform({
|
|
1587
|
+
platformPort: PLATFORM_PORT,
|
|
1588
|
+
accountId: ACCOUNT_ID,
|
|
1589
|
+
slug: agentSlug,
|
|
1590
|
+
houseAdminScope: process.env.HOUSE_ADMIN_SCOPE,
|
|
1591
|
+
});
|
|
1592
|
+
logAgentWrite("create", agentSlug, "ok", proj.projected ? "none" : "projection-failed", proj.error ?? "-", proj.projected);
|
|
1593
|
+
if (!proj.projected) {
|
|
1594
|
+
return {
|
|
1595
|
+
content: [{ type: "text", text: `Agent '${agentSlug}' was written to disk but NOT projected into the graph: ${proj.error}. It will not appear in /graph. Re-run agent-update to retry the projection.` }],
|
|
1596
|
+
isError: true,
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
return { content: [{ type: "text", text: `Agent '${agentSlug}' created and projected. Reachable at /${agentSlug}.` }] };
|
|
1600
|
+
}
|
|
1601
|
+
catch (err) {
|
|
1602
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1603
|
+
logAgentWrite("create", agentSlug, "refused", "write-failed", msg, 0);
|
|
1604
|
+
return { content: [{ type: "text", text: `agent-create failed: ${msg}` }], isError: true };
|
|
1605
|
+
}
|
|
1606
|
+
});
|
|
1607
|
+
lifelineTool(server, "agent-update", "Update a public agent's SOUL.md, KNOWLEDGE.md or config fields, then re-project it into the graph in the same call. Only the fields supplied are written; config fields merge into the existing file. A refusal leaves the agent directory byte-identical. Use this instead of editing the files directly, or the graph falls behind the files.", {
|
|
1608
|
+
agentSlug: z.string().describe("Agent slug"),
|
|
1609
|
+
displayName: z.string().optional(),
|
|
1610
|
+
model: z.string().optional().describe("claude-haiku-4-5, claude-sonnet-5, or claude-opus-5[1m]"),
|
|
1611
|
+
soul: z.string().optional().describe("Replacement SOUL.md body"),
|
|
1612
|
+
knowledge: z.string().optional().describe("Replacement KNOWLEDGE.md body. Must be non-empty when supplied"),
|
|
1613
|
+
knowledgeKeywords: z.array(z.string()).optional().describe("Up to 5 keyword subscriptions"),
|
|
1614
|
+
status: z.enum(["active", "inactive"]).optional(),
|
|
1615
|
+
showAgentName: z.union([z.boolean(), z.literal("none")]).optional(),
|
|
1616
|
+
accessMode: z.enum(["open", "gated", "paid"]).optional(),
|
|
1617
|
+
}, async ({ agentSlug, ...rest }) => {
|
|
1618
|
+
if (!ACCOUNT_ID)
|
|
1619
|
+
return refuseNoAccount("agent-update");
|
|
1620
|
+
// Same rethrow contract as agent-create: without this catch an
|
|
1621
|
+
// unresolvable account dir or a write error leaves no op=agent-write line.
|
|
1622
|
+
try {
|
|
1623
|
+
const res = updateAgent({ ...rest, slug: agentSlug, accountDir: getAccountDir() });
|
|
1624
|
+
if (!res.ok) {
|
|
1625
|
+
logAgentWrite("update", agentSlug, "refused", res.reason, res.detail, 0);
|
|
1626
|
+
return { content: [{ type: "text", text: `Refused: ${res.reason} — ${res.detail}` }], isError: true };
|
|
1627
|
+
}
|
|
1628
|
+
const proj = await projectAgentViaPlatform({
|
|
1629
|
+
platformPort: PLATFORM_PORT,
|
|
1630
|
+
accountId: ACCOUNT_ID,
|
|
1631
|
+
slug: agentSlug,
|
|
1632
|
+
houseAdminScope: process.env.HOUSE_ADMIN_SCOPE,
|
|
1633
|
+
});
|
|
1634
|
+
logAgentWrite("update", agentSlug, "ok", proj.projected ? "none" : "projection-failed", proj.error ?? "-", proj.projected);
|
|
1635
|
+
if (!proj.projected) {
|
|
1636
|
+
return {
|
|
1637
|
+
content: [{ type: "text", text: `Agent '${agentSlug}' was updated on disk but NOT re-projected: ${proj.error}. /graph now shows stale state for this agent.` }],
|
|
1638
|
+
isError: true,
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
return { content: [{ type: "text", text: `Agent '${agentSlug}' updated (${res.filesWritten.join(", ")}) and re-projected.` }] };
|
|
1642
|
+
}
|
|
1643
|
+
catch (err) {
|
|
1644
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1645
|
+
logAgentWrite("update", agentSlug, "refused", "write-failed", msg, 0);
|
|
1646
|
+
return { content: [{ type: "text", text: `agent-update failed: ${msg}` }], isError: true };
|
|
1647
|
+
}
|
|
1648
|
+
});
|
|
1649
|
+
lifelineTool(server, "agent-delete", "Delete a public agent: removes its :Agent node and owned knowledge projections from the graph first, then its directory. Refuses the admin agent. Calls the platform route that owns the ordering, so a graph failure preserves the files and the delete can be safely re-run.", {
|
|
1650
|
+
agentSlug: z.string().describe("Agent slug"),
|
|
1651
|
+
}, async ({ agentSlug }) => {
|
|
1652
|
+
if (!ACCOUNT_ID)
|
|
1653
|
+
return refuseNoAccount("agent-delete");
|
|
1654
|
+
// Refused here as well as at the route so the refusal is attributable from
|
|
1655
|
+
// the MCP log alone, without correlating against the platform log.
|
|
1656
|
+
if (agentSlug === "admin") {
|
|
1657
|
+
logAgentWrite("delete", agentSlug, "refused", "slug-unsafe", "reserved", 0);
|
|
1658
|
+
return { content: [{ type: "text", text: "Refused: the admin agent cannot be deleted." }], isError: true };
|
|
1659
|
+
}
|
|
1660
|
+
const headers = { "x-maxy-caller-account": ACCOUNT_ID };
|
|
1661
|
+
if (process.env.HOUSE_ADMIN_SCOPE)
|
|
1662
|
+
headers["x-maxy-house-admin-scope"] = process.env.HOUSE_ADMIN_SCOPE;
|
|
1663
|
+
try {
|
|
1664
|
+
const res = await fetch(`http://127.0.0.1:${PLATFORM_PORT}/api/admin/agents/${agentSlug}?accountId=${ACCOUNT_ID}`, { method: "DELETE", headers, signal: AbortSignal.timeout(5000) });
|
|
1665
|
+
if (!res.ok) {
|
|
1666
|
+
const body = await res.text().catch(() => "");
|
|
1667
|
+
const reason = res.status === 404 ? "not-found" : "delete-failed";
|
|
1668
|
+
logAgentWrite("delete", agentSlug, "refused", reason, String(res.status), 0);
|
|
1669
|
+
return { content: [{ type: "text", text: `Refused: ${reason} — ${res.status} ${body}`.trim() }], isError: true };
|
|
1670
|
+
}
|
|
1671
|
+
logAgentWrite("delete", agentSlug, "ok", "none", "-", 0);
|
|
1672
|
+
return { content: [{ type: "text", text: `Agent '${agentSlug}' deleted from the graph and from disk.` }] };
|
|
1673
|
+
}
|
|
1674
|
+
catch (err) {
|
|
1675
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1676
|
+
logAgentWrite("delete", agentSlug, "refused", "delete-failed", msg, 0);
|
|
1677
|
+
return { content: [{ type: "text", text: `Delete failed: ${msg}` }], isError: true };
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1544
1680
|
eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream/error/session/public) are per-session — pass `sessionKey` (preferred) or the legacy `sessionId` alias to retrieve a single session's log from first [spawn] to final [process-exit]. type=agent-stream: per-session tool-use/tool-result archive (every `[tool-use]` and `[tool-result]` pair with full input + output JSON, plus raw Claude stream-json, agent events, and MCP server stderr via tee). USE THIS when investigating what an agent ACTUALLY did with its tools — server.log only carries `[persist] tool-call persisted` markers, not bodies. (`type=system` is a backwards-compatible alias for the same archive.) type=session: SSE events sent to client. type=error: Claude subprocess stderr (raw — NODE_DEBUG HTTP/NET/UNDICI traces land in agent-stream via the stream tee, not here). type=heartbeat: platform event dispatcher (check-due-events cron). type=public: public agent diagnostic log. type=server: platform server log. type=mcp: MCP server stderr (per-plugin raw), resolved under ~/.<brand>/logs — the platform config dir, not the account log dir. With a sessionKey, every mcp-*.log whose FILENAME carries that key is tailed, up to 20 files, and a truncated reply names the total that matched; an 8-character key prefix matches. The key is never matched against file contents, because MCP log lines carry no session key. type=vnc: VNC browser viewer lifecycle.", {
|
|
1545
1681
|
type: z.enum(["agent-stream", "system", "session", "error", "heartbeat", "public", "server", "mcp", "vnc"]).optional(),
|
|
1546
1682
|
lines: z.number().optional(),
|