@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.
- package/dist/index.js +14 -0
- package/package.json +1 -1
- package/payload/platform/lib/graph-style/dist/index.d.ts +2 -1
- package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-style/dist/index.js +14 -1
- package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-style/src/index.ts +15 -1
- package/payload/platform/package.json +3 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3 -1
- package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +21 -0
- package/payload/platform/plugins/docs/references/troubleshooting.md +2 -0
- package/payload/platform/plugins/whatsapp/PLUGIN.md +4 -0
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +28 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +6 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +65 -3
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +8 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +27 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +45 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.d.ts +29 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.js +121 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-store.js.map +1 -0
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +55 -0
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -0
- package/payload/platform/services/webchat-channel/dist/notification.js +59 -0
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -0
- package/payload/platform/services/webchat-channel/dist/server.d.ts +3 -0
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -0
- package/payload/platform/services/webchat-channel/dist/server.js +179 -0
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -0
- package/payload/platform/services/webchat-channel/package.json +20 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +20 -15
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +23 -19
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/server/public/assets/AdminShell-BgPlhiCM.js +1 -0
- package/payload/server/public/assets/{Checkbox-Dmc64qme.js → Checkbox-DWx2NcU9.js} +1 -1
- package/payload/server/public/assets/SidebarSplitter-CidskiAr.js +1 -0
- package/payload/server/public/assets/Transcript-iuM5b4JT.js +1 -0
- package/payload/server/public/assets/admin-Cdz561nK.js +1 -0
- package/payload/server/public/assets/{arc-BW1WhwmV.js → arc-yRinR5h4.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-B2UAw-4R.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-NkTPStkv.js → architectureDiagram-Q4EWVU46-AtvCAoKj.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DKsRoptY.js → blockDiagram-DXYQGD6D-CwUSTR3t.js} +1 -1
- package/payload/server/public/assets/browser-Bwd_rYu9.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-4SSchEmY.js → c4Diagram-AHTNJAMY-Btkecaf-.js} +1 -1
- package/payload/server/public/assets/channel-1MEkxMOf.js +1 -0
- package/payload/server/public/assets/chat-wbKqew6m.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-CKn-bEkI.js → chunk-2KRD3SAO-DAJbbBPY.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-C8szFVD5.js → chunk-336JU56O-fJXOXFRr.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-28Pgly06.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-B2mSmC97.js → chunk-4BX2VUAB-BTCTbhtf.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-YsoBMSBN.js → chunk-4TB4RGXK-IFvQOpiF.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-JLT9m7Hd.js → chunk-55IACEB6-BY026nUv.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-fvCSUwuQ.js → chunk-5FUZZQ4R-DD-XOAcm.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BKCeZJLg.js → chunk-5PVQY5BW-Ck-5mL2A.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-CCdP3Pdx.js → chunk-67CJDMHE-Dl7bLJGe.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-bXgVzdM9.js → chunk-7N4EOEYR-CFBOyqnD.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-CYeDvY8B.js → chunk-AA7GKIK3-BnnqjSlh.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-U0Fi-Ers.js → chunk-BSJP7CBP-DKCTDAZE.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-C8QrV6Gg.js → chunk-CIAEETIT-jjeAEkQy.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-DhpopONL.js → chunk-EDXVE4YY-BPqvO0TO.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CwpQJ9IE.js → chunk-ENJZ2VHE-PN6Hbw2D.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-DxAQS3UB.js → chunk-FMBD7UC4-B0zglVlf.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-CyIK3zeY.js → chunk-FOC6F5B3-COVX_UuK.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-D5p7fCDj.js → chunk-ICPOFSXX-DkmwqyfQ.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-7GcDzjyJ.js → chunk-K5T4RW27-Bav1KRIS.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-B7pAr9hf.js → chunk-KGLVRYIC-nj7A12cJ.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-DEoU2jrz.js → chunk-LIHQZDEY-BmMkL9jD.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-BwMFuN24.js → chunk-ORNJ4GCN-BvGwrI3j.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-DCXhGWX0.js → chunk-OYMX7WX6-CWyihoif.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-COXR_N4N.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-D6lKmEsB.js → chunk-U2HBQHQK-BCWQB0k9.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-DiKHy0ar.js → chunk-X2U36JSP-CcaCMsL0.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-BA0a8Ygs.js → chunk-XPW4576I-DpLw5_cw.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-AqHm3K1O.js → chunk-YZCP3GAM-BUTzrAoG.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-jDPov-Ao.js → chunk-ZZ45TVLE-BD9UGg96.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BcD2DnVi.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-ChvbGJh0.js +1 -0
- package/payload/server/public/assets/clone-DPfDeykW.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Df_JmB8E.js → cose-bilkent-S5V4N54A-bCIQHniJ.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-DDGXoEYU.js → dagre-KV5264BT-DcOMoMzF.js} +1 -1
- package/payload/server/public/assets/{dagre-Dyawd5Z2.js → dagre-dnTAouT6.js} +1 -1
- package/payload/server/public/assets/data-BSt0roMQ.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-BQ1s5wpz.js → diagram-5BDNPKRD-BuQUC75n.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BnBA0Ain.js → diagram-G4DWMVQ6-DHiu9U7B.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-BrGASMP1.js → diagram-MMDJMWI5-ypu7YJGF.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-iSPhqW2Q.js → diagram-TYMM5635-DIwuWuqN.js} +1 -1
- package/payload/server/public/assets/{dist-BmvZ8OaX.js → dist-ePW3hz19.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-BCRyIkOj.js → erDiagram-SMLLAGMA-CKxGMQZW.js} +1 -1
- package/payload/server/public/assets/{flatten-Bo6YRmWl.js → flatten-CpKIi5d2.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BgMtd8aD.js → flowDiagram-DWJPFMVM-CqH2RE7a.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BKpI7Sqx.js → ganttDiagram-T4ZO3ILL-BfuGXUUh.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CwwaM7ed.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CEx6x6gJ.js → gitGraphDiagram-UUTBAWPF-BlpUYLLd.js} +1 -1
- package/payload/server/public/assets/{graph-DDJ3p_3N.js → graph-BEu_XQMZ.js} +19 -19
- package/payload/server/public/assets/graph-labels-DvO7i7Ez.js +1 -0
- package/payload/server/public/assets/{graphlib-Do8h5YVR.js → graphlib-O_QsiopN.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-CiiU112m.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-tHUu3AX-.js +2 -0
- package/payload/server/public/assets/{isEmpty-D6Kr-M1M.js → isEmpty-C3Vxk1It.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-BmCNGBwK.js → ishikawaDiagram-UXIWVN3A-CVMbR1ZD.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-C_37fL2K.js → journeyDiagram-VCZTEJTY-7pbwsn7f.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BLFxAQHd.js → kanban-definition-6JOO6SKY-CWFMjHiJ.js} +1 -1
- package/payload/server/public/assets/{line-FtY_Ltj6.js → line-B4V-vQdN.js} +1 -1
- package/payload/server/public/assets/{linear-COm19-p7.js → linear-Cdt0EBMa.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-BIr5bg_O.js → mermaid-parser.core-Ba5Re-_1.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-8XmmGzXJ.js → mermaid.core-C39ZL-9e.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DPKDmfiH.js → mindmap-definition-QFDTVHPH-BrREiATP.js} +1 -1
- package/payload/server/public/assets/{ordinal-BDi6f4xk.js → ordinal-BLrOss5K.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Bq_zPNb3.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-R-cewHYM.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DyuI0jFr.js → pieDiagram-DEJITSTG-sJOzKUIf.js} +1 -1
- package/payload/server/public/assets/{public-n0sHV8JI.js → public-927mDSLH.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-B24Cvsjf.js → quadrantDiagram-34T5L4WZ-bxoGUruT.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-CZpBUjmo.js +1 -0
- package/payload/server/public/assets/{reduce-CGi9ik8i.js → reduce-C5tBOlxC.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-DpieLND2.js → requirementDiagram-MS252O5E-C8_uEDnp.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DFSI4LuL.js → sankeyDiagram-XADWPNL6-CKpSBj6p.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-3babM9wY.js → sequenceDiagram-FGHM5R23-BbVOmtji.js} +1 -1
- package/payload/server/public/assets/{src-DLEIsjER.js → src-DssjGmtU.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DKS3fdXm.js → stateDiagram-FHFEXIEX-CLiLypPX.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Cn6OBfIT.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-1nRSO-Z9.js → timeline-definition-GMOUNBTQ-Dzzc-pnB.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CjsdVrjr.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-BZ8peN4O.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-DvBm4di-.js → useSelectionMode-BBvWzgtz.js} +1 -1
- package/payload/server/public/assets/useSelectionMode-CzWzToaM.css +1 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-Ds6i6j3g.js → vennDiagram-DHZGUBPP-CEj_ctTP.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-BYLmRSDV.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-IZMQXgw6.js → wardleyDiagram-NUSXRM2D-Cnbz79qd.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BGZkTooo.js → xychartDiagram-5P7HB3ND-MTjLweae.js} +1 -1
- package/payload/server/public/browser.html +6 -5
- package/payload/server/public/chat.html +19 -0
- package/payload/server/public/data.html +7 -6
- package/payload/server/public/graph.html +8 -7
- package/payload/server/public/index.html +8 -6
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +785 -338
- package/payload/server/public/assets/AdminShell-CnslFKoX.js +0 -1
- package/payload/server/public/assets/admin-BJYDe3p8.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-xHbVjatf.js +0 -1
- package/payload/server/public/assets/browser-CKxPsTlh.js +0 -1
- package/payload/server/public/assets/channel-DPRBU48c.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-CWj9Y5LE.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CHE_iZO7.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BmQz46EF.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DyidaYtj.js +0 -1
- package/payload/server/public/assets/clone-D7qj6dUB.js +0 -1
- package/payload/server/public/assets/data-BEDsi4bU.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CmHdoS27.js +0 -1
- package/payload/server/public/assets/graph-labels-Cgd3XiNd.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-DTA9msO-.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-DGlZXVKh.js +0 -2
- package/payload/server/public/assets/packet-4T2RLAQJ-6GjqIKgu.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-T72DJ5JR.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-x-6xW1dE.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Dh0X-qyv.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-5-6wEryJ.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-DF48Cc86.js +0 -1
- package/payload/server/public/assets/useSelectionMode-CeQtw8Ba.css +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-duKIa6Hq.js +0 -1
- /package/payload/server/public/assets/{_baseFor-Cam2PbSt.js → _baseFor-WfS9pKAn.js} +0 -0
- /package/payload/server/public/assets/{array-DYRGGQae.js → array-HeX70jSN.js} +0 -0
- /package/payload/server/public/assets/{chunk-CnGqDkHZ.js → chunk-CWOGyPgy.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-nWsJMTNI.js → cytoscape.esm-CDZo0kst.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-Du1XY3Dp.js → defaultLocale-GJwWH1Jr.js} +0 -0
- /package/payload/server/public/assets/{init-B5BXBRcm.js → init-BPLPMQ3Y.js} +0 -0
- /package/payload/server/public/assets/{katex-HOUACuRw.js → katex-CKZ-HWMQ.js} +0 -0
- /package/payload/server/public/assets/{path-CNO468J-.js → path-YdFzr2W6.js} +0 -0
- /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 @@
|
|
|
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
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
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
|
|
33
|
-
* not just
|
|
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
|
|
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 —
|
|
65
|
-
* routes the request instead of authoring it inline
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
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
|
|
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"}
|