mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 09:01:14 +00:00
fix: preserve external settings.json edits on reload (#1046)
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
This commit is contained in:
parent
c808de605a
commit
bac57f81be
3 changed files with 170 additions and 5 deletions
99
packages/coding-agent/test/settings-manager-bug.test.ts
Normal file
99
packages/coding-agent/test/settings-manager-bug.test.ts
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { SettingsManager } from "../src/core/settings-manager.js";
|
||||
|
||||
/**
|
||||
* Tests for the fix to a bug where external file changes to arrays were overwritten.
|
||||
*
|
||||
* The bug scenario was:
|
||||
* 1. Pi starts with settings.json containing packages: ["npm:some-pkg"]
|
||||
* 2. User externally edits file to packages: []
|
||||
* 3. User changes an unrelated setting (e.g., theme) via UI
|
||||
* 4. save() would overwrite packages back to ["npm:some-pkg"] from stale in-memory state
|
||||
*
|
||||
* The fix tracks which fields were explicitly modified during the session, and only
|
||||
* those fields override file values during save().
|
||||
*/
|
||||
describe("SettingsManager - External Edit Preservation", () => {
|
||||
const testDir = join(process.cwd(), "test-settings-bug-tmp");
|
||||
const agentDir = join(testDir, "agent");
|
||||
const projectDir = join(testDir, "project");
|
||||
|
||||
beforeEach(() => {
|
||||
if (existsSync(testDir)) {
|
||||
rmSync(testDir, { recursive: true });
|
||||
}
|
||||
mkdirSync(agentDir, { recursive: true });
|
||||
mkdirSync(join(projectDir, ".pi"), { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (existsSync(testDir)) {
|
||||
rmSync(testDir, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("should preserve file changes to packages array when changing unrelated setting", () => {
|
||||
const settingsPath = join(agentDir, "settings.json");
|
||||
|
||||
// Initial state: packages has one item
|
||||
writeFileSync(
|
||||
settingsPath,
|
||||
JSON.stringify({
|
||||
theme: "dark",
|
||||
packages: ["npm:pi-mcp-adapter"],
|
||||
}),
|
||||
);
|
||||
|
||||
// Pi starts up, loads settings into memory
|
||||
const manager = SettingsManager.create(projectDir, agentDir);
|
||||
|
||||
// At this point, globalSettings.packages = ["npm:pi-mcp-adapter"]
|
||||
expect(manager.getPackages()).toEqual(["npm:pi-mcp-adapter"]);
|
||||
|
||||
// User externally edits settings.json to remove the package
|
||||
const currentSettings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
||||
currentSettings.packages = []; // User wants to remove this!
|
||||
writeFileSync(settingsPath, JSON.stringify(currentSettings, null, 2));
|
||||
|
||||
// Verify file was changed
|
||||
expect(JSON.parse(readFileSync(settingsPath, "utf-8")).packages).toEqual([]);
|
||||
|
||||
// User changes an UNRELATED setting via UI (this triggers save)
|
||||
manager.setTheme("light");
|
||||
|
||||
// With the fix, packages should be preserved as [] (not reverted to startup value)
|
||||
const savedSettings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
||||
|
||||
expect(savedSettings.packages).toEqual([]);
|
||||
expect(savedSettings.theme).toBe("light");
|
||||
});
|
||||
|
||||
it("should preserve file changes to extensions array when changing unrelated setting", () => {
|
||||
const settingsPath = join(agentDir, "settings.json");
|
||||
|
||||
writeFileSync(
|
||||
settingsPath,
|
||||
JSON.stringify({
|
||||
theme: "dark",
|
||||
extensions: ["/old/extension.ts"],
|
||||
}),
|
||||
);
|
||||
|
||||
const manager = SettingsManager.create(projectDir, agentDir);
|
||||
|
||||
// User externally updates extensions
|
||||
const currentSettings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
||||
currentSettings.extensions = ["/new/extension.ts"];
|
||||
writeFileSync(settingsPath, JSON.stringify(currentSettings, null, 2));
|
||||
|
||||
// Change unrelated setting
|
||||
manager.setDefaultThinkingLevel("high");
|
||||
|
||||
const savedSettings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
||||
|
||||
// With the fix, extensions should be preserved (not reverted to startup value)
|
||||
expect(savedSettings.extensions).toEqual(["/new/extension.ts"]);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue