@rubytech/create-maxy-code 0.1.538 → 0.1.540

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.
Files changed (279) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/agent-slug/dist/index.d.ts +31 -0
  3. package/payload/platform/lib/agent-slug/dist/index.d.ts.map +1 -0
  4. package/payload/platform/lib/agent-slug/dist/index.js +53 -0
  5. package/payload/platform/lib/agent-slug/dist/index.js.map +1 -0
  6. package/payload/platform/lib/agent-slug/src/index.ts +53 -0
  7. package/payload/platform/lib/agent-slug/tsconfig.json +8 -0
  8. package/payload/platform/package.json +2 -2
  9. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  10. package/payload/platform/plugins/admin/PLUGIN.md +33 -1
  11. package/payload/platform/plugins/admin/mcp/dist/index.js +136 -0
  12. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  13. package/payload/platform/plugins/admin/mcp/dist/tools/agent-config-schema.d.ts +9 -0
  14. package/payload/platform/plugins/admin/mcp/dist/tools/agent-config-schema.d.ts.map +1 -0
  15. package/payload/platform/plugins/admin/mcp/dist/tools/agent-config-schema.js +49 -0
  16. package/payload/platform/plugins/admin/mcp/dist/tools/agent-config-schema.js.map +1 -0
  17. package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.d.ts +64 -0
  18. package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.d.ts.map +1 -0
  19. package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.js +151 -0
  20. package/payload/platform/plugins/admin/mcp/dist/tools/agent-write.js.map +1 -0
  21. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +108 -14
  22. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +36 -20
  23. package/payload/platform/plugins/admin/skills/update-knowledge/SKILL.md +4 -3
  24. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +14 -0
  25. package/payload/platform/plugins/docs/references/admin-ui.md +73 -0
  26. package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +32 -11
  27. package/payload/platform/plugins/docs/references/internals.md +2 -2
  28. package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
  29. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-get-description.test.d.ts +2 -0
  30. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-get-description.test.d.ts.map +1 -0
  31. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-get-description.test.js +59 -0
  32. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-get-description.test.js.map +1 -0
  33. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts.map +1 -1
  34. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js +6 -0
  35. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js.map +1 -1
  36. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -1
  37. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +10 -6
  38. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
  39. package/payload/platform/plugins/whatsapp/PLUGIN.md +2 -2
  40. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +6 -1
  41. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  42. package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +14 -8
  43. package/payload/platform/scripts/__tests__/check-plugin-tool-declarations.test.ts +51 -0
  44. package/payload/platform/scripts/check-plugin-tool-declarations.mjs +97 -0
  45. package/payload/platform/scripts/check-risk-class.mjs +5 -0
  46. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  47. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +8 -0
  48. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  49. package/payload/platform/services/claude-session-manager/dist/channel-targets.d.ts +3 -0
  50. package/payload/platform/services/claude-session-manager/dist/channel-targets.d.ts.map +1 -1
  51. package/payload/platform/services/claude-session-manager/dist/channel-targets.js.map +1 -1
  52. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  53. package/payload/platform/services/claude-session-manager/dist/http-server.js +20 -1
  54. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  55. package/payload/platform/services/claude-session-manager/dist/index.js +35 -18
  56. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  57. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  58. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +57 -8
  59. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  60. package/payload/platform/services/claude-session-manager/dist/public-knowledge-audit.d.ts +58 -0
  61. package/payload/platform/services/claude-session-manager/dist/public-knowledge-audit.d.ts.map +1 -0
  62. package/payload/platform/services/claude-session-manager/dist/public-knowledge-audit.js +152 -0
  63. package/payload/platform/services/claude-session-manager/dist/public-knowledge-audit.js.map +1 -0
  64. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts +4 -0
  65. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts.map +1 -1
  66. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js +3 -0
  67. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js.map +1 -1
  68. package/payload/platform/services/webchat-channel/dist/notification.d.ts +31 -0
  69. package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
  70. package/payload/platform/services/webchat-channel/dist/notification.js +31 -1
  71. package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
  72. package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
  73. package/payload/platform/services/webchat-channel/dist/server.js +15 -1
  74. package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
  75. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +40 -3
  76. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  77. package/payload/platform/services/whatsapp-channel/dist/notification.js +43 -4
  78. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  79. package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
  80. package/payload/platform/services/whatsapp-channel/dist/server.js +41 -25
  81. package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
  82. package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +1 -0
  83. package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
  84. package/payload/platform/services/whatsapp-channel/dist/targets.js +9 -5
  85. package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
  86. package/payload/server/{chunk-BP7LH7MC.js → chunk-CKTHAHL4.js} +26 -16
  87. package/payload/server/{chunk-IALJPXIO.js → chunk-ERIM3EFB.js} +1 -1
  88. package/payload/server/{chunk-FQO5RDWZ.js → chunk-TQTZXAK3.js} +124 -17
  89. package/payload/server/{manager-EBZQRV5V.js → manager-F6NXSOJW.js} +2 -2
  90. package/payload/server/maxy-edge.js +2 -2
  91. package/payload/server/public/activity.html +5 -5
  92. package/payload/server/public/agents.html +4 -4
  93. package/payload/server/public/assets/AdminLoginScreens-DuFCjbz2.js +1 -0
  94. package/payload/server/public/assets/AdminLoginScreens-DuFCjbz2.js.br +0 -0
  95. package/payload/server/public/assets/AdminLoginScreens-DuFCjbz2.js.gz +0 -0
  96. package/payload/server/public/assets/AdminShell-DJL5DzRX.js +2 -0
  97. package/payload/server/public/assets/AdminShell-DJL5DzRX.js.br +0 -0
  98. package/payload/server/public/assets/AdminShell-DJL5DzRX.js.gz +0 -0
  99. package/payload/server/public/assets/activity-CpMnNr5c.js +1 -0
  100. package/payload/server/public/assets/activity-CpMnNr5c.js.br +0 -0
  101. package/payload/server/public/assets/activity-CpMnNr5c.js.gz +0 -0
  102. package/payload/server/public/assets/admin-CBwKIfaI.js +1 -0
  103. package/payload/server/public/assets/admin-CBwKIfaI.js.br +0 -0
  104. package/payload/server/public/assets/admin-CBwKIfaI.js.gz +0 -0
  105. package/payload/server/public/assets/agents-C4LmSKjb.js +1 -0
  106. package/payload/server/public/assets/agents-C4LmSKjb.js.br +0 -0
  107. package/payload/server/public/assets/agents-C4LmSKjb.js.gz +0 -0
  108. package/payload/server/public/assets/browser-Bm9xm_yc.js +1 -0
  109. package/payload/server/public/assets/browser-Bm9xm_yc.js.br +0 -0
  110. package/payload/server/public/assets/browser-Bm9xm_yc.js.gz +0 -0
  111. package/payload/server/public/assets/calendar-CNY9FTWe.js +1 -0
  112. package/payload/server/public/assets/calendar-CNY9FTWe.js.br +0 -0
  113. package/payload/server/public/assets/calendar-CNY9FTWe.js.gz +0 -0
  114. package/payload/server/public/assets/chat-3WoUGCTd.js +1 -0
  115. package/payload/server/public/assets/chat-3WoUGCTd.js.br +0 -0
  116. package/payload/server/public/assets/chat-3WoUGCTd.js.gz +0 -0
  117. package/payload/server/public/assets/chevron-left-BE16BJnw.js +1 -0
  118. package/payload/server/public/assets/chevron-left-BE16BJnw.js.br +0 -0
  119. package/payload/server/public/assets/chevron-right-Bu2VKpeU.js +1 -0
  120. package/payload/server/public/assets/chevron-right-Bu2VKpeU.js.br +0 -0
  121. package/payload/server/public/assets/clock-C4Nu2aRV.js +1 -0
  122. package/payload/server/public/assets/clock-C4Nu2aRV.js.br +0 -0
  123. package/payload/server/public/assets/copy-3kj9Oaoc.js +1 -0
  124. package/payload/server/public/assets/copy-3kj9Oaoc.js.br +0 -0
  125. package/payload/server/public/assets/copy-3kj9Oaoc.js.gz +0 -0
  126. package/payload/server/public/assets/data-C-x5EHyi.js +1 -0
  127. package/payload/server/public/assets/data-C-x5EHyi.js.br +1 -0
  128. package/payload/server/public/assets/data-C-x5EHyi.js.gz +0 -0
  129. package/payload/server/public/assets/file-text-CBaewT76.js +1 -0
  130. package/payload/server/public/assets/file-text-CBaewT76.js.br +0 -0
  131. package/payload/server/public/assets/file-text-CBaewT76.js.gz +0 -0
  132. package/payload/server/public/assets/{graph-Bo-WcsKS.js → graph-B8-e2_Z-.js} +3 -3
  133. package/payload/server/public/assets/graph-B8-e2_Z-.js.br +0 -0
  134. package/payload/server/public/assets/graph-B8-e2_Z-.js.gz +0 -0
  135. package/payload/server/public/assets/graph-labels-Bsc23eZU.js +1 -0
  136. package/payload/server/public/assets/graph-labels-Bsc23eZU.js.br +0 -0
  137. package/payload/server/public/assets/graph-labels-Bsc23eZU.js.gz +0 -0
  138. package/payload/server/public/assets/operator-Cve0-qfO.js +1 -0
  139. package/payload/server/public/assets/operator-Cve0-qfO.js.br +0 -0
  140. package/payload/server/public/assets/operator-Cve0-qfO.js.gz +0 -0
  141. package/payload/server/public/assets/page-BgVMs6Vf.js +1 -0
  142. package/payload/server/public/assets/page-BgVMs6Vf.js.br +0 -0
  143. package/payload/server/public/assets/page-BgVMs6Vf.js.gz +0 -0
  144. package/payload/server/public/assets/page-fABub-w8.js +32 -0
  145. package/payload/server/public/assets/page-fABub-w8.js.br +0 -0
  146. package/payload/server/public/assets/page-fABub-w8.js.gz +0 -0
  147. package/payload/server/public/assets/play-B6zXB9K7.js +1 -0
  148. package/payload/server/public/assets/play-B6zXB9K7.js.br +0 -0
  149. package/payload/server/public/assets/play-B6zXB9K7.js.gz +0 -0
  150. package/payload/server/public/assets/public--R2DbdWs.js +1 -0
  151. package/payload/server/public/assets/public--R2DbdWs.js.br +0 -0
  152. package/payload/server/public/assets/public--R2DbdWs.js.gz +0 -0
  153. package/payload/server/public/assets/rotate-ccw-FZW7c8p8.js +1 -0
  154. package/payload/server/public/assets/rotate-ccw-FZW7c8p8.js.br +0 -0
  155. package/payload/server/public/assets/rotate-ccw-FZW7c8p8.js.gz +0 -0
  156. package/payload/server/public/assets/routines-BpZs2SaT.js +2 -0
  157. package/payload/server/public/assets/routines-BpZs2SaT.js.br +0 -0
  158. package/payload/server/public/assets/routines-BpZs2SaT.js.gz +0 -0
  159. package/payload/server/public/assets/skills-DF7uyEEz.js +1 -0
  160. package/payload/server/public/assets/skills-DF7uyEEz.js.br +0 -0
  161. package/payload/server/public/assets/skills-DF7uyEEz.js.gz +0 -0
  162. package/payload/server/public/assets/tasks-BfJJmoWO.js +3 -0
  163. package/payload/server/public/assets/tasks-BfJJmoWO.js.br +0 -0
  164. package/payload/server/public/assets/tasks-BfJJmoWO.js.gz +0 -0
  165. package/payload/server/public/assets/triangle-alert-CR-jRJdI.js +1 -0
  166. package/payload/server/public/assets/triangle-alert-CR-jRJdI.js.br +0 -0
  167. package/payload/server/public/assets/triangle-alert-CR-jRJdI.js.gz +0 -0
  168. package/payload/server/public/assets/useCopyFeedback-IOuPUAHY.js +1 -0
  169. package/payload/server/public/assets/useCopyFeedback-IOuPUAHY.js.br +0 -0
  170. package/payload/server/public/assets/useCopyFeedback-IOuPUAHY.js.gz +0 -0
  171. package/payload/server/public/assets/{useSubAccountSwitcher-CVHqKsqK.js → useMediaQuery-CA6dR5iz.js} +1 -1
  172. package/payload/server/public/assets/useMediaQuery-CA6dR5iz.js.br +0 -0
  173. package/payload/server/public/assets/{useSubAccountSwitcher-CVHqKsqK.js.gz → useMediaQuery-CA6dR5iz.js.gz} +0 -0
  174. package/payload/server/public/assets/{useSubAccountSwitcher-yN4lhH2x.css → useMediaQuery-DpwgV1Da.css} +1 -1
  175. package/payload/server/public/assets/useMediaQuery-DpwgV1Da.css.br +0 -0
  176. package/payload/server/public/assets/{useSubAccountSwitcher-yN4lhH2x.css.gz → useMediaQuery-DpwgV1Da.css.gz} +0 -0
  177. package/payload/server/public/assets/useVoiceRecorder-DGhsN7nV.js +2 -0
  178. package/payload/server/public/assets/useVoiceRecorder-DGhsN7nV.js.br +0 -0
  179. package/payload/server/public/assets/useVoiceRecorder-DGhsN7nV.js.gz +0 -0
  180. package/payload/server/public/assets/wrench-CpCOYUBc.js +1 -0
  181. package/payload/server/public/assets/wrench-CpCOYUBc.js.br +0 -0
  182. package/payload/server/public/assets/wrench-CpCOYUBc.js.gz +0 -0
  183. package/payload/server/public/browser.html +4 -4
  184. package/payload/server/public/calendar.html +8 -7
  185. package/payload/server/public/chat.html +13 -13
  186. package/payload/server/public/data.html +11 -11
  187. package/payload/server/public/graph.html +9 -9
  188. package/payload/server/public/index.html +14 -14
  189. package/payload/server/public/operator.html +14 -14
  190. package/payload/server/public/public.html +13 -13
  191. package/payload/server/public/routines.html +6 -6
  192. package/payload/server/public/skills.html +5 -5
  193. package/payload/server/public/tasks.html +6 -6
  194. package/payload/server/server.js +476 -148
  195. package/payload/server/public/assets/AdminLoginScreens-CfXQwKIY.js +0 -1
  196. package/payload/server/public/assets/AdminLoginScreens-CfXQwKIY.js.br +0 -0
  197. package/payload/server/public/assets/AdminLoginScreens-CfXQwKIY.js.gz +0 -0
  198. package/payload/server/public/assets/AdminShell-y0_mzlDF.js +0 -2
  199. package/payload/server/public/assets/AdminShell-y0_mzlDF.js.br +0 -0
  200. package/payload/server/public/assets/AdminShell-y0_mzlDF.js.gz +0 -0
  201. package/payload/server/public/assets/activity-h8-sjHz9.js +0 -1
  202. package/payload/server/public/assets/activity-h8-sjHz9.js.br +0 -0
  203. package/payload/server/public/assets/activity-h8-sjHz9.js.gz +0 -0
  204. package/payload/server/public/assets/admin-BzhhLC7C.js +0 -1
  205. package/payload/server/public/assets/admin-BzhhLC7C.js.br +0 -0
  206. package/payload/server/public/assets/admin-BzhhLC7C.js.gz +0 -0
  207. package/payload/server/public/assets/agents-DLuhIIgn.js +0 -1
  208. package/payload/server/public/assets/agents-DLuhIIgn.js.br +0 -0
  209. package/payload/server/public/assets/agents-DLuhIIgn.js.gz +0 -0
  210. package/payload/server/public/assets/browser-FAnTY27n.js +0 -1
  211. package/payload/server/public/assets/browser-FAnTY27n.js.br +0 -0
  212. package/payload/server/public/assets/browser-FAnTY27n.js.gz +0 -0
  213. package/payload/server/public/assets/calendar-C_PkqlkQ.js +0 -1
  214. package/payload/server/public/assets/calendar-C_PkqlkQ.js.br +0 -0
  215. package/payload/server/public/assets/calendar-C_PkqlkQ.js.gz +0 -0
  216. package/payload/server/public/assets/chat-DW81Ra89.js +0 -1
  217. package/payload/server/public/assets/chat-DW81Ra89.js.br +0 -0
  218. package/payload/server/public/assets/chat-DW81Ra89.js.gz +0 -0
  219. package/payload/server/public/assets/chevron-left-zV-WRzHb.js +0 -1
  220. package/payload/server/public/assets/chevron-left-zV-WRzHb.js.br +0 -0
  221. package/payload/server/public/assets/chevron-right-fnINU4bx.js +0 -1
  222. package/payload/server/public/assets/chevron-right-fnINU4bx.js.br +0 -0
  223. package/payload/server/public/assets/clock-2fSxBl6d.js +0 -1
  224. package/payload/server/public/assets/clock-2fSxBl6d.js.br +0 -0
  225. package/payload/server/public/assets/copy-Rde_TL9Q.js +0 -1
  226. package/payload/server/public/assets/copy-Rde_TL9Q.js.br +0 -0
  227. package/payload/server/public/assets/copy-Rde_TL9Q.js.gz +0 -0
  228. package/payload/server/public/assets/data-S5g4wIDe.js +0 -1
  229. package/payload/server/public/assets/data-S5g4wIDe.js.br +0 -0
  230. package/payload/server/public/assets/data-S5g4wIDe.js.gz +0 -0
  231. package/payload/server/public/assets/file-text-DMCUVg80.js +0 -1
  232. package/payload/server/public/assets/file-text-DMCUVg80.js.br +0 -0
  233. package/payload/server/public/assets/file-text-DMCUVg80.js.gz +0 -0
  234. package/payload/server/public/assets/graph-Bo-WcsKS.js.br +0 -0
  235. package/payload/server/public/assets/graph-Bo-WcsKS.js.gz +0 -0
  236. package/payload/server/public/assets/graph-labels-g-JodMWQ.js +0 -1
  237. package/payload/server/public/assets/graph-labels-g-JodMWQ.js.br +0 -0
  238. package/payload/server/public/assets/graph-labels-g-JodMWQ.js.gz +0 -0
  239. package/payload/server/public/assets/operator-X_LcOnAI.js +0 -1
  240. package/payload/server/public/assets/operator-X_LcOnAI.js.br +0 -0
  241. package/payload/server/public/assets/operator-X_LcOnAI.js.gz +0 -0
  242. package/payload/server/public/assets/page-Cz0p1mBf.js +0 -1
  243. package/payload/server/public/assets/page-Cz0p1mBf.js.br +0 -0
  244. package/payload/server/public/assets/page-Cz0p1mBf.js.gz +0 -0
  245. package/payload/server/public/assets/page-Dzs3MsFL.js +0 -32
  246. package/payload/server/public/assets/page-Dzs3MsFL.js.br +0 -0
  247. package/payload/server/public/assets/page-Dzs3MsFL.js.gz +0 -0
  248. package/payload/server/public/assets/play-CraN5kUU.js +0 -1
  249. package/payload/server/public/assets/play-CraN5kUU.js.br +0 -0
  250. package/payload/server/public/assets/play-CraN5kUU.js.gz +0 -0
  251. package/payload/server/public/assets/public--NUjaJ-q.js +0 -1
  252. package/payload/server/public/assets/public--NUjaJ-q.js.br +0 -0
  253. package/payload/server/public/assets/public--NUjaJ-q.js.gz +0 -0
  254. package/payload/server/public/assets/rotate-ccw-DshFgg2T.js +0 -1
  255. package/payload/server/public/assets/rotate-ccw-DshFgg2T.js.br +0 -0
  256. package/payload/server/public/assets/rotate-ccw-DshFgg2T.js.gz +0 -0
  257. package/payload/server/public/assets/routines-CfAS4gri.js +0 -2
  258. package/payload/server/public/assets/routines-CfAS4gri.js.br +0 -0
  259. package/payload/server/public/assets/routines-CfAS4gri.js.gz +0 -0
  260. package/payload/server/public/assets/skills-CM6ryWpx.js +0 -1
  261. package/payload/server/public/assets/skills-CM6ryWpx.js.br +0 -0
  262. package/payload/server/public/assets/skills-CM6ryWpx.js.gz +0 -0
  263. package/payload/server/public/assets/tasks-B07m9LIA.js +0 -3
  264. package/payload/server/public/assets/tasks-B07m9LIA.js.br +0 -0
  265. package/payload/server/public/assets/tasks-B07m9LIA.js.gz +0 -0
  266. package/payload/server/public/assets/triangle-alert-CKHyS_gC.js +0 -1
  267. package/payload/server/public/assets/triangle-alert-CKHyS_gC.js.br +0 -0
  268. package/payload/server/public/assets/triangle-alert-CKHyS_gC.js.gz +0 -0
  269. package/payload/server/public/assets/useCopyFeedback-CmawEsVi.js +0 -1
  270. package/payload/server/public/assets/useCopyFeedback-CmawEsVi.js.br +0 -0
  271. package/payload/server/public/assets/useCopyFeedback-CmawEsVi.js.gz +0 -0
  272. package/payload/server/public/assets/useSubAccountSwitcher-CVHqKsqK.js.br +0 -0
  273. package/payload/server/public/assets/useSubAccountSwitcher-yN4lhH2x.css.br +0 -0
  274. package/payload/server/public/assets/useVoiceRecorder-DpQTvvqD.js +0 -2
  275. package/payload/server/public/assets/useVoiceRecorder-DpQTvvqD.js.br +0 -0
  276. package/payload/server/public/assets/useVoiceRecorder-DpQTvvqD.js.gz +0 -0
  277. package/payload/server/public/assets/wrench-BPOEUNJB.js +0 -1
  278. package/payload/server/public/assets/wrench-BPOEUNJB.js.br +0 -0
  279. package/payload/server/public/assets/wrench-BPOEUNJB.js.gz +0 -0
@@ -0,0 +1,9 @@
1
+ export type AgentConfigVerdict = {
2
+ ok: true;
3
+ } | {
4
+ ok: false;
5
+ field: string;
6
+ detail: string;
7
+ };
8
+ export declare function validateAgentConfig(config: unknown): AgentConfigVerdict;
9
+ //# sourceMappingURL=agent-config-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-config-schema.d.ts","sourceRoot":"","sources":["../../src/tools/agent-config-schema.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,kBAAkB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7F,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,kBAAkB,CAuCvE"}
@@ -0,0 +1,49 @@
1
+ import { isSelectableModel } from "../../../../../lib/models/dist/index.js";
2
+ // What a public agent's config.json must satisfy to be servable.
3
+ //
4
+ // resolveAgentConfig (platform/ui/app/lib/claude-agent/account.ts) silently
5
+ // defaults every bad field: an unknown status makes the agent unreachable with
6
+ // no error, an unselectable model fails at spawn, a missing displayName renders
7
+ // the slug in the chat header. Refusing at the write boundary turns each of
8
+ // those into a message the operator reads before the file exists.
9
+ //
10
+ // Unknown keys pass. A forward-compatible field written by an unreleased
11
+ // feature must not be rejected by a validator that predates it.
12
+ const LEGAL_STATUS = ["active", "inactive"];
13
+ const LEGAL_IMAGE_SHAPE = ["circle", "rounded"];
14
+ const LEGAL_ACCESS_MODE = ["open", "gated", "paid"];
15
+ const MAX_KNOWLEDGE_KEYWORDS = 5;
16
+ export function validateAgentConfig(config) {
17
+ if (typeof config !== "object" || config === null || Array.isArray(config)) {
18
+ return { ok: false, field: "(root)", detail: "config must be a JSON object" };
19
+ }
20
+ const c = config;
21
+ if (typeof c.displayName !== "string" || c.displayName.trim() === "") {
22
+ return { ok: false, field: "displayName", detail: "required, must be a non-blank string" };
23
+ }
24
+ if (typeof c.model !== "string" || !isSelectableModel(c.model)) {
25
+ return { ok: false, field: "model", detail: "required, must be a selectable platform model id" };
26
+ }
27
+ if (typeof c.status !== "string" || !LEGAL_STATUS.includes(c.status)) {
28
+ return { ok: false, field: "status", detail: `required, must be one of ${LEGAL_STATUS.join(" | ")}` };
29
+ }
30
+ if (c.imageShape !== undefined && (typeof c.imageShape !== "string" || !LEGAL_IMAGE_SHAPE.includes(c.imageShape))) {
31
+ return { ok: false, field: "imageShape", detail: `must be one of ${LEGAL_IMAGE_SHAPE.join(" | ")} when present` };
32
+ }
33
+ if (c.accessMode !== undefined && (typeof c.accessMode !== "string" || !LEGAL_ACCESS_MODE.includes(c.accessMode))) {
34
+ return { ok: false, field: "accessMode", detail: `must be one of ${LEGAL_ACCESS_MODE.join(" | ")} when present` };
35
+ }
36
+ if (c.knowledgeKeywords !== undefined) {
37
+ if (!Array.isArray(c.knowledgeKeywords)) {
38
+ return { ok: false, field: "knowledgeKeywords", detail: "must be an array of strings when present" };
39
+ }
40
+ if (c.knowledgeKeywords.length > MAX_KNOWLEDGE_KEYWORDS) {
41
+ return { ok: false, field: "knowledgeKeywords", detail: `at most ${MAX_KNOWLEDGE_KEYWORDS} entries` };
42
+ }
43
+ if (c.knowledgeKeywords.some((k) => typeof k !== "string")) {
44
+ return { ok: false, field: "knowledgeKeywords", detail: "every entry must be a string" };
45
+ }
46
+ }
47
+ return { ok: true };
48
+ }
49
+ //# sourceMappingURL=agent-config-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-config-schema.js","sourceRoot":"","sources":["../../src/tools/agent-config-schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ export type AgentWriteRefusal = "slug-unsafe" | "config-invalid" | "knowledge-empty" | "exists" | "not-found";
2
+ export type AgentWriteResult = {
3
+ ok: true;
4
+ slug: string;
5
+ filesWritten: string[];
6
+ } | {
7
+ ok: false;
8
+ reason: AgentWriteRefusal;
9
+ detail: string;
10
+ };
11
+ export interface CreateAgentArgs {
12
+ accountDir: string;
13
+ platformRoot: string;
14
+ slug: string;
15
+ displayName: string;
16
+ model: string;
17
+ soul: string;
18
+ knowledge: string;
19
+ knowledgeKeywords?: string[];
20
+ status?: string;
21
+ showAgentName?: boolean | "none";
22
+ accessMode?: string;
23
+ }
24
+ export interface UpdateAgentArgs {
25
+ accountDir: string;
26
+ slug: string;
27
+ displayName?: string;
28
+ model?: string;
29
+ soul?: string;
30
+ knowledge?: string;
31
+ knowledgeKeywords?: string[];
32
+ status?: string;
33
+ showAgentName?: boolean | "none";
34
+ accessMode?: string;
35
+ }
36
+ export declare function createAgent(args: CreateAgentArgs): AgentWriteResult;
37
+ export declare function updateAgent(args: UpdateAgentArgs): AgentWriteResult;
38
+ export interface ProjectOpts {
39
+ platformPort: string;
40
+ accountId: string;
41
+ slug: string;
42
+ houseAdminScope?: string;
43
+ /** Injected in tests. Production passes nothing and the global fetch is used. */
44
+ fetchImpl?: typeof fetch;
45
+ }
46
+ /**
47
+ * Project the on-disk agent into the graph through the platform route that
48
+ * already owns the projector, rather than re-implementing the MERGE here. The
49
+ * returned `projected` is read from the response, never assumed: a write that
50
+ * succeeded with `projected=0` is the beagle state (files on disk, no :Agent
51
+ * node) and must be reportable as such.
52
+ *
53
+ * What authorises the call is the loopback peer, not the header:
54
+ * `authorizeAccountWrite` (platform/ui/server/routes/admin/_account-scope.ts:67)
55
+ * returns `via: "on-device"` for any 127.0.0.1 caller with no x-forwarded-for,
56
+ * and never reads x-maxy-caller-account. The header is still sent because it is
57
+ * the identity every other admin-MCP call to the platform carries, so the
58
+ * route's gate can tighten without this caller becoming the exception.
59
+ */
60
+ export declare function projectAgentViaPlatform(opts: ProjectOpts): Promise<{
61
+ projected: number;
62
+ error?: string;
63
+ }>;
64
+ //# sourceMappingURL=agent-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-write.d.ts","sourceRoot":"","sources":["../../src/tools/agent-write.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,iBAAiB,GACzB,aAAa,GACb,gBAAgB,GAChB,iBAAiB,GACjB,QAAQ,GACR,WAAW,CAAC;AAEhB,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,GAClD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA8BD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,gBAAgB,CAsDnE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,gBAAgB,CA4CnE;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAmB/G"}
@@ -0,0 +1,151 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { checkAgentSlug } from "../../../../../lib/agent-slug/dist/index.js";
4
+ import { validateAgentConfig } from "./agent-config-schema.js";
5
+ function agentDirOf(accountDir, slug) {
6
+ return resolve(accountDir, "agents", slug);
7
+ }
8
+ /** Config fields the tools own. An absent optional is left out of the file
9
+ * entirely rather than written as null, so the result matches what the admin
10
+ * UI's creation form produces. */
11
+ function buildConfig(base, args) {
12
+ const next = { ...base };
13
+ if (args.displayName !== undefined)
14
+ next.displayName = args.displayName;
15
+ if (args.model !== undefined)
16
+ next.model = args.model;
17
+ if (args.status !== undefined)
18
+ next.status = args.status;
19
+ if (args.knowledgeKeywords !== undefined)
20
+ next.knowledgeKeywords = args.knowledgeKeywords;
21
+ if (args.showAgentName !== undefined)
22
+ next.showAgentName = args.showAgentName;
23
+ if (args.accessMode !== undefined)
24
+ next.accessMode = args.accessMode;
25
+ return next;
26
+ }
27
+ export function createAgent(args) {
28
+ const verdict = checkAgentSlug(args.slug);
29
+ if (!verdict.ok)
30
+ return { ok: false, reason: "slug-unsafe", detail: verdict.reason };
31
+ const dir = agentDirOf(args.accountDir, args.slug);
32
+ if (existsSync(dir)) {
33
+ return { ok: false, reason: "exists", detail: `agents/${args.slug}/ already exists` };
34
+ }
35
+ if (args.knowledge.trim() === "") {
36
+ return { ok: false, reason: "knowledge-empty", detail: "KNOWLEDGE.md would be empty" };
37
+ }
38
+ const config = buildConfig({}, {
39
+ displayName: args.displayName,
40
+ model: args.model,
41
+ status: args.status ?? "active",
42
+ knowledgeKeywords: args.knowledgeKeywords,
43
+ showAgentName: args.showAgentName,
44
+ accessMode: args.accessMode,
45
+ });
46
+ const configVerdict = validateAgentConfig(config);
47
+ if (!configVerdict.ok) {
48
+ return { ok: false, reason: "config-invalid", detail: configVerdict.field };
49
+ }
50
+ // IDENTITY.md is Rubytech-controlled and copied verbatim. It is not a
51
+ // caller-supplied field: the toolless-public directive is the one part of a
52
+ // public agent the operator does not author. Read before mkdir so an absent
53
+ // template refuses instead of leaving three of the four files on disk.
54
+ const identityPath = resolve(args.platformRoot, "templates", "agents", "public", "IDENTITY.md");
55
+ if (!existsSync(identityPath)) {
56
+ return { ok: false, reason: "not-found", detail: `IDENTITY template missing at ${identityPath}` };
57
+ }
58
+ const identity = readFileSync(identityPath, "utf-8");
59
+ mkdirSync(dir, { recursive: true });
60
+ try {
61
+ writeFileSync(resolve(dir, "IDENTITY.md"), identity);
62
+ writeFileSync(resolve(dir, "SOUL.md"), args.soul);
63
+ writeFileSync(resolve(dir, "KNOWLEDGE.md"), args.knowledge);
64
+ writeFileSync(resolve(dir, "config.json"), `${JSON.stringify(config, null, 2)}\n`);
65
+ }
66
+ catch (err) {
67
+ // The directory did not exist before this call, so removing it restores the
68
+ // pre-call state exactly. A half-written agent is worse than none: it would
69
+ // fail the `exists` check on the retry.
70
+ rmSync(dir, { recursive: true, force: true });
71
+ throw err;
72
+ }
73
+ return { ok: true, slug: args.slug, filesWritten: ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md", "config.json"] };
74
+ }
75
+ export function updateAgent(args) {
76
+ const verdict = checkAgentSlug(args.slug);
77
+ if (!verdict.ok)
78
+ return { ok: false, reason: "slug-unsafe", detail: verdict.reason };
79
+ const dir = agentDirOf(args.accountDir, args.slug);
80
+ const configPath = resolve(dir, "config.json");
81
+ if (!existsSync(configPath)) {
82
+ return { ok: false, reason: "not-found", detail: `no config.json at agents/${args.slug}/` };
83
+ }
84
+ if (args.knowledge !== undefined && args.knowledge.trim() === "") {
85
+ return { ok: false, reason: "knowledge-empty", detail: "KNOWLEDGE.md would be empty" };
86
+ }
87
+ let base;
88
+ try {
89
+ base = JSON.parse(readFileSync(configPath, "utf-8"));
90
+ }
91
+ catch (err) {
92
+ return {
93
+ ok: false,
94
+ reason: "config-invalid",
95
+ detail: `existing config.json is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
96
+ };
97
+ }
98
+ const config = buildConfig(base, args);
99
+ const configVerdict = validateAgentConfig(config);
100
+ if (!configVerdict.ok) {
101
+ return { ok: false, reason: "config-invalid", detail: configVerdict.field };
102
+ }
103
+ const written = [];
104
+ if (args.soul !== undefined) {
105
+ writeFileSync(resolve(dir, "SOUL.md"), args.soul);
106
+ written.push("SOUL.md");
107
+ }
108
+ if (args.knowledge !== undefined) {
109
+ writeFileSync(resolve(dir, "KNOWLEDGE.md"), args.knowledge);
110
+ written.push("KNOWLEDGE.md");
111
+ }
112
+ writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
113
+ written.push("config.json");
114
+ return { ok: true, slug: args.slug, filesWritten: written };
115
+ }
116
+ /**
117
+ * Project the on-disk agent into the graph through the platform route that
118
+ * already owns the projector, rather than re-implementing the MERGE here. The
119
+ * returned `projected` is read from the response, never assumed: a write that
120
+ * succeeded with `projected=0` is the beagle state (files on disk, no :Agent
121
+ * node) and must be reportable as such.
122
+ *
123
+ * What authorises the call is the loopback peer, not the header:
124
+ * `authorizeAccountWrite` (platform/ui/server/routes/admin/_account-scope.ts:67)
125
+ * returns `via: "on-device"` for any 127.0.0.1 caller with no x-forwarded-for,
126
+ * and never reads x-maxy-caller-account. The header is still sent because it is
127
+ * the identity every other admin-MCP call to the platform carries, so the
128
+ * route's gate can tighten without this caller becoming the exception.
129
+ */
130
+ export async function projectAgentViaPlatform(opts) {
131
+ const headers = {
132
+ "content-type": "application/json",
133
+ "x-maxy-caller-account": opts.accountId,
134
+ };
135
+ if (opts.houseAdminScope)
136
+ headers["x-maxy-house-admin-scope"] = opts.houseAdminScope;
137
+ const url = `http://127.0.0.1:${opts.platformPort}/api/admin/agents/${opts.slug}/project?accountId=${opts.accountId}`;
138
+ const doFetch = opts.fetchImpl ?? fetch;
139
+ try {
140
+ const res = await doFetch(url, { method: "POST", headers, signal: AbortSignal.timeout(5000) });
141
+ if (!res.ok) {
142
+ const body = await res.text().catch(() => "");
143
+ return { projected: 0, error: `projection route returned ${res.status} ${body}`.trim() };
144
+ }
145
+ return { projected: 1 };
146
+ }
147
+ catch (err) {
148
+ return { projected: 0, error: err instanceof Error ? err.message : String(err) };
149
+ }
150
+ }
151
+ //# sourceMappingURL=agent-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-write.js","sourceRoot":"","sources":["../../src/tools/agent-write.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: platform-architecture
3
3
  description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
4
- content-hash: sha256:08b03d80446b9b08b4b64926a3ac7d7f55a6f07d4182512dcca1d107c78cc9a2
4
+ content-hash: sha256:3b275a96d70deb1ae39a1fe77c45c8dbc5beb65985a7c5fea62927b99c97e46b
5
5
  brand: maxy-code
6
6
  product-name: Maxy
7
7
  ---
@@ -1695,7 +1695,9 @@ Every turn carries a `source`. Three values exist:
1695
1695
  | `schedule` | The scheduler wrote this turn. The named destination did not send it. |
1696
1696
  | `public-relay` | The platform wrote this turn because a public visitor messaged the account. The named sender is a manager being told, not someone who wrote to you. |
1697
1697
 
1698
- A `public-relay` turn also says so in its own first two lines. If a turn claims a manager wrote something they plainly would not have written, check the source before answering them.
1698
+ A `public-relay` turn also says so in its own first two lines, and states which handset its reply tool reaches. That handset is the manager's, never the visitor's: the turn runs in the manager's own admin session, so a reply written to the visitor is delivered to the manager. If a turn claims a manager wrote something they plainly would not have written, check the source before answering them.
1699
+
1700
+ **On a `public-relay` turn the reply tool is the only way to reach anyone.** On an ordinary turn the platform forwards your closing text to the sender when you called no reply tool. On a relay-woken turn it does not, because the relay carries its own reply path. So whatever you decide the manager should receive has to go through the reply tool; text you merely write at the end of the turn reaches nobody, and a decision not to reply is silence rather than a message.
1699
1701
 
1700
1702
  ## Which files compose the prompt
1701
1703
 
@@ -1712,7 +1714,7 @@ A public agent's directory also carries `KNOWLEDGE.md` and `config.json`. An acc
1712
1714
 
1713
1715
  ## The switches, and what each one stops
1714
1716
 
1715
- Four settings sit on this path. They are not interchangeable, and reaching for the wrong one is how an operator ends up silencing more than they meant.
1717
+ Five settings sit on this path. They are not interchangeable, and reaching for the wrong one is how an operator ends up silencing more than they meant.
1716
1718
 
1717
1719
  | Setting | What it stops | What it leaves running |
1718
1720
  |---|---|---|
@@ -1720,6 +1722,7 @@ Four settings sit on this path. They are not interchangeable, and reaching for t
1720
1722
  | `publicAgentEnabled: false` | The visitor gets no reply. | The manager notification and the relay. |
1721
1723
  | `managerNotifyEnabled: false` | The verbatim copy of the visitor's message. | The relay, and any reply the woken turn sends. |
1722
1724
  | `dispatchInbound: false` | Every agent turn on that account's socket. | Storage: messages are still stored and readable. |
1725
+ | `dispatch: false` on one registered party | The public-agent turn for that one phone. | Everything else: storage, the label, the manager notification, the relay, and every other sender on the line. |
1723
1726
 
1724
1727
  `managerNotifyEnabled` is the fine-grained one, and the one to reach for when the notifications are unwanted but the work is not. Unbinding a manager is not a substitute: the manager registry is shared by the notification, the relay and `whatsapp-notify-manager`, so unbinding silences all three.
1725
1728
 
@@ -1727,19 +1730,37 @@ Read the current value with `whatsapp-config {action:'get-manager-notify-enabled
1727
1730
 
1728
1731
  ## When the answer is not here
1729
1732
 
1730
- `logs-read --tail server` and filter on the tags. One public inbound writes this chain, in order, with `account=` and `sender=` on each line:
1733
+ `logs-read --tail server` and filter on the tags. One public inbound writes this chain, in order:
1734
+
1735
+ ```
1736
+ [whatsapp:wire] op=stanza msgId=<id>
1737
+ [wa-notify] op=eligible msgId=<id> reason=<how the sender was admitted>
1738
+ [whatsapp:route] op=routed inboundId=<id> msgIds=<the stanzas this payload covers>
1739
+ [whatsapp:notify] op=public-inbound inboundId=<id> enabled=0|1 outcome=sent|failed|no-recipients|disabled
1740
+ [whatsapp:relay] op=dispatch inboundId=<id> outcome=sent|failed|no-recipients
1741
+ [whatsapp:party] op=dispatch-decision inboundId=<id> party=… dispatch=true|false spawned=0|1 (labelled senders only)
1742
+ [whatsapp:public-agent] op=route inboundId=<id> enabled=… slug=… spawned=0|1
1743
+ [whatsapp:public-agent] op=spawn-ok | op=spawn-failed inboundId=<id>
1744
+ ```
1745
+
1746
+ Follow one inbound by its `inboundId`. That selects the last five lines and nothing else, however many visitors messaged in the same window. For the first two, read `msgIds=` off the `op=routed` line and grep one of those ids. Two greps rather than one, because the debouncer merges stanzas into a single routed payload and the two halves are keyed either side of that merge.
1747
+
1748
+ Anything that failed carries the same id: the drop lines, `op=public-inbound-rejected`, `op=dispatch-rejected` and `op=spawn-failed`. Fewer lines than expected, with none of them a failure, means a step emitted nothing at all — which is what the standing audits below are for.
1749
+
1750
+ Do not try to follow an inbound by its sender. `sender=` appears on two of these lines, and the same visitor is a LID on `op=stanza` and an E.164 on `op=routed`, so no sender-based filter spans the merge.
1751
+
1752
+ `op=spawn-failed` there is the WhatsApp side reporting a 500. What the spawn itself did is in the manager's own lines, correlated by `pid`:
1731
1753
 
1732
1754
  ```
1733
- [whatsapp:wire] op=stanza
1734
- [wa-notify] op=eligible reason=<how the sender was admitted>
1735
- [whatsapp:route] op=routed agentType=public
1736
- [whatsapp:notify] op=public-inbound enabled=0|1 outcome=sent|failed|no-recipients|disabled
1737
- [whatsapp:relay] op=dispatch outcome=sent|failed|no-recipients
1738
- [whatsapp:public-agent] op=route enabled=… slug=… spawned=0|1
1739
- [whatsapp:public-agent] op=spawn-ok | op=spawn-failed
1755
+ op=startup-watch state=armed
1756
+ op=public-dev-channel-confirmed channel=<kind> bufferCleared=<bool> bytesDropped=<n>
1757
+ op=startup-watch state=reset
1758
+ op=startup-watch state=disposed
1740
1759
  ```
1741
1760
 
1742
- Three standing audits reconcile that chain rather than waiting for someone to notice. `op=public-notify-reconcile` reports `gap`, `relayGap` and `englishGap`, each of which counts a step that a routed inbound reached and the next one did not. `op=spawn-census` reports attempts against successes. A non-zero gap, or attempts with no successes, is a fault even when nothing has been reported.
1761
+ The first-run dialog is answered for the session, and the watcher that guards against an *unanswered* one drops what it saw before that answer. `bufferCleared=false` means the confirm fired and the drop did not, which is the shape that killed a resumed spawn on 2026-08-01: the answered dialog's own footer stayed in the buffer, the replayed transcript slid past it, and the spawn was blocked by a line the agent itself had written the day before.
1762
+
1763
+ Three standing audits reconcile that chain rather than waiting for someone to notice. `op=public-notify-reconcile` reports `gap`, `relayGap` and `answerGap`, each of which counts a step that a routed inbound reached and the next one did not. `op=spawn-census` reports attempts against successes. A non-zero gap, or attempts with no successes, is a fault even when nothing has been reported.
1743
1764
 
1744
1765
  ---
1745
1766
  # Settings
@@ -3426,6 +3447,8 @@ either is a regression.
3426
3447
 
3427
3448
  **`/chat` empty-state starter chips.** While the admin webchat has no conversation JSONL yet (`GET /api/webchat/session` → `projectDir:null`), `app/chat/page.tsx` renders a "What's up next, {givenName}?" greeting (given name = first whitespace token of the admin session's `userName`; degrades to "What's up next?" without one) above three one-tap starter chips (replacing the earlier read-only lists): **Catch me up** (`Inbox`), **My day** (`CalendarClock`), **To-do** (`ListTodo`). `GreetingPanel` no longer fetches `GET /api/webchat/greeting` — the headline reads from the `userName` prop alone. A tap dispatches the chip's verbatim prompt through the existing `send()` with zero typing, via the same arm/fire path as the `?q=` handoff seed: `dispatchChip` logs `[admin-ui] op=chip-tap id=<catch-up|my-day|to-do> chars=<n>`, sets the composer text, and arms a one-shot effect that fires `send()` once the text matches. Chips gate to `variant` admin/operator; the public surface shows the headline alone. The first journaled turn replaces the panel with the transcript. The `/api/webchat/greeting` route (`server/routes/webchat-greeting.ts`) and `specialist-roster.ts` are now unconsumed by this surface — slimming them is a separate follow-up. The full webchat architecture lives in `.docs/admin-webchat-native-channel.md`.
3428
3449
 
3450
+ **`/chat` reply to a specific message.** Each of your own messages and each of the assistant's replies carries a reply control beside its copy button. Clicking it puts a strip above the composer naming who you are replying to and quoting the message; the X on that strip cancels. Sending delivers the quote to the agent as the first line of its context, so "redo that one" resolves to the message you pointed at, and the sent message keeps the quote visible above it when you reload. Two limits are deliberate: a message that arrived while the assistant was mid-turn cannot be quoted (the transcript records that arrival without an id to target), and tool runs, thinking runs and error banners are not reply targets. The quoted text is capped at 500 characters and is read from the conversation's own transcript server-side, never from the browser. The public visitor surface has no reply control. The full path is in `.docs/admin-webchat-native-channel.md`.
3451
+
3429
3452
  **`/chat` composer transport button.** The button at the end of the input shows a **microphone** while the box is empty — tap it to record a voice note. Type a character, or attach a file, and the same button becomes the **send** arrow; while the agent is replying it becomes a **stop** square. So an empty composer offers voice, a composer with something to send offers send, and a running turn offers stop — one button, three states. The microphone-device chooser (which input to record from) stays in the row of icons below the box. This is the same on the admin `/chat`, the public chat, and the maxy-lite webchat.
3430
3453
 
3431
3454
  **`/chat` Conversations flyout + zero-sessions splash.** The admin `/chat` `HeaderMenu` carries a **Conversations** item (rendered only when `onOpenConversations` is wired, which scopes it to `/chat`) that opens an in-chat session-management pane (`app/chat/SessionList.tsx`) hosted by `chat/page.tsx` — distinct from, and sharing endpoints with, the `Sidebar` Sessions list (which stays hidden on narrow viewports). It enumerates the admin's own webchat sessions via `GET /api/admin/sidebar-sessions` (carries the per-row `live` marker and `archived` flag, install-wide), **filtering out `channel:'whatsapp'`/`'telegram'` rows** (those are channel-bound, cannot be chatted in webchat, and live in the WhatsApp/Telegram reader panels; the same endpoint now also feeds the sidebar Sessions list, which does show them), lists the remainder newest-first with the live one marked and archived rows folded under a collapsible subsection, and offers per-row resume (`/chat?session=<id>`), rename, archive/unarchive, two-tap delete, an **End** control on the live row (`session-stop`), plus a New-session control (`session-rc-spawn`) and a copyable full id. The pane header carries the title and a top-right close (X) control that dismisses the flyout (no back-chevron/"Chat" label); the New-session control floats at the pane's bottom-left. When the canonical pointer is `known:false` (`canonical-empty`) and enumeration returns zero rows, the surface renders a splash (brand logo + New session) instead of a dead bootstrap thread; a freshly-spawned New session is `known:true`, so its greeting is preserved. Client breadcrumbs: `[chat-conversations] op=enumerate owned=<n>` and `op=action name=<open|rename|archive|delete|stop> sessionId=<id8>` (`op=action-failed … status=…` on a non-2xx). Detail lives in `.docs/admin-webchat-native-channel.md` ("Conversations flyout + zero-sessions splash").
@@ -3917,6 +3940,40 @@ explicit `?plugin=` parameter, not inferred from `--` in the slug.
3917
3940
  | `DELETE /api/admin/agents/:slug?accountId=` | Public agents only, on the named validated account. Removes the dir after `deleteAgentProjection`; refuses the `admin` slug (403) and a missing/unknown `accountId` (400) with no write. Loud-fail: a graph-cleanup throw aborts the file removal. |
3918
3941
  | `POST /api/admin/agents/:slug/project?accountId=` | Re-projects the named account's on-disk agent into the graph. Same `accountId` contract as delete. |
3919
3942
 
3943
+ ### Agent write tools (admin MCP)
3944
+
3945
+ Public-agent CRUD is tool-only. There is no create or update HTTP route: the three
3946
+ admin MCP tools own the write path, and raw file writes reach none of their checks.
3947
+ That is what left the `beagle` agent on disk and absent from the graph for a day.
3948
+
3949
+ | Tool | Refuses | On success |
3950
+ |---|---|---|
3951
+ | `agent-create` | `slug-unsafe` (shape, reserved or route-shadowed, by the same rule the router serves by), `exists` (the directory is occupied), `knowledge-empty`, `config-invalid` (naming the field), `not-found` (the platform IDENTITY template is missing). Every check runs before the first write, so a refusal leaves no directory. | Writes `IDENTITY.md` (copied verbatim from `templates/agents/public/`), `SOUL.md`, `KNOWLEDGE.md` and `config.json`, then projects. Returns an error when the write landed but the projection did not. |
3952
+ | `agent-update` | `slug-unsafe`, `not-found`, `knowledge-empty` when `knowledge` is supplied, `config-invalid` on the merged config. A refusal leaves the directory byte-identical. | Writes only the fields supplied, merges config fields into the existing file, then re-projects. Called with the slug alone it re-projects and nothing else. |
3953
+ | `agent-delete` | The `admin` slug, at the tool boundary as well as at the route. | Calls `DELETE /api/admin/agents/:slug`, which removes the graph projection before the directory and preserves the files if the graph write throws. |
3954
+
3955
+ The config schema (`plugins/admin/mcp/src/tools/agent-config-schema.ts`) requires a
3956
+ non-blank `displayName`, a `model` passing `isSelectableModel`, and a `status` of
3957
+ `active` or `inactive`; it constrains `imageShape`, `accessMode` and
3958
+ `knowledgeKeywords` when present, and passes unknown keys so a field written by an
3959
+ unreleased feature is not blocked. `KNOWLEDGE-SUMMARY.md` is the one agent file no
3960
+ write tool owns; write it directly and the next `agent-update` projects it.
3961
+
3962
+ Every call emits one line:
3963
+
3964
+ [admin/agents] op=agent-write action=<create|update|delete> slug=<slug> accountId=<8>
3965
+ outcome=<ok|refused> reason=<slug-unsafe|config-invalid|knowledge-empty|exists|not-found|projection-failed|delete-failed|write-failed|none>
3966
+ detail=<shape|reserved|shadowed|field|error text|-> projected=<n>
3967
+
3968
+ `projected` is read from the projection response, never assumed. The
3969
+ disk-without-graph signature is `action=create|update outcome=ok projected=0` —
3970
+ the action matters, because a successful delete also logs `projected=0`, having
3971
+ removed the projection on purpose.
3972
+
3973
+ `reason=write-failed` covers an unresolvable account directory or an I/O error.
3974
+ It exists because `getAccountDir` throws and the lifeline wrapper re-throws, so
3975
+ without a catch in the handler those failures would emit no line at all.
3976
+
3920
3977
  Observability rides `[admin/agents]`, and **every line names the account it acted
3921
3978
  on** (`accountId=<id8>`) — a well-formed answer about the wrong account is
3922
3979
  otherwise indistinguishable from a correct one, which is exactly how an empty
@@ -3937,6 +3994,19 @@ Agents page survived undiagnosed on a multi-account install.
3937
3994
  - `op=<delete|project> rejected reason=<missing-accountId|unknown-accountId>` —
3938
3995
  a caller that did not name its account. A skill that was not updated produces
3939
3996
  this on its first call instead of writing to the wrong account.
3997
+ - `op=project rejected reason=agent-not-on-disk accountId=<id8> slug=<…>
3998
+ probed=<agentDir>` — the projection 404. `probed` names the directory that
3999
+ actually resolved, so a "the route says not found, the files are plainly
4000
+ there" report is refutable without reproducing the call; before it existed the
4001
+ route returned that 404 silently and such a report could be neither confirmed
4002
+ nor refuted. Its two siblings are `op=project ok accountId=<id8> slug=<…>
4003
+ nodesWritten=<n>` and `op=project failed accountId=<id8> slug=<…>
4004
+ error="<msg>"` on a projector throw. `nodesWritten` counts nodes MERGEd — the
4005
+ Agent node plus one KnowledgeDocument per present body file — so it stays
4006
+ non-zero on an idempotent re-projection, and **`nodesWritten=0` on an `ok` is
4007
+ the defect signature**: `projectAgent` returns early without throwing on an
4008
+ unsafe slug, a missing `config.json` or a body-file read error, and the route
4009
+ answers `200 {"ok":true}` in all three cases.
3940
4010
  - `op=delete accountId=<id8> slug=<…> outcome=<ok|failed>` with
3941
4011
  `reason=<graph-cleanup-failed|rm-error>` on failure (files preserved on a
3942
4012
  graph-cleanup throw).
@@ -4340,6 +4410,30 @@ The companion `/api/admin/version` and `/api/admin/actions` routes are
4340
4410
  served by `maxy-edge.service`, not this aggregator. The edge process
4341
4411
  keeps the upgrade view alive while the brand service restarts.
4342
4412
 
4413
+ ### Phone-width layout overflow
4414
+
4415
+ If any part of an admin screen is cut off at the right edge on a phone —
4416
+ a header pill, a message bubble — the dashboard now reports it by itself
4417
+ rather than waiting for a screenshot. Every admin page measures its own
4418
+ width after it settles, and posts a record when something sticks out past
4419
+ the edge.
4420
+
4421
+ Read the reports with:
4422
+
4423
+ ```
4424
+ grep 'op=layout-overflow' ~/.<brand>/logs/client-errors.log
4425
+ ```
4426
+
4427
+ Each line names the page it happened on (`route`) and the element that
4428
+ stuck out (`offender`), so the cause is identifiable without reproducing
4429
+ it on a handset. A line with a `delta` but an empty `offender` means the
4430
+ measurement ran too early, which is a different fault from a cut-off
4431
+ page. No lines at all is the healthy state.
4432
+
4433
+ These reports share the client-error log, so they also count towards the
4434
+ 24-hour client-error figure shown on the upgrade view. A rise there with
4435
+ `op=layout-overflow` lines behind it is a layout problem, not a crash.
4436
+
4343
4437
  ## System-stats widget
4344
4438
 
4345
4439
  Source:
@@ -5399,7 +5493,7 @@ A `Service` node matched by vector search will have its `PriceSpecification`, `R
5399
5493
 
5400
5494
  ## Keyword Subscriptions — Reactive Per-Agent Knowledge
5401
5495
 
5402
- Each public agent can subscribe to up to 5 keywords via `knowledgeKeywords` in its `config.json`. These subscriptions make the agent reactive to new graph content matching its topics — content added after the agent was created becomes discoverable without manual tag updates.
5496
+ Each public agent can subscribe to up to 5 keywords via `knowledgeKeywords` in its `config.json`. Subscriptions default to empty and are opt-in: the operator asks for them or the agent has none. A subscription makes new graph content matching its topics **discoverable at the next refresh** it surfaces candidate lines for the operator to approve, and never adds anything to a public agent's knowledge on its own. Whatever a public agent can say is a line the operator approved for a stranger to read.
5403
5497
 
5404
5498
  ### Dual search per keyword
5405
5499
 
@@ -5417,7 +5511,7 @@ Results from keyword subscription searches are merged into the same scored map a
5417
5511
 
5418
5512
  ### Lifecycle
5419
5513
 
5420
- Keywords are consumed by the `update-knowledge` admin skill when regenerating KNOWLEDGE.md — the regeneration query broadens the operator-tagged set with keyword matches so newly-added graph content that shares a subscribed topic lands in the next baked snapshot. There is no runtime keyword-injection path on the public PTY surface.
5514
+ Keywords are consumed by the `update-knowledge` admin skill when regenerating KNOWLEDGE.md — the regeneration query broadens the operator-tagged set with keyword matches, so newly-added graph content sharing a subscribed topic is *proposed* for the next baked snapshot. It is proposed, not baked: the skill presents the gathered lines and writes only the ones the operator approves. There is no runtime keyword-injection path on the public PTY surface.
5421
5515
 
5422
5516
  ---
5423
5517