@alfe.ai/gateway 0.10.8 → 0.11.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 +157 -38
- package/dist/src/index.d.ts +22 -3
- package/dist/src/index.js +2 -2
- package/dist/upgrade.js +5 -5
- package/package.json +5 -5
package/dist/health.js
CHANGED
|
@@ -7,7 +7,7 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSy
|
|
|
7
7
|
import { ClaudeCodeApplier, ClaudeCodeMcpSync, HermesApplier, HermesMcpSync, IntegrationManager, IntegrationManagerAdapter, LockManager, McpApplier, NoopOpenClawCliLock, OpenClawApplier, SerialOpenClawCliLock } from "@alfe.ai/integrations";
|
|
8
8
|
import { execFile, execSync } from "node:child_process";
|
|
9
9
|
import { promisify } from "node:util";
|
|
10
|
-
import { getEndpointFromToken, readConfig } from "@alfe.ai/config";
|
|
10
|
+
import { getEndpointFromToken, readConfig, resolveAgentWorkspace } from "@alfe.ai/config";
|
|
11
11
|
import { AgentApiClient } from "@alfe.ai/agent-api-client";
|
|
12
12
|
import { parse } from "smol-toml";
|
|
13
13
|
import WebSocket from "ws";
|
|
@@ -3744,11 +3744,23 @@ function superRefine(fn) {
|
|
|
3744
3744
|
* new host, then cut a CLI release so the pin travels with the CLI version. The
|
|
3745
3745
|
* dashboard still surfaces npm-`latest` as an explicit opt-in upgrade.
|
|
3746
3746
|
*
|
|
3747
|
-
* NOTE: claude-code
|
|
3747
|
+
* NOTE: managed claude-code agents run on Hetzner VMs provisioned by cloud-init
|
|
3748
|
+
* + `alfe setup --managed` (no Docker image), so — unlike
|
|
3748
3749
|
* `PINNED_OPENCLAW_VERSION` — there is no `services/compute/Dockerfile` mirror to
|
|
3749
3750
|
* keep in sync.
|
|
3750
3751
|
*/
|
|
3751
|
-
const PINNED_CLAUDE_CODE_HOST_VERSION = "0.1.
|
|
3752
|
+
const PINNED_CLAUDE_CODE_HOST_VERSION = "0.1.15";
|
|
3753
|
+
/**
|
|
3754
|
+
* The `@anthropic-ai/claude-code` (the `claude` CLI) version Alfe installs for
|
|
3755
|
+
* the claude-code runtime: always on managed VMs (`alfe setup --managed`), and
|
|
3756
|
+
* on self-hosted machines only when no `claude` is present (a user-installed
|
|
3757
|
+
* `claude` is never replaced). Pinned to npm's `stable` dist-tag as of
|
|
3758
|
+
* 2026-10-14 — `latest` moves daily and the host drives `claude -p` flags
|
|
3759
|
+
* (`--resume`, `--mcp-config`, `--strict-mcp-config`, `--permission-mode`)
|
|
3760
|
+
* whose behaviour must be validated before a bump. The pin travels with the
|
|
3761
|
+
* CLI release.
|
|
3762
|
+
*/
|
|
3763
|
+
const PINNED_CLAUDE_CODE_VERSION = "2.1.287";
|
|
3752
3764
|
//#endregion
|
|
3753
3765
|
//#region ../../packages-internal/ids/dist/prefixes.js
|
|
3754
3766
|
const ID_PREFIXES = {
|
|
@@ -4388,13 +4400,18 @@ const AnthropicModel = {
|
|
|
4388
4400
|
Opus48: "claude-opus-4-8",
|
|
4389
4401
|
Opus47: "claude-opus-4-7",
|
|
4390
4402
|
Opus46: "claude-opus-4-6",
|
|
4403
|
+
Sonnet55: "claude-sonnet-5-5",
|
|
4391
4404
|
Sonnet5: "claude-sonnet-5",
|
|
4392
4405
|
Sonnet46: "claude-sonnet-4-6",
|
|
4406
|
+
Haiku55: "claude-haiku-5-5",
|
|
4393
4407
|
Haiku45: "claude-haiku-4-5"
|
|
4394
4408
|
};
|
|
4395
4409
|
const ANTHROPIC_MODELS = enumValues(AnthropicModel);
|
|
4396
4410
|
const OpenAIModel = {
|
|
4397
4411
|
GPT6Astra: "gpt-6-astra",
|
|
4412
|
+
GPT61Sol: "gpt-6.1-sol",
|
|
4413
|
+
GPT6Sol: "gpt-6-sol",
|
|
4414
|
+
GPT6Luna: "gpt-6-luna",
|
|
4398
4415
|
GPT4o: "gpt-4o",
|
|
4399
4416
|
GPT4oMini: "gpt-4o-mini",
|
|
4400
4417
|
O3: "o3",
|
|
@@ -4424,8 +4441,8 @@ const DeepSeekModel = {
|
|
|
4424
4441
|
const DEEPSEEK_MODELS = enumValues(DeepSeekModel);
|
|
4425
4442
|
const GoogleModel = {
|
|
4426
4443
|
Gemini38Flash: "gemini-3.8-flash",
|
|
4427
|
-
Gemini37Flash: "gemini-3.7-flash",
|
|
4428
4444
|
Gemini36Flash: "gemini-3.6-flash",
|
|
4445
|
+
Gemini37Flash: "gemini-3.7-flash",
|
|
4429
4446
|
Gemini35Flash: "gemini-3.5-flash",
|
|
4430
4447
|
Gemini35FlashLite: "gemini-3.5-flash-lite",
|
|
4431
4448
|
Gemini31Pro: "gemini-3.1-pro-preview",
|
|
@@ -4439,12 +4456,11 @@ const MiniMaxModel = {
|
|
|
4439
4456
|
M3: "MiniMax-M3",
|
|
4440
4457
|
M27: "MiniMax-M2.7",
|
|
4441
4458
|
M27HighSpeed: "MiniMax-M2.7-highspeed",
|
|
4442
|
-
M25: "MiniMax-M2.5"
|
|
4443
|
-
M21: "MiniMax-M2.1",
|
|
4444
|
-
M2: "MiniMax-M2"
|
|
4459
|
+
M25: "MiniMax-M2.5"
|
|
4445
4460
|
};
|
|
4446
4461
|
const MINIMAX_MODELS = enumValues(MiniMaxModel);
|
|
4447
4462
|
const MistralModel = {
|
|
4463
|
+
Large4: "mistral-large-4",
|
|
4448
4464
|
Large: "mistral-large-latest",
|
|
4449
4465
|
Medium: "mistral-medium-latest",
|
|
4450
4466
|
Small: "mistral-small-latest",
|
|
@@ -4514,7 +4530,7 @@ _enum(ZHIPU_MODELS);
|
|
|
4514
4530
|
_enum(MOONSHOT_MODELS);
|
|
4515
4531
|
_enum(QWEN_MODELS);
|
|
4516
4532
|
string().trim().min(1);
|
|
4517
|
-
AnthropicModel.Opus55, AnthropicModel.Opus5, AnthropicModel.Opus48, AnthropicModel.Opus47, AnthropicModel.Opus46, AnthropicModel.Sonnet5, AnthropicModel.Sonnet46, AnthropicModel.Haiku45, OpenAIModel.GPT6Astra, OpenAIModel.GPT4o, OpenAIModel.GPT4oMini, OpenAIModel.O3, OpenAIModel.GPT41, OpenAIModel.GPT41Mini, OpenAIModel.GPT41Nano, OpenAIModel.GPT54, OpenAIModel.GPT54Mini, OpenAIModel.GPT54Nano, OpenAIModel.GPT54Pro, OpenAIModel.GPT55, OpenAIModel.GPT55Pro, OpenAIModel.GPT56Sol, OpenAIModel.GPT56Terra, OpenAIModel.GPT56Luna, OpenAIModel.O3Mini, OpenAIModel.O4Mini, OpenAIModel.TextEmbedding3Small, OpenAIModel.TextEmbedding3Large, DeepSeekModel.Flash, DeepSeekModel.V4Pro, DeepSeekModel.V4Flash, GoogleModel.Gemini38Flash, GoogleModel.Gemini37Flash, GoogleModel.Gemini36Flash, GoogleModel.Gemini35Flash, GoogleModel.Gemini35FlashLite, GoogleModel.Gemini31Pro, GoogleModel.Gemini31FlashLite, GoogleModel.Gemini25Pro, GoogleModel.Gemini25Flash, GoogleModel.Gemini25FlashLite, MiniMaxModel.M3, MiniMaxModel.M27, MiniMaxModel.M27HighSpeed, MiniMaxModel.M25,
|
|
4533
|
+
AnthropicModel.Opus55, AnthropicModel.Opus5, AnthropicModel.Opus48, AnthropicModel.Opus47, AnthropicModel.Opus46, AnthropicModel.Sonnet55, AnthropicModel.Sonnet5, AnthropicModel.Sonnet46, AnthropicModel.Haiku55, AnthropicModel.Haiku45, OpenAIModel.GPT6Astra, OpenAIModel.GPT61Sol, OpenAIModel.GPT6Sol, OpenAIModel.GPT6Luna, OpenAIModel.GPT4o, OpenAIModel.GPT4oMini, OpenAIModel.O3, OpenAIModel.GPT41, OpenAIModel.GPT41Mini, OpenAIModel.GPT41Nano, OpenAIModel.GPT54, OpenAIModel.GPT54Mini, OpenAIModel.GPT54Nano, OpenAIModel.GPT54Pro, OpenAIModel.GPT55, OpenAIModel.GPT55Pro, OpenAIModel.GPT56Sol, OpenAIModel.GPT56Terra, OpenAIModel.GPT56Luna, OpenAIModel.O3Mini, OpenAIModel.O4Mini, OpenAIModel.TextEmbedding3Small, OpenAIModel.TextEmbedding3Large, DeepSeekModel.Flash, DeepSeekModel.V4Pro, DeepSeekModel.V4Flash, GoogleModel.Gemini38Flash, GoogleModel.Gemini37Flash, GoogleModel.Gemini36Flash, GoogleModel.Gemini35Flash, GoogleModel.Gemini35FlashLite, GoogleModel.Gemini31Pro, GoogleModel.Gemini31FlashLite, GoogleModel.Gemini25Pro, GoogleModel.Gemini25Flash, GoogleModel.Gemini25FlashLite, MiniMaxModel.M3, MiniMaxModel.M27, MiniMaxModel.M27HighSpeed, MiniMaxModel.M25, MistralModel.Large4, MistralModel.Large, MistralModel.Medium, MistralModel.Small, MistralModel.Codestral, MistralModel.Ministral8b, MistralModel.Ministral3b, XAIModel.Grok47, XAIModel.Grok46, XAIModel.Grok45, XAIModel.Grok43, XAIModel.GrokBuild01, XAIModel.Grok4, XAIModel.Grok41Fast, ZhipuModel.GLM53, ZhipuModel.GLM53Flash, ZhipuModel.GLM53FlashX, ZhipuModel.GLM52, ZhipuModel.GLM51, ZhipuModel.GLM46, ZhipuModel.GLM45, ZhipuModel.GLM45Air, MoonshotModel.K3, MoonshotModel.K26, MoonshotModel.K27Code, MoonshotModel.K27CodeHighSpeed, QwenModel.Qwen38Max, QwenModel.Qwen38Flash, QwenModel.Qwen37Max, QwenModel.Qwen37Plus, QwenModel.Qwen36Flash, QwenModel.Qwen35Flash;
|
|
4518
4534
|
/**
|
|
4519
4535
|
* Alfe-hosted open-weight models are promoted dynamically only in regions
|
|
4520
4536
|
* whose private data plane exists. Keep them out of ALL_MODELS so the standard
|
|
@@ -4574,7 +4590,7 @@ const AWS_PRIVATE_MODEL_PRICING = {
|
|
|
4574
4590
|
[BedrockModel.TitanEmbedTextV2]: { input: .026004 }
|
|
4575
4591
|
};
|
|
4576
4592
|
Object.fromEntries(AWS_PRIVATE_BEDROCK_CHAT_MODELS.map((modelId) => [`alfe-bedrock-${modelId}`, AWS_PRIVATE_MODEL_PRICING[modelId]]));
|
|
4577
|
-
AnthropicModel.Opus55, AnthropicModel.Opus5, AnthropicModel.Opus48, AnthropicModel.Opus47, AnthropicModel.Opus46, AnthropicModel.Sonnet5, AnthropicModel.Sonnet46, AnthropicModel.Haiku45, OpenAIModel.GPT6Astra, OpenAIModel.GPT4o, OpenAIModel.GPT4oMini, OpenAIModel.O3, OpenAIModel.GPT41, OpenAIModel.GPT41Mini, OpenAIModel.GPT41Nano, OpenAIModel.GPT54, OpenAIModel.GPT54Mini, OpenAIModel.GPT54Nano, OpenAIModel.GPT54Pro, OpenAIModel.GPT55, OpenAIModel.GPT55Pro, OpenAIModel.GPT56Sol, OpenAIModel.GPT56Terra, OpenAIModel.GPT56Luna, OpenAIModel.O3Mini, OpenAIModel.O4Mini, OpenAIModel.TextEmbedding3Small, OpenAIModel.TextEmbedding3Large, DeepSeekModel.Flash, DeepSeekModel.V4Pro, DeepSeekModel.V4Flash, GoogleModel.Gemini38Flash, GoogleModel.Gemini37Flash, GoogleModel.Gemini36Flash, GoogleModel.Gemini35Flash, GoogleModel.Gemini35FlashLite, GoogleModel.Gemini31Pro, GoogleModel.Gemini31FlashLite, GoogleModel.Gemini25Pro, GoogleModel.Gemini25Flash, GoogleModel.Gemini25FlashLite, MiniMaxModel.M3, MiniMaxModel.M27, MiniMaxModel.M27HighSpeed, MiniMaxModel.M25,
|
|
4593
|
+
AnthropicModel.Opus55, AnthropicModel.Opus5, AnthropicModel.Opus48, AnthropicModel.Opus47, AnthropicModel.Opus46, AnthropicModel.Sonnet55, AnthropicModel.Sonnet5, AnthropicModel.Sonnet46, AnthropicModel.Haiku55, AnthropicModel.Haiku45, OpenAIModel.GPT6Astra, OpenAIModel.GPT61Sol, OpenAIModel.GPT6Sol, OpenAIModel.GPT6Luna, OpenAIModel.GPT4o, OpenAIModel.GPT4oMini, OpenAIModel.O3, OpenAIModel.GPT41, OpenAIModel.GPT41Mini, OpenAIModel.GPT41Nano, OpenAIModel.GPT54, OpenAIModel.GPT54Mini, OpenAIModel.GPT54Nano, OpenAIModel.GPT54Pro, OpenAIModel.GPT55, OpenAIModel.GPT55Pro, OpenAIModel.GPT56Sol, OpenAIModel.GPT56Terra, OpenAIModel.GPT56Luna, OpenAIModel.O3Mini, OpenAIModel.O4Mini, OpenAIModel.TextEmbedding3Small, OpenAIModel.TextEmbedding3Large, DeepSeekModel.Flash, DeepSeekModel.V4Pro, DeepSeekModel.V4Flash, GoogleModel.Gemini38Flash, GoogleModel.Gemini37Flash, GoogleModel.Gemini36Flash, GoogleModel.Gemini35Flash, GoogleModel.Gemini35FlashLite, GoogleModel.Gemini31Pro, GoogleModel.Gemini31FlashLite, GoogleModel.Gemini25Pro, GoogleModel.Gemini25Flash, GoogleModel.Gemini25FlashLite, MiniMaxModel.M3, MiniMaxModel.M27, MiniMaxModel.M27HighSpeed, MiniMaxModel.M25, MistralModel.Large4, MistralModel.Large, MistralModel.Medium, MistralModel.Small, MistralModel.Codestral, MistralModel.Ministral8b, MistralModel.Ministral3b, XAIModel.Grok47, XAIModel.Grok46, XAIModel.Grok45, XAIModel.Grok43, XAIModel.GrokBuild01, XAIModel.Grok4, XAIModel.Grok41Fast, ZhipuModel.GLM53, ZhipuModel.GLM53Flash, ZhipuModel.GLM53FlashX, ZhipuModel.GLM52, ZhipuModel.GLM51, ZhipuModel.GLM46, ZhipuModel.GLM45, ZhipuModel.GLM45Air, MoonshotModel.K3, MoonshotModel.K26, MoonshotModel.K27Code, MoonshotModel.K27CodeHighSpeed, QwenModel.Qwen38Max, QwenModel.Qwen38Flash, QwenModel.Qwen37Max, QwenModel.Qwen37Plus, QwenModel.Qwen36Flash, QwenModel.Qwen35Flash;
|
|
4578
4594
|
enumValues({
|
|
4579
4595
|
Standard: "standard",
|
|
4580
4596
|
AwsPrivate: "aws_private"
|
|
@@ -4718,6 +4734,14 @@ NotificationType.PaymentSucceeded, NotificationCategory.Billing, RecipientStrate
|
|
|
4718
4734
|
* Platform-agnostic: works in React Native and browser environments.
|
|
4719
4735
|
* Uses standard fetch() API — no Node.js dependencies.
|
|
4720
4736
|
*/
|
|
4737
|
+
/** A sane 429 window hint: a positive whole number of seconds (≤ 1 day). */
|
|
4738
|
+
function isRetryAfterSeconds(value) {
|
|
4739
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 && value <= 86400;
|
|
4740
|
+
}
|
|
4741
|
+
/** Narrow allowlist: a non-empty list of `{ profile: string, message: string }`. */
|
|
4742
|
+
function isProfileErrorList(value) {
|
|
4743
|
+
return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "object" && entry !== null && typeof entry.profile === "string" && typeof entry.message === "string");
|
|
4744
|
+
}
|
|
4721
4745
|
var AlfeApiClient = class {
|
|
4722
4746
|
apiBaseUrl;
|
|
4723
4747
|
getToken;
|
|
@@ -4790,7 +4814,12 @@ var AlfeApiClient = class {
|
|
|
4790
4814
|
error: errorMessage ?? (typeof body === "string" ? body : `API error: ${String(res.status)}`),
|
|
4791
4815
|
status: res.status,
|
|
4792
4816
|
...typeof errBody?.code === "string" ? { code: errBody.code } : {},
|
|
4793
|
-
...Array.isArray(errBody?.ineligibleUserIds) && errBody.ineligibleUserIds.every((id) => typeof id === "string") ? { ineligibleUserIds: [...errBody.ineligibleUserIds] } : {}
|
|
4817
|
+
...Array.isArray(errBody?.ineligibleUserIds) && errBody.ineligibleUserIds.every((id) => typeof id === "string") ? { ineligibleUserIds: [...errBody.ineligibleUserIds] } : {},
|
|
4818
|
+
...isProfileErrorList(errBody?.errors) ? { profileErrors: errBody.errors.map(({ profile, message }) => ({
|
|
4819
|
+
profile,
|
|
4820
|
+
message
|
|
4821
|
+
})) } : {},
|
|
4822
|
+
...isRetryAfterSeconds(errBody?.retryAfterSeconds) ? { retryAfterSeconds: errBody.retryAfterSeconds } : {}
|
|
4794
4823
|
}
|
|
4795
4824
|
};
|
|
4796
4825
|
}
|
|
@@ -5517,16 +5546,13 @@ function _resolveManagedGatewayWsUrl(apiEndpoint) {
|
|
|
5517
5546
|
* workspace = "~/.openclaw"
|
|
5518
5547
|
*/
|
|
5519
5548
|
/**
|
|
5520
|
-
* Derive the agent workspace path
|
|
5521
|
-
*
|
|
5522
|
-
*
|
|
5523
|
-
*
|
|
5524
|
-
* + skills"). For other runtimes, default to home itself.
|
|
5549
|
+
* Derive the agent workspace path (the runtime's CWD) from its home dir.
|
|
5550
|
+
* Delegates to the shared `@alfe.ai/config` rule so the daemon, the CLI and
|
|
5551
|
+
* the claude-code host cannot drift: openclaw and claude-code run in
|
|
5552
|
+
* `${home}/workspace`, other runtimes run in the home itself.
|
|
5525
5553
|
*/
|
|
5526
5554
|
function deriveAgentWorkspace(runtime, home) {
|
|
5527
|
-
|
|
5528
|
-
if (runtime === "claude-code") return join(home, "workspace");
|
|
5529
|
-
return home;
|
|
5555
|
+
return resolveAgentWorkspace(runtime, home);
|
|
5530
5556
|
}
|
|
5531
5557
|
const UNSAFE_RECORD_KEYS = new Set([
|
|
5532
5558
|
"__proto__",
|
|
@@ -5589,6 +5615,7 @@ async function loadManagedConfig() {
|
|
|
5589
5615
|
runtime: identity.runtime,
|
|
5590
5616
|
gatewayWsUrl
|
|
5591
5617
|
}, "Managed config resolved");
|
|
5618
|
+
const defaultModel = identity.runtime === "claude-code" ? await resolveClaudeCodeDefaultModel(apiKey, apiEndpoint) : void 0;
|
|
5592
5619
|
return {
|
|
5593
5620
|
apiKey,
|
|
5594
5621
|
apiEndpoint,
|
|
@@ -5599,7 +5626,8 @@ async function loadManagedConfig() {
|
|
|
5599
5626
|
orgId: identity.orgId,
|
|
5600
5627
|
runtime: identity.runtime,
|
|
5601
5628
|
runtimes: buildManagedRuntimes(identity.runtime),
|
|
5602
|
-
autoStartRuntime: true
|
|
5629
|
+
autoStartRuntime: true,
|
|
5630
|
+
...defaultModel ? { defaultModel } : {}
|
|
5603
5631
|
};
|
|
5604
5632
|
}
|
|
5605
5633
|
/**
|
|
@@ -5622,6 +5650,13 @@ function buildManagedRuntimes(runtime) {
|
|
|
5622
5650
|
agentWorkspace: deriveAgentWorkspace("hermes", home)
|
|
5623
5651
|
} };
|
|
5624
5652
|
}
|
|
5653
|
+
if (runtime === "claude-code") {
|
|
5654
|
+
const home = join(homedir(), ".claude-code");
|
|
5655
|
+
return { "claude-code": {
|
|
5656
|
+
workspace: home,
|
|
5657
|
+
agentWorkspace: deriveAgentWorkspace("claude-code", home)
|
|
5658
|
+
} };
|
|
5659
|
+
}
|
|
5625
5660
|
return {};
|
|
5626
5661
|
}
|
|
5627
5662
|
/**
|
|
@@ -5644,17 +5679,7 @@ async function loadDaemonConfig() {
|
|
|
5644
5679
|
const gatewayWsUrl = alfeConfig.gateway_url ?? deriveGatewayWsUrl(apiEndpoint);
|
|
5645
5680
|
const runtimes = await loadRuntimeConfigs();
|
|
5646
5681
|
const runtime = alfeConfig.runtime ?? identity.runtime;
|
|
5647
|
-
|
|
5648
|
-
if (runtime === "claude-code") {
|
|
5649
|
-
let timer;
|
|
5650
|
-
const ws = await Promise.race([fetchAgentConfig(alfeConfig.api_key, apiEndpoint), new Promise((resolve) => {
|
|
5651
|
-
timer = setTimeout(() => {
|
|
5652
|
-
resolve(null);
|
|
5653
|
-
}, 5e3);
|
|
5654
|
-
})]);
|
|
5655
|
-
if (timer) clearTimeout(timer);
|
|
5656
|
-
defaultModel = ws?.defaultModel;
|
|
5657
|
-
}
|
|
5682
|
+
const defaultModel = runtime === "claude-code" ? await resolveClaudeCodeDefaultModel(alfeConfig.api_key, apiEndpoint) : void 0;
|
|
5658
5683
|
return {
|
|
5659
5684
|
apiKey: alfeConfig.api_key,
|
|
5660
5685
|
apiEndpoint,
|
|
@@ -5670,6 +5695,38 @@ async function loadDaemonConfig() {
|
|
|
5670
5695
|
};
|
|
5671
5696
|
}
|
|
5672
5697
|
/**
|
|
5698
|
+
* The claude-code agent's bare `defaultModel`, for `ALFE_DEFAULT_MODEL`.
|
|
5699
|
+
* Bounded so a slow or hung workspace endpoint can't block daemon startup; any
|
|
5700
|
+
* failure or timeout yields `undefined` and the host falls back to the `claude`
|
|
5701
|
+
* CLI default. Shared by the managed and self-hosted config loaders.
|
|
5702
|
+
*/
|
|
5703
|
+
async function resolveClaudeCodeDefaultModel(apiKey, apiEndpoint, options = {}) {
|
|
5704
|
+
const fetcher = options.fetcher ?? fetchWorkspaceDefaultModel;
|
|
5705
|
+
let timer;
|
|
5706
|
+
try {
|
|
5707
|
+
return (await Promise.race([fetcher(apiKey, apiEndpoint), new Promise((resolve) => {
|
|
5708
|
+
timer = setTimeout(() => {
|
|
5709
|
+
resolve(null);
|
|
5710
|
+
}, options.timeoutMs ?? 5e3);
|
|
5711
|
+
})]))?.defaultModel ?? void 0;
|
|
5712
|
+
} catch {
|
|
5713
|
+
return;
|
|
5714
|
+
} finally {
|
|
5715
|
+
if (timer) clearTimeout(timer);
|
|
5716
|
+
}
|
|
5717
|
+
}
|
|
5718
|
+
/**
|
|
5719
|
+
* Workspace metadata only. The default model lives on the workspace record, so
|
|
5720
|
+
* it must not wait on (or time out behind) the persona/template file fetch
|
|
5721
|
+
* that `fetchAgentConfig` also performs.
|
|
5722
|
+
*/
|
|
5723
|
+
async function fetchWorkspaceDefaultModel(apiKey, apiEndpoint) {
|
|
5724
|
+
return { defaultModel: (await new AgentApiClient({
|
|
5725
|
+
apiKey,
|
|
5726
|
+
apiUrl: apiEndpoint
|
|
5727
|
+
}).getWorkspace()).defaultModel ?? void 0 };
|
|
5728
|
+
}
|
|
5729
|
+
/**
|
|
5673
5730
|
* Fetch agent workspace config from the API.
|
|
5674
5731
|
*
|
|
5675
5732
|
* 1. GET /agents/me/workspace → { templateKey }
|
|
@@ -7092,8 +7149,10 @@ var ConfigReconciler = class {
|
|
|
7092
7149
|
getApplier;
|
|
7093
7150
|
verifyRetries;
|
|
7094
7151
|
verifyRetryDelayMs;
|
|
7152
|
+
onKeysApplied;
|
|
7095
7153
|
constructor(options) {
|
|
7096
7154
|
this.getApplier = options.getApplier;
|
|
7155
|
+
this.onKeysApplied = options.onKeysApplied;
|
|
7097
7156
|
this.verifyRetries = options.verifyRetries ?? DEFAULT_VERIFY_RETRIES;
|
|
7098
7157
|
this.verifyRetryDelayMs = options.verifyRetryDelayMs ?? DEFAULT_VERIFY_RETRY_DELAY_MS;
|
|
7099
7158
|
}
|
|
@@ -7116,6 +7175,7 @@ var ConfigReconciler = class {
|
|
|
7116
7175
|
};
|
|
7117
7176
|
const failures = [];
|
|
7118
7177
|
const inconclusiveKeys = [];
|
|
7178
|
+
const changedKeys = [];
|
|
7119
7179
|
for (const [key, want] of entries) try {
|
|
7120
7180
|
if (getConfigRaw) {
|
|
7121
7181
|
let current;
|
|
@@ -7136,8 +7196,11 @@ var ConfigReconciler = class {
|
|
|
7136
7196
|
if (getConfigRaw) {
|
|
7137
7197
|
const outcome = await this.verify(getConfigRaw, key, want);
|
|
7138
7198
|
if (outcome === "mismatched") failures.push(`${key}: verify failed (read-back did not match)`);
|
|
7139
|
-
else
|
|
7140
|
-
|
|
7199
|
+
else {
|
|
7200
|
+
if (outcome === "inconclusive") inconclusiveKeys.push(key);
|
|
7201
|
+
changedKeys.push(key);
|
|
7202
|
+
}
|
|
7203
|
+
} else changedKeys.push(key);
|
|
7141
7204
|
} catch (err) {
|
|
7142
7205
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7143
7206
|
if (getConfigRaw) {
|
|
@@ -7147,15 +7210,18 @@ var ConfigReconciler = class {
|
|
|
7147
7210
|
key,
|
|
7148
7211
|
err: msg
|
|
7149
7212
|
}, "config set errored but value landed — treating as applied");
|
|
7213
|
+
changedKeys.push(key);
|
|
7150
7214
|
continue;
|
|
7151
7215
|
}
|
|
7152
7216
|
if (outcome === "inconclusive") {
|
|
7153
7217
|
inconclusiveKeys.push(key);
|
|
7218
|
+
changedKeys.push(key);
|
|
7154
7219
|
continue;
|
|
7155
7220
|
}
|
|
7156
7221
|
}
|
|
7157
7222
|
failures.push(`${key}: ${msg}`);
|
|
7158
7223
|
}
|
|
7224
|
+
this.notifyKeysApplied(changedKeys);
|
|
7159
7225
|
if (failures.length > 0) {
|
|
7160
7226
|
const joined = failures.join("; ");
|
|
7161
7227
|
const reason = joined.length > 480 ? `${joined.slice(0, 480)}… (truncated)` : joined;
|
|
@@ -7185,6 +7251,17 @@ var ConfigReconciler = class {
|
|
|
7185
7251
|
status: "applied"
|
|
7186
7252
|
};
|
|
7187
7253
|
}
|
|
7254
|
+
notifyKeysApplied(keys) {
|
|
7255
|
+
if (keys.length === 0 || !this.onKeysApplied) return;
|
|
7256
|
+
try {
|
|
7257
|
+
this.onKeysApplied(keys);
|
|
7258
|
+
} catch (err) {
|
|
7259
|
+
log$4.warn({
|
|
7260
|
+
keys,
|
|
7261
|
+
err: err instanceof Error ? err.message : String(err)
|
|
7262
|
+
}, "onKeysApplied hook failed — config report unaffected");
|
|
7263
|
+
}
|
|
7264
|
+
}
|
|
7188
7265
|
async verify(getConfigRaw, key, want) {
|
|
7189
7266
|
let observedValue = false;
|
|
7190
7267
|
for (let attempt = 0; attempt <= this.verifyRetries; attempt++) {
|
|
@@ -7203,6 +7280,38 @@ var ConfigReconciler = class {
|
|
|
7203
7280
|
return observedValue ? "mismatched" : "inconclusive";
|
|
7204
7281
|
}
|
|
7205
7282
|
};
|
|
7283
|
+
/** Extra environment for the runtime child, layered over the daemon's own env. */
|
|
7284
|
+
function buildRuntimeEnv(input) {
|
|
7285
|
+
if (input.runtime !== "claude-code") return {};
|
|
7286
|
+
return {
|
|
7287
|
+
...input.defaultModel ? { ALFE_DEFAULT_MODEL: input.defaultModel } : {},
|
|
7288
|
+
...input.managed ? {
|
|
7289
|
+
ALFE_MANAGED: "1",
|
|
7290
|
+
DISABLE_AUTOUPDATER: "1"
|
|
7291
|
+
} : {}
|
|
7292
|
+
};
|
|
7293
|
+
}
|
|
7294
|
+
/**
|
|
7295
|
+
* True when a config reconcile that wrote `keys` must restart the runtime child.
|
|
7296
|
+
* Only the claude-code host needs it: it reads its credential once per start.
|
|
7297
|
+
* OpenClaw/Hermes hot-reload their state-shaped keys.
|
|
7298
|
+
*/
|
|
7299
|
+
function shouldRestartRuntimeForConfigKeys(runtime, keys) {
|
|
7300
|
+
return runtime === "claude-code" && keys.includes("alfe.claudeCredential.revision");
|
|
7301
|
+
}
|
|
7302
|
+
/**
|
|
7303
|
+
* The `ConfigReconciler.onKeysApplied` hook the daemon installs: restart the
|
|
7304
|
+
* runtime (through the shared, turn-draining restart path) when a reconcile
|
|
7305
|
+
* wrote a new claude-code credential revision. The reconciler value-diffs, so
|
|
7306
|
+
* a reconnect re-sending the same revision does not restart.
|
|
7307
|
+
*/
|
|
7308
|
+
function createCredentialRestartHook(runtime, requestRestart, onRestart) {
|
|
7309
|
+
return (keys) => {
|
|
7310
|
+
if (!shouldRestartRuntimeForConfigKeys(runtime, keys)) return;
|
|
7311
|
+
onRestart?.();
|
|
7312
|
+
requestRestart();
|
|
7313
|
+
};
|
|
7314
|
+
}
|
|
7206
7315
|
//#endregion
|
|
7207
7316
|
//#region src/command-queue.ts
|
|
7208
7317
|
const DEFAULT_TTL_MS$1 = 300 * 1e3;
|
|
@@ -7483,7 +7592,8 @@ function generateLaunchdPlist() {
|
|
|
7483
7592
|
* ~13,570 restarts over 2 days).
|
|
7484
7593
|
*
|
|
7485
7594
|
* The guard:
|
|
7486
|
-
* - checks the CLI is intact: the symlink target (`
|
|
7595
|
+
* - checks the CLI is intact: the symlink target (the package's `bin.alfe`,
|
|
7596
|
+
* `dist/bin.js` today) exists AND
|
|
7487
7597
|
* `alfe --version` exits 0;
|
|
7488
7598
|
* - if broken, reinstalls `@alfe.ai/cli@$ALFE_CLI_VERSION` (the exact version
|
|
7489
7599
|
* baked into the unit's `Environment=`; falls back to `@latest` when
|
|
@@ -7507,7 +7617,7 @@ set -u
|
|
|
7507
7617
|
TARGET='${exactVersion ? `@alfe.ai/cli@${exactVersion}` : "@alfe.ai/cli@latest"}'
|
|
7508
7618
|
log() { echo "[alfe-cli-guard] $*" >&2; }
|
|
7509
7619
|
|
|
7510
|
-
# Resolve the alfe bin and its real target (dist/
|
|
7620
|
+
# Resolve the alfe bin and its real target (dist/bin.js). readlink -f follows
|
|
7511
7621
|
# the whole symlink chain; fall back to the bin path itself if unavailable.
|
|
7512
7622
|
BIN="$(command -v alfe 2>/dev/null || true)"
|
|
7513
7623
|
if [ -n "$BIN" ]; then
|
|
@@ -10250,12 +10360,17 @@ async function startDaemon() {
|
|
|
10250
10360
|
const runtimeGate = new RuntimeGate(() => runtimeProcess);
|
|
10251
10361
|
runtimeGateRef = runtimeGate;
|
|
10252
10362
|
cloudClient.setIntegrationManager(integrationAdapter, runtimeGate);
|
|
10253
|
-
cloudClient.setConfigReconciler(new ConfigReconciler({ getApplier: () => runtimeAppliers.get(config.runtime) }));
|
|
10254
10363
|
const requestRuntimeRestart = () => {
|
|
10255
10364
|
logger.info("Runtime state changed — requesting runtime restart");
|
|
10256
10365
|
runtimeGate.requestRestart();
|
|
10257
10366
|
};
|
|
10258
10367
|
cloudClient.setRuntimeRestartNeededHandler(requestRuntimeRestart);
|
|
10368
|
+
cloudClient.setConfigReconciler(new ConfigReconciler({
|
|
10369
|
+
getApplier: () => runtimeAppliers.get(config.runtime),
|
|
10370
|
+
onKeysApplied: createCredentialRestartHook(config.runtime, requestRuntimeRestart, () => {
|
|
10371
|
+
logger.info({ runtime: config.runtime }, "Claude credential changed — restarting runtime to refetch");
|
|
10372
|
+
})
|
|
10373
|
+
}));
|
|
10259
10374
|
if (config.runtime === "hermes") {
|
|
10260
10375
|
const hermesCfg = config.runtimes[config.runtime];
|
|
10261
10376
|
if (hermesCfg) {
|
|
@@ -10324,7 +10439,11 @@ async function startDaemon() {
|
|
|
10324
10439
|
runtimeProcess = new RuntimeProcess({
|
|
10325
10440
|
runtime: config.runtime,
|
|
10326
10441
|
workspace: runtimeCfg.workspace,
|
|
10327
|
-
env:
|
|
10442
|
+
env: buildRuntimeEnv({
|
|
10443
|
+
runtime: config.runtime,
|
|
10444
|
+
...config.defaultModel ? { defaultModel: config.defaultModel } : {},
|
|
10445
|
+
managed
|
|
10446
|
+
})
|
|
10328
10447
|
});
|
|
10329
10448
|
runtimeProcess.setTurnActivityProbe(turnActivityProbe);
|
|
10330
10449
|
if (firstRuntimeStart) {
|
|
@@ -10542,7 +10661,7 @@ async function executeCloudCommand(command) {
|
|
|
10542
10661
|
pinnedVersion: target.version
|
|
10543
10662
|
}, "runtime.update requested an OpenClaw version above the pin — upgrading to the pin instead");
|
|
10544
10663
|
version = target.version;
|
|
10545
|
-
} else version = payload?.version ?? (runtime === "claude-code" ? "0.1.
|
|
10664
|
+
} else version = payload?.version ?? (runtime === "claude-code" ? "0.1.15" : void 0);
|
|
10546
10665
|
upgradingRuntime = true;
|
|
10547
10666
|
setTimeout(() => {
|
|
10548
10667
|
(async () => {
|
|
@@ -11017,4 +11136,4 @@ function formatDuration(ms) {
|
|
|
11017
11136
|
return `${String(Math.round(seconds / 3600))}h`;
|
|
11018
11137
|
}
|
|
11019
11138
|
//#endregion
|
|
11020
|
-
export { loadDaemonConfig as _, installService as a, startService as c, uninstallService as d, PROTOCOL_VERSION as f, fetchAgentConfig as g, SOCKET_PATH as h, checkExistingDaemon as i, stopExistingDaemon as l, PID_PATH as m, queryDaemonHealth as n, isServiceInstalled as o, ALFE_DIR as p, startDaemon as r, restartService as s, formatHealthReport as t, stopService as u, resolveAgentIdentity as v, PINNED_CLAUDE_CODE_HOST_VERSION as y };
|
|
11139
|
+
export { loadDaemonConfig as _, installService as a, PINNED_CLAUDE_CODE_VERSION as b, startService as c, uninstallService as d, PROTOCOL_VERSION as f, fetchAgentConfig as g, SOCKET_PATH as h, checkExistingDaemon as i, stopExistingDaemon as l, PID_PATH as m, queryDaemonHealth as n, isServiceInstalled as o, ALFE_DIR as p, startDaemon as r, restartService as s, formatHealthReport as t, stopService as u, resolveAgentIdentity as v, PINNED_CLAUDE_CODE_HOST_VERSION as y };
|
package/dist/src/index.d.ts
CHANGED
|
@@ -145,11 +145,23 @@ declare function remediateManagedNode(runCommand: RemediationCommandRunner, base
|
|
|
145
145
|
* new host, then cut a CLI release so the pin travels with the CLI version. The
|
|
146
146
|
* dashboard still surfaces npm-`latest` as an explicit opt-in upgrade.
|
|
147
147
|
*
|
|
148
|
-
* NOTE: claude-code
|
|
148
|
+
* NOTE: managed claude-code agents run on Hetzner VMs provisioned by cloud-init
|
|
149
|
+
* + `alfe setup --managed` (no Docker image), so — unlike
|
|
149
150
|
* `PINNED_OPENCLAW_VERSION` — there is no `services/compute/Dockerfile` mirror to
|
|
150
151
|
* keep in sync.
|
|
151
152
|
*/
|
|
152
|
-
declare const PINNED_CLAUDE_CODE_HOST_VERSION = "0.1.
|
|
153
|
+
declare const PINNED_CLAUDE_CODE_HOST_VERSION = "0.1.15";
|
|
154
|
+
/**
|
|
155
|
+
* The `@anthropic-ai/claude-code` (the `claude` CLI) version Alfe installs for
|
|
156
|
+
* the claude-code runtime: always on managed VMs (`alfe setup --managed`), and
|
|
157
|
+
* on self-hosted machines only when no `claude` is present (a user-installed
|
|
158
|
+
* `claude` is never replaced). Pinned to npm's `stable` dist-tag as of
|
|
159
|
+
* 2026-10-14 — `latest` moves daily and the host drives `claude -p` flags
|
|
160
|
+
* (`--resume`, `--mcp-config`, `--strict-mcp-config`, `--permission-mode`)
|
|
161
|
+
* whose behaviour must be validated before a bump. The pin travels with the
|
|
162
|
+
* CLI release.
|
|
163
|
+
*/
|
|
164
|
+
declare const PINNED_CLAUDE_CODE_VERSION = "2.1.287";
|
|
153
165
|
//#endregion
|
|
154
166
|
//#region src/sentry.d.ts
|
|
155
167
|
/**
|
|
@@ -391,6 +403,13 @@ declare function resolveAgentIdentity(apiKey: string, apiEndpoint: string): Prom
|
|
|
391
403
|
* In managed mode, loads from environment variables instead.
|
|
392
404
|
*/
|
|
393
405
|
declare function loadDaemonConfig(): Promise<DaemonConfig>;
|
|
406
|
+
/**
|
|
407
|
+
* The claude-code agent's bare `defaultModel`, for `ALFE_DEFAULT_MODEL`.
|
|
408
|
+
* Bounded so a slow or hung workspace endpoint can't block daemon startup; any
|
|
409
|
+
* failure or timeout yields `undefined` and the host falls back to the `claude`
|
|
410
|
+
* CLI default. Shared by the managed and self-hosted config loaders.
|
|
411
|
+
*/
|
|
412
|
+
|
|
394
413
|
/**
|
|
395
414
|
* Fetch agent workspace config from the API.
|
|
396
415
|
*
|
|
@@ -495,4 +514,4 @@ declare function checkExistingDaemon(): Promise<number | null>;
|
|
|
495
514
|
*/
|
|
496
515
|
declare function stopExistingDaemon(): Promise<boolean>;
|
|
497
516
|
//#endregion
|
|
498
|
-
export { AGENT_DAEMON_SENTRY_DSN, AGENT_MCP_SENTRY_DSN, AGENT_RUNTIME_SENTRY_DSN, ALFE_DIR, type AgentIdentity, type AgentWorkspaceConfig, type DaemonConfig, type DaemonHealth, type IPCEvent, type IPCRequest, type IPCResponse, type InitAgentSentryOptions, OPENCLAW_MANAGED_NODE_MAJOR, OPENCLAW_NODE_REQUIREMENT, PID_PATH, PINNED_CLAUDE_CODE_HOST_VERSION, PINNED_OPENCLAW_VERSION, PROTOCOL_VERSION, type RemediateManagedNodeOptions, type RemediationCommandRunner, type RuntimeOutputLine, SOCKET_PATH, type SentrySurface, captureCliFailure, captureFatal, captureIntegrationFailure, captureMcpFailure, captureRuntimeCrash, captureRuntimeErrorOutput, checkExistingDaemon, fetchAgentConfig, flushSentry, formatHealthReport, initAgentSentry, installService, isServiceInstalled, loadDaemonConfig, logger, queryDaemonHealth, remediateManagedNode, resolveAgentIdentity, restartService, setAgentContext, startDaemon, startService, stopExistingDaemon, stopService, supportsOpenClawNode, uninstallService };
|
|
517
|
+
export { AGENT_DAEMON_SENTRY_DSN, AGENT_MCP_SENTRY_DSN, AGENT_RUNTIME_SENTRY_DSN, ALFE_DIR, type AgentIdentity, type AgentWorkspaceConfig, type DaemonConfig, type DaemonHealth, type IPCEvent, type IPCRequest, type IPCResponse, type InitAgentSentryOptions, OPENCLAW_MANAGED_NODE_MAJOR, OPENCLAW_NODE_REQUIREMENT, PID_PATH, PINNED_CLAUDE_CODE_HOST_VERSION, PINNED_CLAUDE_CODE_VERSION, PINNED_OPENCLAW_VERSION, PROTOCOL_VERSION, type RemediateManagedNodeOptions, type RemediationCommandRunner, type RuntimeOutputLine, SOCKET_PATH, type SentrySurface, captureCliFailure, captureFatal, captureIntegrationFailure, captureMcpFailure, captureRuntimeCrash, captureRuntimeErrorOutput, checkExistingDaemon, fetchAgentConfig, flushSentry, formatHealthReport, initAgentSentry, installService, isServiceInstalled, loadDaemonConfig, logger, queryDaemonHealth, remediateManagedNode, resolveAgentIdentity, restartService, setAgentContext, startDaemon, startService, stopExistingDaemon, stopService, supportsOpenClawNode, uninstallService };
|
package/dist/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { b as PINNED_OPENCLAW_VERSION, v as OPENCLAW_MANAGED_NODE_MAJOR, w as supportsOpenClawNode, y as OPENCLAW_NODE_REQUIREMENT } from "../runtime-upgrade-recovery.js";
|
|
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";
|
|
2
|
+
import { _ as loadDaemonConfig, a as installService, b as PINNED_CLAUDE_CODE_VERSION, 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";
|
|
5
|
-
export { AGENT_DAEMON_SENTRY_DSN, AGENT_MCP_SENTRY_DSN, AGENT_RUNTIME_SENTRY_DSN, ALFE_DIR, OPENCLAW_MANAGED_NODE_MAJOR, OPENCLAW_NODE_REQUIREMENT, PID_PATH, PINNED_CLAUDE_CODE_HOST_VERSION, PINNED_OPENCLAW_VERSION, PROTOCOL_VERSION, SOCKET_PATH, captureCliFailure, captureFatal, captureIntegrationFailure, captureMcpFailure, captureRuntimeCrash, captureRuntimeErrorOutput, checkExistingDaemon, fetchAgentConfig, flushSentry, formatHealthReport, initAgentSentry, installService, isServiceInstalled, loadDaemonConfig, logger, queryDaemonHealth, remediateManagedNode, resolveAgentIdentity, restartService, setAgentContext, startDaemon, startService, stopExistingDaemon, stopService, supportsOpenClawNode, uninstallService };
|
|
5
|
+
export { AGENT_DAEMON_SENTRY_DSN, AGENT_MCP_SENTRY_DSN, AGENT_RUNTIME_SENTRY_DSN, ALFE_DIR, OPENCLAW_MANAGED_NODE_MAJOR, OPENCLAW_NODE_REQUIREMENT, PID_PATH, PINNED_CLAUDE_CODE_HOST_VERSION, PINNED_CLAUDE_CODE_VERSION, PINNED_OPENCLAW_VERSION, PROTOCOL_VERSION, SOCKET_PATH, captureCliFailure, captureFatal, captureIntegrationFailure, captureMcpFailure, captureRuntimeCrash, captureRuntimeErrorOutput, checkExistingDaemon, fetchAgentConfig, flushSentry, formatHealthReport, initAgentSentry, installService, isServiceInstalled, loadDaemonConfig, logger, queryDaemonHealth, remediateManagedNode, resolveAgentIdentity, restartService, setAgentContext, startDaemon, startService, stopExistingDaemon, stopService, supportsOpenClawNode, uninstallService };
|
package/dist/upgrade.js
CHANGED
|
@@ -21,8 +21,8 @@ import { promisify } from "node:util";
|
|
|
21
21
|
* broken) `alfe` binary. Keep the two in lockstep.
|
|
22
22
|
*
|
|
23
23
|
* The two checks:
|
|
24
|
-
* - the resolved CLI entry (`.../dist/
|
|
25
|
-
* `alfe` bin) exists on disk; and
|
|
24
|
+
* - the resolved CLI entry (the package's `bin.alfe`, `.../dist/bin.js`
|
|
25
|
+
* today, i.e. the symlink target of the `alfe` bin) exists on disk; and
|
|
26
26
|
* - running it (`node <entry> --version`, or `alfe --version`) exits 0 and
|
|
27
27
|
* prints the expected version.
|
|
28
28
|
*
|
|
@@ -61,7 +61,7 @@ function decideCliInstallOk(probe, expectedVersion) {
|
|
|
61
61
|
/**
|
|
62
62
|
* Resolve the CLI entry file this daemon is running from. When the gateway is
|
|
63
63
|
* loaded as a dependency of the globally-installed CLI the layout is
|
|
64
|
-
* `.../@alfe.ai/cli/dist/
|
|
64
|
+
* `.../@alfe.ai/cli/dist/bin.js` with `.../@alfe.ai/gateway/dist/...`
|
|
65
65
|
* alongside — walk up to the sibling `@alfe.ai/cli/package.json` and derive its
|
|
66
66
|
* `bin.alfe` / main entry. Returns undefined when it can't be resolved (e.g.
|
|
67
67
|
* `alfe gateway daemon` run from a dev checkout); the caller then skips the
|
|
@@ -106,7 +106,7 @@ async function tryVersion(cmd, args) {
|
|
|
106
106
|
* Probe + decide whether the on-disk global CLI install is intact.
|
|
107
107
|
*
|
|
108
108
|
* @param expectedVersion when set, the reported version must match exactly.
|
|
109
|
-
* @param entryPath the resolved `.../dist/
|
|
109
|
+
* @param entryPath the resolved `bin.alfe` entry, `.../dist/bin.js` (from
|
|
110
110
|
* `resolveCliEntryPath`). When provided and missing,
|
|
111
111
|
* the check fails fast. Also used to run the CLI
|
|
112
112
|
* directly via `node <entry> --version`, which is more
|
|
@@ -174,7 +174,7 @@ function findOrphanReifyTempDirs(siblings, packageBasename) {
|
|
|
174
174
|
* Detection order (robust — never hardcode `/usr/lib`):
|
|
175
175
|
* 1. `npm root -g` → the global `node_modules` root. Authoritative on the box.
|
|
176
176
|
* 2. Derive from the resolved CLI entry path (`.../node_modules/@alfe.ai/cli/
|
|
177
|
-
* dist/
|
|
177
|
+
* dist/bin.js`) by walking up to the `node_modules` segment.
|
|
178
178
|
*
|
|
179
179
|
* Returns undefined when neither resolves (dev checkout / non-global run); the
|
|
180
180
|
* caller then skips the sweep (there is no global install to clean).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/gateway",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Alfe local gateway daemon — persistent control plane for agent integrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"pino-roll": "^1.2.0",
|
|
24
24
|
"smol-toml": ">=1.6.1",
|
|
25
25
|
"ws": "^8.18.0",
|
|
26
|
-
"@alfe.ai/agent-api-client": "^0.
|
|
26
|
+
"@alfe.ai/agent-api-client": "^0.21.0",
|
|
27
27
|
"@alfe.ai/ai-proxy-local": "^0.0.17",
|
|
28
|
-
"@alfe.ai/config": "^0.4.
|
|
29
|
-
"@alfe.ai/integration-manifest": "^0.
|
|
30
|
-
"@alfe.ai/integrations": "^0.
|
|
28
|
+
"@alfe.ai/config": "^0.4.2",
|
|
29
|
+
"@alfe.ai/integration-manifest": "^0.5.0",
|
|
30
|
+
"@alfe.ai/integrations": "^0.7.0",
|
|
31
31
|
"@alfe.ai/mcp-bundler": "^0.4.3"
|
|
32
32
|
},
|
|
33
33
|
"license": "UNLICENSED",
|