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
@@ -0,0 +1,416 @@
1
+ import asyncio
2
+ import time
3
+ import typing as t
4
+ from concurrent.futures import ThreadPoolExecutor
5
+ from dataclasses import dataclass, field
6
+ from enum import Enum
7
+ from pathlib import Path
8
+
9
+ from crackerjack.config.hooks import HookDefinition, SecurityLevel
10
+ from crackerjack.services.logging import get_logger
11
+ from crackerjack.services.performance_cache import get_performance_cache
12
+
13
+
14
+ class ExecutionStrategy(Enum):
15
+ SEQUENTIAL = "sequential"
16
+ PARALLEL_SAFE = "parallel_safe"
17
+ PARALLEL_AGGRESSIVE = "parallel_aggressive"
18
+
19
+
20
+ @dataclass
21
+ class ExecutionGroup:
22
+ name: str
23
+ operations: list[t.Any]
24
+ max_workers: int = 3
25
+ timeout_seconds: int = 300
26
+ dependencies: set[str] = field(default_factory=set)
27
+ security_level: SecurityLevel = SecurityLevel.MEDIUM
28
+
29
+
30
+ @dataclass
31
+ class ExecutionResult:
32
+ operation_id: str
33
+ success: bool
34
+ duration_seconds: float
35
+ output: str = ""
36
+ error: str = ""
37
+ exit_code: int = 0
38
+ metadata: dict[str, t.Any] = field(default_factory=dict[str, t.Any])
39
+
40
+
41
+ @dataclass
42
+ class ParallelExecutionResult:
43
+ group_name: str
44
+ total_operations: int
45
+ successful_operations: int
46
+ failed_operations: int
47
+ total_duration_seconds: float
48
+ results: list[ExecutionResult]
49
+
50
+ @property
51
+ def success_rate(self) -> float:
52
+ return (
53
+ self.successful_operations / self.total_operations
54
+ if self.total_operations > 0
55
+ else 0.0
56
+ )
57
+
58
+ @property
59
+ def overall_success(self) -> bool:
60
+ return self.failed_operations == 0
61
+
62
+
63
+ class ParallelHookExecutor:
64
+ def __init__(
65
+ self,
66
+ max_workers: int = 3,
67
+ timeout_seconds: int = 300,
68
+ strategy: ExecutionStrategy = ExecutionStrategy.PARALLEL_SAFE,
69
+ ):
70
+ self.max_workers = max_workers
71
+ self.timeout_seconds = timeout_seconds
72
+ self.strategy = strategy
73
+ self._logger = get_logger("crackerjack.parallel_executor")
74
+ self._cache = get_performance_cache()
75
+
76
+ def analyze_hook_dependencies(
77
+ self,
78
+ hooks: list[HookDefinition],
79
+ ) -> dict[str, list[HookDefinition]]:
80
+ groups: dict[str, list[HookDefinition]] = {
81
+ "formatting": [],
82
+ "validation": [],
83
+ "security": [],
84
+ "comprehensive": [],
85
+ }
86
+
87
+ for hook in hooks:
88
+ if hook.is_formatting or hook.security_level == SecurityLevel.LOW:
89
+ groups["formatting"].append(hook)
90
+ elif hook.security_level == SecurityLevel.CRITICAL:
91
+ groups["security"].append(hook)
92
+ elif hook.name in {"check-yaml", "check-json", "check-toml"}:
93
+ groups["validation"].append(hook)
94
+ else:
95
+ groups["comprehensive"].append(hook)
96
+
97
+ return {k: v for k, v in groups.items() if v}
98
+
99
+ def can_execute_in_parallel(
100
+ self,
101
+ hook1: HookDefinition,
102
+ hook2: HookDefinition,
103
+ ) -> bool:
104
+ if hook1.security_level != hook2.security_level:
105
+ return False
106
+
107
+ if hook1.is_formatting and not hook2.is_formatting:
108
+ return False
109
+
110
+ safe_parallel_combinations = [
111
+ (lambda h: h.is_formatting, lambda h: h.is_formatting),
112
+ (
113
+ lambda h: h.name in {"check-yaml", "check-json", "check-toml"},
114
+ lambda h: h.name in {"check-yaml", "check-json", "check-toml"},
115
+ ),
116
+ (
117
+ lambda h: not h.is_formatting
118
+ and h.security_level == SecurityLevel.MEDIUM,
119
+ lambda h: not h.is_formatting
120
+ and h.security_level == SecurityLevel.MEDIUM,
121
+ ),
122
+ ]
123
+
124
+ for check1, check2 in safe_parallel_combinations:
125
+ if check1(hook1) and check2(hook2):
126
+ return True
127
+
128
+ return False
129
+
130
+ async def execute_hooks_parallel(
131
+ self,
132
+ hooks: list[HookDefinition],
133
+ hook_runner: t.Callable[[HookDefinition], t.Awaitable[ExecutionResult]],
134
+ ) -> ParallelExecutionResult:
135
+ start_time = time.time()
136
+
137
+ if self.strategy == ExecutionStrategy.SEQUENTIAL:
138
+ return await self._execute_sequential(hooks, hook_runner, start_time)
139
+
140
+ groups = self.analyze_hook_dependencies(hooks)
141
+ all_results: list[ExecutionResult] = []
142
+
143
+ self._logger.info(
144
+ f"Executing {len(hooks)} hooks in {len(groups)} parallel groups"
145
+ )
146
+
147
+ for group_name, group_hooks in groups.items():
148
+ if len(group_hooks) == 1 or not self._can_parallelize_group(group_hooks):
149
+ for hook in group_hooks:
150
+ result = await hook_runner(hook)
151
+ all_results.append(result)
152
+ else:
153
+ group_results = await self._execute_group_parallel(
154
+ group_hooks,
155
+ hook_runner,
156
+ group_name,
157
+ )
158
+ all_results.extend(group_results)
159
+
160
+ total_duration = time.time() - start_time
161
+ successful = sum(1 for r in all_results if r.success)
162
+ failed = len(all_results) - successful
163
+
164
+ return ParallelExecutionResult(
165
+ group_name="all_hooks",
166
+ total_operations=len(hooks),
167
+ successful_operations=successful,
168
+ failed_operations=failed,
169
+ total_duration_seconds=total_duration,
170
+ results=all_results,
171
+ )
172
+
173
+ async def _execute_sequential(
174
+ self,
175
+ hooks: list[HookDefinition],
176
+ hook_runner: t.Callable[[HookDefinition], t.Awaitable[ExecutionResult]],
177
+ start_time: float,
178
+ ) -> ParallelExecutionResult:
179
+ results: list[ExecutionResult] = []
180
+
181
+ for hook in hooks:
182
+ result = await hook_runner(hook)
183
+ results.append(result)
184
+
185
+ total_duration = time.time() - start_time
186
+ successful = sum(1 for r in results if r.success)
187
+ failed = len(results) - successful
188
+
189
+ return ParallelExecutionResult(
190
+ group_name="sequential",
191
+ total_operations=len(hooks),
192
+ successful_operations=successful,
193
+ failed_operations=failed,
194
+ total_duration_seconds=total_duration,
195
+ results=results,
196
+ )
197
+
198
+ def _can_parallelize_group(self, hooks: list[HookDefinition]) -> bool:
199
+ if len(hooks) < 2:
200
+ return False
201
+
202
+ for i, hook1 in enumerate(hooks):
203
+ for hook2 in hooks[i + 1 :]:
204
+ if not self.can_execute_in_parallel(hook1, hook2):
205
+ return False
206
+
207
+ return True
208
+
209
+ async def _execute_group_parallel(
210
+ self,
211
+ hooks: list[HookDefinition],
212
+ hook_runner: t.Callable[[HookDefinition], t.Awaitable[ExecutionResult]],
213
+ group_name: str,
214
+ ) -> list[ExecutionResult]:
215
+ self._logger.debug(f"Executing {len(hooks)} {group_name} hooks in parallel")
216
+
217
+ max_workers = min(self.max_workers, len(hooks))
218
+
219
+ semaphore = asyncio.Semaphore(max_workers)
220
+
221
+ async def run_with_semaphore(hook: HookDefinition) -> ExecutionResult:
222
+ async with semaphore:
223
+ return await hook_runner(hook)
224
+
225
+ tasks = [run_with_semaphore(hook) for hook in hooks]
226
+ results = await asyncio.gather(*tasks, return_exceptions=True)
227
+
228
+ processed_results: list[ExecutionResult] = []
229
+ for i, result in enumerate(results):
230
+ if isinstance(result, Exception):
231
+ error_result = ExecutionResult(
232
+ operation_id=hooks[i].name,
233
+ success=False,
234
+ duration_seconds=0.0,
235
+ error=str(result),
236
+ )
237
+ processed_results.append(error_result)
238
+ self._logger.error(
239
+ f"Hook {hooks[i].name} failed with exception: {result}"
240
+ )
241
+ else:
242
+ processed_results.append(result)
243
+
244
+ successful = sum(1 for r in processed_results if r.success)
245
+ self._logger.info(
246
+ f"Parallel {group_name} execution: {successful}/{len(hooks)} succeeded"
247
+ )
248
+
249
+ return processed_results
250
+
251
+
252
+ class AsyncCommandExecutor:
253
+ def __init__(
254
+ self,
255
+ max_workers: int = 4,
256
+ cache_results: bool = True,
257
+ ):
258
+ self.max_workers = max_workers
259
+ self.cache_results = cache_results
260
+ self._logger = get_logger("crackerjack.async_executor")
261
+ self._cache = get_performance_cache()
262
+ self._thread_pool = ThreadPoolExecutor(max_workers=max_workers)
263
+
264
+ async def execute_command(
265
+ self,
266
+ command: list[str],
267
+ cwd: Path | None = None,
268
+ timeout: int = 60,
269
+ cache_ttl: int = 120,
270
+ ) -> ExecutionResult:
271
+ if self.cache_results:
272
+ cached_result = await self._get_cached_result(command, cwd)
273
+ if cached_result:
274
+ self._logger.debug(
275
+ f"Using cached result for command: {' '.join(command)}"
276
+ )
277
+ return cached_result
278
+
279
+ start_time = time.time()
280
+ result = await self._run_command_async(command, cwd, timeout)
281
+ result.duration_seconds = time.time() - start_time
282
+
283
+ if self.cache_results and result.success:
284
+ await self._cache_result(command, result, cache_ttl, cwd)
285
+
286
+ return result
287
+
288
+ async def execute_commands_batch(
289
+ self,
290
+ commands: list[tuple[list[str], Path | None]],
291
+ timeout: int = 60,
292
+ ) -> list[ExecutionResult]:
293
+ self._logger.info(f"Executing {len(commands)} commands in batch")
294
+
295
+ tasks = [self.execute_command(cmd, cwd, timeout) for cmd, cwd in commands]
296
+
297
+ results = await asyncio.gather(*tasks, return_exceptions=True)
298
+
299
+ processed_results: list[ExecutionResult] = []
300
+ for i, result in enumerate(results):
301
+ if isinstance(result, Exception):
302
+ error_result = ExecutionResult(
303
+ operation_id=f"command_{i}",
304
+ success=False,
305
+ duration_seconds=0.0,
306
+ error=str(result),
307
+ )
308
+ processed_results.append(error_result)
309
+ else:
310
+ processed_results.append(result)
311
+
312
+ successful = sum(1 for r in processed_results if r.success)
313
+ self._logger.info(
314
+ f"Batch execution: {successful}/{len(commands)} commands succeeded"
315
+ )
316
+
317
+ return processed_results
318
+
319
+ async def _run_command_async(
320
+ self,
321
+ command: list[str],
322
+ cwd: Path | None = None,
323
+ timeout: int = 60,
324
+ ) -> ExecutionResult:
325
+ loop = asyncio.get_event_loop()
326
+
327
+ def run_sync_command() -> ExecutionResult:
328
+ import subprocess
329
+
330
+ try:
331
+ result = subprocess.run(
332
+ command,
333
+ cwd=cwd,
334
+ capture_output=True,
335
+ text=True,
336
+ timeout=timeout,
337
+ check=False,
338
+ )
339
+
340
+ return ExecutionResult(
341
+ operation_id=" ".join(command),
342
+ success=result.returncode == 0,
343
+ duration_seconds=0.0,
344
+ output=result.stdout,
345
+ error=result.stderr,
346
+ exit_code=result.returncode,
347
+ )
348
+
349
+ except subprocess.TimeoutExpired:
350
+ return ExecutionResult(
351
+ operation_id=" ".join(command),
352
+ success=False,
353
+ duration_seconds=timeout,
354
+ error=f"Command timeout after {timeout}s",
355
+ exit_code=-1,
356
+ )
357
+ except Exception as e:
358
+ return ExecutionResult(
359
+ operation_id=" ".join(command),
360
+ success=False,
361
+ duration_seconds=0.0,
362
+ error=str(e),
363
+ exit_code=-1,
364
+ )
365
+
366
+ return await loop.run_in_executor(self._thread_pool, run_sync_command)
367
+
368
+ async def _get_cached_result(
369
+ self,
370
+ command: list[str],
371
+ cwd: Path | None = None,
372
+ ) -> ExecutionResult | None:
373
+ from crackerjack.services.performance_cache import get_command_cache
374
+
375
+ cache_result = get_command_cache().get_command_result(command, cwd)
376
+ return t.cast(ExecutionResult | None, cache_result)
377
+
378
+ async def _cache_result(
379
+ self,
380
+ command: list[str],
381
+ result: ExecutionResult,
382
+ ttl_seconds: int,
383
+ cwd: Path | None = None,
384
+ ) -> None:
385
+ from crackerjack.services.performance_cache import get_command_cache
386
+
387
+ command_cache = get_command_cache()
388
+ command_cache.set_command_result(command, result, cwd, ttl_seconds)
389
+
390
+ def __del__(self) -> None:
391
+ if hasattr(self, "_thread_pool"):
392
+ self._thread_pool.shutdown(wait=False)
393
+
394
+
395
+ _parallel_executor: ParallelHookExecutor | None = None
396
+ _async_executor: AsyncCommandExecutor | None = None
397
+
398
+
399
+ def get_parallel_executor(
400
+ max_workers: int = 3,
401
+ strategy: ExecutionStrategy = ExecutionStrategy.PARALLEL_SAFE,
402
+ ) -> ParallelHookExecutor:
403
+ global _parallel_executor
404
+ if _parallel_executor is None:
405
+ _parallel_executor = ParallelHookExecutor(
406
+ max_workers=max_workers,
407
+ strategy=strategy,
408
+ )
409
+ return _parallel_executor
410
+
411
+
412
+ def get_async_executor(max_workers: int = 4) -> AsyncCommandExecutor:
413
+ global _async_executor
414
+ if _async_executor is None:
415
+ _async_executor = AsyncCommandExecutor(max_workers=max_workers)
416
+ return _async_executor
@@ -195,7 +195,7 @@ class PatternCache:
195
195
  if not self._patterns:
196
196
  return {"total_patterns": 0}
197
197
 
198
- patterns_by_type = {}
198
+ patterns_by_type: dict[str, int] = {}
199
199
  total_usage = 0
200
200
  avg_success_rate = 0.0
201
201
 
@@ -66,7 +66,7 @@ class PatternDetector:
66
66
  self.logger.info("Starting proactive anti-pattern analysis")
67
67
 
68
68
  anti_patterns = []
69
- python_files = list(self.project_path.glob("**/*.py"))
69
+ python_files = list[t.Any](self.project_path.glob("**/*.py"))
70
70
 
71
71
  for file_path in python_files:
72
72
  if self._should_skip_file(file_path):
@@ -155,7 +155,7 @@ class PatternDetector:
155
155
  anti_patterns = []
156
156
 
157
157
  lines = content.split("\n")
158
- line_groups = {}
158
+ line_groups: dict[str, list[int]] = {}
159
159
 
160
160
  for i, line in enumerate(lines, 1):
161
161
  stripped = line.strip()
@@ -197,7 +197,7 @@ class PatternDetector:
197
197
  (
198
198
  node.lineno,
199
199
  "Nested loop detected-potential O(n²) complexity",
200
- "Consider using dictionary lookups or set operations",
200
+ "Consider using dictionary lookups or set[t.Any] operations",
201
201
  )
202
202
  )
203
203
  break
@@ -212,7 +212,7 @@ class PatternDetector:
212
212
  (
213
213
  stmt.lineno,
214
214
  "List concatenation in loop-inefficient",
215
- "Use list.append() and join at the end",
215
+ "Use list[t.Any].append() and join at the end",
216
216
  )
217
217
  )
218
218
 
@@ -254,10 +254,10 @@ class PatternDetector:
254
254
  ) -> list[AntiPattern]:
255
255
  anti_patterns = []
256
256
 
257
- if "/tmp/" in content or "C:\\" in content: # nosec B108
257
+ if "/tmp/" in content or "C: \\" in content: # nosec B108
258
258
  lines = content.split("\n")
259
259
  for i, line in enumerate(lines, 1):
260
- if "/tmp/" in line or "C:\\" in line: # nosec B108
260
+ if "/tmp/" in line or "C: \\" in line: # nosec B108
261
261
  anti_patterns.append(
262
262
  AntiPattern(
263
263
  pattern_type="security_risks",