@integrity-labs/agt-cli 0.28.1148 → 0.28.1150
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 +7 -7
- package/dist/{chunk-JZZW47PT.js → chunk-AJ2Z3VSN.js} +2 -2
- package/dist/{chunk-EZUCUG2W.js → chunk-HZFXWUA2.js} +10 -10
- package/dist/{chunk-LAPK7BDU.js → chunk-NSX27ZTP.js} +4 -4
- package/dist/{chunk-2PGIZQIJ.js → chunk-OISSVMYG.js} +12 -12
- package/dist/{chunk-D25NK5E5.js → chunk-TLDY7AE4.js} +5 -1
- package/dist/{chunk-D25NK5E5.js.map → chunk-TLDY7AE4.js.map} +1 -1
- package/dist/{claude-code-updater-NJMCC77Q.js → claude-code-updater-JXL4CM2V.js} +3 -3
- package/dist/{claude-pair-runtime-VQJGKE4W.js → claude-pair-runtime-7QPXNON3.js} +74 -11
- package/dist/claude-pair-runtime-7QPXNON3.js.map +1 -0
- package/dist/lib/manager-worker.js +298 -71
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-MFHKSBD5.js → persistent-session-YKRO5RLK.js} +4 -4
- package/dist/{responsiveness-probe-YLIBVLAR.js → responsiveness-probe-LVRBC2AA.js} +4 -4
- package/dist/{session-auth-dead-PUVWMX5P.js → session-auth-dead-FREXPXHN.js} +3 -3
- package/package.json +1 -1
- package/dist/claude-pair-runtime-VQJGKE4W.js.map +0 -1
- /package/dist/{chunk-JZZW47PT.js.map → chunk-AJ2Z3VSN.js.map} +0 -0
- /package/dist/{chunk-EZUCUG2W.js.map → chunk-HZFXWUA2.js.map} +0 -0
- /package/dist/{chunk-LAPK7BDU.js.map → chunk-NSX27ZTP.js.map} +0 -0
- /package/dist/{chunk-2PGIZQIJ.js.map → chunk-OISSVMYG.js.map} +0 -0
- /package/dist/{claude-code-updater-NJMCC77Q.js.map → claude-code-updater-JXL4CM2V.js.map} +0 -0
- /package/dist/{persistent-session-MFHKSBD5.js.map → persistent-session-YKRO5RLK.js.map} +0 -0
- /package/dist/{responsiveness-probe-YLIBVLAR.js.map → responsiveness-probe-LVRBC2AA.js.map} +0 -0
- /package/dist/{session-auth-dead-PUVWMX5P.js.map → session-auth-dead-FREXPXHN.js.map} +0 -0
|
@@ -77,11 +77,11 @@ import {
|
|
|
77
77
|
setConfigHash,
|
|
78
78
|
shellGuard,
|
|
79
79
|
tripClass
|
|
80
|
-
} from "../chunk-
|
|
80
|
+
} from "../chunk-HZFXWUA2.js";
|
|
81
81
|
import {
|
|
82
82
|
CLAUDE_CODE_SECURITY_FLOOR,
|
|
83
83
|
compareVersions
|
|
84
|
-
} from "../chunk-
|
|
84
|
+
} from "../chunk-NSX27ZTP.js";
|
|
85
85
|
import {
|
|
86
86
|
getProjectDir as getProjectDir2,
|
|
87
87
|
getReadyTasks,
|
|
@@ -168,7 +168,7 @@ import {
|
|
|
168
168
|
webFetchBaselineValue,
|
|
169
169
|
webFetchRestartNeeded,
|
|
170
170
|
writeEgressAllowlist
|
|
171
|
-
} from "../chunk-
|
|
171
|
+
} from "../chunk-OISSVMYG.js";
|
|
172
172
|
import {
|
|
173
173
|
isAgentIdle,
|
|
174
174
|
isStaleForToday,
|
|
@@ -177,7 +177,7 @@ import {
|
|
|
177
177
|
sessionTranscriptDir,
|
|
178
178
|
subagentActivityAgeSeconds,
|
|
179
179
|
transcriptActivityAgeSeconds
|
|
180
|
-
} from "../chunk-
|
|
180
|
+
} from "../chunk-AJ2Z3VSN.js";
|
|
181
181
|
import {
|
|
182
182
|
classifyUnanswerablePane,
|
|
183
183
|
focusedConfirmDialogBlock,
|
|
@@ -190,6 +190,13 @@ import {
|
|
|
190
190
|
parsePsRows,
|
|
191
191
|
reapOrphanChannelMcps
|
|
192
192
|
} from "../chunk-XWVM4KPK.js";
|
|
193
|
+
import {
|
|
194
|
+
CLAUDE_CONFIG_DIR_ENV,
|
|
195
|
+
claudeConfigDirFor,
|
|
196
|
+
claudeConfigDirIsReady,
|
|
197
|
+
effectiveClaudeJsonPath,
|
|
198
|
+
seedClaudeConfigFromLegacy
|
|
199
|
+
} from "../chunk-EL5MWGGH.js";
|
|
193
200
|
import {
|
|
194
201
|
ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
|
|
195
202
|
AnchorSessionClient,
|
|
@@ -293,14 +300,7 @@ import {
|
|
|
293
300
|
serializeAccountEnforcementMarker,
|
|
294
301
|
stabiliseResetInstant,
|
|
295
302
|
sumTranscriptUsageInWindow
|
|
296
|
-
} from "../chunk-
|
|
297
|
-
import {
|
|
298
|
-
CLAUDE_CONFIG_DIR_ENV,
|
|
299
|
-
claudeConfigDirFor,
|
|
300
|
-
claudeConfigDirIsReady,
|
|
301
|
-
effectiveClaudeJsonPath,
|
|
302
|
-
seedClaudeConfigFromLegacy
|
|
303
|
-
} from "../chunk-EL5MWGGH.js";
|
|
303
|
+
} from "../chunk-TLDY7AE4.js";
|
|
304
304
|
import "../chunk-DGUM43GV.js";
|
|
305
305
|
|
|
306
306
|
// src/lib/manager-worker.ts
|
|
@@ -957,6 +957,156 @@ function claudeCodeUpgradeThrottled() {
|
|
|
957
957
|
}
|
|
958
958
|
}
|
|
959
959
|
|
|
960
|
+
// src/lib/claude-pair-loop.ts
|
|
961
|
+
var PAIR_LOOP_ACTIVE_INTERVAL_MS = 2e3;
|
|
962
|
+
var PAIR_LOOP_IDLE_INTERVAL_MS = 1e4;
|
|
963
|
+
var PAIR_LOOP_MAX_BACKOFF_MS = 12e4;
|
|
964
|
+
var PAIR_LOOP_ARMED_MAX_MS = 15 * 6e4;
|
|
965
|
+
function pairLoopArmed(opts) {
|
|
966
|
+
const max = opts.maxArmedMs ?? PAIR_LOOP_ARMED_MAX_MS;
|
|
967
|
+
const live = /* @__PURE__ */ new Set([...opts.spawnedPairIds, ...opts.pendingPairIds]);
|
|
968
|
+
for (const id of [...opts.firstSeenMs.keys()]) {
|
|
969
|
+
if (!live.has(id)) opts.firstSeenMs.delete(id);
|
|
970
|
+
}
|
|
971
|
+
let fresh = false;
|
|
972
|
+
for (const id of live) {
|
|
973
|
+
let seen = opts.firstSeenMs.get(id);
|
|
974
|
+
if (seen === void 0) {
|
|
975
|
+
seen = opts.nowMs;
|
|
976
|
+
opts.firstSeenMs.set(id, seen);
|
|
977
|
+
}
|
|
978
|
+
if (opts.nowMs - seen < max) fresh = true;
|
|
979
|
+
}
|
|
980
|
+
return fresh;
|
|
981
|
+
}
|
|
982
|
+
function nextPairLoopDelayMs(armed, consecutiveFailures) {
|
|
983
|
+
if (consecutiveFailures > 0) {
|
|
984
|
+
const exp = Math.min(consecutiveFailures - 1, 16);
|
|
985
|
+
return Math.min(PAIR_LOOP_IDLE_INTERVAL_MS * 2 ** exp, PAIR_LOOP_MAX_BACKOFF_MS);
|
|
986
|
+
}
|
|
987
|
+
return armed ? PAIR_LOOP_ACTIVE_INTERVAL_MS : PAIR_LOOP_IDLE_INTERVAL_MS;
|
|
988
|
+
}
|
|
989
|
+
var ClaudePairLoop = class {
|
|
990
|
+
constructor(deps) {
|
|
991
|
+
this.deps = deps;
|
|
992
|
+
this.setTimer = deps.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
|
|
993
|
+
this.clearTimer = deps.clearTimer ?? ((h) => clearTimeout(h));
|
|
994
|
+
}
|
|
995
|
+
timer = null;
|
|
996
|
+
inFlight = false;
|
|
997
|
+
started = false;
|
|
998
|
+
consecutiveFailures = 0;
|
|
999
|
+
// Bumped by stop(): a timer callback from an earlier start() whose tick is
|
|
1000
|
+
// still in flight must not schedule a second timer chain after a restart.
|
|
1001
|
+
generation = 0;
|
|
1002
|
+
inFlightTick = null;
|
|
1003
|
+
setTimer;
|
|
1004
|
+
clearTimer;
|
|
1005
|
+
/** Arm the loop. The first tick runs after one idle interval. Idempotent. */
|
|
1006
|
+
start() {
|
|
1007
|
+
if (this.started) return;
|
|
1008
|
+
this.started = true;
|
|
1009
|
+
this.schedule(PAIR_LOOP_IDLE_INTERVAL_MS);
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Disarm the loop. No new tick starts, and a callback from this generation
|
|
1013
|
+
* will not reschedule. Returns a promise that settles when a tick already in
|
|
1014
|
+
* flight has finished (immediately if none), so shutdown can wait for it
|
|
1015
|
+
* before sweeping tmux sessions.
|
|
1016
|
+
*/
|
|
1017
|
+
stop() {
|
|
1018
|
+
this.started = false;
|
|
1019
|
+
this.generation += 1;
|
|
1020
|
+
if (this.timer != null) this.clearTimer(this.timer);
|
|
1021
|
+
this.timer = null;
|
|
1022
|
+
const pending2 = this.inFlightTick;
|
|
1023
|
+
return pending2 ? pending2.then(() => void 0, () => void 0) : Promise.resolve();
|
|
1024
|
+
}
|
|
1025
|
+
/** True while started. A tick in flight checks this before spawning anything new. */
|
|
1026
|
+
get accepting() {
|
|
1027
|
+
return this.started;
|
|
1028
|
+
}
|
|
1029
|
+
get failures() {
|
|
1030
|
+
return this.consecutiveFailures;
|
|
1031
|
+
}
|
|
1032
|
+
/** True while a tick is running. Set synchronously before the tick starts. */
|
|
1033
|
+
get busy() {
|
|
1034
|
+
return this.inFlight;
|
|
1035
|
+
}
|
|
1036
|
+
/** One guarded pass. Safe to call from anywhere; never overlaps itself. */
|
|
1037
|
+
async runOnce() {
|
|
1038
|
+
if (!this.deps.canRun()) return "skipped-not-running";
|
|
1039
|
+
if (this.inFlight) return "skipped-in-flight";
|
|
1040
|
+
this.inFlight = true;
|
|
1041
|
+
try {
|
|
1042
|
+
const tick = this.deps.tick();
|
|
1043
|
+
this.inFlightTick = tick;
|
|
1044
|
+
await tick;
|
|
1045
|
+
if (this.consecutiveFailures > 0) {
|
|
1046
|
+
this.deps.log(`[claude-pair] loop recovered after ${this.consecutiveFailures} failed tick(s)`);
|
|
1047
|
+
}
|
|
1048
|
+
this.consecutiveFailures = 0;
|
|
1049
|
+
return "ran";
|
|
1050
|
+
} catch (err) {
|
|
1051
|
+
this.consecutiveFailures += 1;
|
|
1052
|
+
if (this.consecutiveFailures === 1 || this.consecutiveFailures % 10 === 0) {
|
|
1053
|
+
this.deps.log(
|
|
1054
|
+
`[claude-pair] poll failed (${this.consecutiveFailures} in a row): ${err?.message ?? String(err)}`
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
return "failed";
|
|
1058
|
+
} finally {
|
|
1059
|
+
this.inFlight = false;
|
|
1060
|
+
this.inFlightTick = null;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
schedule(ms) {
|
|
1064
|
+
if (!this.started) return;
|
|
1065
|
+
const gen = this.generation;
|
|
1066
|
+
const h = this.setTimer(() => {
|
|
1067
|
+
this.timer = null;
|
|
1068
|
+
if (gen !== this.generation) return;
|
|
1069
|
+
void this.runOnce().finally(() => {
|
|
1070
|
+
if (gen !== this.generation) return;
|
|
1071
|
+
let armed = false;
|
|
1072
|
+
try {
|
|
1073
|
+
armed = this.deps.isArmed();
|
|
1074
|
+
} catch {
|
|
1075
|
+
armed = false;
|
|
1076
|
+
}
|
|
1077
|
+
this.schedule(nextPairLoopDelayMs(armed, this.consecutiveFailures));
|
|
1078
|
+
});
|
|
1079
|
+
}, ms);
|
|
1080
|
+
if (h && typeof h === "object" && typeof h.unref === "function") h.unref();
|
|
1081
|
+
this.timer = h;
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
var PairRetryBackoff = class {
|
|
1085
|
+
state = /* @__PURE__ */ new Map();
|
|
1086
|
+
/** True while this pair is inside its backoff window: skip it this tick. */
|
|
1087
|
+
shouldSkip(pairId, nowMs) {
|
|
1088
|
+
const s = this.state.get(pairId);
|
|
1089
|
+
return !!s && nowMs < s.notBeforeMs;
|
|
1090
|
+
}
|
|
1091
|
+
recordFailure(pairId, nowMs) {
|
|
1092
|
+
const failures = (this.state.get(pairId)?.failures ?? 0) + 1;
|
|
1093
|
+
this.state.set(pairId, { failures, notBeforeMs: nowMs + nextPairLoopDelayMs(true, failures) });
|
|
1094
|
+
return failures;
|
|
1095
|
+
}
|
|
1096
|
+
/** A dispatch that completed clears the pair's backoff. */
|
|
1097
|
+
recordSuccess(pairId) {
|
|
1098
|
+
this.state.delete(pairId);
|
|
1099
|
+
}
|
|
1100
|
+
/** Forget pairs that are neither spawned nor pending any more. */
|
|
1101
|
+
prune(liveIds) {
|
|
1102
|
+
const live = new Set(liveIds);
|
|
1103
|
+
for (const id of [...this.state.keys()]) if (!live.has(id)) this.state.delete(id);
|
|
1104
|
+
}
|
|
1105
|
+
failuresFor(pairId) {
|
|
1106
|
+
return this.state.get(pairId)?.failures ?? 0;
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
|
|
960
1110
|
// src/lib/mcp-config-drift.ts
|
|
961
1111
|
import { createHash } from "crypto";
|
|
962
1112
|
function decideMcpDriftAction(currentHash, knownHash) {
|
|
@@ -14891,7 +15041,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
|
|
|
14891
15041
|
var dayRolloverInboundHold = /* @__PURE__ */ new Map();
|
|
14892
15042
|
var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
|
|
14893
15043
|
async function channelInboundActivityAgeSecondsFor(codeName) {
|
|
14894
|
-
const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-
|
|
15044
|
+
const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-LVRBC2AA.js");
|
|
14895
15045
|
const newest = newestPendingInboundActivityMtimeMs(dirname11(paneLogPath(codeName)));
|
|
14896
15046
|
if (newest === null) return null;
|
|
14897
15047
|
return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
|
|
@@ -15649,7 +15799,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
15649
15799
|
var lastVersionCheckAt = 0;
|
|
15650
15800
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
15651
15801
|
var lastResponsivenessProbeAt = 0;
|
|
15652
|
-
var agtCliVersion = true ? "0.28.
|
|
15802
|
+
var agtCliVersion = true ? "0.28.1150" : "dev";
|
|
15653
15803
|
function resolveBrewPath(execFileSync3) {
|
|
15654
15804
|
try {
|
|
15655
15805
|
const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -17424,7 +17574,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
|
|
|
17424
17574
|
if (codeNames.length === 0) return;
|
|
17425
17575
|
void (async () => {
|
|
17426
17576
|
try {
|
|
17427
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
17577
|
+
const { collectDiagnostics } = await import("../persistent-session-YKRO5RLK.js");
|
|
17428
17578
|
await api.post("/host/heartbeat", {
|
|
17429
17579
|
host_id: hostId,
|
|
17430
17580
|
agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
|
|
@@ -17566,7 +17716,7 @@ async function pollCycleInner() {
|
|
|
17566
17716
|
}
|
|
17567
17717
|
try {
|
|
17568
17718
|
const { detectHostSecurity } = await import("../host-security-KQYYZZVW.js");
|
|
17569
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
17719
|
+
const { collectDiagnostics } = await import("../persistent-session-YKRO5RLK.js");
|
|
17570
17720
|
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
17571
17721
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor) : void 0;
|
|
17572
17722
|
let tailscaleHostname;
|
|
@@ -17766,8 +17916,13 @@ async function pollCycleInner() {
|
|
|
17766
17916
|
setConfigHash(hbResp?.config_hash ?? null);
|
|
17767
17917
|
try {
|
|
17768
17918
|
const desiredClaudeCodeVersion = hbResp?.desired_claude_code_version?.trim();
|
|
17769
|
-
const { maybeUpdateClaudeCode, shouldRunClaudeCodeUpdater } = await import("../claude-code-updater-
|
|
17770
|
-
|
|
17919
|
+
const { maybeUpdateClaudeCode, shouldRunClaudeCodeUpdater } = await import("../claude-code-updater-JXL4CM2V.js");
|
|
17920
|
+
claudeUpdaterInFlight = true;
|
|
17921
|
+
if (desiredClaudeCodeVersion && (claudePairLoop.busy || claudePairingInProgress())) {
|
|
17922
|
+
log(
|
|
17923
|
+
claudePairingInProgress() ? "[claude-code-updater] Claude re-login in progress on this host, deferring to a later cycle" : "[claude-code-updater] a claude-pair poll is mid-flight (no re-login), deferring to the next cycle"
|
|
17924
|
+
);
|
|
17925
|
+
} else if (desiredClaudeCodeVersion && shouldRunClaudeCodeUpdater({
|
|
17771
17926
|
desiredVersion: desiredClaudeCodeVersion,
|
|
17772
17927
|
installedVersion: cachedFrameworkVersion,
|
|
17773
17928
|
windowGate: decideMaintenanceWindowGate({ window: cachedMaintenanceWindow, now: /* @__PURE__ */ new Date() })
|
|
@@ -17780,6 +17935,8 @@ async function pollCycleInner() {
|
|
|
17780
17935
|
}
|
|
17781
17936
|
} catch (err) {
|
|
17782
17937
|
log(`Claude Code updater error: ${err.message}`);
|
|
17938
|
+
} finally {
|
|
17939
|
+
claudeUpdaterInFlight = false;
|
|
17783
17940
|
}
|
|
17784
17941
|
} catch (err) {
|
|
17785
17942
|
setConfigHash(null);
|
|
@@ -17791,7 +17948,7 @@ async function pollCycleInner() {
|
|
|
17791
17948
|
collectPanelessActivityProbes,
|
|
17792
17949
|
getResponsivenessIntervalMs,
|
|
17793
17950
|
occupancyQualificationClassifications
|
|
17794
|
-
} = await import("../responsiveness-probe-
|
|
17951
|
+
} = await import("../responsiveness-probe-LVRBC2AA.js");
|
|
17795
17952
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
17796
17953
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
17797
17954
|
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
@@ -17908,7 +18065,7 @@ async function pollCycleInner() {
|
|
|
17908
18065
|
collectResponsivenessProbes,
|
|
17909
18066
|
livePendingInboundOldestAgeSeconds,
|
|
17910
18067
|
parkPendingInbound
|
|
17911
|
-
} = await import("../responsiveness-probe-
|
|
18068
|
+
} = await import("../responsiveness-probe-LVRBC2AA.js");
|
|
17912
18069
|
const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-M6AFZWNU.js");
|
|
17913
18070
|
const wedgeNow = /* @__PURE__ */ new Date();
|
|
17914
18071
|
const liveAgents = agentState.persistentSessionAgents;
|
|
@@ -18194,7 +18351,7 @@ async function pollCycleInner() {
|
|
|
18194
18351
|
}
|
|
18195
18352
|
}
|
|
18196
18353
|
);
|
|
18197
|
-
const { parkPendingInbound } = await import("../responsiveness-probe-
|
|
18354
|
+
const { parkPendingInbound } = await import("../responsiveness-probe-LVRBC2AA.js");
|
|
18198
18355
|
const { parked, deadLettered } = parkPendingInbound(codeName, new Date(fatalNowMs));
|
|
18199
18356
|
paneFatalStreak.delete(codeName);
|
|
18200
18357
|
paneFatalRestarts.set(codeName, [...history, fatalNowMs]);
|
|
@@ -18225,7 +18382,7 @@ async function pollCycleInner() {
|
|
|
18225
18382
|
TRANSCRIPT_MOUNT_ESCALATION_REFRESH_MS,
|
|
18226
18383
|
bindSourceEscalations
|
|
18227
18384
|
} = await import("../transcript-mount-health-OHE6IVJV.js");
|
|
18228
|
-
const { transcriptBindSourcesFor, ensureTranscriptBindSources } = await import("../persistent-session-
|
|
18385
|
+
const { transcriptBindSourcesFor, ensureTranscriptBindSources } = await import("../persistent-session-YKRO5RLK.js");
|
|
18229
18386
|
const mountConfig = resolveTranscriptMountConfig();
|
|
18230
18387
|
const liveAgents = agentState.persistentSessionAgents;
|
|
18231
18388
|
for (const tracked of [
|
|
@@ -18390,7 +18547,7 @@ async function pollCycleInner() {
|
|
|
18390
18547
|
}
|
|
18391
18548
|
try {
|
|
18392
18549
|
const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-VR5QGP3J.js");
|
|
18393
|
-
const { probeSessionAuth } = await import("../session-auth-dead-
|
|
18550
|
+
const { probeSessionAuth } = await import("../session-auth-dead-FREXPXHN.js");
|
|
18394
18551
|
const observations = [];
|
|
18395
18552
|
const pendingCacheCommits = [];
|
|
18396
18553
|
const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
|
|
@@ -18460,6 +18617,10 @@ async function pollCycleInner() {
|
|
|
18460
18617
|
}
|
|
18461
18618
|
const data = await api.post("/host/agents", { host_id: hostId });
|
|
18462
18619
|
const agents = data.agents ?? [];
|
|
18620
|
+
pairableAgentsSnapshot = agents.map((a) => ({
|
|
18621
|
+
agentId: a.agent_id,
|
|
18622
|
+
codeName: a.code_name
|
|
18623
|
+
}));
|
|
18463
18624
|
hostFlagStore().setMirrorAgentIds(agents.map((a) => a.agent_id));
|
|
18464
18625
|
if (agents.length > 0) {
|
|
18465
18626
|
if (consecutiveEmptyAgentPolls > 0) {
|
|
@@ -18881,14 +19042,6 @@ async function pollCycleInner() {
|
|
|
18881
19042
|
clearAgentCaches(prev.agentId, prev.codeName);
|
|
18882
19043
|
}
|
|
18883
19044
|
}
|
|
18884
|
-
try {
|
|
18885
|
-
await processClaudePairSessions(agents.map((a) => ({
|
|
18886
|
-
agentId: a.agent_id,
|
|
18887
|
-
codeName: a.code_name
|
|
18888
|
-
})));
|
|
18889
|
-
} catch (err) {
|
|
18890
|
-
log(`[claude-pair] poll failed: ${err.message}`);
|
|
18891
|
-
}
|
|
18892
19045
|
if (Date.now() - lastChannelSweepAt >= CHANNEL_SWEEP_INTERVAL_MS) {
|
|
18893
19046
|
lastChannelSweepAt = Date.now();
|
|
18894
19047
|
const agentCodeNames = new Set(
|
|
@@ -22269,7 +22422,11 @@ async function ensurePersistentSessionUnchecked(agent, tasks, boardItems, refres
|
|
|
22269
22422
|
const currentPolicyId = currentPolicyModel ? modelPolicy?.policyId ?? null : null;
|
|
22270
22423
|
const recordedAuthTuple = claudeAuthTupleBySession.get(codeName);
|
|
22271
22424
|
const recordedPolicyModel = modelPolicyModelBySession.get(codeName);
|
|
22272
|
-
|
|
22425
|
+
const authTupleChanged = Boolean(recordedAuthTuple && recordedAuthTuple !== currentAuthTuple);
|
|
22426
|
+
if (authTupleChanged && claudePairingInProgress()) {
|
|
22427
|
+
log(`[${codeName}] auth tuple changed while a Claude re-login is in progress, deferring the restart to the next cycle`);
|
|
22428
|
+
}
|
|
22429
|
+
if (recordedAuthTuple && recordedAuthTuple !== currentAuthTuple && !claudePairingInProgress() && isSessionHealthy(codeName)) {
|
|
22273
22430
|
const authTupleDiff = diffAuthTuples(recordedAuthTuple, currentAuthTuple);
|
|
22274
22431
|
log(
|
|
22275
22432
|
`[persistent-session] Auth config changed for '${codeName}' (${recordedAuthTuple} \u2192 ${currentAuthTuple}) \u2014 ${authTupleDiff.summary} \u2014 restarting session`
|
|
@@ -22280,7 +22437,9 @@ async function ensurePersistentSessionUnchecked(agent, tasks, boardItems, refres
|
|
|
22280
22437
|
previousModel: recordedPolicyModel,
|
|
22281
22438
|
currentModel: currentPolicyModel
|
|
22282
22439
|
});
|
|
22283
|
-
|
|
22440
|
+
let restartNoticeLanded = false;
|
|
22441
|
+
const noticeAlreadyDelivered = restartNoticeDeliveredFor.get(codeName) === currentAuthTuple;
|
|
22442
|
+
if (policyNotice && isSessionHealthy(codeName) && !noticeAlreadyDelivered) {
|
|
22284
22443
|
const status = await injectMessageWithStatus(
|
|
22285
22444
|
codeName,
|
|
22286
22445
|
"system",
|
|
@@ -22293,6 +22452,7 @@ async function ensurePersistentSessionUnchecked(agent, tasks, boardItems, refres
|
|
|
22293
22452
|
log
|
|
22294
22453
|
).catch(() => ({ delivered: false, fallbackUsed: false }));
|
|
22295
22454
|
if (status.fallbackUsed) {
|
|
22455
|
+
restartNoticeLanded = true;
|
|
22296
22456
|
await new Promise((r) => setTimeout(r, 3e3));
|
|
22297
22457
|
} else {
|
|
22298
22458
|
log(
|
|
@@ -22300,18 +22460,35 @@ async function ensurePersistentSessionUnchecked(agent, tasks, boardItems, refres
|
|
|
22300
22460
|
);
|
|
22301
22461
|
}
|
|
22302
22462
|
}
|
|
22303
|
-
|
|
22304
|
-
|
|
22305
|
-
|
|
22306
|
-
|
|
22307
|
-
|
|
22308
|
-
|
|
22309
|
-
|
|
22310
|
-
|
|
22463
|
+
if (claudePairingInProgress()) {
|
|
22464
|
+
if (restartNoticeLanded) {
|
|
22465
|
+
restartNoticeDeliveredFor.set(codeName, currentAuthTuple);
|
|
22466
|
+
await injectMessageWithStatus(
|
|
22467
|
+
codeName,
|
|
22468
|
+
"system",
|
|
22469
|
+
"Update: the restart announced above is postponed for a moment while a Claude sign-in finishes on this host. Carry on; it will happen shortly, without a further notice.",
|
|
22470
|
+
{ task_name: "model-policy-restart-postponed" },
|
|
22471
|
+
log
|
|
22472
|
+
).catch(() => void 0);
|
|
22311
22473
|
}
|
|
22312
|
-
|
|
22313
|
-
|
|
22314
|
-
|
|
22474
|
+
log(
|
|
22475
|
+
`[${codeName}] Claude re-login in progress, deferring the auth-tuple restart to the next cycle` + (restartNoticeLanded || noticeAlreadyDelivered ? " (restart notice already delivered, not re-sent)" : "")
|
|
22476
|
+
);
|
|
22477
|
+
} else {
|
|
22478
|
+
restartNoticeDeliveredFor.delete(codeName);
|
|
22479
|
+
stopPersistentSessionAndForgetMcpBaseline(codeName, "auth-tuple-change", void 0, void 0, {
|
|
22480
|
+
reason: authTupleDiff.summary,
|
|
22481
|
+
detail: {
|
|
22482
|
+
auth_tuple: {
|
|
22483
|
+
changed: authTupleDiff.changed,
|
|
22484
|
+
unchanged: authTupleDiff.unchanged,
|
|
22485
|
+
components: authTupleDiff.components
|
|
22486
|
+
}
|
|
22487
|
+
}
|
|
22488
|
+
});
|
|
22489
|
+
agentState.persistentSessionAgents.delete(codeName);
|
|
22490
|
+
restartTrigger = "auth-tuple";
|
|
22491
|
+
}
|
|
22315
22492
|
}
|
|
22316
22493
|
const staleForToday = isStaleForToday(codeName, /* @__PURE__ */ new Date(), agentTimezone);
|
|
22317
22494
|
if (!staleForToday) pendingDayRolloverReset.delete(codeName);
|
|
@@ -23030,7 +23207,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
|
|
|
23030
23207
|
try {
|
|
23031
23208
|
const freshId = rotateSessionForWedge(codeName);
|
|
23032
23209
|
consecutiveWedgeCycles.delete(codeName);
|
|
23033
|
-
const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-
|
|
23210
|
+
const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-LVRBC2AA.js");
|
|
23034
23211
|
const { parked, deadLettered } = parkForRestart(codeName, /* @__PURE__ */ new Date());
|
|
23035
23212
|
const parkNote = parked > 0 ? `, ${parked} inbound parked` : "";
|
|
23036
23213
|
const deadNote = deadLettered > 0 ? `, ${deadLettered} undeliverable dead-lettered` : "";
|
|
@@ -23073,7 +23250,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
|
|
|
23073
23250
|
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}`));
|
|
23074
23251
|
void (async () => {
|
|
23075
23252
|
try {
|
|
23076
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
23253
|
+
const { collectDiagnostics } = await import("../persistent-session-YKRO5RLK.js");
|
|
23077
23254
|
await api.post("/host/heartbeat", {
|
|
23078
23255
|
host_id: hostId,
|
|
23079
23256
|
agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
|
|
@@ -23124,7 +23301,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
|
|
|
23124
23301
|
}
|
|
23125
23302
|
try {
|
|
23126
23303
|
const hostId = await getHostId();
|
|
23127
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
23304
|
+
const { collectDiagnostics } = await import("../persistent-session-YKRO5RLK.js");
|
|
23128
23305
|
await api.post("/host/heartbeat", {
|
|
23129
23306
|
host_id: hostId,
|
|
23130
23307
|
agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
|
|
@@ -23771,6 +23948,47 @@ var boardTokenCache = new BoardTokenCache();
|
|
|
23771
23948
|
var notifyBoardCache = /* @__PURE__ */ new Map();
|
|
23772
23949
|
var notifiedWaitingHumanIds = /* @__PURE__ */ new Map();
|
|
23773
23950
|
var spawnedPairIds = /* @__PURE__ */ new Set();
|
|
23951
|
+
var pairableAgentsSnapshot = [];
|
|
23952
|
+
var lastPairPendingIds = [];
|
|
23953
|
+
var pairFirstSeenMs = /* @__PURE__ */ new Map();
|
|
23954
|
+
function claudePairLoopArmed() {
|
|
23955
|
+
return pairLoopArmed({
|
|
23956
|
+
spawnedPairIds,
|
|
23957
|
+
pendingPairIds: lastPairPendingIds,
|
|
23958
|
+
firstSeenMs: pairFirstSeenMs,
|
|
23959
|
+
nowMs: Date.now()
|
|
23960
|
+
});
|
|
23961
|
+
}
|
|
23962
|
+
var pairRetryBackoff = new PairRetryBackoff();
|
|
23963
|
+
var restartNoticeDeliveredFor = /* @__PURE__ */ new Map();
|
|
23964
|
+
var claudeUpdaterInFlight = false;
|
|
23965
|
+
async function runClaudePairTick() {
|
|
23966
|
+
if (pairableAgentsSnapshot.length === 0 && spawnedPairIds.size === 0) lastPairPendingIds = [];
|
|
23967
|
+
if (claudeUpdaterInFlight) return;
|
|
23968
|
+
await processClaudePairSessions(pairableAgentsSnapshot);
|
|
23969
|
+
pairRetryBackoff.prune([...spawnedPairIds, ...lastPairPendingIds]);
|
|
23970
|
+
}
|
|
23971
|
+
async function _claudePairTickForTests(agents) {
|
|
23972
|
+
const prevRunning = running;
|
|
23973
|
+
running = true;
|
|
23974
|
+
claudePairLoop.start();
|
|
23975
|
+
pairableAgentsSnapshot = [...agents];
|
|
23976
|
+
try {
|
|
23977
|
+
await runClaudePairTick();
|
|
23978
|
+
} finally {
|
|
23979
|
+
void claudePairLoop.stop();
|
|
23980
|
+
running = prevRunning;
|
|
23981
|
+
}
|
|
23982
|
+
}
|
|
23983
|
+
function claudePairingInProgress() {
|
|
23984
|
+
return claudePairLoopArmed();
|
|
23985
|
+
}
|
|
23986
|
+
var claudePairLoop = new ClaudePairLoop({
|
|
23987
|
+
tick: runClaudePairTick,
|
|
23988
|
+
isArmed: claudePairLoopArmed,
|
|
23989
|
+
canRun: () => running && !!config && !restartAfterUpgrade,
|
|
23990
|
+
log
|
|
23991
|
+
});
|
|
23774
23992
|
async function processClaudePairSessions(agents) {
|
|
23775
23993
|
if (agents.length === 0 && spawnedPairIds.size === 0) return;
|
|
23776
23994
|
const agentIds = agents.map((a) => a.agentId);
|
|
@@ -23779,6 +23997,7 @@ async function processClaudePairSessions(agents) {
|
|
|
23779
23997
|
agent_ids: agentIds,
|
|
23780
23998
|
spawned_pair_ids: Array.from(spawnedPairIds)
|
|
23781
23999
|
});
|
|
24000
|
+
lastPairPendingIds = (pendingResp.pending ?? []).map((p) => p.pair_id);
|
|
23782
24001
|
const {
|
|
23783
24002
|
startClaudePair,
|
|
23784
24003
|
submitClaudePairCode,
|
|
@@ -23796,8 +24015,10 @@ async function processClaudePairSessions(agents) {
|
|
|
23796
24015
|
// ENG-10862: the pre-submit mtime baseline. Taken here because finalize
|
|
23797
24016
|
// cannot take it for itself — by the time it runs, the write it is looking
|
|
23798
24017
|
// for may already have happened.
|
|
23799
|
-
snapshotPairConfig
|
|
23800
|
-
|
|
24018
|
+
snapshotPairConfig,
|
|
24019
|
+
// ENG-11659: result -> report body + the manager.log line that records it.
|
|
24020
|
+
planPairStartReport
|
|
24021
|
+
} = await import("../claude-pair-runtime-7QPXNON3.js");
|
|
23801
24022
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
23802
24023
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
23803
24024
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -23815,7 +24036,10 @@ async function processClaudePairSessions(agents) {
|
|
|
23815
24036
|
"timeout"
|
|
23816
24037
|
]);
|
|
23817
24038
|
async function reportAndCleanup(pairId, body) {
|
|
23818
|
-
await api.post("/host/claude-pair/result", {
|
|
24039
|
+
const resp = await api.post("/host/claude-pair/result", {
|
|
24040
|
+
pair_id: pairId,
|
|
24041
|
+
...body
|
|
24042
|
+
});
|
|
23819
24043
|
if (typeof body.status === "string" && TERMINAL.has(body.status)) {
|
|
23820
24044
|
const isOnboardingFailure = typeof body.error_code === "string" && body.error_code.startsWith("onboarding_");
|
|
23821
24045
|
if (body.status === "success" || isOnboardingFailure) {
|
|
@@ -23826,8 +24050,12 @@ async function processClaudePairSessions(agents) {
|
|
|
23826
24050
|
spawnedPairIds.delete(pairId);
|
|
23827
24051
|
}
|
|
23828
24052
|
}
|
|
24053
|
+
return resp?.no_op !== true;
|
|
23829
24054
|
}
|
|
23830
24055
|
for (const session of pendingResp.pending) {
|
|
24056
|
+
if (!running || !claudePairLoop.accepting) break;
|
|
24057
|
+
if (pairRetryBackoff.shouldSkip(session.pair_id, Date.now())) continue;
|
|
24058
|
+
let dispatchFailed = false;
|
|
23831
24059
|
const codeName = codeNameByAgentId.get(session.agent_id) ?? "<unassigned>";
|
|
23832
24060
|
const pairSession = pairTmuxSession(session.pair_id);
|
|
23833
24061
|
try {
|
|
@@ -23847,26 +24075,13 @@ async function processClaudePairSessions(agents) {
|
|
|
23847
24075
|
spawnedPairIds.add(session.pair_id);
|
|
23848
24076
|
log(`[claude-pair] dispatching /login (pair ${session.pair_id.slice(0, 8)})`);
|
|
23849
24077
|
const result = await startClaudePair({ session: pairSession });
|
|
23850
|
-
|
|
23851
|
-
|
|
23852
|
-
|
|
23853
|
-
|
|
23854
|
-
|
|
23855
|
-
|
|
23856
|
-
|
|
23857
|
-
await reportAndCleanup(session.pair_id, {
|
|
23858
|
-
status: "timeout",
|
|
23859
|
-
error_code: "url_prompt_not_seen",
|
|
23860
|
-
error_message: "Claude Code did not print the URL prompt within the deadline"
|
|
23861
|
-
});
|
|
23862
|
-
} else {
|
|
23863
|
-
const errKind = result.error.kind;
|
|
23864
|
-
const errMessage2 = "message" in result.error ? result.error.message : void 0;
|
|
23865
|
-
await reportAndCleanup(session.pair_id, {
|
|
23866
|
-
status: errKind === "no-session" ? "session_missing" : "failure",
|
|
23867
|
-
error_code: errKind,
|
|
23868
|
-
error_message: errMessage2
|
|
23869
|
-
});
|
|
24078
|
+
const report = planPairStartReport(session.pair_id, result);
|
|
24079
|
+
log(report.logLine);
|
|
24080
|
+
const accepted = await reportAndCleanup(session.pair_id, report.body);
|
|
24081
|
+
if (!accepted) {
|
|
24082
|
+
log(
|
|
24083
|
+
`[claude-pair] result for pair ${session.pair_id.slice(0, 8)} was a server no_op: the row was already terminal (e.g. cancelled from the console) when it landed`
|
|
24084
|
+
);
|
|
23870
24085
|
}
|
|
23871
24086
|
} else if (session.status === "code_submitted" && session.code) {
|
|
23872
24087
|
log(`[claude-pair] submitting code (pair ${session.pair_id.slice(0, 8)})`);
|
|
@@ -23937,7 +24152,13 @@ async function processClaudePairSessions(agents) {
|
|
|
23937
24152
|
}
|
|
23938
24153
|
}
|
|
23939
24154
|
} catch (err) {
|
|
23940
|
-
|
|
24155
|
+
dispatchFailed = true;
|
|
24156
|
+
const failures = pairRetryBackoff.recordFailure(session.pair_id, Date.now());
|
|
24157
|
+
log(
|
|
24158
|
+
`[claude-pair] dispatch failed for pair ${session.pair_id.slice(0, 8)} (${failures} in a row, retrying in ${Math.round(nextPairLoopDelayMs(true, failures) / 1e3)}s): ${err.message}`
|
|
24159
|
+
);
|
|
24160
|
+
} finally {
|
|
24161
|
+
if (!dispatchFailed) pairRetryBackoff.recordSuccess(session.pair_id);
|
|
23941
24162
|
}
|
|
23942
24163
|
}
|
|
23943
24164
|
}
|
|
@@ -24624,6 +24845,7 @@ function startPolling() {
|
|
|
24624
24845
|
void postLivenessHeartbeat();
|
|
24625
24846
|
}, LIVENESS_HEARTBEAT_INTERVAL_MS);
|
|
24626
24847
|
livenessTimer.unref();
|
|
24848
|
+
claudePairLoop.start();
|
|
24627
24849
|
startPaneOccupancySampler(() => agentState.persistentSessionAgents);
|
|
24628
24850
|
startPidPressureSampler(() => agentState.persistentSessionAgents);
|
|
24629
24851
|
startRuntimeVersionSampler(() => agentState.persistentSessionAgents);
|
|
@@ -24790,6 +25012,7 @@ async function stopPolling(opts = {}) {
|
|
|
24790
25012
|
clearInterval(livenessTimer);
|
|
24791
25013
|
livenessTimer = null;
|
|
24792
25014
|
}
|
|
25015
|
+
const pairLoopDrained = claudePairLoop.stop();
|
|
24793
25016
|
stopPaneOccupancySampler();
|
|
24794
25017
|
stopPidPressureSampler();
|
|
24795
25018
|
stopRuntimeVersionSampler();
|
|
@@ -24836,6 +25059,7 @@ async function stopPolling(opts = {}) {
|
|
|
24836
25059
|
closeSessionRunForCode(codeName, "completed", "manager shutdown");
|
|
24837
25060
|
}
|
|
24838
25061
|
const drainReleaseSnapshot = snapshotDrainReleaseTargets();
|
|
25062
|
+
await Promise.race([pairLoopDrained, new Promise((r) => setTimeout(r, 3e3).unref())]);
|
|
24839
25063
|
log("Killing tmux sessions...");
|
|
24840
25064
|
try {
|
|
24841
25065
|
await killAllAgtTmuxSessions();
|
|
@@ -25205,6 +25429,7 @@ export {
|
|
|
25205
25429
|
REALTIME_REBIND_STUCK_AFTER_MS,
|
|
25206
25430
|
SELF_UPDATE_LATCH_MAX_HOLD_MS,
|
|
25207
25431
|
UntrustworthyToolkitResponseError,
|
|
25432
|
+
_claudePairTickForTests,
|
|
25208
25433
|
applyMemoryTombstones,
|
|
25209
25434
|
applyRestartAcks,
|
|
25210
25435
|
cancelKanbanNoticeOnDrain,
|
|
@@ -25213,6 +25438,8 @@ export {
|
|
|
25213
25438
|
claudeCodeUpgradeMarkerPath,
|
|
25214
25439
|
claudeCodeUpgradeThrottled,
|
|
25215
25440
|
claudeManagedSettingsPath,
|
|
25441
|
+
claudePairLoopArmed,
|
|
25442
|
+
claudePairingInProgress,
|
|
25216
25443
|
coverageOf,
|
|
25217
25444
|
createManagedPruneLedger,
|
|
25218
25445
|
createManagedToolkitReader,
|