@rubytech/create-maxy-code 0.1.45 → 0.1.49

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 (158) hide show
  1. package/dist/__tests__/premium-mcp-discover.test.js +85 -0
  2. package/dist/index.js +25 -16
  3. package/dist/lib/premium-mcp-discover.js +34 -0
  4. package/package.json +1 -1
  5. package/payload/platform/lib/admins-write/dist/index.d.ts +0 -1
  6. package/payload/platform/lib/admins-write/dist/index.d.ts.map +1 -1
  7. package/payload/platform/lib/admins-write/dist/index.js +2 -5
  8. package/payload/platform/lib/admins-write/dist/index.js.map +1 -1
  9. package/payload/platform/lib/admins-write/src/index.ts +2 -8
  10. package/payload/platform/lib/graph-mcp/dist/index.js +1 -4
  11. package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
  12. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts +7 -6
  13. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts.map +1 -1
  14. package/payload/platform/lib/graph-mcp/dist/schema-cache.js +7 -6
  15. package/payload/platform/lib/graph-mcp/dist/schema-cache.js.map +1 -1
  16. package/payload/platform/lib/graph-mcp/src/index.ts +1 -4
  17. package/payload/platform/lib/graph-mcp/src/schema-cache.ts +7 -6
  18. package/payload/platform/lib/graph-search/dist/index.d.ts +5 -5
  19. package/payload/platform/lib/graph-search/dist/index.js +4 -4
  20. package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +6 -7
  21. package/payload/platform/lib/graph-search/src/index.ts +5 -5
  22. package/payload/platform/lib/graph-trash/dist/index.d.ts +8 -12
  23. package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -1
  24. package/payload/platform/lib/graph-trash/dist/index.js +8 -12
  25. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
  26. package/payload/platform/lib/graph-trash/src/index.ts +8 -12
  27. package/payload/platform/lib/graph-write/dist/index.d.ts +8 -9
  28. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
  29. package/payload/platform/lib/graph-write/dist/index.js +9 -10
  30. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  31. package/payload/platform/lib/graph-write/src/index.ts +9 -10
  32. package/payload/platform/lib/mcp-eager/dist/index.d.ts +4 -4
  33. package/payload/platform/lib/mcp-eager/dist/index.js +4 -4
  34. package/payload/platform/lib/mcp-eager/src/index.ts +4 -4
  35. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  36. package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +56 -38
  37. package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +42 -40
  38. package/payload/platform/plugins/cloudflare/scripts/__tests__/tunnel-ingress.test.ts +2 -2
  39. package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +7 -9
  40. package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +10 -12
  41. package/payload/platform/plugins/cloudflare/scripts/tunnel-ingress.ts +3 -3
  42. package/payload/platform/plugins/docs/references/deployment.md +2 -14
  43. package/payload/platform/plugins/docs/references/platform.md +2 -2
  44. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  45. package/payload/platform/plugins/docs/references/troubleshooting.md +5 -5
  46. package/payload/platform/plugins/loop/PLUGIN.md +67 -12
  47. package/payload/platform/plugins/loop/mcp/dist/index.js +42 -16
  48. package/payload/platform/plugins/loop/mcp/dist/index.js.map +1 -1
  49. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
  50. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
  51. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
  52. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
  53. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
  54. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
  55. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
  56. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
  57. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
  58. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
  59. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
  60. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
  61. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
  62. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
  63. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
  64. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
  65. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
  66. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
  67. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
  68. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
  69. package/payload/platform/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
  70. package/payload/platform/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
  71. package/payload/platform/plugins/loop/mcp/src/index.ts +68 -17
  72. package/payload/platform/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
  73. package/payload/platform/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
  74. package/payload/platform/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
  75. package/payload/platform/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
  76. package/payload/platform/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
  77. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +4 -3
  78. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
  79. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
  80. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +7 -12
  81. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
  82. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.js +2 -2
  83. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js +4 -4
  84. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js.map +1 -1
  85. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.d.ts.map +1 -1
  86. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js +8 -9
  87. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js.map +1 -1
  88. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts +2 -2
  89. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js +2 -2
  90. package/payload/platform/scripts/admin-persist-audit.ts +4 -10
  91. package/payload/platform/scripts/conversation-id-allowlist.txt +0 -1
  92. package/payload/platform/scripts/lib/resolve-account-dir.sh +0 -2
  93. package/payload/platform/scripts/resume-tunnel.sh +2 -9
  94. package/payload/platform/scripts/seed-neo4j.sh +26 -104
  95. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  96. package/payload/platform/services/claude-session-manager/dist/http-server.js +53 -7
  97. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  98. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +0 -5
  99. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  100. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +13 -17
  101. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  102. package/payload/platform/templates/agents/admin/IDENTITY.md +10 -2
  103. package/payload/platform/templates/agents/admin/SOUL.md +23 -1
  104. package/payload/premium-plugins/real-agent/agents/buyer-enquiry/SOUL.md +10 -0
  105. package/payload/premium-plugins/real-agent/agents/compliance.md +1 -1
  106. package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
  107. package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
  108. package/payload/premium-plugins/real-agent/plugins/loop/PLUGIN.md +67 -12
  109. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js +42 -16
  110. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js.map +1 -1
  111. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
  112. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
  113. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
  114. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
  115. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
  116. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
  117. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
  118. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
  119. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
  120. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
  121. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
  122. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
  123. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
  124. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
  125. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
  126. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
  127. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
  128. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
  129. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
  130. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
  131. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
  132. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
  133. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/index.ts +68 -17
  134. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
  135. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
  136. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
  137. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
  138. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
  139. package/payload/server/public/assets/admin-DBuCWSPS.js +216 -0
  140. package/payload/server/public/assets/{data-BxpOR0eM.js → data-BeblX4m4.js} +1 -1
  141. package/payload/server/public/assets/{graph-CrmxRSeb.js → graph-ZuBiYril.js} +1 -1
  142. package/payload/server/public/assets/graph-labels-CnbJR6cp.js +1 -0
  143. package/payload/server/public/assets/page-DDyny08O.js +50 -0
  144. package/payload/server/public/assets/page-nAY64ID7.js +1 -0
  145. package/payload/server/public/data.html +3 -3
  146. package/payload/server/public/graph.html +3 -3
  147. package/payload/server/public/index.html +4 -4
  148. package/payload/server/server.js +9 -46
  149. package/payload/platform/plugins/docs/references/migration-guide.md +0 -90
  150. package/payload/platform/plugins/loop/mcp/src/tools/property-request.ts +0 -42
  151. package/payload/platform/scripts/component-knowledgedoc-backfill.ts +0 -214
  152. package/payload/platform/scripts/migrate-import.sh +0 -437
  153. package/payload/platform/scripts/taskmaster-export.sh +0 -388
  154. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-request.ts +0 -42
  155. package/payload/server/public/assets/admin-DVZcLuYu.js +0 -216
  156. package/payload/server/public/assets/graph-labels-C8A6BmtP.js +0 -1
  157. package/payload/server/public/assets/page-D5wAeFU0.js +0 -50
  158. package/payload/server/public/assets/page-DR5NU6S0.js +0 -1
@@ -1,41 +1,7 @@
1
- import { loopGet, loopPost, loopPut, withTeamKey } from "../lib/loop-api.js";
1
+ import { loopPost, withTeamKey } from "../lib/loop-api.js";
2
2
  export async function marketingEnquiry(params) {
3
- const { accountId, teamName, action } = params;
4
- if (action === "seller-enquiry") {
5
- await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => {
6
- return loopPost(apiKey, "/marketing/enquiries/seller", params.sellerEnquiryData ?? {}, "loop-marketing-enquiry", teamName);
7
- });
8
- return `Seller enquiry submitted via team "${teamName}".`;
9
- }
10
- if (!params.autoResponderId || !params.autoResponderKey) {
11
- throw new Error("autoResponderId and autoResponderKey are required for autoresponder actions.");
12
- }
13
- const id = params.autoResponderId;
14
- const key = params.autoResponderKey;
15
- if (action === "autoresponder-get") {
16
- const result = await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => {
17
- return loopGet(apiKey, `/marketing/enquiries/auto-responder/${id}/${key}`, "loop-marketing-enquiry", teamName);
18
- });
19
- return JSON.stringify(result, null, 2);
20
- }
21
- if (action === "autoresponder-answers") {
22
- await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => {
23
- return loopPut(apiKey, `/marketing/enquiries/auto-responder/${id}/answers/${key}`, params.answers ?? [], "loop-marketing-enquiry", teamName);
24
- });
25
- return `Auto-responder answers submitted for enquiry ${id} via team "${teamName}".`;
26
- }
27
- if (action === "autoresponder-details") {
28
- await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => {
29
- return loopPut(apiKey, `/marketing/enquiries/auto-responder/${id}/details/${key}`, params.details ?? {}, "loop-marketing-enquiry", teamName);
30
- });
31
- return `Auto-responder details updated for enquiry ${id} via team "${teamName}".`;
32
- }
33
- if (action === "autoresponder-refer") {
34
- await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => {
35
- return loopPut(apiKey, `/marketing/enquiries/auto-responder/${id}/refer/${key}`, {}, "loop-marketing-enquiry", teamName);
36
- });
37
- return `Enquiry ${id} referred via team "${teamName}".`;
38
- }
39
- throw new Error(`Unknown action: ${action}`);
3
+ const { accountId, teamName, sellerEnquiryData } = params;
4
+ await withTeamKey(accountId, teamName, "marketing", "loop-marketing-enquiry", async (apiKey) => loopPost(apiKey, "/marketing/enquiries/seller", sellerEnquiryData ?? {}, "loop-marketing-enquiry", teamName));
5
+ return `Seller enquiry submitted via team "${teamName}".`;
40
6
  }
41
7
  //# sourceMappingURL=marketing-enquiry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"marketing-enquiry.js","sourceRoot":"","sources":["../../src/tools/marketing-enquiry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"marketing-enquiry.js","sourceRoot":"","sources":["../../src/tools/marketing-enquiry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAY3D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAItC;IACC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAAC;IAC1D,MAAM,WAAW,CACf,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,wBAAwB,EAC1D,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,QAAQ,CACxB,MAAM,EAAE,6BAA6B,EACrC,iBAAiB,IAAI,EAAE,EAAE,wBAAwB,EAAE,QAAQ,CAC5D,CACF,CAAC;IACF,OAAO,sCAAsC,QAAQ,IAAI,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,33 @@
1
+ type Department = "sales" | "lettings";
2
+ export declare function propertyViewing(params: {
3
+ accountId: string;
4
+ teamName: string;
5
+ propertyId: number;
6
+ department: Department;
7
+ name?: string;
8
+ email?: string;
9
+ phone?: string;
10
+ message?: string;
11
+ }): Promise<string>;
12
+ export declare function propertyCallback(params: {
13
+ accountId: string;
14
+ teamName: string;
15
+ propertyId: number;
16
+ department: Department;
17
+ name?: string;
18
+ email?: string;
19
+ phone?: string;
20
+ message?: string;
21
+ }): Promise<string>;
22
+ export declare function propertyInformation(params: {
23
+ accountId: string;
24
+ teamName: string;
25
+ propertyId: number;
26
+ department: Department;
27
+ name?: string;
28
+ email?: string;
29
+ phone?: string;
30
+ message?: string;
31
+ }): Promise<string>;
32
+ export {};
33
+ //# sourceMappingURL=property-intent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-intent.d.ts","sourceRoot":"","sources":["../../src/tools/property-intent.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AA4CvC,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAElB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAElB;AAED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAElB"}
@@ -0,0 +1,19 @@
1
+ import { loopPost, withTeamKey } from "../lib/loop-api.js";
2
+ async function submitIntent(toolName, action, params, successLabel) {
3
+ const { accountId, teamName, propertyId, department, ...body } = params;
4
+ await withTeamKey(accountId, teamName, "properties", toolName, async (apiKey) => {
5
+ const path = `/property/residential/${department}/${propertyId}/${action}`;
6
+ return loopPost(apiKey, path, body, toolName, teamName);
7
+ });
8
+ return `${successLabel} submitted for property ${propertyId} (${department}) via team "${teamName}".`;
9
+ }
10
+ export async function propertyViewing(params) {
11
+ return submitIntent("loop-property-viewing", "viewing", params, "Viewing request");
12
+ }
13
+ export async function propertyCallback(params) {
14
+ return submitIntent("loop-property-callback", "call-back", params, "Callback request");
15
+ }
16
+ export async function propertyInformation(params) {
17
+ return submitIntent("loop-property-information", "information", params, "Information request");
18
+ }
19
+ //# sourceMappingURL=property-intent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-intent.js","sourceRoot":"","sources":["../../src/tools/property-intent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAiB3D,KAAK,UAAU,YAAY,CACzB,QAAgB,EAChB,MAA+C,EAC/C,MASC,EACD,YAAoB;IAEpB,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;IACxE,MAAM,WAAW,CACf,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,yBAAyB,UAAU,IAAI,UAAU,IAAI,MAAM,EAAE,CAAC;QAC3E,OAAO,QAAQ,CAAsB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/E,CAAC,CACF,CAAC;IACF,OAAO,GAAG,YAAY,2BAA2B,UAAU,KAAK,UAAU,eAAe,QAAQ,IAAI,CAAC;AACxG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MASrC;IACC,OAAO,YAAY,CAAC,uBAAuB,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAStC;IACC,OAAO,YAAY,CAAC,wBAAwB,EAAE,WAAW,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MASzC;IACC,OAAO,YAAY,CAAC,2BAA2B,EAAE,aAAa,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC;AACjG,CAAC"}
@@ -4,7 +4,6 @@ export declare function propertyListed(params: {
4
4
  accountId: string;
5
5
  channel: Channel;
6
6
  department?: Department;
7
- includeSold?: boolean;
8
7
  teamName?: string;
9
8
  limit?: number;
10
9
  }): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"property-listed.d.ts","sourceRoot":"","sources":["../../src/tools/property-listed.ts"],"names":[],"mappings":"AAkCA,KAAK,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAChD,KAAK,OAAO,GAAG,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElE,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2ClB"}
1
+ {"version":3,"file":"property-listed.d.ts","sourceRoot":"","sources":["../../src/tools/property-listed.ts"],"names":[],"mappings":"AAkCA,KAAK,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAChD,KAAK,OAAO,GAAG,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElE,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqClB"}
@@ -1,6 +1,6 @@
1
1
  import { aggregateAcrossTeams, formatAggregationResult, loopGet, } from "../lib/loop-api.js";
2
2
  export async function propertyListed(params) {
3
- const { accountId, channel, department = "both", includeSold = false, teamName, limit } = params;
3
+ const { accountId, channel, department = "both", teamName, limit } = params;
4
4
  const result = await aggregateAcrossTeams(accountId, "properties", "loop-property-listed", async (apiKey, team) => {
5
5
  const all = [];
6
6
  const depts = department === "both" ? ["sales", "lettings"] : [department];
@@ -10,12 +10,6 @@ export async function propertyListed(params) {
10
10
  if (Array.isArray(data))
11
11
  all.push(...data);
12
12
  }
13
- if (includeSold) {
14
- const soldPath = `/property/residential/sold/${channel}`;
15
- const soldData = await loopGet(apiKey, soldPath, "loop-property-listed", team);
16
- if (Array.isArray(soldData))
17
- all.push(...soldData);
18
- }
19
13
  return all;
20
14
  }, { teamName, limitPerTeam: limit ?? 50, limitTotal: limit ?? 200 });
21
15
  return formatAggregationResult(result, (p) => {
@@ -1 +1 @@
1
- {"version":3,"file":"property-listed.js","sourceRoot":"","sources":["../../src/tools/property-listed.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,OAAO,GACR,MAAM,oBAAoB,CAAC;AAiC5B,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAOpC;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAEjG,MAAM,MAAM,GAAG,MAAM,oBAAoB,CACvC,SAAS,EACT,YAAY,EACZ,sBAAsB,EACtB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,GAAG,GAA0B,EAAE,CAAC;QACtC,MAAM,KAAK,GACT,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAE/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,yBAAyB,IAAI,WAAW,OAAO,EAAE,CAAC;YAC/D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAwB,MAAM,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,CAAC,CAAC;YAC9F,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7C,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,QAAQ,GAAG,8BAA8B,OAAO,EAAE,CAAC;YACzD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAwB,MAAM,EAAE,QAAQ,EAAE,sBAAsB,EAAE,IAAI,CAAC,CAAC;YACtG,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QACrD,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,IAAI,GAAG,EAAE,CAClE,CAAC;IAEF,OAAO,uBAAuB,CAC5B,MAAM,EACN,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,IAAI,GAAG,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,eAAe,IAAI,iBAAiB,CAAC;QACxE,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtG,OAAO,KAAK,IAAI,GAAG,EAAE,GAAG,KAAK,GAAG,IAAI,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;IACtE,CAAC,EACD,GAAG,OAAO,WAAW,CACtB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"property-listed.js","sourceRoot":"","sources":["../../src/tools/property-listed.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,OAAO,GACR,MAAM,oBAAoB,CAAC;AAiC5B,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAMpC;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAE5E,MAAM,MAAM,GAAG,MAAM,oBAAoB,CACvC,SAAS,EACT,YAAY,EACZ,sBAAsB,EACtB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,GAAG,GAA0B,EAAE,CAAC;QACtC,MAAM,KAAK,GACT,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAE/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,yBAAyB,IAAI,WAAW,OAAO,EAAE,CAAC;YAC/D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAwB,MAAM,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,CAAC,CAAC;YAC9F,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,IAAI,GAAG,EAAE,CAClE,CAAC;IAEF,OAAO,uBAAuB,CAC5B,MAAM,EACN,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,IAAI,GAAG,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,eAAe,IAAI,iBAAiB,CAAC;QACxE,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtG,OAAO,KAAK,IAAI,GAAG,EAAE,GAAG,KAAK,GAAG,IAAI,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;IACtE,CAAC,EACD,GAAG,OAAO,WAAW,CACtB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ type Channel = "rightmove" | "onTheMarket" | "zoopla" | "website";
2
+ export declare function propertySold(params: {
3
+ accountId: string;
4
+ channel: Channel;
5
+ teamName?: string;
6
+ limit?: number;
7
+ }): Promise<string>;
8
+ export {};
9
+ //# sourceMappingURL=property-sold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-sold.d.ts","sourceRoot":"","sources":["../../src/tools/property-sold.ts"],"names":[],"mappings":"AA+BA,KAAK,OAAO,GAAG,WAAW,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElE,wBAAsB,YAAY,CAAC,MAAM,EAAE;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BlB"}
@@ -0,0 +1,19 @@
1
+ import { aggregateAcrossTeams, formatAggregationResult, loopGet, } from "../lib/loop-api.js";
2
+ export async function propertySold(params) {
3
+ const { accountId, channel, teamName, limit } = params;
4
+ const result = await aggregateAcrossTeams(accountId, "properties", "loop-property-sold", async (apiKey, team) => {
5
+ const path = `/property/residential/sold/${channel}`;
6
+ const data = await loopGet(apiKey, path, "loop-property-sold", team);
7
+ return Array.isArray(data) ? data : [];
8
+ }, { teamName, limitPerTeam: limit ?? 50, limitTotal: limit ?? 200 });
9
+ return formatAggregationResult(result, (p) => {
10
+ const addr = p.displayAddress ?? p.propertyAddress ?? "Unknown address";
11
+ const id = p.propertyId != null ? ` [ID: ${p.propertyId}]` : "";
12
+ const price = p.price ? ` — £${p.price.toLocaleString("en-GB")}` : "";
13
+ const beds = p.bedrooms ? ` ${p.bedrooms}bed` : "";
14
+ const propType = p.propertyType ? ` (${p.propertyType})` : "";
15
+ const status = p.status ? ` [${p.status}]` : "";
16
+ return `- ${addr}${id}${price}${beds}${propType}${status}`;
17
+ }, `${channel} sold`);
18
+ }
19
+ //# sourceMappingURL=property-sold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-sold.js","sourceRoot":"","sources":["../../src/tools/property-sold.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,OAAO,GACR,MAAM,oBAAoB,CAAC;AA6B5B,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAKlC;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAEvD,MAAM,MAAM,GAAG,MAAM,oBAAoB,CACvC,SAAS,EACT,YAAY,EACZ,oBAAoB,EACpB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,IAAI,GAAG,8BAA8B,OAAO,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAwB,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,CAAC,CAAC;QAC5F,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,CAAC,EACD,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,IAAI,GAAG,EAAE,CAClE,CAAC;IAEF,OAAO,uBAAuB,CAC5B,MAAM,EACN,CAAC,CAAC,EAAE,EAAE;QACJ,MAAM,IAAI,GAAG,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,eAAe,IAAI,iBAAiB,CAAC;QACxE,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,OAAO,KAAK,IAAI,GAAG,EAAE,GAAG,KAAK,GAAG,IAAI,GAAG,QAAQ,GAAG,MAAM,EAAE,CAAC;IAC7D,CAAC,EACD,GAAG,OAAO,OAAO,CAClB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Task 103: per-tool shape tests for the three new value-pillar tools
3
+ * (loop-auto-responder, loop-property-sold, and the split property-intent
4
+ * tools). Asserts that each tool source references the swagger path family
5
+ * it claims to cover, and that index.ts registers it with the correct name.
6
+ */
7
+
8
+ import { describe, expect, it } from 'vitest';
9
+ import { readFileSync } from 'node:fs';
10
+ import { resolve, dirname } from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const PLUGIN_SRC = resolve(__dirname, '..');
15
+ const SWAGGER = JSON.parse(
16
+ readFileSync(resolve(__dirname, 'loop-swagger.snapshot.json'), 'utf-8'),
17
+ ) as { paths: Record<string, Record<string, unknown>> };
18
+
19
+ const indexSrc = readFileSync(resolve(PLUGIN_SRC, 'index.ts'), 'utf-8');
20
+ const readSrc = (rel: string) =>
21
+ readFileSync(resolve(PLUGIN_SRC, rel), 'utf-8');
22
+
23
+ interface ToolSpec {
24
+ tool: string;
25
+ source: string;
26
+ // `sourceFragment` is the literal substring the source file must contain —
27
+ // typically the stable prefix before a `${}` template variable.
28
+ sourceFragment: string;
29
+ swaggerPaths: { method: 'get' | 'post' | 'put'; path: string }[];
30
+ }
31
+
32
+ const NEW_TOOLS: ToolSpec[] = [
33
+ {
34
+ tool: 'loop-auto-responder',
35
+ source: 'tools/auto-responder.ts',
36
+ sourceFragment: '/marketing/enquiries/auto-responder/',
37
+ swaggerPaths: [
38
+ { method: 'get', path: '/marketing/enquiries/auto-responder/{id}/{key}' },
39
+ { method: 'put', path: '/marketing/enquiries/auto-responder/{id}/answers/{key}' },
40
+ { method: 'put', path: '/marketing/enquiries/auto-responder/{id}/details/{key}' },
41
+ { method: 'put', path: '/marketing/enquiries/auto-responder/{id}/refer/{key}' },
42
+ ],
43
+ },
44
+ {
45
+ tool: 'loop-property-sold',
46
+ source: 'tools/property-sold.ts',
47
+ sourceFragment: '/property/residential/sold/',
48
+ swaggerPaths: [
49
+ { method: 'get', path: '/property/residential/sold/{channel}' },
50
+ ],
51
+ },
52
+ {
53
+ tool: 'loop-property-viewing',
54
+ source: 'tools/property-intent.ts',
55
+ sourceFragment: '/property/residential/',
56
+ swaggerPaths: [
57
+ { method: 'post', path: '/property/residential/sales/{id}/viewing' },
58
+ { method: 'post', path: '/property/residential/lettings/{id}/viewing' },
59
+ ],
60
+ },
61
+ {
62
+ tool: 'loop-property-callback',
63
+ source: 'tools/property-intent.ts',
64
+ sourceFragment: '/property/residential/',
65
+ swaggerPaths: [
66
+ { method: 'post', path: '/property/residential/sales/{id}/call-back' },
67
+ { method: 'post', path: '/property/residential/lettings/{id}/call-back' },
68
+ ],
69
+ },
70
+ {
71
+ tool: 'loop-property-information',
72
+ source: 'tools/property-intent.ts',
73
+ sourceFragment: '/property/residential/',
74
+ swaggerPaths: [
75
+ { method: 'post', path: '/property/residential/sales/{id}/information' },
76
+ { method: 'post', path: '/property/residential/lettings/{id}/information' },
77
+ ],
78
+ },
79
+ ];
80
+
81
+ describe('Task 103 new tools', () => {
82
+ it.each(NEW_TOOLS)('$tool is registered in index.ts', ({ tool }) => {
83
+ const re = new RegExp(`server\\.tool\\(\\s*"${tool}"`);
84
+ expect(re.test(indexSrc), `tool ${tool} missing from index.ts`).toBe(true);
85
+ });
86
+
87
+ it.each(NEW_TOOLS)('$tool source file references the swagger path family', ({ source, sourceFragment }) => {
88
+ const src = readSrc(source);
89
+ expect(src.includes(sourceFragment), `${source} missing literal "${sourceFragment}"`).toBe(true);
90
+ });
91
+
92
+ it.each(NEW_TOOLS)('$tool swagger paths exist in the snapshot', ({ swaggerPaths }) => {
93
+ for (const { method, path } of swaggerPaths) {
94
+ const op = SWAGGER.paths[path];
95
+ expect(op, `path ${path} missing from swagger snapshot`).toBeDefined();
96
+ expect(op[method], `${method.toUpperCase()} ${path} missing from swagger snapshot`).toBeDefined();
97
+ }
98
+ });
99
+ });
@@ -58,18 +58,19 @@ const ENDPOINT_MAP: EndpointMapping[] = [
58
58
  { method: 'post', path: '/marketing/rentals/matching/{id}/information', tool: 'loop-marketing-match-request', source: 'tools/marketing-match-request.ts', fragment: '/marketing/rentals' },
59
59
  { method: 'post', path: '/marketing/matching/{id}/callback', tool: 'loop-marketing-match-request', source: 'tools/marketing-match-request.ts', fragment: '/matching/' },
60
60
  { method: 'post', path: '/marketing/rentals/matching/{id}/callback', tool: 'loop-marketing-match-request', source: 'tools/marketing-match-request.ts', fragment: '/marketing/rentals' },
61
- // Marketing — enquiries (4)
61
+ // Marketing — seller enquiry (1)
62
62
  { method: 'post', path: '/marketing/enquiries/seller', tool: 'loop-marketing-enquiry', source: 'tools/marketing-enquiry.ts', fragment: '/marketing/enquiries/seller' },
63
- { method: 'put', path: '/marketing/enquiries/auto-responder/{id}/answers/{key}', tool: 'loop-marketing-enquiry', source: 'tools/marketing-enquiry.ts', fragment: '/marketing/enquiries/auto-responder/' },
64
- { method: 'put', path: '/marketing/enquiries/auto-responder/{id}/details/{key}', tool: 'loop-marketing-enquiry', source: 'tools/marketing-enquiry.ts', fragment: '/marketing/enquiries/auto-responder/' },
65
- { method: 'put', path: '/marketing/enquiries/auto-responder/{id}/refer/{key}', tool: 'loop-marketing-enquiry', source: 'tools/marketing-enquiry.ts', fragment: '/marketing/enquiries/auto-responder/' },
66
- // Property (6)
67
- { method: 'post', path: '/property/residential/sales/{id}/viewing', tool: 'loop-property-request', source: 'tools/property-request.ts', fragment: '/property/residential/' },
68
- { method: 'post', path: '/property/residential/sales/{id}/call-back', tool: 'loop-property-request', source: 'tools/property-request.ts', fragment: '/property/residential/' },
69
- { method: 'post', path: '/property/residential/sales/{id}/information', tool: 'loop-property-request', source: 'tools/property-request.ts', fragment: '/property/residential/' },
70
- { method: 'post', path: '/property/residential/lettings/{id}/viewing', tool: 'loop-property-request', source: 'tools/property-request.ts', fragment: '/property/residential/' },
71
- { method: 'post', path: '/property/residential/lettings/{id}/call-back', tool: 'loop-property-request', source: 'tools/property-request.ts', fragment: '/property/residential/' },
72
- { method: 'post', path: '/property/residential/lettings/{id}/information', tool: 'loop-property-request', source: 'tools/property-request.ts', fragment: '/property/residential/' },
63
+ // Marketing auto-responder (3) Task 103 split into loop-auto-responder
64
+ { method: 'put', path: '/marketing/enquiries/auto-responder/{id}/answers/{key}', tool: 'loop-auto-responder', source: 'tools/auto-responder.ts', fragment: '/marketing/enquiries/auto-responder/' },
65
+ { method: 'put', path: '/marketing/enquiries/auto-responder/{id}/details/{key}', tool: 'loop-auto-responder', source: 'tools/auto-responder.ts', fragment: '/marketing/enquiries/auto-responder/' },
66
+ { method: 'put', path: '/marketing/enquiries/auto-responder/{id}/refer/{key}', tool: 'loop-auto-responder', source: 'tools/auto-responder.ts', fragment: '/marketing/enquiries/auto-responder/' },
67
+ // Property intent (6) Task 103 split loop-property-request into three intent-clear tools
68
+ { method: 'post', path: '/property/residential/sales/{id}/viewing', tool: 'loop-property-viewing', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
69
+ { method: 'post', path: '/property/residential/sales/{id}/call-back', tool: 'loop-property-callback', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
70
+ { method: 'post', path: '/property/residential/sales/{id}/information', tool: 'loop-property-information', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
71
+ { method: 'post', path: '/property/residential/lettings/{id}/viewing', tool: 'loop-property-viewing', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
72
+ { method: 'post', path: '/property/residential/lettings/{id}/call-back', tool: 'loop-property-callback', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
73
+ { method: 'post', path: '/property/residential/lettings/{id}/information', tool: 'loop-property-information', source: 'tools/property-intent.ts', fragment: '/property/residential/' },
73
74
  // Supplier (3)
74
75
  { method: 'post', path: '/supplier/maintenance/{code}/{jobid}/complete', tool: 'loop-supplier', source: 'tools/supplier.ts', fragment: '/supplier/maintenance/' },
75
76
  { method: 'put', path: '/supplier/maintenance/{code}/{quoteid}/quote-for-job', tool: 'loop-supplier', source: 'tools/supplier.ts', fragment: '/quote-for-job' },
@@ -10,7 +10,8 @@ import { keyList } from "./tools/key-list.js";
10
10
  import { propertySearch } from "./tools/property-search.js";
11
11
  import { propertyDetail } from "./tools/property-detail.js";
12
12
  import { propertyListed } from "./tools/property-listed.js";
13
- import { propertyRequest } from "./tools/property-request.js";
13
+ import { propertySold } from "./tools/property-sold.js";
14
+ import { propertyViewing, propertyCallback, propertyInformation } from "./tools/property-intent.js";
14
15
  import { peopleSearch } from "./tools/people-search.js";
15
16
  import { peopleDetail } from "./tools/people-detail.js";
16
17
  import { viewingSearch } from "./tools/viewing-search.js";
@@ -24,6 +25,7 @@ import { marketingMatchDetail } from "./tools/marketing-match.js";
24
25
  import { marketingMatchBatch } from "./tools/marketing-match-batch.js";
25
26
  import { marketingMatchRequest } from "./tools/marketing-match-request.js";
26
27
  import { marketingEnquiry } from "./tools/marketing-enquiry.js";
28
+ import { autoResponder } from "./tools/auto-responder.js";
27
29
  import { customerPreferences } from "./tools/customer-preferences.js";
28
30
  import { supplier } from "./tools/supplier.js";
29
31
  import { closeDriver } from "./lib/neo4j.js";
@@ -194,11 +196,10 @@ server.tool(
194
196
 
195
197
  server.tool(
196
198
  "loop-property-listed",
197
- "Get properties listed on a specific channel (Rightmove, Zoopla, OnTheMarket, website). Optionally include sold properties.",
199
+ "Get properties currently listed on a specific channel (Rightmove, Zoopla, OnTheMarket, website). For exchanged/completed properties use loop-property-sold.",
198
200
  {
199
201
  channel: z.enum(["rightmove", "onTheMarket", "zoopla", "website"]).describe("Listing channel"),
200
202
  department: z.enum(["sales", "lettings", "both"]).optional().describe("Department (default: both)"),
201
- includeSold: z.boolean().optional().describe("Include sold gallery (default: false)"),
202
203
  teamName: z.string().optional().describe("Query a specific team only"),
203
204
  limit: z.number().int().optional().describe("Max results (default 200)"),
204
205
  },
@@ -206,19 +207,63 @@ server.tool(
206
207
  );
207
208
 
208
209
  server.tool(
209
- "loop-property-request",
210
- "Submit a viewing, callback, or information request for a property. Requires a specific team.",
210
+ "loop-property-sold",
211
+ "Get exchanged or completed properties on a specific channel. Powers canvassing from recent sales and sold-gallery rendering.",
212
+ {
213
+ channel: z.enum(["rightmove", "onTheMarket", "zoopla", "website"]).describe("Listing channel"),
214
+ teamName: z.string().optional().describe("Query a specific team only"),
215
+ limit: z.number().int().optional().describe("Max results (default 200)"),
216
+ },
217
+ toolHandler(async (p) => propertySold(p as Parameters<typeof propertySold>[0]))
218
+ );
219
+
220
+ // Property-level intent tools (Task 103 split — replaces loop-property-request).
221
+ // Each intent is a distinct operator action so the agent's tool surface
222
+ // preserves intent fidelity.
223
+
224
+ server.tool(
225
+ "loop-property-viewing",
226
+ "Request a viewing for a property. Use when the operator says 'book a viewing', 'arrange a viewing', or 'ask to see the property'.",
227
+ {
228
+ teamName: z.string().min(1).describe("Team to submit the request through"),
229
+ propertyId: z.number().int().describe("Property ID"),
230
+ department: z.enum(["sales", "lettings"]).describe("sales or lettings"),
231
+ name: z.string().optional().describe("Requester name"),
232
+ email: z.string().optional().describe("Requester email"),
233
+ phone: z.string().optional().describe("Requester phone"),
234
+ message: z.string().optional().describe("Additional message"),
235
+ },
236
+ toolHandler(async (p) => propertyViewing(p as Parameters<typeof propertyViewing>[0]))
237
+ );
238
+
239
+ server.tool(
240
+ "loop-property-callback",
241
+ "Request a callback about a property. Use when the operator says 'ask them to call', 'request a callback', or 'have someone ring back'.",
242
+ {
243
+ teamName: z.string().min(1).describe("Team to submit the request through"),
244
+ propertyId: z.number().int().describe("Property ID"),
245
+ department: z.enum(["sales", "lettings"]).describe("sales or lettings"),
246
+ name: z.string().optional().describe("Requester name"),
247
+ email: z.string().optional().describe("Requester email"),
248
+ phone: z.string().optional().describe("Requester phone"),
249
+ message: z.string().optional().describe("Additional message"),
250
+ },
251
+ toolHandler(async (p) => propertyCallback(p as Parameters<typeof propertyCallback>[0]))
252
+ );
253
+
254
+ server.tool(
255
+ "loop-property-information",
256
+ "Request more information about a property. Use when the operator says 'ask for details', 'request the brochure', or 'find out more'.",
211
257
  {
212
258
  teamName: z.string().min(1).describe("Team to submit the request through"),
213
259
  propertyId: z.number().int().describe("Property ID"),
214
260
  department: z.enum(["sales", "lettings"]).describe("sales or lettings"),
215
- action: z.enum(["viewing", "call-back", "information"]).describe("Request type"),
216
261
  name: z.string().optional().describe("Requester name"),
217
262
  email: z.string().optional().describe("Requester email"),
218
263
  phone: z.string().optional().describe("Requester phone"),
219
264
  message: z.string().optional().describe("Additional message"),
220
265
  },
221
- toolHandler(async (p) => propertyRequest(p as Parameters<typeof propertyRequest>[0]))
266
+ toolHandler(async (p) => propertyInformation(p as Parameters<typeof propertyInformation>[0]))
222
267
  );
223
268
 
224
269
  // ─────────────────────────────────────────────────────────────────
@@ -377,22 +422,28 @@ server.tool(
377
422
 
378
423
  server.tool(
379
424
  "loop-marketing-enquiry",
380
- "Marketing enquiry operations: submit seller enquiries, manage auto-responder interactions.",
425
+ "Submit a seller-side marketing enquiry to Loop. For inbound applicant auto-responder workflows use loop-auto-responder.",
381
426
  {
382
427
  teamName: z.string().min(1).describe("Team to submit through"),
383
- action: z.enum([
384
- "seller-enquiry", "autoresponder-get", "autoresponder-answers",
385
- "autoresponder-details", "autoresponder-refer",
386
- ]).describe("Enquiry action"),
387
- sellerEnquiryData: z.record(z.string(), z.unknown()).optional().describe("Seller enquiry request body (for seller-enquiry)"),
388
- autoResponderId: z.number().int().optional().describe("Auto-responder enquiry ID"),
389
- autoResponderKey: z.string().optional().describe("Auto-responder key (UUID)"),
390
- answers: z.array(z.unknown()).optional().describe("Auto-responder answers array"),
391
- details: z.record(z.string(), z.unknown()).optional().describe("Auto-responder details object"),
428
+ sellerEnquiryData: z.record(z.string(), z.unknown()).optional().describe("Seller enquiry request body"),
392
429
  },
393
430
  toolHandler(async (p) => marketingEnquiry(p as Parameters<typeof marketingEnquiry>[0]))
394
431
  );
395
432
 
433
+ server.tool(
434
+ "loop-auto-responder",
435
+ "Read or progress an inbound enquiry through Loop's auto-responder (the surface behind Loop's 40% enquiry-efficiency claim). action=get reads questions+details; answers submits applicant replies; details updates the enquiry record; refer hands it to another team.",
436
+ {
437
+ teamName: z.string().min(1).describe("Team for this operation"),
438
+ action: z.enum(["get", "answers", "details", "refer"]).describe("Auto-responder action"),
439
+ autoResponderId: z.number().int().describe("Auto-responder enquiry ID"),
440
+ autoResponderKey: z.string().describe("Auto-responder key (UUID issued at enquiry creation)"),
441
+ answers: z.array(z.unknown()).optional().describe("Applicant answers (required for action=answers)"),
442
+ details: z.record(z.string(), z.unknown()).optional().describe("Enquiry details (for action=details)"),
443
+ },
444
+ toolHandler(async (p) => autoResponder(p as Parameters<typeof autoResponder>[0]))
445
+ );
446
+
396
447
  // ─────────────────────────────────────────────────────────────────
397
448
  // Customer Tools (1) — permission: customer
398
449
  // ─────────────────────────────────────────────────────────────────
@@ -0,0 +1,80 @@
1
+ import { loopGet, loopPut, withTeamKey } from "../lib/loop-api.js";
2
+
3
+ type AutoResponderAction = "get" | "answers" | "details" | "refer";
4
+
5
+ // Loop API V2: enquiry auto-responder endpoints (Loop's stated 40% efficiency lever)
6
+ // GET /marketing/enquiries/auto-responder/{id}/{key} — read questions + details
7
+ // PUT /marketing/enquiries/auto-responder/{id}/answers/{key} — submit applicant answers
8
+ // PUT /marketing/enquiries/auto-responder/{id}/details/{key} — update enquiry details
9
+ // PUT /marketing/enquiries/auto-responder/{id}/refer/{key} — refer enquiry to another team
10
+ // `id` is the enquiry id, `key` is the UUID handed out at enquiry creation.
11
+
12
+ interface LoopBooleanResponse {
13
+ success?: boolean;
14
+ [key: string]: unknown;
15
+ }
16
+
17
+ interface LoopAutoResponderDetails {
18
+ id?: number;
19
+ questions?: unknown[];
20
+ enquiryDetails?: unknown;
21
+ [key: string]: unknown;
22
+ }
23
+
24
+ export async function autoResponder(params: {
25
+ accountId: string;
26
+ teamName: string;
27
+ action: AutoResponderAction;
28
+ autoResponderId: number;
29
+ autoResponderKey: string;
30
+ answers?: unknown[];
31
+ details?: Record<string, unknown>;
32
+ }): Promise<string> {
33
+ const { accountId, teamName, action, autoResponderId: id, autoResponderKey: key } = params;
34
+
35
+ if (action === "get") {
36
+ const result = await withTeamKey<LoopAutoResponderDetails>(
37
+ accountId, teamName, "marketing", "loop-auto-responder",
38
+ async (apiKey) => loopGet<LoopAutoResponderDetails>(
39
+ apiKey, `/marketing/enquiries/auto-responder/${id}/${key}`,
40
+ "loop-auto-responder", teamName
41
+ )
42
+ );
43
+ return JSON.stringify(result, null, 2);
44
+ }
45
+
46
+ if (action === "answers") {
47
+ await withTeamKey<LoopBooleanResponse>(
48
+ accountId, teamName, "marketing", "loop-auto-responder",
49
+ async (apiKey) => loopPut<LoopBooleanResponse>(
50
+ apiKey, `/marketing/enquiries/auto-responder/${id}/answers/${key}`,
51
+ params.answers ?? [], "loop-auto-responder", teamName
52
+ )
53
+ );
54
+ return `Auto-responder answers submitted for enquiry ${id} via team "${teamName}".`;
55
+ }
56
+
57
+ if (action === "details") {
58
+ await withTeamKey<LoopBooleanResponse>(
59
+ accountId, teamName, "marketing", "loop-auto-responder",
60
+ async (apiKey) => loopPut<LoopBooleanResponse>(
61
+ apiKey, `/marketing/enquiries/auto-responder/${id}/details/${key}`,
62
+ params.details ?? {}, "loop-auto-responder", teamName
63
+ )
64
+ );
65
+ return `Auto-responder details updated for enquiry ${id} via team "${teamName}".`;
66
+ }
67
+
68
+ if (action === "refer") {
69
+ await withTeamKey<LoopBooleanResponse>(
70
+ accountId, teamName, "marketing", "loop-auto-responder",
71
+ async (apiKey) => loopPut<LoopBooleanResponse>(
72
+ apiKey, `/marketing/enquiries/auto-responder/${id}/refer/${key}`,
73
+ {}, "loop-auto-responder", teamName
74
+ )
75
+ );
76
+ return `Enquiry ${id} referred via team "${teamName}".`;
77
+ }
78
+
79
+ throw new Error(`Unknown auto-responder action: ${action}`);
80
+ }