import { existsSync, realpathSync } from "node:fs" import path from "node:path" import { pathToFileURL } from "node:url" export type RuntimeModuleLoader = () => Record | Promise> const runtimePackages = ["effect", "@opencode/plugin"] as const export function resolveHostPackageRoots(from = import.meta.dir, packages: readonly string[] = runtimePackages) { return packages.flatMap((pkgName) => { const dir = path.dirname(Bun.resolveSync(`${pkgName}/package.json`, from)) return [dir, findNodeModulesDir(pkgName, from, dir)] }) } export function loadRuntimeModules(): Readonly> { const entries = discoverPluginRuntimeSpecifiers() const effectEntry = entries.get("effect") if (effectEntry) require(effectEntry) return Object.fromEntries( [...entries.entries()].map(([specifier, resolved]) => [specifier, createLoader(resolved)]), ) } export function discoverPluginRuntimeSpecifiers( from = import.meta.dir, packages: readonly string[] = runtimePackages, ): ReadonlyMap { const entries = new Map() for (const pkgName of packages) { const realDir = path.dirname(Bun.resolveSync(`${pkgName}/package.json`, from)) // Resolve workspace @opencode/plugin paths via node_modules so OpenTUI does not wrap host files in async rewrite loaders. const loadDir = findNodeModulesDir(pkgName, from, realDir) const toLoadPath = (resolved: string) => loadDir === realDir ? resolved : path.join(loadDir, path.relative(realDir, resolved)) const rootEntry = Bun.resolveSync(pkgName, from) const relParts = path.relative(realDir, rootEntry).replaceAll("\\", "/").split("/") const scanDir = relParts.length > 1 ? path.join(realDir, relParts[0]) : realDir const ext = path.extname(rootEntry) || ".js" entries.set(pkgName, toLoadPath(rootEntry)) for (const file of new Bun.Glob(`**/*${ext}`).scanSync({ cwd: scanDir })) { const normalized = file.replaceAll("\\", "/") // The GUI SDK and its Vite preset (`gui/`) run in the desktop app and at build time, never in the server or the TUI. if ( normalized.startsWith("internal/") || normalized.includes("/internal/") || normalized.startsWith("source.") || normalized.startsWith("runtime") || normalized.startsWith("gui/") ) { continue } const base = normalized.slice(0, -ext.length) if (base === "index") continue const candidates = base.endsWith("/index") ? [`${pkgName}/${base.slice(0, -"/index".length)}`, `${pkgName}/${base}`] : [`${pkgName}/${base}`] for (const specifier of candidates) { if (entries.has(specifier)) continue try { entries.set(specifier, toLoadPath(Bun.resolveSync(specifier, from))) } catch {} } } } return entries } export function pluginRuntimeLoaderCode(specifier: string, entries: ReadonlyMap) { if (specifier.startsWith("effect/")) { const slash = specifier.lastIndexOf("/") const parent = specifier.slice(0, slash) const member = specifier.slice(slash + 1) const parentResolved = entries.get(parent) const resolved = entries.get(specifier) if ( member !== "index" && parentResolved && resolved && (require(parentResolved) as Record)[member] === require(resolved) ) { return `() => require(${JSON.stringify(parent)})[${JSON.stringify(member)}]` } } return `() => require(${JSON.stringify(specifier)})` } export function createLoader(resolved: string): RuntimeModuleLoader { let cached: Record | undefined let pending: Promise> | undefined return () => { if (cached) return cached if (pending) return pending try { return (cached = require(resolved) as Record) } catch { return (pending = import(pathToFileURL(resolved).href).then( (mod: Record) => (cached = mod), (error) => { pending = undefined throw error }, )) } } } function findNodeModulesDir(pkgName: string, from: string, realDir: string) { if (/[/\\]node_modules[/\\]/.test(realDir)) return realDir for (let dir = path.resolve(from); ; dir = path.dirname(dir)) { const candidate = path.join(dir, "node_modules", pkgName) if (existsSync(candidate) && realpathSync(candidate) === realDir) return candidate if (path.dirname(dir) === dir) return realDir } }