mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 09:31:25 +00:00
fix(paths): respect OPENCLAW_HOME for all internal path resolution (#12091)
* fix(paths): respect OPENCLAW_HOME for all internal path resolution (#11995) Add home-dir module (src/infra/home-dir.ts) that centralizes home directory resolution with precedence: OPENCLAW_HOME > HOME > USERPROFILE > os.homedir(). Migrate all path-sensitive callsites: config IO, agent dirs, session transcripts, pairing store, cron store, doctor, CLI profiles. Add envHomedir() helper in config/paths.ts to reduce lambda noise. Document OPENCLAW_HOME in docs/help/environment.md. * fix(paths): handle OPENCLAW_HOME '~' fallback (#12091) (thanks @sebslight) * docs: mention OPENCLAW_HOME in install and getting started (#12091) (thanks @sebslight) * fix(status): show OPENCLAW_HOME in shortened paths (#12091) (thanks @sebslight) * docs(changelog): clarify OPENCLAW_HOME and HOME precedence (#12091) (thanks @sebslight)
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import {
|
||||
resolveAgentConfig,
|
||||
resolveAgentDir,
|
||||
resolveAgentModelFallbacksOverride,
|
||||
resolveAgentModelPrimary,
|
||||
resolveAgentWorkspaceDir,
|
||||
} from "./agent-scope.js";
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
describe("resolveAgentConfig", () => {
|
||||
it("should return undefined when no agents config exists", () => {
|
||||
const cfg: OpenClawConfig = {};
|
||||
@@ -200,4 +206,18 @@ describe("resolveAgentConfig", () => {
|
||||
expect(result).toBeDefined();
|
||||
expect(result?.workspace).toBe("~/openclaw");
|
||||
});
|
||||
|
||||
it("uses OPENCLAW_HOME for default agent workspace", () => {
|
||||
vi.stubEnv("OPENCLAW_HOME", "/srv/openclaw-home");
|
||||
|
||||
const workspace = resolveAgentWorkspaceDir({} as OpenClawConfig, "main");
|
||||
expect(workspace).toBe("/srv/openclaw-home/.openclaw/workspace");
|
||||
});
|
||||
|
||||
it("uses OPENCLAW_HOME for default agentDir", () => {
|
||||
vi.stubEnv("OPENCLAW_HOME", "/srv/openclaw-home");
|
||||
|
||||
const agentDir = resolveAgentDir({} as OpenClawConfig, "main");
|
||||
expect(agentDir).toBe("/srv/openclaw-home/.openclaw/agents/main/agent");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
@@ -8,7 +7,7 @@ import {
|
||||
parseAgentSessionKey,
|
||||
} from "../routing/session-key.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { DEFAULT_AGENT_WORKSPACE_DIR } from "./workspace.js";
|
||||
import { resolveDefaultAgentWorkspaceDir } from "./workspace.js";
|
||||
|
||||
export { resolveAgentIdFromSessionKey } from "../routing/session-key.js";
|
||||
|
||||
@@ -176,9 +175,9 @@ export function resolveAgentWorkspaceDir(cfg: OpenClawConfig, agentId: string) {
|
||||
if (fallback) {
|
||||
return resolveUserPath(fallback);
|
||||
}
|
||||
return DEFAULT_AGENT_WORKSPACE_DIR;
|
||||
return resolveDefaultAgentWorkspaceDir(process.env);
|
||||
}
|
||||
const stateDir = resolveStateDir(process.env, os.homedir);
|
||||
const stateDir = resolveStateDir(process.env);
|
||||
return path.join(stateDir, `workspace-${id}`);
|
||||
}
|
||||
|
||||
@@ -188,6 +187,6 @@ export function resolveAgentDir(cfg: OpenClawConfig, agentId: string) {
|
||||
if (configured) {
|
||||
return resolveUserPath(configured);
|
||||
}
|
||||
const root = resolveStateDir(process.env, os.homedir);
|
||||
const root = resolveStateDir(process.env);
|
||||
return path.join(root, "agents", id, "agent");
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
import { resolveRunWorkspaceDir } from "./workspace-run.js";
|
||||
import { DEFAULT_AGENT_WORKSPACE_DIR } from "./workspace.js";
|
||||
import { resolveDefaultAgentWorkspaceDir } from "./workspace.js";
|
||||
|
||||
describe("resolveRunWorkspaceDir", () => {
|
||||
it("resolves explicit workspace values without fallback", () => {
|
||||
@@ -70,7 +70,7 @@ describe("resolveRunWorkspaceDir", () => {
|
||||
expect(result.usedFallback).toBe(true);
|
||||
expect(result.fallbackReason).toBe("missing");
|
||||
expect(result.agentId).toBe("main");
|
||||
expect(result.workspaceDir).toBe(path.resolve(DEFAULT_AGENT_WORKSPACE_DIR));
|
||||
expect(result.workspaceDir).toBe(path.resolve(resolveDefaultAgentWorkspaceDir(process.env)));
|
||||
});
|
||||
|
||||
it("throws for malformed agent session keys", () => {
|
||||
|
||||
17
src/agents/workspace.defaults.test.ts
Normal file
17
src/agents/workspace.defaults.test.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
describe("DEFAULT_AGENT_WORKSPACE_DIR", () => {
|
||||
it("uses OPENCLAW_HOME at module import time", async () => {
|
||||
vi.stubEnv("OPENCLAW_HOME", "/srv/openclaw-home");
|
||||
vi.stubEnv("HOME", "/home/other");
|
||||
vi.resetModules();
|
||||
|
||||
const mod = await import("./workspace.js");
|
||||
expect(mod.DEFAULT_AGENT_WORKSPACE_DIR).toBe("/srv/openclaw-home/.openclaw/workspace");
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,24 @@
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { makeTempWorkspace, writeWorkspaceFile } from "../test-helpers/workspace.js";
|
||||
import {
|
||||
DEFAULT_MEMORY_ALT_FILENAME,
|
||||
DEFAULT_MEMORY_FILENAME,
|
||||
loadWorkspaceBootstrapFiles,
|
||||
resolveDefaultAgentWorkspaceDir,
|
||||
} from "./workspace.js";
|
||||
|
||||
describe("resolveDefaultAgentWorkspaceDir", () => {
|
||||
it("uses OPENCLAW_HOME for default workspace resolution", () => {
|
||||
const dir = resolveDefaultAgentWorkspaceDir({
|
||||
OPENCLAW_HOME: "/srv/openclaw-home",
|
||||
HOME: "/home/other",
|
||||
} as NodeJS.ProcessEnv);
|
||||
|
||||
expect(dir).toBe(path.join("/srv/openclaw-home", ".openclaw", "workspace"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("loadWorkspaceBootstrapFiles", () => {
|
||||
it("includes MEMORY.md when present", async () => {
|
||||
const tempDir = await makeTempWorkspace("openclaw-workspace-");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { resolveRequiredHomeDir } from "../infra/home-dir.js";
|
||||
import { runCommandWithTimeout } from "../process/exec.js";
|
||||
import { isSubagentSessionKey } from "../routing/session-key.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
@@ -10,11 +11,12 @@ export function resolveDefaultAgentWorkspaceDir(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
homedir: () => string = os.homedir,
|
||||
): string {
|
||||
const home = resolveRequiredHomeDir(env, homedir);
|
||||
const profile = env.OPENCLAW_PROFILE?.trim();
|
||||
if (profile && profile.toLowerCase() !== "default") {
|
||||
return path.join(homedir(), ".openclaw", `workspace-${profile}`);
|
||||
return path.join(home, ".openclaw", `workspace-${profile}`);
|
||||
}
|
||||
return path.join(homedir(), ".openclaw", "workspace");
|
||||
return path.join(home, ".openclaw", "workspace");
|
||||
}
|
||||
|
||||
export const DEFAULT_AGENT_WORKSPACE_DIR = resolveDefaultAgentWorkspaceDir();
|
||||
|
||||
Reference in New Issue
Block a user