mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(cli): suppress self-update version warnings
This commit is contained in:
@@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
- WebChat: keep message-tool replies visible in the chat while still summarizing internal tool results for the model. Fixes #86347. Thanks @shakkernerd.
|
||||
- Agents/commitments: serialize commitment store load-modify-save writes so concurrent heartbeat and CLI updates no longer lose dismissal, sent, or attempt state. (#81153) Thanks @ai-hpc.
|
||||
- CLI: suppress benign self-update version-skew warnings during package post-update finalization.
|
||||
- Gateway/perf: tighten restart and startup benchmark failure handling so long profiling runs, failed probes, and fresh Linux runners no longer produce false passing or `n/a` results.
|
||||
- Checks: keep intentional Knip unused-file findings optional so full CI and sparse proof workspaces stay aligned.
|
||||
- Docker: restore writable `~/.config` in runtime images. Fixes #85968. Thanks @hkoessler and @Bartok9.
|
||||
|
||||
@@ -13,6 +13,7 @@ UPDATE_BASELINE_VERSION="${OPENCLAW_INSTALL_UPDATE_BASELINE:-latest}"
|
||||
UPDATE_BASELINE_TAG_URL="${OPENCLAW_INSTALL_UPDATE_BASELINE_TAG_URL:-}"
|
||||
UPDATE_EXPECT_VERSION="${OPENCLAW_INSTALL_UPDATE_EXPECT_VERSION:-}"
|
||||
UPDATE_TAG_URL="${OPENCLAW_INSTALL_UPDATE_TAG_URL:-}"
|
||||
SELF_UPDATE_WARNING_FIXED_VERSION="${OPENCLAW_INSTALL_SELF_UPDATE_WARNING_FIXED_VERSION:-2026.5.25}"
|
||||
FRESHNESS_VERSION="${OPENCLAW_INSTALL_FRESHNESS_VERSION:-latest}"
|
||||
# npm min-release-age is days; 10000 keeps the control failure independent of normal release cadence.
|
||||
FRESHNESS_MIN_RELEASE_AGE="${OPENCLAW_INSTALL_FRESHNESS_MIN_RELEASE_AGE:-10000}"
|
||||
@@ -120,6 +121,75 @@ is_self_swapped_package_process_exit() {
|
||||
[[ "$stderr" == *"/node_modules/openclaw/dist/"* ]]
|
||||
}
|
||||
|
||||
is_version_before() {
|
||||
local candidate="$1"
|
||||
local floor="$2"
|
||||
node - "$candidate" "$floor" <<'NODE'
|
||||
const [, , candidate, floor] = process.argv;
|
||||
function parse(version) {
|
||||
const [core, prerelease = ""] = String(version).split("-", 2);
|
||||
return {
|
||||
core: core.split(".").map((part) => Number.parseInt(part, 10) || 0),
|
||||
prerelease: prerelease ? prerelease.split(".") : [],
|
||||
};
|
||||
}
|
||||
function comparePrerelease(left, right) {
|
||||
if (left.length === 0 && right.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (left.length === 0) {
|
||||
return 1;
|
||||
}
|
||||
if (right.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
|
||||
const l = left[index];
|
||||
const r = right[index];
|
||||
if (l === undefined) {
|
||||
return -1;
|
||||
}
|
||||
if (r === undefined) {
|
||||
return 1;
|
||||
}
|
||||
const ln = Number.parseInt(l, 10);
|
||||
const rn = Number.parseInt(r, 10);
|
||||
const lNumeric = String(ln) === l;
|
||||
const rNumeric = String(rn) === r;
|
||||
if (lNumeric && rNumeric && ln !== rn) {
|
||||
return ln < rn ? -1 : 1;
|
||||
}
|
||||
if (lNumeric !== rNumeric) {
|
||||
return lNumeric ? -1 : 1;
|
||||
}
|
||||
if (l !== r) {
|
||||
return l < r ? -1 : 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const left = parse(candidate);
|
||||
const right = parse(floor);
|
||||
for (let index = 0; index < Math.max(left.core.length, right.core.length); index += 1) {
|
||||
const l = left.core[index] ?? 0;
|
||||
const r = right.core[index] ?? 0;
|
||||
if (l < r) {
|
||||
process.exit(0);
|
||||
}
|
||||
if (l > r) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
const prereleaseOrder = comparePrerelease(left.prerelease, right.prerelease);
|
||||
process.exit(prereleaseOrder < 0 ? 0 : 1);
|
||||
NODE
|
||||
}
|
||||
|
||||
allow_legacy_update_warning() {
|
||||
[[ "${OPENCLAW_INSTALL_ALLOW_LEGACY_UPDATE_WARNING:-0}" == "1" ]] && return 0
|
||||
is_version_before "$UPDATE_BASELINE_VERSION" "$SELF_UPDATE_WARNING_FIXED_VERSION"
|
||||
}
|
||||
|
||||
npm_install_global() {
|
||||
local label="$1"
|
||||
shift
|
||||
@@ -268,11 +338,20 @@ run_update_smoke() {
|
||||
local update_status
|
||||
local update_stderr_file
|
||||
local update_stderr
|
||||
local update_env=(
|
||||
env
|
||||
npm_config_omit=optional
|
||||
NPM_CONFIG_OMIT=optional
|
||||
OPENCLAW_ALLOW_ROOT=1
|
||||
)
|
||||
if allow_legacy_update_warning; then
|
||||
update_env+=(OPENCLAW_UPDATE_IN_PROGRESS=1)
|
||||
fi
|
||||
update_stderr_file="$(mktemp)"
|
||||
set +e
|
||||
UPDATE_JSON="$(
|
||||
run_with_heartbeat "openclaw update" \
|
||||
env npm_config_omit=optional NPM_CONFIG_OMIT=optional OPENCLAW_ALLOW_ROOT=1 \
|
||||
"${update_env[@]}" \
|
||||
openclaw update --tag "$UPDATE_TAG_URL" --yes --json 2>"$update_stderr_file"
|
||||
)"
|
||||
update_status=$?
|
||||
@@ -283,6 +362,12 @@ run_update_smoke() {
|
||||
if [[ -n "$update_stderr" ]]; then
|
||||
printf "%s\n" "$update_stderr" >&2
|
||||
fi
|
||||
if [[ "$update_stderr" == *"config was written by version"* ]] && allow_legacy_update_warning; then
|
||||
echo "WARN: legacy baseline emitted a self-update version-skew warning; fixed baselines must not" >&2
|
||||
elif [[ "$update_stderr" == *"config was written by version"* ]]; then
|
||||
echo "ERROR: openclaw update emitted a self-update version-skew warning" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ "$update_status" -ne 0 ]]; then
|
||||
if is_self_swapped_package_process_exit "$update_stderr"; then
|
||||
echo "WARN: legacy updater process exited after self-swap; validating update JSON and installed CLI" >&2
|
||||
|
||||
@@ -893,6 +893,7 @@ describe("update-cli", () => {
|
||||
expect(call?.[1]).toEqual([entrypoints[0], "update", "--yes", "--timeout", "1800"]);
|
||||
expect(call?.[2]?.stdio).toBe("inherit");
|
||||
expect(call?.[2]?.env?.NODE_DISABLE_COMPILE_CACHE).toBe("1");
|
||||
expect(call?.[2]?.env?.OPENCLAW_UPDATE_IN_PROGRESS).toBe("1");
|
||||
expect(call?.[2]?.env?.OPENCLAW_UPDATE_POST_CORE).toBe("1");
|
||||
expect(call?.[2]?.env?.OPENCLAW_UPDATE_POST_CORE_CHANNEL).toBe("dev");
|
||||
expect(call?.[2]?.env?.OPENCLAW_COMPATIBILITY_HOST_VERSION).toBe("1.0.0");
|
||||
@@ -5230,6 +5231,21 @@ describe("update-cli", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("marks the whole update command as update-in-progress", async () => {
|
||||
await withEnvAsync({ OPENCLAW_UPDATE_IN_PROGRESS: undefined }, async () => {
|
||||
let observedUpdateEnv: string | undefined;
|
||||
vi.mocked(runGatewayUpdate).mockImplementationOnce(async () => {
|
||||
observedUpdateEnv = process.env.OPENCLAW_UPDATE_IN_PROGRESS;
|
||||
return makeOkUpdateResult();
|
||||
});
|
||||
|
||||
await updateCommand({ restart: false });
|
||||
|
||||
expect(observedUpdateEnv).toBe("1");
|
||||
expect(process.env.OPENCLAW_UPDATE_IN_PROGRESS).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("updateFinalizeCommand runs doctor and plugin convergence with full update env", async () => {
|
||||
await withEnvAsync(
|
||||
{
|
||||
|
||||
@@ -2750,6 +2750,7 @@ async function continuePostCoreUpdateInFreshProcess(params: {
|
||||
stdio: childStdio,
|
||||
env: {
|
||||
...stripGatewayServiceMarkerEnv(disableUpdatedPackageCompileCacheEnv(process.env)),
|
||||
OPENCLAW_UPDATE_IN_PROGRESS: "1",
|
||||
[POST_CORE_UPDATE_ENV]: "1",
|
||||
[POST_CORE_UPDATE_CHANNEL_ENV]: params.channel,
|
||||
...(params.requestedChannel
|
||||
@@ -2906,7 +2907,25 @@ async function markControlPlaneUpdateRestartSentinelFailureBestEffort(params: {
|
||||
}
|
||||
}
|
||||
|
||||
async function withUpdateInProgressEnv<T>(run: () => Promise<T>): Promise<T> {
|
||||
const previousUpdateInProgress = process.env.OPENCLAW_UPDATE_IN_PROGRESS;
|
||||
process.env.OPENCLAW_UPDATE_IN_PROGRESS = "1";
|
||||
return run().finally(() => {
|
||||
if (previousUpdateInProgress === undefined) {
|
||||
delete process.env.OPENCLAW_UPDATE_IN_PROGRESS;
|
||||
} else {
|
||||
process.env.OPENCLAW_UPDATE_IN_PROGRESS = previousUpdateInProgress;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
|
||||
return await withUpdateInProgressEnv(async () => {
|
||||
await updateCommandInternal(opts);
|
||||
});
|
||||
}
|
||||
|
||||
async function updateCommandInternal(opts: UpdateCommandOptions): Promise<void> {
|
||||
suppressDeprecations();
|
||||
await cleanupStaleManagedServiceUpdateHandoffs().catch(() => undefined);
|
||||
const invocationCwd = tryResolveInvocationCwd();
|
||||
|
||||
Reference in New Issue
Block a user