package config import ( "fmt" "os" "path/filepath" "github.com/BurntSushi/toml" ) // Load baut die Config aus allen Schichten auf (spätere gewinnt): Defaults, // ~/.config/nub/config.toml, /.nub/config.toml, NUB_*-Umgebungs- // variablen. Flags folgen erst, wenn cmd/nub welche anbietet. func Load(repoRoot string) (Config, error) { cfg := Defaults() if home, err := os.UserHomeDir(); err == nil { if err := mergeFile(&cfg, filepath.Join(home, ".config", "nub", "config.toml")); err != nil { return Config{}, err } } if err := mergeFile(&cfg, filepath.Join(repoRoot, ".nub", "config.toml")); err != nil { return Config{}, err } applyEnvOverrides(&cfg) if cfg.Version != 1 { return Config{}, fmt.Errorf("config: unsupported version %d (nub unterstützt nur version 1)", cfg.Version) } return cfg, nil } func mergeFile(cfg *Config, path string) error { if _, err := os.Stat(path); err != nil { return nil // Datei fehlt -> Schicht wird übersprungen } if _, err := toml.DecodeFile(path, cfg); err != nil { return fmt.Errorf("config: %s: %w", path, err) } return nil } // applyEnvOverrides deckt den kleinen, konkreten Satz an NUB_*-Variablen ab, // der v1 als letzte Schicht vor den (noch nicht existierenden) Flags dient. func applyEnvOverrides(cfg *Config) { if v := os.Getenv("NUB_MODEL"); v != "" { cfg.Model.Default = v } baseURL := os.Getenv("NUB_BASE_URL") apiKey := firstNonEmpty(os.Getenv("NUB_API_KEY"), os.Getenv("OPENAI_API_KEY")) if baseURL == "" && apiKey == "" { return } idx := -1 for i, e := range cfg.Endpoints { if e.Name == cfg.Model.Endpoint { idx = i break } } if idx == -1 { cfg.Endpoints = append(cfg.Endpoints, Endpoint{Name: cfg.Model.Endpoint}) idx = len(cfg.Endpoints) - 1 } if baseURL != "" { cfg.Endpoints[idx].BaseURL = baseURL } if apiKey != "" { cfg.Endpoints[idx].APIKey = apiKey } } func firstNonEmpty(vals ...string) string { for _, v := range vals { if v != "" { return v } } return "" }