crackerjack 0.31.10__py3-none-any.whl → 0.31.12__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 +288 -705
- crackerjack/__main__.py +22 -8
- crackerjack/agents/__init__.py +0 -3
- crackerjack/agents/architect_agent.py +0 -43
- crackerjack/agents/base.py +1 -9
- crackerjack/agents/coordinator.py +2 -148
- crackerjack/agents/documentation_agent.py +109 -81
- crackerjack/agents/dry_agent.py +122 -97
- crackerjack/agents/formatting_agent.py +3 -16
- crackerjack/agents/import_optimization_agent.py +1174 -130
- crackerjack/agents/performance_agent.py +956 -188
- crackerjack/agents/performance_helpers.py +229 -0
- crackerjack/agents/proactive_agent.py +1 -48
- crackerjack/agents/refactoring_agent.py +516 -246
- crackerjack/agents/refactoring_helpers.py +282 -0
- crackerjack/agents/security_agent.py +393 -90
- crackerjack/agents/test_creation_agent.py +1776 -120
- crackerjack/agents/test_specialist_agent.py +59 -15
- crackerjack/agents/tracker.py +0 -102
- crackerjack/api.py +145 -37
- crackerjack/cli/handlers.py +48 -30
- crackerjack/cli/interactive.py +11 -11
- crackerjack/cli/options.py +66 -4
- crackerjack/code_cleaner.py +808 -148
- crackerjack/config/global_lock_config.py +110 -0
- crackerjack/config/hooks.py +43 -64
- crackerjack/core/async_workflow_orchestrator.py +247 -97
- crackerjack/core/autofix_coordinator.py +192 -109
- crackerjack/core/enhanced_container.py +46 -63
- crackerjack/core/file_lifecycle.py +549 -0
- crackerjack/core/performance.py +9 -8
- crackerjack/core/performance_monitor.py +395 -0
- crackerjack/core/phase_coordinator.py +281 -94
- crackerjack/core/proactive_workflow.py +9 -58
- crackerjack/core/resource_manager.py +501 -0
- crackerjack/core/service_watchdog.py +490 -0
- crackerjack/core/session_coordinator.py +4 -8
- crackerjack/core/timeout_manager.py +504 -0
- crackerjack/core/websocket_lifecycle.py +475 -0
- crackerjack/core/workflow_orchestrator.py +343 -209
- crackerjack/dynamic_config.py +47 -6
- crackerjack/errors.py +3 -4
- crackerjack/executors/async_hook_executor.py +63 -13
- crackerjack/executors/cached_hook_executor.py +14 -14
- crackerjack/executors/hook_executor.py +100 -37
- crackerjack/executors/hook_lock_manager.py +856 -0
- crackerjack/executors/individual_hook_executor.py +120 -86
- crackerjack/intelligence/__init__.py +0 -7
- crackerjack/intelligence/adaptive_learning.py +13 -86
- crackerjack/intelligence/agent_orchestrator.py +15 -78
- crackerjack/intelligence/agent_registry.py +12 -59
- crackerjack/intelligence/agent_selector.py +31 -92
- crackerjack/intelligence/integration.py +1 -41
- crackerjack/interactive.py +9 -9
- crackerjack/managers/async_hook_manager.py +25 -8
- crackerjack/managers/hook_manager.py +9 -9
- crackerjack/managers/publish_manager.py +57 -59
- crackerjack/managers/test_command_builder.py +6 -36
- crackerjack/managers/test_executor.py +9 -61
- crackerjack/managers/test_manager.py +17 -63
- crackerjack/managers/test_manager_backup.py +77 -127
- crackerjack/managers/test_progress.py +4 -23
- crackerjack/mcp/cache.py +5 -12
- crackerjack/mcp/client_runner.py +10 -10
- crackerjack/mcp/context.py +64 -6
- crackerjack/mcp/dashboard.py +14 -11
- crackerjack/mcp/enhanced_progress_monitor.py +55 -55
- crackerjack/mcp/file_monitor.py +72 -42
- crackerjack/mcp/progress_components.py +103 -84
- crackerjack/mcp/progress_monitor.py +122 -49
- crackerjack/mcp/rate_limiter.py +12 -12
- crackerjack/mcp/server_core.py +16 -22
- crackerjack/mcp/service_watchdog.py +26 -26
- crackerjack/mcp/state.py +15 -0
- crackerjack/mcp/tools/core_tools.py +95 -39
- crackerjack/mcp/tools/error_analyzer.py +6 -32
- crackerjack/mcp/tools/execution_tools.py +1 -56
- crackerjack/mcp/tools/execution_tools_backup.py +35 -131
- crackerjack/mcp/tools/intelligence_tool_registry.py +0 -36
- crackerjack/mcp/tools/intelligence_tools.py +2 -55
- crackerjack/mcp/tools/monitoring_tools.py +308 -145
- crackerjack/mcp/tools/proactive_tools.py +12 -42
- crackerjack/mcp/tools/progress_tools.py +23 -15
- crackerjack/mcp/tools/utility_tools.py +3 -40
- crackerjack/mcp/tools/workflow_executor.py +40 -60
- crackerjack/mcp/websocket/app.py +0 -3
- crackerjack/mcp/websocket/endpoints.py +206 -268
- crackerjack/mcp/websocket/jobs.py +213 -66
- crackerjack/mcp/websocket/server.py +84 -6
- crackerjack/mcp/websocket/websocket_handler.py +137 -29
- crackerjack/models/config_adapter.py +3 -16
- crackerjack/models/protocols.py +162 -3
- crackerjack/models/resource_protocols.py +454 -0
- crackerjack/models/task.py +3 -3
- crackerjack/monitoring/__init__.py +0 -0
- crackerjack/monitoring/ai_agent_watchdog.py +25 -71
- crackerjack/monitoring/regression_prevention.py +28 -87
- crackerjack/orchestration/advanced_orchestrator.py +44 -78
- crackerjack/orchestration/coverage_improvement.py +10 -60
- crackerjack/orchestration/execution_strategies.py +16 -16
- crackerjack/orchestration/test_progress_streamer.py +61 -53
- crackerjack/plugins/base.py +1 -1
- crackerjack/plugins/managers.py +22 -20
- crackerjack/py313.py +65 -21
- crackerjack/services/backup_service.py +467 -0
- crackerjack/services/bounded_status_operations.py +627 -0
- crackerjack/services/cache.py +7 -9
- crackerjack/services/config.py +35 -52
- crackerjack/services/config_integrity.py +5 -16
- crackerjack/services/config_merge.py +542 -0
- crackerjack/services/contextual_ai_assistant.py +17 -19
- crackerjack/services/coverage_ratchet.py +44 -73
- crackerjack/services/debug.py +25 -39
- crackerjack/services/dependency_monitor.py +52 -50
- crackerjack/services/enhanced_filesystem.py +14 -11
- crackerjack/services/file_hasher.py +1 -1
- crackerjack/services/filesystem.py +1 -12
- crackerjack/services/git.py +71 -47
- crackerjack/services/health_metrics.py +31 -27
- crackerjack/services/initialization.py +276 -428
- crackerjack/services/input_validator.py +760 -0
- crackerjack/services/log_manager.py +16 -16
- crackerjack/services/logging.py +7 -6
- crackerjack/services/metrics.py +43 -43
- crackerjack/services/pattern_cache.py +2 -31
- crackerjack/services/pattern_detector.py +26 -63
- crackerjack/services/performance_benchmarks.py +20 -45
- crackerjack/services/regex_patterns.py +2887 -0
- crackerjack/services/regex_utils.py +537 -0
- crackerjack/services/secure_path_utils.py +683 -0
- crackerjack/services/secure_status_formatter.py +534 -0
- crackerjack/services/secure_subprocess.py +605 -0
- crackerjack/services/security.py +47 -10
- crackerjack/services/security_logger.py +492 -0
- crackerjack/services/server_manager.py +109 -50
- crackerjack/services/smart_scheduling.py +8 -25
- crackerjack/services/status_authentication.py +603 -0
- crackerjack/services/status_security_manager.py +442 -0
- crackerjack/services/thread_safe_status_collector.py +546 -0
- crackerjack/services/tool_version_service.py +1 -23
- crackerjack/services/unified_config.py +36 -58
- crackerjack/services/validation_rate_limiter.py +269 -0
- crackerjack/services/version_checker.py +9 -40
- crackerjack/services/websocket_resource_limiter.py +572 -0
- crackerjack/slash_commands/__init__.py +52 -2
- crackerjack/tools/__init__.py +0 -0
- crackerjack/tools/validate_input_validator_patterns.py +262 -0
- crackerjack/tools/validate_regex_patterns.py +198 -0
- {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/METADATA +197 -12
- crackerjack-0.31.12.dist-info/RECORD +178 -0
- crackerjack/cli/facade.py +0 -104
- crackerjack-0.31.10.dist-info/RECORD +0 -149
- {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/WHEEL +0 -0
- {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.31.10.dist-info → crackerjack-0.31.12.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import typing as t
|
|
2
2
|
|
|
3
|
-
# Helper functions for creating responses and assessments
|
|
4
|
-
|
|
5
3
|
|
|
6
4
|
def _create_architectural_assessment(args: str, parsed_kwargs: dict) -> dict:
|
|
7
|
-
"""Create architectural assessment with recommendations."""
|
|
8
5
|
assessment = {
|
|
9
6
|
"feature": parsed_kwargs.get("feature", "unknown"),
|
|
10
7
|
"complexity": parsed_kwargs.get("complexity", "medium"),
|
|
@@ -14,23 +11,21 @@ def _create_architectural_assessment(args: str, parsed_kwargs: dict) -> dict:
|
|
|
14
11
|
|
|
15
12
|
recommendations = []
|
|
16
13
|
|
|
17
|
-
# Always recommend crackerjack-architect for planning
|
|
18
14
|
recommendations.append(
|
|
19
15
|
{
|
|
20
16
|
"agent": "crackerjack-architect",
|
|
21
17
|
"priority": "high",
|
|
22
18
|
"reason": "Expert architectural planning for crackerjack compliance",
|
|
23
|
-
"action": 'Task tool with subagent_type="crackerjack-architect" for feature planning and architecture',
|
|
19
|
+
"action": 'Task tool with subagent_type ="crackerjack-architect" for feature planning and architecture',
|
|
24
20
|
"benefits": [
|
|
25
21
|
"Prevents violations through proper initial architecture",
|
|
26
22
|
"Applies crackerjack patterns from the start",
|
|
27
|
-
"Reduces iteration cycles by 50
|
|
23
|
+
"Reduces iteration cycles by 50 % +",
|
|
28
24
|
"Ensures consistency with project standards",
|
|
29
25
|
],
|
|
30
26
|
}
|
|
31
27
|
)
|
|
32
28
|
|
|
33
|
-
# Add complexity-specific recommendations
|
|
34
29
|
complexity = parsed_kwargs.get("complexity", "medium")
|
|
35
30
|
if complexity in ("high", "complex"):
|
|
36
31
|
recommendations.append(
|
|
@@ -38,11 +33,10 @@ def _create_architectural_assessment(args: str, parsed_kwargs: dict) -> dict:
|
|
|
38
33
|
"agent": "refactoring-specialist",
|
|
39
34
|
"priority": "high",
|
|
40
35
|
"reason": "Complex features require careful structural planning",
|
|
41
|
-
"action": 'Task tool with subagent_type="refactoring-specialist" for complexity management',
|
|
36
|
+
"action": 'Task tool with subagent_type ="refactoring-specialist" for complexity management',
|
|
42
37
|
}
|
|
43
38
|
)
|
|
44
39
|
|
|
45
|
-
# Add security recommendations for certain features
|
|
46
40
|
feature = parsed_kwargs.get("feature", "")
|
|
47
41
|
if any(
|
|
48
42
|
keyword in feature.lower() for keyword in ("auth", "security", "api", "data")
|
|
@@ -52,7 +46,7 @@ def _create_architectural_assessment(args: str, parsed_kwargs: dict) -> dict:
|
|
|
52
46
|
"agent": "security-auditor",
|
|
53
47
|
"priority": "medium",
|
|
54
48
|
"reason": "Security-sensitive feature requires expert review",
|
|
55
|
-
"action": 'Task tool with subagent_type="security-auditor" for security validation',
|
|
49
|
+
"action": 'Task tool with subagent_type ="security-auditor" for security validation',
|
|
56
50
|
}
|
|
57
51
|
)
|
|
58
52
|
|
|
@@ -63,7 +57,6 @@ def _create_architectural_assessment(args: str, parsed_kwargs: dict) -> dict:
|
|
|
63
57
|
|
|
64
58
|
|
|
65
59
|
def _create_validation_results(file_path: str) -> dict:
|
|
66
|
-
"""Create validation results for architectural compliance."""
|
|
67
60
|
validation = {
|
|
68
61
|
"file_path": file_path,
|
|
69
62
|
"validation_results": [],
|
|
@@ -71,12 +64,11 @@ def _create_validation_results(file_path: str) -> dict:
|
|
|
71
64
|
"recommendations": [],
|
|
72
65
|
}
|
|
73
66
|
|
|
74
|
-
# Check for crackerjack compliance patterns
|
|
75
67
|
compliance_checks = [
|
|
76
68
|
{
|
|
77
69
|
"check": "complexity_compliance",
|
|
78
70
|
"status": "requires_analysis",
|
|
79
|
-
"message": "Cognitive complexity should be ≤
|
|
71
|
+
"message": "Cognitive complexity should be ≤15 per function",
|
|
80
72
|
"tool": "complexipy",
|
|
81
73
|
},
|
|
82
74
|
{
|
|
@@ -105,16 +97,15 @@ def _create_validation_results(file_path: str) -> dict:
|
|
|
105
97
|
|
|
106
98
|
validation["validation_results"] = compliance_checks
|
|
107
99
|
|
|
108
|
-
# Add proactive recommendations
|
|
109
100
|
validation["recommendations"] = [
|
|
110
|
-
"Run full crackerjack quality process: python -m crackerjack
|
|
101
|
+
"Run full crackerjack quality process: python - m crackerjack-t",
|
|
111
102
|
"Use crackerjack-architect for complex refactoring decisions",
|
|
112
103
|
"Apply pattern learning from successful fixes",
|
|
113
104
|
"Validate against architectural plan before committing",
|
|
114
105
|
]
|
|
115
106
|
|
|
116
107
|
validation["next_steps"] = [
|
|
117
|
-
'Task tool with subagent_type="crackerjack-architect" for architectural guidance',
|
|
108
|
+
'Task tool with subagent_type ="crackerjack-architect" for architectural guidance',
|
|
118
109
|
"Run comprehensive quality checks",
|
|
119
110
|
"Apply learned patterns from pattern cache",
|
|
120
111
|
]
|
|
@@ -123,7 +114,6 @@ def _create_validation_results(file_path: str) -> dict:
|
|
|
123
114
|
|
|
124
115
|
|
|
125
116
|
def _create_pattern_suggestions(problem_context: str) -> dict:
|
|
126
|
-
"""Create pattern suggestions based on context."""
|
|
127
117
|
pattern_suggestions = {
|
|
128
118
|
"context": problem_context,
|
|
129
119
|
"recommended_patterns": [],
|
|
@@ -131,32 +121,29 @@ def _create_pattern_suggestions(problem_context: str) -> dict:
|
|
|
131
121
|
"specialist_agents": [],
|
|
132
122
|
}
|
|
133
123
|
|
|
134
|
-
# Add context-specific patterns
|
|
135
124
|
_add_complexity_patterns(pattern_suggestions, problem_context)
|
|
136
125
|
_add_dry_patterns(pattern_suggestions, problem_context)
|
|
137
126
|
_add_performance_patterns(pattern_suggestions, problem_context)
|
|
138
127
|
_add_security_patterns(pattern_suggestions, problem_context)
|
|
139
128
|
|
|
140
|
-
# Add specialist agent recommendations
|
|
141
129
|
pattern_suggestions["specialist_agents"] = [
|
|
142
130
|
{
|
|
143
131
|
"agent": "crackerjack-architect",
|
|
144
132
|
"when_to_use": "For architectural decisions and complex pattern application",
|
|
145
|
-
"action": 'Task tool with subagent_type="crackerjack-architect"',
|
|
133
|
+
"action": 'Task tool with subagent_type ="crackerjack-architect"',
|
|
146
134
|
},
|
|
147
135
|
{
|
|
148
136
|
"agent": "refactoring-specialist",
|
|
149
137
|
"when_to_use": "For complexity reduction and structural improvements",
|
|
150
|
-
"action": 'Task tool with subagent_type="refactoring-specialist"',
|
|
138
|
+
"action": 'Task tool with subagent_type ="refactoring-specialist"',
|
|
151
139
|
},
|
|
152
140
|
{
|
|
153
141
|
"agent": "security-auditor",
|
|
154
142
|
"when_to_use": "For security pattern validation and vulnerability assessment",
|
|
155
|
-
"action": 'Task tool with subagent_type="security-auditor"',
|
|
143
|
+
"action": 'Task tool with subagent_type ="security-auditor"',
|
|
156
144
|
},
|
|
157
145
|
]
|
|
158
146
|
|
|
159
|
-
# Implementation guidance
|
|
160
147
|
pattern_suggestions["implementation_guidance"] = [
|
|
161
148
|
"Start with crackerjack-architect for overall planning",
|
|
162
149
|
"Apply one pattern at a time to avoid complexity",
|
|
@@ -165,7 +152,6 @@ def _create_pattern_suggestions(problem_context: str) -> dict:
|
|
|
165
152
|
"Document architectural decisions for team knowledge",
|
|
166
153
|
]
|
|
167
154
|
|
|
168
|
-
# Default patterns if none specified
|
|
169
155
|
if not pattern_suggestions["recommended_patterns"]:
|
|
170
156
|
pattern_suggestions["recommended_patterns"] = [
|
|
171
157
|
{
|
|
@@ -183,7 +169,6 @@ def _create_pattern_suggestions(problem_context: str) -> dict:
|
|
|
183
169
|
|
|
184
170
|
|
|
185
171
|
def _add_complexity_patterns(pattern_suggestions: dict, problem_context: str) -> None:
|
|
186
|
-
"""Add complexity-related patterns if relevant."""
|
|
187
172
|
if any(
|
|
188
173
|
keyword in problem_context.lower()
|
|
189
174
|
for keyword in ("complex", "refactor", "cleanup")
|
|
@@ -213,7 +198,6 @@ def _add_complexity_patterns(pattern_suggestions: dict, problem_context: str) ->
|
|
|
213
198
|
|
|
214
199
|
|
|
215
200
|
def _add_dry_patterns(pattern_suggestions: dict, problem_context: str) -> None:
|
|
216
|
-
"""Add DRY violation patterns if relevant."""
|
|
217
201
|
if any(
|
|
218
202
|
keyword in problem_context.lower() for keyword in ("duplicate", "repeat", "dry")
|
|
219
203
|
):
|
|
@@ -242,7 +226,6 @@ def _add_dry_patterns(pattern_suggestions: dict, problem_context: str) -> None:
|
|
|
242
226
|
|
|
243
227
|
|
|
244
228
|
def _add_performance_patterns(pattern_suggestions: dict, problem_context: str) -> None:
|
|
245
|
-
"""Add performance patterns if relevant."""
|
|
246
229
|
if any(
|
|
247
230
|
keyword in problem_context.lower()
|
|
248
231
|
for keyword in ("slow", "performance", "optimize")
|
|
@@ -272,7 +255,6 @@ def _add_performance_patterns(pattern_suggestions: dict, problem_context: str) -
|
|
|
272
255
|
|
|
273
256
|
|
|
274
257
|
def _add_security_patterns(pattern_suggestions: dict, problem_context: str) -> None:
|
|
275
|
-
"""Add security patterns if relevant."""
|
|
276
258
|
if any(
|
|
277
259
|
keyword in problem_context.lower() for keyword in ("security", "safe", "secure")
|
|
278
260
|
):
|
|
@@ -301,7 +283,6 @@ def _add_security_patterns(pattern_suggestions: dict, problem_context: str) -> N
|
|
|
301
283
|
|
|
302
284
|
|
|
303
285
|
def _create_error_response(error: Exception, recommendation: str) -> str:
|
|
304
|
-
"""Create standardized error response."""
|
|
305
286
|
import json
|
|
306
287
|
|
|
307
288
|
return json.dumps(
|
|
@@ -318,23 +299,18 @@ def _create_error_response(error: Exception, recommendation: str) -> str:
|
|
|
318
299
|
|
|
319
300
|
|
|
320
301
|
def register_proactive_tools(mcp_app: t.Any) -> None:
|
|
321
|
-
"""Register proactive planning and execution tools."""
|
|
322
302
|
return _register_proactive_tools(mcp_app)
|
|
323
303
|
|
|
324
304
|
|
|
325
305
|
def _register_proactive_tools(mcp_app: t.Any) -> None:
|
|
326
|
-
"""Register proactive planning and execution tools."""
|
|
327
306
|
_register_plan_development_tool(mcp_app)
|
|
328
307
|
_register_validate_architecture_tool(mcp_app)
|
|
329
308
|
_register_suggest_patterns_tool(mcp_app)
|
|
330
309
|
|
|
331
310
|
|
|
332
311
|
def _register_plan_development_tool(mcp_app: t.Any) -> None:
|
|
333
|
-
"""Register the plan_development tool."""
|
|
334
|
-
|
|
335
312
|
@mcp_app.tool()
|
|
336
313
|
async def plan_development(args: str, kwargs: str) -> str:
|
|
337
|
-
"""Plan development approach using crackerjack-architect specialist."""
|
|
338
314
|
import json
|
|
339
315
|
|
|
340
316
|
try:
|
|
@@ -346,11 +322,8 @@ def _register_plan_development_tool(mcp_app: t.Any) -> None:
|
|
|
346
322
|
|
|
347
323
|
|
|
348
324
|
def _register_validate_architecture_tool(mcp_app: t.Any) -> None:
|
|
349
|
-
"""Register the validate_architecture tool."""
|
|
350
|
-
|
|
351
325
|
@mcp_app.tool()
|
|
352
326
|
async def validate_architecture(args: str, kwargs: str) -> str:
|
|
353
|
-
"""Validate code against architectural patterns and crackerjack standards."""
|
|
354
327
|
import json
|
|
355
328
|
|
|
356
329
|
try:
|
|
@@ -360,16 +333,13 @@ def _register_validate_architecture_tool(mcp_app: t.Any) -> None:
|
|
|
360
333
|
return json.dumps(validation, indent=2)
|
|
361
334
|
except Exception as e:
|
|
362
335
|
return _create_error_response(
|
|
363
|
-
e, "Run standard crackerjack validation: python
|
|
336
|
+
e, "Run standard crackerjack validation: python-m crackerjack"
|
|
364
337
|
)
|
|
365
338
|
|
|
366
339
|
|
|
367
340
|
def _register_suggest_patterns_tool(mcp_app: t.Any) -> None:
|
|
368
|
-
"""Register the suggest_patterns tool."""
|
|
369
|
-
|
|
370
341
|
@mcp_app.tool()
|
|
371
342
|
async def suggest_patterns(args: str, kwargs: str) -> str:
|
|
372
|
-
"""Suggest crackerjack patterns for current development context."""
|
|
373
343
|
import json
|
|
374
344
|
|
|
375
345
|
try:
|
|
@@ -380,5 +350,5 @@ def _register_suggest_patterns_tool(mcp_app: t.Any) -> None:
|
|
|
380
350
|
except Exception as e:
|
|
381
351
|
return _create_error_response(
|
|
382
352
|
e,
|
|
383
|
-
'Use Task tool with subagent_type="crackerjack-architect" for expert guidance',
|
|
353
|
+
'Use Task tool with subagent_type ="crackerjack-architect" for expert guidance',
|
|
384
354
|
)
|
|
@@ -4,25 +4,30 @@ import typing as t
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
from crackerjack.mcp.context import get_context
|
|
7
|
+
from crackerjack.services.input_validator import get_input_validator
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def _create_progress_file(job_id: str) -> Path:
|
|
10
|
-
import re
|
|
11
11
|
import tempfile
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if not
|
|
17
|
-
msg = f"Invalid job_id
|
|
13
|
+
# Use secure input validation
|
|
14
|
+
job_id_result = get_input_validator().validate_job_id(job_id)
|
|
15
|
+
|
|
16
|
+
if not job_id_result.valid:
|
|
17
|
+
msg = f"Invalid job_id: {job_id_result.error_message}"
|
|
18
18
|
raise ValueError(msg)
|
|
19
19
|
|
|
20
|
+
# Use sanitized job ID
|
|
21
|
+
sanitized_job_id = job_id_result.sanitized_value
|
|
22
|
+
|
|
20
23
|
context = get_context()
|
|
21
24
|
if context:
|
|
22
|
-
return context.progress_dir / f"job-{
|
|
25
|
+
return context.progress_dir / f"job-{sanitized_job_id}.json"
|
|
26
|
+
|
|
27
|
+
# Create secure temporary directory
|
|
23
28
|
progress_dir = Path(tempfile.gettempdir()) / "crackerjack-mcp-progress"
|
|
24
|
-
progress_dir.mkdir(exist_ok=True)
|
|
25
|
-
return progress_dir / f"job-{
|
|
29
|
+
progress_dir.mkdir(exist_ok=True, mode=0o750) # Restrictive permissions
|
|
30
|
+
return progress_dir / f"job-{sanitized_job_id}.json"
|
|
26
31
|
|
|
27
32
|
|
|
28
33
|
def _clamp_progress(value: int) -> int:
|
|
@@ -96,7 +101,6 @@ def _update_progress(
|
|
|
96
101
|
job_id: str,
|
|
97
102
|
progress_data: dict[str, t.Any] | str = None,
|
|
98
103
|
context: t.Any = None,
|
|
99
|
-
# Legacy parameters for backward compatibility
|
|
100
104
|
iteration: int = 1,
|
|
101
105
|
max_iterations: int = 10,
|
|
102
106
|
overall_progress: int = 0,
|
|
@@ -162,7 +166,7 @@ def _handle_get_job_progress(job_id: str) -> str:
|
|
|
162
166
|
return f'{{"error": "Failed to get progress for job {job_id}: {e}"}}'
|
|
163
167
|
|
|
164
168
|
|
|
165
|
-
def _execute_session_action(
|
|
169
|
+
async def _execute_session_action(
|
|
166
170
|
state_manager,
|
|
167
171
|
action: str,
|
|
168
172
|
checkpoint_name: str | None,
|
|
@@ -174,7 +178,7 @@ def _execute_session_action(
|
|
|
174
178
|
|
|
175
179
|
if action == "checkpoint":
|
|
176
180
|
checkpoint_name = checkpoint_name or f"checkpoint_{context.get_current_time()}"
|
|
177
|
-
state_manager.
|
|
181
|
+
await state_manager.save_checkpoint(checkpoint_name)
|
|
178
182
|
return f'{{"status": "checkpoint_created", "action": "checkpoint", "name": "{checkpoint_name}"}}'
|
|
179
183
|
|
|
180
184
|
if action == "complete":
|
|
@@ -188,7 +192,9 @@ def _execute_session_action(
|
|
|
188
192
|
return f'{{"error": "Invalid action: {action}. Valid actions: start, checkpoint, complete, reset"}}'
|
|
189
193
|
|
|
190
194
|
|
|
191
|
-
def _handle_session_management(
|
|
195
|
+
async def _handle_session_management(
|
|
196
|
+
action: str, checkpoint_name: str | None = None
|
|
197
|
+
) -> str:
|
|
192
198
|
context = get_context()
|
|
193
199
|
if not context:
|
|
194
200
|
return '{"error": "Server context not available"}'
|
|
@@ -198,7 +204,9 @@ def _handle_session_management(action: str, checkpoint_name: str | None = None)
|
|
|
198
204
|
if not state_manager:
|
|
199
205
|
return '{"error": "State manager not available"}'
|
|
200
206
|
|
|
201
|
-
return _execute_session_action(
|
|
207
|
+
return await _execute_session_action(
|
|
208
|
+
state_manager, action, checkpoint_name, context
|
|
209
|
+
)
|
|
202
210
|
|
|
203
211
|
except Exception as e:
|
|
204
212
|
return f'{{"error": "Session management failed: {e}"}}'
|
|
@@ -214,4 +222,4 @@ def register_progress_tools(mcp_app: t.Any) -> None:
|
|
|
214
222
|
action: str,
|
|
215
223
|
checkpoint_name: str | None = None,
|
|
216
224
|
) -> str:
|
|
217
|
-
return _handle_session_management(action, checkpoint_name)
|
|
225
|
+
return await _handle_session_management(action, checkpoint_name)
|
|
@@ -8,12 +8,10 @@ from crackerjack.mcp.context import get_context
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def _create_error_response(message: str, success: bool = False) -> str:
|
|
11
|
-
"""Utility function to create standardized error responses."""
|
|
12
11
|
return json.dumps({"error": message, "success": success}, indent=2)
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
def register_utility_tools(mcp_app: t.Any) -> None:
|
|
16
|
-
"""Register utility slash command tools."""
|
|
17
15
|
_register_clean_tool(mcp_app)
|
|
18
16
|
_register_config_tool(mcp_app)
|
|
19
17
|
_register_analyze_tool(mcp_app)
|
|
@@ -22,7 +20,6 @@ def register_utility_tools(mcp_app: t.Any) -> None:
|
|
|
22
20
|
def _clean_file_if_old(
|
|
23
21
|
file_path: Path, cutoff_time: float, dry_run: bool, file_type: str
|
|
24
22
|
) -> dict | None:
|
|
25
|
-
"""Clean a single file if it's older than cutoff time."""
|
|
26
23
|
with suppress(OSError):
|
|
27
24
|
if file_path.stat().st_mtime < cutoff_time:
|
|
28
25
|
file_size = file_path.stat().st_size
|
|
@@ -33,14 +30,13 @@ def _clean_file_if_old(
|
|
|
33
30
|
|
|
34
31
|
|
|
35
32
|
def _clean_temp_files(cutoff_time: float, dry_run: bool) -> tuple[list[dict], int]:
|
|
36
|
-
"""Clean temporary files older than cutoff time."""
|
|
37
33
|
import tempfile
|
|
38
34
|
|
|
39
35
|
cleaned_files = []
|
|
40
36
|
total_size = 0
|
|
41
37
|
temp_dir = Path(tempfile.gettempdir())
|
|
42
38
|
|
|
43
|
-
patterns = ("crackerjack-*.log", "crackerjack-task-error-*.log", ".coverage.*")
|
|
39
|
+
patterns = ("crackerjack-*.log", "crackerjack - task - error-*.log", ".coverage.*")
|
|
44
40
|
for pattern in patterns:
|
|
45
41
|
for file_path in temp_dir.glob(pattern):
|
|
46
42
|
file_info = _clean_file_if_old(file_path, cutoff_time, dry_run, "temp")
|
|
@@ -54,7 +50,6 @@ def _clean_temp_files(cutoff_time: float, dry_run: bool) -> tuple[list[dict], in
|
|
|
54
50
|
def _clean_progress_files(
|
|
55
51
|
context: t.Any, cutoff_time: float, dry_run: bool
|
|
56
52
|
) -> tuple[list[dict], int]:
|
|
57
|
-
"""Clean progress files older than cutoff time."""
|
|
58
53
|
cleaned_files = []
|
|
59
54
|
total_size = 0
|
|
60
55
|
|
|
@@ -71,7 +66,6 @@ def _clean_progress_files(
|
|
|
71
66
|
|
|
72
67
|
|
|
73
68
|
def _parse_cleanup_options(kwargs: str) -> tuple[dict, str | None]:
|
|
74
|
-
"""Parse and validate cleanup options from kwargs string."""
|
|
75
69
|
try:
|
|
76
70
|
extra_kwargs = json.loads(kwargs) if kwargs.strip() else {}
|
|
77
71
|
return extra_kwargs, None
|
|
@@ -82,12 +76,6 @@ def _parse_cleanup_options(kwargs: str) -> tuple[dict, str | None]:
|
|
|
82
76
|
def _register_clean_tool(mcp_app: t.Any) -> None:
|
|
83
77
|
@mcp_app.tool()
|
|
84
78
|
async def clean_crackerjack(args: str = "", kwargs: str = "{}") -> str:
|
|
85
|
-
"""Clean up temporary files, stale progress data, and cached resources.
|
|
86
|
-
|
|
87
|
-
Args:
|
|
88
|
-
args: Optional cleanup scope: 'temp', 'progress', 'cache', 'all' (default)
|
|
89
|
-
kwargs: JSON with options like {"dry_run": true, "older_than": 24}
|
|
90
|
-
"""
|
|
91
79
|
context = get_context()
|
|
92
80
|
if not context:
|
|
93
81
|
return _create_error_response("Server context not available")
|
|
@@ -104,7 +92,6 @@ def _register_clean_tool(mcp_app: t.Any) -> None:
|
|
|
104
92
|
|
|
105
93
|
|
|
106
94
|
def _parse_clean_configuration(args: str, kwargs: str) -> dict:
|
|
107
|
-
"""Parse and validate cleanup configuration from arguments."""
|
|
108
95
|
extra_kwargs, parse_error = _parse_cleanup_options(kwargs)
|
|
109
96
|
if parse_error:
|
|
110
97
|
return {"error": parse_error}
|
|
@@ -117,7 +104,6 @@ def _parse_clean_configuration(args: str, kwargs: str) -> dict:
|
|
|
117
104
|
|
|
118
105
|
|
|
119
106
|
def _execute_cleanup_operations(context: t.Any, clean_config: dict) -> dict:
|
|
120
|
-
"""Execute the cleanup operations based on configuration."""
|
|
121
107
|
from datetime import datetime, timedelta
|
|
122
108
|
|
|
123
109
|
cutoff_time = (
|
|
@@ -126,13 +112,11 @@ def _execute_cleanup_operations(context: t.Any, clean_config: dict) -> dict:
|
|
|
126
112
|
all_cleaned_files = []
|
|
127
113
|
total_size = 0
|
|
128
114
|
|
|
129
|
-
# Clean temp files
|
|
130
115
|
if clean_config["scope"] in ("temp", "all"):
|
|
131
116
|
temp_files, temp_size = _clean_temp_files(cutoff_time, clean_config["dry_run"])
|
|
132
117
|
all_cleaned_files.extend(temp_files)
|
|
133
118
|
total_size += temp_size
|
|
134
119
|
|
|
135
|
-
# Clean progress files
|
|
136
120
|
if clean_config["scope"] in ("progress", "all"):
|
|
137
121
|
progress_files, progress_size = _clean_progress_files(
|
|
138
122
|
context, cutoff_time, clean_config["dry_run"]
|
|
@@ -140,16 +124,13 @@ def _execute_cleanup_operations(context: t.Any, clean_config: dict) -> dict:
|
|
|
140
124
|
all_cleaned_files.extend(progress_files)
|
|
141
125
|
total_size += progress_size
|
|
142
126
|
|
|
143
|
-
# Clean cache files (if any caching is implemented)
|
|
144
127
|
if clean_config["scope"] in ("cache", "all"):
|
|
145
|
-
# Placeholder for future cache cleaning
|
|
146
128
|
pass
|
|
147
129
|
|
|
148
130
|
return {"all_cleaned_files": all_cleaned_files, "total_size": total_size}
|
|
149
131
|
|
|
150
132
|
|
|
151
133
|
def _create_cleanup_response(clean_config: dict, cleanup_results: dict) -> str:
|
|
152
|
-
"""Create the cleanup response JSON."""
|
|
153
134
|
all_cleaned_files = cleanup_results["all_cleaned_files"]
|
|
154
135
|
|
|
155
136
|
return json.dumps(
|
|
@@ -170,7 +151,6 @@ def _create_cleanup_response(clean_config: dict, cleanup_results: dict) -> str:
|
|
|
170
151
|
|
|
171
152
|
|
|
172
153
|
def _handle_config_list(context: t.Any) -> dict[str, t.Any]:
|
|
173
|
-
"""Handle config list action."""
|
|
174
154
|
return {
|
|
175
155
|
"project_path": str(context.config.project_path),
|
|
176
156
|
"rate_limiter": {
|
|
@@ -185,7 +165,6 @@ def _handle_config_list(context: t.Any) -> dict[str, t.Any]:
|
|
|
185
165
|
|
|
186
166
|
|
|
187
167
|
def _handle_config_get(context: t.Any, key: str) -> dict[str, t.Any]:
|
|
188
|
-
"""Handle config get action."""
|
|
189
168
|
value = getattr(context.config, key, None)
|
|
190
169
|
if value is None:
|
|
191
170
|
value = getattr(context, key, "Key not found")
|
|
@@ -200,7 +179,6 @@ def _handle_config_get(context: t.Any, key: str) -> dict[str, t.Any]:
|
|
|
200
179
|
|
|
201
180
|
|
|
202
181
|
def _handle_config_validate(context: t.Any) -> dict[str, t.Any]:
|
|
203
|
-
"""Handle config validate action."""
|
|
204
182
|
validation_results = {
|
|
205
183
|
"project_path_exists": context.config.project_path.exists(),
|
|
206
184
|
"progress_dir_writable": context.progress_dir.exists()
|
|
@@ -222,12 +200,6 @@ def _handle_config_validate(context: t.Any) -> dict[str, t.Any]:
|
|
|
222
200
|
def _register_config_tool(mcp_app: t.Any) -> None:
|
|
223
201
|
@mcp_app.tool()
|
|
224
202
|
async def config_crackerjack(args: str = "", kwargs: str = "{}") -> str:
|
|
225
|
-
"""View or update crackerjack configuration.
|
|
226
|
-
|
|
227
|
-
Args:
|
|
228
|
-
args: Action - 'get <key>', 'set <key=value>', 'list', or 'validate'
|
|
229
|
-
kwargs: JSON with additional options
|
|
230
|
-
"""
|
|
231
203
|
context = get_context()
|
|
232
204
|
if not context:
|
|
233
205
|
return _create_error_response("Server context not available")
|
|
@@ -254,7 +226,7 @@ def _register_config_tool(mcp_app: t.Any) -> None:
|
|
|
254
226
|
result = _handle_config_validate(context)
|
|
255
227
|
else:
|
|
256
228
|
return _create_error_response(
|
|
257
|
-
f"Invalid action '{action}'. Valid actions: list, get <key>, validate"
|
|
229
|
+
f"Invalid action '{action}'. Valid actions: list, get < key >, validate"
|
|
258
230
|
)
|
|
259
231
|
|
|
260
232
|
return json.dumps(result, indent=2)
|
|
@@ -264,7 +236,6 @@ def _register_config_tool(mcp_app: t.Any) -> None:
|
|
|
264
236
|
|
|
265
237
|
|
|
266
238
|
def _run_hooks_analysis(orchestrator: t.Any, options: t.Any) -> dict:
|
|
267
|
-
"""Run hooks analysis and return results."""
|
|
268
239
|
fast_result = orchestrator.run_fast_hooks_only(options)
|
|
269
240
|
comprehensive_result = orchestrator.run_comprehensive_hooks_only(options)
|
|
270
241
|
|
|
@@ -275,31 +246,23 @@ def _run_hooks_analysis(orchestrator: t.Any, options: t.Any) -> dict:
|
|
|
275
246
|
|
|
276
247
|
|
|
277
248
|
def _run_tests_analysis(orchestrator: t.Any, options: t.Any) -> dict:
|
|
278
|
-
"""Run tests analysis and return results."""
|
|
279
249
|
test_result = orchestrator.run_testing_phase(options)
|
|
280
250
|
return {"status": "passed" if test_result else "failed"}
|
|
281
251
|
|
|
282
252
|
|
|
283
253
|
def _create_analysis_orchestrator(context: t.Any) -> t.Any:
|
|
284
|
-
"""Create workflow orchestrator for analysis."""
|
|
285
254
|
from crackerjack.core.workflow_orchestrator import WorkflowOrchestrator
|
|
286
255
|
|
|
287
256
|
return WorkflowOrchestrator(
|
|
288
257
|
console=context.console,
|
|
289
258
|
pkg_path=context.config.project_path,
|
|
290
|
-
dry_run=True,
|
|
259
|
+
dry_run=True,
|
|
291
260
|
)
|
|
292
261
|
|
|
293
262
|
|
|
294
263
|
def _register_analyze_tool(mcp_app: t.Any) -> None:
|
|
295
264
|
@mcp_app.tool()
|
|
296
265
|
async def analyze_crackerjack(args: str = "", kwargs: str = "{}") -> str:
|
|
297
|
-
"""Analyze code quality without making changes.
|
|
298
|
-
|
|
299
|
-
Args:
|
|
300
|
-
args: Analysis scope - 'hooks', 'tests', 'all' (default)
|
|
301
|
-
kwargs: JSON with options like {"report_format": "summary"}
|
|
302
|
-
"""
|
|
303
266
|
context = get_context()
|
|
304
267
|
if not context:
|
|
305
268
|
return _create_error_response("Server context not available")
|