@rubytech/create-maxy-code 0.1.486 → 0.1.488
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/package.json +1 -1
- package/payload/platform/plugins/cloudflare/PLUGIN.md +3 -3
- package/payload/platform/plugins/cloudflare/bin/portal-index-push.mjs +30 -8
- package/payload/platform/plugins/cloudflare/bin/schema-exposed-dirs.mjs +22 -2
- package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-index-push.test.ts +23 -0
- package/payload/platform/plugins/cloudflare/mcp/__tests__/schema-exposed-dirs.test.ts +43 -0
- package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +12 -2
- package/payload/platform/plugins/memory/PLUGIN.md +1 -0
- package/payload/platform/plugins/memory/references/schema-construction.md +13 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/free-busy-url.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/free-busy-url.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/free-busy-url.test.js +12 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/free-busy-url.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/free-busy-url.d.ts +8 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/free-busy-url.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/free-busy-url.js +12 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/free-busy-url.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js +12 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js.map +1 -1
- package/payload/platform/plugins/storage-broker/PLUGIN.md +1 -0
- package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +22 -2
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +23 -2
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/assets/{AdminLoginScreens-DF9S5Rca.js → AdminLoginScreens-Dic_fPt6.js} +1 -1
- package/payload/server/public/assets/{AdminShell-B0PNDCAb.js → AdminShell-JN7rZ8aG.js} +1 -1
- package/payload/server/public/assets/{Checkbox-s5X6dso4.js → Checkbox-CB74kINA.js} +1 -1
- package/payload/server/public/assets/{activity-BRBsaalV.js → activity-DbfpHg3i.js} +1 -1
- package/payload/server/public/assets/{admin-BoVCP4Mw.js → admin-CThbXaYH.js} +1 -1
- package/payload/server/public/assets/{bot-BVO9Uqr_.js → bot-DnuyRsLS.js} +1 -1
- package/payload/server/public/assets/{browser-BVW4FFii.js → browser-q4EFqKvR.js} +1 -1
- package/payload/server/public/assets/{calendar-CWsD3uLk.js → calendar-C-q9kWmA.js} +1 -1
- package/payload/server/public/assets/chat-DcefIV9q.js +1 -0
- package/payload/server/public/assets/chevron-down-Blma_CKl.js +1 -0
- package/payload/server/public/assets/chevron-left-xeYDxFiC.js +1 -0
- package/payload/server/public/assets/chevron-right-BonbtjqJ.js +1 -0
- package/payload/server/public/assets/data-D5dp6nj6.js +1 -0
- package/payload/server/public/assets/{graph-mJ9ky5dc.js → graph-CNgt7ygi.js} +1 -1
- package/payload/server/public/assets/{graph-labels-C8-sIKuv.js → graph-labels-DA48HrRR.js} +1 -1
- package/payload/server/public/assets/{maximize-2-yucCepu_.js → maximize-2-k3Fu5hdP.js} +1 -1
- package/payload/server/public/assets/{operator-911z_Fy_.js → operator-8NVpNLeD.js} +1 -1
- package/payload/server/public/assets/{page-Cv0qUwMG.js → page-Bvx0A2jB.js} +1 -1
- package/payload/server/public/assets/{page-CgSgj8Cy.js → page-DhwPG5Zf.js} +1 -1
- package/payload/server/public/assets/{public-BzwveFwz.js → public-BJ5Oo2Fw.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-BH51cf2Q.js → rotate-ccw-D-ov5jM4.js} +1 -1
- package/payload/server/public/assets/tasks-DHMxTZVD.js +1 -0
- package/payload/server/public/assets/{time-entry-format-DPdGkp1C.js → time-entry-format-EmV5lz6o.js} +1 -1
- package/payload/server/public/assets/{triangle-alert-DO2rjjfV.js → triangle-alert-CivyPfAL.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-HMSM7-Ir.js → useCopyFeedback-hbnPS-r9.js} +1 -1
- package/payload/server/public/assets/{useSubAccountSwitcher-2ojOOYNo.css → useSubAccountSwitcher-kwhG-aJj.css} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-BcukQIza.js → useVoiceRecorder-QN9_GqB_.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +6 -6
- package/payload/server/public/chat.html +13 -13
- package/payload/server/public/data.html +10 -10
- package/payload/server/public/graph.html +11 -11
- package/payload/server/public/index.html +16 -16
- package/payload/server/public/operator.html +15 -15
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +155 -103
- package/payload/server/public/assets/chat-DKGREuIO.js +0 -1
- package/payload/server/public/assets/chevron-down-m581tl1J.js +0 -1
- package/payload/server/public/assets/chevron-left-BAY0xfmR.js +0 -1
- package/payload/server/public/assets/chevron-right-Dy_REdYZ.js +0 -1
- package/payload/server/public/assets/data-CtOxa94P.js +0 -1
- package/payload/server/public/assets/tasks-21egY7A6.js +0 -1
- /package/payload/server/public/assets/{useSubAccountSwitcher-DLvqvfoc.js → useSubAccountSwitcher-DotTrvX3.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -1643,10 +1643,10 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1643
1643
|
};
|
|
1644
1644
|
|
|
1645
1645
|
// server/index.ts
|
|
1646
|
-
import { readFileSync as
|
|
1646
|
+
import { readFileSync as readFileSync43, existsSync as existsSync39, watchFile, readdirSync as readdirSync26, statSync as statSync17 } from "fs";
|
|
1647
1647
|
import { spawn as spawn3 } from "child_process";
|
|
1648
1648
|
import { createHash as createHash7 } from "crypto";
|
|
1649
|
-
import { resolve as
|
|
1649
|
+
import { resolve as resolve39, join as join45, basename as basename12 } from "path";
|
|
1650
1650
|
import { homedir as homedir4 } from "os";
|
|
1651
1651
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1652
1652
|
|
|
@@ -2920,7 +2920,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
2920
2920
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
2921
2921
|
console.error(`${TAG6} draining credential save queue\u2026`);
|
|
2922
2922
|
const timer = new Promise(
|
|
2923
|
-
(
|
|
2923
|
+
(resolve40) => setTimeout(() => resolve40("timeout"), timeoutMs)
|
|
2924
2924
|
);
|
|
2925
2925
|
const result = await Promise.race([
|
|
2926
2926
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -3097,11 +3097,11 @@ async function createWaSocket(opts) {
|
|
|
3097
3097
|
return sock;
|
|
3098
3098
|
}
|
|
3099
3099
|
async function waitForConnection(sock) {
|
|
3100
|
-
return new Promise((
|
|
3100
|
+
return new Promise((resolve40, reject) => {
|
|
3101
3101
|
const handler = (update) => {
|
|
3102
3102
|
if (update.connection === "open") {
|
|
3103
3103
|
sock.ev.off("connection.update", handler);
|
|
3104
|
-
|
|
3104
|
+
resolve40();
|
|
3105
3105
|
}
|
|
3106
3106
|
if (update.connection === "close") {
|
|
3107
3107
|
sock.ev.off("connection.update", handler);
|
|
@@ -3209,7 +3209,7 @@ function isTimeoutError(err) {
|
|
|
3209
3209
|
return Boolean(err?.__maxyTimeout);
|
|
3210
3210
|
}
|
|
3211
3211
|
function withTimeout(label, promise, timeoutMs) {
|
|
3212
|
-
return new Promise((
|
|
3212
|
+
return new Promise((resolve40, reject) => {
|
|
3213
3213
|
const timer = setTimeout(() => {
|
|
3214
3214
|
const err = new Error(`${label} timed out after ${timeoutMs}ms`);
|
|
3215
3215
|
err.__maxyTimeout = true;
|
|
@@ -3219,7 +3219,7 @@ function withTimeout(label, promise, timeoutMs) {
|
|
|
3219
3219
|
promise.then(
|
|
3220
3220
|
(value) => {
|
|
3221
3221
|
clearTimeout(timer);
|
|
3222
|
-
|
|
3222
|
+
resolve40(value);
|
|
3223
3223
|
},
|
|
3224
3224
|
(err) => {
|
|
3225
3225
|
clearTimeout(timer);
|
|
@@ -4278,8 +4278,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
4278
4278
|
const { givenName, familyName } = splitName(input.pushName);
|
|
4279
4279
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
4280
4280
|
let release;
|
|
4281
|
-
const mine = new Promise((
|
|
4282
|
-
release =
|
|
4281
|
+
const mine = new Promise((resolve40) => {
|
|
4282
|
+
release = resolve40;
|
|
4283
4283
|
});
|
|
4284
4284
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
4285
4285
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -6016,11 +6016,11 @@ async function connectWithReconnect(conn) {
|
|
|
6016
6016
|
console.error(
|
|
6017
6017
|
`${TAG17} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
6018
6018
|
);
|
|
6019
|
-
await new Promise((
|
|
6020
|
-
const timer = setTimeout(
|
|
6019
|
+
await new Promise((resolve40) => {
|
|
6020
|
+
const timer = setTimeout(resolve40, delay);
|
|
6021
6021
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
6022
6022
|
clearTimeout(timer);
|
|
6023
|
-
|
|
6023
|
+
resolve40();
|
|
6024
6024
|
}, { once: true });
|
|
6025
6025
|
});
|
|
6026
6026
|
}
|
|
@@ -6028,16 +6028,16 @@ async function connectWithReconnect(conn) {
|
|
|
6028
6028
|
}
|
|
6029
6029
|
}
|
|
6030
6030
|
function waitForDisconnectEvent(conn) {
|
|
6031
|
-
return new Promise((
|
|
6031
|
+
return new Promise((resolve40) => {
|
|
6032
6032
|
if (!conn.sock) {
|
|
6033
|
-
|
|
6033
|
+
resolve40();
|
|
6034
6034
|
return;
|
|
6035
6035
|
}
|
|
6036
6036
|
const sock = conn.sock;
|
|
6037
6037
|
const handler = (update) => {
|
|
6038
6038
|
if (update.connection === "close") {
|
|
6039
6039
|
sock.ev.off("connection.update", handler);
|
|
6040
|
-
|
|
6040
|
+
resolve40();
|
|
6041
6041
|
}
|
|
6042
6042
|
};
|
|
6043
6043
|
sock.ev.on("connection.update", handler);
|
|
@@ -6511,8 +6511,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
6511
6511
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
6512
6512
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
6513
6513
|
let resolvePending;
|
|
6514
|
-
const sttPending = new Promise((
|
|
6515
|
-
resolvePending =
|
|
6514
|
+
const sttPending = new Promise((resolve40) => {
|
|
6515
|
+
resolvePending = resolve40;
|
|
6516
6516
|
});
|
|
6517
6517
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
6518
6518
|
try {
|
|
@@ -6901,20 +6901,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
6901
6901
|
|
|
6902
6902
|
// server/routes/health.ts
|
|
6903
6903
|
function checkPort(port2, timeoutMs = 500) {
|
|
6904
|
-
return new Promise((
|
|
6904
|
+
return new Promise((resolve40) => {
|
|
6905
6905
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
6906
6906
|
socket.setTimeout(timeoutMs);
|
|
6907
6907
|
socket.once("connect", () => {
|
|
6908
6908
|
socket.destroy();
|
|
6909
|
-
|
|
6909
|
+
resolve40(true);
|
|
6910
6910
|
});
|
|
6911
6911
|
socket.once("error", () => {
|
|
6912
6912
|
socket.destroy();
|
|
6913
|
-
|
|
6913
|
+
resolve40(false);
|
|
6914
6914
|
});
|
|
6915
6915
|
socket.once("timeout", () => {
|
|
6916
6916
|
socket.destroy();
|
|
6917
|
-
|
|
6917
|
+
resolve40(false);
|
|
6918
6918
|
});
|
|
6919
6919
|
});
|
|
6920
6920
|
}
|
|
@@ -8245,8 +8245,8 @@ async function startLogin(opts) {
|
|
|
8245
8245
|
await clearAuth(authDir);
|
|
8246
8246
|
let resolveCode = null;
|
|
8247
8247
|
let rejectCode = null;
|
|
8248
|
-
const codePromise = new Promise((
|
|
8249
|
-
resolveCode =
|
|
8248
|
+
const codePromise = new Promise((resolve40, reject) => {
|
|
8249
|
+
resolveCode = resolve40;
|
|
8250
8250
|
rejectCode = reject;
|
|
8251
8251
|
});
|
|
8252
8252
|
const codeTimer = setTimeout(
|
|
@@ -14681,15 +14681,15 @@ function operatorRoleFor(config, userId) {
|
|
|
14681
14681
|
async function buildAccountOptionList(accounts, userId) {
|
|
14682
14682
|
const houseAccount = accounts.find((a) => a.config.role === "house");
|
|
14683
14683
|
console.log(`[admin-accounts] op=list count=${accounts.length} house=${houseAccount?.accountId ?? "none"}`);
|
|
14684
|
-
const
|
|
14684
|
+
const resolve40 = async (a) => {
|
|
14685
14685
|
const businessName = await fetchAccountName(a.accountId) || void 0;
|
|
14686
14686
|
return { accountId: a.accountId, businessName, role: operatorRoleFor(a.config, userId), isHouse: a.config.role === "house" };
|
|
14687
14687
|
};
|
|
14688
14688
|
const houseOptions = await Promise.all(
|
|
14689
|
-
accounts.filter((a) => a.config.role === "house").map(
|
|
14689
|
+
accounts.filter((a) => a.config.role === "house").map(resolve40)
|
|
14690
14690
|
);
|
|
14691
14691
|
const nonHouseOptions = await Promise.all(
|
|
14692
|
-
accounts.filter((a) => a.config.role !== "house").map(
|
|
14692
|
+
accounts.filter((a) => a.config.role !== "house").map(resolve40)
|
|
14693
14693
|
);
|
|
14694
14694
|
const sortKey = (o) => (o.businessName || o.accountId).toLowerCase();
|
|
14695
14695
|
nonHouseOptions.sort((x, y) => {
|
|
@@ -19393,16 +19393,23 @@ function parseTableTopLevelLabels(referencesDir) {
|
|
|
19393
19393
|
}
|
|
19394
19394
|
return { labels, contributingFiles };
|
|
19395
19395
|
}
|
|
19396
|
+
var ADDITIONAL_BASE_LABELS = Object.freeze(
|
|
19397
|
+
/* @__PURE__ */ new Set(["Supplier"])
|
|
19398
|
+
);
|
|
19396
19399
|
var cached = null;
|
|
19397
19400
|
function getTopLevelLabelAllowlist(opts = {}) {
|
|
19398
19401
|
if (!opts.referencesDir && cached) return cached;
|
|
19399
19402
|
const referencesDir = opts.referencesDir ?? resolveReferencesDir();
|
|
19400
19403
|
const { labels: derived, contributingFiles } = parseTableTopLevelLabels(referencesDir);
|
|
19404
|
+
const excluded = [];
|
|
19405
|
+
for (const label of ADDITIONAL_BASE_LABELS) {
|
|
19406
|
+
if (derived.delete(label)) excluded.push(label);
|
|
19407
|
+
}
|
|
19401
19408
|
const derivedCount = derived.size;
|
|
19402
19409
|
for (const label of STATIC_TOP_LEVEL_LABELS) derived.add(label);
|
|
19403
19410
|
const result = Object.freeze(derived);
|
|
19404
19411
|
process.stderr.write(
|
|
19405
|
-
`[graph-page] op=top-level-labels source=ontology count=${derived.size} files=${contributingFiles.join("|") || "none"} derived=${derivedCount} static=${STATIC_TOP_LEVEL_LABELS.size}
|
|
19412
|
+
`[graph-page] op=top-level-labels source=ontology count=${derived.size} files=${contributingFiles.join("|") || "none"} derived=${derivedCount} static=${STATIC_TOP_LEVEL_LABELS.size} excluded=${excluded.join(",") || "none"}
|
|
19406
19413
|
`
|
|
19407
19414
|
);
|
|
19408
19415
|
if (!opts.referencesDir) cached = result;
|
|
@@ -24494,7 +24501,17 @@ app62.get("/free-busy", async (c) => {
|
|
|
24494
24501
|
if (Number.isNaN(Date.parse(from)) || Number.isNaN(Date.parse(to))) {
|
|
24495
24502
|
return c.json({ error: "from and to must be parseable ISO timestamps" }, 400);
|
|
24496
24503
|
}
|
|
24497
|
-
const
|
|
24504
|
+
const accountParam = c.req.query("account");
|
|
24505
|
+
let account;
|
|
24506
|
+
if (accountParam) {
|
|
24507
|
+
account = listValidAccounts().find((a) => a.accountId === accountParam) ?? null;
|
|
24508
|
+
if (!account) {
|
|
24509
|
+
console.error(`[calendar] op=free-busy-unknown-account account="${accountParam}"`);
|
|
24510
|
+
return c.json({ error: "Availability not configured" }, 404);
|
|
24511
|
+
}
|
|
24512
|
+
} else {
|
|
24513
|
+
account = resolveAccount();
|
|
24514
|
+
}
|
|
24498
24515
|
if (!account) return c.json({ error: "No account configured" }, 500);
|
|
24499
24516
|
let config;
|
|
24500
24517
|
try {
|
|
@@ -24546,6 +24563,8 @@ var ONT_END = "<!-- ontology-buckets:end -->";
|
|
|
24546
24563
|
var OWNED_START = "<!-- plugin-owned-dirs:start -->";
|
|
24547
24564
|
var OWNED_END = "<!-- plugin-owned-dirs:end -->";
|
|
24548
24565
|
var ALWAYS_EXPOSED = "output";
|
|
24566
|
+
var SYSTEM_DIRS = /* @__PURE__ */ new Set(["agents", "secrets", "specialists", "state", "memory", "cache", "logs", "tmp"]);
|
|
24567
|
+
var SAFE_FOLDER = /^[A-Za-z0-9_-]+$/;
|
|
24549
24568
|
var DOMAIN_LINE = /^- `([^`/]+)\/` - one folder per /;
|
|
24550
24569
|
var OWNED_LINE = /^- `([^`/]+)\/` — /;
|
|
24551
24570
|
function region(text, start, end) {
|
|
@@ -24565,7 +24584,7 @@ function allowedBlockOrNull(text) {
|
|
|
24565
24584
|
}
|
|
24566
24585
|
return null;
|
|
24567
24586
|
}
|
|
24568
|
-
function resolveExposedDirs(schemaText) {
|
|
24587
|
+
function resolveExposedDirs(schemaText, exposeFolders = []) {
|
|
24569
24588
|
const empty = {
|
|
24570
24589
|
schemaPresent: false,
|
|
24571
24590
|
allowed: (
|
|
@@ -24607,7 +24626,11 @@ function resolveExposedDirs(schemaText) {
|
|
|
24607
24626
|
const pluginOwned = dirsIn(owned, OWNED_LINE);
|
|
24608
24627
|
const collisions = domainBuckets.filter((d) => pluginOwned.includes(d));
|
|
24609
24628
|
const candidates = [ALWAYS_EXPOSED, ...domainBuckets.filter((d) => !collisions.includes(d))];
|
|
24610
|
-
const
|
|
24629
|
+
const ontologyExposed = [...new Set(candidates)].filter((d) => allowed.includes(d));
|
|
24630
|
+
const extras = (Array.isArray(exposeFolders) ? exposeFolders : []).filter(
|
|
24631
|
+
(f) => typeof f === "string" && SAFE_FOLDER.test(f) && !SYSTEM_DIRS.has(f)
|
|
24632
|
+
);
|
|
24633
|
+
const exposed = [.../* @__PURE__ */ new Set([...ontologyExposed, ...extras])].sort();
|
|
24611
24634
|
return { schemaPresent: true, allowed, domainBuckets, pluginOwned, collisions, exposed };
|
|
24612
24635
|
}
|
|
24613
24636
|
|
|
@@ -24656,6 +24679,14 @@ async function readAccountSecret(accountId) {
|
|
|
24656
24679
|
function isValidAccountId2(value) {
|
|
24657
24680
|
return /^[A-Za-z0-9-]+$/.test(value);
|
|
24658
24681
|
}
|
|
24682
|
+
async function readExposeFolders(accountDir) {
|
|
24683
|
+
try {
|
|
24684
|
+
const cfg = JSON.parse(await readFile6(join42(accountDir, "data-portal.json"), "utf8"));
|
|
24685
|
+
return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
24686
|
+
} catch {
|
|
24687
|
+
return [];
|
|
24688
|
+
}
|
|
24689
|
+
}
|
|
24659
24690
|
async function resolveFetchTarget(accountDir, relPath) {
|
|
24660
24691
|
let schemaText = null;
|
|
24661
24692
|
try {
|
|
@@ -24663,7 +24694,8 @@ async function resolveFetchTarget(accountDir, relPath) {
|
|
|
24663
24694
|
} catch {
|
|
24664
24695
|
schemaText = null;
|
|
24665
24696
|
}
|
|
24666
|
-
const
|
|
24697
|
+
const exposeFolders = await readExposeFolders(accountDir);
|
|
24698
|
+
const { exposed } = resolveExposedDirs(schemaText, exposeFolders);
|
|
24667
24699
|
if (exposed.length === 0) return { ok: false, reason: "not-exposed" };
|
|
24668
24700
|
const lexical = resolve32(accountDir, relPath);
|
|
24669
24701
|
let root;
|
|
@@ -26484,16 +26516,16 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
26484
26516
|
* The public /api/chat route awaits this to return the reply on the same SSE
|
|
26485
26517
|
* response, preserving the pre-756 POST→single-blob browser contract. */
|
|
26486
26518
|
awaitReply(key, timeoutMs) {
|
|
26487
|
-
return new Promise((
|
|
26519
|
+
return new Promise((resolve40) => {
|
|
26488
26520
|
const timer = setTimeout(() => {
|
|
26489
26521
|
this.replyAwaiters.delete(key);
|
|
26490
|
-
|
|
26522
|
+
resolve40({ timeout: true });
|
|
26491
26523
|
}, timeoutMs);
|
|
26492
26524
|
if (timer.unref) timer.unref();
|
|
26493
26525
|
this.replyAwaiters.set(key, (r) => {
|
|
26494
26526
|
clearTimeout(timer);
|
|
26495
26527
|
this.replyAwaiters.delete(key);
|
|
26496
|
-
|
|
26528
|
+
resolve40(r);
|
|
26497
26529
|
});
|
|
26498
26530
|
});
|
|
26499
26531
|
}
|
|
@@ -26504,11 +26536,11 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
26504
26536
|
* terminal dialog stays answerable). */
|
|
26505
26537
|
awaitPermissionVerdict(p, timeoutMs) {
|
|
26506
26538
|
const k = _WebchatGateway.promptKey(p.key, p.requestId);
|
|
26507
|
-
return new Promise((
|
|
26539
|
+
return new Promise((resolve40) => {
|
|
26508
26540
|
this.pendingPrompts.get(k)?.resolve({ timeout: true });
|
|
26509
26541
|
const timer = setTimeout(() => {
|
|
26510
26542
|
this.pendingPrompts.delete(k);
|
|
26511
|
-
|
|
26543
|
+
resolve40({ timeout: true });
|
|
26512
26544
|
}, timeoutMs);
|
|
26513
26545
|
if (timer.unref) timer.unref();
|
|
26514
26546
|
this.pendingPrompts.set(k, {
|
|
@@ -26517,7 +26549,7 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
26517
26549
|
resolve: (r) => {
|
|
26518
26550
|
clearTimeout(timer);
|
|
26519
26551
|
this.pendingPrompts.delete(k);
|
|
26520
|
-
|
|
26552
|
+
resolve40(r);
|
|
26521
26553
|
}
|
|
26522
26554
|
});
|
|
26523
26555
|
console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
|
|
@@ -28141,6 +28173,22 @@ function warnOnChannelAdminBindingDrift() {
|
|
|
28141
28173
|
}
|
|
28142
28174
|
}
|
|
28143
28175
|
|
|
28176
|
+
// server/lib/booking-site-accounts.ts
|
|
28177
|
+
import { existsSync as existsSync37, readFileSync as readFileSync41 } from "fs";
|
|
28178
|
+
import { resolve as resolve37 } from "path";
|
|
28179
|
+
function listBookingSiteAccounts(accounts) {
|
|
28180
|
+
return accounts.filter((a) => {
|
|
28181
|
+
const availPath = resolve37(a.accountDir, "calendar-availability.json");
|
|
28182
|
+
if (!existsSync37(availPath)) return false;
|
|
28183
|
+
try {
|
|
28184
|
+
const cfg = JSON.parse(readFileSync41(availPath, "utf-8"));
|
|
28185
|
+
return typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
28186
|
+
} catch {
|
|
28187
|
+
return false;
|
|
28188
|
+
}
|
|
28189
|
+
});
|
|
28190
|
+
}
|
|
28191
|
+
|
|
28144
28192
|
// app/lib/admin-sse-registry.ts
|
|
28145
28193
|
var activeAdminSSEControllers = /* @__PURE__ */ new Set();
|
|
28146
28194
|
function broadcastAdminShutdown(reason) {
|
|
@@ -28171,8 +28219,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
28171
28219
|
|
|
28172
28220
|
// ../lib/entitlement/src/index.ts
|
|
28173
28221
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
28174
|
-
import { existsSync as
|
|
28175
|
-
import { resolve as
|
|
28222
|
+
import { existsSync as existsSync38, readFileSync as readFileSync42, statSync as statSync16 } from "fs";
|
|
28223
|
+
import { resolve as resolve38 } from "path";
|
|
28176
28224
|
|
|
28177
28225
|
// ../lib/entitlement/src/canonicalize.ts
|
|
28178
28226
|
function canonicalize(value) {
|
|
@@ -28207,7 +28255,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
28207
28255
|
var GRACE_DAYS = 7;
|
|
28208
28256
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
28209
28257
|
function pubkeyPath(brand) {
|
|
28210
|
-
return
|
|
28258
|
+
return resolve38(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
28211
28259
|
}
|
|
28212
28260
|
var memo = null;
|
|
28213
28261
|
function memoKey(mtimeMs, account) {
|
|
@@ -28219,8 +28267,8 @@ function resolveEntitlement(brand, account) {
|
|
|
28219
28267
|
if (brand.commercialMode !== true) {
|
|
28220
28268
|
return logResolved(implicitTrust(account), null);
|
|
28221
28269
|
}
|
|
28222
|
-
const entitlementPath =
|
|
28223
|
-
if (!
|
|
28270
|
+
const entitlementPath = resolve38(brand.configDir, "entitlement.json");
|
|
28271
|
+
if (!existsSync38(entitlementPath)) {
|
|
28224
28272
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
28225
28273
|
}
|
|
28226
28274
|
const stat9 = statSync16(entitlementPath);
|
|
@@ -28235,7 +28283,7 @@ function resolveEntitlement(brand, account) {
|
|
|
28235
28283
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
28236
28284
|
let pubkeyPem;
|
|
28237
28285
|
try {
|
|
28238
|
-
pubkeyPem =
|
|
28286
|
+
pubkeyPem = readFileSync42(pubkeyPath(brand), "utf-8");
|
|
28239
28287
|
} catch (err) {
|
|
28240
28288
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
28241
28289
|
reason: "pubkey-missing"
|
|
@@ -28249,7 +28297,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
28249
28297
|
}
|
|
28250
28298
|
let envelope;
|
|
28251
28299
|
try {
|
|
28252
|
-
envelope = JSON.parse(
|
|
28300
|
+
envelope = JSON.parse(readFileSync42(entitlementPath, "utf-8"));
|
|
28253
28301
|
} catch {
|
|
28254
28302
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
28255
28303
|
}
|
|
@@ -28413,12 +28461,12 @@ installMediaDownloadGuard();
|
|
|
28413
28461
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
28414
28462
|
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join45(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
28415
28463
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
28416
|
-
if (BRAND_JSON_PATH && !
|
|
28464
|
+
if (BRAND_JSON_PATH && !existsSync39(BRAND_JSON_PATH)) {
|
|
28417
28465
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
28418
28466
|
}
|
|
28419
|
-
if (BRAND_JSON_PATH &&
|
|
28467
|
+
if (BRAND_JSON_PATH && existsSync39(BRAND_JSON_PATH)) {
|
|
28420
28468
|
try {
|
|
28421
|
-
const parsed = JSON.parse(
|
|
28469
|
+
const parsed = JSON.parse(readFileSync43(BRAND_JSON_PATH, "utf-8"));
|
|
28422
28470
|
BRAND = { ...BRAND, ...parsed };
|
|
28423
28471
|
} catch (err) {
|
|
28424
28472
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -28453,8 +28501,8 @@ var brandLoginOpts = {
|
|
|
28453
28501
|
var ALIAS_DOMAINS_PATH = join45(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
28454
28502
|
function loadAliasDomains() {
|
|
28455
28503
|
try {
|
|
28456
|
-
if (!
|
|
28457
|
-
const parsed = JSON.parse(
|
|
28504
|
+
if (!existsSync39(ALIAS_DOMAINS_PATH)) return null;
|
|
28505
|
+
const parsed = JSON.parse(readFileSync43(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
28458
28506
|
if (!Array.isArray(parsed)) {
|
|
28459
28507
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
28460
28508
|
return null;
|
|
@@ -28527,7 +28575,7 @@ var waGateway = new WaGateway({
|
|
|
28527
28575
|
fetchStandingRules: fetchAccountStandingRules,
|
|
28528
28576
|
resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
|
|
28529
28577
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
28530
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
28578
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve39(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
28531
28579
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
28532
28580
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
28533
28581
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -28542,7 +28590,7 @@ var waGateway = new WaGateway({
|
|
|
28542
28590
|
caption,
|
|
28543
28591
|
accountId,
|
|
28544
28592
|
maxyAccountId,
|
|
28545
|
-
platformRoot:
|
|
28593
|
+
platformRoot: resolve39(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, ".."))
|
|
28546
28594
|
});
|
|
28547
28595
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
28548
28596
|
},
|
|
@@ -29218,20 +29266,20 @@ app64.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
29218
29266
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
29219
29267
|
return c.text("Not found", 404);
|
|
29220
29268
|
}
|
|
29221
|
-
const filePath =
|
|
29222
|
-
const expectedDir =
|
|
29269
|
+
const filePath = resolve39(account.accountDir, "agents", slug, "assets", filename);
|
|
29270
|
+
const expectedDir = resolve39(account.accountDir, "agents", slug, "assets");
|
|
29223
29271
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
29224
29272
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
29225
29273
|
return c.text("Forbidden", 403);
|
|
29226
29274
|
}
|
|
29227
|
-
if (!
|
|
29275
|
+
if (!existsSync39(filePath)) {
|
|
29228
29276
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
29229
29277
|
return c.text("Not found", 404);
|
|
29230
29278
|
}
|
|
29231
29279
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
29232
29280
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
29233
29281
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
29234
|
-
const body =
|
|
29282
|
+
const body = readFileSync43(filePath);
|
|
29235
29283
|
return c.body(body, 200, {
|
|
29236
29284
|
"Content-Type": contentType,
|
|
29237
29285
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -29248,20 +29296,20 @@ app64.get("/generated/:filename", (c) => {
|
|
|
29248
29296
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
29249
29297
|
return c.text("Not found", 404);
|
|
29250
29298
|
}
|
|
29251
|
-
const filePath =
|
|
29252
|
-
const expectedDir =
|
|
29299
|
+
const filePath = resolve39(account.accountDir, "generated", filename);
|
|
29300
|
+
const expectedDir = resolve39(account.accountDir, "generated");
|
|
29253
29301
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
29254
29302
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
29255
29303
|
return c.text("Forbidden", 403);
|
|
29256
29304
|
}
|
|
29257
|
-
if (!
|
|
29305
|
+
if (!existsSync39(filePath)) {
|
|
29258
29306
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
29259
29307
|
return c.text("Not found", 404);
|
|
29260
29308
|
}
|
|
29261
29309
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
29262
29310
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
29263
29311
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
29264
|
-
const body =
|
|
29312
|
+
const body = readFileSync43(filePath);
|
|
29265
29313
|
return c.body(body, 200, {
|
|
29266
29314
|
"Content-Type": contentType,
|
|
29267
29315
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -29274,9 +29322,9 @@ app64.route("/v", visitor_consent_default);
|
|
|
29274
29322
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
29275
29323
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
29276
29324
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
29277
|
-
if (BRAND_JSON_PATH &&
|
|
29325
|
+
if (BRAND_JSON_PATH && existsSync39(BRAND_JSON_PATH)) {
|
|
29278
29326
|
try {
|
|
29279
|
-
const fullBrand = JSON.parse(
|
|
29327
|
+
const fullBrand = JSON.parse(readFileSync43(BRAND_JSON_PATH, "utf-8"));
|
|
29280
29328
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
29281
29329
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
29282
29330
|
} catch {
|
|
@@ -29303,11 +29351,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
29303
29351
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
29304
29352
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
29305
29353
|
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
29306
|
-
(p) =>
|
|
29354
|
+
(p) => existsSync39(resolve39(process.cwd(), "public", p.replace(/^\//, "")))
|
|
29307
29355
|
);
|
|
29308
29356
|
var SW_SOURCE = (() => {
|
|
29309
29357
|
try {
|
|
29310
|
-
return
|
|
29358
|
+
return readFileSync43(resolve39(process.cwd(), "public", "sw.js"), "utf-8");
|
|
29311
29359
|
} catch {
|
|
29312
29360
|
return null;
|
|
29313
29361
|
}
|
|
@@ -29316,8 +29364,8 @@ function readInstalledVersion() {
|
|
|
29316
29364
|
try {
|
|
29317
29365
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
29318
29366
|
const versionFile = join45(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
29319
|
-
if (!
|
|
29320
|
-
const content =
|
|
29367
|
+
if (!existsSync39(versionFile)) return "unknown";
|
|
29368
|
+
const content = readFileSync43(versionFile, "utf-8").trim();
|
|
29321
29369
|
return content || "unknown";
|
|
29322
29370
|
} catch {
|
|
29323
29371
|
return "unknown";
|
|
@@ -29358,7 +29406,7 @@ var clientErrorReporterScript = `<script>
|
|
|
29358
29406
|
function cachedHtml(file) {
|
|
29359
29407
|
let html = htmlCache.get(file);
|
|
29360
29408
|
if (!html) {
|
|
29361
|
-
html =
|
|
29409
|
+
html = readFileSync43(resolve39(process.cwd(), "public", file), "utf-8");
|
|
29362
29410
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
29363
29411
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
29364
29412
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -29380,8 +29428,8 @@ function loadBrandingCache(agentSlug) {
|
|
|
29380
29428
|
const accountId = getDefaultAccountId();
|
|
29381
29429
|
if (!accountId) return null;
|
|
29382
29430
|
const cachePath = join45(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
29383
|
-
if (!
|
|
29384
|
-
return JSON.parse(
|
|
29431
|
+
if (!existsSync39(cachePath)) return null;
|
|
29432
|
+
return JSON.parse(readFileSync43(cachePath, "utf-8"));
|
|
29385
29433
|
} catch {
|
|
29386
29434
|
return null;
|
|
29387
29435
|
}
|
|
@@ -29476,7 +29524,7 @@ app64.use("/vnc-popout.html", logViewerFetch);
|
|
|
29476
29524
|
app64.get("/vnc-popout.html", (c) => {
|
|
29477
29525
|
let html = htmlCache.get("vnc-popout.html");
|
|
29478
29526
|
if (!html) {
|
|
29479
|
-
html =
|
|
29527
|
+
html = readFileSync43(resolve39(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
29480
29528
|
const name = escapeHtml(BRAND.productName);
|
|
29481
29529
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
29482
29530
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -29614,10 +29662,10 @@ var httpServer = serve({ fetch: app64.fetch, port, hostname });
|
|
|
29614
29662
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
29615
29663
|
{
|
|
29616
29664
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
|
|
29617
|
-
const reconcileScript =
|
|
29665
|
+
const reconcileScript = resolve39(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
29618
29666
|
const RECONCILE_INTERVAL_MS = 12e4;
|
|
29619
29667
|
const runReconcile = (ctx) => {
|
|
29620
|
-
if (!
|
|
29668
|
+
if (!existsSync39(reconcileScript)) return;
|
|
29621
29669
|
try {
|
|
29622
29670
|
const child = spawn3(process.execPath, [reconcileScript], {
|
|
29623
29671
|
env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
|
|
@@ -29640,10 +29688,10 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29640
29688
|
}
|
|
29641
29689
|
{
|
|
29642
29690
|
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
|
|
29643
|
-
const outlookScript =
|
|
29691
|
+
const outlookScript = resolve39(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
29644
29692
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
29645
29693
|
const runOutlookComplete = (ctx) => {
|
|
29646
|
-
if (!
|
|
29694
|
+
if (!existsSync39(outlookScript)) return;
|
|
29647
29695
|
try {
|
|
29648
29696
|
const child = spawn3(process.execPath, [outlookScript], {
|
|
29649
29697
|
env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
|
|
@@ -29666,18 +29714,18 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29666
29714
|
}
|
|
29667
29715
|
{
|
|
29668
29716
|
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
|
|
29669
|
-
const strandedAccountsDir =
|
|
29717
|
+
const strandedAccountsDir = resolve39(auditRoot, "..", "data/accounts");
|
|
29670
29718
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
29671
29719
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
29672
29720
|
const STRANDED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
29673
29721
|
const runStrandedAudit = () => {
|
|
29674
29722
|
try {
|
|
29675
|
-
if (!
|
|
29723
|
+
if (!existsSync39(strandedAccountsDir)) return;
|
|
29676
29724
|
const now = Date.now();
|
|
29677
29725
|
for (const name of readdirSync26(strandedAccountsDir)) {
|
|
29678
29726
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
29679
|
-
const pendingPath2 =
|
|
29680
|
-
if (!
|
|
29727
|
+
const pendingPath2 = resolve39(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
29728
|
+
if (!existsSync39(pendingPath2)) continue;
|
|
29681
29729
|
const ageMs = now - statSync17(pendingPath2).mtimeMs;
|
|
29682
29730
|
if (ageMs > STRANDED_AGE_MS) {
|
|
29683
29731
|
console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs / 1e3)}`);
|
|
@@ -29696,7 +29744,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29696
29744
|
}
|
|
29697
29745
|
{
|
|
29698
29746
|
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
|
|
29699
|
-
const googleAccountsDir =
|
|
29747
|
+
const googleAccountsDir = resolve39(googleRoot, "..", "data/accounts");
|
|
29700
29748
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
29701
29749
|
const runGooglePendingAuditSafe = () => {
|
|
29702
29750
|
try {
|
|
@@ -29711,10 +29759,10 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29711
29759
|
firstRunDelayMs: 27e3,
|
|
29712
29760
|
run: runGooglePendingAuditSafe
|
|
29713
29761
|
});
|
|
29714
|
-
const googleAuditScript =
|
|
29762
|
+
const googleAuditScript = resolve39(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
|
|
29715
29763
|
const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
|
|
29716
29764
|
const runGoogleAccountAudit = (ctx) => {
|
|
29717
|
-
if (!
|
|
29765
|
+
if (!existsSync39(googleAuditScript)) return;
|
|
29718
29766
|
try {
|
|
29719
29767
|
const child = spawn3(process.execPath, [googleAuditScript], {
|
|
29720
29768
|
env: { ...process.env, PLATFORM_ROOT: googleRoot },
|
|
@@ -29774,18 +29822,18 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29774
29822
|
}
|
|
29775
29823
|
{
|
|
29776
29824
|
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
|
|
29777
|
-
const publishScript =
|
|
29825
|
+
const publishScript = resolve39(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
29778
29826
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
29779
|
-
const
|
|
29827
|
+
const bookingAccounts = () => {
|
|
29780
29828
|
try {
|
|
29781
|
-
return
|
|
29829
|
+
return listBookingSiteAccounts(listValidAccounts());
|
|
29782
29830
|
} catch (err) {
|
|
29783
|
-
console.error(`[calendar-availability] op=publish result=error reason=
|
|
29784
|
-
return
|
|
29831
|
+
console.error(`[calendar-availability] op=publish result=error reason=enumerate-failed err="${err.message}"`);
|
|
29832
|
+
return [];
|
|
29785
29833
|
}
|
|
29786
29834
|
};
|
|
29787
29835
|
const spawnPublish = (account, ctx) => {
|
|
29788
|
-
if (!
|
|
29836
|
+
if (!existsSync39(publishScript)) return;
|
|
29789
29837
|
try {
|
|
29790
29838
|
const child = spawn3(process.execPath, [publishScript], {
|
|
29791
29839
|
env: {
|
|
@@ -29804,21 +29852,21 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29804
29852
|
}
|
|
29805
29853
|
};
|
|
29806
29854
|
const auditSnapshotAge = (account) => {
|
|
29807
|
-
const availPath =
|
|
29855
|
+
const availPath = resolve39(account.accountDir, "calendar-availability.json");
|
|
29808
29856
|
let hasBookingSite = false;
|
|
29809
29857
|
try {
|
|
29810
|
-
if (
|
|
29811
|
-
const cfg = JSON.parse(
|
|
29858
|
+
if (existsSync39(availPath)) {
|
|
29859
|
+
const cfg = JSON.parse(readFileSync43(availPath, "utf-8"));
|
|
29812
29860
|
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
29813
29861
|
}
|
|
29814
29862
|
} catch {
|
|
29815
29863
|
}
|
|
29816
29864
|
if (!hasBookingSite) return;
|
|
29817
|
-
const statePath =
|
|
29865
|
+
const statePath = resolve39(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
29818
29866
|
let lastSuccessAt = null;
|
|
29819
|
-
if (
|
|
29867
|
+
if (existsSync39(statePath)) {
|
|
29820
29868
|
try {
|
|
29821
|
-
const rec = JSON.parse(
|
|
29869
|
+
const rec = JSON.parse(readFileSync43(statePath, "utf-8"));
|
|
29822
29870
|
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
29823
29871
|
} catch {
|
|
29824
29872
|
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
|
|
@@ -29830,10 +29878,14 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
29830
29878
|
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=${ageMs ?? "na"}`);
|
|
29831
29879
|
};
|
|
29832
29880
|
const publishTick = (ctx) => {
|
|
29833
|
-
const account
|
|
29834
|
-
|
|
29835
|
-
|
|
29836
|
-
|
|
29881
|
+
for (const account of bookingAccounts()) {
|
|
29882
|
+
try {
|
|
29883
|
+
spawnPublish(account, ctx);
|
|
29884
|
+
auditSnapshotAge(account);
|
|
29885
|
+
} catch (err) {
|
|
29886
|
+
console.error(`[calendar-availability] op=publish accountId=${account.accountId} result=error reason=tick-failed err="${err.message}"`);
|
|
29887
|
+
}
|
|
29888
|
+
}
|
|
29837
29889
|
};
|
|
29838
29890
|
registerLoop({
|
|
29839
29891
|
name: "calendar-availability-publish",
|
|
@@ -29847,11 +29899,11 @@ startTimeEntryCensus(() => getSession());
|
|
|
29847
29899
|
startLedgerCensus(() => getSession());
|
|
29848
29900
|
{
|
|
29849
29901
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..");
|
|
29850
|
-
const auditScript =
|
|
29902
|
+
const auditScript = resolve39(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
29851
29903
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
29852
29904
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
29853
29905
|
const runConnectorAudit = (ctx) => {
|
|
29854
|
-
if (!
|
|
29906
|
+
if (!existsSync39(auditScript)) return;
|
|
29855
29907
|
try {
|
|
29856
29908
|
const child = spawn3(process.execPath, [auditScript], {
|
|
29857
29909
|
env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
|
|
@@ -29971,11 +30023,11 @@ try {
|
|
|
29971
30023
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
29972
30024
|
async function runAdminUserReconcileTick() {
|
|
29973
30025
|
try {
|
|
29974
|
-
if (!
|
|
30026
|
+
if (!existsSync39(USERS_FILE)) {
|
|
29975
30027
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
29976
30028
|
return;
|
|
29977
30029
|
}
|
|
29978
|
-
const usersRaw =
|
|
30030
|
+
const usersRaw = readFileSync43(USERS_FILE, "utf-8").trim();
|
|
29979
30031
|
if (!usersRaw) {
|
|
29980
30032
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
29981
30033
|
return;
|
|
@@ -30022,8 +30074,8 @@ registerLoop({
|
|
|
30022
30074
|
});
|
|
30023
30075
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
30024
30076
|
function countUsersRows() {
|
|
30025
|
-
if (!
|
|
30026
|
-
const raw =
|
|
30077
|
+
if (!existsSync39(USERS_FILE)) return 0;
|
|
30078
|
+
const raw = readFileSync43(USERS_FILE, "utf-8").trim();
|
|
30027
30079
|
if (!raw) return 0;
|
|
30028
30080
|
const users = JSON.parse(raw);
|
|
30029
30081
|
return users.filter((u) => typeof u.userId === "string").length;
|
|
@@ -30156,7 +30208,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
30156
30208
|
}
|
|
30157
30209
|
init({
|
|
30158
30210
|
configDir: configDirForWhatsApp,
|
|
30159
|
-
platformRoot:
|
|
30211
|
+
platformRoot: resolve39(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, "..")),
|
|
30160
30212
|
accountConfig: bootAccountConfig,
|
|
30161
30213
|
onMessage: async (msg) => {
|
|
30162
30214
|
if (isObserveAccount(msg.accountId)) {
|