





















@@ -21,7 +21,11 @@ import { GATEWAY_SERVICE_RUNTIME_PID_ENV } from "../daemon/constants.js";
2121import { resolveGatewayInstallEntrypoint } from "../daemon/gateway-entrypoint.js";
2222import { runCommandWithTimeout } from "../process/exec.js";
2323import { resolveStableNodePath } from "./stable-node-path.js";
24-import type { UpdateChannel } from "./update-channels.js";
24+import {
25+DEFAULT_GIT_CHANNEL,
26+type UpdateChannel,
27+UPDATE_EFFECTIVE_CHANNEL_ENV,
28+} from "./update-channels.js";
2529import type { UpdateRunResult } from "./update-runner.js";
26302731// Whole-process backstop for the finalizer. `update finalize` runs several timed
@@ -36,14 +40,20 @@ const FINALIZE_PROCESS_STEP_BUDGET_MULTIPLIER = 6;
36403741// Strip the running gateway's service identity from the finalizer child so it is
3842// not mistaken for the managed service process (matches the CLI post-core spawn).
43+// Also carry the effective update channel so convergence runs on the channel the
44+// core update actually used (git/dev for an unconfigured source update) — passed
45+// as the *effective* channel, never a *requested* one, so `update finalize` does
46+// not persist `update.channel`.
3947function buildFinalizeEnv(
4048baseEnv: NodeJS.ProcessEnv,
49+effectiveChannel: UpdateChannel,
4150compatHostVersion?: string,
4251): NodeJS.ProcessEnv {
4352const env: NodeJS.ProcessEnv = { ...baseEnv };
4453delete env.OPENCLAW_SERVICE_MARKER;
4554delete env.OPENCLAW_SERVICE_KIND;
4655delete env[GATEWAY_SERVICE_RUNTIME_PID_ENV];
56+env[UPDATE_EFFECTIVE_CHANNEL_ENV] = effectiveChannel;
4757if (compatHostVersion) {
4858env.OPENCLAW_COMPATIBILITY_HOST_VERSION = compatHostVersion;
4959}
@@ -113,9 +123,10 @@ function isGitUpdateNeedingFinalize(
113123function buildFinalizeArgv(params: {
114124nodePath: string;
115125entrypoint: string;
116-channel?: UpdateChannel;
117126timeoutMs?: number;
118127}): string[] {
128+// No `--channel`: the effective channel is passed via env (convergence-only,
129+// not persisted). `update finalize` would persist any `--channel` it sees.
119130const argv = [
120131params.nodePath,
121132params.entrypoint,
@@ -125,9 +136,6 @@ function buildFinalizeArgv(params: {
125136"--yes",
126137"--no-restart",
127138];
128-if (params.channel) {
129-argv.push("--channel", params.channel);
130-}
131139if (typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs)) {
132140// `update finalize --timeout` is per-step seconds.
133141argv.push("--timeout", String(Math.max(1, Math.ceil(params.timeoutMs / 1000))));
@@ -158,23 +166,23 @@ export async function runPostCoreFinalizeAfterGatewayUpdate(params: {
158166typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs)
159167 ? params.timeoutMs
160168 : undefined;
161-// Only forward `--channel` when the caller actually has a configured channel.
162-// `update finalize` treats any `--channel` as an explicit request and persists
163-// it to `openclaw.json` (`persistRequestedUpdateChannel`); emitting a defaulted
164-// channel here would write a channel the user never requested. When omitted,
165-// the finalizer converges on the stored/default channel — the reconcile still
166-// resolves a host-compatible version, it just does not mutate config.
169+// This helper only runs for git/source updates, where `runGatewayUpdate` ran
170+// the core update on `configChannel ?? DEFAULT_GIT_CHANNEL` (dev). Carry that
171+// same effective channel into the finalizer so plugin convergence matches the
172+// core update instead of falling back to the package (stable) channel. It is
173+// passed via env as the *effective* (not requested) channel, so the finalizer
174+// does not persist `update.channel` when the user never configured one.
175+const effectiveChannel: UpdateChannel = params.channel ?? DEFAULT_GIT_CHANNEL;
167176const nodePath = await resolveStableNodePath(process.execPath);
168177const argv = buildFinalizeArgv({
169178 nodePath,
170179 entrypoint,
171- ...(params.channel ? { channel: params.channel } : {}),
172180 ...(perStepTimeoutMs === undefined ? {} : { timeoutMs: perStepTimeoutMs }),
173181});
174182// Pin the finalizer's host-compat resolution to the just-installed core
175183// version so plugins reconcile against the new core, not the running process.
176184const compatHostVersion = result.after?.version ?? undefined;
177-const env = buildFinalizeEnv(params.env ?? process.env, compatHostVersion);
185+const env = buildFinalizeEnv(params.env ?? process.env, effectiveChannel, compatHostVersion);
178186// Outer whole-process backstop, decoupled from the per-step `--timeout` above.
179187const processTimeoutMs = Math.max(
180188FINALIZE_PROCESS_TIMEOUT_FLOOR_MS,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。