crackerjack 0.33.0__py3-none-any.whl → 0.33.2__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 (198) 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 +4 -13
  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 +104 -204
  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 +171 -174
  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 +44 -8
  74. crackerjack/managers/test_command_builder.py +1 -15
  75. crackerjack/managers/test_executor.py +1 -3
  76. crackerjack/managers/test_manager.py +98 -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 +17 -16
  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 +173 -32
  92. crackerjack/mcp/tools/error_analyzer.py +3 -2
  93. crackerjack/mcp/tools/execution_tools.py +8 -10
  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 +0 -2
  109. crackerjack/mixins/error_handling.py +1 -70
  110. crackerjack/models/config.py +12 -1
  111. crackerjack/models/config_adapter.py +49 -1
  112. crackerjack/models/protocols.py +122 -122
  113. crackerjack/models/resource_protocols.py +55 -210
  114. crackerjack/monitoring/ai_agent_watchdog.py +13 -13
  115. crackerjack/monitoring/metrics_collector.py +426 -0
  116. crackerjack/monitoring/regression_prevention.py +8 -8
  117. crackerjack/monitoring/websocket_server.py +643 -0
  118. crackerjack/orchestration/advanced_orchestrator.py +11 -6
  119. crackerjack/orchestration/coverage_improvement.py +3 -3
  120. crackerjack/orchestration/execution_strategies.py +26 -6
  121. crackerjack/orchestration/test_progress_streamer.py +8 -5
  122. crackerjack/plugins/base.py +2 -2
  123. crackerjack/plugins/hooks.py +7 -0
  124. crackerjack/plugins/managers.py +11 -8
  125. crackerjack/security/__init__.py +0 -1
  126. crackerjack/security/audit.py +6 -35
  127. crackerjack/services/anomaly_detector.py +392 -0
  128. crackerjack/services/api_extractor.py +615 -0
  129. crackerjack/services/backup_service.py +2 -2
  130. crackerjack/services/bounded_status_operations.py +15 -152
  131. crackerjack/services/cache.py +127 -1
  132. crackerjack/services/changelog_automation.py +395 -0
  133. crackerjack/services/config.py +15 -9
  134. crackerjack/services/config_merge.py +19 -80
  135. crackerjack/services/config_template.py +506 -0
  136. crackerjack/services/contextual_ai_assistant.py +48 -22
  137. crackerjack/services/coverage_badge_service.py +171 -0
  138. crackerjack/services/coverage_ratchet.py +27 -25
  139. crackerjack/services/debug.py +3 -3
  140. crackerjack/services/dependency_analyzer.py +460 -0
  141. crackerjack/services/dependency_monitor.py +14 -11
  142. crackerjack/services/documentation_generator.py +491 -0
  143. crackerjack/services/documentation_service.py +675 -0
  144. crackerjack/services/enhanced_filesystem.py +6 -5
  145. crackerjack/services/enterprise_optimizer.py +865 -0
  146. crackerjack/services/error_pattern_analyzer.py +676 -0
  147. crackerjack/services/file_hasher.py +1 -1
  148. crackerjack/services/git.py +8 -25
  149. crackerjack/services/health_metrics.py +10 -8
  150. crackerjack/services/heatmap_generator.py +735 -0
  151. crackerjack/services/initialization.py +11 -30
  152. crackerjack/services/input_validator.py +5 -97
  153. crackerjack/services/intelligent_commit.py +327 -0
  154. crackerjack/services/log_manager.py +15 -12
  155. crackerjack/services/logging.py +4 -3
  156. crackerjack/services/lsp_client.py +628 -0
  157. crackerjack/services/memory_optimizer.py +19 -87
  158. crackerjack/services/metrics.py +42 -33
  159. crackerjack/services/parallel_executor.py +9 -67
  160. crackerjack/services/pattern_cache.py +1 -1
  161. crackerjack/services/pattern_detector.py +6 -6
  162. crackerjack/services/performance_benchmarks.py +18 -59
  163. crackerjack/services/performance_cache.py +20 -81
  164. crackerjack/services/performance_monitor.py +27 -95
  165. crackerjack/services/predictive_analytics.py +510 -0
  166. crackerjack/services/quality_baseline.py +234 -0
  167. crackerjack/services/quality_baseline_enhanced.py +646 -0
  168. crackerjack/services/quality_intelligence.py +785 -0
  169. crackerjack/services/regex_patterns.py +618 -524
  170. crackerjack/services/regex_utils.py +43 -123
  171. crackerjack/services/secure_path_utils.py +5 -164
  172. crackerjack/services/secure_status_formatter.py +30 -141
  173. crackerjack/services/secure_subprocess.py +11 -92
  174. crackerjack/services/security.py +9 -41
  175. crackerjack/services/security_logger.py +12 -24
  176. crackerjack/services/server_manager.py +124 -16
  177. crackerjack/services/status_authentication.py +16 -159
  178. crackerjack/services/status_security_manager.py +4 -131
  179. crackerjack/services/thread_safe_status_collector.py +19 -125
  180. crackerjack/services/unified_config.py +21 -13
  181. crackerjack/services/validation_rate_limiter.py +5 -54
  182. crackerjack/services/version_analyzer.py +459 -0
  183. crackerjack/services/version_checker.py +1 -1
  184. crackerjack/services/websocket_resource_limiter.py +10 -144
  185. crackerjack/services/zuban_lsp_service.py +390 -0
  186. crackerjack/slash_commands/__init__.py +2 -7
  187. crackerjack/slash_commands/run.md +2 -2
  188. crackerjack/tools/validate_input_validator_patterns.py +14 -40
  189. crackerjack/tools/validate_regex_patterns.py +19 -48
  190. {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/METADATA +196 -25
  191. crackerjack-0.33.2.dist-info/RECORD +229 -0
  192. crackerjack/CLAUDE.md +0 -207
  193. crackerjack/RULES.md +0 -380
  194. crackerjack/py313.py +0 -234
  195. crackerjack-0.33.0.dist-info/RECORD +0 -187
  196. {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/WHEEL +0 -0
  197. {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/entry_points.txt +0 -0
  198. {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,10 +1,3 @@
1
- """Comprehensive resource management with automatic cleanup patterns.
2
-
3
- This module provides RAII (Resource Acquisition Is Initialization) patterns
4
- and comprehensive resource lifecycle management to prevent resource leaks
5
- even in error scenarios.
6
- """
7
-
8
1
  import asyncio
9
2
  import contextlib
10
3
  import logging
@@ -19,16 +12,10 @@ from types import TracebackType
19
12
 
20
13
 
21
14
  class ResourceProtocol(t.Protocol):
22
- """Protocol for resources that can be cleaned up."""
23
-
24
- async def cleanup(self) -> None:
25
- """Clean up the resource."""
26
- ...
15
+ async def cleanup(self) -> None: ...
27
16
 
28
17
 
29
18
  class ResourceManager:
30
- """Centralized resource management with automatic cleanup on error scenarios."""
31
-
32
19
  def __init__(self, logger: logging.Logger | None = None) -> None:
33
20
  self.logger = logger or logging.getLogger(__name__)
34
21
  self._resources: list[ResourceProtocol] = []
@@ -37,10 +24,8 @@ class ResourceManager:
37
24
  self._closed = False
38
25
 
39
26
  def register_resource(self, resource: ResourceProtocol) -> None:
40
- """Register a resource for automatic cleanup."""
41
27
  with self._lock:
42
28
  if self._closed:
43
- # If already closed, immediately clean up the resource
44
29
  asyncio.create_task(resource.cleanup())
45
30
  return
46
31
  self._resources.append(resource)
@@ -48,10 +33,8 @@ class ResourceManager:
48
33
  def register_cleanup_callback(
49
34
  self, callback: t.Callable[[], t.Awaitable[None]]
50
35
  ) -> None:
51
- """Register a cleanup callback to be called during shutdown."""
52
36
  with self._lock:
53
37
  if self._closed:
54
- # If already closed, immediately call the callback
55
38
  coro = callback()
56
39
  if asyncio.iscoroutine(coro):
57
40
  asyncio.ensure_future(coro)
@@ -59,7 +42,6 @@ class ResourceManager:
59
42
  self._cleanup_callbacks.append(callback)
60
43
 
61
44
  async def cleanup_all(self) -> None:
62
- """Clean up all registered resources."""
63
45
  with self._lock:
64
46
  if self._closed:
65
47
  return
@@ -68,14 +50,12 @@ class ResourceManager:
68
50
  resources = self._resources.copy()
69
51
  callbacks = self._cleanup_callbacks.copy()
70
52
 
71
- # Clean up resources
72
53
  for resource in resources:
73
54
  try:
74
55
  await resource.cleanup()
75
56
  except Exception as e:
76
57
  self.logger.warning(f"Error cleaning up resource {resource}: {e}")
77
58
 
78
- # Call cleanup callbacks
79
59
  for callback in callbacks:
80
60
  try:
81
61
  await callback()
@@ -99,8 +79,6 @@ class ResourceManager:
99
79
 
100
80
 
101
81
  class ManagedResource(ABC):
102
- """Base class for managed resources with automatic cleanup."""
103
-
104
82
  def __init__(self, manager: ResourceManager | None = None) -> None:
105
83
  self.manager = manager
106
84
  self._closed = False
@@ -110,19 +88,15 @@ class ManagedResource(ABC):
110
88
 
111
89
  @abstractmethod
112
90
  async def cleanup(self) -> None:
113
- """Clean up the resource. Must be implemented by subclasses."""
114
91
  pass
115
92
 
116
93
  async def close(self) -> None:
117
- """Manually close the resource."""
118
94
  if not self._closed:
119
95
  self._closed = True
120
96
  await self.cleanup()
121
97
 
122
98
  def __del__(self) -> None:
123
- """Ensure cleanup is called even if explicitly forgotten."""
124
99
  if not self._closed:
125
- # Create cleanup task if event loop is available
126
100
  with contextlib.suppress(RuntimeError):
127
101
  loop = asyncio.get_event_loop()
128
102
  if loop.is_running():
@@ -130,8 +104,6 @@ class ManagedResource(ABC):
130
104
 
131
105
 
132
106
  class ManagedTemporaryFile(ManagedResource):
133
- """Temporary file with automatic cleanup on error scenarios."""
134
-
135
107
  def __init__(
136
108
  self,
137
109
  suffix: str = "",
@@ -142,43 +114,35 @@ class ManagedTemporaryFile(ManagedResource):
142
114
  self.temp_file = tempfile.NamedTemporaryFile(
143
115
  suffix=suffix,
144
116
  prefix=prefix,
145
- delete=False, # We'll handle deletion ourselves
117
+ delete=False,
146
118
  )
147
119
  self.path = Path(self.temp_file.name)
148
120
 
149
121
  async def cleanup(self) -> None:
150
- """Clean up temporary file."""
151
122
  if not self._closed:
152
123
  self._closed = True
153
124
 
154
- # Close file handle
155
125
  if not self.temp_file.closed:
156
126
  self.temp_file.close()
157
127
 
158
- # Remove file if it exists
159
128
  try:
160
129
  if self.path.exists():
161
130
  self.path.unlink()
162
131
  except OSError as e:
163
- # Log but don't raise - cleanup should be best effort
164
132
  logging.getLogger(__name__).warning(
165
133
  f"Failed to remove temporary file {self.path}: {e}"
166
134
  )
167
135
 
168
136
  def write_text(self, content: str, encoding: str = "utf-8") -> None:
169
- """Write text content to the temporary file."""
170
137
  if self._closed:
171
138
  raise RuntimeError("Cannot write to closed temporary file")
172
139
  self.path.write_text(content, encoding=encoding)
173
140
 
174
141
  def read_text(self, encoding: str = "utf-8") -> str:
175
- """Read text content from the temporary file."""
176
142
  return self.path.read_text(encoding=encoding)
177
143
 
178
144
 
179
145
  class ManagedTemporaryDirectory(ManagedResource):
180
- """Temporary directory with automatic cleanup on error scenarios."""
181
-
182
146
  def __init__(
183
147
  self,
184
148
  suffix: str = "",
@@ -190,7 +154,6 @@ class ManagedTemporaryDirectory(ManagedResource):
190
154
  self.path = Path(self.temp_dir)
191
155
 
192
156
  async def cleanup(self) -> None:
193
- """Clean up temporary directory and all contents."""
194
157
  if not self._closed:
195
158
  self._closed = True
196
159
 
@@ -206,8 +169,6 @@ class ManagedTemporaryDirectory(ManagedResource):
206
169
 
207
170
 
208
171
  class ManagedProcess(ManagedResource):
209
- """Process with automatic cleanup on error scenarios."""
210
-
211
172
  def __init__(
212
173
  self,
213
174
  process: asyncio.subprocess.Process,
@@ -219,18 +180,15 @@ class ManagedProcess(ManagedResource):
219
180
  self.timeout = timeout
220
181
 
221
182
  async def cleanup(self) -> None:
222
- """Clean up process with graceful termination."""
223
183
  if not self._closed and self.process.returncode is None:
224
184
  self._closed = True
225
185
 
226
186
  try:
227
- # Try graceful termination first
228
187
  self.process.terminate()
229
188
 
230
189
  try:
231
190
  await asyncio.wait_for(self.process.wait(), timeout=5.0)
232
191
  except TimeoutError:
233
- # Force kill if graceful termination fails
234
192
  self.process.kill()
235
193
  try:
236
194
  await asyncio.wait_for(self.process.wait(), timeout=2.0)
@@ -240,7 +198,6 @@ class ManagedProcess(ManagedResource):
240
198
  )
241
199
 
242
200
  except ProcessLookupError:
243
- # Process already terminated
244
201
  pass
245
202
  except Exception as e:
246
203
  logging.getLogger(__name__).warning(
@@ -249,8 +206,6 @@ class ManagedProcess(ManagedResource):
249
206
 
250
207
 
251
208
  class ManagedTask(ManagedResource):
252
- """Asyncio task with automatic cancellation on error scenarios."""
253
-
254
209
  def __init__(
255
210
  self,
256
211
  task: asyncio.Task[t.Any],
@@ -262,7 +217,6 @@ class ManagedTask(ManagedResource):
262
217
  self.timeout = timeout
263
218
 
264
219
  async def cleanup(self) -> None:
265
- """Clean up task with cancellation."""
266
220
  if not self._closed and not self.task.done():
267
221
  self._closed = True
268
222
 
@@ -271,15 +225,12 @@ class ManagedTask(ManagedResource):
271
225
  try:
272
226
  await asyncio.wait_for(self.task, timeout=self.timeout)
273
227
  except (TimeoutError, asyncio.CancelledError):
274
- # Expected when cancelling or timing out
275
228
  pass
276
229
  except Exception as e:
277
230
  logging.getLogger(__name__).warning(f"Error cleaning up task: {e}")
278
231
 
279
232
 
280
233
  class ManagedFileHandle(ManagedResource):
281
- """File handle with automatic closing on error scenarios."""
282
-
283
234
  def __init__(
284
235
  self,
285
236
  file_handle: t.IO[t.Any],
@@ -289,7 +240,6 @@ class ManagedFileHandle(ManagedResource):
289
240
  self.file_handle = file_handle
290
241
 
291
242
  async def cleanup(self) -> None:
292
- """Clean up file handle."""
293
243
  if not self._closed and not self.file_handle.closed:
294
244
  self._closed = True
295
245
 
@@ -300,8 +250,6 @@ class ManagedFileHandle(ManagedResource):
300
250
 
301
251
 
302
252
  class ResourceContext:
303
- """Context manager for automatic resource management."""
304
-
305
253
  def __init__(self) -> None:
306
254
  self.resource_manager = ResourceManager()
307
255
 
@@ -310,7 +258,6 @@ class ResourceContext:
310
258
  suffix: str = "",
311
259
  prefix: str = "crackerjack-",
312
260
  ) -> ManagedTemporaryFile:
313
- """Create a managed temporary file."""
314
261
  return ManagedTemporaryFile(suffix, prefix, self.resource_manager)
315
262
 
316
263
  def managed_temp_dir(
@@ -318,7 +265,6 @@ class ResourceContext:
318
265
  suffix: str = "",
319
266
  prefix: str = "crackerjack-",
320
267
  ) -> ManagedTemporaryDirectory:
321
- """Create a managed temporary directory."""
322
268
  return ManagedTemporaryDirectory(suffix, prefix, self.resource_manager)
323
269
 
324
270
  def managed_process(
@@ -326,7 +272,6 @@ class ResourceContext:
326
272
  process: asyncio.subprocess.Process,
327
273
  timeout: float = 30.0,
328
274
  ) -> ManagedProcess:
329
- """Create a managed process."""
330
275
  return ManagedProcess(process, timeout, self.resource_manager)
331
276
 
332
277
  def managed_task(
@@ -334,14 +279,12 @@ class ResourceContext:
334
279
  task: asyncio.Task[t.Any],
335
280
  timeout: float = 30.0,
336
281
  ) -> ManagedTask:
337
- """Create a managed task."""
338
282
  return ManagedTask(task, timeout, self.resource_manager)
339
283
 
340
284
  def managed_file(
341
285
  self,
342
286
  file_handle: t.IO[t.Any],
343
287
  ) -> ManagedFileHandle:
344
- """Create a managed file handle."""
345
288
  return ManagedFileHandle(file_handle, self.resource_manager)
346
289
 
347
290
  async def __aenter__(self) -> "ResourceContext":
@@ -357,18 +300,15 @@ class ResourceContext:
357
300
  await self.resource_manager.__aexit__(exc_type, exc_val, exc_tb)
358
301
 
359
302
 
360
- # Global resource manager registry
361
303
  _global_managers: weakref.WeakSet[ResourceManager] = weakref.WeakSet()
362
304
 
363
305
 
364
306
  def register_global_resource_manager(manager: ResourceManager) -> None:
365
- """Register a resource manager for global cleanup."""
366
307
  _global_managers.add(manager)
367
308
 
368
309
 
369
310
  async def cleanup_all_global_resources() -> None:
370
- """Clean up all globally registered resource managers."""
371
- managers = list(_global_managers)
311
+ managers = list[t.Any](_global_managers)
372
312
 
373
313
  cleanup_tasks = [asyncio.create_task(manager.cleanup_all()) for manager in managers]
374
314
 
@@ -376,17 +316,16 @@ async def cleanup_all_global_resources() -> None:
376
316
  await asyncio.gather(*cleanup_tasks, return_exceptions=True)
377
317
 
378
318
 
379
- # Cleanup helper context managers
380
319
  @contextlib.asynccontextmanager
381
- async def with_resource_cleanup():
382
- """Context manager that ensures resource cleanup on any exit."""
320
+ async def with_resource_cleanup() -> t.AsyncIterator[ResourceContext]:
383
321
  async with ResourceContext() as ctx:
384
322
  yield ctx
385
323
 
386
324
 
387
325
  @contextlib.asynccontextmanager
388
- async def with_temp_file(suffix: str = "", prefix: str = "crackerjack-"):
389
- """Context manager for temporary file with automatic cleanup."""
326
+ async def with_temp_file(
327
+ suffix: str = "", prefix: str = "crackerjack-"
328
+ ) -> t.AsyncIterator[ManagedTemporaryFile]:
390
329
  async with ResourceContext() as ctx:
391
330
  temp_file = ctx.managed_temp_file(suffix, prefix)
392
331
  try:
@@ -396,8 +335,9 @@ async def with_temp_file(suffix: str = "", prefix: str = "crackerjack-"):
396
335
 
397
336
 
398
337
  @contextlib.asynccontextmanager
399
- async def with_temp_dir(suffix: str = "", prefix: str = "crackerjack-"):
400
- """Context manager for temporary directory with automatic cleanup."""
338
+ async def with_temp_dir(
339
+ suffix: str = "", prefix: str = "crackerjack-"
340
+ ) -> t.AsyncIterator[ManagedTemporaryDirectory]:
401
341
  async with ResourceContext() as ctx:
402
342
  temp_dir = ctx.managed_temp_dir(suffix, prefix)
403
343
  try:
@@ -410,20 +350,16 @@ async def with_temp_dir(suffix: str = "", prefix: str = "crackerjack-"):
410
350
  async def with_managed_process(
411
351
  process: asyncio.subprocess.Process,
412
352
  timeout: float = 30.0,
413
- ):
414
- """Context manager for process with automatic cleanup."""
353
+ ) -> t.AsyncIterator[asyncio.subprocess.Process]:
415
354
  async with ResourceContext() as ctx:
416
355
  managed_proc = ctx.managed_process(process, timeout)
417
356
  try:
418
- yield managed_proc
357
+ yield managed_proc.process
419
358
  finally:
420
359
  await managed_proc.cleanup()
421
360
 
422
361
 
423
- # Enhanced error handling utilities
424
362
  class ResourceLeakDetector:
425
- """Detector for potential resource leaks during development."""
426
-
427
363
  def __init__(self) -> None:
428
364
  self.open_files: set[str] = set()
429
365
  self.active_processes: set[int] = set()
@@ -431,35 +367,28 @@ class ResourceLeakDetector:
431
367
  self._start_time = time.time()
432
368
 
433
369
  def track_file(self, file_path: str) -> None:
434
- """Track an opened file."""
435
370
  self.open_files.add(file_path)
436
371
 
437
372
  def untrack_file(self, file_path: str) -> None:
438
- """Untrack a closed file."""
439
373
  self.open_files.discard(file_path)
440
374
 
441
375
  def track_process(self, pid: int) -> None:
442
- """Track a spawned process."""
443
376
  self.active_processes.add(pid)
444
377
 
445
378
  def untrack_process(self, pid: int) -> None:
446
- """Untrack a terminated process."""
447
379
  self.active_processes.discard(pid)
448
380
 
449
381
  def track_task(self, task: asyncio.Task[t.Any]) -> None:
450
- """Track an active task."""
451
382
  self.active_tasks.add(task)
452
383
 
453
384
  def untrack_task(self, task: asyncio.Task[t.Any]) -> None:
454
- """Untrack a completed task."""
455
385
  self.active_tasks.discard(task)
456
386
 
457
387
  def get_leak_report(self) -> dict[str, t.Any]:
458
- """Get a report of potential resource leaks."""
459
388
  return {
460
389
  "duration_seconds": time.time() - self._start_time,
461
- "open_files": list(self.open_files),
462
- "active_processes": list(self.active_processes),
390
+ "open_files": list[t.Any](self.open_files),
391
+ "active_processes": list[t.Any](self.active_processes),
463
392
  "active_tasks": len([t for t in self.active_tasks if not t.done()]),
464
393
  "total_tracked_files": len(self.open_files),
465
394
  "total_tracked_processes": len(self.active_processes),
@@ -467,7 +396,6 @@ class ResourceLeakDetector:
467
396
  }
468
397
 
469
398
  def has_potential_leaks(self) -> bool:
470
- """Check if there are potential resource leaks."""
471
399
  return bool(
472
400
  self.open_files
473
401
  or self.active_processes
@@ -475,24 +403,20 @@ class ResourceLeakDetector:
475
403
  )
476
404
 
477
405
 
478
- # Development-time resource leak detection
479
406
  _leak_detector: ResourceLeakDetector | None = None
480
407
 
481
408
 
482
409
  def enable_leak_detection() -> ResourceLeakDetector:
483
- """Enable resource leak detection for development."""
484
410
  global _leak_detector
485
411
  _leak_detector = ResourceLeakDetector()
486
412
  return _leak_detector
487
413
 
488
414
 
489
415
  def get_leak_detector() -> ResourceLeakDetector | None:
490
- """Get the current resource leak detector, if enabled."""
491
416
  return _leak_detector
492
417
 
493
418
 
494
419
  def disable_leak_detection() -> dict[str, t.Any] | None:
495
- """Disable resource leak detection and return final report."""
496
420
  global _leak_detector
497
421
  if _leak_detector:
498
422
  report = _leak_detector.get_leak_report()