@rubytech/create-maxy-code 0.1.461 → 0.1.462
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/lib/graph-mcp/dist/index.d.ts +2 -1
- package/payload/platform/lib/graph-mcp/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-mcp/dist/index.js +14 -22
- package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-mcp/src/index.ts +15 -22
- package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts +8 -7
- package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js +19 -19
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-spawn-tee/src/__tests__/spawn-tee.test.ts +34 -5
- package/payload/platform/lib/mcp-spawn-tee/src/index.ts +22 -19
- package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts +35 -17
- package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/mcp-stderr-tee/dist/index.js +41 -48
- package/payload/platform/lib/mcp-stderr-tee/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-stderr-tee/src/index.ts +42 -51
- package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js +27 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js +49 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/audit.d.ts +11 -0
- package/payload/platform/lib/storage-broker/dist/audit.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/audit.js +16 -0
- package/payload/platform/lib/storage-broker/dist/audit.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts +18 -0
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.js +77 -0
- package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/house-scoped-token.js +3 -0
- package/payload/platform/lib/storage-broker/dist/house-scoped-token.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/registry.d.ts +1 -1
- package/payload/platform/lib/storage-broker/dist/registry.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/registry.js.map +1 -1
- package/payload/platform/lib/storage-broker/src/__tests__/audit.test.ts +32 -1
- package/payload/platform/lib/storage-broker/src/__tests__/cf-exec.test.ts +61 -0
- package/payload/platform/lib/storage-broker/src/audit.ts +45 -0
- package/payload/platform/lib/storage-broker/src/cf-exec.ts +91 -0
- package/payload/platform/lib/storage-broker/src/house-scoped-token.ts +3 -0
- package/payload/platform/lib/storage-broker/src/registry.ts +5 -1
- package/payload/platform/plugins/admin/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +22 -11
- package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/browser/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js +5 -5
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/cloudflare/references/hosting-sites.md +2 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/SKILL.md +1 -1
- package/payload/platform/plugins/cloudflare/skills/site-deploy/SKILL.md +2 -0
- package/payload/platform/plugins/connector/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/docs/references/admin-session.md +3 -3
- package/payload/platform/plugins/docs/references/cloudflare.md +2 -0
- package/payload/platform/plugins/docs/references/outlook-guide.md +11 -4
- package/payload/platform/plugins/docs/references/plugins-guide.md +8 -6
- package/payload/platform/plugins/email/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/filesystem/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/graph-viewer/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js.map +1 -1
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +2 -2
- package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-threaded.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-threaded.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-threaded.test.js +238 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-threaded.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/index.js +9 -5
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts +58 -9
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js +113 -19
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js.map +1 -1
- package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +5 -2
- package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/storage-broker/PLUGIN.md +9 -1
- package/payload/platform/plugins/storage-broker/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.d.ts.map +1 -1
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.js +16 -5
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.js.map +1 -1
- package/payload/platform/plugins/storage-broker/mcp/dist/index.js +49 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/voice-mirror/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/web-designer/PLUGIN.md +1 -1
- package/payload/platform/plugins/web-designer/commands/website.md +6 -0
- package/payload/platform/plugins/web-designer/skills/web-design/references/deploy.md +12 -0
- package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/work/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/scripts/__tests__/logs-rotate.test.sh +24 -20
- package/payload/platform/scripts/logs-read.sh +31 -0
- package/payload/platform/scripts/logs-rotate.sh +21 -18
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +37 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +5 -3
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/server/{chunk-JXWFVE5X.js → chunk-BBSPFN45.js} +65 -0
- package/payload/server/public/assets/{AdminLoginScreens-BFbpkEUS.js → AdminLoginScreens-Bed8SDxY.js} +1 -1
- package/payload/server/public/assets/{AdminShell-CdOGObaZ.js → AdminShell-BLh9O6dn.js} +1 -1
- package/payload/server/public/assets/{Checkbox-RFD_F0c0.js → Checkbox-BC_KSbpS.js} +1 -1
- package/payload/server/public/assets/{admin-CYGdL-1O.js → admin-DfWgJVI3.js} +1 -1
- package/payload/server/public/assets/{browser-DVfa_plj.js → browser-C0vkv-hH.js} +1 -1
- package/payload/server/public/assets/{calendar-JC_Dxa4n.js → calendar-_pfHw0Hp.js} +1 -1
- package/payload/server/public/assets/chat-CufidiBQ.js +1 -0
- package/payload/server/public/assets/chevron-left-BnpVBu51.js +1 -0
- package/payload/server/public/assets/data-CR-fbPWr.js +1 -0
- package/payload/server/public/assets/{graph-hBUrRSkr.js → graph-BZiudUGr.js} +1 -1
- package/payload/server/public/assets/{graph-labels-CHh6zs8t.js → graph-labels-BzmmJwCR.js} +1 -1
- package/payload/server/public/assets/{maximize-2-DjxE4rm9.js → maximize-2-Bhdsv0U-.js} +1 -1
- package/payload/server/public/assets/{operator-BqU9SQuu.js → operator-Cj0B_usT.js} +1 -1
- package/payload/server/public/assets/page-84Fdwiu_.js +32 -0
- package/payload/server/public/assets/{page-DiQhU6lD.js → page-8AB3jUa_.js} +1 -1
- package/payload/server/public/assets/{public-Cu_eALgY.js → public-BkNW9e9T.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-F9DsSTSJ.js → rotate-ccw-D_5cETGt.js} +1 -1
- package/payload/server/public/assets/{tasks-CE-D0f50.js → tasks-EyKLXINi.js} +1 -1
- package/payload/server/public/assets/{time-entry-format-D2rsWhov.js → time-entry-format-DAwmmR3i.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-QxOmoobV.js → useCopyFeedback-rOWd_lzl.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-RIzNqFjV.js → useSelectionMode-DDmLmPph.js} +1 -1
- package/payload/server/public/assets/{useSubAccountSwitcher-BW_fK1Nt.css → useSubAccountSwitcher-pu0jjLCz.css} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-WrWurSYI.js → useVoiceRecorder-azG8zSUI.js} +1 -1
- 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 +526 -174
- package/payload/server/{src-4F37OHLK.js → src-YLGAZY36.js} +5 -1
- package/payload/server/public/assets/chat-Yf8Nkop8.js +0 -1
- package/payload/server/public/assets/chevron-left-CAiAUBxO.js +0 -1
- package/payload/server/public/assets/data-hqdYXaEn.js +0 -1
- package/payload/server/public/assets/page-B4c4_4HP.js +0 -32
- /package/payload/server/public/assets/{useSubAccountSwitcher-wo_qGW-I.js → useSubAccountSwitcher-CU-lOxTd.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -122,10 +122,11 @@ import {
|
|
|
122
122
|
authorizeAccess,
|
|
123
123
|
listResources,
|
|
124
124
|
makeHouseCfExec,
|
|
125
|
+
makeHousePagesExec,
|
|
125
126
|
registerResource,
|
|
126
127
|
resolveOwner,
|
|
127
128
|
tooLargeMessage
|
|
128
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-BBSPFN45.js";
|
|
129
130
|
import {
|
|
130
131
|
__commonJS,
|
|
131
132
|
__toESM
|
|
@@ -1535,7 +1536,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1535
1536
|
import { readFileSync as readFileSync38, existsSync as existsSync36, watchFile, readdirSync as readdirSync21, statSync as statSync14 } from "fs";
|
|
1536
1537
|
import { spawn as spawn3 } from "child_process";
|
|
1537
1538
|
import { createHash as createHash7 } from "crypto";
|
|
1538
|
-
import { resolve as
|
|
1539
|
+
import { resolve as resolve36, join as join38, basename as basename12 } from "path";
|
|
1539
1540
|
import { homedir as homedir4 } from "os";
|
|
1540
1541
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1541
1542
|
|
|
@@ -2248,7 +2249,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
2248
2249
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
2249
2250
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
2250
2251
|
const timer2 = new Promise(
|
|
2251
|
-
(
|
|
2252
|
+
(resolve37) => setTimeout(() => resolve37("timeout"), timeoutMs)
|
|
2252
2253
|
);
|
|
2253
2254
|
const result = await Promise.race([
|
|
2254
2255
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -2411,11 +2412,11 @@ async function createWaSocket(opts) {
|
|
|
2411
2412
|
return sock;
|
|
2412
2413
|
}
|
|
2413
2414
|
async function waitForConnection(sock) {
|
|
2414
|
-
return new Promise((
|
|
2415
|
+
return new Promise((resolve37, reject) => {
|
|
2415
2416
|
const handler = (update) => {
|
|
2416
2417
|
if (update.connection === "open") {
|
|
2417
2418
|
sock.ev.off("connection.update", handler);
|
|
2418
|
-
|
|
2419
|
+
resolve37();
|
|
2419
2420
|
}
|
|
2420
2421
|
if (update.connection === "close") {
|
|
2421
2422
|
sock.ev.off("connection.update", handler);
|
|
@@ -2520,7 +2521,7 @@ import { inspect as inspect2 } from "util";
|
|
|
2520
2521
|
|
|
2521
2522
|
// app/lib/whatsapp/with-timeout.ts
|
|
2522
2523
|
function withTimeout(label, promise, timeoutMs) {
|
|
2523
|
-
return new Promise((
|
|
2524
|
+
return new Promise((resolve37, reject) => {
|
|
2524
2525
|
const timer2 = setTimeout(() => {
|
|
2525
2526
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2526
2527
|
}, timeoutMs);
|
|
@@ -2528,7 +2529,7 @@ function withTimeout(label, promise, timeoutMs) {
|
|
|
2528
2529
|
promise.then(
|
|
2529
2530
|
(value) => {
|
|
2530
2531
|
clearTimeout(timer2);
|
|
2531
|
-
|
|
2532
|
+
resolve37(value);
|
|
2532
2533
|
},
|
|
2533
2534
|
(err) => {
|
|
2534
2535
|
clearTimeout(timer2);
|
|
@@ -3779,8 +3780,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
3779
3780
|
const { givenName, familyName } = splitName(input.pushName);
|
|
3780
3781
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
3781
3782
|
let release;
|
|
3782
|
-
const mine = new Promise((
|
|
3783
|
-
release =
|
|
3783
|
+
const mine = new Promise((resolve37) => {
|
|
3784
|
+
release = resolve37;
|
|
3784
3785
|
});
|
|
3785
3786
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
3786
3787
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -5484,11 +5485,11 @@ async function connectWithReconnect(conn) {
|
|
|
5484
5485
|
console.error(
|
|
5485
5486
|
`${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
5486
5487
|
);
|
|
5487
|
-
await new Promise((
|
|
5488
|
-
const timer2 = setTimeout(
|
|
5488
|
+
await new Promise((resolve37) => {
|
|
5489
|
+
const timer2 = setTimeout(resolve37, delay);
|
|
5489
5490
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
5490
5491
|
clearTimeout(timer2);
|
|
5491
|
-
|
|
5492
|
+
resolve37();
|
|
5492
5493
|
}, { once: true });
|
|
5493
5494
|
});
|
|
5494
5495
|
}
|
|
@@ -5496,16 +5497,16 @@ async function connectWithReconnect(conn) {
|
|
|
5496
5497
|
}
|
|
5497
5498
|
}
|
|
5498
5499
|
function waitForDisconnectEvent(conn) {
|
|
5499
|
-
return new Promise((
|
|
5500
|
+
return new Promise((resolve37) => {
|
|
5500
5501
|
if (!conn.sock) {
|
|
5501
|
-
|
|
5502
|
+
resolve37();
|
|
5502
5503
|
return;
|
|
5503
5504
|
}
|
|
5504
5505
|
const sock = conn.sock;
|
|
5505
5506
|
const handler = (update) => {
|
|
5506
5507
|
if (update.connection === "close") {
|
|
5507
5508
|
sock.ev.off("connection.update", handler);
|
|
5508
|
-
|
|
5509
|
+
resolve37();
|
|
5509
5510
|
}
|
|
5510
5511
|
};
|
|
5511
5512
|
sock.ev.on("connection.update", handler);
|
|
@@ -5873,8 +5874,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
5873
5874
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
5874
5875
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
5875
5876
|
let resolvePending;
|
|
5876
|
-
const sttPending = new Promise((
|
|
5877
|
-
resolvePending =
|
|
5877
|
+
const sttPending = new Promise((resolve37) => {
|
|
5878
|
+
resolvePending = resolve37;
|
|
5878
5879
|
});
|
|
5879
5880
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
5880
5881
|
try {
|
|
@@ -6302,20 +6303,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
6302
6303
|
|
|
6303
6304
|
// server/routes/health.ts
|
|
6304
6305
|
function checkPort(port2, timeoutMs = 500) {
|
|
6305
|
-
return new Promise((
|
|
6306
|
+
return new Promise((resolve37) => {
|
|
6306
6307
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
6307
6308
|
socket.setTimeout(timeoutMs);
|
|
6308
6309
|
socket.once("connect", () => {
|
|
6309
6310
|
socket.destroy();
|
|
6310
|
-
|
|
6311
|
+
resolve37(true);
|
|
6311
6312
|
});
|
|
6312
6313
|
socket.once("error", () => {
|
|
6313
6314
|
socket.destroy();
|
|
6314
|
-
|
|
6315
|
+
resolve37(false);
|
|
6315
6316
|
});
|
|
6316
6317
|
socket.once("timeout", () => {
|
|
6317
6318
|
socket.destroy();
|
|
6318
|
-
|
|
6319
|
+
resolve37(false);
|
|
6319
6320
|
});
|
|
6320
6321
|
});
|
|
6321
6322
|
}
|
|
@@ -7593,8 +7594,8 @@ async function startLogin(opts) {
|
|
|
7593
7594
|
await clearAuth(authDir);
|
|
7594
7595
|
let resolveCode = null;
|
|
7595
7596
|
let rejectCode = null;
|
|
7596
|
-
const codePromise = new Promise((
|
|
7597
|
-
resolveCode =
|
|
7597
|
+
const codePromise = new Promise((resolve37, reject) => {
|
|
7598
|
+
resolveCode = resolve37;
|
|
7598
7599
|
rejectCode = reject;
|
|
7599
7600
|
});
|
|
7600
7601
|
const codeTimer = setTimeout(
|
|
@@ -7766,14 +7767,14 @@ function routeDocumentOutboundAt(to, filePath) {
|
|
|
7766
7767
|
return lastRouteDocumentOutboundAt.get(routeKey(to, filePath));
|
|
7767
7768
|
}
|
|
7768
7769
|
async function sendWhatsAppDocument(input) {
|
|
7769
|
-
const { to, filePath, caption, accountId, maxyAccountId, platformRoot:
|
|
7770
|
+
const { to, filePath, caption, accountId, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
7770
7771
|
if (!to || !filePath) {
|
|
7771
7772
|
return { ok: false, status: 400, error: "Missing required fields: to, filePath" };
|
|
7772
7773
|
}
|
|
7773
|
-
if (!maxyAccountId || !
|
|
7774
|
+
if (!maxyAccountId || !platformRoot5) {
|
|
7774
7775
|
return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
|
|
7775
7776
|
}
|
|
7776
|
-
const accountDir = resolve9(
|
|
7777
|
+
const accountDir = resolve9(platformRoot5, "..", "data/accounts", maxyAccountId);
|
|
7777
7778
|
let resolvedPath;
|
|
7778
7779
|
try {
|
|
7779
7780
|
resolvedPath = realpathSync3(filePath);
|
|
@@ -8734,7 +8735,8 @@ var bodyLimit = (options) => {
|
|
|
8734
8735
|
|
|
8735
8736
|
// server/routes/storage-broker.ts
|
|
8736
8737
|
import { join as join11, resolve as resolve11 } from "path";
|
|
8737
|
-
import { readdirSync as readdirSync6, readFileSync as readFileSync13, existsSync as existsSync8 } from "fs";
|
|
8738
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync13, existsSync as existsSync8, realpathSync as realpathSync4 } from "fs";
|
|
8739
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
8738
8740
|
var app3 = new Hono();
|
|
8739
8741
|
function platformRoot() {
|
|
8740
8742
|
return process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? join11(__dirname, "..", "..");
|
|
@@ -8793,6 +8795,125 @@ var d1QueryBodyLimit = bodyLimit({
|
|
|
8793
8795
|
);
|
|
8794
8796
|
}
|
|
8795
8797
|
});
|
|
8798
|
+
var pagesDeployBodyLimit = bodyLimit({
|
|
8799
|
+
maxSize: STORAGE_RESOURCE_NAME_MAX_BODY_BYTES,
|
|
8800
|
+
onError: (c) => {
|
|
8801
|
+
log("write", "pages", caller(c) ?? "none", "*", null, "deny", "publish-body-too-large");
|
|
8802
|
+
return c.json(
|
|
8803
|
+
{
|
|
8804
|
+
error: `request body exceeds the ${(STORAGE_RESOURCE_NAME_MAX_BODY_BYTES / 1024).toFixed(
|
|
8805
|
+
1
|
|
8806
|
+
)} KiB (${STORAGE_RESOURCE_NAME_MAX_BODY_BYTES} bytes) limit for a Pages publish, which carries only a project name, a site folder name and an optional branch.`
|
|
8807
|
+
},
|
|
8808
|
+
413
|
|
8809
|
+
);
|
|
8810
|
+
}
|
|
8811
|
+
});
|
|
8812
|
+
function resolveSiteDir(account, site) {
|
|
8813
|
+
if (!site || site === "." || site === "..") return null;
|
|
8814
|
+
if (site.includes("/") || site.includes("\\") || site.includes("\0")) return null;
|
|
8815
|
+
const accountsDir = resolve11(platformRoot(), "..", "data", "accounts");
|
|
8816
|
+
const base = resolve11(accountsDir, account, "sites");
|
|
8817
|
+
const dir = resolve11(base, site);
|
|
8818
|
+
if (dir !== base && !dir.startsWith(base + "/")) return null;
|
|
8819
|
+
try {
|
|
8820
|
+
const realBase = realpathSync4(base);
|
|
8821
|
+
const realDir = realpathSync4(dir);
|
|
8822
|
+
if (!realDir.startsWith(realBase + "/")) return null;
|
|
8823
|
+
return realDir;
|
|
8824
|
+
} catch {
|
|
8825
|
+
return null;
|
|
8826
|
+
}
|
|
8827
|
+
}
|
|
8828
|
+
async function verifyDeployed(url) {
|
|
8829
|
+
try {
|
|
8830
|
+
const res = await fetch(`${url}?cb=${Date.now()}`, { method: "GET", redirect: "follow" });
|
|
8831
|
+
return res.status;
|
|
8832
|
+
} catch {
|
|
8833
|
+
return null;
|
|
8834
|
+
}
|
|
8835
|
+
}
|
|
8836
|
+
app3.post("/pages/deploy", pagesDeployBodyLimit, async (c) => {
|
|
8837
|
+
const pub = randomUUID7().slice(0, 8);
|
|
8838
|
+
const account = caller(c);
|
|
8839
|
+
if (!account) {
|
|
8840
|
+
log("write", "pages", "none", "*", null, "deny", "no-caller");
|
|
8841
|
+
return c.json({ error: "no-caller" }, 403);
|
|
8842
|
+
}
|
|
8843
|
+
const parsed = await readJsonBody(c);
|
|
8844
|
+
if (!parsed.ok) return parsed.res;
|
|
8845
|
+
const { project, site, branch } = parsed.body;
|
|
8846
|
+
if (!project || typeof project !== "string") return c.json({ error: "project-required" }, 400);
|
|
8847
|
+
if (!site || typeof site !== "string") return c.json({ error: "site-required" }, 400);
|
|
8848
|
+
if (branch !== void 0 && typeof branch !== "string") return c.json({ error: "branch-invalid" }, 400);
|
|
8849
|
+
console.error(
|
|
8850
|
+
`[pages-broker] op=request pub=${pub} caller=${account} project=${project} site=${site} branch=${branch ?? "default"}`
|
|
8851
|
+
);
|
|
8852
|
+
const dir = resolveSiteDir(account, site);
|
|
8853
|
+
if (dir === null) {
|
|
8854
|
+
console.error(`[pages-broker] op=path pub=${pub} site=${site} inside=false`);
|
|
8855
|
+
log("write", "pages", account, String(site), null, "deny", "invalid-site");
|
|
8856
|
+
return c.json({ error: "invalid-site" }, 400);
|
|
8857
|
+
}
|
|
8858
|
+
console.error(`[pages-broker] op=path pub=${pub} resolved=${dir} inside=true`);
|
|
8859
|
+
const session = getSession();
|
|
8860
|
+
try {
|
|
8861
|
+
const owner = await resolveOwner(session, "pages", project);
|
|
8862
|
+
const decision = authorizeAccess({ caller: account, owner, action: "write" });
|
|
8863
|
+
console.error(
|
|
8864
|
+
`[pages-broker] op=authorize pub=${pub} caller=${account} owner=${owner ?? "none"} decision=${decision.allow ? "allow" : "deny"} reason=${decision.reason}`
|
|
8865
|
+
);
|
|
8866
|
+
log("write", "pages", account, project, owner, decision.allow ? "allow" : "deny", decision.allow ? void 0 : decision.reason);
|
|
8867
|
+
if (!decision.allow) return c.json({ error: decision.reason }, 403);
|
|
8868
|
+
const started = Date.now();
|
|
8869
|
+
const { url } = await (await makeHousePagesExec(platformRoot())).pagesDeploy(dir, project, branch);
|
|
8870
|
+
console.error(`[pages-broker] op=deploy pub=${pub} ranMs=${Date.now() - started} url=${url}`);
|
|
8871
|
+
const httpStatus = await verifyDeployed(url);
|
|
8872
|
+
const verified = httpStatus === 200;
|
|
8873
|
+
console.error(
|
|
8874
|
+
`[pages-broker] op=complete pub=${pub} httpStatus=${httpStatus ?? "unreachable"} verified=${verified}`
|
|
8875
|
+
);
|
|
8876
|
+
if (!verified) {
|
|
8877
|
+
return c.json({ error: "deploy-unverified", url, httpStatus }, 502);
|
|
8878
|
+
}
|
|
8879
|
+
return c.json({ url });
|
|
8880
|
+
} catch (err) {
|
|
8881
|
+
console.error(`[pages-broker] op=exit pub=${pub} result=error detail="${String(err)}"`);
|
|
8882
|
+
return c.json({ error: String(err) }, 500);
|
|
8883
|
+
} finally {
|
|
8884
|
+
await session.close();
|
|
8885
|
+
}
|
|
8886
|
+
});
|
|
8887
|
+
app3.post("/pages/adopt", nameBodyLimit("pages"), async (c) => {
|
|
8888
|
+
const houseAdminScope = c.req.header("x-maxy-house-admin-scope")?.trim() || null;
|
|
8889
|
+
const account = caller(c);
|
|
8890
|
+
if (!houseAdminScope) {
|
|
8891
|
+
log("write", "pages", account ?? "none", "*", null, "deny", "not-house-admin");
|
|
8892
|
+
return c.json({ error: "not-house-admin" }, 403);
|
|
8893
|
+
}
|
|
8894
|
+
const parsed = await readJsonBody(c);
|
|
8895
|
+
if (!parsed.ok) return parsed.res;
|
|
8896
|
+
const { project, account: target } = parsed.body;
|
|
8897
|
+
if (!project || typeof project !== "string") return c.json({ error: "project-required" }, 400);
|
|
8898
|
+
if (!target || typeof target !== "string") return c.json({ error: "account-required" }, 400);
|
|
8899
|
+
const session = getSession();
|
|
8900
|
+
try {
|
|
8901
|
+
const owner = await resolveOwner(session, "pages", project);
|
|
8902
|
+
if (owner !== null && owner !== target) {
|
|
8903
|
+
log("write", "pages", target, project, owner, "deny", "already-owned");
|
|
8904
|
+
return c.json({ error: "already-owned", owner }, 409);
|
|
8905
|
+
}
|
|
8906
|
+
if (owner === null) {
|
|
8907
|
+
await registerResource(session, { accountId: target, kind: "pages", name: project, cfResourceId: project });
|
|
8908
|
+
}
|
|
8909
|
+
log("write", "pages", target, project, target, "allow");
|
|
8910
|
+
return c.json({ project, account: target });
|
|
8911
|
+
} catch (err) {
|
|
8912
|
+
return c.json({ error: String(err) }, 500);
|
|
8913
|
+
} finally {
|
|
8914
|
+
await session.close();
|
|
8915
|
+
}
|
|
8916
|
+
});
|
|
8796
8917
|
app3.get("/d1/list", async (c) => {
|
|
8797
8918
|
const account = caller(c);
|
|
8798
8919
|
if (!account) return c.json({ error: "no-caller" }, 403);
|
|
@@ -9062,7 +9183,7 @@ app3.post("/r2/object/delete", envelopeBodyLimit("write"), async (c) => {
|
|
|
9062
9183
|
});
|
|
9063
9184
|
var storage_broker_default = app3;
|
|
9064
9185
|
async function runStorageAudit(root) {
|
|
9065
|
-
const { reconcileStorage } = await import("./src-
|
|
9186
|
+
const { reconcileStorage } = await import("./src-YLGAZY36.js");
|
|
9066
9187
|
const session = getSession();
|
|
9067
9188
|
try {
|
|
9068
9189
|
const cf = await makeHouseCfExec(root);
|
|
@@ -9094,9 +9215,31 @@ async function runStorageAudit(root) {
|
|
|
9094
9215
|
await session.close();
|
|
9095
9216
|
}
|
|
9096
9217
|
}
|
|
9218
|
+
async function runPagesAudit(root) {
|
|
9219
|
+
const { reconcilePages } = await import("./src-YLGAZY36.js");
|
|
9220
|
+
const session = getSession();
|
|
9221
|
+
try {
|
|
9222
|
+
const cf = await makeHousePagesExec(root);
|
|
9223
|
+
const r = await reconcilePages({
|
|
9224
|
+
cfProjects: async () => (await cf.pagesProjectList()).map((p) => p.name),
|
|
9225
|
+
registeredProjects: async () => {
|
|
9226
|
+
const res = await session.run(
|
|
9227
|
+
"MATCH (r:StorageResource {kind: $kind}) RETURN r.name AS name",
|
|
9228
|
+
{ kind: "pages" }
|
|
9229
|
+
);
|
|
9230
|
+
return res.records.map((rec) => rec.get("name"));
|
|
9231
|
+
}
|
|
9232
|
+
});
|
|
9233
|
+
console.error(
|
|
9234
|
+
`[pages-audit] projects=${r.projects} registered=${r.registered} orphan=${r.orphans.length} phantom=${r.phantoms.length}` + r.orphans.map((n) => ` orphan:${n}`).join("") + r.phantoms.map((n) => ` phantom:${n}`).join("")
|
|
9235
|
+
);
|
|
9236
|
+
} finally {
|
|
9237
|
+
await session.close();
|
|
9238
|
+
}
|
|
9239
|
+
}
|
|
9097
9240
|
|
|
9098
9241
|
// server/routes/whatsapp-reader.ts
|
|
9099
|
-
import { readFileSync as readFileSync17, watch, statSync as statSync5, openSync, readSync, closeSync, existsSync as existsSync11, readdirSync as readdirSync11, realpathSync as
|
|
9242
|
+
import { readFileSync as readFileSync17, watch, statSync as statSync5, openSync, readSync, closeSync, existsSync as existsSync11, readdirSync as readdirSync11, realpathSync as realpathSync5 } from "fs";
|
|
9100
9243
|
import { basename as basename4, dirname as dirname5, isAbsolute, join as join16, relative as relative2, resolve as resolve13, sep as sep3 } from "path";
|
|
9101
9244
|
|
|
9102
9245
|
// server/routes/admin/sidebar-sessions.ts
|
|
@@ -9728,7 +9871,31 @@ function joinTextBlocks(content) {
|
|
|
9728
9871
|
}
|
|
9729
9872
|
return parts.join("");
|
|
9730
9873
|
}
|
|
9731
|
-
function
|
|
9874
|
+
function erroredToolUseIds(lines) {
|
|
9875
|
+
const ids = /* @__PURE__ */ new Set();
|
|
9876
|
+
for (const line of lines) {
|
|
9877
|
+
if (!line || line[0] !== "{" || !line.includes("is_error")) continue;
|
|
9878
|
+
let row;
|
|
9879
|
+
try {
|
|
9880
|
+
const parsed = JSON.parse(line);
|
|
9881
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
9882
|
+
row = parsed;
|
|
9883
|
+
} catch {
|
|
9884
|
+
continue;
|
|
9885
|
+
}
|
|
9886
|
+
const content = row.message?.content;
|
|
9887
|
+
if (!Array.isArray(content)) continue;
|
|
9888
|
+
for (const block of content) {
|
|
9889
|
+
if (!block || typeof block !== "object") continue;
|
|
9890
|
+
const b = block;
|
|
9891
|
+
if (b.type === "tool_result" && b.is_error === true && typeof b.tool_use_id === "string") {
|
|
9892
|
+
ids.add(b.tool_use_id);
|
|
9893
|
+
}
|
|
9894
|
+
}
|
|
9895
|
+
}
|
|
9896
|
+
return ids;
|
|
9897
|
+
}
|
|
9898
|
+
function assistantTurns(content, ts, promoteFinal = false, erroredIds = /* @__PURE__ */ new Set()) {
|
|
9732
9899
|
if (!Array.isArray(content)) return [];
|
|
9733
9900
|
const out = [];
|
|
9734
9901
|
for (const block of content) {
|
|
@@ -9748,7 +9915,12 @@ function assistantTurns(content, ts, promoteFinal = false) {
|
|
|
9748
9915
|
const input = b.input ?? {};
|
|
9749
9916
|
const files = Array.isArray(input.files) ? input.files.filter((f) => typeof f === "string") : [];
|
|
9750
9917
|
const caption = typeof input.caption === "string" ? input.caption : null;
|
|
9751
|
-
|
|
9918
|
+
const refused = typeof b.id === "string" && erroredIds.has(b.id);
|
|
9919
|
+
if (files.length === 0 || refused) {
|
|
9920
|
+
out.push({ kind: "tool-call", name: SEND_USER_FILE_TOOL, input: b.input ?? null, ts });
|
|
9921
|
+
} else {
|
|
9922
|
+
out.push({ kind: "agent-file", files, caption, ts });
|
|
9923
|
+
}
|
|
9752
9924
|
} else if (b.type === "tool_use" && typeof b.name === "string") {
|
|
9753
9925
|
out.push({ kind: "tool-call", name: b.name, input: b.input ?? null, ts });
|
|
9754
9926
|
}
|
|
@@ -9788,6 +9960,7 @@ function renderOrSuppressChannelInbound(u, ts, out, queuedPendingSuppress) {
|
|
|
9788
9960
|
}
|
|
9789
9961
|
function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(), turnCtx = {}) {
|
|
9790
9962
|
const out = [];
|
|
9963
|
+
const erroredIds = erroredToolUseIds(lines);
|
|
9791
9964
|
for (const line of lines) {
|
|
9792
9965
|
if (!line || line[0] !== "{") continue;
|
|
9793
9966
|
let row;
|
|
@@ -9812,7 +9985,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
9812
9985
|
if (hasWebchatReply(msg?.content)) turnCtx.repliedThisTurn = true;
|
|
9813
9986
|
const isEnd = msg?.stop_reason === "end_turn";
|
|
9814
9987
|
const promoteFinal = isEnd && turnCtx.lastChannelSource === "webchat" && !turnCtx.repliedThisTurn;
|
|
9815
|
-
out.push(...assistantTurns(msg?.content, ts, promoteFinal));
|
|
9988
|
+
out.push(...assistantTurns(msg?.content, ts, promoteFinal, erroredIds));
|
|
9816
9989
|
continue;
|
|
9817
9990
|
}
|
|
9818
9991
|
if (row.type === "queue-operation" && row.operation === "enqueue") {
|
|
@@ -10209,7 +10382,7 @@ function enrichDownloads(turn, scratchpadRoot) {
|
|
|
10209
10382
|
if (turn.kind !== "agent-file") return turn;
|
|
10210
10383
|
let scratchpadReal = null;
|
|
10211
10384
|
try {
|
|
10212
|
-
scratchpadReal =
|
|
10385
|
+
scratchpadReal = realpathSync5(scratchpadRoot);
|
|
10213
10386
|
} catch {
|
|
10214
10387
|
scratchpadReal = null;
|
|
10215
10388
|
}
|
|
@@ -10220,7 +10393,7 @@ function enrichDownloads(turn, scratchpadRoot) {
|
|
|
10220
10393
|
}
|
|
10221
10394
|
if (scratchpadReal) {
|
|
10222
10395
|
try {
|
|
10223
|
-
const fileReal =
|
|
10396
|
+
const fileReal = realpathSync5(f);
|
|
10224
10397
|
if (fileReal === scratchpadReal || fileReal.startsWith(scratchpadReal + sep3)) {
|
|
10225
10398
|
return { root: "scratchpad", path: relative2(scratchpadReal, fileReal) };
|
|
10226
10399
|
}
|
|
@@ -12293,8 +12466,8 @@ function routeTelegramUpdate(input) {
|
|
|
12293
12466
|
// server/routes/telegram.ts
|
|
12294
12467
|
var TAG23 = "[telegram-inbound]";
|
|
12295
12468
|
function configDirName() {
|
|
12296
|
-
const
|
|
12297
|
-
const brandPath = join22(
|
|
12469
|
+
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve16(process.cwd(), "..");
|
|
12470
|
+
const brandPath = join22(platformRoot5, "config", "brand.json");
|
|
12298
12471
|
if (existsSync15(brandPath)) {
|
|
12299
12472
|
try {
|
|
12300
12473
|
return JSON.parse(readFileSync23(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
@@ -12493,7 +12666,7 @@ var quickbooks_default = app9;
|
|
|
12493
12666
|
// server/routes/onboarding.ts
|
|
12494
12667
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync3 } from "child_process";
|
|
12495
12668
|
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync10, writeSync, existsSync as existsSync18, readFileSync as readFileSync26, unlinkSync as unlinkSync3, renameSync as renameSync7 } from "fs";
|
|
12496
|
-
import { createHash as createHash4, randomUUID as
|
|
12669
|
+
import { createHash as createHash4, randomUUID as randomUUID8 } from "crypto";
|
|
12497
12670
|
|
|
12498
12671
|
// app/lib/claude-spawn-env.ts
|
|
12499
12672
|
function claudeBin() {
|
|
@@ -12989,7 +13162,7 @@ app10.post("/set-pin", async (c) => {
|
|
|
12989
13162
|
const hash = hashPin2(body.pin);
|
|
12990
13163
|
const account = resolveAccount();
|
|
12991
13164
|
const existingOwnerUserId = account?.config.admins?.find((a) => a.role === "owner")?.userId;
|
|
12992
|
-
const userId = existingOwnerUserId ??
|
|
13165
|
+
const userId = existingOwnerUserId ?? randomUUID8();
|
|
12993
13166
|
if (existingOwnerUserId) {
|
|
12994
13167
|
console.log(`[set-pin] reusing existing owner userId=${userId.slice(0, 8)}\u2026 (change-PIN preserves identity)`);
|
|
12995
13168
|
} else {
|
|
@@ -13381,7 +13554,7 @@ app11.post("/", async (c) => {
|
|
|
13381
13554
|
var client_error_default = app11;
|
|
13382
13555
|
|
|
13383
13556
|
// server/routes/admin/session.ts
|
|
13384
|
-
import { randomUUID as
|
|
13557
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
13385
13558
|
async function resolveUserIdentity(accountId, userId) {
|
|
13386
13559
|
const result = await loadAdminUserName(userId);
|
|
13387
13560
|
if (result.source === "neo4j") {
|
|
@@ -13395,7 +13568,7 @@ async function resolveUserIdentity(accountId, userId) {
|
|
|
13395
13568
|
async function createAdminSession(accountId, thinkingView, userId, userName, role, avatar) {
|
|
13396
13569
|
const account = resolveAccount();
|
|
13397
13570
|
const effectiveThinkingView = thinkingView ?? account?.config.thinkingView ?? "default";
|
|
13398
|
-
const signedSessionToken =
|
|
13571
|
+
const signedSessionToken = randomUUID9();
|
|
13399
13572
|
const cacheKey = fingerprintSessionKey(signedSessionToken);
|
|
13400
13573
|
registerSession(cacheKey, "admin", accountId, void 0, userId, userName ?? void 0, role);
|
|
13401
13574
|
if (userId) setWantsPriorConversation(cacheKey);
|
|
@@ -13437,15 +13610,15 @@ function operatorRoleFor(config, userId) {
|
|
|
13437
13610
|
async function buildAccountOptionList(accounts, userId) {
|
|
13438
13611
|
const houseAccount = accounts.find((a) => a.config.role === "house");
|
|
13439
13612
|
console.log(`[admin-accounts] op=list count=${accounts.length} house=${houseAccount?.accountId ?? "none"}`);
|
|
13440
|
-
const
|
|
13613
|
+
const resolve37 = async (a) => {
|
|
13441
13614
|
const businessName = await fetchAccountName(a.accountId) || void 0;
|
|
13442
13615
|
return { accountId: a.accountId, businessName, role: operatorRoleFor(a.config, userId), isHouse: a.config.role === "house" };
|
|
13443
13616
|
};
|
|
13444
13617
|
const houseOptions = await Promise.all(
|
|
13445
|
-
accounts.filter((a) => a.config.role === "house").map(
|
|
13618
|
+
accounts.filter((a) => a.config.role === "house").map(resolve37)
|
|
13446
13619
|
);
|
|
13447
13620
|
const nonHouseOptions = await Promise.all(
|
|
13448
|
-
accounts.filter((a) => a.config.role !== "house").map(
|
|
13621
|
+
accounts.filter((a) => a.config.role !== "house").map(resolve37)
|
|
13449
13622
|
);
|
|
13450
13623
|
const sortKey = (o) => (o.businessName || o.accountId).toLowerCase();
|
|
13451
13624
|
nonHouseOptions.sort((x, y) => {
|
|
@@ -14929,10 +15102,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
14929
15102
|
}
|
|
14930
15103
|
}
|
|
14931
15104
|
function resolveTunnelUrl() {
|
|
14932
|
-
const
|
|
15105
|
+
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
|
|
14933
15106
|
let brand;
|
|
14934
15107
|
try {
|
|
14935
|
-
brand = JSON.parse(readFileSync30(resolve21(
|
|
15108
|
+
brand = JSON.parse(readFileSync30(resolve21(platformRoot5, "config", "brand.json"), "utf-8"));
|
|
14936
15109
|
} catch {
|
|
14937
15110
|
return null;
|
|
14938
15111
|
}
|
|
@@ -15141,18 +15314,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
15141
15314
|
]);
|
|
15142
15315
|
var app21 = new Hono();
|
|
15143
15316
|
app21.post("/", async (c) => {
|
|
15144
|
-
const
|
|
15317
|
+
const TAG46 = "[admin:events]";
|
|
15145
15318
|
let body;
|
|
15146
15319
|
try {
|
|
15147
15320
|
body = await c.req.json();
|
|
15148
15321
|
} catch (err) {
|
|
15149
15322
|
const detail = err instanceof Error ? err.message : String(err);
|
|
15150
|
-
console.error(`${
|
|
15323
|
+
console.error(`${TAG46} reject reason=body-not-json detail=${detail}`);
|
|
15151
15324
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
15152
15325
|
}
|
|
15153
15326
|
const event = typeof body.event === "string" ? body.event : "";
|
|
15154
15327
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
15155
|
-
console.error(`${
|
|
15328
|
+
console.error(`${TAG46} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
15156
15329
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
15157
15330
|
}
|
|
15158
15331
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -15176,8 +15349,8 @@ var events_default = app21;
|
|
|
15176
15349
|
// server/routes/admin/files.ts
|
|
15177
15350
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync27 } from "fs";
|
|
15178
15351
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename, rmdir } from "fs/promises";
|
|
15179
|
-
import { realpathSync as
|
|
15180
|
-
import { randomUUID as
|
|
15352
|
+
import { realpathSync as realpathSync6 } from "fs";
|
|
15353
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
15181
15354
|
import { basename as basename9, dirname as dirname11, join as join30, relative as relative4, resolve as resolve23, sep as sep6 } from "path";
|
|
15182
15355
|
import { Readable as Readable2 } from "stream";
|
|
15183
15356
|
|
|
@@ -16542,8 +16715,8 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
16542
16715
|
const info = await stat4(destDir).catch(() => null);
|
|
16543
16716
|
if (!info || !info.isDirectory()) return { ok: false, status: 400, error: "Upload destination is not a directory" };
|
|
16544
16717
|
}
|
|
16545
|
-
const dataRootReal =
|
|
16546
|
-
const destDirReal =
|
|
16718
|
+
const dataRootReal = realpathSync6(DATA_ROOT);
|
|
16719
|
+
const destDirReal = realpathSync6(destDir);
|
|
16547
16720
|
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
|
|
16548
16721
|
console.error(`[data-upload] op=path-traversal-blocked uid=${uid} requested="${destRel}" resolved="${destDirReal}"`);
|
|
16549
16722
|
return { ok: false, status: 403, error: "Upload destination escapes DATA_ROOT" };
|
|
@@ -16569,7 +16742,7 @@ app22.post("/upload", requireAdminSession, async (c) => {
|
|
|
16569
16742
|
if (c.req.query("uploadId") !== void 0) {
|
|
16570
16743
|
return handleChunkUpload(c, accountId);
|
|
16571
16744
|
}
|
|
16572
|
-
const uid = `${Date.now()}-${
|
|
16745
|
+
const uid = `${Date.now()}-${randomUUID10().slice(0, 8)}`;
|
|
16573
16746
|
const declaredBytes = c.req.header("content-length") ?? "unknown";
|
|
16574
16747
|
const target = await resolveUploadTarget(c, accountId, uid);
|
|
16575
16748
|
if (!target.ok) return c.json({ error: target.error }, target.status);
|
|
@@ -19644,9 +19817,9 @@ app34.get("/", requireAdminSession, async (c) => {
|
|
|
19644
19817
|
var session_usage_default = app34;
|
|
19645
19818
|
|
|
19646
19819
|
// server/routes/admin/session-rc-spawn.ts
|
|
19647
|
-
import { randomUUID as
|
|
19820
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
19648
19821
|
var ACCOUNT_UUID_RE3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
19649
|
-
function resolveSpawnPlan(host, operatorDomains, body, mintId =
|
|
19822
|
+
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID11, adminUserId, authenticatedName, callerAccountId) {
|
|
19650
19823
|
const operator = isOperatorHost(host, operatorDomains);
|
|
19651
19824
|
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
19652
19825
|
const name = typeof body.name === "string" && body.name.length > 0 ? body.name : void 0;
|
|
@@ -19701,8 +19874,8 @@ app35.post("/", requireAdminSession, async (c) => {
|
|
|
19701
19874
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
19702
19875
|
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
19703
19876
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
19704
|
-
const plan = resolveSpawnPlan(host, getOperatorDomains(), body,
|
|
19705
|
-
const spawnReqId =
|
|
19877
|
+
const plan = resolveSpawnPlan(host, getOperatorDomains(), body, randomUUID11, adminUserId, authenticatedName, accountId);
|
|
19878
|
+
const spawnReqId = randomUUID11();
|
|
19706
19879
|
console.log(
|
|
19707
19880
|
`[chat-spawn] op=request spawnReqId=${spawnReqId} origin=${plan.origin} kind=${plan.kind} sessionId=${plan.kind === "new" ? "new" : plan.sessionId}`
|
|
19708
19881
|
);
|
|
@@ -19774,8 +19947,8 @@ app35.post("/", requireAdminSession, async (c) => {
|
|
|
19774
19947
|
var session_rc_spawn_default = app35;
|
|
19775
19948
|
|
|
19776
19949
|
// server/routes/admin/session-reseat.ts
|
|
19777
|
-
import { randomUUID as
|
|
19778
|
-
function resolveReseatPlan(body, mintId =
|
|
19950
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
19951
|
+
function resolveReseatPlan(body, mintId = randomUUID12, adminUserId, authenticatedName) {
|
|
19779
19952
|
const sessionId = mintId();
|
|
19780
19953
|
const key = `session:${sessionId}`;
|
|
19781
19954
|
const payload = {
|
|
@@ -19829,11 +20002,11 @@ app36.post("/", requireAdminSession, async (c) => {
|
|
|
19829
20002
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
19830
20003
|
const plan = resolveReseatPlan(
|
|
19831
20004
|
{ fromSessionId, model, ...permissionMode ? { permissionMode } : {}, ...effort ? { effort } : {} },
|
|
19832
|
-
|
|
20005
|
+
randomUUID12,
|
|
19833
20006
|
adminUserId,
|
|
19834
20007
|
authenticatedName
|
|
19835
20008
|
);
|
|
19836
|
-
const reseatReqId =
|
|
20009
|
+
const reseatReqId = randomUUID12();
|
|
19837
20010
|
console.log(`[chat-reseat] op=request reseatReqId=${reseatReqId} from=${fromSessionId} to-model=${model} to-mode=${permissionMode ?? "none"} to-effort=${effort ?? "none"} new=${plan.sessionId}`);
|
|
19838
20011
|
let res;
|
|
19839
20012
|
try {
|
|
@@ -20076,7 +20249,7 @@ app38.get("/", async (c) => {
|
|
|
20076
20249
|
var health_default2 = app38;
|
|
20077
20250
|
|
|
20078
20251
|
// server/routes/admin/linkedin-ingest.ts
|
|
20079
|
-
import { randomUUID as
|
|
20252
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
20080
20253
|
|
|
20081
20254
|
// app/lib/channel-pty-bridge/manager-client.ts
|
|
20082
20255
|
function managerBase2() {
|
|
@@ -20329,7 +20502,7 @@ app39.post("/", requireAdminSession, async (c) => {
|
|
|
20329
20502
|
);
|
|
20330
20503
|
const initialMessage = buildInitialMessage(envelope);
|
|
20331
20504
|
const spawnStart = Date.now();
|
|
20332
|
-
const sessionId =
|
|
20505
|
+
const sessionId = randomUUID13();
|
|
20333
20506
|
console.log(TAG27 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
20334
20507
|
const spawned = await managerRcSpawn({
|
|
20335
20508
|
sessionId,
|
|
@@ -21367,7 +21540,7 @@ app47.get("/", requireAdminSession, async (c) => {
|
|
|
21367
21540
|
var tasks_list_default = app47;
|
|
21368
21541
|
|
|
21369
21542
|
// server/routes/admin/task-timer-start.ts
|
|
21370
|
-
import { randomUUID as
|
|
21543
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
21371
21544
|
var TAG34 = "[task-timer]";
|
|
21372
21545
|
var app48 = new Hono();
|
|
21373
21546
|
app48.post("/", requireAdminSession, async (c) => {
|
|
@@ -21405,7 +21578,7 @@ app48.post("/", requireAdminSession, async (c) => {
|
|
|
21405
21578
|
console.log(`${TAG34} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
|
|
21406
21579
|
return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
|
|
21407
21580
|
}
|
|
21408
|
-
const entryId =
|
|
21581
|
+
const entryId = randomUUID14();
|
|
21409
21582
|
await session.run(
|
|
21410
21583
|
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
21411
21584
|
CREATE (te:TimeEntry {entryId: $entryId, taskId: $taskId, accountId: $accountId, startedAt: $now, endedAt: null})
|
|
@@ -21532,7 +21705,7 @@ app50.post("/", requireAdminSession, async (c) => {
|
|
|
21532
21705
|
var task_complete_default = app50;
|
|
21533
21706
|
|
|
21534
21707
|
// server/routes/admin/task-time-adjust.ts
|
|
21535
|
-
import { randomUUID as
|
|
21708
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
21536
21709
|
import neo4j6 from "neo4j-driver";
|
|
21537
21710
|
var TAG37 = "[task-time-adjust]";
|
|
21538
21711
|
var app51 = new Hono();
|
|
@@ -21557,7 +21730,7 @@ app51.post("/", requireAdminSession, async (c) => {
|
|
|
21557
21730
|
console.error(`${TAG37} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
|
|
21558
21731
|
return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
|
|
21559
21732
|
}
|
|
21560
|
-
const adjustmentId =
|
|
21733
|
+
const adjustmentId = randomUUID15();
|
|
21561
21734
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21562
21735
|
console.log(`${TAG37} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
|
|
21563
21736
|
const session = getSession();
|
|
@@ -21891,7 +22064,7 @@ app55.route("/request-magic-link", request_magic_link_default);
|
|
|
21891
22064
|
var access_default = app55;
|
|
21892
22065
|
|
|
21893
22066
|
// server/routes/sites.ts
|
|
21894
|
-
import { existsSync as existsSync31, readFileSync as readFileSync34, realpathSync as
|
|
22067
|
+
import { existsSync as existsSync31, readFileSync as readFileSync34, realpathSync as realpathSync7, statSync as statSync12 } from "fs";
|
|
21895
22068
|
import { resolve as resolve28 } from "path";
|
|
21896
22069
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
21897
22070
|
var MIME = {
|
|
@@ -21983,8 +22156,8 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
21983
22156
|
let realPath;
|
|
21984
22157
|
let realRoot;
|
|
21985
22158
|
try {
|
|
21986
|
-
realPath =
|
|
21987
|
-
realRoot =
|
|
22159
|
+
realPath = realpathSync7(filePath);
|
|
22160
|
+
realRoot = realpathSync7(rootDir);
|
|
21988
22161
|
} catch {
|
|
21989
22162
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
21990
22163
|
return c.text("Not found", 404);
|
|
@@ -22114,9 +22287,9 @@ var cachedAttempted = false;
|
|
|
22114
22287
|
function readBrandConfig() {
|
|
22115
22288
|
if (cachedAttempted) return cached2;
|
|
22116
22289
|
cachedAttempted = true;
|
|
22117
|
-
const
|
|
22118
|
-
if (!
|
|
22119
|
-
const brandPath = join35(
|
|
22290
|
+
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
22291
|
+
if (!platformRoot5) return null;
|
|
22292
|
+
const brandPath = join35(platformRoot5, "config", "brand.json");
|
|
22120
22293
|
if (!existsSync32(brandPath)) return null;
|
|
22121
22294
|
try {
|
|
22122
22295
|
cached2 = JSON.parse(readFileSync36(brandPath, "utf-8"));
|
|
@@ -24453,16 +24626,16 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24453
24626
|
* The public /api/chat route awaits this to return the reply on the same SSE
|
|
24454
24627
|
* response, preserving the pre-756 POST→single-blob browser contract. */
|
|
24455
24628
|
awaitReply(key, timeoutMs) {
|
|
24456
|
-
return new Promise((
|
|
24629
|
+
return new Promise((resolve37) => {
|
|
24457
24630
|
const timer2 = setTimeout(() => {
|
|
24458
24631
|
this.replyAwaiters.delete(key);
|
|
24459
|
-
|
|
24632
|
+
resolve37({ timeout: true });
|
|
24460
24633
|
}, timeoutMs);
|
|
24461
24634
|
if (timer2.unref) timer2.unref();
|
|
24462
24635
|
this.replyAwaiters.set(key, (r) => {
|
|
24463
24636
|
clearTimeout(timer2);
|
|
24464
24637
|
this.replyAwaiters.delete(key);
|
|
24465
|
-
|
|
24638
|
+
resolve37(r);
|
|
24466
24639
|
});
|
|
24467
24640
|
});
|
|
24468
24641
|
}
|
|
@@ -24473,11 +24646,11 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24473
24646
|
* terminal dialog stays answerable). */
|
|
24474
24647
|
awaitPermissionVerdict(p, timeoutMs) {
|
|
24475
24648
|
const k = _WebchatGateway.promptKey(p.key, p.requestId);
|
|
24476
|
-
return new Promise((
|
|
24649
|
+
return new Promise((resolve37) => {
|
|
24477
24650
|
this.pendingPrompts.get(k)?.resolve({ timeout: true });
|
|
24478
24651
|
const timer2 = setTimeout(() => {
|
|
24479
24652
|
this.pendingPrompts.delete(k);
|
|
24480
|
-
|
|
24653
|
+
resolve37({ timeout: true });
|
|
24481
24654
|
}, timeoutMs);
|
|
24482
24655
|
if (timer2.unref) timer2.unref();
|
|
24483
24656
|
this.pendingPrompts.set(k, {
|
|
@@ -24486,7 +24659,7 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24486
24659
|
resolve: (r) => {
|
|
24487
24660
|
clearTimeout(timer2);
|
|
24488
24661
|
this.pendingPrompts.delete(k);
|
|
24489
|
-
|
|
24662
|
+
resolve37(r);
|
|
24490
24663
|
}
|
|
24491
24664
|
});
|
|
24492
24665
|
console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
|
|
@@ -24817,27 +24990,6 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24817
24990
|
}
|
|
24818
24991
|
};
|
|
24819
24992
|
|
|
24820
|
-
// app/lib/webchat/gateway/public-spawn-request.ts
|
|
24821
|
-
function buildPublicWebchatSpawnRequest(input) {
|
|
24822
|
-
const { agentSlug, sliceToken, personId, visitorId, name } = input.public;
|
|
24823
|
-
return {
|
|
24824
|
-
senderId: input.key,
|
|
24825
|
-
role: "public",
|
|
24826
|
-
channel: "webchat",
|
|
24827
|
-
accountId: input.accountId,
|
|
24828
|
-
agentSlug,
|
|
24829
|
-
model: SONNET_MODEL,
|
|
24830
|
-
// sliceToken/personId are present only for a gated visitor; open-mode
|
|
24831
|
-
// public agents carry neither (mirrors the bridge's open-mode key).
|
|
24832
|
-
...sliceToken ? { sliceToken } : {},
|
|
24833
|
-
...personId ? { personId } : {},
|
|
24834
|
-
...visitorId ? { visitorId } : {},
|
|
24835
|
-
...input.previousContext ? { previousContext: input.previousContext } : {},
|
|
24836
|
-
name,
|
|
24837
|
-
webchatChannel: { key: input.key, gatewayUrl: input.gatewayUrl, serverPath: input.serverPath }
|
|
24838
|
-
};
|
|
24839
|
-
}
|
|
24840
|
-
|
|
24841
24993
|
// app/lib/channel-pty-bridge/follower.ts
|
|
24842
24994
|
function followerPendingMaxMs() {
|
|
24843
24995
|
return Number(process.env.CHANNEL_PTY_FOLLOWER_PENDING_MAX_MS ?? String(3e5));
|
|
@@ -24845,6 +24997,13 @@ function followerPendingMaxMs() {
|
|
|
24845
24997
|
function followerRetryMs() {
|
|
24846
24998
|
return Number(process.env.CHANNEL_PTY_FOLLOWER_RETRY_MS ?? String(1e3));
|
|
24847
24999
|
}
|
|
25000
|
+
function toolResultText(content) {
|
|
25001
|
+
if (typeof content === "string") return content;
|
|
25002
|
+
if (!Array.isArray(content)) return "";
|
|
25003
|
+
return content.map(
|
|
25004
|
+
(b) => b && typeof b === "object" && typeof b.text === "string" ? b.text : ""
|
|
25005
|
+
).join("");
|
|
25006
|
+
}
|
|
24848
25007
|
function startFollower(opts) {
|
|
24849
25008
|
const abort = new AbortController();
|
|
24850
25009
|
const { entry, tag } = opts;
|
|
@@ -24887,6 +25046,8 @@ function startFollower(opts) {
|
|
|
24887
25046
|
const decoder = new TextDecoder("utf8");
|
|
24888
25047
|
let buffered = "";
|
|
24889
25048
|
const fileDelivery = opts.fileDelivery ?? null;
|
|
25049
|
+
const captureVerdicts = typeof fileDelivery?.onFileToolResult === "function";
|
|
25050
|
+
const awaitingVerdict = /* @__PURE__ */ new Set();
|
|
24890
25051
|
let firedFileTools = [];
|
|
24891
25052
|
let suppressing = opts.suppressResumeReplay === true;
|
|
24892
25053
|
let discardedTurns = 0;
|
|
@@ -24920,6 +25081,28 @@ function startFollower(opts) {
|
|
|
24920
25081
|
continue;
|
|
24921
25082
|
}
|
|
24922
25083
|
if (event.type === "user") {
|
|
25084
|
+
if (captureVerdicts && awaitingVerdict.size > 0 && !suppressing) {
|
|
25085
|
+
const umsg = event.message;
|
|
25086
|
+
if (umsg && Array.isArray(umsg.content)) {
|
|
25087
|
+
for (const block of umsg.content) {
|
|
25088
|
+
if (block?.type !== "tool_result") continue;
|
|
25089
|
+
const id = block.tool_use_id;
|
|
25090
|
+
if (typeof id !== "string" || !awaitingVerdict.has(id)) continue;
|
|
25091
|
+
awaitingVerdict.delete(id);
|
|
25092
|
+
try {
|
|
25093
|
+
await fileDelivery.onFileToolResult({
|
|
25094
|
+
toolUseId: id,
|
|
25095
|
+
isError: block.is_error === true,
|
|
25096
|
+
text: toolResultText(block.content)
|
|
25097
|
+
});
|
|
25098
|
+
} catch (err) {
|
|
25099
|
+
console.error(
|
|
25100
|
+
`${tag} file-delivery-error sessionId=${sid} phase=tool-result message=${err instanceof Error ? err.message : String(err)}`
|
|
25101
|
+
);
|
|
25102
|
+
}
|
|
25103
|
+
}
|
|
25104
|
+
}
|
|
25105
|
+
}
|
|
24923
25106
|
entry.pendingTurnText = "";
|
|
24924
25107
|
firedFileTools = [];
|
|
24925
25108
|
continue;
|
|
@@ -24941,8 +25124,10 @@ function startFollower(opts) {
|
|
|
24941
25124
|
continue;
|
|
24942
25125
|
}
|
|
24943
25126
|
firedFileTools.push(block.name);
|
|
25127
|
+
const toolUseId = typeof block.id === "string" ? block.id : "";
|
|
25128
|
+
if (captureVerdicts && toolUseId) awaitingVerdict.add(toolUseId);
|
|
24944
25129
|
try {
|
|
24945
|
-
await fileDelivery.onFileToolUse({ toolName: block.name, input: block.input });
|
|
25130
|
+
await fileDelivery.onFileToolUse({ toolName: block.name, toolUseId, input: block.input });
|
|
24946
25131
|
} catch (err) {
|
|
24947
25132
|
console.error(
|
|
24948
25133
|
`${tag} file-delivery-error sessionId=${sid} tool=${block.name} message=${err instanceof Error ? err.message : String(err)}`
|
|
@@ -24964,9 +25149,10 @@ function startFollower(opts) {
|
|
|
24964
25149
|
if (flush.trim()) {
|
|
24965
25150
|
await fanOut(entry.subscribers, flush, opts.onError, tag);
|
|
24966
25151
|
}
|
|
24967
|
-
if (fileDelivery && firedFileTools.length > 0) {
|
|
25152
|
+
if (fileDelivery && (firedFileTools.length > 0 || captureVerdicts)) {
|
|
24968
25153
|
const fired = firedFileTools;
|
|
24969
25154
|
firedFileTools = [];
|
|
25155
|
+
awaitingVerdict.clear();
|
|
24970
25156
|
try {
|
|
24971
25157
|
fileDelivery.onTurnEnd(fired);
|
|
24972
25158
|
} catch (err) {
|
|
@@ -25004,28 +25190,55 @@ async function fanOut(subscribers, text, onError, tag) {
|
|
|
25004
25190
|
);
|
|
25005
25191
|
}
|
|
25006
25192
|
|
|
25193
|
+
// app/lib/webchat/file-delivery.ts
|
|
25194
|
+
import { realpathSync as realpathSync8 } from "fs";
|
|
25195
|
+
import { resolve as resolve32 } from "path";
|
|
25196
|
+
|
|
25007
25197
|
// app/lib/channel-pty-bridge/file-delivery.ts
|
|
25008
25198
|
var SEND_USER_FILE = "SendUserFile";
|
|
25009
25199
|
function makeFileDelivery(opts) {
|
|
25010
|
-
const { entry, tag, channel, sendFile } = opts;
|
|
25200
|
+
const { entry, tag, channel, sendFile, deferUntilVerdict = false } = opts;
|
|
25011
25201
|
let failedFiles = [];
|
|
25012
25202
|
let attempts = 0;
|
|
25013
|
-
|
|
25203
|
+
const pending = /* @__PURE__ */ new Map();
|
|
25204
|
+
function parseInput(input) {
|
|
25205
|
+
const i = input ?? {};
|
|
25206
|
+
return {
|
|
25207
|
+
// A non-array `files` yields zero files. This is the observed refused-call
|
|
25208
|
+
// shape: with the tool absent from the enabled set its schema is absent
|
|
25209
|
+
// from the request, so the model emits a JSON-encoded string. Never parse
|
|
25210
|
+
// it back — the harness refused the call.
|
|
25211
|
+
files: Array.isArray(i.files) ? i.files.filter((f) => typeof f === "string") : [],
|
|
25212
|
+
caption: typeof i.caption === "string" ? i.caption : void 0
|
|
25213
|
+
};
|
|
25214
|
+
}
|
|
25215
|
+
async function forward(call) {
|
|
25216
|
+
for (let i = 0; i < call.files.length; i++) {
|
|
25217
|
+
attempts++;
|
|
25218
|
+
const result = await sendFile(call.files[i], i === 0 ? call.caption : void 0);
|
|
25219
|
+
const name = call.files[i].split("/").pop() ?? call.files[i];
|
|
25220
|
+
console.error(`${tag} op=file-forward channel=${channel} file=${name} outcome=${result.ok ? "ok" : "fail"}`);
|
|
25221
|
+
if (!result.ok) failedFiles.push(call.files[i]);
|
|
25222
|
+
}
|
|
25223
|
+
}
|
|
25224
|
+
function unreconciledCall(reason, files, detail) {
|
|
25225
|
+
const d = detail ? ` detail="${detail.replace(/\s+/g, " ").slice(0, 120)}"` : "";
|
|
25226
|
+
console.error(
|
|
25227
|
+
`${tag} file-delivery-unreconciled sender=${entry.senderId} sessionId=${entry.sessionId.slice(0, 8)} tool=${SEND_USER_FILE} reason=${reason} files=${files}${d}`
|
|
25228
|
+
);
|
|
25229
|
+
}
|
|
25230
|
+
const handler = {
|
|
25014
25231
|
isFileDeliveryTool(toolName) {
|
|
25015
25232
|
return toolName === SEND_USER_FILE;
|
|
25016
25233
|
},
|
|
25017
25234
|
async onFileToolUse(use) {
|
|
25018
25235
|
if (use.toolName !== SEND_USER_FILE) return;
|
|
25019
|
-
const
|
|
25020
|
-
|
|
25021
|
-
|
|
25022
|
-
|
|
25023
|
-
attempts++;
|
|
25024
|
-
const result = await sendFile(files[i], i === 0 ? caption : void 0);
|
|
25025
|
-
const name = files[i].split("/").pop() ?? files[i];
|
|
25026
|
-
console.error(`${tag} op=file-forward channel=${channel} file=${name} outcome=${result.ok ? "ok" : "fail"}`);
|
|
25027
|
-
if (!result.ok) failedFiles.push(files[i]);
|
|
25236
|
+
const call = parseInput(use.input);
|
|
25237
|
+
if (deferUntilVerdict) {
|
|
25238
|
+
pending.set(use.toolUseId, call);
|
|
25239
|
+
return;
|
|
25028
25240
|
}
|
|
25241
|
+
await forward(call);
|
|
25029
25242
|
},
|
|
25030
25243
|
onTurnEnd(firedTools) {
|
|
25031
25244
|
const failed = failedFiles;
|
|
@@ -25038,6 +25251,11 @@ function makeFileDelivery(opts) {
|
|
|
25038
25251
|
`${tag} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${SEND_USER_FILE} file=${file}`
|
|
25039
25252
|
);
|
|
25040
25253
|
}
|
|
25254
|
+
if (deferUntilVerdict) {
|
|
25255
|
+
for (const call of pending.values()) unreconciledCall("no-verdict", call.files.length);
|
|
25256
|
+
pending.clear();
|
|
25257
|
+
return;
|
|
25258
|
+
}
|
|
25041
25259
|
if (firedTools.includes(SEND_USER_FILE) && tried === 0) {
|
|
25042
25260
|
console.error(
|
|
25043
25261
|
`${tag} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${SEND_USER_FILE}`
|
|
@@ -25045,13 +25263,123 @@ function makeFileDelivery(opts) {
|
|
|
25045
25263
|
}
|
|
25046
25264
|
}
|
|
25047
25265
|
};
|
|
25266
|
+
if (deferUntilVerdict) {
|
|
25267
|
+
handler.onFileToolResult = async (result) => {
|
|
25268
|
+
const call = pending.get(result.toolUseId);
|
|
25269
|
+
if (!call) return;
|
|
25270
|
+
pending.delete(result.toolUseId);
|
|
25271
|
+
if (result.isError) {
|
|
25272
|
+
unreconciledCall("harness-refused", call.files.length, result.text);
|
|
25273
|
+
return;
|
|
25274
|
+
}
|
|
25275
|
+
if (call.files.length === 0) {
|
|
25276
|
+
unreconciledCall("no-files", 0);
|
|
25277
|
+
return;
|
|
25278
|
+
}
|
|
25279
|
+
await forward(call);
|
|
25280
|
+
};
|
|
25281
|
+
}
|
|
25282
|
+
return handler;
|
|
25283
|
+
}
|
|
25284
|
+
|
|
25285
|
+
// app/lib/webchat/file-delivery.ts
|
|
25286
|
+
var TAG41 = "[webchat-adaptor]";
|
|
25287
|
+
function platformRoot2() {
|
|
25288
|
+
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
25289
|
+
}
|
|
25290
|
+
function makeWebchatSendFile(entry) {
|
|
25291
|
+
return async (filePath) => {
|
|
25292
|
+
if (!entry.accountId) {
|
|
25293
|
+
console.error(`${TAG41} file-delivery reject reason=no-account sender=${entry.senderId}`);
|
|
25294
|
+
return { ok: false, error: "no-account" };
|
|
25295
|
+
}
|
|
25296
|
+
const accountDir = resolve32(platformRoot2(), "..", "data/accounts", entry.accountId);
|
|
25297
|
+
try {
|
|
25298
|
+
const resolved = realpathSync8(filePath);
|
|
25299
|
+
const accountResolved = realpathSync8(accountDir);
|
|
25300
|
+
if (!resolved.startsWith(accountResolved + "/")) {
|
|
25301
|
+
console.error(`${TAG41} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
|
|
25302
|
+
return { ok: false, error: "outside-account" };
|
|
25303
|
+
}
|
|
25304
|
+
return { ok: true };
|
|
25305
|
+
} catch (err) {
|
|
25306
|
+
const code = err.code;
|
|
25307
|
+
console.error(
|
|
25308
|
+
`${TAG41} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
|
|
25309
|
+
);
|
|
25310
|
+
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
25311
|
+
}
|
|
25312
|
+
};
|
|
25313
|
+
}
|
|
25314
|
+
function makeWebchatFileDelivery(entry) {
|
|
25315
|
+
return makeFileDelivery({
|
|
25316
|
+
entry,
|
|
25317
|
+
tag: TAG41,
|
|
25318
|
+
channel: "webchat",
|
|
25319
|
+
sendFile: makeWebchatSendFile(entry),
|
|
25320
|
+
deferUntilVerdict: true
|
|
25321
|
+
});
|
|
25322
|
+
}
|
|
25323
|
+
|
|
25324
|
+
// app/lib/webchat/gateway/native-file-follower.ts
|
|
25325
|
+
function startWebchatNativeFileFollower(input) {
|
|
25326
|
+
const entry = {
|
|
25327
|
+
sessionId: input.sessionId,
|
|
25328
|
+
role: "admin",
|
|
25329
|
+
channel: "webchat",
|
|
25330
|
+
accountId: input.accountId,
|
|
25331
|
+
senderId: input.key,
|
|
25332
|
+
agentSlug: "admin",
|
|
25333
|
+
lastInboundAt: Date.now(),
|
|
25334
|
+
writeChain: Promise.resolve(),
|
|
25335
|
+
subscribers: /* @__PURE__ */ new Set(),
|
|
25336
|
+
pendingTurnText: "",
|
|
25337
|
+
followerAbort: null,
|
|
25338
|
+
followerRunning: false,
|
|
25339
|
+
sliceToken: "",
|
|
25340
|
+
personId: null,
|
|
25341
|
+
name: null,
|
|
25342
|
+
// Webchat renders from the transcript; there is no separate reply target.
|
|
25343
|
+
replyTarget: null
|
|
25344
|
+
};
|
|
25345
|
+
return startFollower({
|
|
25346
|
+
entry,
|
|
25347
|
+
tag: "[webchat-adaptor]",
|
|
25348
|
+
fileDelivery: makeWebchatFileDelivery(entry),
|
|
25349
|
+
// A resumed session's JSONL already holds prior SendUserFile tool_uses;
|
|
25350
|
+
// suppress replay so historical calls are not re-reconciled on attach.
|
|
25351
|
+
suppressResumeReplay: true,
|
|
25352
|
+
onClose: input.onClose ?? (() => {
|
|
25353
|
+
})
|
|
25354
|
+
});
|
|
25355
|
+
}
|
|
25356
|
+
|
|
25357
|
+
// app/lib/webchat/gateway/public-spawn-request.ts
|
|
25358
|
+
function buildPublicWebchatSpawnRequest(input) {
|
|
25359
|
+
const { agentSlug, sliceToken, personId, visitorId, name } = input.public;
|
|
25360
|
+
return {
|
|
25361
|
+
senderId: input.key,
|
|
25362
|
+
role: "public",
|
|
25363
|
+
channel: "webchat",
|
|
25364
|
+
accountId: input.accountId,
|
|
25365
|
+
agentSlug,
|
|
25366
|
+
model: SONNET_MODEL,
|
|
25367
|
+
// sliceToken/personId are present only for a gated visitor; open-mode
|
|
25368
|
+
// public agents carry neither (mirrors the bridge's open-mode key).
|
|
25369
|
+
...sliceToken ? { sliceToken } : {},
|
|
25370
|
+
...personId ? { personId } : {},
|
|
25371
|
+
...visitorId ? { visitorId } : {},
|
|
25372
|
+
...input.previousContext ? { previousContext: input.previousContext } : {},
|
|
25373
|
+
name,
|
|
25374
|
+
webchatChannel: { key: input.key, gatewayUrl: input.gatewayUrl, serverPath: input.serverPath }
|
|
25375
|
+
};
|
|
25048
25376
|
}
|
|
25049
25377
|
|
|
25050
25378
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
25051
|
-
var
|
|
25379
|
+
var TAG42 = "[whatsapp-adaptor]";
|
|
25052
25380
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
25053
25381
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
25054
|
-
function
|
|
25382
|
+
function platformRoot3() {
|
|
25055
25383
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
25056
25384
|
}
|
|
25057
25385
|
function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
@@ -25062,11 +25390,11 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
25062
25390
|
caption,
|
|
25063
25391
|
accountId: entry.accountId,
|
|
25064
25392
|
maxyAccountId,
|
|
25065
|
-
platformRoot:
|
|
25393
|
+
platformRoot: platformRoot3()
|
|
25066
25394
|
});
|
|
25067
25395
|
if (result.ok) return { ok: true };
|
|
25068
25396
|
console.error(
|
|
25069
|
-
`${
|
|
25397
|
+
`${TAG42} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
25070
25398
|
);
|
|
25071
25399
|
return { ok: false, error: result.error };
|
|
25072
25400
|
};
|
|
@@ -25074,7 +25402,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
25074
25402
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
25075
25403
|
const shared = makeFileDelivery({
|
|
25076
25404
|
entry,
|
|
25077
|
-
tag:
|
|
25405
|
+
tag: TAG42,
|
|
25078
25406
|
channel: "whatsapp",
|
|
25079
25407
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
25080
25408
|
});
|
|
@@ -25109,7 +25437,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
25109
25437
|
if (!delivered) {
|
|
25110
25438
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
25111
25439
|
console.error(
|
|
25112
|
-
`${
|
|
25440
|
+
`${TAG42} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
25113
25441
|
);
|
|
25114
25442
|
}
|
|
25115
25443
|
}
|
|
@@ -25500,35 +25828,35 @@ function buildTelegramSpawnRequest(input) {
|
|
|
25500
25828
|
}
|
|
25501
25829
|
|
|
25502
25830
|
// app/lib/telegram/outbound/send-document.ts
|
|
25503
|
-
import { realpathSync as
|
|
25831
|
+
import { realpathSync as realpathSync9 } from "fs";
|
|
25504
25832
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
25505
|
-
import { resolve as
|
|
25506
|
-
var
|
|
25833
|
+
import { resolve as resolve33, basename as basename11 } from "path";
|
|
25834
|
+
var TAG43 = "[telegram:outbound]";
|
|
25507
25835
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
25508
25836
|
async function sendTelegramDocument(input) {
|
|
25509
|
-
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot:
|
|
25837
|
+
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
25510
25838
|
if (!botToken || !filePath) {
|
|
25511
25839
|
return { ok: false, status: 400, error: "Missing required fields: botToken, filePath" };
|
|
25512
25840
|
}
|
|
25513
|
-
if (!maxyAccountId || !
|
|
25841
|
+
if (!maxyAccountId || !platformRoot5) {
|
|
25514
25842
|
return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
|
|
25515
25843
|
}
|
|
25516
|
-
const accountDir =
|
|
25844
|
+
const accountDir = resolve33(platformRoot5, "..", "data/accounts", maxyAccountId);
|
|
25517
25845
|
let resolvedPath;
|
|
25518
25846
|
try {
|
|
25519
|
-
resolvedPath =
|
|
25520
|
-
const accountResolved =
|
|
25847
|
+
resolvedPath = realpathSync9(filePath);
|
|
25848
|
+
const accountResolved = realpathSync9(accountDir);
|
|
25521
25849
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
25522
|
-
console.error(`${
|
|
25850
|
+
console.error(`${TAG43} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
25523
25851
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
25524
25852
|
}
|
|
25525
25853
|
} catch (err) {
|
|
25526
25854
|
const code = err.code;
|
|
25527
25855
|
if (code === "ENOENT") {
|
|
25528
|
-
console.error(`${
|
|
25856
|
+
console.error(`${TAG43} document ENOENT path=${filePath}`);
|
|
25529
25857
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
25530
25858
|
}
|
|
25531
|
-
console.error(`${
|
|
25859
|
+
console.error(`${TAG43} document path error: ${String(err)}`);
|
|
25532
25860
|
return { ok: false, status: 500, error: String(err) };
|
|
25533
25861
|
}
|
|
25534
25862
|
const fileStat = await stat7(resolvedPath);
|
|
@@ -25561,14 +25889,14 @@ async function sendTelegramDocument(input) {
|
|
|
25561
25889
|
error = e instanceof Error ? e.message : String(e);
|
|
25562
25890
|
}
|
|
25563
25891
|
console.error(
|
|
25564
|
-
`${
|
|
25892
|
+
`${TAG43} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
25565
25893
|
);
|
|
25566
25894
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
25567
25895
|
}
|
|
25568
25896
|
|
|
25569
25897
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
25570
|
-
var
|
|
25571
|
-
function
|
|
25898
|
+
var TAG44 = "[telegram:outbound]";
|
|
25899
|
+
function platformRoot4() {
|
|
25572
25900
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
25573
25901
|
}
|
|
25574
25902
|
function makeTelegramSendFile(entry) {
|
|
@@ -25579,11 +25907,11 @@ function makeTelegramSendFile(entry) {
|
|
|
25579
25907
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
25580
25908
|
}
|
|
25581
25909
|
if (!botToken) {
|
|
25582
|
-
console.error(`${
|
|
25910
|
+
console.error(`${TAG44} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
25583
25911
|
return { ok: false, error: "no-bot-token" };
|
|
25584
25912
|
}
|
|
25585
25913
|
if (entry.replyTarget == null) {
|
|
25586
|
-
console.error(`${
|
|
25914
|
+
console.error(`${TAG44} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
25587
25915
|
return { ok: false, error: "no-reply-target" };
|
|
25588
25916
|
}
|
|
25589
25917
|
const result = await sendTelegramDocument({
|
|
@@ -25592,7 +25920,7 @@ function makeTelegramSendFile(entry) {
|
|
|
25592
25920
|
filePath,
|
|
25593
25921
|
caption,
|
|
25594
25922
|
maxyAccountId: entry.accountId,
|
|
25595
|
-
platformRoot:
|
|
25923
|
+
platformRoot: platformRoot4()
|
|
25596
25924
|
});
|
|
25597
25925
|
return result.ok ? { ok: true } : { ok: false, error: result.error };
|
|
25598
25926
|
};
|
|
@@ -25600,7 +25928,7 @@ function makeTelegramSendFile(entry) {
|
|
|
25600
25928
|
function makeTelegramFileDelivery(entry) {
|
|
25601
25929
|
return makeFileDelivery({
|
|
25602
25930
|
entry,
|
|
25603
|
-
tag:
|
|
25931
|
+
tag: TAG44,
|
|
25604
25932
|
channel: "telegram",
|
|
25605
25933
|
sendFile: makeTelegramSendFile(entry)
|
|
25606
25934
|
});
|
|
@@ -25640,17 +25968,17 @@ function startTelegramNativeFileFollower(input) {
|
|
|
25640
25968
|
}
|
|
25641
25969
|
|
|
25642
25970
|
// server/telegram-descriptor.ts
|
|
25643
|
-
import { resolve as
|
|
25971
|
+
import { resolve as resolve34, join as join37 } from "path";
|
|
25644
25972
|
function telegramGatewayUrl() {
|
|
25645
25973
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
25646
25974
|
}
|
|
25647
25975
|
function telegramServerPath() {
|
|
25648
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ??
|
|
25976
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve34(process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
25649
25977
|
}
|
|
25650
25978
|
|
|
25651
25979
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
25652
|
-
import { randomUUID as
|
|
25653
|
-
var
|
|
25980
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
25981
|
+
var TAG45 = "[public-session-review]";
|
|
25654
25982
|
var CONSUMED_CAP = 500;
|
|
25655
25983
|
var consumed = /* @__PURE__ */ new Set();
|
|
25656
25984
|
function consumeOnce(sessionId) {
|
|
@@ -25677,7 +26005,7 @@ async function fetchJsonl(sessionId) {
|
|
|
25677
26005
|
return await res.text();
|
|
25678
26006
|
} catch (err) {
|
|
25679
26007
|
console.error(
|
|
25680
|
-
`${
|
|
26008
|
+
`${TAG45} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
25681
26009
|
);
|
|
25682
26010
|
return null;
|
|
25683
26011
|
}
|
|
@@ -25701,7 +26029,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
25701
26029
|
const res = await fetch(url);
|
|
25702
26030
|
if (!res.ok) {
|
|
25703
26031
|
console.error(
|
|
25704
|
-
`${
|
|
26032
|
+
`${TAG45} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
25705
26033
|
);
|
|
25706
26034
|
return [];
|
|
25707
26035
|
}
|
|
@@ -25709,7 +26037,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
25709
26037
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
25710
26038
|
} catch (err) {
|
|
25711
26039
|
console.error(
|
|
25712
|
-
`${
|
|
26040
|
+
`${TAG45} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
25713
26041
|
);
|
|
25714
26042
|
return [];
|
|
25715
26043
|
}
|
|
@@ -25737,8 +26065,8 @@ function composeInitialMessage(input) {
|
|
|
25737
26065
|
].join("\n");
|
|
25738
26066
|
}
|
|
25739
26067
|
async function dispatchReviewer(input, initialMessage) {
|
|
25740
|
-
const sessionId =
|
|
25741
|
-
console.log(`${
|
|
26068
|
+
const sessionId = randomUUID16();
|
|
26069
|
+
console.log(`${TAG45} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
25742
26070
|
const spawned = await managerRcSpawn({
|
|
25743
26071
|
sessionId,
|
|
25744
26072
|
initialMessage,
|
|
@@ -25758,21 +26086,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
25758
26086
|
const dispatchedAt = Date.now();
|
|
25759
26087
|
if (consumed.has(input.sessionId)) {
|
|
25760
26088
|
console.log(
|
|
25761
|
-
`${
|
|
26089
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
25762
26090
|
);
|
|
25763
26091
|
return;
|
|
25764
26092
|
}
|
|
25765
26093
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
25766
26094
|
if (!jsonl) {
|
|
25767
26095
|
console.log(
|
|
25768
|
-
`${
|
|
26096
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
25769
26097
|
);
|
|
25770
26098
|
return;
|
|
25771
26099
|
}
|
|
25772
26100
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
25773
26101
|
if (operatorTurns === 0) {
|
|
25774
26102
|
console.log(
|
|
25775
|
-
`${
|
|
26103
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
25776
26104
|
);
|
|
25777
26105
|
return;
|
|
25778
26106
|
}
|
|
@@ -25786,19 +26114,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
25786
26114
|
});
|
|
25787
26115
|
if (!consumeOnce(input.sessionId)) {
|
|
25788
26116
|
console.log(
|
|
25789
|
-
`${
|
|
26117
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
25790
26118
|
);
|
|
25791
26119
|
return;
|
|
25792
26120
|
}
|
|
25793
26121
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
25794
26122
|
if (!dispatched.ok) {
|
|
25795
26123
|
console.error(
|
|
25796
|
-
`${
|
|
26124
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
25797
26125
|
);
|
|
25798
26126
|
return;
|
|
25799
26127
|
}
|
|
25800
26128
|
console.log(
|
|
25801
|
-
`${
|
|
26129
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
25802
26130
|
);
|
|
25803
26131
|
}
|
|
25804
26132
|
|
|
@@ -25908,7 +26236,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
25908
26236
|
// ../lib/entitlement/src/index.ts
|
|
25909
26237
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
25910
26238
|
import { existsSync as existsSync35, readFileSync as readFileSync37, statSync as statSync13 } from "fs";
|
|
25911
|
-
import { resolve as
|
|
26239
|
+
import { resolve as resolve35 } from "path";
|
|
25912
26240
|
|
|
25913
26241
|
// ../lib/entitlement/src/canonicalize.ts
|
|
25914
26242
|
function canonicalize(value) {
|
|
@@ -25943,7 +26271,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
25943
26271
|
var GRACE_DAYS = 7;
|
|
25944
26272
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
25945
26273
|
function pubkeyPath(brand) {
|
|
25946
|
-
return
|
|
26274
|
+
return resolve35(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
25947
26275
|
}
|
|
25948
26276
|
var memo = null;
|
|
25949
26277
|
function memoKey(mtimeMs, account) {
|
|
@@ -25955,7 +26283,7 @@ function resolveEntitlement(brand, account) {
|
|
|
25955
26283
|
if (brand.commercialMode !== true) {
|
|
25956
26284
|
return logResolved(implicitTrust(account), null);
|
|
25957
26285
|
}
|
|
25958
|
-
const entitlementPath =
|
|
26286
|
+
const entitlementPath = resolve35(brand.configDir, "entitlement.json");
|
|
25959
26287
|
if (!existsSync35(entitlementPath)) {
|
|
25960
26288
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
25961
26289
|
}
|
|
@@ -26215,6 +26543,7 @@ function isPublicHost(host) {
|
|
|
26215
26543
|
}
|
|
26216
26544
|
var app62 = new Hono();
|
|
26217
26545
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
26546
|
+
var webchatFileFollowers = /* @__PURE__ */ new Map();
|
|
26218
26547
|
async function fetchAccountStandingRules(accountId) {
|
|
26219
26548
|
const session = getSession();
|
|
26220
26549
|
try {
|
|
@@ -26252,7 +26581,7 @@ async function recordPassiveDispatch(input) {
|
|
|
26252
26581
|
var waGateway = new WaGateway({
|
|
26253
26582
|
fetchStandingRules: fetchAccountStandingRules,
|
|
26254
26583
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
26255
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
26584
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve36(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
26256
26585
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
26257
26586
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
26258
26587
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -26267,7 +26596,7 @@ var waGateway = new WaGateway({
|
|
|
26267
26596
|
caption,
|
|
26268
26597
|
accountId,
|
|
26269
26598
|
maxyAccountId,
|
|
26270
|
-
platformRoot:
|
|
26599
|
+
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, ".."))
|
|
26271
26600
|
});
|
|
26272
26601
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
26273
26602
|
},
|
|
@@ -26425,6 +26754,20 @@ var webchatGateway = new WebchatGateway({
|
|
|
26425
26754
|
console.error(`[webchat:inbound] op=spawn-failed key=${key} error=${result.error} status=${result.status}`);
|
|
26426
26755
|
return;
|
|
26427
26756
|
}
|
|
26757
|
+
const priorWebchatFollower = webchatFileFollowers.get(key);
|
|
26758
|
+
if (priorWebchatFollower) priorWebchatFollower.abort();
|
|
26759
|
+
let wac;
|
|
26760
|
+
wac = startWebchatNativeFileFollower({
|
|
26761
|
+
sessionId: result.sessionId,
|
|
26762
|
+
key,
|
|
26763
|
+
// The session's own resolved account (house or sub-account) — the
|
|
26764
|
+
// file-path validation scope, exactly as passed to the spawn above.
|
|
26765
|
+
accountId,
|
|
26766
|
+
onClose: () => {
|
|
26767
|
+
if (webchatFileFollowers.get(key) === wac) webchatFileFollowers.delete(key);
|
|
26768
|
+
}
|
|
26769
|
+
});
|
|
26770
|
+
webchatFileFollowers.set(key, wac);
|
|
26428
26771
|
return { sessionId: result.sessionId };
|
|
26429
26772
|
},
|
|
26430
26773
|
// Task-962 — the recovery pass asks the manager to respawn a wedged already-
|
|
@@ -26886,8 +27229,8 @@ app62.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
26886
27229
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
26887
27230
|
return c.text("Not found", 404);
|
|
26888
27231
|
}
|
|
26889
|
-
const filePath =
|
|
26890
|
-
const expectedDir =
|
|
27232
|
+
const filePath = resolve36(account.accountDir, "agents", slug, "assets", filename);
|
|
27233
|
+
const expectedDir = resolve36(account.accountDir, "agents", slug, "assets");
|
|
26891
27234
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
26892
27235
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
26893
27236
|
return c.text("Forbidden", 403);
|
|
@@ -26916,8 +27259,8 @@ app62.get("/generated/:filename", (c) => {
|
|
|
26916
27259
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
26917
27260
|
return c.text("Not found", 404);
|
|
26918
27261
|
}
|
|
26919
|
-
const filePath =
|
|
26920
|
-
const expectedDir =
|
|
27262
|
+
const filePath = resolve36(account.accountDir, "generated", filename);
|
|
27263
|
+
const expectedDir = resolve36(account.accountDir, "generated");
|
|
26921
27264
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
26922
27265
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
26923
27266
|
return c.text("Forbidden", 403);
|
|
@@ -26971,11 +27314,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
26971
27314
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
26972
27315
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
26973
27316
|
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
26974
|
-
(p) => existsSync36(
|
|
27317
|
+
(p) => existsSync36(resolve36(process.cwd(), "public", p.replace(/^\//, "")))
|
|
26975
27318
|
);
|
|
26976
27319
|
var SW_SOURCE = (() => {
|
|
26977
27320
|
try {
|
|
26978
|
-
return readFileSync38(
|
|
27321
|
+
return readFileSync38(resolve36(process.cwd(), "public", "sw.js"), "utf-8");
|
|
26979
27322
|
} catch {
|
|
26980
27323
|
return null;
|
|
26981
27324
|
}
|
|
@@ -27026,7 +27369,7 @@ var clientErrorReporterScript = `<script>
|
|
|
27026
27369
|
function cachedHtml(file) {
|
|
27027
27370
|
let html = htmlCache.get(file);
|
|
27028
27371
|
if (!html) {
|
|
27029
|
-
html = readFileSync38(
|
|
27372
|
+
html = readFileSync38(resolve36(process.cwd(), "public", file), "utf-8");
|
|
27030
27373
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
27031
27374
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
27032
27375
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -27144,7 +27487,7 @@ app62.use("/vnc-popout.html", logViewerFetch);
|
|
|
27144
27487
|
app62.get("/vnc-popout.html", (c) => {
|
|
27145
27488
|
let html = htmlCache.get("vnc-popout.html");
|
|
27146
27489
|
if (!html) {
|
|
27147
|
-
html = readFileSync38(
|
|
27490
|
+
html = readFileSync38(resolve36(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
27148
27491
|
const name = escapeHtml(BRAND.productName);
|
|
27149
27492
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
27150
27493
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -27277,7 +27620,7 @@ var httpServer = serve({ fetch: app62.fetch, port, hostname });
|
|
|
27277
27620
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
27278
27621
|
{
|
|
27279
27622
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27280
|
-
const reconcileScript =
|
|
27623
|
+
const reconcileScript = resolve36(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
27281
27624
|
const RECONCILE_INTERVAL_MS = 12e4;
|
|
27282
27625
|
const runReconcile = () => {
|
|
27283
27626
|
if (!existsSync36(reconcileScript)) return;
|
|
@@ -27299,7 +27642,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27299
27642
|
}
|
|
27300
27643
|
{
|
|
27301
27644
|
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27302
|
-
const outlookScript =
|
|
27645
|
+
const outlookScript = resolve36(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
27303
27646
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
27304
27647
|
const runOutlookComplete = () => {
|
|
27305
27648
|
if (!existsSync36(outlookScript)) return;
|
|
@@ -27321,7 +27664,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27321
27664
|
}
|
|
27322
27665
|
{
|
|
27323
27666
|
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27324
|
-
const strandedAccountsDir =
|
|
27667
|
+
const strandedAccountsDir = resolve36(auditRoot, "..", "data/accounts");
|
|
27325
27668
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
27326
27669
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
27327
27670
|
const STRANDED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -27331,7 +27674,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27331
27674
|
const now = Date.now();
|
|
27332
27675
|
for (const name of readdirSync21(strandedAccountsDir)) {
|
|
27333
27676
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
27334
|
-
const pendingPath2 =
|
|
27677
|
+
const pendingPath2 = resolve36(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
27335
27678
|
if (!existsSync36(pendingPath2)) continue;
|
|
27336
27679
|
const ageMs = now - statSync14(pendingPath2).mtimeMs;
|
|
27337
27680
|
if (ageMs > STRANDED_AGE_MS) {
|
|
@@ -27359,10 +27702,19 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27359
27702
|
auditFirst.unref();
|
|
27360
27703
|
const auditLoop = setInterval(runStorageAuditSafe, STORAGE_AUDIT_INTERVAL_MS);
|
|
27361
27704
|
auditLoop.unref();
|
|
27705
|
+
const runPagesAuditSafe = () => {
|
|
27706
|
+
runPagesAudit(auditPlatformRoot).catch(
|
|
27707
|
+
(err) => console.error(`[pages-audit] error="${err.message}"`)
|
|
27708
|
+
);
|
|
27709
|
+
};
|
|
27710
|
+
const pagesAuditFirst = setTimeout(runPagesAuditSafe, 35e3);
|
|
27711
|
+
pagesAuditFirst.unref();
|
|
27712
|
+
const pagesAuditLoop = setInterval(runPagesAuditSafe, STORAGE_AUDIT_INTERVAL_MS);
|
|
27713
|
+
pagesAuditLoop.unref();
|
|
27362
27714
|
}
|
|
27363
27715
|
{
|
|
27364
27716
|
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27365
|
-
const publishScript =
|
|
27717
|
+
const publishScript = resolve36(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
27366
27718
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
27367
27719
|
const currentAccount = () => {
|
|
27368
27720
|
try {
|
|
@@ -27391,7 +27743,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27391
27743
|
}
|
|
27392
27744
|
};
|
|
27393
27745
|
const auditSnapshotAge = (account) => {
|
|
27394
|
-
const availPath =
|
|
27746
|
+
const availPath = resolve36(account.accountDir, "calendar-availability.json");
|
|
27395
27747
|
let hasBookingSite = false;
|
|
27396
27748
|
try {
|
|
27397
27749
|
if (existsSync36(availPath)) {
|
|
@@ -27401,7 +27753,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27401
27753
|
} catch {
|
|
27402
27754
|
}
|
|
27403
27755
|
if (!hasBookingSite) return;
|
|
27404
|
-
const statePath =
|
|
27756
|
+
const statePath = resolve36(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
27405
27757
|
let lastSuccessAt = null;
|
|
27406
27758
|
if (existsSync36(statePath)) {
|
|
27407
27759
|
try {
|
|
@@ -27430,7 +27782,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27430
27782
|
startTimeEntryCensus(() => getSession());
|
|
27431
27783
|
{
|
|
27432
27784
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27433
|
-
const auditScript =
|
|
27785
|
+
const auditScript = resolve36(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
27434
27786
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
27435
27787
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
27436
27788
|
const runConnectorAudit = () => {
|
|
@@ -27699,7 +28051,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
27699
28051
|
}
|
|
27700
28052
|
init({
|
|
27701
28053
|
configDir: configDirForWhatsApp,
|
|
27702
|
-
platformRoot:
|
|
28054
|
+
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..")),
|
|
27703
28055
|
accountConfig: bootAccountConfig,
|
|
27704
28056
|
onMessage: async (msg) => {
|
|
27705
28057
|
if (msg.isOwnerMirror) {
|