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.

Files changed (39) 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/initialization.py +1 -1
  30. crackerjack/services/quality_intelligence.py +11 -1
  31. crackerjack/services/smart_scheduling.py +1 -1
  32. crackerjack/services/status_authentication.py +3 -3
  33. crackerjack/services/vector_store.py +681 -0
  34. crackerjack/slash_commands/run.md +84 -50
  35. {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/METADATA +7 -2
  36. {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/RECORD +39 -29
  37. {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/WHEEL +0 -0
  38. {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/entry_points.txt +0 -0
  39. {crackerjack-0.38.14.dist-info → crackerjack-0.39.0.dist-info}/licenses/LICENSE +0 -0
@@ -3,15 +3,32 @@ from pathlib import Path
3
3
 
4
4
  from ..services.regex_patterns import SAFE_PATTERNS
5
5
  from .base import (
6
+ AgentContext,
6
7
  FixResult,
7
8
  Issue,
8
9
  IssueType,
9
10
  SubAgent,
10
11
  agent_registry,
11
12
  )
13
+ from .semantic_helpers import (
14
+ SemanticInsight,
15
+ create_semantic_enhancer,
16
+ get_session_enhanced_recommendations,
17
+ )
12
18
 
13
19
 
14
20
  class DRYAgent(SubAgent):
21
+ """Agent for detecting and fixing DRY (Don't Repeat Yourself) violations.
22
+
23
+ Enhanced with semantic context to detect conceptual duplicates beyond
24
+ just syntactic pattern matching.
25
+ """
26
+
27
+ def __init__(self, context: AgentContext) -> None:
28
+ super().__init__(context)
29
+ self.semantic_enhancer = create_semantic_enhancer(context.project_path)
30
+ self.semantic_insights: dict[str, SemanticInsight] = {}
31
+
15
32
  def get_supported_types(self) -> set[IssueType]:
16
33
  return {IssueType.DRY_VIOLATION}
17
34
 
@@ -66,8 +83,13 @@ class DRYAgent(SubAgent):
66
83
  remaining_issues=[f"Could not read file: {file_path}"],
67
84
  )
68
85
 
86
+ # Detect traditional pattern-based violations
69
87
  violations = self._detect_dry_violations(content, file_path)
70
88
 
89
+ # Enhance with semantic duplicate detection
90
+ semantic_violations = await self._detect_semantic_violations(content, file_path)
91
+ violations.extend(semantic_violations)
92
+
71
93
  if not violations:
72
94
  return FixResult(
73
95
  success=True,
@@ -75,9 +97,9 @@ class DRYAgent(SubAgent):
75
97
  recommendations=["No DRY violations detected"],
76
98
  )
77
99
 
78
- return self._apply_and_save_dry_fixes(file_path, content, violations)
100
+ return await self._apply_and_save_dry_fixes(file_path, content, violations)
79
101
 
80
- def _apply_and_save_dry_fixes(
102
+ async def _apply_and_save_dry_fixes(
81
103
  self,
82
104
  file_path: Path,
83
105
  content: str,
@@ -96,6 +118,28 @@ class DRYAgent(SubAgent):
96
118
  remaining_issues=[f"Failed to write fixed file: {file_path}"],
97
119
  )
98
120
 
121
+ # Enhance recommendations with semantic insights and session continuity
122
+ recommendations = ["Verify functionality after DRY fixes"]
123
+ if hasattr(self, "current_semantic_insight") and self.current_semantic_insight:
124
+ recommendations = self.semantic_enhancer.enhance_recommendations(
125
+ recommendations, self.current_semantic_insight
126
+ )
127
+ # Log semantic context for debugging
128
+ summary = self.semantic_enhancer.get_semantic_context_summary(
129
+ self.current_semantic_insight
130
+ )
131
+ self.log(f"Semantic context: {summary}")
132
+
133
+ # Store insight for session continuity
134
+ await self.semantic_enhancer.store_insight_to_session(
135
+ self.current_semantic_insight, "DRYAgent"
136
+ )
137
+
138
+ # Enhance with session-stored insights
139
+ recommendations = await get_session_enhanced_recommendations(
140
+ recommendations, "DRYAgent", self.context.project_path
141
+ )
142
+
99
143
  return FixResult(
100
144
  success=True,
101
145
  confidence=0.8,
@@ -104,7 +148,7 @@ class DRYAgent(SubAgent):
104
148
  "Consolidated repetitive patterns",
105
149
  ],
106
150
  files_modified=[str(file_path)],
107
- recommendations=["Verify functionality after DRY fixes"],
151
+ recommendations=recommendations,
108
152
  )
109
153
 
110
154
  def _create_no_fixes_result(self) -> FixResult:
@@ -397,5 +441,145 @@ def _ensure_path(path: str | Path) -> Path:
397
441
 
398
442
  return modified
399
443
 
444
+ async def _detect_semantic_violations(
445
+ self, content: str, file_path: Path
446
+ ) -> list[dict[str, t.Any]]:
447
+ """Detect semantic code duplicates using vector similarity."""
448
+ violations = []
449
+
450
+ try:
451
+ # Extract key code functions for semantic analysis
452
+ code_elements = self._extract_code_functions(content)
453
+
454
+ for element in code_elements:
455
+ if element["type"] == "function" and len(element["body"]) > 50:
456
+ # Search for semantically similar functions
457
+ insight = await self.semantic_enhancer.find_duplicate_patterns(
458
+ element["signature"]
459
+ + "\n"
460
+ + element["body"][:200], # Include body sample
461
+ current_file=file_path,
462
+ )
463
+
464
+ if insight.high_confidence_matches > 0:
465
+ violations.append(
466
+ {
467
+ "type": "semantic_duplicate",
468
+ "element": element,
469
+ "similar_patterns": insight.related_patterns[
470
+ :3
471
+ ], # Top 3 matches
472
+ "confidence_score": insight.high_confidence_matches
473
+ / insight.total_matches
474
+ if insight.total_matches > 0
475
+ else 0,
476
+ "suggestion": "Consider extracting common functionality to shared utility",
477
+ }
478
+ )
479
+
480
+ # Store insight for recommendation enhancement
481
+ self.current_semantic_insight = insight
482
+
483
+ except Exception as e:
484
+ self.log(f"Warning: Semantic violation detection failed: {e}")
485
+
486
+ return violations
487
+
488
+ def _extract_code_functions(self, content: str) -> list[dict[str, t.Any]]:
489
+ """Extract functions from code for semantic analysis."""
490
+ functions: list[dict[str, t.Any]] = []
491
+ lines = content.split("\n")
492
+ current_function = None
493
+
494
+ for i, line in enumerate(lines):
495
+ stripped = line.strip()
496
+
497
+ if self._should_skip_line(stripped, current_function, line):
498
+ continue
499
+
500
+ indent = len(line) - len(line.lstrip())
501
+
502
+ if self._is_function_definition(stripped):
503
+ current_function = self._handle_function_definition(
504
+ functions, current_function, stripped, indent, i
505
+ )
506
+ elif current_function:
507
+ current_function = self._handle_function_body_line(
508
+ functions, current_function, line, stripped, indent, i
509
+ )
510
+
511
+ # Add last function if exists
512
+ if current_function:
513
+ current_function["end_line"] = len(lines)
514
+ functions.append(current_function)
515
+
516
+ return functions
517
+
518
+ def _should_skip_line(
519
+ self, stripped: str, current_function: dict[str, t.Any] | None, line: str
520
+ ) -> bool:
521
+ """Check if line should be skipped during function extraction."""
522
+ if not stripped or stripped.startswith("#"):
523
+ if current_function:
524
+ current_function["body"] += line + "\n"
525
+ return True
526
+ return False
527
+
528
+ def _is_function_definition(self, stripped: str) -> bool:
529
+ """Check if line is a function definition."""
530
+ return stripped.startswith("def ") and "(" in stripped
531
+
532
+ def _handle_function_definition(
533
+ self,
534
+ functions: list[dict[str, t.Any]],
535
+ current_function: dict[str, t.Any] | None,
536
+ stripped: str,
537
+ indent: int,
538
+ line_index: int,
539
+ ) -> dict[str, t.Any]:
540
+ """Handle a new function definition."""
541
+ # Save previous function if exists
542
+ if current_function:
543
+ functions.append(current_function)
544
+
545
+ func_name = stripped.split("(")[0].replace("def ", "").strip()
546
+ return {
547
+ "type": "function",
548
+ "name": func_name,
549
+ "signature": stripped,
550
+ "start_line": line_index + 1,
551
+ "body": "",
552
+ "indent_level": indent,
553
+ }
554
+
555
+ def _handle_function_body_line(
556
+ self,
557
+ functions: list[dict[str, t.Any]],
558
+ current_function: dict[str, t.Any],
559
+ line: str,
560
+ stripped: str,
561
+ indent: int,
562
+ line_index: int,
563
+ ) -> dict[str, t.Any] | None:
564
+ """Handle a line within a function body."""
565
+ # Check if we're still inside the function
566
+ if self._is_line_inside_function(current_function, indent, stripped):
567
+ current_function["body"] += line + "\n"
568
+ return current_function
569
+ else:
570
+ # Function ended
571
+ current_function["end_line"] = line_index
572
+ functions.append(current_function)
573
+ return None
574
+
575
+ def _is_line_inside_function(
576
+ self, current_function: dict[str, t.Any], indent: int, stripped: str
577
+ ) -> bool:
578
+ """Check if line is still inside the current function."""
579
+ return indent > current_function["indent_level"] or (
580
+ indent == current_function["indent_level"]
581
+ and stripped.startswith(('"', "'", "@"))
582
+ )
583
+
400
584
 
401
585
  agent_registry.register(DRYAgent)
@@ -0,0 +1,279 @@
1
+ """
2
+ Enhanced AgentCoordinator with Claude Code external agent integration.
3
+
4
+ This module extends the base AgentCoordinator to seamlessly integrate with
5
+ Claude Code's external agents while maintaining full compatibility with
6
+ the existing crackerjack agent system.
7
+ """
8
+
9
+ import typing as t
10
+
11
+ from .base import AgentContext, FixResult, Issue
12
+ from .claude_code_bridge import ClaudeCodeBridge
13
+ from .coordinator import AgentCoordinator
14
+
15
+
16
+ class EnhancedAgentCoordinator(AgentCoordinator):
17
+ """
18
+ AgentCoordinator enhanced with Claude Code external agent integration.
19
+
20
+ This coordinator maintains all the functionality of the base AgentCoordinator
21
+ while adding intelligent consultation with external Claude Code agents
22
+ when handling complex issues.
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ context: AgentContext,
28
+ cache: t.Any = None,
29
+ enable_external_agents: bool = True,
30
+ ) -> None:
31
+ super().__init__(context, cache)
32
+ self.claude_bridge = ClaudeCodeBridge(context)
33
+ self.external_agents_enabled = enable_external_agents
34
+ self._external_consultation_stats: dict[str, int] = {
35
+ "consultations_requested": 0,
36
+ "consultations_successful": 0,
37
+ "improvements_achieved": 0,
38
+ }
39
+
40
+ self.logger.info(
41
+ f"Enhanced coordinator initialized with external agents: {enable_external_agents}"
42
+ )
43
+
44
+ def enable_external_agents(self, enabled: bool = True) -> None:
45
+ """Enable or disable external Claude Code agent consultation."""
46
+ self.external_agents_enabled = enabled
47
+ self.logger.info(f"External agents {'enabled' if enabled else 'disabled'}")
48
+
49
+ def get_external_consultation_stats(self) -> dict[str, int]:
50
+ """Get statistics about external agent consultations."""
51
+ return self._external_consultation_stats.copy()
52
+
53
+ async def handle_issues_proactively(self, issues: list[Issue]) -> FixResult:
54
+ """
55
+ Enhanced proactive handling with external agent consultation.
56
+
57
+ This method extends the base proactive handling to:
58
+ 1. Identify issues that would benefit from external consultation
59
+ 2. Pre-consult with relevant Claude Code agents for strategic guidance
60
+ 3. Apply the combined internal/external strategy
61
+ """
62
+ if not self.external_agents_enabled:
63
+ return await super().handle_issues_proactively(issues)
64
+
65
+ if not self.agents:
66
+ self.initialize_agents()
67
+
68
+ if not issues:
69
+ return FixResult(success=True, confidence=1.0)
70
+
71
+ self.logger.info(f"Enhanced proactive handling of {len(issues)} issues")
72
+
73
+ # Pre-analyze issues for external consultation opportunities
74
+ strategic_consultations = await self._pre_consult_for_strategy(issues)
75
+
76
+ # Create enhanced architectural plan incorporating external guidance
77
+ architectural_plan = await self._create_enhanced_architectural_plan(
78
+ issues, strategic_consultations
79
+ )
80
+
81
+ # Apply fixes with enhanced strategy
82
+ overall_result = await self._apply_enhanced_fixes_with_plan(
83
+ issues, architectural_plan, strategic_consultations
84
+ )
85
+
86
+ # Post-process with external validation if needed
87
+ validated_result = await self._validate_with_external_agents(
88
+ overall_result, architectural_plan
89
+ )
90
+
91
+ self._update_consultation_stats(strategic_consultations, validated_result)
92
+
93
+ return validated_result
94
+
95
+ async def _pre_consult_for_strategy(self, issues: list[Issue]) -> dict[str, t.Any]:
96
+ """Pre-consult with external agents for strategic guidance."""
97
+ strategic_consultations: dict[str, t.Any] = {
98
+ "crackerjack_architect_guidance": None,
99
+ "specialist_recommendations": {},
100
+ "coordination_strategy": "internal_first",
101
+ }
102
+
103
+ # Identify complex issues that need architectural guidance
104
+ complex_issues = [
105
+ issue
106
+ for issue in issues
107
+ if self.claude_bridge.should_consult_external_agent(issue, 0.0)
108
+ ]
109
+
110
+ if not complex_issues:
111
+ return strategic_consultations
112
+
113
+ # Consult crackerjack-architect for overall strategy if available
114
+ if self.claude_bridge.verify_agent_availability("crackerjack-architect"):
115
+ self._external_consultation_stats["consultations_requested"] += 1
116
+
117
+ # Use the first complex issue as representative for strategic planning
118
+ primary_issue = complex_issues[0]
119
+ architect_consultation = await self.claude_bridge.consult_external_agent(
120
+ primary_issue,
121
+ "crackerjack-architect",
122
+ {"context": "strategic_planning"},
123
+ )
124
+
125
+ if architect_consultation.get("status") == "success":
126
+ strategic_consultations["crackerjack_architect_guidance"] = (
127
+ architect_consultation
128
+ )
129
+ strategic_consultations["coordination_strategy"] = "architect_guided"
130
+ self._external_consultation_stats["consultations_successful"] += 1
131
+
132
+ return strategic_consultations
133
+
134
+ async def _create_enhanced_architectural_plan(
135
+ self, issues: list[Issue], strategic_consultations: dict[str, t.Any]
136
+ ) -> dict[str, t.Any]:
137
+ """Create architectural plan enhanced with external agent guidance."""
138
+ # Start with the base architectural plan
139
+ base_plan = await self._create_architectural_plan(issues)
140
+
141
+ # Enhance with external guidance if available
142
+ architect_guidance = strategic_consultations.get(
143
+ "crackerjack_architect_guidance"
144
+ )
145
+ if architect_guidance and architect_guidance.get("status") == "success":
146
+ # Integrate external architectural guidance
147
+ base_plan["external_guidance"] = architect_guidance
148
+ base_plan["enhanced_patterns"] = architect_guidance.get("patterns", [])
149
+ base_plan["external_validation"] = architect_guidance.get(
150
+ "validation_steps", []
151
+ )
152
+
153
+ # Update strategy based on external guidance
154
+ if "strategy" in architect_guidance:
155
+ base_plan["strategy"] = "external_specialist_guided"
156
+
157
+ return base_plan
158
+
159
+ async def _apply_enhanced_fixes_with_plan(
160
+ self,
161
+ issues: list[Issue],
162
+ plan: dict[str, t.Any],
163
+ strategic_consultations: dict[str, t.Any],
164
+ ) -> FixResult:
165
+ """Apply fixes using enhanced strategy with external guidance."""
166
+ # Use the base implementation but with enhanced plan
167
+ return await self._apply_fixes_with_plan(issues, plan)
168
+
169
+ async def _validate_with_external_agents(
170
+ self, result: FixResult, plan: dict[str, t.Any]
171
+ ) -> FixResult:
172
+ """Post-validate results with external agents if configured."""
173
+ external_validation = plan.get("external_validation", [])
174
+
175
+ if not external_validation or not self.external_agents_enabled:
176
+ return result
177
+
178
+ # Add validation recommendations from external agents
179
+ validation_recommendations = [
180
+ f"External validation: {validation_step}"
181
+ for validation_step in external_validation
182
+ ]
183
+
184
+ enhanced_result = FixResult(
185
+ success=result.success,
186
+ confidence=min(
187
+ result.confidence + 0.1, 1.0
188
+ ), # Slight confidence boost for external validation
189
+ fixes_applied=result.fixes_applied.copy(),
190
+ remaining_issues=result.remaining_issues.copy(),
191
+ recommendations=result.recommendations + validation_recommendations,
192
+ files_modified=result.files_modified.copy(),
193
+ )
194
+
195
+ return enhanced_result
196
+
197
+ def _update_consultation_stats(
198
+ self, strategic_consultations: dict[str, t.Any], result: FixResult
199
+ ) -> None:
200
+ """Update statistics about external consultations."""
201
+ if strategic_consultations.get("crackerjack_architect_guidance"):
202
+ if result.success and result.confidence > 0.8:
203
+ self._external_consultation_stats["improvements_achieved"] += 1
204
+
205
+ async def _handle_with_single_agent_enhanced(
206
+ self, agent: t.Any, issue: Issue
207
+ ) -> FixResult:
208
+ """Enhanced single agent handling with external consultation."""
209
+ # Check if this agent should consult external experts
210
+ internal_result = await super()._handle_with_single_agent(agent, issue)
211
+
212
+ # If the agent is proactive and has external consultation capability, enhance it
213
+ if (
214
+ hasattr(agent, "claude_bridge")
215
+ and self.external_agents_enabled
216
+ and not internal_result.success
217
+ ):
218
+ # Try external consultation for failed fixes
219
+ recommended_agents = self.claude_bridge.get_recommended_external_agents(
220
+ issue
221
+ )
222
+ if recommended_agents:
223
+ self._external_consultation_stats["consultations_requested"] += 1
224
+
225
+ # Consult the top recommended external agent
226
+ consultation = await self.claude_bridge.consult_external_agent(
227
+ issue, recommended_agents[0]
228
+ )
229
+
230
+ if consultation.get("status") == "success":
231
+ self._external_consultation_stats["consultations_successful"] += 1
232
+ enhanced_result = self.claude_bridge.create_enhanced_fix_result(
233
+ internal_result, [consultation]
234
+ )
235
+ return enhanced_result
236
+
237
+ return internal_result
238
+
239
+ def get_enhanced_agent_capabilities(self) -> dict[str, dict[str, t.Any]]:
240
+ """Get capabilities including external agent integration."""
241
+ base_capabilities = self.get_agent_capabilities()
242
+
243
+ # Add information about external agent integration
244
+ enhanced_info = {
245
+ "external_agents_enabled": self.external_agents_enabled,
246
+ "available_external_agents": [
247
+ agent
248
+ for agent in (
249
+ "crackerjack-architect",
250
+ "python-pro",
251
+ "security-auditor",
252
+ "refactoring-specialist",
253
+ "crackerjack-test-specialist",
254
+ )
255
+ if self.claude_bridge.verify_agent_availability(agent)
256
+ ],
257
+ "consultation_stats": self.get_external_consultation_stats(),
258
+ "claude_code_bridge": {
259
+ "agent_mapping_coverage": len(self.claude_bridge._get_agent_mapping()),
260
+ "consultation_threshold": self.claude_bridge._get_consultation_threshold(),
261
+ },
262
+ }
263
+
264
+ return base_capabilities | {"_enhanced_coordinator_info": enhanced_info}
265
+
266
+
267
+ def create_enhanced_coordinator(
268
+ context: AgentContext, cache: t.Any = None, enable_external_agents: bool = True
269
+ ) -> EnhancedAgentCoordinator:
270
+ """
271
+ Factory function to create an enhanced coordinator.
272
+
273
+ This function provides a clean interface for creating coordinators
274
+ with external agent integration while maintaining compatibility
275
+ with existing code.
276
+ """
277
+ return EnhancedAgentCoordinator(
278
+ context=context, cache=cache, enable_external_agents=enable_external_agents
279
+ )