@rubytech/create-maxy-code 0.1.290 → 0.1.291

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 (176) hide show
  1. package/dist/index.js +14 -0
  2. package/package.json +1 -1
  3. package/payload/platform/lib/graph-style/dist/index.d.ts +2 -1
  4. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
  5. package/payload/platform/lib/graph-style/dist/index.js +14 -1
  6. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  7. package/payload/platform/lib/graph-style/src/index.ts +15 -1
  8. package/payload/platform/package.json +3 -2
  9. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3 -1
  10. package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +21 -0
  11. package/payload/platform/plugins/docs/references/troubleshooting.md +2 -0
  12. package/payload/platform/plugins/whatsapp/PLUGIN.md +4 -0
  13. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +28 -1
  14. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +6 -0
  15. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  16. package/payload/platform/services/claude-session-manager/dist/http-server.js +65 -3
  17. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  18. package/payload/platform/services/claude-session-manager/dist/index.js +8 -0
  19. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  20. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +27 -0
  21. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -0
  22. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +45 -0
  23. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -0
  24. package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.d.ts +29 -0
  25. package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.d.ts.map +1 -0
  26. package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.js +121 -0
  27. package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.js.map +1 -0
  28. package/payload/platform/services/webchat-channel/dist/notification.d.ts +55 -0
  29. package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -0
  30. package/payload/platform/services/webchat-channel/dist/notification.js +59 -0
  31. package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -0
  32. package/payload/platform/services/webchat-channel/dist/server.d.ts +3 -0
  33. package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -0
  34. package/payload/platform/services/webchat-channel/dist/server.js +179 -0
  35. package/payload/platform/services/webchat-channel/dist/server.js.map +1 -0
  36. package/payload/platform/services/webchat-channel/package.json +20 -0
  37. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +20 -15
  38. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  39. package/payload/platform/services/whatsapp-channel/dist/notification.js +23 -19
  40. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  41. package/payload/server/public/assets/AdminShell-BgPlhiCM.js +1 -0
  42. package/payload/server/public/assets/{Checkbox-Dmc64qme.js → Checkbox-DWx2NcU9.js} +1 -1
  43. package/payload/server/public/assets/SidebarSplitter-CidskiAr.js +1 -0
  44. package/payload/server/public/assets/Transcript-iuM5b4JT.js +1 -0
  45. package/payload/server/public/assets/admin-Cdz561nK.js +1 -0
  46. package/payload/server/public/assets/{arc-BW1WhwmV.js → arc-yRinR5h4.js} +1 -1
  47. package/payload/server/public/assets/architecture-YZFGNWBL-B2UAw-4R.js +1 -0
  48. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-NkTPStkv.js → architectureDiagram-Q4EWVU46-AtvCAoKj.js} +1 -1
  49. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DKsRoptY.js → blockDiagram-DXYQGD6D-CwUSTR3t.js} +1 -1
  50. package/payload/server/public/assets/browser-Bwd_rYu9.js +1 -0
  51. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-4SSchEmY.js → c4Diagram-AHTNJAMY-Btkecaf-.js} +1 -1
  52. package/payload/server/public/assets/channel-1MEkxMOf.js +1 -0
  53. package/payload/server/public/assets/chat-wbKqew6m.js +1 -0
  54. package/payload/server/public/assets/{chunk-2KRD3SAO-CKn-bEkI.js → chunk-2KRD3SAO-DAJbbBPY.js} +1 -1
  55. package/payload/server/public/assets/{chunk-336JU56O-C8szFVD5.js → chunk-336JU56O-fJXOXFRr.js} +2 -2
  56. package/payload/server/public/assets/chunk-426QAEUC-28Pgly06.js +1 -0
  57. package/payload/server/public/assets/{chunk-4BX2VUAB-B2mSmC97.js → chunk-4BX2VUAB-BTCTbhtf.js} +1 -1
  58. package/payload/server/public/assets/{chunk-4TB4RGXK-YsoBMSBN.js → chunk-4TB4RGXK-IFvQOpiF.js} +1 -1
  59. package/payload/server/public/assets/{chunk-55IACEB6-JLT9m7Hd.js → chunk-55IACEB6-BY026nUv.js} +1 -1
  60. package/payload/server/public/assets/{chunk-5FUZZQ4R-fvCSUwuQ.js → chunk-5FUZZQ4R-DD-XOAcm.js} +1 -1
  61. package/payload/server/public/assets/{chunk-5PVQY5BW-BKCeZJLg.js → chunk-5PVQY5BW-Ck-5mL2A.js} +1 -1
  62. package/payload/server/public/assets/{chunk-67CJDMHE-CCdP3Pdx.js → chunk-67CJDMHE-Dl7bLJGe.js} +1 -1
  63. package/payload/server/public/assets/{chunk-7N4EOEYR-bXgVzdM9.js → chunk-7N4EOEYR-CFBOyqnD.js} +1 -1
  64. package/payload/server/public/assets/{chunk-AA7GKIK3-CYeDvY8B.js → chunk-AA7GKIK3-BnnqjSlh.js} +1 -1
  65. package/payload/server/public/assets/{chunk-BSJP7CBP-U0Fi-Ers.js → chunk-BSJP7CBP-DKCTDAZE.js} +1 -1
  66. package/payload/server/public/assets/{chunk-CIAEETIT-C8QrV6Gg.js → chunk-CIAEETIT-jjeAEkQy.js} +1 -1
  67. package/payload/server/public/assets/{chunk-EDXVE4YY-DhpopONL.js → chunk-EDXVE4YY-BPqvO0TO.js} +1 -1
  68. package/payload/server/public/assets/{chunk-ENJZ2VHE-CwpQJ9IE.js → chunk-ENJZ2VHE-PN6Hbw2D.js} +1 -1
  69. package/payload/server/public/assets/{chunk-FMBD7UC4-DxAQS3UB.js → chunk-FMBD7UC4-B0zglVlf.js} +1 -1
  70. package/payload/server/public/assets/{chunk-FOC6F5B3-CyIK3zeY.js → chunk-FOC6F5B3-COVX_UuK.js} +1 -1
  71. package/payload/server/public/assets/{chunk-ICPOFSXX-D5p7fCDj.js → chunk-ICPOFSXX-DkmwqyfQ.js} +2 -2
  72. package/payload/server/public/assets/{chunk-K5T4RW27-7GcDzjyJ.js → chunk-K5T4RW27-Bav1KRIS.js} +1 -1
  73. package/payload/server/public/assets/{chunk-KGLVRYIC-B7pAr9hf.js → chunk-KGLVRYIC-nj7A12cJ.js} +1 -1
  74. package/payload/server/public/assets/{chunk-LIHQZDEY-DEoU2jrz.js → chunk-LIHQZDEY-BmMkL9jD.js} +1 -1
  75. package/payload/server/public/assets/{chunk-ORNJ4GCN-BwMFuN24.js → chunk-ORNJ4GCN-BvGwrI3j.js} +1 -1
  76. package/payload/server/public/assets/{chunk-OYMX7WX6-DCXhGWX0.js → chunk-OYMX7WX6-CWyihoif.js} +1 -1
  77. package/payload/server/public/assets/chunk-QZHKN3VN-COXR_N4N.js +1 -0
  78. package/payload/server/public/assets/{chunk-U2HBQHQK-D6lKmEsB.js → chunk-U2HBQHQK-BCWQB0k9.js} +1 -1
  79. package/payload/server/public/assets/{chunk-X2U36JSP-DiKHy0ar.js → chunk-X2U36JSP-CcaCMsL0.js} +1 -1
  80. package/payload/server/public/assets/{chunk-XPW4576I-BA0a8Ygs.js → chunk-XPW4576I-DpLw5_cw.js} +1 -1
  81. package/payload/server/public/assets/{chunk-YZCP3GAM-AqHm3K1O.js → chunk-YZCP3GAM-BUTzrAoG.js} +1 -1
  82. package/payload/server/public/assets/{chunk-ZZ45TVLE-jDPov-Ao.js → chunk-ZZ45TVLE-BD9UGg96.js} +1 -1
  83. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BcD2DnVi.js +1 -0
  84. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-ChvbGJh0.js +1 -0
  85. package/payload/server/public/assets/clone-DPfDeykW.js +1 -0
  86. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Df_JmB8E.js → cose-bilkent-S5V4N54A-bCIQHniJ.js} +1 -1
  87. package/payload/server/public/assets/{dagre-KV5264BT-DDGXoEYU.js → dagre-KV5264BT-DcOMoMzF.js} +1 -1
  88. package/payload/server/public/assets/{dagre-Dyawd5Z2.js → dagre-dnTAouT6.js} +1 -1
  89. package/payload/server/public/assets/data-BSt0roMQ.js +1 -0
  90. package/payload/server/public/assets/{diagram-5BDNPKRD-BQ1s5wpz.js → diagram-5BDNPKRD-BuQUC75n.js} +1 -1
  91. package/payload/server/public/assets/{diagram-G4DWMVQ6-BnBA0Ain.js → diagram-G4DWMVQ6-DHiu9U7B.js} +1 -1
  92. package/payload/server/public/assets/{diagram-MMDJMWI5-BrGASMP1.js → diagram-MMDJMWI5-ypu7YJGF.js} +1 -1
  93. package/payload/server/public/assets/{diagram-TYMM5635-iSPhqW2Q.js → diagram-TYMM5635-DIwuWuqN.js} +1 -1
  94. package/payload/server/public/assets/{dist-BmvZ8OaX.js → dist-ePW3hz19.js} +1 -1
  95. package/payload/server/public/assets/{erDiagram-SMLLAGMA-BCRyIkOj.js → erDiagram-SMLLAGMA-CKxGMQZW.js} +1 -1
  96. package/payload/server/public/assets/{flatten-Bo6YRmWl.js → flatten-CpKIi5d2.js} +1 -1
  97. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BgMtd8aD.js → flowDiagram-DWJPFMVM-CqH2RE7a.js} +1 -1
  98. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BKpI7Sqx.js → ganttDiagram-T4ZO3ILL-BfuGXUUh.js} +1 -1
  99. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CwwaM7ed.js +1 -0
  100. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CEx6x6gJ.js → gitGraphDiagram-UUTBAWPF-BlpUYLLd.js} +1 -1
  101. package/payload/server/public/assets/{graph-DDJ3p_3N.js → graph-BEu_XQMZ.js} +19 -19
  102. package/payload/server/public/assets/graph-labels-DvO7i7Ez.js +1 -0
  103. package/payload/server/public/assets/{graphlib-Do8h5YVR.js → graphlib-O_QsiopN.js} +1 -1
  104. package/payload/server/public/assets/info-OMHHGYJF-CiiU112m.js +1 -0
  105. package/payload/server/public/assets/infoDiagram-42DDH7IO-tHUu3AX-.js +2 -0
  106. package/payload/server/public/assets/{isEmpty-D6Kr-M1M.js → isEmpty-C3Vxk1It.js} +1 -1
  107. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-BmCNGBwK.js → ishikawaDiagram-UXIWVN3A-CVMbR1ZD.js} +1 -1
  108. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-C_37fL2K.js → journeyDiagram-VCZTEJTY-7pbwsn7f.js} +1 -1
  109. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BLFxAQHd.js → kanban-definition-6JOO6SKY-CWFMjHiJ.js} +1 -1
  110. package/payload/server/public/assets/{line-FtY_Ltj6.js → line-B4V-vQdN.js} +1 -1
  111. package/payload/server/public/assets/{linear-COm19-p7.js → linear-Cdt0EBMa.js} +1 -1
  112. package/payload/server/public/assets/{mermaid-parser.core-BIr5bg_O.js → mermaid-parser.core-Ba5Re-_1.js} +2 -2
  113. package/payload/server/public/assets/{mermaid.core-8XmmGzXJ.js → mermaid.core-C39ZL-9e.js} +3 -3
  114. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DPKDmfiH.js → mindmap-definition-QFDTVHPH-BrREiATP.js} +1 -1
  115. package/payload/server/public/assets/{ordinal-BDi6f4xk.js → ordinal-BLrOss5K.js} +1 -1
  116. package/payload/server/public/assets/packet-4T2RLAQJ-Bq_zPNb3.js +1 -0
  117. package/payload/server/public/assets/pie-ZZUOXDRM-R-cewHYM.js +1 -0
  118. package/payload/server/public/assets/{pieDiagram-DEJITSTG-DyuI0jFr.js → pieDiagram-DEJITSTG-sJOzKUIf.js} +1 -1
  119. package/payload/server/public/assets/{public-n0sHV8JI.js → public-927mDSLH.js} +3 -3
  120. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-B24Cvsjf.js → quadrantDiagram-34T5L4WZ-bxoGUruT.js} +1 -1
  121. package/payload/server/public/assets/radar-PYXPWWZC-CZpBUjmo.js +1 -0
  122. package/payload/server/public/assets/{reduce-CGi9ik8i.js → reduce-C5tBOlxC.js} +1 -1
  123. package/payload/server/public/assets/{requirementDiagram-MS252O5E-DpieLND2.js → requirementDiagram-MS252O5E-C8_uEDnp.js} +1 -1
  124. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DFSI4LuL.js → sankeyDiagram-XADWPNL6-CKpSBj6p.js} +1 -1
  125. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-3babM9wY.js → sequenceDiagram-FGHM5R23-BbVOmtji.js} +1 -1
  126. package/payload/server/public/assets/{src-DLEIsjER.js → src-DssjGmtU.js} +1 -1
  127. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DKS3fdXm.js → stateDiagram-FHFEXIEX-CLiLypPX.js} +1 -1
  128. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Cn6OBfIT.js +1 -0
  129. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-1nRSO-Z9.js → timeline-definition-GMOUNBTQ-Dzzc-pnB.js} +1 -1
  130. package/payload/server/public/assets/treeView-SZITEDCU-CjsdVrjr.js +1 -0
  131. package/payload/server/public/assets/treemap-W4RFUUIX-BZ8peN4O.js +1 -0
  132. package/payload/server/public/assets/{useSelectionMode-DvBm4di-.js → useSelectionMode-BBvWzgtz.js} +1 -1
  133. package/payload/server/public/assets/useSelectionMode-CzWzToaM.css +1 -0
  134. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-Ds6i6j3g.js → vennDiagram-DHZGUBPP-CEj_ctTP.js} +1 -1
  135. package/payload/server/public/assets/wardley-RL74JXVD-BYLmRSDV.js +1 -0
  136. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-IZMQXgw6.js → wardleyDiagram-NUSXRM2D-Cnbz79qd.js} +1 -1
  137. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BGZkTooo.js → xychartDiagram-5P7HB3ND-MTjLweae.js} +1 -1
  138. package/payload/server/public/browser.html +6 -5
  139. package/payload/server/public/chat.html +19 -0
  140. package/payload/server/public/data.html +7 -6
  141. package/payload/server/public/graph.html +8 -7
  142. package/payload/server/public/index.html +8 -6
  143. package/payload/server/public/public.html +5 -5
  144. package/payload/server/server.js +785 -338
  145. package/payload/server/public/assets/AdminShell-CnslFKoX.js +0 -1
  146. package/payload/server/public/assets/admin-BJYDe3p8.js +0 -1
  147. package/payload/server/public/assets/architecture-YZFGNWBL-xHbVjatf.js +0 -1
  148. package/payload/server/public/assets/browser-CKxPsTlh.js +0 -1
  149. package/payload/server/public/assets/channel-DPRBU48c.js +0 -1
  150. package/payload/server/public/assets/chunk-426QAEUC-CWj9Y5LE.js +0 -1
  151. package/payload/server/public/assets/chunk-QZHKN3VN-CHE_iZO7.js +0 -1
  152. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BmQz46EF.js +0 -1
  153. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DyidaYtj.js +0 -1
  154. package/payload/server/public/assets/clone-D7qj6dUB.js +0 -1
  155. package/payload/server/public/assets/data-BEDsi4bU.js +0 -1
  156. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CmHdoS27.js +0 -1
  157. package/payload/server/public/assets/graph-labels-Cgd3XiNd.js +0 -1
  158. package/payload/server/public/assets/info-OMHHGYJF-DTA9msO-.js +0 -1
  159. package/payload/server/public/assets/infoDiagram-42DDH7IO-DGlZXVKh.js +0 -2
  160. package/payload/server/public/assets/packet-4T2RLAQJ-6GjqIKgu.js +0 -1
  161. package/payload/server/public/assets/pie-ZZUOXDRM-T72DJ5JR.js +0 -1
  162. package/payload/server/public/assets/radar-PYXPWWZC-x-6xW1dE.js +0 -1
  163. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Dh0X-qyv.js +0 -1
  164. package/payload/server/public/assets/treeView-SZITEDCU-5-6wEryJ.js +0 -1
  165. package/payload/server/public/assets/treemap-W4RFUUIX-DF48Cc86.js +0 -1
  166. package/payload/server/public/assets/useSelectionMode-CeQtw8Ba.css +0 -1
  167. package/payload/server/public/assets/wardley-RL74JXVD-duKIa6Hq.js +0 -1
  168. /package/payload/server/public/assets/{_baseFor-Cam2PbSt.js → _baseFor-WfS9pKAn.js} +0 -0
  169. /package/payload/server/public/assets/{array-DYRGGQae.js → array-HeX70jSN.js} +0 -0
  170. /package/payload/server/public/assets/{chunk-CnGqDkHZ.js → chunk-CWOGyPgy.js} +0 -0
  171. /package/payload/server/public/assets/{cytoscape.esm-nWsJMTNI.js → cytoscape.esm-CDZo0kst.js} +0 -0
  172. /package/payload/server/public/assets/{defaultLocale-Du1XY3Dp.js → defaultLocale-GJwWH1Jr.js} +0 -0
  173. /package/payload/server/public/assets/{init-B5BXBRcm.js → init-BPLPMQ3Y.js} +0 -0
  174. /package/payload/server/public/assets/{katex-HOUACuRw.js → katex-CKZ-HWMQ.js} +0 -0
  175. /package/payload/server/public/assets/{path-CNO468J-.js → path-YdFzr2W6.js} +0 -0
  176. /package/payload/server/public/assets/{rough.esm-DRO6hWPh.js → rough.esm-HAx67Hnb.js} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webchat-channel-mcp.js","sourceRoot":"","sources":["../src/webchat-channel-mcp.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,yEAAyE;AACzE,+EAA+E;AAC/E,eAAe;AACf,EAAE;AACF,yEAAyE;AACzE,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAEhF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,MAAM,CAAC,MAAM,2BAA2B,GAAG,iBAAiB,CAAA;AAkB5D,MAAM,UAAU,6BAA6B,CAC3C,CAA0B;IAE1B,OAAO;QACL,CAAC,2BAA2B,CAAC,EAAE;YAC7B,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;YACpB,GAAG,EAAE;gBACH,mBAAmB,EAAE,CAAC,CAAC,GAAG;gBAC1B,2BAA2B,EAAE,CAAC,CAAC,UAAU;gBACzC,0BAA0B,EAAE,CAAC,CAAC,SAAS;aACxC;SACF;KACF,CAAA;AACH,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,6BAA6B;IAC3C,OAAO,CAAC,yCAAyC,EAAE,UAAU,2BAA2B,EAAE,CAAC,CAAA;AAC7F,CAAC;AAED;;;kCAGkC;AAClC,MAAM,UAAU,2BAA2B,CAAC,SAAiB,EAAE,GAAW;IACxE,OAAO,IAAI,CAAC,GAAG,EAAE,wBAAwB,SAAS,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;AAC5F,CAAC;AAED;4EAC4E;AAC5E,MAAM,UAAU,uBAAuB,CAAC,aAAqB;IAC3D,OAAO,CAAC,cAAc,EAAE,aAAa,EAAE,GAAG,6BAA6B,EAAE,CAAC,CAAA;AAC5E,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { Logger } from './types.js';
2
+ /** The three launch fields the channel argv is rebuilt from. */
3
+ export interface WebchatChannelBinding {
4
+ key: string;
5
+ gatewayUrl: string;
6
+ serverPath: string;
7
+ }
8
+ export interface WebchatChannelEntry extends WebchatChannelBinding {
9
+ boundAt: string;
10
+ }
11
+ export declare class WebchatChannelStore {
12
+ private readonly bySessionId;
13
+ private readonly filePath;
14
+ private readonly logger;
15
+ constructor(filePath: string, logger: Logger);
16
+ /** Read the persisted file into the in-memory map. Boot-resilient: any
17
+ * failure (missing file, malformed JSON, permission denied) is logged and
18
+ * the store starts empty. Never throws. */
19
+ loadFromDisk(): void;
20
+ get(sessionId: string): WebchatChannelEntry | undefined;
21
+ /** Write-through `binding` for `sessionId`; refreshes boundAt each call. */
22
+ set(sessionId: string, binding: WebchatChannelBinding): WebchatChannelEntry;
23
+ /** Remove the entry for `sessionId` if present. Returns true when removed. */
24
+ remove(sessionId: string): boolean;
25
+ /** Current in-memory snapshot — diagnostic only. */
26
+ size(): number;
27
+ private persistAtomic;
28
+ }
29
+ //# sourceMappingURL=webchat-channel-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webchat-channel-store.d.ts","sourceRoot":"","sources":["../src/webchat-channel-store.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC,gEAAgE;AAChE,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,OAAO,EAAE,MAAM,CAAA;CAChB;AAYD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyC;IACrE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;gBAEnB,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAK5C;;gDAE4C;IAC5C,YAAY,IAAI,IAAI;IA0CpB,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAIvD,4EAA4E;IAC5E,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,GAAG,mBAAmB;IAO3E,8EAA8E;IAC9E,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAMlC,oDAAoD;IACpD,IAAI,IAAI,MAAM;IAId,OAAO,CAAC,aAAa;CAatB"}
@@ -0,0 +1,121 @@
1
+ // Persistent per-session webchat native-channel binding. Mirror of
2
+ // wa-channel-store.ts with the webchat identity (key instead of senderId).
3
+ // One webchat session resumes through the manager's `/rc-spawn`, but only the
4
+ // gateway path carries `webchatChannel`. Persisting the binding here lets
5
+ // every resume path re-apply the channel argv so
6
+ // `mcp__webchat-channel__reply` is present on every live PTY for the session.
7
+ //
8
+ // Lifecycle:
9
+ // - Boot reads `<accountDir>/webchat-channel-bindings.json` into the Map.
10
+ // - `set(sessionId, binding)` write-throughs and atomically persists; called
11
+ // on every gateway `/rc-spawn` so gatewayUrl/serverPath stay current.
12
+ // - `get(sessionId)` reads the in-memory map for the resume read-back.
13
+ // - `remove(sessionId)` on session purge / delete cascade.
14
+ // - Corruption / missing file / permission errors at boot are logged and
15
+ // treated as an empty map; the manager NEVER refuses to start.
16
+ //
17
+ // File format (UTF-8 JSON):
18
+ // { "<sessionId>": { "key": "...", "gatewayUrl": "...", "serverPath": "...", "boundAt": "ISO-8601" } }
19
+ import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
20
+ function isValidBinding(v) {
21
+ if (!v || typeof v !== 'object')
22
+ return false;
23
+ const o = v;
24
+ return (typeof o.key === 'string' && o.key.length > 0 &&
25
+ typeof o.gatewayUrl === 'string' && o.gatewayUrl.length > 0 &&
26
+ typeof o.serverPath === 'string' && o.serverPath.length > 0);
27
+ }
28
+ export class WebchatChannelStore {
29
+ bySessionId = new Map();
30
+ filePath;
31
+ logger;
32
+ constructor(filePath, logger) {
33
+ this.filePath = filePath;
34
+ this.logger = logger;
35
+ }
36
+ /** Read the persisted file into the in-memory map. Boot-resilient: any
37
+ * failure (missing file, malformed JSON, permission denied) is logged and
38
+ * the store starts empty. Never throws. */
39
+ loadFromDisk() {
40
+ if (!existsSync(this.filePath)) {
41
+ this.logger(`[claude-session-manager] webchat-channel-store-load empty reason=file-missing path=${this.filePath}`);
42
+ return;
43
+ }
44
+ let raw;
45
+ try {
46
+ raw = readFileSync(this.filePath, 'utf-8');
47
+ }
48
+ catch (err) {
49
+ const detail = err instanceof Error ? err.message : String(err);
50
+ this.logger(`[claude-session-manager] webchat-channel-store-load failed reason=read-error detail=${detail.slice(0, 200)} — starting empty`);
51
+ return;
52
+ }
53
+ let parsed;
54
+ try {
55
+ parsed = JSON.parse(raw);
56
+ }
57
+ catch (err) {
58
+ const detail = err instanceof Error ? err.message : String(err);
59
+ this.logger(`[claude-session-manager] webchat-channel-store-load failed reason=malformed-json detail=${detail.slice(0, 200)} — starting empty`);
60
+ return;
61
+ }
62
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
63
+ this.logger(`[claude-session-manager] webchat-channel-store-load failed reason=not-an-object — starting empty`);
64
+ return;
65
+ }
66
+ let loaded = 0;
67
+ for (const [sessionId, value] of Object.entries(parsed)) {
68
+ if (typeof sessionId !== 'string' || sessionId.length === 0)
69
+ continue;
70
+ if (!isValidBinding(value))
71
+ continue;
72
+ const rawBoundAt = value.boundAt;
73
+ const boundAt = typeof rawBoundAt === 'string' && rawBoundAt.length > 0 ? rawBoundAt : new Date(0).toISOString();
74
+ this.bySessionId.set(sessionId, {
75
+ key: value.key,
76
+ gatewayUrl: value.gatewayUrl,
77
+ serverPath: value.serverPath,
78
+ boundAt,
79
+ });
80
+ loaded += 1;
81
+ }
82
+ this.logger(`[claude-session-manager] webchat-channel-store-load ok entries=${loaded} path=${this.filePath}`);
83
+ }
84
+ get(sessionId) {
85
+ return this.bySessionId.get(sessionId);
86
+ }
87
+ /** Write-through `binding` for `sessionId`; refreshes boundAt each call. */
88
+ set(sessionId, binding) {
89
+ const entry = { ...binding, boundAt: new Date().toISOString() };
90
+ this.bySessionId.set(sessionId, entry);
91
+ this.persistAtomic();
92
+ return entry;
93
+ }
94
+ /** Remove the entry for `sessionId` if present. Returns true when removed. */
95
+ remove(sessionId) {
96
+ const had = this.bySessionId.delete(sessionId);
97
+ if (had)
98
+ this.persistAtomic();
99
+ return had;
100
+ }
101
+ /** Current in-memory snapshot — diagnostic only. */
102
+ size() {
103
+ return this.bySessionId.size;
104
+ }
105
+ persistAtomic() {
106
+ const obj = {};
107
+ for (const [sessionId, entry] of this.bySessionId)
108
+ obj[sessionId] = entry;
109
+ const tmp = `${this.filePath}.tmp`;
110
+ try {
111
+ writeFileSync(tmp, JSON.stringify(obj, null, 2), 'utf-8');
112
+ renameSync(tmp, this.filePath);
113
+ }
114
+ catch (err) {
115
+ const detail = err instanceof Error ? err.message : String(err);
116
+ this.logger(`[claude-session-manager] webchat-channel-store-persist failed detail=${detail.slice(0, 200)}`);
117
+ // No rethrow — reads still serve from the in-memory map until next boot.
118
+ }
119
+ }
120
+ }
121
+ //# sourceMappingURL=webchat-channel-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webchat-channel-store.js","sourceRoot":"","sources":["../src/webchat-channel-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ export interface InboundPayload {
2
+ /** The webchat conversation key this payload is for. */
3
+ key: string;
4
+ /** The operator's typed message, verbatim — multi-line content is preserved. */
5
+ text: string;
6
+ /** Per-message id, for dedup/observability. */
7
+ messageId: string;
8
+ }
9
+ /** The composed content the agent receives, plus the inner payload's byte
10
+ * length for the observability line. */
11
+ export interface ComposedInbound {
12
+ content: string;
13
+ payloadBytes: number;
14
+ }
15
+ /** Deliver the operator's text plain. The admin webchat is an operator
16
+ * surface; it does NOT get the Task 753 customer reframe. */
17
+ export declare function composeContent(p: InboundPayload): ComposedInbound;
18
+ /** Defence in depth: this server serves exactly one key. Even though the
19
+ * gateway only streams that key's messages, refuse anything else before it
20
+ * reaches the session. */
21
+ export declare function acceptsKey(myKey: string, p: {
22
+ key: string;
23
+ }): boolean;
24
+ /** Build the body for POST /webchat-channel/reply. The reply tool exposes only
25
+ * `text` to the model; the key is the server's fixed key (from spawn env),
26
+ * never trusted from the model, so a compromised turn cannot redirect a reply
27
+ * to a different conversation. */
28
+ export declare function buildReplyPostBody(myKey: string, text: string): {
29
+ key: string;
30
+ text: string;
31
+ };
32
+ /** Build the body for POST /webchat-channel/received — the receipt ack the
33
+ * channel server sends after it has emitted a drained inbound to the agent,
34
+ * so the gateway marks it delivered instead of sweeping it as
35
+ * drain-undelivered. The key is the server's fixed key, never model-supplied. */
36
+ export declare function buildReceivedPostBody(myKey: string, messageId: string): {
37
+ key: string;
38
+ messageId: string;
39
+ };
40
+ /** Retry an idempotent POST until it is accepted or the attempt cap is
41
+ * reached. `attempt` returns whether the POST was accepted; the helper
42
+ * returns on the first acceptance, otherwise sleeps `delayMs` and retries,
43
+ * up to `attempts` total. `sleep` is injected so tests run without real
44
+ * timers. */
45
+ export declare function postWithRetry(attempt: () => Promise<boolean>, opts: {
46
+ attempts: number;
47
+ delayMs: number;
48
+ sleep: (ms: number) => Promise<void>;
49
+ }): Promise<boolean>;
50
+ /** Map a non-OK /webchat-channel/reply response into an actionable MCP error
51
+ * string. Falls back to the bare status when the body carries no usable
52
+ * reason. (No terminal/logged-out branch — there is no external transport to
53
+ * log out of.) */
54
+ export declare function buildReplyError(status: number, body: unknown): string;
55
+ //# sourceMappingURL=notification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,GAAG,EAAE,MAAM,CAAA;IACX,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAA;IACZ,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;yCACyC;AACzC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;8DAC8D;AAC9D,wBAAgB,cAAc,CAAC,CAAC,EAAE,cAAc,GAAG,eAAe,CAEjE;AAED;;2BAE2B;AAC3B,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAErE;AAED;;;mCAGmC;AACnC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAE7F;AAED;;;kFAGkF;AAClF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAEpC;AAED;;;;cAIc;AACd,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC/B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAChF,OAAO,CAAC,OAAO,CAAC,CAMlB;AAED;;;mBAGmB;AACnB,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAIrE"}
@@ -0,0 +1,59 @@
1
+ // Pure helpers for the webchat channel server. No MCP SDK import here, so
2
+ // these unit-test without the SDK and keep server.ts's transport wiring
3
+ // separable from its message shaping. Mirrors whatsapp-channel/notification.ts
4
+ // with the deliberate divergences below.
5
+ //
6
+ // Divergence from whatsapp-channel (Task 772): the admin webchat is an
7
+ // OPERATOR surface, so the inbound is delivered PLAIN — no Task 753
8
+ // `## Context / ## Instruction` customer reframe. There is no media weaving
9
+ // (the browser POST carries text only) and no reply-document — the browser
10
+ // reader renders agent replies straight from the session JSONL.
11
+ /** Deliver the operator's text plain. The admin webchat is an operator
12
+ * surface; it does NOT get the Task 753 customer reframe. */
13
+ export function composeContent(p) {
14
+ return { content: p.text, payloadBytes: Buffer.byteLength(p.text, 'utf8') };
15
+ }
16
+ /** Defence in depth: this server serves exactly one key. Even though the
17
+ * gateway only streams that key's messages, refuse anything else before it
18
+ * reaches the session. */
19
+ export function acceptsKey(myKey, p) {
20
+ return p.key === myKey;
21
+ }
22
+ /** Build the body for POST /webchat-channel/reply. The reply tool exposes only
23
+ * `text` to the model; the key is the server's fixed key (from spawn env),
24
+ * never trusted from the model, so a compromised turn cannot redirect a reply
25
+ * to a different conversation. */
26
+ export function buildReplyPostBody(myKey, text) {
27
+ return { key: myKey, text };
28
+ }
29
+ /** Build the body for POST /webchat-channel/received — the receipt ack the
30
+ * channel server sends after it has emitted a drained inbound to the agent,
31
+ * so the gateway marks it delivered instead of sweeping it as
32
+ * drain-undelivered. The key is the server's fixed key, never model-supplied. */
33
+ export function buildReceivedPostBody(myKey, messageId) {
34
+ return { key: myKey, messageId };
35
+ }
36
+ /** Retry an idempotent POST until it is accepted or the attempt cap is
37
+ * reached. `attempt` returns whether the POST was accepted; the helper
38
+ * returns on the first acceptance, otherwise sleeps `delayMs` and retries,
39
+ * up to `attempts` total. `sleep` is injected so tests run without real
40
+ * timers. */
41
+ export async function postWithRetry(attempt, opts) {
42
+ for (let i = 0; i < opts.attempts; i++) {
43
+ if (await attempt())
44
+ return true;
45
+ if (i < opts.attempts - 1)
46
+ await opts.sleep(opts.delayMs);
47
+ }
48
+ return false;
49
+ }
50
+ /** Map a non-OK /webchat-channel/reply response into an actionable MCP error
51
+ * string. Falls back to the bare status when the body carries no usable
52
+ * reason. (No terminal/logged-out branch — there is no external transport to
53
+ * log out of.) */
54
+ export function buildReplyError(status, body) {
55
+ const b = body;
56
+ const reason = typeof b?.error === 'string' && b.error.length > 0 ? b.error : null;
57
+ return reason ? `reply: ${reason}` : `reply: gateway returned ${status}`;
58
+ }
59
+ //# sourceMappingURL=notification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification.js","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,wEAAwE;AACxE,+EAA+E;AAC/E,yCAAyC;AACzC,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AACpE,4EAA4E;AAC5E,2EAA2E;AAC3E,gEAAgE;AAkBhE;8DAC8D;AAC9D,MAAM,UAAU,cAAc,CAAC,CAAiB;IAC9C,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAA;AAC7E,CAAC;AAED;;2BAE2B;AAC3B,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,CAAkB;IAC1D,OAAO,CAAC,CAAC,GAAG,KAAK,KAAK,CAAA;AACxB,CAAC;AAED;;;mCAGmC;AACnC,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,IAAY;IAC5D,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;AAC7B,CAAC;AAED;;;kFAGkF;AAClF,MAAM,UAAU,qBAAqB,CACnC,KAAa,EACb,SAAiB;IAEjB,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAA;AAClC,CAAC;AAED;;;;cAIc;AACd,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAA+B,EAC/B,IAAiF;IAEjF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,IAAI,MAAM,OAAO,EAAE;YAAE,OAAO,IAAI,CAAA;QAChC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC;YAAE,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC3D,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;mBAGmB;AACnB,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,IAAa;IAC3D,MAAM,CAAC,GAAG,IAAkC,CAAA;IAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IAClF,OAAO,MAAM,CAAC,CAAC,CAAC,UAAU,MAAM,EAAE,CAAC,CAAC,CAAC,2BAA2B,MAAM,EAAE,CAAA;AAC1E,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":""}
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env node
2
+ // Per-conversation webchat channel MCP server. Spawned as a stdio child of one
3
+ // `claude` session (so it dies when that session dies — no bound port, no
4
+ // orphan). It:
5
+ // - subscribes to the gateway for ITS key's inbound (SSE) and emits each
6
+ // message as a notifications/claude/channel event;
7
+ // - exposes a `reply` tool. The reply's text reaches the operator through
8
+ // the browser reader, which tails the session JSONL and renders the
9
+ // tool_use — the gateway POST exists only to stamp the op=reply lifeline.
10
+ //
11
+ // Transport glue only — message shaping and the post bodies are the
12
+ // unit-tested pure helpers in ./notification. Mirrors
13
+ // whatsapp-channel/server.ts minus the outbound transport (no Baileys, no
14
+ // reply-document) and minus the Task 753 reframe (operator surface).
15
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
16
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
17
+ import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
18
+ import { acceptsKey, composeContent, buildReplyPostBody, buildReceivedPostBody, buildReplyError, postWithRetry, } from './notification.js';
19
+ function requireEnv(name) {
20
+ const v = process.env[name];
21
+ if (!v)
22
+ throw new Error(`webchat-channel: missing required env ${name}`);
23
+ return v;
24
+ }
25
+ const KEY = requireEnv('WEBCHAT_CHANNEL_KEY');
26
+ const GATEWAY_URL = requireEnv('WEBCHAT_CHANNEL_GATEWAY_URL').replace(/\/$/, '');
27
+ // Receipt-ack retry budget. 5 attempts × 2000ms = up to ~8s of sleeping,
28
+ // comfortably inside the gateway's 30s ack window (ACK_THRESHOLD_MS), so a
29
+ // recovered ack lands before the sweep would emit a false drain-undelivered.
30
+ const RECEIPT_ACK_ATTEMPTS = 5;
31
+ const RECEIPT_ACK_DELAY_MS = 2000;
32
+ // Operator surface: the typed message IS the operator's instruction. The reply
33
+ // tool is the delivery path back to the browser chat (the reader renders the
34
+ // tool call's text), so every turn must end with it.
35
+ const INSTRUCTIONS = `You are connected to the operator's admin webchat. Every ` +
36
+ `<channel source="webchat"> event is a message the operator has typed to you directly — treat it ` +
37
+ `EXACTLY as if they typed it in this session, and act on it immediately as their instruction. ` +
38
+ `Do NOT describe it as an "incoming message", do NOT summarise it, and do NOT ask whether to ` +
39
+ `reply — the answer is always yes. For every such event: (1) do the work or answer the question, ` +
40
+ `then (2) call the reply tool with your response so it is delivered to the operator's chat. ` +
41
+ `Always finish by calling the reply tool; never wait for confirmation before replying.`;
42
+ const mcp = new Server({ name: 'webchat', version: '0.1.0' }, {
43
+ capabilities: { experimental: { 'claude/channel': {} }, tools: {} },
44
+ instructions: INSTRUCTIONS,
45
+ });
46
+ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
47
+ tools: [
48
+ {
49
+ name: 'reply',
50
+ description: 'Send your reply text to the operator in this admin webchat conversation.',
51
+ inputSchema: {
52
+ type: 'object',
53
+ properties: { text: { type: 'string', description: 'The message to send to the operator' } },
54
+ required: ['text'],
55
+ },
56
+ },
57
+ ],
58
+ }));
59
+ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
60
+ if (req.params.name === 'reply') {
61
+ const text = req.params.arguments?.text;
62
+ if (typeof text !== 'string')
63
+ throw new Error('reply: text must be a string');
64
+ const res = await fetch(`${GATEWAY_URL}/webchat-channel/reply`, {
65
+ method: 'POST',
66
+ headers: { 'content-type': 'application/json' },
67
+ body: JSON.stringify(buildReplyPostBody(KEY, text)),
68
+ });
69
+ if (!res.ok) {
70
+ const body = await res.json().catch(() => null);
71
+ throw new Error(buildReplyError(res.status, body));
72
+ }
73
+ return { content: [{ type: 'text', text: 'sent' }] };
74
+ }
75
+ throw new Error(`unknown tool: ${req.params.name}`);
76
+ });
77
+ // Subscribe to this key's inbound stream and emit each message as an event.
78
+ // Reconnect loop: the channel server must stay alive — and its reply tool
79
+ // available — for the whole claude session. If the SSE link to the gateway
80
+ // drops (gateway restart, idle close, transient blip), reconnect instead of
81
+ // returning. The process still dies with the session because claude SIGTERMs
82
+ // its stdio child.
83
+ async function postReady() {
84
+ await fetch(`${GATEWAY_URL}/webchat-channel/ready`, {
85
+ method: 'POST',
86
+ headers: { 'content-type': 'application/json' },
87
+ body: JSON.stringify({ key: KEY }),
88
+ }).catch(() => { });
89
+ }
90
+ async function subscribeInbound() {
91
+ const url = `${GATEWAY_URL}/webchat-channel/inbound?key=${encodeURIComponent(KEY)}`;
92
+ for (;;) {
93
+ try {
94
+ const res = await fetch(url, { headers: { accept: 'text/event-stream' } });
95
+ if (!res.ok || !res.body)
96
+ throw new Error(`subscribe failed: ${res.status}`);
97
+ // The SSE link is established. Only NOW announce readiness, so the
98
+ // gateway drains any cold-start queue ONTO this live subscription rather
99
+ // than into a stream the channel server is not yet consuming.
100
+ await postReady();
101
+ const reader = res.body.getReader();
102
+ const decoder = new TextDecoder();
103
+ let buffer = '';
104
+ for (;;) {
105
+ const { value, done } = await reader.read();
106
+ if (done)
107
+ break;
108
+ buffer += decoder.decode(value, { stream: true });
109
+ const frames = buffer.split('\n\n');
110
+ buffer = frames.pop() ?? '';
111
+ for (const frame of frames) {
112
+ const dataLine = frame.split('\n').find((l) => l.startsWith('data:'));
113
+ if (!dataLine)
114
+ continue;
115
+ const data = dataLine.slice('data:'.length).trim();
116
+ if (!data)
117
+ continue; // ping/keepalive
118
+ let payload;
119
+ try {
120
+ payload = JSON.parse(data);
121
+ }
122
+ catch {
123
+ continue;
124
+ }
125
+ if (!acceptsKey(KEY, payload))
126
+ continue;
127
+ // Operator surface — deliver plain, no reframe (Task 772 divergence
128
+ // from the WhatsApp channel's Task 753 composeAdminContent).
129
+ const composed = composeContent(payload);
130
+ console.error(`[webchat:inbound] op=delivered key=${KEY.slice(0, 8)} role=admin payloadBytes=${composed.payloadBytes}`);
131
+ await mcp.notification({
132
+ method: 'notifications/claude/channel',
133
+ params: { content: composed.content },
134
+ });
135
+ // Confirm receipt so the gateway marks this message delivered
136
+ // instead of timing out as drain-undelivered. Retry within the
137
+ // gateway's ack window; log only on final give-up.
138
+ const acked = await postWithRetry(async () => {
139
+ try {
140
+ const r = await fetch(`${GATEWAY_URL}/webchat-channel/received`, {
141
+ method: 'POST',
142
+ headers: { 'content-type': 'application/json' },
143
+ body: JSON.stringify(buildReceivedPostBody(KEY, payload.messageId)),
144
+ });
145
+ return r.ok;
146
+ }
147
+ catch {
148
+ return false;
149
+ }
150
+ }, {
151
+ attempts: RECEIPT_ACK_ATTEMPTS,
152
+ delayMs: RECEIPT_ACK_DELAY_MS,
153
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
154
+ });
155
+ if (!acked) {
156
+ console.error(`[webchat:inbound] op=receipt-ack-failed key=${KEY} messageId=${payload.messageId} attempts=${RECEIPT_ACK_ATTEMPTS}`);
157
+ }
158
+ }
159
+ }
160
+ console.error('[webchat-channel] inbound stream closed by gateway; reconnecting');
161
+ }
162
+ catch (err) {
163
+ console.error(`[webchat-channel] inbound stream error: ${err instanceof Error ? err.message : String(err)}; reconnecting`);
164
+ }
165
+ await new Promise((resolve) => setTimeout(resolve, 2000));
166
+ }
167
+ }
168
+ async function main() {
169
+ await mcp.connect(new StdioServerTransport());
170
+ // Readiness is announced inside subscribeInbound, after the SSE link is up —
171
+ // never before, or the gateway would drain into a stream this server is not
172
+ // yet consuming.
173
+ await subscribeInbound();
174
+ }
175
+ main().catch((err) => {
176
+ console.error(`[webchat-channel] fatal: ${err instanceof Error ? err.message : String(err)}`);
177
+ process.exit(1);
178
+ });
179
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@maxy/webchat-channel",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "dist/server.js",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "start": "node dist/server.js",
10
+ "test": "vitest run"
11
+ },
12
+ "dependencies": {
13
+ "@modelcontextprotocol/sdk": "^1.0.0"
14
+ },
15
+ "devDependencies": {
16
+ "typescript": "^5.7.0",
17
+ "@types/node": "^22.0.0",
18
+ "vitest": "^4.1.2"
19
+ }
20
+ }
@@ -17,24 +17,27 @@ export interface InboundPayload {
17
17
  media: MediaInbound[];
18
18
  }
19
19
  /**
20
- * Task 753 — the standing select-and-dispatch instruction prepended to every
21
- * channel turn. The inbound message is demoted to payload and the turn becomes
22
- * a routing question: pick the owning specialist (dispatch via the Agent tool),
23
- * else load the owning skill, else answer directly. Freestyle inline authoring
24
- * is the `direct` floor, reached only when nothing owns the work — which is why
25
- * a greeting/confirmation needs no separate skip: it falls through to `direct`.
20
+ * Task 753 — the standing select-and-dispatch instruction. The inbound message
21
+ * is demoted to payload and the turn becomes a routing question: pick the owning
22
+ * specialist (dispatch via the Agent tool), else load the owning skill, else
23
+ * answer directly. Freestyle inline authoring is the `direct` floor, reached only
24
+ * when nothing owns the work — which is why a greeting/confirmation needs no
25
+ * separate skip: it falls through to `direct`. The turn is now framed in two
26
+ * markdown sections (see {@link composeAdminContent}): `## Context` carries the
27
+ * inbound payload first, then `## Instruction` carries this directive — so the
28
+ * agent reads the request, then how to act on it.
26
29
  *
27
30
  * Task 761 — the cadence clause. A long turn (e.g. building a quote across many
28
31
  * Write/Bash/Edit steps) was producing one channel message, dispatched only at
29
32
  * turn-end, leaving the sender in silence for minutes. The agent's interim
30
33
  * narration is surfaced in the dashboard but is never dispatched to the channel;
31
34
  * only `reply`-tool calls reach WhatsApp. So the clause directs the agent to use
32
- * the reply tool for an early acknowledgement and mid-turn progress on slow work,
33
- * not just for the final result. Outcome, not script.
35
+ * the reply tool for an early acknowledgement and mid-turn progress, then the
36
+ * result — not just the final message. Outcome, not script.
34
37
  *
35
38
  * Exported so the unit tests assert the exact wrapped shape.
36
39
  */
37
- export declare const REFRAME_PREFIX: string;
40
+ export declare const REFRAME_INSTRUCTION: string;
38
41
  /** Task 753 — the reframe decision for one inbound: the wrapped `content` the
39
42
  * agent receives, and `payloadBytes`, the byte length of the inner payload
40
43
  * (message + woven media notes, excluding the wrapper) for the observability
@@ -61,12 +64,14 @@ export declare function buildInboundNotification(p: InboundPayload): {
61
64
  };
62
65
  };
63
66
  /**
64
- * Task 753 — wrap the composed payload in {@link REFRAME_PREFIX} so the agent
65
- * routes the request instead of authoring it inline. Every channel turn is
66
- * wrapped there is no deterministic trivia-skip (operator decision): a
67
- * greeting is handled by the cascade's `direct` branch, not by a pre-classifier
68
- * here. Returns the wrapped `content` plus `payloadBytes` (the inner payload's
69
- * byte length) for the channel server's `[reframe]` observability line.
67
+ * Task 753 — frame the composed payload as two markdown sections so the agent
68
+ * routes the request instead of authoring it inline: `## Context` carries the
69
+ * inbound payload, then `## Instruction` carries {@link REFRAME_INSTRUCTION}.
70
+ * Every channel turn is framed there is no deterministic trivia-skip (operator
71
+ * decision): a greeting is handled by the cascade's `direct` branch, not by a
72
+ * pre-classifier here. Returns the framed `content` plus `payloadBytes` (the
73
+ * inner payload's byte length) for the channel server's `[reframe]`
74
+ * observability line.
70
75
  */
71
76
  export declare function composeAdminContent(p: InboundPayload): ComposedInbound;
72
77
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAA;IACnB;;;kFAG8E;IAC9E,KAAK,EAAE,YAAY,EAAE,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc,QAQP,CAAA;AAEpB;;;YAGY;AACZ,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,cAAc;;;;;EAOzD;AA0BD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,cAAc,GAAG,eAAe,CAMtE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAElF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAEvG;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,CAAC,EAAE,MAAM,GACf;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAIzD;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAE3C;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC/B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAChF,OAAO,CAAC,OAAO,CAAC,CAMlB;AAED;;;;gCAIgC;AAChC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAMrE"}
1
+ {"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAA;IACnB;;;kFAG8E;IAC9E,KAAK,EAAE,YAAY,EAAE,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mBAAmB,QAOI,CAAA;AAEpC;;;YAGY;AACZ,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,cAAc;;;;;EAOzD;AA0BD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,cAAc,GAAG,eAAe,CAMtE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAElF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAEvG;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,CAAC,EAAE,MAAM,GACf;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAIzD;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAE3C;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC/B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAChF,OAAO,CAAC,OAAO,CAAC,CAMlB;AAED;;;;gCAIgC;AAChC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAMrE"}