@integrity-labs/agt-cli 0.28.764 → 0.28.766

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.
@@ -58,7 +58,7 @@ import {
58
58
  safeWriteJsonAtomic,
59
59
  setConfigHash,
60
60
  tripClass
61
- } from "../chunk-SMY25FCN.js";
61
+ } from "../chunk-HAYQ6DYC.js";
62
62
  import {
63
63
  getProjectDir as getProjectDir2,
64
64
  getReadyTasks,
@@ -246,6 +246,49 @@ import { join as join41, dirname as dirname10, delimiter as pathDelimiter } from
246
246
  import { homedir as homedir17 } from "os";
247
247
  import { fileURLToPath } from "url";
248
248
 
249
+ // ../../packages/core/dist/provisioning/channel-policy-env.js
250
+ var TELEGRAM_RESTART_ON_CHANGE_ENV_KEYS = [
251
+ /** Who may talk to the agent — and, at four MCP call sites, who it may send to. */
252
+ "TELEGRAM_ALLOWED_CHATS",
253
+ /** Drops every group / supergroup / channel message. A containment control. */
254
+ "TELEGRAM_PRIVATE_CHATS_ONLY",
255
+ /** Peer kill switch. A switch whose purpose is stopping something promptly. */
256
+ "PEER_DISABLED",
257
+ /** Derived boolean mirror of the same switch, kept for the rollout. */
258
+ "TELEGRAM_PEER_DISABLED"
259
+ ];
260
+ function telegramPolicyEnvBasis(env) {
261
+ const parts = [];
262
+ for (const key of [...TELEGRAM_RESTART_ON_CHANGE_ENV_KEYS].sort()) {
263
+ const raw = env[key];
264
+ if (raw === void 0)
265
+ continue;
266
+ const value = key === "TELEGRAM_ALLOWED_CHATS" ? [...new Set(raw.split(",").map((v) => v.trim()).filter((v) => v.length > 0))].sort().join(",") : raw.trim();
267
+ parts.push(`${key}=${value}`);
268
+ }
269
+ return parts.join("\n");
270
+ }
271
+ function telegramPolicyEnvFromInputs(config2, opts) {
272
+ const env = {};
273
+ const allowedChats = config2["allowed_chats"];
274
+ if (Array.isArray(allowedChats)) {
275
+ const ids = allowedChats.map((v) => typeof v === "string" || typeof v === "number" ? String(v).trim() : "").filter((v) => v.length > 0);
276
+ if (ids.length > 0)
277
+ env["TELEGRAM_ALLOWED_CHATS"] = ids.join(",");
278
+ }
279
+ if (config2["private_chats_only"] === true)
280
+ env["TELEGRAM_PRIVATE_CHATS_ONLY"] = "1";
281
+ const mode = opts?.peerDisabledMode;
282
+ if (mode && mode !== "off")
283
+ env["PEER_DISABLED"] = mode;
284
+ if (mode === "all")
285
+ env["TELEGRAM_PEER_DISABLED"] = "true";
286
+ return env;
287
+ }
288
+ function isTelegramPolicyRestrictive(env) {
289
+ return telegramPolicyEnvBasis(env).length > 0;
290
+ }
291
+
249
292
  // src/lib/single-flight.ts
250
293
  function createSingleFlight(task, opts = {}) {
251
294
  let running2 = false;
@@ -5993,12 +6036,23 @@ import { existsSync as existsSync10, readFileSync as readFileSync21 } from "fs";
5993
6036
  import { join as join27 } from "path";
5994
6037
  var BASELINE_FILENAME = "sender-policy-baseline.json";
5995
6038
  var SENDER_POLICY_BASELINE_VERSION = 1;
5996
- var BASELINE_CONCERNS = ["senderPolicy", "slackBehaviour", "msteamsBehaviour"];
6039
+ var BASELINE_CONCERNS = [
6040
+ "senderPolicy",
6041
+ "slackBehaviour",
6042
+ "msteamsBehaviour",
6043
+ // ENG-9802: the telegram chat policy (allowlist / private-chats-only / peer
6044
+ // kill switch). Same shape and same reason as senderPolicy — the MCP child
6045
+ // reads it once at boot, so a change has to be delivered by a respawn, and
6046
+ // the baseline has to survive a manager restart or every deploy would look
6047
+ // like a first poll and respawn the fleet (ENG-7771).
6048
+ "telegramPolicy"
6049
+ ];
5997
6050
  function createDeliveryBaselineMaps() {
5998
6051
  return {
5999
6052
  senderPolicy: /* @__PURE__ */ new Map(),
6000
6053
  slackBehaviour: /* @__PURE__ */ new Map(),
6001
- msteamsBehaviour: /* @__PURE__ */ new Map()
6054
+ msteamsBehaviour: /* @__PURE__ */ new Map(),
6055
+ telegramPolicy: /* @__PURE__ */ new Map()
6002
6056
  };
6003
6057
  }
6004
6058
  function getSenderPolicyBaselineFile(configDir) {
@@ -6575,6 +6629,8 @@ var agentState = {
6575
6629
  * (they read SLACK_SENDER_POLICY / MSTEAMS_SENDER_POLICY only at boot).
6576
6630
  */
6577
6631
  knownSenderPolicyHashes: /* @__PURE__ */ new Map(),
6632
+ /** ENG-9802: per-agent telegram chat-policy hash (allowlist / private-chats-only / peer kill switch). */
6633
+ knownTelegramPolicyHashes: /* @__PURE__ */ new Map(),
6578
6634
  /**
6579
6635
  * ENG-6024: hash of the Teams behaviour subset (thread_auto_follow,
6580
6636
  * channel_response_mode, adaptive_cards_enabled/_ask_user_enabled) from the
@@ -6662,6 +6718,7 @@ function clearAgentState(agentId, codeName) {
6662
6718
  agentState.knownManagedMcpHashes.delete(agentId);
6663
6719
  agentState.knownManagedMcpStructure.delete(agentId);
6664
6720
  agentState.knownSenderPolicyHashes.delete(agentId);
6721
+ agentState.knownTelegramPolicyHashes.delete(agentId);
6665
6722
  agentState.knownMsTeamsBehaviourHashes.delete(agentId);
6666
6723
  agentState.knownSlackBehaviourHashes.delete(agentId);
6667
6724
  agentState.knownGlobalSkillIds.delete(agentId);
@@ -12659,6 +12716,11 @@ function scheduleSessionRestart(codeName, delayMs, reason, breakerReason = "hot-
12659
12716
  baselineAgentId,
12660
12717
  agentState.knownMsTeamsBehaviourHashes.get(baselineAgentId)
12661
12718
  );
12719
+ persistDeliveryBaselineEntry(
12720
+ "telegramPolicy",
12721
+ baselineAgentId,
12722
+ agentState.knownTelegramPolicyHashes.get(baselineAgentId)
12723
+ );
12662
12724
  }
12663
12725
  }
12664
12726
  runningMcpHashes.delete(codeName);
@@ -13468,7 +13530,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
13468
13530
  var lastVersionCheckAt = 0;
13469
13531
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13470
13532
  var lastResponsivenessProbeAt = 0;
13471
- var agtCliVersion = true ? "0.28.764" : "dev";
13533
+ var agtCliVersion = true ? "0.28.766" : "dev";
13472
13534
  function resolveBrewPath(execFileSync2) {
13473
13535
  try {
13474
13536
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14723,6 +14785,9 @@ function loadSenderPolicyBaseline2() {
14723
14785
  for (const [agentId, hash] of persistedDeliveryBaseline.msteamsBehaviour) {
14724
14786
  agentState.knownMsTeamsBehaviourHashes.set(agentId, hash);
14725
14787
  }
14788
+ for (const [agentId, hash] of persistedDeliveryBaseline.telegramPolicy) {
14789
+ agentState.knownTelegramPolicyHashes.set(agentId, hash);
14790
+ }
14726
14791
  }
14727
14792
  var deliveryBaselineDirty = false;
14728
14793
  function saveDeliveryBaseline() {
@@ -16491,6 +16556,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16491
16556
  const known = agentState.knownVersions.get(agent.agent_id);
16492
16557
  let lastProvisionAt = state8.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
16493
16558
  const quarantinedChannels = channelQuarantineStore().getQuarantinedKeys(agent.code_name);
16559
+ let telegramPolicyEnvForRestart;
16494
16560
  const currentChannelIds = setWithout(
16495
16561
  launchableChannelIds(refreshData.channel_configs),
16496
16562
  quarantinedChannels
@@ -16805,6 +16871,12 @@ async function processAgent(agent, agentStates, managedToolkits) {
16805
16871
  if (next === "off" || next === "cross_team_only" || next === "all") return next;
16806
16872
  return teamSettings?.["telegram_peer_disabled"] === true ? "all" : "off";
16807
16873
  })();
16874
+ if (channelId === "telegram") {
16875
+ telegramPolicyEnvForRestart = telegramPolicyEnvFromInputs(
16876
+ entry.config,
16877
+ { peerDisabledMode }
16878
+ );
16879
+ }
16808
16880
  const agentTimezone = (() => {
16809
16881
  const tz = teamSettings?.["timezone"];
16810
16882
  return typeof tz === "string" && tz.trim() !== "" ? tz.trim() : void 0;
@@ -17092,6 +17164,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17092
17164
  persistDeliveryBaselineEntry("senderPolicy", agent.agent_id, senderPolicyHash);
17093
17165
  }
17094
17166
  let msteamsBehaviourRestartScheduled = false;
17167
+ let slackBehaviourRestartScheduled = false;
17095
17168
  if (currentChannelIds.has("msteams")) {
17096
17169
  const msteamsEntry = refreshData.channel_configs?.["msteams"];
17097
17170
  const behaviourSubset = extractMsTeamsBehaviourSubset(
@@ -17194,6 +17267,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17194
17267
  "channel-behaviour-change"
17195
17268
  );
17196
17269
  }
17270
+ if (slackBehaviourDecision.restart) slackBehaviourRestartScheduled = true;
17197
17271
  agentState.knownSlackBehaviourHashes.set(agent.agent_id, slackBehaviourHash);
17198
17272
  const hasLiveSlackBehaviourConsumer = spSessionHealthy && spSessionMode === "persistent" && spFramework === "claude-code";
17199
17273
  if (!hasLiveSlackBehaviourConsumer) {
@@ -17205,6 +17279,59 @@ async function processAgent(agent, agentStates, managedToolkits) {
17205
17279
  agentState.knownSlackBehaviourHashes.delete(agent.agent_id);
17206
17280
  removeDeliveryBaselineEntry("slackBehaviour", agent.agent_id);
17207
17281
  }
17282
+ if (currentChannelIds.has("telegram")) {
17283
+ const telegramPolicyEnv = telegramPolicyEnvForRestart ?? {};
17284
+ const telegramPolicyHash = createHash20("sha256").update(telegramPolicyEnvBasis(telegramPolicyEnv)).digest("hex");
17285
+ const prevTelegramPolicyHash = agentState.knownTelegramPolicyHashes.get(agent.agent_id);
17286
+ const telegramPolicyRestrictive = isTelegramPolicyRestrictive(telegramPolicyEnv);
17287
+ const telegramPolicyDecision = decideSenderPolicyRestart({
17288
+ previousHash: prevTelegramPolicyHash,
17289
+ currentPolicyRestrictive: telegramPolicyRestrictive,
17290
+ currentHash: telegramPolicyHash,
17291
+ sessionMode: spSessionMode,
17292
+ framework: spFramework,
17293
+ sessionHealthy: spSessionHealthy,
17294
+ // Any earlier restart scheduled this tick already respawns the MCP
17295
+ // children with the freshly-written env.
17296
+ channelSetRestartAlreadyScheduled: channelSetRestartScheduled || senderPolicyDecision.restart || msteamsBehaviourRestartScheduled || slackBehaviourRestartScheduled
17297
+ });
17298
+ if (telegramPolicyDecision.restart) {
17299
+ const isTelegramVerifyRestart = telegramPolicyDecision.firstPoll;
17300
+ log(
17301
+ isTelegramVerifyRestart ? `[hot-reload] telegram chat-policy delivery baseline unknown for '${agent.code_name}' with a policy set (\u2192 ${telegramPolicyHash.slice(0, 8)}) \u2014 restarting session to guarantee enforcement (fail closed, ENG-9802)` : `[hot-reload] telegram chat policy changed for '${agent.code_name}' (${prevTelegramPolicyHash?.slice(0, 8) ?? "first"} \u2192 ${telegramPolicyHash.slice(0, 8)}) \u2014 restarting session`
17302
+ );
17303
+ const telegramNotice = isTelegramVerifyRestart ? "Your manager was updated and needs to restart your session to make sure your configured Telegram chat policy is enforced by the channel MCP server." : "Your Telegram chat policy has been updated. Restarting session shortly so the channel MCP server picks up the new allowlist.";
17304
+ const telegramDelivered = await injectMessage(
17305
+ agent.code_name,
17306
+ "system",
17307
+ telegramNotice + BACK_ONLINE_GREETING_GUIDANCE,
17308
+ { task_name: "telegram-policy-update" },
17309
+ log
17310
+ ).catch(() => false);
17311
+ const telegramDelay = telegramDelivered ? 8e3 : 3e3;
17312
+ if (!telegramDelivered) {
17313
+ log(
17314
+ `[hot-reload] Inject notification unconfirmed for '${agent.code_name}' \u2014 proceeding with shorter delay`
17315
+ );
17316
+ }
17317
+ scheduleSessionRestart(
17318
+ agent.code_name,
17319
+ telegramDelay,
17320
+ isTelegramVerifyRestart ? "telegram chat-policy verify (unknown baseline)" : "telegram chat-policy change",
17321
+ "telegram-policy-change"
17322
+ );
17323
+ }
17324
+ agentState.knownTelegramPolicyHashes.set(agent.agent_id, telegramPolicyHash);
17325
+ const hasLiveTelegramPolicyConsumer = spSessionHealthy && spSessionMode === "persistent" && spFramework === "claude-code";
17326
+ if (!hasLiveTelegramPolicyConsumer) {
17327
+ persistDeliveryBaselineEntry("telegramPolicy", agent.agent_id, telegramPolicyHash);
17328
+ } else if (telegramPolicyDecision.firstPoll && !telegramPolicyRestrictive) {
17329
+ persistDeliveryBaselineEntry("telegramPolicy", agent.agent_id, telegramPolicyHash);
17330
+ }
17331
+ } else {
17332
+ agentState.knownTelegramPolicyHashes.delete(agent.agent_id);
17333
+ removeDeliveryBaselineEntry("telegramPolicy", agent.agent_id);
17334
+ }
17208
17335
  }
17209
17336
  const agentSessionMode = refreshData.agent.session_mode;
17210
17337
  if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? DEFAULT_FRAMEWORK) === "claude-code") {