empathy-framework 4.6.6__py3-none-any.whl → 4.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 (273) hide show
  1. empathy_framework-4.7.1.dist-info/METADATA +690 -0
  2. empathy_framework-4.7.1.dist-info/RECORD +379 -0
  3. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/top_level.txt +1 -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 2.py +173 -0
  130. empathy_os/vscode_bridge.py +173 -0
  131. empathy_os/workflows/__init__.py +212 -120
  132. empathy_os/workflows/batch_processing.py +8 -24
  133. empathy_os/workflows/bug_predict.py +1 -1
  134. empathy_os/workflows/code_review.py +20 -5
  135. empathy_os/workflows/code_review_pipeline.py +13 -8
  136. empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
  137. empathy_os/workflows/manage_documentation.py +1 -0
  138. empathy_os/workflows/orchestrated_health_check.py +6 -11
  139. empathy_os/workflows/orchestrated_release_prep.py +3 -3
  140. empathy_os/workflows/pr_review.py +18 -10
  141. empathy_os/workflows/progressive/README 2.md +454 -0
  142. empathy_os/workflows/progressive/__init__ 2.py +92 -0
  143. empathy_os/workflows/progressive/__init__.py +2 -12
  144. empathy_os/workflows/progressive/cli 2.py +242 -0
  145. empathy_os/workflows/progressive/cli.py +14 -37
  146. empathy_os/workflows/progressive/core 2.py +488 -0
  147. empathy_os/workflows/progressive/core.py +12 -12
  148. empathy_os/workflows/progressive/orchestrator 2.py +701 -0
  149. empathy_os/workflows/progressive/orchestrator.py +166 -144
  150. empathy_os/workflows/progressive/reports 2.py +528 -0
  151. empathy_os/workflows/progressive/reports.py +22 -31
  152. empathy_os/workflows/progressive/telemetry 2.py +280 -0
  153. empathy_os/workflows/progressive/telemetry.py +8 -14
  154. empathy_os/workflows/progressive/test_gen 2.py +514 -0
  155. empathy_os/workflows/progressive/test_gen.py +29 -48
  156. empathy_os/workflows/progressive/workflow 2.py +628 -0
  157. empathy_os/workflows/progressive/workflow.py +31 -70
  158. empathy_os/workflows/release_prep.py +21 -6
  159. empathy_os/workflows/release_prep_crew.py +1 -0
  160. empathy_os/workflows/secure_release.py +13 -6
  161. empathy_os/workflows/security_audit.py +8 -3
  162. empathy_os/workflows/test_coverage_boost_crew.py +3 -2
  163. empathy_os/workflows/test_maintenance_crew.py +1 -0
  164. empathy_os/workflows/test_runner.py +16 -12
  165. empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
  166. empathy_software_plugin/cli.py +0 -122
  167. patterns/README.md +119 -0
  168. patterns/__init__.py +95 -0
  169. patterns/behavior.py +298 -0
  170. patterns/code_review_memory.json +441 -0
  171. patterns/core.py +97 -0
  172. patterns/debugging.json +3763 -0
  173. patterns/empathy.py +268 -0
  174. patterns/health_check_memory.json +505 -0
  175. patterns/input.py +161 -0
  176. patterns/memory_graph.json +8 -0
  177. patterns/refactoring_memory.json +1113 -0
  178. patterns/registry.py +663 -0
  179. patterns/security_memory.json +8 -0
  180. patterns/structural.py +415 -0
  181. patterns/validation.py +194 -0
  182. coach_wizards/__init__.py +0 -45
  183. coach_wizards/accessibility_wizard.py +0 -91
  184. coach_wizards/api_wizard.py +0 -91
  185. coach_wizards/base_wizard.py +0 -209
  186. coach_wizards/cicd_wizard.py +0 -91
  187. coach_wizards/code_reviewer_README.md +0 -60
  188. coach_wizards/code_reviewer_wizard.py +0 -180
  189. coach_wizards/compliance_wizard.py +0 -91
  190. coach_wizards/database_wizard.py +0 -91
  191. coach_wizards/debugging_wizard.py +0 -91
  192. coach_wizards/documentation_wizard.py +0 -91
  193. coach_wizards/generate_wizards.py +0 -347
  194. coach_wizards/localization_wizard.py +0 -173
  195. coach_wizards/migration_wizard.py +0 -91
  196. coach_wizards/monitoring_wizard.py +0 -91
  197. coach_wizards/observability_wizard.py +0 -91
  198. coach_wizards/performance_wizard.py +0 -91
  199. coach_wizards/prompt_engineering_wizard.py +0 -661
  200. coach_wizards/refactoring_wizard.py +0 -91
  201. coach_wizards/scaling_wizard.py +0 -90
  202. coach_wizards/security_wizard.py +0 -92
  203. coach_wizards/testing_wizard.py +0 -91
  204. empathy_framework-4.6.6.dist-info/METADATA +0 -1597
  205. empathy_framework-4.6.6.dist-info/RECORD +0 -410
  206. empathy_llm_toolkit/wizards/__init__.py +0 -43
  207. empathy_llm_toolkit/wizards/base_wizard.py +0 -364
  208. empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
  209. empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
  210. empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
  211. empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
  212. empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
  213. empathy_os/wizard_factory_cli.py +0 -170
  214. empathy_software_plugin/wizards/__init__.py +0 -42
  215. empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
  216. empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
  217. empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
  218. empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
  219. empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
  220. empathy_software_plugin/wizards/base_wizard.py +0 -288
  221. empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
  222. empathy_software_plugin/wizards/code_review_wizard.py +0 -604
  223. empathy_software_plugin/wizards/debugging/__init__.py +0 -50
  224. empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
  225. empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
  226. empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
  227. empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
  228. empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
  229. empathy_software_plugin/wizards/debugging/verification.py +0 -369
  230. empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
  231. empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
  232. empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
  233. empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
  234. empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
  235. empathy_software_plugin/wizards/performance/__init__.py +0 -9
  236. empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
  237. empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
  238. empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
  239. empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
  240. empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
  241. empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
  242. empathy_software_plugin/wizards/security/__init__.py +0 -32
  243. empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
  244. empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
  245. empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
  246. empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
  247. empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
  248. empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
  249. empathy_software_plugin/wizards/testing/__init__.py +0 -27
  250. empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
  251. empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
  252. empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
  253. empathy_software_plugin/wizards/testing_wizard.py +0 -274
  254. wizards/__init__.py +0 -82
  255. wizards/admission_assessment_wizard.py +0 -644
  256. wizards/care_plan.py +0 -321
  257. wizards/clinical_assessment.py +0 -769
  258. wizards/discharge_planning.py +0 -77
  259. wizards/discharge_summary_wizard.py +0 -468
  260. wizards/dosage_calculation.py +0 -497
  261. wizards/incident_report_wizard.py +0 -454
  262. wizards/medication_reconciliation.py +0 -85
  263. wizards/nursing_assessment.py +0 -171
  264. wizards/patient_education.py +0 -654
  265. wizards/quality_improvement.py +0 -705
  266. wizards/sbar_report.py +0 -324
  267. wizards/sbar_wizard.py +0 -608
  268. wizards/shift_handoff_wizard.py +0 -535
  269. wizards/soap_note_wizard.py +0 -679
  270. wizards/treatment_plan.py +0 -15
  271. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/WHEEL +0 -0
  272. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/entry_points.txt +0 -0
  273. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,369 +0,0 @@
1
- """Verification Module
2
-
3
- Re-runs linters to verify fixes were successful.
4
-
5
- Copyright 2025 Smart AI Memory, LLC
6
- Licensed under Fair Source 0.9
7
- """
8
-
9
- import logging
10
- import subprocess
11
- from dataclasses import dataclass
12
- from pathlib import Path
13
- from typing import Any
14
-
15
- from .linter_parsers import LintIssue, parse_linter_output
16
-
17
- logger = logging.getLogger(__name__)
18
-
19
-
20
- def _validate_target_path(target: str) -> bool:
21
- """Validate target path is safe for linter subprocess execution.
22
-
23
- SECURITY: Prevents command injection via malicious file/directory paths.
24
- Checks that path exists and doesn't contain shell metacharacters.
25
- """
26
- if not target:
27
- return False
28
- try:
29
- p = Path(target).resolve()
30
- # Must exist as file or directory
31
- if not p.exists():
32
- return False
33
- # Must not contain shell metacharacters
34
- shell_chars = set(";|&$`(){}[]<>\\'\"\n\r\t")
35
- if any(c in str(p) for c in shell_chars):
36
- return False
37
- return True
38
- except Exception as e:
39
- # Security: Reject any path that fails validation (malformed, permission denied, etc.)
40
- logger.debug(f"Path validation failed for {target}: {e}")
41
- return False
42
-
43
-
44
- @dataclass
45
- class VerificationResult:
46
- """Result of verification check"""
47
-
48
- linter: str
49
- success: bool
50
- issues_before: int
51
- issues_after: int
52
- issues_fixed: int
53
- issues_remaining: int
54
- new_issues: int
55
- remaining_issues: list[LintIssue]
56
- error: str | None = None
57
-
58
- def to_dict(self) -> dict[str, Any]:
59
- """Convert to dictionary"""
60
- return {
61
- "linter": self.linter,
62
- "success": self.success,
63
- "issues_before": self.issues_before,
64
- "issues_after": self.issues_after,
65
- "issues_fixed": self.issues_fixed,
66
- "issues_remaining": self.issues_remaining,
67
- "new_issues": self.new_issues,
68
- "remaining_issues": [i.to_dict() for i in self.remaining_issues],
69
- "error": self.error,
70
- }
71
-
72
-
73
- class BaseLinterRunner:
74
- """Base class for running linters"""
75
-
76
- def __init__(self, linter_name: str):
77
- self.linter_name = linter_name
78
-
79
- def run(self, target: str, output_format: str = "json") -> list[LintIssue]:
80
- """Run linter on target.
81
-
82
- Args:
83
- target: File or directory to lint
84
- output_format: Output format ("json" or "text")
85
-
86
- Returns:
87
- List of LintIssue objects
88
-
89
- """
90
- raise NotImplementedError
91
-
92
-
93
- class ESLintRunner(BaseLinterRunner):
94
- """Run ESLint"""
95
-
96
- def __init__(self):
97
- super().__init__("eslint")
98
-
99
- def run(self, target: str, output_format: str = "json") -> list[LintIssue]:
100
- """Run ESLint"""
101
- # SECURITY: Validate target path before subprocess execution
102
- if not _validate_target_path(target):
103
- raise ValueError(f"Invalid or unsafe target path: {target}")
104
-
105
- cmd = ["npx", "eslint"]
106
-
107
- if output_format == "json":
108
- cmd.append("--format=json")
109
-
110
- cmd.append(target)
111
-
112
- try:
113
- result = subprocess.run(cmd, check=False, capture_output=True, text=True, timeout=60)
114
-
115
- # ESLint exits with 1 if there are violations (expected)
116
- output = result.stdout
117
-
118
- if output_format == "json":
119
- return parse_linter_output(self.linter_name, output, "json")
120
- return parse_linter_output(self.linter_name, output, "text")
121
-
122
- except subprocess.TimeoutExpired:
123
- return []
124
- except FileNotFoundError as e:
125
- raise RuntimeError("ESLint not found. Run: npm install eslint") from e
126
-
127
-
128
- class PylintRunner(BaseLinterRunner):
129
- """Run Pylint"""
130
-
131
- def __init__(self):
132
- super().__init__("pylint")
133
-
134
- def run(self, target: str, output_format: str = "json") -> list[LintIssue]:
135
- """Run Pylint"""
136
- # SECURITY: Validate target path before subprocess execution
137
- if not _validate_target_path(target):
138
- raise ValueError(f"Invalid or unsafe target path: {target}")
139
-
140
- cmd = ["pylint"]
141
-
142
- if output_format == "json":
143
- cmd.append("--output-format=json")
144
-
145
- cmd.append(target)
146
-
147
- try:
148
- result = subprocess.run(cmd, check=False, capture_output=True, text=True, timeout=60)
149
-
150
- # Pylint exits with non-zero if violations (expected)
151
- output = result.stdout
152
-
153
- if output_format == "json":
154
- return parse_linter_output(self.linter_name, output, "json")
155
- return parse_linter_output(self.linter_name, output, "text")
156
-
157
- except subprocess.TimeoutExpired:
158
- return []
159
- except FileNotFoundError as e:
160
- raise RuntimeError("Pylint not found. Run: pip install pylint") from e
161
-
162
-
163
- class MyPyRunner(BaseLinterRunner):
164
- """Run mypy"""
165
-
166
- def __init__(self):
167
- super().__init__("mypy")
168
-
169
- def run(self, target: str, output_format: str = "json") -> list[LintIssue]:
170
- """Run mypy"""
171
- # SECURITY: Validate target path before subprocess execution
172
- if not _validate_target_path(target):
173
- raise ValueError(f"Invalid or unsafe target path: {target}")
174
-
175
- cmd = ["mypy", target]
176
-
177
- try:
178
- result = subprocess.run(cmd, check=False, capture_output=True, text=True, timeout=60)
179
-
180
- output = result.stdout
181
-
182
- return parse_linter_output(self.linter_name, output, "text")
183
-
184
- except subprocess.TimeoutExpired:
185
- return []
186
- except FileNotFoundError as e:
187
- raise RuntimeError("mypy not found. Run: pip install mypy") from e
188
-
189
-
190
- class TypeScriptRunner(BaseLinterRunner):
191
- """Run TypeScript compiler"""
192
-
193
- def __init__(self):
194
- super().__init__("typescript")
195
-
196
- def run(self, target: str, output_format: str = "json") -> list[LintIssue]:
197
- """Run tsc"""
198
- cmd = ["npx", "tsc", "--noEmit"]
199
-
200
- # If target is a directory, use project mode
201
- if Path(target).is_dir():
202
- cmd.extend(["--project", target])
203
- else:
204
- cmd.append(target)
205
-
206
- try:
207
- result = subprocess.run(cmd, check=False, capture_output=True, text=True, timeout=60)
208
-
209
- output = result.stdout
210
-
211
- return parse_linter_output(self.linter_name, output, "text")
212
-
213
- except subprocess.TimeoutExpired:
214
- return []
215
- except FileNotFoundError as e:
216
- raise RuntimeError("TypeScript not found. Run: npm install typescript") from e
217
-
218
-
219
- class LinterRunnerFactory:
220
- """Factory for creating linter runners"""
221
-
222
- _runners = {
223
- "eslint": ESLintRunner,
224
- "pylint": PylintRunner,
225
- "mypy": MyPyRunner,
226
- "typescript": TypeScriptRunner,
227
- "tsc": TypeScriptRunner,
228
- }
229
-
230
- @classmethod
231
- def create(cls, linter_name: str) -> BaseLinterRunner:
232
- """Create linter runner"""
233
- runner_class = cls._runners.get(linter_name.lower())
234
-
235
- if not runner_class:
236
- raise ValueError(
237
- f"Unsupported linter runner: {linter_name}. "
238
- f"Supported: {', '.join(cls._runners.keys())}",
239
- )
240
-
241
- return runner_class()
242
-
243
-
244
- def run_linter(linter_name: str, target: str, output_format: str = "json") -> list[LintIssue]:
245
- """Run linter on target.
246
-
247
- Args:
248
- linter_name: Name of linter
249
- target: File or directory to lint
250
- output_format: "json" or "text"
251
-
252
- Returns:
253
- List of LintIssue objects
254
-
255
- Example:
256
- >>> issues = run_linter("eslint", "/path/to/project")
257
- >>> print(f"Found {len(issues)} issues")
258
-
259
- """
260
- runner = LinterRunnerFactory.create(linter_name)
261
- return runner.run(target, output_format)
262
-
263
-
264
- def verify_fixes(
265
- linter_name: str,
266
- target: str,
267
- issues_before: list[LintIssue],
268
- ) -> VerificationResult:
269
- """Verify that fixes were successful by re-running linter.
270
-
271
- Args:
272
- linter_name: Name of linter
273
- target: File or directory that was fixed
274
- issues_before: Issues that existed before fixes
275
-
276
- Returns:
277
- VerificationResult with comparison
278
-
279
- Example:
280
- >>> result = verify_fixes("eslint", "/path/to/project", original_issues)
281
- >>> if result.success:
282
- ... print(f"Fixed {result.issues_fixed} issues!")
283
-
284
- """
285
- try:
286
- # Re-run linter
287
- issues_after = run_linter(linter_name, target)
288
-
289
- # Compare
290
- issues_before_count = len(issues_before)
291
- issues_after_count = len(issues_after)
292
-
293
- issues_fixed = max(0, issues_before_count - issues_after_count)
294
- issues_remaining = issues_after_count
295
-
296
- # Check for new issues (regressions)
297
- before_keys = {(i.file_path, i.line, i.rule) for i in issues_before}
298
- after_keys = {(i.file_path, i.line, i.rule) for i in issues_after}
299
-
300
- new_issue_keys = after_keys - before_keys
301
- new_issues = len(new_issue_keys)
302
-
303
- return VerificationResult(
304
- linter=linter_name,
305
- success=(issues_after_count < issues_before_count and new_issues == 0),
306
- issues_before=issues_before_count,
307
- issues_after=issues_after_count,
308
- issues_fixed=issues_fixed,
309
- issues_remaining=issues_remaining,
310
- new_issues=new_issues,
311
- remaining_issues=issues_after,
312
- )
313
-
314
- except Exception as e:
315
- return VerificationResult(
316
- linter=linter_name,
317
- success=False,
318
- issues_before=len(issues_before),
319
- issues_after=0,
320
- issues_fixed=0,
321
- issues_remaining=0,
322
- new_issues=0,
323
- remaining_issues=[],
324
- error=str(e),
325
- )
326
-
327
-
328
- def compare_issue_lists(before: list[LintIssue], after: list[LintIssue]) -> dict[str, Any]:
329
- """Detailed comparison of issue lists.
330
-
331
- Args:
332
- before: Issues before fixes
333
- after: Issues after fixes
334
-
335
- Returns:
336
- Dictionary with detailed comparison
337
-
338
- """
339
- before_set = {(i.file_path, i.line, i.column, i.rule) for i in before}
340
- after_set = {(i.file_path, i.line, i.column, i.rule) for i in after}
341
-
342
- fixed = before_set - after_set
343
- remaining = before_set & after_set
344
- new = after_set - before_set
345
-
346
- # Group by file
347
- files_improved = set()
348
- files_regressed = set()
349
-
350
- for issue in before:
351
- key = (issue.file_path, issue.line, issue.column, issue.rule)
352
- if key in fixed:
353
- files_improved.add(issue.file_path)
354
-
355
- for issue in after:
356
- key = (issue.file_path, issue.line, issue.column, issue.rule)
357
- if key in new:
358
- files_regressed.add(issue.file_path)
359
-
360
- return {
361
- "total_before": len(before),
362
- "total_after": len(after),
363
- "fixed_count": len(fixed),
364
- "remaining_count": len(remaining),
365
- "new_count": len(new),
366
- "files_improved": list(files_improved),
367
- "files_regressed": list(files_regressed),
368
- "net_improvement": len(fixed) - len(new),
369
- }