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,243 @@
1
+ import functools
2
+ import time
3
+ import typing as t
4
+ from pathlib import Path
5
+
6
+ from rich.console import Console
7
+
8
+
9
+ class FileCache:
10
+ def __init__(self, ttl: float = 300.0) -> None:
11
+ self.ttl = ttl
12
+ self._cache: dict[str, tuple[float, t.Any]] = {}
13
+
14
+ def get(self, key: str) -> t.Any | None:
15
+ if key not in self._cache:
16
+ return None
17
+ timestamp, value = self._cache[key]
18
+ if time.time() - timestamp > self.ttl:
19
+ del self._cache[key]
20
+ return None
21
+
22
+ return value
23
+
24
+ def set(self, key: str, value: t.Any) -> None:
25
+ self._cache[key] = (time.time(), value)
26
+
27
+ def clear(self) -> None:
28
+ self._cache.clear()
29
+
30
+ def size(self) -> int:
31
+ return len(self._cache)
32
+
33
+
34
+ class PerformanceMonitor:
35
+ def __init__(self, console: Console | None = None) -> None:
36
+ self.console = console
37
+ self.metrics: dict[str, list[float]] = {}
38
+
39
+ def time_operation(
40
+ self,
41
+ operation_name: str,
42
+ ) -> t.Callable[[t.Callable[..., t.Any]], t.Callable[..., t.Any]]:
43
+ def decorator(func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
44
+ @functools.wraps(func)
45
+ def wrapper(*args: t.Any, **kwargs: t.Any) -> t.Any:
46
+ start_time = time.time()
47
+ try:
48
+ return func(*args, **kwargs)
49
+ finally:
50
+ duration = time.time() - start_time
51
+ self.record_metric(operation_name, duration)
52
+
53
+ return wrapper
54
+
55
+ return decorator
56
+
57
+ def record_metric(self, name: str, value: float) -> None:
58
+ if name not in self.metrics:
59
+ self.metrics[name] = []
60
+ self.metrics[name].append(value)
61
+
62
+ def get_stats(self, name: str) -> dict[str, float]:
63
+ if name not in self.metrics or not self.metrics[name]:
64
+ return {}
65
+ values = self.metrics[name]
66
+ return {
67
+ "count": len(values),
68
+ "total": sum(values),
69
+ "avg": sum(values) / len(values),
70
+ "min": min(values),
71
+ "max": max(values),
72
+ }
73
+
74
+ def print_stats(self, name: str | None = None) -> None:
75
+ if not self.console:
76
+ return
77
+ if name:
78
+ stats = self.get_stats(name)
79
+ if stats:
80
+ self.console.print(
81
+ f"[cyan]📊 {name}: [/cyan] "
82
+ f"avg = {stats['avg']:.3f}s, "
83
+ f"min = {stats['min']:.3f}s, "
84
+ f"max = {stats['max']:.3f}s, "
85
+ f"count = {stats['count']}",
86
+ )
87
+ else:
88
+ for metric_name in self.metrics:
89
+ self.print_stats(metric_name)
90
+
91
+
92
+ def memoize_with_ttl(
93
+ ttl: float = 300.0,
94
+ ) -> t.Callable[[t.Callable[..., t.Any]], t.Callable[..., t.Any]]:
95
+ def decorator(func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
96
+ cache: dict[str, tuple[float, t.Any]] = {}
97
+
98
+ @functools.wraps(func)
99
+ def wrapper(*args: t.Any, **kwargs: t.Any) -> t.Any:
100
+ key = str(args) + str(sorted(kwargs.items()))
101
+ if key in cache:
102
+ timestamp, value = cache[key]
103
+ if time.time() - timestamp <= ttl:
104
+ return value
105
+ del cache[key]
106
+ result = func(*args, **kwargs)
107
+ cache[key] = (time.time(), result)
108
+ return result
109
+
110
+ wrapper.cache_clear = cache.clear # type: ignore[attr-defined]
111
+ wrapper.cache_info = lambda: {"size": len(cache), "ttl": ttl} # type: ignore[attr-defined]
112
+ return wrapper
113
+
114
+ return decorator
115
+
116
+
117
+ def batch_file_operations(
118
+ operations: list[t.Callable[[], t.Any]],
119
+ batch_size: int = 50,
120
+ ) -> list[t.Any]:
121
+ results: list[t.Any] = []
122
+ for i in range(0, len(operations), batch_size):
123
+ batch = operations[i : i + batch_size]
124
+ batch_results: list[t.Any] = []
125
+ for operation in batch:
126
+ try:
127
+ result = operation()
128
+ batch_results.append(result)
129
+ except Exception as e:
130
+ batch_results.append(e)
131
+ results.extend(batch_results)
132
+ if i + batch_size < len(operations):
133
+ time.sleep(0.01)
134
+
135
+ return results
136
+
137
+
138
+ class OptimizedFileWatcher:
139
+ def __init__(self, root_path: Path) -> None:
140
+ self.root_path = root_path
141
+ self._file_cache = FileCache(ttl=60.0)
142
+
143
+ @memoize_with_ttl(ttl=30.0)
144
+ def get_python_files(self) -> list[Path]:
145
+ return list(self.root_path.rglob("*.py"))
146
+
147
+ def get_modified_files(self, since: float) -> list[Path]:
148
+ cache_key = f"modified_since_{since}"
149
+ cached = self._file_cache.get(cache_key)
150
+ if cached is not None:
151
+ return cached
152
+ modified_files: list[Path] = []
153
+ for py_file in self.get_python_files():
154
+ try:
155
+ if py_file.stat().st_mtime > since:
156
+ modified_files.append(py_file)
157
+ except (OSError, FileNotFoundError):
158
+ continue
159
+ self._file_cache.set(cache_key, modified_files)
160
+ return modified_files
161
+
162
+ def clear_cache(self) -> None:
163
+ self._file_cache.clear()
164
+
165
+ if hasattr(self.get_python_files, "cache_clear"):
166
+ self.get_python_files.cache_clear() # type: ignore[attr-defined]
167
+
168
+
169
+ class ParallelTaskExecutor:
170
+ def __init__(self, max_workers: int | None = None) -> None:
171
+ import os
172
+
173
+ self.max_workers = max_workers or min(os.cpu_count() or 1, 8)
174
+
175
+ def execute_tasks(
176
+ self,
177
+ tasks: list[t.Callable[[], t.Any]],
178
+ timeout: float = 300.0,
179
+ ) -> list[t.Any]:
180
+ if len(tasks) <= 1:
181
+ return [task() for task in tasks]
182
+ import concurrent.futures
183
+
184
+ results: list[tuple[int, t.Any]] = []
185
+ with concurrent.futures.ThreadPoolExecutor(
186
+ max_workers=self.max_workers,
187
+ ) as executor:
188
+ future_to_task = {executor.submit(task): i for i, task in enumerate(tasks)}
189
+ for future in concurrent.futures.as_completed(
190
+ future_to_task,
191
+ timeout=timeout,
192
+ ):
193
+ task_index = future_to_task[future]
194
+ try:
195
+ result = future.result()
196
+ results.append((task_index, result))
197
+ except Exception as e:
198
+ results.append((task_index, e))
199
+ import operator
200
+
201
+ results.sort(key=operator.itemgetter(0))
202
+ return [result for _, result in results]
203
+
204
+
205
+ def optimize_subprocess_calls(
206
+ commands: list[list[str]],
207
+ cwd: Path | None = None,
208
+ ) -> list[t.Any]:
209
+ if len(commands) <= 1:
210
+ import subprocess
211
+
212
+ return [
213
+ subprocess.run(cmd, check=False, cwd=cwd, capture_output=True, text=True)
214
+ for cmd in commands
215
+ ]
216
+ executor = ParallelTaskExecutor()
217
+
218
+ def run_command(cmd: list[str]) -> t.Any:
219
+ import subprocess
220
+
221
+ return subprocess.run(cmd, check=False, cwd=cwd, capture_output=True, text=True)
222
+
223
+ import functools
224
+
225
+ tasks: list[t.Callable[[], t.Any]] = [
226
+ functools.partial(run_command, cmd) for cmd in commands
227
+ ]
228
+ return executor.execute_tasks(tasks)
229
+
230
+
231
+ _performance_monitor: PerformanceMonitor | None = None
232
+
233
+
234
+ def get_performance_monitor() -> PerformanceMonitor:
235
+ global _performance_monitor
236
+ if _performance_monitor is None:
237
+ _performance_monitor = PerformanceMonitor()
238
+ return _performance_monitor
239
+
240
+
241
+ def reset_performance_monitor() -> None:
242
+ global _performance_monitor
243
+ _performance_monitor = None