@rubytech/create-realagent-code 0.1.594 → 0.1.596

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.
Files changed (22) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/telegram-button-labels/dist/index.d.ts +19 -0
  3. package/payload/platform/lib/telegram-button-labels/dist/index.d.ts.map +1 -0
  4. package/payload/platform/lib/telegram-button-labels/dist/index.js +84 -0
  5. package/payload/platform/lib/telegram-button-labels/dist/index.js.map +1 -0
  6. package/payload/platform/lib/telegram-button-labels/src/__tests__/store.test.ts +67 -0
  7. package/payload/platform/lib/telegram-button-labels/src/index.ts +88 -0
  8. package/payload/platform/lib/telegram-button-labels/tsconfig.json +9 -0
  9. package/payload/platform/lib/telegram-button-labels/vitest.config.ts +9 -0
  10. package/payload/platform/package.json +2 -2
  11. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +8 -1
  12. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +10 -0
  13. package/payload/platform/plugins/docs/references/telegram-guide.md +7 -0
  14. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +74 -1
  15. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
  16. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +0 -11
  17. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  18. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +103 -3
  19. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  20. package/payload/platform/plugins/scheduling/skills/routine-control/SKILL.md +4 -0
  21. package/payload/server/public/operator.html +1 -1
  22. package/payload/server/server.js +564 -411
@@ -363,10 +363,10 @@ var require_dist2 = __commonJS({
363
363
  } catch {
364
364
  return { newest, storeRows };
365
365
  }
366
- for (const entry2 of entries2) {
367
- if (!entry2.endsWith(".jsonl"))
366
+ for (const entry3 of entries2) {
367
+ if (!entry3.endsWith(".jsonl"))
368
368
  continue;
369
- const stem = entry2.slice(0, -".jsonl".length);
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, entry2), "utf8");
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 require_dist5 = __commonJS({
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 require_dist6 = __commonJS({
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 require_dist7 = __commonJS({
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 require_dist8 = __commonJS({
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 = require_dist9();
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 require_dist9 = __commonJS({
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(entry2) {
3233
+ function recomputeFloorMs(entry3) {
3173
3234
  return Math.min(
3174
- Math.max(entry2.computeMs * RECOMPUTE_FLOOR_FACTOR, MIN_RECOMPUTE_FLOOR_MS),
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 entry2 = entries.get(key2);
3181
- if (entry2 !== void 0) {
3182
- const age = Date.now() - entry2.computedAt;
3183
- if (!entry2.dirty && age <= BACKSTOP_MS) {
3184
- return { value: entry2.value, state: "hit" };
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() - entry2.lastAttemptAt;
3187
- if (entry2.dirty && sinceAttempt < recomputeFloorMs(entry2) && age <= BACKSTOP_MS) {
3188
- return { value: entry2.value, state: "dirty-floor" };
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 = entry2 === void 0 ? "miss" : "stale-backstop";
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 entry2 = entries.get(key2);
3237
- if (entry2) entry2.dirty = true;
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 entry2 of readdirSync(dir)) {
3431
- if (!entry2.endsWith(".jsonl")) continue;
3432
- const stem = entry2.slice(0, -".jsonl".length);
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 entry2 of readdirSync(dir)) {
3462
- if (!entry2.endsWith(".jsonl")) continue;
3463
- const stem = entry2.slice(0, -".jsonl".length);
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, entry2);
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 entry2 of entries2) {
5129
- if (entry2.family !== "IPv4" || entry2.internal) continue;
5130
- if (entry2.address.startsWith("192.168.") || entry2.address.startsWith("10.")) {
5131
- return entry2.address;
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 = entry2.address;
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(entry2) {
6096
- if (!entry2 || entry2.role !== "public") return { allowChannels: [], allowGroups: [] };
6097
- return { allowChannels: entry2.allowChannels ?? [], allowGroups: entry2.allowGroups ?? [] };
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, entry2] of cache2) obj[sessionId] = entry2;
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, entry2] of updates) merged.set(sessionId, entry2);
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 entry2 of entries2) {
6657
- if (entry2.isFile() && fileRe.test(entry2.name)) {
6658
- out.push({ path: join11(slugDir, entry2.name), isSubagent: false, archived: false });
6659
- } else if (entry2.isDirectory() && entry2.name === "subagents") {
6660
- const subDir = join11(slugDir, entry2.name);
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 (entry2.isDirectory() && entry2.name === "archive") {
6676
- const archiveDir = join11(slugDir, entry2.name);
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 });
@@ -7092,6 +7153,20 @@ function transcriptBoundary(sessionKey) {
7092
7153
  return { transcriptOffset: null, bounded: false };
7093
7154
  }
7094
7155
  }
7156
+ function composeDeliveredText(prompt, deliveredMessages) {
7157
+ if (!Array.isArray(deliveredMessages) || deliveredMessages.length === 0) return prompt;
7158
+ const lines = deliveredMessages.map((m) => {
7159
+ const r = m ?? {};
7160
+ const who = typeof r.senderName === "string" && r.senderName.trim() !== "" ? r.senderName : String(r.senderId ?? "unknown");
7161
+ const when = typeof r.createdAt === "string" ? r.createdAt : "";
7162
+ const text = typeof r.body === "string" ? r.body : "";
7163
+ return `- ${who} (${when}): ${text}`;
7164
+ });
7165
+ return `${prompt}
7166
+
7167
+ ## Messages since the last check
7168
+ ${lines.join("\n")}`;
7169
+ }
7095
7170
  function createScheduleInjectRoutes(deps) {
7096
7171
  const app81 = new Hono();
7097
7172
  app81.post("/", async (c) => {
@@ -7120,6 +7195,7 @@ function createScheduleInjectRoutes(deps) {
7120
7195
  const eventAccountId = typeof body.accountId === "string" && body.accountId.length > 0 ? body.accountId : null;
7121
7196
  const destination = typeof body.destination === "string" ? body.destination : "";
7122
7197
  const prompt = typeof body.prompt === "string" ? body.prompt : "";
7198
+ const injectedText = composeDeliveredText(prompt, body.deliveredMessages);
7123
7199
  const eventId = typeof body.eventId === "string" ? body.eventId : "";
7124
7200
  const scheduleProvenance = parseScheduleProvenance(body.scheduleProvenance);
7125
7201
  if (channel !== "whatsapp" && channel !== "telegram" || !destination || !prompt) {
@@ -7262,7 +7338,7 @@ function createScheduleInjectRoutes(deps) {
7262
7338
  // Task 2619 — a scheduled dispatch is always role:'admin' (see above),
7263
7339
  // so it names no specialist card.
7264
7340
  specialist: null,
7265
- text: prompt,
7341
+ text: injectedText,
7266
7342
  // Task 2489 — a scheduled inject carries no inbound file by
7267
7343
  // construction: there is no message to have attached one.
7268
7344
  media: [],
@@ -7281,7 +7357,7 @@ function createScheduleInjectRoutes(deps) {
7281
7357
  }
7282
7358
 
7283
7359
  // server/index.ts
7284
- var import_dist17 = __toESM(require_dist3(), 1);
7360
+ var import_dist18 = __toESM(require_dist3(), 1);
7285
7361
 
7286
7362
  // app/lib/whatsapp/avatar-store.ts
7287
7363
  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 +7594,12 @@ async function sweepAvatars() {
7518
7594
  var TAG9 = "[wa-chatmeta]";
7519
7595
  function diffStoredAgainstLive(stored, live) {
7520
7596
  const out = [];
7521
- for (const entry2 of stored.values()) {
7522
- if (!entry2.isGroup) continue;
7523
- const seen = live.get(entry2.jid);
7597
+ for (const entry3 of stored.values()) {
7598
+ if (!entry3.isGroup) continue;
7599
+ const seen = live.get(entry3.jid);
7524
7600
  if (seen === void 0) continue;
7525
- if (seen.name !== entry2.name) {
7526
- out.push({ jid: entry2.jid, stored: entry2.name, live: seen.name, observedAt: seen.observedAt });
7601
+ if (seen.name !== entry3.name) {
7602
+ out.push({ jid: entry3.jid, stored: entry3.name, live: seen.name, observedAt: seen.observedAt });
7527
7603
  }
7528
7604
  }
7529
7605
  return out;
@@ -7539,13 +7615,13 @@ async function sweepChatMetadata() {
7539
7615
  const sock = conn.sock;
7540
7616
  const stored = readChatMetadata(conn.platformAccountId);
7541
7617
  const live = /* @__PURE__ */ new Map();
7542
- for (const entry2 of stored.values()) {
7543
- if (!entry2.isGroup) continue;
7618
+ for (const entry3 of stored.values()) {
7619
+ if (!entry3.isGroup) continue;
7544
7620
  groups += 1;
7545
7621
  try {
7546
- const meta = await sock.groupMetadata(entry2.jid);
7622
+ const meta = await sock.groupMetadata(entry3.jid);
7547
7623
  if (typeof meta.subject === "string" && meta.subject.length > 0) {
7548
- live.set(entry2.jid, { name: meta.subject, observedAt: (/* @__PURE__ */ new Date()).toISOString() });
7624
+ live.set(entry3.jid, { name: meta.subject, observedAt: (/* @__PURE__ */ new Date()).toISOString() });
7549
7625
  checked2 += 1;
7550
7626
  }
7551
7627
  } catch {
@@ -8208,9 +8284,9 @@ function purgeNonSocketAccountManagers(accountDir, socketOwnerId) {
8208
8284
  if (targetId === socketOwnerId) return { removed: [] };
8209
8285
  const map = wa.accountManagers;
8210
8286
  if (!map || typeof map !== "object" || Array.isArray(map)) return { removed: [] };
8211
- const removed = Object.entries(map).map(([phone, entry2]) => ({
8287
+ const removed = Object.entries(map).map(([phone, entry3]) => ({
8212
8288
  phone,
8213
- managesAccount: typeof entry2 === "string" ? entry2 : entry2 && typeof entry2 === "object" && typeof entry2.managesAccount === "string" ? entry2.managesAccount : ""
8289
+ managesAccount: typeof entry3 === "string" ? entry3 : entry3 && typeof entry3 === "object" && typeof entry3.managesAccount === "string" ? entry3.managesAccount : ""
8214
8290
  }));
8215
8291
  if (removed.length === 0) return { removed: [] };
8216
8292
  delete wa.accountManagers;
@@ -8513,10 +8589,10 @@ function purgeNonSocketRegisteredParties(accountDir, socketOwnerId) {
8513
8589
  if (targetId === socketOwnerId) return { removed: [] };
8514
8590
  const map = wa.registeredParties;
8515
8591
  if (!map || typeof map !== "object" || Array.isArray(map)) return { removed: [] };
8516
- const removed = Object.entries(map).map(([phone, entry2]) => ({
8592
+ const removed = Object.entries(map).map(([phone, entry3]) => ({
8517
8593
  phone,
8518
- account: entry2 && typeof entry2 === "object" && typeof entry2.account === "string" ? entry2.account : "",
8519
- party: entry2 && typeof entry2 === "object" && typeof entry2.party === "string" ? entry2.party : ""
8594
+ account: entry3 && typeof entry3 === "object" && typeof entry3.account === "string" ? entry3.account : "",
8595
+ party: entry3 && typeof entry3 === "object" && typeof entry3.party === "string" ? entry3.party : ""
8520
8596
  }));
8521
8597
  if (removed.length === 0) return { removed: [] };
8522
8598
  delete wa.registeredParties;
@@ -9350,27 +9426,27 @@ function bare(value) {
9350
9426
  function reconcilePersonIdentities(rows) {
9351
9427
  const perAccount = /* @__PURE__ */ new Map();
9352
9428
  for (const row of rows) {
9353
- let entry2 = perAccount.get(row.accountId);
9354
- if (!entry2) {
9355
- entry2 = { seen: /* @__PURE__ */ new Map(), divergent: 0 };
9356
- perAccount.set(row.accountId, entry2);
9429
+ let entry3 = perAccount.get(row.accountId);
9430
+ if (!entry3) {
9431
+ entry3 = { seen: /* @__PURE__ */ new Map(), divergent: 0 };
9432
+ perAccount.set(row.accountId, entry3);
9357
9433
  }
9358
9434
  const p = row.phone ? bare(row.phone) : null;
9359
9435
  const t = row.telephone ? bare(row.telephone) : null;
9360
- if (p && t && p !== t) entry2.divergent += 1;
9436
+ if (p && t && p !== t) entry3.divergent += 1;
9361
9437
  const key2 = p ?? t;
9362
- if (key2) entry2.seen.set(key2, (entry2.seen.get(key2) ?? 0) + 1);
9438
+ if (key2) entry3.seen.set(key2, (entry3.seen.get(key2) ?? 0) + 1);
9363
9439
  }
9364
9440
  const accounts = [];
9365
9441
  let duplicates = 0;
9366
9442
  let divergent = 0;
9367
- for (const [accountId, entry2] of perAccount) {
9443
+ for (const [accountId, entry3] of perAccount) {
9368
9444
  let dup = 0;
9369
- for (const count of entry2.seen.values()) if (count > 1) dup += count - 1;
9445
+ for (const count of entry3.seen.values()) if (count > 1) dup += count - 1;
9370
9446
  duplicates += dup;
9371
- divergent += entry2.divergent;
9372
- if (dup > 0 || entry2.divergent > 0) {
9373
- accounts.push({ accountId, duplicates: dup, divergent: entry2.divergent });
9447
+ divergent += entry3.divergent;
9448
+ if (dup > 0 || entry3.divergent > 0) {
9449
+ accounts.push({ accountId, duplicates: dup, divergent: entry3.divergent });
9374
9450
  }
9375
9451
  }
9376
9452
  return {
@@ -9392,7 +9468,7 @@ function reconcileSelfPhoneAdmins(input) {
9392
9468
  for (const cred of nonHouse) {
9393
9469
  const selfPhone = cred.selfPhone;
9394
9470
  if (!selfPhone) continue;
9395
- if (input.adminPhones.some((entry2) => phonesMatch(entry2, selfPhone))) {
9471
+ if (input.adminPhones.some((entry3) => phonesMatch(entry3, selfPhone))) {
9396
9472
  matches.push({ accountId: cred.accountId, phone: selfPhone });
9397
9473
  }
9398
9474
  }
@@ -9773,11 +9849,11 @@ function authorizeRecallRead(input) {
9773
9849
  function buildRegisteredPartyReconcile(params) {
9774
9850
  const rows = [];
9775
9851
  const entries2 = Object.entries(params.registeredParties);
9776
- for (const [phone, entry2] of entries2) {
9852
+ for (const [phone, entry3] of entries2) {
9777
9853
  const shadowedBy = isAdminPhone(phone, params.adminPhones) ? "adminPhones" : managedAccountFor(params.accountManagers, phone) ? "accountManagers" : null;
9778
- const unresolved2 = !params.isValidAccount(entry2.account);
9854
+ const unresolved2 = !params.isValidAccount(entry3.account);
9779
9855
  if (shadowedBy || unresolved2) {
9780
- rows.push({ phone, account: entry2.account, party: entry2.party, shadowedBy, unresolved: unresolved2 });
9856
+ rows.push({ phone, account: entry3.account, party: entry3.party, shadowedBy, unresolved: unresolved2 });
9781
9857
  }
9782
9858
  }
9783
9859
  const shadowed = rows.filter((r) => r.shadowedBy !== null).length;
@@ -10187,15 +10263,15 @@ app3.post("/config", async (c) => {
10187
10263
  const agents = [];
10188
10264
  if (existsSync9(agentsDir)) {
10189
10265
  try {
10190
- for (const entry2 of readdirSync8(agentsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
10191
- if (!entry2.isDirectory() || entry2.name === "admin") continue;
10192
- const configPath3 = resolve8(agentsDir, entry2.name, "config.json");
10266
+ for (const entry3 of readdirSync8(agentsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
10267
+ if (!entry3.isDirectory() || entry3.name === "admin") continue;
10268
+ const configPath3 = resolve8(agentsDir, entry3.name, "config.json");
10193
10269
  if (!existsSync9(configPath3)) continue;
10194
10270
  try {
10195
10271
  const parsed = JSON.parse(readFileSync11(configPath3, "utf-8"));
10196
- agents.push({ slug: entry2.name, displayName: parsed.displayName ?? entry2.name });
10272
+ agents.push({ slug: entry3.name, displayName: parsed.displayName ?? entry3.name });
10197
10273
  } catch {
10198
- console.error(`${TAG17} config action=list-public-agents error="failed to parse config.json for agent ${entry2.name}" \u2014 skipping`);
10274
+ console.error(`${TAG17} config action=list-public-agents error="failed to parse config.json for agent ${entry3.name}" \u2014 skipping`);
10199
10275
  }
10200
10276
  }
10201
10277
  } catch (err) {
@@ -10215,8 +10291,8 @@ app3.post("/config", async (c) => {
10215
10291
  const listDenial = bindingScopeDenial(c, callerAccountId, "list-account-managers");
10216
10292
  if (listDenial) return listDenial;
10217
10293
  const all = readAccountManagers(acct.accountDir);
10218
- const boundAccountOf = (entry2) => typeof entry2 === "string" ? entry2 : entry2.managesAccount;
10219
- const accountManagers = houseAdmin ? all : Object.fromEntries(Object.entries(all).filter(([, entry2]) => boundAccountOf(entry2) === callerAccountId));
10294
+ const boundAccountOf = (entry3) => typeof entry3 === "string" ? entry3 : entry3.managesAccount;
10295
+ const accountManagers = houseAdmin ? all : Object.fromEntries(Object.entries(all).filter(([, entry3]) => boundAccountOf(entry3) === callerAccountId));
10220
10296
  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
10297
  return c.json({ ok: true, accountManagers });
10222
10298
  }
@@ -10254,7 +10330,7 @@ app3.post("/config", async (c) => {
10254
10330
  const listDenial = bindingScopeDenial(c, callerAccountId, "list-registered-parties");
10255
10331
  if (listDenial) return listDenial;
10256
10332
  const all = readRegisteredParties(acct.accountDir);
10257
- const registeredParties = houseAdmin ? all : Object.fromEntries(Object.entries(all).filter(([, entry2]) => entry2.account === callerAccountId));
10333
+ const registeredParties = houseAdmin ? all : Object.fromEntries(Object.entries(all).filter(([, entry3]) => entry3.account === callerAccountId));
10258
10334
  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
10335
  return c.json({ ok: true, registeredParties });
10260
10336
  }
@@ -12159,10 +12235,10 @@ function readState(platformRoot5) {
12159
12235
  return {};
12160
12236
  }
12161
12237
  }
12162
- function recordSuccess(platformRoot5, accountId, entry2) {
12238
+ function recordSuccess(platformRoot5, accountId, entry3) {
12163
12239
  const path = stateFilePath(platformRoot5);
12164
12240
  const state = readState(platformRoot5);
12165
- state[accountId] = entry2;
12241
+ state[accountId] = entry3;
12166
12242
  try {
12167
12243
  writeFileSync6(path, JSON.stringify(state, null, 1));
12168
12244
  } catch (err) {
@@ -13259,10 +13335,10 @@ function readVisitsPushState(platformRoot5) {
13259
13335
  return {};
13260
13336
  }
13261
13337
  }
13262
- function recordVisitsPush(platformRoot5, accountId, entry2) {
13338
+ function recordVisitsPush(platformRoot5, accountId, entry3) {
13263
13339
  const path = visitsStateFilePath(platformRoot5);
13264
13340
  const state = readVisitsPushState(platformRoot5);
13265
- state[accountId] = entry2;
13341
+ state[accountId] = entry3;
13266
13342
  try {
13267
13343
  writeFileSync7(path, JSON.stringify(state, null, 1));
13268
13344
  } catch (err) {
@@ -14906,20 +14982,20 @@ function listBotEntries(config) {
14906
14982
  }
14907
14983
  return out;
14908
14984
  }
14909
- function entryAgentSlug(entry2) {
14910
- if (entry2.role === "admin") return "admin";
14911
- if (entry2.role === "unbound") return "unbound";
14912
- if (entry2.role === "specialist") return entry2.specialist;
14913
- return entry2.agent;
14985
+ function entryAgentSlug(entry3) {
14986
+ if (entry3.role === "admin") return "admin";
14987
+ if (entry3.role === "unbound") return "unbound";
14988
+ if (entry3.role === "specialist") return entry3.specialist;
14989
+ return entry3.agent;
14914
14990
  }
14915
- function isBindableEntry(entry2) {
14916
- return entry2.role !== "unbound";
14991
+ function isBindableEntry(entry3) {
14992
+ return entry3.role !== "unbound";
14917
14993
  }
14918
14994
  function resolveBotEntry(accounts, botId) {
14919
14995
  const hits = [];
14920
14996
  for (const a of accounts) {
14921
- for (const entry2 of listBotEntries(a.config.telegram)) {
14922
- if (entry2.id === botId) hits.push({ accountId: a.accountId, accountDir: a.accountDir, entry: entry2 });
14997
+ for (const entry3 of listBotEntries(a.config.telegram)) {
14998
+ if (entry3.id === botId) hits.push({ accountId: a.accountId, accountDir: a.accountDir, entry: entry3 });
14923
14999
  }
14924
15000
  }
14925
15001
  if (hits.length === 0) return { kind: "none" };
@@ -15023,20 +15099,24 @@ app6.get("/gate-probe", (c) => {
15023
15099
  return resolution === "scope" ? c.json({ error: "that telegram bot belongs to another account", reason: "account-scope" }, 403) : c.json({ error: "no such telegram bot", reason: "unknown-bot" }, 404);
15024
15100
  }
15025
15101
  }
15102
+ const since = c.req.query("since")?.trim() || null;
15026
15103
  const all = [...readConversationSummaries2(accountId).keys()];
15027
15104
  const keys = botId === null ? all : all.filter((k) => parseTelegramChannelKey(k)?.botId === botId);
15028
15105
  let newestInboundAt = null;
15106
+ const messages = [];
15029
15107
  for (const channelKey of keys) {
15030
15108
  for (const row of readRows(accountId, channelKey)) {
15031
15109
  if (isUpdateRecord(row)) continue;
15032
15110
  if (row.origin !== "inbound") continue;
15033
15111
  if (newestInboundAt === null || row.createdAt > newestInboundAt) newestInboundAt = row.createdAt;
15112
+ if (since !== null && row.createdAt > since) messages.push(row);
15034
15113
  }
15035
15114
  }
15115
+ messages.sort((a, b) => a.createdAt < b.createdAt ? -1 : a.createdAt > b.createdAt ? 1 : 0);
15036
15116
  console.log(
15037
15117
  `${TAG24} op=gate-probe accountId=${accountId.slice(0, 8)} botId=${botId ?? "all"} resolution=${resolution} conversations=${keys.length} ofAccount=${all.length} newestInboundAt=${newestInboundAt ?? "null"}`
15038
15118
  );
15039
- return c.json({ newestInboundAt });
15119
+ return c.json(since === null ? { newestInboundAt } : { newestInboundAt, messages });
15040
15120
  });
15041
15121
  app6.get("/store-backfill", requireAdminSession, (c) => {
15042
15122
  const v = validate(c.req.query("accountId"), c.req.query("channelKey"));
@@ -16964,7 +17044,7 @@ function createSidecarStore(config) {
16964
17044
  function readAll3(sessionsDir, onSkip) {
16965
17045
  let names;
16966
17046
  try {
16967
- names = readdirSync17(sessionsDir, { withFileTypes: true }).filter((entry2) => entry2.isFile()).map((entry2) => entry2.name);
17047
+ names = readdirSync17(sessionsDir, { withFileTypes: true }).filter((entry3) => entry3.isFile()).map((entry3) => entry3.name);
16968
17048
  } catch {
16969
17049
  return [];
16970
17050
  }
@@ -17897,7 +17977,7 @@ async function setTelegramWebhook(botToken, webhookUrl, secretFilePath, fetchImp
17897
17977
  }
17898
17978
  return { ok: true, secret };
17899
17979
  }
17900
- function writeTelegramBotEntry(accountDir, entry2) {
17980
+ function writeTelegramBotEntry(accountDir, entry3) {
17901
17981
  const configPath3 = join36(accountDir, "account.json");
17902
17982
  if (!existsSync25(configPath3)) {
17903
17983
  return { ok: false, error: `account.json not found at ${configPath3}` };
@@ -17910,9 +17990,9 @@ function writeTelegramBotEntry(accountDir, entry2) {
17910
17990
  }
17911
17991
  const telegram = config.telegram ?? {};
17912
17992
  const bots = Array.isArray(telegram.bots) ? telegram.bots : [];
17913
- const at = bots.findIndex((b) => b && typeof b === "object" && b.id === entry2.id);
17914
- if (at >= 0) bots[at] = entry2;
17915
- else bots.push(entry2);
17993
+ const at = bots.findIndex((b) => b && typeof b === "object" && b.id === entry3.id);
17994
+ if (at >= 0) bots[at] = entry3;
17995
+ else bots.push(entry3);
17916
17996
  telegram.bots = bots;
17917
17997
  config.telegram = telegram;
17918
17998
  writeFileSync12(configPath3, JSON.stringify(config, null, 2) + "\n", "utf-8");
@@ -17998,34 +18078,34 @@ function getTelegramGateway() {
17998
18078
 
17999
18079
  // app/lib/telegram/access-control.ts
18000
18080
  function checkTelegramAccess(params) {
18001
- const { senderId, entry: entry2, chatId, chatType } = params;
18081
+ const { senderId, entry: entry3, chatId, chatType } = params;
18002
18082
  const isGroup = chatType === "group" || chatType === "supergroup";
18003
18083
  const isChannel = chatType === "channel";
18004
- if (isChannel && entry2.role !== "public") {
18084
+ if (isChannel && entry3.role !== "public") {
18005
18085
  return {
18006
18086
  allowed: false,
18007
- reason: entry2.role === "admin" ? "admin-entry-no-channels" : entry2.role === "specialist" ? "specialist-entry-no-channels" : "unbound-entry-no-channels",
18008
- agentType: entry2.role === "admin" ? "admin" : entry2.role === "specialist" ? "specialist" : "public"
18087
+ reason: entry3.role === "admin" ? "admin-entry-no-channels" : entry3.role === "specialist" ? "specialist-entry-no-channels" : "unbound-entry-no-channels",
18088
+ agentType: entry3.role === "admin" ? "admin" : entry3.role === "specialist" ? "specialist" : "public"
18009
18089
  };
18010
18090
  }
18011
- if (isGroup && entry2.role !== "public") {
18091
+ if (isGroup && entry3.role !== "public") {
18012
18092
  return {
18013
18093
  allowed: false,
18014
- reason: entry2.role === "admin" ? "admin-entry-no-groups" : entry2.role === "specialist" ? "specialist-entry-no-groups" : "unbound-entry-no-groups",
18015
- agentType: entry2.role === "admin" ? "admin" : entry2.role === "specialist" ? "specialist" : "public"
18094
+ reason: entry3.role === "admin" ? "admin-entry-no-groups" : entry3.role === "specialist" ? "specialist-entry-no-groups" : "unbound-entry-no-groups",
18095
+ agentType: entry3.role === "admin" ? "admin" : entry3.role === "specialist" ? "specialist" : "public"
18016
18096
  };
18017
18097
  }
18018
- if (entry2.role === "admin") {
18019
- const adminUsers = entry2.adminUsers ?? [];
18098
+ if (entry3.role === "admin") {
18099
+ const adminUsers = entry3.adminUsers ?? [];
18020
18100
  if (adminUsers.includes(senderId)) {
18021
18101
  return { allowed: true, reason: "admin-binding", agentType: "admin" };
18022
18102
  }
18023
18103
  return { allowed: false, reason: "not-admin-user", agentType: "admin" };
18024
18104
  }
18025
- if (isGroup && entry2.role === "public") {
18026
- const groupPolicy = entry2.groupPolicy ?? "disabled";
18105
+ if (isGroup && entry3.role === "public") {
18106
+ const groupPolicy = entry3.groupPolicy ?? "disabled";
18027
18107
  if (groupPolicy === "allowlist") {
18028
- const allowGroups = entry2.allowGroups ?? [];
18108
+ const allowGroups = entry3.allowGroups ?? [];
18029
18109
  if (allowGroups.includes(chatId)) {
18030
18110
  return { allowed: true, reason: "group-allowlist-match", agentType: "public" };
18031
18111
  }
@@ -18033,10 +18113,10 @@ function checkTelegramAccess(params) {
18033
18113
  }
18034
18114
  return { allowed: false, reason: "group-policy-disabled", agentType: "public" };
18035
18115
  }
18036
- if (isChannel && entry2.role === "public") {
18037
- const channelPolicy = entry2.channelPolicy ?? "disabled";
18116
+ if (isChannel && entry3.role === "public") {
18117
+ const channelPolicy = entry3.channelPolicy ?? "disabled";
18038
18118
  if (channelPolicy === "allowlist") {
18039
- const allowChannels = entry2.allowChannels ?? [];
18119
+ const allowChannels = entry3.allowChannels ?? [];
18040
18120
  if (allowChannels.includes(chatId)) {
18041
18121
  return { allowed: true, reason: "channel-allowlist-match", agentType: "public" };
18042
18122
  }
@@ -18044,22 +18124,22 @@ function checkTelegramAccess(params) {
18044
18124
  }
18045
18125
  return { allowed: false, reason: "channel-policy-disabled", agentType: "public" };
18046
18126
  }
18047
- if (entry2.role === "unbound") {
18127
+ if (entry3.role === "unbound") {
18048
18128
  return { allowed: false, reason: "bot-unbound", agentType: "public" };
18049
18129
  }
18050
- if (entry2.role === "specialist") {
18051
- const allowFrom = entry2.allowFrom ?? [];
18130
+ if (entry3.role === "specialist") {
18131
+ const allowFrom = entry3.allowFrom ?? [];
18052
18132
  if (allowFrom.includes(senderId)) {
18053
18133
  return { allowed: true, reason: "specialist-allowlist-match", agentType: "specialist" };
18054
18134
  }
18055
18135
  return { allowed: false, reason: "not-in-allowlist", agentType: "specialist" };
18056
18136
  }
18057
- const policy = entry2.dmPolicy ?? "disabled";
18137
+ const policy = entry3.dmPolicy ?? "disabled";
18058
18138
  switch (policy) {
18059
18139
  case "open":
18060
18140
  return { allowed: true, reason: "dm-policy-open", agentType: "public" };
18061
18141
  case "allowlist": {
18062
- const allowFrom = entry2.allowFrom ?? [];
18142
+ const allowFrom = entry3.allowFrom ?? [];
18063
18143
  if (allowFrom.includes(senderId)) {
18064
18144
  return { allowed: true, reason: "allowlist-match", agentType: "public" };
18065
18145
  }
@@ -19082,6 +19162,9 @@ function runTelegramNotifyReconcile(now) {
19082
19162
  console.error(buildTelegramKindCensusLine(readTelegramKindCensus()));
19083
19163
  }
19084
19164
 
19165
+ // server/routes/telegram.ts
19166
+ var import_dist8 = __toESM(require_dist5(), 1);
19167
+
19085
19168
  // app/lib/telegram/outbound/answer-callback.ts
19086
19169
  async function answerTelegramCallback(botToken, callbackQueryId, text) {
19087
19170
  try {
@@ -19114,8 +19197,8 @@ var NOTIFY_MAX = 5e3;
19114
19197
  var cache = /* @__PURE__ */ new Map();
19115
19198
  function isTelegramNotifyDuplicate(notifyId) {
19116
19199
  const now = Date.now();
19117
- const entry2 = cache.get(notifyId);
19118
- if (entry2 && now - entry2.ts <= NOTIFY_TTL_MS) return true;
19200
+ const entry3 = cache.get(notifyId);
19201
+ if (entry3 && now - entry3.ts <= NOTIFY_TTL_MS) return true;
19119
19202
  for (const [key2, e] of cache) {
19120
19203
  if (now - e.ts > NOTIFY_TTL_MS) cache.delete(key2);
19121
19204
  }
@@ -19174,7 +19257,7 @@ function runTelegramNotifyPublishCensus(now) {
19174
19257
  }
19175
19258
 
19176
19259
  // ../lib/dispatch-write/src/lifecycle.ts
19177
- var import_dist6 = __toESM(require_dist5());
19260
+ var import_dist6 = __toESM(require_dist6());
19178
19261
  function checkTransition(kind, from, to, cfg) {
19179
19262
  const edges = kind === "job" ? cfg.statuses.jobTransitions : cfg.statuses.visitTransitions;
19180
19263
  const legal = edges.some(([f, t]) => f === from && t === to);
@@ -19216,7 +19299,7 @@ function formatTransitionRefused(p) {
19216
19299
  }
19217
19300
 
19218
19301
  // ../lib/dispatch-write/src/write.ts
19219
- var import_dist7 = __toESM(require_dist5());
19302
+ var import_dist7 = __toESM(require_dist6());
19220
19303
  function refuse(reason, message) {
19221
19304
  return { ok: false, reason, message };
19222
19305
  }
@@ -19793,8 +19876,8 @@ function liveLocationCensusLine(accountsRoot, now) {
19793
19876
  let expired = 0;
19794
19877
  let oldestAgeMs = 0;
19795
19878
  try {
19796
- for (const entry2 of readdirSync20(accountsRoot)) {
19797
- const path = join38(accountsRoot, entry2, LIVE_LOCATION_FILE);
19879
+ for (const entry3 of readdirSync20(accountsRoot)) {
19880
+ const path = join38(accountsRoot, entry3, LIVE_LOCATION_FILE);
19798
19881
  if (!existsSync26(path) || !statSync19(path).isFile()) continue;
19799
19882
  for (const rec of Object.values(readAll(path))) {
19800
19883
  records3 += 1;
@@ -19930,20 +20013,20 @@ async function editTelegramMessage(botToken, chatId, messageId, text, keyboard)
19930
20013
  // server/routes/telegram.ts
19931
20014
  var TAG34 = "[telegram-inbound]";
19932
20015
  var PROVISION_TAG = "[telegram-provision]";
19933
- function entryActive(entry2, accountDir, botId, noteSpecialist) {
19934
- if (entry2.role === "admin") return true;
19935
- if (entry2.role === "specialist") {
20016
+ function entryActive(entry3, accountDir, botId, noteSpecialist) {
20017
+ if (entry3.role === "admin") return true;
20018
+ if (entry3.role === "specialist") {
19936
20019
  const cards = listSpecialistCardNames(join40(accountDir, "specialists", "agents"));
19937
- const rosterValid = cards.includes(entry2.specialist);
20020
+ const rosterValid = cards.includes(entry3.specialist);
19938
20021
  noteSpecialist?.(rosterValid);
19939
20022
  if (rosterValid) return true;
19940
20023
  console.error(
19941
- `${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(entry2.specialist)} reason=specialist-unknown`
20024
+ `${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=specialist-unknown`
19942
20025
  );
19943
20026
  return false;
19944
20027
  }
19945
- if (entry2.role === "unbound") return false;
19946
- return isActiveAgentSlug(accountDir, entry2.agent);
20028
+ if (entry3.role === "unbound") return false;
20029
+ return isActiveAgentSlug(accountDir, entry3.agent);
19947
20030
  }
19948
20031
  function logValue2(v) {
19949
20032
  return v.replace(/[\r\n]+/g, " ");
@@ -20055,9 +20138,9 @@ app11.post("/", async (c) => {
20055
20138
  console.error(`${TAG34} op=reject reason=duplicate-bot-id botId=${botId} accounts=${resolved.count}`);
20056
20139
  return c.json({ ok: false }, 401);
20057
20140
  }
20058
- const { accountId, accountDir, entry: entry2 } = resolved;
20059
- const agentSlug = entryAgentSlug(entry2);
20060
- console.error(`${TAG34} op=entry botId=${botId} accountId=${accountId} role=${entry2.role} agent=${agentSlug}`);
20141
+ const { accountId, accountDir, entry: entry3 } = resolved;
20142
+ const agentSlug = entryAgentSlug(entry3);
20143
+ console.error(`${TAG34} op=entry botId=${botId} accountId=${accountId} role=${entry3.role} agent=${agentSlug}`);
20061
20144
  const sp = secretPath(botId);
20062
20145
  if (!existsSync28(sp)) {
20063
20146
  console.error(`${TAG34} op=secret botId=${botId} result=missing-file`);
@@ -20090,13 +20173,13 @@ app11.post("/", async (c) => {
20090
20173
  });
20091
20174
  }
20092
20175
  if (shape.chatType === "group" || shape.chatType === "supergroup") {
20093
- const allowlisted = entry2.role === "public" && (entry2.groupPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry2.allowGroups ?? []).includes(shape.chatId);
20176
+ const allowlisted = entry3.role === "public" && (entry3.groupPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry3.allowGroups ?? []).includes(shape.chatId);
20094
20177
  console.error(
20095
20178
  `${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
20179
  );
20097
20180
  }
20098
20181
  if (shape.chatType === "channel") {
20099
- const allowlisted = entry2.role === "public" && (entry2.channelPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry2.allowChannels ?? []).includes(shape.chatId);
20182
+ const allowlisted = entry3.role === "public" && (entry3.channelPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry3.allowChannels ?? []).includes(shape.chatId);
20100
20183
  console.error(
20101
20184
  `${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
20185
  );
@@ -20104,7 +20187,7 @@ app11.post("/", async (c) => {
20104
20187
  const hostBots = update.managed_bot ? listBotEntries(accountConfig(accountDir).telegram) : [];
20105
20188
  const decision = routeTelegramUpdate({
20106
20189
  update,
20107
- entry: entry2,
20190
+ entry: entry3,
20108
20191
  ...update.managed_bot ? { knownBotIds: hostBots.map((b) => b.id) } : {}
20109
20192
  });
20110
20193
  const raisesTurn = decision.kind === "dispatch" || // Task 2615 — a customer asking a question raises one. `business-deleted`
@@ -20134,14 +20217,14 @@ app11.post("/", async (c) => {
20134
20217
  );
20135
20218
  }
20136
20219
  console.error(`${TAG34} op=access botId=${botId} senderId=- allowed=false reason=${decision.reason}`);
20137
- if (entry2.role === "specialist") {
20220
+ if (entry3.role === "specialist") {
20138
20221
  console.error(
20139
- `${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(entry2.specialist)} reason=${decision.reason}`
20222
+ `${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=${decision.reason}`
20140
20223
  );
20141
20224
  }
20142
20225
  return c.json({ ok: true }, 200);
20143
20226
  }
20144
- if (!isBindableEntry(entry2)) {
20227
+ if (!isBindableEntry(entry3)) {
20145
20228
  console.error(`${TAG34} op=ignore botId=${botId} reason=bot-unbound`);
20146
20229
  return c.json({ ok: true }, 200);
20147
20230
  }
@@ -20174,19 +20257,30 @@ app11.post("/", async (c) => {
20174
20257
  if (decision.allowed) {
20175
20258
  const cbKey = telegramChannelKey(botId, cbSubject);
20176
20259
  const cbAt = (/* @__PURE__ */ new Date()).toISOString();
20260
+ let cbBody = `[button: ${decision.data ?? "no-data"}]`;
20261
+ if (decision.data !== null) {
20262
+ const label = (0, import_dist8.readButtonLabel)(accountDir, (0, import_dist8.buttonLabelKey)(botId, decision.chatId, decision.data));
20263
+ if (label !== null) {
20264
+ cbBody = label;
20265
+ } else {
20266
+ console.error(
20267
+ `${TAG34} op=button-label-miss botId=${botId} chatId=${decision.chatId} data=${logValue2(decision.data)}`
20268
+ );
20269
+ }
20270
+ }
20177
20271
  appendMessage2(accountId, {
20178
20272
  messageId: `telegram:${accountId}:${cbKey}:cb:${decision.callbackId}`,
20179
20273
  // Task 2598 — the one shared derivation, so this row names the session
20180
20274
  // the press actually reaches.
20181
20275
  sessionId: telegramAdminSessionId(accountId, cbSubject, botId),
20182
20276
  dateSent: cbAt,
20183
- body: `[button: ${decision.data ?? "no-data"}]`,
20277
+ body: cbBody,
20184
20278
  fromMe: false,
20185
20279
  senderId: decision.senderId,
20186
20280
  senderName: decision.senderDisplay,
20187
20281
  chatId: String(decision.chatId),
20188
20282
  channelKey: cbKey,
20189
- scope: entry2.role === "admin" ? "admin" : "public",
20283
+ scope: entry3.role === "admin" ? "admin" : "public",
20190
20284
  origin: "inbound",
20191
20285
  createdAt: cbAt
20192
20286
  });
@@ -20202,7 +20296,7 @@ app11.post("/", async (c) => {
20202
20296
  session,
20203
20297
  accountId,
20204
20298
  cfg: load.value,
20205
- token: entry2.token,
20299
+ token: entry3.token,
20206
20300
  botId,
20207
20301
  updateId: decision.updateId,
20208
20302
  chatId: decision.chatId,
@@ -20228,22 +20322,22 @@ app11.post("/", async (c) => {
20228
20322
  }
20229
20323
  }
20230
20324
  const answerStartedAt = Date.now();
20231
- const answered4 = await answerTelegramCallback(entry2.token, decision.callbackId, answerText);
20325
+ const answered4 = await answerTelegramCallback(entry3.token, decision.callbackId, answerText);
20232
20326
  const outcome = !answered4.ok ? "error" : decision.allowed ? "stored" : "refused";
20233
20327
  console.error(
20234
20328
  `${TAG34} op=callback-answered botId=${botId} callbackId=${decision.callbackId} ms=${Date.now() - answerStartedAt} outcome=${outcome}${answered4.error ? ` error=${logValue2(answered4.error)}` : ""}`
20235
20329
  );
20236
20330
  if (decision.allowed && parseDispatchCallback(decision.data) === null) {
20237
- const cbActive = entryActive(entry2, accountDir, botId);
20331
+ const cbActive = entryActive(entry3, accountDir, botId);
20238
20332
  console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${cbActive}`);
20239
20333
  raiseChannelTurn({
20240
20334
  accountId,
20241
20335
  accountDir,
20242
20336
  botId,
20243
- botToken: entry2.token,
20244
- role: entry2.role,
20337
+ botToken: entry3.token,
20338
+ role: entry3.role,
20245
20339
  agentSlug,
20246
- specialist: entry2.role === "specialist" ? entry2.specialist : null,
20340
+ specialist: entry3.role === "specialist" ? entry3.specialist : null,
20247
20341
  active: cbActive,
20248
20342
  senderId: decision.senderId,
20249
20343
  senderDisplay: decision.senderDisplay,
@@ -20253,7 +20347,7 @@ app11.post("/", async (c) => {
20253
20347
  text: `[button: ${decision.data ?? "no-data"}]`,
20254
20348
  channelKey: telegramChannelKey(botId, cbSubject),
20255
20349
  conversationSubject: cbSubject,
20256
- scope: entry2.role === "admin" ? "admin" : "public",
20350
+ scope: entry3.role === "admin" ? "admin" : "public",
20257
20351
  sessionId: telegramAdminSessionId(accountId, cbSubject, botId)
20258
20352
  });
20259
20353
  }
@@ -20269,7 +20363,7 @@ app11.post("/", async (c) => {
20269
20363
  );
20270
20364
  if (!decision.allowed) return c.json({ ok: true }, 200);
20271
20365
  const pollKey = telegramChannelKey(botId, decision.senderId);
20272
- const pollScope = entry2.role === "admin" ? "admin" : "public";
20366
+ const pollScope = entry3.role === "admin" ? "admin" : "public";
20273
20367
  const pollSession = telegramAdminSessionId(accountId, decision.senderId, botId);
20274
20368
  const pollAt = (/* @__PURE__ */ new Date()).toISOString();
20275
20369
  const pollBody = `[poll vote: poll=${decision.pollId} options=${options}]`;
@@ -20287,16 +20381,16 @@ app11.post("/", async (c) => {
20287
20381
  origin: "inbound",
20288
20382
  createdAt: pollAt
20289
20383
  });
20290
- const pollActive = entryActive(entry2, accountDir, botId);
20384
+ const pollActive = entryActive(entry3, accountDir, botId);
20291
20385
  console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${pollActive}`);
20292
20386
  raiseChannelTurn({
20293
20387
  accountId,
20294
20388
  accountDir,
20295
20389
  botId,
20296
- botToken: entry2.token,
20297
- role: entry2.role,
20390
+ botToken: entry3.token,
20391
+ role: entry3.role,
20298
20392
  agentSlug,
20299
- specialist: entry2.role === "specialist" ? entry2.specialist : null,
20393
+ specialist: entry3.role === "specialist" ? entry3.specialist : null,
20300
20394
  active: pollActive,
20301
20395
  senderId: decision.senderId,
20302
20396
  senderDisplay: decision.senderDisplay,
@@ -20320,7 +20414,7 @@ app11.post("/", async (c) => {
20320
20414
  `${TAG34} op=reaction-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
20321
20415
  );
20322
20416
  if (!decision.allowed) return c.json({ ok: true }, 200);
20323
- const rScope = entry2.role === "admin" ? "admin" : "public";
20417
+ const rScope = entry3.role === "admin" ? "admin" : "public";
20324
20418
  const rSession = telegramAdminSessionId(accountId, rSubject, botId);
20325
20419
  const rAt = (/* @__PURE__ */ new Date()).toISOString();
20326
20420
  const rTarget = quotedBody === null ? `message ${decision.messageId} \u2014 not held in this conversation` : `"${quotedBody}"`;
@@ -20339,16 +20433,16 @@ app11.post("/", async (c) => {
20339
20433
  origin: "inbound",
20340
20434
  createdAt: rAt
20341
20435
  });
20342
- const rActive = entryActive(entry2, accountDir, botId);
20436
+ const rActive = entryActive(entry3, accountDir, botId);
20343
20437
  console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${rActive}`);
20344
20438
  raiseChannelTurn({
20345
20439
  accountId,
20346
20440
  accountDir,
20347
20441
  botId,
20348
- botToken: entry2.token,
20349
- role: entry2.role,
20442
+ botToken: entry3.token,
20443
+ role: entry3.role,
20350
20444
  agentSlug,
20351
- specialist: entry2.role === "specialist" ? entry2.specialist : null,
20445
+ specialist: entry3.role === "specialist" ? entry3.specialist : null,
20352
20446
  active: rActive,
20353
20447
  senderId: decision.senderId,
20354
20448
  senderDisplay: decision.senderDisplay,
@@ -20386,7 +20480,7 @@ app11.post("/", async (c) => {
20386
20480
  );
20387
20481
  if (!decision.allowed) return c.json({ ok: true }, 200);
20388
20482
  const sKey = telegramChannelKey(botId, decision.senderId);
20389
- const sScope = entry2.role === "admin" ? "admin" : "public";
20483
+ const sScope = entry3.role === "admin" ? "admin" : "public";
20390
20484
  const sSession = telegramAdminSessionId(accountId, decision.senderId, botId);
20391
20485
  const sAt = (/* @__PURE__ */ new Date()).toISOString();
20392
20486
  const sBody = `[subscription ${decision.state}: payload=${decision.payload}]`;
@@ -20404,16 +20498,16 @@ app11.post("/", async (c) => {
20404
20498
  origin: "inbound",
20405
20499
  createdAt: sAt
20406
20500
  });
20407
- const sActive = entryActive(entry2, accountDir, botId);
20501
+ const sActive = entryActive(entry3, accountDir, botId);
20408
20502
  console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${sActive}`);
20409
20503
  raiseChannelTurn({
20410
20504
  accountId,
20411
20505
  accountDir,
20412
20506
  botId,
20413
- botToken: entry2.token,
20414
- role: entry2.role,
20507
+ botToken: entry3.token,
20508
+ role: entry3.role,
20415
20509
  agentSlug,
20416
- specialist: entry2.role === "specialist" ? entry2.specialist : null,
20510
+ specialist: entry3.role === "specialist" ? entry3.specialist : null,
20417
20511
  active: sActive,
20418
20512
  senderId: decision.senderId,
20419
20513
  senderDisplay: decision.senderDisplay,
@@ -20432,7 +20526,7 @@ app11.post("/", async (c) => {
20432
20526
  `${TAG34} op=poll-closed botId=${botId} pollId=${logValue2(decision.pollId)} options=${decision.options.length} totalVotes=${decision.totalVotes} targetHeld=${where === null ? "no" : "yes"}`
20433
20527
  );
20434
20528
  if (where === null) return c.json({ ok: true }, 200);
20435
- const plScope = entry2.role === "admin" ? "admin" : "public";
20529
+ const plScope = entry3.role === "admin" ? "admin" : "public";
20436
20530
  const plSession = telegramAdminSessionId(accountId, where.senderId, botId);
20437
20531
  const plAt = (/* @__PURE__ */ new Date()).toISOString();
20438
20532
  const tally = decision.options.map((o) => `${o.text}:${o.votes}`).join(", ") || "no options";
@@ -20451,16 +20545,16 @@ app11.post("/", async (c) => {
20451
20545
  origin: "inbound",
20452
20546
  createdAt: plAt
20453
20547
  });
20454
- const plActive = entryActive(entry2, accountDir, botId);
20548
+ const plActive = entryActive(entry3, accountDir, botId);
20455
20549
  console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${plActive}`);
20456
20550
  raiseChannelTurn({
20457
20551
  accountId,
20458
20552
  accountDir,
20459
20553
  botId,
20460
- botToken: entry2.token,
20461
- role: entry2.role,
20554
+ botToken: entry3.token,
20555
+ role: entry3.role,
20462
20556
  agentSlug,
20463
- specialist: entry2.role === "specialist" ? entry2.specialist : null,
20557
+ specialist: entry3.role === "specialist" ? entry3.specialist : null,
20464
20558
  active: plActive,
20465
20559
  senderId: where.senderId,
20466
20560
  chatId: Number(where.chatId),
@@ -20489,7 +20583,7 @@ app11.post("/", async (c) => {
20489
20583
  console.error(
20490
20584
  `${TAG34} op=managed-bot botId=${botId} event=${event} newBotId=${newBotId} creator=${decision.creatorId ?? "none"}`
20491
20585
  );
20492
- const fetched = await getManagedBotToken(entry2.token, Number(newBotId));
20586
+ const fetched = await getManagedBotToken(entry3.token, Number(newBotId));
20493
20587
  console.error(
20494
20588
  `${PROVISION_TAG} op=provision-token botId=${botId} newBotId=${newBotId} fetched=${fetched.ok ? "yes" : "no"} reason=${fetched.ok ? "ok" : "api-error"}`
20495
20589
  );
@@ -20499,7 +20593,7 @@ app11.post("/", async (c) => {
20499
20593
  accountDir,
20500
20594
  existing ? { ...existing, token: fetched.token, managed: true } : { id: newBotId, token: fetched.token, role: "unbound", managed: true }
20501
20595
  );
20502
- const restricted = await setManagedBotAccessSettings(entry2.token, Number(newBotId), true, void 0);
20596
+ const restricted = await setManagedBotAccessSettings(entry3.token, Number(newBotId), true, void 0);
20503
20597
  console.error(
20504
20598
  `${PROVISION_TAG} op=provision-persist botId=${botId} newBotId=${newBotId} written=${persisted.ok ? "yes" : "no"} restricted=${restricted.ok ? "yes" : "no"}`
20505
20599
  );
@@ -20515,7 +20609,7 @@ app11.post("/", async (c) => {
20515
20609
  accountId,
20516
20610
  accountDir,
20517
20611
  botId,
20518
- botToken: entry2.token,
20612
+ botToken: entry3.token,
20519
20613
  // `authorised` above already established this entry is role 'admin', so
20520
20614
  // the admin agent is the one that runs and it is active by construction.
20521
20615
  role: "admin",
@@ -20588,7 +20682,7 @@ app11.post("/", async (c) => {
20588
20682
  });
20589
20683
  }
20590
20684
  const bizMedia = await downloadTelegramMedia({
20591
- token: entry2.token,
20685
+ token: entry3.token,
20592
20686
  botId,
20593
20687
  items: decision.media
20594
20688
  });
@@ -20628,7 +20722,7 @@ app11.post("/", async (c) => {
20628
20722
  return;
20629
20723
  }
20630
20724
  const sent = await sendTelegramText(
20631
- entry2.token,
20725
+ entry3.token,
20632
20726
  decision.chatId,
20633
20727
  replyText,
20634
20728
  void 0,
@@ -20657,7 +20751,7 @@ app11.post("/", async (c) => {
20657
20751
  accountId,
20658
20752
  accountDir,
20659
20753
  botId,
20660
- botToken: entry2.token,
20754
+ botToken: entry3.token,
20661
20755
  agentSlug,
20662
20756
  senderId: decision.senderId,
20663
20757
  // Task 2615 — load-bearing. The gateway keys the hub, the reply closure,
@@ -20707,7 +20801,7 @@ app11.post("/", async (c) => {
20707
20801
  console.error(`${TAG34} op=access botId=${botId} senderId=${senderId} allowed=true reason=${decision.reason}`);
20708
20802
  const subject = telegramConversationSubject(decision.chatType, chatId, senderId);
20709
20803
  const channelKey = telegramChannelKey(botId, subject);
20710
- const scope = entry2.role === "public" ? "public" : "admin";
20804
+ const scope = entry3.role === "public" ? "public" : "admin";
20711
20805
  const sessionId = telegramAdminSessionId(accountId, subject, botId);
20712
20806
  const inboundAt = (/* @__PURE__ */ new Date()).toISOString();
20713
20807
  const editSuffix = decision.isEdit ? `:edit:${decision.editDate}` : "";
@@ -20788,10 +20882,10 @@ app11.post("/", async (c) => {
20788
20882
  });
20789
20883
  }
20790
20884
  }
20791
- const active = entryActive(entry2, accountDir, botId, (rosterValid) => {
20792
- if (entry2.role !== "specialist") return;
20885
+ const active = entryActive(entry3, accountDir, botId, (rosterValid) => {
20886
+ if (entry3.role !== "specialist") return;
20793
20887
  console.error(
20794
- `${TAG34} op=specialist-inbound botId=${botId} specialist=${logValue2(entry2.specialist)} senderId=${senderId} sessionId=${sessionId} rosterValid=${rosterValid ? "yes" : "no"}`
20888
+ `${TAG34} op=specialist-inbound botId=${botId} specialist=${logValue2(entry3.specialist)} senderId=${senderId} sessionId=${sessionId} rosterValid=${rosterValid ? "yes" : "no"}`
20795
20889
  );
20796
20890
  });
20797
20891
  console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${active}`);
@@ -20806,7 +20900,7 @@ app11.post("/", async (c) => {
20806
20900
  }
20807
20901
  const replyThreadId = decision.threadId ?? void 0;
20808
20902
  const reply = async (replyText) => {
20809
- const sent = await sendTelegramText(entry2.token, chatId, replyText, replyThreadId);
20903
+ const sent = await sendTelegramText(entry3.token, chatId, replyText, replyThreadId);
20810
20904
  if (sent.ok) {
20811
20905
  const at = (/* @__PURE__ */ new Date()).toISOString();
20812
20906
  appendMessage2(accountId, {
@@ -20826,7 +20920,7 @@ app11.post("/", async (c) => {
20826
20920
  console.error(`${TAG34} op=reply-sent botId=${botId} ok=true`);
20827
20921
  } else console.error(`${TAG34} op=reply-dropped botId=${botId} reason=${sent.error}`);
20828
20922
  };
20829
- const media = await downloadTelegramMedia({ token: entry2.token, botId, items: decision.media });
20923
+ const media = await downloadTelegramMedia({ token: entry3.token, botId, items: decision.media });
20830
20924
  if (media.length > 0) {
20831
20925
  const attachmentIds = await storeTelegramServable({
20832
20926
  accountId,
@@ -20952,7 +21046,7 @@ app11.post("/", async (c) => {
20952
21046
  accountId,
20953
21047
  accountDir,
20954
21048
  botId,
20955
- botToken: entry2.token,
21049
+ botToken: entry3.token,
20956
21050
  agentSlug,
20957
21051
  senderId,
20958
21052
  // Task 2616 — the name beside the id on the turn's provenance line.
@@ -20962,10 +21056,10 @@ app11.post("/", async (c) => {
20962
21056
  // room reach one channel server rather than opening five sessions whose
20963
21057
  // reply closures all target the same chat. A DM subject IS the sender id.
20964
21058
  conversationSubject: subject,
20965
- role: entry2.role,
21059
+ role: entry3.role,
20966
21060
  personId: null,
20967
21061
  // Task 2619 — the card this bot runs as, null on every other role.
20968
- specialist: entry2.role === "specialist" ? entry2.specialist : null,
21062
+ specialist: entry3.role === "specialist" ? entry3.specialist : null,
20969
21063
  chatId: String(chatId),
20970
21064
  text: turnText,
20971
21065
  media: heard.media,
@@ -21369,9 +21463,9 @@ function computeAdminStoreDivergence(input) {
21369
21463
  result.errors.push({ source: input.accountsDir, detail: err instanceof Error ? err.message : String(err) });
21370
21464
  return result;
21371
21465
  }
21372
- for (const entry2 of entries2) {
21373
- if (entry2.startsWith(".")) continue;
21374
- const accountDir = join42(input.accountsDir, entry2);
21466
+ for (const entry3 of entries2) {
21467
+ if (entry3.startsWith(".")) continue;
21468
+ const accountDir = join42(input.accountsDir, entry3);
21375
21469
  try {
21376
21470
  if (!statSync20(accountDir).isDirectory()) continue;
21377
21471
  } catch {
@@ -23508,12 +23602,12 @@ function authoredAgentFiles(accountDir) {
23508
23602
  const dir = resolve28(pluginsDir, plugin, "agents");
23509
23603
  if (!existsSync38(dir)) continue;
23510
23604
  try {
23511
- for (const entry2 of readdirSync24(dir)) {
23512
- if (!entry2.endsWith(".md")) continue;
23513
- const path = resolve28(dir, entry2);
23514
- const paths = byName.get(entry2);
23605
+ for (const entry3 of readdirSync24(dir)) {
23606
+ if (!entry3.endsWith(".md")) continue;
23607
+ const path = resolve28(dir, entry3);
23608
+ const paths = byName.get(entry3);
23515
23609
  if (paths) paths.push(path);
23516
- else byName.set(entry2, [path]);
23610
+ else byName.set(entry3, [path]);
23517
23611
  }
23518
23612
  } catch (err) {
23519
23613
  console.error(`[admin/agents] op=authored-scan read-failed plugin=${plugin} error="${err}"`);
@@ -23582,7 +23676,7 @@ function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed, author
23582
23676
  for (const dir of dirs) {
23583
23677
  if (!existsSync38(dir)) continue;
23584
23678
  try {
23585
- for (const entry2 of readdirSync24(dir)) if (entry2.endsWith(".md")) names.add(entry2);
23679
+ for (const entry3 of readdirSync24(dir)) if (entry3.endsWith(".md")) names.add(entry3);
23586
23680
  } catch (err) {
23587
23681
  console.error(`[admin/agents] op=list-shipped read-failed dir=${dir} error="${err}"`);
23588
23682
  }
@@ -23676,19 +23770,19 @@ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
23676
23770
  } catch {
23677
23771
  continue;
23678
23772
  }
23679
- for (const entry2 of entries2) {
23680
- if (!entry2.isFile() || !entry2.name.endsWith(".md")) continue;
23773
+ for (const entry3 of entries2) {
23774
+ if (!entry3.isFile() || !entry3.name.endsWith(".md")) continue;
23681
23775
  try {
23682
- const { fm } = splitFrontmatter(readFileSync38(resolve28(agentsDirP, entry2.name), "utf-8"));
23776
+ const { fm } = splitFrontmatter(readFileSync38(resolve28(agentsDirP, entry3.name), "utf-8"));
23683
23777
  if (!fm.name) {
23684
23778
  specialistsSkipped++;
23685
- console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry2.name}`);
23779
+ console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry3.name}`);
23686
23780
  continue;
23687
23781
  }
23688
23782
  const specialistTools = parseToolsLine(fm.tools);
23689
23783
  const r = classify(specialistTools, riskByTool, riskSurfaceFailed);
23690
23784
  specialists.push({
23691
- slug: entry2.name.replace(/\.md$/, ""),
23785
+ slug: entry3.name.replace(/\.md$/, ""),
23692
23786
  displayName: fm.name,
23693
23787
  kind: "specialist",
23694
23788
  origin: "specialist",
@@ -23711,11 +23805,11 @@ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
23711
23805
  // have the surface claim an agent is stopped while it is still being
23712
23806
  // spawned. Absence from the live dir alone is also not the test: a
23713
23807
  // specialist that was never activated was never switched off either.
23714
- disabled: existsSync38(resolve28(accountDir, ...QUARANTINE_DIR, entry2.name)) && !existsSync38(resolve28(accountDir, ...SPECIALISTS_DIR, entry2.name))
23808
+ disabled: existsSync38(resolve28(accountDir, ...QUARANTINE_DIR, entry3.name)) && !existsSync38(resolve28(accountDir, ...SPECIALISTS_DIR, entry3.name))
23715
23809
  });
23716
23810
  } catch {
23717
23811
  specialistsSkipped++;
23718
- console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry2.name}`);
23812
+ console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry3.name}`);
23719
23813
  }
23720
23814
  }
23721
23815
  }
@@ -23742,16 +23836,16 @@ app22.get("/", requireAdminSession, (c) => {
23742
23836
  if (existsSync38(agentsDir)) {
23743
23837
  try {
23744
23838
  const entries2 = readdirSync24(agentsDir, { withFileTypes: true });
23745
- for (const entry2 of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
23746
- if (!entry2.isDirectory()) continue;
23747
- if (entry2.name === "admin") continue;
23748
- const configPath3 = resolve28(agentsDir, entry2.name, "config.json");
23839
+ for (const entry3 of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
23840
+ if (!entry3.isDirectory()) continue;
23841
+ if (entry3.name === "admin") continue;
23842
+ const configPath3 = resolve28(agentsDir, entry3.name, "config.json");
23749
23843
  if (!existsSync38(configPath3)) continue;
23750
23844
  try {
23751
23845
  const config = JSON.parse(readFileSync38(configPath3, "utf-8"));
23752
23846
  agents.push({
23753
- slug: entry2.name,
23754
- displayName: config.displayName ?? entry2.name,
23847
+ slug: entry3.name,
23848
+ displayName: config.displayName ?? entry3.name,
23755
23849
  status: config.status ?? "unknown",
23756
23850
  kind: "public",
23757
23851
  origin: "public",
@@ -23764,7 +23858,7 @@ app22.get("/", requireAdminSession, (c) => {
23764
23858
  });
23765
23859
  } catch {
23766
23860
  skipped++;
23767
- console.error(`[admin/agents] failed to parse config.json for agent "${entry2.name}" \u2014 skipping`);
23861
+ console.error(`[admin/agents] failed to parse config.json for agent "${entry3.name}" \u2014 skipping`);
23768
23862
  }
23769
23863
  }
23770
23864
  } catch (err) {
@@ -24418,7 +24512,7 @@ app23.get("/", requireAdminSession, async (c) => {
24418
24512
  if (!userId) return c.json({ error: "User identity required \u2014 authenticate with users.json PIN" }, 401);
24419
24513
  try {
24420
24514
  const flushed = await listAdminSessions(accountId, userId, 20);
24421
- const sessions3 = flushed.map((r) => ({
24515
+ const sessions4 = flushed.map((r) => ({
24422
24516
  sessionId: r.sessionId,
24423
24517
  cacheKey: null,
24424
24518
  name: r.name,
@@ -24426,15 +24520,15 @@ app23.get("/", requireAdminSession, async (c) => {
24426
24520
  phase: "flushed",
24427
24521
  channel: r.channel
24428
24522
  })).sort((a, b) => a.updatedAt < b.updatedAt ? 1 : a.updatedAt > b.updatedAt ? -1 : 0).slice(0, 20);
24429
- const channelCounts = sessions3.reduce((acc, s) => {
24523
+ const channelCounts = sessions4.reduce((acc, s) => {
24430
24524
  const k = s.channel ?? "unknown";
24431
24525
  acc[k] = (acc[k] ?? 0) + 1;
24432
24526
  return acc;
24433
24527
  }, {});
24434
24528
  console.error(
24435
- `[conversations-list] render rows=${sessions3.length} channels=${JSON.stringify(channelCounts)}`
24529
+ `[conversations-list] render rows=${sessions4.length} channels=${JSON.stringify(channelCounts)}`
24436
24530
  );
24437
- return c.json({ sessions: sessions3 });
24531
+ return c.json({ sessions: sessions4 });
24438
24532
  } catch (err) {
24439
24533
  console.error(`[sessions-list] Failed: ${err instanceof Error ? err.message : String(err)}`);
24440
24534
  return c.json({ error: "Failed to fetch sessions" }, 500);
@@ -26099,14 +26193,14 @@ async function walkSubtree(root, dataRoot, out) {
26099
26193
  return { clean: false };
26100
26194
  }
26101
26195
  let clean = true;
26102
- for (const entry2 of entries2) {
26103
- if (entry2.isSymbolicLink()) continue;
26104
- if (entry2.isDirectory() && entry2.name === ".uploads-tmp") continue;
26105
- const abs = join49(root, entry2.name);
26106
- if (entry2.isDirectory()) {
26196
+ for (const entry3 of entries2) {
26197
+ if (entry3.isSymbolicLink()) continue;
26198
+ if (entry3.isDirectory() && entry3.name === ".uploads-tmp") continue;
26199
+ const abs = join49(root, entry3.name);
26200
+ if (entry3.isDirectory()) {
26107
26201
  const sub = await walkSubtree(abs, dataRoot, out);
26108
26202
  if (!sub.clean) clean = false;
26109
- } else if (entry2.isFile()) {
26203
+ } else if (entry3.isFile()) {
26110
26204
  try {
26111
26205
  const st = await fsp.stat(abs);
26112
26206
  out.push({
@@ -26395,14 +26489,14 @@ function buildZip(entries2) {
26395
26489
  const localChunks = [];
26396
26490
  const centralChunks = [];
26397
26491
  let offset = 0;
26398
- for (const entry2 of entries2) {
26399
- const nameBytes = Buffer.from(entry2.name, "utf8");
26400
- const crc = crc32(entry2.data);
26401
- const uncompressedSize = entry2.data.length;
26402
- const deflated = deflateRawSync(entry2.data);
26492
+ for (const entry3 of entries2) {
26493
+ const nameBytes = Buffer.from(entry3.name, "utf8");
26494
+ const crc = crc32(entry3.data);
26495
+ const uncompressedSize = entry3.data.length;
26496
+ const deflated = deflateRawSync(entry3.data);
26403
26497
  const useDeflate = deflated.length < uncompressedSize;
26404
26498
  const method = useDeflate ? 8 : 0;
26405
- const payload = useDeflate ? deflated : entry2.data;
26499
+ const payload = useDeflate ? deflated : entry3.data;
26406
26500
  const compressedSize = payload.length;
26407
26501
  const localHeader = Buffer.alloc(30);
26408
26502
  localHeader.writeUInt32LE(LOCAL_SIG, 0);
@@ -26454,13 +26548,13 @@ function buildZip(entries2) {
26454
26548
  }
26455
26549
 
26456
26550
  // server/lib/account-root-groups.ts
26457
- var import_dist8 = __toESM(require_dist6(), 1);
26551
+ var import_dist9 = __toESM(require_dist7(), 1);
26458
26552
  function classifyAccountRoot(schemaMd, rootEntries) {
26459
- const regions = (0, import_dist8.parseSchemaRegions)(schemaMd);
26553
+ const regions = (0, import_dist9.parseSchemaRegions)(schemaMd);
26460
26554
  if (!regions.parsed) {
26461
26555
  return { home: [], system: [...rootEntries], unknown: [], parsed: false, reason: regions.reason };
26462
26556
  }
26463
- const homeOrder = [...regions.ontologyRoots, ...import_dist8.HOME_FIXED].filter((d, i, a) => a.indexOf(d) === i);
26557
+ const homeOrder = [...regions.ontologyRoots, ...import_dist9.HOME_FIXED].filter((d, i, a) => a.indexOf(d) === i);
26464
26558
  const homeSet = new Set(homeOrder);
26465
26559
  const present = new Set(rootEntries);
26466
26560
  const home = homeOrder.filter((d) => present.has(d));
@@ -26528,47 +26622,47 @@ async function servableFilesIn(dirAbs, uuid) {
26528
26622
  }
26529
26623
  return out;
26530
26624
  }
26531
- async function enrich(absolute, entry2, accountNames) {
26532
- if (entry2.kind === "directory" && UUID_RE3.test(entry2.name)) {
26533
- const dirAbs = join50(absolute, entry2.name);
26534
- const meta = await readMeta2(dirAbs, entry2.name);
26625
+ async function enrich(absolute, entry3, accountNames) {
26626
+ if (entry3.kind === "directory" && UUID_RE3.test(entry3.name)) {
26627
+ const dirAbs = join50(absolute, entry3.name);
26628
+ const meta = await readMeta2(dirAbs, entry3.name);
26535
26629
  if (meta?.filename) {
26536
- const servable = await servableFilesIn(dirAbs, entry2.name);
26630
+ const servable = await servableFilesIn(dirAbs, entry3.name);
26537
26631
  if (servable.length === 1) {
26538
26632
  const innerName = servable[0];
26539
26633
  let size = null;
26540
- let modifiedAt = entry2.modifiedAt;
26634
+ let modifiedAt = entry3.modifiedAt;
26541
26635
  try {
26542
26636
  const st = await stat6(join50(dirAbs, innerName));
26543
26637
  size = st.size;
26544
26638
  modifiedAt = st.mtime.toISOString();
26545
26639
  } catch {
26546
26640
  }
26547
- entry2.kind = "file";
26548
- entry2.displayName = meta.filename;
26549
- entry2.mimeType = meta.mimeType;
26550
- entry2.sizeBytes = size;
26551
- entry2.modifiedAt = modifiedAt;
26552
- entry2.entryPath = `${entry2.name}/${innerName}`;
26641
+ entry3.kind = "file";
26642
+ entry3.displayName = meta.filename;
26643
+ entry3.mimeType = meta.mimeType;
26644
+ entry3.sizeBytes = size;
26645
+ entry3.modifiedAt = modifiedAt;
26646
+ entry3.entryPath = `${entry3.name}/${innerName}`;
26553
26647
  return "flattened";
26554
26648
  }
26555
- entry2.displayName = meta.filename;
26649
+ entry3.displayName = meta.filename;
26556
26650
  return "kept-as-dir";
26557
26651
  }
26558
- const accountName = accountNames.get(entry2.name);
26652
+ const accountName = accountNames.get(entry3.name);
26559
26653
  if (accountName) {
26560
- entry2.displayName = accountName;
26654
+ entry3.displayName = accountName;
26561
26655
  }
26562
26656
  return null;
26563
26657
  }
26564
- if (entry2.kind === "file") {
26565
- const dot = entry2.name.lastIndexOf(".");
26566
- const base = dot === -1 ? entry2.name : entry2.name.slice(0, dot);
26658
+ if (entry3.kind === "file") {
26659
+ const dot = entry3.name.lastIndexOf(".");
26660
+ const base = dot === -1 ? entry3.name : entry3.name.slice(0, dot);
26567
26661
  if (UUID_RE3.test(base)) {
26568
26662
  const meta = await readMeta2(absolute, base);
26569
26663
  if (meta?.filename) {
26570
- entry2.displayName = meta.filename;
26571
- entry2.mimeType = meta.mimeType;
26664
+ entry3.displayName = meta.filename;
26665
+ entry3.mimeType = meta.mimeType;
26572
26666
  }
26573
26667
  }
26574
26668
  }
@@ -27603,7 +27697,7 @@ app28.post("/rename", requireAdminSession, async (c) => {
27603
27697
  var files_default = app28;
27604
27698
 
27605
27699
  // ../lib/graph-search/src/index.ts
27606
- var import_dist9 = __toESM(require_dist7());
27700
+ var import_dist10 = __toESM(require_dist8());
27607
27701
  import { int } from "neo4j-driver";
27608
27702
 
27609
27703
  // ../lib/graph-search/src/rrf-fusion.ts
@@ -27853,7 +27947,7 @@ async function bm25Only(session, params) {
27853
27947
  ${scopeClause}
27854
27948
  ${agentClause}
27855
27949
  ${labelClause}
27856
- AND ${(0, import_dist9.notTrashed)("node")}
27950
+ AND ${(0, import_dist10.notTrashed)("node")}
27857
27951
  ${kwClause}
27858
27952
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
27859
27953
  ORDER BY score DESC
@@ -28015,7 +28109,7 @@ async function hybrid(session, embed2, params) {
28015
28109
  WHERE node.accountId = $accountId
28016
28110
  ${scopeClause}
28017
28111
  ${agentClause}
28018
- AND ${(0, import_dist9.notTrashed)("node")}
28112
+ AND ${(0, import_dist10.notTrashed)("node")}
28019
28113
  ${keywordClause}
28020
28114
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
28021
28115
  ORDER BY score DESC
@@ -28114,7 +28208,7 @@ async function hybrid(session, embed2, params) {
28114
28208
  const propResult = await session.run(
28115
28209
  `MATCH (node)
28116
28210
  WHERE node.accountId = $accountId
28117
- AND ${(0, import_dist9.notTrashed)("node")}
28211
+ AND ${(0, import_dist10.notTrashed)("node")}
28118
28212
  AND node.keywords IS NOT NULL
28119
28213
  AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
28120
28214
  ${propScope.clause}
@@ -28166,7 +28260,7 @@ async function hybrid(session, embed2, params) {
28166
28260
  const propResult = await session.run(
28167
28261
  `MATCH (node)
28168
28262
  WHERE node.accountId = $accountId
28169
- AND ${(0, import_dist9.notTrashed)("node")}
28263
+ AND ${(0, import_dist10.notTrashed)("node")}
28170
28264
  AND node.keywords IS NOT NULL
28171
28265
  AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
28172
28266
  ${propScope.clause}
@@ -28273,7 +28367,7 @@ async function hybrid(session, embed2, params) {
28273
28367
  `UNWIND $nodeIds AS nid
28274
28368
  MATCH (n)-[r]-(related)
28275
28369
  WHERE elementId(n) = nid
28276
- AND ${(0, import_dist9.notTrashed)("related")}
28370
+ AND ${(0, import_dist10.notTrashed)("related")}
28277
28371
  ${expandScopeClause}
28278
28372
  ${expandAgentClause}
28279
28373
  WITH nid, n, r, related
@@ -28501,8 +28595,8 @@ var graph_search_default = app29;
28501
28595
  import neo4j2 from "neo4j-driver";
28502
28596
 
28503
28597
  // app/lib/graph-labels.ts
28504
- var import_dist10 = __toESM(require_dist8(), 1);
28505
- var import_dist11 = __toESM(require_dist8(), 1);
28598
+ var import_dist11 = __toESM(require_dist9(), 1);
28599
+ var import_dist12 = __toESM(require_dist9(), 1);
28506
28600
  var HIDDEN_BY_DEFAULT_LABELS = Object.freeze(
28507
28601
  /* @__PURE__ */ new Set(["Chunk", "GraphPreference"])
28508
28602
  );
@@ -28586,14 +28680,14 @@ var EXCLUDED_EDGE_TYPES = Object.freeze(
28586
28680
  ])
28587
28681
  );
28588
28682
  function isKnownLabel(label) {
28589
- return Object.prototype.hasOwnProperty.call(import_dist11.GRAPH_LABEL_COLOURS, label);
28683
+ return Object.prototype.hasOwnProperty.call(import_dist12.GRAPH_LABEL_COLOURS, label);
28590
28684
  }
28591
28685
  function isHiddenByDefault(label) {
28592
28686
  return HIDDEN_BY_DEFAULT_LABELS.has(label);
28593
28687
  }
28594
28688
 
28595
28689
  // server/lib/top-level-labels.ts
28596
- var import_dist12 = __toESM(require_dist8(), 1);
28690
+ var import_dist13 = __toESM(require_dist9(), 1);
28597
28691
  import { readdirSync as readdirSync26, readFileSync as readFileSync41 } from "fs";
28598
28692
  import { join as join51, resolve as resolve33 } from "path";
28599
28693
  var STATIC_TOP_LEVEL_LABELS = Object.freeze(
@@ -28730,7 +28824,7 @@ function getTopLevelLabelAllowlist(opts = {}) {
28730
28824
  const referencesDir = opts.referencesDir ?? resolveReferencesDir();
28731
28825
  const { labels: derived, contributingFiles } = parseTableTopLevelLabels(referencesDir);
28732
28826
  const excluded = [];
28733
- for (const label of import_dist12.ADDITIONAL_BASE_LABELS) {
28827
+ for (const label of import_dist13.ADDITIONAL_BASE_LABELS) {
28734
28828
  if (derived.delete(label)) excluded.push(label);
28735
28829
  }
28736
28830
  const derivedCount = derived.size;
@@ -29982,8 +30076,8 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
29982
30076
  if (!existsSync43(dir)) continue;
29983
30077
  try {
29984
30078
  const entries2 = await readdir5(dir);
29985
- for (const entry2 of entries2) {
29986
- if (entry2.endsWith(".md")) names.add(entry2);
30079
+ for (const entry3 of entries2) {
30080
+ if (entry3.endsWith(".md")) names.add(entry3);
29987
30081
  }
29988
30082
  } catch (err) {
29989
30083
  const message = err instanceof Error ? err.message : String(err);
@@ -34247,8 +34341,8 @@ function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
34247
34341
  } catch {
34248
34342
  return [];
34249
34343
  }
34250
- for (const entry2 of entries2) {
34251
- const cfgPath = resolve42(accountsDir, entry2, "account.json");
34344
+ for (const entry3 of entries2) {
34345
+ const cfgPath = resolve42(accountsDir, entry3, "account.json");
34252
34346
  if (!existsSync50(cfgPath)) continue;
34253
34347
  try {
34254
34348
  const cfg = JSON.parse(readFileSync51(cfgPath, "utf-8"));
@@ -35596,9 +35690,9 @@ function originAllowed(origin, allowlist) {
35596
35690
  try {
35597
35691
  const u = new URL(origin);
35598
35692
  const host = u.host;
35599
- return allowlist.some((entry2) => {
35600
- if (entry2 === host) return true;
35601
- if (entry2.startsWith("*.")) return host.endsWith(entry2.slice(1));
35693
+ return allowlist.some((entry3) => {
35694
+ if (entry3 === host) return true;
35695
+ if (entry3.startsWith("*.")) return host.endsWith(entry3.slice(1));
35602
35696
  return false;
35603
35697
  });
35604
35698
  } catch {
@@ -36875,7 +36969,7 @@ async function runConversationAudit() {
36875
36969
  }
36876
36970
 
36877
36971
  // app/lib/graph-health.ts
36878
- var import_dist14 = __toESM(require_dist9(), 1);
36972
+ var import_dist15 = __toESM(require_dist10(), 1);
36879
36973
  var HOUR_MS2 = 60 * 60 * 1e3;
36880
36974
  function renderLabelTop(rows) {
36881
36975
  return rows.map((b) => {
@@ -36920,7 +37014,7 @@ async function runGraphHealthTick() {
36920
37014
  console.error(
36921
37015
  `[graph-health] userprofile-multi accounts=${upAccounts} top=${upTop.length > 0 ? upTop.join(",") : "none"}`
36922
37016
  );
36923
- const indexed = [...import_dist14.VECTOR_INDEXED_LABELS];
37017
+ const indexed = [...import_dist15.VECTOR_INDEXED_LABELS];
36924
37018
  const embCount = await session.run(
36925
37019
  `MATCH (n) WHERE n.embedding IS NULL AND any(l IN labels(n) WHERE l IN $indexed)
36926
37020
  RETURN count(n) AS total`,
@@ -36994,7 +37088,7 @@ function startGraphHealthTimer() {
36994
37088
  // app/lib/shared-folder-census.ts
36995
37089
  import { existsSync as existsSync54, statSync as statSync29, readdirSync as readdirSync32 } from "fs";
36996
37090
  import { join as join65 } from "path";
36997
- var import_dist15 = __toESM(require_dist(), 1);
37091
+ var import_dist16 = __toESM(require_dist(), 1);
36998
37092
  var TAG64 = "[shared-census]";
36999
37093
  var WIRED_SURFACES = 3;
37000
37094
  function countFiles(dir) {
@@ -37012,7 +37106,7 @@ function countFiles(dir) {
37012
37106
  return n;
37013
37107
  }
37014
37108
  function runSharedFolderCensus(dataRoot = DATA_ROOT) {
37015
- const root = (0, import_dist15.sharedRoot)(dataRoot);
37109
+ const root = (0, import_dist16.sharedRoot)(dataRoot);
37016
37110
  const exists = existsSync54(root);
37017
37111
  let isDir = false;
37018
37112
  if (exists) {
@@ -37060,15 +37154,15 @@ function surveyBrandCredentials(home) {
37060
37154
  return [];
37061
37155
  }
37062
37156
  const rows = [];
37063
- for (const entry2 of entries2.sort()) {
37064
- if (!entry2.startsWith(".")) continue;
37157
+ for (const entry3 of entries2.sort()) {
37158
+ if (!entry3.startsWith(".")) continue;
37065
37159
  let raw;
37066
37160
  try {
37067
- raw = readFileSync57(join66(home, entry2, ".claude", ".credentials.json"), "utf-8");
37161
+ raw = readFileSync57(join66(home, entry3, ".claude", ".credentials.json"), "utf-8");
37068
37162
  } catch {
37069
37163
  continue;
37070
37164
  }
37071
- rows.push({ brand: entry2.slice(1), refreshTokenLen: refreshTokenLength(raw) });
37165
+ rows.push({ brand: entry3.slice(1), refreshTokenLen: refreshTokenLength(raw) });
37072
37166
  }
37073
37167
  return rows;
37074
37168
  }
@@ -37277,8 +37371,8 @@ async function migrateUploads(opts = {}) {
37277
37371
  let moved = 0;
37278
37372
  let skipped = 0;
37279
37373
  try {
37280
- for (const entry2 of topEntries) {
37281
- const name = entry2.name;
37374
+ for (const entry3 of topEntries) {
37375
+ const name = entry3.name;
37282
37376
  if (ACCOUNT_UUID_RE4.test(name)) {
37283
37377
  moved += await relocateTree(
37284
37378
  resolve49(oldRoot, name),
@@ -37378,11 +37472,11 @@ async function collectLiveSidecars(projectsRoot) {
37378
37472
  } catch {
37379
37473
  continue;
37380
37474
  }
37381
- for (const entry2 of entries2) {
37382
- if (entry2.isFile() && SESSION_META_RE.test(entry2.name)) {
37383
- out.push(join67(slugDir, entry2.name));
37384
- } else if (entry2.isDirectory() && entry2.name === "subagents") {
37385
- const subDir = join67(slugDir, entry2.name);
37475
+ for (const entry3 of entries2) {
37476
+ if (entry3.isFile() && SESSION_META_RE.test(entry3.name)) {
37477
+ out.push(join67(slugDir, entry3.name));
37478
+ } else if (entry3.isDirectory() && entry3.name === "subagents") {
37479
+ const subDir = join67(slugDir, entry3.name);
37386
37480
  let subs;
37387
37481
  try {
37388
37482
  subs = await readdir7(subDir, { withFileTypes: true });
@@ -37532,11 +37626,11 @@ async function collectSidecars(projectsRoot) {
37532
37626
  } catch {
37533
37627
  continue;
37534
37628
  }
37535
- for (const entry2 of entries2) {
37536
- if (entry2.isFile() && SESSION_META_RE2.test(entry2.name)) {
37537
- out.push({ path: join68(slugDir, entry2.name), slug: slug.name });
37538
- } else if (entry2.isDirectory() && (entry2.name === "subagents" || entry2.name === "archive")) {
37539
- const subDir = join68(slugDir, entry2.name);
37629
+ for (const entry3 of entries2) {
37630
+ if (entry3.isFile() && SESSION_META_RE2.test(entry3.name)) {
37631
+ out.push({ path: join68(slugDir, entry3.name), slug: slug.name });
37632
+ } else if (entry3.isDirectory() && (entry3.name === "subagents" || entry3.name === "archive")) {
37633
+ const subDir = join68(slugDir, entry3.name);
37540
37634
  let subs;
37541
37635
  try {
37542
37636
  subs = await readdir8(subDir, { withFileTypes: true });
@@ -38465,24 +38559,24 @@ var WaGateway = class {
38465
38559
  for (const h of held) {
38466
38560
  const key2 = hubKey(h.accountId, h.senderId);
38467
38561
  if (this.spawning.has(key2)) continue;
38468
- const entry2 = this.heldSpawnArgs.get(key2);
38469
- if (!entry2) {
38562
+ const entry3 = this.heldSpawnArgs.get(key2);
38563
+ if (!entry3) {
38470
38564
  console.error(
38471
38565
  `[whatsapp-native] op=spawn-retry-skipped senderId=${h.senderId} accountId=${h.accountId} ageMs=${h.oldestAgeMs} queued=${h.count} reason=no-args`
38472
38566
  );
38473
38567
  continue;
38474
38568
  }
38475
- entry2.attempts++;
38569
+ entry3.attempts++;
38476
38570
  this.spawning.add(key2);
38477
38571
  calls++;
38478
38572
  try {
38479
- await this.deps.ensureChannelSession(entry2.args);
38573
+ await this.deps.ensureChannelSession(entry3.args);
38480
38574
  console.error(
38481
- `[whatsapp-native] op=spawn-retry senderId=${h.senderId} accountId=${h.accountId} attempt=${entry2.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=true`
38575
+ `[whatsapp-native] op=spawn-retry senderId=${h.senderId} accountId=${h.accountId} attempt=${entry3.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=true`
38482
38576
  );
38483
38577
  } catch (err) {
38484
38578
  console.error(
38485
- `[whatsapp-native] op=spawn-retry senderId=${h.senderId} accountId=${h.accountId} attempt=${entry2.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=false reason=${err instanceof Error ? err.message : String(err)}`
38579
+ `[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
38580
  );
38487
38581
  } finally {
38488
38582
  this.spawning.delete(key2);
@@ -39027,8 +39121,8 @@ var InboundHub2 = class {
39027
39121
  if (!s) return null;
39028
39122
  const i = s.inFlight.findIndex((e) => e.payload.messageId === messageId && e.state === "queued");
39029
39123
  if (i < 0) return null;
39030
- const [entry2] = s.inFlight.splice(i, 1);
39031
- return entry2.payload;
39124
+ const [entry3] = s.inFlight.splice(i, 1);
39125
+ return entry3.payload;
39032
39126
  }
39033
39127
  /** Whether a key currently has a live channel server attached. The gateway
39034
39128
  * uses this to decide whether an inbound needs a cold-start spawn/resume. */
@@ -39360,9 +39454,9 @@ var WebchatGateway = class _WebchatGateway {
39360
39454
  * false (and is a no-op) when no prompt with this key+id is open — a late or
39361
39455
  * duplicate click. */
39362
39456
  resolvePermissionVerdict(key2, requestId, behavior) {
39363
- const entry2 = this.pendingPrompts.get(_WebchatGateway.promptKey(key2, requestId));
39364
- if (!entry2) return false;
39365
- entry2.resolve({ behavior });
39457
+ const entry3 = this.pendingPrompts.get(_WebchatGateway.promptKey(key2, requestId));
39458
+ if (!entry3) return false;
39459
+ entry3.resolve({ behavior });
39366
39460
  console.error(`[webchat:perm] op=verdict key=${keyDisplay(key2)} id=${requestId} behavior=${behavior}`);
39367
39461
  return true;
39368
39462
  }
@@ -39890,6 +39984,23 @@ var AnswerAccumulator = class {
39890
39984
  };
39891
39985
 
39892
39986
  // app/lib/channel-delivery/emitter.ts
39987
+ var CHANNEL_WRAPPER2 = "<channel source=";
39988
+ function classifyTurnStart(event) {
39989
+ const content = event.message?.content;
39990
+ if (typeof content === "string") {
39991
+ return content.trimStart().startsWith(CHANNEL_WRAPPER2) ? "inbound" : "injected";
39992
+ }
39993
+ if (!Array.isArray(content)) return "injected";
39994
+ for (const block of content) {
39995
+ if (block?.type === "tool_result") return "tool-result";
39996
+ }
39997
+ for (const block of content) {
39998
+ if (block?.type === "text" && typeof block.text === "string") {
39999
+ return block.text.trimStart().startsWith(CHANNEL_WRAPPER2) ? "inbound" : "injected";
40000
+ }
40001
+ }
40002
+ return "injected";
40003
+ }
39893
40004
  function followerPendingMaxMs() {
39894
40005
  return Number(process.env.CHANNEL_PTY_FOLLOWER_PENDING_MAX_MS ?? String(3e5));
39895
40006
  }
@@ -39905,33 +40016,33 @@ function toolResultText(content) {
39905
40016
  }
39906
40017
  function startEmitter(opts) {
39907
40018
  const abort2 = new AbortController();
39908
- const { entry: entry2, tag } = opts;
40019
+ const { entry: entry3, tag } = opts;
39909
40020
  const answers = new AnswerAccumulator();
39910
40021
  let answersEmitted = 0;
39911
40022
  let closeReason = "stream-end";
39912
40023
  const emitAnswer = async (answer) => {
39913
40024
  answersEmitted += 1;
39914
- if (answer.text.trim()) await fanOut2(entry2.subscribers, answer.text, opts.onError, tag);
40025
+ if (answer.text.trim()) await fanOut2(entry3.subscribers, answer.text, opts.onError, tag);
39915
40026
  if (!opts.onAnswer) return;
39916
- const guarded = { ...answer, text: guardOutbound(entry2.senderId, answer.text) };
40027
+ const guarded = { ...answer, text: guardOutbound(entry3.senderId, answer.text) };
39917
40028
  try {
39918
40029
  await opts.onAnswer(guarded);
39919
40030
  } catch (err) {
39920
40031
  console.error(
39921
- `${tag} answer-error sessionId=${entry2.sessionId.slice(0, 8)} messageId=${answer.messageId} message=${err instanceof Error ? err.message : String(err)}`
40032
+ `${tag} answer-error sessionId=${entry3.sessionId.slice(0, 8)} messageId=${answer.messageId} message=${err instanceof Error ? err.message : String(err)}`
39922
40033
  );
39923
40034
  }
39924
40035
  };
39925
40036
  void (async () => {
39926
40037
  try {
39927
- const sid = entry2.sessionId.slice(0, 8);
40038
+ const sid = entry3.sessionId.slice(0, 8);
39928
40039
  const deadline = Date.now() + followerPendingMaxMs();
39929
40040
  const retryMs = followerRetryMs();
39930
40041
  let res;
39931
40042
  let attempt = 0;
39932
40043
  for (; ; ) {
39933
40044
  res = await fetch(
39934
- managerLogFollowUrl(entry2.sessionId, { boundary: opts.suppressResumeReplay === true }),
40045
+ managerLogFollowUrl(entry3.sessionId, { boundary: opts.suppressResumeReplay === true }),
39935
40046
  { signal: abort2.signal }
39936
40047
  );
39937
40048
  console.error(`${tag} follower-connect sessionId=${sid} status=${res.status}`);
@@ -39982,7 +40093,7 @@ function startEmitter(opts) {
39982
40093
  event = JSON.parse(line);
39983
40094
  } catch (err) {
39984
40095
  console.error(
39985
- `${tag} jsonl-parse-skip sessionId=${entry2.sessionId.slice(0, 8)} bytes=${line.length} message=${err instanceof Error ? err.message : String(err)}`
40096
+ `${tag} jsonl-parse-skip sessionId=${entry3.sessionId.slice(0, 8)} bytes=${line.length} message=${err instanceof Error ? err.message : String(err)}`
39986
40097
  );
39987
40098
  continue;
39988
40099
  }
@@ -40035,7 +40146,7 @@ function startEmitter(opts) {
40035
40146
  }
40036
40147
  }
40037
40148
  }
40038
- if (!suppressing) opts.onTurnStart?.();
40149
+ if (!suppressing) opts.onTurnStart?.(classifyTurnStart(event));
40039
40150
  firedFileTools = [];
40040
40151
  continue;
40041
40152
  }
@@ -40100,7 +40211,7 @@ function startEmitter(opts) {
40100
40211
  } finally {
40101
40212
  if (abort2.signal.aborted) closeReason = "aborted";
40102
40213
  console.error(
40103
- `${tag} op=follower-closed sessionId=${entry2.sessionId.slice(0, 8)} reason=${closeReason} answers=${answersEmitted}`
40214
+ `${tag} op=follower-closed sessionId=${entry3.sessionId.slice(0, 8)} reason=${closeReason} answers=${answersEmitted}`
40104
40215
  );
40105
40216
  opts.onClose();
40106
40217
  }
@@ -40155,7 +40266,7 @@ import { resolve as resolve50 } from "path";
40155
40266
  // app/lib/channel-pty-bridge/file-delivery.ts
40156
40267
  var SEND_USER_FILE = "SendUserFile";
40157
40268
  function makeFileDelivery(opts) {
40158
- const { entry: entry2, tag, channel, sendFile, deferUntilVerdict = false } = opts;
40269
+ const { entry: entry3, tag, channel, sendFile, deferUntilVerdict = false } = opts;
40159
40270
  let failedFiles = [];
40160
40271
  let attempts = 0;
40161
40272
  const pending = /* @__PURE__ */ new Map();
@@ -40182,7 +40293,7 @@ function makeFileDelivery(opts) {
40182
40293
  function unreconciledCall(reason, files, detail) {
40183
40294
  const d = detail ? ` detail="${detail.replace(/\s+/g, " ").slice(0, 120)}"` : "";
40184
40295
  console.error(
40185
- `${tag} file-delivery-unreconciled sender=${entry2.senderId} sessionId=${entry2.sessionId.slice(0, 8)} tool=${SEND_USER_FILE} reason=${reason} files=${files}${d}`
40296
+ `${tag} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${entry3.sessionId.slice(0, 8)} tool=${SEND_USER_FILE} reason=${reason} files=${files}${d}`
40186
40297
  );
40187
40298
  }
40188
40299
  const handler = {
@@ -40203,10 +40314,10 @@ function makeFileDelivery(opts) {
40203
40314
  const tried = attempts;
40204
40315
  failedFiles = [];
40205
40316
  attempts = 0;
40206
- const sid = entry2.sessionId.slice(0, 8);
40317
+ const sid = entry3.sessionId.slice(0, 8);
40207
40318
  for (const file of failed2) {
40208
40319
  console.error(
40209
- `${tag} file-delivery-unreconciled sender=${entry2.senderId} sessionId=${sid} tool=${SEND_USER_FILE} file=${file}`
40320
+ `${tag} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${sid} tool=${SEND_USER_FILE} file=${file}`
40210
40321
  );
40211
40322
  }
40212
40323
  if (deferUntilVerdict) {
@@ -40216,7 +40327,7 @@ function makeFileDelivery(opts) {
40216
40327
  }
40217
40328
  if (firedTools.includes(SEND_USER_FILE) && tried === 0) {
40218
40329
  console.error(
40219
- `${tag} file-delivery-unreconciled sender=${entry2.senderId} sessionId=${sid} tool=${SEND_USER_FILE}`
40330
+ `${tag} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${sid} tool=${SEND_USER_FILE}`
40220
40331
  );
40221
40332
  }
40222
40333
  }
@@ -40245,43 +40356,43 @@ var TAG66 = "[webchat-adaptor]";
40245
40356
  function platformRoot2() {
40246
40357
  return process.env.MAXY_PLATFORM_ROOT || "";
40247
40358
  }
40248
- function makeWebchatSendFile(entry2) {
40359
+ function makeWebchatSendFile(entry3) {
40249
40360
  return async (filePath) => {
40250
- if (!entry2.accountId) {
40251
- console.error(`${TAG66} file-delivery reject reason=no-account sender=${entry2.senderId}`);
40361
+ if (!entry3.accountId) {
40362
+ console.error(`${TAG66} file-delivery reject reason=no-account sender=${entry3.senderId}`);
40252
40363
  return { ok: false, error: "no-account" };
40253
40364
  }
40254
- const accountDir = resolve50(platformRoot2(), "..", "data/accounts", entry2.accountId);
40365
+ const accountDir = resolve50(platformRoot2(), "..", "data/accounts", entry3.accountId);
40255
40366
  try {
40256
40367
  const resolved = realpathSync9(filePath);
40257
40368
  const accountResolved = realpathSync9(accountDir);
40258
40369
  if (!resolved.startsWith(accountResolved + "/")) {
40259
- console.error(`${TAG66} file-delivery reject reason=outside_account_directory sender=${entry2.senderId}`);
40370
+ console.error(`${TAG66} file-delivery reject reason=outside_account_directory sender=${entry3.senderId}`);
40260
40371
  return { ok: false, error: "outside-account" };
40261
40372
  }
40262
40373
  return { ok: true };
40263
40374
  } catch (err) {
40264
40375
  const code = err.code;
40265
40376
  console.error(
40266
- `${TAG66} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry2.senderId}`
40377
+ `${TAG66} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry3.senderId}`
40267
40378
  );
40268
40379
  return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
40269
40380
  }
40270
40381
  };
40271
40382
  }
40272
- function makeWebchatFileDelivery(entry2) {
40383
+ function makeWebchatFileDelivery(entry3) {
40273
40384
  return makeFileDelivery({
40274
- entry: entry2,
40385
+ entry: entry3,
40275
40386
  tag: TAG66,
40276
40387
  channel: "webchat",
40277
- sendFile: makeWebchatSendFile(entry2),
40388
+ sendFile: makeWebchatSendFile(entry3),
40278
40389
  deferUntilVerdict: true
40279
40390
  });
40280
40391
  }
40281
40392
 
40282
40393
  // app/lib/webchat/gateway/native-file-follower.ts
40283
40394
  function startWebchatNativeFileFollower(input) {
40284
- const entry2 = {
40395
+ const entry3 = {
40285
40396
  sessionId: input.sessionId,
40286
40397
  role: "admin",
40287
40398
  channel: "webchat",
@@ -40300,7 +40411,7 @@ function startWebchatNativeFileFollower(input) {
40300
40411
  replyTarget: null
40301
40412
  };
40302
40413
  return startEmitter({
40303
- entry: entry2,
40414
+ entry: entry3,
40304
40415
  tag: "[webchat-adaptor]",
40305
40416
  // Task 2557 — the emitter has always had this channel and no follower ever
40306
40417
  // passed one, so every cause it reported was discarded. The close line
@@ -40308,7 +40419,7 @@ function startWebchatNativeFileFollower(input) {
40308
40419
  onError: (reason) => {
40309
40420
  console.error(`[webchat-adaptor] op=follower-error sessionId=${input.sessionId.slice(0, 8)} reason=${reason}`);
40310
40421
  },
40311
- fileDelivery: makeWebchatFileDelivery(entry2),
40422
+ fileDelivery: makeWebchatFileDelivery(entry3),
40312
40423
  // A resumed session's JSONL already holds prior SendUserFile tool_uses;
40313
40424
  // suppress replay so historical calls are not re-reconciled on attach.
40314
40425
  suppressResumeReplay: true,
@@ -40357,29 +40468,29 @@ var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
40357
40468
  function platformRoot3() {
40358
40469
  return process.env.MAXY_PLATFORM_ROOT || "";
40359
40470
  }
40360
- function makeWhatsAppSendFile(entry2, maxyAccountId) {
40471
+ function makeWhatsAppSendFile(entry3, maxyAccountId) {
40361
40472
  return async (filePath, caption) => {
40362
40473
  const result = await sendWhatsAppDocument({
40363
- to: entry2.senderId,
40474
+ to: entry3.senderId,
40364
40475
  filePath,
40365
40476
  caption,
40366
- accountId: entry2.accountId,
40477
+ accountId: entry3.accountId,
40367
40478
  maxyAccountId,
40368
40479
  platformRoot: platformRoot3()
40369
40480
  });
40370
40481
  if (result.ok) return { ok: true };
40371
40482
  console.error(
40372
- `${TAG67} file-delivery reject reason=send-failed sender=${entry2.senderId} status=${result.status} message=${result.error}`
40483
+ `${TAG67} file-delivery reject reason=send-failed sender=${entry3.senderId} status=${result.status} message=${result.error}`
40373
40484
  );
40374
40485
  return { ok: false, error: result.error };
40375
40486
  };
40376
40487
  }
40377
- function makeWhatsAppFileDelivery(entry2, maxyAccountId) {
40488
+ function makeWhatsAppFileDelivery(entry3, maxyAccountId) {
40378
40489
  const shared = makeFileDelivery({
40379
- entry: entry2,
40490
+ entry: entry3,
40380
40491
  tag: TAG67,
40381
40492
  channel: "whatsapp",
40382
- sendFile: makeWhatsAppSendFile(entry2, maxyAccountId)
40493
+ sendFile: makeWhatsAppSendFile(entry3, maxyAccountId)
40383
40494
  });
40384
40495
  let turnStartedAt = null;
40385
40496
  let routeCalls = [];
@@ -40404,7 +40515,7 @@ function makeWhatsAppFileDelivery(entry2, maxyAccountId) {
40404
40515
  const routes = routeCalls;
40405
40516
  turnStartedAt = null;
40406
40517
  routeCalls = [];
40407
- const sid = entry2.sessionId.slice(0, 8);
40518
+ const sid = entry3.sessionId.slice(0, 8);
40408
40519
  shared.onTurnEnd(firedTools);
40409
40520
  for (const call2 of routes) {
40410
40521
  const routeAt = call2.to !== void 0 && call2.filePath !== void 0 ? routeDocumentOutboundAt(call2.to, call2.filePath) : void 0;
@@ -40412,7 +40523,7 @@ function makeWhatsAppFileDelivery(entry2, maxyAccountId) {
40412
40523
  if (!delivered) {
40413
40524
  const fileField = call2.filePath !== void 0 ? ` file=${call2.filePath}` : "";
40414
40525
  console.error(
40415
- `${TAG67} file-delivery-unreconciled sender=${entry2.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
40526
+ `${TAG67} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
40416
40527
  );
40417
40528
  }
40418
40529
  }
@@ -40423,7 +40534,7 @@ function makeWhatsAppFileDelivery(entry2, maxyAccountId) {
40423
40534
  // app/lib/whatsapp/gateway/native-file-follower.ts
40424
40535
  var COMPOSING_REFRESH_MS = 1e4;
40425
40536
  function startNativeFileFollower(input) {
40426
- const entry2 = {
40537
+ const entry3 = {
40427
40538
  sessionId: input.sessionId,
40428
40539
  role: input.role,
40429
40540
  channel: "whatsapp",
@@ -40469,7 +40580,7 @@ function startNativeFileFollower(input) {
40469
40580
  void sendPaused(sock, input.senderId);
40470
40581
  };
40471
40582
  return startEmitter({
40472
- entry: entry2,
40583
+ entry: entry3,
40473
40584
  tag: "[whatsapp-adaptor]",
40474
40585
  // Task 2557 — the emitter has always had this channel and no follower ever
40475
40586
  // passed one, so every cause it reported (`follow-status-404`,
@@ -40481,7 +40592,7 @@ function startNativeFileFollower(input) {
40481
40592
  },
40482
40593
  // Task 2521 — admin-only. A public spawn has no tools (Task 2078), so a
40483
40594
  // handler here would reconcile a call that can never fire.
40484
- fileDelivery: input.role === "admin" ? makeWhatsAppFileDelivery(entry2, input.maxyAccountId) : null,
40595
+ fileDelivery: input.role === "admin" ? makeWhatsAppFileDelivery(entry3, input.maxyAccountId) : null,
40485
40596
  // A resumed session's JSONL already holds prior SendUserFile tool_uses;
40486
40597
  // suppress replay so historical files are not re-sent on attach.
40487
40598
  suppressResumeReplay: true,
@@ -41019,24 +41130,24 @@ var TelegramGateway = class {
41019
41130
  let calls = 0;
41020
41131
  for (const h of held) {
41021
41132
  if (this.spawning.has(h.key)) continue;
41022
- const entry2 = this.heldSpawnArgs.get(h.key);
41023
- if (!entry2) {
41133
+ const entry3 = this.heldSpawnArgs.get(h.key);
41134
+ if (!entry3) {
41024
41135
  console.error(
41025
41136
  `[telegram-native] op=spawn-retry-skipped key=${h.key} ageMs=${h.oldestAgeMs} queued=${h.count} reason=no-args`
41026
41137
  );
41027
41138
  continue;
41028
41139
  }
41029
- entry2.attempts++;
41140
+ entry3.attempts++;
41030
41141
  this.spawning.add(h.key);
41031
41142
  calls++;
41032
41143
  try {
41033
- await this.deps.ensureChannelSession(entry2.args);
41144
+ await this.deps.ensureChannelSession(entry3.args);
41034
41145
  console.error(
41035
- `[telegram-native] op=spawn-retry key=${h.key} attempt=${entry2.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=true`
41146
+ `[telegram-native] op=spawn-retry key=${h.key} attempt=${entry3.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=true`
41036
41147
  );
41037
41148
  } catch (err) {
41038
41149
  console.error(
41039
- `[telegram-native] op=spawn-retry key=${h.key} attempt=${entry2.attempts} ageMs=${h.oldestAgeMs} queued=${h.count} ok=false reason=${err instanceof Error ? err.message : String(err)}`
41150
+ `[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
41151
  );
41041
41152
  } finally {
41042
41153
  this.spawning.delete(h.key);
@@ -41489,33 +41600,33 @@ var TAG71 = "[telegram:outbound]";
41489
41600
  function platformRoot4() {
41490
41601
  return process.env.MAXY_PLATFORM_ROOT || "";
41491
41602
  }
41492
- function makeTelegramSendFile(entry2, botToken) {
41603
+ function makeTelegramSendFile(entry3, botToken) {
41493
41604
  return async (filePath, caption) => {
41494
41605
  if (!botToken) {
41495
- console.error(`${TAG71} file-delivery reject reason=no-bot-token sender=${entry2.senderId} role=${entry2.role}`);
41606
+ console.error(`${TAG71} file-delivery reject reason=no-bot-token sender=${entry3.senderId} role=${entry3.role}`);
41496
41607
  return { ok: false, error: "no-bot-token" };
41497
41608
  }
41498
- if (entry2.replyTarget == null) {
41499
- console.error(`${TAG71} file-delivery reject reason=no-reply-target sender=${entry2.senderId} role=${entry2.role}`);
41609
+ if (entry3.replyTarget == null) {
41610
+ console.error(`${TAG71} file-delivery reject reason=no-reply-target sender=${entry3.senderId} role=${entry3.role}`);
41500
41611
  return { ok: false, error: "no-reply-target" };
41501
41612
  }
41502
41613
  const result = await sendTelegramDocument({
41503
41614
  botToken,
41504
- chatId: Number(entry2.replyTarget),
41615
+ chatId: Number(entry3.replyTarget),
41505
41616
  filePath,
41506
41617
  caption,
41507
- maxyAccountId: entry2.accountId,
41618
+ maxyAccountId: entry3.accountId,
41508
41619
  platformRoot: platformRoot4()
41509
41620
  });
41510
41621
  return result.ok ? { ok: true } : { ok: false, error: result.error };
41511
41622
  };
41512
41623
  }
41513
- function makeTelegramFileDelivery(entry2, botToken) {
41624
+ function makeTelegramFileDelivery(entry3, botToken) {
41514
41625
  return makeFileDelivery({
41515
- entry: entry2,
41626
+ entry: entry3,
41516
41627
  tag: TAG71,
41517
41628
  channel: "telegram",
41518
- sendFile: makeTelegramSendFile(entry2, botToken)
41629
+ sendFile: makeTelegramSendFile(entry3, botToken)
41519
41630
  });
41520
41631
  }
41521
41632
 
@@ -41551,11 +41662,46 @@ function runTelegramPresenceCensus() {
41551
41662
  );
41552
41663
  }
41553
41664
 
41665
+ // app/lib/telegram/gateway/card-census.ts
41666
+ var sessions3 = /* @__PURE__ */ new Map();
41667
+ function entry2(sessionId) {
41668
+ let e = sessions3.get(sessionId);
41669
+ if (!e) {
41670
+ e = { armed: 0, suppressed: 0, delivered: 0 };
41671
+ sessions3.set(sessionId, e);
41672
+ }
41673
+ return e;
41674
+ }
41675
+ function noteCardArmed(sessionId) {
41676
+ entry2(sessionId).armed += 1;
41677
+ }
41678
+ function noteCardSuppressed(sessionId) {
41679
+ entry2(sessionId).suppressed += 1;
41680
+ }
41681
+ function noteCardDelivered(sessionId) {
41682
+ const e = sessions3.get(sessionId);
41683
+ if (e && e.armed > 0) e.delivered += 1;
41684
+ }
41685
+ function cardCensusLines() {
41686
+ let armed2 = 0;
41687
+ let suppressed = 0;
41688
+ let delivered = 0;
41689
+ for (const e of sessions3.values()) {
41690
+ armed2 += e.armed;
41691
+ suppressed += e.suppressed;
41692
+ delivered += e.delivered;
41693
+ }
41694
+ const silent = Math.max(0, armed2 - suppressed - delivered);
41695
+ return [
41696
+ `[telegram-card-suppression-census] sessions=${sessions3.size} armed=${armed2} suppressed=${suppressed} silent-turns=${silent}`
41697
+ ];
41698
+ }
41699
+
41554
41700
  // app/lib/telegram/gateway/native-file-follower.ts
41555
41701
  var TELEGRAM_CARD_TOOL = "mcp__telegram__telegram-card";
41556
41702
  var CHAT_ACTION_REFRESH_MS = 4e3;
41557
41703
  function startTelegramNativeFileFollower(input) {
41558
- const entry2 = {
41704
+ const entry3 = {
41559
41705
  sessionId: input.sessionId,
41560
41706
  role: "admin",
41561
41707
  channel: "telegram",
@@ -41599,7 +41745,8 @@ function startTelegramNativeFileFollower(input) {
41599
41745
  stopHeartbeat();
41600
41746
  lastChatActionAt = Number.NEGATIVE_INFINITY;
41601
41747
  };
41602
- const onTurnStart = () => {
41748
+ const onTurnStart = (kind) => {
41749
+ if (kind === "inbound") cardSentThisTurn = false;
41603
41750
  if (turnOpen) return;
41604
41751
  turnOpen = true;
41605
41752
  stopHeartbeat();
@@ -41612,7 +41759,6 @@ function startTelegramNativeFileFollower(input) {
41612
41759
  };
41613
41760
  const onTurnComplete = () => {
41614
41761
  turnOpen = false;
41615
- cardSentThisTurn = false;
41616
41762
  if (input.backgroundActive?.() === true) return;
41617
41763
  stopHeartbeat();
41618
41764
  lastChatActionAt = Number.NEGATIVE_INFINITY;
@@ -41626,7 +41772,7 @@ function startTelegramNativeFileFollower(input) {
41626
41772
  background: () => input.backgroundActive?.() === true
41627
41773
  });
41628
41774
  return startEmitter({
41629
- entry: entry2,
41775
+ entry: entry3,
41630
41776
  tag: "[telegram-adaptor]",
41631
41777
  // Task 2557 — the emitter has always had this channel and no follower ever
41632
41778
  // passed one, so every cause it reported was discarded. The close line
@@ -41634,7 +41780,7 @@ function startTelegramNativeFileFollower(input) {
41634
41780
  onError: (reason) => {
41635
41781
  console.error(`[telegram-adaptor] op=follower-error sessionId=${input.sessionId.slice(0, 8)} reason=${reason}`);
41636
41782
  },
41637
- fileDelivery: makeTelegramFileDelivery(entry2, input.botToken),
41783
+ fileDelivery: makeTelegramFileDelivery(entry3, input.botToken),
41638
41784
  // A resumed session's JSONL already holds prior SendUserFile tool_uses;
41639
41785
  // suppress replay so historical files are not re-sent on attach.
41640
41786
  suppressResumeReplay: true,
@@ -41652,14 +41798,19 @@ function startTelegramNativeFileFollower(input) {
41652
41798
  // before it reaches the optional answerCallbackQuery, so there is no card
41653
41799
  // call that posts nothing and no bare acknowledgement to keep the text for.
41654
41800
  onToolUse: (name) => {
41655
- if (name === TELEGRAM_CARD_TOOL) cardSentThisTurn = true;
41801
+ if (name !== TELEGRAM_CARD_TOOL) return;
41802
+ cardSentThisTurn = true;
41803
+ noteCardArmed(input.sessionId);
41804
+ console.error(
41805
+ `[telegram-public] op=card-armed sessionId=${input.sessionId.slice(0, 8)} tool=${name}`
41806
+ );
41656
41807
  },
41657
41808
  // Task 2521 — the answer reaches every bound door through the one fan-out.
41658
41809
  // Ungated by design: whatever woke the turn, the reader and the chats show
41659
41810
  // the same thing. Task 2666 adds the one exception above.
41660
41811
  onAnswer: async (answer) => {
41661
41812
  if (cardSentThisTurn) {
41662
- cardSentThisTurn = false;
41813
+ noteCardSuppressed(input.sessionId);
41663
41814
  console.error(
41664
41815
  `[telegram-public] op=text-suppressed sessionId=${input.sessionId.slice(0, 8)} messageId=${answer.messageId} reason=card-sent`
41665
41816
  );
@@ -41670,6 +41821,7 @@ function startTelegramNativeFileFollower(input) {
41670
41821
  noteAnswer(input.sessionId, answer.messageId);
41671
41822
  const { line, reached } = await fanOut({ targets, segments: segmentText(answer.text) });
41672
41823
  noteSent(input.sessionId, answer.messageId, reached);
41824
+ noteCardDelivered(input.sessionId);
41673
41825
  console.error(`${line} messageId=${answer.messageId} sessionId=${input.sessionId.slice(0, 8)}`);
41674
41826
  },
41675
41827
  // Task 2603 — the interval must not outlive the reader. The emitter reaches
@@ -41955,11 +42107,11 @@ async function firePublicSessionEndReview(input) {
41955
42107
  }
41956
42108
 
41957
42109
  // app/lib/whatsapp/inbound/resolve-client-graph-owner.ts
41958
- var import_dist16 = __toESM(require_dist3(), 1);
42110
+ var import_dist17 = __toESM(require_dist3(), 1);
41959
42111
  async function resolveClientOwnerUserId(accountId, deps = {}) {
41960
42112
  const listAccounts = deps.listAccounts ?? listValidAccounts;
41961
42113
  const getSession3 = deps.getSession ?? getSession;
41962
- const resolveOwner2 = deps.resolveOwner ?? import_dist16.resolveOwnerUserId;
42114
+ const resolveOwner2 = deps.resolveOwner ?? import_dist17.resolveOwnerUserId;
41963
42115
  const role = listAccounts().find((a) => a.accountId === accountId)?.config.role;
41964
42116
  if (role !== "client") return null;
41965
42117
  const session = getSession3();
@@ -41982,8 +42134,8 @@ async function resolveClientOwnerUserId(accountId, deps = {}) {
41982
42134
  // app/lib/whatsapp/inbound/channel-admin-binding-drift.ts
41983
42135
  function findAccountManagerDrift(accountManagers, validAccountIds) {
41984
42136
  const drift = [];
41985
- for (const [phone, entry2] of Object.entries(accountManagers)) {
41986
- const managesAccount = typeof entry2 === "string" ? entry2 : entry2.managesAccount;
42137
+ for (const [phone, entry3] of Object.entries(accountManagers)) {
42138
+ const managesAccount = typeof entry3 === "string" ? entry3 : entry3.managesAccount;
41987
42139
  if (!validAccountIds.includes(managesAccount)) {
41988
42140
  drift.push({ phone, managesAccount, reason: "not-in-registry" });
41989
42141
  }
@@ -42089,50 +42241,50 @@ import { join as join71 } from "path";
42089
42241
  function buildTelegramAuditLines(input) {
42090
42242
  const lines = [];
42091
42243
  const entries2 = input.accounts.flatMap(
42092
- (a) => listBotEntries(a.telegram).map((entry2) => ({ accountId: a.accountId, accountDir: a.accountDir, entry: entry2 }))
42244
+ (a) => listBotEntries(a.telegram).map((entry3) => ({ accountId: a.accountId, accountDir: a.accountDir, entry: entry3 }))
42093
42245
  );
42094
42246
  if (entries2.length === 0) return lines;
42095
42247
  const byId = /* @__PURE__ */ new Map();
42096
- for (const { entry: entry2 } of entries2) byId.set(entry2.id, (byId.get(entry2.id) ?? 0) + 1);
42248
+ for (const { entry: entry3 } of entries2) byId.set(entry3.id, (byId.get(entry3.id) ?? 0) + 1);
42097
42249
  for (const [botId, count] of byId) {
42098
42250
  if (count > 1) lines.push(`[telegram-audit] op=duplicate-bot-id botId=${botId} accounts=${count}`);
42099
42251
  }
42100
- for (const { accountId, accountDir, entry: entry2 } of entries2) {
42101
- if (entry2.role === "public" && !input.agentActive(accountDir, entry2.agent)) {
42252
+ for (const { accountId, accountDir, entry: entry3 } of entries2) {
42253
+ if (entry3.role === "public" && !input.agentActive(accountDir, entry3.agent)) {
42102
42254
  lines.push(
42103
- `[telegram-audit] op=entry-agent-inactive accountId=${accountId} botId=${entry2.id} agent=${entry2.agent}`
42255
+ `[telegram-audit] op=entry-agent-inactive accountId=${accountId} botId=${entry3.id} agent=${entry3.agent}`
42104
42256
  );
42105
42257
  }
42106
- if (!input.secretFileExists(entry2.id)) {
42107
- lines.push(`[telegram-audit] op=secret-orphan botId=${entry2.id} side=entry`);
42258
+ if (!input.secretFileExists(entry3.id)) {
42259
+ lines.push(`[telegram-audit] op=secret-orphan botId=${entry3.id} side=entry`);
42108
42260
  }
42109
42261
  }
42110
42262
  const known = new Set(entries2.map((e) => e.entry.id));
42111
42263
  for (const botId of input.secretFilesOnDisk) {
42112
42264
  if (!known.has(botId)) lines.push(`[telegram-audit] op=secret-orphan botId=${botId} side=file`);
42113
42265
  }
42114
- for (const { accountId, entry: entry2 } of entries2) {
42115
- const last = input.lastActivityByBot(entry2.id);
42266
+ for (const { accountId, entry: entry3 } of entries2) {
42267
+ const last = input.lastActivityByBot(entry3.id);
42116
42268
  const spawnAge = last === null ? "never" : String(input.now - last.spawnMs);
42117
42269
  const turnAge = last === null || last.turnMs === null ? "never" : String(input.now - last.turnMs);
42118
- const agent = entryAgentSlug(entry2);
42119
- const secretFile = input.secretFileExists(entry2.id) ? "present" : "absent";
42270
+ const agent = entryAgentSlug(entry3);
42271
+ const secretFile = input.secretFileExists(entry3.id) ? "present" : "absent";
42120
42272
  lines.push(
42121
- `[telegram-audit] op=configured botId=${entry2.id} accountId=${accountId} agent=${agent} secretFile=${secretFile} lastSpawnAgeMs=${spawnAge} lastTurnAgeMs=${turnAge}`
42273
+ `[telegram-audit] op=configured botId=${entry3.id} accountId=${accountId} agent=${agent} secretFile=${secretFile} lastSpawnAgeMs=${spawnAge} lastTurnAgeMs=${turnAge}`
42122
42274
  );
42123
42275
  }
42124
42276
  let bound = 0;
42125
42277
  let rosterOk = 0;
42126
42278
  let rosterMissing = 0;
42127
- for (const { accountId, accountDir, entry: entry2 } of entries2) {
42128
- if (entry2.role !== "specialist") continue;
42279
+ for (const { accountId, accountDir, entry: entry3 } of entries2) {
42280
+ if (entry3.role !== "specialist") continue;
42129
42281
  bound++;
42130
- if (input.specialistCards(accountDir).includes(entry2.specialist)) {
42282
+ if (input.specialistCards(accountDir).includes(entry3.specialist)) {
42131
42283
  rosterOk++;
42132
42284
  } else {
42133
42285
  rosterMissing++;
42134
42286
  lines.push(
42135
- `[telegram-audit] op=specialist-binding-missing accountId=${accountId} botId=${entry2.id} specialist=${entry2.specialist}`
42287
+ `[telegram-audit] op=specialist-binding-missing accountId=${accountId} botId=${entry3.id} specialist=${entry3.specialist}`
42136
42288
  );
42137
42289
  }
42138
42290
  }
@@ -42152,9 +42304,9 @@ function buildManagedBotCensusLine(input) {
42152
42304
  const byId = new Map(input.probes.map((p) => [p.botId, p]));
42153
42305
  let webhookOk = 0;
42154
42306
  let unrestricted = 0;
42155
- for (const entry2 of managed) {
42156
- const probe = byId.get(entry2.id);
42157
- if (probe && probe.webhookUrl && webhookPointsHere(probe.webhookUrl, entry2.id)) webhookOk += 1;
42307
+ for (const entry3 of managed) {
42308
+ const probe = byId.get(entry3.id);
42309
+ if (probe && probe.webhookUrl && webhookPointsHere(probe.webhookUrl, entry3.id)) webhookOk += 1;
42158
42310
  if (probe?.isAccessRestricted === false) unrestricted += 1;
42159
42311
  }
42160
42312
  return `[telegram-audit] op=managed-bot-census bots=${entries2.length} managed=${managed.length} webhookOk=${webhookOk} webhookStale=${managed.length - webhookOk} unrestricted=${unrestricted}`;
@@ -42227,19 +42379,19 @@ function buildGroupCensusLine(c) {
42227
42379
  async function runTelegramGroupCensus(accounts, deps) {
42228
42380
  const counts = { bots: 0, groups: 0, present: 0, absent: 0, privacyOff: 0 };
42229
42381
  for (const account of accounts) {
42230
- for (const entry2 of listBotEntries(account.telegram)) {
42231
- if (entry2.role !== "public") continue;
42232
- if ((entry2.groupPolicy ?? "disabled") !== "allowlist") continue;
42382
+ for (const entry3 of listBotEntries(account.telegram)) {
42383
+ if (entry3.role !== "public") continue;
42384
+ if ((entry3.groupPolicy ?? "disabled") !== "allowlist") continue;
42233
42385
  counts.bots += 1;
42234
42386
  try {
42235
- const me = await deps.getMe(entry2.token);
42387
+ const me = await deps.getMe(entry3.token);
42236
42388
  if (me.can_read_all_group_messages === true) counts.privacyOff += 1;
42237
42389
  } catch {
42238
42390
  }
42239
- for (const chatId of entry2.allowGroups ?? []) {
42391
+ for (const chatId of entry3.allowGroups ?? []) {
42240
42392
  counts.groups += 1;
42241
42393
  try {
42242
- const m = await deps.getChatMember(entry2.token, chatId);
42394
+ const m = await deps.getChatMember(entry3.token, chatId);
42243
42395
  if (typeof m.status === "string" && PRESENT_STATUSES.has(m.status)) counts.present += 1;
42244
42396
  else counts.absent += 1;
42245
42397
  } catch {
@@ -42261,14 +42413,14 @@ function buildChannelCensusLine(c) {
42261
42413
  async function runTelegramChannelCensus(accounts, deps) {
42262
42414
  const counts = { bots: 0, channels: 0, admin: 0, notAdmin: 0, noPostRight: 0 };
42263
42415
  for (const account of accounts) {
42264
- for (const entry2 of listBotEntries(account.telegram)) {
42265
- if (entry2.role !== "public") continue;
42266
- if ((entry2.channelPolicy ?? "disabled") !== "allowlist") continue;
42416
+ for (const entry3 of listBotEntries(account.telegram)) {
42417
+ if (entry3.role !== "public") continue;
42418
+ if ((entry3.channelPolicy ?? "disabled") !== "allowlist") continue;
42267
42419
  counts.bots += 1;
42268
- for (const chatId of entry2.allowChannels ?? []) {
42420
+ for (const chatId of entry3.allowChannels ?? []) {
42269
42421
  counts.channels += 1;
42270
42422
  try {
42271
- const m = await deps.getChatMember(entry2.token, chatId);
42423
+ const m = await deps.getChatMember(entry3.token, chatId);
42272
42424
  if (typeof m.status === "string" && ADMIN_STATUSES.has(m.status)) {
42273
42425
  counts.admin += 1;
42274
42426
  if (m.status === "administrator" && m.can_post_messages !== true) {
@@ -42593,17 +42745,17 @@ function broadcastAdminShutdown(reason) {
42593
42745
  const done = encoder.encode(`data: [DONE]
42594
42746
 
42595
42747
  `);
42596
- for (const entry2 of activeAdminSSEControllers) {
42748
+ for (const entry3 of activeAdminSSEControllers) {
42597
42749
  try {
42598
- entry2.controller.enqueue(frame);
42750
+ entry3.controller.enqueue(frame);
42599
42751
  } catch {
42600
42752
  }
42601
42753
  try {
42602
- entry2.controller.enqueue(done);
42754
+ entry3.controller.enqueue(done);
42603
42755
  } catch {
42604
42756
  }
42605
42757
  try {
42606
- entry2.controller.close();
42758
+ entry3.controller.close();
42607
42759
  } catch {
42608
42760
  }
42609
42761
  }
@@ -42960,8 +43112,8 @@ var webchatFileFollowers = /* @__PURE__ */ new Map();
42960
43112
  async function fetchAccountStandingRules(accountId) {
42961
43113
  const session = getSession();
42962
43114
  try {
42963
- const res = await (0, import_dist17.resolveActiveRules)(session, accountId);
42964
- return { block: (0, import_dist17.formatStandingRulesBlock)(res.rules), ownerUserId: res.ownerUserId, source: res.source };
43115
+ const res = await (0, import_dist18.resolveActiveRules)(session, accountId);
43116
+ return { block: (0, import_dist18.formatStandingRulesBlock)(res.rules), ownerUserId: res.ownerUserId, source: res.source };
42965
43117
  } catch (err) {
42966
43118
  console.error(
42967
43119
  `[preference-inject] op=fetch-failed accountId=${accountId} error=${err instanceof Error ? err.message : String(err)}`
@@ -42997,6 +43149,7 @@ registerLoop({
42997
43149
  run: () => {
42998
43150
  const lines = parityCensusLines();
42999
43151
  for (const line of lines) console.error(line);
43152
+ for (const line of cardCensusLines()) console.error(line);
43000
43153
  const missing = lines.filter((l) => !l.includes("missing=0")).length;
43001
43154
  return `${lines.length} session(s), ${missing} with a missing answer`;
43002
43155
  }
@@ -43533,15 +43686,15 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
43533
43686
  const entries2 = listBotEntries(a.config.telegram);
43534
43687
  for (const bot of readChannelAdmins(a.accountDir, "telegram").byBot) {
43535
43688
  if (!bot.adminUsers.includes(asNumber)) continue;
43536
- const entry2 = entries2.find((e) => e.id === bot.botId);
43537
- if (!entry2) continue;
43689
+ const entry3 = entries2.find((e) => e.id === bot.botId);
43690
+ if (!entry3) continue;
43538
43691
  hits.push({
43539
43692
  accountId: a.accountId,
43540
43693
  botId: bot.botId,
43541
- botToken: entry2.token,
43694
+ botToken: entry3.token,
43542
43695
  // Task 2617 — read off the entry this resolver just chose, so the
43543
43696
  // outbound gate below decides on the same entry the token came from.
43544
- ...chatSendAllowlists(entry2)
43697
+ ...chatSendAllowlists(entry3)
43545
43698
  });
43546
43699
  }
43547
43700
  }
@@ -44627,24 +44780,24 @@ registerLoop({
44627
44780
  const managed = accounts.flatMap((a) => {
44628
44781
  const bots = listBotEntries(a.telegram);
44629
44782
  const admin = bots.find((b) => b.role === "admin");
44630
- return bots.filter((e) => e.managed === true).map((entry2) => ({ entry: entry2, managingToken: admin?.token ?? null }));
44783
+ return bots.filter((e) => e.managed === true).map((entry3) => ({ entry: entry3, managingToken: admin?.token ?? null }));
44631
44784
  });
44632
44785
  const probes2 = [];
44633
- for (const { entry: entry2, managingToken } of managed) {
44786
+ for (const { entry: entry3, managingToken } of managed) {
44634
44787
  let webhookUrl = null;
44635
44788
  let isAccessRestricted = null;
44636
44789
  try {
44637
- webhookUrl = (await getTelegramWebhookInfo(entry2.token)).url;
44790
+ webhookUrl = (await getTelegramWebhookInfo(entry3.token)).url;
44638
44791
  } catch {
44639
44792
  }
44640
44793
  if (managingToken) {
44641
44794
  try {
44642
- const got = await getManagedBotAccessSettings(managingToken, Number(entry2.id));
44795
+ const got = await getManagedBotAccessSettings(managingToken, Number(entry3.id));
44643
44796
  if (got.ok) isAccessRestricted = got.isAccessRestricted;
44644
44797
  } catch {
44645
44798
  }
44646
44799
  }
44647
- probes2.push({ botId: entry2.id, webhookUrl, isAccessRestricted });
44800
+ probes2.push({ botId: entry3.id, webhookUrl, isAccessRestricted });
44648
44801
  }
44649
44802
  console.error(buildManagedBotCensusLine({ accounts, probes: probes2 }));
44650
44803
  }