Skip to content

Commit ae29842

Browse files
Gateway: fix stale self version in status output (openclaw#32655)
Merged via squash. Prepared head SHA: b9675d1 Co-authored-by: liuxiaopai-ai <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
1 parent b1b41eb commit ae29842

File tree

7 files changed

+48
-17
lines changed

7 files changed

+48
-17
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
1212
### Fixes
1313

1414
- Agents/Compaction continuity: expand staged-summary merge instructions to preserve active task status, batch progress, latest user request, and follow-up commitments so compaction handoffs retain in-flight work context. (#8903) thanks @joetomasone.
15+
- Gateway/status self version reporting: make Gateway self version in `openclaw status` prefer runtime `VERSION` (while preserving explicit `OPENCLAW_VERSION` override), preventing stale post-upgrade app version output. (#32655) thanks @liuxiaopai-ai.
1516
- Memory/QMD index isolation: set `QMD_CONFIG_DIR` alongside `XDG_CONFIG_HOME` so QMD config state stays per-agent despite upstream XDG handling bugs, preventing cross-agent collection indexing and excess disk/CPU usage. (#27028) thanks @HenryLoenwind.
1617
- LINE/auth boundary hardening synthesis: enforce strict LINE webhook authn/z boundary semantics across pairing-store account scoping, DM/group allowlist separation, fail-closed webhook auth/runtime behavior, and replay/duplication controls (including in-flight replay reservation and post-success dedupe marking). (from #26701, #26683, #25978, #17593, #16619, #31990, #26047, #30584, #18777) Thanks @bmendonca3, @davidahmann, @harshang03, @haosenwang1018, @liuxiaopai-ai, @coygeek, and @Takhoffman.
1718
- LINE/media download synthesis: fix file-media download handling and M4A audio classification across overlapping LINE regressions. (from #26386, #27761, #27787, #29509, #29755, #29776, #29785, #32240) Thanks @kevinWangSheng, @loiie45e, @carrotRakko, @Sid-Qin, @codeafridi, and @bmendonca3.

src/gateway/server.auth.default-token.suite.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,16 @@ export function registerDefaultAuthTokenSuite(): void {
112112
ws.close();
113113
});
114114

115-
test("connect (req) handshake resolves server version from env precedence", async () => {
115+
test("connect (req) handshake resolves server version from runtime precedence", async () => {
116+
const { VERSION } = await import("../version.js");
116117
for (const testCase of [
117118
{
118119
env: {
119120
OPENCLAW_VERSION: " ",
120121
OPENCLAW_SERVICE_VERSION: "2.4.6-service",
121122
npm_package_version: "1.0.0-package",
122123
},
123-
expectedVersion: "2.4.6-service",
124+
expectedVersion: VERSION,
124125
},
125126
{
126127
env: {
@@ -136,7 +137,7 @@ export function registerDefaultAuthTokenSuite(): void {
136137
OPENCLAW_SERVICE_VERSION: "\t",
137138
npm_package_version: "1.0.0-package",
138139
},
139-
expectedVersion: "1.0.0-package",
140+
expectedVersion: VERSION,
140141
},
141142
]) {
142143
await withRuntimeVersionEnv(testCase.env, async () =>

src/gateway/server/ws-connection/message-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@ export function attachGatewayWsMessageHandler(params: {
10321032
type: "hello-ok",
10331033
protocol: PROTOCOL_VERSION,
10341034
server: {
1035-
version: resolveRuntimeServiceVersion(process.env, "dev"),
1035+
version: resolveRuntimeServiceVersion(process.env),
10361036
connId,
10371037
},
10381038
features: { methods: gatewayMethods, events },

src/infra/system-presence.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function resolvePrimaryIPv4(): string | undefined {
5151
function initSelfPresence() {
5252
const host = os.hostname();
5353
const ip = resolvePrimaryIPv4() ?? undefined;
54-
const version = resolveRuntimeServiceVersion(process.env, "unknown");
54+
const version = resolveRuntimeServiceVersion(process.env);
5555
const modelIdentifier = (() => {
5656
const p = os.platform();
5757
if (p === "darwin") {

src/infra/system-presence.version.test.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,21 @@ async function withPresenceModule<T>(
1313
}
1414

1515
describe("system-presence version fallback", () => {
16-
it("uses OPENCLAW_SERVICE_VERSION when OPENCLAW_VERSION is not set", async () => {
16+
it("uses runtime VERSION when OPENCLAW_VERSION is not set", async () => {
1717
await withPresenceModule(
1818
{
1919
OPENCLAW_SERVICE_VERSION: "2.4.6-service",
2020
npm_package_version: "1.0.0-package",
2121
},
22-
({ listSystemPresence }) => {
22+
async ({ listSystemPresence }) => {
23+
const { VERSION } = await import("../version.js");
2324
const selfEntry = listSystemPresence().find((entry) => entry.reason === "self");
24-
expect(selfEntry?.version).toBe("2.4.6-service");
25+
expect(selfEntry?.version).toBe(VERSION);
2526
},
2627
);
2728
});
2829

29-
it("prefers OPENCLAW_VERSION over OPENCLAW_SERVICE_VERSION", async () => {
30+
it("prefers OPENCLAW_VERSION over runtime VERSION", async () => {
3031
await withPresenceModule(
3132
{
3233
OPENCLAW_VERSION: "9.9.9-cli",
@@ -40,16 +41,17 @@ describe("system-presence version fallback", () => {
4041
);
4142
});
4243

43-
it("uses npm_package_version when OPENCLAW_VERSION and OPENCLAW_SERVICE_VERSION are blank", async () => {
44+
it("uses runtime VERSION when OPENCLAW_VERSION and OPENCLAW_SERVICE_VERSION are blank", async () => {
4445
await withPresenceModule(
4546
{
4647
OPENCLAW_VERSION: " ",
4748
OPENCLAW_SERVICE_VERSION: "\t",
4849
npm_package_version: "1.0.0-package",
4950
},
50-
({ listSystemPresence }) => {
51+
async ({ listSystemPresence }) => {
52+
const { VERSION } = await import("../version.js");
5153
const selfEntry = listSystemPresence().find((entry) => entry.reason === "self");
52-
expect(selfEntry?.version).toBe("1.0.0-package");
54+
expect(selfEntry?.version).toBe(VERSION);
5355
},
5456
);
5557
});

src/version.test.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import path from "node:path";
44
import { pathToFileURL } from "node:url";
55
import { describe, expect, it } from "vitest";
66
import {
7+
VERSION,
78
readVersionFromBuildInfoForModuleUrl,
89
readVersionFromPackageJsonForModuleUrl,
910
resolveBinaryVersion,
1011
resolveRuntimeServiceVersion,
12+
resolveUsableRuntimeVersion,
1113
resolveVersionFromModuleUrl,
1214
} from "./version.js";
1315

@@ -141,22 +143,32 @@ describe("version resolution", () => {
141143
).toBe("9.9.9");
142144
});
143145

144-
it("uses service and package fallbacks and ignores blank env values", () => {
146+
it("normalizes runtime version candidate for fallback handling", () => {
147+
expect(resolveUsableRuntimeVersion(undefined)).toBeUndefined();
148+
expect(resolveUsableRuntimeVersion("")).toBeUndefined();
149+
expect(resolveUsableRuntimeVersion(" \t ")).toBeUndefined();
150+
expect(resolveUsableRuntimeVersion("0.0.0")).toBeUndefined();
151+
expect(resolveUsableRuntimeVersion(" 0.0.0 ")).toBeUndefined();
152+
expect(resolveUsableRuntimeVersion("2026.3.2")).toBe("2026.3.2");
153+
expect(resolveUsableRuntimeVersion(" 2026.3.2 ")).toBe("2026.3.2");
154+
});
155+
156+
it("prefers runtime VERSION over service/package markers and ignores blank env values", () => {
145157
expect(
146158
resolveRuntimeServiceVersion({
147159
OPENCLAW_VERSION: " ",
148160
OPENCLAW_SERVICE_VERSION: " 2.0.0 ",
149161
npm_package_version: "1.0.0",
150162
}),
151-
).toBe("2.0.0");
163+
).toBe(VERSION);
152164

153165
expect(
154166
resolveRuntimeServiceVersion({
155167
OPENCLAW_VERSION: " ",
156168
OPENCLAW_SERVICE_VERSION: "\t",
157169
npm_package_version: " 1.0.0-package ",
158170
}),
159-
).toBe("1.0.0-package");
171+
).toBe(VERSION);
160172

161173
expect(
162174
resolveRuntimeServiceVersion(
@@ -167,6 +179,6 @@ describe("version resolution", () => {
167179
},
168180
"fallback",
169181
),
170-
).toBe("fallback");
182+
).toBe(VERSION);
171183
});
172184
});

src/version.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,28 @@ export type RuntimeVersionEnv = {
9090
[key: string]: string | undefined;
9191
};
9292

93+
export const RUNTIME_SERVICE_VERSION_FALLBACK = "unknown";
94+
95+
export function resolveUsableRuntimeVersion(version: string | undefined): string | undefined {
96+
const trimmed = version?.trim();
97+
// "0.0.0" is the resolver's hard fallback when module metadata cannot be read.
98+
// Prefer explicit service/package markers in that edge case.
99+
if (!trimmed || trimmed === "0.0.0") {
100+
return undefined;
101+
}
102+
return trimmed;
103+
}
104+
93105
export function resolveRuntimeServiceVersion(
94106
env: RuntimeVersionEnv = process.env as RuntimeVersionEnv,
95-
fallback = "dev",
107+
fallback = RUNTIME_SERVICE_VERSION_FALLBACK,
96108
): string {
109+
const runtimeVersion = resolveUsableRuntimeVersion(VERSION);
110+
97111
return (
98112
firstNonEmpty(
99113
env["OPENCLAW_VERSION"],
114+
runtimeVersion,
100115
env["OPENCLAW_SERVICE_VERSION"],
101116
env["npm_package_version"],
102117
) ?? fallback

0 commit comments

Comments
 (0)