From 0e86466f990edd046867820b9fac97766d11db3f Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 16 Apr 2026 16:59:30 -0400 Subject: [PATCH] refactor: unwrap Discovery namespace to flat exports + self-reexport (#22878) --- packages/opencode/src/skill/discovery.ts | 208 +++++++++++------------ 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/packages/opencode/src/skill/discovery.ts b/packages/opencode/src/skill/discovery.ts index eff64ed2bb..debd68dd3d 100644 --- a/packages/opencode/src/skill/discovery.ts +++ b/packages/opencode/src/skill/discovery.ts @@ -6,111 +6,111 @@ import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { Global } from "../global" import { Log } from "../util" -export namespace Discovery { - const skillConcurrency = 4 - const fileConcurrency = 8 +const skillConcurrency = 4 +const fileConcurrency = 8 - class IndexSkill extends Schema.Class("IndexSkill")({ - name: Schema.String, - files: Schema.Array(Schema.String), - }) {} +class IndexSkill extends Schema.Class("IndexSkill")({ + name: Schema.String, + files: Schema.Array(Schema.String), +}) {} - class Index extends Schema.Class("Index")({ - skills: Schema.Array(IndexSkill), - }) {} +class Index extends Schema.Class("Index")({ + skills: Schema.Array(IndexSkill), +}) {} - export interface Interface { - readonly pull: (url: string) => Effect.Effect - } - - export class Service extends Context.Service()("@opencode/SkillDiscovery") {} - - export const layer: Layer.Layer = - Layer.effect( - Service, - Effect.gen(function* () { - const log = Log.create({ service: "skill-discovery" }) - const fs = yield* AppFileSystem.Service - const path = yield* Path.Path - const http = HttpClient.filterStatusOk(withTransientReadRetry(yield* HttpClient.HttpClient)) - const cache = path.join(Global.Path.cache, "skills") - - const download = Effect.fn("Discovery.download")(function* (url: string, dest: string) { - if (yield* fs.exists(dest).pipe(Effect.orDie)) return true - - return yield* HttpClientRequest.get(url).pipe( - http.execute, - Effect.flatMap((res) => res.arrayBuffer), - Effect.flatMap((body) => fs.writeWithDirs(dest, new Uint8Array(body))), - Effect.as(true), - Effect.catch((err) => - Effect.sync(() => { - log.error("failed to download", { url, err }) - return false - }), - ), - ) - }) - - const pull = Effect.fn("Discovery.pull")(function* (url: string) { - const base = url.endsWith("/") ? url : `${url}/` - const index = new URL("index.json", base).href - const host = base.slice(0, -1) - - log.info("fetching index", { url: index }) - - const data = yield* HttpClientRequest.get(index).pipe( - HttpClientRequest.acceptJson, - http.execute, - Effect.flatMap(HttpClientResponse.schemaBodyJson(Index)), - Effect.catch((err) => - Effect.sync(() => { - log.error("failed to fetch index", { url: index, err }) - return null - }), - ), - ) - - if (!data) return [] - - const list = data.skills.filter((skill) => { - if (!skill.files.includes("SKILL.md")) { - log.warn("skill entry missing SKILL.md", { url: index, skill: skill.name }) - return false - } - return true - }) - - const dirs = yield* Effect.forEach( - list, - (skill) => - Effect.gen(function* () { - const root = path.join(cache, skill.name) - - yield* Effect.forEach( - skill.files, - (file) => download(new URL(file, `${host}/${skill.name}/`).href, path.join(root, file)), - { - concurrency: fileConcurrency, - }, - ) - - const md = path.join(root, "SKILL.md") - return (yield* fs.exists(md).pipe(Effect.orDie)) ? root : null - }), - { concurrency: skillConcurrency }, - ) - - return dirs.filter((dir): dir is string => dir !== null) - }) - - return Service.of({ pull }) - }), - ) - - export const defaultLayer: Layer.Layer = layer.pipe( - Layer.provide(FetchHttpClient.layer), - Layer.provide(AppFileSystem.defaultLayer), - Layer.provide(NodePath.layer), - ) +export interface Interface { + readonly pull: (url: string) => Effect.Effect } + +export class Service extends Context.Service()("@opencode/SkillDiscovery") {} + +export const layer: Layer.Layer = + Layer.effect( + Service, + Effect.gen(function* () { + const log = Log.create({ service: "skill-discovery" }) + const fs = yield* AppFileSystem.Service + const path = yield* Path.Path + const http = HttpClient.filterStatusOk(withTransientReadRetry(yield* HttpClient.HttpClient)) + const cache = path.join(Global.Path.cache, "skills") + + const download = Effect.fn("Discovery.download")(function* (url: string, dest: string) { + if (yield* fs.exists(dest).pipe(Effect.orDie)) return true + + return yield* HttpClientRequest.get(url).pipe( + http.execute, + Effect.flatMap((res) => res.arrayBuffer), + Effect.flatMap((body) => fs.writeWithDirs(dest, new Uint8Array(body))), + Effect.as(true), + Effect.catch((err) => + Effect.sync(() => { + log.error("failed to download", { url, err }) + return false + }), + ), + ) + }) + + const pull = Effect.fn("Discovery.pull")(function* (url: string) { + const base = url.endsWith("/") ? url : `${url}/` + const index = new URL("index.json", base).href + const host = base.slice(0, -1) + + log.info("fetching index", { url: index }) + + const data = yield* HttpClientRequest.get(index).pipe( + HttpClientRequest.acceptJson, + http.execute, + Effect.flatMap(HttpClientResponse.schemaBodyJson(Index)), + Effect.catch((err) => + Effect.sync(() => { + log.error("failed to fetch index", { url: index, err }) + return null + }), + ), + ) + + if (!data) return [] + + const list = data.skills.filter((skill) => { + if (!skill.files.includes("SKILL.md")) { + log.warn("skill entry missing SKILL.md", { url: index, skill: skill.name }) + return false + } + return true + }) + + const dirs = yield* Effect.forEach( + list, + (skill) => + Effect.gen(function* () { + const root = path.join(cache, skill.name) + + yield* Effect.forEach( + skill.files, + (file) => download(new URL(file, `${host}/${skill.name}/`).href, path.join(root, file)), + { + concurrency: fileConcurrency, + }, + ) + + const md = path.join(root, "SKILL.md") + return (yield* fs.exists(md).pipe(Effect.orDie)) ? root : null + }), + { concurrency: skillConcurrency }, + ) + + return dirs.filter((dir): dir is string => dir !== null) + }) + + return Service.of({ pull }) + }), + ) + +export const defaultLayer: Layer.Layer = layer.pipe( + Layer.provide(FetchHttpClient.layer), + Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(NodePath.layer), +) + +export * as Discovery from "./discovery"