fix(config): preserve explicit git_master overrides during merge

Prevent project config defaults from re-enabling git_master fields that users explicitly disabled. Rebuild git_master from explicit user and project keys so include_co_authored_by and commit_footer merge predictably.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-04-12 18:18:11 +09:00
parent 051ab840d6
commit 3d2eb6e471
2 changed files with 122 additions and 0 deletions
+88
View File
@@ -423,4 +423,92 @@ describe("loadPluginConfig", () => {
expect(existsSync(canonicalConfigPath)).toBe(true)
expect(config.agents?.oracle?.model).toBe("openai/gpt-5.4")
})
it("should preserve explicit user git_master settings when project config omits git_master", async () => {
// given
const rootDir = mkdtempSync(join(tmpdir(), "omo-plugin-config-git-master-user-"))
const userConfigDir = join(rootDir, "user-config")
const projectDir = join(rootDir, "project")
const projectConfigDir = join(projectDir, ".opencode")
tempDirs.push(rootDir)
mkdirSync(userConfigDir, { recursive: true })
mkdirSync(projectConfigDir, { recursive: true })
writeFileSync(
join(userConfigDir, "oh-my-openagent.jsonc"),
JSON.stringify({
git_master: {
commit_footer: false,
include_co_authored_by: false,
},
})
)
writeFileSync(
join(projectConfigDir, "oh-my-openagent.jsonc"),
JSON.stringify({
agents: {
hephaestus: { model: "openai/gpt-5.4" },
},
})
)
process.env.OPENCODE_CONFIG_DIR = userConfigDir
// when
const { loadPluginConfig } = await importFreshPluginConfigModule()
const config = loadPluginConfig(projectDir, {})
// then
expect(config.git_master).toEqual({
commit_footer: false,
include_co_authored_by: false,
git_env_prefix: "GIT_MASTER=1",
})
})
it("should merge explicit git_master keys from user and project configs", async () => {
// given
const rootDir = mkdtempSync(join(tmpdir(), "omo-plugin-config-git-master-merge-"))
const userConfigDir = join(rootDir, "user-config")
const projectDir = join(rootDir, "project")
const projectConfigDir = join(projectDir, ".opencode")
tempDirs.push(rootDir)
mkdirSync(userConfigDir, { recursive: true })
mkdirSync(projectConfigDir, { recursive: true })
writeFileSync(
join(userConfigDir, "oh-my-openagent.jsonc"),
JSON.stringify({
git_master: {
commit_footer: false,
include_co_authored_by: false,
},
})
)
writeFileSync(
join(projectConfigDir, "oh-my-openagent.jsonc"),
JSON.stringify({
git_master: {
commit_footer: true,
},
})
)
process.env.OPENCODE_CONFIG_DIR = userConfigDir
// when
const { loadPluginConfig } = await importFreshPluginConfigModule()
const config = loadPluginConfig(projectDir, {})
// then
expect(config.git_master).toEqual({
commit_footer: true,
include_co_authored_by: false,
git_env_prefix: "GIT_MASTER=1",
})
})
})
+34
View File
@@ -13,6 +13,26 @@ import {
import { migrateLegacyConfigFile } from "./shared/migrate-legacy-config-file";
import { CONFIG_BASENAME, LEGACY_CONFIG_BASENAME } from "./shared/plugin-identity";
function loadExplicitGitMasterOverrides(configPath: string): Record<string, unknown> | undefined {
try {
if (!fs.existsSync(configPath)) {
return undefined
}
const content = fs.readFileSync(configPath, "utf-8")
const rawConfig = parseJsonc<Record<string, unknown>>(content)
const gitMaster = rawConfig.git_master
if (gitMaster && typeof gitMaster === "object" && !Array.isArray(gitMaster)) {
return gitMaster as Record<string, unknown>
}
} catch {
return undefined
}
return undefined
}
const PARTIAL_STRING_ARRAY_KEYS = new Set([
"disabled_mcps",
"disabled_agents",
@@ -229,15 +249,29 @@ export function loadPluginConfig(
// Load user config first (base). Parse empty config through Zod to apply field defaults.
const userConfig = loadConfigFromPath(userConfigPath, ctx)
const userGitMasterOverrides = loadExplicitGitMasterOverrides(userConfigPath)
let config: OhMyOpenCodeConfig =
userConfig ?? OhMyOpenCodeConfigSchema.parse({});
// Override with project config
const defaultGitMaster = OhMyOpenCodeConfigSchema.parse({}).git_master
const projectConfig = loadConfigFromPath(projectConfigPath, ctx);
const projectGitMasterOverrides = loadExplicitGitMasterOverrides(projectConfigPath)
if (projectConfig) {
config = mergeConfigs(config, projectConfig);
}
if (userGitMasterOverrides || projectGitMasterOverrides) {
config = {
...config,
git_master: {
...defaultGitMaster,
...(userGitMasterOverrides ?? {}),
...(projectGitMasterOverrides ?? {}),
},
}
}
config = {
...config,
mcp_env_allowlist: userConfig?.mcp_env_allowlist ?? [],