@rubytech/create-maxy-code 0.1.45 → 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.
- package/dist/index.js +8 -16
- 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 +0 -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-SyUHjvNs.js +216 -0
- package/payload/server/public/assets/{data-BxpOR0eM.js → data-DwQ7ZEyy.js} +1 -1
- package/payload/server/public/assets/{graph-CrmxRSeb.js → graph-CwZkD6GX.js} +1 -1
- package/payload/server/public/assets/graph-labels-CVkmOHhw.js +1 -0
- package/payload/server/public/assets/page-CQ7ELqGs.js +1 -0
- package/payload/server/public/assets/page-SOCqJGlV.js +50 -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
|
@@ -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-
|
|
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-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/page-
|
|
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-
|
|
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-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/page-
|
|
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-
|
|
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-
|
|
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-
|
|
14
|
-
<link rel="modulepreload" crossorigin href="/assets/page-
|
|
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">
|
package/payload/server/server.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
|
10735
|
-
//
|
|
10736
|
-
// - Message base distinct from PublicConversation (
|
|
10737
|
-
//
|
|
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
|
|
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
|
-
});
|