@integrity-labs/agt-cli 0.26.1 → 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.
@@ -13,7 +13,7 @@ import {
13
13
  provisionOrientHook,
14
14
  provisionStopHook,
15
15
  requireHost
16
- } from "../chunk-UTPOHAX7.js";
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-QJJAGFJJ.js";
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-7NDNTSHD.js";
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
- knownVersions.delete(agentId);
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.0" : "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 agentState of agentStates) {
3985
- if (agentState.status !== "active" || !agentState.gatewayPort) continue;
3986
- const adapter = resolveAgentFramework(agentState.codeName);
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(agentState.codeName)) continue;
3989
- const status = await adapter.isGatewayRunning(agentState.codeName);
3990
- if (!status.running && agentState.gatewayRunning) {
3991
- const displayName = agentDisplayNames.get(agentState.codeName) ?? agentState.codeName;
3992
- log(`Gateway for '${agentState.codeName}' crashed, restarting...`);
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}* (\`${agentState.codeName}\`)
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(agentState.codeName, agentState.gatewayPort);
4000
- agentState.gatewayPid = result.pid;
4001
- agentState.gatewayRunning = true;
4002
- log(`Gateway restarted for '${agentState.codeName}' (PID ${result.pid})`);
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(agentState.codeName);
4006
- gatewayPool.addAgent(agentState.codeName, agentState.gatewayPort, token);
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}* (\`${agentState.codeName}\`)
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
- agentState.gatewayRunning = false;
4015
- log(`Failed to restart gateway for '${agentState.codeName}': ${err.message}`);
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}* (\`${agentState.codeName}\`)
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-E5EZ32CI.js");
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-MLUVAXJH.js");
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 agentState = agentStates.find((a) => a.agentId === doc.agent_id);
6834
- if (agentState) {
6835
- knownVersions.delete(doc.agent_id);
6836
- log(`[realtime] Drift invalidated for '${agentState.codeName}' \u2014 will re-provision next cycle`);
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-A35NZYDN.js");
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));