@rubytech/create-maxy-code 0.1.49 → 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 (317) 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 +184 -146
  15. package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +186 -112
  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/PLUGIN.md +3 -1
  27. package/payload/platform/plugins/docs/references/admin-session.md +40 -0
  28. package/payload/platform/plugins/docs/references/deployment.md +25 -0
  29. package/payload/platform/plugins/docs/references/internals.md +30 -0
  30. package/payload/platform/plugins/docs/references/platform.md +3 -1
  31. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  32. package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
  33. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts.map +1 -1
  34. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js +2 -1
  35. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js.map +1 -1
  36. package/payload/platform/plugins/loop/PLUGIN.md +24 -0
  37. package/payload/platform/plugins/loop/mcp/src/__tests__/plugin-md-time-doctrine.test.ts +132 -0
  38. package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
  39. package/payload/platform/plugins/memory/PLUGIN.md +1 -1
  40. package/payload/platform/plugins/memory/mcp/dist/index.js +6 -1
  41. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  42. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts +2 -0
  43. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts.map +1 -0
  44. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +107 -0
  45. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -0
  46. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts +4 -2
  47. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
  48. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +22 -13
  49. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
  50. package/payload/platform/plugins/memory/references/graph-primitives.md +42 -0
  51. package/payload/platform/plugins/memory/skills/concept-synthesis/SKILL.md +1 -1
  52. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +2 -2
  53. package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +1 -1
  54. package/payload/platform/plugins/property-data/.claude-plugin/plugin.json +17 -0
  55. package/payload/platform/plugins/property-data/PLUGIN.md +100 -0
  56. package/payload/platform/plugins/property-data/mcp/dist/index.d.ts +2 -0
  57. package/payload/platform/plugins/property-data/mcp/dist/index.d.ts.map +1 -0
  58. package/payload/platform/plugins/property-data/mcp/dist/index.js +153 -0
  59. package/payload/platform/plugins/property-data/mcp/dist/index.js.map +1 -0
  60. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts +3 -0
  61. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts.map +1 -0
  62. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js +72 -0
  63. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js.map +1 -0
  64. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts +5 -0
  65. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts.map +1 -0
  66. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js +38 -0
  67. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js.map +1 -0
  68. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts +29 -0
  69. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts.map +1 -0
  70. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js +112 -0
  71. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js.map +1 -0
  72. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts +14 -0
  73. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts.map +1 -0
  74. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js +20 -0
  75. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js.map +1 -0
  76. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts +4 -0
  77. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts.map +1 -0
  78. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js +19 -0
  79. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js.map +1 -0
  80. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts +4 -0
  81. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts.map +1 -0
  82. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js +10 -0
  83. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js.map +1 -0
  84. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts +5 -0
  85. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts.map +1 -0
  86. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js +43 -0
  87. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js.map +1 -0
  88. package/payload/platform/plugins/property-data/mcp/package-lock.json +2566 -0
  89. package/payload/platform/plugins/property-data/mcp/package.json +21 -0
  90. package/payload/platform/plugins/property-data/mcp/src/__tests__/key-roundtrip.test.ts +107 -0
  91. package/payload/platform/plugins/property-data/mcp/src/__tests__/propertydata-api.test.ts +184 -0
  92. package/payload/platform/plugins/property-data/mcp/src/__tests__/schema-parity.test.ts +48 -0
  93. package/payload/platform/plugins/property-data/mcp/src/index.ts +249 -0
  94. package/payload/platform/plugins/property-data/mcp/src/lib/crypto.ts +79 -0
  95. package/payload/platform/plugins/property-data/mcp/src/lib/neo4j.ts +47 -0
  96. package/payload/platform/plugins/property-data/mcp/src/lib/propertydata-api.ts +135 -0
  97. package/payload/platform/plugins/property-data/mcp/src/tools/endpoints.ts +27 -0
  98. package/payload/platform/plugins/property-data/mcp/src/tools/key-deregister.ts +21 -0
  99. package/payload/platform/plugins/property-data/mcp/src/tools/key-list.ts +10 -0
  100. package/payload/platform/plugins/property-data/mcp/src/tools/key-register.ts +58 -0
  101. package/payload/platform/plugins/property-data/mcp/tsconfig.json +20 -0
  102. package/payload/platform/plugins/property-data/mcp/vitest.config.ts +8 -0
  103. package/payload/platform/plugins/property-data/skills/property-data/SKILL.md +58 -0
  104. package/payload/platform/plugins/tasks/mcp/dist/index.js +1 -2
  105. package/payload/platform/plugins/tasks/mcp/dist/index.js.map +1 -1
  106. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.d.ts.map +1 -1
  107. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js +3 -2
  108. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js.map +1 -1
  109. package/payload/platform/plugins/waitlist/PLUGIN.md +6 -8
  110. package/payload/platform/plugins/waitlist/mcp/dist/index.js +33 -0
  111. package/payload/platform/plugins/waitlist/mcp/dist/index.js.map +1 -1
  112. package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.d.ts +16 -0
  113. package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.d.ts.map +1 -0
  114. package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.js +58 -0
  115. package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.js.map +1 -0
  116. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts +34 -0
  117. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts.map +1 -0
  118. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js +129 -0
  119. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js.map +1 -0
  120. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts +12 -18
  121. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts.map +1 -1
  122. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js +89 -86
  123. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js.map +1 -1
  124. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.d.ts.map +1 -1
  125. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.js +15 -53
  126. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.js.map +1 -1
  127. package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -0
  128. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +5 -5
  129. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  130. package/payload/platform/plugins/workflows/PLUGIN.md +10 -176
  131. package/payload/platform/plugins/workflows/mcp/dist/index.js +14 -142
  132. package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
  133. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts +1 -88
  134. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts.map +1 -1
  135. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js +0 -86
  136. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js.map +1 -1
  137. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts +5 -12
  138. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts.map +1 -1
  139. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js +5 -46
  140. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js.map +1 -1
  141. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts +1 -16
  142. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts.map +1 -1
  143. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js +39 -75
  144. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js.map +1 -1
  145. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts +8 -21
  146. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts.map +1 -1
  147. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +39 -266
  148. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
  149. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts +3 -8
  150. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts.map +1 -1
  151. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js +3 -10
  152. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js.map +1 -1
  153. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts.map +1 -1
  154. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js +38 -86
  155. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js.map +1 -1
  156. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.d.ts.map +1 -1
  157. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js +8 -26
  158. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js.map +1 -1
  159. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
  160. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +1 -2
  161. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
  162. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  163. package/payload/platform/services/claude-session-manager/dist/http-server.js +221 -25
  164. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  165. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +39 -1
  166. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  167. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +109 -10
  168. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  169. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts.map +1 -1
  170. package/payload/platform/services/claude-session-manager/dist/reaper.js +11 -0
  171. package/payload/platform/services/claude-session-manager/dist/reaper.js.map +1 -1
  172. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +21 -0
  173. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -1
  174. package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -1
  175. package/payload/platform/services/claude-session-manager/vitest.config.ts +14 -0
  176. package/payload/platform/templates/agents/admin/IDENTITY.md +2 -0
  177. package/payload/platform/templates/agents/admin/SOUL.md +3 -1
  178. package/payload/premium-plugins/real-agent/BUNDLE.md +5 -3
  179. package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
  180. package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
  181. package/payload/premium-plugins/real-agent/plugins/.claude-plugin/marketplace.json +5 -0
  182. package/payload/premium-plugins/real-agent/plugins/brochures/PLUGIN.md +2 -0
  183. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/SKILL.md +100 -0
  184. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/references/render.py +267 -0
  185. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/references/template.html +266 -0
  186. package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-socials/SKILL.md +141 -0
  187. package/payload/premium-plugins/real-agent/plugins/loop/PLUGIN.md +24 -0
  188. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/plugin-md-time-doctrine.test.ts +132 -0
  189. package/payload/premium-plugins/real-agent/plugins/property-data/.claude-plugin/plugin.json +17 -0
  190. package/payload/premium-plugins/real-agent/plugins/property-data/PLUGIN.md +100 -0
  191. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.d.ts +2 -0
  192. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.d.ts.map +1 -0
  193. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.js +153 -0
  194. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.js.map +1 -0
  195. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.d.ts +3 -0
  196. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.d.ts.map +1 -0
  197. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.js +72 -0
  198. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.js.map +1 -0
  199. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.d.ts +5 -0
  200. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.d.ts.map +1 -0
  201. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.js +38 -0
  202. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.js.map +1 -0
  203. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts +29 -0
  204. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts.map +1 -0
  205. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.js +112 -0
  206. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.js.map +1 -0
  207. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.d.ts +14 -0
  208. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.d.ts.map +1 -0
  209. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.js +20 -0
  210. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.js.map +1 -0
  211. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.d.ts +4 -0
  212. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.d.ts.map +1 -0
  213. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.js +19 -0
  214. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.js.map +1 -0
  215. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.d.ts +4 -0
  216. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.d.ts.map +1 -0
  217. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.js +10 -0
  218. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.js.map +1 -0
  219. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.d.ts +5 -0
  220. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.d.ts.map +1 -0
  221. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.js +43 -0
  222. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.js.map +1 -0
  223. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/package-lock.json +2566 -0
  224. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/package.json +21 -0
  225. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/key-roundtrip.test.ts +107 -0
  226. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/propertydata-api.test.ts +184 -0
  227. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/schema-parity.test.ts +48 -0
  228. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/index.ts +249 -0
  229. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/crypto.ts +79 -0
  230. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/neo4j.ts +47 -0
  231. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/propertydata-api.ts +135 -0
  232. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/endpoints.ts +27 -0
  233. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-deregister.ts +21 -0
  234. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-list.ts +10 -0
  235. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-register.ts +58 -0
  236. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/tsconfig.json +20 -0
  237. package/payload/premium-plugins/real-agent/plugins/property-data/mcp/vitest.config.ts +8 -0
  238. package/payload/premium-plugins/real-agent/plugins/property-data/skills/property-data/SKILL.md +58 -0
  239. package/payload/server/{chunk-MEGIQYUD.js → chunk-2IKQERHN.js} +33 -5
  240. package/payload/server/{chunk-XJVJ2B2Q.js → chunk-NPZKH5EC.js} +1 -1
  241. package/payload/server/{chunk-4P2MPERV.js → chunk-X3Y6ENKA.js} +0 -90
  242. package/payload/server/{cloudflare-task-tracker-R6MMORFU.js → cloudflare-task-tracker-TL6R364J.js} +2 -2
  243. package/payload/server/maxy-edge.js +54 -26
  244. package/payload/server/public/assets/admin-2ZJmzJ_g.js +216 -0
  245. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Ch-JZ1Q0.js → architectureDiagram-Q4EWVU46-DgfgldJT.js} +1 -1
  246. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-C08tkD4C.js → blockDiagram-DXYQGD6D-agu8GDzA.js} +1 -1
  247. package/payload/server/public/assets/{brand-DCdOhh-I.css → brand-BDASZqMG.css} +1 -1
  248. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-IceRdWw3.js → c4Diagram-AHTNJAMY-CmNsUmAe.js} +1 -1
  249. package/payload/server/public/assets/channel-DXGOX55q.js +1 -0
  250. package/payload/server/public/assets/{chunk-336JU56O-Cey0rxmH.js → chunk-336JU56O-D9Uts7k9.js} +2 -2
  251. package/payload/server/public/assets/{chunk-426QAEUC-Dzk8s0or.js → chunk-426QAEUC-D4ABqXMn.js} +1 -1
  252. package/payload/server/public/assets/{chunk-4TB4RGXK-C10nuKc8.js → chunk-4TB4RGXK-D1KE4OAX.js} +1 -1
  253. package/payload/server/public/assets/{chunk-5FUZZQ4R-B1B8871D.js → chunk-5FUZZQ4R-CAh0GXe2.js} +1 -1
  254. package/payload/server/public/assets/{chunk-5PVQY5BW-jvHIkgqP.js → chunk-5PVQY5BW-DBHa6HOv.js} +1 -1
  255. package/payload/server/public/assets/{chunk-EDXVE4YY-7nDxvXHS.js → chunk-EDXVE4YY-BDC-6mL3.js} +1 -1
  256. package/payload/server/public/assets/{chunk-ENJZ2VHE-C8lJ1YYn.js → chunk-ENJZ2VHE-CH3uROkW.js} +1 -1
  257. package/payload/server/public/assets/{chunk-ICPOFSXX-CT1d7veI.js → chunk-ICPOFSXX-BzZf0nAw.js} +1 -1
  258. package/payload/server/public/assets/{chunk-OYMX7WX6-LTAfwxv0.js → chunk-OYMX7WX6-BrLHrI6O.js} +1 -1
  259. package/payload/server/public/assets/{chunk-U2HBQHQK-RoGrqrH0.js → chunk-U2HBQHQK-Bw4UkLe_.js} +1 -1
  260. package/payload/server/public/assets/{chunk-X2U36JSP-D89ZBg3z.js → chunk-X2U36JSP-23xgdk05.js} +1 -1
  261. package/payload/server/public/assets/{chunk-YZCP3GAM-Cyg122Hf.js → chunk-YZCP3GAM-BA8iGgRa.js} +1 -1
  262. package/payload/server/public/assets/{chunk-ZZ45TVLE-Dg59YYuG.js → chunk-ZZ45TVLE-B-ol4EgR.js} +1 -1
  263. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DTuuDxpK.js +1 -0
  264. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CIw8RU0q.js +1 -0
  265. package/payload/server/public/assets/clone-O4ZyuvYl.js +1 -0
  266. package/payload/server/public/assets/{dagre-BPzUsxie.js → dagre--kXszEIb.js} +1 -1
  267. package/payload/server/public/assets/{dagre-KV5264BT-CjDNXqPy.js → dagre-KV5264BT-amN1uU2d.js} +1 -1
  268. package/payload/server/public/assets/data-DlmoKxmN.js +1 -0
  269. package/payload/server/public/assets/{device-url-actions-B588ZlnE.js → device-url-actions-CPoz5fqz.js} +1 -1
  270. package/payload/server/public/assets/{diagram-5BDNPKRD-Bqq0vqWM.js → diagram-5BDNPKRD-Cwizs9tP.js} +1 -1
  271. package/payload/server/public/assets/{diagram-G4DWMVQ6-DSqocDhm.js → diagram-G4DWMVQ6-BpSu5Uao.js} +1 -1
  272. package/payload/server/public/assets/{diagram-MMDJMWI5-DZRWgKRL.js → diagram-MMDJMWI5-DiArtkto.js} +1 -1
  273. package/payload/server/public/assets/{diagram-TYMM5635-DXRm-FXu.js → diagram-TYMM5635-_tygK58Y.js} +1 -1
  274. package/payload/server/public/assets/{erDiagram-SMLLAGMA-CFVgkUCo.js → erDiagram-SMLLAGMA-CBV6LWYA.js} +1 -1
  275. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-C82XCt9-.js → flowDiagram-DWJPFMVM-CHZFrtOU.js} +1 -1
  276. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-C4tnImlS.js → ganttDiagram-T4ZO3ILL-B3vKq5ov.js} +1 -1
  277. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DXHutP-a.js → gitGraphDiagram-UUTBAWPF-dnJPjbtj.js} +1 -1
  278. package/payload/server/public/assets/graph-BVvcFSEQ.js +1 -0
  279. package/payload/server/public/assets/graph-labels-cCvgu38Y.js +1 -0
  280. package/payload/server/public/assets/{graphlib-BvR5tL62.js → graphlib-CNXtnega.js} +1 -1
  281. package/payload/server/public/assets/{infoDiagram-42DDH7IO-DgFMqgZy.js → infoDiagram-42DDH7IO-D8DYwVAF.js} +1 -1
  282. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-_5gmh1-V.js → ishikawaDiagram-UXIWVN3A-CfEVY2Ud.js} +1 -1
  283. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CNfDVgwI.js → journeyDiagram-VCZTEJTY-FmoBq7Kh.js} +1 -1
  284. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Djifb_Z6.js → kanban-definition-6JOO6SKY-B-Q9qk99.js} +1 -1
  285. package/payload/server/public/assets/{line-0fRVrNiw.js → line-DZwbJENP.js} +1 -1
  286. package/payload/server/public/assets/{mermaid-parser.core-DXA7LKDt.js → mermaid-parser.core-C3ahKykw.js} +1 -1
  287. package/payload/server/public/assets/{mermaid.core-BCfYtdMJ.js → mermaid.core-B8OFZIE8.js} +3 -3
  288. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-sTRvikWi.js → mindmap-definition-QFDTVHPH-CqhkfbWa.js} +1 -1
  289. package/payload/server/public/assets/{page-nAY64ID7.js → page-BnAxPkmg.js} +1 -1
  290. package/payload/server/public/assets/{page-DDyny08O.js → page-BnaN3u86.js} +1 -1
  291. package/payload/server/public/assets/{pieDiagram-DEJITSTG-QLTieded.js → pieDiagram-DEJITSTG-CJqQ6u3-.js} +1 -1
  292. package/payload/server/public/assets/{public-rUUducAl.js → public-rWe9ADCS.js} +3 -3
  293. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-DOKCcqAZ.js → quadrantDiagram-34T5L4WZ-BtEqOXQM.js} +1 -1
  294. package/payload/server/public/assets/{requirementDiagram-MS252O5E-BX6Zpq1X.js → requirementDiagram-MS252O5E-DPHWUtE6.js} +1 -1
  295. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-B05NdgZX.js → sankeyDiagram-XADWPNL6-FBmc3wHT.js} +1 -1
  296. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CHF8ZdUb.js → sequenceDiagram-FGHM5R23-BMSd2-1M.js} +1 -1
  297. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DTAt7Ytz.js → stateDiagram-FHFEXIEX-DqFbU-LT.js} +1 -1
  298. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CXTnsHGq.js +1 -0
  299. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-Dzd6X_ei.js → timeline-definition-GMOUNBTQ-DsfvHVK8.js} +1 -1
  300. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BAbM4QlQ.js → vennDiagram-DHZGUBPP-kHU05mqC.js} +1 -1
  301. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CIOXXKJd.js → wardleyDiagram-NUSXRM2D-C696Mez_.js} +1 -1
  302. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-oF9sZesS.js → xychartDiagram-5P7HB3ND-yht-JyXJ.js} +1 -1
  303. package/payload/server/public/data.html +5 -5
  304. package/payload/server/public/graph.html +5 -5
  305. package/payload/server/public/index.html +7 -7
  306. package/payload/server/public/public.html +4 -4
  307. package/payload/server/server.js +261 -207
  308. package/payload/server/public/assets/admin-DBuCWSPS.js +0 -216
  309. package/payload/server/public/assets/channel-8QQB2Zoe.js +0 -1
  310. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CViZOOjI.js +0 -1
  311. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Dm7eGBqB.js +0 -1
  312. package/payload/server/public/assets/clone-BC8oes11.js +0 -1
  313. package/payload/server/public/assets/data-BeblX4m4.js +0 -1
  314. package/payload/server/public/assets/graph-ZuBiYril.js +0 -1
  315. package/payload/server/public/assets/graph-labels-CnbJR6cp.js +0 -1
  316. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-2bJIW7wn.js +0 -1
  317. /package/payload/server/public/assets/{brand-Dln107gD.js → brand-BWCtpG7_.js} +0 -0
@@ -1,48 +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
- # Pipeline (Task 114 redesign replaces Task 106's `--print` + stdin-EOT
8
- # shape, which is incompatible with the OAuth subscription the manager runs
9
- # on):
10
- # 1. /spawn with `hidden=true, specialist=database-operator` the manager
11
- # produces a structurally normal admin specialist session (same argv,
12
- # same OAuth path) and returns its sessionId.
13
- # 2. POST /<sessionId>/input with `<instruction>\n\nConversation transcript:\n<filtered JSON>`.
14
- # 3. The manager's recorder-auto-archive subscriber stops the PTY as soon
15
- # as the recorder's JSONL contains an assistant message with
16
- # `stop_reason === "end_turn"`. The hook does not need to follow up.
7
+ # Task 134the 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.
17
27
  #
18
- # Gating:
19
- # - MAXY_SESSION_ROLE must equal "admin"
20
- # - MAXY_HIDDEN_SPAWN must equal "0" (the recorder PTY itself runs with
21
- # 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
22
43
  #
23
44
  # Input: Claude Code's Stop hook stdin shape
24
45
  # { "session_id": "<intrinsic>", "transcript_path": "<jsonl path>", ... }
25
- #
26
- # Failure modes are silent (exit 0) — a failure here must never break the
27
- # operator's session.
28
46
 
29
47
  set -uo pipefail
30
48
 
31
- START_MS=$(python3 -c 'import time; print(int(time.time()*1000))')
32
-
33
- if [ "${MAXY_SESSION_ROLE:-}" != "admin" ]; then
34
- exit 0
35
- fi
36
- 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
37
58
  exit 0
38
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
+ }
39
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=""
40
82
  if [ -t 0 ]; then
41
- exit 0
42
- fi
43
- INPUT=$(cat)
44
- if [ -z "$INPUT" ]; then
45
- exit 0
83
+ INPUT=""
84
+ else
85
+ INPUT=$(cat)
46
86
  fi
47
87
 
48
88
  PARSED=$(printf '%s' "$INPUT" | python3 -c '
@@ -58,111 +98,145 @@ except Exception:
58
98
  ADMIN_SESSION_ID="${PARSED%% *}"
59
99
  TRANSCRIPT_PATH="${PARSED#* }"
60
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
61
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"
62
124
  exit 0
63
125
  fi
64
126
 
65
- # Filter the JSONL tail down to records the database-operator cares about:
66
- # user prompts, assistant messages, and tool calls. Drop ephemeral
67
- # admin-state records that bloat the prompt without graph value.
68
- 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'
69
136
  import sys, json
70
- DROP = {
71
- 'queue-operation', 'auto_mode', 'deferred_tools_delta',
72
- 'last-prompt', 'skill_listing', 'mcp_instructions_delta',
73
- 'permission-mode',
74
- }
75
- def keep(rec):
76
- t = rec.get('type') if isinstance(rec, dict) else None
77
- if not isinstance(t, str): return False
78
- if t in DROP: return False
79
- if t.startswith('hook_'): return False
80
- if t in ('user', 'assistant', 'message'): return True
81
- if 'tool' in t.lower(): return True
82
- 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 ""
83
154
 
84
155
  path = sys.argv[1]
85
- out = []
156
+ last_assistant = ""
157
+ last_user = ""
86
158
  try:
87
- with open(path, 'r', encoding='utf-8') as f:
88
- for line in f:
89
- line = line.strip()
90
- if not line: continue
91
- try: rec = json.loads(line)
92
- except Exception: continue
93
- 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
94
172
  except Exception:
95
- pass
96
- out = out[-200:]
97
- print(json.dumps(out, separators=(',', ':')))
173
+ pass
174
+
175
+ print(last_assistant if last_assistant else last_user, end="")
98
176
  PY
99
177
  )
100
178
 
101
- 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)
102
181
 
103
- MANAGER_PORT="${CLAUDE_SESSION_MANAGER_PORT:-19400}"
104
- MANAGER_BASE="http://127.0.0.1:${MANAGER_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}"
105
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
192
+
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.
106
204
  SPAWN_BODY=$(python3 -c '
107
- import json
205
+ import sys, json
206
+ sid = sys.argv[1]
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
108
210
  body = {
109
- "senderId": "turn-recorder",
110
- "role": "admin",
111
- "channel": "browser",
112
- "hidden": True,
113
211
  "specialist": "database-operator",
212
+ "initialMessage": text,
213
+ "originatingSessionId": sid,
114
214
  }
115
215
  print(json.dumps(body))
116
- ' 2>/dev/null)
216
+ ' "$ADMIN_SESSION_ID" "$LAST_TURN_TEXT" 2>/dev/null)
117
217
 
118
- SPAWN_RES=$(curl -sS -X POST \
218
+ SPAWN_RES_FILE=$(mktemp)
219
+ SPAWN_HTTP=$(curl -sS -o "$SPAWN_RES_FILE" -w '%{http_code}' -X POST \
119
220
  -H 'Content-Type: application/json' \
120
221
  --max-time 10 \
121
222
  --data "$SPAWN_BODY" \
122
- "${MANAGER_BASE}/spawn" 2>/dev/null)
123
-
124
- RECORDER_SESSION_ID=$(printf '%s' "$SPAWN_RES" | python3 -c '
125
- import sys, json
126
- try:
127
- d = json.load(sys.stdin)
128
- print(d.get("sessionId", "") or "")
129
- except Exception:
130
- print("")
131
- ' 2>/dev/null)
132
-
133
- if [ -z "$RECORDER_SESSION_ID" ]; then
134
- echo "turn-completed-graph-write spawn-failed conversationId=${ADMIN_SESSION_ID:0:8}" >&2
135
- exit 0
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)
231
+ rm -f "$SPAWN_RES_FILE"
232
+
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
136
240
  fi
137
241
 
138
- # Compose the input prompt and POST it to /<sessionId>/input. The instruction
139
- # string is fixed (Task 114). The transcript is appended as a JSON array so
140
- # the recorder reads it as a single user turn.
141
- INPUT_BODY=$(python3 -c '
142
- import sys, json
143
- sid = sys.argv[1]
144
- tail_json = sys.argv[2]
145
- instruction = "update the graph with any missing information or intent that can be derived from this conversation"
146
- text = (
147
- f"{instruction}\n\n"
148
- f"Conversation id: {sid}\n"
149
- f"Conversation transcript:\n{tail_json}\n"
150
- )
151
- print(json.dumps({"text": text}))
152
- ' "$ADMIN_SESSION_ID" "$FILTERED_TAIL" 2>/dev/null)
153
-
154
- INPUT_BYTES=$(printf '%s' "$INPUT_BODY" | python3 -c 'import sys,json; b=json.load(sys.stdin); print(len(b.get("text","").encode("utf-8")))' 2>/dev/null || echo 0)
155
-
156
- INPUT_HTTP=$(curl -sS -o /tmp/turn-recorder-input.out -w '%{http_code}' -X POST \
157
- -H 'Content-Type: application/json' \
158
- --max-time 10 \
159
- --data "$INPUT_BODY" \
160
- "${MANAGER_BASE}/${RECORDER_SESSION_ID}/input" 2>/dev/null || echo 000)
161
-
162
- 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
163
-
164
- END_MS=$(python3 -c 'import time; print(int(time.time()*1000))')
165
- ELAPSED=$((END_MS - START_MS))
166
- echo "turn-completed-graph-write fired conversationId=${ADMIN_SESSION_ID:0:8} recorderSessionId=${RECORDER_SESSION_ID:0:8} filtered=${FILTERED_COUNT} ms=${ELAPSED}" >&2
167
-
168
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
  };