@integrity-labs/agt-cli 0.27.9-test.13 → 0.27.9-test.14
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/bin/agt.js +4 -4
- package/dist/chunk-354FAVQR.js +173 -0
- package/dist/chunk-354FAVQR.js.map +1 -0
- package/dist/{chunk-MQJ5DMPT.js → chunk-7GKJZBTB.js} +111 -204
- package/dist/chunk-7GKJZBTB.js.map +1 -0
- package/dist/{chunk-HR5T2RQF.js → chunk-I3YS5WFV.js} +3 -1
- package/dist/chunk-I3YS5WFV.js.map +1 -0
- package/dist/{chunk-VNIHFGA2.js → chunk-R7NKCGWN.js} +341 -46
- package/dist/chunk-R7NKCGWN.js.map +1 -0
- package/dist/{chunk-I2OTQJH3.js → chunk-WOOYOAPG.js} +2644 -2142
- package/dist/chunk-WOOYOAPG.js.map +1 -0
- package/dist/{claude-pair-runtime-F6USL3EW.js → claude-pair-runtime-GIUCD7IG.js} +2 -2
- package/dist/{claude-scheduler-EM24LTGV.js → claude-scheduler-FATCLHDM.js} +2 -2
- package/dist/daily-session-PNQX5URX.js +27 -0
- package/dist/lib/manager-worker.js +1125 -149
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/augmented-admin.js +21335 -0
- package/dist/mcp/index.js +121 -4
- package/dist/mcp/slack-channel.js +845 -208
- package/dist/mcp/teams-channel.js +73 -29
- package/dist/mcp/telegram-channel.js +579 -157
- package/dist/{persistent-session-OL5EDYB4.js → persistent-session-35PWSTLO.js} +10 -3
- package/dist/persistent-session-35PWSTLO.js.map +1 -0
- package/dist/responsiveness-probe-MA4M2QM4.js +158 -0
- package/dist/responsiveness-probe-MA4M2QM4.js.map +1 -0
- package/package.json +3 -2
- package/dist/chunk-HR5T2RQF.js.map +0 -1
- package/dist/chunk-I2OTQJH3.js.map +0 -1
- package/dist/chunk-MQJ5DMPT.js.map +0 -1
- package/dist/chunk-VNIHFGA2.js.map +0 -1
- package/dist/responsiveness-probe-B6LJJRUD.js +0 -74
- package/dist/responsiveness-probe-B6LJJRUD.js.map +0 -1
- /package/dist/{claude-pair-runtime-F6USL3EW.js.map → claude-pair-runtime-GIUCD7IG.js.map} +0 -0
- /package/dist/{claude-scheduler-EM24LTGV.js.map → claude-scheduler-FATCLHDM.js.map} +0 -0
- /package/dist/{persistent-session-OL5EDYB4.js.map → daily-session-PNQX5URX.js.map} +0 -0
|
@@ -14180,6 +14180,47 @@ var Server = class extends Protocol {
|
|
|
14180
14180
|
}
|
|
14181
14181
|
};
|
|
14182
14182
|
|
|
14183
|
+
// src/restart-confirm.ts
|
|
14184
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
14185
|
+
import { dirname } from "path";
|
|
14186
|
+
import { randomUUID } from "crypto";
|
|
14187
|
+
var RESTART_CONFIRM_MAX_AGE_MS = 10 * 60 * 1e3;
|
|
14188
|
+
function shouldPostRestartConfirm(marker, processBootMs, nowMs) {
|
|
14189
|
+
if (!marker) return false;
|
|
14190
|
+
const requestedAt = marker.requested_at;
|
|
14191
|
+
if (typeof requestedAt !== "number" || !Number.isFinite(requestedAt)) return false;
|
|
14192
|
+
if (requestedAt >= processBootMs) return false;
|
|
14193
|
+
if (nowMs - requestedAt > RESTART_CONFIRM_MAX_AGE_MS) return false;
|
|
14194
|
+
return true;
|
|
14195
|
+
}
|
|
14196
|
+
function buildBackOnlineText(name) {
|
|
14197
|
+
const trimmed = typeof name === "string" ? name.trim() : "";
|
|
14198
|
+
return trimmed ? `Hey ${trimmed}, I'm back online after my restart. \u{1F7E2}` : `I'm back online after my restart. \u{1F7E2}`;
|
|
14199
|
+
}
|
|
14200
|
+
function writeRestartConfirmMarker(filePath, marker) {
|
|
14201
|
+
const dir = dirname(filePath);
|
|
14202
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 448 });
|
|
14203
|
+
const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
14204
|
+
writeFileSync(tmpPath, JSON.stringify(marker) + "\n", { encoding: "utf8", mode: 384 });
|
|
14205
|
+
renameSync(tmpPath, filePath);
|
|
14206
|
+
}
|
|
14207
|
+
function readRestartConfirmMarker(filePath) {
|
|
14208
|
+
try {
|
|
14209
|
+
if (!existsSync(filePath)) return null;
|
|
14210
|
+
const parsed = JSON.parse(readFileSync(filePath, "utf8"));
|
|
14211
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
14212
|
+
return parsed;
|
|
14213
|
+
} catch {
|
|
14214
|
+
return null;
|
|
14215
|
+
}
|
|
14216
|
+
}
|
|
14217
|
+
function clearRestartConfirmMarker(filePath) {
|
|
14218
|
+
try {
|
|
14219
|
+
if (existsSync(filePath)) unlinkSync(filePath);
|
|
14220
|
+
} catch {
|
|
14221
|
+
}
|
|
14222
|
+
}
|
|
14223
|
+
|
|
14183
14224
|
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
14184
14225
|
import process2 from "process";
|
|
14185
14226
|
|
|
@@ -14274,21 +14315,21 @@ var StdioServerTransport = class {
|
|
|
14274
14315
|
|
|
14275
14316
|
// src/telegram-channel.ts
|
|
14276
14317
|
import https from "https";
|
|
14277
|
-
import { createHash, randomUUID } from "crypto";
|
|
14318
|
+
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
14278
14319
|
import {
|
|
14279
14320
|
createWriteStream,
|
|
14280
|
-
existsSync as
|
|
14281
|
-
mkdirSync as
|
|
14282
|
-
readFileSync as
|
|
14321
|
+
existsSync as existsSync4,
|
|
14322
|
+
mkdirSync as mkdirSync4,
|
|
14323
|
+
readFileSync as readFileSync5,
|
|
14283
14324
|
readdirSync as readdirSync2,
|
|
14284
|
-
renameSync as
|
|
14325
|
+
renameSync as renameSync4,
|
|
14285
14326
|
statSync,
|
|
14286
|
-
unlinkSync as
|
|
14327
|
+
unlinkSync as unlinkSync4,
|
|
14287
14328
|
watch,
|
|
14288
|
-
writeFileSync as
|
|
14329
|
+
writeFileSync as writeFileSync4
|
|
14289
14330
|
} from "fs";
|
|
14290
14331
|
import { homedir as homedir2 } from "os";
|
|
14291
|
-
import { join as
|
|
14332
|
+
import { join as join5 } from "path";
|
|
14292
14333
|
|
|
14293
14334
|
// src/channel-attachments.ts
|
|
14294
14335
|
import { homedir } from "os";
|
|
@@ -14412,7 +14453,7 @@ function redactAugmentedPaths(msg) {
|
|
|
14412
14453
|
}
|
|
14413
14454
|
|
|
14414
14455
|
// src/telegram-attachments.ts
|
|
14415
|
-
import { mkdirSync, writeFileSync, chmodSync, renameSync, unlinkSync } from "fs";
|
|
14456
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, chmodSync, renameSync as renameSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
14416
14457
|
function resolveTelegramInboundDir(codeName) {
|
|
14417
14458
|
return resolveChannelInboundDir(codeName, "telegram-inbound");
|
|
14418
14459
|
}
|
|
@@ -14501,18 +14542,18 @@ async function downloadTelegramFile(fileId, opts) {
|
|
|
14501
14542
|
if (!isPathInside(savedPath, dir)) {
|
|
14502
14543
|
throw new Error(`refusing to write ${savedPath} outside ${dir}`);
|
|
14503
14544
|
}
|
|
14504
|
-
|
|
14545
|
+
mkdirSync2(dir, { recursive: true });
|
|
14505
14546
|
const tempPath = `${savedPath}.${process.pid}.${Date.now()}.tmp`;
|
|
14506
14547
|
try {
|
|
14507
|
-
|
|
14548
|
+
writeFileSync2(tempPath, bytes, { mode: 384, flag: "wx" });
|
|
14508
14549
|
try {
|
|
14509
14550
|
chmodSync(tempPath, 384);
|
|
14510
14551
|
} catch {
|
|
14511
14552
|
}
|
|
14512
|
-
|
|
14553
|
+
renameSync2(tempPath, savedPath);
|
|
14513
14554
|
} catch (err) {
|
|
14514
14555
|
try {
|
|
14515
|
-
|
|
14556
|
+
unlinkSync2(tempPath);
|
|
14516
14557
|
} catch {
|
|
14517
14558
|
}
|
|
14518
14559
|
throw err;
|
|
@@ -14772,6 +14813,61 @@ function parsePeerAgentModeEnv(raw) {
|
|
|
14772
14813
|
return "off";
|
|
14773
14814
|
}
|
|
14774
14815
|
|
|
14816
|
+
// src/sender-policy-decline.ts
|
|
14817
|
+
function politeDeclineCopy(reason) {
|
|
14818
|
+
switch (reason) {
|
|
14819
|
+
case "internal_only":
|
|
14820
|
+
return "Sorry, I can only respond to people inside our organisation. This conversation appears to be from outside.";
|
|
14821
|
+
case "mode_manager_only":
|
|
14822
|
+
return "Sorry, I only respond to my manager in this channel.";
|
|
14823
|
+
case "mode_team_only":
|
|
14824
|
+
return "Sorry, this agent only replies to its team members.";
|
|
14825
|
+
case "mode_team_agents_only":
|
|
14826
|
+
return "Sorry, I only respond to agents on my team in this channel.";
|
|
14827
|
+
case "mode_agents_only":
|
|
14828
|
+
return "Sorry, I only respond to other agents in this channel.";
|
|
14829
|
+
}
|
|
14830
|
+
}
|
|
14831
|
+
|
|
14832
|
+
// src/inbound-access.ts
|
|
14833
|
+
function decideInboundAccess(input) {
|
|
14834
|
+
if (!input.content.forward) {
|
|
14835
|
+
return { kind: "drop", reason: `content:${input.content.reason}` };
|
|
14836
|
+
}
|
|
14837
|
+
if (input.isSelf) {
|
|
14838
|
+
return { kind: "drop", reason: "self" };
|
|
14839
|
+
}
|
|
14840
|
+
if (input.orgBoundary && !input.orgBoundary.forward) {
|
|
14841
|
+
return { kind: "drop", reason: "org_boundary" };
|
|
14842
|
+
}
|
|
14843
|
+
if (input.senderPolicy && !input.senderPolicy.forward) {
|
|
14844
|
+
const reason = input.senderPolicy.reason;
|
|
14845
|
+
const declineWorthy = input.sameOrg && reason !== "internal_only";
|
|
14846
|
+
return {
|
|
14847
|
+
kind: "drop",
|
|
14848
|
+
reason: `sender_policy:${reason}`,
|
|
14849
|
+
decline: declineWorthy ? politeDeclineCopy(reason) : void 0
|
|
14850
|
+
};
|
|
14851
|
+
}
|
|
14852
|
+
if (input.command && !input.isBot) {
|
|
14853
|
+
return {
|
|
14854
|
+
kind: "command",
|
|
14855
|
+
command: input.command.command,
|
|
14856
|
+
authorized: input.command.authorized
|
|
14857
|
+
};
|
|
14858
|
+
}
|
|
14859
|
+
if (input.isBot) {
|
|
14860
|
+
const peer = input.peer;
|
|
14861
|
+
if (!peer || peer.kind === "self") {
|
|
14862
|
+
return { kind: "drop", reason: peer?.kind === "self" ? "self" : "peer:unclassified" };
|
|
14863
|
+
}
|
|
14864
|
+
if (peer.kind === "drop") {
|
|
14865
|
+
return { kind: "drop", reason: `peer:${peer.reason ?? "unspecified"}` };
|
|
14866
|
+
}
|
|
14867
|
+
}
|
|
14868
|
+
return { kind: "admit" };
|
|
14869
|
+
}
|
|
14870
|
+
|
|
14775
14871
|
// src/telegram-peer-rate-limiter.ts
|
|
14776
14872
|
var SECOND_MS = 1e3;
|
|
14777
14873
|
var MINUTE_MS = 60 * SECOND_MS;
|
|
@@ -15269,6 +15365,10 @@ var HELP = {
|
|
|
15269
15365
|
command: "help",
|
|
15270
15366
|
description: "Show available commands"
|
|
15271
15367
|
};
|
|
15368
|
+
var STATUS = {
|
|
15369
|
+
command: "status",
|
|
15370
|
+
description: "Show this agent\u2019s model, session origin + uptime"
|
|
15371
|
+
};
|
|
15272
15372
|
var RESTART = {
|
|
15273
15373
|
command: "restart",
|
|
15274
15374
|
description: "Restart this agent"
|
|
@@ -15279,11 +15379,86 @@ var INVESTIGATE = {
|
|
|
15279
15379
|
};
|
|
15280
15380
|
function buildCommandRegistrations() {
|
|
15281
15381
|
return [
|
|
15282
|
-
{ scope: { type: "default" }, commands: [HELP, RESTART] },
|
|
15283
|
-
{ scope: { type: "all_private_chats" }, commands: [HELP, RESTART, INVESTIGATE] }
|
|
15382
|
+
{ scope: { type: "default" }, commands: [HELP, STATUS, RESTART] },
|
|
15383
|
+
{ scope: { type: "all_private_chats" }, commands: [HELP, STATUS, RESTART, INVESTIGATE] }
|
|
15284
15384
|
];
|
|
15285
15385
|
}
|
|
15286
15386
|
|
|
15387
|
+
// src/agent-config-state.ts
|
|
15388
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
15389
|
+
import { join as join2 } from "path";
|
|
15390
|
+
var SESSION_STATE_FILENAME = "session-state.json";
|
|
15391
|
+
function readAgentSessionState(stateDir) {
|
|
15392
|
+
if (!stateDir) return null;
|
|
15393
|
+
const path = join2(stateDir, SESSION_STATE_FILENAME);
|
|
15394
|
+
if (!existsSync2(path)) return null;
|
|
15395
|
+
try {
|
|
15396
|
+
const parsed = JSON.parse(readFileSync2(path, "utf-8"));
|
|
15397
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
15398
|
+
return parsed;
|
|
15399
|
+
} catch {
|
|
15400
|
+
return null;
|
|
15401
|
+
}
|
|
15402
|
+
}
|
|
15403
|
+
function describeSessionOrigin(source) {
|
|
15404
|
+
switch (source) {
|
|
15405
|
+
case "startup":
|
|
15406
|
+
return "fresh start";
|
|
15407
|
+
case "resume":
|
|
15408
|
+
return "resumed";
|
|
15409
|
+
case "clear":
|
|
15410
|
+
return "cleared (/clear)";
|
|
15411
|
+
case "compact":
|
|
15412
|
+
return "compacted";
|
|
15413
|
+
default:
|
|
15414
|
+
return "unknown";
|
|
15415
|
+
}
|
|
15416
|
+
}
|
|
15417
|
+
function formatModelLabel(model) {
|
|
15418
|
+
const trimmed = model?.trim();
|
|
15419
|
+
return trimmed && trimmed.length > 0 ? trimmed : "unknown";
|
|
15420
|
+
}
|
|
15421
|
+
function shortSessionId(id) {
|
|
15422
|
+
const trimmed = id?.trim();
|
|
15423
|
+
if (!trimmed) return "unknown";
|
|
15424
|
+
return trimmed.length > 8 ? trimmed.slice(0, 8) : trimmed;
|
|
15425
|
+
}
|
|
15426
|
+
function formatRelativeAge(ts, now = Date.now()) {
|
|
15427
|
+
if (typeof ts !== "number" || !Number.isFinite(ts) || ts <= 0) return "unknown";
|
|
15428
|
+
const seconds = Math.floor((now - ts) / 1e3);
|
|
15429
|
+
if (seconds < 0) return "unknown";
|
|
15430
|
+
if (seconds < 5) return "just now";
|
|
15431
|
+
if (seconds < 60) return `${seconds}s ago`;
|
|
15432
|
+
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
|
|
15433
|
+
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
|
|
15434
|
+
return `${Math.floor(seconds / 86400)}d ago`;
|
|
15435
|
+
}
|
|
15436
|
+
function formatChannels(channels) {
|
|
15437
|
+
if (!Array.isArray(channels) || channels.length === 0) return "unknown";
|
|
15438
|
+
const cleaned = channels.map((c) => String(c).trim()).filter((c) => c.length > 0);
|
|
15439
|
+
return cleaned.length > 0 ? cleaned.join(", ") : "unknown";
|
|
15440
|
+
}
|
|
15441
|
+
function buildAgentConfigReport(opts) {
|
|
15442
|
+
const { codeName, connectivityLine, state, now = Date.now() } = opts;
|
|
15443
|
+
const lines = [`\u{1F916} *Config for \`${codeName}\`*`, connectivityLine];
|
|
15444
|
+
if (!state) {
|
|
15445
|
+
lines.push("\u2022 *Model:* unknown \u2014 session state not recorded yet");
|
|
15446
|
+
lines.push("\u2022 *Session:* unknown");
|
|
15447
|
+
return lines.join("\n");
|
|
15448
|
+
}
|
|
15449
|
+
lines.push(`\u2022 *Model:* \`${formatModelLabel(state.model)}\``);
|
|
15450
|
+
const origin = describeSessionOrigin(state.source);
|
|
15451
|
+
const age = formatRelativeAge(state.recorded_at, now);
|
|
15452
|
+
const sessionLine = age === "unknown" ? `\u2022 *Session:* ${origin}` : `\u2022 *Session:* ${origin} \xB7 started ${age}`;
|
|
15453
|
+
lines.push(sessionLine);
|
|
15454
|
+
lines.push(`\u2022 *Session ID:* \`${shortSessionId(state.session_id)}\``);
|
|
15455
|
+
if (state.environment && state.environment.trim().length > 0) {
|
|
15456
|
+
lines.push(`\u2022 *Environment:* ${state.environment.trim()}`);
|
|
15457
|
+
}
|
|
15458
|
+
lines.push(`\u2022 *Channels:* ${formatChannels(state.channels)}`);
|
|
15459
|
+
return lines.join("\n");
|
|
15460
|
+
}
|
|
15461
|
+
|
|
15287
15462
|
// src/pane-tail.ts
|
|
15288
15463
|
import { execFile } from "child_process";
|
|
15289
15464
|
import { promisify } from "util";
|
|
@@ -15733,14 +15908,14 @@ var TELEGRAM_EGRESS_TOOLS = /* @__PURE__ */ new Set([
|
|
|
15733
15908
|
|
|
15734
15909
|
// src/mcp-spawn-lock.ts
|
|
15735
15910
|
import {
|
|
15736
|
-
existsSync,
|
|
15737
|
-
mkdirSync as
|
|
15738
|
-
readFileSync,
|
|
15739
|
-
renameSync as
|
|
15740
|
-
unlinkSync as
|
|
15741
|
-
writeFileSync as
|
|
15911
|
+
existsSync as existsSync3,
|
|
15912
|
+
mkdirSync as mkdirSync3,
|
|
15913
|
+
readFileSync as readFileSync3,
|
|
15914
|
+
renameSync as renameSync3,
|
|
15915
|
+
unlinkSync as unlinkSync3,
|
|
15916
|
+
writeFileSync as writeFileSync3
|
|
15742
15917
|
} from "fs";
|
|
15743
|
-
import { join as
|
|
15918
|
+
import { join as join3 } from "path";
|
|
15744
15919
|
function defaultIsPidAlive(pid) {
|
|
15745
15920
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
15746
15921
|
try {
|
|
@@ -15758,7 +15933,7 @@ function acquireMcpSpawnLock(args) {
|
|
|
15758
15933
|
const isPidAlive = options.isPidAlive ?? defaultIsPidAlive;
|
|
15759
15934
|
const selfPid = options.selfPid ?? process.pid;
|
|
15760
15935
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
15761
|
-
const path =
|
|
15936
|
+
const path = join3(agentDir, basename);
|
|
15762
15937
|
const existing = readLockHolder(path);
|
|
15763
15938
|
if (existing) {
|
|
15764
15939
|
if (existing.pid === selfPid) {
|
|
@@ -15768,11 +15943,11 @@ function acquireMcpSpawnLock(args) {
|
|
|
15768
15943
|
return { kind: "blocked", path, holder: existing };
|
|
15769
15944
|
}
|
|
15770
15945
|
}
|
|
15771
|
-
|
|
15946
|
+
mkdirSync3(agentDir, { recursive: true, mode: 448 });
|
|
15772
15947
|
const tmpPath = `${path}.${selfPid}.tmp`;
|
|
15773
15948
|
const payload = { pid: selfPid, started_at: now() };
|
|
15774
|
-
|
|
15775
|
-
|
|
15949
|
+
writeFileSync3(tmpPath, JSON.stringify(payload), { mode: 384 });
|
|
15950
|
+
renameSync3(tmpPath, path);
|
|
15776
15951
|
return { kind: "acquired", path };
|
|
15777
15952
|
}
|
|
15778
15953
|
function releaseMcpSpawnLock(lockPath, opts = {}) {
|
|
@@ -15782,14 +15957,14 @@ function releaseMcpSpawnLock(lockPath, opts = {}) {
|
|
|
15782
15957
|
if (!existing) return;
|
|
15783
15958
|
if (existing.pid !== selfPid) return;
|
|
15784
15959
|
try {
|
|
15785
|
-
|
|
15960
|
+
unlinkSync3(lockPath);
|
|
15786
15961
|
} catch {
|
|
15787
15962
|
}
|
|
15788
15963
|
}
|
|
15789
15964
|
function readLockHolder(path) {
|
|
15790
|
-
if (!
|
|
15965
|
+
if (!existsSync3(path)) return null;
|
|
15791
15966
|
try {
|
|
15792
|
-
const raw =
|
|
15967
|
+
const raw = readFileSync3(path, "utf8");
|
|
15793
15968
|
const parsed = JSON.parse(raw);
|
|
15794
15969
|
const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
|
|
15795
15970
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
@@ -15801,8 +15976,8 @@ function readLockHolder(path) {
|
|
|
15801
15976
|
}
|
|
15802
15977
|
|
|
15803
15978
|
// src/ack-reaction.ts
|
|
15804
|
-
import { readdirSync, readFileSync as
|
|
15805
|
-
import { join as
|
|
15979
|
+
import { readdirSync, readFileSync as readFileSync4 } from "fs";
|
|
15980
|
+
import { join as join4 } from "path";
|
|
15806
15981
|
var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
15807
15982
|
var ACK_STARTUP_GRACE_MS = 6e4;
|
|
15808
15983
|
var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
|
|
@@ -15832,12 +16007,35 @@ function shouldPostUndeliverableNotice(lastNoticeAtMs, nowMs, throttleMs = UNDEL
|
|
|
15832
16007
|
function undeliverableNoticeText() {
|
|
15833
16008
|
return "\u23F3 I can't get to this right now. Please resend in a few minutes \u2014 I may not see this one.";
|
|
15834
16009
|
}
|
|
16010
|
+
var BUSY_ACK_THRESHOLD_MS = 9e4;
|
|
16011
|
+
var BUSY_ACK_NOTICE_THROTTLE_MS = 10 * 60 * 1e3;
|
|
16012
|
+
function channelBusyAckEnabled() {
|
|
16013
|
+
const v = process.env.AGT_CHANNEL_BUSY_ACK_ENABLED;
|
|
16014
|
+
return v === "1" || v === "true";
|
|
16015
|
+
}
|
|
16016
|
+
function channelBusyAckThresholdMs() {
|
|
16017
|
+
const raw = parseInt(process.env.AGT_CHANNEL_BUSY_ACK_THRESHOLD_MS ?? "", 10);
|
|
16018
|
+
return Number.isFinite(raw) && raw > 0 ? raw : BUSY_ACK_THRESHOLD_MS;
|
|
16019
|
+
}
|
|
16020
|
+
function decideBusyAck(i) {
|
|
16021
|
+
if (!i.hasTarget) return false;
|
|
16022
|
+
if (!i.stillPending) return false;
|
|
16023
|
+
if (!Number.isFinite(i.pendingAgeMs)) return false;
|
|
16024
|
+
const threshold = i.thresholdMs ?? channelBusyAckThresholdMs();
|
|
16025
|
+
if (i.pendingAgeMs < threshold) return false;
|
|
16026
|
+
if (!i.sessionAlive) return false;
|
|
16027
|
+
const paneFreshThreshold = i.paneFreshThresholdMs ?? ACK_PANE_FRESH_THRESHOLD_MS;
|
|
16028
|
+
return i.paneLogFreshAgeMs != null && i.paneLogFreshAgeMs <= paneFreshThreshold;
|
|
16029
|
+
}
|
|
16030
|
+
function busyAckNoticeText() {
|
|
16031
|
+
return "\u{1F6E0}\uFE0F I'm in the middle of something right now \u2014 I'll follow up on this as soon as I'm free.";
|
|
16032
|
+
}
|
|
15835
16033
|
var GIVE_UP_SIGNAL_FILENAME = "watchdog-give-up.json";
|
|
15836
16034
|
var GIVE_UP_SIGNAL_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
15837
16035
|
function readGiveUpSignalAtMs(path, now = Date.now()) {
|
|
15838
16036
|
if (!path) return null;
|
|
15839
16037
|
try {
|
|
15840
|
-
const raw = JSON.parse(
|
|
16038
|
+
const raw = JSON.parse(readFileSync4(path, "utf8"));
|
|
15841
16039
|
if (typeof raw.gave_up_at !== "string") return null;
|
|
15842
16040
|
const t = Date.parse(raw.gave_up_at);
|
|
15843
16041
|
if (!Number.isFinite(t) || t > now) return null;
|
|
@@ -15869,7 +16067,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now()) {
|
|
|
15869
16067
|
if (!name.endsWith(".json")) continue;
|
|
15870
16068
|
let receivedAt;
|
|
15871
16069
|
try {
|
|
15872
|
-
const raw = JSON.parse(
|
|
16070
|
+
const raw = JSON.parse(readFileSync4(join4(dir, name), "utf-8"));
|
|
15873
16071
|
receivedAt = raw.received_at;
|
|
15874
16072
|
} catch {
|
|
15875
16073
|
continue;
|
|
@@ -15917,7 +16115,7 @@ function redactId(id) {
|
|
|
15917
16115
|
}
|
|
15918
16116
|
var BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
|
|
15919
16117
|
var AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME ?? "unknown";
|
|
15920
|
-
var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ?
|
|
16118
|
+
var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join5(homedir2(), ".augmented", AGENT_CODE_NAME) : null;
|
|
15921
16119
|
var AGT_HOST = process.env.AGT_HOST ?? null;
|
|
15922
16120
|
var AGT_API_KEY = process.env.AGT_API_KEY ?? null;
|
|
15923
16121
|
var AGT_AGENT_ID = process.env.AGT_AGENT_ID ?? null;
|
|
@@ -16011,9 +16209,9 @@ if (!BOT_TOKEN) {
|
|
|
16011
16209
|
var stderrLogStream = null;
|
|
16012
16210
|
if (AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown") {
|
|
16013
16211
|
try {
|
|
16014
|
-
const logDir =
|
|
16015
|
-
|
|
16016
|
-
stderrLogStream = createWriteStream(
|
|
16212
|
+
const logDir = join5(homedir2(), ".augmented", AGENT_CODE_NAME);
|
|
16213
|
+
mkdirSync4(logDir, { recursive: true });
|
|
16214
|
+
stderrLogStream = createWriteStream(join5(logDir, "telegram-channel-stderr.log"), {
|
|
16017
16215
|
flags: "a",
|
|
16018
16216
|
mode: 384
|
|
16019
16217
|
});
|
|
@@ -16161,13 +16359,138 @@ function notifyBackOnline(chatId) {
|
|
|
16161
16359
|
function __resetBackOnlineNoticeThrottle() {
|
|
16162
16360
|
lastBackOnlineNoticeAt.clear();
|
|
16163
16361
|
}
|
|
16164
|
-
var
|
|
16362
|
+
var lastBusyAckNoticeAt = /* @__PURE__ */ new Map();
|
|
16363
|
+
function postBusyAckNotice(chatId, messageId) {
|
|
16364
|
+
const key2 = String(chatId);
|
|
16365
|
+
const now = Date.now();
|
|
16366
|
+
if (!shouldPostUndeliverableNotice(lastBusyAckNoticeAt.get(key2), now, BUSY_ACK_NOTICE_THROTTLE_MS)) {
|
|
16367
|
+
return;
|
|
16368
|
+
}
|
|
16369
|
+
lastBusyAckNoticeAt.set(key2, now);
|
|
16370
|
+
void (async () => {
|
|
16371
|
+
try {
|
|
16372
|
+
const resp = await telegramApiCall(
|
|
16373
|
+
"sendMessage",
|
|
16374
|
+
{
|
|
16375
|
+
chat_id: chatId,
|
|
16376
|
+
text: busyAckNoticeText(),
|
|
16377
|
+
reply_to_message_id: Number(messageId),
|
|
16378
|
+
allow_sending_without_reply: true
|
|
16379
|
+
},
|
|
16380
|
+
1e4
|
|
16381
|
+
);
|
|
16382
|
+
if (!resp.ok) {
|
|
16383
|
+
process.stderr.write(
|
|
16384
|
+
`telegram-channel(${AGENT_CODE_NAME}): busy-ack notice failed (chat=${redactId(chatId)}): ${resp.description ?? "unknown"}
|
|
16385
|
+
`
|
|
16386
|
+
);
|
|
16387
|
+
}
|
|
16388
|
+
} catch (err) {
|
|
16389
|
+
process.stderr.write(
|
|
16390
|
+
`telegram-channel(${AGENT_CODE_NAME}): busy-ack notice error: ${err.message}
|
|
16391
|
+
`
|
|
16392
|
+
);
|
|
16393
|
+
}
|
|
16394
|
+
})();
|
|
16395
|
+
}
|
|
16396
|
+
function scheduleBusyAck(chatId, messageId) {
|
|
16397
|
+
if (!channelBusyAckEnabled()) return;
|
|
16398
|
+
const thresholdMs = channelBusyAckThresholdMs();
|
|
16399
|
+
const timer = setTimeout(() => {
|
|
16400
|
+
const probe = process.env.TMUX && AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? probeAgentSessionCached(AGENT_CODE_NAME) : { tmux: "unknown", claude: "unknown" };
|
|
16401
|
+
let paneLogFreshAgeMs = null;
|
|
16402
|
+
if (AGENT_DIR) {
|
|
16403
|
+
try {
|
|
16404
|
+
const paneMtimeMs = statSync(join5(AGENT_DIR, "pane.log")).mtimeMs;
|
|
16405
|
+
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
16406
|
+
} catch {
|
|
16407
|
+
}
|
|
16408
|
+
}
|
|
16409
|
+
const marker = readPendingInboundMarker(chatId, messageId);
|
|
16410
|
+
if (!marker) return;
|
|
16411
|
+
const post = decideBusyAck({
|
|
16412
|
+
hasTarget: Boolean(chatId && messageId),
|
|
16413
|
+
stillPending: true,
|
|
16414
|
+
pendingAgeMs: Math.max(0, Date.now() - Date.parse(marker.received_at)),
|
|
16415
|
+
sessionAlive: probe.tmux === "alive" && probe.claude === "alive",
|
|
16416
|
+
paneLogFreshAgeMs,
|
|
16417
|
+
thresholdMs
|
|
16418
|
+
});
|
|
16419
|
+
if (post) postBusyAckNotice(chatId, messageId);
|
|
16420
|
+
}, thresholdMs);
|
|
16421
|
+
timer.unref();
|
|
16422
|
+
}
|
|
16423
|
+
function __resetBusyAckNoticeThrottle() {
|
|
16424
|
+
lastBusyAckNoticeAt.clear();
|
|
16425
|
+
}
|
|
16426
|
+
var RESTART_FLAGS_DIR = join5(homedir2(), ".augmented", "restart-flags");
|
|
16427
|
+
function writeTelegramRestartConfirm(reply, requesterName) {
|
|
16428
|
+
if (!RESTART_CONFIRM_FILE) return;
|
|
16429
|
+
const marker = {
|
|
16430
|
+
source: "telegram",
|
|
16431
|
+
requested_at: Date.now(),
|
|
16432
|
+
...requesterName ? { requester_name: requesterName } : {},
|
|
16433
|
+
reply
|
|
16434
|
+
};
|
|
16435
|
+
try {
|
|
16436
|
+
writeRestartConfirmMarker(RESTART_CONFIRM_FILE, marker);
|
|
16437
|
+
} catch (err) {
|
|
16438
|
+
process.stderr.write(
|
|
16439
|
+
`telegram-channel(${AGENT_CODE_NAME}): restart-confirm marker write failed: ${redactAugmentedPaths(err.message)}
|
|
16440
|
+
`
|
|
16441
|
+
);
|
|
16442
|
+
}
|
|
16443
|
+
}
|
|
16444
|
+
async function notifyRestartCompleteOnBoot() {
|
|
16445
|
+
if (!RESTART_CONFIRM_FILE) return;
|
|
16446
|
+
const marker = readRestartConfirmMarker(RESTART_CONFIRM_FILE);
|
|
16447
|
+
if (!shouldPostRestartConfirm(marker, TELEGRAM_PROCESS_BOOT_MS, Date.now())) {
|
|
16448
|
+
if (marker) clearRestartConfirmMarker(RESTART_CONFIRM_FILE);
|
|
16449
|
+
return;
|
|
16450
|
+
}
|
|
16451
|
+
const chatId = marker.reply["chat_id"];
|
|
16452
|
+
if (chatId == null) {
|
|
16453
|
+
clearRestartConfirmMarker(RESTART_CONFIRM_FILE);
|
|
16454
|
+
return;
|
|
16455
|
+
}
|
|
16456
|
+
const messageId = marker.reply["message_id"];
|
|
16457
|
+
try {
|
|
16458
|
+
const resp = await telegramApiCall(
|
|
16459
|
+
"sendMessage",
|
|
16460
|
+
{
|
|
16461
|
+
chat_id: chatId,
|
|
16462
|
+
text: buildBackOnlineText(marker.requester_name),
|
|
16463
|
+
// Thread under the original /restart command when we have its id.
|
|
16464
|
+
...messageId != null ? { reply_to_message_id: Number(messageId), allow_sending_without_reply: true } : {}
|
|
16465
|
+
},
|
|
16466
|
+
1e4
|
|
16467
|
+
);
|
|
16468
|
+
if (resp.ok) {
|
|
16469
|
+
clearRestartConfirmMarker(RESTART_CONFIRM_FILE);
|
|
16470
|
+
process.stderr.write(
|
|
16471
|
+
`telegram-channel(${AGENT_CODE_NAME}): posted back-online confirmation after restart
|
|
16472
|
+
`
|
|
16473
|
+
);
|
|
16474
|
+
} else {
|
|
16475
|
+
process.stderr.write(
|
|
16476
|
+
`telegram-channel(${AGENT_CODE_NAME}): back-online confirmation rejected (chat=${redactId(chatId)}): ${resp.description ?? "unknown"}
|
|
16477
|
+
`
|
|
16478
|
+
);
|
|
16479
|
+
}
|
|
16480
|
+
} catch (err) {
|
|
16481
|
+
process.stderr.write(
|
|
16482
|
+
`telegram-channel(${AGENT_CODE_NAME}): back-online confirmation send failed: ${redactAugmentedPaths(err.message)}
|
|
16483
|
+
`
|
|
16484
|
+
);
|
|
16485
|
+
}
|
|
16486
|
+
}
|
|
16165
16487
|
function buildTelegramHelpMessage(codeName) {
|
|
16166
16488
|
return [
|
|
16167
16489
|
`\u{1F916} *Available commands for \`${codeName}\`*`,
|
|
16168
16490
|
"",
|
|
16169
16491
|
`_Type these in any chat where the bot is present (intercepted by the agent):_`,
|
|
16170
16492
|
`\u2022 /help \u2014 show this help`,
|
|
16493
|
+
`\u2022 /status \u2014 this agent's model, session origin, uptime + connectivity`,
|
|
16171
16494
|
`\u2022 /restart \u2014 restart this agent`,
|
|
16172
16495
|
`\u2022 /investigate-${codeName} \u2014 live tail of this agent's terminal pane (DM only; team owners/admins and the agent's reports-to person)`
|
|
16173
16496
|
].join("\n");
|
|
@@ -16197,21 +16520,58 @@ async function handleHelpCommand(opts) {
|
|
|
16197
16520
|
);
|
|
16198
16521
|
}
|
|
16199
16522
|
}
|
|
16523
|
+
function buildTelegramStatusReply() {
|
|
16524
|
+
const state = readAgentSessionState(TELEGRAM_AGENT_DIR);
|
|
16525
|
+
return buildAgentConfigReport({
|
|
16526
|
+
codeName: AGENT_CODE_NAME,
|
|
16527
|
+
connectivityLine: "\u{1F7E2} *online* \u2014 Telegram channel connected.",
|
|
16528
|
+
state
|
|
16529
|
+
});
|
|
16530
|
+
}
|
|
16531
|
+
async function handleStatusCommand(opts) {
|
|
16532
|
+
try {
|
|
16533
|
+
const resp = await telegramApiCall(
|
|
16534
|
+
"sendMessage",
|
|
16535
|
+
{
|
|
16536
|
+
chat_id: opts.chatId,
|
|
16537
|
+
text: buildTelegramStatusReply(),
|
|
16538
|
+
parse_mode: "Markdown",
|
|
16539
|
+
reply_to_message_id: Number(opts.messageId)
|
|
16540
|
+
},
|
|
16541
|
+
1e4
|
|
16542
|
+
);
|
|
16543
|
+
if (!resp.ok) {
|
|
16544
|
+
process.stderr.write(
|
|
16545
|
+
`telegram-channel(${AGENT_CODE_NAME}): /status reply rejected by Telegram (chat ${redactId(opts.chatId)}): ${resp.description ?? "unknown"}
|
|
16546
|
+
`
|
|
16547
|
+
);
|
|
16548
|
+
}
|
|
16549
|
+
} catch (err) {
|
|
16550
|
+
process.stderr.write(
|
|
16551
|
+
`telegram-channel(${AGENT_CODE_NAME}): /status reply send failed: ${redactAugmentedPaths(err.message)}
|
|
16552
|
+
`
|
|
16553
|
+
);
|
|
16554
|
+
}
|
|
16555
|
+
}
|
|
16200
16556
|
async function handleRestartCommand(opts) {
|
|
16201
16557
|
try {
|
|
16202
|
-
if (!
|
|
16203
|
-
|
|
16558
|
+
if (!existsSync4(RESTART_FLAGS_DIR)) {
|
|
16559
|
+
mkdirSync4(RESTART_FLAGS_DIR, { recursive: true });
|
|
16204
16560
|
}
|
|
16205
|
-
const flagPath =
|
|
16561
|
+
const flagPath = join5(RESTART_FLAGS_DIR, `${AGENT_CODE_NAME}.flag`);
|
|
16562
|
+
writeTelegramRestartConfirm(
|
|
16563
|
+
{ chat_id: opts.chatId, message_id: opts.messageId },
|
|
16564
|
+
opts.requesterName
|
|
16565
|
+
);
|
|
16206
16566
|
const flag = {
|
|
16207
16567
|
codeName: AGENT_CODE_NAME,
|
|
16208
16568
|
source: "telegram",
|
|
16209
16569
|
ts: Date.now(),
|
|
16210
16570
|
reply: { chat_id: opts.chatId, message_id: opts.messageId }
|
|
16211
16571
|
};
|
|
16212
|
-
const tmpPath = `${flagPath}.${process.pid}.${
|
|
16213
|
-
|
|
16214
|
-
|
|
16572
|
+
const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
|
|
16573
|
+
writeFileSync4(tmpPath, JSON.stringify(flag) + "\n", "utf8");
|
|
16574
|
+
renameSync4(tmpPath, flagPath);
|
|
16215
16575
|
process.stderr.write(
|
|
16216
16576
|
`telegram-channel(${AGENT_CODE_NAME}): /restart queued from chat ${redactId(opts.chatId)}
|
|
16217
16577
|
`
|
|
@@ -16561,6 +16921,10 @@ var HELP_SYNTAX_RE = /^\/help(?:@([A-Za-z0-9_]{1,64}))?(?:\s|$)/;
|
|
|
16561
16921
|
function isHelpSyntax(text) {
|
|
16562
16922
|
return HELP_SYNTAX_RE.test(text);
|
|
16563
16923
|
}
|
|
16924
|
+
var STATUS_SYNTAX_RE = /^\/status(?:@([A-Za-z0-9_]{1,64}))?(?:\s|$)/;
|
|
16925
|
+
function isStatusSyntax(text) {
|
|
16926
|
+
return STATUS_SYNTAX_RE.test(text);
|
|
16927
|
+
}
|
|
16564
16928
|
function isRestartSyntax(text) {
|
|
16565
16929
|
return RESTART_SYNTAX_RE.test(text);
|
|
16566
16930
|
}
|
|
@@ -16573,16 +16937,18 @@ async function classifyRestartCommand(text) {
|
|
|
16573
16937
|
if (!ours) return "verification_failed";
|
|
16574
16938
|
return target === ours ? "act" : "ignore";
|
|
16575
16939
|
}
|
|
16576
|
-
var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ?
|
|
16577
|
-
var PENDING_INBOUND_DIR = AGENT_DIR ?
|
|
16578
|
-
var RECOVERY_OUTBOX_DIR = AGENT_DIR ?
|
|
16940
|
+
var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join5(homedir2(), ".augmented", AGENT_CODE_NAME) : null;
|
|
16941
|
+
var PENDING_INBOUND_DIR = AGENT_DIR ? join5(AGENT_DIR, "telegram-pending-inbound") : null;
|
|
16942
|
+
var RECOVERY_OUTBOX_DIR = AGENT_DIR ? join5(AGENT_DIR, "telegram-recovery-outbox") : null;
|
|
16943
|
+
var RESTART_CONFIRM_FILE = AGENT_DIR ? join5(AGENT_DIR, "telegram-restart-confirm.json") : null;
|
|
16944
|
+
var TELEGRAM_PROCESS_BOOT_MS = Date.now();
|
|
16579
16945
|
function safeMarkerName(chatId, messageId) {
|
|
16580
16946
|
const safe = (s) => s.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
16581
16947
|
return `${safe(chatId)}__${safe(messageId)}.json`;
|
|
16582
16948
|
}
|
|
16583
16949
|
function pendingInboundPath(chatId, messageId) {
|
|
16584
16950
|
if (!PENDING_INBOUND_DIR) return null;
|
|
16585
|
-
return
|
|
16951
|
+
return join5(PENDING_INBOUND_DIR, safeMarkerName(chatId, messageId));
|
|
16586
16952
|
}
|
|
16587
16953
|
function writePendingInboundMarker(chatId, messageId, chatType, undeliverable = false, payload) {
|
|
16588
16954
|
const path = pendingInboundPath(chatId, messageId);
|
|
@@ -16599,8 +16965,8 @@ function writePendingInboundMarker(chatId, messageId, chatType, undeliverable =
|
|
|
16599
16965
|
...payload ? { payload } : {}
|
|
16600
16966
|
};
|
|
16601
16967
|
try {
|
|
16602
|
-
|
|
16603
|
-
|
|
16968
|
+
mkdirSync4(PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
|
|
16969
|
+
writeFileSync4(path, JSON.stringify(marker), { mode: 384 });
|
|
16604
16970
|
} catch (err) {
|
|
16605
16971
|
process.stderr.write(
|
|
16606
16972
|
`telegram-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
|
|
@@ -16611,7 +16977,7 @@ function writePendingInboundMarker(chatId, messageId, chatType, undeliverable =
|
|
|
16611
16977
|
function clearTelegramMarkerFileWithHeal(fullPath) {
|
|
16612
16978
|
let marker = null;
|
|
16613
16979
|
try {
|
|
16614
|
-
marker = JSON.parse(
|
|
16980
|
+
marker = JSON.parse(readFileSync5(fullPath, "utf-8"));
|
|
16615
16981
|
} catch {
|
|
16616
16982
|
}
|
|
16617
16983
|
if (marker && decideRecoveryHeal({
|
|
@@ -16621,7 +16987,7 @@ function clearTelegramMarkerFileWithHeal(fullPath) {
|
|
|
16621
16987
|
notifyBackOnline(marker.chat_id);
|
|
16622
16988
|
}
|
|
16623
16989
|
try {
|
|
16624
|
-
if (
|
|
16990
|
+
if (existsSync4(fullPath)) unlinkSync4(fullPath);
|
|
16625
16991
|
} catch {
|
|
16626
16992
|
}
|
|
16627
16993
|
}
|
|
@@ -16630,6 +16996,15 @@ function clearPendingInboundMarker(chatId, messageId) {
|
|
|
16630
16996
|
if (!path) return;
|
|
16631
16997
|
clearTelegramMarkerFileWithHeal(path);
|
|
16632
16998
|
}
|
|
16999
|
+
function readPendingInboundMarker(chatId, messageId) {
|
|
17000
|
+
const path = pendingInboundPath(chatId, messageId);
|
|
17001
|
+
if (!path || !existsSync4(path)) return null;
|
|
17002
|
+
try {
|
|
17003
|
+
return JSON.parse(readFileSync5(path, "utf-8"));
|
|
17004
|
+
} catch {
|
|
17005
|
+
return null;
|
|
17006
|
+
}
|
|
17007
|
+
}
|
|
16633
17008
|
var MAX_RECOVERY_ATTEMPTS = 3;
|
|
16634
17009
|
function nextRetryName(filename) {
|
|
16635
17010
|
const match = filename.match(/^(.*?)(?:\.retry-(\d+))?\.json$/);
|
|
@@ -16645,10 +17020,10 @@ function nextRetryName(filename) {
|
|
|
16645
17020
|
async function processRecoveryOutboxFile(filename) {
|
|
16646
17021
|
if (!RECOVERY_OUTBOX_DIR) return;
|
|
16647
17022
|
if (filename.endsWith(".poison.json") || filename.endsWith(".tmp")) return;
|
|
16648
|
-
const fullPath =
|
|
17023
|
+
const fullPath = join5(RECOVERY_OUTBOX_DIR, filename);
|
|
16649
17024
|
let payload;
|
|
16650
17025
|
try {
|
|
16651
|
-
const raw =
|
|
17026
|
+
const raw = readFileSync5(fullPath, "utf-8");
|
|
16652
17027
|
payload = JSON.parse(raw);
|
|
16653
17028
|
} catch (err) {
|
|
16654
17029
|
process.stderr.write(
|
|
@@ -16656,7 +17031,7 @@ async function processRecoveryOutboxFile(filename) {
|
|
|
16656
17031
|
`
|
|
16657
17032
|
);
|
|
16658
17033
|
try {
|
|
16659
|
-
|
|
17034
|
+
renameSync4(fullPath, `${fullPath}.parse-error.poison`);
|
|
16660
17035
|
} catch {
|
|
16661
17036
|
}
|
|
16662
17037
|
return;
|
|
@@ -16667,7 +17042,7 @@ async function processRecoveryOutboxFile(filename) {
|
|
|
16667
17042
|
`
|
|
16668
17043
|
);
|
|
16669
17044
|
try {
|
|
16670
|
-
|
|
17045
|
+
renameSync4(fullPath, `${fullPath}.malformed.poison`);
|
|
16671
17046
|
} catch {
|
|
16672
17047
|
}
|
|
16673
17048
|
return;
|
|
@@ -16703,7 +17078,7 @@ async function processRecoveryOutboxFile(filename) {
|
|
|
16703
17078
|
}
|
|
16704
17079
|
if (sendSucceeded) {
|
|
16705
17080
|
try {
|
|
16706
|
-
|
|
17081
|
+
unlinkSync4(fullPath);
|
|
16707
17082
|
} catch {
|
|
16708
17083
|
}
|
|
16709
17084
|
return;
|
|
@@ -16711,7 +17086,7 @@ async function processRecoveryOutboxFile(filename) {
|
|
|
16711
17086
|
const next = nextRetryName(filename);
|
|
16712
17087
|
if (next) {
|
|
16713
17088
|
try {
|
|
16714
|
-
|
|
17089
|
+
renameSync4(fullPath, join5(RECOVERY_OUTBOX_DIR, next.next));
|
|
16715
17090
|
if (next.attempt >= MAX_RECOVERY_ATTEMPTS) {
|
|
16716
17091
|
process.stderr.write(
|
|
16717
17092
|
`telegram-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
|
|
@@ -16751,7 +17126,7 @@ function scanRecoveryRetries() {
|
|
|
16751
17126
|
if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
|
|
16752
17127
|
let mtimeMs;
|
|
16753
17128
|
try {
|
|
16754
|
-
mtimeMs = statSync(
|
|
17129
|
+
mtimeMs = statSync(join5(RECOVERY_OUTBOX_DIR, f)).mtimeMs;
|
|
16755
17130
|
} catch {
|
|
16756
17131
|
continue;
|
|
16757
17132
|
}
|
|
@@ -16763,7 +17138,7 @@ function scanRecoveryRetries() {
|
|
|
16763
17138
|
function startRecoveryOutboxWatcher() {
|
|
16764
17139
|
if (!RECOVERY_OUTBOX_DIR) return;
|
|
16765
17140
|
try {
|
|
16766
|
-
|
|
17141
|
+
mkdirSync4(RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
|
|
16767
17142
|
} catch (err) {
|
|
16768
17143
|
process.stderr.write(
|
|
16769
17144
|
`telegram-channel(${AGENT_CODE_NAME}): recovery outbox mkdir failed: ${err.message}
|
|
@@ -16781,7 +17156,7 @@ function startRecoveryOutboxWatcher() {
|
|
|
16781
17156
|
const watcher = watch(RECOVERY_OUTBOX_DIR, (event, filename) => {
|
|
16782
17157
|
if (event !== "rename" || !filename) return;
|
|
16783
17158
|
if (!isFirstAttemptOutboxFile(filename)) return;
|
|
16784
|
-
if (
|
|
17159
|
+
if (existsSync4(join5(RECOVERY_OUTBOX_DIR, filename))) {
|
|
16785
17160
|
void processRecoveryOutboxFile(filename);
|
|
16786
17161
|
}
|
|
16787
17162
|
});
|
|
@@ -16802,7 +17177,7 @@ function trackPendingMessage(chatId, messageId, chatType, undeliverable = false,
|
|
|
16802
17177
|
}
|
|
16803
17178
|
function sweepTelegramStaleMarkers(thresholdMs) {
|
|
16804
17179
|
if (!PENDING_INBOUND_DIR) return;
|
|
16805
|
-
if (!
|
|
17180
|
+
if (!existsSync4(PENDING_INBOUND_DIR)) return;
|
|
16806
17181
|
let filenames;
|
|
16807
17182
|
try {
|
|
16808
17183
|
filenames = readdirSync2(PENDING_INBOUND_DIR);
|
|
@@ -16818,17 +17193,17 @@ function sweepTelegramStaleMarkers(thresholdMs) {
|
|
|
16818
17193
|
for (const filename of filenames) {
|
|
16819
17194
|
if (!filename.endsWith(".json")) continue;
|
|
16820
17195
|
if (filename.endsWith(".tmp")) continue;
|
|
16821
|
-
const fullPath =
|
|
17196
|
+
const fullPath = join5(PENDING_INBOUND_DIR, filename);
|
|
16822
17197
|
let marker;
|
|
16823
17198
|
try {
|
|
16824
|
-
marker = JSON.parse(
|
|
17199
|
+
marker = JSON.parse(readFileSync5(fullPath, "utf-8"));
|
|
16825
17200
|
} catch (err) {
|
|
16826
17201
|
process.stderr.write(
|
|
16827
17202
|
`telegram-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactId(filename)}: ${err.message}
|
|
16828
17203
|
`
|
|
16829
17204
|
);
|
|
16830
17205
|
try {
|
|
16831
|
-
|
|
17206
|
+
unlinkSync4(fullPath);
|
|
16832
17207
|
} catch {
|
|
16833
17208
|
}
|
|
16834
17209
|
cleared++;
|
|
@@ -16837,7 +17212,7 @@ function sweepTelegramStaleMarkers(thresholdMs) {
|
|
|
16837
17212
|
const { chat_id, message_id, received_at } = marker;
|
|
16838
17213
|
if (!chat_id || !message_id || isPendingMarkerStale(received_at, now, thresholdMs)) {
|
|
16839
17214
|
try {
|
|
16840
|
-
|
|
17215
|
+
unlinkSync4(fullPath);
|
|
16841
17216
|
} catch {
|
|
16842
17217
|
}
|
|
16843
17218
|
cleared++;
|
|
@@ -16860,14 +17235,14 @@ var orphanSweepTimer = setInterval(() => {
|
|
|
16860
17235
|
orphanSweepTimer.unref?.();
|
|
16861
17236
|
var lastGiveUpHandledAtMs = null;
|
|
16862
17237
|
function listPendingInboundChatIds() {
|
|
16863
|
-
if (!PENDING_INBOUND_DIR || !
|
|
17238
|
+
if (!PENDING_INBOUND_DIR || !existsSync4(PENDING_INBOUND_DIR)) return [];
|
|
16864
17239
|
const chats = /* @__PURE__ */ new Set();
|
|
16865
17240
|
try {
|
|
16866
17241
|
for (const name of readdirSync2(PENDING_INBOUND_DIR)) {
|
|
16867
17242
|
if (!name.endsWith(".json")) continue;
|
|
16868
17243
|
try {
|
|
16869
17244
|
const marker = JSON.parse(
|
|
16870
|
-
|
|
17245
|
+
readFileSync5(join5(PENDING_INBOUND_DIR, name), "utf8")
|
|
16871
17246
|
);
|
|
16872
17247
|
if (typeof marker.chat_id === "string" && marker.chat_id) chats.add(marker.chat_id);
|
|
16873
17248
|
} catch {
|
|
@@ -16908,7 +17283,7 @@ async function notifyWatchdogGiveUp(chatId) {
|
|
|
16908
17283
|
}
|
|
16909
17284
|
function checkWatchdogGiveUpNotice() {
|
|
16910
17285
|
if (!AGENT_DIR) return;
|
|
16911
|
-
const signalAtMs = readGiveUpSignalAtMs(
|
|
17286
|
+
const signalAtMs = readGiveUpSignalAtMs(join5(AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
|
|
16912
17287
|
const act = decideGiveUpNotice({
|
|
16913
17288
|
signalAtMs,
|
|
16914
17289
|
lastHandledAtMs: lastGiveUpHandledAtMs,
|
|
@@ -16986,7 +17361,7 @@ function clearPendingMessage(chatId, messageId) {
|
|
|
16986
17361
|
clearPendingInboundMarker(chatId, messageId);
|
|
16987
17362
|
return;
|
|
16988
17363
|
}
|
|
16989
|
-
if (!PENDING_INBOUND_DIR || !
|
|
17364
|
+
if (!PENDING_INBOUND_DIR || !existsSync4(PENDING_INBOUND_DIR)) return;
|
|
16990
17365
|
const safeChatId = chatId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
16991
17366
|
const prefix = `${safeChatId}__`;
|
|
16992
17367
|
let filenames;
|
|
@@ -16998,7 +17373,7 @@ function clearPendingMessage(chatId, messageId) {
|
|
|
16998
17373
|
for (const filename of filenames) {
|
|
16999
17374
|
if (!filename.startsWith(prefix)) continue;
|
|
17000
17375
|
if (!filename.endsWith(".json")) continue;
|
|
17001
|
-
clearTelegramMarkerFileWithHeal(
|
|
17376
|
+
clearTelegramMarkerFileWithHeal(join5(PENDING_INBOUND_DIR, filename));
|
|
17002
17377
|
}
|
|
17003
17378
|
}
|
|
17004
17379
|
function noteThreadActivity(chatId, messageId) {
|
|
@@ -17597,7 +17972,7 @@ await mcp.connect(new StdioServerTransport());
|
|
|
17597
17972
|
var REPLAY_SCAN_INTERVAL_MS = 6e4;
|
|
17598
17973
|
async function replayPendingTelegramMarkers() {
|
|
17599
17974
|
if (!channelReplayEnabled()) return;
|
|
17600
|
-
if (!PENDING_INBOUND_DIR || !
|
|
17975
|
+
if (!PENDING_INBOUND_DIR || !existsSync4(PENDING_INBOUND_DIR)) return;
|
|
17601
17976
|
const probe = process.env.TMUX && AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? probeAgentSessionCached(AGENT_CODE_NAME) : { tmux: "unknown", claude: "unknown" };
|
|
17602
17977
|
const sessionAlive = probe.tmux === "alive" && probe.claude === "alive";
|
|
17603
17978
|
if (!sessionAlive) return;
|
|
@@ -17611,10 +17986,10 @@ async function replayPendingTelegramMarkers() {
|
|
|
17611
17986
|
const entries = [];
|
|
17612
17987
|
for (const name of filenames) {
|
|
17613
17988
|
if (!name.endsWith(".json") || name.endsWith(".tmp")) continue;
|
|
17614
|
-
const fullPath =
|
|
17989
|
+
const fullPath = join5(PENDING_INBOUND_DIR, name);
|
|
17615
17990
|
let marker;
|
|
17616
17991
|
try {
|
|
17617
|
-
marker = JSON.parse(
|
|
17992
|
+
marker = JSON.parse(readFileSync5(fullPath, "utf-8"));
|
|
17618
17993
|
} catch {
|
|
17619
17994
|
continue;
|
|
17620
17995
|
}
|
|
@@ -17646,12 +18021,12 @@ async function replayPendingTelegramMarkers() {
|
|
|
17646
18021
|
continue;
|
|
17647
18022
|
}
|
|
17648
18023
|
try {
|
|
17649
|
-
if (
|
|
18024
|
+
if (existsSync4(path)) {
|
|
17650
18025
|
const updated = {
|
|
17651
18026
|
...marker,
|
|
17652
18027
|
replay_count: (marker.replay_count ?? 0) + 1
|
|
17653
18028
|
};
|
|
17654
|
-
|
|
18029
|
+
writeFileSync4(path, JSON.stringify(updated), { mode: 384 });
|
|
17655
18030
|
}
|
|
17656
18031
|
} catch {
|
|
17657
18032
|
}
|
|
@@ -17788,14 +18163,68 @@ async function pollLoop() {
|
|
|
17788
18163
|
const content = typeof msg.text === "string" && msg.text.length > 0 ? msg.text : typeof msg.caption === "string" && msg.caption.length > 0 ? msg.caption : "";
|
|
17789
18164
|
if (content.length === 0 && classifiedAttachments.length === 0) continue;
|
|
17790
18165
|
const chatId = String(msg.chat.id);
|
|
17791
|
-
|
|
18166
|
+
const trimmedContent = content.trim();
|
|
18167
|
+
const isFromBot = !!msg.from?.is_bot;
|
|
18168
|
+
const nowMs = Date.now();
|
|
18169
|
+
const telegramCommand = isHelpSyntax(trimmedContent) ? "help" : isStatusSyntax(trimmedContent) ? "status" : isRestartSyntax(trimmedContent) ? "restart" : isInvestigateSyntax(trimmedContent) ? "investigate" : void 0;
|
|
18170
|
+
let classification;
|
|
18171
|
+
let peerLeaf;
|
|
18172
|
+
if (isFromBot) {
|
|
18173
|
+
if (PEER_DISABLED_GLOBAL) {
|
|
18174
|
+
peerLeaf = { kind: "drop", reason: "peer_disabled_global" };
|
|
18175
|
+
} else {
|
|
18176
|
+
const classifierMsg = {
|
|
18177
|
+
message_id: msg.message_id,
|
|
18178
|
+
text: msg.text,
|
|
18179
|
+
caption: msg.caption,
|
|
18180
|
+
from: msg.from ? { id: msg.from.id, username: msg.from.username, is_bot: msg.from.is_bot } : void 0,
|
|
18181
|
+
chat: { id: msg.chat.id, type: msg.chat.type },
|
|
18182
|
+
reply_to_message: msg.reply_to_message ? {
|
|
18183
|
+
message_id: msg.reply_to_message.message_id,
|
|
18184
|
+
from: msg.reply_to_message.from ? { id: msg.reply_to_message.from.id, is_bot: msg.reply_to_message.from.is_bot } : void 0
|
|
18185
|
+
} : void 0,
|
|
18186
|
+
entities: msg.entities,
|
|
18187
|
+
caption_entities: msg.caption_entities
|
|
18188
|
+
};
|
|
18189
|
+
const self = await resolveBotIdentity();
|
|
18190
|
+
classification = classifyPeerMessage(classifierMsg, PEER_CLASSIFIER_CONFIG, self);
|
|
18191
|
+
peerLeaf = {
|
|
18192
|
+
kind: classification.kind,
|
|
18193
|
+
reason: classification.kind === "drop" ? classification.reason : void 0
|
|
18194
|
+
};
|
|
18195
|
+
}
|
|
18196
|
+
}
|
|
18197
|
+
const access = decideInboundAccess({
|
|
18198
|
+
content: { forward: true },
|
|
18199
|
+
// empty content already filtered above
|
|
18200
|
+
// CodeRabbit: derive self from the peer classification so an echo of
|
|
18201
|
+
// our own outbound is dropped at the self step — BEFORE command
|
|
18202
|
+
// routing — instead of slipping through as a command. (Slack catches
|
|
18203
|
+
// self at evt.user===botUserId and Teams inside its activity filter;
|
|
18204
|
+
// Telegram's only self signal is the peer classifier.)
|
|
18205
|
+
isSelf: peerLeaf?.kind === "self",
|
|
18206
|
+
isBot: isFromBot,
|
|
18207
|
+
peer: peerLeaf,
|
|
18208
|
+
// TELEGRAM_ALLOWED_CHATS is Telegram's org-boundary axis (the drift
|
|
18209
|
+
// the consolidation names). An unlisted chat is external ⇒ silent.
|
|
18210
|
+
orgBoundary: ALLOWED_CHATS.size > 0 && !ALLOWED_CHATS.has(chatId) ? { forward: false } : { forward: true },
|
|
18211
|
+
command: telegramCommand ? { command: telegramCommand, authorized: true } : void 0,
|
|
18212
|
+
// No sender-policy mode system on Telegram, so no same-org decline.
|
|
18213
|
+
sameOrg: false
|
|
18214
|
+
});
|
|
18215
|
+
if (access.kind === "drop" && (access.reason === "org_boundary" || access.reason.startsWith("content:"))) {
|
|
18216
|
+
process.stderr.write(
|
|
18217
|
+
`telegram-channel(${AGENT_CODE_NAME}): inbound drop reason=${access.reason} chat=${redactId(chatId)}
|
|
18218
|
+
`
|
|
18219
|
+
);
|
|
18220
|
+
continue;
|
|
18221
|
+
}
|
|
17792
18222
|
observedChatClient?.observe({
|
|
17793
18223
|
chat_id: chatId,
|
|
17794
18224
|
chat_title: msg.chat.title ?? msg.chat.username ?? msg.chat.first_name ?? null,
|
|
17795
18225
|
chat_type: msg.chat.type ?? null
|
|
17796
18226
|
});
|
|
17797
|
-
|
|
17798
|
-
if (isHelpSyntax(trimmedContent)) {
|
|
18227
|
+
if (access.kind === "command" && access.command === "help") {
|
|
17799
18228
|
const disposition = await classifyRestartCommand(trimmedContent.replace(/^\/help/, "/restart"));
|
|
17800
18229
|
if (disposition === "act") {
|
|
17801
18230
|
await handleHelpCommand({
|
|
@@ -17805,12 +18234,26 @@ async function pollLoop() {
|
|
|
17805
18234
|
}
|
|
17806
18235
|
continue;
|
|
17807
18236
|
}
|
|
17808
|
-
if (
|
|
18237
|
+
if (access.kind === "command" && access.command === "status") {
|
|
18238
|
+
const disposition = await classifyRestartCommand(
|
|
18239
|
+
trimmedContent.replace(/^\/status/, "/restart")
|
|
18240
|
+
);
|
|
18241
|
+
if (disposition === "act") {
|
|
18242
|
+
await handleStatusCommand({
|
|
18243
|
+
chatId,
|
|
18244
|
+
messageId: String(msg.message_id)
|
|
18245
|
+
});
|
|
18246
|
+
}
|
|
18247
|
+
continue;
|
|
18248
|
+
}
|
|
18249
|
+
if (access.kind === "command" && access.command === "restart") {
|
|
17809
18250
|
const disposition = await classifyRestartCommand(trimmedContent);
|
|
17810
18251
|
if (disposition === "act") {
|
|
17811
18252
|
await handleRestartCommand({
|
|
17812
18253
|
chatId,
|
|
17813
|
-
messageId: String(msg.message_id)
|
|
18254
|
+
messageId: String(msg.message_id),
|
|
18255
|
+
// ENG-6194: first_name personalises the back-online confirmation.
|
|
18256
|
+
requesterName: msg.from?.first_name?.trim() || void 0
|
|
17814
18257
|
});
|
|
17815
18258
|
} else if (disposition === "verification_failed") {
|
|
17816
18259
|
try {
|
|
@@ -17832,7 +18275,7 @@ async function pollLoop() {
|
|
|
17832
18275
|
}
|
|
17833
18276
|
continue;
|
|
17834
18277
|
}
|
|
17835
|
-
if (
|
|
18278
|
+
if (access.kind === "command" && access.command === "investigate") {
|
|
17836
18279
|
const disposition = await classifyInvestigateCommand(trimmedContent);
|
|
17837
18280
|
if (disposition === "act") {
|
|
17838
18281
|
await handleInvestigateCommand({
|
|
@@ -17863,8 +18306,6 @@ async function pollLoop() {
|
|
|
17863
18306
|
}
|
|
17864
18307
|
const userId = msg.from?.id != null ? String(msg.from.id) : "unknown";
|
|
17865
18308
|
const userName = msg.from?.username || [msg.from?.first_name, msg.from?.last_name].filter(Boolean).join(" ").trim() || userId;
|
|
17866
|
-
const isFromBot = !!msg.from?.is_bot;
|
|
17867
|
-
const nowMs = Date.now();
|
|
17868
18309
|
if (chatId && !isFromBot) {
|
|
17869
18310
|
resetThread(chatId, "");
|
|
17870
18311
|
}
|
|
@@ -17873,38 +18314,14 @@ async function pollLoop() {
|
|
|
17873
18314
|
peerRateLimiter.recordInboundHuman(chatId, nowMs);
|
|
17874
18315
|
}
|
|
17875
18316
|
let peerAgentMeta = null;
|
|
17876
|
-
if (
|
|
17877
|
-
if (
|
|
18317
|
+
if (access.kind === "drop") {
|
|
18318
|
+
if (access.reason !== "self") {
|
|
18319
|
+
const peerReason = access.reason.startsWith("peer:") ? access.reason.slice("peer:".length) : access.reason;
|
|
17878
18320
|
process.stderr.write(
|
|
17879
|
-
`telegram-channel(${AGENT_CODE_NAME}): peer_drop reason
|
|
18321
|
+
`telegram-channel(${AGENT_CODE_NAME}): peer_drop reason=${peerReason} chat=${redactId(chatId)} from=${redactId(String(msg.from?.id ?? "unknown"))}
|
|
17880
18322
|
`
|
|
17881
18323
|
);
|
|
17882
|
-
|
|
17883
|
-
}
|
|
17884
|
-
const classifierMsg = {
|
|
17885
|
-
message_id: msg.message_id,
|
|
17886
|
-
text: msg.text,
|
|
17887
|
-
caption: msg.caption,
|
|
17888
|
-
from: msg.from ? { id: msg.from.id, username: msg.from.username, is_bot: msg.from.is_bot } : void 0,
|
|
17889
|
-
chat: { id: msg.chat.id, type: msg.chat.type },
|
|
17890
|
-
reply_to_message: msg.reply_to_message ? {
|
|
17891
|
-
message_id: msg.reply_to_message.message_id,
|
|
17892
|
-
from: msg.reply_to_message.from ? { id: msg.reply_to_message.from.id, is_bot: msg.reply_to_message.from.is_bot } : void 0
|
|
17893
|
-
} : void 0,
|
|
17894
|
-
entities: msg.entities,
|
|
17895
|
-
caption_entities: msg.caption_entities
|
|
17896
|
-
};
|
|
17897
|
-
const self = await resolveBotIdentity();
|
|
17898
|
-
const classification = classifyPeerMessage(classifierMsg, PEER_CLASSIFIER_CONFIG, self);
|
|
17899
|
-
if (classification.kind === "self") {
|
|
17900
|
-
continue;
|
|
17901
|
-
}
|
|
17902
|
-
if (classification.kind === "drop") {
|
|
17903
|
-
process.stderr.write(
|
|
17904
|
-
`telegram-channel(${AGENT_CODE_NAME}): peer_drop reason=${classification.reason} chat=${redactId(chatId)} from=${redactId(String(msg.from?.id ?? "unknown"))}
|
|
17905
|
-
`
|
|
17906
|
-
);
|
|
17907
|
-
if (classification.reason === "cross_team_grant_missing") {
|
|
18324
|
+
if (classification?.kind === "drop" && classification.reason === "cross_team_grant_missing") {
|
|
17908
18325
|
crossTeamPeerAuditClient?.emit({
|
|
17909
18326
|
event_type: "telegram.peer.drop.cross_team_grant_missing",
|
|
17910
18327
|
peer_agent_id: null,
|
|
@@ -17914,52 +18331,52 @@ async function pollLoop() {
|
|
|
17914
18331
|
message_id: String(msg.message_id)
|
|
17915
18332
|
});
|
|
17916
18333
|
}
|
|
17917
|
-
continue;
|
|
17918
18334
|
}
|
|
17919
|
-
|
|
17920
|
-
|
|
17921
|
-
|
|
17922
|
-
|
|
17923
|
-
|
|
17924
|
-
|
|
17925
|
-
|
|
17926
|
-
|
|
17927
|
-
|
|
18335
|
+
continue;
|
|
18336
|
+
}
|
|
18337
|
+
if (isFromBot && classification?.kind === "peer-ingress") {
|
|
18338
|
+
const limit = await peerRateLimiter.recordInboundPeer(
|
|
18339
|
+
chatId,
|
|
18340
|
+
classification.peer.bot_id,
|
|
18341
|
+
nowMs
|
|
18342
|
+
);
|
|
18343
|
+
if (limit.decision !== "ok") {
|
|
18344
|
+
process.stderr.write(
|
|
18345
|
+
`telegram-channel(${AGENT_CODE_NAME}): peer_drop reason=${limit.decision} chat=${redactId(chatId)} from=${redactId(String(msg.from?.id ?? "unknown"))}
|
|
17928
18346
|
`
|
|
17929
|
-
|
|
17930
|
-
|
|
17931
|
-
|
|
17932
|
-
|
|
17933
|
-
|
|
17934
|
-
|
|
17935
|
-
|
|
18347
|
+
);
|
|
18348
|
+
continue;
|
|
18349
|
+
}
|
|
18350
|
+
if (limit.dailyBudgetWarn && !dailyBudgetWarned) {
|
|
18351
|
+
dailyBudgetWarned = true;
|
|
18352
|
+
process.stderr.write(
|
|
18353
|
+
`telegram-channel(${AGENT_CODE_NAME}): peer_warn reason=daily_budget_80pct
|
|
17936
18354
|
`
|
|
17937
|
-
|
|
17938
|
-
|
|
17939
|
-
|
|
17940
|
-
|
|
17941
|
-
|
|
17942
|
-
|
|
17943
|
-
|
|
17944
|
-
|
|
17945
|
-
|
|
17946
|
-
|
|
17947
|
-
|
|
17948
|
-
|
|
17949
|
-
|
|
17950
|
-
|
|
17951
|
-
|
|
17952
|
-
|
|
17953
|
-
|
|
17954
|
-
|
|
17955
|
-
|
|
17956
|
-
|
|
17957
|
-
|
|
17958
|
-
|
|
17959
|
-
|
|
17960
|
-
|
|
17961
|
-
|
|
17962
|
-
}
|
|
18355
|
+
);
|
|
18356
|
+
}
|
|
18357
|
+
peerAgentMeta = {
|
|
18358
|
+
code_name: classification.peer.code_name,
|
|
18359
|
+
agent_id: classification.peer.agent_id
|
|
18360
|
+
};
|
|
18361
|
+
const gate = classification.peer.gate_path;
|
|
18362
|
+
if (gate && gate !== "same_team" && gate !== "intra_org_unrestricted" && gate.startsWith("grant:")) {
|
|
18363
|
+
crossTeamPeerAuditClient?.emit({
|
|
18364
|
+
event_type: "telegram.peer.ingress.cross_team",
|
|
18365
|
+
peer_agent_id: classification.peer.agent_id || null,
|
|
18366
|
+
gate_path: gate,
|
|
18367
|
+
grant_id: gate.slice("grant:".length),
|
|
18368
|
+
chat_id: String(chatId),
|
|
18369
|
+
message_id: String(msg.message_id)
|
|
18370
|
+
});
|
|
18371
|
+
} else if (gate === "intra_org_unrestricted") {
|
|
18372
|
+
crossTeamPeerAuditClient?.emit({
|
|
18373
|
+
event_type: "telegram.peer.ingress.cross_team",
|
|
18374
|
+
peer_agent_id: classification.peer.agent_id || null,
|
|
18375
|
+
gate_path: gate,
|
|
18376
|
+
grant_id: null,
|
|
18377
|
+
chat_id: String(chatId),
|
|
18378
|
+
message_id: String(msg.message_id)
|
|
18379
|
+
});
|
|
17963
18380
|
}
|
|
17964
18381
|
}
|
|
17965
18382
|
const messageId = String(msg.message_id);
|
|
@@ -17967,7 +18384,7 @@ async function pollLoop() {
|
|
|
17967
18384
|
let paneLogFreshAgeMs = null;
|
|
17968
18385
|
if (AGENT_DIR) {
|
|
17969
18386
|
try {
|
|
17970
|
-
const paneMtimeMs = statSync(
|
|
18387
|
+
const paneMtimeMs = statSync(join5(AGENT_DIR, "pane.log")).mtimeMs;
|
|
17971
18388
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
17972
18389
|
} catch {
|
|
17973
18390
|
}
|
|
@@ -18042,6 +18459,9 @@ async function pollLoop() {
|
|
|
18042
18459
|
ackDecision === "undeliverable",
|
|
18043
18460
|
channelPayload
|
|
18044
18461
|
);
|
|
18462
|
+
if (ackDecision === "ack") {
|
|
18463
|
+
scheduleBusyAck(chatId, messageId);
|
|
18464
|
+
}
|
|
18045
18465
|
await mcp.notification({
|
|
18046
18466
|
method: "notifications/claude/channel",
|
|
18047
18467
|
params: channelPayload
|
|
@@ -18130,6 +18550,7 @@ void (async () => {
|
|
|
18130
18550
|
}
|
|
18131
18551
|
}
|
|
18132
18552
|
})();
|
|
18553
|
+
void notifyRestartCompleteOnBoot();
|
|
18133
18554
|
pollLoop().catch((err) => {
|
|
18134
18555
|
process.stderr.write(
|
|
18135
18556
|
`telegram-channel(${AGENT_CODE_NAME}): poll loop died: ${err.message}
|
|
@@ -18139,6 +18560,7 @@ pollLoop().catch((err) => {
|
|
|
18139
18560
|
});
|
|
18140
18561
|
export {
|
|
18141
18562
|
__resetBackOnlineNoticeThrottle,
|
|
18563
|
+
__resetBusyAckNoticeThrottle,
|
|
18142
18564
|
__resetGiveUpNoticeStateForTests,
|
|
18143
18565
|
__resetUndeliverableNoticeThrottle,
|
|
18144
18566
|
_resetQueuedReplyCountsForTests
|