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 <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-04-04 01:32:59 +09:00
parent 290f7f9543
commit f03c6700d4
8 changed files with 18 additions and 25 deletions
@@ -0,0 +1,2 @@
export { autoMigrateLegacyPluginEntry } from "./auto-migrate"
export type { MigrationResult } from "./auto-migrate"
+9 -20
View File
@@ -1,9 +1,10 @@
import { existsSync, readFileSync, writeFileSync } from "node:fs" import { existsSync, readFileSync } from "node:fs"
import { join } from "node:path" import { join } from "node:path"
import { parseJsoncSafe } from "../../shared/jsonc-parser" import { parseJsoncSafe } from "../../shared/jsonc-parser"
import { getOpenCodeConfigPaths } from "../../shared/opencode-config-dir" import { getOpenCodeConfigPaths } from "../../shared/opencode-config-dir"
import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "../../shared/plugin-identity" import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "../../shared/plugin-identity"
import { migrateLegacyPluginEntry } from "./plugin-entry-migrator"
export interface MigrationResult { export interface MigrationResult {
migrated: boolean migrated: boolean
@@ -63,27 +64,15 @@ export function autoMigrateLegacyPluginEntry(overrideConfigDir?: string): Migrat
const hasCanonical = plugins.some(isCanonicalEntry) const hasCanonical = plugins.some(isCanonicalEntry)
const from = legacyEntries[0] const from = legacyEntries[0]
const to = toLegacyCanonical(from) const to = toLegacyCanonical(from)
const migrated = migrateLegacyPluginEntry(configPath)
if (!migrated) return { migrated: false, from: null, to: null, configPath }
const normalized = hasCanonical return {
? plugins.filter((p) => !isLegacyEntry(p)) migrated: true,
: plugins.map((p) => (isLegacyEntry(p) ? toLegacyCanonical(p) : p)) from,
to: hasCanonical ? PLUGIN_NAME : to,
const isJsonc = configPath.endsWith(".jsonc") configPath,
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 }
}
} }
const parsed = JSON.parse(content) as Record<string, unknown>
parsed.plugin = normalized
writeFileSync(configPath, JSON.stringify(parsed, null, 2) + "\n")
return { migrated: true, from, to, configPath }
} catch { } catch {
return { migrated: false, from: null, to: null, configPath } return { migrated: false, from: null, to: null, configPath }
} }
+2 -2
View File
@@ -1,5 +1,5 @@
import { afterAll, beforeEach, describe, expect, it, mock } from "bun:test" 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(() => ({ const mockCheckForLegacyPluginEntry = mock(() => ({
hasLegacyEntry: false, hasLegacyEntry: false,
@@ -26,7 +26,7 @@ mock.module("../../shared/logger", () => ({
log: mockLog, log: mockLog,
})) }))
mock.module("./auto-migrate", () => ({ mock.module("./auto-migrate-runner", () => ({
autoMigrateLegacyPluginEntry: mockAutoMigrate, autoMigrateLegacyPluginEntry: mockAutoMigrate,
})) }))
+1 -1
View File
@@ -3,7 +3,7 @@ import type { PluginInput } from "@opencode-ai/plugin"
import { checkForLegacyPluginEntry } from "../../shared/legacy-plugin-warning" import { checkForLegacyPluginEntry } from "../../shared/legacy-plugin-warning"
import { log } from "../../shared/logger" import { log } from "../../shared/logger"
import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "../../shared/plugin-identity" 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) { export function createLegacyPluginToastHook(ctx: PluginInput) {
let fired = false let fired = false
@@ -0,0 +1 @@
export { migrateLegacyPluginEntry } from "../../shared/migrate-legacy-plugin-entry"
@@ -26,7 +26,7 @@ mock.module("./logger", () => ({
log: mockLog, log: mockLog,
})) }))
mock.module("./migrate-legacy-plugin-entry", () => ({ mock.module("./plugin-entry-migrator", () => ({
migrateLegacyPluginEntry: mockMigrateLegacyPluginEntry, migrateLegacyPluginEntry: mockMigrateLegacyPluginEntry,
})) }))
@@ -1,6 +1,6 @@
import { checkForLegacyPluginEntry } from "./legacy-plugin-warning" import { checkForLegacyPluginEntry } from "./legacy-plugin-warning"
import { log } from "./logger" 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" import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "./plugin-identity"
function toCanonicalEntry(entry: string): string { function toCanonicalEntry(entry: string): string {
+1
View File
@@ -0,0 +1 @@
export { migrateLegacyPluginEntry } from "./migrate-legacy-plugin-entry"