@rubytech/create-maxy-code 0.1.280 → 0.1.282

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 (234) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts +31 -43
  3. package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/mcp-spawn-tee/dist/index.js +112 -85
  5. package/payload/platform/lib/mcp-spawn-tee/dist/index.js.map +1 -1
  6. package/payload/platform/lib/mcp-spawn-tee/src/__tests__/spawn-tee.test.ts +111 -0
  7. package/payload/platform/lib/mcp-spawn-tee/src/index.ts +113 -84
  8. package/payload/platform/lib/mcp-spawn-tee/tsconfig.json +2 -1
  9. package/payload/platform/plugins/admin/PLUGIN.md +2 -1
  10. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-compliance.test.sh +154 -0
  11. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-directive.test.sh +24 -0
  12. package/payload/platform/plugins/admin/hooks/prompt-optimiser-compliance.sh +174 -0
  13. package/payload/platform/plugins/admin/hooks/prompt-optimiser-directive.sh +22 -2
  14. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4 -2
  15. package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +378 -56
  16. package/payload/platform/plugins/cloudflare/references/api.md +35 -1
  17. package/payload/platform/plugins/cloudflare/references/d1-data-capture.md +2 -0
  18. package/payload/platform/plugins/docs/references/cloudflare.md +1 -1
  19. package/payload/platform/plugins/docs/references/platform.md +2 -0
  20. package/payload/platform/plugins/email/PLUGIN.md +1 -1
  21. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.d.ts +2 -0
  22. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.d.ts.map +1 -0
  23. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.js +92 -0
  24. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.js.map +1 -0
  25. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.d.ts +2 -0
  26. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.d.ts.map +1 -0
  27. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js +55 -0
  28. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js.map +1 -0
  29. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.d.ts +2 -0
  30. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.d.ts.map +1 -0
  31. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.js +110 -0
  32. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.js.map +1 -0
  33. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.d.ts +2 -0
  34. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.d.ts.map +1 -0
  35. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.js +57 -0
  36. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.js.map +1 -0
  37. package/payload/platform/plugins/email/mcp/dist/index.js +8 -1
  38. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  39. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts +12 -0
  40. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts.map +1 -1
  41. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js +44 -5
  42. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js.map +1 -1
  43. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +13 -8
  44. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  45. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +26 -15
  46. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  47. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts +8 -0
  48. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts.map +1 -1
  49. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js.map +1 -1
  50. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts +16 -5
  51. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts.map +1 -1
  52. package/payload/platform/plugins/email/mcp/dist/lib/providers.js +120 -13
  53. package/payload/platform/plugins/email/mcp/dist/lib/providers.js.map +1 -1
  54. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js +3 -3
  55. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js.map +1 -1
  56. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts.map +1 -1
  57. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js +6 -2
  58. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js.map +1 -1
  59. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
  60. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +5 -3
  61. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
  62. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
  63. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +6 -3
  64. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
  65. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
  66. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +22 -4
  67. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
  68. package/payload/platform/plugins/email/mcp/package.json +4 -2
  69. package/payload/platform/plugins/email/mcp/vitest.config.ts +9 -0
  70. package/payload/platform/plugins/email/references/email-reference.md +22 -5
  71. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +1 -1
  72. package/payload/platform/plugins/graph/PLUGIN.md +2 -0
  73. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.d.ts +2 -0
  74. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.d.ts.map +1 -0
  75. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.js +31 -0
  76. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.js.map +1 -0
  77. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts +5 -0
  78. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts.map +1 -1
  79. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js +21 -2
  80. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js.map +1 -1
  81. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +1 -0
  82. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +5 -5
  83. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -1
  84. package/payload/platform/plugins/whatsapp/.claude-plugin/plugin.json +1 -1
  85. package/payload/platform/plugins/whatsapp/PLUGIN.md +7 -11
  86. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +10 -56
  87. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  88. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +26 -2
  89. package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +9 -14
  90. package/payload/platform/scripts/setup-account.sh +7 -0
  91. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  92. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +0 -2
  93. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  94. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  95. package/payload/platform/services/claude-session-manager/dist/http-server.js +63 -3
  96. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  97. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  98. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +7 -1
  99. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  100. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +6 -0
  101. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  102. package/payload/platform/services/whatsapp-channel/dist/notification.js +14 -0
  103. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  104. package/payload/platform/services/whatsapp-channel/dist/server.js +5 -3
  105. package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
  106. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  107. package/payload/server/public/assets/AdminShell-FO766lOW.js +1 -0
  108. package/payload/server/public/assets/{Checkbox-2reCESkb.js → Checkbox-syHoU9nY.js} +1 -1
  109. package/payload/server/public/assets/{admin-BpnsTEa3.js → admin-0_VxffD5.js} +1 -1
  110. package/payload/server/public/assets/{arc-BgelqC_3.js → arc-BW1WhwmV.js} +1 -1
  111. package/payload/server/public/assets/architecture-YZFGNWBL-xHbVjatf.js +1 -0
  112. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-BabnAZJm.js → architectureDiagram-Q4EWVU46-DsionCio.js} +1 -1
  113. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BJzZqNsy.js → blockDiagram-DXYQGD6D-NOG5yVZk.js} +1 -1
  114. package/payload/server/public/assets/{browser-fgBRZ5gK.js → browser-Cxjkhtsk.js} +1 -1
  115. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-By-xuh9F.js → c4Diagram-AHTNJAMY-DwFV1k9I.js} +1 -1
  116. package/payload/server/public/assets/channel-D8Go_zJk.js +1 -0
  117. package/payload/server/public/assets/{chunk-2KRD3SAO-Gj2dSpBl.js → chunk-2KRD3SAO-CKn-bEkI.js} +1 -1
  118. package/payload/server/public/assets/{chunk-336JU56O-2PXVPCUA.js → chunk-336JU56O-iJ4ISPCi.js} +2 -2
  119. package/payload/server/public/assets/chunk-426QAEUC-sWe0Iexz.js +1 -0
  120. package/payload/server/public/assets/{chunk-4BX2VUAB-9XIBlnC2.js → chunk-4BX2VUAB-B2mSmC97.js} +1 -1
  121. package/payload/server/public/assets/{chunk-4TB4RGXK-Cr3mXPnI.js → chunk-4TB4RGXK-kKNYi2_i.js} +1 -1
  122. package/payload/server/public/assets/{chunk-55IACEB6-Ccg46J3A.js → chunk-55IACEB6-JLT9m7Hd.js} +1 -1
  123. package/payload/server/public/assets/{chunk-5FUZZQ4R-Cz9MvPKc.js → chunk-5FUZZQ4R-Car3r0he.js} +1 -1
  124. package/payload/server/public/assets/{chunk-5PVQY5BW-BleOdlgO.js → chunk-5PVQY5BW-DR9EfLvj.js} +1 -1
  125. package/payload/server/public/assets/{chunk-67CJDMHE-CyCYCQWy.js → chunk-67CJDMHE-CCdP3Pdx.js} +1 -1
  126. package/payload/server/public/assets/{chunk-7N4EOEYR-KpT3uHzH.js → chunk-7N4EOEYR-bXgVzdM9.js} +1 -1
  127. package/payload/server/public/assets/{chunk-AA7GKIK3-BfOzbuxq.js → chunk-AA7GKIK3-CYeDvY8B.js} +1 -1
  128. package/payload/server/public/assets/{chunk-BSJP7CBP-Bq0M3wlv.js → chunk-BSJP7CBP-U0Fi-Ers.js} +1 -1
  129. package/payload/server/public/assets/{chunk-CIAEETIT-CR-2dNaL.js → chunk-CIAEETIT-C8QrV6Gg.js} +1 -1
  130. package/payload/server/public/assets/{chunk-EDXVE4YY-egUGMTOS.js → chunk-EDXVE4YY-DLUWVRZV.js} +1 -1
  131. package/payload/server/public/assets/{chunk-ENJZ2VHE-CQohBEFw.js → chunk-ENJZ2VHE-B4bNJo6C.js} +1 -1
  132. package/payload/server/public/assets/{chunk-FMBD7UC4-DIxBUbLP.js → chunk-FMBD7UC4-DxAQS3UB.js} +1 -1
  133. package/payload/server/public/assets/{chunk-FOC6F5B3-C2694Zoq.js → chunk-FOC6F5B3-CyIK3zeY.js} +1 -1
  134. package/payload/server/public/assets/{chunk-ICPOFSXX-DpXZKHyn.js → chunk-ICPOFSXX-Qzl8Ki0l.js} +2 -2
  135. package/payload/server/public/assets/{chunk-K5T4RW27-CUicG0Rp.js → chunk-K5T4RW27-7GcDzjyJ.js} +1 -1
  136. package/payload/server/public/assets/{chunk-KGLVRYIC-B5mPJhOr.js → chunk-KGLVRYIC-B7pAr9hf.js} +1 -1
  137. package/payload/server/public/assets/{chunk-LIHQZDEY-q81QhuMs.js → chunk-LIHQZDEY-DEoU2jrz.js} +1 -1
  138. package/payload/server/public/assets/{chunk-ORNJ4GCN-DgurdFZs.js → chunk-ORNJ4GCN-BwMFuN24.js} +1 -1
  139. package/payload/server/public/assets/{chunk-OYMX7WX6-CxqMRu2d.js → chunk-OYMX7WX6-BenBO6O_.js} +1 -1
  140. package/payload/server/public/assets/chunk-QZHKN3VN-CHE_iZO7.js +1 -0
  141. package/payload/server/public/assets/{chunk-U2HBQHQK-BSLctJC9.js → chunk-U2HBQHQK-DewM8R0D.js} +1 -1
  142. package/payload/server/public/assets/{chunk-X2U36JSP--0AUeeFl.js → chunk-X2U36JSP-C22Q6Ea4.js} +1 -1
  143. package/payload/server/public/assets/{chunk-XPW4576I-D-hf9Bcn.js → chunk-XPW4576I-BA0a8Ygs.js} +1 -1
  144. package/payload/server/public/assets/{chunk-YZCP3GAM-PvOhSwI9.js → chunk-YZCP3GAM-DfUUNTnA.js} +1 -1
  145. package/payload/server/public/assets/{chunk-ZZ45TVLE-1zPUlNWz.js → chunk-ZZ45TVLE-CUT6zma2.js} +1 -1
  146. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BLb1mzrT.js +1 -0
  147. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Ctj5qYTS.js +1 -0
  148. package/payload/server/public/assets/clone-DGZ2vydA.js +1 -0
  149. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Cvo-gkBd.js → cose-bilkent-S5V4N54A-Df_JmB8E.js} +1 -1
  150. package/payload/server/public/assets/{dagre-CMHsNfjP.js → dagre-CYXRIdv0.js} +1 -1
  151. package/payload/server/public/assets/{dagre-KV5264BT-CM1DSx4E.js → dagre-KV5264BT-D4EGb60h.js} +1 -1
  152. package/payload/server/public/assets/{data-Cuynp6Y6.js → data-BOgwOWnw.js} +1 -1
  153. package/payload/server/public/assets/{diagram-5BDNPKRD-VDHiHwEI.js → diagram-5BDNPKRD-BzieCEfT.js} +1 -1
  154. package/payload/server/public/assets/{diagram-G4DWMVQ6-OKdufoeW.js → diagram-G4DWMVQ6-DDbO71XD.js} +1 -1
  155. package/payload/server/public/assets/{diagram-MMDJMWI5-Yg6QdCA1.js → diagram-MMDJMWI5-DqQ_UXDA.js} +1 -1
  156. package/payload/server/public/assets/{diagram-TYMM5635-CpEMZQDu.js → diagram-TYMM5635-CFyxA1aZ.js} +1 -1
  157. package/payload/server/public/assets/{dist-811BIK0R.js → dist-BmvZ8OaX.js} +1 -1
  158. package/payload/server/public/assets/{erDiagram-SMLLAGMA-Dw5gAkFM.js → erDiagram-SMLLAGMA-BMaEBbOK.js} +1 -1
  159. package/payload/server/public/assets/{flatten-BsWEYbBB.js → flatten-Bo6YRmWl.js} +1 -1
  160. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-Cy_R1XHz.js → flowDiagram-DWJPFMVM-De5ChZQP.js} +1 -1
  161. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BYARP_eH.js → ganttDiagram-T4ZO3ILL-CXEMPVaK.js} +1 -1
  162. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CmHdoS27.js +1 -0
  163. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BGOe0unY.js → gitGraphDiagram-UUTBAWPF-OZedr_6y.js} +1 -1
  164. package/payload/server/public/assets/{graph-Ddg24bjy.js → graph-BqD2GjQd.js} +2 -2
  165. package/payload/server/public/assets/{graph-labels-eOrWYy0R.js → graph-labels-DSDTSBfM.js} +1 -1
  166. package/payload/server/public/assets/{graphlib-DaefxCga.js → graphlib-CN4nhD2U.js} +1 -1
  167. package/payload/server/public/assets/info-OMHHGYJF-DTA9msO-.js +1 -0
  168. package/payload/server/public/assets/infoDiagram-42DDH7IO-CSqg4nRL.js +2 -0
  169. package/payload/server/public/assets/{isEmpty-BWl67LAZ.js → isEmpty-D6Kr-M1M.js} +1 -1
  170. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-YrGuzpiI.js → ishikawaDiagram-UXIWVN3A-ChlzrZyx.js} +1 -1
  171. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-EIykOcqg.js → journeyDiagram-VCZTEJTY-DsrK55ZO.js} +1 -1
  172. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BR0TC6Je.js → kanban-definition-6JOO6SKY-DYF-_Rym.js} +1 -1
  173. package/payload/server/public/assets/{line-DPGcT5IM.js → line-3zmwI8XK.js} +1 -1
  174. package/payload/server/public/assets/{linear-CPN03uSh.js → linear-COm19-p7.js} +1 -1
  175. package/payload/server/public/assets/{mermaid-parser.core-D7Iu4c9M.js → mermaid-parser.core-BrcX8-cl.js} +2 -2
  176. package/payload/server/public/assets/{mermaid.core-krXRpXn9.js → mermaid.core-CBdz3b1N.js} +3 -3
  177. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-HwiCtPzN.js → mindmap-definition-QFDTVHPH-BqCqlYZb.js} +1 -1
  178. package/payload/server/public/assets/{ordinal-krseTxxN.js → ordinal-BDi6f4xk.js} +1 -1
  179. package/payload/server/public/assets/packet-4T2RLAQJ-6GjqIKgu.js +1 -0
  180. package/payload/server/public/assets/pie-ZZUOXDRM-T72DJ5JR.js +1 -0
  181. package/payload/server/public/assets/{pieDiagram-DEJITSTG-xodxyWLe.js → pieDiagram-DEJITSTG-D5LiILuM.js} +1 -1
  182. package/payload/server/public/assets/{public-xVaPcg6i.js → public-udi_Z7la.js} +3 -3
  183. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-DuYYY4ZZ.js → quadrantDiagram-34T5L4WZ-C3iuI5l_.js} +1 -1
  184. package/payload/server/public/assets/radar-PYXPWWZC-x-6xW1dE.js +1 -0
  185. package/payload/server/public/assets/{reduce-tk-xY6Fv.js → reduce-CGi9ik8i.js} +1 -1
  186. package/payload/server/public/assets/{requirementDiagram-MS252O5E-D0ta3kru.js → requirementDiagram-MS252O5E-CTPOw5qQ.js} +1 -1
  187. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-KdHdlzvT.js → sankeyDiagram-XADWPNL6-D_5aVlYp.js} +1 -1
  188. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DoSFUTQZ.js → sequenceDiagram-FGHM5R23-D7h5vocM.js} +1 -1
  189. package/payload/server/public/assets/{src-Cpl1JzME.js → src-DLEIsjER.js} +1 -1
  190. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-BLW0KiSA.js → stateDiagram-FHFEXIEX-DyZjuwPj.js} +1 -1
  191. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BiW9pGXy.js +1 -0
  192. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-8QAzhYz1.js → timeline-definition-GMOUNBTQ-BqpVYJz_.js} +1 -1
  193. package/payload/server/public/assets/treeView-SZITEDCU-5-6wEryJ.js +1 -0
  194. package/payload/server/public/assets/treemap-W4RFUUIX-DF48Cc86.js +1 -0
  195. package/payload/server/public/assets/{useSelectionMode-DlJsX-_X.js → useSelectionMode-BPzPjKP_.js} +1 -1
  196. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BKvfScOi.js → vennDiagram-DHZGUBPP-Czflml0e.js} +1 -1
  197. package/payload/server/public/assets/wardley-RL74JXVD-duKIa6Hq.js +1 -0
  198. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DaMfDpJ3.js → wardleyDiagram-NUSXRM2D-Cqz3pSTK.js} +1 -1
  199. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BIkNQlLa.js → xychartDiagram-5P7HB3ND-CS5dEuUO.js} +1 -1
  200. package/payload/server/public/browser.html +4 -4
  201. package/payload/server/public/data.html +5 -5
  202. package/payload/server/public/graph.html +6 -6
  203. package/payload/server/public/index.html +5 -5
  204. package/payload/server/public/public.html +4 -4
  205. package/payload/server/server.js +74 -275
  206. package/payload/server/public/assets/AdminShell-C6_5h1cC.js +0 -1
  207. package/payload/server/public/assets/architecture-YZFGNWBL-YM-TtgPY.js +0 -1
  208. package/payload/server/public/assets/channel-BRPH0atd.js +0 -1
  209. package/payload/server/public/assets/chunk-426QAEUC-QhauxjvK.js +0 -1
  210. package/payload/server/public/assets/chunk-QZHKN3VN-BDAQvtxz.js +0 -1
  211. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BJv89PB6.js +0 -1
  212. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DNUszH5M.js +0 -1
  213. package/payload/server/public/assets/clone-CREg9jLM.js +0 -1
  214. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CtOPqykB.js +0 -1
  215. package/payload/server/public/assets/info-OMHHGYJF-Jba5enA8.js +0 -1
  216. package/payload/server/public/assets/infoDiagram-42DDH7IO-Df9BlkPA.js +0 -2
  217. package/payload/server/public/assets/packet-4T2RLAQJ-D_eWzeAP.js +0 -1
  218. package/payload/server/public/assets/pie-ZZUOXDRM-BDiy1Ob2.js +0 -1
  219. package/payload/server/public/assets/radar-PYXPWWZC-C5mlfmtg.js +0 -1
  220. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-C5zlCV4X.js +0 -1
  221. package/payload/server/public/assets/treeView-SZITEDCU-CM-9m-cS.js +0 -1
  222. package/payload/server/public/assets/treemap-W4RFUUIX-DDHPB-Xh.js +0 -1
  223. package/payload/server/public/assets/wardley-RL74JXVD-CUb3Br4q.js +0 -1
  224. package/payload/server/public/assets/whatsapp-BE79pNh8.js +0 -1
  225. package/payload/server/public/whatsapp.html +0 -18
  226. /package/payload/server/public/assets/{_baseFor-BHtDrjIo.js → _baseFor-Cam2PbSt.js} +0 -0
  227. /package/payload/server/public/assets/{array-DetWRiSa.js → array-DYRGGQae.js} +0 -0
  228. /package/payload/server/public/assets/{chunk-CWOGyPgy.js → chunk-CnGqDkHZ.js} +0 -0
  229. /package/payload/server/public/assets/{cytoscape.esm-C9yNhe1u.js → cytoscape.esm-nWsJMTNI.js} +0 -0
  230. /package/payload/server/public/assets/{defaultLocale-_WRwicXn.js → defaultLocale-Du1XY3Dp.js} +0 -0
  231. /package/payload/server/public/assets/{init-sTEcj9YX.js → init-B5BXBRcm.js} +0 -0
  232. /package/payload/server/public/assets/{katex-s61Rgv6l.js → katex-HOUACuRw.js} +0 -0
  233. /package/payload/server/public/assets/{path-B0Ik7Tu9.js → path-CNO468J-.js} +0 -0
  234. /package/payload/server/public/assets/{rough.esm-DKRO8IF-.js → rough.esm-DRO6hWPh.js} +0 -0
@@ -1513,24 +1513,14 @@ function getLanIp() {
1513
1513
  // app/lib/whatsapp/schema.ts
1514
1514
  import { z } from "zod";
1515
1515
  var DmPolicySchema = z.enum(["open", "allowlist", "disabled"]);
1516
- var GroupPolicySchema = z.enum(["open", "allowlist", "disabled"]);
1517
1516
  var WhatsAppAccountSchema = z.object({
1518
1517
  name: z.string().optional().describe("Display name for this WhatsApp account (e.g. 'Main', 'Sales')."),
1519
1518
  enabled: z.boolean().optional().describe("If disabled, this account won't connect on startup."),
1520
1519
  dmPolicy: DmPolicySchema.optional().describe("Who can message your public agent via WhatsApp DM. 'Open' lets anyone message. 'Allowlist' restricts to approved phone numbers. 'Disabled' blocks all public messages."),
1521
- groupPolicy: GroupPolicySchema.optional().describe("Whether your agent responds in WhatsApp group chats. 'Open' enables group responses (subject to per-group activation). 'Allowlist' restricts to approved senders. 'Disabled' ignores all group messages."),
1522
1520
  selfChatMode: z.boolean().optional().describe("Enable if the bot uses the owner's personal WhatsApp number (same phone for admin and bot). Changes how self-messages are routed."),
1523
1521
  adminPhones: z.array(z.string()).optional().describe("Phone numbers (E.164) that route to the admin agent. Managed via add-admin-phone / remove-admin-phone."),
1524
1522
  allowFrom: z.array(z.string()).optional().describe("Phone numbers allowed to message the public agent when DM policy is 'allowlist'. Add '*' for open access. Does not affect admin routing \u2014 use adminPhones for that."),
1525
- groupAllowFrom: z.array(z.string()).optional().describe("Phone numbers allowed to trigger the agent in groups when group policy is 'allowlist'."),
1526
1523
  sendReadReceipts: z.boolean().optional().default(true).describe("Whether to send read receipts (blue ticks) when messages are received. Disabling may feel less responsive but preserves privacy."),
1527
- groups: z.record(
1528
- z.string(),
1529
- z.object({
1530
- activation: z.enum(["always", "mention", "off"]).optional(),
1531
- publicAgent: z.string().optional().describe("Per-group public-agent slug override. When set, inbound messages in this group route to this agent instead of the per-account or top-level publicAgent.")
1532
- }).strict().optional()
1533
- ).optional().describe("Per-group settings: 'activation' controls when the agent responds ('always', 'mention', 'off'); 'publicAgent' optionally overrides the public-agent slug for this group (precedence: group \u2192 account \u2192 top-level)."),
1534
1524
  ackReaction: z.object({
1535
1525
  emoji: z.string().optional(),
1536
1526
  direct: z.boolean().optional().default(true),
@@ -1552,10 +1542,8 @@ var WhatsAppAccountSchema = z.object({
1552
1542
  var WhatsAppConfigSchema = z.object({
1553
1543
  accounts: z.record(z.string(), WhatsAppAccountSchema.optional()).optional().describe("Per-account config keyed by account ID."),
1554
1544
  dmPolicy: DmPolicySchema.optional().default("disabled").describe("Who can message your public agent via WhatsApp DM. 'Open' lets anyone message. 'Allowlist' restricts to approved phone numbers. 'Disabled' blocks all public messages."),
1555
- groupPolicy: GroupPolicySchema.optional().default("disabled").describe("Whether your agent responds in WhatsApp group chats. 'Open' enables group responses (subject to per-group activation). 'Allowlist' restricts to approved senders. 'Disabled' ignores all group messages."),
1556
1545
  adminPhones: z.array(z.string()).optional().describe("Phone numbers (E.164) that route to the admin agent. Managed via add-admin-phone / remove-admin-phone."),
1557
1546
  allowFrom: z.array(z.string()).optional().describe("Phone numbers allowed to message the public agent when DM policy is 'allowlist'. Add '*' for open access. Does not affect admin routing \u2014 use adminPhones for that."),
1558
- groupAllowFrom: z.array(z.string()).optional().describe("Phone numbers allowed to trigger the agent in groups when group policy is 'allowlist'."),
1559
1547
  sendReadReceipts: z.boolean().optional().default(true).describe("Whether to send read receipts (blue ticks) when messages are received. Disabling may feel less responsive but preserves privacy."),
1560
1548
  mediaMaxMb: z.number().int().positive().optional().default(50).describe("Maximum file size in MB for media the agent will download and process."),
1561
1549
  textChunkLimit: z.number().int().positive().optional().default(4e3).describe("Maximum characters per outbound message. Longer replies are split into multiple messages."),
@@ -2321,10 +2309,8 @@ function extractMessage(msg) {
2321
2309
  function resolveAccountConfig(config, accountConfig) {
2322
2310
  return {
2323
2311
  dmPolicy: accountConfig?.dmPolicy ?? config.dmPolicy ?? "disabled",
2324
- groupPolicy: accountConfig?.groupPolicy ?? config.groupPolicy ?? "disabled",
2325
2312
  adminPhones: accountConfig?.adminPhones ?? config.adminPhones ?? [],
2326
2313
  allowFrom: accountConfig?.allowFrom ?? config.allowFrom ?? [],
2327
- groupAllowFrom: accountConfig?.groupAllowFrom ?? config.groupAllowFrom ?? [],
2328
2314
  selfChatMode: accountConfig?.selfChatMode ?? false
2329
2315
  };
2330
2316
  }
@@ -2361,36 +2347,8 @@ function checkDmAccess(params) {
2361
2347
  return { allowed: false, reason: "unknown-dm-policy", agentType: "public" };
2362
2348
  }
2363
2349
  }
2364
- function checkGroupAccess(params) {
2365
- const { senderPhone, selfPhone, groupJid, isMentioned } = params;
2366
- const cfg = resolveAccountConfig(params.config, params.accountConfig);
2367
- if (phonesMatch(senderPhone, selfPhone)) {
2368
- return { allowed: true, reason: "self-phone-group", agentType: "admin" };
2369
- }
2370
- switch (cfg.groupPolicy) {
2371
- case "open": {
2372
- const groupConfig = params.accountConfig?.groups?.[groupJid];
2373
- const activation = groupConfig?.activation ?? "mention";
2374
- if (activation === "off") {
2375
- return { allowed: false, reason: "group-activation-off", agentType: "public" };
2376
- }
2377
- if (activation === "mention" && !isMentioned) {
2378
- return { allowed: false, reason: "mention-gating", agentType: "public" };
2379
- }
2380
- return { allowed: true, reason: "group-policy-open", agentType: "public" };
2381
- }
2382
- case "allowlist": {
2383
- const inList = cfg.groupAllowFrom.some((entry) => phonesMatch(entry, senderPhone)) || cfg.adminPhones.some((entry) => phonesMatch(entry, senderPhone));
2384
- if (!inList) {
2385
- return { allowed: false, reason: "not-in-group-allowlist", agentType: "public" };
2386
- }
2387
- return { allowed: true, reason: "group-allowlist-match", agentType: "public" };
2388
- }
2389
- case "disabled":
2390
- return { allowed: false, reason: "group-policy-disabled", agentType: "public" };
2391
- default:
2392
- return { allowed: false, reason: "unknown-group-policy", agentType: "public" };
2393
- }
2350
+ function checkGroupAccess(_params) {
2351
+ return { allowed: false, reason: "group-observe-only", agentType: "public" };
2394
2352
  }
2395
2353
 
2396
2354
  // app/lib/whatsapp/inbound/dedupe.ts
@@ -3275,11 +3233,20 @@ async function transcribe(audioPath, mimetype) {
3275
3233
  }
3276
3234
  }
3277
3235
 
3236
+ // app/lib/whatsapp/reply-error.ts
3237
+ var WaReplyError = class extends Error {
3238
+ terminal;
3239
+ constructor(message, terminal) {
3240
+ super(message);
3241
+ this.name = "WaReplyError";
3242
+ this.terminal = terminal;
3243
+ }
3244
+ };
3245
+
3278
3246
  // app/lib/whatsapp/manager.ts
3279
3247
  var TAG12 = "[whatsapp:manager]";
3280
3248
  var MAX_RECONNECT_ATTEMPTS = 10;
3281
3249
  var MESSAGE_STORE_MAX = 500;
3282
- var GROUP_META_TTL = 5 * 60 * 1e3;
3283
3250
  var connections = /* @__PURE__ */ new Map();
3284
3251
  var configDir = null;
3285
3252
  var whatsAppConfig = {};
@@ -3375,8 +3342,7 @@ async function startConnection(accountId) {
3375
3342
  reconnectAttempts: 0,
3376
3343
  abortController: new AbortController(),
3377
3344
  debouncer: null,
3378
- lidMapping: null,
3379
- groupMetaCache: /* @__PURE__ */ new Map()
3345
+ lidMapping: null
3380
3346
  };
3381
3347
  connections.set(accountId, conn);
3382
3348
  await connectWithReconnect(conn);
@@ -3412,7 +3378,8 @@ function getStatus() {
3412
3378
  reconnectAttempts: conn.reconnectAttempts,
3413
3379
  lastConnectedAt: conn.lastConnectedAt,
3414
3380
  lastError: conn.lastError,
3415
- sessionStuckReason: conn.sessionStuckReason
3381
+ sessionStuckReason: conn.sessionStuckReason,
3382
+ terminalReason: conn.terminalReason
3416
3383
  }));
3417
3384
  }
3418
3385
  function getSocket(accountId) {
@@ -3456,8 +3423,7 @@ async function registerLoginSocket(accountId, sock, authDir) {
3456
3423
  lastConnectedAt: Date.now(),
3457
3424
  abortController: new AbortController(),
3458
3425
  debouncer: null,
3459
- lidMapping,
3460
- groupMetaCache: /* @__PURE__ */ new Map()
3426
+ lidMapping
3461
3427
  };
3462
3428
  connections.set(accountId, conn);
3463
3429
  try {
@@ -3570,6 +3536,7 @@ async function connectWithReconnect(conn) {
3570
3536
  conn.selfLid = selfId.lid;
3571
3537
  conn.lastConnectedAt = connectedAt;
3572
3538
  conn.lastError = void 0;
3539
+ conn.terminalReason = void 0;
3573
3540
  const rawLidMapping = sock.signalRepository?.lidMapping ?? null;
3574
3541
  conn.lidMapping = withSelfLidShortcut(rawLidMapping, selfId.lid, selfId.jid);
3575
3542
  if (selfId.lid) {
@@ -3612,6 +3579,7 @@ async function connectWithReconnect(conn) {
3612
3579
  conn.lastError = classification.message;
3613
3580
  console.error(`${TAG12} disconnect account=${conn.accountId}: ${classification.kind} \u2014 ${classification.message}`);
3614
3581
  if (!classification.shouldRetry) {
3582
+ conn.terminalReason = classification.message;
3615
3583
  console.error(`${TAG12} terminal disconnect for account=${conn.accountId}, stopping reconnection`);
3616
3584
  return;
3617
3585
  }
@@ -3687,37 +3655,6 @@ function watchForDisconnect(conn) {
3687
3655
  }
3688
3656
  });
3689
3657
  }
3690
- async function getGroupMeta(conn, jid) {
3691
- const cached3 = conn.groupMetaCache.get(jid);
3692
- if (cached3 && cached3.expires > Date.now()) return cached3;
3693
- if (!conn.sock) return null;
3694
- console.error(`${TAG12} group metadata cache miss for ${jid}, fetching from Baileys account=${conn.accountId}`);
3695
- try {
3696
- const meta = await conn.sock.groupMetadata(jid);
3697
- const participants = await Promise.all(
3698
- (meta.participants ?? []).map(async (p) => {
3699
- return await resolveJidToE164(p.id, conn.lidMapping) ?? p.id;
3700
- })
3701
- );
3702
- const entry = {
3703
- subject: meta.subject,
3704
- participants,
3705
- expires: Date.now() + GROUP_META_TTL
3706
- };
3707
- conn.groupMetaCache.set(jid, entry);
3708
- console.error(
3709
- `${TAG12} group metadata cached for ${jid}: "${meta.subject}", ${participants.length} participants, expires in ${GROUP_META_TTL}ms account=${conn.accountId}`
3710
- );
3711
- return entry;
3712
- } catch (err) {
3713
- console.error(
3714
- `${TAG12} group metadata fetch failed for ${jid}: ${err instanceof Error ? err.message : String(err)}, caching empty entry for ${GROUP_META_TTL}ms account=${conn.accountId}`
3715
- );
3716
- const emptyEntry = { expires: Date.now() + GROUP_META_TTL };
3717
- conn.groupMetaCache.set(jid, emptyEntry);
3718
- return null;
3719
- }
3720
- }
3721
3658
  function monitorInbound(conn) {
3722
3659
  if (!conn.sock || !onInboundMessage) return;
3723
3660
  const sock = conn.sock;
@@ -3941,24 +3878,7 @@ async function handleInboundMessage(conn, msg) {
3941
3878
  }
3942
3879
  let accessResult;
3943
3880
  if (isGroup) {
3944
- accessResult = checkGroupAccess({
3945
- senderPhone,
3946
- selfPhone,
3947
- groupJid: remoteJid,
3948
- // Three-way mention recognition (Sub-fix 4): legacy phone-JID equality,
3949
- // legacy E.164-via-jidToE164 equality, plus the new self-LID equality so
3950
- // mentions in LID-addressed groups (deliver as `<self-lid>@lid`) match.
3951
- // Pre-LID groups continue matching the first two — additive, never blocks.
3952
- // Each clause guards against null on its right operand; a creds-parse
3953
- // failure leaves all three of selfJid/selfLid/selfPhone null and
3954
- // jidToE164 of a malformed mention also returns null — without the
3955
- // guards, `null === null` would spuriously match every nullified field.
3956
- isMentioned: extracted.mentionedJids.some(
3957
- (jid) => conn.selfJid !== null && jid === conn.selfJid || conn.selfLid !== null && jid === conn.selfLid || conn.selfPhone !== null && jidToE164(jid) === conn.selfPhone
3958
- ),
3959
- config: whatsAppConfig,
3960
- accountConfig: whatsAppConfig.accounts?.[conn.accountId]
3961
- });
3881
+ accessResult = checkGroupAccess({ groupJid: remoteJid });
3962
3882
  } else {
3963
3883
  accessResult = checkDmAccess({
3964
3884
  senderPhone,
@@ -3971,18 +3891,20 @@ async function handleInboundMessage(conn, msg) {
3971
3891
  `${TAG12} inbound account=${conn.accountId} from=${senderPhone} group=${isGroup} access=${accessResult.allowed ? "allowed" : "blocked"}(${accessResult.reason}) agent=${accessResult.agentType}` + (extracted.mediaType ? ` media=${extracted.mediaType}` : "") + (mediaResult ? ` mediaPath=${mediaResult.path}` : "") + (extracted.quotedMessage ? ` replyTo=${extracted.quotedMessage.id}` : "")
3972
3892
  );
3973
3893
  if (!accessResult.allowed) return;
3974
- let groupSubject;
3975
- if (isGroup) {
3976
- const groupMeta = await getGroupMeta(conn, remoteJid);
3977
- groupSubject = groupMeta?.subject;
3978
- }
3979
3894
  const sendReceipts = whatsAppConfig.accounts?.[conn.accountId]?.sendReadReceipts ?? whatsAppConfig.sendReadReceipts ?? true;
3980
3895
  if (sendReceipts && msg.key.id) {
3981
3896
  sendReadReceipt(conn.sock, remoteJid, [msg.key.id], isGroup ? senderJid : void 0);
3982
3897
  }
3983
3898
  const reply = async (text) => {
3899
+ if (isGroupJid(remoteJid)) {
3900
+ console.error(`${TAG12} op=group-reply-blocked jid=${remoteJid}`);
3901
+ throw new WaReplyError("group reply blocked \u2014 observe-only", false);
3902
+ }
3984
3903
  const currentSock = conn.sock;
3985
- if (!currentSock) throw new Error("WhatsApp disconnected \u2014 cannot reply");
3904
+ if (!currentSock) {
3905
+ const reason = conn.terminalReason;
3906
+ throw new WaReplyError(reason ?? "WhatsApp disconnected \u2014 cannot reply", Boolean(reason));
3907
+ }
3986
3908
  await sendTextMessage(currentSock, remoteJid, text, { accountId: conn.accountId });
3987
3909
  };
3988
3910
  const composing = async () => {
@@ -4004,7 +3926,6 @@ async function handleInboundMessage(conn, msg) {
4004
3926
  text: extracted.text,
4005
3927
  isGroup,
4006
3928
  groupJid: isGroup ? remoteJid : void 0,
4007
- groupSubject,
4008
3929
  reply,
4009
3930
  composing,
4010
3931
  cacheKey,
@@ -4383,13 +4304,15 @@ app.get("/", async (c) => {
4383
4304
  selfPhone: a.selfPhone ?? null,
4384
4305
  reconnectAttempts: a.reconnectAttempts,
4385
4306
  lastError: a.lastError ?? null,
4386
- sessionStuckReason: a.sessionStuckReason ?? null
4307
+ sessionStuckReason: a.sessionStuckReason ?? null,
4308
+ terminalReason: a.terminalReason ?? null
4387
4309
  }));
4388
4310
  } catch (err) {
4389
4311
  console.error(`[health] failed to read WhatsApp status: ${err instanceof Error ? err.message : String(err)}`);
4390
4312
  }
4391
4313
  const whatsappAnyConnected = whatsappAccounts.some((a) => a.connected);
4392
4314
  const whatsappAnyStuck = whatsappAccounts.some((a) => Boolean(a.sessionStuckReason));
4315
+ const whatsappAnyTerminal = whatsappAccounts.some((a) => Boolean(a.terminalReason));
4393
4316
  const account = resolveAccount();
4394
4317
  const missingPlugins = findMissingPlugins(account?.config.enabledPlugins);
4395
4318
  return c.json({
@@ -4404,6 +4327,7 @@ app.get("/", async (c) => {
4404
4327
  whatsapp: {
4405
4328
  any_connected: whatsappAnyConnected,
4406
4329
  any_stuck: whatsappAnyStuck,
4330
+ any_terminal: whatsappAnyTerminal,
4407
4331
  accounts: whatsappAccounts
4408
4332
  }
4409
4333
  });
@@ -4677,7 +4601,10 @@ async function managerRcSpawn(opts) {
4677
4601
  sliceToken: opts.sliceToken,
4678
4602
  personId: opts.personId,
4679
4603
  userId: opts.userId,
4680
- waChannel: opts.waChannel
4604
+ waChannel: opts.waChannel,
4605
+ role: opts.role,
4606
+ channel: opts.channel,
4607
+ senderId: opts.senderId
4681
4608
  })
4682
4609
  }).catch((err) => ({ __throw: err instanceof Error ? err.message : String(err) }));
4683
4610
  if ("__throw" in res) {
@@ -5286,6 +5213,13 @@ async function ensureEntry(input) {
5286
5213
  spawned = await managerRcSpawn({
5287
5214
  sessionId: adminSessionId,
5288
5215
  name: nameValue ?? void 0,
5216
+ // Task 724 — pass the real channel + role + senderId so the manager writes
5217
+ // the classification sidecar for this admin channel (webchat, email, …),
5218
+ // not just WhatsApp. Without these the live session was left sidecar-less
5219
+ // and the sidebar channel badge / archive classification mis-read it.
5220
+ role: "admin",
5221
+ channel: input.channel,
5222
+ senderId: input.senderId,
5289
5223
  logContext: `channel=${input.channel} senderId=${input.senderId}`
5290
5224
  });
5291
5225
  } else {
@@ -5987,16 +5921,6 @@ function resolvePublicAgent(accountDir, opts) {
5987
5921
  const config = readConfig(accountDir);
5988
5922
  const wa = config.whatsapp;
5989
5923
  if (!wa) return null;
5990
- if (opts.groupJid) {
5991
- const accounts2 = wa.accounts;
5992
- const account2 = accounts2?.[opts.accountId];
5993
- const groups = account2?.groups;
5994
- const group = groups?.[opts.groupJid];
5995
- const groupSlug = group?.publicAgent;
5996
- if (typeof groupSlug === "string" && groupSlug.trim()) {
5997
- return { slug: groupSlug.trim(), source: "group" };
5998
- }
5999
- }
6000
5924
  const accounts = wa.accounts;
6001
5925
  const account = accounts?.[opts.accountId];
6002
5926
  const accountSlug = account?.publicAgent;
@@ -6012,77 +5936,6 @@ function resolvePublicAgent(accountDir, opts) {
6012
5936
  return null;
6013
5937
  }
6014
5938
  }
6015
- function setGroupPublicAgent(accountDir, accountId, groupJid, slug) {
6016
- const trimmedSlug = slug.trim();
6017
- const trimmedGroup = groupJid.trim();
6018
- const trimmedAccount = accountId.trim();
6019
- if (!trimmedSlug) return { ok: false, error: "Agent slug cannot be empty." };
6020
- if (!trimmedGroup) return { ok: false, error: "Group JID cannot be empty." };
6021
- if (!trimmedAccount) return { ok: false, error: "Account ID cannot be empty." };
6022
- const agentConfigPath = join4(accountDir, "agents", trimmedSlug, "config.json");
6023
- if (!existsSync4(agentConfigPath)) {
6024
- return { ok: false, error: `Agent "${trimmedSlug}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
6025
- }
6026
- try {
6027
- const config = readConfig(accountDir);
6028
- if (!config.whatsapp || typeof config.whatsapp !== "object") config.whatsapp = {};
6029
- const wa = config.whatsapp;
6030
- if (!wa.accounts || typeof wa.accounts !== "object") wa.accounts = {};
6031
- const accounts = wa.accounts;
6032
- if (!accounts[trimmedAccount] || typeof accounts[trimmedAccount] !== "object") accounts[trimmedAccount] = {};
6033
- const account = accounts[trimmedAccount];
6034
- if (!account.groups || typeof account.groups !== "object") account.groups = {};
6035
- const groups = account.groups;
6036
- const existing = groups[trimmedGroup] && typeof groups[trimmedGroup] === "object" ? groups[trimmedGroup] : {};
6037
- groups[trimmedGroup] = { ...existing, publicAgent: trimmedSlug };
6038
- const parsed = WhatsAppConfigSchema.safeParse(wa);
6039
- if (!parsed.success) {
6040
- const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
6041
- return { ok: false, error: `Validation failed: ${msg}` };
6042
- }
6043
- config.whatsapp = parsed.data;
6044
- writeConfig(accountDir, config);
6045
- console.error(`${TAG17} setGroupPublicAgent account=${trimmedAccount} groupJid=${trimmedGroup} slug=${trimmedSlug}`);
6046
- reloadManagerConfig(accountDir);
6047
- return { ok: true, message: `Per-group public agent set to "${trimmedSlug}" for group ${trimmedGroup}.` };
6048
- } catch (err) {
6049
- const msg = err instanceof Error ? err.message : String(err);
6050
- console.error(`${TAG17} setGroupPublicAgent failed: ${msg}`);
6051
- return { ok: false, error: msg };
6052
- }
6053
- }
6054
- function unsetGroupPublicAgent(accountDir, accountId, groupJid) {
6055
- const trimmedGroup = groupJid.trim();
6056
- const trimmedAccount = accountId.trim();
6057
- if (!trimmedGroup) return { ok: false, error: "Group JID cannot be empty." };
6058
- if (!trimmedAccount) return { ok: false, error: "Account ID cannot be empty." };
6059
- try {
6060
- const config = readConfig(accountDir);
6061
- const wa = config.whatsapp ?? {};
6062
- const accounts = wa.accounts;
6063
- const account = accounts?.[trimmedAccount];
6064
- const groups = account?.groups;
6065
- const group = groups?.[trimmedGroup];
6066
- if (!group || typeof group.publicAgent !== "string") {
6067
- return { ok: true, message: `No per-group publicAgent override for group ${trimmedGroup}; nothing to remove.` };
6068
- }
6069
- delete group.publicAgent;
6070
- const parsed = WhatsAppConfigSchema.safeParse(wa);
6071
- if (!parsed.success) {
6072
- const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
6073
- return { ok: false, error: `Validation failed: ${msg}` };
6074
- }
6075
- config.whatsapp = parsed.data;
6076
- writeConfig(accountDir, config);
6077
- console.error(`${TAG17} unsetGroupPublicAgent account=${trimmedAccount} groupJid=${trimmedGroup}`);
6078
- reloadManagerConfig(accountDir);
6079
- return { ok: true, message: `Per-group public agent override removed for group ${trimmedGroup}.` };
6080
- } catch (err) {
6081
- const msg = err instanceof Error ? err.message : String(err);
6082
- console.error(`${TAG17} unsetGroupPublicAgent failed: ${msg}`);
6083
- return { ok: false, error: msg };
6084
- }
6085
- }
6086
5939
  function updateConfig(accountDir, fields) {
6087
5940
  const fieldNames = Object.keys(fields);
6088
5941
  if (fieldNames.length === 0) {
@@ -6615,29 +6468,10 @@ app3.post("/reconnect", async (c) => {
6615
6468
  return c.json({ error: String(err) }, 500);
6616
6469
  }
6617
6470
  });
6618
- app3.post("/send", async (c) => {
6619
- try {
6620
- const body = await c.req.json();
6621
- const { to, text } = body;
6622
- const accountId = validateAccountId(body.accountId);
6623
- if (!to || !text) {
6624
- return c.json({ error: "Missing required fields: to, text" }, 400);
6625
- }
6626
- const sock = getSocket(accountId);
6627
- if (!sock) {
6628
- return c.json({ error: `WhatsApp account "${accountId}" is not connected` }, 503);
6629
- }
6630
- const result = await sendTextMessage(sock, to, text, { accountId });
6631
- return c.json(result);
6632
- } catch (err) {
6633
- console.error(`${TAG20} send error: ${String(err)}`);
6634
- return c.json({ error: String(err) }, 500);
6635
- }
6636
- });
6637
6471
  app3.post("/config", async (c) => {
6638
6472
  try {
6639
6473
  const body = await c.req.json().catch(() => ({}));
6640
- const { action, phone, slug, groupJid, fields, accountId } = body;
6474
+ const { action, phone, slug, fields, accountId } = body;
6641
6475
  if (!action || typeof action !== "string") {
6642
6476
  return c.json({ ok: false, error: 'Missing required field "action".' }, 400);
6643
6477
  }
@@ -6677,32 +6511,10 @@ app3.post("/config", async (c) => {
6677
6511
  }
6678
6512
  case "get-public-agent": {
6679
6513
  const targetAccount = typeof accountId === "string" && accountId.trim() ? accountId.trim() : "default";
6680
- const targetGroup = typeof groupJid === "string" && groupJid.trim() ? groupJid.trim() : void 0;
6681
- const resolved = resolvePublicAgent(account.accountDir, { accountId: targetAccount, groupJid: targetGroup });
6682
- console.error(`${TAG20} config action=get-public-agent accountId=${targetAccount} groupJid=${targetGroup ?? "none"} slug=${resolved?.slug ?? "none"} source=${resolved?.source ?? "none"}`);
6514
+ const resolved = resolvePublicAgent(account.accountDir, { accountId: targetAccount });
6515
+ console.error(`${TAG20} config action=get-public-agent accountId=${targetAccount} slug=${resolved?.slug ?? "none"} source=${resolved?.source ?? "none"}`);
6683
6516
  return c.json({ ok: true, slug: resolved?.slug ?? null, source: resolved?.source ?? null });
6684
6517
  }
6685
- case "set-group-public-agent": {
6686
- if (!slug || typeof slug !== "string") {
6687
- return c.json({ ok: false, error: 'Missing required field "slug" (the public-agent directory name, e.g. "my-agent").' }, 400);
6688
- }
6689
- if (!groupJid || typeof groupJid !== "string") {
6690
- return c.json({ ok: false, error: 'Missing required field "groupJid" (group JID ending in @g.us).' }, 400);
6691
- }
6692
- const targetAccount = typeof accountId === "string" && accountId.trim() ? accountId.trim() : "default";
6693
- const result = setGroupPublicAgent(account.accountDir, targetAccount, groupJid, slug);
6694
- console.error(`${TAG20} config action=set-group-public-agent accountId=${targetAccount} groupJid=${groupJid} slug=${slug} ok=${result.ok}`);
6695
- return c.json(result, result.ok ? 200 : 400);
6696
- }
6697
- case "unset-group-public-agent": {
6698
- if (!groupJid || typeof groupJid !== "string") {
6699
- return c.json({ ok: false, error: 'Missing required field "groupJid" (group JID ending in @g.us).' }, 400);
6700
- }
6701
- const targetAccount = typeof accountId === "string" && accountId.trim() ? accountId.trim() : "default";
6702
- const result = unsetGroupPublicAgent(account.accountDir, targetAccount, groupJid);
6703
- console.error(`${TAG20} config action=unset-group-public-agent accountId=${targetAccount} groupJid=${groupJid} ok=${result.ok}`);
6704
- return c.json(result, result.ok ? 200 : 400);
6705
- }
6706
6518
  case "list-public-agents": {
6707
6519
  const agentsDir = resolve7(account.accountDir, "agents");
6708
6520
  const agents = [];
@@ -6769,7 +6581,7 @@ app3.post("/config", async (c) => {
6769
6581
  }
6770
6582
  default:
6771
6583
  return c.json(
6772
- { ok: false, error: `Unknown action "${action}". Valid actions: add-admin-phone, remove-admin-phone, list-admin-phones, set-public-agent, get-public-agent, set-group-public-agent, unset-group-public-agent, list-public-agents, update-config, get-config, schema, list-groups.` },
6584
+ { ok: false, error: `Unknown action "${action}". Valid actions: add-admin-phone, remove-admin-phone, list-admin-phones, set-public-agent, get-public-agent, list-public-agents, update-config, get-config, schema, list-groups.` },
6773
6585
  400
6774
6586
  );
6775
6587
  }
@@ -7319,8 +7131,14 @@ function splitNewLines(buf, baseOffset) {
7319
7131
  };
7320
7132
  }
7321
7133
 
7322
- // server/routes/whatsapp-reader.ts
7134
+ // server/routes/admin/manager-client.ts
7323
7135
  var SESSION_ID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
7136
+ function managerBase3(tag) {
7137
+ const port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag });
7138
+ return `http://127.0.0.1:${port2}`;
7139
+ }
7140
+
7141
+ // server/routes/whatsapp-reader.ts
7324
7142
  var app5 = new Hono();
7325
7143
  app5.get("/conversations", requireAdminSession, async (c) => {
7326
7144
  const cfg = claudeConfigDir();
@@ -8875,12 +8693,11 @@ app13.delete("/:id", requireAdminSession, async (c) => {
8875
8693
  if (!accountId) return c.json({ error: "Account not found for session" }, 401);
8876
8694
  const owned = await verifyConversationOwnership(sessionId, accountId);
8877
8695
  if (!owned) return c.json({ error: "Conversation not found" }, 404);
8878
- const managerPort = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "admin-conversation-delete" });
8879
- const managerBase7 = `http://127.0.0.1:${managerPort}`;
8696
+ const managerBaseUrl = managerBase3("admin-conversation-delete");
8880
8697
  const outcome = await cascadeAdminConversationDelete({
8881
8698
  sessionId,
8882
8699
  accountId,
8883
- managerBase: managerBase7
8700
+ managerBase: managerBaseUrl
8884
8701
  });
8885
8702
  if (outcome.ok) return c.json({ ok: true, claudeSessionIds: outcome.claudeSessionIds });
8886
8703
  if (outcome.reason === "pty-still-alive") {
@@ -9534,10 +9351,6 @@ async function refuseIfClaudeAuthDead(c, route, sessionId) {
9534
9351
  503
9535
9352
  );
9536
9353
  }
9537
- function managerBase3() {
9538
- const port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "claude-session-manager:wrapper" });
9539
- return `http://127.0.0.1:${port2}`;
9540
- }
9541
9354
  var app14 = new Hono();
9542
9355
  async function performSpawnWithInitialMessage(args) {
9543
9356
  const ownerStart = Date.now();
@@ -9576,9 +9389,9 @@ async function performSpawnWithInitialMessage(args) {
9576
9389
  // unshapely values.
9577
9390
  conversationNodeId: args.conversationNodeId
9578
9391
  });
9579
- console.log(`${TAG21} forward-spawn-start managerBase=${managerBase3()} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
9392
+ console.log(`${TAG21} forward-spawn-start managerBase=${managerBase3("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
9580
9393
  const forwardStart = Date.now();
9581
- const upstream = await fetch(`${managerBase3()}/public-spawn`, {
9394
+ const upstream = await fetch(`${managerBase3("claude-session-manager:wrapper")}/public-spawn`, {
9582
9395
  method: "POST",
9583
9396
  headers: { "content-type": "application/json" },
9584
9397
  body: upstreamPayload
@@ -12547,8 +12360,7 @@ app20.post("/", requireAdminSession, async (c) => {
12547
12360
  );
12548
12361
  return c.json({ error: "AdminConversation node is missing sessionId" }, 500);
12549
12362
  }
12550
- const managerPort = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "graph-page-cascade" });
12551
- const managerBase7 = `http://127.0.0.1:${managerPort}`;
12363
+ const managerBaseUrl = managerBase3("graph-page-cascade");
12552
12364
  try {
12553
12365
  await session.close();
12554
12366
  } catch {
@@ -12556,7 +12368,7 @@ app20.post("/", requireAdminSession, async (c) => {
12556
12368
  const outcome = await cascadeAdminConversationDelete({
12557
12369
  sessionId,
12558
12370
  accountId,
12559
- managerBase: managerBase7
12371
+ managerBase: managerBaseUrl
12560
12372
  });
12561
12373
  const elapsed2 = Date.now() - started;
12562
12374
  const labelSummary2 = preflightLabels.join(",");
@@ -13111,11 +12923,6 @@ var sidebar_artefacts_default = app24;
13111
12923
 
13112
12924
  // server/routes/admin/session-delete.ts
13113
12925
  var app25 = new Hono();
13114
- var SESSION_ID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13115
- function managerBase4() {
13116
- const port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "session-delete:wrapper" });
13117
- return `http://127.0.0.1:${port2}`;
13118
- }
13119
12926
  app25.post("/", requireAdminSession, async (c) => {
13120
12927
  let body;
13121
12928
  try {
@@ -13124,10 +12931,10 @@ app25.post("/", requireAdminSession, async (c) => {
13124
12931
  return c.json({ error: "invalid JSON body" }, 400);
13125
12932
  }
13126
12933
  const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
13127
- if (!SESSION_ID_RE3.test(sessionId)) {
12934
+ if (!SESSION_ID_RE2.test(sessionId)) {
13128
12935
  return c.json({ error: "sessionId must be a v4 UUID" }, 400);
13129
12936
  }
13130
- const base = managerBase4();
12937
+ const base = managerBase3("session-delete:wrapper");
13131
12938
  try {
13132
12939
  const stop = await fetch(`${base}/${sessionId}/stop`, { method: "POST" });
13133
12940
  if (stop.status !== 204 && stop.status !== 200 && stop.status !== 404) {
@@ -13158,11 +12965,6 @@ var session_delete_default = app25;
13158
12965
 
13159
12966
  // server/routes/admin/session-stop.ts
13160
12967
  var app26 = new Hono();
13161
- var SESSION_ID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13162
- function managerBase5() {
13163
- const port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "session-stop:wrapper" });
13164
- return `http://127.0.0.1:${port2}`;
13165
- }
13166
12968
  app26.post("/", requireAdminSession, async (c) => {
13167
12969
  let body;
13168
12970
  try {
@@ -13171,12 +12973,12 @@ app26.post("/", requireAdminSession, async (c) => {
13171
12973
  return c.json({ error: "invalid JSON body" }, 400);
13172
12974
  }
13173
12975
  const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
13174
- if (!SESSION_ID_RE4.test(sessionId)) {
12976
+ if (!SESSION_ID_RE2.test(sessionId)) {
13175
12977
  return c.json({ error: "sessionId must be a v4 UUID" }, 400);
13176
12978
  }
13177
12979
  let res;
13178
12980
  try {
13179
- res = await fetch(`${managerBase5()}/${sessionId}/stop`, { method: "POST" });
12981
+ res = await fetch(`${managerBase3("session-stop:wrapper")}/${sessionId}/stop`, { method: "POST" });
13180
12982
  } catch (err) {
13181
12983
  console.error(`[session-stop] sessionId=${sessionId} manager-unreachable err=${err instanceof Error ? err.message : String(err)}`);
13182
12984
  return c.json({ error: "manager-unreachable" }, 502);
@@ -13192,11 +12994,6 @@ var session_stop_default = app26;
13192
12994
 
13193
12995
  // server/routes/admin/session-rc-spawn.ts
13194
12996
  var app27 = new Hono();
13195
- function managerBase6() {
13196
- const port2 = process.env.CLAUDE_SESSION_MANAGER_PORT;
13197
- if (!port2) throw new Error("CLAUDE_SESSION_MANAGER_PORT is not set");
13198
- return `http://127.0.0.1:${port2}`;
13199
- }
13200
12997
  app27.post("/", requireAdminSession, async (c) => {
13201
12998
  let body;
13202
12999
  try {
@@ -13209,7 +13006,7 @@ app27.post("/", requireAdminSession, async (c) => {
13209
13006
  if (typeof body.name === "string" && body.name.length > 0) payload.name = body.name;
13210
13007
  let res;
13211
13008
  try {
13212
- res = await fetch(`${managerBase6()}/rc-spawn`, {
13009
+ res = await fetch(`${managerBase3("session-rc-spawn:wrapper")}/rc-spawn`, {
13213
13010
  method: "POST",
13214
13011
  headers: { "content-type": "application/json" },
13215
13012
  body: JSON.stringify(payload)
@@ -15547,11 +15344,6 @@ async function startFileWatcher(opts = {}) {
15547
15344
  return { stop };
15548
15345
  }
15549
15346
 
15550
- // app/lib/whatsapp/inbound/claude-bridge.ts
15551
- function startReaper2() {
15552
- startReaper();
15553
- }
15554
-
15555
15347
  // app/lib/whatsapp/gateway/inbound-hub.ts
15556
15348
  var InboundHub = class {
15557
15349
  senders = /* @__PURE__ */ new Map();
@@ -15850,10 +15642,12 @@ function createWaChannelRoutes(deps) {
15850
15642
  try {
15851
15643
  await deps.sendOutbound(senderId, text);
15852
15644
  } catch (err) {
15645
+ const message = err instanceof Error ? err.message : String(err);
15646
+ const terminal = err instanceof WaReplyError ? err.terminal : false;
15853
15647
  console.error(
15854
- `[whatsapp-native] op=reply-failed senderId=${senderId} bytes=${bytes} error=${err instanceof Error ? err.message : String(err)}`
15648
+ `[whatsapp-native] op=reply-failed senderId=${senderId} bytes=${bytes} terminal=${terminal} error=${message}`
15855
15649
  );
15856
- return c.json({ error: "send-failed" }, 500);
15650
+ return c.json({ error: message, terminal }, 500);
15857
15651
  }
15858
15652
  console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
15859
15653
  return c.json({ ok: true });
@@ -16373,6 +16167,11 @@ var waGateway = new WaGateway({
16373
16167
  const result = await managerRcSpawn({
16374
16168
  sessionId: adminSessionIdFor(accountId, senderId),
16375
16169
  userId,
16170
+ // Task 724 — supply the channel so /rc-spawn writes the classification
16171
+ // sidecar from the body, the same path every other admin channel uses.
16172
+ // senderId for the sidecar continues to come from the waChannel binding.
16173
+ role: "admin",
16174
+ channel: "whatsapp",
16376
16175
  waChannel: { senderId, gatewayUrl, serverPath },
16377
16176
  logContext: `channel=whatsapp-native senderId=${senderId}`
16378
16177
  });
@@ -17229,7 +17028,7 @@ init({
17229
17028
  }).catch((err) => {
17230
17029
  console.error(`[whatsapp] init failed: ${String(err)}`);
17231
17030
  });
17232
- startReaper2();
17031
+ startReaper();
17233
17032
  var shuttingDown = false;
17234
17033
  process.on("SIGTERM", async () => {
17235
17034
  if (shuttingDown) {