From 4d205027caa2a965a7bef85762f0b8a1526b344a Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Wed, 13 May 2026 17:07:53 +0530 Subject: [PATCH] refactor(flags): route scout through runtime flags (#27318) --- packages/opencode/src/agent/agent.ts | 6 +- packages/opencode/src/reference/reference.ts | 12 +- packages/opencode/test/agent/agent.test.ts | 122 +++++----- .../agent/plugin-agent-regression.test.ts | 1 + .../opencode/test/reference/reference.test.ts | 221 +++++++++--------- packages/opencode/test/tool/read.test.ts | 99 ++++---- 6 files changed, 227 insertions(+), 234 deletions(-) diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index 423a513180..1e4d7e1563 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -15,12 +15,12 @@ import PROMPT_TITLE from "./prompt/title.txt" import { Permission } from "@/permission" import { mergeDeep, pipe, sortBy, values } from "remeda" import { Global } from "@opencode-ai/core/global" -import { Flag } from "@opencode-ai/core/flag/flag" import path from "path" import { Plugin } from "@/plugin" import { Skill } from "../skill" import { Effect, Context, Layer, Schema } from "effect" import { InstanceState } from "@/effect/instance-state" +import { RuntimeFlags } from "@/effect/runtime-flags" import * as Option from "effect/Option" import * as OtelTracer from "@effect/opentelemetry/Tracer" import { type DeepMutable } from "@opencode-ai/core/schema" @@ -81,6 +81,7 @@ export const layer = Layer.effect( const plugin = yield* Plugin.Service const skill = yield* Skill.Service const provider = yield* Provider.Service + const flags = yield* RuntimeFlags.Service const state = yield* InstanceState.make( Effect.fn("Agent.state")(function* (ctx) { @@ -195,7 +196,7 @@ export const layer = Layer.effect( mode: "subagent", native: true, }, - ...(Flag.OPENCODE_EXPERIMENTAL_SCOUT + ...(flags.experimentalScout ? { scout: { name: "scout", @@ -453,6 +454,7 @@ export const defaultLayer = layer.pipe( Layer.provide(Auth.defaultLayer), Layer.provide(Config.defaultLayer), Layer.provide(Skill.defaultLayer), + Layer.provide(RuntimeFlags.defaultLayer), ) export * as Agent from "./agent" diff --git a/packages/opencode/src/reference/reference.ts b/packages/opencode/src/reference/reference.ts index 748c3b2386..3109c37492 100644 --- a/packages/opencode/src/reference/reference.ts +++ b/packages/opencode/src/reference/reference.ts @@ -1,10 +1,10 @@ import path from "path" import { Effect, Context, Layer, Scope } from "effect" import { AppFileSystem } from "@opencode-ai/core/filesystem" -import { Flag } from "@opencode-ai/core/flag/flag" import { Global } from "@opencode-ai/core/global" import { Config } from "@/config/config" import { InstanceState } from "@/effect/instance-state" +import { RuntimeFlags } from "@/effect/runtime-flags" import { Git } from "@/git" import { parseRepositoryReference, repositoryCachePath, type Reference as RepositoryReference } from "@/util/repository" import { RepositoryCache } from "./repository-cache" @@ -143,6 +143,7 @@ export const layer = Layer.effect( const fs = yield* AppFileSystem.Service const git = yield* Git.Service const scope = yield* Scope.Scope + const flags = yield* RuntimeFlags.Service const state = yield* InstanceState.make( Effect.fn("Reference.state")(function* (ctx) { @@ -181,7 +182,7 @@ export const layer = Layer.effect( ) const materializeAll = yield* Effect.cached( - Flag.OPENCODE_EXPERIMENTAL_SCOUT + flags.experimentalScout ? Effect.gen(function* () { yield* Effect.forEach( materializeByPath, @@ -200,7 +201,7 @@ export const layer = Layer.effect( return Service.of({ init: Effect.fn("Reference.init")(function* () { - if (!Flag.OPENCODE_EXPERIMENTAL_SCOUT) return + if (!flags.experimentalScout) return yield* InstanceState.useEffect(state, (s) => s.materializeAll).pipe(Effect.forkIn(scope), Effect.asVoid) }), list: Effect.fn("Reference.list")(function* () { @@ -210,7 +211,7 @@ export const layer = Layer.effect( return yield* InstanceState.use(state, (s) => s.references.find((reference) => reference.name === name)) }), ensure: Effect.fn("Reference.ensure")(function* (target?: string) { - if (!Flag.OPENCODE_EXPERIMENTAL_SCOUT) return + if (!flags.experimentalScout) return const full = normalizedTarget(target) if (!full) return yield* InstanceState.useEffect(state, (s) => s.materializeAll) return yield* InstanceState.useEffect( @@ -219,7 +220,7 @@ export const layer = Layer.effect( ) }), contains: Effect.fn("Reference.contains")(function* (target?: string) { - if (!Flag.OPENCODE_EXPERIMENTAL_SCOUT) return false + if (!flags.experimentalScout) return false const full = normalizedTarget(target) if (!full) return false return yield* InstanceState.use(state, (s) => @@ -234,6 +235,7 @@ export const defaultLayer = layer.pipe( Layer.provide(Config.defaultLayer), Layer.provide(AppFileSystem.defaultLayer), Layer.provide(Git.defaultLayer), + Layer.provide(RuntimeFlags.defaultLayer), ) export * as Reference from "./reference" diff --git a/packages/opencode/test/agent/agent.test.ts b/packages/opencode/test/agent/agent.test.ts index a781a855c3..e0defc1386 100644 --- a/packages/opencode/test/agent/agent.test.ts +++ b/packages/opencode/test/agent/agent.test.ts @@ -1,15 +1,31 @@ import { afterEach, expect } from "bun:test" -import { Cause, Effect, Exit } from "effect" +import { Cause, Effect, Exit, Layer } from "effect" import path from "path" import { disposeAllInstances, TestInstance } from "../fixture/fixture" import { testEffect } from "../lib/effect" import { Agent } from "../../src/agent/agent" +import { Auth } from "../../src/auth" +import { Config } from "../../src/config/config" +import { RuntimeFlags } from "../../src/effect/runtime-flags" import { Global } from "@opencode-ai/core/global" -import { Flag } from "@opencode-ai/core/flag/flag" import { Permission } from "../../src/permission" +import { Plugin } from "../../src/plugin" +import { Provider } from "../../src/provider/provider" +import { Skill } from "../../src/skill" import { Truncate } from "../../src/tool/truncate" -const it = testEffect(Agent.defaultLayer) +const agentLayer = (flags: Partial = {}) => + Agent.layer.pipe( + Layer.provide(Plugin.defaultLayer), + Layer.provide(Provider.defaultLayer), + Layer.provide(Auth.defaultLayer), + Layer.provide(Config.defaultLayer), + Layer.provide(Skill.defaultLayer), + Layer.provide(RuntimeFlags.layer(flags)), + ) + +const it = testEffect(agentLayer()) +const scout = testEffect(agentLayer({ experimentalScout: true })) // Helper to evaluate permission for a tool with wildcard pattern function evalPerm(agent: Agent.Info | undefined, permission: string): Permission.Action | undefined { @@ -21,21 +37,6 @@ function load(fn: (svc: Agent.Interface) => Effect.Effect) { return Agent.Service.use(fn) } -function withExperimentalScout(enabled: boolean, self: Effect.Effect) { - return Effect.acquireUseRelease( - Effect.sync(() => { - const original = Flag.OPENCODE_EXPERIMENTAL_SCOUT - Flag.OPENCODE_EXPERIMENTAL_SCOUT = enabled - return original - }), - () => self, - (original) => - Effect.sync(() => { - Flag.OPENCODE_EXPERIMENTAL_SCOUT = original - }), - ) -} - const expectDefaultAgentError = Effect.fn("AgentTest.expectDefaultAgentError")(function* (message: string) { const exit = yield* load((svc) => svc.defaultAgent()).pipe(Effect.exit) expect(Exit.isFailure(exit)).toBe(true) @@ -47,21 +48,18 @@ afterEach(async () => { }) it.instance("returns default native agents when no config", () => - withExperimentalScout( - false, - Effect.gen(function* () { - const agents = yield* load((svc) => svc.list()) - const names = agents.map((a) => a.name) - expect(names).toContain("build") - expect(names).toContain("plan") - expect(names).toContain("general") - expect(names).toContain("explore") - expect(names).not.toContain("scout") - expect(names).toContain("compaction") - expect(names).toContain("title") - expect(names).toContain("summary") - }), - ), + Effect.gen(function* () { + const agents = yield* load((svc) => svc.list()) + const names = agents.map((a) => a.name) + expect(names).toContain("build") + expect(names).toContain("plan") + expect(names).toContain("general") + expect(names).toContain("explore") + expect(names).not.toContain("scout") + expect(names).toContain("compaction") + expect(names).toContain("title") + expect(names).toContain("summary") + }), ) it.instance("build agent has correct default properties", () => @@ -111,42 +109,36 @@ it.instance("explore agent asks for external directories and allows whitelisted }), ) -it.instance("scout agent allows repo cloning and repo cache reads", () => - withExperimentalScout( - true, - Effect.gen(function* () { - const scout = yield* load((svc) => svc.get("scout")) - expect(scout).toBeDefined() - expect(scout?.mode).toBe("subagent") - expect(evalPerm(scout, "repo_clone")).toBe("allow") - expect(evalPerm(scout, "repo_overview")).toBe("allow") - expect(evalPerm(scout, "edit")).toBe("deny") - expect( - Permission.evaluate( - "external_directory", - path.join(Global.Path.repos, "github.com", "owner", "repo", "README.md"), - scout!.permission, - ).action, - ).toBe("allow") - }), - ), +scout.instance("scout agent allows repo cloning and repo cache reads", () => + Effect.gen(function* () { + const scout = yield* load((svc) => svc.get("scout")) + expect(scout).toBeDefined() + expect(scout?.mode).toBe("subagent") + expect(evalPerm(scout, "repo_clone")).toBe("allow") + expect(evalPerm(scout, "repo_overview")).toBe("allow") + expect(evalPerm(scout, "edit")).toBe("deny") + expect( + Permission.evaluate( + "external_directory", + path.join(Global.Path.repos, "github.com", "owner", "repo", "README.md"), + scout!.permission, + ).action, + ).toBe("allow") + }), ) -it.instance( +scout.instance( "reference config does not create subagents", () => - withExperimentalScout( - true, - Effect.gen(function* () { - const agents = yield* load((svc) => svc.list()) - const names = agents.map((agent) => agent.name) - expect(names).toContain("scout") - expect(names).not.toContain("effect") - expect(names).not.toContain("effectFull") - expect(names).not.toContain("localdocs") - expect(names).not.toContain("localdocsFull") - }), - ), + Effect.gen(function* () { + const agents = yield* load((svc) => svc.list()) + const names = agents.map((agent) => agent.name) + expect(names).toContain("scout") + expect(names).not.toContain("effect") + expect(names).not.toContain("effectFull") + expect(names).not.toContain("localdocs") + expect(names).not.toContain("localdocsFull") + }), { config: { reference: { diff --git a/packages/opencode/test/agent/plugin-agent-regression.test.ts b/packages/opencode/test/agent/plugin-agent-regression.test.ts index 60d59ee907..c437281cc6 100644 --- a/packages/opencode/test/agent/plugin-agent-regression.test.ts +++ b/packages/opencode/test/agent/plugin-agent-regression.test.ts @@ -41,6 +41,7 @@ const agentLayer = Agent.layer.pipe( Layer.provide(SkillTest.empty), Layer.provide(provider.layer), Layer.provide(pluginLayer), + Layer.provide(RuntimeFlags.layer({ disableDefaultPlugins: true })), ) const it = testEffect(Layer.mergeAll(agentLayer, pluginLayer)) diff --git a/packages/opencode/test/reference/reference.test.ts b/packages/opencode/test/reference/reference.test.ts index 4717c61d25..f4a73dbf9f 100644 --- a/packages/opencode/test/reference/reference.test.ts +++ b/packages/opencode/test/reference/reference.test.ts @@ -3,8 +3,9 @@ import path from "path" import { Effect, Layer } from "effect" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" -import { Flag } from "@opencode-ai/core/flag/flag" import { Global } from "@opencode-ai/core/global" +import { Config } from "../../src/config/config" +import { RuntimeFlags } from "../../src/effect/runtime-flags" import { Git } from "../../src/git" import { Reference } from "../../src/reference/reference" import { disposeAllInstances, provideTmpdirInstance, tmpdirScoped } from "../fixture/fixture" @@ -14,24 +15,26 @@ afterEach(async () => { await disposeAllInstances() }) -const it = testEffect( - Layer.mergeAll(AppFileSystem.defaultLayer, CrossSpawnSpawner.defaultLayer, Git.defaultLayer, Reference.defaultLayer), -) - -const experimentalScout = (self: Effect.Effect) => - Effect.acquireUseRelease( - Effect.sync(() => { - const previous = Flag.OPENCODE_EXPERIMENTAL_SCOUT - Flag.OPENCODE_EXPERIMENTAL_SCOUT = true - return previous - }), - () => self, - (previous) => - Effect.sync(() => { - Flag.OPENCODE_EXPERIMENTAL_SCOUT = previous - }), +const referenceLayer = (flags: Partial = {}) => + Reference.layer.pipe( + Layer.provide(Config.defaultLayer), + Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(Git.defaultLayer), + Layer.provide(RuntimeFlags.layer(flags)), ) +const it = testEffect( + Layer.mergeAll(AppFileSystem.defaultLayer, CrossSpawnSpawner.defaultLayer, Git.defaultLayer, referenceLayer()), +) +const scout = testEffect( + Layer.mergeAll( + AppFileSystem.defaultLayer, + CrossSpawnSpawner.defaultLayer, + Git.defaultLayer, + referenceLayer({ experimentalScout: true }), + ), +) + const githubBase = (url: string, self: Effect.Effect) => Effect.acquireUseRelease( Effect.sync(() => { @@ -127,118 +130,114 @@ describe("reference", () => { }), ) - it.live("materializes configured git references during init", () => - experimentalScout( - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-test", "repo") - yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) - yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) + scout.live("materializes configured git references during init", () => + provideTmpdirInstance( + (_dir) => + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-test", "repo") + yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) + yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) - const source = yield* tmpdirScoped({ git: true }) - const remoteRoot = yield* tmpdirScoped() - const remoteDir = path.join(remoteRoot, "opencode-reference-test") - const remoteRepo = path.join(remoteDir, "repo.git") + const source = yield* tmpdirScoped({ git: true }) + const remoteRoot = yield* tmpdirScoped() + const remoteDir = path.join(remoteRoot, "opencode-reference-test") + const remoteRepo = path.join(remoteDir, "repo.git") - yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "configured\n")) - yield* git(source, ["add", "."]) - yield* git(source, ["commit", "-m", "add readme"]) - yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) - yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) + yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "configured\n")) + yield* git(source, ["add", "."]) + yield* git(source, ["commit", "-m", "add readme"]) + yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) + yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) - const reference = yield* Reference.Service - yield* githubBase( - `file://${remoteRoot}/`, - Effect.gen(function* () { - yield* reference.init() - yield* waitForContent(fs, path.join(cache, "README.md"), "configured\n") - }), - ) + const reference = yield* Reference.Service + yield* githubBase( + `file://${remoteRoot}/`, + Effect.gen(function* () { + yield* reference.init() + yield* waitForContent(fs, path.join(cache, "README.md"), "configured\n") + }), + ) - expect(yield* fs.existsSafe(path.join(cache, ".git"))).toBe(true) - expect(yield* fs.readFileString(path.join(cache, "README.md"))).toBe("configured\n") + expect(yield* fs.existsSafe(path.join(cache, ".git"))).toBe(true) + expect(yield* fs.readFileString(path.join(cache, "README.md"))).toBe("configured\n") - const resolved = yield* reference.get("docs") - expect(resolved?.kind).toBe("git") - if (resolved?.kind === "git") expect(resolved.path).toBe(cache) - }), - { - config: { - reference: { - docs: "opencode-reference-test/repo", - }, + const resolved = yield* reference.get("docs") + expect(resolved?.kind).toBe("git") + if (resolved?.kind === "git") expect(resolved.path).toBe(cache) + }), + { + config: { + reference: { + docs: "opencode-reference-test/repo", }, }, - ), + }, ), ) - it.live("refreshes configured git references on new instance init", () => - experimentalScout( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-refresh", "repo") - yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) - yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) + scout.live("refreshes configured git references on new instance init", () => + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-refresh", "repo") + yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) + yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) - const source = yield* tmpdirScoped({ git: true }) - const remoteRoot = yield* tmpdirScoped() - const remoteDir = path.join(remoteRoot, "opencode-reference-refresh") - const remoteRepo = path.join(remoteDir, "repo.git") + const source = yield* tmpdirScoped({ git: true }) + const remoteRoot = yield* tmpdirScoped() + const remoteDir = path.join(remoteRoot, "opencode-reference-refresh") + const remoteRepo = path.join(remoteDir, "repo.git") - yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v1\n")) - yield* git(source, ["add", "."]) - yield* git(source, ["commit", "-m", "add readme"]) - yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) - yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) + yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v1\n")) + yield* git(source, ["add", "."]) + yield* git(source, ["commit", "-m", "add readme"]) + yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) + yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) - yield* githubBase( - `file://${remoteRoot}/`, - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const reference = yield* Reference.Service - yield* reference.init() - yield* waitForContent(fs, path.join(cache, "README.md"), "v1\n") - }), - { - config: { - reference: { - docs: "opencode-reference-refresh/repo", - }, + yield* githubBase( + `file://${remoteRoot}/`, + provideTmpdirInstance( + (_dir) => + Effect.gen(function* () { + const reference = yield* Reference.Service + yield* reference.init() + yield* waitForContent(fs, path.join(cache, "README.md"), "v1\n") + }), + { + config: { + reference: { + docs: "opencode-reference-refresh/repo", }, }, - ), - ) + }, + ), + ) - const branch = yield* git(source, ["branch", "--show-current"]) - yield* git(source, ["remote", "add", "origin", remoteRepo]) - yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v2\n")) - yield* git(source, ["add", "."]) - yield* git(source, ["commit", "-m", "update readme"]) - yield* git(source, ["push", "origin", `${branch}:${branch}`]) + const branch = yield* git(source, ["branch", "--show-current"]) + yield* git(source, ["remote", "add", "origin", remoteRepo]) + yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v2\n")) + yield* git(source, ["add", "."]) + yield* git(source, ["commit", "-m", "update readme"]) + yield* git(source, ["push", "origin", `${branch}:${branch}`]) - yield* githubBase( - `file://${remoteRoot}/`, - provideTmpdirInstance( - (_dir) => - Effect.gen(function* () { - const reference = yield* Reference.Service - yield* reference.init() - yield* waitForContent(fs, path.join(cache, "README.md"), "v2\n") - }), - { - config: { - reference: { - docs: "opencode-reference-refresh/repo", - }, + yield* githubBase( + `file://${remoteRoot}/`, + provideTmpdirInstance( + (_dir) => + Effect.gen(function* () { + const reference = yield* Reference.Service + yield* reference.init() + yield* waitForContent(fs, path.join(cache, "README.md"), "v2\n") + }), + { + config: { + reference: { + docs: "opencode-reference-refresh/repo", }, }, - ), - ) - }), - ), + }, + ), + ) + }), ) }) diff --git a/packages/opencode/test/tool/read.test.ts b/packages/opencode/test/tool/read.test.ts index 11bb1513f3..fcbd10bb4d 100644 --- a/packages/opencode/test/tool/read.test.ts +++ b/packages/opencode/test/tool/read.test.ts @@ -4,8 +4,10 @@ import path from "path" import { Agent } from "../../src/agent/agent" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" import { AppFileSystem } from "@opencode-ai/core/filesystem" -import { Flag } from "@opencode-ai/core/flag/flag" import { Global } from "@opencode-ai/core/global" +import { Config } from "@/config/config" +import { RuntimeFlags } from "@/effect/runtime-flags" +import { Git } from "@/git" import { LSP } from "@/lsp/lsp" import { Permission } from "../../src/permission" import { Instance } from "../../src/project/instance" @@ -36,17 +38,27 @@ const ctx = { ask: () => Effect.void, } -const it = testEffect( +const referenceLayer = (flags: Partial = {}) => + Reference.layer.pipe( + Layer.provide(Config.defaultLayer), + Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(Git.defaultLayer), + Layer.provide(RuntimeFlags.layer(flags)), + ) + +const readLayer = (flags: Partial = {}) => Layer.mergeAll( Agent.defaultLayer, AppFileSystem.defaultLayer, CrossSpawnSpawner.defaultLayer, Instruction.defaultLayer, LSP.defaultLayer, - Reference.defaultLayer, + referenceLayer(flags), Truncate.defaultLayer, - ), -) + ) + +const it = testEffect(readLayer()) +const scout = testEffect(readLayer({ experimentalScout: true })) const init = Effect.fn("ReadToolTest.init")(function* () { const info = yield* ReadTool @@ -85,19 +97,6 @@ const fail = Effect.fn("ReadToolTest.fail")(function* ( const full = (p: string) => (process.platform === "win32" ? Filesystem.normalizePath(p) : p) const glob = (p: string) => process.platform === "win32" ? Filesystem.normalizePathPattern(p) : p.replaceAll("\\", "/") -const experimentalScout = (self: Effect.Effect) => - Effect.acquireUseRelease( - Effect.sync(() => { - const previous = Flag.OPENCODE_EXPERIMENTAL_SCOUT - Flag.OPENCODE_EXPERIMENTAL_SCOUT = true - return previous - }), - () => self, - (previous) => - Effect.sync(() => { - Flag.OPENCODE_EXPERIMENTAL_SCOUT = previous - }), - ) const githubBase = (url: string, self: Effect.Effect) => Effect.acquireUseRelease( Effect.sync(() => { @@ -260,44 +259,42 @@ describe("tool.read external_directory permission", () => { }), ) - it.live("does not ask for external_directory permission when reading configured references", () => - experimentalScout( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - const cache = path.join(Global.Path.repos, "github.com", "opencode-read-reference", "repo") - yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) - yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) + scout.live("does not ask for external_directory permission when reading configured references", () => + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const cache = path.join(Global.Path.repos, "github.com", "opencode-read-reference", "repo") + yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore) + yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore)) - const source = yield* tmpdirScoped({ git: true }) - const remoteRoot = yield* tmpdirScoped() - const remoteDir = path.join(remoteRoot, "opencode-read-reference") - const remoteRepo = path.join(remoteDir, "repo.git") - yield* put(path.join(source, "notes.md"), "reference notes") - yield* git(source, ["add", "."]) - yield* git(source, ["commit", "-m", "add notes"]) - yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) - yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) + const source = yield* tmpdirScoped({ git: true }) + const remoteRoot = yield* tmpdirScoped() + const remoteDir = path.join(remoteRoot, "opencode-read-reference") + const remoteRepo = path.join(remoteDir, "repo.git") + yield* put(path.join(source, "notes.md"), "reference notes") + yield* git(source, ["add", "."]) + yield* git(source, ["commit", "-m", "add notes"]) + yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) + yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) - const dir = yield* tmpdirScoped({ - git: true, - config: { - reference: { - docs: "opencode-read-reference/repo", - }, + const dir = yield* tmpdirScoped({ + git: true, + config: { + reference: { + docs: "opencode-read-reference/repo", }, - }) + }, + }) - const { items, next } = asks() - const result = yield* githubBase( - `file://${remoteRoot}/`, - exec(dir, { filePath: path.join(cache, "notes.md") }, next), - ) - const ext = items.find((item) => item.permission === "external_directory") + const { items, next } = asks() + const result = yield* githubBase( + `file://${remoteRoot}/`, + exec(dir, { filePath: path.join(cache, "notes.md") }, next), + ) + const ext = items.find((item) => item.permission === "external_directory") - expect(result.output).toContain("reference notes") - expect(ext).toBeUndefined() - }), - ), + expect(result.output).toContain("reference notes") + expect(ext).toBeUndefined() + }), ) })