@integrity-labs/agt-cli 0.28.273 → 0.28.274

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.
@@ -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-UQNLB3UF.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-SDDSZN5E.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-WVZRDAFK.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-Z726QSAR.js.map
@@ -38,7 +38,7 @@ import {
38
38
  requireHost,
39
39
  safeWriteJsonAtomic,
40
40
  setConfigHash
41
- } from "../chunk-NKNOIJMC.js";
41
+ } from "../chunk-73NA6BKT.js";
42
42
  import {
43
43
  getProjectDir as getProjectDir2,
44
44
  getReadyTasks,
@@ -125,7 +125,7 @@ import {
125
125
  takeZombieDetection,
126
126
  transcriptActivityAgeSeconds,
127
127
  writeEgressAllowlist
128
- } from "../chunk-PNETKYLF.js";
128
+ } from "../chunk-THMHJITM.js";
129
129
  import {
130
130
  reapOrphanChannelMcps
131
131
  } from "../chunk-XWVM4KPK.js";
@@ -611,8 +611,27 @@ function isQuarantineFile(value) {
611
611
  function reaperRestartBreakerReason(activeKeys) {
612
612
  return activeKeys.length >= 2 ? "mcp-presence-reaper" : void 0;
613
613
  }
614
+ var PROVISIONING_RELOAD_REASONS = /* @__PURE__ */ new Set([
615
+ "hot-reload-mcp",
616
+ "managed-mcp-churn",
617
+ "bind-remediation"
618
+ ]);
619
+ function isProvisioningReloadReason(reason) {
620
+ return PROVISIONING_RELOAD_REASONS.has(reason);
621
+ }
622
+ function countByClass(events) {
623
+ let crash = 0;
624
+ let provisioning = 0;
625
+ for (const e of events) {
626
+ if (isProvisioningReloadReason(e.reason)) provisioning += 1;
627
+ else crash += 1;
628
+ }
629
+ return { crash, provisioning };
630
+ }
614
631
  var DEFAULT_MAX = 2;
615
632
  var DEFAULT_WINDOW_MS = 6e5;
633
+ var DEFAULT_PROVISIONING_MAX = 5;
634
+ var DEFAULT_PROVISIONING_WINDOW_MS = 18e5;
616
635
  function readEnvNumber(name, fallback) {
617
636
  const raw = process.env[name];
618
637
  if (!raw) return fallback;
@@ -622,12 +641,18 @@ function readEnvNumber(name, fallback) {
622
641
  var RestartBreaker = class {
623
642
  max;
624
643
  windowMs;
644
+ provisioningMax;
645
+ provisioningWindowMs;
646
+ /** Longest window either tally needs — how long the events log must retain. */
647
+ retentionMs;
625
648
  now;
626
649
  events = /* @__PURE__ */ new Map();
627
650
  trips = /* @__PURE__ */ new Map();
628
651
  constructor(opts = {}) {
629
652
  this.max = opts.max ?? readEnvNumber("AGT_RESTART_BREAKER_MAX", DEFAULT_MAX);
630
653
  this.windowMs = opts.windowMs ?? readEnvNumber("AGT_RESTART_BREAKER_WINDOW_MS", DEFAULT_WINDOW_MS);
654
+ this.provisioningMax = opts.provisioningMax ?? readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_MAX", DEFAULT_PROVISIONING_MAX);
655
+ this.provisioningWindowMs = opts.provisioningWindowMs ?? readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_WINDOW_MS", DEFAULT_PROVISIONING_WINDOW_MS);
631
656
  this.now = opts.now ?? Date.now;
632
657
  if (!Number.isFinite(this.max) || this.max < 1) {
633
658
  throw new Error("restart-breaker max must be a finite number >= 1");
@@ -635,6 +660,13 @@ var RestartBreaker = class {
635
660
  if (!Number.isFinite(this.windowMs) || this.windowMs < 1e3) {
636
661
  throw new Error("restart-breaker windowMs must be a finite number >= 1000");
637
662
  }
663
+ if (!Number.isFinite(this.provisioningMax) || this.provisioningMax < 1) {
664
+ throw new Error("restart-breaker provisioningMax must be a finite number >= 1");
665
+ }
666
+ if (!Number.isFinite(this.provisioningWindowMs) || this.provisioningWindowMs < 1e3) {
667
+ throw new Error("restart-breaker provisioningWindowMs must be a finite number >= 1000");
668
+ }
669
+ this.retentionMs = Math.max(this.windowMs, this.provisioningWindowMs);
638
670
  }
639
671
  /** True if this agent's breaker is currently tripped (manager must skip spawn). */
640
672
  isTripped(codeName) {
@@ -655,24 +687,54 @@ var RestartBreaker = class {
655
687
  record(codeName, reason) {
656
688
  const existing = this.trips.get(codeName);
657
689
  if (existing) {
658
- return { tripped: false, trip: existing, windowCount: existing.eventsAtTrip.length };
690
+ return {
691
+ tripped: false,
692
+ trip: existing,
693
+ windowCount: existing.eventsAtTrip.length,
694
+ classCounts: countByClass(existing.eventsAtTrip)
695
+ };
659
696
  }
660
697
  const at = this.now();
661
- const cutoff = at - this.windowMs;
662
- const prior = (this.events.get(codeName) ?? []).filter((e) => e.at >= cutoff);
698
+ const retentionCutoff = at - this.retentionMs;
699
+ const prior = (this.events.get(codeName) ?? []).filter((e) => e.at >= retentionCutoff);
663
700
  prior.push({ reason, at });
664
701
  this.events.set(codeName, prior);
665
- if (prior.length > this.max) {
702
+ const crashCount = prior.filter(
703
+ (e) => e.at >= at - this.windowMs && !isProvisioningReloadReason(e.reason)
704
+ ).length;
705
+ const provEvents = prior.filter(
706
+ (e) => e.at >= at - this.provisioningWindowMs && isProvisioningReloadReason(e.reason)
707
+ );
708
+ const windowCount = prior.filter((e) => e.at >= at - this.windowMs).length;
709
+ const classCounts = {
710
+ crash: crashCount,
711
+ provisioning: provEvents.length
712
+ };
713
+ let trippedClass;
714
+ let tripEvents;
715
+ let tripWindowMs = this.windowMs;
716
+ if (crashCount > this.max) {
717
+ trippedClass = "crash";
718
+ tripEvents = prior.filter(
719
+ (e) => e.at >= at - this.windowMs && !isProvisioningReloadReason(e.reason)
720
+ );
721
+ tripWindowMs = this.windowMs;
722
+ } else if (provEvents.length > this.provisioningMax) {
723
+ trippedClass = "provisioning";
724
+ tripEvents = provEvents;
725
+ tripWindowMs = this.provisioningWindowMs;
726
+ }
727
+ if (trippedClass && tripEvents) {
666
728
  const trip = {
667
729
  trippedAt: at,
668
- eventsAtTrip: [...prior],
669
- statusMessage: formatStatusMessage(prior, this.windowMs)
730
+ eventsAtTrip: [...tripEvents],
731
+ statusMessage: formatStatusMessage(tripEvents, tripWindowMs, trippedClass)
670
732
  };
671
733
  this.trips.set(codeName, trip);
672
734
  this.events.delete(codeName);
673
- return { tripped: true, trip, windowCount: prior.length };
735
+ return { tripped: true, trip, windowCount, classCounts, trippedClass };
674
736
  }
675
- return { tripped: false, windowCount: prior.length };
737
+ return { tripped: false, windowCount, classCounts };
676
738
  }
677
739
  /** Operator-initiated reset: drops the trip + the events log for this agent. */
678
740
  clear(codeName) {
@@ -703,13 +765,14 @@ var RestartBreaker = class {
703
765
  return (this.events.get(codeName) ?? []).filter((e) => e.at >= cutoff).length;
704
766
  }
705
767
  };
706
- function formatStatusMessage(events, windowMs) {
768
+ function formatStatusMessage(events, windowMs, klass = "crash") {
707
769
  const last = events[events.length - 1];
708
770
  const windowLabel = windowMs < 6e4 ? `${Math.round(windowMs / 1e3)}s` : `${(windowMs / 6e4).toFixed(1).replace(/\.0$/, "")}min`;
709
771
  const reasonCounts = /* @__PURE__ */ new Map();
710
772
  for (const e of events) reasonCounts.set(e.reason, (reasonCounts.get(e.reason) ?? 0) + 1);
711
773
  const breakdown = Array.from(reasonCounts.entries()).map(([r, n]) => `${r}=${n}`).join(", ");
712
- return `Circuit breaker tripped: ${events.length} restarts in ${windowLabel} (${breakdown}); most recent=${last.reason} at ${new Date(last.at).toISOString()}`;
774
+ const classLabel = klass === "provisioning" ? "provisioning-reload " : "";
775
+ return `Circuit breaker tripped: ${events.length} ${classLabel}restarts in ${windowLabel} (${breakdown}); most recent=${last.reason} at ${new Date(last.at).toISOString()}`;
713
776
  }
714
777
 
715
778
  // src/lib/mcp-flap-dampener.ts
@@ -5953,6 +6016,7 @@ var pendingSessionRestarts = /* @__PURE__ */ new Map();
5953
6016
  var pendingRestartVerifications = /* @__PURE__ */ new Map();
5954
6017
  var restartBreaker = new RestartBreaker();
5955
6018
  var reportedTrips = /* @__PURE__ */ new Map();
6019
+ var RESTART_BREAKER_PROVISIONING_MAX = readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_MAX", 5);
5956
6020
  var mcpFlapDampener = new McpFlapDampener();
5957
6021
  var FLAP_BREAKER_COOLDOWN_MS = readEnvNumber2(
5958
6022
  "AGT_MCP_FLAP_BREAKER_COOLDOWN_MS",
@@ -5992,7 +6056,14 @@ function recordRestartForBreaker(codeName, reason) {
5992
6056
  return;
5993
6057
  }
5994
6058
  const result = restartBreaker.record(codeName, reason);
5995
- if (!result.tripped || !result.trip) return;
6059
+ if (!result.tripped || !result.trip) {
6060
+ if (isProvisioningReloadReason(reason) && result.classCounts.provisioning >= RESTART_BREAKER_PROVISIONING_MAX) {
6061
+ log(
6062
+ `[restart-breaker] agent=${codeName} provisioning-reload churn at the trip bar: ${result.classCounts.provisioning} provisioning restarts in window (reason=${reason}); one more will auto-pause the agent \u2014 a freshly-added integration is likely churning (ENG-7560)`
6063
+ );
6064
+ }
6065
+ return;
6066
+ }
5996
6067
  const trip = result.trip;
5997
6068
  log(
5998
6069
  `[persistent-session-decision] agent=${codeName} decision=circuit-tripped detail=${JSON.stringify(trip.statusMessage)} (ENG-5441)`
@@ -6717,7 +6788,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6717
6788
  var lastVersionCheckAt = 0;
6718
6789
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6719
6790
  var lastResponsivenessProbeAt = 0;
6720
- var agtCliVersion = true ? "0.28.273" : "dev";
6791
+ var agtCliVersion = true ? "0.28.274" : "dev";
6721
6792
  function resolveBrewPath(execFileSync2) {
6722
6793
  try {
6723
6794
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7567,7 +7638,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
7567
7638
  if (codeNames.length === 0) return;
7568
7639
  void (async () => {
7569
7640
  try {
7570
- const { collectDiagnostics } = await import("../persistent-session-UQNLB3UF.js");
7641
+ const { collectDiagnostics } = await import("../persistent-session-SDDSZN5E.js");
7571
7642
  await api.post("/host/heartbeat", {
7572
7643
  host_id: hostId,
7573
7644
  agent_diagnostics: collectDiagnostics(codeNames)
@@ -7665,7 +7736,7 @@ async function pollCycle() {
7665
7736
  }
7666
7737
  try {
7667
7738
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7668
- const { collectDiagnostics } = await import("../persistent-session-UQNLB3UF.js");
7739
+ const { collectDiagnostics } = await import("../persistent-session-SDDSZN5E.js");
7669
7740
  const diagCodeNames = [...agentState.persistentSessionAgents];
7670
7741
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7671
7742
  let tailscaleHostname;
@@ -7813,7 +7884,7 @@ async function pollCycle() {
7813
7884
  const {
7814
7885
  collectResponsivenessProbes,
7815
7886
  getResponsivenessIntervalMs
7816
- } = await import("../responsiveness-probe-GVLCH2IM.js");
7887
+ } = await import("../responsiveness-probe-ODKT4WUR.js");
7817
7888
  const probeIntervalMs = getResponsivenessIntervalMs();
7818
7889
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
7819
7890
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7845,7 +7916,7 @@ async function pollCycle() {
7845
7916
  collectResponsivenessProbes,
7846
7917
  livePendingInboundOldestAgeSeconds,
7847
7918
  parkPendingInbound
7848
- } = await import("../responsiveness-probe-GVLCH2IM.js");
7919
+ } = await import("../responsiveness-probe-ODKT4WUR.js");
7849
7920
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
7850
7921
  const wedgeNow = /* @__PURE__ */ new Date();
7851
7922
  const liveAgents = agentState.persistentSessionAgents;
@@ -10731,7 +10802,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
10731
10802
  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}`));
10732
10803
  void (async () => {
10733
10804
  try {
10734
- const { collectDiagnostics } = await import("../persistent-session-UQNLB3UF.js");
10805
+ const { collectDiagnostics } = await import("../persistent-session-SDDSZN5E.js");
10735
10806
  await api.post("/host/heartbeat", {
10736
10807
  host_id: hostId,
10737
10808
  agent_diagnostics: collectDiagnostics([codeName])
@@ -10781,7 +10852,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
10781
10852
  }
10782
10853
  try {
10783
10854
  const hostId = await getHostId();
10784
- const { collectDiagnostics } = await import("../persistent-session-UQNLB3UF.js");
10855
+ const { collectDiagnostics } = await import("../persistent-session-SDDSZN5E.js");
10785
10856
  await api.post("/host/heartbeat", {
10786
10857
  host_id: hostId,
10787
10858
  agent_diagnostics: collectDiagnostics([codeName])
@@ -11185,7 +11256,7 @@ async function processClaudePairSessions(agents) {
11185
11256
  killPairSession,
11186
11257
  pairTmuxSession,
11187
11258
  finalizeClaudePairOnboarding
11188
- } = await import("../claude-pair-runtime-WVZRDAFK.js");
11259
+ } = await import("../claude-pair-runtime-Z726QSAR.js");
11189
11260
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
11190
11261
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
11191
11262
  const killed = await killPairSession(pairTmuxSession(pairId));