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
@@ -1,9 +1,3 @@
1
- """Smart Agent Selection Engine.
2
-
3
- Intelligently selects the best agents for tasks based on context analysis,
4
- capability matching, and priority scoring.
5
- """
6
-
7
1
  import logging
8
2
  import re
9
3
  import typing as t
@@ -19,8 +13,6 @@ from .agent_registry import (
19
13
 
20
14
 
21
15
  class TaskContext(Enum):
22
- """Context categories for tasks."""
23
-
24
16
  CODE_QUALITY = "code_quality"
25
17
  ARCHITECTURE = "architecture"
26
18
  TESTING = "testing"
@@ -35,32 +27,26 @@ class TaskContext(Enum):
35
27
 
36
28
  @dataclass
37
29
  class TaskDescription:
38
- """Description of a task to be executed."""
39
-
40
30
  description: str
41
31
  context: TaskContext | None = None
42
32
  keywords: list[str] | None = None
43
33
  file_patterns: list[str] | None = None
44
34
  error_types: list[str] | None = None
45
- priority: int = 50 # 0-100, higher is more important
35
+ priority: int = 50
46
36
 
47
37
 
48
38
  @dataclass
49
39
  class AgentScore:
50
- """Score for an agent's suitability for a task."""
51
-
52
40
  agent: RegisteredAgent
53
- base_score: float # 0-1 based on capability match
54
- context_score: float # 0-1 based on context match
55
- priority_bonus: float # 0-1 based on agent priority
56
- confidence_factor: float # Multiplier from agent metadata
57
- final_score: float # Combined weighted score
58
- reasoning: str # Explanation of the score
41
+ base_score: float
42
+ context_score: float
43
+ priority_bonus: float
44
+ confidence_factor: float
45
+ final_score: float
46
+ reasoning: str
59
47
 
60
48
 
61
49
  class AgentSelector:
62
- """Intelligent agent selection engine."""
63
-
64
50
  def __init__(self, registry: AgentRegistry | None = None) -> None:
65
51
  self.logger = logging.getLogger(__name__)
66
52
  self.registry = registry
@@ -68,49 +54,39 @@ class AgentSelector:
68
54
  self._initialize_task_patterns()
69
55
 
70
56
  def _initialize_task_patterns(self) -> None:
71
- """Initialize patterns for task analysis."""
72
57
  self._task_patterns = {
73
- # Architecture patterns
74
- r"architect|design|structure|pattern|refactor.*complex": [
58
+ r"architect | design | structure | pattern | refactor.* complex": [
75
59
  AgentCapability.ARCHITECTURE,
76
60
  AgentCapability.REFACTORING,
77
61
  ],
78
- # Code quality patterns
79
- r"refurb|ruff|format|lint|style|clean.*code": [
62
+ r"refurb | ruff | format | lint | style | clean.* code": [
80
63
  AgentCapability.FORMATTING,
81
64
  AgentCapability.CODE_ANALYSIS,
82
65
  ],
83
- # Testing patterns
84
- r"test|pytest|coverage|mock|fixture": [
66
+ r"test | pytest | coverage | mock | fixture": [
85
67
  AgentCapability.TESTING,
86
68
  ],
87
- # Security patterns
88
- r"security|vulnerability|audit|bandit|safe": [
69
+ r"security | vulnerability | audit | bandit | safe": [
89
70
  AgentCapability.SECURITY,
90
71
  ],
91
- # Performance patterns
92
- r"performance|optimize|speed|efficient|complexity": [
72
+ r"performance | optimize | speed | efficient | complexity": [
93
73
  AgentCapability.PERFORMANCE,
94
74
  AgentCapability.CODE_ANALYSIS,
95
75
  ],
96
- # Documentation patterns
97
- r"document|readme|comment|explain|changelog": [
76
+ r"document | readme | comment | explain | changelog": [
98
77
  AgentCapability.DOCUMENTATION,
99
78
  ],
100
- # Refactoring patterns
101
- r"refactor|improve|simplify|dry.*violation": [
79
+ r"refactor | improve | simplify | dry.* violation": [
102
80
  AgentCapability.REFACTORING,
103
81
  AgentCapability.CODE_ANALYSIS,
104
82
  ],
105
- # Debugging patterns
106
- r"debug|fix|error|bug|failure": [
83
+ r"debug | fix | error | bug | failure": [
107
84
  AgentCapability.DEBUGGING,
108
85
  AgentCapability.CODE_ANALYSIS,
109
86
  ],
110
87
  }
111
88
 
112
89
  async def get_registry(self) -> AgentRegistry:
113
- """Get or initialize the agent registry."""
114
90
  if self.registry is None:
115
91
  self.registry = await get_agent_registry()
116
92
  return self.registry
@@ -120,7 +96,6 @@ class AgentSelector:
120
96
  task: TaskDescription,
121
97
  max_candidates: int = 5,
122
98
  ) -> AgentScore | None:
123
- """Select the single best agent for a task."""
124
99
  candidates = await self.select_agents(task, max_candidates)
125
100
  return candidates[0] if candidates else None
126
101
 
@@ -129,61 +104,53 @@ class AgentSelector:
129
104
  task: TaskDescription,
130
105
  max_candidates: int = 3,
131
106
  ) -> list[AgentScore]:
132
- """Select the best agents for a task, ordered by score."""
133
107
  registry = await self.get_registry()
134
108
 
135
- # Analyze task to determine required capabilities
136
109
  required_capabilities = self._analyze_task_capabilities(task)
137
110
 
138
- # Score all agents
139
111
  scores: list[AgentScore] = []
140
112
 
141
113
  for agent in registry.list_all_agents():
142
114
  score = await self._score_agent_for_task(agent, task, required_capabilities)
143
- if score.final_score > 0.1: # Minimum threshold
115
+ if score.final_score > 0.1:
144
116
  scores.append(score)
145
117
 
146
- # Sort by final score (descending)
147
118
  scores.sort(key=lambda s: s.final_score, reverse=True)
148
119
 
149
- # Return top candidates
150
120
  selected = scores[:max_candidates]
151
121
 
152
122
  self.logger.debug(
153
123
  f"Selected {len(selected)} agents for task '{task.description[:50]}...': "
154
- f"{[f'{s.agent.metadata.name}({s.final_score:.2f})' for s in selected]}"
124
+ f"{[f'{s.agent.metadata.name}({s.final_score: .2f})' for s in selected]}"
155
125
  )
156
126
 
157
127
  return selected
158
128
 
159
129
  def _analyze_task_capabilities(self, task: TaskDescription) -> set[AgentCapability]:
160
- """Analyze a task to determine required capabilities."""
161
130
  capabilities = set()
162
131
 
163
- # Apply different analysis methods
164
132
  capabilities.update(self._analyze_text_patterns(task))
165
133
  capabilities.update(self._analyze_context(task))
166
134
  capabilities.update(self._analyze_file_patterns(task))
167
135
  capabilities.update(self._analyze_error_types(task))
168
136
 
169
- # Fallback
170
137
  return capabilities or {AgentCapability.CODE_ANALYSIS}
171
138
 
172
139
  def _analyze_text_patterns(self, task: TaskDescription) -> set[AgentCapability]:
173
- """Analyze text patterns in task description and keywords."""
174
140
  text = task.description.lower()
175
141
  if task.keywords:
176
142
  text += " " + " ".join(task.keywords).lower()
177
143
 
178
144
  capabilities = set()
179
145
  for pattern, caps in self._task_patterns.items():
180
- if re.search(pattern, text, re.IGNORECASE):
146
+ if re.search(
147
+ pattern, text, re.IGNORECASE
148
+ ): # REGEX OK: dynamic pattern matching from config
181
149
  capabilities.update(caps)
182
150
 
183
151
  return capabilities
184
152
 
185
153
  def _analyze_context(self, task: TaskDescription) -> set[AgentCapability]:
186
- """Analyze task context to determine capabilities."""
187
154
  if not task.context:
188
155
  return set()
189
156
 
@@ -218,7 +185,6 @@ class AgentSelector:
218
185
  return set(context_map.get(task.context, []))
219
186
 
220
187
  def _analyze_file_patterns(self, task: TaskDescription) -> set[AgentCapability]:
221
- """Analyze file patterns to determine capabilities."""
222
188
  if not task.file_patterns:
223
189
  return set()
224
190
 
@@ -227,13 +193,12 @@ class AgentSelector:
227
193
  pattern_lower = pattern.lower()
228
194
  if any(ext in pattern_lower for ext in (".py", ".pyi")):
229
195
  capabilities.add(AgentCapability.CODE_ANALYSIS)
230
- if any(test in pattern_lower for test in ("test_", "_test", "tests/")):
196
+ if any(test in pattern_lower for test in ("test_", "_test", "tests /")):
231
197
  capabilities.add(AgentCapability.TESTING)
232
198
 
233
199
  return capabilities
234
200
 
235
201
  def _analyze_error_types(self, task: TaskDescription) -> set[AgentCapability]:
236
- """Analyze error types to determine capabilities."""
237
202
  if not task.error_types:
238
203
  return set()
239
204
 
@@ -259,29 +224,23 @@ class AgentSelector:
259
224
  task: TaskDescription,
260
225
  required_capabilities: set[AgentCapability],
261
226
  ) -> AgentScore:
262
- """Score an agent's suitability for a task."""
263
- # Base score: capability overlap
264
227
  agent_capabilities = agent.metadata.capabilities
265
228
  overlap = len(required_capabilities & agent_capabilities)
266
229
  max_overlap = len(required_capabilities)
267
230
 
268
231
  base_score = overlap / max_overlap if max_overlap > 0 else 0.0
269
232
 
270
- # Context score: how well the agent matches the task context
271
233
  context_score = self._calculate_context_score(agent, task)
272
234
 
273
- # Priority bonus: normalized agent priority (0-1)
274
235
  priority_bonus = min(agent.metadata.priority / 100.0, 1.0)
275
236
 
276
- # Confidence factor from agent metadata
277
237
  confidence_factor = agent.metadata.confidence_factor
278
238
 
279
- # Calculate weighted final score
280
239
  weights = {
281
- "base": 0.4, # Capability match is most important
282
- "context": 0.3, # Context matching
283
- "priority": 0.2, # Agent priority (source-based)
284
- "bonus": 0.1, # Additional considerations
240
+ "base": 0.4,
241
+ "context": 0.3,
242
+ "priority": 0.2,
243
+ "bonus": 0.1,
285
244
  }
286
245
 
287
246
  weighted_score = (
@@ -290,10 +249,8 @@ class AgentSelector:
290
249
  + priority_bonus * weights["priority"]
291
250
  )
292
251
 
293
- # Apply confidence factor
294
252
  final_score = weighted_score * confidence_factor
295
253
 
296
- # Generate reasoning
297
254
  reasoning = self._generate_score_reasoning(
298
255
  agent, base_score, context_score, priority_bonus, required_capabilities
299
256
  )
@@ -311,7 +268,6 @@ class AgentSelector:
311
268
  def _calculate_context_score(
312
269
  self, agent: RegisteredAgent, task: TaskDescription
313
270
  ) -> float:
314
- """Calculate how well an agent matches the task context."""
315
271
  score = 0.0
316
272
 
317
273
  agent_name_lower = agent.metadata.name.lower()
@@ -325,7 +281,6 @@ class AgentSelector:
325
281
  return min(score, 1.0)
326
282
 
327
283
  def _score_name_matches(self, agent_name_lower: str, task_text: str) -> float:
328
- """Score direct name matches between agent and task."""
329
284
  if any(keyword in agent_name_lower for keyword in task_text.split()):
330
285
  return 0.3
331
286
  return 0.0
@@ -333,7 +288,6 @@ class AgentSelector:
333
288
  def _score_description_matches(
334
289
  self, agent: RegisteredAgent, task_text: str
335
290
  ) -> float:
336
- """Score description word overlap."""
337
291
  if not agent.metadata.description:
338
292
  return 0.0
339
293
 
@@ -348,7 +302,6 @@ class AgentSelector:
348
302
  def _score_keyword_matches(
349
303
  self, agent: RegisteredAgent, task: TaskDescription
350
304
  ) -> float:
351
- """Score keyword/tag overlap."""
352
305
  if not task.keywords or not agent.metadata.tags:
353
306
  return 0.0
354
307
 
@@ -361,7 +314,6 @@ class AgentSelector:
361
314
  return 0.0
362
315
 
363
316
  def _score_special_patterns(self, agent_name_lower: str, task_text: str) -> float:
364
- """Score special pattern bonuses."""
365
317
  score = 0.0
366
318
 
367
319
  if "architect" in agent_name_lower and (
@@ -383,14 +335,11 @@ class AgentSelector:
383
335
  priority_bonus: float,
384
336
  required_capabilities: set[AgentCapability],
385
337
  ) -> str:
386
- """Generate human-readable reasoning for the score."""
387
338
  parts = []
388
339
 
389
- # Capability match
390
340
  overlap = len(required_capabilities & agent.metadata.capabilities)
391
341
  parts.append(f"Capabilities: {overlap}/{len(required_capabilities)} match")
392
342
 
393
- # Context relevance
394
343
  if context_score > 0.5:
395
344
  parts.append("High context relevance")
396
345
  elif context_score > 0.2:
@@ -398,7 +347,6 @@ class AgentSelector:
398
347
  else:
399
348
  parts.append("Low context relevance")
400
349
 
401
- # Source priority
402
350
  source_desc = {
403
351
  "crackerjack": "Built-in specialist",
404
352
  "user": "User agent",
@@ -406,7 +354,6 @@ class AgentSelector:
406
354
  }
407
355
  parts.append(source_desc.get(agent.metadata.source.value, "Unknown source"))
408
356
 
409
- # Special strengths
410
357
  if agent.metadata.capabilities:
411
358
  top_caps = list(agent.metadata.capabilities)[:2]
412
359
  cap_names = [cap.value.replace("_", " ") for cap in top_caps]
@@ -415,11 +362,9 @@ class AgentSelector:
415
362
  return " | ".join(parts)
416
363
 
417
364
  async def analyze_task_complexity(self, task: TaskDescription) -> dict[str, t.Any]:
418
- """Analyze task complexity and provide recommendations."""
419
365
  registry = await self.get_registry()
420
366
  required_capabilities = self._analyze_task_capabilities(task)
421
367
 
422
- # Get all agents that could handle this task
423
368
  all_scores = []
424
369
  for agent in registry.list_all_agents():
425
370
  score = await self._score_agent_for_task(agent, task, required_capabilities)
@@ -453,13 +398,12 @@ class AgentSelector:
453
398
  def _assess_complexity(
454
399
  self, capabilities: set[AgentCapability], scores: list[AgentScore]
455
400
  ) -> str:
456
- """Assess the complexity level of a task."""
457
401
  if len(capabilities) >= 4:
458
402
  return "high"
459
403
  elif len(capabilities) >= 2:
460
404
  return "medium"
461
405
  elif not scores or scores[0].final_score < 0.3:
462
- return "high" # No good matches = complex
406
+ return "high"
463
407
 
464
408
  return "low"
465
409
 
@@ -468,33 +412,28 @@ class AgentSelector:
468
412
  capabilities: set[AgentCapability],
469
413
  scores: list[AgentScore],
470
414
  ) -> list[str]:
471
- """Generate recommendations based on analysis."""
472
415
  recommendations = []
473
416
 
474
417
  if not scores:
475
- recommendations.append(
476
- "No suitable agents found - consider manual approach"
477
- )
418
+ recommendations.append("No suitable agents found-consider manual approach")
478
419
  return recommendations
479
420
 
480
421
  top_score = scores[0].final_score
481
422
 
482
423
  if top_score > 0.8:
483
424
  recommendations.append(
484
- "Excellent agent match found - high confidence execution"
425
+ "Excellent agent match found-high confidence execution"
485
426
  )
486
427
  elif top_score > 0.6:
487
- recommendations.append("Good agent match - should handle task well")
428
+ recommendations.append("Good agent match-should handle task well")
488
429
  elif top_score > 0.4:
489
- recommendations.append("Moderate match - may need supervision")
430
+ recommendations.append("Moderate match-may need supervision")
490
431
  else:
491
- recommendations.append("Weak matches - consider alternative approaches")
432
+ recommendations.append("Weak matches-consider alternative approaches")
492
433
 
493
- # Multi-agent recommendations
494
434
  if len(capabilities) > 2:
495
435
  recommendations.append("Consider multi-agent approach for complex task")
496
436
 
497
- # Source diversity
498
437
  sources = {score.agent.metadata.source for score in scores[:3]}
499
438
  if len(sources) > 1:
500
439
  recommendations.append("Multiple agent sources available for redundancy")
@@ -1,9 +1,3 @@
1
- """Integration layer for Intelligent Agent Selection System.
2
-
3
- Provides high-level API for integrating the intelligent agent system with
4
- existing crackerjack workflows and MCP tools.
5
- """
6
-
7
1
  import logging
8
2
  import typing as t
9
3
  from dataclasses import dataclass
@@ -22,8 +16,6 @@ from .agent_selector import TaskContext, TaskDescription
22
16
 
23
17
  @dataclass
24
18
  class SmartAgentResult:
25
- """Result from smart agent execution."""
26
-
27
19
  success: bool
28
20
  result: t.Any
29
21
  agents_used: list[str]
@@ -34,27 +26,22 @@ class SmartAgentResult:
34
26
 
35
27
 
36
28
  class IntelligentAgentSystem:
37
- """High-level interface to the intelligent agent system."""
38
-
39
29
  def __init__(self) -> None:
40
30
  self.logger = logging.getLogger(__name__)
41
31
  self._initialized = False
42
32
 
43
33
  async def initialize(self) -> None:
44
- """Initialize the intelligent agent system."""
45
34
  if self._initialized:
46
35
  return
47
36
 
48
37
  self.logger.info("Initializing Intelligent Agent System")
49
38
 
50
- # Initialize all components
51
39
  self.registry = await get_agent_registry()
52
40
  self.orchestrator = await get_agent_orchestrator()
53
41
  self.learning_system = await get_learning_system()
54
42
 
55
43
  self._initialized = True
56
44
 
57
- # Log system status
58
45
  stats = self.registry.get_agent_stats()
59
46
  self.logger.info(
60
47
  f"System initialized: {stats['total_agents']} agents available "
@@ -68,16 +55,13 @@ class IntelligentAgentSystem:
68
55
  strategy: ExecutionStrategy = ExecutionStrategy.SINGLE_BEST,
69
56
  context_data: AgentContext | None = None,
70
57
  ) -> SmartAgentResult:
71
- """Execute a task using intelligent agent selection."""
72
58
  await self.initialize()
73
59
 
74
- # Create task description
75
60
  task = TaskDescription(
76
61
  description=description,
77
62
  context=context,
78
63
  )
79
64
 
80
- # Get learning recommendations
81
65
  candidates = await self.orchestrator.selector.select_agents(
82
66
  task, max_candidates=5
83
67
  )
@@ -87,19 +71,14 @@ class IntelligentAgentSystem:
87
71
  task, candidate_names
88
72
  )
89
73
 
90
- # Apply learning to boost scores
91
74
  for candidate in candidates:
92
75
  agent_name = candidate.agent.metadata.name
93
76
  if agent_name in learning_recommendations:
94
- learning_boost = (
95
- learning_recommendations[agent_name] * 0.2
96
- ) # 20% boost max
77
+ learning_boost = learning_recommendations[agent_name] * 0.2
97
78
  candidate.final_score = min(1.0, candidate.final_score + learning_boost)
98
79
 
99
- # Re-sort by updated scores
100
80
  candidates.sort(key=lambda c: c.final_score, reverse=True)
101
81
 
102
- # Create execution request
103
82
  request = ExecutionRequest(
104
83
  task=task,
105
84
  strategy=strategy,
@@ -107,10 +86,8 @@ class IntelligentAgentSystem:
107
86
  context=context_data,
108
87
  )
109
88
 
110
- # Execute with orchestrator
111
89
  result = await self.orchestrator.execute(request)
112
90
 
113
- # Record results for learning
114
91
  if candidates:
115
92
  best_candidate = candidates[0]
116
93
  await self.learning_system.record_execution(
@@ -122,7 +99,6 @@ class IntelligentAgentSystem:
122
99
  error_message=result.error_message,
123
100
  )
124
101
 
125
- # Create smart result
126
102
  return SmartAgentResult(
127
103
  success=result.success,
128
104
  result=result.primary_result,
@@ -139,10 +115,8 @@ class IntelligentAgentSystem:
139
115
  context: AgentContext,
140
116
  use_learning: bool = True,
141
117
  ) -> FixResult:
142
- """Handle a crackerjack Issue using intelligent agent selection."""
143
118
  await self.initialize()
144
119
 
145
- # Convert issue to task description
146
120
  task_context = self._map_issue_to_task_context(issue)
147
121
 
148
122
  task = TaskDescription(
@@ -152,18 +126,15 @@ class IntelligentAgentSystem:
152
126
  priority=self._map_severity_to_priority(issue.severity),
153
127
  )
154
128
 
155
- # Execute smart task
156
129
  smart_result = await self.execute_smart_task(
157
130
  description=task.description,
158
131
  context=task_context,
159
132
  context_data=context,
160
133
  )
161
134
 
162
- # Convert result back to FixResult
163
135
  if smart_result.success and isinstance(smart_result.result, FixResult):
164
136
  return smart_result.result
165
137
 
166
- # Create fallback FixResult
167
138
  return FixResult(
168
139
  success=smart_result.success,
169
140
  confidence=smart_result.confidence,
@@ -181,7 +152,6 @@ class IntelligentAgentSystem:
181
152
  description: str,
182
153
  context: TaskContext | None = None,
183
154
  ) -> tuple[str, float] | None:
184
- """Get the best agent for a task without executing it."""
185
155
  await self.initialize()
186
156
 
187
157
  task = TaskDescription(description=description, context=context)
@@ -192,14 +162,12 @@ class IntelligentAgentSystem:
192
162
  return None
193
163
 
194
164
  async def analyze_task_complexity(self, description: str) -> dict[str, t.Any]:
195
- """Analyze a task's complexity and provide recommendations."""
196
165
  await self.initialize()
197
166
 
198
167
  task = TaskDescription(description=description)
199
168
  return await self.orchestrator.selector.analyze_task_complexity(task)
200
169
 
201
170
  def _map_issue_to_task_context(self, issue: Issue) -> TaskContext | None:
202
- """Map crackerjack Issue type to TaskContext."""
203
171
  from crackerjack.agents.base import IssueType
204
172
 
205
173
  mapping = {
@@ -220,7 +188,6 @@ class IntelligentAgentSystem:
220
188
  return mapping.get(issue.type) or TaskContext.GENERAL
221
189
 
222
190
  def _map_severity_to_priority(self, severity: t.Any) -> int:
223
- """Map crackerjack Priority to task priority."""
224
191
  from crackerjack.agents.base import Priority
225
192
 
226
193
  mapping = {
@@ -232,7 +199,6 @@ class IntelligentAgentSystem:
232
199
  return mapping.get(severity) or 50
233
200
 
234
201
  async def get_system_status(self) -> dict[str, t.Any]:
235
- """Get comprehensive system status."""
236
202
  await self.initialize()
237
203
 
238
204
  registry_stats = self.registry.get_agent_stats()
@@ -247,12 +213,10 @@ class IntelligentAgentSystem:
247
213
  }
248
214
 
249
215
 
250
- # Global intelligent agent system
251
216
  _intelligent_system_instance: IntelligentAgentSystem | None = None
252
217
 
253
218
 
254
219
  async def get_intelligent_agent_system() -> IntelligentAgentSystem:
255
- """Get or create the global intelligent agent system."""
256
220
  global _intelligent_system_instance
257
221
 
258
222
  if _intelligent_system_instance is None:
@@ -261,12 +225,10 @@ async def get_intelligent_agent_system() -> IntelligentAgentSystem:
261
225
  return _intelligent_system_instance
262
226
 
263
227
 
264
- # Convenience functions for common use cases
265
228
  async def smart_fix_issue(
266
229
  issue: Issue,
267
230
  context: AgentContext,
268
231
  ) -> FixResult:
269
- """Fix an issue using intelligent agent selection."""
270
232
  system = await get_intelligent_agent_system()
271
233
  return await system.handle_crackerjack_issue(issue, context)
272
234
 
@@ -276,7 +238,6 @@ async def smart_execute_task(
276
238
  context: TaskContext | None = None,
277
239
  strategy: ExecutionStrategy = ExecutionStrategy.SINGLE_BEST,
278
240
  ) -> SmartAgentResult:
279
- """Execute a task using intelligent agent selection."""
280
241
  system = await get_intelligent_agent_system()
281
242
  return await system.execute_smart_task(description, context, strategy)
282
243
 
@@ -285,6 +246,5 @@ async def get_smart_recommendation(
285
246
  description: str,
286
247
  context: TaskContext | None = None,
287
248
  ) -> tuple[str, float] | None:
288
- """Get a smart agent recommendation without executing."""
289
249
  system = await get_intelligent_agent_system()
290
250
  return await system.get_best_agent_for_task(description, context)
@@ -311,12 +311,12 @@ class WorkflowManager:
311
311
 
312
312
  def _handle_task_without_executor(self, task: Task) -> bool:
313
313
  task.skip()
314
- self.console.print(f"[yellow]⏭️ Skipped {task.name} (no executor)[/yellow]")
314
+ self.console.print(f"[yellow]⏭️ Skipped {task.name} (no executor)[/ yellow]")
315
315
  return True
316
316
 
317
317
  def _execute_task_with_executor(self, task: Task) -> bool:
318
318
  task.start()
319
- self.console.print(f"[blue]🔄 Running {task.name}...[/blue]")
319
+ self.console.print(f"[blue]🔄 Running {task.name}...[/ blue]")
320
320
 
321
321
  try:
322
322
  return self._try_execute_task(task)
@@ -334,9 +334,9 @@ class WorkflowManager:
334
334
  def _display_task_result(self, task: Task, success: bool) -> None:
335
335
  if success:
336
336
  duration_str = f" ({task.duration: .1f}s)" if task.duration else ""
337
- self.console.print(f"[green]✅ {task.name}{duration_str}[/green]")
337
+ self.console.print(f"[green]✅ {task.name}{duration_str}[/ green]")
338
338
  else:
339
- self.console.print(f"[red]❌ {task.name} failed[/red]")
339
+ self.console.print(f"[red]❌ {task.name} failed[/ red]")
340
340
 
341
341
  def _handle_task_exception(self, task: Task, e: Exception) -> bool:
342
342
  error = CrackerjackError(
@@ -344,7 +344,7 @@ class WorkflowManager:
344
344
  error_code=ErrorCode.COMMAND_EXECUTION_ERROR,
345
345
  )
346
346
  task.fail(error)
347
- self.console.print(f"[red]💥 {task.name} crashed: {e}[/red]")
347
+ self.console.print(f"[red]💥 {task.name} crashed: {e}[/ red]")
348
348
  return False
349
349
 
350
350
  def display_task_tree(self) -> None:
@@ -587,11 +587,11 @@ class InteractiveCLI:
587
587
  )
588
588
  self.create_dynamic_workflow(options)
589
589
 
590
- self.console.print("[bold blue]🚀 Starting Interactive Workflow[/bold blue]")
590
+ self.console.print("[bold blue]🚀 Starting Interactive Workflow[/ bold blue]")
591
591
  self.workflow.display_task_tree()
592
592
 
593
593
  if not Confirm.ask("Continue with workflow?"):
594
- self.console.print("[yellow]Workflow cancelled by user[/yellow]")
594
+ self.console.print("[yellow]Workflow cancelled by user[/ yellow]")
595
595
  return False
596
596
 
597
597
  return self._execute_workflow_loop()
@@ -626,7 +626,7 @@ class InteractiveCLI:
626
626
  ]
627
627
 
628
628
  if pending_tasks:
629
- self.console.print("[red]❌ Workflow stuck - unresolved dependencies[/red]")
629
+ self.console.print("[red]❌ Workflow stuck-unresolved dependencies[/ red]")
630
630
  return False
631
631
  return True
632
632
 
@@ -645,7 +645,7 @@ class InteractiveCLI:
645
645
  def _display_workflow_summary(self) -> None:
646
646
  summary = self.workflow.get_workflow_summary()
647
647
 
648
- self.console.print("\n[bold]📊 Workflow Summary[/bold]")
648
+ self.console.print("\n[bold]📊 Workflow Summary[/ bold]")
649
649
 
650
650
  table = Table(show_header=True, header_style="bold magenta")
651
651
  table.add_column("Status", style="cyan")