@rubytech/create-maxy-code 0.1.499 → 0.1.501

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 (221) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-style/dist/index.d.ts +9 -0
  3. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/graph-style/dist/index.js +152 -6
  5. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  6. package/payload/platform/lib/graph-style/src/__tests__/caption-coverage.test.ts +69 -0
  7. package/payload/platform/lib/graph-style/src/__tests__/coverage-source.ts +73 -0
  8. package/payload/platform/lib/graph-style/src/__tests__/icons.test.ts +20 -3
  9. package/payload/platform/lib/graph-style/src/index.ts +166 -5
  10. package/payload/platform/plugins/admin/PLUGIN.md +2 -1
  11. package/payload/platform/plugins/admin/hooks/__tests__/admin-authoring-observer.test.sh +135 -0
  12. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-directive.test.sh +11 -2
  13. package/payload/platform/plugins/admin/hooks/prompt-optimiser-directive.sh +6 -3
  14. package/payload/platform/plugins/admin/mcp/dist/index.js +52 -107
  15. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  16. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts +8 -4
  17. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts.map +1 -1
  18. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js +67 -50
  19. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js.map +1 -1
  20. package/payload/platform/plugins/admin/mcp/dist/store-skill-core.d.ts +33 -0
  21. package/payload/platform/plugins/admin/mcp/dist/store-skill-core.d.ts.map +1 -0
  22. package/payload/platform/plugins/admin/mcp/dist/store-skill-core.js +122 -0
  23. package/payload/platform/plugins/admin/mcp/dist/store-skill-core.js.map +1 -0
  24. package/payload/platform/plugins/admin/skills/agent-builder/SKILL.md +15 -0
  25. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +59 -3
  26. package/payload/platform/plugins/admin/skills/summarise/SKILL.md +37 -0
  27. package/payload/platform/plugins/contacts/.claude-plugin/plugin.json +1 -1
  28. package/payload/platform/plugins/contacts/PLUGIN.md +1 -1
  29. package/payload/platform/plugins/contacts/mcp/dist/index.js +3 -12
  30. package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
  31. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.js +105 -2
  32. package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.js.map +1 -1
  33. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +11 -1
  34. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -1
  35. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +56 -4
  36. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -1
  37. package/payload/platform/plugins/docs/references/admin-ui.md +50 -0
  38. package/payload/platform/plugins/docs/references/contacts-guide.md +2 -0
  39. package/payload/platform/plugins/docs/references/outlook-guide.md +4 -0
  40. package/payload/platform/plugins/docs/references/plugins-guide.md +2 -2
  41. package/payload/platform/plugins/docs/references/summarise-skill.md +7 -0
  42. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +9 -1
  43. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +6 -0
  44. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +1 -1
  45. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/__tests__/restatement-ladder.test.sh +2 -1
  46. package/payload/platform/services/claude-session-manager/dist/index.js +26 -1
  47. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  48. package/payload/platform/services/claude-session-manager/dist/skill-registration-drift.d.ts +15 -0
  49. package/payload/platform/services/claude-session-manager/dist/skill-registration-drift.d.ts.map +1 -1
  50. package/payload/platform/services/claude-session-manager/dist/skill-registration-drift.js +61 -0
  51. package/payload/platform/services/claude-session-manager/dist/skill-registration-drift.js.map +1 -1
  52. package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
  53. package/payload/server/public/activity.html +6 -6
  54. package/payload/server/public/assets/{AdminLoginScreens-Ce5aBBWF.js → AdminLoginScreens-C3LZOPIY.js} +1 -1
  55. package/payload/server/public/assets/AdminShell-BlbUNAPc.js +2 -0
  56. package/payload/server/public/assets/{activity-CKUYOLd2.js → activity-CVdVSw5V.js} +1 -1
  57. package/payload/server/public/assets/admin-If1QLlS3.js +1 -0
  58. package/payload/server/public/assets/{arc-CpWWSum8.js → arc-CvlzUHOf.js} +1 -1
  59. package/payload/server/public/assets/architecture-YZFGNWBL-BQc779DH.js +1 -0
  60. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-D2EzaII0.js → architectureDiagram-Q4EWVU46-I1Hs0RJA.js} +1 -1
  61. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-8kDpaNSZ.js → blockDiagram-DXYQGD6D-Df5jTGtl.js} +1 -1
  62. package/payload/server/public/assets/{bot-DESMpxSQ.js → bot-8b26IlQY.js} +1 -1
  63. package/payload/server/public/assets/{browser-CpLq_DIo.js → browser-F40DXfKA.js} +1 -1
  64. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-CbwmZpK3.js → c4Diagram-AHTNJAMY-B6WY5IDv.js} +1 -1
  65. package/payload/server/public/assets/{calendar-ClOwyuz-.js → calendar-DZiHiBwV.js} +1 -1
  66. package/payload/server/public/assets/channel-AqnC3SHu.js +1 -0
  67. package/payload/server/public/assets/chat-uD28FVCS.js +1 -0
  68. package/payload/server/public/assets/chevron-left-lBxD57tD.js +1 -0
  69. package/payload/server/public/assets/chevron-right-C-lDig9Y.js +1 -0
  70. package/payload/server/public/assets/{chunk-2KRD3SAO-PFheZ9mw.js → chunk-2KRD3SAO-BsIIFDkc.js} +1 -1
  71. package/payload/server/public/assets/{chunk-336JU56O-CCFOp5VK.js → chunk-336JU56O-j9z1VtyC.js} +2 -2
  72. package/payload/server/public/assets/chunk-426QAEUC-CO02gU5d.js +1 -0
  73. package/payload/server/public/assets/{chunk-4BX2VUAB-Hz4JWOf2.js → chunk-4BX2VUAB-C9i7prxq.js} +1 -1
  74. package/payload/server/public/assets/{chunk-4TB4RGXK-4xeV0s85.js → chunk-4TB4RGXK-DH0QVGcv.js} +1 -1
  75. package/payload/server/public/assets/{chunk-55IACEB6-4QKgBpoh.js → chunk-55IACEB6-Dnd_YCPA.js} +1 -1
  76. package/payload/server/public/assets/{chunk-5FUZZQ4R-ms3K6Z5z.js → chunk-5FUZZQ4R-D5sSz3yN.js} +1 -1
  77. package/payload/server/public/assets/{chunk-5PVQY5BW-CIC4GIGi.js → chunk-5PVQY5BW-CJrwWjAT.js} +1 -1
  78. package/payload/server/public/assets/{chunk-67CJDMHE-B-XrWVmV.js → chunk-67CJDMHE-SjP6_hUw.js} +1 -1
  79. package/payload/server/public/assets/{chunk-7N4EOEYR-C7ECOUYQ.js → chunk-7N4EOEYR-fAuhVJD0.js} +1 -1
  80. package/payload/server/public/assets/{chunk-AA7GKIK3-DOZ6Fxwk.js → chunk-AA7GKIK3-DZxa7KVg.js} +1 -1
  81. package/payload/server/public/assets/{chunk-BSJP7CBP-4cJ_b0c6.js → chunk-BSJP7CBP-DjeG3eQ-.js} +1 -1
  82. package/payload/server/public/assets/{chunk-CIAEETIT--mhZipWM.js → chunk-CIAEETIT-RYQULNJm.js} +1 -1
  83. package/payload/server/public/assets/{chunk-EDXVE4YY-jZpVwob_.js → chunk-EDXVE4YY-Cahapnon.js} +1 -1
  84. package/payload/server/public/assets/{chunk-ENJZ2VHE-Nn-p-xIA.js → chunk-ENJZ2VHE-1146X1L4.js} +1 -1
  85. package/payload/server/public/assets/{chunk-FMBD7UC4-DyNpcKOS.js → chunk-FMBD7UC4-BCFumtcP.js} +1 -1
  86. package/payload/server/public/assets/{chunk-FOC6F5B3-C0P8q1uz.js → chunk-FOC6F5B3-CkrtX8Zt.js} +1 -1
  87. package/payload/server/public/assets/{chunk-ICPOFSXX-CdXQ5SfI.js → chunk-ICPOFSXX-Ba1y3DaW.js} +2 -2
  88. package/payload/server/public/assets/{chunk-K5T4RW27-BVZJKKsT.js → chunk-K5T4RW27-CF-PI3uQ.js} +1 -1
  89. package/payload/server/public/assets/{chunk-KGLVRYIC-QlVWTe0V.js → chunk-KGLVRYIC-SFFC6ZC-.js} +1 -1
  90. package/payload/server/public/assets/{chunk-LIHQZDEY-CpGVZutP.js → chunk-LIHQZDEY-DbOLEP4R.js} +1 -1
  91. package/payload/server/public/assets/{chunk-ORNJ4GCN-WVcS6fUC.js → chunk-ORNJ4GCN-VB963bkN.js} +1 -1
  92. package/payload/server/public/assets/{chunk-OYMX7WX6-B7hiSTed.js → chunk-OYMX7WX6-DWYY1pQa.js} +1 -1
  93. package/payload/server/public/assets/chunk-QZHKN3VN-BiFMbK8t.js +1 -0
  94. package/payload/server/public/assets/{chunk-U2HBQHQK-DJPnZxGy.js → chunk-U2HBQHQK-DAH1diYP.js} +1 -1
  95. package/payload/server/public/assets/{chunk-X2U36JSP-DilBs1Yc.js → chunk-X2U36JSP-Dmw9coXz.js} +1 -1
  96. package/payload/server/public/assets/{chunk-XPW4576I-B5-uyrJ0.js → chunk-XPW4576I-DaAUON1-.js} +1 -1
  97. package/payload/server/public/assets/{chunk-YZCP3GAM-BNO4z0Mv.js → chunk-YZCP3GAM-BUcfkEef.js} +1 -1
  98. package/payload/server/public/assets/{chunk-ZZ45TVLE-BzHMQpip.js → chunk-ZZ45TVLE-BLD-vFRO.js} +1 -1
  99. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BdRqzScB.js +1 -0
  100. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-ChPLgHbS.js +1 -0
  101. package/payload/server/public/assets/clock-DqRNsY40.js +1 -0
  102. package/payload/server/public/assets/clone-TKtrjWBC.js +1 -0
  103. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-3DWYmn1o.js → cose-bilkent-S5V4N54A-CoZX0uki.js} +1 -1
  104. package/payload/server/public/assets/{dagre-Cpy31xJW.js → dagre-Bmjs8zJA.js} +1 -1
  105. package/payload/server/public/assets/{dagre-KV5264BT-C8fyxHFd.js → dagre-KV5264BT-BZCP2wnq.js} +1 -1
  106. package/payload/server/public/assets/data-BsFyBN85.js +1 -0
  107. package/payload/server/public/assets/{diagram-5BDNPKRD-ycyhnLvr.js → diagram-5BDNPKRD-8Nt9a4xX.js} +1 -1
  108. package/payload/server/public/assets/{diagram-G4DWMVQ6-BkeYicIt.js → diagram-G4DWMVQ6-vh5tcYqJ.js} +1 -1
  109. package/payload/server/public/assets/{diagram-MMDJMWI5-BcGZU-Q3.js → diagram-MMDJMWI5-DGf--jc8.js} +1 -1
  110. package/payload/server/public/assets/{diagram-TYMM5635-DuBDCFb_.js → diagram-TYMM5635-CsO7TIdw.js} +1 -1
  111. package/payload/server/public/assets/{dist-BYc_arNy.js → dist-cdnE4DqK.js} +1 -1
  112. package/payload/server/public/assets/{erDiagram-SMLLAGMA-DmkeOzvp.js → erDiagram-SMLLAGMA-4a78yV8_.js} +1 -1
  113. package/payload/server/public/assets/file-text-B1HjPFbM.js +1 -0
  114. package/payload/server/public/assets/{flatten-QjnJ1Gcl.js → flatten-BtIc9jX7.js} +1 -1
  115. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-CkE-pjuB.js → flowDiagram-DWJPFMVM-BoQBXs6t.js} +1 -1
  116. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-Cjiy3kvE.js → ganttDiagram-T4ZO3ILL-CvzqwCC8.js} +1 -1
  117. package/payload/server/public/assets/gitGraph-7Q5UKJZL-DfcaTE9L.js +1 -0
  118. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CsI4lKZm.js → gitGraphDiagram-UUTBAWPF-D_nBxay_.js} +1 -1
  119. package/payload/server/public/assets/graph-CIC-mgKR.js +51 -0
  120. package/payload/server/public/assets/graph-labels-BnpHCHaQ.js +1 -0
  121. package/payload/server/public/assets/{graphlib-BkXxC6D5.js → graphlib-D0NdsKJI.js} +1 -1
  122. package/payload/server/public/assets/info-OMHHGYJF-CD-u6gw9.js +1 -0
  123. package/payload/server/public/assets/infoDiagram-42DDH7IO-C6gPQCvO.js +2 -0
  124. package/payload/server/public/assets/{isEmpty-BavJI9Cn.js → isEmpty-Bu4fZ8Kf.js} +1 -1
  125. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-D8lZtjRc.js → ishikawaDiagram-UXIWVN3A-auW-s0i0.js} +1 -1
  126. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-kLE7SiR_.js → journeyDiagram-VCZTEJTY-3Q6AWK4A.js} +1 -1
  127. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-ove6JuD3.js → kanban-definition-6JOO6SKY-B4MPFp98.js} +1 -1
  128. package/payload/server/public/assets/{line-CZMSoxM6.js → line-26MdeG5Z.js} +1 -1
  129. package/payload/server/public/assets/{linear-Be8IK9hK.js → linear-Dq9s_bDO.js} +1 -1
  130. package/payload/server/public/assets/{maximize-2-BbzPm7o8.js → maximize-2-BL7QVTcQ.js} +1 -1
  131. package/payload/server/public/assets/{mermaid-parser.core-BBADqbnp.js → mermaid-parser.core-vLEpOXgf.js} +2 -2
  132. package/payload/server/public/assets/{mermaid.core-mH3N7K0I.js → mermaid.core-Durk4m6D.js} +3 -3
  133. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-BjwwwWil.js → mindmap-definition-QFDTVHPH-DOIg-TyG.js} +1 -1
  134. package/payload/server/public/assets/{operator-DCNWUKP_.js → operator-B62h_TaC.js} +1 -1
  135. package/payload/server/public/assets/{ordinal-BHeIKG-K.js → ordinal-C2TEWKNu.js} +1 -1
  136. package/payload/server/public/assets/packet-4T2RLAQJ-BaLYeIrU.js +1 -0
  137. package/payload/server/public/assets/page-BUUBseJZ.js +32 -0
  138. package/payload/server/public/assets/page-Bw-tYjw7.js +1 -0
  139. package/payload/server/public/assets/{pdf-render-fJz4vym9.js → pdf-render-C257cidb.js} +1 -1
  140. package/payload/server/public/assets/pie-ZZUOXDRM-CL-XJtk-.js +1 -0
  141. package/payload/server/public/assets/{pieDiagram-DEJITSTG-D-lXWWta.js → pieDiagram-DEJITSTG-DtgBHZfi.js} +1 -1
  142. package/payload/server/public/assets/{public-DXJXQPwe.js → public-BI21tOkm.js} +1 -1
  143. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-13QyG_AO.js → quadrantDiagram-34T5L4WZ-BTc5Qn2y.js} +1 -1
  144. package/payload/server/public/assets/radar-PYXPWWZC-Cn-g6F_h.js +1 -0
  145. package/payload/server/public/assets/{reduce-Fm685to3.js → reduce-BGpN5lgn.js} +1 -1
  146. package/payload/server/public/assets/{requirementDiagram-MS252O5E-Bx45Bgn4.js → requirementDiagram-MS252O5E-BNgOO5YW.js} +1 -1
  147. package/payload/server/public/assets/{rotate-ccw-L42fL8ey.js → rotate-ccw-C_20Bc3E.js} +1 -1
  148. package/payload/server/public/assets/routines-Ci3N8wqV.js +1 -0
  149. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-Cj-Gq25v.js → sankeyDiagram-XADWPNL6-MyUATmVt.js} +1 -1
  150. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-B8RDRq93.js → sequenceDiagram-FGHM5R23-CBJrF5Vi.js} +1 -1
  151. package/payload/server/public/assets/skills-CiflzOko.js +1 -0
  152. package/payload/server/public/assets/{src-D3VYuW_Z.js → src-DekKlUCp.js} +1 -1
  153. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DoyFF1Kl.js → stateDiagram-FHFEXIEX-6wbUjn1Q.js} +1 -1
  154. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BdMdfBeC.js +1 -0
  155. package/payload/server/public/assets/{tasks-GNtvZL8F.js → tasks-DC2Yf2Ev.js} +1 -1
  156. package/payload/server/public/assets/{time-entry-format-BreNpFLJ.js → time-entry-format-CNcjs2HV.js} +1 -1
  157. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-Df4RQXm6.js → timeline-definition-GMOUNBTQ-BHjTMCGY.js} +1 -1
  158. package/payload/server/public/assets/treeView-SZITEDCU-CmZoOGlC.js +1 -0
  159. package/payload/server/public/assets/treemap-W4RFUUIX-H27WFS-y.js +1 -0
  160. package/payload/server/public/assets/{triangle-alert-DumCWC08.js → triangle-alert-CngnWtjD.js} +1 -1
  161. package/payload/server/public/assets/{useCopyFeedback-DHCtz8qX.js → useCopyFeedback-DZ9Bw5CI.js} +1 -1
  162. package/payload/server/public/assets/{useSubAccountSwitcher-Bc7XHr0L.js → useSubAccountSwitcher-CHwQhkaI.js} +1 -1
  163. package/payload/server/public/assets/{useSubAccountSwitcher-DPHQJO7E.css → useSubAccountSwitcher-yFQqnpQ8.css} +1 -1
  164. package/payload/server/public/assets/useVoiceRecorder-C3G6aqZr.js +2 -0
  165. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-D2o5og9l.js → vennDiagram-DHZGUBPP-yo3-cf0U.js} +1 -1
  166. package/payload/server/public/assets/wardley-RL74JXVD-DNpWIvU4.js +1 -0
  167. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BDueObbS.js → wardleyDiagram-NUSXRM2D-DZlyFzrg.js} +1 -1
  168. package/payload/server/public/assets/{wrench-iWkROE1V.js → wrench-dky2-13x.js} +1 -1
  169. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BTYs4Fgh.js → xychartDiagram-5P7HB3ND-B5HV5h80.js} +1 -1
  170. package/payload/server/public/browser.html +5 -5
  171. package/payload/server/public/calendar.html +8 -8
  172. package/payload/server/public/chat.html +16 -15
  173. package/payload/server/public/data.html +13 -12
  174. package/payload/server/public/graph.html +10 -10
  175. package/payload/server/public/index.html +17 -16
  176. package/payload/server/public/operator.html +17 -16
  177. package/payload/server/public/public.html +16 -15
  178. package/payload/server/public/routines.html +7 -7
  179. package/payload/server/public/skills.html +19 -0
  180. package/payload/server/public/tasks.html +7 -7
  181. package/payload/server/server.js +714 -402
  182. package/payload/server/public/assets/AdminShell-BFVVkWFC.js +0 -2
  183. package/payload/server/public/assets/admin-BWb8me-E.js +0 -1
  184. package/payload/server/public/assets/architecture-YZFGNWBL-D-AX2VuA.js +0 -1
  185. package/payload/server/public/assets/channel-DZ5sh6YQ.js +0 -1
  186. package/payload/server/public/assets/chat-MvnxPJZ5.js +0 -1
  187. package/payload/server/public/assets/chevron-left-BzIg4in6.js +0 -1
  188. package/payload/server/public/assets/chevron-right-BcFSa9C3.js +0 -1
  189. package/payload/server/public/assets/chunk-426QAEUC-CcjBLp4a.js +0 -1
  190. package/payload/server/public/assets/chunk-QZHKN3VN-B2WjDYBE.js +0 -1
  191. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CT3jNrze.js +0 -1
  192. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DJRsjAkC.js +0 -1
  193. package/payload/server/public/assets/clock-Dr3NGtjR.js +0 -1
  194. package/payload/server/public/assets/clone-FcEDnoMT.js +0 -1
  195. package/payload/server/public/assets/data-BjqC4hyM.js +0 -1
  196. package/payload/server/public/assets/gitGraph-7Q5UKJZL-D1uhnP9U.js +0 -1
  197. package/payload/server/public/assets/graph-B7niLM97.js +0 -51
  198. package/payload/server/public/assets/graph-labels-DykmXYHA.js +0 -1
  199. package/payload/server/public/assets/info-OMHHGYJF-oNm27GAV.js +0 -1
  200. package/payload/server/public/assets/infoDiagram-42DDH7IO-LxTftqyS.js +0 -2
  201. package/payload/server/public/assets/packet-4T2RLAQJ-eQNVGiK3.js +0 -1
  202. package/payload/server/public/assets/page-C4TrTU6r.js +0 -32
  203. package/payload/server/public/assets/page-DUgrGrJp.js +0 -1
  204. package/payload/server/public/assets/pie-ZZUOXDRM-E1u-48rt.js +0 -1
  205. package/payload/server/public/assets/radar-PYXPWWZC-Cn2cGN90.js +0 -1
  206. package/payload/server/public/assets/routines-JOV6xdYh.js +0 -1
  207. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Bml-X4-H.js +0 -1
  208. package/payload/server/public/assets/treeView-SZITEDCU-CimabhXy.js +0 -1
  209. package/payload/server/public/assets/treemap-W4RFUUIX-Cg264rpM.js +0 -1
  210. package/payload/server/public/assets/useVoiceRecorder-Cu6zvuFx.js +0 -2
  211. package/payload/server/public/assets/wardley-RL74JXVD-tbgfCg0E.js +0 -1
  212. /package/payload/server/public/assets/{_baseFor-Bvwvhrz4.js → _baseFor-Be3EKK3K.js} +0 -0
  213. /package/payload/server/public/assets/{array-D3d-WgFW.js → array-X0JlPOfd.js} +0 -0
  214. /package/payload/server/public/assets/{chunk-fQC6bEKA.js → chunk-CCr-iYLO.js} +0 -0
  215. /package/payload/server/public/assets/{cytoscape.esm-Cun-OM6a.js → cytoscape.esm-CI2IWMLB.js} +0 -0
  216. /package/payload/server/public/assets/{defaultLocale-CisKV5Ew.js → defaultLocale-B6RGN4id.js} +0 -0
  217. /package/payload/server/public/assets/{init-D9ZOVaZ3.js → init-BmUWJJHz.js} +0 -0
  218. /package/payload/server/public/assets/{katex-C-3ZDK8o.js → katex-BjZuzSQn.js} +0 -0
  219. /package/payload/server/public/assets/{path-BMOgQSLM.js → path-CoPyR7c2.js} +0 -0
  220. /package/payload/server/public/assets/{preload-helper-DL2DwvxV.js → preload-helper-BQrMkyGX.js} +0 -0
  221. /package/payload/server/public/assets/{rough.esm-BrTFrov0.js → rough.esm-jSt7UMyi.js} +0 -0
@@ -42,11 +42,12 @@ export const GRAPH_LABEL_COLOURS: Record<string, string> = {
42
42
  // JobLogic service-delivery ontology (Task 1084; supersedes the Task 650/773
43
43
  // homegrown set). Muted brick-red / earthy family — the service register sits
44
44
  // apart from people-terracotta, viewing-amber, and task-rose bands so
45
- // sitedesk legends read as their own group. Top-level (operator-entry)
46
- // labels only; child labels (QuoteLine, Milestone, Valuation, VariationNote,
47
- // JobCost, Contact, PurchaseOrderLine, InvoiceLine, InvoicePayment, Credit)
48
- // intentionally stay fallback-grey. :Engineer is an additional label on
49
- // Person and takes the Person colour; :Supplier is an additional label on
45
+ // sitedesk legends read as their own group. These are the top-level
46
+ // (operator-entry) labels; the child labels (QuoteLine, Milestone, Valuation,
47
+ // VariationNote, JobCost, Contact, PurchaseOrderLine, InvoiceLine,
48
+ // InvoicePayment, Credit) are coloured in the Task 1965 block appended at the
49
+ // end of this object, not here. :Engineer is an additional label on Person
50
+ // and takes the Person colour; :Supplier is an additional label on
50
51
  // Organization and takes the tobacco Organization colour. All hexes here are
51
52
  // pairwise-unique across the registry.
52
53
  Job: '#8C3B2E',
@@ -156,6 +157,93 @@ export const GRAPH_LABEL_COLOURS: Record<string, string> = {
156
157
  // (this object's key order), so a mid-table insert would silently change
157
158
  // the rendered shape of every label after it.
158
159
  CashEntry: '#7D5A2B',
160
+
161
+ // --- Task 1965: colour every node type that can appear in the graph ---
162
+ // Appended at the END so SHAPE_BY_LABEL indices for the labels above are
163
+ // unchanged. Grouped by family band; each hex is pairwise-unique across the
164
+ // whole registry (except the pre-existing UserMessage/Preference twin).
165
+
166
+ // Ledger / money children (brown-gold, beside Invoice and CashEntry).
167
+ InvoiceLine: '#7A5326',
168
+ InvoicePayment: '#8A6230',
169
+ QuoteLine: '#9A7038',
170
+ PurchaseOrderLine: '#A67E42',
171
+ JobCost: '#6A4A22',
172
+ Credit: '#B48A48',
173
+ Retainer: '#C29A55',
174
+ Sale: '#8E5E2A',
175
+ Valuation: '#A06A34',
176
+ Order: '#B87C3E',
177
+ DiningOrder: '#C9954E',
178
+
179
+ // Documents / content (steel-blue, hue-adjacent to the business slates).
180
+ Content: '#58708C',
181
+ Report: '#6D8299',
182
+ Page: '#849AAF',
183
+ Post: '#93A7BA',
184
+ VariationNote: '#47617B',
185
+ FileArtifact: '#A9BBCC',
186
+
187
+ // Marketing (bright teal-green, apart from workflow and research teals).
188
+ SocialPost: '#2FA69A',
189
+ Campaign: '#3FB8A0',
190
+ BrandDeal: '#57C2AE',
191
+ Recommendation: '#74CDBB',
192
+
193
+ // CRM people (terracotta, beside Person and Customer).
194
+ Contact: '#C97E52',
195
+ Lead: '#A85E38',
196
+ Position: '#96522E',
197
+ Audience: '#E0B088',
198
+
199
+ // Places / transport / retail (forest-emerald, apart from knowledge moss).
200
+ PostalAddress: '#2E8B57',
201
+ Room: '#3A9B63',
202
+ StoreLocation: '#46A96F',
203
+ Vehicle: '#54B77B',
204
+ Route: '#62C187',
205
+ Stop: '#2A7A4C',
206
+ Shipment: '#6FCB93',
207
+ Reservation: '#7ED4A0',
208
+ TableReservation: '#8CDBAC',
209
+ Menu: '#1F6B41',
210
+ MenuItem: '#98E0B6',
211
+ Product: '#34925E',
212
+ StockMovement: '#4CA574',
213
+
214
+ // Work / delivery (indigo, apart from the strategy indigo band).
215
+ Milestone: '#4A5FA8',
216
+ Deliverable: '#6274C0',
217
+ TimeEntry: '#8189CE',
218
+ Engagement: '#9AA0DA',
219
+ Case: '#3B4E92',
220
+ Meeting: '#5566B4',
221
+
222
+ // Idea (amber).
223
+ Idea: '#E0A82E',
224
+
225
+ // Web analytics (sky-cyan, apart from the research teal).
226
+ Session: '#2AA7C4',
227
+ PageView: '#3DB4CE',
228
+ Click: '#55C0D6',
229
+ ScrollMilestone: '#70CCDE',
230
+ TimelineEvent: '#1E93B0',
231
+ AnonVisitor: '#88D6E6',
232
+ AEOAudit: '#46B0CB',
233
+
234
+ // WhatsApp transport (brand green).
235
+ WhatsAppConversation: '#128C7E',
236
+ WhatsAppMessage: '#1FA894',
237
+
238
+ // Cloudflare / chain infra (grey-blue).
239
+ CloudflareHostname: '#5B6E82',
240
+ CloudflareTunnel: '#6E8296',
241
+ Chain: '#47586A',
242
+ ChainLink: '#8496AA',
243
+
244
+ // Voice (violet).
245
+ VoiceProfile: '#9B59B6',
246
+ VoiceEdit: '#B07CC9',
159
247
  }
160
248
 
161
249
  export const FALLBACK_LABEL_COLOUR = '#94A3B8'
@@ -251,6 +339,18 @@ export function shapeForLabel(label: string): GraphNodeShape {
251
339
  return SHAPE_BY_LABEL[label] ?? FALLBACK_LABEL_SHAPE
252
340
  }
253
341
 
342
+ /**
343
+ * Node labels written by code with no schema node-type-table row and no
344
+ * typed-edge declaration. They still render as graph nodes, so they must carry
345
+ * a colour + glyph like any other node type. The reconciliation gate in
346
+ * __tests__/icons.test.ts folds this set into the node-label universe. Add a
347
+ * label here when the runtime `op=icon-fallback` census names one that no
348
+ * schema table or typed edge declares.
349
+ */
350
+ export const CODE_EMITTED_NODE_LABELS: ReadonlySet<string> = Object.freeze(
351
+ new Set(['FileArtifact']),
352
+ ) as ReadonlySet<string>
353
+
254
354
  // ---------------------------------------------------------------------------
255
355
  // Icon registry — a third visual channel alongside colour + shape.
256
356
  //
@@ -325,6 +425,67 @@ const LABEL_ICONS: Record<string, string> = {
325
425
  Finding: '<path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"></path><path d="M9 18h6"></path><path d="M10 22h4"></path>',
326
426
  Hypothesis: '<path d="M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2"></path><path d="M6.453 15h11.094"></path><path d="M8.5 2h7"></path>',
327
427
  CashEntry: '<rect width="20" height="12" x="2" y="6" rx="2"></rect><circle cx="12" cy="12" r="2"></circle><path d="M6 12h.01"></path><path d="M18 12h.01"></path>',
428
+ // --- Task 1965: glyphs for the 60 previously-uncovered node labels ---
429
+ InvoiceLine: '<path d="M13 16H8" /><path d="M14 8H8" /><path d="M16 12H8" /><path d="M4 3a1 1 0 0 1 1-1 1.3 1.3 0 0 1 .7.2l.933.6a1.3 1.3 0 0 0 1.4 0l.934-.6a1.3 1.3 0 0 1 1.4 0l.933.6a1.3 1.3 0 0 0 1.4 0l.933-.6a1.3 1.3 0 0 1 1.4 0l.934.6a1.3 1.3 0 0 0 1.4 0l.933-.6A1.3 1.3 0 0 1 19 2a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1 1.3 1.3 0 0 1-.7-.2l-.933-.6a1.3 1.3 0 0 0-1.4 0l-.934.6a1.3 1.3 0 0 1-1.4 0l-.933-.6a1.3 1.3 0 0 0-1.4 0l-.933.6a1.3 1.3 0 0 1-1.4 0l-.934-.6a1.3 1.3 0 0 0-1.4 0l-.933.6a1.3 1.3 0 0 1-.7.2 1 1 0 0 1-1-1z" />',
430
+ InvoicePayment: '<path d="M11 15h2a2 2 0 1 0 0-4h-3c-.6 0-1.1.2-1.4.6L3 17" /><path d="m7 21 1.6-1.4c.3-.4.8-.6 1.4-.6h4c1.1 0 2.1-.4 2.8-1.2l4.6-4.4a2 2 0 0 0-2.75-2.91l-4.2 3.9" /><path d="m2 16 6 6" /><circle cx="16" cy="9" r="2.9" /><circle cx="6" cy="5" r="3" />',
431
+ QuoteLine: '<path d="M3 5h.01" /><path d="M3 12h.01" /><path d="M3 19h.01" /><path d="M8 5h13" /><path d="M8 12h13" /><path d="M8 19h13" />',
432
+ PurchaseOrderLine: '<path d="M11 5h10" /><path d="M11 12h10" /><path d="M11 19h10" /><path d="M4 4h1v5" /><path d="M4 9h2" /><path d="M6.5 20H3.4c0-1 2.6-1.925 2.6-3.5a1.5 1.5 0 0 0-2.6-1.02" />',
433
+ JobCost: '<rect width="20" height="12" x="2" y="6" rx="2" /><circle cx="12" cy="12" r="2" /><path d="M6 12h.01M18 12h.01" />',
434
+ Credit: '<path d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" /><path d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8" /><path d="M12 18V6" />',
435
+ Retainer: '<path d="M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" /><path d="M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" />',
436
+ Sale: '<path d="M12 17V7" /><path d="M16 8h-6a2 2 0 0 0 0 4h4a2 2 0 0 1 0 4H8" /><path d="M4 3a1 1 0 0 1 1-1 1.3 1.3 0 0 1 .7.2l.933.6a1.3 1.3 0 0 0 1.4 0l.934-.6a1.3 1.3 0 0 1 1.4 0l.933.6a1.3 1.3 0 0 0 1.4 0l.933-.6a1.3 1.3 0 0 1 1.4 0l.934.6a1.3 1.3 0 0 0 1.4 0l.933-.6A1.3 1.3 0 0 1 19 2a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1 1.3 1.3 0 0 1-.7-.2l-.933-.6a1.3 1.3 0 0 0-1.4 0l-.934.6a1.3 1.3 0 0 1-1.4 0l-.933-.6a1.3 1.3 0 0 0-1.4 0l-.933.6a1.3 1.3 0 0 1-1.4 0l-.934-.6a1.3 1.3 0 0 0-1.4 0l-.933.6a1.3 1.3 0 0 1-.7.2 1 1 0 0 1-1-1z" />',
437
+ Valuation: '<path d="M12 3v18" /><path d="m19 8 3 8a5 5 0 0 1-6 0zV7" /><path d="M3 7h1a17 17 0 0 0 8-2 17 17 0 0 0 8 2h1" /><path d="m5 8 3 8a5 5 0 0 1-6 0zV7" /><path d="M7 21h10" />',
438
+ Order: '<path d="M16 10a4 4 0 0 1-8 0" /><path d="M3.103 6.034h17.794" /><path d="M3.4 5.467a2 2 0 0 0-.4 1.2V20a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6.667a2 2 0 0 0-.4-1.2l-2-2.667A2 2 0 0 0 17 2H7a2 2 0 0 0-1.6.8z" />',
439
+ DiningOrder: '<path d="M3 2v7c0 1.1.9 2 2 2h4a2 2 0 0 0 2-2V2" /><path d="M7 2v20" /><path d="M21 15V2a5 5 0 0 0-5 5v6c0 1.1.9 2 2 2h3Zm0 0v7" />',
440
+ Content: '<path d="M15 18h-5" /><path d="M18 14h-8" /><path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2" /><rect width="8" height="4" x="10" y="6" rx="1" />',
441
+ Report: '<rect width="8" height="4" x="8" y="2" rx="1" ry="1" /><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" /><path d="M12 11h4" /><path d="M12 16h4" /><path d="M8 11h.01" /><path d="M8 16h.01" />',
442
+ Page: '<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z" /><path d="M14 2v5a1 1 0 0 0 1 1h5" />',
443
+ Post: '<path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" /><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z" />',
444
+ SocialPost: '<path d="M11 6a13 13 0 0 0 8.4-2.8A1 1 0 0 1 21 4v12a1 1 0 0 1-1.6.8A13 13 0 0 0 11 14H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z" /><path d="M6 14a12 12 0 0 0 2.4 7.2 2 2 0 0 0 3.2-2.4A8 8 0 0 1 10 14" /><path d="M8 6v8" />',
445
+ VariationNote: '<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z" /><path d="M9 10h6" /><path d="M12 13V7" /><path d="M9 17h6" />',
446
+ Contact: '<path d="M16 2v2" /><path d="M17.915 22a6 6 0 0 0-12 0" /><path d="M8 2v2" /><circle cx="12" cy="12" r="4" /><rect x="3" y="4" width="18" height="18" rx="2" />',
447
+ Lead: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /><circle cx="9" cy="7" r="4" /><line x1="19" x2="19" y1="8" y2="14" /><line x1="22" x2="16" y1="11" y2="11" />',
448
+ Position: '<path d="M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16" /><rect width="20" height="14" x="2" y="6" rx="2" />',
449
+ Audience: '<path d="M18 21a8 8 0 0 0-16 0" /><circle cx="10" cy="8" r="5" /><path d="M22 20c0-3.37-2-6.5-4-8a5 5 0 0 0-.45-8.3" />',
450
+ PostalAddress: '<path d="M18 8c0 3.613-3.869 7.429-5.393 8.795a1 1 0 0 1-1.214 0C9.87 15.429 6 11.613 6 8a6 6 0 0 1 12 0" /><circle cx="12" cy="8" r="2" /><path d="M8.714 14h-3.71a1 1 0 0 0-.948.683l-2.004 6A1 1 0 0 0 3 22h18a1 1 0 0 0 .948-1.316l-2-6a1 1 0 0 0-.949-.684h-3.712" />',
451
+ Room: '<path d="M11 20H2" /><path d="M11 4.562v16.157a1 1 0 0 0 1.242.97L19 20V5.562a2 2 0 0 0-1.515-1.94l-4-1A2 2 0 0 0 11 4.561z" /><path d="M11 4H8a2 2 0 0 0-2 2v14" /><path d="M14 12h.01" /><path d="M22 20h-3" />',
452
+ StoreLocation: '<path d="M15 21v-5a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v5" /><path d="M17.774 10.31a1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.451 0 1.12 1.12 0 0 0-1.548 0 2.5 2.5 0 0 1-3.452 0 1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.77-3.248l2.889-4.184A2 2 0 0 1 7 2h10a2 2 0 0 1 1.653.873l2.895 4.192a2.5 2.5 0 0 1-3.774 3.244" /><path d="M4 10.95V19a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8.05" />',
453
+ Vehicle: '<path d="M19 17h2c.6 0 1-.4 1-1v-3c0-.9-.7-1.7-1.5-1.9C18.7 10.6 16 10 16 10s-1.3-1.4-2.2-2.3c-.5-.4-1.1-.7-1.8-.7H5c-.6 0-1.1.4-1.4.9l-1.4 2.9A3.7 3.7 0 0 0 2 12v4c0 .6.4 1 1 1h2" /><circle cx="7" cy="17" r="2" /><path d="M9 17h6" /><circle cx="17" cy="17" r="2" />',
454
+ Route: '<circle cx="6" cy="19" r="3" /><path d="M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15" /><circle cx="18" cy="5" r="3" />',
455
+ Stop: '<path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0" /><circle cx="12" cy="10" r="3" />',
456
+ Shipment: '<path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z" /><path d="M12 22V12" /><polyline points="3.29 7 12 12 20.71 7" /><path d="m7.5 4.27 9 5.15" />',
457
+ Reservation: '<path d="M8 2v4" /><path d="M16 2v4" /><rect width="18" height="18" x="3" y="4" rx="2" /><path d="M3 10h18" /><path d="m9 16 2 2 4-4" />',
458
+ TableReservation: '<path d="m16 2-2.3 2.3a3 3 0 0 0 0 4.2l1.8 1.8a3 3 0 0 0 4.2 0L22 8" /><path d="M15 15 3.3 3.3a4.2 4.2 0 0 0 0 6l7.3 7.3c.7.7 2 .7 2.8 0L15 15Zm0 0 7 7" /><path d="m2.1 21.8 6.4-6.3" /><path d="m19 5-7 7" />',
459
+ Menu: '<path d="M12 5v16" /><path d="M20.001 19A2 2 0 0022 17V5a2 2 0 00-1.999-2L16 3.002A5 5 0 0012 5a5 5 0 00-4-2H4a2 2 0 00-2 2v12a2 2 0 001.999 2H8a5 5 0 014 2 5 5 0 014-2z" />',
460
+ MenuItem: '<path d="M7 21h10" /><path d="M12 21a9 9 0 0 0 9-9H3a9 9 0 0 0 9 9Z" /><path d="M11.38 12a2.4 2.4 0 0 1-.4-4.77 2.4 2.4 0 0 1 3.2-2.77 2.4 2.4 0 0 1 3.47-.63 2.4 2.4 0 0 1 3.37 3.37 2.4 2.4 0 0 1-1.1 3.7 2.51 2.51 0 0 1 .03 1.1" /><path d="m13 12 4-4" /><path d="M10.9 7.25A3.99 3.99 0 0 0 4 10c0 .73.2 1.41.54 2" />',
461
+ Product: '<path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z" /><path d="m3.3 7 8.7 5 8.7-5" /><path d="M12 22V12" />',
462
+ StockMovement: '<path d="m16 3 4 4-4 4" /><path d="M20 7H4" /><path d="m8 21-4-4 4-4" /><path d="M4 17h16" />',
463
+ Milestone: '<path d="M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528" />',
464
+ Deliverable: '<path d="M12 22V12" /><path d="m16 17 2 2 4-4" /><path d="M21 11.127V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.729l7 4a2 2 0 0 0 2 .001l1.32-.753" /><path d="M3.29 7 12 12l8.71-5" /><path d="m7.5 4.27 8.997 5.148" />',
465
+ TimeEntry: '<line x1="10" x2="14" y1="2" y2="2" /><line x1="12" x2="15" y1="14" y2="11" /><circle cx="12" cy="14" r="8" />',
466
+ Engagement: '<path d="m11 17 2 2a1 1 0 1 0 3-3" /><path d="m14 14 2.5 2.5a1 1 0 1 0 3-3l-3.88-3.88a3 3 0 0 0-4.24 0l-.88.88a1 1 0 1 1-3-3l2.81-2.81a5.79 5.79 0 0 1 7.06-.87l.47.28a2 2 0 0 0 1.42.25L21 4" /><path d="m21 3 1 11h-2" /><path d="M3 3 2 14l6.5 6.5a1 1 0 1 0 3-3" /><path d="M3 4h8" />',
467
+ Case: '<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />',
468
+ Meeting: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /><path d="M16 3.128a4 4 0 0 1 0 7.744" /><path d="M22 21v-2a4 4 0 0 0-3-3.87" /><circle cx="9" cy="7" r="4" />',
469
+ Idea: '<path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5" /><path d="M9 18h6" /><path d="M10 22h4" />',
470
+ Campaign: '<path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5" /><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09" /><path d="M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z" /><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05" />',
471
+ BrandDeal: '<path d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" /><path d="m9 12 2 2 4-4" />',
472
+ Recommendation: '<path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z" /><path d="M7 10v12" />',
473
+ Session: '<rect width="20" height="14" x="2" y="3" rx="2" /><line x1="8" x2="16" y1="21" y2="21" /><line x1="12" x2="12" y1="17" y2="21" />',
474
+ PageView: '<path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" /><circle cx="12" cy="12" r="3" />',
475
+ Click: '<path d="M14 4.1 12 6" /><path d="m5.1 8-2.9-.8" /><path d="m6 12-1.9 2" /><path d="M7.2 2.2 8 5.1" /><path d="M9.037 9.69a.498.498 0 0 1 .653-.653l11 4.5a.5.5 0 0 1-.074.949l-4.349 1.041a1 1 0 0 0-.74.739l-1.04 4.35a.5.5 0 0 1-.95.074z" />',
476
+ ScrollMilestone: '<path d="m7 6 5 5 5-5" /><path d="m7 13 5 5 5-5" />',
477
+ TimelineEvent: '<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" /><path d="M3 3v5h5" /><path d="M12 7v5l4 2" />',
478
+ AnonVisitor: '<path d="M9 10h.01" /><path d="M15 10h.01" /><path d="M12 2a8 8 0 0 0-8 8v12l3-3 2.5 2.5L12 19l2.5 2.5L17 19l3 3V10a8 8 0 0 0-8-8z" />',
479
+ AEOAudit: '<path d="m8 11 2 2 4-4" /><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" />',
480
+ WhatsAppConversation: '<path d="M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719" />',
481
+ WhatsAppMessage: '<path d="M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z" /><path d="M7 11h10" /><path d="M7 15h6" /><path d="M7 7h8" />',
482
+ CloudflareHostname: '<circle cx="12" cy="12" r="10" /><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" /><path d="M2 12h20" />',
483
+ CloudflareTunnel: '<rect x="16" y="16" width="6" height="6" rx="1" /><rect x="2" y="16" width="6" height="6" rx="1" /><rect x="9" y="2" width="6" height="6" rx="1" /><path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3" /><path d="M12 12V8" />',
484
+ Chain: '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" /><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />',
485
+ ChainLink: '<path d="M9 17H7A5 5 0 0 1 7 7h2" /><path d="M15 7h2a5 5 0 1 1 0 10h-2" /><line x1="8" x2="16" y1="12" y2="12" />',
486
+ FileArtifact: '<path d="M13.659 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v11.5" /><path d="M14 2v5a1 1 0 0 0 1 1h5" /><path d="M8 12v-1" /><path d="M8 18v-2" /><path d="M8 7V6" /><circle cx="8" cy="20" r="2" />',
487
+ VoiceProfile: '<path d="M12 19v3" /><path d="M19 10v2a7 7 0 0 1-14 0v-2" /><rect x="9" y="2" width="6" height="13" rx="3" />',
488
+ VoiceEdit: '<path d="M2 10v3" /><path d="M6 6v11" /><path d="M10 3v18" /><path d="M14 8v7" /><path d="M18 5v13" /><path d="M22 10v3" />',
328
489
  }
329
490
 
330
491
  /**
@@ -184,6 +184,7 @@ Tools are available via the `admin` MCP server.
184
184
  | Investigate a bug or unexpected behaviour | User asks to debug, fix a bug, find the root cause, or investigate an error | `skills/investigate/SKILL.md` |
185
185
  | Capture work as a task before implementing | User asks to "task it", create a task, or describes work that should be a task file before a sprint | `skills/task/SKILL.md` |
186
186
  | Run an insight pass on this session | Operator asks to run an insight pass, review this session, capture what we learned, or do a retrospective on the conversation | `skills/insight/SKILL.md` |
187
+ | Summarise the last turn | User asks to summarise, recap, or give the "in short" version of what the agent just said or asked | `skills/summarise/SKILL.md` |
187
188
 
188
189
  ## Hooks
189
190
 
@@ -196,7 +197,7 @@ Tools are available via the `admin` MCP server.
196
197
  - `hooks/mcp-tool-missing.sh` — **PostToolUse hook on `mcp__.*` (directive 3).** Defence-in-depth for the `No such tool available: mcp__…` failure class that the 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`.
197
198
  - `hooks/post-tool-use-agent.sh` — **PostToolUse hook on `Agent`.** 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. 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).
198
199
  - `hooks/admin-authoring-observer.sh` — **PostToolUse hook on Write and Edit.** 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 this hook 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.
199
- - `hooks/prompt-optimiser-directive.sh` — **UserPromptSubmit hook.** 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). The directive also 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. The directive is also **suppressed on native channel turns** — when the parsed `.prompt` starts with the `<channel source=` event marker, the hook logs `[prompt-optimiser-directive] skipped reason=channel-turn session=<id>` to stderr and exits without injecting, because the channel service already reframes the inbound into a select-and-dispatch turn (`composeAdminContent`, see `.docs/whatsapp-inbound-lifeline.md`). Marker-matched at start-of-prompt only, so an admin/Terminal prompt that merely mentions "channel" still gets the directive; fail-open injects if the prompt cannot be parsed.
200
+ - `hooks/prompt-optimiser-directive.sh` — **UserPromptSubmit hook.** Injects the standing prompt-optimiser restatement directive plus the per-turn four-rung routing ladder as `additionalContext`: **(1)** delegate to the specialist that owns the deliverable via the Agent tool, where 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 the deliverable recurs and no specialist or skill owns it, author its owning skill via `skill-builder` (or `agent-builder` for a worker agent) and produce through it; **(4)** only if it is a genuine one-off, author inline as 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). The directive also 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. The directive is also **suppressed on native channel turns** — when the parsed `.prompt` starts with the `<channel source=` event marker, the hook logs `[prompt-optimiser-directive] skipped reason=channel-turn session=<id>` to stderr and exits without injecting, because the channel service already reframes the inbound into a select-and-dispatch turn (`composeAdminContent`, see `.docs/whatsapp-inbound-lifeline.md`). Marker-matched at start-of-prompt only, so an admin/Terminal prompt that merely mentions "channel" still gets the directive; fail-open injects if the prompt cannot be parsed.
200
201
  - `hooks/preference-consult-directive.sh` — **UserPromptSubmit hook.** Injects a standing `<preference-adherence>` block naming the two-layer preference architecture (layer 1 the fixed block already in front of the agent every turn; layer 2 the account's own saved `Preference` records, read with `profile-read`, holding signature policy, header, naming and styling) and two directives: consult the relevant layer-2 preferences with `profile-read` before any customer-facing document deliverable, and store finished deliverables under `documents/` or the project folder because `output/` is scratch of last resort. Prompt-independent and always exit 0 (fail-open). Breadcrumb (stderr): `[pref-wrapper] op=inject`. This is the advisory companion to the `preference-consult-gate` hard gate.
201
202
  - `hooks/datetime-inject.sh` — **UserPromptSubmit hook.** Injects a fresh `<datetime>` block as `additionalContext` on every turn (`refresh=per-turn`), so the agent always has the current instant — date, time, timezone, weekday, and the raw UTC ISO — without hand-computing it and without depending on Claude Code's spawn-time "Today's date" line going stale. The instant is computed fresh each turn; the timezone is **not** computed here — it is the operator's own zone, resolved from their `UserProfile.timezone` on the graph once per admin spawn and stamped into `MAXY_ACCOUNT_TZ` (see `platform/services/claude-session-manager/src/account-timezone.ts`). When `MAXY_ACCOUNT_TZ` is empty (a non-admin turn, an unset profile timezone, or a neo4j hiccup at spawn) the block falls back to the server's own zone and labels the source, so a reader can always tell which clock the agent saw. This is the current-time surface the `datetime` skill points at. **Fail-open** on every path (missing `python3` or `node`, any formatting error → exit 0, empty stdout — the turn is never blocked). The hook appends `<ts> [datetime-inject] injected tz=<zone> source=<graph|server-fallback> refresh=per-turn session=<id>` to `$LOG_DIR/datetime-inject.log` so "did the agent have the right time this turn, and from which clock?" is answerable from logs without reproduction.
202
203
  - `hooks/prompt-optimiser-compliance.sh` — **Stop hook.** 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 turn recorder below).
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env bash
2
+ # Task 1961 — the classless inline-write line is the recurring-deliverable
3
+ # arming signal.
4
+ #
5
+ # admin-authoring-observer.sh emits, on stderr, one line when the admin
6
+ # process (MAXY_SPECIALIST empty) writes under <accountDir>/output/:
7
+ # [admin-authoring] inline-write path=<rel> priorSpecialistSpawnInTurn=<true|false|unknown>
8
+ #
9
+ # priorSpecialistSpawnInTurn=false is the arming signal: an inline output
10
+ # write with no specialist dispatched earlier in the turn. This suite pins
11
+ # fixture transcripts via ADMIN_AUTHORING_TRANSCRIPT_PATH and asserts:
12
+ # - false when the transcript has no specialists: Task after the last user turn
13
+ # - true when it does
14
+ # - unknown when no transcript is available
15
+ # - no line at all for writes outside output/, or from a specialist process
16
+ set -u
17
+ HOOK="$(cd "$(dirname "$0")/.." && pwd)/admin-authoring-observer.sh"
18
+ [[ -x "$HOOK" ]] || { echo "FAIL: $HOOK not executable"; exit 1; }
19
+
20
+ PASS=0; FAIL=0
21
+ pass() { PASS=$((PASS+1)); echo "PASS: $1"; }
22
+ fail() { FAIL=$((FAIL+1)); echo "FAIL: $1" >&2; }
23
+
24
+ TMP=$(mktemp -d)
25
+ trap 'rm -rf "$TMP"' EXIT
26
+ ACCT="$TMP/account"
27
+ mkdir -p "$ACCT/output"
28
+
29
+ # Fixture transcripts.
30
+ NO_SPECIALIST="$TMP/no-specialist.jsonl"
31
+ cat >"$NO_SPECIALIST" <<'JSON'
32
+ {"type":"user","message":{"role":"user","content":"draft a quote for the Smith job"}}
33
+ {"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"On it."}]}}
34
+ JSON
35
+
36
+ WITH_SPECIALIST="$TMP/with-specialist.jsonl"
37
+ cat >"$WITH_SPECIALIST" <<'JSON'
38
+ {"type":"user","message":{"role":"user","content":"draft a quote for the Smith job"}}
39
+ {"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Task","input":{"subagent_type":"specialists:content-producer"}}]}}
40
+ JSON
41
+
42
+ # A Task whose subagent_type is not a specialist: must not count as a spawn.
43
+ NON_SPECIALIST_TASK="$TMP/non-specialist-task.jsonl"
44
+ cat >"$NON_SPECIALIST_TASK" <<'JSON'
45
+ {"type":"user","message":{"role":"user","content":"draft a quote for the Smith job"}}
46
+ {"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Task","input":{"subagent_type":"general-purpose"}}]}}
47
+ JSON
48
+
49
+ # A specialist dispatched in a PRIOR turn must not arm the current turn: the
50
+ # hook walks forward only from the last real-user turn.
51
+ PRIOR_TURN_SPECIALIST="$TMP/prior-turn-specialist.jsonl"
52
+ cat >"$PRIOR_TURN_SPECIALIST" <<'JSON'
53
+ {"type":"user","message":{"role":"user","content":"earlier request"}}
54
+ {"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Task","input":{"subagent_type":"specialists:content-producer"}}]}}
55
+ {"type":"user","message":{"role":"user","content":"draft a quote for the Smith job"}}
56
+ {"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"On it."}]}}
57
+ JSON
58
+
59
+ # input <tool_name> <file_path> — builds the PostToolUse payload the hook parses.
60
+ mk_input() {
61
+ python3 -c '
62
+ import json, sys
63
+ print(json.dumps({
64
+ "hook_event_name": "PostToolUse",
65
+ "tool_name": sys.argv[1],
66
+ "tool_input": {"file_path": sys.argv[2]},
67
+ "transcript_path": ""
68
+ }, separators=(",", ":")))
69
+ ' "$1" "$2"
70
+ }
71
+
72
+ # run <transcript-or-empty> <MAXY_SPECIALIST> <tool_name> <file_path> — fires the
73
+ # hook from inside the account dir (its output/ scope keys off $PWD) and returns
74
+ # stderr.
75
+ run() {
76
+ local transcript="$1" specialist="$2" tool="$3" fp="$4"
77
+ ( cd "$ACCT" \
78
+ && mk_input "$tool" "$fp" \
79
+ | ADMIN_AUTHORING_TRANSCRIPT_PATH="$transcript" MAXY_SPECIALIST="$specialist" \
80
+ bash "$HOOK" 2>&1 1>/dev/null )
81
+ }
82
+
83
+ ARM_RE='\[admin-authoring\] inline-write path=output/quote\.html priorSpecialistSpawnInTurn='
84
+
85
+ # 1. Arming signal: inline output write, no specialist in the turn.
86
+ OUT=$(run "$NO_SPECIALIST" "" Write "output/quote.html")
87
+ echo "$OUT" | grep -qE "${ARM_RE}false" \
88
+ && pass "arming: priorSpecialistSpawnInTurn=false on inline output write" \
89
+ || fail "arming false expected, got: $OUT"
90
+
91
+ # 2. Owned: a specialist was dispatched earlier in the same turn.
92
+ OUT=$(run "$WITH_SPECIALIST" "" Write "output/quote.html")
93
+ echo "$OUT" | grep -qE "${ARM_RE}true" \
94
+ && pass "owned: priorSpecialistSpawnInTurn=true when specialist dispatched" \
95
+ || fail "true expected, got: $OUT"
96
+
97
+ # 3. Unknown: no transcript available — line still fires, value is not the arming one.
98
+ OUT=$(run "$TMP/does-not-exist.jsonl" "" Write "output/quote.html")
99
+ echo "$OUT" | grep -qE "${ARM_RE}unknown" \
100
+ && pass "unknown: priorSpecialistSpawnInTurn=unknown with no transcript" \
101
+ || fail "unknown expected, got: $OUT"
102
+
103
+ # 4. Edit is observed like Write.
104
+ OUT=$(run "$NO_SPECIALIST" "" Edit "output/quote.html")
105
+ echo "$OUT" | grep -qE "${ARM_RE}false" \
106
+ && pass "Edit under output/ is observed" \
107
+ || fail "Edit expected arming line, got: $OUT"
108
+
109
+ # 4a. A non-specialist Task in the turn does not count as a spawn — still armed.
110
+ OUT=$(run "$NON_SPECIALIST_TASK" "" Write "output/quote.html")
111
+ echo "$OUT" | grep -qE "${ARM_RE}false" \
112
+ && pass "arming: non-specialist Task does not disarm" \
113
+ || fail "false expected for non-specialist Task, got: $OUT"
114
+
115
+ # 4b. A specialist in a PRIOR turn does not disarm the current turn.
116
+ OUT=$(run "$PRIOR_TURN_SPECIALIST" "" Write "output/quote.html")
117
+ echo "$OUT" | grep -qE "${ARM_RE}false" \
118
+ && pass "arming: prior-turn specialist does not disarm current turn" \
119
+ || fail "false expected for prior-turn specialist, got: $OUT"
120
+
121
+ # 5. Scope guard — write outside output/ emits no line.
122
+ OUT=$(run "$NO_SPECIALIST" "" Write "notes/scratch.txt")
123
+ echo "$OUT" | grep -q '\[admin-authoring\]' \
124
+ && fail "write outside output/ must emit nothing, got: $OUT" \
125
+ || pass "scope guard: write outside output/ emits no line"
126
+
127
+ # 6. Scope guard — a specialist process (MAXY_SPECIALIST set) emits no line.
128
+ OUT=$(run "$NO_SPECIALIST" "content-producer" Write "output/quote.html")
129
+ echo "$OUT" | grep -q '\[admin-authoring\]' \
130
+ && fail "specialist process must emit nothing, got: $OUT" \
131
+ || pass "scope guard: specialist process emits no line"
132
+
133
+ echo "----"
134
+ echo "PASS=$PASS FAIL=$FAIL"
135
+ [[ "$FAIL" -eq 0 ]]
@@ -65,7 +65,7 @@ else
65
65
  fi
66
66
  rm -rf "$FAKEBIN"
67
67
 
68
- # Case 4 — both generated lists present: the ladder carries all three tiers, both
68
+ # Case 4 — both generated lists present: the ladder carries all four rungs, both
69
69
  # full lists, and the relocated outcome-only-brief contract. The hook reads the
70
70
  # lists from $PWD/agents/admin, so run it from a temp account dir.
71
71
  WD=$(mktemp -d); mkdir -p "$WD/agents/admin"
@@ -78,11 +78,20 @@ if printf '%s' "$ctx" | grep -q "specialists:content-producer" \
78
78
  && printf '%s' "$ctx" | grep -qE '(^|[^0-9])1\)' \
79
79
  && printf '%s' "$ctx" | grep -qE '(^|[^0-9])2\)' \
80
80
  && printf '%s' "$ctx" | grep -qE '(^|[^0-9])3\)' \
81
+ && printf '%s' "$ctx" | grep -qE '(^|[^0-9])4\)' \
81
82
  && printf '%s' "$ctx" | grep -qiE "freestyle|last resort"; then
82
- echo "PASS: both lists injected in three-tier ladder"; PASS=$((PASS+1))
83
+ echo "PASS: both lists injected in four-rung ladder"; PASS=$((PASS+1))
83
84
  else
84
85
  echo "FAIL: ladder/lists missing from additionalContext: $ctx" >&2; FAIL=$((FAIL+1))
85
86
  fi
87
+ # Task 1959: recurring-deliverable rung sits before the freestyle last resort.
88
+ if printf '%s' "$ctx" | grep -qi "skill-builder" \
89
+ && printf '%s' "$ctx" | grep -qiE "recurs|issues repeatedly|repeatable" \
90
+ && printf '%s' "$ctx" | grep -qi "agent-builder"; then
91
+ echo "PASS: recurring-deliverable rung present in ladder"; PASS=$((PASS+1))
92
+ else
93
+ echo "FAIL: recurring-deliverable rung missing from ladder: $ctx" >&2; FAIL=$((FAIL+1))
94
+ fi
86
95
  # Relocated outcome-only-brief contract.
87
96
  if printf '%s' "$ctx" | grep -qi "outcome" \
88
97
  && printf '%s' "$ctx" | grep -qi "binding constraints" \
@@ -1,13 +1,15 @@
1
1
  #!/usr/bin/env bash
2
2
  # UserPromptSubmit hook: inject the standing prompt-optimiser directive plus the
3
- # per-turn three-tier routing ladder as additionalContext on every turn, so the
3
+ # per-turn four-rung routing ladder as additionalContext on every turn, so the
4
4
  # agent restates each non-trivial prompt and routes it before acting. Mirrors
5
5
  # doctrine.sh: emit hookSpecificOutput.additionalContext via python3, fail-open
6
6
  # with exit 0.
7
7
  #
8
8
  # The ladder ranks, in order: (1) delegate to a specialist that owns the
9
9
  # deliverable via the Agent tool; (2) only if none fits, load an admin-usable
10
- # skill; (3) only if neither fits, author inline freestyle is the named last
10
+ # skill; (3) only if the deliverable recurs and no specialist or skill owns it,
11
+ # author its owning skill via skill-builder (or agent-builder) and produce
12
+ # through it; (4) only if it is a genuine one-off, author inline as the last
11
13
  # resort. The full agent roster and admin-usable skills list are re-emitted every
12
14
  # turn by reading two generated files from the account dir; the hook never walks
13
15
  # the plugins tree per turn (Task 698).
@@ -102,7 +104,8 @@ IFS= read -r -d '' DIRECTIVE_MID <<'DIRECTIVE_EOF' || true
102
104
  DIRECTIVE_EOF
103
105
 
104
106
  IFS= read -r -d '' DIRECTIVE_TAIL <<'DIRECTIVE_EOF' || true
105
- 3) Only if neither a specialist nor an admin skill fits, author it directly. Freestyle inline authoring is the last resort, not a peer of the two routes above.
107
+ 3) Only if neither a specialist nor an admin skill already owns it, decide whether the deliverable recurs. A deliverable the business issues repeatedly, or one the operator gives a fixed template, numbering, naming, or filing rule for, is authored once as its own skill: load skill-builder with skill-load (or agent-builder for a worker agent), create the owning skill, then produce the deliverable through it. This rung owns every repeatable business document or process; hand-building a recurring deliverable here is not a route.
108
+ 4) Only if the deliverable is a genuine one-off, author it directly. Freestyle inline authoring is the last resort, not a peer of the routes above.
106
109
  DIRECTIVE_EOF
107
110
 
108
111
  DIRECTIVE=$(printf '%s\n%s\n%s\n%s\n%s' \