crackerjack 0.30.3__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.

Files changed (155) hide show
  1. crackerjack/CLAUDE.md +1005 -0
  2. crackerjack/RULES.md +380 -0
  3. crackerjack/__init__.py +42 -13
  4. crackerjack/__main__.py +225 -299
  5. crackerjack/agents/__init__.py +41 -0
  6. crackerjack/agents/architect_agent.py +281 -0
  7. crackerjack/agents/base.py +169 -0
  8. crackerjack/agents/coordinator.py +512 -0
  9. crackerjack/agents/documentation_agent.py +498 -0
  10. crackerjack/agents/dry_agent.py +388 -0
  11. crackerjack/agents/formatting_agent.py +245 -0
  12. crackerjack/agents/import_optimization_agent.py +281 -0
  13. crackerjack/agents/performance_agent.py +669 -0
  14. crackerjack/agents/proactive_agent.py +104 -0
  15. crackerjack/agents/refactoring_agent.py +788 -0
  16. crackerjack/agents/security_agent.py +529 -0
  17. crackerjack/agents/test_creation_agent.py +652 -0
  18. crackerjack/agents/test_specialist_agent.py +486 -0
  19. crackerjack/agents/tracker.py +212 -0
  20. crackerjack/api.py +560 -0
  21. crackerjack/cli/__init__.py +24 -0
  22. crackerjack/cli/facade.py +104 -0
  23. crackerjack/cli/handlers.py +267 -0
  24. crackerjack/cli/interactive.py +471 -0
  25. crackerjack/cli/options.py +401 -0
  26. crackerjack/cli/utils.py +18 -0
  27. crackerjack/code_cleaner.py +618 -928
  28. crackerjack/config/__init__.py +19 -0
  29. crackerjack/config/hooks.py +218 -0
  30. crackerjack/core/__init__.py +0 -0
  31. crackerjack/core/async_workflow_orchestrator.py +406 -0
  32. crackerjack/core/autofix_coordinator.py +200 -0
  33. crackerjack/core/container.py +104 -0
  34. crackerjack/core/enhanced_container.py +542 -0
  35. crackerjack/core/performance.py +243 -0
  36. crackerjack/core/phase_coordinator.py +561 -0
  37. crackerjack/core/proactive_workflow.py +316 -0
  38. crackerjack/core/session_coordinator.py +289 -0
  39. crackerjack/core/workflow_orchestrator.py +640 -0
  40. crackerjack/dynamic_config.py +94 -103
  41. crackerjack/errors.py +263 -41
  42. crackerjack/executors/__init__.py +11 -0
  43. crackerjack/executors/async_hook_executor.py +431 -0
  44. crackerjack/executors/cached_hook_executor.py +242 -0
  45. crackerjack/executors/hook_executor.py +345 -0
  46. crackerjack/executors/individual_hook_executor.py +669 -0
  47. crackerjack/intelligence/__init__.py +44 -0
  48. crackerjack/intelligence/adaptive_learning.py +751 -0
  49. crackerjack/intelligence/agent_orchestrator.py +551 -0
  50. crackerjack/intelligence/agent_registry.py +414 -0
  51. crackerjack/intelligence/agent_selector.py +502 -0
  52. crackerjack/intelligence/integration.py +290 -0
  53. crackerjack/interactive.py +576 -315
  54. crackerjack/managers/__init__.py +11 -0
  55. crackerjack/managers/async_hook_manager.py +135 -0
  56. crackerjack/managers/hook_manager.py +137 -0
  57. crackerjack/managers/publish_manager.py +411 -0
  58. crackerjack/managers/test_command_builder.py +151 -0
  59. crackerjack/managers/test_executor.py +435 -0
  60. crackerjack/managers/test_manager.py +258 -0
  61. crackerjack/managers/test_manager_backup.py +1124 -0
  62. crackerjack/managers/test_progress.py +144 -0
  63. crackerjack/mcp/__init__.py +0 -0
  64. crackerjack/mcp/cache.py +336 -0
  65. crackerjack/mcp/client_runner.py +104 -0
  66. crackerjack/mcp/context.py +615 -0
  67. crackerjack/mcp/dashboard.py +636 -0
  68. crackerjack/mcp/enhanced_progress_monitor.py +479 -0
  69. crackerjack/mcp/file_monitor.py +336 -0
  70. crackerjack/mcp/progress_components.py +569 -0
  71. crackerjack/mcp/progress_monitor.py +949 -0
  72. crackerjack/mcp/rate_limiter.py +332 -0
  73. crackerjack/mcp/server.py +22 -0
  74. crackerjack/mcp/server_core.py +244 -0
  75. crackerjack/mcp/service_watchdog.py +501 -0
  76. crackerjack/mcp/state.py +395 -0
  77. crackerjack/mcp/task_manager.py +257 -0
  78. crackerjack/mcp/tools/__init__.py +17 -0
  79. crackerjack/mcp/tools/core_tools.py +249 -0
  80. crackerjack/mcp/tools/error_analyzer.py +308 -0
  81. crackerjack/mcp/tools/execution_tools.py +370 -0
  82. crackerjack/mcp/tools/execution_tools_backup.py +1097 -0
  83. crackerjack/mcp/tools/intelligence_tool_registry.py +80 -0
  84. crackerjack/mcp/tools/intelligence_tools.py +314 -0
  85. crackerjack/mcp/tools/monitoring_tools.py +502 -0
  86. crackerjack/mcp/tools/proactive_tools.py +384 -0
  87. crackerjack/mcp/tools/progress_tools.py +141 -0
  88. crackerjack/mcp/tools/utility_tools.py +341 -0
  89. crackerjack/mcp/tools/workflow_executor.py +360 -0
  90. crackerjack/mcp/websocket/__init__.py +14 -0
  91. crackerjack/mcp/websocket/app.py +39 -0
  92. crackerjack/mcp/websocket/endpoints.py +559 -0
  93. crackerjack/mcp/websocket/jobs.py +253 -0
  94. crackerjack/mcp/websocket/server.py +116 -0
  95. crackerjack/mcp/websocket/websocket_handler.py +78 -0
  96. crackerjack/mcp/websocket_server.py +10 -0
  97. crackerjack/models/__init__.py +31 -0
  98. crackerjack/models/config.py +93 -0
  99. crackerjack/models/config_adapter.py +230 -0
  100. crackerjack/models/protocols.py +118 -0
  101. crackerjack/models/task.py +154 -0
  102. crackerjack/monitoring/ai_agent_watchdog.py +450 -0
  103. crackerjack/monitoring/regression_prevention.py +638 -0
  104. crackerjack/orchestration/__init__.py +0 -0
  105. crackerjack/orchestration/advanced_orchestrator.py +970 -0
  106. crackerjack/orchestration/execution_strategies.py +341 -0
  107. crackerjack/orchestration/test_progress_streamer.py +636 -0
  108. crackerjack/plugins/__init__.py +15 -0
  109. crackerjack/plugins/base.py +200 -0
  110. crackerjack/plugins/hooks.py +246 -0
  111. crackerjack/plugins/loader.py +335 -0
  112. crackerjack/plugins/managers.py +259 -0
  113. crackerjack/py313.py +8 -3
  114. crackerjack/services/__init__.py +22 -0
  115. crackerjack/services/cache.py +314 -0
  116. crackerjack/services/config.py +347 -0
  117. crackerjack/services/config_integrity.py +99 -0
  118. crackerjack/services/contextual_ai_assistant.py +516 -0
  119. crackerjack/services/coverage_ratchet.py +347 -0
  120. crackerjack/services/debug.py +736 -0
  121. crackerjack/services/dependency_monitor.py +617 -0
  122. crackerjack/services/enhanced_filesystem.py +439 -0
  123. crackerjack/services/file_hasher.py +151 -0
  124. crackerjack/services/filesystem.py +395 -0
  125. crackerjack/services/git.py +165 -0
  126. crackerjack/services/health_metrics.py +611 -0
  127. crackerjack/services/initialization.py +847 -0
  128. crackerjack/services/log_manager.py +286 -0
  129. crackerjack/services/logging.py +174 -0
  130. crackerjack/services/metrics.py +578 -0
  131. crackerjack/services/pattern_cache.py +362 -0
  132. crackerjack/services/pattern_detector.py +515 -0
  133. crackerjack/services/performance_benchmarks.py +653 -0
  134. crackerjack/services/security.py +163 -0
  135. crackerjack/services/server_manager.py +234 -0
  136. crackerjack/services/smart_scheduling.py +144 -0
  137. crackerjack/services/tool_version_service.py +61 -0
  138. crackerjack/services/unified_config.py +437 -0
  139. crackerjack/services/version_checker.py +248 -0
  140. crackerjack/slash_commands/__init__.py +14 -0
  141. crackerjack/slash_commands/init.md +122 -0
  142. crackerjack/slash_commands/run.md +163 -0
  143. crackerjack/slash_commands/status.md +127 -0
  144. crackerjack-0.31.4.dist-info/METADATA +742 -0
  145. crackerjack-0.31.4.dist-info/RECORD +148 -0
  146. crackerjack-0.31.4.dist-info/entry_points.txt +2 -0
  147. crackerjack/.gitignore +0 -34
  148. crackerjack/.libcst.codemod.yaml +0 -18
  149. crackerjack/.pdm.toml +0 -1
  150. crackerjack/crackerjack.py +0 -3805
  151. crackerjack/pyproject.toml +0 -286
  152. crackerjack-0.30.3.dist-info/METADATA +0 -1290
  153. crackerjack-0.30.3.dist-info/RECORD +0 -16
  154. {crackerjack-0.30.3.dist-info โ†’ crackerjack-0.31.4.dist-info}/WHEEL +0 -0
  155. {crackerjack-0.30.3.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