@rubytech/create-realagent-code 0.1.594 → 0.1.595
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/telegram-button-labels/dist/index.d.ts +19 -0
- package/payload/platform/lib/telegram-button-labels/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/telegram-button-labels/dist/index.js +84 -0
- package/payload/platform/lib/telegram-button-labels/dist/index.js.map +1 -0
- package/payload/platform/lib/telegram-button-labels/src/__tests__/store.test.ts +67 -0
- package/payload/platform/lib/telegram-button-labels/src/index.ts +88 -0
- package/payload/platform/lib/telegram-button-labels/tsconfig.json +9 -0
- package/payload/platform/lib/telegram-button-labels/vitest.config.ts +9 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +8 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +5 -0
- package/payload/platform/plugins/docs/references/telegram-guide.md +7 -0
- package/payload/server/server.js +543 -409
package/payload/server/server.js
CHANGED
|
@@ -363,10 +363,10 @@ var require_dist2 = __commonJS({
|
|
|
363
363
|
} catch {
|
|
364
364
|
return { newest, storeRows };
|
|
365
365
|
}
|
|
366
|
-
for (const
|
|
367
|
-
if (!
|
|
366
|
+
for (const entry3 of entries2) {
|
|
367
|
+
if (!entry3.endsWith(".jsonl"))
|
|
368
368
|
continue;
|
|
369
|
-
const stem =
|
|
369
|
+
const stem = entry3.slice(0, -".jsonl".length);
|
|
370
370
|
const channelKey = fileStemToChannelKey3(stem);
|
|
371
371
|
if (!isStorableChannelKey3(channelKey))
|
|
372
372
|
continue;
|
|
@@ -375,7 +375,7 @@ var require_dist2 = __commonJS({
|
|
|
375
375
|
const botId = channelKey.slice(0, channelKey.indexOf(":"));
|
|
376
376
|
let raw;
|
|
377
377
|
try {
|
|
378
|
-
raw = (0, node_fs_1.readFileSync)((0, node_path_1.join)(storeDir,
|
|
378
|
+
raw = (0, node_fs_1.readFileSync)((0, node_path_1.join)(storeDir, entry3), "utf8");
|
|
379
379
|
} catch {
|
|
380
380
|
continue;
|
|
381
381
|
}
|
|
@@ -604,6 +604,67 @@ var require_dist4 = __commonJS({
|
|
|
604
604
|
}
|
|
605
605
|
});
|
|
606
606
|
|
|
607
|
+
// ../lib/telegram-button-labels/dist/index.js
|
|
608
|
+
var require_dist5 = __commonJS({
|
|
609
|
+
"../lib/telegram-button-labels/dist/index.js"(exports) {
|
|
610
|
+
"use strict";
|
|
611
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
612
|
+
exports.BUTTON_LABEL_TTL_MS = void 0;
|
|
613
|
+
exports.buttonLabelKey = buttonLabelKey2;
|
|
614
|
+
exports.writeButtonLabels = writeButtonLabels;
|
|
615
|
+
exports.readButtonLabel = readButtonLabel2;
|
|
616
|
+
var node_fs_1 = __require("fs");
|
|
617
|
+
var node_path_1 = __require("path");
|
|
618
|
+
var FILE4 = "telegram-button-labels.json";
|
|
619
|
+
exports.BUTTON_LABEL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
620
|
+
function isEntry(v) {
|
|
621
|
+
if (!v || typeof v !== "object" || Array.isArray(v))
|
|
622
|
+
return false;
|
|
623
|
+
const e = v;
|
|
624
|
+
return typeof e.label === "string" && typeof e.at === "number" && Number.isFinite(e.at);
|
|
625
|
+
}
|
|
626
|
+
function buttonLabelKey2(botId, chatId, data) {
|
|
627
|
+
return `${botId}:${chatId}:${data}`;
|
|
628
|
+
}
|
|
629
|
+
function readAll3(path) {
|
|
630
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
631
|
+
return {};
|
|
632
|
+
try {
|
|
633
|
+
const parsed = JSON.parse((0, node_fs_1.readFileSync)(path, "utf-8"));
|
|
634
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
635
|
+
return {};
|
|
636
|
+
const out = {};
|
|
637
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
638
|
+
if (isEntry(v))
|
|
639
|
+
out[k] = v;
|
|
640
|
+
}
|
|
641
|
+
return out;
|
|
642
|
+
} catch {
|
|
643
|
+
return {};
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
function writeButtonLabels(storeDir, entries2, now = Date.now()) {
|
|
647
|
+
if (entries2.length === 0)
|
|
648
|
+
return;
|
|
649
|
+
const path = (0, node_path_1.join)(storeDir, FILE4);
|
|
650
|
+
const kept = {};
|
|
651
|
+
for (const [key2, entry3] of Object.entries(readAll3(path))) {
|
|
652
|
+
if (now - entry3.at < exports.BUTTON_LABEL_TTL_MS)
|
|
653
|
+
kept[key2] = entry3;
|
|
654
|
+
}
|
|
655
|
+
for (const e of entries2)
|
|
656
|
+
kept[e.key] = { label: e.label, at: now };
|
|
657
|
+
(0, node_fs_1.writeFileSync)(path, JSON.stringify(kept, null, 2) + "\n", "utf-8");
|
|
658
|
+
}
|
|
659
|
+
function readButtonLabel2(storeDir, key2, now = Date.now()) {
|
|
660
|
+
const entry3 = readAll3((0, node_path_1.join)(storeDir, FILE4))[key2];
|
|
661
|
+
if (!entry3)
|
|
662
|
+
return null;
|
|
663
|
+
return now - entry3.at >= exports.BUTTON_LABEL_TTL_MS ? null : entry3.label;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
|
|
607
668
|
// ../lib/dispatch-read/dist/config.js
|
|
608
669
|
var require_config = __commonJS({
|
|
609
670
|
"../lib/dispatch-read/dist/config.js"(exports) {
|
|
@@ -1514,7 +1575,7 @@ var require_geo = __commonJS({
|
|
|
1514
1575
|
});
|
|
1515
1576
|
|
|
1516
1577
|
// ../lib/dispatch-read/dist/index.js
|
|
1517
|
-
var
|
|
1578
|
+
var require_dist6 = __commonJS({
|
|
1518
1579
|
"../lib/dispatch-read/dist/index.js"(exports) {
|
|
1519
1580
|
"use strict";
|
|
1520
1581
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1673,7 +1734,7 @@ var require_dist5 = __commonJS({
|
|
|
1673
1734
|
});
|
|
1674
1735
|
|
|
1675
1736
|
// ../lib/account-schema-regions/dist/index.js
|
|
1676
|
-
var
|
|
1737
|
+
var require_dist7 = __commonJS({
|
|
1677
1738
|
"../lib/account-schema-regions/dist/index.js"(exports) {
|
|
1678
1739
|
"use strict";
|
|
1679
1740
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1743,7 +1804,7 @@ var require_dist6 = __commonJS({
|
|
|
1743
1804
|
});
|
|
1744
1805
|
|
|
1745
1806
|
// ../lib/graph-trash/dist/index.js
|
|
1746
|
-
var
|
|
1807
|
+
var require_dist8 = __commonJS({
|
|
1747
1808
|
"../lib/graph-trash/dist/index.js"(exports) {
|
|
1748
1809
|
"use strict";
|
|
1749
1810
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -2024,7 +2085,7 @@ var require_dist7 = __commonJS({
|
|
|
2024
2085
|
});
|
|
2025
2086
|
|
|
2026
2087
|
// ../lib/graph-style/dist/index.js
|
|
2027
|
-
var
|
|
2088
|
+
var require_dist9 = __commonJS({
|
|
2028
2089
|
"../lib/graph-style/dist/index.js"(exports) {
|
|
2029
2090
|
"use strict";
|
|
2030
2091
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -2784,7 +2845,7 @@ var require_conversation_provenance = __commonJS({
|
|
|
2784
2845
|
"use strict";
|
|
2785
2846
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2786
2847
|
exports.injectConversationProvenance = injectConversationProvenance;
|
|
2787
|
-
var index_js_1 =
|
|
2848
|
+
var index_js_1 = require_dist10();
|
|
2788
2849
|
async function injectConversationProvenance(params) {
|
|
2789
2850
|
const { session, relationships, accountId, writeLabels, conversationNodeId, logNamespace, tool } = params;
|
|
2790
2851
|
const original = [...relationships];
|
|
@@ -2834,7 +2895,7 @@ var require_conversation_provenance = __commonJS({
|
|
|
2834
2895
|
});
|
|
2835
2896
|
|
|
2836
2897
|
// ../lib/graph-write/dist/index.js
|
|
2837
|
-
var
|
|
2898
|
+
var require_dist10 = __commonJS({
|
|
2838
2899
|
"../lib/graph-write/dist/index.js"(exports) {
|
|
2839
2900
|
"use strict";
|
|
2840
2901
|
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
@@ -3169,26 +3230,26 @@ function keyOf(resource, accountId) {
|
|
|
3169
3230
|
function generationOf(resource, key2) {
|
|
3170
3231
|
return (keyGenerations.get(key2) ?? 0) + (resourceGenerations.get(resource) ?? 0);
|
|
3171
3232
|
}
|
|
3172
|
-
function recomputeFloorMs(
|
|
3233
|
+
function recomputeFloorMs(entry3) {
|
|
3173
3234
|
return Math.min(
|
|
3174
|
-
Math.max(
|
|
3235
|
+
Math.max(entry3.computeMs * RECOMPUTE_FLOOR_FACTOR, MIN_RECOMPUTE_FLOOR_MS),
|
|
3175
3236
|
MAX_RECOMPUTE_FLOOR_MS
|
|
3176
3237
|
);
|
|
3177
3238
|
}
|
|
3178
3239
|
async function getOrCompute(resource, accountId, compute) {
|
|
3179
3240
|
const key2 = keyOf(resource, accountId);
|
|
3180
|
-
const
|
|
3181
|
-
if (
|
|
3182
|
-
const age = Date.now() -
|
|
3183
|
-
if (!
|
|
3184
|
-
return { value:
|
|
3241
|
+
const entry3 = entries.get(key2);
|
|
3242
|
+
if (entry3 !== void 0) {
|
|
3243
|
+
const age = Date.now() - entry3.computedAt;
|
|
3244
|
+
if (!entry3.dirty && age <= BACKSTOP_MS) {
|
|
3245
|
+
return { value: entry3.value, state: "hit" };
|
|
3185
3246
|
}
|
|
3186
|
-
const sinceAttempt = Date.now() -
|
|
3187
|
-
if (
|
|
3188
|
-
return { value:
|
|
3247
|
+
const sinceAttempt = Date.now() - entry3.lastAttemptAt;
|
|
3248
|
+
if (entry3.dirty && sinceAttempt < recomputeFloorMs(entry3) && age <= BACKSTOP_MS) {
|
|
3249
|
+
return { value: entry3.value, state: "dirty-floor" };
|
|
3189
3250
|
}
|
|
3190
3251
|
}
|
|
3191
|
-
const state =
|
|
3252
|
+
const state = entry3 === void 0 ? "miss" : "stale-backstop";
|
|
3192
3253
|
const existing = inFlight.get(key2);
|
|
3193
3254
|
if (existing) return { value: await existing, state };
|
|
3194
3255
|
const startedGeneration = generationOf(resource, key2);
|
|
@@ -3233,8 +3294,8 @@ function invalidate(resource, accountId, source = "action") {
|
|
|
3233
3294
|
entries.delete(key2);
|
|
3234
3295
|
return;
|
|
3235
3296
|
}
|
|
3236
|
-
const
|
|
3237
|
-
if (
|
|
3297
|
+
const entry3 = entries.get(key2);
|
|
3298
|
+
if (entry3) entry3.dirty = true;
|
|
3238
3299
|
};
|
|
3239
3300
|
if (accountId === null) {
|
|
3240
3301
|
resourceGenerations.set(resource, (resourceGenerations.get(resource) ?? 0) + 1);
|
|
@@ -3427,9 +3488,9 @@ function findPollConversation(accountId, pollId) {
|
|
|
3427
3488
|
const needle = `:poll:${pollId}:`;
|
|
3428
3489
|
try {
|
|
3429
3490
|
if (!existsSync(dir)) return null;
|
|
3430
|
-
for (const
|
|
3431
|
-
if (!
|
|
3432
|
-
const stem =
|
|
3491
|
+
for (const entry3 of readdirSync(dir)) {
|
|
3492
|
+
if (!entry3.endsWith(".jsonl")) continue;
|
|
3493
|
+
const stem = entry3.slice(0, -".jsonl".length);
|
|
3433
3494
|
if (!isStorableStem(stem)) continue;
|
|
3434
3495
|
const channelKey = (0, import_dist2.fileStemToChannelKey)(stem);
|
|
3435
3496
|
for (const row of readRows(accountId, channelKey)) {
|
|
@@ -3458,12 +3519,12 @@ function readConversationSummaries2(accountId) {
|
|
|
3458
3519
|
const seen = /* @__PURE__ */ new Set();
|
|
3459
3520
|
try {
|
|
3460
3521
|
if (!existsSync(dir)) return out;
|
|
3461
|
-
for (const
|
|
3462
|
-
if (!
|
|
3463
|
-
const stem =
|
|
3522
|
+
for (const entry3 of readdirSync(dir)) {
|
|
3523
|
+
if (!entry3.endsWith(".jsonl")) continue;
|
|
3524
|
+
const stem = entry3.slice(0, -".jsonl".length);
|
|
3464
3525
|
if (!isStorableStem(stem)) continue;
|
|
3465
3526
|
const channelKey = (0, import_dist2.fileStemToChannelKey)(stem);
|
|
3466
|
-
const file = join(dir,
|
|
3527
|
+
const file = join(dir, entry3);
|
|
3467
3528
|
seen.add(file);
|
|
3468
3529
|
let size;
|
|
3469
3530
|
let mtimeMs;
|
|
@@ -5125,12 +5186,12 @@ function getLanIp() {
|
|
|
5125
5186
|
let fallback = null;
|
|
5126
5187
|
for (const entries2 of Object.values(nets)) {
|
|
5127
5188
|
if (!entries2) continue;
|
|
5128
|
-
for (const
|
|
5129
|
-
if (
|
|
5130
|
-
if (
|
|
5131
|
-
return
|
|
5189
|
+
for (const entry3 of entries2) {
|
|
5190
|
+
if (entry3.family !== "IPv4" || entry3.internal) continue;
|
|
5191
|
+
if (entry3.address.startsWith("192.168.") || entry3.address.startsWith("10.")) {
|
|
5192
|
+
return entry3.address;
|
|
5132
5193
|
}
|
|
5133
|
-
if (!fallback) fallback =
|
|
5194
|
+
if (!fallback) fallback = entry3.address;
|
|
5134
5195
|
}
|
|
5135
5196
|
}
|
|
5136
5197
|
return fallback;
|
|
@@ -6092,9 +6153,9 @@ function checkTelegramChatSend(params) {
|
|
|
6092
6153
|
}
|
|
6093
6154
|
return { allowed: false, reason: "not-in-allowChannels" };
|
|
6094
6155
|
}
|
|
6095
|
-
function chatSendAllowlists(
|
|
6096
|
-
if (!
|
|
6097
|
-
return { allowChannels:
|
|
6156
|
+
function chatSendAllowlists(entry3) {
|
|
6157
|
+
if (!entry3 || entry3.role !== "public") return { allowChannels: [], allowGroups: [] };
|
|
6158
|
+
return { allowChannels: entry3.allowChannels ?? [], allowGroups: entry3.allowGroups ?? [] };
|
|
6098
6159
|
}
|
|
6099
6160
|
|
|
6100
6161
|
// app/lib/channel-pty-bridge/admin-session-id.ts
|
|
@@ -6193,7 +6254,7 @@ function parseTitleCache(raw) {
|
|
|
6193
6254
|
}
|
|
6194
6255
|
function serializeTitleCache(cache2) {
|
|
6195
6256
|
const obj = {};
|
|
6196
|
-
for (const [sessionId,
|
|
6257
|
+
for (const [sessionId, entry3] of cache2) obj[sessionId] = entry3;
|
|
6197
6258
|
return JSON.stringify(obj);
|
|
6198
6259
|
}
|
|
6199
6260
|
async function loadTitleCacheOutcome(accountDir) {
|
|
@@ -6226,7 +6287,7 @@ async function saveTitleCacheMerged(accountDir, updates, evict) {
|
|
|
6226
6287
|
if (err.code !== "ENOENT") throw err;
|
|
6227
6288
|
merged = /* @__PURE__ */ new Map();
|
|
6228
6289
|
}
|
|
6229
|
-
for (const [sessionId,
|
|
6290
|
+
for (const [sessionId, entry3] of updates) merged.set(sessionId, entry3);
|
|
6230
6291
|
let evicted = 0;
|
|
6231
6292
|
if (evict !== void 0) {
|
|
6232
6293
|
for (const sessionId of evict) {
|
|
@@ -6653,11 +6714,11 @@ function enumerateJsonlsWithSkips(projectsRoot, fileRe = SESSION_ID_RE) {
|
|
|
6653
6714
|
skipped += 1;
|
|
6654
6715
|
continue;
|
|
6655
6716
|
}
|
|
6656
|
-
for (const
|
|
6657
|
-
if (
|
|
6658
|
-
out.push({ path: join11(slugDir,
|
|
6659
|
-
} else if (
|
|
6660
|
-
const subDir = join11(slugDir,
|
|
6717
|
+
for (const entry3 of entries2) {
|
|
6718
|
+
if (entry3.isFile() && fileRe.test(entry3.name)) {
|
|
6719
|
+
out.push({ path: join11(slugDir, entry3.name), isSubagent: false, archived: false });
|
|
6720
|
+
} else if (entry3.isDirectory() && entry3.name === "subagents") {
|
|
6721
|
+
const subDir = join11(slugDir, entry3.name);
|
|
6661
6722
|
let subEntries;
|
|
6662
6723
|
try {
|
|
6663
6724
|
subEntries = readdirSync5(subDir, { withFileTypes: true });
|
|
@@ -6672,8 +6733,8 @@ function enumerateJsonlsWithSkips(projectsRoot, fileRe = SESSION_ID_RE) {
|
|
|
6672
6733
|
out.push({ path: join11(subDir, sub.name), isSubagent: true, archived: false });
|
|
6673
6734
|
}
|
|
6674
6735
|
}
|
|
6675
|
-
} else if (
|
|
6676
|
-
const archiveDir = join11(slugDir,
|
|
6736
|
+
} else if (entry3.isDirectory() && entry3.name === "archive") {
|
|
6737
|
+
const archiveDir = join11(slugDir, entry3.name);
|
|
6677
6738
|
let archiveEntries;
|
|
6678
6739
|
try {
|
|
6679
6740
|
archiveEntries = readdirSync5(archiveDir, { withFileTypes: true });
|
|
@@ -7281,7 +7342,7 @@ function createScheduleInjectRoutes(deps) {
|
|
|
7281
7342
|
}
|
|
7282
7343
|
|
|
7283
7344
|
// server/index.ts
|
|
7284
|
-
var
|
|
7345
|
+
var import_dist18 = __toESM(require_dist3(), 1);
|
|
7285
7346
|
|
|
7286
7347
|
// app/lib/whatsapp/avatar-store.ts
|
|
7287
7348
|
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync4, readdirSync as readdirSync6, statSync as statSync8, rmSync as rmSync3 } from "fs";
|
|
@@ -7518,12 +7579,12 @@ async function sweepAvatars() {
|
|
|
7518
7579
|
var TAG9 = "[wa-chatmeta]";
|
|
7519
7580
|
function diffStoredAgainstLive(stored, live) {
|
|
7520
7581
|
const out = [];
|
|
7521
|
-
for (const
|
|
7522
|
-
if (!
|
|
7523
|
-
const seen = live.get(
|
|
7582
|
+
for (const entry3 of stored.values()) {
|
|
7583
|
+
if (!entry3.isGroup) continue;
|
|
7584
|
+
const seen = live.get(entry3.jid);
|
|
7524
7585
|
if (seen === void 0) continue;
|
|
7525
|
-
if (seen.name !==
|
|
7526
|
-
out.push({ jid:
|
|
7586
|
+
if (seen.name !== entry3.name) {
|
|
7587
|
+
out.push({ jid: entry3.jid, stored: entry3.name, live: seen.name, observedAt: seen.observedAt });
|
|
7527
7588
|
}
|
|
7528
7589
|
}
|
|
7529
7590
|
return out;
|
|
@@ -7539,13 +7600,13 @@ async function sweepChatMetadata() {
|
|
|
7539
7600
|
const sock = conn.sock;
|
|
7540
7601
|
const stored = readChatMetadata(conn.platformAccountId);
|
|
7541
7602
|
const live = /* @__PURE__ */ new Map();
|
|
7542
|
-
for (const
|
|
7543
|
-
if (!
|
|
7603
|
+
for (const entry3 of stored.values()) {
|
|
7604
|
+
if (!entry3.isGroup) continue;
|
|
7544
7605
|
groups += 1;
|
|
7545
7606
|
try {
|
|
7546
|
-
const meta = await sock.groupMetadata(
|
|
7607
|
+
const meta = await sock.groupMetadata(entry3.jid);
|
|
7547
7608
|
if (typeof meta.subject === "string" && meta.subject.length > 0) {
|
|
7548
|
-
live.set(
|
|
7609
|
+
live.set(entry3.jid, { name: meta.subject, observedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
7549
7610
|
checked2 += 1;
|
|
7550
7611
|
}
|
|
7551
7612
|
} catch {
|
|
@@ -8208,9 +8269,9 @@ function purgeNonSocketAccountManagers(accountDir, socketOwnerId) {
|
|
|
8208
8269
|
if (targetId === socketOwnerId) return { removed: [] };
|
|
8209
8270
|
const map = wa.accountManagers;
|
|
8210
8271
|
if (!map || typeof map !== "object" || Array.isArray(map)) return { removed: [] };
|
|
8211
|
-
const removed = Object.entries(map).map(([phone,
|
|
8272
|
+
const removed = Object.entries(map).map(([phone, entry3]) => ({
|
|
8212
8273
|
phone,
|
|
8213
|
-
managesAccount: typeof
|
|
8274
|
+
managesAccount: typeof entry3 === "string" ? entry3 : entry3 && typeof entry3 === "object" && typeof entry3.managesAccount === "string" ? entry3.managesAccount : ""
|
|
8214
8275
|
}));
|
|
8215
8276
|
if (removed.length === 0) return { removed: [] };
|
|
8216
8277
|
delete wa.accountManagers;
|
|
@@ -8513,10 +8574,10 @@ function purgeNonSocketRegisteredParties(accountDir, socketOwnerId) {
|
|
|
8513
8574
|
if (targetId === socketOwnerId) return { removed: [] };
|
|
8514
8575
|
const map = wa.registeredParties;
|
|
8515
8576
|
if (!map || typeof map !== "object" || Array.isArray(map)) return { removed: [] };
|
|
8516
|
-
const removed = Object.entries(map).map(([phone,
|
|
8577
|
+
const removed = Object.entries(map).map(([phone, entry3]) => ({
|
|
8517
8578
|
phone,
|
|
8518
|
-
account:
|
|
8519
|
-
party:
|
|
8579
|
+
account: entry3 && typeof entry3 === "object" && typeof entry3.account === "string" ? entry3.account : "",
|
|
8580
|
+
party: entry3 && typeof entry3 === "object" && typeof entry3.party === "string" ? entry3.party : ""
|
|
8520
8581
|
}));
|
|
8521
8582
|
if (removed.length === 0) return { removed: [] };
|
|
8522
8583
|
delete wa.registeredParties;
|
|
@@ -9350,27 +9411,27 @@ function bare(value) {
|
|
|
9350
9411
|
function reconcilePersonIdentities(rows) {
|
|
9351
9412
|
const perAccount = /* @__PURE__ */ new Map();
|
|
9352
9413
|
for (const row of rows) {
|
|
9353
|
-
let
|
|
9354
|
-
if (!
|
|
9355
|
-
|
|
9356
|
-
perAccount.set(row.accountId,
|
|
9414
|
+
let entry3 = perAccount.get(row.accountId);
|
|
9415
|
+
if (!entry3) {
|
|
9416
|
+
entry3 = { seen: /* @__PURE__ */ new Map(), divergent: 0 };
|
|
9417
|
+
perAccount.set(row.accountId, entry3);
|
|
9357
9418
|
}
|
|
9358
9419
|
const p = row.phone ? bare(row.phone) : null;
|
|
9359
9420
|
const t = row.telephone ? bare(row.telephone) : null;
|
|
9360
|
-
if (p && t && p !== t)
|
|
9421
|
+
if (p && t && p !== t) entry3.divergent += 1;
|
|
9361
9422
|
const key2 = p ?? t;
|
|
9362
|
-
if (key2)
|
|
9423
|
+
if (key2) entry3.seen.set(key2, (entry3.seen.get(key2) ?? 0) + 1);
|
|
9363
9424
|
}
|
|
9364
9425
|
const accounts = [];
|
|
9365
9426
|
let duplicates = 0;
|
|
9366
9427
|
let divergent = 0;
|
|
9367
|
-
for (const [accountId,
|
|
9428
|
+
for (const [accountId, entry3] of perAccount) {
|
|
9368
9429
|
let dup = 0;
|
|
9369
|
-
for (const count of
|
|
9430
|
+
for (const count of entry3.seen.values()) if (count > 1) dup += count - 1;
|
|
9370
9431
|
duplicates += dup;
|
|
9371
|
-
divergent +=
|
|
9372
|
-
if (dup > 0 ||
|
|
9373
|
-
accounts.push({ accountId, duplicates: dup, divergent:
|
|
9432
|
+
divergent += entry3.divergent;
|
|
9433
|
+
if (dup > 0 || entry3.divergent > 0) {
|
|
9434
|
+
accounts.push({ accountId, duplicates: dup, divergent: entry3.divergent });
|
|
9374
9435
|
}
|
|
9375
9436
|
}
|
|
9376
9437
|
return {
|
|
@@ -9392,7 +9453,7 @@ function reconcileSelfPhoneAdmins(input) {
|
|
|
9392
9453
|
for (const cred of nonHouse) {
|
|
9393
9454
|
const selfPhone = cred.selfPhone;
|
|
9394
9455
|
if (!selfPhone) continue;
|
|
9395
|
-
if (input.adminPhones.some((
|
|
9456
|
+
if (input.adminPhones.some((entry3) => phonesMatch(entry3, selfPhone))) {
|
|
9396
9457
|
matches.push({ accountId: cred.accountId, phone: selfPhone });
|
|
9397
9458
|
}
|
|
9398
9459
|
}
|
|
@@ -9773,11 +9834,11 @@ function authorizeRecallRead(input) {
|
|
|
9773
9834
|
function buildRegisteredPartyReconcile(params) {
|
|
9774
9835
|
const rows = [];
|
|
9775
9836
|
const entries2 = Object.entries(params.registeredParties);
|
|
9776
|
-
for (const [phone,
|
|
9837
|
+
for (const [phone, entry3] of entries2) {
|
|
9777
9838
|
const shadowedBy = isAdminPhone(phone, params.adminPhones) ? "adminPhones" : managedAccountFor(params.accountManagers, phone) ? "accountManagers" : null;
|
|
9778
|
-
const unresolved2 = !params.isValidAccount(
|
|
9839
|
+
const unresolved2 = !params.isValidAccount(entry3.account);
|
|
9779
9840
|
if (shadowedBy || unresolved2) {
|
|
9780
|
-
rows.push({ phone, account:
|
|
9841
|
+
rows.push({ phone, account: entry3.account, party: entry3.party, shadowedBy, unresolved: unresolved2 });
|
|
9781
9842
|
}
|
|
9782
9843
|
}
|
|
9783
9844
|
const shadowed = rows.filter((r) => r.shadowedBy !== null).length;
|
|
@@ -10187,15 +10248,15 @@ app3.post("/config", async (c) => {
|
|
|
10187
10248
|
const agents = [];
|
|
10188
10249
|
if (existsSync9(agentsDir)) {
|
|
10189
10250
|
try {
|
|
10190
|
-
for (const
|
|
10191
|
-
if (!
|
|
10192
|
-
const configPath3 = resolve8(agentsDir,
|
|
10251
|
+
for (const entry3 of readdirSync8(agentsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
10252
|
+
if (!entry3.isDirectory() || entry3.name === "admin") continue;
|
|
10253
|
+
const configPath3 = resolve8(agentsDir, entry3.name, "config.json");
|
|
10193
10254
|
if (!existsSync9(configPath3)) continue;
|
|
10194
10255
|
try {
|
|
10195
10256
|
const parsed = JSON.parse(readFileSync11(configPath3, "utf-8"));
|
|
10196
|
-
agents.push({ slug:
|
|
10257
|
+
agents.push({ slug: entry3.name, displayName: parsed.displayName ?? entry3.name });
|
|
10197
10258
|
} catch {
|
|
10198
|
-
console.error(`${TAG17} config action=list-public-agents error="failed to parse config.json for agent ${
|
|
10259
|
+
console.error(`${TAG17} config action=list-public-agents error="failed to parse config.json for agent ${entry3.name}" \u2014 skipping`);
|
|
10199
10260
|
}
|
|
10200
10261
|
}
|
|
10201
10262
|
} catch (err) {
|
|
@@ -10215,8 +10276,8 @@ app3.post("/config", async (c) => {
|
|
|
10215
10276
|
const listDenial = bindingScopeDenial(c, callerAccountId, "list-account-managers");
|
|
10216
10277
|
if (listDenial) return listDenial;
|
|
10217
10278
|
const all = readAccountManagers(acct.accountDir);
|
|
10218
|
-
const boundAccountOf = (
|
|
10219
|
-
const accountManagers = houseAdmin ? all : Object.fromEntries(Object.entries(all).filter(([,
|
|
10279
|
+
const boundAccountOf = (entry3) => typeof entry3 === "string" ? entry3 : entry3.managesAccount;
|
|
10280
|
+
const accountManagers = houseAdmin ? all : Object.fromEntries(Object.entries(all).filter(([, entry3]) => boundAccountOf(entry3) === callerAccountId));
|
|
10220
10281
|
console.error(`${TAG17} config action=list-account-managers caller=${callerAccountId || "none"} houseAdmin=${houseAdmin ? "y" : "n"} count=${Object.keys(accountManagers).length} of=${Object.keys(all).length}`);
|
|
10221
10282
|
return c.json({ ok: true, accountManagers });
|
|
10222
10283
|
}
|
|
@@ -10254,7 +10315,7 @@ app3.post("/config", async (c) => {
|
|
|
10254
10315
|
const listDenial = bindingScopeDenial(c, callerAccountId, "list-registered-parties");
|
|
10255
10316
|
if (listDenial) return listDenial;
|
|
10256
10317
|
const all = readRegisteredParties(acct.accountDir);
|
|
10257
|
-
const registeredParties = houseAdmin ? all : Object.fromEntries(Object.entries(all).filter(([,
|
|
10318
|
+
const registeredParties = houseAdmin ? all : Object.fromEntries(Object.entries(all).filter(([, entry3]) => entry3.account === callerAccountId));
|
|
10258
10319
|
console.error(`${TAG17} config action=list-registered-parties caller=${callerAccountId || "none"} houseAdmin=${houseAdmin ? "y" : "n"} count=${Object.keys(registeredParties).length} of=${Object.keys(all).length}`);
|
|
10259
10320
|
return c.json({ ok: true, registeredParties });
|
|
10260
10321
|
}
|
|
@@ -12159,10 +12220,10 @@ function readState(platformRoot5) {
|
|
|
12159
12220
|
return {};
|
|
12160
12221
|
}
|
|
12161
12222
|
}
|
|
12162
|
-
function recordSuccess(platformRoot5, accountId,
|
|
12223
|
+
function recordSuccess(platformRoot5, accountId, entry3) {
|
|
12163
12224
|
const path = stateFilePath(platformRoot5);
|
|
12164
12225
|
const state = readState(platformRoot5);
|
|
12165
|
-
state[accountId] =
|
|
12226
|
+
state[accountId] = entry3;
|
|
12166
12227
|
try {
|
|
12167
12228
|
writeFileSync6(path, JSON.stringify(state, null, 1));
|
|
12168
12229
|
} catch (err) {
|
|
@@ -13259,10 +13320,10 @@ function readVisitsPushState(platformRoot5) {
|
|
|
13259
13320
|
return {};
|
|
13260
13321
|
}
|
|
13261
13322
|
}
|
|
13262
|
-
function recordVisitsPush(platformRoot5, accountId,
|
|
13323
|
+
function recordVisitsPush(platformRoot5, accountId, entry3) {
|
|
13263
13324
|
const path = visitsStateFilePath(platformRoot5);
|
|
13264
13325
|
const state = readVisitsPushState(platformRoot5);
|
|
13265
|
-
state[accountId] =
|
|
13326
|
+
state[accountId] = entry3;
|
|
13266
13327
|
try {
|
|
13267
13328
|
writeFileSync7(path, JSON.stringify(state, null, 1));
|
|
13268
13329
|
} catch (err) {
|
|
@@ -14906,20 +14967,20 @@ function listBotEntries(config) {
|
|
|
14906
14967
|
}
|
|
14907
14968
|
return out;
|
|
14908
14969
|
}
|
|
14909
|
-
function entryAgentSlug(
|
|
14910
|
-
if (
|
|
14911
|
-
if (
|
|
14912
|
-
if (
|
|
14913
|
-
return
|
|
14970
|
+
function entryAgentSlug(entry3) {
|
|
14971
|
+
if (entry3.role === "admin") return "admin";
|
|
14972
|
+
if (entry3.role === "unbound") return "unbound";
|
|
14973
|
+
if (entry3.role === "specialist") return entry3.specialist;
|
|
14974
|
+
return entry3.agent;
|
|
14914
14975
|
}
|
|
14915
|
-
function isBindableEntry(
|
|
14916
|
-
return
|
|
14976
|
+
function isBindableEntry(entry3) {
|
|
14977
|
+
return entry3.role !== "unbound";
|
|
14917
14978
|
}
|
|
14918
14979
|
function resolveBotEntry(accounts, botId) {
|
|
14919
14980
|
const hits = [];
|
|
14920
14981
|
for (const a of accounts) {
|
|
14921
|
-
for (const
|
|
14922
|
-
if (
|
|
14982
|
+
for (const entry3 of listBotEntries(a.config.telegram)) {
|
|
14983
|
+
if (entry3.id === botId) hits.push({ accountId: a.accountId, accountDir: a.accountDir, entry: entry3 });
|
|
14923
14984
|
}
|
|
14924
14985
|
}
|
|
14925
14986
|
if (hits.length === 0) return { kind: "none" };
|
|
@@ -16964,7 +17025,7 @@ function createSidecarStore(config) {
|
|
|
16964
17025
|
function readAll3(sessionsDir, onSkip) {
|
|
16965
17026
|
let names;
|
|
16966
17027
|
try {
|
|
16967
|
-
names = readdirSync17(sessionsDir, { withFileTypes: true }).filter((
|
|
17028
|
+
names = readdirSync17(sessionsDir, { withFileTypes: true }).filter((entry3) => entry3.isFile()).map((entry3) => entry3.name);
|
|
16968
17029
|
} catch {
|
|
16969
17030
|
return [];
|
|
16970
17031
|
}
|
|
@@ -17897,7 +17958,7 @@ async function setTelegramWebhook(botToken, webhookUrl, secretFilePath, fetchImp
|
|
|
17897
17958
|
}
|
|
17898
17959
|
return { ok: true, secret };
|
|
17899
17960
|
}
|
|
17900
|
-
function writeTelegramBotEntry(accountDir,
|
|
17961
|
+
function writeTelegramBotEntry(accountDir, entry3) {
|
|
17901
17962
|
const configPath3 = join36(accountDir, "account.json");
|
|
17902
17963
|
if (!existsSync25(configPath3)) {
|
|
17903
17964
|
return { ok: false, error: `account.json not found at ${configPath3}` };
|
|
@@ -17910,9 +17971,9 @@ function writeTelegramBotEntry(accountDir, entry2) {
|
|
|
17910
17971
|
}
|
|
17911
17972
|
const telegram = config.telegram ?? {};
|
|
17912
17973
|
const bots = Array.isArray(telegram.bots) ? telegram.bots : [];
|
|
17913
|
-
const at = bots.findIndex((b) => b && typeof b === "object" && b.id ===
|
|
17914
|
-
if (at >= 0) bots[at] =
|
|
17915
|
-
else bots.push(
|
|
17974
|
+
const at = bots.findIndex((b) => b && typeof b === "object" && b.id === entry3.id);
|
|
17975
|
+
if (at >= 0) bots[at] = entry3;
|
|
17976
|
+
else bots.push(entry3);
|
|
17916
17977
|
telegram.bots = bots;
|
|
17917
17978
|
config.telegram = telegram;
|
|
17918
17979
|
writeFileSync12(configPath3, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
@@ -17998,34 +18059,34 @@ function getTelegramGateway() {
|
|
|
17998
18059
|
|
|
17999
18060
|
// app/lib/telegram/access-control.ts
|
|
18000
18061
|
function checkTelegramAccess(params) {
|
|
18001
|
-
const { senderId, entry:
|
|
18062
|
+
const { senderId, entry: entry3, chatId, chatType } = params;
|
|
18002
18063
|
const isGroup = chatType === "group" || chatType === "supergroup";
|
|
18003
18064
|
const isChannel = chatType === "channel";
|
|
18004
|
-
if (isChannel &&
|
|
18065
|
+
if (isChannel && entry3.role !== "public") {
|
|
18005
18066
|
return {
|
|
18006
18067
|
allowed: false,
|
|
18007
|
-
reason:
|
|
18008
|
-
agentType:
|
|
18068
|
+
reason: entry3.role === "admin" ? "admin-entry-no-channels" : entry3.role === "specialist" ? "specialist-entry-no-channels" : "unbound-entry-no-channels",
|
|
18069
|
+
agentType: entry3.role === "admin" ? "admin" : entry3.role === "specialist" ? "specialist" : "public"
|
|
18009
18070
|
};
|
|
18010
18071
|
}
|
|
18011
|
-
if (isGroup &&
|
|
18072
|
+
if (isGroup && entry3.role !== "public") {
|
|
18012
18073
|
return {
|
|
18013
18074
|
allowed: false,
|
|
18014
|
-
reason:
|
|
18015
|
-
agentType:
|
|
18075
|
+
reason: entry3.role === "admin" ? "admin-entry-no-groups" : entry3.role === "specialist" ? "specialist-entry-no-groups" : "unbound-entry-no-groups",
|
|
18076
|
+
agentType: entry3.role === "admin" ? "admin" : entry3.role === "specialist" ? "specialist" : "public"
|
|
18016
18077
|
};
|
|
18017
18078
|
}
|
|
18018
|
-
if (
|
|
18019
|
-
const adminUsers =
|
|
18079
|
+
if (entry3.role === "admin") {
|
|
18080
|
+
const adminUsers = entry3.adminUsers ?? [];
|
|
18020
18081
|
if (adminUsers.includes(senderId)) {
|
|
18021
18082
|
return { allowed: true, reason: "admin-binding", agentType: "admin" };
|
|
18022
18083
|
}
|
|
18023
18084
|
return { allowed: false, reason: "not-admin-user", agentType: "admin" };
|
|
18024
18085
|
}
|
|
18025
|
-
if (isGroup &&
|
|
18026
|
-
const groupPolicy =
|
|
18086
|
+
if (isGroup && entry3.role === "public") {
|
|
18087
|
+
const groupPolicy = entry3.groupPolicy ?? "disabled";
|
|
18027
18088
|
if (groupPolicy === "allowlist") {
|
|
18028
|
-
const allowGroups =
|
|
18089
|
+
const allowGroups = entry3.allowGroups ?? [];
|
|
18029
18090
|
if (allowGroups.includes(chatId)) {
|
|
18030
18091
|
return { allowed: true, reason: "group-allowlist-match", agentType: "public" };
|
|
18031
18092
|
}
|
|
@@ -18033,10 +18094,10 @@ function checkTelegramAccess(params) {
|
|
|
18033
18094
|
}
|
|
18034
18095
|
return { allowed: false, reason: "group-policy-disabled", agentType: "public" };
|
|
18035
18096
|
}
|
|
18036
|
-
if (isChannel &&
|
|
18037
|
-
const channelPolicy =
|
|
18097
|
+
if (isChannel && entry3.role === "public") {
|
|
18098
|
+
const channelPolicy = entry3.channelPolicy ?? "disabled";
|
|
18038
18099
|
if (channelPolicy === "allowlist") {
|
|
18039
|
-
const allowChannels =
|
|
18100
|
+
const allowChannels = entry3.allowChannels ?? [];
|
|
18040
18101
|
if (allowChannels.includes(chatId)) {
|
|
18041
18102
|
return { allowed: true, reason: "channel-allowlist-match", agentType: "public" };
|
|
18042
18103
|
}
|
|
@@ -18044,22 +18105,22 @@ function checkTelegramAccess(params) {
|
|
|
18044
18105
|
}
|
|
18045
18106
|
return { allowed: false, reason: "channel-policy-disabled", agentType: "public" };
|
|
18046
18107
|
}
|
|
18047
|
-
if (
|
|
18108
|
+
if (entry3.role === "unbound") {
|
|
18048
18109
|
return { allowed: false, reason: "bot-unbound", agentType: "public" };
|
|
18049
18110
|
}
|
|
18050
|
-
if (
|
|
18051
|
-
const allowFrom =
|
|
18111
|
+
if (entry3.role === "specialist") {
|
|
18112
|
+
const allowFrom = entry3.allowFrom ?? [];
|
|
18052
18113
|
if (allowFrom.includes(senderId)) {
|
|
18053
18114
|
return { allowed: true, reason: "specialist-allowlist-match", agentType: "specialist" };
|
|
18054
18115
|
}
|
|
18055
18116
|
return { allowed: false, reason: "not-in-allowlist", agentType: "specialist" };
|
|
18056
18117
|
}
|
|
18057
|
-
const policy =
|
|
18118
|
+
const policy = entry3.dmPolicy ?? "disabled";
|
|
18058
18119
|
switch (policy) {
|
|
18059
18120
|
case "open":
|
|
18060
18121
|
return { allowed: true, reason: "dm-policy-open", agentType: "public" };
|
|
18061
18122
|
case "allowlist": {
|
|
18062
|
-
const allowFrom =
|
|
18123
|
+
const allowFrom = entry3.allowFrom ?? [];
|
|
18063
18124
|
if (allowFrom.includes(senderId)) {
|
|
18064
18125
|
return { allowed: true, reason: "allowlist-match", agentType: "public" };
|
|
18065
18126
|
}
|
|
@@ -19082,6 +19143,9 @@ function runTelegramNotifyReconcile(now) {
|
|
|
19082
19143
|
console.error(buildTelegramKindCensusLine(readTelegramKindCensus()));
|
|
19083
19144
|
}
|
|
19084
19145
|
|
|
19146
|
+
// server/routes/telegram.ts
|
|
19147
|
+
var import_dist8 = __toESM(require_dist5(), 1);
|
|
19148
|
+
|
|
19085
19149
|
// app/lib/telegram/outbound/answer-callback.ts
|
|
19086
19150
|
async function answerTelegramCallback(botToken, callbackQueryId, text) {
|
|
19087
19151
|
try {
|
|
@@ -19114,8 +19178,8 @@ var NOTIFY_MAX = 5e3;
|
|
|
19114
19178
|
var cache = /* @__PURE__ */ new Map();
|
|
19115
19179
|
function isTelegramNotifyDuplicate(notifyId) {
|
|
19116
19180
|
const now = Date.now();
|
|
19117
|
-
const
|
|
19118
|
-
if (
|
|
19181
|
+
const entry3 = cache.get(notifyId);
|
|
19182
|
+
if (entry3 && now - entry3.ts <= NOTIFY_TTL_MS) return true;
|
|
19119
19183
|
for (const [key2, e] of cache) {
|
|
19120
19184
|
if (now - e.ts > NOTIFY_TTL_MS) cache.delete(key2);
|
|
19121
19185
|
}
|
|
@@ -19174,7 +19238,7 @@ function runTelegramNotifyPublishCensus(now) {
|
|
|
19174
19238
|
}
|
|
19175
19239
|
|
|
19176
19240
|
// ../lib/dispatch-write/src/lifecycle.ts
|
|
19177
|
-
var import_dist6 = __toESM(
|
|
19241
|
+
var import_dist6 = __toESM(require_dist6());
|
|
19178
19242
|
function checkTransition(kind, from, to, cfg) {
|
|
19179
19243
|
const edges = kind === "job" ? cfg.statuses.jobTransitions : cfg.statuses.visitTransitions;
|
|
19180
19244
|
const legal = edges.some(([f, t]) => f === from && t === to);
|
|
@@ -19216,7 +19280,7 @@ function formatTransitionRefused(p) {
|
|
|
19216
19280
|
}
|
|
19217
19281
|
|
|
19218
19282
|
// ../lib/dispatch-write/src/write.ts
|
|
19219
|
-
var import_dist7 = __toESM(
|
|
19283
|
+
var import_dist7 = __toESM(require_dist6());
|
|
19220
19284
|
function refuse(reason, message) {
|
|
19221
19285
|
return { ok: false, reason, message };
|
|
19222
19286
|
}
|
|
@@ -19793,8 +19857,8 @@ function liveLocationCensusLine(accountsRoot, now) {
|
|
|
19793
19857
|
let expired = 0;
|
|
19794
19858
|
let oldestAgeMs = 0;
|
|
19795
19859
|
try {
|
|
19796
|
-
for (const
|
|
19797
|
-
const path = join38(accountsRoot,
|
|
19860
|
+
for (const entry3 of readdirSync20(accountsRoot)) {
|
|
19861
|
+
const path = join38(accountsRoot, entry3, LIVE_LOCATION_FILE);
|
|
19798
19862
|
if (!existsSync26(path) || !statSync19(path).isFile()) continue;
|
|
19799
19863
|
for (const rec of Object.values(readAll(path))) {
|
|
19800
19864
|
records3 += 1;
|
|
@@ -19930,20 +19994,20 @@ async function editTelegramMessage(botToken, chatId, messageId, text, keyboard)
|
|
|
19930
19994
|
// server/routes/telegram.ts
|
|
19931
19995
|
var TAG34 = "[telegram-inbound]";
|
|
19932
19996
|
var PROVISION_TAG = "[telegram-provision]";
|
|
19933
|
-
function entryActive(
|
|
19934
|
-
if (
|
|
19935
|
-
if (
|
|
19997
|
+
function entryActive(entry3, accountDir, botId, noteSpecialist) {
|
|
19998
|
+
if (entry3.role === "admin") return true;
|
|
19999
|
+
if (entry3.role === "specialist") {
|
|
19936
20000
|
const cards = listSpecialistCardNames(join40(accountDir, "specialists", "agents"));
|
|
19937
|
-
const rosterValid = cards.includes(
|
|
20001
|
+
const rosterValid = cards.includes(entry3.specialist);
|
|
19938
20002
|
noteSpecialist?.(rosterValid);
|
|
19939
20003
|
if (rosterValid) return true;
|
|
19940
20004
|
console.error(
|
|
19941
|
-
`${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(
|
|
20005
|
+
`${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=specialist-unknown`
|
|
19942
20006
|
);
|
|
19943
20007
|
return false;
|
|
19944
20008
|
}
|
|
19945
|
-
if (
|
|
19946
|
-
return isActiveAgentSlug(accountDir,
|
|
20009
|
+
if (entry3.role === "unbound") return false;
|
|
20010
|
+
return isActiveAgentSlug(accountDir, entry3.agent);
|
|
19947
20011
|
}
|
|
19948
20012
|
function logValue2(v) {
|
|
19949
20013
|
return v.replace(/[\r\n]+/g, " ");
|
|
@@ -20055,9 +20119,9 @@ app11.post("/", async (c) => {
|
|
|
20055
20119
|
console.error(`${TAG34} op=reject reason=duplicate-bot-id botId=${botId} accounts=${resolved.count}`);
|
|
20056
20120
|
return c.json({ ok: false }, 401);
|
|
20057
20121
|
}
|
|
20058
|
-
const { accountId, accountDir, entry:
|
|
20059
|
-
const agentSlug = entryAgentSlug(
|
|
20060
|
-
console.error(`${TAG34} op=entry botId=${botId} accountId=${accountId} role=${
|
|
20122
|
+
const { accountId, accountDir, entry: entry3 } = resolved;
|
|
20123
|
+
const agentSlug = entryAgentSlug(entry3);
|
|
20124
|
+
console.error(`${TAG34} op=entry botId=${botId} accountId=${accountId} role=${entry3.role} agent=${agentSlug}`);
|
|
20061
20125
|
const sp = secretPath(botId);
|
|
20062
20126
|
if (!existsSync28(sp)) {
|
|
20063
20127
|
console.error(`${TAG34} op=secret botId=${botId} result=missing-file`);
|
|
@@ -20090,13 +20154,13 @@ app11.post("/", async (c) => {
|
|
|
20090
20154
|
});
|
|
20091
20155
|
}
|
|
20092
20156
|
if (shape.chatType === "group" || shape.chatType === "supergroup") {
|
|
20093
|
-
const allowlisted =
|
|
20157
|
+
const allowlisted = entry3.role === "public" && (entry3.groupPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry3.allowGroups ?? []).includes(shape.chatId);
|
|
20094
20158
|
console.error(
|
|
20095
20159
|
`${TAG34} op=group-inbound botId=${botId} chatType=${shape.chatType} chatId=${shape.chatId ?? "none"} senderId=${shape.senderId ?? "none"} threadId=${shape.threadId ?? "none"} allowlisted=${allowlisted ? "yes" : "no"}`
|
|
20096
20160
|
);
|
|
20097
20161
|
}
|
|
20098
20162
|
if (shape.chatType === "channel") {
|
|
20099
|
-
const allowlisted =
|
|
20163
|
+
const allowlisted = entry3.role === "public" && (entry3.channelPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry3.allowChannels ?? []).includes(shape.chatId);
|
|
20100
20164
|
console.error(
|
|
20101
20165
|
`${TAG34} op=channel-post botId=${botId} chatId=${shape.chatId ?? "none"} messageId=${shape.messageId ?? "none"} senderChat=${shape.senderChat ?? "none"} isEdit=${shape.isEdit ? "yes" : "no"} allowlisted=${allowlisted ? "yes" : "no"}`
|
|
20102
20166
|
);
|
|
@@ -20104,7 +20168,7 @@ app11.post("/", async (c) => {
|
|
|
20104
20168
|
const hostBots = update.managed_bot ? listBotEntries(accountConfig(accountDir).telegram) : [];
|
|
20105
20169
|
const decision = routeTelegramUpdate({
|
|
20106
20170
|
update,
|
|
20107
|
-
entry:
|
|
20171
|
+
entry: entry3,
|
|
20108
20172
|
...update.managed_bot ? { knownBotIds: hostBots.map((b) => b.id) } : {}
|
|
20109
20173
|
});
|
|
20110
20174
|
const raisesTurn = decision.kind === "dispatch" || // Task 2615 — a customer asking a question raises one. `business-deleted`
|
|
@@ -20134,14 +20198,14 @@ app11.post("/", async (c) => {
|
|
|
20134
20198
|
);
|
|
20135
20199
|
}
|
|
20136
20200
|
console.error(`${TAG34} op=access botId=${botId} senderId=- allowed=false reason=${decision.reason}`);
|
|
20137
|
-
if (
|
|
20201
|
+
if (entry3.role === "specialist") {
|
|
20138
20202
|
console.error(
|
|
20139
|
-
`${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(
|
|
20203
|
+
`${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=${decision.reason}`
|
|
20140
20204
|
);
|
|
20141
20205
|
}
|
|
20142
20206
|
return c.json({ ok: true }, 200);
|
|
20143
20207
|
}
|
|
20144
|
-
if (!isBindableEntry(
|
|
20208
|
+
if (!isBindableEntry(entry3)) {
|
|
20145
20209
|
console.error(`${TAG34} op=ignore botId=${botId} reason=bot-unbound`);
|
|
20146
20210
|
return c.json({ ok: true }, 200);
|
|
20147
20211
|
}
|
|
@@ -20174,19 +20238,30 @@ app11.post("/", async (c) => {
|
|
|
20174
20238
|
if (decision.allowed) {
|
|
20175
20239
|
const cbKey = telegramChannelKey(botId, cbSubject);
|
|
20176
20240
|
const cbAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20241
|
+
let cbBody = `[button: ${decision.data ?? "no-data"}]`;
|
|
20242
|
+
if (decision.data !== null) {
|
|
20243
|
+
const label = (0, import_dist8.readButtonLabel)(accountDir, (0, import_dist8.buttonLabelKey)(botId, decision.chatId, decision.data));
|
|
20244
|
+
if (label !== null) {
|
|
20245
|
+
cbBody = label;
|
|
20246
|
+
} else {
|
|
20247
|
+
console.error(
|
|
20248
|
+
`${TAG34} op=button-label-miss botId=${botId} chatId=${decision.chatId} data=${logValue2(decision.data)}`
|
|
20249
|
+
);
|
|
20250
|
+
}
|
|
20251
|
+
}
|
|
20177
20252
|
appendMessage2(accountId, {
|
|
20178
20253
|
messageId: `telegram:${accountId}:${cbKey}:cb:${decision.callbackId}`,
|
|
20179
20254
|
// Task 2598 — the one shared derivation, so this row names the session
|
|
20180
20255
|
// the press actually reaches.
|
|
20181
20256
|
sessionId: telegramAdminSessionId(accountId, cbSubject, botId),
|
|
20182
20257
|
dateSent: cbAt,
|
|
20183
|
-
body:
|
|
20258
|
+
body: cbBody,
|
|
20184
20259
|
fromMe: false,
|
|
20185
20260
|
senderId: decision.senderId,
|
|
20186
20261
|
senderName: decision.senderDisplay,
|
|
20187
20262
|
chatId: String(decision.chatId),
|
|
20188
20263
|
channelKey: cbKey,
|
|
20189
|
-
scope:
|
|
20264
|
+
scope: entry3.role === "admin" ? "admin" : "public",
|
|
20190
20265
|
origin: "inbound",
|
|
20191
20266
|
createdAt: cbAt
|
|
20192
20267
|
});
|
|
@@ -20202,7 +20277,7 @@ app11.post("/", async (c) => {
|
|
|
20202
20277
|
session,
|
|
20203
20278
|
accountId,
|
|
20204
20279
|
cfg: load.value,
|
|
20205
|
-
token:
|
|
20280
|
+
token: entry3.token,
|
|
20206
20281
|
botId,
|
|
20207
20282
|
updateId: decision.updateId,
|
|
20208
20283
|
chatId: decision.chatId,
|
|
@@ -20228,22 +20303,22 @@ app11.post("/", async (c) => {
|
|
|
20228
20303
|
}
|
|
20229
20304
|
}
|
|
20230
20305
|
const answerStartedAt = Date.now();
|
|
20231
|
-
const answered4 = await answerTelegramCallback(
|
|
20306
|
+
const answered4 = await answerTelegramCallback(entry3.token, decision.callbackId, answerText);
|
|
20232
20307
|
const outcome = !answered4.ok ? "error" : decision.allowed ? "stored" : "refused";
|
|
20233
20308
|
console.error(
|
|
20234
20309
|
`${TAG34} op=callback-answered botId=${botId} callbackId=${decision.callbackId} ms=${Date.now() - answerStartedAt} outcome=${outcome}${answered4.error ? ` error=${logValue2(answered4.error)}` : ""}`
|
|
20235
20310
|
);
|
|
20236
20311
|
if (decision.allowed && parseDispatchCallback(decision.data) === null) {
|
|
20237
|
-
const cbActive = entryActive(
|
|
20312
|
+
const cbActive = entryActive(entry3, accountDir, botId);
|
|
20238
20313
|
console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${cbActive}`);
|
|
20239
20314
|
raiseChannelTurn({
|
|
20240
20315
|
accountId,
|
|
20241
20316
|
accountDir,
|
|
20242
20317
|
botId,
|
|
20243
|
-
botToken:
|
|
20244
|
-
role:
|
|
20318
|
+
botToken: entry3.token,
|
|
20319
|
+
role: entry3.role,
|
|
20245
20320
|
agentSlug,
|
|
20246
|
-
specialist:
|
|
20321
|
+
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20247
20322
|
active: cbActive,
|
|
20248
20323
|
senderId: decision.senderId,
|
|
20249
20324
|
senderDisplay: decision.senderDisplay,
|
|
@@ -20253,7 +20328,7 @@ app11.post("/", async (c) => {
|
|
|
20253
20328
|
text: `[button: ${decision.data ?? "no-data"}]`,
|
|
20254
20329
|
channelKey: telegramChannelKey(botId, cbSubject),
|
|
20255
20330
|
conversationSubject: cbSubject,
|
|
20256
|
-
scope:
|
|
20331
|
+
scope: entry3.role === "admin" ? "admin" : "public",
|
|
20257
20332
|
sessionId: telegramAdminSessionId(accountId, cbSubject, botId)
|
|
20258
20333
|
});
|
|
20259
20334
|
}
|
|
@@ -20269,7 +20344,7 @@ app11.post("/", async (c) => {
|
|
|
20269
20344
|
);
|
|
20270
20345
|
if (!decision.allowed) return c.json({ ok: true }, 200);
|
|
20271
20346
|
const pollKey = telegramChannelKey(botId, decision.senderId);
|
|
20272
|
-
const pollScope =
|
|
20347
|
+
const pollScope = entry3.role === "admin" ? "admin" : "public";
|
|
20273
20348
|
const pollSession = telegramAdminSessionId(accountId, decision.senderId, botId);
|
|
20274
20349
|
const pollAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20275
20350
|
const pollBody = `[poll vote: poll=${decision.pollId} options=${options}]`;
|
|
@@ -20287,16 +20362,16 @@ app11.post("/", async (c) => {
|
|
|
20287
20362
|
origin: "inbound",
|
|
20288
20363
|
createdAt: pollAt
|
|
20289
20364
|
});
|
|
20290
|
-
const pollActive = entryActive(
|
|
20365
|
+
const pollActive = entryActive(entry3, accountDir, botId);
|
|
20291
20366
|
console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${pollActive}`);
|
|
20292
20367
|
raiseChannelTurn({
|
|
20293
20368
|
accountId,
|
|
20294
20369
|
accountDir,
|
|
20295
20370
|
botId,
|
|
20296
|
-
botToken:
|
|
20297
|
-
role:
|
|
20371
|
+
botToken: entry3.token,
|
|
20372
|
+
role: entry3.role,
|
|
20298
20373
|
agentSlug,
|
|
20299
|
-
specialist:
|
|
20374
|
+
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20300
20375
|
active: pollActive,
|
|
20301
20376
|
senderId: decision.senderId,
|
|
20302
20377
|
senderDisplay: decision.senderDisplay,
|
|
@@ -20320,7 +20395,7 @@ app11.post("/", async (c) => {
|
|
|
20320
20395
|
`${TAG34} op=reaction-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
|
|
20321
20396
|
);
|
|
20322
20397
|
if (!decision.allowed) return c.json({ ok: true }, 200);
|
|
20323
|
-
const rScope =
|
|
20398
|
+
const rScope = entry3.role === "admin" ? "admin" : "public";
|
|
20324
20399
|
const rSession = telegramAdminSessionId(accountId, rSubject, botId);
|
|
20325
20400
|
const rAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20326
20401
|
const rTarget = quotedBody === null ? `message ${decision.messageId} \u2014 not held in this conversation` : `"${quotedBody}"`;
|
|
@@ -20339,16 +20414,16 @@ app11.post("/", async (c) => {
|
|
|
20339
20414
|
origin: "inbound",
|
|
20340
20415
|
createdAt: rAt
|
|
20341
20416
|
});
|
|
20342
|
-
const rActive = entryActive(
|
|
20417
|
+
const rActive = entryActive(entry3, accountDir, botId);
|
|
20343
20418
|
console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${rActive}`);
|
|
20344
20419
|
raiseChannelTurn({
|
|
20345
20420
|
accountId,
|
|
20346
20421
|
accountDir,
|
|
20347
20422
|
botId,
|
|
20348
|
-
botToken:
|
|
20349
|
-
role:
|
|
20423
|
+
botToken: entry3.token,
|
|
20424
|
+
role: entry3.role,
|
|
20350
20425
|
agentSlug,
|
|
20351
|
-
specialist:
|
|
20426
|
+
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20352
20427
|
active: rActive,
|
|
20353
20428
|
senderId: decision.senderId,
|
|
20354
20429
|
senderDisplay: decision.senderDisplay,
|
|
@@ -20386,7 +20461,7 @@ app11.post("/", async (c) => {
|
|
|
20386
20461
|
);
|
|
20387
20462
|
if (!decision.allowed) return c.json({ ok: true }, 200);
|
|
20388
20463
|
const sKey = telegramChannelKey(botId, decision.senderId);
|
|
20389
|
-
const sScope =
|
|
20464
|
+
const sScope = entry3.role === "admin" ? "admin" : "public";
|
|
20390
20465
|
const sSession = telegramAdminSessionId(accountId, decision.senderId, botId);
|
|
20391
20466
|
const sAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20392
20467
|
const sBody = `[subscription ${decision.state}: payload=${decision.payload}]`;
|
|
@@ -20404,16 +20479,16 @@ app11.post("/", async (c) => {
|
|
|
20404
20479
|
origin: "inbound",
|
|
20405
20480
|
createdAt: sAt
|
|
20406
20481
|
});
|
|
20407
|
-
const sActive = entryActive(
|
|
20482
|
+
const sActive = entryActive(entry3, accountDir, botId);
|
|
20408
20483
|
console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${sActive}`);
|
|
20409
20484
|
raiseChannelTurn({
|
|
20410
20485
|
accountId,
|
|
20411
20486
|
accountDir,
|
|
20412
20487
|
botId,
|
|
20413
|
-
botToken:
|
|
20414
|
-
role:
|
|
20488
|
+
botToken: entry3.token,
|
|
20489
|
+
role: entry3.role,
|
|
20415
20490
|
agentSlug,
|
|
20416
|
-
specialist:
|
|
20491
|
+
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20417
20492
|
active: sActive,
|
|
20418
20493
|
senderId: decision.senderId,
|
|
20419
20494
|
senderDisplay: decision.senderDisplay,
|
|
@@ -20432,7 +20507,7 @@ app11.post("/", async (c) => {
|
|
|
20432
20507
|
`${TAG34} op=poll-closed botId=${botId} pollId=${logValue2(decision.pollId)} options=${decision.options.length} totalVotes=${decision.totalVotes} targetHeld=${where === null ? "no" : "yes"}`
|
|
20433
20508
|
);
|
|
20434
20509
|
if (where === null) return c.json({ ok: true }, 200);
|
|
20435
|
-
const plScope =
|
|
20510
|
+
const plScope = entry3.role === "admin" ? "admin" : "public";
|
|
20436
20511
|
const plSession = telegramAdminSessionId(accountId, where.senderId, botId);
|
|
20437
20512
|
const plAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20438
20513
|
const tally = decision.options.map((o) => `${o.text}:${o.votes}`).join(", ") || "no options";
|
|
@@ -20451,16 +20526,16 @@ app11.post("/", async (c) => {
|
|
|
20451
20526
|
origin: "inbound",
|
|
20452
20527
|
createdAt: plAt
|
|
20453
20528
|
});
|
|
20454
|
-
const plActive = entryActive(
|
|
20529
|
+
const plActive = entryActive(entry3, accountDir, botId);
|
|
20455
20530
|
console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${plActive}`);
|
|
20456
20531
|
raiseChannelTurn({
|
|
20457
20532
|
accountId,
|
|
20458
20533
|
accountDir,
|
|
20459
20534
|
botId,
|
|
20460
|
-
botToken:
|
|
20461
|
-
role:
|
|
20535
|
+
botToken: entry3.token,
|
|
20536
|
+
role: entry3.role,
|
|
20462
20537
|
agentSlug,
|
|
20463
|
-
specialist:
|
|
20538
|
+
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20464
20539
|
active: plActive,
|
|
20465
20540
|
senderId: where.senderId,
|
|
20466
20541
|
chatId: Number(where.chatId),
|
|
@@ -20489,7 +20564,7 @@ app11.post("/", async (c) => {
|
|
|
20489
20564
|
console.error(
|
|
20490
20565
|
`${TAG34} op=managed-bot botId=${botId} event=${event} newBotId=${newBotId} creator=${decision.creatorId ?? "none"}`
|
|
20491
20566
|
);
|
|
20492
|
-
const fetched = await getManagedBotToken(
|
|
20567
|
+
const fetched = await getManagedBotToken(entry3.token, Number(newBotId));
|
|
20493
20568
|
console.error(
|
|
20494
20569
|
`${PROVISION_TAG} op=provision-token botId=${botId} newBotId=${newBotId} fetched=${fetched.ok ? "yes" : "no"} reason=${fetched.ok ? "ok" : "api-error"}`
|
|
20495
20570
|
);
|
|
@@ -20499,7 +20574,7 @@ app11.post("/", async (c) => {
|
|
|
20499
20574
|
accountDir,
|
|
20500
20575
|
existing ? { ...existing, token: fetched.token, managed: true } : { id: newBotId, token: fetched.token, role: "unbound", managed: true }
|
|
20501
20576
|
);
|
|
20502
|
-
const restricted = await setManagedBotAccessSettings(
|
|
20577
|
+
const restricted = await setManagedBotAccessSettings(entry3.token, Number(newBotId), true, void 0);
|
|
20503
20578
|
console.error(
|
|
20504
20579
|
`${PROVISION_TAG} op=provision-persist botId=${botId} newBotId=${newBotId} written=${persisted.ok ? "yes" : "no"} restricted=${restricted.ok ? "yes" : "no"}`
|
|
20505
20580
|
);
|
|
@@ -20515,7 +20590,7 @@ app11.post("/", async (c) => {
|
|
|
20515
20590
|
accountId,
|
|
20516
20591
|
accountDir,
|
|
20517
20592
|
botId,
|
|
20518
|
-
botToken:
|
|
20593
|
+
botToken: entry3.token,
|
|
20519
20594
|
// `authorised` above already established this entry is role 'admin', so
|
|
20520
20595
|
// the admin agent is the one that runs and it is active by construction.
|
|
20521
20596
|
role: "admin",
|
|
@@ -20588,7 +20663,7 @@ app11.post("/", async (c) => {
|
|
|
20588
20663
|
});
|
|
20589
20664
|
}
|
|
20590
20665
|
const bizMedia = await downloadTelegramMedia({
|
|
20591
|
-
token:
|
|
20666
|
+
token: entry3.token,
|
|
20592
20667
|
botId,
|
|
20593
20668
|
items: decision.media
|
|
20594
20669
|
});
|
|
@@ -20628,7 +20703,7 @@ app11.post("/", async (c) => {
|
|
|
20628
20703
|
return;
|
|
20629
20704
|
}
|
|
20630
20705
|
const sent = await sendTelegramText(
|
|
20631
|
-
|
|
20706
|
+
entry3.token,
|
|
20632
20707
|
decision.chatId,
|
|
20633
20708
|
replyText,
|
|
20634
20709
|
void 0,
|
|
@@ -20657,7 +20732,7 @@ app11.post("/", async (c) => {
|
|
|
20657
20732
|
accountId,
|
|
20658
20733
|
accountDir,
|
|
20659
20734
|
botId,
|
|
20660
|
-
botToken:
|
|
20735
|
+
botToken: entry3.token,
|
|
20661
20736
|
agentSlug,
|
|
20662
20737
|
senderId: decision.senderId,
|
|
20663
20738
|
// Task 2615 — load-bearing. The gateway keys the hub, the reply closure,
|
|
@@ -20707,7 +20782,7 @@ app11.post("/", async (c) => {
|
|
|
20707
20782
|
console.error(`${TAG34} op=access botId=${botId} senderId=${senderId} allowed=true reason=${decision.reason}`);
|
|
20708
20783
|
const subject = telegramConversationSubject(decision.chatType, chatId, senderId);
|
|
20709
20784
|
const channelKey = telegramChannelKey(botId, subject);
|
|
20710
|
-
const scope =
|
|
20785
|
+
const scope = entry3.role === "public" ? "public" : "admin";
|
|
20711
20786
|
const sessionId = telegramAdminSessionId(accountId, subject, botId);
|
|
20712
20787
|
const inboundAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20713
20788
|
const editSuffix = decision.isEdit ? `:edit:${decision.editDate}` : "";
|
|
@@ -20788,10 +20863,10 @@ app11.post("/", async (c) => {
|
|
|
20788
20863
|
});
|
|
20789
20864
|
}
|
|
20790
20865
|
}
|
|
20791
|
-
const active = entryActive(
|
|
20792
|
-
if (
|
|
20866
|
+
const active = entryActive(entry3, accountDir, botId, (rosterValid) => {
|
|
20867
|
+
if (entry3.role !== "specialist") return;
|
|
20793
20868
|
console.error(
|
|
20794
|
-
`${TAG34} op=specialist-inbound botId=${botId} specialist=${logValue2(
|
|
20869
|
+
`${TAG34} op=specialist-inbound botId=${botId} specialist=${logValue2(entry3.specialist)} senderId=${senderId} sessionId=${sessionId} rosterValid=${rosterValid ? "yes" : "no"}`
|
|
20795
20870
|
);
|
|
20796
20871
|
});
|
|
20797
20872
|
console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${active}`);
|
|
@@ -20806,7 +20881,7 @@ app11.post("/", async (c) => {
|
|
|
20806
20881
|
}
|
|
20807
20882
|
const replyThreadId = decision.threadId ?? void 0;
|
|
20808
20883
|
const reply = async (replyText) => {
|
|
20809
|
-
const sent = await sendTelegramText(
|
|
20884
|
+
const sent = await sendTelegramText(entry3.token, chatId, replyText, replyThreadId);
|
|
20810
20885
|
if (sent.ok) {
|
|
20811
20886
|
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
20812
20887
|
appendMessage2(accountId, {
|
|
@@ -20826,7 +20901,7 @@ app11.post("/", async (c) => {
|
|
|
20826
20901
|
console.error(`${TAG34} op=reply-sent botId=${botId} ok=true`);
|
|
20827
20902
|
} else console.error(`${TAG34} op=reply-dropped botId=${botId} reason=${sent.error}`);
|
|
20828
20903
|
};
|
|
20829
|
-
const media = await downloadTelegramMedia({ token:
|
|
20904
|
+
const media = await downloadTelegramMedia({ token: entry3.token, botId, items: decision.media });
|
|
20830
20905
|
if (media.length > 0) {
|
|
20831
20906
|
const attachmentIds = await storeTelegramServable({
|
|
20832
20907
|
accountId,
|
|
@@ -20952,7 +21027,7 @@ app11.post("/", async (c) => {
|
|
|
20952
21027
|
accountId,
|
|
20953
21028
|
accountDir,
|
|
20954
21029
|
botId,
|
|
20955
|
-
botToken:
|
|
21030
|
+
botToken: entry3.token,
|
|
20956
21031
|
agentSlug,
|
|
20957
21032
|
senderId,
|
|
20958
21033
|
// Task 2616 — the name beside the id on the turn's provenance line.
|
|
@@ -20962,10 +21037,10 @@ app11.post("/", async (c) => {
|
|
|
20962
21037
|
// room reach one channel server rather than opening five sessions whose
|
|
20963
21038
|
// reply closures all target the same chat. A DM subject IS the sender id.
|
|
20964
21039
|
conversationSubject: subject,
|
|
20965
|
-
role:
|
|
21040
|
+
role: entry3.role,
|
|
20966
21041
|
personId: null,
|
|
20967
21042
|
// Task 2619 — the card this bot runs as, null on every other role.
|
|
20968
|
-
specialist:
|
|
21043
|
+
specialist: entry3.role === "specialist" ? entry3.specialist : null,
|
|
20969
21044
|
chatId: String(chatId),
|
|
20970
21045
|
text: turnText,
|
|
20971
21046
|
media: heard.media,
|
|
@@ -21369,9 +21444,9 @@ function computeAdminStoreDivergence(input) {
|
|
|
21369
21444
|
result.errors.push({ source: input.accountsDir, detail: err instanceof Error ? err.message : String(err) });
|
|
21370
21445
|
return result;
|
|
21371
21446
|
}
|
|
21372
|
-
for (const
|
|
21373
|
-
if (
|
|
21374
|
-
const accountDir = join42(input.accountsDir,
|
|
21447
|
+
for (const entry3 of entries2) {
|
|
21448
|
+
if (entry3.startsWith(".")) continue;
|
|
21449
|
+
const accountDir = join42(input.accountsDir, entry3);
|
|
21375
21450
|
try {
|
|
21376
21451
|
if (!statSync20(accountDir).isDirectory()) continue;
|
|
21377
21452
|
} catch {
|
|
@@ -23508,12 +23583,12 @@ function authoredAgentFiles(accountDir) {
|
|
|
23508
23583
|
const dir = resolve28(pluginsDir, plugin, "agents");
|
|
23509
23584
|
if (!existsSync38(dir)) continue;
|
|
23510
23585
|
try {
|
|
23511
|
-
for (const
|
|
23512
|
-
if (!
|
|
23513
|
-
const path = resolve28(dir,
|
|
23514
|
-
const paths = byName.get(
|
|
23586
|
+
for (const entry3 of readdirSync24(dir)) {
|
|
23587
|
+
if (!entry3.endsWith(".md")) continue;
|
|
23588
|
+
const path = resolve28(dir, entry3);
|
|
23589
|
+
const paths = byName.get(entry3);
|
|
23515
23590
|
if (paths) paths.push(path);
|
|
23516
|
-
else byName.set(
|
|
23591
|
+
else byName.set(entry3, [path]);
|
|
23517
23592
|
}
|
|
23518
23593
|
} catch (err) {
|
|
23519
23594
|
console.error(`[admin/agents] op=authored-scan read-failed plugin=${plugin} error="${err}"`);
|
|
@@ -23582,7 +23657,7 @@ function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed, author
|
|
|
23582
23657
|
for (const dir of dirs) {
|
|
23583
23658
|
if (!existsSync38(dir)) continue;
|
|
23584
23659
|
try {
|
|
23585
|
-
for (const
|
|
23660
|
+
for (const entry3 of readdirSync24(dir)) if (entry3.endsWith(".md")) names.add(entry3);
|
|
23586
23661
|
} catch (err) {
|
|
23587
23662
|
console.error(`[admin/agents] op=list-shipped read-failed dir=${dir} error="${err}"`);
|
|
23588
23663
|
}
|
|
@@ -23676,19 +23751,19 @@ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
|
|
|
23676
23751
|
} catch {
|
|
23677
23752
|
continue;
|
|
23678
23753
|
}
|
|
23679
|
-
for (const
|
|
23680
|
-
if (!
|
|
23754
|
+
for (const entry3 of entries2) {
|
|
23755
|
+
if (!entry3.isFile() || !entry3.name.endsWith(".md")) continue;
|
|
23681
23756
|
try {
|
|
23682
|
-
const { fm } = splitFrontmatter(readFileSync38(resolve28(agentsDirP,
|
|
23757
|
+
const { fm } = splitFrontmatter(readFileSync38(resolve28(agentsDirP, entry3.name), "utf-8"));
|
|
23683
23758
|
if (!fm.name) {
|
|
23684
23759
|
specialistsSkipped++;
|
|
23685
|
-
console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${
|
|
23760
|
+
console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry3.name}`);
|
|
23686
23761
|
continue;
|
|
23687
23762
|
}
|
|
23688
23763
|
const specialistTools = parseToolsLine(fm.tools);
|
|
23689
23764
|
const r = classify(specialistTools, riskByTool, riskSurfaceFailed);
|
|
23690
23765
|
specialists.push({
|
|
23691
|
-
slug:
|
|
23766
|
+
slug: entry3.name.replace(/\.md$/, ""),
|
|
23692
23767
|
displayName: fm.name,
|
|
23693
23768
|
kind: "specialist",
|
|
23694
23769
|
origin: "specialist",
|
|
@@ -23711,11 +23786,11 @@ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
|
|
|
23711
23786
|
// have the surface claim an agent is stopped while it is still being
|
|
23712
23787
|
// spawned. Absence from the live dir alone is also not the test: a
|
|
23713
23788
|
// specialist that was never activated was never switched off either.
|
|
23714
|
-
disabled: existsSync38(resolve28(accountDir, ...QUARANTINE_DIR,
|
|
23789
|
+
disabled: existsSync38(resolve28(accountDir, ...QUARANTINE_DIR, entry3.name)) && !existsSync38(resolve28(accountDir, ...SPECIALISTS_DIR, entry3.name))
|
|
23715
23790
|
});
|
|
23716
23791
|
} catch {
|
|
23717
23792
|
specialistsSkipped++;
|
|
23718
|
-
console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${
|
|
23793
|
+
console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry3.name}`);
|
|
23719
23794
|
}
|
|
23720
23795
|
}
|
|
23721
23796
|
}
|
|
@@ -23742,16 +23817,16 @@ app22.get("/", requireAdminSession, (c) => {
|
|
|
23742
23817
|
if (existsSync38(agentsDir)) {
|
|
23743
23818
|
try {
|
|
23744
23819
|
const entries2 = readdirSync24(agentsDir, { withFileTypes: true });
|
|
23745
|
-
for (const
|
|
23746
|
-
if (!
|
|
23747
|
-
if (
|
|
23748
|
-
const configPath3 = resolve28(agentsDir,
|
|
23820
|
+
for (const entry3 of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
23821
|
+
if (!entry3.isDirectory()) continue;
|
|
23822
|
+
if (entry3.name === "admin") continue;
|
|
23823
|
+
const configPath3 = resolve28(agentsDir, entry3.name, "config.json");
|
|
23749
23824
|
if (!existsSync38(configPath3)) continue;
|
|
23750
23825
|
try {
|
|
23751
23826
|
const config = JSON.parse(readFileSync38(configPath3, "utf-8"));
|
|
23752
23827
|
agents.push({
|
|
23753
|
-
slug:
|
|
23754
|
-
displayName: config.displayName ??
|
|
23828
|
+
slug: entry3.name,
|
|
23829
|
+
displayName: config.displayName ?? entry3.name,
|
|
23755
23830
|
status: config.status ?? "unknown",
|
|
23756
23831
|
kind: "public",
|
|
23757
23832
|
origin: "public",
|
|
@@ -23764,7 +23839,7 @@ app22.get("/", requireAdminSession, (c) => {
|
|
|
23764
23839
|
});
|
|
23765
23840
|
} catch {
|
|
23766
23841
|
skipped++;
|
|
23767
|
-
console.error(`[admin/agents] failed to parse config.json for agent "${
|
|
23842
|
+
console.error(`[admin/agents] failed to parse config.json for agent "${entry3.name}" \u2014 skipping`);
|
|
23768
23843
|
}
|
|
23769
23844
|
}
|
|
23770
23845
|
} catch (err) {
|
|
@@ -24418,7 +24493,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
24418
24493
|
if (!userId) return c.json({ error: "User identity required \u2014 authenticate with users.json PIN" }, 401);
|
|
24419
24494
|
try {
|
|
24420
24495
|
const flushed = await listAdminSessions(accountId, userId, 20);
|
|
24421
|
-
const
|
|
24496
|
+
const sessions4 = flushed.map((r) => ({
|
|
24422
24497
|
sessionId: r.sessionId,
|
|
24423
24498
|
cacheKey: null,
|
|
24424
24499
|
name: r.name,
|
|
@@ -24426,15 +24501,15 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
24426
24501
|
phase: "flushed",
|
|
24427
24502
|
channel: r.channel
|
|
24428
24503
|
})).sort((a, b) => a.updatedAt < b.updatedAt ? 1 : a.updatedAt > b.updatedAt ? -1 : 0).slice(0, 20);
|
|
24429
|
-
const channelCounts =
|
|
24504
|
+
const channelCounts = sessions4.reduce((acc, s) => {
|
|
24430
24505
|
const k = s.channel ?? "unknown";
|
|
24431
24506
|
acc[k] = (acc[k] ?? 0) + 1;
|
|
24432
24507
|
return acc;
|
|
24433
24508
|
}, {});
|
|
24434
24509
|
console.error(
|
|
24435
|
-
`[conversations-list] render rows=${
|
|
24510
|
+
`[conversations-list] render rows=${sessions4.length} channels=${JSON.stringify(channelCounts)}`
|
|
24436
24511
|
);
|
|
24437
|
-
return c.json({ sessions:
|
|
24512
|
+
return c.json({ sessions: sessions4 });
|
|
24438
24513
|
} catch (err) {
|
|
24439
24514
|
console.error(`[sessions-list] Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
24440
24515
|
return c.json({ error: "Failed to fetch sessions" }, 500);
|
|
@@ -26099,14 +26174,14 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
26099
26174
|
return { clean: false };
|
|
26100
26175
|
}
|
|
26101
26176
|
let clean = true;
|
|
26102
|
-
for (const
|
|
26103
|
-
if (
|
|
26104
|
-
if (
|
|
26105
|
-
const abs = join49(root,
|
|
26106
|
-
if (
|
|
26177
|
+
for (const entry3 of entries2) {
|
|
26178
|
+
if (entry3.isSymbolicLink()) continue;
|
|
26179
|
+
if (entry3.isDirectory() && entry3.name === ".uploads-tmp") continue;
|
|
26180
|
+
const abs = join49(root, entry3.name);
|
|
26181
|
+
if (entry3.isDirectory()) {
|
|
26107
26182
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
26108
26183
|
if (!sub.clean) clean = false;
|
|
26109
|
-
} else if (
|
|
26184
|
+
} else if (entry3.isFile()) {
|
|
26110
26185
|
try {
|
|
26111
26186
|
const st = await fsp.stat(abs);
|
|
26112
26187
|
out.push({
|
|
@@ -26395,14 +26470,14 @@ function buildZip(entries2) {
|
|
|
26395
26470
|
const localChunks = [];
|
|
26396
26471
|
const centralChunks = [];
|
|
26397
26472
|
let offset = 0;
|
|
26398
|
-
for (const
|
|
26399
|
-
const nameBytes = Buffer.from(
|
|
26400
|
-
const crc = crc32(
|
|
26401
|
-
const uncompressedSize =
|
|
26402
|
-
const deflated = deflateRawSync(
|
|
26473
|
+
for (const entry3 of entries2) {
|
|
26474
|
+
const nameBytes = Buffer.from(entry3.name, "utf8");
|
|
26475
|
+
const crc = crc32(entry3.data);
|
|
26476
|
+
const uncompressedSize = entry3.data.length;
|
|
26477
|
+
const deflated = deflateRawSync(entry3.data);
|
|
26403
26478
|
const useDeflate = deflated.length < uncompressedSize;
|
|
26404
26479
|
const method = useDeflate ? 8 : 0;
|
|
26405
|
-
const payload = useDeflate ? deflated :
|
|
26480
|
+
const payload = useDeflate ? deflated : entry3.data;
|
|
26406
26481
|
const compressedSize = payload.length;
|
|
26407
26482
|
const localHeader = Buffer.alloc(30);
|
|
26408
26483
|
localHeader.writeUInt32LE(LOCAL_SIG, 0);
|
|
@@ -26454,13 +26529,13 @@ function buildZip(entries2) {
|
|
|
26454
26529
|
}
|
|
26455
26530
|
|
|
26456
26531
|
// server/lib/account-root-groups.ts
|
|
26457
|
-
var
|
|
26532
|
+
var import_dist9 = __toESM(require_dist7(), 1);
|
|
26458
26533
|
function classifyAccountRoot(schemaMd, rootEntries) {
|
|
26459
|
-
const regions = (0,
|
|
26534
|
+
const regions = (0, import_dist9.parseSchemaRegions)(schemaMd);
|
|
26460
26535
|
if (!regions.parsed) {
|
|
26461
26536
|
return { home: [], system: [...rootEntries], unknown: [], parsed: false, reason: regions.reason };
|
|
26462
26537
|
}
|
|
26463
|
-
const homeOrder = [...regions.ontologyRoots, ...
|
|
26538
|
+
const homeOrder = [...regions.ontologyRoots, ...import_dist9.HOME_FIXED].filter((d, i, a) => a.indexOf(d) === i);
|
|
26464
26539
|
const homeSet = new Set(homeOrder);
|
|
26465
26540
|
const present = new Set(rootEntries);
|
|
26466
26541
|
const home = homeOrder.filter((d) => present.has(d));
|
|
@@ -26528,47 +26603,47 @@ async function servableFilesIn(dirAbs, uuid) {
|
|
|
26528
26603
|
}
|
|
26529
26604
|
return out;
|
|
26530
26605
|
}
|
|
26531
|
-
async function enrich(absolute,
|
|
26532
|
-
if (
|
|
26533
|
-
const dirAbs = join50(absolute,
|
|
26534
|
-
const meta = await readMeta2(dirAbs,
|
|
26606
|
+
async function enrich(absolute, entry3, accountNames) {
|
|
26607
|
+
if (entry3.kind === "directory" && UUID_RE3.test(entry3.name)) {
|
|
26608
|
+
const dirAbs = join50(absolute, entry3.name);
|
|
26609
|
+
const meta = await readMeta2(dirAbs, entry3.name);
|
|
26535
26610
|
if (meta?.filename) {
|
|
26536
|
-
const servable = await servableFilesIn(dirAbs,
|
|
26611
|
+
const servable = await servableFilesIn(dirAbs, entry3.name);
|
|
26537
26612
|
if (servable.length === 1) {
|
|
26538
26613
|
const innerName = servable[0];
|
|
26539
26614
|
let size = null;
|
|
26540
|
-
let modifiedAt =
|
|
26615
|
+
let modifiedAt = entry3.modifiedAt;
|
|
26541
26616
|
try {
|
|
26542
26617
|
const st = await stat6(join50(dirAbs, innerName));
|
|
26543
26618
|
size = st.size;
|
|
26544
26619
|
modifiedAt = st.mtime.toISOString();
|
|
26545
26620
|
} catch {
|
|
26546
26621
|
}
|
|
26547
|
-
|
|
26548
|
-
|
|
26549
|
-
|
|
26550
|
-
|
|
26551
|
-
|
|
26552
|
-
|
|
26622
|
+
entry3.kind = "file";
|
|
26623
|
+
entry3.displayName = meta.filename;
|
|
26624
|
+
entry3.mimeType = meta.mimeType;
|
|
26625
|
+
entry3.sizeBytes = size;
|
|
26626
|
+
entry3.modifiedAt = modifiedAt;
|
|
26627
|
+
entry3.entryPath = `${entry3.name}/${innerName}`;
|
|
26553
26628
|
return "flattened";
|
|
26554
26629
|
}
|
|
26555
|
-
|
|
26630
|
+
entry3.displayName = meta.filename;
|
|
26556
26631
|
return "kept-as-dir";
|
|
26557
26632
|
}
|
|
26558
|
-
const accountName = accountNames.get(
|
|
26633
|
+
const accountName = accountNames.get(entry3.name);
|
|
26559
26634
|
if (accountName) {
|
|
26560
|
-
|
|
26635
|
+
entry3.displayName = accountName;
|
|
26561
26636
|
}
|
|
26562
26637
|
return null;
|
|
26563
26638
|
}
|
|
26564
|
-
if (
|
|
26565
|
-
const dot =
|
|
26566
|
-
const base = dot === -1 ?
|
|
26639
|
+
if (entry3.kind === "file") {
|
|
26640
|
+
const dot = entry3.name.lastIndexOf(".");
|
|
26641
|
+
const base = dot === -1 ? entry3.name : entry3.name.slice(0, dot);
|
|
26567
26642
|
if (UUID_RE3.test(base)) {
|
|
26568
26643
|
const meta = await readMeta2(absolute, base);
|
|
26569
26644
|
if (meta?.filename) {
|
|
26570
|
-
|
|
26571
|
-
|
|
26645
|
+
entry3.displayName = meta.filename;
|
|
26646
|
+
entry3.mimeType = meta.mimeType;
|
|
26572
26647
|
}
|
|
26573
26648
|
}
|
|
26574
26649
|
}
|
|
@@ -27603,7 +27678,7 @@ app28.post("/rename", requireAdminSession, async (c) => {
|
|
|
27603
27678
|
var files_default = app28;
|
|
27604
27679
|
|
|
27605
27680
|
// ../lib/graph-search/src/index.ts
|
|
27606
|
-
var
|
|
27681
|
+
var import_dist10 = __toESM(require_dist8());
|
|
27607
27682
|
import { int } from "neo4j-driver";
|
|
27608
27683
|
|
|
27609
27684
|
// ../lib/graph-search/src/rrf-fusion.ts
|
|
@@ -27853,7 +27928,7 @@ async function bm25Only(session, params) {
|
|
|
27853
27928
|
${scopeClause}
|
|
27854
27929
|
${agentClause}
|
|
27855
27930
|
${labelClause}
|
|
27856
|
-
AND ${(0,
|
|
27931
|
+
AND ${(0, import_dist10.notTrashed)("node")}
|
|
27857
27932
|
${kwClause}
|
|
27858
27933
|
RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
|
|
27859
27934
|
ORDER BY score DESC
|
|
@@ -28015,7 +28090,7 @@ async function hybrid(session, embed2, params) {
|
|
|
28015
28090
|
WHERE node.accountId = $accountId
|
|
28016
28091
|
${scopeClause}
|
|
28017
28092
|
${agentClause}
|
|
28018
|
-
AND ${(0,
|
|
28093
|
+
AND ${(0, import_dist10.notTrashed)("node")}
|
|
28019
28094
|
${keywordClause}
|
|
28020
28095
|
RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
|
|
28021
28096
|
ORDER BY score DESC
|
|
@@ -28114,7 +28189,7 @@ async function hybrid(session, embed2, params) {
|
|
|
28114
28189
|
const propResult = await session.run(
|
|
28115
28190
|
`MATCH (node)
|
|
28116
28191
|
WHERE node.accountId = $accountId
|
|
28117
|
-
AND ${(0,
|
|
28192
|
+
AND ${(0, import_dist10.notTrashed)("node")}
|
|
28118
28193
|
AND node.keywords IS NOT NULL
|
|
28119
28194
|
AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
|
|
28120
28195
|
${propScope.clause}
|
|
@@ -28166,7 +28241,7 @@ async function hybrid(session, embed2, params) {
|
|
|
28166
28241
|
const propResult = await session.run(
|
|
28167
28242
|
`MATCH (node)
|
|
28168
28243
|
WHERE node.accountId = $accountId
|
|
28169
|
-
AND ${(0,
|
|
28244
|
+
AND ${(0, import_dist10.notTrashed)("node")}
|
|
28170
28245
|
AND node.keywords IS NOT NULL
|
|
28171
28246
|
AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
|
|
28172
28247
|
${propScope.clause}
|
|
@@ -28273,7 +28348,7 @@ async function hybrid(session, embed2, params) {
|
|
|
28273
28348
|
`UNWIND $nodeIds AS nid
|
|
28274
28349
|
MATCH (n)-[r]-(related)
|
|
28275
28350
|
WHERE elementId(n) = nid
|
|
28276
|
-
AND ${(0,
|
|
28351
|
+
AND ${(0, import_dist10.notTrashed)("related")}
|
|
28277
28352
|
${expandScopeClause}
|
|
28278
28353
|
${expandAgentClause}
|
|
28279
28354
|
WITH nid, n, r, related
|
|
@@ -28501,8 +28576,8 @@ var graph_search_default = app29;
|
|
|
28501
28576
|
import neo4j2 from "neo4j-driver";
|
|
28502
28577
|
|
|
28503
28578
|
// app/lib/graph-labels.ts
|
|
28504
|
-
var
|
|
28505
|
-
var
|
|
28579
|
+
var import_dist11 = __toESM(require_dist9(), 1);
|
|
28580
|
+
var import_dist12 = __toESM(require_dist9(), 1);
|
|
28506
28581
|
var HIDDEN_BY_DEFAULT_LABELS = Object.freeze(
|
|
28507
28582
|
/* @__PURE__ */ new Set(["Chunk", "GraphPreference"])
|
|
28508
28583
|
);
|
|
@@ -28586,14 +28661,14 @@ var EXCLUDED_EDGE_TYPES = Object.freeze(
|
|
|
28586
28661
|
])
|
|
28587
28662
|
);
|
|
28588
28663
|
function isKnownLabel(label) {
|
|
28589
|
-
return Object.prototype.hasOwnProperty.call(
|
|
28664
|
+
return Object.prototype.hasOwnProperty.call(import_dist12.GRAPH_LABEL_COLOURS, label);
|
|
28590
28665
|
}
|
|
28591
28666
|
function isHiddenByDefault(label) {
|
|
28592
28667
|
return HIDDEN_BY_DEFAULT_LABELS.has(label);
|
|
28593
28668
|
}
|
|
28594
28669
|
|
|
28595
28670
|
// server/lib/top-level-labels.ts
|
|
28596
|
-
var
|
|
28671
|
+
var import_dist13 = __toESM(require_dist9(), 1);
|
|
28597
28672
|
import { readdirSync as readdirSync26, readFileSync as readFileSync41 } from "fs";
|
|
28598
28673
|
import { join as join51, resolve as resolve33 } from "path";
|
|
28599
28674
|
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
@@ -28730,7 +28805,7 @@ function getTopLevelLabelAllowlist(opts = {}) {
|
|
|
28730
28805
|
const referencesDir = opts.referencesDir ?? resolveReferencesDir();
|
|
28731
28806
|
const { labels: derived, contributingFiles } = parseTableTopLevelLabels(referencesDir);
|
|
28732
28807
|
const excluded = [];
|
|
28733
|
-
for (const label of
|
|
28808
|
+
for (const label of import_dist13.ADDITIONAL_BASE_LABELS) {
|
|
28734
28809
|
if (derived.delete(label)) excluded.push(label);
|
|
28735
28810
|
}
|
|
28736
28811
|
const derivedCount = derived.size;
|
|
@@ -29982,8 +30057,8 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
29982
30057
|
if (!existsSync43(dir)) continue;
|
|
29983
30058
|
try {
|
|
29984
30059
|
const entries2 = await readdir5(dir);
|
|
29985
|
-
for (const
|
|
29986
|
-
if (
|
|
30060
|
+
for (const entry3 of entries2) {
|
|
30061
|
+
if (entry3.endsWith(".md")) names.add(entry3);
|
|
29987
30062
|
}
|
|
29988
30063
|
} catch (err) {
|
|
29989
30064
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -34247,8 +34322,8 @@ function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
|
|
|
34247
34322
|
} catch {
|
|
34248
34323
|
return [];
|
|
34249
34324
|
}
|
|
34250
|
-
for (const
|
|
34251
|
-
const cfgPath = resolve42(accountsDir,
|
|
34325
|
+
for (const entry3 of entries2) {
|
|
34326
|
+
const cfgPath = resolve42(accountsDir, entry3, "account.json");
|
|
34252
34327
|
if (!existsSync50(cfgPath)) continue;
|
|
34253
34328
|
try {
|
|
34254
34329
|
const cfg = JSON.parse(readFileSync51(cfgPath, "utf-8"));
|
|
@@ -35596,9 +35671,9 @@ function originAllowed(origin, allowlist) {
|
|
|
35596
35671
|
try {
|
|
35597
35672
|
const u = new URL(origin);
|
|
35598
35673
|
const host = u.host;
|
|
35599
|
-
return allowlist.some((
|
|
35600
|
-
if (
|
|
35601
|
-
if (
|
|
35674
|
+
return allowlist.some((entry3) => {
|
|
35675
|
+
if (entry3 === host) return true;
|
|
35676
|
+
if (entry3.startsWith("*.")) return host.endsWith(entry3.slice(1));
|
|
35602
35677
|
return false;
|
|
35603
35678
|
});
|
|
35604
35679
|
} catch {
|
|
@@ -36875,7 +36950,7 @@ async function runConversationAudit() {
|
|
|
36875
36950
|
}
|
|
36876
36951
|
|
|
36877
36952
|
// app/lib/graph-health.ts
|
|
36878
|
-
var
|
|
36953
|
+
var import_dist15 = __toESM(require_dist10(), 1);
|
|
36879
36954
|
var HOUR_MS2 = 60 * 60 * 1e3;
|
|
36880
36955
|
function renderLabelTop(rows) {
|
|
36881
36956
|
return rows.map((b) => {
|
|
@@ -36920,7 +36995,7 @@ async function runGraphHealthTick() {
|
|
|
36920
36995
|
console.error(
|
|
36921
36996
|
`[graph-health] userprofile-multi accounts=${upAccounts} top=${upTop.length > 0 ? upTop.join(",") : "none"}`
|
|
36922
36997
|
);
|
|
36923
|
-
const indexed = [...
|
|
36998
|
+
const indexed = [...import_dist15.VECTOR_INDEXED_LABELS];
|
|
36924
36999
|
const embCount = await session.run(
|
|
36925
37000
|
`MATCH (n) WHERE n.embedding IS NULL AND any(l IN labels(n) WHERE l IN $indexed)
|
|
36926
37001
|
RETURN count(n) AS total`,
|
|
@@ -36994,7 +37069,7 @@ function startGraphHealthTimer() {
|
|
|
36994
37069
|
// app/lib/shared-folder-census.ts
|
|
36995
37070
|
import { existsSync as existsSync54, statSync as statSync29, readdirSync as readdirSync32 } from "fs";
|
|
36996
37071
|
import { join as join65 } from "path";
|
|
36997
|
-
var
|
|
37072
|
+
var import_dist16 = __toESM(require_dist(), 1);
|
|
36998
37073
|
var TAG64 = "[shared-census]";
|
|
36999
37074
|
var WIRED_SURFACES = 3;
|
|
37000
37075
|
function countFiles(dir) {
|
|
@@ -37012,7 +37087,7 @@ function countFiles(dir) {
|
|
|
37012
37087
|
return n;
|
|
37013
37088
|
}
|
|
37014
37089
|
function runSharedFolderCensus(dataRoot = DATA_ROOT) {
|
|
37015
|
-
const root = (0,
|
|
37090
|
+
const root = (0, import_dist16.sharedRoot)(dataRoot);
|
|
37016
37091
|
const exists = existsSync54(root);
|
|
37017
37092
|
let isDir = false;
|
|
37018
37093
|
if (exists) {
|
|
@@ -37060,15 +37135,15 @@ function surveyBrandCredentials(home) {
|
|
|
37060
37135
|
return [];
|
|
37061
37136
|
}
|
|
37062
37137
|
const rows = [];
|
|
37063
|
-
for (const
|
|
37064
|
-
if (!
|
|
37138
|
+
for (const entry3 of entries2.sort()) {
|
|
37139
|
+
if (!entry3.startsWith(".")) continue;
|
|
37065
37140
|
let raw;
|
|
37066
37141
|
try {
|
|
37067
|
-
raw = readFileSync57(join66(home,
|
|
37142
|
+
raw = readFileSync57(join66(home, entry3, ".claude", ".credentials.json"), "utf-8");
|
|
37068
37143
|
} catch {
|
|
37069
37144
|
continue;
|
|
37070
37145
|
}
|
|
37071
|
-
rows.push({ brand:
|
|
37146
|
+
rows.push({ brand: entry3.slice(1), refreshTokenLen: refreshTokenLength(raw) });
|
|
37072
37147
|
}
|
|
37073
37148
|
return rows;
|
|
37074
37149
|
}
|
|
@@ -37277,8 +37352,8 @@ async function migrateUploads(opts = {}) {
|
|
|
37277
37352
|
let moved = 0;
|
|
37278
37353
|
let skipped = 0;
|
|
37279
37354
|
try {
|
|
37280
|
-
for (const
|
|
37281
|
-
const name =
|
|
37355
|
+
for (const entry3 of topEntries) {
|
|
37356
|
+
const name = entry3.name;
|
|
37282
37357
|
if (ACCOUNT_UUID_RE4.test(name)) {
|
|
37283
37358
|
moved += await relocateTree(
|
|
37284
37359
|
resolve49(oldRoot, name),
|
|
@@ -37378,11 +37453,11 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
37378
37453
|
} catch {
|
|
37379
37454
|
continue;
|
|
37380
37455
|
}
|
|
37381
|
-
for (const
|
|
37382
|
-
if (
|
|
37383
|
-
out.push(join67(slugDir,
|
|
37384
|
-
} else if (
|
|
37385
|
-
const subDir = join67(slugDir,
|
|
37456
|
+
for (const entry3 of entries2) {
|
|
37457
|
+
if (entry3.isFile() && SESSION_META_RE.test(entry3.name)) {
|
|
37458
|
+
out.push(join67(slugDir, entry3.name));
|
|
37459
|
+
} else if (entry3.isDirectory() && entry3.name === "subagents") {
|
|
37460
|
+
const subDir = join67(slugDir, entry3.name);
|
|
37386
37461
|
let subs;
|
|
37387
37462
|
try {
|
|
37388
37463
|
subs = await readdir7(subDir, { withFileTypes: true });
|
|
@@ -37532,11 +37607,11 @@ async function collectSidecars(projectsRoot) {
|
|
|
37532
37607
|
} catch {
|
|
37533
37608
|
continue;
|
|
37534
37609
|
}
|
|
37535
|
-
for (const
|
|
37536
|
-
if (
|
|
37537
|
-
out.push({ path: join68(slugDir,
|
|
37538
|
-
} else if (
|
|
37539
|
-
const subDir = join68(slugDir,
|
|
37610
|
+
for (const entry3 of entries2) {
|
|
37611
|
+
if (entry3.isFile() && SESSION_META_RE2.test(entry3.name)) {
|
|
37612
|
+
out.push({ path: join68(slugDir, entry3.name), slug: slug.name });
|
|
37613
|
+
} else if (entry3.isDirectory() && (entry3.name === "subagents" || entry3.name === "archive")) {
|
|
37614
|
+
const subDir = join68(slugDir, entry3.name);
|
|
37540
37615
|
let subs;
|
|
37541
37616
|
try {
|
|
37542
37617
|
subs = await readdir8(subDir, { withFileTypes: true });
|
|
@@ -38465,24 +38540,24 @@ var WaGateway = class {
|
|
|
38465
38540
|
for (const h of held) {
|
|
38466
38541
|
const key2 = hubKey(h.accountId, h.senderId);
|
|
38467
38542
|
if (this.spawning.has(key2)) continue;
|
|
38468
|
-
const
|
|
38469
|
-
if (!
|
|
38543
|
+
const entry3 = this.heldSpawnArgs.get(key2);
|
|
38544
|
+
if (!entry3) {
|
|
38470
38545
|
console.error(
|
|
38471
38546
|
`[whatsapp-native] op=spawn-retry-skipped senderId=${h.senderId} accountId=${h.accountId} ageMs=${h.oldestAgeMs} queued=${h.count} reason=no-args`
|
|
38472
38547
|
);
|
|
38473
38548
|
continue;
|
|
38474
38549
|
}
|
|
38475
|
-
|
|
38550
|
+
entry3.attempts++;
|
|
38476
38551
|
this.spawning.add(key2);
|
|
38477
38552
|
calls++;
|
|
38478
38553
|
try {
|
|
38479
|
-
await this.deps.ensureChannelSession(
|
|
38554
|
+
await this.deps.ensureChannelSession(entry3.args);
|
|
38480
38555
|
console.error(
|
|
38481
|
-
`[whatsapp-native] op=spawn-retry senderId=${h.senderId} accountId=${h.accountId} attempt=${
|
|
38556
|
+
`[whatsapp-native] op=spawn-retry senderId=${h.senderId} accountId=${h.accountId} attempt=${entry3.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=true`
|
|
38482
38557
|
);
|
|
38483
38558
|
} catch (err) {
|
|
38484
38559
|
console.error(
|
|
38485
|
-
`[whatsapp-native] op=spawn-retry senderId=${h.senderId} accountId=${h.accountId} attempt=${
|
|
38560
|
+
`[whatsapp-native] op=spawn-retry senderId=${h.senderId} accountId=${h.accountId} attempt=${entry3.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=false reason=${err instanceof Error ? err.message : String(err)}`
|
|
38486
38561
|
);
|
|
38487
38562
|
} finally {
|
|
38488
38563
|
this.spawning.delete(key2);
|
|
@@ -39027,8 +39102,8 @@ var InboundHub2 = class {
|
|
|
39027
39102
|
if (!s) return null;
|
|
39028
39103
|
const i = s.inFlight.findIndex((e) => e.payload.messageId === messageId && e.state === "queued");
|
|
39029
39104
|
if (i < 0) return null;
|
|
39030
|
-
const [
|
|
39031
|
-
return
|
|
39105
|
+
const [entry3] = s.inFlight.splice(i, 1);
|
|
39106
|
+
return entry3.payload;
|
|
39032
39107
|
}
|
|
39033
39108
|
/** Whether a key currently has a live channel server attached. The gateway
|
|
39034
39109
|
* uses this to decide whether an inbound needs a cold-start spawn/resume. */
|
|
@@ -39360,9 +39435,9 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
39360
39435
|
* false (and is a no-op) when no prompt with this key+id is open — a late or
|
|
39361
39436
|
* duplicate click. */
|
|
39362
39437
|
resolvePermissionVerdict(key2, requestId, behavior) {
|
|
39363
|
-
const
|
|
39364
|
-
if (!
|
|
39365
|
-
|
|
39438
|
+
const entry3 = this.pendingPrompts.get(_WebchatGateway.promptKey(key2, requestId));
|
|
39439
|
+
if (!entry3) return false;
|
|
39440
|
+
entry3.resolve({ behavior });
|
|
39366
39441
|
console.error(`[webchat:perm] op=verdict key=${keyDisplay(key2)} id=${requestId} behavior=${behavior}`);
|
|
39367
39442
|
return true;
|
|
39368
39443
|
}
|
|
@@ -39890,6 +39965,23 @@ var AnswerAccumulator = class {
|
|
|
39890
39965
|
};
|
|
39891
39966
|
|
|
39892
39967
|
// app/lib/channel-delivery/emitter.ts
|
|
39968
|
+
var CHANNEL_WRAPPER2 = "<channel source=";
|
|
39969
|
+
function classifyTurnStart(event) {
|
|
39970
|
+
const content = event.message?.content;
|
|
39971
|
+
if (typeof content === "string") {
|
|
39972
|
+
return content.trimStart().startsWith(CHANNEL_WRAPPER2) ? "inbound" : "injected";
|
|
39973
|
+
}
|
|
39974
|
+
if (!Array.isArray(content)) return "injected";
|
|
39975
|
+
for (const block of content) {
|
|
39976
|
+
if (block?.type === "tool_result") return "tool-result";
|
|
39977
|
+
}
|
|
39978
|
+
for (const block of content) {
|
|
39979
|
+
if (block?.type === "text" && typeof block.text === "string") {
|
|
39980
|
+
return block.text.trimStart().startsWith(CHANNEL_WRAPPER2) ? "inbound" : "injected";
|
|
39981
|
+
}
|
|
39982
|
+
}
|
|
39983
|
+
return "injected";
|
|
39984
|
+
}
|
|
39893
39985
|
function followerPendingMaxMs() {
|
|
39894
39986
|
return Number(process.env.CHANNEL_PTY_FOLLOWER_PENDING_MAX_MS ?? String(3e5));
|
|
39895
39987
|
}
|
|
@@ -39905,33 +39997,33 @@ function toolResultText(content) {
|
|
|
39905
39997
|
}
|
|
39906
39998
|
function startEmitter(opts) {
|
|
39907
39999
|
const abort2 = new AbortController();
|
|
39908
|
-
const { entry:
|
|
40000
|
+
const { entry: entry3, tag } = opts;
|
|
39909
40001
|
const answers = new AnswerAccumulator();
|
|
39910
40002
|
let answersEmitted = 0;
|
|
39911
40003
|
let closeReason = "stream-end";
|
|
39912
40004
|
const emitAnswer = async (answer) => {
|
|
39913
40005
|
answersEmitted += 1;
|
|
39914
|
-
if (answer.text.trim()) await fanOut2(
|
|
40006
|
+
if (answer.text.trim()) await fanOut2(entry3.subscribers, answer.text, opts.onError, tag);
|
|
39915
40007
|
if (!opts.onAnswer) return;
|
|
39916
|
-
const guarded = { ...answer, text: guardOutbound(
|
|
40008
|
+
const guarded = { ...answer, text: guardOutbound(entry3.senderId, answer.text) };
|
|
39917
40009
|
try {
|
|
39918
40010
|
await opts.onAnswer(guarded);
|
|
39919
40011
|
} catch (err) {
|
|
39920
40012
|
console.error(
|
|
39921
|
-
`${tag} answer-error sessionId=${
|
|
40013
|
+
`${tag} answer-error sessionId=${entry3.sessionId.slice(0, 8)} messageId=${answer.messageId} message=${err instanceof Error ? err.message : String(err)}`
|
|
39922
40014
|
);
|
|
39923
40015
|
}
|
|
39924
40016
|
};
|
|
39925
40017
|
void (async () => {
|
|
39926
40018
|
try {
|
|
39927
|
-
const sid =
|
|
40019
|
+
const sid = entry3.sessionId.slice(0, 8);
|
|
39928
40020
|
const deadline = Date.now() + followerPendingMaxMs();
|
|
39929
40021
|
const retryMs = followerRetryMs();
|
|
39930
40022
|
let res;
|
|
39931
40023
|
let attempt = 0;
|
|
39932
40024
|
for (; ; ) {
|
|
39933
40025
|
res = await fetch(
|
|
39934
|
-
managerLogFollowUrl(
|
|
40026
|
+
managerLogFollowUrl(entry3.sessionId, { boundary: opts.suppressResumeReplay === true }),
|
|
39935
40027
|
{ signal: abort2.signal }
|
|
39936
40028
|
);
|
|
39937
40029
|
console.error(`${tag} follower-connect sessionId=${sid} status=${res.status}`);
|
|
@@ -39982,7 +40074,7 @@ function startEmitter(opts) {
|
|
|
39982
40074
|
event = JSON.parse(line);
|
|
39983
40075
|
} catch (err) {
|
|
39984
40076
|
console.error(
|
|
39985
|
-
`${tag} jsonl-parse-skip sessionId=${
|
|
40077
|
+
`${tag} jsonl-parse-skip sessionId=${entry3.sessionId.slice(0, 8)} bytes=${line.length} message=${err instanceof Error ? err.message : String(err)}`
|
|
39986
40078
|
);
|
|
39987
40079
|
continue;
|
|
39988
40080
|
}
|
|
@@ -40035,7 +40127,7 @@ function startEmitter(opts) {
|
|
|
40035
40127
|
}
|
|
40036
40128
|
}
|
|
40037
40129
|
}
|
|
40038
|
-
if (!suppressing) opts.onTurnStart?.();
|
|
40130
|
+
if (!suppressing) opts.onTurnStart?.(classifyTurnStart(event));
|
|
40039
40131
|
firedFileTools = [];
|
|
40040
40132
|
continue;
|
|
40041
40133
|
}
|
|
@@ -40100,7 +40192,7 @@ function startEmitter(opts) {
|
|
|
40100
40192
|
} finally {
|
|
40101
40193
|
if (abort2.signal.aborted) closeReason = "aborted";
|
|
40102
40194
|
console.error(
|
|
40103
|
-
`${tag} op=follower-closed sessionId=${
|
|
40195
|
+
`${tag} op=follower-closed sessionId=${entry3.sessionId.slice(0, 8)} reason=${closeReason} answers=${answersEmitted}`
|
|
40104
40196
|
);
|
|
40105
40197
|
opts.onClose();
|
|
40106
40198
|
}
|
|
@@ -40155,7 +40247,7 @@ import { resolve as resolve50 } from "path";
|
|
|
40155
40247
|
// app/lib/channel-pty-bridge/file-delivery.ts
|
|
40156
40248
|
var SEND_USER_FILE = "SendUserFile";
|
|
40157
40249
|
function makeFileDelivery(opts) {
|
|
40158
|
-
const { entry:
|
|
40250
|
+
const { entry: entry3, tag, channel, sendFile, deferUntilVerdict = false } = opts;
|
|
40159
40251
|
let failedFiles = [];
|
|
40160
40252
|
let attempts = 0;
|
|
40161
40253
|
const pending = /* @__PURE__ */ new Map();
|
|
@@ -40182,7 +40274,7 @@ function makeFileDelivery(opts) {
|
|
|
40182
40274
|
function unreconciledCall(reason, files, detail) {
|
|
40183
40275
|
const d = detail ? ` detail="${detail.replace(/\s+/g, " ").slice(0, 120)}"` : "";
|
|
40184
40276
|
console.error(
|
|
40185
|
-
`${tag} file-delivery-unreconciled sender=${
|
|
40277
|
+
`${tag} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${entry3.sessionId.slice(0, 8)} tool=${SEND_USER_FILE} reason=${reason} files=${files}${d}`
|
|
40186
40278
|
);
|
|
40187
40279
|
}
|
|
40188
40280
|
const handler = {
|
|
@@ -40203,10 +40295,10 @@ function makeFileDelivery(opts) {
|
|
|
40203
40295
|
const tried = attempts;
|
|
40204
40296
|
failedFiles = [];
|
|
40205
40297
|
attempts = 0;
|
|
40206
|
-
const sid =
|
|
40298
|
+
const sid = entry3.sessionId.slice(0, 8);
|
|
40207
40299
|
for (const file of failed2) {
|
|
40208
40300
|
console.error(
|
|
40209
|
-
`${tag} file-delivery-unreconciled sender=${
|
|
40301
|
+
`${tag} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${sid} tool=${SEND_USER_FILE} file=${file}`
|
|
40210
40302
|
);
|
|
40211
40303
|
}
|
|
40212
40304
|
if (deferUntilVerdict) {
|
|
@@ -40216,7 +40308,7 @@ function makeFileDelivery(opts) {
|
|
|
40216
40308
|
}
|
|
40217
40309
|
if (firedTools.includes(SEND_USER_FILE) && tried === 0) {
|
|
40218
40310
|
console.error(
|
|
40219
|
-
`${tag} file-delivery-unreconciled sender=${
|
|
40311
|
+
`${tag} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${sid} tool=${SEND_USER_FILE}`
|
|
40220
40312
|
);
|
|
40221
40313
|
}
|
|
40222
40314
|
}
|
|
@@ -40245,43 +40337,43 @@ var TAG66 = "[webchat-adaptor]";
|
|
|
40245
40337
|
function platformRoot2() {
|
|
40246
40338
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
40247
40339
|
}
|
|
40248
|
-
function makeWebchatSendFile(
|
|
40340
|
+
function makeWebchatSendFile(entry3) {
|
|
40249
40341
|
return async (filePath) => {
|
|
40250
|
-
if (!
|
|
40251
|
-
console.error(`${TAG66} file-delivery reject reason=no-account sender=${
|
|
40342
|
+
if (!entry3.accountId) {
|
|
40343
|
+
console.error(`${TAG66} file-delivery reject reason=no-account sender=${entry3.senderId}`);
|
|
40252
40344
|
return { ok: false, error: "no-account" };
|
|
40253
40345
|
}
|
|
40254
|
-
const accountDir = resolve50(platformRoot2(), "..", "data/accounts",
|
|
40346
|
+
const accountDir = resolve50(platformRoot2(), "..", "data/accounts", entry3.accountId);
|
|
40255
40347
|
try {
|
|
40256
40348
|
const resolved = realpathSync9(filePath);
|
|
40257
40349
|
const accountResolved = realpathSync9(accountDir);
|
|
40258
40350
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
40259
|
-
console.error(`${TAG66} file-delivery reject reason=outside_account_directory sender=${
|
|
40351
|
+
console.error(`${TAG66} file-delivery reject reason=outside_account_directory sender=${entry3.senderId}`);
|
|
40260
40352
|
return { ok: false, error: "outside-account" };
|
|
40261
40353
|
}
|
|
40262
40354
|
return { ok: true };
|
|
40263
40355
|
} catch (err) {
|
|
40264
40356
|
const code = err.code;
|
|
40265
40357
|
console.error(
|
|
40266
|
-
`${TAG66} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${
|
|
40358
|
+
`${TAG66} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry3.senderId}`
|
|
40267
40359
|
);
|
|
40268
40360
|
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
40269
40361
|
}
|
|
40270
40362
|
};
|
|
40271
40363
|
}
|
|
40272
|
-
function makeWebchatFileDelivery(
|
|
40364
|
+
function makeWebchatFileDelivery(entry3) {
|
|
40273
40365
|
return makeFileDelivery({
|
|
40274
|
-
entry:
|
|
40366
|
+
entry: entry3,
|
|
40275
40367
|
tag: TAG66,
|
|
40276
40368
|
channel: "webchat",
|
|
40277
|
-
sendFile: makeWebchatSendFile(
|
|
40369
|
+
sendFile: makeWebchatSendFile(entry3),
|
|
40278
40370
|
deferUntilVerdict: true
|
|
40279
40371
|
});
|
|
40280
40372
|
}
|
|
40281
40373
|
|
|
40282
40374
|
// app/lib/webchat/gateway/native-file-follower.ts
|
|
40283
40375
|
function startWebchatNativeFileFollower(input) {
|
|
40284
|
-
const
|
|
40376
|
+
const entry3 = {
|
|
40285
40377
|
sessionId: input.sessionId,
|
|
40286
40378
|
role: "admin",
|
|
40287
40379
|
channel: "webchat",
|
|
@@ -40300,7 +40392,7 @@ function startWebchatNativeFileFollower(input) {
|
|
|
40300
40392
|
replyTarget: null
|
|
40301
40393
|
};
|
|
40302
40394
|
return startEmitter({
|
|
40303
|
-
entry:
|
|
40395
|
+
entry: entry3,
|
|
40304
40396
|
tag: "[webchat-adaptor]",
|
|
40305
40397
|
// Task 2557 — the emitter has always had this channel and no follower ever
|
|
40306
40398
|
// passed one, so every cause it reported was discarded. The close line
|
|
@@ -40308,7 +40400,7 @@ function startWebchatNativeFileFollower(input) {
|
|
|
40308
40400
|
onError: (reason) => {
|
|
40309
40401
|
console.error(`[webchat-adaptor] op=follower-error sessionId=${input.sessionId.slice(0, 8)} reason=${reason}`);
|
|
40310
40402
|
},
|
|
40311
|
-
fileDelivery: makeWebchatFileDelivery(
|
|
40403
|
+
fileDelivery: makeWebchatFileDelivery(entry3),
|
|
40312
40404
|
// A resumed session's JSONL already holds prior SendUserFile tool_uses;
|
|
40313
40405
|
// suppress replay so historical calls are not re-reconciled on attach.
|
|
40314
40406
|
suppressResumeReplay: true,
|
|
@@ -40357,29 +40449,29 @@ var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
|
40357
40449
|
function platformRoot3() {
|
|
40358
40450
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
40359
40451
|
}
|
|
40360
|
-
function makeWhatsAppSendFile(
|
|
40452
|
+
function makeWhatsAppSendFile(entry3, maxyAccountId) {
|
|
40361
40453
|
return async (filePath, caption) => {
|
|
40362
40454
|
const result = await sendWhatsAppDocument({
|
|
40363
|
-
to:
|
|
40455
|
+
to: entry3.senderId,
|
|
40364
40456
|
filePath,
|
|
40365
40457
|
caption,
|
|
40366
|
-
accountId:
|
|
40458
|
+
accountId: entry3.accountId,
|
|
40367
40459
|
maxyAccountId,
|
|
40368
40460
|
platformRoot: platformRoot3()
|
|
40369
40461
|
});
|
|
40370
40462
|
if (result.ok) return { ok: true };
|
|
40371
40463
|
console.error(
|
|
40372
|
-
`${TAG67} file-delivery reject reason=send-failed sender=${
|
|
40464
|
+
`${TAG67} file-delivery reject reason=send-failed sender=${entry3.senderId} status=${result.status} message=${result.error}`
|
|
40373
40465
|
);
|
|
40374
40466
|
return { ok: false, error: result.error };
|
|
40375
40467
|
};
|
|
40376
40468
|
}
|
|
40377
|
-
function makeWhatsAppFileDelivery(
|
|
40469
|
+
function makeWhatsAppFileDelivery(entry3, maxyAccountId) {
|
|
40378
40470
|
const shared = makeFileDelivery({
|
|
40379
|
-
entry:
|
|
40471
|
+
entry: entry3,
|
|
40380
40472
|
tag: TAG67,
|
|
40381
40473
|
channel: "whatsapp",
|
|
40382
|
-
sendFile: makeWhatsAppSendFile(
|
|
40474
|
+
sendFile: makeWhatsAppSendFile(entry3, maxyAccountId)
|
|
40383
40475
|
});
|
|
40384
40476
|
let turnStartedAt = null;
|
|
40385
40477
|
let routeCalls = [];
|
|
@@ -40404,7 +40496,7 @@ function makeWhatsAppFileDelivery(entry2, maxyAccountId) {
|
|
|
40404
40496
|
const routes = routeCalls;
|
|
40405
40497
|
turnStartedAt = null;
|
|
40406
40498
|
routeCalls = [];
|
|
40407
|
-
const sid =
|
|
40499
|
+
const sid = entry3.sessionId.slice(0, 8);
|
|
40408
40500
|
shared.onTurnEnd(firedTools);
|
|
40409
40501
|
for (const call2 of routes) {
|
|
40410
40502
|
const routeAt = call2.to !== void 0 && call2.filePath !== void 0 ? routeDocumentOutboundAt(call2.to, call2.filePath) : void 0;
|
|
@@ -40412,7 +40504,7 @@ function makeWhatsAppFileDelivery(entry2, maxyAccountId) {
|
|
|
40412
40504
|
if (!delivered) {
|
|
40413
40505
|
const fileField = call2.filePath !== void 0 ? ` file=${call2.filePath}` : "";
|
|
40414
40506
|
console.error(
|
|
40415
|
-
`${TAG67} file-delivery-unreconciled sender=${
|
|
40507
|
+
`${TAG67} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
40416
40508
|
);
|
|
40417
40509
|
}
|
|
40418
40510
|
}
|
|
@@ -40423,7 +40515,7 @@ function makeWhatsAppFileDelivery(entry2, maxyAccountId) {
|
|
|
40423
40515
|
// app/lib/whatsapp/gateway/native-file-follower.ts
|
|
40424
40516
|
var COMPOSING_REFRESH_MS = 1e4;
|
|
40425
40517
|
function startNativeFileFollower(input) {
|
|
40426
|
-
const
|
|
40518
|
+
const entry3 = {
|
|
40427
40519
|
sessionId: input.sessionId,
|
|
40428
40520
|
role: input.role,
|
|
40429
40521
|
channel: "whatsapp",
|
|
@@ -40469,7 +40561,7 @@ function startNativeFileFollower(input) {
|
|
|
40469
40561
|
void sendPaused(sock, input.senderId);
|
|
40470
40562
|
};
|
|
40471
40563
|
return startEmitter({
|
|
40472
|
-
entry:
|
|
40564
|
+
entry: entry3,
|
|
40473
40565
|
tag: "[whatsapp-adaptor]",
|
|
40474
40566
|
// Task 2557 — the emitter has always had this channel and no follower ever
|
|
40475
40567
|
// passed one, so every cause it reported (`follow-status-404`,
|
|
@@ -40481,7 +40573,7 @@ function startNativeFileFollower(input) {
|
|
|
40481
40573
|
},
|
|
40482
40574
|
// Task 2521 — admin-only. A public spawn has no tools (Task 2078), so a
|
|
40483
40575
|
// handler here would reconcile a call that can never fire.
|
|
40484
|
-
fileDelivery: input.role === "admin" ? makeWhatsAppFileDelivery(
|
|
40576
|
+
fileDelivery: input.role === "admin" ? makeWhatsAppFileDelivery(entry3, input.maxyAccountId) : null,
|
|
40485
40577
|
// A resumed session's JSONL already holds prior SendUserFile tool_uses;
|
|
40486
40578
|
// suppress replay so historical files are not re-sent on attach.
|
|
40487
40579
|
suppressResumeReplay: true,
|
|
@@ -41019,24 +41111,24 @@ var TelegramGateway = class {
|
|
|
41019
41111
|
let calls = 0;
|
|
41020
41112
|
for (const h of held) {
|
|
41021
41113
|
if (this.spawning.has(h.key)) continue;
|
|
41022
|
-
const
|
|
41023
|
-
if (!
|
|
41114
|
+
const entry3 = this.heldSpawnArgs.get(h.key);
|
|
41115
|
+
if (!entry3) {
|
|
41024
41116
|
console.error(
|
|
41025
41117
|
`[telegram-native] op=spawn-retry-skipped key=${h.key} ageMs=${h.oldestAgeMs} queued=${h.count} reason=no-args`
|
|
41026
41118
|
);
|
|
41027
41119
|
continue;
|
|
41028
41120
|
}
|
|
41029
|
-
|
|
41121
|
+
entry3.attempts++;
|
|
41030
41122
|
this.spawning.add(h.key);
|
|
41031
41123
|
calls++;
|
|
41032
41124
|
try {
|
|
41033
|
-
await this.deps.ensureChannelSession(
|
|
41125
|
+
await this.deps.ensureChannelSession(entry3.args);
|
|
41034
41126
|
console.error(
|
|
41035
|
-
`[telegram-native] op=spawn-retry key=${h.key} attempt=${
|
|
41127
|
+
`[telegram-native] op=spawn-retry key=${h.key} attempt=${entry3.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=true`
|
|
41036
41128
|
);
|
|
41037
41129
|
} catch (err) {
|
|
41038
41130
|
console.error(
|
|
41039
|
-
`[telegram-native] op=spawn-retry key=${h.key} attempt=${
|
|
41131
|
+
`[telegram-native] op=spawn-retry key=${h.key} attempt=${entry3.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=false reason=${err instanceof Error ? err.message : String(err)}`
|
|
41040
41132
|
);
|
|
41041
41133
|
} finally {
|
|
41042
41134
|
this.spawning.delete(h.key);
|
|
@@ -41489,33 +41581,33 @@ var TAG71 = "[telegram:outbound]";
|
|
|
41489
41581
|
function platformRoot4() {
|
|
41490
41582
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
41491
41583
|
}
|
|
41492
|
-
function makeTelegramSendFile(
|
|
41584
|
+
function makeTelegramSendFile(entry3, botToken) {
|
|
41493
41585
|
return async (filePath, caption) => {
|
|
41494
41586
|
if (!botToken) {
|
|
41495
|
-
console.error(`${TAG71} file-delivery reject reason=no-bot-token sender=${
|
|
41587
|
+
console.error(`${TAG71} file-delivery reject reason=no-bot-token sender=${entry3.senderId} role=${entry3.role}`);
|
|
41496
41588
|
return { ok: false, error: "no-bot-token" };
|
|
41497
41589
|
}
|
|
41498
|
-
if (
|
|
41499
|
-
console.error(`${TAG71} file-delivery reject reason=no-reply-target sender=${
|
|
41590
|
+
if (entry3.replyTarget == null) {
|
|
41591
|
+
console.error(`${TAG71} file-delivery reject reason=no-reply-target sender=${entry3.senderId} role=${entry3.role}`);
|
|
41500
41592
|
return { ok: false, error: "no-reply-target" };
|
|
41501
41593
|
}
|
|
41502
41594
|
const result = await sendTelegramDocument({
|
|
41503
41595
|
botToken,
|
|
41504
|
-
chatId: Number(
|
|
41596
|
+
chatId: Number(entry3.replyTarget),
|
|
41505
41597
|
filePath,
|
|
41506
41598
|
caption,
|
|
41507
|
-
maxyAccountId:
|
|
41599
|
+
maxyAccountId: entry3.accountId,
|
|
41508
41600
|
platformRoot: platformRoot4()
|
|
41509
41601
|
});
|
|
41510
41602
|
return result.ok ? { ok: true } : { ok: false, error: result.error };
|
|
41511
41603
|
};
|
|
41512
41604
|
}
|
|
41513
|
-
function makeTelegramFileDelivery(
|
|
41605
|
+
function makeTelegramFileDelivery(entry3, botToken) {
|
|
41514
41606
|
return makeFileDelivery({
|
|
41515
|
-
entry:
|
|
41607
|
+
entry: entry3,
|
|
41516
41608
|
tag: TAG71,
|
|
41517
41609
|
channel: "telegram",
|
|
41518
|
-
sendFile: makeTelegramSendFile(
|
|
41610
|
+
sendFile: makeTelegramSendFile(entry3, botToken)
|
|
41519
41611
|
});
|
|
41520
41612
|
}
|
|
41521
41613
|
|
|
@@ -41551,11 +41643,46 @@ function runTelegramPresenceCensus() {
|
|
|
41551
41643
|
);
|
|
41552
41644
|
}
|
|
41553
41645
|
|
|
41646
|
+
// app/lib/telegram/gateway/card-census.ts
|
|
41647
|
+
var sessions3 = /* @__PURE__ */ new Map();
|
|
41648
|
+
function entry2(sessionId) {
|
|
41649
|
+
let e = sessions3.get(sessionId);
|
|
41650
|
+
if (!e) {
|
|
41651
|
+
e = { armed: 0, suppressed: 0, delivered: 0 };
|
|
41652
|
+
sessions3.set(sessionId, e);
|
|
41653
|
+
}
|
|
41654
|
+
return e;
|
|
41655
|
+
}
|
|
41656
|
+
function noteCardArmed(sessionId) {
|
|
41657
|
+
entry2(sessionId).armed += 1;
|
|
41658
|
+
}
|
|
41659
|
+
function noteCardSuppressed(sessionId) {
|
|
41660
|
+
entry2(sessionId).suppressed += 1;
|
|
41661
|
+
}
|
|
41662
|
+
function noteCardDelivered(sessionId) {
|
|
41663
|
+
const e = sessions3.get(sessionId);
|
|
41664
|
+
if (e && e.armed > 0) e.delivered += 1;
|
|
41665
|
+
}
|
|
41666
|
+
function cardCensusLines() {
|
|
41667
|
+
let armed2 = 0;
|
|
41668
|
+
let suppressed = 0;
|
|
41669
|
+
let delivered = 0;
|
|
41670
|
+
for (const e of sessions3.values()) {
|
|
41671
|
+
armed2 += e.armed;
|
|
41672
|
+
suppressed += e.suppressed;
|
|
41673
|
+
delivered += e.delivered;
|
|
41674
|
+
}
|
|
41675
|
+
const silent = Math.max(0, armed2 - suppressed - delivered);
|
|
41676
|
+
return [
|
|
41677
|
+
`[telegram-card-suppression-census] sessions=${sessions3.size} armed=${armed2} suppressed=${suppressed} silent-turns=${silent}`
|
|
41678
|
+
];
|
|
41679
|
+
}
|
|
41680
|
+
|
|
41554
41681
|
// app/lib/telegram/gateway/native-file-follower.ts
|
|
41555
41682
|
var TELEGRAM_CARD_TOOL = "mcp__telegram__telegram-card";
|
|
41556
41683
|
var CHAT_ACTION_REFRESH_MS = 4e3;
|
|
41557
41684
|
function startTelegramNativeFileFollower(input) {
|
|
41558
|
-
const
|
|
41685
|
+
const entry3 = {
|
|
41559
41686
|
sessionId: input.sessionId,
|
|
41560
41687
|
role: "admin",
|
|
41561
41688
|
channel: "telegram",
|
|
@@ -41599,7 +41726,8 @@ function startTelegramNativeFileFollower(input) {
|
|
|
41599
41726
|
stopHeartbeat();
|
|
41600
41727
|
lastChatActionAt = Number.NEGATIVE_INFINITY;
|
|
41601
41728
|
};
|
|
41602
|
-
const onTurnStart = () => {
|
|
41729
|
+
const onTurnStart = (kind) => {
|
|
41730
|
+
if (kind === "inbound") cardSentThisTurn = false;
|
|
41603
41731
|
if (turnOpen) return;
|
|
41604
41732
|
turnOpen = true;
|
|
41605
41733
|
stopHeartbeat();
|
|
@@ -41612,7 +41740,6 @@ function startTelegramNativeFileFollower(input) {
|
|
|
41612
41740
|
};
|
|
41613
41741
|
const onTurnComplete = () => {
|
|
41614
41742
|
turnOpen = false;
|
|
41615
|
-
cardSentThisTurn = false;
|
|
41616
41743
|
if (input.backgroundActive?.() === true) return;
|
|
41617
41744
|
stopHeartbeat();
|
|
41618
41745
|
lastChatActionAt = Number.NEGATIVE_INFINITY;
|
|
@@ -41626,7 +41753,7 @@ function startTelegramNativeFileFollower(input) {
|
|
|
41626
41753
|
background: () => input.backgroundActive?.() === true
|
|
41627
41754
|
});
|
|
41628
41755
|
return startEmitter({
|
|
41629
|
-
entry:
|
|
41756
|
+
entry: entry3,
|
|
41630
41757
|
tag: "[telegram-adaptor]",
|
|
41631
41758
|
// Task 2557 — the emitter has always had this channel and no follower ever
|
|
41632
41759
|
// passed one, so every cause it reported was discarded. The close line
|
|
@@ -41634,7 +41761,7 @@ function startTelegramNativeFileFollower(input) {
|
|
|
41634
41761
|
onError: (reason) => {
|
|
41635
41762
|
console.error(`[telegram-adaptor] op=follower-error sessionId=${input.sessionId.slice(0, 8)} reason=${reason}`);
|
|
41636
41763
|
},
|
|
41637
|
-
fileDelivery: makeTelegramFileDelivery(
|
|
41764
|
+
fileDelivery: makeTelegramFileDelivery(entry3, input.botToken),
|
|
41638
41765
|
// A resumed session's JSONL already holds prior SendUserFile tool_uses;
|
|
41639
41766
|
// suppress replay so historical files are not re-sent on attach.
|
|
41640
41767
|
suppressResumeReplay: true,
|
|
@@ -41652,14 +41779,19 @@ function startTelegramNativeFileFollower(input) {
|
|
|
41652
41779
|
// before it reaches the optional answerCallbackQuery, so there is no card
|
|
41653
41780
|
// call that posts nothing and no bare acknowledgement to keep the text for.
|
|
41654
41781
|
onToolUse: (name) => {
|
|
41655
|
-
if (name
|
|
41782
|
+
if (name !== TELEGRAM_CARD_TOOL) return;
|
|
41783
|
+
cardSentThisTurn = true;
|
|
41784
|
+
noteCardArmed(input.sessionId);
|
|
41785
|
+
console.error(
|
|
41786
|
+
`[telegram-public] op=card-armed sessionId=${input.sessionId.slice(0, 8)} tool=${name}`
|
|
41787
|
+
);
|
|
41656
41788
|
},
|
|
41657
41789
|
// Task 2521 — the answer reaches every bound door through the one fan-out.
|
|
41658
41790
|
// Ungated by design: whatever woke the turn, the reader and the chats show
|
|
41659
41791
|
// the same thing. Task 2666 adds the one exception above.
|
|
41660
41792
|
onAnswer: async (answer) => {
|
|
41661
41793
|
if (cardSentThisTurn) {
|
|
41662
|
-
|
|
41794
|
+
noteCardSuppressed(input.sessionId);
|
|
41663
41795
|
console.error(
|
|
41664
41796
|
`[telegram-public] op=text-suppressed sessionId=${input.sessionId.slice(0, 8)} messageId=${answer.messageId} reason=card-sent`
|
|
41665
41797
|
);
|
|
@@ -41670,6 +41802,7 @@ function startTelegramNativeFileFollower(input) {
|
|
|
41670
41802
|
noteAnswer(input.sessionId, answer.messageId);
|
|
41671
41803
|
const { line, reached } = await fanOut({ targets, segments: segmentText(answer.text) });
|
|
41672
41804
|
noteSent(input.sessionId, answer.messageId, reached);
|
|
41805
|
+
noteCardDelivered(input.sessionId);
|
|
41673
41806
|
console.error(`${line} messageId=${answer.messageId} sessionId=${input.sessionId.slice(0, 8)}`);
|
|
41674
41807
|
},
|
|
41675
41808
|
// Task 2603 — the interval must not outlive the reader. The emitter reaches
|
|
@@ -41955,11 +42088,11 @@ async function firePublicSessionEndReview(input) {
|
|
|
41955
42088
|
}
|
|
41956
42089
|
|
|
41957
42090
|
// app/lib/whatsapp/inbound/resolve-client-graph-owner.ts
|
|
41958
|
-
var
|
|
42091
|
+
var import_dist17 = __toESM(require_dist3(), 1);
|
|
41959
42092
|
async function resolveClientOwnerUserId(accountId, deps = {}) {
|
|
41960
42093
|
const listAccounts = deps.listAccounts ?? listValidAccounts;
|
|
41961
42094
|
const getSession3 = deps.getSession ?? getSession;
|
|
41962
|
-
const resolveOwner2 = deps.resolveOwner ??
|
|
42095
|
+
const resolveOwner2 = deps.resolveOwner ?? import_dist17.resolveOwnerUserId;
|
|
41963
42096
|
const role = listAccounts().find((a) => a.accountId === accountId)?.config.role;
|
|
41964
42097
|
if (role !== "client") return null;
|
|
41965
42098
|
const session = getSession3();
|
|
@@ -41982,8 +42115,8 @@ async function resolveClientOwnerUserId(accountId, deps = {}) {
|
|
|
41982
42115
|
// app/lib/whatsapp/inbound/channel-admin-binding-drift.ts
|
|
41983
42116
|
function findAccountManagerDrift(accountManagers, validAccountIds) {
|
|
41984
42117
|
const drift = [];
|
|
41985
|
-
for (const [phone,
|
|
41986
|
-
const managesAccount = typeof
|
|
42118
|
+
for (const [phone, entry3] of Object.entries(accountManagers)) {
|
|
42119
|
+
const managesAccount = typeof entry3 === "string" ? entry3 : entry3.managesAccount;
|
|
41987
42120
|
if (!validAccountIds.includes(managesAccount)) {
|
|
41988
42121
|
drift.push({ phone, managesAccount, reason: "not-in-registry" });
|
|
41989
42122
|
}
|
|
@@ -42089,50 +42222,50 @@ import { join as join71 } from "path";
|
|
|
42089
42222
|
function buildTelegramAuditLines(input) {
|
|
42090
42223
|
const lines = [];
|
|
42091
42224
|
const entries2 = input.accounts.flatMap(
|
|
42092
|
-
(a) => listBotEntries(a.telegram).map((
|
|
42225
|
+
(a) => listBotEntries(a.telegram).map((entry3) => ({ accountId: a.accountId, accountDir: a.accountDir, entry: entry3 }))
|
|
42093
42226
|
);
|
|
42094
42227
|
if (entries2.length === 0) return lines;
|
|
42095
42228
|
const byId = /* @__PURE__ */ new Map();
|
|
42096
|
-
for (const { entry:
|
|
42229
|
+
for (const { entry: entry3 } of entries2) byId.set(entry3.id, (byId.get(entry3.id) ?? 0) + 1);
|
|
42097
42230
|
for (const [botId, count] of byId) {
|
|
42098
42231
|
if (count > 1) lines.push(`[telegram-audit] op=duplicate-bot-id botId=${botId} accounts=${count}`);
|
|
42099
42232
|
}
|
|
42100
|
-
for (const { accountId, accountDir, entry:
|
|
42101
|
-
if (
|
|
42233
|
+
for (const { accountId, accountDir, entry: entry3 } of entries2) {
|
|
42234
|
+
if (entry3.role === "public" && !input.agentActive(accountDir, entry3.agent)) {
|
|
42102
42235
|
lines.push(
|
|
42103
|
-
`[telegram-audit] op=entry-agent-inactive accountId=${accountId} botId=${
|
|
42236
|
+
`[telegram-audit] op=entry-agent-inactive accountId=${accountId} botId=${entry3.id} agent=${entry3.agent}`
|
|
42104
42237
|
);
|
|
42105
42238
|
}
|
|
42106
|
-
if (!input.secretFileExists(
|
|
42107
|
-
lines.push(`[telegram-audit] op=secret-orphan botId=${
|
|
42239
|
+
if (!input.secretFileExists(entry3.id)) {
|
|
42240
|
+
lines.push(`[telegram-audit] op=secret-orphan botId=${entry3.id} side=entry`);
|
|
42108
42241
|
}
|
|
42109
42242
|
}
|
|
42110
42243
|
const known = new Set(entries2.map((e) => e.entry.id));
|
|
42111
42244
|
for (const botId of input.secretFilesOnDisk) {
|
|
42112
42245
|
if (!known.has(botId)) lines.push(`[telegram-audit] op=secret-orphan botId=${botId} side=file`);
|
|
42113
42246
|
}
|
|
42114
|
-
for (const { accountId, entry:
|
|
42115
|
-
const last = input.lastActivityByBot(
|
|
42247
|
+
for (const { accountId, entry: entry3 } of entries2) {
|
|
42248
|
+
const last = input.lastActivityByBot(entry3.id);
|
|
42116
42249
|
const spawnAge = last === null ? "never" : String(input.now - last.spawnMs);
|
|
42117
42250
|
const turnAge = last === null || last.turnMs === null ? "never" : String(input.now - last.turnMs);
|
|
42118
|
-
const agent = entryAgentSlug(
|
|
42119
|
-
const secretFile = input.secretFileExists(
|
|
42251
|
+
const agent = entryAgentSlug(entry3);
|
|
42252
|
+
const secretFile = input.secretFileExists(entry3.id) ? "present" : "absent";
|
|
42120
42253
|
lines.push(
|
|
42121
|
-
`[telegram-audit] op=configured botId=${
|
|
42254
|
+
`[telegram-audit] op=configured botId=${entry3.id} accountId=${accountId} agent=${agent} secretFile=${secretFile} lastSpawnAgeMs=${spawnAge} lastTurnAgeMs=${turnAge}`
|
|
42122
42255
|
);
|
|
42123
42256
|
}
|
|
42124
42257
|
let bound = 0;
|
|
42125
42258
|
let rosterOk = 0;
|
|
42126
42259
|
let rosterMissing = 0;
|
|
42127
|
-
for (const { accountId, accountDir, entry:
|
|
42128
|
-
if (
|
|
42260
|
+
for (const { accountId, accountDir, entry: entry3 } of entries2) {
|
|
42261
|
+
if (entry3.role !== "specialist") continue;
|
|
42129
42262
|
bound++;
|
|
42130
|
-
if (input.specialistCards(accountDir).includes(
|
|
42263
|
+
if (input.specialistCards(accountDir).includes(entry3.specialist)) {
|
|
42131
42264
|
rosterOk++;
|
|
42132
42265
|
} else {
|
|
42133
42266
|
rosterMissing++;
|
|
42134
42267
|
lines.push(
|
|
42135
|
-
`[telegram-audit] op=specialist-binding-missing accountId=${accountId} botId=${
|
|
42268
|
+
`[telegram-audit] op=specialist-binding-missing accountId=${accountId} botId=${entry3.id} specialist=${entry3.specialist}`
|
|
42136
42269
|
);
|
|
42137
42270
|
}
|
|
42138
42271
|
}
|
|
@@ -42152,9 +42285,9 @@ function buildManagedBotCensusLine(input) {
|
|
|
42152
42285
|
const byId = new Map(input.probes.map((p) => [p.botId, p]));
|
|
42153
42286
|
let webhookOk = 0;
|
|
42154
42287
|
let unrestricted = 0;
|
|
42155
|
-
for (const
|
|
42156
|
-
const probe = byId.get(
|
|
42157
|
-
if (probe && probe.webhookUrl && webhookPointsHere(probe.webhookUrl,
|
|
42288
|
+
for (const entry3 of managed) {
|
|
42289
|
+
const probe = byId.get(entry3.id);
|
|
42290
|
+
if (probe && probe.webhookUrl && webhookPointsHere(probe.webhookUrl, entry3.id)) webhookOk += 1;
|
|
42158
42291
|
if (probe?.isAccessRestricted === false) unrestricted += 1;
|
|
42159
42292
|
}
|
|
42160
42293
|
return `[telegram-audit] op=managed-bot-census bots=${entries2.length} managed=${managed.length} webhookOk=${webhookOk} webhookStale=${managed.length - webhookOk} unrestricted=${unrestricted}`;
|
|
@@ -42227,19 +42360,19 @@ function buildGroupCensusLine(c) {
|
|
|
42227
42360
|
async function runTelegramGroupCensus(accounts, deps) {
|
|
42228
42361
|
const counts = { bots: 0, groups: 0, present: 0, absent: 0, privacyOff: 0 };
|
|
42229
42362
|
for (const account of accounts) {
|
|
42230
|
-
for (const
|
|
42231
|
-
if (
|
|
42232
|
-
if ((
|
|
42363
|
+
for (const entry3 of listBotEntries(account.telegram)) {
|
|
42364
|
+
if (entry3.role !== "public") continue;
|
|
42365
|
+
if ((entry3.groupPolicy ?? "disabled") !== "allowlist") continue;
|
|
42233
42366
|
counts.bots += 1;
|
|
42234
42367
|
try {
|
|
42235
|
-
const me = await deps.getMe(
|
|
42368
|
+
const me = await deps.getMe(entry3.token);
|
|
42236
42369
|
if (me.can_read_all_group_messages === true) counts.privacyOff += 1;
|
|
42237
42370
|
} catch {
|
|
42238
42371
|
}
|
|
42239
|
-
for (const chatId of
|
|
42372
|
+
for (const chatId of entry3.allowGroups ?? []) {
|
|
42240
42373
|
counts.groups += 1;
|
|
42241
42374
|
try {
|
|
42242
|
-
const m = await deps.getChatMember(
|
|
42375
|
+
const m = await deps.getChatMember(entry3.token, chatId);
|
|
42243
42376
|
if (typeof m.status === "string" && PRESENT_STATUSES.has(m.status)) counts.present += 1;
|
|
42244
42377
|
else counts.absent += 1;
|
|
42245
42378
|
} catch {
|
|
@@ -42261,14 +42394,14 @@ function buildChannelCensusLine(c) {
|
|
|
42261
42394
|
async function runTelegramChannelCensus(accounts, deps) {
|
|
42262
42395
|
const counts = { bots: 0, channels: 0, admin: 0, notAdmin: 0, noPostRight: 0 };
|
|
42263
42396
|
for (const account of accounts) {
|
|
42264
|
-
for (const
|
|
42265
|
-
if (
|
|
42266
|
-
if ((
|
|
42397
|
+
for (const entry3 of listBotEntries(account.telegram)) {
|
|
42398
|
+
if (entry3.role !== "public") continue;
|
|
42399
|
+
if ((entry3.channelPolicy ?? "disabled") !== "allowlist") continue;
|
|
42267
42400
|
counts.bots += 1;
|
|
42268
|
-
for (const chatId of
|
|
42401
|
+
for (const chatId of entry3.allowChannels ?? []) {
|
|
42269
42402
|
counts.channels += 1;
|
|
42270
42403
|
try {
|
|
42271
|
-
const m = await deps.getChatMember(
|
|
42404
|
+
const m = await deps.getChatMember(entry3.token, chatId);
|
|
42272
42405
|
if (typeof m.status === "string" && ADMIN_STATUSES.has(m.status)) {
|
|
42273
42406
|
counts.admin += 1;
|
|
42274
42407
|
if (m.status === "administrator" && m.can_post_messages !== true) {
|
|
@@ -42593,17 +42726,17 @@ function broadcastAdminShutdown(reason) {
|
|
|
42593
42726
|
const done = encoder.encode(`data: [DONE]
|
|
42594
42727
|
|
|
42595
42728
|
`);
|
|
42596
|
-
for (const
|
|
42729
|
+
for (const entry3 of activeAdminSSEControllers) {
|
|
42597
42730
|
try {
|
|
42598
|
-
|
|
42731
|
+
entry3.controller.enqueue(frame);
|
|
42599
42732
|
} catch {
|
|
42600
42733
|
}
|
|
42601
42734
|
try {
|
|
42602
|
-
|
|
42735
|
+
entry3.controller.enqueue(done);
|
|
42603
42736
|
} catch {
|
|
42604
42737
|
}
|
|
42605
42738
|
try {
|
|
42606
|
-
|
|
42739
|
+
entry3.controller.close();
|
|
42607
42740
|
} catch {
|
|
42608
42741
|
}
|
|
42609
42742
|
}
|
|
@@ -42960,8 +43093,8 @@ var webchatFileFollowers = /* @__PURE__ */ new Map();
|
|
|
42960
43093
|
async function fetchAccountStandingRules(accountId) {
|
|
42961
43094
|
const session = getSession();
|
|
42962
43095
|
try {
|
|
42963
|
-
const res = await (0,
|
|
42964
|
-
return { block: (0,
|
|
43096
|
+
const res = await (0, import_dist18.resolveActiveRules)(session, accountId);
|
|
43097
|
+
return { block: (0, import_dist18.formatStandingRulesBlock)(res.rules), ownerUserId: res.ownerUserId, source: res.source };
|
|
42965
43098
|
} catch (err) {
|
|
42966
43099
|
console.error(
|
|
42967
43100
|
`[preference-inject] op=fetch-failed accountId=${accountId} error=${err instanceof Error ? err.message : String(err)}`
|
|
@@ -42997,6 +43130,7 @@ registerLoop({
|
|
|
42997
43130
|
run: () => {
|
|
42998
43131
|
const lines = parityCensusLines();
|
|
42999
43132
|
for (const line of lines) console.error(line);
|
|
43133
|
+
for (const line of cardCensusLines()) console.error(line);
|
|
43000
43134
|
const missing = lines.filter((l) => !l.includes("missing=0")).length;
|
|
43001
43135
|
return `${lines.length} session(s), ${missing} with a missing answer`;
|
|
43002
43136
|
}
|
|
@@ -43533,15 +43667,15 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
43533
43667
|
const entries2 = listBotEntries(a.config.telegram);
|
|
43534
43668
|
for (const bot of readChannelAdmins(a.accountDir, "telegram").byBot) {
|
|
43535
43669
|
if (!bot.adminUsers.includes(asNumber)) continue;
|
|
43536
|
-
const
|
|
43537
|
-
if (!
|
|
43670
|
+
const entry3 = entries2.find((e) => e.id === bot.botId);
|
|
43671
|
+
if (!entry3) continue;
|
|
43538
43672
|
hits.push({
|
|
43539
43673
|
accountId: a.accountId,
|
|
43540
43674
|
botId: bot.botId,
|
|
43541
|
-
botToken:
|
|
43675
|
+
botToken: entry3.token,
|
|
43542
43676
|
// Task 2617 — read off the entry this resolver just chose, so the
|
|
43543
43677
|
// outbound gate below decides on the same entry the token came from.
|
|
43544
|
-
...chatSendAllowlists(
|
|
43678
|
+
...chatSendAllowlists(entry3)
|
|
43545
43679
|
});
|
|
43546
43680
|
}
|
|
43547
43681
|
}
|
|
@@ -44627,24 +44761,24 @@ registerLoop({
|
|
|
44627
44761
|
const managed = accounts.flatMap((a) => {
|
|
44628
44762
|
const bots = listBotEntries(a.telegram);
|
|
44629
44763
|
const admin = bots.find((b) => b.role === "admin");
|
|
44630
|
-
return bots.filter((e) => e.managed === true).map((
|
|
44764
|
+
return bots.filter((e) => e.managed === true).map((entry3) => ({ entry: entry3, managingToken: admin?.token ?? null }));
|
|
44631
44765
|
});
|
|
44632
44766
|
const probes2 = [];
|
|
44633
|
-
for (const { entry:
|
|
44767
|
+
for (const { entry: entry3, managingToken } of managed) {
|
|
44634
44768
|
let webhookUrl = null;
|
|
44635
44769
|
let isAccessRestricted = null;
|
|
44636
44770
|
try {
|
|
44637
|
-
webhookUrl = (await getTelegramWebhookInfo(
|
|
44771
|
+
webhookUrl = (await getTelegramWebhookInfo(entry3.token)).url;
|
|
44638
44772
|
} catch {
|
|
44639
44773
|
}
|
|
44640
44774
|
if (managingToken) {
|
|
44641
44775
|
try {
|
|
44642
|
-
const got = await getManagedBotAccessSettings(managingToken, Number(
|
|
44776
|
+
const got = await getManagedBotAccessSettings(managingToken, Number(entry3.id));
|
|
44643
44777
|
if (got.ok) isAccessRestricted = got.isAccessRestricted;
|
|
44644
44778
|
} catch {
|
|
44645
44779
|
}
|
|
44646
44780
|
}
|
|
44647
|
-
probes2.push({ botId:
|
|
44781
|
+
probes2.push({ botId: entry3.id, webhookUrl, isAccessRestricted });
|
|
44648
44782
|
}
|
|
44649
44783
|
console.error(buildManagedBotCensusLine({ accounts, probes: probes2 }));
|
|
44650
44784
|
}
|