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,16 @@
1
1
  import typing as t
2
2
 
3
- from crackerjack.mcp.context import get_context
3
+ from crackerjack.mcp.context import MCPServerContext, get_context
4
+ from crackerjack.mcp.rate_limiter import RateLimitMiddleware
4
5
  from crackerjack.services.input_validator import (
6
+ SecureInputValidator,
5
7
  get_input_validator,
6
8
  )
7
9
 
10
+ if t.TYPE_CHECKING:
11
+ from crackerjack.core.workflow_orchestrator import WorkflowOrchestrator
12
+ from crackerjack.models.config import WorkflowOptions
13
+
8
14
 
9
15
  async def create_task_with_subagent(
10
16
  description: str,
@@ -12,10 +18,8 @@ async def create_task_with_subagent(
12
18
  subagent_type: str,
13
19
  ) -> dict[str, t.Any]:
14
20
  try:
15
- # Input validation with security checks
16
21
  validator = get_input_validator()
17
22
 
18
- # Validate description
19
23
  desc_result = validator.validate_command_args(description)
20
24
  if not desc_result.valid:
21
25
  return {
@@ -24,7 +28,6 @@ async def create_task_with_subagent(
24
28
  "validation_type": desc_result.validation_type,
25
29
  }
26
30
 
27
- # Validate prompt
28
31
  prompt_result = validator.validate_command_args(prompt)
29
32
  if not prompt_result.valid:
30
33
  return {
@@ -33,7 +36,6 @@ async def create_task_with_subagent(
33
36
  "validation_type": prompt_result.validation_type,
34
37
  }
35
38
 
36
- # Validate subagent_type (should be safe identifier)
37
39
  subagent_result = validator.sanitizer.sanitize_string(
38
40
  subagent_type, max_length=100, strict_alphanumeric=True
39
41
  )
@@ -44,7 +46,6 @@ async def create_task_with_subagent(
44
46
  "validation_type": subagent_result.validation_type,
45
47
  }
46
48
 
47
- # Use sanitized values
48
49
  sanitized_description = desc_result.sanitized_value or description
49
50
  sanitized_prompt = prompt_result.sanitized_value or prompt
50
51
  sanitized_subagent = subagent_result.sanitized_value
@@ -72,7 +73,9 @@ async def create_task_with_subagent(
72
73
  }
73
74
 
74
75
 
75
- async def _validate_stage_request(context, rate_limiter) -> str | None:
76
+ async def _validate_stage_request(
77
+ context: MCPServerContext | None, rate_limiter: RateLimitMiddleware | None
78
+ ) -> str | None:
76
79
  if not context:
77
80
  return '{"error": "Server context not available", "success": false}'
78
81
 
@@ -83,17 +86,15 @@ async def _validate_stage_request(context, rate_limiter) -> str | None:
83
86
  return None
84
87
 
85
88
 
86
- def _parse_stage_args(args: str, kwargs: str) -> tuple[str, dict] | str:
89
+ def _parse_stage_args(args: str, kwargs: str) -> tuple[str, dict[str, t.Any]] | str:
87
90
  try:
88
91
  validator = get_input_validator()
89
92
 
90
- # Validate stage argument
91
93
  stage_validation = _validate_stage_argument(validator, args)
92
94
  if isinstance(stage_validation, str):
93
95
  return stage_validation
94
96
  stage = stage_validation
95
97
 
96
- # Validate and parse kwargs
97
98
  kwargs_validation = _validate_kwargs_argument(validator, kwargs)
98
99
  if isinstance(kwargs_validation, str):
99
100
  return kwargs_validation
@@ -105,15 +106,14 @@ def _parse_stage_args(args: str, kwargs: str) -> tuple[str, dict] | str:
105
106
  return f'{{"error": "Stage argument parsing failed: {e}", "success": false}}'
106
107
 
107
108
 
108
- def _validate_stage_argument(validator, args: str) -> str:
109
- """Validate and sanitize the stage argument."""
109
+ def _validate_stage_argument(validator: SecureInputValidator, args: str) -> str:
110
110
  stage_result = validator.sanitizer.sanitize_string(
111
111
  args.strip(), max_length=50, strict_alphanumeric=True
112
112
  )
113
113
  if not stage_result.valid:
114
114
  return f'{{"error": "Invalid stage argument: {stage_result.error_message}", "success": false}}'
115
115
 
116
- stage = stage_result.sanitized_value.lower()
116
+ stage: str = str(stage_result.sanitized_value).lower()
117
117
  valid_stages = {"fast", "comprehensive", "tests", "cleaning", "init"}
118
118
 
119
119
  if stage not in valid_stages:
@@ -122,9 +122,10 @@ def _validate_stage_argument(validator, args: str) -> str:
122
122
  return stage
123
123
 
124
124
 
125
- def _validate_kwargs_argument(validator, kwargs: str) -> dict | str:
126
- """Validate and parse the kwargs argument."""
127
- extra_kwargs = {}
125
+ def _validate_kwargs_argument(
126
+ validator: SecureInputValidator, kwargs: str
127
+ ) -> dict[str, t.Any] | str:
128
+ extra_kwargs: dict[str, t.Any] = {}
128
129
  if not kwargs.strip():
129
130
  return extra_kwargs
130
131
 
@@ -134,7 +135,6 @@ def _validate_kwargs_argument(validator, kwargs: str) -> dict | str:
134
135
 
135
136
  extra_kwargs = kwargs_result.sanitized_value
136
137
 
137
- # Additional validation on JSON structure
138
138
  if not isinstance(extra_kwargs, dict):
139
139
  return f'{{"error": "kwargs must be a JSON object, got {type(extra_kwargs).__name__}", "success": false}}'
140
140
 
@@ -146,31 +146,171 @@ def _configure_stage_options(stage: str) -> "WorkflowOptions":
146
146
 
147
147
  options = WorkflowOptions()
148
148
  if stage in {"fast", "comprehensive"}:
149
- options.skip_hooks = False
149
+ options.hooks.skip_hooks = False
150
150
  elif stage == "tests":
151
151
  options.testing.test = True
152
152
  elif stage == "cleaning":
153
153
  options.cleaning.clean = True
154
154
  elif stage == "init":
155
- options.skip_hooks = True
155
+ options.hooks.skip_hooks = True
156
156
  return options
157
157
 
158
158
 
159
- def _execute_stage(orchestrator, stage: str, options) -> bool:
159
+ def _execute_stage(
160
+ orchestrator: "WorkflowOrchestrator", stage: str, options: "WorkflowOptions"
161
+ ) -> bool:
162
+ # Convert WorkflowOptions to OptionsProtocol
163
+ adapted_options = _adapt_workflow_options_to_protocol(options)
164
+
160
165
  if stage == "fast":
161
- return orchestrator.run_fast_hooks_only(options)
166
+ return orchestrator.run_fast_hooks_only(adapted_options)
162
167
  if stage == "comprehensive":
163
- return orchestrator.run_comprehensive_hooks_only(options)
168
+ return orchestrator.run_comprehensive_hooks_only(adapted_options)
164
169
  if stage == "tests":
165
- return orchestrator.run_testing_phase(options)
170
+ return orchestrator.run_testing_phase(adapted_options)
166
171
  if stage == "cleaning":
167
- return orchestrator.run_cleaning_phase(options)
168
- if stage == "init":
169
- return _execute_init_stage(orchestrator)
172
+ return orchestrator.run_cleaning_phase(adapted_options)
170
173
  return False
171
174
 
172
175
 
173
- def _execute_init_stage(orchestrator) -> bool:
176
+ def _adapt_workflow_options_to_protocol(options: "WorkflowOptions") -> t.Any:
177
+ """Adapt WorkflowOptions to match OptionsProtocol."""
178
+ return _AdaptedOptions(options) # type: ignore
179
+
180
+
181
+ class _AdaptedOptions:
182
+ """Adapter class to convert WorkflowOptions to OptionsProtocol."""
183
+
184
+ def __init__(self, opts: "WorkflowOptions"):
185
+ self.opts = opts
186
+
187
+ # Git properties
188
+ @property
189
+ def commit(self) -> bool:
190
+ return getattr(self.opts.git, "commit", False)
191
+
192
+ @property
193
+ def create_pr(self) -> bool:
194
+ return getattr(self.opts.git, "create_pr", False)
195
+
196
+ # Execution properties
197
+ @property
198
+ def interactive(self) -> bool:
199
+ return getattr(self.opts.execution, "interactive", False)
200
+
201
+ @property
202
+ def no_config_updates(self) -> bool:
203
+ return getattr(self.opts.execution, "no_config_updates", False)
204
+
205
+ @property
206
+ def verbose(self) -> bool:
207
+ return getattr(self.opts.execution, "verbose", False)
208
+
209
+ @property
210
+ def async_mode(self) -> bool:
211
+ return getattr(self.opts.execution, "async_mode", False)
212
+
213
+ # Testing properties
214
+ @property
215
+ def test(self) -> bool:
216
+ return getattr(self.opts.testing, "test", False)
217
+
218
+ @property
219
+ def benchmark(self) -> bool:
220
+ return getattr(self.opts.testing, "benchmark", False)
221
+
222
+ @property
223
+ def test_workers(self) -> int:
224
+ return getattr(self.opts.testing, "test_workers", 0)
225
+
226
+ @property
227
+ def test_timeout(self) -> int:
228
+ return getattr(self.opts.testing, "test_timeout", 0)
229
+
230
+ # Publishing properties
231
+ @property
232
+ def publish(self) -> t.Any | None:
233
+ return getattr(self.opts.publishing, "publish", None)
234
+
235
+ @property
236
+ def bump(self) -> t.Any | None:
237
+ return getattr(self.opts.publishing, "bump", None)
238
+
239
+ @property
240
+ def all(self) -> t.Any | None:
241
+ return getattr(self.opts.publishing, "all", None)
242
+
243
+ @property
244
+ def no_git_tags(self) -> bool:
245
+ return getattr(self.opts.publishing, "no_git_tags", False)
246
+
247
+ @property
248
+ def skip_version_check(self) -> bool:
249
+ return getattr(self.opts.publishing, "skip_version_check", False)
250
+
251
+ # AI properties
252
+ @property
253
+ def ai_agent(self) -> bool:
254
+ return getattr(self.opts.ai, "ai_agent", False)
255
+
256
+ @property
257
+ def start_mcp_server(self) -> bool:
258
+ return getattr(self.opts.ai, "start_mcp_server", False)
259
+
260
+ # Hook properties
261
+ @property
262
+ def skip_hooks(self) -> bool:
263
+ return getattr(self.opts.hooks, "skip_hooks", False)
264
+
265
+ @property
266
+ def update_precommit(self) -> bool:
267
+ return getattr(self.opts.hooks, "update_precommit", False)
268
+
269
+ @property
270
+ def experimental_hooks(self) -> bool:
271
+ return getattr(self.opts.hooks, "experimental_hooks", False)
272
+
273
+ @property
274
+ def enable_pyrefly(self) -> bool:
275
+ return getattr(self.opts.hooks, "enable_pyrefly", False)
276
+
277
+ @property
278
+ def enable_ty(self) -> bool:
279
+ return getattr(self.opts.hooks, "enable_ty", False)
280
+
281
+ # Cleaning properties
282
+ @property
283
+ def clean(self) -> bool:
284
+ return getattr(self.opts.cleaning, "clean", False)
285
+
286
+ # Progress properties
287
+ @property
288
+ def track_progress(self) -> bool:
289
+ return getattr(self.opts.progress, "track_progress", False)
290
+
291
+ # Default/static properties
292
+ @property
293
+ def cleanup(self) -> t.Any | None:
294
+ return None
295
+
296
+ @property
297
+ def cleanup_pypi(self) -> bool:
298
+ return False
299
+
300
+ @property
301
+ def coverage(self) -> bool:
302
+ return False
303
+
304
+ @property
305
+ def keep_releases(self) -> int:
306
+ return 10
307
+
308
+ @property
309
+ def fast(self) -> bool:
310
+ return False
311
+
312
+
313
+ def _execute_init_stage(orchestrator: "WorkflowOrchestrator") -> bool:
174
314
  try:
175
315
  from pathlib import Path
176
316
 
@@ -188,7 +328,8 @@ def _execute_init_stage(orchestrator) -> bool:
188
328
 
189
329
  results = init_service.initialize_project_full(target_path=Path.cwd())
190
330
 
191
- return results.get("success", False)
331
+ success_result: bool = bool(results.get("success", False))
332
+ return success_result
192
333
 
193
334
  except Exception as e:
194
335
  if hasattr(orchestrator, "console"):
@@ -197,7 +338,7 @@ def _execute_init_stage(orchestrator) -> bool:
197
338
 
198
339
 
199
340
  def register_core_tools(mcp_app: t.Any) -> None:
200
- @mcp_app.tool()
341
+ @mcp_app.tool() # type: ignore[misc]
201
342
  async def run_crackerjack_stage(args: str, kwargs: str) -> str:
202
343
  context = get_context()
203
344
  rate_limiter = context.rate_limiter if context else None
@@ -258,8 +399,8 @@ def _detect_errors_and_suggestions(
258
399
  ) -> tuple[list[str], list[str]]:
259
400
  import re
260
401
 
261
- detected_errors = []
262
- suggestions = []
402
+ detected_errors: list[str] = []
403
+ suggestions: list[str] = []
263
404
 
264
405
  for error_type, pattern in _get_error_patterns():
265
406
  if re.search(pattern, text, re.IGNORECASE):
@@ -271,7 +412,7 @@ def _detect_errors_and_suggestions(
271
412
 
272
413
 
273
414
  def register_analyze_errors_tool(mcp_app: t.Any) -> None:
274
- @mcp_app.tool()
415
+ @mcp_app.tool() # type: ignore[misc]
275
416
  async def analyze_errors(output: str = "", include_suggestions: bool = True) -> str:
276
417
  context = get_context()
277
418
  if not context:
@@ -25,7 +25,8 @@ def _get_cached_patterns(context: t.Any, use_cache: bool) -> list[t.Any]:
25
25
  with suppress(Exception):
26
26
  cache = getattr(context, "cache", None)
27
27
  if cache and hasattr(cache, "get_error_patterns"):
28
- return cache.get_error_patterns()
28
+ patterns: list[t.Any] = cache.get_error_patterns()
29
+ return patterns
29
30
 
30
31
  return []
31
32
 
@@ -70,7 +71,7 @@ def _build_error_analysis(patterns: list[t.Any], context: t.Any) -> dict[str, t.
70
71
 
71
72
 
72
73
  def _categorize_error_patterns(patterns: list[t.Any]) -> dict[str, list[t.Any]]:
73
- categories = {
74
+ categories: dict[str, list[t.Any]] = {
74
75
  "syntax_errors": [],
75
76
  "import_errors": [],
76
77
  "type_errors": [],
@@ -15,7 +15,7 @@ def register_execution_tools(mcp_app: t.Any) -> None:
15
15
 
16
16
 
17
17
  def _register_execute_crackerjack_tool(mcp_app: t.Any) -> None:
18
- @mcp_app.tool()
18
+ @mcp_app.tool() # type: ignore[misc]
19
19
  async def execute_crackerjack(args: str, kwargs: str) -> str:
20
20
  context = get_context()
21
21
 
@@ -29,13 +29,11 @@ def _register_execute_crackerjack_tool(mcp_app: t.Any) -> None:
29
29
 
30
30
  extra_kwargs = kwargs_result["kwargs"]
31
31
 
32
- # Add extended timeout for long-running operations
33
32
  if "execution_timeout" not in extra_kwargs:
34
- # Default to 15 minutes, extend to 20 minutes for test operations
35
33
  if extra_kwargs.get("test", False) or extra_kwargs.get("testing", False):
36
- extra_kwargs["execution_timeout"] = 1200 # 20 minutes for tests
34
+ extra_kwargs["execution_timeout"] = 1200
37
35
  else:
38
- extra_kwargs["execution_timeout"] = 900 # 15 minutes default
36
+ extra_kwargs["execution_timeout"] = 900
39
37
 
40
38
  try:
41
39
  result = await execute_crackerjack_workflow(args, extra_kwargs)
@@ -53,7 +51,7 @@ def _register_execute_crackerjack_tool(mcp_app: t.Any) -> None:
53
51
 
54
52
 
55
53
  def _register_smart_error_analysis_tool(mcp_app: t.Any) -> None:
56
- @mcp_app.tool()
54
+ @mcp_app.tool() # type: ignore[misc]
57
55
  async def smart_error_analysis(use_cache: bool = True) -> str:
58
56
  context = get_context()
59
57
 
@@ -71,7 +69,7 @@ def _register_smart_error_analysis_tool(mcp_app: t.Any) -> None:
71
69
 
72
70
 
73
71
  def _register_init_crackerjack_tool(mcp_app: t.Any) -> None:
74
- @mcp_app.tool()
72
+ @mcp_app.tool() # type: ignore[misc]
75
73
  def init_crackerjack(args: str = "", kwargs: str = "{}") -> str:
76
74
  try:
77
75
  target_path, force, error = _parse_init_arguments(args, kwargs)
@@ -86,7 +84,7 @@ def _register_init_crackerjack_tool(mcp_app: t.Any) -> None:
86
84
 
87
85
 
88
86
  def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
89
- @mcp_app.tool()
87
+ @mcp_app.tool() # type: ignore[misc]
90
88
  def suggest_agents(
91
89
  task_description: str = "",
92
90
  project_type: str = "python",
@@ -139,7 +137,7 @@ def _parse_kwargs(kwargs: str) -> dict[str, t.Any]:
139
137
  def _parse_init_arguments(args: str, kwargs: str) -> tuple[t.Any, bool, str | None]:
140
138
  try:
141
139
  target_path = args.strip() or "."
142
- kwargs_dict = json.loads(kwargs) if kwargs.strip() else {}
140
+ kwargs_dict: dict[str, t.Any] = json.loads(kwargs) if kwargs.strip() else {}
143
141
  force = kwargs_dict.get("force") or False
144
142
 
145
143
  from pathlib import Path
@@ -165,7 +163,7 @@ def _execute_initialization(target_path: t.Any, force: bool) -> dict[str, t.Any]
165
163
  from crackerjack.services.git import GitService
166
164
 
167
165
  filesystem = FileSystemService()
168
- git_service = GitService()
166
+ git_service = GitService(console)
169
167
  return InitializationService(
170
168
  console, filesystem, git_service, target_path
171
169
  ).initialize_project_full(force=force)
@@ -85,7 +85,7 @@ async def _validate_context_and_rate_limit(context: t.Any) -> str | None:
85
85
  return None
86
86
 
87
87
 
88
- def _handle_task_exception(job_id: str, task: asyncio.Task) -> None:
88
+ def _handle_task_exception(job_id: str, task: asyncio.Task[t.Any]) -> None:
89
89
  import tempfile
90
90
  from pathlib import Path
91
91
 
@@ -405,10 +405,9 @@ def _create_workflow_options(kwargs: dict[str, t.Any]) -> t.Any:
405
405
 
406
406
  options = WorkflowOptions()
407
407
  options.testing.test = kwargs.get("test", True)
408
- options.ai_agent = kwargs.get("ai_agent", True)
409
- options.skip_hooks = kwargs.get("skip_hooks", False)
408
+ options.ai.ai_agent = kwargs.get("ai_agent", True)
409
+ options.hooks.skip_hooks = kwargs.get("skip_hooks", False)
410
410
 
411
- options.proactive_mode = kwargs.get("proactive_mode", True)
412
411
  return options
413
412
 
414
413
 
@@ -418,8 +417,10 @@ async def _execute_single_iteration(
418
417
  options: t.Any,
419
418
  ) -> bool:
420
419
  if use_advanced_orchestrator:
421
- return await orchestrator.execute_orchestrated_workflow(options)
422
- return await orchestrator.run_complete_workflow(options)
420
+ result = await orchestrator.execute_orchestrated_workflow(options)
421
+ return bool(result)
422
+ result = await orchestrator.run_complete_workflow(options)
423
+ return bool(result)
423
424
 
424
425
 
425
426
  def _create_success_result(
@@ -715,6 +716,8 @@ def _register_init_crackerjack_tool(mcp_app: t.Any) -> None:
715
716
 
716
717
  try:
717
718
  results = _execute_initialization(context, target_path, force)
719
+ if isinstance(results, bool):
720
+ return json.dumps({"success": results})
718
721
  return _create_init_success_response(results, target_path, force)
719
722
  except Exception as e:
720
723
  return _create_init_exception_response(e, target_path)
@@ -730,18 +733,20 @@ def _parse_init_arguments(args: str, kwargs: str) -> tuple[t.Any, bool, str | No
730
733
  target_path = args.strip() or None
731
734
 
732
735
  try:
733
- extra_kwargs = json.loads(kwargs) if kwargs.strip() else {}
736
+ extra_kwargs: dict[str, t.Any] = json.loads(kwargs) if kwargs.strip() else {}
734
737
  except json.JSONDecodeError as e:
735
738
  return None, False, _create_init_error_response(f"Invalid JSON in kwargs: {e}")
736
739
 
737
740
  force = extra_kwargs.get("force", False)
738
741
 
739
742
  if target_path:
740
- target_path = Path(target_path).resolve()
743
+ target_path_obj = Path(target_path).resolve()
744
+ target_path = str(target_path_obj)
741
745
  else:
742
- target_path = Path.cwd()
746
+ target_path_obj = Path.cwd()
747
+ target_path = str(target_path_obj)
743
748
 
744
- if not target_path.exists():
749
+ if not Path(target_path).exists():
745
750
  return (
746
751
  None,
747
752
  False,
@@ -751,9 +756,7 @@ def _parse_init_arguments(args: str, kwargs: str) -> tuple[t.Any, bool, str | No
751
756
  return target_path, force, None
752
757
 
753
758
 
754
- def _execute_initialization(
755
- context: t.Any, target_path: t.Any, force: bool
756
- ) -> dict[str, t.Any]:
759
+ def _execute_initialization(context: t.Any, target_path: t.Any, force: bool) -> bool:
757
760
  from crackerjack.services.filesystem import FileSystemService
758
761
  from crackerjack.services.git import GitService
759
762
  from crackerjack.services.initialization import InitializationService
@@ -792,15 +795,24 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
792
795
  project_type: str = "python",
793
796
  current_context: str = "",
794
797
  ) -> str:
795
- suggestions = {
796
- "primary_agents": [],
797
- "task_specific_agents": [],
798
- "usage_patterns": [],
798
+ suggestions: dict[str, list[dict[str, str]] | list[str] | str] = {
799
+ "primary_agents": t.cast(list[dict[str, str]], []),
800
+ "task_specific_agents": t.cast(list[dict[str, str]], []),
801
+ "usage_patterns": t.cast(list[str], []),
799
802
  "rationale": "",
800
803
  }
801
804
 
805
+ # Type cast the lists to ensure proper typing
806
+ primary_agents: list[dict[str, str]] = t.cast(
807
+ list[dict[str, str]], suggestions["primary_agents"]
808
+ )
809
+ task_specific_agents: list[dict[str, str]] = t.cast(
810
+ list[dict[str, str]], suggestions["task_specific_agents"]
811
+ )
812
+ t.cast(list[str], suggestions["usage_patterns"])
813
+
802
814
  if project_type.lower() == "python" or "python" in task_description.lower():
803
- suggestions["primary_agents"].append(
815
+ primary_agents.append(
804
816
  {
805
817
  "name": "crackerjack-architect",
806
818
  "emoji": "๐Ÿ—๏ธ",
@@ -810,11 +822,11 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
810
822
  }
811
823
  )
812
824
 
813
- suggestions["primary_agents"].append(
825
+ primary_agents.append(
814
826
  {
815
827
  "name": "python-pro",
816
828
  "emoji": "๐Ÿ",
817
- "description": "Modern Python development with type hints, async / await patterns, and clean architecture",
829
+ "description": "Modern Python development with type hints, async/await patterns, and clean architecture",
818
830
  "usage": "Use for implementing Python code with best practices",
819
831
  "priority": "HIGH",
820
832
  }
@@ -827,9 +839,9 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
827
839
  word in task_lower + context_lower
828
840
  for word in ("test", "testing", "coverage", "pytest")
829
841
  ):
830
- suggestions["task_specific_agents"].append(
842
+ task_specific_agents.append(
831
843
  {
832
- "name": "crackerjack - test-specialist",
844
+ "name": "crackerjack-test-specialist",
833
845
  "emoji": "๐Ÿงช",
834
846
  "description": "Advanced testing specialist for complex scenarios and coverage optimization",
835
847
  "usage": "Use for test creation, debugging test failures, and coverage improvements",
@@ -837,9 +849,9 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
837
849
  }
838
850
  )
839
851
 
840
- suggestions["task_specific_agents"].append(
852
+ task_specific_agents.append(
841
853
  {
842
- "name": "pytest - hypothesis-specialist",
854
+ "name": "pytest-hypothesis-specialist",
843
855
  "emoji": "๐Ÿงช",
844
856
  "description": "Advanced testing patterns and property-based testing",
845
857
  "usage": "Use for comprehensive test development and optimization",
@@ -851,12 +863,12 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
851
863
  word in task_lower + context_lower
852
864
  for word in ("security", "vulnerability", "auth", "permission")
853
865
  ):
854
- suggestions["task_specific_agents"].append(
866
+ task_specific_agents.append(
855
867
  {
856
868
  "name": "security-auditor",
857
869
  "emoji": "๐Ÿ”’",
858
- "description": "Security analysis, vulnerability detection, and secure coding practices",
859
- "usage": "Use for security review and vulnerability assessment",
870
+ "description": "Security auditing and vulnerability detection specialist",
871
+ "usage": "Use for identifying and mitigating security vulnerabilities",
860
872
  "priority": "HIGH",
861
873
  }
862
874
  )
@@ -865,12 +877,12 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
865
877
  word in task_lower + context_lower
866
878
  for word in ("architecture", "design", "api", "backend")
867
879
  ):
868
- suggestions["task_specific_agents"].append(
880
+ task_specific_agents.append(
869
881
  {
870
882
  "name": "backend-architect",
871
883
  "emoji": "๐Ÿ—๏ธ",
872
- "description": "System design, API architecture, and service integration patterns",
873
- "usage": "Use for architectural planning and system design",
884
+ "description": "Backend architecture and system design specialist",
885
+ "usage": "Use for complex backend design decisions and system architecture",
874
886
  "priority": "MEDIUM",
875
887
  }
876
888
  )
@@ -1,3 +1,5 @@
1
+ import typing as t
2
+
1
3
  from .intelligence_tools import (
2
4
  analyze_agent_performance,
3
5
  execute_smart_agent_task,
@@ -6,7 +8,7 @@ from .intelligence_tools import (
6
8
  )
7
9
 
8
10
 
9
- def register_intelligence_tools(mcp_app) -> None:
11
+ def register_intelligence_tools(mcp_app: t.Any) -> None:
10
12
  @mcp_app.tool()
11
13
  async def execute_smart_task(
12
14
  task_description: str,
@@ -14,7 +16,7 @@ def register_intelligence_tools(mcp_app) -> None:
14
16
  strategy: str = "single_best",
15
17
  max_agents: int = 3,
16
18
  use_learning: bool = True,
17
- ):
19
+ ) -> t.Any:
18
20
  return await execute_smart_agent_task(
19
21
  task_description,
20
22
  context_type,
@@ -28,7 +30,7 @@ def register_intelligence_tools(mcp_app) -> None:
28
30
  task_description: str,
29
31
  context_type: str = "general",
30
32
  include_analysis: bool = True,
31
- ):
33
+ ) -> t.Any:
32
34
  return await get_smart_agent_recommendation(
33
35
  task_description,
34
36
  context_type,
@@ -36,9 +38,9 @@ def register_intelligence_tools(mcp_app) -> None:
36
38
  )
37
39
 
38
40
  @mcp_app.tool()
39
- async def intelligence_system_status():
41
+ async def intelligence_system_status() -> t.Any:
40
42
  return await get_intelligence_system_status()
41
43
 
42
44
  @mcp_app.tool()
43
- async def agent_performance_analysis():
45
+ async def agent_performance_analysis() -> t.Any:
44
46
  return await analyze_agent_performance()
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import json
2
3
  import logging
3
4
  import typing as t
4
5
 
@@ -173,10 +174,12 @@ async def get_smart_agent_recommendation(
173
174
  if include_analysis:
174
175
  try:
175
176
  analysis = await system.analyze_task_complexity(task_description)
176
- response["complexity_analysis"] = analysis
177
+ response["complexity_analysis"] = json.dumps(analysis, indent=2)
177
178
  except Exception as e:
178
179
  logger.warning(f"Failed to analyze task complexity: {e}")
179
- response["complexity_analysis"] = {"error": str(e)}
180
+ response["complexity_analysis"] = json.dumps(
181
+ {"error": str(e)}, indent=2
182
+ )
180
183
 
181
184
  logger.debug(f"Generated recommendation for task: {task_description[:50]}...")
182
185
  return response