@rubytech/create-maxy-code 0.1.51 → 0.1.58

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 +211 -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
@@ -0,0 +1,47 @@
1
+ import neo4j, { Driver, Session } from "neo4j-driver";
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+
5
+ let driver: Driver | null = null;
6
+
7
+ function readPassword(): string {
8
+ if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
9
+ const passwordFile = resolve(
10
+ process.env.PLATFORM_ROOT ?? resolve(import.meta.dirname, "../../../.."),
11
+ "config/.neo4j-password",
12
+ );
13
+ try {
14
+ return readFileSync(passwordFile, "utf-8").trim();
15
+ } catch {
16
+ throw new Error(
17
+ `Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`,
18
+ );
19
+ }
20
+ }
21
+
22
+ export function getDriver(): Driver {
23
+ if (!driver) {
24
+ const uri = process.env.NEO4J_URI;
25
+ if (!uri) {
26
+ throw new Error(
27
+ "[property-data] NEO4J_URI unset — refusing to default to bolt://localhost:7687",
28
+ );
29
+ }
30
+ const user = process.env.NEO4J_USER ?? "neo4j";
31
+ const password = readPassword();
32
+ console.error(`[property-data] resolved neo4j_uri=${uri}`);
33
+ driver = neo4j.driver(uri, neo4j.auth.basic(user, password));
34
+ }
35
+ return driver;
36
+ }
37
+
38
+ export function getSession(): Session {
39
+ return getDriver().session();
40
+ }
41
+
42
+ export async function closeDriver(): Promise<void> {
43
+ if (driver) {
44
+ await driver.close();
45
+ driver = null;
46
+ }
47
+ }
@@ -0,0 +1,135 @@
1
+ import { getSession } from "./neo4j.js";
2
+ import { decrypt } from "./crypto.js";
3
+
4
+ // PropertyData API V1 client. Every endpoint is a GET against
5
+ // https://api.propertydata.co.uk/<endpoint> with `key=<api-key>` plus
6
+ // endpoint-specific query params. Response envelope:
7
+ //
8
+ // { "status": "success", ...payload }
9
+ // { "status": "error", "message": "..." }
10
+ //
11
+ // The `propertyDataCall` helper returns either the parsed payload as a
12
+ // JSON string ready for tool text content, or throws PropertyDataError /
13
+ // KeyNotRegisteredError so the tool wrapper can produce a deterministic
14
+ // error envelope.
15
+
16
+ const BASE_URL = "https://api.propertydata.co.uk";
17
+ const REQUEST_TIMEOUT_MS = 15_000;
18
+
19
+ export class KeyNotRegisteredError extends Error {
20
+ constructor() {
21
+ super("key-not-registered");
22
+ this.name = "KeyNotRegisteredError";
23
+ }
24
+ }
25
+
26
+ export class PropertyDataError extends Error {
27
+ constructor(
28
+ public readonly status: number,
29
+ public readonly endpoint: string,
30
+ public readonly upstreamMessage: string,
31
+ ) {
32
+ super(`http-${status} from PropertyData endpoint=${endpoint}: ${upstreamMessage}`);
33
+ this.name = "PropertyDataError";
34
+ }
35
+ }
36
+
37
+ export class BadResponseError extends Error {
38
+ constructor(public readonly endpoint: string, public readonly length: number) {
39
+ super(`bad-response from PropertyData endpoint=${endpoint} (non-JSON, length=${length})`);
40
+ this.name = "BadResponseError";
41
+ }
42
+ }
43
+
44
+ export interface PropertyDataKey {
45
+ encryptedKey: string;
46
+ createdAt: string;
47
+ updatedAt: string;
48
+ }
49
+
50
+ export async function loadAccountKey(accountId: string): Promise<PropertyDataKey | null> {
51
+ const session = getSession();
52
+ try {
53
+ const result = await session.run(
54
+ `MATCH (k:PropertyDataKey {accountId: $accountId})
55
+ RETURN k.encryptedKey AS encryptedKey,
56
+ k.createdAt AS createdAt,
57
+ k.updatedAt AS updatedAt`,
58
+ { accountId },
59
+ );
60
+ if (result.records.length === 0) return null;
61
+ const r = result.records[0];
62
+ return {
63
+ encryptedKey: r.get("encryptedKey"),
64
+ createdAt: r.get("createdAt") ?? "",
65
+ updatedAt: r.get("updatedAt") ?? "",
66
+ };
67
+ } finally {
68
+ await session.close();
69
+ }
70
+ }
71
+
72
+ export async function resolveAccountApiKey(accountId: string): Promise<string> {
73
+ const stored = await loadAccountKey(accountId);
74
+ if (!stored) throw new KeyNotRegisteredError();
75
+ return decrypt(stored.encryptedKey);
76
+ }
77
+
78
+ export interface CallOptions {
79
+ endpoint: string;
80
+ toolName: string;
81
+ accountId: string;
82
+ params: Record<string, string | number | undefined>;
83
+ }
84
+
85
+ export async function propertyDataCall(opts: CallOptions): Promise<string> {
86
+ const { endpoint, toolName, accountId, params } = opts;
87
+ const apiKey = await resolveAccountApiKey(accountId);
88
+
89
+ const search = new URLSearchParams();
90
+ search.set("key", apiKey);
91
+ for (const [k, v] of Object.entries(params)) {
92
+ if (v === undefined || v === null || v === "") continue;
93
+ search.set(k, String(v));
94
+ }
95
+ const url = `${BASE_URL}/${endpoint}?${search.toString()}`;
96
+
97
+ const postcode = params.postcode ?? "";
98
+ const start = Date.now();
99
+ const response = await fetch(url, {
100
+ headers: { Accept: "application/json" },
101
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
102
+ });
103
+ const ms = Date.now() - start;
104
+
105
+ const statusTag = response.ok ? "ok" : `http-${Math.floor(response.status / 100)}xx`;
106
+ console.error(
107
+ `[property-data] tool=${toolName} account=${accountId} postcode=${postcode} status=${statusTag} ms=${ms}`,
108
+ );
109
+
110
+ if (!response.ok) {
111
+ const body = await response.text().catch(() => "");
112
+ throw new PropertyDataError(response.status, endpoint, body.slice(0, 200));
113
+ }
114
+
115
+ const text = await response.text();
116
+ let parsed: unknown;
117
+ try {
118
+ parsed = JSON.parse(text);
119
+ } catch {
120
+ throw new BadResponseError(endpoint, text.length);
121
+ }
122
+
123
+ if (
124
+ parsed &&
125
+ typeof parsed === "object" &&
126
+ !Array.isArray(parsed) &&
127
+ "status" in parsed &&
128
+ (parsed as { status: unknown }).status === "error"
129
+ ) {
130
+ const msg = String((parsed as { message?: unknown }).message ?? "unknown error");
131
+ throw new PropertyDataError(response.status, endpoint, msg);
132
+ }
133
+
134
+ return JSON.stringify(parsed, null, 2);
135
+ }
@@ -0,0 +1,27 @@
1
+ import { propertyDataCall } from "../lib/propertydata-api.js";
2
+
3
+ // Every endpoint tool takes the same shape: { accountId, ...params }.
4
+ // Per-tool param schemas are enforced by zod in index.ts; this layer only
5
+ // forwards values to the HTTP client.
6
+
7
+ type Args = Record<string, unknown> & { accountId: string };
8
+
9
+ function call(toolName: string, endpoint: string, args: Args): Promise<string> {
10
+ const { accountId, ...rest } = args;
11
+ return propertyDataCall({
12
+ endpoint,
13
+ toolName,
14
+ accountId,
15
+ params: rest as Record<string, string | number | undefined>,
16
+ });
17
+ }
18
+
19
+ export const valuationSale = (a: Args) => call("property-data-valuation-sale", "valuation-sale", a);
20
+ export const valuationRent = (a: Args) => call("property-data-valuation-rent", "valuation-rent", a);
21
+ export const prices = (a: Args) => call("property-data-prices", "prices", a);
22
+ export const pricesRent = (a: Args) => call("property-data-prices-rent", "prices-rent", a);
23
+ export const soldPrices = (a: Args) => call("property-data-sold-prices", "sold-prices", a);
24
+ export const demand = (a: Args) => call("property-data-demand", "demand", a);
25
+ export const yields = (a: Args) => call("property-data-yields", "yields", a);
26
+ export const growth = (a: Args) => call("property-data-growth", "growth", a);
27
+ export const nationalHpi = (a: Args) => call("property-data-national-hpi", "national-hpi", a);
@@ -0,0 +1,21 @@
1
+ import { getSession } from "../lib/neo4j.js";
2
+
3
+ export async function keyDeregister(params: { accountId: string }): Promise<void> {
4
+ const { accountId } = params;
5
+ const session = getSession();
6
+ try {
7
+ const result = await session.run(
8
+ `MATCH (k:PropertyDataKey {accountId: $accountId})
9
+ DELETE k
10
+ RETURN count(k) AS deleted`,
11
+ { accountId },
12
+ );
13
+ const deleted = result.records[0]?.get("deleted")?.toNumber?.() ?? 0;
14
+ if (deleted === 0) {
15
+ throw new Error("No PropertyData API key is registered for this account.");
16
+ }
17
+ } finally {
18
+ await session.close();
19
+ }
20
+ console.error(`[property-data] key-op op=deregister account=${accountId}`);
21
+ }
@@ -0,0 +1,10 @@
1
+ import { loadAccountKey } from "../lib/propertydata-api.js";
2
+
3
+ export async function keyList(params: { accountId: string }): Promise<string> {
4
+ const key = await loadAccountKey(params.accountId);
5
+ console.error(`[property-data] key-op op=list account=${params.accountId}`);
6
+ if (!key) {
7
+ return "No PropertyData API key registered. Use property-data-key-register to add one.";
8
+ }
9
+ return `PropertyData API key registered (created: ${key.createdAt}, updated: ${key.updatedAt}). Key value is encrypted and cannot be retrieved.`;
10
+ }
@@ -0,0 +1,58 @@
1
+ import { getSession } from "../lib/neo4j.js";
2
+ import { encrypt } from "../lib/crypto.js";
3
+ import { PropertyDataError } from "../lib/propertydata-api.js";
4
+
5
+ const BASE_URL = "https://api.propertydata.co.uk";
6
+ const REQUEST_TIMEOUT_MS = 15_000;
7
+
8
+ // Validate by hitting a cheap endpoint that returns success on any valid key:
9
+ // /national-hpi takes no postcode and is rate-cheap. Treat a 200 as the key
10
+ // passing PropertyData's authentication check; treat 401/403 as an explicit
11
+ // key rejection so the operator gets an actionable message; treat anything
12
+ // else as an unverified-key error (network, upstream outage).
13
+ async function validateApiKey(apiKey: string): Promise<void> {
14
+ const url = `${BASE_URL}/national-hpi?key=${encodeURIComponent(apiKey)}`;
15
+ const response = await fetch(url, {
16
+ headers: { Accept: "application/json" },
17
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
18
+ });
19
+ if (response.status === 401 || response.status === 403) {
20
+ throw new Error(`PropertyData rejected the API key (HTTP ${response.status}).`);
21
+ }
22
+ if (!response.ok) {
23
+ const body = await response.text().catch(() => "");
24
+ throw new PropertyDataError(response.status, "national-hpi", body.slice(0, 200));
25
+ }
26
+ }
27
+
28
+ export async function keyRegister(params: {
29
+ apiKey: string;
30
+ accountId: string;
31
+ }): Promise<void> {
32
+ const { apiKey, accountId } = params;
33
+
34
+ await validateApiKey(apiKey);
35
+
36
+ const encryptedKey = encrypt(apiKey);
37
+ const now = new Date().toISOString();
38
+
39
+ const session = getSession();
40
+ try {
41
+ await session.run(
42
+ `CREATE INDEX property_data_key_account IF NOT EXISTS
43
+ FOR (k:PropertyDataKey) ON (k.accountId)`,
44
+ {},
45
+ );
46
+
47
+ await session.run(
48
+ `MERGE (k:PropertyDataKey {accountId: $accountId})
49
+ ON CREATE SET k.encryptedKey = $encryptedKey, k.createdAt = $now, k.updatedAt = $now
50
+ ON MATCH SET k.encryptedKey = $encryptedKey, k.updatedAt = $now`,
51
+ { accountId, encryptedKey, now },
52
+ );
53
+ } finally {
54
+ await session.close();
55
+ }
56
+
57
+ console.error(`[property-data] key-op op=register account=${accountId}`);
58
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "lib": ["ES2022"],
7
+ "outDir": "dist",
8
+ "rootDir": "src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "declaration": true,
15
+ "declarationMap": true,
16
+ "sourceMap": true
17
+ },
18
+ "include": ["src"],
19
+ "exclude": ["src/**/__tests__/**", "src/**/*.test.ts"]
20
+ }
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ["src/**/__tests__/**/*.test.ts"],
6
+ environment: "node",
7
+ },
8
+ });
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: property-data
3
+ description: "Given a UK postcode plus property attributes (type, bedrooms, area), return structured market data — comparable sold prices, asking-price baselines, demand index, rental yield, and growth signals — for valuation and negotiation workflows."
4
+ ---
5
+
6
+ # Property Data
7
+
8
+ Outcome: given a UK postcode and property attributes, return structured market evidence — comparables, asking prices, sold prices, demand, yield, growth — so the valuer composes a valuation brief and the negotiator backs an offer position with numbers, not prose.
9
+
10
+ ## When to use
11
+
12
+ Trigger phrases:
13
+ - "comps for [address|postcode]"
14
+ - "what are properties going for in [postcode]"
15
+ - "demand in [postcode]"
16
+ - "yield on [bedrooms]-bed in [postcode]"
17
+ - "asking prices around [postcode]"
18
+ - "what's it worth — [postcode], [type], [beds]"
19
+ - "sold prices on [street|postcode]"
20
+ - "growth in [postcode]"
21
+
22
+ ## Inputs required
23
+
24
+ - **Postcode** — UK outcode (e.g. `SN7`) or full postcode (e.g. `SN7 8AA`). The PropertyData endpoints accept either; outcode broadens the sample, full postcode tightens it.
25
+ - **Property type** — one of: `detached`, `semi-detached`, `terraced`, `flat`. Required for valuation and price-distribution endpoints.
26
+ - **Bedrooms** — integer. Required for valuation and yield endpoints.
27
+ - **Internal area (sq ft)** — required for `valuation-sale` and `valuation-rent` point estimates. If unknown, fall back to `prices` / `prices-rent` for a distribution and state the area assumption.
28
+
29
+ ## Tools
30
+
31
+ | Tool | Use for | Required inputs |
32
+ |---|---|---|
33
+ | `property-data-valuation-sale` | Point sale-price estimate | postcode, type, bedrooms, bathrooms, internal_area |
34
+ | `property-data-valuation-rent` | Point rent estimate | postcode, type, bedrooms, bathrooms, internal_area |
35
+ | `property-data-prices` | Asking-price distribution (mean / median / 80th pct) | postcode, type, bedrooms |
36
+ | `property-data-prices-rent` | Rent asking-price distribution | postcode, type, bedrooms |
37
+ | `property-data-sold-prices` | Land Registry sold transactions | postcode (max_age, type, bedrooms optional) |
38
+ | `property-data-demand` | Supply count + days to sell-STC | postcode |
39
+ | `property-data-yields` | Gross rental yield | postcode, bedrooms |
40
+ | `property-data-growth` | Short and long-term price growth | postcode |
41
+ | `property-data-national-hpi` | UK national HPI series | (none) |
42
+
43
+ ## Output
44
+
45
+ Return the structured `data` payload directly to the caller (valuer / negotiator). Do not collapse it to prose — downstream skills (`comparable-finder`, `local-market-stats`, `pricing-scenario-builder`) consume the fields.
46
+
47
+ ## Failure modes
48
+
49
+ - `Error: key-not-registered` — surface the registration prompt: "PropertyData API key not registered. Register it with `property-data-key-register`."
50
+ - `Error: http-4xx` — bad input (usually invalid postcode or unsupported type). Restate the inputs the operator gave; do not retry blindly.
51
+ - `Error: http-5xx` — PropertyData upstream outage. Surface the failure and fall back to Loop sold-prices (`loop-property-sold`) if available.
52
+ - Empty `data` — the postcode has insufficient comparables. Broaden the postcode (full → outcode) and retry once; if still empty, surface "no PropertyData comparables for this postcode" and let the agent fall back.
53
+
54
+ ## Do not
55
+
56
+ - Do not compose a valuation figure or asking-price range in this skill — that is the valuer's output contract, composed downstream from the structured data returned here.
57
+ - Do not call any endpoint without a postcode argument (except `national-hpi`).
58
+ - Do not invent fields not returned by PropertyData. If a field is absent, name it as a gap.
@@ -3732,12 +3732,40 @@ var emitMissingOnResolve = (..._args) => null;
3732
3732
  // app/lib/claude-agent/spawn-env.ts
3733
3733
  var getBundleMtimeIso = (..._args) => null;
3734
3734
 
3735
- // app/lib/claude-agent/stream-log-writer.ts
3736
- var appendStreamLogLine = (..._args) => null;
3737
-
3738
3735
  // app/lib/claude-agent/summary-helpers.ts
3739
3736
  var stripAttachmentMetaSuffix = (..._args) => null;
3740
3737
 
3738
+ // ../lib/require-port-env/src/index.ts
3739
+ var MissingPortEnvError = class extends Error {
3740
+ envName;
3741
+ tag;
3742
+ failLine;
3743
+ constructor(envName, tag, failLine, message) {
3744
+ super(message);
3745
+ this.name = "MissingPortEnvError";
3746
+ this.envName = envName;
3747
+ this.tag = tag;
3748
+ this.failLine = failLine;
3749
+ }
3750
+ };
3751
+ var VALID_PORT_MIN = 1;
3752
+ var VALID_PORT_MAX = 65535;
3753
+ function requirePortEnv(envName, options = {}) {
3754
+ const tag = options.tag ?? "port-env";
3755
+ const failLine = options.failLine ?? "missing-port-env";
3756
+ const raw2 = process.env[envName];
3757
+ if (raw2 === void 0 || raw2 === "") {
3758
+ const msg = `[${tag}] ${failLine} reason=missing-env env=${envName}`;
3759
+ throw new MissingPortEnvError(envName, tag, failLine, msg);
3760
+ }
3761
+ const parsed = Number.parseInt(raw2, 10);
3762
+ if (!Number.isInteger(parsed) || parsed < VALID_PORT_MIN || parsed > VALID_PORT_MAX || String(parsed) !== raw2.trim()) {
3763
+ const msg = `[${tag}] ${failLine} reason=invalid-port-env env=${envName} value=${JSON.stringify(raw2)}`;
3764
+ throw new MissingPortEnvError(envName, tag, failLine, msg);
3765
+ }
3766
+ return parsed;
3767
+ }
3768
+
3741
3769
  // server/routes/_helpers.ts
3742
3770
  async function safeJson(c) {
3743
3771
  try {
@@ -4399,8 +4427,8 @@ export {
4399
4427
  reconcileEnabledPlugins,
4400
4428
  emitMissingOnResolve,
4401
4429
  getBundleMtimeIso,
4402
- appendStreamLogLine,
4403
4430
  stripAttachmentMetaSuffix,
4431
+ requirePortEnv,
4404
4432
  safeJson,
4405
4433
  requireAdminSession,
4406
4434
  tryCookieBridgeForConversation,
@@ -14,11 +14,12 @@ import {
14
14
  parseCookieValue,
15
15
  primeSudo,
16
16
  requireAdminCookie,
17
+ requirePortEnv,
17
18
  sanitizeClientCorrId,
18
19
  streamActionEvents,
19
20
  vncLog,
20
21
  websockifyLog
21
- } from "./chunk-CWI7NOWK.js";
22
+ } from "./chunk-2IKQERHN.js";
22
23
  import "./chunk-X3Y6ENKA.js";
23
24
  import "./chunk-JSBRDJBE.js";
24
25
 
@@ -596,32 +597,57 @@ function countClientErrors24h() {
596
597
 
597
598
  // server/routes/admin/version.ts
598
599
  var PLATFORM_ROOT = process.env.MAXY_PLATFORM_ROOT ?? resolve(process.cwd(), "..");
599
- var brandHostname = "maxy";
600
- var brandNpmPackage = "@rubytech/create-maxy";
601
- var brandJsonPath = join2(PLATFORM_ROOT, "config", "brand.json");
602
- if (existsSync3(brandJsonPath)) {
600
+ var DEFAULT_HOSTNAME = "maxy";
601
+ var DEFAULT_NPM_PACKAGE = "@rubytech/create-maxy";
602
+ var FETCH_TIMEOUT_MS = 5e3;
603
+ var fallbackLogged = /* @__PURE__ */ new Set();
604
+ function logFallbackOnce(reason, field, usingDefault) {
605
+ const key = `${reason}:${field}`;
606
+ if (fallbackLogged.has(key)) return;
607
+ fallbackLogged.add(key);
608
+ console.log(`[admin/version] brand-config-fallback reason=${reason} field=${field} using=${usingDefault}`);
609
+ }
610
+ function resolveBrandConfig() {
611
+ const brandJsonPath = join2(PLATFORM_ROOT, "config", "brand.json");
612
+ if (!existsSync3(brandJsonPath)) {
613
+ logFallbackOnce("file-missing", "hostname", DEFAULT_HOSTNAME);
614
+ logFallbackOnce("file-missing", "npm.packageName", DEFAULT_NPM_PACKAGE);
615
+ return { hostname: DEFAULT_HOSTNAME, npmPackage: DEFAULT_NPM_PACKAGE };
616
+ }
617
+ let parsed;
603
618
  try {
604
- const brand = JSON.parse(readFileSync2(brandJsonPath, "utf-8"));
605
- if (brand.hostname) brandHostname = brand.hostname;
606
- if (brand.npm?.packageName) brandNpmPackage = brand.npm.packageName;
619
+ parsed = JSON.parse(readFileSync2(brandJsonPath, "utf-8"));
607
620
  } catch {
621
+ logFallbackOnce("parse-failed", "hostname", DEFAULT_HOSTNAME);
622
+ logFallbackOnce("parse-failed", "npm.packageName", DEFAULT_NPM_PACKAGE);
623
+ return { hostname: DEFAULT_HOSTNAME, npmPackage: DEFAULT_NPM_PACKAGE };
608
624
  }
625
+ let hostname = DEFAULT_HOSTNAME;
626
+ let npmPackage = DEFAULT_NPM_PACKAGE;
627
+ if (typeof parsed?.hostname === "string" && parsed.hostname) {
628
+ hostname = parsed.hostname;
629
+ } else {
630
+ logFallbackOnce("field-missing", "hostname", DEFAULT_HOSTNAME);
631
+ }
632
+ if (typeof parsed?.npm?.packageName === "string" && parsed.npm.packageName) {
633
+ npmPackage = parsed.npm.packageName;
634
+ } else {
635
+ logFallbackOnce("field-missing", "npm.packageName", DEFAULT_NPM_PACKAGE);
636
+ }
637
+ return { hostname, npmPackage };
609
638
  }
610
- var VERSION_FILE = resolve(PLATFORM_ROOT, `config/.${brandHostname}-version`);
611
- var NPM_PACKAGE = brandNpmPackage;
612
- var REGISTRY_URL = `https://registry.npmjs.org/${NPM_PACKAGE}/latest`;
613
- var FETCH_TIMEOUT_MS = 5e3;
614
639
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
615
- function readInstalled() {
616
- if (!existsSync3(VERSION_FILE)) return "unknown";
617
- const content = readFileSync2(VERSION_FILE, "utf-8").trim();
640
+ function readInstalled(versionFile) {
641
+ if (!existsSync3(versionFile)) return "unknown";
642
+ const content = readFileSync2(versionFile, "utf-8").trim();
618
643
  return content || "unknown";
619
644
  }
620
- async function fetchLatest() {
645
+ async function fetchLatest(npmPackage) {
646
+ const registryUrl = `https://registry.npmjs.org/${npmPackage}/latest`;
621
647
  try {
622
648
  const controller = new AbortController();
623
649
  const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
624
- const res = await fetch(REGISTRY_URL, { signal: controller.signal });
650
+ const res = await fetch(registryUrl, { signal: controller.signal });
625
651
  clearTimeout(timer);
626
652
  if (!res.ok) {
627
653
  console.error(`[admin/version] npm registry returned ${res.status}`);
@@ -654,13 +680,15 @@ function isNewer(latest, installed) {
654
680
  }
655
681
  var app5 = new Hono();
656
682
  app5.get("/", async (c) => {
657
- const installed = readInstalled();
658
- const latest = await fetchLatest();
683
+ const { hostname, npmPackage } = resolveBrandConfig();
684
+ const versionFile = resolve(PLATFORM_ROOT, `config/.${hostname}-version`);
685
+ const installed = readInstalled(versionFile);
686
+ const latest = await fetchLatest(npmPackage);
659
687
  const updateAvailable = installed !== "unknown" && latest !== null && isNewer(latest, installed);
660
688
  const outcome = installed === "unknown" ? "stale-version-file" : latest === null ? "fetch-failed" : "ok";
661
689
  const clientErrors24h = countClientErrors24h();
662
690
  console.log(
663
- `[admin/version] outcome=${outcome} installed=${installed} latest=${latest ?? "null"} updateAvailable=${updateAvailable} clientErrors24h=${clientErrors24h} processStartedAt=${PROCESS_STARTED_AT}`
691
+ `[admin/version] outcome=${outcome} installed=${installed} latest=${latest ?? "null"} updateAvailable=${updateAvailable} clientErrors24h=${clientErrors24h} processStartedAt=${PROCESS_STARTED_AT} versionFile=${versionFile} npmPackage=${npmPackage}`
664
692
  );
665
693
  return c.json({ installed, latest, updateAvailable, clientErrors24h, processStartedAt: PROCESS_STARTED_AT });
666
694
  });
@@ -730,10 +758,10 @@ function inlineAsset(filePath) {
730
758
  function readString(value, fallback) {
731
759
  return typeof value === "string" && value.length > 0 ? value : fallback;
732
760
  }
733
- function loadBrand(brandJsonPath2, assetsDir = "") {
734
- if (!brandJsonPath2 || !existsSync4(brandJsonPath2)) return { ...BRAND_DEFAULTS };
761
+ function loadBrand(brandJsonPath, assetsDir = "") {
762
+ if (!brandJsonPath || !existsSync4(brandJsonPath)) return { ...BRAND_DEFAULTS };
735
763
  try {
736
- const parsed = JSON.parse(readFileSync3(brandJsonPath2, "utf-8"));
764
+ const parsed = JSON.parse(readFileSync3(brandJsonPath, "utf-8"));
737
765
  const logoFile = typeof parsed.assets?.logo === "string" ? parsed.assets.logo : null;
738
766
  const logoDataUri = logoFile && assetsDir ? inlineAsset(join3(assetsDir, logoFile)) : null;
739
767
  return {
@@ -853,10 +881,10 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
853
881
  function isPublicHost(host) {
854
882
  return host.startsWith("public.") || aliasDomains.has(host);
855
883
  }
856
- var EDGE_PORT = parseInt(process.env.EDGE_PORT ?? process.env.PORT ?? "19200", 10);
884
+ var EDGE_PORT = requirePortEnv("EDGE_PORT", { tag: "edge" });
857
885
  var EDGE_HOSTNAME = process.env.EDGE_HOSTNAME ?? "0.0.0.0";
858
886
  var UPSTREAM_HOST = process.env.MAXY_UI_HOST ?? "127.0.0.1";
859
- var UPSTREAM_PORT = parseInt(process.env.MAXY_UI_PORT ?? "19199", 10);
887
+ var UPSTREAM_PORT = requirePortEnv("MAXY_UI_PORT", { tag: "edge" });
860
888
  var WEBSOCKIFY_HOST = process.env.WEBSOCKIFY_HOST ?? "127.0.0.1";
861
889
  var WEBSOCKIFY_PORT2 = parseInt(process.env.WEBSOCKIFY_PORT ?? String(WEBSOCKIFY_PORT), 10);
862
890
  var HOP_BY_HOP2 = /* @__PURE__ */ new Set([