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,470 +0,0 @@
1
- """Linter Output Parsers
2
-
3
- Parses output from various linters into standardized format.
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 enum import Enum
13
- from typing import Any
14
-
15
-
16
- class Severity(Enum):
17
- """Issue severity levels"""
18
-
19
- ERROR = "error"
20
- WARNING = "warning"
21
- INFO = "info"
22
- STYLE = "style"
23
-
24
-
25
- @dataclass
26
- class LintIssue:
27
- """Standardized lint issue across all linters.
28
-
29
- This is the universal format - all parser output converts to this.
30
- """
31
-
32
- file_path: str
33
- line: int
34
- column: int
35
- rule: str
36
- message: str
37
- severity: Severity
38
- linter: str
39
- has_autofix: bool = False
40
- fix_suggestion: str | None = None
41
- context: dict[str, Any] | None = None
42
-
43
- def to_dict(self) -> dict[str, Any]:
44
- """Convert to dictionary"""
45
- return {
46
- "file_path": self.file_path,
47
- "line": self.line,
48
- "column": self.column,
49
- "rule": self.rule,
50
- "message": self.message,
51
- "severity": self.severity.value,
52
- "linter": self.linter,
53
- "has_autofix": self.has_autofix,
54
- "fix_suggestion": self.fix_suggestion,
55
- "context": self.context or {},
56
- }
57
-
58
-
59
- class BaseLinterParser:
60
- """Base class for all linter parsers"""
61
-
62
- def __init__(self, linter_name: str):
63
- self.linter_name = linter_name
64
-
65
- def parse(self, output: str, format: str = "auto") -> list[LintIssue]:
66
- """Parse linter output into standardized issues.
67
-
68
- Args:
69
- output: Raw linter output (text or JSON)
70
- format: "json", "text", or "auto" (detect)
71
-
72
- Returns:
73
- List of LintIssue objects
74
-
75
- """
76
- raise NotImplementedError(
77
- f"{self.__class__.__name__}.parse() must be implemented. "
78
- "Create a subclass of BaseLinterParser and implement the parse() method. "
79
- f"See ESLintParser, PylintParser, or MyPyParser for examples."
80
- )
81
-
82
- def parse_file(self, file_path: str, format: str = "auto") -> list[LintIssue]:
83
- """Parse linter output from file"""
84
- with open(file_path) as f:
85
- return self.parse(f.read(), format)
86
-
87
-
88
- class ESLintParser(BaseLinterParser):
89
- """Parse ESLint output.
90
-
91
- Supports both JSON and text formats.
92
- """
93
-
94
- def __init__(self):
95
- super().__init__("eslint")
96
-
97
- def parse(self, output: str, format: str = "auto") -> list[LintIssue]:
98
- """Parse ESLint output"""
99
- # Auto-detect format
100
- if format == "auto":
101
- format = "json" if output.strip().startswith("[") else "text"
102
-
103
- if format == "json":
104
- return self._parse_json(output)
105
- return self._parse_text(output)
106
-
107
- def _parse_json(self, output: str) -> list[LintIssue]:
108
- """Parse ESLint JSON format"""
109
- issues = []
110
-
111
- try:
112
- data = json.loads(output)
113
-
114
- for file_result in data:
115
- file_path = file_result.get("filePath", "")
116
-
117
- for message in file_result.get("messages", []):
118
- issues.append(
119
- LintIssue(
120
- file_path=file_path,
121
- line=message.get("line", 0),
122
- column=message.get("column", 0),
123
- rule=message.get("ruleId", "unknown"),
124
- message=message.get("message", ""),
125
- severity=self._map_severity(message.get("severity", 1)),
126
- linter=self.linter_name,
127
- has_autofix=message.get("fix") is not None,
128
- fix_suggestion=str(message.get("fix")) if message.get("fix") else None,
129
- context={
130
- "node_type": message.get("nodeType"),
131
- "end_line": message.get("endLine"),
132
- "end_column": message.get("endColumn"),
133
- },
134
- ),
135
- )
136
-
137
- except json.JSONDecodeError:
138
- # Return empty list if JSON invalid
139
- pass
140
-
141
- return issues
142
-
143
- def _parse_text(self, output: str) -> list[LintIssue]:
144
- """Parse ESLint text format"""
145
- issues = []
146
-
147
- # Pattern: /path/to/file.js
148
- # 1:5 error 'foo' is not defined no-undef
149
- pattern = r"^\s*(\d+):(\d+)\s+(error|warning)\s+(.+?)\s+([a-z-]+)$"
150
-
151
- current_file = None
152
-
153
- for line in output.split("\n"):
154
- # Check if this is a file path line
155
- if line and not line.startswith(" "):
156
- current_file = line.strip()
157
- continue
158
-
159
- # Try to match issue line
160
- match = re.match(pattern, line)
161
- if match and current_file:
162
- line_num, col_num, severity, message, rule = match.groups()
163
-
164
- issues.append(
165
- LintIssue(
166
- file_path=current_file,
167
- line=int(line_num),
168
- column=int(col_num),
169
- rule=rule,
170
- message=message,
171
- severity=Severity.ERROR if severity == "error" else Severity.WARNING,
172
- linter=self.linter_name,
173
- has_autofix=False, # Can't tell from text format
174
- ),
175
- )
176
-
177
- return issues
178
-
179
- def _map_severity(self, eslint_severity: int) -> Severity:
180
- """Map ESLint severity (1=warning, 2=error) to our enum"""
181
- return Severity.ERROR if eslint_severity == 2 else Severity.WARNING
182
-
183
-
184
- class PylintParser(BaseLinterParser):
185
- """Parse Pylint output.
186
-
187
- Supports JSON and text formats.
188
- """
189
-
190
- def __init__(self):
191
- super().__init__("pylint")
192
-
193
- def parse(self, output: str, format: str = "auto") -> list[LintIssue]:
194
- """Parse Pylint output"""
195
- # Auto-detect format
196
- if format == "auto":
197
- format = "json" if output.strip().startswith("[") else "text"
198
-
199
- if format == "json":
200
- return self._parse_json(output)
201
- return self._parse_text(output)
202
-
203
- def _parse_json(self, output: str) -> list[LintIssue]:
204
- """Parse Pylint JSON format"""
205
- issues = []
206
-
207
- try:
208
- data = json.loads(output)
209
-
210
- for item in data:
211
- issues.append(
212
- LintIssue(
213
- file_path=item.get("path", ""),
214
- line=item.get("line", 0),
215
- column=item.get("column", 0),
216
- rule=item.get("symbol", item.get("message-id", "unknown")),
217
- message=item.get("message", ""),
218
- severity=self._map_severity(item.get("type", "convention")),
219
- linter=self.linter_name,
220
- has_autofix=False, # Pylint doesn't provide autofixes
221
- context={
222
- "symbol": item.get("symbol"),
223
- "module": item.get("module"),
224
- "obj": item.get("obj"),
225
- },
226
- ),
227
- )
228
-
229
- except json.JSONDecodeError:
230
- pass
231
-
232
- return issues
233
-
234
- def _parse_text(self, output: str) -> list[LintIssue]:
235
- """Parse Pylint text format"""
236
- issues = []
237
-
238
- # Pattern: path/to/file.py:42:8: C0103: Variable name "X" doesn't conform (invalid-name)
239
- pattern = r"^(.+?):(\d+):(\d+):\s*([A-Z]\d+):\s*(.+?)\s*\(([a-z-]+)\)$"
240
-
241
- for line in output.split("\n"):
242
- match = re.match(pattern, line.strip())
243
- if match:
244
- file_path, line_num, col_num, code, message, symbol = match.groups()
245
-
246
- issues.append(
247
- LintIssue(
248
- file_path=file_path,
249
- line=int(line_num),
250
- column=int(col_num),
251
- rule=symbol,
252
- message=message,
253
- severity=self._map_severity(code[0]),
254
- linter=self.linter_name,
255
- has_autofix=False,
256
- context={"code": code, "symbol": symbol},
257
- ),
258
- )
259
-
260
- return issues
261
-
262
- def _map_severity(self, type_or_code: str) -> Severity:
263
- """Map Pylint type/code to severity"""
264
- if isinstance(type_or_code, str):
265
- first_char = type_or_code[0].upper() if type_or_code else "C"
266
-
267
- mapping = {
268
- "E": Severity.ERROR, # Error
269
- "F": Severity.ERROR, # Fatal
270
- "W": Severity.WARNING, # Warning
271
- "R": Severity.INFO, # Refactor
272
- "C": Severity.STYLE, # Convention
273
- "I": Severity.INFO, # Informational
274
- }
275
-
276
- return mapping.get(first_char, Severity.INFO)
277
-
278
- return Severity.INFO
279
-
280
-
281
- class MyPyParser(BaseLinterParser):
282
- """Parse mypy (Python type checker) output."""
283
-
284
- def __init__(self):
285
- super().__init__("mypy")
286
-
287
- def parse(self, output: str, format: str = "auto") -> list[LintIssue]:
288
- """Parse mypy output (text only)"""
289
- issues = []
290
-
291
- # Pattern: path/to/file.py:42: error: Incompatible types [assignment]
292
- pattern = r"^(.+?):(\d+):\s*(error|warning|note):\s*(.+?)(?:\s*\[([a-z-]+)\])?$"
293
-
294
- for line in output.split("\n"):
295
- match = re.match(pattern, line.strip())
296
- if match:
297
- file_path, line_num, severity, message, code = match.groups()
298
-
299
- issues.append(
300
- LintIssue(
301
- file_path=file_path,
302
- line=int(line_num),
303
- column=0, # mypy doesn't always provide column
304
- rule=code or "type-error",
305
- message=message,
306
- severity=Severity.ERROR if severity == "error" else Severity.WARNING,
307
- linter=self.linter_name,
308
- has_autofix=False,
309
- context={"severity_text": severity},
310
- ),
311
- )
312
-
313
- return issues
314
-
315
-
316
- class TypeScriptParser(BaseLinterParser):
317
- """Parse TypeScript compiler (tsc) output."""
318
-
319
- def __init__(self):
320
- super().__init__("typescript")
321
-
322
- def parse(self, output: str, format: str = "auto") -> list[LintIssue]:
323
- """Parse tsc output"""
324
- issues = []
325
-
326
- # Pattern: src/file.ts(42,8): error TS2322: Type 'string' is not assignable to type 'number'.
327
- pattern = r"^(.+?)\((\d+),(\d+)\):\s*(error|warning)\s*TS(\d+):\s*(.+)$"
328
-
329
- for line in output.split("\n"):
330
- match = re.match(pattern, line.strip())
331
- if match:
332
- file_path, line_num, col_num, severity, code, message = match.groups()
333
-
334
- issues.append(
335
- LintIssue(
336
- file_path=file_path,
337
- line=int(line_num),
338
- column=int(col_num),
339
- rule=f"TS{code}",
340
- message=message,
341
- severity=Severity.ERROR if severity == "error" else Severity.WARNING,
342
- linter=self.linter_name,
343
- has_autofix=False,
344
- context={"ts_code": code},
345
- ),
346
- )
347
-
348
- return issues
349
-
350
-
351
- class ClippyParser(BaseLinterParser):
352
- """Parse Rust Clippy output."""
353
-
354
- def __init__(self):
355
- super().__init__("clippy")
356
-
357
- def parse(self, output: str, format: str = "auto") -> list[LintIssue]:
358
- """Parse clippy output"""
359
- issues = []
360
-
361
- # Pattern: warning: unused variable: `x`
362
- # --> src/main.rs:5:9
363
- current_issue: dict[str, Any] = {}
364
-
365
- for line in output.split("\n"):
366
- # Check for severity line
367
- severity_match = re.match(r"^(error|warning):\s*(.+)$", line.strip())
368
- if severity_match:
369
- if current_issue:
370
- issues.append(self._create_issue(current_issue))
371
-
372
- current_issue = {
373
- "severity": severity_match.group(1),
374
- "message": severity_match.group(2),
375
- }
376
- continue
377
-
378
- # Check for location line
379
- loc_match = re.match(r"^\s*-->\s*(.+?):(\d+):(\d+)$", line.strip())
380
- if loc_match and current_issue:
381
- current_issue["file_path"] = loc_match.group(1)
382
- current_issue["line"] = int(loc_match.group(2))
383
- current_issue["column"] = int(loc_match.group(3))
384
-
385
- # Check for lint name
386
- lint_match = re.match(r"^\s*=\s*note:\s*#\[.*?\(([a-z_]+)\)\]", line.strip())
387
- if lint_match and current_issue:
388
- current_issue["rule"] = lint_match.group(1)
389
-
390
- # Add last issue
391
- if current_issue:
392
- issues.append(self._create_issue(current_issue))
393
-
394
- return issues
395
-
396
- def _create_issue(self, issue_dict: dict) -> LintIssue:
397
- """Create LintIssue from dict"""
398
- return LintIssue(
399
- file_path=issue_dict.get("file_path", ""),
400
- line=issue_dict.get("line", 0),
401
- column=issue_dict.get("column", 0),
402
- rule=issue_dict.get("rule", "clippy"),
403
- message=issue_dict.get("message", ""),
404
- severity=Severity.ERROR if issue_dict.get("severity") == "error" else Severity.WARNING,
405
- linter=self.linter_name,
406
- has_autofix=False,
407
- )
408
-
409
-
410
- class LinterParserFactory:
411
- """Factory for creating appropriate parser based on linter type."""
412
-
413
- _parsers = {
414
- "eslint": ESLintParser,
415
- "pylint": PylintParser,
416
- "mypy": MyPyParser,
417
- "typescript": TypeScriptParser,
418
- "tsc": TypeScriptParser,
419
- "clippy": ClippyParser,
420
- "rustc": ClippyParser,
421
- }
422
-
423
- @classmethod
424
- def create(cls, linter_name: str) -> BaseLinterParser:
425
- """Create parser for specified linter.
426
-
427
- Args:
428
- linter_name: Name of linter (eslint, pylint, mypy, etc.)
429
-
430
- Returns:
431
- Appropriate parser instance
432
-
433
- Raises:
434
- ValueError if linter not supported
435
-
436
- """
437
- parser_class = cls._parsers.get(linter_name.lower())
438
-
439
- if not parser_class:
440
- raise ValueError(
441
- f"Unsupported linter: {linter_name}. Supported: {', '.join(cls._parsers.keys())}",
442
- )
443
-
444
- return parser_class()
445
-
446
- @classmethod
447
- def get_supported_linters(cls) -> list[str]:
448
- """Get list of supported linters"""
449
- return list(cls._parsers.keys())
450
-
451
-
452
- def parse_linter_output(linter_name: str, output: str, format: str = "auto") -> list[LintIssue]:
453
- """Convenience function to parse linter output.
454
-
455
- Args:
456
- linter_name: Name of linter
457
- output: Raw linter output
458
- format: "json", "text", or "auto"
459
-
460
- Returns:
461
- List of standardized LintIssue objects
462
-
463
- Example:
464
- >>> issues = parse_linter_output("eslint", eslint_json_output)
465
- >>> for issue in issues:
466
- ... print(f"{issue.file_path}:{issue.line} - {issue.message}")
467
-
468
- """
469
- parser = LinterParserFactory.create(linter_name)
470
- return parser.parse(output, format)