@alfe.ai/gateway 0.2.1 → 0.2.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.
- package/dist/health.js +166 -20
- package/package.json +2 -2
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 { HermesApplier, HermesMcpSync, IntegrationManager, IntegrationManagerAdapter, McpApplier, OpenClawApplier } from "@alfe.ai/integrations";
|
|
15
|
+
import { HermesApplier, HermesMcpSync, IntegrationManager, IntegrationManagerAdapter, McpApplier, NoopOpenClawCliLock, OpenClawApplier, SerialOpenClawCliLock } 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";
|
|
@@ -5257,6 +5257,79 @@ function isIPCResponse(msg) {
|
|
|
5257
5257
|
/** Current IPC protocol version */
|
|
5258
5258
|
const PROTOCOL_VERSION = 1;
|
|
5259
5259
|
//#endregion
|
|
5260
|
+
//#region src/runtime-gate.ts
|
|
5261
|
+
const log$3 = logger$1.child({ component: "RuntimeGate" });
|
|
5262
|
+
var RuntimeGate = class {
|
|
5263
|
+
depth = 0;
|
|
5264
|
+
wasRunning = false;
|
|
5265
|
+
constructor(getRuntime) {
|
|
5266
|
+
this.getRuntime = getRuntime;
|
|
5267
|
+
}
|
|
5268
|
+
/**
|
|
5269
|
+
* Suspend the runtime child. Only the outermost call (depth 0 → 1) actually
|
|
5270
|
+
* stops it; nested calls just bump the refcount. Remembers whether the child
|
|
5271
|
+
* was running so `resume()` doesn't spuriously start a runtime that was never
|
|
5272
|
+
* up (e.g. autoStartRuntime=false).
|
|
5273
|
+
*/
|
|
5274
|
+
async suspend() {
|
|
5275
|
+
if (this.depth++ > 0) return;
|
|
5276
|
+
const rp = this.getRuntime();
|
|
5277
|
+
this.wasRunning = rp?.isRunning ?? false;
|
|
5278
|
+
if (rp && this.wasRunning) {
|
|
5279
|
+
log$3.info("Suspending runtime for mutating reconcile (avoid concurrent SQLite writers)");
|
|
5280
|
+
await rp.stop();
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
/**
|
|
5284
|
+
* Resume the runtime child. Only the outermost call (depth 1 → 0) actually
|
|
5285
|
+
* restarts it, and only if it was running when we suspended. This subsumes
|
|
5286
|
+
* the old post-reconcile "restart if plugins changed" step — bringing the
|
|
5287
|
+
* runtime back is exactly what a restart-after-reconcile did.
|
|
5288
|
+
*/
|
|
5289
|
+
resume() {
|
|
5290
|
+
if (--this.depth > 0) return Promise.resolve();
|
|
5291
|
+
if (this.depth < 0) this.depth = 0;
|
|
5292
|
+
const rp = this.getRuntime();
|
|
5293
|
+
if (rp && this.wasRunning) {
|
|
5294
|
+
log$3.info("Resuming runtime after mutating reconcile");
|
|
5295
|
+
rp.resume();
|
|
5296
|
+
}
|
|
5297
|
+
this.wasRunning = false;
|
|
5298
|
+
return Promise.resolve();
|
|
5299
|
+
}
|
|
5300
|
+
/**
|
|
5301
|
+
* Out-of-band restart request (e.g. `alfe.config_set`, Hermes MCP sync).
|
|
5302
|
+
* Deferred while a suspend is active — the pending `resume()` will bring the
|
|
5303
|
+
* runtime back with fresh config, so restarting mid-suspend would just fight
|
|
5304
|
+
* the gate (and risk spawning the runtime while a CLI mutation is still
|
|
5305
|
+
* writing the DB).
|
|
5306
|
+
*/
|
|
5307
|
+
requestRestart() {
|
|
5308
|
+
if (this.depth > 0) {
|
|
5309
|
+
log$3.info("Runtime restart requested while suspended — deferring to pending resume");
|
|
5310
|
+
return;
|
|
5311
|
+
}
|
|
5312
|
+
const rp = this.getRuntime();
|
|
5313
|
+
if (rp) rp.restart().catch((err) => {
|
|
5314
|
+
log$3.error({ err: err instanceof Error ? err.message : String(err) }, "Failed to restart runtime");
|
|
5315
|
+
});
|
|
5316
|
+
}
|
|
5317
|
+
};
|
|
5318
|
+
/**
|
|
5319
|
+
* A gate that never touches the runtime — for runtimes that don't share the
|
|
5320
|
+
* single-writer SQLite hazard, or for tests. `suspend`/`resume` are no-ops and
|
|
5321
|
+
* `requestRestart` does nothing.
|
|
5322
|
+
*/
|
|
5323
|
+
var NoopRuntimeGate = class {
|
|
5324
|
+
suspend() {
|
|
5325
|
+
return Promise.resolve();
|
|
5326
|
+
}
|
|
5327
|
+
resume() {
|
|
5328
|
+
return Promise.resolve();
|
|
5329
|
+
}
|
|
5330
|
+
requestRestart() {}
|
|
5331
|
+
};
|
|
5332
|
+
//#endregion
|
|
5260
5333
|
//#region src/reconciliation.ts
|
|
5261
5334
|
const log$2 = logger$1.child({ component: "Reconciliation" });
|
|
5262
5335
|
/**
|
|
@@ -5271,13 +5344,50 @@ const MAX_ERROR_ACTIVATE_ATTEMPTS = 3;
|
|
|
5271
5344
|
var ReconciliationEngine = class {
|
|
5272
5345
|
/** Consecutive re-activation attempts for an intact error-state integration, keyed by id. */
|
|
5273
5346
|
activateAttempts = /* @__PURE__ */ new Map();
|
|
5274
|
-
|
|
5347
|
+
/**
|
|
5348
|
+
* Whether this reconcile pass has already suspended the runtime. Reset at the
|
|
5349
|
+
* start of every {@link reconcile} call. The runtime is suspended lazily on
|
|
5350
|
+
* the first mutating branch (install / reinstall / activate / removal-of-
|
|
5351
|
+
* existing) so an all-`up_to_date` pass never touches the runtime.
|
|
5352
|
+
*/
|
|
5353
|
+
suspended = false;
|
|
5354
|
+
/**
|
|
5355
|
+
* @param manager The integration manager to converge.
|
|
5356
|
+
* @param gate Runtime gate used to suspend the runtime child around
|
|
5357
|
+
* mutating branches so `openclaw` CLI subprocesses don't write
|
|
5358
|
+
* `~/.openclaw/state/openclaw.sqlite` concurrently with a live
|
|
5359
|
+
* `openclaw gateway run` (see runtime-gate.ts). Defaults to a
|
|
5360
|
+
* no-op gate for runtimes/tests that don't need protection.
|
|
5361
|
+
*/
|
|
5362
|
+
constructor(manager, gate = new NoopRuntimeGate()) {
|
|
5275
5363
|
this.manager = manager;
|
|
5364
|
+
this.gate = gate;
|
|
5365
|
+
}
|
|
5366
|
+
/**
|
|
5367
|
+
* Suspend the runtime on the first mutating branch of a reconcile pass.
|
|
5368
|
+
* Idempotent within a pass — subsequent mutating branches are covered by the
|
|
5369
|
+
* single suspend held until the `finally` in {@link reconcile}.
|
|
5370
|
+
*/
|
|
5371
|
+
async ensureSuspended() {
|
|
5372
|
+
if (!this.suspended) {
|
|
5373
|
+
this.suspended = true;
|
|
5374
|
+
await this.gate.suspend();
|
|
5375
|
+
}
|
|
5376
|
+
}
|
|
5377
|
+
/**
|
|
5378
|
+
* Resume the runtime if this pass suspended it. Called from `reconcile()`'s
|
|
5379
|
+
* `finally`. Kept as a method (rather than an inline `if (this.suspended)`)
|
|
5380
|
+
* so the mutation performed by {@link ensureSuspended} in a different method
|
|
5381
|
+
* isn't narrowed away by control-flow analysis at the callsite.
|
|
5382
|
+
*/
|
|
5383
|
+
async resumeIfSuspended() {
|
|
5384
|
+
if (this.suspended) await this.gate.resume();
|
|
5276
5385
|
}
|
|
5277
5386
|
/**
|
|
5278
5387
|
* Reconcile local state against desired state from cloud.
|
|
5279
5388
|
*/
|
|
5280
5389
|
async reconcile(desiredIntegrations) {
|
|
5390
|
+
this.suspended = false;
|
|
5281
5391
|
const report = {
|
|
5282
5392
|
results: [],
|
|
5283
5393
|
installed: [],
|
|
@@ -5296,15 +5406,20 @@ var ReconciliationEngine = class {
|
|
|
5296
5406
|
}
|
|
5297
5407
|
const localMap = new Map(localIntegrations.map((i) => [i.id, i]));
|
|
5298
5408
|
const desiredMap = new Map(desiredIntegrations.map((d) => [d.integrationId, d]));
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5409
|
+
try {
|
|
5410
|
+
for (const desired of desiredIntegrations) if (desired.desiredStatus === "active") await this.reconcileActive(desired, localMap.get(desired.integrationId), report);
|
|
5411
|
+
else await this.reconcileRemoved(desired.integrationId, localMap.get(desired.integrationId), report);
|
|
5412
|
+
for (const local of localIntegrations) if (!desiredMap.has(local.id)) await this.reconcileRemoved(local.id, local, report);
|
|
5413
|
+
} finally {
|
|
5414
|
+
await this.resumeIfSuspended();
|
|
5415
|
+
}
|
|
5302
5416
|
return report;
|
|
5303
5417
|
}
|
|
5304
5418
|
async reconcileActive(desired, local, report) {
|
|
5305
5419
|
const id = desired.integrationId;
|
|
5306
5420
|
try {
|
|
5307
5421
|
if (!local) {
|
|
5422
|
+
await this.ensureSuspended();
|
|
5308
5423
|
log$2.info(`Installing ${id}@${desired.version}`);
|
|
5309
5424
|
await this.manager.install(id, desired.version, desired.config, desired.customSource);
|
|
5310
5425
|
report.installed.push(id);
|
|
@@ -5319,6 +5434,7 @@ var ReconciliationEngine = class {
|
|
|
5319
5434
|
return;
|
|
5320
5435
|
}
|
|
5321
5436
|
if (local.version !== desired.version && desired.version !== "" && local.version !== "unknown") {
|
|
5437
|
+
await this.ensureSuspended();
|
|
5322
5438
|
log$2.info(`Upgrading ${id}: ${local.version} → ${desired.version}`);
|
|
5323
5439
|
if ((await this.manager.reinstall(id, desired.version, desired.config, desired.customSource)).configApplied) report.configApplied = true;
|
|
5324
5440
|
report.installed.push(id);
|
|
@@ -5332,6 +5448,7 @@ var ReconciliationEngine = class {
|
|
|
5332
5448
|
}
|
|
5333
5449
|
if (local.status === "error") {
|
|
5334
5450
|
if (desired.reinstallRequestedAt && local.installedAt && desired.reinstallRequestedAt > local.installedAt) {
|
|
5451
|
+
await this.ensureSuspended();
|
|
5335
5452
|
log$2.info(`Reinstalling ${id} from error state (requested: ${desired.reinstallRequestedAt}, installed: ${local.installedAt})`);
|
|
5336
5453
|
this.manager.resetReinstallAttempts(id);
|
|
5337
5454
|
this.activateAttempts.delete(id);
|
|
@@ -5361,6 +5478,7 @@ var ReconciliationEngine = class {
|
|
|
5361
5478
|
});
|
|
5362
5479
|
return;
|
|
5363
5480
|
}
|
|
5481
|
+
await this.ensureSuspended();
|
|
5364
5482
|
log$2.info(`Auto-reinstalling ${id} — install directory is corrupted or missing (attempt ${String(attempts + 1)}/3)`);
|
|
5365
5483
|
this.manager.incrementReinstallAttempts(id);
|
|
5366
5484
|
try {
|
|
@@ -5393,6 +5511,7 @@ var ReconciliationEngine = class {
|
|
|
5393
5511
|
const activateAttempts = this.activateAttempts.get(id) ?? 0;
|
|
5394
5512
|
if (activateAttempts < MAX_ERROR_ACTIVATE_ATTEMPTS) {
|
|
5395
5513
|
this.activateAttempts.set(id, activateAttempts + 1);
|
|
5514
|
+
await this.ensureSuspended();
|
|
5396
5515
|
log$2.info(`Re-activating ${id} from error state (attempt ${String(activateAttempts + 1)}/${String(MAX_ERROR_ACTIVATE_ATTEMPTS)})`);
|
|
5397
5516
|
try {
|
|
5398
5517
|
if ((await this.manager.activate(id)).configApplied) report.configApplied = true;
|
|
@@ -5434,6 +5553,7 @@ var ReconciliationEngine = class {
|
|
|
5434
5553
|
return;
|
|
5435
5554
|
}
|
|
5436
5555
|
if (local.status !== "active") {
|
|
5556
|
+
await this.ensureSuspended();
|
|
5437
5557
|
log$2.info(`Activating ${id}`);
|
|
5438
5558
|
if ((await this.manager.activate(id)).configApplied) report.configApplied = true;
|
|
5439
5559
|
report.activated.push(id);
|
|
@@ -5445,6 +5565,7 @@ var ReconciliationEngine = class {
|
|
|
5445
5565
|
return;
|
|
5446
5566
|
}
|
|
5447
5567
|
if (desired.reinstallRequestedAt && local.installedAt && desired.reinstallRequestedAt > local.installedAt) {
|
|
5568
|
+
await this.ensureSuspended();
|
|
5448
5569
|
log$2.info(`Reinstall requested for ${id} (requested: ${desired.reinstallRequestedAt}, installed: ${local.installedAt})`);
|
|
5449
5570
|
this.manager.resetReinstallAttempts(id);
|
|
5450
5571
|
this.activateAttempts.delete(id);
|
|
@@ -5489,6 +5610,7 @@ var ReconciliationEngine = class {
|
|
|
5489
5610
|
return;
|
|
5490
5611
|
}
|
|
5491
5612
|
try {
|
|
5613
|
+
await this.ensureSuspended();
|
|
5492
5614
|
log$2.info(`Removing ${id}`);
|
|
5493
5615
|
if (local.status === "active") {
|
|
5494
5616
|
await this.manager.deactivate(id);
|
|
@@ -5576,8 +5698,16 @@ var CloudClient = class {
|
|
|
5576
5698
|
setOnReconciliationComplete(handler) {
|
|
5577
5699
|
this.onReconciliationComplete = handler;
|
|
5578
5700
|
}
|
|
5579
|
-
|
|
5580
|
-
|
|
5701
|
+
/**
|
|
5702
|
+
* Set the integration manager (and optionally the runtime gate) for
|
|
5703
|
+
* reconciliation. When set, the cloud client handles DESIRED_STATE messages
|
|
5704
|
+
* automatically. The gate is passed to the ReconciliationEngine so mutating
|
|
5705
|
+
* reconcile branches suspend the runtime child around runtime-CLI mutations
|
|
5706
|
+
* (avoids concurrent SQLite writers — see runtime-gate.ts). Resuming the
|
|
5707
|
+
* runtime after a mutating pass subsumes the old post-reconcile restart.
|
|
5708
|
+
*/
|
|
5709
|
+
setIntegrationManager(manager, gate) {
|
|
5710
|
+
this.reconciliationEngine = new ReconciliationEngine(manager, gate);
|
|
5581
5711
|
}
|
|
5582
5712
|
/**
|
|
5583
5713
|
* Start the cloud connection with auto-reconnect.
|
|
@@ -5813,7 +5943,6 @@ var CloudClient = class {
|
|
|
5813
5943
|
}, "Cloud: reconciliation complete");
|
|
5814
5944
|
const reportMsg = createReconciliationReport(report.results);
|
|
5815
5945
|
this.send(reportMsg);
|
|
5816
|
-
if ((report.installed.length > 0 || report.uninstalled.length > 0 || report.configApplied) && this.onRuntimeRestartNeeded) this.onRuntimeRestartNeeded();
|
|
5817
5946
|
this.onReconciliationComplete?.();
|
|
5818
5947
|
}
|
|
5819
5948
|
send(msg) {
|
|
@@ -21772,6 +21901,17 @@ var RuntimeProcess = class {
|
|
|
21772
21901
|
});
|
|
21773
21902
|
}
|
|
21774
21903
|
/**
|
|
21904
|
+
* Resume after a suspend (stop). `start()` alone is a no-op while stopped
|
|
21905
|
+
* because `stop()` latches `this.stopped = true`; resume clears that latch,
|
|
21906
|
+
* resets the crash backoff, and re-spawns. Used by the RuntimeGate to bring
|
|
21907
|
+
* the runtime back after a mutating reconcile branch has finished.
|
|
21908
|
+
*/
|
|
21909
|
+
resume() {
|
|
21910
|
+
this.stopped = false;
|
|
21911
|
+
this.backoffMs = BACKOFF_INITIAL_MS;
|
|
21912
|
+
this.start();
|
|
21913
|
+
}
|
|
21914
|
+
/**
|
|
21775
21915
|
* Restart the runtime process (stop then start with fresh backoff).
|
|
21776
21916
|
*/
|
|
21777
21917
|
async restart() {
|
|
@@ -22054,13 +22194,15 @@ async function approvePendingScopeUpgrades(opts) {
|
|
|
22054
22194
|
function startPairingApprovalPoller(opts) {
|
|
22055
22195
|
const stateDir = resolveStateDir(opts.stateDir);
|
|
22056
22196
|
const intervalMs = opts.intervalMs ?? 3e4;
|
|
22057
|
-
const
|
|
22197
|
+
const cliLock = opts.cliLock ?? new NoopOpenClawCliLock();
|
|
22198
|
+
const rawExec = opts.exec ?? (async (file, args, { timeout }) => {
|
|
22058
22199
|
const { stdout, stderr } = await execFileAsync$2(file, args, { timeout });
|
|
22059
22200
|
return {
|
|
22060
22201
|
stdout,
|
|
22061
22202
|
stderr
|
|
22062
22203
|
};
|
|
22063
22204
|
});
|
|
22205
|
+
const exec = (file, args, execOpts) => cliLock.run(() => rawExec(file, args, execOpts));
|
|
22064
22206
|
const pendingPath = join(stateDir, "devices", "pending.json");
|
|
22065
22207
|
let lastSeenMtime = null;
|
|
22066
22208
|
let stopped = false;
|
|
@@ -22165,6 +22307,7 @@ const defaultOpenclaw = {
|
|
|
22165
22307
|
async function runOpenclawMcpCleanup(opts) {
|
|
22166
22308
|
const sentinelPath = opts.sentinelPath ?? DEFAULT_SENTINEL_PATH;
|
|
22167
22309
|
const openclaw = opts.openclaw ?? defaultOpenclaw;
|
|
22310
|
+
const cliLock = opts.cliLock ?? new NoopOpenClawCliLock();
|
|
22168
22311
|
if (existsSync(sentinelPath)) {
|
|
22169
22312
|
opts.logger.debug({ sentinel: sentinelPath }, "openclaw.json mcp.servers cleanup already ran — skipping");
|
|
22170
22313
|
return;
|
|
@@ -22195,7 +22338,7 @@ async function runOpenclawMcpCleanup(opts) {
|
|
|
22195
22338
|
return;
|
|
22196
22339
|
}
|
|
22197
22340
|
for (const key of toUnset) try {
|
|
22198
|
-
await openclaw.unsetServer(key);
|
|
22341
|
+
await cliLock.run(() => openclaw.unsetServer(key));
|
|
22199
22342
|
opts.logger.info({ key }, "Cleaned up stale openclaw.json#mcp.servers entry");
|
|
22200
22343
|
} catch (err) {
|
|
22201
22344
|
opts.logger.warn({
|
|
@@ -22548,11 +22691,13 @@ async function startDaemon() {
|
|
|
22548
22691
|
logger$1.info({ connected }, "Cloud connection state changed");
|
|
22549
22692
|
ipcServer?.broadcastEvent("cloud.status", { connected });
|
|
22550
22693
|
});
|
|
22694
|
+
const openclawCliLock = new SerialOpenClawCliLock();
|
|
22551
22695
|
const runtimeAppliers = /* @__PURE__ */ new Map();
|
|
22552
22696
|
for (const [name, runtimeCfg] of Object.entries(config.runtimes)) if (name === "openclaw") {
|
|
22553
22697
|
runtimeAppliers.set(name, new OpenClawApplier({
|
|
22554
22698
|
home: runtimeCfg.workspace,
|
|
22555
|
-
agentWorkspace: runtimeCfg.agentWorkspace
|
|
22699
|
+
agentWorkspace: runtimeCfg.agentWorkspace,
|
|
22700
|
+
cliLock: openclawCliLock
|
|
22556
22701
|
}));
|
|
22557
22702
|
logger$1.info({
|
|
22558
22703
|
runtime: name,
|
|
@@ -22601,7 +22746,8 @@ async function startDaemon() {
|
|
|
22601
22746
|
}
|
|
22602
22747
|
if (config.runtime === "openclaw") await runOpenclawMcpCleanup({
|
|
22603
22748
|
manager: mcpManager,
|
|
22604
|
-
logger: logger$1
|
|
22749
|
+
logger: logger$1,
|
|
22750
|
+
cliLock: openclawCliLock
|
|
22605
22751
|
}).catch((err) => {
|
|
22606
22752
|
logger$1.warn({ err: err instanceof Error ? err.message : String(err) }, "openclaw.json mcp.servers cleanup threw — startup continues");
|
|
22607
22753
|
});
|
|
@@ -22619,14 +22765,11 @@ async function startDaemon() {
|
|
|
22619
22765
|
}
|
|
22620
22766
|
});
|
|
22621
22767
|
const integrationAdapter = new IntegrationManagerAdapter(integrationManager);
|
|
22622
|
-
|
|
22768
|
+
const runtimeGate = new RuntimeGate(() => runtimeProcess);
|
|
22769
|
+
cloudClient.setIntegrationManager(integrationAdapter, runtimeGate);
|
|
22623
22770
|
const requestRuntimeRestart = () => {
|
|
22624
|
-
|
|
22625
|
-
|
|
22626
|
-
runtimeProcess.restart().catch((err) => {
|
|
22627
|
-
logger$1.error({ err: err instanceof Error ? err.message : String(err) }, "Failed to restart runtime");
|
|
22628
|
-
});
|
|
22629
|
-
}
|
|
22771
|
+
logger$1.info("Runtime state changed — requesting runtime restart");
|
|
22772
|
+
runtimeGate.requestRestart();
|
|
22630
22773
|
};
|
|
22631
22774
|
cloudClient.setRuntimeRestartNeededHandler(requestRuntimeRestart);
|
|
22632
22775
|
if (config.runtime === "hermes") {
|
|
@@ -22676,7 +22819,10 @@ async function startDaemon() {
|
|
|
22676
22819
|
runtimeProcess.start();
|
|
22677
22820
|
logger$1.debug("Runtime process started");
|
|
22678
22821
|
if (config.runtime === "openclaw") {
|
|
22679
|
-
stopPairingApprovalPoller = startPairingApprovalPoller({
|
|
22822
|
+
stopPairingApprovalPoller = startPairingApprovalPoller({
|
|
22823
|
+
log: logger$1,
|
|
22824
|
+
cliLock: openclawCliLock
|
|
22825
|
+
});
|
|
22680
22826
|
logger$1.debug("Pairing approval poller started");
|
|
22681
22827
|
}
|
|
22682
22828
|
} else logger$1.warn({ runtime: config.runtime }, "No runtime config found — skipping runtime start");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/gateway",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Alfe local gateway daemon — persistent control plane for agent integrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@alfe.ai/ai-proxy-local": "^0.0.12",
|
|
27
27
|
"@alfe.ai/config": "^0.2.0",
|
|
28
28
|
"@alfe.ai/integration-manifest": "^0.3.1",
|
|
29
|
-
"@alfe.ai/integrations": "^0.2.
|
|
29
|
+
"@alfe.ai/integrations": "^0.2.6",
|
|
30
30
|
"@alfe.ai/mcp-bundler": "^0.2.2"
|
|
31
31
|
},
|
|
32
32
|
"license": "UNLICENSED",
|