@rubytech/create-maxy-code 0.1.547 → 0.1.549
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 +2 -2
- 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 +48 -14
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +11 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +47 -13
- package/payload/platform/plugins/scheduling/PLUGIN.md +12 -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/scripts/check-routine-roster-doc.mjs +127 -0
- 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 +285 -170
- 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}`);
|
|
@@ -13123,6 +13057,12 @@ app10.post("/", async (c) => {
|
|
|
13123
13057
|
});
|
|
13124
13058
|
var telegram_default = app10;
|
|
13125
13059
|
|
|
13060
|
+
// server/telegram-mount.ts
|
|
13061
|
+
function mountTelegramRoutes(app77, telegramRoutes) {
|
|
13062
|
+
app77.route("/api/telegram", telegramRoutes);
|
|
13063
|
+
app77.route("/api/telegram/", telegramRoutes);
|
|
13064
|
+
}
|
|
13065
|
+
|
|
13126
13066
|
// server/routes/quickbooks.ts
|
|
13127
13067
|
import { join as join30 } from "path";
|
|
13128
13068
|
import { existsSync as existsSync22, readFileSync as readFileSync24, writeFileSync as writeFileSync9, mkdirSync as mkdirSync4, rmSync as rmSync3, renameSync as renameSync5 } from "fs";
|
|
@@ -24070,7 +24010,7 @@ var ROUTINE_COLS = `e.eventId AS eventId, e.name AS name, e.eventStatus AS event
|
|
|
24070
24010
|
e.timezone AS timezone, e.startDate AS startDate,
|
|
24071
24011
|
e.agentChannel AS agentChannel, e.agentDestination AS agentDestination, e.agentPrompt AS agentPrompt,
|
|
24072
24012
|
e.actionPlugin AS actionPlugin, e.actionTool AS actionTool, e.actionArgs AS actionArgs,
|
|
24073
|
-
e.notes AS notes, e.
|
|
24013
|
+
e.notes AS notes, e.description AS description,
|
|
24074
24014
|
e.lastDispatchResult AS lastDispatchResult, e.lastDispatchAt AS lastDispatchAt,
|
|
24075
24015
|
e.suspendedInBulk AS suspendedInBulk`;
|
|
24076
24016
|
function mapRoutine(r) {
|
|
@@ -24091,11 +24031,11 @@ function mapRoutine(r) {
|
|
|
24091
24031
|
actionTool: g("actionTool"),
|
|
24092
24032
|
actionArgs: g("actionArgs"),
|
|
24093
24033
|
notes: g("notes"),
|
|
24094
|
-
// Task
|
|
24095
|
-
//
|
|
24096
|
-
// it
|
|
24097
|
-
//
|
|
24098
|
-
|
|
24034
|
+
// Task 2361 — operator-writable, and the only caption any routines surface
|
|
24035
|
+
// shows. Never dispatched: agentPrompt is the text a fire sends. PATCH
|
|
24036
|
+
// accepts it below and stamps operatorEdited, which is what stops the next
|
|
24037
|
+
// roster version bump overwriting the operator's wording.
|
|
24038
|
+
description: g("description"),
|
|
24099
24039
|
lastDispatchResult: g("lastDispatchResult"),
|
|
24100
24040
|
lastDispatchAt: g("lastDispatchAt"),
|
|
24101
24041
|
// Task 2106 — on the wire so the page can gate Resume all on the set the
|
|
@@ -24391,23 +24331,29 @@ app51.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
24391
24331
|
console.error(`[admin:routines] op=patch id=${id82} fields=agentChannel+agentDestination outcome=rejected reason=invalid-channel channel=${body.agentChannel}`);
|
|
24392
24332
|
return c.json({ error: `Unknown dispatch channel "${body.agentChannel}".` }, 400);
|
|
24393
24333
|
}
|
|
24334
|
+
const describing = "description" in body;
|
|
24394
24335
|
let timezone = null;
|
|
24395
24336
|
let storedPrompt = null;
|
|
24396
24337
|
let storedRecurrence = null;
|
|
24397
24338
|
let storedActionPlugin = null;
|
|
24398
|
-
|
|
24339
|
+
let storedName = null;
|
|
24340
|
+
let storedDescription = null;
|
|
24341
|
+
if (typeof body.recurrence === "string" || binding || clearing || describing) {
|
|
24399
24342
|
const preSession = getSession();
|
|
24400
24343
|
try {
|
|
24401
24344
|
const pre = await preSession.run(
|
|
24402
24345
|
`MATCH (e:Event {eventId: $eventId, accountId: $accountId})
|
|
24403
24346
|
RETURN e.timezone AS timezone, e.agentPrompt AS agentPrompt,
|
|
24404
|
-
e.recurrence AS recurrence, e.actionPlugin AS actionPlugin
|
|
24347
|
+
e.recurrence AS recurrence, e.actionPlugin AS actionPlugin,
|
|
24348
|
+
e.name AS name, e.description AS description`,
|
|
24405
24349
|
{ eventId, accountId }
|
|
24406
24350
|
);
|
|
24407
24351
|
timezone = pre.records[0]?.get("timezone") ?? null;
|
|
24408
24352
|
storedPrompt = pre.records[0]?.get("agentPrompt") ?? null;
|
|
24409
24353
|
storedRecurrence = pre.records[0]?.get("recurrence") ?? null;
|
|
24410
24354
|
storedActionPlugin = pre.records[0]?.get("actionPlugin") ?? null;
|
|
24355
|
+
storedName = pre.records[0]?.get("name") ?? null;
|
|
24356
|
+
storedDescription = pre.records[0]?.get("description") ?? null;
|
|
24411
24357
|
} catch (err) {
|
|
24412
24358
|
const message = err instanceof Error ? err.message : String(err);
|
|
24413
24359
|
console.error(`[admin:routines] op=patch id=${id82} outcome=rejected reason=tz-read-fail err="${message}"`);
|
|
@@ -24475,6 +24421,27 @@ app51.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
24475
24421
|
setClauses.push("e.operatorEdited = $operatorEdited");
|
|
24476
24422
|
params.operatorEdited = (/* @__PURE__ */ new Date()).toISOString();
|
|
24477
24423
|
}
|
|
24424
|
+
if (describing) {
|
|
24425
|
+
const raw = body.description;
|
|
24426
|
+
if (typeof raw !== "string" && raw !== null) {
|
|
24427
|
+
console.error(`[admin:routines] op=patch id=${id82} fields=description outcome=rejected reason=not-a-string`);
|
|
24428
|
+
return c.json({ error: "A description must be text, or null to clear it." }, 400);
|
|
24429
|
+
}
|
|
24430
|
+
const next = typeof raw === "string" && raw.trim().length > 0 ? raw : null;
|
|
24431
|
+
setClauses.push("e.description = $description");
|
|
24432
|
+
params.description = next;
|
|
24433
|
+
fields.push("description");
|
|
24434
|
+
setClauses.push("e.operatorEdited = $operatorEdited");
|
|
24435
|
+
params.operatorEdited = (/* @__PURE__ */ new Date()).toISOString();
|
|
24436
|
+
if (next !== storedDescription) {
|
|
24437
|
+
const parts = [`Event: ${storedName ?? ""}`, next ?? ""].filter(Boolean);
|
|
24438
|
+
const embedding = await embedForWrite(parts.join(" \u2014 "));
|
|
24439
|
+
if (embedding.length > 0) {
|
|
24440
|
+
setClauses.push("e.embedding = $embedding");
|
|
24441
|
+
params.embedding = embedding;
|
|
24442
|
+
}
|
|
24443
|
+
}
|
|
24444
|
+
}
|
|
24478
24445
|
if (typeof body.recurrence === "string") {
|
|
24479
24446
|
try {
|
|
24480
24447
|
const interval = parseExpression(body.recurrence, { currentDate: /* @__PURE__ */ new Date(), tz: timezone ?? void 0 });
|
|
@@ -28790,18 +28757,23 @@ function createWaChannelRoutes(deps) {
|
|
|
28790
28757
|
if (typeof senderId !== "string" || typeof text !== "string") {
|
|
28791
28758
|
return c.json({ error: "senderId and text required" }, 400);
|
|
28792
28759
|
}
|
|
28760
|
+
const accountId = body?.accountId;
|
|
28761
|
+
if (typeof accountId !== "string" || accountId.length === 0) {
|
|
28762
|
+
console.error(`[whatsapp-native] op=reply-rejected senderId=${senderId} reason=no-account`);
|
|
28763
|
+
return c.json({ error: "accountId required" }, 400);
|
|
28764
|
+
}
|
|
28793
28765
|
const bytes = Buffer.byteLength(text, "utf8");
|
|
28794
28766
|
try {
|
|
28795
|
-
await deps.sendOutbound(senderId, text);
|
|
28767
|
+
await deps.sendOutbound(accountId, senderId, text);
|
|
28796
28768
|
} catch (err) {
|
|
28797
28769
|
const message = err instanceof Error ? err.message : String(err);
|
|
28798
28770
|
const terminal = err instanceof WaReplyError ? err.terminal : false;
|
|
28799
28771
|
console.error(
|
|
28800
|
-
`[whatsapp-native] op=reply-failed senderId=${senderId} bytes=${bytes} terminal=${terminal} error=${message}`
|
|
28772
|
+
`[whatsapp-native] op=reply-failed senderId=${senderId} account=${accountId} bytes=${bytes} terminal=${terminal} error=${message}`
|
|
28801
28773
|
);
|
|
28802
28774
|
return c.json({ error: message, terminal }, 500);
|
|
28803
28775
|
}
|
|
28804
|
-
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
28776
|
+
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} account=${accountId} bytes=${bytes}`);
|
|
28805
28777
|
deps.onReplyDispatch?.(senderId, Date.now());
|
|
28806
28778
|
return c.json({ ok: true });
|
|
28807
28779
|
});
|
|
@@ -28813,13 +28785,18 @@ function createWaChannelRoutes(deps) {
|
|
|
28813
28785
|
if (typeof senderId !== "string" || !Array.isArray(files) || files.length === 0 || !files.every((f) => typeof f === "string")) {
|
|
28814
28786
|
return c.json({ error: "senderId and a non-empty files string array required" }, 400);
|
|
28815
28787
|
}
|
|
28788
|
+
const accountId = body?.accountId;
|
|
28789
|
+
if (typeof accountId !== "string" || accountId.length === 0) {
|
|
28790
|
+
console.error(`[whatsapp-native] op=reply-document-rejected senderId=${senderId} reason=no-account`);
|
|
28791
|
+
return c.json({ error: "accountId required" }, 400);
|
|
28792
|
+
}
|
|
28816
28793
|
const results = [];
|
|
28817
28794
|
for (let i = 0; i < files.length; i++) {
|
|
28818
28795
|
const file = files[i];
|
|
28819
28796
|
console.error(`[whatsapp-native] op=reply-document-request senderId=${senderId} file=${file}`);
|
|
28820
28797
|
let outcome;
|
|
28821
28798
|
try {
|
|
28822
|
-
outcome = await deps.sendDocument(senderId, file, i === 0 ? caption : void 0);
|
|
28799
|
+
outcome = await deps.sendDocument(accountId, senderId, file, i === 0 ? caption : void 0);
|
|
28823
28800
|
} catch (err) {
|
|
28824
28801
|
const message = err instanceof Error ? err.message : String(err);
|
|
28825
28802
|
const terminal = err instanceof WaReplyError ? err.terminal : false;
|
|
@@ -28899,6 +28876,11 @@ function createWaChannelRoutes(deps) {
|
|
|
28899
28876
|
if (typeof senderId !== "string" || typeof sessionId !== "string" || typeof replied !== "boolean") {
|
|
28900
28877
|
return c.json({ error: "senderId, sessionId and replied required" }, 400);
|
|
28901
28878
|
}
|
|
28879
|
+
const accountId = body?.accountId;
|
|
28880
|
+
if (typeof accountId !== "string" || accountId.length === 0) {
|
|
28881
|
+
console.error(`[whatsapp-native] op=turn-end-rejected senderId=${senderId} reason=no-account`);
|
|
28882
|
+
return c.json({ error: "accountId required" }, 400);
|
|
28883
|
+
}
|
|
28902
28884
|
const interactive = body?.interactive === true;
|
|
28903
28885
|
const finalText = typeof body?.finalText === "string" ? body.finalText : "";
|
|
28904
28886
|
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : -1;
|
|
@@ -28908,6 +28890,9 @@ function createWaChannelRoutes(deps) {
|
|
|
28908
28890
|
const consumed2 = num(body?.consumed);
|
|
28909
28891
|
const source = typeof body?.source === "string" ? body.source : null;
|
|
28910
28892
|
const sid = sessionId.slice(0, 8);
|
|
28893
|
+
console.error(
|
|
28894
|
+
`[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)}`
|
|
28895
|
+
);
|
|
28911
28896
|
const deliver = interactive && !replied && finalText.trim().length > 0;
|
|
28912
28897
|
const decision = `sessionId=${sid} replied=${replied ? "yes" : "no"} interactive=${interactive ? "yes" : "no"} source=${source ?? "unset"} finalBytes=${finalBytes} queueDepth=${queueDepth} pendingTurns=${pendingTurns} consumed=${consumed2}`;
|
|
28913
28898
|
if (!replied && finalBytes > 0 && !deliver) {
|
|
@@ -28919,7 +28904,7 @@ function createWaChannelRoutes(deps) {
|
|
|
28919
28904
|
if (deliver) {
|
|
28920
28905
|
const bytes = Buffer.byteLength(finalText, "utf8");
|
|
28921
28906
|
try {
|
|
28922
|
-
await deps.sendOutbound(senderId, finalText);
|
|
28907
|
+
await deps.sendOutbound(accountId, senderId, finalText);
|
|
28923
28908
|
} catch (err) {
|
|
28924
28909
|
const message = err instanceof Error ? err.message : String(err);
|
|
28925
28910
|
console.error(
|
|
@@ -29003,6 +28988,13 @@ var WaGateway = class {
|
|
|
29003
28988
|
this.deps = deps;
|
|
29004
28989
|
}
|
|
29005
28990
|
hub = new InboundHub();
|
|
28991
|
+
// Task 2363 — keyed by (effective account, sender) through the same `hubKey`
|
|
28992
|
+
// the hub uses, never by the number alone. A phone bound to two accounts holds
|
|
28993
|
+
// one reply closure per account, and the last inbound used to overwrite the
|
|
28994
|
+
// other account's route, so an answer composed for one account went out on the
|
|
28995
|
+
// other's socket. The account is the EFFECTIVE session account, which is what
|
|
28996
|
+
// `hub.deliver` below keys on and what the channel server sends back: the
|
|
28997
|
+
// socket owner is not addressable by the requester.
|
|
29006
28998
|
replies = /* @__PURE__ */ new Map();
|
|
29007
28999
|
// Per-sender document-delivery context, set on every inbound. Its presence is
|
|
29008
29000
|
// the reply-only guard: a sender with no inbound has no context, so a file
|
|
@@ -29034,6 +29026,16 @@ var WaGateway = class {
|
|
|
29034
29026
|
mediaRaces = 0;
|
|
29035
29027
|
mediaRaceSenders = /* @__PURE__ */ new Set();
|
|
29036
29028
|
mediaStanzaExpired = 0;
|
|
29029
|
+
// Task 2363 — the outbound-account census, reset on every print. `sends` is
|
|
29030
|
+
// every sendOutbound call; `mismatched` is the subset that missed for
|
|
29031
|
+
// (account, sender) while ANOTHER account held a live route for that sender.
|
|
29032
|
+
// Before this task those sends succeeded on the other account's socket and
|
|
29033
|
+
// emitted no error, so nothing but a reconciliation count could see them; they
|
|
29034
|
+
// now throw, and this counts them at the point they are refused. A cold miss
|
|
29035
|
+
// (no route under any account) is deliberately excluded — it is an ordinary
|
|
29036
|
+
// reply to a sender with no conversation, not a crossed one.
|
|
29037
|
+
outboundSends = 0;
|
|
29038
|
+
outboundMismatched = 0;
|
|
29037
29039
|
/** Task 2110 — the WhatsApp manager reports that a non-audio media stanza for
|
|
29038
29040
|
* this sender has started downloading. The gateway cannot derive this itself:
|
|
29039
29041
|
* it first learns of the media when the completed inbound arrives, which is
|
|
@@ -29090,8 +29092,8 @@ var WaGateway = class {
|
|
|
29090
29092
|
routes() {
|
|
29091
29093
|
return createWaChannelRoutes({
|
|
29092
29094
|
hub: this.hub,
|
|
29093
|
-
sendOutbound: (senderId, text) => this.sendOutbound(senderId, text),
|
|
29094
|
-
sendDocument: (senderId, filePath, caption) => this.sendDocument(senderId, filePath, caption),
|
|
29095
|
+
sendOutbound: (accountId, senderId, text) => this.sendOutbound(accountId, senderId, text),
|
|
29096
|
+
sendDocument: (accountId, senderId, filePath, caption) => this.sendDocument(accountId, senderId, filePath, caption),
|
|
29095
29097
|
onReady: (accountId, senderId) => {
|
|
29096
29098
|
const count = this.hub.markReady(accountId, senderId, Date.now());
|
|
29097
29099
|
if (count > 0) {
|
|
@@ -29225,7 +29227,7 @@ var WaGateway = class {
|
|
|
29225
29227
|
const openable = input.media.filter((m) => m.type !== "audio");
|
|
29226
29228
|
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
29229
|
const source = input.source ?? "user";
|
|
29228
|
-
this.replies.set(senderId, input.reply);
|
|
29230
|
+
this.replies.set(hubKey(input.effectiveAccountId, senderId), input.reply);
|
|
29229
29231
|
this.docContexts.set(senderId, { accountId: input.accountId, maxyAccountId: input.effectiveAccountId });
|
|
29230
29232
|
console.error(
|
|
29231
29233
|
`[whatsapp-native] op=doc-context senderId=${senderId} accountId=${input.accountId} maxyAccountId=${input.effectiveAccountId}`
|
|
@@ -29336,17 +29338,41 @@ var WaGateway = class {
|
|
|
29336
29338
|
input.role === "public" && input.personId ? input.personId : void 0
|
|
29337
29339
|
);
|
|
29338
29340
|
}
|
|
29339
|
-
async sendOutbound(senderId, text) {
|
|
29340
|
-
|
|
29341
|
-
|
|
29341
|
+
async sendOutbound(accountId, senderId, text) {
|
|
29342
|
+
this.outboundSends++;
|
|
29343
|
+
const reply = this.replies.get(hubKey(accountId, senderId));
|
|
29344
|
+
if (!reply) {
|
|
29345
|
+
const suffix = hubKey("", senderId);
|
|
29346
|
+
if ([...this.replies.keys()].some((k) => k.endsWith(suffix))) {
|
|
29347
|
+
this.outboundMismatched++;
|
|
29348
|
+
console.error(
|
|
29349
|
+
`[whatsapp-native] op=outbound-account-miss senderId=${senderId} requested=${accountId} held=other-account`
|
|
29350
|
+
);
|
|
29351
|
+
}
|
|
29352
|
+
throw new Error(`wa-gateway: no reply route for account ${accountId} sender ${senderId}`);
|
|
29353
|
+
}
|
|
29342
29354
|
await reply(text);
|
|
29343
29355
|
}
|
|
29356
|
+
/** Task 2363 — read and reset the outbound-account census. Printed on the
|
|
29357
|
+
* duplicate-sender audit tick; see server/index.ts. */
|
|
29358
|
+
takeOutboundAccountCensus() {
|
|
29359
|
+
const census = { sends: this.outboundSends, mismatched: this.outboundMismatched };
|
|
29360
|
+
this.outboundSends = 0;
|
|
29361
|
+
this.outboundMismatched = 0;
|
|
29362
|
+
return census;
|
|
29363
|
+
}
|
|
29344
29364
|
/** Deliver a file to a sender as a WhatsApp document. Throws `WaReplyError`
|
|
29345
29365
|
* (reply-only guard) when no inbound has registered a document context for
|
|
29346
29366
|
* the sender — file delivery is only ever a reply on a live conversation. */
|
|
29347
|
-
async sendDocument(senderId, filePath, caption) {
|
|
29367
|
+
async sendDocument(accountId, senderId, filePath, caption) {
|
|
29348
29368
|
const ctx = this.docContexts.get(senderId);
|
|
29349
29369
|
if (!ctx) throw new WaReplyError(`no conversation for sender ${senderId}`, false);
|
|
29370
|
+
if (ctx.maxyAccountId !== accountId) {
|
|
29371
|
+
console.error(
|
|
29372
|
+
`[whatsapp-native] op=document-account-mismatch senderId=${senderId} requested=${accountId} context=${ctx.maxyAccountId}`
|
|
29373
|
+
);
|
|
29374
|
+
throw new WaReplyError(`no conversation for sender ${senderId} on account ${accountId}`, false);
|
|
29375
|
+
}
|
|
29350
29376
|
return this.deps.sendDocument({ senderId, accountId: ctx.accountId, maxyAccountId: ctx.maxyAccountId, filePath, caption });
|
|
29351
29377
|
}
|
|
29352
29378
|
};
|
|
@@ -29782,6 +29808,10 @@ function createWebchatChannelRoutes(deps) {
|
|
|
29782
29808
|
const finalBytes = typeof body?.finalBytes === "number" && Number.isFinite(body.finalBytes) ? body.finalBytes : 0;
|
|
29783
29809
|
const k = key.slice(0, 8);
|
|
29784
29810
|
const sid = sessionId.slice(0, 8);
|
|
29811
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : -1;
|
|
29812
|
+
console.error(
|
|
29813
|
+
`[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)}`
|
|
29814
|
+
);
|
|
29785
29815
|
const repliedField = role === "public" ? ` replied=${replied ? "yes" : "no"}` : "";
|
|
29786
29816
|
console.error(`[webchat-native] op=turn-end channel=webchat key=${k} role=${role} sessionId=${sid}${repliedField} trailing=${finalBytes}`);
|
|
29787
29817
|
if (role === "admin" && finalBytes === 0) {
|
|
@@ -30964,6 +30994,10 @@ function createTelegramChannelRoutes(deps) {
|
|
|
30964
30994
|
const interactive = body?.interactive === true;
|
|
30965
30995
|
const finalText = typeof body?.finalText === "string" ? body.finalText : "";
|
|
30966
30996
|
const sid = sessionId.slice(0, 8);
|
|
30997
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : -1;
|
|
30998
|
+
console.error(
|
|
30999
|
+
`[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)}`
|
|
31000
|
+
);
|
|
30967
31001
|
const deliver = interactive && !replied && finalText.trim().length > 0;
|
|
30968
31002
|
if (deliver) {
|
|
30969
31003
|
const bytes = Buffer.byteLength(finalText, "utf8");
|
|
@@ -31585,6 +31619,50 @@ function runPublicAddressCollisionAudit(deps) {
|
|
|
31585
31619
|
);
|
|
31586
31620
|
}
|
|
31587
31621
|
|
|
31622
|
+
// server/telegram-audit.ts
|
|
31623
|
+
import { statSync as statSync25 } from "fs";
|
|
31624
|
+
import { basename as basename17, dirname as dirname17, join as join54 } from "path";
|
|
31625
|
+
function buildTelegramAuditLines(input) {
|
|
31626
|
+
const lines = [];
|
|
31627
|
+
for (const account of input.accounts) {
|
|
31628
|
+
const tg = account.telegram;
|
|
31629
|
+
if (!tg) continue;
|
|
31630
|
+
const botTypes = [];
|
|
31631
|
+
if (tg.adminBotToken) botTypes.push("admin");
|
|
31632
|
+
if (tg.publicBotToken) botTypes.push("public");
|
|
31633
|
+
if (botTypes.length === 0) continue;
|
|
31634
|
+
const last = input.lastInboundAt(account.accountId);
|
|
31635
|
+
const age = last === null ? "never" : String(input.now - last);
|
|
31636
|
+
for (const botType of botTypes) {
|
|
31637
|
+
const secretFile = input.secretFileExists(botType, account.accountId) ? "present" : "absent";
|
|
31638
|
+
lines.push(
|
|
31639
|
+
`[telegram-audit] op=configured accountId=${account.accountId} botType=${botType} secretFile=${secretFile} lastInboundAgeMs=${age}`
|
|
31640
|
+
);
|
|
31641
|
+
}
|
|
31642
|
+
}
|
|
31643
|
+
return lines;
|
|
31644
|
+
}
|
|
31645
|
+
function newestTelegramSessionByAccount() {
|
|
31646
|
+
const out = /* @__PURE__ */ new Map();
|
|
31647
|
+
const cfg = claudeConfigDir();
|
|
31648
|
+
if (!cfg) return out;
|
|
31649
|
+
const projectsRoot = join54(cfg, "projects");
|
|
31650
|
+
for (const { path } of enumerateJsonls(projectsRoot)) {
|
|
31651
|
+
const sessionId = basename17(path).replace(/\.jsonl$/, "");
|
|
31652
|
+
const meta = readSidecarMeta(join54(dirname17(path), `${sessionId}.meta.json`));
|
|
31653
|
+
if (meta.channel !== "telegram" || !meta.accountId) continue;
|
|
31654
|
+
let mtime;
|
|
31655
|
+
try {
|
|
31656
|
+
mtime = statSync25(path).mtimeMs;
|
|
31657
|
+
} catch {
|
|
31658
|
+
continue;
|
|
31659
|
+
}
|
|
31660
|
+
const prev = out.get(meta.accountId);
|
|
31661
|
+
if (prev === void 0 || mtime > prev) out.set(meta.accountId, mtime);
|
|
31662
|
+
}
|
|
31663
|
+
return out;
|
|
31664
|
+
}
|
|
31665
|
+
|
|
31588
31666
|
// app/lib/whatsapp/recall-store-backfill.ts
|
|
31589
31667
|
function backfillMisfiledRecords(params) {
|
|
31590
31668
|
const { houseAccountId, isTargetAccount } = params;
|
|
@@ -31666,7 +31744,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
31666
31744
|
|
|
31667
31745
|
// ../lib/entitlement/src/index.ts
|
|
31668
31746
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
31669
|
-
import { existsSync as existsSync50, readFileSync as readFileSync46, statSync as
|
|
31747
|
+
import { existsSync as existsSync50, readFileSync as readFileSync46, statSync as statSync26 } from "fs";
|
|
31670
31748
|
import { resolve as resolve44 } from "path";
|
|
31671
31749
|
|
|
31672
31750
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -31718,7 +31796,7 @@ function resolveEntitlement(brand, account) {
|
|
|
31718
31796
|
if (!existsSync50(entitlementPath)) {
|
|
31719
31797
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
31720
31798
|
}
|
|
31721
|
-
const stat11 =
|
|
31799
|
+
const stat11 = statSync26(entitlementPath);
|
|
31722
31800
|
const key = memoKey(stat11.mtimeMs, account);
|
|
31723
31801
|
if (memo && memo.key === key) {
|
|
31724
31802
|
return memo.result;
|
|
@@ -31906,7 +31984,7 @@ function clientFrom(c) {
|
|
|
31906
31984
|
}
|
|
31907
31985
|
installMediaDownloadGuard();
|
|
31908
31986
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
31909
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT6 ?
|
|
31987
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join55(PLATFORM_ROOT6, "config", "brand.json") : "";
|
|
31910
31988
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
31911
31989
|
if (BRAND_JSON_PATH && !existsSync51(BRAND_JSON_PATH)) {
|
|
31912
31990
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -31945,7 +32023,7 @@ var brandLoginOpts = {
|
|
|
31945
32023
|
appleTouchIconPath: brandAppIcon512Path,
|
|
31946
32024
|
themeColor: BRAND.defaultColors?.primary
|
|
31947
32025
|
};
|
|
31948
|
-
var ALIAS_DOMAINS_PATH =
|
|
32026
|
+
var ALIAS_DOMAINS_PATH = join55(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
31949
32027
|
function loadAliasDomains() {
|
|
31950
32028
|
try {
|
|
31951
32029
|
if (!existsSync51(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -32040,7 +32118,7 @@ var waGateway = new WaGateway({
|
|
|
32040
32118
|
sendToParty: (accountId, phone, text) => sendWhatsAppTextForRelay(accountId, phone, text),
|
|
32041
32119
|
resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
|
|
32042
32120
|
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 ??
|
|
32121
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
32044
32122
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
32045
32123
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
32046
32124
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -32055,7 +32133,7 @@ var waGateway = new WaGateway({
|
|
|
32055
32133
|
caption,
|
|
32056
32134
|
accountId,
|
|
32057
32135
|
maxyAccountId,
|
|
32058
|
-
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
32136
|
+
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, ".."))
|
|
32059
32137
|
});
|
|
32060
32138
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
32061
32139
|
},
|
|
@@ -32222,7 +32300,7 @@ function runDuplicateSenderAudit() {
|
|
|
32222
32300
|
try {
|
|
32223
32301
|
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
32224
32302
|
if (!configDir) return;
|
|
32225
|
-
const projectsRoot =
|
|
32303
|
+
const projectsRoot = join55(configDir, "projects");
|
|
32226
32304
|
const records = [];
|
|
32227
32305
|
for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
|
|
32228
32306
|
if (isSubagent || archived) continue;
|
|
@@ -32233,6 +32311,10 @@ function runDuplicateSenderAudit() {
|
|
|
32233
32311
|
}
|
|
32234
32312
|
logDuplicateSenderGroups(findDuplicateSenderGroups(records));
|
|
32235
32313
|
logCrossAccountSenderGroups(findCrossAccountSenderGroups(records));
|
|
32314
|
+
const outbound = waGateway.takeOutboundAccountCensus();
|
|
32315
|
+
console.error(
|
|
32316
|
+
`[whatsapp-native] op=outbound-account-mismatch sends=${outbound.sends} mismatched=${outbound.mismatched}`
|
|
32317
|
+
);
|
|
32236
32318
|
} catch (err) {
|
|
32237
32319
|
console.error(`[whatsapp-native] op=duplicate-sender-audit-error error=${err instanceof Error ? err.message : String(err)}`);
|
|
32238
32320
|
}
|
|
@@ -32435,7 +32517,26 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
32435
32517
|
// than returning the house id this closure used to be handed. See
|
|
32436
32518
|
// effective-account.ts for why `resolveAccount()` was the wrong side to move,
|
|
32437
32519
|
// and why the real dependencies are bound there rather than assembled here.
|
|
32438
|
-
effectiveAccountFor: resolveScheduledEffectiveAccountForInstall
|
|
32520
|
+
effectiveAccountFor: resolveScheduledEffectiveAccountForInstall,
|
|
32521
|
+
// Task 2365 — the account whose own telegram.adminUsers claims this chat id.
|
|
32522
|
+
// Reads the same list, through the same readChannelAdmins call, that
|
|
32523
|
+
// validateAgentDestination uses (agent-dispatch-rule), so the routine picker,
|
|
32524
|
+
// the save and this dispatch cannot disagree. Two claimants is reported to
|
|
32525
|
+
// the route and refused there, never picked between.
|
|
32526
|
+
telegramAccountForDestination: (destination) => {
|
|
32527
|
+
const asNumber = Number(destination);
|
|
32528
|
+
if (!Number.isInteger(asNumber)) return { kind: "none" };
|
|
32529
|
+
const claimants = listValidAccounts().filter(
|
|
32530
|
+
(a) => readChannelAdmins(a.accountDir, "telegram").adminUsers.includes(asNumber)
|
|
32531
|
+
);
|
|
32532
|
+
if (claimants.length === 0) return { kind: "none" };
|
|
32533
|
+
if (claimants.length > 1) return { kind: "ambiguous", count: claimants.length };
|
|
32534
|
+
return {
|
|
32535
|
+
kind: "one",
|
|
32536
|
+
accountId: claimants[0].accountId,
|
|
32537
|
+
botToken: claimants[0].config.telegram?.adminBotToken ?? null
|
|
32538
|
+
};
|
|
32539
|
+
}
|
|
32439
32540
|
});
|
|
32440
32541
|
app76.route("/api/channel/schedule-inject", scheduleInjectRoutes);
|
|
32441
32542
|
app76.use("*", clientIpMiddleware);
|
|
@@ -32710,15 +32811,10 @@ app76.post("/api/remote-auth/set-password", async (c) => {
|
|
|
32710
32811
|
});
|
|
32711
32812
|
app76.route("/api/_client-error", client_error_default);
|
|
32712
32813
|
console.log("[client-error-route] mounted");
|
|
32713
|
-
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
32714
32814
|
app76.use("*", async (c, next) => {
|
|
32715
32815
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
32716
32816
|
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)) {
|
|
32817
|
+
if (isRemoteAuthBypassPath(path)) {
|
|
32722
32818
|
await next();
|
|
32723
32819
|
return;
|
|
32724
32820
|
}
|
|
@@ -32771,7 +32867,7 @@ app76.route("/api/webchat", createWebchatRoutes({
|
|
|
32771
32867
|
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
32772
32868
|
}));
|
|
32773
32869
|
app76.route("/api/webchat/greeting", webchat_greeting_default);
|
|
32774
|
-
app76
|
|
32870
|
+
mountTelegramRoutes(app76, telegram_default);
|
|
32775
32871
|
app76.route("/api/quickbooks", quickbooks_default);
|
|
32776
32872
|
app76.route("/api/onboarding", onboarding_default);
|
|
32777
32873
|
app76.route("/api/admin", admin_default);
|
|
@@ -32903,7 +32999,7 @@ var SW_SOURCE = (() => {
|
|
|
32903
32999
|
function readInstalledVersion() {
|
|
32904
33000
|
try {
|
|
32905
33001
|
if (!PLATFORM_ROOT6) return "unknown";
|
|
32906
|
-
const versionFile =
|
|
33002
|
+
const versionFile = join55(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
|
|
32907
33003
|
if (!existsSync51(versionFile)) return "unknown";
|
|
32908
33004
|
const content = readFileSync47(versionFile, "utf-8").trim();
|
|
32909
33005
|
return content || "unknown";
|
|
@@ -32933,12 +33029,12 @@ ${clientErrorReporterScript}
|
|
|
32933
33029
|
return html;
|
|
32934
33030
|
}
|
|
32935
33031
|
function loadBrandingCache(agentSlug) {
|
|
32936
|
-
const configDir =
|
|
33032
|
+
const configDir = join55(homedir4(), BRAND.configDir);
|
|
32937
33033
|
try {
|
|
32938
33034
|
const verdict = resolvePublicAddressFromDisk(agentSlug);
|
|
32939
33035
|
const accountId = verdict.kind === "served" ? verdict.owner.accountId : getDefaultAccountId();
|
|
32940
33036
|
if (!accountId) return null;
|
|
32941
|
-
const cachePath =
|
|
33037
|
+
const cachePath = join55(configDir, "branding-cache", accountId, `${agentSlug}.json`);
|
|
32942
33038
|
if (!existsSync51(cachePath)) return null;
|
|
32943
33039
|
return JSON.parse(readFileSync47(cachePath, "utf-8"));
|
|
32944
33040
|
} catch {
|
|
@@ -33188,7 +33284,7 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
33188
33284
|
var httpServer = serve({ fetch: app76.fetch, port, hostname });
|
|
33189
33285
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
33190
33286
|
{
|
|
33191
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33287
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33192
33288
|
const reconcileScript = resolve45(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
33193
33289
|
const runReconcile = (ctx) => {
|
|
33194
33290
|
if (!existsSync51(reconcileScript)) return;
|
|
@@ -33211,7 +33307,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33211
33307
|
detached: true,
|
|
33212
33308
|
run: runReconcile
|
|
33213
33309
|
});
|
|
33214
|
-
const reconcileStatePath =
|
|
33310
|
+
const reconcileStatePath = join55(MAXY_DIR, "booking-reconcile-state.json");
|
|
33215
33311
|
registerLoop({
|
|
33216
33312
|
name: "calendar-reconcile-liveness",
|
|
33217
33313
|
intervalMs: 6e5,
|
|
@@ -33229,7 +33325,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33229
33325
|
}
|
|
33230
33326
|
{
|
|
33231
33327
|
const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
|
|
33232
|
-
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33328
|
+
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33233
33329
|
const dreamSweepScript = resolve45(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
|
|
33234
33330
|
registerLoop({
|
|
33235
33331
|
name: "dream-cycle-sweep",
|
|
@@ -33253,7 +33349,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33253
33349
|
});
|
|
33254
33350
|
}
|
|
33255
33351
|
{
|
|
33256
|
-
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33352
|
+
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33257
33353
|
const outlookScript = resolve45(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
33258
33354
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
33259
33355
|
const runOutlookComplete = (ctx) => {
|
|
@@ -33279,7 +33375,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33279
33375
|
});
|
|
33280
33376
|
}
|
|
33281
33377
|
{
|
|
33282
|
-
const auditRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33378
|
+
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33283
33379
|
const strandedAccountsDir = resolve45(auditRoot, "..", "data/accounts");
|
|
33284
33380
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
33285
33381
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
@@ -33292,7 +33388,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33292
33388
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
33293
33389
|
const pendingPath2 = resolve45(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
33294
33390
|
if (!existsSync51(pendingPath2)) continue;
|
|
33295
|
-
const ageMs2 = now -
|
|
33391
|
+
const ageMs2 = now - statSync27(pendingPath2).mtimeMs;
|
|
33296
33392
|
if (ageMs2 > STRANDED_AGE_MS) {
|
|
33297
33393
|
console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs2 / 1e3)}`);
|
|
33298
33394
|
}
|
|
@@ -33309,7 +33405,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33309
33405
|
});
|
|
33310
33406
|
}
|
|
33311
33407
|
{
|
|
33312
|
-
const googleRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33408
|
+
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33313
33409
|
const googleAccountsDir = resolve45(googleRoot, "..", "data/accounts");
|
|
33314
33410
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
33315
33411
|
const runGooglePendingAuditSafe = () => {
|
|
@@ -33353,7 +33449,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33353
33449
|
});
|
|
33354
33450
|
}
|
|
33355
33451
|
{
|
|
33356
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33452
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33357
33453
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
33358
33454
|
const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
|
|
33359
33455
|
console.error(`[storage-audit] error="${err.message}"`);
|
|
@@ -33385,6 +33481,25 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33385
33481
|
firstRunDelayMs: 5e4,
|
|
33386
33482
|
run: runDataPortalAuditSafe
|
|
33387
33483
|
});
|
|
33484
|
+
const runTelegramAudit = async () => {
|
|
33485
|
+
const accounts = listValidAccounts().map((a) => ({ accountId: a.accountId, telegram: a.config.telegram }));
|
|
33486
|
+
const configured = accounts.some((a) => a.telegram?.adminBotToken || a.telegram?.publicBotToken);
|
|
33487
|
+
if (!configured) return;
|
|
33488
|
+
const lastByAccount = newestTelegramSessionByAccount();
|
|
33489
|
+
const lines = buildTelegramAuditLines({
|
|
33490
|
+
accounts,
|
|
33491
|
+
secretFileExists: (botType, accountId) => existsSync51(secretPath(botType, accountId)),
|
|
33492
|
+
lastInboundAt: (accountId) => lastByAccount.get(accountId) ?? null,
|
|
33493
|
+
now: Date.now()
|
|
33494
|
+
});
|
|
33495
|
+
for (const line of lines) console.error(line);
|
|
33496
|
+
};
|
|
33497
|
+
registerLoop({
|
|
33498
|
+
name: "telegram-audit",
|
|
33499
|
+
intervalMs: STORAGE_AUDIT_INTERVAL_MS,
|
|
33500
|
+
firstRunDelayMs: 65e3,
|
|
33501
|
+
run: runTelegramAudit
|
|
33502
|
+
});
|
|
33388
33503
|
registerLoop({
|
|
33389
33504
|
name: "portal-uploads-pull",
|
|
33390
33505
|
intervalMs: PORTAL_UPLOADS_PULL_INTERVAL_MS,
|
|
@@ -33450,7 +33565,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33450
33565
|
});
|
|
33451
33566
|
}
|
|
33452
33567
|
{
|
|
33453
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33568
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33454
33569
|
const publishScript = resolve45(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
33455
33570
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
33456
33571
|
const bookingAccounts = () => {
|
|
@@ -33527,7 +33642,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33527
33642
|
startTimeEntryCensus(() => getSession());
|
|
33528
33643
|
startLedgerCensus(() => getSession());
|
|
33529
33644
|
{
|
|
33530
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33645
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..");
|
|
33531
33646
|
const auditScript = resolve45(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
33532
33647
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
33533
33648
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
@@ -33738,8 +33853,8 @@ var runIngestAuditTick = () => {
|
|
|
33738
33853
|
},
|
|
33739
33854
|
agentExists: (accountId, slug) => {
|
|
33740
33855
|
if (!house) return false;
|
|
33741
|
-
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir :
|
|
33742
|
-
return existsSync51(
|
|
33856
|
+
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir : join55(ACCOUNTS_DIR, accountId);
|
|
33857
|
+
return existsSync51(join55(dir, "agents", slug, "config.json"));
|
|
33743
33858
|
}
|
|
33744
33859
|
});
|
|
33745
33860
|
} catch (err) {
|
|
@@ -33787,7 +33902,7 @@ registerLoop({
|
|
|
33787
33902
|
runPublicAddressCollisionAudit({
|
|
33788
33903
|
houseAccountId: () => resolveAccount()?.accountId ?? null,
|
|
33789
33904
|
activeSlugs: () => listValidAccounts().map((a) => {
|
|
33790
|
-
const agentsRoot =
|
|
33905
|
+
const agentsRoot = join55(a.accountDir, "agents");
|
|
33791
33906
|
if (!existsSync51(agentsRoot)) return { accountId: a.accountId, slugs: [] };
|
|
33792
33907
|
const slugs = readdirSync30(agentsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).filter((slug) => isActiveAgentSlug(a.accountDir, slug));
|
|
33793
33908
|
return { accountId: a.accountId, slugs };
|
|
@@ -33873,7 +33988,7 @@ try {
|
|
|
33873
33988
|
} catch (err) {
|
|
33874
33989
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
33875
33990
|
}
|
|
33876
|
-
var configDirForWhatsApp =
|
|
33991
|
+
var configDirForWhatsApp = basename18(MAXY_DIR) || ".maxy";
|
|
33877
33992
|
var bootAccount = resolveAccount();
|
|
33878
33993
|
if (bootAccount) {
|
|
33879
33994
|
migrateRemovedConfigKeys(bootAccount.accountDir);
|
|
@@ -33939,7 +34054,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
33939
34054
|
}
|
|
33940
34055
|
init({
|
|
33941
34056
|
configDir: configDirForWhatsApp,
|
|
33942
|
-
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
34057
|
+
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join55(__dirname, "..")),
|
|
33943
34058
|
accountConfig: bootAccountConfig,
|
|
33944
34059
|
// Task 2074 — enrich with the sub-account name and fan out to every open
|
|
33945
34060
|
// admin SSE stream. Fire-and-forget: the manager's persist path must not
|