@integrity-labs/agt-cli 0.27.94 → 0.27.95
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.
|
@@ -15154,8 +15154,296 @@ function createCrossTeamPeerAuditClient(args) {
|
|
|
15154
15154
|
};
|
|
15155
15155
|
}
|
|
15156
15156
|
|
|
15157
|
-
// src/
|
|
15157
|
+
// src/diagnostic-event-client.ts
|
|
15158
15158
|
var REQUEST_TIMEOUT_MS2 = 1e4;
|
|
15159
|
+
function createDiagnosticEventClient(args) {
|
|
15160
|
+
if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
|
|
15161
|
+
const fetchImpl = args.fetchImpl ?? fetch;
|
|
15162
|
+
const log = args.log ?? (() => {
|
|
15163
|
+
});
|
|
15164
|
+
const base = args.agtHost.replace(/\/+$/, "");
|
|
15165
|
+
const agentId = args.agentId;
|
|
15166
|
+
const apiKey = args.agtApiKey;
|
|
15167
|
+
let cachedToken = null;
|
|
15168
|
+
let cachedTokenExpiresAt = 0;
|
|
15169
|
+
async function getToken() {
|
|
15170
|
+
if (cachedToken && Date.now() < cachedTokenExpiresAt) return cachedToken;
|
|
15171
|
+
const resp = await fetchImpl(`${base}/host/exchange`, {
|
|
15172
|
+
method: "POST",
|
|
15173
|
+
headers: { "Content-Type": "application/json" },
|
|
15174
|
+
body: JSON.stringify({ host_key: apiKey }),
|
|
15175
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
|
|
15176
|
+
});
|
|
15177
|
+
if (!resp.ok) {
|
|
15178
|
+
const body = await resp.text().catch(() => "");
|
|
15179
|
+
throw new Error(`/host/exchange failed (${resp.status}): ${body.slice(0, 200)}`);
|
|
15180
|
+
}
|
|
15181
|
+
const data = await resp.json();
|
|
15182
|
+
cachedToken = data.token;
|
|
15183
|
+
cachedTokenExpiresAt = data.expires_at ? new Date(data.expires_at).getTime() - 12e4 : Date.now() + 55 * 6e4;
|
|
15184
|
+
return cachedToken;
|
|
15185
|
+
}
|
|
15186
|
+
async function postOnce(event) {
|
|
15187
|
+
const token = await getToken();
|
|
15188
|
+
return fetchImpl(`${base}/host/diagnostic-command-event`, {
|
|
15189
|
+
method: "POST",
|
|
15190
|
+
headers: {
|
|
15191
|
+
Authorization: `Bearer ${token}`,
|
|
15192
|
+
"Content-Type": "application/json"
|
|
15193
|
+
},
|
|
15194
|
+
body: JSON.stringify({ agent_id: agentId, ...event }),
|
|
15195
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
|
|
15196
|
+
});
|
|
15197
|
+
}
|
|
15198
|
+
async function emitAsync(event) {
|
|
15199
|
+
try {
|
|
15200
|
+
let resp = await postOnce(event);
|
|
15201
|
+
if (resp.status === 401) {
|
|
15202
|
+
cachedToken = null;
|
|
15203
|
+
cachedTokenExpiresAt = 0;
|
|
15204
|
+
resp = await postOnce(event);
|
|
15205
|
+
}
|
|
15206
|
+
if (!resp.ok) {
|
|
15207
|
+
const body = await resp.text().catch(() => "");
|
|
15208
|
+
log(
|
|
15209
|
+
`diagnostic-event: POST failed (${resp.status}) outcome=${event.outcome}: ${body.slice(0, 200)}`
|
|
15210
|
+
);
|
|
15211
|
+
}
|
|
15212
|
+
} catch (err) {
|
|
15213
|
+
log(`diagnostic-event: emit threw outcome=${event.outcome}: ${err.message}`);
|
|
15214
|
+
}
|
|
15215
|
+
}
|
|
15216
|
+
return {
|
|
15217
|
+
emit(event) {
|
|
15218
|
+
void emitAsync(event);
|
|
15219
|
+
}
|
|
15220
|
+
};
|
|
15221
|
+
}
|
|
15222
|
+
|
|
15223
|
+
// src/telegram-investigate.ts
|
|
15224
|
+
var INVESTIGATE_SYNTAX_RE = /^\/investigate(?:[-_]([A-Za-z0-9_-]{1,64}))?(?:@([A-Za-z0-9_]{1,64}))?(?:\s|$)/;
|
|
15225
|
+
function isInvestigateSyntax(text) {
|
|
15226
|
+
return INVESTIGATE_SYNTAX_RE.test(text);
|
|
15227
|
+
}
|
|
15228
|
+
function classifyInvestigateText(text, opts) {
|
|
15229
|
+
const m = INVESTIGATE_SYNTAX_RE.exec(text);
|
|
15230
|
+
if (!m) return "ignore";
|
|
15231
|
+
const codeSuffix = m[1];
|
|
15232
|
+
if (codeSuffix) {
|
|
15233
|
+
const normalise = (s) => s.toLowerCase().replace(/_/g, "-");
|
|
15234
|
+
if (normalise(codeSuffix) !== normalise(opts.codeName)) return "ignore";
|
|
15235
|
+
}
|
|
15236
|
+
const botSuffix = m[2]?.toLowerCase();
|
|
15237
|
+
if (!botSuffix) return "act";
|
|
15238
|
+
if (!opts.botUsername) return "verification_failed";
|
|
15239
|
+
return botSuffix === opts.botUsername.toLowerCase() ? "act" : "ignore";
|
|
15240
|
+
}
|
|
15241
|
+
function evaluateInvestigateGate(opts) {
|
|
15242
|
+
if (opts.chatType !== "private") return { ok: false, reason: "not-dm" };
|
|
15243
|
+
if (opts.diagnosticChatIds.size === 0) return { ok: false, reason: "allowlist-empty" };
|
|
15244
|
+
if (!opts.senderId || !opts.diagnosticChatIds.has(opts.senderId)) {
|
|
15245
|
+
return { ok: false, reason: "not-allowed" };
|
|
15246
|
+
}
|
|
15247
|
+
return { ok: true };
|
|
15248
|
+
}
|
|
15249
|
+
function createSingleTailSlot() {
|
|
15250
|
+
let expiresAtMs = null;
|
|
15251
|
+
return {
|
|
15252
|
+
reserve(windowMs, nowMs = Date.now()) {
|
|
15253
|
+
if (expiresAtMs !== null && expiresAtMs > nowMs) return null;
|
|
15254
|
+
expiresAtMs = nowMs + windowMs;
|
|
15255
|
+
return expiresAtMs;
|
|
15256
|
+
},
|
|
15257
|
+
remainingMs(nowMs = Date.now()) {
|
|
15258
|
+
if (expiresAtMs === null) return 0;
|
|
15259
|
+
return Math.max(0, expiresAtMs - nowMs);
|
|
15260
|
+
},
|
|
15261
|
+
release() {
|
|
15262
|
+
expiresAtMs = null;
|
|
15263
|
+
}
|
|
15264
|
+
};
|
|
15265
|
+
}
|
|
15266
|
+
|
|
15267
|
+
// src/pane-tail.ts
|
|
15268
|
+
import { execFile } from "child_process";
|
|
15269
|
+
import { promisify } from "util";
|
|
15270
|
+
import { open, stat } from "fs/promises";
|
|
15271
|
+
|
|
15272
|
+
// src/session-probe-runtime.ts
|
|
15273
|
+
import { execFileSync } from "child_process";
|
|
15274
|
+
function agentTmuxSessionName(codeName) {
|
|
15275
|
+
return `agt-${codeName}`;
|
|
15276
|
+
}
|
|
15277
|
+
function escapePgrepRegex(value) {
|
|
15278
|
+
return value.replace(/[.[\]{}()*+?^$|\\]/g, "\\$&");
|
|
15279
|
+
}
|
|
15280
|
+
function probeClaudeProcessInTmux(tmuxSession) {
|
|
15281
|
+
const escapedSession = escapePgrepRegex(tmuxSession);
|
|
15282
|
+
const pattern = `(^|[[:space:]])--name ${escapedSession}([[:space:]]|$)`;
|
|
15283
|
+
try {
|
|
15284
|
+
const out = execFileSync("pgrep", ["-f", "--", pattern], {
|
|
15285
|
+
encoding: "utf-8",
|
|
15286
|
+
timeout: 3e3
|
|
15287
|
+
}).trim();
|
|
15288
|
+
return out.length > 0 ? "alive" : "dead";
|
|
15289
|
+
} catch (err) {
|
|
15290
|
+
const e = err;
|
|
15291
|
+
if (e?.code === "ENOENT") return "unknown";
|
|
15292
|
+
return e?.status === 1 ? "dead" : "unknown";
|
|
15293
|
+
}
|
|
15294
|
+
}
|
|
15295
|
+
function probeTmuxSession(tmuxSession) {
|
|
15296
|
+
try {
|
|
15297
|
+
execFileSync("tmux", ["has-session", "-t", tmuxSession], {
|
|
15298
|
+
stdio: "ignore",
|
|
15299
|
+
timeout: 3e3
|
|
15300
|
+
});
|
|
15301
|
+
return "alive";
|
|
15302
|
+
} catch (err) {
|
|
15303
|
+
const e = err;
|
|
15304
|
+
if (e?.code === "ENOENT") return "unknown";
|
|
15305
|
+
return "dead";
|
|
15306
|
+
}
|
|
15307
|
+
}
|
|
15308
|
+
function probeAgentSession(codeName) {
|
|
15309
|
+
const session = agentTmuxSessionName(codeName);
|
|
15310
|
+
const tmux = probeTmuxSession(session);
|
|
15311
|
+
const claude = tmux === "alive" ? probeClaudeProcessInTmux(session) : tmux;
|
|
15312
|
+
return { tmux, claude };
|
|
15313
|
+
}
|
|
15314
|
+
var probeCache = /* @__PURE__ */ new Map();
|
|
15315
|
+
var SESSION_PROBE_TTL_MS = 15e3;
|
|
15316
|
+
function probeAgentSessionCached(codeName, ttlMs = SESSION_PROBE_TTL_MS, now = Date.now()) {
|
|
15317
|
+
const cached2 = probeCache.get(codeName);
|
|
15318
|
+
if (cached2 && now - cached2.at < ttlMs) return cached2.value;
|
|
15319
|
+
const value = probeAgentSession(codeName);
|
|
15320
|
+
probeCache.set(codeName, { at: now, value });
|
|
15321
|
+
return value;
|
|
15322
|
+
}
|
|
15323
|
+
|
|
15324
|
+
// src/pane-tail.ts
|
|
15325
|
+
var execFileAsync = promisify(execFile);
|
|
15326
|
+
var PANE_LOG_TAIL_BYTES = 64 * 1024;
|
|
15327
|
+
var TMUX_CAPTURE_TIMEOUT_MS = 2e3;
|
|
15328
|
+
async function capturePaneSnapshot(opts) {
|
|
15329
|
+
const scrollback = opts.scrollbackLines ?? 200;
|
|
15330
|
+
try {
|
|
15331
|
+
const { stdout } = await execFileAsync(
|
|
15332
|
+
"tmux",
|
|
15333
|
+
["capture-pane", "-p", "-t", agentTmuxSessionName(opts.codeName), "-S", `-${scrollback}`],
|
|
15334
|
+
{ timeout: TMUX_CAPTURE_TIMEOUT_MS, maxBuffer: 4 * 1024 * 1024 }
|
|
15335
|
+
);
|
|
15336
|
+
return { source: "tmux", text: stdout };
|
|
15337
|
+
} catch {
|
|
15338
|
+
}
|
|
15339
|
+
if (!opts.agentDir) return null;
|
|
15340
|
+
const paneLogPath = `${opts.agentDir}/pane.log`;
|
|
15341
|
+
try {
|
|
15342
|
+
const tail = await readFileTail(paneLogPath, PANE_LOG_TAIL_BYTES);
|
|
15343
|
+
if (tail === null) return null;
|
|
15344
|
+
return { source: "pane-log", text: stripAnsi(tail) };
|
|
15345
|
+
} catch {
|
|
15346
|
+
return null;
|
|
15347
|
+
}
|
|
15348
|
+
}
|
|
15349
|
+
async function readFileTail(path, maxBytes) {
|
|
15350
|
+
const st = await stat(path);
|
|
15351
|
+
if (!st.isFile()) return null;
|
|
15352
|
+
const start = Math.max(0, st.size - maxBytes);
|
|
15353
|
+
const length = st.size - start;
|
|
15354
|
+
if (length === 0) return "";
|
|
15355
|
+
const handle = await open(path, "r");
|
|
15356
|
+
try {
|
|
15357
|
+
const buf = Buffer.alloc(length);
|
|
15358
|
+
await handle.read(buf, 0, length, start);
|
|
15359
|
+
let text = buf.toString("utf8");
|
|
15360
|
+
if (start > 0) {
|
|
15361
|
+
const nl = text.indexOf("\n");
|
|
15362
|
+
if (nl !== -1) text = text.slice(nl + 1);
|
|
15363
|
+
}
|
|
15364
|
+
return text;
|
|
15365
|
+
} finally {
|
|
15366
|
+
await handle.close();
|
|
15367
|
+
}
|
|
15368
|
+
}
|
|
15369
|
+
function stripAnsi(text) {
|
|
15370
|
+
return text.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "").replace(/\x1b\[[0-9;?<=>!]*[ -\/]*[@-~]/g, "").replace(/\x1b./g, "").replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
|
|
15371
|
+
}
|
|
15372
|
+
var SECRET_PATTERNS = [
|
|
15373
|
+
// Augmented host API keys
|
|
15374
|
+
{ re: /tlk_[A-Za-z0-9]{8,}/g, label: "agt-api-key" },
|
|
15375
|
+
// Slack tokens: bot/app/user/refresh/config
|
|
15376
|
+
{ re: /x(?:ox[abprs]|app)-[A-Za-z0-9-]{8,}/g, label: "slack-token" },
|
|
15377
|
+
// JWTs (three base64url segments, first one always starts with eyJ)
|
|
15378
|
+
{ re: /eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g, label: "jwt" },
|
|
15379
|
+
// OpenAI / Anthropic-style keys (sk-..., sk-ant-...)
|
|
15380
|
+
{ re: /sk-[A-Za-z0-9_-]{16,}/g, label: "sk-key" },
|
|
15381
|
+
// AWS access key IDs
|
|
15382
|
+
{ re: /(?:AKIA|ASIA)[0-9A-Z]{16}/g, label: "aws-key" },
|
|
15383
|
+
// GitHub tokens
|
|
15384
|
+
{ re: /gh[pousr]_[A-Za-z0-9]{20,}/g, label: "github-token" }
|
|
15385
|
+
];
|
|
15386
|
+
function redactPaneText(text) {
|
|
15387
|
+
let out = redactAugmentedPaths(text);
|
|
15388
|
+
for (const { re, label } of SECRET_PATTERNS) {
|
|
15389
|
+
out = out.replace(re, `<redacted:${label}>`);
|
|
15390
|
+
}
|
|
15391
|
+
return out;
|
|
15392
|
+
}
|
|
15393
|
+
var DEFAULT_MAX_CHARS = 3900;
|
|
15394
|
+
var REFLOW_COLS = 80;
|
|
15395
|
+
function formatPaneSnapshot(opts) {
|
|
15396
|
+
const maxChars = opts.maxChars ?? DEFAULT_MAX_CHARS;
|
|
15397
|
+
const commandName = opts.commandName ?? "/debug";
|
|
15398
|
+
const header = opts.status.kind === "live" ? `\u{1F50E} Live pane tail for \`${opts.codeName}\` \u2014 captured ${opts.capturedAtLabel} \xB7 updates ~3s \xB7 expires in ${formatCountdown(opts.status.secondsRemaining)}` : `\u{1F50E} Pane tail for \`${opts.codeName}\` \u2014 captured ${opts.capturedAtLabel} \xB7 *expired* \u2014 run \`${commandName}\` to restart`;
|
|
15399
|
+
const fenceOverhead = header.length + "\n```\n".length + "\n```".length + 16;
|
|
15400
|
+
const contentBudget = Math.max(0, maxChars - fenceOverhead);
|
|
15401
|
+
const lines = reflowLines(sanitizeForCodeBlock(opts.text), REFLOW_COLS);
|
|
15402
|
+
const kept = [];
|
|
15403
|
+
let used = 0;
|
|
15404
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
15405
|
+
const cost = lines[i].length + 1;
|
|
15406
|
+
if (used + cost > contentBudget) break;
|
|
15407
|
+
kept.unshift(lines[i]);
|
|
15408
|
+
used += cost;
|
|
15409
|
+
}
|
|
15410
|
+
const truncated = kept.length < lines.length;
|
|
15411
|
+
const body = kept.join("\n").trimEnd();
|
|
15412
|
+
const block = body.length > 0 ? `\`\`\`
|
|
15413
|
+
${truncated ? "\u2026\n" : ""}${body}
|
|
15414
|
+
\`\`\`` : "_(pane is empty)_";
|
|
15415
|
+
return `${header}
|
|
15416
|
+
${block}`;
|
|
15417
|
+
}
|
|
15418
|
+
function formatCountdown(totalSeconds) {
|
|
15419
|
+
const s = Math.max(0, Math.floor(totalSeconds));
|
|
15420
|
+
return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
|
|
15421
|
+
}
|
|
15422
|
+
function sanitizeForCodeBlock(text) {
|
|
15423
|
+
return text.replace(/```/g, "`\u200B`\u200B`");
|
|
15424
|
+
}
|
|
15425
|
+
function reflowLines(text, cols) {
|
|
15426
|
+
const out = [];
|
|
15427
|
+
for (const rawLine of text.split("\n")) {
|
|
15428
|
+
const line = rawLine.replace(/\s+$/, "");
|
|
15429
|
+
if (line.length <= cols) {
|
|
15430
|
+
out.push(line);
|
|
15431
|
+
continue;
|
|
15432
|
+
}
|
|
15433
|
+
for (let i = 0; i < line.length; i += cols) {
|
|
15434
|
+
out.push(line.slice(i, i + cols));
|
|
15435
|
+
}
|
|
15436
|
+
}
|
|
15437
|
+
const collapsed = [];
|
|
15438
|
+
for (const line of out) {
|
|
15439
|
+
if (line === "" && collapsed[collapsed.length - 1] === "") continue;
|
|
15440
|
+
collapsed.push(line);
|
|
15441
|
+
}
|
|
15442
|
+
return collapsed;
|
|
15443
|
+
}
|
|
15444
|
+
|
|
15445
|
+
// src/observed-chat-client.ts
|
|
15446
|
+
var REQUEST_TIMEOUT_MS3 = 1e4;
|
|
15159
15447
|
function createObservedChatClient(args) {
|
|
15160
15448
|
if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
|
|
15161
15449
|
const fetchImpl = args.fetchImpl ?? fetch;
|
|
@@ -15173,7 +15461,7 @@ function createObservedChatClient(args) {
|
|
|
15173
15461
|
method: "POST",
|
|
15174
15462
|
headers: { "Content-Type": "application/json" },
|
|
15175
15463
|
body: JSON.stringify({ host_key: apiKey }),
|
|
15176
|
-
signal: AbortSignal.timeout(
|
|
15464
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
15177
15465
|
});
|
|
15178
15466
|
if (!resp.ok) {
|
|
15179
15467
|
const body = await resp.text().catch(() => "");
|
|
@@ -15190,7 +15478,7 @@ function createObservedChatClient(args) {
|
|
|
15190
15478
|
method: "POST",
|
|
15191
15479
|
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
15192
15480
|
body: JSON.stringify({ agent_id: agentId, ...chat }),
|
|
15193
|
-
signal: AbortSignal.timeout(
|
|
15481
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
15194
15482
|
});
|
|
15195
15483
|
}
|
|
15196
15484
|
async function emitAsync(chat) {
|
|
@@ -15237,7 +15525,7 @@ function createObservedChatClient(args) {
|
|
|
15237
15525
|
}
|
|
15238
15526
|
|
|
15239
15527
|
// src/conversation-ingest-client.ts
|
|
15240
|
-
var
|
|
15528
|
+
var REQUEST_TIMEOUT_MS4 = 1e4;
|
|
15241
15529
|
function createConversationIngestClient(args) {
|
|
15242
15530
|
if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
|
|
15243
15531
|
const fetchImpl = args.fetchImpl ?? fetch;
|
|
@@ -15254,7 +15542,7 @@ function createConversationIngestClient(args) {
|
|
|
15254
15542
|
method: "POST",
|
|
15255
15543
|
headers: { "Content-Type": "application/json" },
|
|
15256
15544
|
body: JSON.stringify({ host_key: apiKey }),
|
|
15257
|
-
signal: AbortSignal.timeout(
|
|
15545
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
|
|
15258
15546
|
});
|
|
15259
15547
|
if (!resp.ok) {
|
|
15260
15548
|
const body = await resp.text().catch(() => "");
|
|
@@ -15277,7 +15565,7 @@ function createConversationIngestClient(args) {
|
|
|
15277
15565
|
method: "POST",
|
|
15278
15566
|
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
15279
15567
|
body: JSON.stringify({ agent_id: agentId, ...payload }),
|
|
15280
|
-
signal: AbortSignal.timeout(
|
|
15568
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
|
|
15281
15569
|
});
|
|
15282
15570
|
}
|
|
15283
15571
|
function refKey(payload) {
|
|
@@ -15309,7 +15597,7 @@ function createConversationIngestClient(args) {
|
|
|
15309
15597
|
}
|
|
15310
15598
|
|
|
15311
15599
|
// src/inbound-context-client.ts
|
|
15312
|
-
var
|
|
15600
|
+
var REQUEST_TIMEOUT_MS5 = 1e4;
|
|
15313
15601
|
function createInboundContextClient(args) {
|
|
15314
15602
|
if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
|
|
15315
15603
|
const fetchImpl = args.fetchImpl ?? fetch;
|
|
@@ -15326,7 +15614,7 @@ function createInboundContextClient(args) {
|
|
|
15326
15614
|
method: "POST",
|
|
15327
15615
|
headers: { "Content-Type": "application/json" },
|
|
15328
15616
|
body: JSON.stringify({ host_key: apiKey }),
|
|
15329
|
-
signal: AbortSignal.timeout(
|
|
15617
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS5)
|
|
15330
15618
|
});
|
|
15331
15619
|
if (!resp.ok) {
|
|
15332
15620
|
const body = await resp.text().catch(() => "");
|
|
@@ -15343,7 +15631,7 @@ function createInboundContextClient(args) {
|
|
|
15343
15631
|
method: "POST",
|
|
15344
15632
|
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
15345
15633
|
body: JSON.stringify(body),
|
|
15346
|
-
signal: AbortSignal.timeout(
|
|
15634
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS5)
|
|
15347
15635
|
});
|
|
15348
15636
|
}
|
|
15349
15637
|
async function emit(args2) {
|
|
@@ -15579,58 +15867,6 @@ function shouldReplayMarker(i) {
|
|
|
15579
15867
|
return i.replayCount < (i.maxReplays ?? MAX_MARKER_REPLAYS);
|
|
15580
15868
|
}
|
|
15581
15869
|
|
|
15582
|
-
// src/session-probe-runtime.ts
|
|
15583
|
-
import { execFileSync } from "child_process";
|
|
15584
|
-
function agentTmuxSessionName(codeName) {
|
|
15585
|
-
return `agt-${codeName}`;
|
|
15586
|
-
}
|
|
15587
|
-
function escapePgrepRegex(value) {
|
|
15588
|
-
return value.replace(/[.[\]{}()*+?^$|\\]/g, "\\$&");
|
|
15589
|
-
}
|
|
15590
|
-
function probeClaudeProcessInTmux(tmuxSession) {
|
|
15591
|
-
const escapedSession = escapePgrepRegex(tmuxSession);
|
|
15592
|
-
const pattern = `(^|[[:space:]])--name ${escapedSession}([[:space:]]|$)`;
|
|
15593
|
-
try {
|
|
15594
|
-
const out = execFileSync("pgrep", ["-f", "--", pattern], {
|
|
15595
|
-
encoding: "utf-8",
|
|
15596
|
-
timeout: 3e3
|
|
15597
|
-
}).trim();
|
|
15598
|
-
return out.length > 0 ? "alive" : "dead";
|
|
15599
|
-
} catch (err) {
|
|
15600
|
-
const e = err;
|
|
15601
|
-
if (e?.code === "ENOENT") return "unknown";
|
|
15602
|
-
return e?.status === 1 ? "dead" : "unknown";
|
|
15603
|
-
}
|
|
15604
|
-
}
|
|
15605
|
-
function probeTmuxSession(tmuxSession) {
|
|
15606
|
-
try {
|
|
15607
|
-
execFileSync("tmux", ["has-session", "-t", tmuxSession], {
|
|
15608
|
-
stdio: "ignore",
|
|
15609
|
-
timeout: 3e3
|
|
15610
|
-
});
|
|
15611
|
-
return "alive";
|
|
15612
|
-
} catch (err) {
|
|
15613
|
-
const e = err;
|
|
15614
|
-
if (e?.code === "ENOENT") return "unknown";
|
|
15615
|
-
return "dead";
|
|
15616
|
-
}
|
|
15617
|
-
}
|
|
15618
|
-
function probeAgentSession(codeName) {
|
|
15619
|
-
const session = agentTmuxSessionName(codeName);
|
|
15620
|
-
const tmux = probeTmuxSession(session);
|
|
15621
|
-
const claude = tmux === "alive" ? probeClaudeProcessInTmux(session) : tmux;
|
|
15622
|
-
return { tmux, claude };
|
|
15623
|
-
}
|
|
15624
|
-
var probeCache = /* @__PURE__ */ new Map();
|
|
15625
|
-
var SESSION_PROBE_TTL_MS = 15e3;
|
|
15626
|
-
function probeAgentSessionCached(codeName, ttlMs = SESSION_PROBE_TTL_MS, now = Date.now()) {
|
|
15627
|
-
const cached2 = probeCache.get(codeName);
|
|
15628
|
-
if (cached2 && now - cached2.at < ttlMs) return cached2.value;
|
|
15629
|
-
const value = probeAgentSession(codeName);
|
|
15630
|
-
probeCache.set(codeName, { at: now, value });
|
|
15631
|
-
return value;
|
|
15632
|
-
}
|
|
15633
|
-
|
|
15634
15870
|
// src/telegram-channel.ts
|
|
15635
15871
|
function redactId(id) {
|
|
15636
15872
|
return createHash("sha256").update(String(id)).digest("hex").slice(0, 8);
|
|
@@ -15644,6 +15880,9 @@ var AGT_AGENT_ID = process.env.AGT_AGENT_ID ?? null;
|
|
|
15644
15880
|
var ALLOWED_CHATS = new Set(
|
|
15645
15881
|
(process.env.TELEGRAM_ALLOWED_CHATS ?? "").split(",").map((s) => s.trim()).filter(Boolean)
|
|
15646
15882
|
);
|
|
15883
|
+
var DIAGNOSTIC_CHAT_IDS = new Set(
|
|
15884
|
+
(process.env.TELEGRAM_DIAGNOSTIC_CHAT_IDS ?? "").split(",").map((s) => s.trim()).filter(Boolean)
|
|
15885
|
+
);
|
|
15647
15886
|
var PEER_CLASSIFIER_CONFIG = {
|
|
15648
15887
|
peer_agent_mode: parsePeerAgentModeEnv(process.env.TELEGRAM_PEER_AGENT_MODE),
|
|
15649
15888
|
peer_group_ids: parsePeerGroupIdsEnv(process.env.TELEGRAM_PEER_GROUP_IDS),
|
|
@@ -15679,6 +15918,13 @@ var crossTeamPeerAuditClient = createCrossTeamPeerAuditClient({
|
|
|
15679
15918
|
log: (line) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${line}
|
|
15680
15919
|
`)
|
|
15681
15920
|
});
|
|
15921
|
+
var diagnosticEventClient = createDiagnosticEventClient({
|
|
15922
|
+
agtHost: AGT_HOST,
|
|
15923
|
+
agtApiKey: AGT_API_KEY,
|
|
15924
|
+
agentId: process.env.AGT_AGENT_ID ?? null,
|
|
15925
|
+
log: (line) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${line}
|
|
15926
|
+
`)
|
|
15927
|
+
});
|
|
15682
15928
|
var observedChatClient = createObservedChatClient({
|
|
15683
15929
|
agtHost: AGT_HOST,
|
|
15684
15930
|
agtApiKey: AGT_API_KEY,
|
|
@@ -15878,7 +16124,8 @@ function buildTelegramHelpMessage(codeName) {
|
|
|
15878
16124
|
"",
|
|
15879
16125
|
`_Type these in any chat where the bot is present (intercepted by the agent):_`,
|
|
15880
16126
|
`\u2022 /help \u2014 show this help`,
|
|
15881
|
-
`\u2022 /restart \u2014 restart this agent
|
|
16127
|
+
`\u2022 /restart \u2014 restart this agent`,
|
|
16128
|
+
`\u2022 /investigate-${codeName} \u2014 live tail of this agent's terminal pane (DM only; team owners/admins and the agent's reports-to person)`
|
|
15882
16129
|
].join("\n");
|
|
15883
16130
|
}
|
|
15884
16131
|
async function handleHelpCommand(opts) {
|
|
@@ -15973,6 +16220,261 @@ async function handleRestartCommand(opts) {
|
|
|
15973
16220
|
}
|
|
15974
16221
|
}
|
|
15975
16222
|
}
|
|
16223
|
+
var INVESTIGATE_TAIL_WINDOW_MS = 12e4;
|
|
16224
|
+
var INVESTIGATE_TAIL_INTERVAL_MS = 3e3;
|
|
16225
|
+
var INVESTIGATE_TAIL_MAX_CONSECUTIVE_FAILURES = 4;
|
|
16226
|
+
var INVESTIGATE_MAX_CHARS = 3800;
|
|
16227
|
+
var investigateTailSlot = createSingleTailSlot();
|
|
16228
|
+
function investigateAuditLog(line) {
|
|
16229
|
+
process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): /investigate ${line}
|
|
16230
|
+
`);
|
|
16231
|
+
}
|
|
16232
|
+
function investigateNowUtcLabel() {
|
|
16233
|
+
return `${(/* @__PURE__ */ new Date()).toISOString().slice(11, 19)} UTC`;
|
|
16234
|
+
}
|
|
16235
|
+
function investigateSleep(ms) {
|
|
16236
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
16237
|
+
}
|
|
16238
|
+
async function classifyInvestigateCommand(text) {
|
|
16239
|
+
const needsUsername = /@[A-Za-z0-9_]{1,64}(?:\s|$)/.test(text);
|
|
16240
|
+
const ours = needsUsername ? await resolveBotUsername() : null;
|
|
16241
|
+
return classifyInvestigateText(text, { codeName: AGENT_CODE_NAME, botUsername: ours });
|
|
16242
|
+
}
|
|
16243
|
+
async function sendInvestigateReply(chatId, messageId, text) {
|
|
16244
|
+
try {
|
|
16245
|
+
const resp = await telegramApiCall(
|
|
16246
|
+
"sendMessage",
|
|
16247
|
+
{
|
|
16248
|
+
chat_id: chatId,
|
|
16249
|
+
text,
|
|
16250
|
+
parse_mode: "Markdown",
|
|
16251
|
+
reply_to_message_id: Number(messageId)
|
|
16252
|
+
},
|
|
16253
|
+
1e4
|
|
16254
|
+
);
|
|
16255
|
+
if (!resp.ok) {
|
|
16256
|
+
investigateAuditLog(`reply rejected by Telegram: ${resp.description ?? "unknown"}`);
|
|
16257
|
+
}
|
|
16258
|
+
} catch (err) {
|
|
16259
|
+
investigateAuditLog(`reply send failed: ${redactAugmentedPaths(err.message)}`);
|
|
16260
|
+
}
|
|
16261
|
+
}
|
|
16262
|
+
async function runInvestigateTailLoop(opts) {
|
|
16263
|
+
const investigateCmd = `/investigate-${AGENT_CODE_NAME}`;
|
|
16264
|
+
let last = opts.initialFrame;
|
|
16265
|
+
let consecutiveFailures = 0;
|
|
16266
|
+
let delayMs = INVESTIGATE_TAIL_INTERVAL_MS;
|
|
16267
|
+
try {
|
|
16268
|
+
while (Date.now() + delayMs < opts.expiresAtMs) {
|
|
16269
|
+
await investigateSleep(delayMs);
|
|
16270
|
+
delayMs = INVESTIGATE_TAIL_INTERVAL_MS;
|
|
16271
|
+
const snapshot = await capturePaneSnapshot({
|
|
16272
|
+
codeName: AGENT_CODE_NAME,
|
|
16273
|
+
agentDir: TELEGRAM_AGENT_DIR
|
|
16274
|
+
});
|
|
16275
|
+
if (!snapshot) {
|
|
16276
|
+
consecutiveFailures++;
|
|
16277
|
+
if (consecutiveFailures >= INVESTIGATE_TAIL_MAX_CONSECUTIVE_FAILURES) {
|
|
16278
|
+
investigateAuditLog(`tail aborted after ${consecutiveFailures} consecutive capture failures`);
|
|
16279
|
+
break;
|
|
16280
|
+
}
|
|
16281
|
+
continue;
|
|
16282
|
+
}
|
|
16283
|
+
const frame = {
|
|
16284
|
+
body: redactPaneText(snapshot.text),
|
|
16285
|
+
source: snapshot.source,
|
|
16286
|
+
capturedAtLabel: investigateNowUtcLabel()
|
|
16287
|
+
};
|
|
16288
|
+
if (frame.body === last.body) continue;
|
|
16289
|
+
const text = formatPaneSnapshot({
|
|
16290
|
+
codeName: AGENT_CODE_NAME,
|
|
16291
|
+
text: frame.body,
|
|
16292
|
+
source: frame.source,
|
|
16293
|
+
capturedAtLabel: frame.capturedAtLabel,
|
|
16294
|
+
status: {
|
|
16295
|
+
kind: "live",
|
|
16296
|
+
secondsRemaining: Math.max(0, Math.round((opts.expiresAtMs - Date.now()) / 1e3))
|
|
16297
|
+
},
|
|
16298
|
+
maxChars: INVESTIGATE_MAX_CHARS,
|
|
16299
|
+
commandName: investigateCmd
|
|
16300
|
+
});
|
|
16301
|
+
try {
|
|
16302
|
+
const resp = await telegramApiCall(
|
|
16303
|
+
"editMessageText",
|
|
16304
|
+
{
|
|
16305
|
+
chat_id: opts.chatId,
|
|
16306
|
+
message_id: opts.messageId,
|
|
16307
|
+
text,
|
|
16308
|
+
parse_mode: "Markdown"
|
|
16309
|
+
},
|
|
16310
|
+
1e4
|
|
16311
|
+
);
|
|
16312
|
+
if (resp.ok) {
|
|
16313
|
+
last = frame;
|
|
16314
|
+
consecutiveFailures = 0;
|
|
16315
|
+
continue;
|
|
16316
|
+
}
|
|
16317
|
+
const retryAfter = resp.parameters?.retry_after;
|
|
16318
|
+
if (typeof retryAfter === "number" && retryAfter > 0) {
|
|
16319
|
+
delayMs = Math.max(INVESTIGATE_TAIL_INTERVAL_MS, retryAfter * 1e3);
|
|
16320
|
+
continue;
|
|
16321
|
+
}
|
|
16322
|
+
consecutiveFailures++;
|
|
16323
|
+
if (consecutiveFailures >= INVESTIGATE_TAIL_MAX_CONSECUTIVE_FAILURES) {
|
|
16324
|
+
investigateAuditLog(
|
|
16325
|
+
`tail aborted after ${consecutiveFailures} consecutive update failures (last: ${resp.description ?? "unknown"})`
|
|
16326
|
+
);
|
|
16327
|
+
break;
|
|
16328
|
+
}
|
|
16329
|
+
} catch (err) {
|
|
16330
|
+
consecutiveFailures++;
|
|
16331
|
+
if (consecutiveFailures >= INVESTIGATE_TAIL_MAX_CONSECUTIVE_FAILURES) {
|
|
16332
|
+
investigateAuditLog(
|
|
16333
|
+
`tail aborted after ${consecutiveFailures} consecutive update failures (last: ${redactAugmentedPaths(err.message)})`
|
|
16334
|
+
);
|
|
16335
|
+
break;
|
|
16336
|
+
}
|
|
16337
|
+
}
|
|
16338
|
+
}
|
|
16339
|
+
} finally {
|
|
16340
|
+
investigateTailSlot.release();
|
|
16341
|
+
try {
|
|
16342
|
+
await telegramApiCall(
|
|
16343
|
+
"editMessageText",
|
|
16344
|
+
{
|
|
16345
|
+
chat_id: opts.chatId,
|
|
16346
|
+
message_id: opts.messageId,
|
|
16347
|
+
text: formatPaneSnapshot({
|
|
16348
|
+
codeName: AGENT_CODE_NAME,
|
|
16349
|
+
text: last.body,
|
|
16350
|
+
source: last.source,
|
|
16351
|
+
capturedAtLabel: last.capturedAtLabel,
|
|
16352
|
+
status: { kind: "expired" },
|
|
16353
|
+
maxChars: INVESTIGATE_MAX_CHARS,
|
|
16354
|
+
commandName: investigateCmd
|
|
16355
|
+
}),
|
|
16356
|
+
parse_mode: "Markdown"
|
|
16357
|
+
},
|
|
16358
|
+
1e4
|
|
16359
|
+
);
|
|
16360
|
+
} catch (err) {
|
|
16361
|
+
investigateAuditLog(`expired-edit failed: ${redactAugmentedPaths(err.message)}`);
|
|
16362
|
+
}
|
|
16363
|
+
}
|
|
16364
|
+
}
|
|
16365
|
+
async function handleInvestigateCommand(opts) {
|
|
16366
|
+
const investigateCmd = `/investigate-${AGENT_CODE_NAME}`;
|
|
16367
|
+
const emitAudit = (outcome, reason) => {
|
|
16368
|
+
diagnosticEventClient?.emit({
|
|
16369
|
+
channel: "telegram",
|
|
16370
|
+
command: "investigate",
|
|
16371
|
+
outcome,
|
|
16372
|
+
reason,
|
|
16373
|
+
chat_id: opts.chatId,
|
|
16374
|
+
sender_chat_id: opts.senderId
|
|
16375
|
+
});
|
|
16376
|
+
};
|
|
16377
|
+
const verdict = evaluateInvestigateGate({
|
|
16378
|
+
chatType: opts.chatType,
|
|
16379
|
+
senderId: opts.senderId,
|
|
16380
|
+
diagnosticChatIds: DIAGNOSTIC_CHAT_IDS
|
|
16381
|
+
});
|
|
16382
|
+
if (!verdict.ok) {
|
|
16383
|
+
investigateAuditLog(
|
|
16384
|
+
`denied reason=${verdict.reason} sender=${opts.senderId ? redactId(opts.senderId) : "unknown"}`
|
|
16385
|
+
);
|
|
16386
|
+
emitAudit("denied", verdict.reason);
|
|
16387
|
+
const denialText = verdict.reason === "not-dm" ? `\u26A0\uFE0F \`${investigateCmd}\` only works in a direct message with \`${AGENT_CODE_NAME}\` \u2014 it shows the agent's raw terminal, so it stays 1:1. Open a DM with the bot and run it there.` : verdict.reason === "allowlist-empty" ? `\u{1F6AB} \`${investigateCmd}\` is disabled for \`${AGENT_CODE_NAME}\` \u2014 no diagnostic allowlist reached this host. It is derived from team owners/admins and the agent's reports-to person; if that's you, link your Telegram in your Augmented Team contact preferences and wait for the next refresh.` : `\u{1F6AB} \`${investigateCmd}\` denied \u2014 it's limited to team owners/admins and the person this agent reports to. If that's you, link your Telegram in your Augmented Team contact preferences and wait for the next refresh.`;
|
|
16388
|
+
await sendInvestigateReply(opts.chatId, opts.messageId, denialText);
|
|
16389
|
+
return;
|
|
16390
|
+
}
|
|
16391
|
+
const reservedExpiresAtMs = investigateTailSlot.reserve(INVESTIGATE_TAIL_WINDOW_MS);
|
|
16392
|
+
if (reservedExpiresAtMs === null) {
|
|
16393
|
+
const remaining = formatCountdown(investigateTailSlot.remainingMs() / 1e3);
|
|
16394
|
+
investigateAuditLog(
|
|
16395
|
+
`not-started reason=tail-already-running sender=${redactId(opts.senderId ?? "unknown")} remaining=${remaining}`
|
|
16396
|
+
);
|
|
16397
|
+
emitAudit("not_started", "tail-already-running");
|
|
16398
|
+
await sendInvestigateReply(
|
|
16399
|
+
opts.chatId,
|
|
16400
|
+
opts.messageId,
|
|
16401
|
+
`\u23F3 A \`${investigateCmd}\` tail is already running for \`${AGENT_CODE_NAME}\` (one at a time) \u2014 it expires in ${remaining}.`
|
|
16402
|
+
);
|
|
16403
|
+
return;
|
|
16404
|
+
}
|
|
16405
|
+
const snapshot = await capturePaneSnapshot({
|
|
16406
|
+
codeName: AGENT_CODE_NAME,
|
|
16407
|
+
agentDir: TELEGRAM_AGENT_DIR
|
|
16408
|
+
});
|
|
16409
|
+
if (!snapshot) {
|
|
16410
|
+
investigateTailSlot.release();
|
|
16411
|
+
investigateAuditLog(`not-started reason=no-pane-output sender=${redactId(opts.senderId ?? "unknown")}`);
|
|
16412
|
+
emitAudit("not_started", "no-pane-output");
|
|
16413
|
+
await sendInvestigateReply(
|
|
16414
|
+
opts.chatId,
|
|
16415
|
+
opts.messageId,
|
|
16416
|
+
`\u26A0\uFE0F No pane output available for \`${AGENT_CODE_NAME}\` yet \u2014 the agent session may not have started. (If the whole host is wedged, \`${investigateCmd}\` can't reach it either \u2014 fall back to the SSM diagnostics runbook.)`
|
|
16417
|
+
);
|
|
16418
|
+
return;
|
|
16419
|
+
}
|
|
16420
|
+
investigateAuditLog(`granted sender=${redactId(opts.senderId ?? "unknown")} \u2014 starting live tail (source=${snapshot.source})`);
|
|
16421
|
+
emitAudit("granted", null);
|
|
16422
|
+
const initialFrame = {
|
|
16423
|
+
body: redactPaneText(snapshot.text),
|
|
16424
|
+
source: snapshot.source,
|
|
16425
|
+
capturedAtLabel: investigateNowUtcLabel()
|
|
16426
|
+
};
|
|
16427
|
+
let postedMessageId = null;
|
|
16428
|
+
try {
|
|
16429
|
+
const posted = await telegramApiCall(
|
|
16430
|
+
"sendMessage",
|
|
16431
|
+
{
|
|
16432
|
+
chat_id: opts.chatId,
|
|
16433
|
+
text: formatPaneSnapshot({
|
|
16434
|
+
codeName: AGENT_CODE_NAME,
|
|
16435
|
+
text: initialFrame.body,
|
|
16436
|
+
source: initialFrame.source,
|
|
16437
|
+
capturedAtLabel: initialFrame.capturedAtLabel,
|
|
16438
|
+
status: {
|
|
16439
|
+
kind: "live",
|
|
16440
|
+
secondsRemaining: Math.max(0, Math.round((reservedExpiresAtMs - Date.now()) / 1e3))
|
|
16441
|
+
},
|
|
16442
|
+
maxChars: INVESTIGATE_MAX_CHARS,
|
|
16443
|
+
commandName: investigateCmd
|
|
16444
|
+
}),
|
|
16445
|
+
parse_mode: "Markdown",
|
|
16446
|
+
reply_to_message_id: Number(opts.messageId)
|
|
16447
|
+
},
|
|
16448
|
+
1e4
|
|
16449
|
+
);
|
|
16450
|
+
const result = posted.result;
|
|
16451
|
+
if (posted.ok && typeof result?.message_id === "number") {
|
|
16452
|
+
postedMessageId = result.message_id;
|
|
16453
|
+
} else {
|
|
16454
|
+
investigateAuditLog(`not-started reason=post-failed error=${posted.description ?? "unknown"}`);
|
|
16455
|
+
}
|
|
16456
|
+
} catch (err) {
|
|
16457
|
+
investigateAuditLog(`not-started reason=post-failed error=${redactAugmentedPaths(err.message)}`);
|
|
16458
|
+
}
|
|
16459
|
+
if (postedMessageId === null) {
|
|
16460
|
+
investigateTailSlot.release();
|
|
16461
|
+
await sendInvestigateReply(
|
|
16462
|
+
opts.chatId,
|
|
16463
|
+
opts.messageId,
|
|
16464
|
+
`\u274C Failed to post the pane snapshot. Try again in a moment.`
|
|
16465
|
+
);
|
|
16466
|
+
return;
|
|
16467
|
+
}
|
|
16468
|
+
void runInvestigateTailLoop({
|
|
16469
|
+
chatId: opts.chatId,
|
|
16470
|
+
messageId: postedMessageId,
|
|
16471
|
+
initialFrame,
|
|
16472
|
+
expiresAtMs: reservedExpiresAtMs
|
|
16473
|
+
}).catch((err) => {
|
|
16474
|
+
investigateTailSlot.release();
|
|
16475
|
+
investigateAuditLog(`tail loop crashed: ${redactAugmentedPaths(err.message)}`);
|
|
16476
|
+
});
|
|
16477
|
+
}
|
|
15976
16478
|
var cachedBotUsername = null;
|
|
15977
16479
|
var cachedBotId = null;
|
|
15978
16480
|
async function refreshBotIdentity() {
|
|
@@ -17204,6 +17706,35 @@ async function pollLoop() {
|
|
|
17204
17706
|
} catch (err) {
|
|
17205
17707
|
process.stderr.write(
|
|
17206
17708
|
`telegram-channel(${AGENT_CODE_NAME}): /restart verification-failed ack send failed: ${redactAugmentedPaths(err.message)}
|
|
17709
|
+
`
|
|
17710
|
+
);
|
|
17711
|
+
}
|
|
17712
|
+
}
|
|
17713
|
+
continue;
|
|
17714
|
+
}
|
|
17715
|
+
if (isInvestigateSyntax(trimmedContent)) {
|
|
17716
|
+
const disposition = await classifyInvestigateCommand(trimmedContent);
|
|
17717
|
+
if (disposition === "act") {
|
|
17718
|
+
await handleInvestigateCommand({
|
|
17719
|
+
chatId,
|
|
17720
|
+
messageId: String(msg.message_id),
|
|
17721
|
+
chatType: msg.chat.type ?? null,
|
|
17722
|
+
senderId: msg.from?.id != null ? String(msg.from.id) : null
|
|
17723
|
+
});
|
|
17724
|
+
} else if (disposition === "verification_failed") {
|
|
17725
|
+
try {
|
|
17726
|
+
await telegramApiCall(
|
|
17727
|
+
"sendMessage",
|
|
17728
|
+
{
|
|
17729
|
+
chat_id: chatId,
|
|
17730
|
+
text: `\u274C Couldn't verify the investigate target. Please retry in a few seconds.`,
|
|
17731
|
+
reply_to_message_id: Number(msg.message_id)
|
|
17732
|
+
},
|
|
17733
|
+
1e4
|
|
17734
|
+
);
|
|
17735
|
+
} catch (err) {
|
|
17736
|
+
process.stderr.write(
|
|
17737
|
+
`telegram-channel(${AGENT_CODE_NAME}): /investigate verification-failed ack send failed: ${redactAugmentedPaths(err.message)}
|
|
17207
17738
|
`
|
|
17208
17739
|
);
|
|
17209
17740
|
}
|