@integrity-labs/agt-cli 0.28.170 → 0.28.172

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.
@@ -28,7 +28,7 @@ import {
28
28
  requireHost,
29
29
  safeWriteJsonAtomic,
30
30
  setConfigHash
31
- } from "../chunk-ZLEYBDHR.js";
31
+ } from "../chunk-XGTHOGKA.js";
32
32
  import {
33
33
  getProjectDir as getProjectDir2,
34
34
  getReadyTasks,
@@ -70,7 +70,7 @@ import {
70
70
  takeZombieDetection,
71
71
  transcriptActivityAgeSeconds,
72
72
  writeEgressAllowlist
73
- } from "../chunk-25T4GQTU.js";
73
+ } from "../chunk-N25WAF7G.js";
74
74
  import {
75
75
  CONVERSATION_FAILURE_CATEGORIES,
76
76
  DEFAULT_FRAMEWORK,
@@ -111,7 +111,7 @@ import {
111
111
  resolveChannels,
112
112
  resolveDmTarget,
113
113
  sumTranscriptUsageInWindow
114
- } from "../chunk-VZP5CIVP.js";
114
+ } from "../chunk-OMC7BHRP.js";
115
115
  import {
116
116
  parsePsRows,
117
117
  reapOrphanChannelMcps
@@ -119,7 +119,7 @@ import {
119
119
 
120
120
  // src/lib/manager-worker.ts
121
121
  import { createHash as createHash10 } from "crypto";
122
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync8, rmSync as rmSync4, readdirSync as readdirSync5, statSync as statSync4, unlinkSync, copyFileSync } from "fs";
122
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync8, rmSync as rmSync4, readdirSync as readdirSync5, statSync as statSync4, copyFileSync } from "fs";
123
123
  import { execFileSync as syncExecFile } from "child_process";
124
124
  import { join as join16, dirname as dirname5 } from "path";
125
125
  import { homedir as homedir9 } from "os";
@@ -3056,275 +3056,6 @@ function bundleFingerprint(files) {
3056
3056
  return sorted.map((f) => `${f.relativePath}\0${f.content}`).join("");
3057
3057
  }
3058
3058
 
3059
- // src/lib/gateway-client.ts
3060
- import { EventEmitter } from "events";
3061
- import WebSocket from "ws";
3062
- var DEFAULT_PORT = 18789;
3063
- var RECONNECT_INITIAL_MS = 1e3;
3064
- var RECONNECT_BASE_MS = 5e3;
3065
- var RECONNECT_MAX_MS = 3e4;
3066
- var HEARTBEAT_INTERVAL_MS = 3e4;
3067
- var GatewayClient = class extends EventEmitter {
3068
- port;
3069
- token;
3070
- ws = null;
3071
- _connected = false;
3072
- _everConnected = false;
3073
- reconnectAttempts = 0;
3074
- reconnectTimer = null;
3075
- heartbeatTimer = null;
3076
- pongReceived = true;
3077
- intentionalClose = false;
3078
- pendingRpc = /* @__PURE__ */ new Map();
3079
- rpcSeq = 0;
3080
- constructor(options = {}) {
3081
- super();
3082
- this.port = options.port ?? Number(process.env["OPENCLAW_GATEWAY_PORT"]) ?? DEFAULT_PORT;
3083
- this.token = options.token ?? process.env["OPENCLAW_GATEWAY_TOKEN"];
3084
- }
3085
- get connected() {
3086
- return this._connected;
3087
- }
3088
- connect() {
3089
- this.intentionalClose = false;
3090
- this.doConnect();
3091
- }
3092
- disconnect() {
3093
- this.intentionalClose = true;
3094
- this.clearTimers();
3095
- if (this.ws) {
3096
- this.ws.removeAllListeners();
3097
- this.ws.close(1e3);
3098
- this.ws = null;
3099
- }
3100
- if (this._connected) {
3101
- this._connected = false;
3102
- this.emit("disconnected");
3103
- }
3104
- }
3105
- // ── Private ──────────────────────────────────────────────────────────────
3106
- doConnect() {
3107
- const url = `ws://127.0.0.1:${this.port}`;
3108
- try {
3109
- const headers = {};
3110
- if (this.token) {
3111
- headers["Authorization"] = `Bearer ${this.token}`;
3112
- }
3113
- this.ws = new WebSocket(url, { headers });
3114
- } catch (err) {
3115
- this.emit("error", err);
3116
- this.scheduleReconnect();
3117
- return;
3118
- }
3119
- this.ws.on("open", () => {
3120
- });
3121
- this.ws.on("message", (data) => {
3122
- try {
3123
- const msg = JSON.parse(data.toString());
3124
- this.handleMessage(msg);
3125
- } catch {
3126
- }
3127
- });
3128
- this.ws.on("close", (code, reason) => {
3129
- this.clearHeartbeat();
3130
- if (this._connected) {
3131
- this._connected = false;
3132
- this.emit("disconnected");
3133
- } else if (!this._everConnected) {
3134
- this.emit("error", new Error(`WebSocket closed before auth (code=${code}, reason=${reason?.toString() || "none"})`));
3135
- }
3136
- if (!this.intentionalClose) {
3137
- this.scheduleReconnect();
3138
- }
3139
- });
3140
- this.ws.on("error", (err) => {
3141
- if (!this._everConnected && err.code === "ECONNREFUSED") {
3142
- return;
3143
- }
3144
- this.emit("error", err);
3145
- });
3146
- this.ws.on("pong", () => {
3147
- this.pongReceived = true;
3148
- });
3149
- }
3150
- handleMessage(msg) {
3151
- switch (msg.type) {
3152
- case "challenge":
3153
- this.sendJson({
3154
- type: "connect",
3155
- nonce: msg.nonce,
3156
- role: "operator",
3157
- scopes: ["events:read"]
3158
- });
3159
- break;
3160
- case "hello-ok":
3161
- this._connected = true;
3162
- this._everConnected = true;
3163
- this.reconnectAttempts = 0;
3164
- this.startHeartbeat();
3165
- this.emit("connected");
3166
- break;
3167
- case "event":
3168
- this.emit("event", {
3169
- type: "event",
3170
- event: msg.event,
3171
- payload: msg.payload,
3172
- seq: msg.seq,
3173
- stateVersion: msg.stateVersion
3174
- });
3175
- break;
3176
- case "heartbeat":
3177
- case "tick":
3178
- break;
3179
- case "rpc-result":
3180
- case "rpc-error": {
3181
- const rpcId = msg.id;
3182
- const pending = this.pendingRpc.get(rpcId);
3183
- if (pending) {
3184
- this.pendingRpc.delete(rpcId);
3185
- clearTimeout(pending.timer);
3186
- if (msg.type === "rpc-error") {
3187
- pending.reject(new Error(msg.error ?? "RPC error"));
3188
- } else {
3189
- pending.resolve(msg.result);
3190
- }
3191
- }
3192
- break;
3193
- }
3194
- default:
3195
- if (msg.id && typeof msg.id === "string") {
3196
- const pending = this.pendingRpc.get(msg.id);
3197
- if (pending) {
3198
- this.pendingRpc.delete(msg.id);
3199
- clearTimeout(pending.timer);
3200
- if (msg.error) {
3201
- pending.reject(new Error(String(msg.error)));
3202
- } else {
3203
- pending.resolve(msg);
3204
- }
3205
- }
3206
- }
3207
- break;
3208
- }
3209
- }
3210
- /**
3211
- * Send an RPC call to the gateway and wait for a response.
3212
- * Returns the response payload or throws on timeout/error.
3213
- */
3214
- sendRpc(method, params = {}, timeoutMs = 1e4) {
3215
- return new Promise((resolve, reject) => {
3216
- if (!this._connected || this.ws?.readyState !== WebSocket.OPEN) {
3217
- reject(new Error("Gateway not connected"));
3218
- return;
3219
- }
3220
- const id = `rpc-${++this.rpcSeq}-${Date.now()}`;
3221
- const timer = setTimeout(() => {
3222
- this.pendingRpc.delete(id);
3223
- reject(new Error(`RPC ${method} timed out after ${timeoutMs}ms`));
3224
- }, timeoutMs);
3225
- this.pendingRpc.set(id, { resolve, reject, timer });
3226
- this.sendJson({ type: "rpc", id, method, params });
3227
- });
3228
- }
3229
- sendJson(obj) {
3230
- if (this.ws?.readyState === WebSocket.OPEN) {
3231
- this.ws.send(JSON.stringify(obj));
3232
- }
3233
- }
3234
- startHeartbeat() {
3235
- this.clearHeartbeat();
3236
- this.pongReceived = true;
3237
- this.heartbeatTimer = setInterval(() => {
3238
- if (!this.pongReceived) {
3239
- this.ws?.terminate();
3240
- return;
3241
- }
3242
- this.pongReceived = false;
3243
- this.ws?.ping();
3244
- }, HEARTBEAT_INTERVAL_MS);
3245
- }
3246
- clearHeartbeat() {
3247
- if (this.heartbeatTimer) {
3248
- clearInterval(this.heartbeatTimer);
3249
- this.heartbeatTimer = null;
3250
- }
3251
- }
3252
- scheduleReconnect() {
3253
- if (this.intentionalClose) return;
3254
- const delay = this.reconnectAttempts === 0 ? RECONNECT_INITIAL_MS : Math.min(RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempts - 1), RECONNECT_MAX_MS);
3255
- this.reconnectAttempts++;
3256
- this.reconnectTimer = setTimeout(() => {
3257
- this.reconnectTimer = null;
3258
- this.doConnect();
3259
- }, delay);
3260
- }
3261
- clearTimers() {
3262
- this.clearHeartbeat();
3263
- if (this.reconnectTimer) {
3264
- clearTimeout(this.reconnectTimer);
3265
- this.reconnectTimer = null;
3266
- }
3267
- }
3268
- };
3269
- var GatewayClientPool = class extends EventEmitter {
3270
- clients = /* @__PURE__ */ new Map();
3271
- addAgent(codeName, port, token) {
3272
- if (this.clients.has(codeName)) {
3273
- this.removeAgent(codeName);
3274
- }
3275
- const client2 = new GatewayClient({ port, token });
3276
- client2.on("connected", () => {
3277
- this.emit("connected", codeName);
3278
- });
3279
- client2.on("disconnected", () => {
3280
- this.emit("disconnected", codeName);
3281
- });
3282
- client2.on("error", (err) => {
3283
- this.emit("error", err, codeName);
3284
- });
3285
- client2.on("event", (evt) => {
3286
- const pooledEvent = {
3287
- ...evt,
3288
- agentCodeName: codeName
3289
- };
3290
- this.emit("event", pooledEvent);
3291
- });
3292
- this.clients.set(codeName, client2);
3293
- client2.connect();
3294
- }
3295
- removeAgent(codeName) {
3296
- const client2 = this.clients.get(codeName);
3297
- if (client2) {
3298
- client2.disconnect();
3299
- this.clients.delete(codeName);
3300
- }
3301
- }
3302
- hasAgent(codeName) {
3303
- return this.clients.has(codeName);
3304
- }
3305
- isConnected(codeName) {
3306
- return this.clients.get(codeName)?.connected ?? false;
3307
- }
3308
- /**
3309
- * Send an RPC call to a specific agent's gateway.
3310
- * Returns the response or throws on timeout/error/not connected.
3311
- */
3312
- async sendRpc(codeName, method, params = {}, timeoutMs = 1e4) {
3313
- const client2 = this.clients.get(codeName);
3314
- if (!client2) throw new Error(`No gateway client for agent '${codeName}'`);
3315
- return client2.sendRpc(method, params, timeoutMs);
3316
- }
3317
- disconnectAll() {
3318
- for (const [, client2] of this.clients) {
3319
- client2.disconnect();
3320
- }
3321
- this.clients.clear();
3322
- }
3323
- get size() {
3324
- return this.clients.size;
3325
- }
3326
- };
3327
-
3328
3059
  // src/lib/claude-auth-detect.ts
3329
3060
  import { readFile as readFile2, readdir as readdir2 } from "fs/promises";
3330
3061
  import { homedir as homedir4, platform } from "os";
@@ -3932,15 +3663,6 @@ function hashFile(filePath) {
3932
3663
  return null;
3933
3664
  }
3934
3665
  }
3935
- async function execFilePromise(cmd, args) {
3936
- const { execFile: ef } = await import("child_process");
3937
- return new Promise((resolve, reject) => {
3938
- ef(cmd, args, { timeout: 15e3 }, (err, stdout, stderr) => {
3939
- if (err) reject(err);
3940
- else resolve({ stdout, stderr });
3941
- });
3942
- });
3943
- }
3944
3666
  var ChildProcessError = class extends Error {
3945
3667
  code;
3946
3668
  stdout;
@@ -6080,11 +5802,6 @@ function applyRestartAcks(args) {
6080
5802
  }
6081
5803
  return changed;
6082
5804
  }
6083
- var GATEWAY_PORT_BASE = 18800;
6084
- var GATEWAY_PORT_STEP = 10;
6085
- var GATEWAY_PORT_MAX = 18899;
6086
- var AUGMENTED_DIR = join16(process.env["HOME"] ?? "/tmp", ".augmented");
6087
- var GATEWAY_PORTS_FILE = join16(AUGMENTED_DIR, "gateway-ports.json");
6088
5805
  var CHANNEL_SWEEP_INTERVAL_MS = (() => {
6089
5806
  const raw = parseInt(process.env["AGT_CHANNEL_SWEEP_INTERVAL_MS"] ?? "", 10);
6090
5807
  if (!Number.isFinite(raw)) return 5 * 60 * 1e3;
@@ -6819,21 +6536,17 @@ var managedToolkitIdByAgentAndServerId = /* @__PURE__ */ new Map();
6819
6536
  function managedToolkitMapKey(agentId, serverId) {
6820
6537
  return `${agentId}\0${serverId}`;
6821
6538
  }
6822
- var lastCronRunTs = /* @__PURE__ */ new Map();
6823
6539
  var lastWorkTriggerAt = /* @__PURE__ */ new Map();
6824
6540
  var alertedStaleItems = /* @__PURE__ */ new Set();
6825
6541
  var stuckKanbanLogged = /* @__PURE__ */ new Set();
6826
- var apiKeyStatusCache = /* @__PURE__ */ new Map();
6827
6542
  var STALE_TASK_THRESHOLD_MS = (() => {
6828
6543
  const env = process.env["AUGMENTED_STUCK_TASK_THRESHOLD_MINUTES"];
6829
6544
  const minutes = env ? Number.parseInt(env, 10) : NaN;
6830
6545
  if (Number.isFinite(minutes) && minutes > 0) return minutes * 60 * 1e3;
6831
6546
  return 30 * 60 * 1e3;
6832
6547
  })();
6833
- var alertedJobs = /* @__PURE__ */ new Set();
6834
6548
  var taskDisplayInfo = /* @__PURE__ */ new Map();
6835
6549
  var activeChannels = /* @__PURE__ */ new Map();
6836
- var gatewaysStartedThisCycle = /* @__PURE__ */ new Set();
6837
6550
  var state6 = {
6838
6551
  pid: process.pid,
6839
6552
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -6852,7 +6565,6 @@ function resolveAgentFramework(codeName) {
6852
6565
  const frameworkId = agentFrameworkCache.get(codeName) ?? DEFAULT_FRAMEWORK;
6853
6566
  return getFramework(frameworkId);
6854
6567
  }
6855
- var gatewayPool = null;
6856
6568
  function clearAgentCaches(agentId, codeName) {
6857
6569
  const channelCacheMutated = clearAgentState(agentId, codeName);
6858
6570
  agentChannelTokens.delete(codeName);
@@ -6878,7 +6590,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6878
6590
  var lastVersionCheckAt = 0;
6879
6591
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6880
6592
  var lastResponsivenessProbeAt = 0;
6881
- var agtCliVersion = true ? "0.28.170" : "dev";
6593
+ var agtCliVersion = true ? "0.28.172" : "dev";
6882
6594
  function resolveBrewPath(execFileSync4) {
6883
6595
  try {
6884
6596
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7556,37 +7268,6 @@ function resolveConversationEvalBackend() {
7556
7268
  conversationEvalBackendSig = sig;
7557
7269
  return conversationEvalBackend;
7558
7270
  }
7559
- function loadGatewayPorts() {
7560
- try {
7561
- return JSON.parse(readFileSync14(GATEWAY_PORTS_FILE, "utf-8"));
7562
- } catch {
7563
- return {};
7564
- }
7565
- }
7566
- function saveGatewayPorts(ports) {
7567
- mkdirSync6(AUGMENTED_DIR, { recursive: true });
7568
- writeFileSync6(GATEWAY_PORTS_FILE, JSON.stringify(ports, null, 2));
7569
- }
7570
- function allocatePort(codeName) {
7571
- const ports = loadGatewayPorts();
7572
- if (ports[codeName]) return ports[codeName];
7573
- const usedPorts = new Set(Object.values(ports));
7574
- for (let port = GATEWAY_PORT_BASE; port <= GATEWAY_PORT_MAX; port += GATEWAY_PORT_STEP) {
7575
- if (!usedPorts.has(port)) {
7576
- ports[codeName] = port;
7577
- saveGatewayPorts(ports);
7578
- return port;
7579
- }
7580
- }
7581
- throw new Error(`No free gateway ports in range ${GATEWAY_PORT_BASE}-${GATEWAY_PORT_MAX}`);
7582
- }
7583
- function freePort(codeName) {
7584
- const ports = loadGatewayPorts();
7585
- if (ports[codeName]) {
7586
- delete ports[codeName];
7587
- saveGatewayPorts(ports);
7588
- }
7589
- }
7590
7271
  function getStateFile() {
7591
7272
  return join16(config?.configDir ?? join16(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
7592
7273
  }
@@ -7713,214 +7394,6 @@ ${SKILLS_INDEX_END}`;
7713
7394
  log2(`Refreshed skills index in CLAUDE.md for '${codeName}' (${entries.length} skills)`);
7714
7395
  }
7715
7396
  }
7716
- async function migrateToProfiles() {
7717
- const homeDir = process.env["HOME"] ?? "/tmp";
7718
- const sharedConfigPath = join16(homeDir, ".openclaw", "openclaw.json");
7719
- let sharedConfig;
7720
- try {
7721
- sharedConfig = JSON.parse(readFileSync14(sharedConfigPath, "utf-8"));
7722
- } catch {
7723
- return;
7724
- }
7725
- const agents = sharedConfig["agents"];
7726
- const agentList = agents?.["list"] ?? [];
7727
- if (agentList.length === 0) return;
7728
- const adapter = getFramework(DEFAULT_FRAMEWORK);
7729
- let migrated = 0;
7730
- for (const agentEntry of agentList) {
7731
- const codeName = agentEntry["id"];
7732
- if (!codeName) continue;
7733
- if (codeName === "main") continue;
7734
- const profileDir = join16(homeDir, `.openclaw-${codeName}`);
7735
- if (existsSync8(join16(profileDir, "openclaw.json"))) continue;
7736
- log(`Migrating agent '${codeName}' to per-agent profile`);
7737
- if (adapter.seedProfileConfig) {
7738
- adapter.seedProfileConfig(codeName);
7739
- }
7740
- const sharedAuthDir = join16(homeDir, ".openclaw", "agents", codeName, "agent");
7741
- const profileAuthDir = join16(profileDir, "agents", codeName, "agent");
7742
- const authFile = join16(sharedAuthDir, "auth-profiles.json");
7743
- if (existsSync8(authFile)) {
7744
- mkdirSync6(profileAuthDir, { recursive: true });
7745
- const authContent = readFileSync14(authFile, "utf-8");
7746
- writeFileSync6(join16(profileAuthDir, "auth-profiles.json"), authContent);
7747
- }
7748
- allocatePort(codeName);
7749
- migrated++;
7750
- }
7751
- if (migrated > 0) {
7752
- log(`Migration complete: ${migrated} agent(s) migrated to per-agent profiles`);
7753
- }
7754
- }
7755
- function readGatewayToken(codeName) {
7756
- const adapter = resolveAgentFramework(codeName);
7757
- if (adapter.readGatewayToken) {
7758
- return adapter.readGatewayToken(codeName);
7759
- }
7760
- const homeDir = process.env["HOME"] ?? "/tmp";
7761
- try {
7762
- const cfg = JSON.parse(readFileSync14(join16(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
7763
- return cfg?.gateway?.auth?.token;
7764
- } catch {
7765
- return void 0;
7766
- }
7767
- }
7768
- var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
7769
- function isGatewayHung(codeName) {
7770
- const homeDir = process.env["HOME"] ?? "/tmp";
7771
- const jobsPath = join16(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
7772
- if (!existsSync8(jobsPath)) return false;
7773
- try {
7774
- const data = JSON.parse(readFileSync14(jobsPath, "utf-8"));
7775
- const jobs = data.jobs ?? data;
7776
- if (!Array.isArray(jobs)) return false;
7777
- const now = Date.now();
7778
- for (const job of jobs) {
7779
- const state7 = job.state;
7780
- if (!state7) continue;
7781
- const runStartedAt = state7.runStartedAtMs;
7782
- const isRunning = state7.status === "running" || state7.running === true;
7783
- if (isRunning && runStartedAt && now - runStartedAt > GATEWAY_HUNG_TIMEOUT_MS) {
7784
- return true;
7785
- }
7786
- }
7787
- } catch {
7788
- }
7789
- return false;
7790
- }
7791
- async function ensureGatewayRunning(codeName, adapter) {
7792
- if (!adapter.isGatewayRunning || !adapter.startGateway) {
7793
- return { pid: null, port: null, running: false };
7794
- }
7795
- const status = await adapter.isGatewayRunning(codeName);
7796
- if (status.running) {
7797
- if (await isGatewayHung(codeName)) {
7798
- log(`Gateway for '${codeName}' appears hung (cron stuck >5min) \u2014 restarting`);
7799
- if (adapter.stopGateway) {
7800
- try {
7801
- await adapter.stopGateway(codeName);
7802
- } catch {
7803
- }
7804
- }
7805
- await new Promise((r) => setTimeout(r, 2e3));
7806
- const homeDir = process.env["HOME"] ?? "/tmp";
7807
- const cronJobsPath = join16(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
7808
- clearStaleCronRunState(cronJobsPath);
7809
- } else {
7810
- if (status.port) {
7811
- try {
7812
- const homeDir = process.env["HOME"] ?? "/tmp";
7813
- const configPath = join16(homeDir, `.openclaw-${codeName}`, "openclaw.json");
7814
- if (existsSync8(configPath)) {
7815
- const cfg = JSON.parse(readFileSync14(configPath, "utf-8"));
7816
- if (cfg.gateway?.port !== status.port) {
7817
- if (!cfg.gateway) cfg.gateway = {};
7818
- cfg.gateway.port = status.port;
7819
- writeFileSync6(configPath, JSON.stringify(cfg, null, 2));
7820
- }
7821
- }
7822
- } catch {
7823
- }
7824
- }
7825
- if (gatewayPool && status.port && !gatewayPool.hasAgent(codeName)) {
7826
- const token = readGatewayToken(codeName);
7827
- gatewayPool.addAgent(codeName, status.port, token);
7828
- }
7829
- return { pid: status.pid ?? null, port: status.port ?? null, running: true };
7830
- }
7831
- }
7832
- const port = allocatePort(codeName);
7833
- try {
7834
- const result = await adapter.startGateway(codeName, port);
7835
- log(`Gateway started for '${codeName}' on port ${port} (PID ${result.pid})`);
7836
- gatewaysStartedThisCycle.add(codeName);
7837
- try {
7838
- const homeDir = process.env["HOME"] ?? "/tmp";
7839
- const configPath = join16(homeDir, `.openclaw-${codeName}`, "openclaw.json");
7840
- if (existsSync8(configPath)) {
7841
- const cfg = JSON.parse(readFileSync14(configPath, "utf-8"));
7842
- if (!cfg.gateway) cfg.gateway = {};
7843
- cfg.gateway.port = port;
7844
- writeFileSync6(configPath, JSON.stringify(cfg, null, 2));
7845
- }
7846
- } catch {
7847
- }
7848
- if (gatewayPool) {
7849
- const token = readGatewayToken(codeName);
7850
- gatewayPool.addAgent(codeName, port, token);
7851
- }
7852
- return { pid: result.pid, port, running: true };
7853
- } catch (err) {
7854
- log(`Failed to start gateway for '${codeName}': ${err.message}`);
7855
- return { pid: null, port, running: false };
7856
- }
7857
- }
7858
- async function stopGatewayIfRunning(codeName, adapter) {
7859
- if (!adapter.stopGateway) return;
7860
- try {
7861
- const stopped = await adapter.stopGateway(codeName);
7862
- if (stopped) {
7863
- log(`Gateway stopped for '${codeName}'`);
7864
- }
7865
- } catch (err) {
7866
- log(`Failed to stop gateway for '${codeName}': ${err.message}`);
7867
- }
7868
- if (gatewayPool) {
7869
- gatewayPool.removeAgent(codeName);
7870
- }
7871
- }
7872
- async function stopAllGateways() {
7873
- const ports = loadGatewayPorts();
7874
- for (const codeName of Object.keys(ports)) {
7875
- const adapter = resolveAgentFramework(codeName);
7876
- await stopGatewayIfRunning(codeName, adapter);
7877
- }
7878
- if (gatewayPool) {
7879
- gatewayPool.disconnectAll();
7880
- }
7881
- }
7882
- async function healthCheckGateways(agentStates) {
7883
- for (const agent of agentStates) {
7884
- if (agent.status !== "active" || !agent.gatewayPort) continue;
7885
- const adapter = resolveAgentFramework(agent.codeName);
7886
- if (!adapter.isGatewayRunning || !adapter.startGateway) continue;
7887
- if (gatewaysStartedThisCycle.has(agent.codeName)) continue;
7888
- const status = await adapter.isGatewayRunning(agent.codeName);
7889
- if (!status.running && agent.gatewayRunning) {
7890
- const displayName = agentState.agentDisplayNames.get(agent.codeName) ?? agent.codeName;
7891
- log(`Gateway for '${agent.codeName}' crashed, restarting...`);
7892
- sendSlackWebhookMessage(
7893
- `:red_circle: *Host Down* \u2014 *${displayName}* (\`${agent.codeName}\`)
7894
- OpenClaw gateway crashed. Attempting automatic restart...`
7895
- ).catch(() => {
7896
- });
7897
- try {
7898
- const result = await adapter.startGateway(agent.codeName, agent.gatewayPort);
7899
- agent.gatewayPid = result.pid;
7900
- agent.gatewayRunning = true;
7901
- log(`Gateway restarted for '${agent.codeName}' (PID ${result.pid})`);
7902
- await new Promise((resolve) => setTimeout(resolve, 2e3));
7903
- if (gatewayPool) {
7904
- const token = readGatewayToken(agent.codeName);
7905
- gatewayPool.addAgent(agent.codeName, agent.gatewayPort, token);
7906
- }
7907
- sendSlackWebhookMessage(
7908
- `:large_green_circle: *Host Recovered* \u2014 *${displayName}* (\`${agent.codeName}\`)
7909
- Gateway restarted successfully (PID ${result.pid}).`
7910
- ).catch(() => {
7911
- });
7912
- } catch (err) {
7913
- agent.gatewayRunning = false;
7914
- log(`Failed to restart gateway for '${agent.codeName}': ${err.message}`);
7915
- sendSlackWebhookMessage(
7916
- `:x: *Host Restart Failed* \u2014 *${displayName}* (\`${agent.codeName}\`)
7917
- Automatic restart failed: ${err.message}`
7918
- ).catch(() => {
7919
- });
7920
- }
7921
- }
7922
- }
7923
- }
7924
7397
  var consecutivePollFailures = 0;
7925
7398
  async function pollCycle() {
7926
7399
  if (!config) return;
@@ -7991,7 +7464,6 @@ async function pollCycle() {
7991
7464
  maybeUpgradeClaudeCode().catch((err) => log(`[claude-code-upgrade] Check failed: ${err.message}`));
7992
7465
  try {
7993
7466
  registeredAgentsCache.clear();
7994
- gatewaysStartedThisCycle.clear();
7995
7467
  const hostId = await getHostId();
7996
7468
  if (!hostId) {
7997
7469
  send({ type: "error", message: "Could not resolve host ID from API key" });
@@ -8011,7 +7483,7 @@ async function pollCycle() {
8011
7483
  }
8012
7484
  try {
8013
7485
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
8014
- const { collectDiagnostics } = await import("../persistent-session-2QNOLKCT.js");
7486
+ const { collectDiagnostics } = await import("../persistent-session-4HC7YFSU.js");
8015
7487
  const diagCodeNames = [...agentState.persistentSessionAgents];
8016
7488
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
8017
7489
  let tailscaleHostname;
@@ -8159,7 +7631,7 @@ async function pollCycle() {
8159
7631
  const {
8160
7632
  collectResponsivenessProbes,
8161
7633
  getResponsivenessIntervalMs
8162
- } = await import("../responsiveness-probe-4JPUYWPB.js");
7634
+ } = await import("../responsiveness-probe-W4PCY6HC.js");
8163
7635
  const probeIntervalMs = getResponsivenessIntervalMs();
8164
7636
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
8165
7637
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -8191,7 +7663,7 @@ async function pollCycle() {
8191
7663
  collectResponsivenessProbes,
8192
7664
  livePendingInboundOldestAgeSeconds,
8193
7665
  parkPendingInbound
8194
- } = await import("../responsiveness-probe-4JPUYWPB.js");
7666
+ } = await import("../responsiveness-probe-W4PCY6HC.js");
8195
7667
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
8196
7668
  const wedgeNow = /* @__PURE__ */ new Date();
8197
7669
  const liveAgents = agentState.persistentSessionAgents;
@@ -8401,9 +7873,6 @@ async function pollCycle() {
8401
7873
  lastProvisionAt: null,
8402
7874
  lastDriftCheckAt: null,
8403
7875
  lastSecretsProvisionAt: null,
8404
- gatewayPort: null,
8405
- gatewayPid: null,
8406
- gatewayRunning: false,
8407
7876
  acpSessions: []
8408
7877
  });
8409
7878
  }
@@ -8439,7 +7908,6 @@ async function pollCycle() {
8439
7908
  if (!currentIds.has(prev.agentId)) {
8440
7909
  log(`Agent '${prev.codeName}' removed from host (deleted or unassigned)`);
8441
7910
  const adapter = resolveAgentFramework(prev.codeName);
8442
- await stopGatewayIfRunning(prev.codeName, adapter);
8443
7911
  stopPersistentSessionAndForgetMcpBaseline(prev.codeName);
8444
7912
  try {
8445
7913
  const { execSync: es } = await import("child_process");
@@ -8447,7 +7915,6 @@ async function pollCycle() {
8447
7915
  } catch {
8448
7916
  }
8449
7917
  killAgentChannelProcesses(prev.codeName, { log });
8450
- freePort(prev.codeName);
8451
7918
  const agentDir = join16(adapter.getAgentDir(prev.codeName), "provision");
8452
7919
  await cleanupAgentFiles(prev.codeName, agentDir);
8453
7920
  clearAgentCaches(prev.agentId, prev.codeName);
@@ -8461,7 +7928,6 @@ async function pollCycle() {
8461
7928
  } catch (err) {
8462
7929
  log(`[claude-pair] poll failed: ${err.message}`);
8463
7930
  }
8464
- await healthCheckGateways(agentStates);
8465
7931
  if (Date.now() - lastChannelSweepAt >= CHANNEL_SWEEP_INTERVAL_MS) {
8466
7932
  lastChannelSweepAt = Date.now();
8467
7933
  const agentCodeNames = new Set(
@@ -8552,13 +8018,6 @@ async function pollCycle() {
8552
8018
  healMode: process.env.AGT_INPUT_HEAL_MODE === "bare" ? "bare" : "disturb"
8553
8019
  });
8554
8020
  }
8555
- const lastHealthCheck = lastHarvestAt.get("__cron_health__") ?? 0;
8556
- if (Date.now() - lastHealthCheck >= HARVEST_INTERVAL_MS) {
8557
- lastHarvestAt.set("__cron_health__", Date.now());
8558
- monitorCronHealth(agentStates).catch((err) => {
8559
- log(`Cron health monitor error: ${err.message}`);
8560
- });
8561
- }
8562
8021
  healRealtimeSocketDivergence();
8563
8022
  if (!isRealtimeConnected()) {
8564
8023
  pollDirectChatMessages(agentStates).catch((err) => {
@@ -8681,7 +8140,6 @@ async function processAgent(agent, agentStates) {
8681
8140
  } else if (killPausedCodeNames.delete(agent.code_name)) {
8682
8141
  log(`[kill-switch] '${agent.code_name}' kill switch cleared while still ${agent.status} (no resume \u2014 paused for another reason)`);
8683
8142
  }
8684
- await stopGatewayIfRunning(agent.code_name, adapter);
8685
8143
  stopPersistentSessionAndForgetMcpBaseline(agent.code_name);
8686
8144
  try {
8687
8145
  const { execSync: es } = await import("child_process");
@@ -8703,9 +8161,6 @@ async function processAgent(agent, agentStates) {
8703
8161
  lastProvisionAt: null,
8704
8162
  lastDriftCheckAt: null,
8705
8163
  lastSecretsProvisionAt: null,
8706
- gatewayPort: null,
8707
- gatewayPid: null,
8708
- gatewayRunning: false,
8709
8164
  acpSessions: []
8710
8165
  });
8711
8166
  agentState.knownStatuses.set(agent.agent_id, agent.status);
@@ -8713,11 +8168,9 @@ async function processAgent(agent, agentStates) {
8713
8168
  }
8714
8169
  if (agent.status === "revoked") {
8715
8170
  if (shouldSkipRevokedCleanup(previousKnownStatus)) {
8716
- const ports = loadGatewayPorts();
8717
- const gatewayLiveness = adapter.isGatewayRunning ? await adapter.isGatewayRunning(agent.code_name).catch(() => ({ running: false })) : { running: false };
8718
8171
  const residuals = {
8719
- gatewayRunning: gatewayLiveness.running,
8720
- portAllocated: Object.prototype.hasOwnProperty.call(ports, agent.code_name),
8172
+ gatewayRunning: false,
8173
+ portAllocated: false,
8721
8174
  provisionDirExists: existsSync8(agentDir)
8722
8175
  };
8723
8176
  if (!hasRevokedResiduals(residuals)) {
@@ -8732,19 +8185,15 @@ async function processAgent(agent, agentStates) {
8732
8185
  lastProvisionAt: null,
8733
8186
  lastDriftCheckAt: null,
8734
8187
  lastSecretsProvisionAt: null,
8735
- gatewayPort: null,
8736
- gatewayPid: null,
8737
- gatewayRunning: false,
8738
8188
  acpSessions: []
8739
8189
  });
8740
8190
  return;
8741
8191
  }
8742
8192
  log(
8743
- `[revoked] residuals for '${agent.code_name}': gateway=${residuals.gatewayRunning} dir=${residuals.provisionDirExists} port=${residuals.portAllocated ? ports[agent.code_name] : "none"} \u2014 retrying cleanup`
8193
+ `[revoked] residuals for '${agent.code_name}': dir=${residuals.provisionDirExists} \u2014 retrying cleanup`
8744
8194
  );
8745
8195
  }
8746
8196
  log(`Agent '${agent.code_name}' is revoked, cleaning up`);
8747
- await stopGatewayIfRunning(agent.code_name, adapter);
8748
8197
  stopPersistentSessionAndForgetMcpBaseline(agent.code_name);
8749
8198
  try {
8750
8199
  const { execSync: es } = await import("child_process");
@@ -8752,7 +8201,6 @@ async function processAgent(agent, agentStates) {
8752
8201
  } catch {
8753
8202
  }
8754
8203
  killAgentChannelProcesses(agent.code_name, { log });
8755
- freePort(agent.code_name);
8756
8204
  await cleanupAgentFiles(agent.code_name, agentDir);
8757
8205
  clearAgentCaches(agent.agent_id, agent.code_name);
8758
8206
  agentState.knownStatuses.set(agent.agent_id, agent.status);
@@ -8767,9 +8215,6 @@ async function processAgent(agent, agentStates) {
8767
8215
  lastProvisionAt: null,
8768
8216
  lastDriftCheckAt: null,
8769
8217
  lastSecretsProvisionAt: null,
8770
- gatewayPort: null,
8771
- gatewayPid: null,
8772
- gatewayRunning: false,
8773
8218
  acpSessions: []
8774
8219
  });
8775
8220
  return;
@@ -8834,9 +8279,6 @@ async function processAgent(agent, agentStates) {
8834
8279
  lastProvisionAt: null,
8835
8280
  lastDriftCheckAt: null,
8836
8281
  lastSecretsProvisionAt: null,
8837
- gatewayPort: null,
8838
- gatewayPid: null,
8839
- gatewayRunning: false,
8840
8282
  acpSessions: []
8841
8283
  });
8842
8284
  return;
@@ -8860,9 +8302,6 @@ async function processAgent(agent, agentStates) {
8860
8302
  lastProvisionAt: null,
8861
8303
  lastDriftCheckAt: null,
8862
8304
  lastSecretsProvisionAt: null,
8863
- gatewayPort: null,
8864
- gatewayPid: null,
8865
- gatewayRunning: false,
8866
8305
  acpSessions: []
8867
8306
  });
8868
8307
  return;
@@ -9138,8 +8577,6 @@ async function processAgent(agent, agentStates) {
9138
8577
  agentChannelTokens.delete(agent.code_name);
9139
8578
  }
9140
8579
  }
9141
- let needsGatewayRestart = false;
9142
- const hasChannelConfigs = refreshData.channel_configs && Object.keys(refreshData.channel_configs).length > 0;
9143
8580
  if (refreshData.channel_configs && frameworkAdapter.writeChannelCredentials) {
9144
8581
  if (agent.status === "active") {
9145
8582
  for (const [channelId, entry] of Object.entries(refreshData.channel_configs)) {
@@ -9640,7 +9077,6 @@ async function processAgent(agent, agentStates) {
9640
9077
  if (rotationHandled) {
9641
9078
  agentState.knownIntegrationHashes.set(agent.agent_id, intHash);
9642
9079
  }
9643
- needsGatewayRestart = true;
9644
9080
  }
9645
9081
  }
9646
9082
  const fwForMcp = agentFrameworkCache.get(agent.code_name) ?? DEFAULT_FRAMEWORK;
@@ -9747,17 +9183,6 @@ async function processAgent(agent, agentStates) {
9747
9183
  } catch (err) {
9748
9184
  log(`Integration provisioning failed for '${agent.code_name}': ${err.message}`);
9749
9185
  }
9750
- let gatewayPort = null;
9751
- let gatewayPid = null;
9752
- let gatewayRunning = false;
9753
- if (agent.status === "active" && hasChannelConfigs) {
9754
- const gwStatus = await ensureGatewayRunning(agent.code_name, frameworkAdapter);
9755
- gatewayPort = gwStatus.port;
9756
- gatewayPid = gwStatus.pid;
9757
- gatewayRunning = gwStatus.running;
9758
- } else if (agent.status === "paused") {
9759
- await stopGatewayIfRunning(agent.code_name, frameworkAdapter);
9760
- }
9761
9186
  let tasks = refreshData.scheduled_tasks ?? [];
9762
9187
  const existingTemplateIds = new Set(tasks.map((t) => t.template_id));
9763
9188
  const kanbanWorkRetired = (agentFrameworkCache.get(agent.code_name) ?? DEFAULT_FRAMEWORK) === "claude-code" && agentSessionMode === "persistent";
@@ -9789,20 +9214,6 @@ async function processAgent(agent, agentStates) {
9789
9214
  tasks = tasks.filter((t) => t.template_id !== "kanban-work");
9790
9215
  }
9791
9216
  if (agent.status === "active") {
9792
- if (frameworkAdapter.installPlugin) {
9793
- try {
9794
- const pluginPath = join16(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
9795
- if (existsSync8(pluginPath)) {
9796
- frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
9797
- agtHost: requireHost(),
9798
- agtApiKey: getApiKey() ?? void 0,
9799
- agentId: agent.agent_id
9800
- });
9801
- }
9802
- } catch (err) {
9803
- log(`Augmented plugin install failed for '${agent.code_name}': ${err.message}`);
9804
- }
9805
- }
9806
9217
  if (frameworkAdapter.installSkillFiles) {
9807
9218
  try {
9808
9219
  const skillContent = getBuiltInSkillContent("kanban");
@@ -9865,8 +9276,6 @@ async function processAgent(agent, agentStates) {
9865
9276
  join16(homedir10(), ".augmented", agent.code_name, "skills"),
9866
9277
  // Claude Code — project tree
9867
9278
  join16(homedir10(), ".augmented", agent.code_name, "project", ".claude", "skills"),
9868
- // OpenClaw — framework runtime tree
9869
- join16(homedir10(), `.openclaw-${agent.code_name}`, "skills"),
9870
9279
  // Defensive: legacy provision-side path, not currently an
9871
9280
  // install target but cheap to sweep.
9872
9281
  join16(agentDir, ".claude", "skills")
@@ -9918,7 +9327,6 @@ async function processAgent(agent, agentStates) {
9918
9327
  const globalSkillDirs = [
9919
9328
  join16(homedir10(), ".augmented", agent.code_name, "skills"),
9920
9329
  join16(homedir10(), ".augmented", agent.code_name, "project", ".claude", "skills"),
9921
- join16(homedir10(), `.openclaw-${agent.code_name}`, "skills"),
9922
9330
  join16(agentDir, ".claude", "skills")
9923
9331
  ];
9924
9332
  for (const id of plan.removes) {
@@ -10242,72 +9650,6 @@ async function processAgent(agent, agentStates) {
10242
9650
  }
10243
9651
  } else if (agentFw === "claude-code" && tasks.length > 0) {
10244
9652
  await syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData);
10245
- } else if (frameworkAdapter.syncScheduledTasks && gatewayRunning && gatewayPort) {
10246
- const stableTasksHash = createHash10("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
10247
- const boardHash = boardItems.length > 0 ? createHash10("sha256").update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable })))).digest("hex").slice(0, 16) : "empty";
10248
- const resolvedModels = resolveModelChain(refreshData);
10249
- const modelsHash = createHash10("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
10250
- const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
10251
- const prevTasksHash = agentState.knownTasksHashes.get(agent.agent_id);
10252
- if (combinedHash !== prevTasksHash) {
10253
- const enrichedTasks = tasks.map((t) => {
10254
- if (BOARD_INJECT_TEMPLATES.has(t.template_id) && boardItems.length > 0) {
10255
- const template = PLAN_TEMPLATES.has(t.template_id) ? "morning-plan" : "follow-up";
10256
- const boardPrefix = formatBoardForPrompt(boardItems, template);
10257
- return { ...t, prompt: boardPrefix + t.prompt };
10258
- }
10259
- return t;
10260
- });
10261
- try {
10262
- const token = readGatewayToken(agent.code_name);
10263
- await frameworkAdapter.syncScheduledTasks(
10264
- agent.code_name,
10265
- enrichedTasks.map((t) => ({
10266
- id: t.id,
10267
- template_id: t.template_id,
10268
- name: t.name,
10269
- schedule_kind: t.schedule_kind,
10270
- schedule_expr: t.schedule_expr,
10271
- schedule_every: t.schedule_every,
10272
- schedule_at: t.schedule_at,
10273
- timezone: t.timezone,
10274
- prompt: t.prompt,
10275
- session_target: t.session_target,
10276
- delivery_mode: t.delivery_mode,
10277
- delivery_channel: t.delivery_channel,
10278
- delivery_to: t.delivery_to,
10279
- enabled: t.enabled,
10280
- model_tier: t.model_tier ?? "primary"
10281
- })),
10282
- gatewayPort,
10283
- token,
10284
- {
10285
- models: resolvedModels
10286
- }
10287
- );
10288
- agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
10289
- log(`Scheduled tasks synced for '${agent.code_name}' (${enrichedTasks.length} task(s))`);
10290
- } catch (err) {
10291
- log(`Failed to sync scheduled tasks for '${agent.code_name}': ${err.message}`);
10292
- }
10293
- }
10294
- }
10295
- for (const t of tasks) {
10296
- const jobName = `aug:${t.template_id}:${t.id ?? t.name.toLowerCase().replace(/\s+/g, "-")}`;
10297
- taskDisplayInfo.set(`${agent.code_name}:${jobName}`, {
10298
- taskName: t.name,
10299
- schedule: t.schedule_expr ?? t.schedule_every ?? "",
10300
- agentDisplayName: agent.display_name
10301
- });
10302
- }
10303
- if (agentFw === "openclaw" && gatewayRunning && gatewayPort && tasks.length > 0) {
10304
- const lastHarvest = lastHarvestAt.get(agent.code_name) ?? 0;
10305
- if (Date.now() - lastHarvest >= HARVEST_INTERVAL_MS) {
10306
- lastHarvestAt.set(agent.code_name, Date.now());
10307
- harvestCronResults(agent.code_name, tasks, gatewayPort).catch((err) => {
10308
- log(`Cron result harvest failed for '${agent.code_name}': ${err.message}`);
10309
- });
10310
- }
10311
9653
  }
10312
9654
  {
10313
9655
  const triggerAt = refreshData.agent.work_trigger_at;
@@ -10316,24 +9658,7 @@ async function processAgent(agent, agentStates) {
10316
9658
  const lastTrigger = lastWorkTriggerAt.get(agent.code_name) ?? 0;
10317
9659
  if (triggerTs > lastTrigger) {
10318
9660
  lastWorkTriggerAt.set(agent.code_name, triggerTs);
10319
- if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
10320
- const homeDir = process.env["HOME"] ?? "/tmp";
10321
- const jobsPath = join16(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
10322
- if (existsSync8(jobsPath)) {
10323
- try {
10324
- const jobsData = JSON.parse(readFileSync14(jobsPath, "utf-8"));
10325
- const kanbanJob = (jobsData.jobs ?? []).find(
10326
- (j) => typeof j.name === "string" && j.name.includes("kanban-work")
10327
- );
10328
- if (kanbanJob?.id) {
10329
- const cliBin = resolveAgentFramework(agent.code_name).cliBinary ?? "claude";
10330
- log(`Work trigger: firing kanban-work for '${agent.code_name}'`);
10331
- execFilePromise(cliBin, ["--profile", agent.code_name, "cron", "run", kanbanJob.id]).then(() => log(`Work trigger succeeded for '${agent.code_name}'`)).catch((err) => log(`Work trigger failed for '${agent.code_name}': ${err.message}`));
10332
- }
10333
- } catch {
10334
- }
10335
- }
10336
- } else if (agentFw === "claude-code") {
9661
+ if (agentFw === "claude-code") {
10337
9662
  if (sessionMode === "persistent") {
10338
9663
  if (isSessionHealthy(agent.code_name)) {
10339
9664
  const todayItem = boardItems.find((b) => b.status === "todo");
@@ -10350,9 +9675,6 @@ async function processAgent(agent, agentStates) {
10350
9675
  }
10351
9676
  }
10352
9677
  }
10353
- if (agentFw === "openclaw") {
10354
- cleanupStaleSessions(agent.code_name);
10355
- }
10356
9678
  {
10357
9679
  const agentId = agentState.codeNameToAgentId.get(agent.code_name);
10358
9680
  if (agentId) {
@@ -10519,143 +9841,9 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
10519
9841
  lastProvisionAt,
10520
9842
  lastDriftCheckAt,
10521
9843
  lastSecretsProvisionAt,
10522
- gatewayPort,
10523
- gatewayPid,
10524
- gatewayRunning,
10525
9844
  acpSessions: []
10526
9845
  });
10527
9846
  }
10528
- var CRON_SESSION_KEEP_COUNT = 10;
10529
- var CRON_RUN_RETENTION_DAYS = 7;
10530
- var lastCleanupAt = /* @__PURE__ */ new Map();
10531
- var CLEANUP_INTERVAL_MS = 6e4;
10532
- function cleanupStaleSessions(codeName) {
10533
- const lastRun = lastCleanupAt.get(codeName) ?? 0;
10534
- if (lastRun > 0 && Date.now() - lastRun < CLEANUP_INTERVAL_MS) return;
10535
- lastCleanupAt.set(codeName, Date.now());
10536
- const homeDir = process.env["HOME"] ?? "/tmp";
10537
- for (const agentDir of ["main", codeName]) {
10538
- const sessionsDir = join16(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
10539
- cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
10540
- }
10541
- const cronRunsDir = join16(homeDir, `.openclaw-${codeName}`, "cron", "runs");
10542
- cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
10543
- const cronJobsPath = join16(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
10544
- clearStaleCronRunState(cronJobsPath);
10545
- }
10546
- function cleanupCronSessions(sessionsDir, keepCount) {
10547
- const indexPath = join16(sessionsDir, "sessions.json");
10548
- if (!existsSync8(indexPath)) return;
10549
- try {
10550
- const raw = readFileSync14(indexPath, "utf-8");
10551
- const index = JSON.parse(raw);
10552
- const cronRunKeys = Object.keys(index).filter((k) => k.includes(":cron:") && k.includes(":run:")).map((k) => ({
10553
- key: k,
10554
- sessionId: index[k]?.sessionId,
10555
- updatedAt: index[k]?.updatedAt ?? 0
10556
- })).sort((a, b) => b.updatedAt - a.updatedAt);
10557
- if (cronRunKeys.length <= keepCount) return;
10558
- const toDelete = cronRunKeys.slice(keepCount);
10559
- let deletedFiles = 0;
10560
- for (const entry of toDelete) {
10561
- delete index[entry.key];
10562
- if (entry.sessionId) {
10563
- const sessionFile = join16(sessionsDir, `${entry.sessionId}.jsonl`);
10564
- try {
10565
- if (existsSync8(sessionFile)) {
10566
- unlinkSync(sessionFile);
10567
- deletedFiles++;
10568
- }
10569
- } catch {
10570
- }
10571
- }
10572
- }
10573
- const cronParentKeys = Object.keys(index).filter(
10574
- (k) => k.includes(":cron:") && !k.includes(":run:") && k !== "agent:main:main"
10575
- );
10576
- for (const parentKey of cronParentKeys) {
10577
- const hasRuns = Object.keys(index).some(
10578
- (k) => k.startsWith(parentKey + ":run:")
10579
- );
10580
- if (!hasRuns) {
10581
- const parentSessionId = index[parentKey]?.sessionId;
10582
- delete index[parentKey];
10583
- if (parentSessionId) {
10584
- try {
10585
- const f = join16(sessionsDir, `${parentSessionId}.jsonl`);
10586
- if (existsSync8(f)) {
10587
- unlinkSync(f);
10588
- deletedFiles++;
10589
- }
10590
- } catch {
10591
- }
10592
- }
10593
- }
10594
- }
10595
- writeFileSync6(indexPath, JSON.stringify(index));
10596
- if (toDelete.length > 0) {
10597
- log(`Cleaned ${toDelete.length} cron session(s) and ${deletedFiles} file(s) from ${sessionsDir}`);
10598
- }
10599
- } catch {
10600
- }
10601
- }
10602
- var STALE_RUN_TIMEOUT_MS = 5 * 6e4;
10603
- function clearStaleCronRunState(jobsPath) {
10604
- if (!existsSync8(jobsPath)) return;
10605
- try {
10606
- const raw = readFileSync14(jobsPath, "utf-8");
10607
- const data = JSON.parse(raw);
10608
- const jobs = data.jobs ?? data;
10609
- if (!Array.isArray(jobs)) return;
10610
- let changed = false;
10611
- const now = Date.now();
10612
- for (const job of jobs) {
10613
- const state7 = job.state;
10614
- if (!state7) continue;
10615
- const runStartedAt = state7.runningAtMs ?? state7.runStartedAtMs;
10616
- const isRunning = state7.running === true || state7.status === "running";
10617
- if (isRunning && runStartedAt && now - runStartedAt > STALE_RUN_TIMEOUT_MS) {
10618
- state7.running = false;
10619
- delete state7.status;
10620
- delete state7.runStartedAtMs;
10621
- delete state7.currentRunId;
10622
- changed = true;
10623
- log(`Cleared stale running state for cron job '${job.name}' (stuck for ${Math.round((now - runStartedAt) / 6e4)}min)`);
10624
- } else if (isRunning && !runStartedAt) {
10625
- state7.running = false;
10626
- changed = true;
10627
- log(`Cleared stale running state for cron job '${job.name}' (no start timestamp)`);
10628
- }
10629
- }
10630
- if (changed) {
10631
- writeFileSync6(jobsPath, JSON.stringify(data, null, 2));
10632
- }
10633
- } catch {
10634
- }
10635
- }
10636
- function cleanupOldFiles(dir, maxAgeDays, ext) {
10637
- if (!existsSync8(dir)) return;
10638
- const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
10639
- let removed = 0;
10640
- try {
10641
- for (const f of readdirSync5(dir)) {
10642
- if (!f.endsWith(ext)) continue;
10643
- const fullPath = join16(dir, f);
10644
- try {
10645
- const st = statSync4(fullPath);
10646
- if (st.mtimeMs < cutoff) {
10647
- unlinkSync(fullPath);
10648
- removed++;
10649
- }
10650
- } catch {
10651
- }
10652
- }
10653
- if (removed > 0) {
10654
- log(`Cleaned ${removed} old cron run log(s) from ${dir}`);
10655
- }
10656
- } catch {
10657
- }
10658
- }
10659
9847
  var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
10660
9848
  var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
10661
9849
  var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
@@ -11266,8 +10454,6 @@ var directChatInFlight = /* @__PURE__ */ new Set();
11266
10454
  async function pollDirectChatMessages(agentStates) {
11267
10455
  for (const agent of agentStates) {
11268
10456
  if (agent.status !== "active") continue;
11269
- const fw = agentFrameworkCache.get(agent.codeName) ?? DEFAULT_FRAMEWORK;
11270
- if (fw === "openclaw" && (!agent.gatewayRunning || !agent.gatewayPort)) continue;
11271
10457
  try {
11272
10458
  const data = await api.post("/host/direct-chat/poll", { agent_id: agent.agentId });
11273
10459
  for (const msg of data.messages) {
@@ -11332,51 +10518,7 @@ ${escapeXml(msg.content)}
11332
10518
  }
11333
10519
  log(`[direct-chat] Inject reported unverified for '${agent.codeName}' (msg=${msg.id}) \u2014 leaving pending for durable replay`);
11334
10520
  }
11335
- if (fw === "claude-code") {
11336
- log(`[direct-chat] No in-session delivery for '${agent.codeName}' (msg=${msg.id}) \u2014 leaving pending for ENG-5927 durable replay`);
11337
- return;
11338
- }
11339
- try {
11340
- const { stdout } = await execFilePromiseLong("openclaw", [
11341
- "--profile",
11342
- agent.codeName,
11343
- "agent",
11344
- "--local",
11345
- "--agent",
11346
- agent.codeName,
11347
- "--message",
11348
- msg.content,
11349
- "--session-id",
11350
- msg.session_id,
11351
- "--json"
11352
- ]);
11353
- let reply;
11354
- try {
11355
- const parsed = JSON.parse(stdout);
11356
- const payloads = parsed?.payloads ?? parsed?.result?.payloads;
11357
- reply = payloads?.[0]?.text ?? parsed?.reply ?? parsed?.text ?? parsed?.message ?? stdout;
11358
- } catch {
11359
- reply = stdout.trim() || "[No response from agent]";
11360
- }
11361
- await api.post("/host/direct-chat/reply", {
11362
- agent_id: agent.agentId,
11363
- session_id: msg.session_id,
11364
- content: reply
11365
- });
11366
- log(`[direct-chat] Reply sent for '${agent.codeName}'`);
11367
- } catch (err) {
11368
- const errMsg = err instanceof Error ? err.message : String(err);
11369
- const errorId = createHash10("sha256").update(errMsg).digest("hex").slice(0, 12);
11370
- log(`[direct-chat] Failed to process message for '${agent.codeName}': error_id=${errorId} error=${errMsg.slice(0, 500)}`);
11371
- try {
11372
- await api.post("/host/direct-chat/reply", {
11373
- agent_id: agent.agentId,
11374
- session_id: msg.session_id,
11375
- content: `[Error] Failed to process message (ref: ${errorId}). Please retry.`
11376
- });
11377
- } catch {
11378
- }
11379
- }
10521
+ log(`[direct-chat] No in-session delivery for '${agent.codeName}' (msg=${msg.id}) \u2014 leaving pending for ENG-5927 durable replay`);
11380
10522
  }
11381
10523
  var lastKanbanInjectAt = /* @__PURE__ */ new Map();
11382
10524
  var openInjectedRunByCode = /* @__PURE__ */ new Map();
@@ -11480,205 +10622,6 @@ var lastHarvestAt = /* @__PURE__ */ new Map();
11480
10622
  var HARVEST_INTERVAL_MS = 3 * 60 * 1e3;
11481
10623
  var kanbanBoardCache = /* @__PURE__ */ new Map();
11482
10624
  var notifyBoardCache = /* @__PURE__ */ new Map();
11483
- async function harvestCronResults(codeName, tasks, gatewayPort) {
11484
- const token = readGatewayToken(codeName);
11485
- const gwArgs = ["--url", `ws://127.0.0.1:${gatewayPort}`, ...token ? ["--token", token] : []];
11486
- let gatewayJobs = [];
11487
- try {
11488
- const cliBin = resolveAgentFramework(codeName).cliBinary ?? "claude";
11489
- const { stdout } = await execFilePromise(cliBin, ["--profile", codeName, "cron", "list", "--json", ...gwArgs]);
11490
- const parsed = JSON.parse(stdout);
11491
- gatewayJobs = parsed.jobs ?? [];
11492
- } catch {
11493
- return;
11494
- }
11495
- const jobTemplateMap = /* @__PURE__ */ new Map();
11496
- for (const job of gatewayJobs) {
11497
- if (!job.name.startsWith("aug:")) continue;
11498
- const parts = job.name.split(":");
11499
- if (parts.length >= 3) {
11500
- jobTemplateMap.set(job.id, parts[1]);
11501
- }
11502
- }
11503
- for (const [jobId, templateId] of jobTemplateMap) {
11504
- if (!STANDUP_TEMPLATES.has(templateId) && !TASK_UPDATE_TEMPLATES.has(templateId) && !PLAN_TEMPLATES.has(templateId) && !KANBAN_WORK_TEMPLATES.has(templateId)) continue;
11505
- let runs = [];
11506
- try {
11507
- const cliBin2 = resolveAgentFramework(codeName).cliBinary ?? "claude";
11508
- const { stdout } = await execFilePromise(cliBin2, ["--profile", codeName, "cron", "runs", "--id", jobId, ...gwArgs]);
11509
- const parsed = JSON.parse(stdout);
11510
- runs = parsed.entries ?? [];
11511
- } catch {
11512
- continue;
11513
- }
11514
- const latestRun = runs.filter((r) => r.action === "finished").sort((a, b) => b.ts - a.ts)[0];
11515
- if (latestRun) {
11516
- const agentId = agentState.codeNameToAgentId.get(codeName);
11517
- const summary = latestRun.summary ?? "";
11518
- 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");
11519
- if (agentId) {
11520
- if (latestRun.status === "error" && isKeyError) {
11521
- const errorMsg = summary.slice(0, 200);
11522
- if (!apiKeyStatusCache.get(codeName)) {
11523
- apiKeyStatusCache.set(codeName, true);
11524
- api.post("/host/agent-api-key-status", { agent_id: agentId, status: "rate_limited", error: errorMsg }).catch(() => {
11525
- });
11526
- log(`API key error detected for '${codeName}': ${errorMsg}`);
11527
- }
11528
- } else if (latestRun.status === "ok" && apiKeyStatusCache.get(codeName)) {
11529
- apiKeyStatusCache.delete(codeName);
11530
- api.post("/host/agent-api-key-status", { agent_id: agentId, status: null, error: null }).catch(() => {
11531
- });
11532
- log(`API key status cleared for '${codeName}' \u2014 run succeeded`);
11533
- }
11534
- }
11535
- }
11536
- const completed = runs.filter((r) => r.action === "finished" && r.status === "ok" && r.summary).sort((a, b) => b.ts - a.ts);
11537
- if (completed.length === 0) continue;
11538
- const latest = completed[0];
11539
- const lastSeen = lastCronRunTs.get(jobId) ?? 0;
11540
- if (latest.ts <= lastSeen) continue;
11541
- lastCronRunTs.set(jobId, latest.ts);
11542
- const statusUpdate = { agent_code_name: codeName };
11543
- if (STANDUP_TEMPLATES.has(templateId)) {
11544
- const summary = latest.summary ?? "";
11545
- statusUpdate.standup = parseStandupSummary(summary);
11546
- }
11547
- if (TASK_UPDATE_TEMPLATES.has(templateId)) {
11548
- statusUpdate.current_tasks = latest.summary ?? "";
11549
- }
11550
- if (statusUpdate.standup || statusUpdate.current_tasks !== void 0) {
11551
- try {
11552
- await api.post("/host/agent-status", statusUpdate);
11553
- log(`Updated ${templateId} for '${codeName}' from cron result`);
11554
- } catch (err) {
11555
- log(`Failed to update ${templateId} for '${codeName}': ${err.message}`);
11556
- }
11557
- }
11558
- if (PLAN_TEMPLATES.has(templateId)) {
11559
- const summary = latest.summary ?? "";
11560
- const planItems = parsePlanItems(summary);
11561
- if (planItems.length > 0) {
11562
- try {
11563
- const agentId = agentState.codeNameToAgentId.get(codeName);
11564
- if (agentId) {
11565
- await api.post("/host/kanban", {
11566
- agent_id: agentId,
11567
- add: planItems,
11568
- archive_days: 7
11569
- });
11570
- log(`Added ${planItems.length} kanban items for '${codeName}' from morning-plan`);
11571
- }
11572
- } catch (err) {
11573
- log(`Failed to update kanban for '${codeName}': ${err.message}`);
11574
- }
11575
- }
11576
- }
11577
- if (TASK_UPDATE_TEMPLATES.has(templateId) || KANBAN_WORK_TEMPLATES.has(templateId)) {
11578
- const summary = latest.summary ?? "";
11579
- const kanbanUpdates = parseKanbanUpdates(summary);
11580
- if (kanbanUpdates.length > 0) {
11581
- try {
11582
- const agentId = agentState.codeNameToAgentId.get(codeName);
11583
- if (agentId) {
11584
- await api.post("/host/kanban", {
11585
- agent_id: agentId,
11586
- update: kanbanUpdates
11587
- });
11588
- log(`Updated ${kanbanUpdates.length} kanban items for '${codeName}'`);
11589
- }
11590
- } catch (err) {
11591
- log(`Failed to update kanban for '${codeName}': ${err.message}`);
11592
- }
11593
- }
11594
- }
11595
- }
11596
- }
11597
- var LATE_THRESHOLD_MS = 5 * 60 * 1e3;
11598
- async function monitorCronHealth(agentStates) {
11599
- const alerts = [];
11600
- const now = Date.now();
11601
- for (const agent of agentStates) {
11602
- if (!agent.gatewayRunning || !agent.gatewayPort) continue;
11603
- const token = readGatewayToken(agent.codeName);
11604
- const gwArgs = ["--url", `ws://127.0.0.1:${agent.gatewayPort}`, ...token ? ["--token", token] : []];
11605
- let jobs = [];
11606
- try {
11607
- const cliBin = resolveAgentFramework(agent.codeName).cliBinary ?? "claude";
11608
- const { stdout } = await execFilePromise(cliBin, ["--profile", agent.codeName, "cron", "list", "--json", ...gwArgs]);
11609
- const parsed = JSON.parse(stdout);
11610
- jobs = parsed.jobs ?? [];
11611
- } catch {
11612
- continue;
11613
- }
11614
- for (const job of jobs) {
11615
- if (!job.enabled || !job.name.startsWith("aug:")) continue;
11616
- const alertKey = `${agent.codeName}:${job.id}`;
11617
- const displayInfo = taskDisplayInfo.get(`${agent.codeName}:${job.name}`);
11618
- const taskName = displayInfo?.taskName ?? job.name;
11619
- const schedule = displayInfo?.schedule ?? "";
11620
- const agentDisplayName = displayInfo?.agentDisplayName ?? agent.codeName;
11621
- if (job.state?.nextRunAtMs && job.state.nextRunAtMs + LATE_THRESHOLD_MS < now) {
11622
- if (!alertedJobs.has(`late:${alertKey}`)) {
11623
- const minsLate = Math.round((now - job.state.nextRunAtMs) / 6e4);
11624
- alerts.push({
11625
- type: "late_standup",
11626
- agentCodeName: agent.codeName,
11627
- agentDisplayName,
11628
- jobName: job.name,
11629
- taskName,
11630
- schedule,
11631
- jobId: job.id,
11632
- detail: `Job is ${minsLate}m late (expected at ${new Date(job.state.nextRunAtMs).toISOString()})`
11633
- });
11634
- alertedJobs.add(`late:${alertKey}`);
11635
- }
11636
- } else {
11637
- alertedJobs.delete(`late:${alertKey}`);
11638
- }
11639
- if (job.state?.lastRunStatus === "error" || job.state?.consecutiveErrors && job.state.consecutiveErrors > 0) {
11640
- if (!alertedJobs.has(`fail:${alertKey}`)) {
11641
- alerts.push({
11642
- type: "cron_failure",
11643
- agentCodeName: agent.codeName,
11644
- agentDisplayName,
11645
- jobName: job.name,
11646
- taskName,
11647
- schedule,
11648
- jobId: job.id,
11649
- detail: `Last run failed (${job.state.consecutiveErrors ?? 1} consecutive error(s))`
11650
- });
11651
- alertedJobs.add(`fail:${alertKey}`);
11652
- }
11653
- } else {
11654
- alertedJobs.delete(`fail:${alertKey}`);
11655
- }
11656
- }
11657
- }
11658
- if (alerts.length === 0) return;
11659
- for (const alert of alerts) {
11660
- log(`ALERT [${alert.type}] ${alert.agentCodeName}/${alert.jobName}: ${alert.detail}`);
11661
- }
11662
- if (getAlertSlackWebhook()) {
11663
- await sendSlackAlert(alerts);
11664
- }
11665
- try {
11666
- await api.post("/host/cron-alerts", { alerts });
11667
- } catch {
11668
- }
11669
- }
11670
- async function sendSlackAlert(alerts) {
11671
- const blocks = alerts.map((a) => {
11672
- const emoji = a.type === "late_standup" ? ":warning:" : ":x:";
11673
- const label = a.type === "late_standup" ? "Late" : "Failed";
11674
- const scheduleInfo = a.schedule ? ` (${a.schedule})` : "";
11675
- return `${emoji} *${label}* \u2014 *${a.agentDisplayName}* / ${a.taskName}${scheduleInfo}
11676
- ${a.detail}`;
11677
- });
11678
- await sendSlackWebhookMessage(`:rotating_light: *Cron Health Alert*
11679
-
11680
- ${blocks.join("\n\n")}`);
11681
- }
11682
10625
  var spawnedPairIds = /* @__PURE__ */ new Set();
11683
10626
  async function processClaudePairSessions(agents) {
11684
10627
  if (agents.length === 0 && spawnedPairIds.size === 0) return;
@@ -11695,7 +10638,7 @@ async function processClaudePairSessions(agents) {
11695
10638
  killPairSession,
11696
10639
  pairTmuxSession,
11697
10640
  finalizeClaudePairOnboarding
11698
- } = await import("../claude-pair-runtime-SEFGHAXC.js");
10641
+ } = await import("../claude-pair-runtime-XIVBNVSR.js");
11699
10642
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
11700
10643
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
11701
10644
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -11877,7 +10820,6 @@ function generateArtifacts(agent, refreshData, adapter) {
11877
10820
  toolsContent,
11878
10821
  resolvedChannels: effectiveChannels,
11879
10822
  deploymentTarget: "local_docker",
11880
- gatewayPort: 9e3,
11881
10823
  team: refreshData.team ?? void 0,
11882
10824
  activeTasks: activeTasksFromRefresh,
11883
10825
  // ENG-5009: org name for the identity-preamble. Only present when
@@ -12074,41 +11016,6 @@ async function cleanupAgentFiles(codeName, agentDir) {
12074
11016
  log(`Failed to deregister '${codeName}': ${err.message}`);
12075
11017
  }
12076
11018
  }
12077
- function startGatewayPool() {
12078
- if (gatewayPool) return;
12079
- gatewayPool = new GatewayClientPool();
12080
- gatewayPool.on("connected", (codeName) => {
12081
- log(`Gateway WebSocket connected for '${codeName}'`);
12082
- });
12083
- gatewayPool.on("disconnected", (codeName) => {
12084
- log(`Gateway WebSocket disconnected for '${codeName}'`);
12085
- });
12086
- gatewayPool.on("error", (err, codeName) => {
12087
- log(`Gateway WebSocket error for '${codeName}': ${err.message}`);
12088
- });
12089
- gatewayPool.on("event", (evt) => {
12090
- send({ type: "gateway-event", event: evt.event, payload: evt.payload, agentCodeName: evt.agentCodeName });
12091
- getHostId().then((hostId) => {
12092
- if (!hostId) return;
12093
- api.post("/host/events", {
12094
- host_id: hostId,
12095
- agent_code_name: evt.agentCodeName,
12096
- event_type: evt.event,
12097
- payload: evt.payload,
12098
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
12099
- }).catch((err) => {
12100
- log(`Failed to forward gateway event: ${err.message}`);
12101
- });
12102
- }).catch(() => {
12103
- });
12104
- });
12105
- }
12106
- function stopGatewayPool() {
12107
- if (gatewayPool) {
12108
- gatewayPool.disconnectAll();
12109
- gatewayPool = null;
12110
- }
12111
- }
12112
11019
  var caffeinateProc = null;
12113
11020
  async function startCaffeinate() {
12114
11021
  if (process.platform !== "darwin") return;
@@ -12183,8 +11090,7 @@ function startPolling() {
12183
11090
  hostFlagStore().init();
12184
11091
  log(`Starting poll loop (interval=${config.intervalMs}ms, configDir=${config.configDir})`);
12185
11092
  void killAllAgtTmuxSessions().catch(() => {
12186
- }).then(() => migrateToProfiles()).then(() => {
12187
- startGatewayPool();
11093
+ }).then(() => {
12188
11094
  return pollCycle();
12189
11095
  }).then(() => {
12190
11096
  void driveArtifactStreaming();
@@ -12287,7 +11193,6 @@ async function stopPolling(opts = {}) {
12287
11193
  const subsysStartedAt = Date.now();
12288
11194
  stopCaffeinate();
12289
11195
  stopRealtimeChat();
12290
- stopGatewayPool();
12291
11196
  log(formatDrainShutdownLine({ step: "stop-subsystems", elapsedMs: Date.now() - subsysStartedAt }));
12292
11197
  for (const codeName of [...scheduledRunsByCode.keys()]) {
12293
11198
  closeScheduledRunsForCode(codeName, "cancelled", "manager shutdown");
@@ -12296,8 +11201,6 @@ async function stopPolling(opts = {}) {
12296
11201
  await killAllAgtTmuxSessions();
12297
11202
  log("Stopping persistent sessions...");
12298
11203
  await stopAllSessionsAndWait(log, { timeoutMs: 4e3 });
12299
- log("Stopping gateway processes...");
12300
- await stopAllGateways();
12301
11204
  clearTimeout(shutdownTimer);
12302
11205
  }
12303
11206
  function startManager(opts) {