|
|
@@ -32,44 +32,59 @@ export namespace Skill {
|
|
|
}),
|
|
|
)
|
|
|
|
|
|
- const SKILL_GLOB = new Bun.Glob("skill/**/SKILL.md")
|
|
|
+ const OPENCODE_SKILL_GLOB = new Bun.Glob("skill/**/SKILL.md")
|
|
|
+ const CLAUDE_SKILL_GLOB = new Bun.Glob(".claude/skills/**/SKILL.md")
|
|
|
|
|
|
export const state = Instance.state(async () => {
|
|
|
const directories = await Config.directories()
|
|
|
const skills: Record<string, Info> = {}
|
|
|
|
|
|
+ const addSkill = async (match: string) => {
|
|
|
+ const md = await ConfigMarkdown.parse(match)
|
|
|
+ if (!md) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const parsed = Info.pick({ name: true, description: true }).safeParse(md.data)
|
|
|
+ if (!parsed.success) return
|
|
|
+
|
|
|
+ // Warn on duplicate skill names
|
|
|
+ if (skills[parsed.data.name]) {
|
|
|
+ log.warn("duplicate skill name", {
|
|
|
+ name: parsed.data.name,
|
|
|
+ existing: skills[parsed.data.name].location,
|
|
|
+ duplicate: match,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ skills[parsed.data.name] = {
|
|
|
+ name: parsed.data.name,
|
|
|
+ description: parsed.data.description,
|
|
|
+ location: match,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
for (const dir of directories) {
|
|
|
- for await (const match of SKILL_GLOB.scan({
|
|
|
+ for await (const match of OPENCODE_SKILL_GLOB.scan({
|
|
|
cwd: dir,
|
|
|
absolute: true,
|
|
|
onlyFiles: true,
|
|
|
followSymlinks: true,
|
|
|
})) {
|
|
|
- const md = await ConfigMarkdown.parse(match)
|
|
|
- if (!md) {
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- const parsed = Info.pick({ name: true, description: true }).safeParse(md.data)
|
|
|
- if (!parsed.success) continue
|
|
|
-
|
|
|
- // Warn on duplicate skill names
|
|
|
- if (skills[parsed.data.name]) {
|
|
|
- log.warn("duplicate skill name", {
|
|
|
- name: parsed.data.name,
|
|
|
- existing: skills[parsed.data.name].location,
|
|
|
- duplicate: match,
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- skills[parsed.data.name] = {
|
|
|
- name: parsed.data.name,
|
|
|
- description: parsed.data.description,
|
|
|
- location: match,
|
|
|
- }
|
|
|
+ await addSkill(match)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ for await (const match of CLAUDE_SKILL_GLOB.scan({
|
|
|
+ cwd: Instance.worktree,
|
|
|
+ absolute: true,
|
|
|
+ onlyFiles: true,
|
|
|
+ followSymlinks: true,
|
|
|
+ dot: true,
|
|
|
+ })) {
|
|
|
+ await addSkill(match)
|
|
|
+ }
|
|
|
+
|
|
|
return skills
|
|
|
})
|
|
|
|