@integrity-labs/agt-cli 0.28.57 → 0.28.58

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.
@@ -14221,6 +14221,156 @@ function clearRestartConfirmMarker(filePath) {
14221
14221
  }
14222
14222
  }
14223
14223
 
14224
+ // src/dm-restart-notice.ts
14225
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
14226
+ import { dirname as dirname2 } from "path";
14227
+ var RECENT_DM_VERSION = 1;
14228
+ var DEFAULT_RECENT_DM_TTL_MS = 30 * 60 * 1e3;
14229
+ var DEFAULT_DM_NOTICE_WINDOW_MS = 5 * 60 * 1e3;
14230
+ var DEFAULT_MIN_INTERVAL_MS = 1e3;
14231
+ function recordDmActivity(map, dmKey, now = /* @__PURE__ */ new Date()) {
14232
+ if (!dmKey) return;
14233
+ map.set(dmKey, { last_activity_at: now.toISOString() });
14234
+ }
14235
+ function recentlyActiveDmKeys(map, now = /* @__PURE__ */ new Date(), windowMs = DEFAULT_DM_NOTICE_WINDOW_MS) {
14236
+ const cutoff = now.getTime() - windowMs;
14237
+ return [...map.entries()].map(([key2, e]) => ({ key: key2, ts: Date.parse(e.last_activity_at) })).filter(({ ts }) => Number.isFinite(ts) && ts >= cutoff).sort((a, b) => b.ts - a.ts).map(({ key: key2 }) => key2);
14238
+ }
14239
+ function serializeRecentDms(map) {
14240
+ const out = { version: RECENT_DM_VERSION, dms: {} };
14241
+ for (const [key2, e] of map) out.dms[key2] = e;
14242
+ return JSON.stringify(out, null, 2);
14243
+ }
14244
+ function loadRecentDms(filePath, opts = {}) {
14245
+ const now = opts.now ?? /* @__PURE__ */ new Date();
14246
+ const ttlMs = opts.ttlMs ?? DEFAULT_RECENT_DM_TTL_MS;
14247
+ let raw;
14248
+ try {
14249
+ raw = readFileSync2(filePath, "utf-8");
14250
+ } catch (err) {
14251
+ const code = err.code;
14252
+ if (code !== "ENOENT") {
14253
+ opts.onError?.(`dm-restart-notice: failed to read recent-DM file: ${err.message}`);
14254
+ }
14255
+ return /* @__PURE__ */ new Map();
14256
+ }
14257
+ let parsed;
14258
+ try {
14259
+ parsed = JSON.parse(raw);
14260
+ } catch (err) {
14261
+ opts.onError?.(`dm-restart-notice: malformed recent-DM JSON (${err.message}) \u2014 ignoring`);
14262
+ return /* @__PURE__ */ new Map();
14263
+ }
14264
+ if (typeof parsed !== "object" || parsed === null || // CodeRabbit: reject unknown versions so a future/legacy on-disk format can't
14265
+ // be read with this version's (possibly incompatible) semantics.
14266
+ parsed.version !== RECENT_DM_VERSION || typeof parsed.dms !== "object" || parsed.dms === null) {
14267
+ opts.onError?.("dm-restart-notice: unexpected recent-DM shape/version \u2014 ignoring");
14268
+ return /* @__PURE__ */ new Map();
14269
+ }
14270
+ const map = /* @__PURE__ */ new Map();
14271
+ const cutoff = now.getTime() - ttlMs;
14272
+ for (const [key2, val] of Object.entries(parsed.dms)) {
14273
+ const at = val?.last_activity_at;
14274
+ if (typeof at !== "string") continue;
14275
+ const ts = Date.parse(at);
14276
+ if (!Number.isFinite(ts) || ts < cutoff) continue;
14277
+ map.set(key2, { last_activity_at: at });
14278
+ }
14279
+ return map;
14280
+ }
14281
+ function createRecentDmPersister(opts) {
14282
+ const interval = opts.minIntervalMs ?? DEFAULT_MIN_INTERVAL_MS;
14283
+ let lastWriteAt = 0;
14284
+ let pendingTimer = null;
14285
+ let pendingSnapshot = null;
14286
+ const writeNow = (snap) => {
14287
+ try {
14288
+ mkdirSync2(dirname2(opts.filePath), { recursive: true });
14289
+ writeFileSync2(opts.filePath, serializeRecentDms(snap), "utf-8");
14290
+ lastWriteAt = Date.now();
14291
+ } catch (err) {
14292
+ opts.onError?.(`dm-restart-notice: failed to persist recent-DMs: ${err.message}`);
14293
+ }
14294
+ };
14295
+ return {
14296
+ schedule(map) {
14297
+ pendingSnapshot = new Map(map);
14298
+ const sinceLast = Date.now() - lastWriteAt;
14299
+ if (sinceLast >= interval) {
14300
+ const snap = pendingSnapshot;
14301
+ pendingSnapshot = null;
14302
+ writeNow(snap);
14303
+ return;
14304
+ }
14305
+ if (pendingTimer) return;
14306
+ pendingTimer = setTimeout(() => {
14307
+ pendingTimer = null;
14308
+ const snap = pendingSnapshot;
14309
+ pendingSnapshot = null;
14310
+ if (snap) writeNow(snap);
14311
+ }, interval - sinceLast);
14312
+ pendingTimer.unref?.();
14313
+ },
14314
+ flush(map) {
14315
+ if (pendingTimer) {
14316
+ clearTimeout(pendingTimer);
14317
+ pendingTimer = null;
14318
+ pendingSnapshot = null;
14319
+ }
14320
+ writeNow(new Map(map));
14321
+ },
14322
+ dispose() {
14323
+ if (pendingTimer) clearTimeout(pendingTimer);
14324
+ pendingTimer = null;
14325
+ pendingSnapshot = null;
14326
+ }
14327
+ };
14328
+ }
14329
+ var CHANNEL_ADD_RESTART_VERSION = 1;
14330
+ var CHANNEL_ADD_RESTART_MAX_AGE_MS = 15 * 60 * 1e3;
14331
+ function readChannelAddRestartMarker(filePath) {
14332
+ let raw;
14333
+ try {
14334
+ raw = readFileSync2(filePath, "utf-8");
14335
+ } catch {
14336
+ return null;
14337
+ }
14338
+ try {
14339
+ const parsed = JSON.parse(raw);
14340
+ if (typeof parsed !== "object" || parsed === null || parsed.version !== CHANNEL_ADD_RESTART_VERSION || typeof parsed.at !== "string") {
14341
+ return null;
14342
+ }
14343
+ const rawAdded = parsed.added;
14344
+ const added = Array.isArray(rawAdded) ? rawAdded.filter((x) => typeof x === "string") : [];
14345
+ return { version: CHANNEL_ADD_RESTART_VERSION, at: parsed.at, added };
14346
+ } catch {
14347
+ return null;
14348
+ }
14349
+ }
14350
+ function shouldPostChannelAddNotice(marker, bootMs, maxAgeMs = CHANNEL_ADD_RESTART_MAX_AGE_MS) {
14351
+ if (!marker) return false;
14352
+ const at = Date.parse(marker.at);
14353
+ if (!Number.isFinite(at)) return false;
14354
+ const age = bootMs - at;
14355
+ return age <= maxAgeMs && age >= -6e4;
14356
+ }
14357
+ function clearChannelAddRestartMarker(filePath) {
14358
+ try {
14359
+ unlinkSync2(filePath);
14360
+ } catch {
14361
+ }
14362
+ }
14363
+ function buildChannelAddNoticeText(added) {
14364
+ const list = added.filter(Boolean);
14365
+ if (list.length === 1) {
14366
+ return `Quick heads-up \u2014 I briefly restarted to bring a new channel (${list[0]}) online. I'm back now; please re-send anything I might have missed.`;
14367
+ }
14368
+ if (list.length > 1) {
14369
+ return `Quick heads-up \u2014 I briefly restarted to bring new channels (${list.join(", ")}) online. I'm back now; please re-send anything I might have missed.`;
14370
+ }
14371
+ return `Quick heads-up \u2014 I briefly restarted to update my configuration. I'm back now; please re-send anything I might have missed.`;
14372
+ }
14373
+
14224
14374
  // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
14225
14375
  import process2 from "process";
14226
14376
 
@@ -14321,15 +14471,15 @@ import {
14321
14471
  createWriteStream,
14322
14472
  existsSync as existsSync5,
14323
14473
  ftruncateSync,
14324
- mkdirSync as mkdirSync4,
14474
+ mkdirSync as mkdirSync5,
14325
14475
  openSync,
14326
- readFileSync as readFileSync7,
14476
+ readFileSync as readFileSync8,
14327
14477
  readdirSync as readdirSync3,
14328
14478
  renameSync as renameSync4,
14329
14479
  statSync as statSync2,
14330
- unlinkSync as unlinkSync4,
14480
+ unlinkSync as unlinkSync5,
14331
14481
  watch,
14332
- writeFileSync as writeFileSync5,
14482
+ writeFileSync as writeFileSync6,
14333
14483
  writeSync
14334
14484
  } from "fs";
14335
14485
  import { homedir as homedir3 } from "os";
@@ -14457,7 +14607,7 @@ function redactAugmentedPaths(msg) {
14457
14607
  }
14458
14608
 
14459
14609
  // src/telegram-attachments.ts
14460
- import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, chmodSync, renameSync as renameSync2, unlinkSync as unlinkSync2 } from "fs";
14610
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, chmodSync, renameSync as renameSync2, unlinkSync as unlinkSync3 } from "fs";
14461
14611
  function resolveTelegramInboundDir(codeName) {
14462
14612
  return resolveChannelInboundDir(codeName, "telegram-inbound");
14463
14613
  }
@@ -14546,10 +14696,10 @@ async function downloadTelegramFile(fileId, opts) {
14546
14696
  if (!isPathInside(savedPath, dir)) {
14547
14697
  throw new Error(`refusing to write ${savedPath} outside ${dir}`);
14548
14698
  }
14549
- mkdirSync2(dir, { recursive: true });
14699
+ mkdirSync3(dir, { recursive: true });
14550
14700
  const tempPath = `${savedPath}.${process.pid}.${Date.now()}.tmp`;
14551
14701
  try {
14552
- writeFileSync2(tempPath, bytes, { mode: 384, flag: "wx" });
14702
+ writeFileSync3(tempPath, bytes, { mode: 384, flag: "wx" });
14553
14703
  try {
14554
14704
  chmodSync(tempPath, 384);
14555
14705
  } catch {
@@ -14557,7 +14707,7 @@ async function downloadTelegramFile(fileId, opts) {
14557
14707
  renameSync2(tempPath, savedPath);
14558
14708
  } catch (err) {
14559
14709
  try {
14560
- unlinkSync2(tempPath);
14710
+ unlinkSync3(tempPath);
14561
14711
  } catch {
14562
14712
  }
14563
14713
  throw err;
@@ -15483,7 +15633,7 @@ function buildCommandRegistrations() {
15483
15633
  }
15484
15634
 
15485
15635
  // src/agent-config-state.ts
15486
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
15636
+ import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
15487
15637
  import { join as join2 } from "path";
15488
15638
  var SESSION_STATE_FILENAME = "session-state.json";
15489
15639
  function readAgentSessionState(stateDir) {
@@ -15491,7 +15641,7 @@ function readAgentSessionState(stateDir) {
15491
15641
  const path = join2(stateDir, SESSION_STATE_FILENAME);
15492
15642
  if (!existsSync2(path)) return null;
15493
15643
  try {
15494
- const parsed = JSON.parse(readFileSync2(path, "utf-8"));
15644
+ const parsed = JSON.parse(readFileSync3(path, "utf-8"));
15495
15645
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
15496
15646
  return parsed;
15497
15647
  } catch {
@@ -16005,11 +16155,11 @@ var TELEGRAM_EGRESS_TOOLS = /* @__PURE__ */ new Set([
16005
16155
  ]);
16006
16156
 
16007
16157
  // src/telegram-pending-inbound-cleanup.ts
16008
- import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
16158
+ import { readdirSync, readFileSync as readFileSync4, statSync } from "fs";
16009
16159
  import { join as join3 } from "path";
16010
16160
  function markerArrivalMs(fullPath) {
16011
16161
  try {
16012
- const received = JSON.parse(readFileSync3(fullPath, "utf-8")).received_at;
16162
+ const received = JSON.parse(readFileSync4(fullPath, "utf-8")).received_at;
16013
16163
  const parsed = received ? Date.parse(received) : Number.NaN;
16014
16164
  if (Number.isFinite(parsed)) return parsed;
16015
16165
  } catch {
@@ -16044,11 +16194,11 @@ function clearAllTelegramPendingMarkersForChat(pendingDir, chatId, clearMarkerFi
16044
16194
  // src/mcp-spawn-lock.ts
16045
16195
  import {
16046
16196
  existsSync as existsSync3,
16047
- mkdirSync as mkdirSync3,
16048
- readFileSync as readFileSync4,
16197
+ mkdirSync as mkdirSync4,
16198
+ readFileSync as readFileSync5,
16049
16199
  renameSync as renameSync3,
16050
- unlinkSync as unlinkSync3,
16051
- writeFileSync as writeFileSync3
16200
+ unlinkSync as unlinkSync4,
16201
+ writeFileSync as writeFileSync4
16052
16202
  } from "fs";
16053
16203
  import { join as join4 } from "path";
16054
16204
  function defaultIsPidAlive(pid) {
@@ -16078,10 +16228,10 @@ function acquireMcpSpawnLock(args) {
16078
16228
  return { kind: "blocked", path, holder: existing };
16079
16229
  }
16080
16230
  }
16081
- mkdirSync3(agentDir, { recursive: true, mode: 448 });
16231
+ mkdirSync4(agentDir, { recursive: true, mode: 448 });
16082
16232
  const tmpPath = `${path}.${selfPid}.tmp`;
16083
16233
  const payload = { pid: selfPid, started_at: now() };
16084
- writeFileSync3(tmpPath, JSON.stringify(payload), { mode: 384 });
16234
+ writeFileSync4(tmpPath, JSON.stringify(payload), { mode: 384 });
16085
16235
  renameSync3(tmpPath, path);
16086
16236
  return { kind: "acquired", path };
16087
16237
  }
@@ -16092,14 +16242,14 @@ function releaseMcpSpawnLock(lockPath, opts = {}) {
16092
16242
  if (!existing) return;
16093
16243
  if (existing.pid !== selfPid) return;
16094
16244
  try {
16095
- unlinkSync3(lockPath);
16245
+ unlinkSync4(lockPath);
16096
16246
  } catch {
16097
16247
  }
16098
16248
  }
16099
16249
  function readLockHolder(path) {
16100
16250
  if (!existsSync3(path)) return null;
16101
16251
  try {
16102
- const raw = readFileSync4(path, "utf8");
16252
+ const raw = readFileSync5(path, "utf8");
16103
16253
  const parsed = JSON.parse(raw);
16104
16254
  const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
16105
16255
  if (!Number.isFinite(pid) || pid <= 0) return null;
@@ -16111,11 +16261,11 @@ function readLockHolder(path) {
16111
16261
  }
16112
16262
 
16113
16263
  // src/ack-reaction.ts
16114
- import { readdirSync as readdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
16264
+ import { readdirSync as readdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
16115
16265
  import { join as join6 } from "path";
16116
16266
 
16117
16267
  // src/flags-cache-read.ts
16118
- import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
16268
+ import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
16119
16269
  import { homedir as homedir2 } from "os";
16120
16270
  import { join as join5 } from "path";
16121
16271
  function defaultFlagsCachePath() {
@@ -16132,7 +16282,7 @@ function envBoolean(raw) {
16132
16282
  function cachedBoolean(key2, path) {
16133
16283
  try {
16134
16284
  if (!existsSync4(path)) return void 0;
16135
- const parsed = JSON.parse(readFileSync5(path, "utf8"));
16285
+ const parsed = JSON.parse(readFileSync6(path, "utf8"));
16136
16286
  if (!parsed || typeof parsed !== "object") return void 0;
16137
16287
  const flags = parsed.flags;
16138
16288
  if (!flags || typeof flags !== "object") return void 0;
@@ -16224,7 +16374,7 @@ var GIVE_UP_SIGNAL_MAX_AGE_MS = 30 * 60 * 1e3;
16224
16374
  function readGiveUpSignalAtMs(path, now = Date.now()) {
16225
16375
  if (!path) return null;
16226
16376
  try {
16227
- const raw = JSON.parse(readFileSync6(path, "utf8"));
16377
+ const raw = JSON.parse(readFileSync7(path, "utf8"));
16228
16378
  if (typeof raw.gave_up_at !== "string") return null;
16229
16379
  const t = Date.parse(raw.gave_up_at);
16230
16380
  if (!Number.isFinite(t) || t > now) return null;
@@ -16256,7 +16406,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now()) {
16256
16406
  if (!name.endsWith(".json")) continue;
16257
16407
  let receivedAt;
16258
16408
  try {
16259
- const raw = JSON.parse(readFileSync6(join6(dir, name), "utf-8"));
16409
+ const raw = JSON.parse(readFileSync7(join6(dir, name), "utf-8"));
16260
16410
  if (raw.discretionary === true) continue;
16261
16411
  receivedAt = raw.received_at;
16262
16412
  } catch {
@@ -16314,13 +16464,13 @@ function recordChannelDeflection(agentDir, channel, cause) {
16314
16464
  const path = deflectionCounterPath(agentDir, channel);
16315
16465
  let counts = {};
16316
16466
  try {
16317
- const parsed = JSON.parse(readFileSync6(path, "utf-8"));
16467
+ const parsed = JSON.parse(readFileSync7(path, "utf-8"));
16318
16468
  if (parsed && typeof parsed === "object") counts = parsed;
16319
16469
  } catch {
16320
16470
  }
16321
16471
  counts[cause] = (counts[cause] ?? 0) + 1;
16322
16472
  try {
16323
- writeFileSync4(path, JSON.stringify(counts), { mode: 384 });
16473
+ writeFileSync5(path, JSON.stringify(counts), { mode: 384 });
16324
16474
  } catch {
16325
16475
  }
16326
16476
  }
@@ -16457,7 +16607,7 @@ var stderrLogStream = null;
16457
16607
  if (AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown") {
16458
16608
  try {
16459
16609
  const logDir = join7(homedir3(), ".augmented", AGENT_CODE_NAME);
16460
- mkdirSync4(logDir, { recursive: true });
16610
+ mkdirSync5(logDir, { recursive: true });
16461
16611
  stderrLogStream = createWriteStream(join7(logDir, "telegram-channel-stderr.log"), {
16462
16612
  flags: "a",
16463
16613
  mode: 384
@@ -16871,7 +17021,7 @@ async function handleStatusCommand(opts) {
16871
17021
  async function handleRestartCommand(opts) {
16872
17022
  try {
16873
17023
  if (!existsSync5(RESTART_FLAGS_DIR)) {
16874
- mkdirSync4(RESTART_FLAGS_DIR, { recursive: true });
17024
+ mkdirSync5(RESTART_FLAGS_DIR, { recursive: true });
16875
17025
  }
16876
17026
  const flagPath = join7(RESTART_FLAGS_DIR, `${AGENT_CODE_NAME}.flag`);
16877
17027
  writeTelegramRestartConfirm(
@@ -16885,7 +17035,7 @@ async function handleRestartCommand(opts) {
16885
17035
  reply: { chat_id: opts.chatId, message_id: opts.messageId }
16886
17036
  };
16887
17037
  const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
16888
- writeFileSync5(tmpPath, JSON.stringify(flag) + "\n", "utf8");
17038
+ writeFileSync6(tmpPath, JSON.stringify(flag) + "\n", "utf8");
16889
17039
  renameSync4(tmpPath, flagPath);
16890
17040
  process.stderr.write(
16891
17041
  `telegram-channel(${AGENT_CODE_NAME}): /restart queued from chat ${redactId(opts.chatId)}
@@ -17261,6 +17411,56 @@ var PENDING_INBOUND_DIR = AGENT_DIR ? join7(AGENT_DIR, "telegram-pending-inbound
17261
17411
  var RECOVERY_OUTBOX_DIR = AGENT_DIR ? join7(AGENT_DIR, "telegram-recovery-outbox") : null;
17262
17412
  var RESTART_CONFIRM_FILE = AGENT_DIR ? join7(AGENT_DIR, "telegram-restart-confirm.json") : null;
17263
17413
  var TELEGRAM_PROCESS_BOOT_MS = Date.now();
17414
+ var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ? join7(AGENT_DIR, "telegram-recent-dms.json") : null;
17415
+ var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ? join7(AGENT_DIR, "telegram-channel-add-restart.json") : null;
17416
+ var recentDms = /* @__PURE__ */ new Map();
17417
+ var recentDmPersister = TELEGRAM_RECENT_DMS_FILE ? createRecentDmPersister({
17418
+ filePath: TELEGRAM_RECENT_DMS_FILE,
17419
+ onError: (m) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${redactAugmentedPaths(m)}
17420
+ `)
17421
+ }) : null;
17422
+ if (TELEGRAM_RECENT_DMS_FILE) {
17423
+ const loadedRecentDms = loadRecentDms(TELEGRAM_RECENT_DMS_FILE, {
17424
+ onError: (m) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${redactAugmentedPaths(m)}
17425
+ `)
17426
+ });
17427
+ for (const [k, v] of loadedRecentDms) recentDms.set(k, v);
17428
+ }
17429
+ async function notifyDmUsersOnChannelAddRestart() {
17430
+ if (!TELEGRAM_CHANNEL_ADD_RESTART_FILE) return;
17431
+ const marker = readChannelAddRestartMarker(TELEGRAM_CHANNEL_ADD_RESTART_FILE);
17432
+ if (!shouldPostChannelAddNotice(marker, TELEGRAM_PROCESS_BOOT_MS)) {
17433
+ if (marker) clearChannelAddRestartMarker(TELEGRAM_CHANNEL_ADD_RESTART_FILE);
17434
+ return;
17435
+ }
17436
+ const chats = recentlyActiveDmKeys(recentDms);
17437
+ const text = buildChannelAddNoticeText(marker.added);
17438
+ let notified = 0;
17439
+ for (const chatId of chats) {
17440
+ try {
17441
+ const resp = await telegramApiCall("sendMessage", { chat_id: chatId, text }, 1e4);
17442
+ if (resp.ok) notified += 1;
17443
+ else {
17444
+ process.stderr.write(
17445
+ `telegram-channel(${AGENT_CODE_NAME}): channel-add DM notice rejected chat=${redactId(chatId)}: ${resp.description ?? "unknown"}
17446
+ `
17447
+ );
17448
+ }
17449
+ } catch (err) {
17450
+ process.stderr.write(
17451
+ `telegram-channel(${AGENT_CODE_NAME}): channel-add DM notice send failed: ${redactAugmentedPaths(err.message)}
17452
+ `
17453
+ );
17454
+ }
17455
+ }
17456
+ clearChannelAddRestartMarker(TELEGRAM_CHANNEL_ADD_RESTART_FILE);
17457
+ if (notified > 0) {
17458
+ process.stderr.write(
17459
+ `telegram-channel(${AGENT_CODE_NAME}): notified ${notified} recently-active chat(s) after channel-add restart
17460
+ `
17461
+ );
17462
+ }
17463
+ }
17264
17464
  function safeMarkerName(chatId, messageId) {
17265
17465
  const safe = (s) => s.replace(/[^A-Za-z0-9_-]/g, "_");
17266
17466
  return `${safe(chatId)}__${safe(messageId)}.json`;
@@ -17284,8 +17484,8 @@ function writePendingInboundMarker(chatId, messageId, chatType, undeliverable =
17284
17484
  ...payload ? { payload } : {}
17285
17485
  };
17286
17486
  try {
17287
- mkdirSync4(PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
17288
- writeFileSync5(path, JSON.stringify(marker), { mode: 384 });
17487
+ mkdirSync5(PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
17488
+ writeFileSync6(path, JSON.stringify(marker), { mode: 384 });
17289
17489
  } catch (err) {
17290
17490
  process.stderr.write(
17291
17491
  `telegram-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
@@ -17313,7 +17513,7 @@ function rewriteTelegramMarkerInPlace(path, marker) {
17313
17513
  function clearTelegramMarkerFileWithHeal(fullPath) {
17314
17514
  let marker = null;
17315
17515
  try {
17316
- marker = JSON.parse(readFileSync7(fullPath, "utf-8"));
17516
+ marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
17317
17517
  } catch {
17318
17518
  }
17319
17519
  if (marker && decideRecoveryHeal({
@@ -17323,7 +17523,7 @@ function clearTelegramMarkerFileWithHeal(fullPath) {
17323
17523
  notifyBackOnline(marker.chat_id);
17324
17524
  }
17325
17525
  try {
17326
- if (existsSync5(fullPath)) unlinkSync4(fullPath);
17526
+ if (existsSync5(fullPath)) unlinkSync5(fullPath);
17327
17527
  } catch {
17328
17528
  }
17329
17529
  }
@@ -17331,7 +17531,7 @@ function readPendingInboundMarker(chatId, messageId) {
17331
17531
  const path = pendingInboundPath(chatId, messageId);
17332
17532
  if (!path || !existsSync5(path)) return null;
17333
17533
  try {
17334
- return JSON.parse(readFileSync7(path, "utf-8"));
17534
+ return JSON.parse(readFileSync8(path, "utf-8"));
17335
17535
  } catch {
17336
17536
  return null;
17337
17537
  }
@@ -17354,7 +17554,7 @@ async function processRecoveryOutboxFile(filename) {
17354
17554
  const fullPath = join7(RECOVERY_OUTBOX_DIR, filename);
17355
17555
  let payload;
17356
17556
  try {
17357
- const raw = readFileSync7(fullPath, "utf-8");
17557
+ const raw = readFileSync8(fullPath, "utf-8");
17358
17558
  payload = JSON.parse(raw);
17359
17559
  } catch (err) {
17360
17560
  process.stderr.write(
@@ -17412,7 +17612,7 @@ ${payload.text}`;
17412
17612
  }
17413
17613
  if (sendSucceeded) {
17414
17614
  try {
17415
- unlinkSync4(fullPath);
17615
+ unlinkSync5(fullPath);
17416
17616
  } catch {
17417
17617
  }
17418
17618
  return;
@@ -17472,7 +17672,7 @@ function scanRecoveryRetries() {
17472
17672
  function startRecoveryOutboxWatcher() {
17473
17673
  if (!RECOVERY_OUTBOX_DIR) return;
17474
17674
  try {
17475
- mkdirSync4(RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
17675
+ mkdirSync5(RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
17476
17676
  } catch (err) {
17477
17677
  process.stderr.write(
17478
17678
  `telegram-channel(${AGENT_CODE_NAME}): recovery outbox mkdir failed: ${err.message}
@@ -17530,14 +17730,14 @@ function sweepTelegramStaleMarkers(thresholdMs) {
17530
17730
  const fullPath = join7(PENDING_INBOUND_DIR, filename);
17531
17731
  let marker;
17532
17732
  try {
17533
- marker = JSON.parse(readFileSync7(fullPath, "utf-8"));
17733
+ marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
17534
17734
  } catch (err) {
17535
17735
  process.stderr.write(
17536
17736
  `telegram-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactId(filename)}: ${err.message}
17537
17737
  `
17538
17738
  );
17539
17739
  try {
17540
- unlinkSync4(fullPath);
17740
+ unlinkSync5(fullPath);
17541
17741
  } catch {
17542
17742
  }
17543
17743
  cleared++;
@@ -17551,7 +17751,7 @@ function sweepTelegramStaleMarkers(thresholdMs) {
17551
17751
  recordChannelDeflection(AGENT_DIR, "telegram", "replay_orphaned");
17552
17752
  }
17553
17753
  try {
17554
- unlinkSync4(fullPath);
17754
+ unlinkSync5(fullPath);
17555
17755
  } catch {
17556
17756
  }
17557
17757
  cleared++;
@@ -17581,7 +17781,7 @@ function listPendingInboundChatIds() {
17581
17781
  if (!name.endsWith(".json")) continue;
17582
17782
  try {
17583
17783
  const marker = JSON.parse(
17584
- readFileSync7(join7(PENDING_INBOUND_DIR, name), "utf8")
17784
+ readFileSync8(join7(PENDING_INBOUND_DIR, name), "utf8")
17585
17785
  );
17586
17786
  if (typeof marker.chat_id === "string" && marker.chat_id) chats.add(marker.chat_id);
17587
17787
  } catch {
@@ -18329,7 +18529,7 @@ async function replayPendingTelegramMarkers() {
18329
18529
  const fullPath = join7(PENDING_INBOUND_DIR, name);
18330
18530
  let marker;
18331
18531
  try {
18332
- marker = JSON.parse(readFileSync7(fullPath, "utf-8"));
18532
+ marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
18333
18533
  } catch {
18334
18534
  continue;
18335
18535
  }
@@ -18572,6 +18772,11 @@ async function pollLoop() {
18572
18772
  );
18573
18773
  continue;
18574
18774
  }
18775
+ if (msg.chat.type === "private" && !isFromBot && chatId) {
18776
+ recordDmActivity(recentDms, String(chatId));
18777
+ if (isShuttingDown) recentDmPersister?.flush(recentDms);
18778
+ else recentDmPersister?.schedule(recentDms);
18779
+ }
18575
18780
  observedChatClient?.observe({
18576
18781
  chat_id: chatId,
18577
18782
  chat_title: msg.chat.title ?? msg.chat.username ?? msg.chat.first_name ?? null,
@@ -18877,6 +19082,14 @@ function shutdown(reason) {
18877
19082
  `telegram-channel(${AGENT_CODE_NAME}): ${reason} \u2014 exiting
18878
19083
  `
18879
19084
  );
19085
+ try {
19086
+ recentDmPersister?.flush(recentDms);
19087
+ } catch {
19088
+ }
19089
+ try {
19090
+ recentDmPersister?.dispose();
19091
+ } catch {
19092
+ }
18880
19093
  try {
18881
19094
  releaseMcpSpawnLock(acquiredLockPath);
18882
19095
  } catch {
@@ -18926,6 +19139,7 @@ void (async () => {
18926
19139
  }
18927
19140
  })();
18928
19141
  void notifyRestartCompleteOnBoot();
19142
+ void notifyDmUsersOnChannelAddRestart();
18929
19143
  pollLoop().catch((err) => {
18930
19144
  process.stderr.write(
18931
19145
  `telegram-channel(${AGENT_CODE_NAME}): poll loop died: ${err.message}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.57",
3
+ "version": "0.28.58",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {