fix(config): preserve existing nested state dir before short-circuiting

When OPENCLAW_HOME basename matches a known state dir name, the
nesting guard in resolveStateDir now checks whether a nested .openclaw
subdirectory already exists before returning the parent. This preserves
backward compatibility for installs that previously wrote state data
into the (now-prevented) nested path.

Mirrors the same fix already applied to resolveConfigDir in utils.ts.
This commit is contained in:
Jerry-Xin 2026-03-15 00:05:33 +08:00
parent 14fb5801c5
commit d1b488c5a1
2 changed files with 20 additions and 1 deletions

View File

@ -1,6 +1,7 @@
import fs from "node:fs/promises";
import fsSync from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import { withTempDir } from "../test-helpers/temp-dir.js";
import {
resolveDefaultConfigCandidates,
@ -172,4 +173,12 @@ describe("resolveStateDir nesting guard (#45765)", () => {
const env = { HOME: "/home/user" } as NodeJS.ProcessEnv;
expect(resolveStateDir(env)).toBe(path.resolve("/home/user/.openclaw"));
});
it("preserves existing nested state dir for backward compat", () => {
const env = { OPENCLAW_HOME: "/home/user/.openclaw" } as NodeJS.ProcessEnv;
const nestedDir = path.resolve("/home/user/.openclaw/.openclaw");
vi.spyOn(fsSync, "existsSync").mockImplementation((p) => String(p) === nestedDir);
expect(resolveStateDir(env)).toBe(nestedDir);
vi.restoreAllMocks();
});
});

View File

@ -78,6 +78,16 @@ export function resolveStateDir(
if (explicitHome) {
const resolvedHome = effectiveHomedir();
if (ALL_STATE_DIRNAMES.has(path.basename(resolvedHome))) {
// Backward compat: if a nested state dir already exists from the old
// buggy behavior, prefer it so we don't orphan existing state data.
const nestedState = path.join(resolvedHome, ".openclaw");
try {
if (fs.existsSync(nestedState)) {
return nestedState;
}
} catch {
// best-effort
}
return resolvedHome;
}
}