crackerjack 0.32.0__py3-none-any.whl → 0.33.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.
Potentially problematic release.
This version of crackerjack might be problematic. Click here for more details.
- crackerjack/__main__.py +1350 -34
- crackerjack/adapters/__init__.py +17 -0
- crackerjack/adapters/lsp_client.py +358 -0
- crackerjack/adapters/rust_tool_adapter.py +194 -0
- crackerjack/adapters/rust_tool_manager.py +193 -0
- crackerjack/adapters/skylos_adapter.py +231 -0
- crackerjack/adapters/zuban_adapter.py +560 -0
- crackerjack/agents/base.py +7 -3
- crackerjack/agents/coordinator.py +271 -33
- crackerjack/agents/documentation_agent.py +9 -15
- crackerjack/agents/dry_agent.py +3 -15
- crackerjack/agents/formatting_agent.py +1 -1
- crackerjack/agents/import_optimization_agent.py +36 -180
- crackerjack/agents/performance_agent.py +17 -98
- crackerjack/agents/performance_helpers.py +7 -31
- crackerjack/agents/proactive_agent.py +1 -3
- crackerjack/agents/refactoring_agent.py +16 -85
- crackerjack/agents/refactoring_helpers.py +7 -42
- crackerjack/agents/security_agent.py +9 -48
- crackerjack/agents/test_creation_agent.py +356 -513
- crackerjack/agents/test_specialist_agent.py +0 -4
- crackerjack/api.py +6 -25
- crackerjack/cli/cache_handlers.py +204 -0
- crackerjack/cli/cache_handlers_enhanced.py +683 -0
- crackerjack/cli/facade.py +100 -0
- crackerjack/cli/handlers.py +224 -9
- crackerjack/cli/interactive.py +6 -4
- crackerjack/cli/options.py +642 -55
- crackerjack/cli/utils.py +2 -1
- crackerjack/code_cleaner.py +58 -117
- crackerjack/config/global_lock_config.py +8 -48
- crackerjack/config/hooks.py +53 -62
- crackerjack/core/async_workflow_orchestrator.py +24 -34
- crackerjack/core/autofix_coordinator.py +3 -17
- crackerjack/core/enhanced_container.py +64 -6
- crackerjack/core/file_lifecycle.py +12 -89
- crackerjack/core/performance.py +2 -2
- crackerjack/core/performance_monitor.py +15 -55
- crackerjack/core/phase_coordinator.py +257 -218
- crackerjack/core/resource_manager.py +14 -90
- crackerjack/core/service_watchdog.py +62 -95
- crackerjack/core/session_coordinator.py +149 -0
- crackerjack/core/timeout_manager.py +14 -72
- crackerjack/core/websocket_lifecycle.py +13 -78
- crackerjack/core/workflow_orchestrator.py +558 -240
- crackerjack/docs/INDEX.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +765 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +977 -0
- crackerjack/dynamic_config.py +55 -50
- crackerjack/executors/async_hook_executor.py +10 -15
- crackerjack/executors/cached_hook_executor.py +117 -43
- crackerjack/executors/hook_executor.py +8 -34
- crackerjack/executors/hook_lock_manager.py +26 -183
- crackerjack/executors/individual_hook_executor.py +13 -11
- crackerjack/executors/lsp_aware_hook_executor.py +270 -0
- crackerjack/executors/tool_proxy.py +417 -0
- crackerjack/hooks/lsp_hook.py +79 -0
- crackerjack/intelligence/adaptive_learning.py +25 -10
- crackerjack/intelligence/agent_orchestrator.py +2 -5
- crackerjack/intelligence/agent_registry.py +34 -24
- crackerjack/intelligence/agent_selector.py +5 -7
- crackerjack/interactive.py +17 -6
- crackerjack/managers/async_hook_manager.py +0 -1
- crackerjack/managers/hook_manager.py +79 -1
- crackerjack/managers/publish_manager.py +66 -13
- crackerjack/managers/test_command_builder.py +5 -17
- crackerjack/managers/test_executor.py +1 -3
- crackerjack/managers/test_manager.py +109 -7
- crackerjack/managers/test_manager_backup.py +10 -9
- crackerjack/mcp/cache.py +2 -2
- crackerjack/mcp/client_runner.py +1 -1
- crackerjack/mcp/context.py +191 -68
- crackerjack/mcp/dashboard.py +7 -5
- crackerjack/mcp/enhanced_progress_monitor.py +31 -28
- crackerjack/mcp/file_monitor.py +30 -23
- crackerjack/mcp/progress_components.py +31 -21
- crackerjack/mcp/progress_monitor.py +50 -53
- crackerjack/mcp/rate_limiter.py +6 -6
- crackerjack/mcp/server_core.py +161 -32
- crackerjack/mcp/service_watchdog.py +2 -1
- crackerjack/mcp/state.py +4 -7
- crackerjack/mcp/task_manager.py +11 -9
- crackerjack/mcp/tools/core_tools.py +174 -33
- crackerjack/mcp/tools/error_analyzer.py +3 -2
- crackerjack/mcp/tools/execution_tools.py +15 -12
- crackerjack/mcp/tools/execution_tools_backup.py +42 -30
- crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
- crackerjack/mcp/tools/intelligence_tools.py +5 -2
- crackerjack/mcp/tools/monitoring_tools.py +33 -70
- crackerjack/mcp/tools/proactive_tools.py +24 -11
- crackerjack/mcp/tools/progress_tools.py +5 -8
- crackerjack/mcp/tools/utility_tools.py +20 -14
- crackerjack/mcp/tools/workflow_executor.py +62 -40
- crackerjack/mcp/websocket/app.py +8 -0
- crackerjack/mcp/websocket/endpoints.py +352 -357
- crackerjack/mcp/websocket/jobs.py +40 -57
- crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
- crackerjack/mcp/websocket/server.py +7 -25
- crackerjack/mcp/websocket/websocket_handler.py +6 -17
- crackerjack/mixins/__init__.py +3 -0
- crackerjack/mixins/error_handling.py +145 -0
- crackerjack/models/config.py +21 -1
- crackerjack/models/config_adapter.py +49 -1
- crackerjack/models/protocols.py +176 -107
- crackerjack/models/resource_protocols.py +55 -210
- crackerjack/models/task.py +3 -0
- crackerjack/monitoring/ai_agent_watchdog.py +13 -13
- crackerjack/monitoring/metrics_collector.py +426 -0
- crackerjack/monitoring/regression_prevention.py +8 -8
- crackerjack/monitoring/websocket_server.py +643 -0
- crackerjack/orchestration/advanced_orchestrator.py +11 -6
- crackerjack/orchestration/coverage_improvement.py +3 -3
- crackerjack/orchestration/execution_strategies.py +26 -6
- crackerjack/orchestration/test_progress_streamer.py +8 -5
- crackerjack/plugins/base.py +2 -2
- crackerjack/plugins/hooks.py +7 -0
- crackerjack/plugins/managers.py +11 -8
- crackerjack/security/__init__.py +0 -1
- crackerjack/security/audit.py +90 -105
- crackerjack/services/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +615 -0
- crackerjack/services/backup_service.py +2 -2
- crackerjack/services/bounded_status_operations.py +15 -152
- crackerjack/services/cache.py +127 -1
- crackerjack/services/changelog_automation.py +395 -0
- crackerjack/services/config.py +18 -11
- crackerjack/services/config_merge.py +30 -85
- crackerjack/services/config_template.py +506 -0
- crackerjack/services/contextual_ai_assistant.py +48 -22
- crackerjack/services/coverage_badge_service.py +171 -0
- crackerjack/services/coverage_ratchet.py +41 -17
- crackerjack/services/debug.py +3 -3
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +14 -11
- crackerjack/services/documentation_generator.py +491 -0
- crackerjack/services/documentation_service.py +675 -0
- crackerjack/services/enhanced_filesystem.py +6 -5
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_hasher.py +1 -1
- crackerjack/services/git.py +41 -45
- crackerjack/services/health_metrics.py +10 -8
- crackerjack/services/heatmap_generator.py +735 -0
- crackerjack/services/initialization.py +30 -33
- crackerjack/services/input_validator.py +5 -97
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +15 -12
- crackerjack/services/logging.py +4 -3
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +409 -0
- crackerjack/services/metrics.py +42 -33
- crackerjack/services/parallel_executor.py +416 -0
- crackerjack/services/pattern_cache.py +1 -1
- crackerjack/services/pattern_detector.py +6 -6
- crackerjack/services/performance_benchmarks.py +250 -576
- crackerjack/services/performance_cache.py +382 -0
- crackerjack/services/performance_monitor.py +565 -0
- crackerjack/services/predictive_analytics.py +510 -0
- crackerjack/services/quality_baseline.py +234 -0
- crackerjack/services/quality_baseline_enhanced.py +646 -0
- crackerjack/services/quality_intelligence.py +785 -0
- crackerjack/services/regex_patterns.py +605 -524
- crackerjack/services/regex_utils.py +43 -123
- crackerjack/services/secure_path_utils.py +5 -164
- crackerjack/services/secure_status_formatter.py +30 -141
- crackerjack/services/secure_subprocess.py +11 -92
- crackerjack/services/security.py +61 -30
- crackerjack/services/security_logger.py +18 -22
- crackerjack/services/server_manager.py +124 -16
- crackerjack/services/status_authentication.py +16 -159
- crackerjack/services/status_security_manager.py +4 -131
- crackerjack/services/terminal_utils.py +0 -0
- crackerjack/services/thread_safe_status_collector.py +19 -125
- crackerjack/services/unified_config.py +21 -13
- crackerjack/services/validation_rate_limiter.py +5 -54
- crackerjack/services/version_analyzer.py +459 -0
- crackerjack/services/version_checker.py +1 -1
- crackerjack/services/websocket_resource_limiter.py +10 -144
- crackerjack/services/zuban_lsp_service.py +390 -0
- crackerjack/slash_commands/__init__.py +2 -7
- crackerjack/slash_commands/run.md +2 -2
- crackerjack/tools/validate_input_validator_patterns.py +14 -40
- crackerjack/tools/validate_regex_patterns.py +19 -48
- {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +197 -26
- crackerjack-0.33.1.dist-info/RECORD +229 -0
- crackerjack/CLAUDE.md +0 -207
- crackerjack/RULES.md +0 -380
- crackerjack/py313.py +0 -234
- crackerjack-0.32.0.dist-info/RECORD +0 -180
- {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
- {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import typing as t
|
|
3
|
+
from dataclasses import asdict, dataclass
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
from crackerjack.services.cache import CrackerjackCache
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class QualityMetrics:
|
|
11
|
+
"""Quality metrics for a specific commit/session."""
|
|
12
|
+
|
|
13
|
+
git_hash: str
|
|
14
|
+
timestamp: datetime
|
|
15
|
+
coverage_percent: float
|
|
16
|
+
test_count: int
|
|
17
|
+
test_pass_rate: float
|
|
18
|
+
hook_failures: int
|
|
19
|
+
complexity_violations: int
|
|
20
|
+
security_issues: int
|
|
21
|
+
type_errors: int
|
|
22
|
+
linting_issues: int
|
|
23
|
+
quality_score: int # Overall score 0-100
|
|
24
|
+
|
|
25
|
+
def to_dict(self) -> dict[str, t.Any]:
|
|
26
|
+
data = asdict(self)
|
|
27
|
+
data["timestamp"] = self.timestamp.isoformat()
|
|
28
|
+
return data
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def from_dict(cls, data: dict[str, t.Any]) -> "QualityMetrics":
|
|
32
|
+
data = data.copy()
|
|
33
|
+
if isinstance(data["timestamp"], str):
|
|
34
|
+
data["timestamp"] = datetime.fromisoformat(data["timestamp"])
|
|
35
|
+
return cls(**data)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class QualityBaselineService:
|
|
39
|
+
"""Service for tracking and persisting quality baselines across sessions."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, cache: CrackerjackCache | None = None) -> None:
|
|
42
|
+
self.cache = cache or CrackerjackCache()
|
|
43
|
+
|
|
44
|
+
def get_current_git_hash(self) -> str | None:
|
|
45
|
+
"""Get current git commit hash."""
|
|
46
|
+
try:
|
|
47
|
+
result = subprocess.run(
|
|
48
|
+
["git", "rev-parse", "HEAD"],
|
|
49
|
+
capture_output=True,
|
|
50
|
+
text=True,
|
|
51
|
+
check=True,
|
|
52
|
+
)
|
|
53
|
+
return result.stdout.strip()
|
|
54
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
def calculate_quality_score(
|
|
58
|
+
self,
|
|
59
|
+
coverage_percent: float,
|
|
60
|
+
test_pass_rate: float,
|
|
61
|
+
hook_failures: int,
|
|
62
|
+
complexity_violations: int,
|
|
63
|
+
security_issues: int,
|
|
64
|
+
type_errors: int,
|
|
65
|
+
linting_issues: int,
|
|
66
|
+
) -> int:
|
|
67
|
+
"""Calculate overall quality score (0-100)."""
|
|
68
|
+
# Base score from coverage and tests
|
|
69
|
+
base_score = (coverage_percent * 0.4) + (test_pass_rate * 0.3)
|
|
70
|
+
|
|
71
|
+
# Penalty for issues (each issue type has different weight)
|
|
72
|
+
penalties = (
|
|
73
|
+
hook_failures * 2.0 # Hook failures are serious
|
|
74
|
+
+ complexity_violations * 1.5 # Complexity is important
|
|
75
|
+
+ security_issues * 3.0 # Security is critical
|
|
76
|
+
+ type_errors * 2.0 # Type errors are serious
|
|
77
|
+
+ linting_issues * 0.5 # Linting is less critical
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Apply penalties with diminishing returns
|
|
81
|
+
penalty_score = max(0, 30 - (penalties * 0.8))
|
|
82
|
+
|
|
83
|
+
return max(0, min(100, int(base_score + penalty_score)))
|
|
84
|
+
|
|
85
|
+
def record_baseline(
|
|
86
|
+
self,
|
|
87
|
+
coverage_percent: float,
|
|
88
|
+
test_count: int,
|
|
89
|
+
test_pass_rate: float,
|
|
90
|
+
hook_failures: int = 0,
|
|
91
|
+
complexity_violations: int = 0,
|
|
92
|
+
security_issues: int = 0,
|
|
93
|
+
type_errors: int = 0,
|
|
94
|
+
linting_issues: int = 0,
|
|
95
|
+
) -> QualityMetrics | None:
|
|
96
|
+
"""Record quality baseline for current commit."""
|
|
97
|
+
git_hash = self.get_current_git_hash()
|
|
98
|
+
if not git_hash:
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
quality_score = self.calculate_quality_score(
|
|
102
|
+
coverage_percent=coverage_percent,
|
|
103
|
+
test_pass_rate=test_pass_rate,
|
|
104
|
+
hook_failures=hook_failures,
|
|
105
|
+
complexity_violations=complexity_violations,
|
|
106
|
+
security_issues=security_issues,
|
|
107
|
+
type_errors=type_errors,
|
|
108
|
+
linting_issues=linting_issues,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
metrics = QualityMetrics(
|
|
112
|
+
git_hash=git_hash,
|
|
113
|
+
timestamp=datetime.now(),
|
|
114
|
+
coverage_percent=coverage_percent,
|
|
115
|
+
test_count=test_count,
|
|
116
|
+
test_pass_rate=test_pass_rate,
|
|
117
|
+
hook_failures=hook_failures,
|
|
118
|
+
complexity_violations=complexity_violations,
|
|
119
|
+
security_issues=security_issues,
|
|
120
|
+
type_errors=type_errors,
|
|
121
|
+
linting_issues=linting_issues,
|
|
122
|
+
quality_score=quality_score,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Store in cache for persistence across sessions
|
|
126
|
+
self.cache.set_quality_baseline(git_hash, metrics.to_dict())
|
|
127
|
+
return metrics
|
|
128
|
+
|
|
129
|
+
def get_baseline(self, git_hash: str | None = None) -> QualityMetrics | None:
|
|
130
|
+
"""Get quality baseline for specific commit (or current commit)."""
|
|
131
|
+
if not git_hash:
|
|
132
|
+
git_hash = self.get_current_git_hash()
|
|
133
|
+
|
|
134
|
+
if not git_hash:
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
baseline_data = self.cache.get_quality_baseline(git_hash)
|
|
138
|
+
if baseline_data:
|
|
139
|
+
return QualityMetrics.from_dict(baseline_data)
|
|
140
|
+
|
|
141
|
+
return None
|
|
142
|
+
|
|
143
|
+
def compare_with_baseline(
|
|
144
|
+
self,
|
|
145
|
+
current_metrics: dict[str, t.Any],
|
|
146
|
+
baseline_git_hash: str | None = None,
|
|
147
|
+
) -> dict[str, t.Any]:
|
|
148
|
+
"""Compare current metrics with baseline."""
|
|
149
|
+
baseline = self.get_baseline(baseline_git_hash)
|
|
150
|
+
if not baseline:
|
|
151
|
+
return {
|
|
152
|
+
"comparison_available": False,
|
|
153
|
+
"message": "No baseline found for comparison",
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
current_score = self.calculate_quality_score(**current_metrics)
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
"comparison_available": True,
|
|
160
|
+
"baseline_score": baseline.quality_score,
|
|
161
|
+
"current_score": current_score,
|
|
162
|
+
"score_change": current_score - baseline.quality_score,
|
|
163
|
+
"baseline_timestamp": baseline.timestamp.isoformat(),
|
|
164
|
+
"improvements": self._identify_improvements(baseline, current_metrics),
|
|
165
|
+
"regressions": self._identify_regressions(baseline, current_metrics),
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
def _identify_improvements(
|
|
169
|
+
self, baseline: QualityMetrics, current: dict[str, t.Any]
|
|
170
|
+
) -> list[str]:
|
|
171
|
+
"""Identify areas that improved since baseline."""
|
|
172
|
+
improvements = []
|
|
173
|
+
|
|
174
|
+
if current["coverage_percent"] > baseline.coverage_percent:
|
|
175
|
+
improvements.append(
|
|
176
|
+
f"Coverage increased by {current['coverage_percent'] - baseline.coverage_percent:.1f}%"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
if current["test_pass_rate"] > baseline.test_pass_rate:
|
|
180
|
+
improvements.append(
|
|
181
|
+
f"Test pass rate improved by {current['test_pass_rate'] - baseline.test_pass_rate:.1f}%"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
if current.get("hook_failures", 0) < baseline.hook_failures:
|
|
185
|
+
improvements.append(
|
|
186
|
+
f"Hook failures reduced by {baseline.hook_failures - current.get('hook_failures', 0)}"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
return improvements
|
|
190
|
+
|
|
191
|
+
def _identify_regressions(
|
|
192
|
+
self, baseline: QualityMetrics, current: dict[str, t.Any]
|
|
193
|
+
) -> list[str]:
|
|
194
|
+
"""Identify areas that regressed since baseline."""
|
|
195
|
+
regressions = []
|
|
196
|
+
|
|
197
|
+
if current["coverage_percent"] < baseline.coverage_percent:
|
|
198
|
+
regressions.append(
|
|
199
|
+
f"Coverage decreased by {baseline.coverage_percent - current['coverage_percent']:.1f}%"
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if current["test_pass_rate"] < baseline.test_pass_rate:
|
|
203
|
+
regressions.append(
|
|
204
|
+
f"Test pass rate decreased by {baseline.test_pass_rate - current['test_pass_rate']:.1f}%"
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
if current.get("security_issues", 0) > baseline.security_issues:
|
|
208
|
+
regressions.append(
|
|
209
|
+
f"Security issues increased by {current.get('security_issues', 0) - baseline.security_issues}"
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
return regressions
|
|
213
|
+
|
|
214
|
+
def get_recent_baselines(self, limit: int = 10) -> list[QualityMetrics]:
|
|
215
|
+
"""Get recent baselines (requires git log parsing since cache is keyed by hash)."""
|
|
216
|
+
try:
|
|
217
|
+
result = subprocess.run(
|
|
218
|
+
["git", "log", "--oneline", "-n", str(limit), "--format=%H"],
|
|
219
|
+
capture_output=True,
|
|
220
|
+
text=True,
|
|
221
|
+
check=True,
|
|
222
|
+
)
|
|
223
|
+
git_hashes = result.stdout.strip().split("\n")
|
|
224
|
+
|
|
225
|
+
baselines = []
|
|
226
|
+
for git_hash in git_hashes:
|
|
227
|
+
baseline = self.get_baseline(git_hash.strip())
|
|
228
|
+
if baseline:
|
|
229
|
+
baselines.append(baseline)
|
|
230
|
+
|
|
231
|
+
return sorted(baselines, key=lambda b: b.timestamp, reverse=True)
|
|
232
|
+
|
|
233
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
234
|
+
return []
|