|
|
@@ -1,10 +1,11 @@
|
|
|
-import { describe, test, expect, beforeAll, afterAll } from "bun:test"
|
|
|
+import { describe, expect, beforeAll, afterAll } from "bun:test"
|
|
|
import { Effect } from "effect"
|
|
|
import { Discovery } from "../../src/skill/discovery"
|
|
|
import { Global } from "@opencode-ai/core/global"
|
|
|
import { Filesystem } from "@/util/filesystem"
|
|
|
import { rm } from "fs/promises"
|
|
|
import path from "path"
|
|
|
+import { testEffect } from "../lib/effect"
|
|
|
|
|
|
let CLOUDFLARE_SKILLS_URL: string
|
|
|
let server: ReturnType<typeof Bun.serve>
|
|
|
@@ -12,6 +13,7 @@ let downloadCount = 0
|
|
|
|
|
|
const fixturePath = path.join(import.meta.dir, "../fixture/skills")
|
|
|
const cacheDir = path.join(Global.Path.cache, "skills")
|
|
|
+const it = testEffect(Discovery.defaultLayer)
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
await rm(cacheDir, { recursive: true, force: true })
|
|
|
@@ -47,70 +49,83 @@ afterAll(async () => {
|
|
|
})
|
|
|
|
|
|
describe("Discovery.pull", () => {
|
|
|
- const pull = (url: string) =>
|
|
|
- Effect.runPromise(Discovery.Service.use((s) => s.pull(url)).pipe(Effect.provide(Discovery.defaultLayer)))
|
|
|
-
|
|
|
- test("downloads skills from cloudflare url", async () => {
|
|
|
- const dirs = await pull(CLOUDFLARE_SKILLS_URL)
|
|
|
- expect(dirs.length).toBeGreaterThan(0)
|
|
|
- for (const dir of dirs) {
|
|
|
- expect(dir).toStartWith(cacheDir)
|
|
|
- const md = path.join(dir, "SKILL.md")
|
|
|
- expect(await Filesystem.exists(md)).toBe(true)
|
|
|
- }
|
|
|
+ const pull = Effect.fn("DiscoveryTest.pull")(function* (url: string) {
|
|
|
+ return yield* Discovery.Service.use((s) => s.pull(url))
|
|
|
})
|
|
|
|
|
|
- test("url without trailing slash works", async () => {
|
|
|
- const dirs = await pull(CLOUDFLARE_SKILLS_URL.replace(/\/$/, ""))
|
|
|
- expect(dirs.length).toBeGreaterThan(0)
|
|
|
- for (const dir of dirs) {
|
|
|
- const md = path.join(dir, "SKILL.md")
|
|
|
- expect(await Filesystem.exists(md)).toBe(true)
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- test("returns empty array for invalid url", async () => {
|
|
|
- const dirs = await pull(`http://localhost:${server.port}/invalid-url/`)
|
|
|
- expect(dirs).toEqual([])
|
|
|
- })
|
|
|
-
|
|
|
- test("returns empty array for non-json response", async () => {
|
|
|
- // any url not explicitly handled in server returns 404 text "Not Found"
|
|
|
- const dirs = await pull(`http://localhost:${server.port}/some-other-path/`)
|
|
|
- expect(dirs).toEqual([])
|
|
|
- })
|
|
|
-
|
|
|
- test("downloads reference files alongside SKILL.md", async () => {
|
|
|
- const dirs = await pull(CLOUDFLARE_SKILLS_URL)
|
|
|
- // find a skill dir that should have reference files (e.g. agents-sdk)
|
|
|
- const agentsSdk = dirs.find((d) => d.endsWith(path.sep + "agents-sdk"))
|
|
|
- expect(agentsSdk).toBeDefined()
|
|
|
- if (agentsSdk) {
|
|
|
- const refs = path.join(agentsSdk, "references")
|
|
|
- expect(await Filesystem.exists(path.join(agentsSdk, "SKILL.md"))).toBe(true)
|
|
|
- // agents-sdk has reference files per the index
|
|
|
- const refDir = await Array.fromAsync(new Bun.Glob("**/*.md").scan({ cwd: refs, onlyFiles: true }))
|
|
|
- expect(refDir.length).toBeGreaterThan(0)
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- test("caches downloaded files on second pull", async () => {
|
|
|
- // clear dir and downloadCount
|
|
|
- await rm(cacheDir, { recursive: true, force: true })
|
|
|
- downloadCount = 0
|
|
|
-
|
|
|
- // first pull to populate cache
|
|
|
- const first = await pull(CLOUDFLARE_SKILLS_URL)
|
|
|
- expect(first.length).toBeGreaterThan(0)
|
|
|
- const firstCount = downloadCount
|
|
|
- expect(firstCount).toBeGreaterThan(0)
|
|
|
-
|
|
|
- // second pull should return same results from cache
|
|
|
- const second = await pull(CLOUDFLARE_SKILLS_URL)
|
|
|
- expect(second.length).toBe(first.length)
|
|
|
- expect(second.sort()).toEqual(first.sort())
|
|
|
-
|
|
|
- // second pull should NOT increment download count
|
|
|
- expect(downloadCount).toBe(firstCount)
|
|
|
- })
|
|
|
+ it.live("downloads skills from cloudflare url", () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const dirs = yield* pull(CLOUDFLARE_SKILLS_URL)
|
|
|
+ expect(dirs.length).toBeGreaterThan(0)
|
|
|
+ for (const dir of dirs) {
|
|
|
+ expect(dir).toStartWith(cacheDir)
|
|
|
+ const md = path.join(dir, "SKILL.md")
|
|
|
+ expect(yield* Effect.promise(() => Filesystem.exists(md))).toBe(true)
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ )
|
|
|
+
|
|
|
+ it.live("url without trailing slash works", () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const dirs = yield* pull(CLOUDFLARE_SKILLS_URL.replace(/\/$/, ""))
|
|
|
+ expect(dirs.length).toBeGreaterThan(0)
|
|
|
+ for (const dir of dirs) {
|
|
|
+ const md = path.join(dir, "SKILL.md")
|
|
|
+ expect(yield* Effect.promise(() => Filesystem.exists(md))).toBe(true)
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ )
|
|
|
+
|
|
|
+ it.live("returns empty array for invalid url", () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const dirs = yield* pull(`http://localhost:${server.port}/invalid-url/`)
|
|
|
+ expect(dirs).toEqual([])
|
|
|
+ }),
|
|
|
+ )
|
|
|
+
|
|
|
+ it.live("returns empty array for non-json response", () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ // any url not explicitly handled in server returns 404 text "Not Found"
|
|
|
+ const dirs = yield* pull(`http://localhost:${server.port}/some-other-path/`)
|
|
|
+ expect(dirs).toEqual([])
|
|
|
+ }),
|
|
|
+ )
|
|
|
+
|
|
|
+ it.live("downloads reference files alongside SKILL.md", () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const dirs = yield* pull(CLOUDFLARE_SKILLS_URL)
|
|
|
+ // find a skill dir that should have reference files (e.g. agents-sdk)
|
|
|
+ const agentsSdk = dirs.find((d) => d.endsWith(path.sep + "agents-sdk"))
|
|
|
+ expect(agentsSdk).toBeDefined()
|
|
|
+ if (agentsSdk) {
|
|
|
+ const refs = path.join(agentsSdk, "references")
|
|
|
+ expect(yield* Effect.promise(() => Filesystem.exists(path.join(agentsSdk, "SKILL.md")))).toBe(true)
|
|
|
+ // agents-sdk has reference files per the index
|
|
|
+ const refDir = yield* Effect.promise(() => Array.fromAsync(new Bun.Glob("**/*.md").scan({ cwd: refs, onlyFiles: true })))
|
|
|
+ expect(refDir.length).toBeGreaterThan(0)
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ )
|
|
|
+
|
|
|
+ it.live("caches downloaded files on second pull", () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ // clear dir and downloadCount
|
|
|
+ yield* Effect.promise(() => rm(cacheDir, { recursive: true, force: true }))
|
|
|
+ downloadCount = 0
|
|
|
+
|
|
|
+ // first pull to populate cache
|
|
|
+ const first = yield* pull(CLOUDFLARE_SKILLS_URL)
|
|
|
+ expect(first.length).toBeGreaterThan(0)
|
|
|
+ const firstCount = downloadCount
|
|
|
+ expect(firstCount).toBeGreaterThan(0)
|
|
|
+
|
|
|
+ // second pull should return same results from cache
|
|
|
+ const second = yield* pull(CLOUDFLARE_SKILLS_URL)
|
|
|
+ expect(second.length).toBe(first.length)
|
|
|
+ expect(second.sort()).toEqual(first.sort())
|
|
|
+
|
|
|
+ // second pull should NOT increment download count
|
|
|
+ expect(downloadCount).toBe(firstCount)
|
|
|
+ }),
|
|
|
+ )
|
|
|
})
|