empathy-framework 3.7.0__py3-none-any.whl → 3.7.1__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 (267) hide show
  1. coach_wizards/code_reviewer_README.md +60 -0
  2. coach_wizards/code_reviewer_wizard.py +180 -0
  3. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/METADATA +20 -2
  4. empathy_framework-3.7.1.dist-info/RECORD +327 -0
  5. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/top_level.txt +5 -1
  6. empathy_healthcare_plugin/monitors/__init__.py +9 -0
  7. empathy_healthcare_plugin/monitors/clinical_protocol_monitor.py +315 -0
  8. empathy_healthcare_plugin/monitors/monitoring/__init__.py +44 -0
  9. empathy_healthcare_plugin/monitors/monitoring/protocol_checker.py +300 -0
  10. empathy_healthcare_plugin/monitors/monitoring/protocol_loader.py +214 -0
  11. empathy_healthcare_plugin/monitors/monitoring/sensor_parsers.py +306 -0
  12. empathy_healthcare_plugin/monitors/monitoring/trajectory_analyzer.py +389 -0
  13. empathy_llm_toolkit/agent_factory/__init__.py +53 -0
  14. empathy_llm_toolkit/agent_factory/adapters/__init__.py +85 -0
  15. empathy_llm_toolkit/agent_factory/adapters/autogen_adapter.py +312 -0
  16. empathy_llm_toolkit/agent_factory/adapters/crewai_adapter.py +454 -0
  17. empathy_llm_toolkit/agent_factory/adapters/haystack_adapter.py +298 -0
  18. empathy_llm_toolkit/agent_factory/adapters/langchain_adapter.py +362 -0
  19. empathy_llm_toolkit/agent_factory/adapters/langgraph_adapter.py +333 -0
  20. empathy_llm_toolkit/agent_factory/adapters/native.py +228 -0
  21. empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +426 -0
  22. empathy_llm_toolkit/agent_factory/base.py +305 -0
  23. empathy_llm_toolkit/agent_factory/crews/__init__.py +67 -0
  24. empathy_llm_toolkit/agent_factory/crews/code_review.py +1113 -0
  25. empathy_llm_toolkit/agent_factory/crews/health_check.py +1246 -0
  26. empathy_llm_toolkit/agent_factory/crews/refactoring.py +1128 -0
  27. empathy_llm_toolkit/agent_factory/crews/security_audit.py +1018 -0
  28. empathy_llm_toolkit/agent_factory/decorators.py +286 -0
  29. empathy_llm_toolkit/agent_factory/factory.py +558 -0
  30. empathy_llm_toolkit/agent_factory/framework.py +192 -0
  31. empathy_llm_toolkit/agent_factory/memory_integration.py +324 -0
  32. empathy_llm_toolkit/agent_factory/resilient.py +320 -0
  33. empathy_llm_toolkit/cli/__init__.py +8 -0
  34. empathy_llm_toolkit/cli/sync_claude.py +487 -0
  35. empathy_llm_toolkit/code_health.py +150 -3
  36. empathy_llm_toolkit/config/__init__.py +29 -0
  37. empathy_llm_toolkit/config/unified.py +295 -0
  38. empathy_llm_toolkit/routing/__init__.py +32 -0
  39. empathy_llm_toolkit/routing/model_router.py +362 -0
  40. empathy_llm_toolkit/security/IMPLEMENTATION_SUMMARY.md +413 -0
  41. empathy_llm_toolkit/security/PHASE2_COMPLETE.md +384 -0
  42. empathy_llm_toolkit/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
  43. empathy_llm_toolkit/security/QUICK_REFERENCE.md +316 -0
  44. empathy_llm_toolkit/security/README.md +262 -0
  45. empathy_llm_toolkit/security/__init__.py +62 -0
  46. empathy_llm_toolkit/security/audit_logger.py +929 -0
  47. empathy_llm_toolkit/security/audit_logger_example.py +152 -0
  48. empathy_llm_toolkit/security/pii_scrubber.py +640 -0
  49. empathy_llm_toolkit/security/secrets_detector.py +678 -0
  50. empathy_llm_toolkit/security/secrets_detector_example.py +304 -0
  51. empathy_llm_toolkit/security/secure_memdocs.py +1192 -0
  52. empathy_llm_toolkit/security/secure_memdocs_example.py +278 -0
  53. empathy_llm_toolkit/wizards/__init__.py +38 -0
  54. empathy_llm_toolkit/wizards/base_wizard.py +364 -0
  55. empathy_llm_toolkit/wizards/customer_support_wizard.py +190 -0
  56. empathy_llm_toolkit/wizards/healthcare_wizard.py +362 -0
  57. empathy_llm_toolkit/wizards/patient_assessment_README.md +64 -0
  58. empathy_llm_toolkit/wizards/patient_assessment_wizard.py +193 -0
  59. empathy_llm_toolkit/wizards/technology_wizard.py +194 -0
  60. empathy_os/__init__.py +52 -52
  61. empathy_os/adaptive/__init__.py +13 -0
  62. empathy_os/adaptive/task_complexity.py +127 -0
  63. empathy_os/cli.py +118 -8
  64. empathy_os/cli_unified.py +121 -1
  65. empathy_os/config/__init__.py +63 -0
  66. empathy_os/config/xml_config.py +239 -0
  67. empathy_os/dashboard/__init__.py +15 -0
  68. empathy_os/dashboard/server.py +743 -0
  69. empathy_os/memory/__init__.py +195 -0
  70. empathy_os/memory/claude_memory.py +466 -0
  71. empathy_os/memory/config.py +224 -0
  72. empathy_os/memory/control_panel.py +1298 -0
  73. empathy_os/memory/edges.py +179 -0
  74. empathy_os/memory/graph.py +567 -0
  75. empathy_os/memory/long_term.py +1193 -0
  76. empathy_os/memory/nodes.py +179 -0
  77. empathy_os/memory/redis_bootstrap.py +540 -0
  78. empathy_os/memory/security/__init__.py +31 -0
  79. empathy_os/memory/security/audit_logger.py +930 -0
  80. empathy_os/memory/security/pii_scrubber.py +640 -0
  81. empathy_os/memory/security/secrets_detector.py +678 -0
  82. empathy_os/memory/short_term.py +2119 -0
  83. empathy_os/memory/storage/__init__.py +15 -0
  84. empathy_os/memory/summary_index.py +583 -0
  85. empathy_os/memory/unified.py +619 -0
  86. empathy_os/metrics/__init__.py +12 -0
  87. empathy_os/metrics/prompt_metrics.py +190 -0
  88. empathy_os/models/__init__.py +136 -0
  89. empathy_os/models/__main__.py +13 -0
  90. empathy_os/models/cli.py +655 -0
  91. empathy_os/models/empathy_executor.py +354 -0
  92. empathy_os/models/executor.py +252 -0
  93. empathy_os/models/fallback.py +671 -0
  94. empathy_os/models/provider_config.py +563 -0
  95. empathy_os/models/registry.py +382 -0
  96. empathy_os/models/tasks.py +302 -0
  97. empathy_os/models/telemetry.py +548 -0
  98. empathy_os/models/token_estimator.py +378 -0
  99. empathy_os/models/validation.py +274 -0
  100. empathy_os/monitoring/__init__.py +52 -0
  101. empathy_os/monitoring/alerts.py +23 -0
  102. empathy_os/monitoring/alerts_cli.py +268 -0
  103. empathy_os/monitoring/multi_backend.py +271 -0
  104. empathy_os/monitoring/otel_backend.py +363 -0
  105. empathy_os/optimization/__init__.py +19 -0
  106. empathy_os/optimization/context_optimizer.py +272 -0
  107. empathy_os/plugins/__init__.py +28 -0
  108. empathy_os/plugins/base.py +361 -0
  109. empathy_os/plugins/registry.py +268 -0
  110. empathy_os/project_index/__init__.py +30 -0
  111. empathy_os/project_index/cli.py +335 -0
  112. empathy_os/project_index/crew_integration.py +430 -0
  113. empathy_os/project_index/index.py +425 -0
  114. empathy_os/project_index/models.py +501 -0
  115. empathy_os/project_index/reports.py +473 -0
  116. empathy_os/project_index/scanner.py +538 -0
  117. empathy_os/prompts/__init__.py +61 -0
  118. empathy_os/prompts/config.py +77 -0
  119. empathy_os/prompts/context.py +177 -0
  120. empathy_os/prompts/parser.py +285 -0
  121. empathy_os/prompts/registry.py +313 -0
  122. empathy_os/prompts/templates.py +208 -0
  123. empathy_os/resilience/__init__.py +56 -0
  124. empathy_os/resilience/circuit_breaker.py +256 -0
  125. empathy_os/resilience/fallback.py +179 -0
  126. empathy_os/resilience/health.py +300 -0
  127. empathy_os/resilience/retry.py +209 -0
  128. empathy_os/resilience/timeout.py +135 -0
  129. empathy_os/routing/__init__.py +43 -0
  130. empathy_os/routing/chain_executor.py +433 -0
  131. empathy_os/routing/classifier.py +217 -0
  132. empathy_os/routing/smart_router.py +234 -0
  133. empathy_os/routing/wizard_registry.py +307 -0
  134. empathy_os/trust/__init__.py +28 -0
  135. empathy_os/trust/circuit_breaker.py +579 -0
  136. empathy_os/validation/__init__.py +19 -0
  137. empathy_os/validation/xml_validator.py +281 -0
  138. empathy_os/wizard_factory_cli.py +170 -0
  139. empathy_os/workflows/__init__.py +360 -0
  140. empathy_os/workflows/base.py +1530 -0
  141. empathy_os/workflows/bug_predict.py +962 -0
  142. empathy_os/workflows/code_review.py +960 -0
  143. empathy_os/workflows/code_review_adapters.py +310 -0
  144. empathy_os/workflows/code_review_pipeline.py +720 -0
  145. empathy_os/workflows/config.py +600 -0
  146. empathy_os/workflows/dependency_check.py +648 -0
  147. empathy_os/workflows/document_gen.py +1069 -0
  148. empathy_os/workflows/documentation_orchestrator.py +1205 -0
  149. empathy_os/workflows/health_check.py +679 -0
  150. empathy_os/workflows/keyboard_shortcuts/__init__.py +39 -0
  151. empathy_os/workflows/keyboard_shortcuts/generators.py +386 -0
  152. empathy_os/workflows/keyboard_shortcuts/parsers.py +414 -0
  153. empathy_os/workflows/keyboard_shortcuts/prompts.py +295 -0
  154. empathy_os/workflows/keyboard_shortcuts/schema.py +193 -0
  155. empathy_os/workflows/keyboard_shortcuts/workflow.py +505 -0
  156. empathy_os/workflows/manage_documentation.py +804 -0
  157. empathy_os/workflows/new_sample_workflow1.py +146 -0
  158. empathy_os/workflows/new_sample_workflow1_README.md +150 -0
  159. empathy_os/workflows/perf_audit.py +687 -0
  160. empathy_os/workflows/pr_review.py +748 -0
  161. empathy_os/workflows/progress.py +445 -0
  162. empathy_os/workflows/progress_server.py +322 -0
  163. empathy_os/workflows/refactor_plan.py +691 -0
  164. empathy_os/workflows/release_prep.py +808 -0
  165. empathy_os/workflows/research_synthesis.py +404 -0
  166. empathy_os/workflows/secure_release.py +585 -0
  167. empathy_os/workflows/security_adapters.py +297 -0
  168. empathy_os/workflows/security_audit.py +1050 -0
  169. empathy_os/workflows/step_config.py +234 -0
  170. empathy_os/workflows/test5.py +125 -0
  171. empathy_os/workflows/test5_README.md +158 -0
  172. empathy_os/workflows/test_gen.py +1855 -0
  173. empathy_os/workflows/test_lifecycle.py +526 -0
  174. empathy_os/workflows/test_maintenance.py +626 -0
  175. empathy_os/workflows/test_maintenance_cli.py +590 -0
  176. empathy_os/workflows/test_maintenance_crew.py +821 -0
  177. empathy_os/workflows/xml_enhanced_crew.py +285 -0
  178. empathy_software_plugin/cli/__init__.py +120 -0
  179. empathy_software_plugin/cli/inspect.py +362 -0
  180. empathy_software_plugin/cli.py +3 -1
  181. empathy_software_plugin/wizards/__init__.py +42 -0
  182. empathy_software_plugin/wizards/advanced_debugging_wizard.py +392 -0
  183. empathy_software_plugin/wizards/agent_orchestration_wizard.py +511 -0
  184. empathy_software_plugin/wizards/ai_collaboration_wizard.py +503 -0
  185. empathy_software_plugin/wizards/ai_context_wizard.py +441 -0
  186. empathy_software_plugin/wizards/ai_documentation_wizard.py +503 -0
  187. empathy_software_plugin/wizards/base_wizard.py +288 -0
  188. empathy_software_plugin/wizards/book_chapter_wizard.py +519 -0
  189. empathy_software_plugin/wizards/code_review_wizard.py +606 -0
  190. empathy_software_plugin/wizards/debugging/__init__.py +50 -0
  191. empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +414 -0
  192. empathy_software_plugin/wizards/debugging/config_loaders.py +442 -0
  193. empathy_software_plugin/wizards/debugging/fix_applier.py +469 -0
  194. empathy_software_plugin/wizards/debugging/language_patterns.py +383 -0
  195. empathy_software_plugin/wizards/debugging/linter_parsers.py +470 -0
  196. empathy_software_plugin/wizards/debugging/verification.py +369 -0
  197. empathy_software_plugin/wizards/enhanced_testing_wizard.py +537 -0
  198. empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +816 -0
  199. empathy_software_plugin/wizards/multi_model_wizard.py +501 -0
  200. empathy_software_plugin/wizards/pattern_extraction_wizard.py +422 -0
  201. empathy_software_plugin/wizards/pattern_retriever_wizard.py +400 -0
  202. empathy_software_plugin/wizards/performance/__init__.py +9 -0
  203. empathy_software_plugin/wizards/performance/bottleneck_detector.py +221 -0
  204. empathy_software_plugin/wizards/performance/profiler_parsers.py +278 -0
  205. empathy_software_plugin/wizards/performance/trajectory_analyzer.py +429 -0
  206. empathy_software_plugin/wizards/performance_profiling_wizard.py +305 -0
  207. empathy_software_plugin/wizards/prompt_engineering_wizard.py +425 -0
  208. empathy_software_plugin/wizards/rag_pattern_wizard.py +461 -0
  209. empathy_software_plugin/wizards/security/__init__.py +32 -0
  210. empathy_software_plugin/wizards/security/exploit_analyzer.py +290 -0
  211. empathy_software_plugin/wizards/security/owasp_patterns.py +241 -0
  212. empathy_software_plugin/wizards/security/vulnerability_scanner.py +604 -0
  213. empathy_software_plugin/wizards/security_analysis_wizard.py +322 -0
  214. empathy_software_plugin/wizards/security_learning_wizard.py +740 -0
  215. empathy_software_plugin/wizards/tech_debt_wizard.py +726 -0
  216. empathy_software_plugin/wizards/testing/__init__.py +27 -0
  217. empathy_software_plugin/wizards/testing/coverage_analyzer.py +459 -0
  218. empathy_software_plugin/wizards/testing/quality_analyzer.py +531 -0
  219. empathy_software_plugin/wizards/testing/test_suggester.py +533 -0
  220. empathy_software_plugin/wizards/testing_wizard.py +274 -0
  221. hot_reload/README.md +473 -0
  222. hot_reload/__init__.py +62 -0
  223. hot_reload/config.py +84 -0
  224. hot_reload/integration.py +228 -0
  225. hot_reload/reloader.py +298 -0
  226. hot_reload/watcher.py +179 -0
  227. hot_reload/websocket.py +176 -0
  228. scaffolding/README.md +589 -0
  229. scaffolding/__init__.py +35 -0
  230. scaffolding/__main__.py +14 -0
  231. scaffolding/cli.py +240 -0
  232. test_generator/__init__.py +38 -0
  233. test_generator/__main__.py +14 -0
  234. test_generator/cli.py +226 -0
  235. test_generator/generator.py +325 -0
  236. test_generator/risk_analyzer.py +216 -0
  237. workflow_patterns/__init__.py +33 -0
  238. workflow_patterns/behavior.py +249 -0
  239. workflow_patterns/core.py +76 -0
  240. workflow_patterns/output.py +99 -0
  241. workflow_patterns/registry.py +255 -0
  242. workflow_patterns/structural.py +288 -0
  243. workflow_scaffolding/__init__.py +11 -0
  244. workflow_scaffolding/__main__.py +12 -0
  245. workflow_scaffolding/cli.py +206 -0
  246. workflow_scaffolding/generator.py +265 -0
  247. agents/code_inspection/patterns/inspection/recurring_B112.json +0 -18
  248. agents/code_inspection/patterns/inspection/recurring_F541.json +0 -16
  249. agents/code_inspection/patterns/inspection/recurring_FORMAT.json +0 -25
  250. agents/code_inspection/patterns/inspection/recurring_bug_20250822_def456.json +0 -16
  251. agents/code_inspection/patterns/inspection/recurring_bug_20250915_abc123.json +0 -16
  252. agents/code_inspection/patterns/inspection/recurring_bug_20251212_3c5b9951.json +0 -16
  253. agents/code_inspection/patterns/inspection/recurring_bug_20251212_97c0f72f.json +0 -16
  254. agents/code_inspection/patterns/inspection/recurring_bug_20251212_a0871d53.json +0 -16
  255. agents/code_inspection/patterns/inspection/recurring_bug_20251212_a9b6ec41.json +0 -16
  256. agents/code_inspection/patterns/inspection/recurring_bug_null_001.json +0 -16
  257. agents/code_inspection/patterns/inspection/recurring_builtin.json +0 -16
  258. agents/compliance_anticipation_agent.py +0 -1422
  259. agents/compliance_db.py +0 -339
  260. agents/epic_integration_wizard.py +0 -530
  261. agents/notifications.py +0 -291
  262. agents/trust_building_behaviors.py +0 -872
  263. empathy_framework-3.7.0.dist-info/RECORD +0 -105
  264. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/WHEEL +0 -0
  265. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/entry_points.txt +0 -0
  266. {empathy_framework-3.7.0.dist-info → empathy_framework-3.7.1.dist-info}/licenses/LICENSE +0 -0
  267. /empathy_os/{monitoring.py → agent_monitoring.py} +0 -0
@@ -0,0 +1,442 @@
1
+ """Linting Configuration Loaders
2
+
3
+ Reads linting configuration files to understand project standards.
4
+
5
+ Copyright 2025 Smart AI Memory, LLC
6
+ Licensed under Fair Source 0.9
7
+ """
8
+
9
+ import json
10
+ import re
11
+ from dataclasses import dataclass
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+
16
+ @dataclass
17
+ class LintConfig:
18
+ """Standardized linting configuration.
19
+
20
+ Unified format across all linters.
21
+ """
22
+
23
+ linter: str
24
+ config_file: str
25
+ rules: dict[str, Any]
26
+ extends: list[str]
27
+ plugins: list[str]
28
+ severity_overrides: dict[str, str]
29
+ raw_config: dict[str, Any]
30
+
31
+ def get_rule_severity(self, rule_name: str) -> str | None:
32
+ """Get configured severity for rule"""
33
+ rule_config = self.rules.get(rule_name)
34
+
35
+ if rule_config is None:
36
+ return None
37
+
38
+ # Handle different config formats
39
+ if isinstance(rule_config, str):
40
+ return rule_config
41
+ if isinstance(rule_config, list) and len(rule_config) > 0:
42
+ return str(rule_config[0])
43
+ if isinstance(rule_config, int):
44
+ # ESLint: 0=off, 1=warn, 2=error
45
+ return ["off", "warn", "error"][rule_config] if 0 <= rule_config <= 2 else None
46
+
47
+ return None
48
+
49
+ def is_rule_enabled(self, rule_name: str) -> bool:
50
+ """Check if rule is enabled"""
51
+ severity = self.get_rule_severity(rule_name)
52
+ return severity not in [None, "off", "0", 0]
53
+
54
+
55
+ class BaseConfigLoader:
56
+ """Base class for configuration loaders"""
57
+
58
+ def __init__(self, linter_name: str):
59
+ self.linter_name = linter_name
60
+
61
+ def load(self, config_path: str) -> LintConfig:
62
+ """Load configuration from file"""
63
+ raise NotImplementedError(
64
+ f"{self.__class__.__name__}.load() must be implemented. "
65
+ "Create a subclass of BaseConfigLoader and implement the load() method. "
66
+ f"See ESLintConfigLoader, PylintConfigLoader, or TypeScriptConfigLoader for examples."
67
+ )
68
+
69
+ def find_config(self, start_dir: str) -> str | None:
70
+ """Find config file starting from directory"""
71
+ raise NotImplementedError(
72
+ f"{self.__class__.__name__}.find_config() must be implemented. "
73
+ "Create a subclass of BaseConfigLoader and implement the find_config() method. "
74
+ f"See ESLintConfigLoader, PylintConfigLoader, or TypeScriptConfigLoader for examples."
75
+ )
76
+
77
+
78
+ class ESLintConfigLoader(BaseConfigLoader):
79
+ """Load ESLint configuration.
80
+
81
+ Supports:
82
+ - .eslintrc.json
83
+ - .eslintrc.js (limited - JSON portion only)
84
+ - .eslintrc.yml (via JSON-compatible subset)
85
+ - package.json (eslintConfig section)
86
+ """
87
+
88
+ CONFIG_FILES = [
89
+ ".eslintrc.json",
90
+ ".eslintrc",
91
+ ".eslintrc.js",
92
+ ".eslintrc.yml",
93
+ ".eslintrc.yaml",
94
+ "package.json",
95
+ ]
96
+
97
+ def __init__(self):
98
+ super().__init__("eslint")
99
+
100
+ def find_config(self, start_dir: str) -> str | None:
101
+ """Find ESLint config file"""
102
+ current = Path(start_dir).resolve()
103
+
104
+ while True:
105
+ for config_file in self.CONFIG_FILES:
106
+ config_path = current / config_file
107
+ if config_path.exists():
108
+ return str(config_path)
109
+
110
+ # Stop at root
111
+ if current.parent == current:
112
+ break
113
+
114
+ current = current.parent
115
+
116
+ return None
117
+
118
+ def load(self, config_path: str) -> LintConfig:
119
+ """Load ESLint configuration"""
120
+ path = Path(config_path)
121
+
122
+ if not path.exists():
123
+ raise FileNotFoundError(f"Config file not found: {config_path}")
124
+
125
+ # Handle package.json
126
+ if path.name == "package.json":
127
+ return self._load_package_json(path)
128
+
129
+ # Handle .js files (try to extract JSON)
130
+ if path.suffix == ".js":
131
+ return self._load_js_config(path)
132
+
133
+ # Handle JSON files
134
+ with open(path) as f:
135
+ config_data = json.load(f)
136
+
137
+ return self._parse_config(config_data, str(path))
138
+
139
+ def _load_package_json(self, path: Path) -> LintConfig:
140
+ """Load ESLint config from package.json"""
141
+ with open(path) as f:
142
+ package_data = json.load(f)
143
+
144
+ eslint_config = package_data.get("eslintConfig", {})
145
+ return self._parse_config(eslint_config, str(path))
146
+
147
+ def _load_js_config(self, path: Path) -> LintConfig:
148
+ """Load ESLint config from .js file.
149
+
150
+ Limited support - extracts JSON-like objects.
151
+ """
152
+ with open(path) as f:
153
+ content = f.read()
154
+
155
+ # Try to find module.exports = { ... }
156
+ match = re.search(r"module\.exports\s*=\s*(\{[\s\S]*?\})\s*;?", content)
157
+
158
+ if match:
159
+ json_str = match.group(1)
160
+ # Try to convert JS object to JSON
161
+ # This is a simplified approach - may not work for complex configs
162
+ try:
163
+ config_data = json.loads(json_str)
164
+ return self._parse_config(config_data, str(path))
165
+ except json.JSONDecodeError:
166
+ # Return minimal config
167
+ return LintConfig(
168
+ linter=self.linter_name,
169
+ config_file=str(path),
170
+ rules={},
171
+ extends=[],
172
+ plugins=[],
173
+ severity_overrides={},
174
+ raw_config={"note": "JS config - limited parsing"},
175
+ )
176
+
177
+ raise ValueError(f"Could not parse JS config: {path}") from None
178
+
179
+ def _parse_config(self, config_data: dict, config_file: str) -> LintConfig:
180
+ """Parse ESLint config data"""
181
+ return LintConfig(
182
+ linter=self.linter_name,
183
+ config_file=config_file,
184
+ rules=config_data.get("rules", {}),
185
+ extends=self._normalize_extends(config_data.get("extends")),
186
+ plugins=config_data.get("plugins", []),
187
+ severity_overrides={},
188
+ raw_config=config_data,
189
+ )
190
+
191
+ def _normalize_extends(self, extends_value: Any) -> list[str]:
192
+ """Normalize extends to list"""
193
+ if extends_value is None:
194
+ return []
195
+ if isinstance(extends_value, str):
196
+ return [extends_value]
197
+ if isinstance(extends_value, list):
198
+ return extends_value
199
+ return []
200
+
201
+
202
+ class PylintConfigLoader(BaseConfigLoader):
203
+ """Load Pylint configuration.
204
+
205
+ Supports:
206
+ - pyproject.toml (tool.pylint section)
207
+ - .pylintrc
208
+ - pylintrc
209
+ - setup.cfg
210
+ """
211
+
212
+ def __init__(self):
213
+ super().__init__("pylint")
214
+
215
+ def find_config(self, start_dir: str) -> str | None:
216
+ """Find Pylint config file"""
217
+ current = Path(start_dir).resolve()
218
+
219
+ config_files = ["pyproject.toml", ".pylintrc", "pylintrc", "setup.cfg"]
220
+
221
+ while True:
222
+ for config_file in config_files:
223
+ config_path = current / config_file
224
+ if config_path.exists():
225
+ return str(config_path)
226
+
227
+ if current.parent == current:
228
+ break
229
+
230
+ current = current.parent
231
+
232
+ return None
233
+
234
+ def load(self, config_path: str) -> LintConfig:
235
+ """Load Pylint configuration"""
236
+ path = Path(config_path)
237
+
238
+ if not path.exists():
239
+ raise FileNotFoundError(f"Config file not found: {config_path}")
240
+
241
+ if path.name == "pyproject.toml":
242
+ return self._load_pyproject(path)
243
+ return self._load_ini_style(path)
244
+
245
+ def _load_pyproject(self, path: Path) -> LintConfig:
246
+ """Load from pyproject.toml"""
247
+ try:
248
+ import tomli
249
+ except ImportError:
250
+ # Fallback for Python 3.11+
251
+ try:
252
+ import tomllib as tomli
253
+ except ImportError as e:
254
+ raise ImportError("tomli or tomllib required for pyproject.toml") from e
255
+
256
+ with open(path, "rb") as f:
257
+ data = tomli.load(f)
258
+
259
+ pylint_config = data.get("tool", {}).get("pylint", {})
260
+
261
+ # Extract rules
262
+ rules = {}
263
+ if "enable" in pylint_config:
264
+ for rule in pylint_config["enable"]:
265
+ rules[rule] = "enabled"
266
+ if "disable" in pylint_config:
267
+ for rule in pylint_config["disable"]:
268
+ rules[rule] = "disabled"
269
+
270
+ # Get messages control
271
+ messages_control = pylint_config.get("MESSAGES CONTROL", {})
272
+ if "disable" in messages_control:
273
+ for rule in messages_control["disable"].split(","):
274
+ rules[rule.strip()] = "disabled"
275
+
276
+ return LintConfig(
277
+ linter=self.linter_name,
278
+ config_file=str(path),
279
+ rules=rules,
280
+ extends=[],
281
+ plugins=pylint_config.get("load-plugins", []),
282
+ severity_overrides={},
283
+ raw_config=pylint_config,
284
+ )
285
+
286
+ def _load_ini_style(self, path: Path) -> LintConfig:
287
+ """Load from .pylintrc or setup.cfg"""
288
+ import configparser
289
+
290
+ config = configparser.ConfigParser()
291
+ config.read(path)
292
+
293
+ rules = {}
294
+
295
+ # Check for disabled rules
296
+ if config.has_option("MESSAGES CONTROL", "disable"):
297
+ disabled = config.get("MESSAGES CONTROL", "disable")
298
+ for rule in disabled.split(","):
299
+ rules[rule.strip()] = "disabled"
300
+
301
+ if config.has_option("MESSAGES CONTROL", "enable"):
302
+ enabled = config.get("MESSAGES CONTROL", "enable")
303
+ for rule in enabled.split(","):
304
+ rules[rule.strip()] = "enabled"
305
+
306
+ plugins = []
307
+ if config.has_option("MASTER", "load-plugins"):
308
+ plugins = config.get("MASTER", "load-plugins").split(",")
309
+
310
+ return LintConfig(
311
+ linter=self.linter_name,
312
+ config_file=str(path),
313
+ rules=rules,
314
+ extends=[],
315
+ plugins=[p.strip() for p in plugins],
316
+ severity_overrides={},
317
+ raw_config=dict(config.items()) if hasattr(config, "items") else {},
318
+ )
319
+
320
+
321
+ class TypeScriptConfigLoader(BaseConfigLoader):
322
+ """Load TypeScript configuration.
323
+
324
+ Supports tsconfig.json
325
+ """
326
+
327
+ def __init__(self):
328
+ super().__init__("typescript")
329
+
330
+ def find_config(self, start_dir: str) -> str | None:
331
+ """Find tsconfig.json"""
332
+ current = Path(start_dir).resolve()
333
+
334
+ while True:
335
+ tsconfig = current / "tsconfig.json"
336
+ if tsconfig.exists():
337
+ return str(tsconfig)
338
+
339
+ if current.parent == current:
340
+ break
341
+
342
+ current = current.parent
343
+
344
+ return None
345
+
346
+ def load(self, config_path: str) -> LintConfig:
347
+ """Load TypeScript configuration"""
348
+ path = Path(config_path)
349
+
350
+ if not path.exists():
351
+ raise FileNotFoundError(f"Config file not found: {config_path}")
352
+
353
+ with open(path) as f:
354
+ # TypeScript allows comments in JSON
355
+ content = f.read()
356
+ # Remove comments (simplified)
357
+ content = re.sub(r"//.*?\n", "\n", content)
358
+ content = re.sub(r"/\*.*?\*/", "", content, flags=re.DOTALL)
359
+
360
+ config_data = json.loads(content)
361
+
362
+ compiler_options = config_data.get("compilerOptions", {})
363
+
364
+ # Convert compiler options to "rules"
365
+ rules = {}
366
+ for option, value in compiler_options.items():
367
+ rules[option] = value
368
+
369
+ return LintConfig(
370
+ linter=self.linter_name,
371
+ config_file=str(path),
372
+ rules=rules,
373
+ extends=[config_data.get("extends", "")],
374
+ plugins=[],
375
+ severity_overrides={},
376
+ raw_config=config_data,
377
+ )
378
+
379
+
380
+ class ConfigLoaderFactory:
381
+ """Factory for creating config loaders"""
382
+
383
+ _loaders = {
384
+ "eslint": ESLintConfigLoader,
385
+ "pylint": PylintConfigLoader,
386
+ "typescript": TypeScriptConfigLoader,
387
+ "tsc": TypeScriptConfigLoader,
388
+ }
389
+
390
+ @classmethod
391
+ def create(cls, linter_name: str) -> BaseConfigLoader:
392
+ """Create config loader for linter"""
393
+ loader_class = cls._loaders.get(linter_name.lower())
394
+
395
+ if not loader_class:
396
+ raise ValueError(
397
+ f"Unsupported linter config: {linter_name}. "
398
+ f"Supported: {', '.join(cls._loaders.keys())}",
399
+ )
400
+
401
+ return loader_class()
402
+
403
+ @classmethod
404
+ def get_supported_linters(cls) -> list[str]:
405
+ """Get supported linters"""
406
+ return list(cls._loaders.keys())
407
+
408
+
409
+ def load_config(
410
+ linter_name: str,
411
+ config_path: str | None = None,
412
+ start_dir: str | None = None,
413
+ ) -> LintConfig | None:
414
+ """Load linting configuration.
415
+
416
+ Args:
417
+ linter_name: Name of linter
418
+ config_path: Explicit config path (optional)
419
+ start_dir: Directory to start search from (optional)
420
+
421
+ Returns:
422
+ LintConfig or None if not found
423
+
424
+ Example:
425
+ >>> config = load_config("eslint", start_dir="/path/to/project")
426
+ >>> if config:
427
+ ... print(f"Rules: {len(config.rules)}")
428
+
429
+ """
430
+ loader = ConfigLoaderFactory.create(linter_name)
431
+
432
+ # If explicit path provided
433
+ if config_path:
434
+ return loader.load(config_path)
435
+
436
+ # Otherwise, search for config
437
+ if start_dir:
438
+ found_config = loader.find_config(start_dir)
439
+ if found_config:
440
+ return loader.load(found_config)
441
+
442
+ return None