(raw map[string]any, filePath string)
| 75 | } |
| 76 | |
| 77 | func ValidateFrontmatter(raw map[string]any, filePath string) SkillFrontmatter { |
| 78 | canonical := map[string]any{} |
| 79 | for key, value := range raw { |
| 80 | canonical[strings.ReplaceAll(key, "-", "_")] = value |
| 81 | } |
| 82 | name, _ := canonical["name"].(string) |
| 83 | name = strings.TrimSpace(name) |
| 84 | if name == "" { |
| 85 | name = filepath.Base(filepath.Dir(filePath)) |
| 86 | } |
| 87 | description, _ := canonical["description"].(string) |
| 88 | description = strings.TrimSpace(description) |
| 89 | if description == "" { |
| 90 | description = name |
| 91 | } |
| 92 | contextValue, _ := canonical["context"].(string) |
| 93 | if contextValue != "fork" { |
| 94 | contextValue = "inline" |
| 95 | } |
| 96 | return SkillFrontmatter{ |
| 97 | Name: name, |
| 98 | Description: description, |
| 99 | WhenToUse: optionalString(canonical["when_to_use"]), |
| 100 | ArgumentHint: optionalString(canonical["argument_hint"]), |
| 101 | Arguments: coerceStringList(canonical["arguments"], true), |
| 102 | Context: contextValue, |
| 103 | AllowedTools: coerceStringList(canonical["allowed_tools"], true), |
| 104 | Model: coerceModel(canonical["model"]), |
| 105 | Effort: coerceEffort(canonical["effort"]), |
| 106 | Agent: optionalString(canonical["agent"]), |
| 107 | Shell: optionalString(canonical["shell"]), |
| 108 | Paths: coerceStringList(canonical["paths"], true), |
| 109 | UserInvocable: coerceBool(canonical["user_invocable"], true), |
| 110 | DisableModelInvocation: coerceBool(canonical["disable_model_invocation"], false), |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | func optionalString(value any) *string { |
| 115 | if value == nil { |
no test coverage detected