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.
Files changed (175) hide show
  1. ref_agents/__init__.py +9 -0
  2. ref_agents/api_keys.json.example +8 -0
  3. ref_agents/auth.py +129 -0
  4. ref_agents/codemap/..md +62 -0
  5. ref_agents/codemap/CODE_MAP.md +37 -0
  6. ref_agents/codemap/core.md +43 -0
  7. ref_agents/codemap/models.md +43 -0
  8. ref_agents/codemap/prompts.md +40 -0
  9. ref_agents/codemap/security.md +45 -0
  10. ref_agents/codemap/tools.md +94 -0
  11. ref_agents/codemap/tools_browser.md +44 -0
  12. ref_agents/codemap/utils.md +42 -0
  13. ref_agents/codemap/workflow.md +42 -0
  14. ref_agents/config/ai_patterns.yaml +101 -0
  15. ref_agents/config/frameworks/angular.yaml +104 -0
  16. ref_agents/config/frameworks/aspnet.yaml +84 -0
  17. ref_agents/config/frameworks/ef_core.yaml +81 -0
  18. ref_agents/config/frameworks/react.yaml +111 -0
  19. ref_agents/config/frameworks/spring_boot.yaml +117 -0
  20. ref_agents/config/languages/csharp.yaml +153 -0
  21. ref_agents/config/languages/java.yaml +188 -0
  22. ref_agents/config/languages/javascript.yaml +172 -0
  23. ref_agents/config/languages/python.yaml +153 -0
  24. ref_agents/config/languages/typescript.yaml +193 -0
  25. ref_agents/constants.py +553 -0
  26. ref_agents/core/__init__.py +15 -0
  27. ref_agents/core/config_loader.py +160 -0
  28. ref_agents/core/config_models.py +167 -0
  29. ref_agents/core/config_parsing.py +84 -0
  30. ref_agents/core/language_detector.py +388 -0
  31. ref_agents/core/validation_models.py +66 -0
  32. ref_agents/core/validation_primitives.py +176 -0
  33. ref_agents/errors.py +34 -0
  34. ref_agents/license_client.py +247 -0
  35. ref_agents/models/__init__.py +22 -0
  36. ref_agents/models/gherkin.py +45 -0
  37. ref_agents/models/hierarchy.py +80 -0
  38. ref_agents/models/invest.py +59 -0
  39. ref_agents/models/version.py +49 -0
  40. ref_agents/prompts/__init__.py +9 -0
  41. ref_agents/prompts/start_agent.py +772 -0
  42. ref_agents/rules/architecture/backend_patterns.md +43 -0
  43. ref_agents/rules/architecture/diagramming.md +100 -0
  44. ref_agents/rules/architecture/frontend_patterns.md +40 -0
  45. ref_agents/rules/architecture/impact_analysis.md +129 -0
  46. ref_agents/rules/architecture/migration_strategy.md +208 -0
  47. ref_agents/rules/architecture/regression_protocol.md +77 -0
  48. ref_agents/rules/architecture/system_design.md +97 -0
  49. ref_agents/rules/common/codemap_standard.md +97 -0
  50. ref_agents/rules/common/core_protocol.md +59 -0
  51. ref_agents/rules/common/prompt_engineering.md +294 -0
  52. ref_agents/rules/development/debugging.md +32 -0
  53. ref_agents/rules/development/implementation.md +205 -0
  54. ref_agents/rules/operations/completion.md +119 -0
  55. ref_agents/rules/operations/cutover_protocol.md +218 -0
  56. ref_agents/rules/operations/discovery.md +179 -0
  57. ref_agents/rules/operations/fix_workflow.md +87 -0
  58. ref_agents/rules/operations/forensics.md +278 -0
  59. ref_agents/rules/operations/platform.md +263 -0
  60. ref_agents/rules/operations/synchronous_flow.md +25 -0
  61. ref_agents/rules/product/ac_validation.md +25 -0
  62. ref_agents/rules/product/brainstorming.md +27 -0
  63. ref_agents/rules/product/ref_flow.md +101 -0
  64. ref_agents/rules/product/requirements_std.md +114 -0
  65. ref_agents/rules/product/spec_writing.md +235 -0
  66. ref_agents/rules/product/strategy.md +96 -0
  67. ref_agents/rules/quality/documentation_standards.md +46 -0
  68. ref_agents/rules/quality/parity_testing.md +234 -0
  69. ref_agents/rules/quality/project_documentation.md +56 -0
  70. ref_agents/rules/quality/qa_lead.md +111 -0
  71. ref_agents/rules/quality/test_design.md +146 -0
  72. ref_agents/rules/quality/testing_standards.md +293 -0
  73. ref_agents/rules/review/pr_review.md +116 -0
  74. ref_agents/rules/security/security_audit.md +83 -0
  75. ref_agents/security/__init__.py +22 -0
  76. ref_agents/security/dependency_audit.py +188 -0
  77. ref_agents/security/file_audit.py +208 -0
  78. ref_agents/security/network_scan.py +179 -0
  79. ref_agents/security/report_generator.py +313 -0
  80. ref_agents/security/secret_scan.py +252 -0
  81. ref_agents/security/url_scan.py +240 -0
  82. ref_agents/security_scan.py +236 -0
  83. ref_agents/server.py +1586 -0
  84. ref_agents/session.py +100 -0
  85. ref_agents/tool_names.py +55 -0
  86. ref_agents/tools/__init__.py +8 -0
  87. ref_agents/tools/agents_generator.py +315 -0
  88. ref_agents/tools/ai_pattern_detector.py +815 -0
  89. ref_agents/tools/brownfield_populator.py +529 -0
  90. ref_agents/tools/browser/__init__.py +50 -0
  91. ref_agents/tools/browser/evidence_verifier.py +302 -0
  92. ref_agents/tools/browser/execution_logger.py +249 -0
  93. ref_agents/tools/browser/playwright_mcp_client.py +259 -0
  94. ref_agents/tools/browser/screenshot_utils.py +184 -0
  95. ref_agents/tools/browser/test_executor.py +537 -0
  96. ref_agents/tools/code_quality_scanner.py +629 -0
  97. ref_agents/tools/codemap/..md +93 -0
  98. ref_agents/tools/codemap/CODE_MAP.md +30 -0
  99. ref_agents/tools/codemap/browser.md +44 -0
  100. ref_agents/tools/codemap.py +403 -0
  101. ref_agents/tools/codemap_freshness.py +234 -0
  102. ref_agents/tools/comment_smell_scanner.py +346 -0
  103. ref_agents/tools/complexity.py +436 -0
  104. ref_agents/tools/complexity_ast.py +333 -0
  105. ref_agents/tools/compliance.py +246 -0
  106. ref_agents/tools/compliance_remediation.py +846 -0
  107. ref_agents/tools/context_graph.py +839 -0
  108. ref_agents/tools/context_manager.py +550 -0
  109. ref_agents/tools/context_tools.py +121 -0
  110. ref_agents/tools/cross_repo_linker.py +393 -0
  111. ref_agents/tools/dead_code_scanner.py +637 -0
  112. ref_agents/tools/debt_scanner.py +1092 -0
  113. ref_agents/tools/dependency_graph.py +272 -0
  114. ref_agents/tools/discovery_audit.py +372 -0
  115. ref_agents/tools/docs_scanner.py +600 -0
  116. ref_agents/tools/evaluate_gate.py +119 -0
  117. ref_agents/tools/external_detector.py +524 -0
  118. ref_agents/tools/features_generator.py +282 -0
  119. ref_agents/tools/flow_gap_detector.py +373 -0
  120. ref_agents/tools/flow_mapper.py +327 -0
  121. ref_agents/tools/full_suite_runner.py +740 -0
  122. ref_agents/tools/gherkin_parser.py +227 -0
  123. ref_agents/tools/guard_tools.py +139 -0
  124. ref_agents/tools/handoff_tools.py +282 -0
  125. ref_agents/tools/health_scanner.py +1211 -0
  126. ref_agents/tools/hierarchy_manager.py +289 -0
  127. ref_agents/tools/invest_scorer.py +249 -0
  128. ref_agents/tools/jira_confluence_export.py +306 -0
  129. ref_agents/tools/json_output.py +76 -0
  130. ref_agents/tools/migration_mapper.py +946 -0
  131. ref_agents/tools/migration_readiness_scanner.py +209 -0
  132. ref_agents/tools/pattern_learner.py +522 -0
  133. ref_agents/tools/report_utils.py +155 -0
  134. ref_agents/tools/requirements_serializer.py +225 -0
  135. ref_agents/tools/security_audit_tool.py +106 -0
  136. ref_agents/tools/sequencing_engine.py +288 -0
  137. ref_agents/tools/summary_generator.py +275 -0
  138. ref_agents/tools/symbol_resolver.py +306 -0
  139. ref_agents/tools/symbol_smoke_runner.py +336 -0
  140. ref_agents/tools/test_plan_validator.py +189 -0
  141. ref_agents/tools/test_smell_walker.py +902 -0
  142. ref_agents/tools/tier1_fixer.py +502 -0
  143. ref_agents/tools/validators/__init__.py +419 -0
  144. ref_agents/tools/validators/architect.py +268 -0
  145. ref_agents/tools/validators/cutover_engineer.py +167 -0
  146. ref_agents/tools/validators/developer.py +180 -0
  147. ref_agents/tools/validators/discovery.py +150 -0
  148. ref_agents/tools/validators/forensic_engineer.py +191 -0
  149. ref_agents/tools/validators/impact_architect.py +181 -0
  150. ref_agents/tools/validators/migration_planner.py +166 -0
  151. ref_agents/tools/validators/parity_tester.py +155 -0
  152. ref_agents/tools/validators/platform_engineer.py +134 -0
  153. ref_agents/tools/validators/pr_reviewer.py +129 -0
  154. ref_agents/tools/validators/product_manager.py +291 -0
  155. ref_agents/tools/validators/qa_lead.py +172 -0
  156. ref_agents/tools/validators/scrum_master.py +212 -0
  157. ref_agents/tools/validators/security_owner.py +162 -0
  158. ref_agents/tools/validators/specifier.py +134 -0
  159. ref_agents/tools/validators/strategist.py +149 -0
  160. ref_agents/tools/validators/tester.py +121 -0
  161. ref_agents/tools/version_manager.py +202 -0
  162. ref_agents/tools/workflow_tools.py +1549 -0
  163. ref_agents/utils/__init__.py +21 -0
  164. ref_agents/utils/git_utils.py +351 -0
  165. ref_agents/utils/handoff_logger.py +368 -0
  166. ref_agents/utils/ignore_matcher.py +270 -0
  167. ref_agents/workflow/__init__.py +19 -0
  168. ref_agents/workflow/capabilities.py +328 -0
  169. ref_agents/workflow/state_machine.py +708 -0
  170. ref_agents/workflow/transitions.py +658 -0
  171. ref_agents-1.0.0.dist-info/METADATA +365 -0
  172. ref_agents-1.0.0.dist-info/RECORD +175 -0
  173. ref_agents-1.0.0.dist-info/WHEEL +4 -0
  174. ref_agents-1.0.0.dist-info/entry_points.txt +2 -0
  175. 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
+ )