From e4036185f0abe93f4f80e7b9b4cde1c17c394902 Mon Sep 17 00:00:00 2001 From: Nguyen Quang Huy <31732865+huynguyen03dev@users.noreply.github.com> Date: Fri, 12 Dec 2025 06:29:32 +0700 Subject: [PATCH] fix: load config from user-level ~/.config/opencode/oh-my-opencode.json (#17) --- src/index.ts | 82 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/src/index.ts b/src/index.ts index d7f18f9..6ddf5ca 100644 --- a/src/index.ts +++ b/src/index.ts @@ -41,33 +41,77 @@ import { OhMyOpenCodeConfigSchema, type OhMyOpenCodeConfig } from "./config"; import { log } from "./shared/logger"; import * as fs from "fs"; import * as path from "path"; +import * as os from "os"; + +function loadConfigFromPath(configPath: string): OhMyOpenCodeConfig | null { + try { + if (fs.existsSync(configPath)) { + const content = fs.readFileSync(configPath, "utf-8"); + const rawConfig = JSON.parse(content); + const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig); + + if (!result.success) { + log(`Config validation error in ${configPath}:`, result.error.issues); + return null; + } + + log(`Config loaded from ${configPath}`, { agents: result.data.agents }); + return result.data; + } + } catch (err) { + log(`Error loading config from ${configPath}:`, err); + } + return null; +} + +function mergeConfigs(base: OhMyOpenCodeConfig, override: OhMyOpenCodeConfig): OhMyOpenCodeConfig { + return { + ...base, + ...override, + agents: override.agents !== undefined + ? { ...(base.agents ?? {}), ...override.agents } + : base.agents, + disabled_agents: [ + ...new Set([...(base.disabled_agents ?? []), ...(override.disabled_agents ?? [])]) + ], + disabled_mcps: [ + ...new Set([...(base.disabled_mcps ?? []), ...(override.disabled_mcps ?? [])]) + ], + }; +} function loadPluginConfig(directory: string): OhMyOpenCodeConfig { - const configPaths = [ - path.join(directory, "oh-my-opencode.json"), - path.join(directory, ".oh-my-opencode.json"), + // User-level config paths + const userConfigPaths = [ + path.join(os.homedir(), ".config", "opencode", "oh-my-opencode.json"), ]; - for (const configPath of configPaths) { - try { - if (fs.existsSync(configPath)) { - const content = fs.readFileSync(configPath, "utf-8"); - const rawConfig = JSON.parse(content); - const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig); + // Project-level config paths (higher precedence) + const projectConfigPaths = [ + path.join(directory, ".opencode", "oh-my-opencode.json"), + ]; - if (!result.success) { - log(`Config validation error in ${configPath}:`, result.error.issues); - return {}; - } - - return result.data; - } - } catch { - // Ignore parse errors, use defaults + // Load user config first + let config: OhMyOpenCodeConfig = {}; + for (const configPath of userConfigPaths) { + const userConfig = loadConfigFromPath(configPath); + if (userConfig) { + config = userConfig; + break; } } - return {}; + // Override with project config + for (const configPath of projectConfigPaths) { + const projectConfig = loadConfigFromPath(configPath); + if (projectConfig) { + config = mergeConfigs(config, projectConfig); + break; + } + } + + log("Final merged config", { agents: config.agents, disabled_agents: config.disabled_agents, disabled_mcps: config.disabled_mcps }); + return config; } const OhMyOpenCodePlugin: Plugin = async (ctx) => {