echoclaw-relay-agent 0.4.0 → 0.4.2

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/main.js +122 -2
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2963,11 +2963,14 @@ var GatewayRpcProxy = class extends import_events2.EventEmitter {
2963
2963
  }
2964
2964
  handleEvent(frame, generation) {
2965
2965
  const runId = frame.payload?.runId;
2966
+ const state = frame.payload?.state;
2966
2967
  const streamId = frame.payload?.streamId || frame.payload?.id;
2968
+ console.log(`[rpc-proxy] Event received: event=${frame.event}, state=${state}, runId=${runId?.slice(0, 8) ?? "none"}, streams=${this.streams.size}, runIdMap=${this.runIdToRpc.size}`);
2967
2969
  let rpcId = runId ? this.runIdToRpc.get(runId) : void 0;
2968
2970
  if (!rpcId && streamId) rpcId = streamId;
2969
2971
  const stream = rpcId ? this.streams.get(rpcId) : null;
2970
2972
  if (!stream) {
2973
+ console.log(`[rpc-proxy] No matching stream for runId=${runId?.slice(0, 8) ?? "none"}, forwarding as unmatched event`);
2971
2974
  this.emit("gateway_event", frame);
2972
2975
  return;
2973
2976
  }
@@ -2983,7 +2986,6 @@ var GatewayRpcProxy = class extends import_events2.EventEmitter {
2983
2986
  this.cancelStream(stream.requestId);
2984
2987
  return;
2985
2988
  }
2986
- const state = frame.payload?.state;
2987
2989
  const isFinal = state === "final" || state === "aborted" || state === "error";
2988
2990
  this.emitTunnelResponse(stream.requestId, frame, isFinal);
2989
2991
  if (isFinal) {
@@ -3071,6 +3073,16 @@ function startGateway(gwConfig) {
3071
3073
  rpcProxy.on("response", (response) => {
3072
3074
  sendEncryptedPayload(response);
3073
3075
  });
3076
+ rpcProxy.on("gateway_event", (frame) => {
3077
+ console.log(`[relay-agent] Forwarding unmatched gateway event: ${frame.event ?? frame.type}`);
3078
+ sendEncryptedPayload({
3079
+ request_id: `evt-${Date.now().toString(36)}`,
3080
+ direction: "response",
3081
+ type: "ws-rpc",
3082
+ frame,
3083
+ final: false
3084
+ });
3085
+ });
3074
3086
  gatewayConn.on("state", (newState, oldState) => {
3075
3087
  console.log(`[relay-agent] Gateway: ${oldState} \u2192 ${newState}`);
3076
3088
  broadcastControlState();
@@ -3826,6 +3838,106 @@ function isServiceInstalled() {
3826
3838
  }
3827
3839
  }
3828
3840
 
3841
+ // src/service/updater.ts
3842
+ var import_child_process2 = require("child_process");
3843
+ var PACKAGE_NAME = "echoclaw-relay-agent";
3844
+ var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
3845
+ var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
3846
+ var updateTimer = null;
3847
+ function compareSemver(a, b) {
3848
+ const pa = a.replace(/^v/, "").split(".").map(Number);
3849
+ const pb = b.replace(/^v/, "").split(".").map(Number);
3850
+ for (let i = 0; i < 3; i++) {
3851
+ const na = pa[i] || 0;
3852
+ const nb = pb[i] || 0;
3853
+ if (na > nb) return 1;
3854
+ if (na < nb) return -1;
3855
+ }
3856
+ return 0;
3857
+ }
3858
+ async function fetchLatestVersion() {
3859
+ try {
3860
+ const res = await fetch(REGISTRY_URL, {
3861
+ signal: AbortSignal.timeout(1e4),
3862
+ headers: { "Accept": "application/json" }
3863
+ });
3864
+ if (!res.ok) return null;
3865
+ const data = await res.json();
3866
+ return data.version ?? null;
3867
+ } catch {
3868
+ return null;
3869
+ }
3870
+ }
3871
+ function performUpdate(targetVersion) {
3872
+ console.log(`[updater] Downloading ${PACKAGE_NAME}@${targetVersion}...`);
3873
+ try {
3874
+ const npmRoot = (0, import_child_process2.execSync)("npm root -g", { encoding: "utf-8" }).trim();
3875
+ (0, import_child_process2.execSync)(`npm install -g ${PACKAGE_NAME}@${targetVersion} --prefer-online`, {
3876
+ encoding: "utf-8",
3877
+ stdio: ["pipe", "pipe", "pipe"],
3878
+ timeout: 12e4
3879
+ });
3880
+ console.log(`[updater] \u2705 Downloaded ${PACKAGE_NAME}@${targetVersion}`);
3881
+ if (isServiceInstalled()) {
3882
+ console.log("[updater] Updating service...");
3883
+ installService();
3884
+ console.log("[updater] \u2705 Service updated and restarted");
3885
+ }
3886
+ return true;
3887
+ } catch (err2) {
3888
+ console.error(`[updater] Update failed: ${err2.message}`);
3889
+ return false;
3890
+ }
3891
+ }
3892
+ async function checkForUpdate(currentVersion) {
3893
+ const latest = await fetchLatestVersion();
3894
+ if (!latest) return null;
3895
+ if (compareSemver(latest, currentVersion) > 0) {
3896
+ return latest;
3897
+ }
3898
+ return null;
3899
+ }
3900
+ async function startupUpdateCheck(currentVersion, autoUpdate) {
3901
+ const latest = await checkForUpdate(currentVersion);
3902
+ if (!latest) return;
3903
+ console.log("");
3904
+ console.log(` \u{1F4E6} Update available: v${currentVersion} \u2192 v${latest}`);
3905
+ if (autoUpdate && isServiceInstalled()) {
3906
+ console.log(" Auto-updating...");
3907
+ const ok = performUpdate(latest);
3908
+ if (ok) {
3909
+ console.log(" \u2705 Update complete \u2014 service will restart.");
3910
+ process.exit(0);
3911
+ } else {
3912
+ console.log(" \u26A0\uFE0F Auto-update failed \u2014 continuing with current version.");
3913
+ }
3914
+ } else {
3915
+ console.log(` Run: npm cache clean --force && npx ${PACKAGE_NAME}@${latest}`);
3916
+ console.log("");
3917
+ }
3918
+ }
3919
+ function startPeriodicUpdateCheck(currentVersion) {
3920
+ if (updateTimer) return;
3921
+ updateTimer = setInterval(async () => {
3922
+ const latest = await checkForUpdate(currentVersion);
3923
+ if (latest && isServiceInstalled()) {
3924
+ console.log(`[updater] New version available: v${latest} \u2014 auto-updating...`);
3925
+ const ok = performUpdate(latest);
3926
+ if (ok) {
3927
+ console.log("[updater] Update complete \u2014 restarting.");
3928
+ process.exit(0);
3929
+ }
3930
+ }
3931
+ }, CHECK_INTERVAL_MS);
3932
+ if (updateTimer.unref) updateTimer.unref();
3933
+ }
3934
+ function stopPeriodicUpdateCheck() {
3935
+ if (updateTimer) {
3936
+ clearInterval(updateTimer);
3937
+ updateTimer = null;
3938
+ }
3939
+ }
3940
+
3829
3941
  // src/gateway/token-discovery.ts
3830
3942
  var import_fs5 = __toESM(require("fs"));
3831
3943
  var import_path5 = __toESM(require("path"));
@@ -3888,7 +4000,7 @@ async function discoverGatewayToken() {
3888
4000
  }
3889
4001
 
3890
4002
  // src/main.ts
3891
- var VERSION = "0.4.0";
4003
+ var VERSION = "0.4.2";
3892
4004
  function parseArgs() {
3893
4005
  const args = process.argv.slice(2);
3894
4006
  const opts = {
@@ -4111,6 +4223,9 @@ async function main() {
4111
4223
  console.log(" \u2502 Open Source \xB7 Apache License 2.0 \u2502");
4112
4224
  console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
4113
4225
  console.log("");
4226
+ const isService = isServiceInstalled();
4227
+ startupUpdateCheck(VERSION, isService).catch(() => {
4228
+ });
4114
4229
  if (!opts.bridgeUrl) {
4115
4230
  const discovered = await discoverBridge();
4116
4231
  if (discovered) {
@@ -4190,14 +4305,19 @@ async function main() {
4190
4305
  resumeSessionKey,
4191
4306
  gatewayConfig
4192
4307
  });
4308
+ if (isService) {
4309
+ startPeriodicUpdateCheck(VERSION);
4310
+ }
4193
4311
  }
4194
4312
  process.on("SIGINT", () => {
4195
4313
  console.log("\n[relay-agent] Shutting down...");
4314
+ stopPeriodicUpdateCheck();
4196
4315
  stopRelayClient();
4197
4316
  process.exit(0);
4198
4317
  });
4199
4318
  process.on("SIGTERM", () => {
4200
4319
  console.log("\n[relay-agent] Terminated");
4320
+ stopPeriodicUpdateCheck();
4201
4321
  stopRelayClient();
4202
4322
  process.exit(0);
4203
4323
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "echoclaw-relay-agent",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "EchoClaw Relay Agent — connects OpenClaw bridge to the EchoClaw Relay Server with E2E encryption",
5
5
  "main": "./dist/main.js",
6
6
  "bin": {