@integrity-labs/agt-cli 0.26.0 → 0.26.2-eng5706.0
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-LULDCIUS.js → chunk-QSDDP7JN.js} +17 -106
- package/dist/chunk-QSDDP7JN.js.map +1 -0
- package/dist/{chunk-YMIDZT5T.js → chunk-U3HCB23E.js} +157 -6
- package/dist/chunk-U3HCB23E.js.map +1 -0
- package/dist/{chunk-XG4X7BNT.js → chunk-WERKUMWY.js} +97 -5
- package/dist/chunk-WERKUMWY.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-7PHOEAUN.js → claude-pair-runtime-2NNAUBP3.js} +2 -2
- package/dist/lib/manager-worker.js +203 -144
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/index.js +5 -3
- package/dist/{persistent-session-3ITHPO4P.js → persistent-session-K4X76LLB.js} +4 -3
- package/dist/{responsiveness-probe-7XWORQLO.js → responsiveness-probe-QBV43SJ7.js} +4 -3
- package/dist/{responsiveness-probe-7XWORQLO.js.map → responsiveness-probe-QBV43SJ7.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-LULDCIUS.js.map +0 -1
- package/dist/chunk-XG4X7BNT.js.map +0 -1
- package/dist/chunk-YMIDZT5T.js.map +0 -1
- /package/dist/{claude-pair-runtime-7PHOEAUN.js.map → claude-pair-runtime-2NNAUBP3.js.map} +0 -0
- /package/dist/{persistent-session-3ITHPO4P.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-WERKUMWY.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) {
|
|
@@ -2962,7 +3020,14 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
|
|
|
2962
3020
|
auth_type: i.auth_type,
|
|
2963
3021
|
source_type: i.source_type ?? null,
|
|
2964
3022
|
credentials: i.credentials,
|
|
2965
|
-
last_connectivity_check_at: i.last_connectivity_check_at ?? null
|
|
3023
|
+
last_connectivity_check_at: i.last_connectivity_check_at ?? null,
|
|
3024
|
+
// ENG-5665: for managed (Composio) + mcp_server toolkits the connectivity
|
|
3025
|
+
// probe is an MCP `tools/list` against the agent's wired server. Derive the
|
|
3026
|
+
// .mcp.json server key the same way the managed-toolkit writer does
|
|
3027
|
+
// (definition_id === toolkit_id, sanitised: non-alnum → '_', lowercased —
|
|
3028
|
+
// e.g. 'composio_outlook'). The executor looks this up in .mcp.json; an
|
|
3029
|
+
// unresolvable key degrades to transient_error, never a false 'down'.
|
|
3030
|
+
mcp_server_key: i.source_type === "managed" || i.source_type === "mcp_server" ? i.definition_id.replace(/[^a-z0-9]/gi, "_").toLowerCase() : void 0
|
|
2966
3031
|
})),
|
|
2967
3032
|
{ probeDeps, intervalMs: intervalSec * 1e3 }
|
|
2968
3033
|
);
|
|
@@ -3038,13 +3103,6 @@ function checkMcpConfigDriftAndScheduleRestart(codeName, projectDir) {
|
|
|
3038
3103
|
}
|
|
3039
3104
|
}
|
|
3040
3105
|
}
|
|
3041
|
-
var knownChannelConfigHashes = /* @__PURE__ */ new Map();
|
|
3042
|
-
var knownModels = /* @__PURE__ */ new Map();
|
|
3043
|
-
var knownTasksHashes = /* @__PURE__ */ new Map();
|
|
3044
|
-
var knownIntegrationHashes = /* @__PURE__ */ new Map();
|
|
3045
|
-
var knownManagedMcpHashes = /* @__PURE__ */ new Map();
|
|
3046
|
-
var knownManagedMcpStructure = /* @__PURE__ */ new Map();
|
|
3047
|
-
var knownSkillHashes = /* @__PURE__ */ new Map();
|
|
3048
3106
|
var managedToolkitIdByAgentAndServerId = /* @__PURE__ */ new Map();
|
|
3049
3107
|
function managedToolkitMapKey(agentId, serverId) {
|
|
3050
3108
|
return `${agentId}\0${serverId}`;
|
|
@@ -3063,8 +3121,6 @@ var STALE_TASK_THRESHOLD_MS = (() => {
|
|
|
3063
3121
|
var alertSlackWebhook = null;
|
|
3064
3122
|
var alertedJobs = /* @__PURE__ */ new Set();
|
|
3065
3123
|
var taskDisplayInfo = /* @__PURE__ */ new Map();
|
|
3066
|
-
var agentDisplayNames = /* @__PURE__ */ new Map();
|
|
3067
|
-
var codeNameToAgentId = /* @__PURE__ */ new Map();
|
|
3068
3124
|
var agentChannelTokens = /* @__PURE__ */ new Map();
|
|
3069
3125
|
var activeChannels = /* @__PURE__ */ new Map();
|
|
3070
3126
|
var gatewaysStartedThisCycle = /* @__PURE__ */ new Set();
|
|
@@ -3086,18 +3142,7 @@ function resolveAgentFramework(codeName) {
|
|
|
3086
3142
|
}
|
|
3087
3143
|
var gatewayPool = null;
|
|
3088
3144
|
function clearAgentCaches(agentId, codeName) {
|
|
3089
|
-
|
|
3090
|
-
knownStatuses.delete(agentId);
|
|
3091
|
-
knownChannels.delete(agentId);
|
|
3092
|
-
writtenHashes.delete(agentId);
|
|
3093
|
-
knownSecretsHashes.delete(agentId);
|
|
3094
|
-
knownModels.delete(agentId);
|
|
3095
|
-
knownTasksHashes.delete(agentId);
|
|
3096
|
-
knownIntegrationHashes.delete(agentId);
|
|
3097
|
-
knownManagedMcpHashes.delete(agentId);
|
|
3098
|
-
knownManagedMcpStructure.delete(agentId);
|
|
3099
|
-
agentDisplayNames.delete(codeName);
|
|
3100
|
-
codeNameToAgentId.delete(codeName);
|
|
3145
|
+
const channelCacheMutated = clearAgentState(agentId, codeName);
|
|
3101
3146
|
agentFrameworkCache.delete(codeName);
|
|
3102
3147
|
kanbanBoardCache.delete(codeName);
|
|
3103
3148
|
lastHarvestAt.delete(codeName);
|
|
@@ -3107,26 +3152,16 @@ function clearAgentCaches(agentId, codeName) {
|
|
|
3107
3152
|
memoryFileHashes.delete(agentId);
|
|
3108
3153
|
lastDownloadHash.delete(agentId);
|
|
3109
3154
|
lastLocalFileHash.delete(agentId);
|
|
3110
|
-
let channelCacheMutated = false;
|
|
3111
|
-
for (const key of knownChannelConfigHashes.keys()) {
|
|
3112
|
-
if (key.startsWith(`${agentId}:`)) {
|
|
3113
|
-
knownChannelConfigHashes.delete(key);
|
|
3114
|
-
channelCacheMutated = true;
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3117
|
-
if (channelCacheMutated) saveChannelHashCache2();
|
|
3118
|
-
for (const key of knownSkillHashes.keys()) {
|
|
3119
|
-
if (key.startsWith(`${agentId}:`)) knownSkillHashes.delete(key);
|
|
3120
|
-
}
|
|
3121
3155
|
for (const key of taskDisplayInfo.keys()) {
|
|
3122
3156
|
if (key.startsWith(`${codeName}:`)) taskDisplayInfo.delete(key);
|
|
3123
3157
|
}
|
|
3158
|
+
if (channelCacheMutated) saveChannelHashCache2();
|
|
3124
3159
|
}
|
|
3125
3160
|
var cachedFrameworkVersion = null;
|
|
3126
3161
|
var lastVersionCheckAt = 0;
|
|
3127
3162
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
3128
3163
|
var lastResponsivenessProbeAt = 0;
|
|
3129
|
-
var agtCliVersion = true ? "0.26.0" : "dev";
|
|
3164
|
+
var agtCliVersion = true ? "0.26.2-eng5706.0" : "dev";
|
|
3130
3165
|
function resolveBrewPath(execFileSync4) {
|
|
3131
3166
|
try {
|
|
3132
3167
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -3640,10 +3675,10 @@ function channelHashCacheDir() {
|
|
|
3640
3675
|
return config?.configDir ?? join6(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
3641
3676
|
}
|
|
3642
3677
|
function loadChannelHashCache2() {
|
|
3643
|
-
loadChannelHashCache(knownChannelConfigHashes, channelHashCacheDir());
|
|
3678
|
+
loadChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
|
|
3644
3679
|
}
|
|
3645
3680
|
function saveChannelHashCache2() {
|
|
3646
|
-
saveChannelHashCache(knownChannelConfigHashes, channelHashCacheDir());
|
|
3681
|
+
saveChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
|
|
3647
3682
|
}
|
|
3648
3683
|
function send(msg) {
|
|
3649
3684
|
if (msg.type === "state-update") {
|
|
@@ -3974,40 +4009,40 @@ async function stopAllGateways() {
|
|
|
3974
4009
|
}
|
|
3975
4010
|
}
|
|
3976
4011
|
async function healthCheckGateways(agentStates) {
|
|
3977
|
-
for (const
|
|
3978
|
-
if (
|
|
3979
|
-
const adapter = resolveAgentFramework(
|
|
4012
|
+
for (const agent of agentStates) {
|
|
4013
|
+
if (agent.status !== "active" || !agent.gatewayPort) continue;
|
|
4014
|
+
const adapter = resolveAgentFramework(agent.codeName);
|
|
3980
4015
|
if (!adapter.isGatewayRunning || !adapter.startGateway) continue;
|
|
3981
|
-
if (gatewaysStartedThisCycle.has(
|
|
3982
|
-
const status = await adapter.isGatewayRunning(
|
|
3983
|
-
if (!status.running &&
|
|
3984
|
-
const displayName = agentDisplayNames.get(
|
|
3985
|
-
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...`);
|
|
3986
4021
|
sendSlackWebhookMessage(
|
|
3987
|
-
`:red_circle: *Host Down* \u2014 *${displayName}* (\`${
|
|
4022
|
+
`:red_circle: *Host Down* \u2014 *${displayName}* (\`${agent.codeName}\`)
|
|
3988
4023
|
OpenClaw gateway crashed. Attempting automatic restart...`
|
|
3989
4024
|
).catch(() => {
|
|
3990
4025
|
});
|
|
3991
4026
|
try {
|
|
3992
|
-
const result = await adapter.startGateway(
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
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})`);
|
|
3996
4031
|
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
3997
4032
|
if (gatewayPool) {
|
|
3998
|
-
const token = readGatewayToken(
|
|
3999
|
-
gatewayPool.addAgent(
|
|
4033
|
+
const token = readGatewayToken(agent.codeName);
|
|
4034
|
+
gatewayPool.addAgent(agent.codeName, agent.gatewayPort, token);
|
|
4000
4035
|
}
|
|
4001
4036
|
sendSlackWebhookMessage(
|
|
4002
|
-
`:large_green_circle: *Host Recovered* \u2014 *${displayName}* (\`${
|
|
4037
|
+
`:large_green_circle: *Host Recovered* \u2014 *${displayName}* (\`${agent.codeName}\`)
|
|
4003
4038
|
Gateway restarted successfully (PID ${result.pid}).`
|
|
4004
4039
|
).catch(() => {
|
|
4005
4040
|
});
|
|
4006
4041
|
} catch (err) {
|
|
4007
|
-
|
|
4008
|
-
log(`Failed to restart gateway for '${
|
|
4042
|
+
agent.gatewayRunning = false;
|
|
4043
|
+
log(`Failed to restart gateway for '${agent.codeName}': ${err.message}`);
|
|
4009
4044
|
sendSlackWebhookMessage(
|
|
4010
|
-
`:x: *Host Restart Failed* \u2014 *${displayName}* (\`${
|
|
4045
|
+
`:x: *Host Restart Failed* \u2014 *${displayName}* (\`${agent.codeName}\`)
|
|
4011
4046
|
Automatic restart failed: ${err.message}`
|
|
4012
4047
|
).catch(() => {
|
|
4013
4048
|
});
|
|
@@ -4025,7 +4060,7 @@ async function pollCycle() {
|
|
|
4025
4060
|
resolveFramework: (codeName) => agentFrameworkCache.get(codeName) ?? null,
|
|
4026
4061
|
stopSession: (codeName) => {
|
|
4027
4062
|
stopPersistentSessionAndForgetMcpBaseline(codeName, "channel-set-change");
|
|
4028
|
-
persistentSessionAgents.delete(codeName);
|
|
4063
|
+
agentState.persistentSessionAgents.delete(codeName);
|
|
4029
4064
|
claudeAuthTupleBySession.delete(codeName);
|
|
4030
4065
|
},
|
|
4031
4066
|
getTelegramTokens: (codeName) => {
|
|
@@ -4085,8 +4120,8 @@ async function pollCycle() {
|
|
|
4085
4120
|
}
|
|
4086
4121
|
try {
|
|
4087
4122
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
4088
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
4089
|
-
const diagCodeNames = [...persistentSessionAgents];
|
|
4123
|
+
const { collectDiagnostics } = await import("../persistent-session-K4X76LLB.js");
|
|
4124
|
+
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
4090
4125
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
4091
4126
|
let tailscaleHostname;
|
|
4092
4127
|
try {
|
|
@@ -4118,7 +4153,7 @@ async function pollCycle() {
|
|
|
4118
4153
|
const errId = createHash3("sha256").update(errText).digest("hex").slice(0, 12);
|
|
4119
4154
|
log(`Claude auth detection failed (error_id=${errId})`);
|
|
4120
4155
|
}
|
|
4121
|
-
await api.post("/host/heartbeat", {
|
|
4156
|
+
const hbResp = await api.post("/host/heartbeat", {
|
|
4122
4157
|
host_id: hostId,
|
|
4123
4158
|
framework_version: cachedFrameworkVersion ?? void 0,
|
|
4124
4159
|
agt_version: agtCliVersion,
|
|
@@ -4136,6 +4171,16 @@ async function pollCycle() {
|
|
|
4136
4171
|
// behind a fresh heartbeat.
|
|
4137
4172
|
realtime_socket_connected: isRealtimeSocketConnected()
|
|
4138
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
|
+
}
|
|
4139
4184
|
} catch (err) {
|
|
4140
4185
|
log(`Heartbeat failed: ${err.message}`);
|
|
4141
4186
|
}
|
|
@@ -4143,10 +4188,10 @@ async function pollCycle() {
|
|
|
4143
4188
|
const {
|
|
4144
4189
|
collectResponsivenessProbes,
|
|
4145
4190
|
getResponsivenessIntervalMs
|
|
4146
|
-
} = await import("../responsiveness-probe-
|
|
4191
|
+
} = await import("../responsiveness-probe-QBV43SJ7.js");
|
|
4147
4192
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
4148
4193
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
4149
|
-
const probeCodeNames = [...persistentSessionAgents];
|
|
4194
|
+
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
4150
4195
|
if (probeCodeNames.length > 0) {
|
|
4151
4196
|
const probes = collectResponsivenessProbes(probeCodeNames);
|
|
4152
4197
|
if (probes.length > 0) {
|
|
@@ -4164,8 +4209,8 @@ async function pollCycle() {
|
|
|
4164
4209
|
const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
|
|
4165
4210
|
const observations = [];
|
|
4166
4211
|
const pendingCacheCommits = [];
|
|
4167
|
-
for (const codeName of persistentSessionAgents) {
|
|
4168
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
4212
|
+
for (const codeName of agentState.persistentSessionAgents) {
|
|
4213
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
4169
4214
|
if (!agentId) continue;
|
|
4170
4215
|
const tail = readPaneLogTail(codeName, 40);
|
|
4171
4216
|
if (!tail) continue;
|
|
@@ -4185,7 +4230,7 @@ async function pollCycle() {
|
|
|
4185
4230
|
(resp?.results ?? []).filter((r) => r.ok).map((r) => r.agent_id)
|
|
4186
4231
|
);
|
|
4187
4232
|
for (const { codeName, count } of pendingCacheCommits) {
|
|
4188
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
4233
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
4189
4234
|
if (agentId && accepted.has(agentId)) {
|
|
4190
4235
|
lastMcpFailedBannerCount.set(codeName, count);
|
|
4191
4236
|
}
|
|
@@ -4416,9 +4461,9 @@ async function getOrCacheRegisteredAgents(adapter, profile) {
|
|
|
4416
4461
|
}
|
|
4417
4462
|
async function processAgent(agent, agentStates) {
|
|
4418
4463
|
if (!config) return;
|
|
4419
|
-
const previousKnownStatus = knownStatuses.get(agent.agent_id);
|
|
4420
|
-
agentDisplayNames.set(agent.code_name, agent.display_name);
|
|
4421
|
-
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);
|
|
4422
4467
|
maybeReportCurrentTrip(agent.code_name);
|
|
4423
4468
|
if (agent.framework) {
|
|
4424
4469
|
agentFrameworkCache.set(agent.code_name, agent.framework);
|
|
@@ -4468,7 +4513,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4468
4513
|
gatewayRunning: false,
|
|
4469
4514
|
acpSessions: []
|
|
4470
4515
|
});
|
|
4471
|
-
knownStatuses.set(agent.agent_id, agent.status);
|
|
4516
|
+
agentState.knownStatuses.set(agent.agent_id, agent.status);
|
|
4472
4517
|
return;
|
|
4473
4518
|
}
|
|
4474
4519
|
if (agent.status === "revoked") {
|
|
@@ -4515,7 +4560,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4515
4560
|
freePort(agent.code_name);
|
|
4516
4561
|
await cleanupAgentFiles(agent.code_name, agentDir);
|
|
4517
4562
|
clearAgentCaches(agent.agent_id, agent.code_name);
|
|
4518
|
-
knownStatuses.set(agent.agent_id, agent.status);
|
|
4563
|
+
agentState.knownStatuses.set(agent.agent_id, agent.status);
|
|
4519
4564
|
agentStates.push({
|
|
4520
4565
|
agentId: agent.agent_id,
|
|
4521
4566
|
codeName: agent.code_name,
|
|
@@ -4534,25 +4579,25 @@ async function processAgent(agent, agentStates) {
|
|
|
4534
4579
|
});
|
|
4535
4580
|
return;
|
|
4536
4581
|
}
|
|
4537
|
-
const previousStatus = knownStatuses.get(agent.agent_id);
|
|
4582
|
+
const previousStatus = agentState.knownStatuses.get(agent.agent_id);
|
|
4538
4583
|
if (previousStatus && previousStatus !== agent.status) {
|
|
4539
4584
|
log(`Agent '${agent.code_name}' status changed: ${previousStatus} \u2192 ${agent.status}`);
|
|
4540
|
-
knownVersions.delete(agent.agent_id);
|
|
4585
|
+
agentState.knownVersions.delete(agent.agent_id);
|
|
4541
4586
|
if (previousStatus === "paused" && agent.status === "active" && restartBreaker.isTripped(agent.code_name)) {
|
|
4542
4587
|
restartBreaker.clear(agent.code_name);
|
|
4543
4588
|
reportedTrips.delete(agent.code_name);
|
|
4544
4589
|
log(`[circuit-breaker] Cleared trip for '${agent.code_name}' on operator resume (paused \u2192 active)`);
|
|
4545
4590
|
}
|
|
4546
4591
|
let channelCacheMutated = false;
|
|
4547
|
-
for (const key of knownChannelConfigHashes.keys()) {
|
|
4592
|
+
for (const key of agentState.knownChannelConfigHashes.keys()) {
|
|
4548
4593
|
if (key.startsWith(`${agent.agent_id}:`)) {
|
|
4549
|
-
knownChannelConfigHashes.delete(key);
|
|
4594
|
+
agentState.knownChannelConfigHashes.delete(key);
|
|
4550
4595
|
channelCacheMutated = true;
|
|
4551
4596
|
}
|
|
4552
4597
|
}
|
|
4553
4598
|
if (channelCacheMutated) saveChannelHashCache2();
|
|
4554
4599
|
}
|
|
4555
|
-
knownStatuses.set(agent.agent_id, agent.status);
|
|
4600
|
+
agentState.knownStatuses.set(agent.agent_id, agent.status);
|
|
4556
4601
|
let refreshData;
|
|
4557
4602
|
try {
|
|
4558
4603
|
refreshData = await api.post("/host/refresh", {
|
|
@@ -4615,10 +4660,10 @@ async function processAgent(agent, agentStates) {
|
|
|
4615
4660
|
}
|
|
4616
4661
|
const charterVersion = refreshData.charter.version;
|
|
4617
4662
|
const toolsVersion = refreshData.tools.version;
|
|
4618
|
-
const known = knownVersions.get(agent.agent_id);
|
|
4663
|
+
const known = agentState.knownVersions.get(agent.agent_id);
|
|
4619
4664
|
let lastProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
|
|
4620
4665
|
const currentChannelIds = launchableChannelIds(refreshData.channel_configs);
|
|
4621
|
-
const previousChannelIds = knownChannels.get(agent.agent_id);
|
|
4666
|
+
const previousChannelIds = agentState.knownChannels.get(agent.agent_id);
|
|
4622
4667
|
const channelsChanged = !previousChannelIds || currentChannelIds.size !== previousChannelIds.size || [...currentChannelIds].some((ch) => !previousChannelIds.has(ch)) || [...previousChannelIds].some((ch) => !currentChannelIds.has(ch));
|
|
4623
4668
|
let channelConfigConverged = true;
|
|
4624
4669
|
if (previousChannelIds && channelsChanged && frameworkAdapter.removeChannelCredentials) {
|
|
@@ -4716,14 +4761,14 @@ async function processAgent(agent, agentStates) {
|
|
|
4716
4761
|
} catch {
|
|
4717
4762
|
}
|
|
4718
4763
|
lastProvisionAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4719
|
-
knownVersions.set(agent.agent_id, { charterVersion, toolsVersion });
|
|
4764
|
+
agentState.knownVersions.set(agent.agent_id, { charterVersion, toolsVersion });
|
|
4720
4765
|
const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
|
|
4721
4766
|
const hashes = /* @__PURE__ */ new Map();
|
|
4722
4767
|
for (const file of trackedFiles2) {
|
|
4723
4768
|
const h = hashFile(join6(agentDir, file));
|
|
4724
4769
|
if (h) hashes.set(file, h);
|
|
4725
4770
|
}
|
|
4726
|
-
writtenHashes.set(agent.agent_id, hashes);
|
|
4771
|
+
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
4727
4772
|
const resolvedModelsForRegistration = resolveModelChain(refreshData);
|
|
4728
4773
|
const primaryModel2 = resolvedModelsForRegistration.primary ?? refreshData.agent.primary_model;
|
|
4729
4774
|
const registeredAgents = await getOrCacheRegisteredAgents(frameworkAdapter, agent.code_name);
|
|
@@ -4745,7 +4790,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4745
4790
|
const resolvedForModel = resolveModelChain(refreshData);
|
|
4746
4791
|
const primaryModel = resolvedForModel.primary ?? refreshData.agent.primary_model;
|
|
4747
4792
|
if (primaryModel && frameworkAdapter.updateAgentModel) {
|
|
4748
|
-
const previousModel = knownModels.get(agent.agent_id);
|
|
4793
|
+
const previousModel = agentState.knownModels.get(agent.agent_id);
|
|
4749
4794
|
if (previousModel !== primaryModel) {
|
|
4750
4795
|
try {
|
|
4751
4796
|
const updated = await frameworkAdapter.updateAgentModel(agent.code_name, primaryModel);
|
|
@@ -4781,10 +4826,10 @@ async function processAgent(agent, agentStates) {
|
|
|
4781
4826
|
scheduleSessionRestart(agent.code_name, delay, "model change", "model-change");
|
|
4782
4827
|
}
|
|
4783
4828
|
}
|
|
4784
|
-
knownModels.set(agent.agent_id, primaryModel);
|
|
4829
|
+
agentState.knownModels.set(agent.agent_id, primaryModel);
|
|
4785
4830
|
}
|
|
4786
4831
|
let lastDriftCheckAt = now;
|
|
4787
|
-
const written = writtenHashes.get(agent.agent_id);
|
|
4832
|
+
const written = agentState.writtenHashes.get(agent.agent_id);
|
|
4788
4833
|
if (written && existsSync4(agentDir)) {
|
|
4789
4834
|
const driftedFiles = [];
|
|
4790
4835
|
for (const [file, expectedHash] of written) {
|
|
@@ -4881,14 +4926,14 @@ async function processAgent(agent, agentStates) {
|
|
|
4881
4926
|
log(`hasChannelCredentials failed for '${agent.code_name}/${channelId}': ${err.message} \u2014 forcing credential rewrite`);
|
|
4882
4927
|
onDiskPresent = false;
|
|
4883
4928
|
}
|
|
4884
|
-
if (knownChannelConfigHashes.get(cacheKey) === configHash && onDiskPresent) {
|
|
4929
|
+
if (agentState.knownChannelConfigHashes.get(cacheKey) === configHash && onDiskPresent) {
|
|
4885
4930
|
continue;
|
|
4886
4931
|
}
|
|
4887
|
-
const prevHash = knownChannelConfigHashes.get(cacheKey);
|
|
4932
|
+
const prevHash = agentState.knownChannelConfigHashes.get(cacheKey);
|
|
4888
4933
|
const reason = !prevHash ? "first-write" : !onDiskPresent ? "on-disk-missing" : "content-changed";
|
|
4889
4934
|
if (!onDiskPresent && prevHash) {
|
|
4890
4935
|
log(`Cached hash for '${agent.code_name}/${channelId}' but on-disk entry missing \u2014 re-writing credentials`);
|
|
4891
|
-
knownChannelConfigHashes.delete(cacheKey);
|
|
4936
|
+
agentState.knownChannelConfigHashes.delete(cacheKey);
|
|
4892
4937
|
}
|
|
4893
4938
|
try {
|
|
4894
4939
|
const sessionMode2 = refreshData.agent.session_mode;
|
|
@@ -4910,7 +4955,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4910
4955
|
agentTimezone
|
|
4911
4956
|
}
|
|
4912
4957
|
);
|
|
4913
|
-
knownChannelConfigHashes.set(cacheKey, configHash);
|
|
4958
|
+
agentState.knownChannelConfigHashes.set(cacheKey, configHash);
|
|
4914
4959
|
saveChannelHashCache2();
|
|
4915
4960
|
log(`Channel credentials written for '${agent.code_name}/${channelId}' (reason=${reason}, hash=${configHash.slice(0, 8)}${prevHash ? `, prev=${prevHash.slice(0, 8)}` : ""})`);
|
|
4916
4961
|
} catch (err) {
|
|
@@ -4928,7 +4973,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4928
4973
|
}
|
|
4929
4974
|
}
|
|
4930
4975
|
if (channelConfigConverged) {
|
|
4931
|
-
knownChannels.set(agent.agent_id, currentChannelIds);
|
|
4976
|
+
agentState.knownChannels.set(agent.agent_id, currentChannelIds);
|
|
4932
4977
|
} else {
|
|
4933
4978
|
log(`[channels] Credential sync did not converge for '${agent.code_name}' \u2014 leaving diff live for next tick retry`);
|
|
4934
4979
|
}
|
|
@@ -5002,7 +5047,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5002
5047
|
}
|
|
5003
5048
|
}
|
|
5004
5049
|
let lastSecretsProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
|
|
5005
|
-
let secretsHash = knownSecretsHashes.get(agent.agent_id) ?? null;
|
|
5050
|
+
let secretsHash = agentState.knownSecretsHashes.get(agent.agent_id) ?? null;
|
|
5006
5051
|
try {
|
|
5007
5052
|
const secretsData = await api.post("/host/secrets", { agent_id: agent.agent_id });
|
|
5008
5053
|
const newHash = secretsData.secrets_hash;
|
|
@@ -5013,10 +5058,10 @@ async function processAgent(agent, agentStates) {
|
|
|
5013
5058
|
log(`Secrets updated for '${agent.code_name}'`);
|
|
5014
5059
|
}
|
|
5015
5060
|
if (newHash) {
|
|
5016
|
-
knownSecretsHashes.set(agent.agent_id, newHash);
|
|
5061
|
+
agentState.knownSecretsHashes.set(agent.agent_id, newHash);
|
|
5017
5062
|
secretsHash = newHash;
|
|
5018
5063
|
} else {
|
|
5019
|
-
knownSecretsHashes.delete(agent.agent_id);
|
|
5064
|
+
agentState.knownSecretsHashes.delete(agent.agent_id);
|
|
5020
5065
|
secretsHash = null;
|
|
5021
5066
|
}
|
|
5022
5067
|
} catch (err) {
|
|
@@ -5063,7 +5108,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5063
5108
|
}
|
|
5064
5109
|
if (integrations.length > 0) {
|
|
5065
5110
|
const intHash = computeIntegrationsHash(integrations);
|
|
5066
|
-
const prevIntHash = knownIntegrationHashes.get(agent.agent_id);
|
|
5111
|
+
const prevIntHash = agentState.knownIntegrationHashes.get(agent.agent_id);
|
|
5067
5112
|
if (intHash !== prevIntHash) {
|
|
5068
5113
|
const projectDir = join6(homedir4(), ".augmented", agent.code_name, "project");
|
|
5069
5114
|
const envIntPath = join6(projectDir, ".env.integrations");
|
|
@@ -5108,7 +5153,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5108
5153
|
}
|
|
5109
5154
|
}
|
|
5110
5155
|
if (rotationHandled) {
|
|
5111
|
-
knownIntegrationHashes.set(agent.agent_id, intHash);
|
|
5156
|
+
agentState.knownIntegrationHashes.set(agent.agent_id, intHash);
|
|
5112
5157
|
}
|
|
5113
5158
|
needsGatewayRestart = true;
|
|
5114
5159
|
}
|
|
@@ -5138,9 +5183,9 @@ async function processAgent(agent, agentStates) {
|
|
|
5138
5183
|
return `${e.serverId}|${e.url}|${headersHash}`;
|
|
5139
5184
|
}).join("\n");
|
|
5140
5185
|
const mcpHash = createHash3("sha256").update(hashBasis).digest("hex").slice(0, 16);
|
|
5141
|
-
const prevMcpHash = knownManagedMcpHashes.get(agent.agent_id);
|
|
5186
|
+
const prevMcpHash = agentState.knownManagedMcpHashes.get(agent.agent_id);
|
|
5142
5187
|
const structureHash = managedMcpStructureHash(desiredEntries);
|
|
5143
|
-
const prevStructureHash = knownManagedMcpStructure.get(agent.agent_id);
|
|
5188
|
+
const prevStructureHash = agentState.knownManagedMcpStructure.get(agent.agent_id);
|
|
5144
5189
|
if (mcpHash !== prevMcpHash) {
|
|
5145
5190
|
for (const e of desiredEntries) {
|
|
5146
5191
|
frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
|
|
@@ -5177,8 +5222,8 @@ async function processAgent(agent, agentStates) {
|
|
|
5177
5222
|
}
|
|
5178
5223
|
}
|
|
5179
5224
|
}
|
|
5180
|
-
knownManagedMcpHashes.set(agent.agent_id, mcpHash);
|
|
5181
|
-
knownManagedMcpStructure.set(agent.agent_id, structureHash);
|
|
5225
|
+
agentState.knownManagedMcpHashes.set(agent.agent_id, mcpHash);
|
|
5226
|
+
agentState.knownManagedMcpStructure.set(agent.agent_id, structureHash);
|
|
5182
5227
|
if (prevStructureHash !== void 0 && structureHash !== prevStructureHash && fwForMcp === "claude-code" && isSessionHealthy(agent.code_name)) {
|
|
5183
5228
|
const mcpNames = agentToolkits.map((tk) => tk.toolkit_name).join(", ") || "none (all removed)";
|
|
5184
5229
|
log(`[hot-reload] MCP servers changed for '${agent.code_name}': ${mcpNames} \u2014 restarting session`);
|
|
@@ -5304,9 +5349,9 @@ async function processAgent(agent, agentStates) {
|
|
|
5304
5349
|
const bundle = buildIntegrationBundle(renderedScopes);
|
|
5305
5350
|
const contentHash = createHash4("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
|
|
5306
5351
|
const hashKey = `plugin-skill:${agent.agent_id}:${integrationSkillId}`;
|
|
5307
|
-
if (knownSkillHashes.get(hashKey) === contentHash) continue;
|
|
5352
|
+
if (agentState.knownSkillHashes.get(hashKey) === contentHash) continue;
|
|
5308
5353
|
frameworkAdapter.installSkillFiles(agent.code_name, integrationSkillId, bundle.files);
|
|
5309
|
-
knownSkillHashes.set(hashKey, contentHash);
|
|
5354
|
+
agentState.knownSkillHashes.set(hashKey, contentHash);
|
|
5310
5355
|
for (const s of scopes) installedIntegrationSkills.push(s.skill_name);
|
|
5311
5356
|
log(`Installed integration skill bundle '${integrationSkillId}' for '${agent.code_name}' (${scopes.length} scope(s))`);
|
|
5312
5357
|
} catch (err) {
|
|
@@ -5373,7 +5418,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5373
5418
|
try {
|
|
5374
5419
|
const scriptHash = createHash4("sha256").update(hook.script).digest("hex").slice(0, 12);
|
|
5375
5420
|
const hookKey = `${agent.agent_id}:${frameworkAdapter.id}:plugin-hook:${slug}:on_install`;
|
|
5376
|
-
if (knownSkillHashes.get(hookKey) === scriptHash) continue;
|
|
5421
|
+
if (agentState.knownSkillHashes.get(hookKey) === scriptHash) continue;
|
|
5377
5422
|
const result = await frameworkAdapter.executePluginHook({
|
|
5378
5423
|
codeName: agent.code_name,
|
|
5379
5424
|
pluginSlug: slug,
|
|
@@ -5381,7 +5426,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5381
5426
|
script: hook.script
|
|
5382
5427
|
});
|
|
5383
5428
|
if (result.exitCode === 0) {
|
|
5384
|
-
knownSkillHashes.set(hookKey, scriptHash);
|
|
5429
|
+
agentState.knownSkillHashes.set(hookKey, scriptHash);
|
|
5385
5430
|
log(`Integration hook on_install '${slug}' succeeded for '${agent.code_name}' (${result.durationMs}ms)`);
|
|
5386
5431
|
} else if (result.timedOut) {
|
|
5387
5432
|
log(`Integration hook on_install '${slug}' TIMED OUT for '${agent.code_name}' after ${result.durationMs}ms`);
|
|
@@ -5589,7 +5634,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5589
5634
|
const resolvedModels = resolveModelChain(refreshData);
|
|
5590
5635
|
const modelsHash = createHash3("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
|
|
5591
5636
|
const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
|
|
5592
|
-
const prevTasksHash = knownTasksHashes.get(agent.agent_id);
|
|
5637
|
+
const prevTasksHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
5593
5638
|
if (combinedHash !== prevTasksHash) {
|
|
5594
5639
|
const enrichedTasks = tasks.map((t) => {
|
|
5595
5640
|
if (BOARD_INJECT_TEMPLATES.has(t.template_id) && boardItems.length > 0) {
|
|
@@ -5626,7 +5671,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5626
5671
|
models: resolvedModels
|
|
5627
5672
|
}
|
|
5628
5673
|
);
|
|
5629
|
-
knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
5674
|
+
agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
5630
5675
|
log(`Scheduled tasks synced for '${agent.code_name}' (${enrichedTasks.length} task(s))`);
|
|
5631
5676
|
} catch (err) {
|
|
5632
5677
|
log(`Failed to sync scheduled tasks for '${agent.code_name}': ${err.message}`);
|
|
@@ -5695,7 +5740,7 @@ async function processAgent(agent, agentStates) {
|
|
|
5695
5740
|
cleanupStaleSessions(agent.code_name);
|
|
5696
5741
|
}
|
|
5697
5742
|
{
|
|
5698
|
-
const agentId = codeNameToAgentId.get(agent.code_name);
|
|
5743
|
+
const agentId = agentState.codeNameToAgentId.get(agent.code_name);
|
|
5699
5744
|
if (agentId) {
|
|
5700
5745
|
try {
|
|
5701
5746
|
const boardData = await api.post("/host/my-kanban", { agent_id: agentId });
|
|
@@ -5711,16 +5756,11 @@ async function processAgent(agent, agentStates) {
|
|
|
5711
5756
|
);
|
|
5712
5757
|
log(`[${agent.code_name}] Board diff: ${previousDoneIds.size} prev done \u2192 ${freshDoneIds.size} now, ${newlyDone.length} newly done`);
|
|
5713
5758
|
if (newlyDone.length > 0) {
|
|
5714
|
-
const displayName = agentDisplayNames.get(agent.code_name) ?? agent.code_name;
|
|
5759
|
+
const displayName = agentState.agentDisplayNames.get(agent.code_name) ?? agent.code_name;
|
|
5715
5760
|
for (const item of newlyDone) {
|
|
5716
5761
|
log(`Newly done: '${item.title}' notify_channel=${item.notify_channel ?? "none"} notify_to=${item.notify_to ?? "none"}`);
|
|
5717
5762
|
if (item.notify_channel && item.notify_to) {
|
|
5718
|
-
const
|
|
5719
|
-
const resultLine = item.result ? `
|
|
5720
|
-
${isFailed ? "Reason" : "Result"}: ${item.result}` : "";
|
|
5721
|
-
const emoji = isFailed ? "\u274C" : "\u2705";
|
|
5722
|
-
const message = `${emoji} ${isFailed ? "Task Failed" : "Task Complete"} \u2014 ${displayName}
|
|
5723
|
-
${item.title}${resultLine}`;
|
|
5763
|
+
const message = await buildDoneCardNotification(agentId, agent.code_name, displayName, item);
|
|
5724
5764
|
sendTaskNotification(agent.code_name, item.notify_channel, item.notify_to, message).catch((err) => {
|
|
5725
5765
|
log(`sendTaskNotification failed for '${agent.code_name}': ${err.message}`);
|
|
5726
5766
|
});
|
|
@@ -5734,7 +5774,7 @@ ${item.title}${resultLine}`;
|
|
|
5734
5774
|
return age > STALE_TASK_THRESHOLD_MS && !alertedStaleItems.has(`${agent.code_name}:${b.id}`);
|
|
5735
5775
|
});
|
|
5736
5776
|
if (staleItems.length > 0) {
|
|
5737
|
-
const displayName = agentDisplayNames.get(agent.code_name) ?? agent.code_name;
|
|
5777
|
+
const displayName = agentState.agentDisplayNames.get(agent.code_name) ?? agent.code_name;
|
|
5738
5778
|
for (const item of staleItems) {
|
|
5739
5779
|
const age = Math.round((Date.now() - new Date(item.updated_at).getTime()) / 6e4);
|
|
5740
5780
|
const stuckKey = `${agent.code_name}:${item.id}`;
|
|
@@ -5807,9 +5847,9 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
|
|
|
5807
5847
|
const h = hashFile(join6(agentDir, file));
|
|
5808
5848
|
if (h) hashes.set(file, h);
|
|
5809
5849
|
}
|
|
5810
|
-
writtenHashes.set(agent.agent_id, hashes);
|
|
5850
|
+
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
5811
5851
|
} else {
|
|
5812
|
-
writtenHashes.delete(agent.agent_id);
|
|
5852
|
+
agentState.writtenHashes.delete(agent.agent_id);
|
|
5813
5853
|
}
|
|
5814
5854
|
agentStates.push({
|
|
5815
5855
|
agentId: agent.agent_id,
|
|
@@ -5970,7 +6010,7 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
5970
6010
|
const resolvedModels = resolveModelChain(refreshData);
|
|
5971
6011
|
const modelsHash = createHash3("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
|
|
5972
6012
|
const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
|
|
5973
|
-
const prevHash = knownTasksHashes.get(agent.agent_id);
|
|
6013
|
+
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
5974
6014
|
if (combinedHash !== prevHash) {
|
|
5975
6015
|
const taskInputs = tasks.map((t) => ({
|
|
5976
6016
|
id: t.id,
|
|
@@ -5991,7 +6031,7 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
5991
6031
|
}));
|
|
5992
6032
|
const state6 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
|
|
5993
6033
|
claudeSchedulerStates.set(codeName, state6);
|
|
5994
|
-
knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
6034
|
+
agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
5995
6035
|
log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
|
|
5996
6036
|
}
|
|
5997
6037
|
if (!claudeSchedulerStates.has(codeName)) {
|
|
@@ -6414,7 +6454,6 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
6414
6454
|
log(`[claude-scheduler] Failed to post result for '${codeName}': ${err.message}`);
|
|
6415
6455
|
}
|
|
6416
6456
|
}
|
|
6417
|
-
var persistentSessionAgents = /* @__PURE__ */ new Set();
|
|
6418
6457
|
var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
|
|
6419
6458
|
var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
|
|
6420
6459
|
var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
|
|
@@ -6478,7 +6517,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
6478
6517
|
log(`[persistent-session] Failed to resolve auth for '${codeName}': ${msg} \u2014 refusing to spawn`);
|
|
6479
6518
|
if (isSessionHealthy(codeName)) {
|
|
6480
6519
|
stopPersistentSessionAndForgetMcpBaseline(codeName);
|
|
6481
|
-
persistentSessionAgents.delete(codeName);
|
|
6520
|
+
agentState.persistentSessionAgents.delete(codeName);
|
|
6482
6521
|
claudeAuthTupleBySession.delete(codeName);
|
|
6483
6522
|
}
|
|
6484
6523
|
return {
|
|
@@ -6515,7 +6554,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
6515
6554
|
if (recordedAuthTuple && recordedAuthTuple !== currentAuthTuple && isSessionHealthy(codeName)) {
|
|
6516
6555
|
log(`[persistent-session] Auth config changed for '${codeName}' (${recordedAuthTuple} \u2192 ${currentAuthTuple}) \u2014 restarting session`);
|
|
6517
6556
|
stopPersistentSessionAndForgetMcpBaseline(codeName, "auth-tuple-change");
|
|
6518
|
-
persistentSessionAgents.delete(codeName);
|
|
6557
|
+
agentState.persistentSessionAgents.delete(codeName);
|
|
6519
6558
|
restartTrigger = "auth-tuple";
|
|
6520
6559
|
}
|
|
6521
6560
|
if (isStaleForToday(codeName, /* @__PURE__ */ new Date(), agentTimezone) && isSessionHealthy(codeName)) {
|
|
@@ -6527,7 +6566,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
6527
6566
|
`[persistent-session] Day rollover for '${codeName}' (yesterday=${current.date}) \u2014 agent idle, restarting to mint fresh session`
|
|
6528
6567
|
);
|
|
6529
6568
|
stopPersistentSessionAndForgetMcpBaseline(codeName, "day-rollover");
|
|
6530
|
-
persistentSessionAgents.delete(codeName);
|
|
6569
|
+
agentState.persistentSessionAgents.delete(codeName);
|
|
6531
6570
|
restartTrigger = "day-rollover";
|
|
6532
6571
|
} else {
|
|
6533
6572
|
log(
|
|
@@ -6547,7 +6586,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
6547
6586
|
};
|
|
6548
6587
|
}
|
|
6549
6588
|
if (!isSessionHealthy(codeName)) {
|
|
6550
|
-
if (persistentSessionAgents.has(codeName)) {
|
|
6589
|
+
if (agentState.persistentSessionAgents.has(codeName)) {
|
|
6551
6590
|
const ctx = getLastFailureContext(codeName);
|
|
6552
6591
|
const recovery = prepareForRespawn(codeName);
|
|
6553
6592
|
const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
|
|
@@ -6621,7 +6660,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
6621
6660
|
agentTimezone,
|
|
6622
6661
|
log
|
|
6623
6662
|
});
|
|
6624
|
-
persistentSessionAgents.add(codeName);
|
|
6663
|
+
agentState.persistentSessionAgents.add(codeName);
|
|
6625
6664
|
claudeAuthTupleBySession.set(codeName, currentAuthTuple);
|
|
6626
6665
|
return {
|
|
6627
6666
|
decision: "spawn",
|
|
@@ -6635,7 +6674,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
6635
6674
|
claudeAuthTupleBySession.set(codeName, currentAuthTuple);
|
|
6636
6675
|
}
|
|
6637
6676
|
const stableTasksHash = createHash3("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
6638
|
-
const prevHash = knownTasksHashes.get(agent.agent_id);
|
|
6677
|
+
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
6639
6678
|
if (stableTasksHash !== prevHash) {
|
|
6640
6679
|
const taskInputs = tasks.map((t) => ({
|
|
6641
6680
|
id: t.id,
|
|
@@ -6656,7 +6695,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
6656
6695
|
}));
|
|
6657
6696
|
const schedulerState = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
|
|
6658
6697
|
claudeSchedulerStates.set(codeName, schedulerState);
|
|
6659
|
-
knownTasksHashes.set(agent.agent_id, stableTasksHash);
|
|
6698
|
+
agentState.knownTasksHashes.set(agent.agent_id, stableTasksHash);
|
|
6660
6699
|
log(`[persistent-session] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
|
|
6661
6700
|
} else if (!claudeSchedulerStates.has(codeName)) {
|
|
6662
6701
|
claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
|
|
@@ -6828,10 +6867,10 @@ function ensureRealtimeDriftStarted(agentStates) {
|
|
|
6828
6867
|
token: exchange.token,
|
|
6829
6868
|
agentIds: activeAgentIds,
|
|
6830
6869
|
onDrift: (doc) => {
|
|
6831
|
-
const
|
|
6832
|
-
if (
|
|
6833
|
-
knownVersions.delete(doc.agent_id);
|
|
6834
|
-
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`);
|
|
6835
6874
|
}
|
|
6836
6875
|
},
|
|
6837
6876
|
log
|
|
@@ -6883,7 +6922,7 @@ function ensureRealtimeConfigStarted(agentStates) {
|
|
|
6883
6922
|
token: exchange.token,
|
|
6884
6923
|
agentIds: activeAgentIds,
|
|
6885
6924
|
onConfigChange: (agent) => {
|
|
6886
|
-
knownStatuses.delete(agent.agent_id);
|
|
6925
|
+
agentState.knownStatuses.delete(agent.agent_id);
|
|
6887
6926
|
},
|
|
6888
6927
|
log
|
|
6889
6928
|
});
|
|
@@ -6983,9 +7022,9 @@ function ensureRealtimeIntegrationContextStarted(agentStates) {
|
|
|
6983
7022
|
onContextChange: (payload) => {
|
|
6984
7023
|
const agent = agentStates.find((a) => a.agentId === payload.agent_id);
|
|
6985
7024
|
if (agent) {
|
|
6986
|
-
for (const key of knownSkillHashes.keys()) {
|
|
7025
|
+
for (const key of agentState.knownSkillHashes.keys()) {
|
|
6987
7026
|
if (key.startsWith(`plugin-skill:${agent.agentId}:`)) {
|
|
6988
|
-
knownSkillHashes.delete(key);
|
|
7027
|
+
agentState.knownSkillHashes.delete(key);
|
|
6989
7028
|
}
|
|
6990
7029
|
}
|
|
6991
7030
|
}
|
|
@@ -7242,6 +7281,7 @@ var lastHarvestAt = /* @__PURE__ */ new Map();
|
|
|
7242
7281
|
var HARVEST_INTERVAL_MS = 3 * 60 * 1e3;
|
|
7243
7282
|
var kanbanBoardCache = /* @__PURE__ */ new Map();
|
|
7244
7283
|
var notifyBoardCache = /* @__PURE__ */ new Map();
|
|
7284
|
+
var NOTIFY_RESULT_MAX_CHARS = 3500;
|
|
7245
7285
|
async function harvestCronResults(codeName, tasks, gatewayPort) {
|
|
7246
7286
|
const token = readGatewayToken(codeName);
|
|
7247
7287
|
const gwArgs = ["--url", `ws://127.0.0.1:${gatewayPort}`, ...token ? ["--token", token] : []];
|
|
@@ -7275,7 +7315,7 @@ async function harvestCronResults(codeName, tasks, gatewayPort) {
|
|
|
7275
7315
|
}
|
|
7276
7316
|
const latestRun = runs.filter((r) => r.action === "finished").sort((a, b) => b.ts - a.ts)[0];
|
|
7277
7317
|
if (latestRun) {
|
|
7278
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
7318
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
7279
7319
|
const summary = latestRun.summary ?? "";
|
|
7280
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");
|
|
7281
7321
|
if (agentId) {
|
|
@@ -7322,7 +7362,7 @@ async function harvestCronResults(codeName, tasks, gatewayPort) {
|
|
|
7322
7362
|
const planItems = parsePlanItems(summary);
|
|
7323
7363
|
if (planItems.length > 0) {
|
|
7324
7364
|
try {
|
|
7325
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
7365
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
7326
7366
|
if (agentId) {
|
|
7327
7367
|
await api.post("/host/kanban", {
|
|
7328
7368
|
agent_id: agentId,
|
|
@@ -7341,7 +7381,7 @@ async function harvestCronResults(codeName, tasks, gatewayPort) {
|
|
|
7341
7381
|
const kanbanUpdates = parseKanbanUpdates(summary);
|
|
7342
7382
|
if (kanbanUpdates.length > 0) {
|
|
7343
7383
|
try {
|
|
7344
|
-
const agentId = codeNameToAgentId.get(codeName);
|
|
7384
|
+
const agentId = agentState.codeNameToAgentId.get(codeName);
|
|
7345
7385
|
if (agentId) {
|
|
7346
7386
|
await api.post("/host/kanban", {
|
|
7347
7387
|
agent_id: agentId,
|
|
@@ -8071,7 +8111,7 @@ async function processClaudePairSessions(agents) {
|
|
|
8071
8111
|
killPairSession,
|
|
8072
8112
|
pairTmuxSession,
|
|
8073
8113
|
finalizeClaudePairOnboarding
|
|
8074
|
-
} = await import("../claude-pair-runtime-
|
|
8114
|
+
} = await import("../claude-pair-runtime-2NNAUBP3.js");
|
|
8075
8115
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
8076
8116
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
8077
8117
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -8190,6 +8230,24 @@ async function maybePostScheduledTaskRatingPrompt(agentId, taskId, channelId, me
|
|
|
8190
8230
|
log(`[rating-prompt] Failed to post rating prompt for ${agentId}/${taskId}: ${err.message}`);
|
|
8191
8231
|
}
|
|
8192
8232
|
}
|
|
8233
|
+
async function buildDoneCardNotification(agentId, codeName, displayName, item) {
|
|
8234
|
+
const isFailed = item.status === "failed";
|
|
8235
|
+
let resultBody = item.result ?? "";
|
|
8236
|
+
try {
|
|
8237
|
+
const full = await api.post("/host/kanban-item", {
|
|
8238
|
+
agent_id: agentId,
|
|
8239
|
+
item_id: item.id
|
|
8240
|
+
});
|
|
8241
|
+
if (full.item?.result) resultBody = full.item.result;
|
|
8242
|
+
} catch (err) {
|
|
8243
|
+
log(`[notify] full-result fetch failed for card ${item.id} on '${codeName}': ${err.message} \u2014 using truncated board result`);
|
|
8244
|
+
}
|
|
8245
|
+
const resultLine = resultBody ? `
|
|
8246
|
+
${isFailed ? "Reason" : "Result"}: ${resultBody.slice(0, NOTIFY_RESULT_MAX_CHARS)}` : "";
|
|
8247
|
+
const emoji = isFailed ? "\u274C" : "\u2705";
|
|
8248
|
+
return `${emoji} ${isFailed ? "Task Failed" : "Task Complete"} \u2014 ${displayName}
|
|
8249
|
+
${item.title}${resultLine}`;
|
|
8250
|
+
}
|
|
8193
8251
|
async function sendTaskNotification(agentCodeName, channel, to, text) {
|
|
8194
8252
|
const tokens = agentChannelTokens.get(agentCodeName);
|
|
8195
8253
|
if (channel === "slack") {
|
|
@@ -8841,6 +8899,7 @@ export {
|
|
|
8841
8899
|
ChildProcessError,
|
|
8842
8900
|
__resetScheduledDeliveryDedupeForTest,
|
|
8843
8901
|
applyRestartAcks,
|
|
8902
|
+
buildDoneCardNotification,
|
|
8844
8903
|
claudeCodeUpgradeMarkerPath,
|
|
8845
8904
|
claudeCodeUpgradeThrottled,
|
|
8846
8905
|
deliverScheduledCardResult,
|