@integrity-labs/agt-cli 0.26.1 → 0.26.2-eng5706.1
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/bin/agt.js.map +1 -1
- package/dist/{chunk-UTPOHAX7.js → chunk-LBYU24PW.js} +97 -5
- package/dist/chunk-LBYU24PW.js.map +1 -0
- package/dist/{chunk-QJJAGFJJ.js → chunk-QSDDP7JN.js} +17 -106
- package/dist/chunk-QSDDP7JN.js.map +1 -0
- package/dist/{chunk-7NDNTSHD.js → chunk-U3HCB23E.js} +154 -3
- package/dist/chunk-U3HCB23E.js.map +1 -0
- package/dist/chunk-XWVM4KPK.js +96 -0
- package/dist/chunk-XWVM4KPK.js.map +1 -0
- package/dist/claude-code-updater-7BGQ6JCV.js +101 -0
- package/dist/claude-code-updater-7BGQ6JCV.js.map +1 -0
- package/dist/{claude-pair-runtime-A35NZYDN.js → claude-pair-runtime-2NNAUBP3.js} +2 -2
- package/dist/lib/manager-worker.js +174 -137
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/index.js +5 -3
- package/dist/mcp/slack-channel.js +135 -49
- package/dist/{persistent-session-E5EZ32CI.js → persistent-session-K4X76LLB.js} +4 -3
- package/dist/{responsiveness-probe-MLUVAXJH.js → responsiveness-probe-QBV43SJ7.js} +4 -3
- package/dist/{responsiveness-probe-MLUVAXJH.js.map → responsiveness-probe-QBV43SJ7.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-7NDNTSHD.js.map +0 -1
- package/dist/chunk-QJJAGFJJ.js.map +0 -1
- package/dist/chunk-UTPOHAX7.js.map +0 -1
- /package/dist/{claude-pair-runtime-A35NZYDN.js.map → claude-pair-runtime-2NNAUBP3.js.map} +0 -0
- /package/dist/{persistent-session-E5EZ32CI.js.map → persistent-session-K4X76LLB.js.map} +0 -0
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
provisionOrientHook,
|
|
14
14
|
provisionStopHook,
|
|
15
15
|
requireHost
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-LBYU24PW.js";
|
|
17
17
|
import {
|
|
18
18
|
getProjectDir as getProjectDir2,
|
|
19
19
|
getReadyTasks,
|
|
@@ -32,11 +32,9 @@ import {
|
|
|
32
32
|
isAgentPromptReady,
|
|
33
33
|
isSessionHealthy,
|
|
34
34
|
isStaleForToday,
|
|
35
|
-
parsePsRows,
|
|
36
35
|
peekCurrentSession,
|
|
37
36
|
prepareForRespawn,
|
|
38
37
|
readPaneLogTail,
|
|
39
|
-
reapOrphanChannelMcps,
|
|
40
38
|
resetRestartCount,
|
|
41
39
|
resolveClaudeBinary,
|
|
42
40
|
sanitizeMcpJson,
|
|
@@ -46,7 +44,7 @@ import {
|
|
|
46
44
|
stopAllSessionsAndWait,
|
|
47
45
|
stopPersistentSession,
|
|
48
46
|
takeZombieDetection
|
|
49
|
-
} from "../chunk-
|
|
47
|
+
} from "../chunk-QSDDP7JN.js";
|
|
50
48
|
import {
|
|
51
49
|
KANBAN_CHECK_COMMAND,
|
|
52
50
|
appendDmFooter,
|
|
@@ -69,7 +67,11 @@ import {
|
|
|
69
67
|
resolveConnectivityProbe,
|
|
70
68
|
resolveDmTarget,
|
|
71
69
|
wrapScheduledTaskPrompt
|
|
72
|
-
} from "../chunk-
|
|
70
|
+
} from "../chunk-U3HCB23E.js";
|
|
71
|
+
import {
|
|
72
|
+
parsePsRows,
|
|
73
|
+
reapOrphanChannelMcps
|
|
74
|
+
} from "../chunk-XWVM4KPK.js";
|
|
73
75
|
|
|
74
76
|
// src/lib/manager-worker.ts
|
|
75
77
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -2191,6 +2193,67 @@ function withScheduleLinkFooter(opts) {
|
|
|
2191
2193
|
return appendScheduleLinkFooter(opts.body, url, opts.medium);
|
|
2192
2194
|
}
|
|
2193
2195
|
|
|
2196
|
+
// src/lib/manager/agent-state.ts
|
|
2197
|
+
var agentState = {
|
|
2198
|
+
// ---------------------------------------------------------------------------
|
|
2199
|
+
// agentId-keyed
|
|
2200
|
+
// ---------------------------------------------------------------------------
|
|
2201
|
+
knownVersions: /* @__PURE__ */ new Map(),
|
|
2202
|
+
knownStatuses: /* @__PURE__ */ new Map(),
|
|
2203
|
+
knownChannels: /* @__PURE__ */ new Map(),
|
|
2204
|
+
writtenHashes: /* @__PURE__ */ new Map(),
|
|
2205
|
+
knownSecretsHashes: /* @__PURE__ */ new Map(),
|
|
2206
|
+
knownModels: /* @__PURE__ */ new Map(),
|
|
2207
|
+
knownTasksHashes: /* @__PURE__ */ new Map(),
|
|
2208
|
+
knownIntegrationHashes: /* @__PURE__ */ new Map(),
|
|
2209
|
+
knownManagedMcpHashes: /* @__PURE__ */ new Map(),
|
|
2210
|
+
knownManagedMcpStructure: /* @__PURE__ */ new Map(),
|
|
2211
|
+
// ---------------------------------------------------------------------------
|
|
2212
|
+
// codeName-keyed
|
|
2213
|
+
// ---------------------------------------------------------------------------
|
|
2214
|
+
agentDisplayNames: /* @__PURE__ */ new Map(),
|
|
2215
|
+
codeNameToAgentId: /* @__PURE__ */ new Map(),
|
|
2216
|
+
/**
|
|
2217
|
+
* Set of code_names with a live persistent session managed by this worker.
|
|
2218
|
+
* Borderline ownership: written from pollCycle and the persistent-session
|
|
2219
|
+
* lifecycle, read from the kanban-inject gate. Lives in agentState to keep
|
|
2220
|
+
* the kanban subsystem from importing from lifecycle in PR-C/E.
|
|
2221
|
+
*/
|
|
2222
|
+
persistentSessionAgents: /* @__PURE__ */ new Set(),
|
|
2223
|
+
// ---------------------------------------------------------------------------
|
|
2224
|
+
// compound-keyed (`agentId:<suffix>`)
|
|
2225
|
+
// ---------------------------------------------------------------------------
|
|
2226
|
+
knownChannelConfigHashes: /* @__PURE__ */ new Map(),
|
|
2227
|
+
knownSkillHashes: /* @__PURE__ */ new Map()
|
|
2228
|
+
};
|
|
2229
|
+
function clearAgentState(agentId, codeName) {
|
|
2230
|
+
agentState.knownVersions.delete(agentId);
|
|
2231
|
+
agentState.knownStatuses.delete(agentId);
|
|
2232
|
+
agentState.knownChannels.delete(agentId);
|
|
2233
|
+
agentState.writtenHashes.delete(agentId);
|
|
2234
|
+
agentState.knownSecretsHashes.delete(agentId);
|
|
2235
|
+
agentState.knownModels.delete(agentId);
|
|
2236
|
+
agentState.knownTasksHashes.delete(agentId);
|
|
2237
|
+
agentState.knownIntegrationHashes.delete(agentId);
|
|
2238
|
+
agentState.knownManagedMcpHashes.delete(agentId);
|
|
2239
|
+
agentState.knownManagedMcpStructure.delete(agentId);
|
|
2240
|
+
agentState.agentDisplayNames.delete(codeName);
|
|
2241
|
+
agentState.codeNameToAgentId.delete(codeName);
|
|
2242
|
+
let channelCacheMutated = false;
|
|
2243
|
+
for (const key of agentState.knownChannelConfigHashes.keys()) {
|
|
2244
|
+
if (key.startsWith(`${agentId}:`)) {
|
|
2245
|
+
agentState.knownChannelConfigHashes.delete(key);
|
|
2246
|
+
channelCacheMutated = true;
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
for (const key of agentState.knownSkillHashes.keys()) {
|
|
2250
|
+
if (key.startsWith(`${agentId}:`)) {
|
|
2251
|
+
agentState.knownSkillHashes.delete(key);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
return channelCacheMutated;
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2194
2257
|
// src/lib/restart-flags.ts
|
|
2195
2258
|
import { existsSync as existsSync3, mkdirSync, readdirSync as readdirSync2, readFileSync as readFileSync4, renameSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
2196
2259
|
import { homedir as homedir3 } from "os";
|
|
@@ -2846,9 +2909,6 @@ function shouldSkipRevokedCleanup(previousKnownStatus) {
|
|
|
2846
2909
|
function hasRevokedResiduals(state5) {
|
|
2847
2910
|
return state5.gatewayRunning || state5.portAllocated || state5.provisionDirExists;
|
|
2848
2911
|
}
|
|
2849
|
-
var knownVersions = /* @__PURE__ */ new Map();
|
|
2850
|
-
var knownStatuses = /* @__PURE__ */ new Map();
|
|
2851
|
-
var knownChannels = /* @__PURE__ */ new Map();
|
|
2852
2912
|
var pendingSessionRestarts = /* @__PURE__ */ new Map();
|
|
2853
2913
|
var restartBreaker = new RestartBreaker();
|
|
2854
2914
|
var reportedTrips = /* @__PURE__ */ new Map();
|
|
@@ -2863,7 +2923,7 @@ function recordRestartForBreaker(codeName, reason) {
|
|
|
2863
2923
|
}
|
|
2864
2924
|
async function reportCircuitTripped(codeName, trip) {
|
|
2865
2925
|
if (reportedTrips.get(codeName) === trip.trippedAt) return;
|
|
2866
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
2926
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
2867
2927
|
if (!agentId) throw new Error(`no agent_id known yet for '${codeName}' \u2014 will retry next poll`);
|
|
2868
2928
|
await api.post("/host/circuit-breaker/trip", {
|
|
2869
2929
|
agent_id: agentId,
|
|
@@ -2904,8 +2964,6 @@ function cancelPendingSessionRestart(codeName) {
|
|
|
2904
2964
|
pendingSessionRestarts.delete(codeName);
|
|
2905
2965
|
log(`[hot-reload] Cancelled pending restart timer for '${codeName}' (another teardown path is handling it)`);
|
|
2906
2966
|
}
|
|
2907
|
-
var writtenHashes = /* @__PURE__ */ new Map();
|
|
2908
|
-
var knownSecretsHashes = /* @__PURE__ */ new Map();
|
|
2909
2967
|
var runningMcpHashes = /* @__PURE__ */ new Map();
|
|
2910
2968
|
var runningMcpServerKeys = /* @__PURE__ */ new Map();
|
|
2911
2969
|
function projectMcpHash(_codeName, projectDir) {
|
|
@@ -3045,13 +3103,6 @@ function checkMcpConfigDriftAndScheduleRestart(codeName, projectDir) {
|
|
|
3045
3103
|
}
|
|
3046
3104
|
}
|
|
3047
3105
|
}
|
|
3048
|
-
var knownChannelConfigHashes = /* @__PURE__ */ new Map();
|
|
3049
|
-
var knownModels = /* @__PURE__ */ new Map();
|
|
3050
|
-
var knownTasksHashes = /* @__PURE__ */ new Map();
|
|
3051
|
-
var knownIntegrationHashes = /* @__PURE__ */ new Map();
|
|
3052
|
-
var knownManagedMcpHashes = /* @__PURE__ */ new Map();
|
|
3053
|
-
var knownManagedMcpStructure = /* @__PURE__ */ new Map();
|
|
3054
|
-
var knownSkillHashes = /* @__PURE__ */ new Map();
|
|
3055
3106
|
var managedToolkitIdByAgentAndServerId = /* @__PURE__ */ new Map();
|
|
3056
3107
|
function managedToolkitMapKey(agentId, serverId) {
|
|
3057
3108
|
return `${agentId}\0${serverId}`;
|
|
@@ -3070,8 +3121,6 @@ var STALE_TASK_THRESHOLD_MS = (() => {
|
|
|
3070
3121
|
var alertSlackWebhook = null;
|
|
3071
3122
|
var alertedJobs = /* @__PURE__ */ new Set();
|
|
3072
3123
|
var taskDisplayInfo = /* @__PURE__ */ new Map();
|
|
3073
|
-
var agentDisplayNames = /* @__PURE__ */ new Map();
|
|
3074
|
-
var codeNameToAgentId = /* @__PURE__ */ new Map();
|
|
3075
3124
|
var agentChannelTokens = /* @__PURE__ */ new Map();
|
|
3076
3125
|
var activeChannels = /* @__PURE__ */ new Map();
|
|
3077
3126
|
var gatewaysStartedThisCycle = /* @__PURE__ */ new Set();
|
|
@@ -3093,18 +3142,7 @@ function resolveAgentFramework(codeName) {
|
|
|
3093
3142
|
}
|
|
3094
3143
|
var gatewayPool = null;
|
|
3095
3144
|
function clearAgentCaches(agentId, codeName) {
|
|
3096
|
-
|
|
3097
|
-
knownStatuses.delete(agentId);
|
|
3098
|
-
knownChannels.delete(agentId);
|
|
3099
|
-
writtenHashes.delete(agentId);
|
|
3100
|
-
knownSecretsHashes.delete(agentId);
|
|
3101
|
-
knownModels.delete(agentId);
|
|
3102
|
-
knownTasksHashes.delete(agentId);
|
|
3103
|
-
knownIntegrationHashes.delete(agentId);
|
|
3104
|
-
knownManagedMcpHashes.delete(agentId);
|
|
3105
|
-
knownManagedMcpStructure.delete(agentId);
|
|
3106
|
-
agentDisplayNames.delete(codeName);
|
|
3107
|
-
codeNameToAgentId.delete(codeName);
|
|
3145
|
+
const channelCacheMutated = clearAgentState(agentId, codeName);
|
|
3108
3146
|
agentFrameworkCache.delete(codeName);
|
|
3109
3147
|
kanbanBoardCache.delete(codeName);
|
|
3110
3148
|
lastHarvestAt.delete(codeName);
|
|
@@ -3114,26 +3152,16 @@ function clearAgentCaches(agentId, codeName) {
|
|
|
3114
3152
|
memoryFileHashes.delete(agentId);
|
|
3115
3153
|
lastDownloadHash.delete(agentId);
|
|
3116
3154
|
lastLocalFileHash.delete(agentId);
|
|
3117
|
-
let channelCacheMutated = false;
|
|
3118
|
-
for (const key of knownChannelConfigHashes.keys()) {
|
|
3119
|
-
if (key.startsWith(`${agentId}:`)) {
|
|
3120
|
-
knownChannelConfigHashes.delete(key);
|
|
3121
|
-
channelCacheMutated = true;
|
|
3122
|
-
}
|
|
3123
|
-
}
|
|
3124
|
-
if (channelCacheMutated) saveChannelHashCache2();
|
|
3125
|
-
for (const key of knownSkillHashes.keys()) {
|
|
3126
|
-
if (key.startsWith(`${agentId}:`)) knownSkillHashes.delete(key);
|
|
3127
|
-
}
|
|
3128
3155
|
for (const key of taskDisplayInfo.keys()) {
|
|
3129
3156
|
if (key.startsWith(`${codeName}:`)) taskDisplayInfo.delete(key);
|
|
3130
3157
|
}
|
|
3158
|
+
if (channelCacheMutated) saveChannelHashCache2();
|
|
3131
3159
|
}
|
|
3132
3160
|
var cachedFrameworkVersion = null;
|
|
3133
3161
|
var lastVersionCheckAt = 0;
|
|
3134
3162
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
3135
3163
|
var lastResponsivenessProbeAt = 0;
|
|
3136
|
-
var agtCliVersion = true ? "0.26.1" : "dev";
|
|
3164
|
+
var agtCliVersion = true ? "0.26.2-eng5706.1" : "dev";
|
|
3137
3165
|
function resolveBrewPath(execFileSync4) {
|
|
3138
3166
|
try {
|
|
3139
3167
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -3647,10 +3675,10 @@ function channelHashCacheDir() {
|
|
|
3647
3675
|
return config?.configDir ?? join6(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
3648
3676
|
}
|
|
3649
3677
|
function loadChannelHashCache2() {
|
|
3650
|
-
loadChannelHashCache(knownChannelConfigHashes, channelHashCacheDir());
|
|
3678
|
+
loadChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
|
|
3651
3679
|
}
|
|
3652
3680
|
function saveChannelHashCache2() {
|
|
3653
|
-
saveChannelHashCache(knownChannelConfigHashes, channelHashCacheDir());
|
|
3681
|
+
saveChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
|
|
3654
3682
|
}
|
|
3655
3683
|
function send(msg) {
|
|
3656
3684
|
if (msg.type === "state-update") {
|
|
@@ -3981,40 +4009,40 @@ async function stopAllGateways() {
|
|
|
3981
4009
|
}
|
|
3982
4010
|
}
|
|
3983
4011
|
async function healthCheckGateways(agentStates) {
|
|
3984
|
-
for (const
|
|
3985
|
-
if (
|
|
3986
|
-
const adapter = resolveAgentFramework(
|
|
4012
|
+
for (const agent of agentStates) {
|
|
4013
|
+
if (agent.status !== "active" || !agent.gatewayPort) continue;
|
|
4014
|
+
const adapter = resolveAgentFramework(agent.codeName);
|
|
3987
4015
|
if (!adapter.isGatewayRunning || !adapter.startGateway) continue;
|
|
3988
|
-
if (gatewaysStartedThisCycle.has(
|
|
3989
|
-
const status = await adapter.isGatewayRunning(
|
|
3990
|
-
if (!status.running &&
|
|
3991
|
-
const displayName = agentDisplayNames.get(
|
|
3992
|
-
log(`Gateway for '${
|
|
4016
|
+
if (gatewaysStartedThisCycle.has(agent.codeName)) continue;
|
|
4017
|
+
const status = await adapter.isGatewayRunning(agent.codeName);
|
|
4018
|
+
if (!status.running && agent.gatewayRunning) {
|
|
4019
|
+
const displayName = agentState.agentDisplayNames.get(agent.codeName) ?? agent.codeName;
|
|
4020
|
+
log(`Gateway for '${agent.codeName}' crashed, restarting...`);
|
|
3993
4021
|
sendSlackWebhookMessage(
|
|
3994
|
-
`:red_circle: *Host Down* \u2014 *${displayName}* (\`${
|
|
4022
|
+
`:red_circle: *Host Down* \u2014 *${displayName}* (\`${agent.codeName}\`)
|
|
3995
4023
|
OpenClaw gateway crashed. Attempting automatic restart...`
|
|
3996
4024
|
).catch(() => {
|
|
3997
4025
|
});
|
|
3998
4026
|
try {
|
|
3999
|
-
const result = await adapter.startGateway(
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
log(`Gateway restarted for '${
|
|
4027
|
+
const result = await adapter.startGateway(agent.codeName, agent.gatewayPort);
|
|
4028
|
+
agent.gatewayPid = result.pid;
|
|
4029
|
+
agent.gatewayRunning = true;
|
|
4030
|
+
log(`Gateway restarted for '${agent.codeName}' (PID ${result.pid})`);
|
|
4003
4031
|
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
4004
4032
|
if (gatewayPool) {
|
|
4005
|
-
const token = readGatewayToken(
|
|
4006
|
-
gatewayPool.addAgent(
|
|
4033
|
+
const token = readGatewayToken(agent.codeName);
|
|
4034
|
+
gatewayPool.addAgent(agent.codeName, agent.gatewayPort, token);
|
|
4007
4035
|
}
|
|
4008
4036
|
sendSlackWebhookMessage(
|
|
4009
|
-
`:large_green_circle: *Host Recovered* \u2014 *${displayName}* (\`${
|
|
4037
|
+
`:large_green_circle: *Host Recovered* \u2014 *${displayName}* (\`${agent.codeName}\`)
|
|
4010
4038
|
Gateway restarted successfully (PID ${result.pid}).`
|
|
4011
4039
|
).catch(() => {
|
|
4012
4040
|
});
|
|
4013
4041
|
} catch (err) {
|
|
4014
|
-
|
|
4015
|
-
log(`Failed to restart gateway for '${
|
|
4042
|
+
agent.gatewayRunning = false;
|
|
4043
|
+
log(`Failed to restart gateway for '${agent.codeName}': ${err.message}`);
|
|
4016
4044
|
sendSlackWebhookMessage(
|
|
4017
|
-
`:x: *Host Restart Failed* \u2014 *${displayName}* (\`${
|
|
4045
|
+
`:x: *Host Restart Failed* \u2014 *${displayName}* (\`${agent.codeName}\`)
|
|
4018
4046
|
Automatic restart failed: ${err.message}`
|
|
4019
4047
|
).catch(() => {
|
|
4020
4048
|
});
|
|
@@ -4032,7 +4060,7 @@ async function pollCycle() {
|
|
|
4032
4060
|
resolveFramework: (codeName) => agentFrameworkCache.get(codeName) ?? null,
|
|
4033
4061
|
stopSession: (codeName) => {
|
|
4034
4062
|
stopPersistentSessionAndForgetMcpBaseline(codeName, "channel-set-change");
|
|
4035
|
-
persistentSessionAgents.delete(codeName);
|
|
4063
|
+
agentState.persistentSessionAgents.delete(codeName);
|
|
4036
4064
|
claudeAuthTupleBySession.delete(codeName);
|
|
4037
4065
|
},
|
|
4038
4066
|
getTelegramTokens: (codeName) => {
|
|
@@ -4092,8 +4120,8 @@ async function pollCycle() {
|
|
|
4092
4120
|
}
|
|
4093
4121
|
try {
|
|
4094
4122
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
4095
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
4096
|
-
const diagCodeNames = [...persistentSessionAgents];
|
|
4123
|
+
const { collectDiagnostics } = await import("../persistent-session-K4X76LLB.js");
|
|
4124
|
+
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
4097
4125
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
4098
4126
|
let tailscaleHostname;
|
|
4099
4127
|
try {
|
|
@@ -4125,7 +4153,7 @@ async function pollCycle() {
|
|
|
4125
4153
|
const errId = createHash3("sha256").update(errText).digest("hex").slice(0, 12);
|
|
4126
4154
|
log(`Claude auth detection failed (error_id=${errId})`);
|
|
4127
4155
|
}
|
|
4128
|
-
await api.post("/host/heartbeat", {
|
|
4156
|
+
const hbResp = await api.post("/host/heartbeat", {
|
|
4129
4157
|
host_id: hostId,
|
|
4130
4158
|
framework_version: cachedFrameworkVersion ?? void 0,
|
|
4131
4159
|
agt_version: agtCliVersion,
|
|
@@ -4143,6 +4171,16 @@ async function pollCycle() {
|
|
|
4143
4171
|
// behind a fresh heartbeat.
|
|
4144
4172
|
realtime_socket_connected: isRealtimeSocketConnected()
|
|
4145
4173
|
});
|
|
4174
|
+
try {
|
|
4175
|
+
const { maybeUpdateClaudeCode } = await import("../claude-code-updater-7BGQ6JCV.js");
|
|
4176
|
+
await maybeUpdateClaudeCode({
|
|
4177
|
+
desiredVersion: hbResp?.desired_claude_code_version ?? "latest",
|
|
4178
|
+
currentVersion: cachedFrameworkVersion,
|
|
4179
|
+
log
|
|
4180
|
+
});
|
|
4181
|
+
} catch (err) {
|
|
4182
|
+
log(`Claude Code updater error: ${err.message}`);
|
|
4183
|
+
}
|
|
4146
4184
|
} catch (err) {
|
|
4147
4185
|
log(`Heartbeat failed: ${err.message}`);
|
|
4148
4186
|
}
|
|
@@ -4150,10 +4188,10 @@ async function pollCycle() {
|
|
|
4150
4188
|
const {
|
|
4151
4189
|
collectResponsivenessProbes,
|
|
4152
4190
|
getResponsivenessIntervalMs
|
|
4153
|
-
} = await import("../responsiveness-probe-
|
|
4191
|
+
} = await import("../responsiveness-probe-QBV43SJ7.js");
|
|
4154
4192
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
4155
4193
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
4156
|
-
const probeCodeNames = [...persistentSessionAgents];
|
|
4194
|
+
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
4157
4195
|
if (probeCodeNames.length > 0) {
|
|
4158
4196
|
const probes = collectResponsivenessProbes(probeCodeNames);
|
|
4159
4197
|
if (probes.length > 0) {
|
|
@@ -4171,8 +4209,8 @@ async function pollCycle() {
|
|
|
4171
4209
|
const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
|
|
4172
4210
|
const observations = [];
|
|
4173
4211
|
const pendingCacheCommits = [];
|
|
4174
|
-
for (const codeName of persistentSessionAgents) {
|
|
4175
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
4212
|
+
for (const codeName of agentState.persistentSessionAgents) {
|
|
4213
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
4176
4214
|
if (!agentId) continue;
|
|
4177
4215
|
const tail = readPaneLogTail(codeName, 40);
|
|
4178
4216
|
if (!tail) continue;
|
|
@@ -4192,7 +4230,7 @@ async function pollCycle() {
|
|
|
4192
4230
|
(resp?.results ?? []).filter((r) => r.ok).map((r) => r.agent_id)
|
|
4193
4231
|
);
|
|
4194
4232
|
for (const { codeName, count } of pendingCacheCommits) {
|
|
4195
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
4233
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
4196
4234
|
if (agentId && accepted.has(agentId)) {
|
|
4197
4235
|
lastMcpFailedBannerCount.set(codeName, count);
|
|
4198
4236
|
}
|
|
@@ -4423,9 +4461,9 @@ async function getOrCacheRegisteredAgents(adapter, profile) {
|
|
|
4423
4461
|
}
|
|
4424
4462
|
async function processAgent(agent, agentStates) {
|
|
4425
4463
|
if (!config) return;
|
|
4426
|
-
const previousKnownStatus = knownStatuses.get(agent.agent_id);
|
|
4427
|
-
agentDisplayNames.set(agent.code_name, agent.display_name);
|
|
4428
|
-
codeNameToAgentId.set(agent.code_name, agent.agent_id);
|
|
4464
|
+
const previousKnownStatus = agentState.knownStatuses.get(agent.agent_id);
|
|
4465
|
+
agentState.agentDisplayNames.set(agent.code_name, agent.display_name);
|
|
4466
|
+
agentState.codeNameToAgentId.set(agent.code_name, agent.agent_id);
|
|
4429
4467
|
maybeReportCurrentTrip(agent.code_name);
|
|
4430
4468
|
if (agent.framework) {
|
|
4431
4469
|
agentFrameworkCache.set(agent.code_name, agent.framework);
|
|
@@ -4475,7 +4513,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4475
4513
|
gatewayRunning: false,
|
|
4476
4514
|
acpSessions: []
|
|
4477
4515
|
});
|
|
4478
|
-
knownStatuses.set(agent.agent_id, agent.status);
|
|
4516
|
+
agentState.knownStatuses.set(agent.agent_id, agent.status);
|
|
4479
4517
|
return;
|
|
4480
4518
|
}
|
|
4481
4519
|
if (agent.status === "revoked") {
|
|
@@ -4522,7 +4560,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4522
4560
|
freePort(agent.code_name);
|
|
4523
4561
|
await cleanupAgentFiles(agent.code_name, agentDir);
|
|
4524
4562
|
clearAgentCaches(agent.agent_id, agent.code_name);
|
|
4525
|
-
knownStatuses.set(agent.agent_id, agent.status);
|
|
4563
|
+
agentState.knownStatuses.set(agent.agent_id, agent.status);
|
|
4526
4564
|
agentStates.push({
|
|
4527
4565
|
agentId: agent.agent_id,
|
|
4528
4566
|
codeName: agent.code_name,
|
|
@@ -4541,25 +4579,25 @@ async function processAgent(agent, agentStates) {
|
|
|
4541
4579
|
});
|
|
4542
4580
|
return;
|
|
4543
4581
|
}
|
|
4544
|
-
const previousStatus = knownStatuses.get(agent.agent_id);
|
|
4582
|
+
const previousStatus = agentState.knownStatuses.get(agent.agent_id);
|
|
4545
4583
|
if (previousStatus && previousStatus !== agent.status) {
|
|
4546
4584
|
log(`Agent '${agent.code_name}' status changed: ${previousStatus} \u2192 ${agent.status}`);
|
|
4547
|
-
knownVersions.delete(agent.agent_id);
|
|
4585
|
+
agentState.knownVersions.delete(agent.agent_id);
|
|
4548
4586
|
if (previousStatus === "paused" && agent.status === "active" && restartBreaker.isTripped(agent.code_name)) {
|
|
4549
4587
|
restartBreaker.clear(agent.code_name);
|
|
4550
4588
|
reportedTrips.delete(agent.code_name);
|
|
4551
4589
|
log(`[circuit-breaker] Cleared trip for '${agent.code_name}' on operator resume (paused \u2192 active)`);
|
|
4552
4590
|
}
|
|
4553
4591
|
let channelCacheMutated = false;
|
|
4554
|
-
for (const key of knownChannelConfigHashes.keys()) {
|
|
4592
|
+
for (const key of agentState.knownChannelConfigHashes.keys()) {
|
|
4555
4593
|
if (key.startsWith(`${agent.agent_id}:`)) {
|
|
4556
|
-
knownChannelConfigHashes.delete(key);
|
|
4594
|
+
agentState.knownChannelConfigHashes.delete(key);
|
|
4557
4595
|
channelCacheMutated = true;
|
|
4558
4596
|
}
|
|
4559
4597
|
}
|
|
4560
4598
|
if (channelCacheMutated) saveChannelHashCache2();
|
|
4561
4599
|
}
|
|
4562
|
-
knownStatuses.set(agent.agent_id, agent.status);
|
|
4600
|
+
agentState.knownStatuses.set(agent.agent_id, agent.status);
|
|
4563
4601
|
let refreshData;
|
|
4564
4602
|
try {
|
|
4565
4603
|
refreshData = await api.post("/host/refresh", {
|
|
@@ -4622,10 +4660,10 @@ async function processAgent(agent, agentStates) {
|
|
|
4622
4660
|
}
|
|
4623
4661
|
const charterVersion = refreshData.charter.version;
|
|
4624
4662
|
const toolsVersion = refreshData.tools.version;
|
|
4625
|
-
const known = knownVersions.get(agent.agent_id);
|
|
4663
|
+
const known = agentState.knownVersions.get(agent.agent_id);
|
|
4626
4664
|
let lastProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
|
|
4627
4665
|
const currentChannelIds = launchableChannelIds(refreshData.channel_configs);
|
|
4628
|
-
const previousChannelIds = knownChannels.get(agent.agent_id);
|
|
4666
|
+
const previousChannelIds = agentState.knownChannels.get(agent.agent_id);
|
|
4629
4667
|
const channelsChanged = !previousChannelIds || currentChannelIds.size !== previousChannelIds.size || [...currentChannelIds].some((ch) => !previousChannelIds.has(ch)) || [...previousChannelIds].some((ch) => !currentChannelIds.has(ch));
|
|
4630
4668
|
let channelConfigConverged = true;
|
|
4631
4669
|
if (previousChannelIds && channelsChanged && frameworkAdapter.removeChannelCredentials) {
|
|
@@ -4723,14 +4761,14 @@ async function processAgent(agent, agentStates) {
|
|
|
4723
4761
|
} catch {
|
|
4724
4762
|
}
|
|
4725
4763
|
lastProvisionAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4726
|
-
knownVersions.set(agent.agent_id, { charterVersion, toolsVersion });
|
|
4764
|
+
agentState.knownVersions.set(agent.agent_id, { charterVersion, toolsVersion });
|
|
4727
4765
|
const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
|
|
4728
4766
|
const hashes = /* @__PURE__ */ new Map();
|
|
4729
4767
|
for (const file of trackedFiles2) {
|
|
4730
4768
|
const h = hashFile(join6(agentDir, file));
|
|
4731
4769
|
if (h) hashes.set(file, h);
|
|
4732
4770
|
}
|
|
4733
|
-
writtenHashes.set(agent.agent_id, hashes);
|
|
4771
|
+
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
4734
4772
|
const resolvedModelsForRegistration = resolveModelChain(refreshData);
|
|
4735
4773
|
const primaryModel2 = resolvedModelsForRegistration.primary ?? refreshData.agent.primary_model;
|
|
4736
4774
|
const registeredAgents = await getOrCacheRegisteredAgents(frameworkAdapter, agent.code_name);
|
|
@@ -4752,7 +4790,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4752
4790
|
const resolvedForModel = resolveModelChain(refreshData);
|
|
4753
4791
|
const primaryModel = resolvedForModel.primary ?? refreshData.agent.primary_model;
|
|
4754
4792
|
if (primaryModel && frameworkAdapter.updateAgentModel) {
|
|
4755
|
-
const previousModel = knownModels.get(agent.agent_id);
|
|
4793
|
+
const previousModel = agentState.knownModels.get(agent.agent_id);
|
|
4756
4794
|
if (previousModel !== primaryModel) {
|
|
4757
4795
|
try {
|
|
4758
4796
|
const updated = await frameworkAdapter.updateAgentModel(agent.code_name, primaryModel);
|
|
@@ -4788,10 +4826,10 @@ async function processAgent(agent, agentStates) {
|
|
|
4788
4826
|
scheduleSessionRestart(agent.code_name, delay, "model change", "model-change");
|
|
4789
4827
|
}
|
|
4790
4828
|
}
|
|
4791
|
-
knownModels.set(agent.agent_id, primaryModel);
|
|
4829
|
+
agentState.knownModels.set(agent.agent_id, primaryModel);
|
|
4792
4830
|
}
|
|
4793
4831
|
let lastDriftCheckAt = now;
|
|
4794
|
-
const written = writtenHashes.get(agent.agent_id);
|
|
4832
|
+
const written = agentState.writtenHashes.get(agent.agent_id);
|
|
4795
4833
|
if (written && existsSync4(agentDir)) {
|
|
4796
4834
|
const driftedFiles = [];
|
|
4797
4835
|
for (const [file, expectedHash] of written) {
|
|
@@ -4888,14 +4926,14 @@ async function processAgent(agent, agentStates) {
|
|
|
4888
4926
|
log(`hasChannelCredentials failed for '${agent.code_name}/${channelId}': ${err.message} \u2014 forcing credential rewrite`);
|
|
4889
4927
|
onDiskPresent = false;
|
|
4890
4928
|
}
|
|
4891
|
-
if (knownChannelConfigHashes.get(cacheKey) === configHash && onDiskPresent) {
|
|
4929
|
+
if (agentState.knownChannelConfigHashes.get(cacheKey) === configHash && onDiskPresent) {
|
|
4892
4930
|
continue;
|
|
4893
4931
|
}
|
|
4894
|
-
const prevHash = knownChannelConfigHashes.get(cacheKey);
|
|
4932
|
+
const prevHash = agentState.knownChannelConfigHashes.get(cacheKey);
|
|
4895
4933
|
const reason = !prevHash ? "first-write" : !onDiskPresent ? "on-disk-missing" : "content-changed";
|
|
4896
4934
|
if (!onDiskPresent && prevHash) {
|
|
4897
4935
|
log(`Cached hash for '${agent.code_name}/${channelId}' but on-disk entry missing \u2014 re-writing credentials`);
|
|
4898
|
-
knownChannelConfigHashes.delete(cacheKey);
|
|
4936
|
+
agentState.knownChannelConfigHashes.delete(cacheKey);
|
|
4899
4937
|
}
|
|
4900
4938
|
try {
|
|
4901
4939
|
const sessionMode2 = refreshData.agent.session_mode;
|
|
@@ -4917,7 +4955,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4917
4955
|
agentTimezone
|
|
4918
4956
|
}
|
|
4919
4957
|
);
|
|
4920
|
-
knownChannelConfigHashes.set(cacheKey, configHash);
|
|
4958
|
+
agentState.knownChannelConfigHashes.set(cacheKey, configHash);
|
|
4921
4959
|
saveChannelHashCache2();
|
|
4922
4960
|
log(`Channel credentials written for '${agent.code_name}/${channelId}' (reason=${reason}, hash=${configHash.slice(0, 8)}${prevHash ? `, prev=${prevHash.slice(0, 8)}` : ""})`);
|
|
4923
4961
|
} catch (err) {
|
|
@@ -4935,7 +4973,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4935
4973
|
}
|
|
4936
4974
|
}
|
|
4937
4975
|
if (channelConfigConverged) {
|
|
4938
|
-
knownChannels.set(agent.agent_id, currentChannelIds);
|
|
4976
|
+
agentState.knownChannels.set(agent.agent_id, currentChannelIds);
|
|
4939
4977
|
} else {
|
|
4940
4978
|
log(`[channels] Credential sync did not converge for '${agent.code_name}' \u2014 leaving diff live for next tick retry`);
|
|
4941
4979
|
}
|
|
@@ -5009,7 +5047,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5009
5047
|
}
|
|
5010
5048
|
}
|
|
5011
5049
|
let lastSecretsProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
|
|
5012
|
-
let secretsHash = knownSecretsHashes.get(agent.agent_id) ?? null;
|
|
5050
|
+
let secretsHash = agentState.knownSecretsHashes.get(agent.agent_id) ?? null;
|
|
5013
5051
|
try {
|
|
5014
5052
|
const secretsData = await api.post("/host/secrets", { agent_id: agent.agent_id });
|
|
5015
5053
|
const newHash = secretsData.secrets_hash;
|
|
@@ -5020,10 +5058,10 @@ async function processAgent(agent, agentStates) {
|
|
|
5020
5058
|
log(`Secrets updated for '${agent.code_name}'`);
|
|
5021
5059
|
}
|
|
5022
5060
|
if (newHash) {
|
|
5023
|
-
knownSecretsHashes.set(agent.agent_id, newHash);
|
|
5061
|
+
agentState.knownSecretsHashes.set(agent.agent_id, newHash);
|
|
5024
5062
|
secretsHash = newHash;
|
|
5025
5063
|
} else {
|
|
5026
|
-
knownSecretsHashes.delete(agent.agent_id);
|
|
5064
|
+
agentState.knownSecretsHashes.delete(agent.agent_id);
|
|
5027
5065
|
secretsHash = null;
|
|
5028
5066
|
}
|
|
5029
5067
|
} catch (err) {
|
|
@@ -5070,7 +5108,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5070
5108
|
}
|
|
5071
5109
|
if (integrations.length > 0) {
|
|
5072
5110
|
const intHash = computeIntegrationsHash(integrations);
|
|
5073
|
-
const prevIntHash = knownIntegrationHashes.get(agent.agent_id);
|
|
5111
|
+
const prevIntHash = agentState.knownIntegrationHashes.get(agent.agent_id);
|
|
5074
5112
|
if (intHash !== prevIntHash) {
|
|
5075
5113
|
const projectDir = join6(homedir4(), ".augmented", agent.code_name, "project");
|
|
5076
5114
|
const envIntPath = join6(projectDir, ".env.integrations");
|
|
@@ -5115,7 +5153,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5115
5153
|
}
|
|
5116
5154
|
}
|
|
5117
5155
|
if (rotationHandled) {
|
|
5118
|
-
knownIntegrationHashes.set(agent.agent_id, intHash);
|
|
5156
|
+
agentState.knownIntegrationHashes.set(agent.agent_id, intHash);
|
|
5119
5157
|
}
|
|
5120
5158
|
needsGatewayRestart = true;
|
|
5121
5159
|
}
|
|
@@ -5145,9 +5183,9 @@ async function processAgent(agent, agentStates) {
|
|
|
5145
5183
|
return `${e.serverId}|${e.url}|${headersHash}`;
|
|
5146
5184
|
}).join("\n");
|
|
5147
5185
|
const mcpHash = createHash3("sha256").update(hashBasis).digest("hex").slice(0, 16);
|
|
5148
|
-
const prevMcpHash = knownManagedMcpHashes.get(agent.agent_id);
|
|
5186
|
+
const prevMcpHash = agentState.knownManagedMcpHashes.get(agent.agent_id);
|
|
5149
5187
|
const structureHash = managedMcpStructureHash(desiredEntries);
|
|
5150
|
-
const prevStructureHash = knownManagedMcpStructure.get(agent.agent_id);
|
|
5188
|
+
const prevStructureHash = agentState.knownManagedMcpStructure.get(agent.agent_id);
|
|
5151
5189
|
if (mcpHash !== prevMcpHash) {
|
|
5152
5190
|
for (const e of desiredEntries) {
|
|
5153
5191
|
frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
|
|
@@ -5184,8 +5222,8 @@ async function processAgent(agent, agentStates) {
|
|
|
5184
5222
|
}
|
|
5185
5223
|
}
|
|
5186
5224
|
}
|
|
5187
|
-
knownManagedMcpHashes.set(agent.agent_id, mcpHash);
|
|
5188
|
-
knownManagedMcpStructure.set(agent.agent_id, structureHash);
|
|
5225
|
+
agentState.knownManagedMcpHashes.set(agent.agent_id, mcpHash);
|
|
5226
|
+
agentState.knownManagedMcpStructure.set(agent.agent_id, structureHash);
|
|
5189
5227
|
if (prevStructureHash !== void 0 && structureHash !== prevStructureHash && fwForMcp === "claude-code" && isSessionHealthy(agent.code_name)) {
|
|
5190
5228
|
const mcpNames = agentToolkits.map((tk) => tk.toolkit_name).join(", ") || "none (all removed)";
|
|
5191
5229
|
log(`[hot-reload] MCP servers changed for '${agent.code_name}': ${mcpNames} \u2014 restarting session`);
|
|
@@ -5311,9 +5349,9 @@ async function processAgent(agent, agentStates) {
|
|
|
5311
5349
|
const bundle = buildIntegrationBundle(renderedScopes);
|
|
5312
5350
|
const contentHash = createHash4("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
|
|
5313
5351
|
const hashKey = `plugin-skill:${agent.agent_id}:${integrationSkillId}`;
|
|
5314
|
-
if (knownSkillHashes.get(hashKey) === contentHash) continue;
|
|
5352
|
+
if (agentState.knownSkillHashes.get(hashKey) === contentHash) continue;
|
|
5315
5353
|
frameworkAdapter.installSkillFiles(agent.code_name, integrationSkillId, bundle.files);
|
|
5316
|
-
knownSkillHashes.set(hashKey, contentHash);
|
|
5354
|
+
agentState.knownSkillHashes.set(hashKey, contentHash);
|
|
5317
5355
|
for (const s of scopes) installedIntegrationSkills.push(s.skill_name);
|
|
5318
5356
|
log(`Installed integration skill bundle '${integrationSkillId}' for '${agent.code_name}' (${scopes.length} scope(s))`);
|
|
5319
5357
|
} catch (err) {
|
|
@@ -5380,7 +5418,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5380
5418
|
try {
|
|
5381
5419
|
const scriptHash = createHash4("sha256").update(hook.script).digest("hex").slice(0, 12);
|
|
5382
5420
|
const hookKey = `${agent.agent_id}:${frameworkAdapter.id}:plugin-hook:${slug}:on_install`;
|
|
5383
|
-
if (knownSkillHashes.get(hookKey) === scriptHash) continue;
|
|
5421
|
+
if (agentState.knownSkillHashes.get(hookKey) === scriptHash) continue;
|
|
5384
5422
|
const result = await frameworkAdapter.executePluginHook({
|
|
5385
5423
|
codeName: agent.code_name,
|
|
5386
5424
|
pluginSlug: slug,
|
|
@@ -5388,7 +5426,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5388
5426
|
script: hook.script
|
|
5389
5427
|
});
|
|
5390
5428
|
if (result.exitCode === 0) {
|
|
5391
|
-
knownSkillHashes.set(hookKey, scriptHash);
|
|
5429
|
+
agentState.knownSkillHashes.set(hookKey, scriptHash);
|
|
5392
5430
|
log(`Integration hook on_install '${slug}' succeeded for '${agent.code_name}' (${result.durationMs}ms)`);
|
|
5393
5431
|
} else if (result.timedOut) {
|
|
5394
5432
|
log(`Integration hook on_install '${slug}' TIMED OUT for '${agent.code_name}' after ${result.durationMs}ms`);
|
|
@@ -5596,7 +5634,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5596
5634
|
const resolvedModels = resolveModelChain(refreshData);
|
|
5597
5635
|
const modelsHash = createHash3("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
|
|
5598
5636
|
const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
|
|
5599
|
-
const prevTasksHash = knownTasksHashes.get(agent.agent_id);
|
|
5637
|
+
const prevTasksHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
5600
5638
|
if (combinedHash !== prevTasksHash) {
|
|
5601
5639
|
const enrichedTasks = tasks.map((t) => {
|
|
5602
5640
|
if (BOARD_INJECT_TEMPLATES.has(t.template_id) && boardItems.length > 0) {
|
|
@@ -5633,7 +5671,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5633
5671
|
models: resolvedModels
|
|
5634
5672
|
}
|
|
5635
5673
|
);
|
|
5636
|
-
knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
5674
|
+
agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
5637
5675
|
log(`Scheduled tasks synced for '${agent.code_name}' (${enrichedTasks.length} task(s))`);
|
|
5638
5676
|
} catch (err) {
|
|
5639
5677
|
log(`Failed to sync scheduled tasks for '${agent.code_name}': ${err.message}`);
|
|
@@ -5702,7 +5740,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5702
5740
|
cleanupStaleSessions(agent.code_name);
|
|
5703
5741
|
}
|
|
5704
5742
|
{
|
|
5705
|
-
const agentId = codeNameToAgentId.get(agent.code_name);
|
|
5743
|
+
const agentId = agentState.codeNameToAgentId.get(agent.code_name);
|
|
5706
5744
|
if (agentId) {
|
|
5707
5745
|
try {
|
|
5708
5746
|
const boardData = await api.post("/host/my-kanban", { agent_id: agentId });
|
|
@@ -5718,7 +5756,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5718
5756
|
);
|
|
5719
5757
|
log(`[${agent.code_name}] Board diff: ${previousDoneIds.size} prev done \u2192 ${freshDoneIds.size} now, ${newlyDone.length} newly done`);
|
|
5720
5758
|
if (newlyDone.length > 0) {
|
|
5721
|
-
const displayName = agentDisplayNames.get(agent.code_name) ?? agent.code_name;
|
|
5759
|
+
const displayName = agentState.agentDisplayNames.get(agent.code_name) ?? agent.code_name;
|
|
5722
5760
|
for (const item of newlyDone) {
|
|
5723
5761
|
log(`Newly done: '${item.title}' notify_channel=${item.notify_channel ?? "none"} notify_to=${item.notify_to ?? "none"}`);
|
|
5724
5762
|
if (item.notify_channel && item.notify_to) {
|
|
@@ -5736,7 +5774,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5736
5774
|
return age > STALE_TASK_THRESHOLD_MS && !alertedStaleItems.has(`${agent.code_name}:${b.id}`);
|
|
5737
5775
|
});
|
|
5738
5776
|
if (staleItems.length > 0) {
|
|
5739
|
-
const displayName = agentDisplayNames.get(agent.code_name) ?? agent.code_name;
|
|
5777
|
+
const displayName = agentState.agentDisplayNames.get(agent.code_name) ?? agent.code_name;
|
|
5740
5778
|
for (const item of staleItems) {
|
|
5741
5779
|
const age = Math.round((Date.now() - new Date(item.updated_at).getTime()) / 6e4);
|
|
5742
5780
|
const stuckKey = `${agent.code_name}:${item.id}`;
|
|
@@ -5809,9 +5847,9 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
|
|
|
5809
5847
|
const h = hashFile(join6(agentDir, file));
|
|
5810
5848
|
if (h) hashes.set(file, h);
|
|
5811
5849
|
}
|
|
5812
|
-
writtenHashes.set(agent.agent_id, hashes);
|
|
5850
|
+
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
5813
5851
|
} else {
|
|
5814
|
-
writtenHashes.delete(agent.agent_id);
|
|
5852
|
+
agentState.writtenHashes.delete(agent.agent_id);
|
|
5815
5853
|
}
|
|
5816
5854
|
agentStates.push({
|
|
5817
5855
|
agentId: agent.agent_id,
|
|
@@ -5972,7 +6010,7 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
5972
6010
|
const resolvedModels = resolveModelChain(refreshData);
|
|
5973
6011
|
const modelsHash = createHash3("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
|
|
5974
6012
|
const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
|
|
5975
|
-
const prevHash = knownTasksHashes.get(agent.agent_id);
|
|
6013
|
+
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
5976
6014
|
if (combinedHash !== prevHash) {
|
|
5977
6015
|
const taskInputs = tasks.map((t) => ({
|
|
5978
6016
|
id: t.id,
|
|
@@ -5993,7 +6031,7 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
5993
6031
|
}));
|
|
5994
6032
|
const state6 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
|
|
5995
6033
|
claudeSchedulerStates.set(codeName, state6);
|
|
5996
|
-
knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
6034
|
+
agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
5997
6035
|
log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
|
|
5998
6036
|
}
|
|
5999
6037
|
if (!claudeSchedulerStates.has(codeName)) {
|
|
@@ -6416,7 +6454,6 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
6416
6454
|
log(`[claude-scheduler] Failed to post result for '${codeName}': ${err.message}`);
|
|
6417
6455
|
}
|
|
6418
6456
|
}
|
|
6419
|
-
var persistentSessionAgents = /* @__PURE__ */ new Set();
|
|
6420
6457
|
var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
|
|
6421
6458
|
var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
|
|
6422
6459
|
var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
|
|
@@ -6480,7 +6517,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
6480
6517
|
log(`[persistent-session] Failed to resolve auth for '${codeName}': ${msg} \u2014 refusing to spawn`);
|
|
6481
6518
|
if (isSessionHealthy(codeName)) {
|
|
6482
6519
|
stopPersistentSessionAndForgetMcpBaseline(codeName);
|
|
6483
|
-
persistentSessionAgents.delete(codeName);
|
|
6520
|
+
agentState.persistentSessionAgents.delete(codeName);
|
|
6484
6521
|
claudeAuthTupleBySession.delete(codeName);
|
|
6485
6522
|
}
|
|
6486
6523
|
return {
|
|
@@ -6517,7 +6554,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
6517
6554
|
if (recordedAuthTuple && recordedAuthTuple !== currentAuthTuple && isSessionHealthy(codeName)) {
|
|
6518
6555
|
log(`[persistent-session] Auth config changed for '${codeName}' (${recordedAuthTuple} \u2192 ${currentAuthTuple}) \u2014 restarting session`);
|
|
6519
6556
|
stopPersistentSessionAndForgetMcpBaseline(codeName, "auth-tuple-change");
|
|
6520
|
-
persistentSessionAgents.delete(codeName);
|
|
6557
|
+
agentState.persistentSessionAgents.delete(codeName);
|
|
6521
6558
|
restartTrigger = "auth-tuple";
|
|
6522
6559
|
}
|
|
6523
6560
|
if (isStaleForToday(codeName, /* @__PURE__ */ new Date(), agentTimezone) && isSessionHealthy(codeName)) {
|
|
@@ -6529,7 +6566,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
6529
6566
|
`[persistent-session] Day rollover for '${codeName}' (yesterday=${current.date}) \u2014 agent idle, restarting to mint fresh session`
|
|
6530
6567
|
);
|
|
6531
6568
|
stopPersistentSessionAndForgetMcpBaseline(codeName, "day-rollover");
|
|
6532
|
-
persistentSessionAgents.delete(codeName);
|
|
6569
|
+
agentState.persistentSessionAgents.delete(codeName);
|
|
6533
6570
|
restartTrigger = "day-rollover";
|
|
6534
6571
|
} else {
|
|
6535
6572
|
log(
|
|
@@ -6549,7 +6586,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
6549
6586
|
};
|
|
6550
6587
|
}
|
|
6551
6588
|
if (!isSessionHealthy(codeName)) {
|
|
6552
|
-
if (persistentSessionAgents.has(codeName)) {
|
|
6589
|
+
if (agentState.persistentSessionAgents.has(codeName)) {
|
|
6553
6590
|
const ctx = getLastFailureContext(codeName);
|
|
6554
6591
|
const recovery = prepareForRespawn(codeName);
|
|
6555
6592
|
const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
|
|
@@ -6623,7 +6660,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
6623
6660
|
agentTimezone,
|
|
6624
6661
|
log
|
|
6625
6662
|
});
|
|
6626
|
-
persistentSessionAgents.add(codeName);
|
|
6663
|
+
agentState.persistentSessionAgents.add(codeName);
|
|
6627
6664
|
claudeAuthTupleBySession.set(codeName, currentAuthTuple);
|
|
6628
6665
|
return {
|
|
6629
6666
|
decision: "spawn",
|
|
@@ -6637,7 +6674,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
6637
6674
|
claudeAuthTupleBySession.set(codeName, currentAuthTuple);
|
|
6638
6675
|
}
|
|
6639
6676
|
const stableTasksHash = createHash3("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
6640
|
-
const prevHash = knownTasksHashes.get(agent.agent_id);
|
|
6677
|
+
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
6641
6678
|
if (stableTasksHash !== prevHash) {
|
|
6642
6679
|
const taskInputs = tasks.map((t) => ({
|
|
6643
6680
|
id: t.id,
|
|
@@ -6658,7 +6695,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
6658
6695
|
}));
|
|
6659
6696
|
const schedulerState = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
|
|
6660
6697
|
claudeSchedulerStates.set(codeName, schedulerState);
|
|
6661
|
-
knownTasksHashes.set(agent.agent_id, stableTasksHash);
|
|
6698
|
+
agentState.knownTasksHashes.set(agent.agent_id, stableTasksHash);
|
|
6662
6699
|
log(`[persistent-session] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
|
|
6663
6700
|
} else if (!claudeSchedulerStates.has(codeName)) {
|
|
6664
6701
|
claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
|
|
@@ -6830,10 +6867,10 @@ function ensureRealtimeDriftStarted(agentStates) {
|
|
|
6830
6867
|
token: exchange.token,
|
|
6831
6868
|
agentIds: activeAgentIds,
|
|
6832
6869
|
onDrift: (doc) => {
|
|
6833
|
-
const
|
|
6834
|
-
if (
|
|
6835
|
-
knownVersions.delete(doc.agent_id);
|
|
6836
|
-
log(`[realtime] Drift invalidated for '${
|
|
6870
|
+
const agent = agentStates.find((a) => a.agentId === doc.agent_id);
|
|
6871
|
+
if (agent) {
|
|
6872
|
+
agentState.knownVersions.delete(doc.agent_id);
|
|
6873
|
+
log(`[realtime] Drift invalidated for '${agent.codeName}' \u2014 will re-provision next cycle`);
|
|
6837
6874
|
}
|
|
6838
6875
|
},
|
|
6839
6876
|
log
|
|
@@ -6885,7 +6922,7 @@ function ensureRealtimeConfigStarted(agentStates) {
|
|
|
6885
6922
|
token: exchange.token,
|
|
6886
6923
|
agentIds: activeAgentIds,
|
|
6887
6924
|
onConfigChange: (agent) => {
|
|
6888
|
-
knownStatuses.delete(agent.agent_id);
|
|
6925
|
+
agentState.knownStatuses.delete(agent.agent_id);
|
|
6889
6926
|
},
|
|
6890
6927
|
log
|
|
6891
6928
|
});
|
|
@@ -6985,9 +7022,9 @@ function ensureRealtimeIntegrationContextStarted(agentStates) {
|
|
|
6985
7022
|
onContextChange: (payload) => {
|
|
6986
7023
|
const agent = agentStates.find((a) => a.agentId === payload.agent_id);
|
|
6987
7024
|
if (agent) {
|
|
6988
|
-
for (const key of knownSkillHashes.keys()) {
|
|
7025
|
+
for (const key of agentState.knownSkillHashes.keys()) {
|
|
6989
7026
|
if (key.startsWith(`plugin-skill:${agent.agentId}:`)) {
|
|
6990
|
-
knownSkillHashes.delete(key);
|
|
7027
|
+
agentState.knownSkillHashes.delete(key);
|
|
6991
7028
|
}
|
|
6992
7029
|
}
|
|
6993
7030
|
}
|
|
@@ -7278,7 +7315,7 @@ async function harvestCronResults(codeName, tasks, gatewayPort) {
|
|
|
7278
7315
|
}
|
|
7279
7316
|
const latestRun = runs.filter((r) => r.action === "finished").sort((a, b) => b.ts - a.ts)[0];
|
|
7280
7317
|
if (latestRun) {
|
|
7281
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
7318
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
7282
7319
|
const summary = latestRun.summary ?? "";
|
|
7283
7320
|
const isKeyError = summary.includes("Key limit exceeded") || summary.includes("key limit") || summary.includes("rate limit") || summary.includes("insufficient_quota") || summary.includes("billing") || summary.includes("402");
|
|
7284
7321
|
if (agentId) {
|
|
@@ -7325,7 +7362,7 @@ async function harvestCronResults(codeName, tasks, gatewayPort) {
|
|
|
7325
7362
|
const planItems = parsePlanItems(summary);
|
|
7326
7363
|
if (planItems.length > 0) {
|
|
7327
7364
|
try {
|
|
7328
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
7365
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
7329
7366
|
if (agentId) {
|
|
7330
7367
|
await api.post("/host/kanban", {
|
|
7331
7368
|
agent_id: agentId,
|
|
@@ -7344,7 +7381,7 @@ async function harvestCronResults(codeName, tasks, gatewayPort) {
|
|
|
7344
7381
|
const kanbanUpdates = parseKanbanUpdates(summary);
|
|
7345
7382
|
if (kanbanUpdates.length > 0) {
|
|
7346
7383
|
try {
|
|
7347
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
7384
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
7348
7385
|
if (agentId) {
|
|
7349
7386
|
await api.post("/host/kanban", {
|
|
7350
7387
|
agent_id: agentId,
|
|
@@ -8074,7 +8111,7 @@ async function processClaudePairSessions(agents) {
|
|
|
8074
8111
|
killPairSession,
|
|
8075
8112
|
pairTmuxSession,
|
|
8076
8113
|
finalizeClaudePairOnboarding
|
|
8077
|
-
} = await import("../claude-pair-runtime-
|
|
8114
|
+
} = await import("../claude-pair-runtime-2NNAUBP3.js");
|
|
8078
8115
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
8079
8116
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
8080
8117
|
const killed = await killPairSession(pairTmuxSession(pairId));
|