crackerjack 0.32.0__py3-none-any.whl → 0.33.1__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 (200) hide show
  1. crackerjack/__main__.py +1350 -34
  2. crackerjack/adapters/__init__.py +17 -0
  3. crackerjack/adapters/lsp_client.py +358 -0
  4. crackerjack/adapters/rust_tool_adapter.py +194 -0
  5. crackerjack/adapters/rust_tool_manager.py +193 -0
  6. crackerjack/adapters/skylos_adapter.py +231 -0
  7. crackerjack/adapters/zuban_adapter.py +560 -0
  8. crackerjack/agents/base.py +7 -3
  9. crackerjack/agents/coordinator.py +271 -33
  10. crackerjack/agents/documentation_agent.py +9 -15
  11. crackerjack/agents/dry_agent.py +3 -15
  12. crackerjack/agents/formatting_agent.py +1 -1
  13. crackerjack/agents/import_optimization_agent.py +36 -180
  14. crackerjack/agents/performance_agent.py +17 -98
  15. crackerjack/agents/performance_helpers.py +7 -31
  16. crackerjack/agents/proactive_agent.py +1 -3
  17. crackerjack/agents/refactoring_agent.py +16 -85
  18. crackerjack/agents/refactoring_helpers.py +7 -42
  19. crackerjack/agents/security_agent.py +9 -48
  20. crackerjack/agents/test_creation_agent.py +356 -513
  21. crackerjack/agents/test_specialist_agent.py +0 -4
  22. crackerjack/api.py +6 -25
  23. crackerjack/cli/cache_handlers.py +204 -0
  24. crackerjack/cli/cache_handlers_enhanced.py +683 -0
  25. crackerjack/cli/facade.py +100 -0
  26. crackerjack/cli/handlers.py +224 -9
  27. crackerjack/cli/interactive.py +6 -4
  28. crackerjack/cli/options.py +642 -55
  29. crackerjack/cli/utils.py +2 -1
  30. crackerjack/code_cleaner.py +58 -117
  31. crackerjack/config/global_lock_config.py +8 -48
  32. crackerjack/config/hooks.py +53 -62
  33. crackerjack/core/async_workflow_orchestrator.py +24 -34
  34. crackerjack/core/autofix_coordinator.py +3 -17
  35. crackerjack/core/enhanced_container.py +64 -6
  36. crackerjack/core/file_lifecycle.py +12 -89
  37. crackerjack/core/performance.py +2 -2
  38. crackerjack/core/performance_monitor.py +15 -55
  39. crackerjack/core/phase_coordinator.py +257 -218
  40. crackerjack/core/resource_manager.py +14 -90
  41. crackerjack/core/service_watchdog.py +62 -95
  42. crackerjack/core/session_coordinator.py +149 -0
  43. crackerjack/core/timeout_manager.py +14 -72
  44. crackerjack/core/websocket_lifecycle.py +13 -78
  45. crackerjack/core/workflow_orchestrator.py +558 -240
  46. crackerjack/docs/INDEX.md +11 -0
  47. crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
  48. crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
  49. crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
  50. crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
  51. crackerjack/docs/generated/api/SERVICES.md +1252 -0
  52. crackerjack/documentation/__init__.py +31 -0
  53. crackerjack/documentation/ai_templates.py +756 -0
  54. crackerjack/documentation/dual_output_generator.py +765 -0
  55. crackerjack/documentation/mkdocs_integration.py +518 -0
  56. crackerjack/documentation/reference_generator.py +977 -0
  57. crackerjack/dynamic_config.py +55 -50
  58. crackerjack/executors/async_hook_executor.py +10 -15
  59. crackerjack/executors/cached_hook_executor.py +117 -43
  60. crackerjack/executors/hook_executor.py +8 -34
  61. crackerjack/executors/hook_lock_manager.py +26 -183
  62. crackerjack/executors/individual_hook_executor.py +13 -11
  63. crackerjack/executors/lsp_aware_hook_executor.py +270 -0
  64. crackerjack/executors/tool_proxy.py +417 -0
  65. crackerjack/hooks/lsp_hook.py +79 -0
  66. crackerjack/intelligence/adaptive_learning.py +25 -10
  67. crackerjack/intelligence/agent_orchestrator.py +2 -5
  68. crackerjack/intelligence/agent_registry.py +34 -24
  69. crackerjack/intelligence/agent_selector.py +5 -7
  70. crackerjack/interactive.py +17 -6
  71. crackerjack/managers/async_hook_manager.py +0 -1
  72. crackerjack/managers/hook_manager.py +79 -1
  73. crackerjack/managers/publish_manager.py +66 -13
  74. crackerjack/managers/test_command_builder.py +5 -17
  75. crackerjack/managers/test_executor.py +1 -3
  76. crackerjack/managers/test_manager.py +109 -7
  77. crackerjack/managers/test_manager_backup.py +10 -9
  78. crackerjack/mcp/cache.py +2 -2
  79. crackerjack/mcp/client_runner.py +1 -1
  80. crackerjack/mcp/context.py +191 -68
  81. crackerjack/mcp/dashboard.py +7 -5
  82. crackerjack/mcp/enhanced_progress_monitor.py +31 -28
  83. crackerjack/mcp/file_monitor.py +30 -23
  84. crackerjack/mcp/progress_components.py +31 -21
  85. crackerjack/mcp/progress_monitor.py +50 -53
  86. crackerjack/mcp/rate_limiter.py +6 -6
  87. crackerjack/mcp/server_core.py +161 -32
  88. crackerjack/mcp/service_watchdog.py +2 -1
  89. crackerjack/mcp/state.py +4 -7
  90. crackerjack/mcp/task_manager.py +11 -9
  91. crackerjack/mcp/tools/core_tools.py +174 -33
  92. crackerjack/mcp/tools/error_analyzer.py +3 -2
  93. crackerjack/mcp/tools/execution_tools.py +15 -12
  94. crackerjack/mcp/tools/execution_tools_backup.py +42 -30
  95. crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
  96. crackerjack/mcp/tools/intelligence_tools.py +5 -2
  97. crackerjack/mcp/tools/monitoring_tools.py +33 -70
  98. crackerjack/mcp/tools/proactive_tools.py +24 -11
  99. crackerjack/mcp/tools/progress_tools.py +5 -8
  100. crackerjack/mcp/tools/utility_tools.py +20 -14
  101. crackerjack/mcp/tools/workflow_executor.py +62 -40
  102. crackerjack/mcp/websocket/app.py +8 -0
  103. crackerjack/mcp/websocket/endpoints.py +352 -357
  104. crackerjack/mcp/websocket/jobs.py +40 -57
  105. crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
  106. crackerjack/mcp/websocket/server.py +7 -25
  107. crackerjack/mcp/websocket/websocket_handler.py +6 -17
  108. crackerjack/mixins/__init__.py +3 -0
  109. crackerjack/mixins/error_handling.py +145 -0
  110. crackerjack/models/config.py +21 -1
  111. crackerjack/models/config_adapter.py +49 -1
  112. crackerjack/models/protocols.py +176 -107
  113. crackerjack/models/resource_protocols.py +55 -210
  114. crackerjack/models/task.py +3 -0
  115. crackerjack/monitoring/ai_agent_watchdog.py +13 -13
  116. crackerjack/monitoring/metrics_collector.py +426 -0
  117. crackerjack/monitoring/regression_prevention.py +8 -8
  118. crackerjack/monitoring/websocket_server.py +643 -0
  119. crackerjack/orchestration/advanced_orchestrator.py +11 -6
  120. crackerjack/orchestration/coverage_improvement.py +3 -3
  121. crackerjack/orchestration/execution_strategies.py +26 -6
  122. crackerjack/orchestration/test_progress_streamer.py +8 -5
  123. crackerjack/plugins/base.py +2 -2
  124. crackerjack/plugins/hooks.py +7 -0
  125. crackerjack/plugins/managers.py +11 -8
  126. crackerjack/security/__init__.py +0 -1
  127. crackerjack/security/audit.py +90 -105
  128. crackerjack/services/anomaly_detector.py +392 -0
  129. crackerjack/services/api_extractor.py +615 -0
  130. crackerjack/services/backup_service.py +2 -2
  131. crackerjack/services/bounded_status_operations.py +15 -152
  132. crackerjack/services/cache.py +127 -1
  133. crackerjack/services/changelog_automation.py +395 -0
  134. crackerjack/services/config.py +18 -11
  135. crackerjack/services/config_merge.py +30 -85
  136. crackerjack/services/config_template.py +506 -0
  137. crackerjack/services/contextual_ai_assistant.py +48 -22
  138. crackerjack/services/coverage_badge_service.py +171 -0
  139. crackerjack/services/coverage_ratchet.py +41 -17
  140. crackerjack/services/debug.py +3 -3
  141. crackerjack/services/dependency_analyzer.py +460 -0
  142. crackerjack/services/dependency_monitor.py +14 -11
  143. crackerjack/services/documentation_generator.py +491 -0
  144. crackerjack/services/documentation_service.py +675 -0
  145. crackerjack/services/enhanced_filesystem.py +6 -5
  146. crackerjack/services/enterprise_optimizer.py +865 -0
  147. crackerjack/services/error_pattern_analyzer.py +676 -0
  148. crackerjack/services/file_hasher.py +1 -1
  149. crackerjack/services/git.py +41 -45
  150. crackerjack/services/health_metrics.py +10 -8
  151. crackerjack/services/heatmap_generator.py +735 -0
  152. crackerjack/services/initialization.py +30 -33
  153. crackerjack/services/input_validator.py +5 -97
  154. crackerjack/services/intelligent_commit.py +327 -0
  155. crackerjack/services/log_manager.py +15 -12
  156. crackerjack/services/logging.py +4 -3
  157. crackerjack/services/lsp_client.py +628 -0
  158. crackerjack/services/memory_optimizer.py +409 -0
  159. crackerjack/services/metrics.py +42 -33
  160. crackerjack/services/parallel_executor.py +416 -0
  161. crackerjack/services/pattern_cache.py +1 -1
  162. crackerjack/services/pattern_detector.py +6 -6
  163. crackerjack/services/performance_benchmarks.py +250 -576
  164. crackerjack/services/performance_cache.py +382 -0
  165. crackerjack/services/performance_monitor.py +565 -0
  166. crackerjack/services/predictive_analytics.py +510 -0
  167. crackerjack/services/quality_baseline.py +234 -0
  168. crackerjack/services/quality_baseline_enhanced.py +646 -0
  169. crackerjack/services/quality_intelligence.py +785 -0
  170. crackerjack/services/regex_patterns.py +605 -524
  171. crackerjack/services/regex_utils.py +43 -123
  172. crackerjack/services/secure_path_utils.py +5 -164
  173. crackerjack/services/secure_status_formatter.py +30 -141
  174. crackerjack/services/secure_subprocess.py +11 -92
  175. crackerjack/services/security.py +61 -30
  176. crackerjack/services/security_logger.py +18 -22
  177. crackerjack/services/server_manager.py +124 -16
  178. crackerjack/services/status_authentication.py +16 -159
  179. crackerjack/services/status_security_manager.py +4 -131
  180. crackerjack/services/terminal_utils.py +0 -0
  181. crackerjack/services/thread_safe_status_collector.py +19 -125
  182. crackerjack/services/unified_config.py +21 -13
  183. crackerjack/services/validation_rate_limiter.py +5 -54
  184. crackerjack/services/version_analyzer.py +459 -0
  185. crackerjack/services/version_checker.py +1 -1
  186. crackerjack/services/websocket_resource_limiter.py +10 -144
  187. crackerjack/services/zuban_lsp_service.py +390 -0
  188. crackerjack/slash_commands/__init__.py +2 -7
  189. crackerjack/slash_commands/run.md +2 -2
  190. crackerjack/tools/validate_input_validator_patterns.py +14 -40
  191. crackerjack/tools/validate_regex_patterns.py +19 -48
  192. {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +197 -26
  193. crackerjack-0.33.1.dist-info/RECORD +229 -0
  194. crackerjack/CLAUDE.md +0 -207
  195. crackerjack/RULES.md +0 -380
  196. crackerjack/py313.py +0 -234
  197. crackerjack-0.32.0.dist-info/RECORD +0 -180
  198. {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
  199. {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
  200. {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/licenses/LICENSE +0 -0
@@ -63,7 +63,6 @@ class TestSpecialistAgent(SubAgent):
63
63
  )
64
64
 
65
65
  def _check_test_patterns(self, message: str) -> float:
66
- # Map pattern strings back to SAFE_PATTERNS for safe usage
67
66
  pattern_map = {
68
67
  SAFE_PATTERNS[
69
68
  "fixture_not_found_pattern"
@@ -191,7 +190,6 @@ class TestSpecialistAgent(SubAgent):
191
190
  def _identify_failure_type(self, issue: Issue) -> str:
192
191
  message = issue.message
193
192
 
194
- # Map pattern strings back to SAFE_PATTERNS for safe usage
195
193
  pattern_map = {
196
194
  SAFE_PATTERNS[
197
195
  "fixture_not_found_pattern"
@@ -218,12 +216,10 @@ class TestSpecialistAgent(SubAgent):
218
216
  async def _fix_missing_fixtures(self, issue: Issue) -> list[str]:
219
217
  fixes: list[str] = []
220
218
 
221
- # Use safe pattern to test and extract fixture name
222
219
  fixture_pattern = SAFE_PATTERNS["fixture_not_found_pattern"]
223
220
  if not fixture_pattern.test(issue.message):
224
221
  return fixes
225
222
 
226
- # Extract fixture name using the safe pattern's search method
227
223
  match = fixture_pattern.search(issue.message)
228
224
  if not match:
229
225
  return fixes
crackerjack/api.py CHANGED
@@ -131,17 +131,6 @@ class CrackerjackAPI:
131
131
  backup: bool = True,
132
132
  safe_mode: bool = True,
133
133
  ) -> list[CleaningResult] | PackageCleaningResult:
134
- """Clean code with comprehensive backup protection.
135
-
136
- Args:
137
- target_dir: Directory to clean (defaults to package root)
138
- backup: Whether to create backup (deprecated, always True for safety)
139
- safe_mode: Use comprehensive backup system (default: True, recommended)
140
-
141
- Returns:
142
- PackageCleaningResult with backup metadata if safe_mode=True,
143
- otherwise list[CleaningResult] for legacy compatibility
144
- """
145
134
  target_dir = target_dir or self._get_package_root()
146
135
  self.logger.info(f"Cleaning code in {target_dir} (safe_mode={safe_mode})")
147
136
 
@@ -153,7 +142,6 @@ class CrackerjackAPI:
153
142
  )
154
143
  return self._execute_safe_code_cleaning(target_dir)
155
144
  else:
156
- # Note: Legacy mode still uses backup protection for safety
157
145
  self.console.print(
158
146
  "[yellow]āš ļø Legacy mode - backup protection still enabled for safety[/yellow]"
159
147
  )
@@ -210,16 +198,13 @@ class CrackerjackAPI:
210
198
 
211
199
  def _execute_code_cleaning(self, target_dir: Path) -> list[CleaningResult]:
212
200
  try:
213
- # Use backup protection by default for safety
214
201
  results = self.code_cleaner.clean_files(target_dir, use_backup=True)
215
202
 
216
- # Handle both return types (legacy compatibility)
217
203
  if isinstance(results, list):
218
204
  self._report_cleaning_results(results)
219
205
  else:
220
- # PackageCleaningResult from backup mode
221
206
  self._report_safe_cleaning_results(results)
222
- results = results.file_results # Extract list for compatibility
207
+ results = results.file_results
223
208
 
224
209
  return results
225
210
  except Exception as e:
@@ -415,7 +400,7 @@ class CrackerjackAPI:
415
400
  git_dir = self.project_path / ".git"
416
401
  is_git_repo = git_dir.exists()
417
402
 
418
- python_files = list(self.project_path.rglob("*.py"))
403
+ python_files = list[t.Any](self.project_path.rglob("*.py"))
419
404
 
420
405
  return {
421
406
  "project_path": str(self.project_path),
@@ -494,13 +479,13 @@ class CrackerjackAPI:
494
479
  data = tomllib.load(f)
495
480
 
496
481
  if "project" in data and "version" in data["project"]:
497
- return data["project"]["version"]
482
+ return str(data["project"]["version"])
498
483
  if (
499
484
  "tool" in data
500
485
  and "poetry" in data["tool"]
501
486
  and "version" in data["tool"]["poetry"]
502
487
  ):
503
- return data["tool"]["poetry"]["version"]
488
+ return str(data["tool"]["poetry"]["version"])
504
489
 
505
490
  import importlib.metadata
506
491
 
@@ -514,7 +499,6 @@ class CrackerjackAPI:
514
499
  return "unknown"
515
500
 
516
501
  def _check_for_todos(self, target_dir: Path) -> list[tuple[Path, int, str]]:
517
- # Use SAFE_PATTERNS for TODO detection
518
502
  task_pattern = SAFE_PATTERNS["todo_pattern"]
519
503
  python_files = self._get_python_files_for_todo_check(target_dir)
520
504
  return self._scan_files_for_todos(python_files, task_pattern)
@@ -574,12 +558,9 @@ class CrackerjackAPI:
574
558
  with suppress(UnicodeDecodeError, PermissionError):
575
559
  with file_path.open() as f:
576
560
  for line_no, line in enumerate(f, 1):
577
- # For ValidatedPattern, check if applying it changes the line
578
- # If it doesn't change, then it didn't match (identity replacement for match-only patterns)
579
561
  original = line.strip()
580
562
  processed = todo_pattern.apply(original)
581
- # For TODO pattern with identity replacement, a match means no change
582
- # But we need to check if it actually contains TODO
563
+
583
564
  if "todo" in original.lower() and original == processed:
584
565
  todos.append((file_path, line_no, line))
585
566
 
@@ -609,7 +590,7 @@ class CrackerjackAPI:
609
590
  data = tomllib.load(f)
610
591
 
611
592
  if "project" in data and "name" in data["project"]:
612
- return data["project"]["name"]
593
+ return str(data["project"]["name"])
613
594
 
614
595
  return None
615
596
 
@@ -0,0 +1,204 @@
1
+ import typing as t
2
+
3
+ from rich.console import Console
4
+ from rich.panel import Panel
5
+ from rich.table import Table
6
+ from rich.text import Text
7
+
8
+ from crackerjack.services.cache import CrackerjackCache
9
+
10
+
11
+ def handle_clear_cache(console: Console) -> None:
12
+ """Clear all caches and display results."""
13
+ try:
14
+ cache = CrackerjackCache()
15
+
16
+ # Clear memory caches and get cleanup stats
17
+ cleanup_results = cache.cleanup_all()
18
+
19
+ # Clear disk cache completely
20
+ if cache.enable_disk_cache and cache.cache_dir:
21
+ cache.disk_cache.clear()
22
+
23
+ # Calculate total items cleared
24
+ total_cleared = sum(cleanup_results.values())
25
+
26
+ # Create results table
27
+ table = Table(
28
+ title="Cache Cleared", show_header=True, header_style="bold green"
29
+ )
30
+ table.add_column("Cache Type", style="cyan", no_wrap=True)
31
+ table.add_column("Items Cleared", justify="right", style="yellow")
32
+
33
+ for cache_type, count in cleanup_results.items():
34
+ table.add_row(cache_type.replace("_", " ").title(), str(count))
35
+
36
+ table.add_row("", "", end_section=True)
37
+ table.add_row("Total", str(total_cleared), style="bold green")
38
+
39
+ console.print()
40
+ console.print(table)
41
+ console.print(f"\nāœ… Successfully cleared {total_cleared} cache entries")
42
+
43
+ except Exception as e:
44
+ console.print(f"\nāŒ Error clearing cache: {e}", style="bold red")
45
+
46
+
47
+ def handle_cache_stats(console: Console) -> None:
48
+ """Display detailed cache statistics."""
49
+ try:
50
+ cache = CrackerjackCache()
51
+ stats = cache.get_cache_stats()
52
+
53
+ main_table = _create_cache_stats_table()
54
+ totals = _populate_cache_stats_table(main_table, stats)
55
+ _add_cache_totals_row(main_table, totals)
56
+
57
+ console.print()
58
+ console.print(main_table)
59
+
60
+ _display_performance_insights(console, totals)
61
+ _display_cache_directory_info(console, cache)
62
+
63
+ except Exception as e:
64
+ console.print(f"\nāŒ Error retrieving cache stats: {e}", style="bold red")
65
+
66
+
67
+ def _create_cache_stats_table() -> Table:
68
+ """Create and configure the main cache statistics table."""
69
+ table = Table(title="Cache Statistics", show_header=True, header_style="bold blue")
70
+ table.add_column("Cache Layer", style="cyan", no_wrap=True)
71
+ table.add_column("Hit Rate %", justify="right", style="green")
72
+ table.add_column("Hits", justify="right", style="yellow")
73
+ table.add_column("Misses", justify="right", style="red")
74
+ table.add_column("Entries", justify="right", style="magenta")
75
+ table.add_column("Size (MB)", justify="right", style="blue")
76
+ return table
77
+
78
+
79
+ def _populate_cache_stats_table(
80
+ table: Table, stats: dict[str, t.Any]
81
+ ) -> dict[str, t.Any]:
82
+ """Populate table with cache statistics and return totals."""
83
+ totals = {"hits": 0, "misses": 0, "entries": 0, "size": 0.0}
84
+
85
+ for cache_name, cache_stats in stats.items():
86
+ hit_rate = cache_stats.get("hit_rate_percent", 0.0)
87
+ hits = cache_stats.get("hits", 0)
88
+ misses = cache_stats.get("misses", 0)
89
+ entries = cache_stats.get("total_entries", 0)
90
+ size_mb = cache_stats.get("total_size_mb", 0.0)
91
+
92
+ hit_rate_style = _get_hit_rate_style(hit_rate)
93
+
94
+ table.add_row(
95
+ cache_name.replace("_", " ").title(),
96
+ Text(f"{hit_rate:.1f}", style=hit_rate_style),
97
+ str(hits),
98
+ str(misses),
99
+ str(entries),
100
+ f"{size_mb:.2f}",
101
+ )
102
+
103
+ totals["hits"] += hits
104
+ totals["misses"] += misses
105
+ totals["entries"] += entries
106
+ totals["size"] += size_mb
107
+
108
+ return totals
109
+
110
+
111
+ def _get_hit_rate_style(hit_rate: float) -> str:
112
+ """Get color style for hit rate based on performance."""
113
+ return "green" if hit_rate > 70 else "yellow" if hit_rate > 40 else "red"
114
+
115
+
116
+ def _add_cache_totals_row(table: Table, totals: dict[str, t.Any]) -> None:
117
+ """Add totals row to cache statistics table."""
118
+ overall_hit_rate = (
119
+ (totals["hits"] / (totals["hits"] + totals["misses"]) * 100)
120
+ if (totals["hits"] + totals["misses"]) > 0
121
+ else 0
122
+ )
123
+ overall_style = _get_hit_rate_style(overall_hit_rate)
124
+
125
+ table.add_row("", "", "", "", "", "", end_section=True)
126
+ table.add_row(
127
+ "Overall",
128
+ Text(f"{overall_hit_rate:.1f}", style=f"bold {overall_style}"),
129
+ str(totals["hits"]),
130
+ str(totals["misses"]),
131
+ str(totals["entries"]),
132
+ f"{totals['size']:.2f}",
133
+ style="bold",
134
+ )
135
+
136
+
137
+ def _display_performance_insights(console: Console, totals: dict[str, t.Any]) -> None:
138
+ """Display performance insights panel based on cache statistics."""
139
+ overall_hit_rate = (
140
+ (totals["hits"] / (totals["hits"] + totals["misses"]) * 100)
141
+ if (totals["hits"] + totals["misses"]) > 0
142
+ else 0
143
+ )
144
+
145
+ insights = _generate_performance_insights(overall_hit_rate, totals["size"])
146
+
147
+ if insights:
148
+ insights_text = "\n".join(insights)
149
+ insights_panel = Panel(
150
+ insights_text,
151
+ title="Performance Insights",
152
+ border_style="blue",
153
+ padding=(1, 2),
154
+ )
155
+ console.print()
156
+ console.print(insights_panel)
157
+
158
+
159
+ def _generate_performance_insights(hit_rate: float, total_size: float) -> list[str]:
160
+ """Generate performance insights based on cache metrics."""
161
+ insights = []
162
+
163
+ if hit_rate > 80:
164
+ insights.append("šŸš€ Excellent cache performance!")
165
+ elif hit_rate > 60:
166
+ insights.append("āœ… Good cache performance")
167
+ elif hit_rate > 30:
168
+ insights.append("āš ļø Moderate cache performance - consider cache warming")
169
+ else:
170
+ insights.append("āŒ Poor cache performance - check cache configuration")
171
+
172
+ if total_size > 100:
173
+ insights.append(f"šŸ’¾ Large cache size ({total_size:.1f}MB) - consider cleanup")
174
+
175
+ return insights
176
+
177
+
178
+ def _display_cache_directory_info(console: Console, cache: CrackerjackCache) -> None:
179
+ """Display cache directory information."""
180
+ if not (cache.enable_disk_cache and cache.cache_dir):
181
+ return
182
+
183
+ cache_dir_info = f"šŸ“ Cache Directory: {cache.cache_dir}"
184
+ if cache.cache_dir.exists():
185
+ disk_files = len(list[t.Any](cache.cache_dir.rglob("*.cache")))
186
+ cache_dir_info += f" ({disk_files} files)"
187
+
188
+ console.print()
189
+ console.print(cache_dir_info)
190
+
191
+
192
+ def _handle_cache_commands(
193
+ clear_cache: bool, cache_stats: bool, console: Console
194
+ ) -> bool:
195
+ """Handle cache management commands. Returns True if a cache command was executed."""
196
+ if clear_cache:
197
+ handle_clear_cache(console)
198
+ return True
199
+
200
+ if cache_stats:
201
+ handle_cache_stats(console)
202
+ return True
203
+
204
+ return False