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.
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/METADATA +7 -6
- empathy_framework-4.7.0.dist-info/RECORD +354 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/top_level.txt +0 -2
- empathy_healthcare_plugin/monitors/monitoring/__init__.py +9 -9
- empathy_llm_toolkit/agent_factory/__init__.py +6 -6
- empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +7 -10
- empathy_llm_toolkit/agents_md/__init__.py +22 -0
- empathy_llm_toolkit/agents_md/loader.py +218 -0
- empathy_llm_toolkit/agents_md/parser.py +271 -0
- empathy_llm_toolkit/agents_md/registry.py +307 -0
- empathy_llm_toolkit/commands/__init__.py +51 -0
- empathy_llm_toolkit/commands/context.py +375 -0
- empathy_llm_toolkit/commands/loader.py +301 -0
- empathy_llm_toolkit/commands/models.py +231 -0
- empathy_llm_toolkit/commands/parser.py +371 -0
- empathy_llm_toolkit/commands/registry.py +429 -0
- empathy_llm_toolkit/config/__init__.py +8 -8
- empathy_llm_toolkit/config/unified.py +3 -7
- empathy_llm_toolkit/context/__init__.py +22 -0
- empathy_llm_toolkit/context/compaction.py +455 -0
- empathy_llm_toolkit/context/manager.py +434 -0
- empathy_llm_toolkit/hooks/__init__.py +24 -0
- empathy_llm_toolkit/hooks/config.py +306 -0
- empathy_llm_toolkit/hooks/executor.py +289 -0
- empathy_llm_toolkit/hooks/registry.py +302 -0
- empathy_llm_toolkit/hooks/scripts/__init__.py +39 -0
- empathy_llm_toolkit/hooks/scripts/evaluate_session.py +201 -0
- empathy_llm_toolkit/hooks/scripts/first_time_init.py +285 -0
- empathy_llm_toolkit/hooks/scripts/pre_compact.py +207 -0
- empathy_llm_toolkit/hooks/scripts/session_end.py +183 -0
- empathy_llm_toolkit/hooks/scripts/session_start.py +163 -0
- empathy_llm_toolkit/hooks/scripts/suggest_compact.py +225 -0
- empathy_llm_toolkit/learning/__init__.py +30 -0
- empathy_llm_toolkit/learning/evaluator.py +438 -0
- empathy_llm_toolkit/learning/extractor.py +514 -0
- empathy_llm_toolkit/learning/storage.py +560 -0
- empathy_llm_toolkit/providers.py +4 -11
- empathy_llm_toolkit/security/__init__.py +17 -17
- empathy_llm_toolkit/utils/tokens.py +2 -5
- empathy_os/__init__.py +202 -70
- empathy_os/cache_monitor.py +5 -3
- empathy_os/cli/__init__.py +11 -55
- empathy_os/cli/__main__.py +29 -15
- empathy_os/cli/commands/inspection.py +21 -12
- empathy_os/cli/commands/memory.py +4 -12
- empathy_os/cli/commands/profiling.py +198 -0
- empathy_os/cli/commands/utilities.py +27 -7
- empathy_os/cli.py +28 -57
- empathy_os/cli_unified.py +525 -1164
- empathy_os/cost_tracker.py +9 -3
- empathy_os/dashboard/server.py +200 -2
- empathy_os/hot_reload/__init__.py +7 -7
- empathy_os/hot_reload/config.py +6 -7
- empathy_os/hot_reload/integration.py +35 -35
- empathy_os/hot_reload/reloader.py +57 -57
- empathy_os/hot_reload/watcher.py +28 -28
- empathy_os/hot_reload/websocket.py +2 -2
- empathy_os/memory/__init__.py +11 -4
- empathy_os/memory/claude_memory.py +1 -1
- empathy_os/memory/cross_session.py +8 -12
- empathy_os/memory/edges.py +6 -6
- empathy_os/memory/file_session.py +770 -0
- empathy_os/memory/graph.py +30 -30
- empathy_os/memory/nodes.py +6 -6
- empathy_os/memory/short_term.py +15 -9
- empathy_os/memory/unified.py +606 -140
- empathy_os/meta_workflows/agent_creator.py +3 -9
- empathy_os/meta_workflows/cli_meta_workflows.py +113 -53
- empathy_os/meta_workflows/form_engine.py +6 -18
- empathy_os/meta_workflows/intent_detector.py +64 -24
- empathy_os/meta_workflows/models.py +3 -1
- empathy_os/meta_workflows/pattern_learner.py +13 -31
- empathy_os/meta_workflows/plan_generator.py +55 -47
- empathy_os/meta_workflows/session_context.py +2 -3
- empathy_os/meta_workflows/workflow.py +20 -51
- empathy_os/models/cli.py +2 -2
- empathy_os/models/tasks.py +1 -2
- empathy_os/models/telemetry.py +4 -1
- empathy_os/models/token_estimator.py +3 -1
- empathy_os/monitoring/alerts.py +938 -9
- empathy_os/monitoring/alerts_cli.py +346 -183
- empathy_os/orchestration/execution_strategies.py +12 -29
- empathy_os/orchestration/pattern_learner.py +20 -26
- empathy_os/orchestration/real_tools.py +6 -15
- empathy_os/platform_utils.py +2 -1
- empathy_os/plugins/__init__.py +2 -2
- empathy_os/plugins/base.py +64 -64
- empathy_os/plugins/registry.py +32 -32
- empathy_os/project_index/index.py +49 -15
- empathy_os/project_index/models.py +1 -2
- empathy_os/project_index/reports.py +1 -1
- empathy_os/project_index/scanner.py +1 -0
- empathy_os/redis_memory.py +10 -7
- empathy_os/resilience/__init__.py +1 -1
- empathy_os/resilience/health.py +10 -10
- empathy_os/routing/__init__.py +7 -7
- empathy_os/routing/chain_executor.py +37 -37
- empathy_os/routing/classifier.py +36 -36
- empathy_os/routing/smart_router.py +40 -40
- empathy_os/routing/{wizard_registry.py → workflow_registry.py} +47 -47
- empathy_os/scaffolding/__init__.py +8 -8
- empathy_os/scaffolding/__main__.py +1 -1
- empathy_os/scaffolding/cli.py +28 -28
- empathy_os/socratic/__init__.py +3 -19
- empathy_os/socratic/ab_testing.py +25 -36
- empathy_os/socratic/blueprint.py +38 -38
- empathy_os/socratic/cli.py +34 -20
- empathy_os/socratic/collaboration.py +30 -28
- empathy_os/socratic/domain_templates.py +9 -1
- empathy_os/socratic/embeddings.py +17 -13
- empathy_os/socratic/engine.py +135 -70
- empathy_os/socratic/explainer.py +70 -60
- empathy_os/socratic/feedback.py +24 -19
- empathy_os/socratic/forms.py +15 -10
- empathy_os/socratic/generator.py +51 -35
- empathy_os/socratic/llm_analyzer.py +25 -23
- empathy_os/socratic/mcp_server.py +99 -159
- empathy_os/socratic/session.py +19 -13
- empathy_os/socratic/storage.py +98 -67
- empathy_os/socratic/success.py +38 -27
- empathy_os/socratic/visual_editor.py +51 -39
- empathy_os/socratic/web_ui.py +99 -66
- empathy_os/telemetry/cli.py +3 -1
- empathy_os/telemetry/usage_tracker.py +1 -3
- empathy_os/test_generator/__init__.py +3 -3
- empathy_os/test_generator/cli.py +28 -28
- empathy_os/test_generator/generator.py +64 -66
- empathy_os/test_generator/risk_analyzer.py +11 -11
- empathy_os/vscode_bridge.py +173 -0
- empathy_os/workflows/__init__.py +212 -120
- empathy_os/workflows/batch_processing.py +8 -24
- empathy_os/workflows/bug_predict.py +1 -1
- empathy_os/workflows/code_review.py +20 -5
- empathy_os/workflows/code_review_pipeline.py +13 -8
- empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
- empathy_os/workflows/manage_documentation.py +1 -0
- empathy_os/workflows/orchestrated_health_check.py +6 -11
- empathy_os/workflows/orchestrated_release_prep.py +3 -3
- empathy_os/workflows/pr_review.py +18 -10
- empathy_os/workflows/progressive/__init__.py +2 -12
- empathy_os/workflows/progressive/cli.py +14 -37
- empathy_os/workflows/progressive/core.py +12 -12
- empathy_os/workflows/progressive/orchestrator.py +166 -144
- empathy_os/workflows/progressive/reports.py +22 -31
- empathy_os/workflows/progressive/telemetry.py +8 -14
- empathy_os/workflows/progressive/test_gen.py +29 -48
- empathy_os/workflows/progressive/workflow.py +31 -70
- empathy_os/workflows/release_prep.py +21 -6
- empathy_os/workflows/release_prep_crew.py +1 -0
- empathy_os/workflows/secure_release.py +13 -6
- empathy_os/workflows/security_audit.py +8 -3
- empathy_os/workflows/test_coverage_boost_crew.py +3 -2
- empathy_os/workflows/test_maintenance_crew.py +1 -0
- empathy_os/workflows/test_runner.py +16 -12
- empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
- empathy_software_plugin/cli.py +0 -122
- coach_wizards/__init__.py +0 -45
- coach_wizards/accessibility_wizard.py +0 -91
- coach_wizards/api_wizard.py +0 -91
- coach_wizards/base_wizard.py +0 -209
- coach_wizards/cicd_wizard.py +0 -91
- coach_wizards/code_reviewer_README.md +0 -60
- coach_wizards/code_reviewer_wizard.py +0 -180
- coach_wizards/compliance_wizard.py +0 -91
- coach_wizards/database_wizard.py +0 -91
- coach_wizards/debugging_wizard.py +0 -91
- coach_wizards/documentation_wizard.py +0 -91
- coach_wizards/generate_wizards.py +0 -347
- coach_wizards/localization_wizard.py +0 -173
- coach_wizards/migration_wizard.py +0 -91
- coach_wizards/monitoring_wizard.py +0 -91
- coach_wizards/observability_wizard.py +0 -91
- coach_wizards/performance_wizard.py +0 -91
- coach_wizards/prompt_engineering_wizard.py +0 -661
- coach_wizards/refactoring_wizard.py +0 -91
- coach_wizards/scaling_wizard.py +0 -90
- coach_wizards/security_wizard.py +0 -92
- coach_wizards/testing_wizard.py +0 -91
- empathy_framework-4.6.6.dist-info/RECORD +0 -410
- empathy_llm_toolkit/wizards/__init__.py +0 -43
- empathy_llm_toolkit/wizards/base_wizard.py +0 -364
- empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
- empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
- empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
- empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
- empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
- empathy_os/wizard_factory_cli.py +0 -170
- empathy_software_plugin/wizards/__init__.py +0 -42
- empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
- empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
- empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
- empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
- empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
- empathy_software_plugin/wizards/base_wizard.py +0 -288
- empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
- empathy_software_plugin/wizards/code_review_wizard.py +0 -604
- empathy_software_plugin/wizards/debugging/__init__.py +0 -50
- empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
- empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
- empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
- empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
- empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
- empathy_software_plugin/wizards/debugging/verification.py +0 -369
- empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
- empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
- empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
- empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
- empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
- empathy_software_plugin/wizards/performance/__init__.py +0 -9
- empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
- empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
- empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
- empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
- empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
- empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
- empathy_software_plugin/wizards/security/__init__.py +0 -32
- empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
- empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
- empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
- empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
- empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
- empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
- empathy_software_plugin/wizards/testing/__init__.py +0 -27
- empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
- empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
- empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
- empathy_software_plugin/wizards/testing_wizard.py +0 -274
- wizards/__init__.py +0 -82
- wizards/admission_assessment_wizard.py +0 -644
- wizards/care_plan.py +0 -321
- wizards/clinical_assessment.py +0 -769
- wizards/discharge_planning.py +0 -77
- wizards/discharge_summary_wizard.py +0 -468
- wizards/dosage_calculation.py +0 -497
- wizards/incident_report_wizard.py +0 -454
- wizards/medication_reconciliation.py +0 -85
- wizards/nursing_assessment.py +0 -171
- wizards/patient_education.py +0 -654
- wizards/quality_improvement.py +0 -705
- wizards/sbar_report.py +0 -324
- wizards/sbar_wizard.py +0 -608
- wizards/shift_handoff_wizard.py +0 -535
- wizards/soap_note_wizard.py +0 -679
- wizards/treatment_plan.py +0 -15
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/WHEEL +0 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/entry_points.txt +0 -0
- {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
|