auto-update-daily-20260202
1// Package config handles configuration loading and defaults.
2package config
3
4import (
5 "os"
6 "path/filepath"
7 "strings"
8
9 "gopkg.in/yaml.v3"
10)
11
12// Config represents the complete configuration.
13type Config struct {
14 User UserConfig `yaml:"user"`
15 GitHub GitHubConfig `yaml:"github"`
16 Org OrgConfig `yaml:"org"`
17 Jira JiraConfig `yaml:"jira"`
18 Claude ClaudeConfig `yaml:"claude"`
19 Output OutputConfig `yaml:"output"`
20}
21
22// UserConfig holds user identification.
23type UserConfig struct {
24 Name string `yaml:"name"`
25 Email string `yaml:"email"`
26}
27
28// GitHubConfig configures the GitHub source.
29type GitHubConfig struct {
30 Enabled bool `yaml:"enabled"`
31 Username string `yaml:"username"`
32 Repos []string `yaml:"repos,omitempty"`
33 IncludePRs bool `yaml:"include_prs"`
34 IncludeIssues bool `yaml:"include_issues"`
35 IncludeReviews bool `yaml:"include_reviews"`
36 IncludeCommits bool `yaml:"include_commits"`
37 IncludeDiscussions bool `yaml:"include_discussions"`
38 IncludeComments bool `yaml:"include_comments"`
39}
40
41// OrgConfig configures the org-mode source.
42type OrgConfig struct {
43 Enabled bool `yaml:"enabled"`
44 Files []string `yaml:"files"`
45 ArchiveDir string `yaml:"archive_dir,omitempty"` // Optional archive directory to scan
46 IncludeDone bool `yaml:"include_done"`
47 IncludeStateChanges bool `yaml:"include_state_changes"`
48 IncludeClockEntries bool `yaml:"include_clock_entries"`
49}
50
51// JiraConfig configures the Jira source.
52type JiraConfig struct {
53 Enabled bool `yaml:"enabled"`
54 Server string `yaml:"server"`
55 Projects []string `yaml:"projects,omitempty"`
56 Username string `yaml:"username"`
57}
58
59// ClaudeConfig configures the Claude history source.
60type ClaudeConfig struct {
61 Enabled bool `yaml:"enabled"`
62 HistoryDir string `yaml:"history_dir"`
63 IncludeSessions bool `yaml:"include_sessions"`
64 IncludeLearnings bool `yaml:"include_learnings"`
65 IncludeResearch bool `yaml:"include_research"`
66}
67
68// OutputConfig configures output formatting.
69type OutputConfig struct {
70 DefaultFormat string `yaml:"default_format"`
71 IncludeSummary bool `yaml:"include_summary"`
72}
73
74// DefaultConfigPath returns the default config file location.
75func DefaultConfigPath() string {
76 home, _ := os.UserHomeDir()
77 return filepath.Join(home, ".config", "review-tool", "config.yaml")
78}
79
80// Load reads configuration from file, falling back to defaults.
81func Load(path string) (*Config, error) {
82 if path == "" {
83 path = DefaultConfigPath()
84 }
85
86 cfg := DefaultConfig()
87
88 data, err := os.ReadFile(path)
89 if err != nil {
90 if os.IsNotExist(err) {
91 return cfg, nil // Use defaults if no config file
92 }
93 return nil, err
94 }
95
96 if err := yaml.Unmarshal(data, cfg); err != nil {
97 return nil, err
98 }
99
100 // Expand ~ in paths
101 cfg.expandPaths()
102
103 return cfg, nil
104}
105
106// DefaultConfig returns a configuration with sensible defaults.
107func DefaultConfig() *Config {
108 home, _ := os.UserHomeDir()
109
110 return &Config{
111 User: UserConfig{},
112 GitHub: GitHubConfig{
113 Enabled: true,
114 IncludePRs: true,
115 IncludeIssues: true,
116 IncludeReviews: true,
117 IncludeCommits: false,
118 IncludeDiscussions: true,
119 IncludeComments: true,
120 },
121 Org: OrgConfig{
122 Enabled: true,
123 Files: []string{
124 filepath.Join(home, "desktop", "org", "todos.org"),
125 },
126 ArchiveDir: filepath.Join(home, "desktop", "org", "archive"),
127 IncludeDone: true,
128 IncludeStateChanges: true,
129 IncludeClockEntries: true,
130 },
131 Jira: JiraConfig{
132 Enabled: false,
133 },
134 Claude: ClaudeConfig{
135 Enabled: true,
136 HistoryDir: filepath.Join(home, ".config", "claude", "history"),
137 IncludeSessions: true,
138 IncludeLearnings: true,
139 IncludeResearch: true,
140 },
141 Output: OutputConfig{
142 DefaultFormat: "markdown",
143 IncludeSummary: true,
144 },
145 }
146}
147
148func (c *Config) expandPaths() {
149 home, _ := os.UserHomeDir()
150
151 // Expand org files
152 for i, f := range c.Org.Files {
153 c.Org.Files[i] = expandHome(f, home)
154 }
155
156 // Expand org archive dir
157 c.Org.ArchiveDir = expandHome(c.Org.ArchiveDir, home)
158
159 // Expand Claude history dir
160 c.Claude.HistoryDir = expandHome(c.Claude.HistoryDir, home)
161}
162
163func expandHome(path, home string) string {
164 if strings.HasPrefix(path, "~/") {
165 return filepath.Join(home, path[2:])
166 }
167 if path == "~" {
168 return home
169 }
170 return path
171}