fix(shared): add additive opencode config directory discovery

This commit is contained in:
jollyxenon
2026-05-09 00:26:23 +08:00
parent 85c77007f0
commit 71025daeba
4 changed files with 102 additions and 20 deletions
+19 -11
View File
@@ -1,5 +1,5 @@
import { basename, dirname, join } from "node:path"
import { getOpenCodeConfigDir } from "./opencode-config-dir"
import { getOpenCodeConfigDirs } from "./opencode-config-dir"
import type { OpenCodeConfigDirOptions } from "./opencode-config-dir-types"
function getParentOpencodeConfigDir(configDir: string): string | null {
@@ -12,25 +12,33 @@ function getParentOpencodeConfigDir(configDir: string): string | null {
}
export function getOpenCodeCommandDirs(options: OpenCodeConfigDirOptions): string[] {
const configDir = getOpenCodeConfigDir(options)
const parentConfigDir = getParentOpencodeConfigDir(configDir)
const configDirs = getOpenCodeConfigDirs(options)
return Array.from(
new Set([
join(configDir, "commands"),
join(configDir, "command"),
...(parentConfigDir ? [join(parentConfigDir, "commands"), join(parentConfigDir, "command")] : []),
...configDirs.flatMap((configDir) => {
const parentConfigDir = getParentOpencodeConfigDir(configDir)
return [
join(configDir, "commands"),
join(configDir, "command"),
...(parentConfigDir ? [join(parentConfigDir, "commands"), join(parentConfigDir, "command")] : []),
]
}),
])
)
}
export function getOpenCodeSkillDirs(options: OpenCodeConfigDirOptions): string[] {
const configDir = getOpenCodeConfigDir(options)
const parentConfigDir = getParentOpencodeConfigDir(configDir)
const configDirs = getOpenCodeConfigDirs(options)
return Array.from(
new Set([
join(configDir, "skills"),
join(configDir, "skill"),
...(parentConfigDir ? [join(parentConfigDir, "skills"), join(parentConfigDir, "skill")] : []),
...configDirs.flatMap((configDir) => {
const parentConfigDir = getParentOpencodeConfigDir(configDir)
return [
join(configDir, "skills"),
join(configDir, "skill"),
...(parentConfigDir ? [join(parentConfigDir, "skills"), join(parentConfigDir, "skill")] : []),
]
}),
])
)
}
+20 -3
View File
@@ -3,6 +3,7 @@ import { homedir } from "node:os"
import { join, resolve, win32 } from "node:path"
import {
getOpenCodeConfigDir,
getOpenCodeConfigDirs,
getOpenCodeConfigPaths,
isDevBuild,
detectExistingConfigDir,
@@ -45,7 +46,7 @@ describe("opencode-config-dir", () => {
const result = getOpenCodeConfigDir({ binary: "opencode", version: "1.0.200" })
// then returns the custom path
expect(result).toBe("/custom/opencode/path")
expect(result).toBe(resolve("/custom/opencode/path"))
})
test("falls back to default when env var is not set", () => {
@@ -109,7 +110,23 @@ describe("opencode-config-dir", () => {
const result = getOpenCodeConfigDir({ binary: "opencode", version: "1.0.200" })
// then OPENCODE_CONFIG_DIR takes priority
expect(result).toBe("/custom/opencode/path")
expect(result).toBe(resolve("/custom/opencode/path"))
})
test("returns both custom and default config directories for additive discovery", () => {
// given both OPENCODE_CONFIG_DIR and XDG_CONFIG_HOME are set
process.env.OPENCODE_CONFIG_DIR = "/custom/opencode/path"
process.env.XDG_CONFIG_HOME = "/xdg/config"
Object.defineProperty(process, "platform", { value: "linux" })
// when getOpenCodeConfigDirs is called
const result = getOpenCodeConfigDirs({ binary: "opencode", version: "1.0.200" })
// then the custom path stays first, but the default global path remains visible
expect(result).toEqual([
resolve("/custom/opencode/path"),
resolve("/xdg/config/opencode"),
])
})
})
@@ -163,7 +180,7 @@ describe("opencode-config-dir", () => {
const result = getOpenCodeConfigDir({ binary: "opencode", version: "1.0.200" })
// then returns $XDG_CONFIG_HOME/opencode
expect(result).toBe("/custom/config/opencode")
expect(result).toBe(resolve("/custom/config/opencode"))
})
test("returns ~/.config/opencode on macOS", () => {
+27 -6
View File
@@ -55,16 +55,37 @@ function resolveConfigPath(pathValue: string): string {
}
}
function getCliConfigDir(): string {
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim()
if (envConfigDir) {
return resolveConfigPath(envConfigDir)
}
function getCliDefaultConfigDir(): string {
const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), ".config")
return resolveConfigPath(join(xdgConfig, "opencode"))
}
function getCliCustomConfigDir(): string | null {
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim()
if (!envConfigDir) {
return null
}
return resolveConfigPath(envConfigDir)
}
function getCliConfigDir(): string {
return getCliCustomConfigDir() ?? getCliDefaultConfigDir()
}
export function getOpenCodeConfigDirs(options: OpenCodeConfigDirOptions): string[] {
if (options.binary !== "opencode") {
return [getOpenCodeConfigDir(options)]
}
return Array.from(
new Set([
...(getCliCustomConfigDir() ? [getCliCustomConfigDir()!] : []),
getCliDefaultConfigDir(),
]),
)
}
export function getOpenCodeConfigDir(options: OpenCodeConfigDirOptions): string {
const { binary, version, checkExisting = true } = options