@alfe.ai/gateway 0.0.30 → 0.0.32

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 +91 -24
  2. package/package.json +5 -5
package/dist/health.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { n as logger$1 } from "./logger.js";
2
2
  import { createRequire } from "node:module";
3
3
  import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
4
+ import { execFile, execSync, spawn } from "node:child_process";
5
+ import { promisify } from "node:util";
4
6
  import { join } from "node:path";
5
7
  import { homedir } from "node:os";
6
8
  import pino from "pino";
@@ -10,7 +12,6 @@ import crypto from "crypto";
10
12
  import { parse } from "smol-toml";
11
13
  import WebSocket from "ws";
12
14
  import { createConnection, createServer } from "node:net";
13
- import { execSync, spawn } from "node:child_process";
14
15
  import { IntegrationManager, IntegrationManagerAdapter, OpenClawApplier } from "@alfe.ai/integrations";
15
16
  import stream, { Readable } from "stream";
16
17
  import util, { format } from "util";
@@ -487,16 +488,16 @@ var IntegrationsService = class {
487
488
  return this.client.request(`/discord/guilds/${encodeURIComponent(guildId)}/channels`);
488
489
  }
489
490
  listMobileNumbers() {
490
- return this.client.request("/twilio/numbers");
491
+ return this.client.request("/mobile/numbers");
491
492
  }
492
493
  searchMobileNumbers(country, query) {
493
494
  const params = new URLSearchParams();
494
495
  if (country) params.set("country", country);
495
496
  if (query) params.set("query", query);
496
- return this.client.request(`/twilio/numbers/search?${params}`);
497
+ return this.client.request(`/mobile/numbers/search?${params}`);
497
498
  }
498
499
  assignMobileNumber(agentId, phoneNumber, countryCode) {
499
- return this.client.request("/twilio/numbers/assign", {
500
+ return this.client.request("/mobile/numbers/assign", {
500
501
  method: "POST",
501
502
  body: JSON.stringify({
502
503
  agentId,
@@ -505,12 +506,15 @@ var IntegrationsService = class {
505
506
  })
506
507
  });
507
508
  }
508
- releaseMobileNumber(phoneSid) {
509
- return this.client.request("/twilio/numbers/release", {
509
+ releaseMobileNumber(agentId) {
510
+ return this.client.request("/mobile/numbers/release", {
510
511
  method: "POST",
511
- body: JSON.stringify({ phoneSid })
512
+ body: JSON.stringify({ agentId })
512
513
  });
513
514
  }
515
+ getMobileNumber(agentId) {
516
+ return this.client.request(`/mobile/numbers?agentId=${encodeURIComponent(agentId)}`);
517
+ }
514
518
  recallJoinMeeting(agentId, meetingUrl, botName) {
515
519
  if (this.voiceClient) return this.voiceClient.request("/api/join", {
516
520
  method: "POST",
@@ -3704,7 +3708,7 @@ async function loadDaemonConfig() {
3704
3708
  if (isManagedMode()) return loadManagedConfig();
3705
3709
  let alfeConfig;
3706
3710
  try {
3707
- alfeConfig = await readConfig();
3711
+ alfeConfig = readConfig();
3708
3712
  } catch {
3709
3713
  throw new Error("Alfe not configured. Run `alfe login` first.");
3710
3714
  }
@@ -3946,7 +3950,8 @@ var ReconciliationEngine = class {
3946
3950
  activated: [],
3947
3951
  deactivated: [],
3948
3952
  uninstalled: [],
3949
- errors: []
3953
+ errors: [],
3954
+ configApplied: false
3950
3955
  };
3951
3956
  let localIntegrations;
3952
3957
  try {
@@ -3970,7 +3975,7 @@ var ReconciliationEngine = class {
3970
3975
  await this.manager.install(id, desired.version, desired.config);
3971
3976
  report.installed.push(id);
3972
3977
  log$2.info(`Activating ${id}`);
3973
- await this.manager.activate(id);
3978
+ if ((await this.manager.activate(id)).configApplied) report.configApplied = true;
3974
3979
  report.activated.push(id);
3975
3980
  report.results.push({
3976
3981
  integrationId: id,
@@ -3981,7 +3986,7 @@ var ReconciliationEngine = class {
3981
3986
  }
3982
3987
  if (local.version !== desired.version && desired.version !== "" && local.version !== "unknown") {
3983
3988
  log$2.info(`Upgrading ${id}: ${local.version} → ${desired.version}`);
3984
- await this.manager.reinstall(id, desired.version, desired.config);
3989
+ if ((await this.manager.reinstall(id, desired.version, desired.config)).configApplied) report.configApplied = true;
3985
3990
  report.installed.push(id);
3986
3991
  report.activated.push(id);
3987
3992
  report.results.push({
@@ -3994,7 +3999,7 @@ var ReconciliationEngine = class {
3994
3999
  if (local.status === "error") {
3995
4000
  if (desired.reinstallRequestedAt && local.installedAt && desired.reinstallRequestedAt > local.installedAt) {
3996
4001
  log$2.info(`Reinstalling ${id} from error state (requested: ${desired.reinstallRequestedAt}, installed: ${local.installedAt})`);
3997
- await this.manager.reinstall(id, desired.version, desired.config);
4002
+ if ((await this.manager.reinstall(id, desired.version, desired.config)).configApplied) report.configApplied = true;
3998
4003
  report.installed.push(id);
3999
4004
  report.activated.push(id);
4000
4005
  report.results.push({
@@ -4019,7 +4024,7 @@ var ReconciliationEngine = class {
4019
4024
  }
4020
4025
  if (local.status !== "active") {
4021
4026
  log$2.info(`Activating ${id}`);
4022
- await this.manager.activate(id);
4027
+ if ((await this.manager.activate(id)).configApplied) report.configApplied = true;
4023
4028
  report.activated.push(id);
4024
4029
  report.results.push({
4025
4030
  integrationId: id,
@@ -4030,7 +4035,7 @@ var ReconciliationEngine = class {
4030
4035
  }
4031
4036
  if (desired.reinstallRequestedAt && local.installedAt && desired.reinstallRequestedAt > local.installedAt) {
4032
4037
  log$2.info(`Reinstall requested for ${id} (requested: ${desired.reinstallRequestedAt}, installed: ${local.installedAt})`);
4033
- await this.manager.reinstall(id, desired.version, desired.config);
4038
+ if ((await this.manager.reinstall(id, desired.version, desired.config)).configApplied) report.configApplied = true;
4034
4039
  report.installed.push(id);
4035
4040
  report.activated.push(id);
4036
4041
  report.results.push({
@@ -4118,7 +4123,7 @@ var CloudClient = class {
4118
4123
  config;
4119
4124
  onCommand = null;
4120
4125
  onConnectionChange = null;
4121
- onPluginsChanged = null;
4126
+ onRuntimeRestartNeeded = null;
4122
4127
  onReconciliationComplete = null;
4123
4128
  reconciliationEngine = null;
4124
4129
  constructor(config) {
@@ -4144,10 +4149,10 @@ var CloudClient = class {
4144
4149
  * When set, the cloud client will handle DESIRED_STATE messages automatically.
4145
4150
  */
4146
4151
  /**
4147
- * Set a callback for when plugins change (install/uninstall)used to restart the runtime.
4152
+ * Set a callback for when the runtime needs restarting plugins changed or config applied.
4148
4153
  */
4149
- setPluginsChangedHandler(handler) {
4150
- this.onPluginsChanged = handler;
4154
+ setRuntimeRestartNeededHandler(handler) {
4155
+ this.onRuntimeRestartNeeded = handler;
4151
4156
  }
4152
4157
  /**
4153
4158
  * Set a callback for when reconciliation completes — used to rebuild command registry.
@@ -4354,7 +4359,7 @@ var CloudClient = class {
4354
4359
  }, "Cloud: reconciliation complete");
4355
4360
  const reportMsg = createReconciliationReport(report.results);
4356
4361
  this.send(reportMsg);
4357
- if ((report.installed.length > 0 || report.uninstalled.length > 0) && this.onPluginsChanged) this.onPluginsChanged();
4362
+ if ((report.installed.length > 0 || report.uninstalled.length > 0 || report.configApplied) && this.onRuntimeRestartNeeded) this.onRuntimeRestartNeeded();
4358
4363
  this.onReconciliationComplete?.();
4359
4364
  } catch (err) {
4360
4365
  const message = err instanceof Error ? err.message : String(err);
@@ -20019,7 +20024,6 @@ function createLogger(component, additionalData) {
20019
20024
  const log$1 = createLogger("RuntimeProcess");
20020
20025
  const BACKOFF_INITIAL_MS = 1e3;
20021
20026
  const BACKOFF_MAX_MS = 3e4;
20022
- const STABLE_UPTIME_MS = 6e4;
20023
20027
  var RuntimeProcess = class {
20024
20028
  child = null;
20025
20029
  stopped = false;
@@ -20094,13 +20098,24 @@ var RuntimeProcess = class {
20094
20098
  }, "Runtime stopped (expected)");
20095
20099
  return;
20096
20100
  }
20101
+ if (code === 0 && signal == null) {
20102
+ log$1.info({
20103
+ runtime: this.options.runtime,
20104
+ code
20105
+ }, "Runtime exited gracefully — restarting");
20106
+ this.restartTimer = setTimeout(() => {
20107
+ this.restartTimer = null;
20108
+ this.start();
20109
+ }, 500);
20110
+ return;
20111
+ }
20097
20112
  log$1.warn({
20098
20113
  runtime: this.options.runtime,
20099
20114
  code,
20100
20115
  signal,
20101
20116
  backoffMs: this.backoffMs
20102
- }, "Runtime exited unexpectedly — scheduling restart");
20103
- if (Date.now() - this.lastStartTime >= STABLE_UPTIME_MS) this.backoffMs = BACKOFF_INITIAL_MS;
20117
+ }, "Runtime crashed — scheduling restart with backoff");
20118
+ if (Date.now() - this.lastStartTime >= 6e4) this.backoffMs = BACKOFF_INITIAL_MS;
20104
20119
  this.restartTimer = setTimeout(() => {
20105
20120
  this.restartTimer = null;
20106
20121
  this.start();
@@ -20318,6 +20333,7 @@ var CommandRegistry = class {
20318
20333
  * 8. Write PID file (non-managed only)
20319
20334
  * 9. Handle graceful shutdown
20320
20335
  */
20336
+ const execFileAsync = promisify(execFile);
20321
20337
  let config;
20322
20338
  let cloudClient;
20323
20339
  let ipcServer = null;
@@ -20495,9 +20511,9 @@ async function startDaemon() {
20495
20511
  });
20496
20512
  const integrationAdapter = new IntegrationManagerAdapter(integrationManager);
20497
20513
  cloudClient.setIntegrationManager(integrationAdapter);
20498
- cloudClient.setPluginsChangedHandler(() => {
20514
+ cloudClient.setRuntimeRestartNeededHandler(() => {
20499
20515
  if (runtimeProcess) {
20500
- logger$1.info("Plugins changed — restarting runtime to load new plugins");
20516
+ logger$1.info("Runtime state changed — restarting runtime");
20501
20517
  runtimeProcess.restart().catch((err) => {
20502
20518
  logger$1.error({ err: err instanceof Error ? err.message : String(err) }, "Failed to restart runtime");
20503
20519
  });
@@ -20645,6 +20661,57 @@ async function handleCloudCommand(command) {
20645
20661
  };
20646
20662
  }
20647
20663
  }
20664
+ if (command.command === "alfe.config_set") {
20665
+ const payload = command.payload;
20666
+ const key = payload?.key;
20667
+ const value = payload?.value;
20668
+ if (!key || value === void 0) return {
20669
+ type: "COMMAND_ACK",
20670
+ commandId: command.commandId,
20671
+ status: "error",
20672
+ result: {
20673
+ code: "INVALID_PAYLOAD",
20674
+ message: "alfe.config_set requires key and value"
20675
+ }
20676
+ };
20677
+ try {
20678
+ await execFileAsync("openclaw", [
20679
+ "config",
20680
+ "set",
20681
+ key,
20682
+ value
20683
+ ], { timeout: 1e4 });
20684
+ logger$1.info({
20685
+ key,
20686
+ value
20687
+ }, "Applied config via openclaw config set");
20688
+ return {
20689
+ type: "COMMAND_ACK",
20690
+ commandId: command.commandId,
20691
+ status: "ok",
20692
+ result: {
20693
+ key,
20694
+ value
20695
+ }
20696
+ };
20697
+ } catch (err) {
20698
+ const message = err instanceof Error ? err.message : String(err);
20699
+ logger$1.error({
20700
+ err: message,
20701
+ key,
20702
+ value
20703
+ }, "Failed to apply config via openclaw");
20704
+ return {
20705
+ type: "COMMAND_ACK",
20706
+ commandId: command.commandId,
20707
+ status: "error",
20708
+ result: {
20709
+ code: "CONFIG_SET_FAILED",
20710
+ message
20711
+ }
20712
+ };
20713
+ }
20714
+ }
20648
20715
  if (commandRegistry.has(command.command)) try {
20649
20716
  const ctx = buildCommandContext();
20650
20717
  const result = await commandRegistry.execute(command.command, typeof command.payload === "object" && command.payload !== null ? command.payload : {}, ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/gateway",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
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.5",
26
- "@alfe.ai/config": "^0.0.5",
27
- "@alfe.ai/integration-manifest": "^0.0.8",
28
- "@alfe.ai/integrations": "^0.0.20"
25
+ "@alfe.ai/ai-proxy-local": "^0.0.6",
26
+ "@alfe.ai/config": "^0.0.6",
27
+ "@alfe.ai/integration-manifest": "^0.0.9",
28
+ "@alfe.ai/integrations": "^0.0.21"
29
29
  },
30
30
  "license": "UNLICENSED",
31
31
  "scripts": {