@rubytech/create-maxy-code 0.1.280 → 0.1.282

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts +31 -43
  3. package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/mcp-spawn-tee/dist/index.js +112 -85
  5. package/payload/platform/lib/mcp-spawn-tee/dist/index.js.map +1 -1
  6. package/payload/platform/lib/mcp-spawn-tee/src/__tests__/spawn-tee.test.ts +111 -0
  7. package/payload/platform/lib/mcp-spawn-tee/src/index.ts +113 -84
  8. package/payload/platform/lib/mcp-spawn-tee/tsconfig.json +2 -1
  9. package/payload/platform/plugins/admin/PLUGIN.md +2 -1
  10. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-compliance.test.sh +154 -0
  11. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-directive.test.sh +24 -0
  12. package/payload/platform/plugins/admin/hooks/prompt-optimiser-compliance.sh +174 -0
  13. package/payload/platform/plugins/admin/hooks/prompt-optimiser-directive.sh +22 -2
  14. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4 -2
  15. package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +378 -56
  16. package/payload/platform/plugins/cloudflare/references/api.md +35 -1
  17. package/payload/platform/plugins/cloudflare/references/d1-data-capture.md +2 -0
  18. package/payload/platform/plugins/docs/references/cloudflare.md +1 -1
  19. package/payload/platform/plugins/docs/references/platform.md +2 -0
  20. package/payload/platform/plugins/email/PLUGIN.md +1 -1
  21. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.d.ts +2 -0
  22. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.d.ts.map +1 -0
  23. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.js +92 -0
  24. package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.js.map +1 -0
  25. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.d.ts +2 -0
  26. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.d.ts.map +1 -0
  27. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js +55 -0
  28. package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js.map +1 -0
  29. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.d.ts +2 -0
  30. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.d.ts.map +1 -0
  31. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.js +110 -0
  32. package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.js.map +1 -0
  33. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.d.ts +2 -0
  34. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.d.ts.map +1 -0
  35. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.js +57 -0
  36. package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.js.map +1 -0
  37. package/payload/platform/plugins/email/mcp/dist/index.js +8 -1
  38. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  39. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts +12 -0
  40. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts.map +1 -1
  41. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js +44 -5
  42. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js.map +1 -1
  43. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +13 -8
  44. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  45. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +26 -15
  46. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  47. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts +8 -0
  48. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts.map +1 -1
  49. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js.map +1 -1
  50. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts +16 -5
  51. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts.map +1 -1
  52. package/payload/platform/plugins/email/mcp/dist/lib/providers.js +120 -13
  53. package/payload/platform/plugins/email/mcp/dist/lib/providers.js.map +1 -1
  54. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js +3 -3
  55. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js.map +1 -1
  56. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts.map +1 -1
  57. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js +6 -2
  58. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js.map +1 -1
  59. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
  60. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +5 -3
  61. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
  62. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
  63. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +6 -3
  64. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
  65. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
  66. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +22 -4
  67. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
  68. package/payload/platform/plugins/email/mcp/package.json +4 -2
  69. package/payload/platform/plugins/email/mcp/vitest.config.ts +9 -0
  70. package/payload/platform/plugins/email/references/email-reference.md +22 -5
  71. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +1 -1
  72. package/payload/platform/plugins/graph/PLUGIN.md +2 -0
  73. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.d.ts +2 -0
  74. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.d.ts.map +1 -0
  75. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.js +31 -0
  76. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.js.map +1 -0
  77. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts +5 -0
  78. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts.map +1 -1
  79. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js +21 -2
  80. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js.map +1 -1
  81. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +1 -0
  82. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +5 -5
  83. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -1
  84. package/payload/platform/plugins/whatsapp/.claude-plugin/plugin.json +1 -1
  85. package/payload/platform/plugins/whatsapp/PLUGIN.md +7 -11
  86. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +10 -56
  87. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  88. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +26 -2
  89. package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +9 -14
  90. package/payload/platform/scripts/setup-account.sh +7 -0
  91. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  92. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +0 -2
  93. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  94. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  95. package/payload/platform/services/claude-session-manager/dist/http-server.js +63 -3
  96. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  97. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  98. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +7 -1
  99. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  100. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +6 -0
  101. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  102. package/payload/platform/services/whatsapp-channel/dist/notification.js +14 -0
  103. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  104. package/payload/platform/services/whatsapp-channel/dist/server.js +5 -3
  105. package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
  106. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  107. package/payload/server/public/assets/AdminShell-FO766lOW.js +1 -0
  108. package/payload/server/public/assets/{Checkbox-2reCESkb.js → Checkbox-syHoU9nY.js} +1 -1
  109. package/payload/server/public/assets/{admin-BpnsTEa3.js → admin-0_VxffD5.js} +1 -1
  110. package/payload/server/public/assets/{arc-BgelqC_3.js → arc-BW1WhwmV.js} +1 -1
  111. package/payload/server/public/assets/architecture-YZFGNWBL-xHbVjatf.js +1 -0
  112. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-BabnAZJm.js → architectureDiagram-Q4EWVU46-DsionCio.js} +1 -1
  113. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BJzZqNsy.js → blockDiagram-DXYQGD6D-NOG5yVZk.js} +1 -1
  114. package/payload/server/public/assets/{browser-fgBRZ5gK.js → browser-Cxjkhtsk.js} +1 -1
  115. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-By-xuh9F.js → c4Diagram-AHTNJAMY-DwFV1k9I.js} +1 -1
  116. package/payload/server/public/assets/channel-D8Go_zJk.js +1 -0
  117. package/payload/server/public/assets/{chunk-2KRD3SAO-Gj2dSpBl.js → chunk-2KRD3SAO-CKn-bEkI.js} +1 -1
  118. package/payload/server/public/assets/{chunk-336JU56O-2PXVPCUA.js → chunk-336JU56O-iJ4ISPCi.js} +2 -2
  119. package/payload/server/public/assets/chunk-426QAEUC-sWe0Iexz.js +1 -0
  120. package/payload/server/public/assets/{chunk-4BX2VUAB-9XIBlnC2.js → chunk-4BX2VUAB-B2mSmC97.js} +1 -1
  121. package/payload/server/public/assets/{chunk-4TB4RGXK-Cr3mXPnI.js → chunk-4TB4RGXK-kKNYi2_i.js} +1 -1
  122. package/payload/server/public/assets/{chunk-55IACEB6-Ccg46J3A.js → chunk-55IACEB6-JLT9m7Hd.js} +1 -1
  123. package/payload/server/public/assets/{chunk-5FUZZQ4R-Cz9MvPKc.js → chunk-5FUZZQ4R-Car3r0he.js} +1 -1
  124. package/payload/server/public/assets/{chunk-5PVQY5BW-BleOdlgO.js → chunk-5PVQY5BW-DR9EfLvj.js} +1 -1
  125. package/payload/server/public/assets/{chunk-67CJDMHE-CyCYCQWy.js → chunk-67CJDMHE-CCdP3Pdx.js} +1 -1
  126. package/payload/server/public/assets/{chunk-7N4EOEYR-KpT3uHzH.js → chunk-7N4EOEYR-bXgVzdM9.js} +1 -1
  127. package/payload/server/public/assets/{chunk-AA7GKIK3-BfOzbuxq.js → chunk-AA7GKIK3-CYeDvY8B.js} +1 -1
  128. package/payload/server/public/assets/{chunk-BSJP7CBP-Bq0M3wlv.js → chunk-BSJP7CBP-U0Fi-Ers.js} +1 -1
  129. package/payload/server/public/assets/{chunk-CIAEETIT-CR-2dNaL.js → chunk-CIAEETIT-C8QrV6Gg.js} +1 -1
  130. package/payload/server/public/assets/{chunk-EDXVE4YY-egUGMTOS.js → chunk-EDXVE4YY-DLUWVRZV.js} +1 -1
  131. package/payload/server/public/assets/{chunk-ENJZ2VHE-CQohBEFw.js → chunk-ENJZ2VHE-B4bNJo6C.js} +1 -1
  132. package/payload/server/public/assets/{chunk-FMBD7UC4-DIxBUbLP.js → chunk-FMBD7UC4-DxAQS3UB.js} +1 -1
  133. package/payload/server/public/assets/{chunk-FOC6F5B3-C2694Zoq.js → chunk-FOC6F5B3-CyIK3zeY.js} +1 -1
  134. package/payload/server/public/assets/{chunk-ICPOFSXX-DpXZKHyn.js → chunk-ICPOFSXX-Qzl8Ki0l.js} +2 -2
  135. package/payload/server/public/assets/{chunk-K5T4RW27-CUicG0Rp.js → chunk-K5T4RW27-7GcDzjyJ.js} +1 -1
  136. package/payload/server/public/assets/{chunk-KGLVRYIC-B5mPJhOr.js → chunk-KGLVRYIC-B7pAr9hf.js} +1 -1
  137. package/payload/server/public/assets/{chunk-LIHQZDEY-q81QhuMs.js → chunk-LIHQZDEY-DEoU2jrz.js} +1 -1
  138. package/payload/server/public/assets/{chunk-ORNJ4GCN-DgurdFZs.js → chunk-ORNJ4GCN-BwMFuN24.js} +1 -1
  139. package/payload/server/public/assets/{chunk-OYMX7WX6-CxqMRu2d.js → chunk-OYMX7WX6-BenBO6O_.js} +1 -1
  140. package/payload/server/public/assets/chunk-QZHKN3VN-CHE_iZO7.js +1 -0
  141. package/payload/server/public/assets/{chunk-U2HBQHQK-BSLctJC9.js → chunk-U2HBQHQK-DewM8R0D.js} +1 -1
  142. package/payload/server/public/assets/{chunk-X2U36JSP--0AUeeFl.js → chunk-X2U36JSP-C22Q6Ea4.js} +1 -1
  143. package/payload/server/public/assets/{chunk-XPW4576I-D-hf9Bcn.js → chunk-XPW4576I-BA0a8Ygs.js} +1 -1
  144. package/payload/server/public/assets/{chunk-YZCP3GAM-PvOhSwI9.js → chunk-YZCP3GAM-DfUUNTnA.js} +1 -1
  145. package/payload/server/public/assets/{chunk-ZZ45TVLE-1zPUlNWz.js → chunk-ZZ45TVLE-CUT6zma2.js} +1 -1
  146. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BLb1mzrT.js +1 -0
  147. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Ctj5qYTS.js +1 -0
  148. package/payload/server/public/assets/clone-DGZ2vydA.js +1 -0
  149. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Cvo-gkBd.js → cose-bilkent-S5V4N54A-Df_JmB8E.js} +1 -1
  150. package/payload/server/public/assets/{dagre-CMHsNfjP.js → dagre-CYXRIdv0.js} +1 -1
  151. package/payload/server/public/assets/{dagre-KV5264BT-CM1DSx4E.js → dagre-KV5264BT-D4EGb60h.js} +1 -1
  152. package/payload/server/public/assets/{data-Cuynp6Y6.js → data-BOgwOWnw.js} +1 -1
  153. package/payload/server/public/assets/{diagram-5BDNPKRD-VDHiHwEI.js → diagram-5BDNPKRD-BzieCEfT.js} +1 -1
  154. package/payload/server/public/assets/{diagram-G4DWMVQ6-OKdufoeW.js → diagram-G4DWMVQ6-DDbO71XD.js} +1 -1
  155. package/payload/server/public/assets/{diagram-MMDJMWI5-Yg6QdCA1.js → diagram-MMDJMWI5-DqQ_UXDA.js} +1 -1
  156. package/payload/server/public/assets/{diagram-TYMM5635-CpEMZQDu.js → diagram-TYMM5635-CFyxA1aZ.js} +1 -1
  157. package/payload/server/public/assets/{dist-811BIK0R.js → dist-BmvZ8OaX.js} +1 -1
  158. package/payload/server/public/assets/{erDiagram-SMLLAGMA-Dw5gAkFM.js → erDiagram-SMLLAGMA-BMaEBbOK.js} +1 -1
  159. package/payload/server/public/assets/{flatten-BsWEYbBB.js → flatten-Bo6YRmWl.js} +1 -1
  160. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-Cy_R1XHz.js → flowDiagram-DWJPFMVM-De5ChZQP.js} +1 -1
  161. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BYARP_eH.js → ganttDiagram-T4ZO3ILL-CXEMPVaK.js} +1 -1
  162. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CmHdoS27.js +1 -0
  163. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BGOe0unY.js → gitGraphDiagram-UUTBAWPF-OZedr_6y.js} +1 -1
  164. package/payload/server/public/assets/{graph-Ddg24bjy.js → graph-BqD2GjQd.js} +2 -2
  165. package/payload/server/public/assets/{graph-labels-eOrWYy0R.js → graph-labels-DSDTSBfM.js} +1 -1
  166. package/payload/server/public/assets/{graphlib-DaefxCga.js → graphlib-CN4nhD2U.js} +1 -1
  167. package/payload/server/public/assets/info-OMHHGYJF-DTA9msO-.js +1 -0
  168. package/payload/server/public/assets/infoDiagram-42DDH7IO-CSqg4nRL.js +2 -0
  169. package/payload/server/public/assets/{isEmpty-BWl67LAZ.js → isEmpty-D6Kr-M1M.js} +1 -1
  170. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-YrGuzpiI.js → ishikawaDiagram-UXIWVN3A-ChlzrZyx.js} +1 -1
  171. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-EIykOcqg.js → journeyDiagram-VCZTEJTY-DsrK55ZO.js} +1 -1
  172. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BR0TC6Je.js → kanban-definition-6JOO6SKY-DYF-_Rym.js} +1 -1
  173. package/payload/server/public/assets/{line-DPGcT5IM.js → line-3zmwI8XK.js} +1 -1
  174. package/payload/server/public/assets/{linear-CPN03uSh.js → linear-COm19-p7.js} +1 -1
  175. package/payload/server/public/assets/{mermaid-parser.core-D7Iu4c9M.js → mermaid-parser.core-BrcX8-cl.js} +2 -2
  176. package/payload/server/public/assets/{mermaid.core-krXRpXn9.js → mermaid.core-CBdz3b1N.js} +3 -3
  177. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-HwiCtPzN.js → mindmap-definition-QFDTVHPH-BqCqlYZb.js} +1 -1
  178. package/payload/server/public/assets/{ordinal-krseTxxN.js → ordinal-BDi6f4xk.js} +1 -1
  179. package/payload/server/public/assets/packet-4T2RLAQJ-6GjqIKgu.js +1 -0
  180. package/payload/server/public/assets/pie-ZZUOXDRM-T72DJ5JR.js +1 -0
  181. package/payload/server/public/assets/{pieDiagram-DEJITSTG-xodxyWLe.js → pieDiagram-DEJITSTG-D5LiILuM.js} +1 -1
  182. package/payload/server/public/assets/{public-xVaPcg6i.js → public-udi_Z7la.js} +3 -3
  183. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-DuYYY4ZZ.js → quadrantDiagram-34T5L4WZ-C3iuI5l_.js} +1 -1
  184. package/payload/server/public/assets/radar-PYXPWWZC-x-6xW1dE.js +1 -0
  185. package/payload/server/public/assets/{reduce-tk-xY6Fv.js → reduce-CGi9ik8i.js} +1 -1
  186. package/payload/server/public/assets/{requirementDiagram-MS252O5E-D0ta3kru.js → requirementDiagram-MS252O5E-CTPOw5qQ.js} +1 -1
  187. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-KdHdlzvT.js → sankeyDiagram-XADWPNL6-D_5aVlYp.js} +1 -1
  188. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DoSFUTQZ.js → sequenceDiagram-FGHM5R23-D7h5vocM.js} +1 -1
  189. package/payload/server/public/assets/{src-Cpl1JzME.js → src-DLEIsjER.js} +1 -1
  190. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-BLW0KiSA.js → stateDiagram-FHFEXIEX-DyZjuwPj.js} +1 -1
  191. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BiW9pGXy.js +1 -0
  192. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-8QAzhYz1.js → timeline-definition-GMOUNBTQ-BqpVYJz_.js} +1 -1
  193. package/payload/server/public/assets/treeView-SZITEDCU-5-6wEryJ.js +1 -0
  194. package/payload/server/public/assets/treemap-W4RFUUIX-DF48Cc86.js +1 -0
  195. package/payload/server/public/assets/{useSelectionMode-DlJsX-_X.js → useSelectionMode-BPzPjKP_.js} +1 -1
  196. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BKvfScOi.js → vennDiagram-DHZGUBPP-Czflml0e.js} +1 -1
  197. package/payload/server/public/assets/wardley-RL74JXVD-duKIa6Hq.js +1 -0
  198. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DaMfDpJ3.js → wardleyDiagram-NUSXRM2D-Cqz3pSTK.js} +1 -1
  199. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BIkNQlLa.js → xychartDiagram-5P7HB3ND-CS5dEuUO.js} +1 -1
  200. package/payload/server/public/browser.html +4 -4
  201. package/payload/server/public/data.html +5 -5
  202. package/payload/server/public/graph.html +6 -6
  203. package/payload/server/public/index.html +5 -5
  204. package/payload/server/public/public.html +4 -4
  205. package/payload/server/server.js +74 -275
  206. package/payload/server/public/assets/AdminShell-C6_5h1cC.js +0 -1
  207. package/payload/server/public/assets/architecture-YZFGNWBL-YM-TtgPY.js +0 -1
  208. package/payload/server/public/assets/channel-BRPH0atd.js +0 -1
  209. package/payload/server/public/assets/chunk-426QAEUC-QhauxjvK.js +0 -1
  210. package/payload/server/public/assets/chunk-QZHKN3VN-BDAQvtxz.js +0 -1
  211. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BJv89PB6.js +0 -1
  212. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DNUszH5M.js +0 -1
  213. package/payload/server/public/assets/clone-CREg9jLM.js +0 -1
  214. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CtOPqykB.js +0 -1
  215. package/payload/server/public/assets/info-OMHHGYJF-Jba5enA8.js +0 -1
  216. package/payload/server/public/assets/infoDiagram-42DDH7IO-Df9BlkPA.js +0 -2
  217. package/payload/server/public/assets/packet-4T2RLAQJ-D_eWzeAP.js +0 -1
  218. package/payload/server/public/assets/pie-ZZUOXDRM-BDiy1Ob2.js +0 -1
  219. package/payload/server/public/assets/radar-PYXPWWZC-C5mlfmtg.js +0 -1
  220. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-C5zlCV4X.js +0 -1
  221. package/payload/server/public/assets/treeView-SZITEDCU-CM-9m-cS.js +0 -1
  222. package/payload/server/public/assets/treemap-W4RFUUIX-DDHPB-Xh.js +0 -1
  223. package/payload/server/public/assets/wardley-RL74JXVD-CUb3Br4q.js +0 -1
  224. package/payload/server/public/assets/whatsapp-BE79pNh8.js +0 -1
  225. package/payload/server/public/whatsapp.html +0 -18
  226. /package/payload/server/public/assets/{_baseFor-BHtDrjIo.js → _baseFor-Cam2PbSt.js} +0 -0
  227. /package/payload/server/public/assets/{array-DetWRiSa.js → array-DYRGGQae.js} +0 -0
  228. /package/payload/server/public/assets/{chunk-CWOGyPgy.js → chunk-CnGqDkHZ.js} +0 -0
  229. /package/payload/server/public/assets/{cytoscape.esm-C9yNhe1u.js → cytoscape.esm-nWsJMTNI.js} +0 -0
  230. /package/payload/server/public/assets/{defaultLocale-_WRwicXn.js → defaultLocale-Du1XY3Dp.js} +0 -0
  231. /package/payload/server/public/assets/{init-sTEcj9YX.js → init-B5BXBRcm.js} +0 -0
  232. /package/payload/server/public/assets/{katex-s61Rgv6l.js → katex-HOUACuRw.js} +0 -0
  233. /package/payload/server/public/assets/{path-B0Ik7Tu9.js → path-CNO468J-.js} +0 -0
  234. /package/payload/server/public/assets/{rough.esm-DKRO8IF-.js → rough.esm-DRO6hWPh.js} +0 -0
@@ -1,53 +1,41 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * MCP spawn-tee — parent-side stderr capture wrapper.
3
+ * MCP spawn-tee — parent-side stderr capture + lifecycle observability.
4
4
  *
5
- * Claude Code's `--mcp-config` accepts `{command, args, env}` descriptors and
6
- * spawns each MCP server itself; the platform never holds a ChildProcess
7
- * handle. The in-process `mcp-stderr-tee` patches `process.stderr.write` from
8
- * inside the MCP server, but its writes go through `createWriteStream`
9
- * async, buffered. A synchronous module-load throw (e.g. schema-loader's
10
- * line-168 width check on memory) calls `process.exit(1)` before the buffer
11
- * flushes, so the per-server log file is empty and the platform's
12
- * `[mcp-init-error] tail="(no stderr file)"` probe is operationally useless.
13
- * That class shipped as the chronic memory-MCP silent-fail loop fixed by
14
- * (and hit graph — solved there with per-plugin
15
- * `appendFileSync` discipline that this wrapper now generalises).
5
+ * Claude Code spawns each MCP server itself; the platform never holds a
6
+ * ChildProcess handle. This wrapper sits between Claude Code and the real
7
+ * MCP server: Claude Code runs `node <this> <real-entry>`, and the wrapper
8
+ * spawns the real entry with `stdio:['inherit','inherit','pipe']` so stdin
9
+ * and stdout (the JSON-RPC channel) pass through byte-identical. Only stderr
10
+ * is intercepted, and only for logging.
16
11
  *
17
- * The wrapper sits between Claude Code and the real MCP server: it spawns
18
- * the real entry with `stdio: ['inherit', 'inherit', 'pipe']`, then
19
- * synchronously appends every child stderr chunk to
20
- * `${LOG_DIR}/mcp-${name}-stderr-<date>.log`. Synchronous writes survive
21
- * `process.exit` because the kernel queues the syscall before the call
22
- * returns. The chunk is also written to the wrapper's own stderr so
23
- * Claude Code's existing stderr consumer is unchanged — the mechanism is
24
- * additive, not interceptive.
12
+ * Because the wrapper IS the helper's parent, it observes the helper's true
13
+ * exit code, signal, and lifetime for every death mode — including a SIGKILL
14
+ * or a transport-layer crash that an in-process handler would miss.
25
15
  *
26
- * Claude Code CLI
27
- * spawns
28
- *
29
- * wrapper (this file) — argv[2] = real entry, env.MCP_SPAWN_TEE_NAME = name
30
- * │ spawns child with stdio:['inherit','inherit','pipe']
31
- * ▼
32
- * child = node <real-entry>
33
- * │
34
- * ├──▶ stdin/stdout: inherited from wrapper (Claude Code pipe)
35
- * └──▶ stderr → wrapper.on('data', chunk =>)
36
- * ├──▶ appendFileSync(${LOG_DIR}/mcp-${name}-stderr-<date>.log)
37
- * └──▶ process.stderr.write(chunk) → Claude Code consumer
16
+ * Claude Code CLI → wrapper (this file) → child = node <real-entry>
17
+ * child stdin/stdout : inherited (Claude Code pipe, untouched)
18
+ * child stderr : piped → per-date log + per-session log + passthrough
38
19
  *
39
- * The wrapper catches:
40
- * - MODULE_NOT_FOUND on the entry script itself (success criterion #3:
41
- * `mv plugins/memory/mcp/dist plugins/memory/mcp/dist-broken && reboot`
42
- * leaves the cause on disk).
43
- * - Synchronous throws during module load before the in-process tee runs.
44
- * - Any stderr a normally-running plugin emits (steady-state telemetry
45
- * remains visible too — the in-process tee handles per-line stream-log
46
- * prefixing; this wrapper handles the raw per-server file).
20
+ * Destinations (Task 706):
21
+ * - `${LOG_DIR}/mcp-<name>-stderr-<date>.log` — per-date raw (back-compat;
22
+ * the in-process mcp-stderr-tee and the [mcp-init-error] probe read it).
23
+ * - `${LOG_DIR}/mcp-<name>-<SESSION_ID>.log` — per-session raw + lifecycle
24
+ * lines; wrapper-only, so it never mixes the enumeration copy with the
25
+ * live copy. Authoritative sink. Absent when SESSION_ID is unset
26
+ * (enumeration spawn)then the per-date file is the fallback.
27
+ * - `server.log` via the loopback log-ingest route — best-effort mirror of
28
+ * the [mcp-helper] lifecycle lines. A dropped POST loses nothing because
29
+ * the per-session file already holds the line (written synchronously).
47
30
  *
48
- * SIGTERM/SIGINT propagation: forwarded to the child so a Claude Code
49
- * shutdown does not orphan the MCP server. Child exit code is propagated
50
- * verbatim so upstream (Claude Code) sees the real outcome.
31
+ * Lifecycle lines, correlation key `session=<id8> server=<name>`:
32
+ * [mcp-helper] op=spawn ... pid= entry=
33
+ * [mcp-helper] op=boot ... head=<first stderr bytes>
34
+ * [mcp-helper] op=exit ... code= signal= lifetimeMs= stderr-tail= (always)
35
+ *
36
+ * The wrapper never writes to fd 1 (stdout) — that is the JSON-RPC channel.
37
+ * SIGTERM/SIGINT are forwarded to the child so a Claude Code shutdown does
38
+ * not orphan it; the child exit code/signal is propagated verbatim.
51
39
  */
52
40
 
53
41
  import { spawn } from "node:child_process";
@@ -56,31 +44,71 @@ import { resolve } from "node:path";
56
44
 
57
45
  const SERVER_NAME = process.env.MCP_SPAWN_TEE_NAME ?? "unknown";
58
46
  const LOG_DIR = process.env.LOG_DIR;
47
+ const SESSION_ID = process.env.SESSION_ID;
48
+ const PLATFORM_PORT = process.env.PLATFORM_PORT;
59
49
  const ENTRY = process.argv[2];
60
50
 
61
- // Sync-emit: appendFileSync to per-server log + stderr passthrough. Used for
62
- // wrapper-internal diagnostics (attach line, errors) and for forwarding child
63
- // stderr chunks. Each destination wrapped independently — an unwritable log
64
- // must not mask the primary output.
65
- function syncEmitLine(line: string): void {
66
- if (LOG_DIR) {
67
- try {
68
- mkdirSync(LOG_DIR, { recursive: true });
69
- const date = new Date().toISOString().slice(0, 10);
70
- appendFileSync(resolve(LOG_DIR, `mcp-${SERVER_NAME}-stderr-${date}.log`), line);
71
- } catch {
72
- /* unwritable destination — preserve primary failure */
73
- }
51
+ const SESSION_ID8 = SESSION_ID ? SESSION_ID.slice(0, 8) : "—";
52
+ const spawnStamp = Date.now();
53
+
54
+ // Per-session raw + lifecycle log (Task 706). Wrapper-only. Empty SESSION_ID
55
+ // (enumeration spawn) undefined, and the per-date file is the fallback.
56
+ const perSessionPath = LOG_DIR && SESSION_ID
57
+ ? resolve(LOG_DIR, `mcp-${SERVER_NAME}-${SESSION_ID}.log`)
58
+ : undefined;
59
+ const perDatePath = LOG_DIR
60
+ ? resolve(LOG_DIR, `mcp-${SERVER_NAME}-stderr-${new Date(spawnStamp).toISOString().slice(0, 10)}.log`)
61
+ : undefined;
62
+
63
+ // Rolling tail of child stderr for op=exit. Capped so a chatty child cannot
64
+ // grow the buffer without bound.
65
+ const TAIL_CAP = 2048;
66
+ let stderrTail = "";
67
+ let bootEmitted = false;
68
+
69
+ function appendSafe(path: string | undefined, data: string | Uint8Array): void {
70
+ if (!path || !LOG_DIR) return;
71
+ try {
72
+ mkdirSync(LOG_DIR, { recursive: true });
73
+ appendFileSync(path, data);
74
+ } catch {
75
+ /* unwritable destination — never mask primary output */
74
76
  }
77
+ }
78
+
79
+ // Best-effort mirror of a lifecycle line to server.log via the loopback
80
+ // log-ingest route. Fire-and-forget: the per-session file is authoritative,
81
+ // so a dropped POST (unreachable port, process exiting) loses nothing.
82
+ function postToServerLog(suffix: string, level: "info" | "error"): void {
83
+ if (!PLATFORM_PORT) return;
75
84
  try {
76
- process.stderr.write(line);
85
+ const ctrl = new AbortController();
86
+ const t = setTimeout(() => ctrl.abort(), 500);
87
+ t.unref?.(); // never let the abort timer keep the wrapper's event loop alive
88
+ void fetch(`http://127.0.0.1:${PLATFORM_PORT}/api/admin/log-ingest`, {
89
+ method: "POST",
90
+ headers: { "content-type": "application/json" },
91
+ body: JSON.stringify({ tag: "mcp-helper", level, line: suffix }),
92
+ signal: ctrl.signal,
93
+ }).then(() => clearTimeout(t)).catch(() => clearTimeout(t));
77
94
  } catch {
78
- /* stderr closednothing else to do */
95
+ /* fetch threw synchronously best-effort only */
79
96
  }
80
97
  }
81
98
 
99
+ // Emit one [mcp-helper] lifecycle line: authoritative per-session file (sync,
100
+ // survives process.exit), the wrapper's own stderr (journald / Claude Code
101
+ // visibility), and a best-effort server.log mirror. `suffix` is the line body
102
+ // after the tag and carries no newline (the log-ingest route rejects newlines).
103
+ function emitLifecycle(suffix: string, level: "info" | "error"): void {
104
+ const line = `[mcp-helper] ${suffix}\n`;
105
+ appendSafe(perSessionPath, line);
106
+ try { process.stderr.write(line); } catch { /* stderr closed */ }
107
+ postToServerLog(suffix, level);
108
+ }
109
+
82
110
  if (!ENTRY) {
83
- syncEmitLine(`[mcp-spawn-tee-error] server=${SERVER_NAME} reason="no entry given (argv[2] missing)"\n`);
111
+ emitLifecycle(`op=error session=${SESSION_ID8} server=${SERVER_NAME} reason="no entry given (argv[2] missing)"`, "error");
84
112
  process.exit(2);
85
113
  }
86
114
 
@@ -89,46 +117,47 @@ const child = spawn(process.execPath, [ENTRY], {
89
117
  env: process.env,
90
118
  });
91
119
 
92
- syncEmitLine(`[mcp-spawn-tee-attached] server=${SERVER_NAME} pid=${child.pid ?? -1} entry=${ENTRY}\n`);
120
+ emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${child.pid ?? -1} entry=${ENTRY}`, "info");
93
121
 
94
122
  child.on("error", (err) => {
95
123
  const msg = err instanceof Error ? err.message : String(err);
96
- syncEmitLine(`[mcp-spawn-tee-error] server=${SERVER_NAME} reason=${JSON.stringify(`spawn error: ${msg}`)}\n`);
124
+ emitLifecycle(`op=error session=${SESSION_ID8} server=${SERVER_NAME} reason=${JSON.stringify(`spawn error: ${msg}`)}`, "error");
97
125
  process.exit(127);
98
126
  });
99
127
 
100
128
  if (child.stderr) {
101
129
  child.stderr.on("data", (chunk: Buffer) => {
102
- if (LOG_DIR) {
103
- try {
104
- const date = new Date().toISOString().slice(0, 10);
105
- appendFileSync(resolve(LOG_DIR, `mcp-${SERVER_NAME}-stderr-${date}.log`), chunk);
106
- } catch {
107
- /* unwritable destination — preserve passthrough */
108
- }
109
- }
110
- try {
111
- process.stderr.write(chunk);
112
- } catch {
113
- /* stderr closed — nothing else to do */
130
+ appendSafe(perDatePath, chunk); // per-date raw (back-compat)
131
+ appendSafe(perSessionPath, chunk); // per-session raw (Task 706)
132
+ try { process.stderr.write(chunk); } catch { /* stderr closed */ } // passthrough
133
+ stderrTail = (stderrTail + chunk.toString("utf8")).slice(-TAIL_CAP);
134
+ if (!bootEmitted) {
135
+ bootEmitted = true;
136
+ const head = chunk.toString("utf8").split("\n")[0].slice(0, 200);
137
+ emitLifecycle(`op=boot session=${SESSION_ID8} server=${SERVER_NAME} head=${JSON.stringify(head)}`, "info");
114
138
  }
115
139
  });
116
140
  }
117
141
 
118
- // Forward SIGTERM/SIGINT so Claude Code shutdown doesn't orphan the child.
119
- const forward = (signal: NodeJS.Signals) => {
120
- if (!child.killed) child.kill(signal);
121
- };
142
+ const forward = (signal: NodeJS.Signals) => { if (!child.killed) child.kill(signal); };
122
143
  process.on("SIGTERM", () => forward("SIGTERM"));
123
144
  process.on("SIGINT", () => forward("SIGINT"));
124
145
 
146
+ // Signal → number, so a signal-killed child propagates as 128+signum (the
147
+ // shell convention). `code` is null on a signal exit, so `128 + (code ?? 0)`
148
+ // would collapse every signal to 128 and lose the signal identity in the
149
+ // wrapper's own exit status.
150
+ const SIGNUM: Record<string, number> = { SIGHUP: 1, SIGINT: 2, SIGQUIT: 3, SIGKILL: 9, SIGTERM: 15 };
151
+
125
152
  child.on("exit", (code, signal) => {
126
- if (signal) {
127
- syncEmitLine(`[mcp-spawn-tee-exit] server=${SERVER_NAME} pid=${child.pid ?? -1} signal=${signal}\n`);
128
- process.exit(128 + (code ?? 0));
129
- }
130
- if (code !== 0) {
131
- syncEmitLine(`[mcp-spawn-tee-exit] server=${SERVER_NAME} pid=${child.pid ?? -1} code=${code}\n`);
132
- }
153
+ const lifetimeMs = Date.now() - spawnStamp;
154
+ const tail = stderrTail.slice(-200);
155
+ const level: "info" | "error" = signal || (code ?? 0) !== 0 ? "error" : "info";
156
+ emitLifecycle(
157
+ `op=exit session=${SESSION_ID8} server=${SERVER_NAME} pid=${child.pid ?? -1} ` +
158
+ `code=${code ?? "—"} signal=${signal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`,
159
+ level,
160
+ );
161
+ if (signal) process.exit(128 + (SIGNUM[signal] ?? 0));
133
162
  process.exit(code ?? 0);
134
163
  });
@@ -4,5 +4,6 @@
4
4
  "outDir": "dist",
5
5
  "rootDir": "src"
6
6
  },
7
- "include": ["src"]
7
+ "include": ["src"],
8
+ "exclude": ["src/__tests__"]
8
9
  }
@@ -147,7 +147,8 @@ Tools are available via the `admin` MCP server.
147
147
  - `hooks/mcp-tool-missing.sh` — **PostToolUse hook on `mcp__.*` (Task 502, directive 3).** Defence-in-depth for the `No such tool available: mcp__…` failure class that the Task 502 name-binding is built to eliminate. Fires on any MCP tool call; no-op unless the `tool_response` carries `No such tool available` AND the qualified name resolves to a maxy plugin (read from the generated `hooks/lib/maxy-mcp-plugins.txt`). On a maxy match it logs one deterministic `[mcp-tool-missing] server=<server> tool=<tool>` line and exits 2 with a fixed envelope on stderr, so the agent relays a named server-unavailable failure instead of narrating "warming up" or blind-retrying. A missing non-maxy bridge tool (Playwright etc., upstream-owned) passes through (exit 0). The maxy-plugin list is regenerated and gate-diffed by `platform/scripts/check-canonical-tool-names.mjs`.
148
148
  - `hooks/post-tool-use-agent.sh` — **PostToolUse hook on `Agent` (Task 560).** Drains any subagent hook-decision buffers under `~/.maxy-code/logs/hook-decisions/` modified since this parent's previous PostToolUse-Agent fire (cursor file keyed by parent session id), prints one `[hook-propagate]` line per record to stdout — Claude Code attaches the stdout as a `hook_success` attachment on the parent JSONL, making the records grep-queryable from the parent session alone (Task 559 motivating case). Rotates consumed buffers to `consumed/`. Emits one `[hook-propagate-census] parentSession=<…> subagentHooksObserved=<N> attachmentsEmitted=<M>` line per fire to stdout and server.log; `N != M` is the propagation regression signal. The companion emitter library `hooks/lib/hook-emit.sh` is sourced by `post-tool-use-agent.sh` and any other hook that records a block decision (4 KB stderr truncation, `truncated=true` set on the record).
149
149
  - `hooks/admin-authoring-observer.sh` — **PostToolUse hook on Write and Edit (Task 486).** Observation only — never blocks; exits 0 on every path. Fires when the admin agent (not a specialist subagent — gated by `MAXY_SPECIALIST` env) writes or edits a file under `<accountDir>/output/`. Walks the session transcript from the latest real-user turn forward to detect any prior `Task` `tool_use` whose `subagent_type` starts with `specialists:`. Emits one stderr line `[admin-authoring] inline-write path=<rel> priorSpecialistSpawnInTurn=<true|false|unknown>`. A `false` value on a long-form prose file is the regression signal Task 486 was designed to make visible — the BioSymm proposal session (admin authored a customer-facing proposal inline despite content-producer being installed) is the failure mode this surfaces mechanically. Mechanical enforcement (refuse the write, force a re-spawn) is deferred per the task spec.
150
- - `hooks/prompt-optimiser-directive.sh` — **UserPromptSubmit hook (Task 698).** Injects the standing prompt-optimiser restatement directive plus the per-turn three-tier routing ladder as `additionalContext`: **(1)** delegate to the specialist that owns the deliverable via the Agent tool — the brief states the outcome plus binding constraints, never lines/anchors/literal text; **(2)** only if none fits, load an admin-usable skill with `skill-load`; **(3)** only if neither fits, author inline — freestyle is the named last resort. Re-emits the full agent roster (`agents/admin/AGENTS.md`) and the full admin-usable skills list (`agents/admin/ADMIN-SKILLS.md`) every turn by reading the two generated files from the account dir (the hook fires with the account dir as cwd); it never walks the plugins tree per turn. Fail-open is **visible**: a missing list logs `[prompt-optimiser] missing=<AGENTS.md\|ADMIN-SKILLS.md> emitting-partial` to stderr and the ladder still injects. The trivial-turn skip (one-word confirmation, slash-command, direct continuation) is unchanged. **Staleness:** `ADMIN-SKILLS.md` is regenerated only by `setup-account.sh`; a plugin add/remove since the last setup leaves the list stale — compare `ADMIN-SKILLS.md` mtime against the newest `SKILL.md` mtime and re-run setup to refresh. The list generator is `platform/scripts/lib/admin-skills-bootstrap.sh`; it logs `[admin-skills] scanned=<N> admin-usable=<M> no-declaration=<K>` (failure signature: `admin-usable=0` while `scanned>0`, or any `missing-declaration` line).
150
+ - `hooks/prompt-optimiser-directive.sh` — **UserPromptSubmit hook (Task 698).** Injects the standing prompt-optimiser restatement directive plus the per-turn three-tier routing ladder as `additionalContext`: **(1)** delegate to the specialist that owns the deliverable via the Agent tool — the brief states the outcome plus binding constraints, never lines/anchors/literal text; **(2)** only if none fits, load an admin-usable skill with `skill-load`; **(3)** only if neither fits, author inline — freestyle is the named last resort. Re-emits the full agent roster (`agents/admin/AGENTS.md`) and the full admin-usable skills list (`agents/admin/ADMIN-SKILLS.md`) every turn by reading the two generated files from the account dir (the hook fires with the account dir as cwd); it never walks the plugins tree per turn. Fail-open is **visible**: a missing list logs `[prompt-optimiser] missing=<AGENTS.md\|ADMIN-SKILLS.md> emitting-partial` to stderr and the ladder still injects. The trivial-turn skip (one-word confirmation, slash-command, direct continuation) is unchanged. **Staleness:** `ADMIN-SKILLS.md` is regenerated only by `setup-account.sh`; a plugin add/remove since the last setup leaves the list stale — compare `ADMIN-SKILLS.md` mtime against the newest `SKILL.md` mtime and re-run setup to refresh. The list generator is `platform/scripts/lib/admin-skills-bootstrap.sh`; it logs `[admin-skills] scanned=<N> admin-usable=<M> no-declaration=<K>` (failure signature: `admin-usable=0` while `scanned>0`, or any `missing-declaration` line). **Task 719:** the directive now carries a standing CAPABILITY-QUESTIONS-ARE-OWNED-WORK clause (how-to / "do you have instructions for X" / config questions about platform features are answered from the owning specialist or plugin tool/reference, never from training memory), and the hook appends a durable `<ts> [prompt-optimiser-directive] injected len=<n> session=<id>` breadcrumb to `$LOG_DIR/prompt-optimiser-directive.log` so per-turn injection is greppable, not stderr-only.
151
+ - `hooks/prompt-optimiser-compliance.sh` — **Stop hook (Task 719).** After each admin turn, reads the just-finished turn from `transcript_path` and appends `<ts> [prompt-optimiser-compliance] directive-fired no-route-taken session=<id8> prompt="<clip>"` to `$LOG_DIR/prompt-optimiser-directive.log` (and stderr) when the routing directive fired, the prompt was non-trivial (not a slash-command, not a one-word confirmation), and the turn took **no route** — no `Agent` dispatch, no `Skill` load, no `ToolSearch`, no `mcp__*` tool call. This is the standing compliance signal that surfaces the session-`da0b12d4` failure class (agent answers a capability question from memory) as a visible event instead of a silent stale answer. Directive-fired is detected by the marker `PROMPT-OPTIMISER DIRECTIVE` in the turn slice, so it is robust to the CC-version difference in how `UserPromptSubmit` `additionalContext` is recorded (`attachment`/`hook_success` vs `hook_additional_context`). **Known limitation:** "direct continuation of the prior turn" is not detectable from the transcript, so a continuation turn that legitimately needs no route can be flagged; treat the log as a review signal, not a gate. **Fail-open:** no python3, no `transcript_path`, or an unreadable transcript → exit 0, no output. Lives in the same log as the directive breadcrumb, so a single `grep` interleaves "fired" and "no-route" into one per-session timeline; cross-check via `platform/scripts/logs-read.sh <sessionKey>`. This is a lightweight transcript read, not a per-turn spawn (contrast the Task-626 turn recorder below).
151
152
  - **Turn recorder — removed entirely (Task 626).** The `turn-completed-graph-write.sh` Stop hook, the `/api/admin/claude-sessions` loopback bypass it relied on, the `[turn-recorder]` emitters, the envelope walker, and the recorder-auto-archive subscriber are deleted. It had been dormant since Task 214 (never re-registered in settings.json); the admin now writes to the graph by delegating to `database-operator` via the Task tool inside the live session, and the on-demand `/insight` pass (`skills/insight/SKILL.md`, a registered admin skill — Task 641) is the per-session review. There is no per-turn spawn.
152
153
 
153
154
  ## Session identifiers (Task 135)
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env bash
2
+ # Regression test for prompt-optimiser-compliance.sh (Task 719 Stop hook).
3
+ #
4
+ # A turn is flagged "directive-fired no-route-taken" only when the directive
5
+ # marker is in the turn slice AND the prompt is non-trivial AND no Agent/Skill/
6
+ # ToolSearch/mcp__* tool_use occurred. Covers both transcript record shapes,
7
+ # every route surface, the trivial filters, and fail-open.
8
+
9
+ set -u
10
+
11
+ HOOK="$(cd "$(dirname "$0")/.." && pwd)/prompt-optimiser-compliance.sh"
12
+ if [[ ! -x "$HOOK" ]]; then
13
+ echo "FAIL: $HOOK not executable" >&2
14
+ exit 1
15
+ fi
16
+
17
+ PASS=0
18
+ FAIL=0
19
+
20
+ # Build a transcript file from JSONL lines passed as args; echo its path.
21
+ mk_transcript() {
22
+ local f; f=$(mktemp)
23
+ local line
24
+ for line in "$@"; do printf '%s\n' "$line" >> "$f"; done
25
+ printf '%s' "$f"
26
+ }
27
+
28
+ # Run the hook against a transcript; capture combined stderr (where the flag is
29
+ # echoed). $1=transcript path.
30
+ run_hook() {
31
+ printf '{"transcript_path":"%s","session_id":"sess12345678"}' "$1" | bash "$HOOK" 2>&1
32
+ }
33
+
34
+ USER_PROMPT='{"type":"user","message":{"role":"user","content":"how do I set up a Google Workspace email"}}'
35
+ # UserPromptSubmit additionalContext, CC 2.1.x attachment/hook_success shape.
36
+ DIRECTIVE_ATTACH='{"type":"attachment","attachment":{"type":"hook_success","hookEvent":"UserPromptSubmit","stdout":"{\"hookSpecificOutput\":{\"additionalContext\":\"PROMPT-OPTIMISER DIRECTIVE (standing) ...\"}}"}}'
37
+ # Pi shape.
38
+ DIRECTIVE_PI='{"type":"hook_additional_context","additionalContext":"PROMPT-OPTIMISER DIRECTIVE (standing) ..."}'
39
+ ASSISTANT_TEXT='{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"To set up Gmail, enable IMAP in settings."}]}}'
40
+ ASSISTANT_AGENT='{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Agent","input":{}}]}}'
41
+ ASSISTANT_SKILL='{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Skill","input":{}}]}}'
42
+ ASSISTANT_MCP='{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"mcp__plugin_email__email-provider-info","input":{}}]}}'
43
+ ASSISTANT_TOOLSEARCH='{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"ToolSearch","input":{}}]}}'
44
+
45
+ assert_flagged() {
46
+ local name="$1" t="$2" out
47
+ out=$(run_hook "$t")
48
+ if printf '%s' "$out" | grep -q "no-route-taken"; then
49
+ echo "PASS: $name"; PASS=$((PASS+1))
50
+ else
51
+ echo "FAIL: $name (expected flag, got: $out)" >&2; FAIL=$((FAIL+1))
52
+ fi
53
+ rm -f "$t"
54
+ }
55
+
56
+ assert_not_flagged() {
57
+ local name="$1" t="$2" out
58
+ out=$(run_hook "$t")
59
+ if printf '%s' "$out" | grep -q "no-route-taken"; then
60
+ echo "FAIL: $name (expected NO flag, got: $out)" >&2; FAIL=$((FAIL+1))
61
+ else
62
+ echo "PASS: $name"; PASS=$((PASS+1))
63
+ fi
64
+ rm -f "$t"
65
+ }
66
+
67
+ # 1. Directive fired (attachment shape) + prose only -> flagged.
68
+ assert_flagged "attachment-shape directive + no route -> flagged" \
69
+ "$(mk_transcript "$USER_PROMPT" "$DIRECTIVE_ATTACH" "$ASSISTANT_TEXT")"
70
+
71
+ # 2. Directive fired (Pi shape) + prose only -> flagged.
72
+ assert_flagged "pi-shape directive + no route -> flagged" \
73
+ "$(mk_transcript "$USER_PROMPT" "$DIRECTIVE_PI" "$ASSISTANT_TEXT")"
74
+
75
+ # 3–6. Each route surface suppresses the flag.
76
+ assert_not_flagged "Agent dispatch -> not flagged" \
77
+ "$(mk_transcript "$USER_PROMPT" "$DIRECTIVE_ATTACH" "$ASSISTANT_AGENT")"
78
+ assert_not_flagged "Skill load -> not flagged" \
79
+ "$(mk_transcript "$USER_PROMPT" "$DIRECTIVE_ATTACH" "$ASSISTANT_SKILL")"
80
+ assert_not_flagged "mcp__ tool -> not flagged" \
81
+ "$(mk_transcript "$USER_PROMPT" "$DIRECTIVE_ATTACH" "$ASSISTANT_MCP")"
82
+ assert_not_flagged "ToolSearch -> not flagged" \
83
+ "$(mk_transcript "$USER_PROMPT" "$DIRECTIVE_ATTACH" "$ASSISTANT_TOOLSEARCH")"
84
+
85
+ # 7. No directive in the slice -> not flagged.
86
+ assert_not_flagged "no directive -> not flagged" \
87
+ "$(mk_transcript "$USER_PROMPT" "$ASSISTANT_TEXT")"
88
+
89
+ # 8. Slash-command prompt -> not flagged.
90
+ assert_not_flagged "slash-command -> not flagged" \
91
+ "$(mk_transcript '{"type":"user","message":{"role":"user","content":"/insight"}}' "$DIRECTIVE_ATTACH" "$ASSISTANT_TEXT")"
92
+
93
+ # 9. One-word confirmation -> not flagged.
94
+ assert_not_flagged "one-word confirmation -> not flagged" \
95
+ "$(mk_transcript '{"type":"user","message":{"role":"user","content":"yes"}}' "$DIRECTIVE_ATTACH" "$ASSISTANT_TEXT")"
96
+
97
+ # Synthetic (isMeta) user rows that Claude Code injects AFTER the real prompt:
98
+ # a skill body and a system-reminder. The boundary must NOT land on these.
99
+ META_SKILL='{"type":"user","isMeta":true,"message":{"role":"user","content":[{"type":"text","text":"Base directory for this skill: /x/y. Follow the instructions."}]}}'
100
+ META_REMINDER='{"type":"user","isMeta":true,"message":{"role":"user","content":[{"type":"text","text":"<system-reminder>The task tools were not used recently.</system-reminder>"}]}}'
101
+ # WhatsApp/native channel inbound: isMeta:true AND channel-wrapped — this IS the prompt.
102
+ CHANNEL_PROMPT='{"type":"user","isMeta":true,"message":{"role":"user","content":"<channel source=\"whatsapp-channel\"> how do I connect a domain </channel>"}}'
103
+
104
+ # 10. Channel-wrapped non-trivial prompt (isMeta, as on the Pi) -> flagged.
105
+ assert_flagged "isMeta channel-wrapped prompt + no route -> flagged" \
106
+ "$(mk_transcript "$CHANNEL_PROMPT" "$DIRECTIVE_ATTACH" "$ASSISTANT_TEXT")"
107
+
108
+ # 10b. Real prompt followed by isMeta skill/reminder injections -> still flagged
109
+ # (boundary stays on the real prompt; the slice is not truncated). Regression for
110
+ # the boundary bug where the last text-bearing user row was a meta injection.
111
+ assert_flagged "prompt then isMeta injections + no route -> flagged (boundary holds)" \
112
+ "$(mk_transcript "$USER_PROMPT" "$DIRECTIVE_ATTACH" "$ASSISTANT_TEXT" "$META_SKILL" "$META_REMINDER")"
113
+
114
+ # 10c. A route taken before the trailing isMeta injections -> NOT flagged. Proves
115
+ # the slice still reaches the tool_use rather than stopping at the meta boundary.
116
+ assert_not_flagged "route then isMeta injections -> not flagged (slice not truncated)" \
117
+ "$(mk_transcript "$USER_PROMPT" "$DIRECTIVE_ATTACH" "$ASSISTANT_AGENT" "$META_SKILL")"
118
+
119
+ # 10d. Slash-command prompt followed by an isMeta skill body -> not flagged. The
120
+ # boundary must read the slash prompt, not the non-slash injected body.
121
+ assert_not_flagged "slash prompt then isMeta skill body -> not flagged" \
122
+ "$(mk_transcript '{"type":"user","message":{"role":"user","content":"/insight"}}' "$DIRECTIVE_ATTACH" "$ASSISTANT_TEXT" "$META_SKILL")"
123
+
124
+ # 11. Fail-open: missing transcript_path -> exit 0, no output.
125
+ fo_out=$(printf '{"session_id":"x"}' | bash "$HOOK" 2>&1); fo_exit=$?
126
+ if [[ "$fo_exit" -eq 0 && -z "$fo_out" ]]; then
127
+ echo "PASS: missing transcript_path -> exit 0, no output (fail-open)"; PASS=$((PASS+1))
128
+ else
129
+ echo "FAIL: fail-open wrong (exit=$fo_exit out=$fo_out)" >&2; FAIL=$((FAIL+1))
130
+ fi
131
+
132
+ # 12. Fail-open: nonexistent transcript path -> exit 0, no output.
133
+ ne_out=$(printf '{"transcript_path":"/nonexistent/x.jsonl","session_id":"x"}' | bash "$HOOK" 2>&1); ne_exit=$?
134
+ if [[ "$ne_exit" -eq 0 && -z "$ne_out" ]]; then
135
+ echo "PASS: nonexistent transcript -> exit 0, no output (fail-open)"; PASS=$((PASS+1))
136
+ else
137
+ echo "FAIL: nonexistent-transcript fail-open wrong (exit=$ne_exit out=$ne_out)" >&2; FAIL=$((FAIL+1))
138
+ fi
139
+
140
+ # 13. Durable log: flag lands in $LOG_DIR/prompt-optimiser-directive.log.
141
+ LD=$(mktemp -d)
142
+ t13=$(mk_transcript "$USER_PROMPT" "$DIRECTIVE_ATTACH" "$ASSISTANT_TEXT")
143
+ printf '{"transcript_path":"%s","session_id":"sess12345678"}' "$t13" | LOG_DIR="$LD" bash "$HOOK" >/dev/null 2>&1
144
+ if grep -q "no-route-taken" "$LD/prompt-optimiser-directive.log" 2>/dev/null \
145
+ && grep -q "session=sess1234" "$LD/prompt-optimiser-directive.log" 2>/dev/null; then
146
+ echo "PASS: flag appended to durable log with session id"; PASS=$((PASS+1))
147
+ else
148
+ echo "FAIL: durable flag missing (log=$(cat "$LD/prompt-optimiser-directive.log" 2>/dev/null))" >&2; FAIL=$((FAIL+1))
149
+ fi
150
+ rm -rf "$LD" "$t13"
151
+
152
+ echo "----"
153
+ echo "PASS=$PASS FAIL=$FAIL"
154
+ [[ "$FAIL" -eq 0 ]]
@@ -92,6 +92,16 @@ if printf '%s' "$ctx" | grep -qi "outcome" \
92
92
  else
93
93
  echo "FAIL: outcome-only-brief contract missing from ladder" >&2; FAIL=$((FAIL+1))
94
94
  fi
95
+ # Capability-question clause (Task 719): capability/how-to/config questions are
96
+ # owned work, answered from the owning specialist or plugin tool/reference,
97
+ # never from training memory.
98
+ if printf '%s' "$ctx" | grep -qi "owned work" \
99
+ && printf '%s' "$ctx" | grep -qi "training memory" \
100
+ && printf '%s' "$ctx" | grep -qi "do you have instructions"; then
101
+ echo "PASS: capability-question clause present in directive"; PASS=$((PASS+1))
102
+ else
103
+ echo "FAIL: capability-question clause missing from directive" >&2; FAIL=$((FAIL+1))
104
+ fi
95
105
 
96
106
  # Case 5 — ADMIN-SKILLS.md absent: fail-open. exit 0, ladder still injected,
97
107
  # and the missing= breadcrumb on stderr (fail-open must be visible).
@@ -107,6 +117,20 @@ else
107
117
  fi
108
118
  rm -rf "$WD"
109
119
 
120
+ # Case 6 — durable breadcrumb (Task 719). With LOG_DIR set and a session_id on
121
+ # stdin, the hook appends one `injected len=` line carrying the session id to
122
+ # $LOG_DIR/prompt-optimiser-directive.log, in addition to the stderr line.
123
+ LD=$(mktemp -d)
124
+ printf '%s' '{"prompt":"x","session_id":"sess-719-test"}' | LOG_DIR="$LD" bash "$HOOK" >/dev/null 2>&1
125
+ if [[ -f "$LD/prompt-optimiser-directive.log" ]] \
126
+ && grep -q "prompt-optimiser-directive] injected len=" "$LD/prompt-optimiser-directive.log" \
127
+ && grep -q "session=sess-719-test" "$LD/prompt-optimiser-directive.log"; then
128
+ echo "PASS: durable breadcrumb appended with session id"; PASS=$((PASS+1))
129
+ else
130
+ echo "FAIL: durable breadcrumb missing (log=$(cat "$LD/prompt-optimiser-directive.log" 2>/dev/null))" >&2; FAIL=$((FAIL+1))
131
+ fi
132
+ rm -rf "$LD"
133
+
110
134
  echo "----"
111
135
  echo "PASS=$PASS FAIL=$FAIL"
112
136
  [[ "$FAIL" -eq 0 ]]