refactor(core): scope compatibility sources to skills

This commit is contained in:
kitlangton
2026-08-21 03:04:13 +00:00
parent 13dfb578ad
commit a5fed48b39
4 changed files with 32 additions and 18 deletions
+2 -2
View File
@@ -225,13 +225,13 @@ export const layer = (options?: Options) =>
// We load certain files from a few other folders in the ecosystem
const claude = [
...new Set([
globalClaudeDirectory,
...((yield* fs.isDir(globalClaudeDirectory)) ? [globalClaudeDirectory] : []),
...discovered.filter((item) => path.basename(item) === ".claude").toReversed(),
]),
].map((directory) => new ClaudeDirectory({ type: "claude", path: AbsolutePath.make(directory) }))
const agents = [
...new Set([
globalAgentsDirectory,
...((yield* fs.isDir(globalAgentsDirectory)) ? [globalAgentsDirectory] : []),
...discovered.filter((item) => path.basename(item) === ".agents").toReversed(),
]),
].map((directory) => new AgentsDirectory({ type: "agents", path: AbsolutePath.make(directory) }))
+8 -2
View File
@@ -80,8 +80,14 @@ export const Plugin = define({
if (result.some((item) => Skill.Source.equals(item, source))) return
result.push(source)
}
const claude = loaded.entries.flatMap((entry) => (entry.type === "claude" ? [entry.path] : []))
const agents = loaded.entries.flatMap((entry) => (entry.type === "agents" ? [entry.path] : []))
const claude = [
path.join(global.home, ".claude"),
...loaded.entries.flatMap((entry) => (entry.type === "claude" ? [entry.path] : [])),
]
const agents = [
path.join(global.home, ".agents"),
...loaded.entries.flatMap((entry) => (entry.type === "agents" ? [entry.path] : [])),
]
const directories = loaded.entries.flatMap((entry) => (entry.type === "directory" ? [entry.path] : []))
const items = loaded.entries.flatMap((entry) => (entry.type === "document" ? (entry.info.skills ?? []) : []))
for (const directory of [...claude, ...agents]) {
+2 -10
View File
@@ -4,7 +4,7 @@ import { describe, expect } from "bun:test"
import { Effect, Fiber, Layer, Logger, PubSub, Schema, Stream } from "effect"
import { FastCheck } from "effect/testing"
import { Config } from "@opencode-ai/core/config"
import { AgentsDirectory, ClaudeDirectory, Directory, Document, Event, Info } from "@opencode-ai/schema/config"
import { AgentsDirectory, Directory, Document, Event, Info } from "@opencode-ai/schema/config"
import { ConfigModel } from "@opencode-ai/schema/config/model"
import { ConfigProvider } from "@opencode-ai/schema/config/provider"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
@@ -793,7 +793,7 @@ describe("Config", () => {
}),
)
it.live("includes global compatibility directories before they exist", () =>
it.live("returns an empty configuration when directory files do not exist", () =>
Effect.acquireRelease(
Effect.promise(() => tmpdir()),
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
@@ -804,14 +804,6 @@ describe("Config", () => {
const entries = yield* config.entries()
expect(entries).toEqual([
new ClaudeDirectory({
type: "claude",
path: AbsolutePath.make(path.join(tmp.path, "global", "home", ".claude")),
}),
new AgentsDirectory({
type: "agents",
path: AbsolutePath.make(path.join(tmp.path, "global", "home", ".agents")),
}),
new Directory({ type: "directory", path: AbsolutePath.make(path.join(tmp.path, "global")) }),
])
}).pipe(Effect.provide(testLayer(tmp.path))),
+20 -4
View File
@@ -270,7 +270,12 @@ describe("ConfigSkillPlugin.Plugin", () => {
home,
)
const watcher = yield* Watcher.Test
expect(yield* watcher.subscriptions()).toEqual(expected.map((item) => ({ path: item, type: "directory" })))
expect(yield* watcher.subscriptions()).toEqual([
{ path: path.join(home, ".claude"), type: "file" },
{ path: expected[0], type: "directory" },
{ path: path.join(home, ".agents"), type: "file" },
...expected.slice(1).map((item) => ({ path: item, type: "directory" as const })),
])
}),
),
),
@@ -322,8 +327,9 @@ describe("ConfigSkillPlugin.Plugin", () => {
await write(worktreeSkills, "review", "Worktree")
})
const entries = yield* discover(worktree, path.join(tmp.path, "global"))
const skill = yield* startEntries(entries, worktree)
const global = path.join(tmp.path, "global")
const entries = yield* discover(worktree, global)
const skill = yield* startEntries(entries, worktree, path.join(global, "home"))
const review = (yield* skill.list()).find((item) => item.id === "review")
expect(review?.description).toBe("Worktree")
@@ -444,6 +450,8 @@ describe("ConfigSkillPlugin.Plugin", () => {
const watcher = yield* Watcher.Test
expect((yield* skill.list()).find((item) => item.id === "bro")?.description).toBe("First")
expect(yield* watcher.subscriptions()).toEqual([
{ path: path.join(tmp.path, ".claude"), type: "file" },
{ path: path.join(tmp.path, ".agents"), type: "file" },
{ path: first, type: "directory" },
{ path: source, type: "file" },
])
@@ -456,8 +464,12 @@ describe("ConfigSkillPlugin.Plugin", () => {
expect((yield* skill.list()).find((item) => item.id === "bro")?.description).toBe("Second")
expect(yield* watcher.subscriptions()).toEqual([
{ path: path.join(tmp.path, ".claude"), type: "file" },
{ path: path.join(tmp.path, ".agents"), type: "file" },
{ path: first, type: "directory" },
{ path: source, type: "file" },
{ path: path.join(tmp.path, ".claude"), type: "file" },
{ path: path.join(tmp.path, ".agents"), type: "file" },
{ path: second, type: "directory" },
{ path: source, type: "file" },
])
@@ -477,7 +489,11 @@ describe("ConfigSkillPlugin.Plugin", () => {
const skill = yield* start([source], tmp.path)
const watcher = yield* Watcher.Test
expect(yield* skill.list()).toEqual([])
expect(yield* watcher.subscriptions()).toEqual([{ path: path.join(tmp.path, "generated"), type: "file" }])
expect(yield* watcher.subscriptions()).toEqual([
{ path: path.join(tmp.path, ".claude"), type: "file" },
{ path: path.join(tmp.path, ".agents"), type: "file" },
{ path: path.join(tmp.path, "generated"), type: "file" },
])
yield* Effect.promise(() => fs.mkdir(path.join(tmp.path, "generated")))
yield* emitAndWait({ type: "create", path: path.join(tmp.path, "generated") })