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
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Process monitoring and status checking utilities for remote commands.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
import json
|
|
6
7
|
import shlex
|
|
7
8
|
import logging
|
|
@@ -13,91 +14,48 @@ logger = logging.getLogger(__name__)
|
|
|
13
14
|
|
|
14
15
|
class ProcessMonitor:
|
|
15
16
|
"""Handles process status checking and verification on remote machines."""
|
|
16
|
-
|
|
17
|
+
|
|
17
18
|
def __init__(self, remote_executor: RemoteExecutor):
|
|
18
19
|
self.remote_executor = remote_executor
|
|
19
|
-
|
|
20
|
-
def check_command_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]],
|
|
21
|
-
use_verification: bool = True) -> Dict[str, Any]:
|
|
20
|
+
|
|
21
|
+
def check_command_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]], use_verification: bool = True) -> Dict[str, Any]:
|
|
22
22
|
"""Check command status with optional process verification."""
|
|
23
23
|
if tab_name not in tab_config:
|
|
24
|
-
return {
|
|
25
|
-
|
|
26
|
-
"error": f"Tab '{tab_name}' not found in tracked configuration",
|
|
27
|
-
"running": False,
|
|
28
|
-
"pid": None,
|
|
29
|
-
"command": None,
|
|
30
|
-
"remote": self.remote_executor.remote_name
|
|
31
|
-
}
|
|
32
|
-
|
|
24
|
+
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in tracked configuration", "running": False, "pid": None, "command": None, "remote": self.remote_executor.remote_name}
|
|
25
|
+
|
|
33
26
|
# Use the verified method by default for more accurate results
|
|
34
27
|
if use_verification:
|
|
35
28
|
return self.get_verified_process_status(tab_name, tab_config)
|
|
36
|
-
|
|
29
|
+
|
|
37
30
|
return self._basic_process_check(tab_name, tab_config)
|
|
38
|
-
|
|
31
|
+
|
|
39
32
|
def _basic_process_check(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
|
|
40
33
|
"""Basic process checking without verification."""
|
|
41
34
|
_, command = tab_config[tab_name]
|
|
42
|
-
|
|
35
|
+
|
|
43
36
|
try:
|
|
44
37
|
check_script = self._create_process_check_script(command)
|
|
45
|
-
remote_cmd = f"$HOME/
|
|
38
|
+
remote_cmd = f"$HOME/code/machineconfig/.venv/bin/python -c {shlex.quote(check_script)}"
|
|
46
39
|
result = self.remote_executor.run_command(remote_cmd, timeout=15)
|
|
47
|
-
|
|
40
|
+
|
|
48
41
|
if result.returncode == 0:
|
|
49
42
|
try:
|
|
50
43
|
matching_processes = json.loads(result.stdout.strip())
|
|
51
|
-
|
|
44
|
+
|
|
52
45
|
if matching_processes:
|
|
53
|
-
return {
|
|
54
|
-
"status": "running",
|
|
55
|
-
"running": True,
|
|
56
|
-
"processes": matching_processes,
|
|
57
|
-
"command": command,
|
|
58
|
-
"tab_name": tab_name,
|
|
59
|
-
"remote": self.remote_executor.remote_name
|
|
60
|
-
}
|
|
46
|
+
return {"status": "running", "running": True, "processes": matching_processes, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
61
47
|
else:
|
|
62
|
-
return {
|
|
63
|
-
"status": "not_running",
|
|
64
|
-
"running": False,
|
|
65
|
-
"processes": [],
|
|
66
|
-
"command": command,
|
|
67
|
-
"tab_name": tab_name,
|
|
68
|
-
"remote": self.remote_executor.remote_name
|
|
69
|
-
}
|
|
48
|
+
return {"status": "not_running", "running": False, "processes": [], "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
70
49
|
except json.JSONDecodeError as e:
|
|
71
50
|
logger.error(f"Failed to parse remote process check output: {e}")
|
|
72
|
-
return {
|
|
73
|
-
"status": "error",
|
|
74
|
-
"error": f"Failed to parse remote output: {e}",
|
|
75
|
-
"running": False,
|
|
76
|
-
"command": command,
|
|
77
|
-
"tab_name": tab_name,
|
|
78
|
-
"remote": self.remote_executor.remote_name
|
|
79
|
-
}
|
|
51
|
+
return {"status": "error", "error": f"Failed to parse remote output: {e}", "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
80
52
|
else:
|
|
81
|
-
return {
|
|
82
|
-
|
|
83
|
-
"error": f"Remote command failed: {result.stderr}",
|
|
84
|
-
"running": False,
|
|
85
|
-
"command": command,
|
|
86
|
-
"tab_name": tab_name,
|
|
87
|
-
"remote": self.remote_executor.remote_name
|
|
88
|
-
}
|
|
89
|
-
|
|
53
|
+
return {"status": "error", "error": f"Remote command failed: {result.stderr}", "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
54
|
+
|
|
90
55
|
except Exception as e:
|
|
91
56
|
logger.error(f"Error checking command status for tab '{tab_name}': {e}")
|
|
92
|
-
return {
|
|
93
|
-
|
|
94
|
-
"error": str(e),
|
|
95
|
-
"running": False,
|
|
96
|
-
"command": command,
|
|
97
|
-
"tab_name": tab_name,
|
|
98
|
-
"remote": self.remote_executor.remote_name
|
|
99
|
-
}
|
|
100
|
-
|
|
57
|
+
return {"status": "error", "error": str(e), "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
58
|
+
|
|
101
59
|
def _create_process_check_script(self, command: str) -> str:
|
|
102
60
|
"""Create Python script for checking processes on remote machine."""
|
|
103
61
|
return f"""
|
|
@@ -110,25 +68,25 @@ def check_process():
|
|
|
110
68
|
full_command = '{command}'
|
|
111
69
|
cmd_parts = [part for part in full_command.split() if len(part) > 2]
|
|
112
70
|
current_pid = os.getpid()
|
|
113
|
-
|
|
71
|
+
|
|
114
72
|
primary_cmd = cmd_parts[0] if cmd_parts else ''
|
|
115
|
-
|
|
73
|
+
|
|
116
74
|
for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'status', 'create_time']):
|
|
117
75
|
try:
|
|
118
76
|
if proc.info['pid'] == current_pid:
|
|
119
77
|
continue
|
|
120
|
-
|
|
78
|
+
|
|
121
79
|
if proc.info['cmdline'] and len(proc.info['cmdline']) > 0:
|
|
122
80
|
cmdline_str = ' '.join(proc.info['cmdline'])
|
|
123
|
-
|
|
81
|
+
|
|
124
82
|
if 'check_process()' in cmdline_str or 'psutil.process_iter' in cmdline_str:
|
|
125
83
|
continue
|
|
126
|
-
|
|
84
|
+
|
|
127
85
|
matches_primary = primary_cmd in cmdline_str
|
|
128
86
|
matches_parts = sum(1 for part in cmd_parts[1:] if part in cmdline_str)
|
|
129
|
-
|
|
87
|
+
|
|
130
88
|
if (matches_primary and matches_parts >= 2) or \\
|
|
131
|
-
(full_command in cmdline_str and not any(python_indicator in cmdline_str.lower()
|
|
89
|
+
(full_command in cmdline_str and not any(python_indicator in cmdline_str.lower()
|
|
132
90
|
for python_indicator in ['python -c', 'import psutil', 'def check_process'])):
|
|
133
91
|
matching_processes.append({{
|
|
134
92
|
"pid": proc.info['pid'],
|
|
@@ -140,41 +98,35 @@ def check_process():
|
|
|
140
98
|
}})
|
|
141
99
|
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
142
100
|
continue
|
|
143
|
-
|
|
101
|
+
|
|
144
102
|
return matching_processes
|
|
145
103
|
|
|
146
104
|
if __name__ == "__main__":
|
|
147
105
|
processes = check_process()
|
|
148
106
|
print(json.dumps(processes))
|
|
149
107
|
"""
|
|
150
|
-
|
|
108
|
+
|
|
151
109
|
def force_fresh_process_check(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
|
|
152
110
|
"""Force a fresh process check with additional validation."""
|
|
153
111
|
if tab_name not in tab_config:
|
|
154
|
-
return {
|
|
155
|
-
|
|
156
|
-
"error": f"Tab '{tab_name}' not found in tracked configuration",
|
|
157
|
-
"running": False,
|
|
158
|
-
"command": None,
|
|
159
|
-
"remote": self.remote_executor.remote_name
|
|
160
|
-
}
|
|
161
|
-
|
|
112
|
+
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in tracked configuration", "running": False, "command": None, "remote": self.remote_executor.remote_name}
|
|
113
|
+
|
|
162
114
|
_, command = tab_config[tab_name]
|
|
163
|
-
|
|
115
|
+
|
|
164
116
|
try:
|
|
165
117
|
# Get timestamp for freshness validation
|
|
166
118
|
timestamp_result = self.remote_executor.run_command("date +%s", timeout=5)
|
|
167
119
|
check_timestamp = timestamp_result.stdout.strip() if timestamp_result.returncode == 0 else "unknown"
|
|
168
|
-
|
|
120
|
+
|
|
169
121
|
check_script = self._create_fresh_check_script(command)
|
|
170
|
-
remote_cmd = f"$HOME/
|
|
122
|
+
remote_cmd = f"$HOME/code/machineconfig/.venv/bin/python -c {shlex.quote(check_script)}"
|
|
171
123
|
result = self.remote_executor.run_command(remote_cmd, timeout=15)
|
|
172
|
-
|
|
124
|
+
|
|
173
125
|
if result.returncode == 0:
|
|
174
126
|
try:
|
|
175
127
|
check_result = json.loads(result.stdout.strip())
|
|
176
128
|
matching_processes = check_result.get("processes", [])
|
|
177
|
-
|
|
129
|
+
|
|
178
130
|
return {
|
|
179
131
|
"status": "running" if matching_processes else "not_running",
|
|
180
132
|
"running": bool(matching_processes),
|
|
@@ -183,45 +135,23 @@ if __name__ == "__main__":
|
|
|
183
135
|
"tab_name": tab_name,
|
|
184
136
|
"remote": self.remote_executor.remote_name,
|
|
185
137
|
"check_timestamp": check_timestamp,
|
|
186
|
-
"method": "force_fresh_check"
|
|
138
|
+
"method": "force_fresh_check",
|
|
187
139
|
}
|
|
188
140
|
except json.JSONDecodeError as e:
|
|
189
141
|
logger.error(f"Failed to parse fresh check output: {e}")
|
|
190
|
-
return {
|
|
191
|
-
"status": "error",
|
|
192
|
-
"error": f"Failed to parse output: {e}",
|
|
193
|
-
"running": False,
|
|
194
|
-
"command": command,
|
|
195
|
-
"tab_name": tab_name,
|
|
196
|
-
"remote": self.remote_executor.remote_name,
|
|
197
|
-
"raw_output": result.stdout
|
|
198
|
-
}
|
|
142
|
+
return {"status": "error", "error": f"Failed to parse output: {e}", "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name, "raw_output": result.stdout}
|
|
199
143
|
else:
|
|
200
|
-
return {
|
|
201
|
-
|
|
202
|
-
"error": f"Remote command failed: {result.stderr}",
|
|
203
|
-
"running": False,
|
|
204
|
-
"command": command,
|
|
205
|
-
"tab_name": tab_name,
|
|
206
|
-
"remote": self.remote_executor.remote_name
|
|
207
|
-
}
|
|
208
|
-
|
|
144
|
+
return {"status": "error", "error": f"Remote command failed: {result.stderr}", "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
145
|
+
|
|
209
146
|
except Exception as e:
|
|
210
147
|
logger.error(f"Error in fresh process check for tab '{tab_name}': {e}")
|
|
211
|
-
return {
|
|
212
|
-
|
|
213
|
-
"error": str(e),
|
|
214
|
-
"running": False,
|
|
215
|
-
"command": command,
|
|
216
|
-
"tab_name": tab_name,
|
|
217
|
-
"remote": self.remote_executor.remote_name
|
|
218
|
-
}
|
|
219
|
-
|
|
148
|
+
return {"status": "error", "error": str(e), "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
149
|
+
|
|
220
150
|
def _create_fresh_check_script(self, command: str) -> str:
|
|
221
151
|
"""Create enhanced process checking script with freshness validation."""
|
|
222
152
|
escaped_command = command.replace("'", "\\'").replace('"', '\\"')
|
|
223
|
-
|
|
224
|
-
return f
|
|
153
|
+
|
|
154
|
+
return f"""
|
|
225
155
|
import psutil
|
|
226
156
|
import json
|
|
227
157
|
import os
|
|
@@ -229,40 +159,40 @@ import time
|
|
|
229
159
|
|
|
230
160
|
def force_fresh_check():
|
|
231
161
|
time.sleep(0.1)
|
|
232
|
-
|
|
162
|
+
|
|
233
163
|
matching_processes = []
|
|
234
164
|
full_command = '{escaped_command}'
|
|
235
165
|
cmd_parts = [part for part in full_command.split() if len(part) > 2]
|
|
236
166
|
current_pid = os.getpid()
|
|
237
167
|
primary_cmd = cmd_parts[0] if cmd_parts else ''
|
|
238
|
-
|
|
168
|
+
|
|
239
169
|
check_time = time.time()
|
|
240
|
-
|
|
170
|
+
|
|
241
171
|
for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'status', 'create_time']):
|
|
242
172
|
try:
|
|
243
173
|
if proc.info['pid'] == current_pid:
|
|
244
174
|
continue
|
|
245
|
-
|
|
175
|
+
|
|
246
176
|
if proc.info['cmdline'] and len(proc.info['cmdline']) > 0:
|
|
247
177
|
cmdline_str = ' '.join(proc.info['cmdline'])
|
|
248
|
-
|
|
178
|
+
|
|
249
179
|
if any(indicator in cmdline_str for indicator in [
|
|
250
180
|
'check_process()', 'psutil.process_iter', 'force_fresh_check',
|
|
251
181
|
'import psutil', 'def check_process'
|
|
252
182
|
]):
|
|
253
183
|
continue
|
|
254
|
-
|
|
184
|
+
|
|
255
185
|
if proc.info['create_time'] and proc.info['create_time'] > check_time - 5:
|
|
256
186
|
continue
|
|
257
|
-
|
|
187
|
+
|
|
258
188
|
matches_primary = primary_cmd in cmdline_str and primary_cmd != 'python'
|
|
259
189
|
matches_parts = sum(1 for part in cmd_parts[1:] if part in cmdline_str)
|
|
260
|
-
|
|
190
|
+
|
|
261
191
|
if matches_primary and matches_parts >= 2:
|
|
262
192
|
script_indicators = ['-c', 'import ', 'def ', 'psutil']
|
|
263
|
-
is_direct_command = not any(script_indicator in cmdline_str.lower()
|
|
193
|
+
is_direct_command = not any(script_indicator in cmdline_str.lower()
|
|
264
194
|
for script_indicator in script_indicators)
|
|
265
|
-
|
|
195
|
+
|
|
266
196
|
if is_direct_command or (full_command in cmdline_str and 'python -c' not in cmdline_str):
|
|
267
197
|
matching_processes.append({{
|
|
268
198
|
"pid": proc.info['pid'],
|
|
@@ -275,7 +205,7 @@ def force_fresh_check():
|
|
|
275
205
|
}})
|
|
276
206
|
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
277
207
|
continue
|
|
278
|
-
|
|
208
|
+
|
|
279
209
|
return {{
|
|
280
210
|
"processes": matching_processes,
|
|
281
211
|
"check_timestamp": check_time,
|
|
@@ -286,24 +216,24 @@ def force_fresh_check():
|
|
|
286
216
|
if __name__ == "__main__":
|
|
287
217
|
result = force_fresh_check()
|
|
288
218
|
print(json.dumps(result))
|
|
289
|
-
|
|
290
|
-
|
|
219
|
+
"""
|
|
220
|
+
|
|
291
221
|
def verify_process_alive(self, pid: int) -> bool:
|
|
292
222
|
"""Verify if a process with given PID is actually alive."""
|
|
293
223
|
try:
|
|
294
224
|
verify_cmd = f"kill -0 {pid} 2>/dev/null && echo 'alive' || echo 'dead'"
|
|
295
225
|
result = self.remote_executor.run_command(verify_cmd, timeout=5)
|
|
296
|
-
|
|
226
|
+
|
|
297
227
|
if result.returncode == 0:
|
|
298
|
-
return result.stdout.strip() ==
|
|
228
|
+
return result.stdout.strip() == "alive"
|
|
299
229
|
return False
|
|
300
230
|
except Exception:
|
|
301
231
|
return False
|
|
302
|
-
|
|
232
|
+
|
|
303
233
|
def get_verified_process_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
|
|
304
234
|
"""Get process status with additional verification that processes are actually alive."""
|
|
305
235
|
status = self.force_fresh_process_check(tab_name, tab_config)
|
|
306
|
-
|
|
236
|
+
|
|
307
237
|
if status.get("running") and status.get("processes"):
|
|
308
238
|
verified_processes = []
|
|
309
239
|
for proc in status["processes"]:
|
|
@@ -314,20 +244,20 @@ if __name__ == "__main__":
|
|
|
314
244
|
else:
|
|
315
245
|
proc["verified_alive"] = False
|
|
316
246
|
logger.warning(f"Process PID {pid} found in process list but not actually alive")
|
|
317
|
-
|
|
247
|
+
|
|
318
248
|
status["processes"] = verified_processes
|
|
319
249
|
status["running"] = bool(verified_processes)
|
|
320
250
|
status["status"] = "running" if verified_processes else "not_running"
|
|
321
251
|
status["verification_method"] = "kill_signal_check"
|
|
322
|
-
|
|
252
|
+
|
|
323
253
|
return status
|
|
324
|
-
|
|
254
|
+
|
|
325
255
|
def check_all_commands_status(self, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Dict[str, Any]]:
|
|
326
256
|
"""Check status of all commands in the tab configuration."""
|
|
327
257
|
if not tab_config:
|
|
328
258
|
logger.warning("No tab configuration provided.")
|
|
329
259
|
return {}
|
|
330
|
-
|
|
260
|
+
|
|
331
261
|
status_report = {}
|
|
332
262
|
for tab_name in tab_config:
|
|
333
263
|
status_report[tab_name] = self.check_command_status(tab_name, tab_config)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Remote command execution utilities for SSH operations.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
import subprocess
|
|
6
7
|
import logging
|
|
7
8
|
from typing import Dict, Any
|
|
@@ -11,20 +12,15 @@ logger = logging.getLogger(__name__)
|
|
|
11
12
|
|
|
12
13
|
class RemoteExecutor:
|
|
13
14
|
"""Handles SSH command execution on remote machines."""
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
def __init__(self, remote_name: str):
|
|
16
17
|
self.remote_name = remote_name
|
|
17
|
-
|
|
18
|
+
|
|
18
19
|
def run_command(self, command: str, timeout: int = 30) -> subprocess.CompletedProcess[str]:
|
|
19
20
|
"""Execute a command on the remote machine via SSH."""
|
|
20
21
|
ssh_cmd = ["ssh", self.remote_name, command]
|
|
21
22
|
try:
|
|
22
|
-
result = subprocess.run(
|
|
23
|
-
ssh_cmd,
|
|
24
|
-
capture_output=True,
|
|
25
|
-
text=True,
|
|
26
|
-
timeout=timeout
|
|
27
|
-
)
|
|
23
|
+
result = subprocess.run(ssh_cmd, capture_output=True, text=True, timeout=timeout)
|
|
28
24
|
return result
|
|
29
25
|
except subprocess.TimeoutExpired:
|
|
30
26
|
logger.error(f"SSH command timed out after {timeout}s: {command}")
|
|
@@ -32,7 +28,7 @@ class RemoteExecutor:
|
|
|
32
28
|
except Exception as e:
|
|
33
29
|
logger.error(f"SSH command failed: {e}")
|
|
34
30
|
raise
|
|
35
|
-
|
|
31
|
+
|
|
36
32
|
def copy_file_to_remote(self, local_file: str, remote_path: str) -> Dict[str, Any]:
|
|
37
33
|
"""Copy a file to the remote machine using SCP."""
|
|
38
34
|
scp_cmd = ["scp", local_file, f"{self.remote_name}:{remote_path}"]
|
|
@@ -47,7 +43,7 @@ class RemoteExecutor:
|
|
|
47
43
|
except Exception as e:
|
|
48
44
|
logger.error(f"SCP operation failed: {e}")
|
|
49
45
|
return {"success": False, "error": str(e)}
|
|
50
|
-
|
|
46
|
+
|
|
51
47
|
def create_remote_directory(self, remote_dir: str) -> bool:
|
|
52
48
|
"""Create a directory on the remote machine."""
|
|
53
49
|
try:
|
|
@@ -56,7 +52,7 @@ class RemoteExecutor:
|
|
|
56
52
|
except Exception as e:
|
|
57
53
|
logger.error(f"Failed to create remote directory {remote_dir}: {e}")
|
|
58
54
|
return False
|
|
59
|
-
|
|
55
|
+
|
|
60
56
|
def attach_to_session_interactive(self, session_name: str) -> None:
|
|
61
57
|
"""Attach to a Zellij session interactively via SSH."""
|
|
62
58
|
try:
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Zellij session management utilities for remote operations.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
import logging
|
|
6
7
|
from typing import Dict, Any, Optional
|
|
7
8
|
from pathlib import Path
|
|
@@ -16,62 +17,46 @@ console = Console()
|
|
|
16
17
|
|
|
17
18
|
class SessionManager:
|
|
18
19
|
"""Handles Zellij session operations on remote machines."""
|
|
19
|
-
|
|
20
|
+
|
|
20
21
|
def __init__(self, remote_executor: RemoteExecutor, session_name: str, tmp_layout_dir: Path):
|
|
21
22
|
self.remote_executor = remote_executor
|
|
22
23
|
self.session_name = session_name
|
|
23
24
|
self.tmp_layout_dir = tmp_layout_dir
|
|
24
|
-
|
|
25
|
+
|
|
25
26
|
def copy_layout_to_remote(self, local_layout_file: Path, random_suffix: str) -> str:
|
|
26
27
|
"""Copy the layout file to the remote machine and return the remote path."""
|
|
27
28
|
remote_layout_dir = f"~/{self.tmp_layout_dir.relative_to(Path.home())}"
|
|
28
29
|
remote_layout_file = f"{remote_layout_dir}/zellij_layout_{self.session_name}_{random_suffix}.kdl"
|
|
29
|
-
|
|
30
|
+
|
|
30
31
|
# Create remote directory
|
|
31
32
|
if not self.remote_executor.create_remote_directory(remote_layout_dir):
|
|
32
33
|
raise RuntimeError(f"Failed to create remote directory: {remote_layout_dir}")
|
|
33
|
-
|
|
34
|
+
|
|
34
35
|
# Copy layout file to remote machine
|
|
35
36
|
copy_result = self.remote_executor.copy_file_to_remote(str(local_layout_file), remote_layout_file)
|
|
36
37
|
if not copy_result["success"]:
|
|
37
38
|
raise RuntimeError(f"Failed to copy layout file to remote: {copy_result['error']}")
|
|
38
|
-
|
|
39
|
+
|
|
39
40
|
# Enhanced Rich logging
|
|
40
41
|
console.print(f"[bold green]📁 Zellij layout file copied to remote:[/bold green] [yellow]{self.remote_executor.remote_name}[/yellow][cyan]:{remote_layout_file}[/cyan]")
|
|
41
42
|
return remote_layout_file
|
|
42
|
-
|
|
43
|
+
|
|
43
44
|
def check_zellij_session_status(self) -> Dict[str, Any]:
|
|
44
45
|
"""Check if the Zellij session exists and is running."""
|
|
45
46
|
try:
|
|
46
|
-
result = self.remote_executor.run_command(
|
|
47
|
-
|
|
47
|
+
result = self.remote_executor.run_command("zellij list-sessions", timeout=10)
|
|
48
|
+
|
|
48
49
|
if result.returncode == 0:
|
|
49
|
-
sessions = result.stdout.strip().split(
|
|
50
|
+
sessions = result.stdout.strip().split("\n") if result.stdout.strip() else []
|
|
50
51
|
session_running = any(self.session_name in session for session in sessions)
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
"zellij_running": True,
|
|
54
|
-
"session_exists": session_running,
|
|
55
|
-
"session_name": self.session_name,
|
|
56
|
-
"all_sessions": sessions,
|
|
57
|
-
"remote": self.remote_executor.remote_name
|
|
58
|
-
}
|
|
52
|
+
|
|
53
|
+
return {"zellij_running": True, "session_exists": session_running, "session_name": self.session_name, "all_sessions": sessions, "remote": self.remote_executor.remote_name}
|
|
59
54
|
else:
|
|
60
|
-
return {
|
|
61
|
-
|
|
62
|
-
"error": result.stderr,
|
|
63
|
-
"session_name": self.session_name,
|
|
64
|
-
"remote": self.remote_executor.remote_name
|
|
65
|
-
}
|
|
66
|
-
|
|
55
|
+
return {"zellij_running": False, "error": result.stderr, "session_name": self.session_name, "remote": self.remote_executor.remote_name}
|
|
56
|
+
|
|
67
57
|
except Exception as e:
|
|
68
|
-
return {
|
|
69
|
-
|
|
70
|
-
"error": str(e),
|
|
71
|
-
"session_name": self.session_name,
|
|
72
|
-
"remote": self.remote_executor.remote_name
|
|
73
|
-
}
|
|
74
|
-
|
|
58
|
+
return {"zellij_running": False, "error": str(e), "session_name": self.session_name, "remote": self.remote_executor.remote_name}
|
|
59
|
+
|
|
75
60
|
def start_zellij_session(self, layout_file_path: Optional[str] = None) -> Dict[str, Any]:
|
|
76
61
|
"""Start a Zellij session on the remote machine with the generated layout."""
|
|
77
62
|
try:
|
|
@@ -80,40 +65,27 @@ class SessionManager:
|
|
|
80
65
|
remote_layout_file = f"~/{self.tmp_layout_dir.relative_to(Path.home())}/{layout_filename}"
|
|
81
66
|
else:
|
|
82
67
|
raise ValueError("No layout file path provided.")
|
|
83
|
-
|
|
68
|
+
|
|
84
69
|
# Enhanced Rich logging for session start
|
|
85
|
-
console.print(
|
|
86
|
-
|
|
70
|
+
console.print(
|
|
71
|
+
f"[bold cyan]🚀 Starting Zellij session[/bold cyan] [yellow]'{self.session_name}'[/yellow] [dim]on remote[/dim] [bold yellow]'{self.remote_executor.remote_name}'[/bold yellow] [dim]with layout:[/dim] [blue]{remote_layout_file}[/blue]"
|
|
72
|
+
)
|
|
73
|
+
|
|
87
74
|
# Start Zellij session with layout
|
|
88
75
|
start_cmd = f"zellij --layout {remote_layout_file} a -b {self.session_name}"
|
|
89
76
|
console.print(f"[dim]Executing:[/dim] [green]{start_cmd}[/green]")
|
|
90
77
|
result = self.remote_executor.run_command(start_cmd, timeout=30)
|
|
91
|
-
|
|
78
|
+
|
|
92
79
|
if result.returncode == 0:
|
|
93
80
|
console.print(f"[bold green]✅ Zellij session[/bold green] [yellow]'{self.session_name}'[/yellow] [green]started successfully on[/green] [bold yellow]{self.remote_executor.remote_name}[/bold yellow]")
|
|
94
|
-
return {
|
|
95
|
-
"success": True,
|
|
96
|
-
"session_name": self.session_name,
|
|
97
|
-
"remote": self.remote_executor.remote_name,
|
|
98
|
-
"message": "Session started successfully"
|
|
99
|
-
}
|
|
81
|
+
return {"success": True, "session_name": self.session_name, "remote": self.remote_executor.remote_name, "message": "Session started successfully"}
|
|
100
82
|
else:
|
|
101
|
-
return {
|
|
102
|
-
|
|
103
|
-
"error": result.stderr,
|
|
104
|
-
"session_name": self.session_name,
|
|
105
|
-
"remote": self.remote_executor.remote_name
|
|
106
|
-
}
|
|
107
|
-
|
|
83
|
+
return {"success": False, "error": result.stderr, "session_name": self.session_name, "remote": self.remote_executor.remote_name}
|
|
84
|
+
|
|
108
85
|
except Exception as e:
|
|
109
86
|
logger.error(f"Failed to start Zellij session on {self.remote_executor.remote_name}: {e}")
|
|
110
|
-
return {
|
|
111
|
-
|
|
112
|
-
"error": str(e),
|
|
113
|
-
"session_name": self.session_name,
|
|
114
|
-
"remote": self.remote_executor.remote_name
|
|
115
|
-
}
|
|
116
|
-
|
|
87
|
+
return {"success": False, "error": str(e), "session_name": self.session_name, "remote": self.remote_executor.remote_name}
|
|
88
|
+
|
|
117
89
|
def attach_to_session(self) -> None:
|
|
118
90
|
"""Attach to the Zellij session on the remote machine via SSH."""
|
|
119
91
|
self.remote_executor.attach_to_session_interactive(self.session_name)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Status reporting utilities for Zellij remote layouts.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
import logging
|
|
6
7
|
from typing import Dict, Any, Tuple
|
|
7
8
|
from .process_monitor import ProcessMonitor
|
|
@@ -12,19 +13,19 @@ logger = logging.getLogger(__name__)
|
|
|
12
13
|
|
|
13
14
|
class StatusReporter:
|
|
14
15
|
"""Handles comprehensive status reporting for Zellij remote sessions."""
|
|
15
|
-
|
|
16
|
+
|
|
16
17
|
def __init__(self, process_monitor: ProcessMonitor, session_manager: SessionManager):
|
|
17
18
|
self.process_monitor = process_monitor
|
|
18
19
|
self.session_manager = session_manager
|
|
19
|
-
|
|
20
|
+
|
|
20
21
|
def get_comprehensive_status(self, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
|
|
21
22
|
"""Get comprehensive status including Zellij session and all commands."""
|
|
22
23
|
zellij_status = self.session_manager.check_zellij_session_status()
|
|
23
24
|
commands_status = self.process_monitor.check_all_commands_status(tab_config)
|
|
24
|
-
|
|
25
|
+
|
|
25
26
|
running_count = sum(1 for status in commands_status.values() if status.get("running", False))
|
|
26
27
|
total_count = len(commands_status)
|
|
27
|
-
|
|
28
|
+
|
|
28
29
|
return {
|
|
29
30
|
"zellij_session": zellij_status,
|
|
30
31
|
"commands": commands_status,
|
|
@@ -33,20 +34,20 @@ class StatusReporter:
|
|
|
33
34
|
"running_commands": running_count,
|
|
34
35
|
"stopped_commands": total_count - running_count,
|
|
35
36
|
"session_healthy": zellij_status.get("session_exists", False),
|
|
36
|
-
"remote": self.session_manager.remote_executor.remote_name
|
|
37
|
-
}
|
|
37
|
+
"remote": self.session_manager.remote_executor.remote_name,
|
|
38
|
+
},
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
+
|
|
40
41
|
def print_status_report(self, tab_config: Dict[str, Tuple[str, str]]) -> None:
|
|
41
42
|
"""Print a formatted status report to console."""
|
|
42
43
|
status = self.get_comprehensive_status(tab_config)
|
|
43
44
|
remote_name = self.session_manager.remote_executor.remote_name
|
|
44
45
|
session_name = self.session_manager.session_name
|
|
45
|
-
|
|
46
|
+
|
|
46
47
|
print("=" * 60)
|
|
47
48
|
print(f"🔍 ZELLIJ REMOTE LAYOUT STATUS REPORT ({remote_name})")
|
|
48
49
|
print("=" * 60)
|
|
49
|
-
|
|
50
|
+
|
|
50
51
|
# Zellij session status
|
|
51
52
|
zellij = status["zellij_session"]
|
|
52
53
|
if zellij.get("zellij_running", False):
|
|
@@ -56,13 +57,13 @@ class StatusReporter:
|
|
|
56
57
|
print(f"⚠️ Zellij is running on {remote_name} but session '{session_name}' not found")
|
|
57
58
|
else:
|
|
58
59
|
print(f"❌ Zellij session issue on {remote_name}: {zellij.get('error', 'Unknown error')}")
|
|
59
|
-
|
|
60
|
+
|
|
60
61
|
print()
|
|
61
|
-
|
|
62
|
+
|
|
62
63
|
# Commands status
|
|
63
64
|
print("📋 COMMAND STATUS:")
|
|
64
65
|
print("-" * 40)
|
|
65
|
-
|
|
66
|
+
|
|
66
67
|
for tab_name, cmd_status in status["commands"].items():
|
|
67
68
|
if cmd_status.get("running", False):
|
|
68
69
|
print(f"✅ {tab_name}: Running on {remote_name}")
|
|
@@ -73,7 +74,7 @@ class StatusReporter:
|
|
|
73
74
|
print(f"❌ {tab_name}: Not running on {remote_name}")
|
|
74
75
|
print(f" Command: {cmd_status.get('command', 'Unknown')}")
|
|
75
76
|
print()
|
|
76
|
-
|
|
77
|
+
|
|
77
78
|
# Summary
|
|
78
79
|
summary = status["summary"]
|
|
79
80
|
print("📊 SUMMARY:")
|