crackerjack 0.31.18__py3-none-any.whl → 0.33.0__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/CLAUDE.md +71 -452
- crackerjack/__main__.py +1 -1
- crackerjack/agents/refactoring_agent.py +67 -46
- crackerjack/cli/handlers.py +7 -7
- crackerjack/config/hooks.py +36 -6
- crackerjack/core/async_workflow_orchestrator.py +2 -2
- crackerjack/core/enhanced_container.py +67 -0
- crackerjack/core/phase_coordinator.py +211 -44
- crackerjack/core/workflow_orchestrator.py +723 -72
- crackerjack/dynamic_config.py +1 -25
- crackerjack/managers/publish_manager.py +22 -5
- crackerjack/managers/test_command_builder.py +19 -13
- crackerjack/managers/test_manager.py +15 -4
- crackerjack/mcp/server_core.py +162 -34
- crackerjack/mcp/tools/core_tools.py +1 -1
- crackerjack/mcp/tools/execution_tools.py +16 -3
- crackerjack/mcp/tools/workflow_executor.py +130 -40
- crackerjack/mixins/__init__.py +5 -0
- crackerjack/mixins/error_handling.py +214 -0
- crackerjack/models/config.py +9 -0
- crackerjack/models/protocols.py +114 -0
- crackerjack/models/task.py +3 -0
- crackerjack/security/__init__.py +1 -0
- crackerjack/security/audit.py +226 -0
- crackerjack/services/config.py +3 -2
- crackerjack/services/config_merge.py +11 -5
- crackerjack/services/coverage_ratchet.py +22 -0
- crackerjack/services/git.py +121 -22
- crackerjack/services/initialization.py +25 -9
- crackerjack/services/memory_optimizer.py +477 -0
- crackerjack/services/parallel_executor.py +474 -0
- crackerjack/services/performance_benchmarks.py +292 -577
- crackerjack/services/performance_cache.py +443 -0
- crackerjack/services/performance_monitor.py +633 -0
- crackerjack/services/security.py +63 -0
- crackerjack/services/security_logger.py +9 -1
- crackerjack/services/terminal_utils.py +0 -0
- crackerjack/tools/validate_regex_patterns.py +14 -0
- {crackerjack-0.31.18.dist-info → crackerjack-0.33.0.dist-info}/METADATA +2 -2
- {crackerjack-0.31.18.dist-info → crackerjack-0.33.0.dist-info}/RECORD +43 -34
- {crackerjack-0.31.18.dist-info → crackerjack-0.33.0.dist-info}/WHEEL +0 -0
- {crackerjack-0.31.18.dist-info → crackerjack-0.33.0.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.31.18.dist-info → crackerjack-0.33.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -468,19 +468,16 @@ class RefactoringAgent(SubAgent):
|
|
|
468
468
|
|
|
469
469
|
def _apply_enhanced_complexity_patterns(self, content: str) -> str:
|
|
470
470
|
"""Apply enhanced complexity reduction patterns using SAFE_PATTERNS."""
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
modified_content = self._simplify_boolean_expressions(modified_content)
|
|
478
|
-
|
|
479
|
-
# Extract validation patterns to separate methods
|
|
480
|
-
modified_content = self._extract_validation_patterns(modified_content)
|
|
471
|
+
operations = [
|
|
472
|
+
self._extract_nested_conditions,
|
|
473
|
+
self._simplify_boolean_expressions,
|
|
474
|
+
self._extract_validation_patterns,
|
|
475
|
+
self._simplify_data_structures,
|
|
476
|
+
]
|
|
481
477
|
|
|
482
|
-
|
|
483
|
-
|
|
478
|
+
modified_content = content
|
|
479
|
+
for operation in operations:
|
|
480
|
+
modified_content = operation(modified_content)
|
|
484
481
|
|
|
485
482
|
return modified_content
|
|
486
483
|
|
|
@@ -897,13 +894,7 @@ class RefactoringAgent(SubAgent):
|
|
|
897
894
|
def _remove_dead_code_items(self, content: str, analysis: dict[str, t.Any]) -> str:
|
|
898
895
|
"""Enhanced removal of dead code items from content."""
|
|
899
896
|
lines = content.split("\n")
|
|
900
|
-
lines_to_remove = self.
|
|
901
|
-
|
|
902
|
-
# Also remove unreachable code blocks
|
|
903
|
-
lines_to_remove.update(self._find_unreachable_lines(lines, analysis))
|
|
904
|
-
|
|
905
|
-
# Remove redundant code patterns
|
|
906
|
-
lines_to_remove.update(self._find_redundant_lines(lines, analysis))
|
|
897
|
+
lines_to_remove = self._collect_all_removable_lines(lines, analysis)
|
|
907
898
|
|
|
908
899
|
filtered_lines = [
|
|
909
900
|
line for i, line in enumerate(lines) if i not in lines_to_remove
|
|
@@ -911,6 +902,22 @@ class RefactoringAgent(SubAgent):
|
|
|
911
902
|
|
|
912
903
|
return "\n".join(filtered_lines)
|
|
913
904
|
|
|
905
|
+
def _collect_all_removable_lines(
|
|
906
|
+
self, lines: list[str], analysis: dict[str, t.Any]
|
|
907
|
+
) -> set[int]:
|
|
908
|
+
"""Collect all line indices that should be removed."""
|
|
909
|
+
removal_functions = [
|
|
910
|
+
lambda: self._find_lines_to_remove(lines, analysis),
|
|
911
|
+
lambda: self._find_unreachable_lines(lines, analysis),
|
|
912
|
+
lambda: self._find_redundant_lines(lines, analysis),
|
|
913
|
+
]
|
|
914
|
+
|
|
915
|
+
lines_to_remove: set[int] = set()
|
|
916
|
+
for removal_func in removal_functions:
|
|
917
|
+
lines_to_remove.update(removal_func())
|
|
918
|
+
|
|
919
|
+
return lines_to_remove
|
|
920
|
+
|
|
914
921
|
def _find_unreachable_lines(
|
|
915
922
|
self, lines: list[str], analysis: dict[str, t.Any]
|
|
916
923
|
) -> set[int]:
|
|
@@ -933,21 +940,30 @@ class RefactoringAgent(SubAgent):
|
|
|
933
940
|
lines_to_remove: set[int] = set()
|
|
934
941
|
|
|
935
942
|
# Look for empty except blocks
|
|
936
|
-
for i
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
next_line = lines[j].strip()
|
|
942
|
-
if not next_line:
|
|
943
|
-
continue
|
|
944
|
-
if next_line == "pass":
|
|
945
|
-
lines_to_remove.add(j)
|
|
946
|
-
break
|
|
947
|
-
break
|
|
943
|
+
for i in range(len(lines)):
|
|
944
|
+
if self._is_empty_except_block(lines, i):
|
|
945
|
+
empty_pass_idx = self._find_empty_pass_line(lines, i)
|
|
946
|
+
if empty_pass_idx is not None:
|
|
947
|
+
lines_to_remove.add(empty_pass_idx)
|
|
948
948
|
|
|
949
949
|
return lines_to_remove
|
|
950
950
|
|
|
951
|
+
def _is_empty_except_block(self, lines: list[str], line_idx: int) -> bool:
|
|
952
|
+
"""Check if line is an empty except block."""
|
|
953
|
+
stripped = lines[line_idx].strip()
|
|
954
|
+
return stripped == "except:" or stripped.startswith("except ")
|
|
955
|
+
|
|
956
|
+
def _find_empty_pass_line(self, lines: list[str], except_idx: int) -> int | None:
|
|
957
|
+
"""Find the pass line in an empty except block."""
|
|
958
|
+
for j in range(except_idx + 1, min(except_idx + 5, len(lines))):
|
|
959
|
+
next_line = lines[j].strip()
|
|
960
|
+
if not next_line:
|
|
961
|
+
continue
|
|
962
|
+
if next_line == "pass":
|
|
963
|
+
return j
|
|
964
|
+
break
|
|
965
|
+
return None
|
|
966
|
+
|
|
951
967
|
def _extract_function_content(
|
|
952
968
|
self, lines: list[str], func_info: dict[str, t.Any]
|
|
953
969
|
) -> str:
|
|
@@ -968,30 +984,35 @@ class RefactoringAgent(SubAgent):
|
|
|
968
984
|
) -> str:
|
|
969
985
|
"""Apply function extraction by replacing original with calls to helpers."""
|
|
970
986
|
lines = content.split("\n")
|
|
971
|
-
validation_result = self._validate_extraction_params(
|
|
972
|
-
lines, func_info, extracted_helpers
|
|
973
|
-
)
|
|
974
|
-
if validation_result:
|
|
975
|
-
return validation_result
|
|
976
987
|
|
|
977
|
-
|
|
978
|
-
lines
|
|
979
|
-
|
|
980
|
-
return self.
|
|
988
|
+
if not self._is_extraction_valid(lines, func_info, extracted_helpers):
|
|
989
|
+
return "\n".join(lines)
|
|
990
|
+
|
|
991
|
+
return self._perform_extraction(lines, func_info, extracted_helpers)
|
|
981
992
|
|
|
982
|
-
def
|
|
993
|
+
def _is_extraction_valid(
|
|
983
994
|
self,
|
|
984
995
|
lines: list[str],
|
|
985
996
|
func_info: dict[str, t.Any],
|
|
986
997
|
extracted_helpers: list[dict[str, str]],
|
|
987
|
-
) ->
|
|
988
|
-
"""
|
|
998
|
+
) -> bool:
|
|
999
|
+
"""Check if extraction parameters are valid."""
|
|
989
1000
|
start_line = func_info["line_start"] - 1
|
|
990
1001
|
end_line = func_info.get("line_end", len(lines)) - 1
|
|
991
1002
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1003
|
+
return bool(extracted_helpers) and start_line >= 0 and end_line < len(lines)
|
|
1004
|
+
|
|
1005
|
+
def _perform_extraction(
|
|
1006
|
+
self,
|
|
1007
|
+
lines: list[str],
|
|
1008
|
+
func_info: dict[str, t.Any],
|
|
1009
|
+
extracted_helpers: list[dict[str, str]],
|
|
1010
|
+
) -> str:
|
|
1011
|
+
"""Perform the actual function extraction."""
|
|
1012
|
+
new_lines = self._replace_function_with_calls(
|
|
1013
|
+
lines, func_info, extracted_helpers
|
|
1014
|
+
)
|
|
1015
|
+
return self._add_helper_definitions(new_lines, func_info, extracted_helpers)
|
|
995
1016
|
|
|
996
1017
|
def _replace_function_with_calls(
|
|
997
1018
|
self,
|
crackerjack/cli/handlers.py
CHANGED
|
@@ -8,19 +8,19 @@ from rich.console import Console
|
|
|
8
8
|
from .options import Options
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def setup_ai_agent_env(ai_agent: bool,
|
|
12
|
-
#
|
|
13
|
-
if
|
|
11
|
+
def setup_ai_agent_env(ai_agent: bool, debug_mode: bool = False) -> None:
|
|
12
|
+
# Only set debug environment variable if debug mode is explicitly enabled
|
|
13
|
+
if debug_mode:
|
|
14
14
|
os.environ["CRACKERJACK_DEBUG"] = "1"
|
|
15
15
|
|
|
16
16
|
if ai_agent:
|
|
17
17
|
os.environ["AI_AGENT"] = "1"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
# Only enable AI agent debug if debug mode is explicitly requested
|
|
19
|
+
if debug_mode:
|
|
20
|
+
os.environ["AI_AGENT_DEBUG"] = "1"
|
|
21
21
|
os.environ["AI_AGENT_VERBOSE"] = "1"
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
# Show debug configuration when debug mode is enabled
|
|
24
24
|
console = Console()
|
|
25
25
|
console.print(
|
|
26
26
|
"[bold cyan]🐛 AI Agent Debug Mode Configuration: [/ bold cyan]",
|
crackerjack/config/hooks.py
CHANGED
|
@@ -14,6 +14,17 @@ class RetryPolicy(Enum):
|
|
|
14
14
|
ALL_HOOKS = "all_hooks"
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
class SecurityLevel(Enum):
|
|
18
|
+
"""Security classification for hooks - determines bypass behavior."""
|
|
19
|
+
|
|
20
|
+
CRITICAL = (
|
|
21
|
+
"critical" # Cannot be bypassed for publishing (security scans, type safety)
|
|
22
|
+
)
|
|
23
|
+
HIGH = "high" # Important but can be bypassed with warning
|
|
24
|
+
MEDIUM = "medium" # Standard checks, bypassable
|
|
25
|
+
LOW = "low" # Formatting/style, always bypassable
|
|
26
|
+
|
|
27
|
+
|
|
17
28
|
@dataclass
|
|
18
29
|
class HookDefinition:
|
|
19
30
|
name: str
|
|
@@ -24,6 +35,7 @@ class HookDefinition:
|
|
|
24
35
|
is_formatting: bool = False
|
|
25
36
|
manual_stage: bool = False
|
|
26
37
|
config_path: Path | None = None
|
|
38
|
+
security_level: SecurityLevel = SecurityLevel.MEDIUM # Default security level
|
|
27
39
|
|
|
28
40
|
def get_command(self) -> list[str]:
|
|
29
41
|
# Use direct pre-commit execution (pre-commit manages its own environments)
|
|
@@ -66,60 +78,72 @@ FAST_HOOKS = [
|
|
|
66
78
|
is_formatting=True, # Treat as formatting for autofix purposes
|
|
67
79
|
timeout=30,
|
|
68
80
|
retry_on_failure=True, # Enable retries for autofix
|
|
81
|
+
security_level=SecurityLevel.HIGH, # Regex vulnerabilities are security-relevant
|
|
69
82
|
),
|
|
70
83
|
HookDefinition(
|
|
71
84
|
name="trailing-whitespace",
|
|
72
85
|
command=[], # Dynamically built by get_command()
|
|
73
86
|
is_formatting=True,
|
|
74
87
|
retry_on_failure=True,
|
|
88
|
+
security_level=SecurityLevel.LOW, # Whitespace formatting, always bypassable
|
|
75
89
|
),
|
|
76
90
|
HookDefinition(
|
|
77
91
|
name="end-of-file-fixer",
|
|
78
92
|
command=[], # Dynamically built by get_command()
|
|
79
93
|
is_formatting=True,
|
|
80
94
|
retry_on_failure=True,
|
|
95
|
+
security_level=SecurityLevel.LOW, # File formatting, always bypassable
|
|
81
96
|
),
|
|
82
97
|
HookDefinition(
|
|
83
98
|
name="check-yaml",
|
|
84
99
|
command=[], # Dynamically built by get_command()
|
|
100
|
+
security_level=SecurityLevel.MEDIUM, # File validation, standard check
|
|
85
101
|
),
|
|
86
102
|
HookDefinition(
|
|
87
103
|
name="check-toml",
|
|
88
104
|
command=[], # Dynamically built by get_command()
|
|
105
|
+
security_level=SecurityLevel.MEDIUM, # File validation, standard check
|
|
89
106
|
),
|
|
90
107
|
HookDefinition(
|
|
91
108
|
name="check-added-large-files",
|
|
92
109
|
command=[], # Dynamically built by get_command()
|
|
110
|
+
security_level=SecurityLevel.HIGH, # Large files can be security risk
|
|
93
111
|
),
|
|
94
112
|
HookDefinition(
|
|
95
113
|
name="uv-lock",
|
|
96
114
|
command=[], # Dynamically built by get_command()
|
|
115
|
+
security_level=SecurityLevel.HIGH, # Dependency locking is security-relevant
|
|
97
116
|
),
|
|
98
117
|
HookDefinition(
|
|
99
118
|
name="gitleaks",
|
|
100
119
|
command=[], # Dynamically built by get_command()
|
|
120
|
+
security_level=SecurityLevel.CRITICAL, # Secret detection is critical for security
|
|
101
121
|
),
|
|
102
122
|
HookDefinition(
|
|
103
123
|
name="codespell",
|
|
104
124
|
command=[], # Dynamically built by get_command()
|
|
125
|
+
security_level=SecurityLevel.LOW, # Spelling, not security-critical
|
|
105
126
|
),
|
|
106
127
|
HookDefinition(
|
|
107
128
|
name="ruff-check",
|
|
108
129
|
command=[], # Dynamically built by get_command()
|
|
109
130
|
is_formatting=True, # Treat as formatting for autofix purposes
|
|
110
131
|
retry_on_failure=True, # Enable retries for autofix
|
|
132
|
+
security_level=SecurityLevel.MEDIUM, # Code quality, not directly security
|
|
111
133
|
),
|
|
112
134
|
HookDefinition(
|
|
113
135
|
name="ruff-format",
|
|
114
136
|
command=[], # Dynamically built by get_command()
|
|
115
137
|
is_formatting=True,
|
|
116
138
|
retry_on_failure=True,
|
|
139
|
+
security_level=SecurityLevel.LOW, # Pure formatting, always bypassable
|
|
117
140
|
),
|
|
118
141
|
HookDefinition(
|
|
119
142
|
name="mdformat",
|
|
120
143
|
command=[], # Dynamically built by get_command()
|
|
121
144
|
is_formatting=True,
|
|
122
145
|
retry_on_failure=True,
|
|
146
|
+
security_level=SecurityLevel.LOW, # Documentation formatting, always bypassable
|
|
123
147
|
),
|
|
124
148
|
]
|
|
125
149
|
|
|
@@ -127,37 +151,42 @@ COMPREHENSIVE_HOOKS = [
|
|
|
127
151
|
HookDefinition(
|
|
128
152
|
name="pyright",
|
|
129
153
|
command=[], # Dynamically built by get_command()
|
|
130
|
-
timeout=
|
|
154
|
+
timeout=300, # Fixed: Use 300s to match pytest config
|
|
131
155
|
stage=HookStage.COMPREHENSIVE,
|
|
132
156
|
manual_stage=True,
|
|
157
|
+
security_level=SecurityLevel.CRITICAL, # Type safety prevents security holes
|
|
133
158
|
),
|
|
134
159
|
HookDefinition(
|
|
135
160
|
name="bandit",
|
|
136
161
|
command=[], # Dynamically built by get_command()
|
|
137
|
-
timeout=
|
|
162
|
+
timeout=300, # Fixed: Use 300s to match pytest config
|
|
138
163
|
stage=HookStage.COMPREHENSIVE,
|
|
139
164
|
manual_stage=True,
|
|
165
|
+
security_level=SecurityLevel.CRITICAL, # Security vulnerability scanning
|
|
140
166
|
),
|
|
141
167
|
HookDefinition(
|
|
142
168
|
name="vulture",
|
|
143
169
|
command=[], # Dynamically built by get_command()
|
|
144
|
-
timeout=
|
|
170
|
+
timeout=300, # Fixed: Use 300s to match pytest config
|
|
145
171
|
stage=HookStage.COMPREHENSIVE,
|
|
146
172
|
manual_stage=True,
|
|
173
|
+
security_level=SecurityLevel.MEDIUM, # Dead code removal, not critical for security
|
|
147
174
|
),
|
|
148
175
|
HookDefinition(
|
|
149
176
|
name="refurb",
|
|
150
177
|
command=[], # Dynamically built by get_command()
|
|
151
|
-
timeout=
|
|
178
|
+
timeout=300, # Fixed: Use 300s to match pytest config
|
|
152
179
|
stage=HookStage.COMPREHENSIVE,
|
|
153
180
|
manual_stage=True,
|
|
181
|
+
security_level=SecurityLevel.MEDIUM, # Code quality, not directly security
|
|
154
182
|
),
|
|
155
183
|
HookDefinition(
|
|
156
184
|
name="creosote",
|
|
157
185
|
command=[], # Dynamically built by get_command()
|
|
158
|
-
timeout=
|
|
186
|
+
timeout=300, # Fixed: Use 300s to match pytest config
|
|
159
187
|
stage=HookStage.COMPREHENSIVE,
|
|
160
188
|
manual_stage=True,
|
|
189
|
+
security_level=SecurityLevel.HIGH, # Dependency analysis, security-relevant
|
|
161
190
|
),
|
|
162
191
|
HookDefinition(
|
|
163
192
|
name="complexipy",
|
|
@@ -165,6 +194,7 @@ COMPREHENSIVE_HOOKS = [
|
|
|
165
194
|
timeout=60,
|
|
166
195
|
stage=HookStage.COMPREHENSIVE,
|
|
167
196
|
manual_stage=True,
|
|
197
|
+
security_level=SecurityLevel.MEDIUM, # Complexity analysis, not directly security
|
|
168
198
|
),
|
|
169
199
|
]
|
|
170
200
|
|
|
@@ -179,7 +209,7 @@ FAST_STRATEGY = HookStrategy(
|
|
|
179
209
|
COMPREHENSIVE_STRATEGY = HookStrategy(
|
|
180
210
|
name="comprehensive",
|
|
181
211
|
hooks=COMPREHENSIVE_HOOKS,
|
|
182
|
-
timeout=
|
|
212
|
+
timeout=300, # Fixed: Use 300s to match pytest config
|
|
183
213
|
retry_policy=RetryPolicy.NONE,
|
|
184
214
|
)
|
|
185
215
|
|
|
@@ -676,8 +676,8 @@ class AsyncWorkflowOrchestrator:
|
|
|
676
676
|
session_id = getattr(self, "web_job_id", None) or str(int(time.time()))[:8]
|
|
677
677
|
debug_log_file = log_manager.create_debug_log_file(session_id)
|
|
678
678
|
|
|
679
|
-
# Set log level based on
|
|
680
|
-
log_level = "DEBUG" if
|
|
679
|
+
# Set log level based on debug flag only - verbose should not enable DEBUG logs
|
|
680
|
+
log_level = "DEBUG" if self.debug else "INFO"
|
|
681
681
|
setup_structured_logging(
|
|
682
682
|
level=log_level, json_output=False, log_file=debug_log_file
|
|
683
683
|
)
|
|
@@ -11,11 +11,16 @@ from rich.console import Console
|
|
|
11
11
|
|
|
12
12
|
from crackerjack.models.protocols import (
|
|
13
13
|
ConfigMergeServiceProtocol,
|
|
14
|
+
ConfigurationServiceProtocol,
|
|
15
|
+
CoverageRatchetProtocol,
|
|
14
16
|
FileSystemInterface,
|
|
15
17
|
GitInterface,
|
|
16
18
|
HookManager,
|
|
19
|
+
InitializationServiceProtocol,
|
|
17
20
|
PublishManager,
|
|
21
|
+
SecurityServiceProtocol,
|
|
18
22
|
TestManagerProtocol,
|
|
23
|
+
UnifiedConfigurationServiceProtocol,
|
|
19
24
|
)
|
|
20
25
|
from crackerjack.services.logging import get_logger
|
|
21
26
|
|
|
@@ -470,17 +475,79 @@ class ServiceCollectionBuilder:
|
|
|
470
475
|
|
|
471
476
|
return self
|
|
472
477
|
|
|
478
|
+
def add_service_protocols(self) -> "ServiceCollectionBuilder":
|
|
479
|
+
"""Add registrations for service protocols that don't have explicit builders."""
|
|
480
|
+
console = self.console or Console(force_terminal=True)
|
|
481
|
+
pkg_path = self.pkg_path or Path.cwd()
|
|
482
|
+
|
|
483
|
+
# Register CoverageRatchetProtocol
|
|
484
|
+
def create_coverage_ratchet() -> CoverageRatchetProtocol:
|
|
485
|
+
from crackerjack.services.coverage_ratchet import CoverageRatchetService
|
|
486
|
+
|
|
487
|
+
return CoverageRatchetService(pkg_path, console)
|
|
488
|
+
|
|
489
|
+
self.container.register_transient(
|
|
490
|
+
CoverageRatchetProtocol,
|
|
491
|
+
factory=create_coverage_ratchet,
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
# Register ConfigurationServiceProtocol
|
|
495
|
+
def create_configuration_service() -> ConfigurationServiceProtocol:
|
|
496
|
+
from crackerjack.services.config import ConfigurationService
|
|
497
|
+
|
|
498
|
+
return ConfigurationService(console=console, pkg_path=pkg_path)
|
|
499
|
+
|
|
500
|
+
self.container.register_transient(
|
|
501
|
+
ConfigurationServiceProtocol,
|
|
502
|
+
factory=create_configuration_service,
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
# Register SecurityServiceProtocol
|
|
506
|
+
def create_security_service() -> SecurityServiceProtocol:
|
|
507
|
+
from crackerjack.services.security import SecurityService
|
|
508
|
+
|
|
509
|
+
return SecurityService()
|
|
510
|
+
|
|
511
|
+
self.container.register_transient(
|
|
512
|
+
SecurityServiceProtocol,
|
|
513
|
+
factory=create_security_service,
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
# Register InitializationServiceProtocol
|
|
517
|
+
def create_initialization_service() -> InitializationServiceProtocol:
|
|
518
|
+
from crackerjack.services.filesystem import FileSystemService
|
|
519
|
+
from crackerjack.services.git import GitService
|
|
520
|
+
from crackerjack.services.initialization import InitializationService
|
|
521
|
+
|
|
522
|
+
filesystem = FileSystemService()
|
|
523
|
+
git_service = GitService(console, pkg_path)
|
|
524
|
+
return InitializationService(console, filesystem, git_service, pkg_path)
|
|
525
|
+
|
|
526
|
+
self.container.register_transient(
|
|
527
|
+
InitializationServiceProtocol,
|
|
528
|
+
factory=create_initialization_service,
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
return self
|
|
532
|
+
|
|
473
533
|
def add_configuration_services(self) -> "ServiceCollectionBuilder":
|
|
474
534
|
console = self.console or Console(force_terminal=True)
|
|
475
535
|
pkg_path = self.pkg_path or Path.cwd()
|
|
476
536
|
|
|
477
537
|
from crackerjack.services.unified_config import UnifiedConfigurationService
|
|
478
538
|
|
|
539
|
+
# Register concrete class for backwards compatibility
|
|
479
540
|
self.container.register_singleton(
|
|
480
541
|
UnifiedConfigurationService,
|
|
481
542
|
factory=lambda: UnifiedConfigurationService(console, pkg_path),
|
|
482
543
|
)
|
|
483
544
|
|
|
545
|
+
# Register protocol interface
|
|
546
|
+
self.container.register_singleton(
|
|
547
|
+
UnifiedConfigurationServiceProtocol,
|
|
548
|
+
factory=lambda: self.container.get(UnifiedConfigurationService),
|
|
549
|
+
)
|
|
550
|
+
|
|
484
551
|
# Register ConfigMergeService for smart configuration merging
|
|
485
552
|
from crackerjack.services.config_merge import ConfigMergeService
|
|
486
553
|
|