@okxweb3/a2a-node 0.2.3 → 0.2.4-beta-e7a52faf6f-260811185020

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.
Files changed (3) hide show
  1. package/dist/cli.js +286 -109
  2. package/dist/index.js +279 -98
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -26604,7 +26604,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
26604
26604
  client: {
26605
26605
  id: "gateway-client",
26606
26606
  displayName: "okx-a2a-node",
26607
- version: "0.2.3",
26607
+ version: "0.2.4-beta-e7a52faf6f-260811185020",
26608
26608
  platform: "node",
26609
26609
  mode: "backend",
26610
26610
  instanceId
@@ -26615,7 +26615,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
26615
26615
  commands: [],
26616
26616
  permissions: {},
26617
26617
  locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
26618
- userAgent: `okx-a2a-node/${"0.2.3"}`,
26618
+ userAgent: `okx-a2a-node/${"0.2.4-beta-e7a52faf6f-260811185020"}`,
26619
26619
  auth: {
26620
26620
  ...config.token ? { token: config.token } : {},
26621
26621
  ...config.password ? { password: config.password } : {}
@@ -28499,7 +28499,7 @@ var init_sentry_config = __esm({
28499
28499
  environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
28500
28500
  SENTRY_CONFIG = {
28501
28501
  projectName: "okx/openclaw-okx-a2a-extension",
28502
- release: "0.2.3",
28502
+ release: "0.2.4-beta-e7a52faf6f-260811185020",
28503
28503
  environment,
28504
28504
  runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
28505
28505
  };
@@ -39669,7 +39669,7 @@ async function exportDiagnosticLogs(options) {
39669
39669
  node: process.version,
39670
39670
  platform: process.platform,
39671
39671
  arch: process.arch,
39672
- packageVersion: true ? "0.2.3" : "unknown",
39672
+ packageVersion: true ? "0.2.4-beta-e7a52faf6f-260811185020" : "unknown",
39673
39673
  sensitiveContentIncluded: options.includeSensitiveContent,
39674
39674
  listenerAndLlmContentIncluded: true,
39675
39675
  credentialsAlwaysRedacted: true,
@@ -56122,6 +56122,69 @@ var init_installation_prune = __esm({
56122
56122
  }
56123
56123
  });
56124
56124
 
56125
+ // ../core/src/xmtp-sdk/onchainos/session-expired.ts
56126
+ function isSessionExpired(stdout) {
56127
+ try {
56128
+ const res = JSON.parse(stdout);
56129
+ return res.ok === false && SESSION_EXPIRED_RE.test(String(res.error ?? ""));
56130
+ } catch {
56131
+ return SESSION_EXPIRED_RE.test(stdout);
56132
+ }
56133
+ }
56134
+ function classifyOnchainosAuthError(err2) {
56135
+ if (!err2) {
56136
+ return null;
56137
+ }
56138
+ const values = [String(err2)];
56139
+ if (typeof err2 === "object") {
56140
+ const anyErr = err2;
56141
+ values.push(anyErr.stdout, anyErr.stderr, anyErr.message);
56142
+ }
56143
+ for (const value of values) {
56144
+ if (typeof value !== "string") {
56145
+ continue;
56146
+ }
56147
+ for (const [reason, pattern] of AUTH_FAILURE_PATTERNS) {
56148
+ if (pattern.test(value)) {
56149
+ return reason;
56150
+ }
56151
+ }
56152
+ }
56153
+ return null;
56154
+ }
56155
+ function isOnchainosAuthError(err2) {
56156
+ return classifyOnchainosAuthError(err2) !== null;
56157
+ }
56158
+ function reportSessionExpired(command) {
56159
+ logger.error(
56160
+ LogEvent.ONCHAINOS_SESSION_EXPIRED,
56161
+ new Error("onchainos session expired"),
56162
+ {
56163
+ component: "onchainos_cli",
56164
+ source: "onchainos",
56165
+ stage: "session_expired",
56166
+ operation: command,
56167
+ command,
56168
+ communicationClass: "onchainos_auth_issue",
56169
+ reason: "session_expired"
56170
+ }
56171
+ );
56172
+ }
56173
+ var SESSION_EXPIRED_RE, AUTH_FAILURE_PATTERNS;
56174
+ var init_session_expired = __esm({
56175
+ "../core/src/xmtp-sdk/onchainos/session-expired.ts"() {
56176
+ "use strict";
56177
+ init_sentry_logger();
56178
+ SESSION_EXPIRED_RE = /session expired/i;
56179
+ AUTH_FAILURE_PATTERNS = [
56180
+ ["session_expired", /session expired/i],
56181
+ ["not_logged_in", /not logged in/i],
56182
+ ["login_required", /login required/i],
56183
+ ["authentication_required", /authentication required/i]
56184
+ ];
56185
+ }
56186
+ });
56187
+
56125
56188
  // ../core/src/xmtp-sdk/index.ts
56126
56189
  function cachePath(dataDir, fileName) {
56127
56190
  return (0, import_node_path26.join)(dataDir, fileName);
@@ -56149,21 +56212,6 @@ function stringifyJsonForLog(value) {
56149
56212
  function ensureCacheDir(dataDir) {
56150
56213
  ensureA2aTaskDir(dataDir);
56151
56214
  }
56152
- function isSessionExpiredError(err2) {
56153
- if (!err2) {
56154
- return false;
56155
- }
56156
- if (typeof err2 === "object") {
56157
- const anyErr = err2;
56158
- if (typeof anyErr.stdout === "string" && SESSION_EXPIRED_RE.test(anyErr.stdout)) {
56159
- return true;
56160
- }
56161
- if (typeof anyErr.message === "string" && SESSION_EXPIRED_RE.test(anyErr.message)) {
56162
- return true;
56163
- }
56164
- }
56165
- return SESSION_EXPIRED_RE.test(String(err2));
56166
- }
56167
56215
  function loadSensitiveWordsFromCache(dataDir) {
56168
56216
  try {
56169
56217
  const path2 = cachePath(dataDir, "sensitive-words.json");
@@ -56541,7 +56589,7 @@ function createOfflineReplayAddressSummary(address) {
56541
56589
  durationMs: 0
56542
56590
  };
56543
56591
  }
56544
- var import_node_fs22, import_node_path26, DEFAULT_DATA_DIR, XMTP_INSTALLATION_WARNING_THRESHOLD, XMTP_INSTALLATION_NEAR_LIMIT_THRESHOLD, REPLAY_SCAN_INITIAL_BACKOFF_MS, REPLAY_SCAN_MAX_BACKOFF_MS, SENSITIVE_WORDS_LAZY_RETRY_COOLDOWN_MS, SESSION_EXPIRED_RE, InboundReplayGate, SYSTEM_CONFIG_DEFAULTS, STREAM_RECOVERY_ALERT_THRESHOLD_MS, REPLAY_GATE_DRAIN_MAX_ATTEMPTS, REPLAY_GATE_DRAIN_RETRY_DELAY_MS, SEMVER_RE, isRecord5, isPositiveNumber, SYSTEM_CONFIG_VALIDATORS, XmtpService;
56592
+ var import_node_fs22, import_node_path26, DEFAULT_DATA_DIR, XMTP_INSTALLATION_WARNING_THRESHOLD, XMTP_INSTALLATION_NEAR_LIMIT_THRESHOLD, REPLAY_SCAN_INITIAL_BACKOFF_MS, REPLAY_SCAN_MAX_BACKOFF_MS, SENSITIVE_WORDS_LAZY_RETRY_COOLDOWN_MS, InboundReplayGate, SYSTEM_CONFIG_DEFAULTS, STREAM_RECOVERY_ALERT_THRESHOLD_MS, REPLAY_GATE_DRAIN_MAX_ATTEMPTS, REPLAY_GATE_DRAIN_RETRY_DELAY_MS, SEMVER_RE, isRecord5, isPositiveNumber, SYSTEM_CONFIG_VALIDATORS, XmtpService;
56545
56593
  var init_xmtp_sdk = __esm({
56546
56594
  "../core/src/xmtp-sdk/index.ts"() {
56547
56595
  "use strict";
@@ -56559,13 +56607,13 @@ var init_xmtp_sdk = __esm({
56559
56607
  init_concurrency();
56560
56608
  init_a2a_paths();
56561
56609
  init_installation_prune();
56610
+ init_session_expired();
56562
56611
  DEFAULT_DATA_DIR = resolveA2aTaskPaths().xmtpDir;
56563
56612
  XMTP_INSTALLATION_WARNING_THRESHOLD = 2;
56564
56613
  XMTP_INSTALLATION_NEAR_LIMIT_THRESHOLD = 8;
56565
56614
  REPLAY_SCAN_INITIAL_BACKOFF_MS = 3e4;
56566
56615
  REPLAY_SCAN_MAX_BACKOFF_MS = 5 * 6e4;
56567
56616
  SENSITIVE_WORDS_LAZY_RETRY_COOLDOWN_MS = 10 * 60 * 1e3;
56568
- SESSION_EXPIRED_RE = /session expired/i;
56569
56617
  InboundReplayGate = class {
56570
56618
  constructor(inbound) {
56571
56619
  this.inbound = inbound;
@@ -57131,12 +57179,14 @@ var init_xmtp_sdk = __esm({
57131
57179
  newAgents = agentList.agents;
57132
57180
  changed = agentList.changed;
57133
57181
  } catch (err2) {
57134
- if (isSessionExpiredError(err2)) {
57182
+ const authFailureReason = classifyOnchainosAuthError(err2);
57183
+ if (authFailureReason) {
57135
57184
  logWithTimestamp(
57136
- "[xmtp-sdk] refresh: onchainos session expired, taking all local clients offline"
57185
+ `[xmtp-sdk] refresh: onchainos auth unavailable (${authFailureReason}), taking all local clients offline`
57137
57186
  );
57138
57187
  logger.info(LogEvent.AGENT_REFRESH_SESSION_EXPIRED, {
57139
57188
  onchainosAgentId: "*",
57189
+ authFailureReason,
57140
57190
  previousClientCount: String(this.clients.size),
57141
57191
  previousAgentCount: String(this.allAgents.length),
57142
57192
  previousAgentIds: this.allAgents.map((a) => a.agentId).join(","),
@@ -58704,39 +58754,6 @@ var init_cli_response = __esm({
58704
58754
  }
58705
58755
  });
58706
58756
 
58707
- // ../core/src/xmtp-sdk/onchainos/session-expired.ts
58708
- function isSessionExpired(stdout) {
58709
- try {
58710
- const res = JSON.parse(stdout);
58711
- return res.ok === false && SESSION_EXPIRED_RE2.test(String(res.error ?? ""));
58712
- } catch {
58713
- return SESSION_EXPIRED_RE2.test(stdout);
58714
- }
58715
- }
58716
- function reportSessionExpired(command) {
58717
- logger.error(
58718
- LogEvent.ONCHAINOS_SESSION_EXPIRED,
58719
- new Error("onchainos session expired"),
58720
- {
58721
- component: "onchainos_cli",
58722
- source: "onchainos",
58723
- stage: "session_expired",
58724
- operation: command,
58725
- command,
58726
- communicationClass: "onchainos_auth_issue",
58727
- reason: "session_expired"
58728
- }
58729
- );
58730
- }
58731
- var SESSION_EXPIRED_RE2;
58732
- var init_session_expired = __esm({
58733
- "../core/src/xmtp-sdk/onchainos/session-expired.ts"() {
58734
- "use strict";
58735
- init_sentry_logger();
58736
- SESSION_EXPIRED_RE2 = /session expired/i;
58737
- }
58738
- });
58739
-
58740
58757
  // ../core/src/xmtp-sdk/onchainos/offline-replay-capability.ts
58741
58758
  function messageEligibleHelpAdvertisesOfflineReplay(helpText) {
58742
58759
  if (typeof helpText !== "string" || helpText.length === 0) {
@@ -59030,7 +59047,10 @@ async function fetchAgentPage(page) {
59030
59047
  );
59031
59048
  if (!res.ok) {
59032
59049
  guardSessionExpired2(stdout, "list-agents");
59033
- const parseErr = new Error("onchainos agent get failed");
59050
+ const detail = typeof res.error === "string" ? res.error.trim() : "";
59051
+ const parseErr = new Error(
59052
+ detail ? `onchainos agent get failed: ${detail}` : "onchainos agent get failed"
59053
+ );
59034
59054
  logger.error(
59035
59055
  LogEvent.ONCHAINOS_CLI_ERROR,
59036
59056
  parseErr,
@@ -64725,7 +64745,7 @@ async function handleDaemonCommand(command, params) {
64725
64745
  const payload = await handleXmtpDebugCommand(command, params.service);
64726
64746
  return { ok: true, payload };
64727
64747
  }
64728
- const refresh = await params.service.refreshAgents();
64748
+ const refresh = await (params.refreshAgents?.() ?? params.service.refreshAgents());
64729
64749
  return {
64730
64750
  ok: true,
64731
64751
  payload: {
@@ -67003,9 +67023,13 @@ var init_user_attention_watchers = __esm({
67003
67023
  // src/listener.ts
67004
67024
  var listener_exports = {};
67005
67025
  __export(listener_exports, {
67026
+ AgentRefreshAuthGate: () => AgentRefreshAuthGate,
67027
+ AgentRefreshCoordinator: () => AgentRefreshCoordinator,
67006
67028
  DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC: () => DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC,
67007
67029
  DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC: () => DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC,
67008
67030
  HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS: () => HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS,
67031
+ ListenerDeferredTaskScheduler: () => ListenerDeferredTaskScheduler,
67032
+ ListenerMaintenanceGate: () => ListenerMaintenanceGate,
67009
67033
  XMTP_CLIENT_RECYCLE_INTERVAL_ENV: () => XMTP_CLIENT_RECYCLE_INTERVAL_ENV,
67010
67034
  getHermesGatewayPluginStatus: () => getHermesGatewayPluginStatus,
67011
67035
  hermesConfigEnablesOkxA2a: () => hermesConfigEnablesOkxA2a,
@@ -67013,8 +67037,15 @@ __export(listener_exports, {
67013
67037
  isHermesGatewayPluginEnabled: () => isHermesGatewayPluginEnabled,
67014
67038
  resolveOfflineReplayIntervalSec: () => resolveOfflineReplayIntervalSec,
67015
67039
  resolveXmtpClientRecycleIntervalSec: () => resolveXmtpClientRecycleIntervalSec,
67040
+ runHeartbeatRefreshCycle: () => runHeartbeatRefreshCycle,
67016
67041
  runListener: () => runListener
67017
67042
  });
67043
+ async function runHeartbeatRefreshCycle(options) {
67044
+ const heartbeat = await timeSettled(options.heartbeat);
67045
+ const refreshAllowed = heartbeat.value === "performed" || heartbeat.value === "refresh_safe";
67046
+ const refresh = options.refresh && refreshAllowed ? await timeSettled(options.refresh) : void 0;
67047
+ return { heartbeat, refresh };
67048
+ }
67018
67049
  function resolveOfflineReplayIntervalSec(systemConfig) {
67019
67050
  const interval = systemConfig.offlineReplayInterval;
67020
67051
  if (typeof interval !== "number" || !Number.isFinite(interval) || interval <= 0) {
@@ -67212,10 +67243,24 @@ async function runListenerWithLock(options, paths) {
67212
67243
  }
67213
67244
  });
67214
67245
  logWithTimestamp("[okx-agent-task] user_attention watcher coordinator scanning SQLite watcher state");
67246
+ let stopping = false;
67215
67247
  const service = XmtpService.getInstance();
67248
+ const agentRefreshCoordinator = new AgentRefreshCoordinator({
67249
+ lookup: (previousFingerprint) => listAllAgentsWithMetadata(previousFingerprint),
67250
+ refresh: () => service.refreshAgents(),
67251
+ isStopping: () => stopping,
67252
+ onAuthBlocked: () => {
67253
+ logWithTimestamp(
67254
+ "[okx-agent-task] agent refresh auth blocked; periodic agent get paused. After wallet login, run `okx-a2a agent refresh` or restart the daemon"
67255
+ );
67256
+ },
67257
+ onAuthRecovered: () => {
67258
+ logWithTimestamp("[okx-agent-task] agent refresh auth recovered; periodic refresh resumed");
67259
+ }
67260
+ });
67216
67261
  service.setDataDir(paths.xmtpDir);
67217
67262
  service.setTools({
67218
- listAllAgentsWithMetadata: async (previousFingerprint) => listAllAgentsWithMetadata(previousFingerprint),
67263
+ listAllAgentsWithMetadata: (previousFingerprint) => agentRefreshCoordinator.lookup(previousFingerprint),
67219
67264
  fetchSensitiveWords: async () => fetchSensitiveWords(),
67220
67265
  fetchSystemConfig: async () => fetchSystemConfig({
67221
67266
  notifySessionExpired: (command) => service.tools.notifySessionExpired?.(command)
@@ -67242,7 +67287,7 @@ async function runListenerWithLock(options, paths) {
67242
67287
  }
67243
67288
  }),
67244
67289
  notifySessionExpired: (command) => {
67245
- const rawText = `The onchainos login session has expired while running ${command}. Run \`onchainos wallet login\` and restart \`okx-a2a\`.`;
67290
+ const rawText = `The onchainos login session has expired while running ${command}. Run \`onchainos wallet login\`, then \`okx-a2a agent refresh\` or restart \`okx-a2a\`.`;
67246
67291
  void store.appendBackup(buildSystemStoredMessage({
67247
67292
  reason: "onchainos-session-expired",
67248
67293
  rawText,
@@ -67270,12 +67315,12 @@ async function runListenerWithLock(options, paths) {
67270
67315
  });
67271
67316
  }
67272
67317
  });
67273
- service.setPluginVersion("0.2.3");
67318
+ service.setPluginVersion("0.2.4-beta-e7a52faf6f-260811185020");
67274
67319
  await service.init();
67275
67320
  const pluginVersionStatus = service.pluginVersionStatus;
67276
67321
  if (pluginVersionStatus.unavailable) {
67277
67322
  throw new Error(
67278
- `@okxweb3/a2a-node v${"0.2.3"} is below the required minimum v${pluginVersionStatus.minVersion}`
67323
+ `@okxweb3/a2a-node v${"0.2.4-beta-e7a52faf6f-260811185020"} is below the required minimum v${pluginVersionStatus.minVersion}`
67279
67324
  );
67280
67325
  }
67281
67326
  const systemConfig = service.getSystemConfig();
@@ -67293,7 +67338,7 @@ async function runListenerWithLock(options, paths) {
67293
67338
  onchainosAgentId: "*",
67294
67339
  reason: "system-config missing sentryDsn",
67295
67340
  pluginId: "@okxweb3/a2a-node",
67296
- pluginVersion: "0.2.3"
67341
+ pluginVersion: "0.2.4-beta-e7a52faf6f-260811185020"
67297
67342
  });
67298
67343
  }
67299
67344
  logWithTimestamp(
@@ -67305,37 +67350,56 @@ async function runListenerWithLock(options, paths) {
67305
67350
  logWithTimestamp(
67306
67351
  `[okx-agent-task] startup replay complete clients=${startupReplaySummary.clients} replayed=${startupReplaySummary.replayed} skipped=${startupReplaySummary.skipped} duration=${startupReplaySummary.durationMs}ms`
67307
67352
  );
67308
- let maintenanceInFlight = null;
67309
67353
  let lastRecycleReplayAtMs = 0;
67310
- let xmtpRecyclePending = false;
67311
- const tryEnterMaintenanceTask = (task) => {
67312
- if (task !== "xmtp_recycle" && xmtpRecyclePending) {
67313
- return false;
67314
- }
67315
- if (maintenanceInFlight) {
67316
- return false;
67354
+ const maintenanceGate = new ListenerMaintenanceGate();
67355
+ const deferredMaintenanceTasks = new ListenerDeferredTaskScheduler();
67356
+ const leaveMaintenanceTask = (task) => {
67357
+ const pendingTask = maintenanceGate.leave(task);
67358
+ if (stopping) {
67359
+ return;
67317
67360
  }
67318
- if (task === "xmtp_recycle") {
67319
- xmtpRecyclePending = false;
67361
+ if (pendingTask === "xmtp_recycle") {
67362
+ deferredMaintenanceTasks.schedule(() => void xmtpRecycleTick());
67363
+ } else if (pendingTask === "offline_replay") {
67364
+ deferredMaintenanceTasks.schedule(() => void offlineReplayTick());
67320
67365
  }
67321
- maintenanceInFlight = task;
67322
- return true;
67323
67366
  };
67324
- const leaveMaintenanceTask = (task) => {
67325
- if (maintenanceInFlight === task) {
67326
- maintenanceInFlight = null;
67327
- if (xmtpRecyclePending && !stopping) {
67328
- setTimeout(() => void xmtpRecycleTick(), 0);
67367
+ const syncTick = async () => {
67368
+ if (stopping || agentRefreshCoordinator.blocked) {
67369
+ return;
67370
+ }
67371
+ if (!maintenanceGate.tryEnter("sync")) {
67372
+ return;
67373
+ }
67374
+ const tickStartedAt = Date.now();
67375
+ try {
67376
+ const refresh = await agentRefreshCoordinator.runScheduled();
67377
+ if (!refresh) {
67378
+ return;
67329
67379
  }
67380
+ logWithTimestamp(
67381
+ `[okx-agent-task] sync tick agents=${refresh.agentCount} changed=${refresh.changed ? "yes" : "no"} added=${refresh.added.length} removed=${refresh.removed.length}`
67382
+ );
67383
+ } catch (err2) {
67384
+ logger.error(LogEvent.DAEMON_TICK_FAILED, err2 instanceof Error ? err2 : new Error(String(err2)), {
67385
+ component: "node_listener",
67386
+ stage: "sync_tick",
67387
+ durationMs: String(Date.now() - tickStartedAt),
67388
+ reason: "sync_tick_exception"
67389
+ });
67390
+ logWithTimestamp(`[okx-agent-task] sync tick failed total=${Date.now() - tickStartedAt}ms:`, err2);
67391
+ } finally {
67392
+ leaveMaintenanceTask("sync");
67330
67393
  }
67331
67394
  };
67332
- const syncTick = async () => {
67333
- if (!tryEnterMaintenanceTask("sync")) {
67334
- return;
67395
+ let heartbeatInFlight = false;
67396
+ const heartbeatTick = async () => {
67397
+ if (heartbeatInFlight || stopping) {
67398
+ return "blocked";
67335
67399
  }
67400
+ heartbeatInFlight = true;
67336
67401
  const tickStartedAt = Date.now();
67337
67402
  try {
67338
- const refresh = await service.refreshAgents();
67339
67403
  const hasActiveAgents = service.getClients().size > 0;
67340
67404
  let shouldHeartbeat = hasActiveAgents;
67341
67405
  const heartbeatProvider = resolveConfiguredAiProvider({ store: sessionStore }) ?? detectGatewayInvocation();
@@ -67350,7 +67414,7 @@ async function runListenerWithLock(options, paths) {
67350
67414
  new Error(`heartbeat gateway check failed: provider=hermes reason=${hermesStatus.reason}`),
67351
67415
  {
67352
67416
  component: "node_listener",
67353
- stage: "sync_tick",
67417
+ stage: "heartbeat_tick",
67354
67418
  reason: hermesStatus.reason ?? "unknown",
67355
67419
  provider: "hermes",
67356
67420
  hermesHome: hermesStatus.hermesHome,
@@ -67374,7 +67438,7 @@ async function runListenerWithLock(options, paths) {
67374
67438
  new Error(`heartbeat skipped: provider=${heartbeatProvider ?? "(not set)"} gateway unavailable`),
67375
67439
  {
67376
67440
  component: "node_listener",
67377
- stage: "sync_tick",
67441
+ stage: "heartbeat_tick",
67378
67442
  reason: "gateway_unavailable",
67379
67443
  provider: heartbeatProvider ?? "(not set)",
67380
67444
  chainIndex: ONCHAINOS_CHAIN_INDEX,
@@ -67390,7 +67454,7 @@ async function runListenerWithLock(options, paths) {
67390
67454
  new Error("heartbeat skipped: no active agents"),
67391
67455
  {
67392
67456
  component: "node_listener",
67393
- stage: "sync_tick",
67457
+ stage: "heartbeat_tick",
67394
67458
  reason: "no_active_agents",
67395
67459
  provider: heartbeatProvider ?? "(not set)",
67396
67460
  chainIndex: ONCHAINOS_CHAIN_INDEX
@@ -67403,7 +67467,7 @@ async function runListenerWithLock(options, paths) {
67403
67467
  if (shouldHeartbeat && heartbeatResult.error) {
67404
67468
  logger.error(LogEvent.HEARTBEAT_FAILED, heartbeatResult.error instanceof Error ? heartbeatResult.error : new Error(String(heartbeatResult.error)), {
67405
67469
  component: "node_listener",
67406
- stage: "sync_tick",
67470
+ stage: "heartbeat_tick",
67407
67471
  reason: heartbeatResult.error instanceof Error ? heartbeatResult.error.name : "unknown_error",
67408
67472
  durationMs: String(heartbeatMs),
67409
67473
  chainIndex: ONCHAINOS_CHAIN_INDEX,
@@ -67411,23 +67475,27 @@ async function runListenerWithLock(options, paths) {
67411
67475
  });
67412
67476
  logWithTimestamp(`[okx-agent-task] heartbeat failed duration=${heartbeatMs}ms:`, heartbeatResult.error);
67413
67477
  }
67414
- logWithTimestamp(
67415
- `[okx-agent-task] sync tick agents=${refresh.agentCount} changed=${refresh.changed ? "yes" : "no"} added=${refresh.added.length} removed=${refresh.removed.length}`
67416
- );
67478
+ return shouldHeartbeat ? "performed" : "refresh_safe";
67417
67479
  } catch (err2) {
67418
- logger.error(LogEvent.DAEMON_TICK_FAILED, err2 instanceof Error ? err2 : new Error(String(err2)), {
67480
+ logger.error(LogEvent.HEARTBEAT_FAILED, err2 instanceof Error ? err2 : new Error(String(err2)), {
67419
67481
  component: "node_listener",
67420
- stage: "sync_tick",
67482
+ stage: "heartbeat_tick",
67421
67483
  durationMs: String(Date.now() - tickStartedAt),
67422
- reason: "sync_tick_exception"
67484
+ reason: "heartbeat_tick_exception",
67485
+ chainIndex: ONCHAINOS_CHAIN_INDEX,
67486
+ communicationClass: "onchainos_or_network"
67423
67487
  });
67424
- logWithTimestamp(`[okx-agent-task] sync tick failed total=${Date.now() - tickStartedAt}ms:`, err2);
67488
+ logWithTimestamp(`[okx-agent-task] heartbeat tick failed total=${Date.now() - tickStartedAt}ms:`, err2);
67489
+ return "blocked";
67425
67490
  } finally {
67426
- leaveMaintenanceTask("sync");
67491
+ heartbeatInFlight = false;
67427
67492
  }
67428
67493
  };
67429
67494
  const offlineReplayTick = async () => {
67430
- if (!tryEnterMaintenanceTask("offline_replay")) {
67495
+ if (stopping) {
67496
+ return;
67497
+ }
67498
+ if (!maintenanceGate.tryEnter("offline_replay")) {
67431
67499
  return;
67432
67500
  }
67433
67501
  const tickStartedAt = Date.now();
@@ -67469,8 +67537,10 @@ async function runListenerWithLock(options, paths) {
67469
67537
  }
67470
67538
  };
67471
67539
  const xmtpRecycleTick = async () => {
67472
- if (!tryEnterMaintenanceTask("xmtp_recycle")) {
67473
- xmtpRecyclePending = true;
67540
+ if (stopping) {
67541
+ return;
67542
+ }
67543
+ if (!maintenanceGate.tryEnter("xmtp_recycle")) {
67474
67544
  return;
67475
67545
  }
67476
67546
  const tickStartedAt = Date.now();
@@ -67514,7 +67584,6 @@ async function runListenerWithLock(options, paths) {
67514
67584
  let timer;
67515
67585
  let offlineReplayTimer;
67516
67586
  let xmtpClientRecycleTimer;
67517
- let stopping = false;
67518
67587
  const scheduleSyncTimer = (nextIntervalSec) => {
67519
67588
  if (stopping) {
67520
67589
  return;
@@ -67525,7 +67594,10 @@ async function runListenerWithLock(options, paths) {
67525
67594
  intervalSec = Math.max(10, nextIntervalSec);
67526
67595
  logWithTimestamp(`[okx-agent-task] scheduled sync interval ${intervalSec}s`);
67527
67596
  timer = setInterval(() => {
67528
- void syncTick();
67597
+ void runHeartbeatRefreshCycle({
67598
+ heartbeat: heartbeatTick,
67599
+ refresh: syncTick
67600
+ });
67529
67601
  }, intervalSec * 1e3);
67530
67602
  };
67531
67603
  const scheduleOfflineReplayTimer = (nextIntervalSec) => {
@@ -67607,9 +67679,12 @@ async function runListenerWithLock(options, paths) {
67607
67679
  const systemConfigRefreshTimer = setInterval(() => {
67608
67680
  void refreshSystemConfigTick();
67609
67681
  }, 60 * 60 * 1e3);
67610
- void syncTick();
67682
+ void runHeartbeatRefreshCycle({
67683
+ heartbeat: heartbeatTick
67684
+ });
67611
67685
  const commandProcessor = startCommandProcessor({
67612
67686
  service,
67687
+ refreshAgents: () => agentRefreshCoordinator.runManual(),
67613
67688
  store,
67614
67689
  sessionStore,
67615
67690
  homeDir: options.homeDir
@@ -67628,6 +67703,7 @@ async function runListenerWithLock(options, paths) {
67628
67703
  resolve14();
67629
67704
  }, SHUTDOWN_FORCE_RESOLVE_MS);
67630
67705
  void (async () => {
67706
+ deferredMaintenanceTasks.cancelAll();
67631
67707
  if (timer) {
67632
67708
  clearInterval(timer);
67633
67709
  }
@@ -67669,7 +67745,7 @@ async function timeSettled(fn) {
67669
67745
  return { durationMs: Date.now() - startedAt, error };
67670
67746
  }
67671
67747
  }
67672
- var import_node_fs25, import_promises13, import_node_os11, import_node_path30, DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC, DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC, XMTP_CLIENT_RECYCLE_INTERVAL_ENV, HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS, UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY, SHUTDOWN_FORCE_RESOLVE_MS;
67748
+ var import_node_fs25, import_promises13, import_node_os11, import_node_path30, DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC, DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC, XMTP_CLIENT_RECYCLE_INTERVAL_ENV, HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS, AgentRefreshAuthGate, AgentRefreshCoordinator, ListenerDeferredTaskScheduler, ListenerMaintenanceGate, UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY, SHUTDOWN_FORCE_RESOLVE_MS;
67673
67749
  var init_listener = __esm({
67674
67750
  "src/listener.ts"() {
67675
67751
  "use strict";
@@ -67702,6 +67778,107 @@ var init_listener = __esm({
67702
67778
  DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC = 6 * 60 * 60;
67703
67779
  XMTP_CLIENT_RECYCLE_INTERVAL_ENV = "OKX_A2A_XMTP_CLIENT_RECYCLE_INTERVAL_SEC";
67704
67780
  HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS = 2e3;
67781
+ AgentRefreshAuthGate = class {
67782
+ authBlocked = false;
67783
+ get blocked() {
67784
+ return this.authBlocked;
67785
+ }
67786
+ recordSuccess() {
67787
+ this.authBlocked = false;
67788
+ }
67789
+ recordFailure(err2) {
67790
+ if (!isOnchainosAuthError(err2)) {
67791
+ return false;
67792
+ }
67793
+ this.authBlocked = true;
67794
+ return true;
67795
+ }
67796
+ };
67797
+ AgentRefreshCoordinator = class {
67798
+ constructor(options) {
67799
+ this.options = options;
67800
+ }
67801
+ options;
67802
+ authGate = new AgentRefreshAuthGate();
67803
+ get blocked() {
67804
+ return this.authGate.blocked;
67805
+ }
67806
+ async lookup(previousFingerprint) {
67807
+ const wasBlocked = this.authGate.blocked;
67808
+ try {
67809
+ const result = await this.options.lookup(previousFingerprint);
67810
+ this.authGate.recordSuccess();
67811
+ if (wasBlocked) {
67812
+ this.options.onAuthRecovered?.();
67813
+ }
67814
+ return result;
67815
+ } catch (err2) {
67816
+ if (this.authGate.recordFailure(err2) && !wasBlocked) {
67817
+ this.options.onAuthBlocked?.();
67818
+ }
67819
+ throw err2;
67820
+ }
67821
+ }
67822
+ async runScheduled() {
67823
+ if (this.options.isStopping() || this.authGate.blocked) {
67824
+ return null;
67825
+ }
67826
+ return this.options.refresh();
67827
+ }
67828
+ async runManual() {
67829
+ return this.options.refresh();
67830
+ }
67831
+ };
67832
+ ListenerDeferredTaskScheduler = class {
67833
+ timers = /* @__PURE__ */ new Set();
67834
+ schedule(task) {
67835
+ const timer = setTimeout(() => {
67836
+ this.timers.delete(timer);
67837
+ task();
67838
+ }, 0);
67839
+ this.timers.add(timer);
67840
+ }
67841
+ cancelAll() {
67842
+ for (const timer of this.timers) {
67843
+ clearTimeout(timer);
67844
+ }
67845
+ this.timers.clear();
67846
+ }
67847
+ };
67848
+ ListenerMaintenanceGate = class {
67849
+ inFlight = null;
67850
+ offlineReplayPending = false;
67851
+ xmtpRecyclePending = false;
67852
+ tryEnter(task) {
67853
+ if (task !== "xmtp_recycle" && this.xmtpRecyclePending || this.inFlight) {
67854
+ if (task === "offline_replay") {
67855
+ this.offlineReplayPending = true;
67856
+ } else if (task === "xmtp_recycle") {
67857
+ this.xmtpRecyclePending = true;
67858
+ }
67859
+ return false;
67860
+ }
67861
+ if (task === "xmtp_recycle") {
67862
+ this.xmtpRecyclePending = false;
67863
+ }
67864
+ this.inFlight = task;
67865
+ return true;
67866
+ }
67867
+ leave(task) {
67868
+ if (this.inFlight !== task) {
67869
+ return null;
67870
+ }
67871
+ this.inFlight = null;
67872
+ if (this.xmtpRecyclePending) {
67873
+ return "xmtp_recycle";
67874
+ }
67875
+ if (this.offlineReplayPending) {
67876
+ this.offlineReplayPending = false;
67877
+ return "offline_replay";
67878
+ }
67879
+ return null;
67880
+ }
67881
+ };
67705
67882
  UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY = "system:onchainos-offline-replay-upgrade";
67706
67883
  SHUTDOWN_FORCE_RESOLVE_MS = 5e3;
67707
67884
  }
@@ -115480,7 +115657,7 @@ async function getCurrentNodeCliVersion() {
115480
115657
  return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
115481
115658
  }
115482
115659
  function getBundledNodeCliVersion() {
115483
- return true ? "0.2.3" : null;
115660
+ return true ? "0.2.4-beta-e7a52faf6f-260811185020" : null;
115484
115661
  }
115485
115662
  function readConfiguredAiProvider() {
115486
115663
  const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
@@ -115690,7 +115867,7 @@ async function updateHermes(release, options) {
115690
115867
  }
115691
115868
  }
115692
115869
  async function installGatewayPluginForDoctor(target) {
115693
- const release = isPrereleaseVersion("0.2.3") ? "beta" : "latest";
115870
+ const release = isPrereleaseVersion("0.2.4-beta-e7a52faf6f-260811185020") ? "beta" : "latest";
115694
115871
  const insideTargetGateway = detectGatewayInvocation() === target;
115695
115872
  const options = {
115696
115873
  restart: !insideTargetGateway,
@@ -116733,7 +116910,7 @@ async function runDoctor(options = {}) {
116733
116910
  platform: options.platform ?? process.platform,
116734
116911
  env: options.env ?? process.env,
116735
116912
  target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
116736
- cliVersion: options.cliVersion ?? (true ? "0.2.3" : "0.0.0"),
116913
+ cliVersion: options.cliVersion ?? (true ? "0.2.4-beta-e7a52faf6f-260811185020" : "0.0.0"),
116737
116914
  fixMode: options.fix === true,
116738
116915
  nonInteractive: options.nonInteractive === true,
116739
116916
  packageChanged: false,
@@ -117730,7 +117907,7 @@ init_sentry_logger();
117730
117907
  init_sentry_config();
117731
117908
  var CURRENT_GATEWAY_SESSION_KEYS_ENV4 = "OKX_A2A_CURRENT_GATEWAY_SESSION_KEYS";
117732
117909
  function printUsage3() {
117733
- console.log(`okx-a2a ${"0.2.3"}
117910
+ console.log(`okx-a2a ${"0.2.4-beta-e7a52faf6f-260811185020"}
117734
117911
 
117735
117912
  Usage:
117736
117913
  okx-a2a <command> [options]
@@ -117770,7 +117947,7 @@ Run \`okx-a2a <command> -h\` for command-specific help.
117770
117947
  `);
117771
117948
  }
117772
117949
  function printVersion() {
117773
- console.log("0.2.3");
117950
+ console.log("0.2.4-beta-e7a52faf6f-260811185020");
117774
117951
  }
117775
117952
  function printDaemonUsage() {
117776
117953
  console.log(`Usage: okx-a2a daemon <start|restart|stop|status|autostart> [options]
@@ -119206,7 +119383,7 @@ async function main() {
119206
119383
  if (command === "xmtp-test") {
119207
119384
  const { handleXmtpTestCommand: handleXmtpTestCommand2 } = await Promise.resolve().then(() => (init_xmtp_test_cli(), xmtp_test_cli_exports));
119208
119385
  await handleXmtpTestCommand2(process.argv.slice(3), {
119209
- packageVersion: "0.2.3",
119386
+ packageVersion: "0.2.4-beta-e7a52faf6f-260811185020",
119210
119387
  agentSdkVersion: "2.3.0",
119211
119388
  nodeSdkVersion: "6.1.0",
119212
119389
  nodeBindingsVersion: "1.11.0"
package/dist/index.js CHANGED
@@ -32104,7 +32104,7 @@ var init_sentry_config = __esm({
32104
32104
  environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
32105
32105
  SENTRY_CONFIG = {
32106
32106
  projectName: "okx/openclaw-okx-a2a-extension",
32107
- release: "0.2.3",
32107
+ release: "0.2.4-beta-e7a52faf6f-260811185020",
32108
32108
  environment,
32109
32109
  runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
32110
32110
  };
@@ -33045,7 +33045,7 @@ async function getCurrentNodeCliVersion() {
33045
33045
  return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
33046
33046
  }
33047
33047
  function getBundledNodeCliVersion() {
33048
- return true ? "0.2.3" : null;
33048
+ return true ? "0.2.4-beta-e7a52faf6f-260811185020" : null;
33049
33049
  }
33050
33050
  function readConfiguredAiProvider() {
33051
33051
  const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
@@ -33255,7 +33255,7 @@ async function updateHermes(release, options) {
33255
33255
  }
33256
33256
  }
33257
33257
  async function installGatewayPluginForDoctor(target) {
33258
- const release = isPrereleaseVersion("0.2.3") ? "beta" : "latest";
33258
+ const release = isPrereleaseVersion("0.2.4-beta-e7a52faf6f-260811185020") ? "beta" : "latest";
33259
33259
  const insideTargetGateway = detectGatewayInvocation() === target;
33260
33260
  const options = {
33261
33261
  restart: !insideTargetGateway,
@@ -43946,6 +43946,8 @@ var index_exports = {};
43946
43946
  __export(index_exports, {
43947
43947
  AI_PROVIDERS: () => AI_PROVIDERS,
43948
43948
  AgentMessageDirection: () => AgentMessageDirection,
43949
+ AgentRefreshAuthGate: () => AgentRefreshAuthGate,
43950
+ AgentRefreshCoordinator: () => AgentRefreshCoordinator,
43949
43951
  AiRunner: () => AiRunner,
43950
43952
  BACKUP_JOB_ID: () => BACKUP_JOB_ID,
43951
43953
  CODEX_APP_DIRS_ENV: () => CODEX_APP_DIRS_ENV,
@@ -43965,6 +43967,8 @@ __export(index_exports, {
43965
43967
  InboundReplayGate: () => InboundReplayGate,
43966
43968
  InvalidXmtpMessageStore: () => InvalidXmtpMessageStore,
43967
43969
  JOB_PROVIDER_BINDING_SOURCES: () => JOB_PROVIDER_BINDING_SOURCES,
43970
+ ListenerDeferredTaskScheduler: () => ListenerDeferredTaskScheduler,
43971
+ ListenerMaintenanceGate: () => ListenerMaintenanceGate,
43968
43972
  LogEvent: () => LogEvent,
43969
43973
  MESSAGE_ELIGIBLE_OFFLINE_REPLAY_FLAG: () => MESSAGE_ELIGIBLE_OFFLINE_REPLAY_FLAG,
43970
43974
  MESSAGE_ELIGIBLE_OFFLINE_REPLAY_HELP_TOKEN: () => MESSAGE_ELIGIBLE_OFFLINE_REPLAY_HELP_TOKEN,
@@ -44161,6 +44165,7 @@ __export(index_exports, {
44161
44165
  resolveXmtpClientRecycleIntervalSec: () => resolveXmtpClientRecycleIntervalSec,
44162
44166
  runAiAdapter: () => runAiAdapter,
44163
44167
  runDoctor: () => runDoctor,
44168
+ runHeartbeatRefreshCycle: () => runHeartbeatRefreshCycle,
44164
44169
  runListener: () => runListener,
44165
44170
  scanUserAttentionWatchers: () => scanUserAttentionWatchers,
44166
44171
  setOpenClawWebSocketFactoryForTests: () => setOpenClawWebSocketFactoryForTests,
@@ -55865,6 +55870,63 @@ function compareTimestamp(a, b) {
55865
55870
  return 0;
55866
55871
  }
55867
55872
 
55873
+ // ../core/src/xmtp-sdk/onchainos/session-expired.ts
55874
+ init_sentry_logger();
55875
+ var SESSION_EXPIRED_RE = /session expired/i;
55876
+ var AUTH_FAILURE_PATTERNS = [
55877
+ ["session_expired", /session expired/i],
55878
+ ["not_logged_in", /not logged in/i],
55879
+ ["login_required", /login required/i],
55880
+ ["authentication_required", /authentication required/i]
55881
+ ];
55882
+ function isSessionExpired(stdout) {
55883
+ try {
55884
+ const res = JSON.parse(stdout);
55885
+ return res.ok === false && SESSION_EXPIRED_RE.test(String(res.error ?? ""));
55886
+ } catch {
55887
+ return SESSION_EXPIRED_RE.test(stdout);
55888
+ }
55889
+ }
55890
+ function classifyOnchainosAuthError(err) {
55891
+ if (!err) {
55892
+ return null;
55893
+ }
55894
+ const values = [String(err)];
55895
+ if (typeof err === "object") {
55896
+ const anyErr = err;
55897
+ values.push(anyErr.stdout, anyErr.stderr, anyErr.message);
55898
+ }
55899
+ for (const value of values) {
55900
+ if (typeof value !== "string") {
55901
+ continue;
55902
+ }
55903
+ for (const [reason, pattern] of AUTH_FAILURE_PATTERNS) {
55904
+ if (pattern.test(value)) {
55905
+ return reason;
55906
+ }
55907
+ }
55908
+ }
55909
+ return null;
55910
+ }
55911
+ function isOnchainosAuthError(err) {
55912
+ return classifyOnchainosAuthError(err) !== null;
55913
+ }
55914
+ function reportSessionExpired(command) {
55915
+ logger.error(
55916
+ LogEvent.ONCHAINOS_SESSION_EXPIRED,
55917
+ new Error("onchainos session expired"),
55918
+ {
55919
+ component: "onchainos_cli",
55920
+ source: "onchainos",
55921
+ stage: "session_expired",
55922
+ operation: command,
55923
+ command,
55924
+ communicationClass: "onchainos_auth_issue",
55925
+ reason: "session_expired"
55926
+ }
55927
+ );
55928
+ }
55929
+
55868
55930
  // ../core/src/xmtp-sdk/index.ts
55869
55931
  var DEFAULT_DATA_DIR = resolveA2aTaskPaths().xmtpDir;
55870
55932
  var XMTP_INSTALLATION_WARNING_THRESHOLD = 2;
@@ -55898,22 +55960,6 @@ function ensureCacheDir(dataDir) {
55898
55960
  ensureA2aTaskDir(dataDir);
55899
55961
  }
55900
55962
  var SENSITIVE_WORDS_LAZY_RETRY_COOLDOWN_MS = 10 * 60 * 1e3;
55901
- var SESSION_EXPIRED_RE = /session expired/i;
55902
- function isSessionExpiredError(err) {
55903
- if (!err) {
55904
- return false;
55905
- }
55906
- if (typeof err === "object") {
55907
- const anyErr = err;
55908
- if (typeof anyErr.stdout === "string" && SESSION_EXPIRED_RE.test(anyErr.stdout)) {
55909
- return true;
55910
- }
55911
- if (typeof anyErr.message === "string" && SESSION_EXPIRED_RE.test(anyErr.message)) {
55912
- return true;
55913
- }
55914
- }
55915
- return SESSION_EXPIRED_RE.test(String(err));
55916
- }
55917
55963
  function loadSensitiveWordsFromCache(dataDir) {
55918
55964
  try {
55919
55965
  const path2 = cachePath(dataDir, "sensitive-words.json");
@@ -56832,12 +56878,14 @@ var XmtpService = class _XmtpService {
56832
56878
  newAgents = agentList.agents;
56833
56879
  changed = agentList.changed;
56834
56880
  } catch (err) {
56835
- if (isSessionExpiredError(err)) {
56881
+ const authFailureReason = classifyOnchainosAuthError(err);
56882
+ if (authFailureReason) {
56836
56883
  logWithTimestamp(
56837
- "[xmtp-sdk] refresh: onchainos session expired, taking all local clients offline"
56884
+ `[xmtp-sdk] refresh: onchainos auth unavailable (${authFailureReason}), taking all local clients offline`
56838
56885
  );
56839
56886
  logger.info(LogEvent.AGENT_REFRESH_SESSION_EXPIRED, {
56840
56887
  onchainosAgentId: "*",
56888
+ authFailureReason,
56841
56889
  previousClientCount: String(this.clients.size),
56842
56890
  previousAgentCount: String(this.allAgents.length),
56843
56891
  previousAgentIds: this.allAgents.map((a) => a.agentId).join(","),
@@ -58744,33 +58792,6 @@ function parseCliJson(stdout, command, extras = {}) {
58744
58792
  }
58745
58793
  }
58746
58794
 
58747
- // ../core/src/xmtp-sdk/onchainos/session-expired.ts
58748
- init_sentry_logger();
58749
- var SESSION_EXPIRED_RE2 = /session expired/i;
58750
- function isSessionExpired(stdout) {
58751
- try {
58752
- const res = JSON.parse(stdout);
58753
- return res.ok === false && SESSION_EXPIRED_RE2.test(String(res.error ?? ""));
58754
- } catch {
58755
- return SESSION_EXPIRED_RE2.test(stdout);
58756
- }
58757
- }
58758
- function reportSessionExpired(command) {
58759
- logger.error(
58760
- LogEvent.ONCHAINOS_SESSION_EXPIRED,
58761
- new Error("onchainos session expired"),
58762
- {
58763
- component: "onchainos_cli",
58764
- source: "onchainos",
58765
- stage: "session_expired",
58766
- operation: command,
58767
- command,
58768
- communicationClass: "onchainos_auth_issue",
58769
- reason: "session_expired"
58770
- }
58771
- );
58772
- }
58773
-
58774
58795
  // ../core/src/xmtp-sdk/onchainos/offline-replay-capability.ts
58775
58796
  init_log();
58776
58797
  var MESSAGE_ELIGIBLE_OFFLINE_REPLAY_FLAG = "--is-offline-replay";
@@ -59056,7 +59077,10 @@ async function fetchAgentPage(page) {
59056
59077
  );
59057
59078
  if (!res.ok) {
59058
59079
  guardSessionExpired2(stdout, "list-agents");
59059
- const parseErr = new Error("onchainos agent get failed");
59080
+ const detail = typeof res.error === "string" ? res.error.trim() : "";
59081
+ const parseErr = new Error(
59082
+ detail ? `onchainos agent get failed: ${detail}` : "onchainos agent get failed"
59083
+ );
59060
59084
  logger.error(
59061
59085
  LogEvent.ONCHAINOS_CLI_ERROR,
59062
59086
  parseErr,
@@ -60181,7 +60205,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
60181
60205
  client: {
60182
60206
  id: "gateway-client",
60183
60207
  displayName: "okx-a2a-node",
60184
- version: "0.2.3",
60208
+ version: "0.2.4-beta-e7a52faf6f-260811185020",
60185
60209
  platform: "node",
60186
60210
  mode: "backend",
60187
60211
  instanceId
@@ -60192,7 +60216,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
60192
60216
  commands: [],
60193
60217
  permissions: {},
60194
60218
  locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
60195
- userAgent: `okx-a2a-node/${"0.2.3"}`,
60219
+ userAgent: `okx-a2a-node/${"0.2.4-beta-e7a52faf6f-260811185020"}`,
60196
60220
  auth: {
60197
60221
  ...config.token ? { token: config.token } : {},
60198
60222
  ...config.password ? { password: config.password } : {}
@@ -63621,7 +63645,7 @@ async function handleDaemonCommand(command, params) {
63621
63645
  const payload = await handleXmtpDebugCommand(command, params.service);
63622
63646
  return { ok: true, payload };
63623
63647
  }
63624
- const refresh = await params.service.refreshAgents();
63648
+ const refresh = await (params.refreshAgents?.() ?? params.service.refreshAgents());
63625
63649
  return {
63626
63650
  ok: true,
63627
63651
  payload: {
@@ -65974,6 +65998,113 @@ var DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC = 300;
65974
65998
  var DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC = 6 * 60 * 60;
65975
65999
  var XMTP_CLIENT_RECYCLE_INTERVAL_ENV = "OKX_A2A_XMTP_CLIENT_RECYCLE_INTERVAL_SEC";
65976
66000
  var HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS = 2e3;
66001
+ async function runHeartbeatRefreshCycle(options) {
66002
+ const heartbeat = await timeSettled(options.heartbeat);
66003
+ const refreshAllowed = heartbeat.value === "performed" || heartbeat.value === "refresh_safe";
66004
+ const refresh = options.refresh && refreshAllowed ? await timeSettled(options.refresh) : void 0;
66005
+ return { heartbeat, refresh };
66006
+ }
66007
+ var AgentRefreshAuthGate = class {
66008
+ authBlocked = false;
66009
+ get blocked() {
66010
+ return this.authBlocked;
66011
+ }
66012
+ recordSuccess() {
66013
+ this.authBlocked = false;
66014
+ }
66015
+ recordFailure(err) {
66016
+ if (!isOnchainosAuthError(err)) {
66017
+ return false;
66018
+ }
66019
+ this.authBlocked = true;
66020
+ return true;
66021
+ }
66022
+ };
66023
+ var AgentRefreshCoordinator = class {
66024
+ constructor(options) {
66025
+ this.options = options;
66026
+ }
66027
+ options;
66028
+ authGate = new AgentRefreshAuthGate();
66029
+ get blocked() {
66030
+ return this.authGate.blocked;
66031
+ }
66032
+ async lookup(previousFingerprint) {
66033
+ const wasBlocked = this.authGate.blocked;
66034
+ try {
66035
+ const result = await this.options.lookup(previousFingerprint);
66036
+ this.authGate.recordSuccess();
66037
+ if (wasBlocked) {
66038
+ this.options.onAuthRecovered?.();
66039
+ }
66040
+ return result;
66041
+ } catch (err) {
66042
+ if (this.authGate.recordFailure(err) && !wasBlocked) {
66043
+ this.options.onAuthBlocked?.();
66044
+ }
66045
+ throw err;
66046
+ }
66047
+ }
66048
+ async runScheduled() {
66049
+ if (this.options.isStopping() || this.authGate.blocked) {
66050
+ return null;
66051
+ }
66052
+ return this.options.refresh();
66053
+ }
66054
+ async runManual() {
66055
+ return this.options.refresh();
66056
+ }
66057
+ };
66058
+ var ListenerDeferredTaskScheduler = class {
66059
+ timers = /* @__PURE__ */ new Set();
66060
+ schedule(task) {
66061
+ const timer = setTimeout(() => {
66062
+ this.timers.delete(timer);
66063
+ task();
66064
+ }, 0);
66065
+ this.timers.add(timer);
66066
+ }
66067
+ cancelAll() {
66068
+ for (const timer of this.timers) {
66069
+ clearTimeout(timer);
66070
+ }
66071
+ this.timers.clear();
66072
+ }
66073
+ };
66074
+ var ListenerMaintenanceGate = class {
66075
+ inFlight = null;
66076
+ offlineReplayPending = false;
66077
+ xmtpRecyclePending = false;
66078
+ tryEnter(task) {
66079
+ if (task !== "xmtp_recycle" && this.xmtpRecyclePending || this.inFlight) {
66080
+ if (task === "offline_replay") {
66081
+ this.offlineReplayPending = true;
66082
+ } else if (task === "xmtp_recycle") {
66083
+ this.xmtpRecyclePending = true;
66084
+ }
66085
+ return false;
66086
+ }
66087
+ if (task === "xmtp_recycle") {
66088
+ this.xmtpRecyclePending = false;
66089
+ }
66090
+ this.inFlight = task;
66091
+ return true;
66092
+ }
66093
+ leave(task) {
66094
+ if (this.inFlight !== task) {
66095
+ return null;
66096
+ }
66097
+ this.inFlight = null;
66098
+ if (this.xmtpRecyclePending) {
66099
+ return "xmtp_recycle";
66100
+ }
66101
+ if (this.offlineReplayPending) {
66102
+ this.offlineReplayPending = false;
66103
+ return "offline_replay";
66104
+ }
66105
+ return null;
66106
+ }
66107
+ };
65977
66108
  var UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY = "system:onchainos-offline-replay-upgrade";
65978
66109
  function resolveOfflineReplayIntervalSec(systemConfig) {
65979
66110
  const interval = systemConfig.offlineReplayInterval;
@@ -66173,10 +66304,24 @@ async function runListenerWithLock(options, paths) {
66173
66304
  }
66174
66305
  });
66175
66306
  logWithTimestamp("[okx-agent-task] user_attention watcher coordinator scanning SQLite watcher state");
66307
+ let stopping = false;
66176
66308
  const service = XmtpService.getInstance();
66309
+ const agentRefreshCoordinator = new AgentRefreshCoordinator({
66310
+ lookup: (previousFingerprint) => listAllAgentsWithMetadata(previousFingerprint),
66311
+ refresh: () => service.refreshAgents(),
66312
+ isStopping: () => stopping,
66313
+ onAuthBlocked: () => {
66314
+ logWithTimestamp(
66315
+ "[okx-agent-task] agent refresh auth blocked; periodic agent get paused. After wallet login, run `okx-a2a agent refresh` or restart the daemon"
66316
+ );
66317
+ },
66318
+ onAuthRecovered: () => {
66319
+ logWithTimestamp("[okx-agent-task] agent refresh auth recovered; periodic refresh resumed");
66320
+ }
66321
+ });
66177
66322
  service.setDataDir(paths.xmtpDir);
66178
66323
  service.setTools({
66179
- listAllAgentsWithMetadata: async (previousFingerprint) => listAllAgentsWithMetadata(previousFingerprint),
66324
+ listAllAgentsWithMetadata: (previousFingerprint) => agentRefreshCoordinator.lookup(previousFingerprint),
66180
66325
  fetchSensitiveWords: async () => fetchSensitiveWords(),
66181
66326
  fetchSystemConfig: async () => fetchSystemConfig({
66182
66327
  notifySessionExpired: (command) => service.tools.notifySessionExpired?.(command)
@@ -66203,7 +66348,7 @@ async function runListenerWithLock(options, paths) {
66203
66348
  }
66204
66349
  }),
66205
66350
  notifySessionExpired: (command) => {
66206
- const rawText = `The onchainos login session has expired while running ${command}. Run \`onchainos wallet login\` and restart \`okx-a2a\`.`;
66351
+ const rawText = `The onchainos login session has expired while running ${command}. Run \`onchainos wallet login\`, then \`okx-a2a agent refresh\` or restart \`okx-a2a\`.`;
66207
66352
  void store.appendBackup(buildSystemStoredMessage({
66208
66353
  reason: "onchainos-session-expired",
66209
66354
  rawText,
@@ -66231,12 +66376,12 @@ async function runListenerWithLock(options, paths) {
66231
66376
  });
66232
66377
  }
66233
66378
  });
66234
- service.setPluginVersion("0.2.3");
66379
+ service.setPluginVersion("0.2.4-beta-e7a52faf6f-260811185020");
66235
66380
  await service.init();
66236
66381
  const pluginVersionStatus = service.pluginVersionStatus;
66237
66382
  if (pluginVersionStatus.unavailable) {
66238
66383
  throw new Error(
66239
- `@okxweb3/a2a-node v${"0.2.3"} is below the required minimum v${pluginVersionStatus.minVersion}`
66384
+ `@okxweb3/a2a-node v${"0.2.4-beta-e7a52faf6f-260811185020"} is below the required minimum v${pluginVersionStatus.minVersion}`
66240
66385
  );
66241
66386
  }
66242
66387
  const systemConfig = service.getSystemConfig();
@@ -66254,7 +66399,7 @@ async function runListenerWithLock(options, paths) {
66254
66399
  onchainosAgentId: "*",
66255
66400
  reason: "system-config missing sentryDsn",
66256
66401
  pluginId: "@okxweb3/a2a-node",
66257
- pluginVersion: "0.2.3"
66402
+ pluginVersion: "0.2.4-beta-e7a52faf6f-260811185020"
66258
66403
  });
66259
66404
  }
66260
66405
  logWithTimestamp(
@@ -66266,37 +66411,56 @@ async function runListenerWithLock(options, paths) {
66266
66411
  logWithTimestamp(
66267
66412
  `[okx-agent-task] startup replay complete clients=${startupReplaySummary.clients} replayed=${startupReplaySummary.replayed} skipped=${startupReplaySummary.skipped} duration=${startupReplaySummary.durationMs}ms`
66268
66413
  );
66269
- let maintenanceInFlight = null;
66270
66414
  let lastRecycleReplayAtMs = 0;
66271
- let xmtpRecyclePending = false;
66272
- const tryEnterMaintenanceTask = (task) => {
66273
- if (task !== "xmtp_recycle" && xmtpRecyclePending) {
66274
- return false;
66415
+ const maintenanceGate = new ListenerMaintenanceGate();
66416
+ const deferredMaintenanceTasks = new ListenerDeferredTaskScheduler();
66417
+ const leaveMaintenanceTask = (task) => {
66418
+ const pendingTask = maintenanceGate.leave(task);
66419
+ if (stopping) {
66420
+ return;
66275
66421
  }
66276
- if (maintenanceInFlight) {
66277
- return false;
66422
+ if (pendingTask === "xmtp_recycle") {
66423
+ deferredMaintenanceTasks.schedule(() => void xmtpRecycleTick());
66424
+ } else if (pendingTask === "offline_replay") {
66425
+ deferredMaintenanceTasks.schedule(() => void offlineReplayTick());
66278
66426
  }
66279
- if (task === "xmtp_recycle") {
66280
- xmtpRecyclePending = false;
66281
- }
66282
- maintenanceInFlight = task;
66283
- return true;
66284
66427
  };
66285
- const leaveMaintenanceTask = (task) => {
66286
- if (maintenanceInFlight === task) {
66287
- maintenanceInFlight = null;
66288
- if (xmtpRecyclePending && !stopping) {
66289
- setTimeout(() => void xmtpRecycleTick(), 0);
66428
+ const syncTick = async () => {
66429
+ if (stopping || agentRefreshCoordinator.blocked) {
66430
+ return;
66431
+ }
66432
+ if (!maintenanceGate.tryEnter("sync")) {
66433
+ return;
66434
+ }
66435
+ const tickStartedAt = Date.now();
66436
+ try {
66437
+ const refresh = await agentRefreshCoordinator.runScheduled();
66438
+ if (!refresh) {
66439
+ return;
66290
66440
  }
66441
+ logWithTimestamp(
66442
+ `[okx-agent-task] sync tick agents=${refresh.agentCount} changed=${refresh.changed ? "yes" : "no"} added=${refresh.added.length} removed=${refresh.removed.length}`
66443
+ );
66444
+ } catch (err) {
66445
+ logger.error(LogEvent.DAEMON_TICK_FAILED, err instanceof Error ? err : new Error(String(err)), {
66446
+ component: "node_listener",
66447
+ stage: "sync_tick",
66448
+ durationMs: String(Date.now() - tickStartedAt),
66449
+ reason: "sync_tick_exception"
66450
+ });
66451
+ logWithTimestamp(`[okx-agent-task] sync tick failed total=${Date.now() - tickStartedAt}ms:`, err);
66452
+ } finally {
66453
+ leaveMaintenanceTask("sync");
66291
66454
  }
66292
66455
  };
66293
- const syncTick = async () => {
66294
- if (!tryEnterMaintenanceTask("sync")) {
66295
- return;
66456
+ let heartbeatInFlight = false;
66457
+ const heartbeatTick = async () => {
66458
+ if (heartbeatInFlight || stopping) {
66459
+ return "blocked";
66296
66460
  }
66461
+ heartbeatInFlight = true;
66297
66462
  const tickStartedAt = Date.now();
66298
66463
  try {
66299
- const refresh = await service.refreshAgents();
66300
66464
  const hasActiveAgents = service.getClients().size > 0;
66301
66465
  let shouldHeartbeat = hasActiveAgents;
66302
66466
  const heartbeatProvider = resolveConfiguredAiProvider({ store: sessionStore }) ?? detectGatewayInvocation();
@@ -66311,7 +66475,7 @@ async function runListenerWithLock(options, paths) {
66311
66475
  new Error(`heartbeat gateway check failed: provider=hermes reason=${hermesStatus.reason}`),
66312
66476
  {
66313
66477
  component: "node_listener",
66314
- stage: "sync_tick",
66478
+ stage: "heartbeat_tick",
66315
66479
  reason: hermesStatus.reason ?? "unknown",
66316
66480
  provider: "hermes",
66317
66481
  hermesHome: hermesStatus.hermesHome,
@@ -66335,7 +66499,7 @@ async function runListenerWithLock(options, paths) {
66335
66499
  new Error(`heartbeat skipped: provider=${heartbeatProvider ?? "(not set)"} gateway unavailable`),
66336
66500
  {
66337
66501
  component: "node_listener",
66338
- stage: "sync_tick",
66502
+ stage: "heartbeat_tick",
66339
66503
  reason: "gateway_unavailable",
66340
66504
  provider: heartbeatProvider ?? "(not set)",
66341
66505
  chainIndex: ONCHAINOS_CHAIN_INDEX,
@@ -66351,7 +66515,7 @@ async function runListenerWithLock(options, paths) {
66351
66515
  new Error("heartbeat skipped: no active agents"),
66352
66516
  {
66353
66517
  component: "node_listener",
66354
- stage: "sync_tick",
66518
+ stage: "heartbeat_tick",
66355
66519
  reason: "no_active_agents",
66356
66520
  provider: heartbeatProvider ?? "(not set)",
66357
66521
  chainIndex: ONCHAINOS_CHAIN_INDEX
@@ -66364,7 +66528,7 @@ async function runListenerWithLock(options, paths) {
66364
66528
  if (shouldHeartbeat && heartbeatResult.error) {
66365
66529
  logger.error(LogEvent.HEARTBEAT_FAILED, heartbeatResult.error instanceof Error ? heartbeatResult.error : new Error(String(heartbeatResult.error)), {
66366
66530
  component: "node_listener",
66367
- stage: "sync_tick",
66531
+ stage: "heartbeat_tick",
66368
66532
  reason: heartbeatResult.error instanceof Error ? heartbeatResult.error.name : "unknown_error",
66369
66533
  durationMs: String(heartbeatMs),
66370
66534
  chainIndex: ONCHAINOS_CHAIN_INDEX,
@@ -66372,23 +66536,27 @@ async function runListenerWithLock(options, paths) {
66372
66536
  });
66373
66537
  logWithTimestamp(`[okx-agent-task] heartbeat failed duration=${heartbeatMs}ms:`, heartbeatResult.error);
66374
66538
  }
66375
- logWithTimestamp(
66376
- `[okx-agent-task] sync tick agents=${refresh.agentCount} changed=${refresh.changed ? "yes" : "no"} added=${refresh.added.length} removed=${refresh.removed.length}`
66377
- );
66539
+ return shouldHeartbeat ? "performed" : "refresh_safe";
66378
66540
  } catch (err) {
66379
- logger.error(LogEvent.DAEMON_TICK_FAILED, err instanceof Error ? err : new Error(String(err)), {
66541
+ logger.error(LogEvent.HEARTBEAT_FAILED, err instanceof Error ? err : new Error(String(err)), {
66380
66542
  component: "node_listener",
66381
- stage: "sync_tick",
66543
+ stage: "heartbeat_tick",
66382
66544
  durationMs: String(Date.now() - tickStartedAt),
66383
- reason: "sync_tick_exception"
66545
+ reason: "heartbeat_tick_exception",
66546
+ chainIndex: ONCHAINOS_CHAIN_INDEX,
66547
+ communicationClass: "onchainos_or_network"
66384
66548
  });
66385
- logWithTimestamp(`[okx-agent-task] sync tick failed total=${Date.now() - tickStartedAt}ms:`, err);
66549
+ logWithTimestamp(`[okx-agent-task] heartbeat tick failed total=${Date.now() - tickStartedAt}ms:`, err);
66550
+ return "blocked";
66386
66551
  } finally {
66387
- leaveMaintenanceTask("sync");
66552
+ heartbeatInFlight = false;
66388
66553
  }
66389
66554
  };
66390
66555
  const offlineReplayTick = async () => {
66391
- if (!tryEnterMaintenanceTask("offline_replay")) {
66556
+ if (stopping) {
66557
+ return;
66558
+ }
66559
+ if (!maintenanceGate.tryEnter("offline_replay")) {
66392
66560
  return;
66393
66561
  }
66394
66562
  const tickStartedAt = Date.now();
@@ -66430,8 +66598,10 @@ async function runListenerWithLock(options, paths) {
66430
66598
  }
66431
66599
  };
66432
66600
  const xmtpRecycleTick = async () => {
66433
- if (!tryEnterMaintenanceTask("xmtp_recycle")) {
66434
- xmtpRecyclePending = true;
66601
+ if (stopping) {
66602
+ return;
66603
+ }
66604
+ if (!maintenanceGate.tryEnter("xmtp_recycle")) {
66435
66605
  return;
66436
66606
  }
66437
66607
  const tickStartedAt = Date.now();
@@ -66475,7 +66645,6 @@ async function runListenerWithLock(options, paths) {
66475
66645
  let timer;
66476
66646
  let offlineReplayTimer;
66477
66647
  let xmtpClientRecycleTimer;
66478
- let stopping = false;
66479
66648
  const scheduleSyncTimer = (nextIntervalSec) => {
66480
66649
  if (stopping) {
66481
66650
  return;
@@ -66486,7 +66655,10 @@ async function runListenerWithLock(options, paths) {
66486
66655
  intervalSec = Math.max(10, nextIntervalSec);
66487
66656
  logWithTimestamp(`[okx-agent-task] scheduled sync interval ${intervalSec}s`);
66488
66657
  timer = setInterval(() => {
66489
- void syncTick();
66658
+ void runHeartbeatRefreshCycle({
66659
+ heartbeat: heartbeatTick,
66660
+ refresh: syncTick
66661
+ });
66490
66662
  }, intervalSec * 1e3);
66491
66663
  };
66492
66664
  const scheduleOfflineReplayTimer = (nextIntervalSec) => {
@@ -66568,9 +66740,12 @@ async function runListenerWithLock(options, paths) {
66568
66740
  const systemConfigRefreshTimer = setInterval(() => {
66569
66741
  void refreshSystemConfigTick();
66570
66742
  }, 60 * 60 * 1e3);
66571
- void syncTick();
66743
+ void runHeartbeatRefreshCycle({
66744
+ heartbeat: heartbeatTick
66745
+ });
66572
66746
  const commandProcessor = startCommandProcessor({
66573
66747
  service,
66748
+ refreshAgents: () => agentRefreshCoordinator.runManual(),
66574
66749
  store,
66575
66750
  sessionStore,
66576
66751
  homeDir: options.homeDir
@@ -66589,6 +66764,7 @@ async function runListenerWithLock(options, paths) {
66589
66764
  resolve11();
66590
66765
  }, SHUTDOWN_FORCE_RESOLVE_MS);
66591
66766
  void (async () => {
66767
+ deferredMaintenanceTasks.cancelAll();
66592
66768
  if (timer) {
66593
66769
  clearInterval(timer);
66594
66770
  }
@@ -68900,7 +69076,7 @@ async function exportDiagnosticLogs(options) {
68900
69076
  node: process.version,
68901
69077
  platform: process.platform,
68902
69078
  arch: process.arch,
68903
- packageVersion: true ? "0.2.3" : "unknown",
69079
+ packageVersion: true ? "0.2.4-beta-e7a52faf6f-260811185020" : "unknown",
68904
69080
  sensitiveContentIncluded: options.includeSensitiveContent,
68905
69081
  listenerAndLlmContentIncluded: true,
68906
69082
  credentialsAlwaysRedacted: true,
@@ -70736,7 +70912,7 @@ async function runDoctor(options = {}) {
70736
70912
  platform: options.platform ?? process.platform,
70737
70913
  env: options.env ?? process.env,
70738
70914
  target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
70739
- cliVersion: options.cliVersion ?? (true ? "0.2.3" : "0.0.0"),
70915
+ cliVersion: options.cliVersion ?? (true ? "0.2.4-beta-e7a52faf6f-260811185020" : "0.0.0"),
70740
70916
  fixMode: options.fix === true,
70741
70917
  nonInteractive: options.nonInteractive === true,
70742
70918
  packageChanged: false,
@@ -70959,6 +71135,8 @@ init_autostart_windows();
70959
71135
  0 && (module.exports = {
70960
71136
  AI_PROVIDERS,
70961
71137
  AgentMessageDirection,
71138
+ AgentRefreshAuthGate,
71139
+ AgentRefreshCoordinator,
70962
71140
  AiRunner,
70963
71141
  BACKUP_JOB_ID,
70964
71142
  CODEX_APP_DIRS_ENV,
@@ -70978,6 +71156,8 @@ init_autostart_windows();
70978
71156
  InboundReplayGate,
70979
71157
  InvalidXmtpMessageStore,
70980
71158
  JOB_PROVIDER_BINDING_SOURCES,
71159
+ ListenerDeferredTaskScheduler,
71160
+ ListenerMaintenanceGate,
70981
71161
  LogEvent,
70982
71162
  MESSAGE_ELIGIBLE_OFFLINE_REPLAY_FLAG,
70983
71163
  MESSAGE_ELIGIBLE_OFFLINE_REPLAY_HELP_TOKEN,
@@ -71174,6 +71354,7 @@ init_autostart_windows();
71174
71354
  resolveXmtpClientRecycleIntervalSec,
71175
71355
  runAiAdapter,
71176
71356
  runDoctor,
71357
+ runHeartbeatRefreshCycle,
71177
71358
  runListener,
71178
71359
  scanUserAttentionWatchers,
71179
71360
  setOpenClawWebSocketFactoryForTests,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okxweb3/a2a-node",
3
- "version": "0.2.3",
3
+ "version": "0.2.4-beta-e7a52faf6f-260811185020",
4
4
  "description": "Host-agnostic Node CLI for E2E encrypted agent-to-agent communication via XMTP",
5
5
  "main": "dist/index.js",
6
6
  "bin": {