@integrity-labs/agt-cli 0.28.109 → 0.28.110
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 +3 -3
- package/dist/{chunk-ZJLRHPPL.js → chunk-XQTQRU7P.js} +2 -2
- package/dist/lib/manager-worker.js +4 -4
- package/dist/mcp/slack-channel.js +95 -54
- package/dist/mcp/teams-channel.js +76 -35
- package/dist/mcp/telegram-channel.js +101 -60
- package/dist/{responsiveness-probe-2KVIALGI.js → responsiveness-probe-QU5TY2K4.js} +56 -2
- package/dist/responsiveness-probe-QU5TY2K4.js.map +1 -0
- package/package.json +1 -1
- package/dist/responsiveness-probe-2KVIALGI.js.map +0 -1
- /package/dist/{chunk-ZJLRHPPL.js.map → chunk-XQTQRU7P.js.map} +0 -0
|
@@ -14473,17 +14473,17 @@ import {
|
|
|
14473
14473
|
ftruncateSync,
|
|
14474
14474
|
mkdirSync as mkdirSync7,
|
|
14475
14475
|
openSync,
|
|
14476
|
-
readFileSync as
|
|
14476
|
+
readFileSync as readFileSync10,
|
|
14477
14477
|
readdirSync as readdirSync3,
|
|
14478
14478
|
renameSync as renameSync6,
|
|
14479
14479
|
statSync as statSync2,
|
|
14480
14480
|
unlinkSync as unlinkSync6,
|
|
14481
14481
|
watch,
|
|
14482
|
-
writeFileSync as
|
|
14482
|
+
writeFileSync as writeFileSync9,
|
|
14483
14483
|
writeSync
|
|
14484
14484
|
} from "fs";
|
|
14485
14485
|
import { homedir as homedir3 } from "os";
|
|
14486
|
-
import { join as
|
|
14486
|
+
import { join as join8 } from "path";
|
|
14487
14487
|
|
|
14488
14488
|
// src/channel-attachments.ts
|
|
14489
14489
|
import { homedir } from "os";
|
|
@@ -15776,16 +15776,53 @@ function conversationalLaneMeta(expectsReply = true) {
|
|
|
15776
15776
|
};
|
|
15777
15777
|
}
|
|
15778
15778
|
|
|
15779
|
-
// src/
|
|
15780
|
-
import {
|
|
15779
|
+
// src/inbound-lane-telemetry.ts
|
|
15780
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
15781
15781
|
import { join as join3 } from "path";
|
|
15782
|
+
var LANE_CLASSIFICATION_COUNTER_SUFFIX = "-lane-classifications.json";
|
|
15783
|
+
var SUSPECTED_MISCLASSIFICATION_KEY = "suspected_misclassification";
|
|
15784
|
+
var HUMAN_CHANNEL_SOURCES = /* @__PURE__ */ new Set([
|
|
15785
|
+
"slack",
|
|
15786
|
+
"telegram",
|
|
15787
|
+
"msteams",
|
|
15788
|
+
"direct-chat"
|
|
15789
|
+
]);
|
|
15790
|
+
function laneClassificationKey(lane, expectsReply, source) {
|
|
15791
|
+
return `${lane}|${expectsReply ? "true" : "false"}|${source}`;
|
|
15792
|
+
}
|
|
15793
|
+
function isSuspectedMisclassification(lane, source) {
|
|
15794
|
+
return lane === "directive" && HUMAN_CHANNEL_SOURCES.has(source);
|
|
15795
|
+
}
|
|
15796
|
+
function recordLaneClassification(agentDir, channel, classification) {
|
|
15797
|
+
if (!agentDir) return;
|
|
15798
|
+
const path = join3(agentDir, `${channel}${LANE_CLASSIFICATION_COUNTER_SUFFIX}`);
|
|
15799
|
+
let counts = {};
|
|
15800
|
+
try {
|
|
15801
|
+
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
15802
|
+
if (parsed && typeof parsed === "object") counts = parsed;
|
|
15803
|
+
} catch {
|
|
15804
|
+
}
|
|
15805
|
+
const key2 = laneClassificationKey(classification.lane, classification.expectsReply, channel);
|
|
15806
|
+
counts[key2] = (counts[key2] ?? 0) + 1;
|
|
15807
|
+
if (isSuspectedMisclassification(classification.lane, channel)) {
|
|
15808
|
+
counts[SUSPECTED_MISCLASSIFICATION_KEY] = (counts[SUSPECTED_MISCLASSIFICATION_KEY] ?? 0) + 1;
|
|
15809
|
+
}
|
|
15810
|
+
try {
|
|
15811
|
+
writeFileSync6(path, JSON.stringify(counts), { mode: 384 });
|
|
15812
|
+
} catch {
|
|
15813
|
+
}
|
|
15814
|
+
}
|
|
15815
|
+
|
|
15816
|
+
// src/agent-config-state.ts
|
|
15817
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
|
|
15818
|
+
import { join as join4 } from "path";
|
|
15782
15819
|
var SESSION_STATE_FILENAME = "session-state.json";
|
|
15783
15820
|
function readAgentSessionState(stateDir) {
|
|
15784
15821
|
if (!stateDir) return null;
|
|
15785
|
-
const path =
|
|
15822
|
+
const path = join4(stateDir, SESSION_STATE_FILENAME);
|
|
15786
15823
|
if (!existsSync4(path)) return null;
|
|
15787
15824
|
try {
|
|
15788
|
-
const parsed = JSON.parse(
|
|
15825
|
+
const parsed = JSON.parse(readFileSync6(path, "utf-8"));
|
|
15789
15826
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
15790
15827
|
return parsed;
|
|
15791
15828
|
} catch {
|
|
@@ -16299,11 +16336,11 @@ var TELEGRAM_EGRESS_TOOLS = /* @__PURE__ */ new Set([
|
|
|
16299
16336
|
]);
|
|
16300
16337
|
|
|
16301
16338
|
// src/telegram-pending-inbound-cleanup.ts
|
|
16302
|
-
import { readdirSync, readFileSync as
|
|
16303
|
-
import { join as
|
|
16339
|
+
import { readdirSync, readFileSync as readFileSync7, statSync } from "fs";
|
|
16340
|
+
import { join as join5 } from "path";
|
|
16304
16341
|
function markerArrivalMs(fullPath) {
|
|
16305
16342
|
try {
|
|
16306
|
-
const received = JSON.parse(
|
|
16343
|
+
const received = JSON.parse(readFileSync7(fullPath, "utf-8")).received_at;
|
|
16307
16344
|
const parsed = received ? Date.parse(received) : Number.NaN;
|
|
16308
16345
|
if (Number.isFinite(parsed)) return parsed;
|
|
16309
16346
|
} catch {
|
|
@@ -16333,7 +16370,7 @@ function applyToChatMarkers(pendingDir, chatId, op, cutoffMs) {
|
|
|
16333
16370
|
for (const filename of filenames) {
|
|
16334
16371
|
if (!filename.startsWith(prefix)) continue;
|
|
16335
16372
|
if (!filename.endsWith(".json")) continue;
|
|
16336
|
-
const fullPath =
|
|
16373
|
+
const fullPath = join5(pendingDir, filename);
|
|
16337
16374
|
if (bounded && markerArrivalMs(fullPath) > cutoffMs) continue;
|
|
16338
16375
|
op(fullPath);
|
|
16339
16376
|
applied++;
|
|
@@ -16487,12 +16524,12 @@ function createKanbanCardActiveClient(args) {
|
|
|
16487
16524
|
import {
|
|
16488
16525
|
existsSync as existsSync5,
|
|
16489
16526
|
mkdirSync as mkdirSync6,
|
|
16490
|
-
readFileSync as
|
|
16527
|
+
readFileSync as readFileSync8,
|
|
16491
16528
|
renameSync as renameSync5,
|
|
16492
16529
|
unlinkSync as unlinkSync5,
|
|
16493
|
-
writeFileSync as
|
|
16530
|
+
writeFileSync as writeFileSync7
|
|
16494
16531
|
} from "fs";
|
|
16495
|
-
import { join as
|
|
16532
|
+
import { join as join6 } from "path";
|
|
16496
16533
|
function defaultIsPidAlive(pid) {
|
|
16497
16534
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
16498
16535
|
try {
|
|
@@ -16510,7 +16547,7 @@ function acquireMcpSpawnLock(args) {
|
|
|
16510
16547
|
const isPidAlive = options.isPidAlive ?? defaultIsPidAlive;
|
|
16511
16548
|
const selfPid = options.selfPid ?? process.pid;
|
|
16512
16549
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
16513
|
-
const path =
|
|
16550
|
+
const path = join6(agentDir, basename);
|
|
16514
16551
|
const existing = readLockHolder(path);
|
|
16515
16552
|
if (existing) {
|
|
16516
16553
|
if (existing.pid === selfPid) {
|
|
@@ -16523,7 +16560,7 @@ function acquireMcpSpawnLock(args) {
|
|
|
16523
16560
|
mkdirSync6(agentDir, { recursive: true, mode: 448 });
|
|
16524
16561
|
const tmpPath = `${path}.${selfPid}.tmp`;
|
|
16525
16562
|
const payload = { pid: selfPid, started_at: now() };
|
|
16526
|
-
|
|
16563
|
+
writeFileSync7(tmpPath, JSON.stringify(payload), { mode: 384 });
|
|
16527
16564
|
renameSync5(tmpPath, path);
|
|
16528
16565
|
return { kind: "acquired", path };
|
|
16529
16566
|
}
|
|
@@ -16541,7 +16578,7 @@ function releaseMcpSpawnLock(lockPath, opts = {}) {
|
|
|
16541
16578
|
function readLockHolder(path) {
|
|
16542
16579
|
if (!existsSync5(path)) return null;
|
|
16543
16580
|
try {
|
|
16544
|
-
const raw =
|
|
16581
|
+
const raw = readFileSync8(path, "utf8");
|
|
16545
16582
|
const parsed = JSON.parse(raw);
|
|
16546
16583
|
const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
|
|
16547
16584
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
@@ -16553,8 +16590,8 @@ function readLockHolder(path) {
|
|
|
16553
16590
|
}
|
|
16554
16591
|
|
|
16555
16592
|
// src/ack-reaction.ts
|
|
16556
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
16557
|
-
import { join as
|
|
16593
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
|
|
16594
|
+
import { join as join7 } from "path";
|
|
16558
16595
|
var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
16559
16596
|
var ACK_STARTUP_GRACE_MS = 6e4;
|
|
16560
16597
|
var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
|
|
@@ -16627,7 +16664,7 @@ var GIVE_UP_SIGNAL_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
|
16627
16664
|
function readGiveUpSignalAtMs(path, now = Date.now()) {
|
|
16628
16665
|
if (!path) return null;
|
|
16629
16666
|
try {
|
|
16630
|
-
const raw = JSON.parse(
|
|
16667
|
+
const raw = JSON.parse(readFileSync9(path, "utf8"));
|
|
16631
16668
|
if (typeof raw.gave_up_at !== "string") return null;
|
|
16632
16669
|
const t = Date.parse(raw.gave_up_at);
|
|
16633
16670
|
if (!Number.isFinite(t) || t > now) return null;
|
|
@@ -16659,7 +16696,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now()) {
|
|
|
16659
16696
|
if (!name.endsWith(".json")) continue;
|
|
16660
16697
|
let receivedAt;
|
|
16661
16698
|
try {
|
|
16662
|
-
const raw = JSON.parse(
|
|
16699
|
+
const raw = JSON.parse(readFileSync9(join7(dir, name), "utf-8"));
|
|
16663
16700
|
if (raw.discretionary === true) continue;
|
|
16664
16701
|
if (typeof raw.seen_at === "string" && raw.seen_at) continue;
|
|
16665
16702
|
receivedAt = raw.received_at;
|
|
@@ -16714,20 +16751,20 @@ function isMarkerGenuinelyAged(receivedAt, nowMs, thresholdMs) {
|
|
|
16714
16751
|
}
|
|
16715
16752
|
var DEFLECTION_COUNTER_SUFFIX = "-deflections.json";
|
|
16716
16753
|
function deflectionCounterPath(agentDir, channel) {
|
|
16717
|
-
return
|
|
16754
|
+
return join7(agentDir, `${channel}${DEFLECTION_COUNTER_SUFFIX}`);
|
|
16718
16755
|
}
|
|
16719
16756
|
function recordChannelDeflection(agentDir, channel, cause) {
|
|
16720
16757
|
if (!agentDir) return;
|
|
16721
16758
|
const path = deflectionCounterPath(agentDir, channel);
|
|
16722
16759
|
let counts = {};
|
|
16723
16760
|
try {
|
|
16724
|
-
const parsed = JSON.parse(
|
|
16761
|
+
const parsed = JSON.parse(readFileSync9(path, "utf-8"));
|
|
16725
16762
|
if (parsed && typeof parsed === "object") counts = parsed;
|
|
16726
16763
|
} catch {
|
|
16727
16764
|
}
|
|
16728
16765
|
counts[cause] = (counts[cause] ?? 0) + 1;
|
|
16729
16766
|
try {
|
|
16730
|
-
|
|
16767
|
+
writeFileSync8(path, JSON.stringify(counts), { mode: 384 });
|
|
16731
16768
|
} catch {
|
|
16732
16769
|
}
|
|
16733
16770
|
}
|
|
@@ -16769,7 +16806,7 @@ function redactId(id) {
|
|
|
16769
16806
|
}
|
|
16770
16807
|
var BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
|
|
16771
16808
|
var AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME ?? "unknown";
|
|
16772
|
-
var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ?
|
|
16809
|
+
var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join8(homedir3(), ".augmented", AGENT_CODE_NAME) : null;
|
|
16773
16810
|
var AGT_HOST = process.env.AGT_HOST ?? null;
|
|
16774
16811
|
var AGT_API_KEY = process.env.AGT_API_KEY ?? null;
|
|
16775
16812
|
var AGT_AGENT_ID = process.env.AGT_AGENT_ID ?? null;
|
|
@@ -16870,9 +16907,9 @@ if (!BOT_TOKEN) {
|
|
|
16870
16907
|
var stderrLogStream = null;
|
|
16871
16908
|
if (AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown") {
|
|
16872
16909
|
try {
|
|
16873
|
-
const logDir =
|
|
16910
|
+
const logDir = join8(homedir3(), ".augmented", AGENT_CODE_NAME);
|
|
16874
16911
|
mkdirSync7(logDir, { recursive: true });
|
|
16875
|
-
stderrLogStream = createWriteStream(
|
|
16912
|
+
stderrLogStream = createWriteStream(join8(logDir, "telegram-channel-stderr.log"), {
|
|
16876
16913
|
flags: "a",
|
|
16877
16914
|
mode: 384
|
|
16878
16915
|
});
|
|
@@ -17111,7 +17148,7 @@ function scheduleBusyAck(chatId, messageId, arrivedWhileBusy) {
|
|
|
17111
17148
|
let paneLogFreshAgeMs = null;
|
|
17112
17149
|
if (AGENT_DIR) {
|
|
17113
17150
|
try {
|
|
17114
|
-
const paneMtimeMs = statSync2(
|
|
17151
|
+
const paneMtimeMs = statSync2(join8(AGENT_DIR, "pane.log")).mtimeMs;
|
|
17115
17152
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
17116
17153
|
} catch {
|
|
17117
17154
|
}
|
|
@@ -17141,7 +17178,7 @@ function scheduleBusyAck(chatId, messageId, arrivedWhileBusy) {
|
|
|
17141
17178
|
function __resetBusyAckNoticeThrottle() {
|
|
17142
17179
|
lastBusyAckNoticeAt.clear();
|
|
17143
17180
|
}
|
|
17144
|
-
var RESTART_FLAGS_DIR =
|
|
17181
|
+
var RESTART_FLAGS_DIR = join8(homedir3(), ".augmented", "restart-flags");
|
|
17145
17182
|
function writeTelegramRestartConfirm(reply, requesterName) {
|
|
17146
17183
|
if (!RESTART_CONFIRM_FILE) return;
|
|
17147
17184
|
const marker = {
|
|
@@ -17403,7 +17440,7 @@ async function handleRestartCommand(opts) {
|
|
|
17403
17440
|
if (!existsSync6(RESTART_FLAGS_DIR)) {
|
|
17404
17441
|
mkdirSync7(RESTART_FLAGS_DIR, { recursive: true });
|
|
17405
17442
|
}
|
|
17406
|
-
const flagPath =
|
|
17443
|
+
const flagPath = join8(RESTART_FLAGS_DIR, `${AGENT_CODE_NAME}.flag`);
|
|
17407
17444
|
writeTelegramRestartConfirm(
|
|
17408
17445
|
{ chat_id: opts.chatId, message_id: opts.messageId },
|
|
17409
17446
|
opts.requesterName
|
|
@@ -17415,7 +17452,7 @@ async function handleRestartCommand(opts) {
|
|
|
17415
17452
|
reply: { chat_id: opts.chatId, message_id: opts.messageId }
|
|
17416
17453
|
};
|
|
17417
17454
|
const tmpPath = `${flagPath}.${process.pid}.${randomUUID3()}.tmp`;
|
|
17418
|
-
|
|
17455
|
+
writeFileSync9(tmpPath, JSON.stringify(flag) + "\n", "utf8");
|
|
17419
17456
|
renameSync6(tmpPath, flagPath);
|
|
17420
17457
|
process.stderr.write(
|
|
17421
17458
|
`telegram-channel(${AGENT_CODE_NAME}): /restart queued from chat ${redactId(opts.chatId)}
|
|
@@ -17794,14 +17831,14 @@ async function classifyRestartCommand(text) {
|
|
|
17794
17831
|
if (!ours) return "verification_failed";
|
|
17795
17832
|
return target === ours ? "act" : "ignore";
|
|
17796
17833
|
}
|
|
17797
|
-
var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ?
|
|
17798
|
-
var PENDING_INBOUND_DIR = AGENT_DIR ?
|
|
17799
|
-
var RECOVERY_OUTBOX_DIR = AGENT_DIR ?
|
|
17800
|
-
var RESTART_CONFIRM_FILE = AGENT_DIR ?
|
|
17834
|
+
var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join8(homedir3(), ".augmented", AGENT_CODE_NAME) : null;
|
|
17835
|
+
var PENDING_INBOUND_DIR = AGENT_DIR ? join8(AGENT_DIR, "telegram-pending-inbound") : null;
|
|
17836
|
+
var RECOVERY_OUTBOX_DIR = AGENT_DIR ? join8(AGENT_DIR, "telegram-recovery-outbox") : null;
|
|
17837
|
+
var RESTART_CONFIRM_FILE = AGENT_DIR ? join8(AGENT_DIR, "telegram-restart-confirm.json") : null;
|
|
17801
17838
|
var TELEGRAM_PROCESS_BOOT_MS = Date.now();
|
|
17802
|
-
var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ?
|
|
17803
|
-
var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ?
|
|
17804
|
-
var TELEGRAM_OFFSET_FILE = AGENT_DIR ?
|
|
17839
|
+
var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ? join8(AGENT_DIR, "telegram-recent-dms.json") : null;
|
|
17840
|
+
var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ? join8(AGENT_DIR, "telegram-channel-add-restart.json") : null;
|
|
17841
|
+
var TELEGRAM_OFFSET_FILE = AGENT_DIR ? join8(AGENT_DIR, "telegram-getupdates-offset.json") : null;
|
|
17805
17842
|
var recentDms = /* @__PURE__ */ new Map();
|
|
17806
17843
|
var recentDmPersister = TELEGRAM_RECENT_DMS_FILE ? createRecentDmPersister({
|
|
17807
17844
|
filePath: TELEGRAM_RECENT_DMS_FILE,
|
|
@@ -17856,7 +17893,7 @@ function safeMarkerName(chatId, messageId) {
|
|
|
17856
17893
|
}
|
|
17857
17894
|
function pendingInboundPath(chatId, messageId) {
|
|
17858
17895
|
if (!PENDING_INBOUND_DIR) return null;
|
|
17859
|
-
return
|
|
17896
|
+
return join8(PENDING_INBOUND_DIR, safeMarkerName(chatId, messageId));
|
|
17860
17897
|
}
|
|
17861
17898
|
function writePendingInboundMarker(chatId, messageId, chatType, undeliverable = false, payload) {
|
|
17862
17899
|
const path = pendingInboundPath(chatId, messageId);
|
|
@@ -17874,7 +17911,7 @@ function writePendingInboundMarker(chatId, messageId, chatType, undeliverable =
|
|
|
17874
17911
|
};
|
|
17875
17912
|
try {
|
|
17876
17913
|
mkdirSync7(PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
|
|
17877
|
-
|
|
17914
|
+
writeFileSync9(path, JSON.stringify(marker), { mode: 384 });
|
|
17878
17915
|
} catch (err) {
|
|
17879
17916
|
process.stderr.write(
|
|
17880
17917
|
`telegram-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
|
|
@@ -17902,7 +17939,7 @@ function rewriteTelegramMarkerInPlace(path, marker) {
|
|
|
17902
17939
|
function clearTelegramMarkerFileWithHeal(fullPath) {
|
|
17903
17940
|
let marker = null;
|
|
17904
17941
|
try {
|
|
17905
|
-
marker = JSON.parse(
|
|
17942
|
+
marker = JSON.parse(readFileSync10(fullPath, "utf-8"));
|
|
17906
17943
|
} catch {
|
|
17907
17944
|
}
|
|
17908
17945
|
if (marker && decideRecoveryHeal({
|
|
@@ -17919,7 +17956,7 @@ function clearTelegramMarkerFileWithHeal(fullPath) {
|
|
|
17919
17956
|
function markTelegramMarkerSeenInPlace(fullPath) {
|
|
17920
17957
|
let marker;
|
|
17921
17958
|
try {
|
|
17922
|
-
marker = JSON.parse(
|
|
17959
|
+
marker = JSON.parse(readFileSync10(fullPath, "utf-8"));
|
|
17923
17960
|
} catch {
|
|
17924
17961
|
return;
|
|
17925
17962
|
}
|
|
@@ -17931,7 +17968,7 @@ function markTelegramMarkerSeenInPlace(fullPath) {
|
|
|
17931
17968
|
function markTelegramMarkerSeenWithHeal(fullPath) {
|
|
17932
17969
|
let marker = null;
|
|
17933
17970
|
try {
|
|
17934
|
-
marker = JSON.parse(
|
|
17971
|
+
marker = JSON.parse(readFileSync10(fullPath, "utf-8"));
|
|
17935
17972
|
} catch {
|
|
17936
17973
|
return;
|
|
17937
17974
|
}
|
|
@@ -17947,7 +17984,7 @@ function readPendingInboundMarker(chatId, messageId) {
|
|
|
17947
17984
|
const path = pendingInboundPath(chatId, messageId);
|
|
17948
17985
|
if (!path || !existsSync6(path)) return null;
|
|
17949
17986
|
try {
|
|
17950
|
-
return JSON.parse(
|
|
17987
|
+
return JSON.parse(readFileSync10(path, "utf-8"));
|
|
17951
17988
|
} catch {
|
|
17952
17989
|
return null;
|
|
17953
17990
|
}
|
|
@@ -17967,10 +18004,10 @@ function nextRetryName(filename) {
|
|
|
17967
18004
|
async function processRecoveryOutboxFile(filename) {
|
|
17968
18005
|
if (!RECOVERY_OUTBOX_DIR) return;
|
|
17969
18006
|
if (filename.endsWith(".poison.json") || filename.endsWith(".tmp")) return;
|
|
17970
|
-
const fullPath =
|
|
18007
|
+
const fullPath = join8(RECOVERY_OUTBOX_DIR, filename);
|
|
17971
18008
|
let payload;
|
|
17972
18009
|
try {
|
|
17973
|
-
const raw =
|
|
18010
|
+
const raw = readFileSync10(fullPath, "utf-8");
|
|
17974
18011
|
payload = JSON.parse(raw);
|
|
17975
18012
|
} catch (err) {
|
|
17976
18013
|
process.stderr.write(
|
|
@@ -18036,7 +18073,7 @@ ${payload.text}`;
|
|
|
18036
18073
|
const next = nextRetryName(filename);
|
|
18037
18074
|
if (next) {
|
|
18038
18075
|
try {
|
|
18039
|
-
renameSync6(fullPath,
|
|
18076
|
+
renameSync6(fullPath, join8(RECOVERY_OUTBOX_DIR, next.next));
|
|
18040
18077
|
if (next.attempt >= MAX_RECOVERY_ATTEMPTS) {
|
|
18041
18078
|
process.stderr.write(
|
|
18042
18079
|
`telegram-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
|
|
@@ -18076,7 +18113,7 @@ function scanRecoveryRetries() {
|
|
|
18076
18113
|
if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
|
|
18077
18114
|
let mtimeMs;
|
|
18078
18115
|
try {
|
|
18079
|
-
mtimeMs = statSync2(
|
|
18116
|
+
mtimeMs = statSync2(join8(RECOVERY_OUTBOX_DIR, f)).mtimeMs;
|
|
18080
18117
|
} catch {
|
|
18081
18118
|
continue;
|
|
18082
18119
|
}
|
|
@@ -18106,7 +18143,7 @@ function startRecoveryOutboxWatcher() {
|
|
|
18106
18143
|
const watcher = watch(RECOVERY_OUTBOX_DIR, (event, filename) => {
|
|
18107
18144
|
if (event !== "rename" || !filename) return;
|
|
18108
18145
|
if (!isFirstAttemptOutboxFile(filename)) return;
|
|
18109
|
-
if (existsSync6(
|
|
18146
|
+
if (existsSync6(join8(RECOVERY_OUTBOX_DIR, filename))) {
|
|
18110
18147
|
void processRecoveryOutboxFile(filename);
|
|
18111
18148
|
}
|
|
18112
18149
|
});
|
|
@@ -18143,10 +18180,10 @@ function sweepTelegramStaleMarkers(thresholdMs) {
|
|
|
18143
18180
|
for (const filename of filenames) {
|
|
18144
18181
|
if (!filename.endsWith(".json")) continue;
|
|
18145
18182
|
if (filename.endsWith(".tmp")) continue;
|
|
18146
|
-
const fullPath =
|
|
18183
|
+
const fullPath = join8(PENDING_INBOUND_DIR, filename);
|
|
18147
18184
|
let marker;
|
|
18148
18185
|
try {
|
|
18149
|
-
marker = JSON.parse(
|
|
18186
|
+
marker = JSON.parse(readFileSync10(fullPath, "utf-8"));
|
|
18150
18187
|
} catch (err) {
|
|
18151
18188
|
process.stderr.write(
|
|
18152
18189
|
`telegram-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactId(filename)}: ${err.message}
|
|
@@ -18188,13 +18225,13 @@ var orphanSweepTimer = setInterval(() => {
|
|
|
18188
18225
|
checkWatchdogGiveUpNotice();
|
|
18189
18226
|
}, orphanSweepIntervalMs());
|
|
18190
18227
|
orphanSweepTimer.unref?.();
|
|
18191
|
-
var TELEGRAM_PROGRESS_HEARTBEAT_PATH = AGENT_DIR ?
|
|
18228
|
+
var TELEGRAM_PROGRESS_HEARTBEAT_PATH = AGENT_DIR ? join8(AGENT_DIR, "channel-progress-heartbeat.json") : null;
|
|
18192
18229
|
var telegramTrackedProgress = null;
|
|
18193
18230
|
var telegramProgressTickRunning = false;
|
|
18194
18231
|
function readTelegramProgressHeartbeat() {
|
|
18195
18232
|
if (!TELEGRAM_PROGRESS_HEARTBEAT_PATH || !existsSync6(TELEGRAM_PROGRESS_HEARTBEAT_PATH)) return null;
|
|
18196
18233
|
try {
|
|
18197
|
-
return parseProgressHeartbeat(
|
|
18234
|
+
return parseProgressHeartbeat(readFileSync10(TELEGRAM_PROGRESS_HEARTBEAT_PATH, "utf-8"));
|
|
18198
18235
|
} catch {
|
|
18199
18236
|
return null;
|
|
18200
18237
|
}
|
|
@@ -18208,7 +18245,7 @@ function findTelegramProgressTarget() {
|
|
|
18208
18245
|
if (!name.endsWith(".json")) continue;
|
|
18209
18246
|
let m;
|
|
18210
18247
|
try {
|
|
18211
|
-
m = JSON.parse(
|
|
18248
|
+
m = JSON.parse(readFileSync10(join8(PENDING_INBOUND_DIR, name), "utf-8"));
|
|
18212
18249
|
} catch {
|
|
18213
18250
|
continue;
|
|
18214
18251
|
}
|
|
@@ -18339,7 +18376,7 @@ function listPendingInboundChatIds() {
|
|
|
18339
18376
|
if (!name.endsWith(".json")) continue;
|
|
18340
18377
|
try {
|
|
18341
18378
|
const marker = JSON.parse(
|
|
18342
|
-
|
|
18379
|
+
readFileSync10(join8(PENDING_INBOUND_DIR, name), "utf8")
|
|
18343
18380
|
);
|
|
18344
18381
|
if (typeof marker.seen_at === "string" && marker.seen_at) continue;
|
|
18345
18382
|
if (typeof marker.chat_id === "string" && marker.chat_id) chats.add(marker.chat_id);
|
|
@@ -18381,7 +18418,7 @@ async function notifyWatchdogGiveUp(chatId) {
|
|
|
18381
18418
|
}
|
|
18382
18419
|
function checkWatchdogGiveUpNotice() {
|
|
18383
18420
|
if (!AGENT_DIR) return;
|
|
18384
|
-
const signalAtMs = readGiveUpSignalAtMs(
|
|
18421
|
+
const signalAtMs = readGiveUpSignalAtMs(join8(AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
|
|
18385
18422
|
const act = decideGiveUpNotice({
|
|
18386
18423
|
signalAtMs,
|
|
18387
18424
|
lastHandledAtMs: lastGiveUpHandledAtMs,
|
|
@@ -19092,17 +19129,17 @@ async function replayPendingTelegramMarkers() {
|
|
|
19092
19129
|
let paneFreshAgeMs = null;
|
|
19093
19130
|
if (AGENT_DIR) {
|
|
19094
19131
|
try {
|
|
19095
|
-
paneFreshAgeMs = Math.max(0, now - statSync2(
|
|
19132
|
+
paneFreshAgeMs = Math.max(0, now - statSync2(join8(AGENT_DIR, "pane.log")).mtimeMs);
|
|
19096
19133
|
} catch {
|
|
19097
19134
|
}
|
|
19098
19135
|
}
|
|
19099
19136
|
const entries = [];
|
|
19100
19137
|
for (const name of filenames) {
|
|
19101
19138
|
if (!name.endsWith(".json") || name.endsWith(".tmp")) continue;
|
|
19102
|
-
const fullPath =
|
|
19139
|
+
const fullPath = join8(PENDING_INBOUND_DIR, name);
|
|
19103
19140
|
let marker;
|
|
19104
19141
|
try {
|
|
19105
|
-
marker = JSON.parse(
|
|
19142
|
+
marker = JSON.parse(readFileSync10(fullPath, "utf-8"));
|
|
19106
19143
|
} catch {
|
|
19107
19144
|
continue;
|
|
19108
19145
|
}
|
|
@@ -19567,7 +19604,7 @@ async function pollLoop() {
|
|
|
19567
19604
|
let paneLogFreshAgeMs = null;
|
|
19568
19605
|
if (AGENT_DIR) {
|
|
19569
19606
|
try {
|
|
19570
|
-
const paneMtimeMs = statSync2(
|
|
19607
|
+
const paneMtimeMs = statSync2(join8(AGENT_DIR, "pane.log")).mtimeMs;
|
|
19571
19608
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
19572
19609
|
} catch {
|
|
19573
19610
|
}
|
|
@@ -19648,6 +19685,10 @@ async function pollLoop() {
|
|
|
19648
19685
|
} : {}
|
|
19649
19686
|
}
|
|
19650
19687
|
};
|
|
19688
|
+
recordLaneClassification(TELEGRAM_AGENT_DIR, "telegram", {
|
|
19689
|
+
lane: "conversational",
|
|
19690
|
+
expectsReply: true
|
|
19691
|
+
});
|
|
19651
19692
|
trackPendingMessage(
|
|
19652
19693
|
chatId,
|
|
19653
19694
|
messageId,
|
|
@@ -57,6 +57,55 @@ function readAndResetChannelDeflections(agentHomeDir) {
|
|
|
57
57
|
}
|
|
58
58
|
return any ? total : null;
|
|
59
59
|
}
|
|
60
|
+
var LANE_CLASSIFICATION_COUNTER_SUFFIX = "-lane-classifications.json";
|
|
61
|
+
var SUSPECTED_MISCLASSIFICATION_KEY = "suspected_misclassification";
|
|
62
|
+
var KNOWN_LANES = /* @__PURE__ */ new Set(["conversational", "directive", "liveness"]);
|
|
63
|
+
var KNOWN_LANE_SOURCES = /* @__PURE__ */ new Set(["slack", "telegram", "msteams", "direct-chat"]);
|
|
64
|
+
function isKnownLaneClassificationKey(key) {
|
|
65
|
+
if (key === SUSPECTED_MISCLASSIFICATION_KEY) return true;
|
|
66
|
+
const parts = key.split("|");
|
|
67
|
+
if (parts.length !== 3) return false;
|
|
68
|
+
const [lane, expectsReply, source] = parts;
|
|
69
|
+
return KNOWN_LANES.has(lane) && (expectsReply === "true" || expectsReply === "false") && KNOWN_LANE_SOURCES.has(source);
|
|
70
|
+
}
|
|
71
|
+
function readAndResetChannelLaneClassifications(agentHomeDir) {
|
|
72
|
+
let names;
|
|
73
|
+
try {
|
|
74
|
+
names = readdirSync(agentHomeDir);
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const total = {};
|
|
79
|
+
let any = false;
|
|
80
|
+
for (const name of names) {
|
|
81
|
+
if (!name.endsWith(LANE_CLASSIFICATION_COUNTER_SUFFIX)) continue;
|
|
82
|
+
const full = join(agentHomeDir, name);
|
|
83
|
+
const consuming = `${full}.consuming`;
|
|
84
|
+
try {
|
|
85
|
+
renameSync(full, consuming);
|
|
86
|
+
} catch {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const parsed = JSON.parse(readFileSync(consuming, "utf8"));
|
|
91
|
+
if (parsed && typeof parsed === "object") {
|
|
92
|
+
for (const [key, raw] of Object.entries(parsed)) {
|
|
93
|
+
if (!isKnownLaneClassificationKey(key)) continue;
|
|
94
|
+
if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) {
|
|
95
|
+
total[key] = (total[key] ?? 0) + Math.floor(raw);
|
|
96
|
+
any = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
unlinkSync(consuming);
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return any ? total : null;
|
|
108
|
+
}
|
|
60
109
|
var DEFAULT_INTERVAL_MS = 5 * 60 * 1e3;
|
|
61
110
|
function getResponsivenessIntervalMs() {
|
|
62
111
|
const raw = process.env.AUGMENTED_RESPONSIVENESS_INTERVAL_MS;
|
|
@@ -235,6 +284,10 @@ function collectResponsivenessProbes(codeNames, now = /* @__PURE__ */ new Date()
|
|
|
235
284
|
if (deflections) {
|
|
236
285
|
result.deflections = deflections;
|
|
237
286
|
}
|
|
287
|
+
const laneClassifications = readAndResetChannelLaneClassifications(dirname(panePath));
|
|
288
|
+
if (laneClassifications) {
|
|
289
|
+
result.lane_classifications = laneClassifications;
|
|
290
|
+
}
|
|
238
291
|
results.push(result);
|
|
239
292
|
} catch {
|
|
240
293
|
}
|
|
@@ -248,6 +301,7 @@ export {
|
|
|
248
301
|
livePendingInboundOldestAgeSeconds,
|
|
249
302
|
oldestLivePendingInboundMtimeMs,
|
|
250
303
|
parkPendingInbound,
|
|
251
|
-
readAndResetChannelDeflections
|
|
304
|
+
readAndResetChannelDeflections,
|
|
305
|
+
readAndResetChannelLaneClassifications
|
|
252
306
|
};
|
|
253
|
-
//# sourceMappingURL=responsiveness-probe-
|
|
307
|
+
//# sourceMappingURL=responsiveness-probe-QU5TY2K4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/responsiveness-probe.ts"],"sourcesContent":["/**\n * ENG-5399 — Tier 1 responsiveness probe (manager-side).\n *\n * Cheap, fast-cadence canary that catches \"agent went silent\" inside\n * minutes, well before the existing synthetic-probe cron's ~35 min\n * staleness window (`SyntheticReplyAgeSeconds`, ENG-5122).\n *\n * Mechanism: for each managed agent, read the mtime of the agent's\n * `pane.log` and report `now - mtime` as `PaneActivityAgeSeconds` via\n * a new `/host/responsiveness-probe` endpoint. `pane.log` is the\n * tmux pipe-pane sink set up by `setupPaneLog()` — any visible\n * activity (assistant turns, tool calls, in-place progress\n * heartbeats) bumps its mtime. A silent agent has a steadily\n * climbing age that lands in CloudWatch and trips a per-agent alarm.\n *\n * ENG-6017 adds a second per-agent signal on the same cadence:\n * `pending_inbound_oldest_age_seconds` — the age of the oldest marker\n * file across the agent's `*-pending-inbound/` directories (written by\n * the channel MCP servers for inbounds awaiting delivery). This is the\n * one artifact of the \"message typed but never submitted\" failure mode\n * that every other canary is blind to: in the koda incident\n * (2026-06-04) an operator Slack DM sat undelivered for 40+ minutes\n * while pane-activity stayed fresh (health checks), synthetic probes\n * were answered by the one-shot fallback, and heartbeat/session-alive\n * only reflect manager health. The field is OMITTED (not zero) when the\n * agent has no pending-inbound markers — the API treats absent as\n * \"no signal\", never as \"healthy\" (absent-vs-zero matters for\n * mixed-version fleets where old CLIs don't report it at all).\n *\n * Run from `pollCycle()` in `manager-worker.ts` on a configurable\n * interval (default 5 min via `AUGMENTED_RESPONSIVENESS_INTERVAL_MS`).\n */\n\nimport { mkdirSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { paneLogPath } from './persistent-session.js';\n\nexport interface ResponsivenessProbeResult {\n code_name: string;\n pane_activity_age_seconds: number;\n /**\n * ENG-6017: age (s) of the oldest marker file across the agent's\n * `*-pending-inbound/` directories. Omitted when no markers exist —\n * absent means \"no signal\", NOT \"zero / healthy\".\n */\n pending_inbound_oldest_age_seconds?: number;\n /**\n * ENG-6327: per-cause inbound deflection counts since the last probe (read +\n * RESET from the channel servers' `<channel>-deflections.json` counter files).\n * Omitted when there were none. Keyed by DeflectionCause.\n */\n deflections?: Record<string, number>;\n /**\n * ENG-6408 / ADR-0024 Slice 1.5: shadow lane-classification counts since the\n * last probe (read + RESET from `<channel>-lane-classifications.json`). Keyed\n * by `<lane>|<expects_reply>|<source>` plus the reserved\n * `suspected_misclassification` canary. Omitted when there were none.\n */\n lane_classifications?: Record<string, number>;\n}\n\n/**\n * ENG-6327 — per-channel deflection counter file-layout contract. The channel\n * MCP servers increment `<channel>-deflections.json` in the agent home (via\n * recordChannelDeflection in packages/mcp/ack-reaction.ts); apps/cli does not\n * depend on @integrity-labs/mcp, so the manager re-implements the read against\n * this contract — the same read-only, no-IPC posture as the `*-pending-inbound`\n * scan above. Body is a JSON object keyed by cause with integer counts.\n */\nconst DEFLECTION_COUNTER_SUFFIX = '-deflections.json';\nconst KNOWN_DEFLECTION_CAUSES = [\n 'integration_down',\n 'session_dead',\n 'wedged',\n 'busy',\n 'duplicate', // ENG-6270 — a redundant re-delivery dropped at fresh ingress\n 'replay_orphaned', // ENG-6355 — a replay-payload marker GC'd without ever being replayed\n 'unknown',\n] as const;\n\n/**\n * Read and RESET every `<channel>-deflections.json` in an agent home, returning\n * the summed counts by cause (or null when there are none). Consumes via atomic\n * rename-then-read-then-unlink so an increment racing the reset is carried into\n * the next window rather than lost. Only known causes are accumulated so a\n * corrupt file can't smuggle an unbounded dimension into CloudWatch.\n *\n * Reset-on-read is required: these are deltas-since-last-consume, so the metric\n * would over-count if they weren't cleared each cycle. The trade-off is that a\n * failed POST loses that cycle's counts (under-count) — acceptable for a\n * frequency metric and consistent with the other best-effort probe siblings;\n * unlike the in-memory give-up counter, file-based counts aren't re-credited\n * on POST failure.\n */\nexport function readAndResetChannelDeflections(\n agentHomeDir: string,\n): Record<string, number> | null {\n let names: string[];\n try {\n names = readdirSync(agentHomeDir);\n } catch {\n return null;\n }\n const total: Record<string, number> = {};\n let any = false;\n for (const name of names) {\n if (!name.endsWith(DEFLECTION_COUNTER_SUFFIX)) continue;\n const full = join(agentHomeDir, name);\n const consuming = `${full}.consuming`;\n try {\n renameSync(full, consuming); // atomic; replaces any stale .consuming from a crashed cycle\n } catch {\n continue; // vanished / not a regular file — skip\n }\n try {\n const parsed = JSON.parse(readFileSync(consuming, 'utf8')) as Record<string, unknown>;\n if (parsed && typeof parsed === 'object') {\n for (const cause of KNOWN_DEFLECTION_CAUSES) {\n const n = parsed[cause];\n if (typeof n === 'number' && Number.isFinite(n) && n > 0) {\n total[cause] = (total[cause] ?? 0) + Math.floor(n);\n any = true;\n }\n }\n }\n } catch {\n /* corrupt — drop it */\n }\n try {\n unlinkSync(consuming);\n } catch {\n /* non-fatal */\n }\n }\n return any ? total : null;\n}\n\n/**\n * ENG-6408 / ADR-0024 Slice 1.5 - per-channel lane-classification counter\n * file-layout contract. The channel MCP servers increment\n * `<channel>-lane-classifications.json` in the agent home (via\n * recordLaneClassification in packages/mcp/inbound-lane-telemetry.ts); apps/cli\n * does not depend on @integrity-labs/mcp, so the manager re-implements the read\n * against this contract (same posture as the deflection scan above). Body is a\n * JSON object keyed by `<lane>|<expects_reply>|<source>` (plus the reserved\n * `suspected_misclassification`) with integer counts.\n */\nconst LANE_CLASSIFICATION_COUNTER_SUFFIX = '-lane-classifications.json';\nconst SUSPECTED_MISCLASSIFICATION_KEY = 'suspected_misclassification';\nconst KNOWN_LANES = new Set(['conversational', 'directive', 'liveness']);\nconst KNOWN_LANE_SOURCES = new Set(['slack', 'telegram', 'msteams', 'direct-chat']);\n\n/**\n * Only well-formed composite keys (and the misclassification canary) are\n * accumulated, so a corrupt counter file can't smuggle an unbounded dimension\n * into CloudWatch - the same bounding the deflection reader applies.\n */\nfunction isKnownLaneClassificationKey(key: string): boolean {\n if (key === SUSPECTED_MISCLASSIFICATION_KEY) return true;\n const parts = key.split('|');\n if (parts.length !== 3) return false;\n const [lane, expectsReply, source] = parts as [string, string, string];\n return (\n KNOWN_LANES.has(lane) &&\n (expectsReply === 'true' || expectsReply === 'false') &&\n KNOWN_LANE_SOURCES.has(source)\n );\n}\n\n/**\n * Read and RESET every `<channel>-lane-classifications.json` in an agent home,\n * returning the summed counts by key (or null when there are none). Mirrors\n * readAndResetChannelDeflections exactly: atomic rename-then-read-then-unlink so\n * an increment racing the reset carries into the next window, and only known\n * keys are accumulated. SHADOW telemetry - informs the Slice 2 gate, gates\n * nothing itself.\n */\nexport function readAndResetChannelLaneClassifications(\n agentHomeDir: string,\n): Record<string, number> | null {\n let names: string[];\n try {\n names = readdirSync(agentHomeDir);\n } catch {\n return null;\n }\n const total: Record<string, number> = {};\n let any = false;\n for (const name of names) {\n if (!name.endsWith(LANE_CLASSIFICATION_COUNTER_SUFFIX)) continue;\n const full = join(agentHomeDir, name);\n const consuming = `${full}.consuming`;\n try {\n renameSync(full, consuming); // atomic; replaces any stale .consuming from a crashed cycle\n } catch {\n continue; // vanished / not a regular file — skip\n }\n try {\n const parsed = JSON.parse(readFileSync(consuming, 'utf8')) as Record<string, unknown>;\n if (parsed && typeof parsed === 'object') {\n for (const [key, raw] of Object.entries(parsed)) {\n if (!isKnownLaneClassificationKey(key)) continue;\n if (typeof raw === 'number' && Number.isFinite(raw) && raw > 0) {\n total[key] = (total[key] ?? 0) + Math.floor(raw);\n any = true;\n }\n }\n }\n } catch {\n /* corrupt — drop it */\n }\n try {\n unlinkSync(consuming);\n } catch {\n /* non-fatal */\n }\n }\n return any ? total : null;\n}\n\nconst DEFAULT_INTERVAL_MS = 5 * 60 * 1000;\n\nexport function getResponsivenessIntervalMs(): number {\n const raw = process.env.AUGMENTED_RESPONSIVENESS_INTERVAL_MS;\n if (!raw) return DEFAULT_INTERVAL_MS;\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_INTERVAL_MS;\n}\n\n/**\n * ENG-6017: oldest pending-inbound marker mtime (ms epoch) for an agent,\n * or null when the agent has no markers / no pending-inbound dirs.\n *\n * The channel MCP servers (slack-channel, telegram-channel, …) write one\n * marker file per inbound into `~/.augmented/<codeName>/<channel>-pending-\n * inbound/` and clear it when the agent acknowledges the message. The\n * directory layout is the contract here — read-only, no IPC with the MCP\n * (the MCP and CLI release independently; file mtimes need no protocol).\n *\n * ENG-6072: only plain, non-hidden files count as markers. The msteams MCP\n * keeps `.markers/` and `.processed/` housekeeping SUBDIRECTORIES inside its\n * pending-inbound dir; their mtimes never advance, so statting every dirent\n * made the gauge climb forever and fired pending-inbound-stale on agents with\n * zero stranded messages (kylie ~3.4d / scout ~34h false ALARMs the moment\n * ENG-6023 activated the alarm). Dot-entries are skipped wholesale — the\n * hidden namespace is reserved for MCP bookkeeping, never for markers.\n */\nfunction oldestPendingInboundMtimeMs(agentHomeDir: string): number | null {\n let oldest: number | null = null;\n let entries;\n try {\n entries = readdirSync(agentHomeDir, { withFileTypes: true });\n } catch {\n return null; // agent home missing — nothing to report\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith('-pending-inbound')) continue;\n const dir = join(agentHomeDir, entry.name);\n let files;\n try {\n files = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const file of files) {\n if (!file.isFile() || file.name.startsWith('.')) continue;\n try {\n const mtimeMs = statSync(join(dir, file.name)).mtimeMs;\n if (oldest === null || mtimeMs < oldest) oldest = mtimeMs;\n } catch {\n // Marker drained between readdir and stat — that's the happy path.\n }\n }\n }\n return oldest;\n}\n\n/**\n * ENG-6160 / ENG-6319: read a marker's classification flags.\n * - `{...}` → parsed flags.\n * - `null` → vanished mid-scan (ENOENT) — drained between stat and\n * read, the happy path; callers exclude it.\n * - `'malformed'` → present but unreadable for another reason. The live\n * scan treats this as LIVE (a corrupt marker can never\n * mask a real wedge); park leaves it in place (a corrupt\n * marker must never become a dropped message).\n */\ninterface MarkerFlags {\n /** ENG-5846: dead-lettered by the channel (⏳-noticed, never drainable). */\n undeliverable: boolean;\n /**\n * ENG-6319: auto-followed participant-thread inbound the agent may\n * legitimately skip. Excluded from the wedge live-scan (a deliberate skip\n * must not read as \"failing to drain\" and force-respawn a healthy\n * session) but still parked across respawns — it may be a real\n * operator message awaiting a reply.\n */\n discretionary: boolean;\n}\n\nfunction readMarkerFlags(markerPath: string): MarkerFlags | null | 'malformed' {\n try {\n const parsed = JSON.parse(readFileSync(markerPath, 'utf8')) as {\n undeliverable?: unknown;\n discretionary?: unknown;\n };\n return {\n undeliverable: parsed?.undeliverable === true,\n discretionary: parsed?.discretionary === true,\n };\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === 'ENOENT' ? null : 'malformed';\n }\n}\n\n/**\n * ENG-6160: oldest *LIVE* pending-inbound marker mtime (ms epoch) for an agent,\n * or null when there is no live marker. \"Live\" excludes:\n *\n * - markers older than `sessionStartMs` — a marker written before the current\n * session started is a leftover from a PREVIOUS session and cannot mean\n * *this* session is failing to drain. This is the load-bearing exclusion:\n * without it, an orphan marker survives a fresh respawn and the wedge\n * detector re-fires forever on a healthy idle agent (the sherlock enforce\n * loop, 2026-06-08: `inboundAge=3389s` on a `● Ready.` session).\n * - markers flagged `undeliverable: true` — already dead-lettered by the channel.\n * - markers flagged `discretionary: true` (ENG-6319) — skippable auto-followed\n * participant-thread inbound; a deliberate skip must not force-respawn a\n * healthy session.\n *\n * Distinct from `oldestPendingInboundMtimeMs` (which counts ALL markers and\n * feeds the ENG-6017 `pending-inbound-stale` CloudWatch alarm — that alarm\n * *wants* to fire on a stuck inbound, so its semantics must NOT change). This\n * variant is wedge-detection-only.\n */\nexport function oldestLivePendingInboundMtimeMs(\n agentHomeDir: string,\n opts: { sessionStartMs?: number | null } = {},\n): number | null {\n const sessionStartMs = opts.sessionStartMs ?? null;\n let oldest: number | null = null;\n let entries;\n try {\n entries = readdirSync(agentHomeDir, { withFileTypes: true });\n } catch {\n return null;\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith('-pending-inbound')) continue;\n const dir = join(agentHomeDir, entry.name);\n let files;\n try {\n files = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const file of files) {\n if (!file.isFile() || file.name.startsWith('.')) continue;\n const full = join(dir, file.name);\n let mtimeMs: number;\n try {\n mtimeMs = statSync(full).mtimeMs;\n } catch {\n continue; // drained between readdir and stat — happy path\n }\n if (sessionStartMs !== null && mtimeMs < sessionStartMs) continue; // pre-session leftover\n const flags = readMarkerFlags(full);\n if (flags === null) continue; // vanished between stat and read — drained, exclude\n if (flags !== 'malformed' && (flags.undeliverable || flags.discretionary)) continue;\n if (oldest === null || mtimeMs < oldest) oldest = mtimeMs;\n }\n }\n return oldest;\n}\n\n/**\n * ENG-6160: age (s) of the oldest LIVE pending-inbound marker for an agent, or\n * null when none. The wedge detector uses this instead of the alarm-facing\n * `pending_inbound_oldest_age_seconds` so a stale/dead-letter marker can't\n * false-fire a respawn.\n */\nexport function livePendingInboundOldestAgeSeconds(\n codeName: string,\n sessionStartMs: number | null,\n now: Date = new Date(),\n): number | null {\n const oldest = oldestLivePendingInboundMtimeMs(dirname(paneLogPath(codeName)), { sessionStartMs });\n if (oldest === null) return null;\n return Math.max(0, Math.floor((now.getTime() - oldest) / 1000));\n}\n\n/**\n * ENG-6160: move every pending-inbound marker for an agent aside into a sibling\n * `<channel>-pending-inbound-stale/` directory (NOT silently deleted — the\n * payload pointer is preserved for forensics), returning the count moved.\n *\n * ENG-6289: no longer called on wedge respawn — the wedge path parks instead\n * (see `parkPendingInbound` above; blanket dead-letter permanently dropped the\n * user's message). Kept as the explicit \"move everything aside\" seam for tests\n * and operator emergencies. The stale dir does not end in `-pending-inbound`,\n * so neither the probe nor this scan re-counts moved markers.\n */\n/**\n * ENG-6289: park-not-drop. On a force-fresh wedge respawn, KEEP undrained\n * pending-inbound markers in their live dirs instead of dead-lettering them —\n * the fresh session's orient hook surfaces them (\"N queued messages\" + details)\n * and ENG-5969 replay (when enabled) re-pushes their payloads. Markers are NOT\n * rewritten (no counter, no mtime bump): the ENG-6160 pre-session exclusion in\n * `oldestLivePendingInboundMtimeMs` already keeps an untouched parked marker\n * out of the fresh session's wedge signal, and re-delivery stays bounded by\n * the existing machinery — the channel-side `replay_count` cap (≤3) and the\n * orphan sweep's received_at TTL. A manager-side rewrite would be the first\n * cross-process writer into marker files, where a torn read in the channel\n * sweep DELETES the marker (`unlinkSync` on parse failure) — the exact drop\n * this function exists to prevent.\n *\n * Only markers already flagged `undeliverable: true` are dead-lettered (moved\n * to `-stale`) — the channel already gave the user the ⏳ notice for those, so\n * nothing can ever drain them. Malformed markers are LEFT IN PLACE, matching\n * the live-scan philosophy above (a corrupt marker must never mask — or\n * become — a dropped message).\n *\n * The msteams dir is skipped wholesale: its top-level files are raw Bot\n * Framework activity payloads (the transport queue, not bookkeeping — real\n * markers live in the hidden `.markers/` subdir this scan never touches), and\n * the teams channel server's boot drain redelivers them to the fresh session\n * on its own. Moving them aside (what the pre-ENG-6289 dead-letter did) was\n * actively defeating the one channel with native respawn recovery.\n */\nexport interface ParkPendingInboundResult {\n parked: number;\n deadLettered: number;\n}\n\n/**\n * Move one marker into the sibling `-stale` dead-letter dir (moved, not\n * deleted — preserved for forensics). Returns true on success; best-effort —\n * a marker that vanished or can't move is left as-is.\n */\nfunction moveMarkerToStale(dir: string, deadDir: string, name: string): boolean {\n try {\n mkdirSync(deadDir, { recursive: true });\n renameSync(join(dir, name), join(deadDir, name));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function parkPendingInbound(codeName: string, _now: Date = new Date()): ParkPendingInboundResult {\n const home = dirname(paneLogPath(codeName));\n const result: ParkPendingInboundResult = { parked: 0, deadLettered: 0 };\n let entries;\n try {\n entries = readdirSync(home, { withFileTypes: true });\n } catch {\n return result;\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith('-pending-inbound')) continue;\n if (entry.name === 'msteams-pending-inbound') continue; // transport queue — boot drain owns recovery\n const dir = join(home, entry.name);\n const deadDir = join(home, `${entry.name}-stale`);\n let files;\n try {\n files = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const file of files) {\n if (!file.isFile() || file.name.startsWith('.')) continue;\n const flags = readMarkerFlags(join(dir, file.name));\n if (flags === null) continue; // drained mid-scan — already gone\n // Only undeliverable markers dead-letter. Discretionary markers\n // (ENG-6319) PARK like engaged ones — they may be a real operator\n // message awaiting a reply (the live silent-loss class); malformed\n // markers park too (corrupt must never become a drop).\n if (flags !== 'malformed' && flags.undeliverable) {\n if (moveMarkerToStale(dir, deadDir, file.name)) result.deadLettered++;\n } else {\n result.parked++;\n }\n }\n }\n return result;\n}\n\nexport function deadLetterPendingInbound(codeName: string, _now: Date = new Date()): number {\n const home = dirname(paneLogPath(codeName));\n let moved = 0;\n let entries;\n try {\n entries = readdirSync(home, { withFileTypes: true });\n } catch {\n return 0;\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith('-pending-inbound')) continue;\n const dir = join(home, entry.name);\n const deadDir = join(home, `${entry.name}-stale`);\n let files;\n try {\n files = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const file of files) {\n if (!file.isFile() || file.name.startsWith('.')) continue;\n if (moveMarkerToStale(dir, deadDir, file.name)) moved++;\n }\n }\n return moved;\n}\n\n/**\n * Compute the pane.log age for each agent. Missing or unreadable\n * pane.log returns null — the caller should drop those entries\n * rather than fabricate a \"fresh\" or \"ancient\" value. A missing\n * file means the agent has never spawned in this manager generation,\n * which is a separate problem covered by SessionAliveAgeSeconds.\n */\nexport function collectResponsivenessProbes(\n codeNames: string[],\n now: Date = new Date(),\n): ResponsivenessProbeResult[] {\n const nowMs = now.getTime();\n const results: ResponsivenessProbeResult[] = [];\n for (const codeName of codeNames) {\n try {\n const panePath = paneLogPath(codeName);\n const mtimeMs = statSync(panePath).mtimeMs;\n const ageSeconds = Math.max(0, Math.floor((nowMs - mtimeMs) / 1000));\n const result: ResponsivenessProbeResult = {\n code_name: codeName,\n pane_activity_age_seconds: ageSeconds,\n };\n // ENG-6017: piggyback the pending-inbound drain-age scan on the same\n // cadence. Field omitted (not 0) when there are no markers.\n const oldestMarkerMs = oldestPendingInboundMtimeMs(dirname(panePath));\n if (oldestMarkerMs !== null) {\n result.pending_inbound_oldest_age_seconds = Math.max(\n 0,\n Math.floor((nowMs - oldestMarkerMs) / 1000),\n );\n }\n // ENG-6327: read + RESET the per-channel deflection counters on the same\n // cadence so each cause's frequency reaches CloudWatch (ChannelDeflections,\n // Cause dimension). Omitted when there were none this window.\n const deflections = readAndResetChannelDeflections(dirname(panePath));\n if (deflections) {\n result.deflections = deflections;\n }\n // ENG-6408 / ADR-0024 Slice 1.5: read + RESET the shadow lane-classification\n // counters on the same cadence so the classification mix (and the\n // misclassification canary) reaches CloudWatch. Omitted when none this window.\n const laneClassifications = readAndResetChannelLaneClassifications(dirname(panePath));\n if (laneClassifications) {\n result.lane_classifications = laneClassifications;\n }\n results.push(result);\n } catch {\n // No pane.log yet (fresh agent, never spawned) — skip. The\n // session-alive monitor already covers the \"should be running\n // but isn't\" case.\n }\n }\n return results;\n}\n"],"mappings":"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","names":[]}
|