@alfe.ai/gateway 0.0.17 → 0.0.18

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/health.js +22 -265
  2. package/package.json +5 -5
package/dist/health.js CHANGED
@@ -12,7 +12,6 @@ import WebSocket from "ws";
12
12
  import { createConnection, createServer } from "node:net";
13
13
  import { execSync, spawn } from "node:child_process";
14
14
  import { IntegrationManager, IntegrationManagerAdapter, OpenClawApplier } from "@alfe.ai/integrations";
15
- import { randomUUID } from "node:crypto";
16
15
  import stream, { Readable } from "stream";
17
16
  import util, { format } from "util";
18
17
  import http from "http";
@@ -21,6 +20,7 @@ import url from "url";
21
20
  import http2 from "http2";
22
21
  import zlib from "zlib";
23
22
  import { EventEmitter } from "events";
23
+ import { randomUUID } from "node:crypto";
24
24
  //#region \0rolldown/runtime.js
25
25
  var __create = Object.create;
26
26
  var __defProp = Object.defineProperty;
@@ -3465,7 +3465,7 @@ async function loadManagedConfig() {
3465
3465
  apiKey,
3466
3466
  apiEndpoint,
3467
3467
  gatewayWsUrl,
3468
- socketPath: "/tmp/alfe-gateway.sock",
3468
+ socketPath: SOCKET_PATH,
3469
3469
  pidPath: "",
3470
3470
  agentId: identity.agentId,
3471
3471
  orgId: identity.orgId,
@@ -3684,22 +3684,6 @@ function createReconciliationReport(results) {
3684
3684
  };
3685
3685
  }
3686
3686
  /**
3687
- * Type guard: is this a cloud SERVICE_RELAY message?
3688
- */
3689
- function isCloudServiceRelay(msg) {
3690
- return typeof msg === "object" && msg !== null && msg.type === "SERVICE_RELAY";
3691
- }
3692
- /**
3693
- * Create an AGENT_EVENT message for cloud relay.
3694
- */
3695
- function createAgentEvent(agentId, payload) {
3696
- return {
3697
- type: "AGENT_EVENT",
3698
- agentId,
3699
- payload
3700
- };
3701
- }
3702
- /**
3703
3687
  * Type guard: is this a cloud PING message?
3704
3688
  */
3705
3689
  function isCloudPing(msg) {
@@ -3721,7 +3705,7 @@ function isIPCResponse(msg) {
3721
3705
  const PROTOCOL_VERSION = 1;
3722
3706
  //#endregion
3723
3707
  //#region src/reconciliation.ts
3724
- const log$2 = logger$1.child({ component: "Reconciliation" });
3708
+ const log$1 = logger$1.child({ component: "Reconciliation" });
3725
3709
  var ReconciliationEngine = class {
3726
3710
  constructor(manager) {
3727
3711
  this.manager = manager;
@@ -3742,7 +3726,7 @@ var ReconciliationEngine = class {
3742
3726
  try {
3743
3727
  localIntegrations = await this.manager.getInstalledIntegrations();
3744
3728
  } catch (err) {
3745
- log$2.error({ err }, "Failed to get local integrations");
3729
+ log$1.error({ err }, "Failed to get local integrations");
3746
3730
  localIntegrations = [];
3747
3731
  }
3748
3732
  const localMap = new Map(localIntegrations.map((i) => [i.id, i]));
@@ -3756,10 +3740,10 @@ var ReconciliationEngine = class {
3756
3740
  const id = desired.integrationId;
3757
3741
  try {
3758
3742
  if (!local) {
3759
- log$2.info(`Installing ${id}@${desired.version}`);
3743
+ log$1.info(`Installing ${id}@${desired.version}`);
3760
3744
  await this.manager.install(id, desired.version, desired.config);
3761
3745
  report.installed.push(id);
3762
- log$2.info(`Activating ${id}`);
3746
+ log$1.info(`Activating ${id}`);
3763
3747
  await this.manager.activate(id);
3764
3748
  report.activated.push(id);
3765
3749
  report.results.push({
@@ -3770,14 +3754,14 @@ var ReconciliationEngine = class {
3770
3754
  return;
3771
3755
  }
3772
3756
  if (local.version !== desired.version && desired.version !== "" && local.version !== "unknown") {
3773
- log$2.info(`Upgrading ${id}: ${local.version} → ${desired.version}`);
3757
+ log$1.info(`Upgrading ${id}: ${local.version} → ${desired.version}`);
3774
3758
  try {
3775
3759
  await this.manager.deactivate(id);
3776
3760
  await this.manager.uninstall(id);
3777
3761
  } catch {}
3778
3762
  await this.manager.install(id, desired.version, desired.config);
3779
3763
  report.installed.push(id);
3780
- log$2.info(`Activating ${id}`);
3764
+ log$1.info(`Activating ${id}`);
3781
3765
  await this.manager.activate(id);
3782
3766
  report.activated.push(id);
3783
3767
  report.results.push({
@@ -3788,7 +3772,7 @@ var ReconciliationEngine = class {
3788
3772
  return;
3789
3773
  }
3790
3774
  if (local.status !== "active") {
3791
- log$2.info(`Activating ${id}`);
3775
+ log$1.info(`Activating ${id}`);
3792
3776
  await this.manager.activate(id);
3793
3777
  report.activated.push(id);
3794
3778
  report.results.push({
@@ -3805,7 +3789,7 @@ var ReconciliationEngine = class {
3805
3789
  });
3806
3790
  } catch (err) {
3807
3791
  const message = err instanceof Error ? err.message : String(err);
3808
- log$2.error({ err }, `Error reconciling ${id}`);
3792
+ log$1.error({ err }, `Error reconciling ${id}`);
3809
3793
  report.errors.push({
3810
3794
  integrationId: id,
3811
3795
  error: message
@@ -3828,7 +3812,7 @@ var ReconciliationEngine = class {
3828
3812
  return;
3829
3813
  }
3830
3814
  try {
3831
- log$2.info(`Removing ${id}`);
3815
+ log$1.info(`Removing ${id}`);
3832
3816
  if (local.status === "active") {
3833
3817
  await this.manager.deactivate(id);
3834
3818
  report.deactivated.push(id);
@@ -3842,7 +3826,7 @@ var ReconciliationEngine = class {
3842
3826
  });
3843
3827
  } catch (err) {
3844
3828
  const message = err instanceof Error ? err.message : String(err);
3845
- log$2.error({ err }, `Error removing ${id}`);
3829
+ log$1.error({ err }, `Error removing ${id}`);
3846
3830
  report.errors.push({
3847
3831
  integrationId: id,
3848
3832
  error: message
@@ -3876,7 +3860,6 @@ var CloudClient = class {
3876
3860
  config;
3877
3861
  onCommand = null;
3878
3862
  onConnectionChange = null;
3879
- onServiceRelay = null;
3880
3863
  onPluginsChanged = null;
3881
3864
  reconciliationEngine = null;
3882
3865
  constructor(config) {
@@ -3898,20 +3881,6 @@ var CloudClient = class {
3898
3881
  this.onConnectionChange = handler;
3899
3882
  }
3900
3883
  /**
3901
- * Set the handler for incoming SERVICE_RELAY messages (forwarded from services).
3902
- * Used to bridge service messages to the local agent runtime.
3903
- */
3904
- setServiceRelayHandler(handler) {
3905
- this.onServiceRelay = handler;
3906
- }
3907
- /**
3908
- * Send an AGENT_EVENT to the cloud gateway for relay to connected services.
3909
- */
3910
- sendAgentEvent(payload) {
3911
- const msg = createAgentEvent(this.config.agentId, payload);
3912
- this.send(msg);
3913
- }
3914
- /**
3915
3884
  * Set the integration manager for reconciliation.
3916
3885
  * When set, the cloud client will handle DESIRED_STATE messages automatically.
3917
3886
  */
@@ -4039,10 +4008,6 @@ var CloudClient = class {
4039
4008
  await this.handleDesiredState(msg);
4040
4009
  return;
4041
4010
  }
4042
- if (isCloudServiceRelay(msg)) {
4043
- this.handleServiceRelay(msg);
4044
- return;
4045
- }
4046
4011
  if (isCloudCommand(msg)) {
4047
4012
  await this.handleCommand(msg);
4048
4013
  return;
@@ -4123,11 +4088,6 @@ var CloudClient = class {
4123
4088
  logger$1.error({ err: message }, "Cloud: reconciliation failed");
4124
4089
  }
4125
4090
  }
4126
- handleServiceRelay(relay) {
4127
- logger$1.debug({ sourceServiceId: relay.sourceServiceId }, "Cloud: received SERVICE_RELAY");
4128
- if (this.onServiceRelay) this.onServiceRelay(relay);
4129
- else logger$1.warn("Cloud: SERVICE_RELAY received but no handler set — dropping");
4130
- }
4131
4091
  send(msg) {
4132
4092
  if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(JSON.stringify(msg));
4133
4093
  else logger$1.debug({ readyState: this.ws?.readyState }, "Cloud: send skipped — WebSocket not open");
@@ -19783,7 +19743,7 @@ function createLogger(component, additionalData) {
19783
19743
  * Spawns the runtime binary, pipes stdout/stderr to the daemon logger,
19784
19744
  * and restarts on crash with exponential backoff.
19785
19745
  */
19786
- const log$1 = createLogger("RuntimeProcess");
19746
+ const log = createLogger("RuntimeProcess");
19787
19747
  const BACKOFF_INITIAL_MS = 1e3;
19788
19748
  const BACKOFF_MAX_MS = 3e4;
19789
19749
  const STABLE_UPTIME_MS = 6e4;
@@ -19819,7 +19779,7 @@ var RuntimeProcess = class {
19819
19779
  if (this.stopped) return;
19820
19780
  const { command, args } = this.resolveCommand();
19821
19781
  this.lastStartTime = Date.now();
19822
- log$1.info({
19782
+ log.info({
19823
19783
  runtime: this.options.runtime,
19824
19784
  command,
19825
19785
  args,
@@ -19838,14 +19798,14 @@ var RuntimeProcess = class {
19838
19798
  });
19839
19799
  this.child.stdout?.on("data", (data) => {
19840
19800
  const lines = data.toString().trim().split("\n");
19841
- for (const line of lines) log$1.info({
19801
+ for (const line of lines) log.info({
19842
19802
  runtime: this.options.runtime,
19843
19803
  stream: "stdout"
19844
19804
  }, line);
19845
19805
  });
19846
19806
  this.child.stderr?.on("data", (data) => {
19847
19807
  const lines = data.toString().trim().split("\n");
19848
- for (const line of lines) log$1.warn({
19808
+ for (const line of lines) log.warn({
19849
19809
  runtime: this.options.runtime,
19850
19810
  stream: "stderr"
19851
19811
  }, line);
@@ -19853,14 +19813,14 @@ var RuntimeProcess = class {
19853
19813
  this.child.on("exit", (code, signal) => {
19854
19814
  this.child = null;
19855
19815
  if (this.stopped) {
19856
- log$1.info({
19816
+ log.info({
19857
19817
  runtime: this.options.runtime,
19858
19818
  code,
19859
19819
  signal
19860
19820
  }, "Runtime stopped (expected)");
19861
19821
  return;
19862
19822
  }
19863
- log$1.warn({
19823
+ log.warn({
19864
19824
  runtime: this.options.runtime,
19865
19825
  code,
19866
19826
  signal,
@@ -19874,7 +19834,7 @@ var RuntimeProcess = class {
19874
19834
  this.backoffMs = Math.min(this.backoffMs * 2, BACKOFF_MAX_MS);
19875
19835
  });
19876
19836
  this.child.on("error", (err) => {
19877
- log$1.error({
19837
+ log.error({
19878
19838
  runtime: this.options.runtime,
19879
19839
  err: err.message
19880
19840
  }, "Runtime process error");
@@ -19893,7 +19853,7 @@ var RuntimeProcess = class {
19893
19853
  if (!child) return;
19894
19854
  return new Promise((resolve) => {
19895
19855
  const killTimer = setTimeout(() => {
19896
- log$1.warn({ runtime: this.options.runtime }, "Runtime did not exit in time — sending SIGKILL");
19856
+ log.warn({ runtime: this.options.runtime }, "Runtime did not exit in time — sending SIGKILL");
19897
19857
  child.kill("SIGKILL");
19898
19858
  }, 5e3);
19899
19859
  child.on("exit", () => {
@@ -19907,7 +19867,7 @@ var RuntimeProcess = class {
19907
19867
  * Restart the runtime process (stop then start with fresh backoff).
19908
19868
  */
19909
19869
  async restart() {
19910
- log$1.info({ runtime: this.options.runtime }, "Restarting runtime...");
19870
+ log.info({ runtime: this.options.runtime }, "Restarting runtime...");
19911
19871
  await this.stop();
19912
19872
  this.stopped = false;
19913
19873
  this.backoffMs = BACKOFF_INITIAL_MS;
@@ -19921,175 +19881,6 @@ var RuntimeProcess = class {
19921
19881
  }
19922
19882
  };
19923
19883
  //#endregion
19924
- //#region src/local-agent-relay.ts
19925
- /**
19926
- * LocalAgentRelay — bridges the cloud gateway to the agent runtime's local
19927
- * WebSocket server (e.g. OpenClaw on localhost:18789).
19928
- *
19929
- * Incoming SERVICE_RELAY messages from the cloud are forwarded to the local WS.
19930
- * Events and responses from the local WS are forwarded as AGENT_EVENT to the cloud.
19931
- */
19932
- const log = createLogger("LocalAgentRelay");
19933
- const CONNECT_RETRY_DELAYS = [
19934
- 500,
19935
- 1e3,
19936
- 2e3,
19937
- 4e3,
19938
- 8e3,
19939
- 15e3,
19940
- 3e4
19941
- ];
19942
- var LocalAgentRelay = class {
19943
- ws = null;
19944
- stopped = false;
19945
- connected = false;
19946
- retryCount = 0;
19947
- retryTimer = null;
19948
- constructor(options) {
19949
- this.options = options;
19950
- }
19951
- /**
19952
- * Start connecting to the local runtime WS.
19953
- */
19954
- start() {
19955
- log.debug({ wsUrl: this.options.wsUrl }, "Local relay starting...");
19956
- this.stopped = false;
19957
- this.doConnect();
19958
- }
19959
- /**
19960
- * Stop the relay and close the local WS connection.
19961
- */
19962
- stop() {
19963
- log.debug("Local relay stopping...");
19964
- this.stopped = true;
19965
- if (this.retryTimer) {
19966
- clearTimeout(this.retryTimer);
19967
- this.retryTimer = null;
19968
- }
19969
- if (this.ws) {
19970
- log.debug({ readyState: this.ws.readyState }, "Local relay: closing WebSocket");
19971
- try {
19972
- this.ws.close(1e3);
19973
- } catch (err) {
19974
- log.debug({ err }, "websocket close failed during relay stop");
19975
- }
19976
- this.ws = null;
19977
- }
19978
- this.connected = false;
19979
- log.debug("Local relay stopped");
19980
- }
19981
- /**
19982
- * Forward a message payload from the cloud to the local runtime WS.
19983
- */
19984
- forward(payload) {
19985
- if (this.ws?.readyState !== WebSocket.OPEN) {
19986
- log.warn({ readyState: this.ws?.readyState }, "Cannot forward to local runtime — not connected");
19987
- return;
19988
- }
19989
- const data = typeof payload === "string" ? payload : JSON.stringify(payload);
19990
- log.debug({ size: data.length }, "Local relay: forwarding message to runtime");
19991
- this.ws.send(data);
19992
- }
19993
- get isConnected() {
19994
- return this.connected;
19995
- }
19996
- doConnect() {
19997
- if (this.stopped) {
19998
- log.debug("Local relay: doConnect skipped — relay is stopped");
19999
- return;
20000
- }
20001
- log.info({
20002
- url: this.options.wsUrl,
20003
- retryCount: this.retryCount
20004
- }, "Connecting to local runtime WS...");
20005
- this.ws = new WebSocket(this.options.wsUrl, { handshakeTimeout: 1e4 });
20006
- this.ws.on("open", () => {
20007
- log.info("Local runtime WS connected — performing handshake");
20008
- this.retryCount = 0;
20009
- this.performHandshake();
20010
- });
20011
- this.ws.on("message", (data) => {
20012
- const text = Buffer.isBuffer(data) ? data.toString("utf-8") : Buffer.from(data).toString("utf-8");
20013
- log.debug({ size: text.length }, "Local relay: received message");
20014
- this.handleLocalMessage(text);
20015
- });
20016
- this.ws.on("close", (code, reason) => {
20017
- log.warn({
20018
- code,
20019
- reason: reason.toString()
20020
- }, "Local runtime WS disconnected");
20021
- this.connected = false;
20022
- this.scheduleReconnect();
20023
- });
20024
- this.ws.on("error", (err) => {
20025
- log.warn({
20026
- err: err.message,
20027
- url: this.options.wsUrl
20028
- }, "Local runtime WS error");
20029
- });
20030
- }
20031
- performHandshake() {
20032
- log.debug("Local relay: sending connect handshake");
20033
- const connectReq = {
20034
- type: "req",
20035
- id: randomUUID(),
20036
- method: "connect",
20037
- params: {
20038
- minProtocol: 3,
20039
- maxProtocol: 3,
20040
- client: {
20041
- id: "gateway-client",
20042
- displayName: "Alfe Daemon Relay",
20043
- version: "0.1.0",
20044
- platform: process.platform,
20045
- mode: "backend",
20046
- instanceId: randomUUID()
20047
- },
20048
- caps: [],
20049
- role: "operator",
20050
- scopes: ["operator.admin"],
20051
- auth: { token: this.options.apiKey }
20052
- }
20053
- };
20054
- this.ws?.send(JSON.stringify(connectReq));
20055
- this.handshakeId = connectReq.id;
20056
- }
20057
- handshakeId = null;
20058
- handleLocalMessage(raw) {
20059
- let msg;
20060
- try {
20061
- msg = JSON.parse(raw);
20062
- } catch {
20063
- return;
20064
- }
20065
- if (this.handshakeId && msg.id === this.handshakeId) {
20066
- this.handshakeId = null;
20067
- if (msg.ok) {
20068
- this.connected = true;
20069
- log.info("Local runtime handshake complete — relay active");
20070
- } else {
20071
- log.error({ error: msg.error }, "Local runtime handshake failed");
20072
- this.ws?.close(1008, "Handshake failed");
20073
- }
20074
- return;
20075
- }
20076
- this.options.onAgentMessage(msg);
20077
- }
20078
- scheduleReconnect() {
20079
- if (this.stopped) return;
20080
- const delay = CONNECT_RETRY_DELAYS[Math.min(this.retryCount, CONNECT_RETRY_DELAYS.length - 1)];
20081
- this.retryCount++;
20082
- log.info({
20083
- delayMs: delay,
20084
- retryCount: this.retryCount
20085
- }, "Scheduling reconnect to local runtime");
20086
- this.retryTimer = setTimeout(() => {
20087
- this.retryTimer = null;
20088
- this.doConnect();
20089
- }, delay);
20090
- }
20091
- };
20092
- //#endregion
20093
19884
  //#region src/daemon.ts
20094
19885
  /**
20095
19886
  * Alfe Gateway Daemon — main entry point.
@@ -20113,7 +19904,6 @@ let startedAt;
20113
19904
  let integrationManager;
20114
19905
  let aiProxyServer = null;
20115
19906
  let runtimeProcess = null;
20116
- let localRelay = null;
20117
19907
  let aiProxyUrl = null;
20118
19908
  let aiProxyRunning = false;
20119
19909
  let cloudConnected = false;
@@ -20295,7 +20085,6 @@ async function startDaemon() {
20295
20085
  logger$1.debug({ runtime: config.runtime }, "Starting agent runtime...");
20296
20086
  const runtimeCfg = config.runtimes[config.runtime];
20297
20087
  if (runtimeCfg) {
20298
- const runtimeToken = randomUUID();
20299
20088
  logger$1.debug({
20300
20089
  runtime: config.runtime,
20301
20090
  workspace: runtimeCfg.workspace
@@ -20303,37 +20092,10 @@ async function startDaemon() {
20303
20092
  runtimeProcess = new RuntimeProcess({
20304
20093
  runtime: config.runtime,
20305
20094
  workspace: runtimeCfg.workspace,
20306
- env: {
20307
- ALFE_GATEWAY_SOCKET: config.socketPath,
20308
- ALFE_API_KEY: config.apiKey,
20309
- ALFE_API_URL: config.apiEndpoint,
20310
- ALFE_AGENT_ID: config.agentId,
20311
- ANTHROPIC_BASE_URL: aiProxyUrl ?? "http://127.0.0.1:18193",
20312
- OPENAI_BASE_URL: aiProxyUrl ?? "http://127.0.0.1:18193",
20313
- ANTHROPIC_API_KEY: config.apiKey,
20314
- OPENAI_API_KEY: config.apiKey,
20315
- OPENCLAW_GATEWAY_TOKEN: runtimeToken
20316
- }
20095
+ env: {}
20317
20096
  });
20318
20097
  runtimeProcess.start();
20319
20098
  logger$1.debug("Runtime process started");
20320
- const RUNTIME_WS_PORT = 18789;
20321
- logger$1.debug({ runtimeWsPort: RUNTIME_WS_PORT }, "Creating local agent relay...");
20322
- const relay = new LocalAgentRelay({
20323
- wsUrl: `ws://127.0.0.1:${String(RUNTIME_WS_PORT)}`,
20324
- apiKey: runtimeToken,
20325
- onAgentMessage: (payload) => {
20326
- cloudClient.sendAgentEvent(payload);
20327
- }
20328
- });
20329
- localRelay = relay;
20330
- cloudClient.setServiceRelayHandler((msg) => {
20331
- relay.forward(msg.payload);
20332
- });
20333
- logger$1.debug("Scheduling local relay start in 2s (waiting for runtime WS server)...");
20334
- setTimeout(() => {
20335
- relay.start();
20336
- }, 2e3);
20337
20099
  } else logger$1.warn({ runtime: config.runtime }, "No runtime config found — skipping runtime start");
20338
20100
  }
20339
20101
  if (!managed) await writePidFile();
@@ -20341,11 +20103,6 @@ async function startDaemon() {
20341
20103
  if (shuttingDown) return;
20342
20104
  shuttingDown = true;
20343
20105
  logger$1.info({ signal }, "Shutting down...");
20344
- if (localRelay) {
20345
- logger$1.debug("Stopping local relay...");
20346
- localRelay.stop();
20347
- logger$1.debug("Local relay stopped");
20348
- }
20349
20106
  if (runtimeProcess) {
20350
20107
  logger$1.debug("Stopping runtime process...");
20351
20108
  await runtimeProcess.stop();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/gateway",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "Alfe local gateway daemon — persistent control plane for agent integrations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,10 +22,10 @@
22
22
  "pino-roll": "^1.2.0",
23
23
  "smol-toml": ">=1.6.1",
24
24
  "ws": "^8.18.0",
25
- "@alfe.ai/ai-proxy-local": "^0.0.4",
26
- "@alfe.ai/doctor": "^0.0.5",
27
- "@alfe.ai/integrations": "^0.0.10",
28
- "@alfe.ai/config": "^0.0.4"
25
+ "@alfe.ai/ai-proxy-local": "^0.0.5",
26
+ "@alfe.ai/config": "^0.0.5",
27
+ "@alfe.ai/doctor": "^0.0.6",
28
+ "@alfe.ai/integrations": "^0.0.10"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/ws": "^8.5.13",