Merge pull request #239 from mvanhorn/osc/125-fix-install-config-overwrite
fix(install): merge config instead of overwriting on opencode target
This commit is contained in:
@@ -18,8 +18,8 @@ export async function mergeJsonConfigAtKey(options: {
|
||||
const merged = {
|
||||
...existing,
|
||||
[key]: {
|
||||
...existingEntries,
|
||||
...incoming,
|
||||
...existingEntries, // existing user entries win on conflict
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -58,12 +58,16 @@ export async function writeOpenCodeBundle(outputRoot: string, bundle: OpenCodeBu
|
||||
const openCodePaths = resolveOpenCodePaths(outputRoot)
|
||||
await ensureDir(openCodePaths.root)
|
||||
|
||||
const hadExistingConfig = await pathExists(openCodePaths.configPath)
|
||||
const backupPath = await backupFile(openCodePaths.configPath)
|
||||
if (backupPath) {
|
||||
console.log(`Backed up existing config to ${backupPath}`)
|
||||
}
|
||||
const merged = await mergeOpenCodeConfig(openCodePaths.configPath, bundle.config)
|
||||
await writeJson(openCodePaths.configPath, merged)
|
||||
if (hadExistingConfig) {
|
||||
console.log("Merged plugin config into existing opencode.json (user settings preserved)")
|
||||
}
|
||||
|
||||
const agentsDir = openCodePaths.agentsDir
|
||||
for (const agent of bundle.agents) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { promises as fs } from "fs"
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
import { writeOpenCodeBundle } from "../src/targets/opencode"
|
||||
import { mergeJsonConfigAtKey } from "../src/sync/json-config"
|
||||
import type { OpenCodeBundle } from "../src/types/opencode"
|
||||
|
||||
async function exists(filePath: string): Promise<boolean> {
|
||||
@@ -254,3 +255,38 @@ describe("writeOpenCodeBundle", () => {
|
||||
expect(backupContent).toBe("old content\n")
|
||||
})
|
||||
})
|
||||
|
||||
describe("mergeJsonConfigAtKey", () => {
|
||||
test("preserves existing user entries on conflict", async () => {
|
||||
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "json-merge-"))
|
||||
const configPath = path.join(tempDir, "opencode.json")
|
||||
|
||||
// User has an existing MCP server config
|
||||
const existingConfig = {
|
||||
model: "my-model",
|
||||
mcp: {
|
||||
"user-server": { type: "local", command: ["uvx", "user-srv"] },
|
||||
},
|
||||
}
|
||||
await fs.writeFile(configPath, JSON.stringify(existingConfig, null, 2))
|
||||
|
||||
// Plugin tries to add its own server and override user-server
|
||||
await mergeJsonConfigAtKey({
|
||||
configPath,
|
||||
key: "mcp",
|
||||
incoming: {
|
||||
"plugin-server": { type: "local", command: ["uvx", "plugin-srv"] },
|
||||
"user-server": { type: "local", command: ["uvx", "plugin-override"] },
|
||||
},
|
||||
})
|
||||
|
||||
const merged = JSON.parse(await fs.readFile(configPath, "utf8"))
|
||||
|
||||
// User's top-level keys preserved
|
||||
expect(merged.model).toBe("my-model")
|
||||
// Plugin server added
|
||||
expect(merged.mcp["plugin-server"]).toBeDefined()
|
||||
// User's server NOT overwritten by plugin
|
||||
expect(merged.mcp["user-server"].command[1]).toBe("user-srv")
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user