fix(config): avoid mutating caller config when unsetting paths

This commit is contained in:
Frank Yang
2026-02-22 20:01:20 -08:00
committed by Gustavo Madeira Santana
parent 0e28e50b45
commit fb5409eac2
2 changed files with 28 additions and 1 deletions

View File

@@ -1011,10 +1011,13 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) {
const dir = path.dirname(configPath);
await deps.fs.promises.mkdir(dir, { recursive: true, mode: 0o700 });
const outputConfig =
const outputConfigBase =
envRefMap && changedPaths
? (restoreEnvRefsFromMap(cfgToWrite, "", envRefMap, changedPaths) as OpenClawConfig)
: cfgToWrite;
const outputConfig = options.unsetPaths?.length
? cloneUnknown(outputConfigBase)
: outputConfigBase;
if (options.unsetPaths?.length) {
for (const unsetPath of options.unsetPaths) {
if (!Array.isArray(unsetPath) || unsetPath.length === 0) {

View File

@@ -124,6 +124,30 @@ describe("config io write", () => {
});
});
it("does not mutate caller config when unsetPaths is applied on first write", async () => {
await withTempHome("openclaw-config-io-", async (home) => {
const configPath = path.join(home, ".openclaw", "openclaw.json");
const io = createConfigIO({
env: {} as NodeJS.ProcessEnv,
homedir: () => home,
logger: silentLogger,
});
const input: Record<string, unknown> = {
gateway: { mode: "local" },
commands: { ownerDisplay: "hash" },
};
await io.writeConfigFile(input, { unsetPaths: [["commands", "ownerDisplay"]] });
expect((input.commands as Record<string, unknown>).ownerDisplay).toBe("hash");
const persisted = JSON.parse(await fs.readFile(configPath, "utf-8")) as {
commands?: Record<string, unknown>;
};
expect(persisted.commands ?? {}).not.toHaveProperty("ownerDisplay");
});
});
it("preserves env var references when writing", async () => {
await withTempHome("openclaw-config-io-", async (home) => {
const { configPath, io, snapshot } = await writeConfigAndCreateIo({