fix(ci): resolve all test failures + complete rename compat layer

Sisyphus-authored fixes across 15 files:

- plugin-identity: align CONFIG_BASENAME with actual config file name
- add-plugin-to-opencode-config: handle legacy→canonical name migration
- plugin-detection tests: update expectations for new identity constants
- doctor/system: fix legacy name warning test assertions
- install tests: align with new plugin name
- chat-params tests: fix mock isolation
- model-capabilities tests: fix snapshot expectations
- image-converter: fix platform-dependent test assertions (Linux CI)
- example configs: expanded with more detailed comments

Full suite: 4484 pass, 0 fail, typecheck clean.
This commit is contained in:
YeonGyu-Kim
2026-03-26 18:04:31 +09:00
parent e86edca633
commit 4efc181390
17 changed files with 635 additions and 308 deletions
@@ -41,37 +41,39 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
const config = parseResult.config
const plugins = config.plugin ?? []
// Check for existing plugin (either current or legacy name)
const currentNameIndex = plugins.findIndex(
const canonicalEntries = plugins.filter(
(plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`)
)
const legacyNameIndex = plugins.findIndex(
const legacyEntries = plugins.filter(
(plugin) => plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)
)
const otherPlugins = plugins.filter(
(plugin) => !(plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`))
&& !(plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`))
)
// If either name exists, update to new name
if (currentNameIndex !== -1) {
if (plugins[currentNameIndex] === pluginEntry) {
return { success: true, configPath: path }
}
plugins[currentNameIndex] = pluginEntry
} else if (legacyNameIndex !== -1) {
// Upgrade legacy name to new name
plugins[legacyNameIndex] = pluginEntry
const normalizedPlugins = [...otherPlugins]
if (canonicalEntries.length > 0) {
normalizedPlugins.push(canonicalEntries[0])
} else if (legacyEntries.length > 0) {
const versionMatch = legacyEntries[0].match(/@(.+)$/)
const preservedVersion = versionMatch ? versionMatch[1] : null
normalizedPlugins.push(preservedVersion ? `${PLUGIN_NAME}@${preservedVersion}` : pluginEntry)
} else {
plugins.push(pluginEntry)
normalizedPlugins.push(pluginEntry)
}
config.plugin = plugins
config.plugin = normalizedPlugins
if (format === "jsonc") {
const content = readFileSync(path, "utf-8")
const pluginArrayRegex = /"plugin"\s*:\s*\[([\s\S]*?)\]/
const pluginArrayRegex = /((?:"plugin"|plugin)\s*:\s*)\[([\s\S]*?)\]/
const match = content.match(pluginArrayRegex)
if (match) {
const formattedPlugins = plugins.map((p) => `"${p}"`).join(",\n ")
const newContent = content.replace(pluginArrayRegex, `"plugin": [\n ${formattedPlugins}\n ]`)
const formattedPlugins = normalizedPlugins.map((p) => `"${p}"`).join(",\n ")
const newContent = content.replace(pluginArrayRegex, `$1[\n ${formattedPlugins}\n ]`)
writeFileSync(path, newContent)
} else {
const newContent = content.replace(/(\{)/, `$1\n "plugin": ["${pluginEntry}"],`)
+26 -89
View File
@@ -28,10 +28,9 @@ describe("detectCurrentConfig - single package detection", () => {
delete process.env.OPENCODE_CONFIG_DIR
})
it("detects oh-my-opencode in plugin array", () => {
it("detects both legacy and canonical plugin entries", () => {
// given
const config = { plugin: ["oh-my-opencode"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode", "oh-my-openagent@3.11.0"] }, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
@@ -40,58 +39,9 @@ describe("detectCurrentConfig - single package detection", () => {
expect(result.isInstalled).toBe(true)
})
it("detects oh-my-opencode with version pin", () => {
it("returns false when plugin not present with similar name", () => {
// given
const config = { plugin: ["oh-my-opencode@3.11.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("detects oh-my-openagent as installed (legacy name)", () => {
// given
const config = { plugin: ["oh-my-openagent"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("detects oh-my-openagent with version pin as installed (legacy name)", () => {
// given
const config = { plugin: ["oh-my-openagent@3.11.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("returns false when plugin not present", () => {
// given
const config = { plugin: ["some-other-plugin"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(false)
})
it("returns false when plugin not present (even with similar name)", () => {
// given - not exactly oh-my-openagent
const config = { plugin: ["oh-my-openagent-extra"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent-extra"] }, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
@@ -103,11 +53,7 @@ describe("detectCurrentConfig - single package detection", () => {
it("detects OpenCode Go from the existing omo config", () => {
// given
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode"] }, null, 2) + "\n", "utf-8")
writeFileSync(
testOmoConfigPath,
JSON.stringify({ agents: { atlas: { model: "opencode-go/kimi-k2.5" } } }, null, 2) + "\n",
"utf-8",
)
writeFileSync(testOmoConfigPath, JSON.stringify({ agents: { atlas: { model: "opencode-go/kimi-k2.5" } } }, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
@@ -137,10 +83,9 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
delete process.env.OPENCODE_CONFIG_DIR
})
it("keeps oh-my-opencode when it already exists", async () => {
it("writes canonical plugin entry for new installs", async () => {
// given
const config = { plugin: ["oh-my-opencode"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
writeFileSync(testConfigPath, JSON.stringify({}, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
@@ -148,13 +93,12 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-opencode")
expect(savedConfig.plugin).toEqual(["oh-my-openagent"])
})
it("replaces version-pinned oh-my-opencode@X.Y.Z", async () => {
it("upgrades a bare legacy plugin entry to canonical", async () => {
// given
const config = { plugin: ["oh-my-opencode@3.10.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode"] }, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
@@ -162,14 +106,12 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-opencode")
expect(savedConfig.plugin).not.toContain("oh-my-opencode@3.10.0")
expect(savedConfig.plugin).toEqual(["oh-my-openagent"])
})
it("recognizes oh-my-openagent as already installed (legacy name)", async () => {
it("upgrades a version-pinned legacy entry to canonical", async () => {
// given
const config = { plugin: ["oh-my-openagent"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode@3.10.0"] }, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
@@ -177,15 +119,12 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
// Should upgrade to new name
expect(savedConfig.plugin).toContain("oh-my-opencode")
expect(savedConfig.plugin).not.toContain("oh-my-openagent")
expect(savedConfig.plugin).toEqual(["oh-my-openagent@3.10.0"])
})
it("replaces version-pinned oh-my-openagent@X.Y.Z with new name", async () => {
it("removes stale legacy entry when canonical and legacy entries both exist", async () => {
// given
const config = { plugin: ["oh-my-openagent@3.10.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent", "oh-my-opencode"] }, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
@@ -193,15 +132,12 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
// Legacy should be replaced with new name
expect(savedConfig.plugin).toContain("oh-my-opencode")
expect(savedConfig.plugin).not.toContain("oh-my-openagent")
expect(savedConfig.plugin).toEqual(["oh-my-openagent"])
})
it("adds new plugin when none exists", async () => {
it("preserves a canonical entry when it already exists", async () => {
// given
const config = {}
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent@3.10.0"] }, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
@@ -209,20 +145,21 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-opencode")
expect(savedConfig.plugin).toEqual(["oh-my-openagent@3.10.0"])
})
it("adds plugin when plugin array is empty", async () => {
it("rewrites quoted jsonc plugin field in place", async () => {
// given
const config = { plugin: [] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
testConfigPath = join(testConfigDir, "opencode.jsonc")
writeFileSync(testConfigPath, '{\n "plugin": ["oh-my-opencode"]\n}\n', "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toContain("oh-my-opencode")
const savedContent = readFileSync(testConfigPath, "utf-8")
expect(savedContent.includes('"plugin": [\n "oh-my-openagent"\n ]')).toBe(true)
expect(savedContent.includes("oh-my-opencode")).toBe(false)
})
})