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
crackerjack/dynamic_config.py
CHANGED
|
@@ -5,30 +5,6 @@ from pathlib import Path
|
|
|
5
5
|
import jinja2
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def _get_project_root() -> Path:
|
|
9
|
-
"""Get the absolute path to the crackerjack project root."""
|
|
10
|
-
# Start from this file and go up to find the real project root
|
|
11
|
-
current_path = Path(__file__).resolve()
|
|
12
|
-
for parent in current_path.parents:
|
|
13
|
-
if (parent / "pyproject.toml").exists() and (parent / "tools").exists():
|
|
14
|
-
# Verify it's the crackerjack project by checking for unique markers and tools dir
|
|
15
|
-
try:
|
|
16
|
-
pyproject_content = (parent / "pyproject.toml").read_text()
|
|
17
|
-
if (
|
|
18
|
-
'name = "crackerjack"' in pyproject_content
|
|
19
|
-
and (
|
|
20
|
-
parent / "tools" / "validate_regex_patterns_standalone.py"
|
|
21
|
-
).exists()
|
|
22
|
-
):
|
|
23
|
-
return parent
|
|
24
|
-
except Exception:
|
|
25
|
-
# If we can't read the file, continue searching
|
|
26
|
-
continue
|
|
27
|
-
|
|
28
|
-
# Fallback to the parent of the crackerjack package directory
|
|
29
|
-
return Path(__file__).resolve().parent.parent
|
|
30
|
-
|
|
31
|
-
|
|
32
8
|
class HookMetadata(t.TypedDict):
|
|
33
9
|
id: str
|
|
34
10
|
name: str | None
|
|
@@ -70,7 +46,7 @@ HOOKS_REGISTRY: dict[str, list[HookMetadata]] = {
|
|
|
70
46
|
"additional_dependencies": None,
|
|
71
47
|
"types_or": None,
|
|
72
48
|
"language": "system",
|
|
73
|
-
"entry":
|
|
49
|
+
"entry": "uv run python -m crackerjack.tools.validate_regex_patterns",
|
|
74
50
|
"experimental": False,
|
|
75
51
|
},
|
|
76
52
|
{
|
|
@@ -5,17 +5,34 @@ from pathlib import Path
|
|
|
5
5
|
|
|
6
6
|
from rich.console import Console
|
|
7
7
|
|
|
8
|
-
from crackerjack.
|
|
9
|
-
from crackerjack.services.security import SecurityService
|
|
8
|
+
from crackerjack.models.protocols import FileSystemInterface, SecurityServiceProtocol
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class PublishManagerImpl:
|
|
13
|
-
def __init__(
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
console: Console,
|
|
15
|
+
pkg_path: Path,
|
|
16
|
+
dry_run: bool = False,
|
|
17
|
+
filesystem: FileSystemInterface | None = None,
|
|
18
|
+
security: SecurityServiceProtocol | None = None,
|
|
19
|
+
) -> None:
|
|
14
20
|
self.console = console
|
|
15
21
|
self.pkg_path = pkg_path
|
|
16
22
|
self.dry_run = dry_run
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
|
|
24
|
+
if filesystem is None:
|
|
25
|
+
from crackerjack.services.filesystem import FileSystemService
|
|
26
|
+
|
|
27
|
+
filesystem = FileSystemService()
|
|
28
|
+
|
|
29
|
+
if security is None:
|
|
30
|
+
from crackerjack.services.security import SecurityService
|
|
31
|
+
|
|
32
|
+
security = SecurityService()
|
|
33
|
+
|
|
34
|
+
self.filesystem = filesystem
|
|
35
|
+
self.security = security
|
|
19
36
|
|
|
20
37
|
def _run_command(
|
|
21
38
|
self,
|
|
@@ -8,7 +8,7 @@ class TestCommandBuilder:
|
|
|
8
8
|
self.pkg_path = pkg_path
|
|
9
9
|
|
|
10
10
|
def build_command(self, options: OptionsProtocol) -> list[str]:
|
|
11
|
-
cmd = ["python", "-m", "pytest"]
|
|
11
|
+
cmd = ["uv", "run", "python", "-m", "pytest"]
|
|
12
12
|
|
|
13
13
|
self._add_coverage_options(cmd, options)
|
|
14
14
|
self._add_worker_options(cmd, options)
|
|
@@ -23,17 +23,21 @@ class TestCommandBuilder:
|
|
|
23
23
|
if hasattr(options, "test_workers") and options.test_workers:
|
|
24
24
|
return options.test_workers
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
# Temporarily disable multi-worker execution due to pytest-xdist
|
|
27
|
+
# hanging issues with async tests. See GitHub issue for details.
|
|
28
|
+
# TODO: Re-enable after fixing async test timeout issues
|
|
29
|
+
return 1
|
|
30
|
+
|
|
31
|
+
# Original multi-worker logic (commented out):
|
|
32
|
+
# import multiprocessing
|
|
33
|
+
# cpu_count = multiprocessing.cpu_count()
|
|
34
|
+
# if cpu_count <= 2:
|
|
35
|
+
# return 1
|
|
36
|
+
# elif cpu_count <= 4:
|
|
37
|
+
# return 2
|
|
38
|
+
# elif cpu_count <= 8:
|
|
39
|
+
# return 3
|
|
40
|
+
# return 4
|
|
37
41
|
|
|
38
42
|
def get_test_timeout(self, options: OptionsProtocol) -> int:
|
|
39
43
|
if hasattr(options, "test_timeout") and options.test_timeout:
|
|
@@ -95,7 +99,7 @@ class TestCommandBuilder:
|
|
|
95
99
|
cmd.append(str(self.pkg_path))
|
|
96
100
|
|
|
97
101
|
def build_specific_test_command(self, test_pattern: str) -> list[str]:
|
|
98
|
-
cmd = ["python", "-m", "pytest", "-v"]
|
|
102
|
+
cmd = ["uv", "run", "python", "-m", "pytest", "-v"]
|
|
99
103
|
|
|
100
104
|
cmd.extend(
|
|
101
105
|
[
|
|
@@ -112,6 +116,8 @@ class TestCommandBuilder:
|
|
|
112
116
|
|
|
113
117
|
def build_validation_command(self) -> list[str]:
|
|
114
118
|
return [
|
|
119
|
+
"uv",
|
|
120
|
+
"run",
|
|
115
121
|
"python",
|
|
116
122
|
"-m",
|
|
117
123
|
"pytest",
|
|
@@ -5,21 +5,32 @@ from pathlib import Path
|
|
|
5
5
|
|
|
6
6
|
from rich.console import Console
|
|
7
7
|
|
|
8
|
-
from crackerjack.models.protocols import OptionsProtocol
|
|
9
|
-
from crackerjack.services.coverage_ratchet import CoverageRatchetService
|
|
8
|
+
from crackerjack.models.protocols import CoverageRatchetProtocol, OptionsProtocol
|
|
10
9
|
|
|
11
10
|
from .test_command_builder import TestCommandBuilder
|
|
12
11
|
from .test_executor import TestExecutor
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class TestManager:
|
|
16
|
-
def __init__(
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
console: Console,
|
|
18
|
+
pkg_path: Path,
|
|
19
|
+
coverage_ratchet: CoverageRatchetProtocol | None = None,
|
|
20
|
+
) -> None:
|
|
17
21
|
self.console = console
|
|
18
22
|
self.pkg_path = pkg_path
|
|
19
23
|
|
|
20
24
|
self.executor = TestExecutor(console, pkg_path)
|
|
21
25
|
self.command_builder = TestCommandBuilder(pkg_path)
|
|
22
|
-
|
|
26
|
+
|
|
27
|
+
if coverage_ratchet is None:
|
|
28
|
+
# Import here to avoid circular imports
|
|
29
|
+
from crackerjack.services.coverage_ratchet import CoverageRatchetService
|
|
30
|
+
|
|
31
|
+
coverage_ratchet = CoverageRatchetService(pkg_path, console)
|
|
32
|
+
|
|
33
|
+
self.coverage_ratchet = coverage_ratchet
|
|
23
34
|
|
|
24
35
|
self._last_test_failures: list[str] = []
|
|
25
36
|
self._progress_callback: t.Callable[[dict[str, t.Any]], None] | None = None
|
crackerjack/mcp/server_core.py
CHANGED
|
@@ -7,7 +7,12 @@ from typing import Final
|
|
|
7
7
|
from rich.console import Console
|
|
8
8
|
|
|
9
9
|
try:
|
|
10
|
-
|
|
10
|
+
import tomli
|
|
11
|
+
except ImportError:
|
|
12
|
+
tomli = None
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from fastmcp import FastMCP
|
|
11
16
|
|
|
12
17
|
_mcp_available = True
|
|
13
18
|
except ImportError:
|
|
@@ -37,6 +42,42 @@ from .tools import (
|
|
|
37
42
|
console = Console()
|
|
38
43
|
|
|
39
44
|
|
|
45
|
+
def _load_mcp_config(project_path: Path) -> dict[str, t.Any]:
|
|
46
|
+
"""Load MCP server configuration from pyproject.toml."""
|
|
47
|
+
pyproject_path = project_path / "pyproject.toml"
|
|
48
|
+
|
|
49
|
+
if not pyproject_path.exists() or not tomli:
|
|
50
|
+
return {
|
|
51
|
+
"http_port": 8676,
|
|
52
|
+
"http_host": "127.0.0.1",
|
|
53
|
+
"websocket_port": 8675,
|
|
54
|
+
"http_enabled": False,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
with pyproject_path.open("rb") as f:
|
|
59
|
+
pyproject_data = tomli.load(f)
|
|
60
|
+
|
|
61
|
+
crackerjack_config = pyproject_data.get("tool", {}).get("crackerjack", {})
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
"http_port": crackerjack_config.get("mcp_http_port", 8676),
|
|
65
|
+
"http_host": crackerjack_config.get("mcp_http_host", "127.0.0.1"),
|
|
66
|
+
"websocket_port": crackerjack_config.get("mcp_websocket_port", 8675),
|
|
67
|
+
"http_enabled": crackerjack_config.get("mcp_http_enabled", False),
|
|
68
|
+
}
|
|
69
|
+
except Exception as e:
|
|
70
|
+
console.print(
|
|
71
|
+
f"[yellow]Warning: Failed to load MCP config from pyproject.toml: {e}[/yellow]"
|
|
72
|
+
)
|
|
73
|
+
return {
|
|
74
|
+
"http_port": 8676,
|
|
75
|
+
"http_host": "127.0.0.1",
|
|
76
|
+
"websocket_port": 8675,
|
|
77
|
+
"http_enabled": False,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
40
81
|
class MCPOptions:
|
|
41
82
|
def __init__(self, **kwargs: t.Any) -> None:
|
|
42
83
|
self.commit: bool = False
|
|
@@ -77,11 +118,14 @@ async def _start_websocket_server() -> bool:
|
|
|
77
118
|
return False
|
|
78
119
|
|
|
79
120
|
|
|
80
|
-
def create_mcp_server() -> t.Any | None:
|
|
121
|
+
def create_mcp_server(config: dict[str, t.Any] | None = None) -> t.Any | None:
|
|
81
122
|
if not MCP_AVAILABLE or FastMCP is None:
|
|
82
123
|
return None
|
|
83
124
|
|
|
84
|
-
|
|
125
|
+
if config is None:
|
|
126
|
+
config = {"http_port": 8676, "http_host": "127.0.0.1"}
|
|
127
|
+
|
|
128
|
+
mcp_app = FastMCP("crackerjack-mcp-server", streamable_http_path="/mcp")
|
|
85
129
|
|
|
86
130
|
from crackerjack.slash_commands import get_slash_command_path
|
|
87
131
|
|
|
@@ -128,6 +172,8 @@ def handle_mcp_server_command(
|
|
|
128
172
|
stop: bool = False,
|
|
129
173
|
restart: bool = False,
|
|
130
174
|
websocket_port: int | None = None,
|
|
175
|
+
http_mode: bool = False,
|
|
176
|
+
http_port: int | None = None,
|
|
131
177
|
) -> None:
|
|
132
178
|
if stop or restart:
|
|
133
179
|
console.print("[yellow]Stopping MCP servers...[/ yellow]")
|
|
@@ -157,7 +203,7 @@ def handle_mcp_server_command(
|
|
|
157
203
|
if start or restart:
|
|
158
204
|
console.print("[green]Starting MCP server...[/ green]")
|
|
159
205
|
try:
|
|
160
|
-
main(".", websocket_port)
|
|
206
|
+
main(".", websocket_port, http_mode, http_port)
|
|
161
207
|
except Exception as e:
|
|
162
208
|
console.print(f"[red]Failed to start MCP server: {e}[/ red]")
|
|
163
209
|
|
|
@@ -177,45 +223,111 @@ def _stop_websocket_server() -> None:
|
|
|
177
223
|
pass
|
|
178
224
|
|
|
179
225
|
|
|
180
|
-
def
|
|
226
|
+
def _merge_config_with_args(
|
|
227
|
+
mcp_config: dict[str, t.Any],
|
|
228
|
+
http_port: int | None,
|
|
229
|
+
http_mode: bool,
|
|
230
|
+
) -> dict[str, t.Any]:
|
|
231
|
+
"""Merge MCP configuration with command line arguments."""
|
|
232
|
+
if http_port:
|
|
233
|
+
mcp_config["http_port"] = http_port
|
|
234
|
+
if http_mode:
|
|
235
|
+
mcp_config["http_enabled"] = True
|
|
236
|
+
return mcp_config
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _setup_server_context(
|
|
240
|
+
project_path: Path,
|
|
241
|
+
websocket_port: int | None,
|
|
242
|
+
) -> MCPServerContext:
|
|
243
|
+
"""Set up and initialize the MCP server context."""
|
|
244
|
+
config = MCPServerConfig(
|
|
245
|
+
project_path=project_path,
|
|
246
|
+
rate_limit_config=RateLimitConfig(),
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
context = MCPServerContext(config)
|
|
250
|
+
context.console = console
|
|
251
|
+
|
|
252
|
+
if websocket_port:
|
|
253
|
+
context.websocket_server_port = websocket_port
|
|
254
|
+
|
|
255
|
+
_initialize_context(context)
|
|
256
|
+
return context
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _print_server_info(
|
|
260
|
+
project_path: Path,
|
|
261
|
+
mcp_config: dict[str, t.Any],
|
|
262
|
+
websocket_port: int | None,
|
|
263
|
+
http_mode: bool,
|
|
264
|
+
) -> None:
|
|
265
|
+
"""Print server startup information."""
|
|
266
|
+
console.print("[green]Starting Crackerjack MCP Server...[/ green]")
|
|
267
|
+
console.print(f"Project path: {project_path}")
|
|
268
|
+
|
|
269
|
+
if mcp_config.get("http_enabled", False) or http_mode:
|
|
270
|
+
console.print(
|
|
271
|
+
f"[cyan]HTTP Mode: http://{mcp_config['http_host']}:{mcp_config['http_port']}/mcp[/ cyan]"
|
|
272
|
+
)
|
|
273
|
+
else:
|
|
274
|
+
console.print("[cyan]STDIO Mode[/ cyan]")
|
|
275
|
+
|
|
276
|
+
if websocket_port:
|
|
277
|
+
console.print(f"WebSocket port: {websocket_port}")
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _run_mcp_server(
|
|
281
|
+
mcp_app: t.Any, mcp_config: dict[str, t.Any], http_mode: bool
|
|
282
|
+
) -> None:
|
|
283
|
+
"""Execute the MCP server with appropriate transport mode."""
|
|
284
|
+
console.print("[yellow]MCP app created, about to run...[/ yellow]")
|
|
285
|
+
|
|
286
|
+
try:
|
|
287
|
+
if mcp_config.get("http_enabled", False) or http_mode:
|
|
288
|
+
host = mcp_config.get("http_host", "127.0.0.1")
|
|
289
|
+
port = mcp_config.get("http_port", 8676)
|
|
290
|
+
mcp_app.run(transport="streamable-http", host=host, port=port)
|
|
291
|
+
else:
|
|
292
|
+
mcp_app.run()
|
|
293
|
+
except Exception as e:
|
|
294
|
+
console.print(f"[red]MCP run failed: {e}[/ red]")
|
|
295
|
+
import traceback
|
|
296
|
+
|
|
297
|
+
traceback.print_exc()
|
|
298
|
+
raise
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def main(
|
|
302
|
+
project_path_arg: str = ".",
|
|
303
|
+
websocket_port: int | None = None,
|
|
304
|
+
http_mode: bool = False,
|
|
305
|
+
http_port: int | None = None,
|
|
306
|
+
) -> None:
|
|
181
307
|
if not MCP_AVAILABLE:
|
|
182
308
|
return
|
|
183
309
|
|
|
184
310
|
try:
|
|
185
311
|
project_path = Path(project_path_arg).resolve()
|
|
186
312
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
context = MCPServerContext(config)
|
|
193
|
-
context.console = console
|
|
313
|
+
# Load and merge configuration
|
|
314
|
+
mcp_config = _load_mcp_config(project_path)
|
|
315
|
+
mcp_config = _merge_config_with_args(mcp_config, http_port, http_mode)
|
|
194
316
|
|
|
195
|
-
|
|
196
|
-
|
|
317
|
+
# Set up server context
|
|
318
|
+
_setup_server_context(project_path, websocket_port)
|
|
197
319
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
mcp_app = create_mcp_server()
|
|
320
|
+
# Create MCP server
|
|
321
|
+
mcp_app = create_mcp_server(mcp_config)
|
|
201
322
|
if not mcp_app:
|
|
202
323
|
console.print("[red]Failed to create MCP server[/ red]")
|
|
203
324
|
return
|
|
204
325
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if websocket_port:
|
|
208
|
-
console.print(f"WebSocket port: {websocket_port}")
|
|
326
|
+
# Print server information
|
|
327
|
+
_print_server_info(project_path, mcp_config, websocket_port, http_mode)
|
|
209
328
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
mcp_app.run()
|
|
213
|
-
except Exception as e:
|
|
214
|
-
console.print(f"[red]MCP run failed: {e}[/ red]")
|
|
215
|
-
import traceback
|
|
216
|
-
|
|
217
|
-
traceback.print_exc()
|
|
218
|
-
raise
|
|
329
|
+
# Run the server
|
|
330
|
+
_run_mcp_server(mcp_app, mcp_config, http_mode)
|
|
219
331
|
|
|
220
332
|
except KeyboardInterrupt:
|
|
221
333
|
console.print("Server stopped by user")
|
|
@@ -232,7 +344,23 @@ def main(project_path_arg: str = ".", websocket_port: int | None = None) -> None
|
|
|
232
344
|
if __name__ == "__main__":
|
|
233
345
|
import sys
|
|
234
346
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
347
|
+
# Initialize defaults
|
|
348
|
+
project_path = "."
|
|
349
|
+
websocket_port = None
|
|
350
|
+
http_mode = "--http" in sys.argv
|
|
351
|
+
http_port = None
|
|
352
|
+
|
|
353
|
+
# Parse project path from non-flag arguments
|
|
354
|
+
non_flag_args = [arg for arg in sys.argv[1:] if not arg.startswith("--")]
|
|
355
|
+
if non_flag_args:
|
|
356
|
+
project_path = non_flag_args[0]
|
|
357
|
+
if len(non_flag_args) > 1 and non_flag_args[1].isdigit():
|
|
358
|
+
websocket_port = int(non_flag_args[1])
|
|
359
|
+
|
|
360
|
+
# Parse HTTP port flag
|
|
361
|
+
if "--http-port" in sys.argv:
|
|
362
|
+
port_idx = sys.argv.index("--http-port")
|
|
363
|
+
if port_idx + 1 < len(sys.argv):
|
|
364
|
+
http_port = int(sys.argv[port_idx + 1])
|
|
365
|
+
|
|
366
|
+
main(project_path, websocket_port, http_mode, http_port)
|
|
@@ -186,7 +186,7 @@ def _execute_init_stage(orchestrator) -> bool:
|
|
|
186
186
|
|
|
187
187
|
init_service = InitializationService(console, filesystem, git_service, pkg_path)
|
|
188
188
|
|
|
189
|
-
results = init_service.
|
|
189
|
+
results = init_service.initialize_project_full(target_path=Path.cwd())
|
|
190
190
|
|
|
191
191
|
return results.get("success", False)
|
|
192
192
|
|
|
@@ -29,6 +29,14 @@ def _register_execute_crackerjack_tool(mcp_app: t.Any) -> None:
|
|
|
29
29
|
|
|
30
30
|
extra_kwargs = kwargs_result["kwargs"]
|
|
31
31
|
|
|
32
|
+
# Add extended timeout for long-running operations
|
|
33
|
+
if "execution_timeout" not in extra_kwargs:
|
|
34
|
+
# Default to 15 minutes, extend to 20 minutes for test operations
|
|
35
|
+
if extra_kwargs.get("test", False) or extra_kwargs.get("testing", False):
|
|
36
|
+
extra_kwargs["execution_timeout"] = 1200 # 20 minutes for tests
|
|
37
|
+
else:
|
|
38
|
+
extra_kwargs["execution_timeout"] = 900 # 15 minutes default
|
|
39
|
+
|
|
32
40
|
try:
|
|
33
41
|
result = await execute_crackerjack_workflow(args, extra_kwargs)
|
|
34
42
|
return json.dumps(result, indent=2)
|
|
@@ -153,9 +161,14 @@ def _execute_initialization(target_path: t.Any, force: bool) -> dict[str, t.Any]
|
|
|
153
161
|
|
|
154
162
|
console = Console()
|
|
155
163
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
164
|
+
from crackerjack.services.filesystem import FileSystemService
|
|
165
|
+
from crackerjack.services.git import GitService
|
|
166
|
+
|
|
167
|
+
filesystem = FileSystemService()
|
|
168
|
+
git_service = GitService()
|
|
169
|
+
return InitializationService(
|
|
170
|
+
console, filesystem, git_service, target_path
|
|
171
|
+
).initialize_project_full(force=force)
|
|
159
172
|
|
|
160
173
|
|
|
161
174
|
def _create_init_error_response(message: str) -> str:
|