crackerjack 0.31.10__py3-none-any.whl → 0.31.13__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 +50 -9
  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.13.dist-info}/METADATA +197 -12
  150. crackerjack-0.31.13.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.13.dist-info}/WHEEL +0 -0
  154. {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/entry_points.txt +0 -0
  155. {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,3 @@
1
- """Multi-Agent Execution Orchestrator.
2
-
3
- Coordinates execution of multiple agents with smart routing, fallback strategies,
4
- and result aggregation.
5
- """
6
-
7
1
  import asyncio
8
2
  import logging
9
3
  import typing as t
@@ -22,26 +16,20 @@ from .agent_selector import AgentScore, AgentSelector, TaskDescription
22
16
 
23
17
 
24
18
  class ExecutionStrategy(Enum):
25
- """Strategy for multi-agent execution."""
26
-
27
- SINGLE_BEST = "single_best" # Use only the highest-scored agent
28
- PARALLEL = "parallel" # Run multiple agents in parallel
29
- SEQUENTIAL = "sequential" # Run agents one by one until success
30
- CONSENSUS = "consensus" # Run multiple agents and compare results
19
+ SINGLE_BEST = "single_best"
20
+ PARALLEL = "parallel"
21
+ SEQUENTIAL = "sequential"
22
+ CONSENSUS = "consensus"
31
23
 
32
24
 
33
25
  class ExecutionMode(Enum):
34
- """Mode of execution."""
35
-
36
- AUTONOMOUS = "autonomous" # Full automation
37
- GUIDED = "guided" # With human oversight
38
- ADVISORY = "advisory" # Recommendations only
26
+ AUTONOMOUS = "autonomous"
27
+ GUIDED = "guided"
28
+ ADVISORY = "advisory"
39
29
 
40
30
 
41
31
  @dataclass
42
32
  class ExecutionRequest:
43
- """Request for agent execution."""
44
-
45
33
  task: TaskDescription
46
34
  strategy: ExecutionStrategy = ExecutionStrategy.SINGLE_BEST
47
35
  mode: ExecutionMode = ExecutionMode.AUTONOMOUS
@@ -53,11 +41,9 @@ class ExecutionRequest:
53
41
 
54
42
  @dataclass
55
43
  class ExecutionResult:
56
- """Result of agent execution."""
57
-
58
44
  success: bool
59
- primary_result: t.Any | None # Main result from best agent
60
- all_results: list[tuple[RegisteredAgent, t.Any]] # All agent results
45
+ primary_result: t.Any | None
46
+ all_results: list[tuple[RegisteredAgent, t.Any]]
61
47
  execution_time: float
62
48
  agents_used: list[str]
63
49
  strategy_used: ExecutionStrategy
@@ -66,8 +52,6 @@ class ExecutionResult:
66
52
 
67
53
 
68
54
  class AgentOrchestrator:
69
- """Multi-agent execution orchestrator."""
70
-
71
55
  def __init__(
72
56
  self,
73
57
  registry: AgentRegistry | None = None,
@@ -79,7 +63,6 @@ class AgentOrchestrator:
79
63
  self._execution_stats: dict[str, int] = {}
80
64
 
81
65
  async def execute(self, request: ExecutionRequest) -> ExecutionResult:
82
- """Execute a request using the intelligent agent system."""
83
66
  start_time = asyncio.get_event_loop().time()
84
67
 
85
68
  try:
@@ -88,7 +71,6 @@ class AgentOrchestrator:
88
71
  f"(strategy: {request.strategy.value})"
89
72
  )
90
73
 
91
- # Get agent candidates
92
74
  candidates = await self.selector.select_agents(
93
75
  request.task, max_candidates=request.max_agents
94
76
  )
@@ -100,7 +82,6 @@ class AgentOrchestrator:
100
82
  request.strategy,
101
83
  )
102
84
 
103
- # Execute based on strategy
104
85
  if request.strategy == ExecutionStrategy.SINGLE_BEST:
105
86
  result = await self._execute_single_best(request, candidates)
106
87
  elif request.strategy == ExecutionStrategy.PARALLEL:
@@ -115,14 +96,13 @@ class AgentOrchestrator:
115
96
  execution_time = asyncio.get_event_loop().time() - start_time
116
97
  result.execution_time = execution_time
117
98
 
118
- # Update stats
119
99
  for agent_name in result.agents_used:
120
100
  self._execution_stats[agent_name] = (
121
101
  self._execution_stats.get(agent_name, 0) + 1
122
102
  )
123
103
 
124
104
  self.logger.info(
125
- f"Execution completed in {execution_time:.2f}s: "
105
+ f"Execution completed in {execution_time: .2f}s: "
126
106
  f"{'success' if result.success else 'failure'} "
127
107
  f"using {len(result.agents_used)} agents"
128
108
  )
@@ -142,7 +122,6 @@ class AgentOrchestrator:
142
122
  request: ExecutionRequest,
143
123
  candidates: list[AgentScore],
144
124
  ) -> ExecutionResult:
145
- """Execute using the single best agent."""
146
125
  best_candidate = candidates[0]
147
126
 
148
127
  try:
@@ -152,14 +131,13 @@ class AgentOrchestrator:
152
131
  success=True,
153
132
  primary_result=result,
154
133
  all_results=[(best_candidate.agent, result)],
155
- execution_time=0.0, # Will be set by caller
134
+ execution_time=0.0,
156
135
  agents_used=[best_candidate.agent.metadata.name],
157
136
  strategy_used=ExecutionStrategy.SINGLE_BEST,
158
137
  recommendations=self._generate_recommendations(best_candidate),
159
138
  )
160
139
 
161
140
  except Exception as e:
162
- # Fallback to next best agent if available
163
141
  if len(candidates) > 1 and request.fallback_to_system:
164
142
  self.logger.warning(
165
143
  f"Primary agent {best_candidate.agent.metadata.name} failed: {e}. "
@@ -172,7 +150,7 @@ class AgentOrchestrator:
172
150
  mode=request.mode,
173
151
  max_agents=len(candidates) - 1,
174
152
  timeout_seconds=request.timeout_seconds,
175
- fallback_to_system=False, # Prevent infinite recursion
153
+ fallback_to_system=False,
176
154
  context=request.context,
177
155
  )
178
156
 
@@ -193,7 +171,6 @@ class AgentOrchestrator:
193
171
  request: ExecutionRequest,
194
172
  candidates: list[AgentScore],
195
173
  ) -> ExecutionResult:
196
- """Execute multiple agents in parallel."""
197
174
  tasks = []
198
175
  agents_to_execute = candidates[: request.max_agents]
199
176
 
@@ -203,7 +180,6 @@ class AgentOrchestrator:
203
180
  )
204
181
  tasks.append((candidate.agent, task))
205
182
 
206
- # Wait for all tasks to complete
207
183
  results = []
208
184
  successful_results = []
209
185
 
@@ -218,12 +194,10 @@ class AgentOrchestrator:
218
194
  except Exception as e:
219
195
  results.append((agent, e))
220
196
 
221
- # Choose best successful result
222
197
  primary_result = None
223
198
  agents_used = []
224
199
 
225
200
  if successful_results:
226
- # Use result from highest-priority agent
227
201
  successful_results.sort(key=lambda x: x[0].metadata.priority, reverse=True)
228
202
  primary_result = successful_results[0][1]
229
203
  agents_used = [agent.metadata.name for agent, _ in successful_results]
@@ -243,7 +217,6 @@ class AgentOrchestrator:
243
217
  request: ExecutionRequest,
244
218
  candidates: list[AgentScore],
245
219
  ) -> ExecutionResult:
246
- """Execute agents sequentially until one succeeds."""
247
220
  results = []
248
221
 
249
222
  for candidate in candidates[: request.max_agents]:
@@ -255,7 +228,6 @@ class AgentOrchestrator:
255
228
 
256
229
  results.append((candidate.agent, result))
257
230
 
258
- # Success - return immediately
259
231
  return ExecutionResult(
260
232
  success=True,
261
233
  primary_result=result,
@@ -273,7 +245,6 @@ class AgentOrchestrator:
273
245
  )
274
246
  continue
275
247
 
276
- # All agents failed
277
248
  return ExecutionResult(
278
249
  success=False,
279
250
  primary_result=None,
@@ -289,13 +260,11 @@ class AgentOrchestrator:
289
260
  request: ExecutionRequest,
290
261
  candidates: list[AgentScore],
291
262
  ) -> ExecutionResult:
292
- """Execute multiple agents and build consensus from results."""
293
- # First run parallel execution
294
263
  parallel_request = ExecutionRequest(
295
264
  task=request.task,
296
265
  strategy=ExecutionStrategy.PARALLEL,
297
266
  mode=request.mode,
298
- max_agents=min(request.max_agents, 3), # Limit for consensus
267
+ max_agents=min(request.max_agents, 3),
299
268
  timeout_seconds=request.timeout_seconds,
300
269
  fallback_to_system=False,
301
270
  context=request.context,
@@ -306,7 +275,6 @@ class AgentOrchestrator:
306
275
  if not parallel_result.success:
307
276
  return parallel_result
308
277
 
309
- # Analyze results for consensus
310
278
  successful_results = [
311
279
  (agent, result)
312
280
  for agent, result in parallel_result.all_results
@@ -314,10 +282,8 @@ class AgentOrchestrator:
314
282
  ]
315
283
 
316
284
  if len(successful_results) < 2:
317
- # Not enough results for consensus - return best result
318
285
  return parallel_result
319
286
 
320
- # Build consensus (simplified - could be much more sophisticated)
321
287
  consensus_result = self._build_consensus(successful_results)
322
288
 
323
289
  return ExecutionResult(
@@ -333,15 +299,11 @@ class AgentOrchestrator:
333
299
  async def _execute_agent(
334
300
  self, agent: RegisteredAgent, request: ExecutionRequest
335
301
  ) -> t.Any:
336
- """Execute a specific agent."""
337
302
  if agent.agent is not None:
338
- # Crackerjack agent
339
303
  return await self._execute_crackerjack_agent(agent, request)
340
304
  elif agent.agent_path is not None:
341
- # User agent
342
305
  return await self._execute_user_agent(agent, request)
343
306
  elif agent.subagent_type is not None:
344
- # System agent
345
307
  return await self._execute_system_agent(agent, request)
346
308
  else:
347
309
  raise ValueError(f"Invalid agent configuration: {agent.metadata.name}")
@@ -349,7 +311,6 @@ class AgentOrchestrator:
349
311
  async def _execute_agent_safe(
350
312
  self, agent: RegisteredAgent, request: ExecutionRequest
351
313
  ) -> t.Any:
352
- """Execute an agent with exception handling."""
353
314
  try:
354
315
  return await self._execute_agent(agent, request)
355
316
  except Exception as e:
@@ -360,20 +321,17 @@ class AgentOrchestrator:
360
321
  agent: RegisteredAgent,
361
322
  request: ExecutionRequest,
362
323
  ) -> t.Any:
363
- """Execute a built-in crackerjack agent."""
364
324
  if not agent.agent:
365
325
  raise ValueError("No crackerjack agent instance available")
366
326
 
367
- # Convert task to Issue for crackerjack agents
368
327
  issue = Issue(
369
328
  id="orchestrated_task",
370
329
  type=self._map_task_to_issue_type(request.task),
371
330
  severity=self._map_task_priority_to_severity(request.task),
372
331
  message=request.task.description,
373
- file_path=None, # Could be extracted from task if needed
332
+ file_path=None,
374
333
  )
375
334
 
376
- # Execute agent
377
335
  result = await agent.agent.analyze_and_fix(issue)
378
336
  return result
379
337
 
@@ -382,11 +340,8 @@ class AgentOrchestrator:
382
340
  agent: RegisteredAgent,
383
341
  request: ExecutionRequest,
384
342
  ) -> t.Any:
385
- """Execute a user agent via Task tool."""
386
- # Import Task tool dynamically to avoid circular imports
387
343
  from crackerjack.mcp.tools.core_tools import create_task_with_subagent
388
344
 
389
- # Use Task tool to execute user agent
390
345
  result = await create_task_with_subagent(
391
346
  description=f"Execute task using {agent.metadata.name}",
392
347
  prompt=request.task.description,
@@ -400,14 +355,11 @@ class AgentOrchestrator:
400
355
  agent: RegisteredAgent,
401
356
  request: ExecutionRequest,
402
357
  ) -> t.Any:
403
- """Execute a system agent via Task tool."""
404
358
  if not agent.subagent_type:
405
359
  raise ValueError("No subagent type specified for system agent")
406
360
 
407
- # Import Task tool dynamically
408
361
  from crackerjack.mcp.tools.core_tools import create_task_with_subagent
409
362
 
410
- # Use Task tool to execute system agent
411
363
  result = await create_task_with_subagent(
412
364
  description=f"Execute task using {agent.metadata.name}",
413
365
  prompt=request.task.description,
@@ -417,11 +369,8 @@ class AgentOrchestrator:
417
369
  return result
418
370
 
419
371
  def _map_task_to_issue_type(self, task: TaskDescription):
420
- """Map task context to Issue type for crackerjack agents."""
421
- # Import IssueType here to avoid circular imports
422
372
  from crackerjack.agents.base import IssueType
423
373
 
424
- # Simple mapping - could be more sophisticated
425
374
  context_map = {
426
375
  "code_quality": IssueType.FORMATTING,
427
376
  "refactoring": IssueType.COMPLEXITY,
@@ -434,7 +383,6 @@ class AgentOrchestrator:
434
383
  if task.context and task.context.value in context_map:
435
384
  return context_map[task.context.value]
436
385
 
437
- # Analyze task description for hints
438
386
  desc_lower = task.description.lower()
439
387
  if "test" in desc_lower:
440
388
  return IssueType.TEST_FAILURE
@@ -445,10 +393,9 @@ class AgentOrchestrator:
445
393
  elif "format" in desc_lower:
446
394
  return IssueType.FORMATTING
447
395
 
448
- return IssueType.FORMATTING # Default
396
+ return IssueType.FORMATTING
449
397
 
450
398
  def _map_task_priority_to_severity(self, task: TaskDescription):
451
- """Map task priority to Issue severity."""
452
399
  from crackerjack.agents.base import Priority
453
400
 
454
401
  if task.priority >= 80:
@@ -459,14 +406,10 @@ class AgentOrchestrator:
459
406
  return Priority.LOW
460
407
 
461
408
  def _build_consensus(self, results: list[tuple[RegisteredAgent, t.Any]]) -> t.Any:
462
- """Build consensus from multiple agent results."""
463
- # Simplified consensus - could be much more sophisticated
464
- # For now, just return the result from the highest-priority agent
465
409
  results.sort(key=lambda x: x[0].metadata.priority, reverse=True)
466
410
  return results[0][1]
467
411
 
468
412
  def _generate_recommendations(self, candidate: AgentScore) -> list[str]:
469
- """Generate recommendations based on agent selection."""
470
413
  recommendations = []
471
414
 
472
415
  if candidate.final_score > 0.8:
@@ -491,7 +434,6 @@ class AgentOrchestrator:
491
434
  start_time: float,
492
435
  strategy: ExecutionStrategy,
493
436
  ) -> ExecutionResult:
494
- """Create an error result."""
495
437
  execution_time = asyncio.get_event_loop().time() - start_time
496
438
 
497
439
  return ExecutionResult(
@@ -505,7 +447,6 @@ class AgentOrchestrator:
505
447
  )
506
448
 
507
449
  def get_execution_stats(self) -> dict[str, t.Any]:
508
- """Get execution statistics."""
509
450
  from operator import itemgetter
510
451
 
511
452
  return {
@@ -519,10 +460,8 @@ class AgentOrchestrator:
519
460
  }
520
461
 
521
462
  async def analyze_task_routing(self, task: TaskDescription) -> dict[str, t.Any]:
522
- """Analyze how a task would be routed through the system."""
523
463
  analysis = await self.selector.analyze_task_complexity(task)
524
464
 
525
- # Add orchestration recommendations
526
465
  if analysis["complexity_level"] == "high":
527
466
  analysis["recommended_strategy"] = ExecutionStrategy.CONSENSUS
528
467
  elif analysis["candidate_count"] > 3:
@@ -535,12 +474,10 @@ class AgentOrchestrator:
535
474
  return analysis
536
475
 
537
476
 
538
- # Global orchestrator instance
539
477
  _orchestrator_instance: AgentOrchestrator | None = None
540
478
 
541
479
 
542
480
  async def get_agent_orchestrator() -> AgentOrchestrator:
543
- """Get or create the global agent orchestrator."""
544
481
  global _orchestrator_instance
545
482
 
546
483
  if _orchestrator_instance is None:
@@ -1,9 +1,3 @@
1
- """Intelligent Agent Registry System.
2
-
3
- Unifies access to crackerjack agents, user agents, and system agents with smart
4
- prioritization and capability mapping.
5
- """
6
-
7
1
  import logging
8
2
  import typing as t
9
3
  from dataclasses import dataclass
@@ -14,16 +8,12 @@ from crackerjack.agents.base import SubAgent, agent_registry
14
8
 
15
9
 
16
10
  class AgentSource(Enum):
17
- """Source of an agent."""
18
-
19
11
  CRACKERJACK = "crackerjack"
20
12
  USER = "user"
21
13
  SYSTEM = "system"
22
14
 
23
15
 
24
16
  class AgentCapability(Enum):
25
- """Agent capability categories."""
26
-
27
17
  ARCHITECTURE = "architecture"
28
18
  REFACTORING = "refactoring"
29
19
  TESTING = "testing"
@@ -38,13 +28,11 @@ class AgentCapability(Enum):
38
28
 
39
29
  @dataclass
40
30
  class AgentMetadata:
41
- """Metadata about an agent."""
42
-
43
31
  name: str
44
32
  source: AgentSource
45
33
  capabilities: set[AgentCapability]
46
- priority: int # Higher is better
47
- confidence_factor: float # Multiplier for confidence scores
34
+ priority: int
35
+ confidence_factor: float
48
36
  description: str
49
37
  model: str | None = None
50
38
  tags: list[str] | None = None
@@ -52,17 +40,13 @@ class AgentMetadata:
52
40
 
53
41
  @dataclass
54
42
  class RegisteredAgent:
55
- """A registered agent with metadata and access."""
56
-
57
43
  metadata: AgentMetadata
58
- agent: SubAgent | None = None # None for user/system agents
59
- agent_path: Path | None = None # Path to user agent file
60
- subagent_type: str | None = None # For system agents
44
+ agent: SubAgent | None = None
45
+ agent_path: Path | None = None
46
+ subagent_type: str | None = None
61
47
 
62
48
 
63
49
  class AgentRegistry:
64
- """Registry of all available agents across all systems."""
65
-
66
50
  def __init__(self) -> None:
67
51
  self.logger = logging.getLogger(__name__)
68
52
  self._agents: dict[str, RegisteredAgent] = {}
@@ -70,15 +54,12 @@ class AgentRegistry:
70
54
  self._user_agent_cache: dict[str, dict[str, t.Any]] = {}
71
55
 
72
56
  async def initialize(self) -> None:
73
- """Initialize the registry with all available agents."""
74
57
  self.logger.info("Initializing Intelligent Agent Registry")
75
58
 
76
- # Load agents in priority order
77
59
  await self._register_crackerjack_agents()
78
60
  await self._register_user_agents()
79
61
  await self._register_system_agents()
80
62
 
81
- # Build capability mapping
82
63
  self._build_capability_map()
83
64
 
84
65
  self.logger.info(
@@ -89,13 +70,10 @@ class AgentRegistry:
89
70
  )
90
71
 
91
72
  async def _register_crackerjack_agents(self) -> None:
92
- """Register built-in crackerjack agents."""
93
73
  self.logger.debug("Registering crackerjack agents")
94
74
 
95
- # Get all registered crackerjack agents
96
75
  from crackerjack.agents.base import AgentContext
97
76
 
98
- # Create a dummy context to get agents
99
77
  context = AgentContext(
100
78
  project_path=Path.cwd(),
101
79
  )
@@ -109,7 +87,7 @@ class AgentRegistry:
109
87
  name=agent.name,
110
88
  source=AgentSource.CRACKERJACK,
111
89
  capabilities=capabilities,
112
- priority=100, # Highest priority
90
+ priority=100,
113
91
  confidence_factor=1.0,
114
92
  description=f"Built-in crackerjack {agent.__class__.__name__}",
115
93
  )
@@ -123,7 +101,6 @@ class AgentRegistry:
123
101
  self.logger.debug(f"Registered crackerjack agent: {agent.name}")
124
102
 
125
103
  async def _register_user_agents(self) -> None:
126
- """Register user agents from ~/.claude/agents/."""
127
104
  self.logger.debug("Registering user agents")
128
105
 
129
106
  user_agents_dir = Path.home() / ".claude" / "agents"
@@ -141,7 +118,7 @@ class AgentRegistry:
141
118
  name=agent_data["name"],
142
119
  source=AgentSource.USER,
143
120
  capabilities=capabilities,
144
- priority=80, # Second priority
121
+ priority=80,
145
122
  confidence_factor=0.9,
146
123
  description=agent_data.get("description", "User agent"),
147
124
  model=agent_data.get("model"),
@@ -161,10 +138,8 @@ class AgentRegistry:
161
138
  self.logger.warning(f"Failed to parse user agent {agent_file}: {e}")
162
139
 
163
140
  async def _register_system_agents(self) -> None:
164
- """Register built-in system agents from Task tool."""
165
141
  self.logger.debug("Registering system agents")
166
142
 
167
- # Known system agents from Task tool
168
143
  system_agents = [
169
144
  (
170
145
  "general-purpose",
@@ -186,7 +161,7 @@ class AgentRegistry:
186
161
  name=agent_name,
187
162
  source=AgentSource.SYSTEM,
188
163
  capabilities=capabilities,
189
- priority=60, # Lowest priority
164
+ priority=60,
190
165
  confidence_factor=0.7,
191
166
  description=description,
192
167
  )
@@ -200,7 +175,6 @@ class AgentRegistry:
200
175
  self.logger.debug(f"Registered system agent: {agent_name}")
201
176
 
202
177
  async def _parse_user_agent_file(self, agent_file: Path) -> dict[str, t.Any] | None:
203
- """Parse a user agent markdown file."""
204
178
  try:
205
179
  content = agent_file.read_text(encoding="utf-8")
206
180
  return self._extract_agent_data_from_content(content)
@@ -209,8 +183,7 @@ class AgentRegistry:
209
183
  return None
210
184
 
211
185
  def _extract_agent_data_from_content(self, content: str) -> dict[str, t.Any] | None:
212
- """Extract agent data from file content."""
213
- if not content.startswith("---\n"):
186
+ if not content.startswith("- --\n"):
214
187
  return None
215
188
 
216
189
  lines = content.split("\n")
@@ -222,30 +195,26 @@ class AgentRegistry:
222
195
  return self._build_agent_data(lines, yaml_end)
223
196
 
224
197
  def _find_yaml_end_marker(self, lines: list[str]) -> int:
225
- """Find the end marker for YAML frontmatter."""
226
198
  for i, line in enumerate(lines[1:], 1):
227
- if line == "---":
199
+ if line == "- --":
228
200
  return i
229
201
  return -1
230
202
 
231
203
  def _build_agent_data(self, lines: list[str], yaml_end: int) -> dict[str, t.Any]:
232
- """Build agent data from parsed lines."""
233
204
  yaml_lines = lines[1:yaml_end]
234
205
  agent_data = {}
235
206
 
236
207
  for line in yaml_lines:
237
- if ":" in line:
238
- key, value = line.split(":", 1)
208
+ if ": " in line:
209
+ key, value = line.split(": ", 1)
239
210
  agent_data[key.strip()] = value.strip()
240
211
 
241
212
  agent_data["content"] = "\n".join(lines[yaml_end + 1 :])
242
213
  return agent_data
243
214
 
244
215
  def _infer_capabilities_from_agent(self, agent: SubAgent) -> set[AgentCapability]:
245
- """Infer capabilities from a crackerjack agent."""
246
216
  capabilities = set()
247
217
 
248
- # Map agent class names to capabilities
249
218
  class_name = agent.__class__.__name__.lower()
250
219
 
251
220
  if "architect" in class_name:
@@ -269,7 +238,6 @@ class AgentRegistry:
269
238
  if "dry" in class_name:
270
239
  capabilities.add(AgentCapability.REFACTORING)
271
240
 
272
- # Fallback to general code analysis
273
241
  if not capabilities:
274
242
  capabilities.add(AgentCapability.CODE_ANALYSIS)
275
243
 
@@ -278,7 +246,6 @@ class AgentRegistry:
278
246
  def _infer_capabilities_from_user_agent(
279
247
  self, agent_data: dict[str, t.Any]
280
248
  ) -> set[AgentCapability]:
281
- """Infer capabilities from user agent metadata."""
282
249
  capabilities = set()
283
250
 
284
251
  name = agent_data.get("name", "").lower()
@@ -287,7 +254,6 @@ class AgentRegistry:
287
254
 
288
255
  text = f"{name} {description} {content}"
289
256
 
290
- # Keyword mapping
291
257
  keyword_map = {
292
258
  AgentCapability.ARCHITECTURE: [
293
259
  "architect",
@@ -320,7 +286,6 @@ class AgentRegistry:
320
286
  if any(keyword in text for keyword in keywords):
321
287
  capabilities.add(capability)
322
288
 
323
- # Fallback
324
289
  if not capabilities:
325
290
  capabilities.add(AgentCapability.CODE_ANALYSIS)
326
291
 
@@ -329,7 +294,6 @@ class AgentRegistry:
329
294
  def _infer_capabilities_from_system_agent(
330
295
  self, name: str, description: str
331
296
  ) -> set[AgentCapability]:
332
- """Infer capabilities from system agent."""
333
297
  capabilities = set()
334
298
 
335
299
  text = f"{name} {description}".lower()
@@ -341,14 +305,12 @@ class AgentRegistry:
341
305
  if "output" in text or "style" in text:
342
306
  capabilities.add(AgentCapability.FORMATTING)
343
307
 
344
- # Fallback
345
308
  if not capabilities:
346
309
  capabilities.add(AgentCapability.CODE_ANALYSIS)
347
310
 
348
311
  return capabilities
349
312
 
350
313
  def _build_capability_map(self) -> None:
351
- """Build mapping from capabilities to agent names."""
352
314
  self._capability_map.clear()
353
315
 
354
316
  for agent_name, registered_agent in self._agents.items():
@@ -357,7 +319,6 @@ class AgentRegistry:
357
319
  self._capability_map[capability] = []
358
320
  self._capability_map[capability].append(agent_name)
359
321
 
360
- # Sort by priority within each capability
361
322
  for agent_names in self._capability_map.values():
362
323
  agent_names.sort(
363
324
  key=lambda name: self._agents[name].metadata.priority, reverse=True
@@ -366,36 +327,30 @@ class AgentRegistry:
366
327
  def get_agents_by_capability(
367
328
  self, capability: AgentCapability
368
329
  ) -> list[RegisteredAgent]:
369
- """Get agents that have a specific capability, sorted by priority."""
370
330
  agent_names = self._capability_map.get(capability, [])
371
331
  return [self._agents[name] for name in agent_names]
372
332
 
373
333
  def get_agent_by_name(self, name: str) -> RegisteredAgent | None:
374
- """Get a specific agent by name."""
375
334
  return self._agents.get(name)
376
335
 
377
336
  def list_all_agents(self) -> list[RegisteredAgent]:
378
- """List all registered agents, sorted by priority."""
379
337
  agents = list(self._agents.values())
380
338
  agents.sort(key=lambda a: a.metadata.priority, reverse=True)
381
339
  return agents
382
340
 
383
341
  def get_agent_stats(self) -> dict[str, t.Any]:
384
- """Get statistics about registered agents."""
385
342
  stats: dict[str, t.Any] = {
386
343
  "total_agents": len(self._agents),
387
344
  "by_source": {},
388
345
  "by_capability": {},
389
346
  }
390
347
 
391
- # Count by source
392
348
  for source in AgentSource:
393
349
  count = len(
394
350
  [a for a in self._agents.values() if a.metadata.source == source]
395
351
  )
396
352
  stats["by_source"][source.value] = count
397
353
 
398
- # Count by capability
399
354
  for capability in AgentCapability:
400
355
  count = len(self._capability_map.get(capability, []))
401
356
  stats["by_capability"][capability.value] = count
@@ -403,12 +358,10 @@ class AgentRegistry:
403
358
  return stats
404
359
 
405
360
 
406
- # Global registry instance
407
361
  agent_registry_instance = AgentRegistry()
408
362
 
409
363
 
410
364
  async def get_agent_registry() -> AgentRegistry:
411
- """Get the initialized agent registry."""
412
365
  if not agent_registry_instance._agents:
413
366
  await agent_registry_instance.initialize()
414
367
  return agent_registry_instance