package config import ( "encoding/json" "errors" "os" "path/filepath" "strings" "sgg-ai-skill-manager/internal/domain" ) const ( AuthPassword = "password" AuthToken = "token" ) func Default() domain.Config { return domain.Config{ Gitea: domain.GiteaConfig{ AuthType: AuthPassword, CredentialKey: "sgg-ai-skill-manager:gitea", }, Update: domain.UpdateConfig{ AutoUpdate: true, CheckOnStartup: true, IntervalMinutes: 60, }, } } func Load(path string) (domain.Config, error) { cfg := Default() raw, err := os.ReadFile(path) if errors.Is(err, os.ErrNotExist) { return cfg, nil } if err != nil { return cfg, err } if strings.TrimSpace(string(raw)) == "" { return cfg, nil } if err := json.Unmarshal(raw, &cfg); err != nil { return cfg, err } applyDefaults(&cfg) return cfg, nil } func Save(path string, cfg domain.Config) error { applyDefaults(&cfg) if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return err } raw, err := json.MarshalIndent(cfg, "", " ") if err != nil { return err } return os.WriteFile(path, append(raw, '\n'), 0o600) } func Validate(cfg domain.Config) error { if strings.TrimSpace(cfg.Gitea.BaseURL) == "" { return errors.New("gitea baseURL is required") } if strings.TrimSpace(cfg.Gitea.Org) == "" { return errors.New("gitea org is required") } if strings.TrimSpace(cfg.Gitea.Username) == "" { return errors.New("gitea username is required") } if cfg.Gitea.AuthType != AuthPassword && cfg.Gitea.AuthType != AuthToken { return errors.New("authType must be password or token") } if cfg.Update.IntervalMinutes <= 0 { return errors.New("update interval must be positive") } return nil } func applyDefaults(cfg *domain.Config) { if cfg.Gitea.AuthType == "" { cfg.Gitea.AuthType = AuthPassword } if cfg.Gitea.CredentialKey == "" { cfg.Gitea.CredentialKey = "sgg-ai-skill-manager:gitea" } if cfg.Update.IntervalMinutes <= 0 { cfg.Update.IntervalMinutes = 60 } }