@rubytech/create-maxy-code 0.1.464 → 0.1.465

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.
@@ -1422,10 +1422,10 @@ var createStreamBody = (stream2) => {
1422
1422
  });
1423
1423
  return body;
1424
1424
  };
1425
- var getStats = (path2) => {
1425
+ var getStats = (path3) => {
1426
1426
  let stats;
1427
1427
  try {
1428
- stats = statSync(path2);
1428
+ stats = statSync(path3);
1429
1429
  } catch {
1430
1430
  }
1431
1431
  return stats;
@@ -1468,21 +1468,21 @@ var serveStatic = (options = { root: "" }) => {
1468
1468
  return next();
1469
1469
  }
1470
1470
  }
1471
- let path2 = join(
1471
+ let path3 = join(
1472
1472
  root,
1473
1473
  !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
1474
1474
  );
1475
- let stats = getStats(path2);
1475
+ let stats = getStats(path3);
1476
1476
  if (stats && stats.isDirectory()) {
1477
1477
  const indexFile2 = options.index ?? "index.html";
1478
- path2 = join(path2, indexFile2);
1479
- stats = getStats(path2);
1478
+ path3 = join(path3, indexFile2);
1479
+ stats = getStats(path3);
1480
1480
  }
1481
1481
  if (!stats) {
1482
- await options.onNotFound?.(path2, c);
1482
+ await options.onNotFound?.(path3, c);
1483
1483
  return next();
1484
1484
  }
1485
- const mimeType = getMimeType(path2);
1485
+ const mimeType = getMimeType(path3);
1486
1486
  c.header("Content-Type", mimeType || "application/octet-stream");
1487
1487
  if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
1488
1488
  const acceptEncodingSet = new Set(
@@ -1492,12 +1492,12 @@ var serveStatic = (options = { root: "" }) => {
1492
1492
  if (!acceptEncodingSet.has(encoding)) {
1493
1493
  continue;
1494
1494
  }
1495
- const precompressedStats = getStats(path2 + ENCODINGS[encoding]);
1495
+ const precompressedStats = getStats(path3 + ENCODINGS[encoding]);
1496
1496
  if (precompressedStats) {
1497
1497
  c.header("Content-Encoding", encoding);
1498
1498
  c.header("Vary", "Accept-Encoding", { append: true });
1499
1499
  stats = precompressedStats;
1500
- path2 = path2 + ENCODINGS[encoding];
1500
+ path3 = path3 + ENCODINGS[encoding];
1501
1501
  break;
1502
1502
  }
1503
1503
  }
@@ -1511,7 +1511,7 @@ var serveStatic = (options = { root: "" }) => {
1511
1511
  result = c.body(null);
1512
1512
  } else if (!range) {
1513
1513
  c.header("Content-Length", size.toString());
1514
- result = c.body(createStreamBody(createReadStream(path2)), 200);
1514
+ result = c.body(createStreamBody(createReadStream(path3)), 200);
1515
1515
  } else {
1516
1516
  c.header("Accept-Ranges", "bytes");
1517
1517
  c.header("Date", stats.birthtime.toUTCString());
@@ -1522,12 +1522,12 @@ var serveStatic = (options = { root: "" }) => {
1522
1522
  end = size - 1;
1523
1523
  }
1524
1524
  const chunksize = end - start + 1;
1525
- const stream2 = createReadStream(path2, { start, end });
1525
+ const stream2 = createReadStream(path3, { start, end });
1526
1526
  c.header("Content-Length", chunksize.toString());
1527
1527
  c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
1528
1528
  result = c.body(createStreamBody(stream2), 206);
1529
1529
  }
1530
- await options.onFound?.(path2, c);
1530
+ await options.onFound?.(path3, c);
1531
1531
  return result;
1532
1532
  };
1533
1533
  };
@@ -2176,7 +2176,7 @@ function listCredentialAccountIds(configDir2) {
2176
2176
  // app/lib/whatsapp/session.ts
2177
2177
  import { randomUUID } from "crypto";
2178
2178
  import fsSync2 from "fs";
2179
- import fs2 from "fs/promises";
2179
+ import fs3 from "fs/promises";
2180
2180
  import { inspect } from "util";
2181
2181
  import {
2182
2182
  Browsers,
@@ -2187,7 +2187,63 @@ import {
2187
2187
  useMultiFileAuthState
2188
2188
  } from "@whiskeysockets/baileys";
2189
2189
  import { createRequire } from "module";
2190
+
2191
+ // app/lib/whatsapp/baileys-debug-window.ts
2192
+ import fs2 from "fs";
2193
+ import path2 from "path";
2190
2194
  var TAG2 = "[whatsapp:session]";
2195
+ var SENTINEL_BASENAME = "baileys-debug-until";
2196
+ var STAT_INTERVAL_MS = 1e3;
2197
+ var VALID_LEVELS = /* @__PURE__ */ new Set(["trace", "debug", "info"]);
2198
+ var INACTIVE = { active: false, level: "warn" };
2199
+ var cache = /* @__PURE__ */ new Map();
2200
+ function sentinelPath(authDir) {
2201
+ return path2.join(authDir, SENTINEL_BASENAME);
2202
+ }
2203
+ function readSentinel(authDir, nowMs) {
2204
+ let raw;
2205
+ try {
2206
+ raw = fs2.readFileSync(sentinelPath(authDir), "utf-8");
2207
+ } catch {
2208
+ return { state: INACTIVE, deadlineMs: null };
2209
+ }
2210
+ const line = raw.split("\n", 1)[0].trim();
2211
+ if (!line) return { state: INACTIVE, deadlineMs: null };
2212
+ const tokens = line.split(/\s+/);
2213
+ const deadlineMs = Date.parse(tokens[0]);
2214
+ if (Number.isNaN(deadlineMs) || deadlineMs <= nowMs) {
2215
+ return { state: INACTIVE, deadlineMs: null };
2216
+ }
2217
+ let level = "trace";
2218
+ if (tokens.length > 1) {
2219
+ if (!VALID_LEVELS.has(tokens[1])) return { state: INACTIVE, deadlineMs: null };
2220
+ level = tokens[1];
2221
+ }
2222
+ return { state: { active: true, level }, deadlineMs };
2223
+ }
2224
+ function resolveDebugWindow(authDir, nowMs = Date.now()) {
2225
+ if (!authDir) return INACTIVE;
2226
+ const prev = cache.get(authDir);
2227
+ if (prev && nowMs - prev.checkedAtMs < STAT_INTERVAL_MS) {
2228
+ return prev.state;
2229
+ }
2230
+ const { state, deadlineMs } = readSentinel(authDir, nowMs);
2231
+ const wasActive = prev?.state.active ?? false;
2232
+ if (!wasActive && state.active) {
2233
+ console.error(
2234
+ `${TAG2} op=baileys-debug-window-open account=${path2.basename(authDir)} level=${state.level} until=${new Date(deadlineMs).toISOString()}`
2235
+ );
2236
+ } else if (wasActive && !state.active) {
2237
+ console.error(
2238
+ `${TAG2} op=baileys-debug-window-close account=${path2.basename(authDir)}`
2239
+ );
2240
+ }
2241
+ cache.set(authDir, { checkedAtMs: nowMs, state });
2242
+ return state;
2243
+ }
2244
+
2245
+ // app/lib/whatsapp/session.ts
2246
+ var TAG3 = "[whatsapp:session]";
2191
2247
  var WIRE_TAG = "[whatsapp:wire]";
2192
2248
  var baileysPkgVersion = (() => {
2193
2249
  try {
@@ -2197,7 +2253,7 @@ var baileysPkgVersion = (() => {
2197
2253
  return "unknown";
2198
2254
  }
2199
2255
  })();
2200
- console.error(`${TAG2} baileys package loaded version=${baileysPkgVersion}`);
2256
+ console.error(`${TAG3} baileys package loaded version=${baileysPkgVersion}`);
2201
2257
  var __BAILEYS_TAG = "[whatsapp:baileys]";
2202
2258
  var INSPECT_OPTS = {
2203
2259
  depth: null,
@@ -2222,7 +2278,8 @@ function bindingsToPrefix(bindings) {
2222
2278
  }
2223
2279
  return parts.join(" ");
2224
2280
  }
2225
- function createBaileysLogger(bindings = {}) {
2281
+ var LEVEL_RANK = { trace: 10, debug: 20, info: 30 };
2282
+ function createBaileysLogger(bindings = {}, authDir) {
2226
2283
  const prefix = Object.keys(bindings).length > 0 ? bindingsToPrefix(bindings) : "";
2227
2284
  const emit = (level, args) => {
2228
2285
  const serialized = args.map(serializeArg).join(" ");
@@ -2232,23 +2289,32 @@ function createBaileysLogger(bindings = {}) {
2232
2289
  console.error(__BAILEYS_TAG, level, serialized);
2233
2290
  }
2234
2291
  };
2292
+ const emitIfWindowed = (rank, level, args) => {
2293
+ const w = resolveDebugWindow(authDir);
2294
+ if (w.active && rank >= LEVEL_RANK[w.level]) {
2295
+ emit(level, args);
2296
+ }
2297
+ };
2235
2298
  return {
2236
- level: "warn",
2237
- trace: () => {
2238
- },
2239
- debug: () => {
2240
- },
2241
- info: () => {
2299
+ // Live getter: Baileys reads config.logger.level per-frame and (verified on
2300
+ // the pinned version) never shallow-copies the logger, so the window's level
2301
+ // reaches socket.js:449/465 as it changes. A Baileys that spread the logger
2302
+ // would freeze this to one value — revisit on upgrade.
2303
+ get level() {
2304
+ return resolveDebugWindow(authDir).level;
2242
2305
  },
2306
+ trace: (...args) => emitIfWindowed(LEVEL_RANK.trace, "TRACE", args),
2307
+ debug: (...args) => emitIfWindowed(LEVEL_RANK.debug, "DEBUG", args),
2308
+ info: (...args) => emitIfWindowed(LEVEL_RANK.info, "INFO", args),
2243
2309
  warn: (...args) => emit("WARN", args),
2244
2310
  error: (...args) => emit("ERROR", args),
2245
2311
  fatal: (...args) => emit("FATAL", args),
2246
- child: (childBindings) => createBaileysLogger({ ...bindings, ...childBindings ?? {} })
2312
+ child: (childBindings) => createBaileysLogger({ ...bindings, ...childBindings ?? {} }, authDir)
2247
2313
  };
2248
2314
  }
2249
2315
  var credsSaveQueue = Promise.resolve();
2250
2316
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
2251
- console.error(`${TAG2} draining credential save queue\u2026`);
2317
+ console.error(`${TAG3} draining credential save queue\u2026`);
2252
2318
  const timer2 = new Promise(
2253
2319
  (resolve37) => setTimeout(() => resolve37("timeout"), timeoutMs)
2254
2320
  );
@@ -2257,9 +2323,9 @@ async function drainCredsSaveQueue(timeoutMs = 5e3) {
2257
2323
  timer2
2258
2324
  ]);
2259
2325
  if (result === "timeout") {
2260
- console.error(`${TAG2} credential save queue drain timed out after ${timeoutMs}ms`);
2326
+ console.error(`${TAG3} credential save queue drain timed out after ${timeoutMs}ms`);
2261
2327
  } else {
2262
- console.error(`${TAG2} credential save queue drained`);
2328
+ console.error(`${TAG3} credential save queue drained`);
2263
2329
  }
2264
2330
  }
2265
2331
  function readCredsJsonRaw2(filePath) {
@@ -2282,53 +2348,53 @@ async function safeSaveCreds(authDir, saveCreds) {
2282
2348
  JSON.parse(raw);
2283
2349
  fsSync2.copyFileSync(credsPath, backupPath);
2284
2350
  } catch (err) {
2285
- console.warn(`${TAG2} backup pre-copy failed (parse or write) authDir=${authDir}: ${String(err)}`);
2351
+ console.warn(`${TAG3} backup pre-copy failed (parse or write) authDir=${authDir}: ${String(err)}`);
2286
2352
  }
2287
2353
  }
2288
2354
  } catch (err) {
2289
- console.warn(`${TAG2} backup preparation failed authDir=${authDir}: ${String(err)}`);
2355
+ console.warn(`${TAG3} backup preparation failed authDir=${authDir}: ${String(err)}`);
2290
2356
  }
2291
2357
  try {
2292
2358
  await Promise.resolve(saveCreds());
2293
2359
  const credsPath = resolveCredsPath(authDir);
2294
2360
  try {
2295
- const stats = await fs2.stat(credsPath);
2361
+ const stats = await fs3.stat(credsPath);
2296
2362
  if (stats.size <= 1) {
2297
- console.error(`${TAG2} WARNING: creds file empty/truncated after save path=${credsPath} size=${stats.size}`);
2363
+ console.error(`${TAG3} WARNING: creds file empty/truncated after save path=${credsPath} size=${stats.size}`);
2298
2364
  } else {
2299
- console.error(`${TAG2} creds saved and verified path=${credsPath} size=${stats.size}`);
2365
+ console.error(`${TAG3} creds saved and verified path=${credsPath} size=${stats.size}`);
2300
2366
  }
2301
2367
  } catch (statErr) {
2302
- console.error(`${TAG2} creds NOT found on disk after save path=${credsPath}: ${String(statErr)}`);
2368
+ console.error(`${TAG3} creds NOT found on disk after save path=${credsPath}: ${String(statErr)}`);
2303
2369
  }
2304
2370
  } catch (err) {
2305
- console.error(`${TAG2} failed saving creds to ${authDir}: ${String(err)}`);
2371
+ console.error(`${TAG3} failed saving creds to ${authDir}: ${String(err)}`);
2306
2372
  }
2307
2373
  }
2308
2374
  function enqueueSaveCreds(authDir, saveCreds) {
2309
2375
  credsSaveQueue = credsSaveQueue.then(() => safeSaveCreds(authDir, saveCreds)).catch((err) => {
2310
- console.error(`${TAG2} creds save queue error: ${String(err)}`);
2376
+ console.error(`${TAG3} creds save queue error: ${String(err)}`);
2311
2377
  });
2312
2378
  }
2313
2379
  async function createWaSocket(opts) {
2314
2380
  const { authDir, onQr, onConnectionUpdate, silent, correlationId, account, getCodeIssuedTs } = opts;
2315
2381
  const cid = correlationId ?? "none";
2316
2382
  const acct = account ?? "unknown";
2317
- await fs2.mkdir(authDir, { recursive: true });
2383
+ await fs3.mkdir(authDir, { recursive: true });
2318
2384
  maybeRestoreCredsFromBackup(authDir);
2319
2385
  const { state, saveCreds } = await useMultiFileAuthState(authDir);
2320
2386
  const { version } = await fetchLatestBaileysVersion();
2321
2387
  if (!silent) {
2322
2388
  const preCensus = credsCensus(authDir);
2323
2389
  console.error(
2324
- `${TAG2} op=creds-pre cid=${cid} account=${acct} credsPresent=${preCensus.credsPresent} registered=${preCensus.registered} hasAccount=${preCensus.hasAccountSignature}`
2390
+ `${TAG3} op=creds-pre cid=${cid} account=${acct} credsPresent=${preCensus.credsPresent} registered=${preCensus.registered} hasAccount=${preCensus.hasAccountSignature}`
2325
2391
  );
2326
2392
  }
2327
2393
  const openTs = Date.now();
2328
2394
  console.error(
2329
- `${TAG2} op=socket-open cid=${cid} account=${acct} baileysVersion=${baileysPkgVersion} waProtocolVersion=${version.join(".")} openTs=${openTs}`
2395
+ `${TAG3} op=socket-open cid=${cid} account=${acct} baileysVersion=${baileysPkgVersion} waProtocolVersion=${version.join(".")} openTs=${openTs}`
2330
2396
  );
2331
- const baileysLogger = createBaileysLogger();
2397
+ const baileysLogger = createBaileysLogger({}, authDir);
2332
2398
  const sock = makeWASocket({
2333
2399
  auth: {
2334
2400
  creds: state.creds,
@@ -2343,7 +2409,7 @@ async function createWaSocket(opts) {
2343
2409
  fireInitQueries: false
2344
2410
  });
2345
2411
  sock.ev.on("creds.update", () => {
2346
- console.error(`${TAG2} creds.update received \u2014 saving to ${authDir}`);
2412
+ console.error(`${TAG3} creds.update received \u2014 saving to ${authDir}`);
2347
2413
  enqueueSaveCreds(authDir, saveCreds);
2348
2414
  });
2349
2415
  let qrSequence = 0;
@@ -2363,14 +2429,14 @@ async function createWaSocket(opts) {
2363
2429
  parts.push(`disconnectReason=${formatError(update.lastDisconnect.error)}`);
2364
2430
  }
2365
2431
  if (!silent && parts.length > 0) {
2366
- console.error(`${TAG2} connection.update ${parts.join(" ")}`);
2432
+ console.error(`${TAG3} connection.update ${parts.join(" ")}`);
2367
2433
  }
2368
2434
  if (update.qr && !silent) {
2369
2435
  const now = Date.now();
2370
2436
  const sinceLastRefMs = lastQrTs ? now - lastQrTs : null;
2371
2437
  lastQrTs = now;
2372
2438
  console.error(
2373
- `${TAG2} op=qr cid=${cid} qr=#${qrSequence} sinceOpenMs=${now - openTs} sinceLastRefMs=${sinceLastRefMs ?? "n/a"}`
2439
+ `${TAG3} op=qr cid=${cid} qr=#${qrSequence} sinceOpenMs=${now - openTs} sinceLastRefMs=${sinceLastRefMs ?? "n/a"}`
2374
2440
  );
2375
2441
  }
2376
2442
  if (update.isNewLogin === true && !pairSuccessLogged && !silent) {
@@ -2379,7 +2445,7 @@ async function createWaSocket(opts) {
2379
2445
  const sinceCodeIssuedMs = codeIssuedTs ? Date.now() - codeIssuedTs : null;
2380
2446
  const afterCensus = credsCensus(authDir);
2381
2447
  console.error(
2382
- `${TAG2} op=pair-success cid=${cid} account=${acct} sinceCodeIssuedMs=${sinceCodeIssuedMs ?? "n/a"} hasAccountAfter=${afterCensus.hasAccountSignature}`
2448
+ `${TAG3} op=pair-success cid=${cid} account=${acct} sinceCodeIssuedMs=${sinceCodeIssuedMs ?? "n/a"} hasAccountAfter=${afterCensus.hasAccountSignature}`
2383
2449
  );
2384
2450
  }
2385
2451
  if (update.qr && onQr) {
@@ -2389,25 +2455,25 @@ async function createWaSocket(opts) {
2389
2455
  const status = getStatusCode(update.lastDisconnect?.error);
2390
2456
  if (!silent) {
2391
2457
  console.error(
2392
- `${TAG2} op=close cid=${cid} account=${acct} status=${status ?? "unknown"} reason="${formatError(update.lastDisconnect?.error)}" socketLifeMs=${Date.now() - openTs} kind=${closeKind(status, everOpen)}`
2458
+ `${TAG3} op=close cid=${cid} account=${acct} status=${status ?? "unknown"} reason="${formatError(update.lastDisconnect?.error)}" socketLifeMs=${Date.now() - openTs} kind=${closeKind(status, everOpen)}`
2393
2459
  );
2394
2460
  }
2395
2461
  if (status === DisconnectReason.loggedOut && !silent) {
2396
- console.error(`${TAG2} session logged out (401) \u2014 re-link required`);
2462
+ console.error(`${TAG3} session logged out (401) \u2014 re-link required`);
2397
2463
  }
2398
2464
  }
2399
2465
  if (update.connection === "open") {
2400
2466
  everOpen = true;
2401
- if (!silent) console.error(`${TAG2} connected`);
2467
+ if (!silent) console.error(`${TAG3} connected`);
2402
2468
  }
2403
2469
  onConnectionUpdate?.(update);
2404
2470
  } catch (err) {
2405
- console.error(`${TAG2} connection.update handler error: ${String(err)}`);
2471
+ console.error(`${TAG3} connection.update handler error: ${String(err)}`);
2406
2472
  }
2407
2473
  });
2408
2474
  if (sock.ws && typeof sock.ws.on === "function") {
2409
2475
  sock.ws.on("error", (err) => {
2410
- console.error(`${TAG2} WebSocket error: ${String(err)}`);
2476
+ console.error(`${TAG3} WebSocket error: ${String(err)}`);
2411
2477
  });
2412
2478
  sock.ws.on("CB:message", (node) => {
2413
2479
  const attrs = node?.attrs ?? {};
@@ -2547,7 +2613,7 @@ function withTimeout(label, promise, timeoutMs) {
2547
2613
  }
2548
2614
 
2549
2615
  // app/lib/whatsapp/init-queries.ts
2550
- var TAG3 = "[whatsapp:init]";
2616
+ var TAG4 = "[whatsapp:init]";
2551
2617
  var DEFAULT_QUERY_TIMEOUT_MS = 15e3;
2552
2618
  var INSPECT_OPTS2 = {
2553
2619
  depth: null,
@@ -2575,20 +2641,20 @@ async function runInitQueries(sock, ctx) {
2575
2641
  elapsedMs: 0
2576
2642
  };
2577
2643
  console.error(
2578
- `${TAG3} runInitQueries start account=${ctx.accountId} attempt=${ctx.attempt} selfPhone=${ctx.selfPhone ?? "unknown"} authDir=${ctx.authDir} queryTimeoutMs=${queryTimeoutMs}`
2644
+ `${TAG4} runInitQueries start account=${ctx.accountId} attempt=${ctx.attempt} selfPhone=${ctx.selfPhone ?? "unknown"} authDir=${ctx.authDir} queryTimeoutMs=${queryTimeoutMs}`
2579
2645
  );
2580
2646
  console.error(
2581
- `${TAG3} fetchProps SKIPPED account=${ctx.accountId} reason=no-platform-consumer`
2647
+ `${TAG4} fetchProps SKIPPED account=${ctx.accountId} reason=no-platform-consumer`
2582
2648
  );
2583
2649
  if (ctx.signal?.aborted) {
2584
2650
  result.aborted = true;
2585
2651
  result.elapsedMs = Date.now() - startedAt;
2586
2652
  console.error(
2587
- `${TAG3} runInitQueries aborted before start account=${ctx.accountId}`
2653
+ `${TAG4} runInitQueries aborted before start account=${ctx.accountId}`
2588
2654
  );
2589
2655
  return result;
2590
2656
  }
2591
- console.error(`${TAG3} fetchBlocklist start account=${ctx.accountId}`);
2657
+ console.error(`${TAG4} fetchBlocklist start account=${ctx.accountId}`);
2592
2658
  try {
2593
2659
  const blocklist = await withTimeout(
2594
2660
  "fetchBlocklist",
@@ -2598,24 +2664,24 @@ async function runInitQueries(sock, ctx) {
2598
2664
  const count = Array.isArray(blocklist) ? blocklist.length : 0;
2599
2665
  result.blocklistOk = true;
2600
2666
  console.error(
2601
- `${TAG3} fetchBlocklist ok account=${ctx.accountId} count=${count}`
2667
+ `${TAG4} fetchBlocklist ok account=${ctx.accountId} count=${count}`
2602
2668
  );
2603
2669
  } catch (err) {
2604
2670
  const formatted = formatErr(err);
2605
2671
  result.errors.blocklist = formatted;
2606
2672
  console.error(
2607
- `${TAG3} fetchBlocklist FAILED account=${ctx.accountId}: ${formatted}`
2673
+ `${TAG4} fetchBlocklist FAILED account=${ctx.accountId}: ${formatted}`
2608
2674
  );
2609
2675
  }
2610
2676
  if (ctx.signal?.aborted) {
2611
2677
  result.aborted = true;
2612
2678
  result.elapsedMs = Date.now() - startedAt;
2613
2679
  console.error(
2614
- `${TAG3} runInitQueries aborted mid-sequence account=${ctx.accountId} after=fetchBlocklist`
2680
+ `${TAG4} runInitQueries aborted mid-sequence account=${ctx.accountId} after=fetchBlocklist`
2615
2681
  );
2616
2682
  return result;
2617
2683
  }
2618
- console.error(`${TAG3} fetchPrivacySettings start account=${ctx.accountId}`);
2684
+ console.error(`${TAG4} fetchPrivacySettings start account=${ctx.accountId}`);
2619
2685
  try {
2620
2686
  const settings = await withTimeout(
2621
2687
  "fetchPrivacySettings",
@@ -2625,18 +2691,18 @@ async function runInitQueries(sock, ctx) {
2625
2691
  );
2626
2692
  result.privacySettingsOk = true;
2627
2693
  console.error(
2628
- `${TAG3} fetchPrivacySettings ok account=${ctx.accountId} keys=${settings ? Object.keys(settings).join(",") : ""}`
2694
+ `${TAG4} fetchPrivacySettings ok account=${ctx.accountId} keys=${settings ? Object.keys(settings).join(",") : ""}`
2629
2695
  );
2630
2696
  } catch (err) {
2631
2697
  const formatted = formatErr(err);
2632
2698
  result.errors.privacySettings = formatted;
2633
2699
  console.error(
2634
- `${TAG3} fetchPrivacySettings FAILED account=${ctx.accountId}: ${formatted}`
2700
+ `${TAG4} fetchPrivacySettings FAILED account=${ctx.accountId}: ${formatted}`
2635
2701
  );
2636
2702
  }
2637
2703
  result.elapsedMs = Date.now() - startedAt;
2638
2704
  console.error(
2639
- `${TAG3} runInitQueries done account=${ctx.accountId} blocklistOk=${result.blocklistOk} privacySettingsOk=${result.privacySettingsOk} elapsedMs=${result.elapsedMs}`
2705
+ `${TAG4} runInitQueries done account=${ctx.accountId} blocklistOk=${result.blocklistOk} privacySettingsOk=${result.privacySettingsOk} elapsedMs=${result.elapsedMs}`
2640
2706
  );
2641
2707
  return result;
2642
2708
  }
@@ -3533,17 +3599,17 @@ var INBOUND_TTL_MS = 20 * 6e4;
3533
3599
  var INBOUND_MAX = 5e3;
3534
3600
  var agentSentCache = /* @__PURE__ */ new Map();
3535
3601
  var inboundCache = /* @__PURE__ */ new Map();
3536
- function pruneCache(cache2, ttl, max) {
3602
+ function pruneCache(cache3, ttl, max) {
3537
3603
  const now = Date.now();
3538
- for (const [key, entry] of cache2) {
3539
- if (now - entry.ts > ttl) cache2.delete(key);
3604
+ for (const [key, entry] of cache3) {
3605
+ if (now - entry.ts > ttl) cache3.delete(key);
3540
3606
  }
3541
- if (cache2.size > max) {
3542
- const excess = cache2.size - max;
3607
+ if (cache3.size > max) {
3608
+ const excess = cache3.size - max;
3543
3609
  let count = 0;
3544
- for (const key of cache2.keys()) {
3610
+ for (const key of cache3.keys()) {
3545
3611
  if (count >= excess) break;
3546
- cache2.delete(key);
3612
+ cache3.delete(key);
3547
3613
  count++;
3548
3614
  }
3549
3615
  }
@@ -3577,7 +3643,7 @@ function isDuplicateInbound(key) {
3577
3643
  }
3578
3644
 
3579
3645
  // app/lib/whatsapp/inbound/self-chat.ts
3580
- var TAG4 = "[whatsapp:self-chat]";
3646
+ var TAG5 = "[whatsapp:self-chat]";
3581
3647
  function normalizeJid(jid) {
3582
3648
  const m = jid.match(/^(\d+)(?::\d+)?@(s\.whatsapp\.net|lid)$/i);
3583
3649
  return m ? `${m[1]}@${m[2].toLowerCase()}` : jid;
@@ -3597,10 +3663,10 @@ function evaluateSelfChatCommand(input) {
3597
3663
  const connAtMs = input.lastConnectedAtMs ?? 0;
3598
3664
  const msgId = input.msgId ?? "?";
3599
3665
  console.error(
3600
- `${TAG4} op=seen account=${input.accountId} msgId=${msgId} tsMs=${tsMs} connAtMs=${connAtMs} fromMe=true`
3666
+ `${TAG5} op=seen account=${input.accountId} msgId=${msgId} tsMs=${tsMs} connAtMs=${connAtMs} fromMe=true`
3601
3667
  );
3602
3668
  const skip = (reason) => {
3603
- console.error(`${TAG4} op=skip account=${input.accountId} msgId=${msgId} reason=${reason}`);
3669
+ console.error(`${TAG5} op=skip account=${input.accountId} msgId=${msgId} reason=${reason}`);
3604
3670
  return { kind: "skip", reason };
3605
3671
  };
3606
3672
  if (input.msgId && isAgentSentMessage(input.msgId)) return skip("echo");
@@ -3608,13 +3674,13 @@ function evaluateSelfChatCommand(input) {
3608
3674
  if (isDuplicateInbound(`${input.accountId}:${input.remoteJid}:${input.msgId}`)) return skip("duplicate");
3609
3675
  if (!input.text) return skip("no-text");
3610
3676
  console.error(
3611
- `${TAG4} op=dispatch account=${input.accountId} msgId=${msgId} bytes=${Buffer.byteLength(input.text, "utf8")} agentType=admin`
3677
+ `${TAG5} op=dispatch account=${input.accountId} msgId=${msgId} bytes=${Buffer.byteLength(input.text, "utf8")} agentType=admin`
3612
3678
  );
3613
3679
  return { kind: "dispatch", text: input.text };
3614
3680
  }
3615
3681
 
3616
3682
  // app/lib/whatsapp/activity.ts
3617
- var TAG5 = "[whatsapp:activity]";
3683
+ var TAG6 = "[whatsapp:activity]";
3618
3684
  var RECENT_EVENTS_MAX = 200;
3619
3685
  var counters = /* @__PURE__ */ new Map();
3620
3686
  var recentEvents = [];
@@ -3642,10 +3708,10 @@ function recordActivity(event) {
3642
3708
  recentEvents.splice(0, recentEvents.length - RECENT_EVENTS_MAX);
3643
3709
  }
3644
3710
  console.error(
3645
- `${TAG5} channel-activity: direction=${direction} account=${accountId} jid=${jid}` + (messageType ? ` type=${messageType}` : "")
3711
+ `${TAG6} channel-activity: direction=${direction} account=${accountId} jid=${jid}` + (messageType ? ` type=${messageType}` : "")
3646
3712
  );
3647
3713
  } catch (err) {
3648
- console.error(`${TAG5} recording failed: ${String(err)}`);
3714
+ console.error(`${TAG6} recording failed: ${String(err)}`);
3649
3715
  }
3650
3716
  }
3651
3717
  function getChannelActivity(accountId) {
@@ -3666,7 +3732,7 @@ function getChannelActivity(accountId) {
3666
3732
  }
3667
3733
 
3668
3734
  // app/lib/whatsapp/outbound/send.ts
3669
- var TAG6 = "[whatsapp:outbound]";
3735
+ var TAG7 = "[whatsapp:outbound]";
3670
3736
  function buildQuoted(q) {
3671
3737
  return {
3672
3738
  key: {
@@ -3687,14 +3753,14 @@ async function sendTextMessage(sock, to, text, opts) {
3687
3753
  const messageId = result?.key?.id;
3688
3754
  if (messageId) {
3689
3755
  trackAgentSentMessage(messageId);
3690
- console.error(`${TAG6} sent text to=${jid} id=${messageId}`);
3756
+ console.error(`${TAG7} sent text to=${jid} id=${messageId}`);
3691
3757
  }
3692
3758
  if (opts?.accountId) {
3693
3759
  recordActivity({ accountId: opts.accountId, direction: "outbound", jid, messageType: "text" });
3694
3760
  }
3695
3761
  return { success: true, messageId: messageId ?? void 0 };
3696
3762
  } catch (err) {
3697
- console.error(`${TAG6} send failed to=${to}: ${String(err)}`);
3763
+ console.error(`${TAG7} send failed to=${to}: ${String(err)}`);
3698
3764
  return { success: false, error: String(err) };
3699
3765
  }
3700
3766
  }
@@ -3764,20 +3830,20 @@ async function sendMediaMessage(sock, to, media, opts) {
3764
3830
  const messageId = result?.key?.id;
3765
3831
  if (messageId) {
3766
3832
  trackAgentSentMessage(messageId);
3767
- console.error(`${TAG6} sent ${media.type} to=${jid} id=${messageId}`);
3833
+ console.error(`${TAG7} sent ${media.type} to=${jid} id=${messageId}`);
3768
3834
  }
3769
3835
  if (opts?.accountId) {
3770
3836
  recordActivity({ accountId: opts.accountId, direction: "outbound", jid, messageType: media.type });
3771
3837
  }
3772
3838
  return { success: true, messageId: messageId ?? void 0 };
3773
3839
  } catch (err) {
3774
- console.error(`${TAG6} send media failed to=${to}: ${String(err)}`);
3840
+ console.error(`${TAG7} send media failed to=${to}: ${String(err)}`);
3775
3841
  return { success: false, error: String(err) };
3776
3842
  }
3777
3843
  }
3778
3844
 
3779
3845
  // app/lib/whatsapp/persist-message.ts
3780
- var TAG7 = "[whatsapp-persist]";
3846
+ var TAG8 = "[whatsapp-persist]";
3781
3847
  var sessionWriteLocks = /* @__PURE__ */ new Map();
3782
3848
  async function persistWhatsAppMessage(input) {
3783
3849
  if (!input.body && !input.attachmentId || !input.msgKeyId) return null;
@@ -3828,14 +3894,14 @@ async function persistWhatsAppMessage(input) {
3828
3894
  };
3829
3895
  const result = await session.run(cypher, params);
3830
3896
  if (result.records.length === 0) {
3831
- console.error(`${TAG7} skip reason=conversation-not-found accountId=${input.platformAccountId} cacheKey=${input.cacheKey} messageId=${messageId}`);
3897
+ console.error(`${TAG8} skip reason=conversation-not-found accountId=${input.platformAccountId} cacheKey=${input.cacheKey} messageId=${messageId}`);
3832
3898
  return null;
3833
3899
  }
3834
3900
  const rec = result.records[0];
3835
3901
  const senderElementId = rec.get("senderElementId");
3836
3902
  const senderReused = rec.get("senderReused") === true;
3837
3903
  console.error(
3838
- `${TAG7} sender-resolved telephone=${senderTelephone} nodeKind=Person elementId=${senderElementId} reused=${senderReused}`
3904
+ `${TAG8} sender-resolved telephone=${senderTelephone} nodeKind=Person elementId=${senderElementId} reused=${senderReused}`
3839
3905
  );
3840
3906
  const diskRecord = {
3841
3907
  messageId,
@@ -3857,18 +3923,18 @@ async function persistWhatsAppMessage(input) {
3857
3923
  const { created } = appendMessage(input.platformAccountId, diskRecord, altDedupeRemoteJids);
3858
3924
  const ms = Date.now() - t0;
3859
3925
  if (!created) {
3860
- console.error(`${TAG7} noop reason=existing-message messageId=${messageId}`);
3926
+ console.error(`${TAG8} noop reason=existing-message messageId=${messageId}`);
3861
3927
  return { messageId, created: false, senderElementId };
3862
3928
  }
3863
3929
  console.error(
3864
- `${TAG7} write messageId=${messageId} accountId=${input.platformAccountId} cacheKey=${input.cacheKey} fromMe=${input.fromMe} dateSent=${dateSentIso} bodyBytes=${Buffer.byteLength(input.body, "utf8")} attachment=${input.attachmentId ?? "none"} ms=${ms}`
3930
+ `${TAG8} write messageId=${messageId} accountId=${input.platformAccountId} cacheKey=${input.cacheKey} fromMe=${input.fromMe} dateSent=${dateSentIso} bodyBytes=${Buffer.byteLength(input.body, "utf8")} attachment=${input.attachmentId ?? "none"} ms=${ms}`
3865
3931
  );
3866
3932
  return { messageId, created: true, senderElementId };
3867
3933
  } catch (err) {
3868
3934
  const ms = Date.now() - t0;
3869
3935
  const reason = sanitizeReason(err);
3870
3936
  console.error(
3871
- `${TAG7} FAIL accountId=${input.platformAccountId} waname=${input.accountId} remoteJid=${input.remoteJid} msgKey=${input.msgKeyId} reason=${reason} ms=${ms}`
3937
+ `${TAG8} FAIL accountId=${input.platformAccountId} waname=${input.accountId} remoteJid=${input.remoteJid} msgKey=${input.msgKeyId} reason=${reason} ms=${ms}`
3872
3938
  );
3873
3939
  return null;
3874
3940
  } finally {
@@ -3901,7 +3967,7 @@ function sanitizeReason(err) {
3901
3967
  }
3902
3968
 
3903
3969
  // app/lib/whatsapp/ensure-conversation.ts
3904
- var TAG8 = "[whatsapp-persist]";
3970
+ var TAG9 = "[whatsapp-persist]";
3905
3971
  async function ensureWhatsAppConversation(input) {
3906
3972
  const t0 = Date.now();
3907
3973
  try {
@@ -3913,19 +3979,19 @@ async function ensureWhatsAppConversation(input) {
3913
3979
  const ms = Date.now() - t0;
3914
3980
  if (!result.sessionId) {
3915
3981
  console.error(
3916
- `${TAG8} conversation-merged FAIL cacheKey=${input.cacheKey} reason=null-sessionId ms=${ms}`
3982
+ `${TAG9} conversation-merged FAIL cacheKey=${input.cacheKey} reason=null-sessionId ms=${ms}`
3917
3983
  );
3918
3984
  return null;
3919
3985
  }
3920
3986
  console.error(
3921
- `${TAG8} conversation-merged cacheKey=${input.cacheKey} agentType=${input.agentType} channel=whatsapp created=${result.created} ms=${ms}`
3987
+ `${TAG9} conversation-merged cacheKey=${input.cacheKey} agentType=${input.agentType} channel=whatsapp created=${result.created} ms=${ms}`
3922
3988
  );
3923
3989
  return { sessionId: result.sessionId, created: result.created };
3924
3990
  } catch (err) {
3925
3991
  const ms = Date.now() - t0;
3926
3992
  const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
3927
3993
  console.error(
3928
- `${TAG8} conversation-merged FAIL cacheKey=${input.cacheKey} reason=${reason} ms=${ms}`
3994
+ `${TAG9} conversation-merged FAIL cacheKey=${input.cacheKey} reason=${reason} ms=${ms}`
3929
3995
  );
3930
3996
  return null;
3931
3997
  }
@@ -3935,16 +4001,16 @@ async function ensureWhatsAppConversation(input) {
3935
4001
  import { readdirSync as readdirSync2, readFileSync as readFileSync5 } from "fs";
3936
4002
  import { resolve as resolve3 } from "path";
3937
4003
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3938
- var cache = /* @__PURE__ */ new Map();
4004
+ var cache2 = /* @__PURE__ */ new Map();
3939
4005
  function enumerateValidAccountIds(accountsDir) {
3940
- const cached3 = cache.get(accountsDir);
4006
+ const cached3 = cache2.get(accountsDir);
3941
4007
  if (cached3 !== void 0) return cached3;
3942
4008
  let names;
3943
4009
  try {
3944
4010
  names = readdirSync2(accountsDir);
3945
4011
  } catch (err) {
3946
4012
  if (err.code === "ENOENT") {
3947
- cache.set(accountsDir, []);
4013
+ cache2.set(accountsDir, []);
3948
4014
  return [];
3949
4015
  }
3950
4016
  throw err;
@@ -3961,7 +4027,7 @@ function enumerateValidAccountIds(accountsDir) {
3961
4027
  if (code === "ENOENT") continue;
3962
4028
  }
3963
4029
  }
3964
- cache.set(accountsDir, valid);
4030
+ cache2.set(accountsDir, valid);
3965
4031
  return valid;
3966
4032
  }
3967
4033
  function resolveHouseOrSoleAccountId(accountsDir) {
@@ -4559,7 +4625,7 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
4559
4625
  }
4560
4626
 
4561
4627
  // app/lib/whatsapp/inbound/media.ts
4562
- var TAG9 = "[whatsapp:media]";
4628
+ var TAG10 = "[whatsapp:media]";
4563
4629
  var MEDIA_DIR = "/tmp/maxy-media";
4564
4630
  var DOWNLOAD_TIMEOUT_MS = 45e3;
4565
4631
  function deterministicAttachmentId(seed) {
@@ -4647,25 +4713,25 @@ async function downloadInboundMediaBuffer(msg, sock, opts) {
4647
4713
  }
4648
4714
  );
4649
4715
  if (!buffer || buffer.length === 0) {
4650
- console.error(`${TAG9} primary download returned empty, trying direct fallback`);
4716
+ console.error(`${TAG10} primary download returned empty, trying direct fallback`);
4651
4717
  const downloadable = getDownloadableContent(content);
4652
4718
  if (downloadable) {
4653
4719
  try {
4654
4720
  const stream2 = await downloadContentFromMessage(downloadable.downloadable, downloadable.mediaType);
4655
4721
  buffer = await streamToBuffer(stream2);
4656
4722
  } catch (fallbackErr) {
4657
- console.error(`${TAG9} direct download fallback failed: ${String(fallbackErr)}`);
4723
+ console.error(`${TAG10} direct download fallback failed: ${String(fallbackErr)}`);
4658
4724
  }
4659
4725
  }
4660
4726
  }
4661
4727
  if (!buffer || buffer.length === 0) {
4662
- console.error(`${TAG9} download failed: empty buffer for ${mimetype ?? "unknown"}`);
4728
+ console.error(`${TAG10} download failed: empty buffer for ${mimetype ?? "unknown"}`);
4663
4729
  return void 0;
4664
4730
  }
4665
4731
  if (buffer.length > maxBytes) {
4666
4732
  const sizeMB = (buffer.length / (1024 * 1024)).toFixed(1);
4667
4733
  const limitMB = (maxBytes / (1024 * 1024)).toFixed(0);
4668
- console.error(`${TAG9} media too large type=${mimetype ?? "unknown"} size=${sizeMB}MB limit=${limitMB}MB`);
4734
+ console.error(`${TAG10} media too large type=${mimetype ?? "unknown"} size=${sizeMB}MB limit=${limitMB}MB`);
4669
4735
  return void 0;
4670
4736
  }
4671
4737
  return {
@@ -4677,7 +4743,7 @@ async function downloadInboundMediaBuffer(msg, sock, opts) {
4677
4743
  timeoutMs
4678
4744
  );
4679
4745
  } catch (err) {
4680
- console.error(`${TAG9} media download failed type=${mimetype ?? "unknown"} error=${String(err)}`);
4746
+ console.error(`${TAG10} media download failed type=${mimetype ?? "unknown"} error=${String(err)}`);
4681
4747
  return void 0;
4682
4748
  }
4683
4749
  }
@@ -4689,7 +4755,7 @@ async function downloadInboundMedia(msg, sock, opts) {
4689
4755
  const filePath = join6(MEDIA_DIR, `${randomUUID4()}.${ext}`);
4690
4756
  await writeFile2(filePath, res.buffer);
4691
4757
  const sizeKB = (res.buffer.length / 1024).toFixed(0);
4692
- console.error(`${TAG9} media downloaded type=${res.mimetype} size=${sizeKB}KB path=${filePath}`);
4758
+ console.error(`${TAG10} media downloaded type=${res.mimetype} size=${sizeKB}KB path=${filePath}`);
4693
4759
  return { path: filePath, mimetype: res.mimetype, size: res.buffer.length };
4694
4760
  }
4695
4761
  async function storeInboundMediaServable(msg, sock, accountId, seed, opts) {
@@ -4698,19 +4764,27 @@ async function storeInboundMediaServable(msg, sock, accountId, seed, opts) {
4698
4764
  if (attachmentExists(accountId, attachmentId)) return attachmentId;
4699
4765
  const res = await downloadInboundMediaBufferCached(msg, sock, opts);
4700
4766
  if (!res) {
4701
- console.error(`${TAG9} servable-store skip reason=no-buffer id=${attachmentId}`);
4767
+ console.error(`${TAG10} servable-store skip reason=no-buffer id=${attachmentId}`);
4702
4768
  return null;
4703
4769
  }
4704
4770
  const filename = res.filename ?? `${attachmentId}.${mimeToExt(res.mimetype)}`;
4705
4771
  await storeMediaBuffer(accountId, attachmentId, filename, res.mimetype, res.buffer);
4706
- console.error(`${TAG9} servable-store ok id=${attachmentId} mime=${res.mimetype} bytes=${res.buffer.length}`);
4772
+ console.error(`${TAG10} servable-store ok id=${attachmentId} mime=${res.mimetype} bytes=${res.buffer.length}`);
4707
4773
  return attachmentId;
4708
4774
  } catch (err) {
4709
- console.error(`${TAG9} servable-store FAIL id=${attachmentId} reason=${String(err).slice(0, 120)}`);
4775
+ console.error(`${TAG10} servable-store FAIL id=${attachmentId} reason=${String(err).slice(0, 120)}`);
4710
4776
  return null;
4711
4777
  }
4712
4778
  }
4713
4779
 
4780
+ // app/lib/whatsapp/outbound/document-limits.ts
4781
+ var WHATSAPP_DOCUMENT_MAX_BYTES = 100 * 1024 * 1024;
4782
+
4783
+ // app/lib/whatsapp/echo-store-max-bytes.ts
4784
+ function echoStoreMaxBytes(args) {
4785
+ return args.fromMe ? WHATSAPP_DOCUMENT_MAX_BYTES : (args.mediaMaxMb ?? 50) * 1024 * 1024;
4786
+ }
4787
+
4714
4788
  // app/lib/whatsapp/inbound/bounded-queue.ts
4715
4789
  function createBoundedQueue(limit, opts) {
4716
4790
  if (!Number.isInteger(limit) || limit < 1) {
@@ -4746,7 +4820,7 @@ function createBoundedQueue(limit, opts) {
4746
4820
  }
4747
4821
 
4748
4822
  // app/lib/whatsapp/inbound/debounce.ts
4749
- var TAG10 = "[whatsapp:debounce]";
4823
+ var TAG11 = "[whatsapp:debounce]";
4750
4824
  var STT_TAG = "[whatsapp:stt-await]";
4751
4825
  function createInboundDebouncer(opts) {
4752
4826
  const { debounceMs, buildKey, onFlush, onError } = opts;
@@ -4777,7 +4851,7 @@ function createInboundDebouncer(opts) {
4777
4851
  pending.delete(key);
4778
4852
  const batchSize = batch.entries.length;
4779
4853
  try {
4780
- console.error(`${TAG10} debounce flush key=${key} batchSize=${batchSize}`);
4854
+ console.error(`${TAG11} debounce flush key=${key} batchSize=${batchSize}`);
4781
4855
  const result = onFlush(batch.entries);
4782
4856
  if (result && typeof result.catch === "function") {
4783
4857
  result.catch(onError);
@@ -4857,7 +4931,7 @@ function combineInboundBatch(entries) {
4857
4931
  }
4858
4932
 
4859
4933
  // app/lib/whatsapp/opening-hours.ts
4860
- var TAG11 = "[whatsapp:hours]";
4934
+ var TAG12 = "[whatsapp:hours]";
4861
4935
  async function isBusinessOpen(accountId) {
4862
4936
  try {
4863
4937
  const timezone = await resolveTimezone(accountId);
@@ -4875,7 +4949,7 @@ async function isBusinessOpen(accountId) {
4875
4949
  { accountId, dayOfWeek, previousDayOfWeek }
4876
4950
  );
4877
4951
  if (result.records.length === 0) {
4878
- console.error(`${TAG11} [${accountId}] business hours check: no opening hours configured, treating as open`);
4952
+ console.error(`${TAG12} [${accountId}] business hours check: no opening hours configured, treating as open`);
4879
4953
  return { open: true, reason: "no opening hours configured" };
4880
4954
  }
4881
4955
  const specs = result.records.filter((r) => r.get("opens") != null && r.get("closes") != null).map((r) => ({
@@ -4884,7 +4958,7 @@ async function isBusinessOpen(accountId) {
4884
4958
  closes: String(r.get("closes")).trim()
4885
4959
  }));
4886
4960
  if (specs.length === 0) {
4887
- console.error(`${TAG11} [${accountId}] business hours check: no opening hours configured, treating as open`);
4961
+ console.error(`${TAG12} [${accountId}] business hours check: no opening hours configured, treating as open`);
4888
4962
  return { open: true, reason: "no opening hours configured" };
4889
4963
  }
4890
4964
  for (const spec of specs) {
@@ -4894,7 +4968,7 @@ async function isBusinessOpen(accountId) {
4894
4968
  if (spec.opens > spec.closes && currentTime < spec.closes) {
4895
4969
  const hoursStr = `${spec.opens}-${spec.closes} (${spec.day})`;
4896
4970
  console.error(
4897
- `${TAG11} [${accountId}] business hours check: open (day=${dayOfWeek}, time=${currentTime}, hours=${hoursStr})`
4971
+ `${TAG12} [${accountId}] business hours check: open (day=${dayOfWeek}, time=${currentTime}, hours=${hoursStr})`
4898
4972
  );
4899
4973
  return {
4900
4974
  open: true,
@@ -4907,7 +4981,7 @@ async function isBusinessOpen(accountId) {
4907
4981
  } else if (isTimeInRange(currentTime, spec.opens, spec.closes)) {
4908
4982
  const hoursStr = `${spec.opens}-${spec.closes}`;
4909
4983
  console.error(
4910
- `${TAG11} [${accountId}] business hours check: open (day=${dayOfWeek}, time=${currentTime}, hours=${hoursStr})`
4984
+ `${TAG12} [${accountId}] business hours check: open (day=${dayOfWeek}, time=${currentTime}, hours=${hoursStr})`
4911
4985
  );
4912
4986
  return {
4913
4987
  open: true,
@@ -4921,7 +4995,7 @@ async function isBusinessOpen(accountId) {
4921
4995
  const todaySpecs = specs.filter((s) => s.day === dayOfWeek);
4922
4996
  const allHours = todaySpecs.map((s) => `${s.opens}-${s.closes}`).join(", ") || "none today";
4923
4997
  console.error(
4924
- `${TAG11} [${accountId}] business hours check: closed (day=${dayOfWeek}, time=${currentTime}, hours=${allHours})`
4998
+ `${TAG12} [${accountId}] business hours check: closed (day=${dayOfWeek}, time=${currentTime}, hours=${allHours})`
4925
4999
  );
4926
5000
  return {
4927
5001
  open: false,
@@ -4935,7 +5009,7 @@ async function isBusinessOpen(accountId) {
4935
5009
  }
4936
5010
  } catch (err) {
4937
5011
  console.error(
4938
- `${TAG11} [${accountId}] business hours check failed, treating as open: ${err instanceof Error ? err.message : String(err)}`
5012
+ `${TAG12} [${accountId}] business hours check failed, treating as open: ${err instanceof Error ? err.message : String(err)}`
4939
5013
  );
4940
5014
  return { open: true, reason: "hours check failed (treating as open)" };
4941
5015
  }
@@ -4981,7 +5055,7 @@ import { execFile } from "child_process";
4981
5055
  import { unlink, stat } from "fs/promises";
4982
5056
  import { promisify } from "util";
4983
5057
  var execFileAsync = promisify(execFile);
4984
- var TAG12 = "[stt]";
5058
+ var TAG13 = "[stt]";
4985
5059
  var WHISPER_BINARY = process.env.WHISPER_BINARY ?? "/opt/whisper.cpp/build/bin/whisper-cli";
4986
5060
  var WHISPER_MODEL = process.env.WHISPER_MODEL ?? "/opt/whisper.cpp/models/ggml-base.bin";
4987
5061
  var WHISPER_TIMEOUT_MS = 20 * 60 * 1e3;
@@ -5000,11 +5074,11 @@ async function transcribe(audioPath, mimetype) {
5000
5074
  const s = await stat(audioPath);
5001
5075
  audioBytes = s.size;
5002
5076
  } catch {
5003
- console.error(`${TAG12} failed: file not readable path=${audioPath}`);
5077
+ console.error(`${TAG13} failed: file not readable path=${audioPath}`);
5004
5078
  return void 0;
5005
5079
  }
5006
5080
  console.error(
5007
- `${TAG12} start provider=whisper-local audio_bytes=${audioBytes} mimetype=${mimetype} path=${audioPath}`
5081
+ `${TAG13} start provider=whisper-local audio_bytes=${audioBytes} mimetype=${mimetype} path=${audioPath}`
5008
5082
  );
5009
5083
  const wavPath = audioPath.replace(/\.[^.]+$/, "") + ".wav";
5010
5084
  try {
@@ -5023,7 +5097,7 @@ async function transcribe(audioPath, mimetype) {
5023
5097
  ], { timeout: 3e4 });
5024
5098
  } catch (err) {
5025
5099
  const reason = err instanceof Error ? err.message : String(err);
5026
- console.error(`${TAG12} failed: ffmpeg conversion error=${reason}`);
5100
+ console.error(`${TAG13} failed: ffmpeg conversion error=${reason}`);
5027
5101
  return void 0;
5028
5102
  }
5029
5103
  try {
@@ -5039,20 +5113,20 @@ async function transcribe(audioPath, mimetype) {
5039
5113
  const durationMs = Date.now() - startMs;
5040
5114
  const { text, count: stripped } = stripSpecialTokens(stdout.trim());
5041
5115
  if (!text) {
5042
- console.error(`${TAG12} failed: whisper returned empty output duration_ms=${durationMs}`);
5116
+ console.error(`${TAG13} failed: whisper returned empty output duration_ms=${durationMs}`);
5043
5117
  return void 0;
5044
5118
  }
5045
5119
  const langMatch = stderr.match(/auto-detected language:\s*(\w+)/);
5046
5120
  const language = langMatch?.[1] ?? "unknown";
5047
5121
  const words = text.split(/\s+/).filter(Boolean).length;
5048
5122
  console.error(
5049
- `${TAG12} done provider=whisper-local duration_ms=${durationMs} words=${words} stripped=${stripped} lang=${language}`
5123
+ `${TAG13} done provider=whisper-local duration_ms=${durationMs} words=${words} stripped=${stripped} lang=${language}`
5050
5124
  );
5051
5125
  return { text, language, durationMs };
5052
5126
  } catch (err) {
5053
5127
  const durationMs = Date.now() - startMs;
5054
5128
  const reason = err instanceof Error ? err.message : String(err);
5055
- console.error(`${TAG12} failed provider=whisper-local duration_ms=${durationMs} error=${reason}`);
5129
+ console.error(`${TAG13} failed provider=whisper-local duration_ms=${durationMs} error=${reason}`);
5056
5130
  return void 0;
5057
5131
  } finally {
5058
5132
  unlink(wavPath).catch(() => {
@@ -5071,7 +5145,7 @@ var WaReplyError = class extends Error {
5071
5145
  };
5072
5146
 
5073
5147
  // app/lib/whatsapp/manager.ts
5074
- var TAG13 = "[whatsapp:manager]";
5148
+ var TAG14 = "[whatsapp:manager]";
5075
5149
  var MAX_RECONNECT_ATTEMPTS = 10;
5076
5150
  var MESSAGE_STORE_MAX = 500;
5077
5151
  var APPEND_MEDIA_CONCURRENCY = 3;
@@ -5098,7 +5172,7 @@ function storeMessage(storeKey, entry) {
5098
5172
  if (entries.length > MESSAGE_STORE_MAX) {
5099
5173
  const trimmed = entries.length - MESSAGE_STORE_MAX;
5100
5174
  entries.splice(0, trimmed);
5101
- console.error(`${TAG13} message store trimmed for ${storeKey}: ${trimmed} oldest messages removed`);
5175
+ console.error(`${TAG14} message store trimmed for ${storeKey}: ${trimmed} oldest messages removed`);
5102
5176
  }
5103
5177
  }
5104
5178
  function deriveCacheKey(input) {
@@ -5141,7 +5215,7 @@ function buildSelfChatDispatch(input) {
5141
5215
  }
5142
5216
  async function init(opts) {
5143
5217
  if (initialized) {
5144
- console.error(`${TAG13} already initialized`);
5218
+ console.error(`${TAG14} already initialized`);
5145
5219
  return;
5146
5220
  }
5147
5221
  configDir = opts.configDir;
@@ -5149,20 +5223,20 @@ async function init(opts) {
5149
5223
  loadConfig(opts.accountConfig);
5150
5224
  const accountIds = listCredentialAccountIds(configDir);
5151
5225
  if (accountIds.length === 0) {
5152
- console.error(`${TAG13} init: no stored WhatsApp credentials found`);
5226
+ console.error(`${TAG14} init: no stored WhatsApp credentials found`);
5153
5227
  initialized = true;
5154
5228
  return;
5155
5229
  }
5156
- console.error(`${TAG13} init: found ${accountIds.length} credentialed account(s): ${accountIds.join(", ")}`);
5230
+ console.error(`${TAG14} init: found ${accountIds.length} credentialed account(s): ${accountIds.join(", ")}`);
5157
5231
  initialized = true;
5158
5232
  for (const accountId of accountIds) {
5159
5233
  const accountCfg = whatsAppConfig.accounts?.[accountId];
5160
5234
  if (accountCfg?.enabled === false) {
5161
- console.error(`${TAG13} skipping disabled account=${accountId}`);
5235
+ console.error(`${TAG14} skipping disabled account=${accountId}`);
5162
5236
  continue;
5163
5237
  }
5164
5238
  startConnection(accountId).catch((err) => {
5165
- console.error(`${TAG13} failed to auto-start account=${accountId}: ${formatError(err)}`);
5239
+ console.error(`${TAG14} failed to auto-start account=${accountId}: ${formatError(err)}`);
5166
5240
  });
5167
5241
  }
5168
5242
  }
@@ -5171,7 +5245,7 @@ async function startConnection(accountId) {
5171
5245
  const authDir = resolveAuthDir(configDir, accountId);
5172
5246
  const hasAuth = await authExists(authDir);
5173
5247
  if (!hasAuth) {
5174
- console.error(`${TAG13} no credentials for account=${accountId}`);
5248
+ console.error(`${TAG14} no credentials for account=${accountId}`);
5175
5249
  return;
5176
5250
  }
5177
5251
  let platformAccountId;
@@ -5222,11 +5296,11 @@ async function stopConnection(accountId) {
5222
5296
  conn.sock.ev.removeAllListeners("creds.update");
5223
5297
  conn.sock.ws?.close?.();
5224
5298
  } catch (err) {
5225
- console.warn(`${TAG13} socket cleanup error during stop account=${accountId}: ${String(err)}`);
5299
+ console.warn(`${TAG14} socket cleanup error during stop account=${accountId}: ${String(err)}`);
5226
5300
  }
5227
5301
  }
5228
5302
  connections.delete(accountId);
5229
- console.error(`${TAG13} stopped account=${accountId}`);
5303
+ console.error(`${TAG14} stopped account=${accountId}`);
5230
5304
  }
5231
5305
  function getStatus() {
5232
5306
  return Array.from(connections.values()).map((conn) => ({
@@ -5305,9 +5379,9 @@ async function registerLoginSocket(accountId, sock, authDir) {
5305
5379
  monitorInbound(conn);
5306
5380
  try {
5307
5381
  await sock.sendPresenceUpdate("available");
5308
- console.error(`${TAG13} presence set to available account=${accountId}`);
5382
+ console.error(`${TAG14} presence set to available account=${accountId}`);
5309
5383
  } catch (err) {
5310
- console.error(`${TAG13} presence update failed account=${accountId}: ${String(err)}`);
5384
+ console.error(`${TAG14} presence update failed account=${accountId}: ${String(err)}`);
5311
5385
  }
5312
5386
  await runInitQueries(sock, {
5313
5387
  accountId,
@@ -5318,7 +5392,7 @@ async function registerLoginSocket(accountId, sock, authDir) {
5318
5392
  });
5319
5393
  watchForDisconnect(conn);
5320
5394
  attachSelfIdRefreshOnCredsUpdate(conn);
5321
- console.error(`${TAG13} registered login socket for account=${accountId} phone=${conn.selfPhone ?? "unknown"}`);
5395
+ console.error(`${TAG14} registered login socket for account=${accountId} phone=${conn.selfPhone ?? "unknown"}`);
5322
5396
  }
5323
5397
  function attachSelfIdRefreshOnCredsUpdate(conn) {
5324
5398
  if (!conn.sock) return;
@@ -5363,7 +5437,7 @@ async function shutdown() {
5363
5437
  const ids = Array.from(connections.keys());
5364
5438
  await Promise.all(ids.map((id) => stopConnection(id)));
5365
5439
  initialized = false;
5366
- console.error(`${TAG13} shutdown complete`);
5440
+ console.error(`${TAG14} shutdown complete`);
5367
5441
  }
5368
5442
  function loadConfig(accountConfig) {
5369
5443
  try {
@@ -5374,19 +5448,19 @@ function loadConfig(accountConfig) {
5374
5448
  if (result.ok) {
5375
5449
  whatsAppConfig = result.data;
5376
5450
  if (result.droppedKeys.length > 0) {
5377
- console.error(`${TAG13} config: dropped unknown keys=[${result.droppedKeys.join(",")}] preserved known config`);
5451
+ console.error(`${TAG14} config: dropped unknown keys=[${result.droppedKeys.join(",")}] preserved known config`);
5378
5452
  }
5379
5453
  } else {
5380
- console.error(`${TAG13} config validation failed: ${result.error.message}`);
5454
+ console.error(`${TAG14} config validation failed: ${result.error.message}`);
5381
5455
  whatsAppConfig = {};
5382
5456
  }
5383
5457
  const diskAdmin = Array.isArray(wa.adminPhones) ? wa.adminPhones : [];
5384
5458
  if (diskAdmin.length > 0 && (whatsAppConfig.adminPhones?.length ?? 0) === 0) {
5385
- console.error(`${TAG13} WARN adminPhones present on disk but empty after load`);
5459
+ console.error(`${TAG14} WARN adminPhones present on disk but empty after load`);
5386
5460
  }
5387
5461
  }
5388
5462
  } catch (err) {
5389
- console.error(`${TAG13} config load error: ${String(err)}`);
5463
+ console.error(`${TAG14} config load error: ${String(err)}`);
5390
5464
  whatsAppConfig = {};
5391
5465
  }
5392
5466
  }
@@ -5397,7 +5471,7 @@ async function connectWithReconnect(conn) {
5397
5471
  let cycleError = null;
5398
5472
  let connectedAt;
5399
5473
  try {
5400
- console.error(`${TAG13} connecting account=${conn.accountId} attempt=${conn.reconnectAttempts}`);
5474
+ console.error(`${TAG14} connecting account=${conn.accountId} attempt=${conn.reconnectAttempts}`);
5401
5475
  if (conn.debouncer) {
5402
5476
  await conn.debouncer.destroy();
5403
5477
  conn.debouncer = null;
@@ -5410,7 +5484,7 @@ async function connectWithReconnect(conn) {
5410
5484
  conn.sock = sock;
5411
5485
  applySelfIdentity(conn, sock, "pre-listener");
5412
5486
  monitorInbound(conn);
5413
- console.error(`${TAG13} socket created account=${conn.accountId} \u2014 waiting for connection`);
5487
+ console.error(`${TAG14} socket created account=${conn.accountId} \u2014 waiting for connection`);
5414
5488
  await waitForConnection(sock);
5415
5489
  connectedAt = Date.now();
5416
5490
  conn.connected = true;
@@ -5418,12 +5492,12 @@ async function connectWithReconnect(conn) {
5418
5492
  conn.lastError = void 0;
5419
5493
  conn.terminalReason = void 0;
5420
5494
  applySelfIdentity(conn, sock, "post-connect");
5421
- console.error(`${TAG13} connected account=${conn.accountId} phone=${conn.selfPhone ?? "unknown"}`);
5495
+ console.error(`${TAG14} connected account=${conn.accountId} phone=${conn.selfPhone ?? "unknown"}`);
5422
5496
  try {
5423
5497
  await sock.sendPresenceUpdate("available");
5424
- console.error(`${TAG13} presence set to available account=${conn.accountId}`);
5498
+ console.error(`${TAG14} presence set to available account=${conn.accountId}`);
5425
5499
  } catch (err) {
5426
- console.error(`${TAG13} presence update failed account=${conn.accountId}: ${String(err)}`);
5500
+ console.error(`${TAG14} presence update failed account=${conn.accountId}: ${String(err)}`);
5427
5501
  }
5428
5502
  await runInitQueries(sock, {
5429
5503
  accountId: conn.accountId,
@@ -5446,10 +5520,10 @@ async function connectWithReconnect(conn) {
5446
5520
  }
5447
5521
  const classification = classifyDisconnect(err);
5448
5522
  conn.lastError = classification.message;
5449
- console.error(`${TAG13} disconnect account=${conn.accountId}: ${classification.kind} \u2014 ${classification.message}`);
5523
+ console.error(`${TAG14} disconnect account=${conn.accountId}: ${classification.kind} \u2014 ${classification.message}`);
5450
5524
  if (!classification.shouldRetry) {
5451
5525
  conn.terminalReason = classification.message;
5452
- console.error(`${TAG13} terminal disconnect for account=${conn.accountId}, stopping reconnection`);
5526
+ console.error(`${TAG14} terminal disconnect for account=${conn.accountId}, stopping reconnection`);
5453
5527
  return;
5454
5528
  }
5455
5529
  }
@@ -5462,7 +5536,7 @@ async function connectWithReconnect(conn) {
5462
5536
  if (decision.action === "abort") {
5463
5537
  const stuckReason = `GIVING UP account=${conn.accountId} attempts=${decision.finalAttempts}/${maxAttempts} uptimeMsLast=${uptimeMs} stableThresholdMs=${STABLE_UPTIME_MS} lastError=${conn.lastError ?? "(none)"}`;
5464
5538
  console.error(
5465
- `${TAG13} ${stuckReason} \u2014 re-pair via QR or restart required; WhatsApp will not reconnect automatically`
5539
+ `${TAG14} ${stuckReason} \u2014 re-pair via QR or restart required; WhatsApp will not reconnect automatically`
5466
5540
  );
5467
5541
  conn.sessionStuckReason = stuckReason;
5468
5542
  conn.lastError = stuckReason;
@@ -5471,17 +5545,17 @@ async function connectWithReconnect(conn) {
5471
5545
  conn.reconnectAttempts = decision.nextAttempts;
5472
5546
  if (decision.reason === "short-lived") {
5473
5547
  console.error(
5474
- `${TAG13} short-lived session account=${conn.accountId} uptimeMs=${uptimeMs} attempt=${decision.nextAttempts}/${maxAttempts} lastError=${conn.lastError ?? "(clean disconnect)"}`
5548
+ `${TAG14} short-lived session account=${conn.accountId} uptimeMs=${uptimeMs} attempt=${decision.nextAttempts}/${maxAttempts} lastError=${conn.lastError ?? "(clean disconnect)"}`
5475
5549
  );
5476
5550
  } else {
5477
5551
  console.error(
5478
- `${TAG13} session stable account=${conn.accountId} uptimeMs=${uptimeMs} \u2014 reconnect counter reset`
5552
+ `${TAG14} session stable account=${conn.accountId} uptimeMs=${uptimeMs} \u2014 reconnect counter reset`
5479
5553
  );
5480
5554
  }
5481
5555
  if (decision.reason === "short-lived" || cycleError) {
5482
5556
  const delay = computeBackoff(Math.max(1, decision.nextAttempts));
5483
5557
  console.error(
5484
- `${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
5558
+ `${TAG14} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
5485
5559
  );
5486
5560
  await new Promise((resolve37) => {
5487
5561
  const timer2 = setTimeout(resolve37, delay);
@@ -5515,11 +5589,11 @@ function watchForDisconnect(conn) {
5515
5589
  conn.sock.ev.on("connection.update", (update) => {
5516
5590
  if (update.connection === "close") {
5517
5591
  if (connections.get(conn.accountId) !== conn) return;
5518
- console.error(`${TAG13} socket disconnected for account=${conn.accountId}`);
5592
+ console.error(`${TAG14} socket disconnected for account=${conn.accountId}`);
5519
5593
  conn.connected = false;
5520
5594
  conn.sock = null;
5521
5595
  connectWithReconnect(conn).catch((err) => {
5522
- console.error(`${TAG13} reconnection failed for account=${conn.accountId}: ${formatError(err)}`);
5596
+ console.error(`${TAG14} reconnection failed for account=${conn.accountId}: ${formatError(err)}`);
5523
5597
  });
5524
5598
  }
5525
5599
  });
@@ -5545,7 +5619,7 @@ function monitorInbound(conn) {
5545
5619
  if (!conn.sock || !onInboundMessage) return;
5546
5620
  const sock = conn.sock;
5547
5621
  const debounceMs = whatsAppConfig.accounts?.[conn.accountId]?.debounceMs ?? whatsAppConfig.debounceMs ?? 0;
5548
- console.error(`${TAG13} monitorInbound started account=${conn.accountId} debounceMs=${debounceMs}`);
5622
+ console.error(`${TAG14} monitorInbound started account=${conn.accountId} debounceMs=${debounceMs}`);
5549
5623
  conn.debouncer = createInboundDebouncer({
5550
5624
  debounceMs,
5551
5625
  buildKey: (payload) => {
@@ -5555,12 +5629,12 @@ function monitorInbound(conn) {
5555
5629
  onFlush: (entries) => {
5556
5630
  if (!onInboundMessage) return;
5557
5631
  if (entries.length > 1) {
5558
- console.error(`${TAG13} debounce: combining ${entries.length} messages account=${conn.accountId} from=${entries[0].senderPhone}`);
5632
+ console.error(`${TAG14} debounce: combining ${entries.length} messages account=${conn.accountId} from=${entries[0].senderPhone}`);
5559
5633
  }
5560
5634
  onInboundMessage(combineInboundBatch(entries));
5561
5635
  },
5562
5636
  onError: (err) => {
5563
- console.error(`${TAG13} debounce flush error account=${conn.accountId}: ${String(err)}`);
5637
+ console.error(`${TAG14} debounce flush error account=${conn.accountId}: ${String(err)}`);
5564
5638
  }
5565
5639
  });
5566
5640
  sock.ev.on("messages.upsert", async (upsert) => {
@@ -5592,7 +5666,7 @@ function monitorInbound(conn) {
5592
5666
  }
5593
5667
  const entries = messageStore.get(storeKey);
5594
5668
  console.error(
5595
- `${TAG13} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries?.length ?? 0}/${MESSAGE_STORE_MAX}) account=${conn.platformAccountId}`
5669
+ `${TAG14} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries?.length ?? 0}/${MESSAGE_STORE_MAX}) account=${conn.platformAccountId}`
5596
5670
  );
5597
5671
  recordActivity({
5598
5672
  accountId: conn.accountId,
@@ -5638,11 +5712,14 @@ function monitorInbound(conn) {
5638
5712
  const wantsServableMedia = mediaServable && !!conn.sock && (!fromMe || !alreadyRecorded);
5639
5713
  if (fromMe && mediaServable && !!conn.sock) {
5640
5714
  console.error(
5641
- `${TAG13} fromMe-media-echo msgKey=${msg.key.id} decision=${alreadyRecorded ? "skip" : "store"} reason=${alreadyRecorded ? "already-recorded" : "no-prior-record"}`
5715
+ `${TAG14} fromMe-media-echo msgKey=${msg.key.id} decision=${alreadyRecorded ? "skip" : "store"} reason=${alreadyRecorded ? "already-recorded" : "no-prior-record"}`
5642
5716
  );
5643
5717
  }
5644
5718
  const mediaSeed = `whatsapp-live:${conn.accountId}:${canonicalRemoteJid}:${msg.key.id}`;
5645
- const maxBytes = (whatsAppConfig.mediaMaxMb ?? 50) * 1024 * 1024;
5719
+ const maxBytes = echoStoreMaxBytes({
5720
+ fromMe,
5721
+ mediaMaxMb: whatsAppConfig.mediaMaxMb
5722
+ });
5646
5723
  const basePersist = {
5647
5724
  accountId: conn.accountId,
5648
5725
  platformAccountId: conn.platformAccountId,
@@ -5687,7 +5764,7 @@ function monitorInbound(conn) {
5687
5764
  receiptDeferredToWorker = true;
5688
5765
  if (!accepted) {
5689
5766
  console.error(
5690
- `${TAG13} append-media overflow account=${conn.platformAccountId} msgKey=${msgKeyId ?? "?"} \u2014 pending cap ${APPEND_MEDIA_MAX_PENDING} reached, text-fallback persist, inline media shed`
5767
+ `${TAG14} append-media overflow account=${conn.platformAccountId} msgKey=${msgKeyId ?? "?"} \u2014 pending cap ${APPEND_MEDIA_MAX_PENDING} reached, text-fallback persist, inline media shed`
5691
5768
  );
5692
5769
  const persisted = await persistWhatsAppMessage({
5693
5770
  ...basePersist,
@@ -5761,13 +5838,13 @@ function monitorInbound(conn) {
5761
5838
  const skippedSenderJid = isGroupJid(remoteJid) ? msg.key.participant ?? remoteJid : remoteJid;
5762
5839
  const skippedSenderPhone = await resolveJidToE164(skippedSenderJid, conn.lidMapping) ?? skippedSenderJid;
5763
5840
  console.error(
5764
- `${TAG13} append-type message ${msg.key.id ?? "?"} dispatch skipped from=${skippedSenderPhone}${msg.pushName ? ` name=${msg.pushName}` : ""} account=${conn.accountId} (persistence not confirmed here)`
5841
+ `${TAG14} append-type message ${msg.key.id ?? "?"} dispatch skipped from=${skippedSenderPhone}${msg.pushName ? ` name=${msg.pushName}` : ""} account=${conn.accountId} (persistence not confirmed here)`
5765
5842
  );
5766
5843
  continue;
5767
5844
  }
5768
5845
  await handleInboundMessage(conn, msg);
5769
5846
  } catch (err) {
5770
- console.error(`${TAG13} inbound handler error account=${conn.accountId}: ${String(err)}`);
5847
+ console.error(`${TAG14} inbound handler error account=${conn.accountId}: ${String(err)}`);
5771
5848
  }
5772
5849
  }
5773
5850
  });
@@ -5823,31 +5900,31 @@ async function handleInboundMessage(conn, msg) {
5823
5900
  const remoteJid = msg.key.remoteJid;
5824
5901
  if (!remoteJid) return;
5825
5902
  if (remoteJid === "status@broadcast") {
5826
- console.error(`${TAG13} drop: status broadcast account=${conn.accountId}`);
5903
+ console.error(`${TAG14} drop: status broadcast account=${conn.accountId}`);
5827
5904
  return;
5828
5905
  }
5829
5906
  if (!msg.message) {
5830
- console.error(`${TAG13} drop: empty message account=${conn.accountId} from=${remoteJid}`);
5907
+ console.error(`${TAG14} drop: empty message account=${conn.accountId} from=${remoteJid}`);
5831
5908
  return;
5832
5909
  }
5833
5910
  const dedupKey = `${conn.accountId}:${remoteJid}:${msg.key.id}`;
5834
5911
  if (isDuplicateInbound(dedupKey)) {
5835
- console.error(`${TAG13} drop: duplicate account=${conn.accountId} key=${dedupKey}`);
5912
+ console.error(`${TAG14} drop: duplicate account=${conn.accountId} key=${dedupKey}`);
5836
5913
  return;
5837
5914
  }
5838
5915
  if (msg.key.fromMe) {
5839
5916
  if (msg.key.id && isAgentSentMessage(msg.key.id)) {
5840
- console.error(`${TAG13} drop: echo suppression account=${conn.accountId} msgId=${msg.key.id}`);
5917
+ console.error(`${TAG14} drop: echo suppression account=${conn.accountId} msgId=${msg.key.id}`);
5841
5918
  return;
5842
5919
  }
5843
5920
  const extracted2 = extractMessage(msg);
5844
5921
  if (!extracted2.text) {
5845
- console.error(`${TAG13} owner reply skipped \u2014 no text content account=${conn.accountId}`);
5922
+ console.error(`${TAG14} owner reply skipped \u2014 no text content account=${conn.accountId}`);
5846
5923
  return;
5847
5924
  }
5848
5925
  const isGroup2 = isGroupJid(remoteJid);
5849
5926
  const senderPhone2 = conn.selfPhone ?? "owner";
5850
- console.error(`${TAG13} owner reply mirrored to session from=${senderPhone2} account=${conn.accountId}`);
5927
+ console.error(`${TAG14} owner reply mirrored to session from=${senderPhone2} account=${conn.accountId}`);
5851
5928
  const reply2 = async (text) => {
5852
5929
  const currentSock = conn.sock;
5853
5930
  if (!currentSock) throw new Error("WhatsApp disconnected \u2014 cannot reply");
@@ -5881,7 +5958,7 @@ async function handleInboundMessage(conn, msg) {
5881
5958
  }
5882
5959
  const extracted = extractMessage(msg);
5883
5960
  if (!extracted.text && !extracted.mediaType) {
5884
- console.error(`${TAG13} drop: no text or media account=${conn.accountId} from=${remoteJid}`);
5961
+ console.error(`${TAG14} drop: no text or media account=${conn.accountId} from=${remoteJid}`);
5885
5962
  return;
5886
5963
  }
5887
5964
  let mediaResult;
@@ -5891,7 +5968,7 @@ async function handleInboundMessage(conn, msg) {
5891
5968
  maxBytes: maxMb * 1024 * 1024
5892
5969
  });
5893
5970
  if (!mediaResult) {
5894
- console.error(`${TAG13} media download returned undefined account=${conn.accountId} type=${extracted.mediaType} from=${remoteJid}`);
5971
+ console.error(`${TAG14} media download returned undefined account=${conn.accountId} type=${extracted.mediaType} from=${remoteJid}`);
5895
5972
  }
5896
5973
  }
5897
5974
  const isGroup = isGroupJid(remoteJid);
@@ -5932,7 +6009,7 @@ async function handleInboundMessage(conn, msg) {
5932
6009
  });
5933
6010
  }
5934
6011
  console.error(
5935
- `${TAG13} inbound account=${conn.accountId} from=${senderPhone} group=${isGroup} access=${accessResult.allowed ? "allowed" : "blocked"}(${accessResult.reason}) agent=${accessResult.agentType}` + (extracted.mediaType ? ` media=${extracted.mediaType}` : "") + (mediaResult ? ` mediaPath=${mediaResult.path}` : "") + (extracted.quotedMessage ? ` replyTo=${extracted.quotedMessage.id}` : "")
6012
+ `${TAG14} inbound account=${conn.accountId} from=${senderPhone} group=${isGroup} access=${accessResult.allowed ? "allowed" : "blocked"}(${accessResult.reason}) agent=${accessResult.agentType}` + (extracted.mediaType ? ` media=${extracted.mediaType}` : "") + (mediaResult ? ` mediaPath=${mediaResult.path}` : "") + (extracted.quotedMessage ? ` replyTo=${extracted.quotedMessage.id}` : "")
5936
6013
  );
5937
6014
  if (!accessResult.allowed && accessResult.reason === "account-manager-unresolved") {
5938
6015
  console.error(
@@ -5958,7 +6035,7 @@ async function handleInboundMessage(conn, msg) {
5958
6035
  }
5959
6036
  const reply = async (text) => {
5960
6037
  if (isGroupJid(remoteJid)) {
5961
- console.error(`${TAG13} op=group-reply-blocked jid=${remoteJid}`);
6038
+ console.error(`${TAG14} op=group-reply-blocked jid=${remoteJid}`);
5962
6039
  throw new WaReplyError("group reply blocked \u2014 observe-only", false);
5963
6040
  }
5964
6041
  const currentSock = conn.sock;
@@ -6005,15 +6082,15 @@ async function handleInboundMessage(conn, msg) {
6005
6082
  if (accessResult.agentType === "public") {
6006
6083
  const hoursResult = await isBusinessOpen(conn.accountId);
6007
6084
  if (!hoursResult.open) {
6008
- console.error(`${TAG13} [${conn.accountId}] dispatch skipped: business closed`);
6085
+ console.error(`${TAG14} [${conn.accountId}] dispatch skipped: business closed`);
6009
6086
  const afterHoursMessage = whatsAppConfig.accounts?.[conn.accountId]?.afterHoursMessage ?? whatsAppConfig.afterHoursMessage;
6010
6087
  if (afterHoursMessage) {
6011
6088
  try {
6012
6089
  await reply(afterHoursMessage);
6013
- console.error(`${TAG13} [${conn.accountId}] after-hours auto-reply sent to ${remoteJid}`);
6090
+ console.error(`${TAG14} [${conn.accountId}] after-hours auto-reply sent to ${remoteJid}`);
6014
6091
  } catch (err) {
6015
6092
  console.error(
6016
- `${TAG13} [${conn.accountId}] after-hours auto-reply failed: ${err instanceof Error ? err.message : String(err)}`
6093
+ `${TAG14} [${conn.accountId}] after-hours auto-reply failed: ${err instanceof Error ? err.message : String(err)}`
6017
6094
  );
6018
6095
  }
6019
6096
  }
@@ -6458,13 +6535,13 @@ function audioExtension(mimeType) {
6458
6535
  }
6459
6536
 
6460
6537
  // app/lib/stt/voice-note.ts
6461
- var TAG14 = "[voice]";
6538
+ var TAG15 = "[voice]";
6462
6539
  async function transcribeVoiceNote(file, source) {
6463
6540
  const startMs = Date.now();
6464
6541
  const bytes = file.size;
6465
6542
  const mimeType = file.type;
6466
6543
  console.error(
6467
- `${TAG14} recording send source=${source} duration_ms=unknown bytes=${bytes} format=${mimeType}`
6544
+ `${TAG15} recording send source=${source} duration_ms=unknown bytes=${bytes} format=${mimeType}`
6468
6545
  );
6469
6546
  let tempDir;
6470
6547
  let tempPath;
@@ -6476,7 +6553,7 @@ async function transcribeVoiceNote(file, source) {
6476
6553
  await writeFile3(tempPath, buffer);
6477
6554
  } catch (err) {
6478
6555
  const reason = err instanceof Error ? err.message : String(err);
6479
- console.error(`${TAG14} failed source=${source} error=temp-file-write: ${reason}`);
6556
+ console.error(`${TAG15} failed source=${source} error=temp-file-write: ${reason}`);
6480
6557
  return { ok: false, error: "Could not process voice note" };
6481
6558
  }
6482
6559
  try {
@@ -6484,7 +6561,7 @@ async function transcribeVoiceNote(file, source) {
6484
6561
  if (!sttResult) {
6485
6562
  const elapsed2 = Date.now() - startMs;
6486
6563
  console.error(
6487
- `${TAG14} failed source=${source} error=transcription-failed duration_ms=${elapsed2}`
6564
+ `${TAG15} failed source=${source} error=transcription-failed duration_ms=${elapsed2}`
6488
6565
  );
6489
6566
  return { ok: false, error: "Could not transcribe voice note. Please try again or type your message." };
6490
6567
  }
@@ -6492,7 +6569,7 @@ async function transcribeVoiceNote(file, source) {
6492
6569
  const elapsed = Date.now() - startMs;
6493
6570
  const words = rawText.split(/\s+/).filter(Boolean).length;
6494
6571
  console.error(
6495
- `${TAG14} transcribed source=${source} duration_ms=${elapsed} stt_ms=${sttResult.durationMs} words=${words}`
6572
+ `${TAG15} transcribed source=${source} duration_ms=${elapsed} stt_ms=${sttResult.durationMs} words=${words}`
6496
6573
  );
6497
6574
  return {
6498
6575
  ok: true,
@@ -6502,7 +6579,7 @@ async function transcribeVoiceNote(file, source) {
6502
6579
  const elapsed = Date.now() - startMs;
6503
6580
  const reason = err instanceof Error ? err.message : String(err);
6504
6581
  console.error(
6505
- `${TAG14} failed source=${source} error=${reason} duration_ms=${elapsed}`
6582
+ `${TAG15} failed source=${source} error=${reason} duration_ms=${elapsed}`
6506
6583
  );
6507
6584
  return { ok: false, error: "Voice note transcription failed. Please try again or type your message." };
6508
6585
  } finally {
@@ -6549,7 +6626,7 @@ function composePublicSessionTitle(input) {
6549
6626
  }
6550
6627
 
6551
6628
  // app/lib/webchat/persist-customer-inbound.ts
6552
- var TAG15 = "[channel-house]";
6629
+ var TAG16 = "[channel-house]";
6553
6630
  async function persistCustomerWebchatInbound(input) {
6554
6631
  if (!input.text) return null;
6555
6632
  try {
@@ -6565,7 +6642,7 @@ async function persistCustomerWebchatInbound(input) {
6565
6642
  );
6566
6643
  if (!conv.sessionId) {
6567
6644
  console.error(
6568
- `${TAG15} op=persist-skip reason=conversation-merge-failed accountId=${input.houseAccountId} key=${input.sessionKey}`
6645
+ `${TAG16} op=persist-skip reason=conversation-merge-failed accountId=${input.houseAccountId} key=${input.sessionKey}`
6569
6646
  );
6570
6647
  return null;
6571
6648
  }
@@ -6577,17 +6654,17 @@ async function persistCustomerWebchatInbound(input) {
6577
6654
  );
6578
6655
  if (!messageId) {
6579
6656
  console.error(
6580
- `${TAG15} op=persist-skip reason=message-write-failed accountId=${input.houseAccountId} sessionId=${conv.sessionId.slice(0, 8)}`
6657
+ `${TAG16} op=persist-skip reason=message-write-failed accountId=${input.houseAccountId} sessionId=${conv.sessionId.slice(0, 8)}`
6581
6658
  );
6582
6659
  return null;
6583
6660
  }
6584
6661
  console.error(
6585
- `${TAG15} op=persist accountId=${input.houseAccountId} sessionId=${conv.sessionId.slice(0, 8)} messageId=${messageId.slice(0, 8)} bytes=${Buffer.byteLength(input.text, "utf8")}`
6662
+ `${TAG16} op=persist accountId=${input.houseAccountId} sessionId=${conv.sessionId.slice(0, 8)} messageId=${messageId.slice(0, 8)} bytes=${Buffer.byteLength(input.text, "utf8")}`
6586
6663
  );
6587
6664
  return { sessionId: conv.sessionId, messageId };
6588
6665
  } catch (err) {
6589
6666
  console.error(
6590
- `${TAG15} op=persist-fail accountId=${input.houseAccountId} key=${input.sessionKey} reason=${err instanceof Error ? err.message : String(err)}`
6667
+ `${TAG16} op=persist-fail accountId=${input.houseAccountId} key=${input.sessionKey} reason=${err instanceof Error ? err.message : String(err)}`
6591
6668
  );
6592
6669
  return null;
6593
6670
  }
@@ -6895,7 +6972,7 @@ function parseScheduleProvenance(v) {
6895
6972
  }
6896
6973
 
6897
6974
  // server/routes/channel/schedule-inject.ts
6898
- var TAG16 = "[schedule-inject]";
6975
+ var TAG17 = "[schedule-inject]";
6899
6976
  function isLoopbackAddr(addr) {
6900
6977
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
6901
6978
  }
@@ -6905,7 +6982,7 @@ function createScheduleInjectRoutes(deps) {
6905
6982
  const env = c.env;
6906
6983
  const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
6907
6984
  if (!isLoopbackAddr(remoteAddr)) {
6908
- console.error(`${TAG16} reject reason=non-loopback remoteAddr=${remoteAddr}`);
6985
+ console.error(`${TAG17} reject reason=non-loopback remoteAddr=${remoteAddr}`);
6909
6986
  return c.json({ ok: false, error: "schedule-inject-loopback-only" }, 403);
6910
6987
  }
6911
6988
  const xffHeader = env?.incoming?.headers?.["x-forwarded-for"];
@@ -6913,7 +6990,7 @@ function createScheduleInjectRoutes(deps) {
6913
6990
  if (xffRaw.length > 0) {
6914
6991
  const offender = xffRaw.split(",").map((t) => t.trim()).filter(Boolean).find((t) => !isLoopbackAddr(t));
6915
6992
  if (offender !== void 0) {
6916
- console.error(`${TAG16} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
6993
+ console.error(`${TAG17} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
6917
6994
  return c.json({ ok: false, error: "schedule-inject-loopback-only" }, 403);
6918
6995
  }
6919
6996
  }
@@ -6929,23 +7006,23 @@ function createScheduleInjectRoutes(deps) {
6929
7006
  const eventId = typeof body.eventId === "string" ? body.eventId : "";
6930
7007
  const scheduleProvenance = parseScheduleProvenance(body.scheduleProvenance);
6931
7008
  if (channel !== "whatsapp" && channel !== "telegram" || !destination || !prompt) {
6932
- console.error(`${TAG16} reject reason=bad-request channel=${String(channel)} hasDestination=${Boolean(destination)} hasPrompt=${Boolean(prompt)}`);
7009
+ console.error(`${TAG17} reject reason=bad-request channel=${String(channel)} hasDestination=${Boolean(destination)} hasPrompt=${Boolean(prompt)}`);
6933
7010
  return c.json({ ok: false, error: "schedule-inject-bad-request" }, 400);
6934
7011
  }
6935
7012
  const account = deps.resolveAccount();
6936
7013
  if (!account) {
6937
- console.error(`${TAG16} reject reason=no-account eventId=${eventId}`);
7014
+ console.error(`${TAG17} reject reason=no-account eventId=${eventId}`);
6938
7015
  return c.json({ ok: false, error: "no-account" }, 500);
6939
7016
  }
6940
7017
  const houseAccountId = account.accountId;
6941
- console.error(`${TAG16} op=received eventId=${eventId} channel=${channel} destination=${destination} account=${houseAccountId}`);
7018
+ console.error(`${TAG17} op=received eventId=${eventId} channel=${channel} destination=${destination} account=${houseAccountId}`);
6942
7019
  if (channel === "whatsapp") {
6943
7020
  const effectiveAccount2 = deps.effectiveAccountFor(houseAccountId, account.accountDir, destination);
6944
7021
  if (effectiveAccount2 === null) {
6945
- console.error(`${TAG16} op=schedule-account-manager-reject eventId=${eventId} destination=${destination} reason=unresolved-effective-account`);
7022
+ console.error(`${TAG17} op=schedule-account-manager-reject eventId=${eventId} destination=${destination} reason=unresolved-effective-account`);
6946
7023
  return c.json({ ok: false, error: "account-manager-unresolved" }, 403);
6947
7024
  }
6948
- console.error(`${TAG16} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount2}`);
7025
+ console.error(`${TAG17} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount2}`);
6949
7026
  const sessionId2 = adminSessionIdFor(effectiveAccount2, normalizeTarget(destination) ?? destination);
6950
7027
  const reply2 = (text) => deps.sendWhatsAppText(houseAccountId, destination, text);
6951
7028
  try {
@@ -6967,17 +7044,17 @@ function createScheduleInjectRoutes(deps) {
6967
7044
  reply: reply2
6968
7045
  });
6969
7046
  } catch (err) {
6970
- console.error(`${TAG16} op=inject-spawn eventId=${eventId} sessionId=${sessionId2} result=inject-error status=${err instanceof Error ? err.message : String(err)}`);
7047
+ console.error(`${TAG17} op=inject-spawn eventId=${eventId} sessionId=${sessionId2} result=inject-error status=${err instanceof Error ? err.message : String(err)}`);
6971
7048
  return c.json({ ok: false, error: "inject-error" }, 502);
6972
7049
  }
6973
- console.error(`${TAG16} op=inject-spawn eventId=${eventId} sessionId=${sessionId2} result=ok status=-`);
7050
+ console.error(`${TAG17} op=inject-spawn eventId=${eventId} sessionId=${sessionId2} result=ok status=-`);
6974
7051
  return c.json({ ok: true }, 200);
6975
7052
  }
6976
7053
  const effectiveAccount = houseAccountId;
6977
- console.error(`${TAG16} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount}`);
7054
+ console.error(`${TAG17} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount}`);
6978
7055
  const botToken = account.config.telegram?.adminBotToken;
6979
7056
  if (!botToken) {
6980
- console.error(`${TAG16} reject reason=no-admin-bot-token eventId=${eventId}`);
7057
+ console.error(`${TAG17} reject reason=no-admin-bot-token eventId=${eventId}`);
6981
7058
  return c.json({ ok: false, error: "no-admin-bot-token" }, 400);
6982
7059
  }
6983
7060
  const chatId = Number(destination);
@@ -6996,10 +7073,10 @@ function createScheduleInjectRoutes(deps) {
6996
7073
  reply
6997
7074
  });
6998
7075
  } catch (err) {
6999
- console.error(`${TAG16} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=inject-error status=${err instanceof Error ? err.message : String(err)}`);
7076
+ console.error(`${TAG17} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=inject-error status=${err instanceof Error ? err.message : String(err)}`);
7000
7077
  return c.json({ ok: false, error: "inject-error" }, 502);
7001
7078
  }
7002
- console.error(`${TAG16} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
7079
+ console.error(`${TAG17} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
7003
7080
  return c.json({ ok: true }, 200);
7004
7081
  });
7005
7082
  return app63;
@@ -7033,26 +7110,26 @@ import { randomUUID as randomUUID6 } from "crypto";
7033
7110
  // app/lib/whatsapp/config-persist.ts
7034
7111
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync4, existsSync as existsSync6 } from "fs";
7035
7112
  import { resolve as resolve8, join as join8, dirname as dirname2, basename as basename2 } from "path";
7036
- var TAG17 = "[whatsapp:config]";
7113
+ var TAG18 = "[whatsapp:config]";
7037
7114
  function configPath(accountDir) {
7038
7115
  return resolve8(accountDir, "account.json");
7039
7116
  }
7040
7117
  function readConfig(accountDir) {
7041
- const path2 = configPath(accountDir);
7042
- if (!existsSync6(path2)) throw new Error(`account.json not found at ${path2}`);
7043
- return JSON.parse(readFileSync11(path2, "utf-8"));
7118
+ const path3 = configPath(accountDir);
7119
+ if (!existsSync6(path3)) throw new Error(`account.json not found at ${path3}`);
7120
+ return JSON.parse(readFileSync11(path3, "utf-8"));
7044
7121
  }
7045
7122
  function writeConfig(accountDir, config) {
7046
- const path2 = configPath(accountDir);
7047
- writeFileSync4(path2, JSON.stringify(config, null, 2) + "\n", "utf-8");
7123
+ const path3 = configPath(accountDir);
7124
+ writeFileSync4(path3, JSON.stringify(config, null, 2) + "\n", "utf-8");
7048
7125
  }
7049
7126
  function reloadManagerConfig(accountDir) {
7050
7127
  try {
7051
7128
  const config = readConfig(accountDir);
7052
7129
  reloadConfig(config);
7053
- console.error(`${TAG17} reloaded manager config`);
7130
+ console.error(`${TAG18} reloaded manager config`);
7054
7131
  } catch (err) {
7055
- console.error(`${TAG17} manager config reload failed: ${String(err)}`);
7132
+ console.error(`${TAG18} manager config reload failed: ${String(err)}`);
7056
7133
  }
7057
7134
  }
7058
7135
  var E164_PATTERN = /^\+\d{7,15}$/;
@@ -7078,25 +7155,25 @@ function persistAfterPairing(accountDir, accountId, selfPhone) {
7078
7155
  const adminPhones = wa.adminPhones;
7079
7156
  if (!adminPhones.includes(normalized)) {
7080
7157
  adminPhones.push(normalized);
7081
- console.error(`${TAG17} added selfPhone=${normalized} to adminPhones`);
7158
+ console.error(`${TAG18} added selfPhone=${normalized} to adminPhones`);
7082
7159
  }
7083
7160
  } else {
7084
- console.error(`${TAG17} skipping adminPhones \u2014 selfPhone is null account=${accountId}`);
7161
+ console.error(`${TAG18} skipping adminPhones \u2014 selfPhone is null account=${accountId}`);
7085
7162
  }
7086
7163
  const parsed = WhatsAppConfigSchema.safeParse(wa);
7087
7164
  if (!parsed.success) {
7088
7165
  const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
7089
- console.error(`${TAG17} validation failed after pairing: ${msg}`);
7166
+ console.error(`${TAG18} validation failed after pairing: ${msg}`);
7090
7167
  return { ok: false, error: `Validation failed: ${msg}` };
7091
7168
  }
7092
7169
  config.whatsapp = parsed.data;
7093
7170
  writeConfig(accountDir, config);
7094
- console.error(`${TAG17} persisted after pairing account=${accountId} phone=${selfPhone ?? "null"}`);
7171
+ console.error(`${TAG18} persisted after pairing account=${accountId} phone=${selfPhone ?? "null"}`);
7095
7172
  reloadManagerConfig(accountDir);
7096
7173
  return { ok: true };
7097
7174
  } catch (err) {
7098
7175
  const msg = err instanceof Error ? err.message : String(err);
7099
- console.error(`${TAG17} persist failed account=${accountId}: ${msg}`);
7176
+ console.error(`${TAG18} persist failed account=${accountId}: ${msg}`);
7100
7177
  return { ok: false, error: msg };
7101
7178
  }
7102
7179
  }
@@ -7110,7 +7187,7 @@ function addAdminPhone(accountDir, phone) {
7110
7187
  const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename2(resolve8(accountDir));
7111
7188
  const socketOwner = resolveHouseOrSoleAccountId(dirname2(resolve8(accountDir)));
7112
7189
  if (targetId !== socketOwner) {
7113
- console.error(`${TAG17} add-admin-phone rejected accountId=${targetId} reason=not-socket-account`);
7190
+ console.error(`${TAG18} add-admin-phone rejected accountId=${targetId} reason=not-socket-account`);
7114
7191
  return {
7115
7192
  ok: false,
7116
7193
  reason: "not-socket-account",
@@ -7139,12 +7216,12 @@ function addAdminPhone(accountDir, phone) {
7139
7216
  }
7140
7217
  config.whatsapp = parsed.data;
7141
7218
  writeConfig(accountDir, config);
7142
- console.error(`${TAG17} added admin phone=${normalized}`);
7219
+ console.error(`${TAG18} added admin phone=${normalized}`);
7143
7220
  reloadManagerConfig(accountDir);
7144
7221
  return { ok: true, message: `Added ${normalized} as admin phone. Messages from this number will route to the admin agent.` };
7145
7222
  } catch (err) {
7146
7223
  const msg = err instanceof Error ? err.message : String(err);
7147
- console.error(`${TAG17} addAdminPhone failed: ${msg}`);
7224
+ console.error(`${TAG18} addAdminPhone failed: ${msg}`);
7148
7225
  return { ok: false, error: msg };
7149
7226
  }
7150
7227
  }
@@ -7172,12 +7249,12 @@ function removeAdminPhone(accountDir, phone) {
7172
7249
  }
7173
7250
  config.whatsapp = parsed.data;
7174
7251
  writeConfig(accountDir, config);
7175
- console.error(`${TAG17} removed admin phone=${normalized}`);
7252
+ console.error(`${TAG18} removed admin phone=${normalized}`);
7176
7253
  reloadManagerConfig(accountDir);
7177
7254
  return { ok: true, message: `Removed ${normalized} from admin phones. Messages from this number will now route to the public agent.` };
7178
7255
  } catch (err) {
7179
7256
  const msg = err instanceof Error ? err.message : String(err);
7180
- console.error(`${TAG17} removeAdminPhone failed: ${msg}`);
7257
+ console.error(`${TAG18} removeAdminPhone failed: ${msg}`);
7181
7258
  return { ok: false, error: msg };
7182
7259
  }
7183
7260
  }
@@ -7272,13 +7349,13 @@ function setAccountManager(accountDir, phone, subAccountId, mode = "active") {
7272
7349
  }
7273
7350
  config.whatsapp = parsed.data;
7274
7351
  writeConfig(accountDir, config);
7275
- console.error(`${TAG17} bound account manager phone=${normalized} managesAccount=${sub} mode=${mode}`);
7352
+ console.error(`${TAG18} bound account manager phone=${normalized} managesAccount=${sub} mode=${mode}`);
7276
7353
  reloadManagerConfig(accountDir);
7277
7354
  const behaviour = mode === "passive" ? `Their WhatsApp messages will each file one task scoped to that sub-account; the agent sends nothing back.` : `Their WhatsApp messages will reach that sub-account's admin agent; replies still go out over this account's WhatsApp device.`;
7278
7355
  return { ok: true, message: `Bound ${normalized} as ${mode} account manager for sub-account ${sub}. ${behaviour}` };
7279
7356
  } catch (err) {
7280
7357
  const msg = err instanceof Error ? err.message : String(err);
7281
- console.error(`${TAG17} setAccountManager failed: ${msg}`);
7358
+ console.error(`${TAG18} setAccountManager failed: ${msg}`);
7282
7359
  return { ok: false, error: msg };
7283
7360
  }
7284
7361
  }
@@ -7303,12 +7380,12 @@ function clearAccountManager(accountDir, phone) {
7303
7380
  }
7304
7381
  config.whatsapp = parsed.data;
7305
7382
  writeConfig(accountDir, config);
7306
- console.error(`${TAG17} cleared account manager phone=${normalized}`);
7383
+ console.error(`${TAG18} cleared account manager phone=${normalized}`);
7307
7384
  reloadManagerConfig(accountDir);
7308
7385
  return { ok: true, message: `Cleared the account-manager binding for ${normalized}.` };
7309
7386
  } catch (err) {
7310
7387
  const msg = err instanceof Error ? err.message : String(err);
7311
- console.error(`${TAG17} clearAccountManager failed: ${msg}`);
7388
+ console.error(`${TAG18} clearAccountManager failed: ${msg}`);
7312
7389
  return { ok: false, error: msg };
7313
7390
  }
7314
7391
  }
@@ -7355,12 +7432,12 @@ function setPublicAgent(accountDir, slug) {
7355
7432
  }
7356
7433
  config.whatsapp = parsed.data;
7357
7434
  writeConfig(accountDir, config);
7358
- console.error(`${TAG17} publicAgent set to ${trimmed}`);
7435
+ console.error(`${TAG18} publicAgent set to ${trimmed}`);
7359
7436
  reloadManagerConfig(accountDir);
7360
7437
  return { ok: true, message: `Public agent set to "${trimmed}". WhatsApp messages from non-admin phones will be handled by this agent.` };
7361
7438
  } catch (err) {
7362
7439
  const msg = err instanceof Error ? err.message : String(err);
7363
- console.error(`${TAG17} setPublicAgent failed: ${msg}`);
7440
+ console.error(`${TAG18} setPublicAgent failed: ${msg}`);
7364
7441
  return { ok: false, error: msg };
7365
7442
  }
7366
7443
  }
@@ -7401,17 +7478,17 @@ function updateConfig(accountDir, fields) {
7401
7478
  const parsed = WhatsAppConfigSchema.safeParse(wa);
7402
7479
  if (!parsed.success) {
7403
7480
  const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
7404
- console.error(`${TAG17} update validation failed: ${msg}`);
7481
+ console.error(`${TAG18} update validation failed: ${msg}`);
7405
7482
  return { ok: false, error: `Validation failed: ${msg}` };
7406
7483
  }
7407
7484
  config.whatsapp = parsed.data;
7408
7485
  writeConfig(accountDir, config);
7409
- console.error(`${TAG17} updated fields=[${fieldNames.join(",")}]`);
7486
+ console.error(`${TAG18} updated fields=[${fieldNames.join(",")}]`);
7410
7487
  reloadManagerConfig(accountDir);
7411
7488
  return { ok: true, message: `Updated WhatsApp config: ${fieldNames.join(", ")}.` };
7412
7489
  } catch (err) {
7413
7490
  const msg = err instanceof Error ? err.message : String(err);
7414
- console.error(`${TAG17} updateConfig failed: ${msg}`);
7491
+ console.error(`${TAG18} updateConfig failed: ${msg}`);
7415
7492
  return { ok: false, error: msg };
7416
7493
  }
7417
7494
  }
@@ -7448,17 +7525,17 @@ function migrateRemovedConfigKeys(accountDir) {
7448
7525
  }
7449
7526
  writeConfig(accountDir, config);
7450
7527
  console.error(
7451
- `${TAG17} migration: stripped unknown keys=[${result.droppedKeys.join(",")}] from account.json`
7528
+ `${TAG18} migration: stripped unknown keys=[${result.droppedKeys.join(",")}] from account.json`
7452
7529
  );
7453
7530
  return { dropped: result.droppedKeys };
7454
7531
  } catch (err) {
7455
- console.error(`${TAG17} migration failed: ${String(err)}`);
7532
+ console.error(`${TAG18} migration failed: ${String(err)}`);
7456
7533
  return { dropped: [] };
7457
7534
  }
7458
7535
  }
7459
7536
 
7460
7537
  // app/lib/whatsapp/login.ts
7461
- var TAG18 = "[whatsapp:login]";
7538
+ var TAG19 = "[whatsapp:login]";
7462
7539
  function maskPhone(digits) {
7463
7540
  if (digits.length <= 4) return "*".repeat(digits.length);
7464
7541
  return digits.slice(0, 2) + "*".repeat(digits.length - 4) + digits.slice(-2);
@@ -7469,7 +7546,7 @@ function closeSocket(sock) {
7469
7546
  try {
7470
7547
  sock.ws?.close?.();
7471
7548
  } catch (err) {
7472
- console.warn(`${TAG18} socket close error during cleanup: ${String(err)}`);
7549
+ console.warn(`${TAG19} socket close error during cleanup: ${String(err)}`);
7473
7550
  }
7474
7551
  }
7475
7552
  function resetActiveLogin(accountId) {
@@ -7496,18 +7573,18 @@ async function runPostPairing(login) {
7496
7573
  const masked = selfPhone ? `${selfPhone.slice(0, 4)}***` : "null";
7497
7574
  console.error(`[whatsapp-persist] wa-persist-on-connect account=${login.accountId} phone=${masked}`);
7498
7575
  } else {
7499
- console.error(`${TAG18} wa-persist-on-connect FAILED account=${login.accountId}: ${result.error}`);
7576
+ console.error(`${TAG19} wa-persist-on-connect FAILED account=${login.accountId}: ${result.error}`);
7500
7577
  }
7501
7578
  } catch (err) {
7502
- console.error(`${TAG18} wa-persist-on-connect error account=${login.accountId}: ${String(err)}`);
7579
+ console.error(`${TAG19} wa-persist-on-connect error account=${login.accountId}: ${String(err)}`);
7503
7580
  }
7504
7581
  } else {
7505
- console.error(`${TAG18} wa-persist-on-connect skipped \u2014 no accountDir account=${login.accountId}`);
7582
+ console.error(`${TAG19} wa-persist-on-connect skipped \u2014 no accountDir account=${login.accountId}`);
7506
7583
  }
7507
7584
  try {
7508
7585
  await registerLoginSocket(login.accountId, login.sock, login.authDir);
7509
7586
  } catch (err) {
7510
- console.error(`${TAG18} registerLoginSocket failed account=${login.accountId}: ${String(err)}`);
7587
+ console.error(`${TAG19} registerLoginSocket failed account=${login.accountId}: ${String(err)}`);
7511
7588
  }
7512
7589
  }
7513
7590
  async function loginConnectionLoop(accountId, login) {
@@ -7516,7 +7593,7 @@ async function loginConnectionLoop(accountId, login) {
7516
7593
  const logTerminal = (outcome, errMsg) => {
7517
7594
  const fc = credsCensus(login.authDir);
7518
7595
  console.error(
7519
- `${TAG18} op=terminal cid=${cidShort} outcome=${outcome} credsFinal={registered=${fc.registered},account=${fc.hasAccountSignature},me=${fc.e164 ?? "null"}}` + (errMsg ? ` error="${errMsg}"` : "")
7596
+ `${TAG19} op=terminal cid=${cidShort} outcome=${outcome} credsFinal={registered=${fc.registered},account=${fc.hasAccountSignature},me=${fc.e164 ?? "null"}}` + (errMsg ? ` error="${errMsg}"` : "")
7520
7597
  );
7521
7598
  };
7522
7599
  while (true) {
@@ -7526,7 +7603,7 @@ async function loginConnectionLoop(accountId, login) {
7526
7603
  if (current?.id === login.id) {
7527
7604
  await runPostPairing(current);
7528
7605
  current.connected = true;
7529
- console.error(`${TAG18} loginConnectionLoop: connected account=${accountId} attempt=${attempt} configPersisted=${current.configPersisted}`);
7606
+ console.error(`${TAG19} loginConnectionLoop: connected account=${accountId} attempt=${attempt} configPersisted=${current.configPersisted}`);
7530
7607
  logTerminal("connected");
7531
7608
  }
7532
7609
  return;
@@ -7538,7 +7615,7 @@ async function loginConnectionLoop(accountId, login) {
7538
7615
  if (!preRetryCensus.hasAccountSignature) {
7539
7616
  current.error = "WhatsApp accepted the code but did not finish linking. This usually means the number has reached its linked-device limit or has a stale linked device. On the phone, open WhatsApp, Linked Devices, remove existing devices, then ask for a new code.";
7540
7617
  console.error(
7541
- `${TAG18} op=pairing-incomplete cid=${cidShort} closeKind=${closeKind(getStatusCode(err), false)} reason=no-account-signature`
7618
+ `${TAG19} op=pairing-incomplete cid=${cidShort} closeKind=${closeKind(getStatusCode(err), false)} reason=no-account-signature`
7542
7619
  );
7543
7620
  return;
7544
7621
  }
@@ -7546,7 +7623,7 @@ async function loginConnectionLoop(accountId, login) {
7546
7623
  if (!classification.shouldRetry || attempt >= LOGIN_MAX_RECONNECTS) {
7547
7624
  if (attempt >= LOGIN_MAX_RECONNECTS) {
7548
7625
  console.error(
7549
- `${TAG18} login reconnect attempts exhausted (${attempt}/${LOGIN_MAX_RECONNECTS}) \u2014 surfacing error to agent`
7626
+ `${TAG19} login reconnect attempts exhausted (${attempt}/${LOGIN_MAX_RECONNECTS}) \u2014 surfacing error to agent`
7550
7627
  );
7551
7628
  current.error = `Login failed after ${attempt} reconnect attempts: ${formatError(err)}`;
7552
7629
  } else {
@@ -7559,7 +7636,7 @@ async function loginConnectionLoop(accountId, login) {
7559
7636
  attempt++;
7560
7637
  const delay = LOGIN_RECONNECT_DELAYS[attempt - 1] ?? 8e3;
7561
7638
  console.error(
7562
- `${TAG18} status=${classification.statusCode ?? "unknown"} restart required \u2014 reconnecting with saved creds (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}) delay=${delay}ms`
7639
+ `${TAG19} status=${classification.statusCode ?? "unknown"} restart required \u2014 reconnecting with saved creds (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}) delay=${delay}ms`
7563
7640
  );
7564
7641
  closeSocket(current.sock);
7565
7642
  await new Promise((r) => setTimeout(r, delay));
@@ -7567,14 +7644,14 @@ async function loginConnectionLoop(accountId, login) {
7567
7644
  if (afterDelay?.id !== login.id) return;
7568
7645
  const rc = credsCensus(login.authDir);
7569
7646
  console.error(
7570
- `${TAG18} op=reconnect cid=${cidShort} attempt=${attempt}/${LOGIN_MAX_RECONNECTS} withRegistered=${rc.registered} withAccount=${rc.hasAccountSignature}`
7647
+ `${TAG19} op=reconnect cid=${cidShort} attempt=${attempt}/${LOGIN_MAX_RECONNECTS} withRegistered=${rc.registered} withAccount=${rc.hasAccountSignature}`
7571
7648
  );
7572
7649
  try {
7573
7650
  const newSock = await createWaSocket({ authDir: login.authDir, correlationId: cidShort, account: accountId });
7574
7651
  current.sock = newSock;
7575
7652
  } catch (sockErr) {
7576
7653
  console.error(
7577
- `${TAG18} reconnect socket creation failed (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}): ${String(sockErr)}`
7654
+ `${TAG19} reconnect socket creation failed (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}): ${String(sockErr)}`
7578
7655
  );
7579
7656
  current.error = `Reconnection failed: ${String(sockErr)}`;
7580
7657
  logTerminal("error", current.error);
@@ -7591,7 +7668,7 @@ async function startLogin(opts) {
7591
7668
  const hasAuth = await authExists(authDir);
7592
7669
  const selfId = readSelfId(authDir);
7593
7670
  console.error(
7594
- `${TAG18} op=start cid=${cid} account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasCode=${!!existing0.pairingCode}}` : " activeLogin=none")
7671
+ `${TAG19} op=start cid=${cid} account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasCode=${!!existing0.pairingCode}}` : " activeLogin=none")
7595
7672
  );
7596
7673
  if (hasAuth && !force) {
7597
7674
  const who = selfId.e164 ?? selfId.jid ?? "unknown";
@@ -7606,7 +7683,7 @@ async function startLogin(opts) {
7606
7683
  }
7607
7684
  const existing = activeLogins.get(accountId);
7608
7685
  if (existing && isLoginFresh(existing) && existing.pairingCode && !force) {
7609
- console.error(`${TAG18} startLogin account=${accountId} guard: returning existing pairing code (age=${Math.round((Date.now() - existing.startedAt) / 1e3)}s)`);
7686
+ console.error(`${TAG19} startLogin account=${accountId} guard: returning existing pairing code (age=${Math.round((Date.now() - existing.startedAt) / 1e3)}s)`);
7610
7687
  return {
7611
7688
  pairingCode: existing.pairingCode,
7612
7689
  phone: existing.phone,
@@ -7614,7 +7691,7 @@ async function startLogin(opts) {
7614
7691
  };
7615
7692
  }
7616
7693
  if (existing) {
7617
- console.error(`${TAG18} startLogin account=${accountId} ${force ? "force override" : "stale/no-code"}, resetting active login`);
7694
+ console.error(`${TAG19} startLogin account=${accountId} ${force ? "force override" : "stale/no-code"}, resetting active login`);
7618
7695
  }
7619
7696
  resetActiveLogin(accountId);
7620
7697
  await clearAuth(authDir);
@@ -7645,7 +7722,7 @@ async function startLogin(opts) {
7645
7722
  if (requested) return;
7646
7723
  requested = true;
7647
7724
  console.error(
7648
- `${TAG18} op=pairing-request cid=${cid} account=${accountId} qrRef=#1 sinceOpenMs=${socketOpenTs ? Date.now() - socketOpenTs : 0}`
7725
+ `${TAG19} op=pairing-request cid=${cid} account=${accountId} qrRef=#1 sinceOpenMs=${socketOpenTs ? Date.now() - socketOpenTs : 0}`
7649
7726
  );
7650
7727
  void sock.requestPairingCode(digits).then((code) => {
7651
7728
  clearTimeout(codeTimer);
@@ -7654,7 +7731,7 @@ async function startLogin(opts) {
7654
7731
  if (current?.id !== login.id) return;
7655
7732
  if (!current.pairingCode) current.pairingCode = code;
7656
7733
  console.error(
7657
- `${TAG18} op=code-issued cid=${cid} account=${accountId} phone=${maskPhone(digits)} codeLen=${code.length} sinceOpenMs=${socketOpenTs ? codeIssuedTs - socketOpenTs : 0}`
7734
+ `${TAG19} op=code-issued cid=${cid} account=${accountId} phone=${maskPhone(digits)} codeLen=${code.length} sinceOpenMs=${socketOpenTs ? codeIssuedTs - socketOpenTs : 0}`
7658
7735
  );
7659
7736
  resolveCode?.(code);
7660
7737
  }).catch((err) => {
@@ -7685,7 +7762,7 @@ async function startLogin(opts) {
7685
7762
  const ttlTimer = setTimeout(() => {
7686
7763
  const current = activeLogins.get(accountId);
7687
7764
  if (current?.id === login.id && !current.connected) {
7688
- console.error(`${TAG18} pairing-window-elapsed account=${accountId} (ttl sweep)`);
7765
+ console.error(`${TAG19} pairing-window-elapsed account=${accountId} (ttl sweep)`);
7689
7766
  resetActiveLogin(accountId);
7690
7767
  }
7691
7768
  }, ACTIVE_LOGIN_TTL_MS);
@@ -7693,7 +7770,7 @@ async function startLogin(opts) {
7693
7770
  ttlTimer.unref();
7694
7771
  }
7695
7772
  loginConnectionLoop(accountId, login).catch((err) => {
7696
- console.error(`${TAG18} loginConnectionLoop unexpected error: ${String(err)}`);
7773
+ console.error(`${TAG19} loginConnectionLoop unexpected error: ${String(err)}`);
7697
7774
  const current = activeLogins.get(accountId);
7698
7775
  if (current?.id === login.id) {
7699
7776
  current.error = `Unexpected login error: ${String(err)}`;
@@ -7718,13 +7795,13 @@ async function waitForLogin(opts) {
7718
7795
  const { accountId, timeoutMs = 6e4 } = opts;
7719
7796
  const login = activeLogins.get(accountId);
7720
7797
  console.error(
7721
- `${TAG18} waitForLogin account=${accountId} timeout=${timeoutMs}ms` + (login ? ` login={id=${login.id.slice(0, 8)},age=${Math.round((Date.now() - login.startedAt) / 1e3)}s,connected=${login.connected},hasCode=${!!login.pairingCode}}` : " login=none")
7798
+ `${TAG19} waitForLogin account=${accountId} timeout=${timeoutMs}ms` + (login ? ` login={id=${login.id.slice(0, 8)},age=${Math.round((Date.now() - login.startedAt) / 1e3)}s,connected=${login.connected},hasCode=${!!login.pairingCode}}` : " login=none")
7722
7799
  );
7723
7800
  if (!login) {
7724
7801
  return { connected: false, message: "No active WhatsApp login in progress.", configPersisted: false };
7725
7802
  }
7726
7803
  if (!isLoginFresh(login)) {
7727
- console.error(`${TAG18} pairing-window-elapsed account=${accountId}`);
7804
+ console.error(`${TAG19} pairing-window-elapsed account=${accountId}`);
7728
7805
  resetActiveLogin(accountId);
7729
7806
  return { connected: false, message: "The pairing window expired. Ask me to generate a new code.", configPersisted: false };
7730
7807
  }
@@ -7732,8 +7809,8 @@ async function waitForLogin(opts) {
7732
7809
  while (Date.now() < deadline) {
7733
7810
  if (login.connected) {
7734
7811
  const selfId = readSelfId(login.authDir);
7735
- console.error(`${TAG18} pairing-connected account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
7736
- console.error(`${TAG18} login complete for account=${accountId} phone=${selfId.e164 ?? "unknown"} configPersisted=${login.configPersisted}`);
7812
+ console.error(`${TAG19} pairing-connected account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
7813
+ console.error(`${TAG19} login complete for account=${accountId} phone=${selfId.e164 ?? "unknown"} configPersisted=${login.configPersisted}`);
7737
7814
  const configPersisted = login.configPersisted;
7738
7815
  activeLogins.delete(accountId);
7739
7816
  return {
@@ -7751,7 +7828,7 @@ async function waitForLogin(opts) {
7751
7828
  await new Promise((r) => setTimeout(r, 1e3));
7752
7829
  }
7753
7830
  const elapsed = Math.round((Date.now() - (deadline - timeoutMs)) / 1e3);
7754
- console.error(`${TAG18} waitForLogin poll timeout account=${accountId} elapsed=${elapsed}s \u2014 login kept alive (pairing code still valid)`);
7831
+ console.error(`${TAG19} waitForLogin poll timeout account=${accountId} elapsed=${elapsed}s \u2014 login kept alive (pairing code still valid)`);
7755
7832
  return { connected: false, message: "Still waiting for you to enter the pairing code. The code is still valid \u2014 ask me to keep waiting, or request a new code.", configPersisted: false };
7756
7833
  }
7757
7834
  function listActiveLoginAccountIds() {
@@ -7773,8 +7850,7 @@ function reconcileMessageStoreAccountKeys(input) {
7773
7850
  import { realpathSync as realpathSync3 } from "fs";
7774
7851
  import { readFile, stat as stat2 } from "fs/promises";
7775
7852
  import { resolve as resolve9, basename as basename3 } from "path";
7776
- var TAG19 = "[whatsapp:outbound]";
7777
- var WHATSAPP_DOCUMENT_MAX_BYTES = 100 * 1024 * 1024;
7853
+ var TAG20 = "[whatsapp:outbound]";
7778
7854
  var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
7779
7855
  var lastRouteDocumentOutboundAt = /* @__PURE__ */ new Map();
7780
7856
  function normalizeJid2(to) {
@@ -7807,16 +7883,16 @@ async function sendWhatsAppDocument(input) {
7807
7883
  const accountResolved = realpathSync3(accountDir);
7808
7884
  if (!resolvedPath.startsWith(accountResolved + "/")) {
7809
7885
  const sanitised = filePath.replace(accountDir, "<account>/");
7810
- console.error(`${TAG19} document REJECTED path=${sanitised} reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
7886
+ console.error(`${TAG20} document REJECTED path=${sanitised} reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
7811
7887
  return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
7812
7888
  }
7813
7889
  } catch (err) {
7814
7890
  const code = err.code;
7815
7891
  if (code === "ENOENT") {
7816
- console.error(`${TAG19} document ENOENT path=${filePath}`);
7892
+ console.error(`${TAG20} document ENOENT path=${filePath}`);
7817
7893
  return { ok: false, status: 404, error: `File not found: ${filePath}` };
7818
7894
  }
7819
- console.error(`${TAG19} document path error: ${String(err)}`);
7895
+ console.error(`${TAG20} document path error: ${String(err)}`);
7820
7896
  return { ok: false, status: 500, error: String(err) };
7821
7897
  }
7822
7898
  const fileStat = await stat2(resolvedPath);
@@ -7832,7 +7908,7 @@ async function sendWhatsAppDocument(input) {
7832
7908
  const res = resolveSocket(accountId);
7833
7909
  if (!res.ok) {
7834
7910
  const reason = res.reason === "key-miss" ? `key-miss presentKeys=${res.presentKeys.join(",") || "none"}` : "disconnected";
7835
- console.error(`${TAG19} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=false reason=${reason}`);
7911
+ console.error(`${TAG20} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=false reason=${reason}`);
7836
7912
  if (res.reason === "key-miss") {
7837
7913
  return {
7838
7914
  ok: false,
@@ -7852,7 +7928,7 @@ async function sendWhatsAppDocument(input) {
7852
7928
  { accountId: res.accountId }
7853
7929
  );
7854
7930
  console.error(
7855
- `${TAG19} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=${result.success}` + (result.messageId ? ` id=${result.messageId}` : "")
7931
+ `${TAG20} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=${result.success}` + (result.messageId ? ` id=${result.messageId}` : "")
7856
7932
  );
7857
7933
  if (result.success) {
7858
7934
  recordDocumentOutbound(to);
@@ -7972,7 +8048,7 @@ function serializeWhatsAppSchema() {
7972
8048
  // app/lib/whatsapp/status-reconcile.ts
7973
8049
  import { readdirSync as readdirSync4 } from "fs";
7974
8050
  import { join as join9 } from "path";
7975
- var TAG20 = "[whatsapp:reconcile]";
8051
+ var TAG21 = "[whatsapp:reconcile]";
7976
8052
  var HALF_REGISTERED_MIN_AGE_MS = 5 * 6e4;
7977
8053
  function listCredsAccountIds(credsRoot) {
7978
8054
  try {
@@ -7998,14 +8074,14 @@ function reconcileCredsOnDisk(opts) {
7998
8074
  const ageMs = getAuthAgeMs(authDir);
7999
8075
  const abandoned = !inFlight && ageMs !== null && ageMs >= HALF_REGISTERED_MIN_AGE_MS;
8000
8076
  if (!abandoned) {
8001
- console.error(`${TAG20} op=half-registered account=${accountId} registered=true hasAccount=false inFlight=${inFlight} ageMs=${ageMs ?? "null"}`);
8077
+ console.error(`${TAG21} op=half-registered account=${accountId} registered=true hasAccount=false inFlight=${inFlight} ageMs=${ageMs ?? "null"}`);
8002
8078
  entries.push({ accountId, connected: false, linkedUnconfigured: true });
8003
8079
  continue;
8004
8080
  }
8005
- console.error(`${TAG20} op=discard-half-registered account=${accountId} registered=true hasAccount=false ageMs=${ageMs}`);
8081
+ console.error(`${TAG21} op=discard-half-registered account=${accountId} registered=true hasAccount=false ageMs=${ageMs}`);
8006
8082
  const removed = discardAuthDirSync(authDir);
8007
8083
  if (!removed) {
8008
- console.error(`${TAG20} op=discard-half-registered-failed account=${accountId} \u2014 residue persists`);
8084
+ console.error(`${TAG21} op=discard-half-registered-failed account=${accountId} \u2014 residue persists`);
8009
8085
  entries.push({ accountId, connected: false, linkedUnconfigured: true });
8010
8086
  }
8011
8087
  continue;
@@ -8013,14 +8089,14 @@ function reconcileCredsOnDisk(opts) {
8013
8089
  const selfPhone = readSelfId(authDir).e164 ?? void 0;
8014
8090
  const configured = accountDir ? isAccountConfigured(accountDir, accountId) : false;
8015
8091
  console.error(
8016
- `${TAG20} wa-link-unconfigured account=${accountId} creds=present config=${configured ? "present" : "absent"}`
8092
+ `${TAG21} wa-link-unconfigured account=${accountId} creds=present config=${configured ? "present" : "absent"}`
8017
8093
  );
8018
8094
  if (!configured && accountDir) {
8019
8095
  const result = persistAfterPairing(accountDir, accountId, selfPhone ?? null);
8020
8096
  if (result.ok) {
8021
- console.error(`${TAG20} self-healed account=${accountId}`);
8097
+ console.error(`${TAG21} self-healed account=${accountId}`);
8022
8098
  } else {
8023
- console.error(`${TAG20} self-heal FAILED account=${accountId}: ${result.error}`);
8099
+ console.error(`${TAG21} self-heal FAILED account=${accountId}: ${result.error}`);
8024
8100
  }
8025
8101
  }
8026
8102
  entries.push({ accountId, selfPhone, connected: false, linkedUnconfigured: !configured });
@@ -8121,7 +8197,7 @@ function authorizeRecallRead(input) {
8121
8197
  }
8122
8198
 
8123
8199
  // server/routes/whatsapp.ts
8124
- var TAG21 = "[whatsapp:api]";
8200
+ var TAG22 = "[whatsapp:api]";
8125
8201
  var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT || "";
8126
8202
  function recallAttachment(storeAccountId, attachmentId) {
8127
8203
  if (!attachmentId) return void 0;
@@ -8166,7 +8242,7 @@ function houseSocketScopeDenial(c, op) {
8166
8242
  const houseAccountId = resolveAccount()?.accountId ?? "";
8167
8243
  const { decision, callerAccountId, houseAdminScope } = evaluateCallerScope(c, houseAccountId);
8168
8244
  if (decision.authorized) return null;
8169
- console.error(`${TAG21} op=authz-deny route=${op} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
8245
+ console.error(`${TAG22} op=authz-deny route=${op} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
8170
8246
  return c.json({ ok: false, error: "Not authorized. The WhatsApp connection and its settings are house-scoped; this session may only act on its own account." }, 403);
8171
8247
  }
8172
8248
  var app2 = new Hono();
@@ -8182,7 +8258,7 @@ app2.get("/status", (c) => {
8182
8258
  const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds, activeLoginAccountIds: activeLoginIds });
8183
8259
  const accounts = [...live, ...reconciled];
8184
8260
  const summary = accounts.map((a) => `${a.accountId}:${a.connected ? "up" : a.linkedUnconfigured ? "linked-unconfigured" : "down"}`).join(", ");
8185
- console.error(`${TAG21} status accounts=${accounts.length} [${summary}]`);
8261
+ console.error(`${TAG22} status accounts=${accounts.length} [${summary}]`);
8186
8262
  const reachableAccountIds = [
8187
8263
  .../* @__PURE__ */ new Set([...listStoredAccountIds(), ...listConnectionPlatformAccountIds()])
8188
8264
  ];
@@ -8191,11 +8267,11 @@ app2.get("/status", (c) => {
8191
8267
  reachableAccountIds
8192
8268
  });
8193
8269
  if (!storeKeyReconcile.ok) {
8194
- console.warn(`${TAG21} store-key-drift orphanLiveKeys=[${storeKeyReconcile.orphanLiveKeys.join(",")}] \u2014 in-memory cache keyed by a value with no disk account; read tools will miss`);
8270
+ console.warn(`${TAG22} store-key-drift orphanLiveKeys=[${storeKeyReconcile.orphanLiveKeys.join(",")}] \u2014 in-memory cache keyed by a value with no disk account; read tools will miss`);
8195
8271
  }
8196
8272
  return c.json({ accounts, storeKeyReconcile });
8197
8273
  } catch (err) {
8198
- console.error(`${TAG21} status error: ${String(err)}`);
8274
+ console.error(`${TAG22} status error: ${String(err)}`);
8199
8275
  return c.json({ error: String(err) }, 500);
8200
8276
  }
8201
8277
  });
@@ -8213,10 +8289,10 @@ app2.post("/login/start", async (c) => {
8213
8289
  const authDir = join10(MAXY_DIR, "credentials", "whatsapp", accountId);
8214
8290
  const accountDir = resolveAccount()?.accountDir ?? null;
8215
8291
  const result = await startLogin({ accountId, authDir, phone, accountDir, force });
8216
- console.error(`${TAG21} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
8292
+ console.error(`${TAG22} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
8217
8293
  return c.json(result);
8218
8294
  } catch (err) {
8219
- console.error(`${TAG21} login/start error: ${String(err)}`);
8295
+ console.error(`${TAG22} login/start error: ${String(err)}`);
8220
8296
  return c.json({ error: String(err) }, 500);
8221
8297
  }
8222
8298
  });
@@ -8228,7 +8304,7 @@ app2.post("/login/wait", async (c) => {
8228
8304
  const accountId = validateAccountId(body.accountId);
8229
8305
  const timeoutMs = body.timeoutMs ?? 6e4;
8230
8306
  const result = await waitForLogin({ accountId, timeoutMs });
8231
- console.error(`${TAG21} login/wait result account=${accountId} connected=${result.connected}${result.selfPhone ? ` phone=${result.selfPhone}` : ""} configPersisted=${result.configPersisted}`);
8307
+ console.error(`${TAG22} login/wait result account=${accountId} connected=${result.connected}${result.selfPhone ? ` phone=${result.selfPhone}` : ""} configPersisted=${result.configPersisted}`);
8232
8308
  return c.json({
8233
8309
  connected: result.connected,
8234
8310
  message: result.message,
@@ -8236,7 +8312,7 @@ app2.post("/login/wait", async (c) => {
8236
8312
  configPersisted: result.configPersisted
8237
8313
  });
8238
8314
  } catch (err) {
8239
- console.error(`${TAG21} login/wait error: ${String(err)}`);
8315
+ console.error(`${TAG22} login/wait error: ${String(err)}`);
8240
8316
  return c.json({ error: String(err) }, 500);
8241
8317
  }
8242
8318
  });
@@ -8249,7 +8325,7 @@ app2.post("/disconnect", async (c) => {
8249
8325
  await stopConnection(accountId);
8250
8326
  return c.json({ disconnected: true, accountId });
8251
8327
  } catch (err) {
8252
- console.error(`${TAG21} disconnect error: ${String(err)}`);
8328
+ console.error(`${TAG22} disconnect error: ${String(err)}`);
8253
8329
  return c.json({ error: String(err) }, 500);
8254
8330
  }
8255
8331
  });
@@ -8262,7 +8338,7 @@ app2.post("/reconnect", async (c) => {
8262
8338
  await startConnection(accountId);
8263
8339
  return c.json({ reconnecting: true, accountId });
8264
8340
  } catch (err) {
8265
- console.error(`${TAG21} reconnect error: ${String(err)}`);
8341
+ console.error(`${TAG22} reconnect error: ${String(err)}`);
8266
8342
  return c.json({ error: String(err) }, 500);
8267
8343
  }
8268
8344
  });
@@ -8286,7 +8362,7 @@ app2.post("/config", async (c) => {
8286
8362
  }
8287
8363
  const result = addAdminPhone(account.accountDir, phone);
8288
8364
  const reasonTail = !result.ok && result.reason ? ` reason=${result.reason}` : "";
8289
- console.error(`${TAG21} config action=add-admin-phone accountId=${account.accountId} phone=${phone} ok=${result.ok}${reasonTail}`);
8365
+ console.error(`${TAG22} config action=add-admin-phone accountId=${account.accountId} phone=${phone} ok=${result.ok}${reasonTail}`);
8290
8366
  return c.json(result, result.ok ? 200 : 400);
8291
8367
  }
8292
8368
  case "remove-admin-phone": {
@@ -8294,12 +8370,12 @@ app2.post("/config", async (c) => {
8294
8370
  return c.json({ ok: false, error: 'Missing required field "phone".' }, 400);
8295
8371
  }
8296
8372
  const result = removeAdminPhone(account.accountDir, phone);
8297
- console.error(`${TAG21} config action=remove-admin-phone phone=${phone} ok=${result.ok}`);
8373
+ console.error(`${TAG22} config action=remove-admin-phone phone=${phone} ok=${result.ok}`);
8298
8374
  return c.json(result, result.ok ? 200 : 400);
8299
8375
  }
8300
8376
  case "list-admin-phones": {
8301
8377
  const phones = readAdminPhones(account.accountDir);
8302
- console.error(`${TAG21} config action=list-admin-phones count=${phones.length}`);
8378
+ console.error(`${TAG22} config action=list-admin-phones count=${phones.length}`);
8303
8379
  return c.json({ ok: true, phones });
8304
8380
  }
8305
8381
  case "add-account-manager": {
@@ -8311,7 +8387,7 @@ app2.post("/config", async (c) => {
8311
8387
  }
8312
8388
  const managerMode = mode === "passive" ? "passive" : "active";
8313
8389
  const result = setAccountManager(account.accountDir, phone, managesAccount, managerMode);
8314
- console.error(`${TAG21} config action=add-account-manager phone=${phone} managesAccount=${managesAccount} mode=${managerMode} ok=${result.ok}`);
8390
+ console.error(`${TAG22} config action=add-account-manager phone=${phone} managesAccount=${managesAccount} mode=${managerMode} ok=${result.ok}`);
8315
8391
  return c.json(result, result.ok ? 200 : 400);
8316
8392
  }
8317
8393
  case "remove-account-manager": {
@@ -8319,12 +8395,12 @@ app2.post("/config", async (c) => {
8319
8395
  return c.json({ ok: false, error: 'Missing required field "phone".' }, 400);
8320
8396
  }
8321
8397
  const result = clearAccountManager(account.accountDir, phone);
8322
- console.error(`${TAG21} config action=remove-account-manager phone=${phone} ok=${result.ok}`);
8398
+ console.error(`${TAG22} config action=remove-account-manager phone=${phone} ok=${result.ok}`);
8323
8399
  return c.json(result, result.ok ? 200 : 400);
8324
8400
  }
8325
8401
  case "list-account-managers": {
8326
8402
  const accountManagers = readAccountManagers(account.accountDir);
8327
- console.error(`${TAG21} config action=list-account-managers count=${Object.keys(accountManagers).length}`);
8403
+ console.error(`${TAG22} config action=list-account-managers count=${Object.keys(accountManagers).length}`);
8328
8404
  return c.json({ ok: true, accountManagers });
8329
8405
  }
8330
8406
  case "set-public-agent": {
@@ -8332,13 +8408,13 @@ app2.post("/config", async (c) => {
8332
8408
  return c.json({ ok: false, error: 'Missing required field "slug" (the agent directory name, e.g. "my-agent").' }, 400);
8333
8409
  }
8334
8410
  const result = setPublicAgent(account.accountDir, slug);
8335
- console.error(`${TAG21} config action=set-public-agent slug=${slug} ok=${result.ok}`);
8411
+ console.error(`${TAG22} config action=set-public-agent slug=${slug} ok=${result.ok}`);
8336
8412
  return c.json(result, result.ok ? 200 : 400);
8337
8413
  }
8338
8414
  case "get-public-agent": {
8339
8415
  const targetAccount = typeof accountId === "string" && accountId.trim() ? accountId.trim() : "default";
8340
8416
  const resolved = resolvePublicAgent(account.accountDir, { accountId: targetAccount });
8341
- console.error(`${TAG21} config action=get-public-agent accountId=${targetAccount} slug=${resolved?.slug ?? "none"} source=${resolved?.source ?? "none"}`);
8417
+ console.error(`${TAG22} config action=get-public-agent accountId=${targetAccount} slug=${resolved?.slug ?? "none"} source=${resolved?.source ?? "none"}`);
8342
8418
  return c.json({ ok: true, slug: resolved?.slug ?? null, source: resolved?.source ?? null });
8343
8419
  }
8344
8420
  case "list-public-agents": {
@@ -8355,26 +8431,26 @@ app2.post("/config", async (c) => {
8355
8431
  const config = JSON.parse(readFileSync12(configPath2, "utf-8"));
8356
8432
  agents.push({ slug: entry.name, displayName: config.displayName ?? entry.name });
8357
8433
  } catch {
8358
- console.error(`${TAG21} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
8434
+ console.error(`${TAG22} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
8359
8435
  }
8360
8436
  }
8361
8437
  } catch (err) {
8362
- console.error(`${TAG21} config action=list-public-agents error="failed to scan agents directory: ${String(err)}"`);
8438
+ console.error(`${TAG22} config action=list-public-agents error="failed to scan agents directory: ${String(err)}"`);
8363
8439
  }
8364
8440
  }
8365
- console.error(`${TAG21} config action=list-public-agents count=${agents.length}`);
8441
+ console.error(`${TAG22} config action=list-public-agents count=${agents.length}`);
8366
8442
  return c.json({ ok: true, agents });
8367
8443
  }
8368
8444
  case "schema": {
8369
8445
  const text = serializeWhatsAppSchema();
8370
- console.error(`${TAG21} config action=schema`);
8446
+ console.error(`${TAG22} config action=schema`);
8371
8447
  return c.json({ ok: true, text });
8372
8448
  }
8373
8449
  case "list-groups": {
8374
8450
  const groupAccountId = accountId ?? "default";
8375
8451
  const sock = getSocket(groupAccountId);
8376
8452
  if (!sock) {
8377
- console.error(`${TAG21} config action=list-groups error="not connected" accountId=${groupAccountId}`);
8453
+ console.error(`${TAG22} config action=list-groups error="not connected" accountId=${groupAccountId}`);
8378
8454
  return c.json({ ok: false, error: `WhatsApp account "${groupAccountId}" is not connected. Connect first, then retry.` });
8379
8455
  }
8380
8456
  try {
@@ -8384,10 +8460,10 @@ app2.post("/config", async (c) => {
8384
8460
  name: g.subject ?? g.id,
8385
8461
  participantCount: Array.isArray(g.participants) ? g.participants.length : 0
8386
8462
  }));
8387
- console.error(`${TAG21} config action=list-groups count=${groups.length} accountId=${groupAccountId}`);
8463
+ console.error(`${TAG22} config action=list-groups count=${groups.length} accountId=${groupAccountId}`);
8388
8464
  return c.json({ ok: true, groups });
8389
8465
  } catch (err) {
8390
- console.error(`${TAG21} config action=list-groups error="${String(err)}" accountId=${groupAccountId}`);
8466
+ console.error(`${TAG22} config action=list-groups error="${String(err)}" accountId=${groupAccountId}`);
8391
8467
  return c.json({ ok: false, error: `Failed to fetch groups: ${String(err)}` });
8392
8468
  }
8393
8469
  }
@@ -8397,12 +8473,12 @@ app2.post("/config", async (c) => {
8397
8473
  }
8398
8474
  const result = updateConfig(account.accountDir, fields);
8399
8475
  const fieldNames = Object.keys(fields);
8400
- console.error(`${TAG21} config action=update-config fields=[${fieldNames.join(",")}] ok=${result.ok}`);
8476
+ console.error(`${TAG22} config action=update-config fields=[${fieldNames.join(",")}] ok=${result.ok}`);
8401
8477
  return c.json(result, result.ok ? 200 : 400);
8402
8478
  }
8403
8479
  case "get-config": {
8404
8480
  const waConfig = getConfig(account.accountDir);
8405
- console.error(`${TAG21} config action=get-config`);
8481
+ console.error(`${TAG22} config action=get-config`);
8406
8482
  return c.json({ ok: true, config: waConfig });
8407
8483
  }
8408
8484
  default:
@@ -8412,7 +8488,7 @@ app2.post("/config", async (c) => {
8412
8488
  );
8413
8489
  }
8414
8490
  } catch (err) {
8415
- console.error(`${TAG21} config error: ${String(err)}`);
8491
+ console.error(`${TAG22} config error: ${String(err)}`);
8416
8492
  return c.json({ ok: false, error: String(err) }, 500);
8417
8493
  }
8418
8494
  });
@@ -8433,7 +8509,7 @@ app2.post("/send-document", async (c) => {
8433
8509
  recordRouteDocumentOutbound(to, filePath);
8434
8510
  return c.json({ success: true, messageId: result.messageId });
8435
8511
  } catch (err) {
8436
- console.error(`${TAG21} send-document error: ${String(err)}`);
8512
+ console.error(`${TAG22} send-document error: ${String(err)}`);
8437
8513
  return c.json({ error: String(err) }, 500);
8438
8514
  }
8439
8515
  });
@@ -8478,7 +8554,7 @@ app2.post("/send-admin", async (c) => {
8478
8554
  console.error(`[whatsapp:outbound] op=send-admin-ok via=${via} to=${phone}`);
8479
8555
  return c.json({ success: true, messageId: result.messageId });
8480
8556
  } catch (err) {
8481
- console.error(`${TAG21} send-admin error: ${String(err)}`);
8557
+ console.error(`${TAG22} send-admin error: ${String(err)}`);
8482
8558
  return c.json({ error: String(err) }, 500);
8483
8559
  }
8484
8560
  });
@@ -8488,11 +8564,11 @@ app2.get("/activity", (c) => {
8488
8564
  const result = getChannelActivity(accountId);
8489
8565
  const total = result.accounts.reduce((sum, a) => sum + a.total, 0);
8490
8566
  console.error(
8491
- `${TAG21} activity accounts=${result.accounts.length} total=${total} recentEvents=${result.recentEvents.length}` + (accountId ? ` filter=${accountId}` : "")
8567
+ `${TAG22} activity accounts=${result.accounts.length} total=${total} recentEvents=${result.recentEvents.length}` + (accountId ? ` filter=${accountId}` : "")
8492
8568
  );
8493
8569
  return c.json(result);
8494
8570
  } catch (err) {
8495
- console.error(`${TAG21} activity error: ${String(err)}`);
8571
+ console.error(`${TAG22} activity error: ${String(err)}`);
8496
8572
  return c.json({ error: String(err) }, 500);
8497
8573
  }
8498
8574
  });
@@ -8517,10 +8593,10 @@ app2.get("/conversations", (c) => {
8517
8593
  };
8518
8594
  });
8519
8595
  conversations.sort((a, b) => (b.lastMessageTimestamp ?? 0) - (a.lastMessageTimestamp ?? 0));
8520
- console.error(`${TAG21} conversations requested=${requestedAccountId} account=${storeAccountId} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${allConversations.size > 0} count=${conversations.length}`);
8596
+ console.error(`${TAG22} conversations requested=${requestedAccountId} account=${storeAccountId} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${allConversations.size > 0} count=${conversations.length}`);
8521
8597
  return c.json({ conversations });
8522
8598
  } catch (err) {
8523
- console.error(`${TAG21} conversations error: ${String(err)}`);
8599
+ console.error(`${TAG22} conversations error: ${String(err)}`);
8524
8600
  return c.json({ error: String(err) }, 500);
8525
8601
  }
8526
8602
  });
@@ -8565,10 +8641,10 @@ app2.get("/messages", (c) => {
8565
8641
  ...reactions && reactions.length > 0 ? { reactions } : {}
8566
8642
  };
8567
8643
  });
8568
- console.error(`${TAG21} messages requested=${requestedAccountId} account=${storeAccountId} jid=${jid} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${storeMessages.length > 0} limit=${effectiveLimit ?? "all"} returned=${messages.length} withAttachments=${withAttachments}`);
8644
+ console.error(`${TAG22} messages requested=${requestedAccountId} account=${storeAccountId} jid=${jid} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${storeMessages.length > 0} limit=${effectiveLimit ?? "all"} returned=${messages.length} withAttachments=${withAttachments}`);
8569
8645
  return c.json({ messages });
8570
8646
  } catch (err) {
8571
- console.error(`${TAG21} messages error: ${String(err)}`);
8647
+ console.error(`${TAG22} messages error: ${String(err)}`);
8572
8648
  return c.json({ error: String(err) }, 500);
8573
8649
  }
8574
8650
  });
@@ -8670,7 +8746,7 @@ app2.get("/conversation-graph-state", async (c) => {
8670
8746
  ms
8671
8747
  });
8672
8748
  } catch (err) {
8673
- console.error(`${TAG21} conversation-graph-state error: ${String(err)}`);
8749
+ console.error(`${TAG22} conversation-graph-state error: ${String(err)}`);
8674
8750
  return c.json({ error: String(err) }, 500);
8675
8751
  }
8676
8752
  });
@@ -8682,12 +8758,12 @@ app2.get("/group-info", async (c) => {
8682
8758
  return c.json({ error: "Missing required parameter: jid" }, 400);
8683
8759
  }
8684
8760
  if (!isGroupJid(jid)) {
8685
- console.error(`${TAG21} group-info error="not a group JID" jid=${jid} account=${accountId}`);
8761
+ console.error(`${TAG22} group-info error="not a group JID" jid=${jid} account=${accountId}`);
8686
8762
  return c.json({ error: `"${jid}" is not a group JID. Group JIDs end with @g.us.` }, 400);
8687
8763
  }
8688
8764
  const sock = getSocket(accountId);
8689
8765
  if (!sock) {
8690
- console.error(`${TAG21} group-info error="not connected" account=${accountId}`);
8766
+ console.error(`${TAG22} group-info error="not connected" account=${accountId}`);
8691
8767
  return c.json({ error: `WhatsApp account "${accountId}" is not connected. Connect first, then retry.` }, 400);
8692
8768
  }
8693
8769
  const meta = await sock.groupMetadata(jid);
@@ -8700,10 +8776,10 @@ app2.get("/group-info", async (c) => {
8700
8776
  participantCount: meta.participants.length,
8701
8777
  participants: meta.participants.map((p) => ({ jid: p.id, admin: p.admin ?? null }))
8702
8778
  };
8703
- console.error(`${TAG21} group-info jid=${jid} subject="${meta.subject}" participants=${meta.participants.length} account=${accountId}`);
8779
+ console.error(`${TAG22} group-info jid=${jid} subject="${meta.subject}" participants=${meta.participants.length} account=${accountId}`);
8704
8780
  return c.json(result);
8705
8781
  } catch (err) {
8706
- console.error(`${TAG21} group-info error="${String(err)}" jid=${jid} account=${accountId}`);
8782
+ console.error(`${TAG22} group-info error="${String(err)}" jid=${jid} account=${accountId}`);
8707
8783
  return c.json({ error: `Failed to fetch group info: ${String(err)}` }, 500);
8708
8784
  }
8709
8785
  });
@@ -9510,10 +9586,10 @@ async function fetchLiveSessions() {
9510
9586
  function loadUserTitles(accountDir) {
9511
9587
  const out = /* @__PURE__ */ new Map();
9512
9588
  if (!accountDir) return out;
9513
- const path2 = join14(accountDir, "session-titles.json");
9589
+ const path3 = join14(accountDir, "session-titles.json");
9514
9590
  let raw;
9515
9591
  try {
9516
- raw = readFileSync15(path2, "utf8");
9592
+ raw = readFileSync15(path3, "utf8");
9517
9593
  } catch {
9518
9594
  return out;
9519
9595
  }
@@ -9668,21 +9744,21 @@ app4.get("/", requireAdminSession, async (c) => {
9668
9744
  const adminUserIdBySession = /* @__PURE__ */ new Map();
9669
9745
  const channelSenderBySession = /* @__PURE__ */ new Map();
9670
9746
  const channelMissNoSender = [];
9671
- for (const { path: path2, isSubagent, archived } of jsonls) {
9672
- const lastSlash = path2.lastIndexOf("/");
9673
- const base = path2.slice(lastSlash + 1);
9674
- const projectDir = path2.slice(0, lastSlash);
9747
+ for (const { path: path3, isSubagent, archived } of jsonls) {
9748
+ const lastSlash = path3.lastIndexOf("/");
9749
+ const base = path3.slice(lastSlash + 1);
9750
+ const projectDir = path3.slice(0, lastSlash);
9675
9751
  const sessionId = base.slice(0, -".jsonl".length);
9676
9752
  if (seenIds.has(sessionId)) {
9677
- console.error(`[admin-sessions-list] duplicate-sessionId sessionId=${sessionId} path=${path2}`);
9753
+ console.error(`[admin-sessions-list] duplicate-sessionId sessionId=${sessionId} path=${path3}`);
9678
9754
  continue;
9679
9755
  }
9680
9756
  seenIds.add(sessionId);
9681
9757
  let body;
9682
9758
  let mtimeMs;
9683
9759
  try {
9684
- body = readFileSync15(path2, "utf8");
9685
- mtimeMs = statSync4(path2).mtimeMs;
9760
+ body = readFileSync15(path3, "utf8");
9761
+ mtimeMs = statSync4(path3).mtimeMs;
9686
9762
  } catch {
9687
9763
  continue;
9688
9764
  }
@@ -10301,9 +10377,9 @@ app5.get("/conversations", requireAdminSession, async (c) => {
10301
10377
  const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
10302
10378
  const rows = [];
10303
10379
  let sessionRowsExcludedUntagged = 0;
10304
- for (const { path: path2 } of enumerateJsonls(projectsRoot)) {
10305
- const sessionId = basename4(path2).replace(/\.jsonl$/, "");
10306
- const projectDir = dirname5(path2);
10380
+ for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
10381
+ const sessionId = basename4(path3).replace(/\.jsonl$/, "");
10382
+ const projectDir = dirname5(path3);
10307
10383
  const meta = readSidecarMeta(join16(projectDir, `${sessionId}.meta.json`));
10308
10384
  if (!isReaderChannelSession(meta.role, meta.channel)) continue;
10309
10385
  if (multiAccount) {
@@ -10312,7 +10388,7 @@ app5.get("/conversations", requireAdminSession, async (c) => {
10312
10388
  }
10313
10389
  let body = "";
10314
10390
  try {
10315
- body = readFileSync17(path2, "utf8");
10391
+ body = readFileSync17(path3, "utf8");
10316
10392
  } catch {
10317
10393
  }
10318
10394
  const { title } = resolveTitle(body, sessionId, userTitles);
@@ -10395,10 +10471,10 @@ app5.get("/conversations", requireAdminSession, async (c) => {
10395
10471
  );
10396
10472
  return c.json({ conversations: [...sessionConversations, ...allStoreRows] });
10397
10473
  });
10398
- function readFrom(path2, from) {
10399
- const end = statSync5(path2).size;
10474
+ function readFrom(path3, from) {
10475
+ const end = statSync5(path3).size;
10400
10476
  if (end <= from) return { buf: Buffer.alloc(0), end: from };
10401
- const fd = openSync(path2, "r");
10477
+ const fd = openSync(path3, "r");
10402
10478
  try {
10403
10479
  const buf = Buffer.alloc(end - from);
10404
10480
  readSync(fd, buf, 0, buf.length, from);
@@ -10733,11 +10809,11 @@ app5.get("/directive", requireAdminSession, (c) => {
10733
10809
  }
10734
10810
  const dir = directiveStoreDir(sessionId);
10735
10811
  if (!dir) return c.json({ error: "no account" }, 404);
10736
- const path2 = resolve13(join16(dir, name));
10737
- if (!path2.startsWith(dir + sep3)) return c.json({ error: "bad reference" }, 400);
10812
+ const path3 = resolve13(join16(dir, name));
10813
+ if (!path3.startsWith(dir + sep3)) return c.json({ error: "bad reference" }, 400);
10738
10814
  let body;
10739
10815
  try {
10740
- body = readFileSync17(path2, "utf8");
10816
+ body = readFileSync17(path3, "utf8");
10741
10817
  } catch {
10742
10818
  return c.json({ error: "not found" }, 404);
10743
10819
  }
@@ -11214,7 +11290,7 @@ function resolveOpenVisitorSession(rows, visitorId, agentSlug) {
11214
11290
 
11215
11291
  // server/routes/public-reader.ts
11216
11292
  var app6 = new Hono();
11217
- var TAG22 = "[public-webchat]";
11293
+ var TAG23 = "[public-webchat]";
11218
11294
  function parseAccessSessionId(cookieHeader) {
11219
11295
  if (!cookieHeader) return null;
11220
11296
  const part = cookieHeader.split(";").map((p) => p.trim()).find((p) => p.startsWith("__access_session="));
@@ -11241,9 +11317,9 @@ function enumeratePublicRows() {
11241
11317
  const cfg = claudeConfigDir();
11242
11318
  if (!cfg) return [];
11243
11319
  const rows = [];
11244
- for (const { path: path2 } of enumerateJsonls(join17(cfg, "projects"))) {
11245
- const sessionId = basename5(path2).replace(/\.jsonl$/, "");
11246
- const projectDir = dirname6(path2);
11320
+ for (const { path: path3 } of enumerateJsonls(join17(cfg, "projects"))) {
11321
+ const sessionId = basename5(path3).replace(/\.jsonl$/, "");
11322
+ const projectDir = dirname6(path3);
11247
11323
  const meta = readSidecarMeta(join17(projectDir, `${sessionId}.meta.json`));
11248
11324
  rows.push({
11249
11325
  sessionId,
@@ -11262,7 +11338,7 @@ function enumeratePublicRows() {
11262
11338
  app6.get("/session", (c) => {
11263
11339
  const visitor = resolveVisitor(c);
11264
11340
  if (!visitor) {
11265
- console.error(`${TAG22} op=reader-refused reason=no-anchor path=/session`);
11341
+ console.error(`${TAG23} op=reader-refused reason=no-anchor path=/session`);
11266
11342
  return c.json({ error: "gate-required" }, 401);
11267
11343
  }
11268
11344
  const rows = enumeratePublicRows();
@@ -11281,11 +11357,11 @@ app6.get("/session", (c) => {
11281
11357
  found = effectiveSlug ? resolveOpenVisitorSession(rows, visitor.visitorId, effectiveSlug) : null;
11282
11358
  }
11283
11359
  if (found) {
11284
- console.log(`${TAG22} op=session-resume anchor=${visitor.kind} key=${(found.senderId ?? "").slice(0, 8)} sessionId=${found.sessionId.slice(0, 8)}`);
11360
+ console.log(`${TAG23} op=session-resume anchor=${visitor.kind} key=${(found.senderId ?? "").slice(0, 8)} sessionId=${found.sessionId.slice(0, 8)}`);
11285
11361
  return c.json({ sessionId: found.sessionId, projectDir: found.projectDir, sessionKey: found.senderId });
11286
11362
  }
11287
11363
  const sessionKey = crypto.randomUUID();
11288
- console.log(`${TAG22} op=session-new anchor=${visitor.kind} key=${sessionKey.slice(0, 8)}`);
11364
+ console.log(`${TAG23} op=session-new anchor=${visitor.kind} key=${sessionKey.slice(0, 8)}`);
11289
11365
  return c.json({ sessionId: null, projectDir: null, sessionKey });
11290
11366
  });
11291
11367
  function publicUploadsDir(accountId, sessionId) {
@@ -11299,10 +11375,10 @@ function enrichPublicAttachments(turns, sessionAttachments, cursor) {
11299
11375
  if (slice.length > 0) turn.attachments = slice;
11300
11376
  }
11301
11377
  }
11302
- function readFrom2(path2, from) {
11303
- const end = statSync6(path2).size;
11378
+ function readFrom2(path3, from) {
11379
+ const end = statSync6(path3).size;
11304
11380
  if (end <= from) return { buf: Buffer.alloc(0), end: from };
11305
- const fd = openSync2(path2, "r");
11381
+ const fd = openSync2(path3, "r");
11306
11382
  try {
11307
11383
  const buf = Buffer.alloc(end - from);
11308
11384
  readSync2(fd, buf, 0, buf.length, from);
@@ -11314,7 +11390,7 @@ function readFrom2(path2, from) {
11314
11390
  app6.get("/stream", (c) => {
11315
11391
  const visitor = resolveVisitor(c);
11316
11392
  if (!visitor) {
11317
- console.error(`${TAG22} op=reader-refused reason=no-anchor path=/stream`);
11393
+ console.error(`${TAG23} op=reader-refused reason=no-anchor path=/stream`);
11318
11394
  return c.json({ error: "gate-required" }, 401);
11319
11395
  }
11320
11396
  const sessionId = c.req.query("sessionId") ?? "";
@@ -11332,12 +11408,12 @@ app6.get("/stream", (c) => {
11332
11408
  const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
11333
11409
  const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
11334
11410
  if (!(isPublicWebchat && owns)) {
11335
- console.error(`${TAG22} op=reader-refused reason=not-owner anchor=${visitor.kind} sessionId=${sessionId.slice(0, 8)}`);
11411
+ console.error(`${TAG23} op=reader-refused reason=not-owner anchor=${visitor.kind} sessionId=${sessionId.slice(0, 8)}`);
11336
11412
  return c.json({ error: "forbidden" }, 403);
11337
11413
  }
11338
11414
  const senderShort = (meta.senderId ?? "").slice(0, 8);
11339
11415
  const encoder = new TextEncoder();
11340
- console.log(`${TAG22} op=reader-open anchor=${visitor.kind} key=${senderShort} mode=delivered-only sessionId=${sessionId.slice(0, 8)}`);
11416
+ console.log(`${TAG23} op=reader-open anchor=${visitor.kind} key=${senderShort} mode=delivered-only sessionId=${sessionId.slice(0, 8)}`);
11341
11417
  const send = (controller, turn, id) => controller.enqueue(encoder.encode(`id: ${id}
11342
11418
  data: ${JSON.stringify(turn)}
11343
11419
 
@@ -11352,7 +11428,7 @@ data: ${JSON.stringify(turn)}
11352
11428
  const { turns, dropped } = filterDeliveredFrames(lines);
11353
11429
  if (uploadsDir) enrichPublicAttachments(turns, listSessionAttachmentsInDir(uploadsDir), attachmentCursor);
11354
11430
  for (const turn of turns) send(controller, turn, offset);
11355
- if (dropped > 0) console.log(`${TAG22} op=reader-filtered key=${senderShort} dropped=${dropped}`);
11431
+ if (dropped > 0) console.log(`${TAG23} op=reader-filtered key=${senderShort} dropped=${dropped}`);
11356
11432
  };
11357
11433
  try {
11358
11434
  const { buf, end } = readFrom2(jsonlPath, 0);
@@ -11387,7 +11463,7 @@ data: ${JSON.stringify(turn)}
11387
11463
  watcher?.close();
11388
11464
  clearInterval(poll);
11389
11465
  clearInterval(heartbeat);
11390
- console.log(`${TAG22} op=reader-close key=${senderShort}`);
11466
+ console.log(`${TAG23} op=reader-close key=${senderShort}`);
11391
11467
  try {
11392
11468
  controller.close();
11393
11469
  } catch {
@@ -11504,10 +11580,10 @@ function writeCanonicalOverrideId(accountDir, userId, sessionId) {
11504
11580
  }
11505
11581
  }
11506
11582
  byAdmin[userId] = sessionId;
11507
- const path2 = canonicalOverridePath(accountDir);
11508
- const tmp = `${path2}.${process.pid}.tmp`;
11583
+ const path3 = canonicalOverridePath(accountDir);
11584
+ const tmp = `${path3}.${process.pid}.tmp`;
11509
11585
  writeFileSync5(tmp, JSON.stringify({ byAdmin }, null, 2), "utf8");
11510
- renameSync2(tmp, path2);
11586
+ renameSync2(tmp, path3);
11511
11587
  }
11512
11588
 
11513
11589
  // ../lib/models/src/index.ts
@@ -11516,7 +11592,7 @@ var SONNET_MODEL = "claude-sonnet-5";
11516
11592
  var HAIKU_MODEL = "claude-haiku-4-5";
11517
11593
  var MODEL_CONTEXT_WINDOW = {
11518
11594
  [OPUS_MODEL]: 1e6,
11519
- [SONNET_MODEL]: 2e5,
11595
+ [SONNET_MODEL]: 1e6,
11520
11596
  [HAIKU_MODEL]: 2e5
11521
11597
  };
11522
11598
  function contextWindow(model) {
@@ -11566,11 +11642,11 @@ function createSidecarStore(config) {
11566
11642
  }
11567
11643
  function write(sessionsDir, id, record) {
11568
11644
  mkdirSync3(sessionsDir, { recursive: true });
11569
- const path2 = pathFor(sessionsDir, id);
11570
- const tmp = `${path2}.tmp.${process.pid}`;
11645
+ const path3 = pathFor(sessionsDir, id);
11646
+ const tmp = `${path3}.tmp.${process.pid}`;
11571
11647
  try {
11572
11648
  writeFileSync6(tmp, JSON.stringify(record), "utf8");
11573
- renameSync3(tmp, path2);
11649
+ renameSync3(tmp, path3);
11574
11650
  return { ok: true };
11575
11651
  } catch (error) {
11576
11652
  try {
@@ -11580,10 +11656,10 @@ function createSidecarStore(config) {
11580
11656
  return { ok: false, error };
11581
11657
  }
11582
11658
  }
11583
- function readFileAt(path2) {
11659
+ function readFileAt(path3) {
11584
11660
  let raw;
11585
11661
  try {
11586
- raw = readFileSync20(path2, "utf8");
11662
+ raw = readFileSync20(path3, "utf8");
11587
11663
  } catch {
11588
11664
  return null;
11589
11665
  }
@@ -11606,10 +11682,10 @@ function createSidecarStore(config) {
11606
11682
  const out = [];
11607
11683
  for (const name of names) {
11608
11684
  if (!suffixRe.test(name)) continue;
11609
- const path2 = join19(sessionsDir, name);
11685
+ const path3 = join19(sessionsDir, name);
11610
11686
  let raw;
11611
11687
  try {
11612
- raw = readFileSync20(path2, "utf8");
11688
+ raw = readFileSync20(path3, "utf8");
11613
11689
  } catch {
11614
11690
  onSkip?.(name, "unreadable");
11615
11691
  continue;
@@ -11628,10 +11704,10 @@ function createSidecarStore(config) {
11628
11704
  return out;
11629
11705
  }
11630
11706
  function clear(sessionsDir, id) {
11631
- const path2 = pathFor(sessionsDir, id);
11707
+ const path3 = pathFor(sessionsDir, id);
11632
11708
  try {
11633
- if (existsSync12(path2)) {
11634
- unlinkSync2(path2);
11709
+ if (existsSync12(path3)) {
11710
+ unlinkSync2(path3);
11635
11711
  return { ok: true, removed: true };
11636
11712
  }
11637
11713
  return { ok: true, removed: false };
@@ -11860,15 +11936,15 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccoun
11860
11936
  const cfg = claudeConfigDir();
11861
11937
  if (!cfg) return null;
11862
11938
  let best = null;
11863
- for (const { path: path2, isSubagent, archived } of enumerateJsonls(join20(cfg, "projects"))) {
11939
+ for (const { path: path3, isSubagent, archived } of enumerateJsonls(join20(cfg, "projects"))) {
11864
11940
  if (isSubagent || archived) continue;
11865
- const id = basename6(path2).slice(0, -".jsonl".length);
11866
- const meta = readSidecarMeta(join20(dirname7(path2), `${id}.meta.json`));
11941
+ const id = basename6(path3).slice(0, -".jsonl".length);
11942
+ const meta = readSidecarMeta(join20(dirname7(path3), `${id}.meta.json`));
11867
11943
  if (meta.role !== "admin" || meta.channel !== "webchat") continue;
11868
11944
  if (multiAccount && meta.accountId !== scopeAccountId) continue;
11869
11945
  let mtimeMs;
11870
11946
  try {
11871
- mtimeMs = statSync7(path2).mtimeMs;
11947
+ mtimeMs = statSync7(path3).mtimeMs;
11872
11948
  } catch {
11873
11949
  continue;
11874
11950
  }
@@ -12265,9 +12341,9 @@ ${note}` : note;
12265
12341
  const cfg = claudeConfigDir();
12266
12342
  let projectDir = null;
12267
12343
  if (cfg) {
12268
- for (const { path: path2 } of enumerateJsonls(join20(cfg, "projects"))) {
12269
- if (basename6(path2) === `${sessionId}.jsonl`) {
12270
- projectDir = dirname7(path2);
12344
+ for (const { path: path3 } of enumerateJsonls(join20(cfg, "projects"))) {
12345
+ if (basename6(path3) === `${sessionId}.jsonl`) {
12346
+ projectDir = dirname7(path3);
12271
12347
  break;
12272
12348
  }
12273
12349
  }
@@ -12499,7 +12575,7 @@ function routeTelegramUpdate(input) {
12499
12575
  }
12500
12576
 
12501
12577
  // server/routes/telegram.ts
12502
- var TAG23 = "[telegram-inbound]";
12578
+ var TAG24 = "[telegram-inbound]";
12503
12579
  function configDirName() {
12504
12580
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve16(process.cwd(), "..");
12505
12581
  const brandPath = join22(platformRoot5, "config", "brand.json");
@@ -12520,18 +12596,18 @@ app8.post("/", async (c) => {
12520
12596
  const botParam = c.req.query("bot");
12521
12597
  const botType = botParam === "admin" ? "admin" : botParam === "public" ? "public" : null;
12522
12598
  if (!botType) {
12523
- console.error(`${TAG23} op=reject reason=missing-bot-param`);
12599
+ console.error(`${TAG24} op=reject reason=missing-bot-param`);
12524
12600
  return c.json({ ok: false }, 400);
12525
12601
  }
12526
12602
  const sp = secretPath(botType);
12527
12603
  if (!existsSync15(sp)) {
12528
- console.error(`${TAG23} op=reject reason=no-secret-file botType=${botType}`);
12604
+ console.error(`${TAG24} op=reject reason=no-secret-file botType=${botType}`);
12529
12605
  return c.json({ ok: false }, 401);
12530
12606
  }
12531
12607
  const expected = readFileSync23(sp, "utf-8").trim();
12532
12608
  const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
12533
12609
  if (got !== expected) {
12534
- console.error(`${TAG23} op=reject reason=bad-secret botType=${botType}`);
12610
+ console.error(`${TAG24} op=reject reason=bad-secret botType=${botType}`);
12535
12611
  return c.json({ ok: false }, 401);
12536
12612
  }
12537
12613
  let update;
@@ -12542,40 +12618,40 @@ app8.post("/", async (c) => {
12542
12618
  }
12543
12619
  const account = resolveAccount();
12544
12620
  if (!account) {
12545
- console.error(`${TAG23} op=reject reason=no-account`);
12621
+ console.error(`${TAG24} op=reject reason=no-account`);
12546
12622
  return c.json({ ok: true }, 200);
12547
12623
  }
12548
12624
  const decision = routeTelegramUpdate({ update, botType, config: account.config.telegram ?? {} });
12549
12625
  if (decision.kind === "ignore") {
12550
- console.error(`${TAG23} op=ignore reason=${decision.reason}`);
12626
+ console.error(`${TAG24} op=ignore reason=${decision.reason}`);
12551
12627
  return c.json({ ok: true }, 200);
12552
12628
  }
12553
12629
  if (decision.kind === "denied") {
12554
- console.error(`${TAG23} op=denied reason=${decision.reason} agentType=${decision.agentType}`);
12630
+ console.error(`${TAG24} op=denied reason=${decision.reason} agentType=${decision.agentType}`);
12555
12631
  return c.json({ ok: true }, 200);
12556
12632
  }
12557
12633
  const role = decision.agentType === "admin" ? "admin" : "public";
12558
12634
  const agentSlug = role === "admin" ? "admin" : resolveDefaultAgentSlug(account.accountDir);
12559
12635
  if (!agentSlug) {
12560
- console.error(`${TAG23} op=reject reason=no-default-agent`);
12636
+ console.error(`${TAG24} op=reject reason=no-default-agent`);
12561
12637
  return c.json({ ok: true }, 200);
12562
12638
  }
12563
- console.error(`${TAG23} op=update accountId=${account.accountId} from=${decision.senderId}`);
12639
+ console.error(`${TAG24} op=update accountId=${account.accountId} from=${decision.senderId}`);
12564
12640
  const botToken = botType === "admin" ? account.config.telegram?.adminBotToken : account.config.telegram?.publicBotToken;
12565
12641
  const { senderId, chatId, text } = decision;
12566
12642
  const gateway = getTelegramGateway();
12567
12643
  if (!gateway) {
12568
- console.error(`${TAG23} op=reject reason=gateway-not-ready from=${senderId}`);
12644
+ console.error(`${TAG24} op=reject reason=gateway-not-ready from=${senderId}`);
12569
12645
  return c.json({ ok: true }, 200);
12570
12646
  }
12571
12647
  const reply = async (replyText) => {
12572
12648
  if (!botToken) {
12573
12649
  const reason = account.config.telegram ? "no-bot-token" : "no-telegram-config";
12574
- console.error(`${TAG23} op=reply-dropped reason=${reason} botType=${botType} from=${senderId}`);
12650
+ console.error(`${TAG24} op=reply-dropped reason=${reason} botType=${botType} from=${senderId}`);
12575
12651
  return;
12576
12652
  }
12577
12653
  const sent = await sendTelegramText(botToken, chatId, replyText);
12578
- console.error(`${TAG23} op=reply-sent from=${senderId} ok=${sent.ok}${sent.ok ? "" : ` error=${sent.error}`}`);
12654
+ console.error(`${TAG24} op=reply-sent from=${senderId} ok=${sent.ok}${sent.ok ? "" : ` error=${sent.error}`}`);
12579
12655
  };
12580
12656
  void gateway.handleInbound({
12581
12657
  accountId: account.accountId,
@@ -12593,7 +12669,7 @@ var telegram_default = app8;
12593
12669
  // server/routes/quickbooks.ts
12594
12670
  import { join as join23 } from "path";
12595
12671
  import { existsSync as existsSync16, readFileSync as readFileSync24, writeFileSync as writeFileSync8, mkdirSync as mkdirSync4, rmSync, renameSync as renameSync5 } from "fs";
12596
- var TAG24 = "[quickbooks]";
12672
+ var TAG25 = "[quickbooks]";
12597
12673
  var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
12598
12674
  var STATE_RE = /^[A-Za-z0-9_-]+$/;
12599
12675
  function pendingPath(accountDir, state) {
@@ -12606,14 +12682,14 @@ async function completeConsent(args) {
12606
12682
  const { accountDir, code, realmId } = args;
12607
12683
  const state = args.state;
12608
12684
  if (!state || !STATE_RE.test(state) || !existsSync16(pendingPath(accountDir, state))) {
12609
- console.error(`${TAG24} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
12685
+ console.error(`${TAG25} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
12610
12686
  return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
12611
12687
  }
12612
12688
  const claimFile = `${pendingPath(accountDir, state)}.claimed`;
12613
12689
  try {
12614
12690
  renameSync5(pendingPath(accountDir, state), claimFile);
12615
12691
  } catch {
12616
- console.error(`${TAG24} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
12692
+ console.error(`${TAG25} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
12617
12693
  return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
12618
12694
  }
12619
12695
  try {
@@ -12621,14 +12697,14 @@ async function completeConsent(args) {
12621
12697
  try {
12622
12698
  pending = JSON.parse(readFileSync24(claimFile, "utf-8"));
12623
12699
  } catch {
12624
- console.error(`${TAG24} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
12700
+ console.error(`${TAG25} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
12625
12701
  return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
12626
12702
  }
12627
12703
  if (Date.now() > pending.expiresAt) {
12628
- console.error(`${TAG24} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
12704
+ console.error(`${TAG25} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
12629
12705
  return { ok: false, status: 400, message: "Authorization request expired. Generate a new consent link.", stateValid: false };
12630
12706
  }
12631
- console.error(`${TAG24} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
12707
+ console.error(`${TAG25} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
12632
12708
  if (!code || !realmId) {
12633
12709
  return { ok: false, status: 400, message: "Missing code or realmId in the callback.", stateValid: true };
12634
12710
  }
@@ -12652,12 +12728,12 @@ async function completeConsent(args) {
12652
12728
  });
12653
12729
  const text = await res.text();
12654
12730
  if (!res.ok) {
12655
- console.error(`${TAG24} op=token-exchange realmId=${realmId} persisted=false`);
12731
+ console.error(`${TAG25} op=token-exchange realmId=${realmId} persisted=false`);
12656
12732
  return { ok: false, status: 502, message: `Token exchange failed (${res.status}). Generate a new consent link to retry.`, stateValid: true };
12657
12733
  }
12658
12734
  const body = JSON.parse(text);
12659
12735
  if (!body.refresh_token) {
12660
- console.error(`${TAG24} op=token-exchange realmId=${realmId} persisted=false`);
12736
+ console.error(`${TAG25} op=token-exchange realmId=${realmId} persisted=false`);
12661
12737
  return { ok: false, status: 502, message: "Token exchange returned no refresh token.", stateValid: true };
12662
12738
  }
12663
12739
  const now = Date.now();
@@ -12670,7 +12746,7 @@ async function completeConsent(args) {
12670
12746
  mkdirSync4(join23(accountDir, "secrets"), { recursive: true });
12671
12747
  writeFileSync8(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
12672
12748
  const persisted = JSON.parse(readFileSync24(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
12673
- console.error(`${TAG24} op=token-exchange realmId=${realmId} persisted=${persisted}`);
12749
+ console.error(`${TAG25} op=token-exchange realmId=${realmId} persisted=${persisted}`);
12674
12750
  return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
12675
12751
  } finally {
12676
12752
  rmSync(claimFile, { force: true });
@@ -12683,7 +12759,7 @@ var app9 = new Hono();
12683
12759
  app9.get("/callback", async (c) => {
12684
12760
  const account = resolveAccount();
12685
12761
  if (!account) {
12686
- console.error(`${TAG24} op=callback stateValid=false realmId= reason=no-account`);
12762
+ console.error(`${TAG25} op=callback stateValid=false realmId= reason=no-account`);
12687
12763
  return c.html(page("QuickBooks", "This install has no account configured."), 500);
12688
12764
  }
12689
12765
  const result = await completeConsent({
@@ -14875,10 +14951,10 @@ function extractPluginToolDescriptions(pluginDir) {
14875
14951
  join28(pluginDir, "mcp/src/index.ts")
14876
14952
  ];
14877
14953
  let raw = null;
14878
- for (const path2 of candidates) {
14879
- if (!existsSync25(path2)) continue;
14954
+ for (const path3 of candidates) {
14955
+ if (!existsSync25(path3)) continue;
14880
14956
  try {
14881
- raw = readFileSync29(path2, "utf-8");
14957
+ raw = readFileSync29(path3, "utf-8");
14882
14958
  break;
14883
14959
  } catch {
14884
14960
  }
@@ -14968,11 +15044,11 @@ function readEnabledPlugins(accountId) {
14968
15044
  return /* @__PURE__ */ new Set();
14969
15045
  }
14970
15046
  }
14971
- function readFrontmatter(path2) {
14972
- if (!existsSync25(path2)) return null;
15047
+ function readFrontmatter(path3) {
15048
+ if (!existsSync25(path3)) return null;
14973
15049
  let raw;
14974
15050
  try {
14975
- raw = readFileSync29(path2, "utf-8");
15051
+ raw = readFileSync29(path3, "utf-8");
14976
15052
  } catch {
14977
15053
  return null;
14978
15054
  }
@@ -15151,7 +15227,7 @@ function resolveTunnelUrl() {
15151
15227
  if (!state) return null;
15152
15228
  return `https://${hostname2}.${state.domain}`;
15153
15229
  }
15154
- var TAG25 = "[claude-session-manager:wrapper]";
15230
+ var TAG26 = "[claude-session-manager:wrapper]";
15155
15231
  async function refuseIfClaudeAuthDead(c, route, sessionId) {
15156
15232
  const auth = await ensureAuth();
15157
15233
  if (auth.status !== "dead" && auth.status !== "missing") return null;
@@ -15169,12 +15245,12 @@ async function performSpawnWithInitialMessage(args) {
15169
15245
  const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
15170
15246
  const ownerMs = Date.now() - ownerStart;
15171
15247
  const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
15172
- console.log(`${TAG25} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
15248
+ console.log(`${TAG26} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
15173
15249
  const dormantPlugins = computeDormantPlugins(args.senderId);
15174
15250
  const activePlugins = computeActivePlugins(args.senderId);
15175
15251
  const specialistDomains = computeSpecialistDomains(args.senderId);
15176
15252
  const tunnelUrl = resolveTunnelUrl();
15177
- console.log(`${TAG25} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
15253
+ console.log(`${TAG26} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
15178
15254
  const upstreamPayload = JSON.stringify({
15179
15255
  senderId: args.senderId,
15180
15256
  // Task 205 — pass userId through to the manager so it lands as
@@ -15201,24 +15277,24 @@ async function performSpawnWithInitialMessage(args) {
15201
15277
  // unshapely values.
15202
15278
  conversationNodeId: args.conversationNodeId
15203
15279
  });
15204
- console.log(`${TAG25} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
15280
+ console.log(`${TAG26} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
15205
15281
  const forwardStart = Date.now();
15206
15282
  const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
15207
15283
  method: "POST",
15208
15284
  headers: { "content-type": "application/json" },
15209
15285
  body: upstreamPayload
15210
15286
  }).catch((err) => {
15211
- console.error(`${TAG25} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
15287
+ console.error(`${TAG26} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
15212
15288
  return null;
15213
15289
  });
15214
15290
  if (!upstream) return {
15215
15291
  response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
15216
15292
  claudeSessionId: null
15217
15293
  };
15218
- console.log(`${TAG25} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
15294
+ console.log(`${TAG26} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
15219
15295
  if (args.initialMessage) {
15220
15296
  const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
15221
- console.log(`${TAG25} initial-message-inlined bytes=${inputBytes}`);
15297
+ console.log(`${TAG26} initial-message-inlined bytes=${inputBytes}`);
15222
15298
  }
15223
15299
  const bodyText = await upstream.text().catch(() => "");
15224
15300
  let claudeSessionId = null;
@@ -15253,7 +15329,7 @@ app19.post("/", async (c) => {
15253
15329
  if (refusal) return refusal;
15254
15330
  const senderId = getAccountIdForSession(cacheKey) ?? "";
15255
15331
  if (!senderId) {
15256
- console.error(`${TAG25} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
15332
+ console.error(`${TAG26} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
15257
15333
  return c.json({ error: "admin-account-not-resolved" }, 500);
15258
15334
  }
15259
15335
  const userId = getUserIdForSession(cacheKey) ?? void 0;
@@ -15262,7 +15338,7 @@ app19.post("/", async (c) => {
15262
15338
  const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
15263
15339
  const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
15264
15340
  const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
15265
- console.log(`${TAG25} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
15341
+ console.log(`${TAG26} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
15266
15342
  const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
15267
15343
  const { response, claudeSessionId } = await performSpawnWithInitialMessage({
15268
15344
  senderId,
@@ -15281,13 +15357,13 @@ app19.post("/", async (c) => {
15281
15357
  claudeSessionId,
15282
15358
  senderId
15283
15359
  );
15284
- console.log(`${TAG25} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
15360
+ console.log(`${TAG26} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
15285
15361
  return response;
15286
15362
  });
15287
15363
  var claude_sessions_default = app19;
15288
15364
 
15289
15365
  // server/routes/admin/log-ingest.ts
15290
- var TAG26 = "[log-ingest]";
15366
+ var TAG27 = "[log-ingest]";
15291
15367
  var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
15292
15368
  var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
15293
15369
  var MAX_LINE_BYTES = 4096;
@@ -15298,7 +15374,7 @@ function isLoopbackAddr2(addr) {
15298
15374
  app20.post("/", async (c) => {
15299
15375
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
15300
15376
  if (!isLoopbackAddr2(remoteAddr)) {
15301
- console.error(`${TAG26} reject reason=non-loopback remoteAddr=${remoteAddr}`);
15377
+ console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
15302
15378
  return c.json({ error: "log-ingest-loopback-only" }, 403);
15303
15379
  }
15304
15380
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -15307,7 +15383,7 @@ app20.post("/", async (c) => {
15307
15383
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
15308
15384
  const offender = tokens.find((t) => !isLoopbackAddr2(t));
15309
15385
  if (offender !== void 0) {
15310
- console.error(`${TAG26} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
15386
+ console.error(`${TAG27} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
15311
15387
  return c.json({ error: "log-ingest-loopback-only" }, 403);
15312
15388
  }
15313
15389
  }
@@ -15349,18 +15425,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
15349
15425
  ]);
15350
15426
  var app21 = new Hono();
15351
15427
  app21.post("/", async (c) => {
15352
- const TAG46 = "[admin:events]";
15428
+ const TAG47 = "[admin:events]";
15353
15429
  let body;
15354
15430
  try {
15355
15431
  body = await c.req.json();
15356
15432
  } catch (err) {
15357
15433
  const detail = err instanceof Error ? err.message : String(err);
15358
- console.error(`${TAG46} reject reason=body-not-json detail=${detail}`);
15434
+ console.error(`${TAG47} reject reason=body-not-json detail=${detail}`);
15359
15435
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
15360
15436
  }
15361
15437
  const event = typeof body.event === "string" ? body.event : "";
15362
15438
  if (!ALLOWED_EVENTS.has(event)) {
15363
- console.error(`${TAG46} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
15439
+ console.error(`${TAG47} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
15364
15440
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
15365
15441
  }
15366
15442
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -20412,7 +20488,7 @@ function managerLogFollowUrl(sessionId, opts) {
20412
20488
  }
20413
20489
 
20414
20490
  // server/routes/admin/linkedin-ingest.ts
20415
- var TAG27 = "[linkedin-ingest-route]";
20491
+ var TAG28 = "[linkedin-ingest-route]";
20416
20492
  var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
20417
20493
  var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
20418
20494
  var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
@@ -20516,29 +20592,29 @@ app39.post("/", requireAdminSession, async (c) => {
20516
20592
  try {
20517
20593
  body = await c.req.json();
20518
20594
  } catch {
20519
- console.error(TAG27 + " rejected status=400 reason=schema:body-not-json");
20595
+ console.error(TAG28 + " rejected status=400 reason=schema:body-not-json");
20520
20596
  return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
20521
20597
  }
20522
20598
  const v = validate(body);
20523
20599
  if (!v.ok) {
20524
- console.error(TAG27 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
20600
+ console.error(TAG28 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
20525
20601
  return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
20526
20602
  }
20527
20603
  const envelope = v.envelope;
20528
20604
  const cacheKey = c.var.cacheKey ?? "";
20529
20605
  const senderId = getAccountIdForSession(cacheKey) ?? "";
20530
20606
  if (!senderId) {
20531
- console.error(TAG27 + " rejected status=500 reason=admin-account-not-resolved");
20607
+ console.error(TAG28 + " rejected status=500 reason=admin-account-not-resolved");
20532
20608
  return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
20533
20609
  }
20534
20610
  const payloadBytes = JSON.stringify(envelope).length;
20535
20611
  console.log(
20536
- TAG27 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
20612
+ TAG28 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
20537
20613
  );
20538
20614
  const initialMessage = buildInitialMessage(envelope);
20539
20615
  const spawnStart = Date.now();
20540
20616
  const sessionId = randomUUID13();
20541
- console.log(TAG27 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
20617
+ console.log(TAG28 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
20542
20618
  const spawned = await managerRcSpawn({
20543
20619
  sessionId,
20544
20620
  initialMessage,
@@ -20547,12 +20623,12 @@ app39.post("/", requireAdminSession, async (c) => {
20547
20623
  });
20548
20624
  if ("error" in spawned) {
20549
20625
  console.error(
20550
- TAG27 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
20626
+ TAG28 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
20551
20627
  );
20552
20628
  return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
20553
20629
  }
20554
20630
  console.log(
20555
- TAG27 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
20631
+ TAG28 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
20556
20632
  );
20557
20633
  return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
20558
20634
  });
@@ -20560,7 +20636,7 @@ var linkedin_ingest_default = app39;
20560
20636
 
20561
20637
  // server/routes/admin/post-turn-context.ts
20562
20638
  import neo4j3 from "neo4j-driver";
20563
- var TAG28 = "[post-turn-context]";
20639
+ var TAG29 = "[post-turn-context]";
20564
20640
  var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
20565
20641
  "embedding",
20566
20642
  "passwordHash",
@@ -20602,7 +20678,7 @@ var app40 = new Hono();
20602
20678
  app40.get("/", async (c) => {
20603
20679
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
20604
20680
  if (!isLoopbackAddr3(remoteAddr)) {
20605
- console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20681
+ console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20606
20682
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
20607
20683
  }
20608
20684
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -20611,7 +20687,7 @@ app40.get("/", async (c) => {
20611
20687
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
20612
20688
  const offender = tokens.find((t) => !isLoopbackAddr3(t));
20613
20689
  if (offender !== void 0) {
20614
- console.error(`${TAG28} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20690
+ console.error(`${TAG29} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20615
20691
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
20616
20692
  }
20617
20693
  }
@@ -20643,7 +20719,7 @@ app40.get("/", async (c) => {
20643
20719
  writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
20644
20720
  const total = Date.now() - started;
20645
20721
  console.log(
20646
- `${TAG28} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
20722
+ `${TAG29} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
20647
20723
  );
20648
20724
  return c.json({
20649
20725
  writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
@@ -20652,7 +20728,7 @@ app40.get("/", async (c) => {
20652
20728
  const elapsed = Date.now() - started;
20653
20729
  const message = err instanceof Error ? err.message : String(err);
20654
20730
  console.error(
20655
- `${TAG28} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
20731
+ `${TAG29} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
20656
20732
  );
20657
20733
  return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
20658
20734
  } finally {
@@ -20765,7 +20841,7 @@ function formatPreviousContext(writes) {
20765
20841
  }
20766
20842
 
20767
20843
  // server/routes/admin/public-session-context.ts
20768
- var TAG29 = "[public-session-context]";
20844
+ var TAG30 = "[public-session-context]";
20769
20845
  function isLoopbackAddr4(addr) {
20770
20846
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
20771
20847
  }
@@ -20773,7 +20849,7 @@ var app41 = new Hono();
20773
20849
  app41.get("/", async (c) => {
20774
20850
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
20775
20851
  if (!isLoopbackAddr4(remoteAddr)) {
20776
- console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20852
+ console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20777
20853
  return c.json({ error: "public-session-context-loopback-only" }, 403);
20778
20854
  }
20779
20855
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -20782,7 +20858,7 @@ app41.get("/", async (c) => {
20782
20858
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
20783
20859
  const offender = tokens.find((t) => !isLoopbackAddr4(t));
20784
20860
  if (offender !== void 0) {
20785
- console.error(`${TAG29} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20861
+ console.error(`${TAG30} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20786
20862
  return c.json({ error: "public-session-context-loopback-only" }, 403);
20787
20863
  }
20788
20864
  }
@@ -20796,14 +20872,14 @@ app41.get("/", async (c) => {
20796
20872
  const writes = await fetchSliceWrites(session, sliceToken, accountId);
20797
20873
  const total = Date.now() - started;
20798
20874
  console.log(
20799
- `${TAG29} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
20875
+ `${TAG30} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
20800
20876
  );
20801
20877
  return c.json({ writes });
20802
20878
  } catch (err) {
20803
20879
  const elapsed = Date.now() - started;
20804
20880
  const message = err instanceof Error ? err.message : String(err);
20805
20881
  console.error(
20806
- `${TAG29} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
20882
+ `${TAG30} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
20807
20883
  );
20808
20884
  return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
20809
20885
  } finally {
@@ -20822,7 +20898,7 @@ function getWebchatGateway() {
20822
20898
  }
20823
20899
 
20824
20900
  // server/routes/admin/public-session-exit.ts
20825
- var TAG30 = "[public-session-exit-route]";
20901
+ var TAG31 = "[public-session-exit-route]";
20826
20902
  function isLoopbackAddr5(addr) {
20827
20903
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
20828
20904
  }
@@ -20830,7 +20906,7 @@ var app42 = new Hono();
20830
20906
  app42.post("/", async (c) => {
20831
20907
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
20832
20908
  if (!isLoopbackAddr5(remoteAddr)) {
20833
- console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20909
+ console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20834
20910
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
20835
20911
  }
20836
20912
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -20839,7 +20915,7 @@ app42.post("/", async (c) => {
20839
20915
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
20840
20916
  const offender = tokens.find((t) => !isLoopbackAddr5(t));
20841
20917
  if (offender !== void 0) {
20842
- console.error(`${TAG30} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20918
+ console.error(`${TAG31} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20843
20919
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
20844
20920
  }
20845
20921
  }
@@ -20853,7 +20929,7 @@ app42.post("/", async (c) => {
20853
20929
  if (!sessionId) return c.json({ error: "sessionId required" }, 400);
20854
20930
  const gateway = getWebchatGateway();
20855
20931
  if (!gateway) {
20856
- console.error(`${TAG30} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
20932
+ console.error(`${TAG31} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
20857
20933
  return c.json({ error: "webchat-gateway-unset" }, 503);
20858
20934
  }
20859
20935
  gateway.handlePublicSessionExit(sessionId);
@@ -20862,7 +20938,7 @@ app42.post("/", async (c) => {
20862
20938
  var public_session_exit_default = app42;
20863
20939
 
20864
20940
  // server/routes/admin/access-session-evict.ts
20865
- var TAG31 = "[access-session-evict]";
20941
+ var TAG32 = "[access-session-evict]";
20866
20942
  function isLoopbackAddr6(addr) {
20867
20943
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
20868
20944
  }
@@ -20870,7 +20946,7 @@ var app43 = new Hono();
20870
20946
  app43.post("/", async (c) => {
20871
20947
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
20872
20948
  if (!isLoopbackAddr6(remoteAddr)) {
20873
- console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20949
+ console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20874
20950
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
20875
20951
  }
20876
20952
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -20879,7 +20955,7 @@ app43.post("/", async (c) => {
20879
20955
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
20880
20956
  const offender = tokens.find((t) => !isLoopbackAddr6(t));
20881
20957
  if (offender !== void 0) {
20882
- console.error(`${TAG31} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20958
+ console.error(`${TAG32} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20883
20959
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
20884
20960
  }
20885
20961
  }
@@ -20892,13 +20968,13 @@ app43.post("/", async (c) => {
20892
20968
  const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
20893
20969
  if (!grantId) return c.json({ error: "grantId required" }, 400);
20894
20970
  const dropped = evictAccessSessionsByGrant(grantId);
20895
- console.log(`${TAG31} grantId=${grantId} dropped=${dropped}`);
20971
+ console.log(`${TAG32} grantId=${grantId} dropped=${dropped}`);
20896
20972
  return c.json({ ok: true, dropped });
20897
20973
  });
20898
20974
  var access_session_evict_default = app43;
20899
20975
 
20900
20976
  // server/routes/admin/enrol-person.ts
20901
- var TAG32 = "[enrol]";
20977
+ var TAG33 = "[enrol]";
20902
20978
  function isLoopbackAddr7(addr) {
20903
20979
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
20904
20980
  }
@@ -20907,7 +20983,7 @@ var app44 = new Hono();
20907
20983
  app44.post("/", async (c) => {
20908
20984
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
20909
20985
  if (!isLoopbackAddr7(remoteAddr)) {
20910
- console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20986
+ console.error(`${TAG33} reject reason=non-loopback remoteAddr=${remoteAddr}`);
20911
20987
  return c.json({ error: "enrol-person-loopback-only" }, 403);
20912
20988
  }
20913
20989
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -20916,7 +20992,7 @@ app44.post("/", async (c) => {
20916
20992
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
20917
20993
  const offender = tokens.find((t) => !isLoopbackAddr7(t));
20918
20994
  if (offender !== void 0) {
20919
- console.error(`${TAG32} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20995
+ console.error(`${TAG33} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
20920
20996
  return c.json({ error: "enrol-person-loopback-only" }, 403);
20921
20997
  }
20922
20998
  }
@@ -20941,7 +21017,7 @@ app44.post("/", async (c) => {
20941
21017
  }
20942
21018
  const accountId = process.env.ACCOUNT_ID ?? "";
20943
21019
  if (!accountId) {
20944
- console.error(`${TAG32} op=person result=no-account-id`);
21020
+ console.error(`${TAG33} op=person result=no-account-id`);
20945
21021
  return c.json({ error: "no-account-id" }, 500);
20946
21022
  }
20947
21023
  let personId;
@@ -20949,7 +21025,7 @@ app44.post("/", async (c) => {
20949
21025
  personId = await enrolPerson({ accountId, phone, email, agentSlug });
20950
21026
  } catch (err) {
20951
21027
  console.error(
20952
- `${TAG32} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
21028
+ `${TAG33} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
20953
21029
  );
20954
21030
  return c.json({ error: "enrol-failed" }, 500);
20955
21031
  }
@@ -20959,11 +21035,11 @@ app44.post("/", async (c) => {
20959
21035
  if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
20960
21036
  } catch (err) {
20961
21037
  console.error(
20962
- `${TAG32} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
21038
+ `${TAG33} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
20963
21039
  );
20964
21040
  }
20965
21041
  console.log(
20966
- `${TAG32} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
21042
+ `${TAG33} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
20967
21043
  );
20968
21044
  return c.json({ personId, grant }, 200);
20969
21045
  });
@@ -21119,33 +21195,33 @@ var REQUIRED_KEYS = [
21119
21195
  "weekly"
21120
21196
  ];
21121
21197
  function readAvailabilityConfig(accountDir) {
21122
- const path2 = join33(accountDir, AVAILABILITY_FILENAME);
21198
+ const path3 = join33(accountDir, AVAILABILITY_FILENAME);
21123
21199
  let raw;
21124
21200
  try {
21125
- raw = readFileSync33(path2, "utf-8");
21201
+ raw = readFileSync33(path3, "utf-8");
21126
21202
  } catch {
21127
- throw new Error(`availability not configured: ${path2} not found`);
21203
+ throw new Error(`availability not configured: ${path3} not found`);
21128
21204
  }
21129
21205
  let parsed;
21130
21206
  try {
21131
21207
  parsed = JSON.parse(raw);
21132
21208
  } catch (err) {
21133
- throw new Error(`invalid JSON in ${path2}: ${err.message}`);
21209
+ throw new Error(`invalid JSON in ${path3}: ${err.message}`);
21134
21210
  }
21135
21211
  const cfg = parsed;
21136
21212
  for (const key of REQUIRED_KEYS) {
21137
21213
  if (cfg[key] === void 0 || cfg[key] === null) {
21138
- throw new Error(`availability config ${path2} missing required key: ${key}`);
21214
+ throw new Error(`availability config ${path3} missing required key: ${key}`);
21139
21215
  }
21140
21216
  }
21141
21217
  if (cfg.daysAhead !== void 0 && cfg.daysAhead !== null) {
21142
21218
  if (typeof cfg.daysAhead !== "number" || !Number.isInteger(cfg.daysAhead) || cfg.daysAhead < 1) {
21143
- throw new Error(`availability config ${path2} invalid daysAhead: must be a positive integer`);
21219
+ throw new Error(`availability config ${path3} invalid daysAhead: must be a positive integer`);
21144
21220
  }
21145
21221
  }
21146
21222
  if (cfg.allowMultiSlot !== void 0 && cfg.allowMultiSlot !== null) {
21147
21223
  if (typeof cfg.allowMultiSlot !== "boolean") {
21148
- throw new Error(`availability config ${path2} invalid allowMultiSlot: must be a boolean`);
21224
+ throw new Error(`availability config ${path3} invalid allowMultiSlot: must be a boolean`);
21149
21225
  }
21150
21226
  }
21151
21227
  return cfg;
@@ -21517,7 +21593,7 @@ function toNum(v) {
21517
21593
  }
21518
21594
 
21519
21595
  // server/routes/admin/tasks-list.ts
21520
- var TAG33 = "[task-timer]";
21596
+ var TAG34 = "[task-timer]";
21521
21597
  var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
21522
21598
  var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
21523
21599
  var app47 = new Hono();
@@ -21525,7 +21601,7 @@ app47.get("/", requireAdminSession, async (c) => {
21525
21601
  const cacheKey = c.var.cacheKey;
21526
21602
  const accountId = getAccountIdForSession(cacheKey);
21527
21603
  if (!accountId) {
21528
- console.error(`${TAG33} op=list auth-rejected reason="no account for session"`);
21604
+ console.error(`${TAG34} op=list auth-rejected reason="no account for session"`);
21529
21605
  return c.json({ error: "Account not found for session" }, 401);
21530
21606
  }
21531
21607
  const session = getSession();
@@ -21563,10 +21639,10 @@ app47.get("/", requireAdminSession, async (c) => {
21563
21639
  if (COMPLETED.has(status)) completed.push(row);
21564
21640
  else if (!HIDDEN_FROM_OPEN.has(status)) open.push(row);
21565
21641
  }
21566
- console.log(`${TAG33} op=list account=${accountId} open=${open.length} completed=${completed.length}`);
21642
+ console.log(`${TAG34} op=list account=${accountId} open=${open.length} completed=${completed.length}`);
21567
21643
  return c.json({ open, completed });
21568
21644
  } catch (err) {
21569
- console.error(`${TAG33} op=list error="${err instanceof Error ? err.message : String(err)}"`);
21645
+ console.error(`${TAG34} op=list error="${err instanceof Error ? err.message : String(err)}"`);
21570
21646
  return c.json({ error: "tasks-list-failed" }, 500);
21571
21647
  } finally {
21572
21648
  await session.close();
@@ -21576,7 +21652,7 @@ var tasks_list_default = app47;
21576
21652
 
21577
21653
  // server/routes/admin/task-timer-start.ts
21578
21654
  import { randomUUID as randomUUID14 } from "crypto";
21579
- var TAG34 = "[task-timer]";
21655
+ var TAG35 = "[task-timer]";
21580
21656
  var app48 = new Hono();
21581
21657
  app48.post("/", requireAdminSession, async (c) => {
21582
21658
  const cacheKey = c.var.cacheKey;
@@ -21598,7 +21674,7 @@ app48.post("/", requireAdminSession, async (c) => {
21598
21674
  { taskId, accountId }
21599
21675
  );
21600
21676
  if (target.records.length === 0) {
21601
- console.error(`${TAG34} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
21677
+ console.error(`${TAG35} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
21602
21678
  return c.json({ error: "task-not-found" }, 404);
21603
21679
  }
21604
21680
  const open = await session.run(
@@ -21610,7 +21686,7 @@ app48.post("/", requireAdminSession, async (c) => {
21610
21686
  const priorEntryId = open.records[0]?.get("entryId");
21611
21687
  const priorStartedAt = open.records[0]?.get("startedAt");
21612
21688
  if (priorEntryId) {
21613
- console.log(`${TAG34} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
21689
+ console.log(`${TAG35} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
21614
21690
  return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
21615
21691
  }
21616
21692
  const entryId = randomUUID14();
@@ -21620,10 +21696,10 @@ app48.post("/", requireAdminSession, async (c) => {
21620
21696
  CREATE (te)-[:LOGGED_AGAINST]->(t)`,
21621
21697
  { taskId, accountId, entryId, now }
21622
21698
  );
21623
- console.log(`${TAG34} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
21699
+ console.log(`${TAG35} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
21624
21700
  return c.json({ ok: true, running: true, entryId, startedAt: now });
21625
21701
  } catch (err) {
21626
- console.error(`${TAG34} op=start error="${err instanceof Error ? err.message : String(err)}"`);
21702
+ console.error(`${TAG35} op=start error="${err instanceof Error ? err.message : String(err)}"`);
21627
21703
  return c.json({ error: "task-timer-start-failed" }, 500);
21628
21704
  } finally {
21629
21705
  await session.close();
@@ -21633,7 +21709,7 @@ var task_timer_start_default = app48;
21633
21709
 
21634
21710
  // server/routes/admin/task-timer-stop.ts
21635
21711
  import neo4j5 from "neo4j-driver";
21636
- var TAG35 = "[task-timer]";
21712
+ var TAG36 = "[task-timer]";
21637
21713
  var app49 = new Hono();
21638
21714
  app49.post("/", requireAdminSession, async (c) => {
21639
21715
  const cacheKey = c.var.cacheKey;
@@ -21665,7 +21741,7 @@ app49.post("/", requireAdminSession, async (c) => {
21665
21741
  { taskId, accountId }
21666
21742
  );
21667
21743
  const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
21668
- console.log(`${TAG35} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
21744
+ console.log(`${TAG36} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
21669
21745
  return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
21670
21746
  }
21671
21747
  const seconds = secondsBetween(startedAt, now);
@@ -21688,11 +21764,11 @@ app49.post("/", requireAdminSession, async (c) => {
21688
21764
  const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
21689
21765
  const sumAdjustments = toNum(verify.records[0]?.get("sumAdjustments"));
21690
21766
  const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
21691
- console.log(`${TAG35} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
21692
- console.log(`${TAG35} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
21767
+ console.log(`${TAG36} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
21768
+ console.log(`${TAG36} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
21693
21769
  return c.json({ ok: true, running: false, seconds, secondsLogged });
21694
21770
  } catch (err) {
21695
- console.error(`${TAG35} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
21771
+ console.error(`${TAG36} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
21696
21772
  return c.json({ error: "task-timer-stop-failed" }, 500);
21697
21773
  } finally {
21698
21774
  await session.close();
@@ -21701,7 +21777,7 @@ app49.post("/", requireAdminSession, async (c) => {
21701
21777
  var task_timer_stop_default = app49;
21702
21778
 
21703
21779
  // server/routes/admin/task-complete.ts
21704
- var TAG36 = "[task-timer]";
21780
+ var TAG37 = "[task-timer]";
21705
21781
  var app50 = new Hono();
21706
21782
  app50.post("/", requireAdminSession, async (c) => {
21707
21783
  const cacheKey = c.var.cacheKey;
@@ -21728,10 +21804,10 @@ app50.post("/", requireAdminSession, async (c) => {
21728
21804
  return c.json({ error: "task-not-found" }, 404);
21729
21805
  }
21730
21806
  const secondsLogged = toNum(result.records[0].get("secondsLogged"));
21731
- console.log(`${TAG36} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
21807
+ console.log(`${TAG37} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
21732
21808
  return c.json({ ok: true, status: "completed", secondsLogged });
21733
21809
  } catch (err) {
21734
- console.error(`${TAG36} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
21810
+ console.error(`${TAG37} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
21735
21811
  return c.json({ error: "task-complete-failed" }, 500);
21736
21812
  } finally {
21737
21813
  await session.close();
@@ -21742,7 +21818,7 @@ var task_complete_default = app50;
21742
21818
  // server/routes/admin/task-time-adjust.ts
21743
21819
  import { randomUUID as randomUUID15 } from "crypto";
21744
21820
  import neo4j6 from "neo4j-driver";
21745
- var TAG37 = "[task-time-adjust]";
21821
+ var TAG38 = "[task-time-adjust]";
21746
21822
  var app51 = new Hono();
21747
21823
  app51.post("/", requireAdminSession, async (c) => {
21748
21824
  const cacheKey = c.var.cacheKey;
@@ -21752,22 +21828,22 @@ app51.post("/", requireAdminSession, async (c) => {
21752
21828
  try {
21753
21829
  body = await c.req.json();
21754
21830
  } catch {
21755
- console.error(`${TAG37} op=reject reason=bad-json`);
21831
+ console.error(`${TAG38} op=reject reason=bad-json`);
21756
21832
  return c.json({ error: "invalid-json" }, 400);
21757
21833
  }
21758
21834
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
21759
21835
  if (!taskId) {
21760
- console.error(`${TAG37} op=reject reason=no-task`);
21836
+ console.error(`${TAG38} op=reject reason=no-task`);
21761
21837
  return c.json({ error: "taskId required" }, 400);
21762
21838
  }
21763
21839
  const newSeconds = body.newSeconds;
21764
21840
  if (typeof newSeconds !== "number" || !Number.isInteger(newSeconds) || newSeconds < 0) {
21765
- console.error(`${TAG37} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
21841
+ console.error(`${TAG38} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
21766
21842
  return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
21767
21843
  }
21768
21844
  const adjustmentId = randomUUID15();
21769
21845
  const now = (/* @__PURE__ */ new Date()).toISOString();
21770
- console.log(`${TAG37} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
21846
+ console.log(`${TAG38} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
21771
21847
  const session = getSession();
21772
21848
  try {
21773
21849
  const guard = await session.run(
@@ -21777,12 +21853,12 @@ app51.post("/", requireAdminSession, async (c) => {
21777
21853
  { taskId, accountId }
21778
21854
  );
21779
21855
  if (guard.records.length === 0) {
21780
- console.error(`${TAG37} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
21856
+ console.error(`${TAG38} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
21781
21857
  return c.json({ error: "task-not-found" }, 404);
21782
21858
  }
21783
21859
  const openCount = toNum(guard.records[0].get("openCount"));
21784
21860
  if (openCount > 0) {
21785
- console.error(`${TAG37} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
21861
+ console.error(`${TAG38} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
21786
21862
  return c.json({ error: "task-timer-running" }, 409);
21787
21863
  }
21788
21864
  const previousSeconds = toNum(guard.records[0].get("previousSeconds"));
@@ -21808,10 +21884,10 @@ app51.post("/", requireAdminSession, async (c) => {
21808
21884
  }
21809
21885
  );
21810
21886
  const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
21811
- console.log(`${TAG37} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
21887
+ console.log(`${TAG38} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
21812
21888
  return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
21813
21889
  } catch (err) {
21814
- console.error(`${TAG37} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
21890
+ console.error(`${TAG38} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
21815
21891
  return c.json({ error: "task-time-adjust-failed" }, 500);
21816
21892
  } finally {
21817
21893
  await session.close();
@@ -21865,7 +21941,7 @@ app52.route("/task-time-adjust", task_time_adjust_default);
21865
21941
  var admin_default = app52;
21866
21942
 
21867
21943
  // server/routes/access/verify-token.ts
21868
- var TAG38 = "[access-verify]";
21944
+ var TAG39 = "[access-verify]";
21869
21945
  var MINT_TAG = "[access-session-mint]";
21870
21946
  var COOKIE_NAME = "__access_session";
21871
21947
  var app53 = new Hono();
@@ -21884,39 +21960,39 @@ app53.post("/", async (c) => {
21884
21960
  }
21885
21961
  const rateMsg = checkAccessRateLimit(ip, agentSlug);
21886
21962
  if (rateMsg) {
21887
- console.error(`${TAG38} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
21963
+ console.error(`${TAG39} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
21888
21964
  return c.json({ error: rateMsg }, 429);
21889
21965
  }
21890
21966
  const grant = await findGrantByMagicToken(token);
21891
21967
  if (!grant) {
21892
21968
  recordAccessFailedAttempt(ip, agentSlug);
21893
- console.error(`${TAG38} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
21969
+ console.error(`${TAG39} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
21894
21970
  return c.json({ error: "invalid-or-expired-link" }, 401);
21895
21971
  }
21896
21972
  if (grant.agentSlug !== agentSlug) {
21897
21973
  recordAccessFailedAttempt(ip, agentSlug);
21898
21974
  console.error(
21899
- `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
21975
+ `${TAG39} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
21900
21976
  );
21901
21977
  return c.json({ error: "invalid-or-expired-link" }, 401);
21902
21978
  }
21903
21979
  if (grant.status === "expired" || grant.status === "revoked") {
21904
21980
  recordAccessFailedAttempt(ip, agentSlug);
21905
21981
  console.error(
21906
- `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
21982
+ `${TAG39} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
21907
21983
  );
21908
21984
  return c.json({ error: "access-no-longer-valid" }, 401);
21909
21985
  }
21910
21986
  if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
21911
21987
  recordAccessFailedAttempt(ip, agentSlug);
21912
21988
  console.error(
21913
- `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
21989
+ `${TAG39} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
21914
21990
  );
21915
21991
  return c.json({ error: "access-no-longer-valid" }, 401);
21916
21992
  }
21917
21993
  if (!grant.sliceToken) {
21918
21994
  console.error(
21919
- `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
21995
+ `${TAG39} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
21920
21996
  );
21921
21997
  return c.json({ error: "grant-misconfigured" }, 500);
21922
21998
  }
@@ -21932,12 +22008,12 @@ app53.post("/", async (c) => {
21932
22008
  await consumeMagicTokenAndActivate(grant.grantId);
21933
22009
  } catch (err) {
21934
22010
  console.error(
21935
- `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
22011
+ `${TAG39} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
21936
22012
  );
21937
22013
  return c.json({ error: "verification-failed" }, 500);
21938
22014
  }
21939
22015
  clearAccessRateLimit(ip, agentSlug);
21940
- console.log(`${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
22016
+ console.log(`${TAG39} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
21941
22017
  console.log(
21942
22018
  `${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
21943
22019
  );
@@ -22013,7 +22089,7 @@ async function sendMagicLinkEmail(payload) {
22013
22089
  }
22014
22090
 
22015
22091
  // server/routes/access/request-magic-link.ts
22016
- var TAG39 = "[access-request-link]";
22092
+ var TAG40 = "[access-request-link]";
22017
22093
  var app54 = new Hono();
22018
22094
  var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
22019
22095
  app54.post("/", async (c) => {
@@ -22030,18 +22106,18 @@ app54.post("/", async (c) => {
22030
22106
  }
22031
22107
  const rateMsg = checkRequestLinkRateLimit(contactValue);
22032
22108
  if (rateMsg) {
22033
- console.error(`${TAG39} contactValue=${maskContact(contactValue)} result=rate-limited`);
22109
+ console.error(`${TAG40} contactValue=${maskContact(contactValue)} result=rate-limited`);
22034
22110
  return c.json({ error: rateMsg }, 429);
22035
22111
  }
22036
22112
  recordRequestLinkAttempt(contactValue);
22037
22113
  const accountId = process.env.ACCOUNT_ID ?? "";
22038
22114
  if (!accountId) {
22039
- console.error(`${TAG39} contactValue=${maskContact(contactValue)} result=no-account-id`);
22115
+ console.error(`${TAG40} contactValue=${maskContact(contactValue)} result=no-account-id`);
22040
22116
  return c.json({ message: VISITOR_MESSAGE }, 200);
22041
22117
  }
22042
22118
  const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
22043
22119
  if (!grant) {
22044
- console.log(`${TAG39} contactValue=${maskContact(contactValue)} result=notfound`);
22120
+ console.log(`${TAG40} contactValue=${maskContact(contactValue)} result=notfound`);
22045
22121
  return c.json({ message: VISITOR_MESSAGE }, 200);
22046
22122
  }
22047
22123
  let token;
@@ -22049,7 +22125,7 @@ app54.post("/", async (c) => {
22049
22125
  token = await generateNewMagicToken(grant.grantId);
22050
22126
  } catch (err) {
22051
22127
  console.error(
22052
- `${TAG39} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
22128
+ `${TAG40} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
22053
22129
  );
22054
22130
  return c.json({ message: VISITOR_MESSAGE }, 200);
22055
22131
  }
@@ -22081,12 +22157,12 @@ app54.post("/", async (c) => {
22081
22157
  });
22082
22158
  if (!sendResult.ok) {
22083
22159
  console.error(
22084
- `${TAG39} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
22160
+ `${TAG40} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
22085
22161
  );
22086
22162
  return c.json({ message: VISITOR_MESSAGE }, 200);
22087
22163
  }
22088
22164
  console.log(
22089
- `${TAG39} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
22165
+ `${TAG40} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
22090
22166
  );
22091
22167
  return c.json({ message: VISITOR_MESSAGE }, 200);
22092
22168
  });
@@ -23148,7 +23224,7 @@ app61.get("/free-busy", async (c) => {
23148
23224
  var calendar_public_default = app61;
23149
23225
 
23150
23226
  // app/lib/timeentry-census.ts
23151
- var TAG40 = "[timeentry-census]";
23227
+ var TAG41 = "[timeentry-census]";
23152
23228
  function reconcileTimeEntries(rows, now, horizonMs) {
23153
23229
  const openEntries = rows.openEntries.length;
23154
23230
  let oldestOpenAgeMs = 0;
@@ -23188,12 +23264,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
23188
23264
  sumAdjustments: toNum(r.get("sumAdjustments"))
23189
23265
  }));
23190
23266
  const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
23191
- const line = `${TAG40} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
23267
+ const line = `${TAG41} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
23192
23268
  if (finding.alarm) console.error(`${line} alarm=true`);
23193
23269
  else console.log(line);
23194
23270
  return finding;
23195
23271
  } catch (err) {
23196
- console.error(`${TAG40} error="${err instanceof Error ? err.message : String(err)}"`);
23272
+ console.error(`${TAG41} error="${err instanceof Error ? err.message : String(err)}"`);
23197
23273
  return null;
23198
23274
  }
23199
23275
  }
@@ -23207,13 +23283,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
23207
23283
  try {
23208
23284
  session = openSession();
23209
23285
  } catch (err) {
23210
- console.error(`${TAG40} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
23286
+ console.error(`${TAG41} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
23211
23287
  return;
23212
23288
  }
23213
23289
  try {
23214
23290
  await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
23215
23291
  } catch (err) {
23216
- console.error(`${TAG40} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
23292
+ console.error(`${TAG41} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
23217
23293
  } finally {
23218
23294
  try {
23219
23295
  await session.close();
@@ -23585,10 +23661,10 @@ var defaultResolveName = async (_accountId, userId) => {
23585
23661
  const res = await loadAdminUserName(userId);
23586
23662
  return res.source === "neo4j" && res.joined.length > 0 ? res.joined : null;
23587
23663
  };
23588
- async function readRaw2(path2) {
23664
+ async function readRaw2(path3) {
23589
23665
  let raw;
23590
23666
  try {
23591
- raw = await readFile6(path2, "utf8");
23667
+ raw = await readFile6(path3, "utf8");
23592
23668
  } catch {
23593
23669
  return null;
23594
23670
  }
@@ -23599,11 +23675,11 @@ async function readRaw2(path2) {
23599
23675
  return null;
23600
23676
  }
23601
23677
  }
23602
- async function writeRaw(path2, obj) {
23603
- const tmp = `${path2}.tmp.${process.pid}.${Date.now()}`;
23678
+ async function writeRaw(path3, obj) {
23679
+ const tmp = `${path3}.tmp.${process.pid}.${Date.now()}`;
23604
23680
  try {
23605
23681
  await writeFile4(tmp, JSON.stringify(obj, null, 2), "utf8");
23606
- await rename3(tmp, path2);
23682
+ await rename3(tmp, path3);
23607
23683
  } catch (err) {
23608
23684
  try {
23609
23685
  if (existsSync34(tmp)) await unlink3(tmp);
@@ -23648,8 +23724,8 @@ async function collectLiveSidecars(projectsRoot) {
23648
23724
  }
23649
23725
  return out;
23650
23726
  }
23651
- function shortId(path2) {
23652
- const base = path2.slice(path2.lastIndexOf("/") + 1).replace(/\.meta\.json$/, "");
23727
+ function shortId(path3) {
23728
+ const base = path3.slice(path3.lastIndexOf("/") + 1).replace(/\.meta\.json$/, "");
23653
23729
  return base.slice(0, 8);
23654
23730
  }
23655
23731
  async function migrateAdminWebchatSidecars(opts = {}) {
@@ -23692,8 +23768,8 @@ async function migrateAdminWebchatSidecars(opts = {}) {
23692
23768
  }
23693
23769
  };
23694
23770
  const sidecars = await collectLiveSidecars(projectsRoot);
23695
- for (const path2 of sidecars) {
23696
- const raw = await readRaw2(path2);
23771
+ for (const path3 of sidecars) {
23772
+ const raw = await readRaw2(path3);
23697
23773
  if (!raw) continue;
23698
23774
  if (raw.role !== ADMIN_ROLE2 || raw.channel !== WEBCHAT_CHANNEL2) continue;
23699
23775
  result.scanned++;
@@ -23704,21 +23780,21 @@ async function migrateAdminWebchatSidecars(opts = {}) {
23704
23780
  }
23705
23781
  if (!singleAdmin) {
23706
23782
  result.skippedAmbiguous++;
23707
- console.error(`[sidecar-backfill] skip sessionId=${shortId(path2)} reason=admin-count-not-one count=${adminCount < 0 ? "unparseable" : adminCount}`);
23783
+ console.error(`[sidecar-backfill] skip sessionId=${shortId(path3)} reason=admin-count-not-one count=${adminCount < 0 ? "unparseable" : adminCount}`);
23708
23784
  continue;
23709
23785
  }
23710
23786
  raw.adminUserId = soleAdminUserId;
23711
- await writeRaw(path2, raw);
23787
+ await writeRaw(path3, raw);
23712
23788
  result.backfilled++;
23713
23789
  await resolveAdminName();
23714
- const back = await readRaw2(path2);
23790
+ const back = await readRaw2(path3);
23715
23791
  const wrote = back && back.adminUserId === soleAdminUserId;
23716
23792
  if (wrote && resolvedNameForAdmin) {
23717
23793
  result.resolvedName++;
23718
23794
  } else if (wrote) {
23719
- console.error(`[sidecar-backfill] backfilled-no-name sessionId=${shortId(path2)} userId=${soleAdminUserId.slice(0, 8)}`);
23795
+ console.error(`[sidecar-backfill] backfilled-no-name sessionId=${shortId(path3)} userId=${soleAdminUserId.slice(0, 8)}`);
23720
23796
  } else {
23721
- console.error(`[sidecar-backfill] post-write-verify-failed sessionId=${shortId(path2)}`);
23797
+ console.error(`[sidecar-backfill] post-write-verify-failed sessionId=${shortId(path3)}`);
23722
23798
  }
23723
23799
  }
23724
23800
  console.error(
@@ -25321,14 +25397,14 @@ function makeFileDelivery(opts) {
25321
25397
  }
25322
25398
 
25323
25399
  // app/lib/webchat/file-delivery.ts
25324
- var TAG41 = "[webchat-adaptor]";
25400
+ var TAG42 = "[webchat-adaptor]";
25325
25401
  function platformRoot2() {
25326
25402
  return process.env.MAXY_PLATFORM_ROOT || "";
25327
25403
  }
25328
25404
  function makeWebchatSendFile(entry) {
25329
25405
  return async (filePath) => {
25330
25406
  if (!entry.accountId) {
25331
- console.error(`${TAG41} file-delivery reject reason=no-account sender=${entry.senderId}`);
25407
+ console.error(`${TAG42} file-delivery reject reason=no-account sender=${entry.senderId}`);
25332
25408
  return { ok: false, error: "no-account" };
25333
25409
  }
25334
25410
  const accountDir = resolve32(platformRoot2(), "..", "data/accounts", entry.accountId);
@@ -25336,14 +25412,14 @@ function makeWebchatSendFile(entry) {
25336
25412
  const resolved = realpathSync8(filePath);
25337
25413
  const accountResolved = realpathSync8(accountDir);
25338
25414
  if (!resolved.startsWith(accountResolved + "/")) {
25339
- console.error(`${TAG41} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
25415
+ console.error(`${TAG42} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
25340
25416
  return { ok: false, error: "outside-account" };
25341
25417
  }
25342
25418
  return { ok: true };
25343
25419
  } catch (err) {
25344
25420
  const code = err.code;
25345
25421
  console.error(
25346
- `${TAG41} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
25422
+ `${TAG42} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
25347
25423
  );
25348
25424
  return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
25349
25425
  }
@@ -25352,7 +25428,7 @@ function makeWebchatSendFile(entry) {
25352
25428
  function makeWebchatFileDelivery(entry) {
25353
25429
  return makeFileDelivery({
25354
25430
  entry,
25355
- tag: TAG41,
25431
+ tag: TAG42,
25356
25432
  channel: "webchat",
25357
25433
  sendFile: makeWebchatSendFile(entry),
25358
25434
  deferUntilVerdict: true
@@ -25414,7 +25490,7 @@ function buildPublicWebchatSpawnRequest(input) {
25414
25490
  }
25415
25491
 
25416
25492
  // app/lib/whatsapp/inbound/file-delivery-bridge.ts
25417
- var TAG42 = "[whatsapp-adaptor]";
25493
+ var TAG43 = "[whatsapp-adaptor]";
25418
25494
  var SEND_USER_FILE2 = "SendUserFile";
25419
25495
  var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
25420
25496
  function platformRoot3() {
@@ -25432,7 +25508,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
25432
25508
  });
25433
25509
  if (result.ok) return { ok: true };
25434
25510
  console.error(
25435
- `${TAG42} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
25511
+ `${TAG43} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
25436
25512
  );
25437
25513
  return { ok: false, error: result.error };
25438
25514
  };
@@ -25440,7 +25516,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
25440
25516
  function makeWhatsAppFileDelivery(entry, maxyAccountId) {
25441
25517
  const shared = makeFileDelivery({
25442
25518
  entry,
25443
- tag: TAG42,
25519
+ tag: TAG43,
25444
25520
  channel: "whatsapp",
25445
25521
  sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
25446
25522
  });
@@ -25475,7 +25551,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
25475
25551
  if (!delivered) {
25476
25552
  const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
25477
25553
  console.error(
25478
- `${TAG42} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
25554
+ `${TAG43} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
25479
25555
  );
25480
25556
  }
25481
25557
  }
@@ -25870,7 +25946,7 @@ function buildTelegramSpawnRequest(input) {
25870
25946
  import { realpathSync as realpathSync9 } from "fs";
25871
25947
  import { readFile as readFile7, stat as stat7 } from "fs/promises";
25872
25948
  import { resolve as resolve33, basename as basename11 } from "path";
25873
- var TAG43 = "[telegram:outbound]";
25949
+ var TAG44 = "[telegram:outbound]";
25874
25950
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
25875
25951
  async function sendTelegramDocument(input) {
25876
25952
  const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
@@ -25886,16 +25962,16 @@ async function sendTelegramDocument(input) {
25886
25962
  resolvedPath = realpathSync9(filePath);
25887
25963
  const accountResolved = realpathSync9(accountDir);
25888
25964
  if (!resolvedPath.startsWith(accountResolved + "/")) {
25889
- console.error(`${TAG43} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
25965
+ console.error(`${TAG44} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
25890
25966
  return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
25891
25967
  }
25892
25968
  } catch (err) {
25893
25969
  const code = err.code;
25894
25970
  if (code === "ENOENT") {
25895
- console.error(`${TAG43} document ENOENT path=${filePath}`);
25971
+ console.error(`${TAG44} document ENOENT path=${filePath}`);
25896
25972
  return { ok: false, status: 404, error: `File not found: ${filePath}` };
25897
25973
  }
25898
- console.error(`${TAG43} document path error: ${String(err)}`);
25974
+ console.error(`${TAG44} document path error: ${String(err)}`);
25899
25975
  return { ok: false, status: 500, error: String(err) };
25900
25976
  }
25901
25977
  const fileStat = await stat7(resolvedPath);
@@ -25928,13 +26004,13 @@ async function sendTelegramDocument(input) {
25928
26004
  error = e instanceof Error ? e.message : String(e);
25929
26005
  }
25930
26006
  console.error(
25931
- `${TAG43} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
26007
+ `${TAG44} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
25932
26008
  );
25933
26009
  return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
25934
26010
  }
25935
26011
 
25936
26012
  // app/lib/telegram/outbound/file-delivery.ts
25937
- var TAG44 = "[telegram:outbound]";
26013
+ var TAG45 = "[telegram:outbound]";
25938
26014
  function platformRoot4() {
25939
26015
  return process.env.MAXY_PLATFORM_ROOT || "";
25940
26016
  }
@@ -25946,11 +26022,11 @@ function makeTelegramSendFile(entry) {
25946
26022
  botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
25947
26023
  }
25948
26024
  if (!botToken) {
25949
- console.error(`${TAG44} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
26025
+ console.error(`${TAG45} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
25950
26026
  return { ok: false, error: "no-bot-token" };
25951
26027
  }
25952
26028
  if (entry.replyTarget == null) {
25953
- console.error(`${TAG44} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
26029
+ console.error(`${TAG45} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
25954
26030
  return { ok: false, error: "no-reply-target" };
25955
26031
  }
25956
26032
  const result = await sendTelegramDocument({
@@ -25967,7 +26043,7 @@ function makeTelegramSendFile(entry) {
25967
26043
  function makeTelegramFileDelivery(entry) {
25968
26044
  return makeFileDelivery({
25969
26045
  entry,
25970
- tag: TAG44,
26046
+ tag: TAG45,
25971
26047
  channel: "telegram",
25972
26048
  sendFile: makeTelegramSendFile(entry)
25973
26049
  });
@@ -26017,7 +26093,7 @@ function telegramServerPath() {
26017
26093
 
26018
26094
  // app/lib/channel-pty-bridge/public-session-end-review.ts
26019
26095
  import { randomUUID as randomUUID16 } from "crypto";
26020
- var TAG45 = "[public-session-review]";
26096
+ var TAG46 = "[public-session-review]";
26021
26097
  var CONSUMED_CAP = 500;
26022
26098
  var consumed = /* @__PURE__ */ new Set();
26023
26099
  function consumeOnce(sessionId) {
@@ -26044,7 +26120,7 @@ async function fetchJsonl(sessionId) {
26044
26120
  return await res.text();
26045
26121
  } catch (err) {
26046
26122
  console.error(
26047
- `${TAG45} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
26123
+ `${TAG46} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
26048
26124
  );
26049
26125
  return null;
26050
26126
  }
@@ -26068,7 +26144,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
26068
26144
  const res = await fetch(url);
26069
26145
  if (!res.ok) {
26070
26146
  console.error(
26071
- `${TAG45} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
26147
+ `${TAG46} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
26072
26148
  );
26073
26149
  return [];
26074
26150
  }
@@ -26076,7 +26152,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
26076
26152
  return Array.isArray(body.writes) ? body.writes : [];
26077
26153
  } catch (err) {
26078
26154
  console.error(
26079
- `${TAG45} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
26155
+ `${TAG46} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
26080
26156
  );
26081
26157
  return [];
26082
26158
  }
@@ -26105,7 +26181,7 @@ function composeInitialMessage(input) {
26105
26181
  }
26106
26182
  async function dispatchReviewer(input, initialMessage) {
26107
26183
  const sessionId = randomUUID16();
26108
- console.log(`${TAG45} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
26184
+ console.log(`${TAG46} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
26109
26185
  const spawned = await managerRcSpawn({
26110
26186
  sessionId,
26111
26187
  initialMessage,
@@ -26125,21 +26201,21 @@ async function firePublicSessionEndReview(input) {
26125
26201
  const dispatchedAt = Date.now();
26126
26202
  if (consumed.has(input.sessionId)) {
26127
26203
  console.log(
26128
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
26204
+ `${TAG46} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
26129
26205
  );
26130
26206
  return;
26131
26207
  }
26132
26208
  const jsonl = await fetchJsonl(input.sessionId);
26133
26209
  if (!jsonl) {
26134
26210
  console.log(
26135
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
26211
+ `${TAG46} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
26136
26212
  );
26137
26213
  return;
26138
26214
  }
26139
26215
  const operatorTurns = countOperatorTurns(jsonl);
26140
26216
  if (operatorTurns === 0) {
26141
26217
  console.log(
26142
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
26218
+ `${TAG46} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
26143
26219
  );
26144
26220
  return;
26145
26221
  }
@@ -26153,19 +26229,19 @@ async function firePublicSessionEndReview(input) {
26153
26229
  });
26154
26230
  if (!consumeOnce(input.sessionId)) {
26155
26231
  console.log(
26156
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
26232
+ `${TAG46} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
26157
26233
  );
26158
26234
  return;
26159
26235
  }
26160
26236
  const dispatched = await dispatchReviewer(input, initialMessage);
26161
26237
  if (!dispatched.ok) {
26162
26238
  console.error(
26163
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
26239
+ `${TAG46} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
26164
26240
  );
26165
26241
  return;
26166
26242
  }
26167
26243
  console.log(
26168
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
26244
+ `${TAG46} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
26169
26245
  );
26170
26246
  }
26171
26247
 
@@ -26938,8 +27014,8 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
26938
27014
  });
26939
27015
  app62.route("/api/channel/schedule-inject", scheduleInjectRoutes);
26940
27016
  app62.use("*", clientIpMiddleware);
26941
- function allowsSameOriginFraming(path2) {
26942
- return path2 === "/vnc-viewer.html" || path2.startsWith("/api/admin/attachment/") || path2.startsWith("/api/public-reader/attachment/") || path2 === "/api/admin/files/download";
27017
+ function allowsSameOriginFraming(path3) {
27018
+ return path3 === "/vnc-viewer.html" || path3.startsWith("/api/admin/attachment/") || path3.startsWith("/api/public-reader/attachment/") || path3 === "/api/admin/files/download";
26943
27019
  }
26944
27020
  app62.use("*", async (c, next) => {
26945
27021
  await next();
@@ -26972,12 +27048,12 @@ app62.use("*", async (c, next) => {
26972
27048
  await next();
26973
27049
  return;
26974
27050
  }
26975
- const path2 = c.req.path;
26976
- if (isPublicPathAllowed(path2)) {
27051
+ const path3 = c.req.path;
27052
+ if (isPublicPathAllowed(path3)) {
26977
27053
  await next();
26978
27054
  return;
26979
27055
  }
26980
- console.error(`[public-host] blocked path=${path2}`);
27056
+ console.error(`[public-host] blocked path=${path3}`);
26981
27057
  return c.text("Not found", 404);
26982
27058
  });
26983
27059
  var lastRemoteAuthDisplayName = "";
@@ -27212,12 +27288,12 @@ console.log("[client-error-route] mounted");
27212
27288
  var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
27213
27289
  app62.use("*", async (c, next) => {
27214
27290
  const host = (c.req.header("host") ?? "").split(":")[0];
27215
- const path2 = c.req.path;
27216
- if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
27291
+ const path3 = c.req.path;
27292
+ if (path3 === "/favicon.ico" || path3.startsWith("/assets/") || path3.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
27217
27293
  // origin) against the brand host with no admin cookie. It is public by
27218
27294
  // design — open slots only, no :Meeting detail — so it bypasses the gate
27219
27295
  // exactly like /brand/. The detail-leak guard lives in the route + its test.
27220
- path2 === "/api/calendar/free-busy" || PWA_PUBLIC_PATHS.has(path2)) {
27296
+ path3 === "/api/calendar/free-busy" || PWA_PUBLIC_PATHS.has(path3)) {
27221
27297
  await next();
27222
27298
  return;
27223
27299
  }
@@ -27244,15 +27320,15 @@ app62.use("*", async (c, next) => {
27244
27320
  }
27245
27321
  const disambig = `remoteAddress="${rawRemote ?? ""}" xff="${rawXff ?? ""}" resolvedKind=${decision.client.kind}`;
27246
27322
  if (decision.reason === "remote-unconfigured") {
27247
- console.error(`[remote-auth] not configured, redirecting to setup ip=${clientIp} path=${path2} ${disambig}`);
27323
+ console.error(`[remote-auth] not configured, redirecting to setup ip=${clientIp} path=${path3} ${disambig}`);
27248
27324
  return c.redirect("/__remote-auth/setup");
27249
27325
  }
27250
- const respond = isApiRequestPath(path2) ? "401" : "html";
27251
- console.error(`[remote-auth] login required ip=${clientIp} path=${path2} respond=${respond} ${disambig}`);
27326
+ const respond = isApiRequestPath(path3) ? "401" : "html";
27327
+ console.error(`[remote-auth] login required ip=${clientIp} path=${path3} respond=${respond} ${disambig}`);
27252
27328
  if (respond === "401") {
27253
27329
  return c.json({ code: "remote-auth-required" }, 401);
27254
27330
  }
27255
- return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path2 }), 200);
27331
+ return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path3 }), 200);
27256
27332
  });
27257
27333
  app62.route("/api/health", health_default);
27258
27334
  app62.route("/api/chat", chatRoutes);
@@ -27677,11 +27753,11 @@ if (brandFaviconPath !== "/favicon.ico") {
27677
27753
  app62.use("/*", serveStatic({ root: "./public" }));
27678
27754
  app62.all("*", (c) => {
27679
27755
  const host = (c.req.header("host") ?? "").split(":")[0];
27680
- const path2 = c.req.path;
27756
+ const path3 = c.req.path;
27681
27757
  if (isPublicHost(host)) {
27682
- const inAllowedList = PUBLIC_ALLOWED_EXACT.includes(path2) || PUBLIC_ALLOWED_PREFIXES.some((prefix) => path2.startsWith(prefix));
27758
+ const inAllowedList = PUBLIC_ALLOWED_EXACT.includes(path3) || PUBLIC_ALLOWED_PREFIXES.some((prefix) => path3.startsWith(prefix));
27683
27759
  if (inAllowedList) {
27684
- console.error(`[public-host] unmatched-allowed path=${path2}`);
27760
+ console.error(`[public-host] unmatched-allowed path=${path3}`);
27685
27761
  return c.json({ error: "not-found" }, 404);
27686
27762
  }
27687
27763
  }