@integrity-labs/agt-cli 0.28.671 → 0.28.673

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.
Files changed (27) hide show
  1. package/dist/bin/agt.js +6 -6
  2. package/dist/bin/agt.js.map +1 -1
  3. package/dist/{chunk-ZU2BHLUS.js → chunk-RSERKOS7.js} +20 -76
  4. package/dist/chunk-RSERKOS7.js.map +1 -0
  5. package/dist/{chunk-57XP5OG6.js → chunk-YAVWYI5S.js} +104 -5
  6. package/dist/chunk-YAVWYI5S.js.map +1 -0
  7. package/dist/{chunk-DWFN5PMF.js → chunk-YOID6KOQ.js} +22 -1
  8. package/dist/chunk-YOID6KOQ.js.map +1 -0
  9. package/dist/{claude-pair-runtime-ANNQRKO4.js → claude-pair-runtime-UZ2JB2KY.js} +2 -2
  10. package/dist/lib/manager-worker.js +78 -22
  11. package/dist/lib/manager-worker.js.map +1 -1
  12. package/dist/mcp/direct-chat-channel.js +21 -0
  13. package/dist/mcp/index.js +21 -0
  14. package/dist/mcp/origami.js +21 -0
  15. package/dist/mcp/slack-channel.js +21 -0
  16. package/dist/mcp/telegram-channel.js +21 -0
  17. package/dist/{persistent-session-LTFB4M53.js → persistent-session-PYAJ4VJW.js} +3 -3
  18. package/dist/{responsiveness-probe-P2S3UMRE.js → responsiveness-probe-5I2LIVCA.js} +3 -3
  19. package/dist/{session-auth-dead-YHSQBOB4.js → session-auth-dead-NUX643UJ.js} +2 -2
  20. package/package.json +1 -1
  21. package/dist/chunk-57XP5OG6.js.map +0 -1
  22. package/dist/chunk-DWFN5PMF.js.map +0 -1
  23. package/dist/chunk-ZU2BHLUS.js.map +0 -1
  24. /package/dist/{claude-pair-runtime-ANNQRKO4.js.map → claude-pair-runtime-UZ2JB2KY.js.map} +0 -0
  25. /package/dist/{persistent-session-LTFB4M53.js.map → persistent-session-PYAJ4VJW.js.map} +0 -0
  26. /package/dist/{responsiveness-probe-P2S3UMRE.js.map → responsiveness-probe-5I2LIVCA.js.map} +0 -0
  27. /package/dist/{session-auth-dead-YHSQBOB4.js.map → session-auth-dead-NUX643UJ.js.map} +0 -0
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-LTFB4M53.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-PYAJ4VJW.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-ANNQRKO4.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-UZ2JB2KY.js.map
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  ApiError,
3
- CHANNEL_SECRET_ENV_KEYS,
4
3
  FIRST_CONNECT_WINDOW_MS,
5
4
  HostFlagStore,
6
5
  RestartBreaker,
@@ -55,7 +54,7 @@ import {
55
54
  safeWriteJsonAtomic,
56
55
  setConfigHash,
57
56
  tripClass
58
- } from "../chunk-ZU2BHLUS.js";
57
+ } from "../chunk-RSERKOS7.js";
59
58
  import {
60
59
  getProjectDir as getProjectDir2,
61
60
  getReadyTasks,
@@ -64,10 +63,12 @@ import {
64
63
  syncTasksToScheduler
65
64
  } from "../chunk-3HLECXMI.js";
66
65
  import {
66
+ CHANNEL_SECRET_ENV_KEYS,
67
67
  ChildProcessError,
68
68
  agentRuntimeKey,
69
69
  buildEgressAllowlist,
70
70
  checkChannelInputs,
71
+ collectChannelSpawnSecrets,
71
72
  creditWatchdogGiveUpCount,
72
73
  egressMode,
73
74
  execFilePromiseLong,
@@ -111,7 +112,7 @@ import {
111
112
  takeZombieDetection,
112
113
  toOpencodeModel,
113
114
  writeEgressAllowlist
114
- } from "../chunk-57XP5OG6.js";
115
+ } from "../chunk-YAVWYI5S.js";
115
116
  import {
116
117
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
117
118
  AnchorSessionClient,
@@ -192,7 +193,7 @@ import {
192
193
  subagentActivityAgeSeconds,
193
194
  sumTranscriptUsageInWindow,
194
195
  transcriptActivityAgeSeconds
195
- } from "../chunk-DWFN5PMF.js";
196
+ } from "../chunk-YOID6KOQ.js";
196
197
  import {
197
198
  reapOrphanChannelMcps
198
199
  } from "../chunk-XWVM4KPK.js";
@@ -4996,7 +4997,12 @@ function computeChannelConfigHash(input) {
4996
4997
  sessionMode: input.sessionMode ?? null,
4997
4998
  // ENG-7435: value-blind on the team_principals id SETS so a reorder of
4998
4999
  // the same principals can't oscillate this hash into a false rewrite.
4999
- senderPolicy: normalizeSenderPolicyForHash(input.senderPolicy)
5000
+ senderPolicy: normalizeSenderPolicyForHash(input.senderPolicy),
5001
+ // ENG-9350: a `spawn-inject-channel-secrets` flip must invalidate the
5002
+ // cache so writeChannelCredentials re-runs (evict on enable / restore on
5003
+ // disable). Absent folds to 'file', so pre-ENG-9350 callers and the
5004
+ // file-delivery default keep a stable digest relative to each other.
5005
+ channelSecretDelivery: input.channelSecretDelivery ?? "file"
5000
5006
  })
5001
5007
  ).digest("hex");
5002
5008
  }
@@ -11611,7 +11617,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
11611
11617
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
11612
11618
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
11613
11619
  async function channelInboundActivityAgeSecondsFor(codeName) {
11614
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-P2S3UMRE.js");
11620
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-5I2LIVCA.js");
11615
11621
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
11616
11622
  if (newest === null) return null;
11617
11623
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -11818,7 +11824,7 @@ function runPendingForcedUpdate() {
11818
11824
  }
11819
11825
  return false;
11820
11826
  }
11821
- if (selfUpdateInFlight) {
11827
+ if (selfUpdateLatchVerdict(selfUpdateInFlightSince, Date.now()) === "held") {
11822
11828
  log(
11823
11829
  `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 deferring: a self-update is already in flight. Retrying next poll.`
11824
11830
  );
@@ -12155,6 +12161,9 @@ function checkMcpConfigDriftAndScheduleRestart(codeName, projectDir) {
12155
12161
  }
12156
12162
  }
12157
12163
  }
12164
+ function shouldInjectChannelSecrets(agentId) {
12165
+ return hostFlagStore().getBooleanForAgent("spawn-inject-channel-secrets", agentId);
12166
+ }
12158
12167
  function projectChannelSecretHash(projectDir) {
12159
12168
  try {
12160
12169
  const entries = parseEnvIntegrations(
@@ -12165,8 +12174,8 @@ function projectChannelSecretHash(projectDir) {
12165
12174
  return null;
12166
12175
  }
12167
12176
  }
12168
- function checkChannelSecretDriftAndScheduleRestart(codeName, projectDir) {
12169
- const currentHash = projectChannelSecretHash(projectDir);
12177
+ function checkChannelSecretDriftAndScheduleRestart(codeName, projectDir, spawnEnvSecrets) {
12178
+ const currentHash = spawnEnvSecrets !== void 0 ? channelSecretValueHash(spawnEnvSecrets, CHANNEL_SECRET_ENV_KEYS) : projectChannelSecretHash(projectDir);
12170
12179
  const action = decideMcpDriftAction(currentHash, runningChannelSecretHashes.get(codeName));
12171
12180
  switch (action.kind) {
12172
12181
  case "no-config":
@@ -12256,7 +12265,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
12256
12265
  var lastVersionCheckAt = 0;
12257
12266
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
12258
12267
  var lastResponsivenessProbeAt = 0;
12259
- var agtCliVersion = true ? "0.28.671" : "dev";
12268
+ var agtCliVersion = true ? "0.28.673" : "dev";
12260
12269
  function resolveBrewPath(execFileSync3) {
12261
12270
  try {
12262
12271
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -12771,14 +12780,35 @@ var selfUpdatePinInvalidLogged = false;
12771
12780
  var restartAfterUpgrade = false;
12772
12781
  var pendingUpgradeVersion = null;
12773
12782
  var selfUpdateInFlight = false;
12783
+ var selfUpdateInFlightSince = null;
12784
+ var SELF_UPDATE_LATCH_MAX_HOLD_MS = 20 * 6e4;
12785
+ function selfUpdateLatchVerdict(heldSince, now, maxHoldMs = SELF_UPDATE_LATCH_MAX_HOLD_MS) {
12786
+ if (heldSince === null) return "free";
12787
+ const heldMs = now - heldSince;
12788
+ return heldMs >= maxHoldMs ? "expired" : "held";
12789
+ }
12774
12790
  var upgradeRestartInitiated = false;
12775
12791
  var cachedUpdateRequestedAt = null;
12776
12792
  var forcedUpdateDeferStreak = 0;
12777
12793
  var forcedUpdateRelaxAnnounced = false;
12778
12794
  async function checkAndUpdateCli(opts) {
12779
12795
  const force = opts?.force ?? false;
12780
- if (selfUpdateInFlight) return "failed";
12796
+ const verdict = selfUpdateLatchVerdict(selfUpdateInFlightSince, Date.now());
12797
+ if (verdict === "held") {
12798
+ const heldSec = Math.round((Date.now() - (selfUpdateInFlightSince ?? Date.now())) / 1e3);
12799
+ log(
12800
+ `[self-update] deferring: a self-update has been in flight for ${heldSec}s. Retrying next poll; the latch breaks at ${Math.round(SELF_UPDATE_LATCH_MAX_HOLD_MS / 6e4)}m.`
12801
+ );
12802
+ return "failed";
12803
+ }
12804
+ if (verdict === "expired") {
12805
+ const heldMin = Math.round((Date.now() - (selfUpdateInFlightSince ?? Date.now())) / 6e4);
12806
+ console.warn(
12807
+ `[manager-worker] [self-update] WEDGE: the in-flight latch has been held for ${heldMin}m, past the ${Math.round(SELF_UPDATE_LATCH_MAX_HOLD_MS / 6e4)}m bound. Breaking it and proceeding \u2014 the previous updater never settled (ENG-8624).`
12808
+ );
12809
+ }
12781
12810
  selfUpdateInFlight = true;
12811
+ selfUpdateInFlightSince = Date.now();
12782
12812
  try {
12783
12813
  const cliPath = process.argv[1] ?? "";
12784
12814
  const isDevMode = cliPath.includes("/src/") || cliPath.includes("tsx");
@@ -12813,6 +12843,7 @@ async function checkAndUpdateCli(opts) {
12813
12843
  return outcome;
12814
12844
  } finally {
12815
12845
  selfUpdateInFlight = false;
12846
+ selfUpdateInFlightSince = null;
12816
12847
  }
12817
12848
  }
12818
12849
  async function checkAndUpdateCliViaBrew(force = false) {
@@ -13620,7 +13651,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
13620
13651
  if (codeNames.length === 0) return;
13621
13652
  void (async () => {
13622
13653
  try {
13623
- const { collectDiagnostics } = await import("../persistent-session-LTFB4M53.js");
13654
+ const { collectDiagnostics } = await import("../persistent-session-PYAJ4VJW.js");
13624
13655
  await api.post("/host/heartbeat", {
13625
13656
  host_id: hostId,
13626
13657
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -13736,7 +13767,7 @@ async function pollCycleInner() {
13736
13767
  }
13737
13768
  try {
13738
13769
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
13739
- const { collectDiagnostics } = await import("../persistent-session-LTFB4M53.js");
13770
+ const { collectDiagnostics } = await import("../persistent-session-PYAJ4VJW.js");
13740
13771
  const diagCodeNames = [...agentState.persistentSessionAgents];
13741
13772
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor) : void 0;
13742
13773
  let tailscaleHostname;
@@ -13888,7 +13919,7 @@ async function pollCycleInner() {
13888
13919
  collectPanelessActivityProbes,
13889
13920
  getResponsivenessIntervalMs,
13890
13921
  occupancyQualificationClassifications
13891
- } = await import("../responsiveness-probe-P2S3UMRE.js");
13922
+ } = await import("../responsiveness-probe-5I2LIVCA.js");
13892
13923
  const probeIntervalMs = getResponsivenessIntervalMs();
13893
13924
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
13894
13925
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -13998,7 +14029,7 @@ async function pollCycleInner() {
13998
14029
  collectResponsivenessProbes,
13999
14030
  livePendingInboundOldestAgeSeconds,
14000
14031
  parkPendingInbound
14001
- } = await import("../responsiveness-probe-P2S3UMRE.js");
14032
+ } = await import("../responsiveness-probe-5I2LIVCA.js");
14002
14033
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
14003
14034
  const wedgeNow = /* @__PURE__ */ new Date();
14004
14035
  const liveAgents = agentState.persistentSessionAgents;
@@ -14154,7 +14185,7 @@ async function pollCycleInner() {
14154
14185
  }
14155
14186
  try {
14156
14187
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
14157
- const { probeSessionAuth } = await import("../session-auth-dead-YHSQBOB4.js");
14188
+ const { probeSessionAuth } = await import("../session-auth-dead-NUX643UJ.js");
14158
14189
  const observations = [];
14159
14190
  const pendingCacheCommits = [];
14160
14191
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -15301,7 +15332,12 @@ async function processAgent(agent, agentStates, managedToolkits) {
15301
15332
  team: slackTeamPeerUserIds !== void 0 ? { ...teamSettingsForHash, slack_team_peer_user_ids: slackTeamPeerUserIds } : teamSettingsForHash,
15302
15333
  peers: peersForHash,
15303
15334
  sessionMode: sessionModeForHash,
15304
- senderPolicy: senderPolicyForHash
15335
+ senderPolicy: senderPolicyForHash,
15336
+ // ENG-9350: fold the delivery mode in so a `spawn-inject-channel-
15337
+ // secrets` flip invalidates the cache and re-runs the writer (evict
15338
+ // on enable / restore on disable). Same per-agent value the writer
15339
+ // call below passes as channelSecretDelivery.
15340
+ channelSecretDelivery: shouldInjectChannelSecrets(agent.agent_id) ? "spawn-env" : "file"
15305
15341
  });
15306
15342
  const cacheKey = `${agent.agent_id}:${channelId}`;
15307
15343
  let onDiskPresent = true;
@@ -15353,7 +15389,14 @@ async function processAgent(agent, agentStates, managedToolkits) {
15353
15389
  slackTeamPeerUserIds,
15354
15390
  agentTimezone,
15355
15391
  senderPolicy: senderPolicyForCall,
15356
- agentAvatarUrl
15392
+ agentAvatarUrl,
15393
+ // ENG-9350 (epic ENG-9347): in spawn-env mode the writer null-
15394
+ // deletes the channel token from `.env.integrations` (evicting any
15395
+ // stale copy) and leaves the `.mcp.json` `${VAR}` template — the
15396
+ // manager injects the value at spawn via `tmux -e` instead. The
15397
+ // `.mcp.json` server entry is still written, so the landed check
15398
+ // below (which reads `.mcp.json`, not the file) is unaffected.
15399
+ channelSecretDelivery: shouldInjectChannelSecrets(agent.agent_id) ? "spawn-env" : "file"
15357
15400
  }
15358
15401
  );
15359
15402
  const landed = frameworkAdapter.hasChannelCredentials?.(agent.code_name, channelId) ?? true;
@@ -16506,7 +16549,11 @@ async function processAgent(agent, agentStates, managedToolkits) {
16506
16549
  }
16507
16550
  if (channelConfigConvergedThisTick) {
16508
16551
  try {
16509
- checkChannelSecretDriftAndScheduleRestart(agent.code_name, getProjectDir(agent.code_name));
16552
+ checkChannelSecretDriftAndScheduleRestart(
16553
+ agent.code_name,
16554
+ getProjectDir(agent.code_name),
16555
+ shouldInjectChannelSecrets(agent.agent_id) ? collectChannelSpawnSecrets(refreshData.channel_configs) : void 0
16556
+ );
16510
16557
  } catch (err) {
16511
16558
  log(`[hot-reload] channel-secret drift check failed for '${agent.code_name}': ${err.message}`);
16512
16559
  }
@@ -17533,6 +17580,13 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash17("sha256")
17533
17580
  // ADR-0042 pt3b (ENG-7607 / ENG-8992): this agent's own org-scoped key
17534
17581
  // (null when unarmed). The spawn env carries it as this agent's AGT_API_KEY.
17535
17582
  perAgentApiKey,
17583
+ // ENG-9350 (epic ENG-9347): when `spawn-inject-channel-secrets` is ON for
17584
+ // this agent, deliver its channel bot tokens through the spawn env (`tmux
17585
+ // -e`) instead of the on-disk `.env.integrations` file (which the writer
17586
+ // above evicted). Undefined ⇒ file-sourced delivery, unchanged. Derived
17587
+ // from the same channel_configs the writer used, via the shared core helper
17588
+ // so the KEYS/VALUES can't diverge from what would have been persisted.
17589
+ channelSpawnSecrets: shouldInjectChannelSecrets(agent.agent_id) ? collectChannelSpawnSecrets(channelConfigs) : void 0,
17536
17590
  log
17537
17591
  });
17538
17592
  agentState.persistentSessionAgents.add(codeName);
@@ -17891,7 +17945,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
17891
17945
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
17892
17946
  void (async () => {
17893
17947
  try {
17894
- const { collectDiagnostics } = await import("../persistent-session-LTFB4M53.js");
17948
+ const { collectDiagnostics } = await import("../persistent-session-PYAJ4VJW.js");
17895
17949
  await api.post("/host/heartbeat", {
17896
17950
  host_id: hostId,
17897
17951
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -17942,7 +17996,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
17942
17996
  }
17943
17997
  try {
17944
17998
  const hostId = await getHostId();
17945
- const { collectDiagnostics } = await import("../persistent-session-LTFB4M53.js");
17999
+ const { collectDiagnostics } = await import("../persistent-session-PYAJ4VJW.js");
17946
18000
  await api.post("/host/heartbeat", {
17947
18001
  host_id: hostId,
17948
18002
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -18573,7 +18627,7 @@ async function processClaudePairSessions(agents) {
18573
18627
  killPairSession,
18574
18628
  pairTmuxSession,
18575
18629
  finalizeClaudePairOnboarding
18576
- } = await import("../claude-pair-runtime-ANNQRKO4.js");
18630
+ } = await import("../claude-pair-runtime-UZ2JB2KY.js");
18577
18631
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
18578
18632
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
18579
18633
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -19755,6 +19809,7 @@ export {
19755
19809
  REALTIME_REBIND_IN_FLIGHT_GRACE_MS,
19756
19810
  REALTIME_REBIND_MAX_BACKOFF_MS,
19757
19811
  REALTIME_REBIND_STUCK_AFTER_MS,
19812
+ SELF_UPDATE_LATCH_MAX_HOLD_MS,
19758
19813
  UntrustworthyToolkitResponseError,
19759
19814
  applyMemoryTombstones,
19760
19815
  applyRestartAcks,
@@ -19798,6 +19853,7 @@ export {
19798
19853
  restartReasonBindsNewMcp,
19799
19854
  retiredMemoryDir,
19800
19855
  sameChannelSet,
19856
+ selfUpdateLatchVerdict,
19801
19857
  shouldLogChannelSyncFailure,
19802
19858
  shouldReapOnRetag,
19803
19859
  shouldReportRestartToAudit,