CLI: preserve profile passthrough args and env overrides
This commit is contained in:
parent
e13cc5b66b
commit
0a30503239
@ -103,6 +103,48 @@ describe("parseCliProfileArgs", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not intercept --profile in nodes run argv without passthrough terminator", () => {
|
||||
const res = parseCliProfileArgs([
|
||||
"node",
|
||||
"openclaw",
|
||||
"nodes",
|
||||
"run",
|
||||
"--node",
|
||||
"abc123",
|
||||
"aws",
|
||||
"--profile",
|
||||
"prod",
|
||||
"sts",
|
||||
"get-caller-identity",
|
||||
]);
|
||||
if (!res.ok) {
|
||||
throw new Error(res.error);
|
||||
}
|
||||
expect(res.profile).toBeNull();
|
||||
expect(res.argv).toEqual([
|
||||
"node",
|
||||
"openclaw",
|
||||
"nodes",
|
||||
"run",
|
||||
"--node",
|
||||
"abc123",
|
||||
"aws",
|
||||
"--profile",
|
||||
"prod",
|
||||
"sts",
|
||||
"get-caller-identity",
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not intercept --profile in docs query args", () => {
|
||||
const res = parseCliProfileArgs(["node", "openclaw", "docs", "aws", "--profile", "prod"]);
|
||||
if (!res.ok) {
|
||||
throw new Error(res.error);
|
||||
}
|
||||
expect(res.profile).toBeNull();
|
||||
expect(res.argv).toEqual(["node", "openclaw", "docs", "aws", "--profile", "prod"]);
|
||||
});
|
||||
|
||||
it("keeps passthrough --profile when global --profile is set before terminator", () => {
|
||||
const res = parseCliProfileArgs([
|
||||
"node",
|
||||
@ -183,12 +225,11 @@ describe("applyCliProfileEnv", () => {
|
||||
homedir: () => "/home/peter",
|
||||
});
|
||||
expect(env.OPENCLAW_STATE_DIR).toBe("/custom");
|
||||
// OPENCLAW_GATEWAY_PORT is intentionally reset for profile isolation.
|
||||
expect(env.OPENCLAW_GATEWAY_PORT).toBe("19001");
|
||||
expect(env.OPENCLAW_GATEWAY_PORT).toBe("19099");
|
||||
expect(env.OPENCLAW_CONFIG_PATH).toBe(path.join("/custom", "openclaw.json"));
|
||||
});
|
||||
|
||||
it("clears inherited OPENCLAW_GATEWAY_PORT for non-dev profiles", () => {
|
||||
it("preserves explicit OPENCLAW_GATEWAY_PORT for non-dev profiles", () => {
|
||||
const env: Record<string, string | undefined> = {
|
||||
OPENCLAW_GATEWAY_PORT: "18789",
|
||||
};
|
||||
@ -197,10 +238,10 @@ describe("applyCliProfileEnv", () => {
|
||||
env,
|
||||
homedir: () => "/home/peter",
|
||||
});
|
||||
expect(env.OPENCLAW_GATEWAY_PORT).toBeUndefined();
|
||||
expect(env.OPENCLAW_GATEWAY_PORT).toBe("18789");
|
||||
});
|
||||
|
||||
it("clears inherited service env vars for profile isolation", () => {
|
||||
it("preserves service override env vars", () => {
|
||||
const env: Record<string, string | undefined> = {
|
||||
OPENCLAW_GATEWAY_PORT: "18789",
|
||||
OPENCLAW_LAUNCHD_LABEL: "ai.openclaw.gateway",
|
||||
@ -212,13 +253,23 @@ describe("applyCliProfileEnv", () => {
|
||||
env,
|
||||
homedir: () => "/home/peter",
|
||||
});
|
||||
expect(env.OPENCLAW_GATEWAY_PORT).toBeUndefined();
|
||||
expect(env.OPENCLAW_LAUNCHD_LABEL).toBeUndefined();
|
||||
expect(env.OPENCLAW_SYSTEMD_UNIT).toBeUndefined();
|
||||
expect(env.OPENCLAW_SERVICE_VERSION).toBeUndefined();
|
||||
expect(env.OPENCLAW_GATEWAY_PORT).toBe("18789");
|
||||
expect(env.OPENCLAW_LAUNCHD_LABEL).toBe("ai.openclaw.gateway");
|
||||
expect(env.OPENCLAW_SYSTEMD_UNIT).toBe("openclaw-gateway.service");
|
||||
expect(env.OPENCLAW_SERVICE_VERSION).toBe("2026.1.0");
|
||||
expect(env.OPENCLAW_PROFILE).toBe("work");
|
||||
});
|
||||
|
||||
it("uses 19001 for dev profile only when OPENCLAW_GATEWAY_PORT is unset", () => {
|
||||
const env: Record<string, string | undefined> = {};
|
||||
applyCliProfileEnv({
|
||||
profile: "dev",
|
||||
env,
|
||||
homedir: () => "/home/peter",
|
||||
});
|
||||
expect(env.OPENCLAW_GATEWAY_PORT).toBe("19001");
|
||||
});
|
||||
|
||||
it("uses OPENCLAW_HOME when deriving profile state dir", () => {
|
||||
const env: Record<string, string | undefined> = {
|
||||
OPENCLAW_HOME: "/srv/openclaw-home",
|
||||
|
||||
@ -27,6 +27,57 @@ function takeValue(
|
||||
return { value: trimmed || null, consumedNext: Boolean(next) };
|
||||
}
|
||||
|
||||
const ARBITRARY_ARG_COMMAND_PATHS = [["nodes", "run"], ["docs"]] as const;
|
||||
|
||||
function shouldGuardTrailingArgsFromProfileParsing(args: string[]): boolean {
|
||||
const commandTokens: string[] = [];
|
||||
|
||||
for (let i = 0; i < args.length; i += 1) {
|
||||
const arg = args[i];
|
||||
if (!arg || arg === "--") {
|
||||
break;
|
||||
}
|
||||
|
||||
if (arg === "--dev") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg === "--profile" || arg.startsWith("--profile=")) {
|
||||
if (arg === "--profile") {
|
||||
i += 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.startsWith("-")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
commandTokens.push(arg);
|
||||
|
||||
if (
|
||||
ARBITRARY_ARG_COMMAND_PATHS.some(
|
||||
(path) =>
|
||||
path.length === commandTokens.length &&
|
||||
path.every((part, idx) => part === commandTokens[idx]),
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const couldStillMatch = ARBITRARY_ARG_COMMAND_PATHS.some(
|
||||
(path) =>
|
||||
commandTokens.length <= path.length &&
|
||||
commandTokens.every((part, idx) => path[idx] === part),
|
||||
);
|
||||
if (!couldStillMatch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function parseCliProfileArgs(argv: string[]): CliProfileParseResult {
|
||||
if (argv.length < 2) {
|
||||
return { ok: true, profile: null, argv };
|
||||
@ -39,6 +90,7 @@ export function parseCliProfileArgs(argv: string[]): CliProfileParseResult {
|
||||
let sawTerminator = false;
|
||||
|
||||
const args = argv.slice(2);
|
||||
const guardTrailingArgs = shouldGuardTrailingArgsFromProfileParsing(args);
|
||||
for (let i = 0; i < args.length; i += 1) {
|
||||
const arg = args[i];
|
||||
if (arg === undefined) {
|
||||
@ -56,7 +108,10 @@ export function parseCliProfileArgs(argv: string[]): CliProfileParseResult {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sawCommand && arg !== "--profile" && !arg.startsWith("--profile=")) {
|
||||
if (
|
||||
sawCommand &&
|
||||
(guardTrailingArgs || (arg !== "--profile" && !arg.startsWith("--profile=")))
|
||||
) {
|
||||
out.push(arg);
|
||||
continue;
|
||||
}
|
||||
@ -147,12 +202,7 @@ export function applyCliProfileEnv(params: {
|
||||
}
|
||||
|
||||
// Convenience only: fill defaults, never override explicit env values.
|
||||
// Exception: clear inherited service-scoped env vars for profile isolation.
|
||||
env.OPENCLAW_PROFILE = profile;
|
||||
delete env.OPENCLAW_GATEWAY_PORT;
|
||||
delete env.OPENCLAW_LAUNCHD_LABEL;
|
||||
delete env.OPENCLAW_SYSTEMD_UNIT;
|
||||
delete env.OPENCLAW_SERVICE_VERSION;
|
||||
|
||||
const stateDir = env.OPENCLAW_STATE_DIR?.trim() || resolveProfileStateDir(profile, env, homedir);
|
||||
if (!env.OPENCLAW_STATE_DIR?.trim()) {
|
||||
@ -163,7 +213,7 @@ export function applyCliProfileEnv(params: {
|
||||
env.OPENCLAW_CONFIG_PATH = path.join(stateDir, "openclaw.json");
|
||||
}
|
||||
|
||||
if (profile === "dev") {
|
||||
if (profile === "dev" && !env.OPENCLAW_GATEWAY_PORT?.trim()) {
|
||||
env.OPENCLAW_GATEWAY_PORT = "19001";
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user