@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.
- package/dist/__tests__/premium-mcp-discover.test.js +85 -0
- package/dist/index.js +25 -16
- package/dist/lib/premium-mcp-discover.js +34 -0
- package/package.json +1 -1
- package/payload/platform/lib/admins-write/dist/index.d.ts +0 -1
- package/payload/platform/lib/admins-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/admins-write/dist/index.js +2 -5
- package/payload/platform/lib/admins-write/dist/index.js.map +1 -1
- package/payload/platform/lib/admins-write/src/index.ts +2 -8
- package/payload/platform/lib/graph-mcp/dist/index.js +1 -4
- package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts +7 -6
- package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts.map +1 -1
- package/payload/platform/lib/graph-mcp/dist/schema-cache.js +7 -6
- package/payload/platform/lib/graph-mcp/dist/schema-cache.js.map +1 -1
- package/payload/platform/lib/graph-mcp/src/index.ts +1 -4
- package/payload/platform/lib/graph-mcp/src/schema-cache.ts +7 -6
- package/payload/platform/lib/graph-search/dist/index.d.ts +5 -5
- package/payload/platform/lib/graph-search/dist/index.js +4 -4
- package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +6 -7
- package/payload/platform/lib/graph-search/src/index.ts +5 -5
- package/payload/platform/lib/graph-trash/dist/index.d.ts +8 -12
- package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-trash/dist/index.js +8 -12
- package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-trash/src/index.ts +8 -12
- package/payload/platform/lib/graph-write/dist/index.d.ts +8 -9
- package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +9 -10
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/index.ts +9 -10
- package/payload/platform/lib/mcp-eager/dist/index.d.ts +4 -4
- package/payload/platform/lib/mcp-eager/dist/index.js +4 -4
- package/payload/platform/lib/mcp-eager/src/index.ts +4 -4
- package/payload/platform/plugins/admin/PLUGIN.md +1 -1
- package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +56 -38
- package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +42 -40
- package/payload/platform/plugins/cloudflare/scripts/__tests__/tunnel-ingress.test.ts +2 -2
- package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +7 -9
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +10 -12
- package/payload/platform/plugins/cloudflare/scripts/tunnel-ingress.ts +3 -3
- package/payload/platform/plugins/docs/references/deployment.md +2 -14
- package/payload/platform/plugins/docs/references/platform.md +2 -2
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +5 -5
- package/payload/platform/plugins/loop/PLUGIN.md +67 -12
- package/payload/platform/plugins/loop/mcp/dist/index.js +42 -16
- package/payload/platform/plugins/loop/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
- package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
- package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
- package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
- package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
- package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
- package/payload/platform/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
- package/payload/platform/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
- package/payload/platform/plugins/loop/mcp/src/index.ts +68 -17
- package/payload/platform/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
- package/payload/platform/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
- package/payload/platform/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
- package/payload/platform/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
- package/payload/platform/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +4 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +7 -12
- package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js +4 -4
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.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 +8 -9
- package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js.map +1 -1
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts +2 -2
- package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js +2 -2
- package/payload/platform/scripts/admin-persist-audit.ts +4 -10
- package/payload/platform/scripts/conversation-id-allowlist.txt +0 -1
- package/payload/platform/scripts/lib/resolve-account-dir.sh +0 -2
- package/payload/platform/scripts/resume-tunnel.sh +2 -9
- package/payload/platform/scripts/seed-neo4j.sh +26 -104
- 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 +53 -7
- 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 +0 -5
- 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 +13 -17
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +10 -2
- package/payload/platform/templates/agents/admin/SOUL.md +23 -1
- package/payload/premium-plugins/real-agent/agents/buyer-enquiry/SOUL.md +10 -0
- package/payload/premium-plugins/real-agent/agents/compliance.md +1 -1
- 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/loop/PLUGIN.md +67 -12
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js +42 -16
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/index.ts +68 -17
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
- package/payload/server/public/assets/admin-DBuCWSPS.js +216 -0
- package/payload/server/public/assets/{data-BxpOR0eM.js → data-BeblX4m4.js} +1 -1
- package/payload/server/public/assets/{graph-CrmxRSeb.js → graph-ZuBiYril.js} +1 -1
- package/payload/server/public/assets/graph-labels-CnbJR6cp.js +1 -0
- package/payload/server/public/assets/page-DDyny08O.js +50 -0
- package/payload/server/public/assets/page-nAY64ID7.js +1 -0
- package/payload/server/public/data.html +3 -3
- package/payload/server/public/graph.html +3 -3
- package/payload/server/public/index.html +4 -4
- package/payload/server/server.js +9 -46
- package/payload/platform/plugins/docs/references/migration-guide.md +0 -90
- package/payload/platform/plugins/loop/mcp/src/tools/property-request.ts +0 -42
- package/payload/platform/scripts/component-knowledgedoc-backfill.ts +0 -214
- package/payload/platform/scripts/migrate-import.sh +0 -437
- package/payload/platform/scripts/taskmaster-export.sh +0 -388
- package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-request.ts +0 -42
- package/payload/server/public/assets/admin-DVZcLuYu.js +0 -216
- package/payload/server/public/assets/graph-labels-C8A6BmtP.js +0 -1
- package/payload/server/public/assets/page-D5wAeFU0.js +0 -50
- package/payload/server/public/assets/page-DR5NU6S0.js +0 -1
|
@@ -1,113 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loopPost, withTeamKey } from "../lib/loop-api.js";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// Loop API V2: POST /marketing/enquiries/seller
|
|
4
|
+
// Submit a seller-side marketing enquiry. Auto-responder endpoints used to
|
|
5
|
+
// live in this tool but were split into `loop-auto-responder` for intent
|
|
6
|
+
// fidelity (Task 103).
|
|
4
7
|
|
|
5
|
-
// ─── Loop API V2: Marketing Enquiry Endpoints ──────────────────
|
|
6
|
-
// POST /marketing/enquiries/seller — submit seller enquiry
|
|
7
|
-
// GET /marketing/enquiries/auto-responder/{id}/{key} — read enquiry
|
|
8
|
-
// PUT .../auto-responder/{id}/answers/{key} — submit answers
|
|
9
|
-
// PUT .../auto-responder/{id}/details/{key} — update details
|
|
10
|
-
// PUT .../auto-responder/{id}/refer/{key} — refer enquiry
|
|
11
|
-
// Note: auto-responder uses personCode + key (UUID), not personId
|
|
12
|
-
// ────────────────────────────────────────────────────────────────
|
|
13
8
|
interface LoopBooleanResponse {
|
|
14
9
|
success?: boolean;
|
|
15
10
|
[key: string]: unknown;
|
|
16
11
|
}
|
|
17
12
|
|
|
18
|
-
interface LoopAutoResponderDetails {
|
|
19
|
-
id?: number;
|
|
20
|
-
questions?: unknown[];
|
|
21
|
-
enquiryDetails?: unknown;
|
|
22
|
-
[key: string]: unknown;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
13
|
export async function marketingEnquiry(params: {
|
|
26
14
|
accountId: string;
|
|
27
15
|
teamName: string;
|
|
28
|
-
action: EnquiryAction;
|
|
29
|
-
// For seller-enquiry
|
|
30
16
|
sellerEnquiryData?: Record<string, unknown>;
|
|
31
|
-
// For autoresponder actions
|
|
32
|
-
autoResponderId?: number;
|
|
33
|
-
autoResponderKey?: string;
|
|
34
|
-
// For autoresponder-answers
|
|
35
|
-
answers?: unknown[];
|
|
36
|
-
// For autoresponder-details
|
|
37
|
-
details?: Record<string, unknown>;
|
|
38
17
|
}): Promise<string> {
|
|
39
|
-
const { accountId, teamName,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
);
|
|
51
|
-
return `Seller enquiry submitted via team "${teamName}".`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (!params.autoResponderId || !params.autoResponderKey) {
|
|
55
|
-
throw new Error("autoResponderId and autoResponderKey are required for autoresponder actions.");
|
|
56
|
-
}
|
|
57
|
-
const id = params.autoResponderId;
|
|
58
|
-
const key = params.autoResponderKey;
|
|
59
|
-
|
|
60
|
-
if (action === "autoresponder-get") {
|
|
61
|
-
const result = await withTeamKey<LoopAutoResponderDetails>(
|
|
62
|
-
accountId, teamName, "marketing", "loop-marketing-enquiry",
|
|
63
|
-
async (apiKey) => {
|
|
64
|
-
return loopGet<LoopAutoResponderDetails>(
|
|
65
|
-
apiKey, `/marketing/enquiries/auto-responder/${id}/${key}`,
|
|
66
|
-
"loop-marketing-enquiry", teamName
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
return JSON.stringify(result, null, 2);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (action === "autoresponder-answers") {
|
|
74
|
-
await withTeamKey<LoopBooleanResponse>(
|
|
75
|
-
accountId, teamName, "marketing", "loop-marketing-enquiry",
|
|
76
|
-
async (apiKey) => {
|
|
77
|
-
return loopPut<LoopBooleanResponse>(
|
|
78
|
-
apiKey, `/marketing/enquiries/auto-responder/${id}/answers/${key}`,
|
|
79
|
-
params.answers ?? [], "loop-marketing-enquiry", teamName
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
);
|
|
83
|
-
return `Auto-responder answers submitted for enquiry ${id} via team "${teamName}".`;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (action === "autoresponder-details") {
|
|
87
|
-
await withTeamKey<LoopBooleanResponse>(
|
|
88
|
-
accountId, teamName, "marketing", "loop-marketing-enquiry",
|
|
89
|
-
async (apiKey) => {
|
|
90
|
-
return loopPut<LoopBooleanResponse>(
|
|
91
|
-
apiKey, `/marketing/enquiries/auto-responder/${id}/details/${key}`,
|
|
92
|
-
params.details ?? {}, "loop-marketing-enquiry", teamName
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
);
|
|
96
|
-
return `Auto-responder details updated for enquiry ${id} via team "${teamName}".`;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (action === "autoresponder-refer") {
|
|
100
|
-
await withTeamKey<LoopBooleanResponse>(
|
|
101
|
-
accountId, teamName, "marketing", "loop-marketing-enquiry",
|
|
102
|
-
async (apiKey) => {
|
|
103
|
-
return loopPut<LoopBooleanResponse>(
|
|
104
|
-
apiKey, `/marketing/enquiries/auto-responder/${id}/refer/${key}`,
|
|
105
|
-
{}, "loop-marketing-enquiry", teamName
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
);
|
|
109
|
-
return `Enquiry ${id} referred via team "${teamName}".`;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
throw new Error(`Unknown action: ${action}`);
|
|
18
|
+
const { accountId, teamName, sellerEnquiryData } = params;
|
|
19
|
+
await withTeamKey<LoopBooleanResponse>(
|
|
20
|
+
accountId, teamName, "marketing", "loop-marketing-enquiry",
|
|
21
|
+
async (apiKey) => loopPost<LoopBooleanResponse>(
|
|
22
|
+
apiKey, "/marketing/enquiries/seller",
|
|
23
|
+
sellerEnquiryData ?? {}, "loop-marketing-enquiry", teamName
|
|
24
|
+
)
|
|
25
|
+
);
|
|
26
|
+
return `Seller enquiry submitted via team "${teamName}".`;
|
|
113
27
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { loopPost, withTeamKey } from "../lib/loop-api.js";
|
|
2
|
+
|
|
3
|
+
type Department = "sales" | "lettings";
|
|
4
|
+
|
|
5
|
+
// Loop API V2: distinct operator-intent endpoints (post-Task 103 split).
|
|
6
|
+
// POST /property/residential/{dept}/{id}/viewing — request a viewing
|
|
7
|
+
// POST /property/residential/{dept}/{id}/call-back — request a callback
|
|
8
|
+
// POST /property/residential/{dept}/{id}/information — request more information
|
|
9
|
+
// Each endpoint takes the same {name?, email?, phone?, message?} body but is
|
|
10
|
+
// surfaced as a separate tool so operator intent is preserved on the agent's
|
|
11
|
+
// tool-call surface (replaces the prior bundled loop-property-request).
|
|
12
|
+
|
|
13
|
+
interface LoopBooleanResponse {
|
|
14
|
+
success?: boolean;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function submitIntent(
|
|
19
|
+
toolName: string,
|
|
20
|
+
action: "viewing" | "call-back" | "information",
|
|
21
|
+
params: {
|
|
22
|
+
accountId: string;
|
|
23
|
+
teamName: string;
|
|
24
|
+
propertyId: number;
|
|
25
|
+
department: Department;
|
|
26
|
+
name?: string;
|
|
27
|
+
email?: string;
|
|
28
|
+
phone?: string;
|
|
29
|
+
message?: string;
|
|
30
|
+
},
|
|
31
|
+
successLabel: string
|
|
32
|
+
): Promise<string> {
|
|
33
|
+
const { accountId, teamName, propertyId, department, ...body } = params;
|
|
34
|
+
await withTeamKey<LoopBooleanResponse>(
|
|
35
|
+
accountId,
|
|
36
|
+
teamName,
|
|
37
|
+
"properties",
|
|
38
|
+
toolName,
|
|
39
|
+
async (apiKey) => {
|
|
40
|
+
const path = `/property/residential/${department}/${propertyId}/${action}`;
|
|
41
|
+
return loopPost<LoopBooleanResponse>(apiKey, path, body, toolName, teamName);
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
return `${successLabel} submitted for property ${propertyId} (${department}) via team "${teamName}".`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function propertyViewing(params: {
|
|
48
|
+
accountId: string;
|
|
49
|
+
teamName: string;
|
|
50
|
+
propertyId: number;
|
|
51
|
+
department: Department;
|
|
52
|
+
name?: string;
|
|
53
|
+
email?: string;
|
|
54
|
+
phone?: string;
|
|
55
|
+
message?: string;
|
|
56
|
+
}): Promise<string> {
|
|
57
|
+
return submitIntent("loop-property-viewing", "viewing", params, "Viewing request");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function propertyCallback(params: {
|
|
61
|
+
accountId: string;
|
|
62
|
+
teamName: string;
|
|
63
|
+
propertyId: number;
|
|
64
|
+
department: Department;
|
|
65
|
+
name?: string;
|
|
66
|
+
email?: string;
|
|
67
|
+
phone?: string;
|
|
68
|
+
message?: string;
|
|
69
|
+
}): Promise<string> {
|
|
70
|
+
return submitIntent("loop-property-callback", "call-back", params, "Callback request");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function propertyInformation(params: {
|
|
74
|
+
accountId: string;
|
|
75
|
+
teamName: string;
|
|
76
|
+
propertyId: number;
|
|
77
|
+
department: Department;
|
|
78
|
+
name?: string;
|
|
79
|
+
email?: string;
|
|
80
|
+
phone?: string;
|
|
81
|
+
message?: string;
|
|
82
|
+
}): Promise<string> {
|
|
83
|
+
return submitIntent("loop-property-information", "information", params, "Information request");
|
|
84
|
+
}
|
|
@@ -39,11 +39,10 @@ export async function propertyListed(params: {
|
|
|
39
39
|
accountId: string;
|
|
40
40
|
channel: Channel;
|
|
41
41
|
department?: Department;
|
|
42
|
-
includeSold?: boolean;
|
|
43
42
|
teamName?: string;
|
|
44
43
|
limit?: number;
|
|
45
44
|
}): Promise<string> {
|
|
46
|
-
const { accountId, channel, department = "both",
|
|
45
|
+
const { accountId, channel, department = "both", teamName, limit } = params;
|
|
47
46
|
|
|
48
47
|
const result = await aggregateAcrossTeams<LoopPropertyListing>(
|
|
49
48
|
accountId,
|
|
@@ -60,12 +59,6 @@ export async function propertyListed(params: {
|
|
|
60
59
|
if (Array.isArray(data)) all.push(...data);
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
if (includeSold) {
|
|
64
|
-
const soldPath = `/property/residential/sold/${channel}`;
|
|
65
|
-
const soldData = await loopGet<LoopPropertyListing[]>(apiKey, soldPath, "loop-property-listed", team);
|
|
66
|
-
if (Array.isArray(soldData)) all.push(...soldData);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
62
|
return all;
|
|
70
63
|
},
|
|
71
64
|
{ teamName, limitPerTeam: limit ?? 50, limitTotal: limit ?? 200 }
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
aggregateAcrossTeams,
|
|
3
|
+
formatAggregationResult,
|
|
4
|
+
loopGet,
|
|
5
|
+
} from "../lib/loop-api.js";
|
|
6
|
+
|
|
7
|
+
// Loop API V2: GET /property/residential/sold/{channel}
|
|
8
|
+
// Distinct from /listed/{channel} — returns exchanged or completed properties
|
|
9
|
+
// (Loop swagger summary: "USE THIS TO POWER WEBSITE SOLD GALLERIES").
|
|
10
|
+
// Use case: canvassing letters built from recent sales in a target postcode.
|
|
11
|
+
|
|
12
|
+
interface LoopPropertyListing {
|
|
13
|
+
listingId?: number;
|
|
14
|
+
propertyId?: number;
|
|
15
|
+
propertyRefId?: string;
|
|
16
|
+
channel?: string;
|
|
17
|
+
propertyAddress?: string;
|
|
18
|
+
displayAddress?: string;
|
|
19
|
+
status?: string;
|
|
20
|
+
propertyType?: string;
|
|
21
|
+
dateLaunched?: string;
|
|
22
|
+
price?: number;
|
|
23
|
+
bedrooms?: number;
|
|
24
|
+
bathrooms?: number;
|
|
25
|
+
receptionRooms?: number;
|
|
26
|
+
shortDescription?: string;
|
|
27
|
+
features?: string[];
|
|
28
|
+
images?: { url: string }[];
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type Channel = "rightmove" | "onTheMarket" | "zoopla" | "website";
|
|
33
|
+
|
|
34
|
+
export async function propertySold(params: {
|
|
35
|
+
accountId: string;
|
|
36
|
+
channel: Channel;
|
|
37
|
+
teamName?: string;
|
|
38
|
+
limit?: number;
|
|
39
|
+
}): Promise<string> {
|
|
40
|
+
const { accountId, channel, teamName, limit } = params;
|
|
41
|
+
|
|
42
|
+
const result = await aggregateAcrossTeams<LoopPropertyListing>(
|
|
43
|
+
accountId,
|
|
44
|
+
"properties",
|
|
45
|
+
"loop-property-sold",
|
|
46
|
+
async (apiKey, team) => {
|
|
47
|
+
const path = `/property/residential/sold/${channel}`;
|
|
48
|
+
const data = await loopGet<LoopPropertyListing[]>(apiKey, path, "loop-property-sold", team);
|
|
49
|
+
return Array.isArray(data) ? data : [];
|
|
50
|
+
},
|
|
51
|
+
{ teamName, limitPerTeam: limit ?? 50, limitTotal: limit ?? 200 }
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return formatAggregationResult(
|
|
55
|
+
result,
|
|
56
|
+
(p) => {
|
|
57
|
+
const addr = p.displayAddress ?? p.propertyAddress ?? "Unknown address";
|
|
58
|
+
const id = p.propertyId != null ? ` [ID: ${p.propertyId}]` : "";
|
|
59
|
+
const price = p.price ? ` — £${p.price.toLocaleString("en-GB")}` : "";
|
|
60
|
+
const beds = p.bedrooms ? ` ${p.bedrooms}bed` : "";
|
|
61
|
+
const propType = p.propertyType ? ` (${p.propertyType})` : "";
|
|
62
|
+
const status = p.status ? ` [${p.status}]` : "";
|
|
63
|
+
return `- ${addr}${id}${price}${beds}${propType}${status}`;
|
|
64
|
+
},
|
|
65
|
+
`${channel} sold`
|
|
66
|
+
);
|
|
67
|
+
}
|