@rubytech/create-sitedesk-code 0.1.612 → 0.1.614
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/lib/agent-dispatch-rule/dist/index.d.ts +34 -0
- package/payload/platform/lib/agent-dispatch-rule/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/agent-dispatch-rule/dist/index.js +39 -0
- package/payload/platform/lib/agent-dispatch-rule/dist/index.js.map +1 -1
- package/payload/platform/lib/agent-dispatch-rule/src/__tests__/carrier-verdict.test.ts +92 -0
- package/payload/platform/lib/agent-dispatch-rule/src/index.ts +59 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +67 -10
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +11 -0
- package/payload/platform/plugins/docs/references/telegram-guide.md +66 -9
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch-carrier.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch-carrier.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch-carrier.test.js +72 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch-carrier.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-delivery-reconcile.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-delivery-reconcile.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-delivery-reconcile.test.js +327 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-delivery-reconcile.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-delivery.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-delivery.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-delivery.test.js +130 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-delivery.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js +27 -58
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts +8 -3
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js +37 -3
- package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-delivery.d.ts +67 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-delivery.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-delivery.js +133 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-delivery.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts +67 -12
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.js +226 -72
- package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +66 -4
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/reconcile-run-controls.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/reconcile-run-controls.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/reconcile-run-controls.test.js +45 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/reconcile-run-controls.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +3 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +32 -7
- 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 +12 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +15 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +14 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +4 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts +3 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js.map +1 -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 +14 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/card-row.test.d.ts +2 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/card-row.test.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/card-row.test.js +237 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/card-row.test.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js +6 -4
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/lib/card-row.d.ts +96 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/card-row.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/card-row.js +156 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/card-row.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/card.d.ts.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/card.js +53 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/card.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/instruct.d.ts +7 -5
- package/payload/platform/plugins/telegram/mcp/dist/tools/instruct.d.ts.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/instruct.js +14 -12
- package/payload/platform/plugins/telegram/mcp/dist/tools/instruct.js.map +1 -1
- package/payload/server/public/operator.html +1 -1
- package/payload/server/server.js +804 -724
package/payload/server/server.js
CHANGED
|
@@ -3220,10 +3220,10 @@ var require_dist10 = __commonJS({
|
|
|
3220
3220
|
});
|
|
3221
3221
|
|
|
3222
3222
|
// server/index.ts
|
|
3223
|
-
import { readFileSync as
|
|
3223
|
+
import { readFileSync as readFileSync64, existsSync as existsSync63, watchFile, readdirSync as readdirSync38, statSync as statSync34 } from "fs";
|
|
3224
3224
|
import { spawn as spawn3 } from "child_process";
|
|
3225
3225
|
import { createHash as createHash8 } from "crypto";
|
|
3226
|
-
import { resolve as resolve55, join as
|
|
3226
|
+
import { resolve as resolve55, join as join78, basename as basename19 } from "path";
|
|
3227
3227
|
import { homedir as homedir5 } from "os";
|
|
3228
3228
|
|
|
3229
3229
|
// server/lib/route-cache-watchers.ts
|
|
@@ -6248,6 +6248,82 @@ function parseTelegramChannelKey(key2) {
|
|
|
6248
6248
|
return { botId, senderId: rest, business: false };
|
|
6249
6249
|
}
|
|
6250
6250
|
|
|
6251
|
+
// app/lib/telegram/access-control.ts
|
|
6252
|
+
function checkTelegramAccess(params) {
|
|
6253
|
+
const { senderId, entry: entry3, chatId, chatType } = params;
|
|
6254
|
+
const isGroup = chatType === "group" || chatType === "supergroup";
|
|
6255
|
+
const isChannel = chatType === "channel";
|
|
6256
|
+
if (isChannel && entry3.role !== "public") {
|
|
6257
|
+
return {
|
|
6258
|
+
allowed: false,
|
|
6259
|
+
reason: entry3.role === "admin" ? "admin-entry-no-channels" : entry3.role === "specialist" ? "specialist-entry-no-channels" : "unbound-entry-no-channels",
|
|
6260
|
+
agentType: entry3.role === "admin" ? "admin" : entry3.role === "specialist" ? "specialist" : "public"
|
|
6261
|
+
};
|
|
6262
|
+
}
|
|
6263
|
+
if (isGroup && entry3.role !== "public") {
|
|
6264
|
+
return {
|
|
6265
|
+
allowed: false,
|
|
6266
|
+
reason: entry3.role === "admin" ? "admin-entry-no-groups" : entry3.role === "specialist" ? "specialist-entry-no-groups" : "unbound-entry-no-groups",
|
|
6267
|
+
agentType: entry3.role === "admin" ? "admin" : entry3.role === "specialist" ? "specialist" : "public"
|
|
6268
|
+
};
|
|
6269
|
+
}
|
|
6270
|
+
if (entry3.role === "admin") {
|
|
6271
|
+
const adminUsers = entry3.adminUsers ?? [];
|
|
6272
|
+
if (adminUsers.includes(senderId)) {
|
|
6273
|
+
return { allowed: true, reason: "admin-binding", agentType: "admin" };
|
|
6274
|
+
}
|
|
6275
|
+
return { allowed: false, reason: "not-admin-user", agentType: "admin" };
|
|
6276
|
+
}
|
|
6277
|
+
if (isGroup && entry3.role === "public") {
|
|
6278
|
+
const groupPolicy = entry3.groupPolicy ?? "disabled";
|
|
6279
|
+
if (groupPolicy === "allowlist") {
|
|
6280
|
+
const allowGroups = entry3.allowGroups ?? [];
|
|
6281
|
+
if (allowGroups.includes(chatId)) {
|
|
6282
|
+
return { allowed: true, reason: "group-allowlist-match", agentType: "public" };
|
|
6283
|
+
}
|
|
6284
|
+
return { allowed: false, reason: "not-in-allowGroups", agentType: "public" };
|
|
6285
|
+
}
|
|
6286
|
+
return { allowed: false, reason: "group-policy-disabled", agentType: "public" };
|
|
6287
|
+
}
|
|
6288
|
+
if (isChannel && entry3.role === "public") {
|
|
6289
|
+
const channelPolicy = entry3.channelPolicy ?? "disabled";
|
|
6290
|
+
if (channelPolicy === "allowlist") {
|
|
6291
|
+
const allowChannels = entry3.allowChannels ?? [];
|
|
6292
|
+
if (allowChannels.includes(chatId)) {
|
|
6293
|
+
return { allowed: true, reason: "channel-allowlist-match", agentType: "public" };
|
|
6294
|
+
}
|
|
6295
|
+
return { allowed: false, reason: "not-in-allowChannels", agentType: "public" };
|
|
6296
|
+
}
|
|
6297
|
+
return { allowed: false, reason: "channel-policy-disabled", agentType: "public" };
|
|
6298
|
+
}
|
|
6299
|
+
if (entry3.role === "unbound") {
|
|
6300
|
+
return { allowed: false, reason: "bot-unbound", agentType: "public" };
|
|
6301
|
+
}
|
|
6302
|
+
if (entry3.role === "specialist") {
|
|
6303
|
+
const allowFrom = entry3.allowFrom ?? [];
|
|
6304
|
+
if (allowFrom.includes(senderId)) {
|
|
6305
|
+
return { allowed: true, reason: "specialist-allowlist-match", agentType: "specialist" };
|
|
6306
|
+
}
|
|
6307
|
+
return { allowed: false, reason: "not-in-allowlist", agentType: "specialist" };
|
|
6308
|
+
}
|
|
6309
|
+
const policy = entry3.dmPolicy ?? "disabled";
|
|
6310
|
+
switch (policy) {
|
|
6311
|
+
case "open":
|
|
6312
|
+
return { allowed: true, reason: "dm-policy-open", agentType: "public" };
|
|
6313
|
+
case "allowlist": {
|
|
6314
|
+
const allowFrom = entry3.allowFrom ?? [];
|
|
6315
|
+
if (allowFrom.includes(senderId)) {
|
|
6316
|
+
return { allowed: true, reason: "allowlist-match", agentType: "public" };
|
|
6317
|
+
}
|
|
6318
|
+
return { allowed: false, reason: "not-in-allowlist", agentType: "public" };
|
|
6319
|
+
}
|
|
6320
|
+
case "disabled":
|
|
6321
|
+
return { allowed: false, reason: "dm-policy-disabled", agentType: "public" };
|
|
6322
|
+
default:
|
|
6323
|
+
return { allowed: false, reason: "unknown-dm-policy", agentType: "public" };
|
|
6324
|
+
}
|
|
6325
|
+
}
|
|
6326
|
+
|
|
6251
6327
|
// app/lib/telegram/chat-send-policy.ts
|
|
6252
6328
|
var BROADCAST_PREFIX = "-100";
|
|
6253
6329
|
function checkTelegramChatSend(params) {
|
|
@@ -6263,6 +6339,21 @@ function chatSendAllowlists(entry3) {
|
|
|
6263
6339
|
if (!entry3 || entry3.role !== "public") return { allowChannels: [], allowGroups: [] };
|
|
6264
6340
|
return { allowChannels: entry3.allowChannels ?? [], allowGroups: entry3.allowGroups ?? [] };
|
|
6265
6341
|
}
|
|
6342
|
+
function checkTelegramOutboundTarget(params) {
|
|
6343
|
+
const { chatId, entry: entry3 } = params;
|
|
6344
|
+
if (String(chatId).startsWith(BROADCAST_PREFIX)) {
|
|
6345
|
+
const lists = chatSendAllowlists(entry3);
|
|
6346
|
+
const verdict2 = checkTelegramChatSend({
|
|
6347
|
+
chatId,
|
|
6348
|
+
allowChannels: lists.allowChannels,
|
|
6349
|
+
allowGroups: lists.allowGroups
|
|
6350
|
+
});
|
|
6351
|
+
return { allowed: verdict2.allowed, reason: verdict2.reason, kind: "broadcast" };
|
|
6352
|
+
}
|
|
6353
|
+
const kind = chatId < 0 ? "group" : "private";
|
|
6354
|
+
const verdict = checkTelegramAccess({ senderId: chatId, entry: entry3, chatId, chatType: kind });
|
|
6355
|
+
return { allowed: verdict.allowed, reason: verdict.reason, kind };
|
|
6356
|
+
}
|
|
6266
6357
|
|
|
6267
6358
|
// app/lib/channel-pty-bridge/admin-session-id.ts
|
|
6268
6359
|
import { createHash } from "crypto";
|
|
@@ -7105,17 +7196,17 @@ async function computeSessionList(scopeAccountId) {
|
|
|
7105
7196
|
if (adminUserId && role === ADMIN_ROLE && sidecarChannel === WEBCHAT_CHANNEL) {
|
|
7106
7197
|
adminUserIdBySession.set(sessionId, adminUserId);
|
|
7107
7198
|
}
|
|
7108
|
-
const
|
|
7109
|
-
if (
|
|
7199
|
+
const tail2 = await lastAssistantModelFromTail(path, size);
|
|
7200
|
+
if (tail2.failure) {
|
|
7110
7201
|
tailReadFails += 1;
|
|
7111
7202
|
console.error(
|
|
7112
|
-
`[admin-sessions-list] op=tail-read-failed sessionId=${sessionId.slice(0, 8)} reason=${
|
|
7203
|
+
`[admin-sessions-list] op=tail-read-failed sessionId=${sessionId.slice(0, 8)} reason=${tail2.failure}`
|
|
7113
7204
|
);
|
|
7114
7205
|
} else {
|
|
7115
|
-
if (
|
|
7116
|
-
if (
|
|
7206
|
+
if (tail2.bytesRead > 0) tailReads += 1;
|
|
7207
|
+
if (tail2.model === null) tailModelMiss += 1;
|
|
7117
7208
|
}
|
|
7118
|
-
tailBytes +=
|
|
7209
|
+
tailBytes += tail2.bytesRead;
|
|
7119
7210
|
rows.push({
|
|
7120
7211
|
sessionId,
|
|
7121
7212
|
title: resolved.title,
|
|
@@ -7134,7 +7225,7 @@ async function computeSessionList(scopeAccountId) {
|
|
|
7134
7225
|
// diverge from the sidecar (e.g. an ai-titled channel row).
|
|
7135
7226
|
channel: sidecarChannel,
|
|
7136
7227
|
personName: null,
|
|
7137
|
-
model:
|
|
7228
|
+
model: tail2.model,
|
|
7138
7229
|
accountId: rowAccountId,
|
|
7139
7230
|
senderId,
|
|
7140
7231
|
whatsappName: null
|
|
@@ -7354,33 +7445,53 @@ function createScheduleInjectRoutes(deps) {
|
|
|
7354
7445
|
console.error(`${TAG6} op=inject-spawn eventId=${eventId} sessionId=${sessionId2} result=ok status=-`);
|
|
7355
7446
|
return c.json({ ok: true, sessionKey: sessionId2, ...transcriptBoundary(sessionId2) }, 200);
|
|
7356
7447
|
}
|
|
7357
|
-
const
|
|
7358
|
-
if (resolution.kind === "none") {
|
|
7359
|
-
console.error(`${TAG6} op=schedule-telegram-reject eventId=${eventId} destination=${destination} reason=unresolved-effective-account`);
|
|
7360
|
-
return c.json({ ok: false, error: "unresolved-effective-account" }, 403);
|
|
7361
|
-
}
|
|
7448
|
+
const namedBotId = typeof body.botId === "string" && body.botId.length > 0 ? body.botId : null;
|
|
7362
7449
|
let claimant;
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7450
|
+
let carrierSource;
|
|
7451
|
+
let claimantCount = 0;
|
|
7452
|
+
if (namedBotId !== null && eventAccountId !== null) {
|
|
7453
|
+
carrierSource = "named";
|
|
7454
|
+
const carrier = deps.carrierFor(eventAccountId, namedBotId, destination);
|
|
7455
|
+
if ("error" in carrier) {
|
|
7368
7456
|
console.error(
|
|
7369
|
-
`${TAG6} op=
|
|
7457
|
+
`${TAG6} op=carrier-unavailable eventId=${eventId} botId=${namedBotId} reason=${carrier.error}`
|
|
7370
7458
|
);
|
|
7371
|
-
return c.json({ ok: false, error: "
|
|
7459
|
+
return c.json({ ok: false, error: "carrier-unavailable" }, 403);
|
|
7372
7460
|
}
|
|
7373
|
-
|
|
7461
|
+
claimant = carrier;
|
|
7462
|
+
} else {
|
|
7463
|
+
carrierSource = "resolved";
|
|
7464
|
+
const resolution = deps.telegramAccountForDestination(destination);
|
|
7465
|
+
if (resolution.kind === "none") {
|
|
7466
|
+
console.error(`${TAG6} op=schedule-telegram-reject eventId=${eventId} destination=${destination} reason=unresolved-effective-account`);
|
|
7467
|
+
return c.json({ ok: false, error: "unresolved-effective-account" }, 403);
|
|
7468
|
+
}
|
|
7469
|
+
claimantCount = resolution.kind === "ambiguous" ? resolution.claimants.length : 1;
|
|
7470
|
+
if (resolution.kind === "one") {
|
|
7471
|
+
claimant = resolution;
|
|
7472
|
+
} else {
|
|
7473
|
+
const mine = resolution.claimants.filter((c2) => c2.accountId === eventAccountId);
|
|
7474
|
+
if (mine.length === 0) {
|
|
7475
|
+
console.error(
|
|
7476
|
+
`${TAG6} op=event-account-scope-mismatch eventId=${eventId} eventAccount=${eventAccountId ?? "-"} effectiveAccount=none claimants=${resolution.claimants.length} destination=${destination} dispatched=no`
|
|
7477
|
+
);
|
|
7478
|
+
return c.json({ ok: false, error: "event-account-scope-mismatch" }, 403);
|
|
7479
|
+
}
|
|
7480
|
+
if (mine.length > 1) {
|
|
7481
|
+
console.error(
|
|
7482
|
+
`${TAG6} op=telegram-destination-ambiguous eventId=${eventId} destination=${destination} accounts=${mine.length} scope=within-account dispatched=no`
|
|
7483
|
+
);
|
|
7484
|
+
return c.json({ ok: false, error: "telegram-destination-ambiguous" }, 403);
|
|
7485
|
+
}
|
|
7486
|
+
claimant = mine[0];
|
|
7374
7487
|
console.error(
|
|
7375
|
-
`${TAG6} op=telegram-destination-
|
|
7488
|
+
`${TAG6} op=telegram-destination-narrowed eventId=${eventId} destination=${destination} claimants=${resolution.claimants.length} account=${claimant.accountId} botId=${claimant.botId}`
|
|
7376
7489
|
);
|
|
7377
|
-
return c.json({ ok: false, error: "telegram-destination-ambiguous" }, 403);
|
|
7378
7490
|
}
|
|
7379
|
-
claimant = mine[0];
|
|
7380
|
-
console.error(
|
|
7381
|
-
`${TAG6} op=telegram-destination-narrowed eventId=${eventId} destination=${destination} claimants=${resolution.claimants.length} account=${claimant.accountId} botId=${claimant.botId}`
|
|
7382
|
-
);
|
|
7383
7491
|
}
|
|
7492
|
+
console.error(
|
|
7493
|
+
`${TAG6} op=carrier eventId=${eventId} botId=${claimant.botId} source=${carrierSource} claimants=${claimantCount}`
|
|
7494
|
+
);
|
|
7384
7495
|
const { accountId: effectiveAccount, botId, botToken } = claimant;
|
|
7385
7496
|
console.error(`${TAG6} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount} botId=${botId}`);
|
|
7386
7497
|
if (eventAccountId === null || eventAccountId !== effectiveAccount) {
|
|
@@ -7732,13 +7843,24 @@ function createOperatorInjectRoutes(deps) {
|
|
|
7732
7843
|
const { accountId, accountDir, entry: entry3 } = resolved;
|
|
7733
7844
|
const role = entry3.role;
|
|
7734
7845
|
const agent = agentOf(entry3);
|
|
7735
|
-
if (role
|
|
7736
|
-
report({ botId, chatId, sessionId: "none", role, agent, accepted: false, reason: "
|
|
7846
|
+
if (role === "admin") {
|
|
7847
|
+
report({ botId, chatId, sessionId: "none", role, agent, accepted: false, reason: "admin-bot" });
|
|
7737
7848
|
return c.json(
|
|
7738
7849
|
{
|
|
7739
7850
|
ok: false,
|
|
7740
|
-
error: "
|
|
7741
|
-
detail: `Bot ${botId} is
|
|
7851
|
+
error: "admin-bot",
|
|
7852
|
+
detail: `Bot ${botId} is this account's admin bot. Its chat is your own conversation with the agent, so there is nothing to instruct.`
|
|
7853
|
+
},
|
|
7854
|
+
403
|
|
7855
|
+
);
|
|
7856
|
+
}
|
|
7857
|
+
if (role === "unbound") {
|
|
7858
|
+
report({ botId, chatId, sessionId: "none", role, agent, accepted: false, reason: "unbound-bot" });
|
|
7859
|
+
return c.json(
|
|
7860
|
+
{
|
|
7861
|
+
ok: false,
|
|
7862
|
+
error: "unbound-bot",
|
|
7863
|
+
detail: `Bot ${botId} is not bound to an agent or a specialist card, so it answers nobody. Bind it before instructing it.`
|
|
7742
7864
|
},
|
|
7743
7865
|
403
|
|
7744
7866
|
);
|
|
@@ -7771,30 +7893,18 @@ function createOperatorInjectRoutes(deps) {
|
|
|
7771
7893
|
403
|
|
7772
7894
|
);
|
|
7773
7895
|
}
|
|
7774
|
-
const
|
|
7775
|
-
const verdict = checkTelegramChatSend({
|
|
7776
|
-
chatId: Number(chatId),
|
|
7777
|
-
allowChannels: lists.allowChannels,
|
|
7778
|
-
allowGroups: lists.allowGroups
|
|
7779
|
-
});
|
|
7896
|
+
const verdict = checkTelegramOutboundTarget({ chatId: Number(chatId), entry: entry3 });
|
|
7780
7897
|
console.error(
|
|
7781
7898
|
`[telegram-outbound] op=channel-send botId=${logValue2(botId)} chatId=${logValue2(chatId)} allowed=${verdict.allowed ? "yes" : "no"} reason=${verdict.reason} messageId=none`
|
|
7782
7899
|
);
|
|
7783
7900
|
if (!verdict.allowed) {
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
chatId,
|
|
7787
|
-
sessionId: "none",
|
|
7788
|
-
role,
|
|
7789
|
-
agent,
|
|
7790
|
-
accepted: false,
|
|
7791
|
-
reason: "chat-not-allowlisted"
|
|
7792
|
-
});
|
|
7901
|
+
const outcome = verdict.kind === "broadcast" ? "chat-not-allowlisted" : "chat-not-permitted";
|
|
7902
|
+
report({ botId, chatId, sessionId: "none", role, agent, accepted: false, reason: outcome });
|
|
7793
7903
|
return c.json(
|
|
7794
7904
|
{
|
|
7795
7905
|
ok: false,
|
|
7796
|
-
error:
|
|
7797
|
-
detail: `Chat ${chatId} is a broadcast channel that bot ${botId} does not allowlist, so nothing was sent.`
|
|
7906
|
+
error: outcome,
|
|
7907
|
+
detail: verdict.kind === "broadcast" ? `Chat ${chatId} is a broadcast channel that bot ${botId} does not allowlist, so nothing was sent.` : `Bot ${botId} may not talk to chat ${chatId} (${verdict.reason}), so nothing was sent. It would refuse that chat's own messages too.`
|
|
7798
7908
|
},
|
|
7799
7909
|
403
|
|
7800
7910
|
);
|
|
@@ -7823,13 +7933,22 @@ function createOperatorInjectRoutes(deps) {
|
|
|
7823
7933
|
accountDir,
|
|
7824
7934
|
botId,
|
|
7825
7935
|
botToken: entry3.token,
|
|
7826
|
-
|
|
7936
|
+
// Task 2773 — `entryAgentSlug`, not `entry.agent`: a specialist entry
|
|
7937
|
+
// carries a card name and no `agent` field at all, so the property read
|
|
7938
|
+
// is `undefined` there. The webhook resolves the same way
|
|
7939
|
+
// (`routes/telegram.ts`), so both doors name the spawn's agent from one
|
|
7940
|
+
// definition.
|
|
7941
|
+
agentSlug: entryAgentSlug(entry3),
|
|
7827
7942
|
senderId: chatId,
|
|
7828
7943
|
conversationSubject: chatId,
|
|
7829
7944
|
businessChatId: null,
|
|
7830
|
-
role
|
|
7945
|
+
// Task 2773 — the entry's OWN role, replacing a hardcoded 'public'. This
|
|
7946
|
+
// picks the session derivation in `sessionIdFor` and the framing in the
|
|
7947
|
+
// channel server; a value disagreeing with the registry would land the
|
|
7948
|
+
// instruction in a session the counterparty's real messages never reach.
|
|
7949
|
+
role,
|
|
7831
7950
|
personId: null,
|
|
7832
|
-
specialist: null,
|
|
7951
|
+
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
7833
7952
|
chatId,
|
|
7834
7953
|
text: instruction,
|
|
7835
7954
|
// An instruction carries no file by construction: there is no message to
|
|
@@ -8171,8 +8290,8 @@ function auditGroupOutbound() {
|
|
|
8171
8290
|
}
|
|
8172
8291
|
function auditGroupOutboundNote() {
|
|
8173
8292
|
const a = auditGroupOutbound();
|
|
8174
|
-
const
|
|
8175
|
-
const note = `convos=${a.convos} outbound=${a.outbound} operator=${a.operator} agent=${a.agent} unstamped=${a.unstamped}${
|
|
8293
|
+
const tail2 = a.agent > 0 ? ` offenders=${a.offenders.join(",")}` : "";
|
|
8294
|
+
const note = `convos=${a.convos} outbound=${a.outbound} operator=${a.operator} agent=${a.agent} unstamped=${a.unstamped}${tail2}`;
|
|
8176
8295
|
console.log(`${TAG13} op=group-outbound-audit ${note}`);
|
|
8177
8296
|
return note;
|
|
8178
8297
|
}
|
|
@@ -9203,10 +9322,10 @@ function resolveKey(accountId, ctx) {
|
|
|
9203
9322
|
function setAccountPolicy(accountDir, accountId, policy, ctx) {
|
|
9204
9323
|
const id = accountId.trim();
|
|
9205
9324
|
if (!id) return { ok: false, reason: "missing-account-id", error: "Missing account id." };
|
|
9206
|
-
const
|
|
9325
|
+
const fields2 = ["dmPolicy", "adminPhones", "allowFrom"].filter(
|
|
9207
9326
|
(f) => policy[f] !== void 0
|
|
9208
9327
|
);
|
|
9209
|
-
if (
|
|
9328
|
+
if (fields2.length === 0) {
|
|
9210
9329
|
return {
|
|
9211
9330
|
ok: false,
|
|
9212
9331
|
reason: "empty-policy",
|
|
@@ -9228,7 +9347,7 @@ function setAccountPolicy(accountDir, accountId, policy, ctx) {
|
|
|
9228
9347
|
const accounts = wa.accounts;
|
|
9229
9348
|
if (!accounts[key2] || typeof accounts[key2] !== "object") accounts[key2] = { name: "Main" };
|
|
9230
9349
|
const slice = accounts[key2];
|
|
9231
|
-
for (const field2 of
|
|
9350
|
+
for (const field2 of fields2) slice[field2] = policy[field2];
|
|
9232
9351
|
const parsed = WhatsAppConfigSchema.safeParse(wa);
|
|
9233
9352
|
if (!parsed.success) {
|
|
9234
9353
|
const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
|
|
@@ -9238,7 +9357,7 @@ function setAccountPolicy(accountDir, accountId, policy, ctx) {
|
|
|
9238
9357
|
config.whatsapp = parsed.data;
|
|
9239
9358
|
writeConfig(accountDir, config);
|
|
9240
9359
|
console.error(
|
|
9241
|
-
`${TAG15} op=set-account-policy account=${id} key=${key2} keyKind=${verdict.kind} fields=[${
|
|
9360
|
+
`${TAG15} op=set-account-policy account=${id} key=${key2} keyKind=${verdict.kind} fields=[${fields2.join(",")}] ok=true`
|
|
9242
9361
|
);
|
|
9243
9362
|
reloadManagerConfig(accountDir);
|
|
9244
9363
|
return { ok: true, key: key2 };
|
|
@@ -9500,8 +9619,8 @@ function resolvePublicAgentEnabled(accountDir, opts) {
|
|
|
9500
9619
|
return { enabled: false, source: "default" };
|
|
9501
9620
|
}
|
|
9502
9621
|
}
|
|
9503
|
-
function updateConfig(accountDir,
|
|
9504
|
-
const fieldNames = Object.keys(
|
|
9622
|
+
function updateConfig(accountDir, fields2) {
|
|
9623
|
+
const fieldNames = Object.keys(fields2);
|
|
9505
9624
|
if (fieldNames.length === 0) {
|
|
9506
9625
|
return { ok: false, error: "No fields provided to update." };
|
|
9507
9626
|
}
|
|
@@ -9511,7 +9630,7 @@ function updateConfig(accountDir, fields) {
|
|
|
9511
9630
|
config.whatsapp = {};
|
|
9512
9631
|
}
|
|
9513
9632
|
const wa = config.whatsapp;
|
|
9514
|
-
for (const [key2, value] of Object.entries(
|
|
9633
|
+
for (const [key2, value] of Object.entries(fields2)) {
|
|
9515
9634
|
wa[key2] = value;
|
|
9516
9635
|
}
|
|
9517
9636
|
const parsed = WhatsAppConfigSchema.safeParse(wa);
|
|
@@ -10221,12 +10340,12 @@ function unwrapToShape(schema) {
|
|
|
10221
10340
|
}
|
|
10222
10341
|
function extractFields(schema) {
|
|
10223
10342
|
const shape = unwrapToShape(schema);
|
|
10224
|
-
const
|
|
10343
|
+
const fields2 = [];
|
|
10225
10344
|
for (const [name, fieldSchema] of Object.entries(shape)) {
|
|
10226
10345
|
const def = fieldSchema?._def;
|
|
10227
10346
|
const resolved = resolveZodType(def);
|
|
10228
10347
|
const description = extractDescription(fieldSchema, def);
|
|
10229
|
-
|
|
10348
|
+
fields2.push({
|
|
10230
10349
|
name,
|
|
10231
10350
|
type: resolved.type,
|
|
10232
10351
|
required: resolved.required,
|
|
@@ -10234,14 +10353,14 @@ function extractFields(schema) {
|
|
|
10234
10353
|
...description !== void 0 ? { description } : {}
|
|
10235
10354
|
});
|
|
10236
10355
|
}
|
|
10237
|
-
return
|
|
10356
|
+
return fields2;
|
|
10238
10357
|
}
|
|
10239
10358
|
function escapeTableCell(text) {
|
|
10240
10359
|
return text.replace(/\|/g, "\\|");
|
|
10241
10360
|
}
|
|
10242
|
-
function formatFieldTable(title,
|
|
10361
|
+
function formatFieldTable(title, fields2) {
|
|
10243
10362
|
const lines = [`## ${title}`, "", "| Field | Type | Required | Default | Description |", "|-------|------|----------|---------|-------------|"];
|
|
10244
|
-
for (const f of
|
|
10363
|
+
for (const f of fields2) {
|
|
10245
10364
|
const desc = f.description ? escapeTableCell(f.description) : "\u2014";
|
|
10246
10365
|
lines.push(`| ${f.name} | ${f.type} | ${f.required ? "yes" : "no"} | ${f.default ?? "\u2014"} | ${desc} |`);
|
|
10247
10366
|
}
|
|
@@ -10398,12 +10517,12 @@ function houseSocketScopeDenial(c, op) {
|
|
|
10398
10517
|
}
|
|
10399
10518
|
function selfOrHouseScopeDenial(c, targetAccountId, op, targetSource = "explicit") {
|
|
10400
10519
|
const { decision, callerAccountId, houseAdminScope } = evaluateCallerScope(c, targetAccountId);
|
|
10401
|
-
const
|
|
10520
|
+
const tail2 = `target=${targetAccountId} targetSource=${targetSource} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`;
|
|
10402
10521
|
if (decision.authorized) {
|
|
10403
|
-
console.error(`${TAG20} op=authz-ok route=${op} ${
|
|
10522
|
+
console.error(`${TAG20} op=authz-ok route=${op} ${tail2}`);
|
|
10404
10523
|
return null;
|
|
10405
10524
|
}
|
|
10406
|
-
console.error(`${TAG20} op=authz-deny route=${op} ${
|
|
10525
|
+
console.error(`${TAG20} op=authz-deny route=${op} ${tail2}`);
|
|
10407
10526
|
return c.json({ ok: false, error: "Not authorized. This session may only pair or manage its own account." }, 403);
|
|
10408
10527
|
}
|
|
10409
10528
|
function bindingScopeDenial(c, targetAccountId, op) {
|
|
@@ -10677,7 +10796,7 @@ app3.post("/reconnect", async (c) => {
|
|
|
10677
10796
|
app3.post("/config", async (c) => {
|
|
10678
10797
|
try {
|
|
10679
10798
|
const body = await c.req.json().catch(() => ({}));
|
|
10680
|
-
const { action, phone, slug, fields, accountId, managesAccount, mode, policy, party, account: partyAccount, enabled } = body;
|
|
10799
|
+
const { action, phone, slug, fields: fields2, accountId, managesAccount, mode, policy, party, account: partyAccount, enabled } = body;
|
|
10681
10800
|
if (!action || typeof action !== "string") {
|
|
10682
10801
|
return c.json({ ok: false, error: 'Missing required field "action".' }, 400);
|
|
10683
10802
|
}
|
|
@@ -10941,11 +11060,11 @@ app3.post("/config", async (c) => {
|
|
|
10941
11060
|
}
|
|
10942
11061
|
}
|
|
10943
11062
|
case "update-config": {
|
|
10944
|
-
if (!
|
|
11063
|
+
if (!fields2 || typeof fields2 !== "object" || Array.isArray(fields2)) {
|
|
10945
11064
|
return c.json({ ok: false, error: 'Missing required field "fields" (object with config field names and values).' }, 400);
|
|
10946
11065
|
}
|
|
10947
|
-
const result = updateConfig(account.accountDir,
|
|
10948
|
-
const fieldNames = Object.keys(
|
|
11066
|
+
const result = updateConfig(account.accountDir, fields2);
|
|
11067
|
+
const fieldNames = Object.keys(fields2);
|
|
10949
11068
|
console.error(`${TAG20} config action=update-config fields=[${fieldNames.join(",")}] ok=${result.ok}`);
|
|
10950
11069
|
return c.json(result, result.ok ? 200 : 400);
|
|
10951
11070
|
}
|
|
@@ -14095,13 +14214,13 @@ async function pullVisitStatusForAccount(opts) {
|
|
|
14095
14214
|
log2(
|
|
14096
14215
|
`${TAG24} op=merged account=${accountId} id=${row.id} labour=${row.dayHundredths > 0} forWorker=${row.forOwnerId !== ""}`
|
|
14097
14216
|
);
|
|
14098
|
-
const
|
|
14099
|
-
if (row.workDate !== "")
|
|
14100
|
-
if (row.workNote !== "")
|
|
14101
|
-
if (row.assignedOwnerId !== "")
|
|
14102
|
-
if (row.startDate !== "")
|
|
14103
|
-
if (row.forOwnerId !== "")
|
|
14104
|
-
for (const field2 of
|
|
14217
|
+
const fields2 = ["status"];
|
|
14218
|
+
if (row.workDate !== "") fields2.push("workDate");
|
|
14219
|
+
if (row.workNote !== "") fields2.push("workNote");
|
|
14220
|
+
if (row.assignedOwnerId !== "") fields2.push("assignedOwnerId");
|
|
14221
|
+
if (row.startDate !== "") fields2.push("startDate");
|
|
14222
|
+
if (row.forOwnerId !== "") fields2.push("forOwnerId");
|
|
14223
|
+
for (const field2 of fields2) {
|
|
14105
14224
|
log2(`${TAG24} op=applied visitId=${row.visitId} field=${field2}`);
|
|
14106
14225
|
}
|
|
14107
14226
|
} catch (err) {
|
|
@@ -15516,11 +15635,19 @@ async function recordManualSendContext(input, deps) {
|
|
|
15516
15635
|
mechanism,
|
|
15517
15636
|
reason
|
|
15518
15637
|
});
|
|
15519
|
-
if (input.entry.role
|
|
15638
|
+
if (input.entry.role === "admin") return refuse2("admin-bot");
|
|
15639
|
+
if (input.entry.role === "unbound") return refuse2("unbound-bot");
|
|
15520
15640
|
const businessKey = telegramBusinessChannelKey(input.botId, String(input.chatId));
|
|
15521
15641
|
if (deps.newestInboundTelegramDate(input.accountId, businessKey) !== null) {
|
|
15522
15642
|
return refuse2("business-chat");
|
|
15523
15643
|
}
|
|
15644
|
+
const target = checkTelegramOutboundTarget({ chatId: input.chatId, entry: input.entry });
|
|
15645
|
+
if (!target.allowed) {
|
|
15646
|
+
deps.log(
|
|
15647
|
+
`[telegram-manual-send] op=target-refused botId=${input.botId} chatId=${input.chatId} kind=${target.kind} reason=${target.reason}`
|
|
15648
|
+
);
|
|
15649
|
+
return refuse2("chat-not-permitted");
|
|
15650
|
+
}
|
|
15524
15651
|
const projectDir = deps.findSessionProjectDir(input.sessionId);
|
|
15525
15652
|
if (projectDir === null) return refuse2("no-transcript");
|
|
15526
15653
|
const live = deps.isLive(input.channelKey);
|
|
@@ -15541,16 +15668,22 @@ async function recordManualSendContext(input, deps) {
|
|
|
15541
15668
|
accountDir: input.accountDir,
|
|
15542
15669
|
botId: input.botId,
|
|
15543
15670
|
botToken: input.entry.token,
|
|
15544
|
-
|
|
15671
|
+
// Task 2773 — `entryAgentSlug`, not `entry.agent`: a specialist entry has
|
|
15672
|
+
// no `agent` field, so the property read is `undefined` there.
|
|
15673
|
+
agentSlug: entryAgentSlug(input.entry),
|
|
15545
15674
|
senderId: input.senderId,
|
|
15546
15675
|
// The route admits only a private chat, where the conversation's subject IS
|
|
15547
15676
|
// the sender. Passed explicitly so the gateway's key and its session id are
|
|
15548
15677
|
// derived from the same value the store row already carries.
|
|
15549
15678
|
conversationSubject: input.senderId,
|
|
15550
15679
|
businessChatId: null,
|
|
15551
|
-
role
|
|
15680
|
+
// Task 2773 — the entry's OWN role, replacing a hardcoded 'public'. It
|
|
15681
|
+
// picks the session derivation in `sessionIdFor`, which for a specialist is
|
|
15682
|
+
// `telegramAdminSessionId` — the same value the caller already derived for
|
|
15683
|
+
// `input.sessionId`.
|
|
15684
|
+
role: input.entry.role,
|
|
15552
15685
|
personId: null,
|
|
15553
|
-
specialist: null,
|
|
15686
|
+
specialist: input.entry.role === "specialist" ? input.entry.specialist : null,
|
|
15554
15687
|
chatId: String(input.chatId),
|
|
15555
15688
|
text: input.text,
|
|
15556
15689
|
// No file by construction: this is text the operator typed into the send
|
|
@@ -16185,10 +16318,97 @@ function runTelegramStoreCensus() {
|
|
|
16185
16318
|
return c;
|
|
16186
16319
|
}
|
|
16187
16320
|
|
|
16321
|
+
// app/lib/telegram/card-row-census.ts
|
|
16322
|
+
import { closeSync as closeSync6, openSync as openSync6, readdirSync as readdirSync15, readFileSync as readFileSync24, readSync as readSync6, statSync as statSync15 } from "fs";
|
|
16323
|
+
import { join as join30 } from "path";
|
|
16324
|
+
var CARD_ROW_CENSUS_TAG = "[telegram-card-row-census]";
|
|
16325
|
+
var CARD_ROW_WINDOW_MS = 60 * 60 * 1e3;
|
|
16326
|
+
var MAX_BYTES_PER_FILE = 4e6;
|
|
16327
|
+
function tail(path, size) {
|
|
16328
|
+
if (size <= MAX_BYTES_PER_FILE) return readFileSync24(path, "utf-8");
|
|
16329
|
+
const buf = Buffer.alloc(MAX_BYTES_PER_FILE);
|
|
16330
|
+
const fd = openSync6(path, "r");
|
|
16331
|
+
try {
|
|
16332
|
+
const read = readSync6(fd, buf, 0, MAX_BYTES_PER_FILE, size - MAX_BYTES_PER_FILE);
|
|
16333
|
+
const text = buf.subarray(0, read).toString("utf-8");
|
|
16334
|
+
const nl = text.indexOf("\n");
|
|
16335
|
+
return nl === -1 ? "" : text.slice(nl + 1);
|
|
16336
|
+
} finally {
|
|
16337
|
+
closeSync6(fd);
|
|
16338
|
+
}
|
|
16339
|
+
}
|
|
16340
|
+
function fields(line) {
|
|
16341
|
+
const out = {};
|
|
16342
|
+
for (const part of line.split(" ")) {
|
|
16343
|
+
const i = part.indexOf("=");
|
|
16344
|
+
if (i > 0) out[part.slice(0, i)] = part.slice(i + 1);
|
|
16345
|
+
}
|
|
16346
|
+
return out;
|
|
16347
|
+
}
|
|
16348
|
+
function parseCardSends(lines) {
|
|
16349
|
+
const out = [];
|
|
16350
|
+
for (const line of lines) {
|
|
16351
|
+
if (!line.startsWith("[telegram-tools] op=card-sent ")) continue;
|
|
16352
|
+
const f = fields(line);
|
|
16353
|
+
if (f.outcome !== "sent") continue;
|
|
16354
|
+
if (!f.accountId || !f.key || !f.messageId) continue;
|
|
16355
|
+
const atMs = Date.parse(f.at ?? "");
|
|
16356
|
+
if (!Number.isFinite(atMs)) continue;
|
|
16357
|
+
out.push({ accountId: f.accountId, channelKey: f.key, messageId: f.messageId, atMs });
|
|
16358
|
+
}
|
|
16359
|
+
return out;
|
|
16360
|
+
}
|
|
16361
|
+
function rowExists(send) {
|
|
16362
|
+
const rowId = `telegram:${send.accountId}:${send.channelKey}:card:${send.messageId}`;
|
|
16363
|
+
for (const row of readRows(send.accountId, send.channelKey)) {
|
|
16364
|
+
if (isUpdateRecord(row)) continue;
|
|
16365
|
+
if (row.messageId === rowId) return true;
|
|
16366
|
+
}
|
|
16367
|
+
return false;
|
|
16368
|
+
}
|
|
16369
|
+
function collectCardRowCensus(input) {
|
|
16370
|
+
const floor = input.nowMs - CARD_ROW_WINDOW_MS;
|
|
16371
|
+
const sends = /* @__PURE__ */ new Map();
|
|
16372
|
+
try {
|
|
16373
|
+
if (input.logDir) {
|
|
16374
|
+
for (const name of readdirSync15(input.logDir)) {
|
|
16375
|
+
if (!name.startsWith("mcp-") || !name.endsWith(".log")) continue;
|
|
16376
|
+
const path = join30(input.logDir, name);
|
|
16377
|
+
let text;
|
|
16378
|
+
try {
|
|
16379
|
+
text = tail(path, statSync15(path).size);
|
|
16380
|
+
} catch {
|
|
16381
|
+
continue;
|
|
16382
|
+
}
|
|
16383
|
+
for (const send of parseCardSends(text.split("\n"))) {
|
|
16384
|
+
if (send.atMs < floor || send.atMs > input.nowMs) continue;
|
|
16385
|
+
sends.set(`${send.accountId}:${send.channelKey}:${send.messageId}`, send);
|
|
16386
|
+
}
|
|
16387
|
+
}
|
|
16388
|
+
}
|
|
16389
|
+
} catch {
|
|
16390
|
+
}
|
|
16391
|
+
let rows = 0;
|
|
16392
|
+
const missingIds = [];
|
|
16393
|
+
for (const send of sends.values()) {
|
|
16394
|
+
if (rowExists(send)) rows += 1;
|
|
16395
|
+
else missingIds.push(send.messageId);
|
|
16396
|
+
}
|
|
16397
|
+
return { sent: sends.size, rows, missing: missingIds.length, missingIds };
|
|
16398
|
+
}
|
|
16399
|
+
function cardRowCensusLine(input) {
|
|
16400
|
+
const c = collectCardRowCensus(input);
|
|
16401
|
+
const head = `${CARD_ROW_CENSUS_TAG} sent=${c.sent} rows=${c.rows} missing=${c.missing} window=60m`;
|
|
16402
|
+
return c.missing > 0 ? `${head} missing-ids=[${c.missingIds.join(",")}]` : head;
|
|
16403
|
+
}
|
|
16404
|
+
function runTelegramCardRowCensus(logDir, nowMs = Date.now()) {
|
|
16405
|
+
console.error(cardRowCensusLine({ logDir, nowMs }));
|
|
16406
|
+
}
|
|
16407
|
+
|
|
16188
16408
|
// app/lib/telegram/reach-census.ts
|
|
16189
16409
|
var import_dist4 = __toESM(require_dist2(), 1);
|
|
16190
16410
|
import { existsSync as existsSync21 } from "fs";
|
|
16191
|
-
import { join as
|
|
16411
|
+
import { join as join31 } from "path";
|
|
16192
16412
|
function collectTelegramReachCensus(accounts) {
|
|
16193
16413
|
const out = {
|
|
16194
16414
|
accounts: accounts.length,
|
|
@@ -16198,7 +16418,7 @@ function collectTelegramReachCensus(accounts) {
|
|
|
16198
16418
|
};
|
|
16199
16419
|
for (const account of accounts) {
|
|
16200
16420
|
const reach = (0, import_dist4.collectTelegramReach)({
|
|
16201
|
-
storeDir:
|
|
16421
|
+
storeDir: join31(STORE_ROOT2(), account.accountId),
|
|
16202
16422
|
bots: account.bots
|
|
16203
16423
|
});
|
|
16204
16424
|
for (const bot of reach.bots) {
|
|
@@ -16252,7 +16472,7 @@ function runTelegramCheckoutCensus(bots, now) {
|
|
|
16252
16472
|
}
|
|
16253
16473
|
|
|
16254
16474
|
// app/lib/telegram/media-census.ts
|
|
16255
|
-
import { join as
|
|
16475
|
+
import { join as join32, resolve as resolve20 } from "path";
|
|
16256
16476
|
function idsByTarget(rows) {
|
|
16257
16477
|
const out = /* @__PURE__ */ new Map();
|
|
16258
16478
|
for (const row of rows) {
|
|
@@ -16333,8 +16553,8 @@ function readWaOperatorTurns() {
|
|
|
16333
16553
|
}
|
|
16334
16554
|
|
|
16335
16555
|
// server/routes/session-reader.ts
|
|
16336
|
-
import { readFileSync as
|
|
16337
|
-
import { isAbsolute as isAbsolute2, join as
|
|
16556
|
+
import { readFileSync as readFileSync25, watch as watch4, statSync as statSync16, existsSync as existsSync22, readdirSync as readdirSync16, realpathSync as realpathSync5 } from "fs";
|
|
16557
|
+
import { isAbsolute as isAbsolute2, join as join33, relative as relative3, resolve as resolve21, sep as sep5 } from "path";
|
|
16338
16558
|
|
|
16339
16559
|
// server/routes/admin/manager-client.ts
|
|
16340
16560
|
var SESSION_ID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -16439,7 +16659,7 @@ function openTaskKey(turns) {
|
|
|
16439
16659
|
}
|
|
16440
16660
|
function readSubagentMeta(dir, hex) {
|
|
16441
16661
|
try {
|
|
16442
|
-
const m = JSON.parse(
|
|
16662
|
+
const m = JSON.parse(readFileSync25(join33(dir, `agent-${hex}.meta.json`), "utf8"));
|
|
16443
16663
|
if (typeof m.agentType === "string" && typeof m.description === "string" && typeof m.toolUseId === "string") {
|
|
16444
16664
|
return { agentType: m.agentType, description: m.description, toolUseId: m.toolUseId };
|
|
16445
16665
|
}
|
|
@@ -16462,7 +16682,7 @@ function runActivityTick(c) {
|
|
|
16462
16682
|
c.parentGrewThisTick = false;
|
|
16463
16683
|
let names = [];
|
|
16464
16684
|
try {
|
|
16465
|
-
names =
|
|
16685
|
+
names = readdirSync16(c.subagentsDir).filter((n) => AGENT_JSONL_RE.test(n));
|
|
16466
16686
|
} catch {
|
|
16467
16687
|
}
|
|
16468
16688
|
const entries2 = [];
|
|
@@ -16471,7 +16691,7 @@ function runActivityTick(c) {
|
|
|
16471
16691
|
let size = 0;
|
|
16472
16692
|
let mtimeMs = 0;
|
|
16473
16693
|
try {
|
|
16474
|
-
const st =
|
|
16694
|
+
const st = statSync16(join33(c.subagentsDir, name));
|
|
16475
16695
|
size = st.size;
|
|
16476
16696
|
mtimeMs = st.mtimeMs;
|
|
16477
16697
|
} catch {
|
|
@@ -16516,11 +16736,11 @@ app7.get("/stream", requireAdminSession, (c) => {
|
|
|
16516
16736
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
16517
16737
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
16518
16738
|
const cfg = claudeConfigDir();
|
|
16519
|
-
const projectsRoot = cfg ? resolve21(
|
|
16739
|
+
const projectsRoot = cfg ? resolve21(join33(cfg, "projects")) : null;
|
|
16520
16740
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
16521
16741
|
return c.json({ error: "bad session reference" }, 400);
|
|
16522
16742
|
}
|
|
16523
|
-
const jsonlPath = resolve21(
|
|
16743
|
+
const jsonlPath = resolve21(join33(projectDir, `${sessionId}.jsonl`));
|
|
16524
16744
|
if (!jsonlPath.startsWith(projectsRoot + sep5)) {
|
|
16525
16745
|
return c.json({ error: "bad session reference" }, 400);
|
|
16526
16746
|
}
|
|
@@ -16540,7 +16760,7 @@ data: ${JSON.stringify(turn)}
|
|
|
16540
16760
|
start(controller) {
|
|
16541
16761
|
const fileEnd0 = (() => {
|
|
16542
16762
|
try {
|
|
16543
|
-
return
|
|
16763
|
+
return statSync16(jsonlPath).size;
|
|
16544
16764
|
} catch {
|
|
16545
16765
|
return 0;
|
|
16546
16766
|
}
|
|
@@ -16548,7 +16768,7 @@ data: ${JSON.stringify(turn)}
|
|
|
16548
16768
|
let offset = resumeOffset(lastEventId, fileEnd0);
|
|
16549
16769
|
console.log(`[wa-stream] op=open conn=${connId} sessionId=${sessionId} channel=reader resume=${offset}`);
|
|
16550
16770
|
const sessionKey = c.req.query("session_key") ?? "";
|
|
16551
|
-
const subagentsDir = resolve21(
|
|
16771
|
+
const subagentsDir = resolve21(join33(projectDir, sessionId, "subagents"));
|
|
16552
16772
|
console.log(
|
|
16553
16773
|
`[webchat-activity] op=watch-subagents key=${sessionKey} dir=${subagentsDir} exists=${existsSync22(subagentsDir)}`
|
|
16554
16774
|
);
|
|
@@ -16701,11 +16921,11 @@ app7.get("/backfill", requireAdminSession, (c) => {
|
|
|
16701
16921
|
const beforeRaw = c.req.query("before") ?? "";
|
|
16702
16922
|
const before = Number(beforeRaw);
|
|
16703
16923
|
const cfg = claudeConfigDir();
|
|
16704
|
-
const projectsRoot = cfg ? resolve21(
|
|
16924
|
+
const projectsRoot = cfg ? resolve21(join33(cfg, "projects")) : null;
|
|
16705
16925
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId) || beforeRaw === "" || !Number.isFinite(before) || before < 0) {
|
|
16706
16926
|
return c.json({ error: "bad session reference" }, 400);
|
|
16707
16927
|
}
|
|
16708
|
-
const jsonlPath = resolve21(
|
|
16928
|
+
const jsonlPath = resolve21(join33(projectDir, `${sessionId}.jsonl`));
|
|
16709
16929
|
if (!jsonlPath.startsWith(projectsRoot + sep5)) {
|
|
16710
16930
|
return c.json({ error: "bad session reference" }, 400);
|
|
16711
16931
|
}
|
|
@@ -16717,7 +16937,7 @@ app7.get("/backfill", requireAdminSession, (c) => {
|
|
|
16717
16937
|
const scratchpadRoot = sessionScratchpadRoot(projectDir, sessionId);
|
|
16718
16938
|
const fileEnd = (() => {
|
|
16719
16939
|
try {
|
|
16720
|
-
return
|
|
16940
|
+
return statSync16(jsonlPath).size;
|
|
16721
16941
|
} catch {
|
|
16722
16942
|
return 0;
|
|
16723
16943
|
}
|
|
@@ -16760,7 +16980,7 @@ app7.get("/directives", requireAdminSession, (c) => {
|
|
|
16760
16980
|
if (!dir || !existsSync22(dir)) return c.json({ entries: [] });
|
|
16761
16981
|
let names;
|
|
16762
16982
|
try {
|
|
16763
|
-
names =
|
|
16983
|
+
names = readdirSync16(dir).filter((n) => DIRECTIVE_NAME_RE.test(n));
|
|
16764
16984
|
} catch {
|
|
16765
16985
|
return c.json({ entries: [] });
|
|
16766
16986
|
}
|
|
@@ -16770,7 +16990,7 @@ app7.get("/directives", requireAdminSession, (c) => {
|
|
|
16770
16990
|
const pid = Number(pidPart);
|
|
16771
16991
|
let len = 0;
|
|
16772
16992
|
try {
|
|
16773
|
-
len =
|
|
16993
|
+
len = statSync16(join33(dir, name)).size;
|
|
16774
16994
|
} catch {
|
|
16775
16995
|
}
|
|
16776
16996
|
return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
|
|
@@ -16785,11 +17005,11 @@ app7.get("/directive", requireAdminSession, (c) => {
|
|
|
16785
17005
|
}
|
|
16786
17006
|
const dir = directiveStoreDir(sessionId);
|
|
16787
17007
|
if (!dir) return c.json({ error: "no account" }, 404);
|
|
16788
|
-
const path = resolve21(
|
|
17008
|
+
const path = resolve21(join33(dir, name));
|
|
16789
17009
|
if (!path.startsWith(dir + sep5)) return c.json({ error: "bad reference" }, 400);
|
|
16790
17010
|
let body;
|
|
16791
17011
|
try {
|
|
16792
|
-
body =
|
|
17012
|
+
body = readFileSync25(path, "utf8");
|
|
16793
17013
|
} catch {
|
|
16794
17014
|
return c.json({ error: "not found" }, 404);
|
|
16795
17015
|
}
|
|
@@ -16798,8 +17018,8 @@ app7.get("/directive", requireAdminSession, (c) => {
|
|
|
16798
17018
|
var session_reader_default = app7;
|
|
16799
17019
|
|
|
16800
17020
|
// server/routes/operator-conversations.ts
|
|
16801
|
-
import { readFileSync as
|
|
16802
|
-
import { basename as basename9, dirname as dirname9, join as
|
|
17021
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
17022
|
+
import { basename as basename9, dirname as dirname9, join as join34 } from "path";
|
|
16803
17023
|
|
|
16804
17024
|
// app/lib/reader/operator-conversations.ts
|
|
16805
17025
|
function operatorConvName(row) {
|
|
@@ -16887,7 +17107,7 @@ app8.get("/conversations", requireAdminSession, async (c) => {
|
|
|
16887
17107
|
}
|
|
16888
17108
|
const cfg = claudeConfigDir();
|
|
16889
17109
|
if (!cfg) return c.json({ conversations: [] });
|
|
16890
|
-
const projectsRoot =
|
|
17110
|
+
const projectsRoot = join34(cfg, "projects");
|
|
16891
17111
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
16892
17112
|
const rows = [];
|
|
16893
17113
|
let sessionRowsExcludedUntagged = 0;
|
|
@@ -16905,7 +17125,7 @@ app8.get("/conversations", requireAdminSession, async (c) => {
|
|
|
16905
17125
|
enumeratedCount += 1;
|
|
16906
17126
|
const sessionId = basename9(path).replace(/\.jsonl$/, "");
|
|
16907
17127
|
const projectDir = dirname9(path);
|
|
16908
|
-
const meta = readSidecarMeta(
|
|
17128
|
+
const meta = readSidecarMeta(join34(projectDir, `${sessionId}.meta.json`));
|
|
16909
17129
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
16910
17130
|
if (multiAccount) {
|
|
16911
17131
|
if (meta.accountId === null) {
|
|
@@ -16917,7 +17137,7 @@ app8.get("/conversations", requireAdminSession, async (c) => {
|
|
|
16917
17137
|
let body = "";
|
|
16918
17138
|
let bodyRead = false;
|
|
16919
17139
|
try {
|
|
16920
|
-
body =
|
|
17140
|
+
body = readFileSync26(path, "utf8");
|
|
16921
17141
|
bodyRead = true;
|
|
16922
17142
|
bodyReadCount += 1;
|
|
16923
17143
|
} catch (err) {
|
|
@@ -17093,7 +17313,7 @@ app8.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
17093
17313
|
const { value, state } = await getOrCompute("conversations-all", houseId, async () => {
|
|
17094
17314
|
const cfg = claudeConfigDir();
|
|
17095
17315
|
if (!cfg) return { conversations: [] };
|
|
17096
|
-
const projectsRoot =
|
|
17316
|
+
const projectsRoot = join34(cfg, "projects");
|
|
17097
17317
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
17098
17318
|
const validAccounts = listValidAccounts();
|
|
17099
17319
|
const validIds = new Set(validAccounts.map((a) => a.accountId));
|
|
@@ -17113,7 +17333,7 @@ app8.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
17113
17333
|
enumeratedCount += 1;
|
|
17114
17334
|
const sessionId = basename9(path).replace(/\.jsonl$/, "");
|
|
17115
17335
|
const projectDir = dirname9(path);
|
|
17116
|
-
const meta = readSidecarMeta(
|
|
17336
|
+
const meta = readSidecarMeta(join34(projectDir, `${sessionId}.meta.json`));
|
|
17117
17337
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
17118
17338
|
if (meta.accountId === null) {
|
|
17119
17339
|
untaggedCount += 1;
|
|
@@ -17124,7 +17344,7 @@ app8.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
17124
17344
|
let body = "";
|
|
17125
17345
|
let bodyRead = false;
|
|
17126
17346
|
try {
|
|
17127
|
-
body =
|
|
17347
|
+
body = readFileSync26(path, "utf8");
|
|
17128
17348
|
bodyRead = true;
|
|
17129
17349
|
bodyReadCount += 1;
|
|
17130
17350
|
} catch (err) {
|
|
@@ -17249,8 +17469,8 @@ app8.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
17249
17469
|
var operator_conversations_default = app8;
|
|
17250
17470
|
|
|
17251
17471
|
// server/routes/public-reader.ts
|
|
17252
|
-
import { statSync as
|
|
17253
|
-
import { basename as basename10, dirname as dirname10, join as
|
|
17472
|
+
import { statSync as statSync18, watch as watch6, readFileSync as readFileSync27, readdirSync as readdirSync18 } from "fs";
|
|
17473
|
+
import { basename as basename10, dirname as dirname10, join as join35, resolve as resolve23, sep as sep7 } from "path";
|
|
17254
17474
|
|
|
17255
17475
|
// app/lib/reader/delivered-kinds.ts
|
|
17256
17476
|
var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -17339,10 +17559,10 @@ function enumeratePublicRows() {
|
|
|
17339
17559
|
const cfg = claudeConfigDir();
|
|
17340
17560
|
if (!cfg) return [];
|
|
17341
17561
|
const rows = [];
|
|
17342
|
-
for (const { path } of enumerateJsonls(
|
|
17562
|
+
for (const { path } of enumerateJsonls(join35(cfg, "projects"))) {
|
|
17343
17563
|
const sessionId = basename10(path).replace(/\.jsonl$/, "");
|
|
17344
17564
|
const projectDir = dirname10(path);
|
|
17345
|
-
const meta = readSidecarMeta(
|
|
17565
|
+
const meta = readSidecarMeta(join35(projectDir, `${sessionId}.meta.json`));
|
|
17346
17566
|
rows.push({
|
|
17347
17567
|
sessionId,
|
|
17348
17568
|
projectDir,
|
|
@@ -17409,15 +17629,15 @@ app9.get("/backfill", (c) => {
|
|
|
17409
17629
|
const beforeRaw = c.req.query("before") ?? "";
|
|
17410
17630
|
const before = Number(beforeRaw);
|
|
17411
17631
|
const cfg = claudeConfigDir();
|
|
17412
|
-
const projectsRoot = cfg ? resolve23(
|
|
17632
|
+
const projectsRoot = cfg ? resolve23(join35(cfg, "projects")) : null;
|
|
17413
17633
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId) || beforeRaw === "" || !Number.isFinite(before) || before < 0) {
|
|
17414
17634
|
return c.json({ error: "bad session reference" }, 400);
|
|
17415
17635
|
}
|
|
17416
|
-
const jsonlPath = resolve23(
|
|
17636
|
+
const jsonlPath = resolve23(join35(projectDir, `${sessionId}.jsonl`));
|
|
17417
17637
|
if (!jsonlPath.startsWith(projectsRoot + sep7)) {
|
|
17418
17638
|
return c.json({ error: "bad session reference" }, 400);
|
|
17419
17639
|
}
|
|
17420
|
-
const meta = readSidecarMeta(
|
|
17640
|
+
const meta = readSidecarMeta(join35(projectDir, `${sessionId}.meta.json`));
|
|
17421
17641
|
const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
|
|
17422
17642
|
const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
|
|
17423
17643
|
if (!(isPublicWebchat && owns)) {
|
|
@@ -17433,7 +17653,7 @@ app9.get("/backfill", (c) => {
|
|
|
17433
17653
|
}
|
|
17434
17654
|
const fileEnd = (() => {
|
|
17435
17655
|
try {
|
|
17436
|
-
return
|
|
17656
|
+
return statSync18(jsonlPath).size;
|
|
17437
17657
|
} catch {
|
|
17438
17658
|
return 0;
|
|
17439
17659
|
}
|
|
@@ -17476,15 +17696,15 @@ app9.get("/stream", (c) => {
|
|
|
17476
17696
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
17477
17697
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
17478
17698
|
const cfg = claudeConfigDir();
|
|
17479
|
-
const projectsRoot = cfg ? resolve23(
|
|
17699
|
+
const projectsRoot = cfg ? resolve23(join35(cfg, "projects")) : null;
|
|
17480
17700
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
17481
17701
|
return c.json({ error: "bad session reference" }, 400);
|
|
17482
17702
|
}
|
|
17483
|
-
const jsonlPath = resolve23(
|
|
17703
|
+
const jsonlPath = resolve23(join35(projectDir, `${sessionId}.jsonl`));
|
|
17484
17704
|
if (!jsonlPath.startsWith(projectsRoot + sep7)) {
|
|
17485
17705
|
return c.json({ error: "bad session reference" }, 400);
|
|
17486
17706
|
}
|
|
17487
|
-
const meta = readSidecarMeta(
|
|
17707
|
+
const meta = readSidecarMeta(join35(projectDir, `${sessionId}.meta.json`));
|
|
17488
17708
|
const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
|
|
17489
17709
|
const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
|
|
17490
17710
|
if (!(isPublicWebchat && owns)) {
|
|
@@ -17513,7 +17733,7 @@ data: ${JSON.stringify(turn)}
|
|
|
17513
17733
|
};
|
|
17514
17734
|
const fileEnd0 = (() => {
|
|
17515
17735
|
try {
|
|
17516
|
-
return
|
|
17736
|
+
return statSync18(jsonlPath).size;
|
|
17517
17737
|
} catch {
|
|
17518
17738
|
return 0;
|
|
17519
17739
|
}
|
|
@@ -17628,9 +17848,9 @@ app9.get("/attachment/:attachmentId", (c) => {
|
|
|
17628
17848
|
let dataFile;
|
|
17629
17849
|
let buffer;
|
|
17630
17850
|
try {
|
|
17631
|
-
dataFile =
|
|
17851
|
+
dataFile = readdirSync18(dir).find((f) => !f.endsWith(".meta.json") && !f.endsWith(EXTRACTED_TEXT_SUFFIX));
|
|
17632
17852
|
if (!dataFile) throw new Error("no data file");
|
|
17633
|
-
buffer =
|
|
17853
|
+
buffer = readFileSync27(resolve23(dir, dataFile));
|
|
17634
17854
|
} catch {
|
|
17635
17855
|
console.error(`${ATT_TAG} op=denied session=${ses} att=${at} reason=not-found`);
|
|
17636
17856
|
return new Response("Not found", { status: 404 });
|
|
@@ -17652,20 +17872,20 @@ var public_reader_default = app9;
|
|
|
17652
17872
|
|
|
17653
17873
|
// server/routes/webchat.ts
|
|
17654
17874
|
import { basename as basename11, dirname as dirname11 } from "path";
|
|
17655
|
-
import { join as
|
|
17656
|
-
import { existsSync as existsSync25, readdirSync as
|
|
17875
|
+
import { join as join38 } from "path";
|
|
17876
|
+
import { existsSync as existsSync25, readdirSync as readdirSync20, readFileSync as readFileSync30, renameSync as renameSync4, statSync as statSync19, writeFileSync as writeFileSync11 } from "fs";
|
|
17657
17877
|
|
|
17658
17878
|
// server/canonical-webchat-override.ts
|
|
17659
|
-
import { readFileSync as
|
|
17660
|
-
import { join as
|
|
17879
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync9, renameSync as renameSync2 } from "fs";
|
|
17880
|
+
import { join as join36 } from "path";
|
|
17661
17881
|
var FILE = "canonical-webchat-session.json";
|
|
17662
17882
|
var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
17663
17883
|
function canonicalOverridePath(accountDir) {
|
|
17664
|
-
return
|
|
17884
|
+
return join36(accountDir, FILE);
|
|
17665
17885
|
}
|
|
17666
17886
|
function readRaw(accountDir) {
|
|
17667
17887
|
try {
|
|
17668
|
-
return JSON.parse(
|
|
17888
|
+
return JSON.parse(readFileSync28(canonicalOverridePath(accountDir), "utf8"));
|
|
17669
17889
|
} catch {
|
|
17670
17890
|
return null;
|
|
17671
17891
|
}
|
|
@@ -17778,8 +17998,8 @@ function isNewSessionEffortLevel(value) {
|
|
|
17778
17998
|
}
|
|
17779
17999
|
|
|
17780
18000
|
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
17781
|
-
import { existsSync as existsSync24, mkdirSync as mkdirSync4, readdirSync as
|
|
17782
|
-
import { join as
|
|
18001
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync4, readdirSync as readdirSync19, readFileSync as readFileSync29, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
|
|
18002
|
+
import { join as join37 } from "path";
|
|
17783
18003
|
function escapeRegExp(s) {
|
|
17784
18004
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
17785
18005
|
}
|
|
@@ -17787,7 +18007,7 @@ function createSidecarStore(config) {
|
|
|
17787
18007
|
const { suffix, validate: validate3 } = config;
|
|
17788
18008
|
const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
|
|
17789
18009
|
function pathFor(sessionsDir, id) {
|
|
17790
|
-
return
|
|
18010
|
+
return join37(sessionsDir, `${id}${suffix}`);
|
|
17791
18011
|
}
|
|
17792
18012
|
function write(sessionsDir, id, record) {
|
|
17793
18013
|
mkdirSync4(sessionsDir, { recursive: true });
|
|
@@ -17808,7 +18028,7 @@ function createSidecarStore(config) {
|
|
|
17808
18028
|
function readFileAt(path) {
|
|
17809
18029
|
let raw;
|
|
17810
18030
|
try {
|
|
17811
|
-
raw =
|
|
18031
|
+
raw = readFileSync29(path, "utf8");
|
|
17812
18032
|
} catch {
|
|
17813
18033
|
return null;
|
|
17814
18034
|
}
|
|
@@ -17824,17 +18044,17 @@ function createSidecarStore(config) {
|
|
|
17824
18044
|
function readAll3(sessionsDir, onSkip) {
|
|
17825
18045
|
let names;
|
|
17826
18046
|
try {
|
|
17827
|
-
names =
|
|
18047
|
+
names = readdirSync19(sessionsDir, { withFileTypes: true }).filter((entry3) => entry3.isFile()).map((entry3) => entry3.name);
|
|
17828
18048
|
} catch {
|
|
17829
18049
|
return [];
|
|
17830
18050
|
}
|
|
17831
18051
|
const out = [];
|
|
17832
18052
|
for (const name of names) {
|
|
17833
18053
|
if (!suffixRe.test(name)) continue;
|
|
17834
|
-
const path =
|
|
18054
|
+
const path = join37(sessionsDir, name);
|
|
17835
18055
|
let raw;
|
|
17836
18056
|
try {
|
|
17837
|
-
raw =
|
|
18057
|
+
raw = readFileSync29(path, "utf8");
|
|
17838
18058
|
} catch {
|
|
17839
18059
|
onSkip?.(name, "unreadable");
|
|
17840
18060
|
continue;
|
|
@@ -17907,7 +18127,7 @@ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9
|
|
|
17907
18127
|
function locateSession(sessionId) {
|
|
17908
18128
|
const dir = findSessionProjectDir(sessionId);
|
|
17909
18129
|
if (!dir) return { projectDir: null, channel: null, accountId: null };
|
|
17910
|
-
const meta = readSidecarMeta(
|
|
18130
|
+
const meta = readSidecarMeta(join38(dir, `${sessionId}.meta.json`));
|
|
17911
18131
|
return { projectDir: dir, channel: meta.channel, accountId: meta.accountId };
|
|
17912
18132
|
}
|
|
17913
18133
|
function resolveQuoted(sessionId, quotedUuid, sendId) {
|
|
@@ -17925,7 +18145,7 @@ function resolveQuoted(sessionId, quotedUuid, sendId) {
|
|
|
17925
18145
|
let line;
|
|
17926
18146
|
try {
|
|
17927
18147
|
const needle = `"uuid":"${quotedUuid}"`;
|
|
17928
|
-
line =
|
|
18148
|
+
line = readFileSync30(join38(projectDir, `${sessionId}.jsonl`), "utf8").split("\n").find((l) => l.includes(needle));
|
|
17929
18149
|
} catch {
|
|
17930
18150
|
log2(false, 0);
|
|
17931
18151
|
return void 0;
|
|
@@ -17942,15 +18162,15 @@ function resolveQuoted(sessionId, quotedUuid, sendId) {
|
|
|
17942
18162
|
function locateSidecar(sessionId) {
|
|
17943
18163
|
const cfg = claudeConfigDir();
|
|
17944
18164
|
if (!cfg) return null;
|
|
17945
|
-
const projectsRoot =
|
|
18165
|
+
const projectsRoot = join38(cfg, "projects");
|
|
17946
18166
|
let slugs;
|
|
17947
18167
|
try {
|
|
17948
|
-
slugs =
|
|
18168
|
+
slugs = readdirSync20(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
17949
18169
|
} catch {
|
|
17950
18170
|
return null;
|
|
17951
18171
|
}
|
|
17952
18172
|
for (const slug of slugs) {
|
|
17953
|
-
const metaPath =
|
|
18173
|
+
const metaPath = join38(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
17954
18174
|
if (existsSync25(metaPath)) return readSidecarMeta(metaPath);
|
|
17955
18175
|
}
|
|
17956
18176
|
return null;
|
|
@@ -17960,7 +18180,7 @@ function readTargetOwner(sessionId) {
|
|
|
17960
18180
|
if (sidecar !== null) return { found: true, owner: sidecar.adminUserId };
|
|
17961
18181
|
const { projectDir } = locateSession(sessionId);
|
|
17962
18182
|
if (projectDir !== null) {
|
|
17963
|
-
return { found: true, owner: readSidecarMeta(
|
|
18183
|
+
return { found: true, owner: readSidecarMeta(join38(projectDir, `${sessionId}.meta.json`)).adminUserId };
|
|
17964
18184
|
}
|
|
17965
18185
|
return { found: false, owner: null };
|
|
17966
18186
|
}
|
|
@@ -17968,7 +18188,7 @@ function readSourceRowMeta(sessionId) {
|
|
|
17968
18188
|
const sidecar = locateSidecar(sessionId);
|
|
17969
18189
|
if (sidecar !== null) return sidecar;
|
|
17970
18190
|
const { projectDir } = locateSession(sessionId);
|
|
17971
|
-
if (projectDir !== null) return readSidecarMeta(
|
|
18191
|
+
if (projectDir !== null) return readSidecarMeta(join38(projectDir, `${sessionId}.meta.json`));
|
|
17972
18192
|
return null;
|
|
17973
18193
|
}
|
|
17974
18194
|
function ownedByRequester(owner, requesterUserId, primaryUserId) {
|
|
@@ -17981,7 +18201,7 @@ function sessionSidecarExists(sessionId) {
|
|
|
17981
18201
|
function jsonlSizeBytes(projectDir, sessionId) {
|
|
17982
18202
|
if (projectDir === null) return null;
|
|
17983
18203
|
try {
|
|
17984
|
-
return
|
|
18204
|
+
return statSync19(join38(projectDir, `${sessionId}.jsonl`)).size;
|
|
17985
18205
|
} catch {
|
|
17986
18206
|
return null;
|
|
17987
18207
|
}
|
|
@@ -18109,15 +18329,15 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccoun
|
|
|
18109
18329
|
const cfg = claudeConfigDir();
|
|
18110
18330
|
if (!cfg) return null;
|
|
18111
18331
|
let best = null;
|
|
18112
|
-
for (const { path, isSubagent, archived } of enumerateJsonls(
|
|
18332
|
+
for (const { path, isSubagent, archived } of enumerateJsonls(join38(cfg, "projects"))) {
|
|
18113
18333
|
if (isSubagent || archived) continue;
|
|
18114
18334
|
const id = basename11(path).slice(0, -".jsonl".length);
|
|
18115
|
-
const meta = readSidecarMeta(
|
|
18335
|
+
const meta = readSidecarMeta(join38(dirname11(path), `${id}.meta.json`));
|
|
18116
18336
|
if (meta.role !== "admin" || meta.channel !== "webchat") continue;
|
|
18117
18337
|
if (multiAccount && meta.accountId !== scopeAccountId) continue;
|
|
18118
18338
|
let mtimeMs;
|
|
18119
18339
|
try {
|
|
18120
|
-
mtimeMs =
|
|
18340
|
+
mtimeMs = statSync19(path).mtimeMs;
|
|
18121
18341
|
} catch {
|
|
18122
18342
|
continue;
|
|
18123
18343
|
}
|
|
@@ -18472,9 +18692,9 @@ ${timeline}`;
|
|
|
18472
18692
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} accountId=none reason=no-account-for-session`);
|
|
18473
18693
|
return c.json({ error: "account unresolved" }, 503);
|
|
18474
18694
|
}
|
|
18475
|
-
const accountJsonPath =
|
|
18695
|
+
const accountJsonPath = join38(account.accountDir, "account.json");
|
|
18476
18696
|
try {
|
|
18477
|
-
const parsed = JSON.parse(
|
|
18697
|
+
const parsed = JSON.parse(readFileSync30(accountJsonPath, "utf8"));
|
|
18478
18698
|
if (op === "model") parsed.adminModel = value;
|
|
18479
18699
|
else if (op === "effort") parsed.effort = value;
|
|
18480
18700
|
else parsed.adminPermissionMode = value;
|
|
@@ -18520,7 +18740,7 @@ ${timeline}`;
|
|
|
18520
18740
|
const cfg2 = claudeConfigDir();
|
|
18521
18741
|
if (cfg2) {
|
|
18522
18742
|
const source2 = resolveBridgeSource(
|
|
18523
|
-
|
|
18743
|
+
join38(cfg2, "sessions"),
|
|
18524
18744
|
target,
|
|
18525
18745
|
(id) => locateSession(id).projectDir !== null
|
|
18526
18746
|
);
|
|
@@ -18547,7 +18767,7 @@ ${timeline}`;
|
|
|
18547
18767
|
const cfg = claudeConfigDir();
|
|
18548
18768
|
let projectDir = null;
|
|
18549
18769
|
if (cfg) {
|
|
18550
|
-
for (const { path } of enumerateJsonls(
|
|
18770
|
+
for (const { path } of enumerateJsonls(join38(cfg, "projects"))) {
|
|
18551
18771
|
if (basename11(path) === `${sessionId}.jsonl`) {
|
|
18552
18772
|
projectDir = dirname11(path);
|
|
18553
18773
|
break;
|
|
@@ -18555,7 +18775,7 @@ ${timeline}`;
|
|
|
18555
18775
|
}
|
|
18556
18776
|
}
|
|
18557
18777
|
if (source === "latest" && requesterUserId !== null) {
|
|
18558
|
-
const owner = readSidecarMeta(
|
|
18778
|
+
const owner = readSidecarMeta(join38(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
|
|
18559
18779
|
if (owner !== null && owner !== requesterUserId && requesterUserId !== primaryUserId) {
|
|
18560
18780
|
console.error(`[webchat:inbound] op=session-resolve-foreign key=${sessionId.slice(0, 8)} owner=${owner.slice(0, 8)} requester=${requesterUserId.slice(0, 8)}`);
|
|
18561
18781
|
}
|
|
@@ -18680,13 +18900,13 @@ var webchat_greeting_default = app10;
|
|
|
18680
18900
|
|
|
18681
18901
|
// server/routes/telegram.ts
|
|
18682
18902
|
import { homedir as homedir2 } from "os";
|
|
18683
|
-
import { resolve as resolve25, join as
|
|
18684
|
-
import { existsSync as existsSync29, readFileSync as
|
|
18903
|
+
import { resolve as resolve25, join as join43 } from "path";
|
|
18904
|
+
import { existsSync as existsSync29, readFileSync as readFileSync34 } from "fs";
|
|
18685
18905
|
|
|
18686
18906
|
// ../lib/telegram-managed-bot/src/index.ts
|
|
18687
18907
|
import { randomBytes } from "crypto";
|
|
18688
|
-
import { existsSync as existsSync26, readFileSync as
|
|
18689
|
-
import { dirname as dirname12, join as
|
|
18908
|
+
import { existsSync as existsSync26, readFileSync as readFileSync31, writeFileSync as writeFileSync12, mkdirSync as mkdirSync5 } from "fs";
|
|
18909
|
+
import { dirname as dirname12, join as join39 } from "path";
|
|
18690
18910
|
var TELEGRAM_API = "https://api.telegram.org";
|
|
18691
18911
|
var TELEGRAM_ALLOWED_UPDATES = [
|
|
18692
18912
|
"message",
|
|
@@ -18753,13 +18973,13 @@ async function setTelegramWebhook(botToken, webhookUrl, secretFilePath, fetchImp
|
|
|
18753
18973
|
return { ok: true, secret };
|
|
18754
18974
|
}
|
|
18755
18975
|
function writeTelegramBotEntry(accountDir, entry3) {
|
|
18756
|
-
const configPath3 =
|
|
18976
|
+
const configPath3 = join39(accountDir, "account.json");
|
|
18757
18977
|
if (!existsSync26(configPath3)) {
|
|
18758
18978
|
return { ok: false, error: `account.json not found at ${configPath3}` };
|
|
18759
18979
|
}
|
|
18760
18980
|
let config;
|
|
18761
18981
|
try {
|
|
18762
|
-
config = JSON.parse(
|
|
18982
|
+
config = JSON.parse(readFileSync31(configPath3, "utf-8"));
|
|
18763
18983
|
} catch (e) {
|
|
18764
18984
|
return { ok: false, error: `account.json parse failed: ${e.message}` };
|
|
18765
18985
|
}
|
|
@@ -18842,82 +19062,6 @@ async function setManagedBotAccessSettings(managingBotToken, userId, isAccessRes
|
|
|
18842
19062
|
return r.ok ? { ok: true } : { ok: false, error: r.error };
|
|
18843
19063
|
}
|
|
18844
19064
|
|
|
18845
|
-
// app/lib/telegram/access-control.ts
|
|
18846
|
-
function checkTelegramAccess(params) {
|
|
18847
|
-
const { senderId, entry: entry3, chatId, chatType } = params;
|
|
18848
|
-
const isGroup = chatType === "group" || chatType === "supergroup";
|
|
18849
|
-
const isChannel = chatType === "channel";
|
|
18850
|
-
if (isChannel && entry3.role !== "public") {
|
|
18851
|
-
return {
|
|
18852
|
-
allowed: false,
|
|
18853
|
-
reason: entry3.role === "admin" ? "admin-entry-no-channels" : entry3.role === "specialist" ? "specialist-entry-no-channels" : "unbound-entry-no-channels",
|
|
18854
|
-
agentType: entry3.role === "admin" ? "admin" : entry3.role === "specialist" ? "specialist" : "public"
|
|
18855
|
-
};
|
|
18856
|
-
}
|
|
18857
|
-
if (isGroup && entry3.role !== "public") {
|
|
18858
|
-
return {
|
|
18859
|
-
allowed: false,
|
|
18860
|
-
reason: entry3.role === "admin" ? "admin-entry-no-groups" : entry3.role === "specialist" ? "specialist-entry-no-groups" : "unbound-entry-no-groups",
|
|
18861
|
-
agentType: entry3.role === "admin" ? "admin" : entry3.role === "specialist" ? "specialist" : "public"
|
|
18862
|
-
};
|
|
18863
|
-
}
|
|
18864
|
-
if (entry3.role === "admin") {
|
|
18865
|
-
const adminUsers = entry3.adminUsers ?? [];
|
|
18866
|
-
if (adminUsers.includes(senderId)) {
|
|
18867
|
-
return { allowed: true, reason: "admin-binding", agentType: "admin" };
|
|
18868
|
-
}
|
|
18869
|
-
return { allowed: false, reason: "not-admin-user", agentType: "admin" };
|
|
18870
|
-
}
|
|
18871
|
-
if (isGroup && entry3.role === "public") {
|
|
18872
|
-
const groupPolicy = entry3.groupPolicy ?? "disabled";
|
|
18873
|
-
if (groupPolicy === "allowlist") {
|
|
18874
|
-
const allowGroups = entry3.allowGroups ?? [];
|
|
18875
|
-
if (allowGroups.includes(chatId)) {
|
|
18876
|
-
return { allowed: true, reason: "group-allowlist-match", agentType: "public" };
|
|
18877
|
-
}
|
|
18878
|
-
return { allowed: false, reason: "not-in-allowGroups", agentType: "public" };
|
|
18879
|
-
}
|
|
18880
|
-
return { allowed: false, reason: "group-policy-disabled", agentType: "public" };
|
|
18881
|
-
}
|
|
18882
|
-
if (isChannel && entry3.role === "public") {
|
|
18883
|
-
const channelPolicy = entry3.channelPolicy ?? "disabled";
|
|
18884
|
-
if (channelPolicy === "allowlist") {
|
|
18885
|
-
const allowChannels = entry3.allowChannels ?? [];
|
|
18886
|
-
if (allowChannels.includes(chatId)) {
|
|
18887
|
-
return { allowed: true, reason: "channel-allowlist-match", agentType: "public" };
|
|
18888
|
-
}
|
|
18889
|
-
return { allowed: false, reason: "not-in-allowChannels", agentType: "public" };
|
|
18890
|
-
}
|
|
18891
|
-
return { allowed: false, reason: "channel-policy-disabled", agentType: "public" };
|
|
18892
|
-
}
|
|
18893
|
-
if (entry3.role === "unbound") {
|
|
18894
|
-
return { allowed: false, reason: "bot-unbound", agentType: "public" };
|
|
18895
|
-
}
|
|
18896
|
-
if (entry3.role === "specialist") {
|
|
18897
|
-
const allowFrom = entry3.allowFrom ?? [];
|
|
18898
|
-
if (allowFrom.includes(senderId)) {
|
|
18899
|
-
return { allowed: true, reason: "specialist-allowlist-match", agentType: "specialist" };
|
|
18900
|
-
}
|
|
18901
|
-
return { allowed: false, reason: "not-in-allowlist", agentType: "specialist" };
|
|
18902
|
-
}
|
|
18903
|
-
const policy = entry3.dmPolicy ?? "disabled";
|
|
18904
|
-
switch (policy) {
|
|
18905
|
-
case "open":
|
|
18906
|
-
return { allowed: true, reason: "dm-policy-open", agentType: "public" };
|
|
18907
|
-
case "allowlist": {
|
|
18908
|
-
const allowFrom = entry3.allowFrom ?? [];
|
|
18909
|
-
if (allowFrom.includes(senderId)) {
|
|
18910
|
-
return { allowed: true, reason: "allowlist-match", agentType: "public" };
|
|
18911
|
-
}
|
|
18912
|
-
return { allowed: false, reason: "not-in-allowlist", agentType: "public" };
|
|
18913
|
-
}
|
|
18914
|
-
case "disabled":
|
|
18915
|
-
return { allowed: false, reason: "dm-policy-disabled", agentType: "public" };
|
|
18916
|
-
default:
|
|
18917
|
-
return { allowed: false, reason: "unknown-dm-policy", agentType: "public" };
|
|
18918
|
-
}
|
|
18919
|
-
}
|
|
18920
|
-
|
|
18921
19065
|
// app/lib/telegram/managed-bot.ts
|
|
18922
19066
|
function parseManagedBotUpdate(u) {
|
|
18923
19067
|
const id = u?.bot?.id;
|
|
@@ -19730,7 +19874,7 @@ function routeTelegramUpdate(input) {
|
|
|
19730
19874
|
|
|
19731
19875
|
// app/lib/telegram/inbound/media.ts
|
|
19732
19876
|
var import_dist5 = __toESM(require_dist4(), 1);
|
|
19733
|
-
import { join as
|
|
19877
|
+
import { join as join40 } from "path";
|
|
19734
19878
|
var TAG30 = "[telegram-inbound]";
|
|
19735
19879
|
var TELEGRAM_MEDIA_DIR = "/tmp/maxy-media";
|
|
19736
19880
|
var DOWNLOAD_TIMEOUT_MS = 45e3;
|
|
@@ -19758,7 +19902,7 @@ async function downloadTelegramMedia(input) {
|
|
|
19758
19902
|
if (!meta.ok) {
|
|
19759
19903
|
result = { ...base, failure: meta.failure };
|
|
19760
19904
|
} else {
|
|
19761
|
-
const path =
|
|
19905
|
+
const path = join40(
|
|
19762
19906
|
dir,
|
|
19763
19907
|
`tg-${(0, import_dist5.pathSafe)(input.botId)}-${(0, import_dist5.pathSafe)(item.fileUniqueId)}.${(0, import_dist5.extensionFor)(meta.filePath, item.mimetype)}`
|
|
19764
19908
|
);
|
|
@@ -20625,8 +20769,8 @@ async function handleDispatchMedia(p) {
|
|
|
20625
20769
|
}
|
|
20626
20770
|
|
|
20627
20771
|
// app/lib/telegram/live-location.ts
|
|
20628
|
-
import { existsSync as existsSync27, mkdirSync as mkdirSync6, readFileSync as
|
|
20629
|
-
import { join as
|
|
20772
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync6, readFileSync as readFileSync32, readdirSync as readdirSync21, statSync as statSync20, writeFileSync as writeFileSync13 } from "fs";
|
|
20773
|
+
import { join as join41 } from "path";
|
|
20630
20774
|
var TAG37 = "[telegram-inbound]";
|
|
20631
20775
|
var LIVE_LOCATION_FILE = "telegram-live-location.json";
|
|
20632
20776
|
var LIVE_LOCATION_CENSUS_TAG = "[telegram-live-location-census]";
|
|
@@ -20641,7 +20785,7 @@ function isRecord(v) {
|
|
|
20641
20785
|
function readAll(path) {
|
|
20642
20786
|
if (!existsSync27(path)) return {};
|
|
20643
20787
|
try {
|
|
20644
|
-
const parsed = JSON.parse(
|
|
20788
|
+
const parsed = JSON.parse(readFileSync32(path, "utf-8"));
|
|
20645
20789
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
20646
20790
|
const out = {};
|
|
20647
20791
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -20658,7 +20802,7 @@ function isExpired(rec, now) {
|
|
|
20658
20802
|
function writeLiveLocation(input) {
|
|
20659
20803
|
const { accountDir, botId, senderId, now, emit } = input;
|
|
20660
20804
|
const key2 = liveLocationKey(botId, senderId);
|
|
20661
|
-
const path =
|
|
20805
|
+
const path = join41(accountDir, LIVE_LOCATION_FILE);
|
|
20662
20806
|
const stored = readAll(path);
|
|
20663
20807
|
const livePeriodS = input.livePeriodS ?? stored[key2]?.livePeriodS ?? null;
|
|
20664
20808
|
if (livePeriodS === null) {
|
|
@@ -20707,9 +20851,9 @@ function liveLocationCensusLine(accountsRoot, now) {
|
|
|
20707
20851
|
let expired = 0;
|
|
20708
20852
|
let oldestAgeMs = 0;
|
|
20709
20853
|
try {
|
|
20710
|
-
for (const entry3 of
|
|
20711
|
-
const path =
|
|
20712
|
-
if (!existsSync27(path) || !
|
|
20854
|
+
for (const entry3 of readdirSync21(accountsRoot)) {
|
|
20855
|
+
const path = join41(accountsRoot, entry3, LIVE_LOCATION_FILE);
|
|
20856
|
+
if (!existsSync27(path) || !statSync20(path).isFile()) continue;
|
|
20713
20857
|
for (const rec of Object.values(readAll(path))) {
|
|
20714
20858
|
records5 += 1;
|
|
20715
20859
|
if (isExpired(rec, now)) expired += 1;
|
|
@@ -20728,8 +20872,8 @@ function liveLocationCensusLine(accountsRoot, now) {
|
|
|
20728
20872
|
}
|
|
20729
20873
|
|
|
20730
20874
|
// app/lib/telegram/business-connection.ts
|
|
20731
|
-
import { existsSync as existsSync28, mkdirSync as mkdirSync7, readFileSync as
|
|
20732
|
-
import { join as
|
|
20875
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync7, readFileSync as readFileSync33, writeFileSync as writeFileSync14 } from "fs";
|
|
20876
|
+
import { join as join42 } from "path";
|
|
20733
20877
|
var TAG38 = "[telegram-inbound]";
|
|
20734
20878
|
var BUSINESS_CONNECTION_FILE = "telegram-business-connection.json";
|
|
20735
20879
|
function truncateConnectionId(id) {
|
|
@@ -20743,7 +20887,7 @@ function isRecord2(v) {
|
|
|
20743
20887
|
function readAll2(path) {
|
|
20744
20888
|
if (!existsSync28(path)) return {};
|
|
20745
20889
|
try {
|
|
20746
|
-
const parsed = JSON.parse(
|
|
20890
|
+
const parsed = JSON.parse(readFileSync33(path, "utf-8"));
|
|
20747
20891
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
20748
20892
|
const out = {};
|
|
20749
20893
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -20779,7 +20923,7 @@ function writeBusinessConnection(input) {
|
|
|
20779
20923
|
rights,
|
|
20780
20924
|
at: now
|
|
20781
20925
|
};
|
|
20782
|
-
const path =
|
|
20926
|
+
const path = join42(accountDir, BUSINESS_CONNECTION_FILE);
|
|
20783
20927
|
const all = readAll2(path);
|
|
20784
20928
|
all[botId] = next;
|
|
20785
20929
|
try {
|
|
@@ -20793,12 +20937,12 @@ function writeBusinessConnection(input) {
|
|
|
20793
20937
|
return { written: true, reason: "ok" };
|
|
20794
20938
|
}
|
|
20795
20939
|
function readBusinessConnection(accountDir, botId) {
|
|
20796
|
-
const rec = readAll2(
|
|
20940
|
+
const rec = readAll2(join42(accountDir, BUSINESS_CONNECTION_FILE))[botId];
|
|
20797
20941
|
if (!rec || !rec.isEnabled) return null;
|
|
20798
20942
|
return rec;
|
|
20799
20943
|
}
|
|
20800
20944
|
function readAllBusinessConnections(accountDir) {
|
|
20801
|
-
return readAll2(
|
|
20945
|
+
return readAll2(join42(accountDir, BUSINESS_CONNECTION_FILE));
|
|
20802
20946
|
}
|
|
20803
20947
|
|
|
20804
20948
|
// app/lib/telegram/business-window.ts
|
|
@@ -20854,10 +20998,10 @@ function logValue4(v) {
|
|
|
20854
20998
|
}
|
|
20855
20999
|
function configDirName() {
|
|
20856
21000
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
|
|
20857
|
-
const brandPath =
|
|
21001
|
+
const brandPath = join43(platformRoot5, "config", "brand.json");
|
|
20858
21002
|
if (existsSync29(brandPath)) {
|
|
20859
21003
|
try {
|
|
20860
|
-
return JSON.parse(
|
|
21004
|
+
return JSON.parse(readFileSync34(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
20861
21005
|
} catch {
|
|
20862
21006
|
}
|
|
20863
21007
|
}
|
|
@@ -20885,7 +21029,7 @@ function provisionedWebhookUrl(c, botId) {
|
|
|
20885
21029
|
}
|
|
20886
21030
|
function accountConfig(accountDir) {
|
|
20887
21031
|
try {
|
|
20888
|
-
return JSON.parse(
|
|
21032
|
+
return JSON.parse(readFileSync34(join43(accountDir, "account.json"), "utf-8"));
|
|
20889
21033
|
} catch {
|
|
20890
21034
|
return {};
|
|
20891
21035
|
}
|
|
@@ -20967,7 +21111,7 @@ app11.post("/", async (c) => {
|
|
|
20967
21111
|
console.error(`${TAG39} op=secret botId=${botId} result=missing-file`);
|
|
20968
21112
|
return c.json({ ok: false }, 401);
|
|
20969
21113
|
}
|
|
20970
|
-
const expected =
|
|
21114
|
+
const expected = readFileSync34(sp, "utf-8").trim();
|
|
20971
21115
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
20972
21116
|
if (got !== expected) {
|
|
20973
21117
|
console.error(`${TAG39} op=secret botId=${botId} result=mismatch`);
|
|
@@ -21912,16 +22056,16 @@ function mountTelegramRoutes(app81, telegramRoutes) {
|
|
|
21912
22056
|
}
|
|
21913
22057
|
|
|
21914
22058
|
// server/routes/quickbooks.ts
|
|
21915
|
-
import { join as
|
|
21916
|
-
import { existsSync as existsSync30, readFileSync as
|
|
22059
|
+
import { join as join44 } from "path";
|
|
22060
|
+
import { existsSync as existsSync30, readFileSync as readFileSync35, writeFileSync as writeFileSync15, mkdirSync as mkdirSync8, rmSync as rmSync4, renameSync as renameSync5 } from "fs";
|
|
21917
22061
|
var TAG40 = "[quickbooks]";
|
|
21918
22062
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
21919
22063
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
21920
22064
|
function pendingPath(accountDir, state) {
|
|
21921
|
-
return
|
|
22065
|
+
return join44(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
|
|
21922
22066
|
}
|
|
21923
22067
|
function storePath(accountDir) {
|
|
21924
|
-
return
|
|
22068
|
+
return join44(accountDir, "secrets", "quickbooks.json");
|
|
21925
22069
|
}
|
|
21926
22070
|
async function completeConsent(args) {
|
|
21927
22071
|
const { accountDir, code, realmId } = args;
|
|
@@ -21940,7 +22084,7 @@ async function completeConsent(args) {
|
|
|
21940
22084
|
try {
|
|
21941
22085
|
let pending;
|
|
21942
22086
|
try {
|
|
21943
|
-
pending = JSON.parse(
|
|
22087
|
+
pending = JSON.parse(readFileSync35(claimFile, "utf-8"));
|
|
21944
22088
|
} catch {
|
|
21945
22089
|
console.error(`${TAG40} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
21946
22090
|
return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
|
|
@@ -21956,7 +22100,7 @@ async function completeConsent(args) {
|
|
|
21956
22100
|
if (!existsSync30(storePath(accountDir))) {
|
|
21957
22101
|
return { ok: false, status: 500, message: "No QuickBooks credentials are stored for this account.", stateValid: true };
|
|
21958
22102
|
}
|
|
21959
|
-
const store2 = JSON.parse(
|
|
22103
|
+
const store2 = JSON.parse(readFileSync35(storePath(accountDir), "utf-8"));
|
|
21960
22104
|
const form = new URLSearchParams({
|
|
21961
22105
|
grant_type: "authorization_code",
|
|
21962
22106
|
code,
|
|
@@ -21988,9 +22132,9 @@ async function completeConsent(args) {
|
|
|
21988
22132
|
refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
|
|
21989
22133
|
lastRefresh: now
|
|
21990
22134
|
};
|
|
21991
|
-
mkdirSync8(
|
|
22135
|
+
mkdirSync8(join44(accountDir, "secrets"), { recursive: true });
|
|
21992
22136
|
writeFileSync15(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
21993
|
-
const persisted = JSON.parse(
|
|
22137
|
+
const persisted = JSON.parse(readFileSync35(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
21994
22138
|
console.error(`${TAG40} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
21995
22139
|
return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
|
|
21996
22140
|
} finally {
|
|
@@ -22021,7 +22165,7 @@ var quickbooks_default = app12;
|
|
|
22021
22165
|
|
|
22022
22166
|
// server/routes/onboarding.ts
|
|
22023
22167
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync4 } from "child_process";
|
|
22024
|
-
import { openSync as
|
|
22168
|
+
import { openSync as openSync9, closeSync as closeSync9, appendFileSync as appendFileSync4, writeFileSync as writeFileSync17, writeSync, existsSync as existsSync32, readFileSync as readFileSync37, unlinkSync as unlinkSync3 } from "fs";
|
|
22025
22169
|
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
22026
22170
|
|
|
22027
22171
|
// app/lib/claude-spawn-env.ts
|
|
@@ -22030,7 +22174,7 @@ function claudeBin() {
|
|
|
22030
22174
|
}
|
|
22031
22175
|
|
|
22032
22176
|
// server/routes/onboarding.ts
|
|
22033
|
-
import { dirname as dirname14, join as
|
|
22177
|
+
import { dirname as dirname14, join as join46 } from "path";
|
|
22034
22178
|
|
|
22035
22179
|
// app/lib/claude-keychain.ts
|
|
22036
22180
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
@@ -22161,19 +22305,19 @@ function readHostCredsBlob(service) {
|
|
|
22161
22305
|
}
|
|
22162
22306
|
|
|
22163
22307
|
// ../lib/admins-write/src/index.ts
|
|
22164
|
-
import { existsSync as existsSync31, readFileSync as
|
|
22165
|
-
import { dirname as dirname13, join as
|
|
22308
|
+
import { existsSync as existsSync31, readFileSync as readFileSync36, writeFileSync as writeFileSync16, renameSync as renameSync6, mkdirSync as mkdirSync9, readdirSync as readdirSync22, statSync as statSync21, appendFileSync as appendFileSync3 } from "fs";
|
|
22309
|
+
import { dirname as dirname13, join as join45 } from "path";
|
|
22166
22310
|
function id8(value) {
|
|
22167
22311
|
return value.slice(0, 8);
|
|
22168
22312
|
}
|
|
22169
22313
|
function formatAuditRowIds(userIds) {
|
|
22170
22314
|
return userIds.map(id8).join(",");
|
|
22171
22315
|
}
|
|
22172
|
-
function appendUsersAuditLine(audit,
|
|
22316
|
+
function appendUsersAuditLine(audit, fields2) {
|
|
22173
22317
|
const sess = audit.session ? ` session=${id8(audit.session)}` : "";
|
|
22174
22318
|
const actor = audit.actor.includes("-") ? id8(audit.actor) : audit.actor;
|
|
22175
22319
|
const targetFields = audit.target !== void 0 ? ` target=${audit.target.includes("-") ? id8(audit.target) : audit.target} explicitUserId=${audit.explicitUserId ? "true" : "false"}` : "";
|
|
22176
|
-
const line = `[users-audit] action=${
|
|
22320
|
+
const line = `[users-audit] action=${fields2.action} actor=${actor}${targetFields}${sess} field=${fields2.field} rowsBefore=${fields2.rowsBefore} rowsAfter=${fields2.rowsAfter} ts=${(/* @__PURE__ */ new Date()).toISOString()}
|
|
22177
22321
|
`;
|
|
22178
22322
|
try {
|
|
22179
22323
|
mkdirSync9(dirname13(audit.logFile), { recursive: true, mode: 448 });
|
|
@@ -22184,8 +22328,8 @@ function appendUsersAuditLine(audit, fields) {
|
|
|
22184
22328
|
);
|
|
22185
22329
|
}
|
|
22186
22330
|
}
|
|
22187
|
-
function logUsersAudit(audit,
|
|
22188
|
-
appendUsersAuditLine(audit,
|
|
22331
|
+
function logUsersAudit(audit, fields2) {
|
|
22332
|
+
appendUsersAuditLine(audit, fields2);
|
|
22189
22333
|
}
|
|
22190
22334
|
function logLine(input, result) {
|
|
22191
22335
|
const userIdShort = input.userId.slice(0, 8);
|
|
@@ -22204,7 +22348,7 @@ function writeAdminEntry(input) {
|
|
|
22204
22348
|
try {
|
|
22205
22349
|
let users = [];
|
|
22206
22350
|
if (existsSync31(input.usersFile)) {
|
|
22207
|
-
const raw =
|
|
22351
|
+
const raw = readFileSync36(input.usersFile, "utf-8").trim();
|
|
22208
22352
|
if (raw) {
|
|
22209
22353
|
const parsed = JSON.parse(raw);
|
|
22210
22354
|
if (!Array.isArray(parsed)) {
|
|
@@ -22246,11 +22390,11 @@ function writeAdminEntry(input) {
|
|
|
22246
22390
|
return result;
|
|
22247
22391
|
}
|
|
22248
22392
|
try {
|
|
22249
|
-
const accountJsonPath =
|
|
22393
|
+
const accountJsonPath = join45(input.accountDir, "account.json");
|
|
22250
22394
|
if (!existsSync31(accountJsonPath)) {
|
|
22251
22395
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
22252
22396
|
}
|
|
22253
|
-
const config = JSON.parse(
|
|
22397
|
+
const config = JSON.parse(readFileSync36(accountJsonPath, "utf-8"));
|
|
22254
22398
|
const admins = config.admins ?? [];
|
|
22255
22399
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
22256
22400
|
result.accountJsonResult = "noop";
|
|
@@ -22272,7 +22416,7 @@ function computeAdminStoreDivergence(input) {
|
|
|
22272
22416
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
22273
22417
|
if (existsSync31(input.usersFile)) {
|
|
22274
22418
|
try {
|
|
22275
|
-
const raw =
|
|
22419
|
+
const raw = readFileSync36(input.usersFile, "utf-8").trim();
|
|
22276
22420
|
if (raw) {
|
|
22277
22421
|
const users = JSON.parse(raw);
|
|
22278
22422
|
for (const u of users) {
|
|
@@ -22287,24 +22431,24 @@ function computeAdminStoreDivergence(input) {
|
|
|
22287
22431
|
if (existsSync31(input.accountsDir)) {
|
|
22288
22432
|
let entries2;
|
|
22289
22433
|
try {
|
|
22290
|
-
entries2 =
|
|
22434
|
+
entries2 = readdirSync22(input.accountsDir);
|
|
22291
22435
|
} catch (err) {
|
|
22292
22436
|
result.errors.push({ source: input.accountsDir, detail: err instanceof Error ? err.message : String(err) });
|
|
22293
22437
|
return result;
|
|
22294
22438
|
}
|
|
22295
22439
|
for (const entry3 of entries2) {
|
|
22296
22440
|
if (entry3.startsWith(".")) continue;
|
|
22297
|
-
const accountDir =
|
|
22441
|
+
const accountDir = join45(input.accountsDir, entry3);
|
|
22298
22442
|
try {
|
|
22299
|
-
if (!
|
|
22443
|
+
if (!statSync21(accountDir).isDirectory()) continue;
|
|
22300
22444
|
} catch {
|
|
22301
22445
|
continue;
|
|
22302
22446
|
}
|
|
22303
|
-
const accountJsonPath =
|
|
22447
|
+
const accountJsonPath = join45(accountDir, "account.json");
|
|
22304
22448
|
if (!existsSync31(accountJsonPath)) continue;
|
|
22305
22449
|
let admins = [];
|
|
22306
22450
|
try {
|
|
22307
|
-
const config = JSON.parse(
|
|
22451
|
+
const config = JSON.parse(readFileSync36(accountJsonPath, "utf-8"));
|
|
22308
22452
|
admins = config.admins ?? [];
|
|
22309
22453
|
} catch (err) {
|
|
22310
22454
|
result.errors.push({ source: accountJsonPath, detail: err instanceof Error ? err.message : String(err) });
|
|
@@ -22353,7 +22497,7 @@ function hashPin2(pin) {
|
|
|
22353
22497
|
}
|
|
22354
22498
|
function readUsersFile2() {
|
|
22355
22499
|
if (!existsSync32(USERS_FILE)) return null;
|
|
22356
|
-
const raw =
|
|
22500
|
+
const raw = readFileSync37(USERS_FILE, "utf-8").trim();
|
|
22357
22501
|
if (!raw) return [];
|
|
22358
22502
|
return JSON.parse(raw);
|
|
22359
22503
|
}
|
|
@@ -22484,7 +22628,7 @@ app13.post("/claude-auth", async (c) => {
|
|
|
22484
22628
|
ensureLogDir();
|
|
22485
22629
|
appendFileSync4(logPath("claude-auth"), `==== attempt ${attemptId} ${(/* @__PURE__ */ new Date()).toISOString()} ====
|
|
22486
22630
|
`);
|
|
22487
|
-
const claudeAuthLogFd =
|
|
22631
|
+
const claudeAuthLogFd = openSync9(logPath("claude-auth"), "a");
|
|
22488
22632
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
22489
22633
|
if (process.platform === "darwin") {
|
|
22490
22634
|
vncLog("claude-auth", { action: "start", transport: "native", platform: "darwin" });
|
|
@@ -22501,7 +22645,7 @@ app13.post("/claude-auth", async (c) => {
|
|
|
22501
22645
|
claudeProc2.stdout?.on("data", onClaudeOutput);
|
|
22502
22646
|
claudeProc2.stderr?.on("data", onClaudeOutput);
|
|
22503
22647
|
claudeProc2.once("close", () => {
|
|
22504
|
-
|
|
22648
|
+
closeSync9(claudeAuthLogFd);
|
|
22505
22649
|
const writebackResult = bridgeKeychainToFile({
|
|
22506
22650
|
platform: process.platform,
|
|
22507
22651
|
before: darwinCredsBefore,
|
|
@@ -22514,7 +22658,7 @@ app13.post("/claude-auth", async (c) => {
|
|
|
22514
22658
|
});
|
|
22515
22659
|
persistKeychainService(
|
|
22516
22660
|
writebackResult,
|
|
22517
|
-
(service) => writeFileSync17(
|
|
22661
|
+
(service) => writeFileSync17(join46(dirname14(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
|
|
22518
22662
|
(line) => console.log(line)
|
|
22519
22663
|
);
|
|
22520
22664
|
if (pendingAuthLogin?.child === claudeProc2) pendingAuthLogin = null;
|
|
@@ -22539,7 +22683,7 @@ app13.post("/claude-auth", async (c) => {
|
|
|
22539
22683
|
claudeProc.stdout?.on("data", onClaudeOutput);
|
|
22540
22684
|
claudeProc.stderr?.on("data", onClaudeOutput);
|
|
22541
22685
|
claudeProc.once("close", () => {
|
|
22542
|
-
|
|
22686
|
+
closeSync9(claudeAuthLogFd);
|
|
22543
22687
|
if (pendingAuthLogin?.child === claudeProc) pendingAuthLogin = null;
|
|
22544
22688
|
});
|
|
22545
22689
|
await waitForAuthPage(2e4);
|
|
@@ -22604,7 +22748,7 @@ app13.post("/set-pin", async (c) => {
|
|
|
22604
22748
|
let installOwner = null;
|
|
22605
22749
|
if (existsSync32(INSTALL_OWNER_FILE)) {
|
|
22606
22750
|
try {
|
|
22607
|
-
const raw =
|
|
22751
|
+
const raw = readFileSync37(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
22608
22752
|
if (raw.length > 0) installOwner = raw;
|
|
22609
22753
|
} catch (err) {
|
|
22610
22754
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -22752,7 +22896,7 @@ app13.put("/set-pin", requireAdminSession, async (c) => {
|
|
|
22752
22896
|
let installOwner = null;
|
|
22753
22897
|
if (existsSync32(INSTALL_OWNER_FILE)) {
|
|
22754
22898
|
try {
|
|
22755
|
-
const raw =
|
|
22899
|
+
const raw = readFileSync37(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
22756
22900
|
if (raw.length > 0) installOwner = raw;
|
|
22757
22901
|
} catch (err) {
|
|
22758
22902
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -23209,9 +23353,9 @@ app14.post("/probe", async (c) => {
|
|
|
23209
23353
|
var field_default = app14;
|
|
23210
23354
|
|
|
23211
23355
|
// server/routes/client-error.ts
|
|
23212
|
-
import { appendFileSync as appendFileSync5, existsSync as existsSync33, renameSync as renameSync8, statSync as
|
|
23213
|
-
import { join as
|
|
23214
|
-
var CLIENT_ERRORS_LOG =
|
|
23356
|
+
import { appendFileSync as appendFileSync5, existsSync as existsSync33, renameSync as renameSync8, statSync as statSync22 } from "fs";
|
|
23357
|
+
import { join as join47 } from "path";
|
|
23358
|
+
var CLIENT_ERRORS_LOG = join47(LOG_DIR, "client-errors.log");
|
|
23215
23359
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
23216
23360
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
23217
23361
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -23269,7 +23413,7 @@ function stackHead(stack) {
|
|
|
23269
23413
|
function rotateIfNeeded() {
|
|
23270
23414
|
try {
|
|
23271
23415
|
if (!existsSync33(CLIENT_ERRORS_LOG)) return;
|
|
23272
|
-
const stats =
|
|
23416
|
+
const stats = statSync22(CLIENT_ERRORS_LOG);
|
|
23273
23417
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
23274
23418
|
renameSync8(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
23275
23419
|
} catch (err) {
|
|
@@ -23625,17 +23769,17 @@ app17.get("/", requireAdminSession, async (c) => {
|
|
|
23625
23769
|
var accounts_default = app17;
|
|
23626
23770
|
|
|
23627
23771
|
// server/routes/admin/logs.ts
|
|
23628
|
-
import { existsSync as existsSync35, readdirSync as
|
|
23772
|
+
import { existsSync as existsSync35, readdirSync as readdirSync23, readFileSync as readFileSync38, statSync as statSync23 } from "fs";
|
|
23629
23773
|
import { resolve as resolve26, basename as basename13 } from "path";
|
|
23630
23774
|
|
|
23631
23775
|
// app/lib/logs-read-resolve.ts
|
|
23632
23776
|
import { existsSync as existsSync34 } from "fs";
|
|
23633
|
-
import { join as
|
|
23777
|
+
import { join as join48 } from "path";
|
|
23634
23778
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
23635
23779
|
const tried = [filename];
|
|
23636
23780
|
const hits = [];
|
|
23637
23781
|
for (const dir of logDirs) {
|
|
23638
|
-
const fullPath =
|
|
23782
|
+
const fullPath = join48(dir, filename);
|
|
23639
23783
|
if (existsSync34(fullPath)) {
|
|
23640
23784
|
hits.push({ path: fullPath, dir });
|
|
23641
23785
|
}
|
|
@@ -23661,8 +23805,8 @@ app18.get("/", async (c) => {
|
|
|
23661
23805
|
const filePath = resolve26(dir, safe);
|
|
23662
23806
|
searched.push(filePath);
|
|
23663
23807
|
try {
|
|
23664
|
-
const buffer =
|
|
23665
|
-
const onDiskBytes =
|
|
23808
|
+
const buffer = readFileSync38(filePath);
|
|
23809
|
+
const onDiskBytes = statSync23(filePath).size;
|
|
23666
23810
|
const headers = {
|
|
23667
23811
|
"Content-Type": "text/plain; charset=utf-8",
|
|
23668
23812
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -23726,8 +23870,8 @@ app18.get("/", async (c) => {
|
|
|
23726
23870
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
23727
23871
|
try {
|
|
23728
23872
|
const filename = basename13(hit.path);
|
|
23729
|
-
const buffer =
|
|
23730
|
-
const onDiskBytes =
|
|
23873
|
+
const buffer = readFileSync38(hit.path);
|
|
23874
|
+
const onDiskBytes = statSync23(hit.path).size;
|
|
23731
23875
|
const headers = {
|
|
23732
23876
|
"Content-Type": "text/plain; charset=utf-8",
|
|
23733
23877
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -23764,18 +23908,18 @@ app18.get("/", async (c) => {
|
|
|
23764
23908
|
if (!existsSync35(dir)) continue;
|
|
23765
23909
|
let files;
|
|
23766
23910
|
try {
|
|
23767
|
-
files =
|
|
23911
|
+
files = readdirSync23(dir).filter((f) => f.endsWith(".log"));
|
|
23768
23912
|
} catch (err) {
|
|
23769
23913
|
const reason = err instanceof Error ? err.message : String(err);
|
|
23770
23914
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
23771
23915
|
continue;
|
|
23772
23916
|
}
|
|
23773
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime:
|
|
23917
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync23(resolve26(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
23774
23918
|
seen.add(name);
|
|
23775
23919
|
try {
|
|
23776
|
-
const content =
|
|
23777
|
-
const
|
|
23778
|
-
logs[name] =
|
|
23920
|
+
const content = readFileSync38(resolve26(dir, name));
|
|
23921
|
+
const tail2 = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
23922
|
+
logs[name] = tail2.trim() || "(empty)";
|
|
23779
23923
|
} catch (err) {
|
|
23780
23924
|
const reason = err instanceof Error ? err.message : String(err);
|
|
23781
23925
|
console.debug(`[admin/logs] read-fail name=${name} reason=${reason}`);
|
|
@@ -23895,7 +24039,7 @@ var attachment_default = app20;
|
|
|
23895
24039
|
|
|
23896
24040
|
// server/routes/admin/session-upload.ts
|
|
23897
24041
|
import { readFile as readFile8 } from "fs/promises";
|
|
23898
|
-
import { existsSync as existsSync37, statSync as
|
|
24042
|
+
import { existsSync as existsSync37, statSync as statSync24 } from "fs";
|
|
23899
24043
|
var app21 = new Hono();
|
|
23900
24044
|
app21.get("/", requireAdminSession, async (c) => {
|
|
23901
24045
|
const cacheKey = c.var.cacheKey;
|
|
@@ -23916,7 +24060,7 @@ app21.get("/", requireAdminSession, async (c) => {
|
|
|
23916
24060
|
return c.json({ error: "Not found" }, 404);
|
|
23917
24061
|
}
|
|
23918
24062
|
const resolution = resolveClaudeUploadsPath(`${sessionId}/${file}`);
|
|
23919
|
-
if (!resolution.ok || !existsSync37(resolution.absolute) || !
|
|
24063
|
+
if (!resolution.ok || !existsSync37(resolution.absolute) || !statSync24(resolution.absolute).isFile()) {
|
|
23920
24064
|
console.log(`[session-upload] op=miss session=${short2} file=${file} status=404 reason=absent`);
|
|
23921
24065
|
return c.json({ error: "Not found" }, 404);
|
|
23922
24066
|
}
|
|
@@ -23938,13 +24082,13 @@ var session_upload_default = app21;
|
|
|
23938
24082
|
|
|
23939
24083
|
// server/routes/admin/agents.ts
|
|
23940
24084
|
import { resolve as resolve28 } from "path";
|
|
23941
|
-
import { readdirSync as
|
|
24085
|
+
import { readdirSync as readdirSync25, readFileSync as readFileSync40, existsSync as existsSync39, rmSync as rmSync5, renameSync as renameSync9, mkdirSync as mkdirSync10, writeFileSync as writeFileSync18, chmodSync } from "fs";
|
|
23942
24086
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
23943
24087
|
|
|
23944
24088
|
// ../services/claude-session-manager/src/tool-surface.ts
|
|
23945
|
-
import { readFileSync as
|
|
24089
|
+
import { readFileSync as readFileSync39, readdirSync as readdirSync24, statSync as statSync25, existsSync as existsSync38 } from "fs";
|
|
23946
24090
|
import { createHash as createHash5 } from "crypto";
|
|
23947
|
-
import { join as
|
|
24091
|
+
import { join as join49 } from "path";
|
|
23948
24092
|
|
|
23949
24093
|
// ../services/claude-session-manager/src/canonical-tool-names.ts
|
|
23950
24094
|
function canonicalToolName(plugin, tool) {
|
|
@@ -24197,15 +24341,15 @@ function loadToolSurface(pluginsRoots) {
|
|
|
24197
24341
|
const riskByTool = /* @__PURE__ */ new Map();
|
|
24198
24342
|
const manifestPaths = /* @__PURE__ */ new Map();
|
|
24199
24343
|
const loadOne = (pluginsRoot, plugin) => {
|
|
24200
|
-
const pluginDir =
|
|
24344
|
+
const pluginDir = join49(pluginsRoot, plugin);
|
|
24201
24345
|
try {
|
|
24202
|
-
if (!
|
|
24346
|
+
if (!statSync25(pluginDir).isDirectory()) return;
|
|
24203
24347
|
} catch {
|
|
24204
24348
|
return;
|
|
24205
24349
|
}
|
|
24206
|
-
const manifestPath =
|
|
24350
|
+
const manifestPath = join49(pluginDir, "PLUGIN.md");
|
|
24207
24351
|
if (!existsSync38(manifestPath)) return;
|
|
24208
|
-
const raw =
|
|
24352
|
+
const raw = readFileSync39(manifestPath, "utf-8");
|
|
24209
24353
|
const frontmatter = extractFrontmatter(raw, plugin);
|
|
24210
24354
|
const tools = parseToolsBlock(frontmatter, plugin);
|
|
24211
24355
|
if (tools.length === 0) return;
|
|
@@ -24224,7 +24368,7 @@ function loadToolSurface(pluginsRoots) {
|
|
|
24224
24368
|
`${plugin}: mcpServers has entry but manifestPaths is missing \u2014 invariant violated, both maps must be written together`
|
|
24225
24369
|
);
|
|
24226
24370
|
}
|
|
24227
|
-
const priorSha = createHash5("sha256").update(
|
|
24371
|
+
const priorSha = createHash5("sha256").update(readFileSync39(priorPath)).digest("hex").slice(0, 8);
|
|
24228
24372
|
const newSha = createHash5("sha256").update(raw).digest("hex").slice(0, 8);
|
|
24229
24373
|
throw new ToolSurfaceError(
|
|
24230
24374
|
"mcp-plugin-duplicate",
|
|
@@ -24247,15 +24391,15 @@ function loadToolSurface(pluginsRoots) {
|
|
|
24247
24391
|
}
|
|
24248
24392
|
};
|
|
24249
24393
|
for (const root of roots) {
|
|
24250
|
-
const entries2 =
|
|
24394
|
+
const entries2 = readdirSync24(root).sort();
|
|
24251
24395
|
for (const plugin of entries2) {
|
|
24252
|
-
const pluginDir =
|
|
24396
|
+
const pluginDir = join49(root, plugin);
|
|
24253
24397
|
loadOne(root, plugin);
|
|
24254
|
-
const subRoot =
|
|
24398
|
+
const subRoot = join49(pluginDir, "plugins");
|
|
24255
24399
|
let subEntries;
|
|
24256
24400
|
try {
|
|
24257
|
-
if (!
|
|
24258
|
-
subEntries =
|
|
24401
|
+
if (!statSync25(subRoot).isDirectory()) continue;
|
|
24402
|
+
subEntries = readdirSync24(subRoot).sort();
|
|
24259
24403
|
} catch {
|
|
24260
24404
|
continue;
|
|
24261
24405
|
}
|
|
@@ -24387,7 +24531,7 @@ var SLUG_UNSAFE = (s) => s.includes("/") || s.includes("..") || s.includes("\\")
|
|
|
24387
24531
|
function subdirs(dir) {
|
|
24388
24532
|
if (!existsSync39(dir)) return [];
|
|
24389
24533
|
try {
|
|
24390
|
-
return
|
|
24534
|
+
return readdirSync25(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
24391
24535
|
} catch {
|
|
24392
24536
|
return [];
|
|
24393
24537
|
}
|
|
@@ -24419,7 +24563,7 @@ function loadRiskSurface() {
|
|
|
24419
24563
|
function readDisabledStoreStrict(accountDir) {
|
|
24420
24564
|
const p = resolve28(accountDir, DISABLED_STORE);
|
|
24421
24565
|
if (!existsSync39(p)) return /* @__PURE__ */ new Set();
|
|
24422
|
-
const parsed = JSON.parse(
|
|
24566
|
+
const parsed = JSON.parse(readFileSync40(p, "utf-8"));
|
|
24423
24567
|
if (!Array.isArray(parsed.disabled)) throw new Error("disabled is not an array");
|
|
24424
24568
|
return new Set(parsed.disabled.filter((x) => typeof x === "string"));
|
|
24425
24569
|
}
|
|
@@ -24439,7 +24583,7 @@ function authoredAgentFiles(accountDir) {
|
|
|
24439
24583
|
const dir = resolve28(pluginsDir, plugin, "agents");
|
|
24440
24584
|
if (!existsSync39(dir)) continue;
|
|
24441
24585
|
try {
|
|
24442
|
-
for (const entry3 of
|
|
24586
|
+
for (const entry3 of readdirSync25(dir)) {
|
|
24443
24587
|
if (!entry3.endsWith(".md")) continue;
|
|
24444
24588
|
const path = resolve28(dir, entry3);
|
|
24445
24589
|
const paths = byName.get(entry3);
|
|
@@ -24460,7 +24604,7 @@ function shippedSourceDirs(accountDir) {
|
|
|
24460
24604
|
];
|
|
24461
24605
|
}
|
|
24462
24606
|
function readRowFields(path) {
|
|
24463
|
-
const { fm } = splitFrontmatter(
|
|
24607
|
+
const { fm } = splitFrontmatter(readFileSync40(path, "utf-8"));
|
|
24464
24608
|
return {
|
|
24465
24609
|
name: fm.name ?? "",
|
|
24466
24610
|
description: fm.description ?? "",
|
|
@@ -24493,9 +24637,9 @@ function compareToAuthored(candidatePath, authoredPaths, filename) {
|
|
|
24493
24637
|
anyUnreadable = true;
|
|
24494
24638
|
continue;
|
|
24495
24639
|
}
|
|
24496
|
-
const
|
|
24497
|
-
if (
|
|
24498
|
-
firstDivergence ??= { authoredPath: path, fields };
|
|
24640
|
+
const fields2 = divergentFields(candidate, authored);
|
|
24641
|
+
if (fields2.length === 0) return { verdict: "matched" };
|
|
24642
|
+
firstDivergence ??= { authoredPath: path, fields: fields2 };
|
|
24499
24643
|
}
|
|
24500
24644
|
if (firstDivergence) return { verdict: "divergent", ...firstDivergence };
|
|
24501
24645
|
if (anyUnreadable) return { verdict: "unreadable" };
|
|
@@ -24513,7 +24657,7 @@ function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed, author
|
|
|
24513
24657
|
for (const dir of dirs) {
|
|
24514
24658
|
if (!existsSync39(dir)) continue;
|
|
24515
24659
|
try {
|
|
24516
|
-
for (const entry3 of
|
|
24660
|
+
for (const entry3 of readdirSync25(dir)) if (entry3.endsWith(".md")) names.add(entry3);
|
|
24517
24661
|
} catch (err) {
|
|
24518
24662
|
console.error(`[admin/agents] op=list-shipped read-failed dir=${dir} error="${err}"`);
|
|
24519
24663
|
}
|
|
@@ -24541,7 +24685,7 @@ function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed, author
|
|
|
24541
24685
|
}
|
|
24542
24686
|
}
|
|
24543
24687
|
try {
|
|
24544
|
-
const { fm } = splitFrontmatter(
|
|
24688
|
+
const { fm } = splitFrontmatter(readFileSync40(resolve28(source, filename), "utf-8"));
|
|
24545
24689
|
if (!fm.name) {
|
|
24546
24690
|
shippedSkipped++;
|
|
24547
24691
|
console.error(`[admin/agents] op=list-shipped-skip file=${filename} reason=no-name`);
|
|
@@ -24603,14 +24747,14 @@ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
|
|
|
24603
24747
|
if (!existsSync39(agentsDirP)) continue;
|
|
24604
24748
|
let entries2;
|
|
24605
24749
|
try {
|
|
24606
|
-
entries2 =
|
|
24750
|
+
entries2 = readdirSync25(agentsDirP, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
24607
24751
|
} catch {
|
|
24608
24752
|
continue;
|
|
24609
24753
|
}
|
|
24610
24754
|
for (const entry3 of entries2) {
|
|
24611
24755
|
if (!entry3.isFile() || !entry3.name.endsWith(".md")) continue;
|
|
24612
24756
|
try {
|
|
24613
|
-
const { fm } = splitFrontmatter(
|
|
24757
|
+
const { fm } = splitFrontmatter(readFileSync40(resolve28(agentsDirP, entry3.name), "utf-8"));
|
|
24614
24758
|
if (!fm.name) {
|
|
24615
24759
|
specialistsSkipped++;
|
|
24616
24760
|
console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry3.name}`);
|
|
@@ -24672,14 +24816,14 @@ app22.get("/", requireAdminSession, (c) => {
|
|
|
24672
24816
|
const agentsDir = resolve28(account.accountDir, "agents");
|
|
24673
24817
|
if (existsSync39(agentsDir)) {
|
|
24674
24818
|
try {
|
|
24675
|
-
const entries2 =
|
|
24819
|
+
const entries2 = readdirSync25(agentsDir, { withFileTypes: true });
|
|
24676
24820
|
for (const entry3 of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
24677
24821
|
if (!entry3.isDirectory()) continue;
|
|
24678
24822
|
if (entry3.name === "admin") continue;
|
|
24679
24823
|
const configPath3 = resolve28(agentsDir, entry3.name, "config.json");
|
|
24680
24824
|
if (!existsSync39(configPath3)) continue;
|
|
24681
24825
|
try {
|
|
24682
|
-
const config = JSON.parse(
|
|
24826
|
+
const config = JSON.parse(readFileSync40(configPath3, "utf-8"));
|
|
24683
24827
|
agents.push({
|
|
24684
24828
|
slug: entry3.name,
|
|
24685
24829
|
displayName: config.displayName ?? entry3.name,
|
|
@@ -24761,7 +24905,7 @@ app22.get("/:slug", requireAdminSession, (c) => {
|
|
|
24761
24905
|
const dirs = shippedSourceDirs(account.accountDir);
|
|
24762
24906
|
const source = dirs.find((d) => existsSync39(resolve28(d, `${slug}.md`)));
|
|
24763
24907
|
if (!source) return c.json({ error: "Agent not found" }, 404);
|
|
24764
|
-
const { fm, body } = splitFrontmatter(
|
|
24908
|
+
const { fm, body } = splitFrontmatter(readFileSync40(resolve28(source, `${slug}.md`), "utf-8"));
|
|
24765
24909
|
const { riskByTool, failed: failed2 } = loadRiskSurface();
|
|
24766
24910
|
const tools = parseToolsLine(fm.tools);
|
|
24767
24911
|
const r = classify(tools, riskByTool, failed2 !== null);
|
|
@@ -24793,7 +24937,7 @@ app22.get("/:slug", requireAdminSession, (c) => {
|
|
|
24793
24937
|
if (SLUG_UNSAFE(pluginParam)) return c.json({ error: "Invalid plugin" }, 400);
|
|
24794
24938
|
const file = resolve28(account.accountDir, "plugins", pluginParam, "agents", `${slug}.md`);
|
|
24795
24939
|
if (!existsSync39(file)) return c.json({ error: "Agent not found" }, 404);
|
|
24796
|
-
const { fm, body } = splitFrontmatter(
|
|
24940
|
+
const { fm, body } = splitFrontmatter(readFileSync40(file, "utf-8"));
|
|
24797
24941
|
const skills = subdirs(resolve28(account.accountDir, "plugins", pluginParam, "skills"));
|
|
24798
24942
|
const { riskByTool, failed: failed2 } = loadRiskSurface();
|
|
24799
24943
|
const tools = parseToolsLine(fm.tools);
|
|
@@ -24826,7 +24970,7 @@ app22.get("/:slug", requireAdminSession, (c) => {
|
|
|
24826
24970
|
if (!existsSync39(configPath3)) return c.json({ error: "Agent not found" }, 404);
|
|
24827
24971
|
let config;
|
|
24828
24972
|
try {
|
|
24829
|
-
config = JSON.parse(
|
|
24973
|
+
config = JSON.parse(readFileSync40(configPath3, "utf-8"));
|
|
24830
24974
|
} catch {
|
|
24831
24975
|
console.error(`[admin/agents] op=detail slug=${slug} error="config.json parse failed"`);
|
|
24832
24976
|
return c.json({ error: "Agent config unreadable" }, 500);
|
|
@@ -24837,7 +24981,7 @@ app22.get("/:slug", requireAdminSession, (c) => {
|
|
|
24837
24981
|
const p = resolve28(agentDir, file);
|
|
24838
24982
|
try {
|
|
24839
24983
|
if (existsSync39(p)) {
|
|
24840
|
-
docs[key2] =
|
|
24984
|
+
docs[key2] = readFileSync40(p, "utf-8");
|
|
24841
24985
|
present[key2] = true;
|
|
24842
24986
|
} else {
|
|
24843
24987
|
docs[key2] = "";
|
|
@@ -24899,9 +25043,9 @@ function reconcileAuthoredRoutingLine(accountDir, accountId, op, source) {
|
|
|
24899
25043
|
const agentsMd = resolve28(accountDir, "agents", "admin", "AGENTS.md");
|
|
24900
25044
|
if (!existsSync39(agentsMd) || !existsSync39(source)) return false;
|
|
24901
25045
|
try {
|
|
24902
|
-
const { fm } = splitFrontmatter(
|
|
25046
|
+
const { fm } = splitFrontmatter(readFileSync40(source, "utf-8"));
|
|
24903
25047
|
if (!fm.name) return false;
|
|
24904
|
-
const lines =
|
|
25048
|
+
const lines = readFileSync40(agentsMd, "utf-8").split("\n");
|
|
24905
25049
|
const prefix = `- **specialists:${fm.name}**:`;
|
|
24906
25050
|
const without = lines.filter((l) => !l.startsWith(prefix));
|
|
24907
25051
|
const next = op === "disable" ? without : [...without, `${prefix} ${fm.description ?? ""}`.trimEnd()];
|
|
@@ -25479,21 +25623,21 @@ app23.post("/:id/resume", async (c) => {
|
|
|
25479
25623
|
if (bridge.reason === "conversation-not-found") {
|
|
25480
25624
|
return c.json({ error: "Conversation not found" }, 404);
|
|
25481
25625
|
}
|
|
25482
|
-
const
|
|
25483
|
-
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="cookie-bridge-rejected:${bridge.reason}" path=${c.req.path} cacheKey=${
|
|
25626
|
+
const tail2 = cacheKey.slice(0, 8);
|
|
25627
|
+
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="cookie-bridge-rejected:${bridge.reason}" path=${c.req.path} cacheKey=${tail2}\u2026`);
|
|
25484
25628
|
return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
|
|
25485
25629
|
}
|
|
25486
25630
|
bridged = true;
|
|
25487
25631
|
result = validateSession(cacheKey, "admin", signedSessionToken);
|
|
25488
25632
|
if (!result.ok) {
|
|
25489
|
-
const
|
|
25490
|
-
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="post-bridge re-validate failed" path=${c.req.path} cacheKey=${
|
|
25633
|
+
const tail2 = cacheKey.slice(0, 8);
|
|
25634
|
+
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="post-bridge re-validate failed" path=${c.req.path} cacheKey=${tail2}\u2026`);
|
|
25491
25635
|
return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
|
|
25492
25636
|
}
|
|
25493
25637
|
} else {
|
|
25494
|
-
const
|
|
25638
|
+
const tail2 = cacheKey.slice(0, 8);
|
|
25495
25639
|
const wireCode = result.reason === "agent-type-mismatch" ? "session-not-registered" : result.reason;
|
|
25496
|
-
console.error(`[session] middleware-reject status=401 code=${wireCode} reason="invalid or expired admin session" path=${c.req.path} cacheKey=${
|
|
25640
|
+
console.error(`[session] middleware-reject status=401 code=${wireCode} reason="invalid or expired admin session" path=${c.req.path} cacheKey=${tail2}\u2026`);
|
|
25497
25641
|
return c.json({ error: "Invalid or expired admin session", code: wireCode }, 401);
|
|
25498
25642
|
}
|
|
25499
25643
|
}
|
|
@@ -25759,8 +25903,8 @@ app23.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
25759
25903
|
var sessions_default = app23;
|
|
25760
25904
|
|
|
25761
25905
|
// app/lib/claude-agent/spawn-context.ts
|
|
25762
|
-
import { existsSync as existsSync41, readFileSync as
|
|
25763
|
-
import { dirname as dirname15, resolve as resolve29, join as
|
|
25906
|
+
import { existsSync as existsSync41, readFileSync as readFileSync41, readdirSync as readdirSync26, statSync as statSync26 } from "fs";
|
|
25907
|
+
import { dirname as dirname15, resolve as resolve29, join as join50 } from "path";
|
|
25764
25908
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
25765
25909
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
25766
25910
|
try {
|
|
@@ -25801,14 +25945,14 @@ function frontmatterField(manifest, field2) {
|
|
|
25801
25945
|
function extractPluginToolDescriptions(pluginDir) {
|
|
25802
25946
|
const out = /* @__PURE__ */ new Map();
|
|
25803
25947
|
const candidates = [
|
|
25804
|
-
|
|
25805
|
-
|
|
25948
|
+
join50(pluginDir, "mcp/dist/index.js"),
|
|
25949
|
+
join50(pluginDir, "mcp/src/index.ts")
|
|
25806
25950
|
];
|
|
25807
25951
|
let raw = null;
|
|
25808
25952
|
for (const path of candidates) {
|
|
25809
25953
|
if (!existsSync41(path)) continue;
|
|
25810
25954
|
try {
|
|
25811
|
-
raw =
|
|
25955
|
+
raw = readFileSync41(path, "utf-8");
|
|
25812
25956
|
break;
|
|
25813
25957
|
} catch {
|
|
25814
25958
|
}
|
|
@@ -25859,24 +26003,24 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
25859
26003
|
const out = /* @__PURE__ */ new Map();
|
|
25860
26004
|
const platformPlugins = resolve29(PLATFORM_ROOT, "plugins");
|
|
25861
26005
|
if (existsSync41(platformPlugins)) {
|
|
25862
|
-
for (const name of
|
|
25863
|
-
const dir =
|
|
26006
|
+
for (const name of readdirSync26(platformPlugins)) {
|
|
26007
|
+
const dir = join50(platformPlugins, name);
|
|
25864
26008
|
try {
|
|
25865
|
-
if (
|
|
26009
|
+
if (statSync26(dir).isDirectory()) out.set(name, dir);
|
|
25866
26010
|
} catch {
|
|
25867
26011
|
}
|
|
25868
26012
|
}
|
|
25869
26013
|
}
|
|
25870
26014
|
const premiumRoot = resolve29(dirname15(PLATFORM_ROOT), "premium-plugins");
|
|
25871
26015
|
if (existsSync41(premiumRoot)) {
|
|
25872
|
-
for (const bundle of
|
|
25873
|
-
const bundlePlugins =
|
|
26016
|
+
for (const bundle of readdirSync26(premiumRoot)) {
|
|
26017
|
+
const bundlePlugins = join50(premiumRoot, bundle, "plugins");
|
|
25874
26018
|
if (!existsSync41(bundlePlugins)) continue;
|
|
25875
26019
|
try {
|
|
25876
|
-
for (const name of
|
|
25877
|
-
const dir =
|
|
26020
|
+
for (const name of readdirSync26(bundlePlugins)) {
|
|
26021
|
+
const dir = join50(bundlePlugins, name);
|
|
25878
26022
|
try {
|
|
25879
|
-
if (
|
|
26023
|
+
if (statSync26(dir).isDirectory()) out.set(name, dir);
|
|
25880
26024
|
} catch {
|
|
25881
26025
|
}
|
|
25882
26026
|
}
|
|
@@ -25886,11 +26030,11 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
25886
26030
|
}
|
|
25887
26031
|
if (accountPluginsDir && existsSync41(accountPluginsDir)) {
|
|
25888
26032
|
try {
|
|
25889
|
-
for (const name of
|
|
26033
|
+
for (const name of readdirSync26(accountPluginsDir)) {
|
|
25890
26034
|
if (out.has(name)) continue;
|
|
25891
|
-
const dir =
|
|
26035
|
+
const dir = join50(accountPluginsDir, name);
|
|
25892
26036
|
try {
|
|
25893
|
-
if (
|
|
26037
|
+
if (statSync26(dir).isDirectory()) out.set(name, dir);
|
|
25894
26038
|
} catch {
|
|
25895
26039
|
}
|
|
25896
26040
|
}
|
|
@@ -25905,9 +26049,9 @@ function accountPluginsDirFor(accountId) {
|
|
|
25905
26049
|
function listAccountPluginNames(accountPluginsDir) {
|
|
25906
26050
|
if (!existsSync41(accountPluginsDir)) return [];
|
|
25907
26051
|
try {
|
|
25908
|
-
return
|
|
26052
|
+
return readdirSync26(accountPluginsDir).filter((name) => {
|
|
25909
26053
|
try {
|
|
25910
|
-
return
|
|
26054
|
+
return statSync26(join50(accountPluginsDir, name)).isDirectory();
|
|
25911
26055
|
} catch {
|
|
25912
26056
|
return false;
|
|
25913
26057
|
}
|
|
@@ -25920,7 +26064,7 @@ function readEnabledPlugins(accountId) {
|
|
|
25920
26064
|
const accountFile = resolve29(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
25921
26065
|
if (!existsSync41(accountFile)) return /* @__PURE__ */ new Set();
|
|
25922
26066
|
try {
|
|
25923
|
-
const parsed = JSON.parse(
|
|
26067
|
+
const parsed = JSON.parse(readFileSync41(accountFile, "utf-8"));
|
|
25924
26068
|
return new Set(
|
|
25925
26069
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
25926
26070
|
);
|
|
@@ -25932,7 +26076,7 @@ function readFrontmatter(path) {
|
|
|
25932
26076
|
if (!existsSync41(path)) return null;
|
|
25933
26077
|
let raw;
|
|
25934
26078
|
try {
|
|
25935
|
-
raw =
|
|
26079
|
+
raw = readFileSync41(path, "utf-8");
|
|
25936
26080
|
} catch {
|
|
25937
26081
|
return null;
|
|
25938
26082
|
}
|
|
@@ -25950,7 +26094,7 @@ function computeActivePlugins(accountId) {
|
|
|
25950
26094
|
for (const name of emitNames) {
|
|
25951
26095
|
const dir = pluginDirs.get(name);
|
|
25952
26096
|
if (!dir) continue;
|
|
25953
|
-
const fm = readFrontmatter(
|
|
26097
|
+
const fm = readFrontmatter(join50(dir, "PLUGIN.md"));
|
|
25954
26098
|
if (!fm) continue;
|
|
25955
26099
|
const description = frontmatterField(`---
|
|
25956
26100
|
${fm}
|
|
@@ -25967,7 +26111,7 @@ ${fm}
|
|
|
25967
26111
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
25968
26112
|
);
|
|
25969
26113
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
25970
|
-
const hasSource = existsSync41(
|
|
26114
|
+
const hasSource = existsSync41(join50(dir, "mcp/dist/index.js")) || existsSync41(join50(dir, "mcp/src/index.ts"));
|
|
25971
26115
|
if (hasSource) {
|
|
25972
26116
|
console.warn(
|
|
25973
26117
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -25977,7 +26121,7 @@ ${fm}
|
|
|
25977
26121
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
25978
26122
|
const skills = [];
|
|
25979
26123
|
for (const relPath of skillPaths) {
|
|
25980
|
-
const skillPath =
|
|
26124
|
+
const skillPath = join50(dir, relPath);
|
|
25981
26125
|
const skillFm = readFrontmatter(skillPath);
|
|
25982
26126
|
if (!skillFm) continue;
|
|
25983
26127
|
const skillName = frontmatterField(`---
|
|
@@ -25997,7 +26141,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
25997
26141
|
if (!existsSync41(specialistsDir)) return [];
|
|
25998
26142
|
let entries2;
|
|
25999
26143
|
try {
|
|
26000
|
-
entries2 =
|
|
26144
|
+
entries2 = readdirSync26(specialistsDir);
|
|
26001
26145
|
} catch {
|
|
26002
26146
|
return [];
|
|
26003
26147
|
}
|
|
@@ -26021,7 +26165,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
26021
26165
|
const out = [];
|
|
26022
26166
|
for (const file of entries2.sort()) {
|
|
26023
26167
|
if (!file.endsWith(".md")) continue;
|
|
26024
|
-
const fm = readFrontmatter(
|
|
26168
|
+
const fm = readFrontmatter(join50(specialistsDir, file));
|
|
26025
26169
|
if (!fm) continue;
|
|
26026
26170
|
const wrapped = `---
|
|
26027
26171
|
${fm}
|
|
@@ -26043,7 +26187,7 @@ function computeDormantPlugins(accountId) {
|
|
|
26043
26187
|
if (!existsSync41(accountFile)) return [];
|
|
26044
26188
|
let enabled;
|
|
26045
26189
|
try {
|
|
26046
|
-
const raw =
|
|
26190
|
+
const raw = readFileSync41(accountFile, "utf-8");
|
|
26047
26191
|
const parsed = JSON.parse(raw);
|
|
26048
26192
|
enabled = new Set(
|
|
26049
26193
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -26058,7 +26202,7 @@ function computeDormantPlugins(accountId) {
|
|
|
26058
26202
|
if (!existsSync41(pluginsDir)) return [];
|
|
26059
26203
|
let entries2;
|
|
26060
26204
|
try {
|
|
26061
|
-
entries2 =
|
|
26205
|
+
entries2 = readdirSync26(pluginsDir);
|
|
26062
26206
|
} catch {
|
|
26063
26207
|
return [];
|
|
26064
26208
|
}
|
|
@@ -26069,7 +26213,7 @@ function computeDormantPlugins(accountId) {
|
|
|
26069
26213
|
if (!existsSync41(manifestPath)) continue;
|
|
26070
26214
|
let manifest;
|
|
26071
26215
|
try {
|
|
26072
|
-
manifest =
|
|
26216
|
+
manifest = readFileSync41(manifestPath, "utf-8");
|
|
26073
26217
|
} catch {
|
|
26074
26218
|
continue;
|
|
26075
26219
|
}
|
|
@@ -26083,13 +26227,13 @@ function computeDormantPlugins(accountId) {
|
|
|
26083
26227
|
}
|
|
26084
26228
|
|
|
26085
26229
|
// server/routes/admin/claude-sessions.ts
|
|
26086
|
-
import { existsSync as existsSync42, readFileSync as
|
|
26230
|
+
import { existsSync as existsSync42, readFileSync as readFileSync42 } from "fs";
|
|
26087
26231
|
import { resolve as resolve30 } from "path";
|
|
26088
26232
|
function readTunnelState(brandConfigDir) {
|
|
26089
26233
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
26090
26234
|
if (!existsSync42(statePath)) return null;
|
|
26091
26235
|
try {
|
|
26092
|
-
const parsed = JSON.parse(
|
|
26236
|
+
const parsed = JSON.parse(readFileSync42(statePath, "utf-8"));
|
|
26093
26237
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
26094
26238
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
26095
26239
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -26103,7 +26247,7 @@ function resolveTunnelUrl() {
|
|
|
26103
26247
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve30(process.cwd(), "..");
|
|
26104
26248
|
let brand;
|
|
26105
26249
|
try {
|
|
26106
|
-
brand = JSON.parse(
|
|
26250
|
+
brand = JSON.parse(readFileSync42(resolve30(platformRoot5, "config", "brand.json"), "utf-8"));
|
|
26107
26251
|
} catch {
|
|
26108
26252
|
return null;
|
|
26109
26253
|
}
|
|
@@ -26304,7 +26448,7 @@ app25.post("/", async (c) => {
|
|
|
26304
26448
|
var log_ingest_default = app25;
|
|
26305
26449
|
|
|
26306
26450
|
// server/routes/admin/session-blocked.ts
|
|
26307
|
-
import { join as
|
|
26451
|
+
import { join as join51 } from "path";
|
|
26308
26452
|
var TAG44 = "[blocked-tool-notify]";
|
|
26309
26453
|
function isLoopbackAddr4(addr) {
|
|
26310
26454
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
@@ -26351,7 +26495,7 @@ app26.post("/", async (c) => {
|
|
|
26351
26495
|
if (!tool) return c.json({ error: "tool-required" }, 400);
|
|
26352
26496
|
const text = blockedNotificationText({ sessionId, agentId, tool, blockedForMs });
|
|
26353
26497
|
const projectDir = findSessionProjectDir(sessionId);
|
|
26354
|
-
const meta = projectDir ? readSidecarMeta(
|
|
26498
|
+
const meta = projectDir ? readSidecarMeta(join51(projectDir, `${sessionId}.meta.json`)) : { role: null, channel: null, senderId: null, accountId: null };
|
|
26355
26499
|
const account = validateAccountId2(meta.accountId ?? "");
|
|
26356
26500
|
if (!account) {
|
|
26357
26501
|
console.error(
|
|
@@ -26550,7 +26694,7 @@ import { createReadStream as createReadStream2, createWriteStream as createWrite
|
|
|
26550
26694
|
import { readdir as readdir4, readFile as readFile10, stat as stat6, mkdir as mkdir2, unlink as unlink3, rename as rename3, rmdir } from "fs/promises";
|
|
26551
26695
|
import { realpathSync as realpathSync7 } from "fs";
|
|
26552
26696
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
26553
|
-
import { basename as basename15, dirname as dirname16, join as
|
|
26697
|
+
import { basename as basename15, dirname as dirname16, join as join53, relative as relative6, resolve as resolve32, sep as sep9 } from "path";
|
|
26554
26698
|
import { Readable as Readable2 } from "stream";
|
|
26555
26699
|
|
|
26556
26700
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -26868,7 +27012,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
26868
27012
|
|
|
26869
27013
|
// app/lib/file-index.ts
|
|
26870
27014
|
import * as fsp from "fs/promises";
|
|
26871
|
-
import { resolve as resolve31, relative as relative5, join as
|
|
27015
|
+
import { resolve as resolve31, relative as relative5, join as join52, basename as basename14, extname, sep as sep8 } from "path";
|
|
26872
27016
|
import { tmpdir as tmpdir3 } from "os";
|
|
26873
27017
|
import { execFile } from "child_process";
|
|
26874
27018
|
import { promisify } from "util";
|
|
@@ -26950,7 +27094,7 @@ async function extractPdf(absolute) {
|
|
|
26950
27094
|
return stdout.trim();
|
|
26951
27095
|
}
|
|
26952
27096
|
async function ocrPdf(absolute) {
|
|
26953
|
-
const outPdf =
|
|
27097
|
+
const outPdf = join52(tmpdir3(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
26954
27098
|
try {
|
|
26955
27099
|
await execFileAsync(
|
|
26956
27100
|
"ocrmypdf",
|
|
@@ -27012,7 +27156,7 @@ async function readDisplayName(absolute) {
|
|
|
27012
27156
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
27013
27157
|
if (base === `${stem}.meta.json`) return null;
|
|
27014
27158
|
try {
|
|
27015
|
-
const raw = await fsp.readFile(
|
|
27159
|
+
const raw = await fsp.readFile(join52(dir, `${stem}.meta.json`), "utf-8");
|
|
27016
27160
|
const meta = JSON.parse(raw);
|
|
27017
27161
|
const dn = meta.displayName ?? meta.filename;
|
|
27018
27162
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -27033,7 +27177,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
27033
27177
|
for (const entry3 of entries2) {
|
|
27034
27178
|
if (entry3.isSymbolicLink()) continue;
|
|
27035
27179
|
if (entry3.isDirectory() && entry3.name === ".uploads-tmp") continue;
|
|
27036
|
-
const abs =
|
|
27180
|
+
const abs = join52(root, entry3.name);
|
|
27037
27181
|
if (entry3.isDirectory()) {
|
|
27038
27182
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
27039
27183
|
if (!sub.clean) clean = false;
|
|
@@ -27406,7 +27550,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
|
27406
27550
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
27407
27551
|
async function readMeta2(absDir, baseName) {
|
|
27408
27552
|
try {
|
|
27409
|
-
const raw = await readFile10(
|
|
27553
|
+
const raw = await readFile10(join53(absDir, `${baseName}.meta.json`), "utf8");
|
|
27410
27554
|
const parsed = JSON.parse(raw);
|
|
27411
27555
|
if (typeof parsed?.filename === "string") {
|
|
27412
27556
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -27461,7 +27605,7 @@ async function servableFilesIn(dirAbs, uuid) {
|
|
|
27461
27605
|
}
|
|
27462
27606
|
async function enrich(absolute, entry3, accountNames) {
|
|
27463
27607
|
if (entry3.kind === "directory" && UUID_RE3.test(entry3.name)) {
|
|
27464
|
-
const dirAbs =
|
|
27608
|
+
const dirAbs = join53(absolute, entry3.name);
|
|
27465
27609
|
const meta = await readMeta2(dirAbs, entry3.name);
|
|
27466
27610
|
if (meta?.filename) {
|
|
27467
27611
|
const servable = await servableFilesIn(dirAbs, entry3.name);
|
|
@@ -27470,7 +27614,7 @@ async function enrich(absolute, entry3, accountNames) {
|
|
|
27470
27614
|
let size = null;
|
|
27471
27615
|
let modifiedAt = entry3.modifiedAt;
|
|
27472
27616
|
try {
|
|
27473
|
-
const st = await stat6(
|
|
27617
|
+
const st = await stat6(join53(dirAbs, innerName));
|
|
27474
27618
|
size = st.size;
|
|
27475
27619
|
modifiedAt = st.mtime.toISOString();
|
|
27476
27620
|
} catch {
|
|
@@ -27682,7 +27826,7 @@ app28.get("/", requireAdminSession, async (c) => {
|
|
|
27682
27826
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
27683
27827
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
27684
27828
|
try {
|
|
27685
|
-
const entryPath =
|
|
27829
|
+
const entryPath = join53(absolute, name);
|
|
27686
27830
|
const s = await stat6(entryPath);
|
|
27687
27831
|
entries2.push({
|
|
27688
27832
|
name,
|
|
@@ -27711,7 +27855,7 @@ app28.get("/", requireAdminSession, async (c) => {
|
|
|
27711
27855
|
const displayPath = buildDisplayPath(relPath, accountNames);
|
|
27712
27856
|
if (groupReq || isAccountRoot(relPath)) {
|
|
27713
27857
|
const acctId = relPath.split("/")[1] ?? accountId;
|
|
27714
|
-
const schemaMd = await readFile10(
|
|
27858
|
+
const schemaMd = await readFile10(join53(absolute, "SCHEMA.md"), "utf8").catch(() => null);
|
|
27715
27859
|
const groups = classifyAccountRoot(schemaMd, entries2.map((e) => e.name));
|
|
27716
27860
|
console.error(
|
|
27717
27861
|
`[data-schema] op=classify account=${acctId} status=${groups.parsed ? "ok" : "parse-failed"} reason=${groups.reason} entries=${entries2.length} home=${groups.home.join(",") || "none"} system=${groups.system.length} unknown=${groups.unknown.join(",") || "none"}`
|
|
@@ -27749,7 +27893,7 @@ app28.get("/", requireAdminSession, async (c) => {
|
|
|
27749
27893
|
for (const name of homeDirs) {
|
|
27750
27894
|
const base = byName.get(name);
|
|
27751
27895
|
try {
|
|
27752
|
-
const dirents = await readdir4(
|
|
27896
|
+
const dirents = await readdir4(join53(absolute, name), { withFileTypes: true });
|
|
27753
27897
|
const visible = dirents.filter((d) => !d.name.startsWith("."));
|
|
27754
27898
|
visible.sort((a, b) => {
|
|
27755
27899
|
const ad = a.isDirectory() ? 0 : 1;
|
|
@@ -27814,7 +27958,7 @@ app28.get("/download", requireAdminSession, async (c) => {
|
|
|
27814
27958
|
console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
|
|
27815
27959
|
return c.json({ error: "Not found" }, 404);
|
|
27816
27960
|
}
|
|
27817
|
-
const meta = readSidecarMeta(
|
|
27961
|
+
const meta = readSidecarMeta(join53(projectDir, `${sessionId}.meta.json`));
|
|
27818
27962
|
if (!meta.accountId || meta.accountId !== accountId) {
|
|
27819
27963
|
console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
27820
27964
|
return c.json({ error: "Not found" }, 404);
|
|
@@ -27908,7 +28052,7 @@ async function* walkRegularFiles(dirAbsolute) {
|
|
|
27908
28052
|
const dirents = await readdir4(dirAbsolute, { withFileTypes: true });
|
|
27909
28053
|
for (const d of dirents) {
|
|
27910
28054
|
if (d.isSymbolicLink()) continue;
|
|
27911
|
-
const child =
|
|
28055
|
+
const child = join53(dirAbsolute, d.name);
|
|
27912
28056
|
if (d.isDirectory()) {
|
|
27913
28057
|
yield* walkRegularFiles(child);
|
|
27914
28058
|
continue;
|
|
@@ -28014,7 +28158,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
28014
28158
|
const base = resolveSharedOrOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
28015
28159
|
if (!base.ok) return { ok: false, status: base.status, error: base.error };
|
|
28016
28160
|
const relDir = relpath ? dirname16(relpath) : ".";
|
|
28017
|
-
const destRel = relDir === "." ? base.relative :
|
|
28161
|
+
const destRel = relDir === "." ? base.relative : join53(base.relative, relDir);
|
|
28018
28162
|
if ((0, import_dist.isSharedPath)(destRel)) {
|
|
28019
28163
|
const gate2 = gateSharedWrite(base.absolute, destRel, accountId, "POST /api/admin/files/upload");
|
|
28020
28164
|
if (!gate2.ok) return { ok: false, status: gate2.status, error: gate2.error };
|
|
@@ -28400,7 +28544,7 @@ app28.delete("/", requireAdminSession, async (c) => {
|
|
|
28400
28544
|
const dot = base.lastIndexOf(".");
|
|
28401
28545
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
28402
28546
|
const containerDir = dirname16(absolute);
|
|
28403
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
28547
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join53(containerDir, `${stem}.meta.json`) : null;
|
|
28404
28548
|
const isAttachmentContainer = UUID_RE3.test(stem) && basename15(containerDir) === stem;
|
|
28405
28549
|
await unlink3(absolute);
|
|
28406
28550
|
if (sidecarPath) {
|
|
@@ -28410,7 +28554,7 @@ app28.delete("/", requireAdminSession, async (c) => {
|
|
|
28410
28554
|
}
|
|
28411
28555
|
}
|
|
28412
28556
|
if (isAttachmentContainer) {
|
|
28413
|
-
await unlink3(
|
|
28557
|
+
await unlink3(join53(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
|
|
28414
28558
|
});
|
|
28415
28559
|
await rmdir(containerDir).catch(() => {
|
|
28416
28560
|
});
|
|
@@ -29525,8 +29669,8 @@ function isHiddenByDefault(label) {
|
|
|
29525
29669
|
|
|
29526
29670
|
// server/lib/top-level-labels.ts
|
|
29527
29671
|
var import_dist14 = __toESM(require_dist9(), 1);
|
|
29528
|
-
import { readdirSync as
|
|
29529
|
-
import { join as
|
|
29672
|
+
import { readdirSync as readdirSync27, readFileSync as readFileSync43 } from "fs";
|
|
29673
|
+
import { join as join54, resolve as resolve33 } from "path";
|
|
29530
29674
|
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
29531
29675
|
/* @__PURE__ */ new Set([
|
|
29532
29676
|
// Base-schema infra (schema-base.md has no top-level section).
|
|
@@ -29630,7 +29774,7 @@ function parseTopLevelLabels(content) {
|
|
|
29630
29774
|
}
|
|
29631
29775
|
function resolveReferencesDir() {
|
|
29632
29776
|
if (process.env.MAXY_PLATFORM_ROOT) {
|
|
29633
|
-
return
|
|
29777
|
+
return join54(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
|
|
29634
29778
|
}
|
|
29635
29779
|
return resolve33(import.meta.dirname, "../../../plugins/memory/references");
|
|
29636
29780
|
}
|
|
@@ -29638,9 +29782,9 @@ function parseTableTopLevelLabels(referencesDir) {
|
|
|
29638
29782
|
const labels = /* @__PURE__ */ new Set();
|
|
29639
29783
|
const contributingFiles = [];
|
|
29640
29784
|
try {
|
|
29641
|
-
const fileNames =
|
|
29785
|
+
const fileNames = readdirSync27(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
|
|
29642
29786
|
for (const fileName of fileNames) {
|
|
29643
|
-
const content =
|
|
29787
|
+
const content = readFileSync43(join54(referencesDir, fileName), "utf-8");
|
|
29644
29788
|
const parsed = parseTopLevelLabels(content);
|
|
29645
29789
|
if (parsed.length > 0) contributingFiles.push(fileName);
|
|
29646
29790
|
for (const label of parsed) labels.add(label);
|
|
@@ -30978,19 +31122,19 @@ function isWithin(target, root) {
|
|
|
30978
31122
|
var sidebar_artefacts_default = app35;
|
|
30979
31123
|
|
|
30980
31124
|
// server/channel-session-override.ts
|
|
30981
|
-
import { readFileSync as
|
|
30982
|
-
import { join as
|
|
31125
|
+
import { readFileSync as readFileSync44, writeFileSync as writeFileSync19, renameSync as renameSync10 } from "fs";
|
|
31126
|
+
import { join as join55 } from "path";
|
|
30983
31127
|
var FILE2 = "channel-session-override.json";
|
|
30984
31128
|
var UUID3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
30985
31129
|
function channelOverridePath(accountDir) {
|
|
30986
|
-
return
|
|
31130
|
+
return join55(accountDir, FILE2);
|
|
30987
31131
|
}
|
|
30988
31132
|
function senderKey(channel, senderId) {
|
|
30989
31133
|
return `${channel}:${senderId}`;
|
|
30990
31134
|
}
|
|
30991
31135
|
function readRaw2(accountDir) {
|
|
30992
31136
|
try {
|
|
30993
|
-
return JSON.parse(
|
|
31137
|
+
return JSON.parse(readFileSync44(channelOverridePath(accountDir), "utf8"));
|
|
30994
31138
|
} catch {
|
|
30995
31139
|
return null;
|
|
30996
31140
|
}
|
|
@@ -31428,24 +31572,24 @@ var session_rc_spawn_default = app41;
|
|
|
31428
31572
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
31429
31573
|
|
|
31430
31574
|
// server/wa-descriptor.ts
|
|
31431
|
-
import { resolve as resolve35, join as
|
|
31575
|
+
import { resolve as resolve35, join as join56 } from "path";
|
|
31432
31576
|
function waGatewayUrl() {
|
|
31433
31577
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
31434
31578
|
}
|
|
31435
31579
|
function waServerPath() {
|
|
31436
|
-
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve35(process.env.MAXY_PLATFORM_ROOT ??
|
|
31580
|
+
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve35(process.env.MAXY_PLATFORM_ROOT ?? join56(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
|
|
31437
31581
|
}
|
|
31438
31582
|
function waChannelDescriptor(senderId) {
|
|
31439
31583
|
return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
|
|
31440
31584
|
}
|
|
31441
31585
|
|
|
31442
31586
|
// server/telegram-descriptor.ts
|
|
31443
|
-
import { resolve as resolve36, join as
|
|
31587
|
+
import { resolve as resolve36, join as join57 } from "path";
|
|
31444
31588
|
function telegramGatewayUrl() {
|
|
31445
31589
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
31446
31590
|
}
|
|
31447
31591
|
function telegramServerPath() {
|
|
31448
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve36(process.env.MAXY_PLATFORM_ROOT ??
|
|
31592
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve36(process.env.MAXY_PLATFORM_ROOT ?? join57(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
31449
31593
|
}
|
|
31450
31594
|
function telegramChannelDescriptor(senderId) {
|
|
31451
31595
|
return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
|
|
@@ -31616,12 +31760,12 @@ function parseCpuStat(blob) {
|
|
|
31616
31760
|
const line = blob.split("\n", 1)[0] ?? "";
|
|
31617
31761
|
const parts = line.trim().split(/\s+/);
|
|
31618
31762
|
if (parts[0] !== "cpu") throw new Error(`unexpected /proc/stat header: ${parts[0] ?? "(empty)"}`);
|
|
31619
|
-
const
|
|
31620
|
-
if (
|
|
31763
|
+
const fields2 = parts.slice(1).map((n) => Number.parseInt(n, 10));
|
|
31764
|
+
if (fields2.length < 4 || fields2.some((n) => !Number.isFinite(n))) {
|
|
31621
31765
|
throw new Error("malformed /proc/stat cpu line");
|
|
31622
31766
|
}
|
|
31623
|
-
const idle =
|
|
31624
|
-
const total =
|
|
31767
|
+
const idle = fields2[3] + (fields2[4] ?? 0);
|
|
31768
|
+
const total = fields2.reduce((a, b) => a + b, 0);
|
|
31625
31769
|
return { idle, total };
|
|
31626
31770
|
}
|
|
31627
31771
|
function cpuPctFromSamples(a, b) {
|
|
@@ -31731,14 +31875,14 @@ app43.get("/", async (c) => {
|
|
|
31731
31875
|
var system_stats_default = app43;
|
|
31732
31876
|
|
|
31733
31877
|
// server/routes/admin/health.ts
|
|
31734
|
-
import { existsSync as existsSync45, readFileSync as
|
|
31735
|
-
import { resolve as resolve37, join as
|
|
31878
|
+
import { existsSync as existsSync45, readFileSync as readFileSync45 } from "fs";
|
|
31879
|
+
import { resolve as resolve37, join as join58 } from "path";
|
|
31736
31880
|
var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve37(process.cwd(), "..");
|
|
31737
31881
|
var brandHostname = "maxy";
|
|
31738
|
-
var brandJsonPath =
|
|
31882
|
+
var brandJsonPath = join58(PLATFORM_ROOT4, "config", "brand.json");
|
|
31739
31883
|
if (existsSync45(brandJsonPath)) {
|
|
31740
31884
|
try {
|
|
31741
|
-
const brand = JSON.parse(
|
|
31885
|
+
const brand = JSON.parse(readFileSync45(brandJsonPath, "utf-8"));
|
|
31742
31886
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
31743
31887
|
} catch {
|
|
31744
31888
|
}
|
|
@@ -31748,7 +31892,7 @@ var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
|
31748
31892
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
31749
31893
|
function readVersion() {
|
|
31750
31894
|
if (!existsSync45(VERSION_FILE)) return "unknown";
|
|
31751
|
-
return
|
|
31895
|
+
return readFileSync45(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
31752
31896
|
}
|
|
31753
31897
|
async function probeConversationDb() {
|
|
31754
31898
|
let session;
|
|
@@ -31803,7 +31947,7 @@ import { randomUUID as randomUUID10 } from "crypto";
|
|
|
31803
31947
|
|
|
31804
31948
|
// ../lib/account-ingest-token/src/index.ts
|
|
31805
31949
|
import { randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
31806
|
-
import { existsSync as existsSync46, readdirSync as
|
|
31950
|
+
import { existsSync as existsSync46, readdirSync as readdirSync28, readFileSync as readFileSync46, writeFileSync as writeFileSync20 } from "fs";
|
|
31807
31951
|
import { resolve as resolve38 } from "path";
|
|
31808
31952
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
31809
31953
|
var INGEST_TOKEN_FIELD = "ingestToken";
|
|
@@ -31815,7 +31959,7 @@ function readConfig2(accountsDir, accountId) {
|
|
|
31815
31959
|
const path = configPath2(accountsDir, accountId);
|
|
31816
31960
|
if (!existsSync46(path)) return null;
|
|
31817
31961
|
try {
|
|
31818
|
-
const parsed = JSON.parse(
|
|
31962
|
+
const parsed = JSON.parse(readFileSync46(path, "utf-8"));
|
|
31819
31963
|
return parsed !== null && typeof parsed === "object" ? parsed : null;
|
|
31820
31964
|
} catch {
|
|
31821
31965
|
return null;
|
|
@@ -31829,7 +31973,7 @@ function listAccountIdsOnDisk(accountsDir) {
|
|
|
31829
31973
|
if (!existsSync46(accountsDir)) return [];
|
|
31830
31974
|
let entries2;
|
|
31831
31975
|
try {
|
|
31832
|
-
entries2 =
|
|
31976
|
+
entries2 = readdirSync28(accountsDir);
|
|
31833
31977
|
} catch {
|
|
31834
31978
|
return [];
|
|
31835
31979
|
}
|
|
@@ -32356,9 +32500,9 @@ function renderWrite(write) {
|
|
|
32356
32500
|
const val = String(v).slice(0, 200);
|
|
32357
32501
|
kv.push(`${k}=${val}`);
|
|
32358
32502
|
}
|
|
32359
|
-
const
|
|
32360
|
-
if (
|
|
32361
|
-
return `- ${label}: ${
|
|
32503
|
+
const tail2 = [parts.join(" "), kv.join("; ")].filter((s) => s.length > 0).join(" \u2014 ");
|
|
32504
|
+
if (tail2.length === 0) return null;
|
|
32505
|
+
return `- ${label}: ${tail2}`;
|
|
32362
32506
|
}
|
|
32363
32507
|
function formatPreviousContext(writes) {
|
|
32364
32508
|
if (writes.length === 0) return null;
|
|
@@ -32668,7 +32812,7 @@ var browser_default = app51;
|
|
|
32668
32812
|
// server/routes/admin/calendar.ts
|
|
32669
32813
|
import { existsSync as existsSync47 } from "fs";
|
|
32670
32814
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
32671
|
-
import { join as
|
|
32815
|
+
import { join as join60 } from "path";
|
|
32672
32816
|
|
|
32673
32817
|
// server/lib/calendar-ics.ts
|
|
32674
32818
|
var CRLF = "\r\n";
|
|
@@ -32768,8 +32912,8 @@ function countVEvents(ics) {
|
|
|
32768
32912
|
}
|
|
32769
32913
|
|
|
32770
32914
|
// server/lib/calendar-availability.ts
|
|
32771
|
-
import { readFileSync as
|
|
32772
|
-
import { join as
|
|
32915
|
+
import { readFileSync as readFileSync47 } from "fs";
|
|
32916
|
+
import { join as join59 } from "path";
|
|
32773
32917
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
32774
32918
|
var REQUIRED_KEYS = [
|
|
32775
32919
|
"timezone",
|
|
@@ -32778,10 +32922,10 @@ var REQUIRED_KEYS = [
|
|
|
32778
32922
|
"weekly"
|
|
32779
32923
|
];
|
|
32780
32924
|
function readAvailabilityConfig(accountDir) {
|
|
32781
|
-
const path =
|
|
32925
|
+
const path = join59(accountDir, AVAILABILITY_FILENAME);
|
|
32782
32926
|
let raw;
|
|
32783
32927
|
try {
|
|
32784
|
-
raw =
|
|
32928
|
+
raw = readFileSync47(path, "utf-8");
|
|
32785
32929
|
} catch {
|
|
32786
32930
|
throw new Error(`availability not configured: ${path} not found`);
|
|
32787
32931
|
}
|
|
@@ -33167,16 +33311,16 @@ app52.patch("/meetings/:id", requireAdminSession, async (c) => {
|
|
|
33167
33311
|
}
|
|
33168
33312
|
const id = c.req.param("id");
|
|
33169
33313
|
const body = await safeJson(c) ?? {};
|
|
33170
|
-
const
|
|
33171
|
-
if (
|
|
33314
|
+
const fields2 = EDITABLE_FIELDS.filter((f) => f in body);
|
|
33315
|
+
if (fields2.length === 0) {
|
|
33172
33316
|
return c.json({ error: "No editable field supplied (title, startsAt, endsAt, location, description, privateNote)" }, 400);
|
|
33173
33317
|
}
|
|
33174
|
-
const setClauses =
|
|
33318
|
+
const setClauses = fields2.map(
|
|
33175
33319
|
(f) => f === "startsAt" || f === "endsAt" ? `m.${f} = datetime($${f})` : `m.${f} = $${f}`
|
|
33176
33320
|
);
|
|
33177
33321
|
setClauses.push("m.updatedAt = datetime()");
|
|
33178
33322
|
const params = { accountId, id };
|
|
33179
|
-
for (const f of
|
|
33323
|
+
for (const f of fields2) params[f] = body[f];
|
|
33180
33324
|
const session = getSession();
|
|
33181
33325
|
try {
|
|
33182
33326
|
const res = await session.run(
|
|
@@ -33187,12 +33331,12 @@ app52.patch("/meetings/:id", requireAdminSession, async (c) => {
|
|
|
33187
33331
|
params
|
|
33188
33332
|
);
|
|
33189
33333
|
if (res.records.length === 0) {
|
|
33190
|
-
console.warn(`[calendar-edit] account=${accountId.slice(0, 8)} uid=absent fields=${
|
|
33334
|
+
console.warn(`[calendar-edit] account=${accountId.slice(0, 8)} uid=absent fields=${fields2.join(",")} found=0`);
|
|
33191
33335
|
return c.json({ error: "Meeting not found for this account" }, 404);
|
|
33192
33336
|
}
|
|
33193
33337
|
const r = res.records[0];
|
|
33194
33338
|
const uid = r.get("uid");
|
|
33195
|
-
console.log(`[calendar-edit] account=${accountId.slice(0, 8)} uid=${uid ?? "absent"} fields=${
|
|
33339
|
+
console.log(`[calendar-edit] account=${accountId.slice(0, 8)} uid=${uid ?? "absent"} fields=${fields2.join(",")}`);
|
|
33196
33340
|
return c.json({ meeting: mapMeeting(r) });
|
|
33197
33341
|
} catch (err) {
|
|
33198
33342
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -33336,7 +33480,7 @@ app52.get("/booking-link", requireAdminSession, (c) => {
|
|
|
33336
33480
|
}
|
|
33337
33481
|
const id83 = account.accountId.slice(0, 8);
|
|
33338
33482
|
try {
|
|
33339
|
-
if (!existsSync47(
|
|
33483
|
+
if (!existsSync47(join60(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
33340
33484
|
console.log(`[calendar] op=booking-link accountId=${id83} bookingDomain=none source=availability-config`);
|
|
33341
33485
|
return c.json({ bookingDomain: null });
|
|
33342
33486
|
}
|
|
@@ -33355,8 +33499,8 @@ app52.get("/booking-link", requireAdminSession, (c) => {
|
|
|
33355
33499
|
var calendar_default = app52;
|
|
33356
33500
|
|
|
33357
33501
|
// server/routes/admin/data-portal.ts
|
|
33358
|
-
import { existsSync as existsSync48, readFileSync as
|
|
33359
|
-
import { join as
|
|
33502
|
+
import { existsSync as existsSync48, readFileSync as readFileSync48 } from "fs";
|
|
33503
|
+
import { join as join61 } from "path";
|
|
33360
33504
|
var app53 = new Hono();
|
|
33361
33505
|
var PORTAL_FILENAME = "data-portal.json";
|
|
33362
33506
|
app53.get("/portal-link", requireAdminSession, (c) => {
|
|
@@ -33367,12 +33511,12 @@ app53.get("/portal-link", requireAdminSession, (c) => {
|
|
|
33367
33511
|
}
|
|
33368
33512
|
const id83 = account.accountId.slice(0, 8);
|
|
33369
33513
|
try {
|
|
33370
|
-
const path =
|
|
33514
|
+
const path = join61(account.accountDir, PORTAL_FILENAME);
|
|
33371
33515
|
if (!existsSync48(path)) {
|
|
33372
33516
|
console.log(`[data-portal] op=portal-link accountId=${id83} portalDomain=none source=data-portal-config`);
|
|
33373
33517
|
return c.json({ portalDomain: null });
|
|
33374
33518
|
}
|
|
33375
|
-
const cfg = JSON.parse(
|
|
33519
|
+
const cfg = JSON.parse(readFileSync48(path, "utf-8"));
|
|
33376
33520
|
const portalDomain = typeof cfg.portalDomain === "string" && cfg.portalDomain.trim() ? cfg.portalDomain.trim() : null;
|
|
33377
33521
|
console.log(`[data-portal] op=portal-link accountId=${id83} portalDomain=${portalDomain ?? "none"} source=data-portal-config`);
|
|
33378
33522
|
return c.json({ portalDomain });
|
|
@@ -33385,8 +33529,8 @@ app53.get("/portal-link", requireAdminSession, (c) => {
|
|
|
33385
33529
|
var data_portal_default = app53;
|
|
33386
33530
|
|
|
33387
33531
|
// server/routes/admin/dispatch-planner.ts
|
|
33388
|
-
import { existsSync as existsSync49, readFileSync as
|
|
33389
|
-
import { join as
|
|
33532
|
+
import { existsSync as existsSync49, readFileSync as readFileSync49 } from "fs";
|
|
33533
|
+
import { join as join62 } from "path";
|
|
33390
33534
|
var app54 = new Hono();
|
|
33391
33535
|
var PORTAL_FILENAME2 = "data-portal.json";
|
|
33392
33536
|
app54.get("/planner-link", requireAdminSession, (c) => {
|
|
@@ -33399,15 +33543,15 @@ app54.get("/planner-link", requireAdminSession, (c) => {
|
|
|
33399
33543
|
}
|
|
33400
33544
|
const id83 = account.accountId.slice(0, 8);
|
|
33401
33545
|
try {
|
|
33402
|
-
const portalPath =
|
|
33403
|
-
const dispatchConfigured = existsSync49(
|
|
33546
|
+
const portalPath = join62(account.accountDir, PORTAL_FILENAME2);
|
|
33547
|
+
const dispatchConfigured = existsSync49(join62(account.accountDir, "dispatch", "config.json"));
|
|
33404
33548
|
if (!existsSync49(portalPath) || !dispatchConfigured) {
|
|
33405
33549
|
console.log(
|
|
33406
33550
|
`[dispatch-planner] op=planner-link accountId=${id83} plannerUrl=none portal=${existsSync49(portalPath)} dispatch=${dispatchConfigured}`
|
|
33407
33551
|
);
|
|
33408
33552
|
return c.json({ plannerUrl: null });
|
|
33409
33553
|
}
|
|
33410
|
-
const cfg = JSON.parse(
|
|
33554
|
+
const cfg = JSON.parse(readFileSync49(portalPath, "utf-8"));
|
|
33411
33555
|
const domain = typeof cfg.portalDomain === "string" && cfg.portalDomain.trim() ? cfg.portalDomain.trim() : null;
|
|
33412
33556
|
const plannerUrl = domain ? `https://${domain}/planner` : null;
|
|
33413
33557
|
console.log(
|
|
@@ -33425,11 +33569,11 @@ var dispatch_planner_default = app54;
|
|
|
33425
33569
|
// server/routes/admin/routines.ts
|
|
33426
33570
|
import cronParser from "cron-parser";
|
|
33427
33571
|
import { int as int2 } from "neo4j-driver";
|
|
33428
|
-
import { readFileSync as
|
|
33572
|
+
import { readFileSync as readFileSync51 } from "fs";
|
|
33429
33573
|
import { resolve as resolve40 } from "path";
|
|
33430
33574
|
|
|
33431
33575
|
// ../lib/agent-dispatch-rule/src/index.ts
|
|
33432
|
-
import { readFileSync as
|
|
33576
|
+
import { readFileSync as readFileSync50 } from "fs";
|
|
33433
33577
|
import { resolve as resolve39 } from "path";
|
|
33434
33578
|
function normalizeE1642(value) {
|
|
33435
33579
|
let candidate = value.trim().replace(/[\s\-().]/g, "");
|
|
@@ -33447,7 +33591,7 @@ function phonesMatch2(a, b) {
|
|
|
33447
33591
|
function readChannelAdmins(accountDir, channel) {
|
|
33448
33592
|
let config = {};
|
|
33449
33593
|
try {
|
|
33450
|
-
config = JSON.parse(
|
|
33594
|
+
config = JSON.parse(readFileSync50(resolve39(accountDir, "account.json"), "utf-8"));
|
|
33451
33595
|
} catch {
|
|
33452
33596
|
config = {};
|
|
33453
33597
|
}
|
|
@@ -33554,23 +33698,39 @@ function listDispatchDestinations(input) {
|
|
|
33554
33698
|
const byDestination = (a, b) => a.destination.localeCompare(b.destination);
|
|
33555
33699
|
return [...managers.sort(byDestination), ...admins.sort(byDestination), ...telegram];
|
|
33556
33700
|
}
|
|
33557
|
-
function isDispatchable(
|
|
33558
|
-
if (
|
|
33559
|
-
return Boolean(
|
|
33701
|
+
function isDispatchable(fields2) {
|
|
33702
|
+
if (fields2.agentChannel && fields2.agentDestination && fields2.agentPrompt) return true;
|
|
33703
|
+
return Boolean(fields2.actionPlugin && fields2.actionTool);
|
|
33560
33704
|
}
|
|
33561
|
-
function dispatchGapReason(
|
|
33562
|
-
if (
|
|
33705
|
+
function dispatchGapReason(fields2) {
|
|
33706
|
+
if (fields2.agentChannel || fields2.agentDestination || fields2.agentPrompt) {
|
|
33563
33707
|
const missing = [];
|
|
33564
|
-
if (!
|
|
33565
|
-
if (!
|
|
33566
|
-
if (!
|
|
33708
|
+
if (!fields2.agentChannel) missing.push("channel");
|
|
33709
|
+
if (!fields2.agentDestination) missing.push("destination");
|
|
33710
|
+
if (!fields2.agentPrompt) missing.push("prompt");
|
|
33567
33711
|
return `no-${missing.join("+")}`;
|
|
33568
33712
|
}
|
|
33569
|
-
if (
|
|
33570
|
-
return
|
|
33713
|
+
if (fields2.actionPlugin || fields2.actionTool) {
|
|
33714
|
+
return fields2.actionTool ? "no-action-plugin" : "no-action-tool";
|
|
33571
33715
|
}
|
|
33572
33716
|
return "no-dispatch-configured";
|
|
33573
33717
|
}
|
|
33718
|
+
function carrierVerdict(accountDir, botId, destination) {
|
|
33719
|
+
let config = {};
|
|
33720
|
+
try {
|
|
33721
|
+
config = JSON.parse(readFileSync50(resolve39(accountDir, "account.json"), "utf-8"));
|
|
33722
|
+
} catch {
|
|
33723
|
+
return { ok: false, reason: "absent" };
|
|
33724
|
+
}
|
|
33725
|
+
const bots = Array.isArray(config.telegram?.bots) ? config.telegram.bots : [];
|
|
33726
|
+
const entry3 = bots.find(
|
|
33727
|
+
(raw) => raw && typeof raw === "object" && raw.id === botId
|
|
33728
|
+
);
|
|
33729
|
+
if (!entry3) return { ok: false, reason: "absent" };
|
|
33730
|
+
if (entry3.role !== "admin") return { ok: false, reason: "not-admin" };
|
|
33731
|
+
const users = Array.isArray(entry3.adminUsers) ? entry3.adminUsers.filter((u) => typeof u === "number") : [];
|
|
33732
|
+
return users.includes(Number(destination)) ? { ok: true } : { ok: false, reason: "not-listed" };
|
|
33733
|
+
}
|
|
33574
33734
|
|
|
33575
33735
|
// server/routes/admin/routines.ts
|
|
33576
33736
|
var { parseExpression } = cronParser;
|
|
@@ -33615,7 +33775,7 @@ function gateWatermarkPath(eventId) {
|
|
|
33615
33775
|
}
|
|
33616
33776
|
function readGateLastCommitAt(eventId) {
|
|
33617
33777
|
try {
|
|
33618
|
-
const parsed = JSON.parse(
|
|
33778
|
+
const parsed = JSON.parse(readFileSync51(gateWatermarkPath(eventId), "utf-8"));
|
|
33619
33779
|
return typeof parsed?.lastCommitAt === "string" ? parsed.lastCommitAt : null;
|
|
33620
33780
|
} catch {
|
|
33621
33781
|
return null;
|
|
@@ -33725,9 +33885,9 @@ function describeDispatchGap(reason) {
|
|
|
33725
33885
|
destination: "a destination",
|
|
33726
33886
|
prompt: "an instruction"
|
|
33727
33887
|
};
|
|
33728
|
-
const
|
|
33729
|
-
if (
|
|
33730
|
-
const list =
|
|
33888
|
+
const fields2 = reason.startsWith("no-") ? reason.slice(3).split("+") : [];
|
|
33889
|
+
if (fields2.length > 0 && fields2.every((f) => f in words)) {
|
|
33890
|
+
const list = fields2.map((f) => words[f]);
|
|
33731
33891
|
const joined = list.length === 1 ? list[0] : `${list.slice(0, -1).join(", ")} and ${list[list.length - 1]}`;
|
|
33732
33892
|
return `This routine has no ${joined.replace(/^an? /, "")} set, so arming it would deliver nothing.`;
|
|
33733
33893
|
}
|
|
@@ -34056,7 +34216,7 @@ app55.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
34056
34216
|
const id83 = eventId.slice(0, 8);
|
|
34057
34217
|
const setClauses = [];
|
|
34058
34218
|
const params = { eventId, accountId };
|
|
34059
|
-
const
|
|
34219
|
+
const fields2 = [];
|
|
34060
34220
|
let nextRunLog = "unchanged";
|
|
34061
34221
|
let bindingLog = "";
|
|
34062
34222
|
const hasChannel = "agentChannel" in body;
|
|
@@ -34140,7 +34300,7 @@ app55.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
34140
34300
|
setClauses.push("e.agentChannel = $agentChannel", "e.agentDestination = $agentDestination");
|
|
34141
34301
|
params.agentChannel = channel;
|
|
34142
34302
|
params.agentDestination = destination;
|
|
34143
|
-
|
|
34303
|
+
fields2.push("agentChannel", "agentDestination");
|
|
34144
34304
|
bindingLog = ` channel=${channel} destination=${destination.slice(-4)}`;
|
|
34145
34305
|
}
|
|
34146
34306
|
if (clearing) {
|
|
@@ -34153,13 +34313,13 @@ app55.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
34153
34313
|
);
|
|
34154
34314
|
}
|
|
34155
34315
|
setClauses.push("e.agentChannel = null", "e.agentDestination = null");
|
|
34156
|
-
|
|
34316
|
+
fields2.push("agentChannel", "agentDestination");
|
|
34157
34317
|
bindingLog = " channel=none destination=none";
|
|
34158
34318
|
}
|
|
34159
34319
|
if (typeof body.agentPrompt === "string") {
|
|
34160
34320
|
setClauses.push("e.agentPrompt = $agentPrompt");
|
|
34161
34321
|
params.agentPrompt = body.agentPrompt;
|
|
34162
|
-
|
|
34322
|
+
fields2.push("agentPrompt");
|
|
34163
34323
|
setClauses.push("e.operatorEdited = $operatorEdited");
|
|
34164
34324
|
params.operatorEdited = (/* @__PURE__ */ new Date()).toISOString();
|
|
34165
34325
|
}
|
|
@@ -34176,7 +34336,7 @@ app55.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
34176
34336
|
}
|
|
34177
34337
|
setClauses.push("e.name = $name");
|
|
34178
34338
|
params.name = nextName;
|
|
34179
|
-
|
|
34339
|
+
fields2.push("name");
|
|
34180
34340
|
setClauses.push("e.operatorEdited = $operatorEdited");
|
|
34181
34341
|
params.operatorEdited = (/* @__PURE__ */ new Date()).toISOString();
|
|
34182
34342
|
}
|
|
@@ -34190,7 +34350,7 @@ app55.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
34190
34350
|
nextDescription = typeof raw === "string" && raw.trim().length > 0 ? raw : null;
|
|
34191
34351
|
setClauses.push("e.description = $description");
|
|
34192
34352
|
params.description = nextDescription;
|
|
34193
|
-
|
|
34353
|
+
fields2.push("description");
|
|
34194
34354
|
setClauses.push("e.operatorEdited = $operatorEdited");
|
|
34195
34355
|
params.operatorEdited = (/* @__PURE__ */ new Date()).toISOString();
|
|
34196
34356
|
}
|
|
@@ -34205,7 +34365,7 @@ app55.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
34205
34365
|
params.embedding = embedding;
|
|
34206
34366
|
} else {
|
|
34207
34367
|
embedLog = " embed=failed";
|
|
34208
|
-
console.error(`[admin:routines] op=patch id=${id83} fields=${
|
|
34368
|
+
console.error(`[admin:routines] op=patch id=${id83} fields=${fields2.join("+")} embed=failed`);
|
|
34209
34369
|
}
|
|
34210
34370
|
}
|
|
34211
34371
|
if (typeof body.recurrence === "string") {
|
|
@@ -34215,7 +34375,7 @@ app55.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
34215
34375
|
setClauses.push("e.recurrence = $recurrence", "e.nextRun = $nextRun");
|
|
34216
34376
|
params.recurrence = body.recurrence;
|
|
34217
34377
|
params.nextRun = nextRun;
|
|
34218
|
-
|
|
34378
|
+
fields2.push("recurrence");
|
|
34219
34379
|
nextRunLog = nextRun;
|
|
34220
34380
|
} catch (err) {
|
|
34221
34381
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -34241,7 +34401,7 @@ app55.patch("/:eventId", requireAdminSession, async (c) => {
|
|
|
34241
34401
|
return c.json({ error: "Routine not found" }, 404);
|
|
34242
34402
|
}
|
|
34243
34403
|
const nameLog = nextName === null ? "" : ` name=len:${nextName.length} operatorEdited=stamped`;
|
|
34244
|
-
console.log(`[admin:routines] op=patch id=${id83} fields=${
|
|
34404
|
+
console.log(`[admin:routines] op=patch id=${id83} fields=${fields2.join("+")} outcome=ok nextRun=${nextRunLog} cron=${params.recurrence ?? "unchanged"}${bindingLog}${nameLog}${embedLog}`);
|
|
34245
34405
|
return c.json({ routine: mapRoutine(res.records[0]) });
|
|
34246
34406
|
} catch (err) {
|
|
34247
34407
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -34492,7 +34652,7 @@ app55.delete("/:eventId", requireAdminSession, async (c) => {
|
|
|
34492
34652
|
var routines_default = app55;
|
|
34493
34653
|
|
|
34494
34654
|
// server/routes/admin/skills.ts
|
|
34495
|
-
import { existsSync as existsSync50, readdirSync as
|
|
34655
|
+
import { existsSync as existsSync50, readdirSync as readdirSync29, readFileSync as readFileSync52, rmSync as rmSync6 } from "fs";
|
|
34496
34656
|
import { resolve as resolve41 } from "path";
|
|
34497
34657
|
var app56 = new Hono();
|
|
34498
34658
|
var NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
@@ -34518,7 +34678,7 @@ function stripQuotes(s) {
|
|
|
34518
34678
|
function subdirs2(dir) {
|
|
34519
34679
|
if (!existsSync50(dir)) return [];
|
|
34520
34680
|
try {
|
|
34521
|
-
return
|
|
34681
|
+
return readdirSync29(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
34522
34682
|
} catch {
|
|
34523
34683
|
return [];
|
|
34524
34684
|
}
|
|
@@ -34541,9 +34701,9 @@ app56.get("/", requireAdminSession, async (c) => {
|
|
|
34541
34701
|
const skillMd = resolve41(skillsDir, skill, "SKILL.md");
|
|
34542
34702
|
if (!existsSync50(skillMd)) continue;
|
|
34543
34703
|
try {
|
|
34544
|
-
const { frontmatter } = splitSkillMd(
|
|
34704
|
+
const { frontmatter } = splitSkillMd(readFileSync52(skillMd, "utf-8"));
|
|
34545
34705
|
const refsDir = resolve41(skillsDir, skill, "references");
|
|
34546
|
-
const refCount = existsSync50(refsDir) ?
|
|
34706
|
+
const refCount = existsSync50(refsDir) ? readdirSync29(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).length : 0;
|
|
34547
34707
|
skills.push({ plugin, skill, description: frontmatter.description, refCount });
|
|
34548
34708
|
} catch (err) {
|
|
34549
34709
|
console.error(`[admin:skills] op=list-skip plugin=${plugin} skill=${skill} reason="${err instanceof Error ? err.message : String(err)}"`);
|
|
@@ -34571,9 +34731,9 @@ app56.get("/:plugin/:skill", requireAdminSession, async (c) => {
|
|
|
34571
34731
|
console.log(`[admin:skills] op=get plugin=${plugin} skill=${skill} found=${found}`);
|
|
34572
34732
|
if (!found) return c.json({ error: "Skill not found" }, 404);
|
|
34573
34733
|
try {
|
|
34574
|
-
const { frontmatter, body } = splitSkillMd(
|
|
34734
|
+
const { frontmatter, body } = splitSkillMd(readFileSync52(skillMd, "utf-8"));
|
|
34575
34735
|
const refsDir = resolve41(skillDir, "references");
|
|
34576
|
-
const references = existsSync50(refsDir) ?
|
|
34736
|
+
const references = existsSync50(refsDir) ? readdirSync29(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).sort() : [];
|
|
34577
34737
|
return c.json({ skill: { plugin, skill, frontmatter, body, references } });
|
|
34578
34738
|
} catch (err) {
|
|
34579
34739
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -34617,7 +34777,7 @@ app56.delete("/:plugin/:skill", requireAdminSession, async (c) => {
|
|
|
34617
34777
|
var skills_default = app56;
|
|
34618
34778
|
|
|
34619
34779
|
// server/routes/admin/tasks-list.ts
|
|
34620
|
-
import { basename as basename17, join as
|
|
34780
|
+
import { basename as basename17, join as join63 } from "path";
|
|
34621
34781
|
|
|
34622
34782
|
// app/lib/time-entry-format.ts
|
|
34623
34783
|
function secondsBetween(startIso, endIso) {
|
|
@@ -34793,7 +34953,7 @@ async function computeTaskList(accountId) {
|
|
|
34793
34953
|
dangling = 0;
|
|
34794
34954
|
} else if (cfg !== null) {
|
|
34795
34955
|
try {
|
|
34796
|
-
const walk = enumerateJsonlsWithSkips(
|
|
34956
|
+
const walk = enumerateJsonlsWithSkips(join63(cfg, "projects"));
|
|
34797
34957
|
if (walk.skipped > 0) {
|
|
34798
34958
|
console.error(
|
|
34799
34959
|
`${TAG51} op=session-dangling-census-incomplete account=${accountId} skipped=${walk.skipped} detail="a slug the walk could not read contributes no session ids, so its links cannot be judged"`
|
|
@@ -35205,12 +35365,12 @@ app62.post("/", requireAdminSession, async (c) => {
|
|
|
35205
35365
|
var task_delete_default = app62;
|
|
35206
35366
|
|
|
35207
35367
|
// app/lib/admin-roster.ts
|
|
35208
|
-
import { existsSync as existsSync51, readdirSync as
|
|
35368
|
+
import { existsSync as existsSync51, readdirSync as readdirSync30, readFileSync as readFileSync53 } from "fs";
|
|
35209
35369
|
import { resolve as resolve42 } from "path";
|
|
35210
35370
|
function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
|
|
35211
35371
|
let entries2;
|
|
35212
35372
|
try {
|
|
35213
|
-
entries2 =
|
|
35373
|
+
entries2 = readdirSync30(accountsDir);
|
|
35214
35374
|
} catch {
|
|
35215
35375
|
return [];
|
|
35216
35376
|
}
|
|
@@ -35218,7 +35378,7 @@ function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
|
|
|
35218
35378
|
const cfgPath = resolve42(accountsDir, entry3, "account.json");
|
|
35219
35379
|
if (!existsSync51(cfgPath)) continue;
|
|
35220
35380
|
try {
|
|
35221
|
-
const cfg = JSON.parse(
|
|
35381
|
+
const cfg = JSON.parse(readFileSync53(cfgPath, "utf-8"));
|
|
35222
35382
|
if (cfg.role !== "house") continue;
|
|
35223
35383
|
if (!Array.isArray(cfg.admins)) return [];
|
|
35224
35384
|
return cfg.admins.map(
|
|
@@ -35633,7 +35793,7 @@ app67.get("/", requireAdminSession, async (c) => {
|
|
|
35633
35793
|
var dispatch_destinations_default = app67;
|
|
35634
35794
|
|
|
35635
35795
|
// server/routes/admin/activity.ts
|
|
35636
|
-
import { readdirSync as
|
|
35796
|
+
import { readdirSync as readdirSync31 } from "fs";
|
|
35637
35797
|
var app68 = new Hono();
|
|
35638
35798
|
var TAG62 = "[activity]";
|
|
35639
35799
|
function resolveHouseAccountId2(accounts) {
|
|
@@ -35649,7 +35809,7 @@ function requestToken() {
|
|
|
35649
35809
|
var short = (id) => id ? id.slice(0, 8) : "unset";
|
|
35650
35810
|
function countAccountDirsOnDisk() {
|
|
35651
35811
|
try {
|
|
35652
|
-
return
|
|
35812
|
+
return readdirSync31(ACCOUNTS_DIR, { withFileTypes: true }).filter(
|
|
35653
35813
|
(e) => e.isDirectory() && !e.name.startsWith(".")
|
|
35654
35814
|
).length;
|
|
35655
35815
|
} catch {
|
|
@@ -36060,7 +36220,7 @@ app72.route("/request-magic-link", request_magic_link_default);
|
|
|
36060
36220
|
var access_default = app72;
|
|
36061
36221
|
|
|
36062
36222
|
// server/routes/sites.ts
|
|
36063
|
-
import { existsSync as existsSync52, readFileSync as
|
|
36223
|
+
import { existsSync as existsSync52, readFileSync as readFileSync54, realpathSync as realpathSync8, statSync as statSync28 } from "fs";
|
|
36064
36224
|
import { resolve as resolve45 } from "path";
|
|
36065
36225
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
36066
36226
|
var MIME = {
|
|
@@ -36126,7 +36286,7 @@ app73.get("/:rel{.*}", (c) => {
|
|
|
36126
36286
|
}
|
|
36127
36287
|
let stat11;
|
|
36128
36288
|
try {
|
|
36129
|
-
stat11 = existsSync52(filePath) ?
|
|
36289
|
+
stat11 = existsSync52(filePath) ? statSync28(filePath) : null;
|
|
36130
36290
|
} catch {
|
|
36131
36291
|
stat11 = null;
|
|
36132
36292
|
}
|
|
@@ -36164,7 +36324,7 @@ app73.get("/:rel{.*}", (c) => {
|
|
|
36164
36324
|
}
|
|
36165
36325
|
let body;
|
|
36166
36326
|
try {
|
|
36167
|
-
body =
|
|
36327
|
+
body = readFileSync54(realPath);
|
|
36168
36328
|
} catch (err) {
|
|
36169
36329
|
const code = err?.code;
|
|
36170
36330
|
if (code === "EISDIR") {
|
|
@@ -36200,7 +36360,7 @@ var sites_default = app73;
|
|
|
36200
36360
|
|
|
36201
36361
|
// app/lib/visitor-token.ts
|
|
36202
36362
|
import { createHmac as createHmac2, randomBytes as randomBytes3, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
36203
|
-
import { mkdirSync as mkdirSync12, readFileSync as
|
|
36363
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync55, writeFileSync as writeFileSync21 } from "fs";
|
|
36204
36364
|
import { dirname as dirname17 } from "path";
|
|
36205
36365
|
var TOKEN_PREFIX = "v1.";
|
|
36206
36366
|
var SECRET_BYTES = 32;
|
|
@@ -36209,7 +36369,7 @@ var cachedSecret = null;
|
|
|
36209
36369
|
function getSecret() {
|
|
36210
36370
|
if (cachedSecret) return cachedSecret;
|
|
36211
36371
|
try {
|
|
36212
|
-
const hex2 =
|
|
36372
|
+
const hex2 = readFileSync55(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
36213
36373
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
36214
36374
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
36215
36375
|
return cachedSecret;
|
|
@@ -36223,7 +36383,7 @@ function getSecret() {
|
|
|
36223
36383
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
36224
36384
|
} catch {
|
|
36225
36385
|
}
|
|
36226
|
-
const hex =
|
|
36386
|
+
const hex = readFileSync55(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
36227
36387
|
cachedSecret = Buffer.from(hex, "hex");
|
|
36228
36388
|
return cachedSecret;
|
|
36229
36389
|
}
|
|
@@ -36276,8 +36436,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
36276
36436
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
36277
36437
|
|
|
36278
36438
|
// app/lib/brand-config.ts
|
|
36279
|
-
import { existsSync as existsSync53, readFileSync as
|
|
36280
|
-
import { join as
|
|
36439
|
+
import { existsSync as existsSync53, readFileSync as readFileSync56 } from "fs";
|
|
36440
|
+
import { join as join64 } from "path";
|
|
36281
36441
|
var cached2 = null;
|
|
36282
36442
|
var cachedAttempted = false;
|
|
36283
36443
|
function readBrandConfig() {
|
|
@@ -36285,10 +36445,10 @@ function readBrandConfig() {
|
|
|
36285
36445
|
cachedAttempted = true;
|
|
36286
36446
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
36287
36447
|
if (!platformRoot5) return null;
|
|
36288
|
-
const brandPath =
|
|
36448
|
+
const brandPath = join64(platformRoot5, "config", "brand.json");
|
|
36289
36449
|
if (!existsSync53(brandPath)) return null;
|
|
36290
36450
|
try {
|
|
36291
|
-
cached2 = JSON.parse(
|
|
36451
|
+
cached2 = JSON.parse(readFileSync56(brandPath, "utf-8"));
|
|
36292
36452
|
return cached2;
|
|
36293
36453
|
} catch {
|
|
36294
36454
|
return null;
|
|
@@ -37054,7 +37214,7 @@ var calendar_public_default = app78;
|
|
|
37054
37214
|
// server/routes/portal-fetch.ts
|
|
37055
37215
|
import { createReadStream as createReadStream3 } from "fs";
|
|
37056
37216
|
import { stat as stat8, readFile as readFile12, realpath } from "fs/promises";
|
|
37057
|
-
import { join as
|
|
37217
|
+
import { join as join65, resolve as resolve47, sep as sep11 } from "path";
|
|
37058
37218
|
import { Readable as Readable3 } from "stream";
|
|
37059
37219
|
var app79 = new Hono();
|
|
37060
37220
|
var TAG65 = "[portal-fetch]";
|
|
@@ -37127,7 +37287,7 @@ function isValidAccountId2(value) {
|
|
|
37127
37287
|
}
|
|
37128
37288
|
async function readExposeFolders2(accountDir) {
|
|
37129
37289
|
try {
|
|
37130
|
-
const cfg = JSON.parse(await readFile12(
|
|
37290
|
+
const cfg = JSON.parse(await readFile12(join65(accountDir, "data-portal.json"), "utf8"));
|
|
37131
37291
|
return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
37132
37292
|
} catch {
|
|
37133
37293
|
return [];
|
|
@@ -37136,7 +37296,7 @@ async function readExposeFolders2(accountDir) {
|
|
|
37136
37296
|
async function resolveFetchTarget(accountDir, relPath, ownerId) {
|
|
37137
37297
|
let schemaText = null;
|
|
37138
37298
|
try {
|
|
37139
|
-
schemaText = await readFile12(
|
|
37299
|
+
schemaText = await readFile12(join65(accountDir, "SCHEMA.md"), "utf8");
|
|
37140
37300
|
} catch {
|
|
37141
37301
|
schemaText = null;
|
|
37142
37302
|
}
|
|
@@ -37306,8 +37466,8 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
37306
37466
|
}
|
|
37307
37467
|
|
|
37308
37468
|
// app/lib/ledger-census.ts
|
|
37309
|
-
import { readdirSync as
|
|
37310
|
-
import { join as
|
|
37469
|
+
import { readdirSync as readdirSync32, readFileSync as readFileSync57, statSync as statSync29 } from "fs";
|
|
37470
|
+
import { join as join66 } from "path";
|
|
37311
37471
|
|
|
37312
37472
|
// ../lib/ledger-core/dist/reconcile.js
|
|
37313
37473
|
var LEDGER_INDEX_NAMES = [
|
|
@@ -37355,16 +37515,16 @@ var DAY_MS = 864e5;
|
|
|
37355
37515
|
function countWriteRejects24h(logDir, now) {
|
|
37356
37516
|
let entries2;
|
|
37357
37517
|
try {
|
|
37358
|
-
entries2 =
|
|
37518
|
+
entries2 = readdirSync32(logDir).filter((f) => f.startsWith("mcp-ledger-") && f.endsWith(".log"));
|
|
37359
37519
|
} catch {
|
|
37360
37520
|
return 0;
|
|
37361
37521
|
}
|
|
37362
37522
|
let total = 0;
|
|
37363
37523
|
for (const name of entries2) {
|
|
37364
|
-
const path =
|
|
37524
|
+
const path = join66(logDir, name);
|
|
37365
37525
|
try {
|
|
37366
|
-
if (now -
|
|
37367
|
-
for (const line of
|
|
37526
|
+
if (now - statSync29(path).mtimeMs > DAY_MS) continue;
|
|
37527
|
+
for (const line of readFileSync57(path, "utf8").split("\n")) {
|
|
37368
37528
|
if (line.includes("[graph-write] reject")) total += 1;
|
|
37369
37529
|
}
|
|
37370
37530
|
} catch {
|
|
@@ -37465,8 +37625,8 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
37465
37625
|
}
|
|
37466
37626
|
|
|
37467
37627
|
// app/lib/dispatch-census.ts
|
|
37468
|
-
import { readFileSync as
|
|
37469
|
-
import { join as
|
|
37628
|
+
import { readFileSync as readFileSync58 } from "fs";
|
|
37629
|
+
import { join as join67 } from "path";
|
|
37470
37630
|
|
|
37471
37631
|
// ../lib/canonical-instant/src/index.ts
|
|
37472
37632
|
var CANONICAL_INSTANT_PATTERN = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z";
|
|
@@ -37504,7 +37664,7 @@ function percentile(sortedAsc, p) {
|
|
|
37504
37664
|
function auditConfigFile(accountDir) {
|
|
37505
37665
|
let cfg;
|
|
37506
37666
|
try {
|
|
37507
|
-
cfg = JSON.parse(
|
|
37667
|
+
cfg = JSON.parse(readFileSync58(join67(accountDir, "dispatch", "config.json"), "utf-8"));
|
|
37508
37668
|
} catch {
|
|
37509
37669
|
return null;
|
|
37510
37670
|
}
|
|
@@ -37529,7 +37689,7 @@ function auditConfigFile(accountDir) {
|
|
|
37529
37689
|
function terminalStatuses(accountDir) {
|
|
37530
37690
|
try {
|
|
37531
37691
|
const cfg = JSON.parse(
|
|
37532
|
-
|
|
37692
|
+
readFileSync58(join67(accountDir, "dispatch", "config.json"), "utf-8")
|
|
37533
37693
|
);
|
|
37534
37694
|
return {
|
|
37535
37695
|
job: (cfg.statuses?.job ?? []).filter((s) => s.terminal).map((s) => s.name),
|
|
@@ -37959,8 +38119,8 @@ function startGraphHealthTimer() {
|
|
|
37959
38119
|
}
|
|
37960
38120
|
|
|
37961
38121
|
// app/lib/shared-folder-census.ts
|
|
37962
|
-
import { existsSync as existsSync55, statSync as
|
|
37963
|
-
import { join as
|
|
38122
|
+
import { existsSync as existsSync55, statSync as statSync30, readdirSync as readdirSync33 } from "fs";
|
|
38123
|
+
import { join as join68 } from "path";
|
|
37964
38124
|
var import_dist17 = __toESM(require_dist(), 1);
|
|
37965
38125
|
var TAG69 = "[shared-census]";
|
|
37966
38126
|
var WIRED_SURFACES = 3;
|
|
@@ -37968,12 +38128,12 @@ function countFiles(dir) {
|
|
|
37968
38128
|
let n = 0;
|
|
37969
38129
|
let entries2;
|
|
37970
38130
|
try {
|
|
37971
|
-
entries2 =
|
|
38131
|
+
entries2 = readdirSync33(dir, { withFileTypes: true });
|
|
37972
38132
|
} catch {
|
|
37973
38133
|
return 0;
|
|
37974
38134
|
}
|
|
37975
38135
|
for (const e of entries2) {
|
|
37976
|
-
if (e.isDirectory()) n += countFiles(
|
|
38136
|
+
if (e.isDirectory()) n += countFiles(join68(dir, e.name));
|
|
37977
38137
|
else if (e.isFile()) n++;
|
|
37978
38138
|
}
|
|
37979
38139
|
return n;
|
|
@@ -37984,7 +38144,7 @@ function runSharedFolderCensus(dataRoot = DATA_ROOT) {
|
|
|
37984
38144
|
let isDir = false;
|
|
37985
38145
|
if (exists) {
|
|
37986
38146
|
try {
|
|
37987
|
-
isDir =
|
|
38147
|
+
isDir = statSync30(root).isDirectory();
|
|
37988
38148
|
} catch {
|
|
37989
38149
|
isDir = false;
|
|
37990
38150
|
}
|
|
@@ -38022,9 +38182,9 @@ function startAccountsStateCensus() {
|
|
|
38022
38182
|
}
|
|
38023
38183
|
|
|
38024
38184
|
// app/lib/cred-refresh-census.ts
|
|
38025
|
-
import { readdirSync as
|
|
38185
|
+
import { readdirSync as readdirSync34, readFileSync as readFileSync59 } from "fs";
|
|
38026
38186
|
import { homedir as homedir4 } from "os";
|
|
38027
|
-
import { join as
|
|
38187
|
+
import { join as join69 } from "path";
|
|
38028
38188
|
var TAG71 = "[claude-auth]";
|
|
38029
38189
|
function refreshTokenLength(raw) {
|
|
38030
38190
|
let data;
|
|
@@ -38040,7 +38200,7 @@ function refreshTokenLength(raw) {
|
|
|
38040
38200
|
function surveyBrandCredentials(home) {
|
|
38041
38201
|
let entries2;
|
|
38042
38202
|
try {
|
|
38043
|
-
entries2 =
|
|
38203
|
+
entries2 = readdirSync34(home);
|
|
38044
38204
|
} catch {
|
|
38045
38205
|
return [];
|
|
38046
38206
|
}
|
|
@@ -38049,7 +38209,7 @@ function surveyBrandCredentials(home) {
|
|
|
38049
38209
|
if (!entry3.startsWith(".")) continue;
|
|
38050
38210
|
let raw;
|
|
38051
38211
|
try {
|
|
38052
|
-
raw =
|
|
38212
|
+
raw = readFileSync59(join69(home, entry3, ".claude", ".credentials.json"), "utf-8");
|
|
38053
38213
|
} catch {
|
|
38054
38214
|
continue;
|
|
38055
38215
|
}
|
|
@@ -38311,7 +38471,7 @@ async function migrateUploads(opts = {}) {
|
|
|
38311
38471
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
38312
38472
|
import { readdir as readdir7, readFile as readFile13, rename as rename5, writeFile as writeFile4, unlink as unlink4 } from "fs/promises";
|
|
38313
38473
|
import { existsSync as existsSync56 } from "fs";
|
|
38314
|
-
import { join as
|
|
38474
|
+
import { join as join70 } from "path";
|
|
38315
38475
|
var ADMIN_ROLE2 = "admin";
|
|
38316
38476
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
38317
38477
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -38356,7 +38516,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
38356
38516
|
}
|
|
38357
38517
|
for (const slug of slugs) {
|
|
38358
38518
|
if (!slug.isDirectory()) continue;
|
|
38359
|
-
const slugDir =
|
|
38519
|
+
const slugDir = join70(projectsRoot, slug.name);
|
|
38360
38520
|
let entries2;
|
|
38361
38521
|
try {
|
|
38362
38522
|
entries2 = await readdir7(slugDir, { withFileTypes: true });
|
|
@@ -38365,9 +38525,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
38365
38525
|
}
|
|
38366
38526
|
for (const entry3 of entries2) {
|
|
38367
38527
|
if (entry3.isFile() && SESSION_META_RE.test(entry3.name)) {
|
|
38368
|
-
out.push(
|
|
38528
|
+
out.push(join70(slugDir, entry3.name));
|
|
38369
38529
|
} else if (entry3.isDirectory() && entry3.name === "subagents") {
|
|
38370
|
-
const subDir =
|
|
38530
|
+
const subDir = join70(slugDir, entry3.name);
|
|
38371
38531
|
let subs;
|
|
38372
38532
|
try {
|
|
38373
38533
|
subs = await readdir7(subDir, { withFileTypes: true });
|
|
@@ -38375,7 +38535,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
38375
38535
|
continue;
|
|
38376
38536
|
}
|
|
38377
38537
|
for (const s of subs) {
|
|
38378
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
38538
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join70(subDir, s.name));
|
|
38379
38539
|
}
|
|
38380
38540
|
}
|
|
38381
38541
|
}
|
|
@@ -38387,7 +38547,7 @@ function shortId(path) {
|
|
|
38387
38547
|
return base.slice(0, 8);
|
|
38388
38548
|
}
|
|
38389
38549
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
38390
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
38550
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join70(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
38391
38551
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
38392
38552
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
38393
38553
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -38464,7 +38624,7 @@ async function migrateAdminWebchatSidecars(opts = {}) {
|
|
|
38464
38624
|
// app/lib/migrate-sidecar-account-ids.ts
|
|
38465
38625
|
import { readdir as readdir8, readFile as readFile14, rename as rename6, writeFile as writeFile5, unlink as unlink5 } from "fs/promises";
|
|
38466
38626
|
import { existsSync as existsSync57 } from "fs";
|
|
38467
|
-
import { join as
|
|
38627
|
+
import { join as join71 } from "path";
|
|
38468
38628
|
var SESSION_META_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
38469
38629
|
function projectSlugForCwd(cwd) {
|
|
38470
38630
|
return cwd.replace(/\//g, "-");
|
|
@@ -38510,7 +38670,7 @@ async function collectSidecars(projectsRoot) {
|
|
|
38510
38670
|
}
|
|
38511
38671
|
for (const slug of slugs) {
|
|
38512
38672
|
if (!slug.isDirectory()) continue;
|
|
38513
|
-
const slugDir =
|
|
38673
|
+
const slugDir = join71(projectsRoot, slug.name);
|
|
38514
38674
|
let entries2;
|
|
38515
38675
|
try {
|
|
38516
38676
|
entries2 = await readdir8(slugDir, { withFileTypes: true });
|
|
@@ -38519,9 +38679,9 @@ async function collectSidecars(projectsRoot) {
|
|
|
38519
38679
|
}
|
|
38520
38680
|
for (const entry3 of entries2) {
|
|
38521
38681
|
if (entry3.isFile() && SESSION_META_RE2.test(entry3.name)) {
|
|
38522
|
-
out.push({ path:
|
|
38682
|
+
out.push({ path: join71(slugDir, entry3.name), slug: slug.name });
|
|
38523
38683
|
} else if (entry3.isDirectory() && (entry3.name === "subagents" || entry3.name === "archive")) {
|
|
38524
|
-
const subDir =
|
|
38684
|
+
const subDir = join71(slugDir, entry3.name);
|
|
38525
38685
|
let subs;
|
|
38526
38686
|
try {
|
|
38527
38687
|
subs = await readdir8(subDir, { withFileTypes: true });
|
|
@@ -38530,7 +38690,7 @@ async function collectSidecars(projectsRoot) {
|
|
|
38530
38690
|
}
|
|
38531
38691
|
for (const s of subs) {
|
|
38532
38692
|
if (s.isFile() && SESSION_META_RE2.test(s.name)) {
|
|
38533
|
-
out.push({ path:
|
|
38693
|
+
out.push({ path: join71(subDir, s.name), slug: slug.name });
|
|
38534
38694
|
}
|
|
38535
38695
|
}
|
|
38536
38696
|
}
|
|
@@ -38539,7 +38699,7 @@ async function collectSidecars(projectsRoot) {
|
|
|
38539
38699
|
return out;
|
|
38540
38700
|
}
|
|
38541
38701
|
async function migrateSidecarAccountIds(opts = {}) {
|
|
38542
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
38702
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join71(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
38543
38703
|
const accounts = opts.accounts ?? listValidAccounts();
|
|
38544
38704
|
const result = {
|
|
38545
38705
|
scanned: 0,
|
|
@@ -40162,8 +40322,8 @@ function createWebchatChannelRoutes(deps) {
|
|
|
40162
40322
|
}
|
|
40163
40323
|
|
|
40164
40324
|
// app/lib/webchat/gateway/resolve-turn-answer.ts
|
|
40165
|
-
import { existsSync as existsSync58, openSync as
|
|
40166
|
-
import { join as
|
|
40325
|
+
import { existsSync as existsSync58, openSync as openSync10, readSync as readSync9, closeSync as closeSync10, readdirSync as readdirSync35 } from "fs";
|
|
40326
|
+
import { join as join72 } from "path";
|
|
40167
40327
|
|
|
40168
40328
|
// app/lib/channel-delivery/outbound-guard.ts
|
|
40169
40329
|
var INTERNAL_LEAK_PATTERNS = [
|
|
@@ -40205,13 +40365,13 @@ function resolveTurnAnswer(p) {
|
|
|
40205
40365
|
if (!(length > 0)) return "";
|
|
40206
40366
|
let text;
|
|
40207
40367
|
try {
|
|
40208
|
-
const fd =
|
|
40368
|
+
const fd = openSync10(path, "r");
|
|
40209
40369
|
try {
|
|
40210
40370
|
const buf = Buffer.alloc(length);
|
|
40211
|
-
|
|
40371
|
+
readSync9(fd, buf, 0, length, p.segmentStart);
|
|
40212
40372
|
text = buf.toString("utf8");
|
|
40213
40373
|
} finally {
|
|
40214
|
-
|
|
40374
|
+
closeSync10(fd);
|
|
40215
40375
|
}
|
|
40216
40376
|
} catch {
|
|
40217
40377
|
return "";
|
|
@@ -40227,12 +40387,12 @@ function findJsonl(projectsRoot, sessionId) {
|
|
|
40227
40387
|
if (!existsSync58(projectsRoot)) return null;
|
|
40228
40388
|
let slugs;
|
|
40229
40389
|
try {
|
|
40230
|
-
slugs =
|
|
40390
|
+
slugs = readdirSync35(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
40231
40391
|
} catch {
|
|
40232
40392
|
return null;
|
|
40233
40393
|
}
|
|
40234
40394
|
for (const slug of slugs) {
|
|
40235
|
-
const live =
|
|
40395
|
+
const live = join72(projectsRoot, slug, `${sessionId}.jsonl`);
|
|
40236
40396
|
if (existsSync58(live)) return live;
|
|
40237
40397
|
}
|
|
40238
40398
|
return null;
|
|
@@ -41614,21 +41774,21 @@ function refusalNoticeText(reason) {
|
|
|
41614
41774
|
}
|
|
41615
41775
|
async function sendRefusalNotice(input) {
|
|
41616
41776
|
if (notified.has(input.doorId)) return;
|
|
41617
|
-
const
|
|
41777
|
+
const fields2 = `channel=${input.channel} sender=${input.sender} reason=${input.reason}`;
|
|
41618
41778
|
if (!input.send) {
|
|
41619
|
-
console.error(`${TAG74} op=refusal-notice-failed ${
|
|
41779
|
+
console.error(`${TAG74} op=refusal-notice-failed ${fields2} error=no-target`);
|
|
41620
41780
|
return;
|
|
41621
41781
|
}
|
|
41622
41782
|
try {
|
|
41623
41783
|
await input.send(guardOutbound(input.sender, refusalNoticeText(input.reason)));
|
|
41624
41784
|
} catch (e) {
|
|
41625
41785
|
console.error(
|
|
41626
|
-
`${TAG74} op=refusal-notice-failed ${
|
|
41786
|
+
`${TAG74} op=refusal-notice-failed ${fields2} error=${e instanceof Error ? e.message : String(e)}`
|
|
41627
41787
|
);
|
|
41628
41788
|
return;
|
|
41629
41789
|
}
|
|
41630
41790
|
notified.add(input.doorId);
|
|
41631
|
-
console.error(`${TAG74} op=refusal-notice ${
|
|
41791
|
+
console.error(`${TAG74} op=refusal-notice ${fields2} status=${input.status}`);
|
|
41632
41792
|
}
|
|
41633
41793
|
function clearRefusalNotice(doorId) {
|
|
41634
41794
|
notified.delete(doorId);
|
|
@@ -42635,7 +42795,7 @@ var sessions3 = /* @__PURE__ */ new Map();
|
|
|
42635
42795
|
function entry2(sessionId) {
|
|
42636
42796
|
let e = sessions3.get(sessionId);
|
|
42637
42797
|
if (!e) {
|
|
42638
|
-
e = { armed: 0, suppressed: 0, delivered: 0
|
|
42798
|
+
e = { armed: 0, suppressed: 0, delivered: 0 };
|
|
42639
42799
|
sessions3.set(sessionId, e);
|
|
42640
42800
|
}
|
|
42641
42801
|
return e;
|
|
@@ -42650,59 +42810,23 @@ function noteCardDelivered(sessionId) {
|
|
|
42650
42810
|
const e = sessions3.get(sessionId);
|
|
42651
42811
|
if (e && e.armed > 0) e.delivered += 1;
|
|
42652
42812
|
}
|
|
42653
|
-
function noteCardPersisted(sessionId) {
|
|
42654
|
-
entry2(sessionId).persisted += 1;
|
|
42655
|
-
}
|
|
42656
|
-
function noteCardSent(sessionId) {
|
|
42657
|
-
entry2(sessionId).sent += 1;
|
|
42658
|
-
}
|
|
42659
|
-
function noteCardCrossChat(sessionId) {
|
|
42660
|
-
entry2(sessionId).crossChat += 1;
|
|
42661
|
-
}
|
|
42662
42813
|
function cardCensusLines() {
|
|
42663
42814
|
let armed3 = 0;
|
|
42664
42815
|
let suppressed = 0;
|
|
42665
42816
|
let delivered = 0;
|
|
42666
|
-
let persisted = 0;
|
|
42667
|
-
let sent = 0;
|
|
42668
|
-
let crossChat = 0;
|
|
42669
42817
|
for (const e of sessions3.values()) {
|
|
42670
42818
|
armed3 += e.armed;
|
|
42671
42819
|
suppressed += e.suppressed;
|
|
42672
42820
|
delivered += e.delivered;
|
|
42673
|
-
persisted += e.persisted;
|
|
42674
|
-
sent += e.sent;
|
|
42675
|
-
crossChat += e.crossChat;
|
|
42676
42821
|
}
|
|
42677
42822
|
const silent = Math.max(0, armed3 - suppressed - delivered);
|
|
42678
42823
|
return [
|
|
42679
|
-
`[telegram-card-suppression-census] sessions=${sessions3.size} armed=${armed3} suppressed=${suppressed} silent-turns=${silent}
|
|
42824
|
+
`[telegram-card-suppression-census] sessions=${sessions3.size} armed=${armed3} suppressed=${suppressed} silent-turns=${silent}`
|
|
42680
42825
|
];
|
|
42681
42826
|
}
|
|
42682
42827
|
|
|
42683
42828
|
// app/lib/telegram/gateway/native-file-follower.ts
|
|
42684
42829
|
var TELEGRAM_CARD_TOOL = "mcp__telegram__telegram-card";
|
|
42685
|
-
var CARD_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
42686
|
-
"mcp__telegram__telegram-card",
|
|
42687
|
-
"mcp__plugin_telegram_telegram__telegram-card"
|
|
42688
|
-
]);
|
|
42689
|
-
var CARD_RESULT_RE = /card-result: outcome=(sent|edited|unchanged|none) messageId=(\d+|none)(?: botId=(-?\d+) chatId=(-?\d+))?/;
|
|
42690
|
-
function parseCardButtons(input) {
|
|
42691
|
-
const rows = input?.buttons;
|
|
42692
|
-
if (!Array.isArray(rows)) return [];
|
|
42693
|
-
const out = [];
|
|
42694
|
-
for (const row of rows) {
|
|
42695
|
-
if (!Array.isArray(row)) continue;
|
|
42696
|
-
for (const b of row) {
|
|
42697
|
-
if (!b || typeof b !== "object") continue;
|
|
42698
|
-
const text = b.text;
|
|
42699
|
-
if (typeof text !== "string") continue;
|
|
42700
|
-
const data = b.callbackData;
|
|
42701
|
-
out.push({ text, data: typeof data === "string" ? data : null });
|
|
42702
|
-
}
|
|
42703
|
-
}
|
|
42704
|
-
return out;
|
|
42705
|
-
}
|
|
42706
42830
|
var CHAT_ACTION_REFRESH_MS = 4e3;
|
|
42707
42831
|
function startTelegramNativeFileFollower(input) {
|
|
42708
42832
|
const entry3 = {
|
|
@@ -42723,9 +42847,7 @@ function startTelegramNativeFileFollower(input) {
|
|
|
42723
42847
|
// The chat id the document is addressed to (set per spawn from the inbound).
|
|
42724
42848
|
replyTarget: input.chatId
|
|
42725
42849
|
};
|
|
42726
|
-
const pendingCards = /* @__PURE__ */ new Map();
|
|
42727
42850
|
const channelKey = input.senderId;
|
|
42728
|
-
const numericSenderId = parseTelegramChannelKey(channelKey)?.senderId ?? input.chatId;
|
|
42729
42851
|
let lastChatActionAt = Number.NEGATIVE_INFINITY;
|
|
42730
42852
|
let turnOpen = false;
|
|
42731
42853
|
let cardSentThisTurn = false;
|
|
@@ -42814,13 +42936,6 @@ function startTelegramNativeFileFollower(input) {
|
|
|
42814
42936
|
// before it reaches the optional answerCallbackQuery, so there is no card
|
|
42815
42937
|
// call that posts nothing and no bare acknowledgement to keep the text for.
|
|
42816
42938
|
onToolUse: (tool) => {
|
|
42817
|
-
if (CARD_TOOL_NAMES.has(tool.name) && tool.id) {
|
|
42818
|
-
const text = tool.input?.text;
|
|
42819
|
-
pendingCards.set(tool.id, {
|
|
42820
|
-
text: typeof text === "string" ? text : "",
|
|
42821
|
-
buttons: parseCardButtons(tool.input)
|
|
42822
|
-
});
|
|
42823
|
-
}
|
|
42824
42939
|
if (tool.name !== TELEGRAM_CARD_TOOL) return;
|
|
42825
42940
|
cardSentThisTurn = true;
|
|
42826
42941
|
noteCardArmed(input.sessionId);
|
|
@@ -42828,75 +42943,6 @@ function startTelegramNativeFileFollower(input) {
|
|
|
42828
42943
|
`[telegram-public] op=card-armed sessionId=${input.sessionId.slice(0, 8)} tool=${tool.name}`
|
|
42829
42944
|
);
|
|
42830
42945
|
},
|
|
42831
|
-
// Task 2677 — the card's send outcome and message id arrive here, parsed out
|
|
42832
|
-
// of the result text card.ts encoded them into. On a confirmed send write one
|
|
42833
|
-
// outbound store row keyed by the card message id; on an edit patch that same
|
|
42834
|
-
// row (Telegram reuses the id for an edit); unchanged/none write nothing.
|
|
42835
|
-
onToolResult: ({ toolUseId, text }) => {
|
|
42836
|
-
const pending = pendingCards.get(toolUseId);
|
|
42837
|
-
if (!pending) return;
|
|
42838
|
-
pendingCards.delete(toolUseId);
|
|
42839
|
-
const m = CARD_RESULT_RE.exec(text);
|
|
42840
|
-
if (!m) return;
|
|
42841
|
-
const outcome = m[1];
|
|
42842
|
-
const messageId = m[2];
|
|
42843
|
-
if (outcome !== "sent" && outcome !== "edited" || messageId === "none") return;
|
|
42844
|
-
noteCardSent(input.sessionId);
|
|
42845
|
-
const destBot = m[3];
|
|
42846
|
-
const destChat = m[4];
|
|
42847
|
-
const follower = parseTelegramChannelKey(channelKey);
|
|
42848
|
-
let destKey = channelKey;
|
|
42849
|
-
let rowChat = input.chatId;
|
|
42850
|
-
let rowSender = numericSenderId;
|
|
42851
|
-
if (destBot === void 0 || destChat === void 0) {
|
|
42852
|
-
console.error(
|
|
42853
|
-
`[telegram-adaptor] op=card-destination-absent sessionId=${input.sessionId.slice(0, 8)} toolUseId=${toolUseId} follower=${channelKey}`
|
|
42854
|
-
);
|
|
42855
|
-
} else if (follower?.business === true && follower.botId === destBot && follower.senderId === destChat) {
|
|
42856
|
-
rowChat = destChat;
|
|
42857
|
-
rowSender = destChat;
|
|
42858
|
-
} else {
|
|
42859
|
-
destKey = `${destBot}:${destChat}`;
|
|
42860
|
-
rowChat = destChat;
|
|
42861
|
-
rowSender = destChat;
|
|
42862
|
-
}
|
|
42863
|
-
if (destKey !== channelKey) noteCardCrossChat(input.sessionId);
|
|
42864
|
-
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
42865
|
-
const rowId = `telegram:${input.accountId}:${destKey}:card:${messageId}`;
|
|
42866
|
-
let created;
|
|
42867
|
-
if (outcome === "sent") {
|
|
42868
|
-
created = appendMessage2(input.accountId, {
|
|
42869
|
-
messageId: rowId,
|
|
42870
|
-
sessionId: input.sessionId,
|
|
42871
|
-
dateSent: at,
|
|
42872
|
-
body: pending.text,
|
|
42873
|
-
fromMe: true,
|
|
42874
|
-
senderId: rowSender,
|
|
42875
|
-
senderName: null,
|
|
42876
|
-
chatId: rowChat,
|
|
42877
|
-
channelKey: destKey,
|
|
42878
|
-
// Telegram row scope is not consumed for rendering or routing (only
|
|
42879
|
-
// WhatsApp rows feed the operator-conversations scope counter); 'admin'
|
|
42880
|
-
// matches the operator-surface intent of the card row.
|
|
42881
|
-
scope: "admin",
|
|
42882
|
-
origin: "agent",
|
|
42883
|
-
...pending.buttons.length > 0 ? { buttons: pending.buttons } : {},
|
|
42884
|
-
createdAt: at
|
|
42885
|
-
}).created;
|
|
42886
|
-
} else {
|
|
42887
|
-
created = appendUpdate(input.accountId, destKey, {
|
|
42888
|
-
kind: "update",
|
|
42889
|
-
targetMessageId: rowId,
|
|
42890
|
-
body: pending.text,
|
|
42891
|
-
...pending.buttons.length > 0 ? { buttons: pending.buttons } : {},
|
|
42892
|
-
createdAt: at
|
|
42893
|
-
}).created;
|
|
42894
|
-
}
|
|
42895
|
-
if (created) noteCardPersisted(input.sessionId);
|
|
42896
|
-
console.error(
|
|
42897
|
-
`[telegram-adaptor] op=${created ? "card-persisted" : "card-persist-refused"} sessionId=${input.sessionId.slice(0, 8)} messageId=${messageId} outcome=${outcome} buttons=${pending.buttons.length} channelKey=${destKey} follower=${channelKey}`
|
|
42898
|
-
);
|
|
42899
|
-
},
|
|
42900
42946
|
// Task 2521 — the answer reaches every bound door through the one fan-out.
|
|
42901
42947
|
// Ungated by design: whatever woke the turn, the reader and the chats show
|
|
42902
42948
|
// the same thing. Task 2666 adds the one exception above.
|
|
@@ -42936,15 +42982,15 @@ function startTelegramNativeFileFollower(input) {
|
|
|
42936
42982
|
}
|
|
42937
42983
|
|
|
42938
42984
|
// server/telegram-background-active.ts
|
|
42939
|
-
import { join as
|
|
42940
|
-
import { readdirSync as
|
|
42985
|
+
import { join as join73, resolve as resolve52 } from "path";
|
|
42986
|
+
import { readdirSync as readdirSync36, statSync as statSync31 } from "fs";
|
|
42941
42987
|
var SUBAGENT_STALE_WINDOW_MS = 6e4;
|
|
42942
42988
|
var AGENT_JSONL_RE2 = /^agent-([0-9a-f]+)\.jsonl$/;
|
|
42943
42989
|
function makeBackgroundActive(sessionId, deps = {}) {
|
|
42944
42990
|
const findProjectDir = deps.findProjectDir ?? findSessionProjectDir;
|
|
42945
|
-
const readDir = deps.readDir ?? ((d) =>
|
|
42991
|
+
const readDir = deps.readDir ?? ((d) => readdirSync36(d));
|
|
42946
42992
|
const statFile = deps.statFile ?? ((p) => {
|
|
42947
|
-
const st =
|
|
42993
|
+
const st = statSync31(p);
|
|
42948
42994
|
return { size: st.size, mtimeMs: st.mtimeMs };
|
|
42949
42995
|
});
|
|
42950
42996
|
const now = deps.now ?? (() => Date.now());
|
|
@@ -42955,7 +43001,7 @@ function makeBackgroundActive(sessionId, deps = {}) {
|
|
|
42955
43001
|
if (subagentsDir === null) {
|
|
42956
43002
|
const projectDir = findProjectDir(sessionId);
|
|
42957
43003
|
if (projectDir === null) return false;
|
|
42958
|
-
subagentsDir = resolve52(
|
|
43004
|
+
subagentsDir = resolve52(join73(projectDir, sessionId, "subagents"));
|
|
42959
43005
|
}
|
|
42960
43006
|
let names;
|
|
42961
43007
|
try {
|
|
@@ -42969,7 +43015,7 @@ function makeBackgroundActive(sessionId, deps = {}) {
|
|
|
42969
43015
|
let size;
|
|
42970
43016
|
let mtimeMs;
|
|
42971
43017
|
try {
|
|
42972
|
-
const st = statFile(
|
|
43018
|
+
const st = statFile(join73(subagentsDir, name));
|
|
42973
43019
|
size = st.size;
|
|
42974
43020
|
mtimeMs = st.mtimeMs;
|
|
42975
43021
|
} catch {
|
|
@@ -43289,9 +43335,9 @@ function warnOnChannelAdminBindingDrift() {
|
|
|
43289
43335
|
);
|
|
43290
43336
|
}
|
|
43291
43337
|
for (const d of drift) {
|
|
43292
|
-
const
|
|
43338
|
+
const tail2 = d.reason === "userid-not-admin" ? ` userId=${d.userId}` : "";
|
|
43293
43339
|
console.error(
|
|
43294
|
-
`[admin-identity] binding-drift accountId=${acct.accountId} phone=${d.phone} reason=${d.reason}${
|
|
43340
|
+
`[admin-identity] binding-drift accountId=${acct.accountId} phone=${d.phone} reason=${d.reason}${tail2}`
|
|
43295
43341
|
);
|
|
43296
43342
|
}
|
|
43297
43343
|
const managerDrift = findAccountManagerDrift(readAccountManagers(acct.accountDir), validAccountIds);
|
|
@@ -43335,8 +43381,8 @@ function runPublicAddressCollisionAudit(deps) {
|
|
|
43335
43381
|
}
|
|
43336
43382
|
|
|
43337
43383
|
// server/telegram-audit.ts
|
|
43338
|
-
import { statSync as
|
|
43339
|
-
import { join as
|
|
43384
|
+
import { statSync as statSync32 } from "fs";
|
|
43385
|
+
import { join as join74 } from "path";
|
|
43340
43386
|
function buildTelegramAuditLines(input) {
|
|
43341
43387
|
const lines = [];
|
|
43342
43388
|
const entries2 = input.accounts.flatMap(
|
|
@@ -43444,19 +43490,19 @@ function countTelegramSessionsForAccount(accountId) {
|
|
|
43444
43490
|
function* walkTelegramSidecars() {
|
|
43445
43491
|
const cfg = claudeConfigDir();
|
|
43446
43492
|
if (!cfg) return;
|
|
43447
|
-
const projectsRoot =
|
|
43493
|
+
const projectsRoot = join74(cfg, "projects");
|
|
43448
43494
|
for (const { path } of enumerateSessionSidecars(projectsRoot)) {
|
|
43449
43495
|
const meta = readSidecarMeta(path);
|
|
43450
43496
|
if (meta.channel !== "telegram" || !meta.accountId) continue;
|
|
43451
43497
|
let spawnMs;
|
|
43452
43498
|
try {
|
|
43453
|
-
spawnMs =
|
|
43499
|
+
spawnMs = statSync32(path).mtimeMs;
|
|
43454
43500
|
} catch {
|
|
43455
43501
|
continue;
|
|
43456
43502
|
}
|
|
43457
43503
|
let turnMs;
|
|
43458
43504
|
try {
|
|
43459
|
-
turnMs =
|
|
43505
|
+
turnMs = statSync32(path.replace(/\.meta\.json$/, ".jsonl")).mtimeMs;
|
|
43460
43506
|
} catch {
|
|
43461
43507
|
turnMs = null;
|
|
43462
43508
|
}
|
|
@@ -43656,8 +43702,8 @@ function businessConnectionCensusLine(c) {
|
|
|
43656
43702
|
}
|
|
43657
43703
|
|
|
43658
43704
|
// app/lib/telegram/business-window-census.ts
|
|
43659
|
-
import { readdirSync as
|
|
43660
|
-
import { join as
|
|
43705
|
+
import { readdirSync as readdirSync37, existsSync as existsSync59 } from "fs";
|
|
43706
|
+
import { join as join75 } from "path";
|
|
43661
43707
|
var BUSINESS_WINDOW_CENSUS_TAG = "[telegram-audit]";
|
|
43662
43708
|
var EXPIRING_SOON_S = 3600;
|
|
43663
43709
|
function collectBusinessWindowCensus(input) {
|
|
@@ -43685,11 +43731,11 @@ function businessWindowCensusLine(c) {
|
|
|
43685
43731
|
function readBusinessChatClocks(accountIds) {
|
|
43686
43732
|
const out = [];
|
|
43687
43733
|
for (const accountId of accountIds) {
|
|
43688
|
-
const dir =
|
|
43734
|
+
const dir = join75(STORE_ROOT2(), accountId);
|
|
43689
43735
|
if (!existsSync59(dir)) continue;
|
|
43690
43736
|
let names;
|
|
43691
43737
|
try {
|
|
43692
|
-
names =
|
|
43738
|
+
names = readdirSync37(dir);
|
|
43693
43739
|
} catch {
|
|
43694
43740
|
continue;
|
|
43695
43741
|
}
|
|
@@ -43747,15 +43793,15 @@ async function getTelegramBusinessConnection(botToken, connectionId, opts = {})
|
|
|
43747
43793
|
}
|
|
43748
43794
|
|
|
43749
43795
|
// server/telegram-migrate.ts
|
|
43750
|
-
import { readFileSync as
|
|
43751
|
-
import { dirname as dirname19, join as
|
|
43796
|
+
import { readFileSync as readFileSync60, writeFileSync as writeFileSync23, existsSync as existsSync60, renameSync as renameSync11, mkdirSync as mkdirSync14 } from "fs";
|
|
43797
|
+
import { dirname as dirname19, join as join76 } from "path";
|
|
43752
43798
|
function migrateTelegramTwoSlot(input) {
|
|
43753
43799
|
const out = [];
|
|
43754
43800
|
for (const account of input.accounts) {
|
|
43755
|
-
const configPath3 =
|
|
43801
|
+
const configPath3 = join76(account.accountDir, "account.json");
|
|
43756
43802
|
let config;
|
|
43757
43803
|
try {
|
|
43758
|
-
config = JSON.parse(
|
|
43804
|
+
config = JSON.parse(readFileSync60(configPath3, "utf-8"));
|
|
43759
43805
|
} catch {
|
|
43760
43806
|
console.error(`[telegram-audit] op=migrate-unreadable accountId=${account.accountId}`);
|
|
43761
43807
|
continue;
|
|
@@ -43814,16 +43860,16 @@ function moveSecret(from, to) {
|
|
|
43814
43860
|
}
|
|
43815
43861
|
|
|
43816
43862
|
// server/telegram-unadopt.ts
|
|
43817
|
-
import { readFileSync as
|
|
43818
|
-
import { join as
|
|
43863
|
+
import { readFileSync as readFileSync61, writeFileSync as writeFileSync24, renameSync as renameSync12 } from "fs";
|
|
43864
|
+
import { join as join77 } from "path";
|
|
43819
43865
|
var FILE3 = "channel-session-override.json";
|
|
43820
43866
|
function unadoptTelegramPointers(input) {
|
|
43821
43867
|
return input.accounts.map(({ accountId, accountDir }) => {
|
|
43822
43868
|
const out = { accountId, dropped: [], kept: 0, unknown: 0 };
|
|
43823
|
-
const path =
|
|
43869
|
+
const path = join77(accountDir, FILE3);
|
|
43824
43870
|
const bySender = {};
|
|
43825
43871
|
try {
|
|
43826
|
-
const raw = JSON.parse(
|
|
43872
|
+
const raw = JSON.parse(readFileSync61(path, "utf8"));
|
|
43827
43873
|
if (!raw.bySender || typeof raw.bySender !== "object") return out;
|
|
43828
43874
|
for (const [k, v] of Object.entries(raw.bySender)) if (typeof v === "string") bySender[k] = v;
|
|
43829
43875
|
} catch {
|
|
@@ -43894,14 +43940,14 @@ function backfillMisfiledRecords(params) {
|
|
|
43894
43940
|
}
|
|
43895
43941
|
|
|
43896
43942
|
// server/lib/booking-site-accounts.ts
|
|
43897
|
-
import { existsSync as existsSync61, readFileSync as
|
|
43943
|
+
import { existsSync as existsSync61, readFileSync as readFileSync62 } from "fs";
|
|
43898
43944
|
import { resolve as resolve53 } from "path";
|
|
43899
43945
|
function listBookingSiteAccounts(accounts) {
|
|
43900
43946
|
return accounts.filter((a) => {
|
|
43901
43947
|
const availPath = resolve53(a.accountDir, "calendar-availability.json");
|
|
43902
43948
|
if (!existsSync61(availPath)) return false;
|
|
43903
43949
|
try {
|
|
43904
|
-
const cfg = JSON.parse(
|
|
43950
|
+
const cfg = JSON.parse(readFileSync62(availPath, "utf-8"));
|
|
43905
43951
|
return typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
43906
43952
|
} catch {
|
|
43907
43953
|
return false;
|
|
@@ -43939,7 +43985,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
43939
43985
|
|
|
43940
43986
|
// ../lib/entitlement/src/index.ts
|
|
43941
43987
|
import { createPublicKey, createHash as createHash7, verify as cryptoVerify } from "crypto";
|
|
43942
|
-
import { existsSync as existsSync62, readFileSync as
|
|
43988
|
+
import { existsSync as existsSync62, readFileSync as readFileSync63, statSync as statSync33 } from "fs";
|
|
43943
43989
|
import { resolve as resolve54 } from "path";
|
|
43944
43990
|
|
|
43945
43991
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -43991,7 +44037,7 @@ function resolveEntitlement(brand, account) {
|
|
|
43991
44037
|
if (!existsSync62(entitlementPath)) {
|
|
43992
44038
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
43993
44039
|
}
|
|
43994
|
-
const stat11 =
|
|
44040
|
+
const stat11 = statSync33(entitlementPath);
|
|
43995
44041
|
const key2 = memoKey(stat11.mtimeMs, account);
|
|
43996
44042
|
if (memo && memo.key === key2) {
|
|
43997
44043
|
return memo.result;
|
|
@@ -44003,7 +44049,7 @@ function resolveEntitlement(brand, account) {
|
|
|
44003
44049
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
44004
44050
|
let pubkeyPem;
|
|
44005
44051
|
try {
|
|
44006
|
-
pubkeyPem =
|
|
44052
|
+
pubkeyPem = readFileSync63(pubkeyPath(brand), "utf-8");
|
|
44007
44053
|
} catch (err) {
|
|
44008
44054
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
44009
44055
|
reason: "pubkey-missing"
|
|
@@ -44017,7 +44063,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
44017
44063
|
}
|
|
44018
44064
|
let envelope;
|
|
44019
44065
|
try {
|
|
44020
|
-
envelope = JSON.parse(
|
|
44066
|
+
envelope = JSON.parse(readFileSync63(entitlementPath, "utf-8"));
|
|
44021
44067
|
} catch {
|
|
44022
44068
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
44023
44069
|
}
|
|
@@ -44179,14 +44225,14 @@ function clientFrom(c) {
|
|
|
44179
44225
|
}
|
|
44180
44226
|
installMediaDownloadGuard();
|
|
44181
44227
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
44182
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT6 ?
|
|
44228
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join78(PLATFORM_ROOT6, "config", "brand.json") : "";
|
|
44183
44229
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
44184
44230
|
if (BRAND_JSON_PATH && !existsSync63(BRAND_JSON_PATH)) {
|
|
44185
44231
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
44186
44232
|
}
|
|
44187
44233
|
if (BRAND_JSON_PATH && existsSync63(BRAND_JSON_PATH)) {
|
|
44188
44234
|
try {
|
|
44189
|
-
const parsed = JSON.parse(
|
|
44235
|
+
const parsed = JSON.parse(readFileSync64(BRAND_JSON_PATH, "utf-8"));
|
|
44190
44236
|
BRAND = { ...BRAND, ...parsed };
|
|
44191
44237
|
} catch (err) {
|
|
44192
44238
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -44218,11 +44264,11 @@ var brandLoginOpts = {
|
|
|
44218
44264
|
appleTouchIconPath: brandAppIcon512Path,
|
|
44219
44265
|
themeColor: BRAND.defaultColors?.primary
|
|
44220
44266
|
};
|
|
44221
|
-
var ALIAS_DOMAINS_PATH =
|
|
44267
|
+
var ALIAS_DOMAINS_PATH = join78(homedir5(), BRAND.configDir, "alias-domains.json");
|
|
44222
44268
|
function loadAliasDomains() {
|
|
44223
44269
|
try {
|
|
44224
44270
|
if (!existsSync63(ALIAS_DOMAINS_PATH)) return null;
|
|
44225
|
-
const parsed = JSON.parse(
|
|
44271
|
+
const parsed = JSON.parse(readFileSync64(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
44226
44272
|
if (!Array.isArray(parsed)) {
|
|
44227
44273
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
44228
44274
|
return null;
|
|
@@ -44364,7 +44410,7 @@ var waGateway = new WaGateway({
|
|
|
44364
44410
|
// resolver and `fanTargetsFor` is a constructor dep, not a callable method.
|
|
44365
44411
|
fanTargetsFor: whatsappFanTargets,
|
|
44366
44412
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
44367
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve55(process.env.MAXY_PLATFORM_ROOT ??
|
|
44413
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve55(process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
44368
44414
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
44369
44415
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
44370
44416
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -44379,7 +44425,7 @@ var waGateway = new WaGateway({
|
|
|
44379
44425
|
caption,
|
|
44380
44426
|
accountId,
|
|
44381
44427
|
maxyAccountId,
|
|
44382
|
-
platformRoot: resolve55(process.env.MAXY_PLATFORM_ROOT ??
|
|
44428
|
+
platformRoot: resolve55(process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, ".."))
|
|
44383
44429
|
});
|
|
44384
44430
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
44385
44431
|
},
|
|
@@ -44554,7 +44600,7 @@ function runDuplicateSenderAudit() {
|
|
|
44554
44600
|
try {
|
|
44555
44601
|
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
44556
44602
|
if (!configDir) return;
|
|
44557
|
-
const projectsRoot =
|
|
44603
|
+
const projectsRoot = join78(configDir, "projects");
|
|
44558
44604
|
const records5 = [];
|
|
44559
44605
|
for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
|
|
44560
44606
|
if (isSubagent || archived) continue;
|
|
@@ -44606,7 +44652,7 @@ var webchatGateway = new WebchatGateway({
|
|
|
44606
44652
|
// rather than hanging the POST.
|
|
44607
44653
|
publicProjectsRoot: () => {
|
|
44608
44654
|
const cfg = claudeConfigDir();
|
|
44609
|
-
return cfg ?
|
|
44655
|
+
return cfg ? join78(cfg, "projects") : "";
|
|
44610
44656
|
},
|
|
44611
44657
|
gatewayUrl: webchatGatewayUrl(),
|
|
44612
44658
|
serverPath: webchatServerPath(),
|
|
@@ -44876,6 +44922,32 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
44876
44922
|
if (hits.length === 0) return { kind: "none" };
|
|
44877
44923
|
if (hits.length > 1) return { kind: "ambiguous", claimants: hits };
|
|
44878
44924
|
return { kind: "one", ...hits[0] };
|
|
44925
|
+
},
|
|
44926
|
+
// Task 2776 — the carrier a routine NAMED, resolved against that account's own
|
|
44927
|
+
// bots and never install-wide. The verdict comes from `carrierVerdict`, the
|
|
44928
|
+
// same function `validateAgentDispatch` calls at write time, so a bot that
|
|
44929
|
+
// saved cannot be refused here for a reason the save would not have given.
|
|
44930
|
+
//
|
|
44931
|
+
// The token and allowlists are read off the entry this lookup just chose, for
|
|
44932
|
+
// the reason the resolver above states about its own: a second read of the
|
|
44933
|
+
// registry could disagree with the entry chosen.
|
|
44934
|
+
//
|
|
44935
|
+
// `absent` covers the two ways an entry can be missing — no such account, and
|
|
44936
|
+
// no such bot on it — because both mean the same thing to the operator: the id
|
|
44937
|
+
// this routine names is not a bot they can dispatch on.
|
|
44938
|
+
carrierFor: (accountId, botId, destination) => {
|
|
44939
|
+
const account = listValidAccounts().find((a) => a.accountId === accountId);
|
|
44940
|
+
if (!account) return { error: "absent" };
|
|
44941
|
+
const verdict = carrierVerdict(account.accountDir, botId, destination);
|
|
44942
|
+
if (!verdict.ok) return { error: verdict.reason };
|
|
44943
|
+
const entry3 = listBotEntries(account.config.telegram).find((e) => e.id === botId);
|
|
44944
|
+
if (!entry3) return { error: "absent" };
|
|
44945
|
+
return {
|
|
44946
|
+
accountId: account.accountId,
|
|
44947
|
+
botId,
|
|
44948
|
+
botToken: entry3.token,
|
|
44949
|
+
...chatSendAllowlists(entry3)
|
|
44950
|
+
};
|
|
44879
44951
|
}
|
|
44880
44952
|
// Task 2078 — the same binding the live inbound resolves. Without it a
|
|
44881
44953
|
// scheduled dispatch to a BOUND admin would derive the legacy per-chat id and
|
|
@@ -45280,7 +45352,7 @@ app80.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
45280
45352
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
45281
45353
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
45282
45354
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
45283
|
-
const body =
|
|
45355
|
+
const body = readFileSync64(filePath);
|
|
45284
45356
|
return c.body(body, 200, {
|
|
45285
45357
|
"Content-Type": contentType,
|
|
45286
45358
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -45310,7 +45382,7 @@ app80.get("/generated/:filename", (c) => {
|
|
|
45310
45382
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
45311
45383
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
45312
45384
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
45313
|
-
const body =
|
|
45385
|
+
const body = readFileSync64(filePath);
|
|
45314
45386
|
return c.body(body, 200, {
|
|
45315
45387
|
"Content-Type": contentType,
|
|
45316
45388
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -45325,7 +45397,7 @@ var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
|
45325
45397
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
45326
45398
|
if (BRAND_JSON_PATH && existsSync63(BRAND_JSON_PATH)) {
|
|
45327
45399
|
try {
|
|
45328
|
-
const fullBrand = JSON.parse(
|
|
45400
|
+
const fullBrand = JSON.parse(readFileSync64(BRAND_JSON_PATH, "utf-8"));
|
|
45329
45401
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
45330
45402
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
45331
45403
|
} catch {
|
|
@@ -45356,7 +45428,7 @@ var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskabl
|
|
|
45356
45428
|
);
|
|
45357
45429
|
var SW_SOURCE = (() => {
|
|
45358
45430
|
try {
|
|
45359
|
-
return
|
|
45431
|
+
return readFileSync64(resolve55(process.cwd(), "public", "sw.js"), "utf-8");
|
|
45360
45432
|
} catch {
|
|
45361
45433
|
return null;
|
|
45362
45434
|
}
|
|
@@ -45364,9 +45436,9 @@ var SW_SOURCE = (() => {
|
|
|
45364
45436
|
function readInstalledVersion() {
|
|
45365
45437
|
try {
|
|
45366
45438
|
if (!PLATFORM_ROOT6) return "unknown";
|
|
45367
|
-
const versionFile =
|
|
45439
|
+
const versionFile = join78(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
|
|
45368
45440
|
if (!existsSync63(versionFile)) return "unknown";
|
|
45369
|
-
const content =
|
|
45441
|
+
const content = readFileSync64(versionFile, "utf-8").trim();
|
|
45370
45442
|
return content || "unknown";
|
|
45371
45443
|
} catch {
|
|
45372
45444
|
return "unknown";
|
|
@@ -45377,7 +45449,7 @@ var versionScript = `<script>window.__MAXY_VERSION__=${JSON.stringify(INSTALLED_
|
|
|
45377
45449
|
function cachedHtml(file) {
|
|
45378
45450
|
let html = htmlCache.get(file);
|
|
45379
45451
|
if (!html) {
|
|
45380
|
-
html =
|
|
45452
|
+
html = readFileSync64(resolve55(process.cwd(), "public", file), "utf-8");
|
|
45381
45453
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
45382
45454
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
45383
45455
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -45394,14 +45466,14 @@ ${clientErrorReporterScript}
|
|
|
45394
45466
|
return html;
|
|
45395
45467
|
}
|
|
45396
45468
|
function loadBrandingCache(agentSlug) {
|
|
45397
|
-
const configDir =
|
|
45469
|
+
const configDir = join78(homedir5(), BRAND.configDir);
|
|
45398
45470
|
try {
|
|
45399
45471
|
const verdict = resolvePublicAddressFromDisk(agentSlug);
|
|
45400
45472
|
const accountId = verdict.kind === "served" ? verdict.owner.accountId : getDefaultAccountId();
|
|
45401
45473
|
if (!accountId) return null;
|
|
45402
|
-
const cachePath =
|
|
45474
|
+
const cachePath = join78(configDir, "branding-cache", accountId, `${agentSlug}.json`);
|
|
45403
45475
|
if (!existsSync63(cachePath)) return null;
|
|
45404
|
-
return JSON.parse(
|
|
45476
|
+
return JSON.parse(readFileSync64(cachePath, "utf-8"));
|
|
45405
45477
|
} catch {
|
|
45406
45478
|
return null;
|
|
45407
45479
|
}
|
|
@@ -45496,7 +45568,7 @@ app80.use("/vnc-popout.html", logViewerFetch);
|
|
|
45496
45568
|
app80.get("/vnc-popout.html", (c) => {
|
|
45497
45569
|
let html = htmlCache.get("vnc-popout.html");
|
|
45498
45570
|
if (!html) {
|
|
45499
|
-
html =
|
|
45571
|
+
html = readFileSync64(resolve55(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
45500
45572
|
const name = escapeHtml(BRAND.productName);
|
|
45501
45573
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
45502
45574
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -45650,7 +45722,7 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
45650
45722
|
var httpServer = serve({ fetch: app80.fetch, port, hostname });
|
|
45651
45723
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
45652
45724
|
{
|
|
45653
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
45725
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, "..");
|
|
45654
45726
|
const reconcileScript = resolve55(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
45655
45727
|
const runReconcile = (ctx) => {
|
|
45656
45728
|
if (!existsSync63(reconcileScript)) return;
|
|
@@ -45673,7 +45745,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
45673
45745
|
detached: true,
|
|
45674
45746
|
run: runReconcile
|
|
45675
45747
|
});
|
|
45676
|
-
const reconcileStatePath =
|
|
45748
|
+
const reconcileStatePath = join78(MAXY_DIR, "booking-reconcile-state.json");
|
|
45677
45749
|
registerLoop({
|
|
45678
45750
|
name: "calendar-reconcile-liveness",
|
|
45679
45751
|
intervalMs: 6e5,
|
|
@@ -45691,7 +45763,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
45691
45763
|
}
|
|
45692
45764
|
{
|
|
45693
45765
|
const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
|
|
45694
|
-
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
45766
|
+
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, "..");
|
|
45695
45767
|
const dreamSweepScript = resolve55(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
|
|
45696
45768
|
registerLoop({
|
|
45697
45769
|
name: "dream-cycle-sweep",
|
|
@@ -45715,7 +45787,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
45715
45787
|
});
|
|
45716
45788
|
}
|
|
45717
45789
|
{
|
|
45718
|
-
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
45790
|
+
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, "..");
|
|
45719
45791
|
const outlookScript = resolve55(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
45720
45792
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
45721
45793
|
const runOutlookComplete = (ctx) => {
|
|
@@ -45741,7 +45813,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
45741
45813
|
});
|
|
45742
45814
|
}
|
|
45743
45815
|
{
|
|
45744
|
-
const auditRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
45816
|
+
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, "..");
|
|
45745
45817
|
const strandedAccountsDir = resolve55(auditRoot, "..", "data/accounts");
|
|
45746
45818
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
45747
45819
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
@@ -45750,11 +45822,11 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
45750
45822
|
try {
|
|
45751
45823
|
if (!existsSync63(strandedAccountsDir)) return;
|
|
45752
45824
|
const now = Date.now();
|
|
45753
|
-
for (const name of
|
|
45825
|
+
for (const name of readdirSync38(strandedAccountsDir)) {
|
|
45754
45826
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
45755
45827
|
const pendingPath2 = resolve55(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
45756
45828
|
if (!existsSync63(pendingPath2)) continue;
|
|
45757
|
-
const ageMs2 = now -
|
|
45829
|
+
const ageMs2 = now - statSync34(pendingPath2).mtimeMs;
|
|
45758
45830
|
if (ageMs2 > STRANDED_AGE_MS) {
|
|
45759
45831
|
console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs2 / 1e3)}`);
|
|
45760
45832
|
}
|
|
@@ -45771,7 +45843,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
45771
45843
|
});
|
|
45772
45844
|
}
|
|
45773
45845
|
{
|
|
45774
|
-
const googleRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
45846
|
+
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, "..");
|
|
45775
45847
|
const googleAccountsDir = resolve55(googleRoot, "..", "data/accounts");
|
|
45776
45848
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
45777
45849
|
const runGooglePendingAuditSafe = () => {
|
|
@@ -45827,7 +45899,7 @@ registerLoop({
|
|
|
45827
45899
|
}
|
|
45828
45900
|
});
|
|
45829
45901
|
{
|
|
45830
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
45902
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, "..");
|
|
45831
45903
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
45832
45904
|
const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
|
|
45833
45905
|
console.error(`[storage-audit] error="${err.message}"`);
|
|
@@ -45894,7 +45966,7 @@ registerLoop({
|
|
|
45894
45966
|
const lastByBot = newestTelegramSessionByBot();
|
|
45895
45967
|
let secretFilesOnDisk = [];
|
|
45896
45968
|
try {
|
|
45897
|
-
secretFilesOnDisk =
|
|
45969
|
+
secretFilesOnDisk = readdirSync38(telegramSecretsDir());
|
|
45898
45970
|
} catch {
|
|
45899
45971
|
}
|
|
45900
45972
|
const lines = buildTelegramAuditLines({
|
|
@@ -45902,7 +45974,7 @@ registerLoop({
|
|
|
45902
45974
|
secretFileExists: (botId) => existsSync63(secretPath(botId)),
|
|
45903
45975
|
agentActive: isActiveAgentSlug,
|
|
45904
45976
|
// Task 2619 — the card set a specialist binding is reconciled against.
|
|
45905
|
-
specialistCards: (accountDir) => listSpecialistCardNames(
|
|
45977
|
+
specialistCards: (accountDir) => listSpecialistCardNames(join78(accountDir, "specialists", "agents")),
|
|
45906
45978
|
// Task 2619 — the doors that can be sent to right now. The same accessor
|
|
45907
45979
|
// the follower census reads (:1185), so "should have a reader" and "can be
|
|
45908
45980
|
// sent to" stay one fact.
|
|
@@ -45988,6 +46060,14 @@ registerLoop({
|
|
|
45988
46060
|
runTelegramMediaCensus();
|
|
45989
46061
|
}
|
|
45990
46062
|
});
|
|
46063
|
+
registerLoop({
|
|
46064
|
+
name: "telegram-card-row-census",
|
|
46065
|
+
intervalMs: STORAGE_AUDIT_INTERVAL_MS,
|
|
46066
|
+
firstRunDelayMs: 11e4,
|
|
46067
|
+
run: async () => {
|
|
46068
|
+
runTelegramCardRowCensus(process.env.LOG_DIR ?? LOG_DIR);
|
|
46069
|
+
}
|
|
46070
|
+
});
|
|
45991
46071
|
registerLoop({
|
|
45992
46072
|
name: "telegram-checkout-census",
|
|
45993
46073
|
intervalMs: STORAGE_AUDIT_INTERVAL_MS,
|
|
@@ -46303,7 +46383,7 @@ registerLoop({
|
|
|
46303
46383
|
});
|
|
46304
46384
|
}
|
|
46305
46385
|
{
|
|
46306
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
46386
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, "..");
|
|
46307
46387
|
const publishScript = resolve55(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
46308
46388
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
46309
46389
|
const bookingAccounts = () => {
|
|
@@ -46338,7 +46418,7 @@ registerLoop({
|
|
|
46338
46418
|
let hasBookingSite = false;
|
|
46339
46419
|
try {
|
|
46340
46420
|
if (existsSync63(availPath)) {
|
|
46341
|
-
const cfg = JSON.parse(
|
|
46421
|
+
const cfg = JSON.parse(readFileSync64(availPath, "utf-8"));
|
|
46342
46422
|
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
46343
46423
|
}
|
|
46344
46424
|
} catch {
|
|
@@ -46348,7 +46428,7 @@ registerLoop({
|
|
|
46348
46428
|
let lastSuccessAt = null;
|
|
46349
46429
|
if (existsSync63(statePath)) {
|
|
46350
46430
|
try {
|
|
46351
|
-
const rec = JSON.parse(
|
|
46431
|
+
const rec = JSON.parse(readFileSync64(statePath, "utf-8"));
|
|
46352
46432
|
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
46353
46433
|
} catch {
|
|
46354
46434
|
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
|
|
@@ -46383,7 +46463,7 @@ startDispatchCensus(() => getSession());
|
|
|
46383
46463
|
startDispatchFieldCensus(() => getSession());
|
|
46384
46464
|
startDispatchTgCensus(() => getSession());
|
|
46385
46465
|
{
|
|
46386
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
46466
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, "..");
|
|
46387
46467
|
const auditScript = resolve55(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
46388
46468
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
46389
46469
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
@@ -46514,7 +46594,7 @@ async function runAdminUserReconcileTick() {
|
|
|
46514
46594
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
46515
46595
|
return;
|
|
46516
46596
|
}
|
|
46517
|
-
const usersRaw =
|
|
46597
|
+
const usersRaw = readFileSync64(USERS_FILE, "utf-8").trim();
|
|
46518
46598
|
if (!usersRaw) {
|
|
46519
46599
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
46520
46600
|
return;
|
|
@@ -46596,8 +46676,8 @@ var runIngestAuditTick = () => {
|
|
|
46596
46676
|
},
|
|
46597
46677
|
agentExists: (accountId, slug) => {
|
|
46598
46678
|
if (!house) return false;
|
|
46599
|
-
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir :
|
|
46600
|
-
return existsSync63(
|
|
46679
|
+
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir : join78(ACCOUNTS_DIR, accountId);
|
|
46680
|
+
return existsSync63(join78(dir, "agents", slug, "config.json"));
|
|
46601
46681
|
}
|
|
46602
46682
|
});
|
|
46603
46683
|
} catch (err) {
|
|
@@ -46645,9 +46725,9 @@ registerLoop({
|
|
|
46645
46725
|
runPublicAddressCollisionAudit({
|
|
46646
46726
|
houseAccountId: () => resolveAccount()?.accountId ?? null,
|
|
46647
46727
|
activeSlugs: () => listValidAccounts().map((a) => {
|
|
46648
|
-
const agentsRoot =
|
|
46728
|
+
const agentsRoot = join78(a.accountDir, "agents");
|
|
46649
46729
|
if (!existsSync63(agentsRoot)) return { accountId: a.accountId, slugs: [] };
|
|
46650
|
-
const slugs =
|
|
46730
|
+
const slugs = readdirSync38(agentsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).filter((slug) => isActiveAgentSlug(a.accountDir, slug));
|
|
46651
46731
|
return { accountId: a.accountId, slugs };
|
|
46652
46732
|
})
|
|
46653
46733
|
});
|
|
@@ -46661,7 +46741,7 @@ registerLoop({
|
|
|
46661
46741
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
46662
46742
|
function countUsersRows() {
|
|
46663
46743
|
if (!existsSync63(USERS_FILE)) return 0;
|
|
46664
|
-
const raw =
|
|
46744
|
+
const raw = readFileSync64(USERS_FILE, "utf-8").trim();
|
|
46665
46745
|
if (!raw) return 0;
|
|
46666
46746
|
const users = JSON.parse(raw);
|
|
46667
46747
|
return users.filter((u) => typeof u.userId === "string").length;
|
|
@@ -46764,7 +46844,7 @@ function sessionChannelResolver() {
|
|
|
46764
46844
|
byId = /* @__PURE__ */ new Map();
|
|
46765
46845
|
const cfg = claudeConfigDir();
|
|
46766
46846
|
if (cfg) {
|
|
46767
|
-
for (const { path } of enumerateSessionSidecars(
|
|
46847
|
+
for (const { path } of enumerateSessionSidecars(join78(cfg, "projects"))) {
|
|
46768
46848
|
const channel = readSidecarMeta(path).channel;
|
|
46769
46849
|
if (channel) byId.set(basename19(path).replace(/\.meta\.json$/, ""), channel);
|
|
46770
46850
|
}
|
|
@@ -46839,7 +46919,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
46839
46919
|
}
|
|
46840
46920
|
init({
|
|
46841
46921
|
configDir: configDirForWhatsApp,
|
|
46842
|
-
platformRoot: resolve55(process.env.MAXY_PLATFORM_ROOT ??
|
|
46922
|
+
platformRoot: resolve55(process.env.MAXY_PLATFORM_ROOT ?? join78(__dirname, "..")),
|
|
46843
46923
|
accountConfig: bootAccountConfig,
|
|
46844
46924
|
// Task 2074 — enrich with the sub-account name and fan out to every open
|
|
46845
46925
|
// admin SSE stream. Fire-and-forget: the manager's persist path must not
|