crackerjack 0.38.15__py3-none-any.whl → 0.39.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.

Files changed (37) hide show
  1. crackerjack/__main__.py +134 -13
  2. crackerjack/agents/__init__.py +2 -0
  3. crackerjack/agents/base.py +1 -0
  4. crackerjack/agents/claude_code_bridge.py +319 -0
  5. crackerjack/agents/coordinator.py +6 -3
  6. crackerjack/agents/dry_agent.py +187 -3
  7. crackerjack/agents/enhanced_coordinator.py +279 -0
  8. crackerjack/agents/enhanced_proactive_agent.py +185 -0
  9. crackerjack/agents/performance_agent.py +324 -3
  10. crackerjack/agents/refactoring_agent.py +254 -5
  11. crackerjack/agents/semantic_agent.py +479 -0
  12. crackerjack/agents/semantic_helpers.py +356 -0
  13. crackerjack/cli/options.py +27 -0
  14. crackerjack/cli/semantic_handlers.py +290 -0
  15. crackerjack/core/async_workflow_orchestrator.py +9 -8
  16. crackerjack/core/enhanced_container.py +1 -1
  17. crackerjack/core/phase_coordinator.py +1 -1
  18. crackerjack/core/proactive_workflow.py +1 -1
  19. crackerjack/core/workflow_orchestrator.py +9 -6
  20. crackerjack/documentation/ai_templates.py +1 -1
  21. crackerjack/interactive.py +1 -1
  22. crackerjack/mcp/server_core.py +2 -0
  23. crackerjack/mcp/tools/__init__.py +2 -0
  24. crackerjack/mcp/tools/semantic_tools.py +584 -0
  25. crackerjack/models/semantic_models.py +271 -0
  26. crackerjack/plugins/loader.py +2 -2
  27. crackerjack/py313.py +4 -1
  28. crackerjack/services/embeddings.py +444 -0
  29. crackerjack/services/quality_intelligence.py +11 -1
  30. crackerjack/services/smart_scheduling.py +1 -1
  31. crackerjack/services/vector_store.py +681 -0
  32. crackerjack/slash_commands/run.md +84 -50
  33. {crackerjack-0.38.15.dist-info → crackerjack-0.39.1.dist-info}/METADATA +7 -2
  34. {crackerjack-0.38.15.dist-info → crackerjack-0.39.1.dist-info}/RECORD +37 -27
  35. {crackerjack-0.38.15.dist-info → crackerjack-0.39.1.dist-info}/WHEEL +0 -0
  36. {crackerjack-0.38.15.dist-info → crackerjack-0.39.1.dist-info}/entry_points.txt +0 -0
  37. {crackerjack-0.38.15.dist-info → crackerjack-0.39.1.dist-info}/licenses/LICENSE +0 -0
@@ -4,12 +4,18 @@ from pathlib import Path
4
4
 
5
5
  from ..services.regex_patterns import SAFE_PATTERNS
6
6
  from .base import (
7
+ AgentContext,
7
8
  FixResult,
8
9
  Issue,
9
10
  IssueType,
10
11
  SubAgent,
11
12
  agent_registry,
12
13
  )
14
+ from .semantic_helpers import (
15
+ SemanticInsight,
16
+ create_semantic_enhancer,
17
+ get_session_enhanced_recommendations,
18
+ )
13
19
 
14
20
  if t.TYPE_CHECKING:
15
21
  from .refactoring_helpers import (
@@ -20,6 +26,11 @@ if t.TYPE_CHECKING:
20
26
 
21
27
 
22
28
  class RefactoringAgent(SubAgent):
29
+ def __init__(self, context: AgentContext) -> None:
30
+ super().__init__(context)
31
+ self.semantic_enhancer = create_semantic_enhancer(context.project_path)
32
+ self.semantic_insights: dict[str, SemanticInsight] = {}
33
+
23
34
  def get_supported_types(self) -> set[IssueType]:
24
35
  return {IssueType.COMPLEXITY, IssueType.DEAD_CODE}
25
36
 
@@ -126,7 +137,9 @@ class RefactoringAgent(SubAgent):
126
137
  "Applied proven complexity reduction pattern for detect_agent_needs"
127
138
  ],
128
139
  files_modified=[str(file_path)],
129
- recommendations=["Verify functionality after complexity reduction"],
140
+ recommendations=await self._enhance_recommendations_with_semantic(
141
+ ["Verify functionality after complexity reduction"]
142
+ ),
130
143
  )
131
144
  else:
132
145
  return FixResult(
@@ -178,6 +191,13 @@ class RefactoringAgent(SubAgent):
178
191
  tree = ast.parse(content)
179
192
  complex_functions = self._find_complex_functions(tree, content)
180
193
 
194
+ # Enhance complex function detection with semantic analysis
195
+ semantic_complex_functions = await self._find_semantic_complex_patterns(
196
+ content, file_path
197
+ )
198
+ if semantic_complex_functions:
199
+ complex_functions.extend(semantic_complex_functions)
200
+
181
201
  if not complex_functions:
182
202
  return FixResult(
183
203
  success=True,
@@ -185,9 +205,11 @@ class RefactoringAgent(SubAgent):
185
205
  recommendations=["No overly complex functions found"],
186
206
  )
187
207
 
188
- return self._apply_and_save_refactoring(file_path, content, complex_functions)
208
+ return await self._apply_and_save_refactoring(
209
+ file_path, content, complex_functions
210
+ )
189
211
 
190
- def _apply_and_save_refactoring(
212
+ async def _apply_and_save_refactoring(
191
213
  self,
192
214
  file_path: Path,
193
215
  content: str,
@@ -214,7 +236,9 @@ class RefactoringAgent(SubAgent):
214
236
  confidence=0.8,
215
237
  fixes_applied=[f"Reduced complexity in {len(complex_functions)} functions"],
216
238
  files_modified=[str(file_path)],
217
- recommendations=["Verify functionality after complexity reduction"],
239
+ recommendations=await self._enhance_recommendations_with_semantic(
240
+ ["Verify functionality after complexity reduction"]
241
+ ),
218
242
  )
219
243
 
220
244
  def _create_no_changes_result(self) -> FixResult:
@@ -852,7 +876,7 @@ class RefactoringAgent(SubAgent):
852
876
  def _collect_all_removable_lines(
853
877
  self, lines: list[str], analysis: dict[str, t.Any]
854
878
  ) -> set[int]:
855
- removal_functions = [
879
+ removal_functions: list[t.Callable[[], set[int]]] = [
856
880
  lambda: self._find_lines_to_remove(lines, analysis),
857
881
  lambda: self._find_unreachable_lines(lines, analysis),
858
882
  lambda: self._find_redundant_lines(lines, analysis),
@@ -1006,5 +1030,230 @@ class RefactoringAgent(SubAgent):
1006
1030
  return i
1007
1031
  return len(lines)
1008
1032
 
1033
+ async def _find_semantic_complex_patterns(
1034
+ self, content: str, file_path: Path
1035
+ ) -> list[dict[str, t.Any]]:
1036
+ """Find semantically complex patterns using vector similarity."""
1037
+ semantic_functions = []
1038
+
1039
+ try:
1040
+ # Extract code functions for semantic complexity analysis
1041
+ code_elements = self._extract_code_functions_for_semantic_analysis(content)
1042
+
1043
+ for element in code_elements:
1044
+ if (
1045
+ element["type"] == "function"
1046
+ and element["estimated_complexity"] > 10
1047
+ ):
1048
+ # Search for similar complex patterns
1049
+ insight = (
1050
+ await self.semantic_enhancer.find_refactoring_opportunities(
1051
+ element["signature"]
1052
+ + "\n"
1053
+ + element["body"][:150], # Include body sample
1054
+ current_file=file_path,
1055
+ )
1056
+ )
1057
+
1058
+ if insight.total_matches > 2:
1059
+ semantic_functions.append(
1060
+ {
1061
+ "name": element["name"],
1062
+ "line_start": element["start_line"],
1063
+ "line_end": element["end_line"],
1064
+ "complexity": element["estimated_complexity"],
1065
+ "semantic_matches": insight.total_matches,
1066
+ "refactor_opportunities": insight.related_patterns[
1067
+ :3
1068
+ ], # Top 3 matches
1069
+ "node": element.get("node"),
1070
+ }
1071
+ )
1072
+
1073
+ # Store insight for recommendation enhancement
1074
+ self.semantic_insights[element["name"]] = insight
1075
+
1076
+ except Exception as e:
1077
+ self.log(f"Warning: Semantic complexity detection failed: {e}")
1078
+
1079
+ return semantic_functions
1080
+
1081
+ def _extract_code_functions_for_semantic_analysis(
1082
+ self, content: str
1083
+ ) -> list[dict[str, t.Any]]:
1084
+ """Extract functions with complexity estimation for semantic analysis."""
1085
+ functions: list[dict[str, t.Any]] = []
1086
+ lines = content.split("\n")
1087
+ current_function = None
1088
+
1089
+ for i, line in enumerate(lines):
1090
+ stripped = line.strip()
1091
+
1092
+ if self._should_skip_semantic_line(stripped, current_function, line):
1093
+ continue
1094
+
1095
+ indent = len(line) - len(line.lstrip())
1096
+
1097
+ if self._is_semantic_function_definition(stripped):
1098
+ current_function = self._handle_semantic_function_definition(
1099
+ functions, current_function, stripped, indent, i
1100
+ )
1101
+ elif current_function:
1102
+ current_function = self._handle_semantic_function_body_line(
1103
+ functions, current_function, line, stripped, indent, i
1104
+ )
1105
+
1106
+ # Add last function if exists
1107
+ if current_function:
1108
+ current_function["end_line"] = len(lines)
1109
+ current_function["estimated_complexity"] = (
1110
+ self._estimate_function_complexity(current_function["body"])
1111
+ )
1112
+ functions.append(current_function)
1113
+
1114
+ return functions
1115
+
1116
+ def _estimate_function_complexity(self, function_body: str) -> int:
1117
+ """Estimate function complexity based on code patterns."""
1118
+ if not function_body:
1119
+ return 0
1120
+
1121
+ complexity_score = 1 # Base complexity
1122
+ lines = function_body.split("\n")
1123
+
1124
+ for line in lines:
1125
+ stripped = line.strip()
1126
+ # Control flow statements increase complexity
1127
+ if any(
1128
+ stripped.startswith(keyword)
1129
+ for keyword in ("if ", "elif ", "for ", "while ", "try:", "except")
1130
+ ):
1131
+ complexity_score += 1
1132
+ # Nested structures
1133
+ indent_level = len(line) - len(line.lstrip())
1134
+ if indent_level > 8: # Deeply nested
1135
+ complexity_score += 1
1136
+ # Complex conditions
1137
+ if " and " in stripped or " or " in stripped:
1138
+ complexity_score += 1
1139
+
1140
+ return complexity_score
1141
+
1142
+ async def _enhance_recommendations_with_semantic(
1143
+ self, base_recommendations: list[str]
1144
+ ) -> list[str]:
1145
+ """Enhance recommendations with semantic insights."""
1146
+ enhanced = base_recommendations.copy()
1147
+
1148
+ # Add semantic insights if available
1149
+ if self.semantic_insights:
1150
+ total_semantic_matches = sum(
1151
+ insight.total_matches for insight in self.semantic_insights.values()
1152
+ )
1153
+ high_conf_matches = sum(
1154
+ insight.high_confidence_matches
1155
+ for insight in self.semantic_insights.values()
1156
+ )
1157
+
1158
+ if high_conf_matches > 0:
1159
+ enhanced.append(
1160
+ f"Semantic analysis found {high_conf_matches} similar complex patterns - "
1161
+ f"consider extracting common refactoring utilities"
1162
+ )
1163
+
1164
+ if total_semantic_matches >= 3:
1165
+ enhanced.append(
1166
+ f"Found {total_semantic_matches} related complexity patterns across codebase - "
1167
+ f"review for consistent refactoring approach"
1168
+ )
1169
+
1170
+ # Store insights for session continuity
1171
+ for func_name, insight in self.semantic_insights.items():
1172
+ summary = self.semantic_enhancer.get_semantic_context_summary(insight)
1173
+ self.log(f"Semantic context for {func_name}: {summary}")
1174
+ await self.semantic_enhancer.store_insight_to_session(
1175
+ insight, "RefactoringAgent"
1176
+ )
1177
+
1178
+ # Enhance with session-stored insights
1179
+ enhanced = await get_session_enhanced_recommendations(
1180
+ enhanced, "RefactoringAgent", self.context.project_path
1181
+ )
1182
+
1183
+ return enhanced
1184
+
1185
+ def _should_skip_semantic_line(
1186
+ self, stripped: str, current_function: dict[str, t.Any] | None, line: str
1187
+ ) -> bool:
1188
+ """Check if line should be skipped during semantic function extraction."""
1189
+ if not stripped or stripped.startswith("#"):
1190
+ if current_function:
1191
+ current_function["body"] += line + "\n"
1192
+ return True
1193
+ return False
1194
+
1195
+ def _is_semantic_function_definition(self, stripped: str) -> bool:
1196
+ """Check if line is a function definition for semantic analysis."""
1197
+ return stripped.startswith("def ") and "(" in stripped
1198
+
1199
+ def _handle_semantic_function_definition(
1200
+ self,
1201
+ functions: list[dict[str, t.Any]],
1202
+ current_function: dict[str, t.Any] | None,
1203
+ stripped: str,
1204
+ indent: int,
1205
+ line_index: int,
1206
+ ) -> dict[str, t.Any]:
1207
+ """Handle a new function definition for semantic analysis."""
1208
+ # Save previous function if exists
1209
+ if current_function:
1210
+ current_function["end_line"] = line_index
1211
+ current_function["estimated_complexity"] = (
1212
+ self._estimate_function_complexity(current_function["body"])
1213
+ )
1214
+ functions.append(current_function)
1215
+
1216
+ func_name = stripped.split("(")[0].replace("def ", "").strip()
1217
+ return {
1218
+ "type": "function",
1219
+ "name": func_name,
1220
+ "signature": stripped,
1221
+ "start_line": line_index + 1,
1222
+ "body": "",
1223
+ "indent_level": indent,
1224
+ }
1225
+
1226
+ def _handle_semantic_function_body_line(
1227
+ self,
1228
+ functions: list[dict[str, t.Any]],
1229
+ current_function: dict[str, t.Any],
1230
+ line: str,
1231
+ stripped: str,
1232
+ indent: int,
1233
+ line_index: int,
1234
+ ) -> dict[str, t.Any] | None:
1235
+ """Handle a line within a function body for semantic analysis."""
1236
+ # Check if we're still inside the function
1237
+ if self._is_semantic_line_inside_function(current_function, indent, stripped):
1238
+ current_function["body"] += line + "\n"
1239
+ return current_function
1240
+ else:
1241
+ # Function ended
1242
+ current_function["end_line"] = line_index
1243
+ current_function["estimated_complexity"] = (
1244
+ self._estimate_function_complexity(current_function["body"])
1245
+ )
1246
+ functions.append(current_function)
1247
+ return None
1248
+
1249
+ def _is_semantic_line_inside_function(
1250
+ self, current_function: dict[str, t.Any], indent: int, stripped: str
1251
+ ) -> bool:
1252
+ """Check if line is still inside the current function for semantic analysis."""
1253
+ return indent > current_function["indent_level"] or (
1254
+ indent == current_function["indent_level"]
1255
+ and stripped.startswith(('"', "'", "@"))
1256
+ )
1257
+
1009
1258
 
1010
1259
  agent_registry.register(RefactoringAgent)