crackerjack 0.29.0__py3-none-any.whl โ 0.31.4__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/CLAUDE.md +1005 -0
- crackerjack/RULES.md +380 -0
- crackerjack/__init__.py +42 -13
- crackerjack/__main__.py +225 -253
- crackerjack/agents/__init__.py +41 -0
- crackerjack/agents/architect_agent.py +281 -0
- crackerjack/agents/base.py +169 -0
- crackerjack/agents/coordinator.py +512 -0
- crackerjack/agents/documentation_agent.py +498 -0
- crackerjack/agents/dry_agent.py +388 -0
- crackerjack/agents/formatting_agent.py +245 -0
- crackerjack/agents/import_optimization_agent.py +281 -0
- crackerjack/agents/performance_agent.py +669 -0
- crackerjack/agents/proactive_agent.py +104 -0
- crackerjack/agents/refactoring_agent.py +788 -0
- crackerjack/agents/security_agent.py +529 -0
- crackerjack/agents/test_creation_agent.py +652 -0
- crackerjack/agents/test_specialist_agent.py +486 -0
- crackerjack/agents/tracker.py +212 -0
- crackerjack/api.py +560 -0
- crackerjack/cli/__init__.py +24 -0
- crackerjack/cli/facade.py +104 -0
- crackerjack/cli/handlers.py +267 -0
- crackerjack/cli/interactive.py +471 -0
- crackerjack/cli/options.py +401 -0
- crackerjack/cli/utils.py +18 -0
- crackerjack/code_cleaner.py +670 -0
- crackerjack/config/__init__.py +19 -0
- crackerjack/config/hooks.py +218 -0
- crackerjack/core/__init__.py +0 -0
- crackerjack/core/async_workflow_orchestrator.py +406 -0
- crackerjack/core/autofix_coordinator.py +200 -0
- crackerjack/core/container.py +104 -0
- crackerjack/core/enhanced_container.py +542 -0
- crackerjack/core/performance.py +243 -0
- crackerjack/core/phase_coordinator.py +561 -0
- crackerjack/core/proactive_workflow.py +316 -0
- crackerjack/core/session_coordinator.py +289 -0
- crackerjack/core/workflow_orchestrator.py +640 -0
- crackerjack/dynamic_config.py +577 -0
- crackerjack/errors.py +263 -41
- crackerjack/executors/__init__.py +11 -0
- crackerjack/executors/async_hook_executor.py +431 -0
- crackerjack/executors/cached_hook_executor.py +242 -0
- crackerjack/executors/hook_executor.py +345 -0
- crackerjack/executors/individual_hook_executor.py +669 -0
- crackerjack/intelligence/__init__.py +44 -0
- crackerjack/intelligence/adaptive_learning.py +751 -0
- crackerjack/intelligence/agent_orchestrator.py +551 -0
- crackerjack/intelligence/agent_registry.py +414 -0
- crackerjack/intelligence/agent_selector.py +502 -0
- crackerjack/intelligence/integration.py +290 -0
- crackerjack/interactive.py +576 -315
- crackerjack/managers/__init__.py +11 -0
- crackerjack/managers/async_hook_manager.py +135 -0
- crackerjack/managers/hook_manager.py +137 -0
- crackerjack/managers/publish_manager.py +411 -0
- crackerjack/managers/test_command_builder.py +151 -0
- crackerjack/managers/test_executor.py +435 -0
- crackerjack/managers/test_manager.py +258 -0
- crackerjack/managers/test_manager_backup.py +1124 -0
- crackerjack/managers/test_progress.py +144 -0
- crackerjack/mcp/__init__.py +0 -0
- crackerjack/mcp/cache.py +336 -0
- crackerjack/mcp/client_runner.py +104 -0
- crackerjack/mcp/context.py +615 -0
- crackerjack/mcp/dashboard.py +636 -0
- crackerjack/mcp/enhanced_progress_monitor.py +479 -0
- crackerjack/mcp/file_monitor.py +336 -0
- crackerjack/mcp/progress_components.py +569 -0
- crackerjack/mcp/progress_monitor.py +949 -0
- crackerjack/mcp/rate_limiter.py +332 -0
- crackerjack/mcp/server.py +22 -0
- crackerjack/mcp/server_core.py +244 -0
- crackerjack/mcp/service_watchdog.py +501 -0
- crackerjack/mcp/state.py +395 -0
- crackerjack/mcp/task_manager.py +257 -0
- crackerjack/mcp/tools/__init__.py +17 -0
- crackerjack/mcp/tools/core_tools.py +249 -0
- crackerjack/mcp/tools/error_analyzer.py +308 -0
- crackerjack/mcp/tools/execution_tools.py +370 -0
- crackerjack/mcp/tools/execution_tools_backup.py +1097 -0
- crackerjack/mcp/tools/intelligence_tool_registry.py +80 -0
- crackerjack/mcp/tools/intelligence_tools.py +314 -0
- crackerjack/mcp/tools/monitoring_tools.py +502 -0
- crackerjack/mcp/tools/proactive_tools.py +384 -0
- crackerjack/mcp/tools/progress_tools.py +141 -0
- crackerjack/mcp/tools/utility_tools.py +341 -0
- crackerjack/mcp/tools/workflow_executor.py +360 -0
- crackerjack/mcp/websocket/__init__.py +14 -0
- crackerjack/mcp/websocket/app.py +39 -0
- crackerjack/mcp/websocket/endpoints.py +559 -0
- crackerjack/mcp/websocket/jobs.py +253 -0
- crackerjack/mcp/websocket/server.py +116 -0
- crackerjack/mcp/websocket/websocket_handler.py +78 -0
- crackerjack/mcp/websocket_server.py +10 -0
- crackerjack/models/__init__.py +31 -0
- crackerjack/models/config.py +93 -0
- crackerjack/models/config_adapter.py +230 -0
- crackerjack/models/protocols.py +118 -0
- crackerjack/models/task.py +154 -0
- crackerjack/monitoring/ai_agent_watchdog.py +450 -0
- crackerjack/monitoring/regression_prevention.py +638 -0
- crackerjack/orchestration/__init__.py +0 -0
- crackerjack/orchestration/advanced_orchestrator.py +970 -0
- crackerjack/orchestration/execution_strategies.py +341 -0
- crackerjack/orchestration/test_progress_streamer.py +636 -0
- crackerjack/plugins/__init__.py +15 -0
- crackerjack/plugins/base.py +200 -0
- crackerjack/plugins/hooks.py +246 -0
- crackerjack/plugins/loader.py +335 -0
- crackerjack/plugins/managers.py +259 -0
- crackerjack/py313.py +8 -3
- crackerjack/services/__init__.py +22 -0
- crackerjack/services/cache.py +314 -0
- crackerjack/services/config.py +347 -0
- crackerjack/services/config_integrity.py +99 -0
- crackerjack/services/contextual_ai_assistant.py +516 -0
- crackerjack/services/coverage_ratchet.py +347 -0
- crackerjack/services/debug.py +736 -0
- crackerjack/services/dependency_monitor.py +617 -0
- crackerjack/services/enhanced_filesystem.py +439 -0
- crackerjack/services/file_hasher.py +151 -0
- crackerjack/services/filesystem.py +395 -0
- crackerjack/services/git.py +165 -0
- crackerjack/services/health_metrics.py +611 -0
- crackerjack/services/initialization.py +847 -0
- crackerjack/services/log_manager.py +286 -0
- crackerjack/services/logging.py +174 -0
- crackerjack/services/metrics.py +578 -0
- crackerjack/services/pattern_cache.py +362 -0
- crackerjack/services/pattern_detector.py +515 -0
- crackerjack/services/performance_benchmarks.py +653 -0
- crackerjack/services/security.py +163 -0
- crackerjack/services/server_manager.py +234 -0
- crackerjack/services/smart_scheduling.py +144 -0
- crackerjack/services/tool_version_service.py +61 -0
- crackerjack/services/unified_config.py +437 -0
- crackerjack/services/version_checker.py +248 -0
- crackerjack/slash_commands/__init__.py +14 -0
- crackerjack/slash_commands/init.md +122 -0
- crackerjack/slash_commands/run.md +163 -0
- crackerjack/slash_commands/status.md +127 -0
- crackerjack-0.31.4.dist-info/METADATA +742 -0
- crackerjack-0.31.4.dist-info/RECORD +148 -0
- crackerjack-0.31.4.dist-info/entry_points.txt +2 -0
- crackerjack/.gitignore +0 -34
- crackerjack/.libcst.codemod.yaml +0 -18
- crackerjack/.pdm.toml +0 -1
- crackerjack/.pre-commit-config-ai.yaml +0 -149
- crackerjack/.pre-commit-config-fast.yaml +0 -69
- crackerjack/.pre-commit-config.yaml +0 -114
- crackerjack/crackerjack.py +0 -4140
- crackerjack/pyproject.toml +0 -285
- crackerjack-0.29.0.dist-info/METADATA +0 -1289
- crackerjack-0.29.0.dist-info/RECORD +0 -17
- {crackerjack-0.29.0.dist-info โ crackerjack-0.31.4.dist-info}/WHEEL +0 -0
- {crackerjack-0.29.0.dist-info โ crackerjack-0.31.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import typing as t
|
|
2
|
+
|
|
3
|
+
from crackerjack.mcp.context import get_context
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async def create_task_with_subagent(
|
|
7
|
+
description: str,
|
|
8
|
+
prompt: str,
|
|
9
|
+
subagent_type: str,
|
|
10
|
+
) -> dict[str, t.Any]:
|
|
11
|
+
"""Create a task using a specific subagent type.
|
|
12
|
+
|
|
13
|
+
This function provides integration with the Task tool for executing
|
|
14
|
+
user agents and system agents through the intelligent agent system.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
description: Description of the task
|
|
18
|
+
prompt: The actual task prompt/content
|
|
19
|
+
subagent_type: Type of subagent to use
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Dictionary with task execution results
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
# For now, return a placeholder result indicating the task would be executed
|
|
26
|
+
# In a full implementation, this would integrate with the actual Task tool
|
|
27
|
+
|
|
28
|
+
result = {
|
|
29
|
+
"success": True,
|
|
30
|
+
"description": description,
|
|
31
|
+
"prompt": prompt,
|
|
32
|
+
"subagent_type": subagent_type,
|
|
33
|
+
"result": f"Task would be executed by {subagent_type}: {prompt[:100]}...",
|
|
34
|
+
"agent_type": "user"
|
|
35
|
+
if subagent_type
|
|
36
|
+
not in ("general-purpose", "statusline-setup", "output-style-setup")
|
|
37
|
+
else "system",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return result
|
|
41
|
+
|
|
42
|
+
except Exception as e:
|
|
43
|
+
return {
|
|
44
|
+
"success": False,
|
|
45
|
+
"error": str(e),
|
|
46
|
+
"description": description,
|
|
47
|
+
"subagent_type": subagent_type,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async def _validate_stage_request(context, rate_limiter) -> str | None:
|
|
52
|
+
if not context:
|
|
53
|
+
return '{"error": "Server context not available", "success": false}'
|
|
54
|
+
|
|
55
|
+
# Skip rate limiting if not configured
|
|
56
|
+
if rate_limiter and hasattr(rate_limiter, "check_request_allowed"):
|
|
57
|
+
allowed, details = await rate_limiter.check_request_allowed()
|
|
58
|
+
if not allowed:
|
|
59
|
+
return f'{{"error": "Rate limit exceeded: {details.get("reason", "unknown")}", "success": false}}'
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _parse_stage_args(args: str, kwargs: str) -> tuple[str, dict] | str:
|
|
64
|
+
stage = args.strip().lower()
|
|
65
|
+
valid_stages = {"fast", "comprehensive", "tests", "cleaning", "init"}
|
|
66
|
+
|
|
67
|
+
if stage not in valid_stages:
|
|
68
|
+
return f'{{"error": "Invalid stage: {stage}. Valid stages: {valid_stages}", "success": false}}'
|
|
69
|
+
|
|
70
|
+
import json
|
|
71
|
+
|
|
72
|
+
extra_kwargs = {}
|
|
73
|
+
if kwargs.strip():
|
|
74
|
+
try:
|
|
75
|
+
extra_kwargs = json.loads(kwargs)
|
|
76
|
+
except json.JSONDecodeError as e:
|
|
77
|
+
return f'{{"error": "Invalid JSON in kwargs: {e}", "success": false}}'
|
|
78
|
+
|
|
79
|
+
return stage, extra_kwargs
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _configure_stage_options(stage: str) -> "WorkflowOptions":
|
|
83
|
+
from crackerjack.models.config import WorkflowOptions
|
|
84
|
+
|
|
85
|
+
options = WorkflowOptions()
|
|
86
|
+
if stage in {"fast", "comprehensive"}:
|
|
87
|
+
options.skip_hooks = False
|
|
88
|
+
elif stage == "tests":
|
|
89
|
+
options.testing.test = True
|
|
90
|
+
elif stage == "cleaning":
|
|
91
|
+
options.cleaning.clean = True
|
|
92
|
+
elif stage == "init":
|
|
93
|
+
# Init stage doesn't use standard workflow options
|
|
94
|
+
options.skip_hooks = True
|
|
95
|
+
return options
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _execute_stage(orchestrator, stage: str, options) -> bool:
|
|
99
|
+
if stage == "fast":
|
|
100
|
+
return orchestrator.run_fast_hooks_only(options)
|
|
101
|
+
if stage == "comprehensive":
|
|
102
|
+
return orchestrator.run_comprehensive_hooks_only(options)
|
|
103
|
+
if stage == "tests":
|
|
104
|
+
return orchestrator.run_testing_phase(options)
|
|
105
|
+
if stage == "cleaning":
|
|
106
|
+
return orchestrator.run_cleaning_phase(options)
|
|
107
|
+
if stage == "init":
|
|
108
|
+
return _execute_init_stage(orchestrator)
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _execute_init_stage(orchestrator) -> bool:
|
|
113
|
+
"""Execute project initialization stage."""
|
|
114
|
+
try:
|
|
115
|
+
from pathlib import Path
|
|
116
|
+
|
|
117
|
+
from crackerjack.services.filesystem import FileSystemService
|
|
118
|
+
from crackerjack.services.git import GitService
|
|
119
|
+
from crackerjack.services.initialization import InitializationService
|
|
120
|
+
|
|
121
|
+
# Get orchestrator dependencies
|
|
122
|
+
console = orchestrator.console
|
|
123
|
+
pkg_path = orchestrator.pkg_path
|
|
124
|
+
|
|
125
|
+
# Create service dependencies
|
|
126
|
+
filesystem = FileSystemService()
|
|
127
|
+
git_service = GitService(console, pkg_path)
|
|
128
|
+
|
|
129
|
+
# Initialize the service
|
|
130
|
+
init_service = InitializationService(console, filesystem, git_service, pkg_path)
|
|
131
|
+
|
|
132
|
+
# Run initialization in current directory
|
|
133
|
+
results = init_service.initialize_project(target_path=Path.cwd())
|
|
134
|
+
|
|
135
|
+
return results.get("success", False)
|
|
136
|
+
|
|
137
|
+
except Exception as e:
|
|
138
|
+
if hasattr(orchestrator, "console"):
|
|
139
|
+
orchestrator.console.print(f"[red]โ[/red] Initialization failed: {e}")
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def register_core_tools(mcp_app: t.Any) -> None:
|
|
144
|
+
@mcp_app.tool()
|
|
145
|
+
async def run_crackerjack_stage(args: str, kwargs: str) -> str:
|
|
146
|
+
context = get_context()
|
|
147
|
+
rate_limiter = context.rate_limiter if context else None
|
|
148
|
+
|
|
149
|
+
validation_error = await _validate_stage_request(context, rate_limiter)
|
|
150
|
+
if validation_error:
|
|
151
|
+
return validation_error
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
from crackerjack.core.workflow_orchestrator import WorkflowOrchestrator
|
|
155
|
+
|
|
156
|
+
parse_result = _parse_stage_args(args, kwargs)
|
|
157
|
+
if isinstance(parse_result, str):
|
|
158
|
+
return parse_result
|
|
159
|
+
|
|
160
|
+
stage, extra_kwargs = parse_result
|
|
161
|
+
|
|
162
|
+
orchestrator = WorkflowOrchestrator(
|
|
163
|
+
console=context.console,
|
|
164
|
+
pkg_path=context.config.project_path,
|
|
165
|
+
dry_run=extra_kwargs.get("dry_run", False),
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
options = _configure_stage_options(stage)
|
|
169
|
+
success = _execute_stage(orchestrator, stage, options)
|
|
170
|
+
|
|
171
|
+
return f'{{"success": {str(success).lower()}, "stage": "{stage}"}}'
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
context.safe_print(f"Error executing stage {args}: {e}")
|
|
175
|
+
return f'{{"error": "Stage execution failed: {e}", "success": false}}'
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _get_error_patterns() -> list[tuple[str, str]]:
|
|
179
|
+
return [
|
|
180
|
+
("type_error", r"TypeError:|type object .* has no attribute"),
|
|
181
|
+
("import_error", r"ImportError:|ModuleNotFoundError:"),
|
|
182
|
+
("attribute_error", r"AttributeError: "),
|
|
183
|
+
("syntax_error", r"SyntaxError:|invalid syntax"),
|
|
184
|
+
("test_failure", r"FAILED|AssertionError:"),
|
|
185
|
+
("hook_failure", r"hook .* failed"),
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _get_error_suggestion(error_type: str) -> str:
|
|
190
|
+
suggestions = {
|
|
191
|
+
"type_error": "Check type annotations and ensure proper imports",
|
|
192
|
+
"import_error": "Verify module exists and is properly installed",
|
|
193
|
+
"test_failure": "Review test assertions and expected behavior",
|
|
194
|
+
"hook_failure": "Run hooks individually to identify specific failures",
|
|
195
|
+
}
|
|
196
|
+
return suggestions.get(error_type) or "No specific suggestion available"
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _detect_errors_and_suggestions(
|
|
200
|
+
text: str,
|
|
201
|
+
include_suggestions: bool,
|
|
202
|
+
) -> tuple[list[str], list[str]]:
|
|
203
|
+
import re
|
|
204
|
+
|
|
205
|
+
detected_errors = []
|
|
206
|
+
suggestions = []
|
|
207
|
+
|
|
208
|
+
for error_type, pattern in _get_error_patterns():
|
|
209
|
+
if re.search(pattern, text, re.IGNORECASE):
|
|
210
|
+
detected_errors.append(error_type)
|
|
211
|
+
if include_suggestions:
|
|
212
|
+
suggestions.append(_get_error_suggestion(error_type))
|
|
213
|
+
|
|
214
|
+
return detected_errors, suggestions
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def register_analyze_errors_tool(mcp_app: t.Any) -> None:
|
|
218
|
+
@mcp_app.tool()
|
|
219
|
+
async def analyze_errors(output: str = "", include_suggestions: bool = True) -> str:
|
|
220
|
+
context = get_context()
|
|
221
|
+
if not context:
|
|
222
|
+
return '{"error": "Server context not available"}'
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
from crackerjack.services.debug import get_ai_agent_debugger
|
|
226
|
+
|
|
227
|
+
debugger = get_ai_agent_debugger()
|
|
228
|
+
if not debugger.enabled:
|
|
229
|
+
return '{"analysis": "Debugging not enabled", "suggestions": []}'
|
|
230
|
+
|
|
231
|
+
analysis_text = output or "No specific output provided"
|
|
232
|
+
detected_errors, suggestions = _detect_errors_and_suggestions(
|
|
233
|
+
analysis_text,
|
|
234
|
+
include_suggestions,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
result = {
|
|
238
|
+
"analysis": f"Detected {len(detected_errors)} error types",
|
|
239
|
+
"error_types": detected_errors,
|
|
240
|
+
"suggestions": suggestions if include_suggestions else [],
|
|
241
|
+
"raw_output_length": len(analysis_text),
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
import json
|
|
245
|
+
|
|
246
|
+
return json.dumps(result, indent=2)
|
|
247
|
+
|
|
248
|
+
except Exception as e:
|
|
249
|
+
return f'{{"error": "Error analysis failed: {e}"}}'
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""Error analysis and pattern detection for MCP tools.
|
|
2
|
+
|
|
3
|
+
This module handles intelligent error analysis, pattern caching, and diagnostic
|
|
4
|
+
recommendations. Split from execution_tools.py for better separation of concerns.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import typing as t
|
|
8
|
+
from contextlib import suppress
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def analyze_errors_with_caching(
|
|
12
|
+
context: t.Any, use_cache: bool = True
|
|
13
|
+
) -> dict[str, t.Any]:
|
|
14
|
+
"""Analyze errors with intelligent caching and pattern detection."""
|
|
15
|
+
try:
|
|
16
|
+
cached_patterns = _get_cached_patterns(context, use_cache)
|
|
17
|
+
return _build_error_analysis(cached_patterns, context)
|
|
18
|
+
|
|
19
|
+
except Exception as e:
|
|
20
|
+
return {
|
|
21
|
+
"status": "error",
|
|
22
|
+
"message": f"Error analysis failed: {e}",
|
|
23
|
+
"recommendations": [],
|
|
24
|
+
"patterns": [],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _get_cached_patterns(context: t.Any, use_cache: bool) -> list[t.Any]:
|
|
29
|
+
"""Get cached error patterns from context."""
|
|
30
|
+
if not use_cache:
|
|
31
|
+
return []
|
|
32
|
+
|
|
33
|
+
with suppress(Exception):
|
|
34
|
+
cache = getattr(context, "cache", None)
|
|
35
|
+
if cache and hasattr(cache, "get_error_patterns"):
|
|
36
|
+
return cache.get_error_patterns()
|
|
37
|
+
|
|
38
|
+
return []
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _build_error_analysis(patterns: list[t.Any], context: t.Any) -> dict[str, t.Any]:
|
|
42
|
+
"""Build comprehensive error analysis from patterns."""
|
|
43
|
+
analysis = {
|
|
44
|
+
"status": "success",
|
|
45
|
+
"patterns_found": len(patterns),
|
|
46
|
+
"recommendations": [],
|
|
47
|
+
"error_categories": {},
|
|
48
|
+
"fix_suggestions": [],
|
|
49
|
+
"urgency_level": "low",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if not patterns:
|
|
53
|
+
analysis.update(
|
|
54
|
+
{
|
|
55
|
+
"message": "No cached error patterns found - this indicates clean execution history",
|
|
56
|
+
"recommendations": [
|
|
57
|
+
"Continue with current development practices",
|
|
58
|
+
"Consider running comprehensive quality checks if issues arise",
|
|
59
|
+
],
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
return analysis
|
|
63
|
+
|
|
64
|
+
# Categorize error patterns
|
|
65
|
+
categories = _categorize_error_patterns(patterns)
|
|
66
|
+
analysis["error_categories"] = categories
|
|
67
|
+
|
|
68
|
+
# Generate recommendations
|
|
69
|
+
recommendations = _generate_error_recommendations(categories)
|
|
70
|
+
analysis["recommendations"] = recommendations
|
|
71
|
+
|
|
72
|
+
# Determine urgency
|
|
73
|
+
analysis["urgency_level"] = _calculate_urgency_level(categories)
|
|
74
|
+
|
|
75
|
+
# Generate fix suggestions
|
|
76
|
+
analysis["fix_suggestions"] = _generate_fix_suggestions(categories)
|
|
77
|
+
|
|
78
|
+
analysis["message"] = (
|
|
79
|
+
f"Found {len(patterns)} cached error patterns across {len(categories)} categories"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return analysis
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _categorize_error_patterns(patterns: list[t.Any]) -> dict[str, list[t.Any]]:
|
|
86
|
+
"""Categorize error patterns by type."""
|
|
87
|
+
categories = {
|
|
88
|
+
"syntax_errors": [],
|
|
89
|
+
"import_errors": [],
|
|
90
|
+
"type_errors": [],
|
|
91
|
+
"test_failures": [],
|
|
92
|
+
"security_issues": [],
|
|
93
|
+
"complexity_issues": [],
|
|
94
|
+
"dependency_issues": [],
|
|
95
|
+
"formatting_issues": [],
|
|
96
|
+
"unknown": [],
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for pattern in patterns:
|
|
100
|
+
category = _classify_error_pattern(pattern)
|
|
101
|
+
categories[category].append(pattern)
|
|
102
|
+
|
|
103
|
+
# Remove empty categories
|
|
104
|
+
return {k: v for k, v in categories.items() if v}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _classify_error_pattern(pattern: t.Any) -> str:
|
|
108
|
+
"""Classify a single error pattern into a category."""
|
|
109
|
+
# Convert pattern to string for analysis
|
|
110
|
+
pattern_str = str(pattern).lower()
|
|
111
|
+
|
|
112
|
+
if any(
|
|
113
|
+
keyword in pattern_str
|
|
114
|
+
for keyword in ("syntax", "invalid syntax", "unexpected token")
|
|
115
|
+
):
|
|
116
|
+
return "syntax_errors"
|
|
117
|
+
elif any(
|
|
118
|
+
keyword in pattern_str for keyword in ("import", "module", "no module named")
|
|
119
|
+
):
|
|
120
|
+
return "import_errors"
|
|
121
|
+
elif any(
|
|
122
|
+
keyword in pattern_str for keyword in ("type", "annotation", "mypy", "pyright")
|
|
123
|
+
):
|
|
124
|
+
return "type_errors"
|
|
125
|
+
elif any(
|
|
126
|
+
keyword in pattern_str for keyword in ("test", "assert", "pytest", "failed")
|
|
127
|
+
):
|
|
128
|
+
return "test_failures"
|
|
129
|
+
elif any(
|
|
130
|
+
keyword in pattern_str for keyword in ("security", "bandit", "vulnerability")
|
|
131
|
+
):
|
|
132
|
+
return "security_issues"
|
|
133
|
+
elif any(
|
|
134
|
+
keyword in pattern_str for keyword in ("complexity", "complex", "cognitive")
|
|
135
|
+
):
|
|
136
|
+
return "complexity_issues"
|
|
137
|
+
elif any(
|
|
138
|
+
keyword in pattern_str for keyword in ("dependency", "requirement", "package")
|
|
139
|
+
):
|
|
140
|
+
return "dependency_issues"
|
|
141
|
+
elif any(
|
|
142
|
+
keyword in pattern_str for keyword in ("format", "style", "ruff", "black")
|
|
143
|
+
):
|
|
144
|
+
return "formatting_issues"
|
|
145
|
+
return "unknown"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _generate_error_recommendations(categories: dict[str, list[t.Any]]) -> list[str]:
|
|
149
|
+
"""Generate actionable recommendations based on error categories."""
|
|
150
|
+
recommendations = []
|
|
151
|
+
|
|
152
|
+
if categories.get("syntax_errors"):
|
|
153
|
+
recommendations.append(
|
|
154
|
+
"๐ง Review syntax errors and fix basic Python syntax issues"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if categories.get("import_errors"):
|
|
158
|
+
recommendations.extend(
|
|
159
|
+
[
|
|
160
|
+
"๐ฆ Check imports and module dependencies",
|
|
161
|
+
"๐ Verify all required packages are installed",
|
|
162
|
+
]
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if categories.get("type_errors"):
|
|
166
|
+
recommendations.extend(
|
|
167
|
+
[
|
|
168
|
+
"๐ท๏ธ Add missing type annotations",
|
|
169
|
+
"๐ง Fix type mismatches and annotation issues",
|
|
170
|
+
]
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
if categories.get("test_failures"):
|
|
174
|
+
recommendations.extend(
|
|
175
|
+
[
|
|
176
|
+
"๐งช Fix failing tests and improve test reliability",
|
|
177
|
+
"๐ฌ Review test fixtures and dependencies",
|
|
178
|
+
]
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
if categories.get("security_issues"):
|
|
182
|
+
recommendations.extend(
|
|
183
|
+
[
|
|
184
|
+
"๐ Address security vulnerabilities immediately",
|
|
185
|
+
"๐ก๏ธ Follow security best practices",
|
|
186
|
+
]
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if categories.get("complexity_issues"):
|
|
190
|
+
recommendations.extend(
|
|
191
|
+
[
|
|
192
|
+
"๐ Refactor complex functions to reduce cognitive load",
|
|
193
|
+
"๐ Break down large functions into smaller components",
|
|
194
|
+
]
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
if categories.get("dependency_issues"):
|
|
198
|
+
recommendations.extend(
|
|
199
|
+
[
|
|
200
|
+
"๐ Update dependency management",
|
|
201
|
+
"๐ Review and clean up requirements",
|
|
202
|
+
]
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
if categories.get("formatting_issues"):
|
|
206
|
+
recommendations.extend(
|
|
207
|
+
[
|
|
208
|
+
"๐
Apply code formatting and style fixes",
|
|
209
|
+
"๐ Ensure consistent code style",
|
|
210
|
+
]
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Add general recommendations
|
|
214
|
+
if len(categories) > 3:
|
|
215
|
+
recommendations.extend(
|
|
216
|
+
[
|
|
217
|
+
"๐ฏ Consider running AI agent auto-fixing for comprehensive resolution",
|
|
218
|
+
"๐ Monitor quality metrics to prevent regression",
|
|
219
|
+
]
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
return recommendations
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _calculate_urgency_level(categories: dict[str, list[t.Any]]) -> str:
|
|
226
|
+
"""Calculate urgency level based on error categories and counts."""
|
|
227
|
+
total_errors = sum(len(errors) for errors in categories.values())
|
|
228
|
+
|
|
229
|
+
# Security issues are always high priority
|
|
230
|
+
if categories.get("security_issues"):
|
|
231
|
+
return "high"
|
|
232
|
+
|
|
233
|
+
# Many test failures indicate critical issues
|
|
234
|
+
if categories.get("test_failures") and len(categories["test_failures"]) > 5:
|
|
235
|
+
return "high"
|
|
236
|
+
|
|
237
|
+
# Syntax errors block development
|
|
238
|
+
if categories.get("syntax_errors"):
|
|
239
|
+
return "medium"
|
|
240
|
+
|
|
241
|
+
# Large number of total errors
|
|
242
|
+
if total_errors > 20:
|
|
243
|
+
return "medium"
|
|
244
|
+
|
|
245
|
+
# Multiple categories indicate systemic issues
|
|
246
|
+
if len(categories) > 4:
|
|
247
|
+
return "medium"
|
|
248
|
+
|
|
249
|
+
return "low"
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _generate_fix_suggestions(
|
|
253
|
+
categories: dict[str, list[t.Any]],
|
|
254
|
+
) -> list[dict[str, str]]:
|
|
255
|
+
"""Generate specific fix suggestions with commands."""
|
|
256
|
+
suggestions = []
|
|
257
|
+
|
|
258
|
+
if categories.get("formatting_issues"):
|
|
259
|
+
suggestions.append(
|
|
260
|
+
{
|
|
261
|
+
"category": "formatting",
|
|
262
|
+
"action": "Run code formatting",
|
|
263
|
+
"command": "python -m crackerjack --skip-tests",
|
|
264
|
+
"description": "Fix formatting and style issues",
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
if categories.get("type_errors"):
|
|
269
|
+
suggestions.append(
|
|
270
|
+
{
|
|
271
|
+
"category": "types",
|
|
272
|
+
"action": "Fix type annotations",
|
|
273
|
+
"command": "python -m crackerjack --ai-agent",
|
|
274
|
+
"description": "Add missing type hints and resolve type conflicts",
|
|
275
|
+
}
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
if categories.get("test_failures"):
|
|
279
|
+
suggestions.append(
|
|
280
|
+
{
|
|
281
|
+
"category": "tests",
|
|
282
|
+
"action": "Fix test failures",
|
|
283
|
+
"command": "python -m crackerjack -t --ai-agent",
|
|
284
|
+
"description": "Run tests with AI auto-fixing enabled",
|
|
285
|
+
}
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if categories.get("security_issues"):
|
|
289
|
+
suggestions.append(
|
|
290
|
+
{
|
|
291
|
+
"category": "security",
|
|
292
|
+
"action": "Address security issues",
|
|
293
|
+
"command": "python -m crackerjack --ai-agent -t",
|
|
294
|
+
"description": "Fix security vulnerabilities with AI assistance",
|
|
295
|
+
}
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
if len(categories) > 3:
|
|
299
|
+
suggestions.append(
|
|
300
|
+
{
|
|
301
|
+
"category": "comprehensive",
|
|
302
|
+
"action": "Full quality check with AI fixing",
|
|
303
|
+
"command": "python -m crackerjack --ai-agent -t",
|
|
304
|
+
"description": "Comprehensive quality check with autonomous fixing",
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
return suggestions
|