fix(coding-agent): load project config yml overrides

Fixes #946
This commit is contained in:
can1357
2026-05-06 17:12:33 +02:00
parent d438c4e8a0
commit d6cb0cc56e
2 changed files with 43 additions and 9 deletions
+34 -9
View File
@@ -5,6 +5,7 @@
*/
import * as path from "node:path";
import { logger, parseFrontmatter, tryParseJson } from "@oh-my-pi/pi-utils";
import { YAML } from "bun";
import { registerProvider } from "../capability";
import { type ContextFile, contextFileCapability } from "../capability/context-file";
import { type Extension, type ExtensionManifest, extensionCapability } from "../capability/extension";
@@ -778,22 +779,46 @@ async function loadSettings(ctx: LoadContext): Promise<LoadResult<Settings>> {
const items: Settings[] = [];
const warnings: string[] = [];
const parseYamlSettings = (content: string, filePath: string): Record<string, unknown> | null => {
try {
const data = YAML.parse(content);
if (!data || typeof data !== "object" || Array.isArray(data)) return {};
return data as Record<string, unknown>;
} catch {
warnings.push(`Failed to parse ${filePath}`);
return null;
}
};
for (const { dir, level } of await getConfigDirs(ctx)) {
const settingsPath = path.join(dir, "settings.json");
const content = await readFile(settingsPath);
if (!content) continue;
const data = tryParseJson<Record<string, unknown>>(content);
if (!data) {
warnings.push(`Failed to parse ${settingsPath}`);
continue;
const settingsContent = await readFile(settingsPath);
if (settingsContent) {
const data = tryParseJson<Record<string, unknown>>(settingsContent);
if (data) {
items.push({
path: settingsPath,
data,
level,
_source: createSourceMeta(PROVIDER_ID, settingsPath, level),
});
} else {
warnings.push(`Failed to parse ${settingsPath}`);
}
}
const configPath = path.join(dir, "config.yml");
const configContent = await readFile(configPath);
if (!configContent) continue;
const data = parseYamlSettings(configContent, configPath);
if (!data) continue;
items.push({
path: settingsPath,
path: configPath,
data,
level,
_source: createSourceMeta(PROVIDER_ID, settingsPath, level),
_source: createSourceMeta(PROVIDER_ID, configPath, level),
});
}
@@ -54,6 +54,15 @@ describe("autocompleteMaxVisible setting", () => {
const settings = await Settings.init({ cwd: projectDir, agentDir });
expect(settings.get("autocompleteMaxVisible")).toBe(15);
});
it("should let project config.yml override global config.yml", async () => {
await Bun.write(path.join(agentDir, "config.yml"), YAML.stringify({ autocompleteMaxVisible: 15 }, null, 2));
await Bun.write(path.join(getProjectAgentDir(projectDir), "config.yml"), YAML.stringify({ autocompleteMaxVisible: 20 }, null, 2));
const settings = await Settings.init({ cwd: projectDir, agentDir });
expect(settings.get("autocompleteMaxVisible")).toBe(20);
});
it("should coerce submenu string values for live editor updates", () => {
const setAutocompleteMaxVisible = vi.fn();