crackerjack 0.30.3__py3-none-any.whl → 0.31.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of crackerjack might be problematic. Click here for more details.
- crackerjack/CLAUDE.md +1005 -0
- crackerjack/RULES.md +380 -0
- crackerjack/__init__.py +42 -13
- crackerjack/__main__.py +227 -299
- crackerjack/agents/__init__.py +41 -0
- crackerjack/agents/architect_agent.py +281 -0
- crackerjack/agents/base.py +170 -0
- crackerjack/agents/coordinator.py +512 -0
- crackerjack/agents/documentation_agent.py +498 -0
- crackerjack/agents/dry_agent.py +388 -0
- crackerjack/agents/formatting_agent.py +245 -0
- crackerjack/agents/import_optimization_agent.py +281 -0
- crackerjack/agents/performance_agent.py +669 -0
- crackerjack/agents/proactive_agent.py +104 -0
- crackerjack/agents/refactoring_agent.py +788 -0
- crackerjack/agents/security_agent.py +529 -0
- crackerjack/agents/test_creation_agent.py +657 -0
- crackerjack/agents/test_specialist_agent.py +486 -0
- crackerjack/agents/tracker.py +212 -0
- crackerjack/api.py +560 -0
- crackerjack/cli/__init__.py +24 -0
- crackerjack/cli/facade.py +104 -0
- crackerjack/cli/handlers.py +267 -0
- crackerjack/cli/interactive.py +471 -0
- crackerjack/cli/options.py +409 -0
- crackerjack/cli/utils.py +18 -0
- crackerjack/code_cleaner.py +618 -928
- crackerjack/config/__init__.py +19 -0
- crackerjack/config/hooks.py +218 -0
- crackerjack/core/__init__.py +0 -0
- crackerjack/core/async_workflow_orchestrator.py +406 -0
- crackerjack/core/autofix_coordinator.py +200 -0
- crackerjack/core/container.py +104 -0
- crackerjack/core/enhanced_container.py +542 -0
- crackerjack/core/performance.py +243 -0
- crackerjack/core/phase_coordinator.py +585 -0
- crackerjack/core/proactive_workflow.py +316 -0
- crackerjack/core/session_coordinator.py +289 -0
- crackerjack/core/workflow_orchestrator.py +826 -0
- crackerjack/dynamic_config.py +94 -103
- crackerjack/errors.py +263 -41
- crackerjack/executors/__init__.py +11 -0
- crackerjack/executors/async_hook_executor.py +431 -0
- crackerjack/executors/cached_hook_executor.py +242 -0
- crackerjack/executors/hook_executor.py +345 -0
- crackerjack/executors/individual_hook_executor.py +669 -0
- crackerjack/intelligence/__init__.py +44 -0
- crackerjack/intelligence/adaptive_learning.py +751 -0
- crackerjack/intelligence/agent_orchestrator.py +551 -0
- crackerjack/intelligence/agent_registry.py +414 -0
- crackerjack/intelligence/agent_selector.py +502 -0
- crackerjack/intelligence/integration.py +290 -0
- crackerjack/interactive.py +576 -315
- crackerjack/managers/__init__.py +11 -0
- crackerjack/managers/async_hook_manager.py +135 -0
- crackerjack/managers/hook_manager.py +137 -0
- crackerjack/managers/publish_manager.py +433 -0
- crackerjack/managers/test_command_builder.py +151 -0
- crackerjack/managers/test_executor.py +443 -0
- crackerjack/managers/test_manager.py +258 -0
- crackerjack/managers/test_manager_backup.py +1124 -0
- crackerjack/managers/test_progress.py +114 -0
- crackerjack/mcp/__init__.py +0 -0
- crackerjack/mcp/cache.py +336 -0
- crackerjack/mcp/client_runner.py +104 -0
- crackerjack/mcp/context.py +621 -0
- crackerjack/mcp/dashboard.py +636 -0
- crackerjack/mcp/enhanced_progress_monitor.py +479 -0
- crackerjack/mcp/file_monitor.py +336 -0
- crackerjack/mcp/progress_components.py +569 -0
- crackerjack/mcp/progress_monitor.py +949 -0
- crackerjack/mcp/rate_limiter.py +332 -0
- crackerjack/mcp/server.py +22 -0
- crackerjack/mcp/server_core.py +244 -0
- crackerjack/mcp/service_watchdog.py +501 -0
- crackerjack/mcp/state.py +395 -0
- crackerjack/mcp/task_manager.py +257 -0
- crackerjack/mcp/tools/__init__.py +17 -0
- crackerjack/mcp/tools/core_tools.py +249 -0
- crackerjack/mcp/tools/error_analyzer.py +308 -0
- crackerjack/mcp/tools/execution_tools.py +372 -0
- crackerjack/mcp/tools/execution_tools_backup.py +1097 -0
- crackerjack/mcp/tools/intelligence_tool_registry.py +80 -0
- crackerjack/mcp/tools/intelligence_tools.py +314 -0
- crackerjack/mcp/tools/monitoring_tools.py +502 -0
- crackerjack/mcp/tools/proactive_tools.py +384 -0
- crackerjack/mcp/tools/progress_tools.py +217 -0
- crackerjack/mcp/tools/utility_tools.py +341 -0
- crackerjack/mcp/tools/workflow_executor.py +565 -0
- crackerjack/mcp/websocket/__init__.py +14 -0
- crackerjack/mcp/websocket/app.py +39 -0
- crackerjack/mcp/websocket/endpoints.py +559 -0
- crackerjack/mcp/websocket/jobs.py +253 -0
- crackerjack/mcp/websocket/server.py +116 -0
- crackerjack/mcp/websocket/websocket_handler.py +78 -0
- crackerjack/mcp/websocket_server.py +10 -0
- crackerjack/models/__init__.py +31 -0
- crackerjack/models/config.py +93 -0
- crackerjack/models/config_adapter.py +230 -0
- crackerjack/models/protocols.py +118 -0
- crackerjack/models/task.py +154 -0
- crackerjack/monitoring/ai_agent_watchdog.py +450 -0
- crackerjack/monitoring/regression_prevention.py +638 -0
- crackerjack/orchestration/__init__.py +0 -0
- crackerjack/orchestration/advanced_orchestrator.py +970 -0
- crackerjack/orchestration/coverage_improvement.py +223 -0
- crackerjack/orchestration/execution_strategies.py +341 -0
- crackerjack/orchestration/test_progress_streamer.py +636 -0
- crackerjack/plugins/__init__.py +15 -0
- crackerjack/plugins/base.py +200 -0
- crackerjack/plugins/hooks.py +246 -0
- crackerjack/plugins/loader.py +335 -0
- crackerjack/plugins/managers.py +259 -0
- crackerjack/py313.py +8 -3
- crackerjack/services/__init__.py +22 -0
- crackerjack/services/cache.py +314 -0
- crackerjack/services/config.py +358 -0
- crackerjack/services/config_integrity.py +99 -0
- crackerjack/services/contextual_ai_assistant.py +516 -0
- crackerjack/services/coverage_ratchet.py +356 -0
- crackerjack/services/debug.py +736 -0
- crackerjack/services/dependency_monitor.py +617 -0
- crackerjack/services/enhanced_filesystem.py +439 -0
- crackerjack/services/file_hasher.py +151 -0
- crackerjack/services/filesystem.py +421 -0
- crackerjack/services/git.py +176 -0
- crackerjack/services/health_metrics.py +611 -0
- crackerjack/services/initialization.py +873 -0
- crackerjack/services/log_manager.py +286 -0
- crackerjack/services/logging.py +174 -0
- crackerjack/services/metrics.py +578 -0
- crackerjack/services/pattern_cache.py +362 -0
- crackerjack/services/pattern_detector.py +515 -0
- crackerjack/services/performance_benchmarks.py +653 -0
- crackerjack/services/security.py +163 -0
- crackerjack/services/server_manager.py +234 -0
- crackerjack/services/smart_scheduling.py +144 -0
- crackerjack/services/tool_version_service.py +61 -0
- crackerjack/services/unified_config.py +437 -0
- crackerjack/services/version_checker.py +248 -0
- crackerjack/slash_commands/__init__.py +14 -0
- crackerjack/slash_commands/init.md +122 -0
- crackerjack/slash_commands/run.md +163 -0
- crackerjack/slash_commands/status.md +127 -0
- crackerjack-0.31.7.dist-info/METADATA +742 -0
- crackerjack-0.31.7.dist-info/RECORD +149 -0
- crackerjack-0.31.7.dist-info/entry_points.txt +2 -0
- crackerjack/.gitignore +0 -34
- crackerjack/.libcst.codemod.yaml +0 -18
- crackerjack/.pdm.toml +0 -1
- crackerjack/crackerjack.py +0 -3805
- crackerjack/pyproject.toml +0 -286
- crackerjack-0.30.3.dist-info/METADATA +0 -1290
- crackerjack-0.30.3.dist-info/RECORD +0 -16
- {crackerjack-0.30.3.dist-info → crackerjack-0.31.7.dist-info}/WHEEL +0 -0
- {crackerjack-0.30.3.dist-info → crackerjack-0.31.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import time
|
|
3
|
+
import typing as t
|
|
4
|
+
from contextlib import suppress
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from crackerjack.mcp.context import get_context
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _create_error_response(message: str, success: bool = False) -> str:
|
|
11
|
+
"""Utility function to create standardized error responses."""
|
|
12
|
+
return json.dumps({"error": message, "success": success}, indent=2)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def register_utility_tools(mcp_app: t.Any) -> None:
|
|
16
|
+
"""Register utility slash command tools."""
|
|
17
|
+
_register_clean_tool(mcp_app)
|
|
18
|
+
_register_config_tool(mcp_app)
|
|
19
|
+
_register_analyze_tool(mcp_app)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _clean_file_if_old(
|
|
23
|
+
file_path: Path, cutoff_time: float, dry_run: bool, file_type: str
|
|
24
|
+
) -> dict | None:
|
|
25
|
+
"""Clean a single file if it's older than cutoff time."""
|
|
26
|
+
with suppress(OSError):
|
|
27
|
+
if file_path.stat().st_mtime < cutoff_time:
|
|
28
|
+
file_size = file_path.stat().st_size
|
|
29
|
+
if not dry_run:
|
|
30
|
+
file_path.unlink()
|
|
31
|
+
return {"path": str(file_path), "size": file_size, "type": file_type}
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _clean_temp_files(cutoff_time: float, dry_run: bool) -> tuple[list[dict], int]:
|
|
36
|
+
"""Clean temporary files older than cutoff time."""
|
|
37
|
+
import tempfile
|
|
38
|
+
|
|
39
|
+
cleaned_files = []
|
|
40
|
+
total_size = 0
|
|
41
|
+
temp_dir = Path(tempfile.gettempdir())
|
|
42
|
+
|
|
43
|
+
patterns = ("crackerjack-*.log", "crackerjack-task-error-*.log", ".coverage.*")
|
|
44
|
+
for pattern in patterns:
|
|
45
|
+
for file_path in temp_dir.glob(pattern):
|
|
46
|
+
file_info = _clean_file_if_old(file_path, cutoff_time, dry_run, "temp")
|
|
47
|
+
if file_info:
|
|
48
|
+
cleaned_files.append(file_info)
|
|
49
|
+
total_size += file_info["size"]
|
|
50
|
+
|
|
51
|
+
return cleaned_files, total_size
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _clean_progress_files(
|
|
55
|
+
context: t.Any, cutoff_time: float, dry_run: bool
|
|
56
|
+
) -> tuple[list[dict], int]:
|
|
57
|
+
"""Clean progress files older than cutoff time."""
|
|
58
|
+
cleaned_files = []
|
|
59
|
+
total_size = 0
|
|
60
|
+
|
|
61
|
+
if context.progress_dir.exists():
|
|
62
|
+
for progress_file in context.progress_dir.glob("*.json"):
|
|
63
|
+
file_info = _clean_file_if_old(
|
|
64
|
+
progress_file, cutoff_time, dry_run, "progress"
|
|
65
|
+
)
|
|
66
|
+
if file_info:
|
|
67
|
+
cleaned_files.append(file_info)
|
|
68
|
+
total_size += file_info["size"]
|
|
69
|
+
|
|
70
|
+
return cleaned_files, total_size
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _parse_cleanup_options(kwargs: str) -> tuple[dict, str | None]:
|
|
74
|
+
"""Parse and validate cleanup options from kwargs string."""
|
|
75
|
+
try:
|
|
76
|
+
extra_kwargs = json.loads(kwargs) if kwargs.strip() else {}
|
|
77
|
+
return extra_kwargs, None
|
|
78
|
+
except json.JSONDecodeError as e:
|
|
79
|
+
return {}, f"Invalid JSON in kwargs: {e}"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _register_clean_tool(mcp_app: t.Any) -> None:
|
|
83
|
+
@mcp_app.tool()
|
|
84
|
+
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
|
+
context = get_context()
|
|
92
|
+
if not context:
|
|
93
|
+
return _create_error_response("Server context not available")
|
|
94
|
+
|
|
95
|
+
clean_config = _parse_clean_configuration(args, kwargs)
|
|
96
|
+
if "error" in clean_config:
|
|
97
|
+
return _create_error_response(clean_config["error"])
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
cleanup_results = _execute_cleanup_operations(context, clean_config)
|
|
101
|
+
return _create_cleanup_response(clean_config, cleanup_results)
|
|
102
|
+
except Exception as e:
|
|
103
|
+
return _create_error_response(f"Cleanup failed: {e}")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _parse_clean_configuration(args: str, kwargs: str) -> dict:
|
|
107
|
+
"""Parse and validate cleanup configuration from arguments."""
|
|
108
|
+
extra_kwargs, parse_error = _parse_cleanup_options(kwargs)
|
|
109
|
+
if parse_error:
|
|
110
|
+
return {"error": parse_error}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
"scope": args.strip().lower() or "all",
|
|
114
|
+
"dry_run": extra_kwargs.get("dry_run", False),
|
|
115
|
+
"older_than_hours": extra_kwargs.get("older_than", 24),
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _execute_cleanup_operations(context: t.Any, clean_config: dict) -> dict:
|
|
120
|
+
"""Execute the cleanup operations based on configuration."""
|
|
121
|
+
from datetime import datetime, timedelta
|
|
122
|
+
|
|
123
|
+
cutoff_time = (
|
|
124
|
+
datetime.now() - timedelta(hours=clean_config["older_than_hours"])
|
|
125
|
+
).timestamp()
|
|
126
|
+
all_cleaned_files = []
|
|
127
|
+
total_size = 0
|
|
128
|
+
|
|
129
|
+
# Clean temp files
|
|
130
|
+
if clean_config["scope"] in ("temp", "all"):
|
|
131
|
+
temp_files, temp_size = _clean_temp_files(cutoff_time, clean_config["dry_run"])
|
|
132
|
+
all_cleaned_files.extend(temp_files)
|
|
133
|
+
total_size += temp_size
|
|
134
|
+
|
|
135
|
+
# Clean progress files
|
|
136
|
+
if clean_config["scope"] in ("progress", "all"):
|
|
137
|
+
progress_files, progress_size = _clean_progress_files(
|
|
138
|
+
context, cutoff_time, clean_config["dry_run"]
|
|
139
|
+
)
|
|
140
|
+
all_cleaned_files.extend(progress_files)
|
|
141
|
+
total_size += progress_size
|
|
142
|
+
|
|
143
|
+
# Clean cache files (if any caching is implemented)
|
|
144
|
+
if clean_config["scope"] in ("cache", "all"):
|
|
145
|
+
# Placeholder for future cache cleaning
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
return {"all_cleaned_files": all_cleaned_files, "total_size": total_size}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _create_cleanup_response(clean_config: dict, cleanup_results: dict) -> str:
|
|
152
|
+
"""Create the cleanup response JSON."""
|
|
153
|
+
all_cleaned_files = cleanup_results["all_cleaned_files"]
|
|
154
|
+
|
|
155
|
+
return json.dumps(
|
|
156
|
+
{
|
|
157
|
+
"success": True,
|
|
158
|
+
"command": "clean_crackerjack",
|
|
159
|
+
"dry_run": clean_config["dry_run"],
|
|
160
|
+
"scope": clean_config["scope"],
|
|
161
|
+
"older_than_hours": clean_config["older_than_hours"],
|
|
162
|
+
"files_cleaned": len(all_cleaned_files),
|
|
163
|
+
"total_size_bytes": cleanup_results["total_size"],
|
|
164
|
+
"files": all_cleaned_files
|
|
165
|
+
if len(all_cleaned_files) <= 50
|
|
166
|
+
else all_cleaned_files[:50],
|
|
167
|
+
},
|
|
168
|
+
indent=2,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _handle_config_list(context: t.Any) -> dict[str, t.Any]:
|
|
173
|
+
"""Handle config list action."""
|
|
174
|
+
return {
|
|
175
|
+
"project_path": str(context.config.project_path),
|
|
176
|
+
"rate_limiter": {
|
|
177
|
+
"enabled": context.rate_limiter is not None,
|
|
178
|
+
"config": context.rate_limiter.config.__dict__
|
|
179
|
+
if context.rate_limiter
|
|
180
|
+
else None,
|
|
181
|
+
},
|
|
182
|
+
"progress_dir": str(context.progress_dir),
|
|
183
|
+
"websocket_port": getattr(context, "websocket_server_port", None),
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _handle_config_get(context: t.Any, key: str) -> dict[str, t.Any]:
|
|
188
|
+
"""Handle config get action."""
|
|
189
|
+
value = getattr(context.config, key, None)
|
|
190
|
+
if value is None:
|
|
191
|
+
value = getattr(context, key, "Key not found")
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
"success": True,
|
|
195
|
+
"command": "config_crackerjack",
|
|
196
|
+
"action": "get",
|
|
197
|
+
"key": key,
|
|
198
|
+
"value": str(value),
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _handle_config_validate(context: t.Any) -> dict[str, t.Any]:
|
|
203
|
+
"""Handle config validate action."""
|
|
204
|
+
validation_results = {
|
|
205
|
+
"project_path_exists": context.config.project_path.exists(),
|
|
206
|
+
"progress_dir_writable": context.progress_dir.exists()
|
|
207
|
+
and context.progress_dir.is_dir(),
|
|
208
|
+
"rate_limiter_configured": context.rate_limiter is not None,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
all_valid = all(validation_results.values())
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
"success": True,
|
|
215
|
+
"command": "config_crackerjack",
|
|
216
|
+
"action": "validate",
|
|
217
|
+
"valid": all_valid,
|
|
218
|
+
"checks": validation_results,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _register_config_tool(mcp_app: t.Any) -> None:
|
|
223
|
+
@mcp_app.tool()
|
|
224
|
+
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
|
+
context = get_context()
|
|
232
|
+
if not context:
|
|
233
|
+
return _create_error_response("Server context not available")
|
|
234
|
+
|
|
235
|
+
extra_kwargs, parse_error = _parse_cleanup_options(kwargs)
|
|
236
|
+
if parse_error:
|
|
237
|
+
return _create_error_response(parse_error)
|
|
238
|
+
|
|
239
|
+
args_parts = args.strip().split() if args.strip() else ["list"]
|
|
240
|
+
action = args_parts[0].lower()
|
|
241
|
+
|
|
242
|
+
try:
|
|
243
|
+
if action == "list":
|
|
244
|
+
config_info = _handle_config_list(context)
|
|
245
|
+
result = {
|
|
246
|
+
"success": True,
|
|
247
|
+
"command": "config_crackerjack",
|
|
248
|
+
"action": "list",
|
|
249
|
+
"configuration": config_info,
|
|
250
|
+
}
|
|
251
|
+
elif action == "get" and len(args_parts) > 1:
|
|
252
|
+
result = _handle_config_get(context, args_parts[1])
|
|
253
|
+
elif action == "validate":
|
|
254
|
+
result = _handle_config_validate(context)
|
|
255
|
+
else:
|
|
256
|
+
return _create_error_response(
|
|
257
|
+
f"Invalid action '{action}'. Valid actions: list, get <key>, validate"
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
return json.dumps(result, indent=2)
|
|
261
|
+
|
|
262
|
+
except Exception as e:
|
|
263
|
+
return _create_error_response(f"Config operation failed: {e}")
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _run_hooks_analysis(orchestrator: t.Any, options: t.Any) -> dict:
|
|
267
|
+
"""Run hooks analysis and return results."""
|
|
268
|
+
fast_result = orchestrator.run_fast_hooks_only(options)
|
|
269
|
+
comprehensive_result = orchestrator.run_comprehensive_hooks_only(options)
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
"fast_hooks": "passed" if fast_result else "failed",
|
|
273
|
+
"comprehensive_hooks": "passed" if comprehensive_result else "failed",
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _run_tests_analysis(orchestrator: t.Any, options: t.Any) -> dict:
|
|
278
|
+
"""Run tests analysis and return results."""
|
|
279
|
+
test_result = orchestrator.run_testing_phase(options)
|
|
280
|
+
return {"status": "passed" if test_result else "failed"}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _create_analysis_orchestrator(context: t.Any) -> t.Any:
|
|
284
|
+
"""Create workflow orchestrator for analysis."""
|
|
285
|
+
from crackerjack.core.workflow_orchestrator import WorkflowOrchestrator
|
|
286
|
+
|
|
287
|
+
return WorkflowOrchestrator(
|
|
288
|
+
console=context.console,
|
|
289
|
+
pkg_path=context.config.project_path,
|
|
290
|
+
dry_run=True, # Analysis only, no changes
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _register_analyze_tool(mcp_app: t.Any) -> None:
|
|
295
|
+
@mcp_app.tool()
|
|
296
|
+
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
|
+
context = get_context()
|
|
304
|
+
if not context:
|
|
305
|
+
return _create_error_response("Server context not available")
|
|
306
|
+
|
|
307
|
+
extra_kwargs, parse_error = _parse_cleanup_options(kwargs)
|
|
308
|
+
if parse_error:
|
|
309
|
+
return _create_error_response(parse_error)
|
|
310
|
+
|
|
311
|
+
scope = args.strip().lower() or "all"
|
|
312
|
+
report_format = extra_kwargs.get("report_format", "summary")
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
from crackerjack.models.config import WorkflowOptions
|
|
316
|
+
|
|
317
|
+
orchestrator = _create_analysis_orchestrator(context)
|
|
318
|
+
options = WorkflowOptions()
|
|
319
|
+
analysis_results = {}
|
|
320
|
+
|
|
321
|
+
if scope in ("hooks", "all"):
|
|
322
|
+
analysis_results["hooks"] = _run_hooks_analysis(orchestrator, options)
|
|
323
|
+
|
|
324
|
+
if scope in ("tests", "all"):
|
|
325
|
+
analysis_results["tests"] = _run_tests_analysis(orchestrator, options)
|
|
326
|
+
|
|
327
|
+
return json.dumps(
|
|
328
|
+
{
|
|
329
|
+
"success": True,
|
|
330
|
+
"command": "analyze_crackerjack",
|
|
331
|
+
"scope": scope,
|
|
332
|
+
"report_format": report_format,
|
|
333
|
+
"dry_run": True,
|
|
334
|
+
"timestamp": time.time(),
|
|
335
|
+
"analysis": analysis_results,
|
|
336
|
+
},
|
|
337
|
+
indent=2,
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
except Exception as e:
|
|
341
|
+
return _create_error_response(f"Analysis failed: {e}")
|