@integrity-labs/agt-cli 0.28.457 → 0.28.459
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-QFBCK4ZH.js → chunk-BWH5XTDU.js} +55 -7
- package/dist/chunk-BWH5XTDU.js.map +1 -0
- package/dist/{chunk-WMGMLOPB.js → chunk-PKZMFA2U.js} +60 -22
- package/dist/{chunk-WMGMLOPB.js.map → chunk-PKZMFA2U.js.map} +1 -1
- package/dist/{claude-pair-runtime-QNOUSTW3.js → claude-pair-runtime-YNOY2ATX.js} +2 -2
- package/dist/lib/manager-worker.js +24 -11
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +1134 -772
- package/dist/mcp/origami.js +27 -1
- package/dist/mcp/slack-channel.js +555 -139
- package/dist/mcp/telegram-channel.js +498 -94
- package/dist/{persistent-session-LEWM6BKO.js → persistent-session-KGRCIIS5.js} +2 -2
- package/dist/{responsiveness-probe-U6DPVIDD.js → responsiveness-probe-4FVGB6NY.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-QFBCK4ZH.js.map +0 -1
- /package/dist/{claude-pair-runtime-QNOUSTW3.js.map → claude-pair-runtime-YNOY2ATX.js.map} +0 -0
- /package/dist/{persistent-session-LEWM6BKO.js.map → persistent-session-KGRCIIS5.js.map} +0 -0
- /package/dist/{responsiveness-probe-U6DPVIDD.js.map → responsiveness-probe-4FVGB6NY.js.map} +0 -0
|
@@ -18906,7 +18906,7 @@ var require_filters = __commonJS({
|
|
|
18906
18906
|
return r.copySafeness(str, res);
|
|
18907
18907
|
}
|
|
18908
18908
|
_exports.indent = indent;
|
|
18909
|
-
function
|
|
18909
|
+
function join18(arr, del, attr) {
|
|
18910
18910
|
del = del || "";
|
|
18911
18911
|
if (attr) {
|
|
18912
18912
|
arr = lib.map(arr, function(v) {
|
|
@@ -18915,7 +18915,7 @@ var require_filters = __commonJS({
|
|
|
18915
18915
|
}
|
|
18916
18916
|
return arr.join(del);
|
|
18917
18917
|
}
|
|
18918
|
-
_exports.join =
|
|
18918
|
+
_exports.join = join18;
|
|
18919
18919
|
function last(arr) {
|
|
18920
18920
|
return arr[arr.length - 1];
|
|
18921
18921
|
}
|
|
@@ -22516,11 +22516,11 @@ async function waitForResolution(cfg, callbackId, opts) {
|
|
|
22516
22516
|
}
|
|
22517
22517
|
} catch {
|
|
22518
22518
|
}
|
|
22519
|
-
await
|
|
22519
|
+
await sleep3(interval);
|
|
22520
22520
|
}
|
|
22521
22521
|
return { kind: "timeout" };
|
|
22522
22522
|
}
|
|
22523
|
-
function
|
|
22523
|
+
function sleep3(ms) {
|
|
22524
22524
|
return new Promise((r) => setTimeout(r, ms));
|
|
22525
22525
|
}
|
|
22526
22526
|
function generateOptionToken() {
|
|
@@ -30132,18 +30132,18 @@ import {
|
|
|
30132
30132
|
ftruncateSync,
|
|
30133
30133
|
mkdirSync as mkdirSync9,
|
|
30134
30134
|
openSync,
|
|
30135
|
-
readFileSync as
|
|
30136
|
-
readdirSync as
|
|
30135
|
+
readFileSync as readFileSync17,
|
|
30136
|
+
readdirSync as readdirSync6,
|
|
30137
30137
|
realpathSync,
|
|
30138
30138
|
renameSync as renameSync7,
|
|
30139
|
-
statSync as
|
|
30139
|
+
statSync as statSync5,
|
|
30140
30140
|
unlinkSync as unlinkSync8,
|
|
30141
30141
|
watch,
|
|
30142
30142
|
writeFileSync as writeFileSync11,
|
|
30143
30143
|
writeSync
|
|
30144
30144
|
} from "fs";
|
|
30145
30145
|
import { homedir as homedir7 } from "os";
|
|
30146
|
-
import { basename, extname, join as
|
|
30146
|
+
import { basename, extname, join as join17, resolve as resolve2 } from "path";
|
|
30147
30147
|
|
|
30148
30148
|
// src/channel-attachments.ts
|
|
30149
30149
|
import { homedir } from "os";
|
|
@@ -34354,6 +34354,160 @@ function classifyTranscriptRateLimit(jsonl, startMs, endMs, now) {
|
|
|
34354
34354
|
return newest;
|
|
34355
34355
|
}
|
|
34356
34356
|
|
|
34357
|
+
// ../core/dist/claude-code-usage/turn-failure-classifier.js
|
|
34358
|
+
var UNKNOWN_TURN_FAILURE = Object.freeze({
|
|
34359
|
+
outcome: "unknown",
|
|
34360
|
+
atMs: null,
|
|
34361
|
+
failureClass: null,
|
|
34362
|
+
httpStatus: null,
|
|
34363
|
+
attempt: null,
|
|
34364
|
+
maxAttempts: null
|
|
34365
|
+
});
|
|
34366
|
+
var EXCLUDED_STATUSES = /* @__PURE__ */ new Set([429]);
|
|
34367
|
+
function classifyTransientStatus(status) {
|
|
34368
|
+
if (!Number.isFinite(status))
|
|
34369
|
+
return null;
|
|
34370
|
+
if (EXCLUDED_STATUSES.has(status))
|
|
34371
|
+
return null;
|
|
34372
|
+
if (status === 529)
|
|
34373
|
+
return "overloaded";
|
|
34374
|
+
if (status >= 500 && status <= 599)
|
|
34375
|
+
return "server_error";
|
|
34376
|
+
return null;
|
|
34377
|
+
}
|
|
34378
|
+
function numberOrNull(value) {
|
|
34379
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
34380
|
+
}
|
|
34381
|
+
function isErrorShaped(record2) {
|
|
34382
|
+
if (record2.isApiErrorMessage === true)
|
|
34383
|
+
return true;
|
|
34384
|
+
if (record2.type === "system" && record2.level === "error")
|
|
34385
|
+
return true;
|
|
34386
|
+
if (record2.type === "assistant" && typeof record2.error === "string" && record2.error)
|
|
34387
|
+
return true;
|
|
34388
|
+
return false;
|
|
34389
|
+
}
|
|
34390
|
+
function classifyRecord(record2, tsMs) {
|
|
34391
|
+
if (record2.isSidechain === true)
|
|
34392
|
+
return null;
|
|
34393
|
+
if (record2.type === "system" && record2.subtype === "api_error") {
|
|
34394
|
+
const error2 = record2.error;
|
|
34395
|
+
const status = typeof error2 === "object" && error2 !== null ? numberOrNull(error2.status) : null;
|
|
34396
|
+
if (status === null)
|
|
34397
|
+
return null;
|
|
34398
|
+
const failureClass = classifyTransientStatus(status);
|
|
34399
|
+
if (!failureClass)
|
|
34400
|
+
return null;
|
|
34401
|
+
return {
|
|
34402
|
+
outcome: "retrying",
|
|
34403
|
+
atMs: tsMs,
|
|
34404
|
+
failureClass,
|
|
34405
|
+
httpStatus: status,
|
|
34406
|
+
attempt: numberOrNull(record2.retryAttempt),
|
|
34407
|
+
maxAttempts: numberOrNull(record2.maxRetries)
|
|
34408
|
+
};
|
|
34409
|
+
}
|
|
34410
|
+
if (record2.type !== "assistant")
|
|
34411
|
+
return null;
|
|
34412
|
+
if (record2.isApiErrorMessage === true) {
|
|
34413
|
+
const status = numberOrNull(record2.apiErrorStatus);
|
|
34414
|
+
const failureClass = status === null ? null : classifyTransientStatus(status);
|
|
34415
|
+
if (!failureClass)
|
|
34416
|
+
return null;
|
|
34417
|
+
return {
|
|
34418
|
+
outcome: "failed",
|
|
34419
|
+
atMs: tsMs,
|
|
34420
|
+
failureClass,
|
|
34421
|
+
httpStatus: status,
|
|
34422
|
+
attempt: null,
|
|
34423
|
+
maxAttempts: null
|
|
34424
|
+
};
|
|
34425
|
+
}
|
|
34426
|
+
const message = record2.message;
|
|
34427
|
+
if (typeof message !== "object" || message === null)
|
|
34428
|
+
return null;
|
|
34429
|
+
const msg = message;
|
|
34430
|
+
if (msg.model === "<synthetic>")
|
|
34431
|
+
return null;
|
|
34432
|
+
const usage = msg.usage;
|
|
34433
|
+
if (typeof usage !== "object" || usage === null)
|
|
34434
|
+
return null;
|
|
34435
|
+
const u = usage;
|
|
34436
|
+
const spent = Number(u.input_tokens ?? 0) + Number(u.output_tokens ?? 0) + Number(u.cache_creation_input_tokens ?? 0) + Number(u.cache_read_input_tokens ?? 0);
|
|
34437
|
+
if (!Number.isFinite(spent) || spent <= 0)
|
|
34438
|
+
return null;
|
|
34439
|
+
return {
|
|
34440
|
+
outcome: "served",
|
|
34441
|
+
atMs: tsMs,
|
|
34442
|
+
failureClass: null,
|
|
34443
|
+
httpStatus: null,
|
|
34444
|
+
attempt: null,
|
|
34445
|
+
maxAttempts: null
|
|
34446
|
+
};
|
|
34447
|
+
}
|
|
34448
|
+
function pickNewerTurnFailure(current, next) {
|
|
34449
|
+
if (next.outcome === "unknown")
|
|
34450
|
+
return current;
|
|
34451
|
+
if (current.outcome === "unknown")
|
|
34452
|
+
return next;
|
|
34453
|
+
return (next.atMs ?? 0) >= (current.atMs ?? 0) ? next : current;
|
|
34454
|
+
}
|
|
34455
|
+
function isShapeRecognised(record2) {
|
|
34456
|
+
if (record2.type === "system" && record2.subtype === "api_error") {
|
|
34457
|
+
const error2 = record2.error;
|
|
34458
|
+
return typeof error2 === "object" && error2 !== null && numberOrNull(error2.status) !== null;
|
|
34459
|
+
}
|
|
34460
|
+
if (record2.type === "assistant" && record2.isApiErrorMessage === true) {
|
|
34461
|
+
return numberOrNull(record2.apiErrorStatus) !== null;
|
|
34462
|
+
}
|
|
34463
|
+
return false;
|
|
34464
|
+
}
|
|
34465
|
+
function analyzeTranscriptTurnFailure(jsonl, startMs, endMs, opts = {}) {
|
|
34466
|
+
const maxKeys = opts.maxKeys ?? 40;
|
|
34467
|
+
let newest = UNKNOWN_TURN_FAILURE;
|
|
34468
|
+
let coarse = 0;
|
|
34469
|
+
let fine = 0;
|
|
34470
|
+
const keys = /* @__PURE__ */ new Set();
|
|
34471
|
+
for (const line of jsonl.split("\n")) {
|
|
34472
|
+
const trimmed = line.trim();
|
|
34473
|
+
if (!trimmed)
|
|
34474
|
+
continue;
|
|
34475
|
+
let obj;
|
|
34476
|
+
try {
|
|
34477
|
+
obj = JSON.parse(trimmed);
|
|
34478
|
+
} catch {
|
|
34479
|
+
continue;
|
|
34480
|
+
}
|
|
34481
|
+
if (typeof obj !== "object" || obj === null)
|
|
34482
|
+
continue;
|
|
34483
|
+
const record2 = obj;
|
|
34484
|
+
const ts = record2.timestamp;
|
|
34485
|
+
if (typeof ts !== "string" || !ts)
|
|
34486
|
+
continue;
|
|
34487
|
+
const tsMs = new Date(ts).getTime();
|
|
34488
|
+
if (!Number.isFinite(tsMs) || tsMs < startMs || tsMs > endMs)
|
|
34489
|
+
continue;
|
|
34490
|
+
const classified = classifyRecord(record2, tsMs);
|
|
34491
|
+
if (classified)
|
|
34492
|
+
newest = pickNewerTurnFailure(newest, classified);
|
|
34493
|
+
if (!isErrorShaped(record2) || record2.isSidechain === true)
|
|
34494
|
+
continue;
|
|
34495
|
+
coarse++;
|
|
34496
|
+
if (isShapeRecognised(record2)) {
|
|
34497
|
+
fine++;
|
|
34498
|
+
continue;
|
|
34499
|
+
}
|
|
34500
|
+
if (keys.size < maxKeys) {
|
|
34501
|
+
for (const key2 of Object.keys(record2)) {
|
|
34502
|
+
if (keys.size >= maxKeys)
|
|
34503
|
+
break;
|
|
34504
|
+
keys.add(key2);
|
|
34505
|
+
}
|
|
34506
|
+
}
|
|
34507
|
+
}
|
|
34508
|
+
return { result: newest, coarse, fine, unrecognisedKeys: [...keys].sort() };
|
|
34509
|
+
}
|
|
34510
|
+
|
|
34357
34511
|
// ../core/dist/claude-code-usage/transcript-location.js
|
|
34358
34512
|
function encodeClaudeProjectPath(projectDir) {
|
|
34359
34513
|
return "-" + projectDir.replace(/^\//, "").replace(/[/.]/g, "-");
|
|
@@ -35210,7 +35364,7 @@ var FLAG_REGISTRY = [
|
|
|
35210
35364
|
},
|
|
35211
35365
|
{
|
|
35212
35366
|
key: "wedge-transient-notice",
|
|
35213
|
-
description:
|
|
35367
|
+
description: `Tell the person waiting when their turn dies on a transient LLM-API failure (529 overloaded / 5xx). TWO consumers now share this gate. (1) ENG-7360: a wedge-respawn preceded by such an error writes the ENG-6058 give-up signal tagged reason=transient_overload so the channel sweeps post a "please resend" notice. (2) ENG-8269: the channel MCPs watch the dispatched turn in Claude Code's own transcript and notify the conversation that was actually waiting \u2014 Slack, Telegram AND direct chat \u2014 plus a "still working on this" notice after ~3min on Slack/Telegram only (direct chat already shows a client-side one at 90s). NOTE: (2) fires on a MUCH larger population than (1) \u2014 any dispatched turn that dies, not only one that also wedged the session \u2014 and (1) has never actually been able to fire, because its pane.log detector cannot match the banner Claude Code renders today. So flipping this on is in practice enabling (2) for the first time. Boolean gate; ships dark \u2014 channel-visible copy soaks per host before going wide. Materialized into the channel-MCP spawn env: a Docker-isolated agent never mounts the host flags-cache, so a central flip reaches it only that way.`,
|
|
35214
35368
|
flagType: "boolean",
|
|
35215
35369
|
defaultValue: false,
|
|
35216
35370
|
envVar: "AGT_WEDGE_TRANSIENT_NOTICE_ENABLED"
|
|
@@ -35704,6 +35858,22 @@ var FLAG_REGISTRY = [
|
|
|
35704
35858
|
// registry-only (ADR-0022). NOT `public`: it is resolved server-side only, so it
|
|
35705
35859
|
// must never be serialized into the browser map.
|
|
35706
35860
|
defaultValue: false
|
|
35861
|
+
},
|
|
35862
|
+
{
|
|
35863
|
+
key: "ninjafy-brand",
|
|
35864
|
+
description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is USER-FACING BRAND TEXT ONLY: it must never gate a code identifier, package name, env var or CLI name, which stay `Augmented`/`agt` per the CLAUDE.md naming contract (the deep code rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here). Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot one organization while every other org still sees Augmented. Ships dark.',
|
|
35865
|
+
flagType: "boolean",
|
|
35866
|
+
// Declared safe value is `false`: the pre-rebrand brand. `false` is also the
|
|
35867
|
+
// fail-closed direction — if the flag DB is unreachable we must show the brand
|
|
35868
|
+
// that is currently live and contractually correct, never leak an unannounced
|
|
35869
|
+
// rebrand to every customer at once.
|
|
35870
|
+
defaultValue: false,
|
|
35871
|
+
// Read CLIENT-SIDE: sidebar.tsx is a "use client" component and resolves this
|
|
35872
|
+
// via usePublicBooleanFlag, so the key must be in the browser-exposed public
|
|
35873
|
+
// map. Unlike onboarding-msteams-channel above there is no wrong-org hazard —
|
|
35874
|
+
// the sidebar renders inside the active-org cookie's scope, which is exactly
|
|
35875
|
+
// the org whose brand should be shown.
|
|
35876
|
+
public: true
|
|
35707
35877
|
}
|
|
35708
35878
|
];
|
|
35709
35879
|
var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
|
|
@@ -37480,6 +37650,149 @@ async function watchForRateLimitRefusal(opts) {
|
|
|
37480
37650
|
}
|
|
37481
37651
|
}
|
|
37482
37652
|
|
|
37653
|
+
// src/turn-failure-watch.ts
|
|
37654
|
+
import { readFileSync as readFileSync12, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
37655
|
+
import { join as join10 } from "path";
|
|
37656
|
+
function turnFailureNoticeEnabled(env2) {
|
|
37657
|
+
return resolveHostBooleanFlag({
|
|
37658
|
+
key: "wedge-transient-notice",
|
|
37659
|
+
envVar: "AGT_WEDGE_TRANSIENT_NOTICE_ENABLED",
|
|
37660
|
+
defaultValue: false,
|
|
37661
|
+
...env2 ? { env: env2 } : {}
|
|
37662
|
+
});
|
|
37663
|
+
}
|
|
37664
|
+
var DEFAULT_FAILURE_WATCH_MS = 5 * 6e4;
|
|
37665
|
+
var FAST_POLL_MS = 500;
|
|
37666
|
+
var SLOW_POLL_MS = 3e3;
|
|
37667
|
+
var FAST_PHASE_MS = 1e4;
|
|
37668
|
+
var RETRYING_NOTICE_AFTER_MS = 3 * 6e4;
|
|
37669
|
+
var sleep2 = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
37670
|
+
function classifyTurnFailureSince(opts) {
|
|
37671
|
+
const dir = opts.transcriptDir ?? agentTranscriptDir({ cwd: opts.cwd, home: opts.home });
|
|
37672
|
+
let entries;
|
|
37673
|
+
try {
|
|
37674
|
+
entries = readdirSync2(dir);
|
|
37675
|
+
} catch {
|
|
37676
|
+
return { result: UNKNOWN_TURN_FAILURE, coarse: 0, fine: 0, unrecognisedKeys: [] };
|
|
37677
|
+
}
|
|
37678
|
+
let newest = UNKNOWN_TURN_FAILURE;
|
|
37679
|
+
let coarse = 0;
|
|
37680
|
+
let fine = 0;
|
|
37681
|
+
const unrecognised = /* @__PURE__ */ new Set();
|
|
37682
|
+
for (const name of entries) {
|
|
37683
|
+
if (!name.endsWith(".jsonl")) continue;
|
|
37684
|
+
const path = join10(dir, name);
|
|
37685
|
+
let fingerprint;
|
|
37686
|
+
try {
|
|
37687
|
+
const st = statSync2(path);
|
|
37688
|
+
if (!st.isFile() || st.mtimeMs < opts.sinceMs) continue;
|
|
37689
|
+
fingerprint = `${st.mtimeMs}:${st.size}`;
|
|
37690
|
+
} catch {
|
|
37691
|
+
continue;
|
|
37692
|
+
}
|
|
37693
|
+
const cached2 = opts.cache?.get(path);
|
|
37694
|
+
let scan;
|
|
37695
|
+
if (cached2 && cached2.fingerprint === fingerprint) {
|
|
37696
|
+
scan = cached2.scan;
|
|
37697
|
+
} else {
|
|
37698
|
+
let content;
|
|
37699
|
+
try {
|
|
37700
|
+
content = readFileSync12(path, "utf-8");
|
|
37701
|
+
} catch {
|
|
37702
|
+
continue;
|
|
37703
|
+
}
|
|
37704
|
+
const analysis = analyzeTranscriptTurnFailure(content, opts.sinceMs, opts.nowMs);
|
|
37705
|
+
scan = {
|
|
37706
|
+
result: analysis.result,
|
|
37707
|
+
coarse: analysis.coarse,
|
|
37708
|
+
fine: analysis.fine,
|
|
37709
|
+
unrecognisedKeys: analysis.unrecognisedKeys
|
|
37710
|
+
};
|
|
37711
|
+
opts.cache?.set(path, { fingerprint, scan });
|
|
37712
|
+
}
|
|
37713
|
+
newest = pickNewerTurnFailure(newest, scan.result);
|
|
37714
|
+
coarse += scan.coarse;
|
|
37715
|
+
fine += scan.fine;
|
|
37716
|
+
for (const key2 of scan.unrecognisedKeys) unrecognised.add(key2);
|
|
37717
|
+
}
|
|
37718
|
+
return { result: newest, coarse, fine, unrecognisedKeys: [...unrecognised].sort() };
|
|
37719
|
+
}
|
|
37720
|
+
function emitDriftTelemetryIfBlind(args) {
|
|
37721
|
+
if (args.coarse <= 0 || args.fine > 0) return;
|
|
37722
|
+
try {
|
|
37723
|
+
process.stderr.write(
|
|
37724
|
+
`agt.transcript.api_error.unclassified ${JSON.stringify({
|
|
37725
|
+
channel: args.channel,
|
|
37726
|
+
agent_code: process.env.AGT_AGENT_CODE_NAME ?? "unknown",
|
|
37727
|
+
coarse: args.coarse,
|
|
37728
|
+
keys: args.unrecognisedKeys.slice(0, 20)
|
|
37729
|
+
})}
|
|
37730
|
+
`
|
|
37731
|
+
);
|
|
37732
|
+
} catch {
|
|
37733
|
+
}
|
|
37734
|
+
}
|
|
37735
|
+
async function watchForTurnFailure(opts) {
|
|
37736
|
+
const now = opts.now ?? (() => Date.now());
|
|
37737
|
+
const wait = opts.wait ?? sleep2;
|
|
37738
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_FAILURE_WATCH_MS;
|
|
37739
|
+
const fastPollMs = opts.fastPollMs ?? FAST_POLL_MS;
|
|
37740
|
+
const slowPollMs = opts.slowPollMs ?? SLOW_POLL_MS;
|
|
37741
|
+
const fastPhaseMs = opts.fastPhaseMs ?? FAST_PHASE_MS;
|
|
37742
|
+
const retryingAfterMs = opts.retryingNoticeAfterMs ?? RETRYING_NOTICE_AFTER_MS;
|
|
37743
|
+
const startedAt = now();
|
|
37744
|
+
const deadline = startedAt + timeoutMs;
|
|
37745
|
+
let longRetryFired = false;
|
|
37746
|
+
let driftEmitted = false;
|
|
37747
|
+
const cache = /* @__PURE__ */ new Map();
|
|
37748
|
+
for (; ; ) {
|
|
37749
|
+
let scan;
|
|
37750
|
+
try {
|
|
37751
|
+
scan = classifyTurnFailureSince({
|
|
37752
|
+
sinceMs: opts.sinceMs,
|
|
37753
|
+
// No upper bound, deliberately. Two reasons, and the second is a
|
|
37754
|
+
// correctness requirement of the cache above:
|
|
37755
|
+
// 1. For a post-dispatch watch the question is "has anything since the
|
|
37756
|
+
// dispatch killed this turn?" — a future-dated entry is still an
|
|
37757
|
+
// answer, and rejecting it on clock skew would drop the notice.
|
|
37758
|
+
// 2. A window that widens each poll makes a cached scan unsound: an
|
|
37759
|
+
// entry stamped a hair ahead of our clock would be parsed as
|
|
37760
|
+
// out-of-window, cached as "not seen", and — because a DEAD turn
|
|
37761
|
+
// produces no further appends to invalidate the entry — never looked
|
|
37762
|
+
// at again. That is exactly the silence this feature exists to end.
|
|
37763
|
+
nowMs: Number.POSITIVE_INFINITY,
|
|
37764
|
+
transcriptDir: opts.transcriptDir,
|
|
37765
|
+
cwd: opts.cwd,
|
|
37766
|
+
home: opts.home,
|
|
37767
|
+
cache
|
|
37768
|
+
});
|
|
37769
|
+
} catch {
|
|
37770
|
+
return null;
|
|
37771
|
+
}
|
|
37772
|
+
if (!driftEmitted && scan.coarse > 0 && scan.fine === 0) {
|
|
37773
|
+
driftEmitted = true;
|
|
37774
|
+
emitDriftTelemetryIfBlind({
|
|
37775
|
+
channel: opts.channel ?? "unknown",
|
|
37776
|
+
coarse: scan.coarse,
|
|
37777
|
+
fine: scan.fine,
|
|
37778
|
+
unrecognisedKeys: scan.unrecognisedKeys
|
|
37779
|
+
});
|
|
37780
|
+
}
|
|
37781
|
+
const { result } = scan;
|
|
37782
|
+
if (result.outcome === "failed") return result;
|
|
37783
|
+
if (result.outcome === "served") return null;
|
|
37784
|
+
if (result.outcome === "retrying" && !longRetryFired && opts.onLongRetry && now() - startedAt >= retryingAfterMs) {
|
|
37785
|
+
longRetryFired = true;
|
|
37786
|
+
try {
|
|
37787
|
+
await opts.onLongRetry(result);
|
|
37788
|
+
} catch {
|
|
37789
|
+
}
|
|
37790
|
+
}
|
|
37791
|
+
if (now() >= deadline) return null;
|
|
37792
|
+
await wait(now() - startedAt < fastPhaseMs ? fastPollMs : slowPollMs);
|
|
37793
|
+
}
|
|
37794
|
+
}
|
|
37795
|
+
|
|
37483
37796
|
// src/usage-limit-reactive-decision.ts
|
|
37484
37797
|
import { createHash } from "crypto";
|
|
37485
37798
|
function shouldReadPredictiveMarker(mode) {
|
|
@@ -37506,7 +37819,7 @@ function describeUnparsedRefusal(text) {
|
|
|
37506
37819
|
import { execFile as execFile2 } from "child_process";
|
|
37507
37820
|
import { existsSync as existsSync5, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
37508
37821
|
import { homedir as homedir6 } from "os";
|
|
37509
|
-
import { join as
|
|
37822
|
+
import { join as join11 } from "path";
|
|
37510
37823
|
var DEFAULT_CLAUDE_EVAL_MODEL = "claude-haiku-4-5-20251001";
|
|
37511
37824
|
var DEFAULT_ANTHROPIC_MESSAGES_URL = "https://api.anthropic.com/v1/messages";
|
|
37512
37825
|
var ANTHROPIC_API_VERSION = "2023-06-01";
|
|
@@ -37605,12 +37918,12 @@ async function runAnthropicMessages(prompt, opts) {
|
|
|
37605
37918
|
var emptyMcpConfigPath = null;
|
|
37606
37919
|
function ensureEmptyMcpConfig() {
|
|
37607
37920
|
if (emptyMcpConfigPath && existsSync5(emptyMcpConfigPath)) return emptyMcpConfigPath;
|
|
37608
|
-
const dir =
|
|
37921
|
+
const dir = join11(homedir6(), ".augmented");
|
|
37609
37922
|
try {
|
|
37610
37923
|
mkdirSync6(dir, { recursive: true });
|
|
37611
37924
|
} catch {
|
|
37612
37925
|
}
|
|
37613
|
-
const p2 =
|
|
37926
|
+
const p2 = join11(dir, ".reply-intent-empty-mcp.json");
|
|
37614
37927
|
writeFileSync7(p2, JSON.stringify({ mcpServers: {} }));
|
|
37615
37928
|
emptyMcpConfigPath = p2;
|
|
37616
37929
|
return p2;
|
|
@@ -37757,17 +38070,17 @@ function emitTransientApiErrorTelemetry(channel, match, original) {
|
|
|
37757
38070
|
}
|
|
37758
38071
|
|
|
37759
38072
|
// src/telegram-pending-inbound-cleanup.ts
|
|
37760
|
-
import { readdirSync as
|
|
37761
|
-
import { join as
|
|
38073
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync3 } from "fs";
|
|
38074
|
+
import { join as join12 } from "path";
|
|
37762
38075
|
function markerArrivalMs(fullPath) {
|
|
37763
38076
|
try {
|
|
37764
|
-
const received = JSON.parse(
|
|
38077
|
+
const received = JSON.parse(readFileSync13(fullPath, "utf-8")).received_at;
|
|
37765
38078
|
const parsed = received ? Date.parse(received) : Number.NaN;
|
|
37766
38079
|
if (Number.isFinite(parsed)) return parsed;
|
|
37767
38080
|
} catch {
|
|
37768
38081
|
}
|
|
37769
38082
|
try {
|
|
37770
|
-
return
|
|
38083
|
+
return statSync3(fullPath).mtimeMs;
|
|
37771
38084
|
} catch {
|
|
37772
38085
|
return Number.POSITIVE_INFINITY;
|
|
37773
38086
|
}
|
|
@@ -37783,7 +38096,7 @@ function applyToChatMarkers(pendingDir, chatId, op, cutoffMs) {
|
|
|
37783
38096
|
const bounded = Number.isFinite(cutoffMs);
|
|
37784
38097
|
let filenames;
|
|
37785
38098
|
try {
|
|
37786
|
-
filenames =
|
|
38099
|
+
filenames = readdirSync3(pendingDir);
|
|
37787
38100
|
} catch {
|
|
37788
38101
|
return 0;
|
|
37789
38102
|
}
|
|
@@ -37791,7 +38104,7 @@ function applyToChatMarkers(pendingDir, chatId, op, cutoffMs) {
|
|
|
37791
38104
|
for (const filename of filenames) {
|
|
37792
38105
|
if (!filename.startsWith(prefix)) continue;
|
|
37793
38106
|
if (!filename.endsWith(".json")) continue;
|
|
37794
|
-
const fullPath =
|
|
38107
|
+
const fullPath = join12(pendingDir, filename);
|
|
37795
38108
|
if (bounded && markerArrivalMs(fullPath) > cutoffMs) continue;
|
|
37796
38109
|
op(fullPath);
|
|
37797
38110
|
applied++;
|
|
@@ -37801,12 +38114,12 @@ function applyToChatMarkers(pendingDir, chatId, op, cutoffMs) {
|
|
|
37801
38114
|
|
|
37802
38115
|
// src/recovery-ledger.ts
|
|
37803
38116
|
import { existsSync as existsSync6, unlinkSync as unlinkSync6 } from "fs";
|
|
37804
|
-
import { join as
|
|
38117
|
+
import { join as join13 } from "path";
|
|
37805
38118
|
function recoveryLedgerEntryExists(ledgerDir, markerName, exists = (p2) => existsSync6(p2)) {
|
|
37806
38119
|
if (!ledgerDir || !markerName) return false;
|
|
37807
38120
|
if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return false;
|
|
37808
38121
|
try {
|
|
37809
|
-
return exists(
|
|
38122
|
+
return exists(join13(ledgerDir, markerName));
|
|
37810
38123
|
} catch {
|
|
37811
38124
|
return false;
|
|
37812
38125
|
}
|
|
@@ -37817,14 +38130,14 @@ function removeRecoveryLedgerEntry(ledgerDir, markerName, unlink = (p2) => {
|
|
|
37817
38130
|
if (!ledgerDir || !markerName) return;
|
|
37818
38131
|
if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return;
|
|
37819
38132
|
try {
|
|
37820
|
-
unlink(
|
|
38133
|
+
unlink(join13(ledgerDir, markerName));
|
|
37821
38134
|
} catch {
|
|
37822
38135
|
}
|
|
37823
38136
|
}
|
|
37824
38137
|
|
|
37825
38138
|
// src/inbound-delivery-ledger.ts
|
|
37826
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync7, readdirSync as
|
|
37827
|
-
import { join as
|
|
38139
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync7, readdirSync as readdirSync4, readFileSync as readFileSync14, renameSync as renameSync5, writeFileSync as writeFileSync8 } from "fs";
|
|
38140
|
+
import { join as join14 } from "path";
|
|
37828
38141
|
function safeInboundId(inboundId) {
|
|
37829
38142
|
return inboundId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
37830
38143
|
}
|
|
@@ -37832,8 +38145,8 @@ var defaultDeps = {
|
|
|
37832
38145
|
mkdir: (dir) => mkdirSync7(dir, { recursive: true }),
|
|
37833
38146
|
writeFile: (path, data) => writeFileSync8(path, data, "utf8"),
|
|
37834
38147
|
rename: (from, to) => renameSync5(from, to),
|
|
37835
|
-
readdir: (dir) =>
|
|
37836
|
-
readFile: (path) =>
|
|
38148
|
+
readdir: (dir) => readdirSync4(dir),
|
|
38149
|
+
readFile: (path) => readFileSync14(path, "utf8"),
|
|
37837
38150
|
exists: (path) => existsSync7(path)
|
|
37838
38151
|
};
|
|
37839
38152
|
function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
|
|
@@ -37842,7 +38155,7 @@ function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
|
|
|
37842
38155
|
if (!safe || safe.includes("/") || safe.includes("\\") || safe.includes("..")) return;
|
|
37843
38156
|
try {
|
|
37844
38157
|
deps.mkdir(dir);
|
|
37845
|
-
const final =
|
|
38158
|
+
const final = join14(dir, `${safe}.json`);
|
|
37846
38159
|
const tmp = `${final}.tmp`;
|
|
37847
38160
|
deps.writeFile(tmp, JSON.stringify(record2));
|
|
37848
38161
|
deps.rename(tmp, final);
|
|
@@ -38047,14 +38360,14 @@ function createKanbanCardActiveClient(args) {
|
|
|
38047
38360
|
import {
|
|
38048
38361
|
existsSync as existsSync8,
|
|
38049
38362
|
mkdirSync as mkdirSync8,
|
|
38050
|
-
readFileSync as
|
|
38363
|
+
readFileSync as readFileSync15,
|
|
38051
38364
|
renameSync as renameSync6,
|
|
38052
|
-
statSync as
|
|
38365
|
+
statSync as statSync4,
|
|
38053
38366
|
unlinkSync as unlinkSync7,
|
|
38054
38367
|
utimesSync,
|
|
38055
38368
|
writeFileSync as writeFileSync9
|
|
38056
38369
|
} from "fs";
|
|
38057
|
-
import { join as
|
|
38370
|
+
import { join as join15 } from "path";
|
|
38058
38371
|
var STALE_LOCK_MS = 9e4;
|
|
38059
38372
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
38060
38373
|
function defaultIsPidAlive(pid) {
|
|
@@ -38077,7 +38390,7 @@ function acquireMcpSpawnLock(args) {
|
|
|
38077
38390
|
const nowMs = options.nowMs ?? (() => Date.now());
|
|
38078
38391
|
const lockMtimeMs = options.lockMtimeMs ?? defaultLockMtimeMs;
|
|
38079
38392
|
const staleMs = options.staleMs ?? STALE_LOCK_MS;
|
|
38080
|
-
const path =
|
|
38393
|
+
const path = join15(agentDir, basename2);
|
|
38081
38394
|
const existing = readLockHolder(path);
|
|
38082
38395
|
if (existing) {
|
|
38083
38396
|
if (existing.pid === selfPid) {
|
|
@@ -38136,7 +38449,7 @@ function startMcpSpawnLockHeartbeat(lockPath, opts = {}) {
|
|
|
38136
38449
|
}
|
|
38137
38450
|
function defaultLockMtimeMs(path) {
|
|
38138
38451
|
try {
|
|
38139
|
-
return
|
|
38452
|
+
return statSync4(path).mtimeMs;
|
|
38140
38453
|
} catch {
|
|
38141
38454
|
return null;
|
|
38142
38455
|
}
|
|
@@ -38144,7 +38457,7 @@ function defaultLockMtimeMs(path) {
|
|
|
38144
38457
|
function readLockHolder(path) {
|
|
38145
38458
|
if (!existsSync8(path)) return null;
|
|
38146
38459
|
try {
|
|
38147
|
-
const raw =
|
|
38460
|
+
const raw = readFileSync15(path, "utf8");
|
|
38148
38461
|
const parsed = JSON.parse(raw);
|
|
38149
38462
|
const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
|
|
38150
38463
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
@@ -38156,8 +38469,8 @@ function readLockHolder(path) {
|
|
|
38156
38469
|
}
|
|
38157
38470
|
|
|
38158
38471
|
// src/ack-reaction.ts
|
|
38159
|
-
import { readdirSync as
|
|
38160
|
-
import { join as
|
|
38472
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync16, writeFileSync as writeFileSync10 } from "fs";
|
|
38473
|
+
import { join as join16 } from "path";
|
|
38161
38474
|
var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
38162
38475
|
var ACK_STARTUP_GRACE_MS = 6e4;
|
|
38163
38476
|
var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
|
|
@@ -38230,7 +38543,7 @@ var GIVE_UP_SIGNAL_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
|
38230
38543
|
function readGiveUpSignal(path, now = Date.now()) {
|
|
38231
38544
|
if (!path) return null;
|
|
38232
38545
|
try {
|
|
38233
|
-
const raw = JSON.parse(
|
|
38546
|
+
const raw = JSON.parse(readFileSync16(path, "utf8"));
|
|
38234
38547
|
if (typeof raw.gave_up_at !== "string") return null;
|
|
38235
38548
|
const t = Date.parse(raw.gave_up_at);
|
|
38236
38549
|
if (!Number.isFinite(t) || t > now) return null;
|
|
@@ -38252,11 +38565,17 @@ function giveUpNoticeText(reason = null) {
|
|
|
38252
38565
|
}
|
|
38253
38566
|
return "\u26A0\uFE0F I couldn't read your last message \u2014 please resend it.";
|
|
38254
38567
|
}
|
|
38568
|
+
function turnFailedNoticeText() {
|
|
38569
|
+
return "\u26A0\uFE0F Something went wrong on my side and I couldn\u2019t finish that. Sorry \u2014 send it again when you get a chance and I\u2019ll pick it straight up.";
|
|
38570
|
+
}
|
|
38571
|
+
function turnRetryingNoticeText() {
|
|
38572
|
+
return "\u23F3 Still working on this \u2014 things are running slower than usual on my side. I\u2019ll reply as soon as I have it.";
|
|
38573
|
+
}
|
|
38255
38574
|
function oldestPendingMarkerAgeMs(dir, now = Date.now(), opts) {
|
|
38256
38575
|
if (!dir) return null;
|
|
38257
38576
|
let names;
|
|
38258
38577
|
try {
|
|
38259
|
-
names =
|
|
38578
|
+
names = readdirSync5(dir);
|
|
38260
38579
|
} catch {
|
|
38261
38580
|
return null;
|
|
38262
38581
|
}
|
|
@@ -38265,7 +38584,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now(), opts) {
|
|
|
38265
38584
|
if (!name.endsWith(".json")) continue;
|
|
38266
38585
|
let receivedAt;
|
|
38267
38586
|
try {
|
|
38268
|
-
const raw = JSON.parse(
|
|
38587
|
+
const raw = JSON.parse(readFileSync16(join16(dir, name), "utf-8"));
|
|
38269
38588
|
if (raw.discretionary === true) continue;
|
|
38270
38589
|
if (!opts?.includeSeen && typeof raw.seen_at === "string" && raw.seen_at) continue;
|
|
38271
38590
|
receivedAt = raw.received_at;
|
|
@@ -38342,14 +38661,14 @@ function isMarkerGenuinelyAged(receivedAt, nowMs, thresholdMs) {
|
|
|
38342
38661
|
}
|
|
38343
38662
|
var DEFLECTION_COUNTER_SUFFIX = "-deflections.json";
|
|
38344
38663
|
function deflectionCounterPath(agentDir, channel) {
|
|
38345
|
-
return
|
|
38664
|
+
return join16(agentDir, `${channel}${DEFLECTION_COUNTER_SUFFIX}`);
|
|
38346
38665
|
}
|
|
38347
38666
|
function recordChannelDeflection(agentDir, channel, cause) {
|
|
38348
38667
|
if (!agentDir) return;
|
|
38349
38668
|
const path = deflectionCounterPath(agentDir, channel);
|
|
38350
38669
|
let counts = {};
|
|
38351
38670
|
try {
|
|
38352
|
-
const parsed = JSON.parse(
|
|
38671
|
+
const parsed = JSON.parse(readFileSync16(path, "utf-8"));
|
|
38353
38672
|
if (parsed && typeof parsed === "object") counts = parsed;
|
|
38354
38673
|
} catch {
|
|
38355
38674
|
}
|
|
@@ -38430,7 +38749,7 @@ function redactId(id) {
|
|
|
38430
38749
|
}
|
|
38431
38750
|
var BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
|
|
38432
38751
|
var AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME ?? "unknown";
|
|
38433
|
-
var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ?
|
|
38752
|
+
var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join17(homedir7(), ".augmented", AGENT_CODE_NAME) : null;
|
|
38434
38753
|
var AGT_HOST = process.env.AGT_HOST ?? null;
|
|
38435
38754
|
var AGT_API_KEY = process.env.AGT_API_KEY ?? null;
|
|
38436
38755
|
var AGT_AGENT_ID = process.env.AGT_AGENT_ID ?? null;
|
|
@@ -38533,11 +38852,11 @@ var peerRateLimiter = peerRateApiClient && parsePeerAgentModeEnv(process.env.TEL
|
|
|
38533
38852
|
log: (line) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${line}
|
|
38534
38853
|
`)
|
|
38535
38854
|
}) : createPeerRateLimiter();
|
|
38536
|
-
var PEER_PRESENCE_STATE_FILE = TELEGRAM_AGENT_DIR ?
|
|
38855
|
+
var PEER_PRESENCE_STATE_FILE = TELEGRAM_AGENT_DIR ? join17(TELEGRAM_AGENT_DIR, "telegram-peer-presence.json") : null;
|
|
38537
38856
|
function readPeerPresenceState() {
|
|
38538
38857
|
if (!PEER_PRESENCE_STATE_FILE) return null;
|
|
38539
38858
|
try {
|
|
38540
|
-
const parsed = JSON.parse(
|
|
38859
|
+
const parsed = JSON.parse(readFileSync17(PEER_PRESENCE_STATE_FILE, "utf-8"));
|
|
38541
38860
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
38542
38861
|
return parsed;
|
|
38543
38862
|
} catch {
|
|
@@ -38572,9 +38891,9 @@ if (!BOT_TOKEN) {
|
|
|
38572
38891
|
var stderrLogStream = null;
|
|
38573
38892
|
if (AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown") {
|
|
38574
38893
|
try {
|
|
38575
|
-
const logDir =
|
|
38894
|
+
const logDir = join17(homedir7(), ".augmented", AGENT_CODE_NAME);
|
|
38576
38895
|
mkdirSync9(logDir, { recursive: true });
|
|
38577
|
-
stderrLogStream = createWriteStream(
|
|
38896
|
+
stderrLogStream = createWriteStream(join17(logDir, "telegram-channel-stderr.log"), {
|
|
38578
38897
|
flags: "a",
|
|
38579
38898
|
mode: 384
|
|
38580
38899
|
});
|
|
@@ -39011,7 +39330,7 @@ function scheduleBusyAck(chatId, messageId, arrivedWhileBusy) {
|
|
|
39011
39330
|
let paneLogFreshAgeMs = null;
|
|
39012
39331
|
if (AGENT_DIR) {
|
|
39013
39332
|
try {
|
|
39014
|
-
const paneMtimeMs =
|
|
39333
|
+
const paneMtimeMs = statSync5(join17(AGENT_DIR, "pane.log")).mtimeMs;
|
|
39015
39334
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
39016
39335
|
} catch {
|
|
39017
39336
|
}
|
|
@@ -39041,7 +39360,7 @@ function scheduleBusyAck(chatId, messageId, arrivedWhileBusy) {
|
|
|
39041
39360
|
function __resetBusyAckNoticeThrottle() {
|
|
39042
39361
|
lastBusyAckNoticeAt.clear();
|
|
39043
39362
|
}
|
|
39044
|
-
var RESTART_FLAGS_DIR =
|
|
39363
|
+
var RESTART_FLAGS_DIR = join17(homedir7(), ".augmented", "restart-flags");
|
|
39045
39364
|
function actuateHostRestartTelegram() {
|
|
39046
39365
|
return actuateHostRestart({
|
|
39047
39366
|
agtHost: AGT_HOST,
|
|
@@ -39426,7 +39745,7 @@ async function handleRestartCommand(opts) {
|
|
|
39426
39745
|
if (!existsSync9(RESTART_FLAGS_DIR)) {
|
|
39427
39746
|
mkdirSync9(RESTART_FLAGS_DIR, { recursive: true });
|
|
39428
39747
|
}
|
|
39429
|
-
const flagPath =
|
|
39748
|
+
const flagPath = join17(RESTART_FLAGS_DIR, `${AGENT_CODE_NAME}.flag`);
|
|
39430
39749
|
const flag = {
|
|
39431
39750
|
codeName: AGENT_CODE_NAME,
|
|
39432
39751
|
source: "telegram",
|
|
@@ -39832,16 +40151,16 @@ async function classifyRestartCommand(text) {
|
|
|
39832
40151
|
if (!ours) return "verification_failed";
|
|
39833
40152
|
return target === ours ? "act" : "ignore";
|
|
39834
40153
|
}
|
|
39835
|
-
var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ?
|
|
39836
|
-
var PENDING_INBOUND_DIR = AGENT_DIR ?
|
|
39837
|
-
var RECOVERY_OUTBOX_DIR = AGENT_DIR ?
|
|
39838
|
-
var RECOVERY_LEDGER_DIR = AGENT_DIR ?
|
|
39839
|
-
var DELIVERY_LEDGER_DIR = AGENT_DIR ?
|
|
39840
|
-
var RESTART_CONFIRM_FILE = AGENT_DIR ?
|
|
40154
|
+
var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join17(homedir7(), ".augmented", AGENT_CODE_NAME) : null;
|
|
40155
|
+
var PENDING_INBOUND_DIR = AGENT_DIR ? join17(AGENT_DIR, "telegram-pending-inbound") : null;
|
|
40156
|
+
var RECOVERY_OUTBOX_DIR = AGENT_DIR ? join17(AGENT_DIR, "telegram-recovery-outbox") : null;
|
|
40157
|
+
var RECOVERY_LEDGER_DIR = AGENT_DIR ? join17(AGENT_DIR, ".agt-telegram-recovery-ledger") : null;
|
|
40158
|
+
var DELIVERY_LEDGER_DIR = AGENT_DIR ? join17(AGENT_DIR, ".agt-inbound-delivery-ledger") : null;
|
|
40159
|
+
var RESTART_CONFIRM_FILE = AGENT_DIR ? join17(AGENT_DIR, "telegram-restart-confirm.json") : null;
|
|
39841
40160
|
var TELEGRAM_PROCESS_BOOT_MS = Date.now();
|
|
39842
|
-
var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ?
|
|
39843
|
-
var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ?
|
|
39844
|
-
var TELEGRAM_OFFSET_FILE = AGENT_DIR ?
|
|
40161
|
+
var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ? join17(AGENT_DIR, "telegram-recent-dms.json") : null;
|
|
40162
|
+
var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ? join17(AGENT_DIR, "telegram-channel-add-restart.json") : null;
|
|
40163
|
+
var TELEGRAM_OFFSET_FILE = AGENT_DIR ? join17(AGENT_DIR, "telegram-getupdates-offset.json") : null;
|
|
39845
40164
|
var recentDms = /* @__PURE__ */ new Map();
|
|
39846
40165
|
var recentDmPersister = TELEGRAM_RECENT_DMS_FILE ? createRecentDmPersister({
|
|
39847
40166
|
filePath: TELEGRAM_RECENT_DMS_FILE,
|
|
@@ -39896,7 +40215,7 @@ function safeMarkerName(chatId, messageId) {
|
|
|
39896
40215
|
}
|
|
39897
40216
|
function pendingInboundPath(chatId, messageId) {
|
|
39898
40217
|
if (!PENDING_INBOUND_DIR) return null;
|
|
39899
|
-
return
|
|
40218
|
+
return join17(PENDING_INBOUND_DIR, safeMarkerName(chatId, messageId));
|
|
39900
40219
|
}
|
|
39901
40220
|
function writePendingInboundMarker(chatId, messageId, chatType, undeliverable = false, payload) {
|
|
39902
40221
|
const path = pendingInboundPath(chatId, messageId);
|
|
@@ -39944,7 +40263,7 @@ function rewriteTelegramMarkerInPlace(path, marker) {
|
|
|
39944
40263
|
function clearTelegramMarkerFileWithHeal(fullPath) {
|
|
39945
40264
|
let marker = null;
|
|
39946
40265
|
try {
|
|
39947
|
-
marker = JSON.parse(
|
|
40266
|
+
marker = JSON.parse(readFileSync17(fullPath, "utf-8"));
|
|
39948
40267
|
} catch {
|
|
39949
40268
|
}
|
|
39950
40269
|
if (marker && decideRecoveryHeal({
|
|
@@ -39961,7 +40280,7 @@ function clearTelegramMarkerFileWithHeal(fullPath) {
|
|
|
39961
40280
|
function markTelegramMarkerSeenInPlace(fullPath) {
|
|
39962
40281
|
let marker;
|
|
39963
40282
|
try {
|
|
39964
|
-
marker = JSON.parse(
|
|
40283
|
+
marker = JSON.parse(readFileSync17(fullPath, "utf-8"));
|
|
39965
40284
|
} catch {
|
|
39966
40285
|
return;
|
|
39967
40286
|
}
|
|
@@ -39973,7 +40292,7 @@ function markTelegramMarkerSeenInPlace(fullPath) {
|
|
|
39973
40292
|
function markTelegramMarkerSeenWithHeal(fullPath) {
|
|
39974
40293
|
let marker = null;
|
|
39975
40294
|
try {
|
|
39976
|
-
marker = JSON.parse(
|
|
40295
|
+
marker = JSON.parse(readFileSync17(fullPath, "utf-8"));
|
|
39977
40296
|
} catch {
|
|
39978
40297
|
return;
|
|
39979
40298
|
}
|
|
@@ -39989,7 +40308,7 @@ function readPendingInboundMarker(chatId, messageId) {
|
|
|
39989
40308
|
const path = pendingInboundPath(chatId, messageId);
|
|
39990
40309
|
if (!path || !existsSync9(path)) return null;
|
|
39991
40310
|
try {
|
|
39992
|
-
return JSON.parse(
|
|
40311
|
+
return JSON.parse(readFileSync17(path, "utf-8"));
|
|
39993
40312
|
} catch {
|
|
39994
40313
|
return null;
|
|
39995
40314
|
}
|
|
@@ -40009,10 +40328,10 @@ function nextRetryName(filename) {
|
|
|
40009
40328
|
async function processRecoveryOutboxFile(filename) {
|
|
40010
40329
|
if (!RECOVERY_OUTBOX_DIR) return;
|
|
40011
40330
|
if (filename.endsWith(".poison.json") || filename.endsWith(".tmp")) return;
|
|
40012
|
-
const fullPath =
|
|
40331
|
+
const fullPath = join17(RECOVERY_OUTBOX_DIR, filename);
|
|
40013
40332
|
let payload;
|
|
40014
40333
|
try {
|
|
40015
|
-
const raw =
|
|
40334
|
+
const raw = readFileSync17(fullPath, "utf-8");
|
|
40016
40335
|
payload = JSON.parse(raw);
|
|
40017
40336
|
} catch (err) {
|
|
40018
40337
|
process.stderr.write(
|
|
@@ -40106,7 +40425,7 @@ async function processRecoveryOutboxFile(filename) {
|
|
|
40106
40425
|
const next = nextRetryName(filename);
|
|
40107
40426
|
if (next) {
|
|
40108
40427
|
try {
|
|
40109
|
-
renameSync7(fullPath,
|
|
40428
|
+
renameSync7(fullPath, join17(RECOVERY_OUTBOX_DIR, next.next));
|
|
40110
40429
|
if (next.attempt >= MAX_RECOVERY_ATTEMPTS) {
|
|
40111
40430
|
process.stderr.write(
|
|
40112
40431
|
`telegram-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
|
|
@@ -40138,7 +40457,7 @@ function scanRecoveryRetries() {
|
|
|
40138
40457
|
if (!RECOVERY_OUTBOX_DIR) return;
|
|
40139
40458
|
let entries;
|
|
40140
40459
|
try {
|
|
40141
|
-
entries =
|
|
40460
|
+
entries = readdirSync6(RECOVERY_OUTBOX_DIR);
|
|
40142
40461
|
} catch {
|
|
40143
40462
|
return;
|
|
40144
40463
|
}
|
|
@@ -40147,7 +40466,7 @@ function scanRecoveryRetries() {
|
|
|
40147
40466
|
if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
|
|
40148
40467
|
let mtimeMs;
|
|
40149
40468
|
try {
|
|
40150
|
-
mtimeMs =
|
|
40469
|
+
mtimeMs = statSync5(join17(RECOVERY_OUTBOX_DIR, f)).mtimeMs;
|
|
40151
40470
|
} catch {
|
|
40152
40471
|
continue;
|
|
40153
40472
|
}
|
|
@@ -40168,7 +40487,7 @@ function startRecoveryOutboxWatcher() {
|
|
|
40168
40487
|
return;
|
|
40169
40488
|
}
|
|
40170
40489
|
try {
|
|
40171
|
-
for (const f of
|
|
40490
|
+
for (const f of readdirSync6(RECOVERY_OUTBOX_DIR)) {
|
|
40172
40491
|
if (isFirstAttemptOutboxFile(f)) void processRecoveryOutboxFile(f);
|
|
40173
40492
|
}
|
|
40174
40493
|
} catch {
|
|
@@ -40177,7 +40496,7 @@ function startRecoveryOutboxWatcher() {
|
|
|
40177
40496
|
const watcher = watch(RECOVERY_OUTBOX_DIR, (event, filename) => {
|
|
40178
40497
|
if (event !== "rename" || !filename) return;
|
|
40179
40498
|
if (!isFirstAttemptOutboxFile(filename)) return;
|
|
40180
|
-
if (existsSync9(
|
|
40499
|
+
if (existsSync9(join17(RECOVERY_OUTBOX_DIR, filename))) {
|
|
40181
40500
|
void processRecoveryOutboxFile(filename);
|
|
40182
40501
|
}
|
|
40183
40502
|
});
|
|
@@ -40192,7 +40511,7 @@ function startRecoveryOutboxWatcher() {
|
|
|
40192
40511
|
retryTimer.unref?.();
|
|
40193
40512
|
}
|
|
40194
40513
|
startRecoveryOutboxWatcher();
|
|
40195
|
-
var NOTICE_OUTBOX_DIR = AGENT_DIR ?
|
|
40514
|
+
var NOTICE_OUTBOX_DIR = AGENT_DIR ? join17(AGENT_DIR, "telegram-notice-outbox") : null;
|
|
40196
40515
|
var NOTICE_MAX_AGE_MS = 9e4;
|
|
40197
40516
|
var NOTICE_INFLIGHT = /* @__PURE__ */ new Set();
|
|
40198
40517
|
async function processNoticeOutboxFile(filename) {
|
|
@@ -40200,11 +40519,11 @@ async function processNoticeOutboxFile(filename) {
|
|
|
40200
40519
|
if (filename.startsWith(".") || filename.endsWith(".tmp") || !filename.endsWith(".json")) return;
|
|
40201
40520
|
if (NOTICE_INFLIGHT.has(filename)) return;
|
|
40202
40521
|
NOTICE_INFLIGHT.add(filename);
|
|
40203
|
-
const fullPath =
|
|
40522
|
+
const fullPath = join17(NOTICE_OUTBOX_DIR, filename);
|
|
40204
40523
|
try {
|
|
40205
40524
|
let mtimeMs;
|
|
40206
40525
|
try {
|
|
40207
|
-
mtimeMs =
|
|
40526
|
+
mtimeMs = statSync5(fullPath).mtimeMs;
|
|
40208
40527
|
} catch {
|
|
40209
40528
|
return;
|
|
40210
40529
|
}
|
|
@@ -40217,7 +40536,7 @@ async function processNoticeOutboxFile(filename) {
|
|
|
40217
40536
|
}
|
|
40218
40537
|
let payload;
|
|
40219
40538
|
try {
|
|
40220
|
-
const parsed = JSON.parse(
|
|
40539
|
+
const parsed = JSON.parse(readFileSync17(fullPath, "utf-8"));
|
|
40221
40540
|
if (!parsed || typeof parsed !== "object") throw new Error("not an object");
|
|
40222
40541
|
payload = parsed;
|
|
40223
40542
|
} catch {
|
|
@@ -40288,13 +40607,13 @@ function startNoticeOutboxWatcher() {
|
|
|
40288
40607
|
return;
|
|
40289
40608
|
}
|
|
40290
40609
|
try {
|
|
40291
|
-
for (const f of
|
|
40610
|
+
for (const f of readdirSync6(NOTICE_OUTBOX_DIR)) void processNoticeOutboxFile(f);
|
|
40292
40611
|
} catch {
|
|
40293
40612
|
}
|
|
40294
40613
|
try {
|
|
40295
40614
|
const watcher = watch(NOTICE_OUTBOX_DIR, (event, filename) => {
|
|
40296
40615
|
if (event !== "rename" || !filename) return;
|
|
40297
|
-
if (existsSync9(
|
|
40616
|
+
if (existsSync9(join17(NOTICE_OUTBOX_DIR, filename))) void processNoticeOutboxFile(filename);
|
|
40298
40617
|
});
|
|
40299
40618
|
watcher.unref?.();
|
|
40300
40619
|
} catch (err) {
|
|
@@ -40314,7 +40633,7 @@ function sweepTelegramStaleMarkers(thresholdMs) {
|
|
|
40314
40633
|
if (!existsSync9(PENDING_INBOUND_DIR)) return;
|
|
40315
40634
|
let filenames;
|
|
40316
40635
|
try {
|
|
40317
|
-
filenames =
|
|
40636
|
+
filenames = readdirSync6(PENDING_INBOUND_DIR);
|
|
40318
40637
|
} catch (err) {
|
|
40319
40638
|
process.stderr.write(
|
|
40320
40639
|
`telegram-channel(${AGENT_CODE_NAME}): stale-marker readdir failed: ${err.message}
|
|
@@ -40328,10 +40647,10 @@ function sweepTelegramStaleMarkers(thresholdMs) {
|
|
|
40328
40647
|
for (const filename of filenames) {
|
|
40329
40648
|
if (!filename.endsWith(".json")) continue;
|
|
40330
40649
|
if (filename.endsWith(".tmp")) continue;
|
|
40331
|
-
const fullPath =
|
|
40650
|
+
const fullPath = join17(PENDING_INBOUND_DIR, filename);
|
|
40332
40651
|
let marker;
|
|
40333
40652
|
try {
|
|
40334
|
-
marker = JSON.parse(
|
|
40653
|
+
marker = JSON.parse(readFileSync17(fullPath, "utf-8"));
|
|
40335
40654
|
} catch (err) {
|
|
40336
40655
|
process.stderr.write(
|
|
40337
40656
|
`telegram-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactId(filename)}: ${err.message}
|
|
@@ -40384,13 +40703,13 @@ var orphanSweepTimer = setInterval(() => {
|
|
|
40384
40703
|
checkWatchdogGiveUpNotice();
|
|
40385
40704
|
}, orphanSweepIntervalMs());
|
|
40386
40705
|
orphanSweepTimer.unref?.();
|
|
40387
|
-
var TELEGRAM_PROGRESS_HEARTBEAT_PATH = AGENT_DIR ?
|
|
40706
|
+
var TELEGRAM_PROGRESS_HEARTBEAT_PATH = AGENT_DIR ? join17(AGENT_DIR, "channel-progress-heartbeat.json") : null;
|
|
40388
40707
|
var telegramTrackedProgress = null;
|
|
40389
40708
|
var telegramProgressTickRunning = false;
|
|
40390
40709
|
function readTelegramProgressHeartbeat() {
|
|
40391
40710
|
if (!TELEGRAM_PROGRESS_HEARTBEAT_PATH || !existsSync9(TELEGRAM_PROGRESS_HEARTBEAT_PATH)) return null;
|
|
40392
40711
|
try {
|
|
40393
|
-
return parseProgressHeartbeat(
|
|
40712
|
+
return parseProgressHeartbeat(readFileSync17(TELEGRAM_PROGRESS_HEARTBEAT_PATH, "utf-8"));
|
|
40394
40713
|
} catch {
|
|
40395
40714
|
return null;
|
|
40396
40715
|
}
|
|
@@ -40413,11 +40732,11 @@ function findTelegramProgressTarget() {
|
|
|
40413
40732
|
let best = null;
|
|
40414
40733
|
let bestMs = Infinity;
|
|
40415
40734
|
try {
|
|
40416
|
-
for (const name of
|
|
40735
|
+
for (const name of readdirSync6(PENDING_INBOUND_DIR)) {
|
|
40417
40736
|
if (!name.endsWith(".json")) continue;
|
|
40418
40737
|
let m;
|
|
40419
40738
|
try {
|
|
40420
|
-
m = JSON.parse(
|
|
40739
|
+
m = JSON.parse(readFileSync17(join17(PENDING_INBOUND_DIR, name), "utf-8"));
|
|
40421
40740
|
} catch {
|
|
40422
40741
|
continue;
|
|
40423
40742
|
}
|
|
@@ -40544,11 +40863,11 @@ function listPendingInboundChatIds() {
|
|
|
40544
40863
|
if (!PENDING_INBOUND_DIR || !existsSync9(PENDING_INBOUND_DIR)) return [];
|
|
40545
40864
|
const chats = /* @__PURE__ */ new Set();
|
|
40546
40865
|
try {
|
|
40547
|
-
for (const name of
|
|
40866
|
+
for (const name of readdirSync6(PENDING_INBOUND_DIR)) {
|
|
40548
40867
|
if (!name.endsWith(".json")) continue;
|
|
40549
40868
|
try {
|
|
40550
40869
|
const marker = JSON.parse(
|
|
40551
|
-
|
|
40870
|
+
readFileSync17(join17(PENDING_INBOUND_DIR, name), "utf8")
|
|
40552
40871
|
);
|
|
40553
40872
|
if (typeof marker.seen_at === "string" && marker.seen_at) continue;
|
|
40554
40873
|
if (typeof marker.chat_id === "string" && marker.chat_id) chats.add(marker.chat_id);
|
|
@@ -40560,6 +40879,84 @@ function listPendingInboundChatIds() {
|
|
|
40560
40879
|
}
|
|
40561
40880
|
return [...chats];
|
|
40562
40881
|
}
|
|
40882
|
+
var lastTurnFailedNoticeAt = /* @__PURE__ */ new Map();
|
|
40883
|
+
var lastTurnRetryingNoticeAt = /* @__PURE__ */ new Map();
|
|
40884
|
+
async function postTelegramTurnNotice(args) {
|
|
40885
|
+
try {
|
|
40886
|
+
const resp = await telegramApiCall(
|
|
40887
|
+
"sendMessage",
|
|
40888
|
+
{
|
|
40889
|
+
chat_id: args.chatId,
|
|
40890
|
+
text: args.text,
|
|
40891
|
+
...args.messageThreadId != null ? { message_thread_id: args.messageThreadId } : {}
|
|
40892
|
+
},
|
|
40893
|
+
1e4
|
|
40894
|
+
);
|
|
40895
|
+
return resp.ok === true;
|
|
40896
|
+
} catch {
|
|
40897
|
+
return false;
|
|
40898
|
+
}
|
|
40899
|
+
}
|
|
40900
|
+
function armTelegramTurnFailureWatch(args) {
|
|
40901
|
+
const conversationKey = args.messageThreadId != null ? `${args.chatId}:${args.messageThreadId}` : args.chatId;
|
|
40902
|
+
void (async () => {
|
|
40903
|
+
try {
|
|
40904
|
+
const failure = await watchForTurnFailure({
|
|
40905
|
+
sinceMs: args.sinceMs,
|
|
40906
|
+
channel: "telegram",
|
|
40907
|
+
onLongRetry: async () => {
|
|
40908
|
+
const now2 = Date.now();
|
|
40909
|
+
if (!shouldPostUndeliverableNotice(lastTurnRetryingNoticeAt.get(conversationKey), now2)) {
|
|
40910
|
+
return;
|
|
40911
|
+
}
|
|
40912
|
+
lastTurnRetryingNoticeAt.set(conversationKey, now2);
|
|
40913
|
+
const posted2 = await postTelegramTurnNotice({
|
|
40914
|
+
chatId: args.chatId,
|
|
40915
|
+
...args.messageThreadId != null ? { messageThreadId: args.messageThreadId } : {},
|
|
40916
|
+
text: turnRetryingNoticeText()
|
|
40917
|
+
});
|
|
40918
|
+
if (!posted2) lastTurnRetryingNoticeAt.delete(conversationKey);
|
|
40919
|
+
process.stderr.write(
|
|
40920
|
+
`telegram-channel(${AGENT_CODE_NAME}): [turn-failure] retrying notice ${posted2 ? "posted" : "FAILED"} chat=${redactId(args.chatId)}
|
|
40921
|
+
`
|
|
40922
|
+
);
|
|
40923
|
+
}
|
|
40924
|
+
});
|
|
40925
|
+
if (!failure) return;
|
|
40926
|
+
const now = Date.now();
|
|
40927
|
+
if (!shouldPostUndeliverableNotice(lastTurnFailedNoticeAt.get(conversationKey), now)) {
|
|
40928
|
+
process.stderr.write(
|
|
40929
|
+
`telegram-channel(${AGENT_CODE_NAME}): [turn-failure] suppressed (throttled) chat=${redactId(args.chatId)} class=${failure.failureClass}
|
|
40930
|
+
`
|
|
40931
|
+
);
|
|
40932
|
+
return;
|
|
40933
|
+
}
|
|
40934
|
+
lastTurnFailedNoticeAt.set(conversationKey, now);
|
|
40935
|
+
const posted = await postTelegramTurnNotice({
|
|
40936
|
+
chatId: args.chatId,
|
|
40937
|
+
...args.messageThreadId != null ? { messageThreadId: args.messageThreadId } : {},
|
|
40938
|
+
text: turnFailedNoticeText()
|
|
40939
|
+
});
|
|
40940
|
+
if (!posted) {
|
|
40941
|
+
lastTurnFailedNoticeAt.delete(conversationKey);
|
|
40942
|
+
process.stderr.write(
|
|
40943
|
+
`telegram-channel(${AGENT_CODE_NAME}): [turn-failure] NOTICE POST FAILED chat=${redactId(args.chatId)} - the user is still waiting on a dead turn
|
|
40944
|
+
`
|
|
40945
|
+
);
|
|
40946
|
+
return;
|
|
40947
|
+
}
|
|
40948
|
+
process.stderr.write(
|
|
40949
|
+
`telegram-channel(${AGENT_CODE_NAME}): [turn-failure] notified chat=${redactId(args.chatId)} class=${failure.failureClass} status=${failure.httpStatus}
|
|
40950
|
+
`
|
|
40951
|
+
);
|
|
40952
|
+
} catch (err) {
|
|
40953
|
+
process.stderr.write(
|
|
40954
|
+
`telegram-channel(${AGENT_CODE_NAME}): [turn-failure] watch error: ${err.message}
|
|
40955
|
+
`
|
|
40956
|
+
);
|
|
40957
|
+
}
|
|
40958
|
+
})();
|
|
40959
|
+
}
|
|
40563
40960
|
async function notifyWatchdogGiveUp(chatId, reason) {
|
|
40564
40961
|
const now = Date.now();
|
|
40565
40962
|
if (!shouldPostUndeliverableNotice(lastUndeliverableNoticeAt.get(chatId), now)) return;
|
|
@@ -40590,7 +40987,7 @@ async function notifyWatchdogGiveUp(chatId, reason) {
|
|
|
40590
40987
|
}
|
|
40591
40988
|
function checkWatchdogGiveUpNotice() {
|
|
40592
40989
|
if (!AGENT_DIR) return;
|
|
40593
|
-
const signal = readGiveUpSignal(
|
|
40990
|
+
const signal = readGiveUpSignal(join17(AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
|
|
40594
40991
|
const signalAtMs = signal?.atMs ?? null;
|
|
40595
40992
|
const act = decideGiveUpNotice({
|
|
40596
40993
|
signalAtMs,
|
|
@@ -40932,7 +41329,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
40932
41329
|
let bytes;
|
|
40933
41330
|
let size;
|
|
40934
41331
|
try {
|
|
40935
|
-
const st =
|
|
41332
|
+
const st = statSync5(realPath);
|
|
40936
41333
|
if (!st.isFile()) {
|
|
40937
41334
|
return { content: [{ type: "text", text: `Upload refused: ${resolvedPath} is not a regular file.` }], isError: true };
|
|
40938
41335
|
}
|
|
@@ -40946,7 +41343,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
40946
41343
|
isError: true
|
|
40947
41344
|
};
|
|
40948
41345
|
}
|
|
40949
|
-
bytes =
|
|
41346
|
+
bytes = readFileSync17(realPath);
|
|
40950
41347
|
} catch (err) {
|
|
40951
41348
|
return { content: [{ type: "text", text: `Failed to read file: ${err.message}` }], isError: true };
|
|
40952
41349
|
}
|
|
@@ -41500,7 +41897,7 @@ async function replayPendingTelegramMarkers() {
|
|
|
41500
41897
|
if (!sessionAlive) return;
|
|
41501
41898
|
let filenames;
|
|
41502
41899
|
try {
|
|
41503
|
-
filenames =
|
|
41900
|
+
filenames = readdirSync6(PENDING_INBOUND_DIR);
|
|
41504
41901
|
} catch {
|
|
41505
41902
|
return;
|
|
41506
41903
|
}
|
|
@@ -41508,7 +41905,7 @@ async function replayPendingTelegramMarkers() {
|
|
|
41508
41905
|
let paneFreshAgeMs = null;
|
|
41509
41906
|
if (AGENT_DIR) {
|
|
41510
41907
|
try {
|
|
41511
|
-
paneFreshAgeMs = Math.max(0, now -
|
|
41908
|
+
paneFreshAgeMs = Math.max(0, now - statSync5(join17(AGENT_DIR, "pane.log")).mtimeMs);
|
|
41512
41909
|
} catch {
|
|
41513
41910
|
}
|
|
41514
41911
|
}
|
|
@@ -41516,10 +41913,10 @@ async function replayPendingTelegramMarkers() {
|
|
|
41516
41913
|
const entries = [];
|
|
41517
41914
|
for (const name of filenames) {
|
|
41518
41915
|
if (!name.endsWith(".json") || name.endsWith(".tmp")) continue;
|
|
41519
|
-
const fullPath =
|
|
41916
|
+
const fullPath = join17(PENDING_INBOUND_DIR, name);
|
|
41520
41917
|
let marker;
|
|
41521
41918
|
try {
|
|
41522
|
-
marker = JSON.parse(
|
|
41919
|
+
marker = JSON.parse(readFileSync17(fullPath, "utf-8"));
|
|
41523
41920
|
} catch {
|
|
41524
41921
|
continue;
|
|
41525
41922
|
}
|
|
@@ -41687,7 +42084,7 @@ async function pollLoop() {
|
|
|
41687
42084
|
`telegram-channel(${AGENT_CODE_NAME}): getUpdates failed: ${resp.description ?? "unknown"}
|
|
41688
42085
|
`
|
|
41689
42086
|
);
|
|
41690
|
-
await
|
|
42087
|
+
await sleep4(5e3);
|
|
41691
42088
|
continue;
|
|
41692
42089
|
}
|
|
41693
42090
|
const offsetBeforeBatch = nextOffset;
|
|
@@ -42070,7 +42467,7 @@ async function pollLoop() {
|
|
|
42070
42467
|
let paneLogFreshAgeMs = null;
|
|
42071
42468
|
if (AGENT_DIR) {
|
|
42072
42469
|
try {
|
|
42073
|
-
const paneMtimeMs =
|
|
42470
|
+
const paneMtimeMs = statSync5(join17(AGENT_DIR, "pane.log")).mtimeMs;
|
|
42074
42471
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
42075
42472
|
} catch {
|
|
42076
42473
|
}
|
|
@@ -42190,6 +42587,13 @@ async function pollLoop() {
|
|
|
42190
42587
|
sinceMs: dispatchedAtMs
|
|
42191
42588
|
});
|
|
42192
42589
|
}
|
|
42590
|
+
if (!isFromBot && !peerAgentMeta && turnFailureNoticeEnabled()) {
|
|
42591
|
+
armTelegramTurnFailureWatch({
|
|
42592
|
+
chatId,
|
|
42593
|
+
...msg.message_thread_id != null ? { messageThreadId: msg.message_thread_id } : {},
|
|
42594
|
+
sinceMs: dispatchedAtMs
|
|
42595
|
+
});
|
|
42596
|
+
}
|
|
42193
42597
|
seedTelegramProgressHeartbeat();
|
|
42194
42598
|
conversationIngestClient?.ingest({
|
|
42195
42599
|
channel: "telegram",
|
|
@@ -42235,11 +42639,11 @@ async function pollLoop() {
|
|
|
42235
42639
|
`telegram-channel(${AGENT_CODE_NAME}): poll error: ${err.message}
|
|
42236
42640
|
`
|
|
42237
42641
|
);
|
|
42238
|
-
await
|
|
42642
|
+
await sleep4(5e3);
|
|
42239
42643
|
}
|
|
42240
42644
|
}
|
|
42241
42645
|
}
|
|
42242
|
-
function
|
|
42646
|
+
function sleep4(ms) {
|
|
42243
42647
|
return new Promise((resolve3) => setTimeout(resolve3, ms).unref());
|
|
42244
42648
|
}
|
|
42245
42649
|
function shutdown(reason) {
|