@integrity-labs/agt-cli 0.28.452 → 0.28.454

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-7HZXY56P.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-X5N7UFEF.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-RCH4LKDE.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-NRKOKQYR.js.map
@@ -42,7 +42,7 @@ import {
42
42
  resolveEffectivePinRaw,
43
43
  safeWriteJsonAtomic,
44
44
  setConfigHash
45
- } from "../chunk-WOZINHUT.js";
45
+ } from "../chunk-23E2T5UT.js";
46
46
  import {
47
47
  getProjectDir as getProjectDir2,
48
48
  getReadyTasks,
@@ -53,6 +53,7 @@ import {
53
53
  import {
54
54
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
55
55
  AnchorSessionClient,
56
+ BIND_FAILURE_QUARANTINE_THRESHOLD,
56
57
  CLAUDE_MD_MAX_CHARS,
57
58
  CONVERSATION_FAILURE_CATEGORIES,
58
59
  DEFAULT_FRAMEWORK,
@@ -63,6 +64,9 @@ import {
63
64
  KANBAN_CHECK_COMMAND,
64
65
  KANBAN_NUDGE_ACTIONABLE_STATUSES,
65
66
  MAX_AVATAR_ENV_URL_BYTES,
67
+ MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING,
68
+ RESTART_BREAKER_PROVISIONING_MAX,
69
+ RESTART_BREAKER_PROVISIONING_WINDOW_MS,
66
70
  SCHEDULED_TURN_MARKER_FILENAME,
67
71
  SUPPRESS_SENTINEL,
68
72
  StreamEncoder,
@@ -160,7 +164,7 @@ import {
160
164
  toOpencodeModel,
161
165
  transcriptActivityAgeSeconds,
162
166
  writeEgressAllowlist
163
- } from "../chunk-ESZRW7A3.js";
167
+ } from "../chunk-3NJHNIO3.js";
164
168
  import {
165
169
  reapOrphanChannelMcps
166
170
  } from "../chunk-XWVM4KPK.js";
@@ -844,7 +848,13 @@ function reaperRestartBreakerReason(activeKeys) {
844
848
  var KNOWN_REASON_CLASS_MAP = {
845
849
  crash: true,
846
850
  provisioning: true,
847
- "credential-rotation": true
851
+ "credential-rotation": true,
852
+ // ENG-8215: the self-healing class (bind-remediation - the manager's OWN
853
+ // repair attempts, which must never count toward a trip). Adding it here is
854
+ // forced by the Record type, which is exactly why that shape was chosen over
855
+ // a Set literal (ENG-7577, CodeRabbit on #3861) - a new union member cannot
856
+ // be silently omitted from the rehydration allowlist.
857
+ "self-healing": true
848
858
  };
849
859
  var KNOWN_REASON_CLASSES = new Set(
850
860
  Object.keys(KNOWN_REASON_CLASS_MAP)
@@ -852,7 +862,10 @@ var KNOWN_REASON_CLASSES = new Set(
852
862
  var PROVISIONING_RELOAD_REASONS = /* @__PURE__ */ new Set([
853
863
  "hot-reload-mcp",
854
864
  "managed-mcp-churn",
855
- "bind-remediation",
865
+ // ENG-8215: 'bind-remediation' MOVED OUT of this set into SELF_HEALING_REASONS.
866
+ // It is the manager repairing itself, not a config reload, and counting it
867
+ // meant the harder the platform tried to fix an agent the more certain it
868
+ // became that it should give up. Deliberately NOT re-added here.
856
869
  // ENG-7576: the dashboard integration-add stop itself - the first restart of
857
870
  // the very burst this class exists for, previously uncounted entirely.
858
871
  "integration-change",
@@ -876,21 +889,35 @@ var CREDENTIAL_ROTATION_REASONS = /* @__PURE__ */ new Set([
876
889
  function isCredentialRotationReason(reason) {
877
890
  return CREDENTIAL_ROTATION_REASONS.has(reason);
878
891
  }
892
+ var SELF_HEALING_REASONS = /* @__PURE__ */ new Set([
893
+ "bind-remediation"
894
+ ]);
895
+ function isSelfHealingReason(reason) {
896
+ return SELF_HEALING_REASONS.has(reason);
897
+ }
879
898
  function restartReasonClass(reason) {
880
899
  if (isCredentialRotationReason(reason)) return "credential-rotation";
900
+ if (isSelfHealingReason(reason)) return "self-healing";
881
901
  return isProvisioningReloadReason(reason) ? "provisioning" : "crash";
882
902
  }
883
903
  function countByClass(events) {
884
904
  let crash = 0;
885
905
  let provisioning = 0;
886
906
  let credentialRotation = 0;
907
+ let selfHealing = 0;
887
908
  for (const e of events) {
888
909
  const klass = restartReasonClass(e.reason);
889
910
  if (klass === "provisioning") provisioning += 1;
890
911
  else if (klass === "credential-rotation") credentialRotation += 1;
912
+ else if (klass === "self-healing") selfHealing += 1;
891
913
  else crash += 1;
892
914
  }
893
- return { crash, provisioning, "credential-rotation": credentialRotation };
915
+ return {
916
+ crash,
917
+ provisioning,
918
+ "credential-rotation": credentialRotation,
919
+ "self-healing": selfHealing
920
+ };
894
921
  }
895
922
  function maxProvisioningBucket(events) {
896
923
  const buckets = /* @__PURE__ */ new Map();
@@ -912,8 +939,8 @@ function tripClass(trip) {
912
939
  }
913
940
  var DEFAULT_MAX = 2;
914
941
  var DEFAULT_WINDOW_MS = 6e5;
915
- var DEFAULT_PROVISIONING_MAX = 5;
916
- var DEFAULT_PROVISIONING_WINDOW_MS = 18e5;
942
+ var DEFAULT_PROVISIONING_MAX = RESTART_BREAKER_PROVISIONING_MAX;
943
+ var DEFAULT_PROVISIONING_WINDOW_MS = RESTART_BREAKER_PROVISIONING_WINDOW_MS;
917
944
  function readEnvNumber(name, fallback) {
918
945
  const raw = process.env[name];
919
946
  if (!raw) return fallback;
@@ -923,6 +950,11 @@ function readEnvNumber(name, fallback) {
923
950
  var RestartBreaker = class {
924
951
  max;
925
952
  windowMs;
953
+ /**
954
+ * ENG-8215: NOT readonly - the constructor may clamp it upward to preserve the
955
+ * quarantine-fires-first ordering against a runtime override. Never mutated
956
+ * after construction.
957
+ */
926
958
  provisioningMax;
927
959
  provisioningWindowMs;
928
960
  /** Longest window either tally needs — how long the events log must retain. */
@@ -930,6 +962,13 @@ var RestartBreaker = class {
930
962
  now;
931
963
  events = /* @__PURE__ */ new Map();
932
964
  trips = /* @__PURE__ */ new Map();
965
+ /**
966
+ * ENG-8215: set when a supplied `provisioningMax` was raised to keep MCP
967
+ * quarantine ahead of the breaker. Read once by the manager at construction so
968
+ * an overridden-and-clamped value is visible in manager.log rather than
969
+ * silently discarded.
970
+ */
971
+ quarantineOrderingClamped;
933
972
  constructor(opts = {}) {
934
973
  this.max = opts.max ?? readEnvNumber("AGT_RESTART_BREAKER_MAX", DEFAULT_MAX);
935
974
  this.windowMs = opts.windowMs ?? readEnvNumber("AGT_RESTART_BREAKER_WINDOW_MS", DEFAULT_WINDOW_MS);
@@ -945,11 +984,27 @@ var RestartBreaker = class {
945
984
  if (!Number.isFinite(this.provisioningMax) || this.provisioningMax < 1) {
946
985
  throw new Error("restart-breaker provisioningMax must be a finite number >= 1");
947
986
  }
987
+ if (this.provisioningMax < MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING) {
988
+ this.quarantineOrderingClamped = {
989
+ requested: this.provisioningMax,
990
+ applied: MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING,
991
+ quarantineThreshold: BIND_FAILURE_QUARANTINE_THRESHOLD
992
+ };
993
+ this.provisioningMax = MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING;
994
+ }
948
995
  if (!Number.isFinite(this.provisioningWindowMs) || this.provisioningWindowMs < 1e3) {
949
996
  throw new Error("restart-breaker provisioningWindowMs must be a finite number >= 1000");
950
997
  }
951
998
  this.retentionMs = Math.max(this.windowMs, this.provisioningWindowMs);
952
999
  }
1000
+ /**
1001
+ * ENG-8215: the clamp record, if the configured provisioning max had to be
1002
+ * raised to keep MCP quarantine ahead of the breaker. `undefined` when the
1003
+ * configured value already satisfied the ordering.
1004
+ */
1005
+ getQuarantineOrderingClamp() {
1006
+ return this.quarantineOrderingClamped;
1007
+ }
953
1008
  /** True if this agent's breaker is currently tripped (manager must skip spawn). */
954
1009
  isTripped(codeName) {
955
1010
  return this.trips.has(codeName);
@@ -995,11 +1050,15 @@ var RestartBreaker = class {
995
1050
  const credRotCount = prior.filter(
996
1051
  (e) => e.at >= at - this.provisioningWindowMs && isCredentialRotationReason(e.reason)
997
1052
  ).length;
1053
+ const selfHealCount = prior.filter(
1054
+ (e) => e.at >= at - this.provisioningWindowMs && isSelfHealingReason(e.reason)
1055
+ ).length;
998
1056
  const windowCount = prior.filter((e) => e.at >= at - this.windowMs).length;
999
1057
  const classCounts = {
1000
1058
  crash: crashCount,
1001
1059
  provisioning: provEvents.length,
1002
- "credential-rotation": credRotCount
1060
+ "credential-rotation": credRotCount,
1061
+ "self-healing": selfHealCount
1003
1062
  };
1004
1063
  const provBucket = maxProvisioningBucket(provEvents);
1005
1064
  let trippedClass;
@@ -8863,9 +8922,17 @@ var pendingSessionRestarts = /* @__PURE__ */ new Map();
8863
8922
  var lastRestartWasExternal = /* @__PURE__ */ new Map();
8864
8923
  var pendingRestartVerifications = /* @__PURE__ */ new Map();
8865
8924
  var restartBreaker = new RestartBreaker();
8925
+ {
8926
+ const clamp = restartBreaker.getQuarantineOrderingClamp();
8927
+ if (clamp) {
8928
+ log(
8929
+ `[circuit-breaker] provisioningMax=${clamp.requested} would trip before MCP quarantine (threshold=${clamp.quarantineThreshold}); raised to ${clamp.applied} so a failing integration is isolated before the whole agent is paused (ENG-8215)`
8930
+ );
8931
+ }
8932
+ }
8866
8933
  var reportedTrips = /* @__PURE__ */ new Map();
8867
- var RESTART_BREAKER_PROVISIONING_MAX = readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_MAX", 5);
8868
- var RESTART_BREAKER_PROVISIONING_WINDOW_MS = readEnvNumber(
8934
+ var RESTART_BREAKER_PROVISIONING_MAX2 = readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_MAX", 5);
8935
+ var RESTART_BREAKER_PROVISIONING_WINDOW_MS2 = readEnvNumber(
8869
8936
  "AGT_RESTART_BREAKER_PROVISIONING_WINDOW_MS",
8870
8937
  18e5
8871
8938
  );
@@ -8910,13 +8977,13 @@ function recordRestartForBreaker(codeName, reason) {
8910
8977
  let integrationKey;
8911
8978
  if (isProvisioningReloadReason(reason)) {
8912
8979
  const attribution = agentState.provisioningAttribution.get(codeName);
8913
- if (attribution && Date.now() - attribution.at <= RESTART_BREAKER_PROVISIONING_WINDOW_MS) {
8980
+ if (attribution && Date.now() - attribution.at <= RESTART_BREAKER_PROVISIONING_WINDOW_MS2) {
8914
8981
  integrationKey = attribution.key;
8915
8982
  }
8916
8983
  }
8917
8984
  const result = restartBreaker.record(codeName, reason, integrationKey);
8918
8985
  if (!result.tripped || !result.trip) {
8919
- if (isProvisioningReloadReason(reason) && result.maxProvisioningBucket >= RESTART_BREAKER_PROVISIONING_MAX) {
8986
+ if (isProvisioningReloadReason(reason) && result.maxProvisioningBucket >= RESTART_BREAKER_PROVISIONING_MAX2) {
8920
8987
  const culprit = result.maxProvisioningBucketKey ? ` [${result.maxProvisioningBucketKey}]` : "";
8921
8988
  log(
8922
8989
  `[restart-breaker] agent=${codeName} provisioning-reload churn at the trip bar: ${result.maxProvisioningBucket} restarts for one integration${culprit} in window (reason=${reason}); one more will auto-pause the agent; that integration is likely churning (ENG-7560, ENG-7812)`
@@ -9882,7 +9949,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
9882
9949
  var lastVersionCheckAt = 0;
9883
9950
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
9884
9951
  var lastResponsivenessProbeAt = 0;
9885
- var agtCliVersion = true ? "0.28.452" : "dev";
9952
+ var agtCliVersion = true ? "0.28.454" : "dev";
9886
9953
  function resolveBrewPath(execFileSync2) {
9887
9954
  try {
9888
9955
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -11043,7 +11110,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
11043
11110
  if (codeNames.length === 0) return;
11044
11111
  void (async () => {
11045
11112
  try {
11046
- const { collectDiagnostics } = await import("../persistent-session-7HZXY56P.js");
11113
+ const { collectDiagnostics } = await import("../persistent-session-X5N7UFEF.js");
11047
11114
  await api.post("/host/heartbeat", {
11048
11115
  host_id: hostId,
11049
11116
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor)
@@ -11150,7 +11217,7 @@ async function pollCycle() {
11150
11217
  }
11151
11218
  try {
11152
11219
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
11153
- const { collectDiagnostics } = await import("../persistent-session-7HZXY56P.js");
11220
+ const { collectDiagnostics } = await import("../persistent-session-X5N7UFEF.js");
11154
11221
  const diagCodeNames = [...agentState.persistentSessionAgents];
11155
11222
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor) : void 0;
11156
11223
  let tailscaleHostname;
@@ -11264,7 +11331,7 @@ async function pollCycle() {
11264
11331
  collectResponsivenessProbes,
11265
11332
  collectPanelessActivityProbes,
11266
11333
  getResponsivenessIntervalMs
11267
- } = await import("../responsiveness-probe-AIA7ZEBW.js");
11334
+ } = await import("../responsiveness-probe-OAZ55KPC.js");
11268
11335
  const probeIntervalMs = getResponsivenessIntervalMs();
11269
11336
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
11270
11337
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -11328,7 +11395,7 @@ async function pollCycle() {
11328
11395
  collectResponsivenessProbes,
11329
11396
  livePendingInboundOldestAgeSeconds,
11330
11397
  parkPendingInbound
11331
- } = await import("../responsiveness-probe-AIA7ZEBW.js");
11398
+ } = await import("../responsiveness-probe-OAZ55KPC.js");
11332
11399
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
11333
11400
  const wedgeNow = /* @__PURE__ */ new Date();
11334
11401
  const liveAgents = agentState.persistentSessionAgents;
@@ -14700,7 +14767,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
14700
14767
  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}`));
14701
14768
  void (async () => {
14702
14769
  try {
14703
- const { collectDiagnostics } = await import("../persistent-session-7HZXY56P.js");
14770
+ const { collectDiagnostics } = await import("../persistent-session-X5N7UFEF.js");
14704
14771
  await api.post("/host/heartbeat", {
14705
14772
  host_id: hostId,
14706
14773
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -14750,7 +14817,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
14750
14817
  }
14751
14818
  try {
14752
14819
  const hostId = await getHostId();
14753
- const { collectDiagnostics } = await import("../persistent-session-7HZXY56P.js");
14820
+ const { collectDiagnostics } = await import("../persistent-session-X5N7UFEF.js");
14754
14821
  await api.post("/host/heartbeat", {
14755
14822
  host_id: hostId,
14756
14823
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -15203,7 +15270,7 @@ async function processClaudePairSessions(agents) {
15203
15270
  killPairSession,
15204
15271
  pairTmuxSession,
15205
15272
  finalizeClaudePairOnboarding
15206
- } = await import("../claude-pair-runtime-RCH4LKDE.js");
15273
+ } = await import("../claude-pair-runtime-NRKOKQYR.js");
15207
15274
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
15208
15275
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
15209
15276
  const killed = await killPairSession(pairTmuxSession(pairId));