ref-agents 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ref_agents/__init__.py +9 -0
- ref_agents/api_keys.json.example +8 -0
- ref_agents/auth.py +129 -0
- ref_agents/codemap/..md +62 -0
- ref_agents/codemap/CODE_MAP.md +37 -0
- ref_agents/codemap/core.md +43 -0
- ref_agents/codemap/models.md +43 -0
- ref_agents/codemap/prompts.md +40 -0
- ref_agents/codemap/security.md +45 -0
- ref_agents/codemap/tools.md +94 -0
- ref_agents/codemap/tools_browser.md +44 -0
- ref_agents/codemap/utils.md +42 -0
- ref_agents/codemap/workflow.md +42 -0
- ref_agents/config/ai_patterns.yaml +101 -0
- ref_agents/config/frameworks/angular.yaml +104 -0
- ref_agents/config/frameworks/aspnet.yaml +84 -0
- ref_agents/config/frameworks/ef_core.yaml +81 -0
- ref_agents/config/frameworks/react.yaml +111 -0
- ref_agents/config/frameworks/spring_boot.yaml +117 -0
- ref_agents/config/languages/csharp.yaml +153 -0
- ref_agents/config/languages/java.yaml +188 -0
- ref_agents/config/languages/javascript.yaml +172 -0
- ref_agents/config/languages/python.yaml +153 -0
- ref_agents/config/languages/typescript.yaml +193 -0
- ref_agents/constants.py +553 -0
- ref_agents/core/__init__.py +15 -0
- ref_agents/core/config_loader.py +160 -0
- ref_agents/core/config_models.py +167 -0
- ref_agents/core/config_parsing.py +84 -0
- ref_agents/core/language_detector.py +388 -0
- ref_agents/core/validation_models.py +66 -0
- ref_agents/core/validation_primitives.py +176 -0
- ref_agents/errors.py +34 -0
- ref_agents/license_client.py +247 -0
- ref_agents/models/__init__.py +22 -0
- ref_agents/models/gherkin.py +45 -0
- ref_agents/models/hierarchy.py +80 -0
- ref_agents/models/invest.py +59 -0
- ref_agents/models/version.py +49 -0
- ref_agents/prompts/__init__.py +9 -0
- ref_agents/prompts/start_agent.py +772 -0
- ref_agents/rules/architecture/backend_patterns.md +43 -0
- ref_agents/rules/architecture/diagramming.md +100 -0
- ref_agents/rules/architecture/frontend_patterns.md +40 -0
- ref_agents/rules/architecture/impact_analysis.md +129 -0
- ref_agents/rules/architecture/migration_strategy.md +208 -0
- ref_agents/rules/architecture/regression_protocol.md +77 -0
- ref_agents/rules/architecture/system_design.md +97 -0
- ref_agents/rules/common/codemap_standard.md +97 -0
- ref_agents/rules/common/core_protocol.md +59 -0
- ref_agents/rules/common/prompt_engineering.md +294 -0
- ref_agents/rules/development/debugging.md +32 -0
- ref_agents/rules/development/implementation.md +205 -0
- ref_agents/rules/operations/completion.md +119 -0
- ref_agents/rules/operations/cutover_protocol.md +218 -0
- ref_agents/rules/operations/discovery.md +179 -0
- ref_agents/rules/operations/fix_workflow.md +87 -0
- ref_agents/rules/operations/forensics.md +278 -0
- ref_agents/rules/operations/platform.md +263 -0
- ref_agents/rules/operations/synchronous_flow.md +25 -0
- ref_agents/rules/product/ac_validation.md +25 -0
- ref_agents/rules/product/brainstorming.md +27 -0
- ref_agents/rules/product/ref_flow.md +101 -0
- ref_agents/rules/product/requirements_std.md +114 -0
- ref_agents/rules/product/spec_writing.md +235 -0
- ref_agents/rules/product/strategy.md +96 -0
- ref_agents/rules/quality/documentation_standards.md +46 -0
- ref_agents/rules/quality/parity_testing.md +234 -0
- ref_agents/rules/quality/project_documentation.md +56 -0
- ref_agents/rules/quality/qa_lead.md +111 -0
- ref_agents/rules/quality/test_design.md +146 -0
- ref_agents/rules/quality/testing_standards.md +293 -0
- ref_agents/rules/review/pr_review.md +116 -0
- ref_agents/rules/security/security_audit.md +83 -0
- ref_agents/security/__init__.py +22 -0
- ref_agents/security/dependency_audit.py +188 -0
- ref_agents/security/file_audit.py +208 -0
- ref_agents/security/network_scan.py +179 -0
- ref_agents/security/report_generator.py +313 -0
- ref_agents/security/secret_scan.py +252 -0
- ref_agents/security/url_scan.py +240 -0
- ref_agents/security_scan.py +236 -0
- ref_agents/server.py +1586 -0
- ref_agents/session.py +100 -0
- ref_agents/tool_names.py +55 -0
- ref_agents/tools/__init__.py +8 -0
- ref_agents/tools/agents_generator.py +315 -0
- ref_agents/tools/ai_pattern_detector.py +815 -0
- ref_agents/tools/brownfield_populator.py +529 -0
- ref_agents/tools/browser/__init__.py +50 -0
- ref_agents/tools/browser/evidence_verifier.py +302 -0
- ref_agents/tools/browser/execution_logger.py +249 -0
- ref_agents/tools/browser/playwright_mcp_client.py +259 -0
- ref_agents/tools/browser/screenshot_utils.py +184 -0
- ref_agents/tools/browser/test_executor.py +537 -0
- ref_agents/tools/code_quality_scanner.py +629 -0
- ref_agents/tools/codemap/..md +93 -0
- ref_agents/tools/codemap/CODE_MAP.md +30 -0
- ref_agents/tools/codemap/browser.md +44 -0
- ref_agents/tools/codemap.py +403 -0
- ref_agents/tools/codemap_freshness.py +234 -0
- ref_agents/tools/comment_smell_scanner.py +346 -0
- ref_agents/tools/complexity.py +436 -0
- ref_agents/tools/complexity_ast.py +333 -0
- ref_agents/tools/compliance.py +246 -0
- ref_agents/tools/compliance_remediation.py +846 -0
- ref_agents/tools/context_graph.py +839 -0
- ref_agents/tools/context_manager.py +550 -0
- ref_agents/tools/context_tools.py +121 -0
- ref_agents/tools/cross_repo_linker.py +393 -0
- ref_agents/tools/dead_code_scanner.py +637 -0
- ref_agents/tools/debt_scanner.py +1092 -0
- ref_agents/tools/dependency_graph.py +272 -0
- ref_agents/tools/discovery_audit.py +372 -0
- ref_agents/tools/docs_scanner.py +600 -0
- ref_agents/tools/evaluate_gate.py +119 -0
- ref_agents/tools/external_detector.py +524 -0
- ref_agents/tools/features_generator.py +282 -0
- ref_agents/tools/flow_gap_detector.py +373 -0
- ref_agents/tools/flow_mapper.py +327 -0
- ref_agents/tools/full_suite_runner.py +740 -0
- ref_agents/tools/gherkin_parser.py +227 -0
- ref_agents/tools/guard_tools.py +139 -0
- ref_agents/tools/handoff_tools.py +282 -0
- ref_agents/tools/health_scanner.py +1211 -0
- ref_agents/tools/hierarchy_manager.py +289 -0
- ref_agents/tools/invest_scorer.py +249 -0
- ref_agents/tools/jira_confluence_export.py +306 -0
- ref_agents/tools/json_output.py +76 -0
- ref_agents/tools/migration_mapper.py +946 -0
- ref_agents/tools/migration_readiness_scanner.py +209 -0
- ref_agents/tools/pattern_learner.py +522 -0
- ref_agents/tools/report_utils.py +155 -0
- ref_agents/tools/requirements_serializer.py +225 -0
- ref_agents/tools/security_audit_tool.py +106 -0
- ref_agents/tools/sequencing_engine.py +288 -0
- ref_agents/tools/summary_generator.py +275 -0
- ref_agents/tools/symbol_resolver.py +306 -0
- ref_agents/tools/symbol_smoke_runner.py +336 -0
- ref_agents/tools/test_plan_validator.py +189 -0
- ref_agents/tools/test_smell_walker.py +902 -0
- ref_agents/tools/tier1_fixer.py +502 -0
- ref_agents/tools/validators/__init__.py +419 -0
- ref_agents/tools/validators/architect.py +268 -0
- ref_agents/tools/validators/cutover_engineer.py +167 -0
- ref_agents/tools/validators/developer.py +180 -0
- ref_agents/tools/validators/discovery.py +150 -0
- ref_agents/tools/validators/forensic_engineer.py +191 -0
- ref_agents/tools/validators/impact_architect.py +181 -0
- ref_agents/tools/validators/migration_planner.py +166 -0
- ref_agents/tools/validators/parity_tester.py +155 -0
- ref_agents/tools/validators/platform_engineer.py +134 -0
- ref_agents/tools/validators/pr_reviewer.py +129 -0
- ref_agents/tools/validators/product_manager.py +291 -0
- ref_agents/tools/validators/qa_lead.py +172 -0
- ref_agents/tools/validators/scrum_master.py +212 -0
- ref_agents/tools/validators/security_owner.py +162 -0
- ref_agents/tools/validators/specifier.py +134 -0
- ref_agents/tools/validators/strategist.py +149 -0
- ref_agents/tools/validators/tester.py +121 -0
- ref_agents/tools/version_manager.py +202 -0
- ref_agents/tools/workflow_tools.py +1549 -0
- ref_agents/utils/__init__.py +21 -0
- ref_agents/utils/git_utils.py +351 -0
- ref_agents/utils/handoff_logger.py +368 -0
- ref_agents/utils/ignore_matcher.py +270 -0
- ref_agents/workflow/__init__.py +19 -0
- ref_agents/workflow/capabilities.py +328 -0
- ref_agents/workflow/state_machine.py +708 -0
- ref_agents/workflow/transitions.py +658 -0
- ref_agents-1.0.0.dist-info/METADATA +365 -0
- ref_agents-1.0.0.dist-info/RECORD +175 -0
- ref_agents-1.0.0.dist-info/WHEEL +4 -0
- ref_agents-1.0.0.dist-info/entry_points.txt +2 -0
- ref_agents-1.0.0.dist-info/licenses/LICENSE +115 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Configuration Loader for REF Agents.
|
|
2
|
+
|
|
3
|
+
Loads language-specific and framework-specific configurations for
|
|
4
|
+
debt scanning, pattern detection, and compliance checking.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import structlog
|
|
10
|
+
|
|
11
|
+
from ref_agents.core.config_models import (
|
|
12
|
+
LanguageConfig,
|
|
13
|
+
)
|
|
14
|
+
from ref_agents.core.config_parsing import parse_config
|
|
15
|
+
|
|
16
|
+
logger = structlog.get_logger(__name__)
|
|
17
|
+
|
|
18
|
+
CONFIG_ROOT = Path(__file__).parent.parent / "config"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ConfigLoader:
|
|
22
|
+
"""Loads and caches language/framework configurations."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, config_root: Path | None = None) -> None:
|
|
25
|
+
"""Initialize config loader.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
config_root: Config directory. Defaults to src/ref_agents/config.
|
|
29
|
+
"""
|
|
30
|
+
self.config_root = config_root or CONFIG_ROOT
|
|
31
|
+
self._cache: dict[str, LanguageConfig] = {}
|
|
32
|
+
|
|
33
|
+
def _load_yaml(self, path: Path) -> dict:
|
|
34
|
+
"""Load YAML file.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
path: Path to YAML file.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Parsed YAML content.
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
FileNotFoundError: If file doesn't exist.
|
|
44
|
+
"""
|
|
45
|
+
if not path.exists():
|
|
46
|
+
raise FileNotFoundError(f"Config not found: {path}")
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
import yaml
|
|
50
|
+
|
|
51
|
+
return yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
52
|
+
except ImportError:
|
|
53
|
+
logger.error("yaml_not_installed", msg="Install PyYAML: pip install pyyaml")
|
|
54
|
+
raise
|
|
55
|
+
|
|
56
|
+
def load_language(self, language: str) -> LanguageConfig:
|
|
57
|
+
"""Load configuration for a language.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
language: Language name (python, typescript, javascript, java).
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
LanguageConfig for the language.
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
FileNotFoundError: If config file not found.
|
|
67
|
+
"""
|
|
68
|
+
cache_key = language
|
|
69
|
+
|
|
70
|
+
if cache_key in self._cache:
|
|
71
|
+
return self._cache[cache_key]
|
|
72
|
+
|
|
73
|
+
config_path = self.config_root / "languages" / f"{language}.yaml"
|
|
74
|
+
data = self._load_yaml(config_path)
|
|
75
|
+
config = parse_config(data)
|
|
76
|
+
|
|
77
|
+
self._cache[cache_key] = config
|
|
78
|
+
logger.debug("config_loaded", language=language)
|
|
79
|
+
|
|
80
|
+
return config
|
|
81
|
+
|
|
82
|
+
def load_framework(self, framework: str) -> LanguageConfig:
|
|
83
|
+
"""Load configuration for a framework.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
framework: Framework name (react, angular, spring_boot).
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
LanguageConfig for the framework.
|
|
90
|
+
|
|
91
|
+
Raises:
|
|
92
|
+
FileNotFoundError: If config file not found.
|
|
93
|
+
"""
|
|
94
|
+
config_path = self.config_root / "frameworks" / f"{framework}.yaml"
|
|
95
|
+
data = self._load_yaml(config_path)
|
|
96
|
+
return parse_config(data)
|
|
97
|
+
|
|
98
|
+
def load(self, language: str, framework: str | None = None) -> LanguageConfig:
|
|
99
|
+
"""Load configuration for language with optional framework overlay.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
language: Language name.
|
|
103
|
+
framework: Optional framework name.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Merged LanguageConfig.
|
|
107
|
+
"""
|
|
108
|
+
cache_key = f"{language}/{framework}" if framework else language
|
|
109
|
+
|
|
110
|
+
if cache_key in self._cache:
|
|
111
|
+
return self._cache[cache_key]
|
|
112
|
+
|
|
113
|
+
base_config = self.load_language(language)
|
|
114
|
+
|
|
115
|
+
if framework:
|
|
116
|
+
try:
|
|
117
|
+
framework_config = self.load_framework(framework)
|
|
118
|
+
merged = base_config.merge_framework(framework_config)
|
|
119
|
+
self._cache[cache_key] = merged
|
|
120
|
+
return merged
|
|
121
|
+
except FileNotFoundError:
|
|
122
|
+
logger.warning(
|
|
123
|
+
"framework_config_not_found",
|
|
124
|
+
framework=framework,
|
|
125
|
+
using="base_language_config",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
return base_config
|
|
129
|
+
|
|
130
|
+
def get_available_languages(self) -> list[str]:
|
|
131
|
+
"""Get list of available language configs."""
|
|
132
|
+
lang_dir = self.config_root / "languages"
|
|
133
|
+
if not lang_dir.exists():
|
|
134
|
+
return []
|
|
135
|
+
|
|
136
|
+
return [p.stem for p in lang_dir.glob("*.yaml")]
|
|
137
|
+
|
|
138
|
+
def get_available_frameworks(self) -> list[str]:
|
|
139
|
+
"""Get list of available framework configs."""
|
|
140
|
+
fw_dir = self.config_root / "frameworks"
|
|
141
|
+
if not fw_dir.exists():
|
|
142
|
+
return []
|
|
143
|
+
|
|
144
|
+
return [p.stem for p in fw_dir.glob("*.yaml")]
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
_default_loader: ConfigLoader | None = None
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def get_config_loader() -> ConfigLoader:
|
|
151
|
+
"""Get default ConfigLoader instance."""
|
|
152
|
+
global _default_loader
|
|
153
|
+
if _default_loader is None:
|
|
154
|
+
_default_loader = ConfigLoader()
|
|
155
|
+
return _default_loader
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def load_config(language: str, framework: str | None = None) -> LanguageConfig:
|
|
159
|
+
"""Load configuration (convenience function)."""
|
|
160
|
+
return get_config_loader().load(language, framework)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""Configuration data models for REF Agents.
|
|
2
|
+
|
|
3
|
+
Dataclasses and merge logic used by config_loader and config_parsing.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class DebtPattern:
|
|
12
|
+
"""Technical debt pattern definition.
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
name: Pattern identifier.
|
|
16
|
+
description: Human-readable description.
|
|
17
|
+
severity: critical, high, medium, low.
|
|
18
|
+
pattern: Regex pattern (if regex-based).
|
|
19
|
+
ast_node: AST node type (if AST-based).
|
|
20
|
+
condition: Additional condition for AST matching.
|
|
21
|
+
suggestion: Fix suggestion.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
name: str
|
|
25
|
+
description: str
|
|
26
|
+
severity: str = "medium"
|
|
27
|
+
pattern: str | None = None
|
|
28
|
+
ast_node: str | None = None
|
|
29
|
+
condition: str | None = None
|
|
30
|
+
suggestion: str = ""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class NamingRules:
|
|
35
|
+
"""Naming convention rules.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
generic_names: Names considered too generic.
|
|
39
|
+
conventions: Naming conventions (snake_case, camelCase, etc.).
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
generic_names: list[str] = field(default_factory=list)
|
|
43
|
+
conventions: dict[str, str] = field(default_factory=dict)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class Thresholds:
|
|
48
|
+
"""Code quality thresholds.
|
|
49
|
+
|
|
50
|
+
Attributes:
|
|
51
|
+
complexity: Max cyclomatic complexity (legacy, use function_complexity_block).
|
|
52
|
+
function_complexity_warn: Per-function cognitive complexity warning threshold.
|
|
53
|
+
function_complexity_block: Per-function cognitive complexity blocker threshold.
|
|
54
|
+
file_complexity_warn: Aggregate file complexity warning threshold.
|
|
55
|
+
file_complexity_block: Aggregate file complexity blocker threshold.
|
|
56
|
+
function_length: Max function lines.
|
|
57
|
+
nesting_depth: Max nesting levels.
|
|
58
|
+
file_length: Max file lines.
|
|
59
|
+
comment_ratio: Max comment-to-code ratio.
|
|
60
|
+
class_ratio: Max class-to-function ratio.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
complexity: int = 15 # Legacy fallback
|
|
64
|
+
function_complexity_warn: int | None = None
|
|
65
|
+
function_complexity_block: int | None = None
|
|
66
|
+
file_complexity_warn: int | None = None
|
|
67
|
+
file_complexity_block: int | None = None
|
|
68
|
+
function_length: int = 100
|
|
69
|
+
nesting_depth: int = 4
|
|
70
|
+
file_length: int = 500
|
|
71
|
+
comment_ratio: float = 0.4
|
|
72
|
+
class_ratio: float = 0.5
|
|
73
|
+
|
|
74
|
+
def __post_init__(self) -> None:
|
|
75
|
+
"""Set defaults for dual thresholds if not provided."""
|
|
76
|
+
if self.function_complexity_warn is None:
|
|
77
|
+
self.function_complexity_warn = 15
|
|
78
|
+
if self.function_complexity_block is None:
|
|
79
|
+
self.function_complexity_block = 25
|
|
80
|
+
if self.file_complexity_warn is None:
|
|
81
|
+
self.file_complexity_warn = 80
|
|
82
|
+
if self.file_complexity_block is None:
|
|
83
|
+
self.file_complexity_block = 150
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclass
|
|
87
|
+
class LanguageConfig:
|
|
88
|
+
"""Complete language configuration.
|
|
89
|
+
|
|
90
|
+
Attributes:
|
|
91
|
+
language: Language name.
|
|
92
|
+
extensions: File extensions.
|
|
93
|
+
framework: Framework name (if applicable).
|
|
94
|
+
debt_patterns: Debt detection patterns.
|
|
95
|
+
deprecated_imports: Deprecated import mappings.
|
|
96
|
+
naming: Naming rules.
|
|
97
|
+
thresholds: Quality thresholds.
|
|
98
|
+
anti_patterns: AI anti-pattern rules.
|
|
99
|
+
parser: Parser type (ast, regex, tree-sitter).
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
language: str
|
|
103
|
+
extensions: list[str] = field(default_factory=list)
|
|
104
|
+
framework: str | None = None
|
|
105
|
+
debt_patterns: list[DebtPattern] = field(default_factory=list)
|
|
106
|
+
deprecated_imports: dict[str, str] = field(default_factory=dict)
|
|
107
|
+
naming: NamingRules = field(default_factory=NamingRules)
|
|
108
|
+
thresholds: Thresholds = field(default_factory=Thresholds)
|
|
109
|
+
anti_patterns: dict[str, Any] = field(default_factory=dict)
|
|
110
|
+
parser: str = "regex"
|
|
111
|
+
exclusions: dict[str, list[str]] = field(default_factory=dict)
|
|
112
|
+
|
|
113
|
+
def merge_framework(self, framework_config: "LanguageConfig") -> "LanguageConfig":
|
|
114
|
+
"""Merge framework-specific config on top of base config.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
framework_config: Framework configuration to merge.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
New merged configuration.
|
|
121
|
+
"""
|
|
122
|
+
merged_patterns = self.debt_patterns.copy()
|
|
123
|
+
pattern_names = {p.name for p in merged_patterns}
|
|
124
|
+
for pattern in framework_config.debt_patterns:
|
|
125
|
+
if pattern.name not in pattern_names:
|
|
126
|
+
merged_patterns.append(pattern)
|
|
127
|
+
|
|
128
|
+
merged_deprecated = {
|
|
129
|
+
**self.deprecated_imports,
|
|
130
|
+
**framework_config.deprecated_imports,
|
|
131
|
+
}
|
|
132
|
+
merged_naming = NamingRules(
|
|
133
|
+
generic_names=list(
|
|
134
|
+
set(self.naming.generic_names + framework_config.naming.generic_names)
|
|
135
|
+
),
|
|
136
|
+
conventions={
|
|
137
|
+
**self.naming.conventions,
|
|
138
|
+
**framework_config.naming.conventions,
|
|
139
|
+
},
|
|
140
|
+
)
|
|
141
|
+
merged_thresholds = Thresholds(
|
|
142
|
+
complexity=framework_config.thresholds.complexity
|
|
143
|
+
or self.thresholds.complexity,
|
|
144
|
+
function_length=framework_config.thresholds.function_length
|
|
145
|
+
or self.thresholds.function_length,
|
|
146
|
+
nesting_depth=framework_config.thresholds.nesting_depth
|
|
147
|
+
or self.thresholds.nesting_depth,
|
|
148
|
+
file_length=framework_config.thresholds.file_length
|
|
149
|
+
or self.thresholds.file_length,
|
|
150
|
+
comment_ratio=framework_config.thresholds.comment_ratio
|
|
151
|
+
or self.thresholds.comment_ratio,
|
|
152
|
+
class_ratio=framework_config.thresholds.class_ratio
|
|
153
|
+
or self.thresholds.class_ratio,
|
|
154
|
+
)
|
|
155
|
+
merged_anti = {**self.anti_patterns, **framework_config.anti_patterns}
|
|
156
|
+
|
|
157
|
+
return LanguageConfig(
|
|
158
|
+
language=self.language,
|
|
159
|
+
extensions=self.extensions,
|
|
160
|
+
framework=framework_config.framework,
|
|
161
|
+
debt_patterns=merged_patterns,
|
|
162
|
+
deprecated_imports=merged_deprecated,
|
|
163
|
+
naming=merged_naming,
|
|
164
|
+
thresholds=merged_thresholds,
|
|
165
|
+
anti_patterns=merged_anti,
|
|
166
|
+
parser=self.parser,
|
|
167
|
+
)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Parse YAML config dicts into LanguageConfig.
|
|
2
|
+
|
|
3
|
+
Used by ConfigLoader to build LanguageConfig from raw dict data.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from ref_agents.core.config_models import (
|
|
9
|
+
DebtPattern,
|
|
10
|
+
LanguageConfig,
|
|
11
|
+
NamingRules,
|
|
12
|
+
Thresholds,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _parse_debt_patterns(data: dict[str, Any]) -> list[DebtPattern]:
|
|
17
|
+
"""Parse debt_patterns section from config dict."""
|
|
18
|
+
patterns = []
|
|
19
|
+
for name, pattern_data in data.get("debt_patterns", {}).items():
|
|
20
|
+
if isinstance(pattern_data, dict):
|
|
21
|
+
patterns.append(
|
|
22
|
+
DebtPattern(
|
|
23
|
+
name=name,
|
|
24
|
+
description=pattern_data.get("description", ""),
|
|
25
|
+
severity=pattern_data.get("severity", "medium"),
|
|
26
|
+
pattern=pattern_data.get("pattern"),
|
|
27
|
+
ast_node=pattern_data.get("ast_node"),
|
|
28
|
+
condition=pattern_data.get("condition"),
|
|
29
|
+
suggestion=pattern_data.get("suggestion", ""),
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
return patterns
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _parse_naming(data: dict[str, Any]) -> NamingRules:
|
|
36
|
+
"""Parse naming section from config dict."""
|
|
37
|
+
naming_data = data.get("naming", {})
|
|
38
|
+
return NamingRules(
|
|
39
|
+
generic_names=naming_data.get("generic_names", []),
|
|
40
|
+
conventions=naming_data.get("conventions", {}),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _parse_thresholds(data: dict[str, Any]) -> Thresholds:
|
|
45
|
+
"""Parse thresholds section from config dict."""
|
|
46
|
+
thresh_data = data.get("thresholds", {})
|
|
47
|
+
return Thresholds(
|
|
48
|
+
complexity=thresh_data.get("complexity", 15),
|
|
49
|
+
function_complexity_warn=thresh_data.get("function_complexity_warn"),
|
|
50
|
+
function_complexity_block=thresh_data.get("function_complexity_block"),
|
|
51
|
+
file_complexity_warn=thresh_data.get("file_complexity_warn"),
|
|
52
|
+
file_complexity_block=thresh_data.get("file_complexity_block"),
|
|
53
|
+
function_length=thresh_data.get("function_length", 100),
|
|
54
|
+
nesting_depth=thresh_data.get("nesting_depth", 4),
|
|
55
|
+
file_length=thresh_data.get("file_length", 500),
|
|
56
|
+
comment_ratio=thresh_data.get("comment_ratio", 0.4),
|
|
57
|
+
class_ratio=thresh_data.get("class_ratio", 0.5),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def parse_config(data: dict[str, Any]) -> LanguageConfig:
|
|
62
|
+
"""Parse raw config dict into LanguageConfig.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
data: Raw config dictionary (e.g. from YAML).
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Parsed LanguageConfig.
|
|
69
|
+
"""
|
|
70
|
+
patterns = _parse_debt_patterns(data)
|
|
71
|
+
naming = _parse_naming(data)
|
|
72
|
+
thresholds = _parse_thresholds(data)
|
|
73
|
+
return LanguageConfig(
|
|
74
|
+
language=data.get("language", "unknown"),
|
|
75
|
+
extensions=data.get("extensions", []),
|
|
76
|
+
framework=data.get("framework"),
|
|
77
|
+
debt_patterns=patterns,
|
|
78
|
+
deprecated_imports=data.get("deprecated_imports", {}),
|
|
79
|
+
naming=naming,
|
|
80
|
+
thresholds=thresholds,
|
|
81
|
+
anti_patterns=data.get("anti_patterns", {}),
|
|
82
|
+
parser=data.get("parser", "regex"),
|
|
83
|
+
exclusions=data.get("exclusions", {}),
|
|
84
|
+
)
|