@alfe.ai/gateway 0.10.1 → 0.10.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 +83 -6
- package/dist/node-remediation.js +1 -1
- package/dist/runtime-process.js +11 -1
- package/dist/runtime-upgrade.js +48 -19
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.js +1 -1
- package/package.json +2 -2
package/dist/health.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ErrorLineDetector, c as createLogger, i as CaptureThrottle, m as
|
|
1
|
+
import { a as ErrorLineDetector, c as createLogger, f as parseOpenClawVersion, h as __require, i as CaptureThrottle, m as __commonJSMin, n as OPENCLAW_EXTERNAL_SUPERVISOR_ENV, o as STRICT_ERROR_CAPTURE_PROFILE, r as RuntimeProcess, s as toFingerprintKey, t as DRAIN_GRACE_MS } from "./runtime-process.js";
|
|
2
2
|
import { a as captureFatal, d as flushSentry, f as initAgentSentry, h as logger, o as captureIntegrationFailure, p as setAgentContext, s as captureMcpFailure } from "./sentry.js";
|
|
3
3
|
import { chmod, mkdir, readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
@@ -5858,16 +5858,57 @@ const log$5 = logger.child({ component: "RuntimeGate" });
|
|
|
5858
5858
|
var RuntimeGate = class {
|
|
5859
5859
|
depth = 0;
|
|
5860
5860
|
wasRunning = false;
|
|
5861
|
+
exclusive = false;
|
|
5862
|
+
/** Brackets parked behind an exclusive hold (or an exclusive request parked behind open brackets). */
|
|
5863
|
+
waiters = [];
|
|
5861
5864
|
constructor(getRuntime) {
|
|
5862
5865
|
this.getRuntime = getRuntime;
|
|
5863
5866
|
}
|
|
5867
|
+
/** True while any bracket (shared or exclusive) is open. */
|
|
5868
|
+
get isSuspended() {
|
|
5869
|
+
return this.depth > 0;
|
|
5870
|
+
}
|
|
5871
|
+
/** True while an exclusive bracket is open. */
|
|
5872
|
+
get isExclusive() {
|
|
5873
|
+
return this.exclusive;
|
|
5874
|
+
}
|
|
5875
|
+
waitFor(ready) {
|
|
5876
|
+
if (ready()) return Promise.resolve();
|
|
5877
|
+
return new Promise((resolve) => {
|
|
5878
|
+
const check = () => {
|
|
5879
|
+
if (ready()) resolve();
|
|
5880
|
+
else this.waiters.push(check);
|
|
5881
|
+
};
|
|
5882
|
+
this.waiters.push(check);
|
|
5883
|
+
});
|
|
5884
|
+
}
|
|
5885
|
+
wakeWaiters() {
|
|
5886
|
+
const pending = this.waiters;
|
|
5887
|
+
this.waiters = [];
|
|
5888
|
+
for (const wake of pending) wake();
|
|
5889
|
+
}
|
|
5864
5890
|
/**
|
|
5865
5891
|
* Suspend the runtime child. Only the outermost call (depth 0 → 1) actually
|
|
5866
5892
|
* stops it; nested calls just bump the refcount. Remembers whether the child
|
|
5867
5893
|
* was running so `resume()` doesn't spuriously start a runtime that was never
|
|
5868
|
-
* up (e.g. autoStartRuntime=false).
|
|
5894
|
+
* up (e.g. autoStartRuntime=false). Waits while an exclusive bracket is open.
|
|
5869
5895
|
*/
|
|
5870
5896
|
async suspend() {
|
|
5897
|
+
if (this.exclusive) log$5.info("Mutating reconcile parked behind an exclusive runtime hold (upgrade in flight)");
|
|
5898
|
+
while (this.exclusive) await this.waitFor(() => !this.exclusive);
|
|
5899
|
+
await this.enter();
|
|
5900
|
+
}
|
|
5901
|
+
async suspendExclusive() {
|
|
5902
|
+
if (this.exclusive || this.depth !== 0) log$5.info({
|
|
5903
|
+
depth: this.depth,
|
|
5904
|
+
exclusive: this.exclusive
|
|
5905
|
+
}, "Exclusive runtime hold parked behind open brackets (reconcile in flight)");
|
|
5906
|
+
while (this.exclusive || this.depth !== 0) await this.waitFor(() => !this.exclusive && this.depth === 0);
|
|
5907
|
+
log$5.info("Exclusive runtime hold acquired");
|
|
5908
|
+
this.exclusive = true;
|
|
5909
|
+
await this.enter();
|
|
5910
|
+
}
|
|
5911
|
+
async enter() {
|
|
5871
5912
|
if (this.depth++ > 0) return;
|
|
5872
5913
|
const rp = this.getRuntime();
|
|
5873
5914
|
this.wasRunning = rp?.isRunning ?? false;
|
|
@@ -5891,6 +5932,8 @@ var RuntimeGate = class {
|
|
|
5891
5932
|
rp.resume();
|
|
5892
5933
|
}
|
|
5893
5934
|
this.wasRunning = false;
|
|
5935
|
+
if (this.exclusive) this.exclusive = false;
|
|
5936
|
+
this.wakeWaiters();
|
|
5894
5937
|
return Promise.resolve();
|
|
5895
5938
|
}
|
|
5896
5939
|
/**
|
|
@@ -5920,6 +5963,9 @@ var NoopRuntimeGate = class {
|
|
|
5920
5963
|
suspend() {
|
|
5921
5964
|
return Promise.resolve();
|
|
5922
5965
|
}
|
|
5966
|
+
suspendExclusive() {
|
|
5967
|
+
return Promise.resolve();
|
|
5968
|
+
}
|
|
5923
5969
|
resume() {
|
|
5924
5970
|
return Promise.resolve();
|
|
5925
5971
|
}
|
|
@@ -7982,6 +8028,7 @@ var IPCServer = class {
|
|
|
7982
8028
|
* standalone pieces of `startDaemon()`: version detection, the one-shot
|
|
7983
8029
|
* persona-file migration, the AI proxy listener, and the IPC server start.
|
|
7984
8030
|
*/
|
|
8031
|
+
const RUNTIME_VERSION_TIMEOUT_MS = 1e4;
|
|
7985
8032
|
const execFileAsync$2 = promisify(execFile);
|
|
7986
8033
|
/**
|
|
7987
8034
|
* Resolve the installed @alfe.ai/cli version.
|
|
@@ -8040,9 +8087,24 @@ function resolveRuntimeVersionCommand(runtime) {
|
|
|
8040
8087
|
return RUNTIME_VERSION_COMMANDS[runtime];
|
|
8041
8088
|
}
|
|
8042
8089
|
/**
|
|
8090
|
+
* Reduce a runtime's `--version` output to the bare version the control plane
|
|
8091
|
+
* compares against catalog versions. Every OpenClaw release prints a branded
|
|
8092
|
+
* line (`OpenClaw 2026.9.5 (ec9c1a1)`); reporting that verbatim hid every
|
|
8093
|
+
* dashboard upgrade affordance for the agents that most needed one. The agents
|
|
8094
|
+
* service also normalises at ingest (it reaches hosts on older daemons); this
|
|
8095
|
+
* is the producer-side half. Falls back to the trimmed output when no version
|
|
8096
|
+
* token is found so an unexpected format is still visible rather than blank.
|
|
8097
|
+
*/
|
|
8098
|
+
function normalizeRuntimeVersion(runtime, stdout) {
|
|
8099
|
+
const trimmed = stdout.trim();
|
|
8100
|
+
if (!trimmed) return void 0;
|
|
8101
|
+
if (runtime === "openclaw") return parseOpenClawVersion(trimmed) ?? trimmed;
|
|
8102
|
+
return trimmed;
|
|
8103
|
+
}
|
|
8104
|
+
/**
|
|
8043
8105
|
* Resolve the installed runtime version by running the per-runtime version
|
|
8044
|
-
* command and
|
|
8045
|
-
*
|
|
8106
|
+
* command and normalising its stdout. An unknown runtime (no command in the
|
|
8107
|
+
* map) returns `undefined` without spawning — it must never throw.
|
|
8046
8108
|
*/
|
|
8047
8109
|
async function getRuntimeVersion(runtime) {
|
|
8048
8110
|
const cmd = resolveRuntimeVersionCommand(runtime);
|
|
@@ -8051,8 +8113,14 @@ async function getRuntimeVersion(runtime) {
|
|
|
8051
8113
|
return;
|
|
8052
8114
|
}
|
|
8053
8115
|
try {
|
|
8054
|
-
const { stdout } = await execFileAsync$2(cmd.command, cmd.args
|
|
8055
|
-
|
|
8116
|
+
const { stdout } = await execFileAsync$2(cmd.command, cmd.args, {
|
|
8117
|
+
timeout: RUNTIME_VERSION_TIMEOUT_MS,
|
|
8118
|
+
env: {
|
|
8119
|
+
...process.env,
|
|
8120
|
+
...runtime === "openclaw" ? OPENCLAW_EXTERNAL_SUPERVISOR_ENV : {}
|
|
8121
|
+
}
|
|
8122
|
+
});
|
|
8123
|
+
return normalizeRuntimeVersion(runtime, stdout);
|
|
8056
8124
|
} catch {
|
|
8057
8125
|
logger.debug({ runtime }, "Could not resolve runtime version");
|
|
8058
8126
|
return;
|
|
@@ -9929,6 +9997,15 @@ async function drainRuntimeBeforeExit(reason) {
|
|
|
9929
9997
|
}
|
|
9930
9998
|
async function executeCloudCommand(command) {
|
|
9931
9999
|
if (isWorkCommand(command.command)) return executeWorkCommand(command, config.agentId, config.runtime, ipcServer);
|
|
10000
|
+
if ((command.command === "daemon.update" || command.command === "daemon.restart") && upgradingRuntime) return {
|
|
10001
|
+
type: "COMMAND_ACK",
|
|
10002
|
+
commandId: command.commandId,
|
|
10003
|
+
status: "error",
|
|
10004
|
+
result: {
|
|
10005
|
+
code: "RUNTIME_UPGRADE_IN_PROGRESS",
|
|
10006
|
+
message: `${command.command} refused: a runtime upgrade is in progress; retry when it has completed`
|
|
10007
|
+
}
|
|
10008
|
+
};
|
|
9932
10009
|
if (command.command === "daemon.update") {
|
|
9933
10010
|
const version = command.payload?.version ?? "latest";
|
|
9934
10011
|
setTimeout(() => {
|
package/dist/node-remediation.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { p as supportsOpenClawNode, u as OPENCLAW_NODE_REQUIREMENT } from "./runtime-process.js";
|
|
2
2
|
import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
package/dist/runtime-process.js
CHANGED
|
@@ -90,6 +90,16 @@ function supportsOpenClawNode(nodeVersion) {
|
|
|
90
90
|
if (major === 26) return minor >= 1;
|
|
91
91
|
return major > 26;
|
|
92
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Extract the semver-like version token printed by `openclaw --version`.
|
|
95
|
+
* Every OpenClaw release prints a branded line (`OpenClaw 2026.6.11 (e085fa1)`,
|
|
96
|
+
* `OpenClaw 2026.9.5 (ec9c1a1)`); this reduces it to the bare token. Requires
|
|
97
|
+
* whitespace delimiters and a four-digit year major, so unexpected formats
|
|
98
|
+
* return `undefined` and callers fall back to the raw line.
|
|
99
|
+
*/
|
|
100
|
+
function parseOpenClawVersion(output) {
|
|
101
|
+
return /(?:^|\s)(\d{4}\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)(?:\s|$)/u.exec(output.trim())?.[1];
|
|
102
|
+
}
|
|
93
103
|
//#endregion
|
|
94
104
|
//#region ../../node_modules/.pnpm/dotenv@17.2.2/node_modules/dotenv/package.json
|
|
95
105
|
var require_package = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -15766,4 +15776,4 @@ var RuntimeProcess = class {
|
|
|
15766
15776
|
}
|
|
15767
15777
|
};
|
|
15768
15778
|
//#endregion
|
|
15769
|
-
export { ErrorLineDetector as a, createLogger as c, PINNED_OPENCLAW_VERSION as d,
|
|
15779
|
+
export { ErrorLineDetector as a, createLogger as c, PINNED_OPENCLAW_VERSION as d, parseOpenClawVersion as f, __require as h, CaptureThrottle as i, OPENCLAW_MANAGED_NODE_MAJOR as l, __commonJSMin as m, OPENCLAW_EXTERNAL_SUPERVISOR_ENV as n, STRICT_ERROR_CAPTURE_PROFILE as o, supportsOpenClawNode as p, RuntimeProcess as r, toFingerprintKey as s, DRAIN_GRACE_MS as t, OPENCLAW_NODE_REQUIREMENT as u };
|
package/dist/runtime-upgrade.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as
|
|
2
|
-
import { c as captureNodeRemediation, h as logger } from "./sentry.js";
|
|
1
|
+
import { f as parseOpenClawVersion, n as OPENCLAW_EXTERNAL_SUPERVISOR_ENV, p as supportsOpenClawNode, u as OPENCLAW_NODE_REQUIREMENT } from "./runtime-process.js";
|
|
2
|
+
import { c as captureNodeRemediation, h as logger, i as captureCliFailure } from "./sentry.js";
|
|
3
3
|
import { n as remediateManagedNode, t as NodeRemediationError } from "./node-remediation.js";
|
|
4
4
|
import { mkdir } from "node:fs/promises";
|
|
5
5
|
import { join } from "node:path";
|
|
@@ -27,6 +27,7 @@ import { promisify } from "node:util";
|
|
|
27
27
|
const execFileAsync = promisify(execFile);
|
|
28
28
|
const OPENCLAW_UPGRADE_TIMEOUT_MS = 3e5;
|
|
29
29
|
const OPENCLAW_DOCTOR_TIMEOUT_MS = 9e5;
|
|
30
|
+
const OPENCLAW_DOCTOR_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
30
31
|
/**
|
|
31
32
|
* A non-diagnostic probe run right after the new package lands. 2026.9.x
|
|
32
33
|
* classifies `--version`/`--help` as diagnostic and lets them succeed even when
|
|
@@ -41,6 +42,31 @@ const OPENCLAW_DOCTOR_TIMEOUT_MS = 9e5;
|
|
|
41
42
|
* runtime regardless of config contents.
|
|
42
43
|
*/
|
|
43
44
|
const OPENCLAW_ADMISSION_PROBE_ARGS = ["config", "file"];
|
|
45
|
+
/**
|
|
46
|
+
* `doctor --fix` runs the state/config migration. On 2026.9.x `--json` puts
|
|
47
|
+
* doctor into READ-ONLY lint mode and it refuses the combination outright
|
|
48
|
+
* (exit 2: "doctor --json runs read-only lint checks and cannot be combined
|
|
49
|
+
* with --repair, --fix, or --force"), so the migration must run without it.
|
|
50
|
+
* The post-upgrade audit is read-only and keeps `--json`.
|
|
51
|
+
*/
|
|
52
|
+
const OPENCLAW_DOCTOR_FIX_ARGS = [
|
|
53
|
+
"doctor",
|
|
54
|
+
"--fix",
|
|
55
|
+
"--non-interactive",
|
|
56
|
+
"--yes"
|
|
57
|
+
];
|
|
58
|
+
const OPENCLAW_DOCTOR_AUDIT_ARGS = [
|
|
59
|
+
"doctor",
|
|
60
|
+
"--post-upgrade",
|
|
61
|
+
"--json"
|
|
62
|
+
];
|
|
63
|
+
/** Keep the tail of a command's output in an error so a failed migration is diagnosable from the daemon log. */
|
|
64
|
+
const OUTPUT_TAIL_CHARS = 1500;
|
|
65
|
+
const ANSI_ESCAPE = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[A-Za-z]`, "g");
|
|
66
|
+
function outputTail(value) {
|
|
67
|
+
const text = typeof value === "string" ? value.replace(ANSI_ESCAPE, "").trim() : "";
|
|
68
|
+
return text.length > OUTPUT_TAIL_CHARS ? `…${text.slice(-OUTPUT_TAIL_CHARS)}` : text;
|
|
69
|
+
}
|
|
44
70
|
function resolveUpgradeCommand(runtime, version) {
|
|
45
71
|
switch (runtime) {
|
|
46
72
|
case "openclaw":
|
|
@@ -70,10 +96,6 @@ function resolveUpgradeCommand(runtime, version) {
|
|
|
70
96
|
default: return;
|
|
71
97
|
}
|
|
72
98
|
}
|
|
73
|
-
/** Extract the semver-like version token printed by `openclaw --version`. */
|
|
74
|
-
function parseOpenClawVersion(output) {
|
|
75
|
-
return /(?:^|\s)(\d{4}\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)(?:\s|$)/u.exec(output.trim())?.[1];
|
|
76
|
-
}
|
|
77
99
|
async function upgradeRuntime(runtime, version, runtimeProcess, options = {}) {
|
|
78
100
|
const runCommand = options.runCommand ?? (async (command, args, commandOptions) => {
|
|
79
101
|
const result = await execFileAsync(command, args, commandOptions);
|
|
@@ -210,18 +232,25 @@ async function upgradeRuntime(runtime, version, runtimeProcess, options = {}) {
|
|
|
210
232
|
runtimeChanged = installedVersion !== previousOpenClawVersion;
|
|
211
233
|
await runCommand("openclaw", [...OPENCLAW_ADMISSION_PROBE_ARGS], commandOptions(6e4));
|
|
212
234
|
doctorStarted = true;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
"
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
235
|
+
try {
|
|
236
|
+
const doctor = await runCommand("openclaw", [...OPENCLAW_DOCTOR_FIX_ARGS], {
|
|
237
|
+
...commandOptions(OPENCLAW_DOCTOR_TIMEOUT_MS),
|
|
238
|
+
maxBuffer: OPENCLAW_DOCTOR_MAX_BUFFER_BYTES
|
|
239
|
+
});
|
|
240
|
+
logger.info({ doctor: outputTail(doctor.stdout) }, "OpenClaw doctor migration completed");
|
|
241
|
+
} catch (err) {
|
|
242
|
+
const failure = err;
|
|
243
|
+
const stdout = outputTail(failure.stdout);
|
|
244
|
+
const stderr = outputTail(failure.stderr);
|
|
245
|
+
logger.error({
|
|
246
|
+
stdout,
|
|
247
|
+
stderr
|
|
248
|
+
}, "OpenClaw doctor migration failed");
|
|
249
|
+
const wrapped = new Error(`openclaw doctor --fix failed: ${failure.message ?? String(err)}` + (stderr ? `\nstderr: ${stderr}` : "") + (stdout ? `\nstdout: ${stdout}` : ""), { cause: err });
|
|
250
|
+
captureCliFailure("openclaw-doctor-migration", wrapped);
|
|
251
|
+
throw wrapped;
|
|
252
|
+
}
|
|
253
|
+
const audit = await runCommand("openclaw", [...OPENCLAW_DOCTOR_AUDIT_ARGS], commandOptions(OPENCLAW_DOCTOR_TIMEOUT_MS));
|
|
225
254
|
if (audit.stdout) logger.info({ audit: audit.stdout.trim() }, "OpenClaw post-upgrade audit completed");
|
|
226
255
|
}
|
|
227
256
|
} catch (err) {
|
|
@@ -243,7 +272,7 @@ async function upgradeRuntime(runtime, version, runtimeProcess, options = {}) {
|
|
|
243
272
|
try {
|
|
244
273
|
if (options.gate) {
|
|
245
274
|
gateSuspended = true;
|
|
246
|
-
await options.gate.
|
|
275
|
+
await options.gate.suspendExclusive();
|
|
247
276
|
} else if (runtimeProcess) await runtimeProcess.stopWhenIdle();
|
|
248
277
|
if (runtime === "openclaw" && options.cliLock) await options.cliLock.run(performUpgrade);
|
|
249
278
|
else await performUpgrade();
|
package/dist/src/index.d.ts
CHANGED
|
@@ -76,6 +76,13 @@ declare const OPENCLAW_MANAGED_NODE_MAJOR = 24;
|
|
|
76
76
|
* Pre-release tags are rejected; build metadata (`+…`) is accepted.
|
|
77
77
|
*/
|
|
78
78
|
declare function supportsOpenClawNode(nodeVersion: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Extract the semver-like version token printed by `openclaw --version`.
|
|
81
|
+
* Every OpenClaw release prints a branded line (`OpenClaw 2026.6.11 (e085fa1)`,
|
|
82
|
+
* `OpenClaw 2026.9.5 (ec9c1a1)`); this reduces it to the bare token. Requires
|
|
83
|
+
* whitespace delimiters and a four-digit year major, so unexpected formats
|
|
84
|
+
* return `undefined` and callers fall back to the raw line.
|
|
85
|
+
*/
|
|
79
86
|
//#endregion
|
|
80
87
|
//#region src/node-remediation.d.ts
|
|
81
88
|
|
package/dist/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as PINNED_OPENCLAW_VERSION,
|
|
1
|
+
import { d as PINNED_OPENCLAW_VERSION, l as OPENCLAW_MANAGED_NODE_MAJOR, p as supportsOpenClawNode, u as OPENCLAW_NODE_REQUIREMENT } from "../runtime-process.js";
|
|
2
2
|
import { _ as loadDaemonConfig, a as installService, c as startService, d as uninstallService, f as PROTOCOL_VERSION, g as fetchAgentConfig, h as SOCKET_PATH, i as checkExistingDaemon, l as stopExistingDaemon, m as PID_PATH, n as queryDaemonHealth, o as isServiceInstalled, p as ALFE_DIR, r as startDaemon, s as restartService, t as formatHealthReport, u as stopService, v as resolveAgentIdentity, y as PINNED_CLAUDE_CODE_HOST_VERSION } from "../health.js";
|
|
3
3
|
import { a as captureFatal, d as flushSentry, f as initAgentSentry, h as logger, i as captureCliFailure, l as captureRuntimeCrash, n as AGENT_MCP_SENTRY_DSN, o as captureIntegrationFailure, p as setAgentContext, r as AGENT_RUNTIME_SENTRY_DSN, s as captureMcpFailure, t as AGENT_DAEMON_SENTRY_DSN, u as captureRuntimeErrorOutput } from "../sentry.js";
|
|
4
4
|
import { n as remediateManagedNode } from "../node-remediation.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/gateway",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "Alfe local gateway daemon — persistent control plane for agent integrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@alfe.ai/ai-proxy-local": "^0.0.17",
|
|
28
28
|
"@alfe.ai/config": "^0.4.1",
|
|
29
29
|
"@alfe.ai/integration-manifest": "^0.4.2",
|
|
30
|
-
"@alfe.ai/integrations": "^0.6.
|
|
30
|
+
"@alfe.ai/integrations": "^0.6.8",
|
|
31
31
|
"@alfe.ai/mcp-bundler": "^0.4.2"
|
|
32
32
|
},
|
|
33
33
|
"license": "UNLICENSED",
|