|
|
@@ -3,7 +3,7 @@ import path from "path"
|
|
|
import { pathToFileURL } from "url"
|
|
|
import os from "os"
|
|
|
import z from "zod"
|
|
|
-import { mergeDeep, pipe } from "remeda"
|
|
|
+import { mergeDeep } from "remeda"
|
|
|
import { Global } from "@opencode-ai/core/global"
|
|
|
import fsNode from "fs/promises"
|
|
|
import { NamedError } from "@opencode-ai/core/util/error"
|
|
|
@@ -47,8 +47,13 @@ import { Npm } from "@opencode-ai/core/npm"
|
|
|
const log = Log.create({ service: "config" })
|
|
|
|
|
|
// Custom merge function that concatenates array fields instead of replacing them
|
|
|
+// Keep remeda's deep conditional merge type out of hot config-loading paths; TS profiling showed it dominates here.
|
|
|
+function mergeConfig(target: Info, source: Info): Info {
|
|
|
+ return mergeDeep(target, source) as Info
|
|
|
+}
|
|
|
+
|
|
|
function mergeConfigConcatArrays(target: Info, source: Info): Info {
|
|
|
- const merged = mergeDeep(target, source)
|
|
|
+ const merged = mergeConfig(target, source)
|
|
|
if (target.instructions && source.instructions) {
|
|
|
merged.instructions = Array.from(new Set([...target.instructions, ...source.instructions]))
|
|
|
}
|
|
|
@@ -387,12 +392,10 @@ export const layer = Layer.effect(
|
|
|
})
|
|
|
|
|
|
const loadGlobal = Effect.fnUntraced(function* () {
|
|
|
- let result: Info = pipe(
|
|
|
- {},
|
|
|
- mergeDeep(yield* loadFile(path.join(Global.Path.config, "config.json"))),
|
|
|
- mergeDeep(yield* loadFile(path.join(Global.Path.config, "opencode.json"))),
|
|
|
- mergeDeep(yield* loadFile(path.join(Global.Path.config, "opencode.jsonc"))),
|
|
|
- )
|
|
|
+ let result: Info = {}
|
|
|
+ result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "config.json")))
|
|
|
+ result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "opencode.json")))
|
|
|
+ result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "opencode.jsonc")))
|
|
|
|
|
|
const legacy = path.join(Global.Path.config, "config")
|
|
|
if (existsSync(legacy)) {
|
|
|
@@ -402,7 +405,7 @@ export const layer = Layer.effect(
|
|
|
const { provider, model, ...rest } = mod.default
|
|
|
if (provider && model) result.model = `${provider}/${model}`
|
|
|
result["$schema"] = "https://opencode.ai/config.json"
|
|
|
- result = mergeDeep(result, rest)
|
|
|
+ result = mergeConfig(result, rest)
|
|
|
await fsNode.writeFile(path.join(Global.Path.config, "config.json"), JSON.stringify(result, null, 2))
|
|
|
await fsNode.unlink(legacy)
|
|
|
})
|