@rubytech/create-maxy-code 0.1.49 → 0.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/platform-port-stamp.test.js +24 -0
- package/dist/index.js +5 -2
- package/dist/port-resolution.js +2 -0
- package/package.json +1 -1
- package/payload/platform/lib/require-port-env/dist/index.d.ts +31 -0
- package/payload/platform/lib/require-port-env/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/require-port-env/dist/index.js +52 -0
- package/payload/platform/lib/require-port-env/dist/index.js.map +1 -0
- package/payload/platform/lib/require-port-env/src/index.ts +56 -0
- package/payload/platform/lib/require-port-env/tsconfig.json +8 -0
- package/payload/platform/package-lock.json +0 -1
- package/payload/platform/package.json +2 -3
- package/payload/platform/plugins/admin/PLUGIN.md +16 -3
- package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +184 -146
- package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +186 -112
- package/payload/platform/plugins/admin/mcp/dist/index.js +20 -12
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/brochures/PLUGIN.md +2 -0
- package/payload/platform/plugins/brochures/skills/property-market-report/SKILL.md +100 -0
- package/payload/platform/plugins/brochures/skills/property-market-report/references/render.py +267 -0
- package/payload/platform/plugins/brochures/skills/property-market-report/references/template.html +266 -0
- package/payload/platform/plugins/brochures/skills/property-socials/SKILL.md +141 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.d.ts.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js +2 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js.map +1 -1
- package/payload/platform/plugins/docs/PLUGIN.md +3 -1
- package/payload/platform/plugins/docs/references/admin-session.md +40 -0
- package/payload/platform/plugins/docs/references/deployment.md +25 -0
- package/payload/platform/plugins/docs/references/internals.md +30 -0
- package/payload/platform/plugins/docs/references/platform.md +3 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js +2 -1
- package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js.map +1 -1
- package/payload/platform/plugins/loop/PLUGIN.md +24 -0
- package/payload/platform/plugins/loop/mcp/src/__tests__/plugin-md-time-doctrine.test.ts +132 -0
- package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +6 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +107 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts +4 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +22 -13
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
- package/payload/platform/plugins/memory/references/graph-primitives.md +42 -0
- package/payload/platform/plugins/memory/skills/concept-synthesis/SKILL.md +1 -1
- package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +2 -2
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +1 -1
- package/payload/platform/plugins/property-data/.claude-plugin/plugin.json +17 -0
- package/payload/platform/plugins/property-data/PLUGIN.md +100 -0
- package/payload/platform/plugins/property-data/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/property-data/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/index.js +153 -0
- package/payload/platform/plugins/property-data/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts +3 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js +72 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/crypto.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js +38 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts +29 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js +112 -0
- package/payload/platform/plugins/property-data/mcp/dist/lib/propertydata-api.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts +14 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js +20 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/endpoints.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts +4 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js +19 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-deregister.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts +4 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js +10 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-list.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts +5 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.d.ts.map +1 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js +43 -0
- package/payload/platform/plugins/property-data/mcp/dist/tools/key-register.js.map +1 -0
- package/payload/platform/plugins/property-data/mcp/package-lock.json +2566 -0
- package/payload/platform/plugins/property-data/mcp/package.json +21 -0
- package/payload/platform/plugins/property-data/mcp/src/__tests__/key-roundtrip.test.ts +107 -0
- package/payload/platform/plugins/property-data/mcp/src/__tests__/propertydata-api.test.ts +184 -0
- package/payload/platform/plugins/property-data/mcp/src/__tests__/schema-parity.test.ts +48 -0
- package/payload/platform/plugins/property-data/mcp/src/index.ts +249 -0
- package/payload/platform/plugins/property-data/mcp/src/lib/crypto.ts +79 -0
- package/payload/platform/plugins/property-data/mcp/src/lib/neo4j.ts +47 -0
- package/payload/platform/plugins/property-data/mcp/src/lib/propertydata-api.ts +135 -0
- package/payload/platform/plugins/property-data/mcp/src/tools/endpoints.ts +27 -0
- package/payload/platform/plugins/property-data/mcp/src/tools/key-deregister.ts +21 -0
- package/payload/platform/plugins/property-data/mcp/src/tools/key-list.ts +10 -0
- package/payload/platform/plugins/property-data/mcp/src/tools/key-register.ts +58 -0
- package/payload/platform/plugins/property-data/mcp/tsconfig.json +20 -0
- package/payload/platform/plugins/property-data/mcp/vitest.config.ts +8 -0
- package/payload/platform/plugins/property-data/skills/property-data/SKILL.md +58 -0
- package/payload/platform/plugins/tasks/mcp/dist/index.js +1 -2
- package/payload/platform/plugins/tasks/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.d.ts.map +1 -1
- package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js +3 -2
- package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js.map +1 -1
- package/payload/platform/plugins/waitlist/PLUGIN.md +6 -8
- package/payload/platform/plugins/waitlist/mcp/dist/index.js +33 -0
- package/payload/platform/plugins/waitlist/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.d.ts +16 -0
- package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.d.ts.map +1 -0
- package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.js +58 -0
- package/payload/platform/plugins/waitlist/mcp/dist/lib/admin-model.js.map +1 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts +34 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts.map +1 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js +129 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js.map +1 -0
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts +12 -18
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js +89 -86
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.d.ts.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.js +15 -53
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-setup.js.map +1 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +5 -5
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/workflows/PLUGIN.md +10 -176
- package/payload/platform/plugins/workflows/mcp/dist/index.js +14 -142
- package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts +1 -88
- package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js +0 -86
- package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts +5 -12
- package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js +5 -46
- package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts +1 -16
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js +39 -75
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts +8 -21
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +39 -266
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts +3 -8
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js +3 -10
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js +38 -86
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js +8 -26
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +1 -2
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +221 -25
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +39 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +109 -10
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/reaper.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/reaper.js +11 -0
- package/payload/platform/services/claude-session-manager/dist/reaper.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +21 -0
- package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -1
- package/payload/platform/services/claude-session-manager/vitest.config.ts +14 -0
- package/payload/platform/templates/agents/admin/IDENTITY.md +2 -0
- package/payload/platform/templates/agents/admin/SOUL.md +3 -1
- package/payload/premium-plugins/real-agent/BUNDLE.md +5 -3
- package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
- package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
- package/payload/premium-plugins/real-agent/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/PLUGIN.md +2 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/SKILL.md +100 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/references/render.py +267 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-market-report/references/template.html +266 -0
- package/payload/premium-plugins/real-agent/plugins/brochures/skills/property-socials/SKILL.md +141 -0
- package/payload/premium-plugins/real-agent/plugins/loop/PLUGIN.md +24 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/plugin-md-time-doctrine.test.ts +132 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/.claude-plugin/plugin.json +17 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/PLUGIN.md +100 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.d.ts +2 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.js +153 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/index.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.d.ts +3 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.js +72 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/crypto.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.js +38 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts +29 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.js +112 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/lib/propertydata-api.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.d.ts +14 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.js +20 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/endpoints.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.d.ts +4 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.js +19 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-deregister.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.d.ts +4 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.js +10 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-list.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.d.ts +5 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.js +43 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/dist/tools/key-register.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/package-lock.json +2566 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/package.json +21 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/key-roundtrip.test.ts +107 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/propertydata-api.test.ts +184 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/__tests__/schema-parity.test.ts +48 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/index.ts +249 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/crypto.ts +79 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/neo4j.ts +47 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/lib/propertydata-api.ts +135 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/endpoints.ts +27 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-deregister.ts +21 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-list.ts +10 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/src/tools/key-register.ts +58 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/tsconfig.json +20 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/mcp/vitest.config.ts +8 -0
- package/payload/premium-plugins/real-agent/plugins/property-data/skills/property-data/SKILL.md +58 -0
- package/payload/server/{chunk-MEGIQYUD.js → chunk-2IKQERHN.js} +33 -5
- package/payload/server/{chunk-XJVJ2B2Q.js → chunk-NPZKH5EC.js} +1 -1
- package/payload/server/{chunk-4P2MPERV.js → chunk-X3Y6ENKA.js} +0 -90
- package/payload/server/{cloudflare-task-tracker-R6MMORFU.js → cloudflare-task-tracker-TL6R364J.js} +2 -2
- package/payload/server/maxy-edge.js +54 -26
- package/payload/server/public/assets/admin-2ZJmzJ_g.js +216 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Ch-JZ1Q0.js → architectureDiagram-Q4EWVU46-DgfgldJT.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-C08tkD4C.js → blockDiagram-DXYQGD6D-agu8GDzA.js} +1 -1
- package/payload/server/public/assets/{brand-DCdOhh-I.css → brand-BDASZqMG.css} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-IceRdWw3.js → c4Diagram-AHTNJAMY-CmNsUmAe.js} +1 -1
- package/payload/server/public/assets/channel-DXGOX55q.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-Cey0rxmH.js → chunk-336JU56O-D9Uts7k9.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-Dzk8s0or.js → chunk-426QAEUC-D4ABqXMn.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-C10nuKc8.js → chunk-4TB4RGXK-D1KE4OAX.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-B1B8871D.js → chunk-5FUZZQ4R-CAh0GXe2.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-jvHIkgqP.js → chunk-5PVQY5BW-DBHa6HOv.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-7nDxvXHS.js → chunk-EDXVE4YY-BDC-6mL3.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-C8lJ1YYn.js → chunk-ENJZ2VHE-CH3uROkW.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-CT1d7veI.js → chunk-ICPOFSXX-BzZf0nAw.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-LTAfwxv0.js → chunk-OYMX7WX6-BrLHrI6O.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-RoGrqrH0.js → chunk-U2HBQHQK-Bw4UkLe_.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-D89ZBg3z.js → chunk-X2U36JSP-23xgdk05.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Cyg122Hf.js → chunk-YZCP3GAM-BA8iGgRa.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Dg59YYuG.js → chunk-ZZ45TVLE-B-ol4EgR.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DTuuDxpK.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CIw8RU0q.js +1 -0
- package/payload/server/public/assets/clone-O4ZyuvYl.js +1 -0
- package/payload/server/public/assets/{dagre-BPzUsxie.js → dagre--kXszEIb.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-CjDNXqPy.js → dagre-KV5264BT-amN1uU2d.js} +1 -1
- package/payload/server/public/assets/data-DlmoKxmN.js +1 -0
- package/payload/server/public/assets/{device-url-actions-B588ZlnE.js → device-url-actions-CPoz5fqz.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-Bqq0vqWM.js → diagram-5BDNPKRD-Cwizs9tP.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DSqocDhm.js → diagram-G4DWMVQ6-BpSu5Uao.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DZRWgKRL.js → diagram-MMDJMWI5-DiArtkto.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-DXRm-FXu.js → diagram-TYMM5635-_tygK58Y.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-CFVgkUCo.js → erDiagram-SMLLAGMA-CBV6LWYA.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-C82XCt9-.js → flowDiagram-DWJPFMVM-CHZFrtOU.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-C4tnImlS.js → ganttDiagram-T4ZO3ILL-B3vKq5ov.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DXHutP-a.js → gitGraphDiagram-UUTBAWPF-dnJPjbtj.js} +1 -1
- package/payload/server/public/assets/graph-BVvcFSEQ.js +1 -0
- package/payload/server/public/assets/graph-labels-cCvgu38Y.js +1 -0
- package/payload/server/public/assets/{graphlib-BvR5tL62.js → graphlib-CNXtnega.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-DgFMqgZy.js → infoDiagram-42DDH7IO-D8DYwVAF.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-_5gmh1-V.js → ishikawaDiagram-UXIWVN3A-CfEVY2Ud.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CNfDVgwI.js → journeyDiagram-VCZTEJTY-FmoBq7Kh.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Djifb_Z6.js → kanban-definition-6JOO6SKY-B-Q9qk99.js} +1 -1
- package/payload/server/public/assets/{line-0fRVrNiw.js → line-DZwbJENP.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-DXA7LKDt.js → mermaid-parser.core-C3ahKykw.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-BCfYtdMJ.js → mermaid.core-B8OFZIE8.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-sTRvikWi.js → mindmap-definition-QFDTVHPH-CqhkfbWa.js} +1 -1
- package/payload/server/public/assets/{page-nAY64ID7.js → page-BnAxPkmg.js} +1 -1
- package/payload/server/public/assets/{page-DDyny08O.js → page-BnaN3u86.js} +1 -1
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-QLTieded.js → pieDiagram-DEJITSTG-CJqQ6u3-.js} +1 -1
- package/payload/server/public/assets/{public-rUUducAl.js → public-rWe9ADCS.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-DOKCcqAZ.js → quadrantDiagram-34T5L4WZ-BtEqOXQM.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-BX6Zpq1X.js → requirementDiagram-MS252O5E-DPHWUtE6.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-B05NdgZX.js → sankeyDiagram-XADWPNL6-FBmc3wHT.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CHF8ZdUb.js → sequenceDiagram-FGHM5R23-BMSd2-1M.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DTAt7Ytz.js → stateDiagram-FHFEXIEX-DqFbU-LT.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CXTnsHGq.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-Dzd6X_ei.js → timeline-definition-GMOUNBTQ-DsfvHVK8.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BAbM4QlQ.js → vennDiagram-DHZGUBPP-kHU05mqC.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CIOXXKJd.js → wardleyDiagram-NUSXRM2D-C696Mez_.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-oF9sZesS.js → xychartDiagram-5P7HB3ND-yht-JyXJ.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +5 -5
- package/payload/server/public/index.html +7 -7
- package/payload/server/public/public.html +4 -4
- package/payload/server/server.js +261 -207
- package/payload/server/public/assets/admin-DBuCWSPS.js +0 -216
- package/payload/server/public/assets/channel-8QQB2Zoe.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CViZOOjI.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Dm7eGBqB.js +0 -1
- package/payload/server/public/assets/clone-BC8oes11.js +0 -1
- package/payload/server/public/assets/data-BeblX4m4.js +0 -1
- package/payload/server/public/assets/graph-ZuBiYril.js +0 -1
- package/payload/server/public/assets/graph-labels-CnbJR6cp.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-2bJIW7wn.js +0 -1
- /package/payload/server/public/assets/{brand-Dln107gD.js → brand-BWCtpG7_.js} +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: property-socials
|
|
3
|
+
description: Use when generating Open Graph / social-share images for a property page built by the real-estate brochure pipeline (estate-agents/<agent>/properties/<slug>/output/web/page.html). Produces landscape, square, and portrait JPGs that match the brochure's brand palette and typography, pulling copy from property.json and hero images already curated for that property. Triggers include "og images for <property>", "social collateral for <listing>", "Instagram tiles for that brochure", or any request to create share-card imagery for a published realagent.chat property page.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Property OG / Social Images
|
|
7
|
+
|
|
8
|
+
The brochure pipeline already produces a styled property page at
|
|
9
|
+
`estate-agents/<agent>/properties/<slug>/output/web/page.html` with curated hero
|
|
10
|
+
images under `images/`, branding tokens in `:root` of the page CSS, and
|
|
11
|
+
structured metadata in the property's `property.json`. This skill renders
|
|
12
|
+
share-ready images by overlaying brand-consistent typography on those hero
|
|
13
|
+
shots — it does not re-design anything.
|
|
14
|
+
|
|
15
|
+
## Inputs the skill consumes (never invents)
|
|
16
|
+
|
|
17
|
+
- **Palette and fonts** — read from `:root` in `output/web/page.html`. Use the
|
|
18
|
+
exact `--paper / --ink / --gold` tokens and Google Font imports already on
|
|
19
|
+
that page. Do not pick new colours.
|
|
20
|
+
- **Copy** — `property.json` is canonical for address, price, qualifier,
|
|
21
|
+
bedrooms/baths/receptions, agent name + phone. The page's
|
|
22
|
+
`<meta name="description">` is the sub-headline. The brochure folder's
|
|
23
|
+
display name (e.g. *Sparrows Farm*) is the headline.
|
|
24
|
+
- **Hero images** — `images/<slug>-hero-1-main.webp`, `hero-2-kitchen.webp`,
|
|
25
|
+
`hero-3-garden.webp` are the curated set. Use them by name; do not pick
|
|
26
|
+
numbered shots from the raw set unless the curated heroes are missing.
|
|
27
|
+
|
|
28
|
+
## Output contract
|
|
29
|
+
|
|
30
|
+
Two deliverables every time: image files and the captions that go with them.
|
|
31
|
+
|
|
32
|
+
**Image files** are written next to `page.html` so they share the same public
|
|
33
|
+
URL prefix:
|
|
34
|
+
|
|
35
|
+
| File | Dimensions | Use |
|
|
36
|
+
|------|------------|-----|
|
|
37
|
+
| `og-landscape-<hero>.jpg` | 1200×628 | Twitter / LinkedIn / Facebook / OG |
|
|
38
|
+
| `og-square-<hero>.jpg` | 1200×1200 | Instagram feed |
|
|
39
|
+
| `og-portrait-<hero>.jpg` | 1080×1350 | Instagram portrait, mobile |
|
|
40
|
+
|
|
41
|
+
`<hero>` is `main`, `kitchen`, or `garden`. At minimum produce
|
|
42
|
+
`og-landscape-main.jpg`; offer the full five-variant set (landscape + square +
|
|
43
|
+
three portraits) when the user wants social collateral, not just a meta image.
|
|
44
|
+
|
|
45
|
+
**Captions** are written into `output/web/social-posts.md`, one section per
|
|
46
|
+
image, ready to paste. Every caption is generated through the `plainly` skill's
|
|
47
|
+
register: no em-dashes, no inflation vocabulary (*discover*, *unlock*,
|
|
48
|
+
*nestled*, *stunning*, *boasts*, *bespoke* where it isn't literally bespoke),
|
|
49
|
+
no antithetical "it's not X, it's Y", no rhetorical openers (*Imagine…*,
|
|
50
|
+
*Picture this…*). Read each draft aloud; if it sounds like an estate-agent
|
|
51
|
+
blurb-bot rather than a person, rewrite it.
|
|
52
|
+
|
|
53
|
+
Per-platform shape (these are caps, not minimums):
|
|
54
|
+
|
|
55
|
+
- **Landscape post (Twitter / X)**: under 280 characters. One sentence of
|
|
56
|
+
scene, one of specs, one of agent + phone. Link as last token.
|
|
57
|
+
- **Landscape post (LinkedIn / Facebook)**: three short paragraphs. Opening
|
|
58
|
+
line that names the property and locality. A middle paragraph of concrete
|
|
59
|
+
features taken from `property.json`'s `key_features`. A closing paragraph
|
|
60
|
+
with price, agent name, phone, listing URL.
|
|
61
|
+
- **Square (Instagram feed)**: property name + locality on line one, two or
|
|
62
|
+
three lines of concrete features, price, agent + phone, "link in bio", four
|
|
63
|
+
to six hashtags drawn from locality + property type + agency.
|
|
64
|
+
- **Portrait (Instagram portrait / Reels cover)**: lead with what is visible
|
|
65
|
+
in *that specific hero* (exterior, kitchen, or garden), not the generic
|
|
66
|
+
property summary. Three lines maximum. Price + agent line at the bottom.
|
|
67
|
+
|
|
68
|
+
Copy sources, in order: `property.json` for facts (address, price, beds, baths,
|
|
69
|
+
acreage, key features); the page's `<meta name="description">` for tone of the
|
|
70
|
+
hero sub-line; the brochure folder display name for the headline. Do not invent
|
|
71
|
+
features that are not in those sources.
|
|
72
|
+
|
|
73
|
+
## How rendering works
|
|
74
|
+
|
|
75
|
+
A single `og.html` template lives at `output/web/og.html` alongside `page.html`
|
|
76
|
+
so it can use relative `images/` paths. It accepts `?format=landscape|square|
|
|
77
|
+
portrait` and `?hero=main|kitchen|garden`, applies the matching CSS class with
|
|
78
|
+
explicit min/max width and height (no relative units), and sets the background
|
|
79
|
+
hero image from the param. Playwright screenshots the URL at exactly the
|
|
80
|
+
container's pixel size.
|
|
81
|
+
|
|
82
|
+
Critical layout rules:
|
|
83
|
+
|
|
84
|
+
- The stage div fixes its own width and height with `width / minWidth / maxWidth`
|
|
85
|
+
(and the height triple). Without max constraints the viewport bleeds.
|
|
86
|
+
- Hero fills the stage with `background-size: cover; background-position: center`
|
|
87
|
+
so the same template works across all three aspect ratios.
|
|
88
|
+
- A vertical gradient scrim (transparent → ink 0.85) sits between hero and copy.
|
|
89
|
+
On bright daytime shots the scrim's bottom stop must reach ≥ 0.85 or the
|
|
90
|
+
eyebrow/sub copy loses contrast.
|
|
91
|
+
- Copy block sits in the bottom-left: eyebrow (locality, gold), headline
|
|
92
|
+
(display serif), sub (italic body serif), thin rule, specs row, footer line
|
|
93
|
+
with `realagent.chat / <agent>` left and `<agent name> · <phone>` right.
|
|
94
|
+
|
|
95
|
+
## Generation flow
|
|
96
|
+
|
|
97
|
+
1. Confirm `output/web/og.html` is in sync with the page's `:root` palette and
|
|
98
|
+
`property.json` copy. If the property page has been re-themed since the last
|
|
99
|
+
render, update the template before screenshotting.
|
|
100
|
+
2. Start a static server in `output/web/` on any free port:
|
|
101
|
+
`python3 -m http.server <port> &`. Hold the PID so it can be killed at the
|
|
102
|
+
end. Relative `images/` paths require a real HTTP origin; `file://` won't
|
|
103
|
+
render webfonts either.
|
|
104
|
+
3. On a fresh machine, `npx -y playwright install chromium` once. The first
|
|
105
|
+
`playwright screenshot` invocation otherwise fails with "Executable doesn't
|
|
106
|
+
exist".
|
|
107
|
+
4. Screenshot each variant. Pass `--wait-for-timeout=2500` so Google Fonts
|
|
108
|
+
land before capture. Always quote URLs that contain `&`.
|
|
109
|
+
5. Stop the server. Verify each JPG with `Read` so the user sees the rendered
|
|
110
|
+
collateral inline — file sizes alone aren't proof of a good render.
|
|
111
|
+
|
|
112
|
+
## Failure modes seen on first use
|
|
113
|
+
|
|
114
|
+
- **Filename mangling.** A bash loop using `for v in "landscape main" …; set --
|
|
115
|
+
$v` collapses to filenames like `og-landscape main-.jpg` (space, then dash).
|
|
116
|
+
Use an explicit per-variant call or an array; never rely on positional
|
|
117
|
+
splitting for two-word tuples.
|
|
118
|
+
- **6 KB screenshots.** A screenshot under ~20 KB is a blank page. Common
|
|
119
|
+
causes: server not running, wrong port, Chromium not installed, or `og.html`
|
|
120
|
+
threw a JS error. Open the URL in a browser to confirm before re-running.
|
|
121
|
+
- **Eyebrow on a light surface.** The garden / pool hero washes the eyebrow
|
|
122
|
+
out. Either deepen the scrim's bottom stop or move the eyebrow above the
|
|
123
|
+
hero crop on that variant. Don't ship a low-contrast tile.
|
|
124
|
+
- **Treating this as a Next.js task.** The brochure site is static HTML. The
|
|
125
|
+
upstream `og-images` skill assumes `app/og/page.tsx`; ignore that scaffold
|
|
126
|
+
and render against the static page directly.
|
|
127
|
+
- **Captions that sound like AI marketing.** "Discover this stunning home
|
|
128
|
+
nestled in the heart of Essex" is the failure mode. Strip *discover*,
|
|
129
|
+
*unlock*, *nestled*, *stunning*, *boasts*, *exquisite*, *charming*, every
|
|
130
|
+
em-dash, every exclamation mark used to fake enthusiasm. The aloud test from
|
|
131
|
+
the `plainly` skill applies: read the caption out; if you would not say it
|
|
132
|
+
in conversation to a buyer, rewrite it.
|
|
133
|
+
|
|
134
|
+
## Out of scope
|
|
135
|
+
|
|
136
|
+
- The brochure page itself (owned by `real-estate-brochure:property-brochure`).
|
|
137
|
+
- Property metadata extraction (owned by
|
|
138
|
+
`real-estate-brochure:property-extract`).
|
|
139
|
+
- Wiring `<meta property="og:image">` into `page.html`. Surface the snippet for
|
|
140
|
+
the operator; the page is regenerated by a separate skill and edits there
|
|
141
|
+
belong in that pipeline, not this one.
|
|
@@ -174,6 +174,30 @@ Loop covers five value pillars with API surface. Each pillar has both read and w
|
|
|
174
174
|
- `loop-customer-preferences` (action=write)
|
|
175
175
|
- `loop-supplier` (action=maintenance-complete, board-complete, maintenance-submit-quote)
|
|
176
176
|
|
|
177
|
+
## Time presentation
|
|
178
|
+
|
|
179
|
+
**Every datetime field in a Loop response is UTC, returned without a timezone marker.** The Loop V2 API stores and returns instants as bare `YYYY-MM-DDTHH:MM:SS` strings whose true zone is UTC. Presenting them verbatim is silent misrepresentation: a viewing whose `dateOfAppointment` is `12:00:00` is `12:00Z`, which is `13:00 BST` between late March and late October in the UK. Off-by-one-hour viewing times have already misled an operator (Task 126).
|
|
180
|
+
|
|
181
|
+
**Convert before any datetime appears in agent output.** The operator's zone comes from the `Person.timezone` property on the operator's `Person` node; Real Agent UK accounts default to `Europe/London` when that property is absent. The conversion is non-negotiable — there is no case where a Loop datetime is presented to the operator in its raw UTC form. State the converted local time, and where ambiguous (cross-DST scheduling, calendar invites), name the zone explicitly (`13:00 BST`, `09:30 GMT`).
|
|
182
|
+
|
|
183
|
+
The tools whose responses carry one or more datetime fields — and therefore require this conversion before any field value reaches the operator — are exhaustive:
|
|
184
|
+
|
|
185
|
+
- `loop-viewing-search` — `dateOfAppointment`, `dateOfAppointmentEnd`
|
|
186
|
+
- `loop-viewing-detail` — `dateCreated`, `dateOfAppointment`, `dateOfAppointmentEnd`, `dateBuyerFeedbackGiven`, `dateSellerFeedbackGiven`, `dateDone`
|
|
187
|
+
- `loop-feedback-get` — `viewingDateOfAppointment`
|
|
188
|
+
- `loop-people-search` — renters list: `dateRequired`
|
|
189
|
+
- `loop-people-detail` — `dateCreated`; nested `viewings[].dateOfAppointment(+End)`, `offers[].dateReceived`, `applications[].dateReceived`, `applications[].proposedStartDate`, `property.dateCreated` (sellers/landlords), `dateRequired` (renters)
|
|
190
|
+
- `loop-property-search` — `dateCreated`
|
|
191
|
+
- `loop-property-detail` — `dateCreated`, `dateInstructed`, `dateUnderOffer`, `dateLaunched`, `dateExchanged`, `dateCompleted`, `dateWithdrawn`, `dateFirstAvailable`, `leaseExpiryDate`
|
|
192
|
+
- `loop-property-listed` — `dateLaunched`, `dateFirstAvailable`, `leaseExpiryDate`
|
|
193
|
+
- `loop-property-sold` — `dateLaunched`, `leaseExpiryDate`, `images[].dateUpdated`
|
|
194
|
+
- `loop-marketing-match` — `dateCreated`, `dateInstructed`, `dateUnderOffer`, `dateLaunched`, `dateExchanged`, `dateCompleted`, `dateWithdrawn`, `dateFirstAvailable`, `viewings[].dateOfAppointment(+End)`, `applications[].dateReceived`, `applications[].proposedStartDate`, `marketListings[].dateListed`, `images[].dateUpdated`
|
|
195
|
+
- `loop-auto-responder` — `enquiry.dateMoving`
|
|
196
|
+
- `loop-team-availability` — `start`, `end`
|
|
197
|
+
- `loop-supplier` — `dateCreated`, `dateDone`, `dateReported`, `dateQuoteBy`, `dateCompleted`, `dateApproved`
|
|
198
|
+
|
|
199
|
+
Tools not listed (`loop-key-*`, `loop-team-info`, `loop-customer-preferences`, `loop-marketing-enquiry`, `loop-marketing-match-batch`, `loop-marketing-match-request`, `loop-viewing-create`, `loop-viewing-update`, `loop-feedback-submit`, `loop-property-viewing`, `loop-property-callback`, `loop-property-information`) either have no datetime in response or are write-only acknowledgements. The enumeration is grounded in the vendored swagger snapshot at `mcp/src/__tests__/loop-swagger.snapshot.json`; the pinning test at `mcp/src/__tests__/plugin-md-time-doctrine.test.ts` blocks silent drift.
|
|
200
|
+
|
|
177
201
|
### Team-key prerequisite
|
|
178
202
|
|
|
179
203
|
Every Loop tool routes through one or more team keys. If `loop-key-list` returns nothing for the account, surface the registration prompt before attempting any other Loop call — every downstream tool will fail otherwise. If a call returns `Team "X" does not have <group> permission`, the key was scoped to fewer than 8 endpoint groups; re-register with the full permissions array (`["properties","people","viewings","feedback","team","marketing","customer","supplier"]`).
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anti-regression: PLUGIN.md must carry the "Time presentation" doctrine
|
|
3
|
+
* paragraph and enumerate every Loop tool whose response contains a
|
|
4
|
+
* datetime field. The doctrine is the agent's only signal that Loop
|
|
5
|
+
* returns bare UTC strings without a zone marker — silent drop of this
|
|
6
|
+
* section recurs the off-by-one-hour viewing-time failure (Task 126).
|
|
7
|
+
*
|
|
8
|
+
* The expected tool list is derived live from the vendored swagger
|
|
9
|
+
* snapshot, so if Loop adds a new datetime-bearing endpoint and we miss
|
|
10
|
+
* mapping it in PLUGIN.md, the test fails and names the orphan.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, expect, it } from 'vitest';
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
import { resolve, dirname } from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
|
|
18
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const PLUGIN_MD = resolve(__dirname, '../../../PLUGIN.md');
|
|
20
|
+
const SWAGGER_PATH = resolve(__dirname, 'loop-swagger.snapshot.json');
|
|
21
|
+
|
|
22
|
+
interface SwaggerDoc {
|
|
23
|
+
paths: Record<string, Record<string, { responses?: Record<string, { content?: Record<string, { schema?: unknown }> }> }>>;
|
|
24
|
+
components?: { schemas?: Record<string, unknown> };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const swagger = JSON.parse(readFileSync(SWAGGER_PATH, 'utf-8')) as SwaggerDoc;
|
|
28
|
+
const plugin = readFileSync(PLUGIN_MD, 'utf-8');
|
|
29
|
+
|
|
30
|
+
// Swagger path → tool name. Every response-bearing GET path that surfaces
|
|
31
|
+
// a datetime field must map to exactly one tool here. Add a row when Loop
|
|
32
|
+
// publishes a new datetime endpoint that we expose.
|
|
33
|
+
const PATH_TO_TOOL: Record<string, string> = {
|
|
34
|
+
'/residential/sales/viewings': 'loop-viewing-search',
|
|
35
|
+
'/residential/lettings/viewings': 'loop-viewing-search',
|
|
36
|
+
'/residential/sales/viewings/{id}': 'loop-viewing-detail',
|
|
37
|
+
'/residential/lettings/viewings/{id}': 'loop-viewing-detail',
|
|
38
|
+
'/feedback/residential/sales/viewings/{id}': 'loop-feedback-get',
|
|
39
|
+
'/feedback/residential/lettings/viewings/{id}': 'loop-feedback-get',
|
|
40
|
+
'/people/renters': 'loop-people-search',
|
|
41
|
+
'/people/{id}': 'loop-people-detail',
|
|
42
|
+
'/people/buyers/{id}': 'loop-people-detail',
|
|
43
|
+
'/people/sellers/{id}': 'loop-people-detail',
|
|
44
|
+
'/people/landlords/{id}': 'loop-people-detail',
|
|
45
|
+
'/people/renters/{id}': 'loop-people-detail',
|
|
46
|
+
'/property/residential/sales/{id}': 'loop-property-detail',
|
|
47
|
+
'/property/residential/lettings/{id}': 'loop-property-detail',
|
|
48
|
+
'/property/residential/sales': 'loop-property-search',
|
|
49
|
+
'/property/residential/lettings': 'loop-property-search',
|
|
50
|
+
'/property/residential/sales/listed/{channel}': 'loop-property-listed',
|
|
51
|
+
'/property/residential/lettings/listed/{channel}': 'loop-property-listed',
|
|
52
|
+
'/property/residential/sales/{id}/preview/{previewHash}': 'loop-property-detail',
|
|
53
|
+
'/property/residential/lettings/{id}/preview/{previewHash}': 'loop-property-detail',
|
|
54
|
+
'/property/residential/sold/{channel}': 'loop-property-sold',
|
|
55
|
+
'/marketing/matching/{id}': 'loop-marketing-match',
|
|
56
|
+
'/marketing/rentals/matching/{id}': 'loop-marketing-match',
|
|
57
|
+
'/marketing/enquiries/auto-responder/{id}/{key}': 'loop-auto-responder',
|
|
58
|
+
'/team/{agentId}/availability/{searchDate}': 'loop-team-availability',
|
|
59
|
+
'/supplier/board-contractor/{code}/{jobid}/job-list': 'loop-supplier',
|
|
60
|
+
'/supplier/maintenance/{quoteCode}/{jobid}/job-list': 'loop-supplier',
|
|
61
|
+
'/supplier/maintenance/{quoteCode}/{jobId}/quote-list': 'loop-supplier',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
function resolveRef(ref: string): unknown {
|
|
65
|
+
const parts = ref.replace('#/', '').split('/');
|
|
66
|
+
let cur: unknown = swagger;
|
|
67
|
+
for (const p of parts) cur = cur && typeof cur === 'object' ? (cur as Record<string, unknown>)[p] : null;
|
|
68
|
+
return cur;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function hasDateField(node: unknown, depth = 0, visited = new WeakSet<object>()): boolean {
|
|
72
|
+
if (!node || typeof node !== 'object' || depth > 12) return false;
|
|
73
|
+
if (visited.has(node as object)) return false;
|
|
74
|
+
visited.add(node as object);
|
|
75
|
+
const n = node as Record<string, unknown>;
|
|
76
|
+
if (typeof n.$ref === 'string') return hasDateField(resolveRef(n.$ref), depth + 1, visited);
|
|
77
|
+
if (n.format === 'date-time' || n.format === 'date') return true;
|
|
78
|
+
if (n.properties && typeof n.properties === 'object') {
|
|
79
|
+
for (const v of Object.values(n.properties as Record<string, unknown>)) {
|
|
80
|
+
if (hasDateField(v, depth + 1, visited)) return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (n.items && hasDateField(n.items, depth + 1, visited)) return true;
|
|
84
|
+
if (Array.isArray(n.allOf)) {
|
|
85
|
+
for (const v of n.allOf) if (hasDateField(v, depth + 1, visited)) return true;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function toolsRequiringDoctrine(): Set<string> {
|
|
91
|
+
const tools = new Set<string>();
|
|
92
|
+
for (const [path, methods] of Object.entries(swagger.paths)) {
|
|
93
|
+
const op = methods.get;
|
|
94
|
+
if (!op || !op.responses) continue;
|
|
95
|
+
const anyDate = Object.values(op.responses).some(r =>
|
|
96
|
+
Object.values(r.content || {}).some(sw => hasDateField(sw.schema)),
|
|
97
|
+
);
|
|
98
|
+
if (!anyDate) continue;
|
|
99
|
+
const tool = PATH_TO_TOOL[path];
|
|
100
|
+
if (tool) tools.add(tool);
|
|
101
|
+
else throw new Error(`Swagger GET ${path} returns a datetime but has no PATH_TO_TOOL mapping — add it and list the tool in PLUGIN.md "Time presentation".`);
|
|
102
|
+
}
|
|
103
|
+
return tools;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
describe('PLUGIN.md time-presentation doctrine', () => {
|
|
107
|
+
it('contains the Time presentation section', () => {
|
|
108
|
+
expect(plugin).toMatch(/^## Time presentation$/m);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('names UTC, Person.timezone, and the Europe/London default', () => {
|
|
112
|
+
expect(plugin).toMatch(/UTC/);
|
|
113
|
+
expect(plugin).toMatch(/Person\.timezone/);
|
|
114
|
+
expect(plugin).toMatch(/Europe\/London/);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('forbids raw UTC presentation', () => {
|
|
118
|
+
// Must state conversion is required before any datetime appears in output.
|
|
119
|
+
expect(plugin).toMatch(/Convert before any datetime appears in agent output/);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('enumerates every tool whose Loop response carries a datetime field', () => {
|
|
123
|
+
const required = toolsRequiringDoctrine();
|
|
124
|
+
const missing: string[] = [];
|
|
125
|
+
for (const tool of required) {
|
|
126
|
+
// Each tool must appear in the doctrine section as a bullet item.
|
|
127
|
+
const re = new RegExp(`^- \`${tool.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}\``, 'm');
|
|
128
|
+
if (!re.test(plugin)) missing.push(tool);
|
|
129
|
+
}
|
|
130
|
+
expect(missing, `PLUGIN.md "Time presentation" must list: ${missing.join(', ')}`).toEqual([]);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "real-agent-property-data",
|
|
3
|
+
"description": "PropertyData UK market analytics — postcode-keyed valuation, asking prices, sold prices, demand, yields, growth, national HPI. One encrypted API key per account.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Rubytech LLC"
|
|
7
|
+
},
|
|
8
|
+
"mcpServers": {
|
|
9
|
+
"real-agent-property-data": {
|
|
10
|
+
"type": "stdio",
|
|
11
|
+
"command": "node",
|
|
12
|
+
"args": [
|
|
13
|
+
"${CLAUDE_PLUGIN_ROOT}/mcp/dist/index.js"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: real-agent-property-data
|
|
3
|
+
description: "PropertyData UK market analytics — postcode-keyed valuation, asking prices, sold prices, demand, yields, growth, national HPI. One encrypted API key per account."
|
|
4
|
+
tools:
|
|
5
|
+
- name: property-data-key-register
|
|
6
|
+
publicAllowlist: false
|
|
7
|
+
- name: property-data-key-deregister
|
|
8
|
+
publicAllowlist: false
|
|
9
|
+
- name: property-data-key-list
|
|
10
|
+
publicAllowlist: false
|
|
11
|
+
- name: property-data-valuation-sale
|
|
12
|
+
publicAllowlist: false
|
|
13
|
+
- name: property-data-valuation-rent
|
|
14
|
+
publicAllowlist: false
|
|
15
|
+
- name: property-data-prices
|
|
16
|
+
publicAllowlist: false
|
|
17
|
+
- name: property-data-prices-rent
|
|
18
|
+
publicAllowlist: false
|
|
19
|
+
- name: property-data-sold-prices
|
|
20
|
+
publicAllowlist: false
|
|
21
|
+
- name: property-data-demand
|
|
22
|
+
publicAllowlist: false
|
|
23
|
+
- name: property-data-yields
|
|
24
|
+
publicAllowlist: false
|
|
25
|
+
- name: property-data-growth
|
|
26
|
+
publicAllowlist: false
|
|
27
|
+
- name: property-data-national-hpi
|
|
28
|
+
publicAllowlist: false
|
|
29
|
+
skills:
|
|
30
|
+
- skills/property-data/SKILL.md
|
|
31
|
+
always: false
|
|
32
|
+
metadata: {"platform":{"optional":true,"embed":["admin"]}}
|
|
33
|
+
mcp:
|
|
34
|
+
command: node
|
|
35
|
+
args:
|
|
36
|
+
- ${PLATFORM_ROOT}/lib/mcp-spawn-tee/dist/index.js
|
|
37
|
+
- ${PREMIUM_PLUGINS_ROOT}/real-agent/plugins/property-data/mcp/dist/index.js
|
|
38
|
+
env:
|
|
39
|
+
MCP_SPAWN_TEE_NAME: property-data
|
|
40
|
+
LOG_DIR: ${LOG_DIR}
|
|
41
|
+
PLATFORM_ROOT: ${PLATFORM_ROOT}
|
|
42
|
+
ACCOUNT_ID: ${ACCOUNT_ID}
|
|
43
|
+
SESSION_ID: ${SESSION_ID}
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# Real Agent — PropertyData
|
|
47
|
+
|
|
48
|
+
Local stdio MCP that proxies the PropertyData UK market-analytics HTTP API (propertydata.co.uk). Postcode-keyed analytics powering valuer + negotiator workflows: comparable evidence, asking-price baselines, sold-price history, demand index, rental yield, growth signals, and the national house-price index.
|
|
49
|
+
|
|
50
|
+
## Capabilities
|
|
51
|
+
|
|
52
|
+
- **Key management** — register, deregister, and list a single PropertyData API key per account. AES-256-GCM encrypted at rest in Neo4j under the `PropertyDataKey` label.
|
|
53
|
+
- **Valuation** — point-estimate sale and rent valuations from postcode + property attributes (`valuation-sale`, `valuation-rent`).
|
|
54
|
+
- **Asking-price baselines** — live mean / median / 80th-percentile asking prices for sale and rent in a postcode (`prices`, `prices-rent`).
|
|
55
|
+
- **Sold-price history** — Land Registry sold transactions filtered by postcode, property type, and age (`sold-prices`).
|
|
56
|
+
- **Demand index** — number of properties currently for sale vs. average days to sell-STC for a postcode (`demand`).
|
|
57
|
+
- **Rental yield** — gross yield estimates by postcode and bedroom count (`yields`).
|
|
58
|
+
- **Growth signals** — short and long-term price growth by postcode (`growth`).
|
|
59
|
+
- **National house-price index** — UK-wide HPI series (`national-hpi`).
|
|
60
|
+
|
|
61
|
+
## Security
|
|
62
|
+
|
|
63
|
+
The PropertyData API key is encrypted at rest with AES-256-GCM. Encryption key lives at `~/<configDir>/.property-data-encryption-key` with mode `0600`. Never include the key value in responses; identify the key by registration timestamp only. If the operator asks for the key value, explain that keys are encrypted and cannot be retrieved — they must be re-registered from the PropertyData dashboard.
|
|
64
|
+
|
|
65
|
+
## When to use these tools
|
|
66
|
+
|
|
67
|
+
### Pillar 1 — Comparable evidence for valuation
|
|
68
|
+
|
|
69
|
+
**Triggers** — operator says "comps for", "sold prices around", "what's gone for", "comparable evidence":
|
|
70
|
+
- `property-data-sold-prices` — Land Registry sold prices for the postcode
|
|
71
|
+
|
|
72
|
+
### Pillar 2 — Asking-price baselines and point valuations
|
|
73
|
+
|
|
74
|
+
**Triggers** — operator says "what's it worth", "asking prices in", "point estimate", "ballpark":
|
|
75
|
+
- `property-data-valuation-sale` — point sale estimate for postcode + attributes
|
|
76
|
+
- `property-data-valuation-rent` — point rent estimate
|
|
77
|
+
- `property-data-prices` — distribution of asking prices for sale
|
|
78
|
+
- `property-data-prices-rent` — distribution of asking prices for rent
|
|
79
|
+
|
|
80
|
+
### Pillar 3 — Demand + yield + growth (negotiation signals)
|
|
81
|
+
|
|
82
|
+
**Triggers** — operator says "demand in", "yield on", "growth", "is the market moving":
|
|
83
|
+
- `property-data-demand` — supply count + average days to sell-STC
|
|
84
|
+
- `property-data-yields` — gross rental yield by bedroom count
|
|
85
|
+
- `property-data-growth` — short and long-term price growth
|
|
86
|
+
- `property-data-national-hpi` — national HPI context
|
|
87
|
+
|
|
88
|
+
### Key prerequisite
|
|
89
|
+
|
|
90
|
+
Every PropertyData tool requires a registered key. If `property-data-key-list` returns nothing for the account, surface the registration prompt before attempting any other call — every downstream tool will return `status=key-missing` otherwise.
|
|
91
|
+
|
|
92
|
+
## Tool error envelope
|
|
93
|
+
|
|
94
|
+
Every tool returns either the PropertyData `data` payload as JSON text or an `isError: true` envelope with deterministic text shape:
|
|
95
|
+
|
|
96
|
+
- `Error: key-not-registered. Register a PropertyData API key with property-data-key-register before calling this tool.`
|
|
97
|
+
- `Error: http-<status> from PropertyData. <message>`
|
|
98
|
+
- `Error: bad-response from PropertyData (non-JSON, length=<n>).`
|
|
99
|
+
|
|
100
|
+
Operators see the reason directly; downstream skills branch on the prefix.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { initStderrTee } from "../../../../lib/mcp-stderr-tee/dist/index.js";
|
|
2
|
+
initStderrTee("property-data");
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { keyRegister } from "./tools/key-register.js";
|
|
7
|
+
import { keyDeregister } from "./tools/key-deregister.js";
|
|
8
|
+
import { keyList } from "./tools/key-list.js";
|
|
9
|
+
import { valuationSale, valuationRent, prices, pricesRent, soldPrices, demand, yields, growth, nationalHpi, } from "./tools/endpoints.js";
|
|
10
|
+
import { closeDriver } from "./lib/neo4j.js";
|
|
11
|
+
import { KeyNotRegisteredError, PropertyDataError, BadResponseError, } from "./lib/propertydata-api.js";
|
|
12
|
+
const accountId = process.env.ACCOUNT_ID;
|
|
13
|
+
if (!accountId) {
|
|
14
|
+
throw new Error("ACCOUNT_ID environment variable is required");
|
|
15
|
+
}
|
|
16
|
+
const server = new McpServer({
|
|
17
|
+
name: "maxy-property-data",
|
|
18
|
+
version: "0.1.0",
|
|
19
|
+
});
|
|
20
|
+
console.error(`[property-data] server started, account=${accountId}`);
|
|
21
|
+
function errorEnvelope(err) {
|
|
22
|
+
let text;
|
|
23
|
+
if (err instanceof KeyNotRegisteredError) {
|
|
24
|
+
text =
|
|
25
|
+
"Error: key-not-registered. Register a PropertyData API key with property-data-key-register before calling this tool.";
|
|
26
|
+
}
|
|
27
|
+
else if (err instanceof PropertyDataError) {
|
|
28
|
+
text = `Error: http-${err.status} from PropertyData. ${err.upstreamMessage}`;
|
|
29
|
+
}
|
|
30
|
+
else if (err instanceof BadResponseError) {
|
|
31
|
+
text = `Error: bad-response from PropertyData (non-JSON, length=${err.length}).`;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
text = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
35
|
+
}
|
|
36
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
37
|
+
}
|
|
38
|
+
function endpointHandler(fn) {
|
|
39
|
+
return async (params) => {
|
|
40
|
+
try {
|
|
41
|
+
const text = await fn({ ...params, accountId: accountId });
|
|
42
|
+
return { content: [{ type: "text", text }] };
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
return errorEnvelope(err);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// ─────────────────────────────────────────────────────────────────
|
|
50
|
+
// Key Management
|
|
51
|
+
// ─────────────────────────────────────────────────────────────────
|
|
52
|
+
server.tool("property-data-key-register", "Register the account's PropertyData API key. Validates the key against PropertyData's /national-hpi endpoint, encrypts it with AES-256-GCM, and stores it in Neo4j. One key per account; re-registering overwrites the existing key.", {
|
|
53
|
+
apiKey: z.string().min(8).describe("PropertyData API key from propertydata.co.uk dashboard"),
|
|
54
|
+
}, async ({ apiKey }) => {
|
|
55
|
+
try {
|
|
56
|
+
await keyRegister({ apiKey, accountId: accountId });
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: "text",
|
|
61
|
+
text: "PropertyData API key registered successfully.",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return errorEnvelope(err);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
server.tool("property-data-key-deregister", "Remove the account's PropertyData API key. The encrypted key is permanently deleted from Neo4j.", {}, async () => {
|
|
71
|
+
try {
|
|
72
|
+
await keyDeregister({ accountId: accountId });
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: "PropertyData API key deregistered." }],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
return errorEnvelope(err);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
server.tool("property-data-key-list", "Show whether a PropertyData API key is registered for this account. Never reveals the key value.", {}, async () => {
|
|
82
|
+
try {
|
|
83
|
+
const text = await keyList({ accountId: accountId });
|
|
84
|
+
return { content: [{ type: "text", text }] };
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
return errorEnvelope(err);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// ─────────────────────────────────────────────────────────────────
|
|
91
|
+
// Valuation endpoints
|
|
92
|
+
// ─────────────────────────────────────────────────────────────────
|
|
93
|
+
const valuationSchema = {
|
|
94
|
+
postcode: z.string().min(2).describe("UK postcode (outcode or full)"),
|
|
95
|
+
type: z
|
|
96
|
+
.enum(["detached", "semi-detached", "terraced", "flat"])
|
|
97
|
+
.describe("Property type"),
|
|
98
|
+
bedrooms: z.number().int().min(0).describe("Bedroom count"),
|
|
99
|
+
bathrooms: z.number().int().min(0).optional().describe("Bathroom count"),
|
|
100
|
+
internal_area: z.number().optional().describe("Internal area (sq ft)"),
|
|
101
|
+
construction_date: z.string().optional().describe("Construction date band (e.g. 'pre1900', '1900-1929')"),
|
|
102
|
+
finish_quality: z
|
|
103
|
+
.enum(["luxury", "above_average", "average", "below_average", "needs_modernisation"])
|
|
104
|
+
.optional()
|
|
105
|
+
.describe("Finish quality"),
|
|
106
|
+
};
|
|
107
|
+
server.tool("property-data-valuation-sale", "Point sale-price estimate for a property given postcode + attributes. Returns point estimate plus comparables.", valuationSchema, endpointHandler(valuationSale));
|
|
108
|
+
server.tool("property-data-valuation-rent", "Point rent estimate (PCM) for a property given postcode + attributes. Returns point estimate plus comparables.", valuationSchema, endpointHandler(valuationRent));
|
|
109
|
+
// ─────────────────────────────────────────────────────────────────
|
|
110
|
+
// Asking-price distributions
|
|
111
|
+
// ─────────────────────────────────────────────────────────────────
|
|
112
|
+
const pricesSchema = {
|
|
113
|
+
postcode: z.string().min(2).describe("UK postcode (outcode or full)"),
|
|
114
|
+
type: z
|
|
115
|
+
.enum(["detached", "semi-detached", "terraced", "flat"])
|
|
116
|
+
.optional()
|
|
117
|
+
.describe("Filter by property type"),
|
|
118
|
+
bedrooms: z.number().int().min(0).optional().describe("Filter by bedroom count"),
|
|
119
|
+
};
|
|
120
|
+
server.tool("property-data-prices", "Asking-price distribution for sale listings in a postcode — mean, median, 80th percentile.", pricesSchema, endpointHandler(prices));
|
|
121
|
+
server.tool("property-data-prices-rent", "Asking-price distribution for rental listings in a postcode — mean, median, 80th percentile (PCM).", pricesSchema, endpointHandler(pricesRent));
|
|
122
|
+
// ─────────────────────────────────────────────────────────────────
|
|
123
|
+
// Sold prices (Land Registry)
|
|
124
|
+
// ─────────────────────────────────────────────────────────────────
|
|
125
|
+
server.tool("property-data-sold-prices", "Land Registry sold transactions for a postcode, optionally filtered by age, type, and bedrooms.", {
|
|
126
|
+
postcode: z.string().min(2).describe("UK postcode (outcode or full)"),
|
|
127
|
+
max_age: z.number().int().min(1).optional().describe("Max transaction age in months"),
|
|
128
|
+
type: z
|
|
129
|
+
.enum(["detached", "semi-detached", "terraced", "flat"])
|
|
130
|
+
.optional()
|
|
131
|
+
.describe("Filter by property type"),
|
|
132
|
+
bedrooms: z.number().int().min(0).optional().describe("Filter by bedroom count"),
|
|
133
|
+
}, endpointHandler(soldPrices));
|
|
134
|
+
// ─────────────────────────────────────────────────────────────────
|
|
135
|
+
// Demand / yields / growth / national HPI
|
|
136
|
+
// ─────────────────────────────────────────────────────────────────
|
|
137
|
+
server.tool("property-data-demand", "Demand signals for a postcode — count of properties for sale and average days to sell-STC.", { postcode: z.string().min(2).describe("UK postcode (outcode or full)") }, endpointHandler(demand));
|
|
138
|
+
server.tool("property-data-yields", "Gross rental yield for a postcode and bedroom count.", {
|
|
139
|
+
postcode: z.string().min(2).describe("UK postcode (outcode or full)"),
|
|
140
|
+
bedrooms: z.number().int().min(0).describe("Bedroom count"),
|
|
141
|
+
}, endpointHandler(yields));
|
|
142
|
+
server.tool("property-data-growth", "Short-term and long-term price growth signals for a postcode.", { postcode: z.string().min(2).describe("UK postcode (outcode or full)") }, endpointHandler(growth));
|
|
143
|
+
server.tool("property-data-national-hpi", "UK national house-price index series. No postcode required.", {}, endpointHandler(nationalHpi));
|
|
144
|
+
// ─────────────────────────────────────────────────────────────────
|
|
145
|
+
// Lifecycle
|
|
146
|
+
// ─────────────────────────────────────────────────────────────────
|
|
147
|
+
process.on("SIGINT", async () => {
|
|
148
|
+
await closeDriver();
|
|
149
|
+
process.exit(0);
|
|
150
|
+
});
|
|
151
|
+
const transport = new StdioServerTransport();
|
|
152
|
+
await server.connect(transport);
|
|
153
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/lib/crypto.ts"],"names":[],"mappings":"AAgDA,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED,wBAAgB,OAAO,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAoBtD"}
|