-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathconfig.go
More file actions
155 lines (140 loc) · 4.9 KB
/
Copy pathconfig.go
File metadata and controls
155 lines (140 loc) · 4.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package config
import (
"fmt"
"os"
"gopkg.in/yaml.v3"
)
// Config represents the mcp-arch.yaml configuration.
type Config struct {
Repo string `yaml:"repo"`
Ignore []string `yaml:"ignore"`
TestGlobs []string `yaml:"test_globs"`
Extractors []string `yaml:"extractors"`
Explainers []string `yaml:"explainers"`
Renderers []string `yaml:"renderers"`
Output OutputConfig `yaml:"output"`
// Incremental enables per-extractor caching: an extractor's facts are reused
// across snapshots when the files it owns (and the repo's shared config files)
// are unchanged. Defaults to true. Set `incremental: false` to force a full
// re-extraction every run.
Incremental *bool `yaml:"incremental,omitempty"`
}
// IncrementalEnabled reports whether per-extractor caching is on (the default).
func (c *Config) IncrementalEnabled() bool {
return c.Incremental == nil || *c.Incremental
}
// OutputConfig controls where and how output artifacts are generated.
type OutputConfig struct {
Dir string `yaml:"dir"`
MaxContextTokens int `yaml:"max_context_tokens"`
}
// Default returns a Config with sensible defaults.
func Default() *Config {
return &Config{
Repo: ".",
Ignore: []string{
"vendor/**",
"node_modules/**",
".git/**",
"**/*_test.go",
"**/*.test.ts",
"**/*.test.tsx",
"**/*.spec.ts",
"**/*.spec.tsx",
"**/*_spec.rb",
"**/*_test.rb",
".enola/**",
// Build / cache artifacts. These are generated output (often transpiled
// JS, e.g. Next.js .next/) and must never be indexed as source — doing so
// pollutes query_facts with thousands of spurious facts. The **/<dir>/**
// form matches the directory at ANY depth (e.g. Gradle/Android emit
// data/build/kspCaches/...), not just at the repo root.
".next/**",
"dist/**",
"**/build/**",
"out/**",
".vercel/**",
".turbo/**",
"coverage/**",
".nuxt/**",
".svelte-kit/**",
"**/__pycache__/**",
// Python virtual environments, installed dependencies, and tool caches.
// A repo-local .venv/venv holds the entire dependency tree (thousands of
// third-party .py files); indexing it is never wanted and dominates
// snapshot time. site-packages is the definitive catch for any oddly-named
// env (.tox/.nox/conda/direnv all nest one). Any-depth (**/x/**) form so
// monorepo sub-project venvs are pruned too.
"**/.venv/**",
"**/venv/**",
"**/site-packages/**",
"**/.tox/**",
"**/.nox/**",
"**/.eggs/**",
"**/.mypy_cache/**",
"**/.pytest_cache/**",
"**/.ruff_cache/**",
"**/Pods/**",
"**/.gradle/**",
// Minified / bundled JS by name. The extractor also detects minified
// content heuristically (very long lines), but these globs cheaply skip
// the common named cases before a file is ever read. Keep in sync with
// the bundled mcp-arch.yaml ignore list.
"**/*.min.js",
"**/*.bundle.js",
},
// TestGlobs identify test/spec files. They stay ignored for normal indexing
// (still listed in Ignore above) — production architecture facts must not
// include test symbols — but the engine collects them separately for
// reference-only extraction so the dead-code detector can see that a
// production symbol is exercised by a test and not mis-report it as dead.
TestGlobs: []string{"**/*_spec.rb", "**/*_test.rb"},
Extractors: []string{"cpp", "go", "grpc", "java", "kotlin", "openapi", "php", "python", "typescript", "swift", "ruby"},
Explainers: []string{"cycles", "layers", "crossrepo", "coverage", "unused-routes", "god-class", "hotspots", "dependency-depth", "exported-surface", "complexity-outliers"},
Renderers: []string{"llm_context"},
Output: OutputConfig{
Dir: ".enola",
MaxContextTokens: 16000,
},
}
}
// Load reads a configuration file from the given path.
// Missing fields are filled with defaults.
func Load(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading config %s: %w", path, err)
}
cfg := Default()
if err := yaml.Unmarshal(data, cfg); err != nil {
return nil, fmt.Errorf("parsing config %s: %w", path, err)
}
// Ensure required defaults
if cfg.Output.Dir == "" {
cfg.Output.Dir = ".enola"
}
if cfg.Output.MaxContextTokens == 0 {
cfg.Output.MaxContextTokens = 16000
}
return cfg, nil
}
// IsExtractorEnabled returns true if the named extractor is enabled.
func (c *Config) IsExtractorEnabled(name string) bool {
return contains(c.Extractors, name)
}
// IsExplainerEnabled returns true if the named explainer is enabled.
func (c *Config) IsExplainerEnabled(name string) bool {
return contains(c.Explainers, name)
}
// IsRendererEnabled returns true if the named renderer is enabled.
func (c *Config) IsRendererEnabled(name string) bool {
return contains(c.Renderers, name)
}
func contains(ss []string, s string) bool {
for _, v := range ss {
if v == s {
return true
}
}
return false
}