crackerjack 0.31.10__py3-none-any.whl → 0.31.12__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 +288 -705
  2. crackerjack/__main__.py +22 -8
  3. crackerjack/agents/__init__.py +0 -3
  4. crackerjack/agents/architect_agent.py +0 -43
  5. crackerjack/agents/base.py +1 -9
  6. crackerjack/agents/coordinator.py +2 -148
  7. crackerjack/agents/documentation_agent.py +109 -81
  8. crackerjack/agents/dry_agent.py +122 -97
  9. crackerjack/agents/formatting_agent.py +3 -16
  10. crackerjack/agents/import_optimization_agent.py +1174 -130
  11. crackerjack/agents/performance_agent.py +956 -188
  12. crackerjack/agents/performance_helpers.py +229 -0
  13. crackerjack/agents/proactive_agent.py +1 -48
  14. crackerjack/agents/refactoring_agent.py +516 -246
  15. crackerjack/agents/refactoring_helpers.py +282 -0
  16. crackerjack/agents/security_agent.py +393 -90
  17. crackerjack/agents/test_creation_agent.py +1776 -120
  18. crackerjack/agents/test_specialist_agent.py +59 -15
  19. crackerjack/agents/tracker.py +0 -102
  20. crackerjack/api.py +145 -37
  21. crackerjack/cli/handlers.py +48 -30
  22. crackerjack/cli/interactive.py +11 -11
  23. crackerjack/cli/options.py +66 -4
  24. crackerjack/code_cleaner.py +808 -148
  25. crackerjack/config/global_lock_config.py +110 -0
  26. crackerjack/config/hooks.py +43 -64
  27. crackerjack/core/async_workflow_orchestrator.py +247 -97
  28. crackerjack/core/autofix_coordinator.py +192 -109
  29. crackerjack/core/enhanced_container.py +46 -63
  30. crackerjack/core/file_lifecycle.py +549 -0
  31. crackerjack/core/performance.py +9 -8
  32. crackerjack/core/performance_monitor.py +395 -0
  33. crackerjack/core/phase_coordinator.py +281 -94
  34. crackerjack/core/proactive_workflow.py +9 -58
  35. crackerjack/core/resource_manager.py +501 -0
  36. crackerjack/core/service_watchdog.py +490 -0
  37. crackerjack/core/session_coordinator.py +4 -8
  38. crackerjack/core/timeout_manager.py +504 -0
  39. crackerjack/core/websocket_lifecycle.py +475 -0
  40. crackerjack/core/workflow_orchestrator.py +343 -209
  41. crackerjack/dynamic_config.py +47 -6
  42. crackerjack/errors.py +3 -4
  43. crackerjack/executors/async_hook_executor.py +63 -13
  44. crackerjack/executors/cached_hook_executor.py +14 -14
  45. crackerjack/executors/hook_executor.py +100 -37
  46. crackerjack/executors/hook_lock_manager.py +856 -0
  47. crackerjack/executors/individual_hook_executor.py +120 -86
  48. crackerjack/intelligence/__init__.py +0 -7
  49. crackerjack/intelligence/adaptive_learning.py +13 -86
  50. crackerjack/intelligence/agent_orchestrator.py +15 -78
  51. crackerjack/intelligence/agent_registry.py +12 -59
  52. crackerjack/intelligence/agent_selector.py +31 -92
  53. crackerjack/intelligence/integration.py +1 -41
  54. crackerjack/interactive.py +9 -9
  55. crackerjack/managers/async_hook_manager.py +25 -8
  56. crackerjack/managers/hook_manager.py +9 -9
  57. crackerjack/managers/publish_manager.py +57 -59
  58. crackerjack/managers/test_command_builder.py +6 -36
  59. crackerjack/managers/test_executor.py +9 -61
  60. crackerjack/managers/test_manager.py +17 -63
  61. crackerjack/managers/test_manager_backup.py +77 -127
  62. crackerjack/managers/test_progress.py +4 -23
  63. crackerjack/mcp/cache.py +5 -12
  64. crackerjack/mcp/client_runner.py +10 -10
  65. crackerjack/mcp/context.py +64 -6
  66. crackerjack/mcp/dashboard.py +14 -11
  67. crackerjack/mcp/enhanced_progress_monitor.py +55 -55
  68. crackerjack/mcp/file_monitor.py +72 -42
  69. crackerjack/mcp/progress_components.py +103 -84
  70. crackerjack/mcp/progress_monitor.py +122 -49
  71. crackerjack/mcp/rate_limiter.py +12 -12
  72. crackerjack/mcp/server_core.py +16 -22
  73. crackerjack/mcp/service_watchdog.py +26 -26
  74. crackerjack/mcp/state.py +15 -0
  75. crackerjack/mcp/tools/core_tools.py +95 -39
  76. crackerjack/mcp/tools/error_analyzer.py +6 -32
  77. crackerjack/mcp/tools/execution_tools.py +1 -56
  78. crackerjack/mcp/tools/execution_tools_backup.py +35 -131
  79. crackerjack/mcp/tools/intelligence_tool_registry.py +0 -36
  80. crackerjack/mcp/tools/intelligence_tools.py +2 -55
  81. crackerjack/mcp/tools/monitoring_tools.py +308 -145
  82. crackerjack/mcp/tools/proactive_tools.py +12 -42
  83. crackerjack/mcp/tools/progress_tools.py +23 -15
  84. crackerjack/mcp/tools/utility_tools.py +3 -40
  85. crackerjack/mcp/tools/workflow_executor.py +40 -60
  86. crackerjack/mcp/websocket/app.py +0 -3
  87. crackerjack/mcp/websocket/endpoints.py +206 -268
  88. crackerjack/mcp/websocket/jobs.py +213 -66
  89. crackerjack/mcp/websocket/server.py +84 -6
  90. crackerjack/mcp/websocket/websocket_handler.py +137 -29
  91. crackerjack/models/config_adapter.py +3 -16
  92. crackerjack/models/protocols.py +162 -3
  93. crackerjack/models/resource_protocols.py +454 -0
  94. crackerjack/models/task.py +3 -3
  95. crackerjack/monitoring/__init__.py +0 -0
  96. crackerjack/monitoring/ai_agent_watchdog.py +25 -71
  97. crackerjack/monitoring/regression_prevention.py +28 -87
  98. crackerjack/orchestration/advanced_orchestrator.py +44 -78
  99. crackerjack/orchestration/coverage_improvement.py +10 -60
  100. crackerjack/orchestration/execution_strategies.py +16 -16
  101. crackerjack/orchestration/test_progress_streamer.py +61 -53
  102. crackerjack/plugins/base.py +1 -1
  103. crackerjack/plugins/managers.py +22 -20
  104. crackerjack/py313.py +65 -21
  105. crackerjack/services/backup_service.py +467 -0
  106. crackerjack/services/bounded_status_operations.py +627 -0
  107. crackerjack/services/cache.py +7 -9
  108. crackerjack/services/config.py +35 -52
  109. crackerjack/services/config_integrity.py +5 -16
  110. crackerjack/services/config_merge.py +542 -0
  111. crackerjack/services/contextual_ai_assistant.py +17 -19
  112. crackerjack/services/coverage_ratchet.py +44 -73
  113. crackerjack/services/debug.py +25 -39
  114. crackerjack/services/dependency_monitor.py +52 -50
  115. crackerjack/services/enhanced_filesystem.py +14 -11
  116. crackerjack/services/file_hasher.py +1 -1
  117. crackerjack/services/filesystem.py +1 -12
  118. crackerjack/services/git.py +71 -47
  119. crackerjack/services/health_metrics.py +31 -27
  120. crackerjack/services/initialization.py +276 -428
  121. crackerjack/services/input_validator.py +760 -0
  122. crackerjack/services/log_manager.py +16 -16
  123. crackerjack/services/logging.py +7 -6
  124. crackerjack/services/metrics.py +43 -43
  125. crackerjack/services/pattern_cache.py +2 -31
  126. crackerjack/services/pattern_detector.py +26 -63
  127. crackerjack/services/performance_benchmarks.py +20 -45
  128. crackerjack/services/regex_patterns.py +2887 -0
  129. crackerjack/services/regex_utils.py +537 -0
  130. crackerjack/services/secure_path_utils.py +683 -0
  131. crackerjack/services/secure_status_formatter.py +534 -0
  132. crackerjack/services/secure_subprocess.py +605 -0
  133. crackerjack/services/security.py +47 -10
  134. crackerjack/services/security_logger.py +492 -0
  135. crackerjack/services/server_manager.py +109 -50
  136. crackerjack/services/smart_scheduling.py +8 -25
  137. crackerjack/services/status_authentication.py +603 -0
  138. crackerjack/services/status_security_manager.py +442 -0
  139. crackerjack/services/thread_safe_status_collector.py +546 -0
  140. crackerjack/services/tool_version_service.py +1 -23
  141. crackerjack/services/unified_config.py +36 -58
  142. crackerjack/services/validation_rate_limiter.py +269 -0
  143. crackerjack/services/version_checker.py +9 -40
  144. crackerjack/services/websocket_resource_limiter.py +572 -0
  145. crackerjack/slash_commands/__init__.py +52 -2
  146. crackerjack/tools/__init__.py +0 -0
  147. crackerjack/tools/validate_input_validator_patterns.py +262 -0
  148. crackerjack/tools/validate_regex_patterns.py +198 -0
  149. {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/METADATA +197 -12
  150. crackerjack-0.31.12.dist-info/RECORD +178 -0
  151. crackerjack/cli/facade.py +0 -104
  152. crackerjack-0.31.10.dist-info/RECORD +0 -149
  153. {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/WHEEL +0 -0
  154. {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/entry_points.txt +0 -0
  155. {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/licenses/LICENSE +0 -0
crackerjack/__main__.py CHANGED
@@ -35,7 +35,6 @@ def _handle_monitoring_commands(
35
35
  watchdog: bool,
36
36
  dev: bool,
37
37
  ) -> bool:
38
- """Handle monitoring commands."""
39
38
  if monitor:
40
39
  handle_monitor_mode(dev_mode=dev)
41
40
  return True
@@ -57,7 +56,6 @@ def _handle_websocket_commands(
57
56
  restart_websocket_server: bool,
58
57
  websocket_port: int | None,
59
58
  ) -> bool:
60
- """Handle WebSocket server commands."""
61
59
  if start_websocket_server:
62
60
  port = websocket_port or 8675
63
61
  handle_start_websocket_server(port)
@@ -78,7 +76,6 @@ def _handle_mcp_commands(
78
76
  restart_mcp_server: bool,
79
77
  websocket_port: int | None,
80
78
  ) -> bool:
81
- """Handle MCP server commands."""
82
79
  if start_mcp_server:
83
80
  handle_mcp_server(websocket_port)
84
81
  return True
@@ -105,7 +102,6 @@ def _handle_server_commands(
105
102
  websocket_port: int | None,
106
103
  dev: bool,
107
104
  ) -> bool:
108
- """Handle server-related commands. Returns True if a server command was handled."""
109
105
  return (
110
106
  _handle_monitoring_commands(monitor, enhanced_monitor, dashboard, watchdog, dev)
111
107
  or _handle_websocket_commands(
@@ -130,6 +126,7 @@ def main(
130
126
  no_config_updates: bool = CLI_OPTIONS["no_config_updates"],
131
127
  update_precommit: bool = CLI_OPTIONS["update_precommit"],
132
128
  verbose: bool = CLI_OPTIONS["verbose"],
129
+ debug: bool = CLI_OPTIONS["debug"],
133
130
  publish: BumpOption | None = CLI_OPTIONS["publish"],
134
131
  all: BumpOption | None = CLI_OPTIONS["all"],
135
132
  bump: BumpOption | None = CLI_OPTIONS["bump"],
@@ -172,6 +169,12 @@ def main(
172
169
  coverage_goal: float | None = CLI_OPTIONS["coverage_goal"],
173
170
  no_coverage_ratchet: bool = CLI_OPTIONS["no_coverage_ratchet"],
174
171
  boost_coverage: bool = CLI_OPTIONS["boost_coverage"],
172
+ disable_global_locks: bool = CLI_OPTIONS["disable_global_locks"],
173
+ global_lock_timeout: int = CLI_OPTIONS["global_lock_timeout"],
174
+ global_lock_cleanup: bool = CLI_OPTIONS["global_lock_cleanup"],
175
+ global_lock_dir: str | None = CLI_OPTIONS["global_lock_dir"],
176
+ quick: bool = CLI_OPTIONS["quick"],
177
+ thorough: bool = CLI_OPTIONS["thorough"],
175
178
  ) -> None:
176
179
  options = create_options(
177
180
  commit,
@@ -179,6 +182,7 @@ def main(
179
182
  no_config_updates,
180
183
  update_precommit,
181
184
  verbose,
185
+ debug,
182
186
  publish,
183
187
  all,
184
188
  bump,
@@ -209,15 +213,27 @@ def main(
209
213
  coverage_goal,
210
214
  no_coverage_ratchet,
211
215
  boost_coverage,
216
+ disable_global_locks,
217
+ global_lock_timeout,
218
+ global_lock_cleanup,
219
+ global_lock_dir,
220
+ quick,
221
+ thorough,
212
222
  )
213
223
 
214
224
  if ai_debug:
215
225
  ai_agent = True
216
226
  verbose = True
227
+ # Update the options object to reflect the verbose setting
228
+ options.verbose = True
217
229
 
218
- setup_ai_agent_env(ai_agent, verbose or ai_debug)
230
+ # If debug flag is set, enable verbose mode as well
231
+ if debug:
232
+ verbose = True
233
+ options.verbose = True
234
+
235
+ setup_ai_agent_env(ai_agent, verbose or ai_debug or debug)
219
236
 
220
- # Handle server commands
221
237
  if _handle_server_commands(
222
238
  monitor,
223
239
  enhanced_monitor,
@@ -234,7 +250,6 @@ def main(
234
250
  ):
235
251
  return
236
252
 
237
- # Handle main workflow
238
253
  if interactive:
239
254
  handle_interactive_mode(options)
240
255
  else:
@@ -242,7 +257,6 @@ def main(
242
257
 
243
258
 
244
259
  def cli() -> None:
245
- """Entry point for console script."""
246
260
  app()
247
261
 
248
262
 
@@ -1,4 +1,3 @@
1
- # Import all agent modules to trigger registration
2
1
  from . import (
3
2
  architect_agent,
4
3
  documentation_agent,
@@ -20,12 +19,10 @@ __all__ = [
20
19
  "AgentCoordinator",
21
20
  "AgentTracker",
22
21
  "FixResult",
23
- # Exported classes
24
22
  "Issue",
25
23
  "IssueType",
26
24
  "Priority",
27
25
  "SubAgent",
28
- # Agent modules (imported for registration)
29
26
  "architect_agent",
30
27
  "documentation_agent",
31
28
  "dry_agent",
@@ -5,15 +5,7 @@ from .proactive_agent import ProactiveAgent
5
5
 
6
6
 
7
7
  class ArchitectAgent(ProactiveAgent):
8
- """Agent that provides architectural planning and guidance.
9
-
10
- This agent bridges to the external crackerjack-architect specialist
11
- for complex architectural decisions while handling simpler planning
12
- internally through cached patterns.
13
- """
14
-
15
8
  def get_supported_types(self) -> set[IssueType]:
16
- """Support all issue types for architectural planning."""
17
9
  return {
18
10
  IssueType.COMPLEXITY,
19
11
  IssueType.DRY_VIOLATION,
@@ -30,58 +22,39 @@ class ArchitectAgent(ProactiveAgent):
30
22
  }
31
23
 
32
24
  async def can_handle(self, issue: Issue) -> float:
33
- """Determine confidence in handling this issue architecturally."""
34
- # High confidence for complex issues that benefit from planning
35
25
  if issue.type == IssueType.COMPLEXITY:
36
26
  return 0.9
37
27
 
38
- # High confidence for DRY violations (architectural)
39
28
  if issue.type == IssueType.DRY_VIOLATION:
40
29
  return 0.85
41
30
 
42
- # Medium-high confidence for performance issues
43
31
  if issue.type == IssueType.PERFORMANCE:
44
32
  return 0.8
45
33
 
46
- # Medium confidence for security (architectural patterns)
47
34
  if issue.type == IssueType.SECURITY:
48
35
  return 0.75
49
36
 
50
- # Lower confidence for formatting/imports (less architectural)
51
37
  if issue.type in {IssueType.FORMATTING, IssueType.IMPORT_ERROR}:
52
38
  return 0.4
53
39
 
54
- # Medium confidence for other types
55
40
  return 0.6
56
41
 
57
42
  async def plan_before_action(self, issue: Issue) -> dict[str, t.Any]:
58
- """Create architectural plan for fixing the issue."""
59
- # Check if this is a complex issue requiring external specialist
60
43
  if await self._needs_external_specialist(issue):
61
44
  return await self._get_specialist_plan(issue)
62
45
 
63
- # Use internal planning for simpler issues
64
46
  return await self._get_internal_plan(issue)
65
47
 
66
48
  async def _needs_external_specialist(self, issue: Issue) -> bool:
67
- """Determine if external crackerjack-architect specialist is needed."""
68
- # Always use specialist for complexity issues
69
49
  if issue.type == IssueType.COMPLEXITY:
70
50
  return True
71
51
 
72
- # Use specialist for DRY violations
73
52
  if issue.type == IssueType.DRY_VIOLATION:
74
53
  return True
75
54
 
76
- # Use specialist for multiple related issues
77
- # (This would be determined by the coordinator in practice)
78
55
  return False
79
56
 
80
57
  async def _get_specialist_plan(self, issue: Issue) -> dict[str, t.Any]:
81
- """Get plan from external crackerjack-architect specialist."""
82
- # This would use the Task tool to invoke crackerjack-architect
83
- # For now, return a structured plan that mimics what the specialist would provide
84
-
85
58
  plan = {
86
59
  "strategy": "external_specialist_guided",
87
60
  "specialist": "crackerjack-architect",
@@ -95,7 +68,6 @@ class ArchitectAgent(ProactiveAgent):
95
68
  return plan
96
69
 
97
70
  async def _get_internal_plan(self, issue: Issue) -> dict[str, t.Any]:
98
- """Create plan using internal architectural knowledge."""
99
71
  plan = {
100
72
  "strategy": "internal_pattern_based",
101
73
  "approach": self._get_internal_approach(issue),
@@ -108,7 +80,6 @@ class ArchitectAgent(ProactiveAgent):
108
80
  return plan
109
81
 
110
82
  def _get_specialist_approach(self, issue: Issue) -> str:
111
- """Get the approach that crackerjack-architect would recommend."""
112
83
  if issue.type == IssueType.COMPLEXITY:
113
84
  return "break_into_helper_methods"
114
85
  elif issue.type == IssueType.DRY_VIOLATION:
@@ -120,7 +91,6 @@ class ArchitectAgent(ProactiveAgent):
120
91
  return "apply_clean_code_principles"
121
92
 
122
93
  def _get_internal_approach(self, issue: Issue) -> str:
123
- """Get internal approach for simpler issues."""
124
94
  return {
125
95
  IssueType.FORMATTING: "apply_standard_formatting",
126
96
  IssueType.IMPORT_ERROR: "optimize_imports",
@@ -131,7 +101,6 @@ class ArchitectAgent(ProactiveAgent):
131
101
  }.get(issue.type, "apply_standard_fix")
132
102
 
133
103
  def _get_recommended_patterns(self, issue: Issue) -> list[str]:
134
- """Get patterns recommended by crackerjack-architect."""
135
104
  return {
136
105
  IssueType.COMPLEXITY: [
137
106
  "extract_method",
@@ -160,7 +129,6 @@ class ArchitectAgent(ProactiveAgent):
160
129
  }.get(issue.type, ["standard_patterns"])
161
130
 
162
131
  def _get_cached_patterns_for_issue(self, issue: Issue) -> list[str]:
163
- """Get cached patterns that match this issue type."""
164
132
  cached = self.get_cached_patterns()
165
133
  matching_patterns = []
166
134
 
@@ -173,7 +141,6 @@ class ArchitectAgent(ProactiveAgent):
173
141
  return matching_patterns or ["default_pattern"]
174
142
 
175
143
  def _analyze_dependencies(self, issue: Issue) -> list[str]:
176
- """Analyze what other changes might be needed."""
177
144
  dependencies = []
178
145
 
179
146
  if issue.type == IssueType.COMPLEXITY:
@@ -193,7 +160,6 @@ class ArchitectAgent(ProactiveAgent):
193
160
  return dependencies
194
161
 
195
162
  def _identify_risks(self, issue: Issue) -> list[str]:
196
- """Identify potential risks in fixing this issue."""
197
163
  risks = []
198
164
 
199
165
  if issue.type == IssueType.COMPLEXITY:
@@ -211,7 +177,6 @@ class ArchitectAgent(ProactiveAgent):
211
177
  return risks
212
178
 
213
179
  def _get_validation_steps(self, issue: Issue) -> list[str]:
214
- """Get steps to validate the fix."""
215
180
  return [
216
181
  "run_fast_hooks",
217
182
  "run_full_tests",
@@ -221,13 +186,11 @@ class ArchitectAgent(ProactiveAgent):
221
186
  ]
222
187
 
223
188
  async def analyze_and_fix(self, issue: Issue) -> FixResult:
224
- """Standard fix method - delegates to proactive version."""
225
189
  return await self.analyze_and_fix_proactively(issue)
226
190
 
227
191
  async def _execute_with_plan(
228
192
  self, issue: Issue, plan: dict[str, t.Any]
229
193
  ) -> FixResult:
230
- """Execute fix following the architectural plan."""
231
194
  strategy = plan.get("strategy", "internal_pattern_based")
232
195
 
233
196
  if strategy == "external_specialist_guided":
@@ -237,10 +200,6 @@ class ArchitectAgent(ProactiveAgent):
237
200
  async def _execute_specialist_guided_fix(
238
201
  self, issue: Issue, plan: dict[str, t.Any]
239
202
  ) -> FixResult:
240
- """Execute fix guided by external specialist plan."""
241
- # This would invoke the actual Task tool with crackerjack-architect
242
- # For now, return a structured result indicating the plan was followed
243
-
244
203
  return FixResult(
245
204
  success=True,
246
205
  confidence=0.9,
@@ -260,7 +219,6 @@ class ArchitectAgent(ProactiveAgent):
260
219
  async def _execute_pattern_based_fix(
261
220
  self, issue: Issue, plan: dict[str, t.Any]
262
221
  ) -> FixResult:
263
- """Execute fix using cached patterns and internal logic."""
264
222
  patterns = plan.get("patterns", [])
265
223
  approach = plan.get("approach", "standard")
266
224
 
@@ -277,5 +235,4 @@ class ArchitectAgent(ProactiveAgent):
277
235
  )
278
236
 
279
237
 
280
- # Register the agent
281
238
  agent_registry.register(ArchitectAgent)
@@ -27,6 +27,7 @@ class IssueType(Enum):
27
27
  DOCUMENTATION = "documentation"
28
28
  TEST_ORGANIZATION = "test_organization"
29
29
  COVERAGE_IMPROVEMENT = "coverage_improvement"
30
+ REGEX_VALIDATION = "regex_validation"
30
31
 
31
32
 
32
33
  @dataclass
@@ -40,10 +41,6 @@ class Issue:
40
41
  details: list[str] = field(default_factory=list)
41
42
  stage: str = "unknown"
42
43
 
43
- @property
44
- def context_key(self) -> str:
45
- return f"{self.type.value}: {self.file_path}: {self.line_number}"
46
-
47
44
 
48
45
  @dataclass
49
46
  class FixResult:
@@ -145,11 +142,9 @@ class SubAgent(ABC):
145
142
  pass
146
143
 
147
144
  async def plan_before_action(self, issue: Issue) -> dict[str, t.Any]:
148
- """Plan actions before executing fixes. Override in subclasses."""
149
145
  return {"strategy": "default", "confidence": 0.5}
150
146
 
151
147
  def get_cached_patterns(self) -> dict[str, t.Any]:
152
- """Get cached patterns for this agent. Override in subclasses."""
153
148
  return {}
154
149
 
155
150
 
@@ -163,8 +158,5 @@ class AgentRegistry:
163
158
  def create_all(self, context: AgentContext) -> list[SubAgent]:
164
159
  return [agent_cls(context) for agent_cls in self._agents.values()]
165
160
 
166
- def get_by_name(self, name: str) -> type[SubAgent] | None:
167
- return self._agents.get(name)
168
-
169
161
 
170
162
  agent_registry = AgentRegistry()
@@ -1,6 +1,5 @@
1
1
  import asyncio
2
2
  import logging
3
- import operator
4
3
  import typing as t
5
4
  from collections import defaultdict
6
5
 
@@ -11,7 +10,6 @@ from .base import (
11
10
  FixResult,
12
11
  Issue,
13
12
  IssueType,
14
- Priority,
15
13
  SubAgent,
16
14
  agent_registry,
17
15
  )
@@ -27,7 +25,7 @@ class AgentCoordinator:
27
25
  self._collaboration_threshold = 0.7
28
26
  self.tracker = get_agent_tracker()
29
27
  self.debugger = get_ai_agent_debugger()
30
- self.proactive_mode = True # Enabled by default
28
+ self.proactive_mode = True
31
29
 
32
30
  def initialize_agents(self) -> None:
33
31
  self.agents = agent_registry.create_all(self.context)
@@ -62,40 +60,7 @@ class AgentCoordinator:
62
60
 
63
61
  return overall_result
64
62
 
65
- async def handle_single_issue(self, issue: Issue) -> FixResult:
66
- if not self.agents:
67
- self.initialize_agents()
68
-
69
- cache_key = issue.context_key
70
- if cache_key in self._issue_cache:
71
- cached_result = self._issue_cache[cache_key]
72
- self.logger.info(f"Using cached result for {cache_key}")
73
- self.tracker.track_cache_hit()
74
- return cached_result
75
-
76
- self.tracker.track_cache_miss()
77
-
78
- agent_scores = await self._evaluate_agents_for_issue(issue)
79
-
80
- if not agent_scores:
81
- self.logger.warning(f"No agents can handle issue: {issue.message}")
82
- return FixResult(
83
- success=False,
84
- confidence=0.0,
85
- remaining_issues=[f"No agent available for: {issue.message}"],
86
- recommendations=["Manual intervention required"],
87
- )
88
-
89
- best_agent, best_score = agent_scores[0]
90
-
91
- if best_score >= self._collaboration_threshold:
92
- result = await self._handle_with_single_agent(best_agent, issue)
93
- else:
94
- result = await self._handle_with_collaboration(agent_scores[:3], issue)
95
-
96
- self._issue_cache[cache_key] = result
97
-
98
- return result
63
+ # Removed unused method: handle_single_issue
99
64
 
100
65
  async def _handle_issues_by_type(
101
66
  self,
@@ -139,23 +104,6 @@ class AgentCoordinator:
139
104
 
140
105
  return combined_result
141
106
 
142
- async def _evaluate_agents_for_issue(
143
- self,
144
- issue: Issue,
145
- ) -> list[tuple[SubAgent, float]]:
146
- evaluations: list[tuple[SubAgent, float]] = []
147
-
148
- for agent in self.agents:
149
- try:
150
- confidence = await agent.can_handle(issue)
151
- if confidence > 0.0:
152
- evaluations.append((agent, confidence))
153
- except Exception as e:
154
- self.logger.exception(f"Error evaluating {agent.name} for issue: {e}")
155
-
156
- evaluations.sort(key=operator.itemgetter(1), reverse=True)
157
- return evaluations
158
-
159
107
  async def _find_best_specialist(
160
108
  self,
161
109
  specialists: list[SubAgent],
@@ -226,45 +174,6 @@ class AgentCoordinator:
226
174
  self.tracker.track_agent_complete(agent.name, error_result)
227
175
  return error_result
228
176
 
229
- async def _handle_with_collaboration(
230
- self,
231
- agent_scores: list[tuple[SubAgent, float]],
232
- issue: Issue,
233
- ) -> FixResult:
234
- self.logger.info(
235
- f"Using collaborative approach for issue: {issue.message[:100]}",
236
- )
237
-
238
- results: list[FixResult] = []
239
-
240
- for agent, _ in agent_scores:
241
- try:
242
- result = await agent.analyze_and_fix(issue)
243
- results.append(result)
244
-
245
- if result.success and result.confidence >= 0.8:
246
- self.logger.info(f"{agent.name} solved issue with high confidence")
247
- break
248
-
249
- except Exception as e:
250
- self.logger.exception(f"Collaborative agent {agent.name} failed: {e}")
251
- results.append(
252
- FixResult(
253
- success=False,
254
- confidence=0.0,
255
- remaining_issues=[f"{agent.name} failed: {e}"],
256
- ),
257
- )
258
-
259
- if not results:
260
- return FixResult(success=False, confidence=0.0)
261
-
262
- combined_result = results[0]
263
- for result in results[1:]:
264
- combined_result = combined_result.merge_with(result)
265
-
266
- return combined_result
267
-
268
177
  def _group_issues_by_type(
269
178
  self,
270
179
  issues: list[Issue],
@@ -286,34 +195,7 @@ class AgentCoordinator:
286
195
  }
287
196
  return capabilities
288
197
 
289
- def clear_cache(self) -> None:
290
- self._issue_cache.clear()
291
- self.logger.info("Cleared issue cache")
292
-
293
- async def test_agent_connectivity(self) -> dict[str, bool]:
294
- if not self.agents:
295
- self.initialize_agents()
296
-
297
- test_issue = Issue(
298
- id="test",
299
- type=IssueType.FORMATTING,
300
- severity=Priority.LOW,
301
- message="Test connectivity",
302
- )
303
-
304
- connectivity = {}
305
- for agent in self.agents:
306
- try:
307
- confidence = await agent.can_handle(test_issue)
308
- connectivity[agent.name] = confidence >= 0.0
309
- except Exception as e:
310
- self.logger.exception(f"Connectivity test failed for {agent.name}: {e}")
311
- connectivity[agent.name] = False
312
-
313
- return connectivity
314
-
315
198
  async def handle_issues_proactively(self, issues: list[Issue]) -> FixResult:
316
- """Handle issues with proactive planning phase."""
317
199
  if not self.proactive_mode:
318
200
  return await self.handle_issues(issues)
319
201
 
@@ -325,13 +207,10 @@ class AgentCoordinator:
325
207
 
326
208
  self.logger.info(f"Handling {len(issues)} issues with proactive planning")
327
209
 
328
- # Phase 1: Create architectural plan
329
210
  architectural_plan = await self._create_architectural_plan(issues)
330
211
 
331
- # Phase 2: Apply fixes following the plan
332
212
  overall_result = await self._apply_fixes_with_plan(issues, architectural_plan)
333
213
 
334
- # Phase 3: Validate against plan
335
214
  validation_result = await self._validate_against_plan(
336
215
  overall_result, architectural_plan
337
216
  )
@@ -339,14 +218,12 @@ class AgentCoordinator:
339
218
  return validation_result
340
219
 
341
220
  async def _create_architectural_plan(self, issues: list[Issue]) -> dict[str, t.Any]:
342
- """Create architectural plan using ArchitectAgent."""
343
221
  architect = self._get_architect_agent()
344
222
 
345
223
  if not architect:
346
224
  self.logger.warning("No ArchitectAgent available for planning")
347
225
  return {"strategy": "reactive_fallback", "patterns": []}
348
226
 
349
- # Analyze all issues together for comprehensive planning
350
227
  complex_issues = [
351
228
  issue
352
229
  for issue in issues
@@ -357,14 +234,11 @@ class AgentCoordinator:
357
234
  if not complex_issues:
358
235
  return {"strategy": "simple_fixes", "patterns": ["standard_patterns"]}
359
236
 
360
- # Use the first complex issue for planning (represents the architectural challenge)
361
237
  primary_issue = complex_issues[0]
362
238
 
363
239
  try:
364
- # Get plan from ArchitectAgent
365
240
  plan = await architect.plan_before_action(primary_issue)
366
241
 
367
- # Extend plan to cover all issues
368
242
  plan["all_issues"] = [issue.id for issue in issues]
369
243
  plan["issue_types"] = list({issue.type.value for issue in issues})
370
244
 
@@ -380,16 +254,13 @@ class AgentCoordinator:
380
254
  async def _apply_fixes_with_plan(
381
255
  self, issues: list[Issue], plan: dict[str, t.Any]
382
256
  ) -> FixResult:
383
- """Apply fixes following the architectural plan."""
384
257
  strategy = plan.get("strategy", "reactive_fallback")
385
258
 
386
259
  if strategy == "reactive_fallback":
387
- # Fallback to standard processing
388
260
  return await self.handle_issues(issues)
389
261
 
390
262
  self.logger.info(f"Applying fixes with {strategy} strategy")
391
263
 
392
- # Group issues by priority based on plan
393
264
  prioritized_issues = self._prioritize_issues_by_plan(issues, plan)
394
265
 
395
266
  overall_result = FixResult(success=True, confidence=1.0)
@@ -398,7 +269,6 @@ class AgentCoordinator:
398
269
  group_result = await self._handle_issue_group_with_plan(issue_group, plan)
399
270
  overall_result = overall_result.merge_with(group_result)
400
271
 
401
- # If a critical group fails, consider the overall strategy
402
272
  if not group_result.success and self._is_critical_group(issue_group, plan):
403
273
  overall_result.success = False
404
274
  overall_result.remaining_issues.append(
@@ -410,7 +280,6 @@ class AgentCoordinator:
410
280
  async def _validate_against_plan(
411
281
  self, result: FixResult, plan: dict[str, t.Any]
412
282
  ) -> FixResult:
413
- """Validate the results against the architectural plan."""
414
283
  validation_steps = plan.get("validation", [])
415
284
 
416
285
  if not validation_steps:
@@ -418,7 +287,6 @@ class AgentCoordinator:
418
287
 
419
288
  self.logger.info(f"Validating against plan: {validation_steps}")
420
289
 
421
- # Add validation recommendations
422
290
  result.recommendations.extend(
423
291
  [
424
292
  f"Validate with: {', '.join(validation_steps)}",
@@ -430,7 +298,6 @@ class AgentCoordinator:
430
298
  return result
431
299
 
432
300
  def _get_architect_agent(self) -> SubAgent | None:
433
- """Get the ArchitectAgent from available agents."""
434
301
  for agent in self.agents:
435
302
  if agent.__class__.__name__ == "ArchitectAgent":
436
303
  return agent
@@ -439,11 +306,9 @@ class AgentCoordinator:
439
306
  def _prioritize_issues_by_plan(
440
307
  self, issues: list[Issue], plan: dict[str, t.Any]
441
308
  ) -> list[list[Issue]]:
442
- """Prioritize issues based on the architectural plan."""
443
309
  strategy = plan.get("strategy", "reactive_fallback")
444
310
 
445
311
  if strategy == "external_specialist_guided":
446
- # Handle complex issues first, then simple ones
447
312
  complex_issues = [
448
313
  issue
449
314
  for issue in issues
@@ -452,24 +317,20 @@ class AgentCoordinator:
452
317
  other_issues = [issue for issue in issues if issue not in complex_issues]
453
318
  return [complex_issues, other_issues] if complex_issues else [other_issues]
454
319
 
455
- # Default: group by type for parallel processing
456
320
  groups = self._group_issues_by_type(issues)
457
321
  return list(groups.values())
458
322
 
459
323
  async def _handle_issue_group_with_plan(
460
324
  self, issues: list[Issue], plan: dict[str, t.Any]
461
325
  ) -> FixResult:
462
- """Handle a group of issues with architectural guidance."""
463
326
  if not issues:
464
327
  return FixResult(success=True, confidence=1.0)
465
328
 
466
- # Get the best agent for this group, preferring ArchitectAgent for complex issues
467
329
  representative_issue = issues[0]
468
330
 
469
331
  if self._should_use_architect_for_group(issues, plan):
470
332
  architect = self._get_architect_agent()
471
333
  if architect:
472
- # Use architect for the whole group
473
334
  group_result = FixResult(success=True, confidence=1.0)
474
335
 
475
336
  for issue in issues:
@@ -478,20 +339,16 @@ class AgentCoordinator:
478
339
 
479
340
  return group_result
480
341
 
481
- # Use standard routing for simpler issues
482
342
  return await self._handle_issues_by_type(representative_issue.type, issues)
483
343
 
484
344
  def _should_use_architect_for_group(
485
345
  self, issues: list[Issue], plan: dict[str, t.Any]
486
346
  ) -> bool:
487
- """Determine if ArchitectAgent should handle this group."""
488
347
  strategy = plan.get("strategy", "")
489
348
 
490
- # Always use architect for specialist-guided strategies
491
349
  if strategy == "external_specialist_guided":
492
350
  return True
493
351
 
494
- # Use architect for complex or architectural issues
495
352
  architectural_types = {
496
353
  IssueType.COMPLEXITY,
497
354
  IssueType.DRY_VIOLATION,
@@ -501,12 +358,9 @@ class AgentCoordinator:
501
358
  return any(issue.type in architectural_types for issue in issues)
502
359
 
503
360
  def _is_critical_group(self, issues: list[Issue], plan: dict[str, t.Any]) -> bool:
504
- """Determine if this issue group is critical to the plan."""
505
- # Complex and DRY violations are typically critical
506
361
  critical_types = {IssueType.COMPLEXITY, IssueType.DRY_VIOLATION}
507
362
  return any(issue.type in critical_types for issue in issues)
508
363
 
509
364
  def set_proactive_mode(self, enabled: bool) -> None:
510
- """Enable or disable proactive planning mode."""
511
365
  self.proactive_mode = enabled
512
366
  self.logger.info(f"Proactive mode {'enabled' if enabled else 'disabled'}")