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:
@@ -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",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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 ?? [],
|
||||
|
||||
Reference in New Issue
Block a user