From dad534e7c018a540baca20ace7408fc0cc82902c Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 19 Dec 2025 02:19:54 +0900 Subject: [PATCH] fix: break circular dependency in config error utilities to prevent plugin loader crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created src/shared/config-errors.ts to isolate config error state management - Removed function re-exports (getConfigLoadErrors, clearConfigLoadErrors) from main index.ts - Only ConfigLoadError type is re-exported from main module to avoid OpenCode calling it as a plugin - Updated auto-update-checker hook to import from shared/config-errors instead of main index - Fixes "TypeError: undefined is not an object" crash when OpenCode iterated through ALL exports and called clearConfigLoadErrors(input) which returned undefined 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) --- src/hooks/auto-update-checker/index.ts | 2 +- src/index.ts | 26 ++++++++------------------ src/shared/config-errors.ts | 18 ++++++++++++++++++ src/shared/index.ts | 1 + 4 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 src/shared/config-errors.ts diff --git a/src/hooks/auto-update-checker/index.ts b/src/hooks/auto-update-checker/index.ts index a720260..eed61ec 100644 --- a/src/hooks/auto-update-checker/index.ts +++ b/src/hooks/auto-update-checker/index.ts @@ -4,7 +4,7 @@ import { invalidatePackage } from "./cache" import { PACKAGE_NAME } from "./constants" import { log } from "../../shared/logger" import { getUserConfigPath } from "../../shared/config-path" -import { getConfigLoadErrors, clearConfigLoadErrors } from "../../index" +import { getConfigLoadErrors, clearConfigLoadErrors } from "../../shared/config-errors" import type { AutoUpdateCheckerOptions } from "./types" export function createAutoUpdateCheckerHook(ctx: PluginInput, options: AutoUpdateCheckerOptions = {}) { diff --git a/src/index.ts b/src/index.ts index 2ca036b..9b9e868 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,7 +46,7 @@ import { builtinTools, createCallOmoAgent, createBackgroundTools, createLookAt, import { BackgroundManager } from "./features/background-agent"; import { createBuiltinMcps } from "./mcp"; import { OhMyOpenCodeConfigSchema, type OhMyOpenCodeConfig, type HookName } from "./config"; -import { log, deepMerge, getUserConfigDir } from "./shared"; +import { log, deepMerge, getUserConfigDir, addConfigLoadError } from "./shared"; import { PLAN_SYSTEM_PROMPT, PLAN_PERMISSION } from "./agents/plan-prompt"; import * as fs from "fs"; import * as path from "path"; @@ -62,21 +62,6 @@ const AGENT_NAME_MAP: Record = { "multimodal-looker": "multimodal-looker", }; -export type ConfigLoadError = { - path: string; - error: string; -}; - -let configLoadErrors: ConfigLoadError[] = []; - -export function getConfigLoadErrors(): ConfigLoadError[] { - return configLoadErrors; -} - -export function clearConfigLoadErrors(): void { - configLoadErrors = []; -} - function normalizeAgentNames(agents: Record): Record { const normalized: Record = {}; for (const [key, value] of Object.entries(agents)) { @@ -101,7 +86,7 @@ function loadConfigFromPath(configPath: string): OhMyOpenCodeConfig | null { if (!result.success) { const errorMsg = result.error.issues.map(i => `${i.path.join(".")}: ${i.message}`).join(", "); log(`Config validation error in ${configPath}:`, result.error.issues); - configLoadErrors.push({ path: configPath, error: `Validation error: ${errorMsg}` }); + addConfigLoadError({ path: configPath, error: `Validation error: ${errorMsg}` }); return null; } @@ -111,7 +96,7 @@ function loadConfigFromPath(configPath: string): OhMyOpenCodeConfig | null { } catch (err) { const errorMsg = err instanceof Error ? err.message : String(err); log(`Error loading config from ${configPath}:`, err); - configLoadErrors.push({ path: configPath, error: errorMsg }); + addConfigLoadError({ path: configPath, error: errorMsg }); } return null; } @@ -506,3 +491,8 @@ export type { McpName, HookName, } from "./config"; + +// NOTE: Do NOT export functions from main index.ts! +// OpenCode treats ALL exports as plugin instances and calls them. +// Config error utilities are available via "./shared/config-errors" for internal use only. +export type { ConfigLoadError } from "./shared/config-errors"; diff --git a/src/shared/config-errors.ts b/src/shared/config-errors.ts new file mode 100644 index 0000000..951a6c0 --- /dev/null +++ b/src/shared/config-errors.ts @@ -0,0 +1,18 @@ +export type ConfigLoadError = { + path: string + error: string +} + +let configLoadErrors: ConfigLoadError[] = [] + +export function getConfigLoadErrors(): ConfigLoadError[] { + return configLoadErrors +} + +export function clearConfigLoadErrors(): void { + configLoadErrors = [] +} + +export function addConfigLoadError(error: ConfigLoadError): void { + configLoadErrors.push(error) +} diff --git a/src/shared/index.ts b/src/shared/index.ts index 9a371b7..593195b 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -11,3 +11,4 @@ export * from "./deep-merge" export * from "./file-utils" export * from "./dynamic-truncator" export * from "./config-path" +export * from "./config-errors"