@rubytech/create-maxy-code 0.1.51 → 0.1.57

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 (304) hide show
  1. package/dist/__tests__/platform-port-stamp.test.js +24 -0
  2. package/dist/index.js +5 -2
  3. package/dist/port-resolution.js +2 -0
  4. package/package.json +1 -1
  5. package/payload/platform/lib/require-port-env/dist/index.d.ts +31 -0
  6. package/payload/platform/lib/require-port-env/dist/index.d.ts.map +1 -0
  7. package/payload/platform/lib/require-port-env/dist/index.js +52 -0
  8. package/payload/platform/lib/require-port-env/dist/index.js.map +1 -0
  9. package/payload/platform/lib/require-port-env/src/index.ts +56 -0
  10. package/payload/platform/lib/require-port-env/tsconfig.json +8 -0
  11. package/payload/platform/package-lock.json +0 -1
  12. package/payload/platform/package.json +2 -3
  13. package/payload/platform/plugins/admin/PLUGIN.md +16 -3
  14. package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +183 -144
  15. package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +180 -99
  16. package/payload/platform/plugins/admin/mcp/dist/index.js +20 -12
  17. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  18. package/payload/platform/plugins/brochures/PLUGIN.md +2 -0
  19. package/payload/platform/plugins/brochures/skills/property-market-report/SKILL.md +100 -0
  20. package/payload/platform/plugins/brochures/skills/property-market-report/references/render.py +267 -0
  21. package/payload/platform/plugins/brochures/skills/property-market-report/references/template.html +266 -0
  22. package/payload/platform/plugins/brochures/skills/property-socials/SKILL.md +141 -0
  23. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.d.ts.map +1 -1
  24. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js +2 -1
  25. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js.map +1 -1
  26. package/payload/platform/plugins/docs/references/admin-session.md +33 -3
  27. package/payload/platform/plugins/docs/references/deployment.md +25 -0
  28. package/payload/platform/plugins/docs/references/internals.md +26 -0
  29. package/payload/platform/plugins/docs/references/platform.md +3 -1
  30. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  31. package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
  32. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts.map +1 -1
  33. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js +2 -1
  34. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js.map +1 -1
  35. package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
  36. package/payload/platform/plugins/memory/PLUGIN.md +1 -1
  37. package/payload/platform/plugins/memory/mcp/dist/index.js +6 -1
  38. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  39. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts +2 -0
  40. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts.map +1 -0
  41. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +107 -0
  42. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -0
  43. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts +4 -2
  44. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
  45. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +22 -13
  46. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
  47. package/payload/platform/plugins/memory/references/graph-primitives.md +42 -0
  48. package/payload/platform/plugins/memory/skills/concept-synthesis/SKILL.md +1 -1
  49. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +2 -2
  50. package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +1 -1
  51. package/payload/platform/plugins/property-data/.claude-plugin/plugin.json +17 -0
  52. package/payload/platform/plugins/property-data/PLUGIN.md +100 -0
  53. package/payload/platform/plugins/property-data/mcp/dist/index.d.ts +2 -0
  54. package/payload/platform/plugins/property-data/mcp/dist/index.d.ts.map +1 -0
  55. package/payload/platform/plugins/property-data/mcp/dist/index.js +153 -0
  56. package/payload/platform/plugins/property-data/mcp/dist/index.js.map +1 -0
  57. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts +3 -0
  58. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts.map +1 -0
  59. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js +72 -0
  60. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js.map +1 -0
  61. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts +5 -0
  62. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts.map +1 -0
  63. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js +38 -0
  64. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js.map +1 -0
  65. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts +29 -0
  66. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts.map +1 -0
  67. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js +112 -0
  68. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js.map +1 -0
  69. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts +14 -0
  70. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts.map +1 -0
  71. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js +20 -0
  72. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js.map +1 -0
  73. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts +4 -0
  74. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts.map +1 -0
  75. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js +19 -0
  76. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js.map +1 -0
  77. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts +4 -0
  78. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts.map +1 -0
  79. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js +10 -0
  80. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js.map +1 -0
  81. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts +5 -0
  82. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts.map +1 -0
  83. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js +43 -0
  84. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js.map +1 -0
  85. package/payload/platform/plugins/property-data/mcp/package-lock.json +2566 -0
  86. package/payload/platform/plugins/property-data/mcp/package.json +21 -0
  87. package/payload/platform/plugins/property-data/mcp/src/__tests__/key-roundtrip.test.ts +107 -0
  88. package/payload/platform/plugins/property-data/mcp/src/__tests__/propertydata-api.test.ts +184 -0
  89. package/payload/platform/plugins/property-data/mcp/src/__tests__/schema-parity.test.ts +48 -0
  90. package/payload/platform/plugins/property-data/mcp/src/index.ts +249 -0
  91. package/payload/platform/plugins/property-data/mcp/src/lib/crypto.ts +79 -0
  92. package/payload/platform/plugins/property-data/mcp/src/lib/neo4j.ts +47 -0
  93. package/payload/platform/plugins/property-data/mcp/src/lib/propertydata-api.ts +135 -0
  94. package/payload/platform/plugins/property-data/mcp/src/tools/endpoints.ts +27 -0
  95. package/payload/platform/plugins/property-data/mcp/src/tools/key-deregister.ts +21 -0
  96. package/payload/platform/plugins/property-data/mcp/src/tools/key-list.ts +10 -0
  97. package/payload/platform/plugins/property-data/mcp/src/tools/key-register.ts +58 -0
  98. package/payload/platform/plugins/property-data/mcp/tsconfig.json +20 -0
  99. package/payload/platform/plugins/property-data/mcp/vitest.config.ts +8 -0
  100. package/payload/platform/plugins/property-data/skills/property-data/SKILL.md +58 -0
  101. package/payload/platform/plugins/waitlist/PLUGIN.md +6 -8
  102. package/payload/platform/plugins/waitlist/mcp/dist/index.js +33 -0
  103. package/payload/platform/plugins/waitlist/mcp/dist/index.js.map +1 -1
  104. package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.d.ts +16 -0
  105. package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.d.ts.map +1 -0
  106. package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.js +58 -0
  107. package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.js.map +1 -0
  108. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts +34 -0
  109. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts.map +1 -0
  110. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js +129 -0
  111. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js.map +1 -0
  112. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts +12 -18
  113. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts.map +1 -1
  114. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js +89 -86
  115. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js.map +1 -1
  116. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.d.ts.map +1 -1
  117. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.js +15 -53
  118. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.js.map +1 -1
  119. package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -0
  120. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +5 -5
  121. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  122. package/payload/platform/plugins/workflows/PLUGIN.md +10 -176
  123. package/payload/platform/plugins/workflows/mcp/dist/index.js +14 -142
  124. package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
  125. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts +1 -88
  126. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts.map +1 -1
  127. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js +0 -86
  128. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js.map +1 -1
  129. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts +5 -12
  130. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts.map +1 -1
  131. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js +5 -46
  132. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js.map +1 -1
  133. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts +1 -16
  134. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts.map +1 -1
  135. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js +39 -75
  136. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js.map +1 -1
  137. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts +8 -21
  138. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts.map +1 -1
  139. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +39 -266
  140. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
  141. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts +3 -8
  142. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts.map +1 -1
  143. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js +3 -10
  144. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js.map +1 -1
  145. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts.map +1 -1
  146. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js +38 -86
  147. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js.map +1 -1
  148. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.d.ts.map +1 -1
  149. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js +8 -26
  150. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js.map +1 -1
  151. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
  152. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +1 -2
  153. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
  154. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  155. package/payload/platform/services/claude-session-manager/dist/http-server.js +204 -23
  156. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  157. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +39 -1
  158. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  159. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +109 -10
  160. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  161. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts.map +1 -1
  162. package/payload/platform/services/claude-session-manager/dist/reaper.js +11 -0
  163. package/payload/platform/services/claude-session-manager/dist/reaper.js.map +1 -1
  164. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +21 -0
  165. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -1
  166. package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -1
  167. package/payload/platform/services/claude-session-manager/vitest.config.ts +14 -0
  168. package/payload/platform/templates/agents/admin/IDENTITY.md +2 -0
  169. package/payload/platform/templates/agents/admin/SOUL.md +3 -1
  170. package/payload/premium-plugins/real-agent/BUNDLE.md +5 -3
  171. package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
  172. package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
  173. package/payload/premium-plugins/real-agent/plugins/.claude-plugin/marketplace.json +5 -0
  174. package/payload/premium-plugins/real-agent/plugins/brochures/PLUGIN.md +2 -0
  175. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/SKILL.md +100 -0
  176. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/references/render.py +267 -0
  177. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/references/template.html +266 -0
  178. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-socials/SKILL.md +141 -0
  179. package/payload/premium-plugins/real-agent/plugins/property-data/.claude-plugin/plugin.json +17 -0
  180. package/payload/premium-plugins/real-agent/plugins/property-data/PLUGIN.md +100 -0
  181. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.d.ts +2 -0
  182. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.d.ts.map +1 -0
  183. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.js +153 -0
  184. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.js.map +1 -0
  185. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.d.ts +3 -0
  186. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.d.ts.map +1 -0
  187. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.js +72 -0
  188. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.js.map +1 -0
  189. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.d.ts +5 -0
  190. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.d.ts.map +1 -0
  191. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.js +38 -0
  192. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.js.map +1 -0
  193. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts +29 -0
  194. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts.map +1 -0
  195. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.js +112 -0
  196. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.js.map +1 -0
  197. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.d.ts +14 -0
  198. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.d.ts.map +1 -0
  199. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.js +20 -0
  200. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.js.map +1 -0
  201. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.d.ts +4 -0
  202. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.d.ts.map +1 -0
  203. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.js +19 -0
  204. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.js.map +1 -0
  205. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.d.ts +4 -0
  206. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.d.ts.map +1 -0
  207. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.js +10 -0
  208. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.js.map +1 -0
  209. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.d.ts +5 -0
  210. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.d.ts.map +1 -0
  211. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.js +43 -0
  212. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.js.map +1 -0
  213. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/package-lock.json +2566 -0
  214. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/package.json +21 -0
  215. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/key-roundtrip.test.ts +107 -0
  216. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/propertydata-api.test.ts +184 -0
  217. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/schema-parity.test.ts +48 -0
  218. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/index.ts +249 -0
  219. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/crypto.ts +79 -0
  220. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/neo4j.ts +47 -0
  221. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/propertydata-api.ts +135 -0
  222. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/endpoints.ts +27 -0
  223. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-deregister.ts +21 -0
  224. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-list.ts +10 -0
  225. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-register.ts +58 -0
  226. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/tsconfig.json +20 -0
  227. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/vitest.config.ts +8 -0
  228. package/payload/premium-plugins/real-agent/plugins/property-data/skills/property-data/SKILL.md +58 -0
  229. package/payload/server/{chunk-CWI7NOWK.js → chunk-2IKQERHN.js} +32 -4
  230. package/payload/server/maxy-edge.js +53 -25
  231. package/payload/server/public/assets/admin-2ZJmzJ_g.js +216 -0
  232. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DGHlapUl.js → architectureDiagram-Q4EWVU46-DgfgldJT.js} +1 -1
  233. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-Dgnf9J14.js → blockDiagram-DXYQGD6D-agu8GDzA.js} +1 -1
  234. package/payload/server/public/assets/{brand-CtilcX3W.css → brand-BDASZqMG.css} +1 -1
  235. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-GBVmghhJ.js → c4Diagram-AHTNJAMY-CmNsUmAe.js} +1 -1
  236. package/payload/server/public/assets/channel-DXGOX55q.js +1 -0
  237. package/payload/server/public/assets/{chunk-336JU56O-CSVC_J3A.js → chunk-336JU56O-D9Uts7k9.js} +2 -2
  238. package/payload/server/public/assets/{chunk-426QAEUC-CK1Z0942.js → chunk-426QAEUC-D4ABqXMn.js} +1 -1
  239. package/payload/server/public/assets/{chunk-4TB4RGXK-CaqJYLxL.js → chunk-4TB4RGXK-D1KE4OAX.js} +1 -1
  240. package/payload/server/public/assets/{chunk-5FUZZQ4R-57BmPy_B.js → chunk-5FUZZQ4R-CAh0GXe2.js} +1 -1
  241. package/payload/server/public/assets/{chunk-5PVQY5BW-Ud03uYx_.js → chunk-5PVQY5BW-DBHa6HOv.js} +1 -1
  242. package/payload/server/public/assets/{chunk-EDXVE4YY-p5KO0PoG.js → chunk-EDXVE4YY-BDC-6mL3.js} +1 -1
  243. package/payload/server/public/assets/{chunk-ENJZ2VHE-CkxgLujt.js → chunk-ENJZ2VHE-CH3uROkW.js} +1 -1
  244. package/payload/server/public/assets/{chunk-ICPOFSXX-DwMkY8p7.js → chunk-ICPOFSXX-BzZf0nAw.js} +1 -1
  245. package/payload/server/public/assets/{chunk-OYMX7WX6-CyYOUKBw.js → chunk-OYMX7WX6-BrLHrI6O.js} +1 -1
  246. package/payload/server/public/assets/{chunk-U2HBQHQK-Dk5rfJM6.js → chunk-U2HBQHQK-Bw4UkLe_.js} +1 -1
  247. package/payload/server/public/assets/{chunk-X2U36JSP-D0qCg9Nq.js → chunk-X2U36JSP-23xgdk05.js} +1 -1
  248. package/payload/server/public/assets/{chunk-YZCP3GAM-C0uFHrdT.js → chunk-YZCP3GAM-BA8iGgRa.js} +1 -1
  249. package/payload/server/public/assets/{chunk-ZZ45TVLE-C7lSyGRs.js → chunk-ZZ45TVLE-B-ol4EgR.js} +1 -1
  250. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DTuuDxpK.js +1 -0
  251. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CIw8RU0q.js +1 -0
  252. package/payload/server/public/assets/clone-O4ZyuvYl.js +1 -0
  253. package/payload/server/public/assets/{dagre-BWZ4wr8y.js → dagre--kXszEIb.js} +1 -1
  254. package/payload/server/public/assets/{dagre-KV5264BT-C7mpqRpw.js → dagre-KV5264BT-amN1uU2d.js} +1 -1
  255. package/payload/server/public/assets/data-DlmoKxmN.js +1 -0
  256. package/payload/server/public/assets/{device-url-actions-347cMDY4.js → device-url-actions-CPoz5fqz.js} +1 -1
  257. package/payload/server/public/assets/{diagram-5BDNPKRD-BcQRB7_3.js → diagram-5BDNPKRD-Cwizs9tP.js} +1 -1
  258. package/payload/server/public/assets/{diagram-G4DWMVQ6-BLSGUKbc.js → diagram-G4DWMVQ6-BpSu5Uao.js} +1 -1
  259. package/payload/server/public/assets/{diagram-MMDJMWI5-Ra1VvGJh.js → diagram-MMDJMWI5-DiArtkto.js} +1 -1
  260. package/payload/server/public/assets/{diagram-TYMM5635-Bx_r1USn.js → diagram-TYMM5635-_tygK58Y.js} +1 -1
  261. package/payload/server/public/assets/{erDiagram-SMLLAGMA-CJhoN8dG.js → erDiagram-SMLLAGMA-CBV6LWYA.js} +1 -1
  262. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-Bd5CZIoq.js → flowDiagram-DWJPFMVM-CHZFrtOU.js} +1 -1
  263. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BNQJqJFh.js → ganttDiagram-T4ZO3ILL-B3vKq5ov.js} +1 -1
  264. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DoE1AFmA.js → gitGraphDiagram-UUTBAWPF-dnJPjbtj.js} +1 -1
  265. package/payload/server/public/assets/graph-BVvcFSEQ.js +1 -0
  266. package/payload/server/public/assets/graph-labels-cCvgu38Y.js +1 -0
  267. package/payload/server/public/assets/{graphlib-D7JFfLSw.js → graphlib-CNXtnega.js} +1 -1
  268. package/payload/server/public/assets/{infoDiagram-42DDH7IO-BtsKRO-J.js → infoDiagram-42DDH7IO-D8DYwVAF.js} +1 -1
  269. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DapnDR0V.js → ishikawaDiagram-UXIWVN3A-CfEVY2Ud.js} +1 -1
  270. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-BLqfwMMu.js → journeyDiagram-VCZTEJTY-FmoBq7Kh.js} +1 -1
  271. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DqiSbvUW.js → kanban-definition-6JOO6SKY-B-Q9qk99.js} +1 -1
  272. package/payload/server/public/assets/{line-DcwBbbhp.js → line-DZwbJENP.js} +1 -1
  273. package/payload/server/public/assets/{mermaid-parser.core-BZwNRInp.js → mermaid-parser.core-C3ahKykw.js} +1 -1
  274. package/payload/server/public/assets/{mermaid.core-DnsyVInc.js → mermaid.core-B8OFZIE8.js} +3 -3
  275. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-MPPO8aDx.js → mindmap-definition-QFDTVHPH-CqhkfbWa.js} +1 -1
  276. package/payload/server/public/assets/{page-Cz_pVOv_.js → page-BnAxPkmg.js} +1 -1
  277. package/payload/server/public/assets/{page-pXt2BdOS.js → page-BnaN3u86.js} +1 -1
  278. package/payload/server/public/assets/{pieDiagram-DEJITSTG-BKzbjD_5.js → pieDiagram-DEJITSTG-CJqQ6u3-.js} +1 -1
  279. package/payload/server/public/assets/{public-C-0V5aC8.js → public-rWe9ADCS.js} +3 -3
  280. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CvvvRvae.js → quadrantDiagram-34T5L4WZ-BtEqOXQM.js} +1 -1
  281. package/payload/server/public/assets/{requirementDiagram-MS252O5E-BxXZA7z2.js → requirementDiagram-MS252O5E-DPHWUtE6.js} +1 -1
  282. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BRRFjjao.js → sankeyDiagram-XADWPNL6-FBmc3wHT.js} +1 -1
  283. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DOy_E8xe.js → sequenceDiagram-FGHM5R23-BMSd2-1M.js} +1 -1
  284. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CDqat01p.js → stateDiagram-FHFEXIEX-DqFbU-LT.js} +1 -1
  285. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CXTnsHGq.js +1 -0
  286. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-AK1yuR8Z.js → timeline-definition-GMOUNBTQ-DsfvHVK8.js} +1 -1
  287. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CCKJ7H16.js → vennDiagram-DHZGUBPP-kHU05mqC.js} +1 -1
  288. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CKHKJnG_.js → wardleyDiagram-NUSXRM2D-C696Mez_.js} +1 -1
  289. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-BBD35k9e.js → xychartDiagram-5P7HB3ND-yht-JyXJ.js} +1 -1
  290. package/payload/server/public/data.html +5 -5
  291. package/payload/server/public/graph.html +5 -5
  292. package/payload/server/public/index.html +7 -7
  293. package/payload/server/public/public.html +4 -4
  294. package/payload/server/server.js +209 -178
  295. package/payload/server/public/assets/admin-BbcN8otj.js +0 -216
  296. package/payload/server/public/assets/channel-p5ZCfK_I.js +0 -1
  297. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DqDM1D4-.js +0 -1
  298. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DeYvPD8H.js +0 -1
  299. package/payload/server/public/assets/clone-60k82qeh.js +0 -1
  300. package/payload/server/public/assets/data-oXs84UW6.js +0 -1
  301. package/payload/server/public/assets/graph-DcpqWbSs.js +0 -1
  302. package/payload/server/public/assets/graph-labels-DJvuUODB.js +0 -1
  303. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DHckg-aj.js +0 -1
  304. /package/payload/server/public/assets/{brand-B6pMzF6h.js → brand-BWCtpG7_.js} +0 -0
@@ -1,47 +1,88 @@
1
1
  #!/usr/bin/env bash
2
2
  # Stop hook — fires on every completed admin-agent turn and dispatches one
3
- # headless database-operator session against the conversation transcript.
4
- # The hidden recorder is the only writer to the Neo4j graph; the admin agent
3
+ # headless database-operator session against the operator's most recent turn
4
+ # text. The recorder is the only writer to the Neo4j graph; the admin agent
5
5
  # stays focused on the operator's request.
6
6
  #
7
- # Task 122 redesign — the hook now makes ONE HTTP call to the admin
8
- # wrapper's loopback recorder route (`POST /api/admin/claude-sessions/recorder-spawn`)
9
- # instead of curling /spawn and /<id>/input directly against the
10
- # claude-session-manager. The wrapper owns the spawn-with-initial-message
11
- # sequence for every caller (Sidebar and recorder alike), which keeps the
12
- # multi-line submit path in one place. The wrapper bypasses admin-session
13
- # auth on this route because the request originates from 127.0.0.1 and
14
- # the body carries `senderId: 'turn-recorder'` same trust boundary the
15
- # claude-session-manager itself relies on.
7
+ # Task 134 — the four-step per-turn process is:
8
+ # 1. New admin session is spawned the SAME way a Sidebar "New session"
9
+ # click spawns one same route (`POST /api/admin/claude-sessions`,
10
+ # the one Sidebar hits), same payload schema. The wrapper bypasses
11
+ # cookie auth on this exact path when the request originates from
12
+ # 127.0.0.1; the body carries `originatingSessionId` and
13
+ # `specialist: 'database-operator'`, and the wrapper looks up the
14
+ # operator's senderId from `/<originatingSessionId>/meta`. The
15
+ # Task-122-era `/recorder-spawn` sibling route is gone.
16
+ # 2. The spawned session's specialist is `database-operator`.
17
+ # 3. The initial message is the OPERATOR'S LAST TURN, prefixed with the
18
+ # literal instruction
19
+ # "update the graph with any new or missing information or intent"
20
+ # followed by a blank line. No transcript tail, no `Conversation id:`
21
+ # prose — both removed in Task 131. The recorder reads only this one
22
+ # most-recent turn.
23
+ # 4. When the recorder's turn ends (`stop_reason:"end_turn"` lands in
24
+ # the recorder JSONL), the manager posts `/<sid>/stop`, claude exits,
25
+ # the fs-watcher observes the PID-file removal, and the row leaves
26
+ # the index. No reaper involvement on the success path.
16
27
  #
17
- # Gating:
18
- # - MAXY_SESSION_ROLE must equal "admin"
19
- # - MAXY_HIDDEN_SPAWN must equal "0" (the recorder PTY itself runs with
20
- # MAXY_HIDDEN_SPAWN=1; the guard prevents accidental recursion).
28
+ # Task 129 — every emit goes through the platform's `/api/admin/log-ingest`
29
+ # endpoint (loopback-only). Hook stderr is silent on the success path.
30
+ # Every line carries the operator's `sessionId=<op>` so one grep against
31
+ # `server.log` returns the whole chain. The `originatingSessionId` is
32
+ # posted as a top-level field of the spawn body; the wrapper reads it,
33
+ # resolves the operator's account from it, and forwards a Sidebar-shape
34
+ # spawn body to the manager.
35
+ #
36
+ # Gating (emits a `trigger-skipped` line, no longer a silent exit 0):
37
+ # - MAXY_SESSION_ROLE must equal "admin" → reason=role-not-admin
38
+ # - MAXY_IS_RECORDER must NOT equal "1" → reason=is-recorder
39
+ # - Stop-hook stdin must be non-empty → reason=empty-stdin
40
+ # - transcript_path must exist on disk → reason=missing-transcript
41
+ # - a most-recent assistant or user turn → reason=last-turn-empty
42
+ # must be extractable from the JSONL
21
43
  #
22
44
  # Input: Claude Code's Stop hook stdin shape
23
45
  # { "session_id": "<intrinsic>", "transcript_path": "<jsonl path>", ... }
24
- #
25
- # Failure modes are silent (exit 0) — a failure here must never break the
26
- # operator's session.
27
46
 
28
47
  set -uo pipefail
29
48
 
30
- START_MS=$(python3 -c 'import time; print(int(time.time()*1000))')
31
-
32
- if [ "${MAXY_SESSION_ROLE:-}" != "admin" ]; then
33
- exit 0
34
- fi
35
- if [ "${MAXY_HIDDEN_SPAWN:-0}" = "1" ]; then
49
+ # UI listener port is stamped on the claude-session-manager systemd unit
50
+ # as `Environment=MAXY_UI_INTERNAL_PORT=<port>` (Task 134). Absence is a
51
+ # structural defect historically the hook fell back to 19199 with no
52
+ # listener on most devices and silently swallowed connection-refused. Now
53
+ # it short-circuits with a named diagnostic to stderr (the only sink the
54
+ # log-ingest endpoint itself depends on this var to reach).
55
+ UI_PORT="${MAXY_UI_INTERNAL_PORT:-}"
56
+ if [ -z "$UI_PORT" ]; then
57
+ echo "[turn-recorder] spawn-failed sessionId=unknown reason=missing-env env=MAXY_UI_INTERNAL_PORT" >&2
36
58
  exit 0
37
59
  fi
60
+ UI_BASE="http://127.0.0.1:${UI_PORT}"
61
+ LOG_INGEST_URL="${UI_BASE}/api/admin/log-ingest"
62
+
63
+ # Emit one log line via the platform's log-ingest endpoint. Best-effort:
64
+ # a failed POST does not break the hook — but the absence of the line is
65
+ # itself a system-level defect per Task 129 §157. We do NOT fall back to
66
+ # stderr, because stderr never reaches server.log.
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": "turn-recorder", "level": "info", "line": sys.argv[1]}))
75
+ ' "$line")" \
76
+ "$LOG_INGEST_URL" 2>/dev/null || true
77
+ }
38
78
 
79
+ # Parse stdin first so trigger-skipped lines can carry the operator
80
+ # session id (when present). Stop-hook stdin is required.
81
+ INPUT=""
39
82
  if [ -t 0 ]; then
40
- exit 0
41
- fi
42
- INPUT=$(cat)
43
- if [ -z "$INPUT" ]; then
44
- exit 0
83
+ INPUT=""
84
+ else
85
+ INPUT=$(cat)
45
86
  fi
46
87
 
47
88
  PARSED=$(printf '%s' "$INPUT" | python3 -c '
@@ -57,105 +98,145 @@ except Exception:
57
98
  ADMIN_SESSION_ID="${PARSED%% *}"
58
99
  TRANSCRIPT_PATH="${PARSED#* }"
59
100
 
101
+ # Gate ordering — each gate gets a distinct trigger-skipped reason so the
102
+ # operator-ID-keyed grep can tell why a given turn did not record. Role
103
+ # gate fires first because non-admin invocations may have no operator id
104
+ # at all (the field is empty for public/recorder).
105
+ if [ "${MAXY_SESSION_ROLE:-}" != "admin" ]; then
106
+ emit_log "trigger-skipped sessionId=${ADMIN_SESSION_ID:-unknown} reason=role-not-admin"
107
+ exit 0
108
+ fi
109
+ # Task 131 — the recorder gate is now MAXY_IS_RECORDER (set to '1' by the
110
+ # pty-spawner whenever a spawn carries `originatingSessionId`). The prior
111
+ # MAXY_HIDDEN_SPAWN gate conflated UI visibility with recorder identity;
112
+ # with hidden=false on recorder spawns now, the dedicated env var is the
113
+ # only correct discriminator against hook-recursion.
114
+ if [ "${MAXY_IS_RECORDER:-0}" = "1" ]; then
115
+ emit_log "trigger-skipped sessionId=${ADMIN_SESSION_ID:-unknown} reason=is-recorder"
116
+ exit 0
117
+ fi
118
+ if [ -z "$INPUT" ]; then
119
+ emit_log "trigger-skipped sessionId=${ADMIN_SESSION_ID:-unknown} reason=empty-stdin"
120
+ exit 0
121
+ fi
60
122
  if [ -z "$ADMIN_SESSION_ID" ] || [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
123
+ emit_log "trigger-skipped sessionId=${ADMIN_SESSION_ID:-unknown} reason=missing-transcript"
61
124
  exit 0
62
125
  fi
63
126
 
64
- # Filter the JSONL tail down to records the database-operator cares about:
65
- # user prompts, assistant messages, and tool calls. Drop ephemeral
66
- # admin-state records that bloat the prompt without graph value.
67
- FILTERED_TAIL=$(python3 - "$TRANSCRIPT_PATH" <<'PY'
127
+ # Extract the operator's most-recent turn text from the JSONL. The single
128
+ # rule (no fallbacks beyond the assistant→user pair) is:
129
+ # - the most-recent `assistant` record whose message.content yields any
130
+ # extractable text, OR
131
+ # - if no assistant record produces text, the most-recent `user` record
132
+ # that produces text.
133
+ # Tool-call blocks, system records, and ephemeral admin-state records are
134
+ # never the candidate. Empty output → reason=last-turn-empty.
135
+ LAST_TURN_TEXT=$(python3 - "$TRANSCRIPT_PATH" <<'PY'
68
136
  import sys, json
69
- DROP = {
70
- 'queue-operation', 'auto_mode', 'deferred_tools_delta',
71
- 'last-prompt', 'skill_listing', 'mcp_instructions_delta',
72
- 'permission-mode',
73
- }
74
- def keep(rec):
75
- t = rec.get('type') if isinstance(rec, dict) else None
76
- if not isinstance(t, str): return False
77
- if t in DROP: return False
78
- if t.startswith('hook_'): return False
79
- if t in ('user', 'assistant', 'message'): return True
80
- if 'tool' in t.lower(): return True
81
- return False
137
+
138
+ def block_text(block):
139
+ if not isinstance(block, dict): return ""
140
+ if block.get("type") != "text": return ""
141
+ t = block.get("text")
142
+ return t if isinstance(t, str) else ""
143
+
144
+ def record_text(rec):
145
+ if not isinstance(rec, dict): return ""
146
+ msg = rec.get("message")
147
+ if not isinstance(msg, dict): return ""
148
+ content = msg.get("content")
149
+ if isinstance(content, str): return content
150
+ if isinstance(content, list):
151
+ parts = [block_text(b) for b in content]
152
+ return "\n".join(p for p in parts if p)
153
+ return ""
82
154
 
83
155
  path = sys.argv[1]
84
- out = []
156
+ last_assistant = ""
157
+ last_user = ""
85
158
  try:
86
- with open(path, 'r', encoding='utf-8') as f:
87
- for line in f:
88
- line = line.strip()
89
- if not line: continue
90
- try: rec = json.loads(line)
91
- except Exception: continue
92
- if keep(rec): out.append(rec)
159
+ with open(path, "r", encoding="utf-8") as f:
160
+ for line in f:
161
+ line = line.strip()
162
+ if not line: continue
163
+ try: rec = json.loads(line)
164
+ except Exception: continue
165
+ t = rec.get("type") if isinstance(rec, dict) else None
166
+ if t == "assistant":
167
+ tx = record_text(rec).strip()
168
+ if tx: last_assistant = tx
169
+ elif t == "user":
170
+ tx = record_text(rec).strip()
171
+ if tx: last_user = tx
93
172
  except Exception:
94
- pass
95
- out = out[-200:]
96
- print(json.dumps(out, separators=(',', ':')))
173
+ pass
174
+
175
+ print(last_assistant if last_assistant else last_user, end="")
97
176
  PY
98
177
  )
99
178
 
100
- FILTERED_COUNT=$(printf '%s' "$FILTERED_TAIL" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(len(d) if isinstance(d,list) else 0)' 2>/dev/null || echo 0)
179
+ LAST_TURN_BYTES=$(printf '%s' "$LAST_TURN_TEXT" | wc -c | tr -d ' ')
180
+ TRANSCRIPT_BYTES=$(wc -c <"$TRANSCRIPT_PATH" 2>/dev/null | tr -d ' ' || echo 0)
101
181
 
102
- # UI server runs on MAXY_UI_INTERNAL_PORT (default 19199). The recorder
103
- # route is loopback-only; no admin-session credentials are required.
104
- UI_PORT="${MAXY_UI_INTERNAL_PORT:-19199}"
105
- UI_BASE="http://127.0.0.1:${UI_PORT}"
182
+ # Step 0 trigger line. First link in the chain the operator-ID-keyed
183
+ # grep returns. Task 131: replaced `filteredRecords=<n>` with
184
+ # `lastTurnBytes=<n>` because the hook no longer ships a filtered
185
+ # transcript tail.
186
+ emit_log "trigger sessionId=${ADMIN_SESSION_ID} turnIndex=0 transcriptBytes=${TRANSCRIPT_BYTES} lastTurnBytes=${LAST_TURN_BYTES}"
187
+
188
+ if [ -z "$LAST_TURN_TEXT" ]; then
189
+ emit_log "trigger-skipped sessionId=${ADMIN_SESSION_ID} reason=last-turn-empty"
190
+ exit 0
191
+ fi
106
192
 
107
- # Compose the recorder spawn body in one shot. `initialMessage` carries
108
- # the instruction + conversation id + filtered transcript as a single
109
- # multi-line string; the wrapper hands it to manager POST /<id>/input,
110
- # which now wraps multi-line text in bracketed-paste markers so the TUI
111
- # submits it as one turn (Task 122 root cause).
193
+ # Compose the recorder spawn body. Task 134:
194
+ # - `initialMessage` = literal instruction + "\n\n" + last-turn text.
195
+ # Verbatim instruction wording (no trailing qualifier, includes "new").
196
+ # - `originatingSessionId` carries the operator's session id; the
197
+ # wrapper looks up the operator's real senderId from
198
+ # `/<originatingSessionId>/meta` and forwards a Sidebar-shape spawn
199
+ # body to the manager. No synthetic `senderId: 'turn-recorder'`
200
+ # marker — the loopback bypass is method+path-scoped.
201
+ # - `specialist: 'database-operator'` discriminates the recorder spawn
202
+ # from a vanilla Sidebar click.
203
+ # - No `Conversation id:` prose; no transcript-tail JSON.
112
204
  SPAWN_BODY=$(python3 -c '
113
205
  import sys, json
114
206
  sid = sys.argv[1]
115
- tail_json = sys.argv[2]
116
- instruction = "update the graph with any missing information or intent that can be derived from this conversation"
117
- text = (
118
- f"{instruction}\n\n"
119
- f"Conversation id: {sid}\n"
120
- f"Conversation transcript:\n{tail_json}\n"
121
- )
207
+ last_turn = sys.argv[2]
208
+ instruction = "update the graph with any new or missing information or intent"
209
+ text = instruction + "\n\n" + last_turn
122
210
  body = {
123
- "senderId": "turn-recorder",
124
211
  "specialist": "database-operator",
125
212
  "initialMessage": text,
213
+ "originatingSessionId": sid,
126
214
  }
127
215
  print(json.dumps(body))
128
- ' "$ADMIN_SESSION_ID" "$FILTERED_TAIL" 2>/dev/null)
129
-
130
- INPUT_BYTES=$(printf '%s' "$SPAWN_BODY" | python3 -c 'import sys,json; b=json.load(sys.stdin); print(len(b.get("initialMessage","").encode("utf-8")))' 2>/dev/null || echo 0)
216
+ ' "$ADMIN_SESSION_ID" "$LAST_TURN_TEXT" 2>/dev/null)
131
217
 
132
218
  SPAWN_RES_FILE=$(mktemp)
133
- INPUT_HTTP=$(curl -sS -o "$SPAWN_RES_FILE" -w '%{http_code}' -X POST \
219
+ SPAWN_HTTP=$(curl -sS -o "$SPAWN_RES_FILE" -w '%{http_code}' -X POST \
134
220
  -H 'Content-Type: application/json' \
135
221
  --max-time 10 \
136
222
  --data "$SPAWN_BODY" \
137
- "${UI_BASE}/api/admin/claude-sessions/recorder-spawn" 2>/dev/null || echo 000)
138
-
139
- RECORDER_SESSION_ID=$(python3 -c '
140
- import sys, json
141
- try:
142
- with open(sys.argv[1], "r", encoding="utf-8") as f:
143
- d = json.load(f)
144
- print(d.get("sessionId", "") or "")
145
- except Exception:
146
- print("")
147
- ' "$SPAWN_RES_FILE" 2>/dev/null)
223
+ "${UI_BASE}/api/admin/claude-sessions" 2>/dev/null || echo 000)
224
+
225
+ # The wrapper emits the named `spawn-request` / `spawn-success` /
226
+ # `input-delivered` lines itself. The hook only emits the hook-side
227
+ # failure variant — `loopback-http` — and even then only when the wrapper
228
+ # returned a non-2xx that is NOT one of the preflight reasons (those are
229
+ # logged by the manager before the wrapper sees them).
230
+ RES_BODY=$(cat "$SPAWN_RES_FILE" 2>/dev/null || true)
148
231
  rm -f "$SPAWN_RES_FILE"
149
232
 
150
- if [ -z "$RECORDER_SESSION_ID" ]; then
151
- echo "turn-completed-graph-write spawn-failed conversationId=${ADMIN_SESSION_ID:0:8} http=${INPUT_HTTP}" >&2
152
- exit 0
233
+ if [ "$SPAWN_HTTP" -lt 200 ] || [ "$SPAWN_HTTP" -ge 300 ]; then
234
+ ERR_SHORT=$(printf '%s' "$RES_BODY" | tr -d '\r\n' | cut -c1-200)
235
+ if printf '%s' "$RES_BODY" | grep -q '"error":"tool-surface-missing"\|"error":"missing-originating-session-id"\|"error":"originating-session-id-required"\|"error":"originating-session-not-found"'; then
236
+ : # preflight or lookup already named the failure
237
+ else
238
+ emit_log "spawn-failed sessionId=${ADMIN_SESSION_ID} reason=loopback-http http=${SPAWN_HTTP} err=$(python3 -c 'import sys,json; print(json.dumps(sys.argv[1]))' "${ERR_SHORT}")"
239
+ fi
153
240
  fi
154
241
 
155
- echo "[turn-recorder] spawn-with-input sessionId=${RECORDER_SESSION_ID:0:8} bytes=${INPUT_BYTES} filtered-from-records=${FILTERED_COUNT} input-http=${INPUT_HTTP}" >&2
156
-
157
- END_MS=$(python3 -c 'import time; print(int(time.time()*1000))')
158
- ELAPSED=$((END_MS - START_MS))
159
- echo "turn-completed-graph-write fired conversationId=${ADMIN_SESSION_ID:0:8} recorderSessionId=${RECORDER_SESSION_ID:0:8} filtered=${FILTERED_COUNT} ms=${ELAPSED}" >&2
160
-
161
242
  exit 0
@@ -9,6 +9,7 @@ import { resolve, join } from "node:path";
9
9
  import { execFileSync } from "node:child_process";
10
10
  import { appendFileSync, cpSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
11
11
  import { writeAdminEntry, removeAdminFromAccount } from "../../../../lib/admins-write/dist/index.js";
12
+ import { requirePortEnv } from "../../../../lib/require-port-env/dist/index.js";
12
13
  import { deviceUrlBlock } from "../../../../lib/device-url/dist/index.js";
13
14
  import { substituteBrandPlaceholders } from "../../../../lib/brand-templating/dist/index.js";
14
15
  import { resolveEntitlement } from "../../../../lib/entitlement/dist/index.js";
@@ -28,10 +29,13 @@ const ACCOUNT_ID = process.env.ACCOUNT_ID;
28
29
  if (!ACCOUNT_ID) {
29
30
  throw new Error("ACCOUNT_ID environment variable is required");
30
31
  }
31
- const PLATFORM_PORT = process.env.PLATFORM_PORT;
32
- if (!PLATFORM_PORT) {
33
- throw new Error("PLATFORM_PORT environment variable is required set by getMcpServers() in claude-agent.ts");
34
- }
32
+ // Task 142 — `PLATFORM_PORT` is the internal loopback port, stamped on
33
+ // the claude-session-manager systemd unit and forwarded to this MCP
34
+ // process via the per-spawn `maxy-mcp-*.json` env block written by
35
+ // `pty-spawner.writePerSpawnMcpConfig`. `MAXY_BRAND_PORT` is the brand's
36
+ // public UI port, used only for display-surface `.local` URLs.
37
+ const PLATFORM_PORT = String(requirePortEnv("PLATFORM_PORT", { tag: "admin:module-init" }));
38
+ const MAXY_BRAND_PORT = String(requirePortEnv("MAXY_BRAND_PORT", { tag: "admin:module-init" }));
35
39
  // Brand-aware config — reads configDir, productName, and commercialMode from
36
40
  // brand.json stamped at install time. commercialMode gates the
37
41
  // entitlement verifier: false (default) preserves personal-mode installs;
@@ -372,9 +376,10 @@ eagerTool(server, "system-status", "Check health of all Maxy platform services:
372
376
  console.error("[system-status] os.hostname() failed, falling back to brand.hostname", err);
373
377
  checks.hostname = "unknown (os.hostname failed)";
374
378
  }
375
- // Running port PLATFORM_PORT is what the parent process passes to MCP subprocesses;
376
- // PORT is the main-process variable (available in dev); 19200 is the install default.
377
- checks.port = process.env.PLATFORM_PORT ?? process.env.PORT ?? "19200";
379
+ // Task 142: `port` shown to the operator is the brand's public port
380
+ // (the one external clients reach via `.local`), not the internal
381
+ // loopback. Loud-fail if absent (Task 139 doctrine).
382
+ checks.port = String(requirePortEnv("MAXY_BRAND_PORT", { tag: "system-status" }));
378
383
  console.error(`[system-status] port=${checks.port} hostname=${checks.hostname}`);
379
384
  // Local URL — pre-computed for agent URL construction (avoids hostname/port assembly errors)
380
385
  checks.localUrl = `http://${checks.hostname}.local:${checks.port}`;
@@ -433,15 +438,18 @@ eagerTool(server, "public-hostname", "Resolve this account's canonical public ho
433
438
  });
434
439
  eagerTool(server, "remote-auth-status", "Check whether the remote access password is configured. When not configured, emits a device-bound URL affordance (maxy-device-url fenced block) pointing at the password setup page — this URL opens on the device's own screen when the operator clicks it. The agent never constructs the password file path or runs shell commands — this tool is the single authority.", {}, async () => {
435
440
  const TAG = "[remote-auth-status]";
436
- const platformPort = parseInt(PLATFORM_PORT, 10);
437
- const setupUrl = `http://${osHostname()}.local:${platformPort}/__remote-auth/setup`;
441
+ // Task 142: `.local` URL is a display surface — read the brand's
442
+ // public port. The loopback fetch reads PLATFORM_PORT (internal).
443
+ const brandPort = parseInt(MAXY_BRAND_PORT, 10);
444
+ const internalPort = parseInt(PLATFORM_PORT, 10);
445
+ const setupUrl = `http://${osHostname()}.local:${brandPort}/__remote-auth/setup`;
438
446
  try {
439
- const res = await fetch(`http://127.0.0.1:${platformPort}/api/remote-auth/status`, {
447
+ const res = await fetch(`http://127.0.0.1:${internalPort}/api/remote-auth/status`, {
440
448
  signal: AbortSignal.timeout(5000),
441
449
  });
442
450
  const body = await res.json();
443
451
  const configured = body.configured === true;
444
- console.error(`${TAG} configured=${configured} port=${platformPort}`);
452
+ console.error(`${TAG} configured=${configured} brandPort=${brandPort} internalPort=${internalPort}`);
445
453
  // Shape the response for both the agent (deciding what to say) and
446
454
  // the user (seeing the device-URL button when they need to act).
447
455
  // Configured → plain status, no URL. Unconfigured → include the
@@ -461,7 +469,7 @@ eagerTool(server, "remote-auth-status", "Check whether the remote access passwor
461
469
  return {
462
470
  content: [{
463
471
  type: "text",
464
- text: `Cannot verify remote authentication — the web server at http://127.0.0.1:${platformPort} is not reachable: ${errMsg}. Ensure the ${BRAND_NAME} platform is running.`,
472
+ text: `Cannot verify remote authentication — the web server at http://127.0.0.1:${internalPort} is not reachable: ${errMsg}. Ensure the ${BRAND_NAME} platform is running.`,
465
473
  }],
466
474
  isError: true,
467
475
  };