machineconfig 1.97__py3-none-any.whl → 2.1__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 machineconfig might be problematic. Click here for more details.
- machineconfig/cluster/cloud_manager.py +22 -29
- machineconfig/cluster/data_transfer.py +2 -3
- machineconfig/cluster/distribute.py +0 -2
- machineconfig/cluster/file_manager.py +4 -5
- machineconfig/cluster/job_params.py +1 -4
- machineconfig/cluster/loader_runner.py +8 -11
- machineconfig/cluster/remote_machine.py +4 -5
- machineconfig/cluster/script_execution.py +2 -2
- machineconfig/cluster/script_notify_upon_completion.py +0 -1
- machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +4 -6
- machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -1
- machineconfig/cluster/sessions_managers/enhanced_command_runner.py +35 -75
- machineconfig/cluster/sessions_managers/wt_local.py +113 -185
- machineconfig/cluster/sessions_managers/wt_local_manager.py +127 -197
- machineconfig/cluster/sessions_managers/wt_remote.py +60 -67
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +110 -149
- machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +61 -64
- machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +72 -172
- machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +27 -60
- machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +58 -137
- machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +46 -74
- machineconfig/cluster/sessions_managers/zellij_local.py +91 -147
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +165 -190
- machineconfig/cluster/sessions_managers/zellij_remote.py +51 -58
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +40 -46
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +19 -17
- machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +30 -31
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +64 -134
- machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +7 -11
- machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +27 -55
- machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +14 -13
- machineconfig/cluster/templates/cli_click.py +0 -1
- machineconfig/cluster/templates/cli_gooey.py +0 -2
- machineconfig/cluster/templates/cli_trogon.py +0 -1
- machineconfig/cluster/templates/run_cloud.py +0 -1
- machineconfig/cluster/templates/run_cluster.py +0 -1
- machineconfig/cluster/templates/run_remote.py +0 -1
- machineconfig/cluster/templates/utils.py +27 -11
- machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
- machineconfig/jobs/python/check_installations.py +9 -9
- machineconfig/jobs/python/create_bootable_media.py +0 -2
- machineconfig/jobs/python/python_cargo_build_share.py +2 -2
- machineconfig/jobs/python/python_ve_symlink.py +9 -11
- machineconfig/jobs/python/tasks.py +0 -1
- machineconfig/jobs/python/vscode/api.py +5 -5
- machineconfig/jobs/python/vscode/link_ve.py +20 -21
- machineconfig/jobs/python/vscode/select_interpreter.py +28 -29
- machineconfig/jobs/python/vscode/sync_code.py +14 -18
- machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_custom_installers/archive/ngrok.py +15 -15
- machineconfig/jobs/python_custom_installers/dev/aider.py +10 -18
- machineconfig/jobs/python_custom_installers/dev/alacritty.py +12 -21
- machineconfig/jobs/python_custom_installers/dev/brave.py +13 -22
- machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +13 -20
- machineconfig/jobs/python_custom_installers/dev/code.py +17 -24
- machineconfig/jobs/python_custom_installers/dev/cursor.py +10 -21
- machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +12 -11
- machineconfig/jobs/python_custom_installers/dev/espanso.py +19 -23
- machineconfig/jobs/python_custom_installers/dev/goes.py +9 -16
- machineconfig/jobs/python_custom_installers/dev/lvim.py +13 -21
- machineconfig/jobs/python_custom_installers/dev/nerdfont.py +15 -22
- machineconfig/jobs/python_custom_installers/dev/redis.py +15 -23
- machineconfig/jobs/python_custom_installers/dev/wezterm.py +15 -22
- machineconfig/jobs/python_custom_installers/dev/winget.py +32 -50
- machineconfig/jobs/python_custom_installers/docker.py +15 -24
- machineconfig/jobs/python_custom_installers/gh.py +18 -26
- machineconfig/jobs/python_custom_installers/hx.py +33 -17
- machineconfig/jobs/python_custom_installers/warp-cli.py +15 -23
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_generic_installers/config.json +412 -389
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_windows_installers/dev/config.json +1 -1
- machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -1
- machineconfig/jobs/windows/msc/cli_agents.bat +0 -0
- machineconfig/jobs/windows/msc/cli_agents.ps1 +0 -0
- machineconfig/jobs/windows/start_terminal.ps1 +1 -1
- machineconfig/logger.py +50 -0
- machineconfig/profile/create.py +50 -36
- machineconfig/profile/create_hardlinks.py +33 -26
- machineconfig/profile/shell.py +87 -60
- machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/cloud/init.sh +2 -2
- machineconfig/scripts/linux/checkout_versions +1 -1
- machineconfig/scripts/linux/choose_wezterm_theme +1 -1
- machineconfig/scripts/linux/cloud_copy +1 -1
- machineconfig/scripts/linux/cloud_manager +1 -1
- machineconfig/scripts/linux/cloud_mount +1 -1
- machineconfig/scripts/linux/cloud_repo_sync +1 -1
- machineconfig/scripts/linux/cloud_sync +1 -1
- machineconfig/scripts/linux/croshell +1 -1
- machineconfig/scripts/linux/devops +3 -5
- machineconfig/scripts/linux/fire +2 -1
- machineconfig/scripts/linux/fire_agents +3 -3
- machineconfig/scripts/linux/ftpx +1 -1
- machineconfig/scripts/linux/gh_models +1 -1
- machineconfig/scripts/linux/kill_process +1 -1
- machineconfig/scripts/linux/mcinit +2 -2
- machineconfig/scripts/linux/repos +1 -1
- machineconfig/scripts/linux/scheduler +1 -1
- machineconfig/scripts/linux/start_slidev +1 -1
- machineconfig/scripts/linux/start_terminals +1 -1
- machineconfig/scripts/linux/url2md +1 -1
- machineconfig/scripts/linux/warp-cli.sh +122 -0
- machineconfig/scripts/linux/wifi_conn +1 -1
- machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__init__.py +0 -0
- machineconfig/scripts/python/ai/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/generate_files.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/chatmodes/Thinking-Beast-Mode.chatmode.md +337 -0
- machineconfig/scripts/python/ai/chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md +644 -0
- machineconfig/scripts/python/ai/chatmodes/deepResearch.chatmode.md +81 -0
- machineconfig/scripts/python/ai/configs/.gemini/settings.json +81 -0
- machineconfig/scripts/python/ai/generate_files.py +84 -0
- machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +45 -0
- machineconfig/scripts/python/ai/mcinit.py +107 -0
- machineconfig/scripts/python/ai/prompts/allLintersAndTypeCheckers.prompt.md +5 -0
- machineconfig/scripts/python/ai/prompts/research-report-skeleton.prompt.md +38 -0
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +52 -0
- machineconfig/scripts/python/archive/tmate_conn.py +5 -5
- machineconfig/scripts/python/archive/tmate_start.py +3 -3
- machineconfig/scripts/python/choose_wezterm_theme.py +2 -2
- machineconfig/scripts/python/cloud_copy.py +20 -19
- machineconfig/scripts/python/cloud_mount.py +10 -8
- machineconfig/scripts/python/cloud_repo_sync.py +15 -15
- machineconfig/scripts/python/cloud_sync.py +1 -1
- machineconfig/scripts/python/croshell.py +18 -16
- machineconfig/scripts/python/devops.py +6 -6
- machineconfig/scripts/python/devops_add_identity.py +9 -7
- machineconfig/scripts/python/devops_add_ssh_key.py +19 -19
- machineconfig/scripts/python/devops_backup_retrieve.py +14 -14
- machineconfig/scripts/python/devops_devapps_install.py +3 -3
- machineconfig/scripts/python/devops_update_repos.py +141 -53
- machineconfig/scripts/python/dotfile.py +3 -3
- machineconfig/scripts/python/fire_agents.py +202 -41
- machineconfig/scripts/python/fire_jobs.py +20 -21
- machineconfig/scripts/python/ftpx.py +4 -3
- machineconfig/scripts/python/gh_models.py +94 -94
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/cloud_helpers.py +3 -3
- machineconfig/scripts/python/helpers/helpers2.py +3 -3
- machineconfig/scripts/python/helpers/helpers4.py +8 -7
- machineconfig/scripts/python/helpers/helpers5.py +7 -7
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +2 -2
- machineconfig/scripts/python/mount_nfs.py +4 -3
- machineconfig/scripts/python/mount_nw_drive.py +4 -4
- machineconfig/scripts/python/mount_ssh.py +4 -3
- machineconfig/scripts/python/repos.py +9 -9
- machineconfig/scripts/python/scheduler.py +1 -1
- machineconfig/scripts/python/start_slidev.py +9 -8
- machineconfig/scripts/python/start_terminals.py +1 -1
- machineconfig/scripts/python/viewer.py +40 -40
- machineconfig/scripts/python/wifi_conn.py +65 -66
- machineconfig/scripts/python/wsl_windows_transfer.py +2 -2
- machineconfig/scripts/windows/checkout_version.ps1 +1 -3
- machineconfig/scripts/windows/choose_wezterm_theme.ps1 +1 -3
- machineconfig/scripts/windows/cloud_copy.ps1 +2 -6
- machineconfig/scripts/windows/cloud_manager.ps1 +1 -1
- machineconfig/scripts/windows/cloud_repo_sync.ps1 +1 -2
- machineconfig/scripts/windows/cloud_sync.ps1 +2 -2
- machineconfig/scripts/windows/croshell.ps1 +2 -2
- machineconfig/scripts/windows/devops.ps1 +1 -4
- machineconfig/scripts/windows/dotfile.ps1 +1 -3
- machineconfig/scripts/windows/fire.ps1 +1 -1
- machineconfig/scripts/windows/ftpx.ps1 +2 -2
- machineconfig/scripts/windows/gpt.ps1 +1 -1
- machineconfig/scripts/windows/kill_process.ps1 +1 -2
- machineconfig/scripts/windows/mcinit.ps1 +2 -2
- machineconfig/scripts/windows/mount_nfs.ps1 +1 -1
- machineconfig/scripts/windows/mount_ssh.ps1 +1 -1
- machineconfig/scripts/windows/pomodoro.ps1 +1 -1
- machineconfig/scripts/windows/py2exe.ps1 +1 -3
- machineconfig/scripts/windows/repos.ps1 +1 -1
- machineconfig/scripts/windows/scheduler.ps1 +1 -1
- machineconfig/scripts/windows/snapshot.ps1 +2 -2
- machineconfig/scripts/windows/start_slidev.ps1 +1 -1
- machineconfig/scripts/windows/start_terminals.ps1 +1 -1
- machineconfig/scripts/windows/wifi_conn.ps1 +1 -1
- machineconfig/scripts/windows/wsl_windows_transfer.ps1 +1 -3
- machineconfig/settings/lf/linux/lfrc +1 -1
- machineconfig/settings/linters/.ruff.toml +2 -2
- machineconfig/settings/linters/.ruff_cache/.gitignore +2 -0
- machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +1 -0
- machineconfig/settings/lvim/windows/archive/config_additional.lua +1 -1
- machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +71 -71
- machineconfig/settings/shells/wt/settings.json +8 -8
- machineconfig/settings/svim/linux/init.toml +1 -1
- machineconfig/settings/svim/windows/init.toml +1 -1
- machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -54
- machineconfig/setup_linux/web_shortcuts/interactive.sh +6 -6
- machineconfig/setup_linux/web_shortcuts/tmp.sh +2 -0
- machineconfig/setup_windows/web_shortcuts/all.ps1 +2 -2
- machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/croshell.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +5 -5
- machineconfig/setup_windows/wt_and_pwsh/install_fonts.ps1 +51 -15
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +75 -18
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +52 -42
- machineconfig/utils/ai/browser_user_wrapper.py +5 -5
- machineconfig/utils/ai/generate_file_checklist.py +19 -22
- machineconfig/utils/ai/url2md.py +5 -3
- machineconfig/utils/cloud/onedrive/setup_oauth.py +5 -4
- machineconfig/utils/cloud/onedrive/transaction.py +192 -227
- machineconfig/utils/code.py +71 -43
- machineconfig/utils/installer.py +77 -85
- machineconfig/utils/installer_utils/installer_abc.py +29 -17
- machineconfig/utils/installer_utils/installer_class.py +188 -83
- machineconfig/utils/io_save.py +3 -15
- machineconfig/utils/links.py +22 -11
- machineconfig/utils/notifications.py +197 -0
- machineconfig/utils/options.py +38 -25
- machineconfig/utils/path.py +18 -6
- machineconfig/utils/path_reduced.py +637 -316
- machineconfig/utils/procs.py +69 -63
- machineconfig/utils/scheduling.py +11 -13
- machineconfig/utils/ssh.py +351 -0
- machineconfig/utils/terminal.py +225 -0
- machineconfig/utils/utils.py +13 -12
- machineconfig/utils/utils2.py +43 -10
- machineconfig/utils/utils5.py +242 -46
- machineconfig/utils/ve.py +11 -6
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/METADATA +15 -9
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/RECORD +232 -235
- machineconfig/cluster/self_ssh.py +0 -57
- machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/archive/python_tools.txt +0 -12
- machineconfig/jobs/python/vscode/__pycache__/select_interpreter.cpython-311.pyc +0 -0
- machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/update.py +0 -3
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
- machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/linux/activate_ve +0 -87
- machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_backup_retrieve.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/init.py +0 -56
- machineconfig/scripts/python/ai/rules/python/dev.md +0 -31
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/windows/activate_ve.ps1 +0 -54
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/WHEEL +0 -0
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/top_level.txt +0 -0
|
@@ -4,6 +4,7 @@ import json
|
|
|
4
4
|
import uuid
|
|
5
5
|
import logging
|
|
6
6
|
import subprocess
|
|
7
|
+
import time
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import Optional, Dict, List, Any
|
|
9
10
|
|
|
@@ -21,11 +22,11 @@ TMP_SERIALIZATION_DIR = Path.home().joinpath("tmp_results", "session_manager", "
|
|
|
21
22
|
|
|
22
23
|
class ZellijLocalManager:
|
|
23
24
|
"""Manages multiple local zellij sessions and monitors their tabs and processes."""
|
|
24
|
-
|
|
25
|
+
|
|
25
26
|
def __init__(self, session2zellij_tabs: Dict[str, Dict[str, tuple[str, str]]], session_name_prefix: str = "LocalJobMgr"):
|
|
26
27
|
"""
|
|
27
28
|
Initialize the local zellij manager.
|
|
28
|
-
|
|
29
|
+
|
|
29
30
|
Args:
|
|
30
31
|
session2zellij_tabs: Dict mapping session names to their tab configs
|
|
31
32
|
Format: {session_name: {tab_name: (cwd, command), ...}, ...}
|
|
@@ -34,14 +35,14 @@ class ZellijLocalManager:
|
|
|
34
35
|
self.session_name_prefix = session_name_prefix
|
|
35
36
|
self.session2zellij_tabs = session2zellij_tabs # Store the original config
|
|
36
37
|
self.managers: List[ZellijLayoutGenerator] = []
|
|
37
|
-
|
|
38
|
+
|
|
38
39
|
# Create a ZellijLayoutGenerator for each session
|
|
39
40
|
for session_name, tab_config in session2zellij_tabs.items():
|
|
40
41
|
manager = ZellijLayoutGenerator()
|
|
41
42
|
full_session_name = f"{self.session_name_prefix}_{session_name}"
|
|
42
43
|
manager.create_zellij_layout(tab_config=tab_config, session_name=full_session_name)
|
|
43
44
|
self.managers.append(manager)
|
|
44
|
-
|
|
45
|
+
|
|
45
46
|
# Enhanced Rich logging for initialization
|
|
46
47
|
console.print(f"[bold green]🔧 Initialized ZellijLocalManager[/bold green] [dim]with[/dim] [bright_green]{len(self.managers)} sessions[/bright_green]")
|
|
47
48
|
|
|
@@ -49,55 +50,70 @@ class ZellijLocalManager:
|
|
|
49
50
|
"""Get all managed session names."""
|
|
50
51
|
return [manager.session_name for manager in self.managers if manager.session_name is not None]
|
|
51
52
|
|
|
52
|
-
def start_all_sessions(self) -> Dict[str, Any]:
|
|
53
|
-
"""Start all zellij sessions with their layouts.
|
|
54
|
-
|
|
53
|
+
def start_all_sessions(self, poll_seconds: float = 5.0, poll_interval: float = 0.25) -> Dict[str, Any]:
|
|
54
|
+
"""Start all zellij sessions with their layouts without blocking on the interactive TUI.
|
|
55
|
+
|
|
56
|
+
Rationale:
|
|
57
|
+
Previous implementation used subprocess.run(... timeout=30) on an "attach" command
|
|
58
|
+
which never returns (interactive) causing a timeout. We now:
|
|
59
|
+
1. Ensure any old session is deleted (best-effort, short timeout)
|
|
60
|
+
2. Launch new session in background with Popen (no wait)
|
|
61
|
+
3. Poll 'zellij list-sessions' to confirm creation
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
poll_seconds: Total seconds to wait for session to appear
|
|
65
|
+
poll_interval: Delay between polls
|
|
66
|
+
Returns:
|
|
67
|
+
Dict mapping session name to success metadata.
|
|
68
|
+
"""
|
|
69
|
+
results: Dict[str, Any] = {}
|
|
55
70
|
for manager in self.managers:
|
|
71
|
+
session_name = manager.session_name
|
|
56
72
|
try:
|
|
57
|
-
session_name = manager.session_name
|
|
58
73
|
if session_name is None:
|
|
59
|
-
continue
|
|
60
|
-
|
|
74
|
+
continue
|
|
61
75
|
layout_path = manager.layout_path
|
|
62
|
-
|
|
63
76
|
if not layout_path:
|
|
64
|
-
results[session_name] = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
results[session_name] = {"success": False, "error": "No layout file path available"}
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
# 1. Best-effort delete existing session
|
|
81
|
+
delete_cmd = ["zellij", "delete-session", "--force", session_name]
|
|
82
|
+
try:
|
|
83
|
+
subprocess.run(delete_cmd, capture_output=True, text=True, timeout=5)
|
|
84
|
+
except subprocess.TimeoutExpired:
|
|
85
|
+
logger.warning(f"Timeout deleting session {session_name}; continuing")
|
|
86
|
+
except FileNotFoundError:
|
|
87
|
+
results[session_name] = {"success": False, "error": "'zellij' executable not found in PATH"}
|
|
68
88
|
continue
|
|
69
|
-
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
|
|
90
|
+
# 2. Launch new session. We intentionally do NOT wait for completion.
|
|
91
|
+
# Using the same pattern as before (attach --create) but detached via env var.
|
|
92
|
+
# ZELLIJ_AUTO_ATTACH=0 prevents auto-attach if compiled with that feature; harmless otherwise.
|
|
93
|
+
start_cmd = ["bash", "-lc", f"ZELLIJ_AUTO_ATTACH=0 zellij --layout {layout_path} attach {session_name} --create >/dev/null 2>&1 &"]
|
|
94
|
+
console.print(f"[bold cyan]🚀 Starting session[/bold cyan] [yellow]'{session_name}'[/yellow] with layout [blue]{layout_path}[/blue] (non-blocking)...")
|
|
95
|
+
subprocess.Popen(start_cmd)
|
|
96
|
+
|
|
97
|
+
# 3. Poll for presence
|
|
98
|
+
deadline = time.time() + poll_seconds
|
|
99
|
+
appeared = False
|
|
100
|
+
while time.time() < deadline:
|
|
101
|
+
list_res = subprocess.run(["zellij", "list-sessions"], capture_output=True, text=True)
|
|
102
|
+
if list_res.returncode == 0 and session_name in list_res.stdout:
|
|
103
|
+
appeared = True
|
|
104
|
+
break
|
|
105
|
+
time.sleep(poll_interval)
|
|
106
|
+
|
|
107
|
+
if appeared:
|
|
108
|
+
results[session_name] = {"success": True, "message": f"Session '{session_name}' started"}
|
|
109
|
+
console.print(f"[bold green]✅ Session[/bold green] [yellow]'{session_name}'[/yellow] [green]is up[/green]")
|
|
82
110
|
else:
|
|
83
|
-
results[session_name] = {
|
|
84
|
-
|
|
85
|
-
"error": result.stderr or result.stdout
|
|
86
|
-
}
|
|
87
|
-
console.print(f"[bold red]❌ Failed to start session[/bold red] [yellow]'{session_name}'[/yellow][red]:[/red] [dim]{result.stderr}[/dim]")
|
|
88
|
-
|
|
111
|
+
results[session_name] = {"success": False, "error": "Session did not appear within poll window"}
|
|
112
|
+
console.print(f"[bold red]❌ Session '{session_name}' did not appear after {poll_seconds:.1f}s[/bold red]")
|
|
89
113
|
except Exception as e:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
key = getattr(manager, 'session_name', None) or f"manager_{self.managers.index(manager)}"
|
|
93
|
-
except Exception:
|
|
94
|
-
key = f"manager_{self.managers.index(manager)}"
|
|
95
|
-
results[key] = {
|
|
96
|
-
"success": False,
|
|
97
|
-
"error": str(e)
|
|
98
|
-
}
|
|
114
|
+
key = session_name or f"manager_{self.managers.index(manager)}"
|
|
115
|
+
results[key] = {"success": False, "error": str(e)}
|
|
99
116
|
logger.error(f"❌ Exception starting session '{key}': {e}")
|
|
100
|
-
|
|
101
117
|
return results
|
|
102
118
|
|
|
103
119
|
def kill_all_sessions(self) -> Dict[str, Any]:
|
|
@@ -108,34 +124,28 @@ class ZellijLocalManager:
|
|
|
108
124
|
session_name = manager.session_name
|
|
109
125
|
if session_name is None:
|
|
110
126
|
continue # Skip managers without a session name
|
|
111
|
-
|
|
127
|
+
|
|
112
128
|
cmd = f"zellij delete-session --force {session_name}"
|
|
113
|
-
|
|
129
|
+
|
|
114
130
|
logger.info(f"Killing session '{session_name}'")
|
|
115
131
|
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=10)
|
|
116
|
-
|
|
117
|
-
results[session_name] = {
|
|
118
|
-
|
|
119
|
-
"message": "Session killed" if result.returncode == 0 else result.stderr
|
|
120
|
-
}
|
|
121
|
-
|
|
132
|
+
|
|
133
|
+
results[session_name] = {"success": result.returncode == 0, "message": "Session killed" if result.returncode == 0 else result.stderr}
|
|
134
|
+
|
|
122
135
|
except Exception as e:
|
|
123
136
|
# Use a fallback key since session_name might not be defined here
|
|
124
|
-
key = getattr(manager,
|
|
125
|
-
results[key] = {
|
|
126
|
-
|
|
127
|
-
"error": str(e)
|
|
128
|
-
}
|
|
129
|
-
|
|
137
|
+
key = getattr(manager, "session_name", None) or f"manager_{self.managers.index(manager)}"
|
|
138
|
+
results[key] = {"success": False, "error": str(e)}
|
|
139
|
+
|
|
130
140
|
return results
|
|
131
141
|
|
|
132
142
|
def attach_to_session(self, session_name: Optional[str] = None) -> str:
|
|
133
143
|
"""
|
|
134
144
|
Generate command to attach to a specific session or list attachment commands for all.
|
|
135
|
-
|
|
145
|
+
|
|
136
146
|
Args:
|
|
137
147
|
session_name: Specific session to attach to, or None for all sessions
|
|
138
|
-
|
|
148
|
+
|
|
139
149
|
Returns:
|
|
140
150
|
Command string to attach to session(s)
|
|
141
151
|
"""
|
|
@@ -157,47 +167,39 @@ class ZellijLocalManager:
|
|
|
157
167
|
def check_all_sessions_status(self) -> Dict[str, Dict[str, Any]]:
|
|
158
168
|
"""Check the status of all sessions and their commands."""
|
|
159
169
|
status_report = {}
|
|
160
|
-
|
|
170
|
+
|
|
161
171
|
for manager in self.managers:
|
|
162
172
|
session_name = manager.session_name
|
|
163
173
|
if session_name is None:
|
|
164
174
|
continue # Skip managers without a session name
|
|
165
|
-
|
|
175
|
+
|
|
166
176
|
# Get session status
|
|
167
177
|
session_status = ZellijLayoutGenerator.check_zellij_session_status(session_name)
|
|
168
|
-
|
|
178
|
+
|
|
169
179
|
# Get commands status for this session
|
|
170
180
|
commands_status = manager.check_all_commands_status()
|
|
171
|
-
|
|
181
|
+
|
|
172
182
|
# Calculate summary for this session
|
|
173
183
|
running_count = sum(1 for status in commands_status.values() if status.get("running", False))
|
|
174
184
|
total_count = len(commands_status)
|
|
175
|
-
|
|
185
|
+
|
|
176
186
|
status_report[session_name] = {
|
|
177
187
|
"session_status": session_status,
|
|
178
188
|
"commands_status": commands_status,
|
|
179
|
-
"summary": {
|
|
180
|
-
"total_commands": total_count,
|
|
181
|
-
"running_commands": running_count,
|
|
182
|
-
"stopped_commands": total_count - running_count,
|
|
183
|
-
"session_healthy": session_status.get("session_exists", False)
|
|
184
|
-
}
|
|
189
|
+
"summary": {"total_commands": total_count, "running_commands": running_count, "stopped_commands": total_count - running_count, "session_healthy": session_status.get("session_exists", False)},
|
|
185
190
|
}
|
|
186
|
-
|
|
191
|
+
|
|
187
192
|
return status_report
|
|
188
193
|
|
|
189
194
|
def get_global_summary(self) -> Dict[str, Any]:
|
|
190
195
|
"""Get a global summary across all sessions."""
|
|
191
196
|
all_status = self.check_all_sessions_status()
|
|
192
|
-
|
|
197
|
+
|
|
193
198
|
total_sessions = len(all_status)
|
|
194
|
-
healthy_sessions = sum(1 for status in all_status.values()
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
total_running = sum(status["summary"]["running_commands"]
|
|
199
|
-
for status in all_status.values())
|
|
200
|
-
|
|
199
|
+
healthy_sessions = sum(1 for status in all_status.values() if status["summary"]["session_healthy"])
|
|
200
|
+
total_commands = sum(status["summary"]["total_commands"] for status in all_status.values())
|
|
201
|
+
total_running = sum(status["summary"]["running_commands"] for status in all_status.values())
|
|
202
|
+
|
|
201
203
|
return {
|
|
202
204
|
"total_sessions": total_sessions,
|
|
203
205
|
"healthy_sessions": healthy_sessions,
|
|
@@ -206,18 +208,18 @@ class ZellijLocalManager:
|
|
|
206
208
|
"running_commands": total_running,
|
|
207
209
|
"stopped_commands": total_commands - total_running,
|
|
208
210
|
"all_sessions_healthy": healthy_sessions == total_sessions,
|
|
209
|
-
"all_commands_running": total_running == total_commands
|
|
211
|
+
"all_commands_running": total_running == total_commands,
|
|
210
212
|
}
|
|
211
213
|
|
|
212
214
|
def print_status_report(self) -> None:
|
|
213
215
|
"""Print a comprehensive status report for all sessions."""
|
|
214
216
|
all_status = self.check_all_sessions_status()
|
|
215
217
|
global_summary = self.get_global_summary()
|
|
216
|
-
|
|
218
|
+
|
|
217
219
|
print("=" * 80)
|
|
218
220
|
print("🔍 ZELLIJ LOCAL MANAGER STATUS REPORT")
|
|
219
221
|
print("=" * 80)
|
|
220
|
-
|
|
222
|
+
|
|
221
223
|
# Global summary
|
|
222
224
|
print("🌐 GLOBAL SUMMARY:")
|
|
223
225
|
print(f" Total sessions: {global_summary['total_sessions']}")
|
|
@@ -226,62 +228,65 @@ class ZellijLocalManager:
|
|
|
226
228
|
print(f" Running commands: {global_summary['running_commands']}")
|
|
227
229
|
print(f" All healthy: {'✅' if global_summary['all_sessions_healthy'] else '❌'}")
|
|
228
230
|
print()
|
|
229
|
-
|
|
231
|
+
|
|
230
232
|
# Per-session details
|
|
231
233
|
for session_name, status in all_status.items():
|
|
232
234
|
session_status = status["session_status"]
|
|
233
235
|
commands_status = status["commands_status"]
|
|
234
236
|
summary = status["summary"]
|
|
235
|
-
|
|
237
|
+
|
|
236
238
|
print(f"📋 SESSION: {session_name}")
|
|
237
239
|
print("-" * 60)
|
|
238
|
-
|
|
240
|
+
|
|
239
241
|
# Session health
|
|
240
242
|
if session_status.get("session_exists", False):
|
|
241
243
|
print("✅ Session is running")
|
|
242
244
|
else:
|
|
243
245
|
print(f"❌ Session not found: {session_status.get('error', 'Unknown error')}")
|
|
244
|
-
|
|
246
|
+
|
|
245
247
|
# Commands in this session
|
|
246
248
|
print(f" Commands ({summary['running_commands']}/{summary['total_commands']} running):")
|
|
247
249
|
for tab_name, cmd_status in commands_status.items():
|
|
248
250
|
status_icon = "✅" if cmd_status.get("running", False) else "❌"
|
|
249
251
|
print(f" {status_icon} {tab_name}: {cmd_status.get('command', 'Unknown')}")
|
|
250
|
-
|
|
252
|
+
|
|
251
253
|
if cmd_status.get("processes"):
|
|
252
254
|
for proc in cmd_status["processes"][:2]: # Show first 2 processes
|
|
253
255
|
print(f" └─ PID {proc['pid']}: {proc['name']} ({proc['status']})")
|
|
254
256
|
print()
|
|
255
|
-
|
|
257
|
+
|
|
256
258
|
print("=" * 80)
|
|
257
259
|
|
|
258
260
|
def run_monitoring_routine(self, wait_ms: int = 30000) -> None:
|
|
259
261
|
"""
|
|
260
262
|
Run a continuous monitoring routine that checks status periodically.
|
|
261
|
-
|
|
263
|
+
|
|
262
264
|
Args:
|
|
263
265
|
wait_ms: How long to wait between checks in milliseconds (default: 30000ms = 30s)
|
|
264
266
|
"""
|
|
267
|
+
|
|
265
268
|
def routine(scheduler: Scheduler):
|
|
266
269
|
print(f"\n⏰ Monitoring cycle {scheduler.cycle} at {datetime.now()}")
|
|
267
270
|
print("-" * 50)
|
|
268
|
-
|
|
271
|
+
|
|
269
272
|
if scheduler.cycle % 2 == 0:
|
|
270
273
|
# Detailed status check every other cycle
|
|
271
274
|
all_status = self.check_all_sessions_status()
|
|
272
|
-
|
|
275
|
+
|
|
273
276
|
# Create DataFrame for easier viewing
|
|
274
277
|
status_data = []
|
|
275
278
|
for session_name, status in all_status.items():
|
|
276
279
|
for tab_name, cmd_status in status["commands_status"].items():
|
|
277
|
-
status_data.append(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
280
|
+
status_data.append(
|
|
281
|
+
{
|
|
282
|
+
"session": session_name,
|
|
283
|
+
"tab": tab_name,
|
|
284
|
+
"running": cmd_status.get("running", False),
|
|
285
|
+
"command": cmd_status.get("command", "Unknown")[:50] + "..." if len(cmd_status.get("command", "")) > 50 else cmd_status.get("command", ""),
|
|
286
|
+
"processes": len(cmd_status.get("processes", [])),
|
|
287
|
+
}
|
|
288
|
+
)
|
|
289
|
+
|
|
285
290
|
if status_data:
|
|
286
291
|
# Format data as table
|
|
287
292
|
if status_data:
|
|
@@ -294,7 +299,7 @@ class ZellijLocalManager:
|
|
|
294
299
|
for row in status_data:
|
|
295
300
|
values = [str(row.get(h, ""))[:15] for h in headers]
|
|
296
301
|
print(" | ".join(f"{v:<15}" for v in values))
|
|
297
|
-
|
|
302
|
+
|
|
298
303
|
# Check if all sessions have stopped
|
|
299
304
|
running_count = sum(1 for row in status_data if row.get("running", False))
|
|
300
305
|
if running_count == 0:
|
|
@@ -307,103 +312,93 @@ class ZellijLocalManager:
|
|
|
307
312
|
# Quick summary check
|
|
308
313
|
global_summary = self.get_global_summary()
|
|
309
314
|
print(f"📊 Quick Summary: {global_summary['running_commands']}/{global_summary['total_commands']} commands running across {global_summary['healthy_sessions']}/{global_summary['total_sessions']} sessions")
|
|
310
|
-
|
|
315
|
+
|
|
311
316
|
logger.info(f"Starting monitoring routine with {wait_ms}ms intervals")
|
|
312
|
-
sched = Scheduler(routine=routine, wait_ms=wait_ms)
|
|
317
|
+
sched = Scheduler(routine=routine, wait_ms=wait_ms, logger=logger)
|
|
313
318
|
sched.run()
|
|
314
319
|
|
|
315
320
|
def save(self, session_id: Optional[str] = None) -> str:
|
|
316
321
|
"""Save the manager state to disk."""
|
|
317
322
|
if session_id is None:
|
|
318
323
|
session_id = str(uuid.uuid4())[:8]
|
|
319
|
-
|
|
324
|
+
|
|
320
325
|
# Create session directory
|
|
321
326
|
session_dir = TMP_SERIALIZATION_DIR / session_id
|
|
322
327
|
session_dir.mkdir(parents=True, exist_ok=True)
|
|
323
|
-
|
|
328
|
+
|
|
324
329
|
# Save the session2zellij_tabs configuration
|
|
325
330
|
config_file = session_dir / "session2zellij_tabs.json"
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
331
|
+
text = json.dumps(self.session2zellij_tabs, indent=2, ensure_ascii=False)
|
|
332
|
+
config_file.write_text(text, encoding="utf-8")
|
|
333
|
+
|
|
329
334
|
# Save metadata
|
|
330
|
-
metadata = {
|
|
331
|
-
"session_name_prefix": self.session_name_prefix,
|
|
332
|
-
"created_at": str(datetime.now()),
|
|
333
|
-
"num_managers": len(self.managers),
|
|
334
|
-
"sessions": list(self.session2zellij_tabs.keys()),
|
|
335
|
-
"manager_type": "ZellijLocalManager"
|
|
336
|
-
}
|
|
335
|
+
metadata = {"session_name_prefix": self.session_name_prefix, "created_at": str(datetime.now()), "num_managers": len(self.managers), "sessions": list(self.session2zellij_tabs.keys()), "manager_type": "ZellijLocalManager"}
|
|
337
336
|
metadata_file = session_dir / "metadata.json"
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
337
|
+
text = json.dumps(metadata, indent=2, ensure_ascii=False)
|
|
338
|
+
metadata_file.write_text(text, encoding="utf-8")
|
|
339
|
+
|
|
341
340
|
# Save each manager's state
|
|
342
341
|
managers_dir = session_dir / "managers"
|
|
343
342
|
managers_dir.mkdir(exist_ok=True)
|
|
344
|
-
|
|
343
|
+
|
|
345
344
|
for i, manager in enumerate(self.managers):
|
|
346
|
-
manager_data = {
|
|
347
|
-
"session_name": manager.session_name,
|
|
348
|
-
"tab_config": manager.tab_config,
|
|
349
|
-
"layout_path": manager.layout_path
|
|
350
|
-
}
|
|
345
|
+
manager_data = {"session_name": manager.session_name, "tab_config": manager.tab_config, "layout_path": manager.layout_path}
|
|
351
346
|
manager_file = managers_dir / f"manager_{i}_{manager.session_name}.json"
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
347
|
+
text = json.dumps(manager_data, indent=2, ensure_ascii=False)
|
|
348
|
+
manager_file.write_text(text, encoding="utf-8")
|
|
349
|
+
|
|
355
350
|
logger.info(f"✅ Saved ZellijLocalManager session to: {session_dir}")
|
|
356
351
|
return session_id
|
|
357
352
|
|
|
358
353
|
@classmethod
|
|
359
|
-
def load(cls, session_id: str) ->
|
|
354
|
+
def load(cls, session_id: str) -> "ZellijLocalManager":
|
|
360
355
|
"""Load a saved manager state from disk."""
|
|
361
356
|
session_dir = TMP_SERIALIZATION_DIR / session_id
|
|
362
|
-
|
|
357
|
+
|
|
363
358
|
if not session_dir.exists():
|
|
364
359
|
raise FileNotFoundError(f"Session directory not found: {session_dir}")
|
|
365
|
-
|
|
360
|
+
|
|
366
361
|
# Load configuration
|
|
367
362
|
config_file = session_dir / "session2zellij_tabs.json"
|
|
368
363
|
if not config_file.exists():
|
|
369
364
|
raise FileNotFoundError(f"Configuration file not found: {config_file}")
|
|
370
|
-
|
|
371
|
-
with open(config_file,
|
|
365
|
+
|
|
366
|
+
with open(config_file, "r", encoding="utf-8") as f:
|
|
372
367
|
session2zellij_tabs = json.load(f)
|
|
373
|
-
|
|
368
|
+
|
|
374
369
|
# Load metadata
|
|
375
370
|
metadata_file = session_dir / "metadata.json"
|
|
376
371
|
session_name_prefix = "LocalJobMgr" # default fallback
|
|
377
372
|
if metadata_file.exists():
|
|
378
|
-
with open(metadata_file,
|
|
373
|
+
with open(metadata_file, "r", encoding="utf-8") as f:
|
|
379
374
|
metadata = json.load(f)
|
|
380
375
|
session_name_prefix = metadata.get("session_name_prefix", "LocalJobMgr")
|
|
381
|
-
|
|
376
|
+
|
|
382
377
|
# Create new instance
|
|
383
378
|
instance = cls(session2zellij_tabs=session2zellij_tabs, session_name_prefix=session_name_prefix)
|
|
384
|
-
|
|
379
|
+
|
|
385
380
|
# Load saved manager states
|
|
386
381
|
managers_dir = session_dir / "managers"
|
|
387
382
|
if managers_dir.exists():
|
|
388
383
|
instance.managers = []
|
|
389
384
|
manager_files = sorted(managers_dir.glob("manager_*.json"))
|
|
390
|
-
|
|
385
|
+
|
|
391
386
|
for manager_file in manager_files:
|
|
392
387
|
try:
|
|
393
|
-
with open(manager_file,
|
|
388
|
+
with open(manager_file, "r", encoding="utf-8") as f:
|
|
394
389
|
manager_data = json.load(f)
|
|
395
|
-
|
|
390
|
+
|
|
396
391
|
# Recreate the manager
|
|
397
392
|
manager = ZellijLayoutGenerator()
|
|
398
393
|
manager.session_name = manager_data["session_name"]
|
|
399
394
|
manager.tab_config = manager_data["tab_config"]
|
|
400
395
|
manager.layout_path = manager_data["layout_path"]
|
|
401
|
-
|
|
396
|
+
|
|
402
397
|
instance.managers.append(manager)
|
|
403
|
-
|
|
398
|
+
|
|
404
399
|
except Exception as e:
|
|
405
400
|
logger.warning(f"Failed to load manager from {manager_file}: {e}")
|
|
406
|
-
|
|
401
|
+
|
|
407
402
|
logger.info(f"✅ Loaded ZellijLocalManager session from: {session_dir}")
|
|
408
403
|
return instance
|
|
409
404
|
|
|
@@ -412,25 +407,26 @@ class ZellijLocalManager:
|
|
|
412
407
|
"""List all saved session IDs."""
|
|
413
408
|
if not TMP_SERIALIZATION_DIR.exists():
|
|
414
409
|
return []
|
|
415
|
-
|
|
410
|
+
|
|
416
411
|
sessions = []
|
|
417
412
|
for item in TMP_SERIALIZATION_DIR.iterdir():
|
|
418
413
|
if item.is_dir() and (item / "metadata.json").exists():
|
|
419
414
|
sessions.append(item.name)
|
|
420
|
-
|
|
415
|
+
|
|
421
416
|
return sorted(sessions)
|
|
422
417
|
|
|
423
418
|
@staticmethod
|
|
424
419
|
def delete_session(session_id: str) -> bool:
|
|
425
420
|
"""Delete a saved session."""
|
|
426
421
|
session_dir = TMP_SERIALIZATION_DIR / session_id
|
|
427
|
-
|
|
422
|
+
|
|
428
423
|
if not session_dir.exists():
|
|
429
424
|
logger.warning(f"Session directory not found: {session_dir}")
|
|
430
425
|
return False
|
|
431
|
-
|
|
426
|
+
|
|
432
427
|
try:
|
|
433
428
|
import shutil
|
|
429
|
+
|
|
434
430
|
shutil.rmtree(session_dir)
|
|
435
431
|
logger.info(f"✅ Deleted session: {session_id}")
|
|
436
432
|
return True
|
|
@@ -441,93 +437,72 @@ class ZellijLocalManager:
|
|
|
441
437
|
def list_active_sessions(self) -> List[Dict[str, Any]]:
|
|
442
438
|
"""List currently active zellij sessions managed by this instance."""
|
|
443
439
|
active_sessions = []
|
|
444
|
-
|
|
440
|
+
|
|
445
441
|
try:
|
|
446
442
|
# Get all running zellij sessions
|
|
447
|
-
result = subprocess.run(
|
|
448
|
-
|
|
449
|
-
capture_output=True,
|
|
450
|
-
text=True,
|
|
451
|
-
timeout=10
|
|
452
|
-
)
|
|
453
|
-
|
|
443
|
+
result = subprocess.run(["zellij", "list-sessions"], capture_output=True, text=True, timeout=10)
|
|
444
|
+
|
|
454
445
|
if result.returncode == 0:
|
|
455
|
-
all_sessions = result.stdout.strip().split(
|
|
456
|
-
|
|
446
|
+
all_sessions = result.stdout.strip().split("\n") if result.stdout.strip() else []
|
|
447
|
+
|
|
457
448
|
# Filter to only our managed sessions
|
|
458
449
|
for manager in self.managers:
|
|
459
450
|
session_name = manager.session_name
|
|
460
451
|
if session_name is None:
|
|
461
452
|
continue # Skip managers without a session name
|
|
462
453
|
is_active = any(session_name in session for session in all_sessions)
|
|
463
|
-
|
|
464
|
-
active_sessions.append({
|
|
465
|
-
|
|
466
|
-
"is_active": is_active,
|
|
467
|
-
"tab_count": len(manager.tab_config),
|
|
468
|
-
"tabs": list(manager.tab_config.keys())
|
|
469
|
-
})
|
|
470
|
-
|
|
454
|
+
|
|
455
|
+
active_sessions.append({"session_name": session_name, "is_active": is_active, "tab_count": len(manager.tab_config), "tabs": list(manager.tab_config.keys())})
|
|
456
|
+
|
|
471
457
|
except Exception as e:
|
|
472
458
|
logger.error(f"Error listing active sessions: {e}")
|
|
473
|
-
|
|
459
|
+
|
|
474
460
|
return active_sessions
|
|
475
461
|
|
|
476
462
|
|
|
477
463
|
if __name__ == "__main__":
|
|
478
464
|
# Example usage
|
|
479
465
|
sample_sessions = {
|
|
480
|
-
"development": {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
"📊Monitor": ("~", "htop")
|
|
484
|
-
},
|
|
485
|
-
"testing": {
|
|
486
|
-
"🧪Tests": ("~/code/myapp", "pytest --watch"),
|
|
487
|
-
"🔍Coverage": ("~/code/myapp", "coverage run --source=. -m pytest"),
|
|
488
|
-
"📝Logs": ("~/logs", "tail -f app.log")
|
|
489
|
-
},
|
|
490
|
-
"deployment": {
|
|
491
|
-
"🐳Docker": ("~/code/myapp", "docker-compose up"),
|
|
492
|
-
"☸️K8s": ("~/k8s", "kubectl get pods --watch"),
|
|
493
|
-
"📈Metrics": ("~", "k9s")
|
|
494
|
-
}
|
|
466
|
+
"development": {"🚀Frontend": ("~/code/myapp/frontend", "npm run dev"), "⚙️Backend": ("~/code/myapp/backend", "python manage.py runserver"), "📊Monitor": ("~", "htop")},
|
|
467
|
+
"testing": {"🧪Tests": ("~/code/myapp", "pytest --watch"), "🔍Coverage": ("~/code/myapp", "coverage run --source=. -m pytest"), "📝Logs": ("~/logs", "tail -f app.log")},
|
|
468
|
+
"deployment": {"🐳Docker": ("~/code/myapp", "docker-compose up"), "☸️K8s": ("~/k8s", "kubectl get pods --watch"), "📈Metrics": ("~", "k9s")},
|
|
495
469
|
}
|
|
496
|
-
|
|
470
|
+
|
|
497
471
|
try:
|
|
498
472
|
# Create the local manager
|
|
499
473
|
manager = ZellijLocalManager(sample_sessions, session_name_prefix="DevEnv")
|
|
500
474
|
print(f"✅ Local manager created with {len(manager.managers)} sessions")
|
|
501
|
-
|
|
475
|
+
|
|
502
476
|
# Show session names
|
|
503
477
|
print(f"📋 Sessions: {manager.get_all_session_names()}")
|
|
504
|
-
|
|
478
|
+
|
|
505
479
|
# Print attachment commands (without actually starting)
|
|
506
480
|
print("\n📎 Attachment commands:")
|
|
507
481
|
print(manager.attach_to_session())
|
|
508
|
-
|
|
482
|
+
|
|
509
483
|
# Show current status
|
|
510
484
|
print("\n🔍 Current status:")
|
|
511
485
|
manager.print_status_report()
|
|
512
|
-
|
|
486
|
+
|
|
513
487
|
# Demonstrate save/load
|
|
514
488
|
print("\n💾 Demonstrating save/load...")
|
|
515
489
|
session_id = manager.save()
|
|
516
490
|
print(f"✅ Saved session: {session_id}")
|
|
517
|
-
|
|
491
|
+
|
|
518
492
|
# List saved sessions
|
|
519
493
|
saved_sessions = ZellijLocalManager.list_saved_sessions()
|
|
520
494
|
print(f"📋 Saved sessions: {saved_sessions}")
|
|
521
|
-
|
|
495
|
+
|
|
522
496
|
# Load and verify
|
|
523
497
|
loaded_manager = ZellijLocalManager.load(session_id)
|
|
524
498
|
print(f"✅ Loaded session with {len(loaded_manager.managers)} sessions")
|
|
525
|
-
|
|
499
|
+
|
|
526
500
|
# Show how to start monitoring (commented out to prevent infinite loop in demo)
|
|
527
501
|
print("\n⏰ To start monitoring, run:")
|
|
528
502
|
print("manager.run_monitoring_routine(wait_ms=30000) # 30 seconds")
|
|
529
|
-
|
|
503
|
+
|
|
530
504
|
except Exception as e:
|
|
531
505
|
print(f"❌ Error: {e}")
|
|
532
506
|
import traceback
|
|
533
|
-
|
|
507
|
+
|
|
508
|
+
traceback.print_exc()
|