// Package config liest und schreibt .hugin.yaml (→ KONZEPT.md 11.2). package config import ( "errors" "fmt" "io/fs" "os" "path/filepath" "gopkg.in/yaml.v3" ) const Filename = ".hugin.yaml" type Config struct { Server string `yaml:"server"` Project string `yaml:"project"` // "auto" oder Liste aus claude, opencode Tools Tools `yaml:"tools"` OpencodeReadsClaude *bool `yaml:"opencode_reads_claude,omitempty"` // warn | strict ToolCheck string `yaml:"tool_check,omitempty"` Packages []string `yaml:"packages"` Unsubscribed []string `yaml:"unsubscribed"` } // Tools ist entweder automatisch (leer) oder eine feste Liste. type Tools struct { Auto bool List []string } func (w Tools) MarshalYAML() (any, error) { if w.Auto || len(w.List) == 0 { return "auto", nil } return w.List, nil } func (w *Tools) UnmarshalYAML(n *yaml.Node) error { if n.Kind == yaml.ScalarNode { if n.Value != "auto" { return fmt.Errorf("tools: %q, erwartet auto oder eine Liste", n.Value) } *w = Tools{Auto: true} return nil } var items []string if err := n.Decode(&items); err != nil { return err } for _, name := range items { if name != "claude" && name != "opencode" { return fmt.Errorf("tools: unbekanntes Werkzeug %q", name) } } *w = Tools{List: items} return nil } func (k *Config) ReadsClaude() bool { return k.OpencodeReadsClaude == nil || *k.OpencodeReadsClaude } func (k *Config) Strict() bool { return k.ToolCheck == "strict" } func Load(repo string) (*Config, error) { raw, err := os.ReadFile(filepath.Join(repo, Filename)) if errors.Is(err, fs.ErrNotExist) { return nil, fmt.Errorf("%s fehlt; zuerst hugin init aufrufen", Filename) } if err != nil { return nil, err } k := &Config{} if err := yaml.Unmarshal(raw, k); err != nil { return nil, fmt.Errorf("%s: %w", Filename, err) } switch k.ToolCheck { case "", "warn", "strict": default: return nil, fmt.Errorf("%s: tool_check %q, erwartet warn oder strict", Filename, k.ToolCheck) } return k, nil } func (k *Config) Save(repo string) error { raw, err := yaml.Marshal(k) if err != nil { return err } return os.WriteFile(filepath.Join(repo, Filename), raw, 0o644) }