mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-14 03:56:55 +03:00
fix(core): preserve downloaded skill directory IDs (#45455)
This commit is contained in:
committed by
GitHub
Unverified
parent
5fb3040505
commit
5253603583
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@opencode-ai/core": patch
|
||||
---
|
||||
|
||||
Use parent directory names for SKILL.md IDs so individually downloaded skills do not overwrite each other.
|
||||
@@ -39,7 +39,9 @@ export function parse(directory: string, filepath: string, content: string): Par
|
||||
if (Result.isFailure(decoded)) return { _tag: "Skipped", reason: "frontmatter", issue: decoded.failure }
|
||||
const frontmatter = decoded.success
|
||||
const id =
|
||||
path.dirname(filepath) === directory ? path.basename(filepath, ".md") : path.basename(path.dirname(filepath))
|
||||
path.dirname(filepath) === directory && path.basename(filepath) !== "SKILL.md"
|
||||
? path.basename(filepath, ".md")
|
||||
: path.basename(path.dirname(filepath))
|
||||
const slash = metadataBoolean(frontmatter.metadata, "opencode/slash") ?? frontmatter.slash
|
||||
const autoinvoke = metadataBoolean(frontmatter.metadata, "opencode/autoinvoke")
|
||||
return {
|
||||
|
||||
@@ -162,6 +162,10 @@ metadata:
|
||||
_tag: "Parsed",
|
||||
skill: { id: Skill.ID.make("foo") },
|
||||
})
|
||||
expect(SkillFile.parse("/repo/skills/manual", "/repo/skills/manual/SKILL.md", "# manual")).toMatchObject({
|
||||
_tag: "Parsed",
|
||||
skill: { id: Skill.ID.make("manual"), name: Skill.Name.make("manual") },
|
||||
})
|
||||
expect(
|
||||
SkillFile.parse(directory, "/repo/skills/broken.md", "---\ndescription: foo: bar\nmetadata: [\n---\n# broken"),
|
||||
).toEqual({ _tag: "Skipped", reason: "markdown" })
|
||||
@@ -214,7 +218,7 @@ describe("ConfigSkillPlugin.Plugin", () => {
|
||||
),
|
||||
)
|
||||
|
||||
it.live("loads directory and URL sources with later-source precedence", () =>
|
||||
it.live("loads directory and individual downloaded skill roots with later-source precedence", () =>
|
||||
Effect.acquireRelease(
|
||||
Effect.promise(() => tmpdir()),
|
||||
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
||||
@@ -225,14 +229,24 @@ describe("ConfigSkillPlugin.Plugin", () => {
|
||||
const second = path.join(tmp.path, "second")
|
||||
yield* Effect.promise(async () => {
|
||||
await fs.mkdir(path.join(first, "review"), { recursive: true })
|
||||
await fs.mkdir(path.join(second, "deploy"), { recursive: true })
|
||||
await fs.mkdir(path.join(second, "review"), { recursive: true })
|
||||
await write(first, "review", "First")
|
||||
await write(second, "deploy", "Deploy")
|
||||
await write(second, "review", "Second")
|
||||
})
|
||||
pulls = 0
|
||||
urls.set("https://example.test/skills/", [AbsolutePath.make(second)])
|
||||
urls.set("https://example.test/skills/", [
|
||||
AbsolutePath.make(path.join(second, "deploy")),
|
||||
AbsolutePath.make(path.join(second, "review")),
|
||||
])
|
||||
|
||||
const skill = yield* start([first, "https://example.test/skills/"], tmp.path)
|
||||
expect((yield* skill.list()).map((item) => item.id).toSorted()).toEqual([
|
||||
Skill.ID.make("deploy"),
|
||||
Skill.ID.make("review"),
|
||||
])
|
||||
expect((yield* skill.list()).find((item) => item.id === "deploy")?.description).toBe("Deploy")
|
||||
expect((yield* skill.list()).find((item) => item.id === "review")?.description).toBe("Second")
|
||||
expect(pulls).toBe(1)
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user