@p697/clawket 0.6.1 → 0.6.3

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 (2) hide show
  1. package/dist/index.js +97 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5839,6 +5839,15 @@ var RELAY_CONTROL_PREFIX = "__clawket_relay_control__:";
5839
5839
  var BRIDGE_HEALTH_METHOD = "health";
5840
5840
  var BRIDGE_HEALTH_PARAMS = {};
5841
5841
  var DEFAULT_BRIDGE_HEALTH_PROBE_TIMEOUT_MS = 1e4;
5842
+ var TRACEABLE_RELAY_METHODS = /* @__PURE__ */ new Set([
5843
+ "sessions.list",
5844
+ "chat.history",
5845
+ "last-heartbeat",
5846
+ "model.current",
5847
+ "models.list",
5848
+ "agent.identity.get",
5849
+ "agents.list"
5850
+ ]);
5842
5851
  var HermesRelayRuntime = class {
5843
5852
  options;
5844
5853
  relaySocket = null;
@@ -5853,6 +5862,7 @@ var HermesRelayRuntime = class {
5853
5862
  bridgeStatusProbeInFlight = false;
5854
5863
  pendingBridgeMessages = [];
5855
5864
  bridgeHealthProbeSeq = 0;
5865
+ relayMessageSeq = 0;
5856
5866
  pendingBridgeHealthProbe = null;
5857
5867
  snapshot;
5858
5868
  constructor(options) {
@@ -6010,6 +6020,7 @@ var HermesRelayRuntime = class {
6010
6020
  const text = normalizeText(data);
6011
6021
  if (text == null)
6012
6022
  return;
6023
+ this.traceRelayFrame("relay_in", text);
6013
6024
  if (text.startsWith(RELAY_CONTROL_PREFIX)) {
6014
6025
  this.handleRelayControl(text);
6015
6026
  return;
@@ -6045,6 +6056,7 @@ var HermesRelayRuntime = class {
6045
6056
  const text = normalizeText(data);
6046
6057
  if (text == null)
6047
6058
  return;
6059
+ this.traceRelayFrame("bridge_in", text);
6048
6060
  if (this.handleBridgeHealthProbeResponse(text)) {
6049
6061
  return;
6050
6062
  }
@@ -6055,6 +6067,9 @@ var HermesRelayRuntime = class {
6055
6067
  forwardOrQueueBridgeMessage(message) {
6056
6068
  const bridge = this.bridgeSocket;
6057
6069
  if (!bridge || bridge.readyState !== WebSocket2.OPEN) {
6070
+ if (message.text !== void 0) {
6071
+ this.traceRelayFrame("bridge_queue", message.text);
6072
+ }
6058
6073
  if (this.pendingBridgeMessages.length < 256) {
6059
6074
  this.pendingBridgeMessages.push(message);
6060
6075
  }
@@ -6062,6 +6077,7 @@ var HermesRelayRuntime = class {
6062
6077
  return;
6063
6078
  }
6064
6079
  if (message.text !== void 0) {
6080
+ this.traceRelayFrame("bridge_send", message.text);
6065
6081
  bridge.send(message.text);
6066
6082
  return;
6067
6083
  }
@@ -6078,12 +6094,44 @@ var HermesRelayRuntime = class {
6078
6094
  if (!next)
6079
6095
  break;
6080
6096
  if (next.text !== void 0) {
6097
+ this.traceRelayFrame("bridge_flush", next.text);
6081
6098
  bridge.send(next.text);
6082
6099
  } else if (next.data) {
6083
6100
  bridge.send(next.data);
6084
6101
  }
6085
6102
  }
6086
6103
  }
6104
+ traceRelayFrame(direction, text) {
6105
+ const details = this.describeRelayFrame(text);
6106
+ if (!details)
6107
+ return;
6108
+ this.log(`[trace] ${direction} seq=${++this.relayMessageSeq} ${details}`);
6109
+ }
6110
+ describeRelayFrame(text) {
6111
+ if (text.startsWith(RELAY_CONTROL_PREFIX)) {
6112
+ try {
6113
+ const parsed = JSON.parse(text.slice(RELAY_CONTROL_PREFIX.length));
6114
+ const event = typeof parsed?.event === "string" ? parsed.event : "unknown";
6115
+ return `controlEvent=${event}`;
6116
+ } catch {
6117
+ return "controlEvent=invalid";
6118
+ }
6119
+ }
6120
+ try {
6121
+ const parsed = JSON.parse(text);
6122
+ if (parsed?.type === "req" && typeof parsed.method === "string") {
6123
+ if (!TRACEABLE_RELAY_METHODS.has(parsed.method))
6124
+ return null;
6125
+ return `frame=req id=${String(parsed.id ?? "")} method=${parsed.method}`;
6126
+ }
6127
+ if (parsed?.type === "res" && typeof parsed.id === "string") {
6128
+ return `frame=res id=${parsed.id} ok=${parsed.ok === true ? "true" : "false"}`;
6129
+ }
6130
+ return null;
6131
+ } catch {
6132
+ return null;
6133
+ }
6134
+ }
6087
6135
  scheduleRelayReconnect() {
6088
6136
  if (this.stopped || this.reconnectTimer)
6089
6137
  return;
@@ -6152,9 +6200,8 @@ var HermesRelayRuntime = class {
6152
6200
  } else {
6153
6201
  const payload = await response.json();
6154
6202
  if (!payload?.hasBridge) {
6155
- this.log("bridge status probe reported hasBridge=false; restarting relay socket");
6156
- this.relaySocket?.close();
6157
- this.bridgeSocket?.close();
6203
+ this.log("bridge status probe reported hasBridge=false; recycling relay socket");
6204
+ this.recycleRelaySocket("bridge status probe reported hasBridge=false");
6158
6205
  return;
6159
6206
  }
6160
6207
  }
@@ -6244,6 +6291,26 @@ var HermesRelayRuntime = class {
6244
6291
  clearTimeout(this.pendingBridgeHealthProbe.timeout);
6245
6292
  this.pendingBridgeHealthProbe = null;
6246
6293
  }
6294
+ recycleRelaySocket(reason) {
6295
+ const relay = this.relaySocket;
6296
+ if (!relay)
6297
+ return;
6298
+ this.relaySocket = null;
6299
+ this.clearBridgeStatusProbe();
6300
+ this.clearPendingBridgeHealthProbe();
6301
+ this.updateSnapshot({
6302
+ relayConnected: false,
6303
+ bridgeConnected: this.bridgeSocket?.readyState === WebSocket2.OPEN,
6304
+ lastError: reason
6305
+ });
6306
+ try {
6307
+ relay.close();
6308
+ } catch {
6309
+ }
6310
+ if (!this.stopped) {
6311
+ this.scheduleRelayReconnect();
6312
+ }
6313
+ }
6247
6314
  isRelayOpen() {
6248
6315
  return this.relaySocket?.readyState === WebSocket2.OPEN;
6249
6316
  }
@@ -9249,6 +9316,7 @@ function decidePairServiceAction(paired, service) {
9249
9316
  }
9250
9317
 
9251
9318
  // apps/bridge-cli/src/index.ts
9319
+ var HERMES_SERVICE_WATCHDOG_INTERVAL_MS = 3e4;
9252
9320
  async function main() {
9253
9321
  const [, , command = "help", ...args] = process.argv;
9254
9322
  const isServiceMode = hasFlag(args, "--service");
@@ -9426,6 +9494,9 @@ async function main() {
9426
9494
  instanceId: config.instanceId,
9427
9495
  serviceMode: isServiceMode
9428
9496
  });
9497
+ const hermesServiceWatchdog = isServiceMode ? startHermesServiceWatchdog((line) => {
9498
+ emitRuntimeLine(`[hermes-service] ${line}`);
9499
+ }) : null;
9429
9500
  if (isServiceMode) {
9430
9501
  await restoreHermesServiceRuntime((line) => {
9431
9502
  emitRuntimeLine(`[hermes-service] ${line}`);
@@ -9435,6 +9506,9 @@ async function main() {
9435
9506
  process.off("SIGINT", shutdown);
9436
9507
  process.off("SIGTERM", shutdown);
9437
9508
  await runtime.stop();
9509
+ if (hermesServiceWatchdog) {
9510
+ clearInterval(hermesServiceWatchdog);
9511
+ }
9438
9512
  unregisterRuntimeProcess(process.pid);
9439
9513
  if (isServiceMode) {
9440
9514
  clearServiceState(process.pid);
@@ -10288,6 +10362,16 @@ async function keepHermesBridgeAlive(bridge) {
10288
10362
  });
10289
10363
  }
10290
10364
  async function restoreHermesServiceRuntime(log) {
10365
+ await restoreHermesServiceRuntimeInternal(log, { silentIfHealthy: false });
10366
+ }
10367
+ function startHermesServiceWatchdog(log) {
10368
+ const timer = setInterval(() => {
10369
+ void restoreHermesServiceRuntimeInternal(log, { silentIfHealthy: true });
10370
+ }, HERMES_SERVICE_WATCHDOG_INTERVAL_MS);
10371
+ timer.unref?.();
10372
+ return timer;
10373
+ }
10374
+ async function restoreHermesServiceRuntimeInternal(log, options) {
10291
10375
  const bridgeConfig = readHermesBridgeCliConfig();
10292
10376
  const relayConfig = readHermesRelayConfig();
10293
10377
  if (!bridgeConfig && !relayConfig) {
@@ -10302,9 +10386,11 @@ async function restoreHermesServiceRuntime(log) {
10302
10386
  config: bridgeConfig,
10303
10387
  replaceExisting: false
10304
10388
  });
10305
- log(
10306
- bridgePid == null ? "Hermes bridge runtime already running." : `Started Hermes bridge runtime (pid ${bridgePid}).`
10307
- );
10389
+ if (bridgePid != null || !options.silentIfHealthy) {
10390
+ log(
10391
+ bridgePid == null ? "Hermes bridge runtime already running." : `Started Hermes bridge runtime (pid ${bridgePid}).`
10392
+ );
10393
+ }
10308
10394
  } catch (error) {
10309
10395
  log(`Hermes bridge restore failed: ${formatError3(error)}`);
10310
10396
  return;
@@ -10318,9 +10404,11 @@ async function restoreHermesServiceRuntime(log) {
10318
10404
  config: bridgeConfig,
10319
10405
  replaceExisting: false
10320
10406
  });
10321
- log(
10322
- relayPid == null ? "Hermes relay runtime already running." : `Started Hermes relay runtime (pid ${relayPid}).`
10323
- );
10407
+ if (relayPid != null || !options.silentIfHealthy) {
10408
+ log(
10409
+ relayPid == null ? "Hermes relay runtime already running." : `Started Hermes relay runtime (pid ${relayPid}).`
10410
+ );
10411
+ }
10324
10412
  } catch (error) {
10325
10413
  log(`Hermes relay restore failed: ${formatError3(error)}`);
10326
10414
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@p697/clawket",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",