crackerjack 0.35.0__py3-none-any.whl → 0.35.2__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/api.py CHANGED
@@ -601,10 +601,10 @@ class CrackerjackAPI:
601
601
  return None
602
602
 
603
603
  def _find_fallback_package_directory(self) -> Path | None:
604
- for possible_name in ("src", self.project_path.name):
605
- package_dir = self.project_path / possible_name
606
- if self._is_valid_python_package_directory(package_dir):
607
- return package_dir
604
+ # Only check project directory name, not src
605
+ package_dir = self.project_path / self.project_path.name
606
+ if self._is_valid_python_package_directory(package_dir):
607
+ return package_dir
608
608
  return None
609
609
 
610
610
  def _is_valid_python_package_directory(self, directory: Path) -> bool:
@@ -424,17 +424,25 @@ class WorkflowPipeline:
424
424
  if self._is_publishing_workflow(options):
425
425
  return False
426
426
 
427
- if not await self._execute_publishing_workflow(options, workflow_id):
427
+ # Execute publishing workflow if requested
428
+ publishing_success = await self._execute_publishing_workflow(
429
+ options, workflow_id
430
+ )
431
+ if not publishing_success:
428
432
  success = False
429
- return False
433
+ # Only return early if publishing was requested but failed
434
+ if options.publish or options.all:
435
+ return False
430
436
 
431
- if not await self._execute_commit_workflow(options, workflow_id):
437
+ # Execute commit workflow independently if requested
438
+ commit_success = await self._execute_commit_workflow(options, workflow_id)
439
+ if not commit_success:
432
440
  success = False
433
441
 
434
442
  return success
435
443
 
436
444
  def _is_publishing_workflow(self, options: OptionsProtocol) -> bool:
437
- return bool(options.publish or options.all or options.commit)
445
+ return bool(options.publish or options.all)
438
446
 
439
447
  async def _execute_publishing_workflow(
440
448
  self, options: OptionsProtocol, workflow_id: str
@@ -1457,7 +1465,7 @@ class WorkflowPipeline:
1457
1465
  def _check_security_gates_for_publishing(
1458
1466
  self, options: OptionsProtocol
1459
1467
  ) -> tuple[bool, bool]:
1460
- publishing_requested = bool(options.publish or options.all or options.commit)
1468
+ publishing_requested = bool(options.publish or options.all)
1461
1469
 
1462
1470
  if not publishing_requested:
1463
1471
  return False, False
@@ -499,13 +499,12 @@ class DynamicConfigGenerator:
499
499
  except Exception:
500
500
  pass
501
501
 
502
- # Fallback to common patterns
503
- for possible_name in ("src", current_dir.name):
504
- if (current_dir / possible_name).exists():
505
- return possible_name
502
+ # Fallback to project directory name
503
+ if (current_dir / current_dir.name).exists():
504
+ return current_dir.name
506
505
 
507
- # Default fallback
508
- return "src"
506
+ # Default fallback to current directory name
507
+ return current_dir.name
509
508
 
510
509
  def _should_include_hook(
511
510
  self,
@@ -565,6 +564,13 @@ class DynamicConfigGenerator:
565
564
  "crackerjack", self.package_directory
566
565
  )
567
566
 
567
+ # Ensure hooks exclude src directories to avoid JavaScript conflicts
568
+ if hook["exclude"]:
569
+ if "src/" not in hook["exclude"]:
570
+ hook["exclude"] = f"{hook['exclude']}|^src/"
571
+ else:
572
+ hook["exclude"] = "^src/"
573
+
568
574
  return hook
569
575
 
570
576
  def group_hooks_by_repo(
@@ -6,6 +6,8 @@ from typing import Final
6
6
 
7
7
  from rich.console import Console
8
8
 
9
+ from ..ui.server_panels import create_server_panels
10
+
9
11
  try:
10
12
  import tomli
11
13
  except ImportError:
@@ -259,18 +261,23 @@ def _print_server_info(
259
261
  websocket_port: int | None,
260
262
  http_mode: bool,
261
263
  ) -> None:
262
- console.print("[green]Starting Crackerjack MCP Server...[/ green]")
263
- console.print(f"Project path: {project_path}")
264
+ panels = create_server_panels(console)
264
265
 
265
266
  if mcp_config.get("http_enabled", False) or http_mode:
266
- console.print(
267
- f"[cyan]HTTP Mode: http: //{mcp_config['http_host']}: {mcp_config['http_port']}/mcp[/ cyan]"
267
+ mode = "HTTP"
268
+ http_endpoint = (
269
+ f"http://{mcp_config['http_host']}:{mcp_config['http_port']}/mcp"
268
270
  )
269
271
  else:
270
- console.print("[cyan]STDIO Mode[/ cyan]")
272
+ mode = "STDIO"
273
+ http_endpoint = None
271
274
 
272
- if websocket_port:
273
- console.print(f"WebSocket port: {websocket_port}")
275
+ panels.start_panel(
276
+ project_path=project_path,
277
+ mode=mode,
278
+ http_endpoint=http_endpoint,
279
+ websocket_port=websocket_port,
280
+ )
274
281
 
275
282
 
276
283
  def _run_mcp_server(
@@ -331,6 +338,26 @@ def main(
331
338
  f"[yellow]⚠️ WebSocket server auto-start failed: {e}[/yellow]"
332
339
  )
333
340
 
341
+ # Show final success panel before starting the server
342
+ panels = create_server_panels(console)
343
+
344
+ if mcp_config.get("http_enabled", False) or http_mode:
345
+ http_endpoint = (
346
+ f"http://{mcp_config['http_host']}:{mcp_config['http_port']}/mcp"
347
+ )
348
+ else:
349
+ http_endpoint = None
350
+
351
+ websocket_monitor = (
352
+ f"ws://127.0.0.1:{websocket_port}" if websocket_port else None
353
+ )
354
+
355
+ panels.success_panel(
356
+ http_endpoint=http_endpoint,
357
+ websocket_monitor=websocket_monitor,
358
+ process_id=None, # Will be set by the process manager
359
+ )
360
+
334
361
  _run_mcp_server(mcp_app, mcp_config, http_mode)
335
362
 
336
363
  except KeyboardInterrupt:
@@ -7,6 +7,7 @@ from pathlib import Path
7
7
 
8
8
  from rich.console import Console
9
9
 
10
+ from ..ui.server_panels import create_server_panels
10
11
  from .secure_subprocess import execute_secure_subprocess
11
12
  from .security_logger import get_security_logger
12
13
 
@@ -201,21 +202,27 @@ def stop_mcp_server(console: Console | None = None) -> bool:
201
202
  if console is None:
202
203
  console = Console()
203
204
 
205
+ panels = create_server_panels(console)
204
206
  processes = find_mcp_server_processes()
205
207
 
206
208
  if not processes:
207
209
  console.print("[yellow]⚠️ No MCP server processes found[/ yellow]")
208
210
  return True
209
211
 
212
+ panels.stop_servers(len(processes))
213
+
210
214
  success = True
211
215
  for proc in processes:
212
- console.print(f"🛑 Stopping MCP server process {proc['pid']}")
216
+ console.print(f"Stopping process {proc['pid']}...")
213
217
  if stop_process(proc["pid"]):
214
- console.print(f"✅ Stopped process {proc['pid']}")
218
+ console.print(f"✅ Process {proc['pid']} terminated gracefully")
215
219
  else:
216
220
  console.print(f"❌ Failed to stop process {proc['pid']}")
217
221
  success = False
218
222
 
223
+ if success:
224
+ panels.stop_complete(len(processes))
225
+
219
226
  return success
220
227
 
221
228
 
@@ -282,14 +289,15 @@ def restart_mcp_server(
282
289
  if console is None:
283
290
  console = Console()
284
291
 
285
- console.print("[bold cyan]🔄 Restarting MCP server...[/ bold cyan]")
292
+ panels = create_server_panels(console)
293
+ panels.restart_header()
286
294
 
287
295
  stop_mcp_server(console)
288
296
 
289
- console.print("⏳ Waiting for cleanup...")
297
+ panels.cleanup_wait()
290
298
  time.sleep(2)
291
299
 
292
- console.print("🚀 Starting new MCP server...")
300
+ panels.starting_server()
293
301
  try:
294
302
  cmd = [sys.executable, "-m", "crackerjack", "--start-mcp-server"]
295
303
  if websocket_port:
@@ -297,7 +305,7 @@ def restart_mcp_server(
297
305
 
298
306
  import subprocess
299
307
 
300
- subprocess.Popen(
308
+ process = subprocess.Popen(
301
309
  cmd,
302
310
  stdout=subprocess.DEVNULL,
303
311
  stderr=subprocess.DEVNULL,
@@ -310,11 +318,24 @@ def restart_mcp_server(
310
318
  purpose="mcp_server_restart",
311
319
  )
312
320
 
313
- console.print("✅ MCP server restart initiated")
321
+ # Give the server a moment to start
322
+ time.sleep(1)
323
+
324
+ # Display success panel with server details
325
+ http_endpoint = "http://127.0.0.1:8676/mcp"
326
+ websocket_monitor = (
327
+ f"ws://127.0.0.1:{websocket_port or 8675}" if websocket_port else None
328
+ )
329
+
330
+ panels.success_panel(
331
+ http_endpoint=http_endpoint,
332
+ websocket_monitor=websocket_monitor,
333
+ process_id=process.pid,
334
+ )
314
335
  return True
315
336
 
316
337
  except Exception as e:
317
- console.print(f"❌ Failed to restart MCP server: {e}")
338
+ panels.failure_panel(str(e))
318
339
  return False
319
340
 
320
341
 
@@ -0,0 +1 @@
1
+ """UI components for Crackerjack."""
@@ -0,0 +1,125 @@
1
+ """Rich panel utilities for MCP server operations with consistent styling."""
2
+
3
+ from pathlib import Path
4
+
5
+ from rich.console import Console
6
+ from rich.panel import Panel
7
+ from rich.text import Text
8
+
9
+
10
+ class ServerPanels:
11
+ """Rich panel utilities for server operations with 74-char width limit."""
12
+
13
+ WIDTH = 74 # Match session-mgmt-mcp width constraint
14
+
15
+ def __init__(self, console: Console | None = None) -> None:
16
+ self.console = console or Console()
17
+
18
+ def restart_header(self) -> None:
19
+ """Display server restart header panel."""
20
+ panel = Panel(
21
+ "🔄 Restarting Crackerjack MCP Server...",
22
+ width=self.WIDTH,
23
+ title="Server Restart",
24
+ style="cyan",
25
+ )
26
+ self.console.print(panel)
27
+
28
+ def stop_servers(self, count: int) -> None:
29
+ """Display stopping servers status."""
30
+ self.console.print("📴 Stopping existing servers...")
31
+ self.console.print(f"🛑 Stopping {count} server process(es)...")
32
+
33
+ def process_stopped(self, pid: int) -> None:
34
+ """Display process stopped message."""
35
+ self.console.print(f"Stopping process {pid}...")
36
+ self.console.print(f"✅ Process {pid} terminated gracefully")
37
+
38
+ def stop_complete(self, count: int) -> None:
39
+ """Display stop completion panel."""
40
+ panel = Panel(
41
+ f"✅ Successfully stopped {count} process(es)",
42
+ width=self.WIDTH,
43
+ title="Server Stopped",
44
+ style="green",
45
+ )
46
+ self.console.print(panel)
47
+
48
+ def cleanup_wait(self) -> None:
49
+ """Display cleanup waiting message."""
50
+ self.console.print("⏳ Waiting for cleanup...")
51
+
52
+ def starting_server(self) -> None:
53
+ """Display starting server message."""
54
+ self.console.print("🚀 Starting fresh server instance...")
55
+ self.console.print("🚀 Starting Crackerjack MCP Server...")
56
+ self.console.print("⏳ Waiting for server to start...")
57
+
58
+ def success_panel(
59
+ self,
60
+ http_endpoint: str | None = None,
61
+ websocket_monitor: str | None = None,
62
+ process_id: int | None = None,
63
+ ) -> None:
64
+ """Display success panel with server details."""
65
+ content = Text()
66
+ content.append("✅ Server started successfully!\n", style="green bold")
67
+
68
+ if http_endpoint:
69
+ content.append(f"🌐 HTTP Endpoint: {http_endpoint}\n", style="cyan")
70
+
71
+ if websocket_monitor:
72
+ content.append(f"🔌 WebSocket Monitor: {websocket_monitor}\n", style="cyan")
73
+
74
+ if process_id:
75
+ content.append(f"📊 Process ID: {process_id}", style="cyan")
76
+
77
+ panel = Panel(
78
+ content,
79
+ width=self.WIDTH,
80
+ title="Crackerjack MCP Server",
81
+ style="green",
82
+ )
83
+ self.console.print(panel)
84
+
85
+ def failure_panel(self, error: str) -> None:
86
+ """Display failure panel with error details."""
87
+ panel = Panel(
88
+ f"❌ Server failed to start: {error}",
89
+ width=self.WIDTH,
90
+ title="Server Error",
91
+ style="red",
92
+ )
93
+ self.console.print(panel)
94
+
95
+ def start_panel(
96
+ self,
97
+ project_path: Path,
98
+ mode: str = "STDIO",
99
+ http_endpoint: str | None = None,
100
+ websocket_port: int | None = None,
101
+ ) -> None:
102
+ """Display server start panel with configuration details."""
103
+ content = Text()
104
+ content.append("🚀 Starting Crackerjack MCP Server...\n", style="green bold")
105
+ content.append(f"📁 Project: {project_path.name}\n", style="cyan")
106
+ content.append(f"🔗 Mode: {mode}\n", style="cyan")
107
+
108
+ if http_endpoint:
109
+ content.append(f"🌐 HTTP: {http_endpoint}\n", style="cyan")
110
+
111
+ if websocket_port:
112
+ content.append(f"🔌 WebSocket: {websocket_port}", style="cyan")
113
+
114
+ panel = Panel(
115
+ content,
116
+ width=self.WIDTH,
117
+ title="Server Configuration",
118
+ style="green",
119
+ )
120
+ self.console.print(panel)
121
+
122
+
123
+ def create_server_panels(console: Console | None = None) -> ServerPanels:
124
+ """Factory function to create ServerPanels instance."""
125
+ return ServerPanels(console)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crackerjack
3
- Version: 0.35.0
3
+ Version: 0.35.2
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
@@ -1,8 +1,8 @@
1
1
  crackerjack/__init__.py,sha256=k8_Ev_3fWdjFtGNSJdSOvyaSLW54y3j484d3a8k_Ob4,1396
2
2
  crackerjack/__main__.py,sha256=lE5ZDbAzI9TLCzMTxFGw23Dk1hP-MEhd1i_nNbi_Mag,52515
3
- crackerjack/api.py,sha256=hXWqk9qLxYley6NiIIz9RemYhxC67cwwbktQdV1IPPY,21550
3
+ crackerjack/api.py,sha256=sfKzCphsTMFCvdNizviPdYemwg0H8Oei_5C08LAuDvA,21538
4
4
  crackerjack/code_cleaner.py,sha256=M1zVaq31uW0nOkPneKR8kfR3892gyyVx0VhFgRaxsj4,44338
5
- crackerjack/dynamic_config.py,sha256=DOfq5Qjkfcww7qW9Q-MDOCn-TSUu6sZWMpZ4rbaFn40,21564
5
+ crackerjack/dynamic_config.py,sha256=YGlUyTEp_K9rGWtLsboXMtVeKyI7bUoNoftO3ZnCiwc,21815
6
6
  crackerjack/errors.py,sha256=yYbZ92kn_y6acEWgQvEPvozAYs2HT65uLwAXrtXxGsE,10049
7
7
  crackerjack/interactive.py,sha256=QXFZrnbY0nc8rFJcivFAVFNgUTHXqLCu3FFv5bmq_eI,21634
8
8
  crackerjack/adapters/__init__.py,sha256=k-8ajMDL9DS9hV2FYOu694nmNQg3HkudJRuNcXmx8N4,451
@@ -54,7 +54,7 @@ crackerjack/core/service_watchdog.py,sha256=Ttj1imOxvUea4Tkf5JO1e2dQtGIK7D-bX1xO
54
54
  crackerjack/core/session_coordinator.py,sha256=TgoGE9DfXe2x-OkH93Ld9dX9ROjx2_mZFkGXen-z5YI,15680
55
55
  crackerjack/core/timeout_manager.py,sha256=_sbEsfYDwWx7y0Pn89QCoAZ5DpWIbCdtR9qkG_Kqj5E,15013
56
56
  crackerjack/core/websocket_lifecycle.py,sha256=74kn6ugu6FLlDQhCNSPgqguCFwRoT1WFOvtl8G2OyFc,12860
57
- crackerjack/core/workflow_orchestrator.py,sha256=NgvOn6pTVV8aULxe-bbwT6GeIELRc-KNXU7bYKroGV8,70162
57
+ crackerjack/core/workflow_orchestrator.py,sha256=nMbxxeHzecZBeNk5Do0SJfFGX5UvZXp6H2yPwr2bty4,70470
58
58
  crackerjack/docs/INDEX.md,sha256=a6CGFEeL5DX_FRft_JFWd0nOxoBmCSSp-QHIC3B7ato,342
59
59
  crackerjack/docs/generated/api/API_REFERENCE.md,sha256=mWoqImZA7AhDvRqqF1MhUo70g_pnZr3NoBeZQRotqN8,155816
60
60
  crackerjack/docs/generated/api/CLI_REFERENCE.md,sha256=ikuG0hO5EjIiQlJtAUnvEuAhXDa-JHPULPXNNmUwvk4,2805
@@ -101,7 +101,7 @@ crackerjack/mcp/progress_components.py,sha256=URtnrNv1QQzUKY3msO_cBrYHjPlzVDqFbZ
101
101
  crackerjack/mcp/progress_monitor.py,sha256=3TxQ_Og1md8zuNrH9cltOa8RQf_5lHNiVh9DiBkvbBM,37546
102
102
  crackerjack/mcp/rate_limiter.py,sha256=oM29wHyvoR9Q9cMBAEqWquHoiBBS1ylrZkUhhFnDkVo,12309
103
103
  crackerjack/mcp/server.py,sha256=-AdHHoFNAtoPM1A3_M2giZbIbggUhhvv16uIXk2xqNo,403
104
- crackerjack/mcp/server_core.py,sha256=c1R_X8U2t1B0_4ZfJEHy_e2AXMF6vr9e6KtNGvorytc,10589
104
+ crackerjack/mcp/server_core.py,sha256=o93_j8nmGRIl-FL-Y5cKCDDJh3J7vTi1SmxIOdoqj0w,11301
105
105
  crackerjack/mcp/service_watchdog.py,sha256=_z99JrYrmVaXI2tVERts0_xHsl4pjltD5iF47mQVADk,16826
106
106
  crackerjack/mcp/state.py,sha256=pNclwUxGTH5YiRMq8hB15B9_rpX9aJ-IVnhMw7q9dtI,14427
107
107
  crackerjack/mcp/task_manager.py,sha256=hxuZGbRHwEBO-W3UTbg7Lx7gMhTcPRaAiQ8I8VIFs6g,8713
@@ -202,7 +202,7 @@ crackerjack/services/secure_status_formatter.py,sha256=yhwNtzvvQVcuHsNOTNZMzlqIM
202
202
  crackerjack/services/secure_subprocess.py,sha256=upuiBL0sYIElC8DWQ622-A6572zBaSBoMPVnNM8AeaQ,19838
203
203
  crackerjack/services/security.py,sha256=plgIz-B8oYN_mpF4NYrqHnT7TRcsp4jr0-YlV9WgD5o,7298
204
204
  crackerjack/services/security_logger.py,sha256=AAjd9VKVmCo158UifyEKd79VgtWKeuaIVyXYL8qvqT8,17001
205
- crackerjack/services/server_manager.py,sha256=IQ0oUFEEMZTxI8csecIJzkCSMESE5KIkYqPxa56tvUw,11399
205
+ crackerjack/services/server_manager.py,sha256=MwvMMxhaCiZD4pcKM2ODXB-gu2s22n_v_uIqrwoJsHs,11934
206
206
  crackerjack/services/smart_scheduling.py,sha256=VSaL7DpKR6aa0sC_TUrYP9ZgC9CB7tE3TTNzEqB-GpE,4352
207
207
  crackerjack/services/status_authentication.py,sha256=2OJ1MoWlBuvUUXOX02N_zdWKzQfXz4jhEZpsmIJfQ00,16453
208
208
  crackerjack/services/status_security_manager.py,sha256=et0h6w7Wt1cPFjzg7frsykAQ-IMfiAXr44WU9Fs6-1U,10967
@@ -222,8 +222,10 @@ crackerjack/slash_commands/status.md,sha256=U3qqppVLtIIm2lEiMYaKagaHYLI9UplL7OH1
222
222
  crackerjack/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
223
223
  crackerjack/tools/validate_input_validator_patterns.py,sha256=NN7smYlXWrHLQXTb-81gRam2vjW-cJav92f1klPA0qA,8234
224
224
  crackerjack/tools/validate_regex_patterns.py,sha256=9ejFb7Tw1js_oydzuEeeeXvrU5ipHUEX9ATBfkLCCE8,5811
225
- crackerjack-0.35.0.dist-info/METADATA,sha256=oX8q8fSrssEUsiGO6fkHjuTfDDsj6jw3aYRauYM4qpM,37942
226
- crackerjack-0.35.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
227
- crackerjack-0.35.0.dist-info/entry_points.txt,sha256=AJKNft0WXm9xoGUJ3Trl-iXHOWxRAYbagQiza3AILr4,57
228
- crackerjack-0.35.0.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
229
- crackerjack-0.35.0.dist-info/RECORD,,
225
+ crackerjack/ui/__init__.py,sha256=eMb1OeTU-dSLICAACn0YdYB4Amdr8wHckjKfn0wOIZE,37
226
+ crackerjack/ui/server_panels.py,sha256=F5IH6SNN06BaZQMsFx_D-OA286aojmaFPJ5kvvSRv_c,4232
227
+ crackerjack-0.35.2.dist-info/METADATA,sha256=nRxM91j9awHMHtKkvW6DU77MOJKZxJpPWUlxjZ1Af08,37942
228
+ crackerjack-0.35.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
229
+ crackerjack-0.35.2.dist-info/entry_points.txt,sha256=AJKNft0WXm9xoGUJ3Trl-iXHOWxRAYbagQiza3AILr4,57
230
+ crackerjack-0.35.2.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
231
+ crackerjack-0.35.2.dist-info/RECORD,,