From f03c6700d44c54d33bcaadd94bdee3048bad6743 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 4 Apr 2026 01:32:59 +0900 Subject: [PATCH] fix(hooks): reuse shared legacy plugin migration helper Replace the legacy toast regex writer with the shared atomic helper and route legacy plugin call sites through small wrappers so existing mock.module tests stop leaking across the suite. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../auto-migrate-runner.ts | 2 ++ src/hooks/legacy-plugin-toast/auto-migrate.ts | 29 ++++++------------- src/hooks/legacy-plugin-toast/hook.test.ts | 4 +-- src/hooks/legacy-plugin-toast/hook.ts | 2 +- .../plugin-entry-migrator.ts | 1 + .../log-legacy-plugin-startup-warning.test.ts | 2 +- .../log-legacy-plugin-startup-warning.ts | 2 +- src/shared/plugin-entry-migrator.ts | 1 + 8 files changed, 18 insertions(+), 25 deletions(-) create mode 100644 src/hooks/legacy-plugin-toast/auto-migrate-runner.ts create mode 100644 src/hooks/legacy-plugin-toast/plugin-entry-migrator.ts create mode 100644 src/shared/plugin-entry-migrator.ts diff --git a/src/hooks/legacy-plugin-toast/auto-migrate-runner.ts b/src/hooks/legacy-plugin-toast/auto-migrate-runner.ts new file mode 100644 index 000000000..c77fea2b9 --- /dev/null +++ b/src/hooks/legacy-plugin-toast/auto-migrate-runner.ts @@ -0,0 +1,2 @@ +export { autoMigrateLegacyPluginEntry } from "./auto-migrate" +export type { MigrationResult } from "./auto-migrate" diff --git a/src/hooks/legacy-plugin-toast/auto-migrate.ts b/src/hooks/legacy-plugin-toast/auto-migrate.ts index 34bc4bbc0..a33cf8ac9 100644 --- a/src/hooks/legacy-plugin-toast/auto-migrate.ts +++ b/src/hooks/legacy-plugin-toast/auto-migrate.ts @@ -1,9 +1,10 @@ -import { existsSync, readFileSync, writeFileSync } from "node:fs" +import { existsSync, readFileSync } from "node:fs" import { join } from "node:path" import { parseJsoncSafe } from "../../shared/jsonc-parser" import { getOpenCodeConfigPaths } from "../../shared/opencode-config-dir" import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "../../shared/plugin-identity" +import { migrateLegacyPluginEntry } from "./plugin-entry-migrator" export interface MigrationResult { migrated: boolean @@ -63,27 +64,15 @@ export function autoMigrateLegacyPluginEntry(overrideConfigDir?: string): Migrat const hasCanonical = plugins.some(isCanonicalEntry) const from = legacyEntries[0] const to = toLegacyCanonical(from) + const migrated = migrateLegacyPluginEntry(configPath) + if (!migrated) return { migrated: false, from: null, to: null, configPath } - const normalized = hasCanonical - ? plugins.filter((p) => !isLegacyEntry(p)) - : plugins.map((p) => (isLegacyEntry(p) ? toLegacyCanonical(p) : p)) - - const isJsonc = configPath.endsWith(".jsonc") - if (isJsonc) { - const pluginArrayRegex = /((?:"plugin"|plugin)\s*:\s*)\[([\s\S]*?)\]/ - const match = content.match(pluginArrayRegex) - if (match) { - const formattedPlugins = normalized.map((p) => `"${p}"`).join(",\n ") - const newContent = content.replace(pluginArrayRegex, `$1[\n ${formattedPlugins}\n ]`) - writeFileSync(configPath, newContent) - return { migrated: true, from, to, configPath } - } + return { + migrated: true, + from, + to: hasCanonical ? PLUGIN_NAME : to, + configPath, } - - const parsed = JSON.parse(content) as Record - parsed.plugin = normalized - writeFileSync(configPath, JSON.stringify(parsed, null, 2) + "\n") - return { migrated: true, from, to, configPath } } catch { return { migrated: false, from: null, to: null, configPath } } diff --git a/src/hooks/legacy-plugin-toast/hook.test.ts b/src/hooks/legacy-plugin-toast/hook.test.ts index 490908429..c355587fc 100644 --- a/src/hooks/legacy-plugin-toast/hook.test.ts +++ b/src/hooks/legacy-plugin-toast/hook.test.ts @@ -1,5 +1,5 @@ import { afterAll, beforeEach, describe, expect, it, mock } from "bun:test" -import type { MigrationResult } from "./auto-migrate" +import type { MigrationResult } from "./auto-migrate-runner" const mockCheckForLegacyPluginEntry = mock(() => ({ hasLegacyEntry: false, @@ -26,7 +26,7 @@ mock.module("../../shared/logger", () => ({ log: mockLog, })) -mock.module("./auto-migrate", () => ({ +mock.module("./auto-migrate-runner", () => ({ autoMigrateLegacyPluginEntry: mockAutoMigrate, })) diff --git a/src/hooks/legacy-plugin-toast/hook.ts b/src/hooks/legacy-plugin-toast/hook.ts index 4d6f55918..69f971f25 100644 --- a/src/hooks/legacy-plugin-toast/hook.ts +++ b/src/hooks/legacy-plugin-toast/hook.ts @@ -3,7 +3,7 @@ import type { PluginInput } from "@opencode-ai/plugin" import { checkForLegacyPluginEntry } from "../../shared/legacy-plugin-warning" import { log } from "../../shared/logger" import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "../../shared/plugin-identity" -import { autoMigrateLegacyPluginEntry } from "./auto-migrate" +import { autoMigrateLegacyPluginEntry } from "./auto-migrate-runner" export function createLegacyPluginToastHook(ctx: PluginInput) { let fired = false diff --git a/src/hooks/legacy-plugin-toast/plugin-entry-migrator.ts b/src/hooks/legacy-plugin-toast/plugin-entry-migrator.ts new file mode 100644 index 000000000..27aaaedc1 --- /dev/null +++ b/src/hooks/legacy-plugin-toast/plugin-entry-migrator.ts @@ -0,0 +1 @@ +export { migrateLegacyPluginEntry } from "../../shared/migrate-legacy-plugin-entry" diff --git a/src/shared/log-legacy-plugin-startup-warning.test.ts b/src/shared/log-legacy-plugin-startup-warning.test.ts index 4acd38385..0b288a461 100644 --- a/src/shared/log-legacy-plugin-startup-warning.test.ts +++ b/src/shared/log-legacy-plugin-startup-warning.test.ts @@ -26,7 +26,7 @@ mock.module("./logger", () => ({ log: mockLog, })) -mock.module("./migrate-legacy-plugin-entry", () => ({ +mock.module("./plugin-entry-migrator", () => ({ migrateLegacyPluginEntry: mockMigrateLegacyPluginEntry, })) diff --git a/src/shared/log-legacy-plugin-startup-warning.ts b/src/shared/log-legacy-plugin-startup-warning.ts index dc6505a5f..1ff3c7c19 100644 --- a/src/shared/log-legacy-plugin-startup-warning.ts +++ b/src/shared/log-legacy-plugin-startup-warning.ts @@ -1,6 +1,6 @@ import { checkForLegacyPluginEntry } from "./legacy-plugin-warning" import { log } from "./logger" -import { migrateLegacyPluginEntry } from "./migrate-legacy-plugin-entry" +import { migrateLegacyPluginEntry } from "./plugin-entry-migrator" import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "./plugin-identity" function toCanonicalEntry(entry: string): string { diff --git a/src/shared/plugin-entry-migrator.ts b/src/shared/plugin-entry-migrator.ts new file mode 100644 index 000000000..50cc7c1a1 --- /dev/null +++ b/src/shared/plugin-entry-migrator.ts @@ -0,0 +1 @@ +export { migrateLegacyPluginEntry } from "./migrate-legacy-plugin-entry"