machineconfig 2.0__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 +0 -3
- machineconfig/cluster/data_transfer.py +0 -1
- machineconfig/cluster/file_manager.py +0 -1
- machineconfig/cluster/job_params.py +0 -3
- machineconfig/cluster/loader_runner.py +0 -3
- machineconfig/cluster/remote_machine.py +0 -1
- machineconfig/cluster/script_notify_upon_completion.py +0 -1
- machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +3 -5
- machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -1
- machineconfig/cluster/sessions_managers/enhanced_command_runner.py +17 -57
- machineconfig/cluster/sessions_managers/wt_local.py +36 -110
- machineconfig/cluster/sessions_managers/wt_local_manager.py +42 -112
- machineconfig/cluster/sessions_managers/wt_remote.py +23 -30
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +20 -62
- machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +10 -15
- machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +27 -127
- machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +10 -43
- machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +22 -101
- machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +11 -39
- machineconfig/cluster/sessions_managers/zellij_local.py +49 -102
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +34 -78
- machineconfig/cluster/sessions_managers/zellij_remote.py +17 -24
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +7 -13
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +4 -2
- machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +6 -6
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +18 -88
- machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +2 -6
- machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +12 -40
- machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -2
- 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 +26 -10
- machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
- machineconfig/jobs/python/check_installations.py +1 -0
- machineconfig/jobs/python/create_bootable_media.py +0 -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 +13 -14
- machineconfig/jobs/python/vscode/select_interpreter.py +21 -22
- machineconfig/jobs/python/vscode/sync_code.py +9 -13
- machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_custom_installers/archive/ngrok.py +13 -13
- machineconfig/jobs/python_custom_installers/dev/aider.py +7 -15
- machineconfig/jobs/python_custom_installers/dev/alacritty.py +9 -18
- machineconfig/jobs/python_custom_installers/dev/brave.py +10 -19
- machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +8 -15
- machineconfig/jobs/python_custom_installers/dev/code.py +14 -21
- machineconfig/jobs/python_custom_installers/dev/cursor.py +3 -14
- machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +8 -7
- machineconfig/jobs/python_custom_installers/dev/espanso.py +15 -19
- machineconfig/jobs/python_custom_installers/dev/goes.py +5 -12
- machineconfig/jobs/python_custom_installers/dev/lvim.py +9 -17
- machineconfig/jobs/python_custom_installers/dev/nerdfont.py +12 -19
- machineconfig/jobs/python_custom_installers/dev/redis.py +12 -20
- machineconfig/jobs/python_custom_installers/dev/wezterm.py +12 -19
- machineconfig/jobs/python_custom_installers/dev/winget.py +5 -23
- machineconfig/jobs/python_custom_installers/docker.py +12 -21
- machineconfig/jobs/python_custom_installers/gh.py +11 -19
- machineconfig/jobs/python_custom_installers/hx.py +32 -16
- machineconfig/jobs/python_custom_installers/warp-cli.py +12 -20
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- 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/profile/create.py +29 -22
- machineconfig/profile/create_hardlinks.py +26 -19
- machineconfig/profile/shell.py +51 -28
- 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 +4 -6
- machineconfig/scripts/linux/fire +1 -1
- machineconfig/scripts/linux/fire_agents +3 -2
- machineconfig/scripts/linux/ftpx +1 -1
- machineconfig/scripts/linux/gh_models +1 -1
- machineconfig/scripts/linux/kill_process +1 -1
- machineconfig/scripts/linux/mcinit +1 -1
- 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/generate_files.py +84 -0
- machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +2 -2
- machineconfig/scripts/python/ai/mcinit.py +7 -3
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +10 -5
- machineconfig/scripts/python/cloud_copy.py +1 -1
- machineconfig/scripts/python/cloud_mount.py +1 -1
- machineconfig/scripts/python/cloud_repo_sync.py +4 -4
- machineconfig/scripts/python/croshell.py +5 -3
- machineconfig/scripts/python/devops_add_identity.py +1 -1
- machineconfig/scripts/python/devops_add_ssh_key.py +1 -1
- machineconfig/scripts/python/devops_backup_retrieve.py +1 -1
- machineconfig/scripts/python/devops_update_repos.py +140 -52
- machineconfig/scripts/python/dotfile.py +1 -1
- machineconfig/scripts/python/fire_agents.py +28 -9
- machineconfig/scripts/python/fire_jobs.py +3 -4
- machineconfig/scripts/python/ftpx.py +2 -1
- 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/helpers2.py +2 -2
- machineconfig/scripts/python/helpers/helpers4.py +1 -2
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +1 -1
- machineconfig/scripts/python/mount_nfs.py +1 -1
- machineconfig/scripts/python/mount_ssh.py +1 -1
- machineconfig/scripts/python/repos.py +1 -1
- machineconfig/scripts/python/start_slidev.py +1 -1
- machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
- 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 +1 -1
- 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_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/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_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 +66 -12
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +44 -36
- machineconfig/utils/ai/generate_file_checklist.py +8 -10
- machineconfig/utils/ai/url2md.py +4 -2
- machineconfig/utils/cloud/onedrive/setup_oauth.py +1 -0
- machineconfig/utils/cloud/onedrive/transaction.py +63 -98
- machineconfig/utils/code.py +60 -39
- machineconfig/utils/installer.py +27 -33
- machineconfig/utils/installer_utils/installer_abc.py +8 -7
- machineconfig/utils/installer_utils/installer_class.py +149 -70
- machineconfig/utils/links.py +22 -11
- machineconfig/utils/notifications.py +197 -0
- machineconfig/utils/options.py +29 -23
- machineconfig/utils/path.py +13 -6
- machineconfig/utils/path_reduced.py +485 -216
- machineconfig/utils/procs.py +47 -41
- machineconfig/utils/scheduling.py +0 -1
- machineconfig/utils/ssh.py +157 -76
- machineconfig/utils/terminal.py +82 -37
- machineconfig/utils/utils.py +12 -10
- machineconfig/utils/utils2.py +38 -48
- machineconfig/utils/utils5.py +183 -116
- machineconfig/utils/ve.py +9 -4
- {machineconfig-2.0.dist-info → machineconfig-2.1.dist-info}/METADATA +3 -2
- {machineconfig-2.0.dist-info → machineconfig-2.1.dist-info}/RECORD +200 -217
- machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/__pycache__/python_ve_symlink.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/__pycache__/mcinit.cpython-311.pyc +0 -0
- 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-2.0.dist-info → machineconfig-2.1.dist-info}/WHEEL +0 -0
- {machineconfig-2.0.dist-info → machineconfig-2.1.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Status reporting utilities for Windows Terminal layouts and sessions.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
import logging
|
|
6
7
|
from typing import Dict, Any, Tuple
|
|
7
8
|
from .process_monitor import WTProcessMonitor
|
|
@@ -28,13 +29,7 @@ class WTStatusReporter:
|
|
|
28
29
|
return {
|
|
29
30
|
"wt_session": wt_status,
|
|
30
31
|
"commands": commands_status,
|
|
31
|
-
"summary": {
|
|
32
|
-
"total_commands": total_count,
|
|
33
|
-
"running_commands": running_count,
|
|
34
|
-
"stopped_commands": total_count - running_count,
|
|
35
|
-
"session_healthy": wt_status.get("session_exists", False),
|
|
36
|
-
"location": wt_status.get("location", "unknown")
|
|
37
|
-
}
|
|
32
|
+
"summary": {"total_commands": total_count, "running_commands": running_count, "stopped_commands": total_count - running_count, "session_healthy": wt_status.get("session_exists", False), "location": wt_status.get("location", "unknown")},
|
|
38
33
|
}
|
|
39
34
|
|
|
40
35
|
def print_status_report(self, tab_config: Dict[str, Tuple[str, str]]) -> None:
|
|
@@ -57,11 +52,11 @@ class WTStatusReporter:
|
|
|
57
52
|
if wt_session.get("session_exists", False):
|
|
58
53
|
session_windows = wt_session.get("session_windows", [])
|
|
59
54
|
all_windows = wt_session.get("all_windows", [])
|
|
60
|
-
print(
|
|
55
|
+
print("✅ Windows Terminal is running")
|
|
61
56
|
print(f" Session windows: {len(session_windows)}")
|
|
62
57
|
print(f" Total WT windows: {len(all_windows)}")
|
|
63
58
|
else:
|
|
64
|
-
print(
|
|
59
|
+
print("⚠️ Windows Terminal is running but no session windows found")
|
|
65
60
|
else:
|
|
66
61
|
error_msg = wt_session.get("error", "Unknown error")
|
|
67
62
|
print(f"❌ Windows Terminal session issue: {error_msg}")
|
|
@@ -112,19 +107,10 @@ class WTStatusReporter:
|
|
|
112
107
|
wt_windows = self.process_monitor.get_windows_terminal_windows()
|
|
113
108
|
wt_version = self.session_manager.get_wt_version()
|
|
114
109
|
|
|
115
|
-
return {
|
|
116
|
-
"success": True,
|
|
117
|
-
"windows_info": wt_windows,
|
|
118
|
-
"version_info": wt_version,
|
|
119
|
-
"location": self.process_monitor.location_name
|
|
120
|
-
}
|
|
110
|
+
return {"success": True, "windows_info": wt_windows, "version_info": wt_version, "location": self.process_monitor.location_name}
|
|
121
111
|
except Exception as e:
|
|
122
112
|
logger.error(f"Failed to get Windows Terminal overview: {e}")
|
|
123
|
-
return {
|
|
124
|
-
"success": False,
|
|
125
|
-
"error": str(e),
|
|
126
|
-
"location": self.process_monitor.location_name
|
|
127
|
-
}
|
|
113
|
+
return {"success": False, "error": str(e), "location": self.process_monitor.location_name}
|
|
128
114
|
|
|
129
115
|
def print_windows_terminal_overview(self) -> None:
|
|
130
116
|
"""Print an overview of Windows Terminal status."""
|
|
@@ -190,39 +176,25 @@ class WTStatusReporter:
|
|
|
190
176
|
"stopped_commands": summary["stopped_commands"],
|
|
191
177
|
"all_commands_running": summary["running_commands"] == summary["total_commands"],
|
|
192
178
|
"wt_windows_count": len(wt_overview.get("windows_info", {}).get("windows", [])) if wt_overview["success"] else 0,
|
|
193
|
-
"wt_version": wt_overview.get("version_info", {}).get("version", "Unknown") if wt_overview["success"] else "Unknown"
|
|
179
|
+
"wt_version": wt_overview.get("version_info", {}).get("version", "Unknown") if wt_overview["success"] else "Unknown",
|
|
194
180
|
}
|
|
195
181
|
except Exception as e:
|
|
196
182
|
logger.error(f"Failed to generate status summary: {e}")
|
|
197
|
-
return {
|
|
198
|
-
"error": str(e),
|
|
199
|
-
"session_name": self.session_manager.session_name,
|
|
200
|
-
"location": self.process_monitor.location_name
|
|
201
|
-
}
|
|
183
|
+
return {"error": str(e), "session_name": self.session_manager.session_name, "location": self.process_monitor.location_name}
|
|
202
184
|
|
|
203
185
|
def check_tab_specific_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
|
|
204
186
|
"""Get detailed status for a specific tab."""
|
|
205
187
|
if tab_name not in tab_config:
|
|
206
|
-
return {
|
|
207
|
-
"error": f"Tab '{tab_name}' not found in configuration",
|
|
208
|
-
"tab_name": tab_name
|
|
209
|
-
}
|
|
188
|
+
return {"error": f"Tab '{tab_name}' not found in configuration", "tab_name": tab_name}
|
|
210
189
|
|
|
211
190
|
try:
|
|
212
191
|
cmd_status = self.process_monitor.check_command_status(tab_name, tab_config)
|
|
213
192
|
|
|
214
193
|
# Add additional context
|
|
215
194
|
cwd, command = tab_config[tab_name]
|
|
216
|
-
cmd_status["tab_config"] = {
|
|
217
|
-
"working_directory": cwd,
|
|
218
|
-
"command": command
|
|
219
|
-
}
|
|
195
|
+
cmd_status["tab_config"] = {"working_directory": cwd, "command": command}
|
|
220
196
|
|
|
221
197
|
return cmd_status
|
|
222
198
|
except Exception as e:
|
|
223
199
|
logger.error(f"Failed to check status for tab '{tab_name}': {e}")
|
|
224
|
-
return {
|
|
225
|
-
"error": str(e),
|
|
226
|
-
"tab_name": tab_name,
|
|
227
|
-
"location": self.process_monitor.location_name
|
|
228
|
-
}
|
|
200
|
+
return {"error": str(e), "tab_name": tab_name, "location": self.process_monitor.location_name}
|
|
@@ -34,13 +34,14 @@ class ZellijLayoutGenerator:
|
|
|
34
34
|
@staticmethod
|
|
35
35
|
def _generate_random_suffix(length: int = 8) -> str:
|
|
36
36
|
"""Generate a random string suffix for unique layout file names."""
|
|
37
|
-
return
|
|
37
|
+
return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
|
|
38
38
|
|
|
39
39
|
@staticmethod
|
|
40
40
|
def _parse_command(command: str) -> tuple[str, List[str]]:
|
|
41
41
|
try:
|
|
42
42
|
parts = shlex.split(command)
|
|
43
|
-
if not parts:
|
|
43
|
+
if not parts:
|
|
44
|
+
raise ValueError("Empty command provided")
|
|
44
45
|
return parts[0], parts[1:] if len(parts) > 1 else []
|
|
45
46
|
except ValueError as e:
|
|
46
47
|
logger.error(f"Error parsing command '{command}': {e}")
|
|
@@ -49,10 +50,11 @@ class ZellijLayoutGenerator:
|
|
|
49
50
|
|
|
50
51
|
@staticmethod
|
|
51
52
|
def _format_args_for_kdl(args: List[str]) -> str:
|
|
52
|
-
if not args:
|
|
53
|
+
if not args:
|
|
54
|
+
return ""
|
|
53
55
|
formatted_args = []
|
|
54
56
|
for arg in args:
|
|
55
|
-
if
|
|
57
|
+
if " " in arg or '"' in arg or "'" in arg:
|
|
56
58
|
escaped_arg = arg.replace('"', '\\"')
|
|
57
59
|
formatted_args.append(f'"{escaped_arg}"')
|
|
58
60
|
else:
|
|
@@ -67,17 +69,22 @@ class ZellijLayoutGenerator:
|
|
|
67
69
|
escaped_tab_name = tab_name.replace('"', '\\"')
|
|
68
70
|
tab_section = f' tab name="{escaped_tab_name}" cwd="{tab_cwd}" {{\n'
|
|
69
71
|
tab_section += f' pane command="{cmd}" {{\n'
|
|
70
|
-
if args_str:
|
|
71
|
-
|
|
72
|
+
if args_str:
|
|
73
|
+
tab_section += f" args {args_str}\n"
|
|
74
|
+
tab_section += " }\n }\n"
|
|
72
75
|
return tab_section
|
|
73
76
|
|
|
74
77
|
@staticmethod
|
|
75
78
|
def _validate_tab_config(tab_config: Dict[str, tuple[str, str]]) -> None:
|
|
76
|
-
if not tab_config:
|
|
79
|
+
if not tab_config:
|
|
80
|
+
raise ValueError("Tab configuration cannot be empty")
|
|
77
81
|
for tab_name, (cwd, command) in tab_config.items():
|
|
78
|
-
if not tab_name.strip():
|
|
79
|
-
|
|
80
|
-
if not
|
|
82
|
+
if not tab_name.strip():
|
|
83
|
+
raise ValueError(f"Invalid tab name: {tab_name}")
|
|
84
|
+
if not command.strip():
|
|
85
|
+
raise ValueError(f"Invalid command for tab '{tab_name}': {command}")
|
|
86
|
+
if not cwd.strip():
|
|
87
|
+
raise ValueError(f"Invalid cwd for tab '{tab_name}': {cwd}")
|
|
81
88
|
|
|
82
89
|
def create_zellij_layout(self, tab_config: Dict[str, tuple[str, str]], output_dir: Optional[str] = None, session_name: Optional[str] = None) -> str:
|
|
83
90
|
ZellijLayoutGenerator._validate_tab_config(tab_config)
|
|
@@ -141,14 +148,7 @@ class ZellijLayoutGenerator:
|
|
|
141
148
|
@staticmethod
|
|
142
149
|
def check_command_status(tab_name: str, tab_config: Dict[str, tuple[str, str]]) -> Dict[str, Any]:
|
|
143
150
|
if tab_name not in tab_config:
|
|
144
|
-
return {
|
|
145
|
-
"status": "unknown",
|
|
146
|
-
"error": f"Tab '{tab_name}' not found in tracked tab config",
|
|
147
|
-
"running": False,
|
|
148
|
-
"pid": None,
|
|
149
|
-
"command": None,
|
|
150
|
-
"cwd": None
|
|
151
|
-
}
|
|
151
|
+
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in tracked tab config", "running": False, "pid": None, "command": None, "cwd": None}
|
|
152
152
|
|
|
153
153
|
cwd, command = tab_config[tab_name]
|
|
154
154
|
cmd, _ = ZellijLayoutGenerator._parse_command(command)
|
|
@@ -156,51 +156,23 @@ class ZellijLayoutGenerator:
|
|
|
156
156
|
try:
|
|
157
157
|
# Look for processes matching the command
|
|
158
158
|
matching_processes = []
|
|
159
|
-
for proc in psutil.process_iter([
|
|
159
|
+
for proc in psutil.process_iter(["pid", "name", "cmdline", "status"]):
|
|
160
160
|
try:
|
|
161
|
-
if proc.info[
|
|
161
|
+
if proc.info["cmdline"] and len(proc.info["cmdline"]) > 0:
|
|
162
162
|
# Check if the command matches
|
|
163
|
-
if
|
|
164
|
-
|
|
165
|
-
any(cmd in arg for arg in proc.info['cmdline'])):
|
|
166
|
-
matching_processes.append({
|
|
167
|
-
"pid": proc.info['pid'],
|
|
168
|
-
"name": proc.info['name'],
|
|
169
|
-
"cmdline": proc.info['cmdline'],
|
|
170
|
-
"status": proc.info['status']
|
|
171
|
-
})
|
|
163
|
+
if proc.info["name"] == cmd or cmd in proc.info["cmdline"][0] or any(cmd in arg for arg in proc.info["cmdline"]):
|
|
164
|
+
matching_processes.append({"pid": proc.info["pid"], "name": proc.info["name"], "cmdline": proc.info["cmdline"], "status": proc.info["status"]})
|
|
172
165
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
173
166
|
continue
|
|
174
167
|
|
|
175
168
|
if matching_processes:
|
|
176
|
-
return {
|
|
177
|
-
"status": "running",
|
|
178
|
-
"running": True,
|
|
179
|
-
"processes": matching_processes,
|
|
180
|
-
"command": command,
|
|
181
|
-
"cwd": cwd,
|
|
182
|
-
"tab_name": tab_name
|
|
183
|
-
}
|
|
169
|
+
return {"status": "running", "running": True, "processes": matching_processes, "command": command, "cwd": cwd, "tab_name": tab_name}
|
|
184
170
|
else:
|
|
185
|
-
return {
|
|
186
|
-
"status": "not_running",
|
|
187
|
-
"running": False,
|
|
188
|
-
"processes": [],
|
|
189
|
-
"command": command,
|
|
190
|
-
"cwd": cwd,
|
|
191
|
-
"tab_name": tab_name
|
|
192
|
-
}
|
|
171
|
+
return {"status": "not_running", "running": False, "processes": [], "command": command, "cwd": cwd, "tab_name": tab_name}
|
|
193
172
|
|
|
194
173
|
except Exception as e:
|
|
195
174
|
logger.error(f"Error checking command status for tab '{tab_name}': {e}")
|
|
196
|
-
return {
|
|
197
|
-
"status": "error",
|
|
198
|
-
"error": str(e),
|
|
199
|
-
"running": False,
|
|
200
|
-
"command": command,
|
|
201
|
-
"cwd": cwd,
|
|
202
|
-
"tab_name": tab_name
|
|
203
|
-
}
|
|
175
|
+
return {"status": "error", "error": str(e), "running": False, "command": command, "cwd": cwd, "tab_name": tab_name}
|
|
204
176
|
|
|
205
177
|
def check_all_commands_status(self) -> Dict[str, Dict[str, Any]]:
|
|
206
178
|
if not self.tab_config:
|
|
@@ -217,48 +189,22 @@ class ZellijLayoutGenerator:
|
|
|
217
189
|
def check_zellij_session_status(session_name: str) -> Dict[str, Any]:
|
|
218
190
|
try:
|
|
219
191
|
# Run zellij list-sessions command
|
|
220
|
-
result = subprocess.run(
|
|
221
|
-
['zellij', 'list-sessions'],
|
|
222
|
-
capture_output=True,
|
|
223
|
-
text=True,
|
|
224
|
-
timeout=10
|
|
225
|
-
)
|
|
192
|
+
result = subprocess.run(["zellij", "list-sessions"], capture_output=True, text=True, timeout=10)
|
|
226
193
|
|
|
227
194
|
if result.returncode == 0:
|
|
228
|
-
sessions = result.stdout.strip().split(
|
|
195
|
+
sessions = result.stdout.strip().split("\n") if result.stdout.strip() else []
|
|
229
196
|
session_running = any(session_name in session for session in sessions)
|
|
230
197
|
|
|
231
|
-
return {
|
|
232
|
-
"zellij_running": True,
|
|
233
|
-
"session_exists": session_running,
|
|
234
|
-
"session_name": session_name,
|
|
235
|
-
"all_sessions": sessions
|
|
236
|
-
}
|
|
198
|
+
return {"zellij_running": True, "session_exists": session_running, "session_name": session_name, "all_sessions": sessions}
|
|
237
199
|
else:
|
|
238
|
-
return {
|
|
239
|
-
"zellij_running": False,
|
|
240
|
-
"error": result.stderr,
|
|
241
|
-
"session_name": session_name
|
|
242
|
-
}
|
|
200
|
+
return {"zellij_running": False, "error": result.stderr, "session_name": session_name}
|
|
243
201
|
|
|
244
202
|
except subprocess.TimeoutExpired:
|
|
245
|
-
return {
|
|
246
|
-
"zellij_running": False,
|
|
247
|
-
"error": "Timeout while checking Zellij sessions",
|
|
248
|
-
"session_name": session_name
|
|
249
|
-
}
|
|
203
|
+
return {"zellij_running": False, "error": "Timeout while checking Zellij sessions", "session_name": session_name}
|
|
250
204
|
except FileNotFoundError:
|
|
251
|
-
return {
|
|
252
|
-
"zellij_running": False,
|
|
253
|
-
"error": "Zellij not found in PATH",
|
|
254
|
-
"session_name": session_name
|
|
255
|
-
}
|
|
205
|
+
return {"zellij_running": False, "error": "Zellij not found in PATH", "session_name": session_name}
|
|
256
206
|
except Exception as e:
|
|
257
|
-
return {
|
|
258
|
-
"zellij_running": False,
|
|
259
|
-
"error": str(e),
|
|
260
|
-
"session_name": session_name
|
|
261
|
-
}
|
|
207
|
+
return {"zellij_running": False, "error": str(e), "session_name": session_name}
|
|
262
208
|
|
|
263
209
|
def get_comprehensive_status(self) -> Dict[str, Any]:
|
|
264
210
|
zellij_status = ZellijLayoutGenerator.check_zellij_session_status(self.session_name or "default")
|
|
@@ -270,12 +216,7 @@ class ZellijLayoutGenerator:
|
|
|
270
216
|
return {
|
|
271
217
|
"zellij_session": zellij_status,
|
|
272
218
|
"commands": commands_status,
|
|
273
|
-
"summary": {
|
|
274
|
-
"total_commands": total_count,
|
|
275
|
-
"running_commands": running_count,
|
|
276
|
-
"stopped_commands": total_count - running_count,
|
|
277
|
-
"session_healthy": zellij_status.get("session_exists", False)
|
|
278
|
-
}
|
|
219
|
+
"summary": {"total_commands": total_count, "running_commands": running_count, "stopped_commands": total_count - running_count, "session_healthy": zellij_status.get("session_exists", False)},
|
|
279
220
|
}
|
|
280
221
|
|
|
281
222
|
def print_status_report(self) -> None:
|
|
@@ -296,7 +237,7 @@ class ZellijLayoutGenerator:
|
|
|
296
237
|
else:
|
|
297
238
|
console.print(f"[bold yellow]⚠️ Zellij is running but session[/bold yellow] [yellow]'{self.session_name}'[/yellow] [yellow]not found[/yellow]")
|
|
298
239
|
else:
|
|
299
|
-
error_msg = zellij.get(
|
|
240
|
+
error_msg = zellij.get("error", "Unknown error")
|
|
300
241
|
console.print(f"[bold red]❌ Zellij session issue:[/bold red] [red]{error_msg}[/red]")
|
|
301
242
|
|
|
302
243
|
console.print()
|
|
@@ -316,8 +257,8 @@ class ZellijLayoutGenerator:
|
|
|
316
257
|
processes = cmd_status.get("processes", [])
|
|
317
258
|
if processes:
|
|
318
259
|
proc = processes[0] # Show first process
|
|
319
|
-
pid = str(proc.get(
|
|
320
|
-
memory = f"{proc.get('memory_mb', 0):.1f}MB" if proc.get(
|
|
260
|
+
pid = str(proc.get("pid", "N/A"))
|
|
261
|
+
memory = f"{proc.get('memory_mb', 0):.1f}MB" if proc.get("memory_mb") else "N/A"
|
|
321
262
|
else:
|
|
322
263
|
pid = "N/A"
|
|
323
264
|
memory = "N/A"
|
|
@@ -326,7 +267,7 @@ class ZellijLayoutGenerator:
|
|
|
326
267
|
pid = "N/A"
|
|
327
268
|
memory = "N/A"
|
|
328
269
|
|
|
329
|
-
command = cmd_status.get(
|
|
270
|
+
command = cmd_status.get("command", "Unknown")
|
|
330
271
|
# Truncate long commands
|
|
331
272
|
if len(command) > 35:
|
|
332
273
|
command = command[:32] + "..."
|
|
@@ -339,29 +280,35 @@ class ZellijLayoutGenerator:
|
|
|
339
280
|
# Enhanced summary
|
|
340
281
|
summary = status["summary"]
|
|
341
282
|
from rich.panel import Panel
|
|
342
|
-
|
|
343
|
-
[
|
|
344
|
-
[
|
|
345
|
-
[
|
|
283
|
+
|
|
284
|
+
summary_text = f"""[bold]Total commands:[/bold] {summary["total_commands"]}
|
|
285
|
+
[green]Running:[/green] {summary["running_commands"]}
|
|
286
|
+
[red]Stopped:[/red] {summary["stopped_commands"]}
|
|
287
|
+
[yellow]Session healthy:[/yellow] {"✅" if summary["session_healthy"] else "❌"}"""
|
|
346
288
|
|
|
347
289
|
console.print(Panel(summary_text, title="📊 Summary", style="blue"))
|
|
348
290
|
|
|
291
|
+
|
|
349
292
|
def created_zellij_layout(tab_config: Dict[str, tuple[str, str]], output_dir: Optional[str] = None) -> str:
|
|
350
293
|
generator = ZellijLayoutGenerator()
|
|
351
294
|
return generator.create_zellij_layout(tab_config, output_dir)
|
|
295
|
+
|
|
296
|
+
|
|
352
297
|
def run_zellij_layout(tab_config: Dict[str, tuple[str, str]], session_name: Optional[str] = None) -> str:
|
|
353
298
|
if not session_name:
|
|
354
|
-
session_name =
|
|
299
|
+
session_name = "".join(random.choices(string.ascii_lowercase + string.digits, k=8))
|
|
355
300
|
layout_path = created_zellij_layout(tab_config)
|
|
356
301
|
|
|
357
302
|
# Use enhanced command execution
|
|
358
303
|
try:
|
|
359
304
|
from .enhanced_command_runner import enhanced_zellij_session_start
|
|
305
|
+
|
|
360
306
|
enhanced_zellij_session_start(session_name, layout_path)
|
|
361
307
|
except ImportError:
|
|
362
308
|
# Fallback to original implementation
|
|
363
309
|
cmd = f"zellij delete-session --force {session_name}; zellij --layout {layout_path} a -b {session_name}"
|
|
364
310
|
import subprocess
|
|
311
|
+
|
|
365
312
|
subprocess.run(cmd, shell=True, check=True)
|
|
366
313
|
console.print(f"[bold green]🚀 Zellij layout is running[/bold green] [yellow]@[/yellow] [bold cyan]{session_name}[/bold cyan]")
|
|
367
314
|
return session_name
|
|
@@ -393,7 +340,7 @@ if __name__ == "__main__":
|
|
|
393
340
|
"🤖Bot1": ("~/code/bytesense/bithence", "~/scripts/fire -mO go1.py bot1 --kw create_new_bot True"),
|
|
394
341
|
"🤖Bot2": ("~/code/bytesense/bithence", "~/scripts/fire -mO go2.py bot2 --kw create_new_bot True"),
|
|
395
342
|
"📊Monitor": ("~", "htop"),
|
|
396
|
-
"📝Logs": ("/var/log", "tail -f /var/log/app.log")
|
|
343
|
+
"📝Logs": ("/var/log", "tail -f /var/log/app.log"),
|
|
397
344
|
}
|
|
398
345
|
try:
|
|
399
346
|
# Create layout using the generator directly to access status methods
|
|
@@ -90,10 +90,7 @@ class ZellijLocalManager:
|
|
|
90
90
|
# 2. Launch new session. We intentionally do NOT wait for completion.
|
|
91
91
|
# Using the same pattern as before (attach --create) but detached via env var.
|
|
92
92
|
# ZELLIJ_AUTO_ATTACH=0 prevents auto-attach if compiled with that feature; harmless otherwise.
|
|
93
|
-
start_cmd = [
|
|
94
|
-
"bash", "-lc",
|
|
95
|
-
f"ZELLIJ_AUTO_ATTACH=0 zellij --layout {layout_path} attach {session_name} --create >/dev/null 2>&1 &"
|
|
96
|
-
]
|
|
93
|
+
start_cmd = ["bash", "-lc", f"ZELLIJ_AUTO_ATTACH=0 zellij --layout {layout_path} attach {session_name} --create >/dev/null 2>&1 &"]
|
|
97
94
|
console.print(f"[bold cyan]🚀 Starting session[/bold cyan] [yellow]'{session_name}'[/yellow] with layout [blue]{layout_path}[/blue] (non-blocking)...")
|
|
98
95
|
subprocess.Popen(start_cmd)
|
|
99
96
|
|
|
@@ -133,18 +130,12 @@ class ZellijLocalManager:
|
|
|
133
130
|
logger.info(f"Killing session '{session_name}'")
|
|
134
131
|
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=10)
|
|
135
132
|
|
|
136
|
-
results[session_name] = {
|
|
137
|
-
"success": result.returncode == 0,
|
|
138
|
-
"message": "Session killed" if result.returncode == 0 else result.stderr
|
|
139
|
-
}
|
|
133
|
+
results[session_name] = {"success": result.returncode == 0, "message": "Session killed" if result.returncode == 0 else result.stderr}
|
|
140
134
|
|
|
141
135
|
except Exception as e:
|
|
142
136
|
# Use a fallback key since session_name might not be defined here
|
|
143
|
-
key = getattr(manager,
|
|
144
|
-
results[key] = {
|
|
145
|
-
"success": False,
|
|
146
|
-
"error": str(e)
|
|
147
|
-
}
|
|
137
|
+
key = getattr(manager, "session_name", None) or f"manager_{self.managers.index(manager)}"
|
|
138
|
+
results[key] = {"success": False, "error": str(e)}
|
|
148
139
|
|
|
149
140
|
return results
|
|
150
141
|
|
|
@@ -195,12 +186,7 @@ class ZellijLocalManager:
|
|
|
195
186
|
status_report[session_name] = {
|
|
196
187
|
"session_status": session_status,
|
|
197
188
|
"commands_status": commands_status,
|
|
198
|
-
"summary": {
|
|
199
|
-
"total_commands": total_count,
|
|
200
|
-
"running_commands": running_count,
|
|
201
|
-
"stopped_commands": total_count - running_count,
|
|
202
|
-
"session_healthy": session_status.get("session_exists", False)
|
|
203
|
-
}
|
|
189
|
+
"summary": {"total_commands": total_count, "running_commands": running_count, "stopped_commands": total_count - running_count, "session_healthy": session_status.get("session_exists", False)},
|
|
204
190
|
}
|
|
205
191
|
|
|
206
192
|
return status_report
|
|
@@ -210,12 +196,9 @@ class ZellijLocalManager:
|
|
|
210
196
|
all_status = self.check_all_sessions_status()
|
|
211
197
|
|
|
212
198
|
total_sessions = len(all_status)
|
|
213
|
-
healthy_sessions = sum(1 for status in all_status.values()
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
for status in all_status.values())
|
|
217
|
-
total_running = sum(status["summary"]["running_commands"]
|
|
218
|
-
for status in all_status.values())
|
|
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())
|
|
219
202
|
|
|
220
203
|
return {
|
|
221
204
|
"total_sessions": total_sessions,
|
|
@@ -225,7 +208,7 @@ class ZellijLocalManager:
|
|
|
225
208
|
"running_commands": total_running,
|
|
226
209
|
"stopped_commands": total_commands - total_running,
|
|
227
210
|
"all_sessions_healthy": healthy_sessions == total_sessions,
|
|
228
|
-
"all_commands_running": total_running == total_commands
|
|
211
|
+
"all_commands_running": total_running == total_commands,
|
|
229
212
|
}
|
|
230
213
|
|
|
231
214
|
def print_status_report(self) -> None:
|
|
@@ -281,6 +264,7 @@ class ZellijLocalManager:
|
|
|
281
264
|
Args:
|
|
282
265
|
wait_ms: How long to wait between checks in milliseconds (default: 30000ms = 30s)
|
|
283
266
|
"""
|
|
267
|
+
|
|
284
268
|
def routine(scheduler: Scheduler):
|
|
285
269
|
print(f"\n⏰ Monitoring cycle {scheduler.cycle} at {datetime.now()}")
|
|
286
270
|
print("-" * 50)
|
|
@@ -293,13 +277,15 @@ class ZellijLocalManager:
|
|
|
293
277
|
status_data = []
|
|
294
278
|
for session_name, status in all_status.items():
|
|
295
279
|
for tab_name, cmd_status in status["commands_status"].items():
|
|
296
|
-
status_data.append(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
+
)
|
|
303
289
|
|
|
304
290
|
if status_data:
|
|
305
291
|
# Format data as table
|
|
@@ -346,13 +332,7 @@ class ZellijLocalManager:
|
|
|
346
332
|
config_file.write_text(text, encoding="utf-8")
|
|
347
333
|
|
|
348
334
|
# Save metadata
|
|
349
|
-
metadata = {
|
|
350
|
-
"session_name_prefix": self.session_name_prefix,
|
|
351
|
-
"created_at": str(datetime.now()),
|
|
352
|
-
"num_managers": len(self.managers),
|
|
353
|
-
"sessions": list(self.session2zellij_tabs.keys()),
|
|
354
|
-
"manager_type": "ZellijLocalManager"
|
|
355
|
-
}
|
|
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"}
|
|
356
336
|
metadata_file = session_dir / "metadata.json"
|
|
357
337
|
text = json.dumps(metadata, indent=2, ensure_ascii=False)
|
|
358
338
|
metadata_file.write_text(text, encoding="utf-8")
|
|
@@ -362,11 +342,7 @@ class ZellijLocalManager:
|
|
|
362
342
|
managers_dir.mkdir(exist_ok=True)
|
|
363
343
|
|
|
364
344
|
for i, manager in enumerate(self.managers):
|
|
365
|
-
manager_data = {
|
|
366
|
-
"session_name": manager.session_name,
|
|
367
|
-
"tab_config": manager.tab_config,
|
|
368
|
-
"layout_path": manager.layout_path
|
|
369
|
-
}
|
|
345
|
+
manager_data = {"session_name": manager.session_name, "tab_config": manager.tab_config, "layout_path": manager.layout_path}
|
|
370
346
|
manager_file = managers_dir / f"manager_{i}_{manager.session_name}.json"
|
|
371
347
|
text = json.dumps(manager_data, indent=2, ensure_ascii=False)
|
|
372
348
|
manager_file.write_text(text, encoding="utf-8")
|
|
@@ -375,7 +351,7 @@ class ZellijLocalManager:
|
|
|
375
351
|
return session_id
|
|
376
352
|
|
|
377
353
|
@classmethod
|
|
378
|
-
def load(cls, session_id: str) ->
|
|
354
|
+
def load(cls, session_id: str) -> "ZellijLocalManager":
|
|
379
355
|
"""Load a saved manager state from disk."""
|
|
380
356
|
session_dir = TMP_SERIALIZATION_DIR / session_id
|
|
381
357
|
|
|
@@ -387,14 +363,14 @@ class ZellijLocalManager:
|
|
|
387
363
|
if not config_file.exists():
|
|
388
364
|
raise FileNotFoundError(f"Configuration file not found: {config_file}")
|
|
389
365
|
|
|
390
|
-
with open(config_file,
|
|
366
|
+
with open(config_file, "r", encoding="utf-8") as f:
|
|
391
367
|
session2zellij_tabs = json.load(f)
|
|
392
368
|
|
|
393
369
|
# Load metadata
|
|
394
370
|
metadata_file = session_dir / "metadata.json"
|
|
395
371
|
session_name_prefix = "LocalJobMgr" # default fallback
|
|
396
372
|
if metadata_file.exists():
|
|
397
|
-
with open(metadata_file,
|
|
373
|
+
with open(metadata_file, "r", encoding="utf-8") as f:
|
|
398
374
|
metadata = json.load(f)
|
|
399
375
|
session_name_prefix = metadata.get("session_name_prefix", "LocalJobMgr")
|
|
400
376
|
|
|
@@ -409,7 +385,7 @@ class ZellijLocalManager:
|
|
|
409
385
|
|
|
410
386
|
for manager_file in manager_files:
|
|
411
387
|
try:
|
|
412
|
-
with open(manager_file,
|
|
388
|
+
with open(manager_file, "r", encoding="utf-8") as f:
|
|
413
389
|
manager_data = json.load(f)
|
|
414
390
|
|
|
415
391
|
# Recreate the manager
|
|
@@ -450,6 +426,7 @@ class ZellijLocalManager:
|
|
|
450
426
|
|
|
451
427
|
try:
|
|
452
428
|
import shutil
|
|
429
|
+
|
|
453
430
|
shutil.rmtree(session_dir)
|
|
454
431
|
logger.info(f"✅ Deleted session: {session_id}")
|
|
455
432
|
return True
|
|
@@ -463,15 +440,10 @@ class ZellijLocalManager:
|
|
|
463
440
|
|
|
464
441
|
try:
|
|
465
442
|
# Get all running zellij sessions
|
|
466
|
-
result = subprocess.run(
|
|
467
|
-
['zellij', 'list-sessions'],
|
|
468
|
-
capture_output=True,
|
|
469
|
-
text=True,
|
|
470
|
-
timeout=10
|
|
471
|
-
)
|
|
443
|
+
result = subprocess.run(["zellij", "list-sessions"], capture_output=True, text=True, timeout=10)
|
|
472
444
|
|
|
473
445
|
if result.returncode == 0:
|
|
474
|
-
all_sessions = result.stdout.strip().split(
|
|
446
|
+
all_sessions = result.stdout.strip().split("\n") if result.stdout.strip() else []
|
|
475
447
|
|
|
476
448
|
# Filter to only our managed sessions
|
|
477
449
|
for manager in self.managers:
|
|
@@ -480,12 +452,7 @@ class ZellijLocalManager:
|
|
|
480
452
|
continue # Skip managers without a session name
|
|
481
453
|
is_active = any(session_name in session for session in all_sessions)
|
|
482
454
|
|
|
483
|
-
active_sessions.append({
|
|
484
|
-
"session_name": session_name,
|
|
485
|
-
"is_active": is_active,
|
|
486
|
-
"tab_count": len(manager.tab_config),
|
|
487
|
-
"tabs": list(manager.tab_config.keys())
|
|
488
|
-
})
|
|
455
|
+
active_sessions.append({"session_name": session_name, "is_active": is_active, "tab_count": len(manager.tab_config), "tabs": list(manager.tab_config.keys())})
|
|
489
456
|
|
|
490
457
|
except Exception as e:
|
|
491
458
|
logger.error(f"Error listing active sessions: {e}")
|
|
@@ -496,21 +463,9 @@ class ZellijLocalManager:
|
|
|
496
463
|
if __name__ == "__main__":
|
|
497
464
|
# Example usage
|
|
498
465
|
sample_sessions = {
|
|
499
|
-
"development": {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
"📊Monitor": ("~", "htop")
|
|
503
|
-
},
|
|
504
|
-
"testing": {
|
|
505
|
-
"🧪Tests": ("~/code/myapp", "pytest --watch"),
|
|
506
|
-
"🔍Coverage": ("~/code/myapp", "coverage run --source=. -m pytest"),
|
|
507
|
-
"📝Logs": ("~/logs", "tail -f app.log")
|
|
508
|
-
},
|
|
509
|
-
"deployment": {
|
|
510
|
-
"🐳Docker": ("~/code/myapp", "docker-compose up"),
|
|
511
|
-
"☸️K8s": ("~/k8s", "kubectl get pods --watch"),
|
|
512
|
-
"📈Metrics": ("~", "k9s")
|
|
513
|
-
}
|
|
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")},
|
|
514
469
|
}
|
|
515
470
|
|
|
516
471
|
try:
|
|
@@ -549,4 +504,5 @@ if __name__ == "__main__":
|
|
|
549
504
|
except Exception as e:
|
|
550
505
|
print(f"❌ Error: {e}")
|
|
551
506
|
import traceback
|
|
552
|
-
|
|
507
|
+
|
|
508
|
+
traceback.print_exc()
|