@integrity-labs/agt-cli 0.28.57 → 0.28.59

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 {
@@ -16288,8 +16438,11 @@ function orphanSweepIntervalMs() {
16288
16438
  }
16289
16439
  var MAX_MARKER_REPLAYS = 3;
16290
16440
  function channelReplayEnabled() {
16291
- const v = process.env.AGT_CHANNEL_REPLAY_ENABLED;
16292
- return v === "1" || v === "true";
16441
+ return resolveHostBooleanFlag({
16442
+ key: "channel-replay",
16443
+ envVar: "AGT_CHANNEL_REPLAY_ENABLED",
16444
+ defaultValue: false
16445
+ });
16293
16446
  }
16294
16447
  function shouldReplayMarker(i) {
16295
16448
  if (!i.enabled) return false;
@@ -16314,13 +16467,13 @@ function recordChannelDeflection(agentDir, channel, cause) {
16314
16467
  const path = deflectionCounterPath(agentDir, channel);
16315
16468
  let counts = {};
16316
16469
  try {
16317
- const parsed = JSON.parse(readFileSync6(path, "utf-8"));
16470
+ const parsed = JSON.parse(readFileSync7(path, "utf-8"));
16318
16471
  if (parsed && typeof parsed === "object") counts = parsed;
16319
16472
  } catch {
16320
16473
  }
16321
16474
  counts[cause] = (counts[cause] ?? 0) + 1;
16322
16475
  try {
16323
- writeFileSync4(path, JSON.stringify(counts), { mode: 384 });
16476
+ writeFileSync5(path, JSON.stringify(counts), { mode: 384 });
16324
16477
  } catch {
16325
16478
  }
16326
16479
  }
@@ -16457,7 +16610,7 @@ var stderrLogStream = null;
16457
16610
  if (AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown") {
16458
16611
  try {
16459
16612
  const logDir = join7(homedir3(), ".augmented", AGENT_CODE_NAME);
16460
- mkdirSync4(logDir, { recursive: true });
16613
+ mkdirSync5(logDir, { recursive: true });
16461
16614
  stderrLogStream = createWriteStream(join7(logDir, "telegram-channel-stderr.log"), {
16462
16615
  flags: "a",
16463
16616
  mode: 384
@@ -16871,7 +17024,7 @@ async function handleStatusCommand(opts) {
16871
17024
  async function handleRestartCommand(opts) {
16872
17025
  try {
16873
17026
  if (!existsSync5(RESTART_FLAGS_DIR)) {
16874
- mkdirSync4(RESTART_FLAGS_DIR, { recursive: true });
17027
+ mkdirSync5(RESTART_FLAGS_DIR, { recursive: true });
16875
17028
  }
16876
17029
  const flagPath = join7(RESTART_FLAGS_DIR, `${AGENT_CODE_NAME}.flag`);
16877
17030
  writeTelegramRestartConfirm(
@@ -16885,7 +17038,7 @@ async function handleRestartCommand(opts) {
16885
17038
  reply: { chat_id: opts.chatId, message_id: opts.messageId }
16886
17039
  };
16887
17040
  const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
16888
- writeFileSync5(tmpPath, JSON.stringify(flag) + "\n", "utf8");
17041
+ writeFileSync6(tmpPath, JSON.stringify(flag) + "\n", "utf8");
16889
17042
  renameSync4(tmpPath, flagPath);
16890
17043
  process.stderr.write(
16891
17044
  `telegram-channel(${AGENT_CODE_NAME}): /restart queued from chat ${redactId(opts.chatId)}
@@ -17261,6 +17414,56 @@ var PENDING_INBOUND_DIR = AGENT_DIR ? join7(AGENT_DIR, "telegram-pending-inbound
17261
17414
  var RECOVERY_OUTBOX_DIR = AGENT_DIR ? join7(AGENT_DIR, "telegram-recovery-outbox") : null;
17262
17415
  var RESTART_CONFIRM_FILE = AGENT_DIR ? join7(AGENT_DIR, "telegram-restart-confirm.json") : null;
17263
17416
  var TELEGRAM_PROCESS_BOOT_MS = Date.now();
17417
+ var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ? join7(AGENT_DIR, "telegram-recent-dms.json") : null;
17418
+ var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ? join7(AGENT_DIR, "telegram-channel-add-restart.json") : null;
17419
+ var recentDms = /* @__PURE__ */ new Map();
17420
+ var recentDmPersister = TELEGRAM_RECENT_DMS_FILE ? createRecentDmPersister({
17421
+ filePath: TELEGRAM_RECENT_DMS_FILE,
17422
+ onError: (m) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${redactAugmentedPaths(m)}
17423
+ `)
17424
+ }) : null;
17425
+ if (TELEGRAM_RECENT_DMS_FILE) {
17426
+ const loadedRecentDms = loadRecentDms(TELEGRAM_RECENT_DMS_FILE, {
17427
+ onError: (m) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${redactAugmentedPaths(m)}
17428
+ `)
17429
+ });
17430
+ for (const [k, v] of loadedRecentDms) recentDms.set(k, v);
17431
+ }
17432
+ async function notifyDmUsersOnChannelAddRestart() {
17433
+ if (!TELEGRAM_CHANNEL_ADD_RESTART_FILE) return;
17434
+ const marker = readChannelAddRestartMarker(TELEGRAM_CHANNEL_ADD_RESTART_FILE);
17435
+ if (!shouldPostChannelAddNotice(marker, TELEGRAM_PROCESS_BOOT_MS)) {
17436
+ if (marker) clearChannelAddRestartMarker(TELEGRAM_CHANNEL_ADD_RESTART_FILE);
17437
+ return;
17438
+ }
17439
+ const chats = recentlyActiveDmKeys(recentDms);
17440
+ const text = buildChannelAddNoticeText(marker.added);
17441
+ let notified = 0;
17442
+ for (const chatId of chats) {
17443
+ try {
17444
+ const resp = await telegramApiCall("sendMessage", { chat_id: chatId, text }, 1e4);
17445
+ if (resp.ok) notified += 1;
17446
+ else {
17447
+ process.stderr.write(
17448
+ `telegram-channel(${AGENT_CODE_NAME}): channel-add DM notice rejected chat=${redactId(chatId)}: ${resp.description ?? "unknown"}
17449
+ `
17450
+ );
17451
+ }
17452
+ } catch (err) {
17453
+ process.stderr.write(
17454
+ `telegram-channel(${AGENT_CODE_NAME}): channel-add DM notice send failed: ${redactAugmentedPaths(err.message)}
17455
+ `
17456
+ );
17457
+ }
17458
+ }
17459
+ clearChannelAddRestartMarker(TELEGRAM_CHANNEL_ADD_RESTART_FILE);
17460
+ if (notified > 0) {
17461
+ process.stderr.write(
17462
+ `telegram-channel(${AGENT_CODE_NAME}): notified ${notified} recently-active chat(s) after channel-add restart
17463
+ `
17464
+ );
17465
+ }
17466
+ }
17264
17467
  function safeMarkerName(chatId, messageId) {
17265
17468
  const safe = (s) => s.replace(/[^A-Za-z0-9_-]/g, "_");
17266
17469
  return `${safe(chatId)}__${safe(messageId)}.json`;
@@ -17284,8 +17487,8 @@ function writePendingInboundMarker(chatId, messageId, chatType, undeliverable =
17284
17487
  ...payload ? { payload } : {}
17285
17488
  };
17286
17489
  try {
17287
- mkdirSync4(PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
17288
- writeFileSync5(path, JSON.stringify(marker), { mode: 384 });
17490
+ mkdirSync5(PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
17491
+ writeFileSync6(path, JSON.stringify(marker), { mode: 384 });
17289
17492
  } catch (err) {
17290
17493
  process.stderr.write(
17291
17494
  `telegram-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
@@ -17313,7 +17516,7 @@ function rewriteTelegramMarkerInPlace(path, marker) {
17313
17516
  function clearTelegramMarkerFileWithHeal(fullPath) {
17314
17517
  let marker = null;
17315
17518
  try {
17316
- marker = JSON.parse(readFileSync7(fullPath, "utf-8"));
17519
+ marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
17317
17520
  } catch {
17318
17521
  }
17319
17522
  if (marker && decideRecoveryHeal({
@@ -17323,7 +17526,7 @@ function clearTelegramMarkerFileWithHeal(fullPath) {
17323
17526
  notifyBackOnline(marker.chat_id);
17324
17527
  }
17325
17528
  try {
17326
- if (existsSync5(fullPath)) unlinkSync4(fullPath);
17529
+ if (existsSync5(fullPath)) unlinkSync5(fullPath);
17327
17530
  } catch {
17328
17531
  }
17329
17532
  }
@@ -17331,7 +17534,7 @@ function readPendingInboundMarker(chatId, messageId) {
17331
17534
  const path = pendingInboundPath(chatId, messageId);
17332
17535
  if (!path || !existsSync5(path)) return null;
17333
17536
  try {
17334
- return JSON.parse(readFileSync7(path, "utf-8"));
17537
+ return JSON.parse(readFileSync8(path, "utf-8"));
17335
17538
  } catch {
17336
17539
  return null;
17337
17540
  }
@@ -17354,7 +17557,7 @@ async function processRecoveryOutboxFile(filename) {
17354
17557
  const fullPath = join7(RECOVERY_OUTBOX_DIR, filename);
17355
17558
  let payload;
17356
17559
  try {
17357
- const raw = readFileSync7(fullPath, "utf-8");
17560
+ const raw = readFileSync8(fullPath, "utf-8");
17358
17561
  payload = JSON.parse(raw);
17359
17562
  } catch (err) {
17360
17563
  process.stderr.write(
@@ -17412,7 +17615,7 @@ ${payload.text}`;
17412
17615
  }
17413
17616
  if (sendSucceeded) {
17414
17617
  try {
17415
- unlinkSync4(fullPath);
17618
+ unlinkSync5(fullPath);
17416
17619
  } catch {
17417
17620
  }
17418
17621
  return;
@@ -17472,7 +17675,7 @@ function scanRecoveryRetries() {
17472
17675
  function startRecoveryOutboxWatcher() {
17473
17676
  if (!RECOVERY_OUTBOX_DIR) return;
17474
17677
  try {
17475
- mkdirSync4(RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
17678
+ mkdirSync5(RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
17476
17679
  } catch (err) {
17477
17680
  process.stderr.write(
17478
17681
  `telegram-channel(${AGENT_CODE_NAME}): recovery outbox mkdir failed: ${err.message}
@@ -17530,14 +17733,14 @@ function sweepTelegramStaleMarkers(thresholdMs) {
17530
17733
  const fullPath = join7(PENDING_INBOUND_DIR, filename);
17531
17734
  let marker;
17532
17735
  try {
17533
- marker = JSON.parse(readFileSync7(fullPath, "utf-8"));
17736
+ marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
17534
17737
  } catch (err) {
17535
17738
  process.stderr.write(
17536
17739
  `telegram-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactId(filename)}: ${err.message}
17537
17740
  `
17538
17741
  );
17539
17742
  try {
17540
- unlinkSync4(fullPath);
17743
+ unlinkSync5(fullPath);
17541
17744
  } catch {
17542
17745
  }
17543
17746
  cleared++;
@@ -17551,7 +17754,7 @@ function sweepTelegramStaleMarkers(thresholdMs) {
17551
17754
  recordChannelDeflection(AGENT_DIR, "telegram", "replay_orphaned");
17552
17755
  }
17553
17756
  try {
17554
- unlinkSync4(fullPath);
17757
+ unlinkSync5(fullPath);
17555
17758
  } catch {
17556
17759
  }
17557
17760
  cleared++;
@@ -17581,7 +17784,7 @@ function listPendingInboundChatIds() {
17581
17784
  if (!name.endsWith(".json")) continue;
17582
17785
  try {
17583
17786
  const marker = JSON.parse(
17584
- readFileSync7(join7(PENDING_INBOUND_DIR, name), "utf8")
17787
+ readFileSync8(join7(PENDING_INBOUND_DIR, name), "utf8")
17585
17788
  );
17586
17789
  if (typeof marker.chat_id === "string" && marker.chat_id) chats.add(marker.chat_id);
17587
17790
  } catch {
@@ -18329,7 +18532,7 @@ async function replayPendingTelegramMarkers() {
18329
18532
  const fullPath = join7(PENDING_INBOUND_DIR, name);
18330
18533
  let marker;
18331
18534
  try {
18332
- marker = JSON.parse(readFileSync7(fullPath, "utf-8"));
18535
+ marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
18333
18536
  } catch {
18334
18537
  continue;
18335
18538
  }
@@ -18572,6 +18775,11 @@ async function pollLoop() {
18572
18775
  );
18573
18776
  continue;
18574
18777
  }
18778
+ if (msg.chat.type === "private" && !isFromBot && chatId) {
18779
+ recordDmActivity(recentDms, String(chatId));
18780
+ if (isShuttingDown) recentDmPersister?.flush(recentDms);
18781
+ else recentDmPersister?.schedule(recentDms);
18782
+ }
18575
18783
  observedChatClient?.observe({
18576
18784
  chat_id: chatId,
18577
18785
  chat_title: msg.chat.title ?? msg.chat.username ?? msg.chat.first_name ?? null,
@@ -18877,6 +19085,14 @@ function shutdown(reason) {
18877
19085
  `telegram-channel(${AGENT_CODE_NAME}): ${reason} \u2014 exiting
18878
19086
  `
18879
19087
  );
19088
+ try {
19089
+ recentDmPersister?.flush(recentDms);
19090
+ } catch {
19091
+ }
19092
+ try {
19093
+ recentDmPersister?.dispose();
19094
+ } catch {
19095
+ }
18880
19096
  try {
18881
19097
  releaseMcpSpawnLock(acquiredLockPath);
18882
19098
  } catch {
@@ -18926,6 +19142,7 @@ void (async () => {
18926
19142
  }
18927
19143
  })();
18928
19144
  void notifyRestartCompleteOnBoot();
19145
+ void notifyDmUsersOnChannelAddRestart();
18929
19146
  pollLoop().catch((err) => {
18930
19147
  process.stderr.write(
18931
19148
  `telegram-channel(${AGENT_CODE_NAME}): poll loop died: ${err.message}
@@ -25,8 +25,8 @@ import {
25
25
  takeZombieDetection,
26
26
  writeDirectChatSessionState,
27
27
  writePersistentClaudeWrapper
28
- } from "./chunk-MKKTPM6J.js";
29
- import "./chunk-SJRG5VUF.js";
28
+ } from "./chunk-UA3LEZL4.js";
29
+ import "./chunk-OEZEWEEG.js";
30
30
  import "./chunk-XWVM4KPK.js";
31
31
  export {
32
32
  SEND_KEYS_ENTER_DELAY_MS,
@@ -56,4 +56,4 @@ export {
56
56
  writeDirectChatSessionState,
57
57
  writePersistentClaudeWrapper
58
58
  };
59
- //# sourceMappingURL=persistent-session-INTCKEG6.js.map
59
+ //# sourceMappingURL=persistent-session-42V6NGMR.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-MKKTPM6J.js";
4
- import "./chunk-SJRG5VUF.js";
3
+ } from "./chunk-UA3LEZL4.js";
4
+ import "./chunk-OEZEWEEG.js";
5
5
  import "./chunk-XWVM4KPK.js";
6
6
 
7
7
  // src/lib/responsiveness-probe.ts
@@ -250,4 +250,4 @@ export {
250
250
  parkPendingInbound,
251
251
  readAndResetChannelDeflections
252
252
  };
253
- //# sourceMappingURL=responsiveness-probe-XAYQAVLV.js.map
253
+ //# sourceMappingURL=responsiveness-probe-YSSYWWTG.js.map
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.59",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {