@rubytech/create-maxy 1.0.463 → 1.0.464
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 +16 -0
- package/package.json +1 -1
- package/payload/maxy/public/assets/ChatInput--jdCpO3g.css +1 -0
- package/payload/maxy/public/assets/{admin-DWczKVU_.js → admin-CyqdZrov.js} +60 -60
- package/payload/maxy/public/assets/{public-D-52e3uT.js → public-C7AtLTLg.js} +1 -1
- package/payload/maxy/public/index.html +3 -3
- package/payload/maxy/public/public.html +3 -3
- package/payload/maxy/server.js +302 -100
- package/payload/platform/plugins/admin/PLUGIN.md +2 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +86 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +2 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +22 -0
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +5 -5
- package/payload/platform/templates/specialists/agents/browser-specialist.md +1 -1
- package/payload/maxy/public/assets/ChatInput-rWA47V05.css +0 -1
- /package/payload/maxy/public/assets/{ChatInput-C_H-xxtM.js → ChatInput-CLbf-MFS.js} +0 -0
package/payload/maxy/server.js
CHANGED
|
@@ -2485,7 +2485,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
2485
2485
|
});
|
|
2486
2486
|
if (!chunk) {
|
|
2487
2487
|
if (i === 1) {
|
|
2488
|
-
await new Promise((
|
|
2488
|
+
await new Promise((resolve18) => setTimeout(resolve18));
|
|
2489
2489
|
maxReadCount = 3;
|
|
2490
2490
|
continue;
|
|
2491
2491
|
}
|
|
@@ -2852,7 +2852,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
2852
2852
|
|
|
2853
2853
|
// server/index.ts
|
|
2854
2854
|
import { readFileSync as readFileSync19, existsSync as existsSync19, watchFile } from "fs";
|
|
2855
|
-
import { resolve as
|
|
2855
|
+
import { resolve as resolve17, join as join9, basename as basename4 } from "path";
|
|
2856
2856
|
import { homedir as homedir3 } from "os";
|
|
2857
2857
|
|
|
2858
2858
|
// app/api/health/route.ts
|
|
@@ -3091,20 +3091,20 @@ async function probeApiKey() {
|
|
|
3091
3091
|
}
|
|
3092
3092
|
}
|
|
3093
3093
|
function checkPort(port2, timeoutMs = 500) {
|
|
3094
|
-
return new Promise((
|
|
3094
|
+
return new Promise((resolve18) => {
|
|
3095
3095
|
const socket = createConnection(port2, "127.0.0.1");
|
|
3096
3096
|
socket.setTimeout(timeoutMs);
|
|
3097
3097
|
socket.once("connect", () => {
|
|
3098
3098
|
socket.destroy();
|
|
3099
|
-
|
|
3099
|
+
resolve18(true);
|
|
3100
3100
|
});
|
|
3101
3101
|
socket.once("error", () => {
|
|
3102
3102
|
socket.destroy();
|
|
3103
|
-
|
|
3103
|
+
resolve18(false);
|
|
3104
3104
|
});
|
|
3105
3105
|
socket.once("timeout", () => {
|
|
3106
3106
|
socket.destroy();
|
|
3107
|
-
|
|
3107
|
+
resolve18(false);
|
|
3108
3108
|
});
|
|
3109
3109
|
});
|
|
3110
3110
|
}
|
|
@@ -3668,7 +3668,7 @@ ${userContent}`;
|
|
|
3668
3668
|
"dontAsk",
|
|
3669
3669
|
prompt
|
|
3670
3670
|
];
|
|
3671
|
-
return new Promise((
|
|
3671
|
+
return new Promise((resolve18) => {
|
|
3672
3672
|
let stdout = "";
|
|
3673
3673
|
let stderr = "";
|
|
3674
3674
|
const spawnFn = _spawnOverride ?? spawn;
|
|
@@ -3686,35 +3686,35 @@ ${userContent}`;
|
|
|
3686
3686
|
const timer = setTimeout(() => {
|
|
3687
3687
|
proc.kill("SIGTERM");
|
|
3688
3688
|
console.error("[persist] autoLabel: haiku subprocess timed out");
|
|
3689
|
-
|
|
3689
|
+
resolve18(null);
|
|
3690
3690
|
}, SESSION_LABEL_TIMEOUT_MS);
|
|
3691
3691
|
proc.on("error", (err) => {
|
|
3692
3692
|
clearTimeout(timer);
|
|
3693
3693
|
console.error(`[persist] autoLabel: subprocess error \u2014 ${err.message}`);
|
|
3694
|
-
|
|
3694
|
+
resolve18(null);
|
|
3695
3695
|
});
|
|
3696
3696
|
proc.on("close", (code) => {
|
|
3697
3697
|
clearTimeout(timer);
|
|
3698
3698
|
if (code !== 0) {
|
|
3699
3699
|
console.error(`[persist] autoLabel: subprocess exited code=${code}${stderr ? ` stderr=${stderr.trim().slice(0, 200)}` : ""}`);
|
|
3700
|
-
|
|
3700
|
+
resolve18(null);
|
|
3701
3701
|
return;
|
|
3702
3702
|
}
|
|
3703
3703
|
const text = stdout.trim();
|
|
3704
3704
|
if (!text) {
|
|
3705
3705
|
console.error("[persist] autoLabel: haiku returned empty response");
|
|
3706
|
-
|
|
3706
|
+
resolve18(null);
|
|
3707
3707
|
return;
|
|
3708
3708
|
}
|
|
3709
3709
|
if (text === "SKIP") {
|
|
3710
3710
|
console.error("[persist] autoLabel: haiku returned SKIP \u2014 messages too vague");
|
|
3711
|
-
|
|
3711
|
+
resolve18(null);
|
|
3712
3712
|
return;
|
|
3713
3713
|
}
|
|
3714
3714
|
const words = text.split(/\s+/).slice(0, SESSION_LABEL_MAX_WORDS);
|
|
3715
3715
|
const label = words.join(" ");
|
|
3716
3716
|
console.error(`[persist] autoLabel: haiku response="${label}"`);
|
|
3717
|
-
|
|
3717
|
+
resolve18(label);
|
|
3718
3718
|
});
|
|
3719
3719
|
});
|
|
3720
3720
|
}
|
|
@@ -4808,8 +4808,8 @@ async function buildPluginManifest(enabledPlugins) {
|
|
|
4808
4808
|
for (const entry of readdirSync(current)) {
|
|
4809
4809
|
const full = resolve4(current, entry);
|
|
4810
4810
|
try {
|
|
4811
|
-
const
|
|
4812
|
-
if (
|
|
4811
|
+
const stat3 = statSync2(full);
|
|
4812
|
+
if (stat3.isDirectory()) {
|
|
4813
4813
|
walk(full, `${rel}${entry}/`);
|
|
4814
4814
|
} else if (entry.endsWith(".md")) {
|
|
4815
4815
|
target.push(`${prefix}${rel}${entry}`);
|
|
@@ -5102,7 +5102,7 @@ function getMcpServers(accountId, enabledPlugins) {
|
|
|
5102
5102
|
// the always-on Chromium instance started by vnc.sh on display :99.
|
|
5103
5103
|
"plugin_playwright_playwright": {
|
|
5104
5104
|
command: "npx",
|
|
5105
|
-
args: ["-y", "@playwright/mcp@latest", "--cdp-endpoint", "http://127.0.0.1:9222"
|
|
5105
|
+
args: ["-y", "@playwright/mcp@latest", "--cdp-endpoint", "http://127.0.0.1:9222"]
|
|
5106
5106
|
}
|
|
5107
5107
|
};
|
|
5108
5108
|
if (process.env.TELEGRAM_PUBLIC_BOT_TOKEN) {
|
|
@@ -5194,6 +5194,7 @@ var ADMIN_CORE_TOOLS = [
|
|
|
5194
5194
|
"mcp__whatsapp__whatsapp-status",
|
|
5195
5195
|
"mcp__whatsapp__whatsapp-disconnect",
|
|
5196
5196
|
"mcp__whatsapp__whatsapp-send",
|
|
5197
|
+
"mcp__whatsapp__whatsapp-send-document",
|
|
5197
5198
|
"mcp__whatsapp__whatsapp-config",
|
|
5198
5199
|
"mcp__admin__system-status",
|
|
5199
5200
|
"mcp__admin__brand-settings",
|
|
@@ -5206,6 +5207,7 @@ var ADMIN_CORE_TOOLS = [
|
|
|
5206
5207
|
"mcp__admin__session-resume",
|
|
5207
5208
|
"mcp__admin__api-key-store",
|
|
5208
5209
|
"mcp__admin__api-key-verify",
|
|
5210
|
+
"mcp__admin__file-attach",
|
|
5209
5211
|
"mcp__cloudflare__tunnel-status",
|
|
5210
5212
|
"mcp__cloudflare__tunnel-install",
|
|
5211
5213
|
"mcp__cloudflare__tunnel-login",
|
|
@@ -5343,7 +5345,7 @@ async function fetchMemoryContext(accountId, query, sessionKey, options) {
|
|
|
5343
5345
|
return null;
|
|
5344
5346
|
}
|
|
5345
5347
|
const startMs = Date.now();
|
|
5346
|
-
return new Promise((
|
|
5348
|
+
return new Promise((resolve18) => {
|
|
5347
5349
|
const proc = spawn2(process.execPath, [serverPath], {
|
|
5348
5350
|
env: {
|
|
5349
5351
|
...process.env,
|
|
@@ -5372,7 +5374,7 @@ async function fetchMemoryContext(accountId, query, sessionKey, options) {
|
|
|
5372
5374
|
} else {
|
|
5373
5375
|
console.error(`[fetchMemoryContext] failed: ${reason} (${elapsed}ms)${stderrBuf ? ` stderr: ${stderrBuf.slice(0, 500)}` : ""}`);
|
|
5374
5376
|
}
|
|
5375
|
-
|
|
5377
|
+
resolve18(value);
|
|
5376
5378
|
};
|
|
5377
5379
|
proc.stdout.on("data", (chunk) => {
|
|
5378
5380
|
buffer += chunk.toString();
|
|
@@ -7572,8 +7574,9 @@ ${raw2}`;
|
|
|
7572
7574
|
|
|
7573
7575
|
// app/lib/attachments.ts
|
|
7574
7576
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
7575
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
7576
|
-
import {
|
|
7577
|
+
import { mkdir, readFile, stat, writeFile } from "fs/promises";
|
|
7578
|
+
import { realpathSync } from "fs";
|
|
7579
|
+
import { resolve as resolve6, extname, basename } from "path";
|
|
7577
7580
|
var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "../platform");
|
|
7578
7581
|
var ATTACHMENTS_ROOT = resolve6(PLATFORM_ROOT4, "data/attachments");
|
|
7579
7582
|
var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -7633,6 +7636,44 @@ async function storePublicAttachment(sessionId, file2, buffer) {
|
|
|
7633
7636
|
}
|
|
7634
7637
|
return writeAttachment(`public/${sessionId}`, file2.name, file2.type, file2.size, buffer);
|
|
7635
7638
|
}
|
|
7639
|
+
var MIME_BY_EXT = {
|
|
7640
|
+
".pdf": "application/pdf",
|
|
7641
|
+
".png": "image/png",
|
|
7642
|
+
".jpg": "image/jpeg",
|
|
7643
|
+
".jpeg": "image/jpeg",
|
|
7644
|
+
".gif": "image/gif",
|
|
7645
|
+
".webp": "image/webp",
|
|
7646
|
+
".svg": "image/svg+xml",
|
|
7647
|
+
".html": "text/html",
|
|
7648
|
+
".htm": "text/html",
|
|
7649
|
+
".css": "text/css",
|
|
7650
|
+
".js": "application/javascript",
|
|
7651
|
+
".json": "application/json",
|
|
7652
|
+
".csv": "text/csv",
|
|
7653
|
+
".txt": "text/plain",
|
|
7654
|
+
".md": "text/markdown",
|
|
7655
|
+
".xml": "text/xml",
|
|
7656
|
+
".zip": "application/zip",
|
|
7657
|
+
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
7658
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
7659
|
+
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
7660
|
+
};
|
|
7661
|
+
function detectMimeType(filePath) {
|
|
7662
|
+
const ext = extname(filePath).toLowerCase();
|
|
7663
|
+
return MIME_BY_EXT[ext] ?? "application/octet-stream";
|
|
7664
|
+
}
|
|
7665
|
+
async function storeGeneratedFile(accountId, filePath) {
|
|
7666
|
+
const fileStat = await stat(filePath);
|
|
7667
|
+
if (fileStat.size > MAX_FILE_SIZE_BYTES) {
|
|
7668
|
+
throw new Error(
|
|
7669
|
+
`File exceeds the 20 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB).`
|
|
7670
|
+
);
|
|
7671
|
+
}
|
|
7672
|
+
const filename = basename(filePath);
|
|
7673
|
+
const mimeType = detectMimeType(filePath);
|
|
7674
|
+
const buffer = await readFile(filePath);
|
|
7675
|
+
return writeAttachment(accountId, filename, mimeType, fileStat.size, buffer);
|
|
7676
|
+
}
|
|
7636
7677
|
|
|
7637
7678
|
// app/api/chat/route.ts
|
|
7638
7679
|
function isLocalRequest(req) {
|
|
@@ -7844,10 +7885,10 @@ var SCRYPT_R = 8;
|
|
|
7844
7885
|
var SCRYPT_P = 1;
|
|
7845
7886
|
var SCRYPT_KEYLEN = 64;
|
|
7846
7887
|
function scryptAsync(password, salt) {
|
|
7847
|
-
return new Promise((
|
|
7888
|
+
return new Promise((resolve18, reject) => {
|
|
7848
7889
|
scrypt(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, r: SCRYPT_R, p: SCRYPT_P }, (err, key) => {
|
|
7849
7890
|
if (err) reject(err);
|
|
7850
|
-
else
|
|
7891
|
+
else resolve18(key);
|
|
7851
7892
|
});
|
|
7852
7893
|
});
|
|
7853
7894
|
}
|
|
@@ -9400,7 +9441,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
9400
9441
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
9401
9442
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
9402
9443
|
const timer = new Promise(
|
|
9403
|
-
(
|
|
9444
|
+
(resolve18) => setTimeout(() => resolve18("timeout"), timeoutMs)
|
|
9404
9445
|
);
|
|
9405
9446
|
const result = await Promise.race([
|
|
9406
9447
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -9541,11 +9582,11 @@ async function createWaSocket(opts) {
|
|
|
9541
9582
|
return sock;
|
|
9542
9583
|
}
|
|
9543
9584
|
async function waitForConnection(sock) {
|
|
9544
|
-
return new Promise((
|
|
9585
|
+
return new Promise((resolve18, reject) => {
|
|
9545
9586
|
const handler = (update) => {
|
|
9546
9587
|
if (update.connection === "open") {
|
|
9547
9588
|
sock.ev.off("connection.update", handler);
|
|
9548
|
-
|
|
9589
|
+
resolve18();
|
|
9549
9590
|
}
|
|
9550
9591
|
if (update.connection === "close") {
|
|
9551
9592
|
sock.ev.off("connection.update", handler);
|
|
@@ -9730,8 +9771,8 @@ async function startLogin(opts) {
|
|
|
9730
9771
|
resetActiveLogin(accountId);
|
|
9731
9772
|
let resolveQr = null;
|
|
9732
9773
|
let rejectQr = null;
|
|
9733
|
-
const qrPromise = new Promise((
|
|
9734
|
-
resolveQr =
|
|
9774
|
+
const qrPromise = new Promise((resolve18, reject) => {
|
|
9775
|
+
resolveQr = resolve18;
|
|
9735
9776
|
rejectQr = reject;
|
|
9736
9777
|
});
|
|
9737
9778
|
const qrTimer = setTimeout(
|
|
@@ -23656,7 +23697,7 @@ var WhatsAppAccountSchema = external_exports.object({
|
|
|
23656
23697
|
direct: external_exports.boolean().optional().default(true),
|
|
23657
23698
|
group: external_exports.enum(["always", "mentions", "never"]).optional().default("mentions")
|
|
23658
23699
|
}).strict().optional().describe("React to incoming messages with an emoji to acknowledge receipt before the agent responds."),
|
|
23659
|
-
debounceMs: external_exports.number().int().nonnegative().optional().default(
|
|
23700
|
+
debounceMs: external_exports.number().int().nonnegative().optional().default(2e3).describe("Wait this many milliseconds after the last message before processing, to batch rapid multi-message input into a single agent turn. Default 2000ms catches most multi-message bursts. 0 means process each message immediately."),
|
|
23660
23701
|
publicAgent: external_exports.string().optional().describe("Slug of the public agent that handles WhatsApp inbound from non-admin phones for this account. Overrides the top-level publicAgent when set.")
|
|
23661
23702
|
}).strict().superRefine((value, ctx) => {
|
|
23662
23703
|
if (value.dmPolicy !== "open") return;
|
|
@@ -23678,7 +23719,7 @@ var WhatsAppConfigSchema = external_exports.object({
|
|
|
23678
23719
|
sendReadReceipts: external_exports.boolean().optional().default(true).describe("Whether to send read receipts (blue ticks) when messages are received. Disabling may feel less responsive but preserves privacy."),
|
|
23679
23720
|
mediaMaxMb: external_exports.number().int().positive().optional().default(50).describe("Maximum file size in MB for media the agent will download and process."),
|
|
23680
23721
|
textChunkLimit: external_exports.number().int().positive().optional().default(4e3).describe("Maximum characters per outbound message. Longer replies are split into multiple messages."),
|
|
23681
|
-
debounceMs: external_exports.number().int().nonnegative().optional().default(
|
|
23722
|
+
debounceMs: external_exports.number().int().nonnegative().optional().default(2e3).describe("Wait this many milliseconds after the last message before processing, to batch rapid multi-message input into a single agent turn. Default 2000ms catches most multi-message bursts. 0 means process each message immediately."),
|
|
23682
23723
|
publicAgent: external_exports.string().optional().describe("Slug of the public agent that handles WhatsApp inbound from non-admin phones. Per-account overrides take precedence.")
|
|
23683
23724
|
}).strict().superRefine((value, ctx) => {
|
|
23684
23725
|
if (value.dmPolicy !== "open") return;
|
|
@@ -24284,6 +24325,53 @@ async function sendReadReceipt(sock, chatJid, messageIds, participant) {
|
|
|
24284
24325
|
} catch {
|
|
24285
24326
|
}
|
|
24286
24327
|
}
|
|
24328
|
+
async function sendMediaMessage(sock, to, media) {
|
|
24329
|
+
try {
|
|
24330
|
+
const jid = to.includes("@") ? to : toWhatsappJid(to);
|
|
24331
|
+
let payload;
|
|
24332
|
+
switch (media.type) {
|
|
24333
|
+
case "image":
|
|
24334
|
+
payload = {
|
|
24335
|
+
image: media.buffer,
|
|
24336
|
+
mimetype: media.mimetype,
|
|
24337
|
+
caption: media.caption
|
|
24338
|
+
};
|
|
24339
|
+
break;
|
|
24340
|
+
case "audio":
|
|
24341
|
+
payload = {
|
|
24342
|
+
audio: media.buffer,
|
|
24343
|
+
mimetype: media.mimetype,
|
|
24344
|
+
ptt: media.ptt ?? false
|
|
24345
|
+
};
|
|
24346
|
+
break;
|
|
24347
|
+
case "video":
|
|
24348
|
+
payload = {
|
|
24349
|
+
video: media.buffer,
|
|
24350
|
+
mimetype: media.mimetype,
|
|
24351
|
+
caption: media.caption
|
|
24352
|
+
};
|
|
24353
|
+
break;
|
|
24354
|
+
case "document":
|
|
24355
|
+
payload = {
|
|
24356
|
+
document: media.buffer,
|
|
24357
|
+
mimetype: media.mimetype,
|
|
24358
|
+
fileName: media.filename ?? "file",
|
|
24359
|
+
caption: media.caption
|
|
24360
|
+
};
|
|
24361
|
+
break;
|
|
24362
|
+
}
|
|
24363
|
+
const result = await sock.sendMessage(jid, payload);
|
|
24364
|
+
const messageId = result?.key?.id;
|
|
24365
|
+
if (messageId) {
|
|
24366
|
+
trackAgentSentMessage(messageId);
|
|
24367
|
+
console.error(`${TAG5} sent ${media.type} to=${jid} id=${messageId}`);
|
|
24368
|
+
}
|
|
24369
|
+
return { success: true, messageId: messageId ?? void 0 };
|
|
24370
|
+
} catch (err) {
|
|
24371
|
+
console.error(`${TAG5} send media failed to=${to}: ${String(err)}`);
|
|
24372
|
+
return { success: false, error: String(err) };
|
|
24373
|
+
}
|
|
24374
|
+
}
|
|
24287
24375
|
|
|
24288
24376
|
// app/lib/whatsapp/inbound/media.ts
|
|
24289
24377
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
@@ -24667,11 +24755,11 @@ async function connectWithReconnect(conn) {
|
|
|
24667
24755
|
}
|
|
24668
24756
|
const delay = computeBackoff(conn.reconnectAttempts);
|
|
24669
24757
|
console.error(`${TAG8} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${conn.reconnectAttempts}/${maxAttempts})`);
|
|
24670
|
-
await new Promise((
|
|
24671
|
-
const timer = setTimeout(
|
|
24758
|
+
await new Promise((resolve18) => {
|
|
24759
|
+
const timer = setTimeout(resolve18, delay);
|
|
24672
24760
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
24673
24761
|
clearTimeout(timer);
|
|
24674
|
-
|
|
24762
|
+
resolve18();
|
|
24675
24763
|
}, { once: true });
|
|
24676
24764
|
});
|
|
24677
24765
|
if (conn.abortController.signal.aborted) return;
|
|
@@ -24679,14 +24767,14 @@ async function connectWithReconnect(conn) {
|
|
|
24679
24767
|
}
|
|
24680
24768
|
}
|
|
24681
24769
|
function waitForDisconnectEvent(conn) {
|
|
24682
|
-
return new Promise((
|
|
24770
|
+
return new Promise((resolve18) => {
|
|
24683
24771
|
if (!conn.sock) {
|
|
24684
|
-
|
|
24772
|
+
resolve18();
|
|
24685
24773
|
return;
|
|
24686
24774
|
}
|
|
24687
24775
|
conn.sock.ev.on("connection.update", (update) => {
|
|
24688
24776
|
if (update.connection === "close") {
|
|
24689
|
-
|
|
24777
|
+
resolve18();
|
|
24690
24778
|
}
|
|
24691
24779
|
});
|
|
24692
24780
|
});
|
|
@@ -24978,45 +25066,56 @@ async function POST13(req) {
|
|
|
24978
25066
|
}
|
|
24979
25067
|
|
|
24980
25068
|
// app/lib/whatsapp/schema-serialize.ts
|
|
25069
|
+
function zodTypeName(def) {
|
|
25070
|
+
if (typeof def?.type === "string") return def.type;
|
|
25071
|
+
if (typeof def?.typeName === "string") return def.typeName;
|
|
25072
|
+
return "unknown";
|
|
25073
|
+
}
|
|
25074
|
+
function isType(name, ...candidates) {
|
|
25075
|
+
return candidates.includes(name);
|
|
25076
|
+
}
|
|
24981
25077
|
function resolveZodType(def) {
|
|
24982
|
-
const
|
|
24983
|
-
if (
|
|
25078
|
+
const tn = zodTypeName(def);
|
|
25079
|
+
if (isType(tn, "ZodDefault", "default")) {
|
|
24984
25080
|
const inner = resolveZodType(def.innerType?._def);
|
|
24985
25081
|
const defaultVal = typeof def.defaultValue === "function" ? def.defaultValue() : def.defaultValue;
|
|
24986
25082
|
return { ...inner, default: JSON.stringify(defaultVal) };
|
|
24987
25083
|
}
|
|
24988
|
-
if (
|
|
25084
|
+
if (isType(tn, "ZodOptional", "optional")) {
|
|
24989
25085
|
const inner = resolveZodType(def.innerType?._def);
|
|
24990
25086
|
return { ...inner, required: false };
|
|
24991
25087
|
}
|
|
24992
|
-
if (
|
|
24993
|
-
if (
|
|
24994
|
-
if (
|
|
24995
|
-
if (
|
|
25088
|
+
if (isType(tn, "ZodString", "string")) return { type: "string", required: true };
|
|
25089
|
+
if (isType(tn, "ZodNumber", "number")) return { type: "number", required: true };
|
|
25090
|
+
if (isType(tn, "ZodBoolean", "boolean")) return { type: "boolean", required: true };
|
|
25091
|
+
if (isType(tn, "ZodEnum", "enum")) {
|
|
24996
25092
|
const values = def.values ?? [];
|
|
24997
25093
|
return { type: `enum(${values.join(", ")})`, required: true };
|
|
24998
25094
|
}
|
|
24999
|
-
if (
|
|
25000
|
-
const
|
|
25095
|
+
if (isType(tn, "ZodArray", "array")) {
|
|
25096
|
+
const elementDef = def.element?._def ?? def.type?._def;
|
|
25097
|
+
const inner = resolveZodType(elementDef);
|
|
25001
25098
|
return { type: `${inner.type}[]`, required: true };
|
|
25002
25099
|
}
|
|
25003
|
-
if (
|
|
25100
|
+
if (isType(tn, "ZodRecord", "record")) {
|
|
25004
25101
|
return { type: "Record<string, ...>", required: true };
|
|
25005
25102
|
}
|
|
25006
|
-
if (
|
|
25103
|
+
if (isType(tn, "ZodObject", "object")) {
|
|
25007
25104
|
return { type: "object", required: true };
|
|
25008
25105
|
}
|
|
25009
25106
|
return { type: "unknown", required: true };
|
|
25010
25107
|
}
|
|
25011
|
-
function extractDescription(def) {
|
|
25012
|
-
if (
|
|
25013
|
-
|
|
25014
|
-
if (
|
|
25108
|
+
function extractDescription(schema, def) {
|
|
25109
|
+
if (typeof schema?.description === "string") return schema.description;
|
|
25110
|
+
const d = def ?? schema?._def ?? schema;
|
|
25111
|
+
if (typeof d?.description === "string") return d.description;
|
|
25112
|
+
if (d?.innerType) return extractDescription(d.innerType, d.innerType?._def);
|
|
25015
25113
|
return void 0;
|
|
25016
25114
|
}
|
|
25017
25115
|
function unwrapToShape(schema) {
|
|
25018
25116
|
if (schema?.shape && typeof schema.shape === "object") return schema.shape;
|
|
25019
|
-
|
|
25117
|
+
const tn = zodTypeName(schema?._def);
|
|
25118
|
+
if (isType(tn, "ZodEffects", "effects") && schema._def.schema) {
|
|
25020
25119
|
return unwrapToShape(schema._def.schema);
|
|
25021
25120
|
}
|
|
25022
25121
|
if (typeof schema?._def?.shape === "function") return schema._def.shape();
|
|
@@ -25028,7 +25127,7 @@ function extractFields(schema) {
|
|
|
25028
25127
|
for (const [name, fieldSchema] of Object.entries(shape)) {
|
|
25029
25128
|
const def = fieldSchema?._def;
|
|
25030
25129
|
const resolved = resolveZodType(def);
|
|
25031
|
-
const description = extractDescription(def);
|
|
25130
|
+
const description = extractDescription(fieldSchema, def);
|
|
25032
25131
|
fields.push({
|
|
25033
25132
|
name,
|
|
25034
25133
|
type: resolved.type,
|
|
@@ -25162,6 +25261,107 @@ async function POST14(req) {
|
|
|
25162
25261
|
}
|
|
25163
25262
|
}
|
|
25164
25263
|
|
|
25264
|
+
// app/api/whatsapp/send-document/route.ts
|
|
25265
|
+
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
25266
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
25267
|
+
import { resolve as resolve10, basename as basename2 } from "path";
|
|
25268
|
+
var TAG9 = "[whatsapp:api]";
|
|
25269
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
25270
|
+
async function POST15(req) {
|
|
25271
|
+
try {
|
|
25272
|
+
const body = await req.json();
|
|
25273
|
+
const { to, filePath, caption, maxyAccountId } = body;
|
|
25274
|
+
const accountId = validateAccountId(body.accountId);
|
|
25275
|
+
if (!to || !filePath) {
|
|
25276
|
+
return Response.json({ error: "Missing required fields: to, filePath" }, { status: 400 });
|
|
25277
|
+
}
|
|
25278
|
+
if (!maxyAccountId || !PLATFORM_ROOT6) {
|
|
25279
|
+
return Response.json(
|
|
25280
|
+
{ error: "Cannot validate file path: missing account or platform context" },
|
|
25281
|
+
{ status: 400 }
|
|
25282
|
+
);
|
|
25283
|
+
}
|
|
25284
|
+
const accountDir = resolve10(PLATFORM_ROOT6, "config/accounts", maxyAccountId);
|
|
25285
|
+
let resolvedPath;
|
|
25286
|
+
try {
|
|
25287
|
+
resolvedPath = realpathSync2(filePath);
|
|
25288
|
+
const accountResolved = realpathSync2(accountDir);
|
|
25289
|
+
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
25290
|
+
const sanitised = filePath.replace(accountDir, "<account>/");
|
|
25291
|
+
console.error(`${TAG9} send-document REJECTED path=${sanitised} reason=outside_account_directory`);
|
|
25292
|
+
return Response.json({ error: "Access denied: file is outside the account directory" }, { status: 403 });
|
|
25293
|
+
}
|
|
25294
|
+
} catch (err) {
|
|
25295
|
+
const code = err.code;
|
|
25296
|
+
if (code === "ENOENT") {
|
|
25297
|
+
console.error(`${TAG9} send-document ENOENT path=${filePath}`);
|
|
25298
|
+
return Response.json({ error: `File not found: ${filePath}` }, { status: 404 });
|
|
25299
|
+
}
|
|
25300
|
+
console.error(`${TAG9} send-document path error: ${String(err)}`);
|
|
25301
|
+
return Response.json({ error: String(err) }, { status: 500 });
|
|
25302
|
+
}
|
|
25303
|
+
const fileStat = await stat2(resolvedPath);
|
|
25304
|
+
if (fileStat.size > MAX_FILE_SIZE_BYTES) {
|
|
25305
|
+
return Response.json(
|
|
25306
|
+
{ error: `File exceeds 20 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)` },
|
|
25307
|
+
{ status: 400 }
|
|
25308
|
+
);
|
|
25309
|
+
}
|
|
25310
|
+
const buffer = Buffer.from(await readFile2(resolvedPath));
|
|
25311
|
+
const filename = basename2(resolvedPath);
|
|
25312
|
+
const mimetype = detectMimeType(resolvedPath);
|
|
25313
|
+
const sock = getSocket(accountId);
|
|
25314
|
+
if (!sock) {
|
|
25315
|
+
return Response.json(
|
|
25316
|
+
{ error: `WhatsApp account "${accountId}" is not connected` },
|
|
25317
|
+
{ status: 503 }
|
|
25318
|
+
);
|
|
25319
|
+
}
|
|
25320
|
+
const result = await sendMediaMessage(sock, to, {
|
|
25321
|
+
type: "document",
|
|
25322
|
+
buffer,
|
|
25323
|
+
mimetype,
|
|
25324
|
+
filename,
|
|
25325
|
+
caption
|
|
25326
|
+
});
|
|
25327
|
+
console.error(
|
|
25328
|
+
`${TAG9} send-document to=${to} size=${fileStat.size} mime=${mimetype} ok=${result.success}` + (result.messageId ? ` id=${result.messageId}` : "")
|
|
25329
|
+
);
|
|
25330
|
+
return Response.json(result);
|
|
25331
|
+
} catch (err) {
|
|
25332
|
+
console.error(`${TAG9} send-document error: ${String(err)}`);
|
|
25333
|
+
return Response.json({ error: String(err) }, { status: 500 });
|
|
25334
|
+
}
|
|
25335
|
+
}
|
|
25336
|
+
|
|
25337
|
+
// app/api/admin/file-attach/route.ts
|
|
25338
|
+
async function POST16(req) {
|
|
25339
|
+
try {
|
|
25340
|
+
const body = await req.json();
|
|
25341
|
+
const { filePath, accountId } = body;
|
|
25342
|
+
if (!filePath || !accountId) {
|
|
25343
|
+
return Response.json(
|
|
25344
|
+
{ error: "Missing required fields: filePath, accountId" },
|
|
25345
|
+
{ status: 400 }
|
|
25346
|
+
);
|
|
25347
|
+
}
|
|
25348
|
+
const attachment = await storeGeneratedFile(accountId, filePath);
|
|
25349
|
+
console.error(
|
|
25350
|
+
`[admin:file-attach] stored path=${filePath} id=${attachment.attachmentId} size=${attachment.sizeBytes} mime=${attachment.mimeType}`
|
|
25351
|
+
);
|
|
25352
|
+
return Response.json({
|
|
25353
|
+
attachmentId: attachment.attachmentId,
|
|
25354
|
+
filename: attachment.filename,
|
|
25355
|
+
sizeBytes: attachment.sizeBytes,
|
|
25356
|
+
mimeType: attachment.mimeType
|
|
25357
|
+
});
|
|
25358
|
+
} catch (err) {
|
|
25359
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
25360
|
+
console.error(`[admin:file-attach] error: ${message}`);
|
|
25361
|
+
return Response.json({ error: message }, { status: 500 });
|
|
25362
|
+
}
|
|
25363
|
+
}
|
|
25364
|
+
|
|
25165
25365
|
// app/api/onboarding/claude-auth/route.ts
|
|
25166
25366
|
import { spawn as spawn3, execFileSync as execFileSync2 } from "child_process";
|
|
25167
25367
|
import { openSync, closeSync, writeFileSync as writeFileSync7, writeSync } from "fs";
|
|
@@ -25192,7 +25392,7 @@ async function waitForAuthPage(timeoutMs = 2e4) {
|
|
|
25192
25392
|
async function GET3() {
|
|
25193
25393
|
return Response.json({ authenticated: checkAuthStatus() });
|
|
25194
25394
|
}
|
|
25195
|
-
async function
|
|
25395
|
+
async function POST17(req) {
|
|
25196
25396
|
let body = {};
|
|
25197
25397
|
try {
|
|
25198
25398
|
body = await req.json();
|
|
@@ -25249,7 +25449,7 @@ import { createHash } from "crypto";
|
|
|
25249
25449
|
function hashPin(pin) {
|
|
25250
25450
|
return createHash("sha256").update(pin).digest("hex");
|
|
25251
25451
|
}
|
|
25252
|
-
async function
|
|
25452
|
+
async function POST18(req) {
|
|
25253
25453
|
if (existsSync11(PIN_FILE)) {
|
|
25254
25454
|
return Response.json(
|
|
25255
25455
|
{ error: "PIN is already configured." },
|
|
@@ -25307,7 +25507,7 @@ function getStoredPinHash() {
|
|
|
25307
25507
|
}
|
|
25308
25508
|
return null;
|
|
25309
25509
|
}
|
|
25310
|
-
async function
|
|
25510
|
+
async function POST19(req) {
|
|
25311
25511
|
const storedHash = getStoredPinHash();
|
|
25312
25512
|
if (!storedHash) {
|
|
25313
25513
|
return Response.json(
|
|
@@ -25428,7 +25628,7 @@ function advanceGateIfNeeded(envelope, accountDir, logFn) {
|
|
|
25428
25628
|
const pending = Object.entries(gates).filter(([, v]) => !v).map(([k]) => k);
|
|
25429
25629
|
logFn(`${gateFlag} gate advanced (route-level). Pending: ${pending.length > 0 ? pending.join(", ") : "none"}`);
|
|
25430
25630
|
}
|
|
25431
|
-
async function
|
|
25631
|
+
async function POST20(req) {
|
|
25432
25632
|
const contentType = req.headers.get("content-type") ?? "";
|
|
25433
25633
|
let message;
|
|
25434
25634
|
let session_key;
|
|
@@ -25650,7 +25850,7 @@ async function POST18(req) {
|
|
|
25650
25850
|
}
|
|
25651
25851
|
|
|
25652
25852
|
// app/api/admin/compact/route.ts
|
|
25653
|
-
async function
|
|
25853
|
+
async function POST21(req) {
|
|
25654
25854
|
let body;
|
|
25655
25855
|
try {
|
|
25656
25856
|
body = await req.json();
|
|
@@ -25692,7 +25892,7 @@ async function POST19(req) {
|
|
|
25692
25892
|
|
|
25693
25893
|
// app/api/admin/logs/route.ts
|
|
25694
25894
|
import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync14, statSync as statSync3 } from "fs";
|
|
25695
|
-
import { resolve as
|
|
25895
|
+
import { resolve as resolve11, basename as basename3 } from "path";
|
|
25696
25896
|
var TAIL_BYTES = 8192;
|
|
25697
25897
|
async function GET4(request) {
|
|
25698
25898
|
const { searchParams } = new URL(request.url);
|
|
@@ -25700,12 +25900,12 @@ async function GET4(request) {
|
|
|
25700
25900
|
const typeParam = searchParams.get("type");
|
|
25701
25901
|
const download = searchParams.get("download") === "1";
|
|
25702
25902
|
const account = resolveAccount();
|
|
25703
|
-
const accountLogDir = account ?
|
|
25903
|
+
const accountLogDir = account ? resolve11(account.accountDir, "logs") : null;
|
|
25704
25904
|
if (fileParam) {
|
|
25705
|
-
const safe =
|
|
25905
|
+
const safe = basename3(fileParam);
|
|
25706
25906
|
for (const dir of [accountLogDir, LOG_DIR]) {
|
|
25707
25907
|
if (!dir) continue;
|
|
25708
|
-
const filePath =
|
|
25908
|
+
const filePath = resolve11(dir, safe);
|
|
25709
25909
|
try {
|
|
25710
25910
|
const content = readFileSync14(filePath, "utf-8");
|
|
25711
25911
|
const headers = { "Content-Type": "text/plain; charset=utf-8" };
|
|
@@ -25731,7 +25931,7 @@ async function GET4(request) {
|
|
|
25731
25931
|
}
|
|
25732
25932
|
for (const dir of [accountLogDir, LOG_DIR]) {
|
|
25733
25933
|
if (!dir) continue;
|
|
25734
|
-
const filePath =
|
|
25934
|
+
const filePath = resolve11(dir, fileName);
|
|
25735
25935
|
try {
|
|
25736
25936
|
const content = readFileSync14(filePath, "utf-8");
|
|
25737
25937
|
const headers = { "Content-Type": "text/plain; charset=utf-8" };
|
|
@@ -25752,10 +25952,10 @@ async function GET4(request) {
|
|
|
25752
25952
|
} catch {
|
|
25753
25953
|
continue;
|
|
25754
25954
|
}
|
|
25755
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync3(
|
|
25955
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync3(resolve11(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
25756
25956
|
seen.add(name);
|
|
25757
25957
|
try {
|
|
25758
|
-
const content = readFileSync14(
|
|
25958
|
+
const content = readFileSync14(resolve11(dir, name));
|
|
25759
25959
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
25760
25960
|
logs[name] = tail.trim() || "(empty)";
|
|
25761
25961
|
} catch {
|
|
@@ -25789,9 +25989,9 @@ async function GET5() {
|
|
|
25789
25989
|
}
|
|
25790
25990
|
|
|
25791
25991
|
// app/api/admin/attachment/[attachmentId]/route.ts
|
|
25792
|
-
import { readFile, readdir } from "fs/promises";
|
|
25992
|
+
import { readFile as readFile3, readdir } from "fs/promises";
|
|
25793
25993
|
import { existsSync as existsSync15 } from "fs";
|
|
25794
|
-
import { resolve as
|
|
25994
|
+
import { resolve as resolve12 } from "path";
|
|
25795
25995
|
async function GET6(req, attachmentId) {
|
|
25796
25996
|
const sessionKey = new URL(req.url).searchParams.get("session_key") ?? "";
|
|
25797
25997
|
if (!validateSession(sessionKey, "admin")) {
|
|
@@ -25804,17 +26004,17 @@ async function GET6(req, attachmentId) {
|
|
|
25804
26004
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
|
|
25805
26005
|
return new Response("Not found", { status: 404 });
|
|
25806
26006
|
}
|
|
25807
|
-
const dir =
|
|
26007
|
+
const dir = resolve12(ATTACHMENTS_ROOT, accountId, attachmentId);
|
|
25808
26008
|
if (!existsSync15(dir)) {
|
|
25809
26009
|
return new Response("Not found", { status: 404 });
|
|
25810
26010
|
}
|
|
25811
|
-
const metaPath =
|
|
26011
|
+
const metaPath = resolve12(dir, `${attachmentId}.meta.json`);
|
|
25812
26012
|
if (!existsSync15(metaPath)) {
|
|
25813
26013
|
return new Response("Not found", { status: 404 });
|
|
25814
26014
|
}
|
|
25815
26015
|
let meta3;
|
|
25816
26016
|
try {
|
|
25817
|
-
meta3 = JSON.parse(await
|
|
26017
|
+
meta3 = JSON.parse(await readFile3(metaPath, "utf-8"));
|
|
25818
26018
|
} catch {
|
|
25819
26019
|
return new Response("Not found", { status: 404 });
|
|
25820
26020
|
}
|
|
@@ -25823,8 +26023,8 @@ async function GET6(req, attachmentId) {
|
|
|
25823
26023
|
if (!dataFile) {
|
|
25824
26024
|
return new Response("Not found", { status: 404 });
|
|
25825
26025
|
}
|
|
25826
|
-
const filePath =
|
|
25827
|
-
const buffer = await
|
|
26026
|
+
const filePath = resolve12(dir, dataFile);
|
|
26027
|
+
const buffer = await readFile3(filePath);
|
|
25828
26028
|
return new Response(buffer, {
|
|
25829
26029
|
headers: {
|
|
25830
26030
|
"Content-Type": meta3.mimeType,
|
|
@@ -25836,7 +26036,7 @@ async function GET6(req, attachmentId) {
|
|
|
25836
26036
|
|
|
25837
26037
|
// app/api/admin/account/route.ts
|
|
25838
26038
|
import { readFileSync as readFileSync15, writeFileSync as writeFileSync10 } from "fs";
|
|
25839
|
-
import { resolve as
|
|
26039
|
+
import { resolve as resolve13 } from "path";
|
|
25840
26040
|
var VALID_CONTEXT_MODES = ["managed", "claude-code"];
|
|
25841
26041
|
async function PATCH(req) {
|
|
25842
26042
|
let body;
|
|
@@ -25859,7 +26059,7 @@ async function PATCH(req) {
|
|
|
25859
26059
|
if (!account) {
|
|
25860
26060
|
return Response.json({ error: "No account configured" }, { status: 500 });
|
|
25861
26061
|
}
|
|
25862
|
-
const configPath2 =
|
|
26062
|
+
const configPath2 = resolve13(account.accountDir, "account.json");
|
|
25863
26063
|
try {
|
|
25864
26064
|
const raw2 = readFileSync15(configPath2, "utf-8");
|
|
25865
26065
|
const config2 = JSON.parse(raw2);
|
|
@@ -25874,14 +26074,14 @@ async function PATCH(req) {
|
|
|
25874
26074
|
}
|
|
25875
26075
|
|
|
25876
26076
|
// app/api/admin/agents/route.ts
|
|
25877
|
-
import { resolve as
|
|
26077
|
+
import { resolve as resolve14 } from "path";
|
|
25878
26078
|
import { readdirSync as readdirSync3, readFileSync as readFileSync16, existsSync as existsSync16 } from "fs";
|
|
25879
26079
|
async function GET7() {
|
|
25880
26080
|
const account = resolveAccount();
|
|
25881
26081
|
if (!account) {
|
|
25882
26082
|
return Response.json({ agents: [] });
|
|
25883
26083
|
}
|
|
25884
|
-
const agentsDir =
|
|
26084
|
+
const agentsDir = resolve14(account.accountDir, "agents");
|
|
25885
26085
|
if (!existsSync16(agentsDir)) {
|
|
25886
26086
|
return Response.json({ agents: [] });
|
|
25887
26087
|
}
|
|
@@ -25891,7 +26091,7 @@ async function GET7() {
|
|
|
25891
26091
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
25892
26092
|
if (!entry.isDirectory()) continue;
|
|
25893
26093
|
if (entry.name === "admin") continue;
|
|
25894
|
-
const configPath2 =
|
|
26094
|
+
const configPath2 = resolve14(agentsDir, entry.name, "config.json");
|
|
25895
26095
|
if (!existsSync16(configPath2)) continue;
|
|
25896
26096
|
try {
|
|
25897
26097
|
const config2 = JSON.parse(readFileSync16(configPath2, "utf-8"));
|
|
@@ -25913,11 +26113,11 @@ async function GET7() {
|
|
|
25913
26113
|
|
|
25914
26114
|
// app/api/admin/version/route.ts
|
|
25915
26115
|
import { readFileSync as readFileSync17, existsSync as existsSync17 } from "fs";
|
|
25916
|
-
import { resolve as
|
|
25917
|
-
var
|
|
26116
|
+
import { resolve as resolve15, join as join7 } from "path";
|
|
26117
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "..");
|
|
25918
26118
|
var brandHostname = "maxy";
|
|
25919
26119
|
var brandNpmPackage = "@rubytech/create-maxy";
|
|
25920
|
-
var brandJsonPath = join7(
|
|
26120
|
+
var brandJsonPath = join7(PLATFORM_ROOT7, "config", "brand.json");
|
|
25921
26121
|
if (existsSync17(brandJsonPath)) {
|
|
25922
26122
|
try {
|
|
25923
26123
|
const brand = JSON.parse(readFileSync17(brandJsonPath, "utf-8"));
|
|
@@ -25926,7 +26126,7 @@ if (existsSync17(brandJsonPath)) {
|
|
|
25926
26126
|
} catch {
|
|
25927
26127
|
}
|
|
25928
26128
|
}
|
|
25929
|
-
var VERSION_FILE =
|
|
26129
|
+
var VERSION_FILE = resolve15(PLATFORM_ROOT7, `config/.${brandHostname}-version`);
|
|
25930
26130
|
var NPM_PACKAGE = brandNpmPackage;
|
|
25931
26131
|
var REGISTRY_URL = `https://registry.npmjs.org/${NPM_PACKAGE}/latest`;
|
|
25932
26132
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -25989,11 +26189,11 @@ async function GET8() {
|
|
|
25989
26189
|
// app/api/admin/version/upgrade/route.ts
|
|
25990
26190
|
import { spawn as spawn4 } from "child_process";
|
|
25991
26191
|
import { existsSync as existsSync18, statSync as statSync4, writeFileSync as writeFileSync11, readFileSync as readFileSync18, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
25992
|
-
import { resolve as
|
|
25993
|
-
var
|
|
26192
|
+
import { resolve as resolve16, join as join8 } from "path";
|
|
26193
|
+
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve16(process.cwd(), "..");
|
|
25994
26194
|
var upgradePkg = "@rubytech/create-maxy";
|
|
25995
26195
|
var upgradeHostname = "maxy";
|
|
25996
|
-
var brandPath = join8(
|
|
26196
|
+
var brandPath = join8(PLATFORM_ROOT8, "config", "brand.json");
|
|
25997
26197
|
if (existsSync18(brandPath)) {
|
|
25998
26198
|
try {
|
|
25999
26199
|
const brand = JSON.parse(readFileSync18(brandPath, "utf-8"));
|
|
@@ -26008,13 +26208,13 @@ var LOCK_MAX_AGE_MS = 3 * 60 * 1e3;
|
|
|
26008
26208
|
function isLockFresh() {
|
|
26009
26209
|
if (!existsSync18(LOCK_FILE)) return false;
|
|
26010
26210
|
try {
|
|
26011
|
-
const
|
|
26012
|
-
return Date.now() -
|
|
26211
|
+
const stat3 = statSync4(LOCK_FILE);
|
|
26212
|
+
return Date.now() - stat3.mtimeMs < LOCK_MAX_AGE_MS;
|
|
26013
26213
|
} catch {
|
|
26014
26214
|
return false;
|
|
26015
26215
|
}
|
|
26016
26216
|
}
|
|
26017
|
-
async function
|
|
26217
|
+
async function POST22(req) {
|
|
26018
26218
|
let body;
|
|
26019
26219
|
try {
|
|
26020
26220
|
body = await req.json();
|
|
@@ -26043,7 +26243,7 @@ async function POST20(req) {
|
|
|
26043
26243
|
detached: true,
|
|
26044
26244
|
stdio: ["ignore", logFd, logFd],
|
|
26045
26245
|
env: { ...process.env, npm_config_yes: "true" },
|
|
26046
|
-
cwd:
|
|
26246
|
+
cwd: resolve16(process.cwd(), "..")
|
|
26047
26247
|
});
|
|
26048
26248
|
child.unref();
|
|
26049
26249
|
closeSync2(logFd);
|
|
@@ -26138,7 +26338,7 @@ async function GET10(req, { params }) {
|
|
|
26138
26338
|
}
|
|
26139
26339
|
|
|
26140
26340
|
// app/api/admin/browser/launch/route.ts
|
|
26141
|
-
async function
|
|
26341
|
+
async function POST23() {
|
|
26142
26342
|
try {
|
|
26143
26343
|
const vncOk = await ensureVnc();
|
|
26144
26344
|
if (!vncOk) {
|
|
@@ -26159,8 +26359,8 @@ async function POST21() {
|
|
|
26159
26359
|
}
|
|
26160
26360
|
|
|
26161
26361
|
// server/index.ts
|
|
26162
|
-
var
|
|
26163
|
-
var BRAND_JSON_PATH =
|
|
26362
|
+
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
26363
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join9(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
26164
26364
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
|
|
26165
26365
|
if (BRAND_JSON_PATH && !existsSync19(BRAND_JSON_PATH)) {
|
|
26166
26366
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -26491,13 +26691,14 @@ app.post("/api/whatsapp/disconnect", (c) => POST11(c.req.raw));
|
|
|
26491
26691
|
app.post("/api/whatsapp/reconnect", (c) => POST12(c.req.raw));
|
|
26492
26692
|
app.post("/api/whatsapp/send", (c) => POST13(c.req.raw));
|
|
26493
26693
|
app.post("/api/whatsapp/config", (c) => POST14(c.req.raw));
|
|
26694
|
+
app.post("/api/whatsapp/send-document", (c) => POST15(c.req.raw));
|
|
26494
26695
|
app.get("/api/onboarding/claude-auth", () => GET3());
|
|
26495
|
-
app.post("/api/onboarding/claude-auth", (c) =>
|
|
26496
|
-
app.post("/api/onboarding/set-pin", (c) =>
|
|
26696
|
+
app.post("/api/onboarding/claude-auth", (c) => POST17(c.req.raw));
|
|
26697
|
+
app.post("/api/onboarding/set-pin", (c) => POST18(c.req.raw));
|
|
26497
26698
|
app.delete("/api/onboarding/set-pin", (c) => DELETE(c.req.raw));
|
|
26498
|
-
app.post("/api/admin/session", (c) =>
|
|
26499
|
-
app.post("/api/admin/chat", (c) =>
|
|
26500
|
-
app.post("/api/admin/compact", (c) =>
|
|
26699
|
+
app.post("/api/admin/session", (c) => POST19(c.req.raw));
|
|
26700
|
+
app.post("/api/admin/chat", (c) => POST20(c.req.raw));
|
|
26701
|
+
app.post("/api/admin/compact", (c) => POST21(c.req.raw));
|
|
26501
26702
|
app.get("/api/admin/logs", (c) => GET4(c.req.raw));
|
|
26502
26703
|
app.get("/api/admin/claude-info", () => GET5());
|
|
26503
26704
|
app.patch("/api/admin/account", (c) => PATCH(c.req.raw));
|
|
@@ -26505,10 +26706,11 @@ app.get(
|
|
|
26505
26706
|
"/api/admin/attachment/:attachmentId",
|
|
26506
26707
|
(c) => GET6(c.req.raw, c.req.param("attachmentId"))
|
|
26507
26708
|
);
|
|
26709
|
+
app.post("/api/admin/file-attach", (c) => POST16(c.req.raw));
|
|
26508
26710
|
app.get("/api/admin/version", () => GET8());
|
|
26509
|
-
app.post("/api/admin/version/upgrade", (c) =>
|
|
26711
|
+
app.post("/api/admin/version/upgrade", (c) => POST22(c.req.raw));
|
|
26510
26712
|
app.get("/api/admin/agents", () => GET7());
|
|
26511
|
-
app.post("/api/admin/browser/launch", () =>
|
|
26713
|
+
app.post("/api/admin/browser/launch", () => POST23());
|
|
26512
26714
|
app.get("/api/admin/sessions", (c) => GET9(c.req.raw));
|
|
26513
26715
|
app.delete(
|
|
26514
26716
|
"/api/admin/sessions/:id",
|
|
@@ -26540,7 +26742,7 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
26540
26742
|
function cachedHtml(file2) {
|
|
26541
26743
|
let html = htmlCache.get(file2);
|
|
26542
26744
|
if (!html) {
|
|
26543
|
-
html = readFileSync19(
|
|
26745
|
+
html = readFileSync19(resolve17(process.cwd(), "public", file2), "utf-8");
|
|
26544
26746
|
html = html.replace("</head>", `${brandScript}
|
|
26545
26747
|
</head>`);
|
|
26546
26748
|
htmlCache.set(file2, html);
|
|
@@ -26634,7 +26836,7 @@ var port = parseInt(process.env.PORT ?? "19200", 10);
|
|
|
26634
26836
|
var hostname3 = process.env.HOSTNAME ?? "0.0.0.0";
|
|
26635
26837
|
serve({ fetch: app.fetch, port, hostname: hostname3 });
|
|
26636
26838
|
console.log(`${BRAND.productName} listening on http://${hostname3}:${port}`);
|
|
26637
|
-
var configDirForWhatsApp =
|
|
26839
|
+
var configDirForWhatsApp = basename4(MAXY_DIR) || ".maxy";
|
|
26638
26840
|
var bootAccount = resolveAccount();
|
|
26639
26841
|
var bootAccountConfig = bootAccount?.config;
|
|
26640
26842
|
var bootPublicAgent = bootAccount ? getPublicAgent(bootAccount.accountDir) : null;
|
|
@@ -26645,7 +26847,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
26645
26847
|
}
|
|
26646
26848
|
init({
|
|
26647
26849
|
configDir: configDirForWhatsApp,
|
|
26648
|
-
platformRoot:
|
|
26850
|
+
platformRoot: resolve17(process.env.MAXY_PLATFORM_ROOT ?? join9(__dirname, "..")),
|
|
26649
26851
|
accountConfig: bootAccountConfig,
|
|
26650
26852
|
onMessage: async (msg) => {
|
|
26651
26853
|
try {
|