empathy-framework 4.6.6__py3-none-any.whl → 4.7.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 (247) hide show
  1. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/METADATA +7 -6
  2. empathy_framework-4.7.0.dist-info/RECORD +354 -0
  3. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/top_level.txt +0 -2
  4. empathy_healthcare_plugin/monitors/monitoring/__init__.py +9 -9
  5. empathy_llm_toolkit/agent_factory/__init__.py +6 -6
  6. empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +7 -10
  7. empathy_llm_toolkit/agents_md/__init__.py +22 -0
  8. empathy_llm_toolkit/agents_md/loader.py +218 -0
  9. empathy_llm_toolkit/agents_md/parser.py +271 -0
  10. empathy_llm_toolkit/agents_md/registry.py +307 -0
  11. empathy_llm_toolkit/commands/__init__.py +51 -0
  12. empathy_llm_toolkit/commands/context.py +375 -0
  13. empathy_llm_toolkit/commands/loader.py +301 -0
  14. empathy_llm_toolkit/commands/models.py +231 -0
  15. empathy_llm_toolkit/commands/parser.py +371 -0
  16. empathy_llm_toolkit/commands/registry.py +429 -0
  17. empathy_llm_toolkit/config/__init__.py +8 -8
  18. empathy_llm_toolkit/config/unified.py +3 -7
  19. empathy_llm_toolkit/context/__init__.py +22 -0
  20. empathy_llm_toolkit/context/compaction.py +455 -0
  21. empathy_llm_toolkit/context/manager.py +434 -0
  22. empathy_llm_toolkit/hooks/__init__.py +24 -0
  23. empathy_llm_toolkit/hooks/config.py +306 -0
  24. empathy_llm_toolkit/hooks/executor.py +289 -0
  25. empathy_llm_toolkit/hooks/registry.py +302 -0
  26. empathy_llm_toolkit/hooks/scripts/__init__.py +39 -0
  27. empathy_llm_toolkit/hooks/scripts/evaluate_session.py +201 -0
  28. empathy_llm_toolkit/hooks/scripts/first_time_init.py +285 -0
  29. empathy_llm_toolkit/hooks/scripts/pre_compact.py +207 -0
  30. empathy_llm_toolkit/hooks/scripts/session_end.py +183 -0
  31. empathy_llm_toolkit/hooks/scripts/session_start.py +163 -0
  32. empathy_llm_toolkit/hooks/scripts/suggest_compact.py +225 -0
  33. empathy_llm_toolkit/learning/__init__.py +30 -0
  34. empathy_llm_toolkit/learning/evaluator.py +438 -0
  35. empathy_llm_toolkit/learning/extractor.py +514 -0
  36. empathy_llm_toolkit/learning/storage.py +560 -0
  37. empathy_llm_toolkit/providers.py +4 -11
  38. empathy_llm_toolkit/security/__init__.py +17 -17
  39. empathy_llm_toolkit/utils/tokens.py +2 -5
  40. empathy_os/__init__.py +202 -70
  41. empathy_os/cache_monitor.py +5 -3
  42. empathy_os/cli/__init__.py +11 -55
  43. empathy_os/cli/__main__.py +29 -15
  44. empathy_os/cli/commands/inspection.py +21 -12
  45. empathy_os/cli/commands/memory.py +4 -12
  46. empathy_os/cli/commands/profiling.py +198 -0
  47. empathy_os/cli/commands/utilities.py +27 -7
  48. empathy_os/cli.py +28 -57
  49. empathy_os/cli_unified.py +525 -1164
  50. empathy_os/cost_tracker.py +9 -3
  51. empathy_os/dashboard/server.py +200 -2
  52. empathy_os/hot_reload/__init__.py +7 -7
  53. empathy_os/hot_reload/config.py +6 -7
  54. empathy_os/hot_reload/integration.py +35 -35
  55. empathy_os/hot_reload/reloader.py +57 -57
  56. empathy_os/hot_reload/watcher.py +28 -28
  57. empathy_os/hot_reload/websocket.py +2 -2
  58. empathy_os/memory/__init__.py +11 -4
  59. empathy_os/memory/claude_memory.py +1 -1
  60. empathy_os/memory/cross_session.py +8 -12
  61. empathy_os/memory/edges.py +6 -6
  62. empathy_os/memory/file_session.py +770 -0
  63. empathy_os/memory/graph.py +30 -30
  64. empathy_os/memory/nodes.py +6 -6
  65. empathy_os/memory/short_term.py +15 -9
  66. empathy_os/memory/unified.py +606 -140
  67. empathy_os/meta_workflows/agent_creator.py +3 -9
  68. empathy_os/meta_workflows/cli_meta_workflows.py +113 -53
  69. empathy_os/meta_workflows/form_engine.py +6 -18
  70. empathy_os/meta_workflows/intent_detector.py +64 -24
  71. empathy_os/meta_workflows/models.py +3 -1
  72. empathy_os/meta_workflows/pattern_learner.py +13 -31
  73. empathy_os/meta_workflows/plan_generator.py +55 -47
  74. empathy_os/meta_workflows/session_context.py +2 -3
  75. empathy_os/meta_workflows/workflow.py +20 -51
  76. empathy_os/models/cli.py +2 -2
  77. empathy_os/models/tasks.py +1 -2
  78. empathy_os/models/telemetry.py +4 -1
  79. empathy_os/models/token_estimator.py +3 -1
  80. empathy_os/monitoring/alerts.py +938 -9
  81. empathy_os/monitoring/alerts_cli.py +346 -183
  82. empathy_os/orchestration/execution_strategies.py +12 -29
  83. empathy_os/orchestration/pattern_learner.py +20 -26
  84. empathy_os/orchestration/real_tools.py +6 -15
  85. empathy_os/platform_utils.py +2 -1
  86. empathy_os/plugins/__init__.py +2 -2
  87. empathy_os/plugins/base.py +64 -64
  88. empathy_os/plugins/registry.py +32 -32
  89. empathy_os/project_index/index.py +49 -15
  90. empathy_os/project_index/models.py +1 -2
  91. empathy_os/project_index/reports.py +1 -1
  92. empathy_os/project_index/scanner.py +1 -0
  93. empathy_os/redis_memory.py +10 -7
  94. empathy_os/resilience/__init__.py +1 -1
  95. empathy_os/resilience/health.py +10 -10
  96. empathy_os/routing/__init__.py +7 -7
  97. empathy_os/routing/chain_executor.py +37 -37
  98. empathy_os/routing/classifier.py +36 -36
  99. empathy_os/routing/smart_router.py +40 -40
  100. empathy_os/routing/{wizard_registry.py → workflow_registry.py} +47 -47
  101. empathy_os/scaffolding/__init__.py +8 -8
  102. empathy_os/scaffolding/__main__.py +1 -1
  103. empathy_os/scaffolding/cli.py +28 -28
  104. empathy_os/socratic/__init__.py +3 -19
  105. empathy_os/socratic/ab_testing.py +25 -36
  106. empathy_os/socratic/blueprint.py +38 -38
  107. empathy_os/socratic/cli.py +34 -20
  108. empathy_os/socratic/collaboration.py +30 -28
  109. empathy_os/socratic/domain_templates.py +9 -1
  110. empathy_os/socratic/embeddings.py +17 -13
  111. empathy_os/socratic/engine.py +135 -70
  112. empathy_os/socratic/explainer.py +70 -60
  113. empathy_os/socratic/feedback.py +24 -19
  114. empathy_os/socratic/forms.py +15 -10
  115. empathy_os/socratic/generator.py +51 -35
  116. empathy_os/socratic/llm_analyzer.py +25 -23
  117. empathy_os/socratic/mcp_server.py +99 -159
  118. empathy_os/socratic/session.py +19 -13
  119. empathy_os/socratic/storage.py +98 -67
  120. empathy_os/socratic/success.py +38 -27
  121. empathy_os/socratic/visual_editor.py +51 -39
  122. empathy_os/socratic/web_ui.py +99 -66
  123. empathy_os/telemetry/cli.py +3 -1
  124. empathy_os/telemetry/usage_tracker.py +1 -3
  125. empathy_os/test_generator/__init__.py +3 -3
  126. empathy_os/test_generator/cli.py +28 -28
  127. empathy_os/test_generator/generator.py +64 -66
  128. empathy_os/test_generator/risk_analyzer.py +11 -11
  129. empathy_os/vscode_bridge.py +173 -0
  130. empathy_os/workflows/__init__.py +212 -120
  131. empathy_os/workflows/batch_processing.py +8 -24
  132. empathy_os/workflows/bug_predict.py +1 -1
  133. empathy_os/workflows/code_review.py +20 -5
  134. empathy_os/workflows/code_review_pipeline.py +13 -8
  135. empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
  136. empathy_os/workflows/manage_documentation.py +1 -0
  137. empathy_os/workflows/orchestrated_health_check.py +6 -11
  138. empathy_os/workflows/orchestrated_release_prep.py +3 -3
  139. empathy_os/workflows/pr_review.py +18 -10
  140. empathy_os/workflows/progressive/__init__.py +2 -12
  141. empathy_os/workflows/progressive/cli.py +14 -37
  142. empathy_os/workflows/progressive/core.py +12 -12
  143. empathy_os/workflows/progressive/orchestrator.py +166 -144
  144. empathy_os/workflows/progressive/reports.py +22 -31
  145. empathy_os/workflows/progressive/telemetry.py +8 -14
  146. empathy_os/workflows/progressive/test_gen.py +29 -48
  147. empathy_os/workflows/progressive/workflow.py +31 -70
  148. empathy_os/workflows/release_prep.py +21 -6
  149. empathy_os/workflows/release_prep_crew.py +1 -0
  150. empathy_os/workflows/secure_release.py +13 -6
  151. empathy_os/workflows/security_audit.py +8 -3
  152. empathy_os/workflows/test_coverage_boost_crew.py +3 -2
  153. empathy_os/workflows/test_maintenance_crew.py +1 -0
  154. empathy_os/workflows/test_runner.py +16 -12
  155. empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
  156. empathy_software_plugin/cli.py +0 -122
  157. coach_wizards/__init__.py +0 -45
  158. coach_wizards/accessibility_wizard.py +0 -91
  159. coach_wizards/api_wizard.py +0 -91
  160. coach_wizards/base_wizard.py +0 -209
  161. coach_wizards/cicd_wizard.py +0 -91
  162. coach_wizards/code_reviewer_README.md +0 -60
  163. coach_wizards/code_reviewer_wizard.py +0 -180
  164. coach_wizards/compliance_wizard.py +0 -91
  165. coach_wizards/database_wizard.py +0 -91
  166. coach_wizards/debugging_wizard.py +0 -91
  167. coach_wizards/documentation_wizard.py +0 -91
  168. coach_wizards/generate_wizards.py +0 -347
  169. coach_wizards/localization_wizard.py +0 -173
  170. coach_wizards/migration_wizard.py +0 -91
  171. coach_wizards/monitoring_wizard.py +0 -91
  172. coach_wizards/observability_wizard.py +0 -91
  173. coach_wizards/performance_wizard.py +0 -91
  174. coach_wizards/prompt_engineering_wizard.py +0 -661
  175. coach_wizards/refactoring_wizard.py +0 -91
  176. coach_wizards/scaling_wizard.py +0 -90
  177. coach_wizards/security_wizard.py +0 -92
  178. coach_wizards/testing_wizard.py +0 -91
  179. empathy_framework-4.6.6.dist-info/RECORD +0 -410
  180. empathy_llm_toolkit/wizards/__init__.py +0 -43
  181. empathy_llm_toolkit/wizards/base_wizard.py +0 -364
  182. empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
  183. empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
  184. empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
  185. empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
  186. empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
  187. empathy_os/wizard_factory_cli.py +0 -170
  188. empathy_software_plugin/wizards/__init__.py +0 -42
  189. empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
  190. empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
  191. empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
  192. empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
  193. empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
  194. empathy_software_plugin/wizards/base_wizard.py +0 -288
  195. empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
  196. empathy_software_plugin/wizards/code_review_wizard.py +0 -604
  197. empathy_software_plugin/wizards/debugging/__init__.py +0 -50
  198. empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
  199. empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
  200. empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
  201. empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
  202. empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
  203. empathy_software_plugin/wizards/debugging/verification.py +0 -369
  204. empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
  205. empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
  206. empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
  207. empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
  208. empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
  209. empathy_software_plugin/wizards/performance/__init__.py +0 -9
  210. empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
  211. empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
  212. empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
  213. empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
  214. empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
  215. empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
  216. empathy_software_plugin/wizards/security/__init__.py +0 -32
  217. empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
  218. empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
  219. empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
  220. empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
  221. empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
  222. empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
  223. empathy_software_plugin/wizards/testing/__init__.py +0 -27
  224. empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
  225. empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
  226. empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
  227. empathy_software_plugin/wizards/testing_wizard.py +0 -274
  228. wizards/__init__.py +0 -82
  229. wizards/admission_assessment_wizard.py +0 -644
  230. wizards/care_plan.py +0 -321
  231. wizards/clinical_assessment.py +0 -769
  232. wizards/discharge_planning.py +0 -77
  233. wizards/discharge_summary_wizard.py +0 -468
  234. wizards/dosage_calculation.py +0 -497
  235. wizards/incident_report_wizard.py +0 -454
  236. wizards/medication_reconciliation.py +0 -85
  237. wizards/nursing_assessment.py +0 -171
  238. wizards/patient_education.py +0 -654
  239. wizards/quality_improvement.py +0 -705
  240. wizards/sbar_report.py +0 -324
  241. wizards/sbar_wizard.py +0 -608
  242. wizards/shift_handoff_wizard.py +0 -535
  243. wizards/soap_note_wizard.py +0 -679
  244. wizards/treatment_plan.py +0 -15
  245. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/WHEEL +0 -0
  246. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/entry_points.txt +0 -0
  247. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,446 +0,0 @@
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
-
250
- toml_loader = tomli
251
- except ImportError:
252
- # Fallback for Python 3.11+
253
- try:
254
- import tomllib
255
-
256
- toml_loader = tomllib
257
- except ImportError as e:
258
- raise ImportError("tomli or tomllib required for pyproject.toml") from e
259
-
260
- with open(path, "rb") as f:
261
- data = toml_loader.load(f)
262
-
263
- pylint_config = data.get("tool", {}).get("pylint", {})
264
-
265
- # Extract rules
266
- rules = {}
267
- if "enable" in pylint_config:
268
- for rule in pylint_config["enable"]:
269
- rules[rule] = "enabled"
270
- if "disable" in pylint_config:
271
- for rule in pylint_config["disable"]:
272
- rules[rule] = "disabled"
273
-
274
- # Get messages control
275
- messages_control = pylint_config.get("MESSAGES CONTROL", {})
276
- if "disable" in messages_control:
277
- for rule in messages_control["disable"].split(","):
278
- rules[rule.strip()] = "disabled"
279
-
280
- return LintConfig(
281
- linter=self.linter_name,
282
- config_file=str(path),
283
- rules=rules,
284
- extends=[],
285
- plugins=pylint_config.get("load-plugins", []),
286
- severity_overrides={},
287
- raw_config=pylint_config,
288
- )
289
-
290
- def _load_ini_style(self, path: Path) -> LintConfig:
291
- """Load from .pylintrc or setup.cfg"""
292
- import configparser
293
-
294
- config = configparser.ConfigParser()
295
- config.read(path)
296
-
297
- rules = {}
298
-
299
- # Check for disabled rules
300
- if config.has_option("MESSAGES CONTROL", "disable"):
301
- disabled = config.get("MESSAGES CONTROL", "disable")
302
- for rule in disabled.split(","):
303
- rules[rule.strip()] = "disabled"
304
-
305
- if config.has_option("MESSAGES CONTROL", "enable"):
306
- enabled = config.get("MESSAGES CONTROL", "enable")
307
- for rule in enabled.split(","):
308
- rules[rule.strip()] = "enabled"
309
-
310
- plugins = []
311
- if config.has_option("MASTER", "load-plugins"):
312
- plugins = config.get("MASTER", "load-plugins").split(",")
313
-
314
- return LintConfig(
315
- linter=self.linter_name,
316
- config_file=str(path),
317
- rules=rules,
318
- extends=[],
319
- plugins=[p.strip() for p in plugins],
320
- severity_overrides={},
321
- raw_config=dict(config.items()) if hasattr(config, "items") else {},
322
- )
323
-
324
-
325
- class TypeScriptConfigLoader(BaseConfigLoader):
326
- """Load TypeScript configuration.
327
-
328
- Supports tsconfig.json
329
- """
330
-
331
- def __init__(self):
332
- super().__init__("typescript")
333
-
334
- def find_config(self, start_dir: str) -> str | None:
335
- """Find tsconfig.json"""
336
- current = Path(start_dir).resolve()
337
-
338
- while True:
339
- tsconfig = current / "tsconfig.json"
340
- if tsconfig.exists():
341
- return str(tsconfig)
342
-
343
- if current.parent == current:
344
- break
345
-
346
- current = current.parent
347
-
348
- return None
349
-
350
- def load(self, config_path: str) -> LintConfig:
351
- """Load TypeScript configuration"""
352
- path = Path(config_path)
353
-
354
- if not path.exists():
355
- raise FileNotFoundError(f"Config file not found: {config_path}")
356
-
357
- with open(path) as f:
358
- # TypeScript allows comments in JSON
359
- content = f.read()
360
- # Remove comments (simplified)
361
- content = re.sub(r"//.*?\n", "\n", content)
362
- content = re.sub(r"/\*.*?\*/", "", content, flags=re.DOTALL)
363
-
364
- config_data = json.loads(content)
365
-
366
- compiler_options = config_data.get("compilerOptions", {})
367
-
368
- # Convert compiler options to "rules"
369
- rules = {}
370
- for option, value in compiler_options.items():
371
- rules[option] = value
372
-
373
- return LintConfig(
374
- linter=self.linter_name,
375
- config_file=str(path),
376
- rules=rules,
377
- extends=[config_data.get("extends", "")],
378
- plugins=[],
379
- severity_overrides={},
380
- raw_config=config_data,
381
- )
382
-
383
-
384
- class ConfigLoaderFactory:
385
- """Factory for creating config loaders"""
386
-
387
- _loaders = {
388
- "eslint": ESLintConfigLoader,
389
- "pylint": PylintConfigLoader,
390
- "typescript": TypeScriptConfigLoader,
391
- "tsc": TypeScriptConfigLoader,
392
- }
393
-
394
- @classmethod
395
- def create(cls, linter_name: str) -> BaseConfigLoader:
396
- """Create config loader for linter"""
397
- loader_class = cls._loaders.get(linter_name.lower())
398
-
399
- if not loader_class:
400
- raise ValueError(
401
- f"Unsupported linter config: {linter_name}. "
402
- f"Supported: {', '.join(cls._loaders.keys())}",
403
- )
404
-
405
- return loader_class()
406
-
407
- @classmethod
408
- def get_supported_linters(cls) -> list[str]:
409
- """Get supported linters"""
410
- return list(cls._loaders.keys())
411
-
412
-
413
- def load_config(
414
- linter_name: str,
415
- config_path: str | None = None,
416
- start_dir: str | None = None,
417
- ) -> LintConfig | None:
418
- """Load linting configuration.
419
-
420
- Args:
421
- linter_name: Name of linter
422
- config_path: Explicit config path (optional)
423
- start_dir: Directory to start search from (optional)
424
-
425
- Returns:
426
- LintConfig or None if not found
427
-
428
- Example:
429
- >>> config = load_config("eslint", start_dir="/path/to/project")
430
- >>> if config:
431
- ... print(f"Rules: {len(config.rules)}")
432
-
433
- """
434
- loader = ConfigLoaderFactory.create(linter_name)
435
-
436
- # If explicit path provided
437
- if config_path:
438
- return loader.load(config_path)
439
-
440
- # Otherwise, search for config
441
- if start_dir:
442
- found_config = loader.find_config(start_dir)
443
- if found_config:
444
- return loader.load(found_config)
445
-
446
- return None