crackerjack 0.38.14__py3-none-any.whl → 0.39.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.
Potentially problematic release.
This version of crackerjack might be problematic. Click here for more details.
- crackerjack/__main__.py +134 -13
- crackerjack/agents/__init__.py +2 -0
- crackerjack/agents/base.py +1 -0
- crackerjack/agents/claude_code_bridge.py +319 -0
- crackerjack/agents/coordinator.py +6 -3
- crackerjack/agents/dry_agent.py +187 -3
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/performance_agent.py +324 -3
- crackerjack/agents/refactoring_agent.py +254 -5
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/cli/options.py +27 -0
- crackerjack/cli/semantic_handlers.py +290 -0
- crackerjack/core/async_workflow_orchestrator.py +9 -8
- crackerjack/core/enhanced_container.py +1 -1
- crackerjack/core/phase_coordinator.py +1 -1
- crackerjack/core/proactive_workflow.py +1 -1
- crackerjack/core/workflow_orchestrator.py +9 -6
- crackerjack/documentation/ai_templates.py +1 -1
- crackerjack/interactive.py +1 -1
- crackerjack/mcp/server_core.py +2 -0
- crackerjack/mcp/tools/__init__.py +2 -0
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/models/semantic_models.py +271 -0
- crackerjack/plugins/loader.py +2 -2
- crackerjack/py313.py +4 -1
- crackerjack/services/embeddings.py +444 -0
- crackerjack/services/initialization.py +1 -1
- crackerjack/services/quality_intelligence.py +11 -1
- crackerjack/services/smart_scheduling.py +1 -1
- crackerjack/services/status_authentication.py +3 -3
- crackerjack/services/vector_store.py +681 -0
- crackerjack/slash_commands/run.md +84 -50
- {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/METADATA +7 -2
- {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/RECORD +39 -29
- {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/WHEEL +0 -0
- {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.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=
|
|
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(
|
|
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=
|
|
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)
|