machineconfig 2.98__py3-none-any.whl → 3.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.

Files changed (78) hide show
  1. machineconfig/__init__.py +16 -17
  2. machineconfig/cluster/sessions_managers/enhanced_command_runner.py +6 -6
  3. machineconfig/cluster/sessions_managers/wt_local.py +7 -7
  4. machineconfig/cluster/sessions_managers/wt_local_manager.py +8 -8
  5. machineconfig/cluster/sessions_managers/wt_remote.py +8 -8
  6. machineconfig/cluster/sessions_managers/wt_remote_manager.py +6 -6
  7. machineconfig/cluster/sessions_managers/zellij_local.py +156 -77
  8. machineconfig/cluster/sessions_managers/zellij_local_manager.py +18 -15
  9. machineconfig/cluster/sessions_managers/zellij_remote.py +14 -61
  10. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +15 -12
  11. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +9 -3
  12. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +2 -2
  13. machineconfig/cluster/sessions_managers/zellij_utils/monitoring_types.py +40 -67
  14. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +19 -17
  15. machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +2 -2
  16. machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +1 -1
  17. machineconfig/jobs/python/python_ve_symlink.py +1 -1
  18. machineconfig/profile/create.py +7 -0
  19. machineconfig/scripts/linux/kill_process +1 -1
  20. machineconfig/scripts/python/ai/mcinit.py +2 -3
  21. machineconfig/scripts/python/cloud_mount.py +1 -1
  22. machineconfig/scripts/python/cloud_repo_sync.py +1 -0
  23. machineconfig/scripts/python/cloud_sync.py +1 -0
  24. machineconfig/scripts/python/croshell.py +1 -0
  25. machineconfig/scripts/python/devops.py +11 -0
  26. machineconfig/scripts/python/devops_add_identity.py +1 -0
  27. machineconfig/scripts/python/devops_add_ssh_key.py +1 -0
  28. machineconfig/scripts/python/devops_backup_retrieve.py +1 -0
  29. machineconfig/scripts/python/devops_devapps_install.py +4 -6
  30. machineconfig/scripts/python/devops_update_repos.py +21 -20
  31. machineconfig/scripts/python/fire_agents.py +17 -7
  32. machineconfig/scripts/python/fire_agents_help_launch.py +4 -3
  33. machineconfig/scripts/python/fire_agents_help_search.py +1 -2
  34. machineconfig/scripts/python/fire_agents_load_balancer.py +8 -10
  35. machineconfig/scripts/python/fire_jobs.py +1 -0
  36. machineconfig/scripts/python/helpers/cloud_helpers.py +1 -0
  37. machineconfig/scripts/python/mount_nfs.py +2 -0
  38. machineconfig/scripts/python/mount_nw_drive.py +1 -1
  39. machineconfig/scripts/python/mount_ssh.py +1 -0
  40. machineconfig/scripts/python/repos.py +0 -2
  41. machineconfig/scripts/python/repos_helper_record.py +43 -66
  42. machineconfig/scripts/python/repos_helper_update.py +3 -2
  43. machineconfig/scripts/python/start_slidev.py +1 -0
  44. machineconfig/scripts/python/start_terminals.py +1 -1
  45. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +1 -0
  46. machineconfig/utils/code.py +0 -1
  47. machineconfig/utils/notifications.py +2 -2
  48. machineconfig/utils/procs.py +10 -15
  49. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +9 -4
  50. machineconfig/utils/schemas/layouts/layout_types.py +2 -0
  51. machineconfig/utils/schemas/repos/repos_types.py +0 -3
  52. machineconfig/utils/ssh.py +9 -11
  53. machineconfig/utils/utils2.py +1 -0
  54. machineconfig/utils/ve.py +0 -1
  55. {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/METADATA +1 -1
  56. {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/RECORD +59 -78
  57. {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/entry_points.txt +1 -0
  58. machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
  59. machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  60. machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  61. machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  62. machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
  63. machineconfig/scripts/python/__pycache__/cloud_repo_sync.cpython-313.pyc +0 -0
  64. machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
  65. machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
  66. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
  67. machineconfig/scripts/python/__pycache__/fire_agents.cpython-313.pyc +0 -0
  68. machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-313.pyc +0 -0
  69. machineconfig/scripts/python/__pycache__/repos.cpython-313.pyc +0 -0
  70. machineconfig/scripts/python/__pycache__/repos_helper_record.cpython-313.pyc +0 -0
  71. machineconfig/scripts/python/__pycache__/repos_helper_update.cpython-313.pyc +0 -0
  72. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
  73. machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-313.pyc +0 -0
  74. machineconfig/settings/linters/.ruff_cache/.gitignore +0 -2
  75. machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +0 -1
  76. machineconfig/settings/shells/bash/.inputrc +0 -3
  77. {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/WHEEL +0 -0
  78. {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/top_level.txt +0 -0
@@ -10,7 +10,7 @@ from typing import Optional, List
10
10
 
11
11
  from rich.console import Console
12
12
 
13
- from machineconfig.cluster.sessions_managers.zellij_utils.monitoring_types import SessionReport, GlobalSummary, StartResult, ActiveSessionInfo
13
+ from machineconfig.cluster.sessions_managers.zellij_utils.monitoring_types import SessionReport, GlobalSummary, StartResult, ActiveSessionInfo, StatusRow
14
14
  from machineconfig.utils.utils5 import Scheduler
15
15
  from machineconfig.cluster.sessions_managers.zellij_local import ZellijLayoutGenerator
16
16
  from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
@@ -36,7 +36,7 @@ class ZellijLocalManager:
36
36
  session_name = layout_config["layoutName"].replace(" ", "_")
37
37
  manager = ZellijLayoutGenerator()
38
38
  full_session_name = f"{self.session_name_prefix}_{session_name}"
39
- manager.create_zellij_layout(layout_config=layout_config, session_name=full_session_name)
39
+ manager.create_zellij_layout(layout_config=layout_config, output_dir=None, session_name=full_session_name)
40
40
  self.managers.append(manager)
41
41
 
42
42
  # Enhanced Rich logging for initialization
@@ -46,7 +46,7 @@ class ZellijLocalManager:
46
46
  """Get all managed session names."""
47
47
  return [manager.session_name for manager in self.managers if manager.session_name is not None]
48
48
 
49
- def start_all_sessions(self, poll_seconds: float = 5.0, poll_interval: float = 0.25) -> dict[str, StartResult]:
49
+ def start_all_sessions(self, poll_seconds: float, poll_interval: float) -> dict[str, StartResult]:
50
50
  """Start all zellij sessions with their layouts without blocking on the interactive TUI.
51
51
 
52
52
  Rationale:
@@ -135,7 +135,7 @@ class ZellijLocalManager:
135
135
 
136
136
  return results
137
137
 
138
- def attach_to_session(self, session_name: Optional[str] = None) -> str:
138
+ def attach_to_session(self, session_name: Optional[str]) -> str:
139
139
  """
140
140
  Generate command to attach to a specific session or list attachment commands for all.
141
141
 
@@ -153,7 +153,7 @@ class ZellijLocalManager:
153
153
  raise ValueError(f"Session '{session_name}' not found")
154
154
  else:
155
155
  # Return commands for all sessions
156
- commands = []
156
+ commands: list[str] = []
157
157
  for manager in self.managers:
158
158
  commands.append(f"# Attach to session '{manager.session_name}':")
159
159
  commands.append(f"zellij attach {manager.session_name}")
@@ -253,12 +253,13 @@ class ZellijLocalManager:
253
253
 
254
254
  print("=" * 80)
255
255
 
256
- def run_monitoring_routine(self, wait_ms: int = 30000) -> None:
256
+ def run_monitoring_routine(self, wait_ms: int) -> None:
257
257
  """
258
258
  Run a continuous monitoring routine that checks status periodically.
259
259
 
260
260
  Args:
261
- wait_ms: How long to wait between checks in milliseconds (default: 30000ms = 30s)
261
+ wait_ms: How long to wait between checks in milliseconds
262
+ kill_sessions_on_completion: If True, kill all managed zellij sessions when monitoring stops
262
263
  """
263
264
 
264
265
  def routine(scheduler: Scheduler):
@@ -270,7 +271,7 @@ class ZellijLocalManager:
270
271
  all_status = self.check_all_sessions_status()
271
272
 
272
273
  # Create DataFrame for easier viewing
273
- status_data = []
274
+ status_data: list[StatusRow] = []
274
275
  for session_name, status in all_status.items():
275
276
  for tab_name, cmd_status in status["commands_status"].items():
276
277
  status_data.append(
@@ -314,7 +315,7 @@ class ZellijLocalManager:
314
315
  sched = Scheduler(routine=routine, wait_ms=wait_ms, logger=logger)
315
316
  sched.run()
316
317
 
317
- def save(self, session_id: Optional[str] = None) -> str:
318
+ def save(self, session_id: Optional[str]) -> str:
318
319
  """Save the manager state to disk."""
319
320
  if session_id is None:
320
321
  session_id = str(uuid.uuid4())[:8]
@@ -360,8 +361,8 @@ class ZellijLocalManager:
360
361
  if not config_file.exists():
361
362
  raise FileNotFoundError(f"Configuration file not found: {config_file}")
362
363
 
363
- with open(config_file, "r", encoding="utf-8") as f:
364
- session_layouts = json.load(f)
364
+ text = config_file.read_text(encoding="utf-8")
365
+ session_layouts = json.loads(text)
365
366
 
366
367
  # Create new instance
367
368
  instance = cls(session_layouts=session_layouts)
@@ -374,8 +375,8 @@ class ZellijLocalManager:
374
375
 
375
376
  for manager_file in manager_files:
376
377
  try:
377
- with open(manager_file, "r", encoding="utf-8") as f:
378
- manager_data = json.load(f)
378
+ text = manager_file.read_text(encoding="utf-8")
379
+ manager_data = json.loads(text)
379
380
 
380
381
  # Recreate the manager
381
382
  manager = ZellijLayoutGenerator()
@@ -493,7 +494,7 @@ if __name__ == "__main__":
493
494
 
494
495
  # Print attachment commands (without actually starting)
495
496
  print("\n📎 Attachment commands:")
496
- print(manager.attach_to_session())
497
+ print(manager.attach_to_session(None))
497
498
 
498
499
  # Show current status
499
500
  print("\n🔍 Current status:")
@@ -501,7 +502,7 @@ if __name__ == "__main__":
501
502
 
502
503
  # Demonstrate save/load
503
504
  print("\n💾 Demonstrating save/load...")
504
- session_id = manager.save()
505
+ session_id = manager.save(None)
505
506
  print(f"✅ Saved session: {session_id}")
506
507
 
507
508
  # List saved sessions
@@ -515,6 +516,8 @@ if __name__ == "__main__":
515
516
  # Show how to start monitoring (commented out to prevent infinite loop in demo)
516
517
  print("\n⏰ To start monitoring, run:")
517
518
  print("manager.run_monitoring_routine(wait_ms=30000) # 30 seconds")
519
+ print("# Or with session cleanup:")
520
+ print("manager.run_monitoring_routine(wait_ms=30000, kill_sessions_on_completion=True)")
518
521
 
519
522
  except Exception as e:
520
523
  print(f"❌ Error: {e}")
@@ -24,7 +24,7 @@ TMP_LAYOUT_DIR = Path.home().joinpath("tmp_results", "zellij_layouts", "layout_m
24
24
  class ZellijRemoteLayoutGenerator:
25
25
  def __init__(self, remote_name: str, session_name_prefix: str):
26
26
  self.remote_name = remote_name
27
- self.session_name = session_name_prefix + "_" + LayoutGenerator.generate_random_suffix()
27
+ self.session_name = session_name_prefix + "_" + LayoutGenerator.generate_random_suffix(8)
28
28
  self.layout_config: Optional[LayoutConfig] = None
29
29
  self.layout_path: Optional[str] = None
30
30
 
@@ -35,10 +35,7 @@ class ZellijRemoteLayoutGenerator:
35
35
  self.session_manager = SessionManager(self.remote_executor, self.session_name, TMP_LAYOUT_DIR)
36
36
  self.status_reporter = StatusReporter(self.process_monitor, self.session_manager)
37
37
 
38
- def copy_layout_to_remote(self, local_layout_file: Path, random_suffix: str) -> str:
39
- return self.session_manager.copy_layout_to_remote(local_layout_file, random_suffix)
40
-
41
- def create_zellij_layout(self, layout_config: LayoutConfig, output_dir: Optional[str] = None) -> str:
38
+ def create_zellij_layout(self, layout_config: LayoutConfig, output_dir: Optional[str]) -> str:
42
39
  # Enhanced Rich logging for remote layout creation
43
40
  tab_count = len(layout_config["layoutTabs"])
44
41
  layout_name = layout_config["layoutName"]
@@ -56,63 +53,16 @@ class ZellijRemoteLayoutGenerator:
56
53
  self.layout_path = self.layout_generator.create_layout_file(layout_config, output_path, self.session_name)
57
54
  return self.layout_path
58
55
 
59
- def get_layout_preview(self, layout_config: LayoutConfig) -> str:
60
- return self.layout_generator.generate_layout_content(layout_config)
61
-
62
- def check_command_status(self, tab_name: str, use_verification: bool = True) -> Dict[str, Any]:
63
- if not self.layout_config:
64
- return {"status": "error", "error": "No layout config available", "running": False}
65
- return self.process_monitor.check_command_status(tab_name, self.layout_config, use_verification)
66
-
67
- def check_all_commands_status(self) -> Dict[str, Dict[str, Any]]:
68
- if not self.layout_config:
69
- return {}
70
- return self.process_monitor.check_all_commands_status(self.layout_config)
71
-
72
- def check_zellij_session_status(self) -> Dict[str, Any]:
73
- return self.session_manager.check_zellij_session_status()
74
-
75
- def get_comprehensive_status(self) -> Dict[str, Any]:
76
- if not self.layout_config:
77
- return {"error": "No layout config available"}
78
- return self.status_reporter.get_comprehensive_status(self.layout_config)
79
-
80
- def print_status_report(self) -> None:
81
- if not self.layout_config:
82
- console.print("[bold red]❌ No layout config available[/bold red]")
83
- return
84
- self.status_reporter.print_status_report(self.layout_config)
85
-
86
- def start_zellij_session(self, layout_file_path: Optional[str] = None) -> Dict[str, Any]:
87
- return self.session_manager.start_zellij_session(layout_file_path or self.layout_path)
88
-
89
- def attach_to_session(self) -> None:
90
- self.session_manager.attach_to_session()
91
-
92
- # Legacy methods for backward compatibility
93
- def force_fresh_process_check(self, tab_name: str) -> Dict[str, Any]:
94
- if not self.layout_config:
95
- return {"error": "No layout config available"}
96
- return self.process_monitor.force_fresh_process_check(tab_name, self.layout_config)
97
-
98
- def verify_process_alive(self, pid: int) -> bool:
99
- return self.process_monitor.verify_process_alive(pid)
100
-
101
- def get_verified_process_status(self, tab_name: str) -> Dict[str, Any]:
102
- if not self.layout_config:
103
- return {"error": "No layout config available"}
104
- return self.process_monitor.get_verified_process_status(tab_name, self.layout_config)
105
-
106
56
  # Static methods for backward compatibility
107
57
  @staticmethod
108
- def run_remote_command(remote_name: str, command: str, timeout: int = 30):
58
+ def run_remote_command(remote_name: str, command: str, timeout: int):
109
59
  executor = RemoteExecutor(remote_name)
110
60
  return executor.run_command(command, timeout)
111
61
 
112
62
  def to_dict(self) -> Dict[str, Any]:
113
63
  return {"remote_name": self.remote_name, "session_name": self.session_name, "layout_config": self.layout_config, "layout_path": self.layout_path, "created_at": datetime.now().isoformat(), "class_name": self.__class__.__name__}
114
64
 
115
- def to_json(self, file_path: Optional[Union[str, Path]] = None) -> str:
65
+ def to_json(self, file_path: Optional[Union[str, Path]]) -> str:
116
66
  # Generate file path if not provided
117
67
  if file_path is None:
118
68
  random_id = str(uuid.uuid4())[:8]
@@ -150,8 +100,8 @@ class ZellijRemoteLayoutGenerator:
150
100
  raise FileNotFoundError(f"JSON file not found: {file_path}")
151
101
 
152
102
  # Load JSON data
153
- with open(file_path, "r", encoding="utf-8") as f:
154
- data = json.load(f)
103
+ text = Path(file_path).read_text(encoding="utf-8")
104
+ data = json.loads(text)
155
105
 
156
106
  # Validate that it's the correct class
157
107
  if data.get("class_name") != cls.__name__:
@@ -176,7 +126,7 @@ class ZellijRemoteLayoutGenerator:
176
126
  return instance
177
127
 
178
128
  @staticmethod
179
- def list_saved_sessions(directory_path: Optional[Union[str, Path]] = None) -> List[str]:
129
+ def list_saved_sessions(directory_path: Optional[Union[str, Path]]) -> List[str]:
180
130
  if directory_path is None:
181
131
  directory_path = Path.home() / "tmp_results" / "zellij_sessions" / "serialized"
182
132
  else:
@@ -208,16 +158,16 @@ if __name__ == "__main__":
208
158
  try:
209
159
  # Create layout using the remote generator
210
160
  generator = ZellijRemoteLayoutGenerator(remote_name=remote_name, session_name_prefix=session_name)
211
- layout_path = generator.create_zellij_layout(sample_layout)
161
+ layout_path = generator.create_zellij_layout(sample_layout, None)
212
162
  print(f"✅ Remote layout created successfully: {layout_path}")
213
163
 
214
164
  # Demonstrate serialization
215
165
  print("\n💾 Demonstrating serialization...")
216
- saved_path = generator.to_json()
166
+ saved_path = generator.to_json(None)
217
167
  print(f"✅ Session saved to: {saved_path}")
218
168
 
219
169
  # List all saved sessions
220
- saved_sessions = ZellijRemoteLayoutGenerator.list_saved_sessions()
170
+ saved_sessions = ZellijRemoteLayoutGenerator.list_saved_sessions(None)
221
171
  print(f"📋 Available saved sessions: {saved_sessions}")
222
172
 
223
173
  # Demonstrate loading (using the full path)
@@ -229,7 +179,10 @@ if __name__ == "__main__":
229
179
 
230
180
  # Demonstrate status checking
231
181
  print(f"\n🔍 Checking command status on remote '{remote_name}':")
232
- generator.print_status_report()
182
+ if not generator.layout_config:
183
+ console.print("[bold red]❌ No layout config available[/bold red]")
184
+ else:
185
+ generator.status_reporter.print_status_report(generator.layout_config)
233
186
 
234
187
  # Start the session (uncomment to actually start)
235
188
  # start_result = generator.start_zellij_session()
@@ -15,13 +15,13 @@ logger = get_logger("cluster.sessions_managers.zellij_remote_manager")
15
15
 
16
16
 
17
17
  class ZellijSessionManager:
18
- def __init__(self, machine_layouts: Dict[str, LayoutConfig], session_name_prefix: str = "JobMgr"):
18
+ def __init__(self, machine_layouts: Dict[str, LayoutConfig], session_name_prefix: str):
19
19
  self.session_name_prefix = session_name_prefix
20
20
  self.machine_layouts = machine_layouts # Store the original config
21
21
  self.managers: list[ZellijRemoteLayoutGenerator] = []
22
22
  for machine, layout_config in machine_layouts.items():
23
23
  an_m = ZellijRemoteLayoutGenerator(remote_name=machine, session_name_prefix=self.session_name_prefix)
24
- an_m.create_zellij_layout(layout_config=layout_config)
24
+ an_m.create_zellij_layout(layout_config=layout_config, output_dir=None)
25
25
  self.managers.append(an_m)
26
26
 
27
27
  def ssh_to_all_machines(self) -> str:
@@ -40,18 +40,21 @@ class ZellijSessionManager:
40
40
 
41
41
  def kill_all_sessions(self) -> None:
42
42
  for an_m in self.managers:
43
- ZellijRemoteLayoutGenerator.run_remote_command(remote_name=an_m.remote_name, command="zellij kill-all-sessions --yes")
43
+ ZellijRemoteLayoutGenerator.run_remote_command(remote_name=an_m.remote_name, command="zellij kill-all-sessions --yes", timeout=30)
44
44
 
45
45
  def start_zellij_sessions(self) -> None:
46
46
  for an_m in self.managers:
47
- an_m.start_zellij_session()
47
+ an_m.session_manager.start_zellij_session(an_m.layout_path)
48
48
 
49
49
  def run_monitoring_routine(self) -> None:
50
50
  def routine(scheduler: Scheduler):
51
51
  if scheduler.cycle % 2 == 0:
52
52
  statuses = []
53
53
  for _idx, an_m in enumerate(self.managers):
54
- a_status = an_m.check_all_commands_status()
54
+ if not an_m.layout_config:
55
+ a_status = {}
56
+ else:
57
+ a_status = an_m.process_monitor.check_all_commands_status(an_m.layout_config)
55
58
  statuses.append(a_status)
56
59
  keys = []
57
60
  for item in statuses:
@@ -76,7 +79,7 @@ class ZellijSessionManager:
76
79
  else:
77
80
  statuses = []
78
81
  for _idx, an_m in enumerate(self.managers):
79
- a_status = an_m.check_zellij_session_status()
82
+ a_status = an_m.session_manager.check_zellij_session_status()
80
83
  statuses.append(a_status)
81
84
 
82
85
  # Print statuses
@@ -86,7 +89,7 @@ class ZellijSessionManager:
86
89
  sched = Scheduler(routine=routine, wait_ms=60_000, logger=logger)
87
90
  sched.run()
88
91
 
89
- def save(self, session_id: Optional[str] = None) -> str:
92
+ def save(self, session_id: Optional[str]) -> str:
90
93
  if session_id is None:
91
94
  session_id = str(uuid.uuid4())[:8]
92
95
 
@@ -124,16 +127,16 @@ class ZellijSessionManager:
124
127
  config_file = session_dir / "machine_layouts.json"
125
128
  if not config_file.exists():
126
129
  raise FileNotFoundError(f"Configuration file not found: {config_file}")
127
- with open(config_file, "r", encoding="utf-8") as f:
128
- machine_layouts = json.load(f)
130
+ text = config_file.read_text(encoding="utf-8")
131
+ machine_layouts = json.loads(text)
129
132
 
130
133
  # Load metadata
131
134
  metadata_file = session_dir / "metadata.json"
132
135
  session_name_prefix = "JobMgr" # default fallback
133
136
  if metadata_file.exists():
134
- with open(metadata_file, "r", encoding="utf-8") as f:
135
- metadata = json.load(f)
136
- session_name_prefix = metadata.get("session_name_prefix", "JobMgr")
137
+ text = metadata_file.read_text(encoding="utf-8")
138
+ metadata = json.loads(text)
139
+ session_name_prefix = metadata.get("session_name_prefix", "JobMgr")
137
140
  # Create new instance (this will create new managers)
138
141
  instance = cls(machine_layouts=machine_layouts, session_name_prefix=session_name_prefix)
139
142
  # Load saved managers to restore their states
@@ -3,9 +3,12 @@
3
3
  Example usage of the modularized Zellij remote layout generator.
4
4
  """
5
5
 
6
+ from rich.console import Console
6
7
  from machineconfig.cluster.sessions_managers.zellij_remote import ZellijRemoteLayoutGenerator
7
8
  from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
8
9
 
10
+ console = Console()
11
+
9
12
 
10
13
  def example_usage():
11
14
  """Demonstrate the refactored modular usage."""
@@ -30,16 +33,19 @@ def example_usage():
30
33
  generator = ZellijRemoteLayoutGenerator(remote_name=remote_name, session_name_prefix=session_name)
31
34
 
32
35
  # Create layout file
33
- layout_path = generator.create_zellij_layout(sample_layout)
36
+ layout_path = generator.create_zellij_layout(sample_layout, None)
34
37
  print(f"✅ Remote layout created successfully: {layout_path}")
35
38
 
36
39
  # Preview the layout content
37
- preview = generator.get_layout_preview(sample_layout)
40
+ preview = generator.layout_generator.generate_layout_content(sample_layout)
38
41
  print(f"📄 Layout preview:\n{preview}")
39
42
 
40
43
  # Check status using the modular components
41
44
  print(f"\n🔍 Checking command status on remote '{remote_name}':")
42
- generator.print_status_report()
45
+ if not generator.layout_config:
46
+ console.print("[bold red]❌ No layout config available[/bold red]")
47
+ else:
48
+ generator.status_reporter.print_status_report(generator.layout_config)
43
49
 
44
50
  # The individual components can also be used directly:
45
51
  print("\n🔧 Direct component usage examples:")
@@ -31,7 +31,7 @@ class LayoutGenerator:
31
31
  """
32
32
 
33
33
  @staticmethod
34
- def generate_random_suffix(length: int = 8) -> str:
34
+ def generate_random_suffix(length: int) -> str:
35
35
  """Generate a random string suffix for unique layout file names."""
36
36
  return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
37
37
 
@@ -121,7 +121,7 @@ class LayoutGenerator:
121
121
  self.validate_tab_config(layout_config)
122
122
 
123
123
  # Generate unique suffix for this layout
124
- random_suffix = self.generate_random_suffix()
124
+ random_suffix = self.generate_random_suffix(8)
125
125
  layout_content = self.generate_layout_content(layout_config)
126
126
 
127
127
  try:
@@ -1,7 +1,5 @@
1
- # TypedDict definitions for better type safety
2
- from typing import NotRequired, TypedDict, Optional
3
1
 
4
- # Import concrete types to replace Any usage
2
+ from typing import NotRequired, TypedDict, Optional
5
3
  from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
6
4
 
7
5
 
@@ -10,47 +8,37 @@ class ProcessInfo(TypedDict):
10
8
  name: str
11
9
  cmdline: list[str]
12
10
  status: str
11
+ cmdline_str: NotRequired[str]
12
+ create_time: NotRequired[float]
13
+ is_direct_command: NotRequired[bool]
14
+ verified_alive: NotRequired[bool]
15
+ memory_mb: NotRequired[float]
16
+
13
17
 
14
18
  class CommandStatus(TypedDict):
15
- status: str
16
- running: bool
17
- processes: list[ProcessInfo]
18
- command: str
19
- cwd: str
20
- tab_name: str
19
+ status: str # e.g. running | not_running | unknown | error
20
+ running: bool # Convenience boolean
21
+ processes: list[ProcessInfo] # Matching processes (can be empty)
22
+ command: str # Original command string ('' if unknown)
23
+ tab_name: str # Tab identifier
24
+ # Optional / contextual fields
25
+ cwd: NotRequired[str]
21
26
  error: NotRequired[str]
22
27
  pid: NotRequired[int]
23
-
24
-
25
- class SessionStatus(TypedDict):
26
- session_exists: bool
27
- zellij_running: bool
28
- session_name: str
29
- all_sessions: list[str]
30
- error: NotRequired[str]
31
-
32
-
28
+ remote: NotRequired[str]
29
+ check_timestamp: NotRequired[str | float]
30
+ method: NotRequired[str]
31
+ raw_output: NotRequired[str]
32
+ verification_method: NotRequired[str]
33
33
  class CommandSummary(TypedDict):
34
34
  total_commands: int
35
35
  running_commands: int
36
36
  stopped_commands: int
37
37
  session_healthy: bool
38
38
 
39
-
40
- class CommandStatusResult(TypedDict):
41
- status: str
42
- running: bool
43
- processes: list[ProcessInfo]
44
- command: str
45
- cwd: str
46
- tab_name: str
47
- error: NotRequired[str]
48
- pid: NotRequired[int]
49
-
50
-
51
39
  class ZellijSessionStatus(TypedDict):
52
40
  zellij_running: bool
53
- session_exists: NotRequired[bool]
41
+ session_exists: bool
54
42
  session_name: str
55
43
  all_sessions: list[str]
56
44
  error: NotRequired[str]
@@ -58,8 +46,27 @@ class ZellijSessionStatus(TypedDict):
58
46
 
59
47
  class SessionReport(TypedDict):
60
48
  session_status: ZellijSessionStatus # ZellijSessionStatus from zellij_local
61
- commands_status: dict[str, CommandStatusResult] # dict[str, CommandStatusResult from zellij_local]
49
+ commands_status: dict[str, CommandStatus] # dict[str, CommandStatus from zellij_local]
62
50
  summary: CommandSummary
51
+ class ComprehensiveStatus(TypedDict):
52
+ zellij_session: ZellijSessionStatus
53
+ commands: dict[str, CommandStatus]
54
+ summary: CommandSummary
55
+ class SessionMetadata(TypedDict):
56
+ session_name_prefix: str
57
+ created_at: str
58
+ num_managers: int
59
+ sessions: list[str]
60
+ manager_type: str
61
+ class ManagerData(TypedDict):
62
+ session_name: Optional[str]
63
+ layout_config: Optional[LayoutConfig] # Will be LayoutConfig from layout_types
64
+ layout_path: Optional[str]
65
+ class ActiveSessionInfo(TypedDict):
66
+ session_name: str
67
+ is_active: bool
68
+ tab_count: int
69
+ tabs: list[str]
63
70
 
64
71
 
65
72
  class GlobalSummary(TypedDict):
@@ -77,8 +84,6 @@ class StartResult(TypedDict):
77
84
  success: bool
78
85
  message: NotRequired[str]
79
86
  error: NotRequired[str]
80
-
81
-
82
87
  class StatusRow(TypedDict):
83
88
  session: str
84
89
  tab: str
@@ -87,35 +92,3 @@ class StatusRow(TypedDict):
87
92
  processes: int
88
93
 
89
94
 
90
- class SessionMetadata(TypedDict):
91
- session_name_prefix: str
92
- created_at: str
93
- num_managers: int
94
- sessions: list[str]
95
- manager_type: str
96
-
97
-
98
- class ManagerData(TypedDict):
99
- session_name: Optional[str]
100
- layout_config: Optional[LayoutConfig] # Will be LayoutConfig from layout_types
101
- layout_path: Optional[str]
102
-
103
-
104
- class ActiveSessionInfo(TypedDict):
105
- session_name: str
106
- is_active: bool
107
- tab_count: int
108
- tabs: list[str]
109
-
110
-
111
- class StatusSummary(TypedDict):
112
- total_commands: int
113
- running_commands: int
114
- stopped_commands: int
115
- session_healthy: bool
116
-
117
-
118
- class ComprehensiveStatus(TypedDict):
119
- zellij_session: ZellijSessionStatus
120
- commands: dict[str, CommandStatusResult]
121
- summary: StatusSummary