fix(core): isolate location layer instances

This commit is contained in:
Dax Raad
2026-05-30 19:59:56 -04:00
parent b82aa3865b
commit 72cd2f5fa7
4 changed files with 61 additions and 8 deletions
+5 -1
View File
@@ -317,4 +317,8 @@ export const layer = Layer.effect(
const SMALL_MODEL_RE = /\b(nano|flash|lite|mini|haiku|small|fast)\b/
export const defaultLayer = layer.pipe(Layer.provide(EventV2.defaultLayer), Layer.provide(PluginV2.defaultLayer))
export const defaultLayer = layer.pipe(
Layer.provide(EventV2.defaultLayer),
Layer.provide(PluginV2.defaultLayer),
Layer.provide(Policy.defaultLayer),
)
+1
View File
@@ -199,4 +199,5 @@ export const layer = Layer.effect(
export const defaultLayer = layer.pipe(
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Global.defaultLayer),
Layer.provide(Policy.defaultLayer),
)
+5 -7
View File
@@ -2,18 +2,16 @@ import { Layer, LayerMap } from "effect"
import { Location } from "./location"
import { Catalog } from "./catalog"
import { PluginBoot } from "./plugin/boot"
import { Policy } from "./policy"
import { Config } from "./config"
import { AgentV2 } from "./agent"
export class LocationServiceMap extends LayerMap.Service<LocationServiceMap>()("@opencode/example/LocationServiceMap", {
lookup: (ref: Location.Ref) => {
const result = Layer.mergeAll(
Catalog.defaultLayer,
PluginBoot.defaultLayer,
Config.defaultLayer,
AgentV2.defaultLayer,
).pipe(Layer.provideMerge(Policy.defaultLayer), Layer.provideMerge(Location.defaultLayer(ref)))
const result = Layer.fresh(
Layer.mergeAll(Catalog.defaultLayer, PluginBoot.defaultLayer, Config.defaultLayer, AgentV2.defaultLayer).pipe(
Layer.provideMerge(Location.defaultLayer(ref)),
),
)
return result
},
idleTimeToLive: "60 minutes",
+50
View File
@@ -0,0 +1,50 @@
import fs from "fs/promises"
import path from "path"
import { describe, expect } from "bun:test"
import { Effect } from "effect"
import { Catalog } from "@opencode-ai/core/catalog"
import { LocationServiceMap } from "@opencode-ai/core/location-layer"
import { PluginBoot } from "@opencode-ai/core/plugin/boot"
import { ProviderV2 } from "@opencode-ai/core/provider"
import { AbsolutePath } from "@opencode-ai/core/schema"
import { tmpdir } from "./fixture/tmpdir"
import { testEffect } from "./lib/effect"
const it = testEffect(LocationServiceMap.layer)
describe("LocationServiceMap", () => {
it.live("isolates location state while sharing location policy with catalog", () =>
Effect.acquireRelease(
Effect.promise(() => Promise.all([tmpdir(), tmpdir()])),
(dirs) => Effect.promise(() => Promise.all(dirs.map((dir) => dir[Symbol.asyncDispose]())).then(() => undefined)),
).pipe(
Effect.flatMap(([blocked, allowed]) =>
Effect.gen(function* () {
yield* Effect.promise(() =>
fs.writeFile(
path.join(blocked.path, "opencode.json"),
JSON.stringify({
experimental: { policies: [{ effect: "deny", action: "provider.use", resource: "test" }] },
}),
),
)
const update = (directory: string) =>
Effect.gen(function* () {
yield* PluginBoot.Service.use((boot) => boot.wait())
const catalog = yield* Catalog.Service
const transform = yield* catalog.transform()
yield* transform((editor) => editor.provider.update(ProviderV2.ID.make("test"), () => {}))
return yield* catalog.provider.all()
}).pipe(
Effect.scoped,
Effect.provide(LocationServiceMap.get({ directory: AbsolutePath.make(directory) })),
)
expect((yield* update(blocked.path)).some((provider) => provider.id === ProviderV2.ID.make("test"))).toBe(false)
expect((yield* update(allowed.path)).some((provider) => provider.id === ProviderV2.ID.make("test"))).toBe(true)
}),
),
),
)
})