@integrity-labs/agt-cli 0.28.500 → 0.28.502

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-HL3LNPAX.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-ZW5HH2SC.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-U5ES3GOY.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-5GY4G7MD.js.map
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  ApiError,
3
3
  CHANNEL_SECRET_ENV_KEYS,
4
+ FIRST_CONNECT_WINDOW_MS,
4
5
  HostFlagStore,
6
+ RestartBreaker,
5
7
  SUPERVISOR_RESTART_EXIT_CODE,
6
8
  api,
7
9
  atomicWriteFileSync,
@@ -25,9 +27,11 @@ import {
25
27
  getCachedClaudeAuthMode,
26
28
  getHostId,
27
29
  givenUpMcpServerKeys,
30
+ isProvisioningReloadReason,
28
31
  isTransientAuthFailure,
29
32
  liveProxyExtraHeaderVars,
30
33
  liveProxyTokenVars,
34
+ markQuarantinedForProbe,
31
35
  migrateAgentDirToIdKeyed,
32
36
  pinAllowsUrgent,
33
37
  provision,
@@ -38,14 +42,17 @@ import {
38
42
  provisionPreCompactHook,
39
43
  provisionSessionStateHook,
40
44
  provisionStopHook,
45
+ readEnvNumber,
41
46
  reapMissingMcpSessions,
42
47
  reapStaleMcpChildren,
48
+ reaperRestartBreakerReason,
43
49
  reconstructQuarantinedMcpServerEntry,
44
50
  requireHost,
45
51
  resolveEffectivePinRaw,
46
52
  safeWriteJsonAtomic,
47
- setConfigHash
48
- } from "../chunk-ICNRQ4L5.js";
53
+ setConfigHash,
54
+ tripClass
55
+ } from "../chunk-KS762LYV.js";
49
56
  import {
50
57
  getProjectDir as getProjectDir2,
51
58
  getReadyTasks,
@@ -56,7 +63,6 @@ import {
56
63
  import {
57
64
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
58
65
  AnchorSessionClient,
59
- BIND_FAILURE_QUARANTINE_THRESHOLD,
60
66
  CLAUDE_MD_MAX_CHARS,
61
67
  CONVERSATION_FAILURE_CATEGORIES,
62
68
  DEFAULT_FRAMEWORK,
@@ -67,13 +73,11 @@ import {
67
73
  KANBAN_CHECK_COMMAND,
68
74
  KANBAN_NUDGE_ACTIONABLE_STATUSES,
69
75
  MAX_AVATAR_ENV_URL_BYTES,
70
- MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING,
71
- RESTART_BREAKER_PROVISIONING_MAX,
72
- RESTART_BREAKER_PROVISIONING_WINDOW_MS,
73
76
  SCHEDULED_TURN_MARKER_FILENAME,
74
77
  SUPPRESS_SENTINEL,
75
78
  StreamEncoder,
76
79
  UNKNOWN_RATE_LIMIT,
80
+ agentRuntimeKey,
77
81
  appendDmFooter,
78
82
  attributeTranscriptUsageByRun,
79
83
  buildEgressAllowlist,
@@ -168,7 +172,7 @@ import {
168
172
  toOpencodeModel,
169
173
  transcriptActivityAgeSeconds,
170
174
  writeEgressAllowlist
171
- } from "../chunk-XKBUTWON.js";
175
+ } from "../chunk-HMBECQIY.js";
172
176
  import {
173
177
  reapOrphanChannelMcps
174
178
  } from "../chunk-XWVM4KPK.js";
@@ -845,315 +849,8 @@ function logClaudeMdCeilingTransition(codeName, report, log2) {
845
849
  return line;
846
850
  }
847
851
 
848
- // src/lib/restart-breaker.ts
849
- function reaperRestartBreakerReason(activeKeys) {
850
- return activeKeys.length >= 2 ? "mcp-presence-reaper" : void 0;
851
- }
852
- var KNOWN_REASON_CLASS_MAP = {
853
- crash: true,
854
- provisioning: true,
855
- "credential-rotation": true,
856
- // ENG-8215: the self-healing class (bind-remediation - the manager's OWN
857
- // repair attempts, which must never count toward a trip). Adding it here is
858
- // forced by the Record type, which is exactly why that shape was chosen over
859
- // a Set literal (ENG-7577, CodeRabbit on #3861) - a new union member cannot
860
- // be silently omitted from the rehydration allowlist.
861
- "self-healing": true
862
- };
863
- var KNOWN_REASON_CLASSES = new Set(
864
- Object.keys(KNOWN_REASON_CLASS_MAP)
865
- );
866
- var PROVISIONING_RELOAD_REASONS = /* @__PURE__ */ new Set([
867
- "hot-reload-mcp",
868
- "managed-mcp-churn",
869
- // ENG-8215: 'bind-remediation' MOVED OUT of this set into SELF_HEALING_REASONS.
870
- // It is the manager repairing itself, not a config reload, and counting it
871
- // meant the harder the platform tried to fix an agent the more certain it
872
- // became that it should give up. Deliberately NOT re-added here.
873
- // ENG-7576: the dashboard integration-add stop itself - the first restart of
874
- // the very burst this class exists for, previously uncounted entirely.
875
- "integration-change",
876
- // ENG-7771: a sender_policy delivery restart is a deliberate config-delivery
877
- // reload (operator changed the policy, or the fail-closed first-poll verify
878
- // after a manager restart with no persisted baseline), not a crash. On the
879
- // tight crash tally, a host whose sender-policy-baseline.json write keeps
880
- // failing (disk full, permissions) would convert the fail-closed restart
881
- // into repeated crash tallies across a multi-deploy day and trip the
882
- // breaker - taking the agent DOWN, which is strictly worse than the stale
883
- // policy the restart exists to fix. The looser provisioning tally still
884
- // trips + pages on sustained thrash.
885
- "sender-policy-change"
886
- ]);
887
- function isProvisioningReloadReason(reason) {
888
- return PROVISIONING_RELOAD_REASONS.has(reason);
889
- }
890
- var CREDENTIAL_ROTATION_REASONS = /* @__PURE__ */ new Set([
891
- "credential-rotation"
892
- ]);
893
- function isCredentialRotationReason(reason) {
894
- return CREDENTIAL_ROTATION_REASONS.has(reason);
895
- }
896
- var SELF_HEALING_REASONS = /* @__PURE__ */ new Set([
897
- "bind-remediation"
898
- ]);
899
- function isSelfHealingReason(reason) {
900
- return SELF_HEALING_REASONS.has(reason);
901
- }
902
- function restartReasonClass(reason) {
903
- if (isCredentialRotationReason(reason)) return "credential-rotation";
904
- if (isSelfHealingReason(reason)) return "self-healing";
905
- return isProvisioningReloadReason(reason) ? "provisioning" : "crash";
906
- }
907
- function countByClass(events) {
908
- let crash = 0;
909
- let provisioning = 0;
910
- let credentialRotation = 0;
911
- let selfHealing = 0;
912
- for (const e of events) {
913
- const klass = restartReasonClass(e.reason);
914
- if (klass === "provisioning") provisioning += 1;
915
- else if (klass === "credential-rotation") credentialRotation += 1;
916
- else if (klass === "self-healing") selfHealing += 1;
917
- else crash += 1;
918
- }
919
- return {
920
- crash,
921
- provisioning,
922
- "credential-rotation": credentialRotation,
923
- "self-healing": selfHealing
924
- };
925
- }
926
- function maxProvisioningBucket(events) {
927
- const buckets = /* @__PURE__ */ new Map();
928
- for (const e of events) {
929
- if (!isProvisioningReloadReason(e.reason)) continue;
930
- const key = e.integrationKey ?? "";
931
- buckets.set(key, (buckets.get(key) ?? 0) + 1);
932
- }
933
- let best = { count: 0, key: "" };
934
- for (const [key, count] of buckets) {
935
- if (count > best.count) best = { count, key };
936
- }
937
- return best;
938
- }
939
- function tripClass(trip) {
940
- if (trip.trippedClass) return trip.trippedClass;
941
- if (!Array.isArray(trip.eventsAtTrip) || trip.eventsAtTrip.length === 0) return "crash";
942
- return trip.eventsAtTrip.every((e) => isProvisioningReloadReason(e.reason)) ? "provisioning" : "crash";
943
- }
944
- var DEFAULT_MAX = 2;
945
- var DEFAULT_WINDOW_MS = 6e5;
946
- var DEFAULT_PROVISIONING_MAX = RESTART_BREAKER_PROVISIONING_MAX;
947
- var DEFAULT_PROVISIONING_WINDOW_MS = RESTART_BREAKER_PROVISIONING_WINDOW_MS;
948
- function readEnvNumber(name, fallback) {
949
- const raw = process.env[name];
950
- if (!raw) return fallback;
951
- const parsed = Number(raw);
952
- return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
953
- }
954
- var RestartBreaker = class {
955
- max;
956
- windowMs;
957
- /**
958
- * ENG-8215: NOT readonly - the constructor may clamp it upward to preserve the
959
- * quarantine-fires-first ordering against a runtime override. Never mutated
960
- * after construction.
961
- */
962
- provisioningMax;
963
- provisioningWindowMs;
964
- /** Longest window either tally needs — how long the events log must retain. */
965
- retentionMs;
966
- now;
967
- events = /* @__PURE__ */ new Map();
968
- trips = /* @__PURE__ */ new Map();
969
- /**
970
- * ENG-8215: set when a supplied `provisioningMax` was raised to keep MCP
971
- * quarantine ahead of the breaker. Read once by the manager at construction so
972
- * an overridden-and-clamped value is visible in manager.log rather than
973
- * silently discarded.
974
- */
975
- quarantineOrderingClamped;
976
- constructor(opts = {}) {
977
- this.max = opts.max ?? readEnvNumber("AGT_RESTART_BREAKER_MAX", DEFAULT_MAX);
978
- this.windowMs = opts.windowMs ?? readEnvNumber("AGT_RESTART_BREAKER_WINDOW_MS", DEFAULT_WINDOW_MS);
979
- this.provisioningMax = opts.provisioningMax ?? readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_MAX", DEFAULT_PROVISIONING_MAX);
980
- this.provisioningWindowMs = opts.provisioningWindowMs ?? readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_WINDOW_MS", DEFAULT_PROVISIONING_WINDOW_MS);
981
- this.now = opts.now ?? Date.now;
982
- if (!Number.isFinite(this.max) || this.max < 1) {
983
- throw new Error("restart-breaker max must be a finite number >= 1");
984
- }
985
- if (!Number.isFinite(this.windowMs) || this.windowMs < 1e3) {
986
- throw new Error("restart-breaker windowMs must be a finite number >= 1000");
987
- }
988
- if (!Number.isFinite(this.provisioningMax) || this.provisioningMax < 1) {
989
- throw new Error("restart-breaker provisioningMax must be a finite number >= 1");
990
- }
991
- if (this.provisioningMax < MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING) {
992
- this.quarantineOrderingClamped = {
993
- requested: this.provisioningMax,
994
- applied: MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING,
995
- quarantineThreshold: BIND_FAILURE_QUARANTINE_THRESHOLD
996
- };
997
- this.provisioningMax = MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING;
998
- }
999
- if (!Number.isFinite(this.provisioningWindowMs) || this.provisioningWindowMs < 1e3) {
1000
- throw new Error("restart-breaker provisioningWindowMs must be a finite number >= 1000");
1001
- }
1002
- this.retentionMs = Math.max(this.windowMs, this.provisioningWindowMs);
1003
- }
1004
- /**
1005
- * ENG-8215: the clamp record, if the configured provisioning max had to be
1006
- * raised to keep MCP quarantine ahead of the breaker. `undefined` when the
1007
- * configured value already satisfied the ordering.
1008
- */
1009
- getQuarantineOrderingClamp() {
1010
- return this.quarantineOrderingClamped;
1011
- }
1012
- /** True if this agent's breaker is currently tripped (manager must skip spawn). */
1013
- isTripped(codeName) {
1014
- return this.trips.has(codeName);
1015
- }
1016
- getTrip(codeName) {
1017
- return this.trips.get(codeName);
1018
- }
1019
- /**
1020
- * Record a restart event. If recording this event puts the count
1021
- * inside the window above `max`, the breaker trips and the call site
1022
- * should NOT respawn.
1023
- *
1024
- * Idempotent on already-tripped breakers: returns the existing trip
1025
- * without double-counting events. Callers may still record the reason
1026
- * via the decision-log for forensics.
1027
- */
1028
- record(codeName, reason, integrationKey) {
1029
- const existing = this.trips.get(codeName);
1030
- if (existing) {
1031
- const bucket = maxProvisioningBucket(existing.eventsAtTrip);
1032
- return {
1033
- tripped: false,
1034
- trip: existing,
1035
- windowCount: existing.eventsAtTrip.length,
1036
- classCounts: countByClass(existing.eventsAtTrip),
1037
- maxProvisioningBucket: bucket.count,
1038
- maxProvisioningBucketKey: bucket.key
1039
- };
1040
- }
1041
- const at = this.now();
1042
- const retentionCutoff = at - this.retentionMs;
1043
- const prior = (this.events.get(codeName) ?? []).filter((e) => e.at >= retentionCutoff);
1044
- prior.push(
1045
- isProvisioningReloadReason(reason) && integrationKey ? { reason, at, integrationKey } : { reason, at }
1046
- );
1047
- this.events.set(codeName, prior);
1048
- const crashCount = prior.filter(
1049
- (e) => e.at >= at - this.windowMs && restartReasonClass(e.reason) === "crash"
1050
- ).length;
1051
- const provEvents = prior.filter(
1052
- (e) => e.at >= at - this.provisioningWindowMs && isProvisioningReloadReason(e.reason)
1053
- );
1054
- const credRotCount = prior.filter(
1055
- (e) => e.at >= at - this.provisioningWindowMs && isCredentialRotationReason(e.reason)
1056
- ).length;
1057
- const selfHealCount = prior.filter(
1058
- (e) => e.at >= at - this.provisioningWindowMs && isSelfHealingReason(e.reason)
1059
- ).length;
1060
- const windowCount = prior.filter((e) => e.at >= at - this.windowMs).length;
1061
- const classCounts = {
1062
- crash: crashCount,
1063
- provisioning: provEvents.length,
1064
- "credential-rotation": credRotCount,
1065
- "self-healing": selfHealCount
1066
- };
1067
- const provBucket = maxProvisioningBucket(provEvents);
1068
- let trippedClass;
1069
- let tripEvents;
1070
- let tripWindowMs = this.windowMs;
1071
- if (crashCount > this.max) {
1072
- trippedClass = "crash";
1073
- tripEvents = prior.filter(
1074
- (e) => e.at >= at - this.windowMs && restartReasonClass(e.reason) === "crash"
1075
- );
1076
- tripWindowMs = this.windowMs;
1077
- } else if (provBucket.count > this.provisioningMax) {
1078
- trippedClass = "provisioning";
1079
- tripEvents = provEvents.filter((e) => (e.integrationKey ?? "") === provBucket.key);
1080
- tripWindowMs = this.provisioningWindowMs;
1081
- }
1082
- if (trippedClass && tripEvents) {
1083
- const trip = {
1084
- trippedAt: at,
1085
- eventsAtTrip: [...tripEvents],
1086
- statusMessage: formatStatusMessage(tripEvents, tripWindowMs, trippedClass, provBucket.key),
1087
- // ENG-7577: persist the tripping class so the recovery path can gate on
1088
- // it after a manager restart, without re-deriving it from prose.
1089
- trippedClass
1090
- };
1091
- this.trips.set(codeName, trip);
1092
- this.events.delete(codeName);
1093
- return {
1094
- tripped: true,
1095
- trip,
1096
- windowCount,
1097
- classCounts,
1098
- trippedClass,
1099
- maxProvisioningBucket: provBucket.count,
1100
- maxProvisioningBucketKey: provBucket.key
1101
- };
1102
- }
1103
- return {
1104
- tripped: false,
1105
- windowCount,
1106
- classCounts,
1107
- maxProvisioningBucket: provBucket.count,
1108
- maxProvisioningBucketKey: provBucket.key
1109
- };
1110
- }
1111
- /** Operator-initiated reset: drops the trip + the events log for this agent. */
1112
- clear(codeName) {
1113
- this.trips.delete(codeName);
1114
- this.events.delete(codeName);
1115
- }
1116
- /** Snapshot tripped agents for `manager-state.json`. */
1117
- serialize() {
1118
- return Object.fromEntries(this.trips.entries());
1119
- }
1120
- /**
1121
- * Rehydrate trip state from `manager-state.json`. Called once at
1122
- * worker startup. Window history is intentionally NOT persisted — only
1123
- * tripped state. A tripped breaker survives manager restart; an
1124
- * un-tripped one starts a fresh window in the new worker.
1125
- */
1126
- hydrate(saved) {
1127
- if (!saved) return;
1128
- for (const [codeName, trip] of Object.entries(saved)) {
1129
- if (trip && typeof trip.trippedAt === "number" && Array.isArray(trip.eventsAtTrip)) {
1130
- const klass = trip.trippedClass;
1131
- this.trips.set(
1132
- codeName,
1133
- klass === void 0 || KNOWN_REASON_CLASSES.has(klass) ? trip : { ...trip, trippedClass: void 0 }
1134
- );
1135
- }
1136
- }
1137
- }
1138
- /** Test helper — current in-window event count for `codeName`. */
1139
- windowCount(codeName) {
1140
- const cutoff = this.now() - this.windowMs;
1141
- return (this.events.get(codeName) ?? []).filter((e) => e.at >= cutoff).length;
1142
- }
1143
- };
1144
- function formatStatusMessage(events, windowMs, klass = "crash", integrationKey = "") {
1145
- const last = events[events.length - 1];
1146
- const windowLabel = windowMs < 6e4 ? `${Math.round(windowMs / 1e3)}s` : `${(windowMs / 6e4).toFixed(1).replace(/\.0$/, "")}min`;
1147
- const reasonCounts = /* @__PURE__ */ new Map();
1148
- for (const e of events) reasonCounts.set(e.reason, (reasonCounts.get(e.reason) ?? 0) + 1);
1149
- const breakdown = Array.from(reasonCounts.entries()).map(([r, n]) => `${r}=${n}`).join(", ");
1150
- const classLabel = klass === "provisioning" ? "provisioning-reload " : "";
1151
- const integrationLabel = klass === "provisioning" && integrationKey ? ` for integration '${integrationKey}'` : "";
1152
- return `Circuit breaker tripped: ${events.length} ${classLabel}restarts in ${windowLabel}${integrationLabel} (${breakdown}); most recent=${last.reason} at ${new Date(last.at).toISOString()}`;
1153
- }
1154
-
1155
852
  // src/lib/mcp-flap-dampener.ts
1156
- var DEFAULT_WINDOW_MS2 = 6e5;
853
+ var DEFAULT_WINDOW_MS = 6e5;
1157
854
  var DEFAULT_MIN_TRANSITIONS = 4;
1158
855
  var DEFAULT_MIN_DISTINCT = 2;
1159
856
  var DEFAULT_LONG_WINDOW_MS = 36e5;
@@ -1182,7 +879,7 @@ var McpFlapDampener = class {
1182
879
  // see that method for the Kylie/dig (2026-06-29) rationale.
1183
880
  lastFlapAt = /* @__PURE__ */ new Map();
1184
881
  constructor(opts = {}) {
1185
- this.windowMs = opts.windowMs ?? readEnvNumber2("AGT_MCP_FLAP_WINDOW_MS", DEFAULT_WINDOW_MS2);
882
+ this.windowMs = opts.windowMs ?? readEnvNumber2("AGT_MCP_FLAP_WINDOW_MS", DEFAULT_WINDOW_MS);
1186
883
  this.minTransitions = opts.minTransitions ?? readEnvNumber2("AGT_MCP_FLAP_MIN_TRANSITIONS", DEFAULT_MIN_TRANSITIONS);
1187
884
  this.minDistinct = opts.minDistinct ?? readEnvNumber2("AGT_MCP_FLAP_MIN_DISTINCT", DEFAULT_MIN_DISTINCT);
1188
885
  this.longWindowMs = opts.longWindowMs ?? readEnvNumber2("AGT_MCP_FLAP_LONG_WINDOW_MS", DEFAULT_LONG_WINDOW_MS);
@@ -1586,7 +1283,11 @@ async function runConnectivityProbes(integrations, options = {}) {
1586
1283
  cliBinary: integ.cli_binary,
1587
1284
  mcpServerKey: integ.mcp_server_key,
1588
1285
  connectivityTest: integ.connectivity_test ?? null,
1589
- inlineServerEntry: integ.inline_server_entry
1286
+ inlineServerEntry: integ.inline_server_entry,
1287
+ // ENG-8363: row age + quarantine status decide whether a missing
1288
+ // `.mcp.json` key is "not written yet" (transient) or "not wired" (down).
1289
+ createdAt: integ.created_at ?? null,
1290
+ expectedAbsent: integ.quarantined ?? false
1590
1291
  };
1591
1292
  let outcome;
1592
1293
  try {
@@ -9209,8 +8910,8 @@ var restartBreaker = new RestartBreaker();
9209
8910
  }
9210
8911
  }
9211
8912
  var reportedTrips = /* @__PURE__ */ new Map();
9212
- var RESTART_BREAKER_PROVISIONING_MAX2 = readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_MAX", 5);
9213
- var RESTART_BREAKER_PROVISIONING_WINDOW_MS2 = readEnvNumber(
8913
+ var RESTART_BREAKER_PROVISIONING_MAX = readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_MAX", 5);
8914
+ var RESTART_BREAKER_PROVISIONING_WINDOW_MS = readEnvNumber(
9214
8915
  "AGT_RESTART_BREAKER_PROVISIONING_WINDOW_MS",
9215
8916
  18e5
9216
8917
  );
@@ -9255,13 +8956,13 @@ function recordRestartForBreaker(codeName, reason) {
9255
8956
  let integrationKey;
9256
8957
  if (isProvisioningReloadReason(reason)) {
9257
8958
  const attribution = agentState.provisioningAttribution.get(codeName);
9258
- if (attribution && Date.now() - attribution.at <= RESTART_BREAKER_PROVISIONING_WINDOW_MS2) {
8959
+ if (attribution && Date.now() - attribution.at <= RESTART_BREAKER_PROVISIONING_WINDOW_MS) {
9259
8960
  integrationKey = attribution.key;
9260
8961
  }
9261
8962
  }
9262
8963
  const result = restartBreaker.record(codeName, reason, integrationKey);
9263
8964
  if (!result.tripped || !result.trip) {
9264
- if (isProvisioningReloadReason(reason) && result.maxProvisioningBucket >= RESTART_BREAKER_PROVISIONING_MAX2) {
8965
+ if (isProvisioningReloadReason(reason) && result.maxProvisioningBucket >= RESTART_BREAKER_PROVISIONING_MAX) {
9265
8966
  const culprit = result.maxProvisioningBucketKey ? ` [${result.maxProvisioningBucketKey}]` : "";
9266
8967
  log(
9267
8968
  `[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)`
@@ -9650,11 +9351,7 @@ function bindRemediationEnabled() {
9650
9351
  return hostFlagStore().getBoolean("bind-remediation");
9651
9352
  }
9652
9353
  var BIND_REMEDIATION_JITTER_MS = 3e4;
9653
- var BIND_REMEDIATION_FIRST_CONNECT_WINDOW_MS = readEnvNumber(
9654
- "AGT_BIND_REMEDIATION_FIRST_CONNECT_WINDOW_MS",
9655
- 9e5
9656
- // 15 min
9657
- );
9354
+ var BIND_REMEDIATION_FIRST_CONNECT_WINDOW_MS = FIRST_CONNECT_WINDOW_MS;
9658
9355
  var BIND_REMEDIATION_MAX_CONNECTIVITY_DEFERRALS = readEnvNumber(
9659
9356
  "AGT_BIND_REMEDIATION_MAX_CONNECTIVITY_DEFERRALS",
9660
9357
  3
@@ -9954,7 +9651,13 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
9954
9651
  // ENG-8055: forward the reconstructed inline server entry (managed
9955
9652
  // quarantined rows) so the MCP probe legs hit the real server instead of
9956
9653
  // the missing `.mcp.json` key. Absent on normal (active) rows.
9957
- inline_server_entry: i.inline_server_entry
9654
+ inline_server_entry: i.inline_server_entry,
9655
+ // ENG-8363: age + quarantine status, so an absent `.mcp.json` key is
9656
+ // classified rather than guessed. Forwarding both is what makes the
9657
+ // escalation to `down` reachable at all — an omitted `created_at` reads
9658
+ // as "still settling" and never escalates (fail-open by design).
9659
+ created_at: i.created_at ?? null,
9660
+ quarantined: i.quarantined ?? false
9958
9661
  };
9959
9662
  }),
9960
9663
  { probeDeps, intervalMs: intervalSec * 1e3 }
@@ -10251,7 +9954,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
10251
9954
  var lastVersionCheckAt = 0;
10252
9955
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
10253
9956
  var lastResponsivenessProbeAt = 0;
10254
- var agtCliVersion = true ? "0.28.500" : "dev";
9957
+ var agtCliVersion = true ? "0.28.502" : "dev";
10255
9958
  function resolveBrewPath(execFileSync2) {
10256
9959
  try {
10257
9960
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -11414,7 +11117,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
11414
11117
  if (codeNames.length === 0) return;
11415
11118
  void (async () => {
11416
11119
  try {
11417
- const { collectDiagnostics } = await import("../persistent-session-HL3LNPAX.js");
11120
+ const { collectDiagnostics } = await import("../persistent-session-ZW5HH2SC.js");
11418
11121
  await api.post("/host/heartbeat", {
11419
11122
  host_id: hostId,
11420
11123
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor)
@@ -11521,7 +11224,7 @@ async function pollCycle() {
11521
11224
  }
11522
11225
  try {
11523
11226
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
11524
- const { collectDiagnostics } = await import("../persistent-session-HL3LNPAX.js");
11227
+ const { collectDiagnostics } = await import("../persistent-session-ZW5HH2SC.js");
11525
11228
  const diagCodeNames = [...agentState.persistentSessionAgents];
11526
11229
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor) : void 0;
11527
11230
  let tailscaleHostname;
@@ -11636,7 +11339,7 @@ async function pollCycle() {
11636
11339
  collectResponsivenessProbes,
11637
11340
  collectPanelessActivityProbes,
11638
11341
  getResponsivenessIntervalMs
11639
- } = await import("../responsiveness-probe-AZ44ONES.js");
11342
+ } = await import("../responsiveness-probe-RAHKBJEE.js");
11640
11343
  const probeIntervalMs = getResponsivenessIntervalMs();
11641
11344
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
11642
11345
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -11700,7 +11403,7 @@ async function pollCycle() {
11700
11403
  collectResponsivenessProbes,
11701
11404
  livePendingInboundOldestAgeSeconds,
11702
11405
  parkPendingInbound
11703
- } = await import("../responsiveness-probe-AZ44ONES.js");
11406
+ } = await import("../responsiveness-probe-RAHKBJEE.js");
11704
11407
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
11705
11408
  const wedgeNow = /* @__PURE__ */ new Date();
11706
11409
  const liveAgents = agentState.persistentSessionAgents;
@@ -13315,7 +13018,7 @@ async function processAgent(agent, agentStates) {
13315
13018
  );
13316
13019
  }
13317
13020
  }
13318
- probeSet = [...probeSet, ...qRows];
13021
+ probeSet = [...probeSet, ...markQuarantinedForProbe(qRows)];
13319
13022
  log(
13320
13023
  `Auto-resume: connectivity-probing ${qRows.length} quarantined integration(s) for '${agent.code_name}'`
13321
13024
  );
@@ -15192,7 +14895,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
15192
14895
  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}`));
15193
14896
  void (async () => {
15194
14897
  try {
15195
- const { collectDiagnostics } = await import("../persistent-session-HL3LNPAX.js");
14898
+ const { collectDiagnostics } = await import("../persistent-session-ZW5HH2SC.js");
15196
14899
  await api.post("/host/heartbeat", {
15197
14900
  host_id: hostId,
15198
14901
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -15242,7 +14945,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
15242
14945
  }
15243
14946
  try {
15244
14947
  const hostId = await getHostId();
15245
- const { collectDiagnostics } = await import("../persistent-session-HL3LNPAX.js");
14948
+ const { collectDiagnostics } = await import("../persistent-session-ZW5HH2SC.js");
15246
14949
  await api.post("/host/heartbeat", {
15247
14950
  host_id: hostId,
15248
14951
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -15596,19 +15299,38 @@ ${escapeXml(msg.content)}
15596
15299
  }
15597
15300
  var lastKanbanInjectAt = /* @__PURE__ */ new Map();
15598
15301
  var kanbanNudgeStateByCode = /* @__PURE__ */ new Map();
15302
+ function kanbanNudgeStateKey(codeName) {
15303
+ return agentRuntimeKey(codeName);
15304
+ }
15305
+ function getKanbanNudgeState(codeName) {
15306
+ const key = kanbanNudgeStateKey(codeName);
15307
+ const hit = kanbanNudgeStateByCode.get(key);
15308
+ if (hit || key === codeName) return hit;
15309
+ const legacy = kanbanNudgeStateByCode.get(codeName);
15310
+ if (!legacy) return void 0;
15311
+ kanbanNudgeStateByCode.delete(codeName);
15312
+ kanbanNudgeStateByCode.set(key, legacy);
15313
+ saveKanbanNudgeState(kanbanNudgeStateByCode, channelHashCacheDir());
15314
+ return legacy;
15315
+ }
15599
15316
  function loadKanbanNudgeStateFromDisk() {
15600
15317
  loadKanbanNudgeState(kanbanNudgeStateByCode, channelHashCacheDir());
15601
15318
  }
15602
15319
  function setKanbanNudgeState(codeName, state7) {
15603
- kanbanNudgeStateByCode.set(codeName, state7);
15320
+ const key = kanbanNudgeStateKey(codeName);
15321
+ if (key !== codeName) kanbanNudgeStateByCode.delete(codeName);
15322
+ kanbanNudgeStateByCode.set(key, state7);
15604
15323
  saveKanbanNudgeState(kanbanNudgeStateByCode, channelHashCacheDir());
15605
15324
  }
15606
15325
  function clearKanbanNudgeState(codeName) {
15607
- if (!kanbanNudgeStateByCode.delete(codeName)) return;
15326
+ const key = kanbanNudgeStateKey(codeName);
15327
+ let removed = kanbanNudgeStateByCode.delete(key);
15328
+ if (key !== codeName && kanbanNudgeStateByCode.delete(codeName)) removed = true;
15329
+ if (!removed) return;
15608
15330
  saveKanbanNudgeState(kanbanNudgeStateByCode, channelHashCacheDir());
15609
15331
  }
15610
15332
  function nextKanbanNudgeCount(codeName, signature) {
15611
- const prev = kanbanNudgeStateByCode.get(codeName);
15333
+ const prev = getKanbanNudgeState(codeName);
15612
15334
  return prev && prev.signature === signature ? (prev.nudgeCount ?? 1) + 1 : 1;
15613
15335
  }
15614
15336
  var openInjectedRunByCode = /* @__PURE__ */ new Map();
@@ -15686,7 +15408,7 @@ ${formatRunMarker(run_id)}` : KANBAN_CHECK_COMMAND;
15686
15408
  async function maybeInjectKanbanCheck(codeName, agentId, actionableCount, signature) {
15687
15409
  if (!shouldNudgeUnchangedBoard(
15688
15410
  signature,
15689
- kanbanNudgeStateByCode.get(codeName),
15411
+ getKanbanNudgeState(codeName),
15690
15412
  Date.now(),
15691
15413
  KANBAN_HYBRID_FULL_CADENCE_MS,
15692
15414
  KANBAN_HYBRID_MAX_CADENCE_MS
@@ -15730,7 +15452,7 @@ async function processClaudePairSessions(agents) {
15730
15452
  killPairSession,
15731
15453
  pairTmuxSession,
15732
15454
  finalizeClaudePairOnboarding
15733
- } = await import("../claude-pair-runtime-U5ES3GOY.js");
15455
+ } = await import("../claude-pair-runtime-5GY4G7MD.js");
15734
15456
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
15735
15457
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
15736
15458
  const killed = await killPairSession(pairTmuxSession(pairId));