embed.go

 1package skills
 2
 3import (
 4	"embed"
 5	"io/fs"
 6	"log/slog"
 7	"path/filepath"
 8)
 9
10// BuiltinPrefix is the path prefix for builtin skill files. It is used by
11// the View tool to distinguish embedded files from disk files.
12const BuiltinPrefix = "crush://skills/"
13
14//go:embed builtin/*
15var builtinFS embed.FS
16
17// BuiltinFS returns the embedded filesystem containing builtin skills.
18func BuiltinFS() embed.FS {
19	return builtinFS
20}
21
22// DiscoverBuiltin finds all valid skills embedded in the binary.
23func DiscoverBuiltin() []*Skill {
24	skills, _ := DiscoverBuiltinWithStates()
25	return skills
26}
27
28// DiscoverBuiltinWithStates is like DiscoverBuiltin but additionally returns
29// a per-file state slice describing parse/validation outcomes. Useful for
30// diagnostics.
31func DiscoverBuiltinWithStates() ([]*Skill, []*SkillState) {
32	var discovered []*Skill
33	var states []*SkillState
34
35	fs.WalkDir(builtinFS, "builtin", func(path string, d fs.DirEntry, err error) error {
36		if err != nil {
37			return nil
38		}
39		if d.IsDir() || d.Name() != SkillFileName {
40			return nil
41		}
42
43		content, err := builtinFS.ReadFile(path)
44		if err != nil {
45			slog.Warn("Failed to read builtin skill file", "path", path, "error", err)
46			states = append(states, &SkillState{Path: path, State: StateError, Err: err})
47			return nil
48		}
49
50		skill, err := ParseContent(content)
51		if err != nil {
52			slog.Warn("Failed to parse builtin skill file", "path", path, "error", err)
53			states = append(states, &SkillState{Path: path, State: StateError, Err: err})
54			return nil
55		}
56
57		// Set paths using the crush prefix. Strip the leading "builtin/"
58		// so the path is relative to the embedded root
59		// (e.g., "crush://skills/crush-config/SKILL.md").
60		relPath, _ := filepath.Rel("builtin", path)
61		relPath = filepath.ToSlash(relPath)
62		skill.SkillFilePath = BuiltinPrefix + relPath
63		skill.Path = BuiltinPrefix + filepath.Dir(relPath)
64		skill.Builtin = true
65
66		if err := skill.Validate(); err != nil {
67			slog.Warn("Builtin skill validation failed", "path", path, "error", err)
68			states = append(states, &SkillState{Name: skill.Name, Path: path, State: StateError, Err: err})
69			return nil
70		}
71
72		slog.Debug("Successfully loaded builtin skill", "name", skill.Name, "path", skill.SkillFilePath)
73		discovered = append(discovered, skill)
74		states = append(states, &SkillState{Name: skill.Name, Path: skill.SkillFilePath, State: StateNormal})
75		return nil
76	})
77
78	return discovered, states
79}