@integrity-labs/agt-cli 0.28.467 → 0.28.468
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.
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
diffEnvIntegrations,
|
|
17
17
|
envOnlyRespawnVars,
|
|
18
18
|
exchangeApiKey,
|
|
19
|
+
exchangeFailureKind,
|
|
19
20
|
executeConnectivityProbe,
|
|
20
21
|
extractCommandNotFound,
|
|
21
22
|
findMcpServersUsingVars,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
getCachedClaudeAuthMode,
|
|
25
26
|
getHostId,
|
|
26
27
|
givenUpMcpServerKeys,
|
|
28
|
+
isTransientAuthFailure,
|
|
27
29
|
liveProxyExtraHeaderVars,
|
|
28
30
|
liveProxyTokenVars,
|
|
29
31
|
pinAllowsUrgent,
|
|
@@ -42,7 +44,7 @@ import {
|
|
|
42
44
|
resolveEffectivePinRaw,
|
|
43
45
|
safeWriteJsonAtomic,
|
|
44
46
|
setConfigHash
|
|
45
|
-
} from "../chunk-
|
|
47
|
+
} from "../chunk-Y2XU2XWM.js";
|
|
46
48
|
import {
|
|
47
49
|
getProjectDir as getProjectDir2,
|
|
48
50
|
getReadyTasks,
|
|
@@ -2014,6 +2016,30 @@ function isDirectChatMessageExpired(createdAt, nowMs, maxAgeMs) {
|
|
|
2014
2016
|
return nowMs - created > maxAgeMs;
|
|
2015
2017
|
}
|
|
2016
2018
|
|
|
2019
|
+
// src/lib/manager/auth-resolve-decision.ts
|
|
2020
|
+
function decideAuthResolveFailureAction(args) {
|
|
2021
|
+
const transient = isTransientAuthFailure(args.error);
|
|
2022
|
+
if (!args.sessionHealthy) {
|
|
2023
|
+
return {
|
|
2024
|
+
action: "skip-spawn",
|
|
2025
|
+
transient,
|
|
2026
|
+
reason: transient ? "transient-fault-no-session" : "auth-verdict-no-session"
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
if (transient) {
|
|
2030
|
+
return {
|
|
2031
|
+
action: "preserve-session",
|
|
2032
|
+
transient,
|
|
2033
|
+
reason: "transient-fault-session-preserved"
|
|
2034
|
+
};
|
|
2035
|
+
}
|
|
2036
|
+
return {
|
|
2037
|
+
action: "stop-session",
|
|
2038
|
+
transient,
|
|
2039
|
+
reason: "auth-verdict-session-stopped"
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2017
2043
|
// ../../packages/core/dist/host-config/capture.js
|
|
2018
2044
|
import { createHash as createHash5 } from "crypto";
|
|
2019
2045
|
var NON_SECRET_ENV_GATES = [
|
|
@@ -5370,20 +5396,54 @@ async function startRun(opts) {
|
|
|
5370
5396
|
return { run_id: null, kanban_item_id: null };
|
|
5371
5397
|
}
|
|
5372
5398
|
}
|
|
5399
|
+
var DEFAULT_FINISH_RETRY_ATTEMPTS = 3;
|
|
5400
|
+
var DEFAULT_FINISH_RETRY_BASE_MS = 1e3;
|
|
5401
|
+
function finishRetryAttempts() {
|
|
5402
|
+
const raw = process.env["AGT_RUNS_FINISH_RETRY_ATTEMPTS"];
|
|
5403
|
+
const parsed = raw ? parseInt(raw, 10) : NaN;
|
|
5404
|
+
if (Number.isFinite(parsed) && parsed >= 0) return Math.min(parsed, 6);
|
|
5405
|
+
return DEFAULT_FINISH_RETRY_ATTEMPTS;
|
|
5406
|
+
}
|
|
5407
|
+
function finishRetryBaseMs() {
|
|
5408
|
+
const raw = process.env["AGT_RUNS_FINISH_RETRY_BASE_MS"];
|
|
5409
|
+
const parsed = raw ? parseInt(raw, 10) : NaN;
|
|
5410
|
+
if (Number.isFinite(parsed) && parsed > 0) return Math.min(parsed, 3e4);
|
|
5411
|
+
return DEFAULT_FINISH_RETRY_BASE_MS;
|
|
5412
|
+
}
|
|
5413
|
+
function isRetryableFinishError(err) {
|
|
5414
|
+
if (err instanceof ApiError) return err.status >= 500 || err.status === 429;
|
|
5415
|
+
return true;
|
|
5416
|
+
}
|
|
5373
5417
|
async function finishRun(runId, outcome, options = {}) {
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5418
|
+
const maxRetries = finishRetryAttempts();
|
|
5419
|
+
const baseMs = finishRetryBaseMs();
|
|
5420
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
5421
|
+
try {
|
|
5422
|
+
await api.post("/host/runs/finish", {
|
|
5423
|
+
run_id: runId,
|
|
5424
|
+
outcome,
|
|
5425
|
+
outcome_message: options.outcomeMessage,
|
|
5426
|
+
metadata: options.metadata,
|
|
5427
|
+
complete_kanban_item_id: options.completeKanbanItemId ?? void 0,
|
|
5428
|
+
result: options.result
|
|
5429
|
+
});
|
|
5430
|
+
return;
|
|
5431
|
+
} catch (err) {
|
|
5432
|
+
const errText = err instanceof Error ? err.message : String(err);
|
|
5433
|
+
const errId = createHash9("sha256").update(errText).digest("hex").slice(0, 12);
|
|
5434
|
+
const status = err instanceof ApiError ? err.status : 0;
|
|
5435
|
+
if (isRetryableFinishError(err) && attempt < maxRetries) {
|
|
5436
|
+
log(
|
|
5437
|
+
`[runs] finish attempt ${attempt + 1}/${maxRetries + 1} failed for run_id=${runId} outcome=${outcome} status=${status} error_id=${errId} \u2014 retrying`
|
|
5438
|
+
);
|
|
5439
|
+
await new Promise((resolve) => setTimeout(resolve, baseMs * 2 ** attempt));
|
|
5440
|
+
continue;
|
|
5441
|
+
}
|
|
5442
|
+
log(
|
|
5443
|
+
`[runs] finish failed for run_id=${runId} outcome=${outcome} status=${status} error_id=${errId} attempts=${attempt + 1} \u2014 run row left unclosed`
|
|
5444
|
+
);
|
|
5445
|
+
return;
|
|
5446
|
+
}
|
|
5387
5447
|
}
|
|
5388
5448
|
}
|
|
5389
5449
|
var MAX_PRIOR_RUNS = 5;
|
|
@@ -9758,7 +9818,7 @@ async function runAgentSessionToolBindProbes(agent, integrations, projectDir, op
|
|
|
9758
9818
|
}
|
|
9759
9819
|
return result != null;
|
|
9760
9820
|
}
|
|
9761
|
-
function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason, gateReason = breakerReason) {
|
|
9821
|
+
function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason, gateReason = breakerReason, runClose) {
|
|
9762
9822
|
const gate = restartGateFor(codeName, gateReason);
|
|
9763
9823
|
if (gate !== "bypass" && gate !== "proceed") {
|
|
9764
9824
|
log(`[maintenance-window] Deferring '${gateReason}' restart for '${codeName}' (${gate})`);
|
|
@@ -9771,8 +9831,10 @@ function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason, gate
|
|
|
9771
9831
|
runningMcpServerKeys.delete(codeName);
|
|
9772
9832
|
runningChannelSecretHashes.delete(codeName);
|
|
9773
9833
|
sessionLaunchManagedStructure.delete(codeName);
|
|
9774
|
-
|
|
9775
|
-
|
|
9834
|
+
const runOutcome = runClose?.outcome ?? "cancelled";
|
|
9835
|
+
const runMessage = runClose ? `session stopped (${runClose.message})` : `session stopped (${breakerReason ?? "deprovision"})`;
|
|
9836
|
+
closeInjectedRunIfOpen(codeName, runOutcome, runMessage);
|
|
9837
|
+
closeScheduledRunsForCode(codeName, runOutcome, runMessage);
|
|
9776
9838
|
if (breakerReason) {
|
|
9777
9839
|
recordRestartForBreaker(codeName, breakerReason);
|
|
9778
9840
|
}
|
|
@@ -9976,7 +10038,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
9976
10038
|
var lastVersionCheckAt = 0;
|
|
9977
10039
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
9978
10040
|
var lastResponsivenessProbeAt = 0;
|
|
9979
|
-
var agtCliVersion = true ? "0.28.
|
|
10041
|
+
var agtCliVersion = true ? "0.28.468" : "dev";
|
|
9980
10042
|
function resolveBrewPath(execFileSync2) {
|
|
9981
10043
|
try {
|
|
9982
10044
|
const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -14340,9 +14402,38 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
14340
14402
|
anthropicApiKeyFingerprint = exchange.anthropicApiKeyFingerprint;
|
|
14341
14403
|
} catch (err) {
|
|
14342
14404
|
const msg = err.message;
|
|
14405
|
+
const healthyBefore = isSessionHealthy(codeName);
|
|
14406
|
+
const authFailure = decideAuthResolveFailureAction({ error: err, sessionHealthy: healthyBefore });
|
|
14407
|
+
const kind = exchangeFailureKind(err);
|
|
14408
|
+
if (authFailure.action === "preserve-session") {
|
|
14409
|
+
log(
|
|
14410
|
+
`[persistent-session] Failed to resolve auth for '${codeName}': ${msg} \u2014 transient (${kind}), leaving the healthy session running; retrying next poll`
|
|
14411
|
+
);
|
|
14412
|
+
const healthyAfter = isSessionHealthy(codeName);
|
|
14413
|
+
if (healthyAfter) {
|
|
14414
|
+
return {
|
|
14415
|
+
decision: "skipped-auth-resolve-transient",
|
|
14416
|
+
spawnAttempted: false,
|
|
14417
|
+
sessionHealthyAfter: true,
|
|
14418
|
+
detail: `${authFailure.reason} (${kind}): ${msg}`
|
|
14419
|
+
};
|
|
14420
|
+
}
|
|
14421
|
+
log(
|
|
14422
|
+
`[persistent-session] '${codeName}' session did NOT survive the transient auth failure (${kind}) \u2014 reporting as a skip, next poll respawns`
|
|
14423
|
+
);
|
|
14424
|
+
return {
|
|
14425
|
+
decision: "skipped-auth-resolve-failed",
|
|
14426
|
+
spawnAttempted: false,
|
|
14427
|
+
sessionHealthyAfter: false,
|
|
14428
|
+
detail: `transient-fault-session-lost (${kind}): ${msg}`
|
|
14429
|
+
};
|
|
14430
|
+
}
|
|
14343
14431
|
log(`[persistent-session] Failed to resolve auth for '${codeName}': ${msg} \u2014 refusing to spawn`);
|
|
14344
|
-
if (
|
|
14345
|
-
stopPersistentSessionAndForgetMcpBaseline(codeName
|
|
14432
|
+
if (authFailure.action === "stop-session") {
|
|
14433
|
+
stopPersistentSessionAndForgetMcpBaseline(codeName, void 0, void 0, {
|
|
14434
|
+
outcome: "failed",
|
|
14435
|
+
message: `auth resolve failed (${kind})`
|
|
14436
|
+
});
|
|
14346
14437
|
agentState.persistentSessionAgents.delete(codeName);
|
|
14347
14438
|
claudeAuthTupleBySession.delete(codeName);
|
|
14348
14439
|
}
|
|
@@ -14350,7 +14441,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
14350
14441
|
decision: "skipped-auth-resolve-failed",
|
|
14351
14442
|
spawnAttempted: false,
|
|
14352
14443
|
sessionHealthyAfter: isSessionHealthy(codeName),
|
|
14353
|
-
detail: msg
|
|
14444
|
+
detail: `${authFailure.reason} (${kind}): ${msg}`
|
|
14354
14445
|
};
|
|
14355
14446
|
}
|
|
14356
14447
|
if (claudeAuthMode === "openrouter" || openRouterForAgent) {
|