diff --git a/packages/opencode/test/skill/discovery.test.ts b/packages/opencode/test/skill/discovery.test.ts index 0b07d4df0f..074992c56c 100644 --- a/packages/opencode/test/skill/discovery.test.ts +++ b/packages/opencode/test/skill/discovery.test.ts @@ -1,5 +1,6 @@ import { describe, expect, beforeAll, afterAll } from "bun:test" -import { Effect } from "effect" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { Effect, Layer } from "effect" import { Discovery } from "../../src/skill/discovery" import { Global } from "@opencode-ai/core/global" import { Filesystem } from "@/util/filesystem" @@ -13,7 +14,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) +const it = testEffect(Layer.mergeAll(Discovery.defaultLayer, AppFileSystem.defaultLayer)) beforeAll(async () => { await rm(cacheDir, { recursive: true, force: true }) @@ -49,36 +50,37 @@ afterAll(async () => { }) describe("Discovery.pull", () => { - const pull = Effect.fn("DiscoveryTest.pull")(function* (url: string) { - return yield* Discovery.Service.use((s) => s.pull(url)) - }) - it.live("downloads skills from cloudflare url", () => Effect.gen(function* () { - const dirs = yield* pull(CLOUDFLARE_SKILLS_URL) + const fsys = yield* AppFileSystem.Service + const discovery = yield* Discovery.Service + const dirs = yield* discovery.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) + expect(yield* fsys.existsSafe(md)).toBe(true) } }), ) it.live("url without trailing slash works", () => Effect.gen(function* () { - const dirs = yield* pull(CLOUDFLARE_SKILLS_URL.replace(/\/$/, "")) + const fsys = yield* AppFileSystem.Service + const discovery = yield* Discovery.Service + const dirs = yield* discovery.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) + expect(yield* fsys.existsSafe(md)).toBe(true) } }), ) it.live("returns empty array for invalid url", () => Effect.gen(function* () { - const dirs = yield* pull(`http://localhost:${server.port}/invalid-url/`) + const discovery = yield* Discovery.Service + const dirs = yield* discovery.pull(`http://localhost:${server.port}/invalid-url/`) expect(dirs).toEqual([]) }), ) @@ -86,20 +88,23 @@ describe("Discovery.pull", () => { 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/`) + const discovery = yield* Discovery.Service + const dirs = yield* discovery.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) + const fsys = yield* AppFileSystem.Service + const discovery = yield* Discovery.Service + const dirs = yield* discovery.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) + expect(yield* fsys.existsSafe(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 })), @@ -114,15 +119,16 @@ describe("Discovery.pull", () => { // clear dir and downloadCount yield* Effect.promise(() => rm(cacheDir, { recursive: true, force: true })) downloadCount = 0 + const discovery = yield* Discovery.Service // first pull to populate cache - const first = yield* pull(CLOUDFLARE_SKILLS_URL) + const first = yield* discovery.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) + const second = yield* discovery.pull(CLOUDFLARE_SKILLS_URL) expect(second.length).toBe(first.length) expect(second.sort()).toEqual(first.sort()) diff --git a/packages/opencode/test/snapshot/snapshot.test.ts b/packages/opencode/test/snapshot/snapshot.test.ts index fa167281b9..de60d58b2d 100644 --- a/packages/opencode/test/snapshot/snapshot.test.ts +++ b/packages/opencode/test/snapshot/snapshot.test.ts @@ -1,15 +1,15 @@ import { afterEach, expect } from "bun:test" import { $ } from "bun" import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner" +import { AppFileSystem } from "@opencode-ai/core/filesystem" import fs from "fs/promises" import path from "path" -import { Effect, Fiber } from "effect" +import { Effect, Fiber, Layer } from "effect" import { Snapshot } from "../../src/snapshot" -import { Filesystem } from "@/util/filesystem" import { disposeAllInstances, provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture" import { testEffect } from "../lib/effect" -const it = testEffect(Snapshot.defaultLayer) +const it = testEffect(Layer.mergeAll(Snapshot.defaultLayer, AppFileSystem.defaultLayer)) // Git always outputs /-separated paths internally. Snapshot.patch() joins them // with path.join (which produces \ on Windows) then normalizes back to /. @@ -27,17 +27,13 @@ const exec = (cwd: string, command: string[]) => if (code !== 0) throw new Error(`${command.join(" ")} failed: ${await new Response(proc.stderr).text()}`) }) -const write = (file: string, content: string | Uint8Array) => Effect.promise(() => Filesystem.write(file, content)) -const readText = (file: string) => Effect.promise(() => fs.readFile(file, "utf-8")) -const exists = (file: string) => - Effect.promise(() => - fs - .access(file) - .then(() => true) - .catch(() => false), - ) -const mkdirp = (dir: string) => Effect.promise(() => fs.mkdir(dir, { recursive: true })) -const rm = (file: string) => Effect.promise(() => fs.rm(file, { recursive: true, force: true })) +const write = (file: string, content: string | Uint8Array) => + AppFileSystem.Service.use((fs) => fs.writeWithDirs(file, content)) +const readText = (file: string) => AppFileSystem.Service.use((fs) => fs.readFileString(file)) +const exists = (file: string) => AppFileSystem.Service.use((fs) => fs.existsSafe(file)) +const mkdirp = (dir: string) => AppFileSystem.Service.use((fs) => fs.ensureDir(dir)) +const rm = (file: string) => + AppFileSystem.Service.use((fs) => fs.remove(file, { recursive: true, force: true }).pipe(Effect.ignore)) const initialize = Effect.fn("SnapshotTest.initialize")(function* (dir: string) { const unique = Math.random().toString(36).slice(2)