machineconfig 2.1__py3-none-any.whl → 2.3__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.

Files changed (127) hide show
  1. machineconfig/cluster/sessions_managers/enhanced_command_runner.py +0 -2
  2. machineconfig/cluster/sessions_managers/layout_types.py +29 -0
  3. machineconfig/cluster/sessions_managers/wt_local.py +68 -62
  4. machineconfig/cluster/sessions_managers/wt_local_manager.py +51 -22
  5. machineconfig/cluster/sessions_managers/wt_remote.py +30 -108
  6. machineconfig/cluster/sessions_managers/wt_remote_manager.py +14 -11
  7. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +33 -37
  8. machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +22 -17
  9. machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +59 -10
  10. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +16 -14
  11. machineconfig/cluster/sessions_managers/zellij_local.py +75 -57
  12. machineconfig/cluster/sessions_managers/zellij_local_manager.py +51 -23
  13. machineconfig/cluster/sessions_managers/zellij_remote.py +47 -27
  14. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +13 -12
  15. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +14 -10
  16. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +31 -15
  17. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +47 -21
  18. machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +1 -1
  19. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +8 -7
  20. machineconfig/cluster/templates/utils.py +0 -35
  21. machineconfig/jobs/python/check_installations.py +1 -1
  22. machineconfig/jobs/python_custom_installers/dev/code.py +0 -13
  23. machineconfig/jobs/python_generic_installers/config.json +1 -1
  24. machineconfig/profile/create.py +13 -4
  25. machineconfig/profile/create_hardlinks.py +3 -1
  26. machineconfig/profile/shell.py +8 -7
  27. machineconfig/scripts/__init__.py +0 -2
  28. machineconfig/scripts/linux/devops +6 -4
  29. machineconfig/scripts/python/ai/generate_files.py +14 -15
  30. machineconfig/scripts/python/ai/mcinit.py +8 -5
  31. machineconfig/scripts/python/archive/tmate_conn.py +5 -5
  32. machineconfig/scripts/python/archive/tmate_start.py +7 -7
  33. machineconfig/scripts/python/choose_wezterm_theme.py +35 -32
  34. machineconfig/scripts/python/cloud_copy.py +22 -13
  35. machineconfig/scripts/python/cloud_mount.py +35 -23
  36. machineconfig/scripts/python/cloud_repo_sync.py +38 -25
  37. machineconfig/scripts/python/cloud_sync.py +4 -4
  38. machineconfig/scripts/python/croshell.py +37 -28
  39. machineconfig/scripts/python/devops.py +46 -27
  40. machineconfig/scripts/python/devops_add_identity.py +15 -25
  41. machineconfig/scripts/python/devops_add_ssh_key.py +7 -7
  42. machineconfig/scripts/python/devops_backup_retrieve.py +17 -15
  43. machineconfig/scripts/python/devops_devapps_install.py +26 -20
  44. machineconfig/scripts/python/devops_update_repos.py +142 -57
  45. machineconfig/scripts/python/dotfile.py +16 -14
  46. machineconfig/scripts/python/fire_agents.py +30 -23
  47. machineconfig/scripts/python/fire_jobs.py +86 -98
  48. machineconfig/scripts/python/fire_jobs_args_helper.py +84 -0
  49. machineconfig/scripts/python/fire_jobs_layout_helper.py +66 -0
  50. machineconfig/scripts/python/ftpx.py +24 -14
  51. machineconfig/scripts/python/get_zellij_cmd.py +8 -7
  52. machineconfig/scripts/python/helpers/cloud_helpers.py +33 -28
  53. machineconfig/scripts/python/helpers/helpers2.py +25 -14
  54. machineconfig/scripts/python/helpers/helpers4.py +44 -31
  55. machineconfig/scripts/python/helpers/helpers5.py +1 -1
  56. machineconfig/scripts/python/helpers/repo_sync_helpers.py +31 -9
  57. machineconfig/scripts/python/mount_nfs.py +8 -15
  58. machineconfig/scripts/python/mount_nw_drive.py +10 -5
  59. machineconfig/scripts/python/mount_ssh.py +8 -6
  60. machineconfig/scripts/python/repos.py +215 -57
  61. machineconfig/scripts/python/snapshot.py +0 -1
  62. machineconfig/scripts/python/start_slidev.py +10 -5
  63. machineconfig/scripts/python/start_terminals.py +22 -16
  64. machineconfig/scripts/python/viewer_template.py +0 -1
  65. machineconfig/scripts/python/wifi_conn.py +49 -76
  66. machineconfig/scripts/python/wsl_windows_transfer.py +8 -6
  67. machineconfig/settings/lf/linux/lfrc +1 -0
  68. machineconfig/setup_linux/web_shortcuts/croshell.sh +5 -0
  69. machineconfig/setup_linux/web_shortcuts/interactive.sh +1 -1
  70. machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -4
  71. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +3 -12
  72. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +1 -1
  73. machineconfig/utils/code.py +2 -3
  74. machineconfig/utils/installer.py +2 -2
  75. machineconfig/utils/installer_utils/installer_abc.py +2 -4
  76. machineconfig/utils/installer_utils/installer_class.py +6 -4
  77. machineconfig/utils/links.py +103 -33
  78. machineconfig/utils/notifications.py +52 -38
  79. machineconfig/utils/options.py +14 -21
  80. machineconfig/utils/path.py +12 -12
  81. machineconfig/utils/path_reduced.py +239 -200
  82. machineconfig/utils/procs.py +1 -1
  83. machineconfig/utils/source_of_truth.py +27 -0
  84. machineconfig/utils/ssh.py +9 -19
  85. machineconfig/utils/terminal.py +4 -2
  86. machineconfig/utils/upgrade_packages.py +91 -0
  87. machineconfig/utils/utils2.py +1 -2
  88. machineconfig/utils/utils5.py +23 -11
  89. machineconfig/utils/ve.py +4 -1
  90. {machineconfig-2.1.dist-info → machineconfig-2.3.dist-info}/METADATA +13 -13
  91. {machineconfig-2.1.dist-info → machineconfig-2.3.dist-info}/RECORD +105 -121
  92. machineconfig-2.3.dist-info/entry_points.txt +2 -0
  93. machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +0 -59
  94. machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -183
  95. machineconfig/cluster/sessions_managers/demo_rich_zellij.py +0 -0
  96. machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
  97. machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  98. machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  99. machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  100. machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  101. machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
  102. machineconfig/scripts/python/__pycache__/croshell.cpython-313.pyc +0 -0
  103. machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
  104. machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
  105. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
  106. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-313.pyc +0 -0
  107. machineconfig/scripts/python/ai/__pycache__/__init__.cpython-313.pyc +0 -0
  108. machineconfig/scripts/python/ai/__pycache__/generate_files.cpython-313.pyc +0 -0
  109. machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-313.pyc +0 -0
  110. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
  111. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
  112. machineconfig/setup_linux/web_shortcuts/all.sh +0 -48
  113. machineconfig/setup_linux/web_shortcuts/update_system.sh +0 -48
  114. machineconfig/utils/utils.py +0 -97
  115. /machineconfig/cluster/{cloud_manager.py → remote/cloud_manager.py} +0 -0
  116. /machineconfig/cluster/{data_transfer.py → remote/data_transfer.py} +0 -0
  117. /machineconfig/cluster/{distribute.py → remote/distribute.py} +0 -0
  118. /machineconfig/cluster/{file_manager.py → remote/file_manager.py} +0 -0
  119. /machineconfig/cluster/{job_params.py → remote/job_params.py} +0 -0
  120. /machineconfig/cluster/{loader_runner.py → remote/loader_runner.py} +0 -0
  121. /machineconfig/cluster/{remote_machine.py → remote/remote_machine.py} +0 -0
  122. /machineconfig/cluster/{script_execution.py → remote/script_execution.py} +0 -0
  123. /machineconfig/cluster/{script_notify_upon_completion.py → remote/script_notify_upon_completion.py} +0 -0
  124. /machineconfig/{cluster/sessions_managers/archive/__init__.py → scripts/python/fire_jobs_streamlit_helper.py} +0 -0
  125. /machineconfig/setup_linux/web_shortcuts/{tmp.sh → android.sh} +0 -0
  126. {machineconfig-2.1.dist-info → machineconfig-2.3.dist-info}/WHEEL +0 -0
  127. {machineconfig-2.1.dist-info → machineconfig-2.3.dist-info}/top_level.txt +0 -0
@@ -2,10 +2,11 @@ from datetime import datetime
2
2
  import json
3
3
  import uuid
4
4
  from pathlib import Path
5
- from typing import Optional
5
+ from typing import Optional, Dict
6
6
  from machineconfig.utils.utils5 import Scheduler
7
7
  from machineconfig.cluster.sessions_managers.zellij_local import run_command_in_zellij_tab
8
8
  from machineconfig.cluster.sessions_managers.zellij_remote import ZellijRemoteLayoutGenerator
9
+ from machineconfig.cluster.sessions_managers.layout_types import LayoutConfig
9
10
  from machineconfig.logger import get_logger
10
11
 
11
12
 
@@ -14,13 +15,13 @@ logger = get_logger("cluster.sessions_managers.zellij_remote_manager")
14
15
 
15
16
 
16
17
  class ZellijSessionManager:
17
- def __init__(self, machine2zellij_tabs: dict[str, dict[str, tuple[str, str]]], session_name_prefix: str = "JobMgr"):
18
+ def __init__(self, machine_layouts: Dict[str, LayoutConfig], session_name_prefix: str = "JobMgr"):
18
19
  self.session_name_prefix = session_name_prefix
19
- self.machine2zellij_tabs = machine2zellij_tabs # Store the original config
20
+ self.machine_layouts = machine_layouts # Store the original config
20
21
  self.managers: list[ZellijRemoteLayoutGenerator] = []
21
- for machine, tab_config in machine2zellij_tabs.items():
22
+ for machine, layout_config in machine_layouts.items():
22
23
  an_m = ZellijRemoteLayoutGenerator(remote_name=machine, session_name_prefix=self.session_name_prefix)
23
- an_m.create_zellij_layout(tab_config=tab_config)
24
+ an_m.create_zellij_layout(layout_config=layout_config)
24
25
  self.managers.append(an_m)
25
26
 
26
27
  def ssh_to_all_machines(self) -> str:
@@ -93,13 +94,13 @@ class ZellijSessionManager:
93
94
  session_dir = TMP_SERIALIAZATION_DIR / session_id
94
95
  session_dir.mkdir(parents=True, exist_ok=True)
95
96
 
96
- # Save the machine2zellij_tabs configuration
97
- config_file = session_dir / "machine2zellij_tabs.json"
98
- text = json.dumps(self.machine2zellij_tabs, indent=2, ensure_ascii=False)
97
+ # Save the machine_layouts configuration
98
+ config_file = session_dir / "machine_layouts.json"
99
+ text = json.dumps(self.machine_layouts, indent=2, ensure_ascii=False)
99
100
  config_file.write_text(text, encoding="utf-8")
100
101
 
101
102
  # Save session metadata
102
- metadata = {"session_name_prefix": self.session_name_prefix, "created_at": str(datetime.now()), "num_managers": len(self.managers), "machines": list(self.machine2zellij_tabs.keys())}
103
+ metadata = {"session_name_prefix": self.session_name_prefix, "created_at": str(datetime.now()), "num_managers": len(self.managers), "machines": list(self.machine_layouts.keys())}
103
104
  metadata_file = session_dir / "metadata.json"
104
105
  text = json.dumps(metadata, indent=2, ensure_ascii=False)
105
106
  metadata_file.write_text(text, encoding="utf-8")
@@ -120,11 +121,11 @@ class ZellijSessionManager:
120
121
 
121
122
  if not session_dir.exists():
122
123
  raise FileNotFoundError(f"Session directory not found: {session_dir}")
123
- config_file = session_dir / "machine2zellij_tabs.json"
124
+ config_file = session_dir / "machine_layouts.json"
124
125
  if not config_file.exists():
125
126
  raise FileNotFoundError(f"Configuration file not found: {config_file}")
126
127
  with open(config_file, "r", encoding="utf-8") as f:
127
- machine2zellij_tabs = json.load(f)
128
+ machine_layouts = json.load(f)
128
129
 
129
130
  # Load metadata
130
131
  metadata_file = session_dir / "metadata.json"
@@ -134,7 +135,7 @@ class ZellijSessionManager:
134
135
  metadata = json.load(f)
135
136
  session_name_prefix = metadata.get("session_name_prefix", "JobMgr")
136
137
  # Create new instance (this will create new managers)
137
- instance = cls(machine2zellij_tabs=machine2zellij_tabs, session_name_prefix=session_name_prefix)
138
+ instance = cls(machine_layouts=machine_layouts, session_name_prefix=session_name_prefix)
138
139
  # Load saved managers to restore their states
139
140
  managers_dir = session_dir / "managers"
140
141
  if managers_dir.exists():
@@ -4,17 +4,21 @@ Example usage of the modularized Zellij remote layout generator.
4
4
  """
5
5
 
6
6
  from machineconfig.cluster.sessions_managers.zellij_remote import ZellijRemoteLayoutGenerator
7
+ from machineconfig.cluster.sessions_managers.layout_types import LayoutConfig
7
8
 
8
9
 
9
10
  def example_usage():
10
11
  """Demonstrate the refactored modular usage."""
11
12
 
12
- # Sample tab configuration
13
- sample_tabs = {
14
- "🤖Bot1": ("~/code/bytesense/bithence", "~/scripts/fire -mO go1.py bot1 --kw create_new_bot True"),
15
- "🤖Bot2": ("~/code/bytesense/bithence", "~/scripts/fire -mO go2.py bot2 --kw create_new_bot True"),
16
- "📊Monitor": ("~", "htop"),
17
- "📝Logs": ("/var/log", "tail -f /var/log/app.log"),
13
+ # Sample layout configuration using new schema
14
+ sample_layout: LayoutConfig = {
15
+ "layoutName": "ExampleRemoteSession",
16
+ "layoutTabs": [
17
+ {"tabName": "🤖Bot1", "startDir": "~/code/bytesense/bithence", "command": "~/scripts/fire -mO go1.py bot1 --kw create_new_bot True"},
18
+ {"tabName": "🤖Bot2", "startDir": "~/code/bytesense/bithence", "command": "~/scripts/fire -mO go2.py bot2 --kw create_new_bot True"},
19
+ {"tabName": "📊Monitor", "startDir": "~", "command": "htop"},
20
+ {"tabName": "📝Logs", "startDir": "/var/log", "command": "tail -f /var/log/app.log"},
21
+ ],
18
22
  }
19
23
 
20
24
  # Replace 'myserver' with an actual SSH config alias
@@ -26,11 +30,11 @@ def example_usage():
26
30
  generator = ZellijRemoteLayoutGenerator(remote_name=remote_name, session_name_prefix=session_name)
27
31
 
28
32
  # Create layout file
29
- layout_path = generator.create_zellij_layout(sample_tabs)
33
+ layout_path = generator.create_zellij_layout(sample_layout)
30
34
  print(f"✅ Remote layout created successfully: {layout_path}")
31
35
 
32
36
  # Preview the layout content
33
- preview = generator.get_layout_preview(sample_tabs)
37
+ preview = generator.get_layout_preview(sample_layout)
34
38
  print(f"📄 Layout preview:\n{preview}")
35
39
 
36
40
  # Check status using the modular components
@@ -44,11 +48,11 @@ def example_usage():
44
48
  print(f"Remote executor: {generator.remote_executor.remote_name}")
45
49
 
46
50
  # Use layout generator directly
47
- layout_content = generator.layout_generator.generate_layout_content(sample_tabs)
51
+ layout_content = generator.layout_generator.generate_layout_content(sample_layout)
48
52
  print(f"Layout content length: {len(layout_content)} characters")
49
53
 
50
54
  # Use process monitor directly
51
- status = generator.process_monitor.check_all_commands_status(sample_tabs)
55
+ status = generator.process_monitor.check_all_commands_status(sample_layout)
52
56
  print(f"Command status check completed for {len(status)} commands")
53
57
 
54
58
  print("\n✅ All modular components working correctly!")
@@ -6,11 +6,12 @@ Zellij layout generation utilities for creating KDL layout files.
6
6
  import shlex
7
7
  import random
8
8
  import string
9
- from typing import Dict, List, Tuple
9
+ from typing import List, Tuple
10
10
  from pathlib import Path
11
11
  import logging
12
12
 
13
13
  from rich.console import Console
14
+ from machineconfig.cluster.sessions_managers.layout_types import LayoutConfig
14
15
 
15
16
  logger = logging.getLogger(__name__)
16
17
  console = Console()
@@ -77,36 +78,51 @@ class LayoutGenerator:
77
78
  return tab_section
78
79
 
79
80
  @staticmethod
80
- def validate_tab_config(tab_config: Dict[str, Tuple[str, str]]) -> None:
81
- """Validate tab configuration format and content."""
82
- if not tab_config:
83
- raise ValueError("Tab configuration cannot be empty")
84
- for tab_name, (cwd, command) in tab_config.items():
81
+ def validate_tab_config(layout_config: LayoutConfig) -> None:
82
+ """Validate layout configuration format and content."""
83
+ if not layout_config:
84
+ raise ValueError("Layout configuration cannot be empty")
85
+
86
+ if not layout_config.get("layoutName", "").strip():
87
+ raise ValueError("Layout name cannot be empty")
88
+
89
+ layout_tabs = layout_config.get("layoutTabs", [])
90
+ if not layout_tabs:
91
+ raise ValueError("Layout must have at least one tab")
92
+
93
+ for tab in layout_tabs:
94
+ tab_name = tab.get("tabName", "")
95
+ command = tab.get("command", "")
96
+ start_dir = tab.get("startDir", "")
97
+
85
98
  if not tab_name.strip():
86
99
  raise ValueError(f"Invalid tab name: {tab_name}")
87
100
  if not command.strip():
88
101
  raise ValueError(f"Invalid command for tab '{tab_name}': {command}")
89
- if not cwd.strip():
90
- raise ValueError(f"Invalid cwd for tab '{tab_name}': {cwd}")
102
+ if not start_dir.strip():
103
+ raise ValueError(f"Invalid startDir for tab '{tab_name}': {start_dir}")
91
104
 
92
- def generate_layout_content(self, tab_config: Dict[str, Tuple[str, str]]) -> str:
105
+ def generate_layout_content(self, layout_config: LayoutConfig) -> str:
93
106
  """Generate complete KDL layout content."""
94
- self.validate_tab_config(tab_config)
107
+ self.validate_tab_config(layout_config)
95
108
 
96
109
  layout_content = self.LAYOUT_TEMPLATE
97
- for tab_name, (cwd, command) in tab_config.items():
98
- layout_content += "\n" + self.create_tab_section(tab_name, cwd, command)
110
+ for tab in layout_config["layoutTabs"]:
111
+ tab_name = tab["tabName"]
112
+ start_dir = tab["startDir"]
113
+ command = tab["command"]
114
+ layout_content += "\n" + self.create_tab_section(tab_name, start_dir, command)
99
115
  layout_content += "\n}\n"
100
116
 
101
117
  return layout_content
102
118
 
103
- def create_layout_file(self, tab_config: Dict[str, Tuple[str, str]], output_dir: Path, session_name: str) -> str:
119
+ def create_layout_file(self, layout_config: LayoutConfig, output_dir: Path, session_name: str) -> str:
104
120
  """Create a layout file and return its absolute path."""
105
- self.validate_tab_config(tab_config)
121
+ self.validate_tab_config(layout_config)
106
122
 
107
123
  # Generate unique suffix for this layout
108
124
  random_suffix = self.generate_random_suffix()
109
- layout_content = self.generate_layout_content(tab_config)
125
+ layout_content = self.generate_layout_content(layout_config)
110
126
 
111
127
  try:
112
128
  # Create output directory if it doesn't exist
@@ -6,8 +6,9 @@ Process monitoring and status checking utilities for remote commands.
6
6
  import json
7
7
  import shlex
8
8
  import logging
9
- from typing import Dict, Tuple, Any
10
- from .remote_executor import RemoteExecutor
9
+ from typing import Dict, Any
10
+ from machineconfig.cluster.sessions_managers.zellij_utils.remote_executor import RemoteExecutor
11
+ from machineconfig.cluster.sessions_managers.layout_types import LayoutConfig
11
12
 
12
13
  logger = logging.getLogger(__name__)
13
14
 
@@ -18,20 +19,37 @@ class ProcessMonitor:
18
19
  def __init__(self, remote_executor: RemoteExecutor):
19
20
  self.remote_executor = remote_executor
20
21
 
21
- def check_command_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]], use_verification: bool = True) -> Dict[str, Any]:
22
+ def check_command_status(self, tab_name: str, layout_config: LayoutConfig, use_verification: bool = True) -> Dict[str, Any]:
22
23
  """Check command status with optional process verification."""
23
- if tab_name not in tab_config:
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}
24
+ # Find the tab with the given name
25
+ tab_config = None
26
+ for tab in layout_config["layoutTabs"]:
27
+ if tab["tabName"] == tab_name:
28
+ tab_config = tab
29
+ break
30
+
31
+ if tab_config is None:
32
+ return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "pid": None, "command": None, "remote": self.remote_executor.remote_name}
25
33
 
26
34
  # Use the verified method by default for more accurate results
27
35
  if use_verification:
28
- return self.get_verified_process_status(tab_name, tab_config)
36
+ return self.get_verified_process_status(tab_name, layout_config)
29
37
 
30
- return self._basic_process_check(tab_name, tab_config)
38
+ return self._basic_process_check(tab_name, layout_config)
31
39
 
32
- def _basic_process_check(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
40
+ def _basic_process_check(self, tab_name: str, layout_config: LayoutConfig) -> Dict[str, Any]:
33
41
  """Basic process checking without verification."""
34
- _, command = tab_config[tab_name]
42
+ # Find the tab with the given name
43
+ tab_config = None
44
+ for tab in layout_config["layoutTabs"]:
45
+ if tab["tabName"] == tab_name:
46
+ tab_config = tab
47
+ break
48
+
49
+ if tab_config is None:
50
+ return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "command": None, "remote": self.remote_executor.remote_name}
51
+
52
+ command = tab_config["command"]
35
53
 
36
54
  try:
37
55
  check_script = self._create_process_check_script(command)
@@ -106,12 +124,19 @@ if __name__ == "__main__":
106
124
  print(json.dumps(processes))
107
125
  """
108
126
 
109
- def force_fresh_process_check(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
127
+ def force_fresh_process_check(self, tab_name: str, layout_config: LayoutConfig) -> Dict[str, Any]:
110
128
  """Force a fresh process check with additional validation."""
111
- if tab_name not in tab_config:
112
- return {"status": "unknown", "error": f"Tab '{tab_name}' not found in tracked configuration", "running": False, "command": None, "remote": self.remote_executor.remote_name}
129
+ # Find the tab with the given name
130
+ tab_config = None
131
+ for tab in layout_config["layoutTabs"]:
132
+ if tab["tabName"] == tab_name:
133
+ tab_config = tab
134
+ break
135
+
136
+ if tab_config is None:
137
+ return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "command": None, "remote": self.remote_executor.remote_name}
113
138
 
114
- _, command = tab_config[tab_name]
139
+ command = tab_config["command"]
115
140
 
116
141
  try:
117
142
  # Get timestamp for freshness validation
@@ -230,9 +255,9 @@ if __name__ == "__main__":
230
255
  except Exception:
231
256
  return False
232
257
 
233
- def get_verified_process_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
258
+ def get_verified_process_status(self, tab_name: str, layout_config: LayoutConfig) -> Dict[str, Any]:
234
259
  """Get process status with additional verification that processes are actually alive."""
235
- status = self.force_fresh_process_check(tab_name, tab_config)
260
+ status = self.force_fresh_process_check(tab_name, layout_config)
236
261
 
237
262
  if status.get("running") and status.get("processes"):
238
263
  verified_processes = []
@@ -252,13 +277,14 @@ if __name__ == "__main__":
252
277
 
253
278
  return status
254
279
 
255
- def check_all_commands_status(self, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Dict[str, Any]]:
256
- """Check status of all commands in the tab configuration."""
257
- if not tab_config:
258
- logger.warning("No tab configuration provided.")
280
+ def check_all_commands_status(self, layout_config: LayoutConfig) -> Dict[str, Dict[str, Any]]:
281
+ """Check status of all commands in the layout configuration."""
282
+ if not layout_config or not layout_config.get("layoutTabs"):
283
+ logger.warning("No layout configuration provided.")
259
284
  return {}
260
285
 
261
286
  status_report = {}
262
- for tab_name in tab_config:
263
- status_report[tab_name] = self.check_command_status(tab_name, tab_config)
287
+ for tab in layout_config["layoutTabs"]:
288
+ tab_name = tab["tabName"]
289
+ status_report[tab_name] = self.check_command_status(tab_name, layout_config)
264
290
  return status_report
@@ -9,7 +9,7 @@ from pathlib import Path
9
9
 
10
10
  from rich.console import Console
11
11
 
12
- from .remote_executor import RemoteExecutor
12
+ from machineconfig.cluster.sessions_managers.zellij_utils.remote_executor import RemoteExecutor
13
13
 
14
14
  logger = logging.getLogger(__name__)
15
15
  console = Console()
@@ -4,9 +4,10 @@ Status reporting utilities for Zellij remote layouts.
4
4
  """
5
5
 
6
6
  import logging
7
- from typing import Dict, Any, Tuple
8
- from .process_monitor import ProcessMonitor
9
- from .session_manager import SessionManager
7
+ from typing import Dict, Any
8
+ from machineconfig.cluster.sessions_managers.zellij_utils.process_monitor import ProcessMonitor
9
+ from machineconfig.cluster.sessions_managers.zellij_utils.session_manager import SessionManager
10
+ from machineconfig.cluster.sessions_managers.layout_types import LayoutConfig
10
11
 
11
12
  logger = logging.getLogger(__name__)
12
13
 
@@ -18,10 +19,10 @@ class StatusReporter:
18
19
  self.process_monitor = process_monitor
19
20
  self.session_manager = session_manager
20
21
 
21
- def get_comprehensive_status(self, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
22
+ def get_comprehensive_status(self, layout_config: LayoutConfig) -> Dict[str, Any]:
22
23
  """Get comprehensive status including Zellij session and all commands."""
23
24
  zellij_status = self.session_manager.check_zellij_session_status()
24
- commands_status = self.process_monitor.check_all_commands_status(tab_config)
25
+ commands_status = self.process_monitor.check_all_commands_status(layout_config)
25
26
 
26
27
  running_count = sum(1 for status in commands_status.values() if status.get("running", False))
27
28
  total_count = len(commands_status)
@@ -38,9 +39,9 @@ class StatusReporter:
38
39
  },
39
40
  }
40
41
 
41
- def print_status_report(self, tab_config: Dict[str, Tuple[str, str]]) -> None:
42
+ def print_status_report(self, layout_config: LayoutConfig) -> None:
42
43
  """Print a formatted status report to console."""
43
- status = self.get_comprehensive_status(tab_config)
44
+ status = self.get_comprehensive_status(layout_config)
44
45
  remote_name = self.session_manager.remote_executor.remote_name
45
46
  session_name = self.session_manager.session_name
46
47
 
@@ -1,41 +1,6 @@
1
- # """
2
- # This module contains utility functions for the cluster module.
3
- # """
4
-
5
- # import inspect
6
- # from machineconfig.utils.io_save import save_pickle
7
-
8
- # from machineconfig.cluster.remote_machine import WorkloadParams
9
1
  from typing import Optional
10
2
  from machineconfig.utils.path_reduced import PathExtended, PLike
11
3
 
12
- # def expensive_function(workload_params: WorkloadParams, sim_dict: Optional[dict[str, Any]] = None) -> P:
13
- # import time
14
- # from rich.progress import track
15
- # print("Hello, I am one thread of an expensive function, and I just started running ...")
16
- # print(f"Oh, I recieved this parameter: {sim_dict=} & {workload_params=} ")
17
- # execution_time_in_seconds = 60 * 1
18
- # steps = 100
19
- # for _ in track(range(steps), description="Progress bar ..."):
20
- # time.sleep(execution_time_in_seconds / steps) # Simulate work being done
21
- # print(f"I'm done, I crunched numbers from {workload_params.idx_start} to {workload_params.idx_end}.")
22
- # _ = workload_params.idx_max
23
-
24
- # save_dir = PathExtended.tmp().joinpath("tmp_dirs/expensive_function_single_thread").joinpath(workload_params.save_suffix, f"thread_{workload_params.idx_start}_{workload_params.idx_end}")
25
- # save_dir.mkdir(parents=True, exist_ok=True)
26
- # save_pickle(obj={'a': 1}, path=save_dir.joinpath("trial_func_result.pkl"))
27
- # return save_dir
28
-
29
-
30
- # def assert_has_workload_params(func_or_method: Callable[..., Any]):
31
- # if not inspect.isfunction(func_or_method) and not inspect.ismethod(func_or_method): raise TypeError(f"{func_or_method} is not a function or method.")
32
- # try: params = inspect.signature(func_or_method).parameters
33
- # except ValueError as e: raise ValueError(f"Failed to inspect signature of {func_or_method}: {e}") from e
34
- # if 'workload_params' not in params: raise ValueError(f"{func_or_method.__name__}() does not have 'workload_params' parameter.")
35
- # if params['workload_params'].kind != inspect.Parameter.POSITIONAL_OR_KEYWORD: raise ValueError(f"{func_or_method.__name__}() 'workload_params' parameter is not a positional or keyword parameter.")
36
- # if params['workload_params'].default is not inspect.Parameter.empty: raise ValueError(f"{func_or_method.__name__}() 'workload_params' parameter should not have a default value.")
37
- # return True
38
-
39
4
 
40
5
  def to_cloud(
41
6
  localpath: PLike,
@@ -9,7 +9,7 @@ import platform
9
9
  # from rich.console import Console
10
10
  # from machineconfig.utils.utils2 import pprint
11
11
  # # from rich.progress import track
12
- from machineconfig.utils.utils import LIBRARY_ROOT
12
+ from machineconfig.utils.source_of_truth import LIBRARY_ROOT
13
13
  # from machineconfig.utils.installer import get_installed_cli_apps
14
14
 
15
15
  # from tqdm import tqdm
@@ -36,20 +36,7 @@ def main(version: Optional[str] = None):
36
36
  {"⚠️" * 20}
37
37
  """)
38
38
  raise NotImplementedError(error_msg)
39
-
40
39
  _ = version
41
-
42
- print(f"""
43
- {"=" * 150}
44
- ℹ️ INFO | VS Code features:
45
- 📝 Powerful code editor with IntelliSense
46
- 🧩 Thousands of extensions available
47
- 🔍 Integrated debugging
48
- 🔄 Git integration
49
- ⚙️ Highly customizable
50
- {"=" * 150}
51
- """)
52
-
53
40
  return install_script
54
41
 
55
42
 
@@ -219,7 +219,7 @@
219
219
  "doc": "🚀 Fly through your shell history. Great Scott!",
220
220
  "filename_template_linux_amd_64": "mcfly-v{}-x86_64-unknown-linux-musl.tar.gz",
221
221
  "filename_template_linux_arm_64": "mcfly-v{}-aarch64-unknown-linux-musl.tar.gz",
222
- "filename_template_windows_amd_64": "mcfly-v{}-x86_64-pc-windows-msvc.zip",
222
+ "filename_template_windows_amd_64": "",
223
223
  "filename_template_macos_amd_64": "mcfly-v{}-x86_64-apple-darwin.tar.gz",
224
224
  "filename_template_macos_arm_64": "",
225
225
  "filename_template_windows_arm_64": "",
@@ -5,7 +5,9 @@ This script Takes away all config files from the computer, place them in one dir
5
5
  """
6
6
 
7
7
  from machineconfig.utils.path_reduced import PathExtended as PathExtended
8
- from machineconfig.utils.utils import symlink_func, symlink_copy, LIBRARY_ROOT, REPO_ROOT, display_options
8
+ from machineconfig.utils.links import symlink_func, symlink_copy
9
+ from machineconfig.utils.options import display_options
10
+ from machineconfig.utils.source_of_truth import LIBRARY_ROOT, REPO_ROOT
9
11
  from machineconfig.utils.utils2 import read_toml
10
12
  from machineconfig.profile.shell import create_default_shell_profile
11
13
 
@@ -19,11 +21,18 @@ from typing import Optional, Any, TypedDict
19
21
 
20
22
  system = platform.system() # Linux or Windows
21
23
  ERROR_LIST: list[Any] = [] # append to this after every exception captured.
22
- CONFIG_ROOT = LIBRARY_ROOT.parent.parent.joinpath("settings")
23
- OTHER_SYSTEM = "windows" if system == "Linux" else "linux"
24
+
24
25
  SYSTEM = system.lower()
25
26
 
26
27
 
28
+ def get_other_systems(current_system: str) -> list[str]:
29
+ all_systems = ["linux", "windows", "darwin"]
30
+ return [s for s in all_systems if s != current_system.lower()]
31
+
32
+
33
+ OTHER_SYSTEMS = get_other_systems(SYSTEM)
34
+
35
+
27
36
  class SymlinkMapper(TypedDict):
28
37
  this: str
29
38
  to_this: str
@@ -38,7 +47,7 @@ def main_symlinks(choice: Optional[str] = None):
38
47
  program_keys_raw: list[str] = list(symlink_mapper.keys())
39
48
  program_keys: list[str] = []
40
49
  for program_key in program_keys_raw:
41
- if program_key in exclude or OTHER_SYSTEM in program_key:
50
+ if program_key in exclude or any([another_system in program_key for another_system in OTHER_SYSTEMS]):
42
51
  continue
43
52
  else:
44
53
  program_keys.append(program_key)
@@ -6,7 +6,9 @@ This script Takes away all config files from the computer, place them in one dir
6
6
 
7
7
  import platform
8
8
  from machineconfig.utils.path_reduced import PathExtended as PathExtended
9
- from machineconfig.utils.utils import symlink_copy as symlink_func, LIBRARY_ROOT, REPO_ROOT, display_options
9
+ from machineconfig.utils.links import symlink_copy as symlink_func
10
+ from machineconfig.utils.options import display_options
11
+ from machineconfig.utils.source_of_truth import LIBRARY_ROOT, REPO_ROOT
10
12
  from machineconfig.utils.utils2 import read_toml
11
13
  from machineconfig.profile.shell import create_default_shell_profile
12
14
 
@@ -1,9 +1,10 @@
1
1
  """shell"""
2
2
 
3
3
  from machineconfig.utils.utils2 import randstr
4
- from machineconfig.utils.path_reduced import PathExtended as PathExtended, modify_text
4
+ from machineconfig.utils.path_reduced import PathExtended as PathExtended
5
5
  from machineconfig.utils.terminal import Terminal
6
- from machineconfig.utils.utils import LIBRARY_ROOT, REPO_ROOT, display_options
6
+ from machineconfig.utils.options import display_options
7
+ from machineconfig.utils.source_of_truth import LIBRARY_ROOT, REPO_ROOT
7
8
  import platform
8
9
  import os
9
10
  from typing import Literal, Optional
@@ -27,9 +28,9 @@ def create_default_shell_profile() -> None:
27
28
  profile_path = get_shell_profile_path()
28
29
  profile = profile_path.read_text(encoding="utf-8")
29
30
  if system == "Windows":
30
- source = f""". {str(LIBRARY_ROOT.joinpath("settings/shells/pwsh/init.ps1").collapseuser()).replace("~", "$HOME")}"""
31
+ source = f""". {str(PathExtended(LIBRARY_ROOT).joinpath("settings/shells/pwsh/init.ps1").collapseuser()).replace("~", "$HOME")}"""
31
32
  else:
32
- source = f"""source {str(LIBRARY_ROOT.joinpath("settings/shells/bash/init.sh").collapseuser()).replace("~", "$HOME")}"""
33
+ source = f"""source {str(PathExtended(LIBRARY_ROOT).joinpath("settings/shells/bash/init.sh").collapseuser()).replace("~", "$HOME")}"""
33
34
 
34
35
  if source in profile:
35
36
  console.print(Panel("🔄 PROFILE | Skipping init script sourcing - already present in profile", title="[bold blue]Profile[/bold blue]", border_style="blue"))
@@ -116,9 +117,9 @@ def main_env_path(choice: Optional[str], profile_path: Optional[str]) -> None:
116
117
  profile_path_obj = PathExtended(profile_path) if isinstance(profile_path, str) else get_shell_profile_path()
117
118
  profile_path_obj.copy(name=profile_path_obj.name + ".orig_" + randstr())
118
119
  console.print(f"💾 Created backup of profile: {profile_path_obj.name}.orig_*")
119
- # Inline deprecated P.modify_text: if file missing, seed with search text before modification
120
+ # Inline deprecated modify_text: if file missing, seed with search text before modification
120
121
  current = profile_path_obj.read_text(encoding="utf-8") if profile_path_obj.exists() else addition
121
- updated = modify_text(current, addition, addition, replace_line=False, notfound_append=True)
122
+ updated = current if addition in current else current + "\n" + addition
122
123
  profile_path_obj.write_text(updated, encoding="utf-8")
123
124
  console.print(Panel("✅ PATH variables added to profile successfully", title="[bold blue]Environment[/bold blue]", border_style="blue"))
124
125
 
@@ -172,7 +173,7 @@ def main_add_sources_to_shell_profile(profile_path: Optional[str], choice: Optio
172
173
 
173
174
 
174
175
  def main_add_patches_to_shell_profile(profile_path: Optional[str], choice: Optional[str]) -> None:
175
- patches: list[str] = [item.as_posix() for item in LIBRARY_ROOT.joinpath(f"profile/patches/{system.lower()}").search()]
176
+ patches: list[str] = [item.as_posix() for item in PathExtended(LIBRARY_ROOT).joinpath(f"profile/patches/{system.lower()}").search()]
176
177
 
177
178
  console.print(Panel("🩹 Adding patches to shell profile", title="[bold blue]Patches[/bold blue]", border_style="blue"))
178
179
 
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  version = "0.5"
4
2
  release_notes = """
5
3
  created toml file for symlinks
@@ -1,14 +1,16 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
- source ~/code/machineconfig/.venv/bin/activate
4
-
5
3
  op_script=$HOME/tmp_results/shells/python_return_command.sh
6
4
  if [ -f "$op_script" ]; then
7
5
  rm $op_script
8
6
  fi
9
7
 
10
- # uv run --no-dev --project ~/code/machineconfig python -m machineconfig.scripts.python.devops "$@"
11
- python -m machineconfig.scripts.python.devops "$@"
8
+ # source ~/code/machineconfig/.venv/bin/activate
9
+ # python -m machineconfig.scripts.python.devops "$@"
10
+ # echo "🔄 Running devops script..."
11
+ uv run --no-dev --project $HOME/code/machineconfig python -m machineconfig.scripts.python.devops "$@"
12
+ # uv run --with machineconfig python -m machineconfig.scripts.python.devops "$@"
13
+
12
14
 
13
15
  if [ -f "$op_script" ]; then
14
16
  chmod +x $op_script