parseYAML 解析 YAML 配置
(yamlContent string, skill *SkillDefinition)
| 75 | |
| 76 | // parseYAML 解析 YAML 配置 |
| 77 | func (sl *SkillLoader) parseYAML(yamlContent string, skill *SkillDefinition) error { |
| 78 | var config struct { |
| 79 | Name string `yaml:"name"` |
| 80 | Description string `yaml:"description"` |
| 81 | AllowedTools []string `yaml:"allowed-tools"` |
| 82 | |
| 83 | Kind string `yaml:"kind"` |
| 84 | |
| 85 | Parameters map[string]struct { |
| 86 | Type string `yaml:"type"` |
| 87 | Description string `yaml:"description"` |
| 88 | Required bool `yaml:"required"` |
| 89 | Enum []string `yaml:"enum"` |
| 90 | } `yaml:"parameters"` |
| 91 | |
| 92 | Returns map[string]struct { |
| 93 | Type string `yaml:"type"` |
| 94 | Description string `yaml:"description"` |
| 95 | } `yaml:"returns"` |
| 96 | |
| 97 | Executable *struct { |
| 98 | Runtime string `yaml:"runtime"` |
| 99 | Entry string `yaml:"entry"` |
| 100 | TimeoutSeconds int `yaml:"timeout"` |
| 101 | } `yaml:"executable"` |
| 102 | |
| 103 | Triggers []struct { |
| 104 | Type string `yaml:"type"` |
| 105 | Keywords []string `yaml:"keywords"` |
| 106 | Condition string `yaml:"condition"` |
| 107 | Pattern string `yaml:"pattern"` |
| 108 | } `yaml:"triggers"` |
| 109 | } |
| 110 | |
| 111 | if err := yaml.Unmarshal([]byte(yamlContent), &config); err != nil { |
| 112 | return err |
| 113 | } |
| 114 | |
| 115 | if config.Name != "" { |
| 116 | skill.Name = config.Name |
| 117 | } |
| 118 | skill.Description = config.Description |
| 119 | skill.AllowedTools = config.AllowedTools |
| 120 | |
| 121 | // 验证名称和描述 |
| 122 | if skill.Name == "" { |
| 123 | return errors.New("skill name is required") |
| 124 | } |
| 125 | if !skillNamePattern.MatchString(skill.Name) { |
| 126 | return fmt.Errorf("invalid skill name %q: must be 1-64 characters of lowercase letters, numbers, and hyphens", skill.Name) |
| 127 | } |
| 128 | if strings.ContainsAny(skill.Name, "<>") { |
| 129 | return fmt.Errorf("invalid skill name %q: cannot contain XML/meta characters like '<' or '>'", skill.Name) |
| 130 | } |
| 131 | lowerName := strings.ToLower(skill.Name) |
| 132 | if strings.Contains(lowerName, "anthropic") || strings.Contains(lowerName, "claude") { |
| 133 | return fmt.Errorf("invalid skill name %q: reserved words 'anthropic' and 'claude' are not allowed", skill.Name) |
| 134 | } |