@integrity-labs/agt-cli 0.28.757 → 0.28.759

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 (23) hide show
  1. package/dist/bin/agt.js +5 -5
  2. package/dist/{chunk-JB2LZVNB.js → chunk-4GGLPSVH.js} +2 -2
  3. package/dist/{chunk-45KFVLO4.js → chunk-SD2Y6ZOB.js} +71 -4
  4. package/dist/{chunk-45KFVLO4.js.map → chunk-SD2Y6ZOB.js.map} +1 -1
  5. package/dist/{chunk-43TIELP4.js → chunk-YAONHJW6.js} +4 -4
  6. package/dist/{claude-pair-runtime-MQMZT4AM.js → claude-pair-runtime-I6Q7M7KZ.js} +2 -2
  7. package/dist/lib/manager-worker.js +138 -28
  8. package/dist/lib/manager-worker.js.map +1 -1
  9. package/dist/mcp/direct-chat-channel.js +3 -0
  10. package/dist/mcp/index.js +3 -0
  11. package/dist/mcp/origami.js +3 -0
  12. package/dist/mcp/slack-channel.js +3 -0
  13. package/dist/mcp/telegram-channel.js +3 -0
  14. package/dist/{persistent-session-UVO7INXO.js → persistent-session-IUGL5OEF.js} +3 -3
  15. package/dist/{responsiveness-probe-3F3O7D7H.js → responsiveness-probe-N7QDT6AE.js} +3 -3
  16. package/dist/{session-auth-dead-Z6TCXJ4R.js → session-auth-dead-VE5NYGT7.js} +2 -2
  17. package/package.json +1 -1
  18. /package/dist/{chunk-JB2LZVNB.js.map → chunk-4GGLPSVH.js.map} +0 -0
  19. /package/dist/{chunk-43TIELP4.js.map → chunk-YAONHJW6.js.map} +0 -0
  20. /package/dist/{claude-pair-runtime-MQMZT4AM.js.map → claude-pair-runtime-I6Q7M7KZ.js.map} +0 -0
  21. /package/dist/{persistent-session-UVO7INXO.js.map → persistent-session-IUGL5OEF.js.map} +0 -0
  22. /package/dist/{responsiveness-probe-3F3O7D7H.js.map → responsiveness-probe-N7QDT6AE.js.map} +0 -0
  23. /package/dist/{session-auth-dead-Z6TCXJ4R.js.map → session-auth-dead-VE5NYGT7.js.map} +0 -0
@@ -13,7 +13,7 @@ import {
13
13
  parseEnvFileEntries,
14
14
  parseEnvIntegrations,
15
15
  shellQuote
16
- } from "./chunk-JB2LZVNB.js";
16
+ } from "./chunk-4GGLPSVH.js";
17
17
  import {
18
18
  BIND_FAILURE_QUARANTINE_THRESHOLD,
19
19
  INTEGRATIONS_SECTION_END,
@@ -63,7 +63,7 @@ import {
63
63
  sessionTranscriptDir,
64
64
  worseConnectivityOutcome,
65
65
  wrapScheduledTaskPrompt
66
- } from "./chunk-45KFVLO4.js";
66
+ } from "./chunk-SD2Y6ZOB.js";
67
67
  import {
68
68
  parsePsRows
69
69
  } from "./chunk-XWVM4KPK.js";
@@ -6436,7 +6436,7 @@ function exchangeFailureKind(err) {
6436
6436
  }
6437
6437
 
6438
6438
  // src/lib/api-client.ts
6439
- var agtCliVersion = true ? "0.28.757" : "dev";
6439
+ var agtCliVersion = true ? "0.28.759" : "dev";
6440
6440
  var lastConfigHash = null;
6441
6441
  function setConfigHash(hash) {
6442
6442
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -10593,4 +10593,4 @@ export {
10593
10593
  managerInstallSystemUnitCommand,
10594
10594
  managerUninstallSystemUnitCommand
10595
10595
  };
10596
- //# sourceMappingURL=chunk-43TIELP4.js.map
10596
+ //# sourceMappingURL=chunk-YAONHJW6.js.map
@@ -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-UVO7INXO.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-IUGL5OEF.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-MQMZT4AM.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-I6Q7M7KZ.js.map
@@ -58,7 +58,7 @@ import {
58
58
  safeWriteJsonAtomic,
59
59
  setConfigHash,
60
60
  tripClass
61
- } from "../chunk-43TIELP4.js";
61
+ } from "../chunk-YAONHJW6.js";
62
62
  import {
63
63
  getProjectDir as getProjectDir2,
64
64
  getReadyTasks,
@@ -119,7 +119,7 @@ import {
119
119
  takeZombieDetection,
120
120
  toOpencodeModel,
121
121
  writeEgressAllowlist
122
- } from "../chunk-JB2LZVNB.js";
122
+ } from "../chunk-4GGLPSVH.js";
123
123
  import {
124
124
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
125
125
  AnchorSessionClient,
@@ -208,7 +208,7 @@ import {
208
208
  subagentActivityAgeSeconds,
209
209
  sumTranscriptUsageInWindow,
210
210
  transcriptActivityAgeSeconds
211
- } from "../chunk-45KFVLO4.js";
211
+ } from "../chunk-SD2Y6ZOB.js";
212
212
  import {
213
213
  reapOrphanChannelMcps
214
214
  } from "../chunk-XWVM4KPK.js";
@@ -393,6 +393,7 @@ function decideManagedMcpRestart(input) {
393
393
  const { prevStructureHash, structureHash, launchStructureHash, sessionHealthy, flapping } = input;
394
394
  if (prevStructureHash === void 0) return { kind: "skip-first-convergence" };
395
395
  if (structureHash === prevStructureHash) return { kind: "skip-no-change" };
396
+ if (input.deferringPrune === true) return { kind: "skip-prune-deferred" };
396
397
  if (!sessionHealthy) return { kind: "skip-unhealthy" };
397
398
  if (flapping) return { kind: "skip-flapping" };
398
399
  if (launchStructureHash != null && launchStructureHash === structureHash) {
@@ -6451,6 +6452,75 @@ function withScheduleLinkFooter(opts) {
6451
6452
  return appendScheduleLinkFooter(opts.body, url, opts.medium);
6452
6453
  }
6453
6454
 
6455
+ // src/lib/manager/managed-prune-streak.ts
6456
+ var DEFAULT_PRUNE_CONFIRM_CYCLES = 5;
6457
+ function pruneConfirmCycles(env = process.env) {
6458
+ const raw = env["AUGMENTED_MANAGED_PRUNE_CONFIRM_CYCLES"];
6459
+ if (raw === void 0) return DEFAULT_PRUNE_CONFIRM_CYCLES;
6460
+ const trimmed = raw.trim();
6461
+ if (!/^\d+$/.test(trimmed)) return DEFAULT_PRUNE_CONFIRM_CYCLES;
6462
+ const n = Number(trimmed);
6463
+ if (!Number.isSafeInteger(n) || n < 1) return DEFAULT_PRUNE_CONFIRM_CYCLES;
6464
+ return n;
6465
+ }
6466
+ var ManagedPruneStreaks = class {
6467
+ constructor(threshold = DEFAULT_PRUNE_CONFIRM_CYCLES) {
6468
+ this.threshold = threshold;
6469
+ }
6470
+ streaks = /* @__PURE__ */ new Map();
6471
+ /**
6472
+ * Record one poll cycle for one agent.
6473
+ *
6474
+ * MUST BE CALLED ON EVERY CYCLE, including cycles where nothing changed —
6475
+ * see the trap above. `declaredManagedKeys` is what the agent's config
6476
+ * currently declares; `expectedKeys` is what the API says it should have.
6477
+ *
6478
+ * A key present in `expectedKeys` has its streak cleared IMMEDIATELY, which is
6479
+ * what makes a toolkit's reappearance undo the wait rather than merely pause
6480
+ * it.
6481
+ *
6482
+ * Returns a decision per absent key, in the order given, so the caller can log
6483
+ * the deferrals as well as act on the matured ones.
6484
+ */
6485
+ observe(agentId, declaredManagedKeys, expectedKeys) {
6486
+ let perAgent = this.streaks.get(agentId);
6487
+ if (perAgent) {
6488
+ for (const key of expectedKeys) perAgent.delete(key);
6489
+ }
6490
+ const decisions = [];
6491
+ for (const key of declaredManagedKeys) {
6492
+ if (expectedKeys.has(key)) continue;
6493
+ if (!perAgent) {
6494
+ perAgent = /* @__PURE__ */ new Map();
6495
+ this.streaks.set(agentId, perAgent);
6496
+ }
6497
+ const streak = (perAgent.get(key) ?? 0) + 1;
6498
+ perAgent.set(key, streak);
6499
+ decisions.push({ serverKey: key, streak, mature: streak >= this.threshold });
6500
+ }
6501
+ if (perAgent) {
6502
+ const declared = new Set(declaredManagedKeys);
6503
+ for (const key of [...perAgent.keys()]) {
6504
+ if (!declared.has(key)) perAgent.delete(key);
6505
+ }
6506
+ if (perAgent.size === 0) this.streaks.delete(agentId);
6507
+ }
6508
+ return decisions;
6509
+ }
6510
+ /** Current streak for one key. Zero when untracked. */
6511
+ streakFor(agentId, serverKey) {
6512
+ return this.streaks.get(agentId)?.get(serverKey) ?? 0;
6513
+ }
6514
+ /** Drop everything for an agent — used when an agent leaves the host. */
6515
+ forget(agentId) {
6516
+ this.streaks.delete(agentId);
6517
+ }
6518
+ /** Number of agents currently carrying at least one streak (tests/diagnostics). */
6519
+ get trackedAgents() {
6520
+ return this.streaks.size;
6521
+ }
6522
+ };
6523
+
6454
6524
  // src/lib/manager/agent-state.ts
6455
6525
  var agentState = {
6456
6526
  // ---------------------------------------------------------------------------
@@ -6558,7 +6628,19 @@ var agentState = {
6558
6628
  * it, so an unpublish during a restart window leaves the folder until the next
6559
6629
  * unpublish — acceptable for a platform-staff-rare action.
6560
6630
  */
6561
- knownGlobalSkillIds: /* @__PURE__ */ new Map()
6631
+ knownGlobalSkillIds: /* @__PURE__ */ new Map(),
6632
+ /**
6633
+ * ENG-9708: consecutive cycles each managed MCP server key has been ABSENT
6634
+ * from /host/managed-toolkits, per agent. A key must miss N consecutive polls
6635
+ * before it is pruned, so one degraded-but-well-formed response can no longer
6636
+ * destroy fleet state that does not self-heal (2026-08-31: 24 composio_*
6637
+ * servers across 6+ agents, removed in under two minutes, recovered only by a
6638
+ * manual bulk-reconnect).
6639
+ *
6640
+ * In-memory on purpose: a manager restart clears every streak, which delays a
6641
+ * legitimate prune by a few minutes and can never cause a spurious one.
6642
+ */
6643
+ managedPruneStreaks: new ManagedPruneStreaks(pruneConfirmCycles())
6562
6644
  };
6563
6645
  function clearAgentState(agentId, codeName) {
6564
6646
  agentState.knownVersions.delete(agentId);
@@ -6577,6 +6659,7 @@ function clearAgentState(agentId, codeName) {
6577
6659
  agentState.knownMsTeamsBehaviourHashes.delete(agentId);
6578
6660
  agentState.knownSlackBehaviourHashes.delete(agentId);
6579
6661
  agentState.knownGlobalSkillIds.delete(agentId);
6662
+ agentState.managedPruneStreaks.forget(agentId);
6580
6663
  agentState.agentDisplayNames.delete(codeName);
6581
6664
  agentState.codeNameToAgentId.delete(codeName);
6582
6665
  agentState.provisioningAttribution.delete(codeName);
@@ -12725,7 +12808,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
12725
12808
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
12726
12809
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
12727
12810
  async function channelInboundActivityAgeSecondsFor(codeName) {
12728
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-3F3O7D7H.js");
12811
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-N7QDT6AE.js");
12729
12812
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
12730
12813
  if (newest === null) return null;
12731
12814
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -13385,7 +13468,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
13385
13468
  var lastVersionCheckAt = 0;
13386
13469
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13387
13470
  var lastResponsivenessProbeAt = 0;
13388
- var agtCliVersion = true ? "0.28.757" : "dev";
13471
+ var agtCliVersion = true ? "0.28.759" : "dev";
13389
13472
  function resolveBrewPath(execFileSync3) {
13390
13473
  try {
13391
13474
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14926,7 +15009,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
14926
15009
  if (codeNames.length === 0) return;
14927
15010
  void (async () => {
14928
15011
  try {
14929
- const { collectDiagnostics } = await import("../persistent-session-UVO7INXO.js");
15012
+ const { collectDiagnostics } = await import("../persistent-session-IUGL5OEF.js");
14930
15013
  await api.post("/host/heartbeat", {
14931
15014
  host_id: hostId,
14932
15015
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -15067,7 +15150,7 @@ async function pollCycleInner() {
15067
15150
  }
15068
15151
  try {
15069
15152
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
15070
- const { collectDiagnostics } = await import("../persistent-session-UVO7INXO.js");
15153
+ const { collectDiagnostics } = await import("../persistent-session-IUGL5OEF.js");
15071
15154
  const diagCodeNames = [...agentState.persistentSessionAgents];
15072
15155
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor) : void 0;
15073
15156
  let tailscaleHostname;
@@ -15236,7 +15319,7 @@ async function pollCycleInner() {
15236
15319
  collectPanelessActivityProbes,
15237
15320
  getResponsivenessIntervalMs,
15238
15321
  occupancyQualificationClassifications
15239
- } = await import("../responsiveness-probe-3F3O7D7H.js");
15322
+ } = await import("../responsiveness-probe-N7QDT6AE.js");
15240
15323
  const probeIntervalMs = getResponsivenessIntervalMs();
15241
15324
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
15242
15325
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -15346,7 +15429,7 @@ async function pollCycleInner() {
15346
15429
  collectResponsivenessProbes,
15347
15430
  livePendingInboundOldestAgeSeconds,
15348
15431
  parkPendingInbound
15349
- } = await import("../responsiveness-probe-3F3O7D7H.js");
15432
+ } = await import("../responsiveness-probe-N7QDT6AE.js");
15350
15433
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
15351
15434
  const wedgeNow = /* @__PURE__ */ new Date();
15352
15435
  const liveAgents = agentState.persistentSessionAgents;
@@ -15502,7 +15585,7 @@ async function pollCycleInner() {
15502
15585
  }
15503
15586
  try {
15504
15587
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
15505
- const { probeSessionAuth } = await import("../session-auth-dead-Z6TCXJ4R.js");
15588
+ const { probeSessionAuth } = await import("../session-auth-dead-VE5NYGT7.js");
15506
15589
  const observations = [];
15507
15590
  const pendingCacheCommits = [];
15508
15591
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -17532,32 +17615,59 @@ async function processAgent(agent, agentStates, managedToolkits) {
17532
17615
  );
17533
17616
  recordConfigChurnEvent(agent.agent_id, agent.code_name, FLAP_CHANNEL_MANAGED_MCP, mcpMembership);
17534
17617
  }
17618
+ const deferredPruneKeys = [];
17619
+ if (frameworkAdapter.removeMcpServer && frameworkAdapter.readMcpServers) {
17620
+ try {
17621
+ const declaredManaged = Object.keys(
17622
+ frameworkAdapter.readMcpServers(agent.code_name)
17623
+ ).filter(isManagedMcpServerKey);
17624
+ const decisions = agentState.managedPruneStreaks.observe(
17625
+ agent.agent_id,
17626
+ declaredManaged,
17627
+ expectedServerIds
17628
+ );
17629
+ for (const d of decisions) {
17630
+ if (!d.mature) {
17631
+ deferredPruneKeys.push(d.serverKey);
17632
+ log(
17633
+ `[managed-toolkit] ${agent.code_name}: '${d.serverKey}' absent for ${d.streak}/${pruneConfirmCycles()} cycles \u2014 deferring prune (ENG-9708)`
17634
+ );
17635
+ continue;
17636
+ }
17637
+ frameworkAdapter.removeMcpServer(agent.code_name, d.serverKey);
17638
+ log(
17639
+ `[managed-toolkit] Removed stale MCP server '${d.serverKey}' for '${agent.code_name}' after ${d.streak} consecutive absences (ENG-9708)`
17640
+ );
17641
+ managedPruneLedger.record(agent.code_name, d.serverKey);
17642
+ }
17643
+ } catch {
17644
+ }
17645
+ }
17535
17646
  if (mcpHash !== prevMcpHash) {
17536
17647
  for (const e of desiredEntries) {
17537
17648
  frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
17538
17649
  const urlHash = createHash20("sha256").update(e.url).digest("hex").slice(0, 12);
17539
17650
  log(`[managed-toolkit] ${agent.code_name}: wrote '${e.name}' (serverId=${e.serverId}, url_hash=${urlHash})`);
17540
17651
  }
17541
- if (frameworkAdapter.removeMcpServer && frameworkAdapter.readMcpServers) {
17542
- try {
17543
- for (const key of Object.keys(frameworkAdapter.readMcpServers(agent.code_name))) {
17544
- if (isManagedMcpServerKey(key) && !expectedServerIds.has(key)) {
17545
- frameworkAdapter.removeMcpServer(agent.code_name, key);
17546
- log(`[managed-toolkit] Removed stale MCP server '${key}' for '${agent.code_name}'`);
17547
- managedPruneLedger.record(agent.code_name, key);
17548
- }
17549
- }
17550
- } catch {
17551
- }
17652
+ if (deferredPruneKeys.length === 0) {
17653
+ agentState.knownManagedMcpHashes.set(agent.agent_id, mcpHash);
17654
+ agentState.knownManagedMcpStructure.set(agent.agent_id, structureHash);
17655
+ } else {
17656
+ log(
17657
+ `[managed-toolkit] ${agent.code_name}: holding the managed-MCP baseline and session restart while ${deferredPruneKeys.length} prune(s) await confirmation (${deferredPruneKeys.join(", ")}) \u2014 ENG-9708`
17658
+ );
17552
17659
  }
17553
- agentState.knownManagedMcpHashes.set(agent.agent_id, mcpHash);
17554
- agentState.knownManagedMcpStructure.set(agent.agent_id, structureHash);
17555
17660
  const mcpRestartDecision = fwForMcp === "claude-code" && prevStructureHash !== void 0 && structureHash !== prevStructureHash ? decideManagedMcpRestart({
17556
17661
  prevStructureHash,
17557
17662
  structureHash,
17558
17663
  launchStructureHash: sessionLaunchManagedStructure.get(agent.code_name),
17559
17664
  sessionHealthy: isSessionHealthy(agent.code_name),
17560
- flapping: mcpFlap.flapping
17665
+ flapping: mcpFlap.flapping,
17666
+ // ENG-9708: an unconfirmed prune holds the restart too. The
17667
+ // structural change it would announce ("servers were removed")
17668
+ // has not been applied to the file yet, so restarting now
17669
+ // would churn the session and tell the agent something untrue.
17670
+ deferringPrune: deferredPruneKeys.length > 0
17561
17671
  }) : null;
17562
17672
  if (mcpRestartDecision?.kind === "suppress-already-live") {
17563
17673
  log(
@@ -19453,7 +19563,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
19453
19563
  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}`));
19454
19564
  void (async () => {
19455
19565
  try {
19456
- const { collectDiagnostics } = await import("../persistent-session-UVO7INXO.js");
19566
+ const { collectDiagnostics } = await import("../persistent-session-IUGL5OEF.js");
19457
19567
  await api.post("/host/heartbeat", {
19458
19568
  host_id: hostId,
19459
19569
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -19499,7 +19609,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
19499
19609
  }
19500
19610
  try {
19501
19611
  const hostId = await getHostId();
19502
- const { collectDiagnostics } = await import("../persistent-session-UVO7INXO.js");
19612
+ const { collectDiagnostics } = await import("../persistent-session-IUGL5OEF.js");
19503
19613
  await api.post("/host/heartbeat", {
19504
19614
  host_id: hostId,
19505
19615
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -20135,7 +20245,7 @@ async function processClaudePairSessions(agents) {
20135
20245
  killPairSession,
20136
20246
  pairTmuxSession,
20137
20247
  finalizeClaudePairOnboarding
20138
- } = await import("../claude-pair-runtime-MQMZT4AM.js");
20248
+ } = await import("../claude-pair-runtime-I6Q7M7KZ.js");
20139
20249
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
20140
20250
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
20141
20251
  const killed = await killPairSession(pairTmuxSession(pairId));