diff options
| author | Luke Parker <[email protected]> | 2026-04-21 17:54:53 +1000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-21 07:54:53 +0000 |
| commit | 92c005866b99240a63b11602f3ffb541f844c257 (patch) | |
| tree | cbe7b02de6c9328dc38216f050091f4455e8aa18 | |
| parent | 224548d87d9aa9b8fdbcba2a8c1f96d5f2679ffa (diff) | |
| download | opencode-92c005866b99240a63b11602f3ffb541f844c257.tar.gz opencode-92c005866b99240a63b11602f3ffb541f844c257.zip | |
fix(core): use file:// URLs for local dynamic import() on Windows+Node (#23639)
| -rw-r--r-- | packages/opencode/src/provider/provider.ts | 6 | ||||
| -rw-r--r-- | packages/opencode/src/tool/registry.ts | 6 |
2 files changed, 8 insertions, 4 deletions
diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 6e116fe41..d643f2537 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -19,6 +19,7 @@ import { zod } from "@/util/effect-zod" import { iife } from "@/util/iife" import { Global } from "../global" import path from "path" +import { pathToFileURL } from "url" import { Effect, Layer, Context, Schema, Types } from "effect" import { EffectBridge } from "@/effect" import { InstanceState } from "@/effect" @@ -1506,7 +1507,10 @@ const layer: Layer.Layer< installedPath = model.api.npm } - const mod = await import(installedPath) + // `installedPath` is a local entry path or an existing `file://` URL. Normalize + // only path inputs so Node on Windows accepts the dynamic import. + const importSpec = installedPath.startsWith("file://") ? installedPath : pathToFileURL(installedPath).href + const mod = await import(importSpec) const fn = mod[Object.keys(mod).find((key) => key.startsWith("create"))!] const loaded = fn({ diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index e27593e59..0211e33bc 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -157,9 +157,9 @@ export const layer: Layer.Layer< if (matches.length) yield* config.waitForDependencies() for (const match of matches) { const namespace = path.basename(match, path.extname(match)) - const mod = yield* Effect.promise( - () => import(process.platform === "win32" ? match : pathToFileURL(match).href), - ) + // `match` is an absolute filesystem path from `Glob.scanSync(..., { absolute: true })`. + // Import it as `file://` so Node on Windows accepts the dynamic import. + const mod = yield* Effect.promise(() => import(pathToFileURL(match).href)) for (const [id, def] of Object.entries<ToolDefinition>(mod)) { custom.push(fromPlugin(id === "default" ? namespace : `${namespace}_${id}`, def)) } |
