瀏覽代碼

refactor(config): pass instance context to containsPath (#21882)

Brendan Allan 1 周之前
父節點
當前提交
b6af4d0dc6
共有 2 個文件被更改,包括 25 次插入19 次删除
  1. 21 16
      packages/opencode/src/config/config.ts
  2. 4 3
      packages/opencode/src/project/instance.ts

+ 21 - 16
packages/opencode/src/config/config.ts

@@ -41,6 +41,7 @@ import { Duration, Effect, Layer, Option, ServiceMap } from "effect"
 import { Flock } from "@/util/flock"
 import { isPathPluginSpec, parsePluginSpecifier, resolvePathPluginTarget } from "@/plugin/shared"
 import { Npm } from "@/npm"
+import { InstanceRef } from "@/effect/instance-ref"
 
 export namespace Config {
   const ModelId = z.string().meta({ $ref: "https://models.dev/model-schema.json#/$defs/Model" })
@@ -1327,27 +1328,31 @@ export namespace Config {
           const consoleManagedProviders = new Set<string>()
           let activeOrgName: string | undefined
 
-          const scope = (source: string): PluginScope => {
+          const scope = Effect.fnUntraced(function* (source: string) {
             if (source.startsWith("http://") || source.startsWith("https://")) return "global"
             if (source === "OPENCODE_CONFIG_CONTENT") return "local"
-            if (Instance.containsPath(source)) return "local"
+            if (yield* InstanceRef.use((ctx) => Effect.succeed(Instance.containsPath(source, ctx)))) return "local"
             return "global"
-          }
+          })
 
-          const track = (source: string, list: PluginSpec[] | undefined, kind?: PluginScope) => {
+          const track = Effect.fnUntraced(function* (
+            source: string,
+            list: PluginSpec[] | undefined,
+            kind?: PluginScope,
+          ) {
             if (!list?.length) return
-            const hit = kind ?? scope(source)
+            const hit = kind ?? (yield* scope(source))
             const plugins = deduplicatePluginOrigins([
               ...(result.plugin_origins ?? []),
               ...list.map((spec) => ({ spec, source, scope: hit })),
             ])
             result.plugin = plugins.map((item) => item.spec)
             result.plugin_origins = plugins
-          }
+          })
 
           const merge = (source: string, next: Info, kind?: PluginScope) => {
             result = mergeConfigConcatArrays(result, next)
-            track(source, next.plugin, kind)
+            return track(source, next.plugin, kind)
           }
 
           for (const [key, value] of Object.entries(auth)) {
@@ -1367,16 +1372,16 @@ export namespace Config {
                 dir: path.dirname(source),
                 source,
               })
-              merge(source, next, "global")
+              yield* merge(source, next, "global")
               log.debug("loaded remote config from well-known", { url })
             }
           }
 
           const global = yield* getGlobal()
-          merge(Global.Path.config, global, "global")
+          yield* merge(Global.Path.config, global, "global")
 
           if (Flag.OPENCODE_CONFIG) {
-            merge(Flag.OPENCODE_CONFIG, yield* loadFile(Flag.OPENCODE_CONFIG))
+            yield* merge(Flag.OPENCODE_CONFIG, yield* loadFile(Flag.OPENCODE_CONFIG))
             log.debug("loaded custom config", { path: Flag.OPENCODE_CONFIG })
           }
 
@@ -1384,7 +1389,7 @@ export namespace Config {
             for (const file of yield* Effect.promise(() =>
               ConfigPaths.projectFiles("opencode", ctx.directory, ctx.worktree),
             )) {
-              merge(file, yield* loadFile(file), "local")
+              yield* merge(file, yield* loadFile(file), "local")
             }
           }
 
@@ -1405,7 +1410,7 @@ export namespace Config {
               for (const file of ["opencode.json", "opencode.jsonc"]) {
                 const source = path.join(dir, file)
                 log.debug(`loading config from ${source}`)
-                merge(source, yield* loadFile(source))
+                yield* merge(source, yield* loadFile(source))
                 result.agent ??= {}
                 result.mode ??= {}
                 result.plugin ??= []
@@ -1424,7 +1429,7 @@ export namespace Config {
             result.agent = mergeDeep(result.agent, yield* Effect.promise(() => loadAgent(dir)))
             result.agent = mergeDeep(result.agent, yield* Effect.promise(() => loadMode(dir)))
             const list = yield* Effect.promise(() => loadPlugin(dir))
-            track(dir, list)
+            yield* track(dir, list)
           }
 
           if (process.env.OPENCODE_CONFIG_CONTENT) {
@@ -1433,7 +1438,7 @@ export namespace Config {
               dir: ctx.directory,
               source,
             })
-            merge(source, next, "local")
+            yield* merge(source, next, "local")
             log.debug("loaded custom config from OPENCODE_CONFIG_CONTENT")
           }
 
@@ -1462,7 +1467,7 @@ export namespace Config {
                 for (const providerID of Object.keys(next.provider ?? {})) {
                   consoleManagedProviders.add(providerID)
                 }
-                merge(source, next, "global")
+                yield* merge(source, next, "global")
               }
             }).pipe(
               Effect.catch((err) => {
@@ -1477,7 +1482,7 @@ export namespace Config {
           if (existsSync(managedDir)) {
             for (const file of ["opencode.json", "opencode.jsonc"]) {
               const source = path.join(managedDir, file)
-              merge(source, yield* loadFile(source), "global")
+              yield* merge(source, yield* loadFile(source), "global")
             }
           }
 

+ 4 - 3
packages/opencode/src/project/instance.ts

@@ -90,12 +90,13 @@ export const Instance = {
    * Returns true if path is inside Instance.directory OR Instance.worktree.
    * Paths within the worktree but outside the working directory should not trigger external_directory permission.
    */
-  containsPath(filepath: string) {
-    if (Filesystem.contains(Instance.directory, filepath)) return true
+  containsPath(filepath: string, ctx?: InstanceContext) {
+    const instance = ctx ?? Instance
+    if (Filesystem.contains(instance.directory, filepath)) return true
     // Non-git projects set worktree to "/" which would match ANY absolute path.
     // Skip worktree check in this case to preserve external_directory permissions.
     if (Instance.worktree === "/") return false
-    return Filesystem.contains(Instance.worktree, filepath)
+    return Filesystem.contains(instance.worktree, filepath)
   },
   /**
    * Captures the current instance ALS context and returns a wrapper that