CLI: harden profile passthrough and reset overrides
This commit is contained in:
parent
8ccf40e36a
commit
1fae5ec32f
@ -3,7 +3,6 @@ import fsPromises from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { Command } from "commander";
|
||||
import { withTempSecretFiles } from "../../test-utils/secret-file-fixture.js";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createCliRuntimeCapture } from "../test-runtime-capture.js";
|
||||
|
||||
@ -373,6 +372,18 @@ describe("gateway run option collisions", () => {
|
||||
expect(ensureDevGatewayConfig).toHaveBeenCalledWith({ reset: true });
|
||||
});
|
||||
|
||||
it("allows --dev --reset for explicit non-default legacy state/config paths", async () => {
|
||||
vi.stubEnv("HOME", "/Users/test");
|
||||
vi.stubEnv("CLAWDBOT_STATE_DIR", "/tmp/custom-dev");
|
||||
vi.stubEnv("CLAWDBOT_CONFIG_PATH", "/tmp/custom-dev/openclaw.json");
|
||||
resolveStateDir.mockReturnValue("/tmp/custom-dev");
|
||||
resolveConfigPath.mockReturnValue("/tmp/custom-dev/openclaw.json");
|
||||
|
||||
await runGatewayCli(["gateway", "run", "--dev", "--reset", "--allow-unconfigured"]);
|
||||
|
||||
expect(ensureDevGatewayConfig).toHaveBeenCalledWith({ reset: true });
|
||||
});
|
||||
|
||||
it("hard-stops --dev --reset when state/config match non-dev profile defaults", async () => {
|
||||
vi.stubEnv("HOME", "/Users/test");
|
||||
vi.stubEnv("OPENCLAW_PROFILE", "work");
|
||||
@ -389,6 +400,22 @@ describe("gateway run option collisions", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("hard-stops --dev --reset when legacy env resolves to non-dev profile defaults", async () => {
|
||||
vi.stubEnv("HOME", "/Users/test");
|
||||
vi.stubEnv("OPENCLAW_PROFILE", "work");
|
||||
vi.stubEnv("CLAWDBOT_STATE_DIR", "/Users/test/.openclaw-work");
|
||||
vi.stubEnv("CLAWDBOT_CONFIG_PATH", "/Users/test/.openclaw-work/openclaw.json");
|
||||
resolveStateDir.mockReturnValue("/Users/test/.openclaw-work");
|
||||
resolveConfigPath.mockReturnValue("/Users/test/.openclaw-work/openclaw.json");
|
||||
|
||||
await expectGatewayExit(["gateway", "run", "--dev", "--reset"]);
|
||||
|
||||
expect(ensureDevGatewayConfig).not.toHaveBeenCalled();
|
||||
expect(runtimeErrors.join("\n")).toContain(
|
||||
"Refusing to run `gateway --dev --reset` because the reset target is not dev-isolated.",
|
||||
);
|
||||
});
|
||||
|
||||
it("hard-stops --dev --reset when state is profile-default but config is custom", async () => {
|
||||
vi.stubEnv("HOME", "/Users/test");
|
||||
vi.stubEnv("OPENCLAW_PROFILE", "work");
|
||||
|
||||
@ -248,8 +248,12 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
|
||||
: false;
|
||||
const stateTargetsProfileDefault = stateIsDefault || stateMatchesProfileDefault;
|
||||
const configTargetsProfileDefault = configIsDefault || configMatchesProfileDefault;
|
||||
const hasStateOverride = Boolean(process.env.OPENCLAW_STATE_DIR?.trim());
|
||||
const hasConfigOverride = Boolean(process.env.OPENCLAW_CONFIG_PATH?.trim());
|
||||
const hasStateOverride = Boolean(
|
||||
process.env.OPENCLAW_STATE_DIR?.trim() || process.env.CLAWDBOT_STATE_DIR?.trim(),
|
||||
);
|
||||
const hasConfigOverride = Boolean(
|
||||
process.env.OPENCLAW_CONFIG_PATH?.trim() || process.env.CLAWDBOT_CONFIG_PATH?.trim(),
|
||||
);
|
||||
const hasExplicitCustomTarget =
|
||||
hasStateOverride &&
|
||||
!stateTargetsProfileDefault &&
|
||||
|
||||
@ -145,6 +145,60 @@ describe("parseCliProfileArgs", () => {
|
||||
expect(res.argv).toEqual(["node", "openclaw", "docs", "aws", "--profile", "prod"]);
|
||||
});
|
||||
|
||||
it("does not intercept --profile in acp client server args", () => {
|
||||
const res = parseCliProfileArgs([
|
||||
"node",
|
||||
"openclaw",
|
||||
"acp",
|
||||
"client",
|
||||
"--server-args",
|
||||
"--profile",
|
||||
"work",
|
||||
]);
|
||||
if (!res.ok) {
|
||||
throw new Error(res.error);
|
||||
}
|
||||
expect(res.profile).toBeNull();
|
||||
expect(res.argv).toEqual([
|
||||
"node",
|
||||
"openclaw",
|
||||
"acp",
|
||||
"client",
|
||||
"--server-args",
|
||||
"--profile",
|
||||
"work",
|
||||
]);
|
||||
});
|
||||
|
||||
it("preserves acp client server args after root option values", () => {
|
||||
const res = parseCliProfileArgs([
|
||||
"node",
|
||||
"openclaw",
|
||||
"--log-level",
|
||||
"debug",
|
||||
"acp",
|
||||
"client",
|
||||
"--server-args",
|
||||
"--profile",
|
||||
"work",
|
||||
]);
|
||||
if (!res.ok) {
|
||||
throw new Error(res.error);
|
||||
}
|
||||
expect(res.profile).toBeNull();
|
||||
expect(res.argv).toEqual([
|
||||
"node",
|
||||
"openclaw",
|
||||
"--log-level",
|
||||
"debug",
|
||||
"acp",
|
||||
"client",
|
||||
"--server-args",
|
||||
"--profile",
|
||||
"work",
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps passthrough --profile when global --profile is set before terminator", () => {
|
||||
const res = parseCliProfileArgs([
|
||||
"node",
|
||||
|
||||
@ -27,7 +27,7 @@ function takeValue(
|
||||
return { value: trimmed || null, consumedNext: Boolean(next) };
|
||||
}
|
||||
|
||||
const ARBITRARY_ARG_COMMAND_PATHS = [["nodes", "run"], ["docs"]] as const;
|
||||
const ARBITRARY_ARG_COMMAND_PATHS = [["nodes", "run"], ["docs"], ["acp", "client"]] as const;
|
||||
const ROOT_BOOLEAN_FLAGS = new Set(["--dev", "--no-color"]);
|
||||
const ROOT_VALUE_FLAGS = new Set(["--profile", "--log-level"]);
|
||||
|
||||
|
||||
@ -187,4 +187,17 @@ describe("resolveResetTargets", () => {
|
||||
expect(targets.credentialsPath).toBe(path.resolve("/tmp/custom-openclaw/credentials"));
|
||||
expect(targets.sessionsDir).toBe(path.resolve("/tmp/custom-openclaw/agents/main/sessions"));
|
||||
});
|
||||
|
||||
it("respects legacy CLAWDBOT_CONFIG_PATH override at runtime", () => {
|
||||
const env = {
|
||||
OPENCLAW_STATE_DIR: "/tmp/custom-openclaw",
|
||||
CLAWDBOT_CONFIG_PATH: "/tmp/legacy/openclaw.json",
|
||||
} as NodeJS.ProcessEnv;
|
||||
const targets = resolveResetTargets(env);
|
||||
|
||||
expect(targets.stateDir).toBe(path.resolve("/tmp/custom-openclaw"));
|
||||
expect(targets.configPath).toBe(path.resolve("/tmp/legacy/openclaw.json"));
|
||||
expect(targets.credentialsPath).toBe(path.resolve("/tmp/custom-openclaw/credentials"));
|
||||
expect(targets.sessionsDir).toBe(path.resolve("/tmp/custom-openclaw/agents/main/sessions"));
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,7 +5,7 @@ import { inspect } from "node:util";
|
||||
import { cancel, isCancel } from "@clack/prompts";
|
||||
import { DEFAULT_AGENT_WORKSPACE_DIR, ensureAgentWorkspace } from "../agents/workspace.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveConfigPath, resolveStateDir } from "../config/config.js";
|
||||
import { resolveCanonicalConfigPath, resolveStateDir } from "../config/config.js";
|
||||
import { resolveAgentModelPrimaryValue } from "../config/model-input.js";
|
||||
import { resolveSessionTranscriptsDirForAgent } from "../config/sessions.js";
|
||||
import { callGateway } from "../gateway/call.js";
|
||||
@ -335,7 +335,7 @@ export function resolveResetTargets(
|
||||
const stateDir = resolveStateDir(env);
|
||||
return {
|
||||
stateDir,
|
||||
configPath: resolveConfigPath(env, stateDir),
|
||||
configPath: resolveCanonicalConfigPath(env, stateDir),
|
||||
credentialsPath: path.join(stateDir, "credentials"),
|
||||
sessionsDir: resolveSessionTranscriptsDirForAgent(agentId, env),
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user