@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.
- package/package.json +1 -1
- package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts +31 -43
- package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js +112 -85
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-spawn-tee/src/__tests__/spawn-tee.test.ts +111 -0
- package/payload/platform/lib/mcp-spawn-tee/src/index.ts +113 -84
- package/payload/platform/lib/mcp-spawn-tee/tsconfig.json +2 -1
- package/payload/platform/plugins/admin/PLUGIN.md +2 -1
- package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-compliance.test.sh +154 -0
- package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-directive.test.sh +24 -0
- package/payload/platform/plugins/admin/hooks/prompt-optimiser-compliance.sh +174 -0
- package/payload/platform/plugins/admin/hooks/prompt-optimiser-directive.sh +22 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4 -2
- package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +378 -56
- package/payload/platform/plugins/cloudflare/references/api.md +35 -1
- package/payload/platform/plugins/cloudflare/references/d1-data-capture.md +2 -0
- package/payload/platform/plugins/docs/references/cloudflare.md +1 -1
- package/payload/platform/plugins/docs/references/platform.md +2 -0
- package/payload/platform/plugins/email/PLUGIN.md +1 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.js +92 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/attachment-resolve.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js +55 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-setup.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.js +110 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/providers.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.js +57 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/recipient-filter.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/index.js +8 -1
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts +12 -0
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js +44 -5
- package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +13 -8
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js +26 -15
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts +8 -0
- package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts +16 -5
- package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/providers.js +120 -13
- package/payload/platform/plugins/email/mcp/dist/lib/providers.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js +3 -3
- package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js +6 -2
- package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +5 -3
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +6 -3
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +22 -4
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
- package/payload/platform/plugins/email/mcp/package.json +4 -2
- package/payload/platform/plugins/email/mcp/vitest.config.ts +9 -0
- package/payload/platform/plugins/email/references/email-reference.md +22 -5
- package/payload/platform/plugins/email/skills/email-composition/SKILL.md +1 -1
- package/payload/platform/plugins/graph/PLUGIN.md +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.js +31 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/kd-classify-account-dir.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts +5 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js +21 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js.map +1 -1
- package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +1 -0
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +5 -5
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -1
- package/payload/platform/plugins/whatsapp/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +7 -11
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +10 -56
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +26 -2
- package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +9 -14
- package/payload/platform/scripts/setup-account.sh +7 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +0 -2
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +63 -3
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +7 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +6 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +14 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +5 -3
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/public/assets/AdminShell-FO766lOW.js +1 -0
- package/payload/server/public/assets/{Checkbox-2reCESkb.js → Checkbox-syHoU9nY.js} +1 -1
- package/payload/server/public/assets/{admin-BpnsTEa3.js → admin-0_VxffD5.js} +1 -1
- package/payload/server/public/assets/{arc-BgelqC_3.js → arc-BW1WhwmV.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-xHbVjatf.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-BabnAZJm.js → architectureDiagram-Q4EWVU46-DsionCio.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BJzZqNsy.js → blockDiagram-DXYQGD6D-NOG5yVZk.js} +1 -1
- package/payload/server/public/assets/{browser-fgBRZ5gK.js → browser-Cxjkhtsk.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-By-xuh9F.js → c4Diagram-AHTNJAMY-DwFV1k9I.js} +1 -1
- package/payload/server/public/assets/channel-D8Go_zJk.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-Gj2dSpBl.js → chunk-2KRD3SAO-CKn-bEkI.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-2PXVPCUA.js → chunk-336JU56O-iJ4ISPCi.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-sWe0Iexz.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-9XIBlnC2.js → chunk-4BX2VUAB-B2mSmC97.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-Cr3mXPnI.js → chunk-4TB4RGXK-kKNYi2_i.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-Ccg46J3A.js → chunk-55IACEB6-JLT9m7Hd.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-Cz9MvPKc.js → chunk-5FUZZQ4R-Car3r0he.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BleOdlgO.js → chunk-5PVQY5BW-DR9EfLvj.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-CyCYCQWy.js → chunk-67CJDMHE-CCdP3Pdx.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-KpT3uHzH.js → chunk-7N4EOEYR-bXgVzdM9.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-BfOzbuxq.js → chunk-AA7GKIK3-CYeDvY8B.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-Bq0M3wlv.js → chunk-BSJP7CBP-U0Fi-Ers.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-CR-2dNaL.js → chunk-CIAEETIT-C8QrV6Gg.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-egUGMTOS.js → chunk-EDXVE4YY-DLUWVRZV.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CQohBEFw.js → chunk-ENJZ2VHE-B4bNJo6C.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-DIxBUbLP.js → chunk-FMBD7UC4-DxAQS3UB.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-C2694Zoq.js → chunk-FOC6F5B3-CyIK3zeY.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DpXZKHyn.js → chunk-ICPOFSXX-Qzl8Ki0l.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-CUicG0Rp.js → chunk-K5T4RW27-7GcDzjyJ.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-B5mPJhOr.js → chunk-KGLVRYIC-B7pAr9hf.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-q81QhuMs.js → chunk-LIHQZDEY-DEoU2jrz.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-DgurdFZs.js → chunk-ORNJ4GCN-BwMFuN24.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-CxqMRu2d.js → chunk-OYMX7WX6-BenBO6O_.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CHE_iZO7.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-BSLctJC9.js → chunk-U2HBQHQK-DewM8R0D.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP--0AUeeFl.js → chunk-X2U36JSP-C22Q6Ea4.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-D-hf9Bcn.js → chunk-XPW4576I-BA0a8Ygs.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-PvOhSwI9.js → chunk-YZCP3GAM-DfUUNTnA.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-1zPUlNWz.js → chunk-ZZ45TVLE-CUT6zma2.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BLb1mzrT.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Ctj5qYTS.js +1 -0
- package/payload/server/public/assets/clone-DGZ2vydA.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Cvo-gkBd.js → cose-bilkent-S5V4N54A-Df_JmB8E.js} +1 -1
- package/payload/server/public/assets/{dagre-CMHsNfjP.js → dagre-CYXRIdv0.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-CM1DSx4E.js → dagre-KV5264BT-D4EGb60h.js} +1 -1
- package/payload/server/public/assets/{data-Cuynp6Y6.js → data-BOgwOWnw.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-VDHiHwEI.js → diagram-5BDNPKRD-BzieCEfT.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-OKdufoeW.js → diagram-G4DWMVQ6-DDbO71XD.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-Yg6QdCA1.js → diagram-MMDJMWI5-DqQ_UXDA.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CpEMZQDu.js → diagram-TYMM5635-CFyxA1aZ.js} +1 -1
- package/payload/server/public/assets/{dist-811BIK0R.js → dist-BmvZ8OaX.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-Dw5gAkFM.js → erDiagram-SMLLAGMA-BMaEBbOK.js} +1 -1
- package/payload/server/public/assets/{flatten-BsWEYbBB.js → flatten-Bo6YRmWl.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-Cy_R1XHz.js → flowDiagram-DWJPFMVM-De5ChZQP.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BYARP_eH.js → ganttDiagram-T4ZO3ILL-CXEMPVaK.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CmHdoS27.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BGOe0unY.js → gitGraphDiagram-UUTBAWPF-OZedr_6y.js} +1 -1
- package/payload/server/public/assets/{graph-Ddg24bjy.js → graph-BqD2GjQd.js} +2 -2
- package/payload/server/public/assets/{graph-labels-eOrWYy0R.js → graph-labels-DSDTSBfM.js} +1 -1
- package/payload/server/public/assets/{graphlib-DaefxCga.js → graphlib-CN4nhD2U.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-DTA9msO-.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CSqg4nRL.js +2 -0
- package/payload/server/public/assets/{isEmpty-BWl67LAZ.js → isEmpty-D6Kr-M1M.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-YrGuzpiI.js → ishikawaDiagram-UXIWVN3A-ChlzrZyx.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-EIykOcqg.js → journeyDiagram-VCZTEJTY-DsrK55ZO.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BR0TC6Je.js → kanban-definition-6JOO6SKY-DYF-_Rym.js} +1 -1
- package/payload/server/public/assets/{line-DPGcT5IM.js → line-3zmwI8XK.js} +1 -1
- package/payload/server/public/assets/{linear-CPN03uSh.js → linear-COm19-p7.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-D7Iu4c9M.js → mermaid-parser.core-BrcX8-cl.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-krXRpXn9.js → mermaid.core-CBdz3b1N.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-HwiCtPzN.js → mindmap-definition-QFDTVHPH-BqCqlYZb.js} +1 -1
- package/payload/server/public/assets/{ordinal-krseTxxN.js → ordinal-BDi6f4xk.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-6GjqIKgu.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-T72DJ5JR.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-xodxyWLe.js → pieDiagram-DEJITSTG-D5LiILuM.js} +1 -1
- package/payload/server/public/assets/{public-xVaPcg6i.js → public-udi_Z7la.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-DuYYY4ZZ.js → quadrantDiagram-34T5L4WZ-C3iuI5l_.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-x-6xW1dE.js +1 -0
- package/payload/server/public/assets/{reduce-tk-xY6Fv.js → reduce-CGi9ik8i.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-D0ta3kru.js → requirementDiagram-MS252O5E-CTPOw5qQ.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-KdHdlzvT.js → sankeyDiagram-XADWPNL6-D_5aVlYp.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DoSFUTQZ.js → sequenceDiagram-FGHM5R23-D7h5vocM.js} +1 -1
- package/payload/server/public/assets/{src-Cpl1JzME.js → src-DLEIsjER.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-BLW0KiSA.js → stateDiagram-FHFEXIEX-DyZjuwPj.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BiW9pGXy.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-8QAzhYz1.js → timeline-definition-GMOUNBTQ-BqpVYJz_.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-5-6wEryJ.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-DF48Cc86.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-DlJsX-_X.js → useSelectionMode-BPzPjKP_.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BKvfScOi.js → vennDiagram-DHZGUBPP-Czflml0e.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-duKIa6Hq.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DaMfDpJ3.js → wardleyDiagram-NUSXRM2D-Cqz3pSTK.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BIkNQlLa.js → xychartDiagram-5P7HB3ND-CS5dEuUO.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +5 -5
- package/payload/server/public/public.html +4 -4
- package/payload/server/server.js +74 -275
- package/payload/server/public/assets/AdminShell-C6_5h1cC.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-YM-TtgPY.js +0 -1
- package/payload/server/public/assets/channel-BRPH0atd.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-QhauxjvK.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-BDAQvtxz.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BJv89PB6.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DNUszH5M.js +0 -1
- package/payload/server/public/assets/clone-CREg9jLM.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CtOPqykB.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-Jba5enA8.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-Df9BlkPA.js +0 -2
- package/payload/server/public/assets/packet-4T2RLAQJ-D_eWzeAP.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BDiy1Ob2.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-C5mlfmtg.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-C5zlCV4X.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CM-9m-cS.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-DDHPB-Xh.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-CUb3Br4q.js +0 -1
- package/payload/server/public/assets/whatsapp-BE79pNh8.js +0 -1
- package/payload/server/public/whatsapp.html +0 -18
- /package/payload/server/public/assets/{_baseFor-BHtDrjIo.js → _baseFor-Cam2PbSt.js} +0 -0
- /package/payload/server/public/assets/{array-DetWRiSa.js → array-DYRGGQae.js} +0 -0
- /package/payload/server/public/assets/{chunk-CWOGyPgy.js → chunk-CnGqDkHZ.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-C9yNhe1u.js → cytoscape.esm-nWsJMTNI.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-_WRwicXn.js → defaultLocale-Du1XY3Dp.js} +0 -0
- /package/payload/server/public/assets/{init-sTEcj9YX.js → init-B5BXBRcm.js} +0 -0
- /package/payload/server/public/assets/{katex-s61Rgv6l.js → katex-HOUACuRw.js} +0 -0
- /package/payload/server/public/assets/{path-B0Ik7Tu9.js → path-CNO468J-.js} +0 -0
- /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
|
|
3
|
+
* MCP spawn-tee — parent-side stderr capture + lifecycle observability.
|
|
4
4
|
*
|
|
5
|
-
* Claude Code
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
40
|
-
* -
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
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
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
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
|
-
/*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
});
|
|
@@ -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 ]]
|