crackerjack 0.39.5__py3-none-any.whl → 0.39.6__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/mcp/tools/execution_tools.py +75 -21
- crackerjack/mcp/tools/workflow_executor.py +57 -31
- {crackerjack-0.39.5.dist-info → crackerjack-0.39.6.dist-info}/METADATA +12 -12
- {crackerjack-0.39.5.dist-info → crackerjack-0.39.6.dist-info}/RECORD +7 -7
- {crackerjack-0.39.5.dist-info → crackerjack-0.39.6.dist-info}/WHEEL +0 -0
- {crackerjack-0.39.5.dist-info → crackerjack-0.39.6.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.39.5.dist-info → crackerjack-0.39.6.dist-info}/licenses/LICENSE +0 -0
|
@@ -17,37 +17,91 @@ def register_execution_tools(mcp_app: t.Any) -> None:
|
|
|
17
17
|
def _register_execute_crackerjack_tool(mcp_app: t.Any) -> None:
|
|
18
18
|
@mcp_app.tool() # type: ignore[misc]
|
|
19
19
|
async def execute_crackerjack(args: str, kwargs: str) -> str:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
kwargs_result = _parse_kwargs(kwargs)
|
|
27
|
-
if "error" in kwargs_result:
|
|
28
|
-
return json.dumps(kwargs_result)
|
|
29
|
-
|
|
30
|
-
extra_kwargs = kwargs_result["kwargs"]
|
|
20
|
+
try:
|
|
21
|
+
context = get_context()
|
|
22
|
+
validation_error = await _handle_context_validation(context)
|
|
23
|
+
if validation_error:
|
|
24
|
+
return validation_error
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
if
|
|
34
|
-
|
|
35
|
-
else:
|
|
36
|
-
extra_kwargs["execution_timeout"] = 900
|
|
26
|
+
kwargs_result = _parse_kwargs(kwargs)
|
|
27
|
+
if "error" in kwargs_result:
|
|
28
|
+
return json.dumps(kwargs_result)
|
|
37
29
|
|
|
38
|
-
|
|
30
|
+
extra_kwargs = _prepare_execution_kwargs(kwargs_result["kwargs"])
|
|
39
31
|
result = await execute_crackerjack_workflow(args, extra_kwargs)
|
|
40
32
|
return json.dumps(result, indent=2)
|
|
33
|
+
except TypeError as e:
|
|
34
|
+
return _handle_type_error(e)
|
|
41
35
|
except Exception as e:
|
|
36
|
+
return _handle_general_error(e)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async def _handle_context_validation(context: t.Any) -> str | None:
|
|
40
|
+
"""Handle context validation with proper error handling."""
|
|
41
|
+
from datetime import datetime
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
validation_error = await _validate_context_and_rate_limit(context)
|
|
45
|
+
if validation_error:
|
|
46
|
+
return validation_error
|
|
47
|
+
return None
|
|
48
|
+
except TypeError as e:
|
|
49
|
+
if "NoneType" in str(e) and "await" in str(e):
|
|
42
50
|
return json.dumps(
|
|
43
51
|
{
|
|
44
52
|
"status": "failed",
|
|
45
|
-
"error":
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
"error": "Context validation failed: rate limiter returned None. "
|
|
54
|
+
"MCP server may not be properly initialized.",
|
|
55
|
+
"timestamp": datetime.now().isoformat(),
|
|
56
|
+
"details": str(e),
|
|
49
57
|
}
|
|
50
58
|
)
|
|
59
|
+
raise
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _prepare_execution_kwargs(kwargs: dict[str, t.Any]) -> dict[str, t.Any]:
|
|
63
|
+
"""Prepare execution kwargs with appropriate timeout defaults."""
|
|
64
|
+
if "execution_timeout" not in kwargs:
|
|
65
|
+
if kwargs.get("test", False) or kwargs.get("testing", False):
|
|
66
|
+
kwargs["execution_timeout"] = 1200
|
|
67
|
+
else:
|
|
68
|
+
kwargs["execution_timeout"] = 900
|
|
69
|
+
return kwargs
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _handle_type_error(error: TypeError) -> str:
|
|
73
|
+
"""Handle TypeError with specific async execution error details."""
|
|
74
|
+
import traceback
|
|
75
|
+
from datetime import datetime
|
|
76
|
+
|
|
77
|
+
if "NoneType" in str(error) and "await" in str(error):
|
|
78
|
+
return json.dumps(
|
|
79
|
+
{
|
|
80
|
+
"status": "failed",
|
|
81
|
+
"error": f"Async execution error: A function returned None instead of an awaitable. {error}",
|
|
82
|
+
"traceback": traceback.format_exc(),
|
|
83
|
+
"timestamp": datetime.now().isoformat(),
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
raise error
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _handle_general_error(error: Exception) -> str:
|
|
90
|
+
"""Handle general execution errors with traceback."""
|
|
91
|
+
import traceback
|
|
92
|
+
from datetime import datetime
|
|
93
|
+
|
|
94
|
+
context = get_context()
|
|
95
|
+
return json.dumps(
|
|
96
|
+
{
|
|
97
|
+
"status": "failed",
|
|
98
|
+
"error": f"Execution failed: {error}",
|
|
99
|
+
"traceback": traceback.format_exc(),
|
|
100
|
+
"timestamp": context.get_current_time()
|
|
101
|
+
if context and hasattr(context, "get_current_time")
|
|
102
|
+
else datetime.now().isoformat(),
|
|
103
|
+
}
|
|
104
|
+
)
|
|
51
105
|
|
|
52
106
|
|
|
53
107
|
def _register_smart_error_analysis_tool(mcp_app: t.Any) -> None:
|
|
@@ -419,43 +419,69 @@ async def _execute_single_iteration(
|
|
|
419
419
|
context: t.Any,
|
|
420
420
|
) -> bool:
|
|
421
421
|
try:
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
if result is None:
|
|
433
|
-
raise ValueError(
|
|
434
|
-
"Method run_complete_workflow returned None instead of awaitable"
|
|
435
|
-
)
|
|
436
|
-
workflow_result: bool = await result
|
|
437
|
-
return workflow_result
|
|
438
|
-
elif hasattr(orchestrator, "execute_workflow"):
|
|
439
|
-
result = orchestrator.execute_workflow(options)
|
|
440
|
-
if result is None:
|
|
441
|
-
raise ValueError(
|
|
442
|
-
"Method execute_workflow returned None instead of awaitable"
|
|
443
|
-
)
|
|
444
|
-
workflow_result: bool = await result
|
|
445
|
-
return workflow_result
|
|
446
|
-
elif hasattr(orchestrator, "run"):
|
|
447
|
-
run_result: bool = orchestrator.run(options)
|
|
448
|
-
return run_result
|
|
449
|
-
else:
|
|
450
|
-
raise ValueError(
|
|
451
|
-
f"Orchestrator {type(orchestrator)} has no recognized workflow execution method"
|
|
452
|
-
)
|
|
422
|
+
method_name = _detect_orchestrator_method(orchestrator)
|
|
423
|
+
result = _invoke_orchestrator_method(orchestrator, method_name, options)
|
|
424
|
+
|
|
425
|
+
# Sync methods return directly, async methods need await
|
|
426
|
+
if method_name == "run":
|
|
427
|
+
return result
|
|
428
|
+
|
|
429
|
+
# Async methods - validate and await
|
|
430
|
+
_validate_awaitable_result(result, method_name, orchestrator)
|
|
431
|
+
return await result
|
|
453
432
|
except Exception as e:
|
|
454
433
|
raise RuntimeError(
|
|
455
434
|
f"Error in _execute_single_iteration (iteration {iteration}): {e}"
|
|
456
435
|
) from e
|
|
457
436
|
|
|
458
437
|
|
|
438
|
+
def _detect_orchestrator_method(orchestrator: t.Any) -> str:
|
|
439
|
+
"""Detect which workflow method the orchestrator supports."""
|
|
440
|
+
method_priority = [
|
|
441
|
+
"run_complete_workflow_async",
|
|
442
|
+
"run_complete_workflow",
|
|
443
|
+
"execute_workflow",
|
|
444
|
+
"run",
|
|
445
|
+
]
|
|
446
|
+
|
|
447
|
+
for method_name in method_priority:
|
|
448
|
+
if hasattr(orchestrator, method_name):
|
|
449
|
+
return method_name
|
|
450
|
+
|
|
451
|
+
available_methods = [m for m in dir(orchestrator) if not m.startswith("_")]
|
|
452
|
+
raise ValueError(
|
|
453
|
+
f"Orchestrator {type(orchestrator).__name__} has no recognized workflow execution method. "
|
|
454
|
+
f"Available methods: {available_methods}"
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _invoke_orchestrator_method(
|
|
459
|
+
orchestrator: t.Any, method_name: str, options: t.Any
|
|
460
|
+
) -> t.Any:
|
|
461
|
+
"""Invoke the detected orchestrator method with options."""
|
|
462
|
+
method = getattr(orchestrator, method_name)
|
|
463
|
+
result = method(options)
|
|
464
|
+
|
|
465
|
+
if result is None:
|
|
466
|
+
raise ValueError(
|
|
467
|
+
f"Method {method_name} returned None instead of expected result. "
|
|
468
|
+
f"Orchestrator type: {type(orchestrator).__name__}"
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
return result
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def _validate_awaitable_result(
|
|
475
|
+
result: t.Any, method_name: str, orchestrator: t.Any
|
|
476
|
+
) -> None:
|
|
477
|
+
"""Validate that async method result is awaitable."""
|
|
478
|
+
if not hasattr(result, "__await__"):
|
|
479
|
+
raise ValueError(
|
|
480
|
+
f"Method {method_name} returned non-awaitable object: {type(result).__name__}. "
|
|
481
|
+
f"Orchestrator: {type(orchestrator).__name__}"
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
|
|
459
485
|
def _create_success_result(
|
|
460
486
|
job_id: str,
|
|
461
487
|
iterations: int,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crackerjack
|
|
3
|
-
Version: 0.39.
|
|
3
|
+
Version: 0.39.6
|
|
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
|
|
@@ -142,17 +142,17 @@ Crackerjack is built on the following core principles:
|
|
|
142
142
|
|
|
143
143
|
## Table of Contents
|
|
144
144
|
|
|
145
|
-
- [Installation]
|
|
146
|
-
- [Quick Start]
|
|
147
|
-
- [AI Auto-Fix Features]
|
|
148
|
-
- [Core
|
|
149
|
-
- [
|
|
150
|
-
- [
|
|
151
|
-
- [
|
|
152
|
-
- [Command Reference]
|
|
153
|
-
- [Style Guide]
|
|
154
|
-
- [Publishing & Version Management]
|
|
155
|
-
- [
|
|
145
|
+
- \[[#installation|Installation]\]
|
|
146
|
+
- \[[#quick-start|Quick Start]\]
|
|
147
|
+
- \[[#ai-auto-fix-features|AI Auto-Fix Features]\]
|
|
148
|
+
- \[[#core-workflow|Core Workflow]\]
|
|
149
|
+
- \[[#core-features|Core Features]\]
|
|
150
|
+
- \[[#mcp-server-configuration|MCP Server Configuration]\]
|
|
151
|
+
- \[[#pre-commit-hook-modes|Pre-commit Hook Modes]\]
|
|
152
|
+
- \[[#command-reference|Command Reference]\]
|
|
153
|
+
- \[[#style-guide|Style Guide]\]
|
|
154
|
+
- \[[#publishing--version-management|Publishing & Version Management]\]
|
|
155
|
+
- \[[#-troubleshooting|Troubleshooting]\]
|
|
156
156
|
|
|
157
157
|
## Installation
|
|
158
158
|
|
|
@@ -116,7 +116,7 @@ crackerjack/mcp/websocket_server.py,sha256=Dsw_orJOSeO7t7zRiVErh8GLp5jAaGab6shOe
|
|
|
116
116
|
crackerjack/mcp/tools/__init__.py,sha256=nV3tGXw4M4p8etZGqxKEglEgFZURGtazQvqwzLJ6VRs,696
|
|
117
117
|
crackerjack/mcp/tools/core_tools.py,sha256=8gytjhqxKglR-ZvLIy0DwJzzaqStex_s9WHiAjkXlD0,14612
|
|
118
118
|
crackerjack/mcp/tools/error_analyzer.py,sha256=8ap3_TIqEfrN0n49w_wJFRE3zu7eHB9E8UyXqqz7unM,8515
|
|
119
|
-
crackerjack/mcp/tools/execution_tools.py,sha256=
|
|
119
|
+
crackerjack/mcp/tools/execution_tools.py,sha256=Cow250ChUxM_gu1jOzBfuOM0ILyZ0M5KJwTaNz1EOTg,12288
|
|
120
120
|
crackerjack/mcp/tools/execution_tools_backup.py,sha256=sWOtid00SkuonFLT2XCtljOGZiibbaIXzEdLWsPrXyI,33351
|
|
121
121
|
crackerjack/mcp/tools/intelligence_tool_registry.py,sha256=eAOBzW3EZTKSz_MeYVzgjD6a1xVZFSXUdgOsgcQLSBk,1262
|
|
122
122
|
crackerjack/mcp/tools/intelligence_tools.py,sha256=HRjX6i3wKKniUbffYZFjRP2PdxsTmDwi4D0SAlsyQDs,9124
|
|
@@ -125,7 +125,7 @@ crackerjack/mcp/tools/proactive_tools.py,sha256=EKTCNS8285p6f3p3bd3AdEGN6OWMvAWn
|
|
|
125
125
|
crackerjack/mcp/tools/progress_tools.py,sha256=S4IkENegGaH06EYNotJ3m2Zuky2OMk-iSd3rLs9T9vs,6930
|
|
126
126
|
crackerjack/mcp/tools/semantic_tools.py,sha256=fPH5AAEyttdJibZzmFYTGlUw079ue2gSvTuHC_ihC_g,18512
|
|
127
127
|
crackerjack/mcp/tools/utility_tools.py,sha256=zt4tES5uhyvZfMdgtStlqItWCBA4MWqGCypQ5u_HPds,10367
|
|
128
|
-
crackerjack/mcp/tools/workflow_executor.py,sha256=
|
|
128
|
+
crackerjack/mcp/tools/workflow_executor.py,sha256=ELrWOZ8DYjhciWbi3JtM0SEYecFQmdzKZGbibYMODG0,20128
|
|
129
129
|
crackerjack/mcp/websocket/__init__.py,sha256=lZzyfvYjywHfqyy5X3wWR_jgBkRUxYSpgjdKALBzZcI,345
|
|
130
130
|
crackerjack/mcp/websocket/app.py,sha256=NGZemhdO4TdFBcA8IvRjpRR1_26FTWBGmOsGVyAD2pY,1339
|
|
131
131
|
crackerjack/mcp/websocket/endpoints.py,sha256=SHP6WEm88DMyZvHrc3i3r0o9IDU06Nvce7qPwr43Sv0,16158
|
|
@@ -235,8 +235,8 @@ crackerjack/tools/validate_input_validator_patterns.py,sha256=NN7smYlXWrHLQXTb-8
|
|
|
235
235
|
crackerjack/tools/validate_regex_patterns.py,sha256=J7GG9EP1fASpRIsG8qRPeiCSkdCwmk0sdo29GgoJ6w8,5863
|
|
236
236
|
crackerjack/ui/__init__.py,sha256=eMb1OeTU-dSLICAACn0YdYB4Amdr8wHckjKfn0wOIZE,37
|
|
237
237
|
crackerjack/ui/server_panels.py,sha256=F5IH6SNN06BaZQMsFx_D-OA286aojmaFPJ5kvvSRv_c,4232
|
|
238
|
-
crackerjack-0.39.
|
|
239
|
-
crackerjack-0.39.
|
|
240
|
-
crackerjack-0.39.
|
|
241
|
-
crackerjack-0.39.
|
|
242
|
-
crackerjack-0.39.
|
|
238
|
+
crackerjack-0.39.6.dist-info/METADATA,sha256=n6eZ4gKgYuzvMYUhUTfXFF-Bk9hdg9GvPo4Ua_nbL1g,38257
|
|
239
|
+
crackerjack-0.39.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
240
|
+
crackerjack-0.39.6.dist-info/entry_points.txt,sha256=AJKNft0WXm9xoGUJ3Trl-iXHOWxRAYbagQiza3AILr4,57
|
|
241
|
+
crackerjack-0.39.6.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
|
|
242
|
+
crackerjack-0.39.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|