@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.
- package/dist/bin/agt.js +4 -4
- package/dist/{chunk-XKBUTWON.js → chunk-HMBECQIY.js} +107 -84
- package/dist/chunk-HMBECQIY.js.map +1 -0
- package/dist/{chunk-ICNRQ4L5.js → chunk-KS762LYV.js} +443 -34
- package/dist/chunk-KS762LYV.js.map +1 -0
- package/dist/{claude-pair-runtime-U5ES3GOY.js → claude-pair-runtime-5GY4G7MD.js} +2 -2
- package/dist/lib/manager-worker.js +62 -340
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-HL3LNPAX.js → persistent-session-ZW5HH2SC.js} +2 -2
- package/dist/{responsiveness-probe-AZ44ONES.js → responsiveness-probe-RAHKBJEE.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-ICNRQ4L5.js.map +0 -1
- package/dist/chunk-XKBUTWON.js.map +0 -1
- /package/dist/{claude-pair-runtime-U5ES3GOY.js.map → claude-pair-runtime-5GY4G7MD.js.map} +0 -0
- /package/dist/{persistent-session-HL3LNPAX.js.map → persistent-session-ZW5HH2SC.js.map} +0 -0
- /package/dist/{responsiveness-probe-AZ44ONES.js.map → responsiveness-probe-RAHKBJEE.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-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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
|
|
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",
|
|
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
|
|
9213
|
-
var
|
|
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 <=
|
|
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 >=
|
|
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 =
|
|
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.
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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-
|
|
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));
|