@integrity-labs/agt-cli 0.23.1 → 0.23.2
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-2TOCO5D2.js → chunk-HSIESZMZ.js} +23 -1
- package/dist/{chunk-2TOCO5D2.js.map → chunk-HSIESZMZ.js.map} +1 -1
- package/dist/{chunk-Q4QD3TAC.js → chunk-WUYKMPYW.js} +203 -157
- package/dist/chunk-WUYKMPYW.js.map +1 -0
- package/dist/{chunk-TCCBS3PD.js → chunk-ZKQGDH3T.js} +2 -2
- package/dist/{claude-pair-runtime-KUWBZW33.js → claude-pair-runtime-XCFWTH6T.js} +2 -2
- package/dist/lib/manager-worker.js +199 -14
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/index.js +71 -0
- package/dist/{persistent-session-XEA4SPAN.js → persistent-session-L4YIJJML.js} +3 -3
- package/dist/{responsiveness-probe-VWPOCABI.js → responsiveness-probe-YRLESO54.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-Q4QD3TAC.js.map +0 -1
- /package/dist/{chunk-TCCBS3PD.js.map → chunk-ZKQGDH3T.js.map} +0 -0
- /package/dist/{claude-pair-runtime-KUWBZW33.js.map → claude-pair-runtime-XCFWTH6T.js.map} +0 -0
- /package/dist/{persistent-session-XEA4SPAN.js.map → persistent-session-L4YIJJML.js.map} +0 -0
- /package/dist/{responsiveness-probe-VWPOCABI.js.map → responsiveness-probe-YRLESO54.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
KANBAN_LOOP_COMMAND
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HSIESZMZ.js";
|
|
4
4
|
|
|
5
5
|
// src/lib/persistent-session.ts
|
|
6
6
|
import { spawn, execSync, execFileSync as execFileSync2 } from "child_process";
|
|
@@ -1167,4 +1167,4 @@ export {
|
|
|
1167
1167
|
stopAllSessionsAndWait,
|
|
1168
1168
|
getProjectDir
|
|
1169
1169
|
};
|
|
1170
|
-
//# sourceMappingURL=chunk-
|
|
1170
|
+
//# sourceMappingURL=chunk-ZKQGDH3T.js.map
|
|
@@ -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-L4YIJJML.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-XCFWTH6T.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SUPERVISOR_RESTART_EXIT_CODE,
|
|
3
3
|
api,
|
|
4
|
+
estimateActiveTasksTokens,
|
|
4
5
|
exchangeApiKey,
|
|
5
6
|
extractCommandNotFound,
|
|
6
7
|
getApiKey,
|
|
@@ -11,7 +12,7 @@ import {
|
|
|
11
12
|
provisionOrientHook,
|
|
12
13
|
provisionStopHook,
|
|
13
14
|
requireHost
|
|
14
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-WUYKMPYW.js";
|
|
15
16
|
import {
|
|
16
17
|
findTaskByTemplate,
|
|
17
18
|
getProjectDir as getProjectDir2,
|
|
@@ -46,7 +47,7 @@ import {
|
|
|
46
47
|
stopAllSessionsAndWait,
|
|
47
48
|
stopPersistentSession,
|
|
48
49
|
takeZombieDetection
|
|
49
|
-
} from "../chunk-
|
|
50
|
+
} from "../chunk-ZKQGDH3T.js";
|
|
50
51
|
import {
|
|
51
52
|
KANBAN_CHECK_COMMAND,
|
|
52
53
|
appendDmFooter,
|
|
@@ -62,7 +63,7 @@ import {
|
|
|
62
63
|
resolveChannels,
|
|
63
64
|
resolveDmTarget,
|
|
64
65
|
wrapScheduledTaskPrompt
|
|
65
|
-
} from "../chunk-
|
|
66
|
+
} from "../chunk-HSIESZMZ.js";
|
|
66
67
|
|
|
67
68
|
// src/lib/manager-worker.ts
|
|
68
69
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -552,6 +553,108 @@ function decideChannelRestart(input) {
|
|
|
552
553
|
return { restart: true, added, removed };
|
|
553
554
|
}
|
|
554
555
|
|
|
556
|
+
// src/lib/restart-breaker.ts
|
|
557
|
+
var DEFAULT_MAX = 2;
|
|
558
|
+
var DEFAULT_WINDOW_MS = 6e5;
|
|
559
|
+
function readEnvNumber(name, fallback) {
|
|
560
|
+
const raw = process.env[name];
|
|
561
|
+
if (!raw) return fallback;
|
|
562
|
+
const parsed = Number(raw);
|
|
563
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
564
|
+
}
|
|
565
|
+
var RestartBreaker = class {
|
|
566
|
+
max;
|
|
567
|
+
windowMs;
|
|
568
|
+
now;
|
|
569
|
+
events = /* @__PURE__ */ new Map();
|
|
570
|
+
trips = /* @__PURE__ */ new Map();
|
|
571
|
+
constructor(opts = {}) {
|
|
572
|
+
this.max = opts.max ?? readEnvNumber("AGT_RESTART_BREAKER_MAX", DEFAULT_MAX);
|
|
573
|
+
this.windowMs = opts.windowMs ?? readEnvNumber("AGT_RESTART_BREAKER_WINDOW_MS", DEFAULT_WINDOW_MS);
|
|
574
|
+
this.now = opts.now ?? Date.now;
|
|
575
|
+
if (!Number.isFinite(this.max) || this.max < 1) {
|
|
576
|
+
throw new Error("restart-breaker max must be a finite number >= 1");
|
|
577
|
+
}
|
|
578
|
+
if (!Number.isFinite(this.windowMs) || this.windowMs < 1e3) {
|
|
579
|
+
throw new Error("restart-breaker windowMs must be a finite number >= 1000");
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
/** True if this agent's breaker is currently tripped (manager must skip spawn). */
|
|
583
|
+
isTripped(codeName) {
|
|
584
|
+
return this.trips.has(codeName);
|
|
585
|
+
}
|
|
586
|
+
getTrip(codeName) {
|
|
587
|
+
return this.trips.get(codeName);
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Record a restart event. If recording this event puts the count
|
|
591
|
+
* inside the window above `max`, the breaker trips and the call site
|
|
592
|
+
* should NOT respawn.
|
|
593
|
+
*
|
|
594
|
+
* Idempotent on already-tripped breakers: returns the existing trip
|
|
595
|
+
* without double-counting events. Callers may still record the reason
|
|
596
|
+
* via the decision-log for forensics.
|
|
597
|
+
*/
|
|
598
|
+
record(codeName, reason) {
|
|
599
|
+
const existing = this.trips.get(codeName);
|
|
600
|
+
if (existing) {
|
|
601
|
+
return { tripped: false, trip: existing, windowCount: existing.eventsAtTrip.length };
|
|
602
|
+
}
|
|
603
|
+
const at = this.now();
|
|
604
|
+
const cutoff = at - this.windowMs;
|
|
605
|
+
const prior = (this.events.get(codeName) ?? []).filter((e) => e.at >= cutoff);
|
|
606
|
+
prior.push({ reason, at });
|
|
607
|
+
this.events.set(codeName, prior);
|
|
608
|
+
if (prior.length > this.max) {
|
|
609
|
+
const trip = {
|
|
610
|
+
trippedAt: at,
|
|
611
|
+
eventsAtTrip: [...prior],
|
|
612
|
+
statusMessage: formatStatusMessage(prior, this.windowMs)
|
|
613
|
+
};
|
|
614
|
+
this.trips.set(codeName, trip);
|
|
615
|
+
this.events.delete(codeName);
|
|
616
|
+
return { tripped: true, trip, windowCount: prior.length };
|
|
617
|
+
}
|
|
618
|
+
return { tripped: false, windowCount: prior.length };
|
|
619
|
+
}
|
|
620
|
+
/** Operator-initiated reset: drops the trip + the events log for this agent. */
|
|
621
|
+
clear(codeName) {
|
|
622
|
+
this.trips.delete(codeName);
|
|
623
|
+
this.events.delete(codeName);
|
|
624
|
+
}
|
|
625
|
+
/** Snapshot tripped agents for `manager-state.json`. */
|
|
626
|
+
serialize() {
|
|
627
|
+
return Object.fromEntries(this.trips.entries());
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Rehydrate trip state from `manager-state.json`. Called once at
|
|
631
|
+
* worker startup. Window history is intentionally NOT persisted — only
|
|
632
|
+
* tripped state. A tripped breaker survives manager restart; an
|
|
633
|
+
* un-tripped one starts a fresh window in the new worker.
|
|
634
|
+
*/
|
|
635
|
+
hydrate(saved) {
|
|
636
|
+
if (!saved) return;
|
|
637
|
+
for (const [codeName, trip] of Object.entries(saved)) {
|
|
638
|
+
if (trip && typeof trip.trippedAt === "number" && Array.isArray(trip.eventsAtTrip)) {
|
|
639
|
+
this.trips.set(codeName, trip);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
/** Test helper — current in-window event count for `codeName`. */
|
|
644
|
+
windowCount(codeName) {
|
|
645
|
+
const cutoff = this.now() - this.windowMs;
|
|
646
|
+
return (this.events.get(codeName) ?? []).filter((e) => e.at >= cutoff).length;
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
function formatStatusMessage(events, windowMs) {
|
|
650
|
+
const last = events[events.length - 1];
|
|
651
|
+
const windowLabel = windowMs < 6e4 ? `${Math.round(windowMs / 1e3)}s` : `${(windowMs / 6e4).toFixed(1).replace(/\.0$/, "")}min`;
|
|
652
|
+
const reasonCounts = /* @__PURE__ */ new Map();
|
|
653
|
+
for (const e of events) reasonCounts.set(e.reason, (reasonCounts.get(e.reason) ?? 0) + 1);
|
|
654
|
+
const breakdown = Array.from(reasonCounts.entries()).map(([r, n]) => `${r}=${n}`).join(", ");
|
|
655
|
+
return `Circuit breaker tripped: ${events.length} restarts in ${windowLabel} (${breakdown}); most recent=${last.reason} at ${new Date(last.at).toISOString()}`;
|
|
656
|
+
}
|
|
657
|
+
|
|
555
658
|
// src/lib/usage-banner-monitor.ts
|
|
556
659
|
var MIN_CHECK_INTERVAL_MS = 6e4;
|
|
557
660
|
var PANE_TAIL_LINES_FOR_BANNER = 200;
|
|
@@ -2286,7 +2389,38 @@ var knownVersions = /* @__PURE__ */ new Map();
|
|
|
2286
2389
|
var knownStatuses = /* @__PURE__ */ new Map();
|
|
2287
2390
|
var knownChannels = /* @__PURE__ */ new Map();
|
|
2288
2391
|
var pendingSessionRestarts = /* @__PURE__ */ new Map();
|
|
2289
|
-
|
|
2392
|
+
var restartBreaker = new RestartBreaker();
|
|
2393
|
+
var reportedTrips = /* @__PURE__ */ new Map();
|
|
2394
|
+
function recordRestartForBreaker(codeName, reason) {
|
|
2395
|
+
const result = restartBreaker.record(codeName, reason);
|
|
2396
|
+
if (!result.tripped || !result.trip) return;
|
|
2397
|
+
const trip = result.trip;
|
|
2398
|
+
log(
|
|
2399
|
+
`[persistent-session-decision] agent=${codeName} decision=circuit-tripped detail=${JSON.stringify(trip.statusMessage)} (ENG-5441)`
|
|
2400
|
+
);
|
|
2401
|
+
maybeReportCurrentTrip(codeName);
|
|
2402
|
+
}
|
|
2403
|
+
async function reportCircuitTripped(codeName, trip) {
|
|
2404
|
+
if (reportedTrips.get(codeName) === trip.trippedAt) return;
|
|
2405
|
+
const agentId = codeNameToAgentId.get(codeName);
|
|
2406
|
+
if (!agentId) throw new Error(`no agent_id known yet for '${codeName}' \u2014 will retry next poll`);
|
|
2407
|
+
await api.post("/host/circuit-breaker/trip", {
|
|
2408
|
+
agent_id: agentId,
|
|
2409
|
+
status_message: trip.statusMessage,
|
|
2410
|
+
tripped_at: new Date(trip.trippedAt).toISOString(),
|
|
2411
|
+
events: trip.eventsAtTrip.map((e) => ({ reason: e.reason, at: new Date(e.at).toISOString() }))
|
|
2412
|
+
});
|
|
2413
|
+
reportedTrips.set(codeName, trip.trippedAt);
|
|
2414
|
+
}
|
|
2415
|
+
function maybeReportCurrentTrip(codeName) {
|
|
2416
|
+
const trip = restartBreaker.getTrip(codeName);
|
|
2417
|
+
if (!trip) return;
|
|
2418
|
+
if (reportedTrips.get(codeName) === trip.trippedAt) return;
|
|
2419
|
+
reportCircuitTripped(codeName, trip).catch((err) => {
|
|
2420
|
+
log(`[circuit-breaker] Failed to report trip for '${codeName}' to API: ${err.message}`);
|
|
2421
|
+
});
|
|
2422
|
+
}
|
|
2423
|
+
function scheduleSessionRestart(codeName, delayMs, reason, breakerReason = "hot-reload-mcp") {
|
|
2290
2424
|
const existing = pendingSessionRestarts.get(codeName);
|
|
2291
2425
|
if (existing) {
|
|
2292
2426
|
clearTimeout(existing);
|
|
@@ -2296,6 +2430,7 @@ function scheduleSessionRestart(codeName, delayMs, reason) {
|
|
|
2296
2430
|
pendingSessionRestarts.delete(codeName);
|
|
2297
2431
|
stopPersistentSession(codeName, log);
|
|
2298
2432
|
runningMcpHashes.delete(codeName);
|
|
2433
|
+
recordRestartForBreaker(codeName, breakerReason);
|
|
2299
2434
|
log(`[hot-reload] Session stopped for '${codeName}' \u2014 will respawn with ${reason}`);
|
|
2300
2435
|
}, delayMs);
|
|
2301
2436
|
timer.unref?.();
|
|
@@ -2331,11 +2466,14 @@ function projectMcpKeys(_codeName, projectDir) {
|
|
|
2331
2466
|
return null;
|
|
2332
2467
|
}
|
|
2333
2468
|
}
|
|
2334
|
-
function stopPersistentSessionAndForgetMcpBaseline(codeName) {
|
|
2469
|
+
function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason) {
|
|
2335
2470
|
cancelPendingSessionRestart(codeName);
|
|
2336
2471
|
stopPersistentSession(codeName, log);
|
|
2337
2472
|
runningMcpHashes.delete(codeName);
|
|
2338
2473
|
runningMcpServerKeys.delete(codeName);
|
|
2474
|
+
if (breakerReason) {
|
|
2475
|
+
recordRestartForBreaker(codeName, breakerReason);
|
|
2476
|
+
}
|
|
2339
2477
|
}
|
|
2340
2478
|
function checkMcpConfigDriftAndScheduleRestart(codeName, projectDir) {
|
|
2341
2479
|
const currentHash = projectMcpHash(codeName, projectDir);
|
|
@@ -2472,7 +2610,7 @@ var cachedFrameworkVersion = null;
|
|
|
2472
2610
|
var lastVersionCheckAt = 0;
|
|
2473
2611
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
2474
2612
|
var lastResponsivenessProbeAt = 0;
|
|
2475
|
-
var agtCliVersion = true ? "0.23.
|
|
2613
|
+
var agtCliVersion = true ? "0.23.2" : "dev";
|
|
2476
2614
|
function resolveBrewPath(execFileSync4) {
|
|
2477
2615
|
try {
|
|
2478
2616
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -3368,7 +3506,7 @@ async function pollCycle() {
|
|
|
3368
3506
|
log,
|
|
3369
3507
|
resolveFramework: (codeName) => agentFrameworkCache.get(codeName) ?? null,
|
|
3370
3508
|
stopSession: (codeName) => {
|
|
3371
|
-
stopPersistentSessionAndForgetMcpBaseline(codeName);
|
|
3509
|
+
stopPersistentSessionAndForgetMcpBaseline(codeName, "channel-set-change");
|
|
3372
3510
|
persistentSessionAgents.delete(codeName);
|
|
3373
3511
|
claudeAuthTupleBySession.delete(codeName);
|
|
3374
3512
|
},
|
|
@@ -3429,7 +3567,7 @@ async function pollCycle() {
|
|
|
3429
3567
|
}
|
|
3430
3568
|
try {
|
|
3431
3569
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
3432
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
3570
|
+
const { collectDiagnostics } = await import("../persistent-session-L4YIJJML.js");
|
|
3433
3571
|
const diagCodeNames = [...persistentSessionAgents];
|
|
3434
3572
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
3435
3573
|
let tailscaleHostname;
|
|
@@ -3480,7 +3618,7 @@ async function pollCycle() {
|
|
|
3480
3618
|
const {
|
|
3481
3619
|
collectResponsivenessProbes,
|
|
3482
3620
|
getResponsivenessIntervalMs
|
|
3483
|
-
} = await import("../responsiveness-probe-
|
|
3621
|
+
} = await import("../responsiveness-probe-YRLESO54.js");
|
|
3484
3622
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
3485
3623
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
3486
3624
|
const probeCodeNames = [...persistentSessionAgents];
|
|
@@ -3678,7 +3816,11 @@ async function pollCycle() {
|
|
|
3678
3816
|
...state2,
|
|
3679
3817
|
lastPollAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3680
3818
|
pollCount: state2.pollCount + 1,
|
|
3681
|
-
agents: agentStates
|
|
3819
|
+
agents: agentStates,
|
|
3820
|
+
// ENG-5441: serialise trip state on every poll so manager restarts
|
|
3821
|
+
// never silently clear a tripped breaker. Cheap — only tripped
|
|
3822
|
+
// entries are stored, and the typical state is zero entries.
|
|
3823
|
+
circuitBreakerTrips: restartBreaker.serialize()
|
|
3682
3824
|
};
|
|
3683
3825
|
if (consecutivePollFailures > 0) {
|
|
3684
3826
|
log(`[poll-backoff] recovered after ${consecutivePollFailures} failure(s), resuming normal interval`);
|
|
@@ -3713,6 +3855,7 @@ async function processAgent(agent, agentStates) {
|
|
|
3713
3855
|
const previousKnownStatus = knownStatuses.get(agent.agent_id);
|
|
3714
3856
|
agentDisplayNames.set(agent.code_name, agent.display_name);
|
|
3715
3857
|
codeNameToAgentId.set(agent.code_name, agent.agent_id);
|
|
3858
|
+
maybeReportCurrentTrip(agent.code_name);
|
|
3716
3859
|
if (agent.framework) {
|
|
3717
3860
|
agentFrameworkCache.set(agent.code_name, agent.framework);
|
|
3718
3861
|
}
|
|
@@ -3825,6 +3968,11 @@ async function processAgent(agent, agentStates) {
|
|
|
3825
3968
|
if (previousStatus && previousStatus !== agent.status) {
|
|
3826
3969
|
log(`Agent '${agent.code_name}' status changed: ${previousStatus} \u2192 ${agent.status}`);
|
|
3827
3970
|
knownVersions.delete(agent.agent_id);
|
|
3971
|
+
if (previousStatus === "paused" && agent.status === "active" && restartBreaker.isTripped(agent.code_name)) {
|
|
3972
|
+
restartBreaker.clear(agent.code_name);
|
|
3973
|
+
reportedTrips.delete(agent.code_name);
|
|
3974
|
+
log(`[circuit-breaker] Cleared trip for '${agent.code_name}' on operator resume (paused \u2192 active)`);
|
|
3975
|
+
}
|
|
3828
3976
|
let channelCacheMutated = false;
|
|
3829
3977
|
for (const key of knownChannelConfigHashes.keys()) {
|
|
3830
3978
|
if (key.startsWith(`${agent.agent_id}:`)) {
|
|
@@ -4756,7 +4904,12 @@ async function processAgent(agent, agentStates) {
|
|
|
4756
4904
|
codeName: agent.code_name,
|
|
4757
4905
|
mcpJson: mcpJsonParsed,
|
|
4758
4906
|
sessionStartedAt: sess?.startedAt ?? null,
|
|
4759
|
-
|
|
4907
|
+
// ENG-5441: mcp-presence-reaper-driven restart counts against
|
|
4908
|
+
// the breaker. Each declared MCP has its own ENG-5279 give-up
|
|
4909
|
+
// cap (~3 cycles per server), but a thrashing collection of
|
|
4910
|
+
// MCPs can still rotate restarts of the whole session. The
|
|
4911
|
+
// breaker catches the rotating case the per-MCP cap can't see.
|
|
4912
|
+
stopSession: (codeName) => stopPersistentSessionAndForgetMcpBaseline(codeName, "mcp-presence-reaper"),
|
|
4760
4913
|
// ENG-5292: when the reaper gives up on a managed MCP (cap from
|
|
4761
4914
|
// ENG-5279 + state-preservation from ENG-5285 both said "this
|
|
4762
4915
|
// MCP keeps failing after 3 restart cycles"), mark the matching
|
|
@@ -5545,6 +5698,15 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
5545
5698
|
const projectDir = getProjectDir(codeName);
|
|
5546
5699
|
const mcpConfigPath = join4(projectDir, ".mcp.json");
|
|
5547
5700
|
const claudeMdPath = join4(projectDir, "CLAUDE.md");
|
|
5701
|
+
if (restartBreaker.isTripped(codeName)) {
|
|
5702
|
+
const trip = restartBreaker.getTrip(codeName);
|
|
5703
|
+
return {
|
|
5704
|
+
decision: "circuit-tripped",
|
|
5705
|
+
spawnAttempted: false,
|
|
5706
|
+
sessionHealthyAfter: isSessionHealthy(codeName),
|
|
5707
|
+
detail: trip.statusMessage
|
|
5708
|
+
};
|
|
5709
|
+
}
|
|
5548
5710
|
const teamSettingsForTz = refreshData.team?.settings;
|
|
5549
5711
|
const agentTimezone = (() => {
|
|
5550
5712
|
const tz = teamSettingsForTz?.["timezone"];
|
|
@@ -5627,7 +5789,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
5627
5789
|
const recordedAuthTuple = claudeAuthTupleBySession.get(codeName);
|
|
5628
5790
|
if (recordedAuthTuple && recordedAuthTuple !== currentAuthTuple && isSessionHealthy(codeName)) {
|
|
5629
5791
|
log(`[persistent-session] Auth config changed for '${codeName}' (${recordedAuthTuple} \u2192 ${currentAuthTuple}) \u2014 restarting session`);
|
|
5630
|
-
stopPersistentSessionAndForgetMcpBaseline(codeName);
|
|
5792
|
+
stopPersistentSessionAndForgetMcpBaseline(codeName, "auth-tuple-change");
|
|
5631
5793
|
persistentSessionAgents.delete(codeName);
|
|
5632
5794
|
restartTrigger = "auth-tuple";
|
|
5633
5795
|
}
|
|
@@ -5639,7 +5801,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
5639
5801
|
log(
|
|
5640
5802
|
`[persistent-session] Day rollover for '${codeName}' (yesterday=${current.date}) \u2014 agent idle, restarting to mint fresh session`
|
|
5641
5803
|
);
|
|
5642
|
-
stopPersistentSessionAndForgetMcpBaseline(codeName);
|
|
5804
|
+
stopPersistentSessionAndForgetMcpBaseline(codeName, "day-rollover");
|
|
5643
5805
|
persistentSessionAgents.delete(codeName);
|
|
5644
5806
|
restartTrigger = "day-rollover";
|
|
5645
5807
|
} else {
|
|
@@ -5650,6 +5812,15 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
5650
5812
|
}
|
|
5651
5813
|
}
|
|
5652
5814
|
}
|
|
5815
|
+
if (restartBreaker.isTripped(codeName)) {
|
|
5816
|
+
const trip = restartBreaker.getTrip(codeName);
|
|
5817
|
+
return {
|
|
5818
|
+
decision: "circuit-tripped",
|
|
5819
|
+
spawnAttempted: false,
|
|
5820
|
+
sessionHealthyAfter: isSessionHealthy(codeName),
|
|
5821
|
+
detail: trip.statusMessage
|
|
5822
|
+
};
|
|
5823
|
+
}
|
|
5653
5824
|
if (!isSessionHealthy(codeName)) {
|
|
5654
5825
|
if (persistentSessionAgents.has(codeName)) {
|
|
5655
5826
|
const ctx = getLastFailureContext(codeName);
|
|
@@ -7136,7 +7307,7 @@ async function processClaudePairSessions(agents) {
|
|
|
7136
7307
|
killPairSession,
|
|
7137
7308
|
pairTmuxSession,
|
|
7138
7309
|
finalizeClaudePairOnboarding
|
|
7139
|
-
} = await import("../claude-pair-runtime-
|
|
7310
|
+
} = await import("../claude-pair-runtime-XCFWTH6T.js");
|
|
7140
7311
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
7141
7312
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
7142
7313
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -7357,6 +7528,14 @@ function generateArtifacts(agent, refreshData, adapter) {
|
|
|
7357
7528
|
};
|
|
7358
7529
|
}
|
|
7359
7530
|
}
|
|
7531
|
+
const activeTasksInjectEnabled = process.env["AGT_ACTIVE_TASKS_INJECT"] === "1";
|
|
7532
|
+
const activeTasksFromRefresh = activeTasksInjectEnabled ? refreshData.active_tasks ?? [] : void 0;
|
|
7533
|
+
if (activeTasksInjectEnabled) {
|
|
7534
|
+
const tokens = estimateActiveTasksTokens(activeTasksFromRefresh);
|
|
7535
|
+
log(
|
|
7536
|
+
`[provision/active-tasks] agent=${agent.code_name} count=${activeTasksFromRefresh?.length ?? 0} estimated_tokens=${tokens}`
|
|
7537
|
+
);
|
|
7538
|
+
}
|
|
7360
7539
|
const provisionInput = {
|
|
7361
7540
|
agent: refreshData.agent,
|
|
7362
7541
|
charterFrontmatter,
|
|
@@ -7367,6 +7546,7 @@ function generateArtifacts(agent, refreshData, adapter) {
|
|
|
7367
7546
|
deploymentTarget: "local_docker",
|
|
7368
7547
|
gatewayPort: 9e3,
|
|
7369
7548
|
team: refreshData.team ?? void 0,
|
|
7549
|
+
activeTasks: activeTasksFromRefresh,
|
|
7370
7550
|
// ENG-5009: org name for the identity-preamble. Only present when
|
|
7371
7551
|
// /host/refresh ships the field — falls through cleanly for older
|
|
7372
7552
|
// API payloads that don't carry it.
|
|
@@ -7715,6 +7895,11 @@ function startManager(opts) {
|
|
|
7715
7895
|
state2.agents = parsed.agents;
|
|
7716
7896
|
log(`[startup] rehydrated ${state2.agents.length} agent state(s) from ${stateFile}`);
|
|
7717
7897
|
}
|
|
7898
|
+
if (parsed.circuitBreakerTrips && typeof parsed.circuitBreakerTrips === "object") {
|
|
7899
|
+
restartBreaker.hydrate(parsed.circuitBreakerTrips);
|
|
7900
|
+
const n = Object.keys(parsed.circuitBreakerTrips).length;
|
|
7901
|
+
if (n > 0) log(`[startup] rehydrated ${n} circuit-breaker trip(s) \u2014 agents will remain paused until manually resumed`);
|
|
7902
|
+
}
|
|
7718
7903
|
}
|
|
7719
7904
|
} catch (err) {
|
|
7720
7905
|
log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
|