@rubytech/create-realagent-code 0.1.117 → 0.1.120

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 (137) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/schema.cypher +124 -1
  3. package/payload/platform/package-lock.json +141 -125
  4. package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
  5. package/payload/platform/plugins/aeo/.claude-plugin/plugin.json +17 -0
  6. package/payload/platform/plugins/aeo/PLUGIN.md +81 -0
  7. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts +2 -0
  8. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts.map +1 -0
  9. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js +121 -0
  10. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js.map +1 -0
  11. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts +2 -0
  12. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts.map +1 -0
  13. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js +129 -0
  14. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js.map +1 -0
  15. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts +2 -0
  16. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts.map +1 -0
  17. package/payload/platform/plugins/aeo/mcp/dist/index.js +171 -0
  18. package/payload/platform/plugins/aeo/mcp/dist/index.js.map +1 -0
  19. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts +27 -0
  20. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts.map +1 -0
  21. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js +274 -0
  22. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js.map +1 -0
  23. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts +5 -0
  24. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts.map +1 -0
  25. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js +38 -0
  26. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js.map +1 -0
  27. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts +48 -0
  28. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts.map +1 -0
  29. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js +254 -0
  30. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js.map +1 -0
  31. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts +25 -0
  32. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts.map +1 -0
  33. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js +78 -0
  34. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js.map +1 -0
  35. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts +18 -0
  36. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts.map +1 -0
  37. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js +56 -0
  38. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js.map +1 -0
  39. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts +37 -0
  40. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts.map +1 -0
  41. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js +94 -0
  42. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js.map +1 -0
  43. package/payload/platform/plugins/aeo/mcp/package.json +22 -0
  44. package/payload/platform/plugins/aeo/mcp/vitest.config.ts +9 -0
  45. package/payload/platform/plugins/aeo/skills/structured-answer/SKILL.md +53 -0
  46. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.d.ts +12 -1
  47. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.d.ts.map +1 -1
  48. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.js +34 -1
  49. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.js.map +1 -1
  50. package/payload/platform/plugins/docs/references/aeo.md +87 -0
  51. package/payload/platform/plugins/docs/references/visitor-graph.md +82 -0
  52. package/payload/platform/plugins/email/PLUGIN.md +6 -0
  53. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +180 -0
  54. package/payload/platform/plugins/memory/mcp/dist/index.js +5 -0
  55. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  56. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts +2 -0
  57. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts.map +1 -0
  58. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js +62 -0
  59. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js.map +1 -0
  60. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts +18 -0
  61. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts.map +1 -0
  62. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js +29 -0
  63. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js.map +1 -0
  64. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js +2 -0
  65. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js.map +1 -1
  66. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js +1 -1
  67. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js.map +1 -1
  68. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts +3 -0
  69. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -1
  70. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +9 -1
  71. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -1
  72. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
  73. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +8 -0
  74. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  75. package/payload/platform/plugins/memory/mcp/vitest.config.ts +2 -0
  76. package/payload/platform/plugins/memory/references/schema-base.md +49 -1
  77. package/payload/platform/scripts/smoke-boot-services.sh +30 -2
  78. package/payload/platform/templates/specialists/agents/signal-detector.md +1 -1
  79. package/payload/premium-plugins/real-agent/plugins/buyers/.claude-plugin/plugin.json +1 -1
  80. package/payload/premium-plugins/real-agent/plugins/buyers/PLUGIN.md +33 -3
  81. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/index.d.ts +2 -0
  82. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/index.d.ts.map +1 -0
  83. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/index.js +97 -0
  84. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/index.js.map +1 -0
  85. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/lib/neo4j.d.ts +5 -0
  86. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/lib/neo4j.d.ts.map +1 -0
  87. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/lib/neo4j.js +40 -0
  88. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/lib/neo4j.js.map +1 -0
  89. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-backfill-from-logs.d.ts +24 -0
  90. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-backfill-from-logs.d.ts.map +1 -0
  91. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-backfill-from-logs.js +156 -0
  92. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-backfill-from-logs.js.map +1 -0
  93. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-engagement-score.d.ts +21 -0
  94. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-engagement-score.d.ts.map +1 -0
  95. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-engagement-score.js +65 -0
  96. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-engagement-score.js.map +1 -0
  97. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-event-ingest.d.ts +26 -0
  98. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-event-ingest.d.ts.map +1 -0
  99. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-event-ingest.js +78 -0
  100. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-event-ingest.js.map +1 -0
  101. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recent-by-page.d.ts +19 -0
  102. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recent-by-page.d.ts.map +1 -0
  103. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recent-by-page.js +41 -0
  104. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recent-by-page.js.map +1 -0
  105. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recent-by-person.d.ts +20 -0
  106. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recent-by-person.d.ts.map +1 -0
  107. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recent-by-person.js +44 -0
  108. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recent-by-person.js.map +1 -0
  109. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recommendation-ctr.d.ts +22 -0
  110. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recommendation-ctr.d.ts.map +1 -0
  111. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recommendation-ctr.js +41 -0
  112. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-recommendation-ctr.js.map +1 -0
  113. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-session-detail.d.ts +32 -0
  114. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-session-detail.d.ts.map +1 -0
  115. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-session-detail.js +87 -0
  116. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/dist/tools/visitor-session-detail.js.map +1 -0
  117. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/package-lock.json +2566 -0
  118. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/package.json +21 -0
  119. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/src/index.ts +145 -0
  120. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/src/lib/neo4j.ts +45 -0
  121. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/src/tools/visitor-backfill-from-logs.ts +189 -0
  122. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/src/tools/visitor-engagement-score.ts +87 -0
  123. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/src/tools/visitor-event-ingest.ts +119 -0
  124. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/src/tools/visitor-recent-by-page.ts +61 -0
  125. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/src/tools/visitor-recent-by-person.ts +65 -0
  126. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/src/tools/visitor-recommendation-ctr.ts +67 -0
  127. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/src/tools/visitor-session-detail.ts +127 -0
  128. package/payload/premium-plugins/real-agent/plugins/buyers/mcp/tsconfig.json +20 -0
  129. package/payload/premium-plugins/real-agent/plugins/buyers/skills/property-recommender/SKILL.md +11 -0
  130. package/payload/premium-plugins/real-agent/plugins/leads/skills/lead-nurturing/SKILL.md +9 -0
  131. package/payload/premium-plugins/real-agent/plugins/leads/skills/morning-round/SKILL.md +11 -0
  132. package/payload/premium-plugins/real-agent/plugins/vendors/skills/vendor-updates/SKILL.md +13 -0
  133. package/payload/server/{chunk-FJCI6X3H.js → chunk-HCYM5FLU.js} +2 -0
  134. package/payload/server/maxy-edge.js +1 -1
  135. package/payload/server/public/privacy.html +66 -0
  136. package/payload/server/public/v.js +191 -0
  137. package/payload/server/server.js +473 -85
@@ -0,0 +1,41 @@
1
+ // visitor-recent-by-page — who viewed a given page/listing recently.
2
+ // Operator-side query: "who has shown interest in 12 Oak Street this week?"
3
+ import { getSession } from "../lib/neo4j.js";
4
+ export async function visitorRecentByPage(p) {
5
+ if (!p.listingSlug && !p.url) {
6
+ throw new Error("visitor-recent-by-page requires listingSlug or url");
7
+ }
8
+ const since = p.sinceDays ?? 7;
9
+ const limit = Math.max(1, Math.min(p.limit ?? 50, 200));
10
+ const session = getSession();
11
+ try {
12
+ const result = await session.run(`MATCH (pv:PageView {accountId: $accountId})
13
+ WHERE pv.occurredAt >= datetime() - duration({days: $since})
14
+ AND ($url IS NULL OR EXISTS { MATCH (pv)-[:OF_PAGE]->(:Page {accountId: $accountId, url: $url}) })
15
+ AND ($slug IS NULL OR EXISTS { MATCH (pv)-[:OF_LISTING]->(:Listing {accountId: $accountId, slug: $slug, scope:'public'}) })
16
+ MATCH (s:Session)-[:HAS_EVENT]->(pv)
17
+ OPTIONAL MATCH (per:Person)-[:VISITED]->(s)
18
+ OPTIONAL MATCH (av:AnonVisitor)-[:VISITED]->(s)
19
+ WITH per, av, s, count(pv) AS pageviews
20
+ RETURN coalesce(elementId(per), null) AS personId,
21
+ coalesce(per.name, null) AS personName,
22
+ coalesce(av.visitorId, null) AS anonVisitorId,
23
+ sum(pageviews) AS totalPageviews,
24
+ toString(max(s.lastSeenAt)) AS lastSeenAt
25
+ ORDER BY lastSeenAt DESC
26
+ LIMIT $limit`, { accountId: p.accountId, url: p.url ?? null, slug: p.listingSlug ?? null, since, limit });
27
+ return {
28
+ visitors: result.records.map((r) => ({
29
+ personId: r.get("personId"),
30
+ personName: r.get("personName"),
31
+ anonVisitorId: r.get("anonVisitorId"),
32
+ pageviewCount: Number(r.get("totalPageviews") ?? 0),
33
+ lastSeenAt: r.get("lastSeenAt"),
34
+ })),
35
+ };
36
+ }
37
+ finally {
38
+ await session.close();
39
+ }
40
+ }
41
+ //# sourceMappingURL=visitor-recent-by-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor-recent-by-page.js","sourceRoot":"","sources":["../../src/tools/visitor-recent-by-page.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,4EAA4E;AAE5E,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAmB7C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,CAAqB;IAC7D,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B;;;;;;;;;;;;;;oBAcc,EACd,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAC1F,CAAC;QACF,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACnC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC;gBAC3B,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;gBAC/B,aAAa,EAAE,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC;gBACrC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;gBACnD,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;aAChC,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -0,0 +1,20 @@
1
+ export interface RecentByPersonParams {
2
+ accountId: string;
3
+ personId: string;
4
+ sinceDays?: number;
5
+ limit?: number;
6
+ }
7
+ export interface SessionSummary {
8
+ sessionId: string;
9
+ startedAt: string;
10
+ lastSeenAt: string;
11
+ pageviewCount: number;
12
+ clickCount: number;
13
+ maxScrollDepth: number;
14
+ listingSlugs: string[];
15
+ dwellMs: number;
16
+ }
17
+ export declare function visitorRecentByPerson(p: RecentByPersonParams): Promise<{
18
+ sessions: SessionSummary[];
19
+ }>;
20
+ //# sourceMappingURL=visitor-recent-by-person.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor-recent-by-person.d.ts","sourceRoot":"","sources":["../../src/tools/visitor-recent-by-person.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,cAAc,EAAE,CAAA;CAAE,CAAC,CAwC5G"}
@@ -0,0 +1,44 @@
1
+ // visitor-recent-by-person — list recent :Session activity for a :Person.
2
+ // Walks (Person)-[:VISITED]->(Session)-[:HAS_EVENT]->(*) and returns a
3
+ // chronological summary the morning-round skill folds into its briefing.
4
+ import { getSession } from "../lib/neo4j.js";
5
+ export async function visitorRecentByPerson(p) {
6
+ const since = p.sinceDays ?? 30;
7
+ const limit = Math.max(1, Math.min(p.limit ?? 50, 200));
8
+ const session = getSession();
9
+ try {
10
+ const result = await session.run(`MATCH (per:Person {accountId: $accountId}) WHERE elementId(per) = $personId
11
+ MATCH (per)-[:VISITED]->(s:Session)
12
+ WHERE s.startedAt >= datetime() - duration({days: $since})
13
+ OPTIONAL MATCH (s)-[:HAS_EVENT]->(pv:PageView)
14
+ OPTIONAL MATCH (s)-[:HAS_EVENT]->(cl:Click)
15
+ OPTIONAL MATCH (s)-[:HAS_EVENT]->(sm:ScrollMilestone)
16
+ OPTIONAL MATCH (pv)-[:OF_LISTING]->(l:Listing)
17
+ WITH s, count(DISTINCT pv) AS pageviews, count(DISTINCT cl) AS clicks,
18
+ coalesce(max(sm.maxDepth), 0) AS maxDepth,
19
+ collect(DISTINCT l.slug) AS slugs,
20
+ coalesce(sum(pv.dwellMs), 0) AS dwellMs
21
+ RETURN s.sessionId AS sessionId,
22
+ toString(s.startedAt) AS startedAt,
23
+ toString(s.lastSeenAt) AS lastSeenAt,
24
+ pageviews, clicks, maxDepth, slugs, dwellMs
25
+ ORDER BY s.lastSeenAt DESC
26
+ LIMIT $limit`, { accountId: p.accountId, personId: p.personId, since, limit });
27
+ return {
28
+ sessions: result.records.map((r) => ({
29
+ sessionId: r.get("sessionId"),
30
+ startedAt: r.get("startedAt"),
31
+ lastSeenAt: r.get("lastSeenAt"),
32
+ pageviewCount: Number(r.get("pageviews") ?? 0),
33
+ clickCount: Number(r.get("clicks") ?? 0),
34
+ maxScrollDepth: Number(r.get("maxDepth") ?? 0),
35
+ listingSlugs: (r.get("slugs") ?? []).filter((s) => typeof s === "string"),
36
+ dwellMs: Number(r.get("dwellMs") ?? 0),
37
+ })),
38
+ };
39
+ }
40
+ finally {
41
+ await session.close();
42
+ }
43
+ }
44
+ //# sourceMappingURL=visitor-recent-by-person.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor-recent-by-person.js","sourceRoot":"","sources":["../../src/tools/visitor-recent-by-person.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,uEAAuE;AACvE,yEAAyE;AAEzE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAoB7C,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,CAAuB;IACjE,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B;;;;;;;;;;;;;;;;oBAgBc,EACd,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAC/D,CAAC;QACF,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACnC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;gBAC7B,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;gBAC7B,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;gBAC/B,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBAC9C,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACxC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAC9C,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAU,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;gBAC/F,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;aACvC,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ export interface RecommendationCtrParams {
2
+ accountId: string;
3
+ /** Days back from now. Defaults to 7. */
4
+ sinceDays?: number;
5
+ /** Optional listingSlug filter. */
6
+ listingSlug?: string;
7
+ }
8
+ export interface CtrRow {
9
+ listingSlug: string;
10
+ recommended: number;
11
+ clicked: number;
12
+ ctr: number;
13
+ }
14
+ export interface CtrSummary {
15
+ windowDays: number;
16
+ totalRecommended: number;
17
+ totalClicked: number;
18
+ ctr: number;
19
+ perListing: CtrRow[];
20
+ }
21
+ export declare function visitorRecommendationCtr(p: RecommendationCtrParams): Promise<CtrSummary>;
22
+ //# sourceMappingURL=visitor-recommendation-ctr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor-recommendation-ctr.d.ts","sourceRoot":"","sources":["../../src/tools/visitor-recommendation-ctr.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,wBAAsB,wBAAwB,CAAC,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,UAAU,CAAC,CAmC9F"}
@@ -0,0 +1,41 @@
1
+ // visitor-recommendation-ctr — graph-backed CTR replacement for the
2
+ // log-scan aggregation that ships with Task 336. Operates on Recommendation
3
+ // nodes (materialised from [property-recommended] log lines via backfill)
4
+ // joined to :Click events. Output schema matches the log-scan tool's so
5
+ // the cutover (separate follow-up task) is a one-line swap.
6
+ import { getSession } from "../lib/neo4j.js";
7
+ export async function visitorRecommendationCtr(p) {
8
+ const since = p.sinceDays ?? 7;
9
+ const session = getSession();
10
+ try {
11
+ const result = await session.run(`MATCH (rec:Recommendation {accountId: $accountId})
12
+ WHERE rec.recommendedAt >= datetime() - duration({days: $since})
13
+ AND ($slug IS NULL OR rec.listingSlug = $slug)
14
+ OPTIONAL MATCH (rec)-[:FOR_SESSION]->(s:Session)-[:HAS_EVENT]->(cl:Click {label: 'card'})
15
+ WITH rec.listingSlug AS slug,
16
+ count(DISTINCT rec) AS recommended,
17
+ count(DISTINCT cl) AS clicked
18
+ RETURN slug AS listingSlug, recommended, clicked,
19
+ CASE WHEN recommended > 0 THEN toFloat(clicked) / recommended ELSE 0.0 END AS ctr
20
+ ORDER BY recommended DESC`, { accountId: p.accountId, since, slug: p.listingSlug ?? null });
21
+ const perListing = result.records.map((r) => ({
22
+ listingSlug: r.get("listingSlug") ?? "",
23
+ recommended: Number(r.get("recommended") ?? 0),
24
+ clicked: Number(r.get("clicked") ?? 0),
25
+ ctr: Number(r.get("ctr") ?? 0),
26
+ }));
27
+ const totalRecommended = perListing.reduce((a, b) => a + b.recommended, 0);
28
+ const totalClicked = perListing.reduce((a, b) => a + b.clicked, 0);
29
+ return {
30
+ windowDays: since,
31
+ totalRecommended,
32
+ totalClicked,
33
+ ctr: totalRecommended > 0 ? totalClicked / totalRecommended : 0,
34
+ perListing,
35
+ };
36
+ }
37
+ finally {
38
+ await session.close();
39
+ }
40
+ }
41
+ //# sourceMappingURL=visitor-recommendation-ctr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor-recommendation-ctr.js","sourceRoot":"","sources":["../../src/tools/visitor-recommendation-ctr.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,4EAA4E;AAC5E,0EAA0E;AAC1E,wEAAwE;AACxE,4DAA4D;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAyB7C,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,CAA0B;IACvE,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B;;;;;;;;;iCAS2B,EAC3B,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI,EAAE,CAC/D,CAAC;QACF,MAAM,UAAU,GAAa,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtD,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE;YACvC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YAC9C,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACtC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SAC/B,CAAC,CAAC,CAAC;QACJ,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC3E,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACnE,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,gBAAgB;YAChB,YAAY;YACZ,GAAG,EAAE,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;YAC/D,UAAU;SACX,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ export interface SessionDetailParams {
2
+ accountId: string;
3
+ sessionId: string;
4
+ }
5
+ export interface SessionEvent {
6
+ kind: "pageview" | "click" | "scroll";
7
+ occurredAt: string;
8
+ /** PageView only */
9
+ url?: string;
10
+ path?: string;
11
+ pageViewId?: string;
12
+ referrer?: string;
13
+ dwellMs?: number;
14
+ /** Click only */
15
+ label?: string;
16
+ href?: string;
17
+ /** Scroll only */
18
+ maxDepth?: number;
19
+ /** Optional listing link */
20
+ listingSlug?: string;
21
+ }
22
+ export interface SessionDetail {
23
+ sessionId: string;
24
+ startedAt: string | null;
25
+ lastSeenAt: string | null;
26
+ personId: string | null;
27
+ personName: string | null;
28
+ anonVisitorId: string | null;
29
+ events: SessionEvent[];
30
+ }
31
+ export declare function visitorSessionDetail(p: SessionDetailParams): Promise<SessionDetail>;
32
+ //# sourceMappingURL=visitor-session-detail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor-session-detail.d.ts","sourceRoot":"","sources":["../../src/tools/visitor-session-detail.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,wBAAsB,oBAAoB,CAAC,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAwFzF"}
@@ -0,0 +1,87 @@
1
+ // visitor-session-detail — full event timeline for one :Session.
2
+ // Operator-side query: "show me everything Sarah did in session abc12".
3
+ import { getSession } from "../lib/neo4j.js";
4
+ export async function visitorSessionDetail(p) {
5
+ const session = getSession();
6
+ try {
7
+ const sessionRes = await session.run(`MATCH (s:Session {accountId: $accountId, sessionId: $sessionId})
8
+ OPTIONAL MATCH (per:Person)-[:VISITED]->(s)
9
+ OPTIONAL MATCH (av:AnonVisitor)-[:VISITED]->(s)
10
+ RETURN toString(s.startedAt) AS startedAt,
11
+ toString(s.lastSeenAt) AS lastSeenAt,
12
+ elementId(per) AS personId,
13
+ per.name AS personName,
14
+ av.visitorId AS anonVisitorId
15
+ LIMIT 1`, { accountId: p.accountId, sessionId: p.sessionId });
16
+ if (sessionRes.records.length === 0) {
17
+ return {
18
+ sessionId: p.sessionId,
19
+ startedAt: null,
20
+ lastSeenAt: null,
21
+ personId: null,
22
+ personName: null,
23
+ anonVisitorId: null,
24
+ events: [],
25
+ };
26
+ }
27
+ const head = sessionRes.records[0];
28
+ const eventsRes = await session.run(`MATCH (s:Session {accountId: $accountId, sessionId: $sessionId})-[:HAS_EVENT]->(e)
29
+ OPTIONAL MATCH (e)-[:OF_PAGE]->(pg:Page)
30
+ OPTIONAL MATCH (e)-[:OF_LISTING]->(l:Listing)
31
+ RETURN labels(e) AS labels,
32
+ toString(e.occurredAt) AS occurredAt,
33
+ toString(coalesce(e.firstAt, e.occurredAt)) AS firstAt,
34
+ e.url AS url,
35
+ pg.url AS pageUrl,
36
+ e.path AS path,
37
+ e.pageViewId AS pageViewId,
38
+ e.referrer AS referrer,
39
+ e.dwellMs AS dwellMs,
40
+ e.label AS label,
41
+ e.href AS href,
42
+ e.maxDepth AS maxDepth,
43
+ l.slug AS listingSlug
44
+ ORDER BY firstAt ASC`, { accountId: p.accountId, sessionId: p.sessionId });
45
+ const events = eventsRes.records.map((r) => {
46
+ const labels = r.get("labels");
47
+ const kind = labels.includes("PageView")
48
+ ? "pageview"
49
+ : labels.includes("Click")
50
+ ? "click"
51
+ : "scroll";
52
+ const base = {
53
+ kind,
54
+ occurredAt: r.get("occurredAt") ?? r.get("firstAt") ?? "",
55
+ };
56
+ if (kind === "pageview") {
57
+ base.url = r.get("pageUrl") ?? r.get("url") ?? "";
58
+ base.path = r.get("path") ?? undefined;
59
+ base.pageViewId = r.get("pageViewId") ?? undefined;
60
+ base.referrer = r.get("referrer") ?? undefined;
61
+ base.dwellMs = r.get("dwellMs") != null ? Number(r.get("dwellMs")) : undefined;
62
+ base.listingSlug = r.get("listingSlug") ?? undefined;
63
+ }
64
+ else if (kind === "click") {
65
+ base.label = r.get("label") ?? "unknown";
66
+ base.href = r.get("href") ?? undefined;
67
+ }
68
+ else {
69
+ base.maxDepth = r.get("maxDepth") != null ? Number(r.get("maxDepth")) : undefined;
70
+ }
71
+ return base;
72
+ });
73
+ return {
74
+ sessionId: p.sessionId,
75
+ startedAt: head.get("startedAt"),
76
+ lastSeenAt: head.get("lastSeenAt"),
77
+ personId: head.get("personId"),
78
+ personName: head.get("personName"),
79
+ anonVisitorId: head.get("anonVisitorId"),
80
+ events,
81
+ };
82
+ }
83
+ finally {
84
+ await session.close();
85
+ }
86
+ }
87
+ //# sourceMappingURL=visitor-session-detail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor-session-detail.js","sourceRoot":"","sources":["../../src/tools/visitor-session-detail.ts"],"names":[],"mappings":"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"}