@rubytech/create-maxy-code 0.1.44 → 0.1.47

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 (155) hide show
  1. package/dist/index.js +8 -16
  2. package/package.json +1 -1
  3. package/payload/platform/lib/admins-write/dist/index.d.ts +0 -1
  4. package/payload/platform/lib/admins-write/dist/index.d.ts.map +1 -1
  5. package/payload/platform/lib/admins-write/dist/index.js +2 -5
  6. package/payload/platform/lib/admins-write/dist/index.js.map +1 -1
  7. package/payload/platform/lib/admins-write/src/index.ts +2 -8
  8. package/payload/platform/lib/graph-mcp/dist/index.js +1 -4
  9. package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
  10. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts +7 -6
  11. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts.map +1 -1
  12. package/payload/platform/lib/graph-mcp/dist/schema-cache.js +7 -6
  13. package/payload/platform/lib/graph-mcp/dist/schema-cache.js.map +1 -1
  14. package/payload/platform/lib/graph-mcp/src/index.ts +1 -4
  15. package/payload/platform/lib/graph-mcp/src/schema-cache.ts +7 -6
  16. package/payload/platform/lib/graph-search/dist/index.d.ts +5 -5
  17. package/payload/platform/lib/graph-search/dist/index.js +4 -4
  18. package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +6 -7
  19. package/payload/platform/lib/graph-search/src/index.ts +5 -5
  20. package/payload/platform/lib/graph-trash/dist/index.d.ts +8 -12
  21. package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -1
  22. package/payload/platform/lib/graph-trash/dist/index.js +8 -12
  23. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
  24. package/payload/platform/lib/graph-trash/src/index.ts +8 -12
  25. package/payload/platform/lib/graph-write/dist/index.d.ts +8 -9
  26. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
  27. package/payload/platform/lib/graph-write/dist/index.js +9 -10
  28. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  29. package/payload/platform/lib/graph-write/src/index.ts +9 -10
  30. package/payload/platform/lib/mcp-eager/dist/index.d.ts +4 -4
  31. package/payload/platform/lib/mcp-eager/dist/index.js +4 -4
  32. package/payload/platform/lib/mcp-eager/src/index.ts +4 -4
  33. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  34. package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +138 -18
  35. package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +31 -67
  36. package/payload/platform/plugins/cloudflare/scripts/__tests__/tunnel-ingress.test.ts +2 -2
  37. package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +7 -9
  38. package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +10 -12
  39. package/payload/platform/plugins/cloudflare/scripts/tunnel-ingress.ts +3 -3
  40. package/payload/platform/plugins/docs/references/deployment.md +0 -14
  41. package/payload/platform/plugins/docs/references/platform.md +6 -4
  42. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  43. package/payload/platform/plugins/docs/references/troubleshooting.md +5 -5
  44. package/payload/platform/plugins/loop/PLUGIN.md +67 -12
  45. package/payload/platform/plugins/loop/mcp/dist/index.js +42 -16
  46. package/payload/platform/plugins/loop/mcp/dist/index.js.map +1 -1
  47. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
  48. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
  49. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
  50. package/payload/platform/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
  51. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
  52. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
  53. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
  54. package/payload/platform/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
  55. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
  56. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
  57. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
  58. package/payload/platform/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
  59. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
  60. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
  61. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
  62. package/payload/platform/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
  63. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
  64. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
  65. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
  66. package/payload/platform/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
  67. package/payload/platform/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
  68. package/payload/platform/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
  69. package/payload/platform/plugins/loop/mcp/src/index.ts +68 -17
  70. package/payload/platform/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
  71. package/payload/platform/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
  72. package/payload/platform/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
  73. package/payload/platform/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
  74. package/payload/platform/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
  75. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +4 -3
  76. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
  77. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
  78. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +7 -12
  79. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
  80. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.js +2 -2
  81. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js +4 -4
  82. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js.map +1 -1
  83. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.d.ts.map +1 -1
  84. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js +8 -9
  85. package/payload/platform/plugins/tasks/mcp/dist/tools/session-name.js.map +1 -1
  86. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.d.ts +2 -2
  87. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-heal.js +2 -2
  88. package/payload/platform/scripts/admin-persist-audit.ts +4 -10
  89. package/payload/platform/scripts/conversation-id-allowlist.txt +0 -1
  90. package/payload/platform/scripts/lib/resolve-account-dir.sh +0 -2
  91. package/payload/platform/scripts/resume-tunnel.sh +2 -9
  92. package/payload/platform/scripts/seed-neo4j.sh +26 -104
  93. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  94. package/payload/platform/services/claude-session-manager/dist/http-server.js +67 -5
  95. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  96. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  97. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +13 -0
  98. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  99. package/payload/platform/templates/agents/admin/IDENTITY.md +12 -12
  100. package/payload/platform/templates/agents/admin/SOUL.md +23 -1
  101. package/payload/premium-plugins/real-agent/agents/buyer-enquiry/SOUL.md +10 -0
  102. package/payload/premium-plugins/real-agent/agents/compliance.md +1 -1
  103. package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
  104. package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
  105. package/payload/premium-plugins/real-agent/plugins/loop/PLUGIN.md +67 -12
  106. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js +42 -16
  107. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/index.js.map +1 -1
  108. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts +12 -0
  109. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.d.ts.map +1 -0
  110. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js +22 -0
  111. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/auto-responder.js.map +1 -0
  112. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts +0 -7
  113. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.d.ts.map +1 -1
  114. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js +4 -38
  115. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/marketing-enquiry.js.map +1 -1
  116. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts +33 -0
  117. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.d.ts.map +1 -0
  118. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js +19 -0
  119. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-intent.js.map +1 -0
  120. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts +0 -1
  121. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.d.ts.map +1 -1
  122. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js +1 -7
  123. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-listed.js.map +1 -1
  124. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts +9 -0
  125. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.d.ts.map +1 -0
  126. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js +19 -0
  127. package/payload/premium-plugins/real-agent/plugins/loop/mcp/dist/tools/property-sold.js.map +1 -0
  128. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/new-tool-shape.test.ts +99 -0
  129. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/__tests__/swagger-write-coverage.test.ts +12 -11
  130. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/index.ts +68 -17
  131. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/auto-responder.ts +80 -0
  132. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/marketing-enquiry.ts +14 -100
  133. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-intent.ts +84 -0
  134. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-listed.ts +1 -8
  135. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-sold.ts +67 -0
  136. package/payload/server/public/assets/admin-SyUHjvNs.js +216 -0
  137. package/payload/server/public/assets/{data-CU9uH2JJ.js → data-DwQ7ZEyy.js} +1 -1
  138. package/payload/server/public/assets/{graph-BI7yVwmT.js → graph-CwZkD6GX.js} +1 -1
  139. package/payload/server/public/assets/graph-labels-CVkmOHhw.js +1 -0
  140. package/payload/server/public/assets/page-CQ7ELqGs.js +1 -0
  141. package/payload/server/public/assets/page-SOCqJGlV.js +50 -0
  142. package/payload/server/public/data.html +3 -3
  143. package/payload/server/public/graph.html +3 -3
  144. package/payload/server/public/index.html +4 -4
  145. package/payload/server/server.js +9 -46
  146. package/payload/platform/plugins/docs/references/migration-guide.md +0 -90
  147. package/payload/platform/plugins/loop/mcp/src/tools/property-request.ts +0 -42
  148. package/payload/platform/scripts/component-knowledgedoc-backfill.ts +0 -214
  149. package/payload/platform/scripts/migrate-import.sh +0 -437
  150. package/payload/platform/scripts/taskmaster-export.sh +0 -388
  151. package/payload/premium-plugins/real-agent/plugins/loop/mcp/src/tools/property-request.ts +0 -42
  152. package/payload/server/public/assets/admin-GOZURixP.js +0 -216
  153. package/payload/server/public/assets/graph-labels-bI0uSt_-.js +0 -1
  154. package/payload/server/public/assets/page-BaRMnC96.js +0 -1
  155. package/payload/server/public/assets/page-DKdUMAhI.js +0 -50
@@ -5,11 +5,11 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Data — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/data-CU9uH2JJ.js"></script>
8
+ <script type="module" crossorigin src="/assets/data-DwQ7ZEyy.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-DD-I1_y5.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/brand-Dln107gD.js">
11
- <link rel="modulepreload" crossorigin href="/assets/graph-labels-bI0uSt_-.js">
12
- <link rel="modulepreload" crossorigin href="/assets/page-BaRMnC96.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/graph-labels-CVkmOHhw.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/page-CQ7ELqGs.js">
13
13
  <link rel="stylesheet" crossorigin href="/assets/brand-DCdOhh-I.css">
14
14
  </head>
15
15
  <body>
@@ -5,11 +5,11 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Graph — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/graph-BI7yVwmT.js"></script>
8
+ <script type="module" crossorigin src="/assets/graph-CwZkD6GX.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-DD-I1_y5.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/brand-Dln107gD.js">
11
- <link rel="modulepreload" crossorigin href="/assets/graph-labels-bI0uSt_-.js">
12
- <link rel="modulepreload" crossorigin href="/assets/page-DKdUMAhI.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/graph-labels-CVkmOHhw.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/page-SOCqJGlV.js">
13
13
  <link rel="stylesheet" crossorigin href="/assets/brand-DCdOhh-I.css">
14
14
  </head>
15
15
  <body>
@@ -5,13 +5,13 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/admin-GOZURixP.js"></script>
8
+ <script type="module" crossorigin src="/assets/admin-SyUHjvNs.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-DD-I1_y5.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/brand-Dln107gD.js">
11
- <link rel="modulepreload" crossorigin href="/assets/graph-labels-bI0uSt_-.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/graph-labels-CVkmOHhw.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/device-url-actions-B588ZlnE.js">
13
- <link rel="modulepreload" crossorigin href="/assets/page-BaRMnC96.js">
14
- <link rel="modulepreload" crossorigin href="/assets/page-DKdUMAhI.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/page-CQ7ELqGs.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/page-SOCqJGlV.js">
15
15
  <link rel="stylesheet" crossorigin href="/assets/brand-DCdOhh-I.css">
16
16
  <link rel="stylesheet" crossorigin href="/assets/admin-CWMpccrR.css">
17
17
  <link rel="stylesheet" href="/brand-defaults.css">
@@ -6098,9 +6098,7 @@ function writeAdminEntry(input) {
6098
6098
  if (existing === -1) {
6099
6099
  users.push({ userId: input.userId, pin: input.pin });
6100
6100
  } else {
6101
- const merged = { ...users[existing], pin: input.pin };
6102
- delete merged.name;
6103
- users[existing] = merged;
6101
+ users[existing] = { ...users[existing], pin: input.pin };
6104
6102
  }
6105
6103
  writeFileAtomic(input.usersFile, JSON.stringify(users, null, 2) + "\n", 384);
6106
6104
  result.usersJsonResult = "ok";
@@ -6585,11 +6583,10 @@ app5.post("/", async (c) => {
6585
6583
  var client_error_default = app5;
6586
6584
 
6587
6585
  // server/routes/admin/session.ts
6588
- import { readFileSync as readFileSync10, readdirSync as readdirSync4, statSync as statSync4, writeFileSync as writeFileSync7, existsSync as existsSync8 } from "fs";
6586
+ import { readFileSync as readFileSync10, readdirSync as readdirSync4, statSync as statSync4, existsSync as existsSync8 } from "fs";
6589
6587
  import { join as join8 } from "path";
6590
6588
  import { createHash as createHash2 } from "crypto";
6591
6589
  import { randomUUID as randomUUID6 } from "crypto";
6592
- var deprecationLogged = /* @__PURE__ */ new Set();
6593
6590
  function hashPin2(pin) {
6594
6591
  return createHash2("sha256").update(pin).digest("hex");
6595
6592
  }
@@ -6633,24 +6630,6 @@ function scanForOrphanedAccountAdmins(users) {
6633
6630
  }
6634
6631
  return orphans;
6635
6632
  }
6636
- function stripLegacyNameField(users) {
6637
- const dirty = users.some((u) => "name" in u && u.name !== void 0);
6638
- if (!dirty) return;
6639
- for (const u of users) {
6640
- if ("name" in u && u.name !== void 0) {
6641
- if (!deprecationLogged.has(u.userId)) {
6642
- console.log(`[admin-identity] users-json-name-field-deprecated userId=${u.userId.slice(0, 8)}`);
6643
- deprecationLogged.add(u.userId);
6644
- }
6645
- delete u.name;
6646
- }
6647
- }
6648
- try {
6649
- writeFileSync7(USERS_FILE, JSON.stringify(users), { mode: 384 });
6650
- } catch (err) {
6651
- console.error(`[admin-identity] users-json strip failed: ${err instanceof Error ? err.message : String(err)}`);
6652
- }
6653
- }
6654
6633
  async function resolveUserIdentity(accountId, userId) {
6655
6634
  const result = await loadAdminUserName(accountId, userId);
6656
6635
  if (result.source === "neo4j") {
@@ -6784,7 +6763,6 @@ app6.post("/", async (c) => {
6784
6763
  }
6785
6764
  return c.json({ error: "Invalid PIN" }, 401);
6786
6765
  }
6787
- stripLegacyNameField(users);
6788
6766
  const { userId } = matchedUser;
6789
6767
  const accounts = resolveUserAccounts(userId);
6790
6768
  if (accounts.length === 0) {
@@ -8655,7 +8633,7 @@ function isValidDomain(value) {
8655
8633
  }
8656
8634
 
8657
8635
  // app/lib/alias-domains.ts
8658
- import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
8636
+ import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync7 } from "fs";
8659
8637
  import { dirname as dirname3 } from "path";
8660
8638
  import { resolve as resolve13 } from "path";
8661
8639
  var ALIAS_DOMAINS_PATH = resolve13(MAXY_DIR, "alias-domains.json");
@@ -8674,7 +8652,7 @@ function addAliasDomain(hostname2) {
8674
8652
  if (existing.has(hostname2)) return;
8675
8653
  existing.add(hostname2);
8676
8654
  mkdirSync4(dirname3(ALIAS_DOMAINS_PATH), { recursive: true });
8677
- writeFileSync8(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
8655
+ writeFileSync7(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
8678
8656
  }
8679
8657
 
8680
8658
  // app/lib/script-stream-tailer.ts
@@ -10731,10 +10709,10 @@ var GRAPH_LABEL_COLOURS = {
10731
10709
  // intentional duplicate in the registry — see the
10732
10710
  // `INTENTIONAL_DUPLICATES` set in `graph-labels.test.ts`.
10733
10711
  // - Conversation base distinct from both AdminConversation and
10734
- // PublicConversation so pre-backfill fallback nodes don't
10735
- // visually collide with the sublabelled split.
10736
- // - Message base distinct from PublicConversation (the pre-Task-649
10737
- // `#A78BFA` collision class).
10712
+ // PublicConversation so base-Conversation rows don't visually
10713
+ // collide with the sublabelled split.
10714
+ // - Message base distinct from PublicConversation (`#A78BFA`
10715
+ // collision class).
10738
10716
  Conversation: "#6B5A85",
10739
10717
  AdminConversation: "#4F4070",
10740
10718
  PublicConversation: "#8A75A8",
@@ -12752,7 +12730,7 @@ function logResolved(result, detail) {
12752
12730
  }
12753
12731
 
12754
12732
  // server/index.ts
12755
- import { existsSync as existsSyncBoot, readFileSync as readFileSyncBoot, writeFileSync as writeFileSyncBoot } from "fs";
12733
+ import { existsSync as existsSyncBoot } from "fs";
12756
12734
  import { resolve as resolveBoot } from "path";
12757
12735
  function requestIsTlsTerminated(c) {
12758
12736
  const remote = c.env?.incoming?.socket?.remoteAddress ?? "";
@@ -13536,21 +13514,6 @@ var configDirForWhatsApp = basename5(MAXY_DIR) || ".maxy";
13536
13514
  var bootAccount = resolveAccount();
13537
13515
  var bootAccountConfig = bootAccount?.config;
13538
13516
  var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
13539
- if (bootAccount) {
13540
- const accountJsonPath = resolveBoot(bootAccount.accountDir, "account.json");
13541
- if (existsSyncBoot(accountJsonPath)) {
13542
- try {
13543
- const parsed = JSON.parse(readFileSyncBoot(accountJsonPath, "utf-8"));
13544
- if ("purchasedPlugins" in parsed) {
13545
- delete parsed.purchasedPlugins;
13546
- writeFileSyncBoot(accountJsonPath, JSON.stringify(parsed, null, 2) + "\n");
13547
- console.log(`[account-scrub] removed-purchasedPlugins=true accountId=${bootAccount.accountId}`);
13548
- }
13549
- } catch (err) {
13550
- console.error(`[account-scrub] read/write failed accountId=${bootAccount.accountId} \u2014 ${err instanceof Error ? err.message : String(err)}`);
13551
- }
13552
- }
13553
- }
13554
13517
  var bootEntitlement = bootAccountConfig ? resolveEntitlement(
13555
13518
  { configDir: MAXY_DIR, platformRoot: PLATFORM_ROOT, commercialMode: COMMERCIAL_MODE },
13556
13519
  {
@@ -1,90 +0,0 @@
1
- # Migration Guide — Taskmaster to {{productName}}
2
-
3
- Guide for communicating the migration process to customers moving from Taskmaster to {{productName}}.
4
-
5
- ## What the customer needs to know
6
-
7
- ### What stays the same
8
-
9
- - **All contacts** are transferred — every person the assistant knows about
10
- - **Business information** — address, team details, listings, and operational context
11
- - **Conversation history** — previous chats are preserved as reference material
12
- - **Media files** — uploaded documents, images, and voice notes are carried over
13
- - **Access PIN** — the existing login PIN is reused (no new PIN needed)
14
-
15
- ### What changes
16
-
17
- - **The assistant has new names.** Taskmaster's admin agent (e.g., "Ivan") and public agent (e.g., "Jon") are replaced by the {{productName}} equivalents. The migrated data is accessible to the new agents, but the personality and capabilities are upgraded.
18
-
19
- - **The web address changes.** Taskmaster used Tailscale URLs (`*.ts.net`) for web access. These are permanently replaced by a new local address (`http://{hostname}.local:{port}`). The old URLs stop working immediately. Provide the customer with their new URL.
20
-
21
- - **WhatsApp must be re-paired.** The WhatsApp connection is tied to the physical device session. After migration, the customer must scan a new QR code from their phone to reconnect WhatsApp. This is a one-time step — once paired, it stays connected.
22
-
23
- - **Skills are upgraded.** Taskmaster's skills are replaced by {{productName}}'s plugin system. The functionality is equivalent or better, but the names and capabilities may differ.
24
-
25
- ### What the customer needs to do
26
-
27
- 1. **Nothing during migration** — the entire process is handled by the operator.
28
-
29
- 2. **After migration completes:**
30
- - Open the new web URL (provided by the operator)
31
- - Log in with the existing PIN
32
- - **Re-pair WhatsApp:** Open the admin chat, ask the assistant to "Connect WhatsApp" — a QR code will appear. Scan it with the WhatsApp app on their phone.
33
- - Test the connection by sending a WhatsApp message to the business number
34
-
35
- 3. **Update any saved bookmarks or shortcuts** with the new web URL.
36
-
37
- 4. **Inform team members** (if applicable) about the WhatsApp re-pairing — they don't need to do anything, but may notice a brief gap in automated responses during the transition.
38
-
39
- ## Communication template
40
-
41
- Use this as a starting point for customer communication:
42
-
43
- ---
44
-
45
- **Subject: Your assistant is getting an upgrade**
46
-
47
- Hi {customer_name},
48
-
49
- We're upgrading your assistant from Taskmaster to {brand_name}. Here's what you need to know:
50
-
51
- **What's happening:** We're transferring all your data — contacts, conversations, business info, and files — to the new system. Everything you've built with the assistant carries over.
52
-
53
- **What you need to do:**
54
- 1. Open your new web address: {new_url}
55
- 2. Log in with your existing PIN
56
- 3. Reconnect WhatsApp by asking the assistant to "Connect WhatsApp" and scanning the QR code
57
-
58
- **Important:** Your old web address ({old_url}) will no longer work. Please update any bookmarks.
59
-
60
- **What's better:** {brand_name} includes upgraded capabilities — better scheduling, workflow automation, and an improved chat experience. Your assistant will guide you through the new features.
61
-
62
- If you have any questions, just ask!
63
-
64
- ---
65
-
66
- ## Operator checklist
67
-
68
- Pre-migration:
69
- - [ ] Export completed successfully (check export summary counts)
70
-
71
- Install:
72
- - [ ] {{productName}} installed (`npx -y @rubytech/create-realagent` or `@rubytech/create-maxy`)
73
- - [ ] Hostname set correctly (if different from brand default)
74
- - [ ] Port configured (if different from brand default — override via `~/.{brand}/.env`)
75
-
76
- Import:
77
- - [ ] Import script run (`bash migrate-import.sh ./bundle ~/{installDir}`)
78
- - [ ] Contacts visible in Neo4j (`cypher-shell` verification query)
79
- - [ ] PIN accepted (log in via browser to verify)
80
-
81
- Knowledge ingestion:
82
- - [ ] Admin agent told to read and memorise `memory/shared/business.md`
83
- - [ ] Admin agent told to read and memorise `memory/shared/team.md`
84
- - [ ] Admin agent told to read and memorise other key shared/admin memory files
85
- - [ ] "What's the business address?" returns the correct answer in admin chat
86
-
87
- Post-migration:
88
- - [ ] Customer notified of new URL
89
- - [ ] Customer re-pairs WhatsApp
90
- - [ ] Old Tailscale URL confirmed dead
@@ -1,42 +0,0 @@
1
- import { loopPost, withTeamKey } from "../lib/loop-api.js";
2
-
3
- type Department = "sales" | "lettings";
4
- type RequestAction = "viewing" | "call-back" | "information";
5
-
6
- // ─── Loop API V2: POST /property/residential/{dept}/{id}/{action}
7
- // Actions: viewing, call-back, information
8
- // Request body: { name?, email?, phone?, message? }
9
- // Response: boolean success
10
- // ────────────────────────────────────────────────────────────────
11
- interface LoopBooleanResponse {
12
- success?: boolean;
13
- [key: string]: unknown;
14
- }
15
-
16
- export async function propertyRequest(params: {
17
- accountId: string;
18
- teamName: string;
19
- propertyId: number;
20
- department: Department;
21
- action: RequestAction;
22
- name?: string;
23
- email?: string;
24
- phone?: string;
25
- message?: string;
26
- }): Promise<string> {
27
- const { accountId, teamName, propertyId, department, action, ...body } = params;
28
-
29
- const result = await withTeamKey<LoopBooleanResponse>(
30
- accountId,
31
- teamName,
32
- "properties",
33
- "loop-property-request",
34
- async (apiKey) => {
35
- const path = `/property/residential/${department}/${propertyId}/${action}`;
36
- return loopPost<LoopBooleanResponse>(apiKey, path, body, "loop-property-request", teamName);
37
- }
38
- );
39
-
40
- const actionLabel = action === "call-back" ? "callback" : action;
41
- return `${actionLabel} request submitted for property ${propertyId} (${department}) via team "${teamName}".`;
42
- }
@@ -1,214 +0,0 @@
1
- #!/usr/bin/env -S node --loader tsx
2
- /**
3
- * backfill:KnowledgeDocument projections for legacy
4
- * :Component rows whose component tool_use was emitted before this
5
- * task landed.
6
- *
7
- * Walks every `:Component {name ∈ PERSISTENT_COMPONENTS}` row that
8
- * lacks a sibling `:KnowledgeDocument` (matched by accountId +
9
- * deterministic attachmentId derived from the component's id) and
10
- * for each one materialises the file on disk + MERGEs the projection
11
- * row in a single Cypher tx. Idempotent — re-running against the
12
- * same rows is a no-op (MERGE collapses, file write rewrites the
13
- * same bytes).
14
- *
15
- * Usage:
16
- * tsx platform/scripts/component-knowledgedoc-backfill.ts \
17
- * [--account-id=<uuid>] # optional filter, default = all accounts
18
- * [--dry-run] # print what would happen, do not write
19
- *
20
- * Exit codes:
21
- * 0 = no rows needed backfill, OR all rows succeeded (including --dry-run)
22
- * 1 = at least one row failed (disk write threw, Cypher tx threw)
23
- * 2 = invocation / Neo4j connection error
24
- *
25
- * Per-row log line:
26
- * [component-kd-backfill] convId=<…> componentId=<…> outcome=created|skipped|failed reason=<…>
27
- *
28
- * The skip cases:
29
- * - component data does not contain `data.content` or `data.html`,
30
- * - both fields empty,
31
- * - the projection row already exists (idempotent re-run).
32
- */
33
-
34
- import process from "node:process";
35
-
36
- import { isPersistentComponent, PERSISTENT_COMPONENTS } from "../lib/persistent-components/src/index";
37
- import { deriveComponentAttachmentId, deriveComponentTitle, pickComponentBytes } from "../ui/app/lib/claude-agent/component-attachment";
38
- import { getSession } from "../ui/app/lib/neo4j-store";
39
- import { storeComponentArtefact } from "../ui/app/lib/attachments";
40
-
41
- interface Args {
42
- accountIdFilter?: string;
43
- dryRun: boolean;
44
- }
45
-
46
- function parseArgs(argv: string[]): Args {
47
- const out: Args = { dryRun: false };
48
- for (const a of argv) {
49
- const m = a.match(/^--([a-z-]+)(?:=(.+))?$/);
50
- if (!m) continue;
51
- const [, key, val] = m;
52
- if (key === "account-id") out.accountIdFilter = val;
53
- else if (key === "dry-run") out.dryRun = true;
54
- }
55
- return out;
56
- }
57
-
58
- interface ComponentRow {
59
- componentId: string;
60
- conversationId: string;
61
- accountId: string;
62
- name: string;
63
- data: string;
64
- existingAttachmentId: string | null;
65
- messageId: string;
66
- }
67
-
68
- async function main(): Promise<number> {
69
- const args = parseArgs(process.argv.slice(2));
70
- const session = getSession();
71
- let backfilled = 0;
72
- let skipped = 0;
73
- let failed = 0;
74
-
75
- try {
76
- // Pull every PERSISTENT_COMPONENTS :Component row, optionally
77
- // filtered by accountId. The query also returns the existing
78
- // c.attachmentId (null on legacy / pre-942 rows). For legacy rows
79
- // we derive attachmentId from componentId — it's the only stable
80
- // identifier on the historical data — write the file, MERGE the
81
- // projection, AND back-fill c.attachmentId so the audit harness
82
- // collapses on the same row on its next run.
83
- const componentNames = Array.from(PERSISTENT_COMPONENTS);
84
- const filterClause = args.accountIdFilter ? "AND c.accountId = $accountId" : "";
85
- const result = await session.run(
86
- `MATCH (m:Message)-[:HAS_COMPONENT]->(c:Component)
87
- WHERE c.name IN $names ${filterClause}
88
- RETURN c.componentId AS componentId,
89
- c.conversationId AS conversationId,
90
- c.accountId AS accountId,
91
- c.name AS name,
92
- c.data AS data,
93
- c.attachmentId AS existingAttachmentId,
94
- m.messageId AS messageId
95
- ORDER BY c.createdAt`,
96
- args.accountIdFilter
97
- ? { names: componentNames, accountId: args.accountIdFilter }
98
- : { names: componentNames },
99
- );
100
-
101
- for (const record of result.records) {
102
- const row: ComponentRow = {
103
- componentId: record.get("componentId") as string,
104
- conversationId: record.get("conversationId") as string,
105
- accountId: record.get("accountId") as string,
106
- name: record.get("name") as string,
107
- data: record.get("data") as string,
108
- existingAttachmentId: (record.get("existingAttachmentId") as string | null) ?? null,
109
- messageId: record.get("messageId") as string,
110
- };
111
-
112
- if (!isPersistentComponent(row.name)) {
113
- // Defensive — the WHERE clause already filters, but a future
114
- // schema change might mismatch; log and move on.
115
- skipped += 1;
116
- console.log(`[component-kd-backfill] convId=${row.conversationId.slice(0, 8)} componentId=${row.componentId.slice(0, 8)} outcome=skipped reason=name-not-persistent`);
117
- continue;
118
- }
119
-
120
- let dataObj: Record<string, unknown>;
121
- try {
122
- dataObj = JSON.parse(row.data) as Record<string, unknown>;
123
- } catch {
124
- skipped += 1;
125
- console.log(`[component-kd-backfill] convId=${row.conversationId.slice(0, 8)} componentId=${row.componentId.slice(0, 8)} outcome=skipped reason=data-not-json`);
126
- continue;
127
- }
128
-
129
- const bytesPick = pickComponentBytes(dataObj);
130
- if (!bytesPick) {
131
- skipped += 1;
132
- console.log(`[component-kd-backfill] convId=${row.conversationId.slice(0, 8)} componentId=${row.componentId.slice(0, 8)} outcome=skipped reason=no-content-or-html`);
133
- continue;
134
- }
135
-
136
- // Prefer the live-writer-stamped attachmentId when present;
137
- // otherwise derive from componentId (legacy / pre-942 rows).
138
- // The derived value is then written back onto :Component below
139
- // so the audit harness sees a single source of truth on the
140
- // next run.
141
- const attachmentId = row.existingAttachmentId ?? deriveComponentAttachmentId(row.componentId);
142
- const derivedFromComponentId = !row.existingAttachmentId;
143
- const title = deriveComponentTitle(row.name, dataObj);
144
- const filename = bytesPick.mimeType === "text/html" ? `${title}.html` : `${title}.md`;
145
-
146
- if (args.dryRun) {
147
- console.log(`[component-kd-backfill] convId=${row.conversationId.slice(0, 8)} componentId=${row.componentId.slice(0, 8)} outcome=dry-run attachmentId=${attachmentId.slice(0, 8)} mimeType=${bytesPick.mimeType} bytes=${bytesPick.content.length} source=${derivedFromComponentId ? "derived" : "stamped"}`);
148
- continue;
149
- }
150
-
151
- try {
152
- await storeComponentArtefact(row.accountId, attachmentId, bytesPick.mimeType, bytesPick.content, filename);
153
- } catch (err) {
154
- failed += 1;
155
- const reason = err instanceof Error ? err.message : String(err);
156
- console.log(`[component-kd-backfill] convId=${row.conversationId.slice(0, 8)} componentId=${row.componentId.slice(0, 8)} outcome=failed reason=disk-write:${JSON.stringify(reason.slice(0, 200))}`);
157
- continue;
158
- }
159
-
160
- try {
161
- // MERGE the projection + the discovery edge from :Message + back-fill
162
- // c.attachmentId so the audit harness sees a single attachmentId
163
- // source on its next run. The Cypher returns whether the projection
164
- // was newly created or already existed, so the per-row log line
165
- // distinguishes the two outcomes for forensic purposes.
166
- const mergeResult = await session.run(
167
- `MATCH (m:Message {messageId: $messageId, accountId: $accountId})
168
- MATCH (m)-[:HAS_COMPONENT]->(c:Component {componentId: $componentId})
169
- MERGE (k:KnowledgeDocument {accountId: $accountId, attachmentId: $attachmentId})
170
- ON CREATE SET k.name = $title,
171
- k.encodingFormat = $mimeType,
172
- k.createdAt = datetime(),
173
- k.updatedAt = datetime()
174
- ON MATCH SET k.updatedAt = datetime()
175
- MERGE (m)-[:HAS_KNOWLEDGE_DOCUMENT]->(k)
176
- SET c.attachmentId = $attachmentId
177
- RETURN CASE WHEN k.createdAt = k.updatedAt THEN 'created' ELSE 'projection-existed' END AS state`,
178
- {
179
- accountId: row.accountId,
180
- attachmentId,
181
- title,
182
- mimeType: bytesPick.mimeType,
183
- messageId: row.messageId,
184
- componentId: row.componentId,
185
- },
186
- );
187
- const state = mergeResult.records[0]?.get("state") as string | undefined;
188
- if (state === "created") {
189
- backfilled += 1;
190
- console.log(`[component-kd-backfill] convId=${row.conversationId.slice(0, 8)} componentId=${row.componentId.slice(0, 8)} outcome=created attachmentId=${attachmentId.slice(0, 8)} mimeType=${bytesPick.mimeType} bytes=${bytesPick.content.length} source=${derivedFromComponentId ? "derived" : "stamped"}`);
191
- } else {
192
- skipped += 1;
193
- console.log(`[component-kd-backfill] convId=${row.conversationId.slice(0, 8)} componentId=${row.componentId.slice(0, 8)} outcome=skipped reason=already-projected`);
194
- }
195
- } catch (err) {
196
- failed += 1;
197
- const reason = err instanceof Error ? err.message : String(err);
198
- console.log(`[component-kd-backfill] convId=${row.conversationId.slice(0, 8)} componentId=${row.componentId.slice(0, 8)} outcome=failed reason=cypher:${JSON.stringify(reason.slice(0, 200))}`);
199
- }
200
- }
201
- } finally {
202
- await session.close();
203
- }
204
-
205
- console.log(`[component-kd-backfill] summary backfilled=${backfilled} skipped=${skipped} failed=${failed}`);
206
- return failed === 0 ? 0 : 1;
207
- }
208
-
209
- main()
210
- .then((code) => process.exit(code))
211
- .catch((err) => {
212
- console.error(`[component-kd-backfill] crashed: ${err instanceof Error ? err.stack : String(err)}`);
213
- process.exit(2);
214
- });