switchroom 0.13.56 → 0.13.57

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.
@@ -27779,15 +27779,15 @@ var init_secretlint_source = __esm(() => {
27779
27779
  });
27780
27780
 
27781
27781
  // card-format.ts
27782
- function escapeHtml8(s) {
27782
+ function escapeHtml9(s) {
27783
27783
  return s.replace(/[&<>]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;" })[c]);
27784
27784
  }
27785
- function truncate5(s, n) {
27785
+ function truncate6(s, n) {
27786
27786
  return s.length > n ? s.slice(0, n - 1) + "\u2026" : s;
27787
27787
  }
27788
27788
 
27789
27789
  // gateway/auth-line.ts
27790
- function escapeHtml9(s) {
27790
+ function escapeHtml10(s) {
27791
27791
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
27792
27792
  }
27793
27793
  function formatRelativeMs2(ms) {
@@ -27847,7 +27847,7 @@ function renderAuthLine(state4, agentName3, now = Date.now()) {
27847
27847
  if (!acc)
27848
27848
  continue;
27849
27849
  const marker = label === activeLabel ? "\u25b6" : "\u21b3";
27850
- const labelHtml = `<code>${escapeHtml9(acc.label)}</code>`;
27850
+ const labelHtml = `<code>${escapeHtml10(acc.label)}</code>`;
27851
27851
  const quotaLine = formatAuthQuotaLine(acc, now);
27852
27852
  rows.push(quotaLine ? `${marker} ${labelHtml} ${quotaLine}` : `${marker} ${labelHtml}`);
27853
27853
  }
@@ -28858,14 +28858,14 @@ function shouldSkipDuplicateBootCard(gate, site) {
28858
28858
  function renderNextStep(text) {
28859
28859
  const parts = text.split("`");
28860
28860
  if (parts.length % 2 === 0)
28861
- return escapeHtml8(text);
28862
- return parts.map((p, i) => i % 2 === 0 ? escapeHtml8(p) : `<code>${escapeHtml8(p)}</code>`).join("");
28861
+ return escapeHtml9(text);
28862
+ return parts.map((p, i) => i % 2 === 0 ? escapeHtml9(p) : `<code>${escapeHtml9(p)}</code>`).join("");
28863
28863
  }
28864
28864
  function renderBootCard(opts) {
28865
28865
  const { agentName: agentName3, version: version2, probes, restartReason, restartAgeMs } = opts;
28866
28866
  const agentSlug = opts.agentSlug ?? agentName3;
28867
28867
  const ackEmoji = restartReason ? REASON_EMOJI[restartReason] : "\u2705";
28868
- const ack = `${ackEmoji} <b>${escapeHtml8(agentName3)}</b> back up \u00b7 ${escapeHtml8(version2)}`;
28868
+ const ack = `${ackEmoji} <b>${escapeHtml9(agentName3)}</b> back up \u00b7 ${escapeHtml9(version2)}`;
28869
28869
  const degradedRows = [];
28870
28870
  const snoozeSet = new Set(opts.snoozeRows ?? []);
28871
28871
  if (opts.resolvedRows && opts.resolvedRows.length > 0) {
@@ -28873,13 +28873,13 @@ function renderBootCard(opts) {
28873
28873
  const lbl = PROBE_LABELS[key];
28874
28874
  if (!lbl)
28875
28875
  continue;
28876
- degradedRows.push(`\u2705 <b>${escapeHtml8(lbl)}</b> resolved`);
28876
+ degradedRows.push(`\u2705 <b>${escapeHtml9(lbl)}</b> resolved`);
28877
28877
  }
28878
28878
  }
28879
28879
  if (restartReason === "crash") {
28880
28880
  const ageStr = restartAgeMs != null && restartAgeMs > 0 ? ` \u00b7 ${(restartAgeMs / 1000).toFixed(1)}s ago` : "";
28881
- degradedRows.push(`\u26a0\ufe0f <b>Restart</b> ${escapeHtml8(REASON_LABEL.crash)}${ageStr}`);
28882
- const tailCmd = process.env.SWITCHROOM_RUNTIME === "docker" ? `docker logs --tail 100 switchroom-${escapeHtml8(agentSlug)}` : `journalctl --user -u switchroom-${escapeHtml8(agentSlug)} -n 100`;
28881
+ degradedRows.push(`\u26a0\ufe0f <b>Restart</b> ${escapeHtml9(REASON_LABEL.crash)}${ageStr}`);
28882
+ const tailCmd = process.env.SWITCHROOM_RUNTIME === "docker" ? `docker logs --tail 100 switchroom-${escapeHtml9(agentSlug)}` : `journalctl --user -u switchroom-${escapeHtml9(agentSlug)} -n 100`;
28883
28883
  degradedRows.push(` \u21b3 Tail logs: <code>${tailCmd}</code>`);
28884
28884
  }
28885
28885
  if (probes) {
@@ -28892,7 +28892,7 @@ function renderBootCard(opts) {
28892
28892
  if (snoozeSet.has(key))
28893
28893
  continue;
28894
28894
  const dot = DOT[r.status] ?? DOT.fail;
28895
- degradedRows.push(`${dot} <b>${PROBE_LABELS[key]}</b> ${escapeHtml8(r.detail)}`);
28895
+ degradedRows.push(`${dot} <b>${PROBE_LABELS[key]}</b> ${escapeHtml9(r.detail)}`);
28896
28896
  if (r.nextStep) {
28897
28897
  degradedRows.push(` \u21b3 ${renderNextStep(r.nextStep)}`);
28898
28898
  }
@@ -29607,7 +29607,7 @@ function truncateDiffForCard(unifiedDiff, maxLines = 50, maxChars = 3000) {
29607
29607
  }
29608
29608
  return out === unifiedDiff ? out : out + sentinel;
29609
29609
  }
29610
- function escapeHtml11(s) {
29610
+ function escapeHtml12(s) {
29611
29611
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
29612
29612
  }
29613
29613
  function clipReason(reason) {
@@ -29618,10 +29618,10 @@ function clipReason(reason) {
29618
29618
  function buildConfigApprovalCardBody(args) {
29619
29619
  const safeReason = clipReason(args.reason);
29620
29620
  const render = (diff) => `\uD83D\uDEE0 <b>Config edit proposed</b>
29621
- ` + `Agent: <code>${escapeHtml11(args.agentName)}</code>
29622
- ` + `Reason: ${escapeHtml11(safeReason)}
29621
+ ` + `Agent: <code>${escapeHtml12(args.agentName)}</code>
29622
+ ` + `Reason: ${escapeHtml12(safeReason)}
29623
29623
 
29624
- ` + `<pre>${escapeHtml11(diff)}</pre>`;
29624
+ ` + `<pre>${escapeHtml12(diff)}</pre>`;
29625
29625
  return truncateRawToFit({
29626
29626
  raw: args.unifiedDiff,
29627
29627
  render,
@@ -29728,8 +29728,8 @@ async function handleRequestConfigFinalize(_client, msg, deps) {
29728
29728
  }
29729
29729
  pending.delete(msg.requestId);
29730
29730
  const body = msg.outcome === "applied" ? `\u2705 <b>Applied</b>${msg.detail ? `
29731
- ${escapeHtml11(msg.detail)}` : ""}` : `\u26a0\ufe0f <b>Reconcile failed; rolled back</b>${msg.detail ? `
29732
- ${escapeHtml11(msg.detail)}` : ""}`;
29731
+ ${escapeHtml12(msg.detail)}` : ""}` : `\u26a0\ufe0f <b>Reconcile failed; rolled back</b>${msg.detail ? `
29732
+ ${escapeHtml12(msg.detail)}` : ""}`;
29733
29733
  try {
29734
29734
  await deps.editCard({
29735
29735
  chatId: entry.chatId,
@@ -29999,17 +29999,17 @@ function registerApprovalsCommands(bot, opts) {
29999
29999
  return;
30000
30000
  }
30001
30001
  if (decisions.length === 0) {
30002
- await ctx.reply(agentFilter ? `No active approvals for <code>${escapeHtml12(agentFilter)}</code>.` : "No active approvals.", { parse_mode: "HTML" });
30002
+ await ctx.reply(agentFilter ? `No active approvals for <code>${escapeHtml13(agentFilter)}</code>.` : "No active approvals.", { parse_mode: "HTML" });
30003
30003
  return;
30004
30004
  }
30005
30005
  const byAgent = new Map;
30006
30006
  for (const d of decisions)
30007
30007
  byAgent.set(d.agent_unit, (byAgent.get(d.agent_unit) ?? 0) + 1);
30008
- const summary = Array.from(byAgent.entries()).map(([a, n]) => `\u2022 <b>${escapeHtml12(a)}</b>: ${n}`).join(`
30008
+ const summary = Array.from(byAgent.entries()).map(([a, n]) => `\u2022 <b>${escapeHtml13(a)}</b>: ${n}`).join(`
30009
30009
  `);
30010
30010
  const detail = decisions.slice(0, 20).map((d) => {
30011
30011
  const ttl = d.ttl_expires_at === null ? "always" : `until ${new Date(d.ttl_expires_at).toISOString().slice(0, 16).replace("T", " ")}`;
30012
- return `<code>${escapeHtml12(d.id.slice(0, 8))}</code> ` + `${escapeHtml12(d.agent_unit)} \u2192 ` + `<code>${escapeHtml12(d.scope)}</code> ` + `(${escapeHtml12(d.action)}, ${ttl}) ` + `\u00b7 /approvals revoke ${escapeHtml12(d.id)}`;
30012
+ return `<code>${escapeHtml13(d.id.slice(0, 8))}</code> ` + `${escapeHtml13(d.agent_unit)} \u2192 ` + `<code>${escapeHtml13(d.scope)}</code> ` + `(${escapeHtml13(d.action)}, ${ttl}) ` + `\u00b7 /approvals revoke ${escapeHtml13(d.id)}`;
30013
30013
  }).join(`
30014
30014
  `);
30015
30015
  await ctx.reply(`<b>Active approvals</b>
@@ -30035,13 +30035,13 @@ ${detail}`, {
30035
30035
  await ctx.reply("Approval kernel unreachable.");
30036
30036
  return;
30037
30037
  }
30038
- await ctx.reply(ok ? `Revoked <code>${escapeHtml12(id)}</code>.` : `No such active decision <code>${escapeHtml12(id)}</code>.`, { parse_mode: "HTML" });
30038
+ await ctx.reply(ok ? `Revoked <code>${escapeHtml13(id)}</code>.` : `No such active decision <code>${escapeHtml13(id)}</code>.`, { parse_mode: "HTML" });
30039
30039
  return;
30040
30040
  }
30041
- await ctx.reply(`Unknown subcommand <code>${escapeHtml12(sub)}</code>. ` + `Use <code>/approvals list</code> or <code>/approvals revoke &lt;id&gt;</code>. ` + `(<code>add</code> and <code>stats</code> are coming in a follow-up.)`, { parse_mode: "HTML" });
30041
+ await ctx.reply(`Unknown subcommand <code>${escapeHtml13(sub)}</code>. ` + `Use <code>/approvals list</code> or <code>/approvals revoke &lt;id&gt;</code>. ` + `(<code>add</code> and <code>stats</code> are coming in a follow-up.)`, { parse_mode: "HTML" });
30042
30042
  });
30043
30043
  }
30044
- function escapeHtml12(s) {
30044
+ function escapeHtml13(s) {
30045
30045
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
30046
30046
  }
30047
30047
  var init_approvals_commands = __esm(() => {
@@ -30123,16 +30123,16 @@ function renderAccountRow2(snap, opts) {
30123
30123
  const lines = [];
30124
30124
  const marker = snap.isActive ? "\u25cf " : "";
30125
30125
  if (!snap.quota) {
30126
- lines.push(`${marker}<code>${escapeHtml13(snap.label)}</code> <i>quota probe failed</i>`);
30126
+ lines.push(`${marker}<code>${escapeHtml14(snap.label)}</code> <i>quota probe failed</i>`);
30127
30127
  if (snap.quotaError) {
30128
- lines.push(` <i>${escapeHtml13(snap.quotaError)}</i>`);
30128
+ lines.push(` <i>${escapeHtml14(snap.quotaError)}</i>`);
30129
30129
  }
30130
30130
  return lines;
30131
30131
  }
30132
30132
  const q = snap.quota;
30133
30133
  const fiveStr = fmtPct2(q.fiveHourUtilizationPct);
30134
30134
  const sevenStr = fmtPct2(q.sevenDayUtilizationPct);
30135
- lines.push(`${marker}<code>${escapeHtml13(snap.label)}</code> ${fiveStr} / ${sevenStr}`);
30135
+ lines.push(`${marker}<code>${escapeHtml14(snap.label)}</code> ${fiveStr} / ${sevenStr}`);
30136
30136
  const health = classifyHealth2(snap);
30137
30137
  if (health === "blocked") {
30138
30138
  const win = bindingWindow2(q);
@@ -30238,13 +30238,13 @@ function renderFallbackAnnouncement2(input) {
30238
30238
  const limitWord = input.oldQuota ? limitWordFor2(input.oldQuota) : "quota";
30239
30239
  const headerLimit = limitWord === "quota" ? "quota cap" : `${limitWord} limit`;
30240
30240
  if (!input.newLabel) {
30241
- lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${escapeHtml13(input.oldLabel)}</b>`);
30241
+ lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${escapeHtml14(input.oldLabel)}</b>`);
30242
30242
  lines.push("");
30243
- lines.push(`Triggered by: agent <b>${escapeHtml13(input.triggerAgent)}</b>`);
30243
+ lines.push(`Triggered by: agent <b>${escapeHtml14(input.triggerAgent)}</b>`);
30244
30244
  if (input.oldQuota) {
30245
30245
  const recovery = recoveryAtFor2(input.oldQuota);
30246
30246
  if (recovery) {
30247
- lines.push(`${escapeHtml13(input.oldLabel)} recovers ${formatAbsolute2(recovery, tz)} ` + `(in ${formatRelative2(recovery, now)})`);
30247
+ lines.push(`${escapeHtml14(input.oldLabel)} recovers ${formatAbsolute2(recovery, tz)} ` + `(in ${formatRelative2(recovery, now)})`);
30248
30248
  }
30249
30249
  }
30250
30250
  lines.push("");
@@ -30252,15 +30252,15 @@ function renderFallbackAnnouncement2(input) {
30252
30252
  return lines.join(`
30253
30253
  `);
30254
30254
  }
30255
- lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${escapeHtml13(input.oldLabel)}</b>`);
30255
+ lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${escapeHtml14(input.oldLabel)}</b>`);
30256
30256
  lines.push("");
30257
- lines.push(`<code>${escapeHtml13(input.oldLabel)}</code> \u2192 <code>${escapeHtml13(input.newLabel)}</code>`);
30258
- lines.push(`Triggered by: agent <b>${escapeHtml13(input.triggerAgent)}</b>`);
30257
+ lines.push(`<code>${escapeHtml14(input.oldLabel)}</code> \u2192 <code>${escapeHtml14(input.newLabel)}</code>`);
30258
+ lines.push(`Triggered by: agent <b>${escapeHtml14(input.triggerAgent)}</b>`);
30259
30259
  lines.push("");
30260
30260
  if (input.oldQuota) {
30261
30261
  const recovery = recoveryAtFor2(input.oldQuota);
30262
30262
  if (recovery) {
30263
- lines.push(`<code>${escapeHtml13(input.oldLabel)}</code> recovers ` + `${formatAbsolute2(recovery, tz)} (in ${formatRelative2(recovery, now)})`);
30263
+ lines.push(`<code>${escapeHtml14(input.oldLabel)}</code> recovers ` + `${formatAbsolute2(recovery, tz)} (in ${formatRelative2(recovery, now)})`);
30264
30264
  }
30265
30265
  }
30266
30266
  if (input.newQuota) {
@@ -30268,7 +30268,7 @@ function renderFallbackAnnouncement2(input) {
30268
30268
  const sevenStr = fmtPct2(input.newQuota.sevenDayUtilizationPct);
30269
30269
  const hasHeadroom = input.newQuota.fiveHourUtilizationPct < THROTTLING_THRESHOLD_PCT2 && input.newQuota.sevenDayUtilizationPct < THROTTLING_THRESHOLD_PCT2;
30270
30270
  const headroomStr = hasHeadroom ? "<i>(plenty of headroom)</i>" : "<i>(near limit \u2014 watch this)</i>";
30271
- lines.push(`<code>${escapeHtml13(input.newLabel)}</code> now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
30271
+ lines.push(`<code>${escapeHtml14(input.newLabel)}</code> now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
30272
30272
  } else {
30273
30273
  lines.push(`<i>(quota probe for new account is pending \u2014 will reflect on next /auth)</i>`);
30274
30274
  }
@@ -30327,7 +30327,7 @@ function switchPriority2(s) {
30327
30327
  return 2;
30328
30328
  return 3;
30329
30329
  }
30330
- function escapeHtml13(s) {
30330
+ function escapeHtml14(s) {
30331
30331
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
30332
30332
  }
30333
30333
  function buildSnapshotsFromState2(state4, quotas) {
@@ -30511,7 +30511,7 @@ import {
30511
30511
  appendFileSync as appendFileSync3
30512
30512
  } from "fs";
30513
30513
  import { homedir as homedir12 } from "os";
30514
- import { join as join33, extname, sep as sep3, basename as basename7 } from "path";
30514
+ import { join as join33, extname, sep as sep3, basename as basename8 } from "path";
30515
30515
 
30516
30516
  // plugin-logger.ts
30517
30517
  import { appendFileSync, mkdirSync, renameSync, statSync, existsSync } from "fs";
@@ -31755,6 +31755,264 @@ function prettifyServer(name) {
31755
31755
  return name.charAt(0).toUpperCase() + name.slice(1);
31756
31756
  }
31757
31757
 
31758
+ // tool-intent-surface.ts
31759
+ var MAX_LABEL_LEN = 140;
31760
+ function frameworkVerbFor(toolName) {
31761
+ const m = /^mcp__[^_]+__(.+)$/.exec(toolName);
31762
+ const suffix = (m ? m[1] : toolName).toLowerCase();
31763
+ switch (suffix) {
31764
+ case "bash":
31765
+ case "bashoutput":
31766
+ case "killshell":
31767
+ return "running";
31768
+ case "websearch":
31769
+ case "grep":
31770
+ case "glob":
31771
+ return "searching";
31772
+ case "webfetch":
31773
+ return "fetching";
31774
+ case "read":
31775
+ return "reading";
31776
+ case "write":
31777
+ return "writing";
31778
+ case "edit":
31779
+ case "multiedit":
31780
+ case "notebookedit":
31781
+ return "editing";
31782
+ case "todowrite":
31783
+ case "todoread":
31784
+ return "noting";
31785
+ case "task":
31786
+ case "agent":
31787
+ return "dispatching";
31788
+ case "toolsearch":
31789
+ return "loading tools";
31790
+ default:
31791
+ if (m)
31792
+ return `using ${m[1].replace(/_/g, " ")}`;
31793
+ return `using ${toolName}`;
31794
+ }
31795
+ }
31796
+ function isUserFacingTool(toolName) {
31797
+ const m = /^mcp__switchroom-telegram__(.+)$/.exec(toolName);
31798
+ const suffix = m ? m[1] : toolName;
31799
+ return suffix === "reply" || suffix === "stream_reply" || suffix === "edit_message" || suffix === "react" || suffix === "send_typing" || suffix === "pin_message" || suffix === "delete_message" || suffix === "forward_message" || suffix === "download_attachment" || suffix === "get_recent_messages" || suffix === "progress_update";
31800
+ }
31801
+ function deriveIntentSurface(toolName, toolInput, precomputedLabel) {
31802
+ if (!toolName)
31803
+ return { text: null };
31804
+ if (isUserFacingTool(toolName))
31805
+ return { text: null };
31806
+ const label = toolLabel(toolName, toolInput, undefined, precomputedLabel);
31807
+ if (!label || !label.trim()) {
31808
+ return {
31809
+ text: `<i>${escapeHtml(frameworkVerbFor(toolName))}</i>`
31810
+ };
31811
+ }
31812
+ const verb = frameworkVerbFor(toolName);
31813
+ const safeLabel = escapeHtml(label).slice(0, MAX_LABEL_LEN);
31814
+ return { text: `<i>${escapeHtml(verb)}:</i> ${safeLabel}` };
31815
+ }
31816
+ function escapeHtml(s) {
31817
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
31818
+ }
31819
+
31820
+ // tool-labels.ts
31821
+ var MAX_LABEL_CHARS2 = 60;
31822
+ var MAX_BASH_CHARS2 = 40;
31823
+ var MAX_DESCRIPTION_CHARS2 = 160;
31824
+ function basename2(p) {
31825
+ if (!p)
31826
+ return "";
31827
+ const parts = p.split("/").filter(Boolean);
31828
+ return parts.length > 0 ? parts[parts.length - 1] : p;
31829
+ }
31830
+ function shortenGrepPath2(p) {
31831
+ if (!p)
31832
+ return "repo";
31833
+ const hadTrailingSlash = /\/+$/.test(p);
31834
+ const trimmed = p.replace(/\/+$/, "");
31835
+ const parts = trimmed.split("/").filter(Boolean);
31836
+ if (parts.length === 0)
31837
+ return "repo";
31838
+ const last = parts[parts.length - 1];
31839
+ if (hadTrailingSlash)
31840
+ return `${last}/`;
31841
+ if (last.startsWith(".") && !last.slice(1).includes("."))
31842
+ return last;
31843
+ if (!last.includes("."))
31844
+ return `${last}/`;
31845
+ return last;
31846
+ }
31847
+ function hostFromUrl2(u) {
31848
+ if (!u)
31849
+ return "";
31850
+ try {
31851
+ return new URL(u).host;
31852
+ } catch {
31853
+ return truncate2(u);
31854
+ }
31855
+ }
31856
+ function truncate2(s, n = MAX_LABEL_CHARS2) {
31857
+ if (s.length <= n)
31858
+ return s;
31859
+ return s.slice(0, n - 1) + "\u2026";
31860
+ }
31861
+ function stripHtml2(s) {
31862
+ return s.replace(/<\/?[a-zA-Z][^>]*>/g, "");
31863
+ }
31864
+ function firstLine2(s) {
31865
+ const idx = s.indexOf(`
31866
+ `);
31867
+ return idx === -1 ? s : s.slice(0, idx);
31868
+ }
31869
+ function toolLabel2(tool, input, preamble, precomputedLabel) {
31870
+ if (precomputedLabel && precomputedLabel.trim().length > 0) {
31871
+ return truncate2(firstLine2(precomputedLabel.trim()), MAX_DESCRIPTION_CHARS2);
31872
+ }
31873
+ if (!input || typeof input !== "object")
31874
+ return "";
31875
+ const str = (k) => typeof input[k] === "string" ? input[k] : undefined;
31876
+ const preambleLabel = () => {
31877
+ if (!preamble)
31878
+ return null;
31879
+ if (preamble.includes(`
31880
+ `))
31881
+ return null;
31882
+ const trimmed = preamble.trim();
31883
+ if (!trimmed)
31884
+ return null;
31885
+ if (trimmed.length > MAX_DESCRIPTION_CHARS2)
31886
+ return null;
31887
+ return trimmed;
31888
+ };
31889
+ switch (tool) {
31890
+ case "Read":
31891
+ case "Write":
31892
+ case "NotebookEdit":
31893
+ case "Edit": {
31894
+ const pre = preambleLabel();
31895
+ if (pre)
31896
+ return pre;
31897
+ return truncate2(basename2(str("file_path") ?? ""));
31898
+ }
31899
+ case "Bash":
31900
+ case "BashOutput": {
31901
+ const description = str("description");
31902
+ if (description)
31903
+ return truncate2(firstLine2(description), MAX_DESCRIPTION_CHARS2);
31904
+ const pre = preambleLabel();
31905
+ if (pre)
31906
+ return pre;
31907
+ const cmd = str("command") ?? str("bash_id") ?? "";
31908
+ return truncate2(firstLine2(cmd), MAX_BASH_CHARS2);
31909
+ }
31910
+ case "KillShell":
31911
+ return truncate2(str("shell_id") ?? "");
31912
+ case "Glob": {
31913
+ const pre = preambleLabel();
31914
+ if (pre)
31915
+ return pre;
31916
+ return truncate2(str("pattern") ?? "");
31917
+ }
31918
+ case "Grep": {
31919
+ const pre = preambleLabel();
31920
+ if (pre)
31921
+ return pre;
31922
+ const pat = str("pattern") ?? "";
31923
+ if (!pat)
31924
+ return "";
31925
+ const path = str("path");
31926
+ const where = shortenGrepPath2(path ?? "");
31927
+ return truncate2(`"${pat}" (in ${where})`);
31928
+ }
31929
+ case "WebFetch":
31930
+ return truncate2(hostFromUrl2(str("url") ?? ""));
31931
+ case "WebSearch": {
31932
+ const q = str("query") ?? "";
31933
+ return q ? truncate2(`"${q}"`) : "";
31934
+ }
31935
+ case "Task":
31936
+ case "Agent": {
31937
+ const desc = str("description") ?? str("subagent_type") ?? "";
31938
+ return truncate2(desc);
31939
+ }
31940
+ case "TodoWrite":
31941
+ case "TaskCreate":
31942
+ case "TaskUpdate":
31943
+ case "TaskList":
31944
+ case "TaskGet":
31945
+ case "TaskStop":
31946
+ case "TaskOutput":
31947
+ return "";
31948
+ case "Skill":
31949
+ return truncate2(str("skill") ?? "");
31950
+ case "SlashCommand":
31951
+ return truncate2(str("command") ?? "");
31952
+ case "ToolSearch": {
31953
+ const q = str("query") ?? "";
31954
+ if (!q)
31955
+ return "";
31956
+ const selectMatch = q.match(/^\s*select\s*:\s*(.+)$/i);
31957
+ if (selectMatch) {
31958
+ const names = selectMatch[1].split(",").map((n) => n.trim()).filter((n) => n.length > 0).join(", ");
31959
+ return truncate2(`Loading schema: ${names}`);
31960
+ }
31961
+ return truncate2(`Searching tools: ${q}`);
31962
+ }
31963
+ default:
31964
+ if (tool.startsWith("mcp__")) {
31965
+ const description = str("description");
31966
+ if (description)
31967
+ return truncate2(firstLine2(stripHtml2(description)), MAX_DESCRIPTION_CHARS2);
31968
+ const label = mcpBaseLabel2(tool);
31969
+ const query = str("query") ?? str("text") ?? str("name");
31970
+ if (label && query) {
31971
+ const budget = Math.max(8, MAX_LABEL_CHARS2 - label.length - 4);
31972
+ const preview = truncate2(firstLine2(stripHtml2(query)), budget);
31973
+ return `${label} (${preview})`;
31974
+ }
31975
+ if (label)
31976
+ return truncate2(label);
31977
+ }
31978
+ for (const k of ["description", "file_path", "path", "url", "query", "pattern", "command"]) {
31979
+ const v = str(k);
31980
+ if (v != null && v.length > 0) {
31981
+ if (k === "file_path" || k === "path")
31982
+ return truncate2(basename2(v));
31983
+ if (k === "url")
31984
+ return truncate2(hostFromUrl2(v));
31985
+ if (k === "description")
31986
+ return truncate2(firstLine2(v), MAX_DESCRIPTION_CHARS2);
31987
+ return truncate2(firstLine2(v));
31988
+ }
31989
+ }
31990
+ return "";
31991
+ }
31992
+ }
31993
+ function mcpBaseLabel2(tool) {
31994
+ if (!tool.startsWith("mcp__"))
31995
+ return "";
31996
+ const parts = tool.slice("mcp__".length).split("__");
31997
+ if (parts.length < 2)
31998
+ return "";
31999
+ const rawServer = parts[0];
32000
+ const action = parts.slice(1).join("__");
32001
+ if (!rawServer || !action)
32002
+ return "";
32003
+ return `${prettifyServer2(rawServer)}: ${action}`;
32004
+ }
32005
+ function prettifyServer2(name) {
32006
+ const LABELS = {
32007
+ "switchroom-telegram": "Telegram"
32008
+ };
32009
+ if (LABELS[name])
32010
+ return LABELS[name];
32011
+ if (!name)
32012
+ return name;
32013
+ return name.charAt(0).toUpperCase() + name.slice(1);
32014
+ }
32015
+
31758
32016
  // gateway/chat-key.ts
31759
32017
  function chatKey(chatId, threadId) {
31760
32018
  const t = threadId == null || threadId === 0 ? "_" : String(threadId);
@@ -32887,7 +33145,7 @@ function installTgPostLogger(bot) {
32887
33145
  }
32888
33146
 
32889
33147
  // attachment-path.ts
32890
- import { join as join2, basename as basename2, resolve, sep } from "node:path";
33148
+ import { join as join2, basename as basename3, resolve, sep } from "node:path";
32891
33149
  function sanitizeExtension(ext) {
32892
33150
  if (ext == null)
32893
33151
  return "bin";
@@ -32916,7 +33174,7 @@ function assertInsideInbox(inboxDir, candidatePath) {
32916
33174
  const inboxReal = resolve(inboxDir);
32917
33175
  const candidateReal = resolve(candidatePath);
32918
33176
  if (candidateReal !== inboxReal && !candidateReal.startsWith(inboxReal + sep)) {
32919
- throw new Error(`attachment path escape: ${basename2(candidatePath)} resolved outside ${inboxDir}`);
33177
+ throw new Error(`attachment path escape: ${basename3(candidatePath)} resolved outside ${inboxDir}`);
32920
33178
  }
32921
33179
  }
32922
33180
 
@@ -38806,16 +39064,16 @@ function renderAccountRow(snap, opts) {
38806
39064
  const lines = [];
38807
39065
  const marker = snap.isActive ? "\u25cf " : "";
38808
39066
  if (!snap.quota) {
38809
- lines.push(`${marker}<code>${escapeHtml(snap.label)}</code> <i>quota probe failed</i>`);
39067
+ lines.push(`${marker}<code>${escapeHtml2(snap.label)}</code> <i>quota probe failed</i>`);
38810
39068
  if (snap.quotaError) {
38811
- lines.push(` <i>${escapeHtml(snap.quotaError)}</i>`);
39069
+ lines.push(` <i>${escapeHtml2(snap.quotaError)}</i>`);
38812
39070
  }
38813
39071
  return lines;
38814
39072
  }
38815
39073
  const q = snap.quota;
38816
39074
  const fiveStr = fmtPct(q.fiveHourUtilizationPct);
38817
39075
  const sevenStr = fmtPct(q.sevenDayUtilizationPct);
38818
- lines.push(`${marker}<code>${escapeHtml(snap.label)}</code> ${fiveStr} / ${sevenStr}`);
39076
+ lines.push(`${marker}<code>${escapeHtml2(snap.label)}</code> ${fiveStr} / ${sevenStr}`);
38819
39077
  const health = classifyHealth(snap);
38820
39078
  if (health === "blocked") {
38821
39079
  const win = bindingWindow(q);
@@ -38921,13 +39179,13 @@ function renderFallbackAnnouncement(input) {
38921
39179
  const limitWord = input.oldQuota ? limitWordFor(input.oldQuota) : "quota";
38922
39180
  const headerLimit = limitWord === "quota" ? "quota cap" : `${limitWord} limit`;
38923
39181
  if (!input.newLabel) {
38924
- lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${escapeHtml(input.oldLabel)}</b>`);
39182
+ lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${escapeHtml2(input.oldLabel)}</b>`);
38925
39183
  lines.push("");
38926
- lines.push(`Triggered by: agent <b>${escapeHtml(input.triggerAgent)}</b>`);
39184
+ lines.push(`Triggered by: agent <b>${escapeHtml2(input.triggerAgent)}</b>`);
38927
39185
  if (input.oldQuota) {
38928
39186
  const recovery = recoveryAtFor(input.oldQuota);
38929
39187
  if (recovery) {
38930
- lines.push(`${escapeHtml(input.oldLabel)} recovers ${formatAbsolute(recovery, tz)} ` + `(in ${formatRelative(recovery, now)})`);
39188
+ lines.push(`${escapeHtml2(input.oldLabel)} recovers ${formatAbsolute(recovery, tz)} ` + `(in ${formatRelative(recovery, now)})`);
38931
39189
  }
38932
39190
  }
38933
39191
  lines.push("");
@@ -38935,15 +39193,15 @@ function renderFallbackAnnouncement(input) {
38935
39193
  return lines.join(`
38936
39194
  `);
38937
39195
  }
38938
- lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${escapeHtml(input.oldLabel)}</b>`);
39196
+ lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${escapeHtml2(input.oldLabel)}</b>`);
38939
39197
  lines.push("");
38940
- lines.push(`<code>${escapeHtml(input.oldLabel)}</code> \u2192 <code>${escapeHtml(input.newLabel)}</code>`);
38941
- lines.push(`Triggered by: agent <b>${escapeHtml(input.triggerAgent)}</b>`);
39198
+ lines.push(`<code>${escapeHtml2(input.oldLabel)}</code> \u2192 <code>${escapeHtml2(input.newLabel)}</code>`);
39199
+ lines.push(`Triggered by: agent <b>${escapeHtml2(input.triggerAgent)}</b>`);
38942
39200
  lines.push("");
38943
39201
  if (input.oldQuota) {
38944
39202
  const recovery = recoveryAtFor(input.oldQuota);
38945
39203
  if (recovery) {
38946
- lines.push(`<code>${escapeHtml(input.oldLabel)}</code> recovers ` + `${formatAbsolute(recovery, tz)} (in ${formatRelative(recovery, now)})`);
39204
+ lines.push(`<code>${escapeHtml2(input.oldLabel)}</code> recovers ` + `${formatAbsolute(recovery, tz)} (in ${formatRelative(recovery, now)})`);
38947
39205
  }
38948
39206
  }
38949
39207
  if (input.newQuota) {
@@ -38951,7 +39209,7 @@ function renderFallbackAnnouncement(input) {
38951
39209
  const sevenStr = fmtPct(input.newQuota.sevenDayUtilizationPct);
38952
39210
  const hasHeadroom = input.newQuota.fiveHourUtilizationPct < THROTTLING_THRESHOLD_PCT && input.newQuota.sevenDayUtilizationPct < THROTTLING_THRESHOLD_PCT;
38953
39211
  const headroomStr = hasHeadroom ? "<i>(plenty of headroom)</i>" : "<i>(near limit \u2014 watch this)</i>";
38954
- lines.push(`<code>${escapeHtml(input.newLabel)}</code> now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
39212
+ lines.push(`<code>${escapeHtml2(input.newLabel)}</code> now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
38955
39213
  } else {
38956
39214
  lines.push(`<i>(quota probe for new account is pending \u2014 will reflect on next /auth)</i>`);
38957
39215
  }
@@ -39010,7 +39268,7 @@ function switchPriority(s) {
39010
39268
  return 2;
39011
39269
  return 3;
39012
39270
  }
39013
- function escapeHtml(s) {
39271
+ function escapeHtml2(s) {
39014
39272
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
39015
39273
  }
39016
39274
  function buildSnapshotsFromState(state3, quotas) {
@@ -39103,7 +39361,7 @@ function parseAuthCommand(text) {
39103
39361
  if (tail.length > 0) {
39104
39362
  return {
39105
39363
  kind: "help",
39106
- reason: `Unknown <code>rm</code> modifier: <code>${escapeHtml2(tail)}</code>. Use <code>/auth rm &lt;label&gt; confirm</code> to confirm.`
39364
+ reason: `Unknown <code>rm</code> modifier: <code>${escapeHtml3(tail)}</code>. Use <code>/auth rm &lt;label&gt; confirm</code> to confirm.`
39107
39365
  };
39108
39366
  }
39109
39367
  return { kind: "rm-prompt", label };
@@ -39123,7 +39381,7 @@ function parseAuthCommand(text) {
39123
39381
  if (sub !== "override") {
39124
39382
  return {
39125
39383
  kind: "help",
39126
- reason: `Unknown <code>agent</code> subcommand: <code>${escapeHtml2(sub || "(none)")}</code>. Try <code>/auth agent override &lt;agent&gt; &lt;label|clear&gt;</code>.`
39384
+ reason: `Unknown <code>agent</code> subcommand: <code>${escapeHtml3(sub || "(none)")}</code>. Try <code>/auth agent override &lt;agent&gt; &lt;label|clear&gt;</code>.`
39127
39385
  };
39128
39386
  }
39129
39387
  const agent = parts[2];
@@ -39145,7 +39403,7 @@ function parseAuthCommand(text) {
39145
39403
  case "help":
39146
39404
  return { kind: "help" };
39147
39405
  default:
39148
- return { kind: "help", reason: `Unknown verb: <code>${escapeHtml2(verb)}</code>` };
39406
+ return { kind: "help", reason: `Unknown verb: <code>${escapeHtml3(verb)}</code>` };
39149
39407
  }
39150
39408
  }
39151
39409
  async function handleAuthCommand(parsed, ctx) {
@@ -39199,7 +39457,7 @@ async function handleAuthCommand(parsed, ctx) {
39199
39457
  };
39200
39458
  } catch (err) {
39201
39459
  return {
39202
- text: `<b>/auth show failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
39460
+ text: `<b>/auth show failed:</b> ${escapeHtml3(err?.message ?? String(err))}`,
39203
39461
  html: true
39204
39462
  };
39205
39463
  }
@@ -39211,7 +39469,7 @@ async function handleAuthCommand(parsed, ctx) {
39211
39469
  const agent = state3.agents.find((a) => a.name === agentName3);
39212
39470
  if (!agent) {
39213
39471
  return {
39214
- text: `<b>/auth show:</b> no agent named <code>${escapeHtml2(agentName3)}</code> in broker view.
39472
+ text: `<b>/auth show:</b> no agent named <code>${escapeHtml3(agentName3)}</code> in broker view.
39215
39473
  ` + `Run <code>/auth show</code> for the fleet snapshot.`,
39216
39474
  html: true
39217
39475
  };
@@ -39219,7 +39477,7 @@ async function handleAuthCommand(parsed, ctx) {
39219
39477
  return { text: renderAgentDetail(state3, agent), html: true };
39220
39478
  } catch (err) {
39221
39479
  return {
39222
- text: `<b>/auth show failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
39480
+ text: `<b>/auth show failed:</b> ${escapeHtml3(err?.message ?? String(err))}`,
39223
39481
  html: true
39224
39482
  };
39225
39483
  }
@@ -39241,13 +39499,13 @@ async function handleAuthCommand(parsed, ctx) {
39241
39499
  try {
39242
39500
  const result = await ctx.client.setActive(parsed.label);
39243
39501
  return {
39244
- text: `<b>Active account \u2192</b> <code>${escapeHtml2(result.active)}</code>
39502
+ text: `<b>Active account \u2192</b> <code>${escapeHtml3(result.active)}</code>
39245
39503
  ` + `Re-mirrored credentials for ${result.fanned.length} agent${result.fanned.length === 1 ? "" : "s"}.`,
39246
39504
  html: true
39247
39505
  };
39248
39506
  } catch (err) {
39249
39507
  return {
39250
- text: `<b>/auth use failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
39508
+ text: `<b>/auth use failed:</b> ${escapeHtml3(err?.message ?? String(err))}`,
39251
39509
  html: true
39252
39510
  };
39253
39511
  }
@@ -39265,13 +39523,13 @@ async function handleAuthCommand(parsed, ctx) {
39265
39523
  }
39266
39524
  const result = await ctx.client.setActive(nextLabel);
39267
39525
  return {
39268
- text: `<b>Rotated:</b> active \u2192 <code>${escapeHtml2(result.active)}</code>
39526
+ text: `<b>Rotated:</b> active \u2192 <code>${escapeHtml3(result.active)}</code>
39269
39527
  ` + `Re-mirrored credentials for ${result.fanned.length} agent${result.fanned.length === 1 ? "" : "s"}.`,
39270
39528
  html: true
39271
39529
  };
39272
39530
  } catch (err) {
39273
39531
  return {
39274
- text: `<b>/auth rotate failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
39532
+ text: `<b>/auth rotate failed:</b> ${escapeHtml3(err?.message ?? String(err))}`,
39275
39533
  html: true
39276
39534
  };
39277
39535
  }
@@ -39282,20 +39540,20 @@ async function handleAuthCommand(parsed, ctx) {
39282
39540
  state3 = await ctx.client.listState();
39283
39541
  } catch (err) {
39284
39542
  return {
39285
- text: `<b>/auth rm failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
39543
+ text: `<b>/auth rm failed:</b> ${escapeHtml3(err?.message ?? String(err))}`,
39286
39544
  html: true
39287
39545
  };
39288
39546
  }
39289
39547
  const exists = state3.accounts.some((a) => a.label === parsed.label);
39290
39548
  if (!exists) {
39291
39549
  return {
39292
- text: `<b>/auth rm:</b> no account named <code>${escapeHtml2(parsed.label)}</code>. ` + `Run <code>/auth show</code> for the current list.`,
39550
+ text: `<b>/auth rm:</b> no account named <code>${escapeHtml3(parsed.label)}</code>. ` + `Run <code>/auth show</code> for the current list.`,
39293
39551
  html: true
39294
39552
  };
39295
39553
  }
39296
39554
  if (state3.active === parsed.label) {
39297
39555
  return {
39298
- text: `<b>/auth rm refused.</b> <code>${escapeHtml2(parsed.label)}</code> is the fleet active. ` + `Switch with <code>/auth use &lt;other&gt;</code> or <code>/auth rotate</code> first.`,
39556
+ text: `<b>/auth rm refused.</b> <code>${escapeHtml3(parsed.label)}</code> is the fleet active. ` + `Switch with <code>/auth use &lt;other&gt;</code> or <code>/auth rotate</code> first.`,
39299
39557
  html: true
39300
39558
  };
39301
39559
  }
@@ -39306,10 +39564,10 @@ async function handleAuthCommand(parsed, ctx) {
39306
39564
  });
39307
39565
  }
39308
39566
  return {
39309
- text: `<b>\u26a0 /auth rm</b> \u2014 about to remove <code>${escapeHtml2(parsed.label)}</code> from the broker.
39310
- ` + `The fleet active is unchanged. Any agent override pointing at <code>${escapeHtml2(parsed.label)}</code> will stop working.
39567
+ text: `<b>\u26a0 /auth rm</b> \u2014 about to remove <code>${escapeHtml3(parsed.label)}</code> from the broker.
39568
+ ` + `The fleet active is unchanged. Any agent override pointing at <code>${escapeHtml3(parsed.label)}</code> will stop working.
39311
39569
 
39312
- ` + `Send <code>/auth rm ${escapeHtml2(parsed.label)} confirm</code> within ${Math.round(AUTH_RM_CONFIRM_TTL_MS / 1000)}s to proceed.`,
39570
+ ` + `Send <code>/auth rm ${escapeHtml3(parsed.label)} confirm</code> within ${Math.round(AUTH_RM_CONFIRM_TTL_MS / 1000)}s to proceed.`,
39313
39571
  html: true
39314
39572
  };
39315
39573
  }
@@ -39321,7 +39579,7 @@ async function handleAuthCommand(parsed, ctx) {
39321
39579
  pendingAuthRmFlows.delete(ctx.chatId);
39322
39580
  }
39323
39581
  return {
39324
- text: `<b>/auth rm:</b> no pending confirm for <code>${escapeHtml2(parsed.label)}</code> (expired or not started). ` + `Send <code>/auth rm ${escapeHtml2(parsed.label)}</code> first.`,
39582
+ text: `<b>/auth rm:</b> no pending confirm for <code>${escapeHtml3(parsed.label)}</code> (expired or not started). ` + `Send <code>/auth rm ${escapeHtml3(parsed.label)}</code> first.`,
39325
39583
  html: true
39326
39584
  };
39327
39585
  }
@@ -39330,12 +39588,12 @@ async function handleAuthCommand(parsed, ctx) {
39330
39588
  try {
39331
39589
  const data = await ctx.client.rmAccount(parsed.label);
39332
39590
  return {
39333
- text: `<b>Removed</b> <code>${escapeHtml2(data.label)}</code> from the broker.`,
39591
+ text: `<b>Removed</b> <code>${escapeHtml3(data.label)}</code> from the broker.`,
39334
39592
  html: true
39335
39593
  };
39336
39594
  } catch (err) {
39337
39595
  return {
39338
- text: `<b>/auth rm failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
39596
+ text: `<b>/auth rm failed:</b> ${escapeHtml3(err?.message ?? String(err))}`,
39339
39597
  html: true
39340
39598
  };
39341
39599
  }
@@ -39346,7 +39604,7 @@ async function handleAuthCommand(parsed, ctx) {
39346
39604
  const targets = parsed.label ? state3.accounts.filter((a) => a.label === parsed.label).map((a) => a.label) : state3.accounts.map((a) => a.label);
39347
39605
  if (parsed.label && targets.length === 0) {
39348
39606
  return {
39349
- text: `<b>/auth refresh:</b> no account named <code>${escapeHtml2(parsed.label)}</code>.`,
39607
+ text: `<b>/auth refresh:</b> no account named <code>${escapeHtml3(parsed.label)}</code>.`,
39350
39608
  html: true
39351
39609
  };
39352
39610
  }
@@ -39365,10 +39623,10 @@ async function handleAuthCommand(parsed, ctx) {
39365
39623
  formatExpiryAbs(data.expiresAt)
39366
39624
  ]);
39367
39625
  } catch (err) {
39368
- failures.push(`${label}: ${escapeHtml2(err?.message ?? String(err))}`);
39626
+ failures.push(`${label}: ${escapeHtml3(err?.message ?? String(err))}`);
39369
39627
  }
39370
39628
  }
39371
- const head = targets.length === 1 ? `<b>Refreshed</b> <code>${escapeHtml2(targets[0])}</code>` : `<b>Refreshed</b> ${rows.length - 1}/${targets.length} account${targets.length === 1 ? "" : "s"}`;
39629
+ const head = targets.length === 1 ? `<b>Refreshed</b> <code>${escapeHtml3(targets[0])}</code>` : `<b>Refreshed</b> ${rows.length - 1}/${targets.length} account${targets.length === 1 ? "" : "s"}`;
39372
39630
  const table = rows.length > 1 ? `
39373
39631
  <pre>${alignTable(rows)}</pre>` : "";
39374
39632
  const failBlock = failures.length > 0 ? `
@@ -39378,7 +39636,7 @@ ${failures.map((f) => ` ${f}`).join(`
39378
39636
  return { text: head + table + failBlock, html: true };
39379
39637
  } catch (err) {
39380
39638
  return {
39381
- text: `<b>/auth refresh failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
39639
+ text: `<b>/auth refresh failed:</b> ${escapeHtml3(err?.message ?? String(err))}`,
39382
39640
  html: true
39383
39641
  };
39384
39642
  }
@@ -39387,12 +39645,12 @@ ${failures.map((f) => ` ${f}`).join(`
39387
39645
  try {
39388
39646
  const data = await ctx.client.setOverride(parsed.agent, parsed.label);
39389
39647
  return {
39390
- text: `<b>Override set.</b> <code>${escapeHtml2(data.agent)}</code> is now pinned to ` + `<code>${escapeHtml2(data.account ?? parsed.label)}</code>.`,
39648
+ text: `<b>Override set.</b> <code>${escapeHtml3(data.agent)}</code> is now pinned to ` + `<code>${escapeHtml3(data.account ?? parsed.label)}</code>.`,
39391
39649
  html: true
39392
39650
  };
39393
39651
  } catch (err) {
39394
39652
  return {
39395
- text: `<b>/auth agent override failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
39653
+ text: `<b>/auth agent override failed:</b> ${escapeHtml3(err?.message ?? String(err))}`,
39396
39654
  html: true
39397
39655
  };
39398
39656
  }
@@ -39401,12 +39659,12 @@ ${failures.map((f) => ` ${f}`).join(`
39401
39659
  try {
39402
39660
  const data = await ctx.client.setOverride(parsed.agent, null);
39403
39661
  return {
39404
- text: `<b>Override cleared</b> on <code>${escapeHtml2(data.agent)}</code> ` + `\u2014 back to fleet active.`,
39662
+ text: `<b>Override cleared</b> on <code>${escapeHtml3(data.agent)}</code> ` + `\u2014 back to fleet active.`,
39405
39663
  html: true
39406
39664
  };
39407
39665
  } catch (err) {
39408
39666
  return {
39409
- text: `<b>/auth agent override failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
39667
+ text: `<b>/auth agent override failed:</b> ${escapeHtml3(err?.message ?? String(err))}`,
39410
39668
  html: true
39411
39669
  };
39412
39670
  }
@@ -39485,7 +39743,7 @@ function formatAccountsTable(state3, now) {
39485
39743
  const status = isActive ? "active" : acc.exhausted ? "exhausted" : "available";
39486
39744
  const expires = acc.expiresAt != null ? formatRelativeMs(acc.expiresAt - now) : "\u2014";
39487
39745
  const quotaReset = acc.exhausted && acc.exhausted_until != null && acc.exhausted_until > now ? formatRelativeMs(acc.exhausted_until - now) : "\u2014";
39488
- rows.push([`${marker} ${escapeHtml2(acc.label)}`, status, expires, quotaReset]);
39746
+ rows.push([`${marker} ${escapeHtml3(acc.label)}`, status, expires, quotaReset]);
39489
39747
  }
39490
39748
  return alignTable(rows);
39491
39749
  }
@@ -39493,15 +39751,15 @@ function formatAgentsTable(state3) {
39493
39751
  const rows = [["AGENT", "ACTIVE", "SOURCE"]];
39494
39752
  for (const a of state3.agents) {
39495
39753
  const source = a.override ? "override" : a.account === state3.active ? "fleet-active" : "pinned";
39496
- rows.push([escapeHtml2(a.name), escapeHtml2(a.account), source]);
39754
+ rows.push([escapeHtml3(a.name), escapeHtml3(a.account), source]);
39497
39755
  }
39498
39756
  return alignTable(rows);
39499
39757
  }
39500
39758
  function renderAgentDetail(state3, agent, now = Date.now()) {
39501
39759
  const lines = [];
39502
- lines.push(`<b>${escapeHtml2(agent.name)}</b>`);
39760
+ lines.push(`<b>${escapeHtml3(agent.name)}</b>`);
39503
39761
  const source = agent.override ? "override" : "fleet-active";
39504
- lines.push(`Active account: <code>${escapeHtml2(agent.account)}</code> (${source})`);
39762
+ lines.push(`Active account: <code>${escapeHtml3(agent.account)}</code> (${source})`);
39505
39763
  const acct = state3.accounts.find((a) => a.label === agent.account);
39506
39764
  if (acct) {
39507
39765
  const expRel = acct.expiresAt != null ? formatRelativeMs(acct.expiresAt - now) : "\u2014";
@@ -39524,11 +39782,11 @@ function formatConsumersTable(state3, now) {
39524
39782
  const rows = [["CONSUMER", "ACTIVE", "STATUS"]];
39525
39783
  for (const c of state3.consumers) {
39526
39784
  const status = c.last_seen_at == null ? "socket bound" : `socket bound (last seen ${formatRelativeMs(now - c.last_seen_at)} ago)`;
39527
- rows.push([escapeHtml2(c.name), escapeHtml2(c.account), status]);
39785
+ rows.push([escapeHtml3(c.name), escapeHtml3(c.account), status]);
39528
39786
  }
39529
39787
  return alignTable(rows);
39530
39788
  }
39531
- function escapeHtml2(s) {
39789
+ function escapeHtml3(s) {
39532
39790
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
39533
39791
  }
39534
39792
  function formatRelativeMs(ms) {
@@ -40843,11 +41101,11 @@ function renderTable(headers, rows) {
40843
41101
  if (colCount <= 3 && rowCount <= 6) {
40844
41102
  const bullets = rows.map((row) => {
40845
41103
  const cells = headers.map((_, i) => (row[i] ?? "").trim());
40846
- const key = escapeHtml4(cells[0] || "\u2014");
40847
- const rest = cells.slice(1).filter((v) => v !== "").map((v) => ` \u2014 ${escapeHtml4(v)}`).join("");
41104
+ const key = escapeHtml5(cells[0] || "\u2014");
41105
+ const rest = cells.slice(1).filter((v) => v !== "").map((v) => ` \u2014 ${escapeHtml5(v)}`).join("");
40848
41106
  return `\u2022 <b>${key}</b>${rest}`;
40849
41107
  });
40850
- const headerLine = colCount >= 2 ? `<b>${headers.map((h) => escapeHtml4(h)).join(" / ")}</b>
41108
+ const headerLine = colCount >= 2 ? `<b>${headers.map((h) => escapeHtml5(h)).join(" / ")}</b>
40851
41109
  ` : "";
40852
41110
  return headerLine + bullets.join(`
40853
41111
  `);
@@ -40862,7 +41120,7 @@ function renderTable(headers, rows) {
40862
41120
  sepLine,
40863
41121
  ...rows.map((r) => formatRow(r))
40864
41122
  ];
40865
- return `<pre>${escapeHtml4(lines.join(`
41123
+ return `<pre>${escapeHtml5(lines.join(`
40866
41124
  `))}</pre>`;
40867
41125
  }
40868
41126
  function extractMarkdownTables(text, store2, placeholderPrefix) {
@@ -40910,7 +41168,7 @@ function markdownToHtml(text) {
40910
41168
  const INLINE_PH = "\x00CODEINLINE";
40911
41169
  const TABLE_PH = "\x00TABLEBLOCK";
40912
41170
  let result = text.replace(/```(\w*)\n([\s\S]*?)```/g, (_m, lang, code) => {
40913
- const escaped = escapeHtml4(code.replace(/\n$/, ""));
41171
+ const escaped = escapeHtml5(code.replace(/\n$/, ""));
40914
41172
  const cls = lang ? ` class="language-${lang}"` : "";
40915
41173
  const idx = codeBlocks.length;
40916
41174
  codeBlocks.push(`<pre><code${cls}>${escaped}</code></pre>`);
@@ -40923,7 +41181,7 @@ function markdownToHtml(text) {
40923
41181
  const inlineCodes = [];
40924
41182
  result = result.replace(/`([^`\n]+)`/g, (_m, code) => {
40925
41183
  const idx = inlineCodes.length;
40926
- inlineCodes.push(`<code>${escapeHtml4(code)}</code>`);
41184
+ inlineCodes.push(`<code>${escapeHtml5(code)}</code>`);
40927
41185
  return `${INLINE_PH}${idx}\x00`;
40928
41186
  });
40929
41187
  const htmlTags = [];
@@ -40935,24 +41193,24 @@ function markdownToHtml(text) {
40935
41193
  htmlTags.push(match);
40936
41194
  return `${HTMLTAG_PH}${idx}\x00`;
40937
41195
  });
40938
- result = escapeHtml4(result);
41196
+ result = escapeHtml5(result);
40939
41197
  result = result.replace(/\*\*(.+?)\*\*/g, "<b>$1</b>");
40940
41198
  result = result.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<i>$1</i>");
40941
41199
  result = result.replace(/(?<![\w_])_(?!_)([^_\n]+?)_(?![\w_])/g, "<i>$1</i>");
40942
41200
  result = result.replace(/~~(.+?)~~/g, "<s>$1</s>");
40943
- result = result.replace(new RegExp(`${escapeHtml4(BLOCK_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => codeBlocks[Number(idx)]);
40944
- result = result.replace(new RegExp(`${escapeHtml4(TABLE_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => codeBlocks[Number(idx)]);
40945
- result = result.replace(new RegExp(`${escapeHtml4(INLINE_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => inlineCodes[Number(idx)]);
41201
+ result = result.replace(new RegExp(`${escapeHtml5(BLOCK_PH)}(\\d+)${escapeHtml5("\x00")}`, "g"), (_m, idx) => codeBlocks[Number(idx)]);
41202
+ result = result.replace(new RegExp(`${escapeHtml5(TABLE_PH)}(\\d+)${escapeHtml5("\x00")}`, "g"), (_m, idx) => codeBlocks[Number(idx)]);
41203
+ result = result.replace(new RegExp(`${escapeHtml5(INLINE_PH)}(\\d+)${escapeHtml5("\x00")}`, "g"), (_m, idx) => inlineCodes[Number(idx)]);
40946
41204
  const ALLOWED_LINK_SCHEMES = /^(?:https?|mailto|tel|tg):/i;
40947
41205
  result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, linkText, url) => {
40948
41206
  const safe = ALLOWED_LINK_SCHEMES.test(url.trim()) ? url.trim() : "#";
40949
- return `<a href="${escapeHtml4(safe)}">${linkText}</a>`;
41207
+ return `<a href="${escapeHtml5(safe)}">${linkText}</a>`;
40950
41208
  });
40951
41209
  result = result.replace(/(?<![<\/\w>])(\b[\w][\w.-]*\.(?:ts|js|py|rs|go|json|yaml|yml|toml|md|txt|sh|bash|zsh|css|html|xml|sql|env|cfg|conf|ini|log|csv|tsx|jsx|vue|svelte|rb|java|kt|swift|c|cpp|h|hpp|zig|asm|wasm|lock|mod|sum)\b)(?![^<]*>)/g, "<code>$1</code>");
40952
- result = result.replace(new RegExp(`${escapeHtml4(HTMLTAG_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => htmlTags[Number(idx)]);
41210
+ result = result.replace(new RegExp(`${escapeHtml5(HTMLTAG_PH)}(\\d+)${escapeHtml5("\x00")}`, "g"), (_m, idx) => htmlTags[Number(idx)]);
40953
41211
  return result;
40954
41212
  }
40955
- function escapeHtml4(text) {
41213
+ function escapeHtml5(text) {
40956
41214
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
40957
41215
  }
40958
41216
  function telegramHtmlToPlainText(html) {
@@ -41353,7 +41611,7 @@ async function finalizeCallback(ctx, opts) {
41353
41611
  }
41354
41612
 
41355
41613
  // welcome-text.ts
41356
- function escapeHtml5(text) {
41614
+ function escapeHtml6(text) {
41357
41615
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
41358
41616
  }
41359
41617
  function formatAuthLine(auth) {
@@ -41365,13 +41623,13 @@ function formatAuthLine(auth) {
41365
41623
  return "\u2717 not authenticated";
41366
41624
  }
41367
41625
  const sub = auth.subscription_type ?? "subscription";
41368
- const expires = auth.expires_in ? ` \u00b7 expires ${escapeHtml5(auth.expires_in)}` : "";
41369
- return `\u2713 ${escapeHtml5(sub)}${expires}`;
41626
+ const expires = auth.expires_in ? ` \u00b7 expires ${escapeHtml6(auth.expires_in)}` : "";
41627
+ return `\u2713 ${escapeHtml6(sub)}${expires}`;
41370
41628
  }
41371
41629
  function formatAgentLine(meta) {
41372
41630
  const m = meta.model && meta.model.length > 0 ? meta.model : "default";
41373
- const topic = meta.topicName ? ` \u00b7 topic: ${escapeHtml5([meta.topicEmoji, meta.topicName].filter(Boolean).join(" "))}` : "";
41374
- return `<b>${escapeHtml5(meta.agentName)}</b> \u00b7 model: <code>${escapeHtml5(m)}</code>${topic}`;
41631
+ const topic = meta.topicName ? ` \u00b7 topic: ${escapeHtml6([meta.topicEmoji, meta.topicName].filter(Boolean).join(" "))}` : "";
41632
+ return `<b>${escapeHtml6(meta.agentName)}</b> \u00b7 model: <code>${escapeHtml6(m)}</code>${topic}`;
41375
41633
  }
41376
41634
  function startText(agentName3, dmDisabled) {
41377
41635
  if (dmDisabled)
@@ -41379,7 +41637,7 @@ function startText(agentName3, dmDisabled) {
41379
41637
  return [
41380
41638
  `<b>Switchroom</b> \u2014 Telegram on your Claude Pro or Max subscription.`,
41381
41639
  ``,
41382
- `This bot is the <b>${escapeHtml5(agentName3)}</b> agent. Pair first, then send messages here and they reach the agent; replies and reactions come back.`,
41640
+ `This bot is the <b>${escapeHtml6(agentName3)}</b> agent. Pair first, then send messages here and they reach the agent; replies and reactions come back.`,
41383
41641
  ``,
41384
41642
  `<b>To pair:</b>`,
41385
41643
  `1. DM me anything \u2014 you'll get a 6-char code`,
@@ -41393,7 +41651,7 @@ function helpText(agentName3) {
41393
41651
  return [
41394
41652
  `<b>Switchroom</b> \u2014 your Pro/Max subscription, wired to Telegram.`,
41395
41653
  ``,
41396
- `This bot is the <b>${escapeHtml5(agentName3)}</b> agent. Text and photos route through to it; replies, reactions and progress cards come back.`,
41654
+ `This bot is the <b>${escapeHtml6(agentName3)}</b> agent. Text and photos route through to it; replies, reactions and progress cards come back.`,
41397
41655
  ``,
41398
41656
  `Tool approvals surface as inline buttons (\u2705 / \u274c) or via <code>/approve</code>, <code>/deny</code>, <code>/pending</code>. Start a fresh session with <code>/new</code> or <code>/reset</code>.`,
41399
41657
  ``,
@@ -41412,40 +41670,40 @@ var STATUS_DOT = {
41412
41670
  function statusPairedText(params) {
41413
41671
  const { user, meta } = params;
41414
41672
  const lines = [
41415
- `Paired as ${escapeHtml5(user)}.`,
41673
+ `Paired as ${escapeHtml6(user)}.`,
41416
41674
  ``,
41417
41675
  `Agent: ${formatAgentLine(meta)}`,
41418
41676
  `Auth: ${formatAuthLine(meta.auth)}`
41419
41677
  ];
41420
41678
  if (meta.status)
41421
- lines.push(`Status: <code>${escapeHtml5(meta.status)}</code>${meta.uptime ? ` \u00b7 up ${escapeHtml5(meta.uptime)}` : ""}`);
41679
+ lines.push(`Status: <code>${escapeHtml6(meta.status)}</code>${meta.uptime ? ` \u00b7 up ${escapeHtml6(meta.uptime)}` : ""}`);
41422
41680
  if (meta.live && meta.live.length > 0) {
41423
41681
  lines.push("");
41424
41682
  lines.push("<b>Health</b>");
41425
41683
  for (const row of meta.live) {
41426
41684
  const dot = STATUS_DOT[row.status] ?? STATUS_DOT.fail;
41427
- lines.push(`${dot} <b>${escapeHtml5(row.label)}</b> ${escapeHtml5(row.detail)}`);
41685
+ lines.push(`${dot} <b>${escapeHtml6(row.label)}</b> ${escapeHtml6(row.detail)}`);
41428
41686
  }
41429
41687
  }
41430
41688
  const audit = meta.audit;
41431
41689
  if (audit) {
41432
41690
  lines.push("");
41433
41691
  if (audit.version)
41434
- lines.push(`<b>Version</b> ${escapeHtml5(audit.version)}`);
41692
+ lines.push(`<b>Version</b> ${escapeHtml6(audit.version)}`);
41435
41693
  if (meta.extendsProfile)
41436
- lines.push(`<b>Profile</b> ${escapeHtml5(meta.extendsProfile)}`);
41694
+ lines.push(`<b>Profile</b> ${escapeHtml6(meta.extendsProfile)}`);
41437
41695
  if (audit.tools)
41438
- lines.push(`<b>Tools</b> ${escapeHtml5(audit.tools)}`);
41696
+ lines.push(`<b>Tools</b> ${escapeHtml6(audit.tools)}`);
41439
41697
  if (audit.toolsDeny)
41440
- lines.push(`<b>Deny</b> ${escapeHtml5(audit.toolsDeny)}`);
41698
+ lines.push(`<b>Deny</b> ${escapeHtml6(audit.toolsDeny)}`);
41441
41699
  if (audit.skills)
41442
- lines.push(`<b>Skills</b> ${escapeHtml5(audit.skills)}`);
41700
+ lines.push(`<b>Skills</b> ${escapeHtml6(audit.skills)}`);
41443
41701
  if (audit.limits)
41444
- lines.push(`<b>Limits</b> ${escapeHtml5(audit.limits)}`);
41702
+ lines.push(`<b>Limits</b> ${escapeHtml6(audit.limits)}`);
41445
41703
  if (audit.channel)
41446
- lines.push(`<b>Channel</b> ${escapeHtml5(audit.channel)}`);
41704
+ lines.push(`<b>Channel</b> ${escapeHtml6(audit.channel)}`);
41447
41705
  if (audit.memoryBank)
41448
- lines.push(`<b>Memory</b> ${escapeHtml5(audit.memoryBank)}`);
41706
+ lines.push(`<b>Memory</b> ${escapeHtml6(audit.memoryBank)}`);
41449
41707
  }
41450
41708
  return lines.join(`
41451
41709
  `);
@@ -41453,7 +41711,7 @@ function statusPairedText(params) {
41453
41711
  function statusPendingText(code) {
41454
41712
  return `Pending pairing \u2014 run in Claude Code:
41455
41713
 
41456
- <code>/telegram:access pair ${escapeHtml5(code)}</code>`;
41714
+ <code>/telegram:access pair ${escapeHtml6(code)}</code>`;
41457
41715
  }
41458
41716
  function statusUnpairedText() {
41459
41717
  return "Not paired. Send me a message to get a pairing code.";
@@ -41482,7 +41740,7 @@ var TELEGRAM_BASE_COMMANDS = TELEGRAM_MENU_COMMANDS.slice(0, 3);
41482
41740
  var TELEGRAM_SWITCHROOM_COMMANDS = TELEGRAM_MENU_COMMANDS.slice(3);
41483
41741
  function switchroomHelpText(agentName3) {
41484
41742
  return [
41485
- `<b>Switchroom bot</b> \u2014 commands for the <b>${escapeHtml5(agentName3)}</b> agent.`,
41743
+ `<b>Switchroom bot</b> \u2014 commands for the <b>${escapeHtml6(agentName3)}</b> agent.`,
41486
41744
  ``,
41487
41745
  `<b>Session &amp; approvals</b>`,
41488
41746
  `<code>/new</code> \u2014 fresh session (flush handoff, restart)`,
@@ -41530,15 +41788,15 @@ function switchroomHelpText(agentName3) {
41530
41788
  `);
41531
41789
  }
41532
41790
  function restartAckText(agentName3) {
41533
- return `\uD83D\uDD04 Restarting <b>${escapeHtml5(agentName3)}</b>\u2026`;
41791
+ return `\uD83D\uDD04 Restarting <b>${escapeHtml6(agentName3)}</b>\u2026`;
41534
41792
  }
41535
41793
  function newSessionAckText(agentName3, flushedHandoff) {
41536
41794
  const tail = flushedHandoff ? " \u00b7 flushed handoff" : "";
41537
- return `\uD83C\uDD95 Started fresh session for <b>${escapeHtml5(agentName3)}</b>${tail} \u00b7 restarting\u2026`;
41795
+ return `\uD83C\uDD95 Started fresh session for <b>${escapeHtml6(agentName3)}</b>${tail} \u00b7 restarting\u2026`;
41538
41796
  }
41539
41797
  function resetSessionAckText(agentName3, flushedHandoff) {
41540
41798
  const tail = flushedHandoff ? " \u00b7 flushed handoff" : "";
41541
- return `\uD83D\uDD04 Reset session for <b>${escapeHtml5(agentName3)}</b>${tail} \u00b7 restarting\u2026`;
41799
+ return `\uD83D\uDD04 Reset session for <b>${escapeHtml6(agentName3)}</b>${tail} \u00b7 restarting\u2026`;
41542
41800
  }
41543
41801
 
41544
41802
  // gateway/auth-status-adapter.ts
@@ -41723,7 +41981,7 @@ function shouldShowHandoffLine() {
41723
41981
  function formatHandoffLine(topic, format) {
41724
41982
  const prefix = "\u21a9\ufe0f Picked up where we left off, ";
41725
41983
  if (format === "html") {
41726
- return `<i>${prefix}${escapeHtml6(topic)}</i>
41984
+ return `<i>${prefix}${escapeHtml7(topic)}</i>
41727
41985
 
41728
41986
  `;
41729
41987
  }
@@ -41738,7 +41996,7 @@ function formatHandoffLine(topic, format) {
41738
41996
 
41739
41997
  `;
41740
41998
  }
41741
- function escapeHtml6(s) {
41999
+ function escapeHtml7(s) {
41742
42000
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
41743
42001
  }
41744
42002
  var MDV2_SPECIALS = /[_*\[\]()~`>#+\-=|{}.!\\]/g;
@@ -45117,13 +45375,13 @@ function buildMs365CardText(p) {
45117
45375
  const lines = [];
45118
45376
  lines.push(`\uD83D\uDCC4 Microsoft 365 write approval`);
45119
45377
  lines.push("");
45120
- lines.push(`Agent: ${truncate2(p.agentName, 64)}`);
45121
- lines.push(`Tool: ${truncate2(p.toolName.replace(/^mcp__/, ""), 96)}`);
45122
- lines.push(`Item: ${truncate2(p.itemDisplayName, 256)}`);
45378
+ lines.push(`Agent: ${truncate3(p.agentName, 64)}`);
45379
+ lines.push(`Tool: ${truncate3(p.toolName.replace(/^mcp__/, ""), 96)}`);
45380
+ lines.push(`Item: ${truncate3(p.itemDisplayName, 256)}`);
45123
45381
  if (p.itemId !== "(new)") {
45124
- lines.push(`ID: ${truncate2(p.itemId, 96)}`);
45382
+ lines.push(`ID: ${truncate3(p.itemId, 96)}`);
45125
45383
  }
45126
- lines.push(`Account: ${truncate2(p.accountEmail, 96)}`);
45384
+ lines.push(`Account: ${truncate3(p.accountEmail, 96)}`);
45127
45385
  if (typeof p.sizeBytesBefore === "number" || typeof p.sizeBytesAfter === "number") {
45128
45386
  const before = p.sizeBytesBefore ?? 0;
45129
45387
  const after = p.sizeBytesAfter ?? 0;
@@ -45132,18 +45390,18 @@ function buildMs365CardText(p) {
45132
45390
  lines.push(`Size: ${humanBytes(before)} \u2192 ${humanBytes(after)} (${sign}${humanBytes(delta)})`);
45133
45391
  }
45134
45392
  if (p.deepLink) {
45135
- lines.push(`Link: ${truncate2(p.deepLink, 256)}`);
45393
+ lines.push(`Link: ${truncate3(p.deepLink, 256)}`);
45136
45394
  }
45137
45395
  if (p.agentRationale) {
45138
45396
  lines.push("");
45139
- lines.push(`\uD83D\uDCAC ${truncate2(p.agentRationale, 512)}`);
45397
+ lines.push(`\uD83D\uDCAC ${truncate3(p.agentRationale, 512)}`);
45140
45398
  }
45141
45399
  lines.push("");
45142
45400
  lines.push("\u26a0\ufe0f Weak attestation (RFC \u00a78 v1): operator should click through to verify the actual change before approving. Structural diff coming v1.5.");
45143
45401
  return lines.join(`
45144
45402
  `);
45145
45403
  }
45146
- function truncate2(s, n) {
45404
+ function truncate3(s, n) {
45147
45405
  if (s.length <= n)
45148
45406
  return s;
45149
45407
  return s.slice(0, n - 1) + "\u2026";
@@ -45259,9 +45517,9 @@ function buildDiffPreviewCard(input) {
45259
45517
  }
45260
45518
  const preview = input.preview;
45261
45519
  const bodyLines = [];
45262
- bodyLines.push(`<b>${escapeHtml7(preview.title)}</b>`);
45520
+ bodyLines.push(`<b>${escapeHtml8(preview.title)}</b>`);
45263
45521
  for (const line of preview.lines) {
45264
- bodyLines.push(escapeHtml7(line.text));
45522
+ bodyLines.push(escapeHtml8(line.text));
45265
45523
  }
45266
45524
  const text = bodyLines.join(`
45267
45525
  `);
@@ -45314,7 +45572,7 @@ function buildDiffPreviewCard(input) {
45314
45572
  }
45315
45573
  return { text, reply_markup: kb };
45316
45574
  }
45317
- function escapeHtml7(s) {
45575
+ function escapeHtml8(s) {
45318
45576
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
45319
45577
  }
45320
45578
 
@@ -46160,14 +46418,14 @@ function buildVaultSaveDiscardedInbound(opts) {
46160
46418
  // gateway/subagent-handback-inbound-builder.ts
46161
46419
  var HANDBACK_RESULT_MAX = 3000;
46162
46420
  var HANDBACK_DESC_MAX = 200;
46163
- function truncate3(s, max) {
46421
+ function truncate4(s, max) {
46164
46422
  const t = s.trim();
46165
46423
  return t.length > max ? t.slice(0, max) + "\u2026" : t;
46166
46424
  }
46167
46425
  function buildSubagentHandbackInbound(opts) {
46168
46426
  const ts = opts.nowMs ?? Date.now();
46169
- const desc = truncate3(opts.ctx.taskDescription, HANDBACK_DESC_MAX) || "(no description)";
46170
- const result = truncate3(opts.ctx.resultText, HANDBACK_RESULT_MAX);
46427
+ const desc = truncate4(opts.ctx.taskDescription, HANDBACK_DESC_MAX) || "(no description)";
46428
+ const result = truncate4(opts.ctx.resultText, HANDBACK_RESULT_MAX);
46171
46429
  const text = opts.ctx.outcome === "failed" ? `\uD83E\uDD1D A background worker you dispatched has FAILED.
46172
46430
 
46173
46431
  ` + `Task: ${desc}
@@ -46231,7 +46489,7 @@ function decideSubagentHandback(input) {
46231
46489
  var PROGRESS_RESULT_MAX = 800;
46232
46490
  var PROGRESS_DESC_MAX = 200;
46233
46491
  var DEFAULT_PROGRESS_INTERVAL_MS = 5 * 60 * 1000;
46234
- function truncate4(s, max) {
46492
+ function truncate5(s, max) {
46235
46493
  const t = s.trim();
46236
46494
  return t.length > max ? t.slice(0, max) + "\u2026" : t;
46237
46495
  }
@@ -46245,8 +46503,8 @@ function formatElapsed(ms) {
46245
46503
  }
46246
46504
  function buildSubagentProgressInbound(opts) {
46247
46505
  const ts = opts.nowMs ?? Date.now();
46248
- const desc = truncate4(opts.ctx.taskDescription, PROGRESS_DESC_MAX) || "(no description)";
46249
- const summary = truncate4(opts.ctx.latestSummary, PROGRESS_RESULT_MAX);
46506
+ const desc = truncate5(opts.ctx.taskDescription, PROGRESS_DESC_MAX) || "(no description)";
46507
+ const summary = truncate5(opts.ctx.latestSummary, PROGRESS_RESULT_MAX);
46250
46508
  const elapsed = formatElapsed(opts.ctx.elapsedMs);
46251
46509
  const expiresAt = ts + 2 * opts.ctx.progressIntervalMs;
46252
46510
  const text = `\uD83D\uDD04 A background worker you dispatched is still running.
@@ -47766,7 +48024,7 @@ function sanitiseToolArg(name, raw) {
47766
48024
  case "NotebookEdit": {
47767
48025
  const fp = raw.file_path;
47768
48026
  if (typeof fp === "string" && fp.length > 0)
47769
- out = basename3(fp);
48027
+ out = basename4(fp);
47770
48028
  break;
47771
48029
  }
47772
48030
  case "Bash": {
@@ -47802,7 +48060,7 @@ function sanitiseToolArg(name, raw) {
47802
48060
  out = out.slice(0, SANITISE_MAX_LEN - 1) + "\u2026";
47803
48061
  return out;
47804
48062
  }
47805
- function basename3(p) {
48063
+ function basename4(p) {
47806
48064
  const idx = p.lastIndexOf("/");
47807
48065
  return idx === -1 ? p : p.slice(idx + 1);
47808
48066
  }
@@ -48289,7 +48547,7 @@ function startSubagentWatcher(config) {
48289
48547
  if (idleMs >= threshold) {
48290
48548
  entry.stallNotified = true;
48291
48549
  entry.stalledAt = n;
48292
- const desc = escapeHtml8(truncate5(entry.description, 80));
48550
+ const desc = escapeHtml9(truncate6(entry.description, 80));
48293
48551
  const idleSec = Math.floor(idleMs / 1000);
48294
48552
  log?.(`subagent-watcher: stall detected for ${entry.agentId} (idle ${idleSec}s): ${desc}`);
48295
48553
  if (db2 != null) {
@@ -48763,7 +49021,7 @@ function renderIssuesCard(opts) {
48763
49021
  const maxSeverity = sorted[0].severity;
48764
49022
  const headerEmoji = SEVERITY_EMOJI[maxSeverity];
48765
49023
  const count = sorted.length;
48766
- const header = `${headerEmoji} <b>${escapeHtml8(opts.agentName)}</b> \u00b7 ${count} ${count === 1 ? "issue" : "issues"}`;
49024
+ const header = `${headerEmoji} <b>${escapeHtml9(opts.agentName)}</b> \u00b7 ${count} ${count === 1 ? "issue" : "issues"}`;
48767
49025
  const maxRows = opts.maxRows ?? DEFAULT_MAX_ROWS;
48768
49026
  const visible = sorted.slice(0, maxRows);
48769
49027
  const overflow = sorted.length - visible.length;
@@ -48772,10 +49030,10 @@ function renderIssuesCard(opts) {
48772
49030
  const emoji = SEVERITY_EMOJI[e.severity];
48773
49031
  const occ = e.occurrences > 1 ? ` <i>(\u00d7${e.occurrences})</i>` : "";
48774
49032
  const ago = relTime(now - e.last_seen);
48775
- const head = `${emoji} <code>${escapeHtml8(e.fingerprint)}</code> ${escapeHtml8(e.summary)}${occ} \u2014 <i>${ago}</i>`;
49033
+ const head = `${emoji} <code>${escapeHtml9(e.fingerprint)}</code> ${escapeHtml9(e.summary)}${occ} \u2014 <i>${ago}</i>`;
48776
49034
  const remediation = formatRemediation(e.detail);
48777
49035
  return remediation == null ? head : `${head}
48778
- \u2192 <i>${escapeHtml8(remediation)}</i>`;
49036
+ \u2192 <i>${escapeHtml9(remediation)}</i>`;
48779
49037
  });
48780
49038
  const lines = [header, "", ...rows];
48781
49039
  if (overflow > 0) {
@@ -49204,7 +49462,7 @@ function defaultReadEvents(stateDir) {
49204
49462
  return readAll(stateDir);
49205
49463
  }
49206
49464
  // permission-title.ts
49207
- import { basename as basename5 } from "node:path";
49465
+ import { basename as basename6 } from "node:path";
49208
49466
  var COMMAND_TITLE_MAX = 40;
49209
49467
  var PATH_TITLE_MAX = 40;
49210
49468
  var DESCRIPTION_LINE_MAX = 240;
@@ -49255,13 +49513,13 @@ function summarizeToolForTitle(toolName, inputPreview) {
49255
49513
  return `${toolName} (${skill})`;
49256
49514
  const command = readString(input, "command");
49257
49515
  if (command)
49258
- return `${toolName}: ${truncate6(command, COMMAND_TITLE_MAX)}`;
49516
+ return `${toolName}: ${truncate7(command, COMMAND_TITLE_MAX)}`;
49259
49517
  const argHint = firstScalarArgHint(input);
49260
49518
  return argHint ? `${toolName} (${argHint})` : toolName;
49261
49519
  }
49262
49520
  case "Bash": {
49263
49521
  const command = readString(input, "command");
49264
- return command ? `${toolName}: ${truncate6(command, COMMAND_TITLE_MAX)}` : toolName;
49522
+ return command ? `${toolName}: ${truncate7(command, COMMAND_TITLE_MAX)}` : toolName;
49265
49523
  }
49266
49524
  case "Read":
49267
49525
  case "Edit":
@@ -49269,17 +49527,17 @@ function summarizeToolForTitle(toolName, inputPreview) {
49269
49527
  case "MultiEdit":
49270
49528
  case "NotebookEdit": {
49271
49529
  const filePath = readString(input, "file_path") ?? readString(input, "notebook_path");
49272
- return filePath ? `${toolName}: ${truncate6(basename5(filePath), PATH_TITLE_MAX)}` : toolName;
49530
+ return filePath ? `${toolName}: ${truncate7(basename6(filePath), PATH_TITLE_MAX)}` : toolName;
49273
49531
  }
49274
49532
  case "Glob":
49275
49533
  case "Grep": {
49276
49534
  const pattern = readString(input, "pattern");
49277
- return pattern ? `${toolName}: ${truncate6(pattern, COMMAND_TITLE_MAX)}` : toolName;
49535
+ return pattern ? `${toolName}: ${truncate7(pattern, COMMAND_TITLE_MAX)}` : toolName;
49278
49536
  }
49279
49537
  case "WebFetch":
49280
49538
  case "WebSearch": {
49281
49539
  const query2 = readString(input, "url") ?? readString(input, "query");
49282
- return query2 ? `${toolName}: ${truncate6(query2, COMMAND_TITLE_MAX)}` : toolName;
49540
+ return query2 ? `${toolName}: ${truncate7(query2, COMMAND_TITLE_MAX)}` : toolName;
49283
49541
  }
49284
49542
  default:
49285
49543
  return toolName;
@@ -49318,7 +49576,7 @@ function firstScalarArgHint(input) {
49318
49576
  if (SKIP.has(key))
49319
49577
  continue;
49320
49578
  if (typeof value === "string" && value.length > 0) {
49321
- return `${key}: ${truncate6(value, INPUT_VALUE_MAX)}`;
49579
+ return `${key}: ${truncate7(value, INPUT_VALUE_MAX)}`;
49322
49580
  }
49323
49581
  if (typeof value === "number" || typeof value === "boolean") {
49324
49582
  return `${key}: ${String(value)}`;
@@ -49350,10 +49608,10 @@ function skillBasenameFromPath(input) {
49350
49608
  return null;
49351
49609
  const trimmed = path.replace(/\/SKILL\.md$/i, "").replace(/\/$/, "");
49352
49610
  const lastSlash = trimmed.lastIndexOf("/");
49353
- const basename6 = lastSlash >= 0 ? trimmed.slice(lastSlash + 1) : trimmed;
49354
- return basename6.length > 0 ? basename6 : null;
49611
+ const basename7 = lastSlash >= 0 ? trimmed.slice(lastSlash + 1) : trimmed;
49612
+ return basename7.length > 0 ? basename7 : null;
49355
49613
  }
49356
- function truncate6(text, max) {
49614
+ function truncate7(text, max) {
49357
49615
  const collapsed = text.replace(/\s+/g, " ").trim();
49358
49616
  if (collapsed.length <= max)
49359
49617
  return collapsed;
@@ -49361,7 +49619,7 @@ function truncate6(text, max) {
49361
49619
  }
49362
49620
 
49363
49621
  // permission-rule.ts
49364
- import { basename as basename6 } from "node:path";
49622
+ import { basename as basename7 } from "node:path";
49365
49623
  function resolveAlwaysAllowRule(toolName, inputPreview) {
49366
49624
  if (!toolName)
49367
49625
  return null;
@@ -49427,7 +49685,7 @@ function skillBasenameFromPath2(input) {
49427
49685
  if (!path)
49428
49686
  return null;
49429
49687
  const trimmed = path.replace(/\/SKILL\.md$/i, "").replace(/\/$/, "");
49430
- return basename6(trimmed) || null;
49688
+ return basename7(trimmed) || null;
49431
49689
  }
49432
49690
 
49433
49691
  // credits-watch.ts
@@ -49473,7 +49731,7 @@ function evaluateCreditState(args) {
49473
49731
  if (!currentIsFatal && prevIsFatal) {
49474
49732
  return {
49475
49733
  kind: "notify",
49476
- message: `\u2705 <b>${escapeHtml10(agentName3)}</b>: credits restored \u2014 agent should resume normal operation.`,
49734
+ message: `\u2705 <b>${escapeHtml11(agentName3)}</b>: credits restored \u2014 agent should resume normal operation.`,
49477
49735
  newState: { lastNotifiedReason: null, lastNotifiedAt: now },
49478
49736
  transition: "exited"
49479
49737
  };
@@ -49502,12 +49760,12 @@ function evaluateCreditState(args) {
49502
49760
  function buildEntryMessage(agentName3, reason) {
49503
49761
  const desc = humanizeReason(reason);
49504
49762
  return [
49505
- `\u26a0\ufe0f <b>${escapeHtml10(agentName3)}</b>: ${desc}`,
49763
+ `\u26a0\ufe0f <b>${escapeHtml11(agentName3)}</b>: ${desc}`,
49506
49764
  ``,
49507
49765
  `Cron tasks and inbound replies will fail until this is resolved. Check`,
49508
49766
  `your subscription or pre-paid usage at <a href="https://console.anthropic.com">console.anthropic.com</a>.`,
49509
49767
  ``,
49510
- `<i>Source: Claude CLI cache (cachedExtraUsageDisabledReason=${escapeHtml10(reason)})</i>`
49768
+ `<i>Source: Claude CLI cache (cachedExtraUsageDisabledReason=${escapeHtml11(reason)})</i>`
49511
49769
  ].join(`
49512
49770
  `);
49513
49771
  }
@@ -49525,7 +49783,7 @@ function humanizeReason(reason) {
49525
49783
  return `usage disabled (${reason})`;
49526
49784
  }
49527
49785
  }
49528
- function escapeHtml10(s) {
49786
+ function escapeHtml11(s) {
49529
49787
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
49530
49788
  }
49531
49789
  function loadCreditState(stateDir) {
@@ -49624,10 +49882,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
49624
49882
  }
49625
49883
 
49626
49884
  // ../src/build-info.ts
49627
- var VERSION = "0.13.56";
49628
- var COMMIT_SHA = "821a114e";
49629
- var COMMIT_DATE = "2026-05-27T20:20:37Z";
49630
- var LATEST_PR = 1923;
49885
+ var VERSION = "0.13.57";
49886
+ var COMMIT_SHA = "bed7cd14";
49887
+ var COMMIT_DATE = "2026-05-27T21:24:41Z";
49888
+ var LATEST_PR = 1925;
49631
49889
  var COMMITS_AHEAD_OF_TAG = 0;
49632
49890
 
49633
49891
  // gateway/boot-version.ts
@@ -51838,7 +52096,7 @@ ${reminder}
51838
52096
  noteSubagentDispatch(key);
51839
52097
  }
51840
52098
  if (ev.toolUseId != null && ev.toolUseId.length > 0 && !isTelegramSurfaceTool(ev.toolName)) {
51841
- const label = toolLabel(ev.toolName, ev.input, undefined, ev.precomputedLabel);
52099
+ const label = toolLabel2(ev.toolName, ev.input, undefined, ev.precomputedLabel);
51842
52100
  noteToolStart(key, ev.toolUseId, ev.toolName, label.length > 0 ? label : null, Date.now());
51843
52101
  const evInput = ev.input;
51844
52102
  if (ev.toolName === "Agent" || ev.toolName === "Task" || ev.toolName === "Bash" && evInput?.run_in_background === true) {
@@ -53634,6 +53892,7 @@ function handleSessionEvent(ev) {
53634
53892
  lastAssistantMsgId: null,
53635
53893
  lastAssistantDone: false,
53636
53894
  toolCallCount: 0,
53895
+ intentSurfaceFired: false,
53637
53896
  answerStream: null,
53638
53897
  isDm: isDmChatId(ev.chatId)
53639
53898
  };
@@ -53699,6 +53958,33 @@ function handleSessionEvent(ev) {
53699
53958
  turn.orphanedReplyTimeoutId = null;
53700
53959
  }
53701
53960
  }
53961
+ if (!turn.replyCalled && !turn.intentSurfaceFired && !isTelegramSurfaceTool(name)) {
53962
+ turn.intentSurfaceFired = true;
53963
+ const surface = deriveIntentSurface(name, ev.input, ev.precomputedLabel);
53964
+ if (surface.text != null) {
53965
+ try {
53966
+ markAckSent();
53967
+ } catch (err) {
53968
+ process.stderr.write(`telegram gateway: intent-surface markAckSent failed: ${err}
53969
+ `);
53970
+ }
53971
+ const surfaceChat = turn.sessionChatId;
53972
+ const surfaceThread = turn.sessionThreadId;
53973
+ const surfaceText = surface.text;
53974
+ (async () => {
53975
+ try {
53976
+ await robustApiCall(() => bot.api.sendMessage(surfaceChat, surfaceText, {
53977
+ ...surfaceThread != null ? { message_thread_id: surfaceThread } : {},
53978
+ parse_mode: "HTML",
53979
+ disable_notification: true
53980
+ }), { chat_id: surfaceChat, ...surfaceThread != null ? { threadId: surfaceThread } : {}, verb: "intent-surface" });
53981
+ } catch (err) {
53982
+ process.stderr.write(`telegram gateway: intent-surface send failed: ${err}
53983
+ `);
53984
+ }
53985
+ })();
53986
+ }
53987
+ }
53702
53988
  if (!ctrl)
53703
53989
  return;
53704
53990
  if (isTelegramSurfaceTool(name))
@@ -55053,7 +55339,7 @@ function getMyAgentName() {
55053
55339
  const fromEnv = process.env.SWITCHROOM_AGENT_NAME;
55054
55340
  if (fromEnv && fromEnv.trim().length > 0)
55055
55341
  return fromEnv.trim();
55056
- return basename7(process.cwd());
55342
+ return basename8(process.cwd());
55057
55343
  }
55058
55344
  function isSelfTargetingCommand(name) {
55059
55345
  if (name === "all")