@cfio/cohort-sync 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11700,14 +11700,16 @@ async function executeCommand(cmd, gwClient, cfg, resolveAgentName, logger) {
11700
11700
  throw new Error(`Cron message exceeds maximum length of ${MAX_CRON_MESSAGE_LENGTH} characters`);
11701
11701
  }
11702
11702
  if (cmd.type === "restart") {
11703
- if (gwClient && gwClient.isAlive()) {
11704
- logger.warn(`cohort-sync: RESTART command received (id=${cmd._id}), issuing graceful gateway restart`);
11705
- await gwClient.request("gateway.restart", { reason: "Cohort restart command" });
11706
- } else {
11707
- logger.warn(`cohort-sync: RESTART command received (id=${cmd._id}), no gateway client \u2014 falling back to SIGTERM`);
11708
- await new Promise((r) => setTimeout(r, 500));
11709
- process.kill(process.pid, "SIGTERM");
11703
+ if (cfg.commandsRestartEnabled !== true) {
11704
+ throw new Error(
11705
+ "Gateway restart is not authorized. Set `commands.restart: true` in your OpenClaw config and restart the gateway once. See https://docs.cohort.bot/gateway/restart"
11706
+ );
11710
11707
  }
11708
+ logger.warn(
11709
+ `cohort-sync: RESTART command received (id=${cmd._id}), sending SIGUSR1 for graceful in-process restart`
11710
+ );
11711
+ await new Promise((r) => setTimeout(r, 500));
11712
+ process.kill(process.pid, "SIGUSR1");
11711
11713
  return;
11712
11714
  }
11713
11715
  if (cmd.type.startsWith("cron")) {
@@ -13370,7 +13372,7 @@ function dumpCtx(ctx) {
13370
13372
  function dumpEvent(event) {
13371
13373
  return dumpCtx(event);
13372
13374
  }
13373
- var PLUGIN_VERSION = true ? "0.13.0" : "unknown";
13375
+ var PLUGIN_VERSION = true ? "0.15.0" : "unknown";
13374
13376
  function resolveGatewayToken(api) {
13375
13377
  const token = api.config?.gateway?.auth?.token;
13376
13378
  return typeof token === "string" ? token : null;
@@ -13576,7 +13578,7 @@ async function handleGatewayStart(event, state) {
13576
13578
  tracker.updateStatus(agentName, "idle");
13577
13579
  const snapshot = tracker.getTelemetrySnapshot(agentName);
13578
13580
  if (snapshot) {
13579
- await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13581
+ await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, commandsRestartEnabled: cfg.commandsRestartEnabled, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13580
13582
  tracker.markTelemetryPushed(agentName);
13581
13583
  }
13582
13584
  } catch (err) {
@@ -13590,7 +13592,7 @@ async function handleGatewayStart(event, state) {
13590
13592
  const agentName = state.resolveAgentName(agentId);
13591
13593
  const snapshot = tracker.getTelemetrySnapshot(agentName);
13592
13594
  if (snapshot) {
13593
- await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} }).catch(() => {
13595
+ await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, commandsRestartEnabled: cfg.commandsRestartEnabled, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} }).catch(() => {
13594
13596
  });
13595
13597
  }
13596
13598
  }
@@ -13668,7 +13670,7 @@ function registerHookHandlers(api, logger, getState) {
13668
13670
  if (tracker.shouldPushTelemetry(agentName)) {
13669
13671
  const snapshot = tracker.getTelemetrySnapshot(agentName);
13670
13672
  if (snapshot) {
13671
- await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13673
+ await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, commandsRestartEnabled: cfg.commandsRestartEnabled, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13672
13674
  tracker.markTelemetryPushed(agentName);
13673
13675
  }
13674
13676
  }
@@ -13730,7 +13732,7 @@ function registerHookHandlers(api, logger, getState) {
13730
13732
  if (tracker.shouldPushTelemetry(agentName)) {
13731
13733
  const snapshot = tracker.getTelemetrySnapshot(agentName);
13732
13734
  if (snapshot) {
13733
- await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13735
+ await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, commandsRestartEnabled: cfg.commandsRestartEnabled, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13734
13736
  tracker.markTelemetryPushed(agentName);
13735
13737
  }
13736
13738
  }
@@ -13758,7 +13760,7 @@ function registerHookHandlers(api, logger, getState) {
13758
13760
  if (tracker.shouldPushTelemetry(agentName)) {
13759
13761
  const snapshot = tracker.getTelemetrySnapshot(agentName);
13760
13762
  if (snapshot) {
13761
- await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13763
+ await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, commandsRestartEnabled: cfg.commandsRestartEnabled, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13762
13764
  tracker.markTelemetryPushed(agentName);
13763
13765
  }
13764
13766
  }
@@ -13800,7 +13802,7 @@ function registerHookHandlers(api, logger, getState) {
13800
13802
  if (tracker.shouldPushTelemetry(agentName)) {
13801
13803
  const snapshot = tracker.getTelemetrySnapshot(agentName);
13802
13804
  if (snapshot) {
13803
- await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13805
+ await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, commandsRestartEnabled: cfg.commandsRestartEnabled, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
13804
13806
  tracker.markTelemetryPushed(agentName);
13805
13807
  }
13806
13808
  }
@@ -13986,28 +13988,36 @@ function registerHookHandlers(api, logger, getState) {
13986
13988
  state.logger.warn(`cohort-sync: before_reset activity failed: ${String(err)}`);
13987
13989
  }
13988
13990
  });
13989
- api.on("gateway_stop", async (_event, _ctx) => {
13991
+ api.on("gateway_stop", async (event, _ctx) => {
13990
13992
  const state = getState();
13991
13993
  if (!state) return;
13992
13994
  const { cfg, tracker, logger: log, config } = state;
13993
- log.debug("cohort-sync: hook: gateway_stop", { bridgeState: Object.fromEntries(getChannelAgentBridge()) });
13995
+ const reason = typeof event?.reason === "string" ? event.reason : "";
13996
+ const isRestart = reason.toLowerCase().includes("restart");
13997
+ log.debug("cohort-sync: hook: gateway_stop", {
13998
+ reason,
13999
+ isRestart,
14000
+ bridgeState: Object.fromEntries(getChannelAgentBridge())
14001
+ });
13994
14002
  if (state.keepaliveInterval) {
13995
14003
  clearInterval(state.keepaliveInterval);
13996
14004
  state.keepaliveInterval = null;
13997
14005
  }
13998
14006
  state.activityBatch.drain();
13999
- const shutdownConfigIds = (config?.agents?.list ?? []).map((a) => a.id);
14000
- const allAgentIds = shutdownConfigIds.includes("main") ? shutdownConfigIds : ["main", ...shutdownConfigIds];
14001
- for (const agentId of allAgentIds) {
14002
- const agentName = state.resolveAgentName(agentId);
14003
- try {
14004
- tracker.updateStatus(agentName, "unreachable");
14005
- const snapshot = tracker.getTelemetrySnapshot(agentName);
14006
- if (snapshot) {
14007
- await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
14007
+ if (!isRestart) {
14008
+ const shutdownConfigIds = (config?.agents?.list ?? []).map((a) => a.id);
14009
+ const allAgentIds = shutdownConfigIds.includes("main") ? shutdownConfigIds : ["main", ...shutdownConfigIds];
14010
+ for (const agentId of allAgentIds) {
14011
+ const agentName = state.resolveAgentName(agentId);
14012
+ try {
14013
+ tracker.updateStatus(agentName, "unreachable");
14014
+ const snapshot = tracker.getTelemetrySnapshot(agentName);
14015
+ if (snapshot) {
14016
+ await pushTelemetry(cfg.apiKey, { ...snapshot, pluginVersion: PLUGIN_VERSION, commandsRestartEnabled: cfg.commandsRestartEnabled, ...state.latestPluginVersion ? { latestPluginVersion: state.latestPluginVersion } : {} });
14017
+ }
14018
+ } catch (err) {
14019
+ log.warn(`cohort-sync: final unreachable push failed for ${agentName}: ${String(err)}`);
14008
14020
  }
14009
- } catch (err) {
14010
- log.warn(`cohort-sync: final unreachable push failed for ${agentName}: ${String(err)}`);
14011
14021
  }
14012
14022
  }
14013
14023
  saveSessionsToDisk(tracker, state.stateFilePath);
@@ -14016,14 +14026,18 @@ function registerHookHandlers(api, logger, getState) {
14016
14026
  state.persistentGwClient = null;
14017
14027
  state.gwClientInitialized = false;
14018
14028
  }
14019
- try {
14020
- await markAllUnreachable(cfg, log);
14021
- } catch (err) {
14022
- log.warn(`cohort-sync: markAllUnreachable failed: ${String(err)}`);
14029
+ if (!isRestart) {
14030
+ try {
14031
+ await markAllUnreachable(cfg, log);
14032
+ } catch (err) {
14033
+ log.warn(`cohort-sync: markAllUnreachable failed: ${String(err)}`);
14034
+ }
14023
14035
  }
14024
14036
  tracker.clear();
14025
14037
  closeBridge();
14026
- log.info("cohort-sync: gateway stopped, all resources cleaned up");
14038
+ log.info(
14039
+ isRestart ? "cohort-sync: gateway restarting, resources cleaned up (agents kept online)" : "cohort-sync: gateway stopped, all resources cleaned up"
14040
+ );
14027
14041
  });
14028
14042
  }
14029
14043
  function initializeHookState(api, cfg) {
@@ -14475,11 +14489,13 @@ Do not attempt more comments until tomorrow.`);
14475
14489
  }
14476
14490
  api.logger.info(`cohort-sync: activated (api: ${apiUrl2})`);
14477
14491
  if (!sharedHookState) {
14492
+ const commandsRestartEnabled = api.config?.commands?.restart === true;
14478
14493
  sharedHookState = initializeHookState(api, {
14479
14494
  apiUrl: apiUrl2,
14480
14495
  apiKey: apiKey2,
14481
14496
  stateDir: svcCtx.stateDir,
14482
- agentNameMap: cfg?.agentNameMap
14497
+ agentNameMap: cfg?.agentNameMap,
14498
+ commandsRestartEnabled
14483
14499
  });
14484
14500
  }
14485
14501
  },
@@ -55,5 +55,5 @@
55
55
  }
56
56
  }
57
57
  },
58
- "version": "0.13.0"
58
+ "version": "0.15.0"
59
59
  }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfio/cohort-sync",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "OpenClaw plugin — syncs agent telemetry, sessions, and activity to the Cohort dashboard",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfio/cohort-sync",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "OpenClaw plugin — syncs agent telemetry, sessions, and activity to the Cohort dashboard",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.cohort.bot/gateway",