@integrity-labs/agt-cli 0.28.449 → 0.28.451

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.
@@ -18870,7 +18870,7 @@ var require_filters = __commonJS({
18870
18870
  return r.copySafeness(str, res);
18871
18871
  }
18872
18872
  _exports.indent = indent;
18873
- function join16(arr, del, attr) {
18873
+ function join17(arr, del, attr) {
18874
18874
  del = del || "";
18875
18875
  if (attr) {
18876
18876
  arr = lib.map(arr, function(v) {
@@ -18879,7 +18879,7 @@ var require_filters = __commonJS({
18879
18879
  }
18880
18880
  return arr.join(del);
18881
18881
  }
18882
- _exports.join = join16;
18882
+ _exports.join = join17;
18883
18883
  function last(arr) {
18884
18884
  return arr[arr.length - 1];
18885
18885
  }
@@ -22480,11 +22480,11 @@ async function waitForResolution(cfg, callbackId, opts) {
22480
22480
  }
22481
22481
  } catch {
22482
22482
  }
22483
- await sleep(interval);
22483
+ await sleep2(interval);
22484
22484
  }
22485
22485
  return { kind: "timeout" };
22486
22486
  }
22487
- function sleep(ms) {
22487
+ function sleep2(ms) {
22488
22488
  return new Promise((r) => setTimeout(r, ms));
22489
22489
  }
22490
22490
  function generateOptionToken() {
@@ -30085,7 +30085,7 @@ var StdioServerTransport = class {
30085
30085
 
30086
30086
  // src/telegram-channel.ts
30087
30087
  import https from "https";
30088
- import { createHash as createHash2, randomUUID as randomUUID3 } from "crypto";
30088
+ import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
30089
30089
  import {
30090
30090
  closeSync,
30091
30091
  createWriteStream,
@@ -30093,18 +30093,18 @@ import {
30093
30093
  ftruncateSync,
30094
30094
  mkdirSync as mkdirSync9,
30095
30095
  openSync,
30096
- readFileSync as readFileSync15,
30097
- readdirSync as readdirSync4,
30096
+ readFileSync as readFileSync16,
30097
+ readdirSync as readdirSync5,
30098
30098
  realpathSync,
30099
30099
  renameSync as renameSync7,
30100
- statSync as statSync3,
30100
+ statSync as statSync4,
30101
30101
  unlinkSync as unlinkSync8,
30102
30102
  watch,
30103
30103
  writeFileSync as writeFileSync11,
30104
30104
  writeSync
30105
30105
  } from "fs";
30106
- import { homedir as homedir6 } from "os";
30107
- import { basename, extname, join as join15, resolve as resolve2 } from "path";
30106
+ import { homedir as homedir7 } from "os";
30107
+ import { basename, extname, join as join16, resolve as resolve2 } from "path";
30108
30108
 
30109
30109
  // src/channel-attachments.ts
30110
30110
  import { homedir } from "os";
@@ -30695,6 +30695,40 @@ function resolveGhostReplyMode(opts) {
30695
30695
  if (cached2 !== void 0) return cached2;
30696
30696
  return "off";
30697
30697
  }
30698
+ var USAGE_LIMIT_REACTIVE_FLAG_KEY = "usage-limit-reactive-notice";
30699
+ function parseUsageLimitReactiveMode(raw) {
30700
+ if (raw === void 0) return void 0;
30701
+ const v = raw.trim().toLowerCase();
30702
+ if (v === "") return void 0;
30703
+ if (v === "off" || v === "shadow" || v === "enforce") return v;
30704
+ const b = envBoolean(raw);
30705
+ if (b === true) return "enforce";
30706
+ if (b === false) return "off";
30707
+ return void 0;
30708
+ }
30709
+ function cachedUsageLimitReactiveMode(path) {
30710
+ try {
30711
+ if (!existsSync2(path)) return void 0;
30712
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
30713
+ if (!parsed || typeof parsed !== "object") return void 0;
30714
+ const flags = parsed.flags;
30715
+ if (!flags || typeof flags !== "object") return void 0;
30716
+ const value = flags[USAGE_LIMIT_REACTIVE_FLAG_KEY];
30717
+ if (typeof value === "string") return parseUsageLimitReactiveMode(value);
30718
+ if (typeof value === "boolean") return value ? "enforce" : "off";
30719
+ return void 0;
30720
+ } catch {
30721
+ return void 0;
30722
+ }
30723
+ }
30724
+ function resolveUsageLimitReactiveMode(opts) {
30725
+ const env2 = opts?.env ?? process.env;
30726
+ const modeOverride = parseUsageLimitReactiveMode(env2["AGT_USAGE_LIMIT_REACTIVE_MODE"]);
30727
+ if (modeOverride !== void 0) return modeOverride;
30728
+ const cached2 = cachedUsageLimitReactiveMode(opts?.cachePath ?? defaultFlagsCachePath());
30729
+ if (cached2 !== void 0) return cached2;
30730
+ return "off";
30731
+ }
30698
30732
 
30699
30733
  // src/maintenance-mode.ts
30700
30734
  var FLAG_KEY = "platform-maintenance-mode";
@@ -34036,7 +34070,113 @@ var BANNER_PATTERNS = [
34036
34070
  // pct=100.
34037
34071
  new RegExp(`${SUBJECT}hit\\s+your\\s+(?:[a-z0-9-]+\\s+)?limit${SEP}resets\\s+(${RESET_DATE})`, "i")
34038
34072
  ];
34073
+ function parseUsageBanner(text, now = /* @__PURE__ */ new Date()) {
34074
+ let bestIndex = -1;
34075
+ let best = null;
34076
+ for (let i = 0; i < BANNER_PATTERNS.length; i++) {
34077
+ const pattern = new RegExp(BANNER_PATTERNS[i].source, "gi");
34078
+ let match;
34079
+ while ((match = pattern.exec(text)) !== null) {
34080
+ if (match.index === pattern.lastIndex)
34081
+ pattern.lastIndex++;
34082
+ let pct;
34083
+ let resetStr;
34084
+ if (i === 0) {
34085
+ pct = Number.parseInt(match[1], 10);
34086
+ resetStr = match[2];
34087
+ } else {
34088
+ pct = 100;
34089
+ resetStr = match[1];
34090
+ }
34091
+ if (!Number.isFinite(pct) || pct < 0 || pct > 100)
34092
+ continue;
34093
+ const nextChar = text[match.index + match[0].length];
34094
+ if (nextChar !== void 0 && /[A-Za-z0-9]/.test(nextChar))
34095
+ continue;
34096
+ const weekResetsAt = parseResetDateTime(resetStr, now);
34097
+ if (!weekResetsAt)
34098
+ continue;
34099
+ if (match.index >= bestIndex) {
34100
+ bestIndex = match.index;
34101
+ best = { pct, weekResetsAt };
34102
+ }
34103
+ }
34104
+ }
34105
+ return best;
34106
+ }
34107
+ var MONTHS = [
34108
+ "jan",
34109
+ "feb",
34110
+ "mar",
34111
+ "apr",
34112
+ "may",
34113
+ "jun",
34114
+ "jul",
34115
+ "aug",
34116
+ "sep",
34117
+ "oct",
34118
+ "nov",
34119
+ "dec"
34120
+ ];
34121
+ var TIME_TAIL = /,\s*(\d{1,2})(?::(\d{2}))?\s*(am|pm)(?:\s*\(?UTC\)?)?\s*$/i;
34122
+ var TIME_ONLY = /^(\d{1,2})(?::(\d{2}))?\s*(am|pm)(?:\s*\(?UTC\)?)?$/i;
34039
34123
  var MS_PER_DAY = 24 * 60 * 60 * 1e3;
34124
+ function parseAmPm(hourStr, minStr, ampm) {
34125
+ const rawHour = Number.parseInt(hourStr, 10);
34126
+ if (!Number.isFinite(rawHour) || rawHour < 1 || rawHour > 12)
34127
+ return null;
34128
+ let minute = 0;
34129
+ if (minStr) {
34130
+ minute = Number.parseInt(minStr, 10);
34131
+ if (!Number.isFinite(minute) || minute < 0 || minute > 59)
34132
+ return null;
34133
+ }
34134
+ const isPm = ampm.toLowerCase() === "pm";
34135
+ return { hour: rawHour % 12 + (isPm ? 12 : 0), minute };
34136
+ }
34137
+ function parseResetDateTime(humanDate, now) {
34138
+ const trimmed = humanDate.trim();
34139
+ const timeOnly = trimmed.match(TIME_ONLY);
34140
+ if (timeOnly) {
34141
+ const hm = parseAmPm(timeOnly[1], timeOnly[2], timeOnly[3]);
34142
+ if (!hm)
34143
+ return null;
34144
+ const todayAt = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), hm.hour, hm.minute);
34145
+ return new Date(todayAt <= now.getTime() ? todayAt + MS_PER_DAY : todayAt);
34146
+ }
34147
+ const timeMatch = trimmed.match(TIME_TAIL);
34148
+ const dateOnly = timeMatch ? trimmed.slice(0, timeMatch.index).trim() : trimmed;
34149
+ const parts = dateOnly.split(/\s+/);
34150
+ if (parts.length !== 2)
34151
+ return null;
34152
+ const month = MONTHS.indexOf(parts[0].slice(0, 3).toLowerCase());
34153
+ if (month < 0)
34154
+ return null;
34155
+ const day = Number.parseInt(parts[1], 10);
34156
+ if (!Number.isFinite(day) || day < 1 || day > 31)
34157
+ return null;
34158
+ let hour = 0;
34159
+ let minute = 0;
34160
+ if (timeMatch) {
34161
+ const hm = parseAmPm(timeMatch[1], timeMatch[2], timeMatch[3]);
34162
+ if (!hm)
34163
+ return null;
34164
+ hour = hm.hour;
34165
+ minute = hm.minute;
34166
+ }
34167
+ const baseYear = now.getUTCFullYear();
34168
+ let resolved = null;
34169
+ let bestDelta = Number.POSITIVE_INFINITY;
34170
+ for (const y of [baseYear - 1, baseYear, baseYear + 1]) {
34171
+ const candidate = new Date(Date.UTC(y, month, day, hour, minute));
34172
+ const delta = Math.abs(candidate.getTime() - now.getTime());
34173
+ if (delta < bestDelta) {
34174
+ bestDelta = delta;
34175
+ resolved = candidate;
34176
+ }
34177
+ }
34178
+ return resolved;
34179
+ }
34040
34180
 
34041
34181
  // ../core/dist/claude-code-usage/usage-limit-marker.js
34042
34182
  var USAGE_LIMIT_MARKER_FILENAME = "claude-usage-limit.json";
@@ -34081,6 +34221,101 @@ var UNKNOWN_RATE_LIMIT = Object.freeze({
34081
34221
  resetsAt: null,
34082
34222
  text: null
34083
34223
  });
34224
+ function contentText(record2) {
34225
+ const candidates = [record2.content];
34226
+ const message = record2.message;
34227
+ if (typeof message === "object" && message !== null) {
34228
+ candidates.push(message.content);
34229
+ }
34230
+ const parts = [];
34231
+ for (const candidate of candidates) {
34232
+ if (typeof candidate === "string") {
34233
+ if (candidate)
34234
+ parts.push(candidate);
34235
+ continue;
34236
+ }
34237
+ if (!Array.isArray(candidate))
34238
+ continue;
34239
+ for (const block of candidate) {
34240
+ if (typeof block === "string") {
34241
+ if (block)
34242
+ parts.push(block);
34243
+ continue;
34244
+ }
34245
+ if (typeof block !== "object" || block === null)
34246
+ continue;
34247
+ const text = block.text;
34248
+ if (typeof text === "string" && text)
34249
+ parts.push(text);
34250
+ }
34251
+ }
34252
+ const joined = parts.join("\n").trim();
34253
+ return joined ? joined : null;
34254
+ }
34255
+ function classifyTranscriptLine(line, startMs, endMs, now) {
34256
+ const trimmed = line.trim();
34257
+ if (!trimmed)
34258
+ return null;
34259
+ let obj;
34260
+ try {
34261
+ obj = JSON.parse(trimmed);
34262
+ } catch {
34263
+ return null;
34264
+ }
34265
+ if (typeof obj !== "object" || obj === null)
34266
+ return null;
34267
+ const record2 = obj;
34268
+ if (record2.type !== "assistant")
34269
+ return null;
34270
+ const ts = record2.timestamp;
34271
+ if (typeof ts !== "string" || !ts)
34272
+ return null;
34273
+ const tsMs = new Date(ts).getTime();
34274
+ if (!Number.isFinite(tsMs) || tsMs < startMs || tsMs > endMs)
34275
+ return null;
34276
+ if (record2.error === "rate_limit" || record2.apiErrorStatus === 429) {
34277
+ const text = contentText(record2);
34278
+ const observation = text ? parseUsageBanner(text, now ?? new Date(endMs)) : null;
34279
+ return { verdict: "capped", atMs: tsMs, resetsAt: observation?.weekResetsAt ?? null, text };
34280
+ }
34281
+ if (record2.isApiErrorMessage === true)
34282
+ return null;
34283
+ const message = record2.message;
34284
+ if (typeof message !== "object" || message === null)
34285
+ return null;
34286
+ const msg = message;
34287
+ if (msg.model === "<synthetic>")
34288
+ return null;
34289
+ const usage = msg.usage;
34290
+ if (typeof usage !== "object" || usage === null)
34291
+ return null;
34292
+ const u = usage;
34293
+ 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);
34294
+ if (!Number.isFinite(spent) || spent <= 0)
34295
+ return null;
34296
+ return { verdict: "serving", atMs: tsMs, resetsAt: null, text: null };
34297
+ }
34298
+ function pickNewerClassification(current, next) {
34299
+ if (next.verdict === "unknown")
34300
+ return current;
34301
+ if (current.verdict === "unknown")
34302
+ return next;
34303
+ return next.atMs >= current.atMs ? next : current;
34304
+ }
34305
+ function classifyTranscriptRateLimit(jsonl, startMs, endMs, now) {
34306
+ let newest = UNKNOWN_RATE_LIMIT;
34307
+ for (const line of jsonl.split("\n")) {
34308
+ const classified = classifyTranscriptLine(line, startMs, endMs, now);
34309
+ if (classified)
34310
+ newest = pickNewerClassification(newest, classified);
34311
+ }
34312
+ return newest;
34313
+ }
34314
+
34315
+ // ../core/dist/claude-code-usage/transcript-location.js
34316
+ function encodeClaudeProjectPath(projectDir) {
34317
+ return "-" + projectDir.replace(/^\//, "").replace(/[/.]/g, "-");
34318
+ }
34084
34319
 
34085
34320
  // ../core/dist/account-enforcement/marker.js
34086
34321
  var ACCOUNT_ENFORCEMENT_MARKER_FILENAME = "account-enforcement.json";
@@ -37099,11 +37334,102 @@ function emitToolCallMarkupRedactionTelemetry(channel) {
37099
37334
  }
37100
37335
  }
37101
37336
 
37337
+ // src/rate-limit-watch.ts
37338
+ import { readFileSync as readFileSync11, readdirSync, statSync } from "fs";
37339
+ import { homedir as homedir5 } from "os";
37340
+ import { join as join9 } from "path";
37341
+ var DEFAULT_WATCH_MS = 5e3;
37342
+ var DEFAULT_POLL_MS = 400;
37343
+ function agentTranscriptDir(opts) {
37344
+ const cwd = opts?.cwd ?? process.cwd();
37345
+ const home = opts?.home ?? homedir5();
37346
+ return join9(home, ".claude", "projects", encodeClaudeProjectPath(cwd));
37347
+ }
37348
+ function classifyTranscriptSince(opts) {
37349
+ const dir = opts.transcriptDir ?? agentTranscriptDir({ cwd: opts.cwd, home: opts.home });
37350
+ let entries;
37351
+ try {
37352
+ entries = readdirSync(dir);
37353
+ } catch {
37354
+ return UNKNOWN_RATE_LIMIT;
37355
+ }
37356
+ let newest = UNKNOWN_RATE_LIMIT;
37357
+ for (const name of entries) {
37358
+ if (!name.endsWith(".jsonl")) continue;
37359
+ const path = join9(dir, name);
37360
+ try {
37361
+ const st = statSync(path);
37362
+ if (!st.isFile() || st.mtimeMs < opts.sinceMs) continue;
37363
+ } catch {
37364
+ continue;
37365
+ }
37366
+ let content;
37367
+ try {
37368
+ content = readFileSync11(path, "utf-8");
37369
+ } catch {
37370
+ continue;
37371
+ }
37372
+ newest = pickNewerClassification(
37373
+ newest,
37374
+ classifyTranscriptRateLimit(content, opts.sinceMs, opts.nowMs, new Date(opts.nowMs))
37375
+ );
37376
+ }
37377
+ return newest;
37378
+ }
37379
+ var sleep = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
37380
+ async function watchForRateLimitRefusal(opts) {
37381
+ const now = opts.now ?? (() => Date.now());
37382
+ const wait = opts.wait ?? sleep;
37383
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_WATCH_MS;
37384
+ const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;
37385
+ const deadline = now() + timeoutMs;
37386
+ for (; ; ) {
37387
+ let result;
37388
+ try {
37389
+ result = classifyTranscriptSince({
37390
+ sinceMs: opts.sinceMs,
37391
+ nowMs: now(),
37392
+ transcriptDir: opts.transcriptDir,
37393
+ cwd: opts.cwd,
37394
+ home: opts.home
37395
+ });
37396
+ } catch {
37397
+ return null;
37398
+ }
37399
+ if (result.verdict === "capped") return result;
37400
+ if (result.verdict === "serving") return null;
37401
+ if (now() >= deadline) return null;
37402
+ await wait(pollMs);
37403
+ }
37404
+ }
37405
+
37406
+ // src/usage-limit-reactive-decision.ts
37407
+ import { createHash } from "crypto";
37408
+ function shouldReadPredictiveMarker(mode) {
37409
+ return mode !== "enforce";
37410
+ }
37411
+ function armedWatchMode(opts) {
37412
+ if (opts.mode === "off") return null;
37413
+ if (opts.isBot || !opts.replyOwed) return null;
37414
+ return opts.mode;
37415
+ }
37416
+ function decideRefusalAction(opts) {
37417
+ const { refusal } = opts;
37418
+ if (!refusal || refusal.verdict !== "capped") return "none";
37419
+ if (!refusal.resetsAt) return "missing-reset";
37420
+ return opts.mode === "shadow" ? "shadow-log" : "notify";
37421
+ }
37422
+ function describeUnparsedRefusal(text) {
37423
+ if (!text) return "refusal=absent";
37424
+ const hash = createHash("sha256").update(text).digest("hex").slice(0, 12);
37425
+ return `refusal_hash=${hash} refusal_len=${text.length}`;
37426
+ }
37427
+
37102
37428
  // src/reply-intent-runtime.ts
37103
37429
  import { execFile as execFile2 } from "child_process";
37104
37430
  import { existsSync as existsSync5, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
37105
- import { homedir as homedir5 } from "os";
37106
- import { join as join9 } from "path";
37431
+ import { homedir as homedir6 } from "os";
37432
+ import { join as join10 } from "path";
37107
37433
  var DEFAULT_CLAUDE_EVAL_MODEL = "claude-haiku-4-5-20251001";
37108
37434
  var DEFAULT_ANTHROPIC_MESSAGES_URL = "https://api.anthropic.com/v1/messages";
37109
37435
  var ANTHROPIC_API_VERSION = "2023-06-01";
@@ -37202,12 +37528,12 @@ async function runAnthropicMessages(prompt, opts) {
37202
37528
  var emptyMcpConfigPath = null;
37203
37529
  function ensureEmptyMcpConfig() {
37204
37530
  if (emptyMcpConfigPath && existsSync5(emptyMcpConfigPath)) return emptyMcpConfigPath;
37205
- const dir = join9(homedir5(), ".augmented");
37531
+ const dir = join10(homedir6(), ".augmented");
37206
37532
  try {
37207
37533
  mkdirSync6(dir, { recursive: true });
37208
37534
  } catch {
37209
37535
  }
37210
- const p2 = join9(dir, ".reply-intent-empty-mcp.json");
37536
+ const p2 = join10(dir, ".reply-intent-empty-mcp.json");
37211
37537
  writeFileSync7(p2, JSON.stringify({ mcpServers: {} }));
37212
37538
  emptyMcpConfigPath = p2;
37213
37539
  return p2;
@@ -37232,7 +37558,7 @@ function runClaudeP(prompt, model) {
37232
37558
  execFile2(
37233
37559
  "claude",
37234
37560
  args,
37235
- { cwd: homedir5(), timeout: CLASSIFY_TIMEOUT_MS, maxBuffer: 1 << 20 },
37561
+ { cwd: homedir6(), timeout: CLASSIFY_TIMEOUT_MS, maxBuffer: 1 << 20 },
37236
37562
  (err, stdout) => {
37237
37563
  if (err) {
37238
37564
  reject(err);
@@ -37354,17 +37680,17 @@ function emitTransientApiErrorTelemetry(channel, match, original) {
37354
37680
  }
37355
37681
 
37356
37682
  // src/telegram-pending-inbound-cleanup.ts
37357
- import { readdirSync, readFileSync as readFileSync11, statSync } from "fs";
37358
- import { join as join10 } from "path";
37683
+ import { readdirSync as readdirSync2, readFileSync as readFileSync12, statSync as statSync2 } from "fs";
37684
+ import { join as join11 } from "path";
37359
37685
  function markerArrivalMs(fullPath) {
37360
37686
  try {
37361
- const received = JSON.parse(readFileSync11(fullPath, "utf-8")).received_at;
37687
+ const received = JSON.parse(readFileSync12(fullPath, "utf-8")).received_at;
37362
37688
  const parsed = received ? Date.parse(received) : Number.NaN;
37363
37689
  if (Number.isFinite(parsed)) return parsed;
37364
37690
  } catch {
37365
37691
  }
37366
37692
  try {
37367
- return statSync(fullPath).mtimeMs;
37693
+ return statSync2(fullPath).mtimeMs;
37368
37694
  } catch {
37369
37695
  return Number.POSITIVE_INFINITY;
37370
37696
  }
@@ -37380,7 +37706,7 @@ function applyToChatMarkers(pendingDir, chatId, op, cutoffMs) {
37380
37706
  const bounded = Number.isFinite(cutoffMs);
37381
37707
  let filenames;
37382
37708
  try {
37383
- filenames = readdirSync(pendingDir);
37709
+ filenames = readdirSync2(pendingDir);
37384
37710
  } catch {
37385
37711
  return 0;
37386
37712
  }
@@ -37388,7 +37714,7 @@ function applyToChatMarkers(pendingDir, chatId, op, cutoffMs) {
37388
37714
  for (const filename of filenames) {
37389
37715
  if (!filename.startsWith(prefix)) continue;
37390
37716
  if (!filename.endsWith(".json")) continue;
37391
- const fullPath = join10(pendingDir, filename);
37717
+ const fullPath = join11(pendingDir, filename);
37392
37718
  if (bounded && markerArrivalMs(fullPath) > cutoffMs) continue;
37393
37719
  op(fullPath);
37394
37720
  applied++;
@@ -37398,12 +37724,12 @@ function applyToChatMarkers(pendingDir, chatId, op, cutoffMs) {
37398
37724
 
37399
37725
  // src/recovery-ledger.ts
37400
37726
  import { existsSync as existsSync6, unlinkSync as unlinkSync6 } from "fs";
37401
- import { join as join11 } from "path";
37727
+ import { join as join12 } from "path";
37402
37728
  function recoveryLedgerEntryExists(ledgerDir, markerName, exists = (p2) => existsSync6(p2)) {
37403
37729
  if (!ledgerDir || !markerName) return false;
37404
37730
  if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return false;
37405
37731
  try {
37406
- return exists(join11(ledgerDir, markerName));
37732
+ return exists(join12(ledgerDir, markerName));
37407
37733
  } catch {
37408
37734
  return false;
37409
37735
  }
@@ -37414,14 +37740,14 @@ function removeRecoveryLedgerEntry(ledgerDir, markerName, unlink = (p2) => {
37414
37740
  if (!ledgerDir || !markerName) return;
37415
37741
  if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return;
37416
37742
  try {
37417
- unlink(join11(ledgerDir, markerName));
37743
+ unlink(join12(ledgerDir, markerName));
37418
37744
  } catch {
37419
37745
  }
37420
37746
  }
37421
37747
 
37422
37748
  // src/inbound-delivery-ledger.ts
37423
- import { existsSync as existsSync7, mkdirSync as mkdirSync7, readdirSync as readdirSync2, readFileSync as readFileSync12, renameSync as renameSync5, writeFileSync as writeFileSync8 } from "fs";
37424
- import { join as join12 } from "path";
37749
+ import { existsSync as existsSync7, mkdirSync as mkdirSync7, readdirSync as readdirSync3, readFileSync as readFileSync13, renameSync as renameSync5, writeFileSync as writeFileSync8 } from "fs";
37750
+ import { join as join13 } from "path";
37425
37751
  function safeInboundId(inboundId) {
37426
37752
  return inboundId.replace(/[^A-Za-z0-9_-]/g, "_");
37427
37753
  }
@@ -37429,8 +37755,8 @@ var defaultDeps = {
37429
37755
  mkdir: (dir) => mkdirSync7(dir, { recursive: true }),
37430
37756
  writeFile: (path, data) => writeFileSync8(path, data, "utf8"),
37431
37757
  rename: (from, to) => renameSync5(from, to),
37432
- readdir: (dir) => readdirSync2(dir),
37433
- readFile: (path) => readFileSync12(path, "utf8"),
37758
+ readdir: (dir) => readdirSync3(dir),
37759
+ readFile: (path) => readFileSync13(path, "utf8"),
37434
37760
  exists: (path) => existsSync7(path)
37435
37761
  };
37436
37762
  function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
@@ -37439,7 +37765,7 @@ function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
37439
37765
  if (!safe || safe.includes("/") || safe.includes("\\") || safe.includes("..")) return;
37440
37766
  try {
37441
37767
  deps.mkdir(dir);
37442
- const final = join12(dir, `${safe}.json`);
37768
+ const final = join13(dir, `${safe}.json`);
37443
37769
  const tmp = `${final}.tmp`;
37444
37770
  deps.writeFile(tmp, JSON.stringify(record2));
37445
37771
  deps.rename(tmp, final);
@@ -37448,10 +37774,10 @@ function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
37448
37774
  }
37449
37775
 
37450
37776
  // src/channel-inbound-id.ts
37451
- import { createHash } from "crypto";
37777
+ import { createHash as createHash2 } from "crypto";
37452
37778
  var INBOUND_ID_HEX_LEN = 12;
37453
37779
  function hashInboundId(payload) {
37454
- const digest = createHash("sha256").update(payload).digest("hex").slice(0, INBOUND_ID_HEX_LEN);
37780
+ const digest = createHash2("sha256").update(payload).digest("hex").slice(0, INBOUND_ID_HEX_LEN);
37455
37781
  return `ib_${digest}`;
37456
37782
  }
37457
37783
  function telegramInboundId(chatId, messageId) {
@@ -37644,14 +37970,14 @@ function createKanbanCardActiveClient(args) {
37644
37970
  import {
37645
37971
  existsSync as existsSync8,
37646
37972
  mkdirSync as mkdirSync8,
37647
- readFileSync as readFileSync13,
37973
+ readFileSync as readFileSync14,
37648
37974
  renameSync as renameSync6,
37649
- statSync as statSync2,
37975
+ statSync as statSync3,
37650
37976
  unlinkSync as unlinkSync7,
37651
37977
  utimesSync,
37652
37978
  writeFileSync as writeFileSync9
37653
37979
  } from "fs";
37654
- import { join as join13 } from "path";
37980
+ import { join as join14 } from "path";
37655
37981
  var STALE_LOCK_MS = 9e4;
37656
37982
  var HEARTBEAT_INTERVAL_MS = 3e4;
37657
37983
  function defaultIsPidAlive(pid) {
@@ -37674,7 +38000,7 @@ function acquireMcpSpawnLock(args) {
37674
38000
  const nowMs = options.nowMs ?? (() => Date.now());
37675
38001
  const lockMtimeMs = options.lockMtimeMs ?? defaultLockMtimeMs;
37676
38002
  const staleMs = options.staleMs ?? STALE_LOCK_MS;
37677
- const path = join13(agentDir, basename2);
38003
+ const path = join14(agentDir, basename2);
37678
38004
  const existing = readLockHolder(path);
37679
38005
  if (existing) {
37680
38006
  if (existing.pid === selfPid) {
@@ -37733,7 +38059,7 @@ function startMcpSpawnLockHeartbeat(lockPath, opts = {}) {
37733
38059
  }
37734
38060
  function defaultLockMtimeMs(path) {
37735
38061
  try {
37736
- return statSync2(path).mtimeMs;
38062
+ return statSync3(path).mtimeMs;
37737
38063
  } catch {
37738
38064
  return null;
37739
38065
  }
@@ -37741,7 +38067,7 @@ function defaultLockMtimeMs(path) {
37741
38067
  function readLockHolder(path) {
37742
38068
  if (!existsSync8(path)) return null;
37743
38069
  try {
37744
- const raw = readFileSync13(path, "utf8");
38070
+ const raw = readFileSync14(path, "utf8");
37745
38071
  const parsed = JSON.parse(raw);
37746
38072
  const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
37747
38073
  if (!Number.isFinite(pid) || pid <= 0) return null;
@@ -37753,8 +38079,8 @@ function readLockHolder(path) {
37753
38079
  }
37754
38080
 
37755
38081
  // src/ack-reaction.ts
37756
- import { readdirSync as readdirSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "fs";
37757
- import { join as join14 } from "path";
38082
+ import { readdirSync as readdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync10 } from "fs";
38083
+ import { join as join15 } from "path";
37758
38084
  var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
37759
38085
  var ACK_STARTUP_GRACE_MS = 6e4;
37760
38086
  var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
@@ -37827,7 +38153,7 @@ var GIVE_UP_SIGNAL_MAX_AGE_MS = 30 * 60 * 1e3;
37827
38153
  function readGiveUpSignal(path, now = Date.now()) {
37828
38154
  if (!path) return null;
37829
38155
  try {
37830
- const raw = JSON.parse(readFileSync14(path, "utf8"));
38156
+ const raw = JSON.parse(readFileSync15(path, "utf8"));
37831
38157
  if (typeof raw.gave_up_at !== "string") return null;
37832
38158
  const t = Date.parse(raw.gave_up_at);
37833
38159
  if (!Number.isFinite(t) || t > now) return null;
@@ -37853,7 +38179,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now(), opts) {
37853
38179
  if (!dir) return null;
37854
38180
  let names;
37855
38181
  try {
37856
- names = readdirSync3(dir);
38182
+ names = readdirSync4(dir);
37857
38183
  } catch {
37858
38184
  return null;
37859
38185
  }
@@ -37862,7 +38188,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now(), opts) {
37862
38188
  if (!name.endsWith(".json")) continue;
37863
38189
  let receivedAt;
37864
38190
  try {
37865
- const raw = JSON.parse(readFileSync14(join14(dir, name), "utf-8"));
38191
+ const raw = JSON.parse(readFileSync15(join15(dir, name), "utf-8"));
37866
38192
  if (raw.discretionary === true) continue;
37867
38193
  if (!opts?.includeSeen && typeof raw.seen_at === "string" && raw.seen_at) continue;
37868
38194
  receivedAt = raw.received_at;
@@ -37939,14 +38265,14 @@ function isMarkerGenuinelyAged(receivedAt, nowMs, thresholdMs) {
37939
38265
  }
37940
38266
  var DEFLECTION_COUNTER_SUFFIX = "-deflections.json";
37941
38267
  function deflectionCounterPath(agentDir, channel) {
37942
- return join14(agentDir, `${channel}${DEFLECTION_COUNTER_SUFFIX}`);
38268
+ return join15(agentDir, `${channel}${DEFLECTION_COUNTER_SUFFIX}`);
37943
38269
  }
37944
38270
  function recordChannelDeflection(agentDir, channel, cause) {
37945
38271
  if (!agentDir) return;
37946
38272
  const path = deflectionCounterPath(agentDir, channel);
37947
38273
  let counts = {};
37948
38274
  try {
37949
- const parsed = JSON.parse(readFileSync14(path, "utf-8"));
38275
+ const parsed = JSON.parse(readFileSync15(path, "utf-8"));
37950
38276
  if (parsed && typeof parsed === "object") counts = parsed;
37951
38277
  } catch {
37952
38278
  }
@@ -38023,11 +38349,11 @@ async function actuateHostRestart(opts) {
38023
38349
 
38024
38350
  // src/telegram-channel.ts
38025
38351
  function redactId(id) {
38026
- return createHash2("sha256").update(String(id)).digest("hex").slice(0, 8);
38352
+ return createHash3("sha256").update(String(id)).digest("hex").slice(0, 8);
38027
38353
  }
38028
38354
  var BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
38029
38355
  var AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME ?? "unknown";
38030
- var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join15(homedir6(), ".augmented", AGENT_CODE_NAME) : null;
38356
+ var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join16(homedir7(), ".augmented", AGENT_CODE_NAME) : null;
38031
38357
  var AGT_HOST = process.env.AGT_HOST ?? null;
38032
38358
  var AGT_API_KEY = process.env.AGT_API_KEY ?? null;
38033
38359
  var AGT_AGENT_ID = process.env.AGT_AGENT_ID ?? null;
@@ -38130,11 +38456,11 @@ var peerRateLimiter = peerRateApiClient && parsePeerAgentModeEnv(process.env.TEL
38130
38456
  log: (line) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${line}
38131
38457
  `)
38132
38458
  }) : createPeerRateLimiter();
38133
- var PEER_PRESENCE_STATE_FILE = TELEGRAM_AGENT_DIR ? join15(TELEGRAM_AGENT_DIR, "telegram-peer-presence.json") : null;
38459
+ var PEER_PRESENCE_STATE_FILE = TELEGRAM_AGENT_DIR ? join16(TELEGRAM_AGENT_DIR, "telegram-peer-presence.json") : null;
38134
38460
  function readPeerPresenceState() {
38135
38461
  if (!PEER_PRESENCE_STATE_FILE) return null;
38136
38462
  try {
38137
- const parsed = JSON.parse(readFileSync15(PEER_PRESENCE_STATE_FILE, "utf-8"));
38463
+ const parsed = JSON.parse(readFileSync16(PEER_PRESENCE_STATE_FILE, "utf-8"));
38138
38464
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
38139
38465
  return parsed;
38140
38466
  } catch {
@@ -38169,9 +38495,9 @@ if (!BOT_TOKEN) {
38169
38495
  var stderrLogStream = null;
38170
38496
  if (AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown") {
38171
38497
  try {
38172
- const logDir = join15(homedir6(), ".augmented", AGENT_CODE_NAME);
38498
+ const logDir = join16(homedir7(), ".augmented", AGENT_CODE_NAME);
38173
38499
  mkdirSync9(logDir, { recursive: true });
38174
- stderrLogStream = createWriteStream(join15(logDir, "telegram-channel-stderr.log"), {
38500
+ stderrLogStream = createWriteStream(join16(logDir, "telegram-channel-stderr.log"), {
38175
38501
  flags: "a",
38176
38502
  mode: 384
38177
38503
  });
@@ -38356,6 +38682,47 @@ async function maybeSendTelegramUsageLimitNotice(args) {
38356
38682
  );
38357
38683
  }
38358
38684
  }
38685
+ function armTelegramUsageLimitWatch(args) {
38686
+ void (async () => {
38687
+ try {
38688
+ const refusal = await watchForRateLimitRefusal({ sinceMs: args.sinceMs });
38689
+ const action = decideRefusalAction({ mode: args.mode, refusal });
38690
+ if (action === "none") return;
38691
+ if (action === "missing-reset") {
38692
+ process.stderr.write(
38693
+ `telegram-channel(${AGENT_CODE_NAME}): [usage-limit-reactive] mode=${args.mode} refusal detected for chat=${redactId(args.chatId)} but no reset time in it (${describeUnparsedRefusal(refusal?.text)}) - no notice
38694
+ `
38695
+ );
38696
+ return;
38697
+ }
38698
+ const resetsAt = refusal?.resetsAt;
38699
+ if (!resetsAt) return;
38700
+ if (action === "shadow-log") {
38701
+ process.stderr.write(
38702
+ `telegram-channel(${AGENT_CODE_NAME}): [usage-limit-reactive] mode=shadow WOULD notify chat=${redactId(args.chatId)} resets=${resetsAt.toISOString()}
38703
+ `
38704
+ );
38705
+ return;
38706
+ }
38707
+ await maybeSendTelegramUsageLimitNotice({
38708
+ chatId: args.chatId,
38709
+ senderId: args.senderId,
38710
+ ...args.messageThreadId != null ? { messageThreadId: args.messageThreadId } : {},
38711
+ limitedUntil: resetsAt
38712
+ });
38713
+ clearPendingMessage(args.chatId, args.sinceMs);
38714
+ process.stderr.write(
38715
+ `telegram-channel(${AGENT_CODE_NAME}): [usage-limit-reactive] reported refusal for chat=${redactId(args.chatId)} resets=${resetsAt.toISOString()}
38716
+ `
38717
+ );
38718
+ } catch (err) {
38719
+ process.stderr.write(
38720
+ `telegram-channel(${AGENT_CODE_NAME}): [usage-limit-reactive] watch failed for chat=${redactId(args.chatId)}: ${err.message}
38721
+ `
38722
+ );
38723
+ }
38724
+ })();
38725
+ }
38359
38726
  var TELEGRAM_ACCOUNT_MUTE_NOTICE_CACHE = /* @__PURE__ */ new Map();
38360
38727
  async function maybeSendTelegramAccountMuteNotice(args) {
38361
38728
  if (args.senderId === void 0) return;
@@ -38567,7 +38934,7 @@ function scheduleBusyAck(chatId, messageId, arrivedWhileBusy) {
38567
38934
  let paneLogFreshAgeMs = null;
38568
38935
  if (AGENT_DIR) {
38569
38936
  try {
38570
- const paneMtimeMs = statSync3(join15(AGENT_DIR, "pane.log")).mtimeMs;
38937
+ const paneMtimeMs = statSync4(join16(AGENT_DIR, "pane.log")).mtimeMs;
38571
38938
  paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
38572
38939
  } catch {
38573
38940
  }
@@ -38597,7 +38964,7 @@ function scheduleBusyAck(chatId, messageId, arrivedWhileBusy) {
38597
38964
  function __resetBusyAckNoticeThrottle() {
38598
38965
  lastBusyAckNoticeAt.clear();
38599
38966
  }
38600
- var RESTART_FLAGS_DIR = join15(homedir6(), ".augmented", "restart-flags");
38967
+ var RESTART_FLAGS_DIR = join16(homedir7(), ".augmented", "restart-flags");
38601
38968
  function actuateHostRestartTelegram() {
38602
38969
  return actuateHostRestart({
38603
38970
  agtHost: AGT_HOST,
@@ -38982,7 +39349,7 @@ async function handleRestartCommand(opts) {
38982
39349
  if (!existsSync9(RESTART_FLAGS_DIR)) {
38983
39350
  mkdirSync9(RESTART_FLAGS_DIR, { recursive: true });
38984
39351
  }
38985
- const flagPath = join15(RESTART_FLAGS_DIR, `${AGENT_CODE_NAME}.flag`);
39352
+ const flagPath = join16(RESTART_FLAGS_DIR, `${AGENT_CODE_NAME}.flag`);
38986
39353
  const flag = {
38987
39354
  codeName: AGENT_CODE_NAME,
38988
39355
  source: "telegram",
@@ -39388,16 +39755,16 @@ async function classifyRestartCommand(text) {
39388
39755
  if (!ours) return "verification_failed";
39389
39756
  return target === ours ? "act" : "ignore";
39390
39757
  }
39391
- var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join15(homedir6(), ".augmented", AGENT_CODE_NAME) : null;
39392
- var PENDING_INBOUND_DIR = AGENT_DIR ? join15(AGENT_DIR, "telegram-pending-inbound") : null;
39393
- var RECOVERY_OUTBOX_DIR = AGENT_DIR ? join15(AGENT_DIR, "telegram-recovery-outbox") : null;
39394
- var RECOVERY_LEDGER_DIR = AGENT_DIR ? join15(AGENT_DIR, ".agt-telegram-recovery-ledger") : null;
39395
- var DELIVERY_LEDGER_DIR = AGENT_DIR ? join15(AGENT_DIR, ".agt-inbound-delivery-ledger") : null;
39396
- var RESTART_CONFIRM_FILE = AGENT_DIR ? join15(AGENT_DIR, "telegram-restart-confirm.json") : null;
39758
+ var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join16(homedir7(), ".augmented", AGENT_CODE_NAME) : null;
39759
+ var PENDING_INBOUND_DIR = AGENT_DIR ? join16(AGENT_DIR, "telegram-pending-inbound") : null;
39760
+ var RECOVERY_OUTBOX_DIR = AGENT_DIR ? join16(AGENT_DIR, "telegram-recovery-outbox") : null;
39761
+ var RECOVERY_LEDGER_DIR = AGENT_DIR ? join16(AGENT_DIR, ".agt-telegram-recovery-ledger") : null;
39762
+ var DELIVERY_LEDGER_DIR = AGENT_DIR ? join16(AGENT_DIR, ".agt-inbound-delivery-ledger") : null;
39763
+ var RESTART_CONFIRM_FILE = AGENT_DIR ? join16(AGENT_DIR, "telegram-restart-confirm.json") : null;
39397
39764
  var TELEGRAM_PROCESS_BOOT_MS = Date.now();
39398
- var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ? join15(AGENT_DIR, "telegram-recent-dms.json") : null;
39399
- var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ? join15(AGENT_DIR, "telegram-channel-add-restart.json") : null;
39400
- var TELEGRAM_OFFSET_FILE = AGENT_DIR ? join15(AGENT_DIR, "telegram-getupdates-offset.json") : null;
39765
+ var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ? join16(AGENT_DIR, "telegram-recent-dms.json") : null;
39766
+ var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ? join16(AGENT_DIR, "telegram-channel-add-restart.json") : null;
39767
+ var TELEGRAM_OFFSET_FILE = AGENT_DIR ? join16(AGENT_DIR, "telegram-getupdates-offset.json") : null;
39401
39768
  var recentDms = /* @__PURE__ */ new Map();
39402
39769
  var recentDmPersister = TELEGRAM_RECENT_DMS_FILE ? createRecentDmPersister({
39403
39770
  filePath: TELEGRAM_RECENT_DMS_FILE,
@@ -39452,7 +39819,7 @@ function safeMarkerName(chatId, messageId) {
39452
39819
  }
39453
39820
  function pendingInboundPath(chatId, messageId) {
39454
39821
  if (!PENDING_INBOUND_DIR) return null;
39455
- return join15(PENDING_INBOUND_DIR, safeMarkerName(chatId, messageId));
39822
+ return join16(PENDING_INBOUND_DIR, safeMarkerName(chatId, messageId));
39456
39823
  }
39457
39824
  function writePendingInboundMarker(chatId, messageId, chatType, undeliverable = false, payload) {
39458
39825
  const path = pendingInboundPath(chatId, messageId);
@@ -39500,7 +39867,7 @@ function rewriteTelegramMarkerInPlace(path, marker) {
39500
39867
  function clearTelegramMarkerFileWithHeal(fullPath) {
39501
39868
  let marker = null;
39502
39869
  try {
39503
- marker = JSON.parse(readFileSync15(fullPath, "utf-8"));
39870
+ marker = JSON.parse(readFileSync16(fullPath, "utf-8"));
39504
39871
  } catch {
39505
39872
  }
39506
39873
  if (marker && decideRecoveryHeal({
@@ -39517,7 +39884,7 @@ function clearTelegramMarkerFileWithHeal(fullPath) {
39517
39884
  function markTelegramMarkerSeenInPlace(fullPath) {
39518
39885
  let marker;
39519
39886
  try {
39520
- marker = JSON.parse(readFileSync15(fullPath, "utf-8"));
39887
+ marker = JSON.parse(readFileSync16(fullPath, "utf-8"));
39521
39888
  } catch {
39522
39889
  return;
39523
39890
  }
@@ -39529,7 +39896,7 @@ function markTelegramMarkerSeenInPlace(fullPath) {
39529
39896
  function markTelegramMarkerSeenWithHeal(fullPath) {
39530
39897
  let marker = null;
39531
39898
  try {
39532
- marker = JSON.parse(readFileSync15(fullPath, "utf-8"));
39899
+ marker = JSON.parse(readFileSync16(fullPath, "utf-8"));
39533
39900
  } catch {
39534
39901
  return;
39535
39902
  }
@@ -39545,7 +39912,7 @@ function readPendingInboundMarker(chatId, messageId) {
39545
39912
  const path = pendingInboundPath(chatId, messageId);
39546
39913
  if (!path || !existsSync9(path)) return null;
39547
39914
  try {
39548
- return JSON.parse(readFileSync15(path, "utf-8"));
39915
+ return JSON.parse(readFileSync16(path, "utf-8"));
39549
39916
  } catch {
39550
39917
  return null;
39551
39918
  }
@@ -39565,10 +39932,10 @@ function nextRetryName(filename) {
39565
39932
  async function processRecoveryOutboxFile(filename) {
39566
39933
  if (!RECOVERY_OUTBOX_DIR) return;
39567
39934
  if (filename.endsWith(".poison.json") || filename.endsWith(".tmp")) return;
39568
- const fullPath = join15(RECOVERY_OUTBOX_DIR, filename);
39935
+ const fullPath = join16(RECOVERY_OUTBOX_DIR, filename);
39569
39936
  let payload;
39570
39937
  try {
39571
- const raw = readFileSync15(fullPath, "utf-8");
39938
+ const raw = readFileSync16(fullPath, "utf-8");
39572
39939
  payload = JSON.parse(raw);
39573
39940
  } catch (err) {
39574
39941
  process.stderr.write(
@@ -39662,7 +40029,7 @@ async function processRecoveryOutboxFile(filename) {
39662
40029
  const next = nextRetryName(filename);
39663
40030
  if (next) {
39664
40031
  try {
39665
- renameSync7(fullPath, join15(RECOVERY_OUTBOX_DIR, next.next));
40032
+ renameSync7(fullPath, join16(RECOVERY_OUTBOX_DIR, next.next));
39666
40033
  if (next.attempt >= MAX_RECOVERY_ATTEMPTS) {
39667
40034
  process.stderr.write(
39668
40035
  `telegram-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
@@ -39694,7 +40061,7 @@ function scanRecoveryRetries() {
39694
40061
  if (!RECOVERY_OUTBOX_DIR) return;
39695
40062
  let entries;
39696
40063
  try {
39697
- entries = readdirSync4(RECOVERY_OUTBOX_DIR);
40064
+ entries = readdirSync5(RECOVERY_OUTBOX_DIR);
39698
40065
  } catch {
39699
40066
  return;
39700
40067
  }
@@ -39703,7 +40070,7 @@ function scanRecoveryRetries() {
39703
40070
  if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
39704
40071
  let mtimeMs;
39705
40072
  try {
39706
- mtimeMs = statSync3(join15(RECOVERY_OUTBOX_DIR, f)).mtimeMs;
40073
+ mtimeMs = statSync4(join16(RECOVERY_OUTBOX_DIR, f)).mtimeMs;
39707
40074
  } catch {
39708
40075
  continue;
39709
40076
  }
@@ -39724,7 +40091,7 @@ function startRecoveryOutboxWatcher() {
39724
40091
  return;
39725
40092
  }
39726
40093
  try {
39727
- for (const f of readdirSync4(RECOVERY_OUTBOX_DIR)) {
40094
+ for (const f of readdirSync5(RECOVERY_OUTBOX_DIR)) {
39728
40095
  if (isFirstAttemptOutboxFile(f)) void processRecoveryOutboxFile(f);
39729
40096
  }
39730
40097
  } catch {
@@ -39733,7 +40100,7 @@ function startRecoveryOutboxWatcher() {
39733
40100
  const watcher = watch(RECOVERY_OUTBOX_DIR, (event, filename) => {
39734
40101
  if (event !== "rename" || !filename) return;
39735
40102
  if (!isFirstAttemptOutboxFile(filename)) return;
39736
- if (existsSync9(join15(RECOVERY_OUTBOX_DIR, filename))) {
40103
+ if (existsSync9(join16(RECOVERY_OUTBOX_DIR, filename))) {
39737
40104
  void processRecoveryOutboxFile(filename);
39738
40105
  }
39739
40106
  });
@@ -39748,7 +40115,7 @@ function startRecoveryOutboxWatcher() {
39748
40115
  retryTimer.unref?.();
39749
40116
  }
39750
40117
  startRecoveryOutboxWatcher();
39751
- var NOTICE_OUTBOX_DIR = AGENT_DIR ? join15(AGENT_DIR, "telegram-notice-outbox") : null;
40118
+ var NOTICE_OUTBOX_DIR = AGENT_DIR ? join16(AGENT_DIR, "telegram-notice-outbox") : null;
39752
40119
  var NOTICE_MAX_AGE_MS = 9e4;
39753
40120
  var NOTICE_INFLIGHT = /* @__PURE__ */ new Set();
39754
40121
  async function processNoticeOutboxFile(filename) {
@@ -39756,11 +40123,11 @@ async function processNoticeOutboxFile(filename) {
39756
40123
  if (filename.startsWith(".") || filename.endsWith(".tmp") || !filename.endsWith(".json")) return;
39757
40124
  if (NOTICE_INFLIGHT.has(filename)) return;
39758
40125
  NOTICE_INFLIGHT.add(filename);
39759
- const fullPath = join15(NOTICE_OUTBOX_DIR, filename);
40126
+ const fullPath = join16(NOTICE_OUTBOX_DIR, filename);
39760
40127
  try {
39761
40128
  let mtimeMs;
39762
40129
  try {
39763
- mtimeMs = statSync3(fullPath).mtimeMs;
40130
+ mtimeMs = statSync4(fullPath).mtimeMs;
39764
40131
  } catch {
39765
40132
  return;
39766
40133
  }
@@ -39773,7 +40140,7 @@ async function processNoticeOutboxFile(filename) {
39773
40140
  }
39774
40141
  let payload;
39775
40142
  try {
39776
- const parsed = JSON.parse(readFileSync15(fullPath, "utf-8"));
40143
+ const parsed = JSON.parse(readFileSync16(fullPath, "utf-8"));
39777
40144
  if (!parsed || typeof parsed !== "object") throw new Error("not an object");
39778
40145
  payload = parsed;
39779
40146
  } catch {
@@ -39844,13 +40211,13 @@ function startNoticeOutboxWatcher() {
39844
40211
  return;
39845
40212
  }
39846
40213
  try {
39847
- for (const f of readdirSync4(NOTICE_OUTBOX_DIR)) void processNoticeOutboxFile(f);
40214
+ for (const f of readdirSync5(NOTICE_OUTBOX_DIR)) void processNoticeOutboxFile(f);
39848
40215
  } catch {
39849
40216
  }
39850
40217
  try {
39851
40218
  const watcher = watch(NOTICE_OUTBOX_DIR, (event, filename) => {
39852
40219
  if (event !== "rename" || !filename) return;
39853
- if (existsSync9(join15(NOTICE_OUTBOX_DIR, filename))) void processNoticeOutboxFile(filename);
40220
+ if (existsSync9(join16(NOTICE_OUTBOX_DIR, filename))) void processNoticeOutboxFile(filename);
39854
40221
  });
39855
40222
  watcher.unref?.();
39856
40223
  } catch (err) {
@@ -39870,7 +40237,7 @@ function sweepTelegramStaleMarkers(thresholdMs) {
39870
40237
  if (!existsSync9(PENDING_INBOUND_DIR)) return;
39871
40238
  let filenames;
39872
40239
  try {
39873
- filenames = readdirSync4(PENDING_INBOUND_DIR);
40240
+ filenames = readdirSync5(PENDING_INBOUND_DIR);
39874
40241
  } catch (err) {
39875
40242
  process.stderr.write(
39876
40243
  `telegram-channel(${AGENT_CODE_NAME}): stale-marker readdir failed: ${err.message}
@@ -39884,10 +40251,10 @@ function sweepTelegramStaleMarkers(thresholdMs) {
39884
40251
  for (const filename of filenames) {
39885
40252
  if (!filename.endsWith(".json")) continue;
39886
40253
  if (filename.endsWith(".tmp")) continue;
39887
- const fullPath = join15(PENDING_INBOUND_DIR, filename);
40254
+ const fullPath = join16(PENDING_INBOUND_DIR, filename);
39888
40255
  let marker;
39889
40256
  try {
39890
- marker = JSON.parse(readFileSync15(fullPath, "utf-8"));
40257
+ marker = JSON.parse(readFileSync16(fullPath, "utf-8"));
39891
40258
  } catch (err) {
39892
40259
  process.stderr.write(
39893
40260
  `telegram-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactId(filename)}: ${err.message}
@@ -39940,13 +40307,13 @@ var orphanSweepTimer = setInterval(() => {
39940
40307
  checkWatchdogGiveUpNotice();
39941
40308
  }, orphanSweepIntervalMs());
39942
40309
  orphanSweepTimer.unref?.();
39943
- var TELEGRAM_PROGRESS_HEARTBEAT_PATH = AGENT_DIR ? join15(AGENT_DIR, "channel-progress-heartbeat.json") : null;
40310
+ var TELEGRAM_PROGRESS_HEARTBEAT_PATH = AGENT_DIR ? join16(AGENT_DIR, "channel-progress-heartbeat.json") : null;
39944
40311
  var telegramTrackedProgress = null;
39945
40312
  var telegramProgressTickRunning = false;
39946
40313
  function readTelegramProgressHeartbeat() {
39947
40314
  if (!TELEGRAM_PROGRESS_HEARTBEAT_PATH || !existsSync9(TELEGRAM_PROGRESS_HEARTBEAT_PATH)) return null;
39948
40315
  try {
39949
- return parseProgressHeartbeat(readFileSync15(TELEGRAM_PROGRESS_HEARTBEAT_PATH, "utf-8"));
40316
+ return parseProgressHeartbeat(readFileSync16(TELEGRAM_PROGRESS_HEARTBEAT_PATH, "utf-8"));
39950
40317
  } catch {
39951
40318
  return null;
39952
40319
  }
@@ -39969,11 +40336,11 @@ function findTelegramProgressTarget() {
39969
40336
  let best = null;
39970
40337
  let bestMs = Infinity;
39971
40338
  try {
39972
- for (const name of readdirSync4(PENDING_INBOUND_DIR)) {
40339
+ for (const name of readdirSync5(PENDING_INBOUND_DIR)) {
39973
40340
  if (!name.endsWith(".json")) continue;
39974
40341
  let m;
39975
40342
  try {
39976
- m = JSON.parse(readFileSync15(join15(PENDING_INBOUND_DIR, name), "utf-8"));
40343
+ m = JSON.parse(readFileSync16(join16(PENDING_INBOUND_DIR, name), "utf-8"));
39977
40344
  } catch {
39978
40345
  continue;
39979
40346
  }
@@ -40100,11 +40467,11 @@ function listPendingInboundChatIds() {
40100
40467
  if (!PENDING_INBOUND_DIR || !existsSync9(PENDING_INBOUND_DIR)) return [];
40101
40468
  const chats = /* @__PURE__ */ new Set();
40102
40469
  try {
40103
- for (const name of readdirSync4(PENDING_INBOUND_DIR)) {
40470
+ for (const name of readdirSync5(PENDING_INBOUND_DIR)) {
40104
40471
  if (!name.endsWith(".json")) continue;
40105
40472
  try {
40106
40473
  const marker = JSON.parse(
40107
- readFileSync15(join15(PENDING_INBOUND_DIR, name), "utf8")
40474
+ readFileSync16(join16(PENDING_INBOUND_DIR, name), "utf8")
40108
40475
  );
40109
40476
  if (typeof marker.seen_at === "string" && marker.seen_at) continue;
40110
40477
  if (typeof marker.chat_id === "string" && marker.chat_id) chats.add(marker.chat_id);
@@ -40146,7 +40513,7 @@ async function notifyWatchdogGiveUp(chatId, reason) {
40146
40513
  }
40147
40514
  function checkWatchdogGiveUpNotice() {
40148
40515
  if (!AGENT_DIR) return;
40149
- const signal = readGiveUpSignal(join15(AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
40516
+ const signal = readGiveUpSignal(join16(AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
40150
40517
  const signalAtMs = signal?.atMs ?? null;
40151
40518
  const act = decideGiveUpNotice({
40152
40519
  signalAtMs,
@@ -40425,7 +40792,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
40425
40792
  isError: true
40426
40793
  };
40427
40794
  }
40428
- const allowedRoot = resolve2(homedir6(), ".augmented", AGENT_CODE_NAME, "project") + "/";
40795
+ const allowedRoot = resolve2(homedir7(), ".augmented", AGENT_CODE_NAME, "project") + "/";
40429
40796
  const resolvedPath = resolve2(path);
40430
40797
  if (!resolvedPath.startsWith(allowedRoot)) {
40431
40798
  return {
@@ -40473,7 +40840,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
40473
40840
  }
40474
40841
  let realRoot = allowedRoot;
40475
40842
  try {
40476
- realRoot = realpathSync(resolve2(homedir6(), ".augmented", AGENT_CODE_NAME, "project")) + "/";
40843
+ realRoot = realpathSync(resolve2(homedir7(), ".augmented", AGENT_CODE_NAME, "project")) + "/";
40477
40844
  } catch {
40478
40845
  }
40479
40846
  if (!realPath.startsWith(realRoot)) {
@@ -40488,7 +40855,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
40488
40855
  let bytes;
40489
40856
  let size;
40490
40857
  try {
40491
- const st = statSync3(realPath);
40858
+ const st = statSync4(realPath);
40492
40859
  if (!st.isFile()) {
40493
40860
  return { content: [{ type: "text", text: `Upload refused: ${resolvedPath} is not a regular file.` }], isError: true };
40494
40861
  }
@@ -40502,7 +40869,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
40502
40869
  isError: true
40503
40870
  };
40504
40871
  }
40505
- bytes = readFileSync15(realPath);
40872
+ bytes = readFileSync16(realPath);
40506
40873
  } catch (err) {
40507
40874
  return { content: [{ type: "text", text: `Failed to read file: ${err.message}` }], isError: true };
40508
40875
  }
@@ -41056,7 +41423,7 @@ async function replayPendingTelegramMarkers() {
41056
41423
  if (!sessionAlive) return;
41057
41424
  let filenames;
41058
41425
  try {
41059
- filenames = readdirSync4(PENDING_INBOUND_DIR);
41426
+ filenames = readdirSync5(PENDING_INBOUND_DIR);
41060
41427
  } catch {
41061
41428
  return;
41062
41429
  }
@@ -41064,7 +41431,7 @@ async function replayPendingTelegramMarkers() {
41064
41431
  let paneFreshAgeMs = null;
41065
41432
  if (AGENT_DIR) {
41066
41433
  try {
41067
- paneFreshAgeMs = Math.max(0, now - statSync3(join15(AGENT_DIR, "pane.log")).mtimeMs);
41434
+ paneFreshAgeMs = Math.max(0, now - statSync4(join16(AGENT_DIR, "pane.log")).mtimeMs);
41068
41435
  } catch {
41069
41436
  }
41070
41437
  }
@@ -41072,10 +41439,10 @@ async function replayPendingTelegramMarkers() {
41072
41439
  const entries = [];
41073
41440
  for (const name of filenames) {
41074
41441
  if (!name.endsWith(".json") || name.endsWith(".tmp")) continue;
41075
- const fullPath = join15(PENDING_INBOUND_DIR, name);
41442
+ const fullPath = join16(PENDING_INBOUND_DIR, name);
41076
41443
  let marker;
41077
41444
  try {
41078
- marker = JSON.parse(readFileSync15(fullPath, "utf-8"));
41445
+ marker = JSON.parse(readFileSync16(fullPath, "utf-8"));
41079
41446
  } catch {
41080
41447
  continue;
41081
41448
  }
@@ -41243,7 +41610,7 @@ async function pollLoop() {
41243
41610
  `telegram-channel(${AGENT_CODE_NAME}): getUpdates failed: ${resp.description ?? "unknown"}
41244
41611
  `
41245
41612
  );
41246
- await sleep2(5e3);
41613
+ await sleep3(5e3);
41247
41614
  continue;
41248
41615
  }
41249
41616
  const offsetBeforeBatch = nextOffset;
@@ -41561,7 +41928,8 @@ async function pollLoop() {
41561
41928
  });
41562
41929
  continue;
41563
41930
  }
41564
- const telegramUsageLimitUntil = !isFromBot ? readUsageLimitUntil({ codeName: AGENT_CODE_NAME }) : null;
41931
+ const reactiveMode = resolveUsageLimitReactiveMode();
41932
+ const telegramUsageLimitUntil = !isFromBot && shouldReadPredictiveMarker(reactiveMode) ? readUsageLimitUntil({ codeName: AGENT_CODE_NAME }) : null;
41565
41933
  if (telegramUsageLimitUntil) {
41566
41934
  process.stderr.write(
41567
41935
  `telegram-channel(${AGENT_CODE_NAME}): usage-limit active until ${telegramUsageLimitUntil.toISOString()} \u2014 notice, no dispatch (chat=${redactId(chatId)})
@@ -41625,7 +41993,7 @@ async function pollLoop() {
41625
41993
  let paneLogFreshAgeMs = null;
41626
41994
  if (AGENT_DIR) {
41627
41995
  try {
41628
- const paneMtimeMs = statSync3(join15(AGENT_DIR, "pane.log")).mtimeMs;
41996
+ const paneMtimeMs = statSync4(join16(AGENT_DIR, "pane.log")).mtimeMs;
41629
41997
  paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
41630
41998
  } catch {
41631
41999
  }
@@ -41724,10 +42092,27 @@ async function pollLoop() {
41724
42092
  if (!isFromBot && !peerAgentMeta && userId && userId !== "unknown" && chatId) {
41725
42093
  clearScheduledTurnMarker(TELEGRAM_AGENT_DIR);
41726
42094
  }
42095
+ const dispatchedAtMs = Date.now();
41727
42096
  await mcp.notification({
41728
42097
  method: "notifications/claude/channel",
41729
42098
  params: channelPayload
41730
42099
  });
42100
+ const watchMode = armedWatchMode({
42101
+ mode: reactiveMode,
42102
+ isBot: isFromBot || !!peerAgentMeta,
42103
+ // Every Telegram inbound that reaches here owes a reply — there is no
42104
+ // discretionary auto-follow variant as there is on Slack.
42105
+ replyOwed: true
42106
+ });
42107
+ if (watchMode) {
42108
+ armTelegramUsageLimitWatch({
42109
+ mode: watchMode,
42110
+ chatId,
42111
+ senderId: userId,
42112
+ ...msg.message_thread_id != null ? { messageThreadId: msg.message_thread_id } : {},
42113
+ sinceMs: dispatchedAtMs
42114
+ });
42115
+ }
41731
42116
  seedTelegramProgressHeartbeat();
41732
42117
  conversationIngestClient?.ingest({
41733
42118
  channel: "telegram",
@@ -41773,11 +42158,11 @@ async function pollLoop() {
41773
42158
  `telegram-channel(${AGENT_CODE_NAME}): poll error: ${err.message}
41774
42159
  `
41775
42160
  );
41776
- await sleep2(5e3);
42161
+ await sleep3(5e3);
41777
42162
  }
41778
42163
  }
41779
42164
  }
41780
- function sleep2(ms) {
42165
+ function sleep3(ms) {
41781
42166
  return new Promise((resolve3) => setTimeout(resolve3, ms).unref());
41782
42167
  }
41783
42168
  function shutdown(reason) {