





















@@ -17,6 +17,7 @@
1717// and `runPostCorePluginConvergence`). Finalization never restarts, so the RPC
1818// handler keeps ownership of the gateway restart.
1919import path from "node:path";
20+import { GATEWAY_SERVICE_RUNTIME_PID_ENV } from "../daemon/constants.js";
2021import { resolveGatewayInstallEntrypoint } from "../daemon/gateway-entrypoint.js";
2122import { runCommandWithTimeout } from "../process/exec.js";
2223import { resolveStableNodePath } from "./stable-node-path.js";
@@ -25,6 +26,22 @@ import type { UpdateRunResult } from "./update-runner.js";
25262627const DEFAULT_FINALIZE_TIMEOUT_MS = 30 * 60_000;
272829+// Strip the running gateway's service identity from the finalizer child so it is
30+// not mistaken for the managed service process (matches the CLI post-core spawn).
31+function buildFinalizeEnv(
32+baseEnv: NodeJS.ProcessEnv,
33+compatHostVersion?: string,
34+): NodeJS.ProcessEnv {
35+const env: NodeJS.ProcessEnv = { ...baseEnv };
36+delete env.OPENCLAW_SERVICE_MARKER;
37+delete env.OPENCLAW_SERVICE_KIND;
38+delete env[GATEWAY_SERVICE_RUNTIME_PID_ENV];
39+if (compatHostVersion) {
40+env.OPENCLAW_COMPATIBILITY_HOST_VERSION = compatHostVersion;
41+}
42+return env;
43+}
44+2845export type PostCoreFinalizeOutcome =
2946| { status: "skipped"; reason: "not-git-update" | "entrypoint-missing" }
3047| { status: "ok"; entrypoint: string }
@@ -50,6 +67,25 @@ const defaultFinalizeSpawner: PostCoreFinalizeSpawner = async ({ argv, cwd, time
5067return { code: res.code, ...(res.stderr ? { stderr: res.stderr } : {}) };
5168};
526970+function normalizeOptionalString(value: string | null | undefined): string | undefined {
71+const trimmed = value?.trim();
72+return trimmed ? trimmed : undefined;
73+}
74+75+// A no-op git update (same SHA and version) has nothing new to converge against,
76+// so skip finalize to avoid an unnecessary doctor/convergence run. Mirrors the
77+// CLI's `shouldResumePostCoreUpdateInFreshProcess` git resume gate.
78+function gitCoreChanged(result: UpdateRunResult): boolean {
79+const beforeSha = normalizeOptionalString(result.before?.sha);
80+const afterSha = normalizeOptionalString(result.after?.sha);
81+if (beforeSha && afterSha && beforeSha !== afterSha) {
82+return true;
83+}
84+const beforeVersion = normalizeOptionalString(result.before?.version);
85+const afterVersion = normalizeOptionalString(result.after?.version);
86+return Boolean(beforeVersion && afterVersion && beforeVersion !== afterVersion);
87+}
88+5389// Only git/source updates routed through `runGatewayUpdate` defer-and-drop
5490// plugin convergence. Package-manager/global installs already converge because
5591// the RPC routes them through `startManagedServiceUpdateHandoff`, which
@@ -61,7 +97,8 @@ function isGitUpdateNeedingFinalize(
6197result.status === "ok" &&
6298result.mode === "git" &&
6399typeof result.root === "string" &&
64-result.root.length > 0
100+result.root.length > 0 &&
101+gitCoreChanged(result)
65102);
66103}
67104@@ -123,10 +160,7 @@ export async function runPostCoreFinalizeAfterGatewayUpdate(params: {
123160// Pin the finalizer's host-compat resolution to the just-installed core
124161// version so plugins reconcile against the new core, not the running process.
125162const compatHostVersion = result.after?.version ?? undefined;
126-const baseEnv = params.env ?? process.env;
127-const env: NodeJS.ProcessEnv = compatHostVersion
128- ? { ...baseEnv, OPENCLAW_COMPATIBILITY_HOST_VERSION: compatHostVersion }
129- : { ...baseEnv };
163+const env = buildFinalizeEnv(params.env ?? process.env, compatHostVersion);
130164131165try {
132166const spawnResult = await spawnFinalize({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。