crackerjack 0.30.3__py3-none-any.whl → 0.31.7__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 (156) hide show
  1. crackerjack/CLAUDE.md +1005 -0
  2. crackerjack/RULES.md +380 -0
  3. crackerjack/__init__.py +42 -13
  4. crackerjack/__main__.py +227 -299
  5. crackerjack/agents/__init__.py +41 -0
  6. crackerjack/agents/architect_agent.py +281 -0
  7. crackerjack/agents/base.py +170 -0
  8. crackerjack/agents/coordinator.py +512 -0
  9. crackerjack/agents/documentation_agent.py +498 -0
  10. crackerjack/agents/dry_agent.py +388 -0
  11. crackerjack/agents/formatting_agent.py +245 -0
  12. crackerjack/agents/import_optimization_agent.py +281 -0
  13. crackerjack/agents/performance_agent.py +669 -0
  14. crackerjack/agents/proactive_agent.py +104 -0
  15. crackerjack/agents/refactoring_agent.py +788 -0
  16. crackerjack/agents/security_agent.py +529 -0
  17. crackerjack/agents/test_creation_agent.py +657 -0
  18. crackerjack/agents/test_specialist_agent.py +486 -0
  19. crackerjack/agents/tracker.py +212 -0
  20. crackerjack/api.py +560 -0
  21. crackerjack/cli/__init__.py +24 -0
  22. crackerjack/cli/facade.py +104 -0
  23. crackerjack/cli/handlers.py +267 -0
  24. crackerjack/cli/interactive.py +471 -0
  25. crackerjack/cli/options.py +409 -0
  26. crackerjack/cli/utils.py +18 -0
  27. crackerjack/code_cleaner.py +618 -928
  28. crackerjack/config/__init__.py +19 -0
  29. crackerjack/config/hooks.py +218 -0
  30. crackerjack/core/__init__.py +0 -0
  31. crackerjack/core/async_workflow_orchestrator.py +406 -0
  32. crackerjack/core/autofix_coordinator.py +200 -0
  33. crackerjack/core/container.py +104 -0
  34. crackerjack/core/enhanced_container.py +542 -0
  35. crackerjack/core/performance.py +243 -0
  36. crackerjack/core/phase_coordinator.py +585 -0
  37. crackerjack/core/proactive_workflow.py +316 -0
  38. crackerjack/core/session_coordinator.py +289 -0
  39. crackerjack/core/workflow_orchestrator.py +826 -0
  40. crackerjack/dynamic_config.py +94 -103
  41. crackerjack/errors.py +263 -41
  42. crackerjack/executors/__init__.py +11 -0
  43. crackerjack/executors/async_hook_executor.py +431 -0
  44. crackerjack/executors/cached_hook_executor.py +242 -0
  45. crackerjack/executors/hook_executor.py +345 -0
  46. crackerjack/executors/individual_hook_executor.py +669 -0
  47. crackerjack/intelligence/__init__.py +44 -0
  48. crackerjack/intelligence/adaptive_learning.py +751 -0
  49. crackerjack/intelligence/agent_orchestrator.py +551 -0
  50. crackerjack/intelligence/agent_registry.py +414 -0
  51. crackerjack/intelligence/agent_selector.py +502 -0
  52. crackerjack/intelligence/integration.py +290 -0
  53. crackerjack/interactive.py +576 -315
  54. crackerjack/managers/__init__.py +11 -0
  55. crackerjack/managers/async_hook_manager.py +135 -0
  56. crackerjack/managers/hook_manager.py +137 -0
  57. crackerjack/managers/publish_manager.py +433 -0
  58. crackerjack/managers/test_command_builder.py +151 -0
  59. crackerjack/managers/test_executor.py +443 -0
  60. crackerjack/managers/test_manager.py +258 -0
  61. crackerjack/managers/test_manager_backup.py +1124 -0
  62. crackerjack/managers/test_progress.py +114 -0
  63. crackerjack/mcp/__init__.py +0 -0
  64. crackerjack/mcp/cache.py +336 -0
  65. crackerjack/mcp/client_runner.py +104 -0
  66. crackerjack/mcp/context.py +621 -0
  67. crackerjack/mcp/dashboard.py +636 -0
  68. crackerjack/mcp/enhanced_progress_monitor.py +479 -0
  69. crackerjack/mcp/file_monitor.py +336 -0
  70. crackerjack/mcp/progress_components.py +569 -0
  71. crackerjack/mcp/progress_monitor.py +949 -0
  72. crackerjack/mcp/rate_limiter.py +332 -0
  73. crackerjack/mcp/server.py +22 -0
  74. crackerjack/mcp/server_core.py +244 -0
  75. crackerjack/mcp/service_watchdog.py +501 -0
  76. crackerjack/mcp/state.py +395 -0
  77. crackerjack/mcp/task_manager.py +257 -0
  78. crackerjack/mcp/tools/__init__.py +17 -0
  79. crackerjack/mcp/tools/core_tools.py +249 -0
  80. crackerjack/mcp/tools/error_analyzer.py +308 -0
  81. crackerjack/mcp/tools/execution_tools.py +372 -0
  82. crackerjack/mcp/tools/execution_tools_backup.py +1097 -0
  83. crackerjack/mcp/tools/intelligence_tool_registry.py +80 -0
  84. crackerjack/mcp/tools/intelligence_tools.py +314 -0
  85. crackerjack/mcp/tools/monitoring_tools.py +502 -0
  86. crackerjack/mcp/tools/proactive_tools.py +384 -0
  87. crackerjack/mcp/tools/progress_tools.py +217 -0
  88. crackerjack/mcp/tools/utility_tools.py +341 -0
  89. crackerjack/mcp/tools/workflow_executor.py +565 -0
  90. crackerjack/mcp/websocket/__init__.py +14 -0
  91. crackerjack/mcp/websocket/app.py +39 -0
  92. crackerjack/mcp/websocket/endpoints.py +559 -0
  93. crackerjack/mcp/websocket/jobs.py +253 -0
  94. crackerjack/mcp/websocket/server.py +116 -0
  95. crackerjack/mcp/websocket/websocket_handler.py +78 -0
  96. crackerjack/mcp/websocket_server.py +10 -0
  97. crackerjack/models/__init__.py +31 -0
  98. crackerjack/models/config.py +93 -0
  99. crackerjack/models/config_adapter.py +230 -0
  100. crackerjack/models/protocols.py +118 -0
  101. crackerjack/models/task.py +154 -0
  102. crackerjack/monitoring/ai_agent_watchdog.py +450 -0
  103. crackerjack/monitoring/regression_prevention.py +638 -0
  104. crackerjack/orchestration/__init__.py +0 -0
  105. crackerjack/orchestration/advanced_orchestrator.py +970 -0
  106. crackerjack/orchestration/coverage_improvement.py +223 -0
  107. crackerjack/orchestration/execution_strategies.py +341 -0
  108. crackerjack/orchestration/test_progress_streamer.py +636 -0
  109. crackerjack/plugins/__init__.py +15 -0
  110. crackerjack/plugins/base.py +200 -0
  111. crackerjack/plugins/hooks.py +246 -0
  112. crackerjack/plugins/loader.py +335 -0
  113. crackerjack/plugins/managers.py +259 -0
  114. crackerjack/py313.py +8 -3
  115. crackerjack/services/__init__.py +22 -0
  116. crackerjack/services/cache.py +314 -0
  117. crackerjack/services/config.py +358 -0
  118. crackerjack/services/config_integrity.py +99 -0
  119. crackerjack/services/contextual_ai_assistant.py +516 -0
  120. crackerjack/services/coverage_ratchet.py +356 -0
  121. crackerjack/services/debug.py +736 -0
  122. crackerjack/services/dependency_monitor.py +617 -0
  123. crackerjack/services/enhanced_filesystem.py +439 -0
  124. crackerjack/services/file_hasher.py +151 -0
  125. crackerjack/services/filesystem.py +421 -0
  126. crackerjack/services/git.py +176 -0
  127. crackerjack/services/health_metrics.py +611 -0
  128. crackerjack/services/initialization.py +873 -0
  129. crackerjack/services/log_manager.py +286 -0
  130. crackerjack/services/logging.py +174 -0
  131. crackerjack/services/metrics.py +578 -0
  132. crackerjack/services/pattern_cache.py +362 -0
  133. crackerjack/services/pattern_detector.py +515 -0
  134. crackerjack/services/performance_benchmarks.py +653 -0
  135. crackerjack/services/security.py +163 -0
  136. crackerjack/services/server_manager.py +234 -0
  137. crackerjack/services/smart_scheduling.py +144 -0
  138. crackerjack/services/tool_version_service.py +61 -0
  139. crackerjack/services/unified_config.py +437 -0
  140. crackerjack/services/version_checker.py +248 -0
  141. crackerjack/slash_commands/__init__.py +14 -0
  142. crackerjack/slash_commands/init.md +122 -0
  143. crackerjack/slash_commands/run.md +163 -0
  144. crackerjack/slash_commands/status.md +127 -0
  145. crackerjack-0.31.7.dist-info/METADATA +742 -0
  146. crackerjack-0.31.7.dist-info/RECORD +149 -0
  147. crackerjack-0.31.7.dist-info/entry_points.txt +2 -0
  148. crackerjack/.gitignore +0 -34
  149. crackerjack/.libcst.codemod.yaml +0 -18
  150. crackerjack/.pdm.toml +0 -1
  151. crackerjack/crackerjack.py +0 -3805
  152. crackerjack/pyproject.toml +0 -286
  153. crackerjack-0.30.3.dist-info/METADATA +0 -1290
  154. crackerjack-0.30.3.dist-info/RECORD +0 -16
  155. {crackerjack-0.30.3.dist-info → crackerjack-0.31.7.dist-info}/WHEEL +0 -0
  156. {crackerjack-0.30.3.dist-info → crackerjack-0.31.7.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,200 @@
1
+ """Autofix coordination and retry logic for crackerjack workflows."""
2
+
3
+ import logging
4
+ import subprocess
5
+ import typing as t
6
+ from pathlib import Path
7
+
8
+ from rich.console import Console
9
+
10
+
11
+ class AutofixCoordinator:
12
+ def __init__(self, console: Console, pkg_path: Path) -> None:
13
+ self.console = console
14
+ self.pkg_path = pkg_path
15
+ self.logger = logging.getLogger("crackerjack.autofix")
16
+
17
+ def apply_autofix_for_hooks(self, mode: str, hook_results: list[t.Any]) -> bool:
18
+ self.logger.debug(
19
+ f"Applying autofix for {mode} mode with {len(hook_results)} hook results",
20
+ )
21
+ try:
22
+ if self._should_skip_autofix(hook_results):
23
+ self.logger.info(
24
+ f"Skipping autofix for {mode} - unfixable error patterns detected",
25
+ )
26
+ return False
27
+ if mode == "fast":
28
+ result = self._apply_fast_stage_fixes()
29
+ self.logger.debug(f"Fast stage fixes result: {result}")
30
+ return result
31
+ if mode == "comprehensive":
32
+ result = self._apply_comprehensive_stage_fixes(hook_results)
33
+ self.logger.debug(f"Comprehensive stage fixes result: {result}")
34
+ return result
35
+ self.logger.warning(f"Unknown autofix mode: {mode}")
36
+ return False
37
+ except Exception as e:
38
+ self.logger.error(f"Auto-fix error in {mode} mode: {e}", exc_info=True)
39
+ self.console.print(f"[dim red]Auto-fix error: {e}[/dim red]")
40
+ return False
41
+
42
+ def apply_fast_stage_fixes(self) -> bool:
43
+ """Public interface for applying fast stage fixes."""
44
+ return self._apply_fast_stage_fixes()
45
+
46
+ def apply_comprehensive_stage_fixes(self, hook_results: list[t.Any]) -> bool:
47
+ """Public interface for applying comprehensive stage fixes."""
48
+ return self._apply_comprehensive_stage_fixes(hook_results)
49
+
50
+ def run_fix_command(self, cmd: list[str], description: str) -> bool:
51
+ """Public interface for running fix commands."""
52
+ return self._run_fix_command(cmd, description)
53
+
54
+ def check_tool_success_patterns(self, cmd: list[str], result: t.Any) -> bool:
55
+ """Public interface for checking tool success patterns."""
56
+ return self._check_tool_success_patterns(cmd, result)
57
+
58
+ def validate_fix_command(self, cmd: list[str]) -> bool:
59
+ """Public interface for validating fix commands."""
60
+ return self._validate_fix_command(cmd)
61
+
62
+ def validate_hook_result(self, result: t.Any) -> bool:
63
+ """Public interface for validating hook results."""
64
+ return self._validate_hook_result(result)
65
+
66
+ def should_skip_autofix(self, hook_results: list[t.Any]) -> bool:
67
+ """Public interface for checking if autofix should be skipped."""
68
+ return self._should_skip_autofix(hook_results)
69
+
70
+ def _apply_fast_stage_fixes(self) -> bool:
71
+ return self._execute_fast_fixes()
72
+
73
+ def _execute_fast_fixes(self) -> bool:
74
+ fixes_applied = False
75
+ fix_commands = [
76
+ (["uv", "run", "ruff", "format", "."], "ruff formatting"),
77
+ (["uv", "run", "ruff", "check", ".", "--fix"], "ruff auto-fixes"),
78
+ ]
79
+ for cmd, description in fix_commands:
80
+ if self._run_fix_command(cmd, description):
81
+ fixes_applied = True
82
+
83
+ return fixes_applied
84
+
85
+ def _apply_comprehensive_stage_fixes(self, hook_results: list[t.Any]) -> bool:
86
+ fixes_applied = False
87
+ if self._apply_fast_stage_fixes():
88
+ fixes_applied = True
89
+ failed_hooks = self._extract_failed_hooks(hook_results)
90
+ hook_specific_fixes = self._get_hook_specific_fixes(failed_hooks)
91
+ for cmd, description in hook_specific_fixes:
92
+ if self._run_fix_command(cmd, description):
93
+ fixes_applied = True
94
+
95
+ return fixes_applied
96
+
97
+ def _extract_failed_hooks(self, hook_results: list[t.Any]) -> set[str]:
98
+ failed_hooks: set[str] = set()
99
+ for result in hook_results:
100
+ if self._validate_hook_result(result):
101
+ hook_name: str = getattr(result, "name", "").lower()
102
+ hook_status: str = getattr(result, "status", "")
103
+ if hook_status == "Failed" and hook_name:
104
+ failed_hooks.add(hook_name)
105
+
106
+ return failed_hooks
107
+
108
+ def _get_hook_specific_fixes(
109
+ self,
110
+ failed_hooks: set[str],
111
+ ) -> list[tuple[list[str], str]]:
112
+ hook_specific_fixes: list[tuple[list[str], str]] = []
113
+ if "bandit" in failed_hooks:
114
+ hook_specific_fixes.append(
115
+ (["uv", "run", "bandit", "-f", "json", ".", "-ll"], "bandit analysis"),
116
+ )
117
+
118
+ return hook_specific_fixes
119
+
120
+ def _run_fix_command(self, cmd: list[str], description: str) -> bool:
121
+ if not self._validate_fix_command(cmd):
122
+ return False
123
+ try:
124
+ result = subprocess.run(
125
+ cmd,
126
+ check=False,
127
+ capture_output=True,
128
+ text=True,
129
+ timeout=30,
130
+ cwd=self.pkg_path,
131
+ )
132
+ return self._handle_command_result(result, description)
133
+ except Exception:
134
+ return False
135
+
136
+ def _handle_command_result(
137
+ self,
138
+ result: subprocess.CompletedProcess[str],
139
+ description: str,
140
+ ) -> bool:
141
+ return bool(result.returncode == 0 or self._is_successful_fix(result))
142
+
143
+ def _is_successful_fix(self, result: subprocess.CompletedProcess[str]) -> bool:
144
+ output = result.stdout.lower()
145
+ return "fixed" in output or "reformatted" in output
146
+
147
+ def _check_tool_success_patterns(self, cmd: list[str], result: t.Any) -> bool:
148
+ """Check if a tool command result indicates success."""
149
+ if not cmd or len(cmd) < 3:
150
+ return False
151
+
152
+ tool_name = cmd[2] if len(cmd) > 2 else ""
153
+
154
+ # Check if result is a subprocess.CompletedProcess
155
+ if hasattr(result, "returncode"):
156
+ return result.returncode == 0
157
+
158
+ # Check for specific tool success patterns
159
+ if isinstance(result, str):
160
+ output_lower = result.lower()
161
+ if "ruff" in tool_name:
162
+ return "fixed" in output_lower or "would reformat" in output_lower
163
+ if "trailing-whitespace" in tool_name:
164
+ return "fixing" in output_lower or "fixed" in output_lower
165
+
166
+ return False
167
+
168
+ def _validate_fix_command(self, cmd: list[str]) -> bool:
169
+ if len(cmd) < 3:
170
+ return False
171
+ if cmd[0] != "uv" or cmd[1] != "run":
172
+ return False
173
+ tool_name = cmd[2]
174
+ return tool_name in ("ruff", "bandit")
175
+
176
+ def _validate_hook_result(self, result: t.Any) -> bool:
177
+ if not hasattr(result, "name") or not hasattr(result, "status"):
178
+ self.logger.warning(f"Invalid hook result structure: {type(result)}")
179
+ return False
180
+ name = getattr(result, "name", None)
181
+ status = getattr(result, "status", None)
182
+ if not isinstance(name, str) or not name.strip():
183
+ self.logger.warning(f"Hook result has invalid name: {name}")
184
+ return False
185
+ if status not in ("Passed", "Failed", "Skipped", "Error"):
186
+ self.logger.warning(f"Hook result has invalid status: {status}")
187
+ return False
188
+
189
+ return True
190
+
191
+ def _should_skip_autofix(self, hook_results: list[t.Any]) -> bool:
192
+ for result in hook_results:
193
+ if hasattr(result, "raw_output"):
194
+ output = getattr(result, "raw_output", "")
195
+ if "ModuleNotFoundError" in output or "ImportError" in output:
196
+ self.console.print(
197
+ "[dim yellow] → Skipping autofix (import errors)[/dim yellow]",
198
+ )
199
+ return True
200
+ return False
@@ -0,0 +1,104 @@
1
+ import typing as t
2
+ from pathlib import Path
3
+
4
+ from rich.console import Console
5
+
6
+ from crackerjack.models.protocols import (
7
+ FileSystemInterface,
8
+ GitInterface,
9
+ HookManager,
10
+ PublishManager,
11
+ TestManagerProtocol,
12
+ )
13
+
14
+
15
+ class DependencyContainer:
16
+ def __init__(self) -> None:
17
+ self._services: dict[str, t.Any] = {}
18
+ self._singletons: dict[str, t.Any] = {}
19
+
20
+ def register_singleton(self, interface: type, implementation: t.Any) -> None:
21
+ self._singletons[interface.__name__] = implementation
22
+
23
+ def register_transient(
24
+ self,
25
+ interface: type,
26
+ factory: t.Callable[[], t.Any],
27
+ ) -> None:
28
+ self._services[interface.__name__] = factory
29
+
30
+ def get(self, interface: type) -> t.Any:
31
+ name = interface.__name__
32
+ if name in self._singletons:
33
+ return self._singletons[name]
34
+ if name in self._services:
35
+ return self._services[name]()
36
+ msg = f"Service {name} not registered"
37
+ raise ValueError(msg)
38
+
39
+ def create_default_container(
40
+ self,
41
+ console: Console | None = None,
42
+ pkg_path: Path | None = None,
43
+ dry_run: bool = False,
44
+ verbose: bool = False,
45
+ ) -> "DependencyContainer":
46
+ if console is None:
47
+ console = Console(force_terminal=True)
48
+
49
+ if pkg_path is None:
50
+ pkg_path = Path.cwd()
51
+
52
+ from crackerjack.services.filesystem import FileSystemService
53
+
54
+ self.register_singleton(FileSystemInterface, FileSystemService())
55
+
56
+ from crackerjack.services.git import GitService
57
+
58
+ self.register_transient(
59
+ GitInterface,
60
+ lambda: GitService(console=console, pkg_path=pkg_path),
61
+ )
62
+
63
+ from crackerjack.managers.hook_manager import HookManagerImpl
64
+
65
+ self.register_transient(
66
+ HookManager,
67
+ lambda: HookManagerImpl(
68
+ console=console, pkg_path=pkg_path, verbose=verbose, quiet=True
69
+ ),
70
+ )
71
+
72
+ from crackerjack.managers.test_manager import TestManagementImpl
73
+
74
+ self.register_transient(
75
+ TestManagerProtocol,
76
+ lambda: TestManagementImpl(console=console, pkg_path=pkg_path),
77
+ )
78
+
79
+ from crackerjack.managers.publish_manager import PublishManagerImpl
80
+
81
+ self.register_transient(
82
+ PublishManager,
83
+ lambda: PublishManagerImpl(
84
+ console=console,
85
+ pkg_path=pkg_path,
86
+ dry_run=dry_run,
87
+ ),
88
+ )
89
+
90
+ return self
91
+
92
+
93
+ def create_container(
94
+ console: Console | None = None,
95
+ pkg_path: Path | None = None,
96
+ dry_run: bool = False,
97
+ verbose: bool = False,
98
+ ) -> DependencyContainer:
99
+ return DependencyContainer().create_default_container(
100
+ console=console,
101
+ pkg_path=pkg_path,
102
+ dry_run=dry_run,
103
+ verbose=verbose,
104
+ )