@rubytech/create-maxy-code 0.1.440 → 0.1.442
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +99 -1
- package/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +64 -8
- package/payload/platform/plugins/cloudflare/skills/calendar-site/SKILL.md +15 -5
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/functions/api/calendar/free-busy.ts +152 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/public/index.html +6 -3
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/schema.sql +11 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/calendar-booking.md +1 -1
- package/payload/platform/plugins/docs/references/graph.md +19 -3
- package/payload/platform/plugins/docs/references/outlook-guide.md +7 -2
- package/payload/platform/plugins/docs/references/troubleshooting.md +35 -0
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +7 -3
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.js +100 -10
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.js.map +1 -1
- 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/__tests__/mailbox-list.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js +64 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.js +193 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js +58 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.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/auth/mailbox-registry.d.ts +81 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js +171 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts +16 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js +25 -3
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/index.js +119 -50
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts +13 -4
- 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 +54 -3
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts +26 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js +28 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js.map +1 -0
- package/payload/platform/plugins/outlook/references/auth.md +36 -8
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.d.ts +27 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js +241 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js.map +1 -0
- 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/logs-read.sh +24 -6
- package/payload/platform/scripts/logs-read.test.sh +42 -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 +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +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-NgQDY0Pb.js → graph-DbT8nA6R.js} +2 -2
- 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 +498 -180
- 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,7 +1413,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1413
1413
|
};
|
|
1414
1414
|
|
|
1415
1415
|
// server/index.ts
|
|
1416
|
-
import { readFileSync as
|
|
1416
|
+
import { readFileSync as readFileSync36, existsSync as existsSync35, watchFile } from "fs";
|
|
1417
1417
|
import { spawn as spawn3 } from "child_process";
|
|
1418
1418
|
import { createHash as createHash7 } from "crypto";
|
|
1419
1419
|
import { resolve as resolve33, join as join36, basename as basename12 } from "path";
|
|
@@ -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
|
|
@@ -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()) {
|
|
@@ -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;
|
|
@@ -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 {
|
|
@@ -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);
|
|
@@ -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
|
}
|
|
@@ -8273,6 +8444,7 @@ function pickOwnerUserId(admins) {
|
|
|
8273
8444
|
function resolveOwnerUserId(accountId) {
|
|
8274
8445
|
try {
|
|
8275
8446
|
const account = listValidAccounts().find((a) => a.accountId === accountId);
|
|
8447
|
+
if (account?.config.role === "client") return null;
|
|
8276
8448
|
return pickOwnerUserId(account?.config.admins ?? []);
|
|
8277
8449
|
} catch {
|
|
8278
8450
|
return null;
|
|
@@ -8283,6 +8455,7 @@ function resolveAdminUserId(params) {
|
|
|
8283
8455
|
const users = readUsersFile(USERS_FILE);
|
|
8284
8456
|
if (!users) return null;
|
|
8285
8457
|
const account = listValidAccounts().find((a) => a.accountId === params.accountId);
|
|
8458
|
+
if (account?.config.role === "client") return null;
|
|
8286
8459
|
const admins = account?.config.admins ?? [];
|
|
8287
8460
|
const direct = pickAdminUserId(users, admins, params.senderPhone);
|
|
8288
8461
|
if (direct) return direct;
|
|
@@ -8357,7 +8530,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8357
8530
|
const out = [];
|
|
8358
8531
|
let slugs;
|
|
8359
8532
|
try {
|
|
8360
|
-
slugs =
|
|
8533
|
+
slugs = readdirSync8(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
8361
8534
|
} catch (err) {
|
|
8362
8535
|
if (err.code === "ENOENT") return out;
|
|
8363
8536
|
throw err;
|
|
@@ -8366,7 +8539,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8366
8539
|
const slugDir = join13(projectsRoot, slug);
|
|
8367
8540
|
let entries;
|
|
8368
8541
|
try {
|
|
8369
|
-
entries =
|
|
8542
|
+
entries = readdirSync8(slugDir, { withFileTypes: true });
|
|
8370
8543
|
} catch (err) {
|
|
8371
8544
|
const code = err.code ?? "unknown";
|
|
8372
8545
|
console.error(`[admin-sessions-list] slug-skipped slug=${slug} code=${code}`);
|
|
@@ -8379,7 +8552,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8379
8552
|
const subDir = join13(slugDir, entry.name);
|
|
8380
8553
|
let subEntries;
|
|
8381
8554
|
try {
|
|
8382
|
-
subEntries =
|
|
8555
|
+
subEntries = readdirSync8(subDir, { withFileTypes: true });
|
|
8383
8556
|
} catch (err) {
|
|
8384
8557
|
const code = err.code ?? "unknown";
|
|
8385
8558
|
console.error(`[admin-sessions-list] subagents-skipped slug=${slug} code=${code}`);
|
|
@@ -8394,7 +8567,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8394
8567
|
const archiveDir = join13(slugDir, entry.name);
|
|
8395
8568
|
let archiveEntries;
|
|
8396
8569
|
try {
|
|
8397
|
-
archiveEntries =
|
|
8570
|
+
archiveEntries = readdirSync8(archiveDir, { withFileTypes: true });
|
|
8398
8571
|
} catch (err) {
|
|
8399
8572
|
const code = err.code ?? "unknown";
|
|
8400
8573
|
console.error(`[admin-sessions-list] archive-skipped slug=${slug} code=${code}`);
|
|
@@ -8438,7 +8611,7 @@ function loadUserTitles(accountDir) {
|
|
|
8438
8611
|
const path2 = join13(accountDir, "session-titles.json");
|
|
8439
8612
|
let raw;
|
|
8440
8613
|
try {
|
|
8441
|
-
raw =
|
|
8614
|
+
raw = readFileSync14(path2, "utf8");
|
|
8442
8615
|
} catch {
|
|
8443
8616
|
return out;
|
|
8444
8617
|
}
|
|
@@ -8464,7 +8637,7 @@ function readSidecarMeta(metaPath) {
|
|
|
8464
8637
|
const empty = { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null, personId: null, adminUserId: null, visitorId: null, agentSlug: null, accountId: null };
|
|
8465
8638
|
let raw;
|
|
8466
8639
|
try {
|
|
8467
|
-
raw =
|
|
8640
|
+
raw = readFileSync14(metaPath, "utf8");
|
|
8468
8641
|
} catch {
|
|
8469
8642
|
return empty;
|
|
8470
8643
|
}
|
|
@@ -8606,7 +8779,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
8606
8779
|
let body;
|
|
8607
8780
|
let mtimeMs;
|
|
8608
8781
|
try {
|
|
8609
|
-
body =
|
|
8782
|
+
body = readFileSync14(path2, "utf8");
|
|
8610
8783
|
mtimeMs = statSync4(path2).mtimeMs;
|
|
8611
8784
|
} catch {
|
|
8612
8785
|
continue;
|
|
@@ -8966,7 +9139,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
8966
9139
|
}
|
|
8967
9140
|
|
|
8968
9141
|
// app/lib/whatsapp-reader/enrich-attachments.ts
|
|
8969
|
-
import { readFileSync as
|
|
9142
|
+
import { readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
|
|
8970
9143
|
import { join as join14 } from "path";
|
|
8971
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;
|
|
8972
9145
|
function adminAttachmentIds(text) {
|
|
@@ -8988,7 +9161,7 @@ function adminAttachmentsFromText(text, uploadsBase) {
|
|
|
8988
9161
|
function readSidecar(dir, attachmentId) {
|
|
8989
9162
|
let parsed;
|
|
8990
9163
|
try {
|
|
8991
|
-
parsed = JSON.parse(
|
|
9164
|
+
parsed = JSON.parse(readFileSync15(join14(dir, `${attachmentId}.meta.json`), "utf8"));
|
|
8992
9165
|
} catch {
|
|
8993
9166
|
return null;
|
|
8994
9167
|
}
|
|
@@ -9011,7 +9184,7 @@ function readAttachmentMeta(dir) {
|
|
|
9011
9184
|
function listSessionAttachmentsInDir(dir) {
|
|
9012
9185
|
let entries;
|
|
9013
9186
|
try {
|
|
9014
|
-
entries =
|
|
9187
|
+
entries = readdirSync9(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
9015
9188
|
} catch {
|
|
9016
9189
|
return [];
|
|
9017
9190
|
}
|
|
@@ -9058,7 +9231,7 @@ function pickActivity(entries, grown, nowMs, concurrencyWindowMs) {
|
|
|
9058
9231
|
}
|
|
9059
9232
|
|
|
9060
9233
|
// app/admin-types.ts
|
|
9061
|
-
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";
|
|
9234
|
+
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";
|
|
9062
9235
|
var SUPPORTED_MIME_SET = new Set(ACCEPT_MIME.split(",").filter((t) => !t.startsWith(".")));
|
|
9063
9236
|
var MAX_ATTACHMENTS = 5;
|
|
9064
9237
|
var MAX_FILE_BYTES = 50 * 1024 * 1024;
|
|
@@ -9097,7 +9270,7 @@ app4.get("/conversations", requireAdminSession, async (c) => {
|
|
|
9097
9270
|
}
|
|
9098
9271
|
let body = "";
|
|
9099
9272
|
try {
|
|
9100
|
-
body =
|
|
9273
|
+
body = readFileSync16(path2, "utf8");
|
|
9101
9274
|
} catch {
|
|
9102
9275
|
}
|
|
9103
9276
|
const { title } = resolveTitle(body, sessionId, userTitles);
|
|
@@ -9266,7 +9439,7 @@ function openTaskKey(turns) {
|
|
|
9266
9439
|
}
|
|
9267
9440
|
function readSubagentMeta(dir, hex) {
|
|
9268
9441
|
try {
|
|
9269
|
-
const m = JSON.parse(
|
|
9442
|
+
const m = JSON.parse(readFileSync16(join15(dir, `agent-${hex}.meta.json`), "utf8"));
|
|
9270
9443
|
if (typeof m.agentType === "string" && typeof m.description === "string" && typeof m.toolUseId === "string") {
|
|
9271
9444
|
return { agentType: m.agentType, description: m.description, toolUseId: m.toolUseId };
|
|
9272
9445
|
}
|
|
@@ -9289,7 +9462,7 @@ function runActivityTick(c) {
|
|
|
9289
9462
|
c.parentGrewThisTick = false;
|
|
9290
9463
|
let names = [];
|
|
9291
9464
|
try {
|
|
9292
|
-
names =
|
|
9465
|
+
names = readdirSync10(c.subagentsDir).filter((n) => AGENT_JSONL_RE.test(n));
|
|
9293
9466
|
} catch {
|
|
9294
9467
|
}
|
|
9295
9468
|
const entries = [];
|
|
@@ -9484,7 +9657,7 @@ app4.get("/directives", requireAdminSession, (c) => {
|
|
|
9484
9657
|
if (!dir || !existsSync10(dir)) return c.json({ entries: [] });
|
|
9485
9658
|
let names;
|
|
9486
9659
|
try {
|
|
9487
|
-
names =
|
|
9660
|
+
names = readdirSync10(dir).filter((n) => DIRECTIVE_NAME_RE.test(n));
|
|
9488
9661
|
} catch {
|
|
9489
9662
|
return c.json({ entries: [] });
|
|
9490
9663
|
}
|
|
@@ -9513,7 +9686,7 @@ app4.get("/directive", requireAdminSession, (c) => {
|
|
|
9513
9686
|
if (!path2.startsWith(dir + sep3)) return c.json({ error: "bad reference" }, 400);
|
|
9514
9687
|
let body;
|
|
9515
9688
|
try {
|
|
9516
|
-
body =
|
|
9689
|
+
body = readFileSync16(path2, "utf8");
|
|
9517
9690
|
} catch {
|
|
9518
9691
|
return c.json({ error: "not found" }, 404);
|
|
9519
9692
|
}
|
|
@@ -9870,7 +10043,7 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9870
10043
|
}
|
|
9871
10044
|
for (let i = 0; i < resolvedRefs.length; i++) {
|
|
9872
10045
|
const { absolute, mime } = resolvedRefs[i];
|
|
9873
|
-
const file = new File([
|
|
10046
|
+
const file = new File([readFileSync16(absolute)], basename4(absolute), { type: mime });
|
|
9874
10047
|
const out = await sendStagedFile(file, `ref=${i}`);
|
|
9875
10048
|
if (!out.ok) {
|
|
9876
10049
|
exit("error");
|
|
@@ -9889,7 +10062,7 @@ app4.post("/reply", requireAdminSession, async (c) => {
|
|
|
9889
10062
|
var whatsapp_reader_default = app4;
|
|
9890
10063
|
|
|
9891
10064
|
// server/routes/public-reader.ts
|
|
9892
|
-
import { statSync as statSync6, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as
|
|
10065
|
+
import { statSync as statSync6, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as readFileSync17, readdirSync as readdirSync11 } from "fs";
|
|
9893
10066
|
import { basename as basename5, dirname as dirname5, join as join16, resolve as resolve13, sep as sep4 } from "path";
|
|
9894
10067
|
|
|
9895
10068
|
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
@@ -10123,7 +10296,7 @@ data: ${JSON.stringify(turn)}
|
|
|
10123
10296
|
});
|
|
10124
10297
|
});
|
|
10125
10298
|
var ATT_TAG = "[public-attachment]";
|
|
10126
|
-
var
|
|
10299
|
+
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;
|
|
10127
10300
|
app5.get("/attachment/:attachmentId", (c) => {
|
|
10128
10301
|
const visitor = resolveVisitor(c);
|
|
10129
10302
|
const attachmentId = c.req.param("attachmentId");
|
|
@@ -10135,7 +10308,7 @@ app5.get("/attachment/:attachmentId", (c) => {
|
|
|
10135
10308
|
return new Response("Unauthorized", { status: 401 });
|
|
10136
10309
|
}
|
|
10137
10310
|
console.log(`${ATT_TAG} op=request session=${ses} att=${at}`);
|
|
10138
|
-
if (!
|
|
10311
|
+
if (!ATTACHMENT_ID_RE2.test(attachmentId) || !SESSION_ID_RE2.test(sessionId)) {
|
|
10139
10312
|
console.error(`${ATT_TAG} op=denied session=${ses} att=${at} reason=bad-id`);
|
|
10140
10313
|
return new Response("Not found", { status: 404 });
|
|
10141
10314
|
}
|
|
@@ -10164,19 +10337,22 @@ app5.get("/attachment/:attachmentId", (c) => {
|
|
|
10164
10337
|
let dataFile;
|
|
10165
10338
|
let buffer;
|
|
10166
10339
|
try {
|
|
10167
|
-
dataFile =
|
|
10340
|
+
dataFile = readdirSync11(dir).find((f) => !f.endsWith(".meta.json") && !f.endsWith(EXTRACTED_TEXT_SUFFIX));
|
|
10168
10341
|
if (!dataFile) throw new Error("no data file");
|
|
10169
|
-
buffer =
|
|
10342
|
+
buffer = readFileSync17(resolve13(dir, dataFile));
|
|
10170
10343
|
} catch {
|
|
10171
10344
|
console.error(`${ATT_TAG} op=denied session=${ses} att=${at} reason=not-found`);
|
|
10172
10345
|
return new Response("Not found", { status: 404 });
|
|
10173
10346
|
}
|
|
10174
|
-
|
|
10347
|
+
const inlineSafe = isInlineSafeMime(meta.mimeType);
|
|
10348
|
+
const disposition = inlineSafe ? "inline" : "attachment";
|
|
10349
|
+
console.log(`${ATT_TAG} op=served session=${ses} att=${at} bytes=${buffer.length} mime=${meta.mimeType} disposition=${disposition}${inlineSafe ? "" : " reason=non-preview-mime"}`);
|
|
10175
10350
|
const safeName = meta.filename.replace(/["\\\r\n]/g, "_");
|
|
10176
10351
|
return new Response(new Uint8Array(buffer), {
|
|
10177
10352
|
headers: {
|
|
10178
10353
|
"Content-Type": meta.mimeType,
|
|
10179
|
-
"Content-Disposition":
|
|
10354
|
+
"Content-Disposition": `${disposition}; filename="${safeName}"`,
|
|
10355
|
+
"X-Content-Type-Options": "nosniff",
|
|
10180
10356
|
"Cache-Control": "private, max-age=3600"
|
|
10181
10357
|
}
|
|
10182
10358
|
});
|
|
@@ -10186,10 +10362,10 @@ var public_reader_default = app5;
|
|
|
10186
10362
|
// server/routes/webchat.ts
|
|
10187
10363
|
import { basename as basename6, dirname as dirname6 } from "path";
|
|
10188
10364
|
import { join as join19 } from "path";
|
|
10189
|
-
import { existsSync as existsSync12, readdirSync as
|
|
10365
|
+
import { existsSync as existsSync12, readdirSync as readdirSync13, readFileSync as readFileSync20, renameSync as renameSync4, statSync as statSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
10190
10366
|
|
|
10191
10367
|
// server/canonical-webchat-override.ts
|
|
10192
|
-
import { readFileSync as
|
|
10368
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync5, renameSync as renameSync2 } from "fs";
|
|
10193
10369
|
import { join as join17 } from "path";
|
|
10194
10370
|
var FILE = "canonical-webchat-session.json";
|
|
10195
10371
|
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}$/;
|
|
@@ -10198,7 +10374,7 @@ function canonicalOverridePath(accountDir) {
|
|
|
10198
10374
|
}
|
|
10199
10375
|
function readRaw(accountDir) {
|
|
10200
10376
|
try {
|
|
10201
|
-
return JSON.parse(
|
|
10377
|
+
return JSON.parse(readFileSync18(canonicalOverridePath(accountDir), "utf8"));
|
|
10202
10378
|
} catch {
|
|
10203
10379
|
return null;
|
|
10204
10380
|
}
|
|
@@ -10273,7 +10449,7 @@ function isNewSessionEffortLevel(value) {
|
|
|
10273
10449
|
}
|
|
10274
10450
|
|
|
10275
10451
|
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
10276
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readdirSync as
|
|
10452
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readdirSync as readdirSync12, readFileSync as readFileSync19, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
10277
10453
|
import { join as join18 } from "path";
|
|
10278
10454
|
function escapeRegExp(s) {
|
|
10279
10455
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -10303,7 +10479,7 @@ function createSidecarStore(config) {
|
|
|
10303
10479
|
function readFileAt(path2) {
|
|
10304
10480
|
let raw;
|
|
10305
10481
|
try {
|
|
10306
|
-
raw =
|
|
10482
|
+
raw = readFileSync19(path2, "utf8");
|
|
10307
10483
|
} catch {
|
|
10308
10484
|
return null;
|
|
10309
10485
|
}
|
|
@@ -10319,7 +10495,7 @@ function createSidecarStore(config) {
|
|
|
10319
10495
|
function readAll(sessionsDir, onSkip) {
|
|
10320
10496
|
let names;
|
|
10321
10497
|
try {
|
|
10322
|
-
names =
|
|
10498
|
+
names = readdirSync12(sessionsDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name);
|
|
10323
10499
|
} catch {
|
|
10324
10500
|
return [];
|
|
10325
10501
|
}
|
|
@@ -10329,7 +10505,7 @@ function createSidecarStore(config) {
|
|
|
10329
10505
|
const path2 = join18(sessionsDir, name);
|
|
10330
10506
|
let raw;
|
|
10331
10507
|
try {
|
|
10332
|
-
raw =
|
|
10508
|
+
raw = readFileSync19(path2, "utf8");
|
|
10333
10509
|
} catch {
|
|
10334
10510
|
onSkip?.(name, "unreadable");
|
|
10335
10511
|
continue;
|
|
@@ -10412,7 +10588,7 @@ function locateSidecar(sessionId) {
|
|
|
10412
10588
|
const projectsRoot = join19(cfg, "projects");
|
|
10413
10589
|
let slugs;
|
|
10414
10590
|
try {
|
|
10415
|
-
slugs =
|
|
10591
|
+
slugs = readdirSync13(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
10416
10592
|
} catch {
|
|
10417
10593
|
return null;
|
|
10418
10594
|
}
|
|
@@ -10895,7 +11071,7 @@ ${note}` : note;
|
|
|
10895
11071
|
}
|
|
10896
11072
|
const accountJsonPath = join19(account.accountDir, "account.json");
|
|
10897
11073
|
try {
|
|
10898
|
-
const parsed = JSON.parse(
|
|
11074
|
+
const parsed = JSON.parse(readFileSync20(accountJsonPath, "utf8"));
|
|
10899
11075
|
if (op === "model") parsed.adminModel = value;
|
|
10900
11076
|
else if (op === "effort") parsed.effort = value;
|
|
10901
11077
|
else parsed.adminPermissionMode = value;
|
|
@@ -11013,7 +11189,7 @@ ${note}` : note;
|
|
|
11013
11189
|
import { resolve as resolve14 } from "path";
|
|
11014
11190
|
|
|
11015
11191
|
// app/lib/claude-agent/specialist-roster.ts
|
|
11016
|
-
import { existsSync as existsSync13, readFileSync as
|
|
11192
|
+
import { existsSync as existsSync13, readFileSync as readFileSync21, readdirSync as readdirSync14 } from "fs";
|
|
11017
11193
|
import { join as join20 } from "path";
|
|
11018
11194
|
function field(fm, name) {
|
|
11019
11195
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
@@ -11026,14 +11202,14 @@ function field(fm, name) {
|
|
|
11026
11202
|
}
|
|
11027
11203
|
function readSpecialistRoster(specialistsDir) {
|
|
11028
11204
|
if (!existsSync13(specialistsDir)) return { specialists: [], skipped: [] };
|
|
11029
|
-
const entries =
|
|
11205
|
+
const entries = readdirSync14(specialistsDir);
|
|
11030
11206
|
const specialists = [];
|
|
11031
11207
|
const skipped = [];
|
|
11032
11208
|
for (const file of entries.sort()) {
|
|
11033
11209
|
if (!file.endsWith(".md")) continue;
|
|
11034
11210
|
let raw;
|
|
11035
11211
|
try {
|
|
11036
|
-
raw =
|
|
11212
|
+
raw = readFileSync21(join20(specialistsDir, file), "utf-8");
|
|
11037
11213
|
} catch (err) {
|
|
11038
11214
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
11039
11215
|
continue;
|
|
@@ -11151,7 +11327,7 @@ var webchat_greeting_default = app6;
|
|
|
11151
11327
|
// server/routes/telegram.ts
|
|
11152
11328
|
import { homedir as homedir2 } from "os";
|
|
11153
11329
|
import { resolve as resolve15, join as join21 } from "path";
|
|
11154
|
-
import { existsSync as existsSync14, readFileSync as
|
|
11330
|
+
import { existsSync as existsSync14, readFileSync as readFileSync22 } from "fs";
|
|
11155
11331
|
|
|
11156
11332
|
// app/lib/telegram/gateway/instance.ts
|
|
11157
11333
|
var instance = null;
|
|
@@ -11213,7 +11389,7 @@ function configDirName() {
|
|
|
11213
11389
|
const brandPath = join21(platformRoot3, "config", "brand.json");
|
|
11214
11390
|
if (existsSync14(brandPath)) {
|
|
11215
11391
|
try {
|
|
11216
|
-
return JSON.parse(
|
|
11392
|
+
return JSON.parse(readFileSync22(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
11217
11393
|
} catch {
|
|
11218
11394
|
}
|
|
11219
11395
|
}
|
|
@@ -11236,7 +11412,7 @@ app7.post("/", async (c) => {
|
|
|
11236
11412
|
console.error(`${TAG23} op=reject reason=no-secret-file botType=${botType}`);
|
|
11237
11413
|
return c.json({ ok: false }, 401);
|
|
11238
11414
|
}
|
|
11239
|
-
const expected =
|
|
11415
|
+
const expected = readFileSync22(sp, "utf-8").trim();
|
|
11240
11416
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
11241
11417
|
if (got !== expected) {
|
|
11242
11418
|
console.error(`${TAG23} op=reject reason=bad-secret botType=${botType}`);
|
|
@@ -11300,7 +11476,7 @@ var telegram_default = app7;
|
|
|
11300
11476
|
|
|
11301
11477
|
// server/routes/quickbooks.ts
|
|
11302
11478
|
import { join as join22 } from "path";
|
|
11303
|
-
import { existsSync as existsSync15, readFileSync as
|
|
11479
|
+
import { existsSync as existsSync15, readFileSync as readFileSync23, writeFileSync as writeFileSync8, mkdirSync as mkdirSync4, rmSync, renameSync as renameSync5 } from "fs";
|
|
11304
11480
|
var TAG24 = "[quickbooks]";
|
|
11305
11481
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
11306
11482
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
@@ -11327,7 +11503,7 @@ async function completeConsent(args) {
|
|
|
11327
11503
|
try {
|
|
11328
11504
|
let pending;
|
|
11329
11505
|
try {
|
|
11330
|
-
pending = JSON.parse(
|
|
11506
|
+
pending = JSON.parse(readFileSync23(claimFile, "utf-8"));
|
|
11331
11507
|
} catch {
|
|
11332
11508
|
console.error(`${TAG24} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
11333
11509
|
return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
|
|
@@ -11343,7 +11519,7 @@ async function completeConsent(args) {
|
|
|
11343
11519
|
if (!existsSync15(storePath(accountDir))) {
|
|
11344
11520
|
return { ok: false, status: 500, message: "No QuickBooks credentials are stored for this account.", stateValid: true };
|
|
11345
11521
|
}
|
|
11346
|
-
const store2 = JSON.parse(
|
|
11522
|
+
const store2 = JSON.parse(readFileSync23(storePath(accountDir), "utf-8"));
|
|
11347
11523
|
const form = new URLSearchParams({
|
|
11348
11524
|
grant_type: "authorization_code",
|
|
11349
11525
|
code,
|
|
@@ -11377,7 +11553,7 @@ async function completeConsent(args) {
|
|
|
11377
11553
|
};
|
|
11378
11554
|
mkdirSync4(join22(accountDir, "secrets"), { recursive: true });
|
|
11379
11555
|
writeFileSync8(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
11380
|
-
const persisted = JSON.parse(
|
|
11556
|
+
const persisted = JSON.parse(readFileSync23(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
11381
11557
|
console.error(`${TAG24} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
11382
11558
|
return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
|
|
11383
11559
|
} finally {
|
|
@@ -11408,7 +11584,7 @@ var quickbooks_default = app8;
|
|
|
11408
11584
|
|
|
11409
11585
|
// server/routes/onboarding.ts
|
|
11410
11586
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync3 } from "child_process";
|
|
11411
|
-
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync10, writeSync, existsSync as existsSync17, readFileSync as
|
|
11587
|
+
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";
|
|
11412
11588
|
import { createHash as createHash4, randomUUID as randomUUID7 } from "crypto";
|
|
11413
11589
|
|
|
11414
11590
|
// app/lib/claude-spawn-env.ts
|
|
@@ -11546,7 +11722,7 @@ function readHostCredsBlob(service) {
|
|
|
11546
11722
|
}
|
|
11547
11723
|
|
|
11548
11724
|
// ../lib/admins-write/src/index.ts
|
|
11549
|
-
import { existsSync as existsSync16, readFileSync as
|
|
11725
|
+
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";
|
|
11550
11726
|
import { dirname as dirname7, join as join23 } from "path";
|
|
11551
11727
|
function id8(value) {
|
|
11552
11728
|
return value.slice(0, 8);
|
|
@@ -11589,7 +11765,7 @@ function writeAdminEntry(input) {
|
|
|
11589
11765
|
try {
|
|
11590
11766
|
let users = [];
|
|
11591
11767
|
if (existsSync16(input.usersFile)) {
|
|
11592
|
-
const raw =
|
|
11768
|
+
const raw = readFileSync24(input.usersFile, "utf-8").trim();
|
|
11593
11769
|
if (raw) {
|
|
11594
11770
|
const parsed = JSON.parse(raw);
|
|
11595
11771
|
if (!Array.isArray(parsed)) {
|
|
@@ -11624,7 +11800,7 @@ function writeAdminEntry(input) {
|
|
|
11624
11800
|
if (!existsSync16(accountJsonPath)) {
|
|
11625
11801
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
11626
11802
|
}
|
|
11627
|
-
const config = JSON.parse(
|
|
11803
|
+
const config = JSON.parse(readFileSync24(accountJsonPath, "utf-8"));
|
|
11628
11804
|
const admins = config.admins ?? [];
|
|
11629
11805
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
11630
11806
|
result.accountJsonResult = "noop";
|
|
@@ -11646,7 +11822,7 @@ function computeAdminStoreDivergence(input) {
|
|
|
11646
11822
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
11647
11823
|
if (existsSync16(input.usersFile)) {
|
|
11648
11824
|
try {
|
|
11649
|
-
const raw =
|
|
11825
|
+
const raw = readFileSync24(input.usersFile, "utf-8").trim();
|
|
11650
11826
|
if (raw) {
|
|
11651
11827
|
const users = JSON.parse(raw);
|
|
11652
11828
|
for (const u of users) {
|
|
@@ -11661,7 +11837,7 @@ function computeAdminStoreDivergence(input) {
|
|
|
11661
11837
|
if (existsSync16(input.accountsDir)) {
|
|
11662
11838
|
let entries;
|
|
11663
11839
|
try {
|
|
11664
|
-
entries =
|
|
11840
|
+
entries = readdirSync15(input.accountsDir);
|
|
11665
11841
|
} catch (err) {
|
|
11666
11842
|
result.errors.push({ source: input.accountsDir, detail: err instanceof Error ? err.message : String(err) });
|
|
11667
11843
|
return result;
|
|
@@ -11678,7 +11854,7 @@ function computeAdminStoreDivergence(input) {
|
|
|
11678
11854
|
if (!existsSync16(accountJsonPath)) continue;
|
|
11679
11855
|
let admins = [];
|
|
11680
11856
|
try {
|
|
11681
|
-
const config = JSON.parse(
|
|
11857
|
+
const config = JSON.parse(readFileSync24(accountJsonPath, "utf-8"));
|
|
11682
11858
|
admins = config.admins ?? [];
|
|
11683
11859
|
} catch (err) {
|
|
11684
11860
|
result.errors.push({ source: accountJsonPath, detail: err instanceof Error ? err.message : String(err) });
|
|
@@ -11727,7 +11903,7 @@ function hashPin2(pin) {
|
|
|
11727
11903
|
}
|
|
11728
11904
|
function readUsersFile2() {
|
|
11729
11905
|
if (!existsSync17(USERS_FILE)) return null;
|
|
11730
|
-
const raw =
|
|
11906
|
+
const raw = readFileSync25(USERS_FILE, "utf-8").trim();
|
|
11731
11907
|
if (!raw) return [];
|
|
11732
11908
|
return JSON.parse(raw);
|
|
11733
11909
|
}
|
|
@@ -11937,7 +12113,7 @@ app9.post("/set-pin", async (c) => {
|
|
|
11937
12113
|
let installOwner = null;
|
|
11938
12114
|
if (existsSync17(INSTALL_OWNER_FILE)) {
|
|
11939
12115
|
try {
|
|
11940
|
-
const raw =
|
|
12116
|
+
const raw = readFileSync25(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
11941
12117
|
if (raw.length > 0) installOwner = raw;
|
|
11942
12118
|
} catch (err) {
|
|
11943
12119
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -12085,7 +12261,7 @@ app9.put("/set-pin", requireAdminSession, async (c) => {
|
|
|
12085
12261
|
let installOwner = null;
|
|
12086
12262
|
if (existsSync17(INSTALL_OWNER_FILE)) {
|
|
12087
12263
|
try {
|
|
12088
|
-
const raw =
|
|
12264
|
+
const raw = readFileSync25(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
12089
12265
|
if (raw.length > 0) installOwner = raw;
|
|
12090
12266
|
} catch (err) {
|
|
12091
12267
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -12487,7 +12663,7 @@ app12.get("/", requireAdminSession, async (c) => {
|
|
|
12487
12663
|
var accounts_default = app12;
|
|
12488
12664
|
|
|
12489
12665
|
// server/routes/admin/logs.ts
|
|
12490
|
-
import { existsSync as existsSync20, readdirSync as
|
|
12666
|
+
import { existsSync as existsSync20, readdirSync as readdirSync16, readFileSync as readFileSync26, statSync as statSync10 } from "fs";
|
|
12491
12667
|
import { resolve as resolve16, basename as basename7 } from "path";
|
|
12492
12668
|
|
|
12493
12669
|
// app/lib/logs-read-resolve.ts
|
|
@@ -12526,7 +12702,7 @@ app13.get("/", async (c) => {
|
|
|
12526
12702
|
const filePath = resolve16(dir, safe);
|
|
12527
12703
|
searched.push(filePath);
|
|
12528
12704
|
try {
|
|
12529
|
-
const buffer =
|
|
12705
|
+
const buffer = readFileSync26(filePath);
|
|
12530
12706
|
const onDiskBytes = statSync10(filePath).size;
|
|
12531
12707
|
const headers = {
|
|
12532
12708
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -12591,7 +12767,7 @@ app13.get("/", async (c) => {
|
|
|
12591
12767
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
12592
12768
|
try {
|
|
12593
12769
|
const filename = basename7(hit.path);
|
|
12594
|
-
const buffer =
|
|
12770
|
+
const buffer = readFileSync26(hit.path);
|
|
12595
12771
|
const onDiskBytes = statSync10(hit.path).size;
|
|
12596
12772
|
const headers = {
|
|
12597
12773
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -12629,7 +12805,7 @@ app13.get("/", async (c) => {
|
|
|
12629
12805
|
if (!existsSync20(dir)) continue;
|
|
12630
12806
|
let files;
|
|
12631
12807
|
try {
|
|
12632
|
-
files =
|
|
12808
|
+
files = readdirSync16(dir).filter((f) => f.endsWith(".log"));
|
|
12633
12809
|
} catch (err) {
|
|
12634
12810
|
const reason = err instanceof Error ? err.message : String(err);
|
|
12635
12811
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
@@ -12638,7 +12814,7 @@ app13.get("/", async (c) => {
|
|
|
12638
12814
|
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 }) => {
|
|
12639
12815
|
seen.add(name);
|
|
12640
12816
|
try {
|
|
12641
|
-
const content =
|
|
12817
|
+
const content = readFileSync26(resolve16(dir, name));
|
|
12642
12818
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
12643
12819
|
logs[name] = tail.trim() || "(empty)";
|
|
12644
12820
|
} catch (err) {
|
|
@@ -12681,7 +12857,7 @@ import { readFile as readFile2, readdir } from "fs/promises";
|
|
|
12681
12857
|
import { existsSync as existsSync21 } from "fs";
|
|
12682
12858
|
import { resolve as resolve17 } from "path";
|
|
12683
12859
|
var app15 = new Hono();
|
|
12684
|
-
var
|
|
12860
|
+
var ATTACHMENT_ID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12685
12861
|
function uploadsDirFor2(accountId, attachmentId) {
|
|
12686
12862
|
return resolve17(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
12687
12863
|
}
|
|
@@ -12695,7 +12871,7 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
12695
12871
|
console.log(`[admin-attachment] op=miss attachmentId=${shortId2} session=${shortSession} status=401 reason=no-account`);
|
|
12696
12872
|
return new Response("Unauthorized", { status: 401 });
|
|
12697
12873
|
}
|
|
12698
|
-
if (!
|
|
12874
|
+
if (!ATTACHMENT_ID_RE3.test(attachmentId)) {
|
|
12699
12875
|
console.log(`[admin-attachment] op=miss attachmentId=${shortId2} session=${shortSession} status=404 reason=bad-id`);
|
|
12700
12876
|
return new Response("Not found", { status: 404 });
|
|
12701
12877
|
}
|
|
@@ -12737,10 +12913,16 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
12737
12913
|
}
|
|
12738
12914
|
const filePath = resolve17(dir, dataFile);
|
|
12739
12915
|
const buffer = await readFile2(filePath);
|
|
12916
|
+
const inlineSafe = isInlineSafeMime(meta.mimeType);
|
|
12917
|
+
const safeName = meta.filename.replace(/["\\\r\n]/g, "_");
|
|
12918
|
+
if (!inlineSafe) {
|
|
12919
|
+
console.log(`[admin-attachment] op=served attachmentId=${shortId2} disposition=attachment reason=non-preview-mime mime=${meta.mimeType}`);
|
|
12920
|
+
}
|
|
12740
12921
|
return new Response(new Uint8Array(buffer), {
|
|
12741
12922
|
headers: {
|
|
12742
12923
|
"Content-Type": meta.mimeType,
|
|
12743
|
-
"Content-Disposition":
|
|
12924
|
+
"Content-Disposition": `${inlineSafe ? "inline" : "attachment"}; filename="${safeName}"`,
|
|
12925
|
+
"X-Content-Type-Options": "nosniff",
|
|
12744
12926
|
"Cache-Control": "private, max-age=3600"
|
|
12745
12927
|
}
|
|
12746
12928
|
});
|
|
@@ -12749,7 +12931,7 @@ var attachment_default = app15;
|
|
|
12749
12931
|
|
|
12750
12932
|
// server/routes/admin/agents.ts
|
|
12751
12933
|
import { resolve as resolve18 } from "path";
|
|
12752
|
-
import { readdirSync as
|
|
12934
|
+
import { readdirSync as readdirSync17, readFileSync as readFileSync27, existsSync as existsSync22, rmSync as rmSync2 } from "fs";
|
|
12753
12935
|
var app16 = new Hono();
|
|
12754
12936
|
app16.get("/", (c) => {
|
|
12755
12937
|
const account = resolveAccount();
|
|
@@ -12758,14 +12940,14 @@ app16.get("/", (c) => {
|
|
|
12758
12940
|
if (!existsSync22(agentsDir)) return c.json({ agents: [] });
|
|
12759
12941
|
const agents = [];
|
|
12760
12942
|
try {
|
|
12761
|
-
const entries =
|
|
12943
|
+
const entries = readdirSync17(agentsDir, { withFileTypes: true });
|
|
12762
12944
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
12763
12945
|
if (!entry.isDirectory()) continue;
|
|
12764
12946
|
if (entry.name === "admin") continue;
|
|
12765
12947
|
const configPath2 = resolve18(agentsDir, entry.name, "config.json");
|
|
12766
12948
|
if (!existsSync22(configPath2)) continue;
|
|
12767
12949
|
try {
|
|
12768
|
-
const config = JSON.parse(
|
|
12950
|
+
const config = JSON.parse(readFileSync27(configPath2, "utf-8"));
|
|
12769
12951
|
agents.push({
|
|
12770
12952
|
slug: entry.name,
|
|
12771
12953
|
displayName: config.displayName ?? entry.name,
|
|
@@ -13524,7 +13706,7 @@ app17.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
13524
13706
|
var sessions_default = app17;
|
|
13525
13707
|
|
|
13526
13708
|
// app/lib/claude-agent/spawn-context.ts
|
|
13527
|
-
import { existsSync as existsSync24, readFileSync as
|
|
13709
|
+
import { existsSync as existsSync24, readFileSync as readFileSync28, readdirSync as readdirSync18, statSync as statSync11 } from "fs";
|
|
13528
13710
|
import { dirname as dirname9, resolve as resolve19, join as join27 } from "path";
|
|
13529
13711
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
13530
13712
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
@@ -13573,7 +13755,7 @@ function extractPluginToolDescriptions(pluginDir) {
|
|
|
13573
13755
|
for (const path2 of candidates) {
|
|
13574
13756
|
if (!existsSync24(path2)) continue;
|
|
13575
13757
|
try {
|
|
13576
|
-
raw =
|
|
13758
|
+
raw = readFileSync28(path2, "utf-8");
|
|
13577
13759
|
break;
|
|
13578
13760
|
} catch {
|
|
13579
13761
|
}
|
|
@@ -13624,7 +13806,7 @@ function listPluginDirs() {
|
|
|
13624
13806
|
const out = /* @__PURE__ */ new Map();
|
|
13625
13807
|
const platformPlugins = resolve19(PLATFORM_ROOT, "plugins");
|
|
13626
13808
|
if (existsSync24(platformPlugins)) {
|
|
13627
|
-
for (const name of
|
|
13809
|
+
for (const name of readdirSync18(platformPlugins)) {
|
|
13628
13810
|
const dir = join27(platformPlugins, name);
|
|
13629
13811
|
try {
|
|
13630
13812
|
if (statSync11(dir).isDirectory()) out.set(name, dir);
|
|
@@ -13634,11 +13816,11 @@ function listPluginDirs() {
|
|
|
13634
13816
|
}
|
|
13635
13817
|
const premiumRoot = resolve19(dirname9(PLATFORM_ROOT), "premium-plugins");
|
|
13636
13818
|
if (existsSync24(premiumRoot)) {
|
|
13637
|
-
for (const bundle of
|
|
13819
|
+
for (const bundle of readdirSync18(premiumRoot)) {
|
|
13638
13820
|
const bundlePlugins = join27(premiumRoot, bundle, "plugins");
|
|
13639
13821
|
if (!existsSync24(bundlePlugins)) continue;
|
|
13640
13822
|
try {
|
|
13641
|
-
for (const name of
|
|
13823
|
+
for (const name of readdirSync18(bundlePlugins)) {
|
|
13642
13824
|
const dir = join27(bundlePlugins, name);
|
|
13643
13825
|
try {
|
|
13644
13826
|
if (statSync11(dir).isDirectory()) out.set(name, dir);
|
|
@@ -13655,7 +13837,7 @@ function readEnabledPlugins(accountId) {
|
|
|
13655
13837
|
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
13656
13838
|
if (!existsSync24(accountFile)) return /* @__PURE__ */ new Set();
|
|
13657
13839
|
try {
|
|
13658
|
-
const parsed = JSON.parse(
|
|
13840
|
+
const parsed = JSON.parse(readFileSync28(accountFile, "utf-8"));
|
|
13659
13841
|
return new Set(
|
|
13660
13842
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
13661
13843
|
);
|
|
@@ -13667,7 +13849,7 @@ function readFrontmatter(path2) {
|
|
|
13667
13849
|
if (!existsSync24(path2)) return null;
|
|
13668
13850
|
let raw;
|
|
13669
13851
|
try {
|
|
13670
|
-
raw =
|
|
13852
|
+
raw = readFileSync28(path2, "utf-8");
|
|
13671
13853
|
} catch {
|
|
13672
13854
|
return null;
|
|
13673
13855
|
}
|
|
@@ -13729,7 +13911,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
13729
13911
|
if (!existsSync24(specialistsDir)) return [];
|
|
13730
13912
|
let entries;
|
|
13731
13913
|
try {
|
|
13732
|
-
entries =
|
|
13914
|
+
entries = readdirSync18(specialistsDir);
|
|
13733
13915
|
} catch {
|
|
13734
13916
|
return [];
|
|
13735
13917
|
}
|
|
@@ -13775,7 +13957,7 @@ function computeDormantPlugins(accountId) {
|
|
|
13775
13957
|
if (!existsSync24(accountFile)) return [];
|
|
13776
13958
|
let enabled;
|
|
13777
13959
|
try {
|
|
13778
|
-
const raw =
|
|
13960
|
+
const raw = readFileSync28(accountFile, "utf-8");
|
|
13779
13961
|
const parsed = JSON.parse(raw);
|
|
13780
13962
|
enabled = new Set(
|
|
13781
13963
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -13790,7 +13972,7 @@ function computeDormantPlugins(accountId) {
|
|
|
13790
13972
|
if (!existsSync24(pluginsDir)) return [];
|
|
13791
13973
|
let entries;
|
|
13792
13974
|
try {
|
|
13793
|
-
entries =
|
|
13975
|
+
entries = readdirSync18(pluginsDir);
|
|
13794
13976
|
} catch {
|
|
13795
13977
|
return [];
|
|
13796
13978
|
}
|
|
@@ -13801,7 +13983,7 @@ function computeDormantPlugins(accountId) {
|
|
|
13801
13983
|
if (!existsSync24(manifestPath)) continue;
|
|
13802
13984
|
let manifest;
|
|
13803
13985
|
try {
|
|
13804
|
-
manifest =
|
|
13986
|
+
manifest = readFileSync28(manifestPath, "utf-8");
|
|
13805
13987
|
} catch {
|
|
13806
13988
|
continue;
|
|
13807
13989
|
}
|
|
@@ -13815,13 +13997,13 @@ function computeDormantPlugins(accountId) {
|
|
|
13815
13997
|
}
|
|
13816
13998
|
|
|
13817
13999
|
// server/routes/admin/claude-sessions.ts
|
|
13818
|
-
import { existsSync as existsSync25, readFileSync as
|
|
14000
|
+
import { existsSync as existsSync25, readFileSync as readFileSync29 } from "fs";
|
|
13819
14001
|
import { resolve as resolve20 } from "path";
|
|
13820
14002
|
function readTunnelState(brandConfigDir) {
|
|
13821
14003
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
13822
14004
|
if (!existsSync25(statePath)) return null;
|
|
13823
14005
|
try {
|
|
13824
|
-
const parsed = JSON.parse(
|
|
14006
|
+
const parsed = JSON.parse(readFileSync29(statePath, "utf-8"));
|
|
13825
14007
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
13826
14008
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
13827
14009
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -13835,7 +14017,7 @@ function resolveTunnelUrl() {
|
|
|
13835
14017
|
const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
13836
14018
|
let brand;
|
|
13837
14019
|
try {
|
|
13838
|
-
brand = JSON.parse(
|
|
14020
|
+
brand = JSON.parse(readFileSync29(resolve20(platformRoot3, "config", "brand.json"), "utf-8"));
|
|
13839
14021
|
} catch {
|
|
13840
14022
|
return null;
|
|
13841
14023
|
}
|
|
@@ -14078,7 +14260,7 @@ var events_default = app20;
|
|
|
14078
14260
|
|
|
14079
14261
|
// server/routes/admin/files.ts
|
|
14080
14262
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync26 } from "fs";
|
|
14081
|
-
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename } from "fs/promises";
|
|
14263
|
+
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename, rmdir } from "fs/promises";
|
|
14082
14264
|
import { realpathSync as realpathSync5 } from "fs";
|
|
14083
14265
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
14084
14266
|
import { basename as basename9, dirname as dirname10, join as join29, relative as relative4, resolve as resolve22, sep as sep6 } from "path";
|
|
@@ -14956,19 +15138,55 @@ async function readAccountNames() {
|
|
|
14956
15138
|
}
|
|
14957
15139
|
return map;
|
|
14958
15140
|
}
|
|
15141
|
+
async function servableFilesIn(dirAbs, uuid) {
|
|
15142
|
+
const metaName = `${uuid}.meta.json`;
|
|
15143
|
+
let dirents;
|
|
15144
|
+
try {
|
|
15145
|
+
dirents = await readdir3(dirAbs, { withFileTypes: true });
|
|
15146
|
+
} catch {
|
|
15147
|
+
return [];
|
|
15148
|
+
}
|
|
15149
|
+
const out = [];
|
|
15150
|
+
for (const d of dirents) {
|
|
15151
|
+
if (!d.isFile()) continue;
|
|
15152
|
+
if (d.name === metaName) continue;
|
|
15153
|
+
if (d.name.endsWith(EXTRACTED_TEXT_SUFFIX)) continue;
|
|
15154
|
+
out.push(d.name);
|
|
15155
|
+
}
|
|
15156
|
+
return out;
|
|
15157
|
+
}
|
|
14959
15158
|
async function enrich(absolute, entry, accountNames) {
|
|
14960
15159
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
14961
|
-
const
|
|
15160
|
+
const dirAbs = join29(absolute, entry.name);
|
|
15161
|
+
const meta = await readMeta(dirAbs, entry.name);
|
|
14962
15162
|
if (meta?.filename) {
|
|
15163
|
+
const servable = await servableFilesIn(dirAbs, entry.name);
|
|
15164
|
+
if (servable.length === 1) {
|
|
15165
|
+
const innerName = servable[0];
|
|
15166
|
+
let size = null;
|
|
15167
|
+
let modifiedAt = entry.modifiedAt;
|
|
15168
|
+
try {
|
|
15169
|
+
const st = await stat4(join29(dirAbs, innerName));
|
|
15170
|
+
size = st.size;
|
|
15171
|
+
modifiedAt = st.mtime.toISOString();
|
|
15172
|
+
} catch {
|
|
15173
|
+
}
|
|
15174
|
+
entry.kind = "file";
|
|
15175
|
+
entry.displayName = meta.filename;
|
|
15176
|
+
entry.mimeType = meta.mimeType;
|
|
15177
|
+
entry.sizeBytes = size;
|
|
15178
|
+
entry.modifiedAt = modifiedAt;
|
|
15179
|
+
entry.entryPath = `${entry.name}/${innerName}`;
|
|
15180
|
+
return "flattened";
|
|
15181
|
+
}
|
|
14963
15182
|
entry.displayName = meta.filename;
|
|
14964
|
-
|
|
14965
|
-
return;
|
|
15183
|
+
return "kept-as-dir";
|
|
14966
15184
|
}
|
|
14967
15185
|
const accountName = accountNames.get(entry.name);
|
|
14968
15186
|
if (accountName) {
|
|
14969
15187
|
entry.displayName = accountName;
|
|
14970
15188
|
}
|
|
14971
|
-
return;
|
|
15189
|
+
return null;
|
|
14972
15190
|
}
|
|
14973
15191
|
if (entry.kind === "file") {
|
|
14974
15192
|
const dot = entry.name.lastIndexOf(".");
|
|
@@ -14981,6 +15199,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
14981
15199
|
}
|
|
14982
15200
|
}
|
|
14983
15201
|
}
|
|
15202
|
+
return null;
|
|
14984
15203
|
}
|
|
14985
15204
|
function buildDisplayPath(relPath, accountNames) {
|
|
14986
15205
|
if (relPath === "." || relPath === "") return [];
|
|
@@ -15136,8 +15355,18 @@ app21.get("/", requireAdminSession, async (c) => {
|
|
|
15136
15355
|
}
|
|
15137
15356
|
}
|
|
15138
15357
|
const accountNames = await readAccountNames();
|
|
15139
|
-
await Promise.all(entries.map((e) => enrich(absolute, e, accountNames)));
|
|
15358
|
+
const classes = await Promise.all(entries.map((e) => enrich(absolute, e, accountNames)));
|
|
15140
15359
|
sortDirEntries(entries);
|
|
15360
|
+
let flattened = 0;
|
|
15361
|
+
let keptAsDir = 0;
|
|
15362
|
+
for (const cls of classes) {
|
|
15363
|
+
if (cls === "flattened") flattened++;
|
|
15364
|
+
else if (cls === "kept-as-dir") keptAsDir++;
|
|
15365
|
+
}
|
|
15366
|
+
const containers = flattened + keptAsDir;
|
|
15367
|
+
if (containers > 0) {
|
|
15368
|
+
console.error(`[data] op=uploads-flatten containers=${containers} flattened=${flattened} kept-as-dir=${keptAsDir}`);
|
|
15369
|
+
}
|
|
15141
15370
|
const displayPath = buildDisplayPath(relPath, accountNames);
|
|
15142
15371
|
console.error(`[data] file-list path="${relPath}" entries=${entries.length}`);
|
|
15143
15372
|
return c.json({ path: relPath, displayPath, entries });
|
|
@@ -15226,8 +15455,16 @@ app21.get("/download", requireAdminSession, async (c) => {
|
|
|
15226
15455
|
});
|
|
15227
15456
|
}
|
|
15228
15457
|
console.error(`[data] file-download root="${root}" path="${relPath}" size=${info.size}`);
|
|
15229
|
-
|
|
15230
|
-
|
|
15458
|
+
let downloadName = filename;
|
|
15459
|
+
if (root === "data") {
|
|
15460
|
+
const parsed = parseAttachmentPath(relPath);
|
|
15461
|
+
if (parsed) {
|
|
15462
|
+
const meta = await readMeta(dirname10(absolute), parsed.attachmentId);
|
|
15463
|
+
if (meta?.filename) downloadName = meta.filename;
|
|
15464
|
+
}
|
|
15465
|
+
}
|
|
15466
|
+
const safeQuotedName = downloadName.replace(/[\r\n"\\]/g, "_");
|
|
15467
|
+
const encodedName = encodeURIComponent(downloadName);
|
|
15231
15468
|
return new Response(webStream, {
|
|
15232
15469
|
status: 200,
|
|
15233
15470
|
headers: {
|
|
@@ -15322,7 +15559,13 @@ app21.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
15322
15559
|
if (over) return over;
|
|
15323
15560
|
}
|
|
15324
15561
|
} else if (info.isFile()) {
|
|
15325
|
-
|
|
15562
|
+
let member = basename9(absolute);
|
|
15563
|
+
const parsed = parseAttachmentPath(relPath);
|
|
15564
|
+
if (parsed) {
|
|
15565
|
+
const meta = await readMeta(dirname10(absolute), parsed.attachmentId);
|
|
15566
|
+
if (meta?.filename) member = meta.filename;
|
|
15567
|
+
}
|
|
15568
|
+
const over = await addFile(absolute, info.size, member);
|
|
15326
15569
|
if (over) return over;
|
|
15327
15570
|
} else {
|
|
15328
15571
|
return c.json({ error: "Path is not a file or directory" }, 400);
|
|
@@ -15742,7 +15985,9 @@ app21.delete("/", requireAdminSession, async (c) => {
|
|
|
15742
15985
|
}
|
|
15743
15986
|
const dot = base.lastIndexOf(".");
|
|
15744
15987
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
15745
|
-
const
|
|
15988
|
+
const containerDir = dirname10(absolute);
|
|
15989
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join29(containerDir, `${stem}.meta.json`) : null;
|
|
15990
|
+
const isAttachmentContainer = UUID_RE3.test(stem) && basename9(containerDir) === stem;
|
|
15746
15991
|
await unlink2(absolute);
|
|
15747
15992
|
if (sidecarPath) {
|
|
15748
15993
|
try {
|
|
@@ -15750,6 +15995,12 @@ app21.delete("/", requireAdminSession, async (c) => {
|
|
|
15750
15995
|
} catch {
|
|
15751
15996
|
}
|
|
15752
15997
|
}
|
|
15998
|
+
if (isAttachmentContainer) {
|
|
15999
|
+
await unlink2(join29(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
|
|
16000
|
+
});
|
|
16001
|
+
await rmdir(containerDir).catch(() => {
|
|
16002
|
+
});
|
|
16003
|
+
}
|
|
15753
16004
|
console.error(`[data] file-delete path="${relPath}" bytes=${info.size}`);
|
|
15754
16005
|
try {
|
|
15755
16006
|
await dropFileIndex(accountId, relPath);
|
|
@@ -18706,14 +18957,14 @@ app36.get("/", async (c) => {
|
|
|
18706
18957
|
var system_stats_default = app36;
|
|
18707
18958
|
|
|
18708
18959
|
// server/routes/admin/health.ts
|
|
18709
|
-
import { existsSync as existsSync28, readFileSync as
|
|
18960
|
+
import { existsSync as existsSync28, readFileSync as readFileSync30 } from "fs";
|
|
18710
18961
|
import { resolve as resolve24, join as join30 } from "path";
|
|
18711
18962
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
|
|
18712
18963
|
var brandHostname = "maxy";
|
|
18713
18964
|
var brandJsonPath = join30(PLATFORM_ROOT6, "config", "brand.json");
|
|
18714
18965
|
if (existsSync28(brandJsonPath)) {
|
|
18715
18966
|
try {
|
|
18716
|
-
const brand = JSON.parse(
|
|
18967
|
+
const brand = JSON.parse(readFileSync30(brandJsonPath, "utf-8"));
|
|
18717
18968
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
18718
18969
|
} catch {
|
|
18719
18970
|
}
|
|
@@ -18723,7 +18974,7 @@ var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
|
18723
18974
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
18724
18975
|
function readVersion() {
|
|
18725
18976
|
if (!existsSync28(VERSION_FILE)) return "unknown";
|
|
18726
|
-
return
|
|
18977
|
+
return readFileSync30(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
18727
18978
|
}
|
|
18728
18979
|
async function probeConversationDb() {
|
|
18729
18980
|
let session;
|
|
@@ -19599,7 +19850,7 @@ function countVEvents(ics) {
|
|
|
19599
19850
|
}
|
|
19600
19851
|
|
|
19601
19852
|
// server/lib/calendar-availability.ts
|
|
19602
|
-
import { readFileSync as
|
|
19853
|
+
import { readFileSync as readFileSync31 } from "fs";
|
|
19603
19854
|
import { join as join31 } from "path";
|
|
19604
19855
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
19605
19856
|
var REQUIRED_KEYS = [
|
|
@@ -19612,7 +19863,7 @@ function readAvailabilityConfig(accountDir) {
|
|
|
19612
19863
|
const path2 = join31(accountDir, AVAILABILITY_FILENAME);
|
|
19613
19864
|
let raw;
|
|
19614
19865
|
try {
|
|
19615
|
-
raw =
|
|
19866
|
+
raw = readFileSync31(path2, "utf-8");
|
|
19616
19867
|
} catch {
|
|
19617
19868
|
throw new Error(`availability not configured: ${path2} not found`);
|
|
19618
19869
|
}
|
|
@@ -20589,7 +20840,7 @@ app54.route("/request-magic-link", request_magic_link_default);
|
|
|
20589
20840
|
var access_default = app54;
|
|
20590
20841
|
|
|
20591
20842
|
// server/routes/sites.ts
|
|
20592
|
-
import { existsSync as existsSync30, readFileSync as
|
|
20843
|
+
import { existsSync as existsSync30, readFileSync as readFileSync32, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
|
|
20593
20844
|
import { resolve as resolve26 } from "path";
|
|
20594
20845
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
20595
20846
|
var MIME = {
|
|
@@ -20693,7 +20944,7 @@ app55.get("/:rel{.*}", (c) => {
|
|
|
20693
20944
|
}
|
|
20694
20945
|
let body;
|
|
20695
20946
|
try {
|
|
20696
|
-
body =
|
|
20947
|
+
body = readFileSync32(realPath);
|
|
20697
20948
|
} catch (err) {
|
|
20698
20949
|
const code = err?.code;
|
|
20699
20950
|
if (code === "EISDIR") {
|
|
@@ -20729,7 +20980,7 @@ var sites_default = app55;
|
|
|
20729
20980
|
|
|
20730
20981
|
// app/lib/visitor-token.ts
|
|
20731
20982
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
20732
|
-
import { mkdirSync as mkdirSync7, readFileSync as
|
|
20983
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync33, writeFileSync as writeFileSync11 } from "fs";
|
|
20733
20984
|
import { dirname as dirname11 } from "path";
|
|
20734
20985
|
var TOKEN_PREFIX = "v1.";
|
|
20735
20986
|
var SECRET_BYTES = 32;
|
|
@@ -20738,7 +20989,7 @@ var cachedSecret = null;
|
|
|
20738
20989
|
function getSecret() {
|
|
20739
20990
|
if (cachedSecret) return cachedSecret;
|
|
20740
20991
|
try {
|
|
20741
|
-
const hex2 =
|
|
20992
|
+
const hex2 = readFileSync33(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
20742
20993
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
20743
20994
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
20744
20995
|
return cachedSecret;
|
|
@@ -20752,7 +21003,7 @@ function getSecret() {
|
|
|
20752
21003
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
20753
21004
|
} catch {
|
|
20754
21005
|
}
|
|
20755
|
-
const hex =
|
|
21006
|
+
const hex = readFileSync33(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
20756
21007
|
cachedSecret = Buffer.from(hex, "hex");
|
|
20757
21008
|
return cachedSecret;
|
|
20758
21009
|
}
|
|
@@ -20805,7 +21056,7 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
20805
21056
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
20806
21057
|
|
|
20807
21058
|
// app/lib/brand-config.ts
|
|
20808
|
-
import { existsSync as existsSync31, readFileSync as
|
|
21059
|
+
import { existsSync as existsSync31, readFileSync as readFileSync34 } from "fs";
|
|
20809
21060
|
import { join as join33 } from "path";
|
|
20810
21061
|
var cached = null;
|
|
20811
21062
|
var cachedAttempted = false;
|
|
@@ -20817,7 +21068,7 @@ function readBrandConfig() {
|
|
|
20817
21068
|
const brandPath = join33(platformRoot3, "config", "brand.json");
|
|
20818
21069
|
if (!existsSync31(brandPath)) return null;
|
|
20819
21070
|
try {
|
|
20820
|
-
cached = JSON.parse(
|
|
21071
|
+
cached = JSON.parse(readFileSync34(brandPath, "utf-8"));
|
|
20821
21072
|
return cached;
|
|
20822
21073
|
} catch {
|
|
20823
21074
|
return null;
|
|
@@ -24552,7 +24803,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
24552
24803
|
|
|
24553
24804
|
// ../lib/entitlement/src/index.ts
|
|
24554
24805
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
24555
|
-
import { existsSync as existsSync34, readFileSync as
|
|
24806
|
+
import { existsSync as existsSync34, readFileSync as readFileSync35, statSync as statSync13 } from "fs";
|
|
24556
24807
|
import { resolve as resolve32 } from "path";
|
|
24557
24808
|
|
|
24558
24809
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -24616,7 +24867,7 @@ function resolveEntitlement(brand, account) {
|
|
|
24616
24867
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
24617
24868
|
let pubkeyPem;
|
|
24618
24869
|
try {
|
|
24619
|
-
pubkeyPem =
|
|
24870
|
+
pubkeyPem = readFileSync35(pubkeyPath(brand), "utf-8");
|
|
24620
24871
|
} catch (err) {
|
|
24621
24872
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
24622
24873
|
reason: "pubkey-missing"
|
|
@@ -24630,7 +24881,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
24630
24881
|
}
|
|
24631
24882
|
let envelope;
|
|
24632
24883
|
try {
|
|
24633
|
-
envelope = JSON.parse(
|
|
24884
|
+
envelope = JSON.parse(readFileSync35(entitlementPath, "utf-8"));
|
|
24634
24885
|
} catch {
|
|
24635
24886
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
24636
24887
|
}
|
|
@@ -24798,7 +25049,7 @@ if (BRAND_JSON_PATH && !existsSync35(BRAND_JSON_PATH)) {
|
|
|
24798
25049
|
}
|
|
24799
25050
|
if (BRAND_JSON_PATH && existsSync35(BRAND_JSON_PATH)) {
|
|
24800
25051
|
try {
|
|
24801
|
-
const parsed = JSON.parse(
|
|
25052
|
+
const parsed = JSON.parse(readFileSync36(BRAND_JSON_PATH, "utf-8"));
|
|
24802
25053
|
BRAND = { ...BRAND, ...parsed };
|
|
24803
25054
|
} catch (err) {
|
|
24804
25055
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -24834,7 +25085,7 @@ var ALIAS_DOMAINS_PATH = join36(homedir4(), BRAND.configDir, "alias-domains.json
|
|
|
24834
25085
|
function loadAliasDomains() {
|
|
24835
25086
|
try {
|
|
24836
25087
|
if (!existsSync35(ALIAS_DOMAINS_PATH)) return null;
|
|
24837
|
-
const parsed = JSON.parse(
|
|
25088
|
+
const parsed = JSON.parse(readFileSync36(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
24838
25089
|
if (!Array.isArray(parsed)) {
|
|
24839
25090
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
24840
25091
|
return null;
|
|
@@ -25523,7 +25774,7 @@ app61.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
25523
25774
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
25524
25775
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
25525
25776
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
25526
|
-
const body =
|
|
25777
|
+
const body = readFileSync36(filePath);
|
|
25527
25778
|
return c.body(body, 200, {
|
|
25528
25779
|
"Content-Type": contentType,
|
|
25529
25780
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -25553,7 +25804,7 @@ app61.get("/generated/:filename", (c) => {
|
|
|
25553
25804
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
25554
25805
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
25555
25806
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
25556
|
-
const body =
|
|
25807
|
+
const body = readFileSync36(filePath);
|
|
25557
25808
|
return c.body(body, 200, {
|
|
25558
25809
|
"Content-Type": contentType,
|
|
25559
25810
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -25568,7 +25819,7 @@ var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
|
25568
25819
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
25569
25820
|
if (BRAND_JSON_PATH && existsSync35(BRAND_JSON_PATH)) {
|
|
25570
25821
|
try {
|
|
25571
|
-
const fullBrand = JSON.parse(
|
|
25822
|
+
const fullBrand = JSON.parse(readFileSync36(BRAND_JSON_PATH, "utf-8"));
|
|
25572
25823
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
25573
25824
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
25574
25825
|
} catch {
|
|
@@ -25599,7 +25850,7 @@ var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskabl
|
|
|
25599
25850
|
);
|
|
25600
25851
|
var SW_SOURCE = (() => {
|
|
25601
25852
|
try {
|
|
25602
|
-
return
|
|
25853
|
+
return readFileSync36(resolve33(process.cwd(), "public", "sw.js"), "utf-8");
|
|
25603
25854
|
} catch {
|
|
25604
25855
|
return null;
|
|
25605
25856
|
}
|
|
@@ -25609,7 +25860,7 @@ function readInstalledVersion() {
|
|
|
25609
25860
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
25610
25861
|
const versionFile = join36(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
25611
25862
|
if (!existsSync35(versionFile)) return "unknown";
|
|
25612
|
-
const content =
|
|
25863
|
+
const content = readFileSync36(versionFile, "utf-8").trim();
|
|
25613
25864
|
return content || "unknown";
|
|
25614
25865
|
} catch {
|
|
25615
25866
|
return "unknown";
|
|
@@ -25650,7 +25901,7 @@ var clientErrorReporterScript = `<script>
|
|
|
25650
25901
|
function cachedHtml(file) {
|
|
25651
25902
|
let html = htmlCache.get(file);
|
|
25652
25903
|
if (!html) {
|
|
25653
|
-
html =
|
|
25904
|
+
html = readFileSync36(resolve33(process.cwd(), "public", file), "utf-8");
|
|
25654
25905
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
25655
25906
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
25656
25907
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -25673,7 +25924,7 @@ function loadBrandingCache(agentSlug) {
|
|
|
25673
25924
|
if (!accountId) return null;
|
|
25674
25925
|
const cachePath = join36(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
25675
25926
|
if (!existsSync35(cachePath)) return null;
|
|
25676
|
-
return JSON.parse(
|
|
25927
|
+
return JSON.parse(readFileSync36(cachePath, "utf-8"));
|
|
25677
25928
|
} catch {
|
|
25678
25929
|
return null;
|
|
25679
25930
|
}
|
|
@@ -25768,7 +26019,7 @@ app61.use("/vnc-popout.html", logViewerFetch);
|
|
|
25768
26019
|
app61.get("/vnc-popout.html", (c) => {
|
|
25769
26020
|
let html = htmlCache.get("vnc-popout.html");
|
|
25770
26021
|
if (!html) {
|
|
25771
|
-
html =
|
|
26022
|
+
html = readFileSync36(resolve33(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
25772
26023
|
const name = escapeHtml(BRAND.productName);
|
|
25773
26024
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
25774
26025
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -25921,6 +26172,73 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
25921
26172
|
const loop = setInterval(runReconcile, RECONCILE_INTERVAL_MS);
|
|
25922
26173
|
loop.unref();
|
|
25923
26174
|
}
|
|
26175
|
+
{
|
|
26176
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, "..");
|
|
26177
|
+
const publishScript = resolve33(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
26178
|
+
const PUBLISH_INTERVAL_MS = 3e5;
|
|
26179
|
+
const currentAccount = () => {
|
|
26180
|
+
try {
|
|
26181
|
+
return resolveAccount();
|
|
26182
|
+
} catch (err) {
|
|
26183
|
+
console.error(`[calendar-availability] op=publish result=error reason=account-resolve-failed err="${err.message}"`);
|
|
26184
|
+
return null;
|
|
26185
|
+
}
|
|
26186
|
+
};
|
|
26187
|
+
const spawnPublish = (account) => {
|
|
26188
|
+
if (!existsSync35(publishScript)) return;
|
|
26189
|
+
try {
|
|
26190
|
+
const child = spawn3(process.execPath, [publishScript], {
|
|
26191
|
+
env: {
|
|
26192
|
+
...process.env,
|
|
26193
|
+
PLATFORM_ROOT: publishPlatformRoot,
|
|
26194
|
+
PUBLISH_ACCOUNT_ID: account.accountId,
|
|
26195
|
+
PUBLISH_ACCOUNT_DIR: account.accountDir
|
|
26196
|
+
},
|
|
26197
|
+
stdio: "inherit"
|
|
26198
|
+
});
|
|
26199
|
+
child.unref();
|
|
26200
|
+
child.on("error", (err) => console.error(`[calendar-availability] op=publish result=error reason=spawn-failed err="${err.message}"`));
|
|
26201
|
+
} catch (err) {
|
|
26202
|
+
console.error(`[calendar-availability] op=publish result=error reason=spawn-failed err="${err.message}"`);
|
|
26203
|
+
}
|
|
26204
|
+
};
|
|
26205
|
+
const auditSnapshotAge = (account) => {
|
|
26206
|
+
const availPath = resolve33(account.accountDir, "calendar-availability.json");
|
|
26207
|
+
let hasBookingSite = false;
|
|
26208
|
+
try {
|
|
26209
|
+
if (existsSync35(availPath)) {
|
|
26210
|
+
const cfg = JSON.parse(readFileSync36(availPath, "utf-8"));
|
|
26211
|
+
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
26212
|
+
}
|
|
26213
|
+
} catch {
|
|
26214
|
+
}
|
|
26215
|
+
if (!hasBookingSite) return;
|
|
26216
|
+
const statePath = resolve33(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
26217
|
+
let lastSuccessAt = null;
|
|
26218
|
+
if (existsSync35(statePath)) {
|
|
26219
|
+
try {
|
|
26220
|
+
const rec = JSON.parse(readFileSync36(statePath, "utf-8"));
|
|
26221
|
+
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
26222
|
+
} catch {
|
|
26223
|
+
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
|
|
26224
|
+
return;
|
|
26225
|
+
}
|
|
26226
|
+
}
|
|
26227
|
+
const parsed = lastSuccessAt ? Date.parse(lastSuccessAt) : NaN;
|
|
26228
|
+
const ageMs = Number.isNaN(parsed) ? null : Date.now() - parsed;
|
|
26229
|
+
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=${ageMs ?? "na"}`);
|
|
26230
|
+
};
|
|
26231
|
+
const publishTick = () => {
|
|
26232
|
+
const account = currentAccount();
|
|
26233
|
+
if (!account) return;
|
|
26234
|
+
spawnPublish(account);
|
|
26235
|
+
auditSnapshotAge(account);
|
|
26236
|
+
};
|
|
26237
|
+
const firstPublish = setTimeout(publishTick, 2e4);
|
|
26238
|
+
firstPublish.unref();
|
|
26239
|
+
const publishLoop = setInterval(publishTick, PUBLISH_INTERVAL_MS);
|
|
26240
|
+
publishLoop.unref();
|
|
26241
|
+
}
|
|
25924
26242
|
startTimeEntryCensus(() => getSession());
|
|
25925
26243
|
{
|
|
25926
26244
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, "..");
|
|
@@ -26042,7 +26360,7 @@ async function runAdminUserReconcileTick() {
|
|
|
26042
26360
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
26043
26361
|
return;
|
|
26044
26362
|
}
|
|
26045
|
-
const usersRaw =
|
|
26363
|
+
const usersRaw = readFileSync36(USERS_FILE, "utf-8").trim();
|
|
26046
26364
|
if (!usersRaw) {
|
|
26047
26365
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
26048
26366
|
return;
|
|
@@ -26072,7 +26390,7 @@ if (typeof adminUserReconcileTimer.unref === "function") adminUserReconcileTimer
|
|
|
26072
26390
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
26073
26391
|
function countUsersRows() {
|
|
26074
26392
|
if (!existsSync35(USERS_FILE)) return 0;
|
|
26075
|
-
const raw =
|
|
26393
|
+
const raw = readFileSync36(USERS_FILE, "utf-8").trim();
|
|
26076
26394
|
if (!raw) return 0;
|
|
26077
26395
|
const users = JSON.parse(raw);
|
|
26078
26396
|
return users.filter((u) => typeof u.userId === "string").length;
|