@rubytech/create-maxy-code 0.1.461 → 0.1.463
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 +23 -12
- 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/internals.md +1 -1
- 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/lib/message.d.ts +1 -6
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.js +9 -17
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/recipients.d.ts +56 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/recipients.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/recipients.js +40 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/recipients.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js +1 -3
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.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 +97 -18
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js +1 -3
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js +3 -18
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.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/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +6 -32
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +10 -30
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js +24 -21
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts +27 -18
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +31 -27
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -1
- 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/platform/services/telegram-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/server.js +0 -4
- package/payload/platform/services/telegram-channel/dist/server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +0 -4
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +0 -4
- package/payload/platform/services/whatsapp-channel/dist/server.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-DYT5H81o.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-gm2eP4r6.js} +1 -1
- package/payload/server/public/assets/{page-DiQhU6lD.js → page-8AB3jUa_.js} +1 -1
- package/payload/server/public/assets/page-BoPorLg-.js +32 -0
- package/payload/server/public/assets/{public-Cu_eALgY.js → public-DqJk6qgW.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 +596 -235
- 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
|
|
|
@@ -2187,6 +2188,7 @@ import {
|
|
|
2187
2188
|
} from "@whiskeysockets/baileys";
|
|
2188
2189
|
import { createRequire } from "module";
|
|
2189
2190
|
var TAG2 = "[whatsapp:session]";
|
|
2191
|
+
var WIRE_TAG = "[whatsapp:wire]";
|
|
2190
2192
|
var baileysPkgVersion = (() => {
|
|
2191
2193
|
try {
|
|
2192
2194
|
const req = createRequire(import.meta.url);
|
|
@@ -2248,7 +2250,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
2248
2250
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
2249
2251
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
2250
2252
|
const timer2 = new Promise(
|
|
2251
|
-
(
|
|
2253
|
+
(resolve37) => setTimeout(() => resolve37("timeout"), timeoutMs)
|
|
2252
2254
|
);
|
|
2253
2255
|
const result = await Promise.race([
|
|
2254
2256
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -2407,15 +2409,21 @@ async function createWaSocket(opts) {
|
|
|
2407
2409
|
sock.ws.on("error", (err) => {
|
|
2408
2410
|
console.error(`${TAG2} WebSocket error: ${String(err)}`);
|
|
2409
2411
|
});
|
|
2412
|
+
sock.ws.on("CB:message", (node) => {
|
|
2413
|
+
const attrs = node?.attrs ?? {};
|
|
2414
|
+
console.error(
|
|
2415
|
+
`${WIRE_TAG} op=stanza msgId=${attrs.id ?? "none"} from=${attrs.from ?? "none"} type=${attrs.type ?? "none"} offline=${attrs.offline ?? "none"} account=${acct}`
|
|
2416
|
+
);
|
|
2417
|
+
});
|
|
2410
2418
|
}
|
|
2411
2419
|
return sock;
|
|
2412
2420
|
}
|
|
2413
2421
|
async function waitForConnection(sock) {
|
|
2414
|
-
return new Promise((
|
|
2422
|
+
return new Promise((resolve37, reject) => {
|
|
2415
2423
|
const handler = (update) => {
|
|
2416
2424
|
if (update.connection === "open") {
|
|
2417
2425
|
sock.ev.off("connection.update", handler);
|
|
2418
|
-
|
|
2426
|
+
resolve37();
|
|
2419
2427
|
}
|
|
2420
2428
|
if (update.connection === "close") {
|
|
2421
2429
|
sock.ev.off("connection.update", handler);
|
|
@@ -2520,7 +2528,7 @@ import { inspect as inspect2 } from "util";
|
|
|
2520
2528
|
|
|
2521
2529
|
// app/lib/whatsapp/with-timeout.ts
|
|
2522
2530
|
function withTimeout(label, promise, timeoutMs) {
|
|
2523
|
-
return new Promise((
|
|
2531
|
+
return new Promise((resolve37, reject) => {
|
|
2524
2532
|
const timer2 = setTimeout(() => {
|
|
2525
2533
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2526
2534
|
}, timeoutMs);
|
|
@@ -2528,7 +2536,7 @@ function withTimeout(label, promise, timeoutMs) {
|
|
|
2528
2536
|
promise.then(
|
|
2529
2537
|
(value) => {
|
|
2530
2538
|
clearTimeout(timer2);
|
|
2531
|
-
|
|
2539
|
+
resolve37(value);
|
|
2532
2540
|
},
|
|
2533
2541
|
(err) => {
|
|
2534
2542
|
clearTimeout(timer2);
|
|
@@ -3779,8 +3787,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
3779
3787
|
const { givenName, familyName } = splitName(input.pushName);
|
|
3780
3788
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
3781
3789
|
let release;
|
|
3782
|
-
const mine = new Promise((
|
|
3783
|
-
release =
|
|
3790
|
+
const mine = new Promise((resolve37) => {
|
|
3791
|
+
release = resolve37;
|
|
3784
3792
|
});
|
|
3785
3793
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
3786
3794
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -5270,14 +5278,6 @@ async function registerLoginSocket(accountId, sock, authDir) {
|
|
|
5270
5278
|
throw err;
|
|
5271
5279
|
}
|
|
5272
5280
|
await stopConnection(accountId);
|
|
5273
|
-
const selfId = readSelfId(authDir);
|
|
5274
|
-
const rawLidMapping = sock.signalRepository?.lidMapping ?? null;
|
|
5275
|
-
const lidMapping = withSelfLidShortcut(rawLidMapping, selfId.lid, selfId.jid);
|
|
5276
|
-
if (selfId.lid) {
|
|
5277
|
-
console.error(`[whatsapp:lid] resolved self-lid accountId=${accountId} selfLid=${selfId.lid} source=creds`);
|
|
5278
|
-
} else {
|
|
5279
|
-
console.error(`[whatsapp:lid] FAIL self-lid-resolution accountId=${accountId} reason=creds-missing-lid`);
|
|
5280
|
-
}
|
|
5281
5281
|
const conn = {
|
|
5282
5282
|
accountId,
|
|
5283
5283
|
platformAccountId,
|
|
@@ -5285,16 +5285,18 @@ async function registerLoginSocket(accountId, sock, authDir) {
|
|
|
5285
5285
|
authDir,
|
|
5286
5286
|
sock,
|
|
5287
5287
|
connected: true,
|
|
5288
|
-
selfPhone:
|
|
5289
|
-
selfJid:
|
|
5290
|
-
selfLid:
|
|
5288
|
+
selfPhone: null,
|
|
5289
|
+
selfJid: null,
|
|
5290
|
+
selfLid: null,
|
|
5291
5291
|
reconnectAttempts: 0,
|
|
5292
5292
|
lastConnectedAt: Date.now(),
|
|
5293
5293
|
abortController: new AbortController(),
|
|
5294
5294
|
debouncer: null,
|
|
5295
|
-
lidMapping
|
|
5295
|
+
lidMapping: null
|
|
5296
5296
|
};
|
|
5297
|
+
applySelfIdentity(conn, sock, "register");
|
|
5297
5298
|
connections.set(accountId, conn);
|
|
5299
|
+
monitorInbound(conn);
|
|
5298
5300
|
try {
|
|
5299
5301
|
await sock.sendPresenceUpdate("available");
|
|
5300
5302
|
console.error(`${TAG13} presence set to available account=${accountId}`);
|
|
@@ -5308,10 +5310,9 @@ async function registerLoginSocket(accountId, sock, authDir) {
|
|
|
5308
5310
|
attempt: 0,
|
|
5309
5311
|
signal: conn.abortController.signal
|
|
5310
5312
|
});
|
|
5311
|
-
monitorInbound(conn);
|
|
5312
5313
|
watchForDisconnect(conn);
|
|
5313
5314
|
attachSelfIdRefreshOnCredsUpdate(conn);
|
|
5314
|
-
console.error(`${TAG13} registered login socket for account=${accountId} phone=${
|
|
5315
|
+
console.error(`${TAG13} registered login socket for account=${accountId} phone=${conn.selfPhone ?? "unknown"}`);
|
|
5315
5316
|
}
|
|
5316
5317
|
function attachSelfIdRefreshOnCredsUpdate(conn) {
|
|
5317
5318
|
if (!conn.sock) return;
|
|
@@ -5391,30 +5392,27 @@ async function connectWithReconnect(conn) {
|
|
|
5391
5392
|
let connectedAt;
|
|
5392
5393
|
try {
|
|
5393
5394
|
console.error(`${TAG13} connecting account=${conn.accountId} attempt=${conn.reconnectAttempts}`);
|
|
5395
|
+
if (conn.debouncer) {
|
|
5396
|
+
await conn.debouncer.destroy();
|
|
5397
|
+
conn.debouncer = null;
|
|
5398
|
+
}
|
|
5394
5399
|
const sock = await createWaSocket({
|
|
5395
5400
|
authDir: conn.authDir,
|
|
5396
|
-
silent: true
|
|
5401
|
+
silent: true,
|
|
5402
|
+
account: conn.accountId
|
|
5397
5403
|
});
|
|
5398
5404
|
conn.sock = sock;
|
|
5405
|
+
applySelfIdentity(conn, sock, "pre-listener");
|
|
5406
|
+
monitorInbound(conn);
|
|
5399
5407
|
console.error(`${TAG13} socket created account=${conn.accountId} \u2014 waiting for connection`);
|
|
5400
5408
|
await waitForConnection(sock);
|
|
5401
|
-
const selfId = readSelfId(conn.authDir);
|
|
5402
5409
|
connectedAt = Date.now();
|
|
5403
5410
|
conn.connected = true;
|
|
5404
|
-
conn.selfPhone = selfId.e164;
|
|
5405
|
-
conn.selfJid = selfId.jid;
|
|
5406
|
-
conn.selfLid = selfId.lid;
|
|
5407
5411
|
conn.lastConnectedAt = connectedAt;
|
|
5408
5412
|
conn.lastError = void 0;
|
|
5409
5413
|
conn.terminalReason = void 0;
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
if (selfId.lid) {
|
|
5413
|
-
console.error(`[whatsapp:lid] resolved self-lid accountId=${conn.accountId} selfLid=${selfId.lid} source=creds`);
|
|
5414
|
-
} else {
|
|
5415
|
-
console.error(`[whatsapp:lid] FAIL self-lid-resolution accountId=${conn.accountId} reason=creds-missing-lid`);
|
|
5416
|
-
}
|
|
5417
|
-
console.error(`${TAG13} connected account=${conn.accountId} phone=${selfId.e164 ?? "unknown"}`);
|
|
5414
|
+
applySelfIdentity(conn, sock, "post-connect");
|
|
5415
|
+
console.error(`${TAG13} connected account=${conn.accountId} phone=${conn.selfPhone ?? "unknown"}`);
|
|
5418
5416
|
try {
|
|
5419
5417
|
await sock.sendPresenceUpdate("available");
|
|
5420
5418
|
console.error(`${TAG13} presence set to available account=${conn.accountId}`);
|
|
@@ -5428,11 +5426,6 @@ async function connectWithReconnect(conn) {
|
|
|
5428
5426
|
attempt: conn.reconnectAttempts,
|
|
5429
5427
|
signal: conn.abortController.signal
|
|
5430
5428
|
});
|
|
5431
|
-
if (conn.debouncer) {
|
|
5432
|
-
await conn.debouncer.destroy();
|
|
5433
|
-
conn.debouncer = null;
|
|
5434
|
-
}
|
|
5435
|
-
monitorInbound(conn);
|
|
5436
5429
|
attachSelfIdRefreshOnCredsUpdate(conn);
|
|
5437
5430
|
await waitForDisconnectEvent(conn);
|
|
5438
5431
|
uptimeMs = Date.now() - connectedAt;
|
|
@@ -5484,11 +5477,11 @@ async function connectWithReconnect(conn) {
|
|
|
5484
5477
|
console.error(
|
|
5485
5478
|
`${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
5486
5479
|
);
|
|
5487
|
-
await new Promise((
|
|
5488
|
-
const timer2 = setTimeout(
|
|
5480
|
+
await new Promise((resolve37) => {
|
|
5481
|
+
const timer2 = setTimeout(resolve37, delay);
|
|
5489
5482
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
5490
5483
|
clearTimeout(timer2);
|
|
5491
|
-
|
|
5484
|
+
resolve37();
|
|
5492
5485
|
}, { once: true });
|
|
5493
5486
|
});
|
|
5494
5487
|
}
|
|
@@ -5496,16 +5489,16 @@ async function connectWithReconnect(conn) {
|
|
|
5496
5489
|
}
|
|
5497
5490
|
}
|
|
5498
5491
|
function waitForDisconnectEvent(conn) {
|
|
5499
|
-
return new Promise((
|
|
5492
|
+
return new Promise((resolve37) => {
|
|
5500
5493
|
if (!conn.sock) {
|
|
5501
|
-
|
|
5494
|
+
resolve37();
|
|
5502
5495
|
return;
|
|
5503
5496
|
}
|
|
5504
5497
|
const sock = conn.sock;
|
|
5505
5498
|
const handler = (update) => {
|
|
5506
5499
|
if (update.connection === "close") {
|
|
5507
5500
|
sock.ev.off("connection.update", handler);
|
|
5508
|
-
|
|
5501
|
+
resolve37();
|
|
5509
5502
|
}
|
|
5510
5503
|
};
|
|
5511
5504
|
sock.ev.on("connection.update", handler);
|
|
@@ -5525,6 +5518,23 @@ function watchForDisconnect(conn) {
|
|
|
5525
5518
|
}
|
|
5526
5519
|
});
|
|
5527
5520
|
}
|
|
5521
|
+
function applySelfIdentity(conn, sock, phase) {
|
|
5522
|
+
const selfId = readSelfId(conn.authDir);
|
|
5523
|
+
conn.selfPhone = selfId.e164;
|
|
5524
|
+
conn.selfJid = selfId.jid;
|
|
5525
|
+
conn.selfLid = selfId.lid;
|
|
5526
|
+
const rawLidMapping = sock.signalRepository?.lidMapping ?? null;
|
|
5527
|
+
conn.lidMapping = withSelfLidShortcut(rawLidMapping, selfId.lid, selfId.jid);
|
|
5528
|
+
if (selfId.lid) {
|
|
5529
|
+
console.error(
|
|
5530
|
+
`[whatsapp:lid] resolved self-lid accountId=${conn.accountId} selfLid=${selfId.lid} source=creds phase=${phase}`
|
|
5531
|
+
);
|
|
5532
|
+
} else {
|
|
5533
|
+
console.error(
|
|
5534
|
+
`[whatsapp:lid] FAIL self-lid-resolution accountId=${conn.accountId} reason=creds-missing-lid phase=${phase}`
|
|
5535
|
+
);
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5528
5538
|
function monitorInbound(conn) {
|
|
5529
5539
|
if (!conn.sock || !onInboundMessage) return;
|
|
5530
5540
|
const sock = conn.sock;
|
|
@@ -5873,8 +5883,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
5873
5883
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
5874
5884
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
5875
5885
|
let resolvePending;
|
|
5876
|
-
const sttPending = new Promise((
|
|
5877
|
-
resolvePending =
|
|
5886
|
+
const sttPending = new Promise((resolve37) => {
|
|
5887
|
+
resolvePending = resolve37;
|
|
5878
5888
|
});
|
|
5879
5889
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
5880
5890
|
try {
|
|
@@ -6302,20 +6312,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
6302
6312
|
|
|
6303
6313
|
// server/routes/health.ts
|
|
6304
6314
|
function checkPort(port2, timeoutMs = 500) {
|
|
6305
|
-
return new Promise((
|
|
6315
|
+
return new Promise((resolve37) => {
|
|
6306
6316
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
6307
6317
|
socket.setTimeout(timeoutMs);
|
|
6308
6318
|
socket.once("connect", () => {
|
|
6309
6319
|
socket.destroy();
|
|
6310
|
-
|
|
6320
|
+
resolve37(true);
|
|
6311
6321
|
});
|
|
6312
6322
|
socket.once("error", () => {
|
|
6313
6323
|
socket.destroy();
|
|
6314
|
-
|
|
6324
|
+
resolve37(false);
|
|
6315
6325
|
});
|
|
6316
6326
|
socket.once("timeout", () => {
|
|
6317
6327
|
socket.destroy();
|
|
6318
|
-
|
|
6328
|
+
resolve37(false);
|
|
6319
6329
|
});
|
|
6320
6330
|
});
|
|
6321
6331
|
}
|
|
@@ -6865,7 +6875,6 @@ function parseScheduleProvenance(v) {
|
|
|
6865
6875
|
|
|
6866
6876
|
// server/routes/channel/schedule-inject.ts
|
|
6867
6877
|
var TAG16 = "[schedule-inject]";
|
|
6868
|
-
var UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
6869
6878
|
function isLoopbackAddr(addr) {
|
|
6870
6879
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
6871
6880
|
}
|
|
@@ -6898,7 +6907,6 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6898
6907
|
const prompt = typeof body.prompt === "string" ? body.prompt : "";
|
|
6899
6908
|
const eventId = typeof body.eventId === "string" ? body.eventId : "";
|
|
6900
6909
|
const scheduleProvenance = parseScheduleProvenance(body.scheduleProvenance);
|
|
6901
|
-
const overrideSessionId = typeof body.sessionId === "string" && UUID_V4.test(body.sessionId) ? body.sessionId : void 0;
|
|
6902
6910
|
if (channel !== "whatsapp" && channel !== "telegram" || !destination || !prompt) {
|
|
6903
6911
|
console.error(`${TAG16} reject reason=bad-request channel=${String(channel)} hasDestination=${Boolean(destination)} hasPrompt=${Boolean(prompt)}`);
|
|
6904
6912
|
return c.json({ ok: false, error: "schedule-inject-bad-request" }, 400);
|
|
@@ -6917,7 +6925,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6917
6925
|
return c.json({ ok: false, error: "account-manager-unresolved" }, 403);
|
|
6918
6926
|
}
|
|
6919
6927
|
console.error(`${TAG16} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount2}`);
|
|
6920
|
-
const sessionId2 =
|
|
6928
|
+
const sessionId2 = adminSessionIdFor(effectiveAccount2, normalizeTarget(destination) ?? destination);
|
|
6921
6929
|
const reply2 = (text) => deps.sendWhatsAppText(houseAccountId, destination, text);
|
|
6922
6930
|
try {
|
|
6923
6931
|
await deps.waHandleInbound({
|
|
@@ -6935,7 +6943,6 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6935
6943
|
media: [],
|
|
6936
6944
|
source: "schedule",
|
|
6937
6945
|
scheduleProvenance,
|
|
6938
|
-
scheduledSessionId: overrideSessionId,
|
|
6939
6946
|
reply: reply2
|
|
6940
6947
|
});
|
|
6941
6948
|
} catch (err) {
|
|
@@ -6953,7 +6960,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6953
6960
|
return c.json({ ok: false, error: "no-admin-bot-token" }, 400);
|
|
6954
6961
|
}
|
|
6955
6962
|
const chatId = Number(destination);
|
|
6956
|
-
const sessionId =
|
|
6963
|
+
const sessionId = adminSessionIdFor(effectiveAccount, destination);
|
|
6957
6964
|
const reply = (text) => deps.sendTelegramText(botToken, chatId, text);
|
|
6958
6965
|
try {
|
|
6959
6966
|
await deps.tgHandleInbound({
|
|
@@ -6965,7 +6972,6 @@ function createScheduleInjectRoutes(deps) {
|
|
|
6965
6972
|
text: prompt,
|
|
6966
6973
|
source: "schedule",
|
|
6967
6974
|
scheduleProvenance,
|
|
6968
|
-
scheduledSessionId: overrideSessionId,
|
|
6969
6975
|
reply
|
|
6970
6976
|
});
|
|
6971
6977
|
} catch (err) {
|
|
@@ -7593,8 +7599,8 @@ async function startLogin(opts) {
|
|
|
7593
7599
|
await clearAuth(authDir);
|
|
7594
7600
|
let resolveCode = null;
|
|
7595
7601
|
let rejectCode = null;
|
|
7596
|
-
const codePromise = new Promise((
|
|
7597
|
-
resolveCode =
|
|
7602
|
+
const codePromise = new Promise((resolve37, reject) => {
|
|
7603
|
+
resolveCode = resolve37;
|
|
7598
7604
|
rejectCode = reject;
|
|
7599
7605
|
});
|
|
7600
7606
|
const codeTimer = setTimeout(
|
|
@@ -7766,14 +7772,14 @@ function routeDocumentOutboundAt(to, filePath) {
|
|
|
7766
7772
|
return lastRouteDocumentOutboundAt.get(routeKey(to, filePath));
|
|
7767
7773
|
}
|
|
7768
7774
|
async function sendWhatsAppDocument(input) {
|
|
7769
|
-
const { to, filePath, caption, accountId, maxyAccountId, platformRoot:
|
|
7775
|
+
const { to, filePath, caption, accountId, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
7770
7776
|
if (!to || !filePath) {
|
|
7771
7777
|
return { ok: false, status: 400, error: "Missing required fields: to, filePath" };
|
|
7772
7778
|
}
|
|
7773
|
-
if (!maxyAccountId || !
|
|
7779
|
+
if (!maxyAccountId || !platformRoot5) {
|
|
7774
7780
|
return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
|
|
7775
7781
|
}
|
|
7776
|
-
const accountDir = resolve9(
|
|
7782
|
+
const accountDir = resolve9(platformRoot5, "..", "data/accounts", maxyAccountId);
|
|
7777
7783
|
let resolvedPath;
|
|
7778
7784
|
try {
|
|
7779
7785
|
resolvedPath = realpathSync3(filePath);
|
|
@@ -8734,7 +8740,8 @@ var bodyLimit = (options) => {
|
|
|
8734
8740
|
|
|
8735
8741
|
// server/routes/storage-broker.ts
|
|
8736
8742
|
import { join as join11, resolve as resolve11 } from "path";
|
|
8737
|
-
import { readdirSync as readdirSync6, readFileSync as readFileSync13, existsSync as existsSync8 } from "fs";
|
|
8743
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync13, existsSync as existsSync8, realpathSync as realpathSync4 } from "fs";
|
|
8744
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
8738
8745
|
var app3 = new Hono();
|
|
8739
8746
|
function platformRoot() {
|
|
8740
8747
|
return process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? join11(__dirname, "..", "..");
|
|
@@ -8793,6 +8800,125 @@ var d1QueryBodyLimit = bodyLimit({
|
|
|
8793
8800
|
);
|
|
8794
8801
|
}
|
|
8795
8802
|
});
|
|
8803
|
+
var pagesDeployBodyLimit = bodyLimit({
|
|
8804
|
+
maxSize: STORAGE_RESOURCE_NAME_MAX_BODY_BYTES,
|
|
8805
|
+
onError: (c) => {
|
|
8806
|
+
log("write", "pages", caller(c) ?? "none", "*", null, "deny", "publish-body-too-large");
|
|
8807
|
+
return c.json(
|
|
8808
|
+
{
|
|
8809
|
+
error: `request body exceeds the ${(STORAGE_RESOURCE_NAME_MAX_BODY_BYTES / 1024).toFixed(
|
|
8810
|
+
1
|
|
8811
|
+
)} 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.`
|
|
8812
|
+
},
|
|
8813
|
+
413
|
|
8814
|
+
);
|
|
8815
|
+
}
|
|
8816
|
+
});
|
|
8817
|
+
function resolveSiteDir(account, site) {
|
|
8818
|
+
if (!site || site === "." || site === "..") return null;
|
|
8819
|
+
if (site.includes("/") || site.includes("\\") || site.includes("\0")) return null;
|
|
8820
|
+
const accountsDir = resolve11(platformRoot(), "..", "data", "accounts");
|
|
8821
|
+
const base = resolve11(accountsDir, account, "sites");
|
|
8822
|
+
const dir = resolve11(base, site);
|
|
8823
|
+
if (dir !== base && !dir.startsWith(base + "/")) return null;
|
|
8824
|
+
try {
|
|
8825
|
+
const realBase = realpathSync4(base);
|
|
8826
|
+
const realDir = realpathSync4(dir);
|
|
8827
|
+
if (!realDir.startsWith(realBase + "/")) return null;
|
|
8828
|
+
return realDir;
|
|
8829
|
+
} catch {
|
|
8830
|
+
return null;
|
|
8831
|
+
}
|
|
8832
|
+
}
|
|
8833
|
+
async function verifyDeployed(url) {
|
|
8834
|
+
try {
|
|
8835
|
+
const res = await fetch(`${url}?cb=${Date.now()}`, { method: "GET", redirect: "follow" });
|
|
8836
|
+
return res.status;
|
|
8837
|
+
} catch {
|
|
8838
|
+
return null;
|
|
8839
|
+
}
|
|
8840
|
+
}
|
|
8841
|
+
app3.post("/pages/deploy", pagesDeployBodyLimit, async (c) => {
|
|
8842
|
+
const pub = randomUUID7().slice(0, 8);
|
|
8843
|
+
const account = caller(c);
|
|
8844
|
+
if (!account) {
|
|
8845
|
+
log("write", "pages", "none", "*", null, "deny", "no-caller");
|
|
8846
|
+
return c.json({ error: "no-caller" }, 403);
|
|
8847
|
+
}
|
|
8848
|
+
const parsed = await readJsonBody(c);
|
|
8849
|
+
if (!parsed.ok) return parsed.res;
|
|
8850
|
+
const { project, site, branch } = parsed.body;
|
|
8851
|
+
if (!project || typeof project !== "string") return c.json({ error: "project-required" }, 400);
|
|
8852
|
+
if (!site || typeof site !== "string") return c.json({ error: "site-required" }, 400);
|
|
8853
|
+
if (branch !== void 0 && typeof branch !== "string") return c.json({ error: "branch-invalid" }, 400);
|
|
8854
|
+
console.error(
|
|
8855
|
+
`[pages-broker] op=request pub=${pub} caller=${account} project=${project} site=${site} branch=${branch ?? "default"}`
|
|
8856
|
+
);
|
|
8857
|
+
const dir = resolveSiteDir(account, site);
|
|
8858
|
+
if (dir === null) {
|
|
8859
|
+
console.error(`[pages-broker] op=path pub=${pub} site=${site} inside=false`);
|
|
8860
|
+
log("write", "pages", account, String(site), null, "deny", "invalid-site");
|
|
8861
|
+
return c.json({ error: "invalid-site" }, 400);
|
|
8862
|
+
}
|
|
8863
|
+
console.error(`[pages-broker] op=path pub=${pub} resolved=${dir} inside=true`);
|
|
8864
|
+
const session = getSession();
|
|
8865
|
+
try {
|
|
8866
|
+
const owner = await resolveOwner(session, "pages", project);
|
|
8867
|
+
const decision = authorizeAccess({ caller: account, owner, action: "write" });
|
|
8868
|
+
console.error(
|
|
8869
|
+
`[pages-broker] op=authorize pub=${pub} caller=${account} owner=${owner ?? "none"} decision=${decision.allow ? "allow" : "deny"} reason=${decision.reason}`
|
|
8870
|
+
);
|
|
8871
|
+
log("write", "pages", account, project, owner, decision.allow ? "allow" : "deny", decision.allow ? void 0 : decision.reason);
|
|
8872
|
+
if (!decision.allow) return c.json({ error: decision.reason }, 403);
|
|
8873
|
+
const started = Date.now();
|
|
8874
|
+
const { url } = await (await makeHousePagesExec(platformRoot())).pagesDeploy(dir, project, branch);
|
|
8875
|
+
console.error(`[pages-broker] op=deploy pub=${pub} ranMs=${Date.now() - started} url=${url}`);
|
|
8876
|
+
const httpStatus = await verifyDeployed(url);
|
|
8877
|
+
const verified = httpStatus === 200;
|
|
8878
|
+
console.error(
|
|
8879
|
+
`[pages-broker] op=complete pub=${pub} httpStatus=${httpStatus ?? "unreachable"} verified=${verified}`
|
|
8880
|
+
);
|
|
8881
|
+
if (!verified) {
|
|
8882
|
+
return c.json({ error: "deploy-unverified", url, httpStatus }, 502);
|
|
8883
|
+
}
|
|
8884
|
+
return c.json({ url });
|
|
8885
|
+
} catch (err) {
|
|
8886
|
+
console.error(`[pages-broker] op=exit pub=${pub} result=error detail="${String(err)}"`);
|
|
8887
|
+
return c.json({ error: String(err) }, 500);
|
|
8888
|
+
} finally {
|
|
8889
|
+
await session.close();
|
|
8890
|
+
}
|
|
8891
|
+
});
|
|
8892
|
+
app3.post("/pages/adopt", nameBodyLimit("pages"), async (c) => {
|
|
8893
|
+
const houseAdminScope = c.req.header("x-maxy-house-admin-scope")?.trim() || null;
|
|
8894
|
+
const account = caller(c);
|
|
8895
|
+
if (!houseAdminScope) {
|
|
8896
|
+
log("write", "pages", account ?? "none", "*", null, "deny", "not-house-admin");
|
|
8897
|
+
return c.json({ error: "not-house-admin" }, 403);
|
|
8898
|
+
}
|
|
8899
|
+
const parsed = await readJsonBody(c);
|
|
8900
|
+
if (!parsed.ok) return parsed.res;
|
|
8901
|
+
const { project, account: target } = parsed.body;
|
|
8902
|
+
if (!project || typeof project !== "string") return c.json({ error: "project-required" }, 400);
|
|
8903
|
+
if (!target || typeof target !== "string") return c.json({ error: "account-required" }, 400);
|
|
8904
|
+
const session = getSession();
|
|
8905
|
+
try {
|
|
8906
|
+
const owner = await resolveOwner(session, "pages", project);
|
|
8907
|
+
if (owner !== null && owner !== target) {
|
|
8908
|
+
log("write", "pages", target, project, owner, "deny", "already-owned");
|
|
8909
|
+
return c.json({ error: "already-owned", owner }, 409);
|
|
8910
|
+
}
|
|
8911
|
+
if (owner === null) {
|
|
8912
|
+
await registerResource(session, { accountId: target, kind: "pages", name: project, cfResourceId: project });
|
|
8913
|
+
}
|
|
8914
|
+
log("write", "pages", target, project, target, "allow");
|
|
8915
|
+
return c.json({ project, account: target });
|
|
8916
|
+
} catch (err) {
|
|
8917
|
+
return c.json({ error: String(err) }, 500);
|
|
8918
|
+
} finally {
|
|
8919
|
+
await session.close();
|
|
8920
|
+
}
|
|
8921
|
+
});
|
|
8796
8922
|
app3.get("/d1/list", async (c) => {
|
|
8797
8923
|
const account = caller(c);
|
|
8798
8924
|
if (!account) return c.json({ error: "no-caller" }, 403);
|
|
@@ -9062,7 +9188,7 @@ app3.post("/r2/object/delete", envelopeBodyLimit("write"), async (c) => {
|
|
|
9062
9188
|
});
|
|
9063
9189
|
var storage_broker_default = app3;
|
|
9064
9190
|
async function runStorageAudit(root) {
|
|
9065
|
-
const { reconcileStorage } = await import("./src-
|
|
9191
|
+
const { reconcileStorage } = await import("./src-YLGAZY36.js");
|
|
9066
9192
|
const session = getSession();
|
|
9067
9193
|
try {
|
|
9068
9194
|
const cf = await makeHouseCfExec(root);
|
|
@@ -9094,9 +9220,31 @@ async function runStorageAudit(root) {
|
|
|
9094
9220
|
await session.close();
|
|
9095
9221
|
}
|
|
9096
9222
|
}
|
|
9223
|
+
async function runPagesAudit(root) {
|
|
9224
|
+
const { reconcilePages } = await import("./src-YLGAZY36.js");
|
|
9225
|
+
const session = getSession();
|
|
9226
|
+
try {
|
|
9227
|
+
const cf = await makeHousePagesExec(root);
|
|
9228
|
+
const r = await reconcilePages({
|
|
9229
|
+
cfProjects: async () => (await cf.pagesProjectList()).map((p) => p.name),
|
|
9230
|
+
registeredProjects: async () => {
|
|
9231
|
+
const res = await session.run(
|
|
9232
|
+
"MATCH (r:StorageResource {kind: $kind}) RETURN r.name AS name",
|
|
9233
|
+
{ kind: "pages" }
|
|
9234
|
+
);
|
|
9235
|
+
return res.records.map((rec) => rec.get("name"));
|
|
9236
|
+
}
|
|
9237
|
+
});
|
|
9238
|
+
console.error(
|
|
9239
|
+
`[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("")
|
|
9240
|
+
);
|
|
9241
|
+
} finally {
|
|
9242
|
+
await session.close();
|
|
9243
|
+
}
|
|
9244
|
+
}
|
|
9097
9245
|
|
|
9098
9246
|
// 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
|
|
9247
|
+
import { readFileSync as readFileSync17, watch, statSync as statSync5, openSync, readSync, closeSync, existsSync as existsSync11, readdirSync as readdirSync11, realpathSync as realpathSync5 } from "fs";
|
|
9100
9248
|
import { basename as basename4, dirname as dirname5, isAbsolute, join as join16, relative as relative2, resolve as resolve13, sep as sep3 } from "path";
|
|
9101
9249
|
|
|
9102
9250
|
// server/routes/admin/sidebar-sessions.ts
|
|
@@ -9728,7 +9876,31 @@ function joinTextBlocks(content) {
|
|
|
9728
9876
|
}
|
|
9729
9877
|
return parts.join("");
|
|
9730
9878
|
}
|
|
9731
|
-
function
|
|
9879
|
+
function erroredToolUseIds(lines) {
|
|
9880
|
+
const ids = /* @__PURE__ */ new Set();
|
|
9881
|
+
for (const line of lines) {
|
|
9882
|
+
if (!line || line[0] !== "{" || !line.includes("is_error")) continue;
|
|
9883
|
+
let row;
|
|
9884
|
+
try {
|
|
9885
|
+
const parsed = JSON.parse(line);
|
|
9886
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
9887
|
+
row = parsed;
|
|
9888
|
+
} catch {
|
|
9889
|
+
continue;
|
|
9890
|
+
}
|
|
9891
|
+
const content = row.message?.content;
|
|
9892
|
+
if (!Array.isArray(content)) continue;
|
|
9893
|
+
for (const block of content) {
|
|
9894
|
+
if (!block || typeof block !== "object") continue;
|
|
9895
|
+
const b = block;
|
|
9896
|
+
if (b.type === "tool_result" && b.is_error === true && typeof b.tool_use_id === "string") {
|
|
9897
|
+
ids.add(b.tool_use_id);
|
|
9898
|
+
}
|
|
9899
|
+
}
|
|
9900
|
+
}
|
|
9901
|
+
return ids;
|
|
9902
|
+
}
|
|
9903
|
+
function assistantTurns(content, ts, promoteFinal = false, erroredIds = /* @__PURE__ */ new Set()) {
|
|
9732
9904
|
if (!Array.isArray(content)) return [];
|
|
9733
9905
|
const out = [];
|
|
9734
9906
|
for (const block of content) {
|
|
@@ -9748,7 +9920,12 @@ function assistantTurns(content, ts, promoteFinal = false) {
|
|
|
9748
9920
|
const input = b.input ?? {};
|
|
9749
9921
|
const files = Array.isArray(input.files) ? input.files.filter((f) => typeof f === "string") : [];
|
|
9750
9922
|
const caption = typeof input.caption === "string" ? input.caption : null;
|
|
9751
|
-
|
|
9923
|
+
const refused = typeof b.id === "string" && erroredIds.has(b.id);
|
|
9924
|
+
if (files.length === 0 || refused) {
|
|
9925
|
+
out.push({ kind: "tool-call", name: SEND_USER_FILE_TOOL, input: b.input ?? null, ts });
|
|
9926
|
+
} else {
|
|
9927
|
+
out.push({ kind: "agent-file", files, caption, ts });
|
|
9928
|
+
}
|
|
9752
9929
|
} else if (b.type === "tool_use" && typeof b.name === "string") {
|
|
9753
9930
|
out.push({ kind: "tool-call", name: b.name, input: b.input ?? null, ts });
|
|
9754
9931
|
}
|
|
@@ -9788,6 +9965,7 @@ function renderOrSuppressChannelInbound(u, ts, out, queuedPendingSuppress) {
|
|
|
9788
9965
|
}
|
|
9789
9966
|
function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(), turnCtx = {}) {
|
|
9790
9967
|
const out = [];
|
|
9968
|
+
const erroredIds = erroredToolUseIds(lines);
|
|
9791
9969
|
for (const line of lines) {
|
|
9792
9970
|
if (!line || line[0] !== "{") continue;
|
|
9793
9971
|
let row;
|
|
@@ -9812,7 +9990,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
9812
9990
|
if (hasWebchatReply(msg?.content)) turnCtx.repliedThisTurn = true;
|
|
9813
9991
|
const isEnd = msg?.stop_reason === "end_turn";
|
|
9814
9992
|
const promoteFinal = isEnd && turnCtx.lastChannelSource === "webchat" && !turnCtx.repliedThisTurn;
|
|
9815
|
-
out.push(...assistantTurns(msg?.content, ts, promoteFinal));
|
|
9993
|
+
out.push(...assistantTurns(msg?.content, ts, promoteFinal, erroredIds));
|
|
9816
9994
|
continue;
|
|
9817
9995
|
}
|
|
9818
9996
|
if (row.type === "queue-operation" && row.operation === "enqueue") {
|
|
@@ -10209,7 +10387,7 @@ function enrichDownloads(turn, scratchpadRoot) {
|
|
|
10209
10387
|
if (turn.kind !== "agent-file") return turn;
|
|
10210
10388
|
let scratchpadReal = null;
|
|
10211
10389
|
try {
|
|
10212
|
-
scratchpadReal =
|
|
10390
|
+
scratchpadReal = realpathSync5(scratchpadRoot);
|
|
10213
10391
|
} catch {
|
|
10214
10392
|
scratchpadReal = null;
|
|
10215
10393
|
}
|
|
@@ -10220,7 +10398,7 @@ function enrichDownloads(turn, scratchpadRoot) {
|
|
|
10220
10398
|
}
|
|
10221
10399
|
if (scratchpadReal) {
|
|
10222
10400
|
try {
|
|
10223
|
-
const fileReal =
|
|
10401
|
+
const fileReal = realpathSync5(f);
|
|
10224
10402
|
if (fileReal === scratchpadReal || fileReal.startsWith(scratchpadReal + sep3)) {
|
|
10225
10403
|
return { root: "scratchpad", path: relative2(scratchpadReal, fileReal) };
|
|
10226
10404
|
}
|
|
@@ -12293,8 +12471,8 @@ function routeTelegramUpdate(input) {
|
|
|
12293
12471
|
// server/routes/telegram.ts
|
|
12294
12472
|
var TAG23 = "[telegram-inbound]";
|
|
12295
12473
|
function configDirName() {
|
|
12296
|
-
const
|
|
12297
|
-
const brandPath = join22(
|
|
12474
|
+
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve16(process.cwd(), "..");
|
|
12475
|
+
const brandPath = join22(platformRoot5, "config", "brand.json");
|
|
12298
12476
|
if (existsSync15(brandPath)) {
|
|
12299
12477
|
try {
|
|
12300
12478
|
return JSON.parse(readFileSync23(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
@@ -12493,7 +12671,7 @@ var quickbooks_default = app9;
|
|
|
12493
12671
|
// server/routes/onboarding.ts
|
|
12494
12672
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync3 } from "child_process";
|
|
12495
12673
|
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
|
|
12674
|
+
import { createHash as createHash4, randomUUID as randomUUID8 } from "crypto";
|
|
12497
12675
|
|
|
12498
12676
|
// app/lib/claude-spawn-env.ts
|
|
12499
12677
|
function claudeBin() {
|
|
@@ -12989,7 +13167,7 @@ app10.post("/set-pin", async (c) => {
|
|
|
12989
13167
|
const hash = hashPin2(body.pin);
|
|
12990
13168
|
const account = resolveAccount();
|
|
12991
13169
|
const existingOwnerUserId = account?.config.admins?.find((a) => a.role === "owner")?.userId;
|
|
12992
|
-
const userId = existingOwnerUserId ??
|
|
13170
|
+
const userId = existingOwnerUserId ?? randomUUID8();
|
|
12993
13171
|
if (existingOwnerUserId) {
|
|
12994
13172
|
console.log(`[set-pin] reusing existing owner userId=${userId.slice(0, 8)}\u2026 (change-PIN preserves identity)`);
|
|
12995
13173
|
} else {
|
|
@@ -13381,7 +13559,7 @@ app11.post("/", async (c) => {
|
|
|
13381
13559
|
var client_error_default = app11;
|
|
13382
13560
|
|
|
13383
13561
|
// server/routes/admin/session.ts
|
|
13384
|
-
import { randomUUID as
|
|
13562
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
13385
13563
|
async function resolveUserIdentity(accountId, userId) {
|
|
13386
13564
|
const result = await loadAdminUserName(userId);
|
|
13387
13565
|
if (result.source === "neo4j") {
|
|
@@ -13395,7 +13573,7 @@ async function resolveUserIdentity(accountId, userId) {
|
|
|
13395
13573
|
async function createAdminSession(accountId, thinkingView, userId, userName, role, avatar) {
|
|
13396
13574
|
const account = resolveAccount();
|
|
13397
13575
|
const effectiveThinkingView = thinkingView ?? account?.config.thinkingView ?? "default";
|
|
13398
|
-
const signedSessionToken =
|
|
13576
|
+
const signedSessionToken = randomUUID9();
|
|
13399
13577
|
const cacheKey = fingerprintSessionKey(signedSessionToken);
|
|
13400
13578
|
registerSession(cacheKey, "admin", accountId, void 0, userId, userName ?? void 0, role);
|
|
13401
13579
|
if (userId) setWantsPriorConversation(cacheKey);
|
|
@@ -13437,15 +13615,15 @@ function operatorRoleFor(config, userId) {
|
|
|
13437
13615
|
async function buildAccountOptionList(accounts, userId) {
|
|
13438
13616
|
const houseAccount = accounts.find((a) => a.config.role === "house");
|
|
13439
13617
|
console.log(`[admin-accounts] op=list count=${accounts.length} house=${houseAccount?.accountId ?? "none"}`);
|
|
13440
|
-
const
|
|
13618
|
+
const resolve37 = async (a) => {
|
|
13441
13619
|
const businessName = await fetchAccountName(a.accountId) || void 0;
|
|
13442
13620
|
return { accountId: a.accountId, businessName, role: operatorRoleFor(a.config, userId), isHouse: a.config.role === "house" };
|
|
13443
13621
|
};
|
|
13444
13622
|
const houseOptions = await Promise.all(
|
|
13445
|
-
accounts.filter((a) => a.config.role === "house").map(
|
|
13623
|
+
accounts.filter((a) => a.config.role === "house").map(resolve37)
|
|
13446
13624
|
);
|
|
13447
13625
|
const nonHouseOptions = await Promise.all(
|
|
13448
|
-
accounts.filter((a) => a.config.role !== "house").map(
|
|
13626
|
+
accounts.filter((a) => a.config.role !== "house").map(resolve37)
|
|
13449
13627
|
);
|
|
13450
13628
|
const sortKey = (o) => (o.businessName || o.accountId).toLowerCase();
|
|
13451
13629
|
nonHouseOptions.sort((x, y) => {
|
|
@@ -14929,10 +15107,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
14929
15107
|
}
|
|
14930
15108
|
}
|
|
14931
15109
|
function resolveTunnelUrl() {
|
|
14932
|
-
const
|
|
15110
|
+
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
|
|
14933
15111
|
let brand;
|
|
14934
15112
|
try {
|
|
14935
|
-
brand = JSON.parse(readFileSync30(resolve21(
|
|
15113
|
+
brand = JSON.parse(readFileSync30(resolve21(platformRoot5, "config", "brand.json"), "utf-8"));
|
|
14936
15114
|
} catch {
|
|
14937
15115
|
return null;
|
|
14938
15116
|
}
|
|
@@ -15141,18 +15319,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
15141
15319
|
]);
|
|
15142
15320
|
var app21 = new Hono();
|
|
15143
15321
|
app21.post("/", async (c) => {
|
|
15144
|
-
const
|
|
15322
|
+
const TAG46 = "[admin:events]";
|
|
15145
15323
|
let body;
|
|
15146
15324
|
try {
|
|
15147
15325
|
body = await c.req.json();
|
|
15148
15326
|
} catch (err) {
|
|
15149
15327
|
const detail = err instanceof Error ? err.message : String(err);
|
|
15150
|
-
console.error(`${
|
|
15328
|
+
console.error(`${TAG46} reject reason=body-not-json detail=${detail}`);
|
|
15151
15329
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
15152
15330
|
}
|
|
15153
15331
|
const event = typeof body.event === "string" ? body.event : "";
|
|
15154
15332
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
15155
|
-
console.error(`${
|
|
15333
|
+
console.error(`${TAG46} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
15156
15334
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
15157
15335
|
}
|
|
15158
15336
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -15176,8 +15354,8 @@ var events_default = app21;
|
|
|
15176
15354
|
// server/routes/admin/files.ts
|
|
15177
15355
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync27 } from "fs";
|
|
15178
15356
|
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
|
|
15357
|
+
import { realpathSync as realpathSync6 } from "fs";
|
|
15358
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
15181
15359
|
import { basename as basename9, dirname as dirname11, join as join30, relative as relative4, resolve as resolve23, sep as sep6 } from "path";
|
|
15182
15360
|
import { Readable as Readable2 } from "stream";
|
|
15183
15361
|
|
|
@@ -16542,8 +16720,8 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
16542
16720
|
const info = await stat4(destDir).catch(() => null);
|
|
16543
16721
|
if (!info || !info.isDirectory()) return { ok: false, status: 400, error: "Upload destination is not a directory" };
|
|
16544
16722
|
}
|
|
16545
|
-
const dataRootReal =
|
|
16546
|
-
const destDirReal =
|
|
16723
|
+
const dataRootReal = realpathSync6(DATA_ROOT);
|
|
16724
|
+
const destDirReal = realpathSync6(destDir);
|
|
16547
16725
|
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
|
|
16548
16726
|
console.error(`[data-upload] op=path-traversal-blocked uid=${uid} requested="${destRel}" resolved="${destDirReal}"`);
|
|
16549
16727
|
return { ok: false, status: 403, error: "Upload destination escapes DATA_ROOT" };
|
|
@@ -16569,7 +16747,7 @@ app22.post("/upload", requireAdminSession, async (c) => {
|
|
|
16569
16747
|
if (c.req.query("uploadId") !== void 0) {
|
|
16570
16748
|
return handleChunkUpload(c, accountId);
|
|
16571
16749
|
}
|
|
16572
|
-
const uid = `${Date.now()}-${
|
|
16750
|
+
const uid = `${Date.now()}-${randomUUID10().slice(0, 8)}`;
|
|
16573
16751
|
const declaredBytes = c.req.header("content-length") ?? "unknown";
|
|
16574
16752
|
const target = await resolveUploadTarget(c, accountId, uid);
|
|
16575
16753
|
if (!target.ok) return c.json({ error: target.error }, target.status);
|
|
@@ -19644,9 +19822,9 @@ app34.get("/", requireAdminSession, async (c) => {
|
|
|
19644
19822
|
var session_usage_default = app34;
|
|
19645
19823
|
|
|
19646
19824
|
// server/routes/admin/session-rc-spawn.ts
|
|
19647
|
-
import { randomUUID as
|
|
19825
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
19648
19826
|
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 =
|
|
19827
|
+
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID11, adminUserId, authenticatedName, callerAccountId) {
|
|
19650
19828
|
const operator = isOperatorHost(host, operatorDomains);
|
|
19651
19829
|
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
19652
19830
|
const name = typeof body.name === "string" && body.name.length > 0 ? body.name : void 0;
|
|
@@ -19701,8 +19879,8 @@ app35.post("/", requireAdminSession, async (c) => {
|
|
|
19701
19879
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
19702
19880
|
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
19703
19881
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
19704
|
-
const plan = resolveSpawnPlan(host, getOperatorDomains(), body,
|
|
19705
|
-
const spawnReqId =
|
|
19882
|
+
const plan = resolveSpawnPlan(host, getOperatorDomains(), body, randomUUID11, adminUserId, authenticatedName, accountId);
|
|
19883
|
+
const spawnReqId = randomUUID11();
|
|
19706
19884
|
console.log(
|
|
19707
19885
|
`[chat-spawn] op=request spawnReqId=${spawnReqId} origin=${plan.origin} kind=${plan.kind} sessionId=${plan.kind === "new" ? "new" : plan.sessionId}`
|
|
19708
19886
|
);
|
|
@@ -19774,8 +19952,8 @@ app35.post("/", requireAdminSession, async (c) => {
|
|
|
19774
19952
|
var session_rc_spawn_default = app35;
|
|
19775
19953
|
|
|
19776
19954
|
// server/routes/admin/session-reseat.ts
|
|
19777
|
-
import { randomUUID as
|
|
19778
|
-
function resolveReseatPlan(body, mintId =
|
|
19955
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
19956
|
+
function resolveReseatPlan(body, mintId = randomUUID12, adminUserId, authenticatedName) {
|
|
19779
19957
|
const sessionId = mintId();
|
|
19780
19958
|
const key = `session:${sessionId}`;
|
|
19781
19959
|
const payload = {
|
|
@@ -19829,11 +20007,11 @@ app36.post("/", requireAdminSession, async (c) => {
|
|
|
19829
20007
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
19830
20008
|
const plan = resolveReseatPlan(
|
|
19831
20009
|
{ fromSessionId, model, ...permissionMode ? { permissionMode } : {}, ...effort ? { effort } : {} },
|
|
19832
|
-
|
|
20010
|
+
randomUUID12,
|
|
19833
20011
|
adminUserId,
|
|
19834
20012
|
authenticatedName
|
|
19835
20013
|
);
|
|
19836
|
-
const reseatReqId =
|
|
20014
|
+
const reseatReqId = randomUUID12();
|
|
19837
20015
|
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
20016
|
let res;
|
|
19839
20017
|
try {
|
|
@@ -20076,7 +20254,7 @@ app38.get("/", async (c) => {
|
|
|
20076
20254
|
var health_default2 = app38;
|
|
20077
20255
|
|
|
20078
20256
|
// server/routes/admin/linkedin-ingest.ts
|
|
20079
|
-
import { randomUUID as
|
|
20257
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
20080
20258
|
|
|
20081
20259
|
// app/lib/channel-pty-bridge/manager-client.ts
|
|
20082
20260
|
function managerBase2() {
|
|
@@ -20329,7 +20507,7 @@ app39.post("/", requireAdminSession, async (c) => {
|
|
|
20329
20507
|
);
|
|
20330
20508
|
const initialMessage = buildInitialMessage(envelope);
|
|
20331
20509
|
const spawnStart = Date.now();
|
|
20332
|
-
const sessionId =
|
|
20510
|
+
const sessionId = randomUUID13();
|
|
20333
20511
|
console.log(TAG27 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
20334
20512
|
const spawned = await managerRcSpawn({
|
|
20335
20513
|
sessionId,
|
|
@@ -21367,7 +21545,7 @@ app47.get("/", requireAdminSession, async (c) => {
|
|
|
21367
21545
|
var tasks_list_default = app47;
|
|
21368
21546
|
|
|
21369
21547
|
// server/routes/admin/task-timer-start.ts
|
|
21370
|
-
import { randomUUID as
|
|
21548
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
21371
21549
|
var TAG34 = "[task-timer]";
|
|
21372
21550
|
var app48 = new Hono();
|
|
21373
21551
|
app48.post("/", requireAdminSession, async (c) => {
|
|
@@ -21405,7 +21583,7 @@ app48.post("/", requireAdminSession, async (c) => {
|
|
|
21405
21583
|
console.log(`${TAG34} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
|
|
21406
21584
|
return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
|
|
21407
21585
|
}
|
|
21408
|
-
const entryId =
|
|
21586
|
+
const entryId = randomUUID14();
|
|
21409
21587
|
await session.run(
|
|
21410
21588
|
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
21411
21589
|
CREATE (te:TimeEntry {entryId: $entryId, taskId: $taskId, accountId: $accountId, startedAt: $now, endedAt: null})
|
|
@@ -21532,7 +21710,7 @@ app50.post("/", requireAdminSession, async (c) => {
|
|
|
21532
21710
|
var task_complete_default = app50;
|
|
21533
21711
|
|
|
21534
21712
|
// server/routes/admin/task-time-adjust.ts
|
|
21535
|
-
import { randomUUID as
|
|
21713
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
21536
21714
|
import neo4j6 from "neo4j-driver";
|
|
21537
21715
|
var TAG37 = "[task-time-adjust]";
|
|
21538
21716
|
var app51 = new Hono();
|
|
@@ -21557,7 +21735,7 @@ app51.post("/", requireAdminSession, async (c) => {
|
|
|
21557
21735
|
console.error(`${TAG37} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
|
|
21558
21736
|
return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
|
|
21559
21737
|
}
|
|
21560
|
-
const adjustmentId =
|
|
21738
|
+
const adjustmentId = randomUUID15();
|
|
21561
21739
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21562
21740
|
console.log(`${TAG37} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
|
|
21563
21741
|
const session = getSession();
|
|
@@ -21891,7 +22069,7 @@ app55.route("/request-magic-link", request_magic_link_default);
|
|
|
21891
22069
|
var access_default = app55;
|
|
21892
22070
|
|
|
21893
22071
|
// server/routes/sites.ts
|
|
21894
|
-
import { existsSync as existsSync31, readFileSync as readFileSync34, realpathSync as
|
|
22072
|
+
import { existsSync as existsSync31, readFileSync as readFileSync34, realpathSync as realpathSync7, statSync as statSync12 } from "fs";
|
|
21895
22073
|
import { resolve as resolve28 } from "path";
|
|
21896
22074
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
21897
22075
|
var MIME = {
|
|
@@ -21983,8 +22161,8 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
21983
22161
|
let realPath;
|
|
21984
22162
|
let realRoot;
|
|
21985
22163
|
try {
|
|
21986
|
-
realPath =
|
|
21987
|
-
realRoot =
|
|
22164
|
+
realPath = realpathSync7(filePath);
|
|
22165
|
+
realRoot = realpathSync7(rootDir);
|
|
21988
22166
|
} catch {
|
|
21989
22167
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
21990
22168
|
return c.text("Not found", 404);
|
|
@@ -22114,9 +22292,9 @@ var cachedAttempted = false;
|
|
|
22114
22292
|
function readBrandConfig() {
|
|
22115
22293
|
if (cachedAttempted) return cached2;
|
|
22116
22294
|
cachedAttempted = true;
|
|
22117
|
-
const
|
|
22118
|
-
if (!
|
|
22119
|
-
const brandPath = join35(
|
|
22295
|
+
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
22296
|
+
if (!platformRoot5) return null;
|
|
22297
|
+
const brandPath = join35(platformRoot5, "config", "brand.json");
|
|
22120
22298
|
if (!existsSync32(brandPath)) return null;
|
|
22121
22299
|
try {
|
|
22122
22300
|
cached2 = JSON.parse(readFileSync36(brandPath, "utf-8"));
|
|
@@ -24038,14 +24216,14 @@ var WaGateway = class {
|
|
|
24038
24216
|
},
|
|
24039
24217
|
Date.now()
|
|
24040
24218
|
);
|
|
24219
|
+
const resolvedSessionId = adminSessionIdFor(
|
|
24220
|
+
input.effectiveAccountId,
|
|
24221
|
+
senderId,
|
|
24222
|
+
input.role === "public" && input.personId ? input.personId : void 0
|
|
24223
|
+
);
|
|
24041
24224
|
console.error(
|
|
24042
|
-
`[whatsapp-native] op=inbound senderId=${senderId} accountId=${input.accountId} bytes=${bytes} ${mediaField} source=${source} delivery=${willDeliverNow ? "immediate" : "queued"}`
|
|
24225
|
+
`[whatsapp-native] op=inbound senderId=${senderId} accountId=${input.accountId} bytes=${bytes} ${mediaField} source=${source} delivery=${willDeliverNow ? "immediate" : "queued"} sessionId=${resolvedSessionId}`
|
|
24043
24226
|
);
|
|
24044
|
-
if (source === "schedule" && (hadSubscriber || this.spawning.has(senderId))) {
|
|
24045
|
-
console.error(
|
|
24046
|
-
`[whatsapp-native] op=coalesced-onto-live-session eventId=${input.scheduleProvenance?.eventId ?? "-"} senderId=${senderId} droppedSeat=${input.scheduledSessionId ?? "-"} reason=${hadSubscriber ? "live-subscriber" : "spawn-in-flight"}`
|
|
24047
|
-
);
|
|
24048
|
-
}
|
|
24049
24227
|
if (!hadSubscriber && !this.spawning.has(senderId)) {
|
|
24050
24228
|
this.spawning.add(senderId);
|
|
24051
24229
|
console.error(`[whatsapp-native] op=spawn-trigger senderId=${senderId}`);
|
|
@@ -24058,8 +24236,6 @@ var WaGateway = class {
|
|
|
24058
24236
|
personId: input.personId ?? null,
|
|
24059
24237
|
gatewayUrl: this.deps.gatewayUrl,
|
|
24060
24238
|
serverPath: this.deps.serverPath,
|
|
24061
|
-
// Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
|
|
24062
|
-
sessionIdOverride: input.scheduledSessionId,
|
|
24063
24239
|
// Task 1575 — the gate's owner-self verdict; drives owner attribution
|
|
24064
24240
|
// for an unbound owner self-phone at the spawn site.
|
|
24065
24241
|
ownerSelfPhone: input.ownerSelfPhone
|
|
@@ -24113,7 +24289,12 @@ function logDuplicateSenderGroups(groups) {
|
|
|
24113
24289
|
function buildWaSpawnRequest(input) {
|
|
24114
24290
|
const personId = input.role === "public" && input.personId ? input.personId : void 0;
|
|
24115
24291
|
return {
|
|
24116
|
-
|
|
24292
|
+
// Task 1746 — the deterministic per-sender id is the ONLY id a sender's
|
|
24293
|
+
// session ever has. Task 1526's per-firing seat override used to replace it
|
|
24294
|
+
// on a scheduled cold start, which spawned a second session for the sender;
|
|
24295
|
+
// that session then attached under the sender's own hub key and swallowed
|
|
24296
|
+
// their real messages until it detached, splitting the conversation in two.
|
|
24297
|
+
sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
24117
24298
|
role: input.role,
|
|
24118
24299
|
channel: "whatsapp",
|
|
24119
24300
|
personId,
|
|
@@ -24453,16 +24634,16 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24453
24634
|
* The public /api/chat route awaits this to return the reply on the same SSE
|
|
24454
24635
|
* response, preserving the pre-756 POST→single-blob browser contract. */
|
|
24455
24636
|
awaitReply(key, timeoutMs) {
|
|
24456
|
-
return new Promise((
|
|
24637
|
+
return new Promise((resolve37) => {
|
|
24457
24638
|
const timer2 = setTimeout(() => {
|
|
24458
24639
|
this.replyAwaiters.delete(key);
|
|
24459
|
-
|
|
24640
|
+
resolve37({ timeout: true });
|
|
24460
24641
|
}, timeoutMs);
|
|
24461
24642
|
if (timer2.unref) timer2.unref();
|
|
24462
24643
|
this.replyAwaiters.set(key, (r) => {
|
|
24463
24644
|
clearTimeout(timer2);
|
|
24464
24645
|
this.replyAwaiters.delete(key);
|
|
24465
|
-
|
|
24646
|
+
resolve37(r);
|
|
24466
24647
|
});
|
|
24467
24648
|
});
|
|
24468
24649
|
}
|
|
@@ -24473,11 +24654,11 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24473
24654
|
* terminal dialog stays answerable). */
|
|
24474
24655
|
awaitPermissionVerdict(p, timeoutMs) {
|
|
24475
24656
|
const k = _WebchatGateway.promptKey(p.key, p.requestId);
|
|
24476
|
-
return new Promise((
|
|
24657
|
+
return new Promise((resolve37) => {
|
|
24477
24658
|
this.pendingPrompts.get(k)?.resolve({ timeout: true });
|
|
24478
24659
|
const timer2 = setTimeout(() => {
|
|
24479
24660
|
this.pendingPrompts.delete(k);
|
|
24480
|
-
|
|
24661
|
+
resolve37({ timeout: true });
|
|
24481
24662
|
}, timeoutMs);
|
|
24482
24663
|
if (timer2.unref) timer2.unref();
|
|
24483
24664
|
this.pendingPrompts.set(k, {
|
|
@@ -24486,7 +24667,7 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24486
24667
|
resolve: (r) => {
|
|
24487
24668
|
clearTimeout(timer2);
|
|
24488
24669
|
this.pendingPrompts.delete(k);
|
|
24489
|
-
|
|
24670
|
+
resolve37(r);
|
|
24490
24671
|
}
|
|
24491
24672
|
});
|
|
24492
24673
|
console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
|
|
@@ -24817,27 +24998,6 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
24817
24998
|
}
|
|
24818
24999
|
};
|
|
24819
25000
|
|
|
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
25001
|
// app/lib/channel-pty-bridge/follower.ts
|
|
24842
25002
|
function followerPendingMaxMs() {
|
|
24843
25003
|
return Number(process.env.CHANNEL_PTY_FOLLOWER_PENDING_MAX_MS ?? String(3e5));
|
|
@@ -24845,6 +25005,13 @@ function followerPendingMaxMs() {
|
|
|
24845
25005
|
function followerRetryMs() {
|
|
24846
25006
|
return Number(process.env.CHANNEL_PTY_FOLLOWER_RETRY_MS ?? String(1e3));
|
|
24847
25007
|
}
|
|
25008
|
+
function toolResultText(content) {
|
|
25009
|
+
if (typeof content === "string") return content;
|
|
25010
|
+
if (!Array.isArray(content)) return "";
|
|
25011
|
+
return content.map(
|
|
25012
|
+
(b) => b && typeof b === "object" && typeof b.text === "string" ? b.text : ""
|
|
25013
|
+
).join("");
|
|
25014
|
+
}
|
|
24848
25015
|
function startFollower(opts) {
|
|
24849
25016
|
const abort = new AbortController();
|
|
24850
25017
|
const { entry, tag } = opts;
|
|
@@ -24887,6 +25054,8 @@ function startFollower(opts) {
|
|
|
24887
25054
|
const decoder = new TextDecoder("utf8");
|
|
24888
25055
|
let buffered = "";
|
|
24889
25056
|
const fileDelivery = opts.fileDelivery ?? null;
|
|
25057
|
+
const captureVerdicts = typeof fileDelivery?.onFileToolResult === "function";
|
|
25058
|
+
const awaitingVerdict = /* @__PURE__ */ new Set();
|
|
24890
25059
|
let firedFileTools = [];
|
|
24891
25060
|
let suppressing = opts.suppressResumeReplay === true;
|
|
24892
25061
|
let discardedTurns = 0;
|
|
@@ -24920,6 +25089,28 @@ function startFollower(opts) {
|
|
|
24920
25089
|
continue;
|
|
24921
25090
|
}
|
|
24922
25091
|
if (event.type === "user") {
|
|
25092
|
+
if (captureVerdicts && awaitingVerdict.size > 0 && !suppressing) {
|
|
25093
|
+
const umsg = event.message;
|
|
25094
|
+
if (umsg && Array.isArray(umsg.content)) {
|
|
25095
|
+
for (const block of umsg.content) {
|
|
25096
|
+
if (block?.type !== "tool_result") continue;
|
|
25097
|
+
const id = block.tool_use_id;
|
|
25098
|
+
if (typeof id !== "string" || !awaitingVerdict.has(id)) continue;
|
|
25099
|
+
awaitingVerdict.delete(id);
|
|
25100
|
+
try {
|
|
25101
|
+
await fileDelivery.onFileToolResult({
|
|
25102
|
+
toolUseId: id,
|
|
25103
|
+
isError: block.is_error === true,
|
|
25104
|
+
text: toolResultText(block.content)
|
|
25105
|
+
});
|
|
25106
|
+
} catch (err) {
|
|
25107
|
+
console.error(
|
|
25108
|
+
`${tag} file-delivery-error sessionId=${sid} phase=tool-result message=${err instanceof Error ? err.message : String(err)}`
|
|
25109
|
+
);
|
|
25110
|
+
}
|
|
25111
|
+
}
|
|
25112
|
+
}
|
|
25113
|
+
}
|
|
24923
25114
|
entry.pendingTurnText = "";
|
|
24924
25115
|
firedFileTools = [];
|
|
24925
25116
|
continue;
|
|
@@ -24941,8 +25132,10 @@ function startFollower(opts) {
|
|
|
24941
25132
|
continue;
|
|
24942
25133
|
}
|
|
24943
25134
|
firedFileTools.push(block.name);
|
|
25135
|
+
const toolUseId = typeof block.id === "string" ? block.id : "";
|
|
25136
|
+
if (captureVerdicts && toolUseId) awaitingVerdict.add(toolUseId);
|
|
24944
25137
|
try {
|
|
24945
|
-
await fileDelivery.onFileToolUse({ toolName: block.name, input: block.input });
|
|
25138
|
+
await fileDelivery.onFileToolUse({ toolName: block.name, toolUseId, input: block.input });
|
|
24946
25139
|
} catch (err) {
|
|
24947
25140
|
console.error(
|
|
24948
25141
|
`${tag} file-delivery-error sessionId=${sid} tool=${block.name} message=${err instanceof Error ? err.message : String(err)}`
|
|
@@ -24964,9 +25157,10 @@ function startFollower(opts) {
|
|
|
24964
25157
|
if (flush.trim()) {
|
|
24965
25158
|
await fanOut(entry.subscribers, flush, opts.onError, tag);
|
|
24966
25159
|
}
|
|
24967
|
-
if (fileDelivery && firedFileTools.length > 0) {
|
|
25160
|
+
if (fileDelivery && (firedFileTools.length > 0 || captureVerdicts)) {
|
|
24968
25161
|
const fired = firedFileTools;
|
|
24969
25162
|
firedFileTools = [];
|
|
25163
|
+
awaitingVerdict.clear();
|
|
24970
25164
|
try {
|
|
24971
25165
|
fileDelivery.onTurnEnd(fired);
|
|
24972
25166
|
} catch (err) {
|
|
@@ -25004,28 +25198,55 @@ async function fanOut(subscribers, text, onError, tag) {
|
|
|
25004
25198
|
);
|
|
25005
25199
|
}
|
|
25006
25200
|
|
|
25201
|
+
// app/lib/webchat/file-delivery.ts
|
|
25202
|
+
import { realpathSync as realpathSync8 } from "fs";
|
|
25203
|
+
import { resolve as resolve32 } from "path";
|
|
25204
|
+
|
|
25007
25205
|
// app/lib/channel-pty-bridge/file-delivery.ts
|
|
25008
25206
|
var SEND_USER_FILE = "SendUserFile";
|
|
25009
25207
|
function makeFileDelivery(opts) {
|
|
25010
|
-
const { entry, tag, channel, sendFile } = opts;
|
|
25208
|
+
const { entry, tag, channel, sendFile, deferUntilVerdict = false } = opts;
|
|
25011
25209
|
let failedFiles = [];
|
|
25012
25210
|
let attempts = 0;
|
|
25013
|
-
|
|
25211
|
+
const pending = /* @__PURE__ */ new Map();
|
|
25212
|
+
function parseInput(input) {
|
|
25213
|
+
const i = input ?? {};
|
|
25214
|
+
return {
|
|
25215
|
+
// A non-array `files` yields zero files. This is the observed refused-call
|
|
25216
|
+
// shape: with the tool absent from the enabled set its schema is absent
|
|
25217
|
+
// from the request, so the model emits a JSON-encoded string. Never parse
|
|
25218
|
+
// it back — the harness refused the call.
|
|
25219
|
+
files: Array.isArray(i.files) ? i.files.filter((f) => typeof f === "string") : [],
|
|
25220
|
+
caption: typeof i.caption === "string" ? i.caption : void 0
|
|
25221
|
+
};
|
|
25222
|
+
}
|
|
25223
|
+
async function forward(call) {
|
|
25224
|
+
for (let i = 0; i < call.files.length; i++) {
|
|
25225
|
+
attempts++;
|
|
25226
|
+
const result = await sendFile(call.files[i], i === 0 ? call.caption : void 0);
|
|
25227
|
+
const name = call.files[i].split("/").pop() ?? call.files[i];
|
|
25228
|
+
console.error(`${tag} op=file-forward channel=${channel} file=${name} outcome=${result.ok ? "ok" : "fail"}`);
|
|
25229
|
+
if (!result.ok) failedFiles.push(call.files[i]);
|
|
25230
|
+
}
|
|
25231
|
+
}
|
|
25232
|
+
function unreconciledCall(reason, files, detail) {
|
|
25233
|
+
const d = detail ? ` detail="${detail.replace(/\s+/g, " ").slice(0, 120)}"` : "";
|
|
25234
|
+
console.error(
|
|
25235
|
+
`${tag} file-delivery-unreconciled sender=${entry.senderId} sessionId=${entry.sessionId.slice(0, 8)} tool=${SEND_USER_FILE} reason=${reason} files=${files}${d}`
|
|
25236
|
+
);
|
|
25237
|
+
}
|
|
25238
|
+
const handler = {
|
|
25014
25239
|
isFileDeliveryTool(toolName) {
|
|
25015
25240
|
return toolName === SEND_USER_FILE;
|
|
25016
25241
|
},
|
|
25017
25242
|
async onFileToolUse(use) {
|
|
25018
25243
|
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]);
|
|
25244
|
+
const call = parseInput(use.input);
|
|
25245
|
+
if (deferUntilVerdict) {
|
|
25246
|
+
pending.set(use.toolUseId, call);
|
|
25247
|
+
return;
|
|
25028
25248
|
}
|
|
25249
|
+
await forward(call);
|
|
25029
25250
|
},
|
|
25030
25251
|
onTurnEnd(firedTools) {
|
|
25031
25252
|
const failed = failedFiles;
|
|
@@ -25038,6 +25259,11 @@ function makeFileDelivery(opts) {
|
|
|
25038
25259
|
`${tag} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${SEND_USER_FILE} file=${file}`
|
|
25039
25260
|
);
|
|
25040
25261
|
}
|
|
25262
|
+
if (deferUntilVerdict) {
|
|
25263
|
+
for (const call of pending.values()) unreconciledCall("no-verdict", call.files.length);
|
|
25264
|
+
pending.clear();
|
|
25265
|
+
return;
|
|
25266
|
+
}
|
|
25041
25267
|
if (firedTools.includes(SEND_USER_FILE) && tried === 0) {
|
|
25042
25268
|
console.error(
|
|
25043
25269
|
`${tag} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${SEND_USER_FILE}`
|
|
@@ -25045,13 +25271,123 @@ function makeFileDelivery(opts) {
|
|
|
25045
25271
|
}
|
|
25046
25272
|
}
|
|
25047
25273
|
};
|
|
25274
|
+
if (deferUntilVerdict) {
|
|
25275
|
+
handler.onFileToolResult = async (result) => {
|
|
25276
|
+
const call = pending.get(result.toolUseId);
|
|
25277
|
+
if (!call) return;
|
|
25278
|
+
pending.delete(result.toolUseId);
|
|
25279
|
+
if (result.isError) {
|
|
25280
|
+
unreconciledCall("harness-refused", call.files.length, result.text);
|
|
25281
|
+
return;
|
|
25282
|
+
}
|
|
25283
|
+
if (call.files.length === 0) {
|
|
25284
|
+
unreconciledCall("no-files", 0);
|
|
25285
|
+
return;
|
|
25286
|
+
}
|
|
25287
|
+
await forward(call);
|
|
25288
|
+
};
|
|
25289
|
+
}
|
|
25290
|
+
return handler;
|
|
25291
|
+
}
|
|
25292
|
+
|
|
25293
|
+
// app/lib/webchat/file-delivery.ts
|
|
25294
|
+
var TAG41 = "[webchat-adaptor]";
|
|
25295
|
+
function platformRoot2() {
|
|
25296
|
+
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
25297
|
+
}
|
|
25298
|
+
function makeWebchatSendFile(entry) {
|
|
25299
|
+
return async (filePath) => {
|
|
25300
|
+
if (!entry.accountId) {
|
|
25301
|
+
console.error(`${TAG41} file-delivery reject reason=no-account sender=${entry.senderId}`);
|
|
25302
|
+
return { ok: false, error: "no-account" };
|
|
25303
|
+
}
|
|
25304
|
+
const accountDir = resolve32(platformRoot2(), "..", "data/accounts", entry.accountId);
|
|
25305
|
+
try {
|
|
25306
|
+
const resolved = realpathSync8(filePath);
|
|
25307
|
+
const accountResolved = realpathSync8(accountDir);
|
|
25308
|
+
if (!resolved.startsWith(accountResolved + "/")) {
|
|
25309
|
+
console.error(`${TAG41} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
|
|
25310
|
+
return { ok: false, error: "outside-account" };
|
|
25311
|
+
}
|
|
25312
|
+
return { ok: true };
|
|
25313
|
+
} catch (err) {
|
|
25314
|
+
const code = err.code;
|
|
25315
|
+
console.error(
|
|
25316
|
+
`${TAG41} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
|
|
25317
|
+
);
|
|
25318
|
+
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
25319
|
+
}
|
|
25320
|
+
};
|
|
25321
|
+
}
|
|
25322
|
+
function makeWebchatFileDelivery(entry) {
|
|
25323
|
+
return makeFileDelivery({
|
|
25324
|
+
entry,
|
|
25325
|
+
tag: TAG41,
|
|
25326
|
+
channel: "webchat",
|
|
25327
|
+
sendFile: makeWebchatSendFile(entry),
|
|
25328
|
+
deferUntilVerdict: true
|
|
25329
|
+
});
|
|
25330
|
+
}
|
|
25331
|
+
|
|
25332
|
+
// app/lib/webchat/gateway/native-file-follower.ts
|
|
25333
|
+
function startWebchatNativeFileFollower(input) {
|
|
25334
|
+
const entry = {
|
|
25335
|
+
sessionId: input.sessionId,
|
|
25336
|
+
role: "admin",
|
|
25337
|
+
channel: "webchat",
|
|
25338
|
+
accountId: input.accountId,
|
|
25339
|
+
senderId: input.key,
|
|
25340
|
+
agentSlug: "admin",
|
|
25341
|
+
lastInboundAt: Date.now(),
|
|
25342
|
+
writeChain: Promise.resolve(),
|
|
25343
|
+
subscribers: /* @__PURE__ */ new Set(),
|
|
25344
|
+
pendingTurnText: "",
|
|
25345
|
+
followerAbort: null,
|
|
25346
|
+
followerRunning: false,
|
|
25347
|
+
sliceToken: "",
|
|
25348
|
+
personId: null,
|
|
25349
|
+
name: null,
|
|
25350
|
+
// Webchat renders from the transcript; there is no separate reply target.
|
|
25351
|
+
replyTarget: null
|
|
25352
|
+
};
|
|
25353
|
+
return startFollower({
|
|
25354
|
+
entry,
|
|
25355
|
+
tag: "[webchat-adaptor]",
|
|
25356
|
+
fileDelivery: makeWebchatFileDelivery(entry),
|
|
25357
|
+
// A resumed session's JSONL already holds prior SendUserFile tool_uses;
|
|
25358
|
+
// suppress replay so historical calls are not re-reconciled on attach.
|
|
25359
|
+
suppressResumeReplay: true,
|
|
25360
|
+
onClose: input.onClose ?? (() => {
|
|
25361
|
+
})
|
|
25362
|
+
});
|
|
25363
|
+
}
|
|
25364
|
+
|
|
25365
|
+
// app/lib/webchat/gateway/public-spawn-request.ts
|
|
25366
|
+
function buildPublicWebchatSpawnRequest(input) {
|
|
25367
|
+
const { agentSlug, sliceToken, personId, visitorId, name } = input.public;
|
|
25368
|
+
return {
|
|
25369
|
+
senderId: input.key,
|
|
25370
|
+
role: "public",
|
|
25371
|
+
channel: "webchat",
|
|
25372
|
+
accountId: input.accountId,
|
|
25373
|
+
agentSlug,
|
|
25374
|
+
model: SONNET_MODEL,
|
|
25375
|
+
// sliceToken/personId are present only for a gated visitor; open-mode
|
|
25376
|
+
// public agents carry neither (mirrors the bridge's open-mode key).
|
|
25377
|
+
...sliceToken ? { sliceToken } : {},
|
|
25378
|
+
...personId ? { personId } : {},
|
|
25379
|
+
...visitorId ? { visitorId } : {},
|
|
25380
|
+
...input.previousContext ? { previousContext: input.previousContext } : {},
|
|
25381
|
+
name,
|
|
25382
|
+
webchatChannel: { key: input.key, gatewayUrl: input.gatewayUrl, serverPath: input.serverPath }
|
|
25383
|
+
};
|
|
25048
25384
|
}
|
|
25049
25385
|
|
|
25050
25386
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
25051
|
-
var
|
|
25387
|
+
var TAG42 = "[whatsapp-adaptor]";
|
|
25052
25388
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
25053
25389
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
25054
|
-
function
|
|
25390
|
+
function platformRoot3() {
|
|
25055
25391
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
25056
25392
|
}
|
|
25057
25393
|
function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
@@ -25062,11 +25398,11 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
25062
25398
|
caption,
|
|
25063
25399
|
accountId: entry.accountId,
|
|
25064
25400
|
maxyAccountId,
|
|
25065
|
-
platformRoot:
|
|
25401
|
+
platformRoot: platformRoot3()
|
|
25066
25402
|
});
|
|
25067
25403
|
if (result.ok) return { ok: true };
|
|
25068
25404
|
console.error(
|
|
25069
|
-
`${
|
|
25405
|
+
`${TAG42} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
25070
25406
|
);
|
|
25071
25407
|
return { ok: false, error: result.error };
|
|
25072
25408
|
};
|
|
@@ -25074,7 +25410,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
25074
25410
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
25075
25411
|
const shared = makeFileDelivery({
|
|
25076
25412
|
entry,
|
|
25077
|
-
tag:
|
|
25413
|
+
tag: TAG42,
|
|
25078
25414
|
channel: "whatsapp",
|
|
25079
25415
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
25080
25416
|
});
|
|
@@ -25109,7 +25445,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
25109
25445
|
if (!delivered) {
|
|
25110
25446
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
25111
25447
|
console.error(
|
|
25112
|
-
`${
|
|
25448
|
+
`${TAG42} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
25113
25449
|
);
|
|
25114
25450
|
}
|
|
25115
25451
|
}
|
|
@@ -25445,14 +25781,14 @@ var TelegramGateway = class {
|
|
|
25445
25781
|
{ key: input.senderId, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules, scheduleProvenance: input.scheduleProvenance },
|
|
25446
25782
|
Date.now()
|
|
25447
25783
|
);
|
|
25784
|
+
const resolvedSessionId = adminSessionIdFor(
|
|
25785
|
+
input.accountId,
|
|
25786
|
+
input.senderId,
|
|
25787
|
+
input.role === "public" && input.personId ? input.personId : void 0
|
|
25788
|
+
);
|
|
25448
25789
|
console.error(
|
|
25449
|
-
`[telegram-native] op=inbound key=${input.senderId} accountId=${input.accountId} botType=${input.role} bytes=${bytes} source=${source} delivery=${willDeliverNow ? "immediate" : "queued"}`
|
|
25790
|
+
`[telegram-native] op=inbound key=${input.senderId} accountId=${input.accountId} botType=${input.role} bytes=${bytes} source=${source} delivery=${willDeliverNow ? "immediate" : "queued"} sessionId=${resolvedSessionId}`
|
|
25450
25791
|
);
|
|
25451
|
-
if (source === "schedule" && (hadSubscriber || this.spawning.has(input.senderId))) {
|
|
25452
|
-
console.error(
|
|
25453
|
-
`[telegram-native] op=coalesced-onto-live-session eventId=${input.scheduleProvenance?.eventId ?? "-"} senderId=${input.senderId} droppedSeat=${input.scheduledSessionId ?? "-"} reason=${hadSubscriber ? "live-subscriber" : "spawn-in-flight"}`
|
|
25454
|
-
);
|
|
25455
|
-
}
|
|
25456
25792
|
if (!hadSubscriber && !this.spawning.has(input.senderId)) {
|
|
25457
25793
|
this.spawning.add(input.senderId);
|
|
25458
25794
|
console.error(`[telegram-native] op=spawn-trigger key=${input.senderId} role=${input.role}`);
|
|
@@ -25464,9 +25800,7 @@ var TelegramGateway = class {
|
|
|
25464
25800
|
personId: input.personId ?? null,
|
|
25465
25801
|
chatId: input.chatId,
|
|
25466
25802
|
gatewayUrl: this.deps.gatewayUrl,
|
|
25467
|
-
serverPath: this.deps.serverPath
|
|
25468
|
-
// Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
|
|
25469
|
-
sessionIdOverride: input.scheduledSessionId
|
|
25803
|
+
serverPath: this.deps.serverPath
|
|
25470
25804
|
});
|
|
25471
25805
|
} finally {
|
|
25472
25806
|
this.spawning.delete(input.senderId);
|
|
@@ -25484,7 +25818,10 @@ var TelegramGateway = class {
|
|
|
25484
25818
|
function buildTelegramSpawnRequest(input) {
|
|
25485
25819
|
const personId = input.role === "public" && input.personId ? input.personId : void 0;
|
|
25486
25820
|
return {
|
|
25487
|
-
|
|
25821
|
+
// Task 1746 — the deterministic per-sender id is the ONLY id a sender's
|
|
25822
|
+
// session ever has. Mirror of the WhatsApp builder; see its comment for why
|
|
25823
|
+
// Task 1526's per-firing override was removed.
|
|
25824
|
+
sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
|
|
25488
25825
|
role: input.role,
|
|
25489
25826
|
channel: "telegram",
|
|
25490
25827
|
personId,
|
|
@@ -25500,35 +25837,35 @@ function buildTelegramSpawnRequest(input) {
|
|
|
25500
25837
|
}
|
|
25501
25838
|
|
|
25502
25839
|
// app/lib/telegram/outbound/send-document.ts
|
|
25503
|
-
import { realpathSync as
|
|
25840
|
+
import { realpathSync as realpathSync9 } from "fs";
|
|
25504
25841
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
25505
|
-
import { resolve as
|
|
25506
|
-
var
|
|
25842
|
+
import { resolve as resolve33, basename as basename11 } from "path";
|
|
25843
|
+
var TAG43 = "[telegram:outbound]";
|
|
25507
25844
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
25508
25845
|
async function sendTelegramDocument(input) {
|
|
25509
|
-
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot:
|
|
25846
|
+
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
25510
25847
|
if (!botToken || !filePath) {
|
|
25511
25848
|
return { ok: false, status: 400, error: "Missing required fields: botToken, filePath" };
|
|
25512
25849
|
}
|
|
25513
|
-
if (!maxyAccountId || !
|
|
25850
|
+
if (!maxyAccountId || !platformRoot5) {
|
|
25514
25851
|
return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
|
|
25515
25852
|
}
|
|
25516
|
-
const accountDir =
|
|
25853
|
+
const accountDir = resolve33(platformRoot5, "..", "data/accounts", maxyAccountId);
|
|
25517
25854
|
let resolvedPath;
|
|
25518
25855
|
try {
|
|
25519
|
-
resolvedPath =
|
|
25520
|
-
const accountResolved =
|
|
25856
|
+
resolvedPath = realpathSync9(filePath);
|
|
25857
|
+
const accountResolved = realpathSync9(accountDir);
|
|
25521
25858
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
25522
|
-
console.error(`${
|
|
25859
|
+
console.error(`${TAG43} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
25523
25860
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
25524
25861
|
}
|
|
25525
25862
|
} catch (err) {
|
|
25526
25863
|
const code = err.code;
|
|
25527
25864
|
if (code === "ENOENT") {
|
|
25528
|
-
console.error(`${
|
|
25865
|
+
console.error(`${TAG43} document ENOENT path=${filePath}`);
|
|
25529
25866
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
25530
25867
|
}
|
|
25531
|
-
console.error(`${
|
|
25868
|
+
console.error(`${TAG43} document path error: ${String(err)}`);
|
|
25532
25869
|
return { ok: false, status: 500, error: String(err) };
|
|
25533
25870
|
}
|
|
25534
25871
|
const fileStat = await stat7(resolvedPath);
|
|
@@ -25561,14 +25898,14 @@ async function sendTelegramDocument(input) {
|
|
|
25561
25898
|
error = e instanceof Error ? e.message : String(e);
|
|
25562
25899
|
}
|
|
25563
25900
|
console.error(
|
|
25564
|
-
`${
|
|
25901
|
+
`${TAG43} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
25565
25902
|
);
|
|
25566
25903
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
25567
25904
|
}
|
|
25568
25905
|
|
|
25569
25906
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
25570
|
-
var
|
|
25571
|
-
function
|
|
25907
|
+
var TAG44 = "[telegram:outbound]";
|
|
25908
|
+
function platformRoot4() {
|
|
25572
25909
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
25573
25910
|
}
|
|
25574
25911
|
function makeTelegramSendFile(entry) {
|
|
@@ -25579,11 +25916,11 @@ function makeTelegramSendFile(entry) {
|
|
|
25579
25916
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
25580
25917
|
}
|
|
25581
25918
|
if (!botToken) {
|
|
25582
|
-
console.error(`${
|
|
25919
|
+
console.error(`${TAG44} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
25583
25920
|
return { ok: false, error: "no-bot-token" };
|
|
25584
25921
|
}
|
|
25585
25922
|
if (entry.replyTarget == null) {
|
|
25586
|
-
console.error(`${
|
|
25923
|
+
console.error(`${TAG44} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
25587
25924
|
return { ok: false, error: "no-reply-target" };
|
|
25588
25925
|
}
|
|
25589
25926
|
const result = await sendTelegramDocument({
|
|
@@ -25592,7 +25929,7 @@ function makeTelegramSendFile(entry) {
|
|
|
25592
25929
|
filePath,
|
|
25593
25930
|
caption,
|
|
25594
25931
|
maxyAccountId: entry.accountId,
|
|
25595
|
-
platformRoot:
|
|
25932
|
+
platformRoot: platformRoot4()
|
|
25596
25933
|
});
|
|
25597
25934
|
return result.ok ? { ok: true } : { ok: false, error: result.error };
|
|
25598
25935
|
};
|
|
@@ -25600,7 +25937,7 @@ function makeTelegramSendFile(entry) {
|
|
|
25600
25937
|
function makeTelegramFileDelivery(entry) {
|
|
25601
25938
|
return makeFileDelivery({
|
|
25602
25939
|
entry,
|
|
25603
|
-
tag:
|
|
25940
|
+
tag: TAG44,
|
|
25604
25941
|
channel: "telegram",
|
|
25605
25942
|
sendFile: makeTelegramSendFile(entry)
|
|
25606
25943
|
});
|
|
@@ -25640,17 +25977,17 @@ function startTelegramNativeFileFollower(input) {
|
|
|
25640
25977
|
}
|
|
25641
25978
|
|
|
25642
25979
|
// server/telegram-descriptor.ts
|
|
25643
|
-
import { resolve as
|
|
25980
|
+
import { resolve as resolve34, join as join37 } from "path";
|
|
25644
25981
|
function telegramGatewayUrl() {
|
|
25645
25982
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
25646
25983
|
}
|
|
25647
25984
|
function telegramServerPath() {
|
|
25648
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ??
|
|
25985
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve34(process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
25649
25986
|
}
|
|
25650
25987
|
|
|
25651
25988
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
25652
|
-
import { randomUUID as
|
|
25653
|
-
var
|
|
25989
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
25990
|
+
var TAG45 = "[public-session-review]";
|
|
25654
25991
|
var CONSUMED_CAP = 500;
|
|
25655
25992
|
var consumed = /* @__PURE__ */ new Set();
|
|
25656
25993
|
function consumeOnce(sessionId) {
|
|
@@ -25677,7 +26014,7 @@ async function fetchJsonl(sessionId) {
|
|
|
25677
26014
|
return await res.text();
|
|
25678
26015
|
} catch (err) {
|
|
25679
26016
|
console.error(
|
|
25680
|
-
`${
|
|
26017
|
+
`${TAG45} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
25681
26018
|
);
|
|
25682
26019
|
return null;
|
|
25683
26020
|
}
|
|
@@ -25701,7 +26038,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
25701
26038
|
const res = await fetch(url);
|
|
25702
26039
|
if (!res.ok) {
|
|
25703
26040
|
console.error(
|
|
25704
|
-
`${
|
|
26041
|
+
`${TAG45} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
25705
26042
|
);
|
|
25706
26043
|
return [];
|
|
25707
26044
|
}
|
|
@@ -25709,7 +26046,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
25709
26046
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
25710
26047
|
} catch (err) {
|
|
25711
26048
|
console.error(
|
|
25712
|
-
`${
|
|
26049
|
+
`${TAG45} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
25713
26050
|
);
|
|
25714
26051
|
return [];
|
|
25715
26052
|
}
|
|
@@ -25737,8 +26074,8 @@ function composeInitialMessage(input) {
|
|
|
25737
26074
|
].join("\n");
|
|
25738
26075
|
}
|
|
25739
26076
|
async function dispatchReviewer(input, initialMessage) {
|
|
25740
|
-
const sessionId =
|
|
25741
|
-
console.log(`${
|
|
26077
|
+
const sessionId = randomUUID16();
|
|
26078
|
+
console.log(`${TAG45} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
25742
26079
|
const spawned = await managerRcSpawn({
|
|
25743
26080
|
sessionId,
|
|
25744
26081
|
initialMessage,
|
|
@@ -25758,21 +26095,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
25758
26095
|
const dispatchedAt = Date.now();
|
|
25759
26096
|
if (consumed.has(input.sessionId)) {
|
|
25760
26097
|
console.log(
|
|
25761
|
-
`${
|
|
26098
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
25762
26099
|
);
|
|
25763
26100
|
return;
|
|
25764
26101
|
}
|
|
25765
26102
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
25766
26103
|
if (!jsonl) {
|
|
25767
26104
|
console.log(
|
|
25768
|
-
`${
|
|
26105
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
25769
26106
|
);
|
|
25770
26107
|
return;
|
|
25771
26108
|
}
|
|
25772
26109
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
25773
26110
|
if (operatorTurns === 0) {
|
|
25774
26111
|
console.log(
|
|
25775
|
-
`${
|
|
26112
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
25776
26113
|
);
|
|
25777
26114
|
return;
|
|
25778
26115
|
}
|
|
@@ -25786,19 +26123,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
25786
26123
|
});
|
|
25787
26124
|
if (!consumeOnce(input.sessionId)) {
|
|
25788
26125
|
console.log(
|
|
25789
|
-
`${
|
|
26126
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
25790
26127
|
);
|
|
25791
26128
|
return;
|
|
25792
26129
|
}
|
|
25793
26130
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
25794
26131
|
if (!dispatched.ok) {
|
|
25795
26132
|
console.error(
|
|
25796
|
-
`${
|
|
26133
|
+
`${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
25797
26134
|
);
|
|
25798
26135
|
return;
|
|
25799
26136
|
}
|
|
25800
26137
|
console.log(
|
|
25801
|
-
`${
|
|
26138
|
+
`${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
26139
|
);
|
|
25803
26140
|
}
|
|
25804
26141
|
|
|
@@ -25908,7 +26245,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
25908
26245
|
// ../lib/entitlement/src/index.ts
|
|
25909
26246
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
25910
26247
|
import { existsSync as existsSync35, readFileSync as readFileSync37, statSync as statSync13 } from "fs";
|
|
25911
|
-
import { resolve as
|
|
26248
|
+
import { resolve as resolve35 } from "path";
|
|
25912
26249
|
|
|
25913
26250
|
// ../lib/entitlement/src/canonicalize.ts
|
|
25914
26251
|
function canonicalize(value) {
|
|
@@ -25943,7 +26280,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
25943
26280
|
var GRACE_DAYS = 7;
|
|
25944
26281
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
25945
26282
|
function pubkeyPath(brand) {
|
|
25946
|
-
return
|
|
26283
|
+
return resolve35(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
25947
26284
|
}
|
|
25948
26285
|
var memo = null;
|
|
25949
26286
|
function memoKey(mtimeMs, account) {
|
|
@@ -25955,7 +26292,7 @@ function resolveEntitlement(brand, account) {
|
|
|
25955
26292
|
if (brand.commercialMode !== true) {
|
|
25956
26293
|
return logResolved(implicitTrust(account), null);
|
|
25957
26294
|
}
|
|
25958
|
-
const entitlementPath =
|
|
26295
|
+
const entitlementPath = resolve35(brand.configDir, "entitlement.json");
|
|
25959
26296
|
if (!existsSync35(entitlementPath)) {
|
|
25960
26297
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
25961
26298
|
}
|
|
@@ -26215,6 +26552,7 @@ function isPublicHost(host) {
|
|
|
26215
26552
|
}
|
|
26216
26553
|
var app62 = new Hono();
|
|
26217
26554
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
26555
|
+
var webchatFileFollowers = /* @__PURE__ */ new Map();
|
|
26218
26556
|
async function fetchAccountStandingRules(accountId) {
|
|
26219
26557
|
const session = getSession();
|
|
26220
26558
|
try {
|
|
@@ -26252,7 +26590,7 @@ async function recordPassiveDispatch(input) {
|
|
|
26252
26590
|
var waGateway = new WaGateway({
|
|
26253
26591
|
fetchStandingRules: fetchAccountStandingRules,
|
|
26254
26592
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
26255
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
26593
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve36(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
26256
26594
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
26257
26595
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
26258
26596
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -26267,11 +26605,11 @@ var waGateway = new WaGateway({
|
|
|
26267
26605
|
caption,
|
|
26268
26606
|
accountId,
|
|
26269
26607
|
maxyAccountId,
|
|
26270
|
-
platformRoot:
|
|
26608
|
+
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, ".."))
|
|
26271
26609
|
});
|
|
26272
26610
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
26273
26611
|
},
|
|
26274
|
-
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId,
|
|
26612
|
+
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, ownerSelfPhone }) => {
|
|
26275
26613
|
if (passive) {
|
|
26276
26614
|
const phoneHash = createHash7("sha256").update(senderId).digest("hex").slice(0, 12);
|
|
26277
26615
|
const prompt = (text ?? "").trim();
|
|
@@ -26319,7 +26657,7 @@ var waGateway = new WaGateway({
|
|
|
26319
26657
|
const managesAccount = effectiveAccountId !== accountId ? effectiveAccountId : "none";
|
|
26320
26658
|
console.error(`[whatsapp-native] op=account-manager-route senderId=${senderId} managesAccount=${managesAccount} effectiveAccount=${effectiveAccountId} source=gate`);
|
|
26321
26659
|
}
|
|
26322
|
-
const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath
|
|
26660
|
+
const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath });
|
|
26323
26661
|
const userId = role === "admin" ? resolveAdminUserId({ accountId: effectiveAccountId, senderPhone: senderId }) ?? (ownerSelfPhone ? resolveOwnerUserId(effectiveAccountId) ?? void 0 : void 0) : void 0;
|
|
26324
26662
|
if (role === "admin") {
|
|
26325
26663
|
const attribution = userId ?? (ownerSelfPhone ? "owner-self-unresolved" : "unbound-empty");
|
|
@@ -26425,6 +26763,20 @@ var webchatGateway = new WebchatGateway({
|
|
|
26425
26763
|
console.error(`[webchat:inbound] op=spawn-failed key=${key} error=${result.error} status=${result.status}`);
|
|
26426
26764
|
return;
|
|
26427
26765
|
}
|
|
26766
|
+
const priorWebchatFollower = webchatFileFollowers.get(key);
|
|
26767
|
+
if (priorWebchatFollower) priorWebchatFollower.abort();
|
|
26768
|
+
let wac;
|
|
26769
|
+
wac = startWebchatNativeFileFollower({
|
|
26770
|
+
sessionId: result.sessionId,
|
|
26771
|
+
key,
|
|
26772
|
+
// The session's own resolved account (house or sub-account) — the
|
|
26773
|
+
// file-path validation scope, exactly as passed to the spawn above.
|
|
26774
|
+
accountId,
|
|
26775
|
+
onClose: () => {
|
|
26776
|
+
if (webchatFileFollowers.get(key) === wac) webchatFileFollowers.delete(key);
|
|
26777
|
+
}
|
|
26778
|
+
});
|
|
26779
|
+
webchatFileFollowers.set(key, wac);
|
|
26428
26780
|
return { sessionId: result.sessionId };
|
|
26429
26781
|
},
|
|
26430
26782
|
// Task-962 — the recovery pass asks the manager to respawn a wedged already-
|
|
@@ -26461,8 +26813,8 @@ var telegramGateway = new TelegramGateway({
|
|
|
26461
26813
|
fetchStandingRules: fetchAccountStandingRules,
|
|
26462
26814
|
gatewayUrl: telegramGatewayUrl(),
|
|
26463
26815
|
serverPath: telegramServerPath(),
|
|
26464
|
-
ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath
|
|
26465
|
-
const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath
|
|
26816
|
+
ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath }) => {
|
|
26817
|
+
const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath });
|
|
26466
26818
|
const result = await managerRcSpawn(req);
|
|
26467
26819
|
if ("error" in result) {
|
|
26468
26820
|
console.error(`[telegram-native] spawn-failed senderId=${senderId} role=${role} error=${result.error} status=${result.status}`);
|
|
@@ -26886,8 +27238,8 @@ app62.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
26886
27238
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
26887
27239
|
return c.text("Not found", 404);
|
|
26888
27240
|
}
|
|
26889
|
-
const filePath =
|
|
26890
|
-
const expectedDir =
|
|
27241
|
+
const filePath = resolve36(account.accountDir, "agents", slug, "assets", filename);
|
|
27242
|
+
const expectedDir = resolve36(account.accountDir, "agents", slug, "assets");
|
|
26891
27243
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
26892
27244
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
26893
27245
|
return c.text("Forbidden", 403);
|
|
@@ -26916,8 +27268,8 @@ app62.get("/generated/:filename", (c) => {
|
|
|
26916
27268
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
26917
27269
|
return c.text("Not found", 404);
|
|
26918
27270
|
}
|
|
26919
|
-
const filePath =
|
|
26920
|
-
const expectedDir =
|
|
27271
|
+
const filePath = resolve36(account.accountDir, "generated", filename);
|
|
27272
|
+
const expectedDir = resolve36(account.accountDir, "generated");
|
|
26921
27273
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
26922
27274
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
26923
27275
|
return c.text("Forbidden", 403);
|
|
@@ -26971,11 +27323,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
26971
27323
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
26972
27324
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
26973
27325
|
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
26974
|
-
(p) => existsSync36(
|
|
27326
|
+
(p) => existsSync36(resolve36(process.cwd(), "public", p.replace(/^\//, "")))
|
|
26975
27327
|
);
|
|
26976
27328
|
var SW_SOURCE = (() => {
|
|
26977
27329
|
try {
|
|
26978
|
-
return readFileSync38(
|
|
27330
|
+
return readFileSync38(resolve36(process.cwd(), "public", "sw.js"), "utf-8");
|
|
26979
27331
|
} catch {
|
|
26980
27332
|
return null;
|
|
26981
27333
|
}
|
|
@@ -27026,7 +27378,7 @@ var clientErrorReporterScript = `<script>
|
|
|
27026
27378
|
function cachedHtml(file) {
|
|
27027
27379
|
let html = htmlCache.get(file);
|
|
27028
27380
|
if (!html) {
|
|
27029
|
-
html = readFileSync38(
|
|
27381
|
+
html = readFileSync38(resolve36(process.cwd(), "public", file), "utf-8");
|
|
27030
27382
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
27031
27383
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
27032
27384
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -27144,7 +27496,7 @@ app62.use("/vnc-popout.html", logViewerFetch);
|
|
|
27144
27496
|
app62.get("/vnc-popout.html", (c) => {
|
|
27145
27497
|
let html = htmlCache.get("vnc-popout.html");
|
|
27146
27498
|
if (!html) {
|
|
27147
|
-
html = readFileSync38(
|
|
27499
|
+
html = readFileSync38(resolve36(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
27148
27500
|
const name = escapeHtml(BRAND.productName);
|
|
27149
27501
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
27150
27502
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -27277,7 +27629,7 @@ var httpServer = serve({ fetch: app62.fetch, port, hostname });
|
|
|
27277
27629
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
27278
27630
|
{
|
|
27279
27631
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27280
|
-
const reconcileScript =
|
|
27632
|
+
const reconcileScript = resolve36(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
27281
27633
|
const RECONCILE_INTERVAL_MS = 12e4;
|
|
27282
27634
|
const runReconcile = () => {
|
|
27283
27635
|
if (!existsSync36(reconcileScript)) return;
|
|
@@ -27299,7 +27651,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27299
27651
|
}
|
|
27300
27652
|
{
|
|
27301
27653
|
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27302
|
-
const outlookScript =
|
|
27654
|
+
const outlookScript = resolve36(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
27303
27655
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
27304
27656
|
const runOutlookComplete = () => {
|
|
27305
27657
|
if (!existsSync36(outlookScript)) return;
|
|
@@ -27321,7 +27673,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27321
27673
|
}
|
|
27322
27674
|
{
|
|
27323
27675
|
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27324
|
-
const strandedAccountsDir =
|
|
27676
|
+
const strandedAccountsDir = resolve36(auditRoot, "..", "data/accounts");
|
|
27325
27677
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
27326
27678
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
27327
27679
|
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 +27683,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27331
27683
|
const now = Date.now();
|
|
27332
27684
|
for (const name of readdirSync21(strandedAccountsDir)) {
|
|
27333
27685
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
27334
|
-
const pendingPath2 =
|
|
27686
|
+
const pendingPath2 = resolve36(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
27335
27687
|
if (!existsSync36(pendingPath2)) continue;
|
|
27336
27688
|
const ageMs = now - statSync14(pendingPath2).mtimeMs;
|
|
27337
27689
|
if (ageMs > STRANDED_AGE_MS) {
|
|
@@ -27359,10 +27711,19 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27359
27711
|
auditFirst.unref();
|
|
27360
27712
|
const auditLoop = setInterval(runStorageAuditSafe, STORAGE_AUDIT_INTERVAL_MS);
|
|
27361
27713
|
auditLoop.unref();
|
|
27714
|
+
const runPagesAuditSafe = () => {
|
|
27715
|
+
runPagesAudit(auditPlatformRoot).catch(
|
|
27716
|
+
(err) => console.error(`[pages-audit] error="${err.message}"`)
|
|
27717
|
+
);
|
|
27718
|
+
};
|
|
27719
|
+
const pagesAuditFirst = setTimeout(runPagesAuditSafe, 35e3);
|
|
27720
|
+
pagesAuditFirst.unref();
|
|
27721
|
+
const pagesAuditLoop = setInterval(runPagesAuditSafe, STORAGE_AUDIT_INTERVAL_MS);
|
|
27722
|
+
pagesAuditLoop.unref();
|
|
27362
27723
|
}
|
|
27363
27724
|
{
|
|
27364
27725
|
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27365
|
-
const publishScript =
|
|
27726
|
+
const publishScript = resolve36(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
27366
27727
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
27367
27728
|
const currentAccount = () => {
|
|
27368
27729
|
try {
|
|
@@ -27391,7 +27752,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27391
27752
|
}
|
|
27392
27753
|
};
|
|
27393
27754
|
const auditSnapshotAge = (account) => {
|
|
27394
|
-
const availPath =
|
|
27755
|
+
const availPath = resolve36(account.accountDir, "calendar-availability.json");
|
|
27395
27756
|
let hasBookingSite = false;
|
|
27396
27757
|
try {
|
|
27397
27758
|
if (existsSync36(availPath)) {
|
|
@@ -27401,7 +27762,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27401
27762
|
} catch {
|
|
27402
27763
|
}
|
|
27403
27764
|
if (!hasBookingSite) return;
|
|
27404
|
-
const statePath =
|
|
27765
|
+
const statePath = resolve36(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
27405
27766
|
let lastSuccessAt = null;
|
|
27406
27767
|
if (existsSync36(statePath)) {
|
|
27407
27768
|
try {
|
|
@@ -27430,7 +27791,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27430
27791
|
startTimeEntryCensus(() => getSession());
|
|
27431
27792
|
{
|
|
27432
27793
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..");
|
|
27433
|
-
const auditScript =
|
|
27794
|
+
const auditScript = resolve36(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
27434
27795
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
27435
27796
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
27436
27797
|
const runConnectorAudit = () => {
|
|
@@ -27699,7 +28060,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
27699
28060
|
}
|
|
27700
28061
|
init({
|
|
27701
28062
|
configDir: configDirForWhatsApp,
|
|
27702
|
-
platformRoot:
|
|
28063
|
+
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, "..")),
|
|
27703
28064
|
accountConfig: bootAccountConfig,
|
|
27704
28065
|
onMessage: async (msg) => {
|
|
27705
28066
|
if (msg.isOwnerMirror) {
|