diff options
| author | Kit Langton <[email protected]> | 2026-04-01 12:13:13 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-01 16:13:13 +0000 |
| commit | 2f405daa983c950794aa3982584f59411f89bc50 (patch) | |
| tree | e33511b889de861f1584d3d49dd27061a2ba890c /packages | |
| parent | a9c85b7c2789f9363cbfeb9c1adceaddfbdbbdc3 (diff) | |
| download | opencode-2f405daa983c950794aa3982584f59411f89bc50.tar.gz opencode-2f405daa983c950794aa3982584f59411f89bc50.zip | |
refactor: use Effect services instead of async facades in provider, auth, and file (#20480)
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/opencode/src/effect/instance-state.ts | 8 | ||||
| -rw-r--r-- | packages/opencode/src/file/index.ts | 111 | ||||
| -rw-r--r-- | packages/opencode/src/provider/auth.ts | 33 | ||||
| -rw-r--r-- | packages/opencode/src/provider/provider.ts | 9 |
4 files changed, 79 insertions, 82 deletions
diff --git a/packages/opencode/src/effect/instance-state.ts b/packages/opencode/src/effect/instance-state.ts index b073cf0a4..cc5901fb5 100644 --- a/packages/opencode/src/effect/instance-state.ts +++ b/packages/opencode/src/effect/instance-state.ts @@ -24,9 +24,9 @@ export namespace InstanceState { return ((...args: any[]) => Instance.restore(ctx, () => fn(...args))) as F } - export const context = Effect.fnUntraced(function* () { + export const context = Effect.gen(function* () { return (yield* InstanceRef) ?? Instance.current - })() + }) export const directory = Effect.map(context, (ctx) => ctx.directory) @@ -37,9 +37,9 @@ export namespace InstanceState { const cache = yield* ScopedCache.make<string, A, E, R>({ capacity: Number.POSITIVE_INFINITY, lookup: () => - Effect.fnUntraced(function* () { + Effect.gen(function* () { return yield* init(yield* context) - })(), + }), }) const off = registerDisposer((directory) => Effect.runPromise(ScopedCache.invalidate(cache, directory))) diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts index 08b2faf6b..353f02c31 100644 --- a/packages/opencode/src/file/index.ts +++ b/packages/opencode/src/file/index.ts @@ -5,7 +5,6 @@ import { AppFileSystem } from "@/filesystem" import { git } from "@/util/git" import { Effect, Layer, ServiceMap } from "effect" import { formatPatch, structuredPatch } from "diff" -import fs from "fs" import fuzzysort from "fuzzysort" import ignore from "ignore" import path from "path" @@ -359,49 +358,46 @@ export namespace File { const isGlobalHome = Instance.directory === Global.Path.home && Instance.project.id === "global" const next: Entry = { files: [], dirs: [] } - yield* Effect.promise(async () => { - if (isGlobalHome) { - const dirs = new Set<string>() - const protectedNames = Protected.names() - const ignoreNested = new Set(["node_modules", "dist", "build", "target", "vendor"]) - const shouldIgnoreName = (name: string) => name.startsWith(".") || protectedNames.has(name) - const shouldIgnoreNested = (name: string) => name.startsWith(".") || ignoreNested.has(name) - const top = await fs.promises - .readdir(Instance.directory, { withFileTypes: true }) - .catch(() => [] as fs.Dirent[]) - - for (const entry of top) { - if (!entry.isDirectory()) continue - if (shouldIgnoreName(entry.name)) continue - dirs.add(entry.name + "/") - - const base = path.join(Instance.directory, entry.name) - const children = await fs.promises.readdir(base, { withFileTypes: true }).catch(() => [] as fs.Dirent[]) - for (const child of children) { - if (!child.isDirectory()) continue - if (shouldIgnoreNested(child.name)) continue - dirs.add(entry.name + "/" + child.name + "/") - } + if (isGlobalHome) { + const dirs = new Set<string>() + const protectedNames = Protected.names() + const ignoreNested = new Set(["node_modules", "dist", "build", "target", "vendor"]) + const shouldIgnoreName = (name: string) => name.startsWith(".") || protectedNames.has(name) + const shouldIgnoreNested = (name: string) => name.startsWith(".") || ignoreNested.has(name) + const top = yield* appFs.readDirectoryEntries(Instance.directory).pipe(Effect.orElseSucceed(() => [])) + + for (const entry of top) { + if (entry.type !== "directory") continue + if (shouldIgnoreName(entry.name)) continue + dirs.add(entry.name + "/") + + const base = path.join(Instance.directory, entry.name) + const children = yield* appFs.readDirectoryEntries(base).pipe(Effect.orElseSucceed(() => [])) + for (const child of children) { + if (child.type !== "directory") continue + if (shouldIgnoreNested(child.name)) continue + dirs.add(entry.name + "/" + child.name + "/") } + } - next.dirs = Array.from(dirs).toSorted() - } else { - const seen = new Set<string>() - for await (const file of Ripgrep.files({ cwd: Instance.directory })) { - next.files.push(file) - let current = file - while (true) { - const dir = path.dirname(current) - if (dir === ".") break - if (dir === current) break - current = dir - if (seen.has(dir)) continue - seen.add(dir) - next.dirs.push(dir + "/") - } + next.dirs = Array.from(dirs).toSorted() + } else { + const files = yield* Effect.promise(() => Array.fromAsync(Ripgrep.files({ cwd: Instance.directory }))) + const seen = new Set<string>() + for (const file of files) { + next.files.push(file) + let current = file + while (true) { + const dir = path.dirname(current) + if (dir === ".") break + if (dir === current) break + current = dir + if (seen.has(dir)) continue + seen.add(dir) + next.dirs.push(dir + "/") } } - }) + } const s = yield* InstanceState.get(state) s.cache = next @@ -636,30 +632,27 @@ export namespace File { yield* ensure() const { cache } = yield* InstanceState.get(state) - return yield* Effect.promise(async () => { - const query = input.query.trim() - const limit = input.limit ?? 100 - const kind = input.type ?? (input.dirs === false ? "file" : "all") - log.info("search", { query, kind }) + const query = input.query.trim() + const limit = input.limit ?? 100 + const kind = input.type ?? (input.dirs === false ? "file" : "all") + log.info("search", { query, kind }) - const result = cache - const preferHidden = query.startsWith(".") || query.includes("/.") + const preferHidden = query.startsWith(".") || query.includes("/.") - if (!query) { - if (kind === "file") return result.files.slice(0, limit) - return sortHiddenLast(result.dirs.toSorted(), preferHidden).slice(0, limit) - } + if (!query) { + if (kind === "file") return cache.files.slice(0, limit) + return sortHiddenLast(cache.dirs.toSorted(), preferHidden).slice(0, limit) + } - const items = - kind === "file" ? result.files : kind === "directory" ? result.dirs : [...result.files, ...result.dirs] + const items = + kind === "file" ? cache.files : kind === "directory" ? cache.dirs : [...cache.files, ...cache.dirs] - const searchLimit = kind === "directory" && !preferHidden ? limit * 20 : limit - const sorted = fuzzysort.go(query, items, { limit: searchLimit }).map((item) => item.target) - const output = kind === "directory" ? sortHiddenLast(sorted, preferHidden).slice(0, limit) : sorted + const searchLimit = kind === "directory" && !preferHidden ? limit * 20 : limit + const sorted = fuzzysort.go(query, items, { limit: searchLimit }).map((item) => item.target) + const output = kind === "directory" ? sortHiddenLast(sorted, preferHidden).slice(0, limit) : sorted - log.info("search", { query, kind, results: output.length }) - return output - }) + log.info("search", { query, kind, results: output.length }) + return output }) log.info("init") diff --git a/packages/opencode/src/provider/auth.ts b/packages/opencode/src/provider/auth.ts index fbfab6c3b..38ef4b11f 100644 --- a/packages/opencode/src/provider/auth.ts +++ b/packages/opencode/src/provider/auth.ts @@ -111,26 +111,25 @@ export namespace ProviderAuth { export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/ProviderAuth") {} - export const layer = Layer.effect( + export const layer: Layer.Layer<Service, never, Auth.Service | Plugin.Service> = Layer.effect( Service, Effect.gen(function* () { const auth = yield* Auth.Service + const plugin = yield* Plugin.Service const state = yield* InstanceState.make<State>( - Effect.fn("ProviderAuth.state")(() => - Effect.promise(async () => { - const plugins = await Plugin.list() - return { - hooks: Record.fromEntries( - Arr.filterMap(plugins, (x) => - x.auth?.provider !== undefined - ? Result.succeed([ProviderID.make(x.auth.provider), x.auth] as const) - : Result.failVoid, - ), + Effect.fn("ProviderAuth.state")(function* () { + const plugins = yield* plugin.list() + return { + hooks: Record.fromEntries( + Arr.filterMap(plugins, (x) => + x.auth?.provider !== undefined + ? Result.succeed([ProviderID.make(x.auth.provider), x.auth] as const) + : Result.failVoid, ), - pending: new Map<ProviderID, AuthOAuthResult>(), - } - }), - ), + ), + pending: new Map<ProviderID, AuthOAuthResult>(), + } + }), ) const methods = Effect.fn("ProviderAuth.methods")(function* () { @@ -230,7 +229,9 @@ export namespace ProviderAuth { }), ) - export const defaultLayer = layer.pipe(Layer.provide(Auth.defaultLayer)) + export const defaultLayer = Layer.suspend(() => + layer.pipe(Layer.provide(Auth.defaultLayer), Layer.provide(Plugin.defaultLayer)), + ) const { runPromise } = makeRuntime(Service, defaultLayer) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 40ab69e0f..861b34a7a 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -961,11 +961,12 @@ export namespace Provider { } } - const layer: Layer.Layer<Service, never, Config.Service | Auth.Service> = Layer.effect( + const layer: Layer.Layer<Service, never, Config.Service | Auth.Service | Plugin.Service> = Layer.effect( Service, Effect.gen(function* () { const config = yield* Config.Service const auth = yield* Auth.Service + const plugin = yield* Plugin.Service const state = yield* InstanceState.make<State>(() => Effect.gen(function* () { @@ -1128,7 +1129,7 @@ export namespace Provider { } } - const plugins = yield* Effect.promise(() => Plugin.list()) + const plugins = yield* plugin.list() for (const plugin of plugins) { if (!plugin.auth) continue const providerID = ProviderID.make(plugin.auth.provider) @@ -1541,7 +1542,9 @@ export namespace Provider { }), ) - export const defaultLayer = layer.pipe(Layer.provide(Config.defaultLayer), Layer.provide(Auth.defaultLayer)) + export const defaultLayer = Layer.suspend(() => + layer.pipe(Layer.provide(Config.defaultLayer), Layer.provide(Auth.defaultLayer), Layer.provide(Plugin.defaultLayer)), + ) const { runPromise } = makeRuntime(Service, defaultLayer) |
