import { existsSync, readFileSync } from "node:fs" import { homedir } from "node:os" import { join } from "node:path" import type { CheckResult, CheckDefinition, PluginInfo } from "../types" import { CHECK_IDS, CHECK_NAMES, PACKAGE_NAME } from "../constants" import { parseJsonc } from "../../../shared" const OPENCODE_CONFIG_DIR = join(homedir(), ".config", "opencode") const OPENCODE_JSON = join(OPENCODE_CONFIG_DIR, "opencode.json") const OPENCODE_JSONC = join(OPENCODE_CONFIG_DIR, "opencode.jsonc") function detectConfigPath(): { path: string; format: "json" | "jsonc" } | null { if (existsSync(OPENCODE_JSONC)) { return { path: OPENCODE_JSONC, format: "jsonc" } } if (existsSync(OPENCODE_JSON)) { return { path: OPENCODE_JSON, format: "json" } } return null } function findPluginEntry(plugins: string[]): { entry: string; isPinned: boolean; version: string | null } | null { for (const plugin of plugins) { if (plugin === PACKAGE_NAME || plugin.startsWith(`${PACKAGE_NAME}@`)) { const isPinned = plugin.includes("@") const version = isPinned ? plugin.split("@")[1] : null return { entry: plugin, isPinned, version } } } return null } export function getPluginInfo(): PluginInfo { const configInfo = detectConfigPath() if (!configInfo) { return { registered: false, configPath: null, entry: null, isPinned: false, pinnedVersion: null, } } try { const content = readFileSync(configInfo.path, "utf-8") const config = parseJsonc<{ plugin?: string[] }>(content) const plugins = config.plugin ?? [] const pluginEntry = findPluginEntry(plugins) if (!pluginEntry) { return { registered: false, configPath: configInfo.path, entry: null, isPinned: false, pinnedVersion: null, } } return { registered: true, configPath: configInfo.path, entry: pluginEntry.entry, isPinned: pluginEntry.isPinned, pinnedVersion: pluginEntry.version, } } catch { return { registered: false, configPath: configInfo.path, entry: null, isPinned: false, pinnedVersion: null, } } } export async function checkPluginRegistration(): Promise { const info = getPluginInfo() if (!info.configPath) { return { name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION], status: "fail", message: "OpenCode config file not found", details: [ "Run: bunx oh-my-opencode install", `Expected: ${OPENCODE_JSON} or ${OPENCODE_JSONC}`, ], } } if (!info.registered) { return { name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION], status: "fail", message: "Plugin not registered in config", details: [ "Run: bunx oh-my-opencode install", `Config: ${info.configPath}`, ], } } const message = info.isPinned ? `Registered (pinned: ${info.pinnedVersion})` : "Registered" return { name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION], status: "pass", message, details: [`Config: ${info.configPath}`], } } export function getPluginCheckDefinition(): CheckDefinition { return { id: CHECK_IDS.PLUGIN_REGISTRATION, name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION], category: "installation", check: checkPluginRegistration, critical: true, } }