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.
- 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 +618 -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.2.dist-info}/METADATA +196 -25
- crackerjack-0.33.2.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.2.dist-info}/WHEEL +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/licenses/LICENSE +0 -0
crackerjack/RULES.md
DELETED
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
# Crackerjack Style Rules
|
|
2
|
-
|
|
3
|
-
## Clean Code Philosophy (Foundation)
|
|
4
|
-
|
|
5
|
-
**EVERY LINE OF CODE IS A LIABILITY. The best code is no code.**
|
|
6
|
-
|
|
7
|
-
- **DRY (Don't Repeat Yourself)**: If you write it twice, you're doing it wrong
|
|
8
|
-
- **YAGNI (You Ain't Gonna Need It)**: Build only what's needed NOW
|
|
9
|
-
- **KISS (Keep It Simple, Stupid)**: Complexity is the enemy of maintainability
|
|
10
|
-
- **Less is More**: Prefer 10 lines that are clear over 100 that are clever
|
|
11
|
-
- **Code is Read 10x More Than Written**: Optimize for readability
|
|
12
|
-
- **Self-Documenting Code**: Code should explain itself; comments only for "why", not "what". Variable names should **ALWAYS** be clear and descriptive, even in inline map/filter functions.
|
|
13
|
-
|
|
14
|
-
## Code Quality & Style
|
|
15
|
-
|
|
16
|
-
- **Use Static Typing Everywhere**
|
|
17
|
-
|
|
18
|
-
- Always include comprehensive type hints
|
|
19
|
-
- Use modern typing syntax with the pipe operator (`|`) for unions instead of `Optional[T]`
|
|
20
|
-
- Import typing as `import typing as t` and prefix all typing references with `t.`
|
|
21
|
-
- Never import individual types directly from typing (e.g., avoid `from typing import List, Dict, Optional`)
|
|
22
|
-
- Always use the `t.` prefix for all typing-related types
|
|
23
|
-
- Use built-in collection types directly instead of typing equivalents:
|
|
24
|
-
- Use `list[str]` instead of `t.List[str]`
|
|
25
|
-
- Use `dict[str, int]` instead of `t.Dict[str, int]`
|
|
26
|
-
- Use `tuple[int, ...]` instead of `t.Tuple[int, ...]`
|
|
27
|
-
|
|
28
|
-
- **Modern Python Features**
|
|
29
|
-
|
|
30
|
-
- Target Python 3.13+ features and syntax
|
|
31
|
-
- Use f-strings instead of other string formatting methods
|
|
32
|
-
- Prefer `pathlib.Path` over `os.path` for file operations
|
|
33
|
-
|
|
34
|
-
- **Clean Code Architecture**
|
|
35
|
-
|
|
36
|
-
- Write modular functions that do one thing well
|
|
37
|
-
- **NO DOCSTRINGS**: Never add docstrings to any code - the codebase standard is to have no docstrings (they are automatically removed by the `-x` flag)
|
|
38
|
-
- Avoid unnecessary line comments - use them sparingly only for complex logic
|
|
39
|
-
- Use protocols (`t.Protocol`) instead of abstract base classes
|
|
40
|
-
- Choose clear, descriptive variable and function names that make the code self-documenting (even in map/filter functions)
|
|
41
|
-
- **Keep cognitive complexity ≤15 per function** - extract helper methods if needed (KISS principle)
|
|
42
|
-
|
|
43
|
-
- **Code Organization**
|
|
44
|
-
|
|
45
|
-
- Group related functionality into well-defined classes
|
|
46
|
-
- Use runtime-checkable protocols with `@t.runtime_checkable`
|
|
47
|
-
- Prefer dataclasses for structured data
|
|
48
|
-
- Use type checking with strict enforcement
|
|
49
|
-
|
|
50
|
-
- **Project Structure**
|
|
51
|
-
|
|
52
|
-
- Structure projects with clear separation of concerns
|
|
53
|
-
- Follow standard package layout conventions
|
|
54
|
-
- Use [pyproject.toml](https://github.com/lesleslie/crackerjack/blob/main/pyproject.toml) for all configuration
|
|
55
|
-
- **Modular Architecture**: Use protocol-based dependency injection
|
|
56
|
-
- Core orchestration layer: `WorkflowOrchestrator`, `AsyncWorkflowOrchestrator`
|
|
57
|
-
- Coordinator layer: `SessionCoordinator`, `PhaseCoordinator`
|
|
58
|
-
- Domain managers: `HookManager`, `TestManager`, `PublishManager`
|
|
59
|
-
- Infrastructure services: filesystem, git, config, security
|
|
60
|
-
|
|
61
|
-
## Tool Integration
|
|
62
|
-
|
|
63
|
-
- **Integrate with Quality Tools**
|
|
64
|
-
|
|
65
|
-
- Configure code with Ruff for linting and formatting
|
|
66
|
-
- Set up pre-commit hooks for consistent code quality
|
|
67
|
-
- Use UV for dependency management
|
|
68
|
-
|
|
69
|
-
## Critical Error Prevention
|
|
70
|
-
|
|
71
|
-
**Bandit B108 (Hardcoded Temp Directory):**
|
|
72
|
-
|
|
73
|
-
```python
|
|
74
|
-
# NEVER do this - causes security warnings
|
|
75
|
-
config_path = "/tmp/test-config.yaml"
|
|
76
|
-
|
|
77
|
-
# ALWAYS use tempfile module
|
|
78
|
-
import tempfile
|
|
79
|
-
|
|
80
|
-
with tempfile.NamedTemporaryFile(suffix=".yaml", delete=False) as temp_file:
|
|
81
|
-
config_path = temp_file.name
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**Refurb FURB184 (Return Statement Chaining):**
|
|
85
|
-
|
|
86
|
-
```python
|
|
87
|
-
# AVOID - unnecessary intermediate variable
|
|
88
|
-
def create_config() -> Config:
|
|
89
|
-
generator = ConfigGenerator()
|
|
90
|
-
return generator.create_config()
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# PREFER - chained return statement
|
|
94
|
-
def create_config() -> Config:
|
|
95
|
-
return ConfigGenerator().create_config()
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
**Pyright Protocol Compatibility:**
|
|
99
|
-
|
|
100
|
-
```python
|
|
101
|
-
# ALWAYS implement ALL protocol properties
|
|
102
|
-
class TestOptions(OptionsProtocol):
|
|
103
|
-
# Missing properties cause type errors
|
|
104
|
-
verbose: bool = False
|
|
105
|
-
experimental_hooks: bool = False # Don't forget new properties
|
|
106
|
-
enable_pyrefly: bool = False
|
|
107
|
-
enable_ty: bool = False
|
|
108
|
-
compress_docs: bool = False
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Complexipy Complexity (>15):**
|
|
112
|
-
|
|
113
|
-
```python
|
|
114
|
-
# AVOID - high complexity method
|
|
115
|
-
def process_data(self, data: dict) -> Result:
|
|
116
|
-
if condition1:
|
|
117
|
-
if condition2:
|
|
118
|
-
if condition3:
|
|
119
|
-
pass # ... many nested conditions >15 complexity
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
# PREFER - extracted helper methods
|
|
123
|
-
def process_data(self, data: dict) -> Result:
|
|
124
|
-
if self._should_process(data):
|
|
125
|
-
return self._handle_processing(data)
|
|
126
|
-
return self._handle_error(data)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def _should_process(self, data: dict) -> bool:
|
|
130
|
-
return condition1 and condition2 and condition3
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
- Implement pytest for testing with timeout handling
|
|
134
|
-
|
|
135
|
-
- **Use UV for Tool Execution**
|
|
136
|
-
|
|
137
|
-
- Always use `uv run` to execute tools within the project's virtual environment
|
|
138
|
-
- Run pytest with `uv run pytest` instead of calling pytest directly
|
|
139
|
-
- Execute tools like pyright, ruff, and crackerjack through UV: `uv run pyright`
|
|
140
|
-
- Ensures consistent tool versions and environment isolation
|
|
141
|
-
|
|
142
|
-
- **Pre-Commit Hook Configuration**
|
|
143
|
-
|
|
144
|
-
- Enforce a comprehensive set of pre-commit hooks for quality control:
|
|
145
|
-
- Pyright for static type checking
|
|
146
|
-
- Ruff for linting and formatting
|
|
147
|
-
- Vulture for detecting unused code
|
|
148
|
-
- Creosote for identifying unused dependencies
|
|
149
|
-
- Complexipy for code complexity analysis
|
|
150
|
-
- Codespell for spell checking
|
|
151
|
-
- Autotyping for type annotation
|
|
152
|
-
- Refurb for Python code modernization
|
|
153
|
-
- Bandit for security vulnerabilities
|
|
154
|
-
- Run hooks with `uv run pre-commit run --all-files` during development
|
|
155
|
-
- Configure hooks in `.pre-commit-config.yaml` with exact versions
|
|
156
|
-
- Ensure all code passes pre-commit checks before submitting
|
|
157
|
-
|
|
158
|
-
- **Specific Tool Compliance Standards**
|
|
159
|
-
|
|
160
|
-
- **Refurb (FURB Rules):**
|
|
161
|
-
|
|
162
|
-
- **FURB109**: ALWAYS use tuples `()` instead of lists `[]` for `in` membership testing
|
|
163
|
-
- **FURB120**: Never pass default values that match the function's default (e.g., `None` for optional parameters)
|
|
164
|
-
- Use modern Python patterns and built-ins consistently
|
|
165
|
-
|
|
166
|
-
- **Pyright Type Checking:**
|
|
167
|
-
|
|
168
|
-
- **reportMissingParameterType**: ALL function parameters MUST have complete type annotations
|
|
169
|
-
- **reportArgumentType**: Protocol implementations must include ALL required properties with correct types
|
|
170
|
-
- Use explicit type annotations for all function parameters and return types
|
|
171
|
-
|
|
172
|
-
- **Complexipy Code Complexity (KISS Enforcement):**
|
|
173
|
-
|
|
174
|
-
- Keep cognitive complexity ≤15 per function/method
|
|
175
|
-
- Break complex methods into 3-5 smaller helper functions with single responsibilities
|
|
176
|
-
- Use descriptive function names that explain their purpose
|
|
177
|
-
- Remember: complexity is the enemy of maintainability
|
|
178
|
-
|
|
179
|
-
- **Bandit Security:**
|
|
180
|
-
|
|
181
|
-
- Never use dangerous functions like `eval()`, `exec()`, or `subprocess.shell=True`
|
|
182
|
-
- Use `secrets` module for cryptographic operations, never `random`
|
|
183
|
-
- Always specify encoding when opening files
|
|
184
|
-
|
|
185
|
-
- **Automation Focus**
|
|
186
|
-
|
|
187
|
-
- Automate repetitive tasks whenever possible
|
|
188
|
-
- Create helpers for common development workflows
|
|
189
|
-
- Implement consistent error handling and reporting
|
|
190
|
-
|
|
191
|
-
## Development Philosophy
|
|
192
|
-
|
|
193
|
-
Following our **Clean Code Philosophy** where every line of code is a liability:
|
|
194
|
-
|
|
195
|
-
- **Simplicity Over Cleverness** (KISS)
|
|
196
|
-
|
|
197
|
-
- Choose obvious solutions over clever ones
|
|
198
|
-
- Prefer explicit code over implicit magic
|
|
199
|
-
- Write code that junior developers can understand
|
|
200
|
-
|
|
201
|
-
- **Build Only What's Needed** (YAGNI)
|
|
202
|
-
|
|
203
|
-
- Implement current requirements, not future possibilities
|
|
204
|
-
- Remove dead code immediately when discovered
|
|
205
|
-
- Resist over-engineering and premature optimization
|
|
206
|
-
|
|
207
|
-
- **Eliminate Repetition** (DRY)
|
|
208
|
-
|
|
209
|
-
- Extract common patterns into reusable functions
|
|
210
|
-
- Create shared utilities for repeated operations
|
|
211
|
-
- Use protocols and interfaces to reduce duplication
|
|
212
|
-
|
|
213
|
-
- **Consistency is Key**
|
|
214
|
-
|
|
215
|
-
- Maintain uniform style across the entire codebase
|
|
216
|
-
- Standardize import order and grouping
|
|
217
|
-
- Keep a consistent approach to error handling
|
|
218
|
-
|
|
219
|
-
- **Reliability and Testing**
|
|
220
|
-
|
|
221
|
-
- Write comprehensive tests using pytest
|
|
222
|
-
- Add appropriate timeouts to prevent hanging tests
|
|
223
|
-
- Use parallel test execution when appropriate
|
|
224
|
-
- Never create files directly on the filesystem in tests
|
|
225
|
-
- Always use `tempfile` module for temporary files and directories
|
|
226
|
-
- Use pytest's `tmp_path` and `tmp_path_factory` fixtures
|
|
227
|
-
- Clean up any generated resources after tests complete
|
|
228
|
-
- Tests should be isolated and not affect the surrounding environment
|
|
229
|
-
- Avoid hard-coded paths in tests that point to the real filesystem
|
|
230
|
-
|
|
231
|
-
- **Code Quality Validation**
|
|
232
|
-
|
|
233
|
-
- Code should pass all quality checks when run through crackerjack
|
|
234
|
-
- The ultimate goal is to run `python -m crackerjack -x -t` without any errors
|
|
235
|
-
- This validates proper typing, formatting, linting, and test success
|
|
236
|
-
- Consider code incomplete until it passes this validation
|
|
237
|
-
|
|
238
|
-
- **Error Handling**
|
|
239
|
-
|
|
240
|
-
- Use structured exception handling with specific exception types
|
|
241
|
-
- Provide meaningful error messages
|
|
242
|
-
- Add appropriate error context for debugging
|
|
243
|
-
|
|
244
|
-
- **Rich Output**
|
|
245
|
-
|
|
246
|
-
- Use the Rich library for console output
|
|
247
|
-
- Provide clear status indicators for operations
|
|
248
|
-
- Format output for readability
|
|
249
|
-
|
|
250
|
-
- **Opinionated Choices**
|
|
251
|
-
|
|
252
|
-
- Enforce a single correct way to accomplish tasks
|
|
253
|
-
- Remove unnecessary flexibility that could lead to inconsistency
|
|
254
|
-
- Value clarity over brevity
|
|
255
|
-
|
|
256
|
-
## Additional Best Practices
|
|
257
|
-
|
|
258
|
-
- **Performance Considerations**
|
|
259
|
-
|
|
260
|
-
- Use profiling tools to identify bottlenecks in critical code paths
|
|
261
|
-
- Benchmark and compare alternative implementations for optimization
|
|
262
|
-
- Favor readability over micro-optimizations except for demonstrated hot spots
|
|
263
|
-
- Document any non-obvious optimizations with comments explaining the rationale
|
|
264
|
-
|
|
265
|
-
- **Python Version Strategy**
|
|
266
|
-
|
|
267
|
-
- Target only the latest stable Python release (3.13+)
|
|
268
|
-
- Adopt new language features as soon as they become available
|
|
269
|
-
- Do not maintain backward compatibility with older Python versions
|
|
270
|
-
- Regularly update codebases to take advantage of new language improvements
|
|
271
|
-
- Plan to upgrade within weeks of a new Python release
|
|
272
|
-
|
|
273
|
-
- **Documentation Minimalism**
|
|
274
|
-
|
|
275
|
-
- Keep documentation focused on "why" rather than "what" the code does
|
|
276
|
-
- Document APIs at the module or class level rather than individual functions
|
|
277
|
-
- Use type hints to replace most parameter documentation
|
|
278
|
-
- Create examples for complex functionality instead of verbose explanations
|
|
279
|
-
|
|
280
|
-
- **Testing Philosophy**
|
|
281
|
-
|
|
282
|
-
- Write tests for behavior, not implementation details
|
|
283
|
-
- Focus on testing public interfaces rather than private functions
|
|
284
|
-
- Use property-based testing for algorithmic code where appropriate
|
|
285
|
-
- Separate unit tests, integration tests, and benchmarks
|
|
286
|
-
- Aim for complete test coverage of critical paths but avoid test-for-test's-sake
|
|
287
|
-
- Use asyncio exclusively for async testing; do not test with trio compatibility
|
|
288
|
-
- Configure pytest with asyncio_mode="auto" for simpler async testing
|
|
289
|
-
|
|
290
|
-
- **Test Coverage Improvement (MANDATORY)**
|
|
291
|
-
|
|
292
|
-
- **Maintain 42% minimum coverage**: Never reduce coverage below 42% in config files
|
|
293
|
-
- **Always improve coverage incrementally** when working on projects with pytest coverage below the target
|
|
294
|
-
- **Check coverage first**: Run `uv run pytest --cov=<package_name> --cov-report=term-missing` to see current status
|
|
295
|
-
- **Target 2-5% improvement per session**: Add 1-3 focused tests that cover uncovered lines
|
|
296
|
-
- **Prioritize easy wins**: Test simple functions, error paths, edge cases, and validation logic
|
|
297
|
-
- **3-attempt rule**: If a test doesn't work after 3 debugging attempts, skip it and move on
|
|
298
|
-
- **Time-boxed effort**: Spend maximum 10-15 minutes on coverage improvement per session
|
|
299
|
-
- **Focus on low-hanging fruit**: Property getters, simple validation, string formatting, error handling
|
|
300
|
-
- **Avoid complex coverage improvements**: Skip async operations, external integrations, and complex state management
|
|
301
|
-
- **Write focused tests**: Each test should cover 1-3 lines of uncovered code
|
|
302
|
-
- **Quality over quantity**: Tests should be simple, reliable, and fast (< 1 second each)
|
|
303
|
-
- **Example incremental approach**:
|
|
304
|
-
```python
|
|
305
|
-
# Target: Cover error handling in Options validation
|
|
306
|
-
def test_options_invalid_bump_option():
|
|
307
|
-
with pytest.raises(ValueError, match="Invalid bump option"):
|
|
308
|
-
Options(publish="invalid")
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
# Target: Cover string representation
|
|
312
|
-
def test_bump_option_str():
|
|
313
|
-
assert str(BumpOption.patch) == "patch"
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
# Target: Cover edge case in validation
|
|
317
|
-
def test_validate_empty_string():
|
|
318
|
-
result = Options.validate_bump_options("")
|
|
319
|
-
assert result == BumpOption.interactive
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
- **Dependency Management**
|
|
323
|
-
|
|
324
|
-
- Keep external dependencies to a minimum
|
|
325
|
-
- Pin exact versions in lockfiles but use range specifications in pyproject.toml
|
|
326
|
-
- Regularly audit dependencies for security issues
|
|
327
|
-
- Prefer standard library solutions when reasonable
|
|
328
|
-
- Favor dependencies that support the latest Python version
|
|
329
|
-
|
|
330
|
-
- **Code Review Standards**
|
|
331
|
-
|
|
332
|
-
- All code should be reviewed before merging
|
|
333
|
-
- Automate style and formatting checks to focus reviews on substance
|
|
334
|
-
- Look for edge cases and error handling in reviews
|
|
335
|
-
- Ensure tests adequately cover the changes
|
|
336
|
-
|
|
337
|
-
- **Session Progress Tracking**
|
|
338
|
-
|
|
339
|
-
- Progress tracking is now handled automatically by the MCP WebSocket server
|
|
340
|
-
- Real-time progress monitoring available at `ws://localhost:8675`
|
|
341
|
-
- Use `--resume-from` to continue interrupted sessions rather than starting over
|
|
342
|
-
|
|
343
|
-
## AI Agent Integration
|
|
344
|
-
|
|
345
|
-
- **AI Agent Iteration Workflow (CRITICAL)**
|
|
346
|
-
|
|
347
|
-
- AI agent mode (`--ai-agent`) follows strict iteration protocol:
|
|
348
|
-
1. **Fast Hooks** → Retry once if any fail (formatting fixes often cascade)
|
|
349
|
-
1. **Collect ALL Test Failures** → Don't stop on first failure, gather complete list
|
|
350
|
-
1. **Collect ALL Hook Issues** → Don't stop on first failure, gather complete list
|
|
351
|
-
1. **Apply AI Fixes** → Process ALL collected issues in batch, then move to next iteration
|
|
352
|
-
- **CRITICAL**: AI agent only advances to next iteration AFTER applying fixes
|
|
353
|
-
- This ensures each iteration validates fixes from the previous iteration
|
|
354
|
-
- Maximum 10 iterations to prevent infinite loops
|
|
355
|
-
- AsyncWorkflowOrchestrator implements this logic for MCP server compatibility
|
|
356
|
-
|
|
357
|
-
- **MCP Server Integration**
|
|
358
|
-
|
|
359
|
-
- Use standard orchestrator for MCP compatibility (not advanced orchestrator)
|
|
360
|
-
- WebSocket progress reporting requires proper iteration boundaries
|
|
361
|
-
- Real-time progress available at `ws://localhost:8675/ws/progress/{job_id}`
|
|
362
|
-
- MCP tools: `execute_crackerjack`, `get_job_progress`, `get_comprehensive_status`
|
|
363
|
-
|
|
364
|
-
## AI Assistant Self-Maintenance
|
|
365
|
-
|
|
366
|
-
- **Quality Standards Maintenance**
|
|
367
|
-
|
|
368
|
-
- AI assistants should update CLAUDE.md and RULES.md weekly or after pre-commit failures
|
|
369
|
-
- Learn from new Refurb rules (FURB codes), Pyright errors (reportXxx), and Complexipy thresholds
|
|
370
|
-
- Add newly discovered error patterns to documentation with code examples
|
|
371
|
-
- Test all documentation updates by running `python -m crackerjack --comprehensive`
|
|
372
|
-
- Prioritize frequently occurring error patterns as **CRITICAL** standards
|
|
373
|
-
|
|
374
|
-
- **Self-Learning Protocol**
|
|
375
|
-
|
|
376
|
-
- When encountering new pre-commit failures, extract the error pattern and add to standards
|
|
377
|
-
- Format new patterns with "Bad" and "Good" code examples
|
|
378
|
-
- Update the "AI Code Generation Best Practices" checklist in CLAUDE.md
|
|
379
|
-
- Ensure RULES.md stays synchronized with CLAUDE.md standards
|
|
380
|
-
- Monitor tool version updates and incorporate new rules as they emerge
|
crackerjack/py313.py
DELETED
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import subprocess
|
|
2
|
-
import typing
|
|
3
|
-
from enum import Enum, auto
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from typing import Any, Self, TypedDict
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class CommandRunner[TReturn]:
|
|
9
|
-
def run_command(self, cmd: list[str], **kwargs: Any) -> TReturn: ...
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class CommandResult(TypedDict):
|
|
13
|
-
success: bool
|
|
14
|
-
exit_code: int
|
|
15
|
-
stdout: str
|
|
16
|
-
stderr: str
|
|
17
|
-
command: list[str]
|
|
18
|
-
duration_ms: float
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def process_command_output(result: CommandResult) -> tuple[bool, str]:
|
|
22
|
-
match result:
|
|
23
|
-
case {"success": True, "stdout": stdout} if stdout.strip():
|
|
24
|
-
return (True, stdout)
|
|
25
|
-
case {"success": True}:
|
|
26
|
-
return (True, "Command completed successfully with no output")
|
|
27
|
-
case {"success": False, "exit_code": code, "stderr": stderr} if code == 127:
|
|
28
|
-
return (False, f"Command not found: {stderr}")
|
|
29
|
-
case {"success": False, "exit_code": code} if code > 0:
|
|
30
|
-
return (False, f"Command failed with exit code {code}: {result['stderr']}")
|
|
31
|
-
case _:
|
|
32
|
-
pass
|
|
33
|
-
return (False, "Unknown command result pattern")
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class HookStatus(Enum):
|
|
37
|
-
SUCCESS = auto()
|
|
38
|
-
FAILURE = auto()
|
|
39
|
-
SKIPPED = auto()
|
|
40
|
-
ERROR = auto()
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class HookResult(TypedDict):
|
|
44
|
-
status: HookStatus
|
|
45
|
-
hook_id: str
|
|
46
|
-
output: str
|
|
47
|
-
files: list[str]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def analyze_hook_result(result: HookResult) -> str:
|
|
51
|
-
match result:
|
|
52
|
-
case {"status": HookStatus.SUCCESS, "hook_id": hook_id}:
|
|
53
|
-
return f"✅ Hook {hook_id} passed successfully"
|
|
54
|
-
case {"status": HookStatus.FAILURE, "hook_id": hook_id, "output": output} if (
|
|
55
|
-
"fixable" in output
|
|
56
|
-
):
|
|
57
|
-
return f"🔧 Hook {hook_id} failed with fixable issues"
|
|
58
|
-
case {"status": HookStatus.FAILURE, "hook_id": hook_id}:
|
|
59
|
-
return f"❌ Hook {hook_id} failed"
|
|
60
|
-
case {"status": HookStatus.SKIPPED, "hook_id": hook_id}:
|
|
61
|
-
return f"⏩ Hook {hook_id} was skipped"
|
|
62
|
-
case {"status": HookStatus.ERROR, "hook_id": hook_id, "output": output}:
|
|
63
|
-
return f"💥 Hook {hook_id} encountered an error: {output}"
|
|
64
|
-
case _:
|
|
65
|
-
pass
|
|
66
|
-
return "Unknown hook result pattern"
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class ModernConfigManager:
|
|
70
|
-
def __init__(self, config_path: Path) -> None:
|
|
71
|
-
self.config_path = config_path
|
|
72
|
-
self.config: dict[str, Any] = {}
|
|
73
|
-
|
|
74
|
-
def load(self) -> Self:
|
|
75
|
-
return self
|
|
76
|
-
|
|
77
|
-
def update(self, key: str, value: Any) -> Self:
|
|
78
|
-
self.config[key] = value
|
|
79
|
-
return self
|
|
80
|
-
|
|
81
|
-
def save(self) -> Self:
|
|
82
|
-
return self
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def categorize_file(file_path: Path) -> str:
|
|
86
|
-
path_str = str(file_path)
|
|
87
|
-
name = file_path
|
|
88
|
-
match path_str:
|
|
89
|
-
case s if name.suffix == ".py" and "/ tests /" in s:
|
|
90
|
-
return "Python Test File"
|
|
91
|
-
case s if name.suffix == ".py" and "__init__.py" in name.name:
|
|
92
|
-
return "Python Module Init"
|
|
93
|
-
case s if name.suffix == ".py":
|
|
94
|
-
return "Python Source File"
|
|
95
|
-
case s if name.suffix in {".md", ".rst", ".txt"}:
|
|
96
|
-
return "Documentation File"
|
|
97
|
-
case s if name.stem.startswith(".") or name.name in {
|
|
98
|
-
".gitignore",
|
|
99
|
-
".pre-commit-config.yaml",
|
|
100
|
-
}:
|
|
101
|
-
return "Configuration File"
|
|
102
|
-
case _:
|
|
103
|
-
pass
|
|
104
|
-
return "Unknown File Type"
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def process_hook_results[T, R](
|
|
108
|
-
results: list[T],
|
|
109
|
-
success_handler: typing.Callable[[T], R],
|
|
110
|
-
failure_handler: typing.Callable[[T], R],
|
|
111
|
-
) -> list[R]:
|
|
112
|
-
processed_results: list[R] = []
|
|
113
|
-
for result in results:
|
|
114
|
-
if (
|
|
115
|
-
isinstance(result, dict)
|
|
116
|
-
and "status" in result
|
|
117
|
-
and result["status"] == HookStatus.SUCCESS
|
|
118
|
-
):
|
|
119
|
-
processed_results.append(success_handler(result))
|
|
120
|
-
else:
|
|
121
|
-
processed_results.append(failure_handler(result))
|
|
122
|
-
return processed_results
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
class EnhancedCommandRunner:
|
|
126
|
-
def __init__(self, working_dir: Path | None = None) -> None:
|
|
127
|
-
self.working_dir = working_dir
|
|
128
|
-
|
|
129
|
-
def run(self, cmd: list[str], **kwargs: Any) -> CommandResult:
|
|
130
|
-
import time
|
|
131
|
-
|
|
132
|
-
start_time = time.time()
|
|
133
|
-
try:
|
|
134
|
-
process = subprocess.run(
|
|
135
|
-
cmd,
|
|
136
|
-
check=False,
|
|
137
|
-
capture_output=True,
|
|
138
|
-
text=True,
|
|
139
|
-
cwd=self.working_dir,
|
|
140
|
-
**kwargs,
|
|
141
|
-
)
|
|
142
|
-
duration_ms = (time.time() - start_time) * 1000
|
|
143
|
-
return CommandResult(
|
|
144
|
-
success=process.returncode == 0,
|
|
145
|
-
exit_code=process.returncode,
|
|
146
|
-
stdout=process.stdout,
|
|
147
|
-
stderr=process.stderr,
|
|
148
|
-
command=cmd,
|
|
149
|
-
duration_ms=duration_ms,
|
|
150
|
-
)
|
|
151
|
-
except subprocess.SubprocessError as e:
|
|
152
|
-
duration_ms = (time.time() - start_time) * 1000
|
|
153
|
-
return CommandResult(
|
|
154
|
-
success=False,
|
|
155
|
-
exit_code=-1,
|
|
156
|
-
stdout="",
|
|
157
|
-
stderr=str(e),
|
|
158
|
-
command=cmd,
|
|
159
|
-
duration_ms=duration_ms,
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
def handle_result(self, result: CommandResult) -> tuple[bool, str]:
|
|
163
|
-
return process_command_output(result)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def clean_python_code(code: str) -> str:
|
|
167
|
-
lines = code.splitlines()
|
|
168
|
-
cleaned_lines: list[str] = []
|
|
169
|
-
for line in lines:
|
|
170
|
-
processed_line = _process_line_for_cleaning(line, cleaned_lines)
|
|
171
|
-
if processed_line is not None:
|
|
172
|
-
cleaned_lines.append(processed_line)
|
|
173
|
-
return "\n".join(cleaned_lines)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def _process_line_for_cleaning(line: str, cleaned_lines: list[str]) -> str | None:
|
|
177
|
-
"""Process a single line for Python code cleaning.
|
|
178
|
-
|
|
179
|
-
Returns:
|
|
180
|
-
The processed line to add, or None if the line should be skipped.
|
|
181
|
-
"""
|
|
182
|
-
stripped = line.strip()
|
|
183
|
-
|
|
184
|
-
if _should_handle_empty_line(stripped, cleaned_lines):
|
|
185
|
-
return ""
|
|
186
|
-
|
|
187
|
-
if _is_import_line(stripped):
|
|
188
|
-
return line
|
|
189
|
-
|
|
190
|
-
if _is_comment_to_skip(stripped):
|
|
191
|
-
return None
|
|
192
|
-
|
|
193
|
-
if _has_inline_comment_to_process(stripped):
|
|
194
|
-
return _extract_code_part(line)
|
|
195
|
-
|
|
196
|
-
if _is_docstring_line(stripped):
|
|
197
|
-
return None
|
|
198
|
-
|
|
199
|
-
return line
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def _should_handle_empty_line(stripped: str, cleaned_lines: list[str]) -> bool:
|
|
203
|
-
"""Check if empty line should be preserved."""
|
|
204
|
-
return stripped == "" and (not cleaned_lines or bool(cleaned_lines[-1].strip()))
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def _is_import_line(stripped: str) -> bool:
|
|
208
|
-
"""Check if line is an import statement."""
|
|
209
|
-
return stripped.startswith(("import ", "from "))
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
def _is_comment_to_skip(stripped: str) -> bool:
|
|
213
|
-
"""Check if line is a comment that should be skipped."""
|
|
214
|
-
return stripped.startswith("#")
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def _has_inline_comment_to_process(stripped: str) -> bool:
|
|
218
|
-
"""Check if line has inline comment that should be processed."""
|
|
219
|
-
if "#" not in stripped:
|
|
220
|
-
return False
|
|
221
|
-
|
|
222
|
-
skip_markers = ("# noqa", "# type: ", "# pragma", "# skip")
|
|
223
|
-
return not any(skip in stripped for skip in skip_markers)
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
def _extract_code_part(line: str) -> str | None:
|
|
227
|
-
"""Extract code part from line with inline comment."""
|
|
228
|
-
code_part = line.split("#", 1)[0].rstrip()
|
|
229
|
-
return code_part or None
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
def _is_docstring_line(stripped: str) -> bool:
|
|
233
|
-
"""Check if line starts a docstring."""
|
|
234
|
-
return stripped.startswith(('"""', "'''"))
|