@integrity-labs/agt-cli 0.28.280 → 0.28.282
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-JGM444JK.js → chunk-6SRVCYKR.js} +3 -3
- package/dist/{chunk-7USLYY43.js → chunk-C4QMCOAN.js} +1 -1
- package/dist/chunk-C4QMCOAN.js.map +1 -0
- package/dist/{claude-pair-runtime-EXW6NBLU.js → claude-pair-runtime-JOYTDNXZ.js} +2 -2
- package/dist/lib/manager-worker.js +107 -21
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-SZ4TUGED.js → persistent-session-7H3IYXXP.js} +2 -2
- package/dist/{responsiveness-probe-MKFZAUV5.js → responsiveness-probe-PFJM4QMQ.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-7USLYY43.js.map +0 -1
- /package/dist/{chunk-JGM444JK.js.map → chunk-6SRVCYKR.js.map} +0 -0
- /package/dist/{claude-pair-runtime-EXW6NBLU.js.map → claude-pair-runtime-JOYTDNXZ.js.map} +0 -0
- /package/dist/{persistent-session-SZ4TUGED.js.map → persistent-session-7H3IYXXP.js.map} +0 -0
- /package/dist/{responsiveness-probe-MKFZAUV5.js.map → responsiveness-probe-PFJM4QMQ.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-7H3IYXXP.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-JOYTDNXZ.js.map
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
requireHost,
|
|
39
39
|
safeWriteJsonAtomic,
|
|
40
40
|
setConfigHash
|
|
41
|
-
} from "../chunk-
|
|
41
|
+
} from "../chunk-6SRVCYKR.js";
|
|
42
42
|
import {
|
|
43
43
|
getProjectDir as getProjectDir2,
|
|
44
44
|
getReadyTasks,
|
|
@@ -125,7 +125,7 @@ import {
|
|
|
125
125
|
takeZombieDetection,
|
|
126
126
|
transcriptActivityAgeSeconds,
|
|
127
127
|
writeEgressAllowlist
|
|
128
|
-
} from "../chunk-
|
|
128
|
+
} from "../chunk-C4QMCOAN.js";
|
|
129
129
|
import {
|
|
130
130
|
reapOrphanChannelMcps
|
|
131
131
|
} from "../chunk-XWVM4KPK.js";
|
|
@@ -186,6 +186,29 @@ function managedMcpStructureHash(entries) {
|
|
|
186
186
|
const basis = entries.slice().sort((a, b) => a.serverId.localeCompare(b.serverId)).map((e) => `${e.serverId}|${Object.keys(e.headers ?? {}).sort().join(",")}`).join("\n");
|
|
187
187
|
return createHash("sha256").update(basis).digest("hex").slice(0, 16);
|
|
188
188
|
}
|
|
189
|
+
function managedMcpStructureHashFromFile(mcpConfig, isManagedKey) {
|
|
190
|
+
if (!mcpConfig || typeof mcpConfig !== "object") return null;
|
|
191
|
+
const servers = mcpConfig.mcpServers;
|
|
192
|
+
if (!servers || typeof servers !== "object") return managedMcpStructureHash([]);
|
|
193
|
+
const entries = [];
|
|
194
|
+
for (const [key, value] of Object.entries(servers)) {
|
|
195
|
+
if (!isManagedKey(key)) continue;
|
|
196
|
+
const headers = value && typeof value === "object" && value.headers && typeof value.headers === "object" ? value.headers : void 0;
|
|
197
|
+
entries.push({ serverId: key, headers });
|
|
198
|
+
}
|
|
199
|
+
return managedMcpStructureHash(entries);
|
|
200
|
+
}
|
|
201
|
+
function decideManagedMcpRestart(input) {
|
|
202
|
+
const { prevStructureHash, structureHash, launchStructureHash, sessionHealthy, flapping } = input;
|
|
203
|
+
if (prevStructureHash === void 0) return { kind: "skip-first-convergence" };
|
|
204
|
+
if (structureHash === prevStructureHash) return { kind: "skip-no-change" };
|
|
205
|
+
if (!sessionHealthy) return { kind: "skip-unhealthy" };
|
|
206
|
+
if (flapping) return { kind: "skip-flapping" };
|
|
207
|
+
if (launchStructureHash != null && launchStructureHash === structureHash) {
|
|
208
|
+
return { kind: "suppress-already-live" };
|
|
209
|
+
}
|
|
210
|
+
return { kind: "restart" };
|
|
211
|
+
}
|
|
189
212
|
function channelSecretValueHash(envEntries, channelSecretKeys) {
|
|
190
213
|
if (!envEntries) return null;
|
|
191
214
|
const basis = channelSecretKeys.slice().sort().filter((k) => Object.prototype.hasOwnProperty.call(envEntries, k)).map((k) => `${k}=${envEntries[k]}`).join("\n");
|
|
@@ -626,7 +649,10 @@ function reaperRestartBreakerReason(activeKeys) {
|
|
|
626
649
|
var PROVISIONING_RELOAD_REASONS = /* @__PURE__ */ new Set([
|
|
627
650
|
"hot-reload-mcp",
|
|
628
651
|
"managed-mcp-churn",
|
|
629
|
-
"bind-remediation"
|
|
652
|
+
"bind-remediation",
|
|
653
|
+
// ENG-7576: the dashboard integration-add stop itself - the first restart of
|
|
654
|
+
// the very burst this class exists for, previously uncounted entirely.
|
|
655
|
+
"integration-change"
|
|
630
656
|
]);
|
|
631
657
|
function isProvisioningReloadReason(reason) {
|
|
632
658
|
return PROVISIONING_RELOAD_REASONS.has(reason);
|
|
@@ -6286,7 +6312,15 @@ async function maybeResumeReconcile(agent) {
|
|
|
6286
6312
|
}
|
|
6287
6313
|
}
|
|
6288
6314
|
function restartReasonBindsNewMcp(breakerReason) {
|
|
6289
|
-
return breakerReason === "hot-reload-mcp" || breakerReason === "managed-mcp-churn" || breakerReason === "bind-remediation" || breakerReason === "channel-set-change"
|
|
6315
|
+
return breakerReason === "hot-reload-mcp" || breakerReason === "managed-mcp-churn" || breakerReason === "bind-remediation" || breakerReason === "channel-set-change" || // ENG-7576: the dashboard integration-add stop (the poll's restart-consumption
|
|
6316
|
+
// loop) is the archetypal "stop to rebind a changed MCP set" - the docstring
|
|
6317
|
+
// above always described it, but the path passed no breakerReason so it never
|
|
6318
|
+
// hit this predicate. Including it arms the ENG-6174 respawn verification for
|
|
6319
|
+
// the ONE real respawn of an integration add.
|
|
6320
|
+
breakerReason === "integration-change";
|
|
6321
|
+
}
|
|
6322
|
+
function dashboardRestartBreakerReason(restartReason) {
|
|
6323
|
+
return restartReason === "integration-change" ? "integration-change" : void 0;
|
|
6290
6324
|
}
|
|
6291
6325
|
function scheduleSessionRestart(codeName, delayMs, reason, breakerReason = "hot-reload-mcp", beforeStop) {
|
|
6292
6326
|
const existing = pendingSessionRestarts.get(codeName);
|
|
@@ -6332,6 +6366,7 @@ function scheduleSessionRestart(codeName, delayMs, reason, breakerReason = "hot-
|
|
|
6332
6366
|
stopPersistentSession(codeName, log);
|
|
6333
6367
|
markRestartStopped(codeName, log);
|
|
6334
6368
|
runningMcpHashes.delete(codeName);
|
|
6369
|
+
sessionLaunchManagedStructure.delete(codeName);
|
|
6335
6370
|
recordRestartForBreaker(codeName, breakerReason);
|
|
6336
6371
|
log(`[hot-reload] Session stopped for '${codeName}' \u2014 will respawn with ${reason}`);
|
|
6337
6372
|
const bindsNewMcp = restartReasonBindsNewMcp(breakerReason);
|
|
@@ -6510,6 +6545,7 @@ function isHostBusyForForcedUpdate() {
|
|
|
6510
6545
|
var runningMcpHashes = /* @__PURE__ */ new Map();
|
|
6511
6546
|
var runningMcpServerKeys = /* @__PURE__ */ new Map();
|
|
6512
6547
|
var runningChannelSecretHashes = /* @__PURE__ */ new Map();
|
|
6548
|
+
var sessionLaunchManagedStructure = /* @__PURE__ */ new Map();
|
|
6513
6549
|
function projectMcpHash(_codeName, projectDir) {
|
|
6514
6550
|
try {
|
|
6515
6551
|
const raw = readFileSync15(join17(projectDir, ".mcp.json"), "utf-8");
|
|
@@ -6529,6 +6565,28 @@ function projectMcpKeys(_codeName, projectDir) {
|
|
|
6529
6565
|
return null;
|
|
6530
6566
|
}
|
|
6531
6567
|
}
|
|
6568
|
+
function seedSessionLaunchBaselines(codeName, projectDir) {
|
|
6569
|
+
const hash = projectMcpHash(codeName, projectDir);
|
|
6570
|
+
const keys = projectMcpKeys(codeName, projectDir);
|
|
6571
|
+
if (hash) runningMcpHashes.set(codeName, hash);
|
|
6572
|
+
else runningMcpHashes.delete(codeName);
|
|
6573
|
+
if (keys) runningMcpServerKeys.set(codeName, keys);
|
|
6574
|
+
else runningMcpServerKeys.delete(codeName);
|
|
6575
|
+
let launchStructure = null;
|
|
6576
|
+
try {
|
|
6577
|
+
const raw = readFileSync15(join17(projectDir, ".mcp.json"), "utf-8");
|
|
6578
|
+
launchStructure = managedMcpStructureHashFromFile(
|
|
6579
|
+
JSON.parse(raw),
|
|
6580
|
+
isManagedMcpServerKey
|
|
6581
|
+
);
|
|
6582
|
+
} catch {
|
|
6583
|
+
}
|
|
6584
|
+
if (launchStructure !== null) {
|
|
6585
|
+
sessionLaunchManagedStructure.set(codeName, launchStructure);
|
|
6586
|
+
} else {
|
|
6587
|
+
sessionLaunchManagedStructure.delete(codeName);
|
|
6588
|
+
}
|
|
6589
|
+
}
|
|
6532
6590
|
async function runAgentConnectivityProbes(agent, integrations, projectDir) {
|
|
6533
6591
|
if (integrations.length === 0) return;
|
|
6534
6592
|
const probeEnv = buildProbeEnv(projectDir);
|
|
@@ -6654,12 +6712,13 @@ function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason, gate
|
|
|
6654
6712
|
runningMcpHashes.delete(codeName);
|
|
6655
6713
|
runningMcpServerKeys.delete(codeName);
|
|
6656
6714
|
runningChannelSecretHashes.delete(codeName);
|
|
6715
|
+
sessionLaunchManagedStructure.delete(codeName);
|
|
6657
6716
|
closeInjectedRunIfOpen(codeName, "cancelled", `session stopped (${breakerReason ?? "deprovision"})`);
|
|
6658
6717
|
closeScheduledRunsForCode(codeName, "cancelled", `session stopped (${breakerReason ?? "deprovision"})`);
|
|
6659
6718
|
if (breakerReason) {
|
|
6660
6719
|
recordRestartForBreaker(codeName, breakerReason);
|
|
6661
6720
|
}
|
|
6662
|
-
if (breakerReason && breakerReason !== "agent-requested" && breakerReason !== "channel-restart-flag") {
|
|
6721
|
+
if (breakerReason && breakerReason !== "agent-requested" && breakerReason !== "channel-restart-flag" && breakerReason !== "integration-change") {
|
|
6663
6722
|
const restartAgentId = agentState.codeNameToAgentId.get(codeName);
|
|
6664
6723
|
if (restartAgentId) {
|
|
6665
6724
|
void api.post("/host/restart-event", {
|
|
@@ -6827,7 +6886,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
6827
6886
|
var lastVersionCheckAt = 0;
|
|
6828
6887
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
6829
6888
|
var lastResponsivenessProbeAt = 0;
|
|
6830
|
-
var agtCliVersion = true ? "0.28.
|
|
6889
|
+
var agtCliVersion = true ? "0.28.282" : "dev";
|
|
6831
6890
|
function resolveBrewPath(execFileSync2) {
|
|
6832
6891
|
try {
|
|
6833
6892
|
const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -7677,7 +7736,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
|
|
|
7677
7736
|
if (codeNames.length === 0) return;
|
|
7678
7737
|
void (async () => {
|
|
7679
7738
|
try {
|
|
7680
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
7739
|
+
const { collectDiagnostics } = await import("../persistent-session-7H3IYXXP.js");
|
|
7681
7740
|
await api.post("/host/heartbeat", {
|
|
7682
7741
|
host_id: hostId,
|
|
7683
7742
|
agent_diagnostics: collectDiagnostics(codeNames)
|
|
@@ -7775,7 +7834,7 @@ async function pollCycle() {
|
|
|
7775
7834
|
}
|
|
7776
7835
|
try {
|
|
7777
7836
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
7778
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
7837
|
+
const { collectDiagnostics } = await import("../persistent-session-7H3IYXXP.js");
|
|
7779
7838
|
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
7780
7839
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
7781
7840
|
let tailscaleHostname;
|
|
@@ -7923,7 +7982,7 @@ async function pollCycle() {
|
|
|
7923
7982
|
const {
|
|
7924
7983
|
collectResponsivenessProbes,
|
|
7925
7984
|
getResponsivenessIntervalMs
|
|
7926
|
-
} = await import("../responsiveness-probe-
|
|
7985
|
+
} = await import("../responsiveness-probe-PFJM4QMQ.js");
|
|
7927
7986
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
7928
7987
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
7929
7988
|
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
@@ -7955,7 +8014,7 @@ async function pollCycle() {
|
|
|
7955
8014
|
collectResponsivenessProbes,
|
|
7956
8015
|
livePendingInboundOldestAgeSeconds,
|
|
7957
8016
|
parkPendingInbound
|
|
7958
|
-
} = await import("../responsiveness-probe-
|
|
8017
|
+
} = await import("../responsiveness-probe-PFJM4QMQ.js");
|
|
7959
8018
|
const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
|
|
7960
8019
|
const wedgeNow = /* @__PURE__ */ new Date();
|
|
7961
8020
|
const liveAgents = agentState.persistentSessionAgents;
|
|
@@ -8174,13 +8233,31 @@ async function pollCycle() {
|
|
|
8174
8233
|
const lastProcessed = prev?.lastRestartProcessedAt ?? null;
|
|
8175
8234
|
const alreadyServiced = lastProcessed != null && Date.parse(lastProcessed) >= Date.parse(requested);
|
|
8176
8235
|
if (!alreadyServiced) {
|
|
8177
|
-
|
|
8236
|
+
const restartReason = agent.restart_reason ?? null;
|
|
8237
|
+
log(
|
|
8238
|
+
`[restart] Dashboard requested restart for '${agent.code_name}' at ${requested} (reason=${restartReason ?? "manual"})`
|
|
8239
|
+
);
|
|
8178
8240
|
try {
|
|
8179
8241
|
const { execSync: es } = await import("child_process");
|
|
8180
8242
|
es(`tmux kill-session -t agt-${agent.code_name} 2>/dev/null`, { stdio: "ignore" });
|
|
8181
8243
|
} catch {
|
|
8182
8244
|
}
|
|
8183
|
-
|
|
8245
|
+
const breakerReason = dashboardRestartBreakerReason(restartReason);
|
|
8246
|
+
stopPersistentSessionAndForgetMcpBaseline(agent.code_name, breakerReason);
|
|
8247
|
+
if (breakerReason && restartReasonBindsNewMcp(breakerReason)) {
|
|
8248
|
+
noteRestartRequested(agent.code_name, requested);
|
|
8249
|
+
beginRestartTiming(
|
|
8250
|
+
agent.code_name,
|
|
8251
|
+
{ reason: "integration-change (dashboard restart)", delivered: null, injectDelayMs: null },
|
|
8252
|
+
log
|
|
8253
|
+
);
|
|
8254
|
+
markRestartStopped(agent.code_name, log);
|
|
8255
|
+
const prior = pendingRestartVerifications.get(agent.code_name);
|
|
8256
|
+
pendingRestartVerifications.set(agent.code_name, {
|
|
8257
|
+
firedAt: Date.now(),
|
|
8258
|
+
attempts: prior?.attempts ?? 0
|
|
8259
|
+
});
|
|
8260
|
+
}
|
|
8184
8261
|
restartAcks.set(agent.agent_id, requested);
|
|
8185
8262
|
}
|
|
8186
8263
|
restartClears.push({ agentId: agent.agent_id, requestedAt: requested });
|
|
@@ -9579,12 +9656,19 @@ async function processAgent(agent, agentStates) {
|
|
|
9579
9656
|
}
|
|
9580
9657
|
agentState.knownManagedMcpHashes.set(agent.agent_id, mcpHash);
|
|
9581
9658
|
agentState.knownManagedMcpStructure.set(agent.agent_id, structureHash);
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
9659
|
+
const mcpRestartDecision = fwForMcp === "claude-code" && prevStructureHash !== void 0 && structureHash !== prevStructureHash ? decideManagedMcpRestart({
|
|
9660
|
+
prevStructureHash,
|
|
9661
|
+
structureHash,
|
|
9662
|
+
launchStructureHash: sessionLaunchManagedStructure.get(agent.code_name),
|
|
9663
|
+
sessionHealthy: isSessionHealthy(agent.code_name),
|
|
9664
|
+
flapping: mcpFlap.flapping
|
|
9665
|
+
}) : null;
|
|
9666
|
+
if (mcpRestartDecision?.kind === "suppress-already-live") {
|
|
9667
|
+
log(
|
|
9668
|
+
`[hot-reload] Restart suppressed for '${agent.code_name}': the managed MCP structure change is already live in the running session (launched with it) - no respawn needed (ENG-7576)`
|
|
9669
|
+
);
|
|
9670
|
+
}
|
|
9671
|
+
if (mcpRestartDecision?.kind === "restart") {
|
|
9588
9672
|
const mcpNames = agentToolkits.map((tk) => tk.toolkit_name).join(", ") || "none (all removed)";
|
|
9589
9673
|
log(`[hot-reload] MCP servers changed for '${agent.code_name}': ${mcpNames} \u2014 restarting session`);
|
|
9590
9674
|
const restartNotice = agentToolkits.length > 0 ? `New MCP tool servers have been configured: ${mcpNames}. Note: MCP servers require a session restart to connect. Your manager will restart your session shortly.` : "Managed MCP tool servers were removed. Your manager will restart your session shortly so the session drops those tools.";
|
|
@@ -10590,6 +10674,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash11("sha256")
|
|
|
10590
10674
|
});
|
|
10591
10675
|
agentState.persistentSessionAgents.add(codeName);
|
|
10592
10676
|
claudeAuthTupleBySession.set(codeName, currentAuthTuple);
|
|
10677
|
+
seedSessionLaunchBaselines(codeName, projectDir);
|
|
10593
10678
|
return {
|
|
10594
10679
|
decision: "spawn",
|
|
10595
10680
|
spawnAttempted: true,
|
|
@@ -10845,7 +10930,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
|
|
|
10845
10930
|
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}`));
|
|
10846
10931
|
void (async () => {
|
|
10847
10932
|
try {
|
|
10848
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
10933
|
+
const { collectDiagnostics } = await import("../persistent-session-7H3IYXXP.js");
|
|
10849
10934
|
await api.post("/host/heartbeat", {
|
|
10850
10935
|
host_id: hostId,
|
|
10851
10936
|
agent_diagnostics: collectDiagnostics([codeName])
|
|
@@ -10895,7 +10980,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
|
|
|
10895
10980
|
}
|
|
10896
10981
|
try {
|
|
10897
10982
|
const hostId = await getHostId();
|
|
10898
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
10983
|
+
const { collectDiagnostics } = await import("../persistent-session-7H3IYXXP.js");
|
|
10899
10984
|
await api.post("/host/heartbeat", {
|
|
10900
10985
|
host_id: hostId,
|
|
10901
10986
|
agent_diagnostics: collectDiagnostics([codeName])
|
|
@@ -11299,7 +11384,7 @@ async function processClaudePairSessions(agents) {
|
|
|
11299
11384
|
killPairSession,
|
|
11300
11385
|
pairTmuxSession,
|
|
11301
11386
|
finalizeClaudePairOnboarding
|
|
11302
|
-
} = await import("../claude-pair-runtime-
|
|
11387
|
+
} = await import("../claude-pair-runtime-JOYTDNXZ.js");
|
|
11303
11388
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
11304
11389
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
11305
11390
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -12200,6 +12285,7 @@ export {
|
|
|
12200
12285
|
claudeCodeUpgradeMarkerPath,
|
|
12201
12286
|
claudeCodeUpgradeThrottled,
|
|
12202
12287
|
claudeManagedSettingsPath,
|
|
12288
|
+
dashboardRestartBreakerReason,
|
|
12203
12289
|
ensureClaudeManagedSettings,
|
|
12204
12290
|
extractCharterSlackPeers,
|
|
12205
12291
|
extractCharterTelegramPeers,
|