@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.
Files changed (213) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/PLUGIN.md +10 -10
  3. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +84 -84
  4. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +4 -4
  5. package/payload/platform/plugins/aeo/PLUGIN.md +1 -1
  6. package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +4 -4
  7. package/payload/platform/plugins/cloudflare/references/manual-setup.md +43 -22
  8. package/payload/platform/plugins/cloudflare/references/reset-guide.md +19 -1
  9. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +19 -3
  10. package/payload/platform/plugins/contacts/PLUGIN.md +1 -1
  11. package/payload/platform/plugins/docs/references/admin-identity-gate.md +6 -6
  12. package/payload/platform/plugins/docs/references/admin-session.md +15 -15
  13. package/payload/platform/plugins/docs/references/admin-ui.md +18 -18
  14. package/payload/platform/plugins/docs/references/aeo.md +1 -1
  15. package/payload/platform/plugins/docs/references/deployment.md +3 -3
  16. package/payload/platform/plugins/docs/references/internals.md +28 -28
  17. package/payload/platform/plugins/docs/references/platform.md +21 -21
  18. package/payload/platform/plugins/docs/references/plugins-guide.md +3 -3
  19. package/payload/platform/plugins/docs/references/troubleshooting.md +6 -6
  20. package/payload/platform/plugins/docs/references/visitor-graph.md +3 -3
  21. package/payload/platform/plugins/email/PLUGIN.md +2 -2
  22. package/payload/platform/plugins/email/references/email-reference.md +2 -2
  23. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md +2 -2
  24. package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
  25. package/payload/platform/plugins/memory/PLUGIN.md +9 -9
  26. package/payload/platform/plugins/memory/references/graph-primitives.md +2 -2
  27. package/payload/platform/plugins/memory/references/schema-base.md +14 -14
  28. package/payload/platform/plugins/memory/references/transcript-formats/circleback.md +1 -1
  29. package/payload/platform/plugins/memory/references/transcript-formats/otter.md +1 -1
  30. package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +6 -6
  31. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +1 -1
  32. package/payload/platform/plugins/memory/skills/conversation-archive-mcp/SKILL.md +8 -8
  33. package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +5 -5
  34. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/daily-notes.md +1 -1
  35. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +1 -1
  36. package/payload/platform/plugins/slides/PROVENANCE.md +1 -1
  37. package/payload/platform/plugins/substack-import/skills/substack-import/SKILL.md +1 -1
  38. package/payload/platform/plugins/telegram/PLUGIN.md +1 -1
  39. package/payload/platform/plugins/url-get/PLUGIN.md +2 -2
  40. package/payload/platform/plugins/whatsapp/.claude-plugin/plugin.json +1 -1
  41. package/payload/platform/plugins/whatsapp/PLUGIN.md +5 -5
  42. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +5 -5
  43. package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +1 -1
  44. package/payload/platform/plugins/workflows/PLUGIN.md +1 -1
  45. package/payload/platform/plugins/x-import/PLUGIN.md +2 -2
  46. package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +1 -1
  47. package/payload/platform/scripts/__tests__/check-no-task-id-leaks.test.sh +125 -0
  48. package/payload/platform/scripts/__tests__/resume-tunnel.test.sh +253 -0
  49. package/payload/platform/scripts/check-no-esm-require.mjs +4 -0
  50. package/payload/platform/scripts/check-no-task-id-leaks.mjs +54 -6
  51. package/payload/platform/scripts/resume-tunnel.sh +89 -5
  52. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +14 -0
  53. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  54. package/payload/platform/services/whatsapp-channel/dist/notification.js +11 -0
  55. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  56. package/payload/platform/services/whatsapp-channel/dist/server.d.ts +4 -0
  57. package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
  58. package/payload/platform/services/whatsapp-channel/dist/server.js +54 -3
  59. package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
  60. package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts +18 -0
  61. package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts.map +1 -0
  62. package/payload/platform/services/whatsapp-channel/dist/turn-follow.js +137 -0
  63. package/payload/platform/services/whatsapp-channel/dist/turn-follow.js.map +1 -0
  64. package/payload/platform/templates/specialists/agents/database-operator.md +1 -1
  65. package/payload/platform/templates/specialists/agents/librarian.md +2 -2
  66. package/payload/server/{chunk-7H4KMTMC.js → chunk-JHSF5VPE.js} +171 -95
  67. package/payload/server/maxy-edge.js +19 -1
  68. package/payload/server/public/assets/AdminShell-BJrxifYa.js +1 -0
  69. package/payload/server/public/assets/{Checkbox-DHnspkuk.js → Checkbox-C7bBRzLP.js} +1 -1
  70. package/payload/server/public/assets/{Transcript-9FlneAzM.js → Transcript-bGy_Gx99.js} +1 -1
  71. package/payload/server/public/assets/admin-jYKA7jR5.js +1 -0
  72. package/payload/server/public/assets/{arc-CPOhuw1V.js → arc-DxSm8tli.js} +1 -1
  73. package/payload/server/public/assets/architecture-YZFGNWBL-6g9jRVgc.js +1 -0
  74. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-BaR37f-j.js → architectureDiagram-Q4EWVU46-7JSAh0vL.js} +1 -1
  75. package/payload/server/public/assets/audio-attachment-mime-DL5R1M2A.js +30 -0
  76. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-Du7NMQfQ.js → blockDiagram-DXYQGD6D-DLoVmHKD.js} +1 -1
  77. package/payload/server/public/assets/{browser--bCCzvRh.js → browser-7fyPCFWB.js} +1 -1
  78. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-F3GnFLbs.js → c4Diagram-AHTNJAMY-Nv1G0o9P.js} +1 -1
  79. package/payload/server/public/assets/channel-BgQLJanG.js +1 -0
  80. package/payload/server/public/assets/chat-UF9ATDwe.js +1 -0
  81. package/payload/server/public/assets/{chunk-2KRD3SAO-SUv9UlAA.js → chunk-2KRD3SAO-BpqPMhoA.js} +1 -1
  82. package/payload/server/public/assets/chunk-336JU56O-DgXHlVU_.js +2 -0
  83. package/payload/server/public/assets/chunk-426QAEUC-Dr_XVuUq.js +1 -0
  84. package/payload/server/public/assets/{chunk-4BX2VUAB-D5iKMyHO.js → chunk-4BX2VUAB-nwyZSZH8.js} +1 -1
  85. package/payload/server/public/assets/{chunk-4TB4RGXK-BahbQ7-Z.js → chunk-4TB4RGXK-Tfxz9LHX.js} +1 -1
  86. package/payload/server/public/assets/{chunk-55IACEB6-DfF9myIx.js → chunk-55IACEB6-6FMJQGXG.js} +1 -1
  87. package/payload/server/public/assets/{chunk-5FUZZQ4R-jF6a9UVe.js → chunk-5FUZZQ4R-g2FgZF3D.js} +1 -1
  88. package/payload/server/public/assets/{chunk-5PVQY5BW-BOCI-roy.js → chunk-5PVQY5BW-DtLwXsPH.js} +1 -1
  89. package/payload/server/public/assets/{chunk-67CJDMHE-E5wGK0dP.js → chunk-67CJDMHE-K91CP5ZU.js} +1 -1
  90. package/payload/server/public/assets/{chunk-7N4EOEYR-CtT0GsUT.js → chunk-7N4EOEYR-BGpCQhqK.js} +1 -1
  91. package/payload/server/public/assets/{chunk-AA7GKIK3-CGUj8eo-.js → chunk-AA7GKIK3-jkDbInck.js} +1 -1
  92. package/payload/server/public/assets/{chunk-BSJP7CBP-OPAIjvSk.js → chunk-BSJP7CBP-mDosdzGs.js} +1 -1
  93. package/payload/server/public/assets/{chunk-CIAEETIT-S_D8FhIT.js → chunk-CIAEETIT-DhBxewpQ.js} +1 -1
  94. package/payload/server/public/assets/{chunk-EDXVE4YY-CkD4AyZi.js → chunk-EDXVE4YY-B7c-9Emg.js} +1 -1
  95. package/payload/server/public/assets/{chunk-ENJZ2VHE-CmoK-c5f.js → chunk-ENJZ2VHE-Cqhhncox.js} +1 -1
  96. package/payload/server/public/assets/{chunk-FMBD7UC4-DcyogdNf.js → chunk-FMBD7UC4-BpDq6wj1.js} +1 -1
  97. package/payload/server/public/assets/{chunk-FOC6F5B3-8iNobZdv.js → chunk-FOC6F5B3-Ds02-ktu.js} +1 -1
  98. package/payload/server/public/assets/{chunk-ICPOFSXX-DeGZE9pw.js → chunk-ICPOFSXX-BTX5POFr.js} +2 -2
  99. package/payload/server/public/assets/{chunk-K5T4RW27-CkoKFdgU.js → chunk-K5T4RW27-Du1PXXBU.js} +1 -1
  100. package/payload/server/public/assets/{chunk-KGLVRYIC-DyNP1efP.js → chunk-KGLVRYIC-siasOAf8.js} +1 -1
  101. package/payload/server/public/assets/{chunk-LIHQZDEY-WZPpo5Dd.js → chunk-LIHQZDEY-xf1rbZtf.js} +1 -1
  102. package/payload/server/public/assets/{chunk-ORNJ4GCN-Cr7E0-Df.js → chunk-ORNJ4GCN-DeTLQ_LD.js} +1 -1
  103. package/payload/server/public/assets/{chunk-OYMX7WX6-BPjxo1Oc.js → chunk-OYMX7WX6-DQ7_oVJn.js} +1 -1
  104. package/payload/server/public/assets/chunk-QZHKN3VN-DF4o9HRJ.js +1 -0
  105. package/payload/server/public/assets/{chunk-U2HBQHQK-CuDS7yVX.js → chunk-U2HBQHQK-CXmFUKgn.js} +1 -1
  106. package/payload/server/public/assets/{chunk-X2U36JSP-DEkde3xe.js → chunk-X2U36JSP-Bj8-8Wkz.js} +1 -1
  107. package/payload/server/public/assets/{chunk-XPW4576I-BwRCuKyu.js → chunk-XPW4576I-Con3TXqt.js} +1 -1
  108. package/payload/server/public/assets/{chunk-YZCP3GAM-DD9nUp-w.js → chunk-YZCP3GAM-Dx8BHGWf.js} +1 -1
  109. package/payload/server/public/assets/{chunk-ZZ45TVLE-BDH9b11G.js → chunk-ZZ45TVLE-Dp4Q5Y-f.js} +1 -1
  110. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DAbPKU6u.js +1 -0
  111. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BKuFQLcv.js +1 -0
  112. package/payload/server/public/assets/clone-DnNHGhNe.js +1 -0
  113. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-CfeophtW.js → cose-bilkent-S5V4N54A-pZiCv69E.js} +1 -1
  114. package/payload/server/public/assets/{dagre-CVxEmku2.js → dagre-CLqhEgbL.js} +1 -1
  115. package/payload/server/public/assets/{dagre-KV5264BT-TOuVLdjq.js → dagre-KV5264BT-BCxE8iyk.js} +1 -1
  116. package/payload/server/public/assets/{data-B8Waqy4Q.js → data-CIJnkfgX.js} +1 -1
  117. package/payload/server/public/assets/{diagram-5BDNPKRD-BJQnfJjx.js → diagram-5BDNPKRD-slUEdZzz.js} +1 -1
  118. package/payload/server/public/assets/{diagram-G4DWMVQ6-CqK94J29.js → diagram-G4DWMVQ6-DPcraMfu.js} +1 -1
  119. package/payload/server/public/assets/{diagram-MMDJMWI5-BCnATv2X.js → diagram-MMDJMWI5-DR6luhGK.js} +1 -1
  120. package/payload/server/public/assets/{diagram-TYMM5635-Cl3BUrVs.js → diagram-TYMM5635-Jap1B4wA.js} +1 -1
  121. package/payload/server/public/assets/{erDiagram-SMLLAGMA--Uw0kvib.js → erDiagram-SMLLAGMA-DJKUs2hO.js} +1 -1
  122. package/payload/server/public/assets/{file-download-Pk6cNtuB.js → file-download-gth6Gpmn.js} +1 -1
  123. package/payload/server/public/assets/{flatten-DtM0XAMt.js → flatten-Cl1Bc3dR.js} +1 -1
  124. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-B_VGZIbJ.js → flowDiagram-DWJPFMVM-C8W-ZZ9W.js} +1 -1
  125. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-D-vdf1dC.js → ganttDiagram-T4ZO3ILL-DYCX4Xu2.js} +1 -1
  126. package/payload/server/public/assets/gitGraph-7Q5UKJZL-g7mvu6IY.js +1 -0
  127. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CpyAlvu3.js → gitGraphDiagram-UUTBAWPF-CZu_fpgS.js} +1 -1
  128. package/payload/server/public/assets/{graph-D-VQpkaS.js → graph-DHnB3BHK.js} +1 -1
  129. package/payload/server/public/assets/{graph-labels-cJvlyVxD.js → graph-labels-huk-fKcY.js} +1 -1
  130. package/payload/server/public/assets/{graphlib-DaV4XyBp.js → graphlib-Bdp7TA4y.js} +1 -1
  131. package/payload/server/public/assets/info-OMHHGYJF-DZqJuIkB.js +1 -0
  132. package/payload/server/public/assets/infoDiagram-42DDH7IO-cGfGccHz.js +2 -0
  133. package/payload/server/public/assets/{isEmpty-D__iH1WQ.js → isEmpty-D1pGOD1J.js} +1 -1
  134. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-_4NvfwwU.js → ishikawaDiagram-UXIWVN3A-B7KfIX6z.js} +1 -1
  135. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-PJQ-tPWv.js → journeyDiagram-VCZTEJTY-CSDwBfhF.js} +1 -1
  136. package/payload/server/public/assets/jsx-runtime-DZddXDvJ.css +1 -0
  137. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-asCNlyH4.js → kanban-definition-6JOO6SKY-CWzcEKTr.js} +1 -1
  138. package/payload/server/public/assets/{line-BSXr2IPU.js → line-BNQSlbYn.js} +1 -1
  139. package/payload/server/public/assets/{linear-CSAKvvko.js → linear-BN6kGN93.js} +1 -1
  140. package/payload/server/public/assets/mermaid-parser.core-CcFhkElq.js +4 -0
  141. package/payload/server/public/assets/mermaid.core-BsIeJ7Cc.js +11 -0
  142. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-IxwnMT2Q.js → mindmap-definition-QFDTVHPH-CQVzj6D_.js} +1 -1
  143. package/payload/server/public/assets/operator-D3QAzlPs.js +1 -0
  144. package/payload/server/public/assets/{ordinal-BRQ5CzZY.js → ordinal-CBZeH4Yp.js} +1 -1
  145. package/payload/server/public/assets/packet-4T2RLAQJ-Hn8rlHpy.js +1 -0
  146. package/payload/server/public/assets/page-86edaOS1.js +1 -0
  147. package/payload/server/public/assets/pie-ZZUOXDRM-BPGWVqBm.js +1 -0
  148. package/payload/server/public/assets/{pieDiagram-DEJITSTG-DFqSnPPB.js → pieDiagram-DEJITSTG-DnrQ9fyn.js} +1 -1
  149. package/payload/server/public/assets/preload-helper-CQ36nxok.js +1 -0
  150. package/payload/server/public/assets/public-B4LqL6lA.js +6 -0
  151. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-1AB3hlEb.js → quadrantDiagram-34T5L4WZ-BQWlCyWi.js} +1 -1
  152. package/payload/server/public/assets/radar-PYXPWWZC-DMdLrj3E.js +1 -0
  153. package/payload/server/public/assets/{reduce-CkcXOmmJ.js → reduce-PuPlFPRX.js} +1 -1
  154. package/payload/server/public/assets/{requirementDiagram-MS252O5E-C2Zpzq3l.js → requirementDiagram-MS252O5E-Du_vZhU1.js} +1 -1
  155. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DkmhPhwS.js → sankeyDiagram-XADWPNL6-Cf6Z8GPQ.js} +1 -1
  156. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-1hQLpeZ1.js → sequenceDiagram-FGHM5R23-CS8GVol8.js} +1 -1
  157. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CBHIwm3f.js → stateDiagram-FHFEXIEX-Bv1NW2F1.js} +1 -1
  158. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BGUCxPmp.js +1 -0
  159. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-CLRWWipW.js → timeline-definition-GMOUNBTQ-ClGYAsr0.js} +1 -1
  160. package/payload/server/public/assets/treeView-SZITEDCU-CWxofUbI.js +1 -0
  161. package/payload/server/public/assets/treemap-W4RFUUIX-Cfgb_ZG0.js +1 -0
  162. package/payload/server/public/assets/{useSelectionMode-6fff2UIV.js → useSelectionMode-lrH0qwAR.js} +1 -1
  163. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-ByFoQMek.js → vennDiagram-DHZGUBPP-C2wTcxQT.js} +1 -1
  164. package/payload/server/public/assets/wardley-RL74JXVD-B45olYjj.js +1 -0
  165. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DIkXRSha.js → wardleyDiagram-NUSXRM2D-D86-ivEx.js} +1 -1
  166. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BNdEcN73.js → xychartDiagram-5P7HB3ND-Ba5WAN8P.js} +1 -1
  167. package/payload/server/public/browser.html +6 -6
  168. package/payload/server/public/chat.html +9 -8
  169. package/payload/server/public/data.html +5 -5
  170. package/payload/server/public/graph.html +8 -8
  171. package/payload/server/public/index.html +9 -9
  172. package/payload/server/public/operator.html +9 -9
  173. package/payload/server/public/public.html +7 -6
  174. package/payload/server/server.js +164 -124
  175. package/payload/server/public/assets/AdminShell-Eo1RXZxq.js +0 -1
  176. package/payload/server/public/assets/admin-ORJGvOqo.js +0 -1
  177. package/payload/server/public/assets/architecture-YZFGNWBL-CQHotPO2.js +0 -1
  178. package/payload/server/public/assets/audio-attachment-mime-CFRERhV0.js +0 -1
  179. package/payload/server/public/assets/channel-DfO_IgSU.js +0 -1
  180. package/payload/server/public/assets/chat-DIrzZjdO.js +0 -1
  181. package/payload/server/public/assets/chunk-336JU56O-DHUrM3QG.js +0 -2
  182. package/payload/server/public/assets/chunk-426QAEUC-CBo-Lx7X.js +0 -1
  183. package/payload/server/public/assets/chunk-QZHKN3VN-CNlL2tiW.js +0 -1
  184. package/payload/server/public/assets/classDiagram-6PBFFD2Q-Bo-iLGpk.js +0 -1
  185. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Bz7DNpvQ.js +0 -1
  186. package/payload/server/public/assets/clone-Bh_bM_44.js +0 -1
  187. package/payload/server/public/assets/gitGraph-7Q5UKJZL-Ds2hoRX4.js +0 -1
  188. package/payload/server/public/assets/info-OMHHGYJF-BuX4gDTt.js +0 -1
  189. package/payload/server/public/assets/infoDiagram-42DDH7IO-pcFw8-8F.js +0 -2
  190. package/payload/server/public/assets/jsx-runtime-BjFkEGXb.css +0 -1
  191. package/payload/server/public/assets/mermaid-parser.core-DFxv-h16.js +0 -4
  192. package/payload/server/public/assets/mermaid.core-Be34BFtA.js +0 -11
  193. package/payload/server/public/assets/operator-DyLRFmNE.js +0 -1
  194. package/payload/server/public/assets/packet-4T2RLAQJ-9qQ2zAJ3.js +0 -1
  195. package/payload/server/public/assets/page-CFgywgGE.js +0 -1
  196. package/payload/server/public/assets/pie-ZZUOXDRM-aDbmozld.js +0 -1
  197. package/payload/server/public/assets/public-_pD6yEQ6.js +0 -35
  198. package/payload/server/public/assets/radar-PYXPWWZC-CEm-iLey.js +0 -1
  199. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DHGLsXgi.js +0 -1
  200. package/payload/server/public/assets/treeView-SZITEDCU-DYa2gPJa.js +0 -1
  201. package/payload/server/public/assets/treemap-W4RFUUIX-D816ED1y.js +0 -1
  202. package/payload/server/public/assets/wardley-RL74JXVD-BniDWDlr.js +0 -1
  203. /package/payload/server/public/assets/{_baseFor-SRtUHe7G.js → _baseFor-brRjpUOX.js} +0 -0
  204. /package/payload/server/public/assets/{array-BpsnM-Py.js → array-BGFCBI0e.js} +0 -0
  205. /package/payload/server/public/assets/{cytoscape.esm-D4Rl1H5h.js → cytoscape.esm-TvRJ2tGX.js} +0 -0
  206. /package/payload/server/public/assets/{defaultLocale-C7sQPl-O.js → defaultLocale-CRZydyG6.js} +0 -0
  207. /package/payload/server/public/assets/{dist-BXJR8AkG.js → dist-Dbh7HrZX.js} +0 -0
  208. /package/payload/server/public/assets/{init-BydxaDEV.js → init-B8gtcn7T.js} +0 -0
  209. /package/payload/server/public/assets/{jsx-runtime-B54kfC3e.js → jsx-runtime-CMu8uN0-.js} +0 -0
  210. /package/payload/server/public/assets/{katex-B0fVeDx4.js → katex-RxgSu_dy.js} +0 -0
  211. /package/payload/server/public/assets/{path-jlWYQ2i9.js → path-DZF-JdEe.js} +0 -0
  212. /package/payload/server/public/assets/{rough.esm-c4PR5shF.js → rough.esm-6CnTHTkH.js} +0 -0
  213. /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
- const REPO_ROOT = join(SCRIPT_DIR, '..', '..')
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} operator-visible (Task NNN) citation(s) found:`)
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(` ${leak.file}:${leak.line}: ${leak.content}`)
149
+ console.error(`[task-id-leak] file=${leak.file} line=${leak.line} match=${leak.content}`)
104
150
  }
105
151
  console.error('')
106
- console.error('Citations belong in inline comments only, never in operator-visible strings')
107
- console.error('(stderr/stdout, log files surfaced via logs-read.sh, systemd unit')
108
- console.error('--description=, error messages, console.log/warn/error, throw new 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
- # Liveness check: query the service unit state, not a recorded PID.
64
- # The service is owned by user-systemd, fully outside the brand service's cgroup.
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
- SERVICE_PID=$(systemctl --user show "$SERVICE_UNIT" --property=MainPID --value 2>/dev/null || echo "unknown")
67
- log "Tunnel already running (service $SERVICE_UNIT active, MainPID $SERVICE_PID) skipping resume"
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