@alfe.ai/gateway 0.1.5 → 0.2.0
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.
- package/dist/health.js +166 -51
- package/dist/runtime-upgrade.js +64 -15
- package/package.json +6 -6
package/dist/health.js
CHANGED
|
@@ -12,7 +12,7 @@ import crypto from "crypto";
|
|
|
12
12
|
import { parse } from "smol-toml";
|
|
13
13
|
import WebSocket from "ws";
|
|
14
14
|
import { createConnection, createServer } from "node:net";
|
|
15
|
-
import { IntegrationManager, IntegrationManagerAdapter, McpApplier, OpenClawApplier } from "@alfe.ai/integrations";
|
|
15
|
+
import { HermesApplier, HermesMcpSync, IntegrationManager, IntegrationManagerAdapter, McpApplier, OpenClawApplier } from "@alfe.ai/integrations";
|
|
16
16
|
import { AgentApiClient } from "@alfe.ai/agent-api-client";
|
|
17
17
|
import { Manager, McpBundler, defaultConnect } from "@alfe.ai/mcp-bundler";
|
|
18
18
|
import stream, { Readable } from "stream";
|
|
@@ -4480,7 +4480,8 @@ enumValues({
|
|
|
4480
4480
|
});
|
|
4481
4481
|
enumValues({
|
|
4482
4482
|
OpenClaw: "openclaw",
|
|
4483
|
-
NanoClaw: "nanoclaw"
|
|
4483
|
+
NanoClaw: "nanoclaw",
|
|
4484
|
+
Hermes: "hermes"
|
|
4484
4485
|
});
|
|
4485
4486
|
enumValues({
|
|
4486
4487
|
Org: "org",
|
|
@@ -4965,17 +4966,33 @@ async function loadManagedConfig() {
|
|
|
4965
4966
|
agentId: identity.agentId,
|
|
4966
4967
|
orgId: identity.orgId,
|
|
4967
4968
|
runtime: identity.runtime,
|
|
4968
|
-
runtimes: identity.runtime
|
|
4969
|
-
const home = join(homedir(), ".openclaw");
|
|
4970
|
-
return { openclaw: {
|
|
4971
|
-
workspace: home,
|
|
4972
|
-
agentWorkspace: deriveAgentWorkspace("openclaw", home)
|
|
4973
|
-
} };
|
|
4974
|
-
})() : {},
|
|
4969
|
+
runtimes: buildManagedRuntimes(identity.runtime),
|
|
4975
4970
|
autoStartRuntime: true
|
|
4976
4971
|
};
|
|
4977
4972
|
}
|
|
4978
4973
|
/**
|
|
4974
|
+
* Build the managed-mode `runtimes` map for a single resolved runtime.
|
|
4975
|
+
* Returns an empty map for unknown runtimes (the daemon then skips runtime
|
|
4976
|
+
* start rather than crashing).
|
|
4977
|
+
*/
|
|
4978
|
+
function buildManagedRuntimes(runtime) {
|
|
4979
|
+
if (runtime === "openclaw") {
|
|
4980
|
+
const home = join(homedir(), ".openclaw");
|
|
4981
|
+
return { openclaw: {
|
|
4982
|
+
workspace: home,
|
|
4983
|
+
agentWorkspace: deriveAgentWorkspace("openclaw", home)
|
|
4984
|
+
} };
|
|
4985
|
+
}
|
|
4986
|
+
if (runtime === "hermes") {
|
|
4987
|
+
const home = join(homedir(), ".hermes");
|
|
4988
|
+
return { hermes: {
|
|
4989
|
+
workspace: home,
|
|
4990
|
+
agentWorkspace: deriveAgentWorkspace("hermes", home)
|
|
4991
|
+
} };
|
|
4992
|
+
}
|
|
4993
|
+
return {};
|
|
4994
|
+
}
|
|
4995
|
+
/**
|
|
4979
4996
|
* Load full daemon configuration.
|
|
4980
4997
|
* Reads config.toml, validates the API key, resolves agent identity,
|
|
4981
4998
|
* and parses runtime configurations.
|
|
@@ -4994,6 +5011,7 @@ async function loadDaemonConfig() {
|
|
|
4994
5011
|
const identity = await resolveAgentIdentity(alfeConfig.api_key, apiEndpoint);
|
|
4995
5012
|
const gatewayWsUrl = alfeConfig.gateway_url ?? deriveGatewayWsUrl(apiEndpoint);
|
|
4996
5013
|
const runtimes = await loadRuntimeConfigs();
|
|
5014
|
+
const runtime = alfeConfig.runtime ?? identity.runtime;
|
|
4997
5015
|
return {
|
|
4998
5016
|
apiKey: alfeConfig.api_key,
|
|
4999
5017
|
apiEndpoint,
|
|
@@ -5002,7 +5020,7 @@ async function loadDaemonConfig() {
|
|
|
5002
5020
|
pidPath: PID_PATH,
|
|
5003
5021
|
agentId: identity.agentId,
|
|
5004
5022
|
orgId: identity.orgId,
|
|
5005
|
-
runtime
|
|
5023
|
+
runtime,
|
|
5006
5024
|
runtimes,
|
|
5007
5025
|
autoStartRuntime: alfeConfig.auto_start_runtime ?? true
|
|
5008
5026
|
};
|
|
@@ -21617,6 +21635,10 @@ var RuntimeProcess = class {
|
|
|
21617
21635
|
"--allow-unconfigured"
|
|
21618
21636
|
]
|
|
21619
21637
|
};
|
|
21638
|
+
case "hermes": return {
|
|
21639
|
+
command: "hermes",
|
|
21640
|
+
args: ["gateway", "run"]
|
|
21641
|
+
};
|
|
21620
21642
|
default: throw new Error(`Unsupported runtime: ${this.options.runtime}`);
|
|
21621
21643
|
}
|
|
21622
21644
|
}
|
|
@@ -22195,6 +22217,12 @@ let startedAt;
|
|
|
22195
22217
|
let integrationManager;
|
|
22196
22218
|
let mcpBundler = null;
|
|
22197
22219
|
let mcpManagerRef = null;
|
|
22220
|
+
/**
|
|
22221
|
+
* Hermes-only MCP store consumer (Approach B). Mirrors the runtime-agnostic MCP
|
|
22222
|
+
* store into ~/.hermes/config.yaml. Null for openclaw agents (never constructed)
|
|
22223
|
+
* and for managed/self-hosted runtimes other than hermes.
|
|
22224
|
+
*/
|
|
22225
|
+
let hermesMcpSync = null;
|
|
22198
22226
|
let aiProxyServer = null;
|
|
22199
22227
|
let runtimeProcess = null;
|
|
22200
22228
|
let aiProxyUrl = null;
|
|
@@ -22207,6 +22235,12 @@ let resolvedRuntimeVersion;
|
|
|
22207
22235
|
let upgradingRuntime = false;
|
|
22208
22236
|
let stopPairingApprovalPoller = null;
|
|
22209
22237
|
/**
|
|
22238
|
+
* Module-level handle on the runtime appliers built during start(), so the
|
|
22239
|
+
* module-scoped command handler can route `alfe.config_set` to the active
|
|
22240
|
+
* runtime's applier (mirrors `mcpManagerRef`). Null until start() builds it.
|
|
22241
|
+
*/
|
|
22242
|
+
let runtimeAppliersRef = null;
|
|
22243
|
+
/**
|
|
22210
22244
|
* Resolve the installed @alfe.ai/cli version.
|
|
22211
22245
|
*
|
|
22212
22246
|
* Strategy (in order):
|
|
@@ -22281,15 +22315,44 @@ async function getCliVersion() {
|
|
|
22281
22315
|
logger$1.debug("Could not resolve @alfe.ai/cli version");
|
|
22282
22316
|
}
|
|
22283
22317
|
/**
|
|
22284
|
-
*
|
|
22285
|
-
*
|
|
22318
|
+
* Per-runtime "print installed version" commands. Local to the gateway — we do
|
|
22319
|
+
* NOT import the CLI's `detectRuntime` (`@alfe.ai/gateway` must not depend on
|
|
22320
|
+
* `@alfe.ai/cli`). Unknown runtimes resolve to `undefined` (never throw) so the
|
|
22321
|
+
* connection-status report degrades gracefully instead of crashing.
|
|
22322
|
+
*/
|
|
22323
|
+
const RUNTIME_VERSION_COMMANDS = {
|
|
22324
|
+
openclaw: {
|
|
22325
|
+
command: "openclaw",
|
|
22326
|
+
args: ["--version"]
|
|
22327
|
+
},
|
|
22328
|
+
hermes: {
|
|
22329
|
+
command: "hermes",
|
|
22330
|
+
args: ["version"]
|
|
22331
|
+
}
|
|
22332
|
+
};
|
|
22333
|
+
/**
|
|
22334
|
+
* Pure resolver (exported for tests) — the per-runtime version command, or
|
|
22335
|
+
* `undefined` for an unknown runtime.
|
|
22336
|
+
*/
|
|
22337
|
+
function resolveRuntimeVersionCommand(runtime) {
|
|
22338
|
+
return RUNTIME_VERSION_COMMANDS[runtime];
|
|
22339
|
+
}
|
|
22340
|
+
/**
|
|
22341
|
+
* Resolve the installed runtime version by running the per-runtime version
|
|
22342
|
+
* command and returning the trimmed stdout. An unknown runtime (no command in
|
|
22343
|
+
* the map) returns `undefined` without spawning — it must never throw.
|
|
22286
22344
|
*/
|
|
22287
|
-
async function getRuntimeVersion() {
|
|
22345
|
+
async function getRuntimeVersion(runtime) {
|
|
22346
|
+
const cmd = resolveRuntimeVersionCommand(runtime);
|
|
22347
|
+
if (!cmd) {
|
|
22348
|
+
logger$1.debug({ runtime }, "No version command for runtime — skipping version detection");
|
|
22349
|
+
return;
|
|
22350
|
+
}
|
|
22288
22351
|
try {
|
|
22289
|
-
const { stdout } = await execFileAsync(
|
|
22352
|
+
const { stdout } = await execFileAsync(cmd.command, cmd.args);
|
|
22290
22353
|
return stdout.trim() || void 0;
|
|
22291
22354
|
} catch {
|
|
22292
|
-
logger$1.debug("Could not resolve
|
|
22355
|
+
logger$1.debug({ runtime }, "Could not resolve runtime version");
|
|
22293
22356
|
return;
|
|
22294
22357
|
}
|
|
22295
22358
|
}
|
|
@@ -22437,7 +22500,7 @@ async function startDaemon() {
|
|
|
22437
22500
|
await flushAndExit(1);
|
|
22438
22501
|
}
|
|
22439
22502
|
resolvedCliVersion = await getCliVersion();
|
|
22440
|
-
resolvedRuntimeVersion = await getRuntimeVersion();
|
|
22503
|
+
resolvedRuntimeVersion = await getRuntimeVersion(config.runtime);
|
|
22441
22504
|
logger$1.info({
|
|
22442
22505
|
cliVersion: resolvedCliVersion,
|
|
22443
22506
|
runtimeVersion: resolvedRuntimeVersion
|
|
@@ -22470,7 +22533,14 @@ async function startDaemon() {
|
|
|
22470
22533
|
home: runtimeCfg.workspace,
|
|
22471
22534
|
agentWorkspace: runtimeCfg.agentWorkspace
|
|
22472
22535
|
}, "Registered OpenClaw runtime applier");
|
|
22536
|
+
} else if (name === "hermes") {
|
|
22537
|
+
runtimeAppliers.set(name, new HermesApplier({ home: runtimeCfg.workspace }));
|
|
22538
|
+
logger$1.info({
|
|
22539
|
+
runtime: name,
|
|
22540
|
+
home: runtimeCfg.workspace
|
|
22541
|
+
}, "Registered Hermes runtime applier");
|
|
22473
22542
|
} else logger$1.warn({ runtime: name }, "Unknown runtime type — skipping");
|
|
22543
|
+
runtimeAppliersRef = runtimeAppliers;
|
|
22474
22544
|
const integrationsService = new IntegrationsService(new AlfeApiClient({
|
|
22475
22545
|
apiBaseUrl: config.apiEndpoint,
|
|
22476
22546
|
getToken: () => Promise.resolve(config.apiKey)
|
|
@@ -22485,22 +22555,25 @@ async function startDaemon() {
|
|
|
22485
22555
|
logger: logger$1,
|
|
22486
22556
|
idleTtlMs: 0
|
|
22487
22557
|
}, { connect: defaultConnect });
|
|
22488
|
-
|
|
22489
|
-
|
|
22490
|
-
|
|
22491
|
-
|
|
22492
|
-
|
|
22493
|
-
|
|
22494
|
-
|
|
22495
|
-
|
|
22558
|
+
if (config.runtime === "hermes") logger$1.info("Hermes runtime — daemon MCP bundler left idle (store mirrored to config.yaml by HermesMcpSync)");
|
|
22559
|
+
else {
|
|
22560
|
+
await mcpManager.loadIntoBundler(mcpBundler);
|
|
22561
|
+
const warmBundler = (reason) => {
|
|
22562
|
+
if (!mcpBundler) return;
|
|
22563
|
+
mcpBundler.warmup().catch((err) => {
|
|
22564
|
+
logger$1.warn({
|
|
22565
|
+
err: err instanceof Error ? err.message : String(err),
|
|
22566
|
+
reason
|
|
22567
|
+
}, "MCP bundler warmup failed");
|
|
22568
|
+
});
|
|
22569
|
+
};
|
|
22570
|
+
warmBundler("startup");
|
|
22571
|
+
mcpManager.onChange(() => {
|
|
22572
|
+
warmBundler("store change");
|
|
22496
22573
|
});
|
|
22497
|
-
|
|
22498
|
-
|
|
22499
|
-
|
|
22500
|
-
warmBundler("store change");
|
|
22501
|
-
});
|
|
22502
|
-
logger$1.info("MCP bundler attached to manager — warming children");
|
|
22503
|
-
await runOpenclawMcpCleanup({
|
|
22574
|
+
logger$1.info("MCP bundler attached to manager — warming children");
|
|
22575
|
+
}
|
|
22576
|
+
if (config.runtime === "openclaw") await runOpenclawMcpCleanup({
|
|
22504
22577
|
manager: mcpManager,
|
|
22505
22578
|
logger: logger$1
|
|
22506
22579
|
}).catch((err) => {
|
|
@@ -22521,14 +22594,27 @@ async function startDaemon() {
|
|
|
22521
22594
|
});
|
|
22522
22595
|
const integrationAdapter = new IntegrationManagerAdapter(integrationManager);
|
|
22523
22596
|
cloudClient.setIntegrationManager(integrationAdapter);
|
|
22524
|
-
|
|
22597
|
+
const requestRuntimeRestart = () => {
|
|
22525
22598
|
if (runtimeProcess) {
|
|
22526
22599
|
logger$1.info("Runtime state changed — restarting runtime");
|
|
22527
22600
|
runtimeProcess.restart().catch((err) => {
|
|
22528
22601
|
logger$1.error({ err: err instanceof Error ? err.message : String(err) }, "Failed to restart runtime");
|
|
22529
22602
|
});
|
|
22530
22603
|
}
|
|
22531
|
-
}
|
|
22604
|
+
};
|
|
22605
|
+
cloudClient.setRuntimeRestartNeededHandler(requestRuntimeRestart);
|
|
22606
|
+
if (config.runtime === "hermes") {
|
|
22607
|
+
const hermesCfg = config.runtimes[config.runtime];
|
|
22608
|
+
if (hermesCfg) {
|
|
22609
|
+
hermesMcpSync = new HermesMcpSync({
|
|
22610
|
+
manager: mcpManager,
|
|
22611
|
+
home: hermesCfg.workspace,
|
|
22612
|
+
apiKey: config.apiKey,
|
|
22613
|
+
requestRestart: requestRuntimeRestart
|
|
22614
|
+
});
|
|
22615
|
+
hermesMcpSync.start();
|
|
22616
|
+
}
|
|
22617
|
+
}
|
|
22532
22618
|
cloudClient.setOnReconciliationComplete(() => {
|
|
22533
22619
|
try {
|
|
22534
22620
|
const activeCommands = integrationManager.getActiveCommands();
|
|
@@ -22583,6 +22669,10 @@ async function startDaemon() {
|
|
|
22583
22669
|
await runtimeProcess.stop();
|
|
22584
22670
|
logger$1.debug("Runtime process stopped");
|
|
22585
22671
|
}
|
|
22672
|
+
if (hermesMcpSync) {
|
|
22673
|
+
hermesMcpSync.stop();
|
|
22674
|
+
hermesMcpSync = null;
|
|
22675
|
+
}
|
|
22586
22676
|
if (mcpBundler) {
|
|
22587
22677
|
logger$1.debug("Stopping MCP bundler...");
|
|
22588
22678
|
await mcpBundler.dispose();
|
|
@@ -22671,17 +22761,28 @@ async function handleCloudCommand(command) {
|
|
|
22671
22761
|
message: "Runtime upgrade already in progress"
|
|
22672
22762
|
}
|
|
22673
22763
|
};
|
|
22674
|
-
const
|
|
22764
|
+
const payload = command.payload;
|
|
22765
|
+
const runtime = config.runtime;
|
|
22766
|
+
const version = payload?.version ?? (runtime === "openclaw" ? "2026.6.8" : void 0);
|
|
22675
22767
|
upgradingRuntime = true;
|
|
22676
22768
|
setTimeout(() => {
|
|
22677
22769
|
(async () => {
|
|
22678
22770
|
try {
|
|
22679
22771
|
const { upgradeRuntime } = await import("./runtime-upgrade.js");
|
|
22680
|
-
if ((await upgradeRuntime(version, runtimeProcess)).success) {
|
|
22681
|
-
resolvedRuntimeVersion = await getRuntimeVersion();
|
|
22682
|
-
|
|
22683
|
-
logger$1.
|
|
22684
|
-
|
|
22772
|
+
if ((await upgradeRuntime(runtime, version, runtimeProcess)).success) {
|
|
22773
|
+
resolvedRuntimeVersion = await getRuntimeVersion(runtime);
|
|
22774
|
+
const reportedVersion = resolvedRuntimeVersion ?? version;
|
|
22775
|
+
if (!resolvedRuntimeVersion) logger$1.warn({
|
|
22776
|
+
runtime,
|
|
22777
|
+
requestedVersion: version
|
|
22778
|
+
}, "Could not detect runtime version after upgrade");
|
|
22779
|
+
if (reportedVersion) {
|
|
22780
|
+
logger$1.info({
|
|
22781
|
+
runtime,
|
|
22782
|
+
runtimeVersion: reportedVersion
|
|
22783
|
+
}, "Runtime version updated after upgrade");
|
|
22784
|
+
cloudClient.updateRuntimeVersionAndReRegister(reportedVersion);
|
|
22785
|
+
} else logger$1.warn({ runtime }, "No runtime version to report after upgrade — skipping re-register");
|
|
22685
22786
|
}
|
|
22686
22787
|
} catch (err) {
|
|
22687
22788
|
logger$1.error({ err: err instanceof Error ? err.message : String(err) }, "Runtime upgrade failed");
|
|
@@ -22696,6 +22797,7 @@ async function handleCloudCommand(command) {
|
|
|
22696
22797
|
status: "ok",
|
|
22697
22798
|
result: {
|
|
22698
22799
|
upgrading: true,
|
|
22800
|
+
runtime,
|
|
22699
22801
|
version
|
|
22700
22802
|
}
|
|
22701
22803
|
};
|
|
@@ -22776,17 +22878,30 @@ async function handleCloudCommand(command) {
|
|
|
22776
22878
|
message: "alfe.config_set requires key and value"
|
|
22777
22879
|
}
|
|
22778
22880
|
};
|
|
22881
|
+
const runtime = config.runtime;
|
|
22882
|
+
const applier = runtimeAppliersRef?.get(runtime);
|
|
22883
|
+
if (!applier || typeof applier.setConfigRaw !== "function") {
|
|
22884
|
+
const message = `No runtime applier supports config_set for runtime "${runtime}"`;
|
|
22885
|
+
logger$1.warn({
|
|
22886
|
+
runtime,
|
|
22887
|
+
key
|
|
22888
|
+
}, message);
|
|
22889
|
+
return {
|
|
22890
|
+
type: "COMMAND_ACK",
|
|
22891
|
+
commandId: command.commandId,
|
|
22892
|
+
status: "error",
|
|
22893
|
+
result: {
|
|
22894
|
+
code: "CONFIG_SET_UNSUPPORTED",
|
|
22895
|
+
message
|
|
22896
|
+
}
|
|
22897
|
+
};
|
|
22898
|
+
}
|
|
22779
22899
|
try {
|
|
22780
|
-
await
|
|
22781
|
-
"config",
|
|
22782
|
-
"set",
|
|
22783
|
-
key,
|
|
22784
|
-
value
|
|
22785
|
-
], { timeout: 1e4 });
|
|
22900
|
+
await applier.setConfigRaw(key, value);
|
|
22786
22901
|
logger$1.info({
|
|
22787
|
-
|
|
22788
|
-
|
|
22789
|
-
}, "Applied config via
|
|
22902
|
+
runtime,
|
|
22903
|
+
key
|
|
22904
|
+
}, "Applied config via runtime applier setConfigRaw");
|
|
22790
22905
|
return {
|
|
22791
22906
|
type: "COMMAND_ACK",
|
|
22792
22907
|
commandId: command.commandId,
|
|
@@ -22800,9 +22915,9 @@ async function handleCloudCommand(command) {
|
|
|
22800
22915
|
const message = err instanceof Error ? err.message : String(err);
|
|
22801
22916
|
logger$1.error({
|
|
22802
22917
|
err: message,
|
|
22803
|
-
|
|
22804
|
-
|
|
22805
|
-
}, "Failed to apply config via
|
|
22918
|
+
runtime,
|
|
22919
|
+
key
|
|
22920
|
+
}, "Failed to apply config via runtime applier");
|
|
22806
22921
|
return {
|
|
22807
22922
|
type: "COMMAND_ACK",
|
|
22808
22923
|
commandId: command.commandId,
|
package/dist/runtime-upgrade.js
CHANGED
|
@@ -3,40 +3,87 @@ import { execFile } from "node:child_process";
|
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
//#region src/runtime-upgrade.ts
|
|
5
5
|
/**
|
|
6
|
-
* Runtime upgrade —
|
|
6
|
+
* Runtime upgrade — install/update the runtime binary then cycle the RuntimeProcess.
|
|
7
7
|
*
|
|
8
8
|
* Unlike CLI upgrade (which exits the daemon for systemd restart),
|
|
9
9
|
* runtime upgrade keeps the daemon running and just restarts the child process.
|
|
10
10
|
*
|
|
11
|
-
* Flow:
|
|
11
|
+
* Flow (generic across runtimes):
|
|
12
12
|
* 1. Stop the RuntimeProcess child (SIGTERM + grace period)
|
|
13
|
-
* 2.
|
|
13
|
+
* 2. Run the per-runtime upgrade command (see `resolveUpgradeCommand`)
|
|
14
14
|
* 3. Restart the RuntimeProcess child
|
|
15
15
|
*
|
|
16
|
-
* On
|
|
16
|
+
* On install failure, the runtime is restarted on the old version.
|
|
17
17
|
*/
|
|
18
18
|
const execFileAsync = promisify(execFile);
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the per-runtime upgrade command.
|
|
21
|
+
*
|
|
22
|
+
* - `openclaw`: `npm install -g openclaw@<version>` — version-pinned (unchanged).
|
|
23
|
+
* - `hermes`: `hermes update --yes` — Hermes self-updates from its own channel.
|
|
24
|
+
* A pinned version does not map to a Hermes CLI flag, so the
|
|
25
|
+
* `version` arg is intentionally ignored on this branch.
|
|
26
|
+
*
|
|
27
|
+
* Returns `undefined` for an unknown runtime (or openclaw with no version),
|
|
28
|
+
* which the caller treats as a failed upgrade (restart on the old version).
|
|
29
|
+
*/
|
|
30
|
+
function resolveUpgradeCommand(runtime, version) {
|
|
31
|
+
switch (runtime) {
|
|
32
|
+
case "openclaw":
|
|
33
|
+
if (!version) return void 0;
|
|
34
|
+
return {
|
|
35
|
+
command: "npm",
|
|
36
|
+
args: [
|
|
37
|
+
"install",
|
|
38
|
+
"-g",
|
|
39
|
+
`openclaw@${version}`
|
|
40
|
+
]
|
|
41
|
+
};
|
|
42
|
+
case "hermes": return {
|
|
43
|
+
command: "hermes",
|
|
44
|
+
args: ["update", "--yes"]
|
|
45
|
+
};
|
|
46
|
+
default: return;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function upgradeRuntime(runtime, version, runtimeProcess) {
|
|
50
|
+
const cmd = resolveUpgradeCommand(runtime, version);
|
|
51
|
+
if (!cmd) {
|
|
52
|
+
const message = `No upgrade command for runtime '${runtime}'`;
|
|
53
|
+
logger.error({
|
|
54
|
+
runtime,
|
|
55
|
+
version
|
|
56
|
+
}, message);
|
|
57
|
+
return {
|
|
58
|
+
success: false,
|
|
59
|
+
runtime,
|
|
60
|
+
version,
|
|
61
|
+
error: message
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
logger.info({
|
|
65
|
+
runtime,
|
|
66
|
+
version
|
|
67
|
+
}, "Upgrading runtime...");
|
|
21
68
|
if (runtimeProcess) {
|
|
22
69
|
logger.info("Stopping runtime for upgrade...");
|
|
23
70
|
await runtimeProcess.stop();
|
|
24
71
|
}
|
|
25
72
|
try {
|
|
26
|
-
const { stdout, stderr } = await execFileAsync(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
logger.info({ version }, "OpenClaw runtime upgraded successfully");
|
|
73
|
+
const { stdout, stderr } = await execFileAsync(cmd.command, cmd.args, { timeout: 12e4 });
|
|
74
|
+
if (stdout) logger.debug({ stdout: stdout.trim() }, "runtime upgrade stdout");
|
|
75
|
+
if (stderr) logger.debug({ stderr: stderr.trim() }, "runtime upgrade stderr");
|
|
76
|
+
logger.info({
|
|
77
|
+
runtime,
|
|
78
|
+
version
|
|
79
|
+
}, "Runtime upgraded successfully");
|
|
34
80
|
} catch (err) {
|
|
35
81
|
const message = err instanceof Error ? err.message : String(err);
|
|
36
82
|
logger.error({
|
|
37
83
|
err: message,
|
|
84
|
+
runtime,
|
|
38
85
|
version
|
|
39
|
-
}, "Runtime upgrade
|
|
86
|
+
}, "Runtime upgrade install command failed");
|
|
40
87
|
if (runtimeProcess) try {
|
|
41
88
|
logger.info("Restarting runtime on previous version after failed upgrade...");
|
|
42
89
|
await runtimeProcess.restart();
|
|
@@ -46,6 +93,7 @@ async function upgradeRuntime(version, runtimeProcess) {
|
|
|
46
93
|
}
|
|
47
94
|
return {
|
|
48
95
|
success: false,
|
|
96
|
+
runtime,
|
|
49
97
|
version,
|
|
50
98
|
error: message
|
|
51
99
|
};
|
|
@@ -56,6 +104,7 @@ async function upgradeRuntime(version, runtimeProcess) {
|
|
|
56
104
|
}
|
|
57
105
|
return {
|
|
58
106
|
success: true,
|
|
107
|
+
runtime,
|
|
59
108
|
version
|
|
60
109
|
};
|
|
61
110
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/gateway",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Alfe local gateway daemon — persistent control plane for agent integrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"pino-roll": "^1.2.0",
|
|
23
23
|
"smol-toml": ">=1.6.1",
|
|
24
24
|
"ws": "^8.18.0",
|
|
25
|
-
"@alfe.ai/agent-api-client": "^0.
|
|
26
|
-
"@alfe.ai/ai-proxy-local": "^0.0.
|
|
27
|
-
"@alfe.ai/config": "^0.0
|
|
28
|
-
"@alfe.ai/integration-manifest": "^0.
|
|
29
|
-
"@alfe.ai/integrations": "^0.
|
|
25
|
+
"@alfe.ai/agent-api-client": "^0.3.0",
|
|
26
|
+
"@alfe.ai/ai-proxy-local": "^0.0.11",
|
|
27
|
+
"@alfe.ai/config": "^0.1.0",
|
|
28
|
+
"@alfe.ai/integration-manifest": "^0.3.0",
|
|
29
|
+
"@alfe.ai/integrations": "^0.2.0",
|
|
30
30
|
"@alfe.ai/mcp-bundler": "^0.2.1"
|
|
31
31
|
},
|
|
32
32
|
"license": "UNLICENSED",
|