fix(cli): apply --profile before dotenv bootstrap in runCli (#31950)

Co-authored-by: bmendonca3 <bmendonca3@users.noreply.github.com>
This commit is contained in:
bmendonca3 2026-03-02 11:09:45 -07:00 committed by GitHub
parent a6489ab5e9
commit 8b27582509
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 90 additions and 1 deletions

View File

@ -0,0 +1,79 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const dotenvState = vi.hoisted(() => {
const state = {
profileAtDotenvLoad: undefined as string | undefined,
};
return {
state,
loadDotEnv: vi.fn(() => {
state.profileAtDotenvLoad = process.env.OPENCLAW_PROFILE;
}),
};
});
vi.mock("../infra/dotenv.js", () => ({
loadDotEnv: dotenvState.loadDotEnv,
}));
vi.mock("../infra/env.js", () => ({
normalizeEnv: vi.fn(),
}));
vi.mock("../infra/runtime-guard.js", () => ({
assertSupportedRuntime: vi.fn(),
}));
vi.mock("../infra/path-env.js", () => ({
ensureOpenClawCliOnPath: vi.fn(),
}));
vi.mock("./route.js", () => ({
tryRouteCli: vi.fn(async () => true),
}));
vi.mock("./windows-argv.js", () => ({
normalizeWindowsArgv: (argv: string[]) => argv,
}));
import { runCli } from "./run-main.js";
describe("runCli profile env bootstrap", () => {
const originalProfile = process.env.OPENCLAW_PROFILE;
const originalStateDir = process.env.OPENCLAW_STATE_DIR;
const originalConfigPath = process.env.OPENCLAW_CONFIG_PATH;
beforeEach(() => {
delete process.env.OPENCLAW_PROFILE;
delete process.env.OPENCLAW_STATE_DIR;
delete process.env.OPENCLAW_CONFIG_PATH;
dotenvState.state.profileAtDotenvLoad = undefined;
dotenvState.loadDotEnv.mockClear();
});
afterEach(() => {
if (originalProfile === undefined) {
delete process.env.OPENCLAW_PROFILE;
} else {
process.env.OPENCLAW_PROFILE = originalProfile;
}
if (originalStateDir === undefined) {
delete process.env.OPENCLAW_STATE_DIR;
} else {
process.env.OPENCLAW_STATE_DIR = originalStateDir;
}
if (originalConfigPath === undefined) {
delete process.env.OPENCLAW_CONFIG_PATH;
} else {
process.env.OPENCLAW_CONFIG_PATH = originalConfigPath;
}
});
it("applies --profile before dotenv loading", async () => {
await runCli(["node", "openclaw", "--profile", "rawdog", "status"]);
expect(dotenvState.loadDotEnv).toHaveBeenCalledOnce();
expect(dotenvState.state.profileAtDotenvLoad).toBe("rawdog");
expect(process.env.OPENCLAW_PROFILE).toBe("rawdog");
});
});

View File

@ -9,6 +9,7 @@ import { assertSupportedRuntime } from "../infra/runtime-guard.js";
import { installUnhandledRejectionHandler } from "../infra/unhandled-rejections.js";
import { enableConsoleCapture } from "../logging.js";
import { getCommandPath, getPrimaryCommand, hasHelpOrVersion } from "./argv.js";
import { applyCliProfileEnv, parseCliProfileArgs } from "./profile.js";
import { tryRouteCli } from "./route.js";
import { normalizeWindowsArgv } from "./windows-argv.js";
@ -62,7 +63,16 @@ export function shouldEnsureCliPath(argv: string[]): boolean {
}
export async function runCli(argv: string[] = process.argv) {
const normalizedArgv = normalizeWindowsArgv(argv);
let normalizedArgv = normalizeWindowsArgv(argv);
const parsedProfile = parseCliProfileArgs(normalizedArgv);
if (!parsedProfile.ok) {
throw new Error(parsedProfile.error);
}
if (parsedProfile.profile) {
applyCliProfileEnv({ profile: parsedProfile.profile });
}
normalizedArgv = parsedProfile.argv;
loadDotEnv({ quiet: true });
normalizeEnv();
if (shouldEnsureCliPath(normalizedArgv)) {