crackerjack 0.30.3__py3-none-any.whl → 0.31.4__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 +1005 -0
  2. crackerjack/RULES.md +380 -0
  3. crackerjack/__init__.py +42 -13
  4. crackerjack/__main__.py +225 -299
  5. crackerjack/agents/__init__.py +41 -0
  6. crackerjack/agents/architect_agent.py +281 -0
  7. crackerjack/agents/base.py +169 -0
  8. crackerjack/agents/coordinator.py +512 -0
  9. crackerjack/agents/documentation_agent.py +498 -0
  10. crackerjack/agents/dry_agent.py +388 -0
  11. crackerjack/agents/formatting_agent.py +245 -0
  12. crackerjack/agents/import_optimization_agent.py +281 -0
  13. crackerjack/agents/performance_agent.py +669 -0
  14. crackerjack/agents/proactive_agent.py +104 -0
  15. crackerjack/agents/refactoring_agent.py +788 -0
  16. crackerjack/agents/security_agent.py +529 -0
  17. crackerjack/agents/test_creation_agent.py +652 -0
  18. crackerjack/agents/test_specialist_agent.py +486 -0
  19. crackerjack/agents/tracker.py +212 -0
  20. crackerjack/api.py +560 -0
  21. crackerjack/cli/__init__.py +24 -0
  22. crackerjack/cli/facade.py +104 -0
  23. crackerjack/cli/handlers.py +267 -0
  24. crackerjack/cli/interactive.py +471 -0
  25. crackerjack/cli/options.py +401 -0
  26. crackerjack/cli/utils.py +18 -0
  27. crackerjack/code_cleaner.py +618 -928
  28. crackerjack/config/__init__.py +19 -0
  29. crackerjack/config/hooks.py +218 -0
  30. crackerjack/core/__init__.py +0 -0
  31. crackerjack/core/async_workflow_orchestrator.py +406 -0
  32. crackerjack/core/autofix_coordinator.py +200 -0
  33. crackerjack/core/container.py +104 -0
  34. crackerjack/core/enhanced_container.py +542 -0
  35. crackerjack/core/performance.py +243 -0
  36. crackerjack/core/phase_coordinator.py +561 -0
  37. crackerjack/core/proactive_workflow.py +316 -0
  38. crackerjack/core/session_coordinator.py +289 -0
  39. crackerjack/core/workflow_orchestrator.py +640 -0
  40. crackerjack/dynamic_config.py +94 -103
  41. crackerjack/errors.py +263 -41
  42. crackerjack/executors/__init__.py +11 -0
  43. crackerjack/executors/async_hook_executor.py +431 -0
  44. crackerjack/executors/cached_hook_executor.py +242 -0
  45. crackerjack/executors/hook_executor.py +345 -0
  46. crackerjack/executors/individual_hook_executor.py +669 -0
  47. crackerjack/intelligence/__init__.py +44 -0
  48. crackerjack/intelligence/adaptive_learning.py +751 -0
  49. crackerjack/intelligence/agent_orchestrator.py +551 -0
  50. crackerjack/intelligence/agent_registry.py +414 -0
  51. crackerjack/intelligence/agent_selector.py +502 -0
  52. crackerjack/intelligence/integration.py +290 -0
  53. crackerjack/interactive.py +576 -315
  54. crackerjack/managers/__init__.py +11 -0
  55. crackerjack/managers/async_hook_manager.py +135 -0
  56. crackerjack/managers/hook_manager.py +137 -0
  57. crackerjack/managers/publish_manager.py +411 -0
  58. crackerjack/managers/test_command_builder.py +151 -0
  59. crackerjack/managers/test_executor.py +435 -0
  60. crackerjack/managers/test_manager.py +258 -0
  61. crackerjack/managers/test_manager_backup.py +1124 -0
  62. crackerjack/managers/test_progress.py +144 -0
  63. crackerjack/mcp/__init__.py +0 -0
  64. crackerjack/mcp/cache.py +336 -0
  65. crackerjack/mcp/client_runner.py +104 -0
  66. crackerjack/mcp/context.py +615 -0
  67. crackerjack/mcp/dashboard.py +636 -0
  68. crackerjack/mcp/enhanced_progress_monitor.py +479 -0
  69. crackerjack/mcp/file_monitor.py +336 -0
  70. crackerjack/mcp/progress_components.py +569 -0
  71. crackerjack/mcp/progress_monitor.py +949 -0
  72. crackerjack/mcp/rate_limiter.py +332 -0
  73. crackerjack/mcp/server.py +22 -0
  74. crackerjack/mcp/server_core.py +244 -0
  75. crackerjack/mcp/service_watchdog.py +501 -0
  76. crackerjack/mcp/state.py +395 -0
  77. crackerjack/mcp/task_manager.py +257 -0
  78. crackerjack/mcp/tools/__init__.py +17 -0
  79. crackerjack/mcp/tools/core_tools.py +249 -0
  80. crackerjack/mcp/tools/error_analyzer.py +308 -0
  81. crackerjack/mcp/tools/execution_tools.py +370 -0
  82. crackerjack/mcp/tools/execution_tools_backup.py +1097 -0
  83. crackerjack/mcp/tools/intelligence_tool_registry.py +80 -0
  84. crackerjack/mcp/tools/intelligence_tools.py +314 -0
  85. crackerjack/mcp/tools/monitoring_tools.py +502 -0
  86. crackerjack/mcp/tools/proactive_tools.py +384 -0
  87. crackerjack/mcp/tools/progress_tools.py +141 -0
  88. crackerjack/mcp/tools/utility_tools.py +341 -0
  89. crackerjack/mcp/tools/workflow_executor.py +360 -0
  90. crackerjack/mcp/websocket/__init__.py +14 -0
  91. crackerjack/mcp/websocket/app.py +39 -0
  92. crackerjack/mcp/websocket/endpoints.py +559 -0
  93. crackerjack/mcp/websocket/jobs.py +253 -0
  94. crackerjack/mcp/websocket/server.py +116 -0
  95. crackerjack/mcp/websocket/websocket_handler.py +78 -0
  96. crackerjack/mcp/websocket_server.py +10 -0
  97. crackerjack/models/__init__.py +31 -0
  98. crackerjack/models/config.py +93 -0
  99. crackerjack/models/config_adapter.py +230 -0
  100. crackerjack/models/protocols.py +118 -0
  101. crackerjack/models/task.py +154 -0
  102. crackerjack/monitoring/ai_agent_watchdog.py +450 -0
  103. crackerjack/monitoring/regression_prevention.py +638 -0
  104. crackerjack/orchestration/__init__.py +0 -0
  105. crackerjack/orchestration/advanced_orchestrator.py +970 -0
  106. crackerjack/orchestration/execution_strategies.py +341 -0
  107. crackerjack/orchestration/test_progress_streamer.py +636 -0
  108. crackerjack/plugins/__init__.py +15 -0
  109. crackerjack/plugins/base.py +200 -0
  110. crackerjack/plugins/hooks.py +246 -0
  111. crackerjack/plugins/loader.py +335 -0
  112. crackerjack/plugins/managers.py +259 -0
  113. crackerjack/py313.py +8 -3
  114. crackerjack/services/__init__.py +22 -0
  115. crackerjack/services/cache.py +314 -0
  116. crackerjack/services/config.py +347 -0
  117. crackerjack/services/config_integrity.py +99 -0
  118. crackerjack/services/contextual_ai_assistant.py +516 -0
  119. crackerjack/services/coverage_ratchet.py +347 -0
  120. crackerjack/services/debug.py +736 -0
  121. crackerjack/services/dependency_monitor.py +617 -0
  122. crackerjack/services/enhanced_filesystem.py +439 -0
  123. crackerjack/services/file_hasher.py +151 -0
  124. crackerjack/services/filesystem.py +395 -0
  125. crackerjack/services/git.py +165 -0
  126. crackerjack/services/health_metrics.py +611 -0
  127. crackerjack/services/initialization.py +847 -0
  128. crackerjack/services/log_manager.py +286 -0
  129. crackerjack/services/logging.py +174 -0
  130. crackerjack/services/metrics.py +578 -0
  131. crackerjack/services/pattern_cache.py +362 -0
  132. crackerjack/services/pattern_detector.py +515 -0
  133. crackerjack/services/performance_benchmarks.py +653 -0
  134. crackerjack/services/security.py +163 -0
  135. crackerjack/services/server_manager.py +234 -0
  136. crackerjack/services/smart_scheduling.py +144 -0
  137. crackerjack/services/tool_version_service.py +61 -0
  138. crackerjack/services/unified_config.py +437 -0
  139. crackerjack/services/version_checker.py +248 -0
  140. crackerjack/slash_commands/__init__.py +14 -0
  141. crackerjack/slash_commands/init.md +122 -0
  142. crackerjack/slash_commands/run.md +163 -0
  143. crackerjack/slash_commands/status.md +127 -0
  144. crackerjack-0.31.4.dist-info/METADATA +742 -0
  145. crackerjack-0.31.4.dist-info/RECORD +148 -0
  146. crackerjack-0.31.4.dist-info/entry_points.txt +2 -0
  147. crackerjack/.gitignore +0 -34
  148. crackerjack/.libcst.codemod.yaml +0 -18
  149. crackerjack/.pdm.toml +0 -1
  150. crackerjack/crackerjack.py +0 -3805
  151. crackerjack/pyproject.toml +0 -286
  152. crackerjack-0.30.3.dist-info/METADATA +0 -1290
  153. crackerjack-0.30.3.dist-info/RECORD +0 -16
  154. {crackerjack-0.30.3.dist-info → crackerjack-0.31.4.dist-info}/WHEEL +0 -0
  155. {crackerjack-0.30.3.dist-info → crackerjack-0.31.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,450 @@
1
+ """
2
+ AI Agent Watchdog System
3
+
4
+ Monitors AI agent execution for failures, performance issues, and regression patterns.
5
+ Provides real-time oversight to prevent surprise failures and ensure reliable auto-fixing.
6
+ """
7
+
8
+ import asyncio
9
+ import json
10
+ import typing as t
11
+ from dataclasses import dataclass, field
12
+ from datetime import datetime, timedelta
13
+ from pathlib import Path
14
+
15
+ from crackerjack.agents.base import FixResult, Issue, IssueType, Priority
16
+ from crackerjack.agents.coordinator import AgentCoordinator
17
+ from rich.console import Console
18
+ from rich.live import Live
19
+ from rich.table import Table
20
+
21
+
22
+ @dataclass
23
+ class AgentPerformanceMetrics:
24
+ """Track agent performance over time."""
25
+
26
+ agent_name: str
27
+ total_issues_handled: int = 0
28
+ successful_fixes: int = 0
29
+ failed_fixes: int = 0
30
+ average_confidence: float = 0.0
31
+ average_execution_time: float = 0.0
32
+ issue_types_handled: dict[IssueType, int] = field(default_factory=dict)
33
+ recent_failures: list[str] = field(default_factory=list)
34
+ last_successful_fix: datetime | None = None
35
+ regression_patterns: list[str] = field(default_factory=list)
36
+
37
+
38
+ @dataclass
39
+ class WatchdogAlert:
40
+ """Watchdog alert for monitoring issues."""
41
+
42
+ level: str # "warning", "error", "critical"
43
+ message: str
44
+ agent_name: str | None = None
45
+ issue_id: str | None = None
46
+ timestamp: datetime = field(default_factory=datetime.now)
47
+ details: dict[str, t.Any] = field(default_factory=dict)
48
+
49
+
50
+ class AIAgentWatchdog:
51
+ """Monitors AI agent execution and prevents regression failures."""
52
+
53
+ def __init__(self, console: Console | None = None):
54
+ self.console = console or Console()
55
+ self.performance_metrics: dict[str, AgentPerformanceMetrics] = {}
56
+ self.alerts: list[WatchdogAlert] = []
57
+ self.known_regressions: set[str] = {
58
+ "detect_agent_needs_complexity_22",
59
+ "refactoring_agent_no_changes",
60
+ "agent_coordination_infinite_loop",
61
+ }
62
+ self.monitoring_active = False
63
+ self.execution_history: list[dict[str, t.Any]] = []
64
+
65
+ # Performance thresholds
66
+ self.max_execution_time = 30.0 # seconds
67
+ self.min_success_rate = 0.6 # 60%
68
+ self.max_recent_failures = 3
69
+
70
+ async def start_monitoring(self, coordinator: AgentCoordinator):
71
+ """Start monitoring agent coordinator."""
72
+ self.monitoring_active = True
73
+ self.console.print("šŸ” [bold green]AI Agent Watchdog Started[/bold green]")
74
+
75
+ # Initialize metrics for all agents
76
+ coordinator.initialize_agents()
77
+ for agent in coordinator.agents:
78
+ agent_name = agent.__class__.__name__
79
+ if agent_name not in self.performance_metrics:
80
+ self.performance_metrics[agent_name] = AgentPerformanceMetrics(
81
+ agent_name=agent_name
82
+ )
83
+
84
+ self.console.print(
85
+ f"šŸ“Š Monitoring {len(coordinator.agents)} agents: {[a.__class__.__name__ for a in coordinator.agents]}"
86
+ )
87
+
88
+ def stop_monitoring(self):
89
+ """Stop monitoring and generate final report."""
90
+ self.monitoring_active = False
91
+ self.console.print("šŸ” [bold yellow]AI Agent Watchdog Stopped[/bold yellow]")
92
+ self._generate_final_report()
93
+
94
+ async def monitor_issue_handling(
95
+ self, agent_name: str, issue: Issue, result: FixResult, execution_time: float
96
+ ):
97
+ """Monitor individual issue handling by agents."""
98
+ if not self.monitoring_active:
99
+ return
100
+
101
+ metrics = self.performance_metrics.get(agent_name)
102
+ if not metrics:
103
+ metrics = AgentPerformanceMetrics(agent_name=agent_name)
104
+ self.performance_metrics[agent_name] = metrics
105
+
106
+ # Update metrics
107
+ metrics.total_issues_handled += 1
108
+ if result.success:
109
+ metrics.successful_fixes += 1
110
+ metrics.last_successful_fix = datetime.now()
111
+ else:
112
+ metrics.failed_fixes += 1
113
+ failure_key = f"{issue.type.value}_{issue.message[:50]}"
114
+ metrics.recent_failures.append(failure_key)
115
+
116
+ # Keep only recent failures
117
+ if len(metrics.recent_failures) > self.max_recent_failures:
118
+ metrics.recent_failures.pop(0)
119
+
120
+ # Update averages
121
+ total_fixes = metrics.successful_fixes + metrics.failed_fixes
122
+ metrics.average_confidence = (
123
+ metrics.average_confidence * (total_fixes - 1) + result.confidence
124
+ ) / total_fixes
125
+ metrics.average_execution_time = (
126
+ metrics.average_execution_time * (total_fixes - 1) + execution_time
127
+ ) / total_fixes
128
+
129
+ # Track issue types
130
+ metrics.issue_types_handled[issue.type] = (
131
+ metrics.issue_types_handled.get(issue.type, 0) + 1
132
+ )
133
+
134
+ # Check for alerts
135
+ await self._check_for_alerts(agent_name, issue, result, execution_time, metrics)
136
+
137
+ # Store execution history
138
+ self.execution_history.append(
139
+ {
140
+ "timestamp": datetime.now().isoformat(),
141
+ "agent": agent_name,
142
+ "issue_type": issue.type.value,
143
+ "issue_id": issue.id,
144
+ "success": result.success,
145
+ "confidence": result.confidence,
146
+ "execution_time": execution_time,
147
+ }
148
+ )
149
+
150
+ # Keep history manageable
151
+ if len(self.execution_history) > 1000:
152
+ self.execution_history = self.execution_history[-500:]
153
+
154
+ async def _check_for_alerts(
155
+ self,
156
+ agent_name: str,
157
+ issue: Issue,
158
+ result: FixResult,
159
+ execution_time: float,
160
+ metrics: AgentPerformanceMetrics,
161
+ ):
162
+ """Check for alert conditions."""
163
+ alerts = []
164
+
165
+ # Performance alerts
166
+ if execution_time > self.max_execution_time:
167
+ alerts.append(
168
+ WatchdogAlert(
169
+ level="warning",
170
+ message=f"Agent took {execution_time:.1f}s (>{self.max_execution_time}s threshold)",
171
+ agent_name=agent_name,
172
+ issue_id=issue.id,
173
+ details={
174
+ "execution_time": execution_time,
175
+ "threshold": self.max_execution_time,
176
+ },
177
+ )
178
+ )
179
+
180
+ # Success rate alerts
181
+ if metrics.total_issues_handled >= 5: # Only after handling multiple issues
182
+ success_rate = metrics.successful_fixes / metrics.total_issues_handled
183
+ if success_rate < self.min_success_rate:
184
+ alerts.append(
185
+ WatchdogAlert(
186
+ level="error",
187
+ message=f"Agent success rate {success_rate:.1%} below {self.min_success_rate:.1%} threshold",
188
+ agent_name=agent_name,
189
+ details={
190
+ "success_rate": success_rate,
191
+ "total_handled": metrics.total_issues_handled,
192
+ },
193
+ )
194
+ )
195
+
196
+ # Regression pattern alerts
197
+ failure_signature = f"{agent_name}_{issue.type.value}_{issue.message[:30]}"
198
+ if failure_signature in self.known_regressions and not result.success:
199
+ alerts.append(
200
+ WatchdogAlert(
201
+ level="critical",
202
+ message="REGRESSION DETECTED: Known failure pattern returned",
203
+ agent_name=agent_name,
204
+ issue_id=issue.id,
205
+ details={"regression_pattern": failure_signature},
206
+ )
207
+ )
208
+
209
+ # Repeated failure alerts
210
+ if len(metrics.recent_failures) >= self.max_recent_failures:
211
+ unique_failures = set(metrics.recent_failures)
212
+ if len(unique_failures) == 1: # Same failure repeated
213
+ alerts.append(
214
+ WatchdogAlert(
215
+ level="error",
216
+ message=f"Agent repeating same failure {len(metrics.recent_failures)} times",
217
+ agent_name=agent_name,
218
+ details={"repeated_failure": list(unique_failures)[0]},
219
+ )
220
+ )
221
+
222
+ # Add alerts
223
+ for alert in alerts:
224
+ self.alerts.append(alert)
225
+ await self._handle_alert(alert)
226
+
227
+ async def _handle_alert(self, alert: WatchdogAlert):
228
+ """Handle watchdog alert."""
229
+ colors = {"warning": "yellow", "error": "red", "critical": "bold red"}
230
+ color = colors.get(alert.level) or "white"
231
+
232
+ icon = {"warning": "āš ļø", "error": "🚨", "critical": "šŸ”„"}[alert.level]
233
+
234
+ self.console.print(
235
+ f"{icon} [bold {color}]{alert.level.upper()}[/bold {color}]: {alert.message}"
236
+ )
237
+ if alert.agent_name:
238
+ self.console.print(f" Agent: {alert.agent_name}")
239
+ if alert.issue_id:
240
+ self.console.print(f" Issue: {alert.issue_id}")
241
+
242
+ # For critical alerts, suggest immediate actions
243
+ if alert.level == "critical":
244
+ self.console.print(" [bold red]IMMEDIATE ACTION REQUIRED[/bold red]")
245
+ if "regression" in alert.message.lower():
246
+ self.console.print(" → Run regression tests immediately")
247
+ self.console.print(" → Check agent implementation for recent changes")
248
+
249
+ def create_monitoring_dashboard(self) -> Table:
250
+ """Create real-time monitoring dashboard."""
251
+ table = Table(
252
+ title="AI Agent Watchdog Dashboard",
253
+ header_style="bold magenta",
254
+ )
255
+
256
+ table.add_column("Agent", style="cyan", width=20)
257
+ table.add_column("Issues Handled", justify="center")
258
+ table.add_column("Success Rate", justify="center")
259
+ table.add_column("Avg Confidence", justify="center")
260
+ table.add_column("Avg Time (s)", justify="center")
261
+ table.add_column("Last Success", justify="center")
262
+ table.add_column("Status", justify="center")
263
+
264
+ for agent_name, metrics in self.performance_metrics.items():
265
+ if metrics.total_issues_handled == 0:
266
+ continue
267
+
268
+ success_rate = metrics.successful_fixes / metrics.total_issues_handled
269
+
270
+ # Status determination
271
+ status_color = "green"
272
+ status_text = "āœ… OK"
273
+
274
+ if success_rate < self.min_success_rate:
275
+ status_color = "red"
276
+ status_text = "🚨 FAILING"
277
+ elif len(metrics.recent_failures) >= 2:
278
+ status_color = "yellow"
279
+ status_text = "āš ļø WATCH"
280
+
281
+ last_success = "Never"
282
+ if metrics.last_successful_fix:
283
+ delta = datetime.now() - metrics.last_successful_fix
284
+ if delta.days > 0:
285
+ last_success = f"{delta.days}d ago"
286
+ elif delta.seconds > 3600:
287
+ last_success = f"{delta.seconds // 3600}h ago"
288
+ else:
289
+ last_success = f"{delta.seconds // 60}m ago"
290
+
291
+ table.add_row(
292
+ agent_name,
293
+ str(metrics.total_issues_handled),
294
+ f"{success_rate:.1%}",
295
+ f"{metrics.average_confidence:.2f}",
296
+ f"{metrics.average_execution_time:.1f}",
297
+ last_success,
298
+ f"[{status_color}]{status_text}[/{status_color}]",
299
+ )
300
+
301
+ return table
302
+
303
+ def get_recent_alerts(self, hours: int = 1) -> list[WatchdogAlert]:
304
+ """Get alerts from the last N hours."""
305
+ cutoff = datetime.now() - timedelta(hours=hours)
306
+ return [alert for alert in self.alerts if alert.timestamp > cutoff]
307
+
308
+ def _generate_final_report(self):
309
+ """Generate final monitoring report."""
310
+ self.console.print("\nšŸ“Š [bold]AI Agent Watchdog Final Report[/bold]")
311
+
312
+ # Summary statistics
313
+ total_issues = sum(
314
+ m.total_issues_handled for m in self.performance_metrics.values()
315
+ )
316
+ total_successes = sum(
317
+ m.successful_fixes for m in self.performance_metrics.values()
318
+ )
319
+
320
+ if total_issues > 0:
321
+ overall_success_rate = total_successes / total_issues
322
+ self.console.print(
323
+ f"Overall Success Rate: {overall_success_rate:.1%} ({total_successes}/{total_issues})"
324
+ )
325
+
326
+ # Alert summary
327
+ alert_counts = {"warning": 0, "error": 0, "critical": 0}
328
+ for alert in self.alerts:
329
+ alert_counts[alert.level] += 1
330
+
331
+ self.console.print(
332
+ f"Alerts: {alert_counts['critical']} Critical, {alert_counts['error']} Errors, {alert_counts['warning']} Warnings"
333
+ )
334
+
335
+ # Top performing agents
336
+ if self.performance_metrics:
337
+ best_agent = max(
338
+ (
339
+ m
340
+ for m in self.performance_metrics.values()
341
+ if m.total_issues_handled > 0
342
+ ),
343
+ key=lambda m: m.successful_fixes / m.total_issues_handled,
344
+ default=None,
345
+ )
346
+ if best_agent:
347
+ success_rate = (
348
+ best_agent.successful_fixes / best_agent.total_issues_handled
349
+ )
350
+ self.console.print(
351
+ f"Top Performer: {best_agent.agent_name} ({success_rate:.1%} success rate)"
352
+ )
353
+
354
+ # Save detailed report
355
+ self._save_monitoring_report()
356
+
357
+ def _save_monitoring_report(self):
358
+ """Save detailed monitoring report to file."""
359
+ report_data = {
360
+ "timestamp": datetime.now().isoformat(),
361
+ "metrics": {
362
+ name: {
363
+ "total_issues": m.total_issues_handled,
364
+ "successful_fixes": m.successful_fixes,
365
+ "failed_fixes": m.failed_fixes,
366
+ "success_rate": m.successful_fixes / m.total_issues_handled
367
+ if m.total_issues_handled > 0
368
+ else 0,
369
+ "average_confidence": m.average_confidence,
370
+ "average_execution_time": m.average_execution_time,
371
+ "issue_types": {
372
+ k.value: v for k, v in m.issue_types_handled.items()
373
+ },
374
+ "recent_failures": m.recent_failures,
375
+ }
376
+ for name, m in self.performance_metrics.items()
377
+ },
378
+ "alerts": [
379
+ {
380
+ "level": a.level,
381
+ "message": a.message,
382
+ "agent": a.agent_name,
383
+ "issue_id": a.issue_id,
384
+ "timestamp": a.timestamp.isoformat(),
385
+ "details": a.details,
386
+ }
387
+ for a in self.alerts
388
+ ],
389
+ "execution_history": self.execution_history,
390
+ }
391
+
392
+ report_file = Path(".crackerjack") / "ai_agent_monitoring_report.json"
393
+ report_file.parent.mkdir(exist_ok=True)
394
+
395
+ with open(report_file, "w") as f:
396
+ json.dump(report_data, f, indent=2)
397
+
398
+ self.console.print(f"šŸ“„ Detailed report saved: {report_file}")
399
+
400
+
401
+ async def run_agent_monitoring_demo():
402
+ """Demo of the AI agent monitoring system."""
403
+ console = Console()
404
+ watchdog = AIAgentWatchdog(console)
405
+
406
+ # Simulate agent context and coordinator
407
+ from crackerjack.agents.base import AgentContext
408
+
409
+ context = AgentContext(project_path=Path.cwd())
410
+ coordinator = AgentCoordinator(context)
411
+
412
+ await watchdog.start_monitoring(coordinator)
413
+
414
+ # Simulate some agent executions with monitoring
415
+ with Live(
416
+ watchdog.create_monitoring_dashboard(), refresh_per_second=1, console=console
417
+ ) as live:
418
+ for i in range(10):
419
+ # Simulate issue handling
420
+ issue = Issue(
421
+ id=f"demo_{i}",
422
+ type=IssueType.COMPLEXITY if i % 2 == 0 else IssueType.FORMATTING,
423
+ severity=Priority.HIGH,
424
+ message=f"Demo issue {i}",
425
+ file_path="demo.py",
426
+ )
427
+
428
+ # Simulate varying results
429
+ success = i % 3 != 0 # Fail every 3rd attempt
430
+ result = FixResult(
431
+ success=success,
432
+ confidence=0.8 if success else 0.3,
433
+ fixes_applied=["Demo fix"] if success else [],
434
+ remaining_issues=[] if success else ["Demo failure"],
435
+ )
436
+
437
+ execution_time = 2.0 + (i % 5) * 0.5 # Varying execution times
438
+
439
+ await watchdog.monitor_issue_handling(
440
+ "DemoAgent", issue, result, execution_time
441
+ )
442
+ live.update(watchdog.create_monitoring_dashboard())
443
+
444
+ await asyncio.sleep(0.5) # Simulate work
445
+
446
+ watchdog.stop_monitoring()
447
+
448
+
449
+ if __name__ == "__main__":
450
+ asyncio.run(run_agent_monitoring_demo())