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
@@ -0,0 +1,100 @@
1
+ import asyncio
2
+ from pathlib import Path
3
+
4
+ from rich.console import Console
5
+
6
+ from crackerjack.core.workflow_orchestrator import WorkflowOrchestrator
7
+ from crackerjack.models.protocols import OptionsProtocol
8
+
9
+
10
+ class CrackerjackCLIFacade:
11
+ def __init__(
12
+ self,
13
+ console: Console | None = None,
14
+ pkg_path: Path | None = None,
15
+ ) -> None:
16
+ self.console = console or Console(force_terminal=True)
17
+ self.pkg_path = pkg_path or Path.cwd()
18
+ self.orchestrator = WorkflowOrchestrator(
19
+ console=self.console,
20
+ pkg_path=self.pkg_path,
21
+ )
22
+
23
+ def process(self, options: OptionsProtocol) -> None:
24
+ try:
25
+ if self._should_handle_special_mode(options):
26
+ self._handle_special_modes(options)
27
+ return
28
+ success = asyncio.run(self.orchestrator.run_complete_workflow(options))
29
+ if not success:
30
+ self.console.print("[red]โŒ Workflow completed with errors[/ red]")
31
+ else:
32
+ self.console.print(
33
+ "[green]๐ŸŽ‰ Workflow completed successfully ![/ green]"
34
+ )
35
+ except KeyboardInterrupt:
36
+ self.console.print("\n[yellow]โน๏ธ Operation cancelled by user[/ yellow]")
37
+ raise SystemExit(130)
38
+ except Exception as e:
39
+ self.console.print(f"[red]๐Ÿ’ฅ Unexpected error: {e}[/ red]")
40
+ if options.verbose:
41
+ import traceback
42
+
43
+ self.console.print(f"[dim]{traceback.format_exc()}[/ dim]")
44
+ raise SystemExit(1)
45
+
46
+ async def process_async(self, options: OptionsProtocol) -> None:
47
+ await asyncio.to_thread(self.process, options)
48
+
49
+ def _should_handle_special_mode(self, options: OptionsProtocol) -> bool:
50
+ return (
51
+ getattr(options, "start_mcp_server", False)
52
+ or getattr(options, "enterprise_batch", False)
53
+ or getattr(options, "monitor_dashboard", False)
54
+ )
55
+
56
+ def _handle_special_modes(self, options: OptionsProtocol) -> None:
57
+ if getattr(options, "start_mcp_server", False):
58
+ self._start_mcp_server()
59
+ elif getattr(options, "enterprise_batch", False):
60
+ self._handle_enterprise_batch(options)
61
+ elif getattr(options, "monitor_dashboard", False):
62
+ self._handle_monitor_dashboard(options)
63
+
64
+ def _start_mcp_server(self) -> None:
65
+ try:
66
+ from crackerjack.mcp.server import main as start_mcp_main
67
+
68
+ self.console.print(
69
+ "[bold cyan]๐Ÿค– Starting Crackerjack MCP Server...[/ bold cyan]",
70
+ )
71
+ start_mcp_main(str(self.pkg_path))
72
+ except ImportError:
73
+ self.console.print(
74
+ "[red]โŒ MCP server requires additional dependencies[/ red]",
75
+ )
76
+ self.console.print("[yellow]Install with: uv sync --group mcp[/ yellow]")
77
+ raise SystemExit(1)
78
+ except Exception as e:
79
+ self.console.print(f"[red]โŒ Failed to start MCP server: {e}[/ red]")
80
+ raise SystemExit(1)
81
+
82
+ def _handle_enterprise_batch(self, options: OptionsProtocol) -> None:
83
+ self.console.print(
84
+ "[red]โŒ Enterprise batch processing is not yet implemented[/ red]"
85
+ )
86
+ raise SystemExit(1)
87
+
88
+ def _handle_monitor_dashboard(self, options: OptionsProtocol) -> None:
89
+ self.console.print("[red]โŒ Monitoring dashboard is not yet implemented[/ red]")
90
+ raise SystemExit(1)
91
+
92
+
93
+ def create_crackerjack_runner(
94
+ console: Console | None = None,
95
+ pkg_path: Path | None = None,
96
+ ) -> CrackerjackCLIFacade:
97
+ return CrackerjackCLIFacade(console=console, pkg_path=pkg_path)
98
+
99
+
100
+ CrackerjackRunner = CrackerjackCLIFacade
@@ -1,26 +1,31 @@
1
1
  import asyncio
2
2
  import os
3
3
  import sys
4
+ import typing as t
4
5
  from pathlib import Path
5
6
 
6
7
  from rich.console import Console
7
8
 
8
9
  from .options import Options
9
10
 
11
+ if t.TYPE_CHECKING:
12
+ from crackerjack.services.config_template import (
13
+ ConfigTemplateService,
14
+ ConfigUpdateInfo,
15
+ )
16
+
10
17
 
11
18
  def setup_ai_agent_env(ai_agent: bool, debug_mode: bool = False) -> None:
12
- # Only set debug environment variable if debug mode is explicitly enabled
13
19
  if debug_mode:
14
20
  os.environ["CRACKERJACK_DEBUG"] = "1"
15
21
 
16
22
  if ai_agent:
17
23
  os.environ["AI_AGENT"] = "1"
18
- # Only enable AI agent debug if debug mode is explicitly requested
24
+
19
25
  if debug_mode:
20
26
  os.environ["AI_AGENT_DEBUG"] = "1"
21
27
  os.environ["AI_AGENT_VERBOSE"] = "1"
22
28
 
23
- # Show debug configuration when debug mode is enabled
24
29
  console = Console()
25
30
  console.print(
26
31
  "[bold cyan]๐Ÿ› AI Agent Debug Mode Configuration: [/ bold cyan]",
@@ -91,6 +96,24 @@ def handle_dashboard_mode(dev_mode: bool = False) -> None:
91
96
  console.print("\n[yellow]๐Ÿ›‘ Dashboard stopped[/ yellow]")
92
97
 
93
98
 
99
+ def handle_unified_dashboard_mode(port: int = 8675, dev_mode: bool = False) -> None:
100
+ from crackerjack.monitoring.websocket_server import CrackerjackMonitoringServer
101
+
102
+ console = Console()
103
+ console.print("[bold green]๐Ÿš€ Starting Unified Monitoring Dashboard[/bold green]")
104
+ console.print(
105
+ f"[bold cyan]๐ŸŒ WebSocket server on port {port} with real-time streaming and web UI[/bold cyan]",
106
+ )
107
+
108
+ try:
109
+ server = CrackerjackMonitoringServer()
110
+ asyncio.run(server.start_monitoring(port))
111
+ except KeyboardInterrupt:
112
+ console.print("\n[yellow]๐Ÿ›‘ Unified Dashboard stopped[/yellow]")
113
+ except Exception as e:
114
+ console.print(f"\n[red]โŒ Unified Dashboard failed: {e}[/red]")
115
+
116
+
94
117
  def handle_watchdog_mode() -> None:
95
118
  from crackerjack.mcp.service_watchdog import main as start_watchdog
96
119
 
@@ -145,6 +168,61 @@ def handle_restart_mcp_server(websocket_port: int | None = None) -> None:
145
168
  raise SystemExit(1)
146
169
 
147
170
 
171
+ def handle_start_zuban_lsp(port: int = 8677, mode: str = "tcp") -> None:
172
+ """Start Zuban LSP server."""
173
+ from crackerjack.services.zuban_lsp_service import create_zuban_lsp_service
174
+
175
+ console = Console()
176
+ console.print("[bold cyan]๐Ÿš€ Starting Zuban LSP Server[/bold cyan]")
177
+
178
+ async def _start() -> None:
179
+ lsp_service = await create_zuban_lsp_service(
180
+ port=port, mode=mode, console=console
181
+ )
182
+ if await lsp_service.start():
183
+ console.print(
184
+ f"[bold green]โœ… Zuban LSP server started on port {port} ({mode} mode)[/bold green]"
185
+ )
186
+ else:
187
+ console.print("[bold red]โŒ Failed to start Zuban LSP server[/bold red]")
188
+ raise SystemExit(1)
189
+
190
+ try:
191
+ asyncio.run(_start())
192
+ except KeyboardInterrupt:
193
+ console.print("\n[yellow]๐Ÿ›‘ Zuban LSP startup interrupted[/yellow]")
194
+
195
+
196
+ def handle_stop_zuban_lsp() -> None:
197
+ """Stop Zuban LSP server."""
198
+ from crackerjack.services.server_manager import stop_zuban_lsp
199
+
200
+ console = Console()
201
+ console.print("[bold red]๐Ÿ›‘ Stopping Zuban LSP Server[/bold red]")
202
+
203
+ if stop_zuban_lsp(console):
204
+ console.print(
205
+ "\n[bold green]โœ… Zuban LSP server stopped successfully[/bold green]"
206
+ )
207
+ else:
208
+ console.print("\n[bold red]โŒ Failed to stop Zuban LSP server[/bold red]")
209
+ raise SystemExit(1)
210
+
211
+
212
+ def handle_restart_zuban_lsp(port: int = 8677, mode: str = "tcp") -> None:
213
+ """Restart Zuban LSP server."""
214
+ from crackerjack.services.server_manager import restart_zuban_lsp
215
+
216
+ console = Console()
217
+ if restart_zuban_lsp(console):
218
+ console.print(
219
+ "\n[bold green]โœ… Zuban LSP server restart completed[/bold green]"
220
+ )
221
+ else:
222
+ console.print("\n[bold red]โŒ Zuban LSP server restart failed[/bold red]")
223
+ raise SystemExit(1)
224
+
225
+
148
226
  def handle_interactive_mode(options: Options) -> None:
149
227
  from crackerjack.cli.utils import get_package_version
150
228
 
@@ -164,7 +242,6 @@ def handle_standard_mode(
164
242
 
165
243
  console = Console()
166
244
 
167
- # Configure global lock manager from CLI options
168
245
  from crackerjack.executors.hook_lock_manager import hook_lock_manager
169
246
 
170
247
  hook_lock_manager.configure_from_options(options)
@@ -180,7 +257,7 @@ def handle_standard_mode(
180
257
  pkg_path = Path.cwd()
181
258
 
182
259
  if async_mode:
183
- orchestrator = AsyncWorkflowOrchestrator(
260
+ async_orchestrator = AsyncWorkflowOrchestrator(
184
261
  console=console,
185
262
  pkg_path=pkg_path,
186
263
  dry_run=getattr(options, "dry_run", False),
@@ -188,9 +265,11 @@ def handle_standard_mode(
188
265
  verbose=options.verbose,
189
266
  debug=getattr(options, "debug", False),
190
267
  )
191
- success = asyncio.run(orchestrator.run_complete_workflow_async(options))
268
+ success = asyncio.run(
269
+ async_orchestrator.run_complete_workflow_async(options)
270
+ )
192
271
  else:
193
- orchestrator = WorkflowOrchestrator(
272
+ sync_orchestrator = WorkflowOrchestrator(
194
273
  console=console,
195
274
  pkg_path=pkg_path,
196
275
  dry_run=getattr(options, "dry_run", False),
@@ -198,7 +277,7 @@ def handle_standard_mode(
198
277
  verbose=options.verbose,
199
278
  debug=getattr(options, "debug", False),
200
279
  )
201
- success = asyncio.run(orchestrator.run_complete_workflow(options))
280
+ success = sync_orchestrator.run_complete_workflow_sync(options)
202
281
 
203
282
  if not success:
204
283
  raise SystemExit(1)
@@ -210,7 +289,6 @@ def handle_orchestrated_mode(options: Options, job_id: str | None = None) -> Non
210
289
  console = Console()
211
290
  console.print("[bold bright_blue]๐Ÿš€ ORCHESTRATED MODE ENABLED[/ bold bright_blue]")
212
291
 
213
- # Configure global lock manager from CLI options
214
292
  from crackerjack.executors.hook_lock_manager import hook_lock_manager
215
293
 
216
294
  hook_lock_manager.configure_from_options(options)
@@ -283,3 +361,140 @@ def handle_orchestrated_mode(options: Options, job_id: str | None = None) -> Non
283
361
  except Exception as e:
284
362
  console.print(f"\n[red]๐Ÿ’ฅ Orchestrated workflow error: {e}[/ red]")
285
363
  sys.exit(1)
364
+
365
+
366
+ def handle_config_updates(options: Options) -> None:
367
+ """Handle configuration update commands."""
368
+ from crackerjack.services.config_template import ConfigTemplateService
369
+
370
+ console = Console()
371
+ pkg_path = Path.cwd()
372
+ config_service = ConfigTemplateService(console, pkg_path)
373
+
374
+ if options.check_config_updates:
375
+ _handle_check_updates(config_service, pkg_path, console)
376
+ elif options.apply_config_updates:
377
+ _handle_apply_updates(
378
+ config_service, pkg_path, options.config_interactive, console
379
+ )
380
+ elif options.diff_config:
381
+ _handle_diff_config(config_service, pkg_path, options.diff_config, console)
382
+ elif options.refresh_cache:
383
+ _handle_refresh_cache(config_service, pkg_path, console)
384
+
385
+
386
+ def _handle_check_updates(
387
+ config_service: "ConfigTemplateService", pkg_path: Path, console: Console
388
+ ) -> None:
389
+ """Handle checking for configuration updates."""
390
+ console.print("[bold cyan]๐Ÿ” Checking for configuration updates...[/bold cyan]")
391
+ updates = config_service.check_updates(pkg_path)
392
+
393
+ if not updates:
394
+ console.print("[green]โœ… No configuration templates available[/green]")
395
+ return
396
+
397
+ has_updates = any(update.needs_update for update in updates.values())
398
+ if not has_updates:
399
+ console.print("[green]โœ… All configurations are up to date[/green]")
400
+ return
401
+
402
+ _display_available_updates(updates, console)
403
+ console.print("\nUse --apply-config-updates to apply these updates")
404
+
405
+
406
+ def _handle_apply_updates(
407
+ config_service: "ConfigTemplateService",
408
+ pkg_path: Path,
409
+ interactive: bool,
410
+ console: Console,
411
+ ) -> None:
412
+ """Handle applying configuration updates."""
413
+ console.print("[bold cyan]๐Ÿ”ง Applying configuration updates...[/bold cyan]")
414
+ updates = config_service.check_updates(pkg_path)
415
+
416
+ if not updates:
417
+ console.print("[yellow]โš ๏ธ No configuration templates available[/yellow]")
418
+ return
419
+
420
+ configs_to_update = _get_configs_needing_update(updates)
421
+ if not configs_to_update:
422
+ console.print("[green]โœ… All configurations are already up to date[/green]")
423
+ return
424
+
425
+ success_count = _apply_config_updates_batch(
426
+ config_service, configs_to_update, pkg_path, interactive, console
427
+ )
428
+ _report_update_results(success_count, len(configs_to_update), console)
429
+
430
+
431
+ def _handle_diff_config(
432
+ config_service: "ConfigTemplateService",
433
+ pkg_path: Path,
434
+ config_type: str,
435
+ console: Console,
436
+ ) -> None:
437
+ """Handle showing configuration diff."""
438
+ console.print(f"[bold cyan]๐Ÿ“Š Showing diff for {config_type}...[/bold cyan]")
439
+ diff_preview = config_service._generate_diff_preview(config_type, pkg_path)
440
+ console.print(f"\nChanges for {config_type}:")
441
+ console.print(diff_preview)
442
+
443
+
444
+ def _handle_refresh_cache(
445
+ config_service: "ConfigTemplateService", pkg_path: Path, console: Console
446
+ ) -> None:
447
+ """Handle refreshing pre-commit cache."""
448
+ console.print("[bold cyan]๐Ÿงน Refreshing pre-commit cache...[/bold cyan]")
449
+ config_service._invalidate_precommit_cache(pkg_path)
450
+ console.print("[green]โœ… Pre-commit cache refreshed[/green]")
451
+
452
+
453
+ def _display_available_updates(
454
+ updates: dict[str, "ConfigUpdateInfo"], console: Console
455
+ ) -> None:
456
+ """Display available configuration updates."""
457
+ console.print("[yellow]๐Ÿ“‹ Available updates:[/yellow]")
458
+ for config_type, update_info in updates.items():
459
+ if update_info.needs_update:
460
+ console.print(
461
+ f" โ€ข {config_type}: {update_info.current_version} โ†’ {update_info.latest_version}"
462
+ )
463
+
464
+
465
+ def _get_configs_needing_update(updates: dict[str, "ConfigUpdateInfo"]) -> list[str]:
466
+ """Get list of configurations that need updates."""
467
+ return [
468
+ config_type
469
+ for config_type, update_info in updates.items()
470
+ if update_info.needs_update
471
+ ]
472
+
473
+
474
+ def _apply_config_updates_batch(
475
+ config_service: "ConfigTemplateService",
476
+ configs: list[str],
477
+ pkg_path: Path,
478
+ interactive: bool,
479
+ console: Console,
480
+ ) -> int:
481
+ """Apply configuration updates in batch and return success count."""
482
+ success_count = 0
483
+ for config_type in configs:
484
+ if config_service.apply_update(config_type, pkg_path, interactive=interactive):
485
+ success_count += 1
486
+ return success_count
487
+
488
+
489
+ def _report_update_results(
490
+ success_count: int, total_count: int, console: Console
491
+ ) -> None:
492
+ """Report the results of configuration updates."""
493
+ if success_count == total_count:
494
+ console.print(
495
+ f"[green]โœ… Successfully updated {success_count} configurations[/green]"
496
+ )
497
+ else:
498
+ console.print(
499
+ f"[yellow]โš ๏ธ Updated {success_count}/{total_count} configurations[/yellow]"
500
+ )
@@ -1,4 +1,5 @@
1
1
  import time
2
+ import typing as t
2
3
  from enum import Enum, auto
3
4
 
4
5
  from rich.box import ROUNDED
@@ -146,7 +147,7 @@ class InteractiveWorkflowManager:
146
147
 
147
148
  def _setup_commit_task(self, options: OptionsProtocol) -> None:
148
149
  if options.commit:
149
- all_deps = list(self.tasks.keys())
150
+ all_deps = list[t.Any](self.tasks.keys())
150
151
  self.add_task(
151
152
  "commit",
152
153
  "Commit changes and push to Git",
@@ -193,9 +194,10 @@ class InteractiveWorkflowManager:
193
194
  task.start()
194
195
  try:
195
196
  phase_method = getattr(self.orchestrator, task.phase_method)
196
- success = phase_method(options)
197
- task.complete(success)
198
- return success
197
+ success_result = phase_method(options)
198
+ success_bool = bool(success_result)
199
+ task.complete(success_bool)
200
+ return success_bool
199
201
  except Exception as e:
200
202
  error = CrackerjackError(
201
203
  message=str(e),