switchroom 0.19.14 → 0.19.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/cli/switchroom.js +1 -1
  2. package/dist/host-control/main.js +1 -1
  3. package/package.json +1 -1
  4. package/telegram-plugin/bridge/bridge.ts +1 -1
  5. package/telegram-plugin/dist/bridge/bridge.js +1 -1
  6. package/telegram-plugin/dist/gateway/gateway.js +1002 -504
  7. package/telegram-plugin/dist/server.js +1 -1
  8. package/telegram-plugin/gateway/forward-origin.ts +6 -1
  9. package/telegram-plugin/gateway/gateway.ts +4 -0
  10. package/telegram-plugin/gateway/narrative-lane.ts +11 -0
  11. package/telegram-plugin/gateway/outbox-sweep.ts +32 -2
  12. package/telegram-plugin/gateway/rich-message-handler.ts +235 -0
  13. package/telegram-plugin/gateway/stream-render.ts +107 -15
  14. package/telegram-plugin/gateway/unhandled-message.ts +14 -0
  15. package/telegram-plugin/hooks/narration-classify.d.mts +23 -0
  16. package/telegram-plugin/hooks/narration-classify.mjs +210 -0
  17. package/telegram-plugin/hooks/silent-end-scan.mjs +136 -82
  18. package/telegram-plugin/narrative-flush.ts +35 -0
  19. package/telegram-plugin/outbox.ts +73 -3
  20. package/telegram-plugin/shown-ledger.ts +145 -0
  21. package/telegram-plugin/silent-end.ts +42 -0
  22. package/telegram-plugin/tests/backstop-exactly-once.test.ts +335 -0
  23. package/telegram-plugin/tests/catch-all-unhandled-message.test.ts +14 -0
  24. package/telegram-plugin/tests/forward-origin.test.ts +20 -0
  25. package/telegram-plugin/tests/forwarded-rich-message.test.ts +305 -0
  26. package/telegram-plugin/tests/gateway-handler-registration-wiring.test.ts +1 -0
  27. package/telegram-plugin/tests/narration-leak-3513.test.ts +352 -0
  28. package/telegram-plugin/tests/silent-end-interrupt-stop-scan.test.ts +42 -13
  29. package/telegram-plugin/tests/silent-end.test.ts +7 -1
  30. package/telegram-plugin/tests/turn-flush-safety.test.ts +35 -3
  31. package/telegram-plugin/turn-flush-safety.ts +66 -53
@@ -29091,8 +29091,8 @@ __export(exports_history, {
29091
29091
  _resetForTests: () => _resetForTests,
29092
29092
  MIN_PREFIX_MATCH_CHARS: () => MIN_PREFIX_MATCH_CHARS2
29093
29093
  });
29094
- import { chmodSync as chmodSync9, existsSync as existsSync26, mkdirSync as mkdirSync27 } from "fs";
29095
- import { join as join30 } from "path";
29094
+ import { chmodSync as chmodSync9, existsSync as existsSync27, mkdirSync as mkdirSync28 } from "fs";
29095
+ import { join as join31 } from "path";
29096
29096
  function loadDatabaseClass2() {
29097
29097
  if (DatabaseClass2 != null)
29098
29098
  return DatabaseClass2;
@@ -29123,8 +29123,8 @@ function initHistory2(stateDir, retentionDays = 30) {
29123
29123
  if (db2 != null)
29124
29124
  return;
29125
29125
  const Database = loadDatabaseClass2();
29126
- mkdirSync27(stateDir, { recursive: true, mode: 448 });
29127
- const path2 = join30(stateDir, "history.db");
29126
+ mkdirSync28(stateDir, { recursive: true, mode: 448 });
29127
+ const path2 = join31(stateDir, "history.db");
29128
29128
  dbPath2 = path2;
29129
29129
  db2 = new Database(path2, { create: true });
29130
29130
  db2.exec("PRAGMA journal_mode = WAL");
@@ -29190,7 +29190,7 @@ function initHistory2(stateDir, retentionDays = 30) {
29190
29190
  }
29191
29191
  for (const suffix of ["", "-shm", "-wal"]) {
29192
29192
  const f = path2 + suffix;
29193
- if (existsSync26(f)) {
29193
+ if (existsSync27(f)) {
29194
29194
  try {
29195
29195
  chmodSync9(f, 420);
29196
29196
  } catch {}
@@ -29242,7 +29242,7 @@ function checkpointWal2() {
29242
29242
  if (dbPath2) {
29243
29243
  for (const suffix of ["-shm", "-wal"]) {
29244
29244
  const f = dbPath2 + suffix;
29245
- if (existsSync26(f)) {
29245
+ if (existsSync27(f)) {
29246
29246
  try {
29247
29247
  chmodSync9(f, 420);
29248
29248
  } catch {}
@@ -29489,7 +29489,7 @@ var FLUSH_SUPPRESSION_WINDOW_MS = 2000;
29489
29489
  var init_turn_flush_suppression = () => {};
29490
29490
 
29491
29491
  // ../src/util/atomic.ts
29492
- import { closeSync as closeSync6, constants as constants2, fchmodSync, fchownSync, fsyncSync as fsyncSync2, openSync as openSync6, renameSync as renameSync12, rmSync as rmSync5, writeSync as writeSync4 } from "node:fs";
29492
+ import { closeSync as closeSync6, constants as constants2, fchmodSync, fchownSync, fsyncSync as fsyncSync2, openSync as openSync6, renameSync as renameSync13, rmSync as rmSync5, writeSync as writeSync4 } from "node:fs";
29493
29493
  var TMP_OPEN_FLAGS;
29494
29494
  var init_atomic = __esm(() => {
29495
29495
  TMP_OPEN_FLAGS = constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | (constants2.O_NOFOLLOW ?? 0);
@@ -32451,7 +32451,7 @@ var require_util = __commonJS((exports2) => {
32451
32451
  return path2;
32452
32452
  }
32453
32453
  exports2.normalize = normalize;
32454
- function join38(aRoot, aPath) {
32454
+ function join39(aRoot, aPath) {
32455
32455
  if (aRoot === "") {
32456
32456
  aRoot = ".";
32457
32457
  }
@@ -32483,7 +32483,7 @@ var require_util = __commonJS((exports2) => {
32483
32483
  }
32484
32484
  return joined;
32485
32485
  }
32486
- exports2.join = join38;
32486
+ exports2.join = join39;
32487
32487
  exports2.isAbsolute = function(aPath) {
32488
32488
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
32489
32489
  };
@@ -32656,7 +32656,7 @@ var require_util = __commonJS((exports2) => {
32656
32656
  parsed.path = parsed.path.substring(0, index2 + 1);
32657
32657
  }
32658
32658
  }
32659
- sourceURL = join38(urlGenerate(parsed), sourceURL);
32659
+ sourceURL = join39(urlGenerate(parsed), sourceURL);
32660
32660
  }
32661
32661
  return normalize(sourceURL);
32662
32662
  }
@@ -35261,19 +35261,19 @@ function renderAuthLine(state7, agentName3, now = Date.now()) {
35261
35261
  }
35262
35262
 
35263
35263
  // gateway/quota-cache.ts
35264
- import { existsSync as existsSync42, readFileSync as readFileSync43, writeFileSync as writeFileSync36, mkdirSync as mkdirSync37 } from "fs";
35265
- import { join as join47, dirname as dirname15 } from "path";
35264
+ import { existsSync as existsSync43, readFileSync as readFileSync44, writeFileSync as writeFileSync37, mkdirSync as mkdirSync38 } from "fs";
35265
+ import { join as join48, dirname as dirname15 } from "path";
35266
35266
  function defaultCachePath() {
35267
- return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join47(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
35267
+ return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join48(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
35268
35268
  }
35269
35269
  function readQuotaCache(opts = {}) {
35270
35270
  const path2 = opts.path ?? defaultCachePath();
35271
35271
  const now = opts.now ?? Date.now();
35272
- if (!existsSync42(path2))
35272
+ if (!existsSync43(path2))
35273
35273
  return null;
35274
35274
  let entry;
35275
35275
  try {
35276
- entry = JSON.parse(readFileSync43(path2, "utf8"));
35276
+ entry = JSON.parse(readFileSync44(path2, "utf8"));
35277
35277
  } catch {
35278
35278
  return null;
35279
35279
  }
@@ -35299,8 +35299,8 @@ function writeQuotaCache(result, opts = {}) {
35299
35299
  result
35300
35300
  };
35301
35301
  try {
35302
- mkdirSync37(dirname15(path2), { recursive: true });
35303
- writeFileSync36(path2, JSON.stringify(entry, null, 2), { mode: 384 });
35302
+ mkdirSync38(dirname15(path2), { recursive: true });
35303
+ writeFileSync37(path2, JSON.stringify(entry, null, 2), { mode: 384 });
35304
35304
  } catch {}
35305
35305
  }
35306
35306
  var DEFAULT_TTL_MS4, RATE_LIMIT_TTL_MS;
@@ -35310,8 +35310,8 @@ var init_quota_cache = __esm(() => {
35310
35310
  });
35311
35311
 
35312
35312
  // gateway/boot-probes.ts
35313
- import { readFileSync as readFileSync44, readdirSync as readdirSync10, existsSync as existsSync43 } from "fs";
35314
- import { join as join48 } from "path";
35313
+ import { readFileSync as readFileSync45, readdirSync as readdirSync10, existsSync as existsSync44 } from "fs";
35314
+ import { join as join49 } from "path";
35315
35315
  import { execFile as execFileCb } from "child_process";
35316
35316
  import { promisify } from "util";
35317
35317
  async function withTimeout(label, p, timeoutMs = PROBE_TIMEOUT_MS) {
@@ -35353,11 +35353,11 @@ function mapPlan(billingType, hasExtra) {
35353
35353
  }
35354
35354
  async function probeAccount(agentDir) {
35355
35355
  return withTimeout("Account", (async () => {
35356
- const claudeDir = join48(agentDir, ".claude");
35357
- const claudeJsonPath = join48(claudeDir, ".claude.json");
35356
+ const claudeDir = join49(agentDir, ".claude");
35357
+ const claudeJsonPath = join49(claudeDir, ".claude.json");
35358
35358
  let cfg = {};
35359
35359
  try {
35360
- const raw = readFileSync44(claudeJsonPath, "utf8");
35360
+ const raw = readFileSync45(claudeJsonPath, "utf8");
35361
35361
  cfg = JSON.parse(raw);
35362
35362
  } catch {
35363
35363
  return { status: "fail", label: "Account", detail: "no .claude.json" };
@@ -35375,12 +35375,12 @@ async function probeAccount(agentDir) {
35375
35375
  let tokenStr = "";
35376
35376
  let status = "ok";
35377
35377
  for (const candidate of [
35378
- join48(claudeDir, ".oauth-token.meta.json"),
35379
- join48(claudeDir, "accounts", "default", ".oauth-token.meta.json")
35378
+ join49(claudeDir, ".oauth-token.meta.json"),
35379
+ join49(claudeDir, "accounts", "default", ".oauth-token.meta.json")
35380
35380
  ]) {
35381
- if (existsSync43(candidate)) {
35381
+ if (existsSync44(candidate)) {
35382
35382
  try {
35383
- const meta = JSON.parse(readFileSync44(candidate, "utf8"));
35383
+ const meta = JSON.parse(readFileSync45(candidate, "utf8"));
35384
35384
  if (meta.expiresAt) {
35385
35385
  tokenStr = " \u00b7 " + formatDaysFromNow(meta.expiresAt);
35386
35386
  const daysLeft = Math.round((meta.expiresAt - Date.now()) / 86400000);
@@ -35555,9 +35555,9 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
35555
35555
  if (!cgroup)
35556
35556
  return null;
35557
35557
  const procsPath = `/sys/fs/cgroup${cgroup}/cgroup.procs`;
35558
- if (!existsSync43(procsPath))
35558
+ if (!existsSync44(procsPath))
35559
35559
  return null;
35560
- const pidsRaw = readFileSync44(procsPath, "utf-8");
35560
+ const pidsRaw = readFileSync45(procsPath, "utf-8");
35561
35561
  const pids = pidsRaw.split(`
35562
35562
  `).map((s) => s.trim()).filter(Boolean);
35563
35563
  if (pids.length === 0)
@@ -35570,7 +35570,7 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
35570
35570
  let rss = 0;
35571
35571
  let comm = "";
35572
35572
  try {
35573
- const status = readFileSync44(`/proc/${pid}/status`, "utf-8");
35573
+ const status = readFileSync45(`/proc/${pid}/status`, "utf-8");
35574
35574
  const rssLine = status.split(`
35575
35575
  `).find((l) => l.startsWith("VmRSS:"));
35576
35576
  if (rssLine) {
@@ -35582,7 +35582,7 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
35582
35582
  continue;
35583
35583
  }
35584
35584
  try {
35585
- comm = readFileSync44(`/proc/${pid}/comm`, "utf-8").trim();
35585
+ comm = readFileSync45(`/proc/${pid}/comm`, "utf-8").trim();
35586
35586
  } catch {}
35587
35587
  candidates.push({ pid, rss, comm });
35588
35588
  }
@@ -35762,9 +35762,9 @@ async function probeQuota(claudeConfigDir, _agentDir, fetchImpl = fetch, opts =
35762
35762
  let claudeDirForProbe = null;
35763
35763
  for (const candidate of [
35764
35764
  claudeConfigDir,
35765
- join48(claudeConfigDir, "accounts", "default")
35765
+ join49(claudeConfigDir, "accounts", "default")
35766
35766
  ]) {
35767
- if (existsSync43(join48(candidate, ".oauth-token"))) {
35767
+ if (existsSync44(join49(candidate, ".oauth-token"))) {
35768
35768
  claudeDirForProbe = candidate;
35769
35769
  break;
35770
35770
  }
@@ -35829,7 +35829,7 @@ async function probeHindsight(bankName, fetchImpl = fetch) {
35829
35829
  }
35830
35830
  function readContainerBootTimeMsForProbe() {
35831
35831
  try {
35832
- const stat1 = readFileSync44("/proc/1/stat", "utf8");
35832
+ const stat1 = readFileSync45("/proc/1/stat", "utf8");
35833
35833
  const lastParen = stat1.lastIndexOf(")");
35834
35834
  if (lastParen < 0)
35835
35835
  return null;
@@ -35837,7 +35837,7 @@ function readContainerBootTimeMsForProbe() {
35837
35837
  const starttimeTicks = Number(after[19]);
35838
35838
  if (!Number.isFinite(starttimeTicks))
35839
35839
  return null;
35840
- const procStat = readFileSync44("/proc/stat", "utf8");
35840
+ const procStat = readFileSync45("/proc/stat", "utf8");
35841
35841
  const btimeLine = procStat.split(`
35842
35842
  `).find((l) => l.startsWith("btime "));
35843
35843
  if (!btimeLine)
@@ -35935,7 +35935,7 @@ async function probeUds(label, socketPath, opts = {}) {
35935
35935
  }
35936
35936
  return withTimeout(label, (async () => {
35937
35937
  if (!opts.connectImpl) {
35938
- if (!existsSync43(socketPath)) {
35938
+ if (!existsSync44(socketPath)) {
35939
35939
  return {
35940
35940
  status: "fail",
35941
35941
  label,
@@ -35999,7 +35999,7 @@ async function probeSkills(agentDir, opts = {}) {
35999
35999
  return withTimeout("Skills", (async () => {
36000
36000
  const fs2 = opts.fs ?? realSkillsFs;
36001
36001
  const max = opts.maxNamesShown ?? 3;
36002
- const skillsDir = join48(agentDir, ".claude", "skills");
36002
+ const skillsDir = join49(agentDir, ".claude", "skills");
36003
36003
  if (!fs2.exists(skillsDir)) {
36004
36004
  return { status: "ok", label: "Skills", detail: "no skills dir" };
36005
36005
  }
@@ -36014,17 +36014,17 @@ async function probeSkills(agentDir, opts = {}) {
36014
36014
  }
36015
36015
  const dangling = [];
36016
36016
  for (const name of entries) {
36017
- const skillPath = join48(skillsDir, name);
36017
+ const skillPath = join49(skillsDir, name);
36018
36018
  if (!fs2.exists(skillPath)) {
36019
36019
  dangling.push(name);
36020
36020
  continue;
36021
36021
  }
36022
- const skillMd = join48(skillPath, "SKILL.md");
36022
+ const skillMd = join49(skillPath, "SKILL.md");
36023
36023
  if (!fs2.exists(skillMd) && !fs2.exists(skillPath + ".md")) {
36024
36024
  continue;
36025
36025
  }
36026
36026
  }
36027
- const overlayDir = opts.overlaySkillsDir ?? join48(agentDir, "skills.d");
36027
+ const overlayDir = opts.overlaySkillsDir ?? join49(agentDir, "skills.d");
36028
36028
  const overlaySlugs = new Set;
36029
36029
  if (fs2.exists(overlayDir)) {
36030
36030
  let overlayEntries = [];
@@ -36066,8 +36066,8 @@ function renderBucketedSkills(switchroom, agent) {
36066
36066
  }
36067
36067
  async function probeConnections(agentDir, opts = {}) {
36068
36068
  return withTimeout("Connections", (async () => {
36069
- const path2 = join48(agentDir, ".claude", "connection-health.json");
36070
- const read = opts.readFileImpl ?? ((p) => readFileSync44(p, "utf8"));
36069
+ const path2 = join49(agentDir, ".claude", "connection-health.json");
36070
+ const read = opts.readFileImpl ?? ((p) => readFileSync45(p, "utf8"));
36071
36071
  let issues = [];
36072
36072
  try {
36073
36073
  const parsed = JSON.parse(read(path2));
@@ -36098,24 +36098,24 @@ var init_boot_probes = __esm(() => {
36098
36098
  execFile = promisify(execFileCb);
36099
36099
  realProcFs = {
36100
36100
  readdir: (p) => readdirSync10(p),
36101
- readFile: (p) => readFileSync44(p, "utf-8")
36101
+ readFile: (p) => readFileSync45(p, "utf-8")
36102
36102
  };
36103
36103
  realSchedulerFs = {
36104
- readFile: (p) => readFileSync44(p, "utf-8"),
36104
+ readFile: (p) => readFileSync45(p, "utf-8"),
36105
36105
  mtimeMs: (p) => {
36106
36106
  const { statSync: statSync14 } = __require("fs");
36107
36107
  return statSync14(p).mtimeMs;
36108
36108
  },
36109
- exists: (p) => existsSync43(p)
36109
+ exists: (p) => existsSync44(p)
36110
36110
  };
36111
36111
  realSkillsFs = {
36112
36112
  readdir: (p) => readdirSync10(p),
36113
- exists: (p) => existsSync43(p)
36113
+ exists: (p) => existsSync44(p)
36114
36114
  };
36115
36115
  });
36116
36116
 
36117
36117
  // gateway/boot-issue-cache.ts
36118
- import { existsSync as existsSync44, readFileSync as readFileSync45, writeFileSync as writeFileSync37, mkdirSync as mkdirSync38, renameSync as renameSync18 } from "fs";
36118
+ import { existsSync as existsSync45, readFileSync as readFileSync46, writeFileSync as writeFileSync38, mkdirSync as mkdirSync39, renameSync as renameSync19 } from "fs";
36119
36119
  import { dirname as dirname16 } from "path";
36120
36120
  function fingerprintProbe(key, r) {
36121
36121
  if (r.status === "ok")
@@ -36195,11 +36195,11 @@ function diffProbes(probes, cache, opts = {}) {
36195
36195
  return out;
36196
36196
  }
36197
36197
  function loadCache(path2, now = Date.now) {
36198
- if (!existsSync44(path2))
36198
+ if (!existsSync45(path2))
36199
36199
  return { ...EMPTY_CACHE, probes: {} };
36200
36200
  let raw;
36201
36201
  try {
36202
- raw = readFileSync45(path2, "utf-8");
36202
+ raw = readFileSync46(path2, "utf-8");
36203
36203
  } catch {
36204
36204
  return { ...EMPTY_CACHE, probes: {} };
36205
36205
  }
@@ -36208,7 +36208,7 @@ function loadCache(path2, now = Date.now) {
36208
36208
  parsed = JSON.parse(raw);
36209
36209
  } catch {
36210
36210
  try {
36211
- renameSync18(path2, `${path2}.corrupt-${now()}`);
36211
+ renameSync19(path2, `${path2}.corrupt-${now()}`);
36212
36212
  } catch {}
36213
36213
  return { ...EMPTY_CACHE, probes: {} };
36214
36214
  }
@@ -36242,10 +36242,10 @@ function applyAndSave(path2, cache, diff) {
36242
36242
  }
36243
36243
  }
36244
36244
  try {
36245
- mkdirSync38(dirname16(path2), { recursive: true });
36245
+ mkdirSync39(dirname16(path2), { recursive: true });
36246
36246
  const tmp = `${path2}.tmp`;
36247
- writeFileSync37(tmp, JSON.stringify(next), { mode: 384 });
36248
- renameSync18(tmp, path2);
36247
+ writeFileSync38(tmp, JSON.stringify(next), { mode: 384 });
36248
+ renameSync19(tmp, path2);
36249
36249
  } catch {}
36250
36250
  return next;
36251
36251
  }
@@ -36257,14 +36257,14 @@ var init_boot_issue_cache = __esm(() => {
36257
36257
  });
36258
36258
 
36259
36259
  // gateway/config-snapshot.ts
36260
- import { createHash as createHash4 } from "crypto";
36261
- import { existsSync as existsSync45, readFileSync as readFileSync46, writeFileSync as writeFileSync38, mkdirSync as mkdirSync39, renameSync as renameSync19 } from "fs";
36260
+ import { createHash as createHash5 } from "crypto";
36261
+ import { existsSync as existsSync46, readFileSync as readFileSync47, writeFileSync as writeFileSync39, mkdirSync as mkdirSync40, renameSync as renameSync20 } from "fs";
36262
36262
  import { dirname as dirname17 } from "path";
36263
36263
  function hashStringArray(items) {
36264
36264
  if (!items || items.length === 0)
36265
36265
  return null;
36266
36266
  const sorted = [...items].sort();
36267
- const raw = createHash4("sha256").update(sorted.join("\x00")).digest("hex");
36267
+ const raw = createHash5("sha256").update(sorted.join("\x00")).digest("hex");
36268
36268
  return raw.slice(0, 12);
36269
36269
  }
36270
36270
  function normalizeModel(model) {
@@ -36323,11 +36323,11 @@ function renderConfigChangeDim(dim) {
36323
36323
  }
36324
36324
  }
36325
36325
  function loadSnapshot(path2, now = Date.now) {
36326
- if (!existsSync45(path2))
36326
+ if (!existsSync46(path2))
36327
36327
  return null;
36328
36328
  let raw;
36329
36329
  try {
36330
- raw = readFileSync46(path2, "utf-8");
36330
+ raw = readFileSync47(path2, "utf-8");
36331
36331
  } catch {
36332
36332
  return null;
36333
36333
  }
@@ -36336,7 +36336,7 @@ function loadSnapshot(path2, now = Date.now) {
36336
36336
  parsed = JSON.parse(raw);
36337
36337
  } catch {
36338
36338
  try {
36339
- renameSync19(path2, `${path2}.corrupt-${now()}`);
36339
+ renameSync20(path2, `${path2}.corrupt-${now()}`);
36340
36340
  } catch {}
36341
36341
  return null;
36342
36342
  }
@@ -36357,10 +36357,10 @@ function loadSnapshot(path2, now = Date.now) {
36357
36357
  }
36358
36358
  function persistSnapshot(path2, snapshot) {
36359
36359
  try {
36360
- mkdirSync39(dirname17(path2), { recursive: true });
36360
+ mkdirSync40(dirname17(path2), { recursive: true });
36361
36361
  const tmp = `${path2}.tmp`;
36362
- writeFileSync38(tmp, JSON.stringify(snapshot), { mode: 384 });
36363
- renameSync19(tmp, path2);
36362
+ writeFileSync39(tmp, JSON.stringify(snapshot), { mode: 384 });
36363
+ renameSync20(tmp, path2);
36364
36364
  } catch {}
36365
36365
  }
36366
36366
  var init_config_snapshot = __esm(() => {
@@ -36368,13 +36368,13 @@ var init_config_snapshot = __esm(() => {
36368
36368
  });
36369
36369
 
36370
36370
  // gateway/boot-card-msgid.ts
36371
- import { readFileSync as readFileSync47, writeFileSync as writeFileSync39 } from "node:fs";
36371
+ import { readFileSync as readFileSync48, writeFileSync as writeFileSync40 } from "node:fs";
36372
36372
  function bootCardChatKey(chatId, threadId) {
36373
36373
  return `${chatId}:${threadId ?? ""}`;
36374
36374
  }
36375
36375
  function readStore(path2) {
36376
36376
  try {
36377
- const parsed = JSON.parse(readFileSync47(path2, "utf8"));
36377
+ const parsed = JSON.parse(readFileSync48(path2, "utf8"));
36378
36378
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
36379
36379
  return parsed;
36380
36380
  }
@@ -36393,7 +36393,7 @@ function saveBootCardMsgId(path2, chatKey3, messageId) {
36393
36393
  if (store2[chatKey3] === messageId)
36394
36394
  return;
36395
36395
  store2[chatKey3] = messageId;
36396
- writeFileSync39(path2, JSON.stringify(store2), "utf8");
36396
+ writeFileSync40(path2, JSON.stringify(store2), "utf8");
36397
36397
  } catch {}
36398
36398
  }
36399
36399
  var init_boot_card_msgid = () => {};
@@ -36411,8 +36411,8 @@ __export(exports_boot_card, {
36411
36411
  readRoutingMode: () => readRoutingMode,
36412
36412
  containerBootStartMs: () => containerBootStartMs
36413
36413
  });
36414
- import { join as join49 } from "path";
36415
- import { readFileSync as readFileSync48, statSync as statSync14 } from "fs";
36414
+ import { join as join50 } from "path";
36415
+ import { readFileSync as readFileSync49, statSync as statSync14 } from "fs";
36416
36416
  function resolvePersonaName(slug, loadConfig3) {
36417
36417
  try {
36418
36418
  const config = loadConfig3 ? loadConfig3() : loadConfig();
@@ -36434,7 +36434,7 @@ function shouldSkipDuplicateBootCard(gate, site) {
36434
36434
  }
36435
36435
  return { skip: false };
36436
36436
  }
36437
- function containerBootStartMs(fsImpl = { readFileSync: readFileSync48 }) {
36437
+ function containerBootStartMs(fsImpl = { readFileSync: readFileSync49 }) {
36438
36438
  try {
36439
36439
  const btimeLine = fsImpl.readFileSync("/proc/stat", "utf-8").split(`
36440
36440
  `).find((l) => l.startsWith("btime "));
@@ -36455,8 +36455,8 @@ function containerBootStartMs(fsImpl = { readFileSync: readFileSync48 }) {
36455
36455
  return null;
36456
36456
  }
36457
36457
  }
36458
- function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync: readFileSync48, statSync: statSync14 }) {
36459
- const path2 = join49(agentDir, ".routing-mode");
36458
+ function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync: readFileSync49, statSync: statSync14 }) {
36459
+ const path2 = join50(agentDir, ".routing-mode");
36460
36460
  try {
36461
36461
  const raw = fsImpl.readFileSync(path2, "utf-8");
36462
36462
  const line = raw.split(`
@@ -36563,7 +36563,7 @@ function renderBootCard(opts) {
36563
36563
  return stackCardLines(flatLines);
36564
36564
  }
36565
36565
  async function runAllProbes(opts) {
36566
- const claudeDir = join49(opts.agentDir, ".claude");
36566
+ const claudeDir = join50(opts.agentDir, ".claude");
36567
36567
  const probes = {};
36568
36568
  const slug = opts.agentSlug ?? opts.agentName;
36569
36569
  await Promise.allSettled([
@@ -37417,7 +37417,7 @@ __export(exports_tmux2, {
37417
37417
  captureAgentPane: () => captureAgentPane2
37418
37418
  });
37419
37419
  import { execFileSync as execFileSync8 } from "node:child_process";
37420
- import { chmodSync as chmodSync13, mkdirSync as mkdirSync47, readdirSync as readdirSync13, statSync as statSync19, unlinkSync as unlinkSync26, writeFileSync as writeFileSync48 } from "node:fs";
37420
+ import { chmodSync as chmodSync13, mkdirSync as mkdirSync48, readdirSync as readdirSync13, statSync as statSync19, unlinkSync as unlinkSync26, writeFileSync as writeFileSync49 } from "node:fs";
37421
37421
  import { resolve as resolve12 } from "node:path";
37422
37422
  function captureAgentPane2(opts) {
37423
37423
  const { agentName: agentName3, agentDir, reason } = opts;
@@ -37429,7 +37429,7 @@ function captureAgentPane2(opts) {
37429
37429
  const reasonSlug = sanitizeReason2(reason);
37430
37430
  const outPath = resolve12(outDir, `${ts}-${reasonSlug}.txt`);
37431
37431
  try {
37432
- mkdirSync47(outDir, { recursive: true, mode: 448 });
37432
+ mkdirSync48(outDir, { recursive: true, mode: 448 });
37433
37433
  } catch (err) {
37434
37434
  const msg = `mkdir crash-reports failed: ${err.message}`;
37435
37435
  console.error(`[tmux-capture] ${agentName3}: ${msg}`);
@@ -37468,7 +37468,7 @@ function captureAgentPane2(opts) {
37468
37468
  ` + `
37469
37469
  `;
37470
37470
  try {
37471
- writeFileSync48(outPath, Buffer.concat([Buffer.from(header, "utf8"), body]), {
37471
+ writeFileSync49(outPath, Buffer.concat([Buffer.from(header, "utf8"), body]), {
37472
37472
  mode: 384
37473
37473
  });
37474
37474
  } catch (err) {
@@ -38348,7 +38348,7 @@ __export(exports_materialize_bot_token, {
38348
38348
  materializeBotToken: () => materializeBotToken,
38349
38349
  BotTokenMaterializeError: () => BotTokenMaterializeError
38350
38350
  });
38351
- import { existsSync as existsSync54 } from "node:fs";
38351
+ import { existsSync as existsSync55 } from "node:fs";
38352
38352
  function pickConfiguredToken(config, agentName3) {
38353
38353
  if (agentName3) {
38354
38354
  const agent = config.agents?.[agentName3];
@@ -38362,7 +38362,7 @@ function tryDirectVaultRead4(ref, config, passphrase) {
38362
38362
  if (!passphrase)
38363
38363
  return null;
38364
38364
  const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
38365
- if (!existsSync54(vaultPath))
38365
+ if (!existsSync55(vaultPath))
38366
38366
  return null;
38367
38367
  try {
38368
38368
  const secrets = openVault(passphrase, vaultPath);
@@ -38514,26 +38514,26 @@ var init_approvals_commands = __esm(() => {
38514
38514
  // gateway/gateway.ts
38515
38515
  var import_grammy16 = __toESM(require_mod(), 1);
38516
38516
  var import_runner3 = __toESM(require_mod3(), 1);
38517
- import { randomBytes as randomBytes10, createHash as createHash5 } from "crypto";
38517
+ import { randomBytes as randomBytes10, createHash as createHash6 } from "crypto";
38518
38518
  import { execFileSync as execFileSync9, execSync as execSync2, spawn as spawn2 } from "child_process";
38519
38519
  import {
38520
- readFileSync as readFileSync59,
38521
- writeFileSync as writeFileSync49,
38522
- mkdirSync as mkdirSync48,
38520
+ readFileSync as readFileSync60,
38521
+ writeFileSync as writeFileSync50,
38522
+ mkdirSync as mkdirSync49,
38523
38523
  readdirSync as readdirSync14,
38524
38524
  rmSync as rmSync6,
38525
38525
  statSync as statSync20,
38526
- renameSync as renameSync22,
38526
+ renameSync as renameSync23,
38527
38527
  realpathSync as realpathSync4,
38528
38528
  chmodSync as chmodSync14,
38529
38529
  openSync as openSync12,
38530
38530
  closeSync as closeSync12,
38531
- existsSync as existsSync55,
38531
+ existsSync as existsSync56,
38532
38532
  unlinkSync as unlinkSync27,
38533
- appendFileSync as appendFileSync8
38533
+ appendFileSync as appendFileSync9
38534
38534
  } from "fs";
38535
38535
  import { homedir as homedir20 } from "os";
38536
- import { join as join61, sep as sep4, basename as basename15 } from "path";
38536
+ import { join as join62, sep as sep4, basename as basename15 } from "path";
38537
38537
 
38538
38538
  // plugin-logger.ts
38539
38539
  import { appendFileSync, mkdirSync, renameSync, statSync, existsSync } from "fs";
@@ -40819,6 +40819,141 @@ function forwardOriginDateIso(o) {
40819
40819
  return new Date(o.date * 1000).toISOString();
40820
40820
  }
40821
40821
 
40822
+ // gateway/rich-message-handler.ts
40823
+ var MAX_DEPTH = 32;
40824
+ function renderRichText(rt, depth = 0) {
40825
+ if (depth > MAX_DEPTH || rt == null)
40826
+ return "";
40827
+ if (typeof rt === "string")
40828
+ return rt;
40829
+ if (Array.isArray(rt))
40830
+ return rt.map((t) => renderRichText(t, depth + 1)).join("");
40831
+ if (typeof rt !== "object")
40832
+ return "";
40833
+ const node = rt;
40834
+ if (node.type === "custom_emoji")
40835
+ return node.alternative_text ?? "";
40836
+ if (node.type === "mathematical_expression") {
40837
+ return typeof node.expression === "string" ? node.expression : "";
40838
+ }
40839
+ if (node.type === "anchor")
40840
+ return "";
40841
+ if ("text" in node)
40842
+ return renderRichText(node.text, depth + 1);
40843
+ return "";
40844
+ }
40845
+ function renderCaption(caption, depth) {
40846
+ if (caption == null || typeof caption !== "object")
40847
+ return renderRichText(caption, depth);
40848
+ const c = caption;
40849
+ const text = renderRichText(c.text, depth);
40850
+ const credit = renderRichText(c.credit, depth);
40851
+ return [text, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
40852
+ }
40853
+ function renderBlocks(blocks, depth) {
40854
+ if (depth > MAX_DEPTH || !Array.isArray(blocks))
40855
+ return "";
40856
+ return blocks.map((b) => renderRichBlock(b, depth + 1)).filter((s) => s.length > 0).join(`
40857
+ `);
40858
+ }
40859
+ function renderRichBlock(block, depth = 0) {
40860
+ if (depth > MAX_DEPTH || block == null || typeof block !== "object")
40861
+ return "";
40862
+ const b = block;
40863
+ switch (b.type) {
40864
+ case "paragraph":
40865
+ case "heading":
40866
+ case "footer":
40867
+ return renderRichText(b.text, depth);
40868
+ case "pre": {
40869
+ const body = renderRichText(b.text, depth);
40870
+ return body.length > 0 ? `\`\`\`${b.language ?? ""}
40871
+ ${body}
40872
+ \`\`\`` : "";
40873
+ }
40874
+ case "divider":
40875
+ return "---";
40876
+ case "mathematical_expression":
40877
+ return typeof b.expression === "string" ? b.expression : "";
40878
+ case "anchor":
40879
+ return "";
40880
+ case "list": {
40881
+ if (!Array.isArray(b.items))
40882
+ return "";
40883
+ return b.items.map((item) => {
40884
+ const body = renderBlocks(item?.blocks, depth);
40885
+ const check = item?.has_checkbox ? item.is_checked ? "[x] " : "[ ] " : "";
40886
+ const label = typeof item?.label === "string" && item.label.length > 0 ? item.label : "-";
40887
+ return body.length > 0 ? `${label} ${check}${body}` : "";
40888
+ }).filter((s) => s.length > 0).join(`
40889
+ `);
40890
+ }
40891
+ case "blockquote": {
40892
+ const body = renderBlocks(b.blocks, depth);
40893
+ const credit = renderRichText(b.credit, depth);
40894
+ const quoted = body.split(`
40895
+ `).map((line) => `> ${line}`).join(`
40896
+ `);
40897
+ return [quoted, credit ? `> \u2014 ${credit}` : ""].filter((s) => s.length > 0).join(`
40898
+ `);
40899
+ }
40900
+ case "pullquote": {
40901
+ const body = renderRichText(b.text, depth);
40902
+ const credit = renderRichText(b.credit, depth);
40903
+ return [body, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
40904
+ }
40905
+ case "details": {
40906
+ const summary = renderRichText(b.summary, depth);
40907
+ const body = renderBlocks(b.blocks, depth);
40908
+ return [summary, body].filter((s) => s.length > 0).join(`
40909
+ `);
40910
+ }
40911
+ case "collage":
40912
+ case "slideshow": {
40913
+ const body = renderBlocks(b.blocks, depth);
40914
+ const caption = renderCaption(b.caption, depth);
40915
+ return [body, caption].filter((s) => s.length > 0).join(`
40916
+ `);
40917
+ }
40918
+ case "table": {
40919
+ if (!Array.isArray(b.cells))
40920
+ return "";
40921
+ const rows = b.cells.map((row) => Array.isArray(row) ? row.map((cell) => renderRichText(cell?.text, depth)).join(" | ") : "").filter((s) => s.length > 0).join(`
40922
+ `);
40923
+ const caption = renderRichText(b.caption, depth);
40924
+ return [caption, rows].filter((s) => s.length > 0).join(`
40925
+ `);
40926
+ }
40927
+ case "map":
40928
+ case "animation":
40929
+ case "audio":
40930
+ case "photo":
40931
+ case "video":
40932
+ case "voice_note": {
40933
+ const caption = renderCaption(b.caption, depth);
40934
+ const tag = `[${b.type}]`;
40935
+ return caption.length > 0 ? `${tag} ${caption}` : tag;
40936
+ }
40937
+ case "thinking":
40938
+ return "";
40939
+ default: {
40940
+ const text = renderRichText(b.text, depth);
40941
+ if (text.length > 0)
40942
+ return text;
40943
+ return renderBlocks(b.blocks, depth);
40944
+ }
40945
+ }
40946
+ }
40947
+ function extractRichMessageText(rich) {
40948
+ if (rich == null || typeof rich !== "object")
40949
+ return;
40950
+ const blocks = rich.blocks;
40951
+ const rendered = renderBlocks(blocks, 0).replace(/\n{3,}/g, `
40952
+
40953
+ `).trim();
40954
+ return rendered.length > 0 ? rendered : undefined;
40955
+ }
40956
+
40822
40957
  // gateway/unhandled-message.ts
40823
40958
  var MESSAGE_ENVELOPE_KEYS = new Set([
40824
40959
  "message_id",
@@ -40847,7 +40982,13 @@ var MESSAGE_ENVELOPE_KEYS = new Set([
40847
40982
  "show_caption_above_media",
40848
40983
  "entities",
40849
40984
  "caption_entities",
40850
- "paid_star_count"
40985
+ "paid_star_count",
40986
+ "forward_from",
40987
+ "forward_from_chat",
40988
+ "forward_from_message_id",
40989
+ "forward_signature",
40990
+ "forward_sender_name",
40991
+ "forward_date"
40851
40992
  ]);
40852
40993
  var SERVICE_NOISE_KEYS = new Set([
40853
40994
  "new_chat_members",
@@ -40892,7 +41033,7 @@ function planUnhandledMessage(msg) {
40892
41033
  return { action: "log-only", contentKeys };
40893
41034
  }
40894
41035
  const contentType = contentKeys[0] ?? "unknown";
40895
- const text = (typeof msg.text === "string" ? msg.text : undefined) ?? (typeof msg.caption === "string" ? msg.caption : undefined) ?? `(unhandled message content: ${contentType})`;
41036
+ const text = (typeof msg.text === "string" ? msg.text : undefined) ?? (typeof msg.caption === "string" ? msg.caption : undefined) ?? extractRichMessageText(msg.rich_message) ?? `(unhandled message content: ${contentType})`;
40896
41037
  return { action: "turn", text, contentKeys };
40897
41038
  }
40898
41039
  var TAP_MAX_LINES_PER_MINUTE = 300;
@@ -41091,6 +41232,153 @@ async function handlePassportDataMessage(ctx, deps) {
41091
41232
  await deps.handleRefusal(ctx, "passport_data", PASSPORT_REFUSAL_TEXT);
41092
41233
  }
41093
41234
 
41235
+ // gateway/rich-message-handler.ts
41236
+ var RICH_MESSAGE_EMPTY_TEXT = "(rich message with no extractable text)";
41237
+ var MAX_DEPTH2 = 32;
41238
+ function renderRichText2(rt, depth = 0) {
41239
+ if (depth > MAX_DEPTH2 || rt == null)
41240
+ return "";
41241
+ if (typeof rt === "string")
41242
+ return rt;
41243
+ if (Array.isArray(rt))
41244
+ return rt.map((t) => renderRichText2(t, depth + 1)).join("");
41245
+ if (typeof rt !== "object")
41246
+ return "";
41247
+ const node = rt;
41248
+ if (node.type === "custom_emoji")
41249
+ return node.alternative_text ?? "";
41250
+ if (node.type === "mathematical_expression") {
41251
+ return typeof node.expression === "string" ? node.expression : "";
41252
+ }
41253
+ if (node.type === "anchor")
41254
+ return "";
41255
+ if ("text" in node)
41256
+ return renderRichText2(node.text, depth + 1);
41257
+ return "";
41258
+ }
41259
+ function renderCaption2(caption, depth) {
41260
+ if (caption == null || typeof caption !== "object")
41261
+ return renderRichText2(caption, depth);
41262
+ const c = caption;
41263
+ const text = renderRichText2(c.text, depth);
41264
+ const credit = renderRichText2(c.credit, depth);
41265
+ return [text, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
41266
+ }
41267
+ function renderBlocks2(blocks, depth) {
41268
+ if (depth > MAX_DEPTH2 || !Array.isArray(blocks))
41269
+ return "";
41270
+ return blocks.map((b) => renderRichBlock2(b, depth + 1)).filter((s) => s.length > 0).join(`
41271
+ `);
41272
+ }
41273
+ function renderRichBlock2(block, depth = 0) {
41274
+ if (depth > MAX_DEPTH2 || block == null || typeof block !== "object")
41275
+ return "";
41276
+ const b = block;
41277
+ switch (b.type) {
41278
+ case "paragraph":
41279
+ case "heading":
41280
+ case "footer":
41281
+ return renderRichText2(b.text, depth);
41282
+ case "pre": {
41283
+ const body = renderRichText2(b.text, depth);
41284
+ return body.length > 0 ? `\`\`\`${b.language ?? ""}
41285
+ ${body}
41286
+ \`\`\`` : "";
41287
+ }
41288
+ case "divider":
41289
+ return "---";
41290
+ case "mathematical_expression":
41291
+ return typeof b.expression === "string" ? b.expression : "";
41292
+ case "anchor":
41293
+ return "";
41294
+ case "list": {
41295
+ if (!Array.isArray(b.items))
41296
+ return "";
41297
+ return b.items.map((item) => {
41298
+ const body = renderBlocks2(item?.blocks, depth);
41299
+ const check = item?.has_checkbox ? item.is_checked ? "[x] " : "[ ] " : "";
41300
+ const label = typeof item?.label === "string" && item.label.length > 0 ? item.label : "-";
41301
+ return body.length > 0 ? `${label} ${check}${body}` : "";
41302
+ }).filter((s) => s.length > 0).join(`
41303
+ `);
41304
+ }
41305
+ case "blockquote": {
41306
+ const body = renderBlocks2(b.blocks, depth);
41307
+ const credit = renderRichText2(b.credit, depth);
41308
+ const quoted = body.split(`
41309
+ `).map((line) => `> ${line}`).join(`
41310
+ `);
41311
+ return [quoted, credit ? `> \u2014 ${credit}` : ""].filter((s) => s.length > 0).join(`
41312
+ `);
41313
+ }
41314
+ case "pullquote": {
41315
+ const body = renderRichText2(b.text, depth);
41316
+ const credit = renderRichText2(b.credit, depth);
41317
+ return [body, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
41318
+ }
41319
+ case "details": {
41320
+ const summary = renderRichText2(b.summary, depth);
41321
+ const body = renderBlocks2(b.blocks, depth);
41322
+ return [summary, body].filter((s) => s.length > 0).join(`
41323
+ `);
41324
+ }
41325
+ case "collage":
41326
+ case "slideshow": {
41327
+ const body = renderBlocks2(b.blocks, depth);
41328
+ const caption = renderCaption2(b.caption, depth);
41329
+ return [body, caption].filter((s) => s.length > 0).join(`
41330
+ `);
41331
+ }
41332
+ case "table": {
41333
+ if (!Array.isArray(b.cells))
41334
+ return "";
41335
+ const rows = b.cells.map((row) => Array.isArray(row) ? row.map((cell) => renderRichText2(cell?.text, depth)).join(" | ") : "").filter((s) => s.length > 0).join(`
41336
+ `);
41337
+ const caption = renderRichText2(b.caption, depth);
41338
+ return [caption, rows].filter((s) => s.length > 0).join(`
41339
+ `);
41340
+ }
41341
+ case "map":
41342
+ case "animation":
41343
+ case "audio":
41344
+ case "photo":
41345
+ case "video":
41346
+ case "voice_note": {
41347
+ const caption = renderCaption2(b.caption, depth);
41348
+ const tag = `[${b.type}]`;
41349
+ return caption.length > 0 ? `${tag} ${caption}` : tag;
41350
+ }
41351
+ case "thinking":
41352
+ return "";
41353
+ default: {
41354
+ const text = renderRichText2(b.text, depth);
41355
+ if (text.length > 0)
41356
+ return text;
41357
+ return renderBlocks2(b.blocks, depth);
41358
+ }
41359
+ }
41360
+ }
41361
+ function extractRichMessageText2(rich) {
41362
+ if (rich == null || typeof rich !== "object")
41363
+ return;
41364
+ const blocks = rich.blocks;
41365
+ const rendered = renderBlocks2(blocks, 0).replace(/\n{3,}/g, `
41366
+
41367
+ `).trim();
41368
+ return rendered.length > 0 ? rendered : undefined;
41369
+ }
41370
+ async function handleRichMessageMessage(ctx, deps) {
41371
+ try {
41372
+ const text = extractRichMessageText2(ctx.message.rich_message) ?? RICH_MESSAGE_EMPTY_TEXT;
41373
+ deps.log(`telegram gateway: inbound rich_message from chat=${ctx.chat?.id ?? "?"} chars=${text.length}
41374
+ `);
41375
+ await deps.handleInbound(ctx, text, undefined);
41376
+ } catch (err) {
41377
+ deps.log(`telegram gateway: rich_message handler error: ${err.message}
41378
+ `);
41379
+ }
41380
+ }
41381
+
41094
41382
  // gateway/stop-command.ts
41095
41383
  function parseStopKeyword2(text) {
41096
41384
  return /^stop[.!]?$/i.test(text.trim());
@@ -42712,6 +43000,8 @@ function buildForwardOriginMeta(origins) {
42712
43000
  if (o.date != null) {
42713
43001
  out[`forwarded_date${suffix}`] = fmtLocalStamp(o.date * 1000, resolveEnvTimezone());
42714
43002
  }
43003
+ if (o.messageId != null)
43004
+ out[`forwarded_message_id${suffix}`] = String(o.messageId);
42715
43005
  });
42716
43006
  return out;
42717
43007
  }
@@ -61243,7 +61533,7 @@ function prefixLines(text4, prefix) {
61243
61533
  `);
61244
61534
  }
61245
61535
  function renderBlockquote(node2) {
61246
- const inner = renderBlocks(node2.children);
61536
+ const inner = renderBlocks3(node2.children);
61247
61537
  if (node2.expandable) {
61248
61538
  const lines = inner.split(`
61249
61539
  `);
@@ -61339,7 +61629,7 @@ function renderBlock(node2) {
61339
61629
  function renderBlocksJoined(blocks, sep2) {
61340
61630
  return blocks.map(renderBlock).join(sep2);
61341
61631
  }
61342
- function renderBlocks(blocks) {
61632
+ function renderBlocks3(blocks) {
61343
61633
  return renderBlocksJoined(blocks, `
61344
61634
 
61345
61635
  `);
@@ -74010,6 +74300,33 @@ function readDeliveredNonces(stateDir) {
74010
74300
  } catch {}
74011
74301
  return set;
74012
74302
  }
74303
+ function isBackstopDeliveredEntry(e) {
74304
+ if (e.deliverySource === "sweep" || e.deliverySource === "flush")
74305
+ return true;
74306
+ if (e.deliverySource === "reply-tool" && e.replyAlreadyDeliveredThisTurn === false)
74307
+ return true;
74308
+ return false;
74309
+ }
74310
+ function backstopAlreadyDelivered(nonce, stateDir) {
74311
+ if (nonce == null || nonce === "")
74312
+ return false;
74313
+ const path2 = join28(resolveOutboxDir(stateDir), JOURNAL_FILE);
74314
+ if (!existsSync24(path2))
74315
+ return false;
74316
+ try {
74317
+ for (const line of readFileSync24(path2, "utf8").split(`
74318
+ `)) {
74319
+ if (!line)
74320
+ continue;
74321
+ try {
74322
+ const e = JSON.parse(line);
74323
+ if (e.turnNonce === nonce && isBackstopDeliveredEntry(e))
74324
+ return true;
74325
+ } catch {}
74326
+ }
74327
+ } catch {}
74328
+ return false;
74329
+ }
74013
74330
  var JOURNAL_KEEP = 2000;
74014
74331
  var JOURNAL_ROTATE_AT = 4000;
74015
74332
  function appendDelivered(entry, stateDir) {
@@ -74053,10 +74370,13 @@ function decideOutboxSweep(input) {
74053
74370
  routable,
74054
74371
  routePrefix = "",
74055
74372
  quietMs = OUTBOX_QUIET_MS,
74056
- maxAgeMs = OUTBOX_MAX_AGE_MS
74373
+ maxAgeMs = OUTBOX_MAX_AGE_MS,
74374
+ shownLedgerHit = false
74057
74375
  } = input;
74058
74376
  if (deliveredNonces.has(record.turnNonce))
74059
74377
  return { action: "skip-journaled" };
74378
+ if (shownLedgerHit)
74379
+ return { action: "skip-ephemeral-shown" };
74060
74380
  const age = now - record.createdAt;
74061
74381
  if (age < quietMs)
74062
74382
  return { action: "skip-quiet" };
@@ -74089,6 +74409,149 @@ function extractTaskId(anchorContent) {
74089
74409
  return m ? m[1] : null;
74090
74410
  }
74091
74411
 
74412
+ // shown-ledger.ts
74413
+ import {
74414
+ existsSync as existsSync25,
74415
+ mkdirSync as mkdirSync26,
74416
+ readFileSync as readFileSync25,
74417
+ renameSync as renameSync9,
74418
+ writeFileSync as writeFileSync23,
74419
+ appendFileSync as appendFileSync5
74420
+ } from "node:fs";
74421
+ import { join as join29 } from "node:path";
74422
+
74423
+ // hooks/narration-classify.mjs
74424
+ import { createHash as createHash4 } from "node:crypto";
74425
+ var SUBSTANTIVE_MIN_CHARS = 200;
74426
+ var NARRATION_OPENER = /^(let me\b|lemme\b|i'?ll\b|i will\b|i am going to\b|i'?m going to\b|i'?m about to\b|going to\b|first,?\s+(?:let me|i'?ll|i will)\b|now,?\s+(?:let me|i'?ll|i will)\b|next,?\s+(?:let me|i'?ll|i will)\b|let'?s\b)/i;
74427
+ var NARRATION_TRAILER = /(?:\.{3}|\u2026|:)\s*$/;
74428
+ function isTrailingNarrationLine(block) {
74429
+ const t = typeof block === "string" ? block.trim() : "";
74430
+ if (t.length === 0 || t.length >= SUBSTANTIVE_MIN_CHARS)
74431
+ return false;
74432
+ if (t.includes(`
74433
+ `))
74434
+ return false;
74435
+ return NARRATION_TRAILER.test(t);
74436
+ }
74437
+ function isNarrationBlock(block) {
74438
+ const s = typeof block === "string" ? block : "";
74439
+ return NARRATION_OPENER.test(s.trimStart()) || isTrailingNarrationLine(s);
74440
+ }
74441
+ function isStructuralNarration(text4, followedByToolUse) {
74442
+ if (followedByToolUse !== true)
74443
+ return false;
74444
+ const t = typeof text4 === "string" ? text4.trim() : "";
74445
+ if (t.length === 0)
74446
+ return true;
74447
+ return isNarrationBlock(t) || t.length < SUBSTANTIVE_MIN_CHARS;
74448
+ }
74449
+ var EPHEMERAL_TOOLS = new Set([
74450
+ "react",
74451
+ "send_typing",
74452
+ "pin_message",
74453
+ "delete_message",
74454
+ "edit_message"
74455
+ ]);
74456
+ function isEphemeralTool(name) {
74457
+ if (typeof name !== "string")
74458
+ return false;
74459
+ const suffix = name.replace(/^mcp__[^_].*?telegram__/, "");
74460
+ return EPHEMERAL_TOOLS.has(suffix);
74461
+ }
74462
+ function selectBackstopDelivery(blocks) {
74463
+ const nonEmpty = (Array.isArray(blocks) ? blocks : []).map((b) => ({
74464
+ text: typeof b?.text === "string" ? b.text.trim() : "",
74465
+ followedByToolUse: b?.followedByToolUse
74466
+ })).filter((b) => b.text.length > 0);
74467
+ if (nonEmpty.length === 0)
74468
+ return null;
74469
+ const run3 = [];
74470
+ for (let i = nonEmpty.length - 1;i >= 0; i--) {
74471
+ if (nonEmpty[i].followedByToolUse === true)
74472
+ break;
74473
+ run3.unshift(nonEmpty[i].text);
74474
+ }
74475
+ if (run3.length > 0)
74476
+ return { text: run3.join(`
74477
+
74478
+ `) };
74479
+ const last = nonEmpty[nonEmpty.length - 1];
74480
+ if (last.text.length >= SUBSTANTIVE_MIN_CHARS)
74481
+ return { text: last.text };
74482
+ return null;
74483
+ }
74484
+ function ledgerHashHex(text4) {
74485
+ return createHash4("sha256").update(String(text4 ?? "").trim(), "utf8").digest("hex");
74486
+ }
74487
+
74488
+ // shown-ledger.ts
74489
+ var SHOWN_LEDGER_FILE = "shown-ledger.jsonl";
74490
+ var SHOWN_LEDGER_KEEP = 2000;
74491
+ var SHOWN_LEDGER_ROTATE_AT = 4000;
74492
+ function shownLedgerPath(stateDir) {
74493
+ return join29(resolveOutboxDir(stateDir), SHOWN_LEDGER_FILE);
74494
+ }
74495
+ function appendShownBlock(turnNonce, text4, stateDir, now = Date.now()) {
74496
+ if (turnNonce == null || turnNonce === "")
74497
+ return;
74498
+ const trimmed = typeof text4 === "string" ? text4.trim() : "";
74499
+ if (trimmed.length === 0)
74500
+ return;
74501
+ const dir = resolveOutboxDir(stateDir);
74502
+ const path2 = shownLedgerPath(stateDir);
74503
+ try {
74504
+ mkdirSync26(dir, { recursive: true });
74505
+ const entry = { turnNonce, hash: ledgerHashHex(trimmed), ts: now };
74506
+ appendFileSync5(path2, JSON.stringify(entry) + `
74507
+ `, { mode: 384 });
74508
+ compactIfLarge(path2);
74509
+ } catch {}
74510
+ }
74511
+ function readShownHashes(turnNonce, stateDir) {
74512
+ const set = new Set;
74513
+ if (turnNonce == null || turnNonce === "")
74514
+ return set;
74515
+ const path2 = shownLedgerPath(stateDir);
74516
+ if (!existsSync25(path2))
74517
+ return set;
74518
+ try {
74519
+ for (const line of readFileSync25(path2, "utf8").split(`
74520
+ `)) {
74521
+ if (!line)
74522
+ continue;
74523
+ try {
74524
+ const e = JSON.parse(line);
74525
+ if (e.turnNonce === turnNonce && typeof e.hash === "string")
74526
+ set.add(e.hash);
74527
+ } catch {}
74528
+ }
74529
+ } catch {}
74530
+ return set;
74531
+ }
74532
+ function isShownBlock(turnNonce, text4, stateDir) {
74533
+ if (turnNonce == null || turnNonce === "")
74534
+ return false;
74535
+ const trimmed = typeof text4 === "string" ? text4.trim() : "";
74536
+ if (trimmed.length === 0)
74537
+ return false;
74538
+ return readShownHashes(turnNonce, stateDir).has(ledgerHashHex(trimmed));
74539
+ }
74540
+ function compactIfLarge(path2) {
74541
+ try {
74542
+ const lines = readFileSync25(path2, "utf8").split(`
74543
+ `).filter((l) => l.length > 0);
74544
+ if (lines.length <= SHOWN_LEDGER_ROTATE_AT)
74545
+ return;
74546
+ const kept = lines.slice(lines.length - SHOWN_LEDGER_KEEP);
74547
+ const tmp = `${path2}.${process.pid}.compact`;
74548
+ writeFileSync23(tmp, kept.join(`
74549
+ `) + `
74550
+ `, { mode: 384 });
74551
+ renameSync9(tmp, path2);
74552
+ } catch {}
74553
+ }
74554
+
74092
74555
  // registry/subagents-schema.ts
74093
74556
  function countRunningBackgroundSubagents(db2) {
74094
74557
  const row = db2.prepare("SELECT count(*) AS n FROM subagents WHERE background = 1 AND status = 'running'").get();
@@ -74211,7 +74674,7 @@ function journalExternalDelivery(args, stateDir, now = Date.now()) {
74211
74674
  textSha256: sha256Hex(args.text),
74212
74675
  tgMessageId: args.tgMessageId,
74213
74676
  ts: now,
74214
- deliverySource: "reply-tool",
74677
+ deliverySource: args.deliverySource ?? "reply-tool",
74215
74678
  ...args.replyAlreadyDeliveredThisTurn == null ? {} : { replyAlreadyDeliveredThisTurn: args.replyAlreadyDeliveredThisTurn }
74216
74679
  }, stateDir);
74217
74680
  clearOutboxRecord(nonce, stateDir);
@@ -74606,8 +75069,8 @@ function monotonicNowMs2() {
74606
75069
  }
74607
75070
 
74608
75071
  // silent-end.ts
74609
- import { existsSync as existsSync25, readFileSync as readFileSync25, writeFileSync as writeFileSync23, unlinkSync as unlinkSync13, mkdirSync as mkdirSync26 } from "node:fs";
74610
- import { dirname as dirname11, join as join29 } from "node:path";
75072
+ import { existsSync as existsSync26, readFileSync as readFileSync26, writeFileSync as writeFileSync24, unlinkSync as unlinkSync13, mkdirSync as mkdirSync27 } from "node:fs";
75073
+ import { dirname as dirname11, join as join30 } from "node:path";
74611
75074
  import { homedir as homedir11 } from "node:os";
74612
75075
  var SILENT_END_MAX_RETRIES2 = 2;
74613
75076
  var SILENT_END_STALE_RECORD_MAX_AGE_MS2 = 30 * 60000;
@@ -74622,10 +75085,10 @@ function resolveStateDir3(deps) {
74622
75085
  if (env != null && env !== "")
74623
75086
  return env;
74624
75087
  const home2 = process.env.HOME ?? homedir11();
74625
- return join29(home2, ".claude", "channels", "telegram");
75088
+ return join30(home2, ".claude", "channels", "telegram");
74626
75089
  }
74627
75090
  function resolveStatePath3(deps) {
74628
- return join29(resolveStateDir3(deps), "silent-end-pending.json");
75091
+ return join30(resolveStateDir3(deps), "silent-end-pending.json");
74629
75092
  }
74630
75093
  function emitLog2(deps, line) {
74631
75094
  if (deps?.log != null)
@@ -74637,8 +75100,8 @@ function writeSilentEndState2(args, deps) {
74637
75100
  const statePath = resolveStatePath3(deps);
74638
75101
  let retryCount = 0;
74639
75102
  try {
74640
- if (existsSync25(statePath)) {
74641
- const prev = JSON.parse(readFileSync25(statePath, "utf8"));
75103
+ if (existsSync26(statePath)) {
75104
+ const prev = JSON.parse(readFileSync26(statePath, "utf8"));
74642
75105
  if (prev.turnKey === args.turnKey && typeof prev.retryCount === "number") {
74643
75106
  retryCount = prev.retryCount;
74644
75107
  }
@@ -74654,8 +75117,8 @@ function writeSilentEndState2(args, deps) {
74654
75117
  timestamp: Date.now()
74655
75118
  };
74656
75119
  try {
74657
- mkdirSync26(dirname11(statePath), { recursive: true });
74658
- writeFileSync23(statePath, JSON.stringify(state3), "utf8");
75120
+ mkdirSync27(dirname11(statePath), { recursive: true });
75121
+ writeFileSync24(statePath, JSON.stringify(state3), "utf8");
74659
75122
  emitLog2(deps, `silent-end: wrote state file turnKey=${args.turnKey} retryCount=${retryCount}
74660
75123
  `);
74661
75124
  } catch (err) {
@@ -74665,10 +75128,10 @@ function writeSilentEndState2(args, deps) {
74665
75128
  }
74666
75129
  function clearSilentEndState2(turnKey3, deps) {
74667
75130
  const statePath = resolveStatePath3(deps);
74668
- if (!existsSync25(statePath))
75131
+ if (!existsSync26(statePath))
74669
75132
  return;
74670
75133
  try {
74671
- const prev = JSON.parse(readFileSync25(statePath, "utf8"));
75134
+ const prev = JSON.parse(readFileSync26(statePath, "utf8"));
74672
75135
  if (prev.turnKey != null && prev.turnKey !== turnKey3)
74673
75136
  return;
74674
75137
  unlinkSync13(statePath);
@@ -74690,6 +75153,12 @@ function decideCapturedProseDelivery(args, deps) {
74690
75153
  const text4 = typeof state3.pendingText === "string" ? state3.pendingText : "";
74691
75154
  if (text4.trim().length < minChars)
74692
75155
  return { deliver: false, reason: "no-substantive-prose" };
75156
+ if (deps?.isBlockShown?.(state3.turnId, text4) === true) {
75157
+ return { deliver: false, reason: "ephemeral-shown" };
75158
+ }
75159
+ if (deps?.backstopDeliveredNonceHit?.(state3.turnId) === true) {
75160
+ return { deliver: false, reason: "already-delivered" };
75161
+ }
74693
75162
  return { deliver: true, text: text4, reason: "captured-prose" };
74694
75163
  }
74695
75164
  function settleCapturedProseDelivery(outcome, effects) {
@@ -74702,10 +75171,10 @@ function settleCapturedProseDelivery(outcome, effects) {
74702
75171
  }
74703
75172
  function readSilentEndState2(deps) {
74704
75173
  const statePath = resolveStatePath3(deps);
74705
- if (!existsSync25(statePath))
75174
+ if (!existsSync26(statePath))
74706
75175
  return null;
74707
75176
  try {
74708
- return JSON.parse(readFileSync25(statePath, "utf8"));
75177
+ return JSON.parse(readFileSync26(statePath, "utf8"));
74709
75178
  } catch {
74710
75179
  return null;
74711
75180
  }
@@ -75825,34 +76294,6 @@ function endsWithSilentMarker(text4) {
75825
76294
  return false;
75826
76295
  return isSilentFlushMarker(lines[lines.length - 1]);
75827
76296
  }
75828
- var FLUSH_SUBSTANTIVE_MIN_CHARS = 200;
75829
- function selectFlushDeliveryText(blocks, followedByToolUse) {
75830
- const candidates = blocks.map((b, i) => ({ text: b.trim(), followedByToolUse: followedByToolUse?.[i] })).filter((c) => c.text.length > 0);
75831
- if (candidates.length === 0)
75832
- return "";
75833
- if (candidates.length === 1)
75834
- return candidates[0].text;
75835
- const answer = candidates[candidates.length - 1].text;
75836
- const preceding = candidates.slice(0, -1);
75837
- const allNarration = preceding.every((c) => c.followedByToolUse === true ? isNarrationBlock(c.text) || c.text.trim().length < FLUSH_SUBSTANTIVE_MIN_CHARS : c.followedByToolUse === false ? false : isNarrationBlock(c.text));
75838
- return allNarration ? answer : candidates.map((c) => c.text).join(`
75839
-
75840
- `);
75841
- }
75842
- var NARRATION_OPENER = /^(let me\b|lemme\b|i'?ll\b|i will\b|i am going to\b|i'?m going to\b|i'?m about to\b|going to\b|first,?\s+(?:let me|i'?ll|i will)\b|now,?\s+(?:let me|i'?ll|i will)\b|next,?\s+(?:let me|i'?ll|i will)\b|let'?s\b)/i;
75843
- var NARRATION_TRAILER = /(?:\.{3}|\u2026|:)\s*$/;
75844
- function isTrailingNarrationLine(block) {
75845
- const t = block.trim();
75846
- if (t.length === 0 || t.length >= FLUSH_SUBSTANTIVE_MIN_CHARS)
75847
- return false;
75848
- if (t.includes(`
75849
- `))
75850
- return false;
75851
- return NARRATION_TRAILER.test(t);
75852
- }
75853
- function isNarrationBlock(block) {
75854
- return NARRATION_OPENER.test(block.trimStart()) || isTrailingNarrationLine(block);
75855
- }
75856
76297
  function decideTurnFlush(input) {
75857
76298
  const flushEnabled = input.flushEnabled !== false;
75858
76299
  if (!flushEnabled)
@@ -75872,10 +76313,14 @@ function decideTurnFlush(input) {
75872
76313
  return { kind: "skip", reason: "silent-marker" };
75873
76314
  if (endsWithSilentMarker(joined))
75874
76315
  return { kind: "skip", reason: "silent-marker" };
75875
- return {
75876
- kind: "flush",
75877
- text: selectFlushDeliveryText(input.capturedText, input.capturedBlockMeta)
75878
- };
76316
+ const selected = selectBackstopDelivery(input.capturedText.map((text4, i) => ({
76317
+ text: text4,
76318
+ followedByToolUse: input.capturedBlockMeta?.[i]
76319
+ })));
76320
+ if (selected == null || selected.text.trim().length === 0) {
76321
+ return { kind: "skip", reason: "empty-text" };
76322
+ }
76323
+ return { kind: "flush", text: selected.text };
75879
76324
  }
75880
76325
 
75881
76326
  // answer-stream.ts
@@ -76265,20 +76710,20 @@ var INTERRUPTED_VIA = new Set([
76265
76710
  init_rich_send();
76266
76711
 
76267
76712
  // runtime-metrics.ts
76268
- import { mkdirSync as mkdirSync28, appendFileSync as appendFileSync5 } from "node:fs";
76269
- import { dirname as dirname12, join as join31 } from "node:path";
76713
+ import { mkdirSync as mkdirSync29, appendFileSync as appendFileSync6 } from "node:fs";
76714
+ import { dirname as dirname12, join as join32 } from "node:path";
76270
76715
  function resolveJsonlPath2() {
76271
76716
  const override = process.env.SWITCHROOM_RUNTIME_METRICS_PATH;
76272
76717
  if (override && override.trim() !== "")
76273
76718
  return override.trim();
76274
76719
  const base = process.env.SWITCHROOM_RUNTIME_STATE_DIR ?? "/state/agent";
76275
- return join31(base, "runtime-metrics.jsonl");
76720
+ return join32(base, "runtime-metrics.jsonl");
76276
76721
  }
76277
76722
  function appendJsonl2(line) {
76278
76723
  const path2 = resolveJsonlPath2();
76279
76724
  try {
76280
- mkdirSync28(dirname12(path2), { recursive: true });
76281
- appendFileSync5(path2, line + `
76725
+ mkdirSync29(dirname12(path2), { recursive: true });
76726
+ appendFileSync6(path2, line + `
76282
76727
  `, "utf-8");
76283
76728
  } catch (err) {
76284
76729
  process.stderr.write(`runtime-metrics: jsonl write failed: ${err.message}
@@ -76768,28 +77213,28 @@ function detectStatusSurfaceDegraded(t) {
76768
77213
  // gateway/turn-active-marker.ts
76769
77214
  import {
76770
77215
  closeSync as closeSync5,
76771
- existsSync as existsSync28,
76772
- mkdirSync as mkdirSync29,
77216
+ existsSync as existsSync29,
77217
+ mkdirSync as mkdirSync30,
76773
77218
  openSync as openSync5,
76774
- readFileSync as readFileSync26,
77219
+ readFileSync as readFileSync27,
76775
77220
  statSync as statSync11,
76776
77221
  unlinkSync as unlinkSync14,
76777
77222
  utimesSync,
76778
- writeFileSync as writeFileSync24
77223
+ writeFileSync as writeFileSync25
76779
77224
  } from "node:fs";
76780
- import { join as join32 } from "node:path";
77225
+ import { join as join33 } from "node:path";
76781
77226
  var TURN_ACTIVE_MARKER_FILE = "turn-active.json";
76782
77227
  var TURN_ACTIVE_HARD_TTL_MS = 10 * 60000;
76783
77228
  function writeTurnActiveMarker(stateDir, marker) {
76784
77229
  try {
76785
- mkdirSync29(stateDir, { recursive: true });
76786
- writeFileSync24(join32(stateDir, TURN_ACTIVE_MARKER_FILE), JSON.stringify(marker, null, 2) + `
77230
+ mkdirSync30(stateDir, { recursive: true });
77231
+ writeFileSync25(join33(stateDir, TURN_ACTIVE_MARKER_FILE), JSON.stringify(marker, null, 2) + `
76787
77232
  `, { mode: 384 });
76788
77233
  } catch {}
76789
77234
  }
76790
77235
  function touchTurnActiveMarker(stateDir) {
76791
- const path2 = join32(stateDir, TURN_ACTIVE_MARKER_FILE);
76792
- if (!existsSync28(path2))
77236
+ const path2 = join33(stateDir, TURN_ACTIVE_MARKER_FILE);
77237
+ if (!existsSync29(path2))
76793
77238
  return;
76794
77239
  const now = new Date;
76795
77240
  try {
@@ -76803,11 +77248,11 @@ function touchTurnActiveMarker(stateDir) {
76803
77248
  }
76804
77249
  function removeTurnActiveMarker(stateDir) {
76805
77250
  try {
76806
- unlinkSync14(join32(stateDir, TURN_ACTIVE_MARKER_FILE));
77251
+ unlinkSync14(join33(stateDir, TURN_ACTIVE_MARKER_FILE));
76807
77252
  } catch {}
76808
77253
  }
76809
77254
  function readTurnActiveMarkerAgeMs(stateDir, now) {
76810
- const path2 = join32(stateDir, TURN_ACTIVE_MARKER_FILE);
77255
+ const path2 = join33(stateDir, TURN_ACTIVE_MARKER_FILE);
76811
77256
  try {
76812
77257
  const st = statSync11(path2);
76813
77258
  return (now ?? Date.now()) - st.mtimeMs;
@@ -77229,7 +77674,10 @@ function handleSessionEvent(deps, ev) {
77229
77674
  const turn = getCurrentTurn();
77230
77675
  if (turn == null)
77231
77676
  return;
77232
- clearAnswerReadyFlushTimeout(turn);
77677
+ if (!isEphemeralTool(ev.toolName)) {
77678
+ turn.capturedBlockMeta.fill(true);
77679
+ clearAnswerReadyFlushTimeout(turn);
77680
+ }
77233
77681
  resolvePendingNarrativeOnTool(turn, ev.toolName, ev.input);
77234
77682
  turn.toolCallCount++;
77235
77683
  touchTurnActiveMarker(STATE_DIR);
@@ -77264,7 +77712,9 @@ function handleSessionEvent(deps, ev) {
77264
77712
  const turn = getCurrentTurn();
77265
77713
  if (turn == null)
77266
77714
  return;
77267
- clearAnswerReadyFlushTimeout(turn);
77715
+ if (!isEphemeralTool(ev.toolName)) {
77716
+ clearAnswerReadyFlushTimeout(turn);
77717
+ }
77268
77718
  resetOrphanedReplyTimeout();
77269
77719
  if (isTelegramSurfaceTool(ev.toolName))
77270
77720
  return;
@@ -77642,6 +78092,11 @@ function handleSessionEvent(deps, ev) {
77642
78092
  }
77643
78093
  } catch {}
77644
78094
  }
78095
+ if (backstopAlreadyDelivered(turn.turnId, STATE_DIR)) {
78096
+ process.stderr.write(`telegram gateway: turn-flush skipped \u2014 turn ${turn.turnId} already delivered by a prior backstop (durable journal)
78097
+ `);
78098
+ return;
78099
+ }
77645
78100
  if (!backstopLatchClaimed) {
77646
78101
  process.stderr.write(`telegram gateway: turn-flush skipped \u2014 turn ${turn.turnId} already claimed the delivery latch
77647
78102
  `);
@@ -77704,6 +78159,19 @@ function handleSessionEvent(deps, ev) {
77704
78159
  chunkCount,
77705
78160
  cardMessageId: backstopCardMessageId
77706
78161
  });
78162
+ if (delivered) {
78163
+ try {
78164
+ journalExternalDelivery({
78165
+ turnNonce: turn.turnId,
78166
+ text: capturedText,
78167
+ tgMessageId: sentIds.length > 0 ? sentIds[0] : undefined,
78168
+ deliverySource: "flush"
78169
+ }, STATE_DIR);
78170
+ } catch (err) {
78171
+ process.stderr.write(`telegram gateway: turn-flush delivered but journal write failed (non-fatal): ${err.message}
78172
+ `);
78173
+ }
78174
+ }
77707
78175
  if (OBLIGATION_LEDGER_ENABLED) {
77708
78176
  if (delivered) {
77709
78177
  obligationLedger.close(turn.turnId);
@@ -77764,6 +78232,9 @@ function handleSessionEvent(deps, ev) {
77764
78232
  turnKey: tKey,
77765
78233
  turnId: turn.turnId,
77766
78234
  minChars: proseMinChars
78235
+ }, {
78236
+ isBlockShown: (nonce, text4) => isShownBlock(nonce ?? null, text4),
78237
+ backstopDeliveredNonceHit: (nonce) => backstopAlreadyDelivered(nonce ?? "", STATE_DIR)
77767
78238
  }) : { deliver: false, reason: "no-state" };
77768
78239
  if (proseDecision.deliver && proseDecision.text != null) {
77769
78240
  process.stderr.write(`telegram gateway: captured-prose delivery engaged on first silent-end chat=${chatId} turnKey=${tKey} (#3227)
@@ -77903,6 +78374,7 @@ class NarrativeFlushController {
77903
78374
  this.scheduler.disarm();
77904
78375
  if (this.pending != null) {
77905
78376
  this.effects.show(this.pending);
78377
+ this.markShown(this.pending);
77906
78378
  }
77907
78379
  this.pending = text4;
77908
78380
  this.scheduler.arm(() => this.onTimerFire(), this.flushMs);
@@ -77927,6 +78399,7 @@ class NarrativeFlushController {
77927
78399
  if (replyText != null && isDraftOfReply(pending, replyText))
77928
78400
  return;
77929
78401
  this.effects.show(pending);
78402
+ this.markShown(pending);
77930
78403
  }
77931
78404
  flushAtTurnEnd(lastReplyText) {
77932
78405
  this.scheduler.disarm();
@@ -77945,6 +78418,13 @@ class NarrativeFlushController {
77945
78418
  this.pending = null;
77946
78419
  this.timerShown = null;
77947
78420
  }
78421
+ markShown(text4) {
78422
+ if (this.effects.markDurableNarration == null)
78423
+ return;
78424
+ if (!isStructuralNarration(text4, true))
78425
+ return;
78426
+ this.effects.markDurableNarration(text4);
78427
+ }
77948
78428
  maybeRetract(replyText) {
77949
78429
  const shown = this.timerShown;
77950
78430
  if (shown == null)
@@ -78096,7 +78576,12 @@ function createNarrativeLane(deps) {
78096
78576
  let handle = null;
78097
78577
  return new NarrativeFlushController({
78098
78578
  show: (text4) => showNarrativeStep(turn, text4),
78099
- retractShown: (text4) => retractNarrativeLine(turn, text4)
78579
+ retractShown: (text4) => retractNarrativeLine(turn, text4),
78580
+ markDurableNarration: (text4) => {
78581
+ if (turn.turnId == null)
78582
+ return;
78583
+ appendShownBlock(turn.turnId, text4);
78584
+ }
78100
78585
  }, {
78101
78586
  arm: (fn, ms) => {
78102
78587
  if (handle != null)
@@ -78694,19 +79179,19 @@ function resolveAgentDirFromEnv() {
78694
79179
  }
78695
79180
 
78696
79181
  // active-reactions.ts
78697
- import { readFileSync as readFileSync27, writeFileSync as writeFileSync25, renameSync as renameSync9, existsSync as existsSync29, unlinkSync as unlinkSync15 } from "node:fs";
78698
- import { join as join33 } from "node:path";
79182
+ import { readFileSync as readFileSync28, writeFileSync as writeFileSync26, renameSync as renameSync10, existsSync as existsSync30, unlinkSync as unlinkSync15 } from "node:fs";
79183
+ import { join as join34 } from "node:path";
78699
79184
  var ACTIVE_REACTIONS_FILENAME = ".active-reactions.json";
78700
79185
  function reactionsPath(agentDir) {
78701
- return join33(agentDir, ACTIVE_REACTIONS_FILENAME);
79186
+ return join34(agentDir, ACTIVE_REACTIONS_FILENAME);
78702
79187
  }
78703
79188
  function readActiveReactions(agentDir) {
78704
79189
  const p = reactionsPath(agentDir);
78705
- if (!existsSync29(p))
79190
+ if (!existsSync30(p))
78706
79191
  return [];
78707
79192
  let raw;
78708
79193
  try {
78709
- raw = readFileSync27(p, "utf-8");
79194
+ raw = readFileSync28(p, "utf-8");
78710
79195
  } catch {
78711
79196
  return [];
78712
79197
  }
@@ -78738,9 +79223,9 @@ function writeActiveReactions(agentDir, reactions) {
78738
79223
  }
78739
79224
  const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
78740
79225
  try {
78741
- writeFileSync25(tmp, JSON.stringify(reactions) + `
79226
+ writeFileSync26(tmp, JSON.stringify(reactions) + `
78742
79227
  `, "utf-8");
78743
- renameSync9(tmp, p);
79228
+ renameSync10(tmp, p);
78744
79229
  } catch {}
78745
79230
  }
78746
79231
  function addActiveReaction(agentDir, reaction) {
@@ -78762,19 +79247,19 @@ function clearActiveReactions(agentDir) {
78762
79247
  }
78763
79248
 
78764
79249
  // active-reactions.ts
78765
- import { readFileSync as readFileSync28, writeFileSync as writeFileSync26, renameSync as renameSync10, existsSync as existsSync30, unlinkSync as unlinkSync16 } from "node:fs";
78766
- import { join as join34 } from "node:path";
79250
+ import { readFileSync as readFileSync29, writeFileSync as writeFileSync27, renameSync as renameSync11, existsSync as existsSync31, unlinkSync as unlinkSync16 } from "node:fs";
79251
+ import { join as join35 } from "node:path";
78767
79252
  var ACTIVE_REACTIONS_FILENAME2 = ".active-reactions.json";
78768
79253
  function reactionsPath2(agentDir) {
78769
- return join34(agentDir, ACTIVE_REACTIONS_FILENAME2);
79254
+ return join35(agentDir, ACTIVE_REACTIONS_FILENAME2);
78770
79255
  }
78771
79256
  function readActiveReactions2(agentDir) {
78772
79257
  const p = reactionsPath2(agentDir);
78773
- if (!existsSync30(p))
79258
+ if (!existsSync31(p))
78774
79259
  return [];
78775
79260
  let raw;
78776
79261
  try {
78777
- raw = readFileSync28(p, "utf-8");
79262
+ raw = readFileSync29(p, "utf-8");
78778
79263
  } catch {
78779
79264
  return [];
78780
79265
  }
@@ -79642,17 +80127,17 @@ async function approvalRecord(args, opts) {
79642
80127
  }
79643
80128
 
79644
80129
  // quota-check.ts
79645
- import { readFileSync as readFileSync29, existsSync as existsSync31 } from "fs";
79646
- import { join as join35 } from "path";
80130
+ import { readFileSync as readFileSync30, existsSync as existsSync32 } from "fs";
80131
+ import { join as join36 } from "path";
79647
80132
  var OAUTH_BETA2 = "oauth-2025-04-20";
79648
80133
  var DEFAULT_USER_AGENT2 = "claude-cli/1.0.0 (external, cli)";
79649
80134
  var DEFAULT_PROBE_MODEL2 = "claude-haiku-4-5-20251001";
79650
80135
  function readOauthToken2(claudeConfigDir) {
79651
- const tokenFile = join35(claudeConfigDir, ".oauth-token");
79652
- if (!existsSync31(tokenFile))
80136
+ const tokenFile = join36(claudeConfigDir, ".oauth-token");
80137
+ if (!existsSync32(tokenFile))
79653
80138
  return null;
79654
80139
  try {
79655
- const raw = readFileSync29(tokenFile, "utf-8").trim();
80140
+ const raw = readFileSync30(tokenFile, "utf-8").trim();
79656
80141
  return raw.length > 0 ? raw : null;
79657
80142
  } catch {
79658
80143
  return null;
@@ -80988,15 +81473,15 @@ async function menuWithBannerStatic(deps, banner) {
80988
81473
  }
80989
81474
 
80990
81475
  // gateway/session-model-file.ts
80991
- import { readFileSync as readFileSync30, writeFileSync as writeFileSync27, renameSync as renameSync11, rmSync as rmSync4 } from "node:fs";
80992
- import { join as join36 } from "node:path";
81476
+ import { readFileSync as readFileSync31, writeFileSync as writeFileSync28, renameSync as renameSync12, rmSync as rmSync4 } from "node:fs";
81477
+ import { join as join37 } from "node:path";
80993
81478
  var SESSION_MODEL_FILE = ".session-model";
80994
81479
  var CONFIGURED_DEFAULT_MODEL_FILE = ".configured-default-model";
80995
81480
  var SESSION_MODEL_BOOT_ATTEMPTS_FILE = ".session-model-boot-attempts";
80996
81481
  function atomicWrite(path2, content3) {
80997
81482
  const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
80998
- writeFileSync27(tmp, content3, "utf8");
80999
- renameSync11(tmp, path2);
81483
+ writeFileSync28(tmp, content3, "utf8");
81484
+ renameSync12(tmp, path2);
81000
81485
  }
81001
81486
  function serializeSessionModel(rec) {
81002
81487
  return `${JSON.stringify({
@@ -81011,28 +81496,28 @@ function writeSessionModelFile(agentDir, model, configuredDefaultAtWrite) {
81011
81496
  throw new Error(`refusing to persist non-canonical session model token: ${JSON.stringify(model)}`);
81012
81497
  }
81013
81498
  try {
81014
- rmSync4(join36(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
81499
+ rmSync4(join37(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
81015
81500
  } catch {}
81016
- atomicWrite(join36(agentDir, SESSION_MODEL_FILE), serializeSessionModel({ model, configuredDefaultAtWrite, ts: Date.now() }));
81501
+ atomicWrite(join37(agentDir, SESSION_MODEL_FILE), serializeSessionModel({ model, configuredDefaultAtWrite, ts: Date.now() }));
81017
81502
  }
81018
81503
  function readSessionModelFileRaw(agentDir) {
81019
81504
  try {
81020
- return readFileSync30(join36(agentDir, SESSION_MODEL_FILE), "utf8");
81505
+ return readFileSync31(join37(agentDir, SESSION_MODEL_FILE), "utf8");
81021
81506
  } catch {
81022
81507
  return null;
81023
81508
  }
81024
81509
  }
81025
81510
  function clearSessionModelFile(agentDir) {
81026
81511
  try {
81027
- rmSync4(join36(agentDir, SESSION_MODEL_FILE), { force: true });
81512
+ rmSync4(join37(agentDir, SESSION_MODEL_FILE), { force: true });
81028
81513
  } catch {}
81029
81514
  }
81030
81515
  function consumeSessionModelCarrierOnHealthyBoot(agentDir) {
81031
81516
  try {
81032
- rmSync4(join36(agentDir, SESSION_MODEL_FILE), { force: true });
81517
+ rmSync4(join37(agentDir, SESSION_MODEL_FILE), { force: true });
81033
81518
  } catch {}
81034
81519
  try {
81035
- rmSync4(join36(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
81520
+ rmSync4(join37(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
81036
81521
  } catch {}
81037
81522
  }
81038
81523
  function restoreSessionModelFileRaw(agentDir, raw) {
@@ -81041,12 +81526,12 @@ function restoreSessionModelFileRaw(agentDir, raw) {
81041
81526
  return;
81042
81527
  }
81043
81528
  try {
81044
- atomicWrite(join36(agentDir, SESSION_MODEL_FILE), raw);
81529
+ atomicWrite(join37(agentDir, SESSION_MODEL_FILE), raw);
81045
81530
  } catch {}
81046
81531
  }
81047
81532
  function readConfiguredDefaultModel(agentDir) {
81048
81533
  try {
81049
- const v = readFileSync30(join36(agentDir, CONFIGURED_DEFAULT_MODEL_FILE), "utf8").trim();
81534
+ const v = readFileSync31(join37(agentDir, CONFIGURED_DEFAULT_MODEL_FILE), "utf8").trim();
81050
81535
  return v.length > 0 ? v : null;
81051
81536
  } catch {
81052
81537
  return null;
@@ -81058,12 +81543,12 @@ function writeSessionEffortFile(agentDir, level, configuredDefaultAtWrite) {
81058
81543
  if (!EFFORT_LEVEL_RE.test(level)) {
81059
81544
  throw new Error(`refusing to persist non-allowlisted effort level: ${JSON.stringify(level)}`);
81060
81545
  }
81061
- atomicWrite(join36(agentDir, SESSION_EFFORT_FILE), `${JSON.stringify({ level, configuredDefaultAtWrite: configuredDefaultAtWrite ?? "", ts: Date.now() })}
81546
+ atomicWrite(join37(agentDir, SESSION_EFFORT_FILE), `${JSON.stringify({ level, configuredDefaultAtWrite: configuredDefaultAtWrite ?? "", ts: Date.now() })}
81062
81547
  `);
81063
81548
  }
81064
81549
  function clearSessionEffortFile(agentDir) {
81065
81550
  try {
81066
- rmSync4(join36(agentDir, SESSION_EFFORT_FILE), { force: true });
81551
+ rmSync4(join37(agentDir, SESSION_EFFORT_FILE), { force: true });
81067
81552
  } catch {}
81068
81553
  }
81069
81554
  var PREMIUM_RECOVERY_FILE = ".premium-recovery";
@@ -81086,13 +81571,13 @@ function writePremiumRecoveryFile(agentDir, premiumModel, chats) {
81086
81571
  if (clean.length === 0) {
81087
81572
  throw new Error("refusing to persist premium-recovery marker with no chats to notify");
81088
81573
  }
81089
- atomicWrite(join36(agentDir, PREMIUM_RECOVERY_FILE), `${JSON.stringify({ premiumModel, chats: clean, ts: Date.now() })}
81574
+ atomicWrite(join37(agentDir, PREMIUM_RECOVERY_FILE), `${JSON.stringify({ premiumModel, chats: clean, ts: Date.now() })}
81090
81575
  `);
81091
81576
  }
81092
81577
  function readPremiumRecoveryFile(agentDir) {
81093
81578
  let raw;
81094
81579
  try {
81095
- raw = readFileSync30(join36(agentDir, PREMIUM_RECOVERY_FILE), "utf8");
81580
+ raw = readFileSync31(join37(agentDir, PREMIUM_RECOVERY_FILE), "utf8");
81096
81581
  } catch {
81097
81582
  return null;
81098
81583
  }
@@ -81105,7 +81590,7 @@ function readPremiumRecoveryFile(agentDir) {
81105
81590
  }
81106
81591
  function clearPremiumRecoveryFile(agentDir) {
81107
81592
  try {
81108
- rmSync4(join36(agentDir, PREMIUM_RECOVERY_FILE), { force: true });
81593
+ rmSync4(join37(agentDir, PREMIUM_RECOVERY_FILE), { force: true });
81109
81594
  } catch {}
81110
81595
  }
81111
81596
 
@@ -81394,7 +81879,7 @@ async function discoverModels(agentName3, opts = {}) {
81394
81879
  }
81395
81880
 
81396
81881
  // ../src/agents/scaffold.ts
81397
- import { dirname as dirname14, isAbsolute, join as join39, relative, resolve as resolve8 } from "node:path";
81882
+ import { dirname as dirname14, isAbsolute, join as join40, relative, resolve as resolve8 } from "node:path";
81398
81883
  init_atomic();
81399
81884
 
81400
81885
  // ../src/agents/agent-uid.ts
@@ -81411,7 +81896,7 @@ init_merge();
81411
81896
  init_timezone();
81412
81897
 
81413
81898
  // ../src/cli/agent-config.ts
81414
- import { join as join37 } from "node:path";
81899
+ import { join as join38 } from "node:path";
81415
81900
  import { homedir as homedir12 } from "node:os";
81416
81901
 
81417
81902
  // ../src/cli/helpers.ts
@@ -81432,12 +81917,12 @@ var WEBKITE_VAULT_KEYS = new Set([
81432
81917
  init_overlay_loader();
81433
81918
 
81434
81919
  // ../src/cli/agent-config.ts
81435
- var AUDIT_ROOT = join37(homedir12(), ".switchroom", "audit");
81920
+ var AUDIT_ROOT = join38(homedir12(), ".switchroom", "audit");
81436
81921
 
81437
81922
  // ../src/agents/profiles.ts
81438
81923
  var import_handlebars = __toESM(require_lib(), 1);
81439
- import { readFileSync as readFileSync31, writeFileSync as writeFileSync28, existsSync as existsSync32, readdirSync as readdirSync7, statSync as statSync12, copyFileSync, mkdirSync as mkdirSync30, realpathSync as realpathSync2 } from "node:fs";
81440
- import { resolve as resolve7, join as join38, sep as pathSep } from "node:path";
81924
+ import { readFileSync as readFileSync32, writeFileSync as writeFileSync29, existsSync as existsSync33, readdirSync as readdirSync7, statSync as statSync12, copyFileSync, mkdirSync as mkdirSync31, realpathSync as realpathSync2 } from "node:fs";
81925
+ import { resolve as resolve7, join as join39, sep as pathSep } from "node:path";
81441
81926
  function resolveProfilesRoot() {
81442
81927
  const envOverride = process.env.SWITCHROOM_PROFILES_ROOT?.trim();
81443
81928
  if (envOverride) {
@@ -81448,7 +81933,7 @@ function resolveProfilesRoot() {
81448
81933
  resolve7(import.meta.dirname, "profiles")
81449
81934
  ];
81450
81935
  for (const candidate of candidates) {
81451
- if (existsSync32(candidate)) {
81936
+ if (existsSync33(candidate)) {
81452
81937
  return candidate;
81453
81938
  }
81454
81939
  }
@@ -81464,9 +81949,9 @@ import_handlebars.default.registerHelper("isNumber", (value) => {
81464
81949
  var SHARED_FRAGMENTS_DIR = resolve7(PROFILES_ROOT, "_shared");
81465
81950
  var SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol"];
81466
81951
  for (const name of SHARED_FRAGMENTS) {
81467
- const fragPath = join38(SHARED_FRAGMENTS_DIR, `${name}.md.hbs`);
81468
- if (existsSync32(fragPath)) {
81469
- import_handlebars.default.registerPartial(name, readFileSync31(fragPath, "utf-8"));
81952
+ const fragPath = join39(SHARED_FRAGMENTS_DIR, `${name}.md.hbs`);
81953
+ if (existsSync33(fragPath)) {
81954
+ import_handlebars.default.registerPartial(name, readFileSync32(fragPath, "utf-8"));
81470
81955
  }
81471
81956
  }
81472
81957
 
@@ -82073,7 +82558,7 @@ init_overlay_loader();
82073
82558
  init_merge();
82074
82559
  init_timezone();
82075
82560
  var import_yaml4 = __toESM(require_dist(), 1);
82076
- import { readFileSync as readFileSync32, existsSync as existsSync33 } from "node:fs";
82561
+ import { readFileSync as readFileSync33, existsSync as existsSync34 } from "node:fs";
82077
82562
  import { homedir as homedir13 } from "node:os";
82078
82563
  import { resolve as resolve9 } from "node:path";
82079
82564
 
@@ -82149,7 +82634,7 @@ function findConfigFile2(startDir) {
82149
82634
  resolve9(userDir, "clerk.yml")
82150
82635
  ].filter(Boolean);
82151
82636
  for (const path2 of searchPaths) {
82152
- if (existsSync33(path2)) {
82637
+ if (existsSync34(path2)) {
82153
82638
  return path2;
82154
82639
  }
82155
82640
  }
@@ -82157,12 +82642,12 @@ function findConfigFile2(startDir) {
82157
82642
  }
82158
82643
  function loadConfig2(configPath) {
82159
82644
  const filePath = configPath ?? findConfigFile2();
82160
- if (!existsSync33(filePath)) {
82645
+ if (!existsSync34(filePath)) {
82161
82646
  throw new ConfigError2(`Config file not found: ${filePath}`);
82162
82647
  }
82163
82648
  let raw;
82164
82649
  try {
82165
- raw = readFileSync32(filePath, "utf-8");
82650
+ raw = readFileSync33(filePath, "utf-8");
82166
82651
  } catch (err) {
82167
82652
  throw new ConfigError2(`Failed to read config file: ${filePath}`, [
82168
82653
  ` ${err.message}`
@@ -82692,15 +83177,15 @@ function topicForRecipient(args) {
82692
83177
  }
82693
83178
 
82694
83179
  // ../src/agents/perf.ts
82695
- import { existsSync as existsSync34, readFileSync as readFileSync33 } from "node:fs";
83180
+ import { existsSync as existsSync35, readFileSync as readFileSync34 } from "node:fs";
82696
83181
  function readTurnUsages(jsonlPath, lastN) {
82697
- if (!existsSync34(jsonlPath))
83182
+ if (!existsSync35(jsonlPath))
82698
83183
  return [];
82699
83184
  if (lastN <= 0)
82700
83185
  return [];
82701
83186
  let raw;
82702
83187
  try {
82703
- raw = readFileSync33(jsonlPath, "utf-8");
83188
+ raw = readFileSync34(jsonlPath, "utf-8");
82704
83189
  } catch {
82705
83190
  return [];
82706
83191
  }
@@ -82791,8 +83276,8 @@ function numField(obj, key) {
82791
83276
  }
82792
83277
 
82793
83278
  // gateway/context-occupancy.ts
82794
- import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync29 } from "node:fs";
82795
- import { join as join40 } from "node:path";
83279
+ import { mkdirSync as mkdirSync32, writeFileSync as writeFileSync30 } from "node:fs";
83280
+ import { join as join41 } from "node:path";
82796
83281
  var CONTEXT_OCCUPANCY_FILENAME = "context-occupancy.json";
82797
83282
  var TIGHT_FRACTION = 0.8;
82798
83283
  function buildContextOccupancy(occupancy, cap, now) {
@@ -82815,9 +83300,9 @@ function buildContextOccupancy(occupancy, cap, now) {
82815
83300
  }
82816
83301
  function writeContextOccupancySnapshot(stateDir, snapshot, deps) {
82817
83302
  try {
82818
- const path2 = join40(stateDir, CONTEXT_OCCUPANCY_FILENAME);
82819
- (deps?.mkdir ?? ((p, o) => mkdirSync31(p, o)))(stateDir, { recursive: true });
82820
- (deps?.writeFile ?? ((p, d) => writeFileSync29(p, d)))(path2, JSON.stringify(snapshot, null, 2) + `
83303
+ const path2 = join41(stateDir, CONTEXT_OCCUPANCY_FILENAME);
83304
+ (deps?.mkdir ?? ((p, o) => mkdirSync32(p, o)))(stateDir, { recursive: true });
83305
+ (deps?.writeFile ?? ((p, d) => writeFileSync30(p, d)))(path2, JSON.stringify(snapshot, null, 2) + `
82821
83306
  `);
82822
83307
  } catch {}
82823
83308
  }
@@ -82971,7 +83456,7 @@ function nextCompactNotify(state6, ev) {
82971
83456
  }
82972
83457
 
82973
83458
  // gateway/hostd-dispatch.ts
82974
- import { existsSync as existsSync35 } from "node:fs";
83459
+ import { existsSync as existsSync36 } from "node:fs";
82975
83460
  import { randomBytes as randomBytes7 } from "node:crypto";
82976
83461
  init_loader();
82977
83462
  var _hostdEnabled2;
@@ -82995,13 +83480,13 @@ function hostdSocketPath2(agentName3) {
82995
83480
  function hostdWillBeUsed2(agentName3) {
82996
83481
  if (!isHostdEnabled2())
82997
83482
  return false;
82998
- return existsSync35(hostdSocketPath2(agentName3));
83483
+ return existsSync36(hostdSocketPath2(agentName3));
82999
83484
  }
83000
83485
  async function tryHostdDispatch2(agentName3, req, timeoutMs = 5000) {
83001
83486
  if (!isHostdEnabled2())
83002
83487
  return "not-configured";
83003
83488
  const sockPath = hostdSocketPath2(agentName3);
83004
- if (!existsSync35(sockPath))
83489
+ if (!existsSync36(sockPath))
83005
83490
  return "not-configured";
83006
83491
  try {
83007
83492
  return await hostdRequest({ socketPath: sockPath, timeoutMs }, req);
@@ -83030,7 +83515,7 @@ async function pollHostdStatus(agentName3, targetRequestId, opts) {
83030
83515
  if (!isHostdEnabled2())
83031
83516
  return "not-configured";
83032
83517
  const sockPath = hostdSocketPath2(agentName3);
83033
- if (!existsSync35(sockPath))
83518
+ if (!existsSync36(sockPath))
83034
83519
  return "not-configured";
83035
83520
  const now = opts.now ?? Date.now;
83036
83521
  const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
@@ -83149,7 +83634,7 @@ function createDmPinSweeper(deps) {
83149
83634
 
83150
83635
  // gateway/webhook-ingest-server.ts
83151
83636
  import net4 from "node:net";
83152
- import { chmodSync as chmodSync10, existsSync as existsSync36, unlinkSync as unlinkSync17 } from "node:fs";
83637
+ import { chmodSync as chmodSync10, existsSync as existsSync37, unlinkSync as unlinkSync17 } from "node:fs";
83153
83638
  var MAX_REQUEST_BYTES = 1024 * 1024;
83154
83639
  function fdOf(conn) {
83155
83640
  const handle = conn._handle;
@@ -83161,7 +83646,7 @@ function startWebhookIngestServer(opts) {
83161
83646
  const log = opts.log ?? ((s) => process.stderr.write(s));
83162
83647
  const allowed = new Set(opts.allowedUids);
83163
83648
  try {
83164
- if (existsSync36(opts.socketPath))
83649
+ if (existsSync37(opts.socketPath))
83165
83650
  unlinkSync17(opts.socketPath);
83166
83651
  } catch (err) {
83167
83652
  log(`webhook-ingest-server: could not unlink stale socket: ${err.message}
@@ -83254,7 +83739,7 @@ function startWebhookIngestServer(opts) {
83254
83739
  server.close();
83255
83740
  } catch {}
83256
83741
  try {
83257
- if (existsSync36(opts.socketPath))
83742
+ if (existsSync37(opts.socketPath))
83258
83743
  unlinkSync17(opts.socketPath);
83259
83744
  } catch {}
83260
83745
  }
@@ -83262,20 +83747,20 @@ function startWebhookIngestServer(opts) {
83262
83747
  }
83263
83748
 
83264
83749
  // ../src/web/webhook-gateway-record.ts
83265
- import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync34 } from "fs";
83266
- import { join as join43 } from "path";
83750
+ import { appendFileSync as appendFileSync8, mkdirSync as mkdirSync35 } from "fs";
83751
+ import { join as join44 } from "path";
83267
83752
  import { homedir as homedir15 } from "os";
83268
83753
 
83269
83754
  // ../src/web/webhook-handler.ts
83270
- import { appendFileSync as appendFileSync6, existsSync as existsSync37, mkdirSync as mkdirSync32, readFileSync as readFileSync34, writeFileSync as writeFileSync30 } from "fs";
83271
- import { join as join41 } from "path";
83755
+ import { appendFileSync as appendFileSync7, existsSync as existsSync38, mkdirSync as mkdirSync33, readFileSync as readFileSync35, writeFileSync as writeFileSync31 } from "fs";
83756
+ import { join as join42 } from "path";
83272
83757
  var DEDUP_MAX = 1000;
83273
83758
  var DEDUP_TTL_MS = 24 * 60 * 60 * 1000;
83274
83759
  function loadDedupFile(path2) {
83275
83760
  try {
83276
- if (!existsSync37(path2))
83761
+ if (!existsSync38(path2))
83277
83762
  return {};
83278
- const raw = JSON.parse(readFileSync34(path2, "utf-8"));
83763
+ const raw = JSON.parse(readFileSync35(path2, "utf-8"));
83279
83764
  return typeof raw.deliveries === "object" && raw.deliveries !== null ? raw.deliveries : {};
83280
83765
  } catch {
83281
83766
  return {};
@@ -83289,7 +83774,7 @@ function saveDedupFile(path2, deliveries, now) {
83289
83774
  }
83290
83775
  const sorted = Object.entries(pruned).sort((a, b) => b[1] - a[1]).slice(0, DEDUP_MAX);
83291
83776
  const final = Object.fromEntries(sorted);
83292
- writeFileSync30(path2, JSON.stringify({ deliveries: final }), {
83777
+ writeFileSync31(path2, JSON.stringify({ deliveries: final }), {
83293
83778
  mode: 384
83294
83779
  });
83295
83780
  }
@@ -83297,8 +83782,8 @@ var agentDedupCache = new Map;
83297
83782
  function createFileDedupStore(resolveAgentDir) {
83298
83783
  return {
83299
83784
  check(agent, deliveryId, now) {
83300
- const telegramDir = join41(resolveAgentDir(agent), "telegram");
83301
- const filePath = join41(telegramDir, "webhook-dedup.json");
83785
+ const telegramDir = join42(resolveAgentDir(agent), "telegram");
83786
+ const filePath = join42(telegramDir, "webhook-dedup.json");
83302
83787
  if (!agentDedupCache.has(agent)) {
83303
83788
  agentDedupCache.set(agent, loadDedupFile(filePath));
83304
83789
  }
@@ -83308,7 +83793,7 @@ function createFileDedupStore(resolveAgentDir) {
83308
83793
  }
83309
83794
  deliveries[deliveryId] = now;
83310
83795
  try {
83311
- mkdirSync32(telegramDir, { recursive: true });
83796
+ mkdirSync33(telegramDir, { recursive: true });
83312
83797
  saveDedupFile(filePath, deliveries, now);
83313
83798
  } catch {}
83314
83799
  return;
@@ -83319,8 +83804,8 @@ var tokenBuckets = new Map;
83319
83804
  var throttleIssueWindow = new Map;
83320
83805
 
83321
83806
  // ../src/web/webhook-dispatch.ts
83322
- import { existsSync as existsSync38, mkdirSync as mkdirSync33, readFileSync as readFileSync35, writeFileSync as writeFileSync31 } from "fs";
83323
- import { join as join42 } from "path";
83807
+ import { existsSync as existsSync39, mkdirSync as mkdirSync34, readFileSync as readFileSync36, writeFileSync as writeFileSync32 } from "fs";
83808
+ import { join as join43 } from "path";
83324
83809
  import { homedir as homedir14 } from "os";
83325
83810
 
83326
83811
  // ../src/agent-scheduler/ipc-client.ts
@@ -83619,9 +84104,9 @@ function cooldownKey(source, eventType, repo, number, ruleIndex) {
83619
84104
  }
83620
84105
  function loadCooldownFile(path2) {
83621
84106
  try {
83622
- if (!existsSync38(path2))
84107
+ if (!existsSync39(path2))
83623
84108
  return {};
83624
- const raw = JSON.parse(readFileSync35(path2, "utf-8"));
84109
+ const raw = JSON.parse(readFileSync36(path2, "utf-8"));
83625
84110
  return typeof raw.dispatches === "object" && raw.dispatches !== null ? raw.dispatches : {};
83626
84111
  } catch {
83627
84112
  return {};
@@ -83629,7 +84114,7 @@ function loadCooldownFile(path2) {
83629
84114
  }
83630
84115
  function saveCooldownFile(path2, dispatches) {
83631
84116
  try {
83632
- writeFileSync31(path2, JSON.stringify({ dispatches }), {
84117
+ writeFileSync32(path2, JSON.stringify({ dispatches }), {
83633
84118
  mode: 384
83634
84119
  });
83635
84120
  } catch {}
@@ -83640,8 +84125,8 @@ function createFileCooldownStore(resolveAgentDir) {
83640
84125
  isCoolingDown(agent, key, cooldownMs, now) {
83641
84126
  if (cooldownMs <= 0)
83642
84127
  return false;
83643
- const telegramDir = join42(resolveAgentDir(agent), "telegram");
83644
- const filePath = join42(telegramDir, "webhook-cooldown.json");
84128
+ const telegramDir = join43(resolveAgentDir(agent), "telegram");
84129
+ const filePath = join43(telegramDir, "webhook-cooldown.json");
83645
84130
  if (!cache.has(agent)) {
83646
84131
  cache.set(agent, loadCooldownFile(filePath));
83647
84132
  }
@@ -83652,7 +84137,7 @@ function createFileCooldownStore(resolveAgentDir) {
83652
84137
  }
83653
84138
  dispatches[key] = now;
83654
84139
  try {
83655
- mkdirSync33(telegramDir, { recursive: true });
84140
+ mkdirSync34(telegramDir, { recursive: true });
83656
84141
  saveCooldownFile(filePath, dispatches);
83657
84142
  } catch {}
83658
84143
  return false;
@@ -83698,9 +84183,9 @@ async function defaultInject(socketPath, agentName3, inbound) {
83698
84183
  }
83699
84184
  function injectWebhookInbound(agent, prompt, ctx, deps = {}) {
83700
84185
  const log = deps.log ?? ((s) => process.stderr.write(s));
83701
- const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join42(homedir14(), ".switchroom", "agents", a));
84186
+ const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join43(homedir14(), ".switchroom", "agents", a));
83702
84187
  const now = (deps.now ?? Date.now)();
83703
- const socketPath = join42(resolveAgentDir(agent), "telegram", "gateway.sock");
84188
+ const socketPath = join43(resolveAgentDir(agent), "telegram", "gateway.sock");
83704
84189
  const inbound = {
83705
84190
  type: "inbound",
83706
84191
  chatId: ctx.chatId,
@@ -83772,7 +84257,7 @@ function evaluateDispatch(args, deps = {}) {
83772
84257
  const log = deps.log ?? ((s) => process.stderr.write(s));
83773
84258
  const now = (deps.now ?? Date.now)();
83774
84259
  const nowDate = deps.nowDate ?? (() => new Date(now));
83775
- const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join42(homedir14(), ".switchroom", "agents", a));
84260
+ const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join43(homedir14(), ".switchroom", "agents", a));
83776
84261
  const cooldownStore = deps.cooldownStore ?? createFileCooldownStore(resolveAgentDir);
83777
84262
  if (!DISPATCH_SOURCES.includes(args.source))
83778
84263
  return 0;
@@ -83850,10 +84335,10 @@ var CONSOLIDATION_COMPLETED_EVENT = "consolidation.completed";
83850
84335
  function recordWebhookEvent(rec, deps = {}) {
83851
84336
  const log = deps.log ?? ((s) => process.stderr.write(s));
83852
84337
  const now = rec.ts || (deps.now ?? Date.now)();
83853
- const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join43(homedir15(), ".switchroom", "agents", a));
84338
+ const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join44(homedir15(), ".switchroom", "agents", a));
83854
84339
  const dedupStore = deps.dedupStore ?? createFileDedupStore(resolveAgentDir);
83855
84340
  const agent = rec.agent;
83856
- const telegramDir = join43(resolveAgentDir(agent), "telegram");
84341
+ const telegramDir = join44(resolveAgentDir(agent), "telegram");
83857
84342
  if (rec.source === "github" && rec.delivery_id) {
83858
84343
  const originalTs = dedupStore.check(agent, rec.delivery_id, now);
83859
84344
  if (originalTs !== undefined) {
@@ -83862,9 +84347,9 @@ function recordWebhookEvent(rec, deps = {}) {
83862
84347
  return { status: "deduped", ts: originalTs };
83863
84348
  }
83864
84349
  }
83865
- const logPath = join43(telegramDir, "webhook-events.jsonl");
84350
+ const logPath = join44(telegramDir, "webhook-events.jsonl");
83866
84351
  try {
83867
- mkdirSync34(telegramDir, { recursive: true });
84352
+ mkdirSync35(telegramDir, { recursive: true });
83868
84353
  const record = {
83869
84354
  ts: now,
83870
84355
  source: rec.source,
@@ -83872,7 +84357,7 @@ function recordWebhookEvent(rec, deps = {}) {
83872
84357
  rendered_text: rec.rendered_text,
83873
84358
  payload: rec.payload
83874
84359
  };
83875
- appendFileSync7(logPath, JSON.stringify(record) + `
84360
+ appendFileSync8(logPath, JSON.stringify(record) + `
83876
84361
  `, { mode: 384 });
83877
84362
  } catch (err) {
83878
84363
  log(`webhook-gateway: agent='${agent}' source='${rec.source}' write failed: ${err.message}
@@ -83974,7 +84459,7 @@ function recordWebhookEvent(rec, deps = {}) {
83974
84459
 
83975
84460
  // gateway/ipc-server.ts
83976
84461
  init_format();
83977
- import { renameSync as renameSync13, unlinkSync as unlinkSync18, chmodSync as chmodSync11 } from "fs";
84462
+ import { renameSync as renameSync14, unlinkSync as unlinkSync18, chmodSync as chmodSync11 } from "fs";
83978
84463
  var MAX_BUFFER_SIZE = 1024 * 1024;
83979
84464
  var VALID_OPERATOR_KINDS = new Set([
83980
84465
  "credentials-expired",
@@ -84183,7 +84668,7 @@ function createIpcServer(options) {
84183
84668
  heartbeatTimeoutMs = 30000
84184
84669
  } = options;
84185
84670
  try {
84186
- renameSync13(socketPath, socketPath + ".bak");
84671
+ renameSync14(socketPath, socketPath + ".bak");
84187
84672
  } catch {}
84188
84673
  try {
84189
84674
  unlinkSync18(socketPath + ".bak");
@@ -84573,7 +85058,7 @@ function createIpcServer(options) {
84573
85058
  clientBySocketId.clear();
84574
85059
  server.stop(true);
84575
85060
  try {
84576
- renameSync13(socketPath, socketPath + ".bak");
85061
+ renameSync14(socketPath, socketPath + ".bak");
84577
85062
  } catch {}
84578
85063
  }
84579
85064
  };
@@ -88508,27 +88993,27 @@ function skillProposalKeyboard(id) {
88508
88993
  // ../src/self-improve/skill-proposals.ts
88509
88994
  import {
88510
88995
  closeSync as closeSync7,
88511
- existsSync as existsSync39,
88512
- mkdirSync as mkdirSync35,
88996
+ existsSync as existsSync40,
88997
+ mkdirSync as mkdirSync36,
88513
88998
  openSync as openSync7,
88514
- readFileSync as readFileSync36,
88999
+ readFileSync as readFileSync37,
88515
89000
  writeSync as writeSync5
88516
89001
  } from "node:fs";
88517
- import { join as join44 } from "node:path";
89002
+ import { join as join45 } from "node:path";
88518
89003
  import { randomUUID as randomUUID5 } from "node:crypto";
88519
89004
  var PROPOSALS_FILE2 = "skill-proposals.jsonl";
88520
89005
  var REJECTED_FILE2 = "skill-proposals-rejected.jsonl";
88521
89006
  var REJECTION_TTL_MS2 = 90 * 24 * 60 * 60 * 1000;
88522
89007
  var PROPOSAL_SIM_THRESHOLD = 0.5;
88523
89008
  function proposalsPath2(stateDir) {
88524
- return join44(stateDir, PROPOSALS_FILE2);
89009
+ return join45(stateDir, PROPOSALS_FILE2);
88525
89010
  }
88526
89011
  function rejectedPath2(stateDir) {
88527
- return join44(stateDir, REJECTED_FILE2);
89012
+ return join45(stateDir, REJECTED_FILE2);
88528
89013
  }
88529
89014
  function ensureDir3(stateDir) {
88530
- if (!existsSync39(stateDir)) {
88531
- mkdirSync35(stateDir, { recursive: true, mode: 493 });
89015
+ if (!existsSync40(stateDir)) {
89016
+ mkdirSync36(stateDir, { recursive: true, mode: 493 });
88532
89017
  }
88533
89018
  }
88534
89019
  function appendLine2(path2, obj) {
@@ -88541,11 +89026,11 @@ function appendLine2(path2, obj) {
88541
89026
  }
88542
89027
  }
88543
89028
  function readLines2(path2, isValid2) {
88544
- if (!existsSync39(path2))
89029
+ if (!existsSync40(path2))
88545
89030
  return [];
88546
89031
  let raw;
88547
89032
  try {
88548
- raw = readFileSync36(path2, "utf-8");
89033
+ raw = readFileSync37(path2, "utf-8");
88549
89034
  } catch {
88550
89035
  return [];
88551
89036
  }
@@ -89142,11 +89627,11 @@ function escapeBody2(s) {
89142
89627
  }
89143
89628
 
89144
89629
  // gateway/pid-file.ts
89145
- import { writeFileSync as writeFileSync32, readFileSync as readFileSync37, unlinkSync as unlinkSync19, renameSync as renameSync14 } from "node:fs";
89630
+ import { writeFileSync as writeFileSync33, readFileSync as readFileSync38, unlinkSync as unlinkSync19, renameSync as renameSync15 } from "node:fs";
89146
89631
  function writePidFile(path2, record) {
89147
89632
  const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
89148
- writeFileSync32(tmp, JSON.stringify(record), "utf-8");
89149
- renameSync14(tmp, path2);
89633
+ writeFileSync33(tmp, JSON.stringify(record), "utf-8");
89634
+ renameSync15(tmp, path2);
89150
89635
  }
89151
89636
  function clearPidFile(path2) {
89152
89637
  try {
@@ -89161,10 +89646,10 @@ import {
89161
89646
  writeFile as writeFileAsync,
89162
89647
  readFile as readFileAsync
89163
89648
  } from "node:fs/promises";
89164
- import { readFileSync as readFileSync38 } from "node:fs";
89649
+ import { readFileSync as readFileSync39 } from "node:fs";
89165
89650
  function readCurrentBootId() {
89166
89651
  try {
89167
- const stat = readFileSync38("/proc/1/stat", "utf-8");
89652
+ const stat = readFileSync39("/proc/1/stat", "utf-8");
89168
89653
  const lastParen = stat.lastIndexOf(")");
89169
89654
  if (lastParen < 0)
89170
89655
  return null;
@@ -89367,15 +89852,15 @@ function safeCount(fn) {
89367
89852
  }
89368
89853
 
89369
89854
  // gateway/session-marker.ts
89370
- import { writeFileSync as writeFileSync33, readFileSync as readFileSync39, renameSync as renameSync15, unlinkSync as unlinkSync20 } from "node:fs";
89855
+ import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync16, unlinkSync as unlinkSync20 } from "node:fs";
89371
89856
  function writeSessionMarker(path2, marker) {
89372
89857
  const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
89373
- writeFileSync33(tmp, JSON.stringify(marker), "utf-8");
89374
- renameSync15(tmp, path2);
89858
+ writeFileSync34(tmp, JSON.stringify(marker), "utf-8");
89859
+ renameSync16(tmp, path2);
89375
89860
  }
89376
89861
  function readSessionMarker(path2) {
89377
89862
  try {
89378
- const raw = readFileSync39(path2, "utf-8");
89863
+ const raw = readFileSync40(path2, "utf-8");
89379
89864
  const parsed = JSON.parse(raw);
89380
89865
  if (typeof parsed.pid === "number" && typeof parsed.startedAtMs === "number" && Number.isFinite(parsed.pid) && Number.isFinite(parsed.startedAtMs)) {
89381
89866
  return { pid: parsed.pid, startedAtMs: parsed.startedAtMs };
@@ -89397,16 +89882,16 @@ function shouldFireRestartBanner(input) {
89397
89882
  }
89398
89883
 
89399
89884
  // gateway/clean-shutdown-marker.ts
89400
- import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync16, unlinkSync as unlinkSync21 } from "node:fs";
89885
+ import { writeFileSync as writeFileSync35, readFileSync as readFileSync41, renameSync as renameSync17, unlinkSync as unlinkSync21 } from "node:fs";
89401
89886
  var DEFAULT_MAX_AGE_MS = 60000;
89402
89887
  function writeCleanShutdownMarker(path2, marker) {
89403
89888
  const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
89404
- writeFileSync34(tmp, JSON.stringify(marker), "utf-8");
89405
- renameSync16(tmp, path2);
89889
+ writeFileSync35(tmp, JSON.stringify(marker), "utf-8");
89890
+ renameSync17(tmp, path2);
89406
89891
  }
89407
89892
  function readCleanShutdownMarker(path2) {
89408
89893
  try {
89409
- const raw = readFileSync40(path2, "utf-8");
89894
+ const raw = readFileSync41(path2, "utf-8");
89410
89895
  const parsed = JSON.parse(raw);
89411
89896
  if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.signal === "string" && parsed.signal.length > 0) {
89412
89897
  const out = { ts: parsed.ts, signal: parsed.signal };
@@ -89778,16 +90263,16 @@ function classifyAdminGate(text4, myAgentName) {
89778
90263
 
89779
90264
  // subagent-watcher.ts
89780
90265
  import {
89781
- existsSync as existsSync40,
90266
+ existsSync as existsSync41,
89782
90267
  openSync as openSync8,
89783
90268
  readSync as readSync2,
89784
90269
  statSync as statSync13,
89785
90270
  closeSync as closeSync8,
89786
90271
  watch,
89787
90272
  readdirSync as readdirSync8,
89788
- readFileSync as readFileSync41
90273
+ readFileSync as readFileSync42
89789
90274
  } from "fs";
89790
- import { join as join45 } from "path";
90275
+ import { join as join46 } from "path";
89791
90276
 
89792
90277
  // session-tail.ts
89793
90278
  function sanitizeCwdToProjectName2(cwd) {
@@ -90137,7 +90622,7 @@ function backfillJsonlAgentId(db3, jsonlPath, agentId, log) {
90137
90622
  const metaPath = jsonlPath.replace(/\.jsonl$/, ".meta.json");
90138
90623
  let meta;
90139
90624
  try {
90140
- const raw = readFileSync41(metaPath, "utf8");
90625
+ const raw = readFileSync42(metaPath, "utf8");
90141
90626
  meta = JSON.parse(raw);
90142
90627
  } catch {
90143
90628
  log?.(`subagent-watcher: backfill skip ${agentId} \u2014 meta.json not readable at ${metaPath}`);
@@ -90592,7 +91077,7 @@ function startSubagentWatcher(config) {
90592
91077
  clearTimeout(ref.ref);
90593
91078
  });
90594
91079
  const fs2 = config.fs ?? {
90595
- existsSync: existsSync40,
91080
+ existsSync: existsSync41,
90596
91081
  readdirSync: readdirSync8,
90597
91082
  statSync: statSync13,
90598
91083
  openSync: openSync8,
@@ -91110,8 +91595,8 @@ function startSubagentWatcher(config) {
91110
91595
  if (stopped)
91111
91596
  return;
91112
91597
  pruneVanishedDirWatchers();
91113
- const claudeHome = join45(agentDir, ".claude");
91114
- const projectsRoot = join45(claudeHome, "projects");
91598
+ const claudeHome = join46(agentDir, ".claude");
91599
+ const projectsRoot = join46(claudeHome, "projects");
91115
91600
  if (!fs2.existsSync(projectsRoot))
91116
91601
  return;
91117
91602
  let projectDirs;
@@ -91145,7 +91630,7 @@ function startSubagentWatcher(config) {
91145
91630
  continue;
91146
91631
  }
91147
91632
  warnedForeignSlugs.delete(pDir);
91148
- const projectPath = join45(projectsRoot, pDir);
91633
+ const projectPath = join46(projectsRoot, pDir);
91149
91634
  let sessionDirs;
91150
91635
  try {
91151
91636
  sessionDirs = fs2.readdirSync(projectPath);
@@ -91155,7 +91640,7 @@ function startSubagentWatcher(config) {
91155
91640
  for (const sDir of sessionDirs) {
91156
91641
  if (sDir.endsWith(".jsonl"))
91157
91642
  continue;
91158
- const subagentsPath = join45(projectPath, sDir, "subagents");
91643
+ const subagentsPath = join46(projectPath, sDir, "subagents");
91159
91644
  if (!fs2.existsSync(subagentsPath))
91160
91645
  continue;
91161
91646
  const watchAndScan = (dirPath) => {
@@ -91164,7 +91649,7 @@ function startSubagentWatcher(config) {
91164
91649
  const w = fs2.watch(dirPath, (_event, filename) => {
91165
91650
  if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
91166
91651
  return;
91167
- const filePath = join45(dirPath, filename.toString());
91652
+ const filePath = join46(dirPath, filename.toString());
91168
91653
  if (!knownFiles.has(filePath)) {
91169
91654
  scanSubagentsDir(dirPath);
91170
91655
  }
@@ -91178,7 +91663,7 @@ function startSubagentWatcher(config) {
91178
91663
  scanSubagentsDir(dirPath);
91179
91664
  };
91180
91665
  watchAndScan(subagentsPath);
91181
- const workflowsPath = join45(subagentsPath, "workflows");
91666
+ const workflowsPath = join46(subagentsPath, "workflows");
91182
91667
  if (fs2.existsSync(workflowsPath)) {
91183
91668
  let wfDirs;
91184
91669
  try {
@@ -91188,7 +91673,7 @@ function startSubagentWatcher(config) {
91188
91673
  }
91189
91674
  for (const wfDir of wfDirs) {
91190
91675
  try {
91191
- const wfPath = join45(workflowsPath, wfDir);
91676
+ const wfPath = join46(workflowsPath, wfDir);
91192
91677
  if (!fs2.statSync(wfPath).isDirectory())
91193
91678
  continue;
91194
91679
  watchAndScan(wfPath);
@@ -91208,7 +91693,7 @@ function startSubagentWatcher(config) {
91208
91693
  for (const e of entries) {
91209
91694
  if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
91210
91695
  continue;
91211
- const filePath = join45(subagentsPath, e);
91696
+ const filePath = join46(subagentsPath, e);
91212
91697
  if (knownFiles.has(filePath))
91213
91698
  continue;
91214
91699
  const agentId = e.slice("agent-".length, -".jsonl".length);
@@ -91336,37 +91821,37 @@ function startSubagentWatcher(config) {
91336
91821
 
91337
91822
  // ../src/worktree/registry.ts
91338
91823
  import {
91339
- mkdirSync as mkdirSync36,
91340
- writeFileSync as writeFileSync35,
91341
- readFileSync as readFileSync42,
91824
+ mkdirSync as mkdirSync37,
91825
+ writeFileSync as writeFileSync36,
91826
+ readFileSync as readFileSync43,
91342
91827
  readdirSync as readdirSync9,
91343
91828
  unlinkSync as unlinkSync22,
91344
- existsSync as existsSync41,
91345
- renameSync as renameSync17
91829
+ existsSync as existsSync42,
91830
+ renameSync as renameSync18
91346
91831
  } from "node:fs";
91347
- import { join as join46, resolve as resolve10 } from "node:path";
91832
+ import { join as join47, resolve as resolve10 } from "node:path";
91348
91833
  import { homedir as homedir16 } from "node:os";
91349
91834
  function registryDir() {
91350
- return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join46(homedir16(), ".switchroom", "worktrees"));
91835
+ return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join47(homedir16(), ".switchroom", "worktrees"));
91351
91836
  }
91352
91837
  function recordPath(id) {
91353
- return join46(registryDir(), `${id}.json`);
91838
+ return join47(registryDir(), `${id}.json`);
91354
91839
  }
91355
91840
  function ensureDir4() {
91356
- mkdirSync36(registryDir(), { recursive: true });
91841
+ mkdirSync37(registryDir(), { recursive: true });
91357
91842
  }
91358
91843
  function writeRecord(record) {
91359
91844
  ensureDir4();
91360
91845
  const target = recordPath(record.id);
91361
91846
  const tmp = `${target}.tmp${process.pid}`;
91362
- writeFileSync35(tmp, JSON.stringify(record, null, 2) + `
91847
+ writeFileSync36(tmp, JSON.stringify(record, null, 2) + `
91363
91848
  `, { mode: 384 });
91364
- renameSync17(tmp, target);
91849
+ renameSync18(tmp, target);
91365
91850
  }
91366
91851
  function readRecord(id) {
91367
91852
  const path2 = recordPath(id);
91368
91853
  try {
91369
- const raw = readFileSync42(path2, "utf8");
91854
+ const raw = readFileSync43(path2, "utf8");
91370
91855
  return JSON.parse(raw);
91371
91856
  } catch {
91372
91857
  return null;
@@ -91396,7 +91881,7 @@ function touchHeartbeat(id, onAfterRead) {
91396
91881
  writeRecord({ ...rec, heartbeatAt: new Date().toISOString() });
91397
91882
  }
91398
91883
  function recordExists(id) {
91399
- return existsSync41(recordPath(id));
91884
+ return existsSync42(recordPath(id));
91400
91885
  }
91401
91886
 
91402
91887
  // worktree-watch-cwds.ts
@@ -91528,15 +92013,15 @@ function determineRestartReason(opts) {
91528
92013
  init_boot_card();
91529
92014
 
91530
92015
  // gateway/update-announce.ts
91531
- import { existsSync as existsSync46, mkdirSync as mkdirSync40, openSync as openSync9, closeSync as closeSync9, readFileSync as readFileSync49 } from "node:fs";
91532
- import { join as join51 } from "node:path";
92016
+ import { existsSync as existsSync47, mkdirSync as mkdirSync41, openSync as openSync9, closeSync as closeSync9, readFileSync as readFileSync50 } from "node:fs";
92017
+ import { join as join52 } from "node:path";
91533
92018
  import { homedir as homedir18 } from "node:os";
91534
92019
 
91535
92020
  // ../src/host-control/audit-reader.ts
91536
92021
  import { homedir as homedir17 } from "node:os";
91537
- import { join as join50 } from "node:path";
92022
+ import { join as join51 } from "node:path";
91538
92023
  function defaultAuditLogPath(home2 = homedir17()) {
91539
- return join50(home2, ".switchroom", "host-control-audit.log");
92024
+ return join51(home2, ".switchroom", "host-control-audit.log");
91540
92025
  }
91541
92026
  function parseAuditLine(line) {
91542
92027
  const trimmed = line.trim();
@@ -91659,8 +92144,8 @@ function readAndFilter(raw, filters, limit) {
91659
92144
  var DEFAULT_LOOKBACK_MS = 10 * 60 * 1000;
91660
92145
  function readLastTerminalUpdateAudit(opts = {}) {
91661
92146
  const path2 = opts.auditLogPath ?? defaultAuditLogPath();
91662
- const exists = opts.exists ?? existsSync46;
91663
- const readFile = opts.readFile ?? ((p) => readFileSync49(p, "utf-8"));
92147
+ const exists = opts.exists ?? existsSync47;
92148
+ const readFile = opts.readFile ?? ((p) => readFileSync50(p, "utf-8"));
91664
92149
  if (!exists(path2))
91665
92150
  return null;
91666
92151
  let raw;
@@ -91721,15 +92206,15 @@ function renderUpdateOutcomeLine(entry) {
91721
92206
  `);
91722
92207
  }
91723
92208
  function claimUpdateAnnouncement(requestId, opts = {}) {
91724
- const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join51(homedir18(), ".switchroom");
91725
- const dir = join51(stateDir, "update-announced");
92209
+ const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join52(homedir18(), ".switchroom");
92210
+ const dir = join52(stateDir, "update-announced");
91726
92211
  try {
91727
- mkdirSync40(dir, { recursive: true });
92212
+ mkdirSync41(dir, { recursive: true });
91728
92213
  } catch {
91729
92214
  return false;
91730
92215
  }
91731
92216
  const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
91732
- const path2 = join51(dir, safeId);
92217
+ const path2 = join52(dir, safeId);
91733
92218
  try {
91734
92219
  const fd = openSync9(path2, "wx");
91735
92220
  closeSync9(fd);
@@ -91749,7 +92234,7 @@ function maybeRenderUpdateAnnouncement(opts = {}) {
91749
92234
 
91750
92235
  // issues-card.ts
91751
92236
  init_card_format();
91752
- import { readFileSync as readFileSync50, writeFileSync as writeFileSync40 } from "node:fs";
92237
+ import { readFileSync as readFileSync51, writeFileSync as writeFileSync41 } from "node:fs";
91753
92238
  var SEVERITY_EMOJI = {
91754
92239
  info: "\u2139\ufe0f",
91755
92240
  warn: "\u26a0\ufe0f",
@@ -91841,7 +92326,7 @@ function extractRetryAfterSecs2(err) {
91841
92326
  var COOLDOWN_JITTER_MS2 = 500;
91842
92327
  function readPersistedMessageId(path2, log) {
91843
92328
  try {
91844
- const raw = readFileSync50(path2, "utf8");
92329
+ const raw = readFileSync51(path2, "utf8");
91845
92330
  const parsed = JSON.parse(raw);
91846
92331
  const v = parsed.messageId;
91847
92332
  if (typeof v === "number" && Number.isInteger(v) && v > 0)
@@ -91857,7 +92342,7 @@ function readPersistedMessageId(path2, log) {
91857
92342
  }
91858
92343
  function writePersistedMessageId(path2, messageId, log) {
91859
92344
  try {
91860
- writeFileSync40(path2, JSON.stringify({ messageId }) + `
92345
+ writeFileSync41(path2, JSON.stringify({ messageId }) + `
91861
92346
  `, { mode: 384 });
91862
92347
  } catch (err) {
91863
92348
  log(`issues-card: persist write failed (${err.message})`);
@@ -91950,24 +92435,24 @@ function createIssuesCardHandle(opts) {
91950
92435
  }
91951
92436
 
91952
92437
  // issues-watcher.ts
91953
- import { existsSync as existsSync48, statSync as statSync16 } from "node:fs";
91954
- import { join as join53 } from "node:path";
92438
+ import { existsSync as existsSync49, statSync as statSync16 } from "node:fs";
92439
+ import { join as join54 } from "node:path";
91955
92440
 
91956
92441
  // ../src/issues/store.ts
91957
92442
  import {
91958
92443
  closeSync as closeSync10,
91959
- existsSync as existsSync47,
91960
- mkdirSync as mkdirSync41,
92444
+ existsSync as existsSync48,
92445
+ mkdirSync as mkdirSync42,
91961
92446
  openSync as openSync10,
91962
92447
  readdirSync as readdirSync11,
91963
- readFileSync as readFileSync51,
91964
- renameSync as renameSync20,
92448
+ readFileSync as readFileSync52,
92449
+ renameSync as renameSync21,
91965
92450
  statSync as statSync15,
91966
92451
  unlinkSync as unlinkSync23,
91967
- writeFileSync as writeFileSync41,
92452
+ writeFileSync as writeFileSync42,
91968
92453
  writeSync as writeSync6
91969
92454
  } from "node:fs";
91970
- import { join as join52 } from "node:path";
92455
+ import { join as join53 } from "node:path";
91971
92456
  import { randomBytes as randomBytes8 } from "node:crypto";
91972
92457
  import { execSync } from "node:child_process";
91973
92458
 
@@ -91986,12 +92471,12 @@ init_redact();
91986
92471
  var ISSUES_FILE = "issues.jsonl";
91987
92472
  var ISSUES_LOCK = "issues.lock";
91988
92473
  function readAll(stateDir) {
91989
- const path2 = join52(stateDir, ISSUES_FILE);
91990
- if (!existsSync47(path2))
92474
+ const path2 = join53(stateDir, ISSUES_FILE);
92475
+ if (!existsSync48(path2))
91991
92476
  return [];
91992
92477
  let raw;
91993
92478
  try {
91994
- raw = readFileSync51(path2, "utf-8");
92479
+ raw = readFileSync52(path2, "utf-8");
91995
92480
  } catch {
91996
92481
  return [];
91997
92482
  }
@@ -92023,7 +92508,7 @@ function list2(stateDir, opts = {}) {
92023
92508
  });
92024
92509
  }
92025
92510
  function resolve11(stateDir, fingerprint, nowFn = Date.now) {
92026
- if (!existsSync47(join52(stateDir, ISSUES_FILE)))
92511
+ if (!existsSync48(join53(stateDir, ISSUES_FILE)))
92027
92512
  return 0;
92028
92513
  return withLock(stateDir, () => {
92029
92514
  const all2 = readAll(stateDir);
@@ -92041,14 +92526,14 @@ function resolve11(stateDir, fingerprint, nowFn = Date.now) {
92041
92526
  });
92042
92527
  }
92043
92528
  function writeAll(stateDir, events) {
92044
- const path2 = join52(stateDir, ISSUES_FILE);
92529
+ const path2 = join53(stateDir, ISSUES_FILE);
92045
92530
  sweepOrphanTmpFiles(stateDir);
92046
92531
  const tmp = `${path2}.tmp-${process.pid}-${randomBytes8(4).toString("hex")}`;
92047
92532
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
92048
92533
  `) + `
92049
92534
  `;
92050
- writeFileSync41(tmp, body, "utf-8");
92051
- renameSync20(tmp, path2);
92535
+ writeFileSync42(tmp, body, "utf-8");
92536
+ renameSync21(tmp, path2);
92052
92537
  }
92053
92538
  var ORPHAN_TMP_TTL_MS = 60000;
92054
92539
  var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
@@ -92063,7 +92548,7 @@ function sweepOrphanTmpFiles(stateDir) {
92063
92548
  for (const entry of entries) {
92064
92549
  if (!entry.startsWith(TMP_PREFIX))
92065
92550
  continue;
92066
- const tmpPath2 = join52(stateDir, entry);
92551
+ const tmpPath2 = join53(stateDir, entry);
92067
92552
  try {
92068
92553
  const stat = statSync15(tmpPath2);
92069
92554
  if (stat.mtimeMs < cutoff) {
@@ -92075,7 +92560,7 @@ function sweepOrphanTmpFiles(stateDir) {
92075
92560
  var LOCK_RETRY_MS = 25;
92076
92561
  var LOCK_TIMEOUT_MS = 1e4;
92077
92562
  function withLock(stateDir, fn) {
92078
- const lockPath = join52(stateDir, ISSUES_LOCK);
92563
+ const lockPath = join53(stateDir, ISSUES_LOCK);
92079
92564
  const startedAt = Date.now();
92080
92565
  let fd = null;
92081
92566
  while (fd === null) {
@@ -92110,7 +92595,7 @@ function withLock(stateDir, fn) {
92110
92595
  function tryStealStaleLock(lockPath) {
92111
92596
  let pidStr;
92112
92597
  try {
92113
- pidStr = readFileSync51(lockPath, "utf-8").trim();
92598
+ pidStr = readFileSync52(lockPath, "utf-8").trim();
92114
92599
  } catch {
92115
92600
  return true;
92116
92601
  }
@@ -92160,7 +92645,7 @@ function isIssueEvent(v) {
92160
92645
  // issues-watcher.ts
92161
92646
  var DEFAULT_POLL_INTERVAL_MS2 = 2000;
92162
92647
  function startIssuesWatcher(opts) {
92163
- const path2 = join53(opts.stateDir, ISSUES_FILE);
92648
+ const path2 = join54(opts.stateDir, ISSUES_FILE);
92164
92649
  const log = opts.log ?? (() => {});
92165
92650
  const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
92166
92651
  const setIntervalFn = opts.setInterval ?? setInterval;
@@ -92208,7 +92693,7 @@ function startIssuesWatcher(opts) {
92208
92693
  };
92209
92694
  }
92210
92695
  function defaultSignatureProvider(path2) {
92211
- if (!existsSync48(path2))
92696
+ if (!existsSync49(path2))
92212
92697
  return null;
92213
92698
  try {
92214
92699
  const stat = statSync16(path2);
@@ -92919,8 +93404,8 @@ function readBashCommand(inputPreview) {
92919
93404
  }
92920
93405
 
92921
93406
  // gateway/scoped-grant-store.ts
92922
- import { readFileSync as readFileSync52, writeFileSync as writeFileSync42 } from "node:fs";
92923
- import { join as join54 } from "node:path";
93407
+ import { readFileSync as readFileSync53, writeFileSync as writeFileSync43 } from "node:fs";
93408
+ import { join as join55 } from "node:path";
92924
93409
 
92925
93410
  // scoped-approval.ts
92926
93411
  var SCOPED_APPROVAL_DEFAULT_TTL_MS2 = 30 * 60 * 1000;
@@ -92962,11 +93447,11 @@ function scopedGrantPersistEnabled(env = process.env) {
92962
93447
  return env.SWITCHROOM_SCOPED_GRANT_PERSIST !== "0";
92963
93448
  }
92964
93449
  function createScopedGrantStore(stateDir, env = process.env) {
92965
- const filePath = join54(stateDir, "scoped-grants.json");
93450
+ const filePath = join55(stateDir, "scoped-grants.json");
92966
93451
  const enabled7 = scopedGrantPersistEnabled(env);
92967
93452
  function read() {
92968
93453
  try {
92969
- const raw = readFileSync52(filePath, "utf-8");
93454
+ const raw = readFileSync53(filePath, "utf-8");
92970
93455
  const parsed = JSON.parse(raw);
92971
93456
  return Array.isArray(parsed) ? parsed : [];
92972
93457
  } catch {
@@ -92984,7 +93469,7 @@ function createScopedGrantStore(stateDir, env = process.env) {
92984
93469
  if (!enabled7)
92985
93470
  return;
92986
93471
  try {
92987
- writeFileSync42(filePath, JSON.stringify(serializeScopedGrants(store2)), {
93472
+ writeFileSync43(filePath, JSON.stringify(serializeScopedGrants(store2)), {
92988
93473
  encoding: "utf-8",
92989
93474
  mode: 384
92990
93475
  });
@@ -93335,8 +93820,8 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
93335
93820
 
93336
93821
  // credits-watch.ts
93337
93822
  init_card_format();
93338
- import { readFileSync as readFileSync53, writeFileSync as writeFileSync43, existsSync as existsSync49, mkdirSync as mkdirSync42 } from "fs";
93339
- import { join as join55 } from "path";
93823
+ import { readFileSync as readFileSync54, writeFileSync as writeFileSync44, existsSync as existsSync50, mkdirSync as mkdirSync43 } from "fs";
93824
+ import { join as join56 } from "path";
93340
93825
  var STATE_FILE = "credits-watch.json";
93341
93826
  var DEFAULT_CREDIT_FATAL_REASONS = new Set;
93342
93827
  var KNOWN_CREDIT_REASONS = [
@@ -93358,12 +93843,12 @@ function emptyCreditState() {
93358
93843
  return { lastNotifiedReason: null, lastNotifiedAt: 0 };
93359
93844
  }
93360
93845
  function readClaudeJsonOverage(claudeConfigDir) {
93361
- const path2 = join55(claudeConfigDir, ".claude.json");
93362
- if (!existsSync49(path2))
93846
+ const path2 = join56(claudeConfigDir, ".claude.json");
93847
+ if (!existsSync50(path2))
93363
93848
  return null;
93364
93849
  let raw;
93365
93850
  try {
93366
- raw = readFileSync53(path2, "utf-8");
93851
+ raw = readFileSync54(path2, "utf-8");
93367
93852
  } catch {
93368
93853
  return null;
93369
93854
  }
@@ -93441,11 +93926,11 @@ function humanizeReason(reason) {
93441
93926
  }
93442
93927
  }
93443
93928
  function loadCreditState(stateDir) {
93444
- const path2 = join55(stateDir, STATE_FILE);
93445
- if (!existsSync49(path2))
93929
+ const path2 = join56(stateDir, STATE_FILE);
93930
+ if (!existsSync50(path2))
93446
93931
  return emptyCreditState();
93447
93932
  try {
93448
- const raw = readFileSync53(path2, "utf-8");
93933
+ const raw = readFileSync54(path2, "utf-8");
93449
93934
  const parsed = JSON.parse(raw);
93450
93935
  if (parsed && typeof parsed === "object" && (parsed.lastNotifiedReason === null || typeof parsed.lastNotifiedReason === "string") && typeof parsed.lastNotifiedAt === "number" && Number.isFinite(parsed.lastNotifiedAt)) {
93451
93936
  return {
@@ -93457,17 +93942,17 @@ function loadCreditState(stateDir) {
93457
93942
  return emptyCreditState();
93458
93943
  }
93459
93944
  function saveCreditState(stateDir, state7) {
93460
- mkdirSync42(stateDir, { recursive: true });
93461
- const path2 = join55(stateDir, STATE_FILE);
93462
- writeFileSync43(path2, JSON.stringify(state7, null, 2) + `
93945
+ mkdirSync43(stateDir, { recursive: true });
93946
+ const path2 = join56(stateDir, STATE_FILE);
93947
+ writeFileSync44(path2, JSON.stringify(state7, null, 2) + `
93463
93948
  `, { mode: 384 });
93464
93949
  }
93465
93950
 
93466
93951
  // quota-watch.ts
93467
93952
  init_auth_snapshot_format();
93468
93953
  init_card_format();
93469
- import { readFileSync as readFileSync54, writeFileSync as writeFileSync44, existsSync as existsSync50, mkdirSync as mkdirSync43 } from "fs";
93470
- import { join as join56 } from "path";
93954
+ import { readFileSync as readFileSync55, writeFileSync as writeFileSync45, existsSync as existsSync51, mkdirSync as mkdirSync44 } from "fs";
93955
+ import { join as join57 } from "path";
93471
93956
  var STATE_FILE2 = "quota-watch.json";
93472
93957
  function emptyQuotaWatchState() {
93473
93958
  return {};
@@ -93705,11 +94190,11 @@ function buildRecoveryMessage(agentName3, snap) {
93705
94190
  `);
93706
94191
  }
93707
94192
  function loadQuotaWatchState(stateDir) {
93708
- const path2 = join56(stateDir, STATE_FILE2);
93709
- if (!existsSync50(path2))
94193
+ const path2 = join57(stateDir, STATE_FILE2);
94194
+ if (!existsSync51(path2))
93710
94195
  return emptyQuotaWatchState();
93711
94196
  try {
93712
- const raw = readFileSync54(path2, "utf-8");
94197
+ const raw = readFileSync55(path2, "utf-8");
93713
94198
  const parsed = JSON.parse(raw);
93714
94199
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
93715
94200
  return emptyQuotaWatchState();
@@ -93726,9 +94211,9 @@ function loadQuotaWatchState(stateDir) {
93726
94211
  }
93727
94212
  }
93728
94213
  function saveQuotaWatchState(stateDir, state7) {
93729
- mkdirSync43(stateDir, { recursive: true });
93730
- const path2 = join56(stateDir, STATE_FILE2);
93731
- writeFileSync44(path2, JSON.stringify(state7, null, 2) + `
94214
+ mkdirSync44(stateDir, { recursive: true });
94215
+ const path2 = join57(stateDir, STATE_FILE2);
94216
+ writeFileSync45(path2, JSON.stringify(state7, null, 2) + `
93732
94217
  `, { mode: 384 });
93733
94218
  }
93734
94219
  function patchQuotaWatchState(current, accountLabel, accountState) {
@@ -93776,27 +94261,27 @@ init_auth_snapshot_format2();
93776
94261
  // gateway/turn-active-marker.ts
93777
94262
  import {
93778
94263
  closeSync as closeSync11,
93779
- existsSync as existsSync51,
93780
- mkdirSync as mkdirSync44,
94264
+ existsSync as existsSync52,
94265
+ mkdirSync as mkdirSync45,
93781
94266
  openSync as openSync11,
93782
- readFileSync as readFileSync55,
94267
+ readFileSync as readFileSync56,
93783
94268
  statSync as statSync17,
93784
94269
  unlinkSync as unlinkSync24,
93785
94270
  utimesSync as utimesSync2,
93786
- writeFileSync as writeFileSync45
94271
+ writeFileSync as writeFileSync46
93787
94272
  } from "node:fs";
93788
- import { join as join57 } from "node:path";
94273
+ import { join as join58 } from "node:path";
93789
94274
  var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
93790
94275
  var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
93791
94276
  var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
93792
94277
  function removeTurnActiveMarker2(stateDir) {
93793
94278
  try {
93794
- unlinkSync24(join57(stateDir, TURN_ACTIVE_MARKER_FILE2));
94279
+ unlinkSync24(join58(stateDir, TURN_ACTIVE_MARKER_FILE2));
93795
94280
  } catch {}
93796
94281
  }
93797
94282
  function sweepStaleTurnActiveMarker(stateDir, opts) {
93798
- const path2 = join57(stateDir, TURN_ACTIVE_MARKER_FILE2);
93799
- if (!existsSync51(path2))
94283
+ const path2 = join58(stateDir, TURN_ACTIVE_MARKER_FILE2);
94284
+ if (!existsSync52(path2))
93800
94285
  return false;
93801
94286
  const now = opts.now ?? Date.now();
93802
94287
  try {
@@ -93808,7 +94293,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
93808
94293
  return false;
93809
94294
  let payload = null;
93810
94295
  try {
93811
- payload = readFileSync55(path2, "utf8");
94296
+ payload = readFileSync56(path2, "utf8");
93812
94297
  } catch {}
93813
94298
  unlinkSync24(path2);
93814
94299
  if (opts.onRemove) {
@@ -93826,7 +94311,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
93826
94311
  }
93827
94312
  }
93828
94313
  function readTurnActiveMarkerAgeMs2(stateDir, now) {
93829
- const path2 = join57(stateDir, TURN_ACTIVE_MARKER_FILE2);
94314
+ const path2 = join58(stateDir, TURN_ACTIVE_MARKER_FILE2);
93830
94315
  try {
93831
94316
  const st = statSync17(path2);
93832
94317
  return (now ?? Date.now()) - st.mtimeMs;
@@ -93839,19 +94324,19 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
93839
94324
  }
93840
94325
 
93841
94326
  // gateway/gateway-heartbeat.ts
93842
- import { mkdirSync as mkdirSync45, utimesSync as utimesSync3, writeFileSync as writeFileSync46 } from "node:fs";
93843
- import { join as join58 } from "node:path";
94327
+ import { mkdirSync as mkdirSync46, utimesSync as utimesSync3, writeFileSync as writeFileSync47 } from "node:fs";
94328
+ import { join as join59 } from "node:path";
93844
94329
  var GATEWAY_HEARTBEAT_FILE = "gateway-heartbeat";
93845
94330
  var GATEWAY_HEARTBEAT_INTERVAL_MS = 15000;
93846
94331
  function touchGatewayHeartbeat(stateDir) {
93847
- const path2 = join58(stateDir, GATEWAY_HEARTBEAT_FILE);
94332
+ const path2 = join59(stateDir, GATEWAY_HEARTBEAT_FILE);
93848
94333
  const now = new Date;
93849
94334
  try {
93850
94335
  utimesSync3(path2, now, now);
93851
94336
  } catch {
93852
94337
  try {
93853
- mkdirSync45(stateDir, { recursive: true });
93854
- writeFileSync46(path2, `${Date.now()}
94338
+ mkdirSync46(stateDir, { recursive: true });
94339
+ writeFileSync47(path2, `${Date.now()}
93855
94340
  `, { mode: 384 });
93856
94341
  } catch {}
93857
94342
  }
@@ -93894,11 +94379,23 @@ async function sweepOutbox(deps) {
93894
94379
  textAlreadyDelivered: resolved != null && deps.textAlreadyDelivered(resolved.chatId, resolved.threadId, record2.text),
93895
94380
  routable: resolved != null,
93896
94381
  routePrefix,
93897
- quietMs: deps.quietMs ?? OUTBOX_QUIET_MS
94382
+ quietMs: deps.quietMs ?? OUTBOX_QUIET_MS,
94383
+ shownLedgerHit: isShownBlock(record2.turnNonce, record2.text, deps.stateDir)
93898
94384
  });
93899
94385
  if (decision.action !== "send" && decision.action !== "send-delayed") {
93900
94386
  summary.skipped++;
93901
- if (decision.action === "skip-journaled") {
94387
+ if (decision.action === "skip-ephemeral-shown") {
94388
+ appendDelivered({
94389
+ turnNonce: record2.turnNonce,
94390
+ textSha256: record2.textSha256,
94391
+ ts: now,
94392
+ deliverySource: "sweep",
94393
+ replyAlreadyDeliveredThisTurn: record2.replyAlreadyDeliveredThisTurn === true
94394
+ }, deps.stateDir);
94395
+ clearOutboxRecord(record2.turnNonce, deps.stateDir);
94396
+ log(`outbox-sweep: suppressed ephemeral-shown nonce=${record2.turnNonce}
94397
+ `);
94398
+ } else if (decision.action === "skip-journaled") {
93902
94399
  clearOutboxRecord(record2.turnNonce, deps.stateDir);
93903
94400
  } else if (decision.action === "skip-dedup") {
93904
94401
  appendDelivered({
@@ -93986,10 +94483,10 @@ function startOutboxSweep(deps) {
93986
94483
  }
93987
94484
 
93988
94485
  // ../src/build-info.ts
93989
- var VERSION = "0.19.14";
93990
- var COMMIT_SHA = "1f1f69f8";
93991
- var COMMIT_DATE = "2026-07-24T07:19:40+10:00";
93992
- var LATEST_PR = 3514;
94486
+ var VERSION = "0.19.15";
94487
+ var COMMIT_SHA = "20691874";
94488
+ var COMMIT_DATE = "2026-07-24T12:46:35+10:00";
94489
+ var LATEST_PR = 3518;
93993
94490
  var COMMITS_AHEAD_OF_TAG = 0;
93994
94491
 
93995
94492
  // gateway/boot-version.ts
@@ -94067,11 +94564,11 @@ init_peercred();
94067
94564
  import * as net5 from "node:net";
94068
94565
  import * as fs2 from "node:fs";
94069
94566
  import { homedir as homedir19 } from "node:os";
94070
- import { join as join59 } from "node:path";
94567
+ import { join as join60 } from "node:path";
94071
94568
  var DEFAULT_TIMEOUT_MS4 = 2000;
94072
94569
  var UNLOCK_TIMEOUT_MS = 30000;
94073
- var LEGACY_SOCKET_PATH2 = join59(homedir19(), ".switchroom", "vault-broker.sock");
94074
- var OPERATOR_SOCKET_PATH2 = join59(homedir19(), ".switchroom", "broker-operator", "sock");
94570
+ var LEGACY_SOCKET_PATH2 = join60(homedir19(), ".switchroom", "vault-broker.sock");
94571
+ var OPERATOR_SOCKET_PATH2 = join60(homedir19(), ".switchroom", "broker-operator", "sock");
94075
94572
  function defaultBrokerSocketPath2() {
94076
94573
  if (fs2.existsSync(OPERATOR_SOCKET_PATH2))
94077
94574
  return OPERATOR_SOCKET_PATH2;
@@ -94953,8 +95450,8 @@ function resolveVaultApprovalPosture(broker) {
94953
95450
  }
94954
95451
 
94955
95452
  // registry/turns-schema.ts
94956
- import { chmodSync as chmodSync12, mkdirSync as mkdirSync46 } from "fs";
94957
- import { join as join60 } from "path";
95453
+ import { chmodSync as chmodSync12, mkdirSync as mkdirSync47 } from "fs";
95454
+ import { join as join61 } from "path";
94958
95455
  var DatabaseClass3 = null;
94959
95456
  function loadDatabaseClass3() {
94960
95457
  if (DatabaseClass3 != null)
@@ -95026,9 +95523,9 @@ function applySchema(db3) {
95026
95523
  }
95027
95524
  function openTurnsDb(agentDir) {
95028
95525
  const Database = loadDatabaseClass3();
95029
- const dir = join60(agentDir, "telegram");
95030
- mkdirSync46(dir, { recursive: true, mode: 448 });
95031
- const path2 = join60(dir, "registry.db");
95526
+ const dir = join61(agentDir, "telegram");
95527
+ mkdirSync47(dir, { recursive: true, mode: 448 });
95528
+ const path2 = join61(dir, "registry.db");
95032
95529
  const db3 = new Database(path2, { create: true });
95033
95530
  applySchema(db3);
95034
95531
  try {
@@ -95372,7 +95869,7 @@ function selectResumeBuilder(endedVia, opts) {
95372
95869
  }
95373
95870
 
95374
95871
  // gateway/bridge-dead-watchdog.ts
95375
- import { readFileSync as readFileSync57, writeFileSync as writeFileSync47, renameSync as renameSync21, unlinkSync as unlinkSync25 } from "node:fs";
95872
+ import { readFileSync as readFileSync58, writeFileSync as writeFileSync48, renameSync as renameSync22, unlinkSync as unlinkSync25 } from "node:fs";
95376
95873
 
95377
95874
  // gateway/cron-session.ts
95378
95875
  var CRON_IDENTITY_SUFFIX2 = "-cron";
@@ -95405,7 +95902,7 @@ function readFreshCrashLogTail(path2, opts = {}) {
95405
95902
  const nowMs3 = opts.nowMs ?? Date.now();
95406
95903
  const freshWindowMs = opts.freshWindowMs ?? CRASH_LOG_FRESH_WINDOW_MS;
95407
95904
  const maxLines = opts.maxLines ?? CRASH_LOG_TAIL_LINES;
95408
- const readFile = opts.readFile ?? ((p) => readFileSync57(p, "utf8"));
95905
+ const readFile = opts.readFile ?? ((p) => readFileSync58(p, "utf8"));
95409
95906
  let raw;
95410
95907
  try {
95411
95908
  raw = readFile(path2);
@@ -95426,13 +95923,13 @@ function readFreshCrashLogTail(path2, opts = {}) {
95426
95923
  }
95427
95924
  function writeBridgeDeadEscalationMarker(path2, marker) {
95428
95925
  const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
95429
- writeFileSync47(tmp, JSON.stringify(marker), "utf8");
95430
- renameSync21(tmp, path2);
95926
+ writeFileSync48(tmp, JSON.stringify(marker), "utf8");
95927
+ renameSync22(tmp, path2);
95431
95928
  }
95432
95929
  function consumeBridgeDeadEscalationMarker(path2, nowMs3 = Date.now(), maxAgeMs = ESCALATION_MARKER_MAX_AGE_MS) {
95433
95930
  let marker = null;
95434
95931
  try {
95435
- const parsed = JSON.parse(readFileSync57(path2, "utf8"));
95932
+ const parsed = JSON.parse(readFileSync58(path2, "utf8"));
95436
95933
  if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.reason === "string") {
95437
95934
  const age = nowMs3 - parsed.ts;
95438
95935
  if (age >= 0 && age < maxAgeMs) {
@@ -95585,7 +96082,7 @@ function createBridgeDeadWatchdog(opts) {
95585
96082
  }
95586
96083
 
95587
96084
  // gateway/boot-probes.ts
95588
- import { readFileSync as readFileSync58, readdirSync as readdirSync12, existsSync as existsSync53 } from "fs";
96085
+ import { readFileSync as readFileSync59, readdirSync as readdirSync12, existsSync as existsSync54 } from "fs";
95589
96086
  init_quota_cache();
95590
96087
  init_quota_check();
95591
96088
  import { execFile as execFileCb2 } from "child_process";
@@ -95593,7 +96090,7 @@ import { promisify as promisify2 } from "util";
95593
96090
  var execFile2 = promisify2(execFileCb2);
95594
96091
  var realProcFs2 = {
95595
96092
  readdir: (p) => readdirSync12(p),
95596
- readFile: (p) => readFileSync58(p, "utf-8")
96093
+ readFile: (p) => readFileSync59(p, "utf-8")
95597
96094
  };
95598
96095
  function findAgentProcessInContainer2(fs3 = realProcFs2) {
95599
96096
  let entries;
@@ -95843,7 +96340,7 @@ if (isGatewayMain) {
95843
96340
  shutdownAnalytics();
95844
96341
  });
95845
96342
  }
95846
- var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join61(homedir20(), ".claude", "channels", "telegram");
96343
+ var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join62(homedir20(), ".claude", "channels", "telegram");
95847
96344
  var permCardStore = createPermissionCardStore(STATE_DIR);
95848
96345
  var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
95849
96346
  var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
@@ -95882,7 +96379,7 @@ function alwaysAllowDrainDeps() {
95882
96379
  return {
95883
96380
  readConfigText: () => {
95884
96381
  const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
95885
- return readFileSync59(cfgPath, "utf8");
96382
+ return readFileSync60(cfgPath, "utf8");
95886
96383
  },
95887
96384
  resolveAllowList: (_configText, agentName3) => {
95888
96385
  const cfg = loadConfig2();
@@ -95943,11 +96440,11 @@ function scheduleAlwaysAllowPersistDrain() {
95943
96440
  }, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
95944
96441
  timer3.unref?.();
95945
96442
  }
95946
- var ACCESS_FILE = join61(STATE_DIR, "access.json");
95947
- var APPROVED_DIR = join61(STATE_DIR, "approved");
95948
- var ENV_FILE = join61(STATE_DIR, ".env");
95949
- var INBOX_DIR = join61(STATE_DIR, "inbox");
95950
- var PEOPLE_FILE = join61(STATE_DIR, "people.json");
96443
+ var ACCESS_FILE = join62(STATE_DIR, "access.json");
96444
+ var APPROVED_DIR = join62(STATE_DIR, "approved");
96445
+ var ENV_FILE = join62(STATE_DIR, ".env");
96446
+ var INBOX_DIR = join62(STATE_DIR, "inbox");
96447
+ var PEOPLE_FILE = join62(STATE_DIR, "people.json");
95951
96448
  function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
95952
96449
  const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
95953
96450
  const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
@@ -96012,7 +96509,7 @@ function formatBootVersion() {
96012
96509
  }
96013
96510
  try {
96014
96511
  chmodSync14(ENV_FILE, 384);
96015
- for (const line of readFileSync59(ENV_FILE, "utf8").split(`
96512
+ for (const line of readFileSync60(ENV_FILE, "utf8").split(`
96016
96513
  `)) {
96017
96514
  const m = line.match(/^(\w+)=(.*)$/);
96018
96515
  if (m && process.env[m[1]] === undefined)
@@ -96033,7 +96530,7 @@ var bot;
96033
96530
  var lastGetUpdatesHeartbeatMs = Date.now();
96034
96531
  var GRAMMY_VERSION = (() => {
96035
96532
  try {
96036
- const raw = readFileSync59(new URL("../../node_modules/grammy/package.json", import.meta.url), "utf8");
96533
+ const raw = readFileSync60(new URL("../../node_modules/grammy/package.json", import.meta.url), "utf8");
96037
96534
  return JSON.parse(raw).version ?? "unknown";
96038
96535
  } catch {
96039
96536
  return "unknown";
@@ -96096,7 +96593,7 @@ function assertSendable(f) {
96096
96593
  } catch {
96097
96594
  throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
96098
96595
  }
96099
- const inbox = join61(stateReal, "inbox");
96596
+ const inbox = join62(stateReal, "inbox");
96100
96597
  if (real.startsWith(stateReal + sep4) && !real.startsWith(inbox + sep4)) {
96101
96598
  throw new Error(`refusing to send channel state: ${f}`);
96102
96599
  }
@@ -96115,7 +96612,7 @@ function assertSendable(f) {
96115
96612
  }
96116
96613
  function readAccessFile() {
96117
96614
  try {
96118
- const raw = readFileSync59(ACCESS_FILE, "utf8");
96615
+ const raw = readFileSync60(ACCESS_FILE, "utf8");
96119
96616
  const parsed = JSON.parse(raw);
96120
96617
  const allowFrom = validateStringArray("allowFrom", parsed.allowFrom ?? []);
96121
96618
  const groups = {};
@@ -96155,7 +96652,7 @@ function readAccessFile() {
96155
96652
  if (err.code === "ENOENT")
96156
96653
  return defaultAccess();
96157
96654
  try {
96158
- renameSync22(ACCESS_FILE, `${ACCESS_FILE}.corrupt-${Date.now()}`);
96655
+ renameSync23(ACCESS_FILE, `${ACCESS_FILE}.corrupt-${Date.now()}`);
96159
96656
  } catch {}
96160
96657
  process.stderr.write(`telegram gateway: access.json is corrupt, moved aside. Starting fresh.
96161
96658
  `);
@@ -96177,7 +96674,7 @@ function loadAccess() {
96177
96674
  }
96178
96675
  function readPeopleFile() {
96179
96676
  try {
96180
- const raw = readFileSync59(PEOPLE_FILE, "utf8");
96677
+ const raw = readFileSync60(PEOPLE_FILE, "utf8");
96181
96678
  const parsed = JSON.parse(raw);
96182
96679
  if (!Array.isArray(parsed.entries))
96183
96680
  return [];
@@ -96199,11 +96696,11 @@ function assertAllowedChat(chat_id) {
96199
96696
  function saveAccess(a) {
96200
96697
  if (STATIC)
96201
96698
  return;
96202
- mkdirSync48(STATE_DIR, { recursive: true, mode: 448 });
96699
+ mkdirSync49(STATE_DIR, { recursive: true, mode: 448 });
96203
96700
  const tmp = ACCESS_FILE + ".tmp";
96204
- writeFileSync49(tmp, JSON.stringify(a, null, 2) + `
96701
+ writeFileSync50(tmp, JSON.stringify(a, null, 2) + `
96205
96702
  `, { mode: 384 });
96206
- renameSync22(tmp, ACCESS_FILE);
96703
+ renameSync23(tmp, ACCESS_FILE);
96207
96704
  }
96208
96705
  function pruneExpired(a) {
96209
96706
  const now = Date.now();
@@ -96221,7 +96718,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
96221
96718
  if (isGatewayMain && HISTORY_ENABLED) {
96222
96719
  try {
96223
96720
  initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
96224
- process.stderr.write(`telegram gateway: history capture enabled at ${join61(STATE_DIR, "history.db")}
96721
+ process.stderr.write(`telegram gateway: history capture enabled at ${join62(STATE_DIR, "history.db")}
96225
96722
  `);
96226
96723
  } catch (err) {
96227
96724
  process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
@@ -96240,12 +96737,12 @@ if (isGatewayMain)
96240
96737
  let markerTurnKey = null;
96241
96738
  let markerAgeMs = null;
96242
96739
  try {
96243
- const markerPath = join61(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
96244
- if (existsSync55(markerPath)) {
96740
+ const markerPath = join62(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
96741
+ if (existsSync56(markerPath)) {
96245
96742
  const st = statSync20(markerPath);
96246
96743
  markerAgeMs = Date.now() - st.mtimeMs;
96247
96744
  try {
96248
- const payload = JSON.parse(readFileSync59(markerPath, "utf8"));
96745
+ const payload = JSON.parse(readFileSync60(markerPath, "utf8"));
96249
96746
  if (typeof payload.turnKey === "string" && payload.turnKey.length > 0) {
96250
96747
  markerTurnKey = payload.turnKey;
96251
96748
  }
@@ -96265,10 +96762,10 @@ if (isGatewayMain)
96265
96762
  process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
96266
96763
  `);
96267
96764
  } else {
96268
- process.stderr.write(`telegram gateway: turn-registry initialized at ${join61(agentDir, "telegram", "registry.db")}
96765
+ process.stderr.write(`telegram gateway: turn-registry initialized at ${join62(agentDir, "telegram", "registry.db")}
96269
96766
  `);
96270
96767
  }
96271
- const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join61(STATE_DIR, "bridge-dead-escalation.json"));
96768
+ const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join62(STATE_DIR, "bridge-dead-escalation.json"));
96272
96769
  if (bridgeDeadMarker != null) {
96273
96770
  bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
96274
96771
  process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
@@ -96281,7 +96778,7 @@ if (isGatewayMain)
96281
96778
  const pending2 = findLatestTurnIfInterrupted(turnsDb);
96282
96779
  const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
96283
96780
  if (pending2 != null && selfAgent) {
96284
- const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join61(STATE_DIR, "clean-shutdown.json");
96781
+ const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join62(STATE_DIR, "clean-shutdown.json");
96285
96782
  const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
96286
96783
  const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
96287
96784
  const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
@@ -96394,7 +96891,7 @@ if (isGatewayMain)
96394
96891
  `);
96395
96892
  }
96396
96893
  }
96397
- const pendingEnvPath = join61(agentDir, ".pending-turn.env");
96894
+ const pendingEnvPath = join62(agentDir, ".pending-turn.env");
96398
96895
  try {
96399
96896
  if (pending2 != null) {
96400
96897
  const lines = [
@@ -96408,13 +96905,13 @@ if (isGatewayMain)
96408
96905
  pending2.interrupt_reason != null ? `SWITCHROOM_PENDING_INTERRUPT_REASON=${pending2.interrupt_reason}` : `SWITCHROOM_PENDING_INTERRUPT_REASON=`
96409
96906
  ];
96410
96907
  const pendingEnvTmp = `${pendingEnvPath}.tmp-${process.pid}`;
96411
- writeFileSync49(pendingEnvTmp, lines.join(`
96908
+ writeFileSync50(pendingEnvTmp, lines.join(`
96412
96909
  `) + `
96413
96910
  `, { mode: 384 });
96414
- renameSync22(pendingEnvTmp, pendingEnvPath);
96911
+ renameSync23(pendingEnvTmp, pendingEnvPath);
96415
96912
  process.stderr.write(`telegram gateway: pending-turn env written to ${pendingEnvPath} turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"}
96416
96913
  `);
96417
- } else if (existsSync55(pendingEnvPath)) {
96914
+ } else if (existsSync56(pendingEnvPath)) {
96418
96915
  rmSync6(pendingEnvPath, { force: true });
96419
96916
  process.stderr.write(`telegram gateway: pending-turn env cleared (clean previous shutdown)
96420
96917
  `);
@@ -96522,7 +97019,7 @@ function checkApprovals() {
96522
97019
  return;
96523
97020
  }
96524
97021
  for (const senderId of files) {
96525
- const file = join61(APPROVED_DIR, senderId);
97022
+ const file = join62(APPROVED_DIR, senderId);
96526
97023
  bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync6(file, { force: true }), (err) => {
96527
97024
  process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
96528
97025
  `);
@@ -96695,12 +97192,12 @@ function noteAgentOutputAt(key, ts) {
96695
97192
  lastAgentOutputAt.delete(oldest);
96696
97193
  }
96697
97194
  }
96698
- var OBLIGATION_STORE_PATH = join61(STATE_DIR, "obligations.json");
97195
+ var OBLIGATION_STORE_PATH = join62(STATE_DIR, "obligations.json");
96699
97196
  var obligationStoreFs = {
96700
- readFileSync: (p) => readFileSync59(p, "utf8"),
96701
- writeFileSync: (p, d) => writeFileSync49(p, d),
96702
- renameSync: (a, b) => renameSync22(a, b),
96703
- existsSync: (p) => existsSync55(p)
97197
+ readFileSync: (p) => readFileSync60(p, "utf8"),
97198
+ writeFileSync: (p, d) => writeFileSync50(p, d),
97199
+ renameSync: (a, b) => renameSync23(a, b),
97200
+ existsSync: (p) => existsSync56(p)
96704
97201
  };
96705
97202
  var obligationLedger = new ObligationLedger(OBLIGATION_REPRESENT_MAX, {
96706
97203
  onChange: STATIC || !OBLIGATION_LEDGER_ENABLED ? undefined : (snapshot) => persistObligations(OBLIGATION_STORE_PATH, obligationStoreFs, snapshot)
@@ -97479,9 +97976,9 @@ function emitTurnRecord(turn, endedAt) {
97479
97976
  return;
97480
97977
  }
97481
97978
  },
97482
- rename: (from, to) => renameSync22(from, to)
97979
+ rename: (from, to) => renameSync23(from, to)
97483
97980
  });
97484
- appendFileSync8(turnsPath, rec);
97981
+ appendFileSync9(turnsPath, rec);
97485
97982
  } catch {}
97486
97983
  }
97487
97984
  function maybeProactiveCompact() {
@@ -98107,7 +98604,7 @@ function sweepStaleAlwaysAllowCorrelations(now = Date.now()) {
98107
98604
  var MENTAL_MODEL_CORRELATION_TTL_MS = 720000;
98108
98605
  var pendingMentalModelCorrelations = createSweepableStore((entry, now) => now - entry.createdAt > MENTAL_MODEL_CORRELATION_TTL_MS);
98109
98606
  function mentalModelCorrelationKey(agentName3, unifiedDiff) {
98110
- return `${agentName3}::${createHash5("sha256").update(unifiedDiff).digest("hex")}`;
98607
+ return `${agentName3}::${createHash6("sha256").update(unifiedDiff).digest("hex")}`;
98111
98608
  }
98112
98609
  function sweepStaleMentalModelCorrelations(now = Date.now()) {
98113
98610
  pendingMentalModelCorrelations.sweep(now);
@@ -99043,28 +99540,28 @@ var statusPinState = new Map;
99043
99540
  var statusPinChatIds = new Map;
99044
99541
  var statusPinPinnedAt = new Map;
99045
99542
  var statusPinRightsCache = new PinRightsCache2;
99046
- var STATUS_PIN_STORE_PATH = join61(STATE_DIR, "status-pins.json");
99543
+ var STATUS_PIN_STORE_PATH = join62(STATE_DIR, "status-pins.json");
99047
99544
  var statusPinStoreFs = {
99048
- readFileSync: (p) => readFileSync59(p, "utf8"),
99049
- writeFileSync: (p, d) => writeFileSync49(p, d),
99050
- renameSync: (a, b) => renameSync22(a, b),
99051
- existsSync: (p) => existsSync55(p)
99545
+ readFileSync: (p) => readFileSync60(p, "utf8"),
99546
+ writeFileSync: (p, d) => writeFileSync50(p, d),
99547
+ renameSync: (a, b) => renameSync23(a, b),
99548
+ existsSync: (p) => existsSync56(p)
99052
99549
  };
99053
99550
  var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
99054
- var ACTIVITY_CARD_STORE_PATH = join61(STATE_DIR, "activity-cards-pending.json");
99551
+ var ACTIVITY_CARD_STORE_PATH = join62(STATE_DIR, "activity-cards-pending.json");
99055
99552
  var activityCardStoreFs = {
99056
- readFileSync: (p) => readFileSync59(p, "utf8"),
99057
- writeFileSync: (p, d) => writeFileSync49(p, d),
99058
- renameSync: (a, b) => renameSync22(a, b),
99059
- existsSync: (p) => existsSync55(p)
99553
+ readFileSync: (p) => readFileSync60(p, "utf8"),
99554
+ writeFileSync: (p, d) => writeFileSync50(p, d),
99555
+ renameSync: (a, b) => renameSync23(a, b),
99556
+ existsSync: (p) => existsSync56(p)
99060
99557
  };
99061
99558
  var activityCardPersistEnabled = !STATIC;
99062
- var QUEUED_CARD_STORE_PATH = join61(STATE_DIR, "queued-cards-pending.json");
99559
+ var QUEUED_CARD_STORE_PATH = join62(STATE_DIR, "queued-cards-pending.json");
99063
99560
  var queuedCardStoreFs = {
99064
- readFileSync: (p) => readFileSync59(p, "utf8"),
99065
- writeFileSync: (p, d) => writeFileSync49(p, d),
99066
- renameSync: (a, b) => renameSync22(a, b),
99067
- existsSync: (p) => existsSync55(p)
99561
+ readFileSync: (p) => readFileSync60(p, "utf8"),
99562
+ writeFileSync: (p, d) => writeFileSync50(p, d),
99563
+ renameSync: (a, b) => renameSync23(a, b),
99564
+ existsSync: (p) => existsSync56(p)
99068
99565
  };
99069
99566
  var queuedCardPersistEnabled = !STATIC;
99070
99567
  function persistQueuedCard(key, chatId, threadId, messageId) {
@@ -99437,12 +99934,12 @@ var getPinnedProgressCardMessageId = null;
99437
99934
  var completeProgressCardTurn = null;
99438
99935
  var subagentWatcher = null;
99439
99936
  var workerActivityFeed = null;
99440
- var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join61(STATE_DIR, "gateway.sock");
99937
+ var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join62(STATE_DIR, "gateway.sock");
99441
99938
  if (isGatewayMain)
99442
- mkdirSync48(STATE_DIR, { recursive: true, mode: 448 });
99443
- var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join61(STATE_DIR, "gateway.pid.json");
99444
- var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join61(STATE_DIR, "gateway-session.json");
99445
- var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join61(STATE_DIR, "clean-shutdown.json");
99939
+ mkdirSync49(STATE_DIR, { recursive: true, mode: 448 });
99940
+ var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join62(STATE_DIR, "gateway.pid.json");
99941
+ var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join62(STATE_DIR, "gateway-session.json");
99942
+ var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join62(STATE_DIR, "clean-shutdown.json");
99446
99943
  var GATEWAY_STARTED_AT_MS = Date.now();
99447
99944
  var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
99448
99945
  var activeBootCard = null;
@@ -99471,7 +99968,7 @@ function ensureIssuesCard(chatId, threadId) {
99471
99968
  bot: botApi,
99472
99969
  log: (msg) => process.stderr.write(`telegram gateway: ${msg}
99473
99970
  `),
99474
- persistPath: join61(stateDir, "issues-card.json")
99971
+ persistPath: join62(stateDir, "issues-card.json")
99475
99972
  });
99476
99973
  activeIssuesWatcher = startIssuesWatcher({
99477
99974
  stateDir,
@@ -99669,13 +100166,13 @@ if (isGatewayMain)
99669
100166
  var inboundSpool;
99670
100167
  if (isGatewayMain)
99671
100168
  inboundSpool = STATIC ? undefined : createInboundSpool({
99672
- path: join61(STATE_DIR, "inbound-spool.jsonl"),
100169
+ path: join62(STATE_DIR, "inbound-spool.jsonl"),
99673
100170
  fs: {
99674
- appendFileSync: (p, d) => appendFileSync8(p, d),
99675
- readFileSync: (p) => readFileSync59(p, "utf8"),
99676
- writeFileSync: (p, d) => writeFileSync49(p, d),
99677
- renameSync: (a, b) => renameSync22(a, b),
99678
- existsSync: (p) => existsSync55(p),
100171
+ appendFileSync: (p, d) => appendFileSync9(p, d),
100172
+ readFileSync: (p) => readFileSync60(p, "utf8"),
100173
+ writeFileSync: (p, d) => writeFileSync50(p, d),
100174
+ renameSync: (a, b) => renameSync23(a, b),
100175
+ existsSync: (p) => existsSync56(p),
99679
100176
  statSizeSync: (p) => statSync20(p).size
99680
100177
  },
99681
100178
  onDegraded: (info) => {
@@ -99737,13 +100234,13 @@ async function maybeRedeliverUndeliveredAnswer() {
99737
100234
  let transcriptText;
99738
100235
  try {
99739
100236
  const projectsDir = getProjectsDirForCwd();
99740
- const path2 = join61(projectsDir, `${sessionId}.jsonl`);
99741
- if (!existsSync55(path2)) {
100237
+ const path2 = join62(projectsDir, `${sessionId}.jsonl`);
100238
+ if (!existsSync56(path2)) {
99742
100239
  process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path2}); skipping
99743
100240
  `);
99744
100241
  return;
99745
100242
  }
99746
- transcriptText = readFileSync59(path2, "utf8");
100243
+ transcriptText = readFileSync60(path2, "utf8");
99747
100244
  } catch (err) {
99748
100245
  process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript read failed turnKey=${turn.turn_key}: ${err.message}
99749
100246
  `);
@@ -99902,8 +100399,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
99902
100399
  isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
99903
100400
  isShuttingDown: () => shuttingDown,
99904
100401
  escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
99905
- crashLogPath: join61(STATE_DIR, "bridge-crash.log"),
99906
- markerPath: join61(STATE_DIR, "bridge-dead-escalation.json"),
100402
+ crashLogPath: join62(STATE_DIR, "bridge-crash.log"),
100403
+ markerPath: join62(STATE_DIR, "bridge-dead-escalation.json"),
99907
100404
  log: (line) => process.stderr.write(`${line}
99908
100405
  `),
99909
100406
  priorStreak: bridgeDeadPriorStreak,
@@ -100009,8 +100506,8 @@ if (isGatewayMain)
100009
100506
  probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
100010
100507
  tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
100011
100508
  dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
100012
- configSnapshotPath: join61(resolvedAgentDirForCard, ".config-snapshot.json"),
100013
- bootCardStatePath: join61(resolvedAgentDirForCard, ".boot-card-msgid.json"),
100509
+ configSnapshotPath: join62(resolvedAgentDirForCard, ".config-snapshot.json"),
100510
+ bootCardStatePath: join62(resolvedAgentDirForCard, ".boot-card-msgid.json"),
100014
100511
  floodStatePath: FLOOD_STATE_PATH,
100015
100512
  ...updateOutcomeLine ? { updateOutcomeLine } : {}
100016
100513
  }, ackMsgId).then((handle) => {
@@ -100692,7 +101189,7 @@ if (isGatewayMain)
100692
101189
  const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
100693
101190
  if (Number.isInteger(receiverUid))
100694
101191
  allowedUids.push(receiverUid);
100695
- const socketPath = join61(STATE_DIR, "webhook.sock");
101192
+ const socketPath = join62(STATE_DIR, "webhook.sock");
100696
101193
  const webhookInject = (agentName3, inbound) => {
100697
101194
  const msg = inbound;
100698
101195
  const delivered = ipcServer.sendToAgent(agentName3, msg);
@@ -100920,9 +101417,9 @@ function redactOutboundText(text5, site) {
100920
101417
  var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
100921
101418
  var VOICE_OUT_HARD_CHUNK_CAP = 4096;
100922
101419
  var voiceOnDemandCache = new VoiceOnDemandCache({
100923
- persistPath: join61(STATE_DIR, "voice-ondemand.json")
101420
+ persistPath: join62(STATE_DIR, "voice-ondemand.json")
100924
101421
  });
100925
- var VOICE_CACHE_DIR = join61(STATE_DIR, "voice-cache");
101422
+ var VOICE_CACHE_DIR = join62(STATE_DIR, "voice-cache");
100926
101423
  var voicePreSynthQueue = new PreSynthQueue({
100927
101424
  runJob: async (job) => {
100928
101425
  const sidecarToken = await materializeSidecarToken2();
@@ -101324,11 +101821,11 @@ async function executeSendGif(rawArgs) {
101324
101821
  };
101325
101822
  }
101326
101823
  async function publishToTelegraph(text5, shortName, authorName) {
101327
- const accountPath = join61(STATE_DIR, "telegraph-account.json");
101824
+ const accountPath = join62(STATE_DIR, "telegraph-account.json");
101328
101825
  let account = null;
101329
101826
  try {
101330
- if (existsSync55(accountPath)) {
101331
- const raw = readFileSync59(accountPath, "utf-8");
101827
+ if (existsSync56(accountPath)) {
101828
+ const raw = readFileSync60(accountPath, "utf-8");
101332
101829
  const parsed = JSON.parse(raw);
101333
101830
  if (parsed.shortName && parsed.accessToken) {
101334
101831
  account = parsed;
@@ -101347,8 +101844,8 @@ async function publishToTelegraph(text5, shortName, authorName) {
101347
101844
  }
101348
101845
  account = created.value;
101349
101846
  try {
101350
- mkdirSync48(STATE_DIR, { recursive: true, mode: 448 });
101351
- writeFileSync49(accountPath, JSON.stringify(account, null, 2), { mode: 384 });
101847
+ mkdirSync49(STATE_DIR, { recursive: true, mode: 448 });
101848
+ writeFileSync50(accountPath, JSON.stringify(account, null, 2), { mode: 384 });
101352
101849
  } catch (err) {
101353
101850
  process.stderr.write(`telegram gateway: telegraph cache write failed: ${err.message}
101354
101851
  `);
@@ -101464,7 +101961,7 @@ _The secret was NOT saved. The agent can re-request with \`request_secret\`._`,
101464
101961
  }
101465
101962
  function readLiveSwitchroomConfigText() {
101466
101963
  const cfgPath = process.env.SWITCHROOM_CONFIG ?? findConfigFile2();
101467
- return readFileSync59(cfgPath, "utf8");
101964
+ return readFileSync60(cfgPath, "utf8");
101468
101965
  }
101469
101966
  async function executeReact(args) {
101470
101967
  if (!args.chat_id)
@@ -101503,9 +102000,9 @@ async function executeDownloadAttachment(args) {
101503
102000
  fileUniqueId: file.file_unique_id,
101504
102001
  now: Date.now()
101505
102002
  });
101506
- mkdirSync48(INBOX_DIR, { recursive: true, mode: 448 });
102003
+ mkdirSync49(INBOX_DIR, { recursive: true, mode: 448 });
101507
102004
  assertInsideInbox2(INBOX_DIR, dlPath);
101508
- writeFileSync49(dlPath, buf, { mode: 384 });
102005
+ writeFileSync50(dlPath, buf, { mode: 384 });
101509
102006
  return { content: [{ type: "text", text: dlPath }] };
101510
102007
  }
101511
102008
  async function executeEditMessage(args) {
@@ -102865,14 +103362,14 @@ function restartMarkerPath() {
102865
103362
  const agentDir = resolveAgentDirFromEnv();
102866
103363
  if (!agentDir)
102867
103364
  return null;
102868
- return join61(agentDir, "restart-pending.json");
103365
+ return join62(agentDir, "restart-pending.json");
102869
103366
  }
102870
103367
  function writeRestartMarker(marker) {
102871
103368
  const p = restartMarkerPath();
102872
103369
  if (!p)
102873
103370
  return;
102874
103371
  try {
102875
- writeFileSync49(p, JSON.stringify(marker));
103372
+ writeFileSync50(p, JSON.stringify(marker));
102876
103373
  lastPlannedRestartAt = Date.now();
102877
103374
  process.stderr.write(`telegram gateway: restart-marker: write chat_id=${marker.chat_id} thread_id=${marker.thread_id ?? "-"} ack=${marker.ack_message_id ?? "-"} path=${p}
102878
103375
  `);
@@ -102891,7 +103388,7 @@ function readRestartMarker() {
102891
103388
  if (!p)
102892
103389
  return null;
102893
103390
  try {
102894
- return JSON.parse(readFileSync59(p, "utf8"));
103391
+ return JSON.parse(readFileSync60(p, "utf8"));
102895
103392
  } catch {
102896
103393
  return null;
102897
103394
  }
@@ -103040,7 +103537,7 @@ var _dockerReachable;
103040
103537
  function isDockerReachable() {
103041
103538
  if (_dockerReachable !== undefined)
103042
103539
  return _dockerReachable;
103043
- if (!existsSync55("/var/run/docker.sock")) {
103540
+ if (!existsSync56("/var/run/docker.sock")) {
103044
103541
  _dockerReachable = false;
103045
103542
  return _dockerReachable;
103046
103543
  }
@@ -103057,12 +103554,12 @@ function _resetDockerReachableCache() {
103057
103554
  }
103058
103555
  function spawnSwitchroomDetached(args, onFailure) {
103059
103556
  const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
103060
- const logPath = join61(STATE_DIR, "detached-spawn.log");
103557
+ const logPath = join62(STATE_DIR, "detached-spawn.log");
103061
103558
  let outFd = null;
103062
103559
  try {
103063
- mkdirSync48(STATE_DIR, { recursive: true });
103560
+ mkdirSync49(STATE_DIR, { recursive: true });
103064
103561
  outFd = openSync12(logPath, "a");
103065
- writeFileSync49(logPath, `
103562
+ writeFileSync50(logPath, `
103066
103563
  [${new Date().toISOString()}] spawn ${SWITCHROOM_CLI} ${fullArgs.join(" ")}
103067
103564
  `, { flag: "a" });
103068
103565
  } catch {}
@@ -103088,7 +103585,7 @@ function spawnSwitchroomDetached(args, onFailure) {
103088
103585
  return;
103089
103586
  let tail = "";
103090
103587
  try {
103091
- const full = readFileSync59(logPath, "utf8");
103588
+ const full = readFileSync60(logPath, "utf8");
103092
103589
  tail = full.split(`
103093
103590
  `).slice(-30).join(`
103094
103591
  `).trim();
@@ -103350,10 +103847,10 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
103350
103847
  }
103351
103848
  function readRecentDenialsForAgent(agentName3, windowMs, limit) {
103352
103849
  try {
103353
- const auditPath = join61(homedir20(), ".switchroom", "vault-audit.log");
103354
- if (!existsSync55(auditPath))
103850
+ const auditPath = join62(homedir20(), ".switchroom", "vault-audit.log");
103851
+ if (!existsSync56(auditPath))
103355
103852
  return [];
103356
- const raw = readFileSync59(auditPath, "utf8");
103853
+ const raw = readFileSync60(auditPath, "utf8");
103357
103854
  return recentDenialsFromAuditLog(raw, { agentName: agentName3, windowMs, limit });
103358
103855
  } catch {
103359
103856
  return [];
@@ -103404,7 +103901,7 @@ async function buildAgentMetadata(agentName3) {
103404
103901
  try {
103405
103902
  const agentDir = resolveAgentDirFromEnv();
103406
103903
  if (agentDir) {
103407
- const raw = readFileSync59(join61(agentDir, ".claude", ".claude.json"), "utf8");
103904
+ const raw = readFileSync60(join62(agentDir, ".claude", ".claude.json"), "utf8");
103408
103905
  claudeJson = JSON.parse(raw);
103409
103906
  }
103410
103907
  } catch {}
@@ -103533,7 +104030,7 @@ function buildModelDeps(restartCtx) {
103533
104030
  try {
103534
104031
  const agentDir = resolveAgentDirFromEnv();
103535
104032
  if (agentDir) {
103536
- const local = await fetchQuota2({ claudeConfigDir: join61(agentDir, ".claude") });
104033
+ const local = await fetchQuota2({ claudeConfigDir: join62(agentDir, ".claude") });
103537
104034
  if (local.ok)
103538
104035
  return formatQuotaLine2(local.data);
103539
104036
  }
@@ -103779,9 +104276,9 @@ function effortMenuReplyMarkup(reply) {
103779
104276
  function flushAgentHandoff(agentDir) {
103780
104277
  let removed = 0;
103781
104278
  for (const fname of [".handoff.md", ".handoff-topic"]) {
103782
- const p = join61(agentDir, fname);
104279
+ const p = join62(agentDir, fname);
103783
104280
  try {
103784
- if (existsSync55(p)) {
104281
+ if (existsSync56(p)) {
103785
104282
  unlinkSync27(p);
103786
104283
  removed++;
103787
104284
  }
@@ -103837,7 +104334,7 @@ async function handleNewCommand(ctx) {
103837
104334
  writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
103838
104335
  if (agentDir != null) {
103839
104336
  try {
103840
- writeFileSync49(join61(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
104337
+ writeFileSync50(join62(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
103841
104338
  `, "utf8");
103842
104339
  } catch (err) {
103843
104340
  process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
@@ -103950,16 +104447,16 @@ function buildFolderPickerDeps() {
103950
104447
  };
103951
104448
  }
103952
104449
  var lockoutOps = {
103953
- readFileSync: (p, enc) => readFileSync59(p, enc),
103954
- writeFileSync: (p, data, opts) => writeFileSync49(p, data, opts),
103955
- existsSync: (p) => existsSync55(p),
103956
- mkdirSync: (p, opts) => mkdirSync48(p, opts),
103957
- joinPath: (...parts) => join61(...parts)
104450
+ readFileSync: (p, enc) => readFileSync60(p, enc),
104451
+ writeFileSync: (p, data, opts) => writeFileSync50(p, data, opts),
104452
+ existsSync: (p) => existsSync56(p),
104453
+ mkdirSync: (p, opts) => mkdirSync49(p, opts),
104454
+ joinPath: (...parts) => join62(...parts)
103958
104455
  };
103959
104456
  var FLEET_FALLBACK_DEDUP_MS = 30000;
103960
104457
  function isAuthBrokerSocketReachable() {
103961
104458
  try {
103962
- return existsSync55(resolveAuthBrokerSocketPath2());
104459
+ return existsSync56(resolveAuthBrokerSocketPath2());
103963
104460
  } catch {
103964
104461
  return false;
103965
104462
  }
@@ -104214,7 +104711,7 @@ async function runCreditWatch() {
104214
104711
  if (!agentDir)
104215
104712
  return;
104216
104713
  const agentName3 = getMyAgentName();
104217
- const claudeConfigDir = join61(agentDir, ".claude");
104714
+ const claudeConfigDir = join62(agentDir, ".claude");
104218
104715
  const stateDir = STATE_DIR;
104219
104716
  const reason = readClaudeJsonOverage(claudeConfigDir);
104220
104717
  const prev = loadCreditState(stateDir);
@@ -105970,7 +106467,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
105970
106467
  await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
105971
106468
  return;
105972
106469
  }
105973
- const result = await fetchQuota2({ claudeConfigDir: join61(agentDir, ".claude") });
106470
+ const result = await fetchQuota2({ claudeConfigDir: join62(agentDir, ".claude") });
105974
106471
  if (!result.ok) {
105975
106472
  await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
105976
106473
  return;
@@ -106356,7 +106853,7 @@ ${interimLabel}` : interimLabel
106356
106853
  const unifiedDiff = (() => {
106357
106854
  try {
106358
106855
  const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
106359
- const raw = readFileSync59(cfgPath, "utf8");
106856
+ const raw = readFileSync60(cfgPath, "utf8");
106360
106857
  return synthesizeAllowRuleDiff({ agentName: agentName3, rule: chosen.rule, configText: raw });
106361
106858
  } catch (err) {
106362
106859
  process.stderr.write(`telegram gateway: always-allow diff synth failed: ${err.message}
@@ -106634,6 +107131,7 @@ ${labelWithResume}` : labelWithResume,
106634
107131
  handleChecklistUpdate(ctx, "checklist_tasks_added", checklistHandlerDeps);
106635
107132
  });
106636
107133
  bot2.on("message:pinned_message", (ctx) => handlePinnedMessage(ctx, pinnedMessageHandlerDeps));
107134
+ bot2.on("message:rich_message", (ctx) => handleRichMessageMessage(ctx, mediaEnvelopeDeps));
106637
107135
  installUnhandledMessageCatchAll(bot2, (ctx, text5) => routeInbound(ctx, text5, undefined, undefined, inboundRouterDeps), (line) => process.stderr.write(line));
106638
107136
  bot2.on("message_reaction", (ctx) => {
106639
107137
  handleMessageReaction(ctx);
@@ -107212,7 +107710,7 @@ async function startGateway() {
107212
107710
  return;
107213
107711
  }
107214
107712
  })();
107215
- const resolvedAgentDirForBootCard = agentDir ?? join61(homedir20(), ".switchroom", "agents", agentSlug);
107713
+ const resolvedAgentDirForBootCard = agentDir ?? join62(homedir20(), ".switchroom", "agents", agentSlug);
107216
107714
  const handle = await startBootCard(chatId, threadId, botApiForCard, {
107217
107715
  agentName: agentDisplayName,
107218
107716
  agentSlug,
@@ -107226,8 +107724,8 @@ async function startGateway() {
107226
107724
  probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
107227
107725
  tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
107228
107726
  dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
107229
- configSnapshotPath: join61(resolvedAgentDirForBootCard, ".config-snapshot.json"),
107230
- bootCardStatePath: join61(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
107727
+ configSnapshotPath: join62(resolvedAgentDirForBootCard, ".config-snapshot.json"),
107728
+ bootCardStatePath: join62(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
107231
107729
  floodStatePath: FLOOD_STATE_PATH,
107232
107730
  ...updateOutcomeLine ? { updateOutcomeLine } : {}
107233
107731
  }, ackMsgId);
@@ -107258,10 +107756,10 @@ async function startGateway() {
107258
107756
  try {
107259
107757
  const smAgentDir = resolveAgentDirFromEnv();
107260
107758
  if (smAgentDir) {
107261
- const activePath = join61(smAgentDir, ".active-session-model");
107262
- if (existsSync55(activePath)) {
107759
+ const activePath = join62(smAgentDir, ".active-session-model");
107760
+ if (existsSync56(activePath)) {
107263
107761
  try {
107264
- const launched = readFileSync59(activePath, "utf8").trim();
107762
+ const launched = readFileSync60(activePath, "utf8").trim();
107265
107763
  const configured = (() => {
107266
107764
  const d = switchroomExecJson(["agent", "list"]);
107267
107765
  const raw = d?.agents?.find((a) => a.name === getMyAgentName())?.model ?? null;
@@ -107294,24 +107792,24 @@ async function startGateway() {
107294
107792
  deliverModelSwitchBootNotice({
107295
107793
  ...modelBootCardDeps,
107296
107794
  confirmation,
107297
- hasSessionModelAlert: existsSync55(join61(smAgentDir, ".session-model-alert"))
107795
+ hasSessionModelAlert: existsSync56(join62(smAgentDir, ".session-model-alert"))
107298
107796
  });
107299
107797
  }
107300
107798
  } catch {}
107301
107799
  }
107302
- const activeEffortPath = join61(smAgentDir, ".active-session-effort");
107303
- if (existsSync55(activeEffortPath)) {
107800
+ const activeEffortPath = join62(smAgentDir, ".active-session-effort");
107801
+ if (existsSync56(activeEffortPath)) {
107304
107802
  try {
107305
- const launchedEffort = readFileSync59(activeEffortPath, "utf8").trim();
107803
+ const launchedEffort = readFileSync60(activeEffortPath, "utf8").trim();
107306
107804
  const configuredEffort = getConfiguredEffortForPersist();
107307
107805
  sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
107308
107806
  } catch {}
107309
107807
  }
107310
- const alertPath = join61(smAgentDir, ".session-model-alert");
107311
- if (existsSync55(alertPath)) {
107808
+ const alertPath = join62(smAgentDir, ".session-model-alert");
107809
+ if (existsSync56(alertPath)) {
107312
107810
  let alertText = null;
107313
107811
  try {
107314
- alertText = readFileSync59(alertPath, "utf8").trim();
107812
+ alertText = readFileSync60(alertPath, "utf8").trim();
107315
107813
  } catch {
107316
107814
  alertText = null;
107317
107815
  }