diff --git a/src/config/paths.test.ts b/src/config/paths.test.ts index ab16f26fb1a..b72f7b37590 100644 --- a/src/config/paths.test.ts +++ b/src/config/paths.test.ts @@ -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(); + }); }); diff --git a/src/config/paths.ts b/src/config/paths.ts index 1240e1ba3c7..c35c3ffcf94 100644 --- a/src/config/paths.ts +++ b/src/config/paths.ts @@ -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; } }