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