@rubytech/create-maxy-code 0.1.441 → 0.1.443
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/converge-client-admins.test.js +50 -0
- package/dist/converge-client-admins.js +67 -0
- package/dist/index.js +107 -1
- package/package.json +1 -1
- package/payload/platform/docs/superpowers/plans/2026-07-13-account-schema-ontology-projection.md +547 -0
- package/payload/platform/docs/superpowers/plans/2026-07-14-graph-top-level-labels-ontology-single-source.md +458 -0
- package/payload/platform/docs/superpowers/specs/2026-07-13-account-schema-ontology-projection-design.md +178 -0
- package/payload/platform/docs/superpowers/specs/2026-07-14-graph-top-level-labels-ontology-single-source-design.md +119 -0
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +7 -1
- package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh +19 -2
- package/payload/platform/plugins/admin/mcp/dist/index.js +126 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +30 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +78 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +37 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +35 -0
- package/payload/platform/plugins/memory/PLUGIN.md +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js +12 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts +9 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js +19 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js.map +1 -1
- package/payload/platform/plugins/memory/references/schema-estate-agent.md +8 -3
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js +37 -4
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts +27 -3
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js +52 -11
- package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts +5 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js +32 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +20 -22
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +3 -1
- package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +58 -0
- package/payload/platform/scripts/__tests__/provision-role-stamp.test.sh +6 -0
- package/payload/platform/scripts/lib/account-schema-owned-dirs.py +143 -10
- package/payload/platform/scripts/lib/provision-account-dir.sh +5 -0
- package/payload/platform/scripts/logs-read.sh +24 -6
- package/payload/platform/scripts/logs-read.test.sh +42 -0
- package/payload/platform/scripts/name-glsmith-owner.sh +239 -0
- package/payload/platform/scripts/rss-sampler.sh +107 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-CukwQufW.js → AdminLoginScreens-BJVwtpLH.js} +1 -1
- package/payload/server/public/assets/{AdminShell-BwEBH6tT.js → AdminShell-CMu8_Xwn.js} +1 -1
- package/payload/server/public/assets/{Checkbox-B629mOPp.js → Checkbox-CzD0ORqA.js} +1 -1
- package/payload/server/public/assets/{admin-CdFRCUUZ.js → admin-D0yk2LMq.js} +1 -1
- package/payload/server/public/assets/{browser-BWR59IkB.js → browser-CvfbgznO.js} +1 -1
- package/payload/server/public/assets/{calendar-kuTcxX1t.js → calendar-fw4WethJ.js} +1 -1
- package/payload/server/public/assets/chat-DhD-NES_.js +1 -0
- package/payload/server/public/assets/chevron-left-B3xSeEDR.js +1 -0
- package/payload/server/public/assets/data-CUnDzDox.js +1 -0
- package/payload/server/public/assets/{file-download-4mKJxUi-.js → file-download-Px4s0Bhp.js} +1 -1
- package/payload/server/public/assets/{graph-CboWM2_-.js → graph-DbT8nA6R.js} +1 -1
- package/payload/server/public/assets/{graph-labels-B8YAdo3Z.js → graph-labels-C1YIyLiA.js} +1 -1
- package/payload/server/public/assets/{maximize-2-CxstTgoK.js → maximize-2-BwphzI9S.js} +1 -1
- package/payload/server/public/assets/{operator-oSaB1mya.js → operator-zcIfeB14.js} +1 -1
- package/payload/server/public/assets/{page-DMeJHVfA.js → page-6fCnIb45.js} +2 -2
- package/payload/server/public/assets/page-CfQFAJia.js +1 -0
- package/payload/server/public/assets/{public-C54tl6V4.js → public-C0ehZCdE.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-COGQTi7n.js → rotate-ccw-C7BqkMec.js} +1 -1
- package/payload/server/public/assets/{tasks-B97VpwEJ.js → tasks-DlgiCafL.js} +1 -1
- package/payload/server/public/assets/{time-entry-format-C09rDHo9.js → time-entry-format-CyNYVDkq.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-DHoYHiK9.js → useCopyFeedback-ByGUMN94.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-1izQvPiD.css +1 -0
- package/payload/server/public/assets/useVoiceRecorder-XgpWvXpk.js +2 -0
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +6 -6
- package/payload/server/public/chat.html +12 -12
- package/payload/server/public/data.html +10 -10
- package/payload/server/public/graph.html +11 -11
- package/payload/server/public/index.html +13 -13
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +12 -12
- package/payload/server/public/tasks.html +5 -5
- package/payload/server/server.js +742 -321
- package/payload/platform/plugins/memory/references/schema-trades.md +0 -34
- package/payload/server/public/assets/chat-ejnq2rck.js +0 -1
- package/payload/server/public/assets/chevron-left-u4tjq7fI.js +0 -1
- package/payload/server/public/assets/data-dZbOyLdT.js +0 -1
- package/payload/server/public/assets/page-DEkI-Gl1.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-Dzmd7Aip.css +0 -1
- package/payload/server/public/assets/useVoiceRecorder-b7HzTFs0.js +0 -2
- /package/payload/server/public/assets/{useSubAccountSwitcher-DLJFISqf.js → useSubAccountSwitcher-s6WlRn52.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -1413,10 +1413,10 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1413
1413
|
};
|
|
1414
1414
|
|
|
1415
1415
|
// server/index.ts
|
|
1416
|
-
import { readFileSync as
|
|
1416
|
+
import { readFileSync as readFileSync37, existsSync as existsSync35, watchFile } from "fs";
|
|
1417
1417
|
import { spawn as spawn3 } from "child_process";
|
|
1418
1418
|
import { createHash as createHash7 } from "crypto";
|
|
1419
|
-
import { resolve as
|
|
1419
|
+
import { resolve as resolve34, join as join37, basename as basename12 } from "path";
|
|
1420
1420
|
import { homedir as homedir4 } from "os";
|
|
1421
1421
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1422
1422
|
|
|
@@ -1793,7 +1793,7 @@ async function ensureAuth() {
|
|
|
1793
1793
|
}
|
|
1794
1794
|
|
|
1795
1795
|
// server/routes/health.ts
|
|
1796
|
-
import { existsSync as existsSync5, readFileSync as
|
|
1796
|
+
import { existsSync as existsSync5, readFileSync as readFileSync10 } from "fs";
|
|
1797
1797
|
import { createConnection as createConnection2 } from "net";
|
|
1798
1798
|
|
|
1799
1799
|
// app/lib/network.ts
|
|
@@ -2129,7 +2129,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
2129
2129
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
2130
2130
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
2131
2131
|
const timer2 = new Promise(
|
|
2132
|
-
(
|
|
2132
|
+
(resolve35) => setTimeout(() => resolve35("timeout"), timeoutMs)
|
|
2133
2133
|
);
|
|
2134
2134
|
const result = await Promise.race([
|
|
2135
2135
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -2292,11 +2292,11 @@ async function createWaSocket(opts) {
|
|
|
2292
2292
|
return sock;
|
|
2293
2293
|
}
|
|
2294
2294
|
async function waitForConnection(sock) {
|
|
2295
|
-
return new Promise((
|
|
2295
|
+
return new Promise((resolve35, reject) => {
|
|
2296
2296
|
const handler = (update) => {
|
|
2297
2297
|
if (update.connection === "open") {
|
|
2298
2298
|
sock.ev.off("connection.update", handler);
|
|
2299
|
-
|
|
2299
|
+
resolve35();
|
|
2300
2300
|
}
|
|
2301
2301
|
if (update.connection === "close") {
|
|
2302
2302
|
sock.ev.off("connection.update", handler);
|
|
@@ -2401,7 +2401,7 @@ import { inspect as inspect2 } from "util";
|
|
|
2401
2401
|
|
|
2402
2402
|
// app/lib/whatsapp/with-timeout.ts
|
|
2403
2403
|
function withTimeout(label, promise, timeoutMs) {
|
|
2404
|
-
return new Promise((
|
|
2404
|
+
return new Promise((resolve35, reject) => {
|
|
2405
2405
|
const timer2 = setTimeout(() => {
|
|
2406
2406
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2407
2407
|
}, timeoutMs);
|
|
@@ -2409,7 +2409,7 @@ function withTimeout(label, promise, timeoutMs) {
|
|
|
2409
2409
|
promise.then(
|
|
2410
2410
|
(value) => {
|
|
2411
2411
|
clearTimeout(timer2);
|
|
2412
|
-
|
|
2412
|
+
resolve35(value);
|
|
2413
2413
|
},
|
|
2414
2414
|
(err) => {
|
|
2415
2415
|
clearTimeout(timer2);
|
|
@@ -3489,10 +3489,10 @@ function readConversationSummaries(platformAccountId) {
|
|
|
3489
3489
|
} catch {
|
|
3490
3490
|
continue;
|
|
3491
3491
|
}
|
|
3492
|
-
const
|
|
3493
|
-
if (
|
|
3492
|
+
const cached3 = summaryCache.get(file);
|
|
3493
|
+
if (cached3 && cached3.size === size && cached3.mtimeMs === mtimeMs) {
|
|
3494
3494
|
cacheHits++;
|
|
3495
|
-
out.set(remoteJid,
|
|
3495
|
+
out.set(remoteJid, cached3.summary);
|
|
3496
3496
|
continue;
|
|
3497
3497
|
}
|
|
3498
3498
|
let summary;
|
|
@@ -3556,8 +3556,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
3556
3556
|
const { givenName, familyName } = splitName(input.pushName);
|
|
3557
3557
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
3558
3558
|
let release;
|
|
3559
|
-
const mine = new Promise((
|
|
3560
|
-
release =
|
|
3559
|
+
const mine = new Promise((resolve35) => {
|
|
3560
|
+
release = resolve35;
|
|
3561
3561
|
});
|
|
3562
3562
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
3563
3563
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -3700,8 +3700,8 @@ import { resolve as resolve3 } from "path";
|
|
|
3700
3700
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3701
3701
|
var cache = /* @__PURE__ */ new Map();
|
|
3702
3702
|
function enumerateValidAccountIds(accountsDir) {
|
|
3703
|
-
const
|
|
3704
|
-
if (
|
|
3703
|
+
const cached3 = cache.get(accountsDir);
|
|
3704
|
+
if (cached3 !== void 0) return cached3;
|
|
3705
3705
|
let names;
|
|
3706
3706
|
try {
|
|
3707
3707
|
names = readdirSync2(accountsDir);
|
|
@@ -3843,7 +3843,7 @@ import {
|
|
|
3843
3843
|
// app/lib/attachments.ts
|
|
3844
3844
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3845
3845
|
import { mkdir, writeFile } from "fs/promises";
|
|
3846
|
-
import { realpathSync as realpathSync2, existsSync as existsSync4 } from "fs";
|
|
3846
|
+
import { realpathSync as realpathSync2, existsSync as existsSync4, readFileSync as readFileSync8, readdirSync as readdirSync3 } from "fs";
|
|
3847
3847
|
import { resolve as resolve6, extname } from "path";
|
|
3848
3848
|
|
|
3849
3849
|
// app/lib/data-path.ts
|
|
@@ -3926,11 +3926,15 @@ function resolveScratchpadPath(raw, scratchpadRootAbs) {
|
|
|
3926
3926
|
import { unzipSync, strFromU8 } from "fflate";
|
|
3927
3927
|
var DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
3928
3928
|
var ODT = "application/vnd.oasis.opendocument.text";
|
|
3929
|
+
var XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
3930
|
+
var ODS = "application/vnd.oasis.opendocument.spreadsheet";
|
|
3929
3931
|
var CONVERTIBLE_DOC_MIME = /* @__PURE__ */ new Set([
|
|
3930
3932
|
DOCX,
|
|
3931
3933
|
ODT,
|
|
3932
3934
|
"text/rtf",
|
|
3933
|
-
"application/rtf"
|
|
3935
|
+
"application/rtf",
|
|
3936
|
+
XLSX,
|
|
3937
|
+
ODS
|
|
3934
3938
|
]);
|
|
3935
3939
|
function bareMime(mimeType) {
|
|
3936
3940
|
return mimeType.split(";")[0].trim().toLowerCase();
|
|
@@ -3964,6 +3968,80 @@ function odtToText(buffer) {
|
|
|
3964
3968
|
const stripped = withBreaks.replace(/<[^>]+>/g, "");
|
|
3965
3969
|
return unescapeXml(stripped).replace(/\n{3,}/g, "\n\n").trim();
|
|
3966
3970
|
}
|
|
3971
|
+
function sheetOrdinal(name) {
|
|
3972
|
+
const m = name.match(/sheet(\d+)\.xml$/);
|
|
3973
|
+
return m ? parseInt(m[1], 10) : 0;
|
|
3974
|
+
}
|
|
3975
|
+
function xlsxToText(buffer) {
|
|
3976
|
+
const files = unzipSync(new Uint8Array(buffer));
|
|
3977
|
+
const shared = [];
|
|
3978
|
+
const sharedBytes = files["xl/sharedStrings.xml"];
|
|
3979
|
+
if (sharedBytes) {
|
|
3980
|
+
for (const si of strFromU8(sharedBytes).split("</si>")) {
|
|
3981
|
+
if (!si.includes("<si")) continue;
|
|
3982
|
+
const base = si.replace(/<rPh\b[\s\S]*?<\/rPh>/g, "");
|
|
3983
|
+
let s = "";
|
|
3984
|
+
for (const m of base.matchAll(/<t\b[^>]*>([\s\S]*?)<\/t>/g)) s += m[1];
|
|
3985
|
+
shared.push(unescapeXml(s));
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3988
|
+
const sheetKeys = Object.keys(files).filter((n) => /^xl\/worksheets\/sheet\d+\.xml$/.test(n)).sort((a, b) => sheetOrdinal(a) - sheetOrdinal(b));
|
|
3989
|
+
const sheets = [];
|
|
3990
|
+
for (const key of sheetKeys) {
|
|
3991
|
+
const xml = strFromU8(files[key]);
|
|
3992
|
+
const rows = [];
|
|
3993
|
+
for (const rowXml of xml.split("</row>")) {
|
|
3994
|
+
if (!rowXml.includes("<row")) continue;
|
|
3995
|
+
const cells = [];
|
|
3996
|
+
for (const c of rowXml.matchAll(/<c\b([^>]*)>([\s\S]*?)<\/c>/g)) {
|
|
3997
|
+
const attrs = c[1];
|
|
3998
|
+
const body = c[2];
|
|
3999
|
+
if (/\bt="inlineStr"/.test(attrs)) {
|
|
4000
|
+
let s = "";
|
|
4001
|
+
for (const m of body.matchAll(/<t\b[^>]*>([\s\S]*?)<\/t>/g)) s += m[1];
|
|
4002
|
+
cells.push(unescapeXml(s));
|
|
4003
|
+
continue;
|
|
4004
|
+
}
|
|
4005
|
+
const v = body.match(/<v\b[^>]*>([\s\S]*?)<\/v>/);
|
|
4006
|
+
if (!v) {
|
|
4007
|
+
cells.push("");
|
|
4008
|
+
continue;
|
|
4009
|
+
}
|
|
4010
|
+
if (/\bt="s"/.test(attrs)) {
|
|
4011
|
+
const idx = parseInt(v[1], 10);
|
|
4012
|
+
cells.push(Number.isInteger(idx) && idx >= 0 && idx < shared.length ? shared[idx] : "");
|
|
4013
|
+
} else {
|
|
4014
|
+
cells.push(unescapeXml(v[1]));
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
while (cells.length && cells[cells.length - 1] === "") cells.pop();
|
|
4018
|
+
if (cells.length) rows.push(cells.join(" "));
|
|
4019
|
+
}
|
|
4020
|
+
if (rows.length) sheets.push(rows.join("\n"));
|
|
4021
|
+
}
|
|
4022
|
+
return sheets.join("\n\n");
|
|
4023
|
+
}
|
|
4024
|
+
function odsToText(buffer) {
|
|
4025
|
+
const xml = unzipEntry(buffer, "content.xml");
|
|
4026
|
+
const tables = [];
|
|
4027
|
+
for (const tableXml of xml.split(/<table:table(?=[\s>])/).slice(1)) {
|
|
4028
|
+
const rows = [];
|
|
4029
|
+
for (const rowXml of tableXml.split(/<table:table-row\b/).slice(1)) {
|
|
4030
|
+
const cells = rowXml.split(/<table:(?:covered-)?table-cell\b/).slice(1).map((frag) => {
|
|
4031
|
+
const withBreaks = frag.replace(/<text:line-break\b[^>]*\/?>/g, "\n").replace(/<text:tab\b[^>]*\/?>/g, " ");
|
|
4032
|
+
let s = "";
|
|
4033
|
+
for (const m of withBreaks.matchAll(/<text:p\b[^>]*>([\s\S]*?)<\/text:p>/g)) {
|
|
4034
|
+
s += (s ? "\n" : "") + m[1].replace(/<[^>]+>/g, "");
|
|
4035
|
+
}
|
|
4036
|
+
return unescapeXml(s);
|
|
4037
|
+
});
|
|
4038
|
+
while (cells.length && cells[cells.length - 1] === "") cells.pop();
|
|
4039
|
+
if (cells.length) rows.push(cells.join(" "));
|
|
4040
|
+
}
|
|
4041
|
+
if (rows.length) tables.push(rows.join("\n"));
|
|
4042
|
+
}
|
|
4043
|
+
return tables.join("\n\n");
|
|
4044
|
+
}
|
|
3967
4045
|
var RTF_DROP_DEST = /^\\(?:\*|fonttbl|colortbl|stylesheet|listtable|info|pict)\b/;
|
|
3968
4046
|
function stripRtfDestinations(s) {
|
|
3969
4047
|
let out = "";
|
|
@@ -4004,6 +4082,8 @@ function docToText(buffer, mimeType) {
|
|
|
4004
4082
|
const mime = bareMime(mimeType);
|
|
4005
4083
|
if (mime === DOCX) return docxToText(buffer);
|
|
4006
4084
|
if (mime === ODT) return odtToText(buffer);
|
|
4085
|
+
if (mime === XLSX) return xlsxToText(buffer);
|
|
4086
|
+
if (mime === ODS) return odsToText(buffer);
|
|
4007
4087
|
if (mime === "text/rtf" || mime === "application/rtf") return rtfToText(buffer.toString("latin1"));
|
|
4008
4088
|
return null;
|
|
4009
4089
|
}
|
|
@@ -4033,6 +4113,21 @@ var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
|
4033
4113
|
"application/vnd.oasis.opendocument.text",
|
|
4034
4114
|
"text/rtf",
|
|
4035
4115
|
"application/rtf",
|
|
4116
|
+
// Task 1607 — spreadsheets + presentations operators send. These land
|
|
4117
|
+
// download-only in the reader; the Read tool cannot parse the binary
|
|
4118
|
+
// containers and agent-readable text extraction for them is task 1608.
|
|
4119
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
4120
|
+
// xlsx
|
|
4121
|
+
"application/vnd.ms-excel",
|
|
4122
|
+
// xls
|
|
4123
|
+
"application/vnd.oasis.opendocument.spreadsheet",
|
|
4124
|
+
// ods
|
|
4125
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
4126
|
+
// pptx
|
|
4127
|
+
"application/vnd.ms-powerpoint",
|
|
4128
|
+
// ppt
|
|
4129
|
+
"application/vnd.oasis.opendocument.presentation",
|
|
4130
|
+
// odp
|
|
4036
4131
|
// Task 1240 — voice recordings persist as playable clips in the admin bubble.
|
|
4037
4132
|
// These match AUDIO_MIME_TYPES in app/lib/stt/audio-mime.ts exactly.
|
|
4038
4133
|
"audio/ogg",
|
|
@@ -4049,6 +4144,7 @@ var MAX_FILES_PER_MESSAGE = 5;
|
|
|
4049
4144
|
var MAX_DATA_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024;
|
|
4050
4145
|
var MAX_ZIP_UNCOMPRESSED_BYTES = 100 * 1024 * 1024;
|
|
4051
4146
|
var EXTRACTED_TEXT_SUFFIX = ".extracted.txt";
|
|
4147
|
+
var ATTACHMENT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4052
4148
|
function assertSupportedMime(mimeType) {
|
|
4053
4149
|
const bare = mimeType.split(";")[0].trim().toLowerCase();
|
|
4054
4150
|
if (!SUPPORTED_MIME_TYPES.has(bare)) {
|
|
@@ -4057,22 +4153,47 @@ function assertSupportedMime(mimeType) {
|
|
|
4057
4153
|
);
|
|
4058
4154
|
}
|
|
4059
4155
|
}
|
|
4060
|
-
function
|
|
4061
|
-
|
|
4156
|
+
function isInlineSafeMime(mimeType) {
|
|
4157
|
+
const bare = mimeType.split(";")[0].trim().toLowerCase();
|
|
4158
|
+
if (bare === "image/svg+xml") return false;
|
|
4159
|
+
return bare.startsWith("image/") || bare === "application/pdf" || bare.startsWith("audio/") || bare === "video/mp4";
|
|
4062
4160
|
}
|
|
4063
4161
|
async function storeMediaBuffer(accountId, attachmentId, filename, mimeType, buffer) {
|
|
4064
|
-
assertSupportedMime(mimeType);
|
|
4065
4162
|
if (buffer.byteLength > MAX_FILE_SIZE_BYTES) {
|
|
4066
4163
|
throw new Error(
|
|
4067
4164
|
`Media exceeds the 50 MB limit (${(buffer.byteLength / 1024 / 1024).toFixed(1)} MB).`
|
|
4068
4165
|
);
|
|
4069
4166
|
}
|
|
4070
|
-
return writeAttachment(accountId, "", filename, mimeType, buffer.byteLength, buffer, attachmentId
|
|
4167
|
+
return writeAttachment(accountId, "", filename, mimeType, buffer.byteLength, buffer, attachmentId);
|
|
4071
4168
|
}
|
|
4072
4169
|
function attachmentExists(accountId, attachmentId) {
|
|
4073
4170
|
return existsSync4(resolve6(uploadsDirFor(accountId, "", attachmentId), `${attachmentId}.meta.json`));
|
|
4074
4171
|
}
|
|
4075
|
-
|
|
4172
|
+
function resolveStoredAttachment(accountId, attachmentId) {
|
|
4173
|
+
if (!ATTACHMENT_ID_RE.test(attachmentId)) return null;
|
|
4174
|
+
const dir = uploadsDirFor(accountId, "", attachmentId);
|
|
4175
|
+
let meta;
|
|
4176
|
+
try {
|
|
4177
|
+
meta = JSON.parse(readFileSync8(resolve6(dir, `${attachmentId}.meta.json`), "utf8"));
|
|
4178
|
+
} catch {
|
|
4179
|
+
return null;
|
|
4180
|
+
}
|
|
4181
|
+
if (!meta || typeof meta !== "object") return null;
|
|
4182
|
+
const { filename, mimeType } = meta;
|
|
4183
|
+
if (typeof filename !== "string" || typeof mimeType !== "string") return null;
|
|
4184
|
+
let entries;
|
|
4185
|
+
try {
|
|
4186
|
+
entries = readdirSync3(dir, { withFileTypes: true });
|
|
4187
|
+
} catch {
|
|
4188
|
+
return null;
|
|
4189
|
+
}
|
|
4190
|
+
const dataFile = entries.find((e) => e.isFile() && !e.name.endsWith(".meta.json") && !e.name.endsWith(EXTRACTED_TEXT_SUFFIX));
|
|
4191
|
+
if (!dataFile) return null;
|
|
4192
|
+
const readableSibling = `${attachmentId}${EXTRACTED_TEXT_SUFFIX}`;
|
|
4193
|
+
const readableTextPath = entries.some((e) => e.isFile() && e.name === readableSibling) ? resolve6(dir, readableSibling) : void 0;
|
|
4194
|
+
return { attachmentId, filename, mimeType, path: resolve6(dir, dataFile.name), readableTextPath };
|
|
4195
|
+
}
|
|
4196
|
+
async function writeAttachment(accountId, subPath, filename, mimeType, sizeBytes, buffer, explicitId) {
|
|
4076
4197
|
const attachmentId = explicitId ?? randomUUID3();
|
|
4077
4198
|
const dir = uploadsDirFor(accountId, subPath, attachmentId);
|
|
4078
4199
|
await mkdir(dir, { recursive: true });
|
|
@@ -4090,11 +4211,23 @@ async function writeAttachment(accountId, subPath, filename, mimeType, sizeBytes
|
|
|
4090
4211
|
await writeFile(storagePath, buffer);
|
|
4091
4212
|
await writeFile(metaPath, JSON.stringify(meta, null, 2));
|
|
4092
4213
|
let readableTextPath;
|
|
4093
|
-
|
|
4094
|
-
|
|
4214
|
+
const bare = mimeType.split(";")[0].trim().toLowerCase();
|
|
4215
|
+
if (CONVERTIBLE_DOC_MIME.has(bare)) {
|
|
4216
|
+
let text = null;
|
|
4217
|
+
try {
|
|
4218
|
+
text = docToText(buffer, mimeType);
|
|
4219
|
+
} catch {
|
|
4220
|
+
text = null;
|
|
4221
|
+
}
|
|
4222
|
+
console.error(`[doc-to-text] op=convert mime=${bare} ok=${text !== null} chars=${text?.length ?? 0}`);
|
|
4095
4223
|
if (text) {
|
|
4096
|
-
|
|
4097
|
-
|
|
4224
|
+
const siblingPath = resolve6(dir, `${attachmentId}${EXTRACTED_TEXT_SUFFIX}`);
|
|
4225
|
+
try {
|
|
4226
|
+
await writeFile(siblingPath, text);
|
|
4227
|
+
readableTextPath = siblingPath;
|
|
4228
|
+
} catch (err) {
|
|
4229
|
+
console.error(`[doc-to-text] op=sibling-write mime=${bare} ok=false reason=${String(err).slice(0, 80)}`);
|
|
4230
|
+
}
|
|
4098
4231
|
}
|
|
4099
4232
|
}
|
|
4100
4233
|
return { attachmentId, filename, storagePath, metaPath, mimeType, sizeBytes, readableTextPath };
|
|
@@ -4141,6 +4274,13 @@ var MIME_BY_EXT = {
|
|
|
4141
4274
|
".odt": "application/vnd.oasis.opendocument.text",
|
|
4142
4275
|
".rtf": "text/rtf",
|
|
4143
4276
|
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
4277
|
+
// Task 1607 — legacy + OpenDocument office extensions, so a device-stored file
|
|
4278
|
+
// attached to a WhatsApp reply (detectMimeType → isMimeAdmitted, whatsapp-reader.ts)
|
|
4279
|
+
// resolves to the mime now admitted in SUPPORTED_MIME_TYPES rather than octet-stream.
|
|
4280
|
+
".xls": "application/vnd.ms-excel",
|
|
4281
|
+
".ods": "application/vnd.oasis.opendocument.spreadsheet",
|
|
4282
|
+
".ppt": "application/vnd.ms-powerpoint",
|
|
4283
|
+
".odp": "application/vnd.oasis.opendocument.presentation",
|
|
4144
4284
|
".ics": "text/calendar"
|
|
4145
4285
|
};
|
|
4146
4286
|
function detectMimeType(filePath) {
|
|
@@ -4978,20 +5118,6 @@ function attachSelfIdRefreshOnCredsUpdate(conn) {
|
|
|
4978
5118
|
function reloadConfig(accountConfig) {
|
|
4979
5119
|
loadConfig(accountConfig);
|
|
4980
5120
|
}
|
|
4981
|
-
function getMessages(accountId, jid, limit) {
|
|
4982
|
-
const entries = messageStore.get(messageStoreKey(accountId, jid)) ?? [];
|
|
4983
|
-
return limit ? entries.slice(-limit) : entries.slice();
|
|
4984
|
-
}
|
|
4985
|
-
function listConversationJids(accountId) {
|
|
4986
|
-
const prefix = messageStoreKey(accountId, "");
|
|
4987
|
-
const jids = [];
|
|
4988
|
-
for (const key of messageStore.keys()) {
|
|
4989
|
-
if (key.startsWith(prefix)) {
|
|
4990
|
-
jids.push(key.slice(prefix.length));
|
|
4991
|
-
}
|
|
4992
|
-
}
|
|
4993
|
-
return jids;
|
|
4994
|
-
}
|
|
4995
5121
|
function listStoreAccountKeys() {
|
|
4996
5122
|
const accounts = /* @__PURE__ */ new Set();
|
|
4997
5123
|
for (const key of messageStore.keys()) {
|
|
@@ -5133,11 +5259,11 @@ async function connectWithReconnect(conn) {
|
|
|
5133
5259
|
console.error(
|
|
5134
5260
|
`${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
5135
5261
|
);
|
|
5136
|
-
await new Promise((
|
|
5137
|
-
const timer2 = setTimeout(
|
|
5262
|
+
await new Promise((resolve35) => {
|
|
5263
|
+
const timer2 = setTimeout(resolve35, delay);
|
|
5138
5264
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
5139
5265
|
clearTimeout(timer2);
|
|
5140
|
-
|
|
5266
|
+
resolve35();
|
|
5141
5267
|
}, { once: true });
|
|
5142
5268
|
});
|
|
5143
5269
|
}
|
|
@@ -5145,16 +5271,16 @@ async function connectWithReconnect(conn) {
|
|
|
5145
5271
|
}
|
|
5146
5272
|
}
|
|
5147
5273
|
function waitForDisconnectEvent(conn) {
|
|
5148
|
-
return new Promise((
|
|
5274
|
+
return new Promise((resolve35) => {
|
|
5149
5275
|
if (!conn.sock) {
|
|
5150
|
-
|
|
5276
|
+
resolve35();
|
|
5151
5277
|
return;
|
|
5152
5278
|
}
|
|
5153
5279
|
const sock = conn.sock;
|
|
5154
5280
|
const handler = (update) => {
|
|
5155
5281
|
if (update.connection === "close") {
|
|
5156
5282
|
sock.ev.off("connection.update", handler);
|
|
5157
|
-
|
|
5283
|
+
resolve35();
|
|
5158
5284
|
}
|
|
5159
5285
|
};
|
|
5160
5286
|
sock.ev.on("connection.update", handler);
|
|
@@ -5205,7 +5331,7 @@ function monitorInbound(conn) {
|
|
|
5205
5331
|
if (!msg.message) continue;
|
|
5206
5332
|
let receiptDeferredToWorker = false;
|
|
5207
5333
|
const extracted = extractMessage(msg);
|
|
5208
|
-
const mediaServable = !!(extracted.mediaType && extracted.mimetype
|
|
5334
|
+
const mediaServable = !!(extracted.mediaType && extracted.mimetype);
|
|
5209
5335
|
if (extracted.text || mediaServable) {
|
|
5210
5336
|
const isGroup = isGroupJid(remoteJid);
|
|
5211
5337
|
const senderJid = isGroup ? msg.key.participant ?? remoteJid : remoteJid;
|
|
@@ -5476,8 +5602,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
5476
5602
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
5477
5603
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
5478
5604
|
let resolvePending;
|
|
5479
|
-
const sttPending = new Promise((
|
|
5480
|
-
resolvePending =
|
|
5605
|
+
const sttPending = new Promise((resolve35) => {
|
|
5606
|
+
resolvePending = resolve35;
|
|
5481
5607
|
});
|
|
5482
5608
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
5483
5609
|
try {
|
|
@@ -5602,7 +5728,7 @@ async function handleInboundMessage(conn, msg) {
|
|
|
5602
5728
|
// app/lib/vnc.ts
|
|
5603
5729
|
import { spawnSync, execFileSync } from "child_process";
|
|
5604
5730
|
import { createConnection } from "net";
|
|
5605
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
5731
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
|
|
5606
5732
|
import { resolve as resolve7 } from "path";
|
|
5607
5733
|
var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve7(process.cwd(), "..");
|
|
5608
5734
|
var VNC_SCRIPT = resolve7(PLATFORM_ROOT4, "scripts/vnc.sh");
|
|
@@ -5660,7 +5786,7 @@ function discoverNativeDisplay() {
|
|
|
5660
5786
|
const leaderPid = leaderResult.stdout?.trim();
|
|
5661
5787
|
if (leaderPid) {
|
|
5662
5788
|
try {
|
|
5663
|
-
const environ =
|
|
5789
|
+
const environ = readFileSync9(`/proc/${leaderPid}/environ`, "utf8");
|
|
5664
5790
|
const match = environ.split("\0").find((e) => e.startsWith("WAYLAND_DISPLAY="));
|
|
5665
5791
|
if (match) waylandDisplay = match.split("=")[1];
|
|
5666
5792
|
} catch {
|
|
@@ -5905,20 +6031,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
5905
6031
|
|
|
5906
6032
|
// server/routes/health.ts
|
|
5907
6033
|
function checkPort(port2, timeoutMs = 500) {
|
|
5908
|
-
return new Promise((
|
|
6034
|
+
return new Promise((resolve35) => {
|
|
5909
6035
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
5910
6036
|
socket.setTimeout(timeoutMs);
|
|
5911
6037
|
socket.once("connect", () => {
|
|
5912
6038
|
socket.destroy();
|
|
5913
|
-
|
|
6039
|
+
resolve35(true);
|
|
5914
6040
|
});
|
|
5915
6041
|
socket.once("error", () => {
|
|
5916
6042
|
socket.destroy();
|
|
5917
|
-
|
|
6043
|
+
resolve35(false);
|
|
5918
6044
|
});
|
|
5919
6045
|
socket.once("timeout", () => {
|
|
5920
6046
|
socket.destroy();
|
|
5921
|
-
|
|
6047
|
+
resolve35(false);
|
|
5922
6048
|
});
|
|
5923
6049
|
});
|
|
5924
6050
|
}
|
|
@@ -5928,7 +6054,7 @@ app.get("/", async (c) => {
|
|
|
5928
6054
|
let pinConfigured = false;
|
|
5929
6055
|
try {
|
|
5930
6056
|
if (existsSync5(USERS_FILE)) {
|
|
5931
|
-
const raw =
|
|
6057
|
+
const raw = readFileSync10(USERS_FILE, "utf-8").trim();
|
|
5932
6058
|
if (raw) {
|
|
5933
6059
|
const users = JSON.parse(raw);
|
|
5934
6060
|
pinConfigured = Array.isArray(users) && users.length > 0;
|
|
@@ -6600,13 +6726,13 @@ async function sendTelegramText(botToken, chatId, text) {
|
|
|
6600
6726
|
|
|
6601
6727
|
// server/routes/whatsapp.ts
|
|
6602
6728
|
import { join as join10, resolve as resolve10 } from "path";
|
|
6603
|
-
import { readdirSync as
|
|
6729
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync12, existsSync as existsSync7 } from "fs";
|
|
6604
6730
|
|
|
6605
6731
|
// app/lib/whatsapp/login.ts
|
|
6606
6732
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
6607
6733
|
|
|
6608
6734
|
// app/lib/whatsapp/config-persist.ts
|
|
6609
|
-
import { readFileSync as
|
|
6735
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync4, existsSync as existsSync6 } from "fs";
|
|
6610
6736
|
import { resolve as resolve8, join as join8, dirname as dirname2, basename as basename2 } from "path";
|
|
6611
6737
|
var TAG17 = "[whatsapp:config]";
|
|
6612
6738
|
function configPath(accountDir) {
|
|
@@ -6615,7 +6741,7 @@ function configPath(accountDir) {
|
|
|
6615
6741
|
function readConfig(accountDir) {
|
|
6616
6742
|
const path2 = configPath(accountDir);
|
|
6617
6743
|
if (!existsSync6(path2)) throw new Error(`account.json not found at ${path2}`);
|
|
6618
|
-
return JSON.parse(
|
|
6744
|
+
return JSON.parse(readFileSync11(path2, "utf-8"));
|
|
6619
6745
|
}
|
|
6620
6746
|
function writeConfig(accountDir, config) {
|
|
6621
6747
|
const path2 = configPath(accountDir);
|
|
@@ -7195,8 +7321,8 @@ async function startLogin(opts) {
|
|
|
7195
7321
|
await clearAuth(authDir);
|
|
7196
7322
|
let resolveCode = null;
|
|
7197
7323
|
let rejectCode = null;
|
|
7198
|
-
const codePromise = new Promise((
|
|
7199
|
-
resolveCode =
|
|
7324
|
+
const codePromise = new Promise((resolve35, reject) => {
|
|
7325
|
+
resolveCode = resolve35;
|
|
7200
7326
|
rejectCode = reject;
|
|
7201
7327
|
});
|
|
7202
7328
|
const codeTimer = setTimeout(
|
|
@@ -7536,13 +7662,13 @@ function serializeWhatsAppSchema() {
|
|
|
7536
7662
|
}
|
|
7537
7663
|
|
|
7538
7664
|
// app/lib/whatsapp/status-reconcile.ts
|
|
7539
|
-
import { readdirSync as
|
|
7665
|
+
import { readdirSync as readdirSync4 } from "fs";
|
|
7540
7666
|
import { join as join9 } from "path";
|
|
7541
7667
|
var TAG20 = "[whatsapp:reconcile]";
|
|
7542
7668
|
var HALF_REGISTERED_MIN_AGE_MS = 5 * 6e4;
|
|
7543
7669
|
function listCredsAccountIds(credsRoot) {
|
|
7544
7670
|
try {
|
|
7545
|
-
return
|
|
7671
|
+
return readdirSync4(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(join9(credsRoot, e.name))).map((e) => e.name);
|
|
7546
7672
|
} catch {
|
|
7547
7673
|
return [];
|
|
7548
7674
|
}
|
|
@@ -7689,6 +7815,15 @@ function authorizeRecallRead(input) {
|
|
|
7689
7815
|
// server/routes/whatsapp.ts
|
|
7690
7816
|
var TAG21 = "[whatsapp:api]";
|
|
7691
7817
|
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
7818
|
+
function recallAttachment(storeAccountId, attachmentId) {
|
|
7819
|
+
if (!attachmentId) return void 0;
|
|
7820
|
+
const a = resolveStoredAttachment(storeAccountId, attachmentId);
|
|
7821
|
+
if (!a) {
|
|
7822
|
+
console.error(`[whatsapp-read-tool] op=attachment-miss attachmentId=${attachmentId.slice(0, 8)} storeAccount=${storeAccountId}`);
|
|
7823
|
+
return void 0;
|
|
7824
|
+
}
|
|
7825
|
+
return a;
|
|
7826
|
+
}
|
|
7692
7827
|
function projectionFor(requestedAccountId) {
|
|
7693
7828
|
const validAccounts = listValidAccounts();
|
|
7694
7829
|
if (validAccounts.length <= 1) return { storeAccountId: requestedAccountId, managerPhones: null };
|
|
@@ -7880,13 +8015,13 @@ app2.post("/config", async (c) => {
|
|
|
7880
8015
|
const agents = [];
|
|
7881
8016
|
if (existsSync7(agentsDir)) {
|
|
7882
8017
|
try {
|
|
7883
|
-
const entries =
|
|
8018
|
+
const entries = readdirSync5(agentsDir, { withFileTypes: true });
|
|
7884
8019
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
7885
8020
|
if (!entry.isDirectory() || entry.name === "admin") continue;
|
|
7886
8021
|
const configPath2 = resolve10(agentsDir, entry.name, "config.json");
|
|
7887
8022
|
if (!existsSync7(configPath2)) continue;
|
|
7888
8023
|
try {
|
|
7889
|
-
const config = JSON.parse(
|
|
8024
|
+
const config = JSON.parse(readFileSync12(configPath2, "utf-8"));
|
|
7890
8025
|
agents.push({ slug: entry.name, displayName: config.displayName ?? entry.name });
|
|
7891
8026
|
} catch {
|
|
7892
8027
|
console.error(`${TAG21} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
|
|
@@ -8031,20 +8166,23 @@ app2.get("/conversations", (c) => {
|
|
|
8031
8166
|
const requestedAccountId = validateAccountId(c.req.query("accountId") ?? null);
|
|
8032
8167
|
const denial = callerScopeDenial(c, requestedAccountId);
|
|
8033
8168
|
if (denial) return denial;
|
|
8034
|
-
const
|
|
8035
|
-
const
|
|
8036
|
-
const
|
|
8037
|
-
|
|
8038
|
-
|
|
8169
|
+
const projection = projectionFor(requestedAccountId);
|
|
8170
|
+
const storeAccountId = resolveReadStoreKey(projection.storeAccountId);
|
|
8171
|
+
const projecting = projection.managerPhones != null;
|
|
8172
|
+
const managerPhonesBound = projection.managerPhones?.length ?? 0;
|
|
8173
|
+
const allConversations = readAllConversations(storeAccountId);
|
|
8174
|
+
const scoped = projection.managerPhones ? filterConversationsForSubAccount(allConversations, projection.managerPhones) : allConversations;
|
|
8175
|
+
const conversations = [...scoped.entries()].map(([jid, messages]) => {
|
|
8176
|
+
const last = messages.length > 0 ? messages[messages.length - 1] : null;
|
|
8039
8177
|
return {
|
|
8040
8178
|
jid,
|
|
8041
8179
|
type: isGroupJid(jid) ? "group" : "dm",
|
|
8042
|
-
lastMessageTimestamp:
|
|
8180
|
+
lastMessageTimestamp: last ? Math.floor(Date.parse(last.dateSent) / 1e3) : null,
|
|
8043
8181
|
messageCount: messages.length
|
|
8044
8182
|
};
|
|
8045
8183
|
});
|
|
8046
8184
|
conversations.sort((a, b) => (b.lastMessageTimestamp ?? 0) - (a.lastMessageTimestamp ?? 0));
|
|
8047
|
-
console.error(`${TAG21} conversations requested=${requestedAccountId} account=${
|
|
8185
|
+
console.error(`${TAG21} conversations requested=${requestedAccountId} account=${storeAccountId} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${allConversations.size > 0} count=${conversations.length}`);
|
|
8048
8186
|
return c.json({ conversations });
|
|
8049
8187
|
} catch (err) {
|
|
8050
8188
|
console.error(`${TAG21} conversations error: ${String(err)}`);
|
|
@@ -8056,7 +8194,6 @@ app2.get("/messages", (c) => {
|
|
|
8056
8194
|
const requestedAccountId = validateAccountId(c.req.query("accountId") ?? null);
|
|
8057
8195
|
const denial = callerScopeDenial(c, requestedAccountId);
|
|
8058
8196
|
if (denial) return denial;
|
|
8059
|
-
const accountId = resolveReadStoreKey(requestedAccountId);
|
|
8060
8197
|
const jid = c.req.query("jid");
|
|
8061
8198
|
if (!jid) {
|
|
8062
8199
|
return c.json({ error: "Missing required parameter: jid" }, 400);
|
|
@@ -8064,9 +8201,33 @@ app2.get("/messages", (c) => {
|
|
|
8064
8201
|
const limitParam = c.req.query("limit");
|
|
8065
8202
|
const limit = limitParam ? parseInt(limitParam, 10) : void 0;
|
|
8066
8203
|
const effectiveLimit = limit && !Number.isNaN(limit) && limit > 0 ? limit : void 0;
|
|
8067
|
-
const
|
|
8068
|
-
const
|
|
8069
|
-
|
|
8204
|
+
const projection = projectionFor(requestedAccountId);
|
|
8205
|
+
const storeAccountId = resolveReadStoreKey(projection.storeAccountId);
|
|
8206
|
+
const projecting = projection.managerPhones != null;
|
|
8207
|
+
const managerPhonesBound = projection.managerPhones?.length ?? 0;
|
|
8208
|
+
const storeMessages = readConversation(storeAccountId, jid);
|
|
8209
|
+
const counterpartyBound = !projecting || counterpartyBoundToSubAccount(
|
|
8210
|
+
projection.managerPhones,
|
|
8211
|
+
conversationCounterpartyPhone(jid, storeMessages[0]?.senderTelephone ?? "")
|
|
8212
|
+
);
|
|
8213
|
+
const bounded = counterpartyBound ? storeMessages : [];
|
|
8214
|
+
const limited = effectiveLimit ? bounded.slice(-effectiveLimit) : bounded;
|
|
8215
|
+
let withAttachments = 0;
|
|
8216
|
+
const messages = limited.map((m) => {
|
|
8217
|
+
const attachment = recallAttachment(storeAccountId, m.attachmentId);
|
|
8218
|
+
if (attachment) withAttachments += 1;
|
|
8219
|
+
return {
|
|
8220
|
+
id: m.messageId,
|
|
8221
|
+
sender: m.senderTelephone,
|
|
8222
|
+
senderName: m.senderName ?? void 0,
|
|
8223
|
+
body: m.body,
|
|
8224
|
+
timestamp: Math.floor(Date.parse(m.dateSent) / 1e3),
|
|
8225
|
+
fromMe: m.fromMe,
|
|
8226
|
+
quoted: m.quotedId ? { id: m.quotedId, sender: m.quotedSender ?? void 0 } : void 0,
|
|
8227
|
+
attachment
|
|
8228
|
+
};
|
|
8229
|
+
});
|
|
8230
|
+
console.error(`${TAG21} messages requested=${requestedAccountId} account=${storeAccountId} jid=${jid} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${storeMessages.length > 0} limit=${effectiveLimit ?? "all"} returned=${messages.length} withAttachments=${withAttachments}`);
|
|
8070
8231
|
return c.json({ messages });
|
|
8071
8232
|
} catch (err) {
|
|
8072
8233
|
console.error(`${TAG21} messages error: ${String(err)}`);
|
|
@@ -8090,6 +8251,7 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
8090
8251
|
const rows2 = [];
|
|
8091
8252
|
const nameCache = /* @__PURE__ */ new Map();
|
|
8092
8253
|
let unresolvedSenders = 0;
|
|
8254
|
+
let withAttachments2 = 0;
|
|
8093
8255
|
let session = null;
|
|
8094
8256
|
try {
|
|
8095
8257
|
session = getSession();
|
|
@@ -8105,6 +8267,8 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
8105
8267
|
nameCache.set(m.senderTelephone, resolved);
|
|
8106
8268
|
if (!resolved) unresolvedSenders += 1;
|
|
8107
8269
|
}
|
|
8270
|
+
const attachment = recallAttachment(projection2.storeAccountId, m.attachmentId);
|
|
8271
|
+
if (attachment) withAttachments2 += 1;
|
|
8108
8272
|
rows2.push({
|
|
8109
8273
|
remoteJid: remoteJid2,
|
|
8110
8274
|
messageId: m.messageId,
|
|
@@ -8112,7 +8276,8 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
8112
8276
|
fromMe: m.fromMe,
|
|
8113
8277
|
senderTelephone: m.senderTelephone,
|
|
8114
8278
|
senderName: nameCache.get(m.senderTelephone) ?? m.senderName,
|
|
8115
|
-
body: m.body
|
|
8279
|
+
body: m.body,
|
|
8280
|
+
attachment
|
|
8116
8281
|
});
|
|
8117
8282
|
}
|
|
8118
8283
|
}
|
|
@@ -8120,7 +8285,7 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
8120
8285
|
if (session) await session.close();
|
|
8121
8286
|
}
|
|
8122
8287
|
const ms2 = Date.now() - t0;
|
|
8123
|
-
console.error(`[whatsapp-read-tool] op=query scope=${requestedAccountId} storeAccount=${projection2.storeAccountId} managerPhonesBound=${managerPhonesBound} resultCount=${rows2.length} unresolvedSenders=${unresolvedSenders} ms=${ms2}`);
|
|
8288
|
+
console.error(`[whatsapp-read-tool] op=query scope=${requestedAccountId} storeAccount=${projection2.storeAccountId} managerPhonesBound=${managerPhonesBound} resultCount=${rows2.length} unresolvedSenders=${unresolvedSenders} withAttachments=${withAttachments2} ms=${ms2}`);
|
|
8124
8289
|
return c.json({ accountId: requestedAccountId, rows: rows2, unresolvedSenders, ms: ms2, managerPhonesBound });
|
|
8125
8290
|
}
|
|
8126
8291
|
let remoteJid;
|
|
@@ -8144,15 +8309,21 @@ app2.get("/conversation-graph-state", async (c) => {
|
|
|
8144
8309
|
);
|
|
8145
8310
|
const messages = counterpartyBound ? storeMessages : [];
|
|
8146
8311
|
const sessionId = messages[0]?.sessionId ?? null;
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8312
|
+
let withAttachments = 0;
|
|
8313
|
+
const rows = messages.map((m) => {
|
|
8314
|
+
const attachment = recallAttachment(projection.storeAccountId, m.attachmentId);
|
|
8315
|
+
if (attachment) withAttachments += 1;
|
|
8316
|
+
return {
|
|
8317
|
+
messageId: m.messageId,
|
|
8318
|
+
dateSent: m.dateSent,
|
|
8319
|
+
fromMe: m.fromMe,
|
|
8320
|
+
senderTelephone: m.senderTelephone,
|
|
8321
|
+
body: m.body,
|
|
8322
|
+
attachment
|
|
8323
|
+
};
|
|
8324
|
+
});
|
|
8154
8325
|
const ms = Date.now() - t0;
|
|
8155
|
-
console.error(`[whatsapp-read-tool] op=query mode=single scope=${accountId} storeAccount=${projection.storeAccountId} graphRows=${rows.length} sessionId=${sessionId ?? "null"} ms=${ms}`);
|
|
8326
|
+
console.error(`[whatsapp-read-tool] op=query mode=single scope=${accountId} storeAccount=${projection.storeAccountId} graphRows=${rows.length} sessionId=${sessionId ?? "null"} withAttachments=${withAttachments} ms=${ms}`);
|
|
8156
8327
|
return c.json({
|
|
8157
8328
|
cacheKey,
|
|
8158
8329
|
sessionId,
|
|
@@ -8201,15 +8372,15 @@ app2.get("/group-info", async (c) => {
|
|
|
8201
8372
|
var whatsapp_default = app2;
|
|
8202
8373
|
|
|
8203
8374
|
// server/routes/whatsapp-reader.ts
|
|
8204
|
-
import { readFileSync as
|
|
8375
|
+
import { readFileSync as readFileSync16, watch, statSync as statSync5, openSync, readSync, closeSync, existsSync as existsSync10, readdirSync as readdirSync10, realpathSync as realpathSync4 } from "fs";
|
|
8205
8376
|
import { basename as basename4, dirname as dirname4, isAbsolute, join as join15, relative as relative2, resolve as resolve12, sep as sep3 } from "path";
|
|
8206
8377
|
|
|
8207
8378
|
// server/routes/admin/sidebar-sessions.ts
|
|
8208
|
-
import { readdirSync as
|
|
8379
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync14, statSync as statSync4 } from "fs";
|
|
8209
8380
|
import { dirname as dirname3, join as join13, resolve as resolve11 } from "path";
|
|
8210
8381
|
|
|
8211
8382
|
// ../services/claude-session-manager/src/jsonl-path.ts
|
|
8212
|
-
import { existsSync as existsSync8, readdirSync as
|
|
8383
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6 } from "fs";
|
|
8213
8384
|
import { homedir } from "os";
|
|
8214
8385
|
import { join as join11 } from "path";
|
|
8215
8386
|
function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
@@ -8217,7 +8388,7 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
|
8217
8388
|
if (!existsSync8(projectsRoot)) return null;
|
|
8218
8389
|
let slugs;
|
|
8219
8390
|
try {
|
|
8220
|
-
slugs =
|
|
8391
|
+
slugs = readdirSync6(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
8221
8392
|
} catch {
|
|
8222
8393
|
return null;
|
|
8223
8394
|
}
|
|
@@ -8233,14 +8404,14 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
|
8233
8404
|
|
|
8234
8405
|
// app/lib/admin-identity/pin-validator.ts
|
|
8235
8406
|
import { createHash as createHash3 } from "crypto";
|
|
8236
|
-
import { existsSync as existsSync9, readFileSync as
|
|
8407
|
+
import { existsSync as existsSync9, readFileSync as readFileSync13, readdirSync as readdirSync7, statSync as statSync3 } from "fs";
|
|
8237
8408
|
import { join as join12 } from "path";
|
|
8238
8409
|
function hashPin(pin) {
|
|
8239
8410
|
return createHash3("sha256").update(pin).digest("hex");
|
|
8240
8411
|
}
|
|
8241
8412
|
function readUsersFile(usersFilePath) {
|
|
8242
8413
|
if (!existsSync9(usersFilePath)) return null;
|
|
8243
|
-
const raw =
|
|
8414
|
+
const raw = readFileSync13(usersFilePath, "utf-8").trim();
|
|
8244
8415
|
if (!raw) return [];
|
|
8245
8416
|
return JSON.parse(raw);
|
|
8246
8417
|
}
|
|
@@ -8359,7 +8530,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8359
8530
|
const out = [];
|
|
8360
8531
|
let slugs;
|
|
8361
8532
|
try {
|
|
8362
|
-
slugs =
|
|
8533
|
+
slugs = readdirSync8(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
8363
8534
|
} catch (err) {
|
|
8364
8535
|
if (err.code === "ENOENT") return out;
|
|
8365
8536
|
throw err;
|
|
@@ -8368,7 +8539,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8368
8539
|
const slugDir = join13(projectsRoot, slug);
|
|
8369
8540
|
let entries;
|
|
8370
8541
|
try {
|
|
8371
|
-
entries =
|
|
8542
|
+
entries = readdirSync8(slugDir, { withFileTypes: true });
|
|
8372
8543
|
} catch (err) {
|
|
8373
8544
|
const code = err.code ?? "unknown";
|
|
8374
8545
|
console.error(`[admin-sessions-list] slug-skipped slug=${slug} code=${code}`);
|
|
@@ -8381,7 +8552,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8381
8552
|
const subDir = join13(slugDir, entry.name);
|
|
8382
8553
|
let subEntries;
|
|
8383
8554
|
try {
|
|
8384
|
-
subEntries =
|
|
8555
|
+
subEntries = readdirSync8(subDir, { withFileTypes: true });
|
|
8385
8556
|
} catch (err) {
|
|
8386
8557
|
const code = err.code ?? "unknown";
|
|
8387
8558
|
console.error(`[admin-sessions-list] subagents-skipped slug=${slug} code=${code}`);
|
|
@@ -8396,7 +8567,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8396
8567
|
const archiveDir = join13(slugDir, entry.name);
|
|
8397
8568
|
let archiveEntries;
|
|
8398
8569
|
try {
|
|
8399
|
-
archiveEntries =
|
|
8570
|
+
archiveEntries = readdirSync8(archiveDir, { withFileTypes: true });
|
|
8400
8571
|
} catch (err) {
|
|
8401
8572
|
const code = err.code ?? "unknown";
|
|
8402
8573
|
console.error(`[admin-sessions-list] archive-skipped slug=${slug} code=${code}`);
|
|
@@ -8440,7 +8611,7 @@ function loadUserTitles(accountDir) {
|
|
|
8440
8611
|
const path2 = join13(accountDir, "session-titles.json");
|
|
8441
8612
|
let raw;
|
|
8442
8613
|
try {
|
|
8443
|
-
raw =
|
|
8614
|
+
raw = readFileSync14(path2, "utf8");
|
|
8444
8615
|
} catch {
|
|
8445
8616
|
return out;
|
|
8446
8617
|
}
|
|
@@ -8466,7 +8637,7 @@ function readSidecarMeta(metaPath) {
|
|
|
8466
8637
|
const empty = { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null, personId: null, adminUserId: null, visitorId: null, agentSlug: null, accountId: null };
|
|
8467
8638
|
let raw;
|
|
8468
8639
|
try {
|
|
8469
|
-
raw =
|
|
8640
|
+
raw = readFileSync14(metaPath, "utf8");
|
|
8470
8641
|
} catch {
|
|
8471
8642
|
return empty;
|
|
8472
8643
|
}
|
|
@@ -8608,7 +8779,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
8608
8779
|
let body;
|
|
8609
8780
|
let mtimeMs;
|
|
8610
8781
|
try {
|
|
8611
|
-
body =
|
|
8782
|
+
body = readFileSync14(path2, "utf8");
|
|
8612
8783
|
mtimeMs = statSync4(path2).mtimeMs;
|
|
8613
8784
|
} catch {
|
|
8614
8785
|
continue;
|
|
@@ -8968,7 +9139,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
8968
9139
|
}
|
|
8969
9140
|
|
|
8970
9141
|
// app/lib/whatsapp-reader/enrich-attachments.ts
|
|
8971
|
-
import { readFileSync as
|
|
9142
|
+
import { readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
|
|
8972
9143
|
import { join as join14 } from "path";
|
|
8973
9144
|
var ADMIN_UPLOAD_PATH = /\/uploads\/(?!public\/)([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\//gi;
|
|
8974
9145
|
function adminAttachmentIds(text) {
|
|
@@ -8990,7 +9161,7 @@ function adminAttachmentsFromText(text, uploadsBase) {
|
|
|
8990
9161
|
function readSidecar(dir, attachmentId) {
|
|
8991
9162
|
let parsed;
|
|
8992
9163
|
try {
|
|
8993
|
-
parsed = JSON.parse(
|
|
9164
|
+
parsed = JSON.parse(readFileSync15(join14(dir, `${attachmentId}.meta.json`), "utf8"));
|
|
8994
9165
|
} catch {
|
|
8995
9166
|
return null;
|
|
8996
9167
|
}
|
|
@@ -9013,7 +9184,7 @@ function readAttachmentMeta(dir) {
|
|
|
9013
9184
|
function listSessionAttachmentsInDir(dir) {
|
|
9014
9185
|
let entries;
|
|
9015
9186
|
try {
|
|
9016
|
-
entries =
|
|
9187
|
+
entries = readdirSync9(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
9017
9188
|
} catch {
|
|
9018
9189
|
return [];
|
|
9019
9190
|
}
|
|
@@ -9039,6 +9210,24 @@ function splitNewLines(buf, baseOffset) {
|
|
|
9039
9210
|
};
|
|
9040
9211
|
}
|
|
9041
9212
|
|
|
9213
|
+
// app/lib/whatsapp-reader/authorize-reply-file-ref.ts
|
|
9214
|
+
var ACCOUNT_UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9215
|
+
function accountPartitionOwner(relative7) {
|
|
9216
|
+
const segs = relative7.split("/").filter(Boolean);
|
|
9217
|
+
if (segs.length < 2 || segs[0] !== "accounts") return null;
|
|
9218
|
+
return ACCOUNT_UUID_RE2.test(segs[1]) ? segs[1] : null;
|
|
9219
|
+
}
|
|
9220
|
+
function authorizeReplyFileRef(input) {
|
|
9221
|
+
const { relative: relative7, sendAccountId, sessionAccountId } = input;
|
|
9222
|
+
const segs = relative7.split("/").filter(Boolean);
|
|
9223
|
+
const inAccounts = segs.length >= 2 && segs[0] === "accounts";
|
|
9224
|
+
if (inAccounts && segs[1] === sendAccountId) return { allow: true, via: "own" };
|
|
9225
|
+
if (inAccounts && sessionAccountId && segs[1] === sessionAccountId) return { allow: true, via: "session" };
|
|
9226
|
+
if (accountPartitionOwner(relative7)) return { allow: false, reason: "cross-account" };
|
|
9227
|
+
if (segs[0] === "public" || inAccounts && segs[1] === "public") return { allow: false, reason: "public" };
|
|
9228
|
+
return { allow: false, reason: "foreign" };
|
|
9229
|
+
}
|
|
9230
|
+
|
|
9042
9231
|
// server/routes/admin/manager-client.ts
|
|
9043
9232
|
var SESSION_ID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9044
9233
|
function isSessionId(value) {
|
|
@@ -9060,7 +9249,7 @@ function pickActivity(entries, grown, nowMs, concurrencyWindowMs) {
|
|
|
9060
9249
|
}
|
|
9061
9250
|
|
|
9062
9251
|
// app/admin-types.ts
|
|
9063
|
-
var ACCEPT_MIME = "image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,application/zip,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.text,text/rtf,application/rtf,audio/ogg,audio/opus,audio/mp4,audio/x-m4a,audio/mpeg,audio/webm,audio/wav,video/mp4,.docx,.odt,.rtf,.opus,.ogg,.m4a,.mp4,.mp3,.wav,.webm";
|
|
9252
|
+
var ACCEPT_MIME = "image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,application/zip,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.text,text/rtf,application/rtf,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/vnd.oasis.opendocument.spreadsheet,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.ms-powerpoint,application/vnd.oasis.opendocument.presentation,audio/ogg,audio/opus,audio/mp4,audio/x-m4a,audio/mpeg,audio/webm,audio/wav,video/mp4,.docx,.odt,.rtf,.xlsx,.xls,.ods,.pptx,.ppt,.odp,.opus,.ogg,.m4a,.mp4,.mp3,.wav,.webm";
|
|
9064
9253
|
var SUPPORTED_MIME_SET = new Set(ACCEPT_MIME.split(",").filter((t) => !t.startsWith(".")));
|
|
9065
9254
|
var MAX_ATTACHMENTS = 5;
|
|
9066
9255
|
var MAX_FILE_BYTES = 50 * 1024 * 1024;
|
|
@@ -9073,6 +9262,11 @@ function isMimeAdmitted(mimeType, supportedSet) {
|
|
|
9073
9262
|
|
|
9074
9263
|
// server/routes/whatsapp-reader.ts
|
|
9075
9264
|
var app4 = new Hono();
|
|
9265
|
+
var DENY_COPY = {
|
|
9266
|
+
"cross-account": "This file belongs to another account. Open that account to send it.",
|
|
9267
|
+
public: "This file cannot be sent to a WhatsApp contact.",
|
|
9268
|
+
foreign: "This file cannot be sent to a WhatsApp contact."
|
|
9269
|
+
};
|
|
9076
9270
|
app4.get("/conversations", requireAdminSession, async (c) => {
|
|
9077
9271
|
const cacheKey = c.var.cacheKey;
|
|
9078
9272
|
const scopeAccountId = getAccountIdForSession(cacheKey) ?? null;
|
|
@@ -9099,7 +9293,7 @@ app4.get("/conversations", requireAdminSession, async (c) => {
|
|
|
9099
9293
|
}
|
|
9100
9294
|
let body = "";
|
|
9101
9295
|
try {
|
|
9102
|
-
body =
|
|
9296
|
+
body = readFileSync16(path2, "utf8");
|
|
9103
9297
|
} catch {
|
|
9104
9298
|
}
|
|
9105
9299
|
const { title } = resolveTitle(body, sessionId, userTitles);
|
|
@@ -9268,7 +9462,7 @@ function openTaskKey(turns) {
|
|
|
9268
9462
|
}
|
|
9269
9463
|
function readSubagentMeta(dir, hex) {
|
|
9270
9464
|
try {
|
|
9271
|
-
const m = JSON.parse(
|
|
9465
|
+
const m = JSON.parse(readFileSync16(join15(dir, `agent-${hex}.meta.json`), "utf8"));
|
|
9272
9466
|
if (typeof m.agentType === "string" && typeof m.description === "string" && typeof m.toolUseId === "string") {
|
|
9273
9467
|
return { agentType: m.agentType, description: m.description, toolUseId: m.toolUseId };
|
|
9274
9468
|
}
|
|
@@ -9291,7 +9485,7 @@ function runActivityTick(c) {
|
|
|
9291
9485
|
c.parentGrewThisTick = false;
|
|
9292
9486
|
let names = [];
|
|
9293
9487
|
try {
|
|
9294
|
-
names =
|
|
9488
|
+
names = readdirSync10(c.subagentsDir).filter((n) => AGENT_JSONL_RE.test(n));
|
|
9295
9489
|
} catch {
|
|
9296
9490
|
}
|
|
9297
9491
|
const entries = [];
|
|
@@ -9486,7 +9680,7 @@ app4.get("/directives", requireAdminSession, (c) => {
|
|
|
9486
9680
|
if (!dir || !existsSync10(dir)) return c.json({ entries: [] });
|
|
9487
9681
|
let names;
|
|
9488
9682
|
try {
|
|
9489
|
-
names =
|
|
9683
|
+
names = readdirSync10(dir).filter((n) => DIRECTIVE_NAME_RE.test(n));
|
|
9490
9684
|
} catch {
|
|
9491
9685
|
return c.json({ entries: [] });
|
|
9492
9686
|
}
|
|
@@ -9515,7 +9709,7 @@ app4.get("/directive", requireAdminSession, (c) => {
|
|
|
9515
9709
|
if (!path2.startsWith(dir + sep3)) return c.json({ error: "bad reference" }, 400);
|
|
9516
9710
|
let body;
|
|
9517
9711
|
try {
|
|
9518
|
-
body =
|
|
9712
|
+
body = readFileSync16(path2, "utf8");
|
|
9519
9713
|
} catch {
|
|
9520
9714
|
return c.json({ error: "not found" }, 404);
|
|
9521
9715
|
}
|
|
@@ -9720,7 +9914,9 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9720
9914
|
return c.json({ error: "invalid accountId" }, 400);
|
|
9721
9915
|
}
|
|
9722
9916
|
const validAccount = isValidAccountId(accountId);
|
|
9723
|
-
|
|
9917
|
+
const cacheKey = c.var.cacheKey;
|
|
9918
|
+
const sessionAccountId = getAccountIdForSession(cacheKey) ?? null;
|
|
9919
|
+
console.log(`${MANUAL_TAG} op=scope sendId=${sendId} accountId=${accountId} validAccount=${validAccount} sessionAccount=${sessionAccountId ?? "null"} src=session`);
|
|
9724
9920
|
if (!validAccount) {
|
|
9725
9921
|
exit("rejected");
|
|
9726
9922
|
return c.json({ error: "unknown account" }, 400);
|
|
@@ -9758,26 +9954,37 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9758
9954
|
}
|
|
9759
9955
|
}
|
|
9760
9956
|
const resolvedRefs = [];
|
|
9957
|
+
const acct8 = accountId.slice(0, 8);
|
|
9958
|
+
const sess8 = sessionAccountId ? sessionAccountId.slice(0, 8) : "";
|
|
9761
9959
|
for (const ref of fileRefs) {
|
|
9762
9960
|
const resolved = resolveDataPath(ref);
|
|
9763
|
-
|
|
9764
|
-
|
|
9961
|
+
if (!resolved.ok) {
|
|
9962
|
+
console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} owner= sendAccount=${acct8} sessionAccount=${sess8} via=deny reason=unresolved ok=false`);
|
|
9963
|
+
exit("rejected");
|
|
9964
|
+
return c.json({ error: `device file not found: ${ref}`, reason: "file-ref-unresolved" }, 404);
|
|
9965
|
+
}
|
|
9966
|
+
const owner = accountPartitionOwner(resolved.relative);
|
|
9967
|
+
const owner8 = owner ? owner.slice(0, 8) : "";
|
|
9968
|
+
const decision = authorizeReplyFileRef({ relative: resolved.relative, sendAccountId: accountId, sessionAccountId });
|
|
9969
|
+
if (!decision.allow) {
|
|
9970
|
+
console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} owner=${owner8} sendAccount=${acct8} sessionAccount=${sess8} via=deny reason=${decision.reason} ok=false`);
|
|
9971
|
+
exit("rejected");
|
|
9972
|
+
return c.json({ error: DENY_COPY[decision.reason], reason: `file-ref-${decision.reason}` }, 403);
|
|
9973
|
+
}
|
|
9974
|
+
const absolute = resolved.absolute;
|
|
9765
9975
|
let size = -1;
|
|
9766
|
-
|
|
9767
|
-
|
|
9768
|
-
|
|
9769
|
-
|
|
9770
|
-
|
|
9771
|
-
} catch {
|
|
9772
|
-
size = -1;
|
|
9773
|
-
}
|
|
9976
|
+
try {
|
|
9977
|
+
const st = statSync5(absolute);
|
|
9978
|
+
size = st.isFile() ? st.size : -1;
|
|
9979
|
+
} catch {
|
|
9980
|
+
size = -1;
|
|
9774
9981
|
}
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
if (!ok) {
|
|
9982
|
+
if (size < 0) {
|
|
9983
|
+
console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} owner=${owner8} sendAccount=${acct8} sessionAccount=${sess8} via=${decision.via} reason=missing ok=false`);
|
|
9778
9984
|
exit("rejected");
|
|
9779
9985
|
return c.json({ error: `device file not found: ${ref}`, reason: "file-ref-unresolved" }, 404);
|
|
9780
9986
|
}
|
|
9987
|
+
console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} owner=${owner8} sendAccount=${acct8} sessionAccount=${sess8} via=${decision.via} reason=none ok=true`);
|
|
9781
9988
|
if (size > MAX_FILE_BYTES) {
|
|
9782
9989
|
exit("rejected");
|
|
9783
9990
|
return c.json({ error: `"${basename4(absolute)}" exceeds the 50 MB limit` }, 400);
|
|
@@ -9872,7 +10079,7 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9872
10079
|
}
|
|
9873
10080
|
for (let i = 0; i < resolvedRefs.length; i++) {
|
|
9874
10081
|
const { absolute, mime } = resolvedRefs[i];
|
|
9875
|
-
const file = new File([
|
|
10082
|
+
const file = new File([readFileSync16(absolute)], basename4(absolute), { type: mime });
|
|
9876
10083
|
const out = await sendStagedFile(file, `ref=${i}`);
|
|
9877
10084
|
if (!out.ok) {
|
|
9878
10085
|
exit("error");
|
|
@@ -9891,7 +10098,7 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9891
10098
|
var whatsapp_reader_default = app4;
|
|
9892
10099
|
|
|
9893
10100
|
// server/routes/public-reader.ts
|
|
9894
|
-
import { statSync as statSync6, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as
|
|
10101
|
+
import { statSync as statSync6, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as readFileSync17, readdirSync as readdirSync11 } from "fs";
|
|
9895
10102
|
import { basename as basename5, dirname as dirname5, join as join16, resolve as resolve13, sep as sep4 } from "path";
|
|
9896
10103
|
|
|
9897
10104
|
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
@@ -10125,7 +10332,7 @@ data: ${JSON.stringify(turn)}
|
|
|
10125
10332
|
});
|
|
10126
10333
|
});
|
|
10127
10334
|
var ATT_TAG = "[public-attachment]";
|
|
10128
|
-
var
|
|
10335
|
+
var ATTACHMENT_ID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
10129
10336
|
app5.get("/attachment/:attachmentId", (c) => {
|
|
10130
10337
|
const visitor = resolveVisitor(c);
|
|
10131
10338
|
const attachmentId = c.req.param("attachmentId");
|
|
@@ -10137,7 +10344,7 @@ app5.get("/attachment/:attachmentId", (c) => {
|
|
|
10137
10344
|
return new Response("Unauthorized", { status: 401 });
|
|
10138
10345
|
}
|
|
10139
10346
|
console.log(`${ATT_TAG} op=request session=${ses} att=${at}`);
|
|
10140
|
-
if (!
|
|
10347
|
+
if (!ATTACHMENT_ID_RE2.test(attachmentId) || !SESSION_ID_RE2.test(sessionId)) {
|
|
10141
10348
|
console.error(`${ATT_TAG} op=denied session=${ses} att=${at} reason=bad-id`);
|
|
10142
10349
|
return new Response("Not found", { status: 404 });
|
|
10143
10350
|
}
|
|
@@ -10166,19 +10373,22 @@ app5.get("/attachment/:attachmentId", (c) => {
|
|
|
10166
10373
|
let dataFile;
|
|
10167
10374
|
let buffer;
|
|
10168
10375
|
try {
|
|
10169
|
-
dataFile =
|
|
10376
|
+
dataFile = readdirSync11(dir).find((f) => !f.endsWith(".meta.json") && !f.endsWith(EXTRACTED_TEXT_SUFFIX));
|
|
10170
10377
|
if (!dataFile) throw new Error("no data file");
|
|
10171
|
-
buffer =
|
|
10378
|
+
buffer = readFileSync17(resolve13(dir, dataFile));
|
|
10172
10379
|
} catch {
|
|
10173
10380
|
console.error(`${ATT_TAG} op=denied session=${ses} att=${at} reason=not-found`);
|
|
10174
10381
|
return new Response("Not found", { status: 404 });
|
|
10175
10382
|
}
|
|
10176
|
-
|
|
10383
|
+
const inlineSafe = isInlineSafeMime(meta.mimeType);
|
|
10384
|
+
const disposition = inlineSafe ? "inline" : "attachment";
|
|
10385
|
+
console.log(`${ATT_TAG} op=served session=${ses} att=${at} bytes=${buffer.length} mime=${meta.mimeType} disposition=${disposition}${inlineSafe ? "" : " reason=non-preview-mime"}`);
|
|
10177
10386
|
const safeName = meta.filename.replace(/["\\\r\n]/g, "_");
|
|
10178
10387
|
return new Response(new Uint8Array(buffer), {
|
|
10179
10388
|
headers: {
|
|
10180
10389
|
"Content-Type": meta.mimeType,
|
|
10181
|
-
"Content-Disposition":
|
|
10390
|
+
"Content-Disposition": `${disposition}; filename="${safeName}"`,
|
|
10391
|
+
"X-Content-Type-Options": "nosniff",
|
|
10182
10392
|
"Cache-Control": "private, max-age=3600"
|
|
10183
10393
|
}
|
|
10184
10394
|
});
|
|
@@ -10188,10 +10398,10 @@ var public_reader_default = app5;
|
|
|
10188
10398
|
// server/routes/webchat.ts
|
|
10189
10399
|
import { basename as basename6, dirname as dirname6 } from "path";
|
|
10190
10400
|
import { join as join19 } from "path";
|
|
10191
|
-
import { existsSync as existsSync12, readdirSync as
|
|
10401
|
+
import { existsSync as existsSync12, readdirSync as readdirSync13, readFileSync as readFileSync20, renameSync as renameSync4, statSync as statSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
10192
10402
|
|
|
10193
10403
|
// server/canonical-webchat-override.ts
|
|
10194
|
-
import { readFileSync as
|
|
10404
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync5, renameSync as renameSync2 } from "fs";
|
|
10195
10405
|
import { join as join17 } from "path";
|
|
10196
10406
|
var FILE = "canonical-webchat-session.json";
|
|
10197
10407
|
var UUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
@@ -10200,7 +10410,7 @@ function canonicalOverridePath(accountDir) {
|
|
|
10200
10410
|
}
|
|
10201
10411
|
function readRaw(accountDir) {
|
|
10202
10412
|
try {
|
|
10203
|
-
return JSON.parse(
|
|
10413
|
+
return JSON.parse(readFileSync18(canonicalOverridePath(accountDir), "utf8"));
|
|
10204
10414
|
} catch {
|
|
10205
10415
|
return null;
|
|
10206
10416
|
}
|
|
@@ -10275,7 +10485,7 @@ function isNewSessionEffortLevel(value) {
|
|
|
10275
10485
|
}
|
|
10276
10486
|
|
|
10277
10487
|
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
10278
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readdirSync as
|
|
10488
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readdirSync as readdirSync12, readFileSync as readFileSync19, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
10279
10489
|
import { join as join18 } from "path";
|
|
10280
10490
|
function escapeRegExp(s) {
|
|
10281
10491
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -10305,7 +10515,7 @@ function createSidecarStore(config) {
|
|
|
10305
10515
|
function readFileAt(path2) {
|
|
10306
10516
|
let raw;
|
|
10307
10517
|
try {
|
|
10308
|
-
raw =
|
|
10518
|
+
raw = readFileSync19(path2, "utf8");
|
|
10309
10519
|
} catch {
|
|
10310
10520
|
return null;
|
|
10311
10521
|
}
|
|
@@ -10321,7 +10531,7 @@ function createSidecarStore(config) {
|
|
|
10321
10531
|
function readAll(sessionsDir, onSkip) {
|
|
10322
10532
|
let names;
|
|
10323
10533
|
try {
|
|
10324
|
-
names =
|
|
10534
|
+
names = readdirSync12(sessionsDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name);
|
|
10325
10535
|
} catch {
|
|
10326
10536
|
return [];
|
|
10327
10537
|
}
|
|
@@ -10331,7 +10541,7 @@ function createSidecarStore(config) {
|
|
|
10331
10541
|
const path2 = join18(sessionsDir, name);
|
|
10332
10542
|
let raw;
|
|
10333
10543
|
try {
|
|
10334
|
-
raw =
|
|
10544
|
+
raw = readFileSync19(path2, "utf8");
|
|
10335
10545
|
} catch {
|
|
10336
10546
|
onSkip?.(name, "unreadable");
|
|
10337
10547
|
continue;
|
|
@@ -10414,7 +10624,7 @@ function locateSidecar(sessionId) {
|
|
|
10414
10624
|
const projectsRoot = join19(cfg, "projects");
|
|
10415
10625
|
let slugs;
|
|
10416
10626
|
try {
|
|
10417
|
-
slugs =
|
|
10627
|
+
slugs = readdirSync13(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
10418
10628
|
} catch {
|
|
10419
10629
|
return null;
|
|
10420
10630
|
}
|
|
@@ -10897,7 +11107,7 @@ ${note}` : note;
|
|
|
10897
11107
|
}
|
|
10898
11108
|
const accountJsonPath = join19(account.accountDir, "account.json");
|
|
10899
11109
|
try {
|
|
10900
|
-
const parsed = JSON.parse(
|
|
11110
|
+
const parsed = JSON.parse(readFileSync20(accountJsonPath, "utf8"));
|
|
10901
11111
|
if (op === "model") parsed.adminModel = value;
|
|
10902
11112
|
else if (op === "effort") parsed.effort = value;
|
|
10903
11113
|
else parsed.adminPermissionMode = value;
|
|
@@ -11015,7 +11225,7 @@ ${note}` : note;
|
|
|
11015
11225
|
import { resolve as resolve14 } from "path";
|
|
11016
11226
|
|
|
11017
11227
|
// app/lib/claude-agent/specialist-roster.ts
|
|
11018
|
-
import { existsSync as existsSync13, readFileSync as
|
|
11228
|
+
import { existsSync as existsSync13, readFileSync as readFileSync21, readdirSync as readdirSync14 } from "fs";
|
|
11019
11229
|
import { join as join20 } from "path";
|
|
11020
11230
|
function field(fm, name) {
|
|
11021
11231
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
@@ -11028,14 +11238,14 @@ function field(fm, name) {
|
|
|
11028
11238
|
}
|
|
11029
11239
|
function readSpecialistRoster(specialistsDir) {
|
|
11030
11240
|
if (!existsSync13(specialistsDir)) return { specialists: [], skipped: [] };
|
|
11031
|
-
const entries =
|
|
11241
|
+
const entries = readdirSync14(specialistsDir);
|
|
11032
11242
|
const specialists = [];
|
|
11033
11243
|
const skipped = [];
|
|
11034
11244
|
for (const file of entries.sort()) {
|
|
11035
11245
|
if (!file.endsWith(".md")) continue;
|
|
11036
11246
|
let raw;
|
|
11037
11247
|
try {
|
|
11038
|
-
raw =
|
|
11248
|
+
raw = readFileSync21(join20(specialistsDir, file), "utf-8");
|
|
11039
11249
|
} catch (err) {
|
|
11040
11250
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
11041
11251
|
continue;
|
|
@@ -11153,7 +11363,7 @@ var webchat_greeting_default = app6;
|
|
|
11153
11363
|
// server/routes/telegram.ts
|
|
11154
11364
|
import { homedir as homedir2 } from "os";
|
|
11155
11365
|
import { resolve as resolve15, join as join21 } from "path";
|
|
11156
|
-
import { existsSync as existsSync14, readFileSync as
|
|
11366
|
+
import { existsSync as existsSync14, readFileSync as readFileSync22 } from "fs";
|
|
11157
11367
|
|
|
11158
11368
|
// app/lib/telegram/gateway/instance.ts
|
|
11159
11369
|
var instance = null;
|
|
@@ -11215,7 +11425,7 @@ function configDirName() {
|
|
|
11215
11425
|
const brandPath = join21(platformRoot3, "config", "brand.json");
|
|
11216
11426
|
if (existsSync14(brandPath)) {
|
|
11217
11427
|
try {
|
|
11218
|
-
return JSON.parse(
|
|
11428
|
+
return JSON.parse(readFileSync22(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
11219
11429
|
} catch {
|
|
11220
11430
|
}
|
|
11221
11431
|
}
|
|
@@ -11238,7 +11448,7 @@ app7.post("/", async (c) => {
|
|
|
11238
11448
|
console.error(`${TAG23} op=reject reason=no-secret-file botType=${botType}`);
|
|
11239
11449
|
return c.json({ ok: false }, 401);
|
|
11240
11450
|
}
|
|
11241
|
-
const expected =
|
|
11451
|
+
const expected = readFileSync22(sp, "utf-8").trim();
|
|
11242
11452
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
11243
11453
|
if (got !== expected) {
|
|
11244
11454
|
console.error(`${TAG23} op=reject reason=bad-secret botType=${botType}`);
|
|
@@ -11302,7 +11512,7 @@ var telegram_default = app7;
|
|
|
11302
11512
|
|
|
11303
11513
|
// server/routes/quickbooks.ts
|
|
11304
11514
|
import { join as join22 } from "path";
|
|
11305
|
-
import { existsSync as existsSync15, readFileSync as
|
|
11515
|
+
import { existsSync as existsSync15, readFileSync as readFileSync23, writeFileSync as writeFileSync8, mkdirSync as mkdirSync4, rmSync, renameSync as renameSync5 } from "fs";
|
|
11306
11516
|
var TAG24 = "[quickbooks]";
|
|
11307
11517
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
11308
11518
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
@@ -11329,7 +11539,7 @@ async function completeConsent(args) {
|
|
|
11329
11539
|
try {
|
|
11330
11540
|
let pending;
|
|
11331
11541
|
try {
|
|
11332
|
-
pending = JSON.parse(
|
|
11542
|
+
pending = JSON.parse(readFileSync23(claimFile, "utf-8"));
|
|
11333
11543
|
} catch {
|
|
11334
11544
|
console.error(`${TAG24} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
11335
11545
|
return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
|
|
@@ -11345,7 +11555,7 @@ async function completeConsent(args) {
|
|
|
11345
11555
|
if (!existsSync15(storePath(accountDir))) {
|
|
11346
11556
|
return { ok: false, status: 500, message: "No QuickBooks credentials are stored for this account.", stateValid: true };
|
|
11347
11557
|
}
|
|
11348
|
-
const store2 = JSON.parse(
|
|
11558
|
+
const store2 = JSON.parse(readFileSync23(storePath(accountDir), "utf-8"));
|
|
11349
11559
|
const form = new URLSearchParams({
|
|
11350
11560
|
grant_type: "authorization_code",
|
|
11351
11561
|
code,
|
|
@@ -11379,7 +11589,7 @@ async function completeConsent(args) {
|
|
|
11379
11589
|
};
|
|
11380
11590
|
mkdirSync4(join22(accountDir, "secrets"), { recursive: true });
|
|
11381
11591
|
writeFileSync8(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
11382
|
-
const persisted = JSON.parse(
|
|
11592
|
+
const persisted = JSON.parse(readFileSync23(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
11383
11593
|
console.error(`${TAG24} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
11384
11594
|
return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
|
|
11385
11595
|
} finally {
|
|
@@ -11410,7 +11620,7 @@ var quickbooks_default = app8;
|
|
|
11410
11620
|
|
|
11411
11621
|
// server/routes/onboarding.ts
|
|
11412
11622
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync3 } from "child_process";
|
|
11413
|
-
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync10, writeSync, existsSync as existsSync17, readFileSync as
|
|
11623
|
+
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync10, writeSync, existsSync as existsSync17, readFileSync as readFileSync25, unlinkSync as unlinkSync3, renameSync as renameSync7 } from "fs";
|
|
11414
11624
|
import { createHash as createHash4, randomUUID as randomUUID7 } from "crypto";
|
|
11415
11625
|
|
|
11416
11626
|
// app/lib/claude-spawn-env.ts
|
|
@@ -11548,7 +11758,7 @@ function readHostCredsBlob(service) {
|
|
|
11548
11758
|
}
|
|
11549
11759
|
|
|
11550
11760
|
// ../lib/admins-write/src/index.ts
|
|
11551
|
-
import { existsSync as existsSync16, readFileSync as
|
|
11761
|
+
import { existsSync as existsSync16, readFileSync as readFileSync24, writeFileSync as writeFileSync9, renameSync as renameSync6, mkdirSync as mkdirSync5, readdirSync as readdirSync15, statSync as statSync8, appendFileSync as appendFileSync2 } from "fs";
|
|
11552
11762
|
import { dirname as dirname7, join as join23 } from "path";
|
|
11553
11763
|
function id8(value) {
|
|
11554
11764
|
return value.slice(0, 8);
|
|
@@ -11591,7 +11801,7 @@ function writeAdminEntry(input) {
|
|
|
11591
11801
|
try {
|
|
11592
11802
|
let users = [];
|
|
11593
11803
|
if (existsSync16(input.usersFile)) {
|
|
11594
|
-
const raw =
|
|
11804
|
+
const raw = readFileSync24(input.usersFile, "utf-8").trim();
|
|
11595
11805
|
if (raw) {
|
|
11596
11806
|
const parsed = JSON.parse(raw);
|
|
11597
11807
|
if (!Array.isArray(parsed)) {
|
|
@@ -11626,7 +11836,7 @@ function writeAdminEntry(input) {
|
|
|
11626
11836
|
if (!existsSync16(accountJsonPath)) {
|
|
11627
11837
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
11628
11838
|
}
|
|
11629
|
-
const config = JSON.parse(
|
|
11839
|
+
const config = JSON.parse(readFileSync24(accountJsonPath, "utf-8"));
|
|
11630
11840
|
const admins = config.admins ?? [];
|
|
11631
11841
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
11632
11842
|
result.accountJsonResult = "noop";
|
|
@@ -11648,7 +11858,7 @@ function computeAdminStoreDivergence(input) {
|
|
|
11648
11858
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
11649
11859
|
if (existsSync16(input.usersFile)) {
|
|
11650
11860
|
try {
|
|
11651
|
-
const raw =
|
|
11861
|
+
const raw = readFileSync24(input.usersFile, "utf-8").trim();
|
|
11652
11862
|
if (raw) {
|
|
11653
11863
|
const users = JSON.parse(raw);
|
|
11654
11864
|
for (const u of users) {
|
|
@@ -11663,7 +11873,7 @@ function computeAdminStoreDivergence(input) {
|
|
|
11663
11873
|
if (existsSync16(input.accountsDir)) {
|
|
11664
11874
|
let entries;
|
|
11665
11875
|
try {
|
|
11666
|
-
entries =
|
|
11876
|
+
entries = readdirSync15(input.accountsDir);
|
|
11667
11877
|
} catch (err) {
|
|
11668
11878
|
result.errors.push({ source: input.accountsDir, detail: err instanceof Error ? err.message : String(err) });
|
|
11669
11879
|
return result;
|
|
@@ -11680,7 +11890,7 @@ function computeAdminStoreDivergence(input) {
|
|
|
11680
11890
|
if (!existsSync16(accountJsonPath)) continue;
|
|
11681
11891
|
let admins = [];
|
|
11682
11892
|
try {
|
|
11683
|
-
const config = JSON.parse(
|
|
11893
|
+
const config = JSON.parse(readFileSync24(accountJsonPath, "utf-8"));
|
|
11684
11894
|
admins = config.admins ?? [];
|
|
11685
11895
|
} catch (err) {
|
|
11686
11896
|
result.errors.push({ source: accountJsonPath, detail: err instanceof Error ? err.message : String(err) });
|
|
@@ -11729,7 +11939,7 @@ function hashPin2(pin) {
|
|
|
11729
11939
|
}
|
|
11730
11940
|
function readUsersFile2() {
|
|
11731
11941
|
if (!existsSync17(USERS_FILE)) return null;
|
|
11732
|
-
const raw =
|
|
11942
|
+
const raw = readFileSync25(USERS_FILE, "utf-8").trim();
|
|
11733
11943
|
if (!raw) return [];
|
|
11734
11944
|
return JSON.parse(raw);
|
|
11735
11945
|
}
|
|
@@ -11939,7 +12149,7 @@ app9.post("/set-pin", async (c) => {
|
|
|
11939
12149
|
let installOwner = null;
|
|
11940
12150
|
if (existsSync17(INSTALL_OWNER_FILE)) {
|
|
11941
12151
|
try {
|
|
11942
|
-
const raw =
|
|
12152
|
+
const raw = readFileSync25(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
11943
12153
|
if (raw.length > 0) installOwner = raw;
|
|
11944
12154
|
} catch (err) {
|
|
11945
12155
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -12087,7 +12297,7 @@ app9.put("/set-pin", requireAdminSession, async (c) => {
|
|
|
12087
12297
|
let installOwner = null;
|
|
12088
12298
|
if (existsSync17(INSTALL_OWNER_FILE)) {
|
|
12089
12299
|
try {
|
|
12090
|
-
const raw =
|
|
12300
|
+
const raw = readFileSync25(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
12091
12301
|
if (raw.length > 0) installOwner = raw;
|
|
12092
12302
|
} catch (err) {
|
|
12093
12303
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -12489,7 +12699,7 @@ app12.get("/", requireAdminSession, async (c) => {
|
|
|
12489
12699
|
var accounts_default = app12;
|
|
12490
12700
|
|
|
12491
12701
|
// server/routes/admin/logs.ts
|
|
12492
|
-
import { existsSync as existsSync20, readdirSync as
|
|
12702
|
+
import { existsSync as existsSync20, readdirSync as readdirSync16, readFileSync as readFileSync26, statSync as statSync10 } from "fs";
|
|
12493
12703
|
import { resolve as resolve16, basename as basename7 } from "path";
|
|
12494
12704
|
|
|
12495
12705
|
// app/lib/logs-read-resolve.ts
|
|
@@ -12528,7 +12738,7 @@ app13.get("/", async (c) => {
|
|
|
12528
12738
|
const filePath = resolve16(dir, safe);
|
|
12529
12739
|
searched.push(filePath);
|
|
12530
12740
|
try {
|
|
12531
|
-
const buffer =
|
|
12741
|
+
const buffer = readFileSync26(filePath);
|
|
12532
12742
|
const onDiskBytes = statSync10(filePath).size;
|
|
12533
12743
|
const headers = {
|
|
12534
12744
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -12593,7 +12803,7 @@ app13.get("/", async (c) => {
|
|
|
12593
12803
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
12594
12804
|
try {
|
|
12595
12805
|
const filename = basename7(hit.path);
|
|
12596
|
-
const buffer =
|
|
12806
|
+
const buffer = readFileSync26(hit.path);
|
|
12597
12807
|
const onDiskBytes = statSync10(hit.path).size;
|
|
12598
12808
|
const headers = {
|
|
12599
12809
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -12631,7 +12841,7 @@ app13.get("/", async (c) => {
|
|
|
12631
12841
|
if (!existsSync20(dir)) continue;
|
|
12632
12842
|
let files;
|
|
12633
12843
|
try {
|
|
12634
|
-
files =
|
|
12844
|
+
files = readdirSync16(dir).filter((f) => f.endsWith(".log"));
|
|
12635
12845
|
} catch (err) {
|
|
12636
12846
|
const reason = err instanceof Error ? err.message : String(err);
|
|
12637
12847
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
@@ -12640,7 +12850,7 @@ app13.get("/", async (c) => {
|
|
|
12640
12850
|
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync10(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
12641
12851
|
seen.add(name);
|
|
12642
12852
|
try {
|
|
12643
|
-
const content =
|
|
12853
|
+
const content = readFileSync26(resolve16(dir, name));
|
|
12644
12854
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
12645
12855
|
logs[name] = tail.trim() || "(empty)";
|
|
12646
12856
|
} catch (err) {
|
|
@@ -12683,7 +12893,7 @@ import { readFile as readFile2, readdir } from "fs/promises";
|
|
|
12683
12893
|
import { existsSync as existsSync21 } from "fs";
|
|
12684
12894
|
import { resolve as resolve17 } from "path";
|
|
12685
12895
|
var app15 = new Hono();
|
|
12686
|
-
var
|
|
12896
|
+
var ATTACHMENT_ID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12687
12897
|
function uploadsDirFor2(accountId, attachmentId) {
|
|
12688
12898
|
return resolve17(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
12689
12899
|
}
|
|
@@ -12697,7 +12907,7 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
12697
12907
|
console.log(`[admin-attachment] op=miss attachmentId=${shortId2} session=${shortSession} status=401 reason=no-account`);
|
|
12698
12908
|
return new Response("Unauthorized", { status: 401 });
|
|
12699
12909
|
}
|
|
12700
|
-
if (!
|
|
12910
|
+
if (!ATTACHMENT_ID_RE3.test(attachmentId)) {
|
|
12701
12911
|
console.log(`[admin-attachment] op=miss attachmentId=${shortId2} session=${shortSession} status=404 reason=bad-id`);
|
|
12702
12912
|
return new Response("Not found", { status: 404 });
|
|
12703
12913
|
}
|
|
@@ -12739,10 +12949,16 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
12739
12949
|
}
|
|
12740
12950
|
const filePath = resolve17(dir, dataFile);
|
|
12741
12951
|
const buffer = await readFile2(filePath);
|
|
12952
|
+
const inlineSafe = isInlineSafeMime(meta.mimeType);
|
|
12953
|
+
const safeName = meta.filename.replace(/["\\\r\n]/g, "_");
|
|
12954
|
+
if (!inlineSafe) {
|
|
12955
|
+
console.log(`[admin-attachment] op=served attachmentId=${shortId2} disposition=attachment reason=non-preview-mime mime=${meta.mimeType}`);
|
|
12956
|
+
}
|
|
12742
12957
|
return new Response(new Uint8Array(buffer), {
|
|
12743
12958
|
headers: {
|
|
12744
12959
|
"Content-Type": meta.mimeType,
|
|
12745
|
-
"Content-Disposition":
|
|
12960
|
+
"Content-Disposition": `${inlineSafe ? "inline" : "attachment"}; filename="${safeName}"`,
|
|
12961
|
+
"X-Content-Type-Options": "nosniff",
|
|
12746
12962
|
"Cache-Control": "private, max-age=3600"
|
|
12747
12963
|
}
|
|
12748
12964
|
});
|
|
@@ -12751,7 +12967,7 @@ var attachment_default = app15;
|
|
|
12751
12967
|
|
|
12752
12968
|
// server/routes/admin/agents.ts
|
|
12753
12969
|
import { resolve as resolve18 } from "path";
|
|
12754
|
-
import { readdirSync as
|
|
12970
|
+
import { readdirSync as readdirSync17, readFileSync as readFileSync27, existsSync as existsSync22, rmSync as rmSync2 } from "fs";
|
|
12755
12971
|
var app16 = new Hono();
|
|
12756
12972
|
app16.get("/", (c) => {
|
|
12757
12973
|
const account = resolveAccount();
|
|
@@ -12760,14 +12976,14 @@ app16.get("/", (c) => {
|
|
|
12760
12976
|
if (!existsSync22(agentsDir)) return c.json({ agents: [] });
|
|
12761
12977
|
const agents = [];
|
|
12762
12978
|
try {
|
|
12763
|
-
const entries =
|
|
12979
|
+
const entries = readdirSync17(agentsDir, { withFileTypes: true });
|
|
12764
12980
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
12765
12981
|
if (!entry.isDirectory()) continue;
|
|
12766
12982
|
if (entry.name === "admin") continue;
|
|
12767
12983
|
const configPath2 = resolve18(agentsDir, entry.name, "config.json");
|
|
12768
12984
|
if (!existsSync22(configPath2)) continue;
|
|
12769
12985
|
try {
|
|
12770
|
-
const config = JSON.parse(
|
|
12986
|
+
const config = JSON.parse(readFileSync27(configPath2, "utf-8"));
|
|
12771
12987
|
agents.push({
|
|
12772
12988
|
slug: entry.name,
|
|
12773
12989
|
displayName: config.displayName ?? entry.name,
|
|
@@ -13526,7 +13742,7 @@ app17.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
13526
13742
|
var sessions_default = app17;
|
|
13527
13743
|
|
|
13528
13744
|
// app/lib/claude-agent/spawn-context.ts
|
|
13529
|
-
import { existsSync as existsSync24, readFileSync as
|
|
13745
|
+
import { existsSync as existsSync24, readFileSync as readFileSync28, readdirSync as readdirSync18, statSync as statSync11 } from "fs";
|
|
13530
13746
|
import { dirname as dirname9, resolve as resolve19, join as join27 } from "path";
|
|
13531
13747
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
13532
13748
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
@@ -13575,7 +13791,7 @@ function extractPluginToolDescriptions(pluginDir) {
|
|
|
13575
13791
|
for (const path2 of candidates) {
|
|
13576
13792
|
if (!existsSync24(path2)) continue;
|
|
13577
13793
|
try {
|
|
13578
|
-
raw =
|
|
13794
|
+
raw = readFileSync28(path2, "utf-8");
|
|
13579
13795
|
break;
|
|
13580
13796
|
} catch {
|
|
13581
13797
|
}
|
|
@@ -13626,7 +13842,7 @@ function listPluginDirs() {
|
|
|
13626
13842
|
const out = /* @__PURE__ */ new Map();
|
|
13627
13843
|
const platformPlugins = resolve19(PLATFORM_ROOT, "plugins");
|
|
13628
13844
|
if (existsSync24(platformPlugins)) {
|
|
13629
|
-
for (const name of
|
|
13845
|
+
for (const name of readdirSync18(platformPlugins)) {
|
|
13630
13846
|
const dir = join27(platformPlugins, name);
|
|
13631
13847
|
try {
|
|
13632
13848
|
if (statSync11(dir).isDirectory()) out.set(name, dir);
|
|
@@ -13636,11 +13852,11 @@ function listPluginDirs() {
|
|
|
13636
13852
|
}
|
|
13637
13853
|
const premiumRoot = resolve19(dirname9(PLATFORM_ROOT), "premium-plugins");
|
|
13638
13854
|
if (existsSync24(premiumRoot)) {
|
|
13639
|
-
for (const bundle of
|
|
13855
|
+
for (const bundle of readdirSync18(premiumRoot)) {
|
|
13640
13856
|
const bundlePlugins = join27(premiumRoot, bundle, "plugins");
|
|
13641
13857
|
if (!existsSync24(bundlePlugins)) continue;
|
|
13642
13858
|
try {
|
|
13643
|
-
for (const name of
|
|
13859
|
+
for (const name of readdirSync18(bundlePlugins)) {
|
|
13644
13860
|
const dir = join27(bundlePlugins, name);
|
|
13645
13861
|
try {
|
|
13646
13862
|
if (statSync11(dir).isDirectory()) out.set(name, dir);
|
|
@@ -13657,7 +13873,7 @@ function readEnabledPlugins(accountId) {
|
|
|
13657
13873
|
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
13658
13874
|
if (!existsSync24(accountFile)) return /* @__PURE__ */ new Set();
|
|
13659
13875
|
try {
|
|
13660
|
-
const parsed = JSON.parse(
|
|
13876
|
+
const parsed = JSON.parse(readFileSync28(accountFile, "utf-8"));
|
|
13661
13877
|
return new Set(
|
|
13662
13878
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
13663
13879
|
);
|
|
@@ -13669,7 +13885,7 @@ function readFrontmatter(path2) {
|
|
|
13669
13885
|
if (!existsSync24(path2)) return null;
|
|
13670
13886
|
let raw;
|
|
13671
13887
|
try {
|
|
13672
|
-
raw =
|
|
13888
|
+
raw = readFileSync28(path2, "utf-8");
|
|
13673
13889
|
} catch {
|
|
13674
13890
|
return null;
|
|
13675
13891
|
}
|
|
@@ -13731,7 +13947,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
13731
13947
|
if (!existsSync24(specialistsDir)) return [];
|
|
13732
13948
|
let entries;
|
|
13733
13949
|
try {
|
|
13734
|
-
entries =
|
|
13950
|
+
entries = readdirSync18(specialistsDir);
|
|
13735
13951
|
} catch {
|
|
13736
13952
|
return [];
|
|
13737
13953
|
}
|
|
@@ -13777,7 +13993,7 @@ function computeDormantPlugins(accountId) {
|
|
|
13777
13993
|
if (!existsSync24(accountFile)) return [];
|
|
13778
13994
|
let enabled;
|
|
13779
13995
|
try {
|
|
13780
|
-
const raw =
|
|
13996
|
+
const raw = readFileSync28(accountFile, "utf-8");
|
|
13781
13997
|
const parsed = JSON.parse(raw);
|
|
13782
13998
|
enabled = new Set(
|
|
13783
13999
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -13792,7 +14008,7 @@ function computeDormantPlugins(accountId) {
|
|
|
13792
14008
|
if (!existsSync24(pluginsDir)) return [];
|
|
13793
14009
|
let entries;
|
|
13794
14010
|
try {
|
|
13795
|
-
entries =
|
|
14011
|
+
entries = readdirSync18(pluginsDir);
|
|
13796
14012
|
} catch {
|
|
13797
14013
|
return [];
|
|
13798
14014
|
}
|
|
@@ -13803,7 +14019,7 @@ function computeDormantPlugins(accountId) {
|
|
|
13803
14019
|
if (!existsSync24(manifestPath)) continue;
|
|
13804
14020
|
let manifest;
|
|
13805
14021
|
try {
|
|
13806
|
-
manifest =
|
|
14022
|
+
manifest = readFileSync28(manifestPath, "utf-8");
|
|
13807
14023
|
} catch {
|
|
13808
14024
|
continue;
|
|
13809
14025
|
}
|
|
@@ -13817,13 +14033,13 @@ function computeDormantPlugins(accountId) {
|
|
|
13817
14033
|
}
|
|
13818
14034
|
|
|
13819
14035
|
// server/routes/admin/claude-sessions.ts
|
|
13820
|
-
import { existsSync as existsSync25, readFileSync as
|
|
14036
|
+
import { existsSync as existsSync25, readFileSync as readFileSync29 } from "fs";
|
|
13821
14037
|
import { resolve as resolve20 } from "path";
|
|
13822
14038
|
function readTunnelState(brandConfigDir) {
|
|
13823
14039
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
13824
14040
|
if (!existsSync25(statePath)) return null;
|
|
13825
14041
|
try {
|
|
13826
|
-
const parsed = JSON.parse(
|
|
14042
|
+
const parsed = JSON.parse(readFileSync29(statePath, "utf-8"));
|
|
13827
14043
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
13828
14044
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
13829
14045
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -13837,7 +14053,7 @@ function resolveTunnelUrl() {
|
|
|
13837
14053
|
const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
13838
14054
|
let brand;
|
|
13839
14055
|
try {
|
|
13840
|
-
brand = JSON.parse(
|
|
14056
|
+
brand = JSON.parse(readFileSync29(resolve20(platformRoot3, "config", "brand.json"), "utf-8"));
|
|
13841
14057
|
} catch {
|
|
13842
14058
|
return null;
|
|
13843
14059
|
}
|
|
@@ -14080,7 +14296,7 @@ var events_default = app20;
|
|
|
14080
14296
|
|
|
14081
14297
|
// server/routes/admin/files.ts
|
|
14082
14298
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync26 } from "fs";
|
|
14083
|
-
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename } from "fs/promises";
|
|
14299
|
+
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename, rmdir } from "fs/promises";
|
|
14084
14300
|
import { realpathSync as realpathSync5 } from "fs";
|
|
14085
14301
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
14086
14302
|
import { basename as basename9, dirname as dirname10, join as join29, relative as relative4, resolve as resolve22, sep as sep6 } from "path";
|
|
@@ -14958,19 +15174,55 @@ async function readAccountNames() {
|
|
|
14958
15174
|
}
|
|
14959
15175
|
return map;
|
|
14960
15176
|
}
|
|
15177
|
+
async function servableFilesIn(dirAbs, uuid) {
|
|
15178
|
+
const metaName = `${uuid}.meta.json`;
|
|
15179
|
+
let dirents;
|
|
15180
|
+
try {
|
|
15181
|
+
dirents = await readdir3(dirAbs, { withFileTypes: true });
|
|
15182
|
+
} catch {
|
|
15183
|
+
return [];
|
|
15184
|
+
}
|
|
15185
|
+
const out = [];
|
|
15186
|
+
for (const d of dirents) {
|
|
15187
|
+
if (!d.isFile()) continue;
|
|
15188
|
+
if (d.name === metaName) continue;
|
|
15189
|
+
if (d.name.endsWith(EXTRACTED_TEXT_SUFFIX)) continue;
|
|
15190
|
+
out.push(d.name);
|
|
15191
|
+
}
|
|
15192
|
+
return out;
|
|
15193
|
+
}
|
|
14961
15194
|
async function enrich(absolute, entry, accountNames) {
|
|
14962
15195
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
14963
|
-
const
|
|
15196
|
+
const dirAbs = join29(absolute, entry.name);
|
|
15197
|
+
const meta = await readMeta(dirAbs, entry.name);
|
|
14964
15198
|
if (meta?.filename) {
|
|
15199
|
+
const servable = await servableFilesIn(dirAbs, entry.name);
|
|
15200
|
+
if (servable.length === 1) {
|
|
15201
|
+
const innerName = servable[0];
|
|
15202
|
+
let size = null;
|
|
15203
|
+
let modifiedAt = entry.modifiedAt;
|
|
15204
|
+
try {
|
|
15205
|
+
const st = await stat4(join29(dirAbs, innerName));
|
|
15206
|
+
size = st.size;
|
|
15207
|
+
modifiedAt = st.mtime.toISOString();
|
|
15208
|
+
} catch {
|
|
15209
|
+
}
|
|
15210
|
+
entry.kind = "file";
|
|
15211
|
+
entry.displayName = meta.filename;
|
|
15212
|
+
entry.mimeType = meta.mimeType;
|
|
15213
|
+
entry.sizeBytes = size;
|
|
15214
|
+
entry.modifiedAt = modifiedAt;
|
|
15215
|
+
entry.entryPath = `${entry.name}/${innerName}`;
|
|
15216
|
+
return "flattened";
|
|
15217
|
+
}
|
|
14965
15218
|
entry.displayName = meta.filename;
|
|
14966
|
-
|
|
14967
|
-
return;
|
|
15219
|
+
return "kept-as-dir";
|
|
14968
15220
|
}
|
|
14969
15221
|
const accountName = accountNames.get(entry.name);
|
|
14970
15222
|
if (accountName) {
|
|
14971
15223
|
entry.displayName = accountName;
|
|
14972
15224
|
}
|
|
14973
|
-
return;
|
|
15225
|
+
return null;
|
|
14974
15226
|
}
|
|
14975
15227
|
if (entry.kind === "file") {
|
|
14976
15228
|
const dot = entry.name.lastIndexOf(".");
|
|
@@ -14983,6 +15235,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
14983
15235
|
}
|
|
14984
15236
|
}
|
|
14985
15237
|
}
|
|
15238
|
+
return null;
|
|
14986
15239
|
}
|
|
14987
15240
|
function buildDisplayPath(relPath, accountNames) {
|
|
14988
15241
|
if (relPath === "." || relPath === "") return [];
|
|
@@ -15138,8 +15391,18 @@ app21.get("/", requireAdminSession, async (c) => {
|
|
|
15138
15391
|
}
|
|
15139
15392
|
}
|
|
15140
15393
|
const accountNames = await readAccountNames();
|
|
15141
|
-
await Promise.all(entries.map((e) => enrich(absolute, e, accountNames)));
|
|
15394
|
+
const classes = await Promise.all(entries.map((e) => enrich(absolute, e, accountNames)));
|
|
15142
15395
|
sortDirEntries(entries);
|
|
15396
|
+
let flattened = 0;
|
|
15397
|
+
let keptAsDir = 0;
|
|
15398
|
+
for (const cls of classes) {
|
|
15399
|
+
if (cls === "flattened") flattened++;
|
|
15400
|
+
else if (cls === "kept-as-dir") keptAsDir++;
|
|
15401
|
+
}
|
|
15402
|
+
const containers = flattened + keptAsDir;
|
|
15403
|
+
if (containers > 0) {
|
|
15404
|
+
console.error(`[data] op=uploads-flatten containers=${containers} flattened=${flattened} kept-as-dir=${keptAsDir}`);
|
|
15405
|
+
}
|
|
15143
15406
|
const displayPath = buildDisplayPath(relPath, accountNames);
|
|
15144
15407
|
console.error(`[data] file-list path="${relPath}" entries=${entries.length}`);
|
|
15145
15408
|
return c.json({ path: relPath, displayPath, entries });
|
|
@@ -15228,8 +15491,16 @@ app21.get("/download", requireAdminSession, async (c) => {
|
|
|
15228
15491
|
});
|
|
15229
15492
|
}
|
|
15230
15493
|
console.error(`[data] file-download root="${root}" path="${relPath}" size=${info.size}`);
|
|
15231
|
-
|
|
15232
|
-
|
|
15494
|
+
let downloadName = filename;
|
|
15495
|
+
if (root === "data") {
|
|
15496
|
+
const parsed = parseAttachmentPath(relPath);
|
|
15497
|
+
if (parsed) {
|
|
15498
|
+
const meta = await readMeta(dirname10(absolute), parsed.attachmentId);
|
|
15499
|
+
if (meta?.filename) downloadName = meta.filename;
|
|
15500
|
+
}
|
|
15501
|
+
}
|
|
15502
|
+
const safeQuotedName = downloadName.replace(/[\r\n"\\]/g, "_");
|
|
15503
|
+
const encodedName = encodeURIComponent(downloadName);
|
|
15233
15504
|
return new Response(webStream, {
|
|
15234
15505
|
status: 200,
|
|
15235
15506
|
headers: {
|
|
@@ -15324,7 +15595,13 @@ app21.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
15324
15595
|
if (over) return over;
|
|
15325
15596
|
}
|
|
15326
15597
|
} else if (info.isFile()) {
|
|
15327
|
-
|
|
15598
|
+
let member = basename9(absolute);
|
|
15599
|
+
const parsed = parseAttachmentPath(relPath);
|
|
15600
|
+
if (parsed) {
|
|
15601
|
+
const meta = await readMeta(dirname10(absolute), parsed.attachmentId);
|
|
15602
|
+
if (meta?.filename) member = meta.filename;
|
|
15603
|
+
}
|
|
15604
|
+
const over = await addFile(absolute, info.size, member);
|
|
15328
15605
|
if (over) return over;
|
|
15329
15606
|
} else {
|
|
15330
15607
|
return c.json({ error: "Path is not a file or directory" }, 400);
|
|
@@ -15744,7 +16021,9 @@ app21.delete("/", requireAdminSession, async (c) => {
|
|
|
15744
16021
|
}
|
|
15745
16022
|
const dot = base.lastIndexOf(".");
|
|
15746
16023
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
15747
|
-
const
|
|
16024
|
+
const containerDir = dirname10(absolute);
|
|
16025
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join29(containerDir, `${stem}.meta.json`) : null;
|
|
16026
|
+
const isAttachmentContainer = UUID_RE3.test(stem) && basename9(containerDir) === stem;
|
|
15748
16027
|
await unlink2(absolute);
|
|
15749
16028
|
if (sidecarPath) {
|
|
15750
16029
|
try {
|
|
@@ -15752,6 +16031,12 @@ app21.delete("/", requireAdminSession, async (c) => {
|
|
|
15752
16031
|
} catch {
|
|
15753
16032
|
}
|
|
15754
16033
|
}
|
|
16034
|
+
if (isAttachmentContainer) {
|
|
16035
|
+
await unlink2(join29(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
|
|
16036
|
+
});
|
|
16037
|
+
await rmdir(containerDir).catch(() => {
|
|
16038
|
+
});
|
|
16039
|
+
}
|
|
15755
16040
|
console.error(`[data] file-delete path="${relPath}" bytes=${info.size}`);
|
|
15756
16041
|
try {
|
|
15757
16042
|
await dropFileIndex(accountId, relPath);
|
|
@@ -16850,6 +17135,142 @@ function isHiddenByDefault(label) {
|
|
|
16850
17135
|
return HIDDEN_BY_DEFAULT_LABELS.has(label);
|
|
16851
17136
|
}
|
|
16852
17137
|
|
|
17138
|
+
// server/lib/top-level-labels.ts
|
|
17139
|
+
import { readdirSync as readdirSync19, readFileSync as readFileSync30 } from "fs";
|
|
17140
|
+
import { join as join30, resolve as resolve23 } from "path";
|
|
17141
|
+
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
17142
|
+
/* @__PURE__ */ new Set([
|
|
17143
|
+
// Base-schema infra (schema-base.md has no top-level section).
|
|
17144
|
+
"LocalBusiness",
|
|
17145
|
+
"Service",
|
|
17146
|
+
"PriceSpecification",
|
|
17147
|
+
"OpeningHoursSpecification",
|
|
17148
|
+
"Organization",
|
|
17149
|
+
"Person",
|
|
17150
|
+
"UserProfile",
|
|
17151
|
+
"Preference",
|
|
17152
|
+
"AdminUser",
|
|
17153
|
+
"AccessGrant",
|
|
17154
|
+
"KnowledgeDocument",
|
|
17155
|
+
"DigitalDocument",
|
|
17156
|
+
"CreativeWork",
|
|
17157
|
+
"Question",
|
|
17158
|
+
"FAQPage",
|
|
17159
|
+
"DefinedTerm",
|
|
17160
|
+
"Review",
|
|
17161
|
+
"ImageObject",
|
|
17162
|
+
"Invoice",
|
|
17163
|
+
"Task",
|
|
17164
|
+
"Project",
|
|
17165
|
+
"Event",
|
|
17166
|
+
"Workflow",
|
|
17167
|
+
"Email",
|
|
17168
|
+
"EmailAccount",
|
|
17169
|
+
"Agent",
|
|
17170
|
+
// Knowledge-work vertical: schema-knowledge-work.md has no top-level
|
|
17171
|
+
// section yet.
|
|
17172
|
+
"Objective",
|
|
17173
|
+
"KeyResult",
|
|
17174
|
+
"Decision",
|
|
17175
|
+
"Risk",
|
|
17176
|
+
"Source",
|
|
17177
|
+
"Finding",
|
|
17178
|
+
"Hypothesis"
|
|
17179
|
+
])
|
|
17180
|
+
);
|
|
17181
|
+
function splitPipeRow(row) {
|
|
17182
|
+
let trimmed = row.trim();
|
|
17183
|
+
if (trimmed.startsWith("|")) trimmed = trimmed.slice(1);
|
|
17184
|
+
if (trimmed.endsWith("|")) trimmed = trimmed.slice(0, -1);
|
|
17185
|
+
const cells = [];
|
|
17186
|
+
let inBacktick = false;
|
|
17187
|
+
let start = 0;
|
|
17188
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
17189
|
+
const ch = trimmed[i];
|
|
17190
|
+
if (ch === "`") inBacktick = !inBacktick;
|
|
17191
|
+
else if (ch === "|" && !inBacktick) {
|
|
17192
|
+
cells.push(trimmed.slice(start, i).trim());
|
|
17193
|
+
start = i + 1;
|
|
17194
|
+
}
|
|
17195
|
+
}
|
|
17196
|
+
cells.push(trimmed.slice(start).trim());
|
|
17197
|
+
return cells;
|
|
17198
|
+
}
|
|
17199
|
+
var stripBackticks = (s) => s.replace(/`/g, "").trim();
|
|
17200
|
+
function parseTopLevelLabels(content) {
|
|
17201
|
+
const lines = content.split(/\r?\n/);
|
|
17202
|
+
let i = 0;
|
|
17203
|
+
while (i < lines.length) {
|
|
17204
|
+
if (lines[i].toLowerCase().startsWith("## top-level node types")) break;
|
|
17205
|
+
i++;
|
|
17206
|
+
}
|
|
17207
|
+
if (i >= lines.length) return [];
|
|
17208
|
+
i++;
|
|
17209
|
+
for (; i < lines.length - 1; i++) {
|
|
17210
|
+
const line = lines[i];
|
|
17211
|
+
if (line.startsWith("## ")) return [];
|
|
17212
|
+
if (!line.includes("|")) continue;
|
|
17213
|
+
const sep9 = lines[i + 1];
|
|
17214
|
+
if (!/^\s*\|?[\s:|-]+\|?\s*$/.test(sep9) || !sep9.includes("-")) continue;
|
|
17215
|
+
const headers = splitPipeRow(line).map((h) => stripBackticks(h).toLowerCase());
|
|
17216
|
+
const labelCol = headers.findIndex((h) => h === "neo4j label");
|
|
17217
|
+
if (labelCol === -1) return [];
|
|
17218
|
+
const out = [];
|
|
17219
|
+
let j = i + 2;
|
|
17220
|
+
for (; j < lines.length; j++) {
|
|
17221
|
+
const row = lines[j];
|
|
17222
|
+
if (!row.trim() || !row.includes("|")) break;
|
|
17223
|
+
const cells = splitPipeRow(row);
|
|
17224
|
+
const label = stripBackticks(cells[labelCol] ?? "");
|
|
17225
|
+
if (label) out.push(label);
|
|
17226
|
+
}
|
|
17227
|
+
return out;
|
|
17228
|
+
}
|
|
17229
|
+
return [];
|
|
17230
|
+
}
|
|
17231
|
+
function resolveReferencesDir() {
|
|
17232
|
+
if (process.env.MAXY_PLATFORM_ROOT) {
|
|
17233
|
+
return join30(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
|
|
17234
|
+
}
|
|
17235
|
+
return resolve23(import.meta.dirname, "../../../plugins/memory/references");
|
|
17236
|
+
}
|
|
17237
|
+
function parseTableTopLevelLabels(referencesDir) {
|
|
17238
|
+
const labels = /* @__PURE__ */ new Set();
|
|
17239
|
+
const contributingFiles = [];
|
|
17240
|
+
try {
|
|
17241
|
+
const fileNames = readdirSync19(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
|
|
17242
|
+
for (const fileName of fileNames) {
|
|
17243
|
+
const content = readFileSync30(join30(referencesDir, fileName), "utf-8");
|
|
17244
|
+
const parsed = parseTopLevelLabels(content);
|
|
17245
|
+
if (parsed.length > 0) contributingFiles.push(fileName);
|
|
17246
|
+
for (const label of parsed) labels.add(label);
|
|
17247
|
+
}
|
|
17248
|
+
} catch (err) {
|
|
17249
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
17250
|
+
process.stderr.write(
|
|
17251
|
+
`[graph-page] op=top-level-labels source=ontology status=error dir=${referencesDir} reason="${message}"
|
|
17252
|
+
`
|
|
17253
|
+
);
|
|
17254
|
+
throw err;
|
|
17255
|
+
}
|
|
17256
|
+
return { labels, contributingFiles };
|
|
17257
|
+
}
|
|
17258
|
+
var cached = null;
|
|
17259
|
+
function getTopLevelLabelAllowlist(opts = {}) {
|
|
17260
|
+
if (!opts.referencesDir && cached) return cached;
|
|
17261
|
+
const referencesDir = opts.referencesDir ?? resolveReferencesDir();
|
|
17262
|
+
const { labels: derived, contributingFiles } = parseTableTopLevelLabels(referencesDir);
|
|
17263
|
+
const derivedCount = derived.size;
|
|
17264
|
+
for (const label of STATIC_TOP_LEVEL_LABELS) derived.add(label);
|
|
17265
|
+
const result = Object.freeze(derived);
|
|
17266
|
+
process.stderr.write(
|
|
17267
|
+
`[graph-page] op=top-level-labels source=ontology count=${derived.size} files=${contributingFiles.join("|") || "none"} derived=${derivedCount} static=${STATIC_TOP_LEVEL_LABELS.size}
|
|
17268
|
+
`
|
|
17269
|
+
);
|
|
17270
|
+
if (!opts.referencesDir) cached = result;
|
|
17271
|
+
return result;
|
|
17272
|
+
}
|
|
17273
|
+
|
|
16853
17274
|
// server/routes/admin/graph-subgraph.ts
|
|
16854
17275
|
var CEILING = 2e3;
|
|
16855
17276
|
var TOP_LEVEL_LIMIT = 1e3;
|
|
@@ -16971,7 +17392,7 @@ async function handleDefault(c, accountId) {
|
|
|
16971
17392
|
}
|
|
16972
17393
|
async function handleDefaultTopLevel(c, accountId, flags) {
|
|
16973
17394
|
const { includeTrashed, includeAgentActions } = flags;
|
|
16974
|
-
const labels = [...
|
|
17395
|
+
const labels = [...getTopLevelLabelAllowlist()].filter((l) => !HIDDEN_BY_DEFAULT_LABELS.has(l));
|
|
16975
17396
|
const agentActionLabels = [...AGENT_ACTION_LABELS];
|
|
16976
17397
|
const started = Date.now();
|
|
16977
17398
|
const session = getSession();
|
|
@@ -17782,7 +18203,7 @@ app26.get("/", requireAdminSession, async (c) => {
|
|
|
17782
18203
|
const started = Date.now();
|
|
17783
18204
|
const session = getSession();
|
|
17784
18205
|
try {
|
|
17785
|
-
const allowedSet = new Set(
|
|
18206
|
+
const allowedSet = new Set(getTopLevelLabelAllowlist());
|
|
17786
18207
|
if (includeAgentActions) {
|
|
17787
18208
|
for (const label of AGENT_ACTION_LABELS) allowedSet.add(label);
|
|
17788
18209
|
}
|
|
@@ -17944,12 +18365,12 @@ function validateBody(body) {
|
|
|
17944
18365
|
if (typeof lbl !== "string") {
|
|
17945
18366
|
return { ok: false, code: "shape", reason: "labels must be an array of strings" };
|
|
17946
18367
|
}
|
|
17947
|
-
if (!
|
|
18368
|
+
if (!getTopLevelLabelAllowlist().has(lbl)) {
|
|
17948
18369
|
return {
|
|
17949
18370
|
ok: false,
|
|
17950
18371
|
code: "not-eligible-chip",
|
|
17951
18372
|
label: lbl,
|
|
17952
|
-
reason: `label "${lbl}" is not eligible for default view \u2014 outside the chip allowlist
|
|
18373
|
+
reason: `label "${lbl}" is not eligible for default view \u2014 outside the chip allowlist`
|
|
17953
18374
|
};
|
|
17954
18375
|
}
|
|
17955
18376
|
seen.add(lbl);
|
|
@@ -17972,7 +18393,7 @@ var graph_default_view_default = app27;
|
|
|
17972
18393
|
|
|
17973
18394
|
// server/routes/admin/sidebar-artefacts.ts
|
|
17974
18395
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
17975
|
-
import { resolve as
|
|
18396
|
+
import { resolve as resolve24, relative as relative5, isAbsolute as isAbsolute2, sep as sep7, basename as basename10 } from "path";
|
|
17976
18397
|
import { existsSync as existsSync27 } from "fs";
|
|
17977
18398
|
var LIMIT = 50;
|
|
17978
18399
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
@@ -17992,7 +18413,7 @@ app28.get("/", requireAdminSession, async (c) => {
|
|
|
17992
18413
|
if (accountFiles === null) {
|
|
17993
18414
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
17994
18415
|
}
|
|
17995
|
-
const accountDir =
|
|
18416
|
+
const accountDir = resolve24(ACCOUNTS_DIR, accountId);
|
|
17996
18417
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
17997
18418
|
const artefacts = [...accountFiles, ...agents].sort(
|
|
17998
18419
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -18044,8 +18465,8 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
18044
18465
|
async function fetchAgentTemplateRows(accountDir) {
|
|
18045
18466
|
const rows = [];
|
|
18046
18467
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
18047
|
-
const overridePath =
|
|
18048
|
-
const bundledPath =
|
|
18468
|
+
const overridePath = resolve24(accountDir, "agents", "admin", filename);
|
|
18469
|
+
const bundledPath = resolve24(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
18049
18470
|
const labelStem = filename.replace(/\.md$/, "");
|
|
18050
18471
|
const row = await readAgentTemplateRow({
|
|
18051
18472
|
id: `agent-template:admin:${filename}`,
|
|
@@ -18058,12 +18479,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
18058
18479
|
});
|
|
18059
18480
|
if (row) rows.push(row);
|
|
18060
18481
|
}
|
|
18061
|
-
const overrideDir =
|
|
18062
|
-
const bundledDir =
|
|
18482
|
+
const overrideDir = resolve24(accountDir, "specialists", "agents");
|
|
18483
|
+
const bundledDir = resolve24(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
18063
18484
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
18064
18485
|
for (const filename of specialistNames) {
|
|
18065
|
-
const overridePath =
|
|
18066
|
-
const bundledPath =
|
|
18486
|
+
const overridePath = resolve24(overrideDir, filename);
|
|
18487
|
+
const bundledPath = resolve24(bundledDir, filename);
|
|
18067
18488
|
const row = await readAgentTemplateRow({
|
|
18068
18489
|
id: `agent-template:specialist:${filename}`,
|
|
18069
18490
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -18345,7 +18766,7 @@ var session_usage_default = app33;
|
|
|
18345
18766
|
|
|
18346
18767
|
// server/routes/admin/session-rc-spawn.ts
|
|
18347
18768
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
18348
|
-
var
|
|
18769
|
+
var ACCOUNT_UUID_RE3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
18349
18770
|
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, adminUserId, authenticatedName, callerAccountId) {
|
|
18350
18771
|
const operator = isOperatorHost(host, operatorDomains);
|
|
18351
18772
|
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
@@ -18356,8 +18777,8 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, ad
|
|
|
18356
18777
|
const pickedModel = kind === "new" && typeof body.model === "string" && isSelectableModel(body.model) ? body.model : null;
|
|
18357
18778
|
const pickedEffort = kind === "new" && typeof body.effort === "string" && isNewSessionEffortLevel(body.effort) ? body.effort : null;
|
|
18358
18779
|
const paramsSource = pickedModel !== null && pickedEffort !== null ? "picker" : "default";
|
|
18359
|
-
const callerTargetAccountId = typeof callerAccountId === "string" &&
|
|
18360
|
-
const bodyTargetAccountId = typeof body.targetAccountId === "string" &&
|
|
18780
|
+
const callerTargetAccountId = typeof callerAccountId === "string" && ACCOUNT_UUID_RE3.test(callerAccountId) ? callerAccountId : void 0;
|
|
18781
|
+
const bodyTargetAccountId = typeof body.targetAccountId === "string" && ACCOUNT_UUID_RE3.test(body.targetAccountId) ? body.targetAccountId : void 0;
|
|
18361
18782
|
const targetAccountId = kind === "new" ? callerTargetAccountId : bodyTargetAccountId;
|
|
18362
18783
|
const payload = {};
|
|
18363
18784
|
let sessionId;
|
|
@@ -18708,24 +19129,24 @@ app36.get("/", async (c) => {
|
|
|
18708
19129
|
var system_stats_default = app36;
|
|
18709
19130
|
|
|
18710
19131
|
// server/routes/admin/health.ts
|
|
18711
|
-
import { existsSync as existsSync28, readFileSync as
|
|
18712
|
-
import { resolve as
|
|
18713
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
19132
|
+
import { existsSync as existsSync28, readFileSync as readFileSync31 } from "fs";
|
|
19133
|
+
import { resolve as resolve25, join as join31 } from "path";
|
|
19134
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
|
|
18714
19135
|
var brandHostname = "maxy";
|
|
18715
|
-
var brandJsonPath =
|
|
19136
|
+
var brandJsonPath = join31(PLATFORM_ROOT6, "config", "brand.json");
|
|
18716
19137
|
if (existsSync28(brandJsonPath)) {
|
|
18717
19138
|
try {
|
|
18718
|
-
const brand = JSON.parse(
|
|
19139
|
+
const brand = JSON.parse(readFileSync31(brandJsonPath, "utf-8"));
|
|
18719
19140
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
18720
19141
|
} catch {
|
|
18721
19142
|
}
|
|
18722
19143
|
}
|
|
18723
|
-
var VERSION_FILE =
|
|
19144
|
+
var VERSION_FILE = resolve25(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
18724
19145
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
18725
19146
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
18726
19147
|
function readVersion() {
|
|
18727
19148
|
if (!existsSync28(VERSION_FILE)) return "unknown";
|
|
18728
|
-
return
|
|
19149
|
+
return readFileSync31(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
18729
19150
|
}
|
|
18730
19151
|
async function probeConversationDb() {
|
|
18731
19152
|
let session;
|
|
@@ -19502,7 +19923,7 @@ var browser_default = app44;
|
|
|
19502
19923
|
|
|
19503
19924
|
// server/routes/admin/calendar.ts
|
|
19504
19925
|
import { existsSync as existsSync29 } from "fs";
|
|
19505
|
-
import { join as
|
|
19926
|
+
import { join as join33 } from "path";
|
|
19506
19927
|
|
|
19507
19928
|
// server/lib/calendar-ics.ts
|
|
19508
19929
|
var CRLF = "\r\n";
|
|
@@ -19601,8 +20022,8 @@ function countVEvents(ics) {
|
|
|
19601
20022
|
}
|
|
19602
20023
|
|
|
19603
20024
|
// server/lib/calendar-availability.ts
|
|
19604
|
-
import { readFileSync as
|
|
19605
|
-
import { join as
|
|
20025
|
+
import { readFileSync as readFileSync32 } from "fs";
|
|
20026
|
+
import { join as join32 } from "path";
|
|
19606
20027
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
19607
20028
|
var REQUIRED_KEYS = [
|
|
19608
20029
|
"timezone",
|
|
@@ -19611,10 +20032,10 @@ var REQUIRED_KEYS = [
|
|
|
19611
20032
|
"weekly"
|
|
19612
20033
|
];
|
|
19613
20034
|
function readAvailabilityConfig(accountDir) {
|
|
19614
|
-
const path2 =
|
|
20035
|
+
const path2 = join32(accountDir, AVAILABILITY_FILENAME);
|
|
19615
20036
|
let raw;
|
|
19616
20037
|
try {
|
|
19617
|
-
raw =
|
|
20038
|
+
raw = readFileSync32(path2, "utf-8");
|
|
19618
20039
|
} catch {
|
|
19619
20040
|
throw new Error(`availability not configured: ${path2} not found`);
|
|
19620
20041
|
}
|
|
@@ -19973,7 +20394,7 @@ app45.get("/booking-link", requireAdminSession, (c) => {
|
|
|
19973
20394
|
console.error('[calendar] op=booking-link-fail err="no account configured"');
|
|
19974
20395
|
return c.json({ bookingDomain: null });
|
|
19975
20396
|
}
|
|
19976
|
-
if (!existsSync29(
|
|
20397
|
+
if (!existsSync29(join33(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
19977
20398
|
console.log("[calendar] op=booking-link bookingDomain=none source=availability-config");
|
|
19978
20399
|
return c.json({ bookingDomain: null });
|
|
19979
20400
|
}
|
|
@@ -20447,9 +20868,9 @@ var verify_token_default = app52;
|
|
|
20447
20868
|
|
|
20448
20869
|
// app/lib/access-email.ts
|
|
20449
20870
|
import { spawn as spawn2 } from "child_process";
|
|
20450
|
-
import { resolve as
|
|
20451
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
20452
|
-
var SEND_SCRIPT =
|
|
20871
|
+
import { resolve as resolve26 } from "path";
|
|
20872
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve26(process.cwd(), "..");
|
|
20873
|
+
var SEND_SCRIPT = resolve26(
|
|
20453
20874
|
PLATFORM_ROOT7,
|
|
20454
20875
|
"plugins",
|
|
20455
20876
|
"email",
|
|
@@ -20591,8 +21012,8 @@ app54.route("/request-magic-link", request_magic_link_default);
|
|
|
20591
21012
|
var access_default = app54;
|
|
20592
21013
|
|
|
20593
21014
|
// server/routes/sites.ts
|
|
20594
|
-
import { existsSync as existsSync30, readFileSync as
|
|
20595
|
-
import { resolve as
|
|
21015
|
+
import { existsSync as existsSync30, readFileSync as readFileSync33, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
|
|
21016
|
+
import { resolve as resolve27 } from "path";
|
|
20596
21017
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
20597
21018
|
var MIME = {
|
|
20598
21019
|
".html": "text/html; charset=utf-8",
|
|
@@ -20649,8 +21070,8 @@ app55.get("/:rel{.*}", (c) => {
|
|
|
20649
21070
|
}
|
|
20650
21071
|
segments.push(seg);
|
|
20651
21072
|
}
|
|
20652
|
-
const rootDir =
|
|
20653
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
21073
|
+
const rootDir = resolve27(account.accountDir, "sites");
|
|
21074
|
+
let filePath = segments.length === 0 ? rootDir : resolve27(rootDir, ...segments);
|
|
20654
21075
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
20655
21076
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
20656
21077
|
return c.text("Forbidden", 403);
|
|
@@ -20670,7 +21091,7 @@ app55.get("/:rel{.*}", (c) => {
|
|
|
20670
21091
|
return c.redirect(target, 301);
|
|
20671
21092
|
}
|
|
20672
21093
|
if (stat8?.isDirectory()) {
|
|
20673
|
-
filePath =
|
|
21094
|
+
filePath = resolve27(filePath, "index.html");
|
|
20674
21095
|
}
|
|
20675
21096
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
20676
21097
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
@@ -20695,7 +21116,7 @@ app55.get("/:rel{.*}", (c) => {
|
|
|
20695
21116
|
}
|
|
20696
21117
|
let body;
|
|
20697
21118
|
try {
|
|
20698
|
-
body =
|
|
21119
|
+
body = readFileSync33(realPath);
|
|
20699
21120
|
} catch (err) {
|
|
20700
21121
|
const code = err?.code;
|
|
20701
21122
|
if (code === "EISDIR") {
|
|
@@ -20731,7 +21152,7 @@ var sites_default = app55;
|
|
|
20731
21152
|
|
|
20732
21153
|
// app/lib/visitor-token.ts
|
|
20733
21154
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
20734
|
-
import { mkdirSync as mkdirSync7, readFileSync as
|
|
21155
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync34, writeFileSync as writeFileSync11 } from "fs";
|
|
20735
21156
|
import { dirname as dirname11 } from "path";
|
|
20736
21157
|
var TOKEN_PREFIX = "v1.";
|
|
20737
21158
|
var SECRET_BYTES = 32;
|
|
@@ -20740,7 +21161,7 @@ var cachedSecret = null;
|
|
|
20740
21161
|
function getSecret() {
|
|
20741
21162
|
if (cachedSecret) return cachedSecret;
|
|
20742
21163
|
try {
|
|
20743
|
-
const hex2 =
|
|
21164
|
+
const hex2 = readFileSync34(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
20744
21165
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
20745
21166
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
20746
21167
|
return cachedSecret;
|
|
@@ -20754,7 +21175,7 @@ function getSecret() {
|
|
|
20754
21175
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
20755
21176
|
} catch {
|
|
20756
21177
|
}
|
|
20757
|
-
const hex =
|
|
21178
|
+
const hex = readFileSync34(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
20758
21179
|
cachedSecret = Buffer.from(hex, "hex");
|
|
20759
21180
|
return cachedSecret;
|
|
20760
21181
|
}
|
|
@@ -20807,20 +21228,20 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
20807
21228
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
20808
21229
|
|
|
20809
21230
|
// app/lib/brand-config.ts
|
|
20810
|
-
import { existsSync as existsSync31, readFileSync as
|
|
20811
|
-
import { join as
|
|
20812
|
-
var
|
|
21231
|
+
import { existsSync as existsSync31, readFileSync as readFileSync35 } from "fs";
|
|
21232
|
+
import { join as join34 } from "path";
|
|
21233
|
+
var cached2 = null;
|
|
20813
21234
|
var cachedAttempted = false;
|
|
20814
21235
|
function readBrandConfig() {
|
|
20815
|
-
if (cachedAttempted) return
|
|
21236
|
+
if (cachedAttempted) return cached2;
|
|
20816
21237
|
cachedAttempted = true;
|
|
20817
21238
|
const platformRoot3 = process.env.MAXY_PLATFORM_ROOT;
|
|
20818
21239
|
if (!platformRoot3) return null;
|
|
20819
|
-
const brandPath =
|
|
21240
|
+
const brandPath = join34(platformRoot3, "config", "brand.json");
|
|
20820
21241
|
if (!existsSync31(brandPath)) return null;
|
|
20821
21242
|
try {
|
|
20822
|
-
|
|
20823
|
-
return
|
|
21243
|
+
cached2 = JSON.parse(readFileSync35(brandPath, "utf-8"));
|
|
21244
|
+
return cached2;
|
|
20824
21245
|
} catch {
|
|
20825
21246
|
return null;
|
|
20826
21247
|
}
|
|
@@ -21307,14 +21728,14 @@ async function writeEvent(opts) {
|
|
|
21307
21728
|
var visitor_event_default = app58;
|
|
21308
21729
|
|
|
21309
21730
|
// server/routes/session.ts
|
|
21310
|
-
import { resolve as
|
|
21731
|
+
import { resolve as resolve28 } from "path";
|
|
21311
21732
|
import { existsSync as existsSync32, writeFileSync as writeFileSync12, mkdirSync as mkdirSync8 } from "fs";
|
|
21312
21733
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
21313
21734
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
21314
21735
|
try {
|
|
21315
|
-
const cacheDir =
|
|
21736
|
+
const cacheDir = resolve28(MAXY_DIR, "branding-cache", accountId);
|
|
21316
21737
|
mkdirSync8(cacheDir, { recursive: true });
|
|
21317
|
-
writeFileSync12(
|
|
21738
|
+
writeFileSync12(resolve28(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
21318
21739
|
} catch (err) {
|
|
21319
21740
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
21320
21741
|
}
|
|
@@ -21391,8 +21812,8 @@ app59.post("/", async (c) => {
|
|
|
21391
21812
|
}
|
|
21392
21813
|
let agentConfig = null;
|
|
21393
21814
|
if (account) {
|
|
21394
|
-
const agentDir =
|
|
21395
|
-
if (!existsSync32(agentDir) || !existsSync32(
|
|
21815
|
+
const agentDir = resolve28(account.accountDir, "agents", agentSlug);
|
|
21816
|
+
if (!existsSync32(agentDir) || !existsSync32(resolve28(agentDir, "config.json"))) {
|
|
21396
21817
|
return c.json({ error: "Agent not found" }, 404);
|
|
21397
21818
|
}
|
|
21398
21819
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -21838,8 +22259,8 @@ function startGraphHealthTimer() {
|
|
|
21838
22259
|
|
|
21839
22260
|
// app/lib/file-watcher.ts
|
|
21840
22261
|
import * as fsp2 from "fs/promises";
|
|
21841
|
-
import { resolve as
|
|
21842
|
-
var
|
|
22262
|
+
import { resolve as resolve29, sep as sep8 } from "path";
|
|
22263
|
+
var ACCOUNT_UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
21843
22264
|
var DEFAULT_COALESCE_MS = 500;
|
|
21844
22265
|
var ROOTS = ["accounts"];
|
|
21845
22266
|
function _routeEvent(rootName, filename) {
|
|
@@ -21847,7 +22268,7 @@ function _routeEvent(rootName, filename) {
|
|
|
21847
22268
|
const segs = filename.split(sep8).filter(Boolean);
|
|
21848
22269
|
if (segs.length < 2) return null;
|
|
21849
22270
|
const accountId = segs[0];
|
|
21850
|
-
if (!
|
|
22271
|
+
if (!ACCOUNT_UUID_RE4.test(accountId)) return null;
|
|
21851
22272
|
return { accountId, relativePath: `${rootName}/${segs.join("/")}` };
|
|
21852
22273
|
}
|
|
21853
22274
|
async function startFileWatcher(opts = {}) {
|
|
@@ -21857,7 +22278,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
21857
22278
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
21858
22279
|
for (const r of ROOTS) {
|
|
21859
22280
|
try {
|
|
21860
|
-
await fsp2.mkdir(
|
|
22281
|
+
await fsp2.mkdir(resolve29(dataRoot, r), { recursive: true });
|
|
21861
22282
|
} catch (err) {
|
|
21862
22283
|
console.error(
|
|
21863
22284
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -21878,7 +22299,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
21878
22299
|
timers.set(relativePath, t);
|
|
21879
22300
|
}
|
|
21880
22301
|
async function runHook(relativePath, accountId) {
|
|
21881
|
-
const absolute =
|
|
22302
|
+
const absolute = resolve29(dataRoot, relativePath);
|
|
21882
22303
|
let exists = false;
|
|
21883
22304
|
try {
|
|
21884
22305
|
const st = await fsp2.stat(absolute);
|
|
@@ -21902,7 +22323,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
21902
22323
|
}
|
|
21903
22324
|
}
|
|
21904
22325
|
async function watchRoot(rootName) {
|
|
21905
|
-
const absRoot =
|
|
22326
|
+
const absRoot = resolve29(dataRoot, rootName);
|
|
21906
22327
|
try {
|
|
21907
22328
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
21908
22329
|
for await (const event of iter) {
|
|
@@ -21941,8 +22362,8 @@ async function startFileWatcher(opts = {}) {
|
|
|
21941
22362
|
|
|
21942
22363
|
// app/lib/migrate-uploads.ts
|
|
21943
22364
|
import { mkdir as mkdir5, readdir as readdir5, rename as rename2, rm as rm3 } from "fs/promises";
|
|
21944
|
-
import { dirname as dirname12, relative as relative6, resolve as
|
|
21945
|
-
var
|
|
22365
|
+
import { dirname as dirname12, relative as relative6, resolve as resolve30 } from "path";
|
|
22366
|
+
var ACCOUNT_UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
21946
22367
|
async function walkFiles(dir) {
|
|
21947
22368
|
const out = [];
|
|
21948
22369
|
let entries;
|
|
@@ -21952,7 +22373,7 @@ async function walkFiles(dir) {
|
|
|
21952
22373
|
return out;
|
|
21953
22374
|
}
|
|
21954
22375
|
for (const e of entries) {
|
|
21955
|
-
const abs =
|
|
22376
|
+
const abs = resolve30(dir, e.name);
|
|
21956
22377
|
if (e.isDirectory()) {
|
|
21957
22378
|
out.push(...await walkFiles(abs));
|
|
21958
22379
|
} else if (e.isFile()) {
|
|
@@ -21972,7 +22393,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
21972
22393
|
let moved = 0;
|
|
21973
22394
|
for (const oldAbs of files) {
|
|
21974
22395
|
const suffix = relative6(srcDir, oldAbs);
|
|
21975
|
-
const newAbs =
|
|
22396
|
+
const newAbs = resolve30(destDir, suffix);
|
|
21976
22397
|
await mkdir5(dirname12(newAbs), { recursive: true });
|
|
21977
22398
|
await rename2(oldAbs, newAbs);
|
|
21978
22399
|
moved++;
|
|
@@ -21999,7 +22420,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
21999
22420
|
}
|
|
22000
22421
|
async function migrateUploads(opts = {}) {
|
|
22001
22422
|
const dataRoot = opts.dataRoot ?? DATA_ROOT;
|
|
22002
|
-
const oldRoot =
|
|
22423
|
+
const oldRoot = resolve30(dataRoot, "uploads");
|
|
22003
22424
|
let topEntries;
|
|
22004
22425
|
try {
|
|
22005
22426
|
topEntries = await readdir5(oldRoot, { withFileTypes: true });
|
|
@@ -22018,10 +22439,10 @@ async function migrateUploads(opts = {}) {
|
|
|
22018
22439
|
try {
|
|
22019
22440
|
for (const entry of topEntries) {
|
|
22020
22441
|
const name = entry.name;
|
|
22021
|
-
if (
|
|
22442
|
+
if (ACCOUNT_UUID_RE5.test(name)) {
|
|
22022
22443
|
moved += await relocateTree(
|
|
22023
|
-
|
|
22024
|
-
|
|
22444
|
+
resolve30(oldRoot, name),
|
|
22445
|
+
resolve30(dataRoot, "accounts", name, "uploads"),
|
|
22025
22446
|
dataRoot,
|
|
22026
22447
|
name,
|
|
22027
22448
|
session
|
|
@@ -22033,8 +22454,8 @@ async function migrateUploads(opts = {}) {
|
|
|
22033
22454
|
continue;
|
|
22034
22455
|
}
|
|
22035
22456
|
moved += await relocateTree(
|
|
22036
|
-
|
|
22037
|
-
|
|
22457
|
+
resolve30(oldRoot, "public"),
|
|
22458
|
+
resolve30(dataRoot, "accounts", installAccountId, "uploads", "public"),
|
|
22038
22459
|
dataRoot,
|
|
22039
22460
|
null,
|
|
22040
22461
|
// public uploads carry no graph nodes
|
|
@@ -22065,7 +22486,7 @@ async function migrateUploads(opts = {}) {
|
|
|
22065
22486
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
22066
22487
|
import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
22067
22488
|
import { existsSync as existsSync33 } from "fs";
|
|
22068
|
-
import { join as
|
|
22489
|
+
import { join as join35 } from "path";
|
|
22069
22490
|
var ADMIN_ROLE2 = "admin";
|
|
22070
22491
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
22071
22492
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -22110,7 +22531,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
22110
22531
|
}
|
|
22111
22532
|
for (const slug of slugs) {
|
|
22112
22533
|
if (!slug.isDirectory()) continue;
|
|
22113
|
-
const slugDir =
|
|
22534
|
+
const slugDir = join35(projectsRoot, slug.name);
|
|
22114
22535
|
let entries;
|
|
22115
22536
|
try {
|
|
22116
22537
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -22119,9 +22540,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
22119
22540
|
}
|
|
22120
22541
|
for (const entry of entries) {
|
|
22121
22542
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
22122
|
-
out.push(
|
|
22543
|
+
out.push(join35(slugDir, entry.name));
|
|
22123
22544
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
22124
|
-
const subDir =
|
|
22545
|
+
const subDir = join35(slugDir, entry.name);
|
|
22125
22546
|
let subs;
|
|
22126
22547
|
try {
|
|
22127
22548
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -22129,7 +22550,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
22129
22550
|
continue;
|
|
22130
22551
|
}
|
|
22131
22552
|
for (const s of subs) {
|
|
22132
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
22553
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join35(subDir, s.name));
|
|
22133
22554
|
}
|
|
22134
22555
|
}
|
|
22135
22556
|
}
|
|
@@ -22141,7 +22562,7 @@ function shortId(path2) {
|
|
|
22141
22562
|
return base.slice(0, 8);
|
|
22142
22563
|
}
|
|
22143
22564
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
22144
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
22565
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join35(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
22145
22566
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
22146
22567
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
22147
22568
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -23120,16 +23541,16 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
23120
23541
|
* The public /api/chat route awaits this to return the reply on the same SSE
|
|
23121
23542
|
* response, preserving the pre-756 POST→single-blob browser contract. */
|
|
23122
23543
|
awaitReply(key, timeoutMs) {
|
|
23123
|
-
return new Promise((
|
|
23544
|
+
return new Promise((resolve35) => {
|
|
23124
23545
|
const timer2 = setTimeout(() => {
|
|
23125
23546
|
this.replyAwaiters.delete(key);
|
|
23126
|
-
|
|
23547
|
+
resolve35({ timeout: true });
|
|
23127
23548
|
}, timeoutMs);
|
|
23128
23549
|
if (timer2.unref) timer2.unref();
|
|
23129
23550
|
this.replyAwaiters.set(key, (r) => {
|
|
23130
23551
|
clearTimeout(timer2);
|
|
23131
23552
|
this.replyAwaiters.delete(key);
|
|
23132
|
-
|
|
23553
|
+
resolve35(r);
|
|
23133
23554
|
});
|
|
23134
23555
|
});
|
|
23135
23556
|
}
|
|
@@ -23140,11 +23561,11 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
23140
23561
|
* terminal dialog stays answerable). */
|
|
23141
23562
|
awaitPermissionVerdict(p, timeoutMs) {
|
|
23142
23563
|
const k = _WebchatGateway.promptKey(p.key, p.requestId);
|
|
23143
|
-
return new Promise((
|
|
23564
|
+
return new Promise((resolve35) => {
|
|
23144
23565
|
this.pendingPrompts.get(k)?.resolve({ timeout: true });
|
|
23145
23566
|
const timer2 = setTimeout(() => {
|
|
23146
23567
|
this.pendingPrompts.delete(k);
|
|
23147
|
-
|
|
23568
|
+
resolve35({ timeout: true });
|
|
23148
23569
|
}, timeoutMs);
|
|
23149
23570
|
if (timer2.unref) timer2.unref();
|
|
23150
23571
|
this.pendingPrompts.set(k, {
|
|
@@ -23153,7 +23574,7 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
23153
23574
|
resolve: (r) => {
|
|
23154
23575
|
clearTimeout(timer2);
|
|
23155
23576
|
this.pendingPrompts.delete(k);
|
|
23156
|
-
|
|
23577
|
+
resolve35(r);
|
|
23157
23578
|
}
|
|
23158
23579
|
});
|
|
23159
23580
|
console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
|
|
@@ -24149,7 +24570,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
24149
24570
|
// app/lib/telegram/outbound/send-document.ts
|
|
24150
24571
|
import { realpathSync as realpathSync7 } from "fs";
|
|
24151
24572
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
24152
|
-
import { resolve as
|
|
24573
|
+
import { resolve as resolve31, basename as basename11 } from "path";
|
|
24153
24574
|
var TAG42 = "[telegram:outbound]";
|
|
24154
24575
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
24155
24576
|
async function sendTelegramDocument(input) {
|
|
@@ -24160,7 +24581,7 @@ async function sendTelegramDocument(input) {
|
|
|
24160
24581
|
if (!maxyAccountId || !platformRoot3) {
|
|
24161
24582
|
return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
|
|
24162
24583
|
}
|
|
24163
|
-
const accountDir =
|
|
24584
|
+
const accountDir = resolve31(platformRoot3, "..", "data/accounts", maxyAccountId);
|
|
24164
24585
|
let resolvedPath;
|
|
24165
24586
|
try {
|
|
24166
24587
|
resolvedPath = realpathSync7(filePath);
|
|
@@ -24287,12 +24708,12 @@ function startTelegramNativeFileFollower(input) {
|
|
|
24287
24708
|
}
|
|
24288
24709
|
|
|
24289
24710
|
// server/telegram-descriptor.ts
|
|
24290
|
-
import { resolve as
|
|
24711
|
+
import { resolve as resolve32, join as join36 } from "path";
|
|
24291
24712
|
function telegramGatewayUrl() {
|
|
24292
24713
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
24293
24714
|
}
|
|
24294
24715
|
function telegramServerPath() {
|
|
24295
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ??
|
|
24716
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve32(process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
24296
24717
|
}
|
|
24297
24718
|
|
|
24298
24719
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
@@ -24554,8 +24975,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
24554
24975
|
|
|
24555
24976
|
// ../lib/entitlement/src/index.ts
|
|
24556
24977
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
24557
|
-
import { existsSync as existsSync34, readFileSync as
|
|
24558
|
-
import { resolve as
|
|
24978
|
+
import { existsSync as existsSync34, readFileSync as readFileSync36, statSync as statSync13 } from "fs";
|
|
24979
|
+
import { resolve as resolve33 } from "path";
|
|
24559
24980
|
|
|
24560
24981
|
// ../lib/entitlement/src/canonicalize.ts
|
|
24561
24982
|
function canonicalize(value) {
|
|
@@ -24590,7 +25011,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
24590
25011
|
var GRACE_DAYS = 7;
|
|
24591
25012
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
24592
25013
|
function pubkeyPath(brand) {
|
|
24593
|
-
return
|
|
25014
|
+
return resolve33(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
24594
25015
|
}
|
|
24595
25016
|
var memo = null;
|
|
24596
25017
|
function memoKey(mtimeMs, account) {
|
|
@@ -24602,7 +25023,7 @@ function resolveEntitlement(brand, account) {
|
|
|
24602
25023
|
if (brand.commercialMode !== true) {
|
|
24603
25024
|
return logResolved(implicitTrust(account), null);
|
|
24604
25025
|
}
|
|
24605
|
-
const entitlementPath =
|
|
25026
|
+
const entitlementPath = resolve33(brand.configDir, "entitlement.json");
|
|
24606
25027
|
if (!existsSync34(entitlementPath)) {
|
|
24607
25028
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
24608
25029
|
}
|
|
@@ -24618,7 +25039,7 @@ function resolveEntitlement(brand, account) {
|
|
|
24618
25039
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
24619
25040
|
let pubkeyPem;
|
|
24620
25041
|
try {
|
|
24621
|
-
pubkeyPem =
|
|
25042
|
+
pubkeyPem = readFileSync36(pubkeyPath(brand), "utf-8");
|
|
24622
25043
|
} catch (err) {
|
|
24623
25044
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
24624
25045
|
reason: "pubkey-missing"
|
|
@@ -24632,7 +25053,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
24632
25053
|
}
|
|
24633
25054
|
let envelope;
|
|
24634
25055
|
try {
|
|
24635
|
-
envelope = JSON.parse(
|
|
25056
|
+
envelope = JSON.parse(readFileSync36(entitlementPath, "utf-8"));
|
|
24636
25057
|
} catch {
|
|
24637
25058
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
24638
25059
|
}
|
|
@@ -24793,14 +25214,14 @@ function clientFrom(c) {
|
|
|
24793
25214
|
);
|
|
24794
25215
|
}
|
|
24795
25216
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
24796
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
25217
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join37(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
24797
25218
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
24798
25219
|
if (BRAND_JSON_PATH && !existsSync35(BRAND_JSON_PATH)) {
|
|
24799
25220
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
24800
25221
|
}
|
|
24801
25222
|
if (BRAND_JSON_PATH && existsSync35(BRAND_JSON_PATH)) {
|
|
24802
25223
|
try {
|
|
24803
|
-
const parsed = JSON.parse(
|
|
25224
|
+
const parsed = JSON.parse(readFileSync37(BRAND_JSON_PATH, "utf-8"));
|
|
24804
25225
|
BRAND = { ...BRAND, ...parsed };
|
|
24805
25226
|
} catch (err) {
|
|
24806
25227
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -24832,11 +25253,11 @@ var brandLoginOpts = {
|
|
|
24832
25253
|
appleTouchIconPath: brandAppIcon512Path,
|
|
24833
25254
|
themeColor: BRAND.defaultColors?.primary
|
|
24834
25255
|
};
|
|
24835
|
-
var ALIAS_DOMAINS_PATH =
|
|
25256
|
+
var ALIAS_DOMAINS_PATH = join37(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
24836
25257
|
function loadAliasDomains() {
|
|
24837
25258
|
try {
|
|
24838
25259
|
if (!existsSync35(ALIAS_DOMAINS_PATH)) return null;
|
|
24839
|
-
const parsed = JSON.parse(
|
|
25260
|
+
const parsed = JSON.parse(readFileSync37(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
24840
25261
|
if (!Array.isArray(parsed)) {
|
|
24841
25262
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
24842
25263
|
return null;
|
|
@@ -24899,7 +25320,7 @@ async function recordPassiveDispatch(input) {
|
|
|
24899
25320
|
var waGateway = new WaGateway({
|
|
24900
25321
|
fetchStandingRules: fetchAccountStandingRules,
|
|
24901
25322
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
24902
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
25323
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve34(process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
24903
25324
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
24904
25325
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
24905
25326
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -24914,7 +25335,7 @@ var waGateway = new WaGateway({
|
|
|
24914
25335
|
caption,
|
|
24915
25336
|
accountId,
|
|
24916
25337
|
maxyAccountId,
|
|
24917
|
-
platformRoot:
|
|
25338
|
+
platformRoot: resolve34(process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, ".."))
|
|
24918
25339
|
});
|
|
24919
25340
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
24920
25341
|
},
|
|
@@ -25512,8 +25933,8 @@ app61.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
25512
25933
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
25513
25934
|
return c.text("Not found", 404);
|
|
25514
25935
|
}
|
|
25515
|
-
const filePath =
|
|
25516
|
-
const expectedDir =
|
|
25936
|
+
const filePath = resolve34(account.accountDir, "agents", slug, "assets", filename);
|
|
25937
|
+
const expectedDir = resolve34(account.accountDir, "agents", slug, "assets");
|
|
25517
25938
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
25518
25939
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
25519
25940
|
return c.text("Forbidden", 403);
|
|
@@ -25525,7 +25946,7 @@ app61.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
25525
25946
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
25526
25947
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
25527
25948
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
25528
|
-
const body =
|
|
25949
|
+
const body = readFileSync37(filePath);
|
|
25529
25950
|
return c.body(body, 200, {
|
|
25530
25951
|
"Content-Type": contentType,
|
|
25531
25952
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -25542,8 +25963,8 @@ app61.get("/generated/:filename", (c) => {
|
|
|
25542
25963
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
25543
25964
|
return c.text("Not found", 404);
|
|
25544
25965
|
}
|
|
25545
|
-
const filePath =
|
|
25546
|
-
const expectedDir =
|
|
25966
|
+
const filePath = resolve34(account.accountDir, "generated", filename);
|
|
25967
|
+
const expectedDir = resolve34(account.accountDir, "generated");
|
|
25547
25968
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
25548
25969
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
25549
25970
|
return c.text("Forbidden", 403);
|
|
@@ -25555,7 +25976,7 @@ app61.get("/generated/:filename", (c) => {
|
|
|
25555
25976
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
25556
25977
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
25557
25978
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
25558
|
-
const body =
|
|
25979
|
+
const body = readFileSync37(filePath);
|
|
25559
25980
|
return c.body(body, 200, {
|
|
25560
25981
|
"Content-Type": contentType,
|
|
25561
25982
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -25570,7 +25991,7 @@ var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
|
25570
25991
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
25571
25992
|
if (BRAND_JSON_PATH && existsSync35(BRAND_JSON_PATH)) {
|
|
25572
25993
|
try {
|
|
25573
|
-
const fullBrand = JSON.parse(
|
|
25994
|
+
const fullBrand = JSON.parse(readFileSync37(BRAND_JSON_PATH, "utf-8"));
|
|
25574
25995
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
25575
25996
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
25576
25997
|
} catch {
|
|
@@ -25597,11 +26018,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
25597
26018
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
25598
26019
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
25599
26020
|
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
25600
|
-
(p) => existsSync35(
|
|
26021
|
+
(p) => existsSync35(resolve34(process.cwd(), "public", p.replace(/^\//, "")))
|
|
25601
26022
|
);
|
|
25602
26023
|
var SW_SOURCE = (() => {
|
|
25603
26024
|
try {
|
|
25604
|
-
return
|
|
26025
|
+
return readFileSync37(resolve34(process.cwd(), "public", "sw.js"), "utf-8");
|
|
25605
26026
|
} catch {
|
|
25606
26027
|
return null;
|
|
25607
26028
|
}
|
|
@@ -25609,9 +26030,9 @@ var SW_SOURCE = (() => {
|
|
|
25609
26030
|
function readInstalledVersion() {
|
|
25610
26031
|
try {
|
|
25611
26032
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
25612
|
-
const versionFile =
|
|
26033
|
+
const versionFile = join37(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
25613
26034
|
if (!existsSync35(versionFile)) return "unknown";
|
|
25614
|
-
const content =
|
|
26035
|
+
const content = readFileSync37(versionFile, "utf-8").trim();
|
|
25615
26036
|
return content || "unknown";
|
|
25616
26037
|
} catch {
|
|
25617
26038
|
return "unknown";
|
|
@@ -25652,7 +26073,7 @@ var clientErrorReporterScript = `<script>
|
|
|
25652
26073
|
function cachedHtml(file) {
|
|
25653
26074
|
let html = htmlCache.get(file);
|
|
25654
26075
|
if (!html) {
|
|
25655
|
-
html =
|
|
26076
|
+
html = readFileSync37(resolve34(process.cwd(), "public", file), "utf-8");
|
|
25656
26077
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
25657
26078
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
25658
26079
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -25669,13 +26090,13 @@ ${clientErrorReporterScript}
|
|
|
25669
26090
|
return html;
|
|
25670
26091
|
}
|
|
25671
26092
|
function loadBrandingCache(agentSlug) {
|
|
25672
|
-
const configDir2 =
|
|
26093
|
+
const configDir2 = join37(homedir4(), BRAND.configDir);
|
|
25673
26094
|
try {
|
|
25674
26095
|
const accountId = getDefaultAccountId();
|
|
25675
26096
|
if (!accountId) return null;
|
|
25676
|
-
const cachePath =
|
|
26097
|
+
const cachePath = join37(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
25677
26098
|
if (!existsSync35(cachePath)) return null;
|
|
25678
|
-
return JSON.parse(
|
|
26099
|
+
return JSON.parse(readFileSync37(cachePath, "utf-8"));
|
|
25679
26100
|
} catch {
|
|
25680
26101
|
return null;
|
|
25681
26102
|
}
|
|
@@ -25692,11 +26113,11 @@ var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
|
25692
26113
|
function brandedPublicHtml(agentSlug) {
|
|
25693
26114
|
const baseHtml = cachedHtml("public.html");
|
|
25694
26115
|
if (!agentSlug) return baseHtml;
|
|
25695
|
-
const
|
|
26116
|
+
const cached3 = brandedHtmlCache.get(agentSlug);
|
|
25696
26117
|
const branding = loadBrandingCache(agentSlug);
|
|
25697
26118
|
if (!branding) return baseHtml;
|
|
25698
26119
|
const brandHash = JSON.stringify(branding).length;
|
|
25699
|
-
if (
|
|
26120
|
+
if (cached3 && cached3.mtime === brandHash) return cached3.html;
|
|
25700
26121
|
const title = escapeHtml(branding.name);
|
|
25701
26122
|
const description = branding.tagline ? escapeHtml(branding.tagline) : "";
|
|
25702
26123
|
const themeColor = branding.primaryColor || "";
|
|
@@ -25770,7 +26191,7 @@ app61.use("/vnc-popout.html", logViewerFetch);
|
|
|
25770
26191
|
app61.get("/vnc-popout.html", (c) => {
|
|
25771
26192
|
let html = htmlCache.get("vnc-popout.html");
|
|
25772
26193
|
if (!html) {
|
|
25773
|
-
html =
|
|
26194
|
+
html = readFileSync37(resolve34(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
25774
26195
|
const name = escapeHtml(BRAND.productName);
|
|
25775
26196
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
25776
26197
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -25902,8 +26323,8 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
25902
26323
|
var httpServer = serve({ fetch: app61.fetch, port, hostname });
|
|
25903
26324
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
25904
26325
|
{
|
|
25905
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
25906
|
-
const reconcileScript =
|
|
26326
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, "..");
|
|
26327
|
+
const reconcileScript = resolve34(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
25907
26328
|
const RECONCILE_INTERVAL_MS = 12e4;
|
|
25908
26329
|
const runReconcile = () => {
|
|
25909
26330
|
if (!existsSync35(reconcileScript)) return;
|
|
@@ -25924,8 +26345,8 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
25924
26345
|
loop.unref();
|
|
25925
26346
|
}
|
|
25926
26347
|
{
|
|
25927
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
25928
|
-
const publishScript =
|
|
26348
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, "..");
|
|
26349
|
+
const publishScript = resolve34(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
25929
26350
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
25930
26351
|
const currentAccount = () => {
|
|
25931
26352
|
try {
|
|
@@ -25954,21 +26375,21 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
25954
26375
|
}
|
|
25955
26376
|
};
|
|
25956
26377
|
const auditSnapshotAge = (account) => {
|
|
25957
|
-
const availPath =
|
|
26378
|
+
const availPath = resolve34(account.accountDir, "calendar-availability.json");
|
|
25958
26379
|
let hasBookingSite = false;
|
|
25959
26380
|
try {
|
|
25960
26381
|
if (existsSync35(availPath)) {
|
|
25961
|
-
const cfg = JSON.parse(
|
|
26382
|
+
const cfg = JSON.parse(readFileSync37(availPath, "utf-8"));
|
|
25962
26383
|
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
25963
26384
|
}
|
|
25964
26385
|
} catch {
|
|
25965
26386
|
}
|
|
25966
26387
|
if (!hasBookingSite) return;
|
|
25967
|
-
const statePath =
|
|
26388
|
+
const statePath = resolve34(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
25968
26389
|
let lastSuccessAt = null;
|
|
25969
26390
|
if (existsSync35(statePath)) {
|
|
25970
26391
|
try {
|
|
25971
|
-
const rec = JSON.parse(
|
|
26392
|
+
const rec = JSON.parse(readFileSync37(statePath, "utf-8"));
|
|
25972
26393
|
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
25973
26394
|
} catch {
|
|
25974
26395
|
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
|
|
@@ -25992,8 +26413,8 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
25992
26413
|
}
|
|
25993
26414
|
startTimeEntryCensus(() => getSession());
|
|
25994
26415
|
{
|
|
25995
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
25996
|
-
const auditScript =
|
|
26416
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, "..");
|
|
26417
|
+
const auditScript = resolve34(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
25997
26418
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
25998
26419
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
25999
26420
|
const runConnectorAudit = () => {
|
|
@@ -26111,7 +26532,7 @@ async function runAdminUserReconcileTick() {
|
|
|
26111
26532
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
26112
26533
|
return;
|
|
26113
26534
|
}
|
|
26114
|
-
const usersRaw =
|
|
26535
|
+
const usersRaw = readFileSync37(USERS_FILE, "utf-8").trim();
|
|
26115
26536
|
if (!usersRaw) {
|
|
26116
26537
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
26117
26538
|
return;
|
|
@@ -26141,7 +26562,7 @@ if (typeof adminUserReconcileTimer.unref === "function") adminUserReconcileTimer
|
|
|
26141
26562
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
26142
26563
|
function countUsersRows() {
|
|
26143
26564
|
if (!existsSync35(USERS_FILE)) return 0;
|
|
26144
|
-
const raw =
|
|
26565
|
+
const raw = readFileSync37(USERS_FILE, "utf-8").trim();
|
|
26145
26566
|
if (!raw) return 0;
|
|
26146
26567
|
const users = JSON.parse(raw);
|
|
26147
26568
|
return users.filter((u) => typeof u.userId === "string").length;
|
|
@@ -26261,7 +26682,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
26261
26682
|
}
|
|
26262
26683
|
init({
|
|
26263
26684
|
configDir: configDirForWhatsApp,
|
|
26264
|
-
platformRoot:
|
|
26685
|
+
platformRoot: resolve34(process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, "..")),
|
|
26265
26686
|
accountConfig: bootAccountConfig,
|
|
26266
26687
|
onMessage: async (msg) => {
|
|
26267
26688
|
if (msg.isOwnerMirror) {
|