@rubytech/create-maxy-code 0.1.157 → 0.1.159

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 (236) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts +1 -1
  3. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/admin-conversation-purge/dist/index.js +4 -4
  5. package/payload/platform/lib/admin-conversation-purge/dist/index.js.map +1 -1
  6. package/payload/platform/lib/admin-conversation-purge/src/index.ts +5 -5
  7. package/payload/platform/lib/graph-style/dist/index.js +2 -2
  8. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  9. package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +1 -1
  10. package/payload/platform/lib/graph-style/src/index.ts +2 -2
  11. package/payload/platform/lib/graph-trash/dist/index.js +1 -1
  12. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
  13. package/payload/platform/lib/graph-trash/src/index.ts +1 -1
  14. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js +1 -1
  15. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js.map +1 -1
  16. package/payload/platform/lib/graph-write/dist/conversation-provenance.d.ts +3 -3
  17. package/payload/platform/lib/graph-write/dist/conversation-provenance.js +5 -5
  18. package/payload/platform/lib/graph-write/dist/conversation-provenance.js.map +1 -1
  19. package/payload/platform/lib/graph-write/dist/index.js +1 -1
  20. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  21. package/payload/platform/lib/graph-write/src/__tests__/action-provenance-gate.test.ts +1 -1
  22. package/payload/platform/lib/graph-write/src/conversation-provenance.ts +8 -8
  23. package/payload/platform/lib/graph-write/src/index.ts +1 -1
  24. package/payload/platform/neo4j/schema.cypher +33 -15
  25. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  26. package/payload/platform/plugins/admin/PLUGIN.md +8 -4
  27. package/payload/platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh +1 -1
  28. package/payload/platform/plugins/admin/hooks/__tests__/per-turn-graph-pass-gate.test.sh +361 -0
  29. package/payload/platform/plugins/admin/hooks/__tests__/pre-turn-graph-pass.test.sh +13 -13
  30. package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +1 -1
  31. package/payload/platform/plugins/admin/hooks/lib/admin-graph-pass-common.sh +242 -0
  32. package/payload/platform/plugins/admin/hooks/per-turn-graph-pass-gate.sh +106 -0
  33. package/payload/platform/plugins/admin/hooks/pre-turn-graph-pass.sh +47 -91
  34. package/payload/platform/plugins/admin/hooks/session-end-retrospective.sh +32 -91
  35. package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +4 -4
  36. package/payload/platform/plugins/admin/mcp/dist/index.js +65 -24
  37. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  38. package/payload/platform/plugins/admin/skills/session-management/SKILL.md +2 -2
  39. package/payload/platform/plugins/admin/skills/stream-log-review/SKILL.md +5 -5
  40. package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +6 -6
  41. package/payload/platform/plugins/business-assistant/references/profiling.md +1 -1
  42. package/payload/platform/plugins/contacts/PLUGIN.md +1 -1
  43. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +2 -2
  44. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
  45. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.js +3 -3
  46. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.d.ts +1 -1
  47. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.js +2 -2
  48. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts +1 -1
  49. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts.map +1 -1
  50. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js +4 -4
  51. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js.map +1 -1
  52. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js +10 -10
  53. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js.map +1 -1
  54. package/payload/platform/plugins/docs/references/admin-session.md +6 -6
  55. package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
  56. package/payload/platform/plugins/docs/references/deployment.md +3 -1
  57. package/payload/platform/plugins/docs/references/internals.md +5 -5
  58. package/payload/platform/plugins/docs/references/plugins-guide.md +3 -3
  59. package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
  60. package/payload/platform/plugins/email/.claude-plugin/plugin.json +1 -1
  61. package/payload/platform/plugins/email/PLUGIN.md +15 -2
  62. package/payload/platform/plugins/email/mcp/dist/index.js +53 -0
  63. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  64. package/payload/platform/plugins/email/mcp/dist/lib/embedding.js +2 -2
  65. package/payload/platform/plugins/email/mcp/dist/lib/embedding.js.map +1 -1
  66. package/payload/platform/plugins/email/mcp/dist/lib/graph.js +1 -1
  67. package/payload/platform/plugins/email/mcp/dist/lib/graph.js.map +1 -1
  68. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +1 -1
  69. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts +23 -0
  70. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts.map +1 -0
  71. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js +15 -0
  72. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js.map +1 -0
  73. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts +15 -0
  74. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts.map +1 -0
  75. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js +49 -0
  76. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js.map +1 -0
  77. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts +20 -0
  78. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts.map +1 -0
  79. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js +86 -0
  80. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js.map +1 -0
  81. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
  82. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +32 -52
  83. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
  84. package/payload/platform/plugins/email/references/email-reference.md +19 -83
  85. package/payload/platform/plugins/email/skills/email-ingest/SKILL.md +87 -0
  86. package/payload/platform/plugins/memory/PLUGIN.md +4 -4
  87. package/payload/platform/plugins/memory/mcp/dist/index.js +40 -41
  88. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  89. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js +2 -2
  90. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js.map +1 -1
  91. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts +3 -3
  92. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts.map +1 -1
  93. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js +6 -6
  94. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js.map +1 -1
  95. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js +1 -1
  96. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js.map +1 -1
  97. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts +2 -2
  98. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js +2 -2
  99. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts +1 -1
  100. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts.map +1 -1
  101. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js +3 -3
  102. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js.map +1 -1
  103. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js +2 -2
  104. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js.map +1 -1
  105. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js +8 -8
  106. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js.map +1 -1
  107. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js +2 -2
  108. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js.map +1 -1
  109. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts +1 -1
  110. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts.map +1 -1
  111. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js +2 -2
  112. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js.map +1 -1
  113. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts +35 -0
  114. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts.map +1 -0
  115. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js +80 -0
  116. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js.map +1 -0
  117. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts +1 -1
  118. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js +8 -8
  119. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js.map +1 -1
  120. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts +1 -1
  121. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts.map +1 -1
  122. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js +2 -2
  123. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js.map +1 -1
  124. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.d.ts +1 -1
  125. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.js +1 -1
  126. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +1 -1
  127. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts.map +1 -1
  128. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +2 -2
  129. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js.map +1 -1
  130. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +2 -2
  131. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  132. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +1 -1
  133. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
  134. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +11 -11
  135. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
  136. package/payload/platform/plugins/memory/mcp/scripts/backfill-typed-edges.ts +1 -1
  137. package/payload/platform/plugins/memory/mcp/scripts/graph/fixture.cypher +1 -1
  138. package/payload/platform/plugins/memory/references/graph-primitives.md +1 -1
  139. package/payload/platform/plugins/memory/references/schema-base.md +4 -4
  140. package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +1 -1
  141. package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
  142. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +2 -2
  143. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  144. package/payload/platform/plugins/work/mcp/dist/index.js +2 -2
  145. package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
  146. package/payload/platform/plugins/work/mcp/dist/tools/project-create.js +6 -6
  147. package/payload/platform/plugins/work/mcp/dist/tools/project-create.js.map +1 -1
  148. package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts +1 -1
  149. package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts.map +1 -1
  150. package/payload/platform/plugins/work/mcp/dist/tools/session-list.js +1 -1
  151. package/payload/platform/plugins/work/mcp/dist/tools/session-list.js.map +1 -1
  152. package/payload/platform/plugins/x-import/references/archive-shape.md +2 -2
  153. package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +3 -3
  154. package/payload/platform/scripts/admin-persist-audit.ts +18 -18
  155. package/payload/platform/scripts/identity-forbidden-token-check.mjs +2 -0
  156. package/payload/platform/scripts/seed-neo4j.sh +1 -0
  157. package/payload/platform/scripts/smoke-boot-services.sh +191 -41
  158. package/payload/platform/services/claude-session-manager/dist/http-server.js +3 -3
  159. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  160. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +3 -3
  161. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +4 -4
  162. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  163. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
  164. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +2 -0
  165. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
  166. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  167. package/payload/server/{chunk-AXOL2PPG.js → chunk-3TRIXQSJ.js} +101 -101
  168. package/payload/server/maxy-edge.js +1 -1
  169. package/payload/server/public/assets/{admin-DJW5VnQ1.js → admin-Dal5FWaD.js} +24 -24
  170. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Breg9-99.js → architectureDiagram-Q4EWVU46-Do2zYONG.js} +1 -1
  171. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DXf1_673.js → blockDiagram-DXYQGD6D-DpIX_bRu.js} +1 -1
  172. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-CSZ36W4-.js → c4Diagram-AHTNJAMY-Cz335ZSY.js} +1 -1
  173. package/payload/server/public/assets/channel-PC4_IjI1.js +1 -0
  174. package/payload/server/public/assets/{chunk-336JU56O-DsrLk2eK.js → chunk-336JU56O-Dmknn3Wo.js} +2 -2
  175. package/payload/server/public/assets/{chunk-426QAEUC-JpNfNf81.js → chunk-426QAEUC-ClfGjizN.js} +1 -1
  176. package/payload/server/public/assets/{chunk-4TB4RGXK-DmClEAD0.js → chunk-4TB4RGXK-BPKctJ5c.js} +1 -1
  177. package/payload/server/public/assets/{chunk-5FUZZQ4R-BI9blW3N.js → chunk-5FUZZQ4R-BWDCO9zw.js} +1 -1
  178. package/payload/server/public/assets/{chunk-5PVQY5BW-BbgttEFO.js → chunk-5PVQY5BW-BE34_Db0.js} +1 -1
  179. package/payload/server/public/assets/{chunk-EDXVE4YY-BX_LCFOx.js → chunk-EDXVE4YY-BysA-_6v.js} +1 -1
  180. package/payload/server/public/assets/{chunk-ENJZ2VHE-Bb7EoD0w.js → chunk-ENJZ2VHE-BMVyMsqA.js} +1 -1
  181. package/payload/server/public/assets/{chunk-ICPOFSXX-DH8uQk-s.js → chunk-ICPOFSXX-C5KRdLV4.js} +1 -1
  182. package/payload/server/public/assets/{chunk-OYMX7WX6-FH5kgXsw.js → chunk-OYMX7WX6-DVZD-AVc.js} +1 -1
  183. package/payload/server/public/assets/{chunk-U2HBQHQK-D_ljlkHr.js → chunk-U2HBQHQK-DYmQdx8x.js} +1 -1
  184. package/payload/server/public/assets/{chunk-X2U36JSP-BX3EmZvm.js → chunk-X2U36JSP-DrZenIl3.js} +1 -1
  185. package/payload/server/public/assets/{chunk-YZCP3GAM-Vu7-E93h.js → chunk-YZCP3GAM-CDuGbvMq.js} +1 -1
  186. package/payload/server/public/assets/{chunk-ZZ45TVLE-CwjhNPX5.js → chunk-ZZ45TVLE-COztbiu5.js} +1 -1
  187. package/payload/server/public/assets/classDiagram-6PBFFD2Q-B_pMa-SX.js +1 -0
  188. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BdBAgF20.js +1 -0
  189. package/payload/server/public/assets/clone-CkNt9L9r.js +1 -0
  190. package/payload/server/public/assets/{dagre-Ce6gsj0C.js → dagre-Cv9Ib2OM.js} +1 -1
  191. package/payload/server/public/assets/{dagre-KV5264BT-BaMGpsoy.js → dagre-KV5264BT-CoEd61KZ.js} +1 -1
  192. package/payload/server/public/assets/{data-BHASh0_Y.js → data-DbSORCl4.js} +1 -1
  193. package/payload/server/public/assets/{diagram-5BDNPKRD-CHEE9rjq.js → diagram-5BDNPKRD-WXNzw3uW.js} +1 -1
  194. package/payload/server/public/assets/{diagram-G4DWMVQ6-C98sZLW1.js → diagram-G4DWMVQ6-C6IuQ2VV.js} +1 -1
  195. package/payload/server/public/assets/{diagram-MMDJMWI5-DNvMGsTZ.js → diagram-MMDJMWI5-CdJdir5A.js} +1 -1
  196. package/payload/server/public/assets/{diagram-TYMM5635-Cdte4IBa.js → diagram-TYMM5635-DxWKQH5T.js} +1 -1
  197. package/payload/server/public/assets/{erDiagram-SMLLAGMA-C9VZsWXK.js → erDiagram-SMLLAGMA-C9fvs33K.js} +1 -1
  198. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-tuP5fzzR.js → flowDiagram-DWJPFMVM-BO7Yrbqv.js} +1 -1
  199. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-SJgRPUwx.js → ganttDiagram-T4ZO3ILL-CQJyWBZq.js} +1 -1
  200. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DU_cI_50.js → gitGraphDiagram-UUTBAWPF-DZfQHrYw.js} +1 -1
  201. package/payload/server/public/assets/{graph-labels-DXlmm1og.js → graph-labels-BBB5jsZk.js} +1 -1
  202. package/payload/server/public/assets/{graph-BhEI09tF.js → graph-ys_joP2o.js} +1 -1
  203. package/payload/server/public/assets/{graphlib-D_nAsvmx.js → graphlib-C40H-Q5E.js} +1 -1
  204. package/payload/server/public/assets/{infoDiagram-42DDH7IO-Cj2Y19m6.js → infoDiagram-42DDH7IO-CakfV5f9.js} +1 -1
  205. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DMc1xq1y.js → ishikawaDiagram-UXIWVN3A-CPuBPyfa.js} +1 -1
  206. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-C4CRAQma.js → journeyDiagram-VCZTEJTY-zpZm2Mmo.js} +1 -1
  207. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CTr4AldU.js → kanban-definition-6JOO6SKY-DfJduQCo.js} +1 -1
  208. package/payload/server/public/assets/{line-Btlm_IAl.js → line-BpYQqO5R.js} +1 -1
  209. package/payload/server/public/assets/{mermaid-parser.core-DXFdj_y1.js → mermaid-parser.core-C5Mwi14D.js} +1 -1
  210. package/payload/server/public/assets/{mermaid.core-DFBhoCr5.js → mermaid.core-D8qBtvvT.js} +3 -3
  211. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-r9gVQybo.js → mindmap-definition-QFDTVHPH-Bli9JhIN.js} +1 -1
  212. package/payload/server/public/assets/{page-CDWu1Aft.js → page--bl5Y7ZI.js} +2 -2
  213. package/payload/server/public/assets/page-CwmZ76U7.js +1 -0
  214. package/payload/server/public/assets/{pieDiagram-DEJITSTG-CHKZjSaH.js → pieDiagram-DEJITSTG-MsLXTSLg.js} +1 -1
  215. package/payload/server/public/assets/{public-DyGWgfaZ.js → public-DltgEfA9.js} +2 -2
  216. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CSGR1HJr.js → quadrantDiagram-34T5L4WZ-De1sh2K0.js} +1 -1
  217. package/payload/server/public/assets/{requirementDiagram-MS252O5E-DZ6hX9D6.js → requirementDiagram-MS252O5E-D5Sfg1t_.js} +1 -1
  218. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DbZBKh0m.js → sankeyDiagram-XADWPNL6-DHA3LIbv.js} +1 -1
  219. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BHHpb8dt.js → sequenceDiagram-FGHM5R23-BE_QlG1B.js} +1 -1
  220. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DQ1jiLB4.js → stateDiagram-FHFEXIEX-NIwp3F4u.js} +1 -1
  221. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-pfk2F6st.js +1 -0
  222. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BlGiEU7p.js → timeline-definition-GMOUNBTQ-CPE9jyDF.js} +1 -1
  223. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-DmEH-hsB.js → vennDiagram-DHZGUBPP-CKfoyYmH.js} +1 -1
  224. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-C7KJJ40d.js → wardleyDiagram-NUSXRM2D-B9yJek-o.js} +1 -1
  225. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-JDnusCaa.js → xychartDiagram-5P7HB3ND-DuCcSLqX.js} +1 -1
  226. package/payload/server/public/data.html +3 -3
  227. package/payload/server/public/graph.html +3 -3
  228. package/payload/server/public/index.html +4 -4
  229. package/payload/server/public/public.html +1 -1
  230. package/payload/server/server.js +133 -133
  231. package/payload/server/public/assets/channel-BmZnt3PP.js +0 -1
  232. package/payload/server/public/assets/classDiagram-6PBFFD2Q-kmMLFUpV.js +0 -1
  233. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BV7Ae8ct.js +0 -1
  234. package/payload/server/public/assets/clone-B5eqoN9I.js +0 -1
  235. package/payload/server/public/assets/page-cyvshX4Z.js +0 -1
  236. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CByT2RzF.js +0 -1
@@ -26,13 +26,13 @@
26
26
  # "additionalContext":"..."}}` whose additionalContext begins with
27
27
  # `[system: pre-turn-graph-pass-hook]`, names `database-operator` as
28
28
  # the dispatch target, carries a `<prior-writes>` block with the
29
- # fetched node, interpolates conversationId from CONVERSATION_NODE_ID,
29
+ # fetched node, interpolates sessionId from SESSION_NODE_ID,
30
30
  # and carries NO `<conversation>` block (admin has the turn already).
31
31
  # Dispatch log line carries `directive-shape=admin-walks`.
32
32
  # - Prior-writes fetch fails (context endpoint 500): exit 0, dispatch
33
33
  # still fires, `<prior-writes>` block resolves to `(none)`.
34
- # - CONVERSATION_NODE_ID unset: exit 0, additionalContext names
35
- # `conversationId: <unset>`, and no GET to /api/admin/post-turn-context
34
+ # - SESSION_NODE_ID unset: exit 0, additionalContext names
35
+ # `sessionId: <unset>`, and no GET to /api/admin/post-turn-context
36
36
  # is attempted.
37
37
  # - UserPromptSubmit stdin-shape regression: a synthetic UserPromptSubmit
38
38
  # payload produces the documented stdout envelope; a stale Stop-shaped
@@ -125,7 +125,7 @@ PY
125
125
  }
126
126
 
127
127
  run_hook() {
128
- # Args: role, specialist, ui_port, conversation_node_id, stdin_json
128
+ # Args: role, specialist, ui_port, session_node_id, stdin_json
129
129
  local role="$1"; local specialist="$2"; local ui_port="$3"
130
130
  local conv="$4"; local stdin_json="$5"
131
131
  local stderr_file; stderr_file=$(mktemp); TMPFILES+=("$stderr_file")
@@ -137,7 +137,7 @@ run_hook() {
137
137
  env_cmd+=("MAXY_UI_INTERNAL_PORT=${ui_port}")
138
138
  fi
139
139
  if [[ -n "$conv" ]]; then
140
- env_cmd+=("CONVERSATION_NODE_ID=${conv}")
140
+ env_cmd+=("SESSION_NODE_ID=${conv}")
141
141
  fi
142
142
  env_cmd+=("ACCOUNT_ID=acct-test-0001")
143
143
  printf '%s' "$stdin_json" | "${env_cmd[@]}" bash "$HOOK" >"$stdout_file" 2>"$stderr_file"
@@ -328,14 +328,14 @@ fi
328
328
  if ! printf '%s' "$CTX_BODY" | grep -q 'database-operator'; then
329
329
  fail "case-5 additionalContext must name the database-operator dispatch target"
330
330
  fi
331
- if ! printf '%s' "$CTX_BODY" | grep -q "conversationId: ${CONV_ID}"; then
332
- fail "case-5 additionalContext must interpolate conversationId=${CONV_ID}"
331
+ if ! printf '%s' "$CTX_BODY" | grep -q "sessionId: ${CONV_ID}"; then
332
+ fail "case-5 additionalContext must interpolate sessionId=${CONV_ID}"
333
333
  fi
334
334
  if ! printf '%s' "$CTX_BODY" | grep -q 'KnowledgeDocument'; then
335
335
  fail "case-5 additionalContext <prior-writes> must include fetched labels"
336
336
  fi
337
- if ingest_lines | grep -qE "^dispatch sessionId=${OP_ID} conversationId=${CONV_ID} directive-shape=admin-walks "; then
338
- pass "case-5 dispatch path → exit 0 + JSON envelope with prior-writes, conversationId, admin-walks shape"
337
+ if ingest_lines | grep -qE "^dispatch claudeSessionId=${OP_ID} sessionId=${CONV_ID} directive-shape=admin-walks "; then
338
+ pass "case-5 dispatch path → exit 0 + JSON envelope with prior-writes, sessionId, admin-walks shape"
339
339
  else
340
340
  fail "case-5 expected dispatch log line with directive-shape=admin-walks, got: $(ingest_lines)"
341
341
  fi
@@ -356,7 +356,7 @@ else
356
356
  fi
357
357
 
358
358
  # ---------------------------------------------------------------------------
359
- # Case 7: CONVERSATION_NODE_ID unset → conversationId:<unset>, no context GET.
359
+ # Case 7: SESSION_NODE_ID unset → sessionId:<unset>, no context GET.
360
360
  # ---------------------------------------------------------------------------
361
361
  cat > "$CTX_FILE" <<'JSON'
362
362
  {"writes":[]}
@@ -365,12 +365,12 @@ JSON
365
365
  run_hook "admin" "" "$LISTENER_PORT" "" "$ENV_BASIC"
366
366
  [[ "$HOOK_RC" -eq 0 ]] || fail "case-7 expected rc=0, got $HOOK_RC"
367
367
  CTX_BODY=$(additional_context)
368
- if ! printf '%s' "$CTX_BODY" | grep -q 'conversationId: <unset>'; then
369
- fail "case-7 additionalContext must contain 'conversationId: <unset>'"
368
+ if ! printf '%s' "$CTX_BODY" | grep -q 'sessionId: <unset>'; then
369
+ fail "case-7 additionalContext must contain 'sessionId: <unset>'"
370
370
  fi
371
371
  GET_COUNT=$(context_get_count)
372
372
  if [[ "$GET_COUNT" == "0" ]]; then
373
- pass "case-7 CONVERSATION_NODE_ID unset → no GET /api/admin/post-turn-context attempted"
373
+ pass "case-7 SESSION_NODE_ID unset → no GET /api/admin/post-turn-context attempted"
374
374
  else
375
375
  fail "case-7 expected zero context GETs, got: $GET_COUNT"
376
376
  fi
@@ -194,7 +194,7 @@ fi
194
194
  # --- Case 5 (Task 177): ordered-turns happy path -----------------------
195
195
  # Transcript with four turns: user-A, asst-A-reply, user-B, asst-B-reply.
196
196
  # Envelope `turns` array must carry exactly that order, oldest first.
197
- # Envelope shape: { turns, conversationId, accountId, occurredAt } — no
197
+ # Envelope shape: { turns, sessionId, accountId, occurredAt } — no
198
198
  # top-level operatorMessage / assistantReply.
199
199
  ORDERED_TRANSCRIPT=$(mktemp); TMPFILES+=("$ORDERED_TRANSCRIPT")
200
200
  {
@@ -0,0 +1,242 @@
1
+ #!/usr/bin/env bash
2
+ # Shared plumbing for the two admin-side hooks that orchestrate admin-walked
3
+ # graph writes: `pre-turn-graph-pass.sh` (UserPromptSubmit) and
4
+ # `session-end-retrospective.sh` (Stop on operator end-intent). Task 439.
5
+ #
6
+ # Both hooks are the same process — same stdin parse, same role / specialist
7
+ # / transcript guards, same log-ingest envelope, same admin-walks contract
8
+ # dispatching per-write briefs to `database-operator`. Divergence across
9
+ # Tasks 303 → 412 → 425 → 430 → 282 made shared plumbing a recurring-bug
10
+ # surface; this file is the single body. Only the trigger-specific gating
11
+ # and the dispatch directive text live in each hook.
12
+ #
13
+ # Caller contract:
14
+ # 1. Set `AGP_LOG_TAG` to the hook's identifying tag before sourcing.
15
+ # `pre-turn-graph-pass` and `session-retrospective` are the two
16
+ # current values; the helper itself does not log under its own tag.
17
+ # 2. Source this file.
18
+ # 3. Call `agp_setup_logging`, `agp_read_stdin`, `agp_parse_stdin`,
19
+ # `agp_guard_role_specialist`, `agp_guard_transcript` in that order.
20
+ # Each guard exits 0 from inside the helper when its condition fires
21
+ # (sourced `exit` exits the caller).
22
+ # 4. After the guards return, the hook proceeds with its event-specific
23
+ # body (sentinel-grep + intent token for session-end; post-turn-context
24
+ # fetch + directive envelope for pre-turn).
25
+ #
26
+ # Globals set by the helper (read by callers):
27
+ # INPUT — raw stdin (empty when none piped)
28
+ # SESSION_ID — parsed `session_id` field, empty on parse failure
29
+ # TRANSCRIPT_PATH — parsed `transcript_path` field
30
+ # HOOK_EVENT_NAME — parsed `hook_event_name` field
31
+ # SESSION_ID_REPORTED — `$SESSION_ID` or the literal "unknown"
32
+ # UI_BASE — `http://127.0.0.1:${MAXY_UI_INTERNAL_PORT}`
33
+ # LOG_INGEST_URL — `${UI_BASE}/api/admin/log-ingest`
34
+ #
35
+ # Functions:
36
+ # agp_setup_logging — resolves UI port + URLs, or exits 0 with
37
+ # a stderr loud-fail when the port is unset
38
+ # (fail-open so a missing port never bricks
39
+ # the operator).
40
+ # agp_emit_log <line> — POSTs `{tag, level:"info", line}` to
41
+ # log-ingest; silent on network failure.
42
+ # agp_read_stdin — slurps stdin into `INPUT`, leaves it empty
43
+ # when no input is piped.
44
+ # agp_parse_stdin — populates `SESSION_ID`, `TRANSCRIPT_PATH`,
45
+ # `HOOK_EVENT_NAME`, `SESSION_ID_REPORTED`.
46
+ # agp_guard_role_specialist — exits 0 with `trigger-skipped` log on
47
+ # `role-not-admin` or `is-specialist`.
48
+ # agp_guard_transcript — exits 0 with `trigger-skipped` log on
49
+ # `empty-stdin` (when $1="require-stdin") or
50
+ # `missing-transcript`.
51
+
52
+ if [ -z "${AGP_LOG_TAG:-}" ]; then
53
+ echo "[admin-graph-pass-common] AGP_LOG_TAG not set by caller" >&2
54
+ exit 1
55
+ fi
56
+
57
+ agp_setup_logging() {
58
+ local ui_port="${MAXY_UI_INTERNAL_PORT:-}"
59
+ if [ -z "$ui_port" ]; then
60
+ echo "[${AGP_LOG_TAG}] trigger-skipped sessionId=unknown reason=missing-env env=MAXY_UI_INTERNAL_PORT" >&2
61
+ exit 0
62
+ fi
63
+ UI_BASE="http://127.0.0.1:${ui_port}"
64
+ LOG_INGEST_URL="${UI_BASE}/api/admin/log-ingest"
65
+ }
66
+
67
+ agp_emit_log() {
68
+ local line="$1"
69
+ curl -sS -o /dev/null -X POST \
70
+ -H 'Content-Type: application/json' \
71
+ --max-time 2 \
72
+ --data "$(AGP_TAG="$AGP_LOG_TAG" AGP_LINE="$line" python3 -c '
73
+ import os, json
74
+ print(json.dumps({"tag": os.environ["AGP_TAG"], "level": "info", "line": os.environ["AGP_LINE"]}))
75
+ ')" \
76
+ "$LOG_INGEST_URL" 2>/dev/null || true
77
+ }
78
+
79
+ agp_read_stdin() {
80
+ INPUT=""
81
+ if [ ! -t 0 ]; then
82
+ INPUT=$(cat)
83
+ fi
84
+ }
85
+
86
+ agp_parse_stdin() {
87
+ local parsed
88
+ parsed=$(printf '%s' "$INPUT" | python3 -c '
89
+ import sys, json
90
+ try:
91
+ d = json.load(sys.stdin)
92
+ sid = d.get("session_id", "") or ""
93
+ tpath = d.get("transcript_path", "") or ""
94
+ event = d.get("hook_event_name", "") or ""
95
+ print(f"{sid}\t{tpath}\t{event}")
96
+ except Exception:
97
+ print("\t\t")
98
+ ' 2>/dev/null)
99
+ SESSION_ID="${parsed%% *}"
100
+ local rest="${parsed#* }"
101
+ TRANSCRIPT_PATH="${rest%% *}"
102
+ HOOK_EVENT_NAME="${rest#* }"
103
+ SESSION_ID_REPORTED="${SESSION_ID:-unknown}"
104
+ }
105
+
106
+ agp_guard_role_specialist() {
107
+ if [ "${MAXY_SESSION_ROLE:-}" != "admin" ]; then
108
+ agp_emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=role-not-admin"
109
+ exit 0
110
+ fi
111
+ # Recursion guard. A specialist subagent dispatched via the Task tool
112
+ # (e.g. database-operator running the operator's graph writes) carries
113
+ # `MAXY_SPECIALIST=<name>` on the PTY env. Skip — the hooks only fire
114
+ # for the operator's own admin session.
115
+ #
116
+ # Invariant the PTY spawner is expected to honour: `MAXY_SPECIALIST` is
117
+ # either set to a non-empty specialist name OR absent. An explicit empty
118
+ # string from a wrapper would slip the recursion guard here (`-n ""` is
119
+ # false) — that would be a defect at the spawn site, not here.
120
+ if [ -n "${MAXY_SPECIALIST:-}" ]; then
121
+ agp_emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=is-specialist specialist=${MAXY_SPECIALIST}"
122
+ exit 0
123
+ fi
124
+ }
125
+
126
+ # Usage: agp_guard_transcript [require-stdin]
127
+ # Pass `require-stdin` (session-end-retrospective) to emit `empty-stdin` on a
128
+ # blank `INPUT`. The pre-turn-graph-pass hook calls without the flag because
129
+ # its `wrong-hook-event` guard already runs before this point and parse
130
+ # failure on a non-empty INPUT collapses to `missing-transcript` cleanly.
131
+ agp_guard_transcript() {
132
+ if [ "${1:-}" = "require-stdin" ] && [ -z "$INPUT" ]; then
133
+ agp_emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=empty-stdin"
134
+ exit 0
135
+ fi
136
+ if [ -z "$SESSION_ID" ] || [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
137
+ agp_emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=missing-transcript"
138
+ exit 0
139
+ fi
140
+ }
141
+
142
+ # Walks $TRANSCRIPT_PATH and reports, in one line on stdout:
143
+ # <real-user-present:yes|no>\t<matched-tool-name-or-empty>
144
+ # A "real user" record matches `session-end-retrospective.sh`'s `is_real_user`
145
+ # — `type=user, message.role=user`, content is a string OR a list with at
146
+ # least one non-`tool_result` block. `tool_result`-only user records are tool
147
+ # replies, never turn starts.
148
+ #
149
+ # Every assistant `tool_use` block that appears AFTER the latest real-user
150
+ # record is matched against the alternation passed as `$1` (an extended-regex
151
+ # alternation of literal `tool_use.name` values). The synthetic name
152
+ # `Task:<subagent_type>` is also matched, so callers can release on a
153
+ # `Task` tool_use with `input.subagent_type=<name>` by including
154
+ # `Task:<name>` in the alternation. Returns the first match encountered after
155
+ # the latest real-user record (oldest-first) so the release log carries the
156
+ # matched tool's actual name. Empty match means none of the release patterns
157
+ # appeared since the operator's last turn.
158
+ agp_scan_post_user_toolnames() {
159
+ local pattern="$1"
160
+ TRANSCRIPT_PATH="$TRANSCRIPT_PATH" AGP_PATTERN="$pattern" python3 - <<'PY'
161
+ import os, json, re
162
+
163
+ pattern = re.compile(os.environ["AGP_PATTERN"])
164
+ path = os.environ["TRANSCRIPT_PATH"]
165
+
166
+ def is_real_user(rec):
167
+ if not isinstance(rec, dict) or rec.get("type") != "user":
168
+ return False
169
+ msg = rec.get("message")
170
+ if not isinstance(msg, dict) or msg.get("role") != "user":
171
+ return False
172
+ content = msg.get("content")
173
+ if isinstance(content, str):
174
+ return True
175
+ if isinstance(content, list):
176
+ for b in content:
177
+ if isinstance(b, dict) and b.get("type") != "tool_result":
178
+ return True
179
+ return False
180
+ return True
181
+
182
+ def assistant_tool_use_names(rec):
183
+ if not isinstance(rec, dict) or rec.get("type") != "assistant":
184
+ return []
185
+ msg = rec.get("message", {}) or {}
186
+ if msg.get("role") != "assistant":
187
+ return []
188
+ content = msg.get("content")
189
+ if not isinstance(content, list):
190
+ return []
191
+ names = []
192
+ for b in content:
193
+ if isinstance(b, dict) and b.get("type") == "tool_use":
194
+ n = b.get("name")
195
+ if not isinstance(n, str):
196
+ continue
197
+ names.append(n)
198
+ if n == "Task":
199
+ inp = b.get("input")
200
+ if isinstance(inp, dict):
201
+ st = inp.get("subagent_type")
202
+ if isinstance(st, str) and st:
203
+ names.append(f"Task:{st}")
204
+ return names
205
+
206
+ records = []
207
+ try:
208
+ with open(path, "r", encoding="utf-8") as f:
209
+ for raw in f:
210
+ raw = raw.strip()
211
+ if not raw:
212
+ continue
213
+ try:
214
+ records.append(json.loads(raw))
215
+ except Exception:
216
+ continue
217
+ except Exception:
218
+ print("no\t")
219
+ raise SystemExit(0)
220
+
221
+ latest_user_idx = -1
222
+ for i in range(len(records) - 1, -1, -1):
223
+ if is_real_user(records[i]):
224
+ latest_user_idx = i
225
+ break
226
+
227
+ if latest_user_idx == -1:
228
+ print("no\t")
229
+ raise SystemExit(0)
230
+
231
+ matched = ""
232
+ for r in records[latest_user_idx + 1:]:
233
+ for n in assistant_tool_use_names(r):
234
+ if pattern.fullmatch(n):
235
+ matched = n
236
+ break
237
+ if matched:
238
+ break
239
+
240
+ print(f"yes\t{matched}")
241
+ PY
242
+ }
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env bash
2
+ # Stop hook — per-turn gate. Task 440.
3
+ #
4
+ # Mirrors `session-end-retrospective.sh`'s structural primitive (exit 2 +
5
+ # stderr instruction + sentinel-grep release) but fires on every admin turn
6
+ # end rather than only on operator end-intent. Closes the gap left when
7
+ # Task 425 moved the per-turn graph pass off Stop onto UserPromptSubmit:
8
+ # the UserPromptSubmit `additionalContext` directive carries the prior-writes
9
+ # skip-list and the instruction, but admin can silently drop the directive
10
+ # because UserPromptSubmit's only blocking shape erases the prompt without
11
+ # feeding stderr to Claude. The structural fix is here — Stop's exit-2
12
+ # stderr-to-Claude contract gives the gate a release path admin can act on.
13
+ #
14
+ # Release conditions, evaluated against the operator's JSONL since the
15
+ # latest real-user message (string content OR a content list with at least
16
+ # one non-`tool_result` block):
17
+ # A. admin dispatched the writes — a `Task` `tool_use` whose
18
+ # `input.subagent_type` is `database-operator` appeared.
19
+ # B. admin declined the writes — a `tool_use` whose `name` is exactly
20
+ # `mcp__admin__pre-turn-graph-pass-skip` appeared. The sentinel takes a
21
+ # `reason` string (free-form, e.g. `no-new-entities`,
22
+ # `turn-is-acknowledgement`); the tool records the call for audit but
23
+ # takes no graph action.
24
+ #
25
+ # Either release path emits `gate-released sessionId=<id> via=<dispatch|skip-sentinel>`
26
+ # and exits 0. Both Stop-hook tags emit independently and compose: the
27
+ # session-end retrospective gates only on `/end` intent and uses its own
28
+ # sentinel; this hook gates every turn and uses the two release patterns
29
+ # above.
30
+ #
31
+ # Recursion guard — the shared `agp_guard_role_specialist` skips when
32
+ # `MAXY_SPECIALIST` is set, so the database-operator subagent's own turn
33
+ # end never re-triggers this gate.
34
+ #
35
+ # Loop-safety — once release path A or B fires, the matching tool_use sits
36
+ # in the JSONL and every subsequent Stop on the same operator-prompt window
37
+ # sees it and exits 0 with `gate-released`. The Task 412 loop case is
38
+ # avoided because the release decision is JSONL-based, never a re-fire of
39
+ # the directive.
40
+ #
41
+ # Input: Claude Code's Stop hook stdin shape
42
+ # { "session_id": "<intrinsic>", "transcript_path": "<jsonl path>", ... }
43
+
44
+ set -uo pipefail
45
+
46
+ AGP_LOG_TAG="per-turn-graph-pass-gate"
47
+ AGP_LIB="$(dirname "$0")/lib/admin-graph-pass-common.sh"
48
+ if [ ! -f "$AGP_LIB" ]; then
49
+ echo "[${AGP_LOG_TAG}] trigger-skipped sessionId=unknown reason=missing-helper path=${AGP_LIB}" >&2
50
+ exit 0
51
+ fi
52
+ # shellcheck source=lib/admin-graph-pass-common.sh
53
+ source "$AGP_LIB"
54
+
55
+ agp_setup_logging
56
+ agp_read_stdin
57
+ agp_parse_stdin
58
+ agp_guard_role_specialist
59
+ agp_guard_transcript require-stdin
60
+
61
+ # Release alternation: the MCP-prefixed skip-sentinel name, or a Task
62
+ # tool_use with `input.subagent_type=database-operator` (matched as the
63
+ # synthetic name `Task:database-operator` by the helper).
64
+ RELEASE_PATTERN='mcp__admin__pre-turn-graph-pass-skip|Task:database-operator'
65
+
66
+ INSPECTION=$(agp_scan_post_user_toolnames "$RELEASE_PATTERN")
67
+ USER_PRESENT="${INSPECTION%% *}"
68
+ MATCHED_NAME="${INSPECTION#* }"
69
+
70
+ if [ "$USER_PRESENT" != "yes" ]; then
71
+ # No real-user message in the transcript yet — e.g. the SessionStart
72
+ # bootstrap turn, an empty transcript, or a session that only contains
73
+ # tool_result-shaped user records. Nothing to gate against.
74
+ agp_emit_log "trigger-skipped sessionId=${SESSION_ID} reason=no-real-user"
75
+ exit 0
76
+ fi
77
+
78
+ if [ -n "$MATCHED_NAME" ]; then
79
+ case "$MATCHED_NAME" in
80
+ Task:database-operator)
81
+ VIA="dispatch"
82
+ ;;
83
+ mcp__admin__pre-turn-graph-pass-skip)
84
+ VIA="skip-sentinel"
85
+ ;;
86
+ *)
87
+ VIA="unknown"
88
+ ;;
89
+ esac
90
+ agp_emit_log "gate-released sessionId=${SESSION_ID} via=${VIA}"
91
+ exit 0
92
+ fi
93
+
94
+ agp_emit_log "gate-blocked sessionId=${SESSION_ID} reason=sentinel-absent"
95
+
96
+ cat >&2 <<'INSTRUCTION'
97
+ Before this turn closes, do the per-turn graph pass. Scan the operator's latest message for any new graph-worthy content not already covered by the prior-writes block in this turn's pre-turn-graph-pass directive — mentions of named entities, ideas or learnings the operator stated, contacts named for the first time, tasks the operator committed to, decisions, anything the schema admits.
98
+
99
+ For each candidate write, dispatch one Task to the `database-operator` specialist with a brief that names the label, the relevant properties, and (when attaching to an existing node) the elementId from the prior-writes list. Skip writes the prior-writes list already covers.
100
+
101
+ If the turn supports no new writes, call the `pre-turn-graph-pass-skip` MCP tool with a short `reason` (e.g. `no-new-entities`, `turn-is-acknowledgement`) so the gate releases. Calling that tool is the deterministic signal that you considered the turn and chose not to write.
102
+
103
+ Either path releases this gate and lets the turn close. Do not surface this dispatch in your reply to the operator.
104
+ INSTRUCTION
105
+
106
+ exit 2
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # UserPromptSubmit hook — pre-turn graph pass. Tasks 425, 430.
2
+ # UserPromptSubmit hook — pre-turn graph pass. Tasks 425, 430, 439.
3
3
  #
4
4
  # Fires once per admin-agent operator prompt submission. Emits a
5
5
  # directive into the admin agent's `additionalContext` that instructs
@@ -9,32 +9,19 @@
9
9
  # per candidate write. Admin is the session-walker; the specialist only
10
10
  # sees a narrowly-scoped per-write brief, never the conversation.
11
11
  #
12
- # Task 430 corrects the Task 425 orchestration shape. The Task 425 hook
13
- # packaged the full conversation blob into the specialist's prompt; that
14
- # collapsed the data channel and the instruction channel into one
15
- # context, so operator prose pattern-matching as a writer-binding
16
- # instruction ("memory-update is denied this session") was treated as
17
- # binding and the pass self-denied. Same failure class as the writer-POV
18
- # schema doctrine read as binding the agent (Task 199 / 995). The
19
- # session-end retrospective never had this defect because admin walked
20
- # the transcript itself and dispatched per-item briefs to the
21
- # specialist — Task 430 brings the per-turn pass to the same shape.
12
+ # Task 430 corrects the Task 425 orchestration shape (the Task 425 hook
13
+ # packaged the full conversation blob into the specialist's prompt and
14
+ # collapsed data and instruction channels into one context, so operator
15
+ # prose pattern-matching as a writer-binding instruction was treated as
16
+ # binding and the pass self-denied same failure class as the writer-POV
17
+ # schema doctrine read as binding the agent, Tasks 199 / 995).
22
18
  #
23
- # Supersedes Task 412's Stop-hook registration. The Stop hook fired on
24
- # every assistant `end_turn`, including the agent's own ack after the
25
- # dispatch, producing an unbounded loop. Firing on `UserPromptSubmit`
26
- # fires once per operator turn and removes the loop primitive entirely.
27
- # The agent's response to the most recent operator turn is not covered
28
- # by a per-turn pass until the next operator turn; the
29
- # `session-end-retrospective.sh` Stop hook walks the full transcript at
30
- # `/end` and picks up the final assistant reply.
31
- #
32
- # The doctrinal early exits remain:
33
- # - MAXY_SESSION_ROLE must equal "admin" → reason=role-not-admin
34
- # - MAXY_SPECIALIST must be empty → reason=is-specialist
35
- # `missing-transcript` is retained as a safety exit (the prior-writes
36
- # context fetch still needs a real session). `wrong-hook-event` rejects
37
- # stale Stop-shaped fires.
19
+ # Task 439 converges the shared plumbing stdin parse, role / specialist
20
+ # / transcript guards, log-ingest envelope with `session-end-retrospective.sh`
21
+ # via `lib/admin-graph-pass-common.sh`. The only event-specific code in
22
+ # this hook is the wrong-hook-event check, the post-turn-context fetch,
23
+ # the directive-body composition, and the UserPromptSubmit JSON envelope
24
+ # emission on stdout.
38
25
  #
39
26
  # Input: Claude Code's UserPromptSubmit hook stdin shape
40
27
  # { "session_id": "<intrinsic>", "transcript_path": "<jsonl path>",
@@ -46,76 +33,45 @@
46
33
  # Output: stdout JSON of the documented UserPromptSubmit shape:
47
34
  # { "hookSpecificOutput": { "hookEventName": "UserPromptSubmit",
48
35
  # "additionalContext": "<directive body>" } }
49
- # exit 0. The directive body is self-contained: it names the dispatch
50
- # shape, the skip-list, and the silent-execution rule at fire time, so
51
- # the admin agent does not need a matching IDENTITY.md section to act
52
- # on it (Task 437 — IDENTITY is operator-facing prose, not a protocol
53
- # manual). The agent performs the per-write dispatches as a background
54
- # pass and then continues with its normal response to the operator.
36
+ # exit 0.
55
37
 
56
38
  set -uo pipefail
57
39
 
58
- UI_PORT="${MAXY_UI_INTERNAL_PORT:-}"
59
- if [ -z "$UI_PORT" ]; then
60
- echo "[pre-turn-graph-pass] trigger-skipped sessionId=unknown reason=missing-env env=MAXY_UI_INTERNAL_PORT" >&2
40
+ AGP_LOG_TAG="pre-turn-graph-pass"
41
+ AGP_LIB="$(dirname "$0")/lib/admin-graph-pass-common.sh"
42
+ if [ ! -f "$AGP_LIB" ]; then
43
+ echo "[${AGP_LOG_TAG}] trigger-skipped sessionId=unknown reason=missing-helper path=${AGP_LIB}" >&2
61
44
  exit 0
62
45
  fi
63
- UI_BASE="http://127.0.0.1:${UI_PORT}"
64
- LOG_INGEST_URL="${UI_BASE}/api/admin/log-ingest"
65
- CONTEXT_URL="${UI_BASE}/api/admin/post-turn-context"
46
+ # shellcheck source=lib/admin-graph-pass-common.sh
47
+ source "$AGP_LIB"
66
48
 
67
- emit_log() {
68
- local line="$1"
69
- curl -sS -o /dev/null -X POST \
70
- -H 'Content-Type: application/json' \
71
- --max-time 2 \
72
- --data "$(python3 -c '
73
- import sys, json
74
- print(json.dumps({"tag": "pre-turn-graph-pass", "level": "info", "line": sys.argv[1]}))
75
- ' "$line")" \
76
- "$LOG_INGEST_URL" 2>/dev/null || true
77
- }
78
-
79
- INPUT=""
80
- if [ ! -t 0 ]; then
81
- INPUT=$(cat)
82
- fi
49
+ agp_setup_logging
50
+ CONTEXT_URL="${UI_BASE}/api/admin/post-turn-context"
83
51
 
84
- PARSED=$(printf '%s' "$INPUT" | python3 -c '
85
- import sys, json
86
- try:
87
- d = json.load(sys.stdin)
88
- sid = d.get("session_id", "") or ""
89
- tpath = d.get("transcript_path", "") or ""
90
- event = d.get("hook_event_name", "") or ""
91
- print(f"{sid}\t{tpath}\t{event}")
92
- except Exception:
93
- print("\t\t")
94
- ' 2>/dev/null)
95
- SESSION_ID="${PARSED%% *}"
96
- REST="${PARSED#* }"
97
- TRANSCRIPT_PATH="${REST%% *}"
98
- HOOK_EVENT_NAME="${REST#* }"
99
- SESSION_ID_REPORTED="${SESSION_ID:-unknown}"
52
+ agp_read_stdin
53
+ agp_parse_stdin
100
54
 
55
+ # Wrong-hook-event guard. Pre-turn-graph-pass is UserPromptSubmit-only;
56
+ # reject stale Stop-shaped payloads before the role / transcript guards
57
+ # run so the operator observes a `wrong-hook-event` skip line, not a
58
+ # misleading `missing-transcript`.
101
59
  if [ -n "$HOOK_EVENT_NAME" ] && [ "$HOOK_EVENT_NAME" != "UserPromptSubmit" ]; then
102
- emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=wrong-hook-event event=${HOOK_EVENT_NAME}"
103
- exit 0
104
- fi
105
- if [ "${MAXY_SESSION_ROLE:-}" != "admin" ]; then
106
- emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=role-not-admin"
107
- exit 0
108
- fi
109
- if [ -n "${MAXY_SPECIALIST:-}" ]; then
110
- emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=is-specialist specialist=${MAXY_SPECIALIST}"
111
- exit 0
112
- fi
113
- if [ -z "$SESSION_ID" ] || [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
114
- emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=missing-transcript"
60
+ agp_emit_log "trigger-skipped sessionId=${SESSION_ID_REPORTED} reason=wrong-hook-event event=${HOOK_EVENT_NAME}"
115
61
  exit 0
116
62
  fi
117
63
 
118
- CONVERSATION_ID="${CONVERSATION_NODE_ID:-}"
64
+ agp_guard_role_specialist
65
+ agp_guard_transcript
66
+
67
+ # Task 429 — the env var carries the graph `:Conversation.sessionId`.
68
+ # Claude Code's own stdin `session_id` field (parsed into `SESSION_ID`
69
+ # by `agp_parse_stdin`) is a distinct identifier (JSONL filename); one
70
+ # graph sessionId can map to many Claude session ids. Shadow the lib's
71
+ # `SESSION_ID` into `CLAUDE_SESSION_ID` so the rest of this hook can
72
+ # refer to the graph identifier as `SESSION_ID` without collision.
73
+ CLAUDE_SESSION_ID="$SESSION_ID"
74
+ SESSION_ID="${SESSION_NODE_ID:-}"
119
75
 
120
76
  # Fetch the actual content of every node already written under this
121
77
  # conversation, account-scoped. The route runs loopback-only — the hook
@@ -125,9 +81,9 @@ CONVERSATION_ID="${CONVERSATION_NODE_ID:-}"
125
81
  # elementId admin already resolved when attaching to an existing node).
126
82
  PRIOR_WRITES="(none)"
127
83
  PRIOR_WRITES_COUNT=0
128
- if [ -n "$CONVERSATION_ID" ]; then
84
+ if [ -n "$SESSION_ID" ]; then
129
85
  CONTEXT_JSON=$(curl -sS --max-time 5 -G \
130
- --data-urlencode "conversationId=${CONVERSATION_ID}" \
86
+ --data-urlencode "sessionId=${SESSION_ID}" \
131
87
  --data-urlencode "accountId=${ACCOUNT_ID:-}" \
132
88
  "$CONTEXT_URL" 2>/dev/null || echo '')
133
89
  if [ -n "$CONTEXT_JSON" ]; then
@@ -171,8 +127,8 @@ fi
171
127
  # Compose the directive body before logging so contextBytes reflects
172
128
  # the actual payload size handed to admin (skip-list + directive prose).
173
129
  DIRECTIVE_BODY=$(ACCOUNT_ID_OUT="${ACCOUNT_ID:-<unset>}" \
174
- SESSION_ID_OUT="${SESSION_ID}" \
175
- CONVERSATION_ID_OUT="${CONVERSATION_ID:-<unset>}" \
130
+ CLAUDE_SESSION_ID_OUT="${CLAUDE_SESSION_ID}" \
131
+ SESSION_ID_OUT="${SESSION_ID:-<unset>}" \
176
132
  PRIOR_WRITES_OUT="${PRIOR_WRITES}" \
177
133
  python3 - <<'PY'
178
134
  import os
@@ -186,8 +142,8 @@ body = (
186
142
  "If the turn supports no new writes, dispatch nothing. "
187
143
  "Do not surface these dispatches in your reply to the operator. After the dispatches return, continue with your normal response to the operator's prompt.\n\n"
188
144
  f"accountId: {os.environ['ACCOUNT_ID_OUT']}\n"
189
- f"sessionId: {os.environ['SESSION_ID_OUT']}\n"
190
- f"conversationId: {os.environ['CONVERSATION_ID_OUT']}\n\n"
145
+ f"claudeSessionId: {os.environ['CLAUDE_SESSION_ID_OUT']}\n"
146
+ f"sessionId: {os.environ['SESSION_ID_OUT']}\n\n"
191
147
  "<prior-writes>\n"
192
148
  f"{os.environ['PRIOR_WRITES_OUT']}\n"
193
149
  "</prior-writes>\n"
@@ -197,7 +153,7 @@ PY
197
153
  )
198
154
  CONTEXT_BYTES=${#DIRECTIVE_BODY}
199
155
 
200
- emit_log "dispatch sessionId=${SESSION_ID} conversationId=${CONVERSATION_ID:-<unset>} directive-shape=admin-walks priorWritesCount=${PRIOR_WRITES_COUNT} contextBytes=${CONTEXT_BYTES} ms=0"
156
+ agp_emit_log "dispatch claudeSessionId=${CLAUDE_SESSION_ID} sessionId=${SESSION_ID:-<unset>} directive-shape=admin-walks priorWritesCount=${PRIOR_WRITES_COUNT} contextBytes=${CONTEXT_BYTES} ms=0"
201
157
 
202
158
  # Emit the documented UserPromptSubmit JSON envelope on stdout. Python
203
159
  # handles JSON encoding so embedded newlines, quotes, and backslashes