package role import ( "encoding/json" "errors" "fmt" "strings" ) type ExecutorKind string const ( ExecutorKindCodex ExecutorKind = "codex" ExecutorKindHuman ExecutorKind = "human" ) type PromptKind string const ( PromptSystem PromptKind = "system" ) type Definition struct { Name string `json:"name"` Title string `json:"title"` ExecutorKind ExecutorKind `json:"executor_kind"` Description string `json:"description"` IsEnabled bool `json:"is_enabled"` IsBuiltin bool `json:"is_builtin"` SortOrder int `json:"sort_order"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } func (d Definition) Validate() error { if d.Name == "" { return errors.New("role name is required") } if d.Title == "" { return errors.New("role title is required") } switch d.ExecutorKind { case ExecutorKindCodex, ExecutorKindHuman: default: return fmt.Errorf("invalid role executor kind %q", d.ExecutorKind) } if d.Name == "user" && d.ExecutorKind != ExecutorKindHuman { return fmt.Errorf("user role must use human executor") } return nil } func DefaultExecutorKind(roleName string) ExecutorKind { if roleName == "user" { return ExecutorKindHuman } return ExecutorKindCodex } func NormalizeDefinition(value Definition) Definition { if value.ExecutorKind == "" { value.ExecutorKind = DefaultExecutorKind(value.Name) } return value } type Config struct { RoleName string `json:"role_name"` ConfigTOML string `json:"config_toml"` AuthJSON string `json:"auth_json"` } func (c Config) Validate() error { if strings.TrimSpace(c.RoleName) == "" { return errors.New("role name is required") } if strings.TrimSpace(c.AuthJSON) == "" { return nil } if !json.Valid([]byte(c.AuthJSON)) { return fmt.Errorf("role auth_json must be valid json") } return nil } func NormalizeConfig(value Config) Config { value.RoleName = strings.TrimSpace(value.RoleName) value.ConfigTOML = strings.TrimSpace(value.ConfigTOML) if strings.TrimSpace(value.AuthJSON) == "" { value.AuthJSON = "{}" } return value } type Prompt struct { ID string `json:"id"` RoleName string `json:"role_name"` WorkspaceID string `json:"workspace_id,omitempty"` PromptKind PromptKind `json:"prompt_kind"` ContentMarkdown string `json:"content_markdown"` Version int `json:"version"` UpdatedBy string `json:"updated_by"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } func (p Prompt) Validate() error { if p.RoleName == "" { return errors.New("role name is required") } if p.ContentMarkdown == "" { return errors.New("prompt content is required") } switch p.PromptKind { case PromptSystem: default: return fmt.Errorf("invalid prompt kind %q", p.PromptKind) } return nil } type SkillBinding struct { ID string `json:"id"` RoleName string `json:"role_name"` WorkspaceID string `json:"workspace_id,omitempty"` SkillID string `json:"skill_id"` IsEnabled bool `json:"is_enabled"` SortOrder int `json:"sort_order"` Config map[string]any `json:"config,omitempty"` Version int `json:"version"` UpdatedBy string `json:"updated_by"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } func (b SkillBinding) Validate() error { if b.RoleName == "" { return errors.New("role name is required") } if b.SkillID == "" { return errors.New("skill id is required") } return nil }