@rubytech/create-maxy-code 0.1.63 → 0.1.64

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 (571) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/docs/references/admin-session.md +2 -1
  3. package/payload/platform/plugins/docs/references/platform.md +4 -0
  4. package/payload/platform/services/claude-session-manager/dist/index.js +4 -0
  5. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  6. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +12 -0
  7. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  8. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +67 -19
  9. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  10. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts.map +1 -1
  11. package/payload/platform/services/claude-session-manager/dist/tool-surface.js +19 -4
  12. package/payload/platform/services/claude-session-manager/dist/tool-surface.js.map +1 -1
  13. package/payload/platform/services/claude-session-manager/dist/types.d.ts +5 -0
  14. package/payload/platform/services/claude-session-manager/dist/types.d.ts.map +1 -1
  15. package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
  16. package/payload/premium-plugins/real-agent/BUNDLE.md +2 -4
  17. package/payload/premium-plugins/real-agent/agents/valuer.md +1 -2
  18. package/payload/premium-plugins/real-agent/plugins/epc/.claude-plugin/plugin.json +3 -3
  19. package/payload/premium-plugins/real-agent/plugins/listings/.claude-plugin/plugin.json +1 -1
  20. package/payload/premium-plugins/real-agent/plugins/listings/PLUGIN.md +1 -3
  21. package/payload/premium-plugins/real-agent/plugins/listings/skills/new-instruction/SKILL.md +11 -12
  22. package/payload/premium-plugins/real-agent/plugins/preval/skills/property-preval/SKILL.md +55 -33
  23. package/payload/premium-plugins/real-agent/plugins/preval/skills/property-preval/references/render.py +69 -70
  24. package/payload/premium-plugins/real-agent/plugins/preval/skills/property-preval/references/template-inputs.schema.json +12 -7
  25. package/payload/premium-plugins/real-agent/plugins/preval/skills/property-preval/references/template.html +88 -19
  26. package/payload/premium-plugins/real-agent/specs/03-new-instruction.md +8 -12
  27. package/payload/server/{chunk-2IKQERHN.js → chunk-S6PQA6Q4.js} +43 -34
  28. package/payload/server/maxy-edge.js +1 -1
  29. package/payload/server/server.js +1 -1
  30. package/payload/platform/plugins/brochures/.claude-plugin/plugin.json +0 -8
  31. package/payload/platform/plugins/brochures/PLUGIN.md +0 -38
  32. package/payload/platform/plugins/brochures/commands/make-brochure.md +0 -11
  33. package/payload/platform/plugins/brochures/skills/a4-print-documents/SKILL.md +0 -478
  34. package/payload/platform/plugins/brochures/skills/brand-design/SKILL.md +0 -192
  35. package/payload/platform/plugins/brochures/skills/make-brochure/SKILL.md +0 -354
  36. package/payload/platform/plugins/brochures/skills/make-brochure/references/seller-brief-template.md +0 -115
  37. package/payload/platform/plugins/brochures/skills/property-brochure/SKILL.md +0 -142
  38. package/payload/platform/plugins/brochures/skills/property-brochure/references/build.md +0 -270
  39. package/payload/platform/plugins/brochures/skills/property-brochure/references/copy.md +0 -211
  40. package/payload/platform/plugins/brochures/skills/property-brochure/references/images.md +0 -166
  41. package/payload/platform/plugins/brochures/skills/property-brochure/references/index-landing.md +0 -376
  42. package/payload/platform/plugins/brochures/skills/property-brochure/references/index.html +0 -1288
  43. package/payload/platform/plugins/brochures/skills/property-brochure/references/placeholders.md +0 -250
  44. package/payload/platform/plugins/brochures/skills/property-brochure/references/registers.md +0 -47
  45. package/payload/platform/plugins/brochures/skills/property-brochure/references/seller-brief.md +0 -56
  46. package/payload/platform/plugins/brochures/skills/property-brochure/references/structure.md +0 -249
  47. package/payload/platform/plugins/brochures/skills/property-brochure/references/template.html +0 -2370
  48. package/payload/platform/plugins/brochures/skills/property-extract/SKILL.md +0 -372
  49. package/payload/platform/plugins/brochures/skills/property-market-report/SKILL.md +0 -100
  50. package/payload/platform/plugins/brochures/skills/property-market-report/references/render.py +0 -267
  51. package/payload/platform/plugins/brochures/skills/property-market-report/references/template.html +0 -266
  52. package/payload/platform/plugins/brochures/skills/property-socials/SKILL.md +0 -141
  53. package/payload/platform/plugins/buyers/.claude-plugin/plugin.json +0 -8
  54. package/payload/platform/plugins/buyers/PLUGIN.md +0 -34
  55. package/payload/platform/plugins/buyers/skills/buyer-feedback/SKILL.md +0 -109
  56. package/payload/platform/plugins/buyers/skills/buyer-management/SKILL.md +0 -42
  57. package/payload/platform/plugins/buyers/skills/buyer-management/references/buyer-qualification-questions.md +0 -16
  58. package/payload/platform/plugins/buyers/skills/buyer-management/references/buyer-qualification.md +0 -59
  59. package/payload/platform/plugins/buyers/skills/buyer-management/references/buyer-scripts.md +0 -63
  60. package/payload/platform/plugins/buyers/skills/buyer-management/references/buyer-working-scripts.md +0 -54
  61. package/payload/platform/plugins/buyers/skills/buyer-management/references/feedback-collection.md +0 -42
  62. package/payload/platform/plugins/buyers/skills/buyer-management/references/offer-capture.md +0 -38
  63. package/payload/platform/plugins/buyers/skills/buyer-management/references/viewing-booking.md +0 -32
  64. package/payload/platform/plugins/buyers/skills/buyer-management/references/viewing-management.md +0 -52
  65. package/payload/platform/plugins/buyers/skills/buyer-seller-guides/SKILL.md +0 -407
  66. package/payload/platform/plugins/buyers/skills/buyer-seller-guides/references/care-fees-guide.md +0 -68
  67. package/payload/platform/plugins/buyers/skills/buyer-seller-guides/references/divorce-sales-guide.md +0 -61
  68. package/payload/platform/plugins/buyers/skills/buyer-seller-guides/references/downsizing-guide.md +0 -45
  69. package/payload/platform/plugins/buyers/skills/buyer-seller-guides/references/first-time-buyers.md +0 -92
  70. package/payload/platform/plugins/buyers/skills/buyer-seller-guides/references/first-time-sellers.md +0 -78
  71. package/payload/platform/plugins/buyers/skills/buyer-seller-guides/references/probate-guide.md +0 -53
  72. package/payload/platform/plugins/buyers/skills/buyer-seller-guides/references/upsizing-guide.md +0 -41
  73. package/payload/platform/plugins/buyers/skills/property-enquiry/SKILL.md +0 -126
  74. package/payload/platform/plugins/buyers/skills/viewing-management/SKILL.md +0 -111
  75. package/payload/platform/plugins/epc/.claude-plugin/plugin.json +0 -17
  76. package/payload/platform/plugins/epc/PLUGIN.md +0 -90
  77. package/payload/platform/plugins/epc/mcp/dist/index.d.ts +0 -2
  78. package/payload/platform/plugins/epc/mcp/dist/index.d.ts.map +0 -1
  79. package/payload/platform/plugins/epc/mcp/dist/index.js +0 -117
  80. package/payload/platform/plugins/epc/mcp/dist/index.js.map +0 -1
  81. package/payload/platform/plugins/epc/mcp/dist/lib/crypto.d.ts +0 -3
  82. package/payload/platform/plugins/epc/mcp/dist/lib/crypto.d.ts.map +0 -1
  83. package/payload/platform/plugins/epc/mcp/dist/lib/crypto.js +0 -72
  84. package/payload/platform/plugins/epc/mcp/dist/lib/crypto.js.map +0 -1
  85. package/payload/platform/plugins/epc/mcp/dist/lib/epc-api.d.ts +0 -60
  86. package/payload/platform/plugins/epc/mcp/dist/lib/epc-api.d.ts.map +0 -1
  87. package/payload/platform/plugins/epc/mcp/dist/lib/epc-api.js +0 -181
  88. package/payload/platform/plugins/epc/mcp/dist/lib/epc-api.js.map +0 -1
  89. package/payload/platform/plugins/epc/mcp/dist/lib/file-crypto.d.ts +0 -3
  90. package/payload/platform/plugins/epc/mcp/dist/lib/file-crypto.d.ts.map +0 -1
  91. package/payload/platform/plugins/epc/mcp/dist/lib/file-crypto.js +0 -49
  92. package/payload/platform/plugins/epc/mcp/dist/lib/file-crypto.js.map +0 -1
  93. package/payload/platform/plugins/epc/mcp/dist/lib/key-store.d.ts +0 -15
  94. package/payload/platform/plugins/epc/mcp/dist/lib/key-store.d.ts.map +0 -1
  95. package/payload/platform/plugins/epc/mcp/dist/lib/key-store.js +0 -130
  96. package/payload/platform/plugins/epc/mcp/dist/lib/key-store.js.map +0 -1
  97. package/payload/platform/plugins/epc/mcp/dist/lib/neo4j.d.ts +0 -5
  98. package/payload/platform/plugins/epc/mcp/dist/lib/neo4j.d.ts.map +0 -1
  99. package/payload/platform/plugins/epc/mcp/dist/lib/neo4j.js +0 -38
  100. package/payload/platform/plugins/epc/mcp/dist/lib/neo4j.js.map +0 -1
  101. package/payload/platform/plugins/epc/mcp/dist/tools/key-deregister.d.ts +0 -4
  102. package/payload/platform/plugins/epc/mcp/dist/tools/key-deregister.d.ts.map +0 -1
  103. package/payload/platform/plugins/epc/mcp/dist/tools/key-deregister.js +0 -9
  104. package/payload/platform/plugins/epc/mcp/dist/tools/key-deregister.js.map +0 -1
  105. package/payload/platform/plugins/epc/mcp/dist/tools/key-list.d.ts +0 -4
  106. package/payload/platform/plugins/epc/mcp/dist/tools/key-list.d.ts.map +0 -1
  107. package/payload/platform/plugins/epc/mcp/dist/tools/key-list.js +0 -10
  108. package/payload/platform/plugins/epc/mcp/dist/tools/key-list.js.map +0 -1
  109. package/payload/platform/plugins/epc/mcp/dist/tools/key-register.d.ts +0 -5
  110. package/payload/platform/plugins/epc/mcp/dist/tools/key-register.d.ts.map +0 -1
  111. package/payload/platform/plugins/epc/mcp/dist/tools/key-register.js +0 -36
  112. package/payload/platform/plugins/epc/mcp/dist/tools/key-register.js.map +0 -1
  113. package/payload/platform/plugins/epc/mcp/dist/tools/lookup.d.ts +0 -10
  114. package/payload/platform/plugins/epc/mcp/dist/tools/lookup.d.ts.map +0 -1
  115. package/payload/platform/plugins/epc/mcp/dist/tools/lookup.js +0 -30
  116. package/payload/platform/plugins/epc/mcp/dist/tools/lookup.js.map +0 -1
  117. package/payload/platform/plugins/epc/mcp/package-lock.json +0 -2566
  118. package/payload/platform/plugins/epc/mcp/package.json +0 -21
  119. package/payload/platform/plugins/epc/mcp/src/__tests__/epc-api.test.ts +0 -251
  120. package/payload/platform/plugins/epc/mcp/src/__tests__/key-roundtrip.test.ts +0 -113
  121. package/payload/platform/plugins/epc/mcp/src/__tests__/lookup.test.ts +0 -181
  122. package/payload/platform/plugins/epc/mcp/src/__tests__/schema-parity.test.ts +0 -54
  123. package/payload/platform/plugins/epc/mcp/src/index.ts +0 -156
  124. package/payload/platform/plugins/epc/mcp/src/lib/crypto.ts +0 -79
  125. package/payload/platform/plugins/epc/mcp/src/lib/epc-api.ts +0 -241
  126. package/payload/platform/plugins/epc/mcp/src/lib/file-crypto.ts +0 -55
  127. package/payload/platform/plugins/epc/mcp/src/lib/key-store.ts +0 -172
  128. package/payload/platform/plugins/epc/mcp/src/lib/neo4j.ts +0 -47
  129. package/payload/platform/plugins/epc/mcp/src/tools/key-deregister.ts +0 -9
  130. package/payload/platform/plugins/epc/mcp/src/tools/key-list.ts +0 -10
  131. package/payload/platform/plugins/epc/mcp/src/tools/key-register.ts +0 -44
  132. package/payload/platform/plugins/epc/mcp/src/tools/lookup.ts +0 -43
  133. package/payload/platform/plugins/epc/mcp/tsconfig.json +0 -20
  134. package/payload/platform/plugins/epc/mcp/vitest.config.ts +0 -8
  135. package/payload/platform/plugins/estate-business/.claude-plugin/plugin.json +0 -8
  136. package/payload/platform/plugins/estate-business/PLUGIN.md +0 -64
  137. package/payload/platform/plugins/estate-business/skills/business-growth/SKILL.md +0 -133
  138. package/payload/platform/plugins/estate-business/skills/business-growth/references/buy-back-your-time.md +0 -37
  139. package/payload/platform/plugins/estate-business/skills/business-growth/references/firewave-gost-scorecards.md +0 -14
  140. package/payload/platform/plugins/estate-business/skills/business-growth/references/keller-org-model.md +0 -17
  141. package/payload/platform/plugins/estate-business/skills/business-growth/references/lencioni-team-models.md +0 -22
  142. package/payload/platform/plugins/estate-business/skills/business-growth/references/listing-management-system.md +0 -11
  143. package/payload/platform/plugins/estate-business/skills/business-growth/references/net-figure-form.md +0 -11
  144. package/payload/platform/plugins/estate-business/skills/business-growth/references/serhant-bizinbox-notes.md +0 -13
  145. package/payload/platform/plugins/estate-business/skills/business-growth/references/team-roles-commission.md +0 -14
  146. package/payload/platform/plugins/estate-business/skills/business-growth/references/va-2026-ops.md +0 -43
  147. package/payload/platform/plugins/estate-business/skills/business-growth/references/wingman-structure.md +0 -13
  148. package/payload/platform/plugins/estate-business/skills/business-operations/SKILL.md +0 -32
  149. package/payload/platform/plugins/estate-business/skills/business-operations/references/crm-systems.md +0 -57
  150. package/payload/platform/plugins/estate-business/skills/business-operations/references/hiring-guide.md +0 -59
  151. package/payload/platform/plugins/estate-business/skills/business-operations/references/impact-framework.md +0 -47
  152. package/payload/platform/plugins/estate-business/skills/business-operations/references/minutes-equal-money.md +0 -55
  153. package/payload/platform/plugins/estate-business/skills/business-operations/references/team-management.md +0 -48
  154. package/payload/platform/plugins/estate-business/skills/commission-calculator/SKILL.md +0 -40
  155. package/payload/platform/plugins/estate-business/skills/exp-partnership/SKILL.md +0 -52
  156. package/payload/platform/plugins/estate-business/skills/exp-partnership/references/12-reasons.md +0 -39
  157. package/payload/platform/plugins/estate-business/skills/exp-partnership/references/95-5-system.md +0 -66
  158. package/payload/platform/plugins/estate-business/skills/exp-partnership/references/agent-attraction-scripts.md +0 -90
  159. package/payload/platform/plugins/estate-business/skills/exp-partnership/references/business-partnership.md +0 -92
  160. package/payload/platform/plugins/estate-business/skills/exp-partnership/references/exp-model-overview.md +0 -66
  161. package/payload/platform/plugins/estate-business/skills/exp-partnership/references/model-comparison.md +0 -66
  162. package/payload/platform/plugins/estate-business/skills/exp-partnership/references/revenue-share-explained.md +0 -57
  163. package/payload/platform/plugins/estate-business/skills/month-end-close/SKILL.md +0 -69
  164. package/payload/platform/plugins/estate-business/skills/payment-batch-stager/SKILL.md +0 -42
  165. package/payload/platform/plugins/estate-business/skills/period-reconciler/SKILL.md +0 -42
  166. package/payload/platform/plugins/estate-business/skills/personal-branding/SKILL.md +0 -117
  167. package/payload/platform/plugins/estate-business/skills/personal-branding/references/attraction-agent-notes.md +0 -31
  168. package/payload/platform/plugins/estate-business/skills/personal-branding/references/attraction-agent.md +0 -58
  169. package/payload/platform/plugins/estate-business/skills/personal-branding/references/authenticity-boundaries.md +0 -28
  170. package/payload/platform/plugins/estate-business/skills/personal-branding/references/become-a-brand-leader-notes.md +0 -19
  171. package/payload/platform/plugins/estate-business/skills/personal-branding/references/blast-formula.md +0 -42
  172. package/payload/platform/plugins/estate-business/skills/personal-branding/references/brand-leader.md +0 -48
  173. package/payload/platform/plugins/estate-business/skills/personal-branding/references/brand-strategy-system.md +0 -59
  174. package/payload/platform/plugins/estate-business/skills/personal-branding/references/content-engine.md +0 -49
  175. package/payload/platform/plugins/estate-business/skills/personal-branding/references/firewave-blast-and-blogging.md +0 -23
  176. package/payload/platform/plugins/estate-business/skills/personal-branding/references/gary-v-content.md +0 -52
  177. package/payload/platform/plugins/estate-business/skills/personal-branding/references/gary-v-principles.md +0 -20
  178. package/payload/platform/plugins/estate-business/skills/personal-branding/references/oversubscribed-positioning.md +0 -18
  179. package/payload/platform/plugins/estate-business/skills/personal-branding/references/platforms.md +0 -41
  180. package/payload/platform/plugins/estate-business/skills/personal-branding/references/priestley-oversubscribed.md +0 -54
  181. package/payload/platform/plugins/estate-business/skills/personal-branding/references/storeys-style-examples.md +0 -25
  182. package/payload/platform/plugins/estate-business/skills/personal-branding/references/visual-identity.md +0 -27
  183. package/payload/platform/plugins/estate-coaching/.claude-plugin/plugin.json +0 -8
  184. package/payload/platform/plugins/estate-coaching/PLUGIN.md +0 -54
  185. package/payload/platform/plugins/estate-coaching/skills/agent-performance/SKILL.md +0 -371
  186. package/payload/platform/plugins/estate-coaching/skills/agent-performance/references/atomic-habits.md +0 -52
  187. package/payload/platform/plugins/estate-coaching/skills/agent-performance/references/daily-routine-scorecard.md +0 -104
  188. package/payload/platform/plugins/estate-coaching/skills/agent-performance/references/hp6-model.md +0 -63
  189. package/payload/platform/plugins/estate-coaching/skills/agent-performance/references/twelve-week-year.md +0 -71
  190. package/payload/platform/plugins/estate-coaching/skills/bespoke-coaching/SKILL.md +0 -36
  191. package/payload/platform/plugins/estate-coaching/skills/bespoke-coaching/references/coaching-boundaries.md +0 -56
  192. package/payload/platform/plugins/estate-coaching/skills/bespoke-coaching/references/feedback-framework.md +0 -61
  193. package/payload/platform/plugins/estate-coaching/skills/bespoke-coaching/references/performance-framework.md +0 -109
  194. package/payload/platform/plugins/estate-coaching/skills/coaching-toolkit/SKILL.md +0 -421
  195. package/payload/platform/plugins/estate-coaching/skills/coaching-toolkit/references/coaching-exercises.md +0 -86
  196. package/payload/platform/plugins/estate-coaching/skills/coaching-toolkit/references/goal-setting.md +0 -78
  197. package/payload/platform/plugins/estate-coaching/skills/coaching-toolkit/references/one-to-one-framework.md +0 -92
  198. package/payload/platform/plugins/estate-coaching/skills/coaching-toolkit/references/soi-workbook.md +0 -103
  199. package/payload/platform/plugins/estate-coaching/skills/serhant-training/SKILL.md +0 -410
  200. package/payload/platform/plugins/estate-coaching/skills/serhant-training/references/agent-training-guide.md +0 -70
  201. package/payload/platform/plugins/estate-coaching/skills/serhant-training/references/business-in-a-box.md +0 -72
  202. package/payload/platform/plugins/estate-coaching/skills/serhant-training/references/buyers-guide.md +0 -53
  203. package/payload/platform/plugins/estate-coaching/skills/serhant-training/references/codo-method.md +0 -72
  204. package/payload/platform/plugins/estate-coaching/skills/serhant-training/references/website-planning-guide.md +0 -79
  205. package/payload/platform/plugins/estate-sales/.claude-plugin/plugin.json +0 -8
  206. package/payload/platform/plugins/estate-sales/PLUGIN.md +0 -52
  207. package/payload/platform/plugins/estate-sales/skills/chase-progression/SKILL.md +0 -107
  208. package/payload/platform/plugins/estate-sales/skills/negotiation/SKILL.md +0 -35
  209. package/payload/platform/plugins/estate-sales/skills/negotiation/references/deal-saving.md +0 -47
  210. package/payload/platform/plugins/estate-sales/skills/negotiation/references/negotiation-deep-guide.md +0 -64
  211. package/payload/platform/plugins/estate-sales/skills/negotiation/references/negotiation-prep-principles.md +0 -29
  212. package/payload/platform/plugins/estate-sales/skills/negotiation/references/negotiation-techniques.md +0 -42
  213. package/payload/platform/plugins/estate-sales/skills/negotiation/references/offer-presentation.md +0 -43
  214. package/payload/platform/plugins/estate-sales/skills/risk-scorer/SKILL.md +0 -42
  215. package/payload/platform/plugins/estate-sales/skills/sales-closer/SKILL.md +0 -24
  216. package/payload/platform/plugins/estate-sales/skills/sales-closer/references/serhant-emotion-stages.md +0 -36
  217. package/payload/platform/plugins/estate-sales/skills/sales-discovery/SKILL.md +0 -30
  218. package/payload/platform/plugins/estate-sales/skills/sales-discovery/references/chris-voss-discovery.md +0 -88
  219. package/payload/platform/plugins/estate-sales/skills/sales-discovery/references/firewave-gost-journey.md +0 -68
  220. package/payload/platform/plugins/estate-sales/skills/sales-discovery/references/phil-jones-openers.md +0 -78
  221. package/payload/platform/plugins/estate-sales/skills/sales-discovery/references/pre-listing-checklist.md +0 -77
  222. package/payload/platform/plugins/estate-sales/skills/sales-discovery/references/serhant-improv.md +0 -22
  223. package/payload/platform/plugins/estate-sales/skills/sales-discovery/references/tom-ferry-discovery.md +0 -103
  224. package/payload/platform/plugins/estate-sales/skills/sales-discovery/references/vendor-motivation-competitor.md +0 -52
  225. package/payload/platform/plugins/estate-sales/skills/sales-negotiation/SKILL.md +0 -29
  226. package/payload/platform/plugins/estate-sales/skills/sales-negotiation/references/chris-voss-negotiation.md +0 -70
  227. package/payload/platform/plugins/estate-sales/skills/sales-negotiation/references/phil-jones-price-words.md +0 -40
  228. package/payload/platform/plugins/estate-sales/skills/sales-negotiation/references/serhant-negotiation-plus.md +0 -55
  229. package/payload/platform/plugins/estate-sales/skills/sales-negotiation/references/tom-panos-commission-pricing.md +0 -57
  230. package/payload/platform/plugins/estate-sales/skills/sales-negotiation/references/tony-morris-questioning.md +0 -54
  231. package/payload/platform/plugins/estate-sales/skills/sales-progression/SKILL.md +0 -27
  232. package/payload/platform/plugins/estate-sales/skills/sales-progression/references/conveyancing-guide.md +0 -54
  233. package/payload/platform/plugins/estate-sales/skills/sales-progression/references/transaction-tracking.md +0 -66
  234. package/payload/platform/plugins/estate-teaching/.claude-plugin/plugin.json +0 -8
  235. package/payload/platform/plugins/estate-teaching/PLUGIN.md +0 -30
  236. package/payload/platform/plugins/estate-teaching/skills/content-directory/SKILL.md +0 -39
  237. package/payload/platform/plugins/estate-teaching/skills/content-directory/references/module-delivery.md +0 -65
  238. package/payload/platform/plugins/estate-teaching/skills/content-directory/references/progress-tracking.md +0 -47
  239. package/payload/platform/plugins/leads/.claude-plugin/plugin.json +0 -8
  240. package/payload/platform/plugins/leads/PLUGIN.md +0 -61
  241. package/payload/platform/plugins/leads/skills/chain-progression-tracker/SKILL.md +0 -51
  242. package/payload/platform/plugins/leads/skills/diary-builder/SKILL.md +0 -38
  243. package/payload/platform/plugins/leads/skills/enquiry-triage/SKILL.md +0 -36
  244. package/payload/platform/plugins/leads/skills/lead-nurturing/SKILL.md +0 -137
  245. package/payload/platform/plugins/leads/skills/lead-nurturing/references/buyer-search-letter.md +0 -28
  246. package/payload/platform/plugins/leads/skills/lead-nurturing/references/buyer-search-letters.md +0 -37
  247. package/payload/platform/plugins/leads/skills/lead-nurturing/references/database-reactivation.md +0 -30
  248. package/payload/platform/plugins/leads/skills/lead-nurturing/references/email-nurture-sequences.md +0 -45
  249. package/payload/platform/plugins/leads/skills/lead-nurturing/references/facebook-referrals.md +0 -30
  250. package/payload/platform/plugins/leads/skills/lead-nurturing/references/firewave-email-nurture-sequences.md +0 -41
  251. package/payload/platform/plugins/leads/skills/lead-nurturing/references/keller-33-touch.md +0 -34
  252. package/payload/platform/plugins/leads/skills/lead-nurturing/references/neighbour-letters.md +0 -31
  253. package/payload/platform/plugins/leads/skills/lead-nurturing/references/neighbour-notification-letter.md +0 -20
  254. package/payload/platform/plugins/leads/skills/lead-nurturing/references/ofi-follow-up-dialogue.md +0 -22
  255. package/payload/platform/plugins/leads/skills/lead-nurturing/references/ofi-follow-up.md +0 -26
  256. package/payload/platform/plugins/leads/skills/lead-nurturing/references/serhant-three-fs-plus.md +0 -21
  257. package/payload/platform/plugins/leads/skills/lead-nurturing/references/sharran-10x10x10.md +0 -18
  258. package/payload/platform/plugins/leads/skills/lead-nurturing/references/sms-templates.md +0 -40
  259. package/payload/platform/plugins/leads/skills/lead-nurturing/references/sphere-of-influence-notes.md +0 -34
  260. package/payload/platform/plugins/leads/skills/lead-nurturing/references/sphere-of-influence.md +0 -60
  261. package/payload/platform/plugins/leads/skills/lead-nurturing/references/tom-panos-sms-templates.md +0 -59
  262. package/payload/platform/plugins/leads/skills/morning-round/SKILL.md +0 -72
  263. package/payload/platform/plugins/leads/skills/prospecting/SKILL.md +0 -33
  264. package/payload/platform/plugins/leads/skills/prospecting/references/database-matching.md +0 -30
  265. package/payload/platform/plugins/leads/skills/prospecting/references/database-value.md +0 -53
  266. package/payload/platform/plugins/leads/skills/prospecting/references/prospecting-dialogues.md +0 -24
  267. package/payload/platform/plugins/leads/skills/prospecting/references/reactivation.md +0 -34
  268. package/payload/platform/plugins/listings/.claude-plugin/plugin.json +0 -8
  269. package/payload/platform/plugins/listings/PLUGIN.md +0 -102
  270. package/payload/platform/plugins/listings/skills/comparable-finder/SKILL.md +0 -52
  271. package/payload/platform/plugins/listings/skills/epc-checker/SKILL.md +0 -38
  272. package/payload/platform/plugins/listings/skills/home-preparation/SKILL.md +0 -28
  273. package/payload/platform/plugins/listings/skills/home-preparation/references/kerb-appeal.md +0 -38
  274. package/payload/platform/plugins/listings/skills/home-preparation/references/photo-day.md +0 -59
  275. package/payload/platform/plugins/listings/skills/home-preparation/references/situational-tips.md +0 -50
  276. package/payload/platform/plugins/listings/skills/home-preparation/references/staging-guide.md +0 -52
  277. package/payload/platform/plugins/listings/skills/listing-copy-writer/SKILL.md +0 -55
  278. package/payload/platform/plugins/listings/skills/listing-presentation/SKILL.md +0 -286
  279. package/payload/platform/plugins/listings/skills/listing-presentation/references/booking-script.md +0 -51
  280. package/payload/platform/plugins/listings/skills/listing-presentation/references/objection-scripts.md +0 -193
  281. package/payload/platform/plugins/listings/skills/listing-presentation/references/penhaul-presentation.md +0 -123
  282. package/payload/platform/plugins/listings/skills/listing-presentation/references/pre-listing-kit.md +0 -139
  283. package/payload/platform/plugins/listings/skills/listing-presentation/references/set-to-sell.md +0 -55
  284. package/payload/platform/plugins/listings/skills/listing-presentation/references/sharran-frameworks.md +0 -107
  285. package/payload/platform/plugins/listings/skills/local-market-stats/SKILL.md +0 -33
  286. package/payload/platform/plugins/listings/skills/new-instruction/SKILL.md +0 -78
  287. package/payload/platform/plugins/listings/skills/particulars-builder/SKILL.md +0 -48
  288. package/payload/platform/plugins/listings/skills/portal-launch-scheduler/SKILL.md +0 -49
  289. package/payload/platform/plugins/listings/skills/pricing-scenario-builder/SKILL.md +0 -35
  290. package/payload/platform/plugins/listings/skills/property-marketing/SKILL.md +0 -337
  291. package/payload/platform/plugins/listings/skills/property-marketing/references/auction-report-template.md +0 -41
  292. package/payload/platform/plugins/listings/skills/property-marketing/references/coming-soon-campaign.md +0 -43
  293. package/payload/platform/plugins/listings/skills/property-marketing/references/direct-mail-templates.md +0 -121
  294. package/payload/platform/plugins/listings/skills/property-marketing/references/eoi-form-template.md +0 -62
  295. package/payload/platform/plugins/listings/skills/property-marketing/references/monthly-scorecard.md +0 -63
  296. package/payload/platform/plugins/listings/skills/supplier-booker/SKILL.md +0 -39
  297. package/payload/platform/plugins/listings/skills/talk-track-composer/SKILL.md +0 -36
  298. package/payload/platform/plugins/listings/skills/terms-of-business-drafter/SKILL.md +0 -54
  299. package/payload/platform/plugins/listings/skills/valuation-prep/SKILL.md +0 -69
  300. package/payload/platform/plugins/loop/.claude-plugin/plugin.json +0 -17
  301. package/payload/platform/plugins/loop/PLUGIN.md +0 -260
  302. package/payload/platform/plugins/loop/mcp/dist/index.d.ts +0 -2
  303. package/payload/platform/plugins/loop/mcp/dist/index.d.ts.map +0 -1
  304. package/payload/platform/plugins/loop/mcp/dist/index.js +0 -320
  305. package/payload/platform/plugins/loop/mcp/dist/index.js.map +0 -1
  306. package/payload/platform/plugins/loop/mcp/dist/lib/crypto.d.ts +0 -10
  307. package/payload/platform/plugins/loop/mcp/dist/lib/crypto.d.ts.map +0 -1
  308. package/payload/platform/plugins/loop/mcp/dist/lib/crypto.js +0 -88
  309. package/payload/platform/plugins/loop/mcp/dist/lib/crypto.js.map +0 -1
  310. package/payload/platform/plugins/loop/mcp/dist/lib/file-crypto.d.ts +0 -3
  311. package/payload/platform/plugins/loop/mcp/dist/lib/file-crypto.d.ts.map +0 -1
  312. package/payload/platform/plugins/loop/mcp/dist/lib/file-crypto.js +0 -48
  313. package/payload/platform/plugins/loop/mcp/dist/lib/file-crypto.js.map +0 -1
  314. package/payload/platform/plugins/loop/mcp/dist/lib/key-store.d.ts +0 -22
  315. package/payload/platform/plugins/loop/mcp/dist/lib/key-store.d.ts.map +0 -1
  316. package/payload/platform/plugins/loop/mcp/dist/lib/key-store.js +0 -165
  317. package/payload/platform/plugins/loop/mcp/dist/lib/key-store.js.map +0 -1
  318. package/payload/platform/plugins/loop/mcp/dist/lib/loop-api.d.ts +0 -82
  319. package/payload/platform/plugins/loop/mcp/dist/lib/loop-api.d.ts.map +0 -1
  320. package/payload/platform/plugins/loop/mcp/dist/lib/loop-api.js +0 -392
  321. package/payload/platform/plugins/loop/mcp/dist/lib/loop-api.js.map +0 -1
  322. package/payload/platform/plugins/loop/mcp/dist/lib/neo4j.d.ts +0 -5
  323. package/payload/platform/plugins/loop/mcp/dist/lib/neo4j.d.ts.map +0 -1
  324. package/payload/platform/plugins/loop/mcp/dist/lib/neo4j.js +0 -40
  325. package/payload/platform/plugins/loop/mcp/dist/lib/neo4j.js.map +0 -1
  326. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts +0 -12
  327. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +0 -1
  328. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js +0 -22
  329. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js.map +0 -1
  330. package/payload/platform/plugins/loop/mcp/dist/tools/customer-preferences.d.ts +0 -10
  331. package/payload/platform/plugins/loop/mcp/dist/tools/customer-preferences.d.ts.map +0 -1
  332. package/payload/platform/plugins/loop/mcp/dist/tools/customer-preferences.js +0 -24
  333. package/payload/platform/plugins/loop/mcp/dist/tools/customer-preferences.js.map +0 -1
  334. package/payload/platform/plugins/loop/mcp/dist/tools/feedback.d.ts +0 -16
  335. package/payload/platform/plugins/loop/mcp/dist/tools/feedback.d.ts.map +0 -1
  336. package/payload/platform/plugins/loop/mcp/dist/tools/feedback.js +0 -35
  337. package/payload/platform/plugins/loop/mcp/dist/tools/feedback.js.map +0 -1
  338. package/payload/platform/plugins/loop/mcp/dist/tools/key-deregister.d.ts +0 -5
  339. package/payload/platform/plugins/loop/mcp/dist/tools/key-deregister.d.ts.map +0 -1
  340. package/payload/platform/plugins/loop/mcp/dist/tools/key-deregister.js +0 -9
  341. package/payload/platform/plugins/loop/mcp/dist/tools/key-deregister.js.map +0 -1
  342. package/payload/platform/plugins/loop/mcp/dist/tools/key-list.d.ts +0 -4
  343. package/payload/platform/plugins/loop/mcp/dist/tools/key-list.d.ts.map +0 -1
  344. package/payload/platform/plugins/loop/mcp/dist/tools/key-list.js +0 -14
  345. package/payload/platform/plugins/loop/mcp/dist/tools/key-list.js.map +0 -1
  346. package/payload/platform/plugins/loop/mcp/dist/tools/key-register.d.ts +0 -9
  347. package/payload/platform/plugins/loop/mcp/dist/tools/key-register.d.ts.map +0 -1
  348. package/payload/platform/plugins/loop/mcp/dist/tools/key-register.js +0 -43
  349. package/payload/platform/plugins/loop/mcp/dist/tools/key-register.js.map +0 -1
  350. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -6
  351. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +0 -1
  352. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js +0 -7
  353. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +0 -1
  354. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match-batch.d.ts +0 -9
  355. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match-batch.d.ts.map +0 -1
  356. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match-batch.js +0 -16
  357. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match-batch.js.map +0 -1
  358. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match-request.d.ts +0 -15
  359. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match-request.d.ts.map +0 -1
  360. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match-request.js +0 -11
  361. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match-request.js.map +0 -1
  362. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match.d.ts +0 -10
  363. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match.d.ts.map +0 -1
  364. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match.js +0 -39
  365. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-match.js.map +0 -1
  366. package/payload/platform/plugins/loop/mcp/dist/tools/people-detail.d.ts +0 -9
  367. package/payload/platform/plugins/loop/mcp/dist/tools/people-detail.d.ts.map +0 -1
  368. package/payload/platform/plugins/loop/mcp/dist/tools/people-detail.js +0 -125
  369. package/payload/platform/plugins/loop/mcp/dist/tools/people-detail.js.map +0 -1
  370. package/payload/platform/plugins/loop/mcp/dist/tools/people-search.d.ts +0 -18
  371. package/payload/platform/plugins/loop/mcp/dist/tools/people-search.d.ts.map +0 -1
  372. package/payload/platform/plugins/loop/mcp/dist/tools/people-search.js +0 -87
  373. package/payload/platform/plugins/loop/mcp/dist/tools/people-search.js.map +0 -1
  374. package/payload/platform/plugins/loop/mcp/dist/tools/property-detail.d.ts +0 -10
  375. package/payload/platform/plugins/loop/mcp/dist/tools/property-detail.d.ts.map +0 -1
  376. package/payload/platform/plugins/loop/mcp/dist/tools/property-detail.js +0 -82
  377. package/payload/platform/plugins/loop/mcp/dist/tools/property-detail.js.map +0 -1
  378. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts +0 -33
  379. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +0 -1
  380. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js +0 -19
  381. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js.map +0 -1
  382. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -11
  383. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +0 -1
  384. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js +0 -26
  385. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js.map +0 -1
  386. package/payload/platform/plugins/loop/mcp/dist/tools/property-request.d.ts +0 -15
  387. package/payload/platform/plugins/loop/mcp/dist/tools/property-request.d.ts.map +0 -1
  388. package/payload/platform/plugins/loop/mcp/dist/tools/property-request.js +0 -11
  389. package/payload/platform/plugins/loop/mcp/dist/tools/property-request.js.map +0 -1
  390. package/payload/platform/plugins/loop/mcp/dist/tools/property-search.d.ts +0 -16
  391. package/payload/platform/plugins/loop/mcp/dist/tools/property-search.d.ts.map +0 -1
  392. package/payload/platform/plugins/loop/mcp/dist/tools/property-search.js +0 -41
  393. package/payload/platform/plugins/loop/mcp/dist/tools/property-search.js.map +0 -1
  394. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts +0 -9
  395. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +0 -1
  396. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js +0 -19
  397. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js.map +0 -1
  398. package/payload/platform/plugins/loop/mcp/dist/tools/supplier.d.ts +0 -13
  399. package/payload/platform/plugins/loop/mcp/dist/tools/supplier.d.ts.map +0 -1
  400. package/payload/platform/plugins/loop/mcp/dist/tools/supplier.js +0 -49
  401. package/payload/platform/plugins/loop/mcp/dist/tools/supplier.js.map +0 -1
  402. package/payload/platform/plugins/loop/mcp/dist/tools/team-availability.d.ts +0 -7
  403. package/payload/platform/plugins/loop/mcp/dist/tools/team-availability.d.ts.map +0 -1
  404. package/payload/platform/plugins/loop/mcp/dist/tools/team-availability.js +0 -19
  405. package/payload/platform/plugins/loop/mcp/dist/tools/team-availability.js.map +0 -1
  406. package/payload/platform/plugins/loop/mcp/dist/tools/team-info.d.ts +0 -5
  407. package/payload/platform/plugins/loop/mcp/dist/tools/team-info.d.ts.map +0 -1
  408. package/payload/platform/plugins/loop/mcp/dist/tools/team-info.js +0 -32
  409. package/payload/platform/plugins/loop/mcp/dist/tools/team-info.js.map +0 -1
  410. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-create.d.ts +0 -14
  411. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-create.d.ts.map +0 -1
  412. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-create.js +0 -11
  413. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-create.js.map +0 -1
  414. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-detail.d.ts +0 -9
  415. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-detail.d.ts.map +0 -1
  416. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-detail.js +0 -85
  417. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-detail.js.map +0 -1
  418. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-search.d.ts +0 -13
  419. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-search.d.ts.map +0 -1
  420. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-search.js +0 -44
  421. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-search.js.map +0 -1
  422. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-update.d.ts +0 -14
  423. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-update.d.ts.map +0 -1
  424. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-update.js +0 -18
  425. package/payload/platform/plugins/loop/mcp/dist/tools/viewing-update.js.map +0 -1
  426. package/payload/platform/plugins/loop/mcp/package-lock.json +0 -2549
  427. package/payload/platform/plugins/loop/mcp/package.json +0 -21
  428. package/payload/platform/plugins/loop/mcp/src/__tests__/loop-swagger.snapshot.json +0 -26467
  429. package/payload/platform/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +0 -99
  430. package/payload/platform/plugins/loop/mcp/src/__tests__/plugin-md-time-doctrine.test.ts +0 -132
  431. package/payload/platform/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +0 -154
  432. package/payload/platform/plugins/loop/mcp/src/index.ts +0 -498
  433. package/payload/platform/plugins/loop/mcp/src/lib/crypto.ts +0 -105
  434. package/payload/platform/plugins/loop/mcp/src/lib/file-crypto.ts +0 -54
  435. package/payload/platform/plugins/loop/mcp/src/lib/key-store.ts +0 -221
  436. package/payload/platform/plugins/loop/mcp/src/lib/loop-api.ts +0 -567
  437. package/payload/platform/plugins/loop/mcp/src/lib/neo4j.ts +0 -51
  438. package/payload/platform/plugins/loop/mcp/src/tools/auto-responder.ts +0 -80
  439. package/payload/platform/plugins/loop/mcp/src/tools/customer-preferences.ts +0 -66
  440. package/payload/platform/plugins/loop/mcp/src/tools/feedback.ts +0 -86
  441. package/payload/platform/plugins/loop/mcp/src/tools/key-deregister.ts +0 -12
  442. package/payload/platform/plugins/loop/mcp/src/tools/key-list.ts +0 -19
  443. package/payload/platform/plugins/loop/mcp/src/tools/key-register.ts +0 -70
  444. package/payload/platform/plugins/loop/mcp/src/tools/marketing-enquiry.ts +0 -27
  445. package/payload/platform/plugins/loop/mcp/src/tools/marketing-match-batch.ts +0 -53
  446. package/payload/platform/plugins/loop/mcp/src/tools/marketing-match-request.ts +0 -42
  447. package/payload/platform/plugins/loop/mcp/src/tools/marketing-match.ts +0 -84
  448. package/payload/platform/plugins/loop/mcp/src/tools/people-detail.ts +0 -245
  449. package/payload/platform/plugins/loop/mcp/src/tools/people-search.ts +0 -180
  450. package/payload/platform/plugins/loop/mcp/src/tools/property-detail.ts +0 -145
  451. package/payload/platform/plugins/loop/mcp/src/tools/property-intent.ts +0 -84
  452. package/payload/platform/plugins/loop/mcp/src/tools/property-listed.ts +0 -81
  453. package/payload/platform/plugins/loop/mcp/src/tools/property-search.ts +0 -92
  454. package/payload/platform/plugins/loop/mcp/src/tools/property-sold.ts +0 -67
  455. package/payload/platform/plugins/loop/mcp/src/tools/supplier.ts +0 -129
  456. package/payload/platform/plugins/loop/mcp/src/tools/team-availability.ts +0 -52
  457. package/payload/platform/plugins/loop/mcp/src/tools/team-info.ts +0 -95
  458. package/payload/platform/plugins/loop/mcp/src/tools/viewing-create.ts +0 -41
  459. package/payload/platform/plugins/loop/mcp/src/tools/viewing-detail.ts +0 -171
  460. package/payload/platform/plugins/loop/mcp/src/tools/viewing-search.ts +0 -92
  461. package/payload/platform/plugins/loop/mcp/src/tools/viewing-update.ts +0 -53
  462. package/payload/platform/plugins/loop/mcp/tsconfig.json +0 -20
  463. package/payload/platform/plugins/loop/mcp/vitest.config.ts +0 -9
  464. package/payload/platform/plugins/loop/skills/compliance-flag-checker/SKILL.md +0 -53
  465. package/payload/platform/plugins/loop/skills/priority-ranker/SKILL.md +0 -40
  466. package/payload/platform/plugins/loop/skills/tone-matched-drafter/SKILL.md +0 -53
  467. package/payload/platform/plugins/loop/skills/variance-narrator/SKILL.md +0 -50
  468. package/payload/platform/plugins/loop/skills/vendor-research/SKILL.md +0 -54
  469. package/payload/platform/plugins/preval/.claude-plugin/plugin.json +0 -8
  470. package/payload/platform/plugins/preval/PLUGIN.md +0 -55
  471. package/payload/platform/plugins/preval/hooks/preval-prompt-required.sh +0 -140
  472. package/payload/platform/plugins/preval/skills/property-preval/SKILL.md +0 -176
  473. package/payload/platform/plugins/preval/skills/property-preval/references/__tests__/adherence.test.py +0 -373
  474. package/payload/platform/plugins/preval/skills/property-preval/references/render.py +0 -815
  475. package/payload/platform/plugins/preval/skills/property-preval/references/template-inputs.schema.json +0 -199
  476. package/payload/platform/plugins/preval/skills/property-preval/references/template.html +0 -312
  477. package/payload/platform/plugins/property-data/.claude-plugin/plugin.json +0 -17
  478. package/payload/platform/plugins/property-data/PLUGIN.md +0 -180
  479. package/payload/platform/plugins/property-data/mcp/dist/index.d.ts +0 -2
  480. package/payload/platform/plugins/property-data/mcp/dist/index.d.ts.map +0 -1
  481. package/payload/platform/plugins/property-data/mcp/dist/index.js +0 -236
  482. package/payload/platform/plugins/property-data/mcp/dist/index.js.map +0 -1
  483. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts +0 -3
  484. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts.map +0 -1
  485. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js +0 -72
  486. package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js.map +0 -1
  487. package/payload/platform/plugins/property-data/mcp/dist/lib/file-crypto.d.ts +0 -3
  488. package/payload/platform/plugins/property-data/mcp/dist/lib/file-crypto.d.ts.map +0 -1
  489. package/payload/platform/plugins/property-data/mcp/dist/lib/file-crypto.js +0 -49
  490. package/payload/platform/plugins/property-data/mcp/dist/lib/file-crypto.js.map +0 -1
  491. package/payload/platform/plugins/property-data/mcp/dist/lib/key-store.d.ts +0 -15
  492. package/payload/platform/plugins/property-data/mcp/dist/lib/key-store.d.ts.map +0 -1
  493. package/payload/platform/plugins/property-data/mcp/dist/lib/key-store.js +0 -135
  494. package/payload/platform/plugins/property-data/mcp/dist/lib/key-store.js.map +0 -1
  495. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts +0 -5
  496. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts.map +0 -1
  497. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js +0 -38
  498. package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js.map +0 -1
  499. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts +0 -28
  500. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts.map +0 -1
  501. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js +0 -101
  502. package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js.map +0 -1
  503. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts +0 -24
  504. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts.map +0 -1
  505. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js +0 -33
  506. package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js.map +0 -1
  507. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts +0 -4
  508. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts.map +0 -1
  509. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js +0 -9
  510. package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js.map +0 -1
  511. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts +0 -4
  512. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts.map +0 -1
  513. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js +0 -10
  514. package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js.map +0 -1
  515. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts +0 -5
  516. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts.map +0 -1
  517. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js +0 -50
  518. package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js.map +0 -1
  519. package/payload/platform/plugins/property-data/mcp/package-lock.json +0 -2566
  520. package/payload/platform/plugins/property-data/mcp/package.json +0 -21
  521. package/payload/platform/plugins/property-data/mcp/src/__tests__/endpoints.test.ts +0 -252
  522. package/payload/platform/plugins/property-data/mcp/src/__tests__/key-roundtrip.test.ts +0 -107
  523. package/payload/platform/plugins/property-data/mcp/src/__tests__/propertydata-api.test.ts +0 -184
  524. package/payload/platform/plugins/property-data/mcp/src/__tests__/schema-parity.test.ts +0 -62
  525. package/payload/platform/plugins/property-data/mcp/src/index.ts +0 -409
  526. package/payload/platform/plugins/property-data/mcp/src/lib/crypto.ts +0 -79
  527. package/payload/platform/plugins/property-data/mcp/src/lib/file-crypto.ts +0 -55
  528. package/payload/platform/plugins/property-data/mcp/src/lib/key-store.ts +0 -181
  529. package/payload/platform/plugins/property-data/mcp/src/lib/neo4j.ts +0 -47
  530. package/payload/platform/plugins/property-data/mcp/src/lib/propertydata-api.ts +0 -120
  531. package/payload/platform/plugins/property-data/mcp/src/tools/endpoints.ts +0 -47
  532. package/payload/platform/plugins/property-data/mcp/src/tools/key-deregister.ts +0 -9
  533. package/payload/platform/plugins/property-data/mcp/src/tools/key-list.ts +0 -10
  534. package/payload/platform/plugins/property-data/mcp/src/tools/key-register.ts +0 -54
  535. package/payload/platform/plugins/property-data/mcp/tsconfig.json +0 -20
  536. package/payload/platform/plugins/property-data/mcp/vitest.config.ts +0 -8
  537. package/payload/platform/plugins/property-data/skills/property-data/SKILL.md +0 -77
  538. package/payload/platform/plugins/vendors/.claude-plugin/plugin.json +0 -8
  539. package/payload/platform/plugins/vendors/PLUGIN.md +0 -33
  540. package/payload/platform/plugins/vendors/skills/vendor-communication/SKILL.md +0 -42
  541. package/payload/platform/plugins/vendors/skills/vendor-communication/references/fee-protection-and-agenda.md +0 -28
  542. package/payload/platform/plugins/vendors/skills/vendor-communication/references/listing-scripts.md +0 -44
  543. package/payload/platform/plugins/vendors/skills/vendor-communication/references/negotiation-deep-guide.md +0 -70
  544. package/payload/platform/plugins/vendors/skills/vendor-communication/references/price-alignment-scripts.md +0 -33
  545. package/payload/platform/plugins/vendors/skills/vendor-communication/references/price-alignment.md +0 -34
  546. package/payload/platform/plugins/vendors/skills/vendor-communication/references/scenario-scripts.md +0 -38
  547. package/payload/platform/plugins/vendors/skills/vendor-communication/references/seller-engagement.md +0 -51
  548. package/payload/platform/plugins/vendors/skills/vendor-communication/references/valuation-booking.md +0 -76
  549. package/payload/platform/plugins/vendors/skills/vendor-communication/references/vendor-scripts.md +0 -63
  550. package/payload/platform/plugins/vendors/skills/vendor-communication/references/vendor-updates.md +0 -41
  551. package/payload/platform/plugins/vendors/skills/vendor-updates/SKILL.md +0 -153
  552. package/payload/premium-plugins/real-agent/plugins/epc/PLUGIN.md +0 -90
  553. package/payload/premium-plugins/real-agent/plugins/epc/mcp/package-lock.json +0 -2566
  554. package/payload/premium-plugins/real-agent/plugins/epc/mcp/package.json +0 -21
  555. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/__tests__/epc-api.test.ts +0 -251
  556. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/__tests__/key-roundtrip.test.ts +0 -113
  557. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/__tests__/lookup.test.ts +0 -181
  558. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/__tests__/schema-parity.test.ts +0 -54
  559. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/index.ts +0 -156
  560. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/crypto.ts +0 -79
  561. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/epc-api.ts +0 -241
  562. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/file-crypto.ts +0 -55
  563. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/key-store.ts +0 -172
  564. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/lib/neo4j.ts +0 -47
  565. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/tools/key-deregister.ts +0 -9
  566. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/tools/key-list.ts +0 -10
  567. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/tools/key-register.ts +0 -44
  568. package/payload/premium-plugins/real-agent/plugins/epc/mcp/src/tools/lookup.ts +0 -43
  569. package/payload/premium-plugins/real-agent/plugins/epc/mcp/tsconfig.json +0 -20
  570. package/payload/premium-plugins/real-agent/plugins/epc/mcp/vitest.config.ts +0 -8
  571. package/payload/premium-plugins/real-agent/plugins/listings/skills/epc-checker/SKILL.md +0 -38
@@ -1,815 +0,0 @@
1
- """property-preval renderer.
2
-
3
- Substitutes <!-- REPLACE: <slot> --> placeholders in template.html with values
4
- derived from one inputs.json (shape: template-inputs.schema.json), drives
5
- Chrome headless to produce a 5-page A4 PDF, and asserts page count == 5.
6
-
7
- Fails loud on any missing / unverifiable load-bearing input. No silent
8
- fallback modes — see _assert_inputs. Task 157 layers provenance gates
9
- (market_summary.origin, agent_listings[].origin, agent_overrides) on top
10
- of 156's load-bearing-input checks.
11
-
12
- Usage:
13
- python3 render.py inputs.json
14
- """
15
- from __future__ import annotations
16
- import html, json, re, shutil, subprocess, sys, time
17
- from pathlib import Path
18
-
19
-
20
- M2_TO_SQFT = 10.7639
21
-
22
-
23
- def _money(n: int) -> str:
24
- return f"£{int(n):,}"
25
-
26
-
27
- def _range_money(low: int, high: int) -> str:
28
- return f"£{int(low):,} – £{int(high):,}"
29
-
30
-
31
- # ---------------- helpers ----------------
32
-
33
- def _short_address(address: str) -> str:
34
- """First two address tokens for the cover meta strip."""
35
- parts = [p.strip() for p in address.split(",")]
36
- return ", ".join(parts[:2]) if len(parts) >= 2 else address
37
-
38
-
39
- def _sold_comps_rows(rows: list[dict]) -> str:
40
- if not rows:
41
- return '<tr><td colspan="4" class="muted">No sold transactions in the sample.</td></tr>'
42
- return "".join(
43
- f"<tr><td>{html.escape(r['date'])}</td>"
44
- f"<td>{html.escape(r['address'])}</td>"
45
- f"<td>{html.escape(r['type'])}</td>"
46
- f"<td class=\"num\">{_money(r['price'])}</td></tr>"
47
- for r in rows[:6]
48
- )
49
-
50
-
51
- def _asking_comps_tiles(rows: list[dict]) -> str:
52
- if not rows:
53
- return '<div class="muted">No live asking comps in the sample.</div>'
54
- out = []
55
- for r in rows[:4]:
56
- meta_bits = []
57
- if r.get("beds"):
58
- meta_bits.append(f"{r['beds']} bed")
59
- if r.get("type"):
60
- meta_bits.append(html.escape(r["type"]))
61
- meta = " · ".join(meta_bits) or "&nbsp;"
62
- out.append(
63
- f'<div class="ask-tile">'
64
- f'<div class="addr">{html.escape(r["address"])}</div>'
65
- f'<div class="price">{_money(r["price"])}</div>'
66
- f'<div class="meta">{meta}</div>'
67
- f"</div>"
68
- )
69
- return "".join(out)
70
-
71
-
72
- def _type_dist_rows(rows: list[dict]) -> str:
73
- if not rows:
74
- return '<div class="muted">No property-type mix data.</div>'
75
- ordered = sorted(rows, key=lambda r: float(r["pct"]), reverse=True)
76
- return "".join(
77
- f'<div class="dist-row">'
78
- f'<div class="name">{html.escape(r["name"])}</div>'
79
- f'<div class="bar"><span{" class=gold" if i == 0 else ""} style="width:{float(r["pct"]):.0f}%"></span></div>'
80
- f'<div class="pct">{float(r["pct"]):.1f}%</div>'
81
- f"</div>"
82
- for i, r in enumerate(ordered)
83
- )
84
-
85
-
86
- def _spark_svg(price_series: list[dict], psf_series: list[dict]) -> str:
87
- """Two-line sparkline in a 1000x380 viewBox SVG, no external deps."""
88
- W, H = 1000, 380
89
- pad_l, pad_r, pad_t, pad_b = 70, 30, 30, 50
90
- iw, ih = W - pad_l - pad_r, H - pad_t - pad_b
91
-
92
- def _line(series, key, css_pl, css_pt):
93
- if not series:
94
- return ""
95
- ys = [float(p[key]) for p in series]
96
- ymin, ymax = min(ys), max(ys)
97
- if ymax == ymin:
98
- ymax = ymin + 1
99
- n = len(series)
100
- pts, circles, labels = [], [], []
101
- for i, p in enumerate(series):
102
- x = pad_l + (i * iw / max(1, n - 1))
103
- y = pad_t + ih - ((float(p[key]) - ymin) / (ymax - ymin)) * ih
104
- pts.append(f"{x:.1f},{y:.1f}")
105
- circles.append(f'<circle class="{css_pt}" cx="{x:.1f}" cy="{y:.1f}" r="3"/>')
106
- labels.append(
107
- f'<text x="{x:.1f}" y="{H - 18}" text-anchor="middle">{html.escape(p["label"])}</text>'
108
- )
109
- return (
110
- f'<polyline class="{css_pl}" points="{" ".join(pts)}"/>'
111
- + "".join(circles) + "".join(labels)
112
- )
113
-
114
- axis = (
115
- f'<line class="axis" x1="{pad_l}" y1="{pad_t + ih}" x2="{W - pad_r}" y2="{pad_t + ih}"/>'
116
- )
117
- body = axis + _line(price_series, "price", "pl", "pt") + _line(psf_series, "psf", "pl-psf", "pt-psf")
118
- return (
119
- f'<svg class="spark" viewBox="0 0 {W} {H}" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">{body}</svg>'
120
- )
121
-
122
-
123
- def _summary_paragraphs(paras: list[str]) -> str:
124
- if not paras:
125
- return ""
126
- out = [f'<p class="dropcap">{html.escape(paras[0])}</p>']
127
- for p in paras[1:]:
128
- out.append(f"<p>{html.escape(p)}</p>")
129
- return "".join(out)
130
-
131
-
132
- def _wordmark(brand: dict, variant: str, out_dir: Path) -> str:
133
- """variant ∈ {'light', 'dark'}. Mirrors property-market-report's wordmark."""
134
- key = "logo_light" if variant == "light" else "logo_dark"
135
- logo_path = brand.get(key)
136
- if logo_path:
137
- src = Path(logo_path).expanduser()
138
- dest_dir = out_dir / "img"
139
- dest_dir.mkdir(parents=True, exist_ok=True)
140
- dest = dest_dir / src.name
141
- if src.resolve() != dest.resolve():
142
- shutil.copy2(src, dest)
143
- rel = f"img/{src.name}"
144
- height = "14mm" if variant == "light" else "9mm"
145
- return f'<img src="{html.escape(rel)}" alt="{html.escape(brand["name"])}" style="height:{height};width:auto;display:block">'
146
- cls = "wm light" if variant == "light" else "wm small"
147
- return (
148
- f'<div class="{cls}">'
149
- f'<span class="wm-name">{html.escape(brand["name"])}</span>'
150
- f'<span class="wm-sub">{html.escape(brand["tagline"])}</span>'
151
- f"</div>"
152
- )
153
-
154
-
155
- def _hero_asset(subject: dict, out_dir: Path) -> str:
156
- """Copy subject.cover_hero into img/ and return the relative path. URLs pass through."""
157
- hero = subject["cover_hero"]
158
- if hero.startswith(("http://", "https://", "data:")):
159
- return hero
160
- src = Path(hero).expanduser()
161
- if not src.exists():
162
- raise FileNotFoundError(f"subject.cover_hero not found: {src}")
163
- dest_dir = out_dir / "img"
164
- dest_dir.mkdir(parents=True, exist_ok=True)
165
- dest = dest_dir / f"hero{src.suffix.lower()}"
166
- if src.resolve() != dest.resolve():
167
- shutil.copy2(src, dest)
168
- return f"img/{dest.name}"
169
-
170
-
171
- def _listing_card(p: dict, index: int, out_dir: Path) -> str:
172
- addr_parts = [x.strip() for x in p["address"].split(",")]
173
- addr = html.escape(addr_parts[0])
174
- chips = []
175
- if p.get("beds"): chips.append(f"{p['beds']} bed")
176
- if p.get("type"): chips.append(html.escape(p["type"]))
177
- chips_html = "".join(f"<span>{c}</span>" for c in chips)
178
- img_src = ""
179
- if p.get("image"):
180
- src = Path(p["image"]).expanduser() if not str(p["image"]).startswith(("http://", "https://", "data:")) else None
181
- if src and src.exists():
182
- dest_dir = out_dir / "img"
183
- dest_dir.mkdir(parents=True, exist_ok=True)
184
- dest = dest_dir / f"agent-{index:02d}-{p['slug']}{src.suffix.lower()}"
185
- if src.resolve() != dest.resolve():
186
- shutil.copy2(src, dest)
187
- img_src = f"img/{dest.name}"
188
- elif src is None:
189
- img_src = str(p["image"])
190
- status = p.get("status", "")
191
- badge_cls = {"Sold": "sold", "Under offer": "under"}.get(status, "")
192
- photo = (
193
- f'<div class="photo">'
194
- f'{f"<img src=\"{html.escape(img_src)}\" alt=\"{addr}\">" if img_src else ""}'
195
- f'<div class="badge {badge_cls}">{html.escape(status)}</div>'
196
- f"</div>"
197
- )
198
- meta = (
199
- f'<div class="meta">'
200
- f'<div class="addr">{addr}</div>'
201
- f'<div class="price">{_money(p["price"])}</div>'
202
- f'<div class="kfs">{chips_html}</div>'
203
- f"</div>"
204
- )
205
- inner = photo + meta
206
- if p.get("url"):
207
- return f'<a class="listing" href="{html.escape(p["url"])}" target="_blank" rel="noopener">{inner}</a>'
208
- return f'<div class="listing">{inner}</div>'
209
-
210
-
211
- def _agent_listings_cards(rows: list[dict], out_dir: Path) -> str:
212
- if not rows:
213
- return '<div class="muted" style="margin-top:5mm">No recent listings supplied.</div>'
214
- return "".join(_listing_card(p, i, out_dir) for i, p in enumerate(rows[:6]))
215
-
216
-
217
- # ---------------- valuation maths ----------------
218
-
219
- def _valuation_block(subject: dict, valuation: dict) -> str:
220
- """Build the page-2 valuation panel: headline range, adjustments, final range.
221
-
222
- The three EPC certificate fields are asserted non-null upstream by
223
- _assert_inputs — no fallback panel here. sqft is derived from
224
- total_floor_area_m2 via M2_TO_SQFT.
225
- """
226
- sqft = _derived_sqft(subject)
227
- low_psf = valuation["sold_psf_low"]
228
- mid_psf = valuation["sold_psf"]
229
- high_psf = valuation["sold_psf_high"]
230
- ask_psf = valuation["asking_psf"]
231
-
232
- low_raw = int(sqft * low_psf)
233
- mid_raw = int(sqft * mid_psf)
234
- high_raw = int(sqft * high_psf)
235
- ask_raw = int(sqft * ask_psf)
236
-
237
- rows = [
238
- ('<div class="val-row headline">'
239
- f'<div class="lbl">Headline range<small>{sqft:,} sqft × £{low_psf}–£{high_psf} sold £/sqft (Land Registry 70pc band)</small></div>'
240
- f'<div class="num">{_range_money(low_raw, high_raw)}</div></div>'),
241
- ('<div class="val-row">'
242
- f'<div class="lbl">Cross-check · asking £/sqft<small>{sqft:,} sqft × £{ask_psf} mean asking £/sqft</small></div>'
243
- f'<div class="num">{_money(ask_raw)}</div></div>'),
244
- ]
245
-
246
- adjustments = subject.get("adjustments") or []
247
- if adjustments:
248
- rows.append('<div class="val-row"><div class="lbl" style="font-family:var(--sans);font-weight:600;font-size:8pt;letter-spacing:2pt;text-transform:uppercase;color:var(--text-accent)">Adjustments</div><div class="num">&nbsp;</div></div>')
249
- for adj in adjustments:
250
- delta = float(adj["delta_pct"])
251
- cls = "pos" if delta > 0 else ("neg" if delta < 0 else "")
252
- sign = "+" if delta >= 0 else ""
253
- rows.append(
254
- '<div class="val-row adj">'
255
- f'<div class="lbl">{html.escape(adj["label"])}</div>'
256
- f'<div class="num {cls}">{sign}{delta:.1f}%</div>'
257
- "</div>"
258
- )
259
-
260
- delta_sum = sum(float(a["delta_pct"]) for a in adjustments)
261
- factor = 1.0 + delta_sum / 100.0
262
- low_final = int(low_raw * factor)
263
- high_final = int(high_raw * factor)
264
-
265
- final = (
266
- '<div class="val-final">'
267
- f'<div class="lbl">Final indicative range</div>'
268
- f'<div class="num">{_range_money(low_final, high_final)}</div>'
269
- "</div>"
270
- )
271
-
272
- return '<div class="val-panel">' + "".join(rows) + "</div>" + final
273
-
274
-
275
- def _derived_sqft(subject: dict) -> int:
276
- return round(float(subject["total_floor_area_m2"]) * M2_TO_SQFT)
277
-
278
-
279
- def _kpi_subject_sqft(subject: dict) -> tuple[str, str]:
280
- sqft = _derived_sqft(subject)
281
- m2 = float(subject["total_floor_area_m2"])
282
- return f"{sqft:,}", f"≈ {m2:.0f} m² · from EPC certificate"
283
-
284
-
285
- def _kpi_subject_epc(subject: dict) -> tuple[str, str]:
286
- current = subject["current_energy_rating"]
287
- lodgement = subject["lodgement_date"]
288
- return current, f"lodged {lodgement}"
289
-
290
-
291
- # ---------------- input assertions ----------------
292
-
293
- class PrevalAbort(RuntimeError):
294
- """Raised when a load-bearing input is missing or unverifiable.
295
-
296
- .cause is the short slug logged as `reason=<cause>` and shown in the
297
- operator's remediation hint.
298
- """
299
- def __init__(self, cause: str, hint: str):
300
- super().__init__(f"{cause}: {hint}")
301
- self.cause = cause
302
- self.hint = hint
303
-
304
-
305
- _STREET_TOKEN_STOPWORDS = {
306
- "the", "a", "an", "of", "and",
307
- "road", "street", "drive", "lane", "avenue", "close", "court",
308
- "place", "way", "gardens", "crescent", "hill", "rise", "grove",
309
- "terrace", "mews", "square", "park", "walk", "row",
310
- "rd", "st", "dr", "ln", "ave", "cl", "ct", "pl",
311
- }
312
-
313
-
314
- def _street_token(address: str) -> str | None:
315
- """First non-stopword token from the address's street component.
316
-
317
- Used to detect cover_hero photos sourced from a sister property folder.
318
- "9 Phoenix Drive, Bishop's Stortford, CM23 2UJ" → "phoenix".
319
- """
320
- if not address:
321
- return None
322
- first = address.split(",")[0].strip().lower()
323
- for raw in re.split(r"[^a-z]+", first):
324
- if raw and not raw.isdigit() and raw not in _STREET_TOKEN_STOPWORDS:
325
- return raw
326
- return None
327
-
328
-
329
- def _assert_path_image(path_str: str, min_w: int = 1200, min_h: int = 800) -> None:
330
- """Existence + dimension check. Symlinks pointing into another property's
331
- folder are rejected (cover-hero cross-contamination guard)."""
332
- p = Path(path_str).expanduser()
333
- if not p.exists():
334
- raise PrevalAbort(
335
- "subject-cover-hero-missing",
336
- f"cover_hero path does not exist: {p}",
337
- )
338
- if p.is_symlink():
339
- target = p.resolve()
340
- parts = target.parts
341
- if "properties" in parts:
342
- raise PrevalAbort(
343
- "subject-cover-hero-symlinked-foreign",
344
- f"cover_hero is a symlink into another property's folder: {target}",
345
- )
346
- w, h = _image_dimensions(p)
347
- if w is None or h is None:
348
- raise PrevalAbort(
349
- "subject-cover-hero-unreadable",
350
- f"cover_hero is not a readable PNG or JPEG: {p}",
351
- )
352
- if w < min_w or h < min_h:
353
- raise PrevalAbort(
354
- "subject-cover-hero-too-small",
355
- f"cover_hero is {w}×{h}, below the {min_w}×{min_h} minimum: {p}",
356
- )
357
-
358
-
359
- def _image_dimensions(p: Path) -> tuple[int | None, int | None]:
360
- """Return (width, height) for PNG or JPEG. None on any failure."""
361
- try:
362
- with p.open("rb") as f:
363
- head = f.read(24)
364
- if len(head) < 24:
365
- return None, None
366
- if head[:8] == b"\x89PNG\r\n\x1a\n":
367
- w = int.from_bytes(head[16:20], "big")
368
- h = int.from_bytes(head[20:24], "big")
369
- return w, h
370
- if head[:2] == b"\xff\xd8":
371
- f.seek(2)
372
- while True:
373
- b = f.read(1)
374
- while b and b != b"\xff":
375
- b = f.read(1)
376
- marker = f.read(1)
377
- if not marker:
378
- return None, None
379
- if 0xC0 <= marker[0] <= 0xCF and marker[0] not in (0xC4, 0xC8, 0xCC):
380
- f.read(3)
381
- h = int.from_bytes(f.read(2), "big")
382
- w = int.from_bytes(f.read(2), "big")
383
- return w, h
384
- seg_len = int.from_bytes(f.read(2), "big")
385
- f.seek(seg_len - 2, 1)
386
- return None, None
387
- except OSError:
388
- return None, None
389
-
390
-
391
- def _assert_inputs(inputs: dict) -> None:
392
- """Fail loud on any missing or unverifiable load-bearing input.
393
-
394
- Task 156 causes (load-bearing inputs):
395
- subject-cover-hero-*, brand-unresolved,
396
- agent-listings-empty, market-summary-too-thin.
397
-
398
- Task 157 causes (provenance — agent didn't invent the input):
399
- cover-hero-not-subject, agent-listings-invented,
400
- market-summary-invented, brand-invented.
401
-
402
- Task 163 cause (EPC certificate paste-in completes 157's mandate):
403
- epc-certificate-not-supplied — any of total_floor_area_m2,
404
- current_energy_rating, lodgement_date is null/missing.
405
- """
406
- subject = inputs.get("subject") or {}
407
- address = inputs.get("address") or ""
408
- overrides = inputs.get("agent_overrides") or {}
409
-
410
- # --- 163: EPC certificate fields are operator paste-in ---
411
- missing_epc = [
412
- f for f in ("total_floor_area_m2", "current_energy_rating", "lodgement_date")
413
- if not subject.get(f)
414
- ]
415
- if missing_epc:
416
- raise PrevalAbort(
417
- "epc-certificate-not-supplied",
418
- f"subject is missing EPC certificate field(s) {missing_epc}. "
419
- "Paste total_floor_area_m2, current_energy_rating, and lodgement_date "
420
- "from the EPC certificate into subject before re-invoking. "
421
- "No mid-run prompt — the operator supplies the certificate before invocation.",
422
- )
423
-
424
- hero = subject.get("cover_hero")
425
- if not hero:
426
- raise PrevalAbort(
427
- "subject-cover-hero-missing",
428
- "subject.cover_hero is required for the cover page.",
429
- )
430
- if not hero.startswith(("http://", "https://", "data:")):
431
- _assert_path_image(hero)
432
-
433
- brand = inputs.get("brand") or {}
434
- required_brand = ("name", "tagline", "primary", "primary_dark", "accent", "paper", "paper_banded", "rule")
435
- missing_brand = [k for k in required_brand if not brand.get(k)]
436
- if missing_brand:
437
- raise PrevalAbort(
438
- "brand-unresolved",
439
- f"brand is missing required token(s) {missing_brand} — resolve from the agent's on-disk DESIGN.md before invocation.",
440
- )
441
-
442
- if not inputs.get("agent_listings"):
443
- raise PrevalAbort(
444
- "agent-listings-empty",
445
- "agent_listings is empty — paste at least one recent listing for the closing page.",
446
- )
447
-
448
- ms = inputs.get("market_summary") or {}
449
- paras = ms.get("paragraphs") or []
450
- if len(paras) < 2:
451
- raise PrevalAbort(
452
- "market-summary-too-thin",
453
- f"market_summary.paragraphs has {len(paras)} entries — minimum 2.",
454
- )
455
-
456
- # --- 157: provenance gates ---
457
- if hero and not hero.startswith(("http://", "https://", "data:")):
458
- hero_lc = hero.lower()
459
- match = re.search(r"/properties?/([^/]+)/", hero_lc)
460
- if match:
461
- slug = match.group(1)
462
- street = _street_token(address)
463
- if street and street not in slug:
464
- raise PrevalAbort(
465
- "cover-hero-not-subject",
466
- f"subject.cover_hero ({hero}) sits in a property folder whose "
467
- f"slug ({slug}) does not contain the subject street token "
468
- f"({street}). Prompt the operator for the subject's own photo.",
469
- )
470
-
471
- if not overrides.get("listings_status_curated"):
472
- for listing in inputs.get("agent_listings") or []:
473
- origin = (listing or {}).get("origin")
474
- if not origin or origin == "operator":
475
- continue
476
- src = Path(str(origin)).expanduser()
477
- if not src.exists():
478
- continue
479
- try:
480
- source = json.loads(src.read_text())
481
- except (OSError, json.JSONDecodeError):
482
- continue
483
- if source.get("status") in (None, "") and listing.get("status"):
484
- raise PrevalAbort(
485
- "agent-listings-invented",
486
- f"agent_listings entry {listing.get('slug')} has status "
487
- f"'{listing['status']}' but source {src} carries status:null. "
488
- "Prompt the operator to confirm each status, then set "
489
- "agent_overrides.listings_status_curated: true.",
490
- )
491
-
492
- if ms.get("origin") not in ("operator", "operator-edited-llm-stub"):
493
- raise PrevalAbort(
494
- "market-summary-invented",
495
- "market_summary.origin must be 'operator' or 'operator-edited-llm-stub'. "
496
- "Have the operator draft or accept the paragraphs before rendering — "
497
- "the agent never invents the market narrative unprompted.",
498
- )
499
-
500
- if brand.get("name") and not overrides.get("brand_selected_by_operator"):
501
- raise PrevalAbort(
502
- "brand-invented",
503
- f"brand.name ('{brand['name']}') was set without "
504
- "agent_overrides.brand_selected_by_operator: true. Ask the operator "
505
- "which estate agent is pitching for this instruction; the presence "
506
- "of a DESIGN.md on disk does not authorise selection.",
507
- )
508
-
509
-
510
- # ---------------- render ----------------
511
-
512
- def render(inputs: dict, out_dir: Path, template_path: Path | None = None) -> Path:
513
- _assert_inputs(inputs)
514
-
515
- template_path = template_path or (Path(__file__).parent / "template.html")
516
- tmpl = template_path.read_text()
517
-
518
- brand = inputs["brand"]
519
- subject = inputs["subject"]
520
- v = inputs["valuation"]
521
- a = inputs["area"]
522
- d = inputs["demand_trend"]
523
- ms = inputs["market_summary"]
524
- r = d["rental"]
525
-
526
- out_dir.mkdir(parents=True, exist_ok=True)
527
-
528
- subject_sqft, subject_sqft_sub = _kpi_subject_sqft(subject)
529
- subject_epc, subject_epc_sub = _kpi_subject_epc(subject)
530
-
531
- yoy = d.get("yoy_growth_pct")
532
- if yoy is None and len(d.get("growth_series", [])) >= 2:
533
- last, prev = d["growth_series"][-1]["price"], d["growth_series"][-2]["price"]
534
- yoy = (last - prev) / prev * 100.0
535
- yoy_str = f"{yoy:+.1f}%" if yoy is not None else "—"
536
-
537
- psf = d.get("sales_per_month")
538
- if psf is None:
539
- psf = max(1, round(d["for_sale"] / 7))
540
-
541
- slots = {
542
- "brand_name": brand["name"],
543
- "brand_tagline": brand["tagline"],
544
- "brand_primary": brand["primary"],
545
- "brand_primary_dark": brand["primary_dark"],
546
- "brand_accent": brand["accent"],
547
- "brand_paper": brand["paper"],
548
- "brand_paper_banded": brand["paper_banded"],
549
- "brand_rule": brand["rule"],
550
- "wordmark_light": _wordmark(brand, "light", out_dir),
551
- "wordmark_dark": _wordmark(brand, "dark", out_dir),
552
-
553
- "subject_hero_path": _hero_asset(subject, out_dir),
554
- "address": inputs["address"],
555
- "address_short": _short_address(inputs["address"]),
556
- "postcode": inputs["postcode"],
557
- "generated": inputs["generated"],
558
-
559
- "kpi_subject_sqft": subject_sqft,
560
- "kpi_subject_sqft_sub": subject_sqft_sub,
561
- "kpi_subject_beds": str(subject.get("beds") or "—"),
562
- "kpi_subject_epc": subject_epc,
563
- "kpi_subject_epc_sub": subject_epc_sub,
564
- "kpi_subject_type": subject.get("type") or "—",
565
- "kpi_subject_tenure": subject.get("tenure") or "Tenure unknown",
566
- "valuation_block": _valuation_block(subject, v),
567
- "subject_narrative": subject.get("narrative") or "",
568
-
569
- "summary_headline": ms["headline"],
570
- "summary_paragraphs": _summary_paragraphs(ms["paragraphs"]),
571
- "kpi_avg_asking": _money(v["avg_asking"]),
572
- "kpi_avg_sold": _money(v["avg_sold"]),
573
- "kpi_psf": _money(v["asking_psf"]),
574
- "kpi_yoy": yoy_str,
575
- "demand_rating": d["demand_rating"],
576
- "gauge_position": ms["demand_gauge_position"],
577
- "price_growth_note": ms["price_growth_note"],
578
- "demand_note": ms["demand_note"],
579
- "spark_svg": _spark_svg(d.get("growth_series", []), d.get("growth_psf_series", [])),
580
-
581
- "sold_comps_rows": _sold_comps_rows(v.get("sold_comps", [])),
582
- "asking_comps_tiles": _asking_comps_tiles(v.get("asking_comps", [])),
583
-
584
- "agent_listings_cards": _agent_listings_cards(inputs["agent_listings"], out_dir),
585
- }
586
-
587
- text_slots = {
588
- "address", "address_short", "postcode", "generated",
589
- "brand_name", "brand_tagline",
590
- "kpi_subject_beds", "kpi_subject_epc", "kpi_subject_epc_sub",
591
- "kpi_subject_sqft", "kpi_subject_sqft_sub",
592
- "kpi_subject_type", "kpi_subject_tenure",
593
- "summary_headline", "demand_rating",
594
- "price_growth_note", "demand_note", "subject_narrative",
595
- }
596
- for k in text_slots:
597
- slots[k] = html.escape(str(slots[k]))
598
-
599
- out = tmpl
600
- for k, val in slots.items():
601
- out = out.replace(f"<!-- REPLACE: {k} -->", val)
602
-
603
- leftovers = re.findall(r"<!-- REPLACE: (\w+) -->", out)
604
- if leftovers:
605
- raise RuntimeError(
606
- "template has unfilled placeholders: " + ", ".join(sorted(set(leftovers)))
607
- )
608
-
609
- out_path = out_dir / "index.html"
610
- out_path.write_text(out)
611
- return out_path
612
-
613
-
614
- def render_pdf(out_dir: Path, pdf_name: str) -> Path:
615
- chrome = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
616
- if not Path(chrome).exists():
617
- raise FileNotFoundError(
618
- "Chrome not found at " + chrome + " — install Chrome or override the path."
619
- )
620
- pdf_path = out_dir / pdf_name
621
- subprocess.run([
622
- chrome, "--headless", "--disable-gpu", "--no-pdf-header-footer",
623
- f"--print-to-pdf={pdf_path.resolve()}", "--virtual-time-budget=30000",
624
- f"file://{(out_dir / 'index.html').resolve()}",
625
- ], check=True, capture_output=True)
626
- return pdf_path
627
-
628
-
629
- _PAGE_OBJ_RE = re.compile(rb"/Type\s*/Page(?![sA-Za-z])")
630
-
631
-
632
- def _count_pages(pdf_path: Path) -> int:
633
- pdfinfo = shutil.which("pdfinfo")
634
- if pdfinfo:
635
- result = subprocess.run(
636
- [pdfinfo, str(pdf_path)], check=True, capture_output=True, text=True,
637
- )
638
- for line in result.stdout.splitlines():
639
- if line.startswith("Pages:"):
640
- return int(line.split(":", 1)[1].strip())
641
- raise RuntimeError(f"pdfinfo emitted no Pages line for {pdf_path}")
642
- return len(_PAGE_OBJ_RE.findall(pdf_path.read_bytes()))
643
-
644
-
645
- def assert_page_count(pdf_path: Path, expected: int) -> int:
646
- n = _count_pages(pdf_path)
647
- if n != expected:
648
- raise RuntimeError(
649
- f"page-count mismatch: expected {expected}, got {n} ({pdf_path}) — "
650
- "tighten panel padding for the overflowing page"
651
- )
652
- return n
653
-
654
-
655
- # The 12 PropertyData fan-out tools the preval skill is contracted to call.
656
- # Each tool the MCP server runs emits a `[property-data] tool=<name> ...` line
657
- # (see propertydata-api.ts:92). The watchdog asserts every one of these names
658
- # appears in the log within the 60s budget after `[preval] start`; a missing
659
- # line means the fan-out silently dropped a call and the agent was about to
660
- # render against an incomplete payload.
661
- EXPECTED_PROPERTY_DATA_TOOLS = (
662
- "property-data-prices",
663
- "property-data-prices-per-sqf",
664
- "property-data-sold-prices",
665
- "property-data-sold-prices-per-sqf",
666
- "property-data-growth",
667
- "property-data-growth-psf",
668
- "property-data-demand",
669
- "property-data-demand-rent",
670
- "property-data-property-types",
671
- "property-data-crime",
672
- "property-data-flood-risk",
673
- "property-data-council-tax",
674
- )
675
-
676
-
677
- def _missing_property_data_tools(log_text: str) -> list[str]:
678
- """Return EXPECTED_PROPERTY_DATA_TOOLS that have no `[property-data] tool=<name>` line in log_text."""
679
- return [
680
- name for name in EXPECTED_PROPERTY_DATA_TOOLS
681
- if f"[property-data] tool={name} " not in log_text
682
- and not log_text.endswith(f"[property-data] tool={name}")
683
- and f"[property-data] tool={name}\n" not in log_text
684
- ]
685
-
686
-
687
- def _assert_observability_logs(log_path: Path, *, deadline_s: float = 60.0,
688
- poll_s: float = 2.0, _now=time.monotonic,
689
- _sleep=time.sleep) -> None:
690
- """Poll the log until every PropertyData fan-out tool emitted its line.
691
-
692
- Aborts with cause `observability-missing tool=<name>` once deadline_s
693
- elapses if any expected name is still missing. `_now` and `_sleep` are
694
- injectable for tests so the 60s budget can be exercised without
695
- wall-clock waits.
696
- """
697
- deadline = _now() + deadline_s
698
- while True:
699
- try:
700
- text = log_path.read_text()
701
- except OSError:
702
- text = ""
703
- missing = _missing_property_data_tools(text)
704
- if not missing:
705
- return
706
- if _now() >= deadline:
707
- raise PrevalAbort(
708
- f"observability-missing tool={missing[0]}",
709
- f"PropertyData tool {missing[0]} did not emit "
710
- f"`[property-data] tool={missing[0]} ...` within {int(deadline_s)}s "
711
- "of [preval] start. The fan-out silently dropped one or more calls; "
712
- "re-invoke and confirm every PropertyData tool returned before render. "
713
- f"Other missing tool(s): {missing[1:] or 'none'}.",
714
- )
715
- _sleep(poll_s)
716
-
717
-
718
- def _pick_log_path(out_dir: Path) -> Path:
719
- """~/.maxy/logs/server.log if writable, else <out_dir>/preval.log.
720
-
721
- Aborts with `log-destination-unavailable` if neither is writable —
722
- silent runs are a contract violation.
723
- """
724
- primary = Path("~/.maxy/logs/server.log").expanduser()
725
- for candidate in (primary, out_dir / "preval.log"):
726
- try:
727
- candidate.parent.mkdir(parents=True, exist_ok=True)
728
- with candidate.open("a"):
729
- pass
730
- return candidate
731
- except OSError:
732
- continue
733
- raise PrevalAbort(
734
- "log-destination-unavailable",
735
- "Neither ~/.maxy/logs/server.log nor <out_dir>/preval.log is writable. "
736
- "Fix filesystem permissions before re-running.",
737
- )
738
-
739
-
740
- def _log_line(log_path: Path | None, line: str) -> None:
741
- if log_path is not None:
742
- try:
743
- with log_path.open("a") as f:
744
- f.write(line + "\n")
745
- except OSError:
746
- pass
747
- print(line, file=sys.stderr)
748
-
749
-
750
- def _abort(cause: str, hint: str, *, address: str, postcode: str, t0: float,
751
- out_dir: Path | None, log_path: Path | None) -> None:
752
- ms = int((time.monotonic() - t0) * 1000)
753
- _log_line(
754
- log_path,
755
- f'[preval] aborted reason={cause} address="{address}" postcode={postcode} ms={ms}',
756
- )
757
- print(hint, file=sys.stderr)
758
- if out_dir is not None:
759
- p = out_dir / "index.html"
760
- if p.exists():
761
- p.unlink()
762
- sys.exit(2)
763
-
764
-
765
- def main():
766
- t0 = time.monotonic()
767
- if len(sys.argv) < 2:
768
- print("Usage: render.py <inputs.json>", file=sys.stderr)
769
- sys.exit(2)
770
- inputs = json.loads(Path(sys.argv[1]).read_text())
771
- out_dir = Path(inputs["out_dir"]).expanduser()
772
- out_dir.mkdir(parents=True, exist_ok=True)
773
- base = inputs["filename_stem"]
774
- address = inputs.get("address", "")
775
- postcode = inputs.get("postcode", "")
776
-
777
- try:
778
- log_path = _pick_log_path(out_dir)
779
- except PrevalAbort as e:
780
- _abort(e.cause, e.hint, address=address, postcode=postcode, t0=t0,
781
- out_dir=out_dir, log_path=None)
782
-
783
- _log_line(log_path, f'[preval] start address="{address}" postcode={postcode}')
784
-
785
- try:
786
- _assert_observability_logs(log_path)
787
- except PrevalAbort as e:
788
- _abort(e.cause, e.hint, address=address, postcode=postcode, t0=t0,
789
- out_dir=out_dir, log_path=log_path)
790
-
791
- try:
792
- render(inputs, out_dir)
793
- pdf = render_pdf(out_dir, f"{base}.pdf")
794
- pages = assert_page_count(pdf, 5)
795
- except PrevalAbort as e:
796
- pdf_path = out_dir / f"{base}.pdf"
797
- if pdf_path.exists():
798
- pdf_path.unlink()
799
- _abort(e.cause, e.hint, address=address, postcode=postcode, t0=t0,
800
- out_dir=out_dir, log_path=log_path)
801
- except RuntimeError as e:
802
- pdf_path = out_dir / f"{base}.pdf"
803
- if pdf_path.exists():
804
- pdf_path.unlink()
805
- _abort("render-error", str(e), address=address, postcode=postcode, t0=t0,
806
- out_dir=out_dir, log_path=log_path)
807
-
808
- ms = int((time.monotonic() - t0) * 1000)
809
- _log_line(log_path, f"[preval] done pdf={pdf} pages={pages} ms={ms}")
810
- print(f"HTML → {out_dir/'index.html'}")
811
- print(f"PDF → {pdf} ({pages} pages)")
812
-
813
-
814
- if __name__ == "__main__":
815
- main()