@integrity-labs/agt-cli 0.28.547 → 0.28.549
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.
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
safeWriteJsonAtomic,
|
|
54
54
|
setConfigHash,
|
|
55
55
|
tripClass
|
|
56
|
-
} from "../chunk-
|
|
56
|
+
} from "../chunk-MDIHMULA.js";
|
|
57
57
|
import {
|
|
58
58
|
getProjectDir as getProjectDir2,
|
|
59
59
|
getReadyTasks,
|
|
@@ -288,7 +288,17 @@ function decidePostRestartVerification(pending, sessionStartedAt, sessionHealthy
|
|
|
288
288
|
return { kind: "unverified", attempt, final: attempt >= maxAttempts };
|
|
289
289
|
}
|
|
290
290
|
function shouldRemediateUnverifiedRestart(outcome, ctx) {
|
|
291
|
-
return ctx.enabled && !ctx.breakerTripped &&
|
|
291
|
+
return ctx.enabled && !ctx.breakerTripped && // ENG-8581: never remediate a session whose spawn was SKIPPED because the
|
|
292
|
+
// host cannot authenticate to Claude. Re-respawning cannot bind tools when
|
|
293
|
+
// no session can start at all, so the remediation is incapable of succeeding
|
|
294
|
+
// and simply loops. Observed on dig-host: 28 restarts in 6h, then 21 more in
|
|
295
|
+
// the hour around its re-auth, none of which could ever have worked.
|
|
296
|
+
//
|
|
297
|
+
// The circuit breaker does not catch this, which is the other half of the
|
|
298
|
+
// ticket: a skipped spawn returns `spawnAttempted: false`, so a restart that
|
|
299
|
+
// is never ATTEMPTED never registers as a failing restart. The mechanism
|
|
300
|
+
// designed to stop the loop is structurally blind to it.
|
|
301
|
+
!ctx.authSkipped && outcome.kind === "unverified" && outcome.final;
|
|
292
302
|
}
|
|
293
303
|
function computeFirstConnectUnsettled(integrations, now, windowMs) {
|
|
294
304
|
return integrations.some((i) => {
|
|
@@ -300,7 +310,11 @@ function computeFirstConnectUnsettled(integrations, now, windowMs) {
|
|
|
300
310
|
});
|
|
301
311
|
}
|
|
302
312
|
function shouldDeferBindRemediationForFirstConnect(outcome, ctx) {
|
|
303
|
-
return ctx.enabled && !ctx.breakerTripped &&
|
|
313
|
+
return ctx.enabled && !ctx.breakerTripped && // ENG-8581: an auth-skipped session has no first-connect to wait for either.
|
|
314
|
+
// Deferring would re-arm the verify window forever against a session that
|
|
315
|
+
// cannot start, burning the deferral budget on a condition no amount of
|
|
316
|
+
// waiting fixes. Same gate as remediation, for the same reason.
|
|
317
|
+
!ctx.authSkipped && ctx.firstConnectUnsettled && ctx.deferralsSoFar < ctx.maxDeferrals && outcome.kind === "unverified" && outcome.final;
|
|
304
318
|
}
|
|
305
319
|
|
|
306
320
|
// src/lib/integration-hash.ts
|
|
@@ -9772,6 +9786,12 @@ function cancelPendingSessionRestart(codeName) {
|
|
|
9772
9786
|
deferLogThrottle.delete(codeName);
|
|
9773
9787
|
log(`[hot-reload] Cancelled pending restart timer for '${codeName}' (another teardown path is handling it)`);
|
|
9774
9788
|
}
|
|
9789
|
+
var lastSpawnOutcomeByAgent = /* @__PURE__ */ new Map();
|
|
9790
|
+
function spawnWasRefusedWithNoSession(codeName) {
|
|
9791
|
+
const last = lastSpawnOutcomeByAgent.get(codeName);
|
|
9792
|
+
if (!last) return false;
|
|
9793
|
+
return !last.spawnAttempted && !last.sessionHealthyAfter;
|
|
9794
|
+
}
|
|
9775
9795
|
function bindRemediationEnabled() {
|
|
9776
9796
|
return hostFlagStore().getBoolean("bind-remediation");
|
|
9777
9797
|
}
|
|
@@ -9807,6 +9827,7 @@ function verifyPendingRestarts(now) {
|
|
|
9807
9827
|
if (shouldDeferBindRemediationForFirstConnect(outcome, {
|
|
9808
9828
|
enabled: bindRemediationEnabled(),
|
|
9809
9829
|
breakerTripped: restartBreaker.isTripped(codeName),
|
|
9830
|
+
authSkipped: spawnWasRefusedWithNoSession(codeName),
|
|
9810
9831
|
firstConnectUnsettled: firstConnectUnsettledByAgent.get(codeName) ?? false,
|
|
9811
9832
|
deferralsSoFar: deferrals,
|
|
9812
9833
|
maxDeferrals: BIND_REMEDIATION_MAX_CONNECTIVITY_DEFERRALS
|
|
@@ -9826,9 +9847,15 @@ function verifyPendingRestarts(now) {
|
|
|
9826
9847
|
`[restart-verify] ERROR '${codeName}' did NOT respawn healthy after ${outcome.attempt} attempts following an MCP change \u2014 the live session may be stuck on its pre-restart tools. Check session health / manager.log; a manual session restart may be required (ENG-6174)`
|
|
9827
9848
|
);
|
|
9828
9849
|
finishRestartTiming(codeName, "failed", `${outcome.attempt} verify attempts`, log, now);
|
|
9850
|
+
if (bindRemediationEnabled() && spawnWasRefusedWithNoSession(codeName)) {
|
|
9851
|
+
log(
|
|
9852
|
+
`[bind-remediation] '${codeName}' NOT remediating \u2014 the last spawn was refused and no session is running (e.g. the host cannot authenticate to Claude). A re-respawn cannot bind tools when nothing can start, so this would loop without the breaker ever seeing it (ENG-8581). Fix the host, not the session.`
|
|
9853
|
+
);
|
|
9854
|
+
}
|
|
9829
9855
|
if (shouldRemediateUnverifiedRestart(outcome, {
|
|
9830
9856
|
enabled: bindRemediationEnabled(),
|
|
9831
|
-
breakerTripped: restartBreaker.isTripped(codeName)
|
|
9857
|
+
breakerTripped: restartBreaker.isTripped(codeName),
|
|
9858
|
+
authSkipped: spawnWasRefusedWithNoSession(codeName)
|
|
9832
9859
|
})) {
|
|
9833
9860
|
const jitterMs = Math.floor(Math.random() * BIND_REMEDIATION_JITTER_MS);
|
|
9834
9861
|
log(
|
|
@@ -10455,7 +10482,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
10455
10482
|
var lastVersionCheckAt = 0;
|
|
10456
10483
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
10457
10484
|
var lastResponsivenessProbeAt = 0;
|
|
10458
|
-
var agtCliVersion = true ? "0.28.
|
|
10485
|
+
var agtCliVersion = true ? "0.28.549" : "dev";
|
|
10459
10486
|
function resolveBrewPath(execFileSync2) {
|
|
10460
10487
|
try {
|
|
10461
10488
|
const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -14365,6 +14392,10 @@ async function processAgent(agent, agentStates) {
|
|
|
14365
14392
|
log(
|
|
14366
14393
|
`[persistent-session-decision] agent=${agent.code_name} decision=${psResult.decision} spawn_attempted=${psResult.spawnAttempted} session_healthy_after=${psResult.sessionHealthyAfter}${detailSuffix}`
|
|
14367
14394
|
);
|
|
14395
|
+
lastSpawnOutcomeByAgent.set(agent.code_name, {
|
|
14396
|
+
spawnAttempted: psResult.spawnAttempted,
|
|
14397
|
+
sessionHealthyAfter: psResult.sessionHealthyAfter
|
|
14398
|
+
});
|
|
14368
14399
|
const stuck = persistentSessionStuckTracker.record({
|
|
14369
14400
|
codeName: agent.code_name,
|
|
14370
14401
|
sessionHealthy: psResult.sessionHealthyAfter,
|