@integrity-labs/agt-cli 0.23.1 → 0.24.0
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-2TOCO5D2.js → chunk-HSIESZMZ.js} +23 -1
- package/dist/{chunk-2TOCO5D2.js.map → chunk-HSIESZMZ.js.map} +1 -1
- package/dist/{chunk-Q4QD3TAC.js → chunk-WZTRMJM4.js} +205 -159
- package/dist/chunk-WZTRMJM4.js.map +1 -0
- package/dist/{chunk-TCCBS3PD.js → chunk-ZKQGDH3T.js} +2 -2
- package/dist/{claude-pair-runtime-KUWBZW33.js → claude-pair-runtime-XCFWTH6T.js} +2 -2
- package/dist/lib/manager-worker.js +551 -251
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/index.js +71 -0
- package/dist/mcp/slack-channel.js +32 -246
- package/dist/mcp/telegram-channel.js +30 -232
- package/dist/pane-mcp-banner-scraper-JA437JIB.js +22 -0
- package/dist/pane-mcp-banner-scraper-JA437JIB.js.map +1 -0
- package/dist/{persistent-session-XEA4SPAN.js → persistent-session-L4YIJJML.js} +3 -3
- package/dist/{responsiveness-probe-VWPOCABI.js → responsiveness-probe-YRLESO54.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-Q4QD3TAC.js.map +0 -1
- /package/dist/{chunk-TCCBS3PD.js.map → chunk-ZKQGDH3T.js.map} +0 -0
- /package/dist/{claude-pair-runtime-KUWBZW33.js.map → claude-pair-runtime-XCFWTH6T.js.map} +0 -0
- /package/dist/{persistent-session-XEA4SPAN.js.map → persistent-session-L4YIJJML.js.map} +0 -0
- /package/dist/{responsiveness-probe-VWPOCABI.js.map → responsiveness-probe-YRLESO54.js.map} +0 -0
|
@@ -14295,21 +14295,16 @@ var StdioServerTransport = class {
|
|
|
14295
14295
|
import https from "https";
|
|
14296
14296
|
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
14297
14297
|
import {
|
|
14298
|
-
closeSync,
|
|
14299
14298
|
createWriteStream,
|
|
14300
14299
|
existsSync,
|
|
14301
|
-
fsyncSync,
|
|
14302
|
-
ftruncateSync,
|
|
14303
14300
|
mkdirSync as mkdirSync2,
|
|
14304
|
-
openSync,
|
|
14305
14301
|
readFileSync,
|
|
14306
14302
|
readdirSync,
|
|
14307
14303
|
renameSync as renameSync2,
|
|
14308
|
-
statSync
|
|
14304
|
+
statSync,
|
|
14309
14305
|
unlinkSync as unlinkSync2,
|
|
14310
14306
|
watch,
|
|
14311
|
-
writeFileSync as writeFileSync2
|
|
14312
|
-
writeSync
|
|
14307
|
+
writeFileSync as writeFileSync2
|
|
14313
14308
|
} from "fs";
|
|
14314
14309
|
import { homedir as homedir2 } from "os";
|
|
14315
14310
|
import { join as join2 } from "path";
|
|
@@ -15674,40 +15669,6 @@ function createTelegramProgressFlush(opts) {
|
|
|
15674
15669
|
};
|
|
15675
15670
|
}
|
|
15676
15671
|
|
|
15677
|
-
// src/pending-reminder-schedule.ts
|
|
15678
|
-
import { statSync } from "fs";
|
|
15679
|
-
var REMINDER_SCHEDULE_MS = [5, 10, 20].map((m) => m * 6e4);
|
|
15680
|
-
var MAX_REMINDERS = REMINDER_SCHEDULE_MS.length;
|
|
15681
|
-
var RESPONSE_TIMEOUT_MS = REMINDER_SCHEDULE_MS[0];
|
|
15682
|
-
function nextReminderFireAtMs(receivedAtMs, currentReminderCount) {
|
|
15683
|
-
const safeCount = Number.isFinite(currentReminderCount) ? Math.max(0, Math.trunc(currentReminderCount)) : 0;
|
|
15684
|
-
let elapsed = 0;
|
|
15685
|
-
for (let i = 0; i <= safeCount && i < MAX_REMINDERS; i++) {
|
|
15686
|
-
elapsed += REMINDER_SCHEDULE_MS[i];
|
|
15687
|
-
}
|
|
15688
|
-
return receivedAtMs + elapsed;
|
|
15689
|
-
}
|
|
15690
|
-
function reminderText(reminderIndex, cancelCommandAvailable) {
|
|
15691
|
-
switch (reminderIndex) {
|
|
15692
|
-
case 0:
|
|
15693
|
-
return "Heads-up \u2014 I'm still on it. This one's taking more than the usual minute.";
|
|
15694
|
-
case 1:
|
|
15695
|
-
return "Still working. Going deeper than expected; back when I have something useful.";
|
|
15696
|
-
case 2:
|
|
15697
|
-
default:
|
|
15698
|
-
return cancelCommandAvailable ? "I'm 30+ min in on this. Type `/cancel` to abort, or ping me if it's urgent and I'll re-scope." : "I'm 30+ min in on this. If the answer's urgent, ping me and I'll pause to triage. Otherwise I'll keep going.";
|
|
15699
|
-
}
|
|
15700
|
-
}
|
|
15701
|
-
function agentTurnEndedSinceInbound(lastStopAtPath, receivedAtMs, deps = { statSync }) {
|
|
15702
|
-
if (!lastStopAtPath) return false;
|
|
15703
|
-
try {
|
|
15704
|
-
const stat = deps.statSync(lastStopAtPath);
|
|
15705
|
-
return stat.mtimeMs > receivedAtMs;
|
|
15706
|
-
} catch {
|
|
15707
|
-
return false;
|
|
15708
|
-
}
|
|
15709
|
-
}
|
|
15710
|
-
|
|
15711
15672
|
// src/telegram-channel.ts
|
|
15712
15673
|
function redactId(id) {
|
|
15713
15674
|
return createHash("sha256").update(String(id)).digest("hex").slice(0, 8);
|
|
@@ -15842,8 +15803,6 @@ function telegramApiCall(method, body, timeoutMs) {
|
|
|
15842
15803
|
});
|
|
15843
15804
|
}
|
|
15844
15805
|
var ACK_EMOJI = "\u{1F440}";
|
|
15845
|
-
var CANCEL_COMMAND_AVAILABLE = false;
|
|
15846
|
-
var REMINDER_REACTION_EMOJI = "\u23F3";
|
|
15847
15806
|
async function setMessageReaction(chatId, messageId, emoji2) {
|
|
15848
15807
|
try {
|
|
15849
15808
|
const resp = await telegramApiCall(
|
|
@@ -16024,11 +15983,9 @@ async function classifyRestartCommand(text) {
|
|
|
16024
15983
|
if (!ours) return "verification_failed";
|
|
16025
15984
|
return target === ours ? "act" : "ignore";
|
|
16026
15985
|
}
|
|
16027
|
-
var pendingMessages = /* @__PURE__ */ new Map();
|
|
16028
15986
|
var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join2(homedir2(), ".augmented", AGENT_CODE_NAME) : null;
|
|
16029
15987
|
var PENDING_INBOUND_DIR = AGENT_DIR ? join2(AGENT_DIR, "telegram-pending-inbound") : null;
|
|
16030
15988
|
var RECOVERY_OUTBOX_DIR = AGENT_DIR ? join2(AGENT_DIR, "telegram-recovery-outbox") : null;
|
|
16031
|
-
var LAST_STOP_AT_PATH = AGENT_DIR ? join2(AGENT_DIR, "last-stop-at") : null;
|
|
16032
15989
|
function safeMarkerName(chatId, messageId) {
|
|
16033
15990
|
const safe = (s) => s.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
16034
15991
|
return `${safe(chatId)}__${safe(messageId)}.json`;
|
|
@@ -16064,49 +16021,6 @@ function clearPendingInboundMarker(chatId, messageId) {
|
|
|
16064
16021
|
} catch {
|
|
16065
16022
|
}
|
|
16066
16023
|
}
|
|
16067
|
-
function updatePendingInboundMarker(marker) {
|
|
16068
|
-
const path = pendingInboundPath(marker.chat_id, marker.message_id);
|
|
16069
|
-
if (!path) return false;
|
|
16070
|
-
let fd;
|
|
16071
|
-
try {
|
|
16072
|
-
fd = openSync(path, "r+");
|
|
16073
|
-
} catch (err) {
|
|
16074
|
-
const code = err.code;
|
|
16075
|
-
if (code === "ENOENT") return false;
|
|
16076
|
-
process.stderr.write(
|
|
16077
|
-
`telegram-channel(${AGENT_CODE_NAME}): pending-inbound marker open-for-update failed: ${err.message}
|
|
16078
|
-
`
|
|
16079
|
-
);
|
|
16080
|
-
return false;
|
|
16081
|
-
}
|
|
16082
|
-
try {
|
|
16083
|
-
const payload = Buffer.from(JSON.stringify(marker));
|
|
16084
|
-
ftruncateSync(fd, 0);
|
|
16085
|
-
writeSync(fd, payload, 0, payload.length, 0);
|
|
16086
|
-
fsyncSync(fd);
|
|
16087
|
-
return true;
|
|
16088
|
-
} catch (err) {
|
|
16089
|
-
process.stderr.write(
|
|
16090
|
-
`telegram-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
|
|
16091
|
-
`
|
|
16092
|
-
);
|
|
16093
|
-
return false;
|
|
16094
|
-
} finally {
|
|
16095
|
-
try {
|
|
16096
|
-
closeSync(fd);
|
|
16097
|
-
} catch {
|
|
16098
|
-
}
|
|
16099
|
-
}
|
|
16100
|
-
}
|
|
16101
|
-
function readPendingInboundMarker(chatId, messageId) {
|
|
16102
|
-
const path = pendingInboundPath(chatId, messageId);
|
|
16103
|
-
if (!path || !existsSync(path)) return null;
|
|
16104
|
-
try {
|
|
16105
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
16106
|
-
} catch {
|
|
16107
|
-
return null;
|
|
16108
|
-
}
|
|
16109
|
-
}
|
|
16110
16024
|
var MAX_RECOVERY_ATTEMPTS = 3;
|
|
16111
16025
|
function nextRetryName(filename) {
|
|
16112
16026
|
const match = filename.match(/^(.*?)(?:\.retry-(\d+))?\.json$/);
|
|
@@ -16228,7 +16142,7 @@ function scanRecoveryRetries() {
|
|
|
16228
16142
|
if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
|
|
16229
16143
|
let mtimeMs;
|
|
16230
16144
|
try {
|
|
16231
|
-
mtimeMs =
|
|
16145
|
+
mtimeMs = statSync(join2(RECOVERY_OUTBOX_DIR, f)).mtimeMs;
|
|
16232
16146
|
} catch {
|
|
16233
16147
|
continue;
|
|
16234
16148
|
}
|
|
@@ -16273,86 +16187,11 @@ function startRecoveryOutboxWatcher() {
|
|
|
16273
16187
|
retryTimer.unref?.();
|
|
16274
16188
|
}
|
|
16275
16189
|
startRecoveryOutboxWatcher();
|
|
16276
|
-
|
|
16277
|
-
const marker = readPendingInboundMarker(chatId, messageId);
|
|
16278
|
-
if (!marker) return;
|
|
16279
|
-
const receivedAtMs = Date.parse(marker.received_at);
|
|
16280
|
-
if (Number.isFinite(receivedAtMs) && agentTurnEndedSinceInbound(LAST_STOP_AT_PATH, receivedAtMs)) {
|
|
16281
|
-
process.stderr.write(
|
|
16282
|
-
`telegram-channel(${AGENT_CODE_NAME}): suppressing reminder for ${redactId(messageId)} in chat ${redactId(chatId)} \u2014 turn ended after inbound at ${marker.received_at}; clearing marker
|
|
16283
|
-
`
|
|
16284
|
-
);
|
|
16285
|
-
const key2 = `${chatId}:${messageId}`;
|
|
16286
|
-
const existing = pendingMessages.get(key2);
|
|
16287
|
-
if (existing) {
|
|
16288
|
-
clearTimeout(existing.timer);
|
|
16289
|
-
pendingMessages.delete(key2);
|
|
16290
|
-
}
|
|
16291
|
-
clearPendingInboundMarker(chatId, messageId);
|
|
16292
|
-
return;
|
|
16293
|
-
}
|
|
16294
|
-
const reminderIndex = marker.reminder_count ?? 0;
|
|
16295
|
-
if (reminderIndex >= MAX_REMINDERS) return;
|
|
16296
|
-
const chatType = marker.chat_type ?? "private";
|
|
16297
|
-
void telegramApiCall(
|
|
16298
|
-
"sendMessage",
|
|
16299
|
-
{
|
|
16300
|
-
chat_id: chatId,
|
|
16301
|
-
text: reminderText(reminderIndex, CANCEL_COMMAND_AVAILABLE),
|
|
16302
|
-
reply_to_message_id: Number(messageId),
|
|
16303
|
-
allow_sending_without_reply: true
|
|
16304
|
-
},
|
|
16305
|
-
1e4
|
|
16306
|
-
).then((resp) => {
|
|
16307
|
-
if (!resp.ok) {
|
|
16308
|
-
process.stderr.write(
|
|
16309
|
-
`telegram-channel(${AGENT_CODE_NAME}): reminder sendMessage failed for chat ${redactId(chatId)} message ${redactId(messageId)}: ${resp.description ?? "unknown"}
|
|
16310
|
-
`
|
|
16311
|
-
);
|
|
16312
|
-
}
|
|
16313
|
-
}).catch((err) => {
|
|
16314
|
-
process.stderr.write(
|
|
16315
|
-
`telegram-channel(${AGENT_CODE_NAME}): reminder sendMessage error for chat ${redactId(chatId)} message ${redactId(messageId)}: ${err.message}
|
|
16316
|
-
`
|
|
16317
|
-
);
|
|
16318
|
-
});
|
|
16319
|
-
if (reminderIndex === 1) {
|
|
16320
|
-
void setMessageReaction(chatId, messageId, REMINDER_REACTION_EMOJI);
|
|
16321
|
-
}
|
|
16322
|
-
const nextCount = reminderIndex + 1;
|
|
16323
|
-
const persisted = updatePendingInboundMarker({ ...marker, reminder_count: nextCount, chat_type: chatType });
|
|
16324
|
-
if (!persisted) {
|
|
16325
|
-
process.stderr.write(
|
|
16326
|
-
`telegram-channel(${AGENT_CODE_NAME}): reminder ${nextCount}/${MAX_REMINDERS} posted but marker cleared mid-fire (agent replied) \u2014 not arming next timer
|
|
16327
|
-
`
|
|
16328
|
-
);
|
|
16329
|
-
return;
|
|
16330
|
-
}
|
|
16331
|
-
process.stderr.write(
|
|
16332
|
-
`telegram-channel(${AGENT_CODE_NAME}): reminder ${nextCount}/${MAX_REMINDERS} posted for message ${redactId(messageId)} in chat ${redactId(chatId)} (marker left pending)
|
|
16333
|
-
`
|
|
16334
|
-
);
|
|
16335
|
-
if (nextCount < MAX_REMINDERS) {
|
|
16336
|
-
armTelegramPendingTimer(chatId, messageId, chatType, REMINDER_SCHEDULE_MS[nextCount]);
|
|
16337
|
-
}
|
|
16338
|
-
}
|
|
16339
|
-
function armTelegramPendingTimer(chatId, messageId, chatType, durationMs) {
|
|
16340
|
-
const key2 = `${chatId}:${messageId}`;
|
|
16341
|
-
const existing = pendingMessages.get(key2);
|
|
16342
|
-
if (existing) clearTimeout(existing.timer);
|
|
16343
|
-
const timer = setTimeout(() => {
|
|
16344
|
-
pendingMessages.delete(key2);
|
|
16345
|
-
fireTelegramResponseTimeout(chatId, messageId);
|
|
16346
|
-
}, Math.max(0, durationMs));
|
|
16347
|
-
timer.unref?.();
|
|
16348
|
-
pendingMessages.set(key2, { timer, chatType });
|
|
16349
|
-
}
|
|
16190
|
+
var STALE_MARKER_MS = 24 * 60 * 60 * 1e3;
|
|
16350
16191
|
function trackPendingMessage(chatId, messageId, chatType) {
|
|
16351
16192
|
writePendingInboundMarker(chatId, messageId, chatType);
|
|
16352
|
-
armTelegramPendingTimer(chatId, messageId, chatType, RESPONSE_TIMEOUT_MS);
|
|
16353
16193
|
}
|
|
16354
|
-
|
|
16355
|
-
function rearmPendingTimersFromDisk() {
|
|
16194
|
+
function sweepTelegramStaleMarkersOnBoot() {
|
|
16356
16195
|
if (!PENDING_INBOUND_DIR) return;
|
|
16357
16196
|
if (!existsSync(PENDING_INBOUND_DIR)) return;
|
|
16358
16197
|
let filenames;
|
|
@@ -16360,16 +16199,13 @@ function rearmPendingTimersFromDisk() {
|
|
|
16360
16199
|
filenames = readdirSync(PENDING_INBOUND_DIR);
|
|
16361
16200
|
} catch (err) {
|
|
16362
16201
|
process.stderr.write(
|
|
16363
|
-
`telegram-channel(${AGENT_CODE_NAME}):
|
|
16202
|
+
`telegram-channel(${AGENT_CODE_NAME}): stale-marker readdir failed: ${err.message}
|
|
16364
16203
|
`
|
|
16365
16204
|
);
|
|
16366
16205
|
return;
|
|
16367
16206
|
}
|
|
16368
16207
|
const now = Date.now();
|
|
16369
|
-
let armed = 0;
|
|
16370
|
-
let firedNow = 0;
|
|
16371
16208
|
let cleared = 0;
|
|
16372
|
-
let exhausted = 0;
|
|
16373
16209
|
for (const filename of filenames) {
|
|
16374
16210
|
if (!filename.endsWith(".json")) continue;
|
|
16375
16211
|
if (filename.endsWith(".tmp")) continue;
|
|
@@ -16379,25 +16215,18 @@ function rearmPendingTimersFromDisk() {
|
|
|
16379
16215
|
marker = JSON.parse(readFileSync(fullPath, "utf-8"));
|
|
16380
16216
|
} catch (err) {
|
|
16381
16217
|
process.stderr.write(
|
|
16382
|
-
`telegram-channel(${AGENT_CODE_NAME}):
|
|
16218
|
+
`telegram-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactId(filename)}: ${err.message}
|
|
16383
16219
|
`
|
|
16384
16220
|
);
|
|
16385
16221
|
try {
|
|
16386
16222
|
unlinkSync2(fullPath);
|
|
16387
16223
|
} catch {
|
|
16388
16224
|
}
|
|
16225
|
+
cleared++;
|
|
16389
16226
|
continue;
|
|
16390
16227
|
}
|
|
16391
|
-
const { chat_id, message_id,
|
|
16228
|
+
const { chat_id, message_id, received_at } = marker;
|
|
16392
16229
|
if (!chat_id || !message_id || !received_at) {
|
|
16393
|
-
try {
|
|
16394
|
-
unlinkSync2(fullPath);
|
|
16395
|
-
} catch {
|
|
16396
|
-
}
|
|
16397
|
-
continue;
|
|
16398
|
-
}
|
|
16399
|
-
const receivedAtMs = Date.parse(received_at);
|
|
16400
|
-
if (!Number.isFinite(receivedAtMs)) {
|
|
16401
16230
|
try {
|
|
16402
16231
|
unlinkSync2(fullPath);
|
|
16403
16232
|
} catch {
|
|
@@ -16405,74 +16234,45 @@ function rearmPendingTimersFromDisk() {
|
|
|
16405
16234
|
cleared++;
|
|
16406
16235
|
continue;
|
|
16407
16236
|
}
|
|
16408
|
-
|
|
16409
|
-
|
|
16410
|
-
`telegram-channel(${AGENT_CODE_NAME}): rearm skipping stale marker chat=${redactId(chat_id)} message=${redactId(message_id)}
|
|
16411
|
-
`
|
|
16412
|
-
);
|
|
16237
|
+
const receivedAtMs = Date.parse(received_at);
|
|
16238
|
+
if (!Number.isFinite(receivedAtMs) || receivedAtMs > now || now - receivedAtMs > STALE_MARKER_MS) {
|
|
16413
16239
|
try {
|
|
16414
16240
|
unlinkSync2(fullPath);
|
|
16415
16241
|
} catch {
|
|
16416
16242
|
}
|
|
16417
16243
|
cleared++;
|
|
16418
|
-
continue;
|
|
16419
|
-
}
|
|
16420
|
-
const reminderCount = marker.reminder_count ?? 0;
|
|
16421
|
-
if (reminderCount >= MAX_REMINDERS) {
|
|
16422
|
-
exhausted++;
|
|
16423
|
-
continue;
|
|
16424
|
-
}
|
|
16425
|
-
const nextFireAt = nextReminderFireAtMs(receivedAtMs, reminderCount);
|
|
16426
|
-
const remainingMs = nextFireAt - now;
|
|
16427
|
-
if (remainingMs <= 0) {
|
|
16428
|
-
pendingMessages.delete(`${chat_id}:${message_id}`);
|
|
16429
|
-
fireTelegramResponseTimeout(chat_id, message_id);
|
|
16430
|
-
firedNow++;
|
|
16431
|
-
} else {
|
|
16432
|
-
armTelegramPendingTimer(chat_id, message_id, chat_type ?? "private", remainingMs);
|
|
16433
|
-
armed++;
|
|
16434
16244
|
}
|
|
16435
16245
|
}
|
|
16436
|
-
if (
|
|
16246
|
+
if (cleared > 0) {
|
|
16437
16247
|
process.stderr.write(
|
|
16438
|
-
`telegram-channel(${AGENT_CODE_NAME}):
|
|
16248
|
+
`telegram-channel(${AGENT_CODE_NAME}): stale-marker sweep cleared=${cleared}
|
|
16439
16249
|
`
|
|
16440
16250
|
);
|
|
16441
16251
|
}
|
|
16442
16252
|
}
|
|
16443
|
-
|
|
16253
|
+
sweepTelegramStaleMarkersOnBoot();
|
|
16444
16254
|
function clearPendingMessage(chatId, messageId) {
|
|
16445
16255
|
if (messageId) {
|
|
16446
|
-
|
|
16447
|
-
const entry = pendingMessages.get(key2);
|
|
16448
|
-
if (entry) {
|
|
16449
|
-
clearTimeout(entry.timer);
|
|
16450
|
-
pendingMessages.delete(key2);
|
|
16451
|
-
clearPendingInboundMarker(chatId, messageId);
|
|
16452
|
-
}
|
|
16256
|
+
clearPendingInboundMarker(chatId, messageId);
|
|
16453
16257
|
return;
|
|
16454
16258
|
}
|
|
16455
|
-
|
|
16456
|
-
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
|
|
16462
|
-
const msgId = key2.slice(prefix.length);
|
|
16463
|
-
clearPendingInboundMarker(chatId, msgId);
|
|
16464
|
-
clearedPrivate = true;
|
|
16465
|
-
}
|
|
16466
|
-
if (clearedPrivate) return;
|
|
16467
|
-
for (const [key2, entry] of pendingMessages) {
|
|
16468
|
-
if (!key2.startsWith(prefix)) continue;
|
|
16469
|
-
if (entry.chatType === "private") continue;
|
|
16470
|
-
clearTimeout(entry.timer);
|
|
16471
|
-
pendingMessages.delete(key2);
|
|
16472
|
-
const msgId = key2.slice(prefix.length);
|
|
16473
|
-
clearPendingInboundMarker(chatId, msgId);
|
|
16259
|
+
if (!PENDING_INBOUND_DIR || !existsSync(PENDING_INBOUND_DIR)) return;
|
|
16260
|
+
const safeChatId = chatId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
16261
|
+
const prefix = `${safeChatId}__`;
|
|
16262
|
+
let filenames;
|
|
16263
|
+
try {
|
|
16264
|
+
filenames = readdirSync(PENDING_INBOUND_DIR);
|
|
16265
|
+
} catch {
|
|
16474
16266
|
return;
|
|
16475
16267
|
}
|
|
16268
|
+
for (const filename of filenames) {
|
|
16269
|
+
if (!filename.startsWith(prefix)) continue;
|
|
16270
|
+
if (!filename.endsWith(".json")) continue;
|
|
16271
|
+
try {
|
|
16272
|
+
unlinkSync2(join2(PENDING_INBOUND_DIR, filename));
|
|
16273
|
+
} catch {
|
|
16274
|
+
}
|
|
16275
|
+
}
|
|
16476
16276
|
}
|
|
16477
16277
|
function noteThreadActivity(chatId, messageId) {
|
|
16478
16278
|
if (!chatId) return;
|
|
@@ -17415,8 +17215,6 @@ function sleep2(ms) {
|
|
|
17415
17215
|
function shutdown(reason) {
|
|
17416
17216
|
if (isShuttingDown) return;
|
|
17417
17217
|
isShuttingDown = true;
|
|
17418
|
-
for (const { timer } of pendingMessages.values()) clearTimeout(timer);
|
|
17419
|
-
pendingMessages.clear();
|
|
17420
17218
|
process.stderr.write(
|
|
17421
17219
|
`telegram-channel(${AGENT_CODE_NAME}): ${reason} \u2014 exiting
|
|
17422
17220
|
`
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// src/lib/pane-mcp-banner-scraper.ts
|
|
2
|
+
var BANNER_RE = /(\d+)\s+MCP\s+server(?:s)?\s+failed\s*[·•]\s*\/mcp/gi;
|
|
3
|
+
function scrapeMcpFailedBannerCount(paneTail) {
|
|
4
|
+
if (!paneTail) return null;
|
|
5
|
+
let last = null;
|
|
6
|
+
let m;
|
|
7
|
+
BANNER_RE.lastIndex = 0;
|
|
8
|
+
while ((m = BANNER_RE.exec(paneTail)) !== null) {
|
|
9
|
+
const n = parseInt(m[1], 10);
|
|
10
|
+
if (Number.isFinite(n) && n >= 0) last = n;
|
|
11
|
+
}
|
|
12
|
+
return last;
|
|
13
|
+
}
|
|
14
|
+
function paneHasFailingMcps(paneTail) {
|
|
15
|
+
const n = scrapeMcpFailedBannerCount(paneTail);
|
|
16
|
+
return typeof n === "number" && n > 0;
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
paneHasFailingMcps,
|
|
20
|
+
scrapeMcpFailedBannerCount
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=pane-mcp-banner-scraper-JA437JIB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/pane-mcp-banner-scraper.ts"],"sourcesContent":["/**\n * ENG-5459 — scrape Claude Code's \"N MCP servers failed · /mcp\" status\n * banner from a pane.log tail.\n *\n * Why this exists: mcp-presence-reaper (ENG-5279/5292/5285) checks for\n * live MCP child *processes* of the claude PID. An MCP whose\n * `npx @composio/mcp start --url ...` process is alive but whose URL\n * 401s on every tool call passes the reaper's heuristic — process is\n * up, reaper thinks all is well, but the integration is functionally\n * dead. Observed 2026-05-24 with Pepper post-Composio-revocation: 4\n * MCP processes alive, 0 functional, reaper silent.\n *\n * Claude Code already detects this and renders the banner. The\n * manager scrapes the count from pane.log each poll, persists via\n * `/host/mcp-banner-observation`, and the webapp surfaces it alongside\n * the existing `needsReconnect` signal.\n *\n * Pure function — caller passes a tail of pane.log content and gets\n * back the most-recent observed count (or null if no banner present).\n * Tests drive synthetic strings rather than reading real pane.log.\n */\n\n/**\n * Matches the banner Claude Code renders at the bottom of its TUI:\n *\n * \"1 MCP server failed · /mcp\"\n * \"4 MCP servers failed · /mcp\"\n *\n * The \"·\" is U+00B7 MIDDLE DOT — copy carefully if regenerating.\n * Singular \"server\" vs plural \"servers\" both match (Claude renders the\n * singular form when count === 1).\n */\nconst BANNER_RE = /(\\d+)\\s+MCP\\s+server(?:s)?\\s+failed\\s*[·•]\\s*\\/mcp/gi;\n\n/**\n * Extract the LAST matched banner from a pane tail. Last-wins because\n * the banner re-renders on every screen frame — earlier matches are\n * stale; the most recent reflects the current state.\n *\n * Returns `null` when no banner is present. **Null is \"not detected\n * this tick\", not \"definitely zero\"** — the caller should treat null\n * as \"unknown / observation skipped\". For the agents.mcp_failed_banner_count\n * column the API writes 0 only on an explicit observation of 0, not on\n * a missing banner.\n *\n * Returns 0 when the banner is genuinely \"0 MCP servers failed\" —\n * Claude Code doesn't usually render this (it omits the banner when\n * healthy), but we treat 0 as a valid observation if seen, so a future\n * Claude Code change that always renders the banner is handled.\n */\nexport function scrapeMcpFailedBannerCount(paneTail: string): number | null {\n if (!paneTail) return null;\n let last: number | null = null;\n let m: RegExpExecArray | null;\n // Reset lastIndex so consecutive calls with the same regex don't skip.\n BANNER_RE.lastIndex = 0;\n while ((m = BANNER_RE.exec(paneTail)) !== null) {\n const n = parseInt(m[1]!, 10);\n if (Number.isFinite(n) && n >= 0) last = n;\n }\n return last;\n}\n\n/**\n * Convenience: returns true when the scraped tail shows ANY failing\n * MCPs. Useful for the manager's \"should I bother POSTing this tick?\"\n * gate when the previous count was already 0.\n */\nexport function paneHasFailingMcps(paneTail: string): boolean {\n const n = scrapeMcpFailedBannerCount(paneTail);\n return typeof n === 'number' && n > 0;\n}\n"],"mappings":";AAgCA,IAAM,YAAY;AAkBX,SAAS,2BAA2B,UAAiC;AAC1E,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,OAAsB;AAC1B,MAAI;AAEJ,YAAU,YAAY;AACtB,UAAQ,IAAI,UAAU,KAAK,QAAQ,OAAO,MAAM;AAC9C,UAAM,IAAI,SAAS,EAAE,CAAC,GAAI,EAAE;AAC5B,QAAI,OAAO,SAAS,CAAC,KAAK,KAAK,EAAG,QAAO;AAAA,EAC3C;AACA,SAAO;AACT;AAOO,SAAS,mBAAmB,UAA2B;AAC5D,QAAM,IAAI,2BAA2B,QAAQ;AAC7C,SAAO,OAAO,MAAM,YAAY,IAAI;AACtC;","names":[]}
|
|
@@ -22,8 +22,8 @@ import {
|
|
|
22
22
|
stopPersistentSession,
|
|
23
23
|
takeZombieDetection,
|
|
24
24
|
writePersistentClaudeWrapper
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import "./chunk-
|
|
25
|
+
} from "./chunk-ZKQGDH3T.js";
|
|
26
|
+
import "./chunk-HSIESZMZ.js";
|
|
27
27
|
export {
|
|
28
28
|
_internals,
|
|
29
29
|
collectDiagnostics,
|
|
@@ -49,4 +49,4 @@ export {
|
|
|
49
49
|
takeZombieDetection,
|
|
50
50
|
writePersistentClaudeWrapper
|
|
51
51
|
};
|
|
52
|
-
//# sourceMappingURL=persistent-session-
|
|
52
|
+
//# sourceMappingURL=persistent-session-L4YIJJML.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
paneLogPath
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-ZKQGDH3T.js";
|
|
4
|
+
import "./chunk-HSIESZMZ.js";
|
|
5
5
|
|
|
6
6
|
// src/lib/responsiveness-probe.ts
|
|
7
7
|
import { statSync } from "fs";
|
|
@@ -29,4 +29,4 @@ export {
|
|
|
29
29
|
collectResponsivenessProbes,
|
|
30
30
|
getResponsivenessIntervalMs
|
|
31
31
|
};
|
|
32
|
-
//# sourceMappingURL=responsiveness-probe-
|
|
32
|
+
//# sourceMappingURL=responsiveness-probe-YRLESO54.js.map
|