@rubytech/create-maxy-code 0.1.299 → 0.1.301
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +10 -10
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +84 -84
- package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +4 -4
- package/payload/platform/plugins/aeo/PLUGIN.md +1 -1
- package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +4 -4
- package/payload/platform/plugins/cloudflare/references/manual-setup.md +43 -22
- package/payload/platform/plugins/cloudflare/references/reset-guide.md +19 -1
- package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +19 -3
- package/payload/platform/plugins/contacts/PLUGIN.md +1 -1
- package/payload/platform/plugins/docs/references/admin-identity-gate.md +6 -6
- package/payload/platform/plugins/docs/references/admin-session.md +15 -15
- package/payload/platform/plugins/docs/references/admin-ui.md +18 -18
- package/payload/platform/plugins/docs/references/aeo.md +1 -1
- package/payload/platform/plugins/docs/references/deployment.md +3 -3
- package/payload/platform/plugins/docs/references/internals.md +28 -28
- package/payload/platform/plugins/docs/references/platform.md +21 -21
- package/payload/platform/plugins/docs/references/plugins-guide.md +3 -3
- package/payload/platform/plugins/docs/references/troubleshooting.md +6 -6
- package/payload/platform/plugins/docs/references/visitor-graph.md +3 -3
- package/payload/platform/plugins/email/PLUGIN.md +2 -2
- package/payload/platform/plugins/email/references/email-reference.md +2 -2
- package/payload/platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md +2 -2
- package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +9 -9
- package/payload/platform/plugins/memory/references/graph-primitives.md +2 -2
- package/payload/platform/plugins/memory/references/schema-base.md +14 -14
- package/payload/platform/plugins/memory/references/transcript-formats/circleback.md +1 -1
- package/payload/platform/plugins/memory/references/transcript-formats/otter.md +1 -1
- package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +6 -6
- package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +1 -1
- package/payload/platform/plugins/memory/skills/conversation-archive-mcp/SKILL.md +8 -8
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +5 -5
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/daily-notes.md +1 -1
- package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +1 -1
- package/payload/platform/plugins/slides/PROVENANCE.md +1 -1
- package/payload/platform/plugins/substack-import/skills/substack-import/SKILL.md +1 -1
- package/payload/platform/plugins/telegram/PLUGIN.md +1 -1
- package/payload/platform/plugins/url-get/PLUGIN.md +2 -2
- package/payload/platform/plugins/whatsapp/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +5 -5
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +5 -5
- package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +1 -1
- package/payload/platform/plugins/workflows/PLUGIN.md +1 -1
- package/payload/platform/plugins/x-import/PLUGIN.md +2 -2
- package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +1 -1
- package/payload/platform/scripts/__tests__/check-no-task-id-leaks.test.sh +125 -0
- package/payload/platform/scripts/__tests__/resume-tunnel.test.sh +253 -0
- package/payload/platform/scripts/check-no-esm-require.mjs +4 -0
- package/payload/platform/scripts/check-no-task-id-leaks.mjs +54 -6
- package/payload/platform/scripts/resume-tunnel.sh +89 -5
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +14 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +11 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts +4 -0
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +54 -3
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts +18 -0
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts.map +1 -0
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.js +137 -0
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.js.map +1 -0
- package/payload/platform/templates/specialists/agents/database-operator.md +1 -1
- package/payload/platform/templates/specialists/agents/librarian.md +2 -2
- package/payload/server/{chunk-7H4KMTMC.js → chunk-JHSF5VPE.js} +171 -95
- package/payload/server/maxy-edge.js +19 -1
- package/payload/server/public/assets/AdminShell-BJrxifYa.js +1 -0
- package/payload/server/public/assets/{Checkbox-DHnspkuk.js → Checkbox-C7bBRzLP.js} +1 -1
- package/payload/server/public/assets/{Transcript-9FlneAzM.js → Transcript-bGy_Gx99.js} +1 -1
- package/payload/server/public/assets/admin-jYKA7jR5.js +1 -0
- package/payload/server/public/assets/{arc-CPOhuw1V.js → arc-DxSm8tli.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-6g9jRVgc.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-BaR37f-j.js → architectureDiagram-Q4EWVU46-7JSAh0vL.js} +1 -1
- package/payload/server/public/assets/audio-attachment-mime-DL5R1M2A.js +30 -0
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-Du7NMQfQ.js → blockDiagram-DXYQGD6D-DLoVmHKD.js} +1 -1
- package/payload/server/public/assets/{browser--bCCzvRh.js → browser-7fyPCFWB.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-F3GnFLbs.js → c4Diagram-AHTNJAMY-Nv1G0o9P.js} +1 -1
- package/payload/server/public/assets/channel-BgQLJanG.js +1 -0
- package/payload/server/public/assets/chat-UF9ATDwe.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-SUv9UlAA.js → chunk-2KRD3SAO-BpqPMhoA.js} +1 -1
- package/payload/server/public/assets/chunk-336JU56O-DgXHlVU_.js +2 -0
- package/payload/server/public/assets/chunk-426QAEUC-Dr_XVuUq.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-D5iKMyHO.js → chunk-4BX2VUAB-nwyZSZH8.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BahbQ7-Z.js → chunk-4TB4RGXK-Tfxz9LHX.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-DfF9myIx.js → chunk-55IACEB6-6FMJQGXG.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-jF6a9UVe.js → chunk-5FUZZQ4R-g2FgZF3D.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BOCI-roy.js → chunk-5PVQY5BW-DtLwXsPH.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-E5wGK0dP.js → chunk-67CJDMHE-K91CP5ZU.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-CtT0GsUT.js → chunk-7N4EOEYR-BGpCQhqK.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-CGUj8eo-.js → chunk-AA7GKIK3-jkDbInck.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-OPAIjvSk.js → chunk-BSJP7CBP-mDosdzGs.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-S_D8FhIT.js → chunk-CIAEETIT-DhBxewpQ.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CkD4AyZi.js → chunk-EDXVE4YY-B7c-9Emg.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CmoK-c5f.js → chunk-ENJZ2VHE-Cqhhncox.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-DcyogdNf.js → chunk-FMBD7UC4-BpDq6wj1.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-8iNobZdv.js → chunk-FOC6F5B3-Ds02-ktu.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DeGZE9pw.js → chunk-ICPOFSXX-BTX5POFr.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-CkoKFdgU.js → chunk-K5T4RW27-Du1PXXBU.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-DyNP1efP.js → chunk-KGLVRYIC-siasOAf8.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-WZPpo5Dd.js → chunk-LIHQZDEY-xf1rbZtf.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-Cr7E0-Df.js → chunk-ORNJ4GCN-DeTLQ_LD.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-BPjxo1Oc.js → chunk-OYMX7WX6-DQ7_oVJn.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DF4o9HRJ.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-CuDS7yVX.js → chunk-U2HBQHQK-CXmFUKgn.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-DEkde3xe.js → chunk-X2U36JSP-Bj8-8Wkz.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-BwRCuKyu.js → chunk-XPW4576I-Con3TXqt.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-DD9nUp-w.js → chunk-YZCP3GAM-Dx8BHGWf.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BDH9b11G.js → chunk-ZZ45TVLE-Dp4Q5Y-f.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DAbPKU6u.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BKuFQLcv.js +1 -0
- package/payload/server/public/assets/clone-DnNHGhNe.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-CfeophtW.js → cose-bilkent-S5V4N54A-pZiCv69E.js} +1 -1
- package/payload/server/public/assets/{dagre-CVxEmku2.js → dagre-CLqhEgbL.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-TOuVLdjq.js → dagre-KV5264BT-BCxE8iyk.js} +1 -1
- package/payload/server/public/assets/{data-B8Waqy4Q.js → data-CIJnkfgX.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-BJQnfJjx.js → diagram-5BDNPKRD-slUEdZzz.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-CqK94J29.js → diagram-G4DWMVQ6-DPcraMfu.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-BCnATv2X.js → diagram-MMDJMWI5-DR6luhGK.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-Cl3BUrVs.js → diagram-TYMM5635-Jap1B4wA.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA--Uw0kvib.js → erDiagram-SMLLAGMA-DJKUs2hO.js} +1 -1
- package/payload/server/public/assets/{file-download-Pk6cNtuB.js → file-download-gth6Gpmn.js} +1 -1
- package/payload/server/public/assets/{flatten-DtM0XAMt.js → flatten-Cl1Bc3dR.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-B_VGZIbJ.js → flowDiagram-DWJPFMVM-C8W-ZZ9W.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-D-vdf1dC.js → ganttDiagram-T4ZO3ILL-DYCX4Xu2.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-g7mvu6IY.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CpyAlvu3.js → gitGraphDiagram-UUTBAWPF-CZu_fpgS.js} +1 -1
- package/payload/server/public/assets/{graph-D-VQpkaS.js → graph-DHnB3BHK.js} +1 -1
- package/payload/server/public/assets/{graph-labels-cJvlyVxD.js → graph-labels-huk-fKcY.js} +1 -1
- package/payload/server/public/assets/{graphlib-DaV4XyBp.js → graphlib-Bdp7TA4y.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-DZqJuIkB.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-cGfGccHz.js +2 -0
- package/payload/server/public/assets/{isEmpty-D__iH1WQ.js → isEmpty-D1pGOD1J.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-_4NvfwwU.js → ishikawaDiagram-UXIWVN3A-B7KfIX6z.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-PJQ-tPWv.js → journeyDiagram-VCZTEJTY-CSDwBfhF.js} +1 -1
- package/payload/server/public/assets/jsx-runtime-DZddXDvJ.css +1 -0
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-asCNlyH4.js → kanban-definition-6JOO6SKY-CWzcEKTr.js} +1 -1
- package/payload/server/public/assets/{line-BSXr2IPU.js → line-BNQSlbYn.js} +1 -1
- package/payload/server/public/assets/{linear-CSAKvvko.js → linear-BN6kGN93.js} +1 -1
- package/payload/server/public/assets/mermaid-parser.core-CcFhkElq.js +4 -0
- package/payload/server/public/assets/mermaid.core-BsIeJ7Cc.js +11 -0
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-IxwnMT2Q.js → mindmap-definition-QFDTVHPH-CQVzj6D_.js} +1 -1
- package/payload/server/public/assets/operator-D3QAzlPs.js +1 -0
- package/payload/server/public/assets/{ordinal-BRQ5CzZY.js → ordinal-CBZeH4Yp.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Hn8rlHpy.js +1 -0
- package/payload/server/public/assets/page-86edaOS1.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-BPGWVqBm.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DFqSnPPB.js → pieDiagram-DEJITSTG-DnrQ9fyn.js} +1 -1
- package/payload/server/public/assets/preload-helper-CQ36nxok.js +1 -0
- package/payload/server/public/assets/public-B4LqL6lA.js +6 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-1AB3hlEb.js → quadrantDiagram-34T5L4WZ-BQWlCyWi.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-DMdLrj3E.js +1 -0
- package/payload/server/public/assets/{reduce-CkcXOmmJ.js → reduce-PuPlFPRX.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-C2Zpzq3l.js → requirementDiagram-MS252O5E-Du_vZhU1.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DkmhPhwS.js → sankeyDiagram-XADWPNL6-Cf6Z8GPQ.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-1hQLpeZ1.js → sequenceDiagram-FGHM5R23-CS8GVol8.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CBHIwm3f.js → stateDiagram-FHFEXIEX-Bv1NW2F1.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BGUCxPmp.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-CLRWWipW.js → timeline-definition-GMOUNBTQ-ClGYAsr0.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CWxofUbI.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-Cfgb_ZG0.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-6fff2UIV.js → useSelectionMode-lrH0qwAR.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-ByFoQMek.js → vennDiagram-DHZGUBPP-C2wTcxQT.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-B45olYjj.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DIkXRSha.js → wardleyDiagram-NUSXRM2D-D86-ivEx.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BNdEcN73.js → xychartDiagram-5P7HB3ND-Ba5WAN8P.js} +1 -1
- package/payload/server/public/browser.html +6 -6
- package/payload/server/public/chat.html +9 -8
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +8 -8
- package/payload/server/public/index.html +9 -9
- package/payload/server/public/operator.html +9 -9
- package/payload/server/public/public.html +7 -6
- package/payload/server/server.js +164 -124
- package/payload/server/public/assets/AdminShell-Eo1RXZxq.js +0 -1
- package/payload/server/public/assets/admin-ORJGvOqo.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-CQHotPO2.js +0 -1
- package/payload/server/public/assets/audio-attachment-mime-CFRERhV0.js +0 -1
- package/payload/server/public/assets/channel-DfO_IgSU.js +0 -1
- package/payload/server/public/assets/chat-DIrzZjdO.js +0 -1
- package/payload/server/public/assets/chunk-336JU56O-DHUrM3QG.js +0 -2
- package/payload/server/public/assets/chunk-426QAEUC-CBo-Lx7X.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CNlL2tiW.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-Bo-iLGpk.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Bz7DNpvQ.js +0 -1
- package/payload/server/public/assets/clone-Bh_bM_44.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-Ds2hoRX4.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-BuX4gDTt.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-pcFw8-8F.js +0 -2
- package/payload/server/public/assets/jsx-runtime-BjFkEGXb.css +0 -1
- package/payload/server/public/assets/mermaid-parser.core-DFxv-h16.js +0 -4
- package/payload/server/public/assets/mermaid.core-Be34BFtA.js +0 -11
- package/payload/server/public/assets/operator-DyLRFmNE.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-9qQ2zAJ3.js +0 -1
- package/payload/server/public/assets/page-CFgywgGE.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-aDbmozld.js +0 -1
- package/payload/server/public/assets/public-_pD6yEQ6.js +0 -35
- package/payload/server/public/assets/radar-PYXPWWZC-CEm-iLey.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DHGLsXgi.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-DYa2gPJa.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-D816ED1y.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-BniDWDlr.js +0 -1
- /package/payload/server/public/assets/{_baseFor-SRtUHe7G.js → _baseFor-brRjpUOX.js} +0 -0
- /package/payload/server/public/assets/{array-BpsnM-Py.js → array-BGFCBI0e.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-D4Rl1H5h.js → cytoscape.esm-TvRJ2tGX.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-C7sQPl-O.js → defaultLocale-CRZydyG6.js} +0 -0
- /package/payload/server/public/assets/{dist-BXJR8AkG.js → dist-Dbh7HrZX.js} +0 -0
- /package/payload/server/public/assets/{init-BydxaDEV.js → init-B8gtcn7T.js} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-B54kfC3e.js → jsx-runtime-CMu8uN0-.js} +0 -0
- /package/payload/server/public/assets/{katex-B0fVeDx4.js → katex-RxgSu_dy.js} +0 -0
- /package/payload/server/public/assets/{path-jlWYQ2i9.js → path-DZF-JdEe.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-c4PR5shF.js → rough.esm-6CnTHTkH.js} +0 -0
- /package/payload/server/public/assets/{src-CPkr6SrY.js → src-BoaldmnP.js} +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Standing guard for the markdown task-id leak scan. If a fixture citation under
|
|
3
|
+
# a shipped plugin/template .md stops failing the gate, the markdown coverage
|
|
4
|
+
# regressed back to code-only and internal task numbers can ship to clients
|
|
5
|
+
# again. The gate reads its scan root from TASK_ID_LEAK_ROOT so this test points
|
|
6
|
+
# it at a mktemp fixture tree, never the real corpus.
|
|
7
|
+
set -u
|
|
8
|
+
GATE="$(cd "$(dirname "$0")/.." && pwd)/check-no-task-id-leaks.mjs"
|
|
9
|
+
[[ -f "$GATE" ]] || { echo "FAIL: $GATE missing" >&2; exit 1; }
|
|
10
|
+
PASS=0; FAIL=0
|
|
11
|
+
|
|
12
|
+
ROOT=$(mktemp -d)
|
|
13
|
+
trap 'rm -rf "$ROOT"' EXIT
|
|
14
|
+
mkdir -p "$ROOT/platform/plugins/demo/skills/demo" \
|
|
15
|
+
"$ROOT/platform/templates/specialists" \
|
|
16
|
+
"$ROOT/.docs"
|
|
17
|
+
|
|
18
|
+
clean_skill() { printf '# Demo skill\n\nDoes a thing.\n' > "$ROOT/platform/plugins/demo/skills/demo/SKILL.md"; }
|
|
19
|
+
clean_skill
|
|
20
|
+
|
|
21
|
+
# 1. Clean corpus -> gate passes.
|
|
22
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
23
|
+
if [[ "$rc" -eq 0 ]]; then
|
|
24
|
+
echo "PASS: clean markdown corpus -> exit 0"; PASS=$((PASS+1))
|
|
25
|
+
else
|
|
26
|
+
echo "FAIL: clean corpus tripped gate (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# 2. `(Task 999)` parenthetical under a shipped skill -> gate fails + names it.
|
|
30
|
+
printf '# Demo skill\n\nDoes a thing (Task 999).\n' > "$ROOT/platform/plugins/demo/skills/demo/SKILL.md"
|
|
31
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
32
|
+
if [[ "$rc" -ne 0 ]] \
|
|
33
|
+
&& printf '%s' "$out" | grep -q '\[task-id-leak\] file=platform/plugins/demo/skills/demo/SKILL.md'; then
|
|
34
|
+
echo "PASS: (Task 999) in shipped skill fails the gate"; PASS=$((PASS+1))
|
|
35
|
+
else
|
|
36
|
+
echo "FAIL: parenthetical citation not caught (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
37
|
+
fi
|
|
38
|
+
clean_skill
|
|
39
|
+
|
|
40
|
+
# 3. Bare `Task 999` (prose form) under a shipped template -> gate fails + names it.
|
|
41
|
+
printf 'Task 999 changed the routing.\n' > "$ROOT/platform/templates/specialists/AGENT.md"
|
|
42
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
43
|
+
if [[ "$rc" -ne 0 ]] \
|
|
44
|
+
&& printf '%s' "$out" | grep -q '\[task-id-leak\] file=platform/templates/specialists/AGENT.md'; then
|
|
45
|
+
echo "PASS: bare Task 999 in shipped template fails the gate"; PASS=$((PASS+1))
|
|
46
|
+
else
|
|
47
|
+
echo "FAIL: bare prose citation not caught (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
48
|
+
fi
|
|
49
|
+
rm -f "$ROOT/platform/templates/specialists/AGENT.md"
|
|
50
|
+
|
|
51
|
+
# 4. `Tasks 12 and 34` plural form under a shipped skill -> gate fails.
|
|
52
|
+
printf '# Demo skill\n\nMerged behaviour (Tasks 12 and 34).\n' > "$ROOT/platform/plugins/demo/skills/demo/SKILL.md"
|
|
53
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
54
|
+
if [[ "$rc" -ne 0 ]] \
|
|
55
|
+
&& printf '%s' "$out" | grep -q '\[task-id-leak\] .*match=Tasks 12'; then
|
|
56
|
+
echo "PASS: plural Tasks NNN form fails the gate"; PASS=$((PASS+1))
|
|
57
|
+
else
|
|
58
|
+
echo "FAIL: plural citation not caught (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
59
|
+
fi
|
|
60
|
+
clean_skill
|
|
61
|
+
|
|
62
|
+
# 4b. Hyphenated `Pre-Task-748` form under a shipped skill -> gate fails.
|
|
63
|
+
printf '# Demo skill\n\nPre-Task-748 the index was small.\n' > "$ROOT/platform/plugins/demo/skills/demo/SKILL.md"
|
|
64
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
65
|
+
if [[ "$rc" -ne 0 ]] \
|
|
66
|
+
&& printf '%s' "$out" | grep -q '\[task-id-leak\] .*match=Task-748'; then
|
|
67
|
+
echo "PASS: hyphenated Pre-Task-748 form fails the gate"; PASS=$((PASS+1))
|
|
68
|
+
else
|
|
69
|
+
echo "FAIL: hyphenated citation not caught (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
70
|
+
fi
|
|
71
|
+
clean_skill
|
|
72
|
+
|
|
73
|
+
# 4c. A lowercase `task-836-foo` slug (branch/file name) -> gate does NOT trip.
|
|
74
|
+
printf '# Demo skill\n\nWork landed on branch task-836-foo.\n' > "$ROOT/platform/plugins/demo/skills/demo/SKILL.md"
|
|
75
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
76
|
+
if [[ "$rc" -eq 0 ]]; then
|
|
77
|
+
echo "PASS: lowercase task-836 slug is not flagged"; PASS=$((PASS+1))
|
|
78
|
+
else
|
|
79
|
+
echo "FAIL: lowercase slug wrongly tripped gate (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
80
|
+
fi
|
|
81
|
+
clean_skill
|
|
82
|
+
|
|
83
|
+
# 4d. Lowercase prose `before task 127` under a shipped skill -> gate fails.
|
|
84
|
+
printf '# Demo skill\n\nResults from before task 127 remain in the graph.\n' > "$ROOT/platform/plugins/demo/skills/demo/SKILL.md"
|
|
85
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
86
|
+
if [[ "$rc" -ne 0 ]] \
|
|
87
|
+
&& printf '%s' "$out" | grep -q '\[task-id-leak\] .*match=task 127'; then
|
|
88
|
+
echo "PASS: lowercase prose 'task 127' fails the gate"; PASS=$((PASS+1))
|
|
89
|
+
else
|
|
90
|
+
echo "FAIL: lowercase prose citation not caught (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
91
|
+
fi
|
|
92
|
+
clean_skill
|
|
93
|
+
|
|
94
|
+
# 4e. A `.tasks/<n>-…-task-NNN.md` file-path reference -> gate does NOT trip
|
|
95
|
+
# (file paths are out of scope; the hyphenated-lowercase shape is exempt).
|
|
96
|
+
printf '# Demo skill\n\nTracked in `.tasks/339-installer-smoke-task-297.md` for now.\n' > "$ROOT/platform/plugins/demo/skills/demo/SKILL.md"
|
|
97
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
98
|
+
if [[ "$rc" -eq 0 ]]; then
|
|
99
|
+
echo "PASS: .tasks/ file-path reference is not flagged"; PASS=$((PASS+1))
|
|
100
|
+
else
|
|
101
|
+
echo "FAIL: .tasks/ path wrongly tripped gate (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
102
|
+
fi
|
|
103
|
+
clean_skill
|
|
104
|
+
|
|
105
|
+
# 5. A hex colour `#999` in a shipped .md -> gate does NOT trip (not a citation).
|
|
106
|
+
printf '# Demo skill\n\nUse colour `#999` for labels.\n' > "$ROOT/platform/plugins/demo/skills/demo/SKILL.md"
|
|
107
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
108
|
+
if [[ "$rc" -eq 0 ]]; then
|
|
109
|
+
echo "PASS: hex colour #999 is not flagged as a citation"; PASS=$((PASS+1))
|
|
110
|
+
else
|
|
111
|
+
echo "FAIL: hex colour wrongly tripped gate (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
112
|
+
fi
|
|
113
|
+
clean_skill
|
|
114
|
+
|
|
115
|
+
# 6. Citation in a dev-only .docs doc -> gate does NOT trip (not a shipped root).
|
|
116
|
+
printf 'Internal note about Task 999.\n' > "$ROOT/.docs/note.md"
|
|
117
|
+
out=$(TASK_ID_LEAK_ROOT="$ROOT" node "$GATE" 2>&1); rc=$?
|
|
118
|
+
if [[ "$rc" -eq 0 ]]; then
|
|
119
|
+
echo "PASS: .docs citation is exempt (dev-only, unscanned)"; PASS=$((PASS+1))
|
|
120
|
+
else
|
|
121
|
+
echo "FAIL: .docs citation wrongly tripped gate (rc=$rc): $out" >&2; FAIL=$((FAIL+1))
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
echo "----"; echo "PASS=$PASS FAIL=$FAIL"
|
|
125
|
+
[[ "$FAIL" -eq 0 ]]
|
|
@@ -276,12 +276,265 @@ case_supervision_contract() {
|
|
|
276
276
|
return 0
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
# ---------------------------------------------------------------------------
|
|
280
|
+
# Task 833 — stray-connector reap.
|
|
281
|
+
#
|
|
282
|
+
# install_reap_stubs adds a `ps` stub and a `kill` recorder on top of setup().
|
|
283
|
+
# The ps stub reads a table file ($root/ps_table) of "<pid> <argv...>" lines and
|
|
284
|
+
# answers both query shapes the script uses: `-eo pid=,args=` (full table) and
|
|
285
|
+
# `-p <pid> -o args=` (single argv). The recorder ($root/bin/killrec, wired via
|
|
286
|
+
# RESUME_TUNNEL_KILL_CMD) appends -TERM/-KILL calls to $root/reap_log; on a `-0`
|
|
287
|
+
# liveness query it reports "gone" (exit 1) unless $root/reap_alive exists.
|
|
288
|
+
install_reap_stubs() {
|
|
289
|
+
local root="$1"
|
|
290
|
+
local bin_dir="$root/bin"
|
|
291
|
+
|
|
292
|
+
cat > "$bin_dir/ps" <<SH
|
|
293
|
+
#!/bin/bash
|
|
294
|
+
table="$root/ps_table"
|
|
295
|
+
if [[ "\$*" == *"-p"* ]]; then
|
|
296
|
+
pid=""; prev=""
|
|
297
|
+
for a in "\$@"; do
|
|
298
|
+
[[ "\$prev" == "-p" ]] && pid="\$a"
|
|
299
|
+
prev="\$a"
|
|
300
|
+
done
|
|
301
|
+
awk -v want="\$pid" '{ if (\$1==want){ \$1=""; sub(/^ /,""); print } }' "\$table" 2>/dev/null
|
|
302
|
+
exit 0
|
|
303
|
+
fi
|
|
304
|
+
cat "\$table" 2>/dev/null
|
|
305
|
+
exit 0
|
|
306
|
+
SH
|
|
307
|
+
chmod +x "$bin_dir/ps"
|
|
308
|
+
|
|
309
|
+
cat > "$bin_dir/killrec" <<SH
|
|
310
|
+
#!/bin/bash
|
|
311
|
+
if [[ "\$1" == "-0" ]]; then
|
|
312
|
+
[[ -f "$root/reap_alive" ]] && exit 0 || exit 1
|
|
313
|
+
fi
|
|
314
|
+
echo "\$*" >> "$root/reap_log"
|
|
315
|
+
exit 0
|
|
316
|
+
SH
|
|
317
|
+
chmod +x "$bin_dir/killrec"
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
# Write a config.yml carrying the brand tunnel id so the audit line can resolve it.
|
|
321
|
+
write_branded_config() {
|
|
322
|
+
local cfg="$1"
|
|
323
|
+
cat > "$cfg" <<'YML'
|
|
324
|
+
tunnel: test-tunnel-id
|
|
325
|
+
credentials-file: /dev/null
|
|
326
|
+
ingress:
|
|
327
|
+
- service: http_status:404
|
|
328
|
+
YML
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
# Run resume-tunnel with the reap stubs + recorder active.
|
|
332
|
+
# Args: root config_dir [extra env assignments...]
|
|
333
|
+
run_with_reap() {
|
|
334
|
+
local root="$1" config_dir="$2"; shift 2
|
|
335
|
+
# Use env so any extra "NAME=VALUE" args (e.g. RESUME_TUNNEL_REAP_GRACE=0)
|
|
336
|
+
# are applied as assignments — a variable-expanded NAME=VALUE word is NOT
|
|
337
|
+
# treated as an assignment by bash's own simple-command parsing.
|
|
338
|
+
env \
|
|
339
|
+
HOME="$root/home" \
|
|
340
|
+
PATH="$root/bin:$PATH" \
|
|
341
|
+
MAXY_PLATFORM_ROOT="$root/platform_root" \
|
|
342
|
+
RESUME_TUNNEL_KILL_CMD="$root/bin/killrec" \
|
|
343
|
+
RESUME_TUNNEL_VERIFY_DEADLINE=2 \
|
|
344
|
+
"$@" \
|
|
345
|
+
bash "$RESUME"
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
# CASE A: stray present, service inactive → reap kills stray, leaves none, then spawns.
|
|
349
|
+
case_reap_stray_then_spawn() {
|
|
350
|
+
local root; root=$(mktemp -d /tmp/resume-tunnel-test-XXXXXX)
|
|
351
|
+
setup "$root" ".maxy-code" "inactive" "yes"
|
|
352
|
+
install_reap_stubs "$root"
|
|
353
|
+
local home="$root/home"
|
|
354
|
+
local cert="$home/.maxy-code/cloudflared/cert.pem"
|
|
355
|
+
local cfg="$home/.maxy-code/cloudflared/config.yml"
|
|
356
|
+
write_branded_config "$cfg"
|
|
357
|
+
cat > "$root/ps_table" <<TBL
|
|
358
|
+
210086 cloudflared --origincert $cert --config $cfg tunnel run
|
|
359
|
+
777 cloudflared --origincert /home/other/.realagent/cloudflared/cert.pem --config /home/other/.realagent/cloudflared/config.yml tunnel run
|
|
360
|
+
TBL
|
|
361
|
+
|
|
362
|
+
run_with_reap "$root" ".maxy-code"
|
|
363
|
+
local log; log=$(cat "$home/.maxy-code/logs/cloudflared.log" 2>/dev/null || echo "")
|
|
364
|
+
local rec; rec=$(cat "$root/reap_log" 2>/dev/null || echo "")
|
|
365
|
+
cleanup "$root"
|
|
366
|
+
|
|
367
|
+
echo "$log" | grep -q "op=reap brand=maxy-code found=1 killed=1 survivor=none" || { echo " census wrong"; echo "$log"; return 1; }
|
|
368
|
+
echo "$rec" | grep -q -- "-TERM 210086" || { echo " stray not SIGTERMed"; echo "$rec"; return 1; }
|
|
369
|
+
echo "$rec" | grep -q "777" && { echo " co-resident 777 was signalled"; echo "$rec"; return 1; }
|
|
370
|
+
echo "$log" | grep -q "spawned service=cloudflared-maxy-code.service" || { echo " did not spawn after reap"; echo "$log"; return 1; }
|
|
371
|
+
return 0
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
# CASE B: supervised survivor + stray, service active → reap kills only stray, no spawn.
|
|
375
|
+
case_reap_keeps_survivor() {
|
|
376
|
+
local root; root=$(mktemp -d /tmp/resume-tunnel-test-XXXXXX)
|
|
377
|
+
setup "$root" ".maxy-code" "active" "yes"
|
|
378
|
+
install_reap_stubs "$root"
|
|
379
|
+
local home="$root/home"
|
|
380
|
+
local cert="$home/.maxy-code/cloudflared/cert.pem"
|
|
381
|
+
local cfg="$home/.maxy-code/cloudflared/config.yml"
|
|
382
|
+
write_branded_config "$cfg"
|
|
383
|
+
# 12345 is the MainPID the systemctl stub reports.
|
|
384
|
+
cat > "$root/ps_table" <<TBL
|
|
385
|
+
12345 cloudflared --no-autoupdate --origincert $cert --config $cfg tunnel run
|
|
386
|
+
210086 cloudflared --origincert $cert --config $cfg tunnel run
|
|
387
|
+
TBL
|
|
388
|
+
|
|
389
|
+
run_with_reap "$root" ".maxy-code"
|
|
390
|
+
local log; log=$(cat "$home/.maxy-code/logs/cloudflared.log" 2>/dev/null || echo "")
|
|
391
|
+
local rec; rec=$(cat "$root/reap_log" 2>/dev/null || echo "")
|
|
392
|
+
cleanup "$root"
|
|
393
|
+
|
|
394
|
+
echo "$log" | grep -q "op=reap brand=maxy-code found=2 killed=1 survivor=12345" || { echo " census wrong"; echo "$log"; return 1; }
|
|
395
|
+
echo "$rec" | grep -q -- "-TERM 210086" || { echo " stray not SIGTERMed"; echo "$rec"; return 1; }
|
|
396
|
+
echo "$rec" | grep -q "12345" && { echo " survivor 12345 was signalled"; echo "$rec"; return 1; }
|
|
397
|
+
echo "$log" | grep -q "spawned service=" && { echo " spawned while already active"; echo "$log"; return 1; }
|
|
398
|
+
echo "$log" | grep -q "already running" || { echo " missing already-running log"; echo "$log"; return 1; }
|
|
399
|
+
return 0
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
# CASE C: no stray, service active → idempotent, no kill, no spawn.
|
|
403
|
+
case_reap_idempotent() {
|
|
404
|
+
local root; root=$(mktemp -d /tmp/resume-tunnel-test-XXXXXX)
|
|
405
|
+
setup "$root" ".maxy-code" "active" "yes"
|
|
406
|
+
install_reap_stubs "$root"
|
|
407
|
+
local home="$root/home"
|
|
408
|
+
local cert="$home/.maxy-code/cloudflared/cert.pem"
|
|
409
|
+
local cfg="$home/.maxy-code/cloudflared/config.yml"
|
|
410
|
+
write_branded_config "$cfg"
|
|
411
|
+
cat > "$root/ps_table" <<TBL
|
|
412
|
+
12345 cloudflared --no-autoupdate --origincert $cert --config $cfg tunnel run
|
|
413
|
+
TBL
|
|
414
|
+
|
|
415
|
+
run_with_reap "$root" ".maxy-code"
|
|
416
|
+
local log; log=$(cat "$home/.maxy-code/logs/cloudflared.log" 2>/dev/null || echo "")
|
|
417
|
+
local rec; rec=$(cat "$root/reap_log" 2>/dev/null || echo "")
|
|
418
|
+
cleanup "$root"
|
|
419
|
+
|
|
420
|
+
echo "$log" | grep -q "op=reap brand=maxy-code found=1 killed=0 survivor=12345" || { echo " census wrong"; echo "$log"; return 1; }
|
|
421
|
+
[ -z "$rec" ] || { echo " recorder not empty"; echo "$rec"; return 1; }
|
|
422
|
+
echo "$log" | grep -q "spawned service=" && { echo " spawned while single+active"; echo "$log"; return 1; }
|
|
423
|
+
return 0
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
# CASE D: audit line resolves the brand tunnel id from the victim's --config.
|
|
427
|
+
case_reap_audit_tunnel_id() {
|
|
428
|
+
local root; root=$(mktemp -d /tmp/resume-tunnel-test-XXXXXX)
|
|
429
|
+
setup "$root" ".maxy-code" "inactive" "yes"
|
|
430
|
+
install_reap_stubs "$root"
|
|
431
|
+
local home="$root/home"
|
|
432
|
+
local cert="$home/.maxy-code/cloudflared/cert.pem"
|
|
433
|
+
local cfg="$home/.maxy-code/cloudflared/config.yml"
|
|
434
|
+
write_branded_config "$cfg"
|
|
435
|
+
cat > "$root/ps_table" <<TBL
|
|
436
|
+
210086 cloudflared --origincert $cert --config $cfg tunnel run
|
|
437
|
+
TBL
|
|
438
|
+
|
|
439
|
+
run_with_reap "$root" ".maxy-code"
|
|
440
|
+
local log; log=$(cat "$home/.maxy-code/logs/cloudflared.log" 2>/dev/null || echo "")
|
|
441
|
+
cleanup "$root"
|
|
442
|
+
|
|
443
|
+
echo "$log" | grep -q "op=reap brand=maxy-code target=210086 tunnel=test-tunnel-id" || { echo " audit line missing brand tunnel id"; echo "$log"; return 1; }
|
|
444
|
+
return 0
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
# CASE E: only a foreign (co-resident) connector present → untouched, brand still spawns.
|
|
448
|
+
case_reap_foreign_untouched() {
|
|
449
|
+
local root; root=$(mktemp -d /tmp/resume-tunnel-test-XXXXXX)
|
|
450
|
+
setup "$root" ".maxy-code" "inactive" "yes"
|
|
451
|
+
install_reap_stubs "$root"
|
|
452
|
+
local home="$root/home"
|
|
453
|
+
write_branded_config "$home/.maxy-code/cloudflared/config.yml"
|
|
454
|
+
cat > "$root/ps_table" <<TBL
|
|
455
|
+
777 cloudflared --origincert /home/other/.realagent/cloudflared/cert.pem --config /home/other/.realagent/cloudflared/config.yml tunnel run
|
|
456
|
+
TBL
|
|
457
|
+
|
|
458
|
+
run_with_reap "$root" ".maxy-code"
|
|
459
|
+
local log; log=$(cat "$home/.maxy-code/logs/cloudflared.log" 2>/dev/null || echo "")
|
|
460
|
+
local rec; rec=$(cat "$root/reap_log" 2>/dev/null || echo "")
|
|
461
|
+
cleanup "$root"
|
|
462
|
+
|
|
463
|
+
echo "$log" | grep -q "op=reap brand=maxy-code found=0 killed=0 survivor=none" || { echo " census wrong"; echo "$log"; return 1; }
|
|
464
|
+
[ -z "$rec" ] || { echo " foreign connector signalled"; echo "$rec"; return 1; }
|
|
465
|
+
echo "$log" | grep -q "spawned service=cloudflared-maxy-code.service" || { echo " did not spawn own connector"; echo "$log"; return 1; }
|
|
466
|
+
return 0
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
# CASE G: service active but MainPID unresolved → must NOT reap (can't tell the
|
|
470
|
+
# live supervised connector from a stray), must skip without spawning.
|
|
471
|
+
case_reap_skip_when_mainpid_unresolved() {
|
|
472
|
+
local root; root=$(mktemp -d /tmp/resume-tunnel-test-XXXXXX)
|
|
473
|
+
setup "$root" ".maxy-code" "active" "yes"
|
|
474
|
+
install_reap_stubs "$root"
|
|
475
|
+
local home="$root/home"
|
|
476
|
+
local cert="$home/.maxy-code/cloudflared/cert.pem"
|
|
477
|
+
local cfg="$home/.maxy-code/cloudflared/config.yml"
|
|
478
|
+
write_branded_config "$cfg"
|
|
479
|
+
# Override systemctl so MainPID resolves empty while is-active stays active
|
|
480
|
+
# (the RestartSec transition window).
|
|
481
|
+
cat > "$root/bin/systemctl" <<'SH'
|
|
482
|
+
#!/bin/bash
|
|
483
|
+
if [[ "$*" == *"is-active"* ]]; then echo "active"; exit 0; fi
|
|
484
|
+
if [[ "$*" == *"--property=MainPID"* ]]; then echo ""; fi
|
|
485
|
+
exit 0
|
|
486
|
+
SH
|
|
487
|
+
chmod +x "$root/bin/systemctl"
|
|
488
|
+
cat > "$root/ps_table" <<TBL
|
|
489
|
+
210086 cloudflared --no-autoupdate --origincert $cert --config $cfg tunnel run
|
|
490
|
+
TBL
|
|
491
|
+
|
|
492
|
+
run_with_reap "$root" ".maxy-code"
|
|
493
|
+
local log; log=$(cat "$home/.maxy-code/logs/cloudflared.log" 2>/dev/null || echo "")
|
|
494
|
+
local rec; rec=$(cat "$root/reap_log" 2>/dev/null || echo "")
|
|
495
|
+
cleanup "$root"
|
|
496
|
+
|
|
497
|
+
[ -z "$rec" ] || { echo " reaped while survivor unknown — would kill the live connector"; echo "$rec"; return 1; }
|
|
498
|
+
echo "$log" | grep -q "skipped reason=mainpid-unresolved" || { echo " missing mainpid-unresolved skip log"; echo "$log"; return 1; }
|
|
499
|
+
echo "$log" | grep -q "spawned service=" && { echo " spawned while active"; echo "$log"; return 1; }
|
|
500
|
+
return 0
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
# CASE F: stray survives SIGTERM → escalates to SIGKILL.
|
|
504
|
+
case_reap_sigkill_escalation() {
|
|
505
|
+
local root; root=$(mktemp -d /tmp/resume-tunnel-test-XXXXXX)
|
|
506
|
+
setup "$root" ".maxy-code" "inactive" "yes"
|
|
507
|
+
install_reap_stubs "$root"
|
|
508
|
+
local home="$root/home"
|
|
509
|
+
local cert="$home/.maxy-code/cloudflared/cert.pem"
|
|
510
|
+
local cfg="$home/.maxy-code/cloudflared/config.yml"
|
|
511
|
+
write_branded_config "$cfg"
|
|
512
|
+
touch "$root/reap_alive" # recorder reports the proc still alive on -0
|
|
513
|
+
cat > "$root/ps_table" <<TBL
|
|
514
|
+
210086 cloudflared --origincert $cert --config $cfg tunnel run
|
|
515
|
+
TBL
|
|
516
|
+
|
|
517
|
+
run_with_reap "$root" ".maxy-code" RESUME_TUNNEL_REAP_GRACE=0
|
|
518
|
+
local rec; rec=$(cat "$root/reap_log" 2>/dev/null || echo "")
|
|
519
|
+
cleanup "$root"
|
|
520
|
+
|
|
521
|
+
echo "$rec" | grep -q -- "-KILL 210086" || { echo " no SIGKILL escalation"; echo "$rec"; return 1; }
|
|
522
|
+
return 0
|
|
523
|
+
}
|
|
524
|
+
|
|
279
525
|
run_case "skip when service active" case_skip_when_scope_active
|
|
280
526
|
run_case "spawn succeeds and logs verified" case_spawn_succeeds
|
|
281
527
|
run_case "spawn with no connection logs ERROR exits 0" case_spawn_no_connection
|
|
282
528
|
run_case "service unit name derived from configDir" case_scope_unit_name_from_config_dir
|
|
283
529
|
run_case "slice flag passed to systemd-run" case_slice_flag_present
|
|
284
530
|
run_case "supervision contract: restart-always + no-autoupdate + .service" case_supervision_contract
|
|
531
|
+
run_case "reap: stray reaped then spawn (inactive)" case_reap_stray_then_spawn
|
|
532
|
+
run_case "reap: keeps supervised survivor, no spawn (active)" case_reap_keeps_survivor
|
|
533
|
+
run_case "reap: idempotent when single+active" case_reap_idempotent
|
|
534
|
+
run_case "reap: audit line names brand tunnel id" case_reap_audit_tunnel_id
|
|
535
|
+
run_case "reap: foreign co-resident connector untouched" case_reap_foreign_untouched
|
|
536
|
+
run_case "reap: SIGTERM survivor escalates to SIGKILL" case_reap_sigkill_escalation
|
|
537
|
+
run_case "reap: skip when active unit's MainPID is unresolved" case_reap_skip_when_mainpid_unresolved
|
|
285
538
|
|
|
286
539
|
echo ""
|
|
287
540
|
echo "Results: $PASS passed, $FAIL failed"
|
|
@@ -51,6 +51,10 @@ const ALLOWLIST = new Set([
|
|
|
51
51
|
// (server-init-line-stamper.cjs); the test loads it via the sanctioned
|
|
52
52
|
// createRequire(import.meta.url) ESM→CJS bridge, not a raw require.
|
|
53
53
|
'platform/ui/app/lib/__tests__/server-init-line-stamper.test.ts',
|
|
54
|
+
// Same vi.hoisted pattern: Task 829's operator-domains test builds a tmpdir
|
|
55
|
+
// before the module's `../paths` mock fires, to redirect MAXY_DIR off the
|
|
56
|
+
// operator's real home config.
|
|
57
|
+
'platform/ui/app/lib/__tests__/operator-domains.test.ts',
|
|
54
58
|
])
|
|
55
59
|
|
|
56
60
|
const REQUIRE_CALL_RE = /\brequire\s*\(/
|
|
@@ -21,7 +21,11 @@ import { dirname, join, relative, sep, basename } from 'node:path'
|
|
|
21
21
|
import { fileURLToPath } from 'node:url'
|
|
22
22
|
|
|
23
23
|
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url))
|
|
24
|
-
|
|
24
|
+
// REPO_ROOT is overridable so the `.test.sh` self-test can point the gate at a
|
|
25
|
+
// fixture tree without dropping citation-bearing files into the real corpus.
|
|
26
|
+
const REPO_ROOT = process.env.TASK_ID_LEAK_ROOT
|
|
27
|
+
? process.env.TASK_ID_LEAK_ROOT
|
|
28
|
+
: join(SCRIPT_DIR, '..', '..')
|
|
25
29
|
|
|
26
30
|
const SCAN_ROOTS = [
|
|
27
31
|
join(REPO_ROOT, 'platform', 'scripts'),
|
|
@@ -37,6 +41,26 @@ const SKIP_DIR_NAMES = new Set([
|
|
|
37
41
|
])
|
|
38
42
|
const TASK_ID_RE = /\(Task \d+\)/
|
|
39
43
|
|
|
44
|
+
// Markdown mode. Unlike code files — where a citation is legal in a comment and
|
|
45
|
+
// only the parenthetical operator-visible form is rejected — a shipped `.md`
|
|
46
|
+
// loads into a client-facing agent's context wholesale, so ANY citation form
|
|
47
|
+
// leaks. Catches `Task NNN`, `(Task NNN)`, `Tasks NNN`, `since Task NNN`. It
|
|
48
|
+
// deliberately does NOT match bare `#NNN`: every `#NNN` in the corpus is a hex
|
|
49
|
+
// colour and there is no signal to separate `#732`-issue from `#732`-hex.
|
|
50
|
+
// Two alternatives:
|
|
51
|
+
// `\bTasks?[\s-]+\d{2,4}` — capital-T, any separator: `Task 732`, `(Task 732)`,
|
|
52
|
+
// `Tasks 12`, the hyphenated `Pre-Task-748` / `post-Task-904` forms.
|
|
53
|
+
// `\btasks?\s+\d{2,4}` — lowercase but SPACE-separated only: catches prose
|
|
54
|
+
// citations like "before task 127", while a lowercase HYPHENATED `task-537`
|
|
55
|
+
// stays exempt because that shape is a branch slug or a `.tasks/<n>-…-task-NNN.md`
|
|
56
|
+
// file-path reference (file paths are out of this gate's scope). The 2-digit
|
|
57
|
+
// floor keeps single-digit domain counts ("task 1 of 3") out.
|
|
58
|
+
const MD_TASK_ID_RE = /\bTasks?[\s-]+\d{2,4}|\btasks?\s+\d{2,4}/
|
|
59
|
+
const MD_SCAN_ROOTS = [
|
|
60
|
+
join(REPO_ROOT, 'platform', 'plugins'),
|
|
61
|
+
join(REPO_ROOT, 'platform', 'templates'),
|
|
62
|
+
]
|
|
63
|
+
|
|
40
64
|
function isCommentLine(line) {
|
|
41
65
|
const trimmed = line.replace(/^\s+/, '')
|
|
42
66
|
if (trimmed.startsWith('#')) return true
|
|
@@ -97,14 +121,38 @@ for (const root of SCAN_ROOTS) {
|
|
|
97
121
|
}
|
|
98
122
|
}
|
|
99
123
|
|
|
124
|
+
// Markdown scan — shipped operator-loadable docs. Reuses `walk` (which already
|
|
125
|
+
// skips node_modules/dist/build/.next/payload/__tests__) and matches every line
|
|
126
|
+
// against MD_TASK_ID_RE with no comment skip: the whole doc is agent content.
|
|
127
|
+
// .docs/ and .tasks/ are not under MD_SCAN_ROOTS, so they stay citation-rich.
|
|
128
|
+
for (const root of MD_SCAN_ROOTS) {
|
|
129
|
+
for (const file of walk(root)) {
|
|
130
|
+
if (!file.endsWith('.md')) continue
|
|
131
|
+
let content
|
|
132
|
+
try {
|
|
133
|
+
content = readFileSync(file, 'utf-8')
|
|
134
|
+
} catch {
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
137
|
+
const lines = content.split('\n')
|
|
138
|
+
for (let i = 0; i < lines.length; i++) {
|
|
139
|
+
const m = lines[i].match(MD_TASK_ID_RE)
|
|
140
|
+
if (!m) continue
|
|
141
|
+
leaks.push({ file: relative(REPO_ROOT, file), line: i + 1, content: m[0] })
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
100
146
|
if (leaks.length > 0) {
|
|
101
|
-
console.error(`check-no-task-id-leaks: ${leaks.length}
|
|
147
|
+
console.error(`check-no-task-id-leaks: ${leaks.length} task-id citation(s) found:`)
|
|
102
148
|
for (const leak of leaks) {
|
|
103
|
-
console.error(`
|
|
149
|
+
console.error(`[task-id-leak] file=${leak.file} line=${leak.line} match=${leak.content}`)
|
|
104
150
|
}
|
|
105
151
|
console.error('')
|
|
106
|
-
console.error('
|
|
107
|
-
console.error('(stderr/stdout,
|
|
108
|
-
console.error('
|
|
152
|
+
console.error('Code files: citations belong in inline comments only, never in operator-visible')
|
|
153
|
+
console.error('strings (stderr/stdout, logs, systemd --description=, error messages, console.*).')
|
|
154
|
+
console.error('Shipped markdown (platform/plugins, platform/templates): no task citation in any')
|
|
155
|
+
console.error('form — the whole doc loads into a client-facing agent. Dev docs (.docs/, .tasks/)')
|
|
156
|
+
console.error('are exempt and keep their citations.')
|
|
109
157
|
process.exit(1)
|
|
110
158
|
}
|
|
@@ -60,15 +60,99 @@ fi
|
|
|
60
60
|
BRAND="${CONFIG_DIR#.}"
|
|
61
61
|
SERVICE_UNIT="cloudflared-${BRAND}.service"
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
CERT_PATH="$HOME/$CONFIG_DIR/cloudflared/cert.pem"
|
|
64
|
+
|
|
65
|
+
# Task 833 — single-instance enforcement. cloudflared does not hot-reload
|
|
66
|
+
# config.yml; a config change needs a connector restart. resume-tunnel is the
|
|
67
|
+
# single spawner but historically managed only its OWN connector, so a connector
|
|
68
|
+
# started any other way (an unsupervised process from before Task 757, a manual
|
|
69
|
+
# `tunnel run`, a provisioning step that raw-spawned) survived — two connectors
|
|
70
|
+
# on one tunnel, one on stale config, and Cloudflare routes some requests to the
|
|
71
|
+
# stale one → intermittent 404 for any host added after it started. reap_strays
|
|
72
|
+
# guarantees exactly one connector for THIS brand before the spawn/skip decision.
|
|
73
|
+
#
|
|
74
|
+
# Brand isolation: a candidate is reaped only if its argv carries a brand-scoped
|
|
75
|
+
# token — the cert path, config path, or tunnel id, each unique to ~/.<brand>/.
|
|
76
|
+
# A co-resident brand's connector matches none and is never touched. If no brand
|
|
77
|
+
# token is known we skip the reap entirely rather than risk a match-everything.
|
|
78
|
+
KILL_CMD="${RESUME_TUNNEL_KILL_CMD:-kill}"
|
|
79
|
+
|
|
80
|
+
reap_strays() {
|
|
81
|
+
local survivor_pid="$1"
|
|
82
|
+
local match_args=()
|
|
83
|
+
[ -n "$CERT_PATH" ] && match_args+=( -e "$CERT_PATH" )
|
|
84
|
+
[ -n "$CONFIG_PATH" ] && match_args+=( -e "$CONFIG_PATH" )
|
|
85
|
+
[ -n "$TUNNEL_ID" ] && match_args+=( -e "$TUNNEL_ID" )
|
|
86
|
+
if [ "${#match_args[@]}" -eq 0 ]; then
|
|
87
|
+
log "[tunnel-supervise] op=reap brand=$BRAND found=0 killed=0 survivor=${survivor_pid:-none} (no brand token; skipped)"
|
|
88
|
+
return 0
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
local pids
|
|
92
|
+
pids=$(ps -eo pid=,args= 2>/dev/null \
|
|
93
|
+
| grep 'cloudflared' \
|
|
94
|
+
| grep 'tunnel run' \
|
|
95
|
+
| grep -F "${match_args[@]}" \
|
|
96
|
+
| awk '{print $1}')
|
|
97
|
+
|
|
98
|
+
local found=0 killed=0 pid
|
|
99
|
+
for pid in $pids; do
|
|
100
|
+
found=$((found + 1))
|
|
101
|
+
if [ -n "$survivor_pid" ] && [ "$pid" = "$survivor_pid" ]; then
|
|
102
|
+
continue
|
|
103
|
+
fi
|
|
104
|
+
local victim_cfg victim_tid
|
|
105
|
+
victim_cfg=$(ps -p "$pid" -o args= 2>/dev/null | sed -n 's/.*--config[ =]\([^ ]*\).*/\1/p')
|
|
106
|
+
victim_tid=$(grep -E '^tunnel:' "$victim_cfg" 2>/dev/null | head -1 | awk '{print $2}')
|
|
107
|
+
[ -n "$victim_tid" ] || victim_tid="unknown"
|
|
108
|
+
log "[tunnel-supervise] op=reap brand=$BRAND target=$pid tunnel=$victim_tid"
|
|
109
|
+
"$KILL_CMD" -TERM "$pid" 2>/dev/null
|
|
110
|
+
local waited=0
|
|
111
|
+
while "$KILL_CMD" -0 "$pid" 2>/dev/null; do
|
|
112
|
+
if [ "$waited" -ge "${RESUME_TUNNEL_REAP_GRACE:-5}" ]; then
|
|
113
|
+
"$KILL_CMD" -KILL "$pid" 2>/dev/null
|
|
114
|
+
break
|
|
115
|
+
fi
|
|
116
|
+
sleep 1
|
|
117
|
+
waited=$((waited + 1))
|
|
118
|
+
done
|
|
119
|
+
killed=$((killed + 1))
|
|
120
|
+
done
|
|
121
|
+
|
|
122
|
+
log "[tunnel-supervise] op=reap brand=$BRAND found=$found killed=$killed survivor=${survivor_pid:-none}"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# Determine the supervised survivor before reaping. If the unit is active its
|
|
126
|
+
# MainPID is the connector we keep; every other brand-matched connector is a
|
|
127
|
+
# stray. The service is owned by user-systemd, fully outside the brand service's
|
|
128
|
+
# cgroup. Unlike before, an active unit no longer short-circuits the whole
|
|
129
|
+
# script: the reap runs first so strays die even when the supervised one is up.
|
|
130
|
+
SURVIVOR_PID=""
|
|
131
|
+
SERVICE_ACTIVE=0
|
|
65
132
|
if systemctl --user is-active "$SERVICE_UNIT" >/dev/null 2>&1; then
|
|
66
|
-
|
|
67
|
-
|
|
133
|
+
SERVICE_ACTIVE=1
|
|
134
|
+
SURVIVOR_PID=$(systemctl --user show "$SERVICE_UNIT" --property=MainPID --value 2>/dev/null || echo "")
|
|
135
|
+
[ "$SURVIVOR_PID" = "0" ] && SURVIVOR_PID=""
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
# If the unit is active but its MainPID is unresolved (a RestartSec transition:
|
|
139
|
+
# is-active already true while the new MainPID is not yet published), we cannot
|
|
140
|
+
# tell the live supervised connector from a stray — reaping now could SIGKILL the
|
|
141
|
+
# survivor. Skip the reap this cycle; the next brand-service start reaps once
|
|
142
|
+
# MainPID resolves. The connector is up, so there is nothing to spawn either.
|
|
143
|
+
if [ "$SERVICE_ACTIVE" -eq 1 ] && [ -z "$SURVIVOR_PID" ]; then
|
|
144
|
+
log "[tunnel-supervise] op=reap brand=$BRAND skipped reason=mainpid-unresolved survivor=unknown"
|
|
145
|
+
log "Tunnel already running (service $SERVICE_UNIT active, MainPID unresolved) — reap skipped, skipping resume"
|
|
146
|
+
exit 0
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
reap_strays "$SURVIVOR_PID"
|
|
150
|
+
|
|
151
|
+
if [ "$SERVICE_ACTIVE" -eq 1 ]; then
|
|
152
|
+
log "Tunnel already running (service $SERVICE_UNIT active, MainPID ${SURVIVOR_PID:-unknown}) — strays reaped, skipping resume"
|
|
68
153
|
exit 0
|
|
69
154
|
fi
|
|
70
155
|
|
|
71
|
-
CERT_PATH="$HOME/$CONFIG_DIR/cloudflared/cert.pem"
|
|
72
156
|
CLOUDFLARED_BIN=$(command -v cloudflared 2>/dev/null || true)
|
|
73
157
|
|
|
74
158
|
if [ -z "$CLOUDFLARED_BIN" ]; then
|
|
@@ -137,6 +137,20 @@ export declare function postWithRetry(attempt: () => Promise<boolean>, opts: {
|
|
|
137
137
|
delayMs: number;
|
|
138
138
|
sleep: (ms: number) => Promise<void>;
|
|
139
139
|
}): Promise<boolean>;
|
|
140
|
+
/**
|
|
141
|
+
* Build the body for POST /wa-channel/turn-end — the turn-end decision the
|
|
142
|
+
* channel server posts once per turn (Task 832). senderId + sessionId are the
|
|
143
|
+
* server's fixed values (spawn env), never model-supplied; `replied` is whether
|
|
144
|
+
* a reply/reply-document tool_use occurred in the turn; `finalText` is the
|
|
145
|
+
* end_turn message's text (the conclusion the gateway delivers only when nothing
|
|
146
|
+
* was delivered).
|
|
147
|
+
*/
|
|
148
|
+
export declare function buildTurnEndPostBody(mySenderId: string, sessionId: string, replied: boolean, finalText: string): {
|
|
149
|
+
senderId: string;
|
|
150
|
+
sessionId: string;
|
|
151
|
+
replied: boolean;
|
|
152
|
+
finalText: string;
|
|
153
|
+
};
|
|
140
154
|
/** Map a non-OK /wa-channel/reply response into an actionable MCP error string.
|
|
141
155
|
* Terminal (logged out / device removed) tells the agent re-pairing is needed
|
|
142
156
|
* and it must NOT promise an automatic recovery; transient keeps the
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,mBAAmB,QAYI,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"}
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,mBAAmB,QAYI,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;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAE9E;AAED;;;;gCAIgC;AAChC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAMrE"}
|
|
@@ -156,6 +156,17 @@ export async function postWithRetry(attempt, opts) {
|
|
|
156
156
|
}
|
|
157
157
|
return false;
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Build the body for POST /wa-channel/turn-end — the turn-end decision the
|
|
161
|
+
* channel server posts once per turn (Task 832). senderId + sessionId are the
|
|
162
|
+
* server's fixed values (spawn env), never model-supplied; `replied` is whether
|
|
163
|
+
* a reply/reply-document tool_use occurred in the turn; `finalText` is the
|
|
164
|
+
* end_turn message's text (the conclusion the gateway delivers only when nothing
|
|
165
|
+
* was delivered).
|
|
166
|
+
*/
|
|
167
|
+
export function buildTurnEndPostBody(mySenderId, sessionId, replied, finalText) {
|
|
168
|
+
return { senderId: mySenderId, sessionId, replied, finalText };
|
|
169
|
+
}
|
|
159
170
|
/** Map a non-OK /wa-channel/reply response into an actionable MCP error string.
|
|
160
171
|
* Terminal (logged out / device removed) tells the agent re-pairing is needed
|
|
161
172
|
* and it must NOT promise an automatic recovery; transient keeps the
|