Merge pull request #4248 from MoerAI/fix/getskillbyname-short-name
fix(opencode-skill-loader): align getSkillByName with short-name matching (fixes #4183)
This commit is contained in:
@@ -703,4 +703,90 @@ Skill body.
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("getSkillByName", () => {
|
||||
it("#given a discoverable skill #when getSkillByName is called with the exact full name #then it returns the skill", async () => {
|
||||
// given - a skill with a plain (non-namespaced) name
|
||||
const skillContent = `---
|
||||
name: my-exact-skill
|
||||
description: A skill resolvable by exact name
|
||||
---
|
||||
Body.
|
||||
`
|
||||
createTestSkill("my-exact-skill", skillContent)
|
||||
|
||||
// when
|
||||
const { getSkillByName } = await import("./loader")
|
||||
const originalCwd = process.cwd()
|
||||
process.chdir(TEST_DIR)
|
||||
|
||||
try {
|
||||
const skill = await getSkillByName("my-exact-skill", { includeClaudeCodePaths: false })
|
||||
|
||||
// then
|
||||
expect(skill).toBeDefined()
|
||||
expect(skill?.name).toBe("my-exact-skill")
|
||||
} finally {
|
||||
process.chdir(originalCwd)
|
||||
}
|
||||
})
|
||||
|
||||
it("#given a namespaced skill #when getSkillByName is called with its unique short name #then it returns the skill", async () => {
|
||||
// given - a namespaced skill that is the unique short-name match
|
||||
const skillContent = `---
|
||||
name: superpowers/systematic-debugging
|
||||
description: Namespaced skill the agent should be able to load by short name
|
||||
---
|
||||
Body.
|
||||
`
|
||||
createTestSkill("systematic-debugging", skillContent)
|
||||
|
||||
// when
|
||||
const { getSkillByName } = await import("./loader")
|
||||
const originalCwd = process.cwd()
|
||||
process.chdir(TEST_DIR)
|
||||
|
||||
try {
|
||||
const skill = await getSkillByName("systematic-debugging", { includeClaudeCodePaths: false })
|
||||
|
||||
// then - the short-name lookup must succeed, mirroring matchSkillByName semantics
|
||||
expect(skill).toBeDefined()
|
||||
expect(skill?.name).toBe("superpowers/systematic-debugging")
|
||||
} finally {
|
||||
process.chdir(originalCwd)
|
||||
}
|
||||
})
|
||||
|
||||
it("#given two namespaced skills sharing a short name #when getSkillByName is called with that short name #then it returns undefined (ambiguous)", async () => {
|
||||
// given - two skills under different namespaces with the same short name
|
||||
const skillA = `---
|
||||
name: alpha/duplicated
|
||||
description: Skill A
|
||||
---
|
||||
Body A.
|
||||
`
|
||||
const skillB = `---
|
||||
name: beta/duplicated
|
||||
description: Skill B
|
||||
---
|
||||
Body B.
|
||||
`
|
||||
createTestSkill("alpha-duplicated", skillA)
|
||||
createTestSkill("beta-duplicated", skillB)
|
||||
|
||||
// when
|
||||
const { getSkillByName } = await import("./loader")
|
||||
const originalCwd = process.cwd()
|
||||
process.chdir(TEST_DIR)
|
||||
|
||||
try {
|
||||
const skill = await getSkillByName("duplicated", { includeClaudeCodePaths: false })
|
||||
|
||||
// then - ambiguous short-name match must NOT resolve, matching matchSkillByName behavior
|
||||
expect(skill).toBeUndefined()
|
||||
} finally {
|
||||
process.chdir(originalCwd)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
findProjectClaudeSkillDirs,
|
||||
findProjectOpencodeSkillDirs,
|
||||
} from "../../shared/project-discovery-dirs"
|
||||
import { matchSkillByName } from "../../tools/skill/skill-matcher"
|
||||
import type { CommandDefinition } from "../claude-code-command-loader/types"
|
||||
import type { LoadedSkill } from "./types"
|
||||
import { skillsToCommandDefinitionRecord } from "./skill-definition-record"
|
||||
@@ -122,7 +123,7 @@ export async function discoverSkills(options: DiscoverSkillsOptions = {}): Promi
|
||||
|
||||
export async function getSkillByName(name: string, options: DiscoverSkillsOptions = {}): Promise<LoadedSkill | undefined> {
|
||||
const skills = await discoverSkills(options)
|
||||
return skills.find(s => s.name === name)
|
||||
return matchSkillByName(skills, name)
|
||||
}
|
||||
|
||||
export async function discoverUserClaudeSkills(): Promise<LoadedSkill[]> {
|
||||
|
||||
Reference in New Issue
Block a user