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	var discovered []*Skill
25
26	fs.WalkDir(builtinFS, "builtin", func(path string, d fs.DirEntry, err error) error {
27		if err != nil {
28			return nil
29		}
30		if d.IsDir() || d.Name() != SkillFileName {
31			return nil
32		}
33
34		content, err := builtinFS.ReadFile(path)
35		if err != nil {
36			slog.Warn("Failed to read builtin skill file", "path", path, "error", err)
37			return nil
38		}
39
40		skill, err := ParseContent(content)
41		if err != nil {
42			slog.Warn("Failed to parse builtin skill file", "path", path, "error", err)
43			return nil
44		}
45
46		// Set paths using the crush prefix. Strip the leading "builtin/"
47		// so the path is relative to the embedded root
48		// (e.g., "crush://skills/crush-config/SKILL.md").
49		relPath, _ := filepath.Rel("builtin", path)
50		relPath = filepath.ToSlash(relPath)
51		skill.SkillFilePath = BuiltinPrefix + relPath
52		skill.Path = BuiltinPrefix + filepath.Dir(relPath)
53		skill.Builtin = true
54
55		if err := skill.Validate(); err != nil {
56			slog.Warn("Builtin skill validation failed", "path", path, "error", err)
57			return nil
58		}
59
60		slog.Debug("Successfully loaded builtin skill", "name", skill.Name, "path", skill.SkillFilePath)
61		discovered = append(discovered, skill)
62		return nil
63	})
64
65	return discovered
66}