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,469 +0,0 @@
1
- """Fix Applier
2
-
3
- Systematically applies fixes to code based on linter violations.
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
16
-
17
- logger = logging.getLogger(__name__)
18
-
19
-
20
- def _validate_file_path(file_path: str) -> bool:
21
- """Validate file path is safe for subprocess execution.
22
-
23
- SECURITY: Prevents command injection via malicious file paths.
24
- Checks that path exists, is a file, and doesn't contain shell metacharacters.
25
- """
26
- if not file_path:
27
- return False
28
- try:
29
- p = Path(file_path).resolve()
30
- # Must exist and be a file
31
- if not p.exists() or not p.is_file():
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 {file_path}: {e}")
41
- return False
42
-
43
-
44
- @dataclass
45
- class FixResult:
46
- """Result of attempting to fix an issue"""
47
-
48
- issue: LintIssue
49
- success: bool
50
- method: str # "autofix", "manual_suggestion", "skipped"
51
- changes_made: str | None = None
52
- error: str | None = None
53
-
54
- def to_dict(self) -> dict[str, Any]:
55
- """Convert to dictionary"""
56
- return {
57
- "issue": self.issue.to_dict(),
58
- "success": self.success,
59
- "method": self.method,
60
- "changes_made": self.changes_made,
61
- "error": self.error,
62
- }
63
-
64
-
65
- class BaseFixApplier:
66
- """Base class for fix appliers"""
67
-
68
- def __init__(self, linter_name: str):
69
- self.linter_name = linter_name
70
-
71
- def can_autofix(self, issue: LintIssue) -> bool:
72
- """Check if issue can be auto-fixed"""
73
- raise NotImplementedError(
74
- f"{self.__class__.__name__}.can_autofix() must be implemented. "
75
- "Create a subclass of BaseFixApplier and implement the can_autofix() method. "
76
- f"See ESLintFixApplier, PylintFixApplier, or TypeScriptFixApplier for examples."
77
- )
78
-
79
- def apply_fix(self, issue: LintIssue, dry_run: bool = False) -> FixResult:
80
- """Apply fix for issue.
81
-
82
- Args:
83
- issue: LintIssue to fix
84
- dry_run: If True, don't actually make changes
85
-
86
- Returns:
87
- FixResult with outcome
88
-
89
- """
90
- raise NotImplementedError(
91
- f"{self.__class__.__name__}.apply_fix() must be implemented. "
92
- "Create a subclass of BaseFixApplier and implement the apply_fix() method. "
93
- f"See ESLintFixApplier, PylintFixApplier, or TypeScriptFixApplier for examples."
94
- )
95
-
96
- def apply_fixes_batch(self, issues: list[LintIssue], dry_run: bool = False) -> list[FixResult]:
97
- """Apply fixes for multiple issues"""
98
- results = []
99
- for issue in issues:
100
- result = self.apply_fix(issue, dry_run)
101
- results.append(result)
102
- return results
103
-
104
- def suggest_manual_fix(self, issue: LintIssue) -> str:
105
- """Provide suggestion for manual fix"""
106
- raise NotImplementedError(
107
- f"{self.__class__.__name__}.suggest_manual_fix() must be implemented. "
108
- "Create a subclass of BaseFixApplier and implement the suggest_manual_fix() method. "
109
- f"See ESLintFixApplier, PylintFixApplier, or TypeScriptFixApplier for examples."
110
- )
111
-
112
-
113
- class ESLintFixApplier(BaseFixApplier):
114
- """Apply ESLint fixes.
115
-
116
- Uses --fix flag for auto-fixable issues.
117
- """
118
-
119
- def __init__(self):
120
- super().__init__("eslint")
121
- self.autofixable_rules = self._get_autofixable_rules()
122
-
123
- def _get_autofixable_rules(self) -> set:
124
- """Get set of auto-fixable ESLint rules.
125
-
126
- In practice, we'd query ESLint, but for now use common ones.
127
- """
128
- return {
129
- "semi",
130
- "quotes",
131
- "comma-dangle",
132
- "no-extra-semi",
133
- "no-multi-spaces",
134
- "space-before-blocks",
135
- "keyword-spacing",
136
- "object-curly-spacing",
137
- "array-bracket-spacing",
138
- "eol-last",
139
- "no-trailing-spaces",
140
- "indent",
141
- "arrow-spacing",
142
- "prefer-const",
143
- "no-var",
144
- }
145
-
146
- def can_autofix(self, issue: LintIssue) -> bool:
147
- """Check if ESLint can auto-fix this rule"""
148
- return issue.rule in self.autofixable_rules or issue.has_autofix
149
-
150
- def apply_fix(self, issue: LintIssue, dry_run: bool = False) -> FixResult:
151
- """Apply ESLint fix"""
152
- if not self.can_autofix(issue):
153
- # Provide manual suggestion
154
- _suggestion = self.suggest_manual_fix(issue)
155
- return FixResult(
156
- issue=issue,
157
- success=False,
158
- method="manual_suggestion",
159
- changes_made=None,
160
- error=None,
161
- )
162
-
163
- if dry_run:
164
- return FixResult(
165
- issue=issue,
166
- success=True,
167
- method="autofix",
168
- changes_made="Would fix with ESLint --fix",
169
- )
170
-
171
- # Run ESLint --fix on specific file
172
- # SECURITY: Validate file path before subprocess execution
173
- if not _validate_file_path(issue.file_path):
174
- return FixResult(
175
- issue=issue,
176
- success=False,
177
- method="autofix",
178
- error=f"Invalid or unsafe file path: {issue.file_path}",
179
- )
180
-
181
- try:
182
- result = subprocess.run(
183
- ["npx", "eslint", "--fix", issue.file_path],
184
- check=False,
185
- capture_output=True,
186
- text=True,
187
- timeout=30,
188
- )
189
-
190
- return FixResult(
191
- issue=issue,
192
- success=result.returncode == 0,
193
- method="autofix",
194
- changes_made=f"ESLint --fix applied to {issue.file_path}",
195
- )
196
-
197
- except subprocess.TimeoutExpired:
198
- return FixResult(issue=issue, success=False, method="autofix", error="ESLint timeout")
199
- except FileNotFoundError:
200
- return FixResult(
201
- issue=issue,
202
- success=False,
203
- method="autofix",
204
- error="ESLint not found (run npm install)",
205
- )
206
-
207
- def suggest_manual_fix(self, issue: LintIssue) -> str:
208
- """Suggest manual fix for ESLint issue"""
209
- # Extract variable name from message if present
210
- var_name = "variable"
211
- if "'" in issue.message:
212
- parts = issue.message.split("'")
213
- if len(parts) > 1:
214
- var_name = parts[1]
215
-
216
- suggestions = {
217
- "no-undef": f"Define '{var_name}' or import it",
218
- "no-unused-vars": "Remove unused variable or prefix with _",
219
- "eqeqeq": "Use === instead of ==",
220
- "no-console": "Remove console.log or use a logger",
221
- "prefer-const": "Change 'let' to 'const' if variable never reassigned",
222
- }
223
-
224
- return suggestions.get(issue.rule, f"Manual fix required for {issue.rule}: {issue.message}")
225
-
226
-
227
- class PylintFixApplier(BaseFixApplier):
228
- """Apply Pylint fixes.
229
-
230
- Pylint doesn't have auto-fix, so we provide suggestions.
231
- Can integrate with autopep8/black for some fixes.
232
- """
233
-
234
- def __init__(self):
235
- super().__init__("pylint")
236
-
237
- def can_autofix(self, issue: LintIssue) -> bool:
238
- """Pylint itself doesn't auto-fix, but we can use other tools.
239
-
240
- Some formatting issues can be fixed with black/autopep8.
241
- """
242
- formatting_rules = {
243
- "missing-final-newline",
244
- "trailing-whitespace",
245
- "line-too-long",
246
- "bad-whitespace",
247
- "bad-indentation",
248
- }
249
-
250
- return issue.rule in formatting_rules
251
-
252
- def apply_fix(self, issue: LintIssue, dry_run: bool = False) -> FixResult:
253
- """Apply Pylint fix (via black/autopep8 if possible)"""
254
- if not self.can_autofix(issue):
255
- suggestion = self.suggest_manual_fix(issue)
256
- return FixResult(
257
- issue=issue,
258
- success=False,
259
- method="manual_suggestion",
260
- changes_made=suggestion,
261
- )
262
-
263
- if dry_run:
264
- return FixResult(
265
- issue=issue,
266
- success=True,
267
- method="autofix",
268
- changes_made="Would format with black",
269
- )
270
-
271
- # SECURITY: Validate file path before subprocess execution
272
- if not _validate_file_path(issue.file_path):
273
- return FixResult(
274
- issue=issue,
275
- success=False,
276
- method="autofix",
277
- error=f"Invalid or unsafe file path: {issue.file_path}",
278
- )
279
-
280
- # Try black first
281
- try:
282
- result = subprocess.run(
283
- ["black", issue.file_path],
284
- check=False,
285
- capture_output=True,
286
- text=True,
287
- timeout=30,
288
- )
289
-
290
- if result.returncode == 0:
291
- return FixResult(
292
- issue=issue,
293
- success=True,
294
- method="autofix",
295
- changes_made=f"Formatted with black: {issue.file_path}",
296
- )
297
-
298
- except (FileNotFoundError, subprocess.TimeoutExpired):
299
- pass
300
-
301
- # Try autopep8
302
- try:
303
- result = subprocess.run(
304
- ["autopep8", "--in-place", issue.file_path],
305
- check=False,
306
- capture_output=True,
307
- text=True,
308
- timeout=30,
309
- )
310
-
311
- if result.returncode == 0:
312
- return FixResult(
313
- issue=issue,
314
- success=True,
315
- method="autofix",
316
- changes_made=f"Formatted with autopep8: {issue.file_path}",
317
- )
318
-
319
- except (FileNotFoundError, subprocess.TimeoutExpired):
320
- pass
321
-
322
- return FixResult(
323
- issue=issue,
324
- success=False,
325
- method="manual_suggestion",
326
- error="black/autopep8 not available",
327
- )
328
-
329
- def suggest_manual_fix(self, issue: LintIssue) -> str:
330
- """Suggest manual fix"""
331
- suggestions = {
332
- "unused-variable": "Remove variable or prefix with _",
333
- "unused-import": "Remove unused import",
334
- "invalid-name": "Rename to follow naming conventions",
335
- "missing-docstring": "Add docstring to function/class",
336
- "too-many-arguments": "Reduce parameters or use config object",
337
- "no-else-return": "Remove else after return statement",
338
- }
339
-
340
- return suggestions.get(issue.rule, f"Manual fix required: {issue.message}")
341
-
342
-
343
- class TypeScriptFixApplier(BaseFixApplier):
344
- """Apply TypeScript fixes.
345
-
346
- TypeScript compiler doesn't auto-fix, but we can suggest fixes.
347
- """
348
-
349
- def __init__(self):
350
- super().__init__("typescript")
351
-
352
- def can_autofix(self, issue: LintIssue) -> bool:
353
- """TypeScript doesn't auto-fix"""
354
- return False
355
-
356
- def apply_fix(self, issue: LintIssue, dry_run: bool = False) -> FixResult:
357
- """TypeScript fixes are manual"""
358
- suggestion = self.suggest_manual_fix(issue)
359
-
360
- return FixResult(
361
- issue=issue,
362
- success=False,
363
- method="manual_suggestion",
364
- changes_made=suggestion,
365
- )
366
-
367
- def suggest_manual_fix(self, issue: LintIssue) -> str:
368
- """Suggest TypeScript fix"""
369
- # Extract TS error code
370
- if issue.rule.startswith("TS"):
371
- code = issue.rule[2:]
372
-
373
- suggestions = {
374
- "2322": "Fix type mismatch - check assigned value type",
375
- "2345": "Fix argument type - check function parameter types",
376
- "2339": "Property doesn't exist - check object structure",
377
- "2304": "Cannot find name - import or define the type/variable",
378
- "2551": "Property doesn't exist - check for typos",
379
- "7006": "Add type annotation - implicit any",
380
- }
381
-
382
- suggestion = suggestions.get(code, f"Fix type error: {issue.message}")
383
- return suggestion
384
-
385
- return f"Manual fix required: {issue.message}"
386
-
387
-
388
- class FixApplierFactory:
389
- """Factory for creating fix appliers"""
390
-
391
- _appliers = {
392
- "eslint": ESLintFixApplier,
393
- "pylint": PylintFixApplier,
394
- "typescript": TypeScriptFixApplier,
395
- "tsc": TypeScriptFixApplier,
396
- "mypy": PylintFixApplier, # Similar to Pylint (no autofix)
397
- }
398
-
399
- @classmethod
400
- def create(cls, linter_name: str) -> BaseFixApplier:
401
- """Create fix applier for linter"""
402
- applier_class = cls._appliers.get(linter_name.lower())
403
-
404
- if not applier_class:
405
- raise ValueError(
406
- f"Unsupported fix applier: {linter_name}. "
407
- f"Supported: {', '.join(cls._appliers.keys())}",
408
- )
409
-
410
- return applier_class()
411
-
412
-
413
- def apply_fixes(
414
- linter_name: str,
415
- issues: list[LintIssue],
416
- dry_run: bool = False,
417
- auto_only: bool = False,
418
- ) -> list[FixResult]:
419
- """Apply fixes for list of issues.
420
-
421
- Args:
422
- linter_name: Name of linter
423
- issues: List of issues to fix
424
- dry_run: Don't actually make changes
425
- auto_only: Only apply auto-fixable issues
426
-
427
- Returns:
428
- List of FixResult objects
429
-
430
- Example:
431
- >>> results = apply_fixes("eslint", issues, dry_run=True)
432
- >>> auto_fixed = [r for r in results if r.method == "autofix" and r.success]
433
- >>> print(f"Could auto-fix {len(auto_fixed)} issues")
434
-
435
- """
436
- applier = FixApplierFactory.create(linter_name)
437
-
438
- if auto_only:
439
- issues = [i for i in issues if applier.can_autofix(i)]
440
-
441
- return applier.apply_fixes_batch(issues, dry_run)
442
-
443
-
444
- def group_issues_by_fixability(
445
- linter_name: str,
446
- issues: list[LintIssue],
447
- ) -> dict[str, list[LintIssue]]:
448
- """Group issues by whether they can be auto-fixed.
449
-
450
- Args:
451
- linter_name: Name of linter
452
- issues: List of issues
453
-
454
- Returns:
455
- Dictionary with "auto_fixable" and "manual" keys
456
-
457
- """
458
- applier = FixApplierFactory.create(linter_name)
459
-
460
- auto_fixable = []
461
- manual = []
462
-
463
- for issue in issues:
464
- if applier.can_autofix(issue):
465
- auto_fixable.append(issue)
466
- else:
467
- manual.append(issue)
468
-
469
- return {"auto_fixable": auto_fixable, "manual": manual}