machineconfig 1.97__py3-none-any.whl → 2.0__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 (166) hide show
  1. machineconfig/cluster/cloud_manager.py +22 -26
  2. machineconfig/cluster/data_transfer.py +2 -2
  3. machineconfig/cluster/distribute.py +0 -2
  4. machineconfig/cluster/file_manager.py +4 -4
  5. machineconfig/cluster/job_params.py +1 -1
  6. machineconfig/cluster/loader_runner.py +8 -8
  7. machineconfig/cluster/remote_machine.py +4 -4
  8. machineconfig/cluster/script_execution.py +2 -2
  9. machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +1 -1
  10. machineconfig/cluster/sessions_managers/enhanced_command_runner.py +23 -23
  11. machineconfig/cluster/sessions_managers/wt_local.py +78 -76
  12. machineconfig/cluster/sessions_managers/wt_local_manager.py +91 -91
  13. machineconfig/cluster/sessions_managers/wt_remote.py +39 -39
  14. machineconfig/cluster/sessions_managers/wt_remote_manager.py +94 -91
  15. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +56 -54
  16. machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +49 -49
  17. machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +18 -18
  18. machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +42 -42
  19. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +36 -36
  20. machineconfig/cluster/sessions_managers/zellij_local.py +43 -46
  21. machineconfig/cluster/sessions_managers/zellij_local_manager.py +139 -120
  22. machineconfig/cluster/sessions_managers/zellij_remote.py +35 -35
  23. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +33 -33
  24. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +15 -15
  25. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +25 -26
  26. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +49 -49
  27. machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +5 -5
  28. machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +15 -15
  29. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +11 -11
  30. machineconfig/cluster/templates/utils.py +3 -3
  31. machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
  32. machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
  33. machineconfig/jobs/python/__pycache__/python_ve_symlink.cpython-311.pyc +0 -0
  34. machineconfig/jobs/python/check_installations.py +8 -9
  35. machineconfig/jobs/python/python_cargo_build_share.py +2 -2
  36. machineconfig/jobs/python/vscode/link_ve.py +7 -7
  37. machineconfig/jobs/python/vscode/select_interpreter.py +7 -7
  38. machineconfig/jobs/python/vscode/sync_code.py +5 -5
  39. machineconfig/jobs/python_custom_installers/archive/ngrok.py +2 -2
  40. machineconfig/jobs/python_custom_installers/dev/aider.py +3 -3
  41. machineconfig/jobs/python_custom_installers/dev/alacritty.py +3 -3
  42. machineconfig/jobs/python_custom_installers/dev/brave.py +3 -3
  43. machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +5 -5
  44. machineconfig/jobs/python_custom_installers/dev/code.py +3 -3
  45. machineconfig/jobs/python_custom_installers/dev/cursor.py +9 -9
  46. machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +4 -4
  47. machineconfig/jobs/python_custom_installers/dev/espanso.py +4 -4
  48. machineconfig/jobs/python_custom_installers/dev/goes.py +4 -4
  49. machineconfig/jobs/python_custom_installers/dev/lvim.py +4 -4
  50. machineconfig/jobs/python_custom_installers/dev/nerdfont.py +3 -3
  51. machineconfig/jobs/python_custom_installers/dev/redis.py +3 -3
  52. machineconfig/jobs/python_custom_installers/dev/wezterm.py +3 -3
  53. machineconfig/jobs/python_custom_installers/dev/winget.py +27 -27
  54. machineconfig/jobs/python_custom_installers/docker.py +3 -3
  55. machineconfig/jobs/python_custom_installers/gh.py +7 -7
  56. machineconfig/jobs/python_custom_installers/hx.py +1 -1
  57. machineconfig/jobs/python_custom_installers/warp-cli.py +3 -3
  58. machineconfig/jobs/python_generic_installers/config.json +412 -389
  59. machineconfig/jobs/python_windows_installers/dev/config.json +1 -1
  60. machineconfig/logger.py +50 -0
  61. machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
  62. machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
  63. machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
  64. machineconfig/profile/create.py +23 -16
  65. machineconfig/profile/create_hardlinks.py +8 -8
  66. machineconfig/profile/shell.py +41 -37
  67. machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  68. machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  69. machineconfig/scripts/linux/devops +2 -2
  70. machineconfig/scripts/linux/fire +1 -0
  71. machineconfig/scripts/linux/fire_agents +0 -1
  72. machineconfig/scripts/linux/mcinit +1 -1
  73. machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
  74. machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
  75. machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
  76. machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
  77. machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
  78. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
  79. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
  80. machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
  81. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
  82. machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
  83. machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
  84. machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-311.pyc +0 -0
  85. machineconfig/scripts/python/ai/chatmodes/Thinking-Beast-Mode.chatmode.md +337 -0
  86. machineconfig/scripts/python/ai/chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md +644 -0
  87. machineconfig/scripts/python/ai/chatmodes/deepResearch.chatmode.md +81 -0
  88. machineconfig/scripts/python/ai/configs/.gemini/settings.json +81 -0
  89. machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +45 -0
  90. machineconfig/scripts/python/ai/mcinit.py +103 -0
  91. machineconfig/scripts/python/ai/prompts/allLintersAndTypeCheckers.prompt.md +5 -0
  92. machineconfig/scripts/python/ai/prompts/research-report-skeleton.prompt.md +38 -0
  93. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +47 -0
  94. machineconfig/scripts/python/archive/tmate_conn.py +5 -5
  95. machineconfig/scripts/python/archive/tmate_start.py +3 -3
  96. machineconfig/scripts/python/choose_wezterm_theme.py +2 -2
  97. machineconfig/scripts/python/cloud_copy.py +19 -18
  98. machineconfig/scripts/python/cloud_mount.py +9 -7
  99. machineconfig/scripts/python/cloud_repo_sync.py +11 -11
  100. machineconfig/scripts/python/cloud_sync.py +1 -1
  101. machineconfig/scripts/python/croshell.py +14 -14
  102. machineconfig/scripts/python/devops.py +6 -6
  103. machineconfig/scripts/python/devops_add_identity.py +8 -6
  104. machineconfig/scripts/python/devops_add_ssh_key.py +18 -18
  105. machineconfig/scripts/python/devops_backup_retrieve.py +13 -13
  106. machineconfig/scripts/python/devops_devapps_install.py +3 -3
  107. machineconfig/scripts/python/devops_update_repos.py +1 -1
  108. machineconfig/scripts/python/dotfile.py +2 -2
  109. machineconfig/scripts/python/fire_agents.py +183 -41
  110. machineconfig/scripts/python/fire_jobs.py +17 -17
  111. machineconfig/scripts/python/ftpx.py +2 -2
  112. machineconfig/scripts/python/gh_models.py +94 -94
  113. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
  114. machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
  115. machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
  116. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
  117. machineconfig/scripts/python/helpers/cloud_helpers.py +3 -3
  118. machineconfig/scripts/python/helpers/helpers2.py +1 -1
  119. machineconfig/scripts/python/helpers/helpers4.py +8 -6
  120. machineconfig/scripts/python/helpers/helpers5.py +7 -7
  121. machineconfig/scripts/python/helpers/repo_sync_helpers.py +1 -1
  122. machineconfig/scripts/python/mount_nfs.py +3 -2
  123. machineconfig/scripts/python/mount_nw_drive.py +4 -4
  124. machineconfig/scripts/python/mount_ssh.py +3 -2
  125. machineconfig/scripts/python/repos.py +8 -8
  126. machineconfig/scripts/python/scheduler.py +1 -1
  127. machineconfig/scripts/python/start_slidev.py +8 -7
  128. machineconfig/scripts/python/start_terminals.py +1 -1
  129. machineconfig/scripts/python/viewer.py +40 -40
  130. machineconfig/scripts/python/wifi_conn.py +65 -66
  131. machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
  132. machineconfig/scripts/windows/mcinit.ps1 +1 -1
  133. machineconfig/settings/linters/.ruff.toml +2 -2
  134. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +71 -71
  135. machineconfig/settings/shells/wt/settings.json +8 -8
  136. machineconfig/setup_linux/web_shortcuts/tmp.sh +2 -0
  137. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +10 -7
  138. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +9 -7
  139. machineconfig/utils/ai/browser_user_wrapper.py +5 -5
  140. machineconfig/utils/ai/generate_file_checklist.py +11 -12
  141. machineconfig/utils/ai/url2md.py +1 -1
  142. machineconfig/utils/cloud/onedrive/setup_oauth.py +4 -4
  143. machineconfig/utils/cloud/onedrive/transaction.py +129 -129
  144. machineconfig/utils/code.py +13 -6
  145. machineconfig/utils/installer.py +51 -53
  146. machineconfig/utils/installer_utils/installer_abc.py +21 -10
  147. machineconfig/utils/installer_utils/installer_class.py +42 -16
  148. machineconfig/utils/io_save.py +3 -15
  149. machineconfig/utils/options.py +10 -3
  150. machineconfig/utils/path.py +5 -0
  151. machineconfig/utils/path_reduced.py +201 -149
  152. machineconfig/utils/procs.py +23 -23
  153. machineconfig/utils/scheduling.py +11 -12
  154. machineconfig/utils/ssh.py +270 -0
  155. machineconfig/utils/terminal.py +180 -0
  156. machineconfig/utils/utils.py +1 -2
  157. machineconfig/utils/utils2.py +43 -0
  158. machineconfig/utils/utils5.py +163 -34
  159. machineconfig/utils/ve.py +2 -2
  160. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/METADATA +13 -8
  161. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/RECORD +163 -149
  162. machineconfig/cluster/self_ssh.py +0 -57
  163. machineconfig/scripts/python/ai/init.py +0 -56
  164. machineconfig/scripts/python/ai/rules/python/dev.md +0 -31
  165. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/WHEEL +0 -0
  166. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/top_level.txt +0 -0
@@ -10,6 +10,9 @@ from machineconfig.cluster.sessions_managers.wt_remote import WTRemoteLayoutGene
10
10
 
11
11
  TMP_SERIALIZATION_DIR = Path.home().joinpath("tmp_results", "session_manager", "wt", "remote_manager")
12
12
 
13
+ # Module-level logger to be used throughout this module
14
+ logger = logging.getLogger(__name__)
15
+
13
16
 
14
17
  class WTSessionManager:
15
18
  def __init__(self, machine2wt_tabs: dict[str, dict[str, tuple[str, str]]], session_name_prefix: str = "WTJobMgr"):
@@ -34,7 +37,7 @@ class WTSessionManager:
34
37
  a_cmd = run_command_in_wt_tab(command=ssh_cmd, tab_name=hostname, cwd=None)
35
38
  cmds += a_cmd + "\n"
36
39
  return cmds
37
-
40
+
38
41
  def kill_all_sessions(self) -> None:
39
42
  for an_m in self.managers:
40
43
  WTRemoteLayoutGenerator.run_remote_command(
@@ -60,12 +63,12 @@ class WTSessionManager:
60
63
  for i, key in enumerate(keys):
61
64
  if i < len(values):
62
65
  status_data.append({"tabName": key, "status": values[i]})
63
-
66
+
64
67
  # Check if all stopped
65
68
  running_count = sum(1 for item in status_data if item.get("status", {}).get("running", False))
66
69
  if running_count == 0: # they all stopped
67
70
  scheduler.max_cycles = scheduler.cycle # stop the scheduler from calling this routine again
68
-
71
+
69
72
  # Print status
70
73
  for item in status_data:
71
74
  print(f"Tab: {item['tabName']}, Status: {item['status']}")
@@ -74,26 +77,26 @@ class WTSessionManager:
74
77
  for _idx, an_m in enumerate(self.managers):
75
78
  a_status = an_m.check_wt_session_status()
76
79
  statuses.append(a_status)
77
-
80
+
78
81
  # Print statuses
79
82
  for i, status in enumerate(statuses):
80
83
  print(f"Manager {i}: {status}")
81
- sched = Scheduler(routine=routine, wait_ms=wait_ms)
84
+ sched = Scheduler(routine=routine, wait_ms=wait_ms, logger=logger)
82
85
  sched.run()
83
86
 
84
87
  def save(self, session_id: Optional[str] = None) -> str:
85
88
  if session_id is None:
86
89
  session_id = str(uuid.uuid4())[:8]
87
-
90
+
88
91
  # Create session directory
89
92
  session_dir = TMP_SERIALIZATION_DIR / session_id
90
93
  session_dir.mkdir(parents=True, exist_ok=True)
91
-
94
+
92
95
  # Save the machine2wt_tabs configuration
93
96
  config_file = session_dir / "machine2wt_tabs.json"
94
- with open(config_file, 'w', encoding='utf-8') as f:
95
- json.dump(self.machine2wt_tabs, f, indent=2, ensure_ascii=False)
96
-
97
+ text = json.dumps(self.machine2wt_tabs, indent=2, ensure_ascii=False)
98
+ config_file.write_text(text, encoding="utf-8")
99
+
97
100
  # Save session metadata
98
101
  metadata = {
99
102
  "session_name_prefix": self.session_name_prefix,
@@ -103,39 +106,39 @@ class WTSessionManager:
103
106
  "manager_type": "WTSessionManager"
104
107
  }
105
108
  metadata_file = session_dir / "metadata.json"
106
- with open(metadata_file, 'w', encoding='utf-8') as f:
107
- json.dump(metadata, f, indent=2, ensure_ascii=False)
108
-
109
+ text = json.dumps(metadata, indent=2, ensure_ascii=False)
110
+ metadata_file.write_text(text, encoding="utf-8")
111
+
109
112
  # Save each WTRemoteLayoutGenerator
110
113
  managers_dir = session_dir / "managers"
111
114
  managers_dir.mkdir(exist_ok=True)
112
-
115
+
113
116
  for i, manager in enumerate(self.managers):
114
117
  manager_file = managers_dir / f"manager_{i}_{manager.remote_name}.json"
115
118
  manager.to_json(str(manager_file))
116
-
117
- logging.info(f"✅ Saved WTSessionManager session to: {session_dir}")
119
+
120
+ logger.info(f"✅ Saved WTSessionManager session to: {session_dir}")
118
121
  return session_id
119
122
 
120
123
  @classmethod
121
124
  def load(cls, session_id: str) -> 'WTSessionManager':
122
125
  session_dir = TMP_SERIALIZATION_DIR / session_id
123
-
126
+
124
127
  if not session_dir.exists():
125
- raise FileNotFoundError(f"Session directory not found: {session_dir}")
128
+ raise FileNotFoundError(f"Session directory not found: {session_dir}")
126
129
  config_file = session_dir / "machine2wt_tabs.json"
127
130
  if not config_file.exists():
128
- raise FileNotFoundError(f"Configuration file not found: {config_file}")
131
+ raise FileNotFoundError(f"Configuration file not found: {config_file}")
129
132
  with open(config_file, 'r', encoding='utf-8') as f:
130
133
  machine2wt_tabs = json.load(f)
131
-
134
+
132
135
  # Load metadata
133
136
  metadata_file = session_dir / "metadata.json"
134
137
  session_name_prefix = "WTJobMgr" # default fallback
135
138
  if metadata_file.exists():
136
139
  with open(metadata_file, 'r', encoding='utf-8') as f:
137
140
  metadata = json.load(f)
138
- session_name_prefix = metadata.get("session_name_prefix", "WTJobMgr")
141
+ session_name_prefix = metadata.get("session_name_prefix", "WTJobMgr")
139
142
  # Create new instance (this will create new managers)
140
143
  instance = cls(machine2wt_tabs=machine2wt_tabs, session_name_prefix=session_name_prefix)
141
144
  # Load saved managers to restore their states
@@ -144,43 +147,43 @@ class WTSessionManager:
144
147
  # Clear the auto-created managers and load the saved ones
145
148
  instance.managers = []
146
149
  # Get all manager files and sort them
147
- manager_files = sorted(managers_dir.glob("manager_*.json"))
150
+ manager_files = sorted(managers_dir.glob("manager_*.json"))
148
151
  for manager_file in manager_files:
149
152
  try:
150
153
  loaded_manager = WTRemoteLayoutGenerator.from_json(str(manager_file))
151
154
  instance.managers.append(loaded_manager)
152
155
  except Exception as e:
153
- logging.warning(f"Failed to load manager from {manager_file}: {e}")
154
- logging.info(f"✅ Loaded WTSessionManager session from: {session_dir}")
156
+ logger.warning(f"Failed to load manager from {manager_file}: {e}")
157
+ logger.info(f"✅ Loaded WTSessionManager session from: {session_dir}")
155
158
  return instance
156
159
 
157
160
  @staticmethod
158
161
  def list_saved_sessions() -> list[str]:
159
162
  if not TMP_SERIALIZATION_DIR.exists():
160
163
  return []
161
-
164
+
162
165
  sessions = []
163
166
  for item in TMP_SERIALIZATION_DIR.iterdir():
164
167
  if item.is_dir() and (item / "metadata.json").exists():
165
168
  sessions.append(item.name)
166
-
169
+
167
170
  return sorted(sessions)
168
171
 
169
172
  @staticmethod
170
173
  def delete_session(session_id: str) -> bool:
171
174
  session_dir = TMP_SERIALIZATION_DIR / session_id
172
-
175
+
173
176
  if not session_dir.exists():
174
- logging.warning(f"Session directory not found: {session_dir}")
177
+ logger.warning(f"Session directory not found: {session_dir}")
175
178
  return False
176
-
179
+
177
180
  try:
178
181
  import shutil
179
182
  shutil.rmtree(session_dir)
180
- logging.info(f"✅ Deleted session: {session_id}")
183
+ logger.info(f"✅ Deleted session: {session_id}")
181
184
  return True
182
185
  except Exception as e:
183
- logging.error(f"Failed to delete session {session_id}: {e}")
186
+ logger.error(f"Failed to delete session {session_id}: {e}")
184
187
  return False
185
188
 
186
189
  def start_all_sessions(self) -> dict[str, Any]:
@@ -190,44 +193,44 @@ class WTSessionManager:
190
193
  try:
191
194
  session_name = manager.session_name
192
195
  remote_name = manager.remote_name
193
-
196
+
194
197
  # Start the Windows Terminal session on the remote machine
195
198
  start_result = manager.start_wt_session()
196
-
199
+
197
200
  results[f"{remote_name}:{session_name}"] = start_result
198
-
201
+
199
202
  if start_result.get("success"):
200
- logging.info(f"✅ Started session '{session_name}' on {remote_name}")
203
+ logger.info(f"✅ Started session '{session_name}' on {remote_name}")
201
204
  else:
202
- logging.error(f"❌ Failed to start session '{session_name}' on {remote_name}: {start_result.get('error')}")
203
-
205
+ logger.error(f"❌ Failed to start session '{session_name}' on {remote_name}: {start_result.get('error')}")
206
+
204
207
  except Exception as e:
205
208
  results[f"{manager.remote_name}:{manager.session_name}"] = {
206
209
  "success": False,
207
210
  "error": str(e)
208
211
  }
209
- logging.error(f"❌ Exception starting session on {manager.remote_name}: {e}")
210
-
212
+ logger.error(f"❌ Exception starting session on {manager.remote_name}: {e}")
213
+
211
214
  return results
212
215
 
213
216
  def check_all_sessions_status(self) -> dict[str, dict[str, Any]]:
214
217
  """Check the status of all remote sessions and their commands."""
215
218
  status_report = {}
216
-
219
+
217
220
  for manager in self.managers:
218
221
  session_key = f"{manager.remote_name}:{manager.session_name}"
219
-
222
+
220
223
  try:
221
224
  # Get Windows Terminal session status
222
225
  wt_status = manager.check_wt_session_status()
223
-
226
+
224
227
  # Get commands status for this session
225
228
  commands_status = manager.check_all_commands_status()
226
-
229
+
227
230
  # Calculate summary for this session
228
231
  running_count = sum(1 for status in commands_status.values() if status.get("running", False))
229
232
  total_count = len(commands_status)
230
-
233
+
231
234
  status_report[session_key] = {
232
235
  "remote_name": manager.remote_name,
233
236
  "session_name": manager.session_name,
@@ -240,7 +243,7 @@ class WTSessionManager:
240
243
  "session_healthy": wt_status.get("wt_running", False)
241
244
  }
242
245
  }
243
-
246
+
244
247
  except Exception as e:
245
248
  status_report[session_key] = {
246
249
  "remote_name": manager.remote_name,
@@ -253,22 +256,22 @@ class WTSessionManager:
253
256
  "session_healthy": False
254
257
  }
255
258
  }
256
- logging.error(f"Error checking status for {session_key}: {e}")
257
-
259
+ logger.error(f"Error checking status for {session_key}: {e}")
260
+
258
261
  return status_report
259
262
 
260
263
  def get_global_summary(self) -> dict[str, Any]:
261
264
  """Get a global summary across all remote sessions."""
262
265
  all_status = self.check_all_sessions_status()
263
-
266
+
264
267
  total_sessions = len(all_status)
265
- healthy_sessions = sum(1 for status in all_status.values()
268
+ healthy_sessions = sum(1 for status in all_status.values()
266
269
  if status["summary"]["session_healthy"])
267
- total_commands = sum(status["summary"]["total_commands"]
270
+ total_commands = sum(status["summary"]["total_commands"]
268
271
  for status in all_status.values())
269
- total_running = sum(status["summary"]["running_commands"]
272
+ total_running = sum(status["summary"]["running_commands"]
270
273
  for status in all_status.values())
271
-
274
+
272
275
  return {
273
276
  "total_sessions": total_sessions,
274
277
  "healthy_sessions": healthy_sessions,
@@ -285,11 +288,11 @@ class WTSessionManager:
285
288
  """Print a comprehensive status report for all remote sessions."""
286
289
  all_status = self.check_all_sessions_status()
287
290
  global_summary = self.get_global_summary()
288
-
291
+
289
292
  print("=" * 80)
290
293
  print("🖥️ WINDOWS TERMINAL REMOTE MANAGER STATUS REPORT")
291
294
  print("=" * 80)
292
-
295
+
293
296
  # Global summary
294
297
  print("🌐 GLOBAL SUMMARY:")
295
298
  print(f" Total sessions: {global_summary['total_sessions']}")
@@ -299,24 +302,24 @@ class WTSessionManager:
299
302
  print(f" Remote machines: {len(global_summary['remote_machines'])}")
300
303
  print(f" All healthy: {'✅' if global_summary['all_sessions_healthy'] else '❌'}")
301
304
  print()
302
-
305
+
303
306
  # Per-session details
304
307
  for _, status in all_status.items():
305
308
  remote_name = status["remote_name"]
306
309
  session_name = status["session_name"]
307
-
310
+
308
311
  print(f"🖥️ REMOTE: {remote_name} | SESSION: {session_name}")
309
312
  print("-" * 60)
310
-
313
+
311
314
  if "error" in status:
312
315
  print(f"❌ Error: {status['error']}")
313
316
  print()
314
317
  continue
315
-
318
+
316
319
  wt_status = status["wt_status"]
317
320
  commands_status = status["commands_status"]
318
321
  summary = status["summary"]
319
-
322
+
320
323
  # Windows Terminal session health
321
324
  if wt_status.get("wt_running", False):
322
325
  if wt_status.get("session_exists", False):
@@ -329,7 +332,7 @@ class WTSessionManager:
329
332
  print(f"⚠️ Windows Terminal is running but no session windows found on {remote_name}")
330
333
  else:
331
334
  print(f"❌ Windows Terminal issue on {remote_name}: {wt_status.get('error', 'Unknown error')}")
332
-
335
+
333
336
  # Commands in this session
334
337
  print(f" Commands ({summary['running_commands']}/{summary['total_commands']} running):")
335
338
  for tab_name, cmd_status in commands_status.items():
@@ -338,31 +341,31 @@ class WTSessionManager:
338
341
  if len(cmd_status.get("command", "")) > 50:
339
342
  cmd_text += "..."
340
343
  print(f" {status_icon} {tab_name}: {cmd_text}")
341
-
344
+
342
345
  if cmd_status.get("processes"):
343
346
  for proc in cmd_status["processes"][:2]: # Show first 2 processes
344
347
  print(f" └─ PID {proc.get('pid', 'Unknown')}: {proc.get('name', 'Unknown')}")
345
348
  print()
346
-
349
+
347
350
  print("=" * 80)
348
351
 
349
352
  def get_remote_overview(self) -> dict[str, Any]:
350
353
  """Get overview of all remote machines and their Windows Terminal status."""
351
354
  overview = {}
352
-
355
+
353
356
  for manager in self.managers:
354
357
  try:
355
358
  remote_name = manager.remote_name
356
-
359
+
357
360
  # Get remote Windows info
358
361
  windows_info = manager.get_remote_windows_info()
359
-
362
+
360
363
  # Get Windows Terminal processes
361
364
  wt_processes = manager.list_wt_processes()
362
-
365
+
363
366
  # Get Windows Terminal version
364
367
  wt_version = manager.get_wt_version()
365
-
368
+
366
369
  overview[remote_name] = {
367
370
  "windows_info": windows_info,
368
371
  "wt_processes": wt_processes,
@@ -370,58 +373,58 @@ class WTSessionManager:
370
373
  "session_name": manager.session_name,
371
374
  "tab_count": len(manager.tab_config)
372
375
  }
373
-
376
+
374
377
  except Exception as e:
375
378
  overview[manager.remote_name] = {
376
379
  "error": str(e),
377
380
  "session_name": manager.session_name
378
381
  }
379
-
382
+
380
383
  return overview
381
384
 
382
385
  def print_remote_overview(self) -> None:
383
386
  """Print overview of all remote machines."""
384
387
  overview = self.get_remote_overview()
385
-
388
+
386
389
  print("=" * 80)
387
390
  print("🌐 REMOTE MACHINES OVERVIEW")
388
391
  print("=" * 80)
389
-
392
+
390
393
  for remote_name, info in overview.items():
391
394
  print(f"🖥️ REMOTE: {remote_name}")
392
395
  print("-" * 40)
393
-
396
+
394
397
  if "error" in info:
395
398
  print(f"❌ Error: {info['error']}")
396
399
  print()
397
400
  continue
398
-
401
+
399
402
  # Windows Terminal availability
400
403
  windows_info = info.get("windows_info", {})
401
404
  wt_available = windows_info.get("wt_available", False)
402
405
  print(f"Windows Terminal: {'✅ Available' if wt_available else '❌ Not Available'}")
403
-
406
+
404
407
  # Version info
405
408
  wt_version = info.get("wt_version", {})
406
409
  if wt_version.get("success"):
407
410
  print(f"Version: {wt_version.get('version', 'Unknown')}")
408
-
411
+
409
412
  # Current processes
410
413
  wt_processes = info.get("wt_processes", {})
411
414
  if wt_processes.get("success"):
412
415
  processes_output = wt_processes.get("processes", "")
413
416
  if processes_output.strip():
414
- print(f"Active processes: Found")
417
+ print("Active processes: Found")
415
418
  else:
416
- print(f"Active processes: None")
417
-
419
+ print("Active processes: None")
420
+
418
421
  # Session info
419
422
  session_name = info.get("session_name", "Unknown")
420
423
  tab_count = info.get("tab_count", 0)
421
424
  print(f"Managed session: {session_name} ({tab_count} tabs)")
422
-
425
+
423
426
  print()
424
-
427
+
425
428
  print("=" * 80)
426
429
 
427
430
 
@@ -437,47 +440,47 @@ if __name__ == "__main__":
437
440
  "📝Logs": ("C:/logs", "Get-Content app.log -Wait"),
438
441
  }
439
442
  }
440
-
443
+
441
444
  try:
442
445
  # Create the remote manager
443
446
  manager = WTSessionManager(sample_machines, session_name_prefix="RemoteJobs")
444
447
  print(f"✅ Remote manager created with {len(manager.managers)} remote sessions")
445
-
448
+
446
449
  # Show SSH commands
447
450
  print("\n📎 SSH commands to connect to all machines:")
448
451
  ssh_commands = manager.ssh_to_all_machines()
449
452
  print(ssh_commands)
450
-
453
+
451
454
  # Show current status
452
455
  print("\n🔍 Current status:")
453
456
  manager.print_status_report()
454
-
457
+
455
458
  # Show remote overview
456
459
  print("\n🌐 Remote machines overview:")
457
460
  manager.print_remote_overview()
458
-
461
+
459
462
  # Demonstrate save/load
460
463
  print("\n💾 Demonstrating save/load...")
461
464
  session_id = manager.save()
462
465
  print(f"✅ Saved session: {session_id}")
463
-
466
+
464
467
  # List saved sessions
465
468
  saved_sessions = WTSessionManager.list_saved_sessions()
466
469
  print(f"📋 Saved sessions: {saved_sessions}")
467
-
470
+
468
471
  # Load and verify
469
472
  loaded_manager = WTSessionManager.load(session_id)
470
473
  print(f"✅ Loaded session with {len(loaded_manager.managers)} remote sessions")
471
-
474
+
472
475
  # Show how to start sessions
473
476
  print("\n▶️ To start all sessions, run:")
474
477
  print("manager.start_all_sessions()")
475
-
478
+
476
479
  # Show how to start monitoring (commented out to prevent infinite loop in demo)
477
480
  print("\n⏰ To start monitoring, run:")
478
481
  print("manager.run_monitoring_routine(wait_ms=60000) # 60 seconds")
479
-
482
+
480
483
  except Exception as e:
481
484
  print(f"❌ Error: {e}")
482
485
  import traceback
483
- traceback.print_exc()
486
+ traceback.print_exc()