crackerjack 0.33.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.
- crackerjack/__main__.py +1350 -34
- crackerjack/adapters/__init__.py +17 -0
- crackerjack/adapters/lsp_client.py +358 -0
- crackerjack/adapters/rust_tool_adapter.py +194 -0
- crackerjack/adapters/rust_tool_manager.py +193 -0
- crackerjack/adapters/skylos_adapter.py +231 -0
- crackerjack/adapters/zuban_adapter.py +560 -0
- crackerjack/agents/base.py +7 -3
- crackerjack/agents/coordinator.py +271 -33
- crackerjack/agents/documentation_agent.py +9 -15
- crackerjack/agents/dry_agent.py +3 -15
- crackerjack/agents/formatting_agent.py +1 -1
- crackerjack/agents/import_optimization_agent.py +36 -180
- crackerjack/agents/performance_agent.py +17 -98
- crackerjack/agents/performance_helpers.py +7 -31
- crackerjack/agents/proactive_agent.py +1 -3
- crackerjack/agents/refactoring_agent.py +16 -85
- crackerjack/agents/refactoring_helpers.py +7 -42
- crackerjack/agents/security_agent.py +9 -48
- crackerjack/agents/test_creation_agent.py +356 -513
- crackerjack/agents/test_specialist_agent.py +0 -4
- crackerjack/api.py +6 -25
- crackerjack/cli/cache_handlers.py +204 -0
- crackerjack/cli/cache_handlers_enhanced.py +683 -0
- crackerjack/cli/facade.py +100 -0
- crackerjack/cli/handlers.py +224 -9
- crackerjack/cli/interactive.py +6 -4
- crackerjack/cli/options.py +642 -55
- crackerjack/cli/utils.py +2 -1
- crackerjack/code_cleaner.py +58 -117
- crackerjack/config/global_lock_config.py +8 -48
- crackerjack/config/hooks.py +53 -62
- crackerjack/core/async_workflow_orchestrator.py +24 -34
- crackerjack/core/autofix_coordinator.py +3 -17
- crackerjack/core/enhanced_container.py +4 -13
- crackerjack/core/file_lifecycle.py +12 -89
- crackerjack/core/performance.py +2 -2
- crackerjack/core/performance_monitor.py +15 -55
- crackerjack/core/phase_coordinator.py +104 -204
- crackerjack/core/resource_manager.py +14 -90
- crackerjack/core/service_watchdog.py +62 -95
- crackerjack/core/session_coordinator.py +149 -0
- crackerjack/core/timeout_manager.py +14 -72
- crackerjack/core/websocket_lifecycle.py +13 -78
- crackerjack/core/workflow_orchestrator.py +171 -174
- crackerjack/docs/INDEX.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +765 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +977 -0
- crackerjack/dynamic_config.py +55 -50
- crackerjack/executors/async_hook_executor.py +10 -15
- crackerjack/executors/cached_hook_executor.py +117 -43
- crackerjack/executors/hook_executor.py +8 -34
- crackerjack/executors/hook_lock_manager.py +26 -183
- crackerjack/executors/individual_hook_executor.py +13 -11
- crackerjack/executors/lsp_aware_hook_executor.py +270 -0
- crackerjack/executors/tool_proxy.py +417 -0
- crackerjack/hooks/lsp_hook.py +79 -0
- crackerjack/intelligence/adaptive_learning.py +25 -10
- crackerjack/intelligence/agent_orchestrator.py +2 -5
- crackerjack/intelligence/agent_registry.py +34 -24
- crackerjack/intelligence/agent_selector.py +5 -7
- crackerjack/interactive.py +17 -6
- crackerjack/managers/async_hook_manager.py +0 -1
- crackerjack/managers/hook_manager.py +79 -1
- crackerjack/managers/publish_manager.py +44 -8
- crackerjack/managers/test_command_builder.py +1 -15
- crackerjack/managers/test_executor.py +1 -3
- crackerjack/managers/test_manager.py +98 -7
- crackerjack/managers/test_manager_backup.py +10 -9
- crackerjack/mcp/cache.py +2 -2
- crackerjack/mcp/client_runner.py +1 -1
- crackerjack/mcp/context.py +191 -68
- crackerjack/mcp/dashboard.py +7 -5
- crackerjack/mcp/enhanced_progress_monitor.py +31 -28
- crackerjack/mcp/file_monitor.py +30 -23
- crackerjack/mcp/progress_components.py +31 -21
- crackerjack/mcp/progress_monitor.py +50 -53
- crackerjack/mcp/rate_limiter.py +6 -6
- crackerjack/mcp/server_core.py +17 -16
- crackerjack/mcp/service_watchdog.py +2 -1
- crackerjack/mcp/state.py +4 -7
- crackerjack/mcp/task_manager.py +11 -9
- crackerjack/mcp/tools/core_tools.py +173 -32
- crackerjack/mcp/tools/error_analyzer.py +3 -2
- crackerjack/mcp/tools/execution_tools.py +8 -10
- crackerjack/mcp/tools/execution_tools_backup.py +42 -30
- crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
- crackerjack/mcp/tools/intelligence_tools.py +5 -2
- crackerjack/mcp/tools/monitoring_tools.py +33 -70
- crackerjack/mcp/tools/proactive_tools.py +24 -11
- crackerjack/mcp/tools/progress_tools.py +5 -8
- crackerjack/mcp/tools/utility_tools.py +20 -14
- crackerjack/mcp/tools/workflow_executor.py +62 -40
- crackerjack/mcp/websocket/app.py +8 -0
- crackerjack/mcp/websocket/endpoints.py +352 -357
- crackerjack/mcp/websocket/jobs.py +40 -57
- crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
- crackerjack/mcp/websocket/server.py +7 -25
- crackerjack/mcp/websocket/websocket_handler.py +6 -17
- crackerjack/mixins/__init__.py +0 -2
- crackerjack/mixins/error_handling.py +1 -70
- crackerjack/models/config.py +12 -1
- crackerjack/models/config_adapter.py +49 -1
- crackerjack/models/protocols.py +122 -122
- crackerjack/models/resource_protocols.py +55 -210
- crackerjack/monitoring/ai_agent_watchdog.py +13 -13
- crackerjack/monitoring/metrics_collector.py +426 -0
- crackerjack/monitoring/regression_prevention.py +8 -8
- crackerjack/monitoring/websocket_server.py +643 -0
- crackerjack/orchestration/advanced_orchestrator.py +11 -6
- crackerjack/orchestration/coverage_improvement.py +3 -3
- crackerjack/orchestration/execution_strategies.py +26 -6
- crackerjack/orchestration/test_progress_streamer.py +8 -5
- crackerjack/plugins/base.py +2 -2
- crackerjack/plugins/hooks.py +7 -0
- crackerjack/plugins/managers.py +11 -8
- crackerjack/security/__init__.py +0 -1
- crackerjack/security/audit.py +6 -35
- crackerjack/services/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +615 -0
- crackerjack/services/backup_service.py +2 -2
- crackerjack/services/bounded_status_operations.py +15 -152
- crackerjack/services/cache.py +127 -1
- crackerjack/services/changelog_automation.py +395 -0
- crackerjack/services/config.py +15 -9
- crackerjack/services/config_merge.py +19 -80
- crackerjack/services/config_template.py +506 -0
- crackerjack/services/contextual_ai_assistant.py +48 -22
- crackerjack/services/coverage_badge_service.py +171 -0
- crackerjack/services/coverage_ratchet.py +27 -25
- crackerjack/services/debug.py +3 -3
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +14 -11
- crackerjack/services/documentation_generator.py +491 -0
- crackerjack/services/documentation_service.py +675 -0
- crackerjack/services/enhanced_filesystem.py +6 -5
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_hasher.py +1 -1
- crackerjack/services/git.py +8 -25
- crackerjack/services/health_metrics.py +10 -8
- crackerjack/services/heatmap_generator.py +735 -0
- crackerjack/services/initialization.py +11 -30
- crackerjack/services/input_validator.py +5 -97
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +15 -12
- crackerjack/services/logging.py +4 -3
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +19 -87
- crackerjack/services/metrics.py +42 -33
- crackerjack/services/parallel_executor.py +9 -67
- crackerjack/services/pattern_cache.py +1 -1
- crackerjack/services/pattern_detector.py +6 -6
- crackerjack/services/performance_benchmarks.py +18 -59
- crackerjack/services/performance_cache.py +20 -81
- crackerjack/services/performance_monitor.py +27 -95
- crackerjack/services/predictive_analytics.py +510 -0
- crackerjack/services/quality_baseline.py +234 -0
- crackerjack/services/quality_baseline_enhanced.py +646 -0
- crackerjack/services/quality_intelligence.py +785 -0
- crackerjack/services/regex_patterns.py +605 -524
- crackerjack/services/regex_utils.py +43 -123
- crackerjack/services/secure_path_utils.py +5 -164
- crackerjack/services/secure_status_formatter.py +30 -141
- crackerjack/services/secure_subprocess.py +11 -92
- crackerjack/services/security.py +9 -41
- crackerjack/services/security_logger.py +12 -24
- crackerjack/services/server_manager.py +124 -16
- crackerjack/services/status_authentication.py +16 -159
- crackerjack/services/status_security_manager.py +4 -131
- crackerjack/services/thread_safe_status_collector.py +19 -125
- crackerjack/services/unified_config.py +21 -13
- crackerjack/services/validation_rate_limiter.py +5 -54
- crackerjack/services/version_analyzer.py +459 -0
- crackerjack/services/version_checker.py +1 -1
- crackerjack/services/websocket_resource_limiter.py +10 -144
- crackerjack/services/zuban_lsp_service.py +390 -0
- crackerjack/slash_commands/__init__.py +2 -7
- crackerjack/slash_commands/run.md +2 -2
- crackerjack/tools/validate_input_validator_patterns.py +14 -40
- crackerjack/tools/validate_regex_patterns.py +19 -48
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +196 -25
- crackerjack-0.33.1.dist-info/RECORD +229 -0
- crackerjack/CLAUDE.md +0 -207
- crackerjack/RULES.md +0 -380
- crackerjack/py313.py +0 -234
- crackerjack-0.33.0.dist-info/RECORD +0 -187
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -64,29 +64,24 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
64
64
|
security_logger=None,
|
|
65
65
|
backup_service=None,
|
|
66
66
|
)
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
from crackerjack.services.config import ConfigurationService
|
|
69
69
|
|
|
70
70
|
self.config_service = ConfigurationService(console=console, pkg_path=pkg_path)
|
|
71
|
-
# Lazy-loaded autofix coordinator (now using lazy service)
|
|
72
|
-
# self.autofix_coordinator will be accessed via property
|
|
73
71
|
|
|
74
72
|
self.logger = logging.getLogger("crackerjack.phases")
|
|
75
73
|
|
|
76
|
-
# Performance optimization services
|
|
77
74
|
self._memory_optimizer = get_memory_optimizer()
|
|
78
75
|
self._parallel_executor = get_parallel_executor()
|
|
79
76
|
self._async_executor = get_async_executor()
|
|
80
77
|
self._git_cache = get_git_cache()
|
|
81
78
|
self._filesystem_cache = get_filesystem_cache()
|
|
82
79
|
|
|
83
|
-
# Lazy-loaded heavy services
|
|
84
80
|
self._lazy_autofix = create_lazy_service(
|
|
85
81
|
lambda: AutofixCoordinator(console=console, pkg_path=pkg_path),
|
|
86
82
|
"autofix_coordinator",
|
|
87
83
|
)
|
|
88
84
|
|
|
89
|
-
# Initialize ErrorHandlingMixin
|
|
90
85
|
super().__init__()
|
|
91
86
|
|
|
92
87
|
def run_cleaning_phase(self, options: OptionsProtocol) -> bool:
|
|
@@ -110,17 +105,42 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
110
105
|
self.console.print("-" * 40 + "\n")
|
|
111
106
|
self.console.print("[yellow]🧹[/yellow] Starting code cleaning...")
|
|
112
107
|
|
|
108
|
+
def _display_version_bump_header(self, version_type: str) -> None:
|
|
109
|
+
self.console.print("\n" + "-" * 74)
|
|
110
|
+
self.console.print(
|
|
111
|
+
f"[bold bright_magenta]📦 BUMP VERSION[/bold bright_magenta] [bold bright_white]Updating package version ({version_type})[/bold bright_white]",
|
|
112
|
+
)
|
|
113
|
+
self.console.print("-" * 74 + "\n")
|
|
114
|
+
|
|
115
|
+
def _display_publish_header(self) -> None:
|
|
116
|
+
self.console.print("\n" + "-" * 74)
|
|
117
|
+
self.console.print(
|
|
118
|
+
"[bold bright_yellow]🚀 PUBLISH[/bold bright_yellow] [bold bright_white]Publishing to PyPI[/bold bright_white]",
|
|
119
|
+
)
|
|
120
|
+
self.console.print("-" * 74 + "\n")
|
|
121
|
+
|
|
122
|
+
def _display_git_staging_header(self) -> None:
|
|
123
|
+
self.console.print("\n" + "-" * 74)
|
|
124
|
+
self.console.print(
|
|
125
|
+
"[bold bright_cyan]🏷️ GIT OPERATIONS[/bold bright_cyan] [bold bright_white]Staging files and creating tags[/bold bright_white]",
|
|
126
|
+
)
|
|
127
|
+
self.console.print("-" * 74 + "\n")
|
|
128
|
+
|
|
129
|
+
def _display_commit_push_header(self) -> None:
|
|
130
|
+
self.console.print("\n" + "-" * 74)
|
|
131
|
+
self.console.print(
|
|
132
|
+
"[bold bright_green]📤 COMMIT & PUSH[/bold bright_green] [bold bright_white]Committing and pushing changes[/bold bright_white]",
|
|
133
|
+
)
|
|
134
|
+
self.console.print("-" * 74 + "\n")
|
|
135
|
+
|
|
113
136
|
def _execute_cleaning_process(self) -> bool:
|
|
114
|
-
# Use the comprehensive backup cleaning system for safety
|
|
115
137
|
cleaning_result = self.code_cleaner.clean_files(self.pkg_path, use_backup=True)
|
|
116
138
|
|
|
117
139
|
if isinstance(cleaning_result, list):
|
|
118
|
-
# Legacy mode (should not happen with use_backup=True, but handle gracefully)
|
|
119
140
|
cleaned_files = [str(r.file_path) for r in cleaning_result if r.success]
|
|
120
141
|
self._report_cleaning_results(cleaned_files)
|
|
121
142
|
return all(r.success for r in cleaning_result) if cleaning_result else True
|
|
122
143
|
else:
|
|
123
|
-
# PackageCleaningResult from backup mode
|
|
124
144
|
self._report_package_cleaning_results(cleaning_result)
|
|
125
145
|
return cleaning_result.overall_success
|
|
126
146
|
|
|
@@ -141,7 +161,6 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
141
161
|
self.session.complete_task("cleaning", "No cleaning needed")
|
|
142
162
|
|
|
143
163
|
def _report_package_cleaning_results(self, result: PackageCleaningResult) -> None:
|
|
144
|
-
"""Report package cleaning results with backup information."""
|
|
145
164
|
if result.overall_success:
|
|
146
165
|
self.console.print(
|
|
147
166
|
f"[green]✅[/ green] Package cleaning completed successfully! "
|
|
@@ -188,31 +207,13 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
188
207
|
return False
|
|
189
208
|
|
|
190
209
|
def _execute_configuration_steps(self, options: OptionsProtocol) -> bool:
|
|
191
|
-
"""Execute all configuration steps and return overall success."""
|
|
192
210
|
success = True
|
|
193
211
|
|
|
194
|
-
# FIRST STEP: Smart config merge before all other operations
|
|
195
|
-
self._handle_smart_config_merge(options)
|
|
196
|
-
|
|
197
|
-
# Handle crackerjack project specific configuration
|
|
198
|
-
if self._is_crackerjack_project() and not self._copy_config_files_to_package():
|
|
199
|
-
success = False
|
|
200
|
-
|
|
201
|
-
# Update configuration files
|
|
202
212
|
success &= self._update_configuration_files(options)
|
|
203
213
|
|
|
204
214
|
return success
|
|
205
215
|
|
|
206
|
-
def _handle_smart_config_merge(self, options: OptionsProtocol) -> None:
|
|
207
|
-
"""Handle smart config merge with warning on failure."""
|
|
208
|
-
if not self._perform_smart_config_merge(options):
|
|
209
|
-
self.console.print(
|
|
210
|
-
"[yellow]⚠️[/yellow] Smart config merge encountered issues (continuing)"
|
|
211
|
-
)
|
|
212
|
-
# Don't fail the entire configuration phase, just log the warning
|
|
213
|
-
|
|
214
216
|
def _update_configuration_files(self, options: OptionsProtocol) -> bool:
|
|
215
|
-
"""Update precommit and pyproject configuration files."""
|
|
216
217
|
success = True
|
|
217
218
|
if not self.config_service.update_precommit_config(options):
|
|
218
219
|
success = False
|
|
@@ -221,7 +222,6 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
221
222
|
return success
|
|
222
223
|
|
|
223
224
|
def _complete_configuration_task(self, success: bool) -> None:
|
|
224
|
-
"""Complete the configuration task with appropriate message."""
|
|
225
225
|
message = (
|
|
226
226
|
"Configuration updated successfully"
|
|
227
227
|
if success
|
|
@@ -229,95 +229,6 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
229
229
|
)
|
|
230
230
|
self.session.complete_task("configuration", message)
|
|
231
231
|
|
|
232
|
-
def _perform_smart_config_merge(self, options: OptionsProtocol) -> bool:
|
|
233
|
-
"""Perform smart config merge before git operations."""
|
|
234
|
-
try:
|
|
235
|
-
self.logger.debug("Starting smart config merge process")
|
|
236
|
-
|
|
237
|
-
# Smart merge for critical configuration files
|
|
238
|
-
merged_files = []
|
|
239
|
-
|
|
240
|
-
# Skip smart merge if explicitly requested or in specific modes
|
|
241
|
-
if hasattr(options, "skip_config_merge") and options.skip_config_merge:
|
|
242
|
-
self.logger.debug("Config merge skipped by option")
|
|
243
|
-
return True
|
|
244
|
-
|
|
245
|
-
# Merge .gitignore patterns (always safe to do)
|
|
246
|
-
if self._smart_merge_gitignore():
|
|
247
|
-
merged_files.append(".gitignore")
|
|
248
|
-
|
|
249
|
-
# Merge configuration files (pyproject.toml, .pre-commit-config.yaml)
|
|
250
|
-
# Only for crackerjack projects to avoid breaking user projects
|
|
251
|
-
if self._is_crackerjack_project():
|
|
252
|
-
if self._smart_merge_project_configs():
|
|
253
|
-
merged_files.extend(["pyproject.toml", ".pre-commit-config.yaml"])
|
|
254
|
-
|
|
255
|
-
if merged_files:
|
|
256
|
-
files_str = ", ".join(merged_files)
|
|
257
|
-
self.console.print(
|
|
258
|
-
f"[green]🔧[/green] Smart-merged configurations: {files_str}"
|
|
259
|
-
)
|
|
260
|
-
self.logger.info(f"Smart config merge completed: {merged_files}")
|
|
261
|
-
else:
|
|
262
|
-
self.logger.debug("No configuration files needed smart merging")
|
|
263
|
-
|
|
264
|
-
return True
|
|
265
|
-
|
|
266
|
-
except Exception as e:
|
|
267
|
-
self.console.print(f"[yellow]⚠️[/yellow] Smart config merge failed: {e}")
|
|
268
|
-
self.logger.warning(
|
|
269
|
-
f"Smart config merge failed: {e} (type: {type(e).__name__})"
|
|
270
|
-
)
|
|
271
|
-
# Return True to not block the workflow - this is fail-safe
|
|
272
|
-
return True
|
|
273
|
-
|
|
274
|
-
def _smart_merge_gitignore(self) -> bool:
|
|
275
|
-
"""Smart merge .gitignore patterns."""
|
|
276
|
-
try:
|
|
277
|
-
gitignore_path = self.pkg_path / ".gitignore"
|
|
278
|
-
if not gitignore_path.exists():
|
|
279
|
-
return False
|
|
280
|
-
|
|
281
|
-
# Standard crackerjack ignore patterns to merge
|
|
282
|
-
standard_patterns = [
|
|
283
|
-
"# Crackerjack generated files",
|
|
284
|
-
".crackerjack/",
|
|
285
|
-
"*.crackerjack.bak",
|
|
286
|
-
".coverage.*",
|
|
287
|
-
"crackerjack-debug-*.log",
|
|
288
|
-
"__pycache__/",
|
|
289
|
-
"*.py[cod]",
|
|
290
|
-
"*$py.class",
|
|
291
|
-
".pytest_cache/",
|
|
292
|
-
".tox/",
|
|
293
|
-
".mypy_cache/",
|
|
294
|
-
".ruff_cache/",
|
|
295
|
-
]
|
|
296
|
-
|
|
297
|
-
self.config_merge_service.smart_merge_gitignore(
|
|
298
|
-
patterns=standard_patterns, target_path=str(gitignore_path)
|
|
299
|
-
)
|
|
300
|
-
|
|
301
|
-
return True
|
|
302
|
-
|
|
303
|
-
except Exception as e:
|
|
304
|
-
self.logger.warning(f"Failed to smart merge .gitignore: {e}")
|
|
305
|
-
return False
|
|
306
|
-
|
|
307
|
-
def _smart_merge_project_configs(self) -> bool:
|
|
308
|
-
"""Smart merge pyproject.toml and pre-commit config for crackerjack projects."""
|
|
309
|
-
try:
|
|
310
|
-
# This would be where we implement project config merging
|
|
311
|
-
# For now, just return True as the existing config service handles this
|
|
312
|
-
self.logger.debug(
|
|
313
|
-
"Project config smart merge placeholder - handled by existing config service"
|
|
314
|
-
)
|
|
315
|
-
return True
|
|
316
|
-
|
|
317
|
-
except Exception as e:
|
|
318
|
-
self.logger.warning(f"Failed to smart merge project configs: {e}")
|
|
319
|
-
return False
|
|
320
|
-
|
|
321
232
|
def _is_crackerjack_project(self) -> bool:
|
|
322
233
|
pyproject_path = self.pkg_path / "pyproject.toml"
|
|
323
234
|
if not pyproject_path.exists():
|
|
@@ -329,58 +240,11 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
329
240
|
with pyproject_path.open("rb") as f:
|
|
330
241
|
data = tomllib.load(f)
|
|
331
242
|
|
|
332
|
-
project_name = data.get("project", {}).get("name", "")
|
|
243
|
+
project_name: str = data.get("project", {}).get("name", "")
|
|
333
244
|
return project_name == "crackerjack"
|
|
334
245
|
except Exception:
|
|
335
246
|
return False
|
|
336
247
|
|
|
337
|
-
def _copy_config_files_to_package(self) -> bool:
|
|
338
|
-
try:
|
|
339
|
-
files_to_copy = [
|
|
340
|
-
"pyproject.toml",
|
|
341
|
-
".pre-commit-config.yaml",
|
|
342
|
-
"CLAUDE.md",
|
|
343
|
-
"RULES.md",
|
|
344
|
-
".gitignore",
|
|
345
|
-
"example.mcp.json",
|
|
346
|
-
"uv.lock",
|
|
347
|
-
]
|
|
348
|
-
|
|
349
|
-
package_dir = self.pkg_path / "crackerjack"
|
|
350
|
-
if not package_dir.exists():
|
|
351
|
-
self.console.print(
|
|
352
|
-
"[yellow]⚠️[/ yellow] Package directory not found: crackerjack /",
|
|
353
|
-
)
|
|
354
|
-
return False
|
|
355
|
-
|
|
356
|
-
copied_count = 0
|
|
357
|
-
for filename in files_to_copy:
|
|
358
|
-
src_path = self.pkg_path / filename
|
|
359
|
-
if src_path.exists():
|
|
360
|
-
dst_path = package_dir / filename
|
|
361
|
-
try:
|
|
362
|
-
import shutil
|
|
363
|
-
|
|
364
|
-
shutil.copy2(src_path, dst_path)
|
|
365
|
-
copied_count += 1
|
|
366
|
-
self.logger.debug(f"Copied {filename} to package directory")
|
|
367
|
-
except Exception as e:
|
|
368
|
-
self.console.print(
|
|
369
|
-
f"[yellow]⚠️[/ yellow] Failed to copy {filename}: {e}",
|
|
370
|
-
)
|
|
371
|
-
|
|
372
|
-
if copied_count > 0:
|
|
373
|
-
self.console.print(
|
|
374
|
-
f"[green]✅[/ green] Copied {copied_count} config files to package directory",
|
|
375
|
-
)
|
|
376
|
-
|
|
377
|
-
return True
|
|
378
|
-
except Exception as e:
|
|
379
|
-
self.console.print(
|
|
380
|
-
f"[red]❌[/ red] Failed to copy config files to package: {e}",
|
|
381
|
-
)
|
|
382
|
-
return False
|
|
383
|
-
|
|
384
248
|
def run_hooks_phase(self, options: OptionsProtocol) -> bool:
|
|
385
249
|
if options.skip_hooks:
|
|
386
250
|
return True
|
|
@@ -398,7 +262,6 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
398
262
|
if options.skip_hooks:
|
|
399
263
|
return True
|
|
400
264
|
|
|
401
|
-
# Use standard execution for now - parallel support can be added later
|
|
402
265
|
hook_results = self.hook_manager.run_fast_hooks()
|
|
403
266
|
return all(r.status == "passed" for r in hook_results)
|
|
404
267
|
|
|
@@ -406,7 +269,6 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
406
269
|
if options.skip_hooks:
|
|
407
270
|
return True
|
|
408
271
|
|
|
409
|
-
# Use standard execution for now - parallel support can be added later
|
|
410
272
|
hook_results = self.hook_manager.run_comprehensive_hooks()
|
|
411
273
|
return all(r.status == "passed" for r in hook_results)
|
|
412
274
|
|
|
@@ -415,11 +277,11 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
415
277
|
return True
|
|
416
278
|
self.session.track_task("testing", "Test execution")
|
|
417
279
|
try:
|
|
418
|
-
self.console.print("\n" + "-" *
|
|
280
|
+
self.console.print("\n" + "-" * 74)
|
|
419
281
|
self.console.print(
|
|
420
282
|
"[bold bright_blue]🧪 TESTS[/ bold bright_blue] [bold bright_white]Running test suite[/ bold bright_white]",
|
|
421
283
|
)
|
|
422
|
-
self.console.print("-" *
|
|
284
|
+
self.console.print("-" * 74 + "\n")
|
|
423
285
|
if not self.test_manager.validate_test_environment():
|
|
424
286
|
self.session.fail_task("testing", "Test environment validation failed")
|
|
425
287
|
return False
|
|
@@ -454,9 +316,15 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
454
316
|
|
|
455
317
|
def _determine_version_type(self, options: OptionsProtocol) -> str | None:
|
|
456
318
|
if options.publish:
|
|
457
|
-
|
|
319
|
+
publish_value: str | None = (
|
|
320
|
+
options.publish if isinstance(options.publish, str) else None
|
|
321
|
+
)
|
|
322
|
+
return publish_value
|
|
458
323
|
if options.all:
|
|
459
|
-
|
|
324
|
+
all_value: str | None = (
|
|
325
|
+
options.all if isinstance(options.all, str) else None
|
|
326
|
+
)
|
|
327
|
+
return all_value
|
|
460
328
|
if options.bump:
|
|
461
329
|
self._handle_version_bump_only(options.bump)
|
|
462
330
|
return None
|
|
@@ -467,9 +335,12 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
467
335
|
options: OptionsProtocol,
|
|
468
336
|
version_type: str,
|
|
469
337
|
) -> bool:
|
|
338
|
+
# Display version bump header
|
|
339
|
+
self._display_version_bump_header(version_type)
|
|
470
340
|
new_version = self.publish_manager.bump_version(version_type)
|
|
471
341
|
|
|
472
|
-
#
|
|
342
|
+
# Display git operations header for staging and tagging
|
|
343
|
+
self._display_git_staging_header()
|
|
473
344
|
self.console.print("[blue]📂[/ blue] Staging all changes for publishing...")
|
|
474
345
|
if not self.git_service.add_all_files():
|
|
475
346
|
self.console.print(
|
|
@@ -479,6 +350,8 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
479
350
|
if not options.no_git_tags:
|
|
480
351
|
self.publish_manager.create_git_tag(new_version)
|
|
481
352
|
|
|
353
|
+
# Display publish header
|
|
354
|
+
self._display_publish_header()
|
|
482
355
|
if self.publish_manager.publish_package():
|
|
483
356
|
self._handle_successful_publish(options, new_version)
|
|
484
357
|
return True
|
|
@@ -500,6 +373,9 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
500
373
|
def run_commit_phase(self, options: OptionsProtocol) -> bool:
|
|
501
374
|
if not options.commit:
|
|
502
375
|
return True
|
|
376
|
+
|
|
377
|
+
# Display commit & push header
|
|
378
|
+
self._display_commit_push_header()
|
|
503
379
|
self.session.track_task("commit", "Git commit and push")
|
|
504
380
|
try:
|
|
505
381
|
changed_files = self.git_service.get_changed_files()
|
|
@@ -515,7 +391,6 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
515
391
|
def _handle_no_changes_to_commit(self) -> bool:
|
|
516
392
|
self.console.print("[yellow]ℹ️[/ yellow] No changes to commit")
|
|
517
393
|
|
|
518
|
-
# Check if there are unpushed commits
|
|
519
394
|
from contextlib import suppress
|
|
520
395
|
|
|
521
396
|
with suppress(ValueError, Exception):
|
|
@@ -583,6 +458,8 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
583
458
|
def _handle_version_bump_only(self, bump_type: str) -> bool:
|
|
584
459
|
self.session.track_task("version_bump", f"Version bump ({bump_type})")
|
|
585
460
|
try:
|
|
461
|
+
# Display version bump header
|
|
462
|
+
self._display_version_bump_header(bump_type)
|
|
586
463
|
new_version = self.publish_manager.bump_version(bump_type)
|
|
587
464
|
self.console.print(f"[green]🎯[/ green] Version bumped to {new_version}")
|
|
588
465
|
self.session.complete_task("version_bump", f"Bumped to {new_version}")
|
|
@@ -597,6 +474,49 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
597
474
|
changed_files: list[str],
|
|
598
475
|
options: OptionsProtocol,
|
|
599
476
|
) -> str:
|
|
477
|
+
# Check if smart commit is enabled
|
|
478
|
+
if getattr(options, "smart_commit", False):
|
|
479
|
+
try:
|
|
480
|
+
from crackerjack.services.intelligent_commit import (
|
|
481
|
+
CommitMessageGenerator,
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
self.console.print(
|
|
485
|
+
"[cyan]🤖[/cyan] Generating intelligent commit message..."
|
|
486
|
+
)
|
|
487
|
+
commit_generator = CommitMessageGenerator(
|
|
488
|
+
console=self.console, git_service=self.git_service
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
intelligent_message = commit_generator.generate_commit_message(
|
|
492
|
+
include_body=False,
|
|
493
|
+
conventional_commits=True,
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
if not options.interactive:
|
|
497
|
+
self.console.print(
|
|
498
|
+
f"[green]✨[/green] Generated: {intelligent_message}"
|
|
499
|
+
)
|
|
500
|
+
return intelligent_message
|
|
501
|
+
|
|
502
|
+
# In interactive mode, offer the intelligent message plus fallback suggestions
|
|
503
|
+
suggestions = [intelligent_message]
|
|
504
|
+
fallback_suggestions = self.git_service.get_commit_message_suggestions(
|
|
505
|
+
changed_files
|
|
506
|
+
)
|
|
507
|
+
suggestions.extend(
|
|
508
|
+
fallback_suggestions[:3]
|
|
509
|
+
) # Add up to 3 fallback options
|
|
510
|
+
|
|
511
|
+
return self._interactive_commit_message_selection(suggestions)
|
|
512
|
+
|
|
513
|
+
except Exception as e:
|
|
514
|
+
self.console.print(
|
|
515
|
+
f"[yellow]⚠️[/yellow] Intelligent commit generation failed: {e}"
|
|
516
|
+
)
|
|
517
|
+
# Fallback to original logic
|
|
518
|
+
|
|
519
|
+
# Original logic for non-smart commits
|
|
600
520
|
suggestions = self.git_service.get_commit_message_suggestions(changed_files)
|
|
601
521
|
|
|
602
522
|
if not suggestions:
|
|
@@ -663,7 +583,6 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
663
583
|
def _execute_single_hook_attempt(
|
|
664
584
|
self, hook_runner: t.Callable[[], list[t.Any]]
|
|
665
585
|
) -> tuple[list[t.Any], dict[str, t.Any]] | None:
|
|
666
|
-
"""Execute a single hook attempt and return results and summary."""
|
|
667
586
|
try:
|
|
668
587
|
results = hook_runner()
|
|
669
588
|
summary = self.hook_manager.get_hook_summary(results)
|
|
@@ -680,7 +599,6 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
680
599
|
attempt: int,
|
|
681
600
|
max_retries: int,
|
|
682
601
|
) -> str:
|
|
683
|
-
"""Process hook results and return action: 'continue', 'success', or 'failure'."""
|
|
684
602
|
if not self._has_hook_failures(summary):
|
|
685
603
|
self._handle_hook_success(hook_type, summary)
|
|
686
604
|
return "success"
|
|
@@ -722,12 +640,12 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
722
640
|
return False
|
|
723
641
|
|
|
724
642
|
def _attempt_autofix_for_fast_hooks(self, results: list[t.Any]) -> bool:
|
|
725
|
-
"""Attempt to autofix fast hook failures using lazy-loaded coordinator."""
|
|
726
643
|
try:
|
|
727
644
|
self.logger.info("Attempting autofix for fast hook failures")
|
|
728
|
-
|
|
645
|
+
|
|
729
646
|
autofix_coordinator = self._lazy_autofix.get()
|
|
730
|
-
|
|
647
|
+
fix_result: bool = autofix_coordinator.apply_fast_stage_fixes()
|
|
648
|
+
return fix_result
|
|
731
649
|
except Exception as e:
|
|
732
650
|
self.logger.warning(f"Autofix attempt failed: {e}")
|
|
733
651
|
return False
|
|
@@ -749,15 +667,13 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
749
667
|
f"[red]❌[/ red] {hook_type.title()} hooks failed: {summary['failed']} failed, {summary['errors']} errors",
|
|
750
668
|
)
|
|
751
669
|
|
|
752
|
-
# Try autofix for fast hooks before giving up
|
|
753
670
|
if hook_type == "fast" and attempt < max_retries - 1:
|
|
754
671
|
if self._attempt_autofix_for_fast_hooks(results):
|
|
755
672
|
self.console.print(
|
|
756
673
|
"[yellow]🔧[/ yellow] Applied autofixes for fast hooks, retrying...",
|
|
757
674
|
)
|
|
758
|
-
return True
|
|
675
|
+
return True
|
|
759
676
|
|
|
760
|
-
# Display detailed hook errors in verbose mode
|
|
761
677
|
if getattr(options, "verbose", False):
|
|
762
678
|
self._display_verbose_hook_errors(results, hook_type)
|
|
763
679
|
|
|
@@ -772,13 +688,11 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
772
688
|
def _display_verbose_hook_errors(
|
|
773
689
|
self, results: list[t.Any], hook_type: str
|
|
774
690
|
) -> None:
|
|
775
|
-
"""Display detailed hook error output in verbose mode."""
|
|
776
691
|
self.console.print(
|
|
777
|
-
f"\n[bold yellow]📋 Detailed {hook_type} hook errors:[/bold yellow]"
|
|
692
|
+
f"\n[bold yellow]📋 Detailed {hook_type} hook errors: [/bold yellow]"
|
|
778
693
|
)
|
|
779
694
|
|
|
780
695
|
for result in results:
|
|
781
|
-
# Check if this hook failed
|
|
782
696
|
status = getattr(result, "status", "")
|
|
783
697
|
if status not in ("failed", "error", "timeout"):
|
|
784
698
|
continue
|
|
@@ -791,12 +705,10 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
791
705
|
if issues:
|
|
792
706
|
for issue in issues:
|
|
793
707
|
if isinstance(issue, str) and issue.strip():
|
|
794
|
-
# Clean up the issue text and display with proper indentation
|
|
795
708
|
cleaned_issue = issue.strip()
|
|
796
|
-
self.console.print(f"
|
|
709
|
+
self.console.print(f" {cleaned_issue}")
|
|
797
710
|
else:
|
|
798
|
-
|
|
799
|
-
self.console.print(f" Hook failed with exit code (status: {status})")
|
|
711
|
+
self.console.print(f" Hook failed with exit code (status: {status})")
|
|
800
712
|
|
|
801
713
|
def _build_detailed_hook_error_message(
|
|
802
714
|
self, results: list[t.Any], summary: dict[str, t.Any]
|
|
@@ -851,18 +763,15 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
851
763
|
self.session.fail_task(f"{hook_type}_hooks", str(e))
|
|
852
764
|
return False
|
|
853
765
|
|
|
854
|
-
# Performance-optimized hook execution methods
|
|
855
766
|
async def _execute_hooks_with_parallel_support(
|
|
856
767
|
self,
|
|
857
768
|
hook_type: str,
|
|
858
769
|
hook_runner: t.Callable[[], list[t.Any]],
|
|
859
770
|
options: OptionsProtocol,
|
|
860
771
|
) -> bool:
|
|
861
|
-
"""Execute hooks with parallel optimization where safe."""
|
|
862
772
|
self._initialize_hook_execution(hook_type)
|
|
863
773
|
|
|
864
774
|
try:
|
|
865
|
-
# Execute hooks and handle results
|
|
866
775
|
return await self._process_parallel_hook_execution(
|
|
867
776
|
hook_type, hook_runner, options
|
|
868
777
|
)
|
|
@@ -876,16 +785,12 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
876
785
|
hook_runner: t.Callable[[], list[t.Any]],
|
|
877
786
|
options: OptionsProtocol,
|
|
878
787
|
) -> bool:
|
|
879
|
-
"""Process hook execution with autofix retry logic."""
|
|
880
|
-
# For now, maintain sequential execution for safety
|
|
881
|
-
# Future enhancement: implement parallel execution for independent hooks
|
|
882
788
|
results = hook_runner()
|
|
883
789
|
summary = self.hook_manager.get_hook_summary(results)
|
|
884
790
|
|
|
885
791
|
if not self._has_hook_failures(summary):
|
|
886
792
|
return self._handle_hook_success(hook_type, summary)
|
|
887
793
|
|
|
888
|
-
# Handle failures with potential autofix retry
|
|
889
794
|
return self._handle_parallel_hook_failures(
|
|
890
795
|
hook_type, hook_runner, options, results, summary
|
|
891
796
|
)
|
|
@@ -898,19 +803,16 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
898
803
|
results: list[t.Any],
|
|
899
804
|
summary: dict[str, t.Any],
|
|
900
805
|
) -> bool:
|
|
901
|
-
"""Handle hook failures with autofix retry for fast hooks."""
|
|
902
806
|
if hook_type != "fast":
|
|
903
807
|
return self._handle_hook_failures(
|
|
904
808
|
hook_type, options, summary, results, 0, 1
|
|
905
809
|
)
|
|
906
810
|
|
|
907
|
-
# Try autofix for fast hooks
|
|
908
811
|
if not self._attempt_autofix_for_fast_hooks(results):
|
|
909
812
|
return self._handle_hook_failures(
|
|
910
813
|
hook_type, options, summary, results, 0, 1
|
|
911
814
|
)
|
|
912
815
|
|
|
913
|
-
# Retry after successful autofix
|
|
914
816
|
return self._retry_hooks_after_autofix(hook_type, hook_runner, options)
|
|
915
817
|
|
|
916
818
|
def _retry_hooks_after_autofix(
|
|
@@ -919,12 +821,10 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
919
821
|
hook_runner: t.Callable[[], list[t.Any]],
|
|
920
822
|
options: OptionsProtocol,
|
|
921
823
|
) -> bool:
|
|
922
|
-
"""Retry hooks after autofix was applied."""
|
|
923
824
|
self.console.print(
|
|
924
825
|
"[yellow]🔧[/ yellow] Applied autofixes for fast hooks, retrying..."
|
|
925
826
|
)
|
|
926
827
|
|
|
927
|
-
# Retry after autofix
|
|
928
828
|
results = hook_runner()
|
|
929
829
|
summary = self.hook_manager.get_hook_summary(results)
|
|
930
830
|
|
|
@@ -934,6 +834,6 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
934
834
|
return self._handle_hook_failures(hook_type, options, summary, results, 0, 1)
|
|
935
835
|
|
|
936
836
|
@property
|
|
937
|
-
def autofix_coordinator(self):
|
|
938
|
-
|
|
939
|
-
return
|
|
837
|
+
def autofix_coordinator(self) -> AutofixCoordinator:
|
|
838
|
+
coordinator: AutofixCoordinator = self._lazy_autofix.get()
|
|
839
|
+
return coordinator
|