switchroom 0.13.57 → 0.13.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/switchroom.js +2 -2
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +366 -456
- package/telegram-plugin/gateway/gateway.ts +196 -62
- package/telegram-plugin/tests/tool-activity-summary.test.ts +191 -0
- package/telegram-plugin/tool-activity-summary.ts +164 -0
- package/telegram-plugin/tests/tool-intent-surface.test.ts +0 -128
- package/telegram-plugin/tool-intent-surface.ts +0 -155
|
@@ -27779,15 +27779,15 @@ var init_secretlint_source = __esm(() => {
|
|
|
27779
27779
|
});
|
|
27780
27780
|
|
|
27781
27781
|
// card-format.ts
|
|
27782
|
-
function
|
|
27782
|
+
function escapeHtml8(s) {
|
|
27783
27783
|
return s.replace(/[&<>]/g, (c) => ({ "&": "&", "<": "<", ">": ">" })[c]);
|
|
27784
27784
|
}
|
|
27785
|
-
function
|
|
27785
|
+
function truncate5(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
|
|
27790
|
+
function escapeHtml9(s) {
|
|
27791
27791
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
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>${
|
|
27850
|
+
const labelHtml = `<code>${escapeHtml9(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
|
|
28862
|
-
return parts.map((p, i) => i % 2 === 0 ?
|
|
28861
|
+
return escapeHtml8(text);
|
|
28862
|
+
return parts.map((p, i) => i % 2 === 0 ? escapeHtml8(p) : `<code>${escapeHtml8(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>${
|
|
28868
|
+
const ack = `${ackEmoji} <b>${escapeHtml8(agentName3)}</b> back up \u00b7 ${escapeHtml8(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>${
|
|
28876
|
+
degradedRows.push(`\u2705 <b>${escapeHtml8(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> ${
|
|
28882
|
-
const tailCmd = process.env.SWITCHROOM_RUNTIME === "docker" ? `docker logs --tail 100 switchroom-${
|
|
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`;
|
|
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> ${
|
|
28895
|
+
degradedRows.push(`${dot} <b>${PROBE_LABELS[key]}</b> ${escapeHtml8(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
|
|
29610
|
+
function escapeHtml11(s) {
|
|
29611
29611
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
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>${
|
|
29622
|
-
` + `Reason: ${
|
|
29621
|
+
` + `Agent: <code>${escapeHtml11(args.agentName)}</code>
|
|
29622
|
+
` + `Reason: ${escapeHtml11(safeReason)}
|
|
29623
29623
|
|
|
29624
|
-
` + `<pre>${
|
|
29624
|
+
` + `<pre>${escapeHtml11(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
|
-
${
|
|
29732
|
-
${
|
|
29731
|
+
${escapeHtml11(msg.detail)}` : ""}` : `\u26a0\ufe0f <b>Reconcile failed; rolled back</b>${msg.detail ? `
|
|
29732
|
+
${escapeHtml11(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>${
|
|
30002
|
+
await ctx.reply(agentFilter ? `No active approvals for <code>${escapeHtml12(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>${
|
|
30008
|
+
const summary = Array.from(byAgent.entries()).map(([a, n]) => `\u2022 <b>${escapeHtml12(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>${
|
|
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)}`;
|
|
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>${
|
|
30038
|
+
await ctx.reply(ok ? `Revoked <code>${escapeHtml12(id)}</code>.` : `No such active decision <code>${escapeHtml12(id)}</code>.`, { parse_mode: "HTML" });
|
|
30039
30039
|
return;
|
|
30040
30040
|
}
|
|
30041
|
-
await ctx.reply(`Unknown subcommand <code>${
|
|
30041
|
+
await ctx.reply(`Unknown subcommand <code>${escapeHtml12(sub)}</code>. ` + `Use <code>/approvals list</code> or <code>/approvals revoke <id></code>. ` + `(<code>add</code> and <code>stats</code> are coming in a follow-up.)`, { parse_mode: "HTML" });
|
|
30042
30042
|
});
|
|
30043
30043
|
}
|
|
30044
|
-
function
|
|
30044
|
+
function escapeHtml12(s) {
|
|
30045
30045
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
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>${
|
|
30126
|
+
lines.push(`${marker}<code>${escapeHtml13(snap.label)}</code> <i>quota probe failed</i>`);
|
|
30127
30127
|
if (snap.quotaError) {
|
|
30128
|
-
lines.push(` <i>${
|
|
30128
|
+
lines.push(` <i>${escapeHtml13(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>${
|
|
30135
|
+
lines.push(`${marker}<code>${escapeHtml13(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 ${
|
|
30241
|
+
lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${escapeHtml13(input.oldLabel)}</b>`);
|
|
30242
30242
|
lines.push("");
|
|
30243
|
-
lines.push(`Triggered by: agent <b>${
|
|
30243
|
+
lines.push(`Triggered by: agent <b>${escapeHtml13(input.triggerAgent)}</b>`);
|
|
30244
30244
|
if (input.oldQuota) {
|
|
30245
30245
|
const recovery = recoveryAtFor2(input.oldQuota);
|
|
30246
30246
|
if (recovery) {
|
|
30247
|
-
lines.push(`${
|
|
30247
|
+
lines.push(`${escapeHtml13(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 ${
|
|
30255
|
+
lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${escapeHtml13(input.oldLabel)}</b>`);
|
|
30256
30256
|
lines.push("");
|
|
30257
|
-
lines.push(`<code>${
|
|
30258
|
-
lines.push(`Triggered by: agent <b>${
|
|
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>`);
|
|
30259
30259
|
lines.push("");
|
|
30260
30260
|
if (input.oldQuota) {
|
|
30261
30261
|
const recovery = recoveryAtFor2(input.oldQuota);
|
|
30262
30262
|
if (recovery) {
|
|
30263
|
-
lines.push(`<code>${
|
|
30263
|
+
lines.push(`<code>${escapeHtml13(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>${
|
|
30271
|
+
lines.push(`<code>${escapeHtml13(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
|
|
30330
|
+
function escapeHtml13(s) {
|
|
30331
30331
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
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
|
|
30514
|
+
import { join as join33, extname, sep as sep3, basename as basename7 } from "path";
|
|
30515
30515
|
|
|
30516
30516
|
// plugin-logger.ts
|
|
30517
30517
|
import { appendFileSync, mkdirSync, renameSync, statSync, existsSync } from "fs";
|
|
@@ -31559,6 +31559,109 @@ function isTelegramSurfaceTool(toolName) {
|
|
|
31559
31559
|
return suffix === "reply" || suffix === "stream_reply" || suffix === "edit_message" || suffix === "react";
|
|
31560
31560
|
}
|
|
31561
31561
|
|
|
31562
|
+
// draft-transport.ts
|
|
31563
|
+
var DRAFT_STREAM_STATE_KEY = Symbol.for("switchroom.draftStreamState");
|
|
31564
|
+
function getDraftStreamState() {
|
|
31565
|
+
const g = globalThis;
|
|
31566
|
+
let state = g[DRAFT_STREAM_STATE_KEY];
|
|
31567
|
+
if (!state) {
|
|
31568
|
+
state = { nextDraftId: 0 };
|
|
31569
|
+
g[DRAFT_STREAM_STATE_KEY] = state;
|
|
31570
|
+
}
|
|
31571
|
+
return state;
|
|
31572
|
+
}
|
|
31573
|
+
function allocateDraftId() {
|
|
31574
|
+
const state = getDraftStreamState();
|
|
31575
|
+
state.nextDraftId = state.nextDraftId >= 2147483647 ? 1 : state.nextDraftId + 1;
|
|
31576
|
+
return state.nextDraftId;
|
|
31577
|
+
}
|
|
31578
|
+
|
|
31579
|
+
// tool-activity-summary.ts
|
|
31580
|
+
var READ_VERBS = new Set(["read"]);
|
|
31581
|
+
var WRITE_VERBS = new Set(["wrote", "created", "edited"]);
|
|
31582
|
+
function makeEmptyActivityState() {
|
|
31583
|
+
return { counts: {}, order: [], firstToolName: null };
|
|
31584
|
+
}
|
|
31585
|
+
function verbForTool(toolName) {
|
|
31586
|
+
if (!toolName)
|
|
31587
|
+
return null;
|
|
31588
|
+
const mcpMatch = /^mcp__([^_]+)__(.+)$/.exec(toolName);
|
|
31589
|
+
if (mcpMatch && mcpMatch[1] === "switchroom-telegram")
|
|
31590
|
+
return null;
|
|
31591
|
+
const suffix = (mcpMatch ? mcpMatch[2] : toolName).toLowerCase();
|
|
31592
|
+
switch (suffix) {
|
|
31593
|
+
case "read":
|
|
31594
|
+
return "read";
|
|
31595
|
+
case "write":
|
|
31596
|
+
return "created";
|
|
31597
|
+
case "edit":
|
|
31598
|
+
case "multiedit":
|
|
31599
|
+
case "notebookedit":
|
|
31600
|
+
return "edited";
|
|
31601
|
+
case "bash":
|
|
31602
|
+
case "bashoutput":
|
|
31603
|
+
case "killshell":
|
|
31604
|
+
return "ran";
|
|
31605
|
+
case "websearch":
|
|
31606
|
+
case "grep":
|
|
31607
|
+
case "glob":
|
|
31608
|
+
return "searched";
|
|
31609
|
+
case "webfetch":
|
|
31610
|
+
return "fetched";
|
|
31611
|
+
case "task":
|
|
31612
|
+
case "agent":
|
|
31613
|
+
return "dispatched";
|
|
31614
|
+
case "todowrite":
|
|
31615
|
+
case "todoread":
|
|
31616
|
+
return "noted";
|
|
31617
|
+
default:
|
|
31618
|
+
return "used";
|
|
31619
|
+
}
|
|
31620
|
+
}
|
|
31621
|
+
function register(state, toolName) {
|
|
31622
|
+
const verb = verbForTool(toolName);
|
|
31623
|
+
if (!verb)
|
|
31624
|
+
return false;
|
|
31625
|
+
if (state.firstToolName == null)
|
|
31626
|
+
state.firstToolName = toolName;
|
|
31627
|
+
const prior = state.counts[verb] ?? 0;
|
|
31628
|
+
if (prior === 0)
|
|
31629
|
+
state.order.push(verb);
|
|
31630
|
+
state.counts[verb] = prior + 1;
|
|
31631
|
+
return true;
|
|
31632
|
+
}
|
|
31633
|
+
var VERB_PHRASE = {
|
|
31634
|
+
read: { singular: "read a file", plural: "read $N files" },
|
|
31635
|
+
edited: { singular: "edited a file", plural: "edited $N files" },
|
|
31636
|
+
created: { singular: "created a file", plural: "created $N files" },
|
|
31637
|
+
ran: { singular: "ran a command", plural: "ran $N commands" },
|
|
31638
|
+
searched: { singular: "ran a search", plural: "ran $N searches" },
|
|
31639
|
+
fetched: { singular: "fetched a URL", plural: "fetched $N URLs" },
|
|
31640
|
+
dispatched: { singular: "dispatched a sub-agent", plural: "dispatched $N sub-agents" },
|
|
31641
|
+
noted: { singular: "updated the todo list", plural: "updated the todo list ($N edits)" },
|
|
31642
|
+
used: { singular: "used a tool", plural: "used $N tools" }
|
|
31643
|
+
};
|
|
31644
|
+
function formatSummary(state) {
|
|
31645
|
+
const phrases = [];
|
|
31646
|
+
for (const verb of state.order) {
|
|
31647
|
+
const n = state.counts[verb] ?? 0;
|
|
31648
|
+
if (n <= 0)
|
|
31649
|
+
continue;
|
|
31650
|
+
const p = VERB_PHRASE[verb];
|
|
31651
|
+
phrases.push(n === 1 ? p.singular : p.plural.replace("$N", String(n)));
|
|
31652
|
+
}
|
|
31653
|
+
if (phrases.length === 0)
|
|
31654
|
+
return null;
|
|
31655
|
+
const sentence = phrases.join(", ");
|
|
31656
|
+
return sentence.charAt(0).toUpperCase() + sentence.slice(1);
|
|
31657
|
+
}
|
|
31658
|
+
function registerAndRender(state, toolName) {
|
|
31659
|
+
const changed = register(state, toolName);
|
|
31660
|
+
if (!changed)
|
|
31661
|
+
return null;
|
|
31662
|
+
return formatSummary(state);
|
|
31663
|
+
}
|
|
31664
|
+
|
|
31562
31665
|
// tool-labels.ts
|
|
31563
31666
|
var MAX_LABEL_CHARS = 60;
|
|
31564
31667
|
var MAX_BASH_CHARS = 40;
|
|
@@ -31755,264 +31858,6 @@ function prettifyServer(name) {
|
|
|
31755
31858
|
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
31756
31859
|
}
|
|
31757
31860
|
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
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
|
-
|
|
32016
31861
|
// gateway/chat-key.ts
|
|
32017
31862
|
function chatKey(chatId, threadId) {
|
|
32018
31863
|
const t = threadId == null || threadId === 0 ? "_" : String(threadId);
|
|
@@ -32121,18 +31966,18 @@ function isDraft429(err) {
|
|
|
32121
31966
|
const text = typeof err === "string" ? err : err instanceof Error ? err.message : typeof err === "object" && err != null && ("description" in err) ? typeof err.description === "string" ? err.description : "" : "";
|
|
32122
31967
|
return /sendMessageDraft/i.test(text);
|
|
32123
31968
|
}
|
|
32124
|
-
var
|
|
32125
|
-
function
|
|
31969
|
+
var DRAFT_STREAM_STATE_KEY2 = Symbol.for("switchroom.draftStreamState");
|
|
31970
|
+
function getDraftStreamState2() {
|
|
32126
31971
|
const g = globalThis;
|
|
32127
|
-
let state = g[
|
|
31972
|
+
let state = g[DRAFT_STREAM_STATE_KEY2];
|
|
32128
31973
|
if (!state) {
|
|
32129
31974
|
state = { nextDraftId: 0 };
|
|
32130
|
-
g[
|
|
31975
|
+
g[DRAFT_STREAM_STATE_KEY2] = state;
|
|
32131
31976
|
}
|
|
32132
31977
|
return state;
|
|
32133
31978
|
}
|
|
32134
|
-
function
|
|
32135
|
-
const state =
|
|
31979
|
+
function allocateDraftId2() {
|
|
31980
|
+
const state = getDraftStreamState2();
|
|
32136
31981
|
state.nextDraftId = state.nextDraftId >= 2147483647 ? 1 : state.nextDraftId + 1;
|
|
32137
31982
|
return state.nextDraftId;
|
|
32138
31983
|
}
|
|
@@ -32162,7 +32007,7 @@ function createDraftStream(send, edit, config = {}) {
|
|
|
32162
32007
|
warn?.('draft-stream: previewTransport="auto" with sendMessageDraft but isPrivateChat undefined \u2014 defaulting to message transport');
|
|
32163
32008
|
}
|
|
32164
32009
|
let usesDraftTransport = prefersDraft && draftApi != null;
|
|
32165
|
-
let draftId = usesDraftTransport ?
|
|
32010
|
+
let draftId = usesDraftTransport ? allocateDraftId2() : undefined;
|
|
32166
32011
|
if (prefersDraft && !usesDraftTransport) {
|
|
32167
32012
|
warn?.("draft-stream: sendMessageDraft unavailable; falling back to sendMessage/editMessageText");
|
|
32168
32013
|
}
|
|
@@ -32270,7 +32115,7 @@ function createDraftStream(send, edit, config = {}) {
|
|
|
32270
32115
|
const newMsgId = await send(chunk);
|
|
32271
32116
|
messageId = newMsgId;
|
|
32272
32117
|
persistedTextLen = textToSend.length;
|
|
32273
|
-
draftId =
|
|
32118
|
+
draftId = allocateDraftId2();
|
|
32274
32119
|
currentChunkStartedAt = null;
|
|
32275
32120
|
persistChainFires++;
|
|
32276
32121
|
sendFires++;
|
|
@@ -33145,7 +32990,7 @@ function installTgPostLogger(bot) {
|
|
|
33145
32990
|
}
|
|
33146
32991
|
|
|
33147
32992
|
// attachment-path.ts
|
|
33148
|
-
import { join as join2, basename as
|
|
32993
|
+
import { join as join2, basename as basename2, resolve, sep } from "node:path";
|
|
33149
32994
|
function sanitizeExtension(ext) {
|
|
33150
32995
|
if (ext == null)
|
|
33151
32996
|
return "bin";
|
|
@@ -33174,7 +33019,7 @@ function assertInsideInbox(inboxDir, candidatePath) {
|
|
|
33174
33019
|
const inboxReal = resolve(inboxDir);
|
|
33175
33020
|
const candidateReal = resolve(candidatePath);
|
|
33176
33021
|
if (candidateReal !== inboxReal && !candidateReal.startsWith(inboxReal + sep)) {
|
|
33177
|
-
throw new Error(`attachment path escape: ${
|
|
33022
|
+
throw new Error(`attachment path escape: ${basename2(candidatePath)} resolved outside ${inboxDir}`);
|
|
33178
33023
|
}
|
|
33179
33024
|
}
|
|
33180
33025
|
|
|
@@ -38586,7 +38431,7 @@ function isSilentFlushMarker(text) {
|
|
|
38586
38431
|
var MIN_INITIAL_CHARS = 50;
|
|
38587
38432
|
var DEFAULT_THROTTLE_MS = 1000;
|
|
38588
38433
|
var TELEGRAM_MAX_CHARS2 = 4096;
|
|
38589
|
-
var
|
|
38434
|
+
var allocateDraftId3 = allocateDraftId2;
|
|
38590
38435
|
function createAnswerStream(config) {
|
|
38591
38436
|
const {
|
|
38592
38437
|
chatId,
|
|
@@ -38609,7 +38454,7 @@ function createAnswerStream(config) {
|
|
|
38609
38454
|
const effectiveThrottle = Math.max(250, throttleMs);
|
|
38610
38455
|
const preferDraft = isPrivateChat && draftApi != null;
|
|
38611
38456
|
let usesDraftTransport = preferDraft;
|
|
38612
|
-
let draftId = preferDraft ?
|
|
38457
|
+
let draftId = preferDraft ? allocateDraftId3() : undefined;
|
|
38613
38458
|
let streamMsgId;
|
|
38614
38459
|
let pendingText = null;
|
|
38615
38460
|
let lastSentText = "";
|
|
@@ -38858,7 +38703,7 @@ function createAnswerStream(config) {
|
|
|
38858
38703
|
if (staleDraftId != null) {
|
|
38859
38704
|
clearDraftBestEffort(staleDraftId);
|
|
38860
38705
|
}
|
|
38861
|
-
draftId =
|
|
38706
|
+
draftId = allocateDraftId3();
|
|
38862
38707
|
}
|
|
38863
38708
|
log?.(`answer-stream: forceNewMessage (gen=${generation})`);
|
|
38864
38709
|
},
|
|
@@ -39064,16 +38909,16 @@ function renderAccountRow(snap, opts) {
|
|
|
39064
38909
|
const lines = [];
|
|
39065
38910
|
const marker = snap.isActive ? "\u25cf " : "";
|
|
39066
38911
|
if (!snap.quota) {
|
|
39067
|
-
lines.push(`${marker}<code>${
|
|
38912
|
+
lines.push(`${marker}<code>${escapeHtml(snap.label)}</code> <i>quota probe failed</i>`);
|
|
39068
38913
|
if (snap.quotaError) {
|
|
39069
|
-
lines.push(` <i>${
|
|
38914
|
+
lines.push(` <i>${escapeHtml(snap.quotaError)}</i>`);
|
|
39070
38915
|
}
|
|
39071
38916
|
return lines;
|
|
39072
38917
|
}
|
|
39073
38918
|
const q = snap.quota;
|
|
39074
38919
|
const fiveStr = fmtPct(q.fiveHourUtilizationPct);
|
|
39075
38920
|
const sevenStr = fmtPct(q.sevenDayUtilizationPct);
|
|
39076
|
-
lines.push(`${marker}<code>${
|
|
38921
|
+
lines.push(`${marker}<code>${escapeHtml(snap.label)}</code> ${fiveStr} / ${sevenStr}`);
|
|
39077
38922
|
const health = classifyHealth(snap);
|
|
39078
38923
|
if (health === "blocked") {
|
|
39079
38924
|
const win = bindingWindow(q);
|
|
@@ -39179,13 +39024,13 @@ function renderFallbackAnnouncement(input) {
|
|
|
39179
39024
|
const limitWord = input.oldQuota ? limitWordFor(input.oldQuota) : "quota";
|
|
39180
39025
|
const headerLimit = limitWord === "quota" ? "quota cap" : `${limitWord} limit`;
|
|
39181
39026
|
if (!input.newLabel) {
|
|
39182
|
-
lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${
|
|
39027
|
+
lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${escapeHtml(input.oldLabel)}</b>`);
|
|
39183
39028
|
lines.push("");
|
|
39184
|
-
lines.push(`Triggered by: agent <b>${
|
|
39029
|
+
lines.push(`Triggered by: agent <b>${escapeHtml(input.triggerAgent)}</b>`);
|
|
39185
39030
|
if (input.oldQuota) {
|
|
39186
39031
|
const recovery = recoveryAtFor(input.oldQuota);
|
|
39187
39032
|
if (recovery) {
|
|
39188
|
-
lines.push(`${
|
|
39033
|
+
lines.push(`${escapeHtml(input.oldLabel)} recovers ${formatAbsolute(recovery, tz)} ` + `(in ${formatRelative(recovery, now)})`);
|
|
39189
39034
|
}
|
|
39190
39035
|
}
|
|
39191
39036
|
lines.push("");
|
|
@@ -39193,15 +39038,15 @@ function renderFallbackAnnouncement(input) {
|
|
|
39193
39038
|
return lines.join(`
|
|
39194
39039
|
`);
|
|
39195
39040
|
}
|
|
39196
|
-
lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${
|
|
39041
|
+
lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${escapeHtml(input.oldLabel)}</b>`);
|
|
39197
39042
|
lines.push("");
|
|
39198
|
-
lines.push(`<code>${
|
|
39199
|
-
lines.push(`Triggered by: agent <b>${
|
|
39043
|
+
lines.push(`<code>${escapeHtml(input.oldLabel)}</code> \u2192 <code>${escapeHtml(input.newLabel)}</code>`);
|
|
39044
|
+
lines.push(`Triggered by: agent <b>${escapeHtml(input.triggerAgent)}</b>`);
|
|
39200
39045
|
lines.push("");
|
|
39201
39046
|
if (input.oldQuota) {
|
|
39202
39047
|
const recovery = recoveryAtFor(input.oldQuota);
|
|
39203
39048
|
if (recovery) {
|
|
39204
|
-
lines.push(`<code>${
|
|
39049
|
+
lines.push(`<code>${escapeHtml(input.oldLabel)}</code> recovers ` + `${formatAbsolute(recovery, tz)} (in ${formatRelative(recovery, now)})`);
|
|
39205
39050
|
}
|
|
39206
39051
|
}
|
|
39207
39052
|
if (input.newQuota) {
|
|
@@ -39209,7 +39054,7 @@ function renderFallbackAnnouncement(input) {
|
|
|
39209
39054
|
const sevenStr = fmtPct(input.newQuota.sevenDayUtilizationPct);
|
|
39210
39055
|
const hasHeadroom = input.newQuota.fiveHourUtilizationPct < THROTTLING_THRESHOLD_PCT && input.newQuota.sevenDayUtilizationPct < THROTTLING_THRESHOLD_PCT;
|
|
39211
39056
|
const headroomStr = hasHeadroom ? "<i>(plenty of headroom)</i>" : "<i>(near limit \u2014 watch this)</i>";
|
|
39212
|
-
lines.push(`<code>${
|
|
39057
|
+
lines.push(`<code>${escapeHtml(input.newLabel)}</code> now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
|
|
39213
39058
|
} else {
|
|
39214
39059
|
lines.push(`<i>(quota probe for new account is pending \u2014 will reflect on next /auth)</i>`);
|
|
39215
39060
|
}
|
|
@@ -39268,7 +39113,7 @@ function switchPriority(s) {
|
|
|
39268
39113
|
return 2;
|
|
39269
39114
|
return 3;
|
|
39270
39115
|
}
|
|
39271
|
-
function
|
|
39116
|
+
function escapeHtml(s) {
|
|
39272
39117
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
39273
39118
|
}
|
|
39274
39119
|
function buildSnapshotsFromState(state3, quotas) {
|
|
@@ -39361,7 +39206,7 @@ function parseAuthCommand(text) {
|
|
|
39361
39206
|
if (tail.length > 0) {
|
|
39362
39207
|
return {
|
|
39363
39208
|
kind: "help",
|
|
39364
|
-
reason: `Unknown <code>rm</code> modifier: <code>${
|
|
39209
|
+
reason: `Unknown <code>rm</code> modifier: <code>${escapeHtml2(tail)}</code>. Use <code>/auth rm <label> confirm</code> to confirm.`
|
|
39365
39210
|
};
|
|
39366
39211
|
}
|
|
39367
39212
|
return { kind: "rm-prompt", label };
|
|
@@ -39381,7 +39226,7 @@ function parseAuthCommand(text) {
|
|
|
39381
39226
|
if (sub !== "override") {
|
|
39382
39227
|
return {
|
|
39383
39228
|
kind: "help",
|
|
39384
|
-
reason: `Unknown <code>agent</code> subcommand: <code>${
|
|
39229
|
+
reason: `Unknown <code>agent</code> subcommand: <code>${escapeHtml2(sub || "(none)")}</code>. Try <code>/auth agent override <agent> <label|clear></code>.`
|
|
39385
39230
|
};
|
|
39386
39231
|
}
|
|
39387
39232
|
const agent = parts[2];
|
|
@@ -39403,7 +39248,7 @@ function parseAuthCommand(text) {
|
|
|
39403
39248
|
case "help":
|
|
39404
39249
|
return { kind: "help" };
|
|
39405
39250
|
default:
|
|
39406
|
-
return { kind: "help", reason: `Unknown verb: <code>${
|
|
39251
|
+
return { kind: "help", reason: `Unknown verb: <code>${escapeHtml2(verb)}</code>` };
|
|
39407
39252
|
}
|
|
39408
39253
|
}
|
|
39409
39254
|
async function handleAuthCommand(parsed, ctx) {
|
|
@@ -39457,7 +39302,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39457
39302
|
};
|
|
39458
39303
|
} catch (err) {
|
|
39459
39304
|
return {
|
|
39460
|
-
text: `<b>/auth show failed:</b> ${
|
|
39305
|
+
text: `<b>/auth show failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39461
39306
|
html: true
|
|
39462
39307
|
};
|
|
39463
39308
|
}
|
|
@@ -39469,7 +39314,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39469
39314
|
const agent = state3.agents.find((a) => a.name === agentName3);
|
|
39470
39315
|
if (!agent) {
|
|
39471
39316
|
return {
|
|
39472
|
-
text: `<b>/auth show:</b> no agent named <code>${
|
|
39317
|
+
text: `<b>/auth show:</b> no agent named <code>${escapeHtml2(agentName3)}</code> in broker view.
|
|
39473
39318
|
` + `Run <code>/auth show</code> for the fleet snapshot.`,
|
|
39474
39319
|
html: true
|
|
39475
39320
|
};
|
|
@@ -39477,7 +39322,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39477
39322
|
return { text: renderAgentDetail(state3, agent), html: true };
|
|
39478
39323
|
} catch (err) {
|
|
39479
39324
|
return {
|
|
39480
|
-
text: `<b>/auth show failed:</b> ${
|
|
39325
|
+
text: `<b>/auth show failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39481
39326
|
html: true
|
|
39482
39327
|
};
|
|
39483
39328
|
}
|
|
@@ -39499,13 +39344,13 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39499
39344
|
try {
|
|
39500
39345
|
const result = await ctx.client.setActive(parsed.label);
|
|
39501
39346
|
return {
|
|
39502
|
-
text: `<b>Active account \u2192</b> <code>${
|
|
39347
|
+
text: `<b>Active account \u2192</b> <code>${escapeHtml2(result.active)}</code>
|
|
39503
39348
|
` + `Re-mirrored credentials for ${result.fanned.length} agent${result.fanned.length === 1 ? "" : "s"}.`,
|
|
39504
39349
|
html: true
|
|
39505
39350
|
};
|
|
39506
39351
|
} catch (err) {
|
|
39507
39352
|
return {
|
|
39508
|
-
text: `<b>/auth use failed:</b> ${
|
|
39353
|
+
text: `<b>/auth use failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39509
39354
|
html: true
|
|
39510
39355
|
};
|
|
39511
39356
|
}
|
|
@@ -39523,13 +39368,13 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39523
39368
|
}
|
|
39524
39369
|
const result = await ctx.client.setActive(nextLabel);
|
|
39525
39370
|
return {
|
|
39526
|
-
text: `<b>Rotated:</b> active \u2192 <code>${
|
|
39371
|
+
text: `<b>Rotated:</b> active \u2192 <code>${escapeHtml2(result.active)}</code>
|
|
39527
39372
|
` + `Re-mirrored credentials for ${result.fanned.length} agent${result.fanned.length === 1 ? "" : "s"}.`,
|
|
39528
39373
|
html: true
|
|
39529
39374
|
};
|
|
39530
39375
|
} catch (err) {
|
|
39531
39376
|
return {
|
|
39532
|
-
text: `<b>/auth rotate failed:</b> ${
|
|
39377
|
+
text: `<b>/auth rotate failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39533
39378
|
html: true
|
|
39534
39379
|
};
|
|
39535
39380
|
}
|
|
@@ -39540,20 +39385,20 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39540
39385
|
state3 = await ctx.client.listState();
|
|
39541
39386
|
} catch (err) {
|
|
39542
39387
|
return {
|
|
39543
|
-
text: `<b>/auth rm failed:</b> ${
|
|
39388
|
+
text: `<b>/auth rm failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39544
39389
|
html: true
|
|
39545
39390
|
};
|
|
39546
39391
|
}
|
|
39547
39392
|
const exists = state3.accounts.some((a) => a.label === parsed.label);
|
|
39548
39393
|
if (!exists) {
|
|
39549
39394
|
return {
|
|
39550
|
-
text: `<b>/auth rm:</b> no account named <code>${
|
|
39395
|
+
text: `<b>/auth rm:</b> no account named <code>${escapeHtml2(parsed.label)}</code>. ` + `Run <code>/auth show</code> for the current list.`,
|
|
39551
39396
|
html: true
|
|
39552
39397
|
};
|
|
39553
39398
|
}
|
|
39554
39399
|
if (state3.active === parsed.label) {
|
|
39555
39400
|
return {
|
|
39556
|
-
text: `<b>/auth rm refused.</b> <code>${
|
|
39401
|
+
text: `<b>/auth rm refused.</b> <code>${escapeHtml2(parsed.label)}</code> is the fleet active. ` + `Switch with <code>/auth use <other></code> or <code>/auth rotate</code> first.`,
|
|
39557
39402
|
html: true
|
|
39558
39403
|
};
|
|
39559
39404
|
}
|
|
@@ -39564,10 +39409,10 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39564
39409
|
});
|
|
39565
39410
|
}
|
|
39566
39411
|
return {
|
|
39567
|
-
text: `<b>\u26a0 /auth rm</b> \u2014 about to remove <code>${
|
|
39568
|
-
` + `The fleet active is unchanged. Any agent override pointing at <code>${
|
|
39412
|
+
text: `<b>\u26a0 /auth rm</b> \u2014 about to remove <code>${escapeHtml2(parsed.label)}</code> from the broker.
|
|
39413
|
+
` + `The fleet active is unchanged. Any agent override pointing at <code>${escapeHtml2(parsed.label)}</code> will stop working.
|
|
39569
39414
|
|
|
39570
|
-
` + `Send <code>/auth rm ${
|
|
39415
|
+
` + `Send <code>/auth rm ${escapeHtml2(parsed.label)} confirm</code> within ${Math.round(AUTH_RM_CONFIRM_TTL_MS / 1000)}s to proceed.`,
|
|
39571
39416
|
html: true
|
|
39572
39417
|
};
|
|
39573
39418
|
}
|
|
@@ -39579,7 +39424,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39579
39424
|
pendingAuthRmFlows.delete(ctx.chatId);
|
|
39580
39425
|
}
|
|
39581
39426
|
return {
|
|
39582
|
-
text: `<b>/auth rm:</b> no pending confirm for <code>${
|
|
39427
|
+
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.`,
|
|
39583
39428
|
html: true
|
|
39584
39429
|
};
|
|
39585
39430
|
}
|
|
@@ -39588,12 +39433,12 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39588
39433
|
try {
|
|
39589
39434
|
const data = await ctx.client.rmAccount(parsed.label);
|
|
39590
39435
|
return {
|
|
39591
|
-
text: `<b>Removed</b> <code>${
|
|
39436
|
+
text: `<b>Removed</b> <code>${escapeHtml2(data.label)}</code> from the broker.`,
|
|
39592
39437
|
html: true
|
|
39593
39438
|
};
|
|
39594
39439
|
} catch (err) {
|
|
39595
39440
|
return {
|
|
39596
|
-
text: `<b>/auth rm failed:</b> ${
|
|
39441
|
+
text: `<b>/auth rm failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39597
39442
|
html: true
|
|
39598
39443
|
};
|
|
39599
39444
|
}
|
|
@@ -39604,7 +39449,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39604
39449
|
const targets = parsed.label ? state3.accounts.filter((a) => a.label === parsed.label).map((a) => a.label) : state3.accounts.map((a) => a.label);
|
|
39605
39450
|
if (parsed.label && targets.length === 0) {
|
|
39606
39451
|
return {
|
|
39607
|
-
text: `<b>/auth refresh:</b> no account named <code>${
|
|
39452
|
+
text: `<b>/auth refresh:</b> no account named <code>${escapeHtml2(parsed.label)}</code>.`,
|
|
39608
39453
|
html: true
|
|
39609
39454
|
};
|
|
39610
39455
|
}
|
|
@@ -39623,10 +39468,10 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39623
39468
|
formatExpiryAbs(data.expiresAt)
|
|
39624
39469
|
]);
|
|
39625
39470
|
} catch (err) {
|
|
39626
|
-
failures.push(`${label}: ${
|
|
39471
|
+
failures.push(`${label}: ${escapeHtml2(err?.message ?? String(err))}`);
|
|
39627
39472
|
}
|
|
39628
39473
|
}
|
|
39629
|
-
const head = targets.length === 1 ? `<b>Refreshed</b> <code>${
|
|
39474
|
+
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"}`;
|
|
39630
39475
|
const table = rows.length > 1 ? `
|
|
39631
39476
|
<pre>${alignTable(rows)}</pre>` : "";
|
|
39632
39477
|
const failBlock = failures.length > 0 ? `
|
|
@@ -39636,7 +39481,7 @@ ${failures.map((f) => ` ${f}`).join(`
|
|
|
39636
39481
|
return { text: head + table + failBlock, html: true };
|
|
39637
39482
|
} catch (err) {
|
|
39638
39483
|
return {
|
|
39639
|
-
text: `<b>/auth refresh failed:</b> ${
|
|
39484
|
+
text: `<b>/auth refresh failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39640
39485
|
html: true
|
|
39641
39486
|
};
|
|
39642
39487
|
}
|
|
@@ -39645,12 +39490,12 @@ ${failures.map((f) => ` ${f}`).join(`
|
|
|
39645
39490
|
try {
|
|
39646
39491
|
const data = await ctx.client.setOverride(parsed.agent, parsed.label);
|
|
39647
39492
|
return {
|
|
39648
|
-
text: `<b>Override set.</b> <code>${
|
|
39493
|
+
text: `<b>Override set.</b> <code>${escapeHtml2(data.agent)}</code> is now pinned to ` + `<code>${escapeHtml2(data.account ?? parsed.label)}</code>.`,
|
|
39649
39494
|
html: true
|
|
39650
39495
|
};
|
|
39651
39496
|
} catch (err) {
|
|
39652
39497
|
return {
|
|
39653
|
-
text: `<b>/auth agent override failed:</b> ${
|
|
39498
|
+
text: `<b>/auth agent override failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39654
39499
|
html: true
|
|
39655
39500
|
};
|
|
39656
39501
|
}
|
|
@@ -39659,12 +39504,12 @@ ${failures.map((f) => ` ${f}`).join(`
|
|
|
39659
39504
|
try {
|
|
39660
39505
|
const data = await ctx.client.setOverride(parsed.agent, null);
|
|
39661
39506
|
return {
|
|
39662
|
-
text: `<b>Override cleared</b> on <code>${
|
|
39507
|
+
text: `<b>Override cleared</b> on <code>${escapeHtml2(data.agent)}</code> ` + `\u2014 back to fleet active.`,
|
|
39663
39508
|
html: true
|
|
39664
39509
|
};
|
|
39665
39510
|
} catch (err) {
|
|
39666
39511
|
return {
|
|
39667
|
-
text: `<b>/auth agent override failed:</b> ${
|
|
39512
|
+
text: `<b>/auth agent override failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39668
39513
|
html: true
|
|
39669
39514
|
};
|
|
39670
39515
|
}
|
|
@@ -39743,7 +39588,7 @@ function formatAccountsTable(state3, now) {
|
|
|
39743
39588
|
const status = isActive ? "active" : acc.exhausted ? "exhausted" : "available";
|
|
39744
39589
|
const expires = acc.expiresAt != null ? formatRelativeMs(acc.expiresAt - now) : "\u2014";
|
|
39745
39590
|
const quotaReset = acc.exhausted && acc.exhausted_until != null && acc.exhausted_until > now ? formatRelativeMs(acc.exhausted_until - now) : "\u2014";
|
|
39746
|
-
rows.push([`${marker} ${
|
|
39591
|
+
rows.push([`${marker} ${escapeHtml2(acc.label)}`, status, expires, quotaReset]);
|
|
39747
39592
|
}
|
|
39748
39593
|
return alignTable(rows);
|
|
39749
39594
|
}
|
|
@@ -39751,15 +39596,15 @@ function formatAgentsTable(state3) {
|
|
|
39751
39596
|
const rows = [["AGENT", "ACTIVE", "SOURCE"]];
|
|
39752
39597
|
for (const a of state3.agents) {
|
|
39753
39598
|
const source = a.override ? "override" : a.account === state3.active ? "fleet-active" : "pinned";
|
|
39754
|
-
rows.push([
|
|
39599
|
+
rows.push([escapeHtml2(a.name), escapeHtml2(a.account), source]);
|
|
39755
39600
|
}
|
|
39756
39601
|
return alignTable(rows);
|
|
39757
39602
|
}
|
|
39758
39603
|
function renderAgentDetail(state3, agent, now = Date.now()) {
|
|
39759
39604
|
const lines = [];
|
|
39760
|
-
lines.push(`<b>${
|
|
39605
|
+
lines.push(`<b>${escapeHtml2(agent.name)}</b>`);
|
|
39761
39606
|
const source = agent.override ? "override" : "fleet-active";
|
|
39762
|
-
lines.push(`Active account: <code>${
|
|
39607
|
+
lines.push(`Active account: <code>${escapeHtml2(agent.account)}</code> (${source})`);
|
|
39763
39608
|
const acct = state3.accounts.find((a) => a.label === agent.account);
|
|
39764
39609
|
if (acct) {
|
|
39765
39610
|
const expRel = acct.expiresAt != null ? formatRelativeMs(acct.expiresAt - now) : "\u2014";
|
|
@@ -39782,11 +39627,11 @@ function formatConsumersTable(state3, now) {
|
|
|
39782
39627
|
const rows = [["CONSUMER", "ACTIVE", "STATUS"]];
|
|
39783
39628
|
for (const c of state3.consumers) {
|
|
39784
39629
|
const status = c.last_seen_at == null ? "socket bound" : `socket bound (last seen ${formatRelativeMs(now - c.last_seen_at)} ago)`;
|
|
39785
|
-
rows.push([
|
|
39630
|
+
rows.push([escapeHtml2(c.name), escapeHtml2(c.account), status]);
|
|
39786
39631
|
}
|
|
39787
39632
|
return alignTable(rows);
|
|
39788
39633
|
}
|
|
39789
|
-
function
|
|
39634
|
+
function escapeHtml2(s) {
|
|
39790
39635
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
39791
39636
|
}
|
|
39792
39637
|
function formatRelativeMs(ms) {
|
|
@@ -41101,11 +40946,11 @@ function renderTable(headers, rows) {
|
|
|
41101
40946
|
if (colCount <= 3 && rowCount <= 6) {
|
|
41102
40947
|
const bullets = rows.map((row) => {
|
|
41103
40948
|
const cells = headers.map((_, i) => (row[i] ?? "").trim());
|
|
41104
|
-
const key =
|
|
41105
|
-
const rest = cells.slice(1).filter((v) => v !== "").map((v) => ` \u2014 ${
|
|
40949
|
+
const key = escapeHtml4(cells[0] || "\u2014");
|
|
40950
|
+
const rest = cells.slice(1).filter((v) => v !== "").map((v) => ` \u2014 ${escapeHtml4(v)}`).join("");
|
|
41106
40951
|
return `\u2022 <b>${key}</b>${rest}`;
|
|
41107
40952
|
});
|
|
41108
|
-
const headerLine = colCount >= 2 ? `<b>${headers.map((h) =>
|
|
40953
|
+
const headerLine = colCount >= 2 ? `<b>${headers.map((h) => escapeHtml4(h)).join(" / ")}</b>
|
|
41109
40954
|
` : "";
|
|
41110
40955
|
return headerLine + bullets.join(`
|
|
41111
40956
|
`);
|
|
@@ -41120,7 +40965,7 @@ function renderTable(headers, rows) {
|
|
|
41120
40965
|
sepLine,
|
|
41121
40966
|
...rows.map((r) => formatRow(r))
|
|
41122
40967
|
];
|
|
41123
|
-
return `<pre>${
|
|
40968
|
+
return `<pre>${escapeHtml4(lines.join(`
|
|
41124
40969
|
`))}</pre>`;
|
|
41125
40970
|
}
|
|
41126
40971
|
function extractMarkdownTables(text, store2, placeholderPrefix) {
|
|
@@ -41168,7 +41013,7 @@ function markdownToHtml(text) {
|
|
|
41168
41013
|
const INLINE_PH = "\x00CODEINLINE";
|
|
41169
41014
|
const TABLE_PH = "\x00TABLEBLOCK";
|
|
41170
41015
|
let result = text.replace(/```(\w*)\n([\s\S]*?)```/g, (_m, lang, code) => {
|
|
41171
|
-
const escaped =
|
|
41016
|
+
const escaped = escapeHtml4(code.replace(/\n$/, ""));
|
|
41172
41017
|
const cls = lang ? ` class="language-${lang}"` : "";
|
|
41173
41018
|
const idx = codeBlocks.length;
|
|
41174
41019
|
codeBlocks.push(`<pre><code${cls}>${escaped}</code></pre>`);
|
|
@@ -41181,7 +41026,7 @@ function markdownToHtml(text) {
|
|
|
41181
41026
|
const inlineCodes = [];
|
|
41182
41027
|
result = result.replace(/`([^`\n]+)`/g, (_m, code) => {
|
|
41183
41028
|
const idx = inlineCodes.length;
|
|
41184
|
-
inlineCodes.push(`<code>${
|
|
41029
|
+
inlineCodes.push(`<code>${escapeHtml4(code)}</code>`);
|
|
41185
41030
|
return `${INLINE_PH}${idx}\x00`;
|
|
41186
41031
|
});
|
|
41187
41032
|
const htmlTags = [];
|
|
@@ -41193,24 +41038,24 @@ function markdownToHtml(text) {
|
|
|
41193
41038
|
htmlTags.push(match);
|
|
41194
41039
|
return `${HTMLTAG_PH}${idx}\x00`;
|
|
41195
41040
|
});
|
|
41196
|
-
result =
|
|
41041
|
+
result = escapeHtml4(result);
|
|
41197
41042
|
result = result.replace(/\*\*(.+?)\*\*/g, "<b>$1</b>");
|
|
41198
41043
|
result = result.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<i>$1</i>");
|
|
41199
41044
|
result = result.replace(/(?<![\w_])_(?!_)([^_\n]+?)_(?![\w_])/g, "<i>$1</i>");
|
|
41200
41045
|
result = result.replace(/~~(.+?)~~/g, "<s>$1</s>");
|
|
41201
|
-
result = result.replace(new RegExp(`${
|
|
41202
|
-
result = result.replace(new RegExp(`${
|
|
41203
|
-
result = result.replace(new RegExp(`${
|
|
41046
|
+
result = result.replace(new RegExp(`${escapeHtml4(BLOCK_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => codeBlocks[Number(idx)]);
|
|
41047
|
+
result = result.replace(new RegExp(`${escapeHtml4(TABLE_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => codeBlocks[Number(idx)]);
|
|
41048
|
+
result = result.replace(new RegExp(`${escapeHtml4(INLINE_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => inlineCodes[Number(idx)]);
|
|
41204
41049
|
const ALLOWED_LINK_SCHEMES = /^(?:https?|mailto|tel|tg):/i;
|
|
41205
41050
|
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, linkText, url) => {
|
|
41206
41051
|
const safe = ALLOWED_LINK_SCHEMES.test(url.trim()) ? url.trim() : "#";
|
|
41207
|
-
return `<a href="${
|
|
41052
|
+
return `<a href="${escapeHtml4(safe)}">${linkText}</a>`;
|
|
41208
41053
|
});
|
|
41209
41054
|
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>");
|
|
41210
|
-
result = result.replace(new RegExp(`${
|
|
41055
|
+
result = result.replace(new RegExp(`${escapeHtml4(HTMLTAG_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => htmlTags[Number(idx)]);
|
|
41211
41056
|
return result;
|
|
41212
41057
|
}
|
|
41213
|
-
function
|
|
41058
|
+
function escapeHtml4(text) {
|
|
41214
41059
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
41215
41060
|
}
|
|
41216
41061
|
function telegramHtmlToPlainText(html) {
|
|
@@ -41611,7 +41456,7 @@ async function finalizeCallback(ctx, opts) {
|
|
|
41611
41456
|
}
|
|
41612
41457
|
|
|
41613
41458
|
// welcome-text.ts
|
|
41614
|
-
function
|
|
41459
|
+
function escapeHtml5(text) {
|
|
41615
41460
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
41616
41461
|
}
|
|
41617
41462
|
function formatAuthLine(auth) {
|
|
@@ -41623,13 +41468,13 @@ function formatAuthLine(auth) {
|
|
|
41623
41468
|
return "\u2717 not authenticated";
|
|
41624
41469
|
}
|
|
41625
41470
|
const sub = auth.subscription_type ?? "subscription";
|
|
41626
|
-
const expires = auth.expires_in ? ` \u00b7 expires ${
|
|
41627
|
-
return `\u2713 ${
|
|
41471
|
+
const expires = auth.expires_in ? ` \u00b7 expires ${escapeHtml5(auth.expires_in)}` : "";
|
|
41472
|
+
return `\u2713 ${escapeHtml5(sub)}${expires}`;
|
|
41628
41473
|
}
|
|
41629
41474
|
function formatAgentLine(meta) {
|
|
41630
41475
|
const m = meta.model && meta.model.length > 0 ? meta.model : "default";
|
|
41631
|
-
const topic = meta.topicName ? ` \u00b7 topic: ${
|
|
41632
|
-
return `<b>${
|
|
41476
|
+
const topic = meta.topicName ? ` \u00b7 topic: ${escapeHtml5([meta.topicEmoji, meta.topicName].filter(Boolean).join(" "))}` : "";
|
|
41477
|
+
return `<b>${escapeHtml5(meta.agentName)}</b> \u00b7 model: <code>${escapeHtml5(m)}</code>${topic}`;
|
|
41633
41478
|
}
|
|
41634
41479
|
function startText(agentName3, dmDisabled) {
|
|
41635
41480
|
if (dmDisabled)
|
|
@@ -41637,7 +41482,7 @@ function startText(agentName3, dmDisabled) {
|
|
|
41637
41482
|
return [
|
|
41638
41483
|
`<b>Switchroom</b> \u2014 Telegram on your Claude Pro or Max subscription.`,
|
|
41639
41484
|
``,
|
|
41640
|
-
`This bot is the <b>${
|
|
41485
|
+
`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.`,
|
|
41641
41486
|
``,
|
|
41642
41487
|
`<b>To pair:</b>`,
|
|
41643
41488
|
`1. DM me anything \u2014 you'll get a 6-char code`,
|
|
@@ -41651,7 +41496,7 @@ function helpText(agentName3) {
|
|
|
41651
41496
|
return [
|
|
41652
41497
|
`<b>Switchroom</b> \u2014 your Pro/Max subscription, wired to Telegram.`,
|
|
41653
41498
|
``,
|
|
41654
|
-
`This bot is the <b>${
|
|
41499
|
+
`This bot is the <b>${escapeHtml5(agentName3)}</b> agent. Text and photos route through to it; replies, reactions and progress cards come back.`,
|
|
41655
41500
|
``,
|
|
41656
41501
|
`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>.`,
|
|
41657
41502
|
``,
|
|
@@ -41670,40 +41515,40 @@ var STATUS_DOT = {
|
|
|
41670
41515
|
function statusPairedText(params) {
|
|
41671
41516
|
const { user, meta } = params;
|
|
41672
41517
|
const lines = [
|
|
41673
|
-
`Paired as ${
|
|
41518
|
+
`Paired as ${escapeHtml5(user)}.`,
|
|
41674
41519
|
``,
|
|
41675
41520
|
`Agent: ${formatAgentLine(meta)}`,
|
|
41676
41521
|
`Auth: ${formatAuthLine(meta.auth)}`
|
|
41677
41522
|
];
|
|
41678
41523
|
if (meta.status)
|
|
41679
|
-
lines.push(`Status: <code>${
|
|
41524
|
+
lines.push(`Status: <code>${escapeHtml5(meta.status)}</code>${meta.uptime ? ` \u00b7 up ${escapeHtml5(meta.uptime)}` : ""}`);
|
|
41680
41525
|
if (meta.live && meta.live.length > 0) {
|
|
41681
41526
|
lines.push("");
|
|
41682
41527
|
lines.push("<b>Health</b>");
|
|
41683
41528
|
for (const row of meta.live) {
|
|
41684
41529
|
const dot = STATUS_DOT[row.status] ?? STATUS_DOT.fail;
|
|
41685
|
-
lines.push(`${dot} <b>${
|
|
41530
|
+
lines.push(`${dot} <b>${escapeHtml5(row.label)}</b> ${escapeHtml5(row.detail)}`);
|
|
41686
41531
|
}
|
|
41687
41532
|
}
|
|
41688
41533
|
const audit = meta.audit;
|
|
41689
41534
|
if (audit) {
|
|
41690
41535
|
lines.push("");
|
|
41691
41536
|
if (audit.version)
|
|
41692
|
-
lines.push(`<b>Version</b> ${
|
|
41537
|
+
lines.push(`<b>Version</b> ${escapeHtml5(audit.version)}`);
|
|
41693
41538
|
if (meta.extendsProfile)
|
|
41694
|
-
lines.push(`<b>Profile</b> ${
|
|
41539
|
+
lines.push(`<b>Profile</b> ${escapeHtml5(meta.extendsProfile)}`);
|
|
41695
41540
|
if (audit.tools)
|
|
41696
|
-
lines.push(`<b>Tools</b> ${
|
|
41541
|
+
lines.push(`<b>Tools</b> ${escapeHtml5(audit.tools)}`);
|
|
41697
41542
|
if (audit.toolsDeny)
|
|
41698
|
-
lines.push(`<b>Deny</b> ${
|
|
41543
|
+
lines.push(`<b>Deny</b> ${escapeHtml5(audit.toolsDeny)}`);
|
|
41699
41544
|
if (audit.skills)
|
|
41700
|
-
lines.push(`<b>Skills</b> ${
|
|
41545
|
+
lines.push(`<b>Skills</b> ${escapeHtml5(audit.skills)}`);
|
|
41701
41546
|
if (audit.limits)
|
|
41702
|
-
lines.push(`<b>Limits</b> ${
|
|
41547
|
+
lines.push(`<b>Limits</b> ${escapeHtml5(audit.limits)}`);
|
|
41703
41548
|
if (audit.channel)
|
|
41704
|
-
lines.push(`<b>Channel</b> ${
|
|
41549
|
+
lines.push(`<b>Channel</b> ${escapeHtml5(audit.channel)}`);
|
|
41705
41550
|
if (audit.memoryBank)
|
|
41706
|
-
lines.push(`<b>Memory</b> ${
|
|
41551
|
+
lines.push(`<b>Memory</b> ${escapeHtml5(audit.memoryBank)}`);
|
|
41707
41552
|
}
|
|
41708
41553
|
return lines.join(`
|
|
41709
41554
|
`);
|
|
@@ -41711,7 +41556,7 @@ function statusPairedText(params) {
|
|
|
41711
41556
|
function statusPendingText(code) {
|
|
41712
41557
|
return `Pending pairing \u2014 run in Claude Code:
|
|
41713
41558
|
|
|
41714
|
-
<code>/telegram:access pair ${
|
|
41559
|
+
<code>/telegram:access pair ${escapeHtml5(code)}</code>`;
|
|
41715
41560
|
}
|
|
41716
41561
|
function statusUnpairedText() {
|
|
41717
41562
|
return "Not paired. Send me a message to get a pairing code.";
|
|
@@ -41740,7 +41585,7 @@ var TELEGRAM_BASE_COMMANDS = TELEGRAM_MENU_COMMANDS.slice(0, 3);
|
|
|
41740
41585
|
var TELEGRAM_SWITCHROOM_COMMANDS = TELEGRAM_MENU_COMMANDS.slice(3);
|
|
41741
41586
|
function switchroomHelpText(agentName3) {
|
|
41742
41587
|
return [
|
|
41743
|
-
`<b>Switchroom bot</b> \u2014 commands for the <b>${
|
|
41588
|
+
`<b>Switchroom bot</b> \u2014 commands for the <b>${escapeHtml5(agentName3)}</b> agent.`,
|
|
41744
41589
|
``,
|
|
41745
41590
|
`<b>Session & approvals</b>`,
|
|
41746
41591
|
`<code>/new</code> \u2014 fresh session (flush handoff, restart)`,
|
|
@@ -41788,15 +41633,15 @@ function switchroomHelpText(agentName3) {
|
|
|
41788
41633
|
`);
|
|
41789
41634
|
}
|
|
41790
41635
|
function restartAckText(agentName3) {
|
|
41791
|
-
return `\uD83D\uDD04 Restarting <b>${
|
|
41636
|
+
return `\uD83D\uDD04 Restarting <b>${escapeHtml5(agentName3)}</b>\u2026`;
|
|
41792
41637
|
}
|
|
41793
41638
|
function newSessionAckText(agentName3, flushedHandoff) {
|
|
41794
41639
|
const tail = flushedHandoff ? " \u00b7 flushed handoff" : "";
|
|
41795
|
-
return `\uD83C\uDD95 Started fresh session for <b>${
|
|
41640
|
+
return `\uD83C\uDD95 Started fresh session for <b>${escapeHtml5(agentName3)}</b>${tail} \u00b7 restarting\u2026`;
|
|
41796
41641
|
}
|
|
41797
41642
|
function resetSessionAckText(agentName3, flushedHandoff) {
|
|
41798
41643
|
const tail = flushedHandoff ? " \u00b7 flushed handoff" : "";
|
|
41799
|
-
return `\uD83D\uDD04 Reset session for <b>${
|
|
41644
|
+
return `\uD83D\uDD04 Reset session for <b>${escapeHtml5(agentName3)}</b>${tail} \u00b7 restarting\u2026`;
|
|
41800
41645
|
}
|
|
41801
41646
|
|
|
41802
41647
|
// gateway/auth-status-adapter.ts
|
|
@@ -41981,7 +41826,7 @@ function shouldShowHandoffLine() {
|
|
|
41981
41826
|
function formatHandoffLine(topic, format) {
|
|
41982
41827
|
const prefix = "\u21a9\ufe0f Picked up where we left off, ";
|
|
41983
41828
|
if (format === "html") {
|
|
41984
|
-
return `<i>${prefix}${
|
|
41829
|
+
return `<i>${prefix}${escapeHtml6(topic)}</i>
|
|
41985
41830
|
|
|
41986
41831
|
`;
|
|
41987
41832
|
}
|
|
@@ -41996,7 +41841,7 @@ function formatHandoffLine(topic, format) {
|
|
|
41996
41841
|
|
|
41997
41842
|
`;
|
|
41998
41843
|
}
|
|
41999
|
-
function
|
|
41844
|
+
function escapeHtml6(s) {
|
|
42000
41845
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
42001
41846
|
}
|
|
42002
41847
|
var MDV2_SPECIALS = /[_*\[\]()~`>#+\-=|{}.!\\]/g;
|
|
@@ -45375,13 +45220,13 @@ function buildMs365CardText(p) {
|
|
|
45375
45220
|
const lines = [];
|
|
45376
45221
|
lines.push(`\uD83D\uDCC4 Microsoft 365 write approval`);
|
|
45377
45222
|
lines.push("");
|
|
45378
|
-
lines.push(`Agent: ${
|
|
45379
|
-
lines.push(`Tool: ${
|
|
45380
|
-
lines.push(`Item: ${
|
|
45223
|
+
lines.push(`Agent: ${truncate2(p.agentName, 64)}`);
|
|
45224
|
+
lines.push(`Tool: ${truncate2(p.toolName.replace(/^mcp__/, ""), 96)}`);
|
|
45225
|
+
lines.push(`Item: ${truncate2(p.itemDisplayName, 256)}`);
|
|
45381
45226
|
if (p.itemId !== "(new)") {
|
|
45382
|
-
lines.push(`ID: ${
|
|
45227
|
+
lines.push(`ID: ${truncate2(p.itemId, 96)}`);
|
|
45383
45228
|
}
|
|
45384
|
-
lines.push(`Account: ${
|
|
45229
|
+
lines.push(`Account: ${truncate2(p.accountEmail, 96)}`);
|
|
45385
45230
|
if (typeof p.sizeBytesBefore === "number" || typeof p.sizeBytesAfter === "number") {
|
|
45386
45231
|
const before = p.sizeBytesBefore ?? 0;
|
|
45387
45232
|
const after = p.sizeBytesAfter ?? 0;
|
|
@@ -45390,18 +45235,18 @@ function buildMs365CardText(p) {
|
|
|
45390
45235
|
lines.push(`Size: ${humanBytes(before)} \u2192 ${humanBytes(after)} (${sign}${humanBytes(delta)})`);
|
|
45391
45236
|
}
|
|
45392
45237
|
if (p.deepLink) {
|
|
45393
|
-
lines.push(`Link: ${
|
|
45238
|
+
lines.push(`Link: ${truncate2(p.deepLink, 256)}`);
|
|
45394
45239
|
}
|
|
45395
45240
|
if (p.agentRationale) {
|
|
45396
45241
|
lines.push("");
|
|
45397
|
-
lines.push(`\uD83D\uDCAC ${
|
|
45242
|
+
lines.push(`\uD83D\uDCAC ${truncate2(p.agentRationale, 512)}`);
|
|
45398
45243
|
}
|
|
45399
45244
|
lines.push("");
|
|
45400
45245
|
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.");
|
|
45401
45246
|
return lines.join(`
|
|
45402
45247
|
`);
|
|
45403
45248
|
}
|
|
45404
|
-
function
|
|
45249
|
+
function truncate2(s, n) {
|
|
45405
45250
|
if (s.length <= n)
|
|
45406
45251
|
return s;
|
|
45407
45252
|
return s.slice(0, n - 1) + "\u2026";
|
|
@@ -45517,9 +45362,9 @@ function buildDiffPreviewCard(input) {
|
|
|
45517
45362
|
}
|
|
45518
45363
|
const preview = input.preview;
|
|
45519
45364
|
const bodyLines = [];
|
|
45520
|
-
bodyLines.push(`<b>${
|
|
45365
|
+
bodyLines.push(`<b>${escapeHtml7(preview.title)}</b>`);
|
|
45521
45366
|
for (const line of preview.lines) {
|
|
45522
|
-
bodyLines.push(
|
|
45367
|
+
bodyLines.push(escapeHtml7(line.text));
|
|
45523
45368
|
}
|
|
45524
45369
|
const text = bodyLines.join(`
|
|
45525
45370
|
`);
|
|
@@ -45572,7 +45417,7 @@ function buildDiffPreviewCard(input) {
|
|
|
45572
45417
|
}
|
|
45573
45418
|
return { text, reply_markup: kb };
|
|
45574
45419
|
}
|
|
45575
|
-
function
|
|
45420
|
+
function escapeHtml7(s) {
|
|
45576
45421
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
45577
45422
|
}
|
|
45578
45423
|
|
|
@@ -46418,14 +46263,14 @@ function buildVaultSaveDiscardedInbound(opts) {
|
|
|
46418
46263
|
// gateway/subagent-handback-inbound-builder.ts
|
|
46419
46264
|
var HANDBACK_RESULT_MAX = 3000;
|
|
46420
46265
|
var HANDBACK_DESC_MAX = 200;
|
|
46421
|
-
function
|
|
46266
|
+
function truncate3(s, max) {
|
|
46422
46267
|
const t = s.trim();
|
|
46423
46268
|
return t.length > max ? t.slice(0, max) + "\u2026" : t;
|
|
46424
46269
|
}
|
|
46425
46270
|
function buildSubagentHandbackInbound(opts) {
|
|
46426
46271
|
const ts = opts.nowMs ?? Date.now();
|
|
46427
|
-
const desc =
|
|
46428
|
-
const result =
|
|
46272
|
+
const desc = truncate3(opts.ctx.taskDescription, HANDBACK_DESC_MAX) || "(no description)";
|
|
46273
|
+
const result = truncate3(opts.ctx.resultText, HANDBACK_RESULT_MAX);
|
|
46429
46274
|
const text = opts.ctx.outcome === "failed" ? `\uD83E\uDD1D A background worker you dispatched has FAILED.
|
|
46430
46275
|
|
|
46431
46276
|
` + `Task: ${desc}
|
|
@@ -46489,7 +46334,7 @@ function decideSubagentHandback(input) {
|
|
|
46489
46334
|
var PROGRESS_RESULT_MAX = 800;
|
|
46490
46335
|
var PROGRESS_DESC_MAX = 200;
|
|
46491
46336
|
var DEFAULT_PROGRESS_INTERVAL_MS = 5 * 60 * 1000;
|
|
46492
|
-
function
|
|
46337
|
+
function truncate4(s, max) {
|
|
46493
46338
|
const t = s.trim();
|
|
46494
46339
|
return t.length > max ? t.slice(0, max) + "\u2026" : t;
|
|
46495
46340
|
}
|
|
@@ -46503,8 +46348,8 @@ function formatElapsed(ms) {
|
|
|
46503
46348
|
}
|
|
46504
46349
|
function buildSubagentProgressInbound(opts) {
|
|
46505
46350
|
const ts = opts.nowMs ?? Date.now();
|
|
46506
|
-
const desc =
|
|
46507
|
-
const summary =
|
|
46351
|
+
const desc = truncate4(opts.ctx.taskDescription, PROGRESS_DESC_MAX) || "(no description)";
|
|
46352
|
+
const summary = truncate4(opts.ctx.latestSummary, PROGRESS_RESULT_MAX);
|
|
46508
46353
|
const elapsed = formatElapsed(opts.ctx.elapsedMs);
|
|
46509
46354
|
const expiresAt = ts + 2 * opts.ctx.progressIntervalMs;
|
|
46510
46355
|
const text = `\uD83D\uDD04 A background worker you dispatched is still running.
|
|
@@ -48024,7 +47869,7 @@ function sanitiseToolArg(name, raw) {
|
|
|
48024
47869
|
case "NotebookEdit": {
|
|
48025
47870
|
const fp = raw.file_path;
|
|
48026
47871
|
if (typeof fp === "string" && fp.length > 0)
|
|
48027
|
-
out =
|
|
47872
|
+
out = basename3(fp);
|
|
48028
47873
|
break;
|
|
48029
47874
|
}
|
|
48030
47875
|
case "Bash": {
|
|
@@ -48060,7 +47905,7 @@ function sanitiseToolArg(name, raw) {
|
|
|
48060
47905
|
out = out.slice(0, SANITISE_MAX_LEN - 1) + "\u2026";
|
|
48061
47906
|
return out;
|
|
48062
47907
|
}
|
|
48063
|
-
function
|
|
47908
|
+
function basename3(p) {
|
|
48064
47909
|
const idx = p.lastIndexOf("/");
|
|
48065
47910
|
return idx === -1 ? p : p.slice(idx + 1);
|
|
48066
47911
|
}
|
|
@@ -48547,7 +48392,7 @@ function startSubagentWatcher(config) {
|
|
|
48547
48392
|
if (idleMs >= threshold) {
|
|
48548
48393
|
entry.stallNotified = true;
|
|
48549
48394
|
entry.stalledAt = n;
|
|
48550
|
-
const desc =
|
|
48395
|
+
const desc = escapeHtml8(truncate5(entry.description, 80));
|
|
48551
48396
|
const idleSec = Math.floor(idleMs / 1000);
|
|
48552
48397
|
log?.(`subagent-watcher: stall detected for ${entry.agentId} (idle ${idleSec}s): ${desc}`);
|
|
48553
48398
|
if (db2 != null) {
|
|
@@ -49021,7 +48866,7 @@ function renderIssuesCard(opts) {
|
|
|
49021
48866
|
const maxSeverity = sorted[0].severity;
|
|
49022
48867
|
const headerEmoji = SEVERITY_EMOJI[maxSeverity];
|
|
49023
48868
|
const count = sorted.length;
|
|
49024
|
-
const header = `${headerEmoji} <b>${
|
|
48869
|
+
const header = `${headerEmoji} <b>${escapeHtml8(opts.agentName)}</b> \u00b7 ${count} ${count === 1 ? "issue" : "issues"}`;
|
|
49025
48870
|
const maxRows = opts.maxRows ?? DEFAULT_MAX_ROWS;
|
|
49026
48871
|
const visible = sorted.slice(0, maxRows);
|
|
49027
48872
|
const overflow = sorted.length - visible.length;
|
|
@@ -49030,10 +48875,10 @@ function renderIssuesCard(opts) {
|
|
|
49030
48875
|
const emoji = SEVERITY_EMOJI[e.severity];
|
|
49031
48876
|
const occ = e.occurrences > 1 ? ` <i>(\u00d7${e.occurrences})</i>` : "";
|
|
49032
48877
|
const ago = relTime(now - e.last_seen);
|
|
49033
|
-
const head = `${emoji} <code>${
|
|
48878
|
+
const head = `${emoji} <code>${escapeHtml8(e.fingerprint)}</code> ${escapeHtml8(e.summary)}${occ} \u2014 <i>${ago}</i>`;
|
|
49034
48879
|
const remediation = formatRemediation(e.detail);
|
|
49035
48880
|
return remediation == null ? head : `${head}
|
|
49036
|
-
\u2192 <i>${
|
|
48881
|
+
\u2192 <i>${escapeHtml8(remediation)}</i>`;
|
|
49037
48882
|
});
|
|
49038
48883
|
const lines = [header, "", ...rows];
|
|
49039
48884
|
if (overflow > 0) {
|
|
@@ -49462,7 +49307,7 @@ function defaultReadEvents(stateDir) {
|
|
|
49462
49307
|
return readAll(stateDir);
|
|
49463
49308
|
}
|
|
49464
49309
|
// permission-title.ts
|
|
49465
|
-
import { basename as
|
|
49310
|
+
import { basename as basename5 } from "node:path";
|
|
49466
49311
|
var COMMAND_TITLE_MAX = 40;
|
|
49467
49312
|
var PATH_TITLE_MAX = 40;
|
|
49468
49313
|
var DESCRIPTION_LINE_MAX = 240;
|
|
@@ -49513,13 +49358,13 @@ function summarizeToolForTitle(toolName, inputPreview) {
|
|
|
49513
49358
|
return `${toolName} (${skill})`;
|
|
49514
49359
|
const command = readString(input, "command");
|
|
49515
49360
|
if (command)
|
|
49516
|
-
return `${toolName}: ${
|
|
49361
|
+
return `${toolName}: ${truncate6(command, COMMAND_TITLE_MAX)}`;
|
|
49517
49362
|
const argHint = firstScalarArgHint(input);
|
|
49518
49363
|
return argHint ? `${toolName} (${argHint})` : toolName;
|
|
49519
49364
|
}
|
|
49520
49365
|
case "Bash": {
|
|
49521
49366
|
const command = readString(input, "command");
|
|
49522
|
-
return command ? `${toolName}: ${
|
|
49367
|
+
return command ? `${toolName}: ${truncate6(command, COMMAND_TITLE_MAX)}` : toolName;
|
|
49523
49368
|
}
|
|
49524
49369
|
case "Read":
|
|
49525
49370
|
case "Edit":
|
|
@@ -49527,17 +49372,17 @@ function summarizeToolForTitle(toolName, inputPreview) {
|
|
|
49527
49372
|
case "MultiEdit":
|
|
49528
49373
|
case "NotebookEdit": {
|
|
49529
49374
|
const filePath = readString(input, "file_path") ?? readString(input, "notebook_path");
|
|
49530
|
-
return filePath ? `${toolName}: ${
|
|
49375
|
+
return filePath ? `${toolName}: ${truncate6(basename5(filePath), PATH_TITLE_MAX)}` : toolName;
|
|
49531
49376
|
}
|
|
49532
49377
|
case "Glob":
|
|
49533
49378
|
case "Grep": {
|
|
49534
49379
|
const pattern = readString(input, "pattern");
|
|
49535
|
-
return pattern ? `${toolName}: ${
|
|
49380
|
+
return pattern ? `${toolName}: ${truncate6(pattern, COMMAND_TITLE_MAX)}` : toolName;
|
|
49536
49381
|
}
|
|
49537
49382
|
case "WebFetch":
|
|
49538
49383
|
case "WebSearch": {
|
|
49539
49384
|
const query2 = readString(input, "url") ?? readString(input, "query");
|
|
49540
|
-
return query2 ? `${toolName}: ${
|
|
49385
|
+
return query2 ? `${toolName}: ${truncate6(query2, COMMAND_TITLE_MAX)}` : toolName;
|
|
49541
49386
|
}
|
|
49542
49387
|
default:
|
|
49543
49388
|
return toolName;
|
|
@@ -49576,7 +49421,7 @@ function firstScalarArgHint(input) {
|
|
|
49576
49421
|
if (SKIP.has(key))
|
|
49577
49422
|
continue;
|
|
49578
49423
|
if (typeof value === "string" && value.length > 0) {
|
|
49579
|
-
return `${key}: ${
|
|
49424
|
+
return `${key}: ${truncate6(value, INPUT_VALUE_MAX)}`;
|
|
49580
49425
|
}
|
|
49581
49426
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
49582
49427
|
return `${key}: ${String(value)}`;
|
|
@@ -49608,10 +49453,10 @@ function skillBasenameFromPath(input) {
|
|
|
49608
49453
|
return null;
|
|
49609
49454
|
const trimmed = path.replace(/\/SKILL\.md$/i, "").replace(/\/$/, "");
|
|
49610
49455
|
const lastSlash = trimmed.lastIndexOf("/");
|
|
49611
|
-
const
|
|
49612
|
-
return
|
|
49456
|
+
const basename6 = lastSlash >= 0 ? trimmed.slice(lastSlash + 1) : trimmed;
|
|
49457
|
+
return basename6.length > 0 ? basename6 : null;
|
|
49613
49458
|
}
|
|
49614
|
-
function
|
|
49459
|
+
function truncate6(text, max) {
|
|
49615
49460
|
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
49616
49461
|
if (collapsed.length <= max)
|
|
49617
49462
|
return collapsed;
|
|
@@ -49619,7 +49464,7 @@ function truncate7(text, max) {
|
|
|
49619
49464
|
}
|
|
49620
49465
|
|
|
49621
49466
|
// permission-rule.ts
|
|
49622
|
-
import { basename as
|
|
49467
|
+
import { basename as basename6 } from "node:path";
|
|
49623
49468
|
function resolveAlwaysAllowRule(toolName, inputPreview) {
|
|
49624
49469
|
if (!toolName)
|
|
49625
49470
|
return null;
|
|
@@ -49685,7 +49530,7 @@ function skillBasenameFromPath2(input) {
|
|
|
49685
49530
|
if (!path)
|
|
49686
49531
|
return null;
|
|
49687
49532
|
const trimmed = path.replace(/\/SKILL\.md$/i, "").replace(/\/$/, "");
|
|
49688
|
-
return
|
|
49533
|
+
return basename6(trimmed) || null;
|
|
49689
49534
|
}
|
|
49690
49535
|
|
|
49691
49536
|
// credits-watch.ts
|
|
@@ -49731,7 +49576,7 @@ function evaluateCreditState(args) {
|
|
|
49731
49576
|
if (!currentIsFatal && prevIsFatal) {
|
|
49732
49577
|
return {
|
|
49733
49578
|
kind: "notify",
|
|
49734
|
-
message: `\u2705 <b>${
|
|
49579
|
+
message: `\u2705 <b>${escapeHtml10(agentName3)}</b>: credits restored \u2014 agent should resume normal operation.`,
|
|
49735
49580
|
newState: { lastNotifiedReason: null, lastNotifiedAt: now },
|
|
49736
49581
|
transition: "exited"
|
|
49737
49582
|
};
|
|
@@ -49760,12 +49605,12 @@ function evaluateCreditState(args) {
|
|
|
49760
49605
|
function buildEntryMessage(agentName3, reason) {
|
|
49761
49606
|
const desc = humanizeReason(reason);
|
|
49762
49607
|
return [
|
|
49763
|
-
`\u26a0\ufe0f <b>${
|
|
49608
|
+
`\u26a0\ufe0f <b>${escapeHtml10(agentName3)}</b>: ${desc}`,
|
|
49764
49609
|
``,
|
|
49765
49610
|
`Cron tasks and inbound replies will fail until this is resolved. Check`,
|
|
49766
49611
|
`your subscription or pre-paid usage at <a href="https://console.anthropic.com">console.anthropic.com</a>.`,
|
|
49767
49612
|
``,
|
|
49768
|
-
`<i>Source: Claude CLI cache (cachedExtraUsageDisabledReason=${
|
|
49613
|
+
`<i>Source: Claude CLI cache (cachedExtraUsageDisabledReason=${escapeHtml10(reason)})</i>`
|
|
49769
49614
|
].join(`
|
|
49770
49615
|
`);
|
|
49771
49616
|
}
|
|
@@ -49783,7 +49628,7 @@ function humanizeReason(reason) {
|
|
|
49783
49628
|
return `usage disabled (${reason})`;
|
|
49784
49629
|
}
|
|
49785
49630
|
}
|
|
49786
|
-
function
|
|
49631
|
+
function escapeHtml10(s) {
|
|
49787
49632
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
49788
49633
|
}
|
|
49789
49634
|
function loadCreditState(stateDir) {
|
|
@@ -49882,10 +49727,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
49882
49727
|
}
|
|
49883
49728
|
|
|
49884
49729
|
// ../src/build-info.ts
|
|
49885
|
-
var VERSION = "0.13.
|
|
49886
|
-
var COMMIT_SHA = "
|
|
49887
|
-
var COMMIT_DATE = "2026-05-
|
|
49888
|
-
var LATEST_PR =
|
|
49730
|
+
var VERSION = "0.13.58";
|
|
49731
|
+
var COMMIT_SHA = "20818078";
|
|
49732
|
+
var COMMIT_DATE = "2026-05-27T22:11:23Z";
|
|
49733
|
+
var LATEST_PR = 1928;
|
|
49889
49734
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
49890
49735
|
|
|
49891
49736
|
// gateway/boot-version.ts
|
|
@@ -52096,7 +51941,7 @@ ${reminder}
|
|
|
52096
51941
|
noteSubagentDispatch(key);
|
|
52097
51942
|
}
|
|
52098
51943
|
if (ev.toolUseId != null && ev.toolUseId.length > 0 && !isTelegramSurfaceTool(ev.toolName)) {
|
|
52099
|
-
const label =
|
|
51944
|
+
const label = toolLabel(ev.toolName, ev.input, undefined, ev.precomputedLabel);
|
|
52100
51945
|
noteToolStart(key, ev.toolUseId, ev.toolName, label.length > 0 ? label : null, Date.now());
|
|
52101
51946
|
const evInput = ev.input;
|
|
52102
51947
|
if (ev.toolName === "Agent" || ev.toolName === "Task" || ev.toolName === "Bash" && evInput?.run_in_background === true) {
|
|
@@ -53859,6 +53704,74 @@ function closeProgressLane(chatId, threadId) {
|
|
|
53859
53704
|
}
|
|
53860
53705
|
}
|
|
53861
53706
|
}
|
|
53707
|
+
async function drainActivitySummary(turn) {
|
|
53708
|
+
try {
|
|
53709
|
+
while (turn.activityPendingRender !== turn.activityLastSentRender) {
|
|
53710
|
+
const target = turn.activityPendingRender;
|
|
53711
|
+
if (target == null)
|
|
53712
|
+
break;
|
|
53713
|
+
const html = `<i>${target}</i>`;
|
|
53714
|
+
const chat = turn.sessionChatId;
|
|
53715
|
+
const thread = turn.sessionThreadId;
|
|
53716
|
+
const useDraft = turn.isDm && thread == null && sendMessageDraftFn != null;
|
|
53717
|
+
try {
|
|
53718
|
+
if (useDraft) {
|
|
53719
|
+
if (turn.activityDraftId == null) {
|
|
53720
|
+
turn.activityDraftId = allocateDraftId();
|
|
53721
|
+
}
|
|
53722
|
+
const draftId = turn.activityDraftId;
|
|
53723
|
+
await sendMessageDraftFn(chat, draftId, html, undefined);
|
|
53724
|
+
} else if (turn.activityMessageId == null) {
|
|
53725
|
+
const sent = await robustApiCall(() => bot.api.sendMessage(chat, html, {
|
|
53726
|
+
...thread != null ? { message_thread_id: thread } : {},
|
|
53727
|
+
parse_mode: "HTML",
|
|
53728
|
+
disable_notification: true
|
|
53729
|
+
}), { chat_id: chat, ...thread != null ? { threadId: thread } : {}, verb: "activity-summary.send" });
|
|
53730
|
+
turn.activityMessageId = sent.message_id;
|
|
53731
|
+
} else {
|
|
53732
|
+
const id = turn.activityMessageId;
|
|
53733
|
+
await robustApiCall(() => bot.api.editMessageText(chat, id, html, { parse_mode: "HTML" }), { chat_id: chat, ...thread != null ? { threadId: thread } : {}, verb: "activity-summary.edit" });
|
|
53734
|
+
}
|
|
53735
|
+
turn.activityLastSentRender = target;
|
|
53736
|
+
} catch (err) {
|
|
53737
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
53738
|
+
if (!msg.includes("message is not modified")) {
|
|
53739
|
+
process.stderr.write(`telegram gateway: activity-summary drain failed: ${msg}
|
|
53740
|
+
`);
|
|
53741
|
+
}
|
|
53742
|
+
turn.activityLastSentRender = target;
|
|
53743
|
+
}
|
|
53744
|
+
}
|
|
53745
|
+
} finally {
|
|
53746
|
+
turn.activityInFlight = null;
|
|
53747
|
+
}
|
|
53748
|
+
}
|
|
53749
|
+
function clearActivitySummary(turn) {
|
|
53750
|
+
const chat = turn.sessionChatId;
|
|
53751
|
+
const thread = turn.sessionThreadId;
|
|
53752
|
+
const inFlight = turn.activityInFlight ?? Promise.resolve();
|
|
53753
|
+
inFlight.then(async () => {
|
|
53754
|
+
if (turn.activityDraftId != null && sendMessageDraftFn != null) {
|
|
53755
|
+
const draftId = turn.activityDraftId;
|
|
53756
|
+
turn.activityDraftId = null;
|
|
53757
|
+
try {
|
|
53758
|
+
await sendMessageDraftFn(chat, draftId, "", undefined);
|
|
53759
|
+
} catch (err) {
|
|
53760
|
+
process.stderr.write(`telegram gateway: activity-summary draft-clear failed: ${err}
|
|
53761
|
+
`);
|
|
53762
|
+
}
|
|
53763
|
+
} else if (turn.activityMessageId != null) {
|
|
53764
|
+
const id = turn.activityMessageId;
|
|
53765
|
+
turn.activityMessageId = null;
|
|
53766
|
+
try {
|
|
53767
|
+
await robustApiCall(() => bot.api.deleteMessage(chat, id), { chat_id: chat, ...thread != null ? { threadId: thread } : {}, verb: "activity-summary.delete" });
|
|
53768
|
+
} catch (err) {
|
|
53769
|
+
process.stderr.write(`telegram gateway: activity-summary delete failed: ${err}
|
|
53770
|
+
`);
|
|
53771
|
+
}
|
|
53772
|
+
}
|
|
53773
|
+
});
|
|
53774
|
+
}
|
|
53862
53775
|
function handleSessionEvent(ev) {
|
|
53863
53776
|
switch (ev.kind) {
|
|
53864
53777
|
case "enqueue": {
|
|
@@ -53892,7 +53805,12 @@ function handleSessionEvent(ev) {
|
|
|
53892
53805
|
lastAssistantMsgId: null,
|
|
53893
53806
|
lastAssistantDone: false,
|
|
53894
53807
|
toolCallCount: 0,
|
|
53895
|
-
|
|
53808
|
+
toolActivity: makeEmptyActivityState(),
|
|
53809
|
+
activityMessageId: null,
|
|
53810
|
+
activityDraftId: null,
|
|
53811
|
+
activityInFlight: null,
|
|
53812
|
+
activityPendingRender: null,
|
|
53813
|
+
activityLastSentRender: null,
|
|
53896
53814
|
answerStream: null,
|
|
53897
53815
|
isDm: isDmChatId(ev.chatId)
|
|
53898
53816
|
};
|
|
@@ -53952,37 +53870,29 @@ function handleSessionEvent(ev) {
|
|
|
53952
53870
|
const ctrl = activeStatusReactions.get(statusKey(turn.sessionChatId, turn.sessionThreadId));
|
|
53953
53871
|
const name = ev.toolName;
|
|
53954
53872
|
if (isTelegramReplyTool(name)) {
|
|
53873
|
+
const wasFirstReply = !turn.replyCalled;
|
|
53955
53874
|
turn.replyCalled = true;
|
|
53956
53875
|
if (turn.orphanedReplyTimeoutId != null) {
|
|
53957
53876
|
clearTimeout(turn.orphanedReplyTimeoutId);
|
|
53958
53877
|
turn.orphanedReplyTimeoutId = null;
|
|
53959
53878
|
}
|
|
53879
|
+
if (wasFirstReply) {
|
|
53880
|
+
clearActivitySummary(turn);
|
|
53881
|
+
}
|
|
53960
53882
|
}
|
|
53961
|
-
if (!turn.replyCalled && !
|
|
53962
|
-
turn.
|
|
53963
|
-
|
|
53964
|
-
if (surface.text != null) {
|
|
53883
|
+
if (!turn.replyCalled && !isTelegramSurfaceTool(name)) {
|
|
53884
|
+
const rendered = registerAndRender(turn.toolActivity, name);
|
|
53885
|
+
if (rendered != null) {
|
|
53965
53886
|
try {
|
|
53966
53887
|
markAckSent();
|
|
53967
53888
|
} catch (err) {
|
|
53968
|
-
process.stderr.write(`telegram gateway:
|
|
53889
|
+
process.stderr.write(`telegram gateway: activity-summary markAckSent failed: ${err}
|
|
53969
53890
|
`);
|
|
53970
53891
|
}
|
|
53971
|
-
|
|
53972
|
-
|
|
53973
|
-
|
|
53974
|
-
|
|
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
|
-
})();
|
|
53892
|
+
turn.activityPendingRender = rendered;
|
|
53893
|
+
if (turn.activityInFlight == null) {
|
|
53894
|
+
turn.activityInFlight = drainActivitySummary(turn);
|
|
53895
|
+
}
|
|
53986
53896
|
}
|
|
53987
53897
|
}
|
|
53988
53898
|
if (!ctrl)
|
|
@@ -55339,7 +55249,7 @@ function getMyAgentName() {
|
|
|
55339
55249
|
const fromEnv = process.env.SWITCHROOM_AGENT_NAME;
|
|
55340
55250
|
if (fromEnv && fromEnv.trim().length > 0)
|
|
55341
55251
|
return fromEnv.trim();
|
|
55342
|
-
return
|
|
55252
|
+
return basename7(process.cwd());
|
|
55343
55253
|
}
|
|
55344
55254
|
function isSelfTargetingCommand(name) {
|
|
55345
55255
|
if (name === "all")
|