crackerjack 0.38.12__py3-none-any.whl → 0.38.13__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 +0 -1
- crackerjack/executors/cached_hook_executor.py +2 -2
- crackerjack/orchestration/execution_strategies.py +1 -1
- crackerjack/py313.py +189 -0
- crackerjack/services/cache.py +0 -2
- {crackerjack-0.38.12.dist-info → crackerjack-0.38.13.dist-info}/METADATA +1 -1
- {crackerjack-0.38.12.dist-info → crackerjack-0.38.13.dist-info}/RECORD +10 -9
- {crackerjack-0.38.12.dist-info → crackerjack-0.38.13.dist-info}/WHEEL +0 -0
- {crackerjack-0.38.12.dist-info → crackerjack-0.38.13.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.38.12.dist-info → crackerjack-0.38.13.dist-info}/licenses/LICENSE +0 -0
crackerjack/__main__.py
CHANGED
|
@@ -1318,7 +1318,6 @@ def main(
|
|
|
1318
1318
|
config_interactive: bool = CLI_OPTIONS["config_interactive"],
|
|
1319
1319
|
refresh_cache: bool = CLI_OPTIONS["refresh_cache"],
|
|
1320
1320
|
) -> None:
|
|
1321
|
-
"""Main CLI entry point with complexity <= 15."""
|
|
1322
1321
|
options = create_options(
|
|
1323
1322
|
commit,
|
|
1324
1323
|
interactive,
|
|
@@ -261,11 +261,11 @@ class SmartCacheManager:
|
|
|
261
261
|
hook_name: str,
|
|
262
262
|
project_state: dict[str, t.Any],
|
|
263
263
|
) -> bool:
|
|
264
|
-
external_hooks =
|
|
264
|
+
external_hooks = set()
|
|
265
265
|
if hook_name in external_hooks:
|
|
266
266
|
return False
|
|
267
267
|
|
|
268
|
-
expensive_hooks = {"pyright", "bandit", "vulture", "complexipy"}
|
|
268
|
+
expensive_hooks = {"pyright", "bandit", "vulture", "complexipy", "gitleaks"}
|
|
269
269
|
if hook_name in expensive_hooks:
|
|
270
270
|
return True
|
|
271
271
|
|
|
@@ -198,7 +198,7 @@ class StrategySelector:
|
|
|
198
198
|
if "test" in str(file_path):
|
|
199
199
|
priority_hooks.update(["pytest", "coverage"])
|
|
200
200
|
if str(file_path).endswith(("setup.py", "pyproject.toml")):
|
|
201
|
-
priority_hooks.update(["bandit", "creosote", "
|
|
201
|
+
priority_hooks.update(["bandit", "creosote", "gitleaks"])
|
|
202
202
|
|
|
203
203
|
selected_hooks = [
|
|
204
204
|
hook for hook in strategy.hooks if hook.name in priority_hooks
|
crackerjack/py313.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
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
|
+
raise NotImplementedError("Subclasses must implement run_command")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CommandResult(TypedDict):
|
|
14
|
+
success: bool
|
|
15
|
+
exit_code: int
|
|
16
|
+
stdout: str
|
|
17
|
+
stderr: str
|
|
18
|
+
command: list[str]
|
|
19
|
+
duration_ms: float
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def process_command_output(result: CommandResult) -> tuple[bool, str]:
|
|
23
|
+
match result:
|
|
24
|
+
case {"success": True, "stdout": stdout} if stdout.strip():
|
|
25
|
+
return (True, stdout)
|
|
26
|
+
case {"success": True}:
|
|
27
|
+
return (True, "Command completed successfully with no output")
|
|
28
|
+
case {"success": False, "exit_code": code, "stderr": stderr} if code == 127:
|
|
29
|
+
return (False, f"Command not found: {stderr}")
|
|
30
|
+
case {"success": False, "exit_code": code} if code > 0:
|
|
31
|
+
return (False, f"Command failed with exit code {code}: {result['stderr']}")
|
|
32
|
+
case _:
|
|
33
|
+
pass
|
|
34
|
+
return (False, "Unknown command result pattern")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class HookStatus(Enum):
|
|
38
|
+
SUCCESS = auto()
|
|
39
|
+
FAILURE = auto()
|
|
40
|
+
SKIPPED = auto()
|
|
41
|
+
ERROR = auto()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class HookResult(TypedDict):
|
|
45
|
+
status: HookStatus
|
|
46
|
+
hook_id: str
|
|
47
|
+
output: str
|
|
48
|
+
files: list[str]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def analyze_hook_result(result: HookResult) -> str:
|
|
52
|
+
match result:
|
|
53
|
+
case {"status": HookStatus.SUCCESS, "hook_id": hook_id}:
|
|
54
|
+
return f"✅ Hook {hook_id} passed successfully"
|
|
55
|
+
case {"status": HookStatus.FAILURE, "hook_id": hook_id, "output": output} if (
|
|
56
|
+
"fixable" in output
|
|
57
|
+
):
|
|
58
|
+
return f"🔧 Hook {hook_id} failed with fixable issues"
|
|
59
|
+
case {"status": HookStatus.FAILURE, "hook_id": hook_id}:
|
|
60
|
+
return f"❌ Hook {hook_id} failed"
|
|
61
|
+
case {"status": HookStatus.SKIPPED, "hook_id": hook_id}:
|
|
62
|
+
return f"⏩ Hook {hook_id} was skipped"
|
|
63
|
+
case {"status": HookStatus.ERROR, "hook_id": hook_id, "output": output}:
|
|
64
|
+
return f"💥 Hook {hook_id} encountered an error: {output}"
|
|
65
|
+
case _:
|
|
66
|
+
pass
|
|
67
|
+
return "Unknown hook result pattern"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ModernConfigManager:
|
|
71
|
+
def __init__(self, config_path: Path) -> None:
|
|
72
|
+
self.config_path = config_path
|
|
73
|
+
self.config: dict[str, Any] = {}
|
|
74
|
+
|
|
75
|
+
def load(self) -> Self:
|
|
76
|
+
return self
|
|
77
|
+
|
|
78
|
+
def update(self, key: str, value: Any) -> Self:
|
|
79
|
+
self.config[key] = value
|
|
80
|
+
return self
|
|
81
|
+
|
|
82
|
+
def save(self) -> Self:
|
|
83
|
+
return self
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def categorize_file(file_path: Path) -> str:
|
|
87
|
+
path_str = str(file_path)
|
|
88
|
+
name = file_path
|
|
89
|
+
match path_str:
|
|
90
|
+
case s if name.suffix == ".py" and "/ tests /" in s:
|
|
91
|
+
return "Python Test File"
|
|
92
|
+
case s if name.suffix == ".py" and "__init__.py" in name.name:
|
|
93
|
+
return "Python Module Init"
|
|
94
|
+
case s if name.suffix == ".py":
|
|
95
|
+
return "Python Source File"
|
|
96
|
+
case s if name.suffix in {".md", ".rst", ".txt"}:
|
|
97
|
+
return "Documentation File"
|
|
98
|
+
case s if name.stem.startswith(".") or name.name in {
|
|
99
|
+
".gitignore",
|
|
100
|
+
".pre-commit-config.yaml",
|
|
101
|
+
}:
|
|
102
|
+
return "Configuration File"
|
|
103
|
+
case _:
|
|
104
|
+
pass
|
|
105
|
+
return "Unknown File Type"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def process_hook_results[T: HookResult, R](
|
|
109
|
+
results: list[T],
|
|
110
|
+
success_handler: typing.Callable[[T], R],
|
|
111
|
+
failure_handler: typing.Callable[[T], R],
|
|
112
|
+
) -> list[R]:
|
|
113
|
+
processed_results: list[R] = []
|
|
114
|
+
for result in results:
|
|
115
|
+
# Type checker knows T is HookResult, so no need for isinstance check
|
|
116
|
+
# But we keep it for runtime safety
|
|
117
|
+
if hasattr(result, "status") and result.status == HookStatus.SUCCESS:
|
|
118
|
+
processed_results.append(success_handler(result))
|
|
119
|
+
else:
|
|
120
|
+
processed_results.append(failure_handler(result))
|
|
121
|
+
return processed_results
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class EnhancedCommandRunner:
|
|
125
|
+
def __init__(self, working_dir: Path | None = None) -> None:
|
|
126
|
+
self.working_dir = working_dir
|
|
127
|
+
|
|
128
|
+
def run(self, cmd: list[str], **kwargs: Any) -> CommandResult:
|
|
129
|
+
import time
|
|
130
|
+
|
|
131
|
+
start_time = time.time()
|
|
132
|
+
try:
|
|
133
|
+
process = subprocess.run(
|
|
134
|
+
cmd,
|
|
135
|
+
check=False,
|
|
136
|
+
capture_output=True,
|
|
137
|
+
text=True,
|
|
138
|
+
cwd=self.working_dir,
|
|
139
|
+
**kwargs,
|
|
140
|
+
)
|
|
141
|
+
duration_ms = (time.time() - start_time) * 1000
|
|
142
|
+
return CommandResult(
|
|
143
|
+
success=process.returncode == 0,
|
|
144
|
+
exit_code=process.returncode,
|
|
145
|
+
stdout=process.stdout,
|
|
146
|
+
stderr=process.stderr,
|
|
147
|
+
command=cmd,
|
|
148
|
+
duration_ms=duration_ms,
|
|
149
|
+
)
|
|
150
|
+
except subprocess.SubprocessError as e:
|
|
151
|
+
duration_ms = (time.time() - start_time) * 1000
|
|
152
|
+
return CommandResult(
|
|
153
|
+
success=False,
|
|
154
|
+
exit_code=-1,
|
|
155
|
+
stdout="",
|
|
156
|
+
stderr=str(e),
|
|
157
|
+
command=cmd,
|
|
158
|
+
duration_ms=duration_ms,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
def handle_result(self, result: CommandResult) -> tuple[bool, str]:
|
|
162
|
+
return process_command_output(result)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def clean_python_code(code: str) -> str:
|
|
166
|
+
lines = code.splitlines()
|
|
167
|
+
cleaned_lines: list[str] = []
|
|
168
|
+
for line in lines:
|
|
169
|
+
match line.strip():
|
|
170
|
+
case "":
|
|
171
|
+
if not cleaned_lines or cleaned_lines[-1].strip():
|
|
172
|
+
cleaned_lines.append("")
|
|
173
|
+
case s if s.startswith(("import ", "from ")):
|
|
174
|
+
cleaned_lines.append(line)
|
|
175
|
+
case s if s.startswith("#"):
|
|
176
|
+
continue
|
|
177
|
+
case s if "#" in s and (
|
|
178
|
+
not any(
|
|
179
|
+
skip in s for skip in ("# noqa", "# type: ", "# pragma", "# skip")
|
|
180
|
+
)
|
|
181
|
+
):
|
|
182
|
+
code_part = line.split("#", 1)[0].rstrip()
|
|
183
|
+
if code_part:
|
|
184
|
+
cleaned_lines.append(code_part)
|
|
185
|
+
case s if s.startswith(('"""', "'''")):
|
|
186
|
+
continue
|
|
187
|
+
case _:
|
|
188
|
+
cleaned_lines.append(line)
|
|
189
|
+
return "\n".join(cleaned_lines)
|
crackerjack/services/cache.py
CHANGED
|
@@ -228,7 +228,6 @@ class CrackerjackCache:
|
|
|
228
228
|
"complexipy",
|
|
229
229
|
"refurb",
|
|
230
230
|
"gitleaks",
|
|
231
|
-
"detect-secrets",
|
|
232
231
|
}
|
|
233
232
|
|
|
234
233
|
# TTL configuration for different cache types (in seconds)
|
|
@@ -239,7 +238,6 @@ class CrackerjackCache:
|
|
|
239
238
|
"complexipy": 86400, # 24 hours - complexity analysis
|
|
240
239
|
"refurb": 86400, # 24 hours - code improvements
|
|
241
240
|
"gitleaks": 86400 * 7, # 7 days - secret detection is very stable
|
|
242
|
-
"detect-secrets": 86400 * 7, # 7 days - secret detection
|
|
243
241
|
}
|
|
244
242
|
|
|
245
243
|
# Agent version for cache invalidation when agent logic changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crackerjack
|
|
3
|
-
Version: 0.38.
|
|
3
|
+
Version: 0.38.13
|
|
4
4
|
Summary: Crackerjack Python project management tool
|
|
5
5
|
Project-URL: documentation, https://github.com/lesleslie/crackerjack
|
|
6
6
|
Project-URL: homepage, https://github.com/lesleslie/crackerjack
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
crackerjack/CLAUDE.md,sha256=FnF1XgcaCB59HEZxglEl4qEBTMyHQcqKoL0YjnAq24s,41230
|
|
2
2
|
crackerjack/__init__.py,sha256=DajG9zHB8qBdgdiKMumrrssUbKeMXmtIQ3oOaSTb46Y,1426
|
|
3
|
-
crackerjack/__main__.py,sha256=
|
|
3
|
+
crackerjack/__main__.py,sha256=6Te0CW6qyKiso0cTHv9stWnDZ9W8KnWXzW0oQ3hN7n8,55498
|
|
4
4
|
crackerjack/api.py,sha256=PyCRaZHvKWdu62_2O4t_HcEfKNBdqyrfPdonS_PNn4c,21495
|
|
5
5
|
crackerjack/code_cleaner.py,sha256=M1zVaq31uW0nOkPneKR8kfR3892gyyVx0VhFgRaxsj4,44338
|
|
6
6
|
crackerjack/dynamic_config.py,sha256=4c8Fts9vyH8Tdon_47OFVT1iTBINSzSgB0WoeSvpzII,22418
|
|
7
7
|
crackerjack/errors.py,sha256=yYbZ92kn_y6acEWgQvEPvozAYs2HT65uLwAXrtXxGsE,10049
|
|
8
8
|
crackerjack/interactive.py,sha256=t5FbxWeOErSl5kod4V8Gu5yF5yuWoZlwqlOdquOQ-vo,21943
|
|
9
|
+
crackerjack/py313.py,sha256=uLzXnII2N3Qng45lzb8-gMVe3z-U9dmT7V_BRV-zHJo,6192
|
|
9
10
|
crackerjack/adapters/__init__.py,sha256=k-8ajMDL9DS9hV2FYOu694nmNQg3HkudJRuNcXmx8N4,451
|
|
10
11
|
crackerjack/adapters/lsp_client.py,sha256=4kQ3T5JiWC7uc6kOjZuPdtUboseKSDjZpuKQpV74onc,10963
|
|
11
12
|
crackerjack/adapters/rust_tool_adapter.py,sha256=ui_qMt_WIwInRvRCeT7MnIdp8eln7Fvp4hakXQiVnjg,5999
|
|
@@ -69,7 +70,7 @@ crackerjack/documentation/mkdocs_integration.py,sha256=KqU2_9mA-rjP_VDrrfr6KTuPW
|
|
|
69
70
|
crackerjack/documentation/reference_generator.py,sha256=NGAIsC5bnjLBQkvEXPDU0pw8bQ5kYzbUUokhlXXFqrU,34520
|
|
70
71
|
crackerjack/executors/__init__.py,sha256=HF-DmXvKN45uKKDdiMxOT9bYxuy1B-Z91BihOhkK5lg,322
|
|
71
72
|
crackerjack/executors/async_hook_executor.py,sha256=FmKpiAxpZXKwvOWXnRQ73N-reDfX8NusESQ9a4HeacM,17620
|
|
72
|
-
crackerjack/executors/cached_hook_executor.py,sha256=
|
|
73
|
+
crackerjack/executors/cached_hook_executor.py,sha256=MwnHHBk6KJ_ovAJvAkVA-ad6D2cE0EgXNwy-NZQqB18,11172
|
|
73
74
|
crackerjack/executors/hook_executor.py,sha256=g53TXs5hOY0yRnSpyr44GgEmCRPMxHRgkfjtqBx_-4s,14479
|
|
74
75
|
crackerjack/executors/hook_lock_manager.py,sha256=ft24q6VFEkW_QrifNnSlrQeHGx9GuJeOOTsdlCcjnMI,26694
|
|
75
76
|
crackerjack/executors/individual_hook_executor.py,sha256=t0W9vuqLGPx0HmbTo01N9MRFyqLfY0ZLG06ZIA5qfBY,24362
|
|
@@ -142,7 +143,7 @@ crackerjack/monitoring/websocket_server.py,sha256=tmCYh5Qp58iicS_txj5OTdmt3I85M5
|
|
|
142
143
|
crackerjack/orchestration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
143
144
|
crackerjack/orchestration/advanced_orchestrator.py,sha256=05AZhCkPIiKSVVpIx7gb2_wVvGAKHv7gStu146ivcmY,32066
|
|
144
145
|
crackerjack/orchestration/coverage_improvement.py,sha256=XUTUcgub0nP3vvQ8Ud5SmCYKgulEe8SAY65jbcFQzdw,6869
|
|
145
|
-
crackerjack/orchestration/execution_strategies.py,sha256=
|
|
146
|
+
crackerjack/orchestration/execution_strategies.py,sha256=Iq5Q-dwC2GQ5E99kawqet031DnsrQCxSrqzTPnoWDbE,12476
|
|
146
147
|
crackerjack/orchestration/test_progress_streamer.py,sha256=Yu6uHuhoCvX6SZP0QNG3Yt8Q4s2tufEHr40o16QU98c,22541
|
|
147
148
|
crackerjack/plugins/__init__.py,sha256=B7hy9b9amJVbYLHgIz8kgTI29j-vYxsUY_sZ5ISbXU0,386
|
|
148
149
|
crackerjack/plugins/base.py,sha256=VFk-xNsgjSlmzJ_iPQALhkr7cguiOtEd3XSR9CcCPkc,5732
|
|
@@ -156,7 +157,7 @@ crackerjack/services/anomaly_detector.py,sha256=vUwhhGxNGarHQAly4GaN7kc5PBaBvlTf
|
|
|
156
157
|
crackerjack/services/api_extractor.py,sha256=iN4JDkvSyfHRNlhgV0Sf5B9cg4NVaCZn6p-zQlp9YGU,23836
|
|
157
158
|
crackerjack/services/backup_service.py,sha256=0e8AAo9svSBtbsbI9vwnAVSilB2fjph61lskgsUvDLk,15528
|
|
158
159
|
crackerjack/services/bounded_status_operations.py,sha256=mrBkUQwgtYjkbp-Y-5MdrU2A3rp3ZLVgOJv9vLdnJ8k,18763
|
|
159
|
-
crackerjack/services/cache.py,sha256=
|
|
160
|
+
crackerjack/services/cache.py,sha256=ZNpIHPoslMxgwfqzKJQQEqGUVlar22KGDQbydDuqx-M,14444
|
|
160
161
|
crackerjack/services/changelog_automation.py,sha256=KUeXCYLihRfLR0mUIRiI2aRQdCfe-45GnbB2gYNJJQE,14095
|
|
161
162
|
crackerjack/services/config.py,sha256=1gUQkcHPCGHVYSlx6mcrJlJLVIWhdaL7RjEmuy8_ev4,13704
|
|
162
163
|
crackerjack/services/config_integrity.py,sha256=Ac6-c7WuupsyrP2dxx_ijgjzpNnx9G0NWsXB-SZjelg,2904
|
|
@@ -225,8 +226,8 @@ crackerjack/tools/validate_input_validator_patterns.py,sha256=NN7smYlXWrHLQXTb-8
|
|
|
225
226
|
crackerjack/tools/validate_regex_patterns.py,sha256=J7GG9EP1fASpRIsG8qRPeiCSkdCwmk0sdo29GgoJ6w8,5863
|
|
226
227
|
crackerjack/ui/__init__.py,sha256=eMb1OeTU-dSLICAACn0YdYB4Amdr8wHckjKfn0wOIZE,37
|
|
227
228
|
crackerjack/ui/server_panels.py,sha256=F5IH6SNN06BaZQMsFx_D-OA286aojmaFPJ5kvvSRv_c,4232
|
|
228
|
-
crackerjack-0.38.
|
|
229
|
-
crackerjack-0.38.
|
|
230
|
-
crackerjack-0.38.
|
|
231
|
-
crackerjack-0.38.
|
|
232
|
-
crackerjack-0.38.
|
|
229
|
+
crackerjack-0.38.13.dist-info/METADATA,sha256=0Hn2s62A3z7OJwd0jlZ67DDRblFHWPSNXLbhYfWq9HE,38083
|
|
230
|
+
crackerjack-0.38.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
231
|
+
crackerjack-0.38.13.dist-info/entry_points.txt,sha256=AJKNft0WXm9xoGUJ3Trl-iXHOWxRAYbagQiza3AILr4,57
|
|
232
|
+
crackerjack-0.38.13.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
|
|
233
|
+
crackerjack-0.38.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|