@rubytech/create-maxy-code 0.1.547 → 0.1.548
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +14 -0
- package/package.json +1 -1
- package/payload/platform/lib/routine-templates/dist/index.d.ts +22 -16
- package/payload/platform/lib/routine-templates/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/dist/index.js +15 -10
- package/payload/platform/lib/routine-templates/dist/index.js.map +1 -1
- package/payload/platform/lib/routine-templates/dist/roster.d.ts +3 -3
- package/payload/platform/lib/routine-templates/dist/roster.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/src/__tests__/seed.test.ts +15 -11
- package/payload/platform/lib/routine-templates/src/index.ts +23 -17
- package/payload/platform/lib/routine-templates/src/roster.ts +3 -3
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +41 -9
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +40 -8
- package/payload/platform/plugins/scheduling/PLUGIN.md +6 -0
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +6 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.js +54 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.d.ts +17 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.js +43 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.js +87 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.js +123 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +36 -0
- 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 +89 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +13 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.d.ts +35 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.js +56 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.js +80 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts +2 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +19 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
- package/payload/platform/plugins/telegram/PLUGIN.md +2 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js +47 -47
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.d.ts +16 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.js +50 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.d.ts +8 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.js +12 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.js.map +1 -0
- package/payload/platform/plugins/telegram/references/setup-guide.md +2 -0
- package/payload/platform/plugins/telegram/skills/configure/SKILL.md +6 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +8 -3
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +10 -3
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/server.js +1 -1
- package/payload/platform/services/telegram-channel/dist/server.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/turn-follow.js +33 -1
- package/payload/platform/services/telegram-channel/dist/turn-follow.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +8 -3
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +10 -3
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.js +33 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +28 -4
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +30 -7
- package/payload/platform/services/whatsapp-channel/dist/notification.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 +13 -5
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +2 -0
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.js +14 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.js +34 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.js.map +1 -1
- package/payload/server/{chunk-MHNHG3GL.js → chunk-G6ULACHG.js} +1 -1
- package/payload/server/{chunk-Q33KT7YJ.js → chunk-JOVREC6E.js} +117 -1
- package/payload/server/{chunk-WGMIUXXG.js → chunk-SKYZG6OT.js} +11 -0
- package/payload/server/{manager-W32LVPCT.js → manager-2VEJKVEO.js} +2 -2
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/public/assets/routines-OGFXwTFO.js +2 -0
- package/payload/server/public/assets/routines-OGFXwTFO.js.br +0 -0
- package/payload/server/public/assets/routines-OGFXwTFO.js.gz +0 -0
- package/payload/server/public/routines.html +1 -1
- package/payload/server/server.js +278 -169
- package/payload/server/public/assets/routines-Ds0yz7_C.js +0 -2
- package/payload/server/public/assets/routines-Ds0yz7_C.js.br +0 -0
- package/payload/server/public/assets/routines-Ds0yz7_C.js.gz +0 -0
package/payload/server/server.js
CHANGED
|
@@ -4,10 +4,14 @@ import {
|
|
|
4
4
|
HTTPException,
|
|
5
5
|
Hono,
|
|
6
6
|
HtmlEscapedCallbackPhase,
|
|
7
|
+
MANIFEST_CONTENT_TYPE,
|
|
7
8
|
PUBLIC_ALLOWED_EXACT,
|
|
8
9
|
PUBLIC_ALLOWED_PREFIXES,
|
|
10
|
+
PWA_SURFACES,
|
|
11
|
+
SW_CONTENT_TYPE,
|
|
9
12
|
accessPasswordCollides,
|
|
10
13
|
autoDeliverPremiumPlugins,
|
|
14
|
+
buildManifest,
|
|
11
15
|
canAccessAdmin,
|
|
12
16
|
checkRateLimit,
|
|
13
17
|
classifyHost,
|
|
@@ -33,9 +37,13 @@ import {
|
|
|
33
37
|
isOperatorHost,
|
|
34
38
|
isPasswordValid,
|
|
35
39
|
isPublicPathAllowed,
|
|
40
|
+
isRemoteAuthBypassPath,
|
|
36
41
|
isRemoteAuthConfigured,
|
|
37
42
|
migrateLegacyRemotePassword,
|
|
38
43
|
parseScreencastEvent,
|
|
44
|
+
pwaCensus,
|
|
45
|
+
pwaHeadTags,
|
|
46
|
+
pwaSurfaceForShell,
|
|
39
47
|
reconcileEnabledPluginsForAccounts,
|
|
40
48
|
recordFailedAttempt,
|
|
41
49
|
registerSession,
|
|
@@ -62,7 +70,7 @@ import {
|
|
|
62
70
|
verifyRemotePassword,
|
|
63
71
|
vncLog,
|
|
64
72
|
walkPremiumBundles
|
|
65
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-JOVREC6E.js";
|
|
66
74
|
import {
|
|
67
75
|
ACCOUNTS_ROOT,
|
|
68
76
|
DATA_ROOT,
|
|
@@ -203,7 +211,7 @@ import {
|
|
|
203
211
|
waitForConnection,
|
|
204
212
|
warnNonUuidAccount,
|
|
205
213
|
writeChatMetadataMerged
|
|
206
|
-
} from "./chunk-
|
|
214
|
+
} from "./chunk-G6ULACHG.js";
|
|
207
215
|
import {
|
|
208
216
|
ACCOUNTS_DIR,
|
|
209
217
|
AGENT_SLUG_PATTERN,
|
|
@@ -230,6 +238,7 @@ import {
|
|
|
230
238
|
deleteAgentProjection,
|
|
231
239
|
deleteConversation,
|
|
232
240
|
embed,
|
|
241
|
+
embedForWrite,
|
|
233
242
|
ensureConversation,
|
|
234
243
|
ensureSessionConversation,
|
|
235
244
|
fetchAccountName,
|
|
@@ -267,7 +276,7 @@ import {
|
|
|
267
276
|
verifyAndGetConversationUpdatedAt,
|
|
268
277
|
verifyConversationOwnership,
|
|
269
278
|
writeAdminUserAndPerson
|
|
270
|
-
} from "./chunk-
|
|
279
|
+
} from "./chunk-SKYZG6OT.js";
|
|
271
280
|
import {
|
|
272
281
|
D1_MAX_SQL_STATEMENT_BYTES,
|
|
273
282
|
D1_QUERY_MAX_BODY_BYTES,
|
|
@@ -1827,10 +1836,10 @@ var require_dist6 = __commonJS({
|
|
|
1827
1836
|
});
|
|
1828
1837
|
|
|
1829
1838
|
// server/index.ts
|
|
1830
|
-
import { readFileSync as readFileSync47, existsSync as existsSync51, watchFile, readdirSync as readdirSync30, statSync as
|
|
1839
|
+
import { readFileSync as readFileSync47, existsSync as existsSync51, watchFile, readdirSync as readdirSync30, statSync as statSync27 } from "fs";
|
|
1831
1840
|
import { spawn as spawn3 } from "child_process";
|
|
1832
1841
|
import { createHash as createHash7 } from "crypto";
|
|
1833
|
-
import { resolve as resolve45, join as
|
|
1842
|
+
import { resolve as resolve45, join as join55, basename as basename18 } from "path";
|
|
1834
1843
|
import { homedir as homedir4 } from "os";
|
|
1835
1844
|
|
|
1836
1845
|
// server/lib/route-cache-watchers.ts
|
|
@@ -2637,99 +2646,6 @@ async function resolveNotifyAccountName(accountId, fetch2) {
|
|
|
2637
2646
|
return name;
|
|
2638
2647
|
}
|
|
2639
2648
|
|
|
2640
|
-
// app/lib/pwa.ts
|
|
2641
|
-
var PWA_SURFACES = [
|
|
2642
|
-
{
|
|
2643
|
-
surface: "admin",
|
|
2644
|
-
shellFile: "index.html",
|
|
2645
|
-
manifestPath: "/manifest-admin.webmanifest",
|
|
2646
|
-
nameSuffix: "",
|
|
2647
|
-
startUrl: "/",
|
|
2648
|
-
scope: "/",
|
|
2649
|
-
id: "/?pwa=admin"
|
|
2650
|
-
},
|
|
2651
|
-
{
|
|
2652
|
-
surface: "operator",
|
|
2653
|
-
shellFile: "operator.html",
|
|
2654
|
-
manifestPath: "/manifest-operator.webmanifest",
|
|
2655
|
-
nameSuffix: " Operator",
|
|
2656
|
-
startUrl: "/",
|
|
2657
|
-
scope: "/",
|
|
2658
|
-
id: "/?pwa=operator"
|
|
2659
|
-
},
|
|
2660
|
-
{
|
|
2661
|
-
surface: "chat",
|
|
2662
|
-
shellFile: "chat.html",
|
|
2663
|
-
manifestPath: "/manifest-chat.webmanifest",
|
|
2664
|
-
nameSuffix: " Chat",
|
|
2665
|
-
startUrl: "/chat",
|
|
2666
|
-
scope: "/chat",
|
|
2667
|
-
id: "/chat?pwa=chat"
|
|
2668
|
-
}
|
|
2669
|
-
];
|
|
2670
|
-
var MANIFEST_CONTENT_TYPE = "application/manifest+json";
|
|
2671
|
-
var SW_CONTENT_TYPE = "application/javascript";
|
|
2672
|
-
function pwaSurfaceForShell(file) {
|
|
2673
|
-
return PWA_SURFACES.find((s) => s.shellFile === file);
|
|
2674
|
-
}
|
|
2675
|
-
function buildManifest(s, b) {
|
|
2676
|
-
const name = `${b.productName}${s.nameSuffix}`;
|
|
2677
|
-
return {
|
|
2678
|
-
id: s.id,
|
|
2679
|
-
name,
|
|
2680
|
-
short_name: name,
|
|
2681
|
-
start_url: s.startUrl,
|
|
2682
|
-
scope: s.scope,
|
|
2683
|
-
display: "standalone",
|
|
2684
|
-
theme_color: b.themeColor,
|
|
2685
|
-
background_color: b.backgroundColor,
|
|
2686
|
-
// Explicit 192/512 `any` icons (iOS/macOS composite transparency onto black,
|
|
2687
|
-
// so these are opaque) plus a wider-safe-zone `maskable` entry for Android's
|
|
2688
|
-
// circular crop. background_color sets only the splash; the tile background
|
|
2689
|
-
// is baked into the PNGs.
|
|
2690
|
-
icons: [
|
|
2691
|
-
{ src: b.appIcon192, sizes: "192x192", purpose: "any" },
|
|
2692
|
-
{ src: b.appIcon512, sizes: "512x512", purpose: "any" },
|
|
2693
|
-
{ src: b.maskableIcon, sizes: "512x512", purpose: "maskable" }
|
|
2694
|
-
]
|
|
2695
|
-
};
|
|
2696
|
-
}
|
|
2697
|
-
function escAttr(s) {
|
|
2698
|
-
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
2699
|
-
}
|
|
2700
|
-
function swRegisterScript(s) {
|
|
2701
|
-
return [
|
|
2702
|
-
"<script>",
|
|
2703
|
-
"if('serviceWorker' in navigator){navigator.serviceWorker.register('/sw.js').catch(function(e){",
|
|
2704
|
-
`try{fetch('/api/_client-error',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({kind:'event',source:'pwa',op:'sw-register-fail',surface:'${s.surface}',scope:'${s.scope}',err:String((e&&e.message)||e)}),keepalive:true}).catch(function(){});}catch(_){}`,
|
|
2705
|
-
"});}",
|
|
2706
|
-
"</script>"
|
|
2707
|
-
].join("\n");
|
|
2708
|
-
}
|
|
2709
|
-
function installHeadLines(manifestPath, b) {
|
|
2710
|
-
return [
|
|
2711
|
-
`<link rel="manifest" href="${escAttr(manifestPath)}">`,
|
|
2712
|
-
`<link rel="apple-touch-icon" href="${escAttr(b.appleTouchIcon)}">`,
|
|
2713
|
-
// Both the standards-based and the legacy Apple capable meta: Chromium
|
|
2714
|
-
// deprecates `apple-mobile-web-app-capable` in favour of
|
|
2715
|
-
// `mobile-web-app-capable`, while iOS Safari still reads the apple one.
|
|
2716
|
-
'<meta name="mobile-web-app-capable" content="yes">',
|
|
2717
|
-
'<meta name="apple-mobile-web-app-capable" content="yes">',
|
|
2718
|
-
`<meta name="theme-color" content="${escAttr(b.themeColor)}">`
|
|
2719
|
-
];
|
|
2720
|
-
}
|
|
2721
|
-
function pwaHeadTags(s, b) {
|
|
2722
|
-
return [...installHeadLines(s.manifestPath, b), swRegisterScript(s)].join("\n");
|
|
2723
|
-
}
|
|
2724
|
-
function pwaCensus(d) {
|
|
2725
|
-
const manifestLinked = PWA_SURFACES.filter((s) => {
|
|
2726
|
-
const html = d.shellHtml(s.shellFile);
|
|
2727
|
-
return html != null && html.includes(`"${s.manifestPath}"`);
|
|
2728
|
-
}).length;
|
|
2729
|
-
const iconsPresent = d.iconExists() ? PWA_SURFACES.length : 0;
|
|
2730
|
-
return { surfaces: PWA_SURFACES.length, manifestLinked, iconsPresent };
|
|
2731
|
-
}
|
|
2732
|
-
|
|
2733
2649
|
// server/webchat-descriptor.ts
|
|
2734
2650
|
import { resolve as resolve2, join as join4 } from "path";
|
|
2735
2651
|
function webchatGatewayUrl() {
|
|
@@ -4157,11 +4073,11 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
|
4157
4073
|
} catch {
|
|
4158
4074
|
return null;
|
|
4159
4075
|
}
|
|
4160
|
-
const
|
|
4076
|
+
const basename19 = `${sessionId}.jsonl`;
|
|
4161
4077
|
for (const slug of slugs) {
|
|
4162
|
-
const live = join7(projectsRoot, slug,
|
|
4078
|
+
const live = join7(projectsRoot, slug, basename19);
|
|
4163
4079
|
if (existsSync3(live)) return live;
|
|
4164
|
-
const archived = join7(projectsRoot, slug, "archive",
|
|
4080
|
+
const archived = join7(projectsRoot, slug, "archive", basename19);
|
|
4165
4081
|
if (existsSync3(archived)) return archived;
|
|
4166
4082
|
}
|
|
4167
4083
|
return null;
|
|
@@ -4947,15 +4863,24 @@ function createScheduleInjectRoutes(deps) {
|
|
|
4947
4863
|
console.error(`${TAG5} op=inject-spawn eventId=${eventId} sessionId=${sessionId2} result=ok status=-`);
|
|
4948
4864
|
return c.json({ ok: true, sessionKey: sessionId2, ...transcriptBoundary(sessionId2) }, 200);
|
|
4949
4865
|
}
|
|
4950
|
-
const
|
|
4866
|
+
const resolution = deps.telegramAccountForDestination(destination);
|
|
4867
|
+
if (resolution.kind === "none") {
|
|
4868
|
+
console.error(`${TAG5} op=schedule-telegram-reject eventId=${eventId} destination=${destination} reason=unresolved-effective-account`);
|
|
4869
|
+
return c.json({ ok: false, error: "unresolved-effective-account" }, 403);
|
|
4870
|
+
}
|
|
4871
|
+
if (resolution.kind === "ambiguous") {
|
|
4872
|
+
console.error(`${TAG5} op=telegram-destination-ambiguous eventId=${eventId} destination=${destination} accounts=${resolution.count} dispatched=no`);
|
|
4873
|
+
return c.json({ ok: false, error: "telegram-destination-ambiguous" }, 403);
|
|
4874
|
+
}
|
|
4875
|
+
const effectiveAccount = resolution.accountId;
|
|
4951
4876
|
console.error(`${TAG5} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount}`);
|
|
4952
4877
|
if (eventAccountId === null || eventAccountId !== effectiveAccount) {
|
|
4953
4878
|
console.error(`${TAG5} op=event-account-scope-mismatch eventId=${eventId} eventAccount=${eventAccountId ?? "-"} effectiveAccount=${effectiveAccount} destination=${destination} dispatched=no`);
|
|
4954
4879
|
return c.json({ ok: false, error: "event-account-scope-mismatch" }, 403);
|
|
4955
4880
|
}
|
|
4956
|
-
const botToken =
|
|
4881
|
+
const botToken = resolution.botToken;
|
|
4957
4882
|
if (!botToken) {
|
|
4958
|
-
console.error(`${TAG5} reject reason=no-admin-bot-token eventId=${eventId}`);
|
|
4883
|
+
console.error(`${TAG5} reject reason=no-admin-bot-token eventId=${eventId} accountId=${effectiveAccount}`);
|
|
4959
4884
|
return c.json({ ok: false, error: "no-admin-bot-token" }, 400);
|
|
4960
4885
|
}
|
|
4961
4886
|
const chatId = Number(destination);
|
|
@@ -4963,7 +4888,11 @@ function createScheduleInjectRoutes(deps) {
|
|
|
4963
4888
|
const reply = (text) => deps.sendTelegramText(botToken, chatId, text);
|
|
4964
4889
|
try {
|
|
4965
4890
|
await deps.tgHandleInbound({
|
|
4966
|
-
|
|
4891
|
+
// Task 2365 — the resolved account, not the house. After the
|
|
4892
|
+
// per-account webhook the bot IS that account's own, so transport and
|
|
4893
|
+
// session scope are one account and Telegram needs no
|
|
4894
|
+
// effectiveAccountId companion field the way WhatsApp does above.
|
|
4895
|
+
accountId: effectiveAccount,
|
|
4967
4896
|
senderId: destination,
|
|
4968
4897
|
chatId: destination,
|
|
4969
4898
|
role: "admin",
|
|
@@ -5086,7 +5015,7 @@ async function defaultHttpGet(url) {
|
|
|
5086
5015
|
}
|
|
5087
5016
|
}
|
|
5088
5017
|
async function defaultResolve(accountId) {
|
|
5089
|
-
const { resolveSocket: resolveSocket2 } = await import("./manager-
|
|
5018
|
+
const { resolveSocket: resolveSocket2 } = await import("./manager-2VEJKVEO.js");
|
|
5090
5019
|
return resolveSocket2(accountId);
|
|
5091
5020
|
}
|
|
5092
5021
|
async function fetchAvatar(accountId, jid, deps = {}) {
|
|
@@ -13044,9 +12973,9 @@ function configDirName() {
|
|
|
13044
12973
|
}
|
|
13045
12974
|
return ".maxy";
|
|
13046
12975
|
}
|
|
13047
|
-
function secretPath(botType) {
|
|
13048
|
-
const
|
|
13049
|
-
return resolve17(homedir2(), configDirName(),
|
|
12976
|
+
function secretPath(botType, accountId) {
|
|
12977
|
+
const stem = botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret";
|
|
12978
|
+
return resolve17(homedir2(), configDirName(), `${stem}.${accountId}`);
|
|
13050
12979
|
}
|
|
13051
12980
|
var app10 = new Hono();
|
|
13052
12981
|
app10.post("/", async (c) => {
|
|
@@ -13056,15 +12985,25 @@ app10.post("/", async (c) => {
|
|
|
13056
12985
|
console.error(`${TAG19} op=reject reason=missing-bot-param`);
|
|
13057
12986
|
return c.json({ ok: false }, 400);
|
|
13058
12987
|
}
|
|
13059
|
-
const
|
|
12988
|
+
const accountParam = c.req.query("account");
|
|
12989
|
+
if (!accountParam) {
|
|
12990
|
+
console.error(`${TAG19} op=reject reason=missing-account-param botType=${botType}`);
|
|
12991
|
+
return c.json({ ok: false }, 401);
|
|
12992
|
+
}
|
|
12993
|
+
const account = listValidAccounts().find((a) => a.accountId === accountParam) ?? null;
|
|
12994
|
+
if (!account) {
|
|
12995
|
+
console.error(`${TAG19} op=reject reason=bad-account botType=${botType}`);
|
|
12996
|
+
return c.json({ ok: false }, 401);
|
|
12997
|
+
}
|
|
12998
|
+
const sp = secretPath(botType, account.accountId);
|
|
13060
12999
|
if (!existsSync21(sp)) {
|
|
13061
|
-
console.error(`${TAG19} op=reject reason=no-secret-file botType=${botType}`);
|
|
13000
|
+
console.error(`${TAG19} op=reject reason=no-secret-file botType=${botType} accountId=${account.accountId}`);
|
|
13062
13001
|
return c.json({ ok: false }, 401);
|
|
13063
13002
|
}
|
|
13064
13003
|
const expected = readFileSync23(sp, "utf-8").trim();
|
|
13065
13004
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
13066
13005
|
if (got !== expected) {
|
|
13067
|
-
console.error(`${TAG19} op=reject reason=bad-secret botType=${botType}`);
|
|
13006
|
+
console.error(`${TAG19} op=reject reason=bad-secret botType=${botType} accountId=${account.accountId}`);
|
|
13068
13007
|
return c.json({ ok: false }, 401);
|
|
13069
13008
|
}
|
|
13070
13009
|
let update;
|
|
@@ -13073,11 +13012,6 @@ app10.post("/", async (c) => {
|
|
|
13073
13012
|
} catch {
|
|
13074
13013
|
return c.json({ ok: true }, 200);
|
|
13075
13014
|
}
|
|
13076
|
-
const account = resolveAccount();
|
|
13077
|
-
if (!account) {
|
|
13078
|
-
console.error(`${TAG19} op=reject reason=no-account`);
|
|
13079
|
-
return c.json({ ok: true }, 200);
|
|
13080
|
-
}
|
|
13081
13015
|
const decision = routeTelegramUpdate({ update, botType, config: account.config.telegram ?? {} });
|
|
13082
13016
|
if (decision.kind === "ignore") {
|
|
13083
13017
|
console.error(`${TAG19} op=ignore reason=${decision.reason}`);
|
|
@@ -24070,7 +24004,7 @@ var ROUTINE_COLS = `e.eventId AS eventId, e.name AS name, e.eventStatus AS event
|
|
|
24070
24004
|
e.timezone AS timezone, e.startDate AS startDate,
|
|
24071
24005
|
e.agentChannel AS agentChannel, e.agentDestination AS agentDestination, e.agentPrompt AS agentPrompt,
|
|
24072
24006
|
e.actionPlugin AS actionPlugin, e.actionTool AS actionTool, e.actionArgs AS actionArgs,
|
|
24073
|
-
e.notes AS notes, e.
|
|
24007
|
+
e.notes AS notes, e.description AS description,
|
|
24074
24008
|
e.lastDispatchResult AS lastDispatchResult, e.lastDispatchAt AS lastDispatchAt,
|
|
24075
24009
|
e.suspendedInBulk AS suspendedInBulk`;
|
|
24076
24010
|
function mapRoutine(r) {
|
|
@@ -24091,11 +24025,11 @@ function mapRoutine(r) {
|
|
|
24091
24025
|
actionTool: g("actionTool"),
|
|
24092
24026
|
actionArgs: g("actionArgs"),
|
|
24093
24027
|
notes: g("notes"),
|
|
24094
|
-
// Task
|
|
24095
|
-
//
|
|
24096
|
-
// it
|
|
24097
|
-
//
|
|
24098
|
-
|
|
24028
|
+
// Task 2361 — operator-writable, and the only caption any routines surface
|
|
24029
|
+
// shows. Never dispatched: agentPrompt is the text a fire sends. PATCH
|
|
24030
|
+
// accepts it below and stamps operatorEdited, which is what stops the next
|
|
24031
|
+
// roster version bump overwriting the operator's wording.
|
|
24032
|
+
description: g("description"),
|
|
24099
24033
|
lastDispatchResult: g("lastDispatchResult"),
|
|
24100
24034
|
lastDispatchAt: g("lastDispatchAt"),
|
|
24101
24035
|
// Task 2106 — on the wire so the page can gate Resume all on the set the
|
|
@@ -24391,23 +24325,29 @@ app51.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
24391
24325
|
console.error(`[admin:routines] op=patch id=${id82} fields=agentChannel+agentDestination outcome=rejected reason=invalid-channel channel=${body.agentChannel}`);
|
|
24392
24326
|
return c.json({ error: `Unknown dispatch channel "${body.agentChannel}".` }, 400);
|
|
24393
24327
|
}
|
|
24328
|
+
const describing = "description" in body;
|
|
24394
24329
|
let timezone = null;
|
|
24395
24330
|
let storedPrompt = null;
|
|
24396
24331
|
let storedRecurrence = null;
|
|
24397
24332
|
let storedActionPlugin = null;
|
|
24398
|
-
|
|
24333
|
+
let storedName = null;
|
|
24334
|
+
let storedDescription = null;
|
|
24335
|
+
if (typeof body.recurrence === "string" || binding || clearing || describing) {
|
|
24399
24336
|
const preSession = getSession();
|
|
24400
24337
|
try {
|
|
24401
24338
|
const pre = await preSession.run(
|
|
24402
24339
|
`MATCH (e:Event {eventId: $eventId, accountId: $accountId})
|
|
24403
24340
|
RETURN e.timezone AS timezone, e.agentPrompt AS agentPrompt,
|
|
24404
|
-
e.recurrence AS recurrence, e.actionPlugin AS actionPlugin
|
|
24341
|
+
e.recurrence AS recurrence, e.actionPlugin AS actionPlugin,
|
|
24342
|
+
e.name AS name, e.description AS description`,
|
|
24405
24343
|
{ eventId, accountId }
|
|
24406
24344
|
);
|
|
24407
24345
|
timezone = pre.records[0]?.get("timezone") ?? null;
|
|
24408
24346
|
storedPrompt = pre.records[0]?.get("agentPrompt") ?? null;
|
|
24409
24347
|
storedRecurrence = pre.records[0]?.get("recurrence") ?? null;
|
|
24410
24348
|
storedActionPlugin = pre.records[0]?.get("actionPlugin") ?? null;
|
|
24349
|
+
storedName = pre.records[0]?.get("name") ?? null;
|
|
24350
|
+
storedDescription = pre.records[0]?.get("description") ?? null;
|
|
24411
24351
|
} catch (err) {
|
|
24412
24352
|
const message = err instanceof Error ? err.message : String(err);
|
|
24413
24353
|
console.error(`[admin:routines] op=patch id=${id82} outcome=rejected reason=tz-read-fail err="${message}"`);
|
|
@@ -24475,6 +24415,27 @@ app51.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
24475
24415
|
setClauses.push("e.operatorEdited = $operatorEdited");
|
|
24476
24416
|
params.operatorEdited = (/* @__PURE__ */ new Date()).toISOString();
|
|
24477
24417
|
}
|
|
24418
|
+
if (describing) {
|
|
24419
|
+
const raw = body.description;
|
|
24420
|
+
if (typeof raw !== "string" && raw !== null) {
|
|
24421
|
+
console.error(`[admin:routines] op=patch id=${id82} fields=description outcome=rejected reason=not-a-string`);
|
|
24422
|
+
return c.json({ error: "A description must be text, or null to clear it." }, 400);
|
|
24423
|
+
}
|
|
24424
|
+
const next = typeof raw === "string" && raw.trim().length > 0 ? raw : null;
|
|
24425
|
+
setClauses.push("e.description = $description");
|
|
24426
|
+
params.description = next;
|
|
24427
|
+
fields.push("description");
|
|
24428
|
+
setClauses.push("e.operatorEdited = $operatorEdited");
|
|
24429
|
+
params.operatorEdited = (/* @__PURE__ */ new Date()).toISOString();
|
|
24430
|
+
if (next !== storedDescription) {
|
|
24431
|
+
const parts = [`Event: ${storedName ?? ""}`, next ?? ""].filter(Boolean);
|
|
24432
|
+
const embedding = await embedForWrite(parts.join(" \u2014 "));
|
|
24433
|
+
if (embedding.length > 0) {
|
|
24434
|
+
setClauses.push("e.embedding = $embedding");
|
|
24435
|
+
params.embedding = embedding;
|
|
24436
|
+
}
|
|
24437
|
+
}
|
|
24438
|
+
}
|
|
24478
24439
|
if (typeof body.recurrence === "string") {
|
|
24479
24440
|
try {
|
|
24480
24441
|
const interval = parseExpression(body.recurrence, { currentDate: /* @__PURE__ */ new Date(), tz: timezone ?? void 0 });
|
|
@@ -28790,18 +28751,23 @@ function createWaChannelRoutes(deps) {
|
|
|
28790
28751
|
if (typeof senderId !== "string" || typeof text !== "string") {
|
|
28791
28752
|
return c.json({ error: "senderId and text required" }, 400);
|
|
28792
28753
|
}
|
|
28754
|
+
const accountId = body?.accountId;
|
|
28755
|
+
if (typeof accountId !== "string" || accountId.length === 0) {
|
|
28756
|
+
console.error(`[whatsapp-native] op=reply-rejected senderId=${senderId} reason=no-account`);
|
|
28757
|
+
return c.json({ error: "accountId required" }, 400);
|
|
28758
|
+
}
|
|
28793
28759
|
const bytes = Buffer.byteLength(text, "utf8");
|
|
28794
28760
|
try {
|
|
28795
|
-
await deps.sendOutbound(senderId, text);
|
|
28761
|
+
await deps.sendOutbound(accountId, senderId, text);
|
|
28796
28762
|
} catch (err) {
|
|
28797
28763
|
const message = err instanceof Error ? err.message : String(err);
|
|
28798
28764
|
const terminal = err instanceof WaReplyError ? err.terminal : false;
|
|
28799
28765
|
console.error(
|
|
28800
|
-
`[whatsapp-native] op=reply-failed senderId=${senderId} bytes=${bytes} terminal=${terminal} error=${message}`
|
|
28766
|
+
`[whatsapp-native] op=reply-failed senderId=${senderId} account=${accountId} bytes=${bytes} terminal=${terminal} error=${message}`
|
|
28801
28767
|
);
|
|
28802
28768
|
return c.json({ error: message, terminal }, 500);
|
|
28803
28769
|
}
|
|
28804
|
-
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
28770
|
+
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} account=${accountId} bytes=${bytes}`);
|
|
28805
28771
|
deps.onReplyDispatch?.(senderId, Date.now());
|
|
28806
28772
|
return c.json({ ok: true });
|
|
28807
28773
|
});
|
|
@@ -28813,13 +28779,18 @@ function createWaChannelRoutes(deps) {
|
|
|
28813
28779
|
if (typeof senderId !== "string" || !Array.isArray(files) || files.length === 0 || !files.every((f) => typeof f === "string")) {
|
|
28814
28780
|
return c.json({ error: "senderId and a non-empty files string array required" }, 400);
|
|
28815
28781
|
}
|
|
28782
|
+
const accountId = body?.accountId;
|
|
28783
|
+
if (typeof accountId !== "string" || accountId.length === 0) {
|
|
28784
|
+
console.error(`[whatsapp-native] op=reply-document-rejected senderId=${senderId} reason=no-account`);
|
|
28785
|
+
return c.json({ error: "accountId required" }, 400);
|
|
28786
|
+
}
|
|
28816
28787
|
const results = [];
|
|
28817
28788
|
for (let i = 0; i < files.length; i++) {
|
|
28818
28789
|
const file = files[i];
|
|
28819
28790
|
console.error(`[whatsapp-native] op=reply-document-request senderId=${senderId} file=${file}`);
|
|
28820
28791
|
let outcome;
|
|
28821
28792
|
try {
|
|
28822
|
-
outcome = await deps.sendDocument(senderId, file, i === 0 ? caption : void 0);
|
|
28793
|
+
outcome = await deps.sendDocument(accountId, senderId, file, i === 0 ? caption : void 0);
|
|
28823
28794
|
} catch (err) {
|
|
28824
28795
|
const message = err instanceof Error ? err.message : String(err);
|
|
28825
28796
|
const terminal = err instanceof WaReplyError ? err.terminal : false;
|
|
@@ -28899,6 +28870,11 @@ function createWaChannelRoutes(deps) {
|
|
|
28899
28870
|
if (typeof senderId !== "string" || typeof sessionId !== "string" || typeof replied !== "boolean") {
|
|
28900
28871
|
return c.json({ error: "senderId, sessionId and replied required" }, 400);
|
|
28901
28872
|
}
|
|
28873
|
+
const accountId = body?.accountId;
|
|
28874
|
+
if (typeof accountId !== "string" || accountId.length === 0) {
|
|
28875
|
+
console.error(`[whatsapp-native] op=turn-end-rejected senderId=${senderId} reason=no-account`);
|
|
28876
|
+
return c.json({ error: "accountId required" }, 400);
|
|
28877
|
+
}
|
|
28902
28878
|
const interactive = body?.interactive === true;
|
|
28903
28879
|
const finalText = typeof body?.finalText === "string" ? body.finalText : "";
|
|
28904
28880
|
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : -1;
|
|
@@ -28908,6 +28884,9 @@ function createWaChannelRoutes(deps) {
|
|
|
28908
28884
|
const consumed2 = num(body?.consumed);
|
|
28909
28885
|
const source = typeof body?.source === "string" ? body.source : null;
|
|
28910
28886
|
const sid = sessionId.slice(0, 8);
|
|
28887
|
+
console.error(
|
|
28888
|
+
`[whatsapp-native] op=turn-context sessionId=${sid} cacheReadTokens=${num(body?.cacheReadTokens)} inputTokens=${num(body?.inputTokens)} outputTokens=${num(body?.outputTokens)} thinkingBlocks=${num(body?.thinkingBlocks)} thinkingChars=${num(body?.thinkingChars)}`
|
|
28889
|
+
);
|
|
28911
28890
|
const deliver = interactive && !replied && finalText.trim().length > 0;
|
|
28912
28891
|
const decision = `sessionId=${sid} replied=${replied ? "yes" : "no"} interactive=${interactive ? "yes" : "no"} source=${source ?? "unset"} finalBytes=${finalBytes} queueDepth=${queueDepth} pendingTurns=${pendingTurns} consumed=${consumed2}`;
|
|
28913
28892
|
if (!replied && finalBytes > 0 && !deliver) {
|
|
@@ -28919,7 +28898,7 @@ function createWaChannelRoutes(deps) {
|
|
|
28919
28898
|
if (deliver) {
|
|
28920
28899
|
const bytes = Buffer.byteLength(finalText, "utf8");
|
|
28921
28900
|
try {
|
|
28922
|
-
await deps.sendOutbound(senderId, finalText);
|
|
28901
|
+
await deps.sendOutbound(accountId, senderId, finalText);
|
|
28923
28902
|
} catch (err) {
|
|
28924
28903
|
const message = err instanceof Error ? err.message : String(err);
|
|
28925
28904
|
console.error(
|
|
@@ -29003,6 +28982,13 @@ var WaGateway = class {
|
|
|
29003
28982
|
this.deps = deps;
|
|
29004
28983
|
}
|
|
29005
28984
|
hub = new InboundHub();
|
|
28985
|
+
// Task 2363 — keyed by (effective account, sender) through the same `hubKey`
|
|
28986
|
+
// the hub uses, never by the number alone. A phone bound to two accounts holds
|
|
28987
|
+
// one reply closure per account, and the last inbound used to overwrite the
|
|
28988
|
+
// other account's route, so an answer composed for one account went out on the
|
|
28989
|
+
// other's socket. The account is the EFFECTIVE session account, which is what
|
|
28990
|
+
// `hub.deliver` below keys on and what the channel server sends back: the
|
|
28991
|
+
// socket owner is not addressable by the requester.
|
|
29006
28992
|
replies = /* @__PURE__ */ new Map();
|
|
29007
28993
|
// Per-sender document-delivery context, set on every inbound. Its presence is
|
|
29008
28994
|
// the reply-only guard: a sender with no inbound has no context, so a file
|
|
@@ -29034,6 +29020,16 @@ var WaGateway = class {
|
|
|
29034
29020
|
mediaRaces = 0;
|
|
29035
29021
|
mediaRaceSenders = /* @__PURE__ */ new Set();
|
|
29036
29022
|
mediaStanzaExpired = 0;
|
|
29023
|
+
// Task 2363 — the outbound-account census, reset on every print. `sends` is
|
|
29024
|
+
// every sendOutbound call; `mismatched` is the subset that missed for
|
|
29025
|
+
// (account, sender) while ANOTHER account held a live route for that sender.
|
|
29026
|
+
// Before this task those sends succeeded on the other account's socket and
|
|
29027
|
+
// emitted no error, so nothing but a reconciliation count could see them; they
|
|
29028
|
+
// now throw, and this counts them at the point they are refused. A cold miss
|
|
29029
|
+
// (no route under any account) is deliberately excluded — it is an ordinary
|
|
29030
|
+
// reply to a sender with no conversation, not a crossed one.
|
|
29031
|
+
outboundSends = 0;
|
|
29032
|
+
outboundMismatched = 0;
|
|
29037
29033
|
/** Task 2110 — the WhatsApp manager reports that a non-audio media stanza for
|
|
29038
29034
|
* this sender has started downloading. The gateway cannot derive this itself:
|
|
29039
29035
|
* it first learns of the media when the completed inbound arrives, which is
|
|
@@ -29090,8 +29086,8 @@ var WaGateway = class {
|
|
|
29090
29086
|
routes() {
|
|
29091
29087
|
return createWaChannelRoutes({
|
|
29092
29088
|
hub: this.hub,
|
|
29093
|
-
sendOutbound: (senderId, text) => this.sendOutbound(senderId, text),
|
|
29094
|
-
sendDocument: (senderId, filePath, caption) => this.sendDocument(senderId, filePath, caption),
|
|
29089
|
+
sendOutbound: (accountId, senderId, text) => this.sendOutbound(accountId, senderId, text),
|
|
29090
|
+
sendDocument: (accountId, senderId, filePath, caption) => this.sendDocument(accountId, senderId, filePath, caption),
|
|
29095
29091
|
onReady: (accountId, senderId) => {
|
|
29096
29092
|
const count = this.hub.markReady(accountId, senderId, Date.now());
|
|
29097
29093
|
if (count > 0) {
|
|
@@ -29225,7 +29221,7 @@ var WaGateway = class {
|
|
|
29225
29221
|
const openable = input.media.filter((m) => m.type !== "audio");
|
|
29226
29222
|
const mediaField = openable.length > 0 ? `media=${openable.map((m) => m.type).join(",")} mediaPaths=${openable.map((m) => m.path).join(",")}` : input.media.some((m) => m.type === "audio") ? "media=audio mediaPath=transcribed" : "media=none";
|
|
29227
29223
|
const source = input.source ?? "user";
|
|
29228
|
-
this.replies.set(senderId, input.reply);
|
|
29224
|
+
this.replies.set(hubKey(input.effectiveAccountId, senderId), input.reply);
|
|
29229
29225
|
this.docContexts.set(senderId, { accountId: input.accountId, maxyAccountId: input.effectiveAccountId });
|
|
29230
29226
|
console.error(
|
|
29231
29227
|
`[whatsapp-native] op=doc-context senderId=${senderId} accountId=${input.accountId} maxyAccountId=${input.effectiveAccountId}`
|
|
@@ -29336,17 +29332,41 @@ var WaGateway = class {
|
|
|
29336
29332
|
input.role === "public" && input.personId ? input.personId : void 0
|
|
29337
29333
|
);
|
|
29338
29334
|
}
|
|
29339
|
-
async sendOutbound(senderId, text) {
|
|
29340
|
-
|
|
29341
|
-
|
|
29335
|
+
async sendOutbound(accountId, senderId, text) {
|
|
29336
|
+
this.outboundSends++;
|
|
29337
|
+
const reply = this.replies.get(hubKey(accountId, senderId));
|
|
29338
|
+
if (!reply) {
|
|
29339
|
+
const suffix = hubKey("", senderId);
|
|
29340
|
+
if ([...this.replies.keys()].some((k) => k.endsWith(suffix))) {
|
|
29341
|
+
this.outboundMismatched++;
|
|
29342
|
+
console.error(
|
|
29343
|
+
`[whatsapp-native] op=outbound-account-miss senderId=${senderId} requested=${accountId} held=other-account`
|
|
29344
|
+
);
|
|
29345
|
+
}
|
|
29346
|
+
throw new Error(`wa-gateway: no reply route for account ${accountId} sender ${senderId}`);
|
|
29347
|
+
}
|
|
29342
29348
|
await reply(text);
|
|
29343
29349
|
}
|
|
29350
|
+
/** Task 2363 — read and reset the outbound-account census. Printed on the
|
|
29351
|
+
* duplicate-sender audit tick; see server/index.ts. */
|
|
29352
|
+
takeOutboundAccountCensus() {
|
|
29353
|
+
const census = { sends: this.outboundSends, mismatched: this.outboundMismatched };
|
|
29354
|
+
this.outboundSends = 0;
|
|
29355
|
+
this.outboundMismatched = 0;
|
|
29356
|
+
return census;
|
|
29357
|
+
}
|
|
29344
29358
|
/** Deliver a file to a sender as a WhatsApp document. Throws `WaReplyError`
|
|
29345
29359
|
* (reply-only guard) when no inbound has registered a document context for
|
|
29346
29360
|
* the sender — file delivery is only ever a reply on a live conversation. */
|
|
29347
|
-
async sendDocument(senderId, filePath, caption) {
|
|
29361
|
+
async sendDocument(accountId, senderId, filePath, caption) {
|
|
29348
29362
|
const ctx = this.docContexts.get(senderId);
|
|
29349
29363
|
if (!ctx) throw new WaReplyError(`no conversation for sender ${senderId}`, false);
|
|
29364
|
+
if (ctx.maxyAccountId !== accountId) {
|
|
29365
|
+
console.error(
|
|
29366
|
+
`[whatsapp-native] op=document-account-mismatch senderId=${senderId} requested=${accountId} context=${ctx.maxyAccountId}`
|
|
29367
|
+
);
|
|
29368
|
+
throw new WaReplyError(`no conversation for sender ${senderId} on account ${accountId}`, false);
|
|
29369
|
+
}
|
|
29350
29370
|
return this.deps.sendDocument({ senderId, accountId: ctx.accountId, maxyAccountId: ctx.maxyAccountId, filePath, caption });
|
|
29351
29371
|
}
|
|
29352
29372
|
};
|
|
@@ -29782,6 +29802,10 @@ function createWebchatChannelRoutes(deps) {
|
|
|
29782
29802
|
const finalBytes = typeof body?.finalBytes === "number" && Number.isFinite(body.finalBytes) ? body.finalBytes : 0;
|
|
29783
29803
|
const k = key.slice(0, 8);
|
|
29784
29804
|
const sid = sessionId.slice(0, 8);
|
|
29805
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : -1;
|
|
29806
|
+
console.error(
|
|
29807
|
+
`[webchat-native] op=turn-context sessionId=${sid} cacheReadTokens=${num(body?.cacheReadTokens)} inputTokens=${num(body?.inputTokens)} outputTokens=${num(body?.outputTokens)} thinkingBlocks=${num(body?.thinkingBlocks)} thinkingChars=${num(body?.thinkingChars)}`
|
|
29808
|
+
);
|
|
29785
29809
|
const repliedField = role === "public" ? ` replied=${replied ? "yes" : "no"}` : "";
|
|
29786
29810
|
console.error(`[webchat-native] op=turn-end channel=webchat key=${k} role=${role} sessionId=${sid}${repliedField} trailing=${finalBytes}`);
|
|
29787
29811
|
if (role === "admin" && finalBytes === 0) {
|
|
@@ -30964,6 +30988,10 @@ function createTelegramChannelRoutes(deps) {
|
|
|
30964
30988
|
const interactive = body?.interactive === true;
|
|
30965
30989
|
const finalText = typeof body?.finalText === "string" ? body.finalText : "";
|
|
30966
30990
|
const sid = sessionId.slice(0, 8);
|
|
30991
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : -1;
|
|
30992
|
+
console.error(
|
|
30993
|
+
`[telegram-native] op=turn-context sessionId=${sid} cacheReadTokens=${num(body?.cacheReadTokens)} inputTokens=${num(body?.inputTokens)} outputTokens=${num(body?.outputTokens)} thinkingBlocks=${num(body?.thinkingBlocks)} thinkingChars=${num(body?.thinkingChars)}`
|
|
30994
|
+
);
|
|
30967
30995
|
const deliver = interactive && !replied && finalText.trim().length > 0;
|
|
30968
30996
|
if (deliver) {
|
|
30969
30997
|
const bytes = Buffer.byteLength(finalText, "utf8");
|
|
@@ -31585,6 +31613,50 @@ function runPublicAddressCollisionAudit(deps) {
|
|
|
31585
31613
|
);
|
|
31586
31614
|
}
|
|
31587
31615
|
|
|
31616
|
+
// server/telegram-audit.ts
|
|
31617
|
+
import { statSync as statSync25 } from "fs";
|
|
31618
|
+
import { basename as basename17, dirname as dirname17, join as join54 } from "path";
|
|
31619
|
+
function buildTelegramAuditLines(input) {
|
|
31620
|
+
const lines = [];
|
|
31621
|
+
for (const account of input.accounts) {
|
|
31622
|
+
const tg = account.telegram;
|
|
31623
|
+
if (!tg) continue;
|
|
31624
|
+
const botTypes = [];
|
|
31625
|
+
if (tg.adminBotToken) botTypes.push("admin");
|
|
31626
|
+
if (tg.publicBotToken) botTypes.push("public");
|
|
31627
|
+
if (botTypes.length === 0) continue;
|
|
31628
|
+
const last = input.lastInboundAt(account.accountId);
|
|
31629
|
+
const age = last === null ? "never" : String(input.now - last);
|
|
31630
|
+
for (const botType of botTypes) {
|
|
31631
|
+
const secretFile = input.secretFileExists(botType, account.accountId) ? "present" : "absent";
|
|
31632
|
+
lines.push(
|
|
31633
|
+
`[telegram-audit] op=configured accountId=${account.accountId} botType=${botType} secretFile=${secretFile} lastInboundAgeMs=${age}`
|
|
31634
|
+
);
|
|
31635
|
+
}
|
|
31636
|
+
}
|
|
31637
|
+
return lines;
|
|
31638
|
+
}
|
|
31639
|
+
function newestTelegramSessionByAccount() {
|
|
31640
|
+
const out = /* @__PURE__ */ new Map();
|
|
31641
|
+
const cfg = claudeConfigDir();
|
|
31642
|
+
if (!cfg) return out;
|
|
31643
|
+
const projectsRoot = join54(cfg, "projects");
|
|
31644
|
+
for (const { path } of enumerateJsonls(projectsRoot)) {
|
|
31645
|
+
const sessionId = basename17(path).replace(/\.jsonl$/, "");
|
|
31646
|
+
const meta = readSidecarMeta(join54(dirname17(path), `${sessionId}.meta.json`));
|
|
31647
|
+
if (meta.channel !== "telegram" || !meta.accountId) continue;
|
|
31648
|
+
let mtime;
|
|
31649
|
+
try {
|
|
31650
|
+
mtime = statSync25(path).mtimeMs;
|
|
31651
|
+
} catch {
|
|
31652
|
+
continue;
|
|
31653
|
+
}
|
|
31654
|
+
const prev = out.get(meta.accountId);
|
|
31655
|
+
if (prev === void 0 || mtime > prev) out.set(meta.accountId, mtime);
|
|
31656
|
+
}
|
|
31657
|
+
return out;
|
|
31658
|
+
}
|
|
31659
|
+
|
|
31588
31660
|
// app/lib/whatsapp/recall-store-backfill.ts
|
|
31589
31661
|
function backfillMisfiledRecords(params) {
|
|
31590
31662
|
const { houseAccountId, isTargetAccount } = params;
|
|
@@ -31666,7 +31738,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
31666
31738
|
|
|
31667
31739
|
// ../lib/entitlement/src/index.ts
|
|
31668
31740
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
31669
|
-
import { existsSync as existsSync50, readFileSync as readFileSync46, statSync as
|
|
31741
|
+
import { existsSync as existsSync50, readFileSync as readFileSync46, statSync as statSync26 } from "fs";
|
|
31670
31742
|
import { resolve as resolve44 } from "path";
|
|
31671
31743
|
|
|
31672
31744
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -31718,7 +31790,7 @@ function resolveEntitlement(brand, account) {
|
|
|
31718
31790
|
if (!existsSync50(entitlementPath)) {
|
|
31719
31791
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
31720
31792
|
}
|
|
31721
|
-
const stat11 =
|
|
31793
|
+
const stat11 = statSync26(entitlementPath);
|
|
31722
31794
|
const key = memoKey(stat11.mtimeMs, account);
|
|
31723
31795
|
if (memo && memo.key === key) {
|
|
31724
31796
|
return memo.result;
|
|
@@ -31906,7 +31978,7 @@ function clientFrom(c) {
|
|
|
31906
31978
|
}
|
|
31907
31979
|
installMediaDownloadGuard();
|
|
31908
31980
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
31909
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT6 ?
|
|
31981
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join55(PLATFORM_ROOT6, "config", "brand.json") : "";
|
|
31910
31982
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
31911
31983
|
if (BRAND_JSON_PATH && !existsSync51(BRAND_JSON_PATH)) {
|
|
31912
31984
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -31945,7 +32017,7 @@ var brandLoginOpts = {
|
|
|
31945
32017
|
appleTouchIconPath: brandAppIcon512Path,
|
|
31946
32018
|
themeColor: BRAND.defaultColors?.primary
|
|
31947
32019
|
};
|
|
31948
|
-
var ALIAS_DOMAINS_PATH =
|
|
32020
|
+
var ALIAS_DOMAINS_PATH = join55(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
31949
32021
|
function loadAliasDomains() {
|
|
31950
32022
|
try {
|
|
31951
32023
|
if (!existsSync51(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -32040,7 +32112,7 @@ var waGateway = new WaGateway({
|
|
|
32040
32112
|
sendToParty: (accountId, phone, text) => sendWhatsAppTextForRelay(accountId, phone, text),
|
|
32041
32113
|
resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
|
|
32042
32114
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
32043
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
32115
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
32044
32116
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
32045
32117
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
32046
32118
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -32055,7 +32127,7 @@ var waGateway = new WaGateway({
|
|
|
32055
32127
|
caption,
|
|
32056
32128
|
accountId,
|
|
32057
32129
|
maxyAccountId,
|
|
32058
|
-
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
32130
|
+
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, ".."))
|
|
32059
32131
|
});
|
|
32060
32132
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
32061
32133
|
},
|
|
@@ -32222,7 +32294,7 @@ function runDuplicateSenderAudit() {
|
|
|
32222
32294
|
try {
|
|
32223
32295
|
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
32224
32296
|
if (!configDir) return;
|
|
32225
|
-
const projectsRoot =
|
|
32297
|
+
const projectsRoot = join55(configDir, "projects");
|
|
32226
32298
|
const records = [];
|
|
32227
32299
|
for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
|
|
32228
32300
|
if (isSubagent || archived) continue;
|
|
@@ -32233,6 +32305,10 @@ function runDuplicateSenderAudit() {
|
|
|
32233
32305
|
}
|
|
32234
32306
|
logDuplicateSenderGroups(findDuplicateSenderGroups(records));
|
|
32235
32307
|
logCrossAccountSenderGroups(findCrossAccountSenderGroups(records));
|
|
32308
|
+
const outbound = waGateway.takeOutboundAccountCensus();
|
|
32309
|
+
console.error(
|
|
32310
|
+
`[whatsapp-native] op=outbound-account-mismatch sends=${outbound.sends} mismatched=${outbound.mismatched}`
|
|
32311
|
+
);
|
|
32236
32312
|
} catch (err) {
|
|
32237
32313
|
console.error(`[whatsapp-native] op=duplicate-sender-audit-error error=${err instanceof Error ? err.message : String(err)}`);
|
|
32238
32314
|
}
|
|
@@ -32435,7 +32511,26 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
32435
32511
|
// than returning the house id this closure used to be handed. See
|
|
32436
32512
|
// effective-account.ts for why `resolveAccount()` was the wrong side to move,
|
|
32437
32513
|
// and why the real dependencies are bound there rather than assembled here.
|
|
32438
|
-
effectiveAccountFor: resolveScheduledEffectiveAccountForInstall
|
|
32514
|
+
effectiveAccountFor: resolveScheduledEffectiveAccountForInstall,
|
|
32515
|
+
// Task 2365 — the account whose own telegram.adminUsers claims this chat id.
|
|
32516
|
+
// Reads the same list, through the same readChannelAdmins call, that
|
|
32517
|
+
// validateAgentDestination uses (agent-dispatch-rule), so the routine picker,
|
|
32518
|
+
// the save and this dispatch cannot disagree. Two claimants is reported to
|
|
32519
|
+
// the route and refused there, never picked between.
|
|
32520
|
+
telegramAccountForDestination: (destination) => {
|
|
32521
|
+
const asNumber = Number(destination);
|
|
32522
|
+
if (!Number.isInteger(asNumber)) return { kind: "none" };
|
|
32523
|
+
const claimants = listValidAccounts().filter(
|
|
32524
|
+
(a) => readChannelAdmins(a.accountDir, "telegram").adminUsers.includes(asNumber)
|
|
32525
|
+
);
|
|
32526
|
+
if (claimants.length === 0) return { kind: "none" };
|
|
32527
|
+
if (claimants.length > 1) return { kind: "ambiguous", count: claimants.length };
|
|
32528
|
+
return {
|
|
32529
|
+
kind: "one",
|
|
32530
|
+
accountId: claimants[0].accountId,
|
|
32531
|
+
botToken: claimants[0].config.telegram?.adminBotToken ?? null
|
|
32532
|
+
};
|
|
32533
|
+
}
|
|
32439
32534
|
});
|
|
32440
32535
|
app76.route("/api/channel/schedule-inject", scheduleInjectRoutes);
|
|
32441
32536
|
app76.use("*", clientIpMiddleware);
|
|
@@ -32710,15 +32805,10 @@ app76.post("/api/remote-auth/set-password", async (c) => {
|
|
|
32710
32805
|
});
|
|
32711
32806
|
app76.route("/api/_client-error", client_error_default);
|
|
32712
32807
|
console.log("[client-error-route] mounted");
|
|
32713
|
-
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
32714
32808
|
app76.use("*", async (c, next) => {
|
|
32715
32809
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32716
32810
|
const path = c.req.path;
|
|
32717
|
-
if (
|
|
32718
|
-
// origin) against the brand host with no admin cookie. It is public by
|
|
32719
|
-
// design — open slots only, no :Meeting detail — so it bypasses the gate
|
|
32720
|
-
// exactly like /brand/. The detail-leak guard lives in the route + its test.
|
|
32721
|
-
path === "/api/calendar/free-busy" || PWA_PUBLIC_PATHS.has(path)) {
|
|
32811
|
+
if (isRemoteAuthBypassPath(path)) {
|
|
32722
32812
|
await next();
|
|
32723
32813
|
return;
|
|
32724
32814
|
}
|
|
@@ -32903,7 +32993,7 @@ var SW_SOURCE = (() => {
|
|
|
32903
32993
|
function readInstalledVersion() {
|
|
32904
32994
|
try {
|
|
32905
32995
|
if (!PLATFORM_ROOT6) return "unknown";
|
|
32906
|
-
const versionFile =
|
|
32996
|
+
const versionFile = join55(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
|
|
32907
32997
|
if (!existsSync51(versionFile)) return "unknown";
|
|
32908
32998
|
const content = readFileSync47(versionFile, "utf-8").trim();
|
|
32909
32999
|
return content || "unknown";
|
|
@@ -32933,12 +33023,12 @@ ${clientErrorReporterScript}
|
|
|
32933
33023
|
return html;
|
|
32934
33024
|
}
|
|
32935
33025
|
function loadBrandingCache(agentSlug) {
|
|
32936
|
-
const configDir =
|
|
33026
|
+
const configDir = join55(homedir4(), BRAND.configDir);
|
|
32937
33027
|
try {
|
|
32938
33028
|
const verdict = resolvePublicAddressFromDisk(agentSlug);
|
|
32939
33029
|
const accountId = verdict.kind === "served" ? verdict.owner.accountId : getDefaultAccountId();
|
|
32940
33030
|
if (!accountId) return null;
|
|
32941
|
-
const cachePath =
|
|
33031
|
+
const cachePath = join55(configDir, "branding-cache", accountId, `${agentSlug}.json`);
|
|
32942
33032
|
if (!existsSync51(cachePath)) return null;
|
|
32943
33033
|
return JSON.parse(readFileSync47(cachePath, "utf-8"));
|
|
32944
33034
|
} catch {
|
|
@@ -33188,7 +33278,7 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
33188
33278
|
var httpServer = serve({ fetch: app76.fetch, port, hostname });
|
|
33189
33279
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
33190
33280
|
{
|
|
33191
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33281
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33192
33282
|
const reconcileScript = resolve45(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
33193
33283
|
const runReconcile = (ctx) => {
|
|
33194
33284
|
if (!existsSync51(reconcileScript)) return;
|
|
@@ -33211,7 +33301,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33211
33301
|
detached: true,
|
|
33212
33302
|
run: runReconcile
|
|
33213
33303
|
});
|
|
33214
|
-
const reconcileStatePath =
|
|
33304
|
+
const reconcileStatePath = join55(MAXY_DIR, "booking-reconcile-state.json");
|
|
33215
33305
|
registerLoop({
|
|
33216
33306
|
name: "calendar-reconcile-liveness",
|
|
33217
33307
|
intervalMs: 6e5,
|
|
@@ -33229,7 +33319,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33229
33319
|
}
|
|
33230
33320
|
{
|
|
33231
33321
|
const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
|
|
33232
|
-
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33322
|
+
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33233
33323
|
const dreamSweepScript = resolve45(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
|
|
33234
33324
|
registerLoop({
|
|
33235
33325
|
name: "dream-cycle-sweep",
|
|
@@ -33253,7 +33343,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33253
33343
|
});
|
|
33254
33344
|
}
|
|
33255
33345
|
{
|
|
33256
|
-
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33346
|
+
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33257
33347
|
const outlookScript = resolve45(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
33258
33348
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
33259
33349
|
const runOutlookComplete = (ctx) => {
|
|
@@ -33279,7 +33369,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33279
33369
|
});
|
|
33280
33370
|
}
|
|
33281
33371
|
{
|
|
33282
|
-
const auditRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33372
|
+
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33283
33373
|
const strandedAccountsDir = resolve45(auditRoot, "..", "data/accounts");
|
|
33284
33374
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
33285
33375
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
@@ -33292,7 +33382,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33292
33382
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
33293
33383
|
const pendingPath2 = resolve45(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
33294
33384
|
if (!existsSync51(pendingPath2)) continue;
|
|
33295
|
-
const ageMs2 = now -
|
|
33385
|
+
const ageMs2 = now - statSync27(pendingPath2).mtimeMs;
|
|
33296
33386
|
if (ageMs2 > STRANDED_AGE_MS) {
|
|
33297
33387
|
console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs2 / 1e3)}`);
|
|
33298
33388
|
}
|
|
@@ -33309,7 +33399,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33309
33399
|
});
|
|
33310
33400
|
}
|
|
33311
33401
|
{
|
|
33312
|
-
const googleRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33402
|
+
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33313
33403
|
const googleAccountsDir = resolve45(googleRoot, "..", "data/accounts");
|
|
33314
33404
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
33315
33405
|
const runGooglePendingAuditSafe = () => {
|
|
@@ -33353,7 +33443,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33353
33443
|
});
|
|
33354
33444
|
}
|
|
33355
33445
|
{
|
|
33356
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33446
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33357
33447
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
33358
33448
|
const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
|
|
33359
33449
|
console.error(`[storage-audit] error="${err.message}"`);
|
|
@@ -33385,6 +33475,25 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33385
33475
|
firstRunDelayMs: 5e4,
|
|
33386
33476
|
run: runDataPortalAuditSafe
|
|
33387
33477
|
});
|
|
33478
|
+
const runTelegramAudit = async () => {
|
|
33479
|
+
const accounts = listValidAccounts().map((a) => ({ accountId: a.accountId, telegram: a.config.telegram }));
|
|
33480
|
+
const configured = accounts.some((a) => a.telegram?.adminBotToken || a.telegram?.publicBotToken);
|
|
33481
|
+
if (!configured) return;
|
|
33482
|
+
const lastByAccount = newestTelegramSessionByAccount();
|
|
33483
|
+
const lines = buildTelegramAuditLines({
|
|
33484
|
+
accounts,
|
|
33485
|
+
secretFileExists: (botType, accountId) => existsSync51(secretPath(botType, accountId)),
|
|
33486
|
+
lastInboundAt: (accountId) => lastByAccount.get(accountId) ?? null,
|
|
33487
|
+
now: Date.now()
|
|
33488
|
+
});
|
|
33489
|
+
for (const line of lines) console.error(line);
|
|
33490
|
+
};
|
|
33491
|
+
registerLoop({
|
|
33492
|
+
name: "telegram-audit",
|
|
33493
|
+
intervalMs: STORAGE_AUDIT_INTERVAL_MS,
|
|
33494
|
+
firstRunDelayMs: 65e3,
|
|
33495
|
+
run: runTelegramAudit
|
|
33496
|
+
});
|
|
33388
33497
|
registerLoop({
|
|
33389
33498
|
name: "portal-uploads-pull",
|
|
33390
33499
|
intervalMs: PORTAL_UPLOADS_PULL_INTERVAL_MS,
|
|
@@ -33450,7 +33559,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33450
33559
|
});
|
|
33451
33560
|
}
|
|
33452
33561
|
{
|
|
33453
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33562
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33454
33563
|
const publishScript = resolve45(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
33455
33564
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
33456
33565
|
const bookingAccounts = () => {
|
|
@@ -33527,7 +33636,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33527
33636
|
startTimeEntryCensus(() => getSession());
|
|
33528
33637
|
startLedgerCensus(() => getSession());
|
|
33529
33638
|
{
|
|
33530
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33639
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33531
33640
|
const auditScript = resolve45(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
33532
33641
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
33533
33642
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
@@ -33738,8 +33847,8 @@ var runIngestAuditTick = () => {
|
|
|
33738
33847
|
},
|
|
33739
33848
|
agentExists: (accountId, slug) => {
|
|
33740
33849
|
if (!house) return false;
|
|
33741
|
-
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir :
|
|
33742
|
-
return existsSync51(
|
|
33850
|
+
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir : join55(ACCOUNTS_DIR, accountId);
|
|
33851
|
+
return existsSync51(join55(dir, "agents", slug, "config.json"));
|
|
33743
33852
|
}
|
|
33744
33853
|
});
|
|
33745
33854
|
} catch (err) {
|
|
@@ -33787,7 +33896,7 @@ registerLoop({
|
|
|
33787
33896
|
runPublicAddressCollisionAudit({
|
|
33788
33897
|
houseAccountId: () => resolveAccount()?.accountId ?? null,
|
|
33789
33898
|
activeSlugs: () => listValidAccounts().map((a) => {
|
|
33790
|
-
const agentsRoot =
|
|
33899
|
+
const agentsRoot = join55(a.accountDir, "agents");
|
|
33791
33900
|
if (!existsSync51(agentsRoot)) return { accountId: a.accountId, slugs: [] };
|
|
33792
33901
|
const slugs = readdirSync30(agentsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).filter((slug) => isActiveAgentSlug(a.accountDir, slug));
|
|
33793
33902
|
return { accountId: a.accountId, slugs };
|
|
@@ -33873,7 +33982,7 @@ try {
|
|
|
33873
33982
|
} catch (err) {
|
|
33874
33983
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
33875
33984
|
}
|
|
33876
|
-
var configDirForWhatsApp =
|
|
33985
|
+
var configDirForWhatsApp = basename18(MAXY_DIR) || ".maxy";
|
|
33877
33986
|
var bootAccount = resolveAccount();
|
|
33878
33987
|
if (bootAccount) {
|
|
33879
33988
|
migrateRemovedConfigKeys(bootAccount.accountDir);
|
|
@@ -33939,7 +34048,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
33939
34048
|
}
|
|
33940
34049
|
init({
|
|
33941
34050
|
configDir: configDirForWhatsApp,
|
|
33942
|
-
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
34051
|
+
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..")),
|
|
33943
34052
|
accountConfig: bootAccountConfig,
|
|
33944
34053
|
// Task 2074 — enrich with the sub-account name and fan out to every open
|
|
33945
34054
|
// admin SSE stream. Fire-and-forget: the manager's persist path must not
|