From 310e319a477234b6d90dacd2af92be20a0a8ee9a Mon Sep 17 00:00:00 2001 From: spoons-and-mirrors <212802214+spoons-and-mirrors@users.noreply.github.com> Date: Sat, 31 Jan 2026 04:54:54 +0100 Subject: [PATCH] refactor: unify path resolve --- packages/opencode/src/config/config.ts | 31 +++++++++++++------- packages/opencode/src/session/instruction.ts | 3 -- packages/opencode/src/skill/skill.ts | 3 +- packages/opencode/src/util/filesystem.ts | 5 ++++ 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 7969e30795..da5c61c0b0 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -1162,10 +1162,7 @@ export namespace Config { if (lineIndex !== -1 && lines[lineIndex].trim().startsWith("//")) { continue // Skip if line is commented } - let filePath = match.replace(/^\{file:/, "").replace(/\}$/, "") - if (filePath.startsWith("~/")) { - filePath = path.join(os.homedir(), filePath.slice(2)) - } + const filePath = Filesystem.resolveTilde(match.replace(/^\{file:/, "").replace(/\}$/, "")) const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath) const fileContent = ( await Bun.file(resolvedPath) @@ -1222,14 +1219,26 @@ export namespace Config { await Bun.write(configFilepath, updated).catch(() => {}) } const data = parsed.data - if (data.plugin) { - for (let i = 0; i < data.plugin.length; i++) { - const plugin = data.plugin[i] - try { - data.plugin[i] = import.meta.resolve!(plugin, configFilepath) - } catch (err) {} + const expand = (arr?: string[]) => arr?.forEach((v, i) => (arr[i] = Filesystem.resolveTilde(v))) + + expand(data.instructions) + expand(data.plugin) + if (data.skills) expand(data.skills.paths) + + for (const mcp of Object.values(data.mcp ?? {})) + if (typeof mcp === "object" && "type" in mcp && mcp.type === "local") expand(mcp.command) + for (const lsp of Object.values(data.lsp ?? {})) + if (typeof lsp === "object" && "command" in lsp) expand(lsp.command) + for (const fmt of Object.values(data.formatter ?? {})) + if (typeof fmt === "object" && "command" in fmt) expand(fmt.command) + + data.plugin = data.plugin?.map((p: string) => { + try { + return import.meta.resolve!(p, configFilepath) + } catch { + return p } - } + }) return data } diff --git a/packages/opencode/src/session/instruction.ts b/packages/opencode/src/session/instruction.ts index 723439a3fd..071756f5c0 100644 --- a/packages/opencode/src/session/instruction.ts +++ b/packages/opencode/src/session/instruction.ts @@ -91,9 +91,6 @@ export namespace InstructionPrompt { if (config.instructions) { for (let instruction of config.instructions) { if (instruction.startsWith("https://") || instruction.startsWith("http://")) continue - if (instruction.startsWith("~/")) { - instruction = path.join(os.homedir(), instruction.slice(2)) - } const matches = path.isAbsolute(instruction) ? await Array.fromAsync( new Bun.Glob(path.basename(instruction)).scan({ diff --git a/packages/opencode/src/skill/skill.ts b/packages/opencode/src/skill/skill.ts index 5b300a9287..652c2a0c99 100644 --- a/packages/opencode/src/skill/skill.ts +++ b/packages/opencode/src/skill/skill.ts @@ -127,8 +127,7 @@ export namespace Skill { // Scan additional skill paths from config const config = await Config.get() for (const skillPath of config.skills?.paths ?? []) { - const expanded = skillPath.startsWith("~/") ? path.join(os.homedir(), skillPath.slice(2)) : skillPath - const resolved = path.isAbsolute(expanded) ? expanded : path.join(Instance.directory, expanded) + const resolved = path.isAbsolute(skillPath) ? skillPath : path.join(Instance.directory, skillPath) if (!(await Filesystem.isDir(resolved))) { log.warn("skill path not found", { path: resolved }) continue diff --git a/packages/opencode/src/util/filesystem.ts b/packages/opencode/src/util/filesystem.ts index 7aff6bd1d3..6898187e14 100644 --- a/packages/opencode/src/util/filesystem.ts +++ b/packages/opencode/src/util/filesystem.ts @@ -1,7 +1,12 @@ import { realpathSync } from "fs" import { dirname, join, relative } from "path" +import os from "os" export namespace Filesystem { + export function resolveTilde(p: string): string { + return p.startsWith("~/") ? join(os.homedir(), p.slice(2)) : p + } + export const exists = (p: string) => Bun.file(p) .stat()