import * as fs from "node:fs" import * as os from "node:os" import * as path from "node:path" import { parseJsoncSafe } from "./jsonc-parser" interface OpencodeConfig { plugin?: (string | [string, ...unknown[]])[] } const opencodePluginsCache = new Map() function getWindowsAppdataDir(): string | null { return process.env.APPDATA || null } function getConfigPaths(directory: string): string[] { const crossPlatformDir = path.join(os.homedir(), ".config") const paths = [ path.join(directory, ".opencode", "opencode.json"), path.join(directory, ".opencode", "opencode.jsonc"), path.join(crossPlatformDir, "opencode", "opencode.json"), path.join(crossPlatformDir, "opencode", "opencode.jsonc"), ] const customConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim() if (customConfigDir) { const resolvedCustomConfigDir = path.resolve(customConfigDir) paths.push(path.join(resolvedCustomConfigDir, "opencode.json")) paths.push(path.join(resolvedCustomConfigDir, "opencode.jsonc")) } if (process.platform === "win32") { const appdataDir = getWindowsAppdataDir() if (appdataDir) { paths.push(path.join(appdataDir, "opencode", "opencode.json")) paths.push(path.join(appdataDir, "opencode", "opencode.jsonc")) } } return Array.from(new Set(paths)) } export function loadOpencodePlugins(directory: string): string[] { const cachedPluginEntries = opencodePluginsCache.get(directory) if (cachedPluginEntries) { return cachedPluginEntries } const pluginEntries: string[] = [] const seenPluginEntries = new Set() for (const configPath of getConfigPaths(directory)) { try { if (!fs.existsSync(configPath)) continue const content = fs.readFileSync(configPath, "utf-8") const result = parseJsoncSafe(content) const plugins = result.data?.plugin ?? [] for (const plugin of plugins) { const entry = typeof plugin === "string" ? plugin : Array.isArray(plugin) ? plugin[0] : null if (typeof entry !== "string") continue if (seenPluginEntries.has(entry)) continue seenPluginEntries.add(entry) pluginEntries.push(entry) } } catch { continue } } opencodePluginsCache.set(directory, pluginEntries) return pluginEntries } export function clearOpencodePluginsCache(): void { opencodePluginsCache.clear() }