machineconfig 1.96__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 (164) 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 +27 -0
  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 -11
  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 +4 -0
  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.96.dist-info β†’ machineconfig-2.0.dist-info}/METADATA +13 -8
  161. {machineconfig-1.96.dist-info β†’ machineconfig-2.0.dist-info}/RECORD +163 -144
  162. machineconfig/cluster/self_ssh.py +0 -57
  163. {machineconfig-1.96.dist-info β†’ machineconfig-2.0.dist-info}/WHEEL +0 -0
  164. {machineconfig-1.96.dist-info β†’ machineconfig-2.0.dist-info}/top_level.txt +0 -0
@@ -17,11 +17,11 @@ TMP_SERIALIZATION_DIR = Path.home().joinpath("tmp_results", "session_manager", "
17
17
 
18
18
  class WTLocalManager:
19
19
  """Manages multiple local Windows Terminal sessions and monitors their tabs and processes."""
20
-
20
+
21
21
  def __init__(self, session2wt_tabs: Dict[str, Dict[str, tuple[str, str]]], session_name_prefix: str = "LocalWTMgr"):
22
22
  """
23
23
  Initialize the local Windows Terminal manager.
24
-
24
+
25
25
  Args:
26
26
  session2wt_tabs: Dict mapping session names to their tab configs
27
27
  Format: {session_name: {tab_name: (cwd, command), ...}, ...}
@@ -30,14 +30,14 @@ class WTLocalManager:
30
30
  self.session_name_prefix = session_name_prefix
31
31
  self.session2wt_tabs = session2wt_tabs # Store the original config
32
32
  self.managers: List[WTLayoutGenerator] = []
33
-
33
+
34
34
  # Create a WTLayoutGenerator for each session
35
35
  for session_name, tab_config in session2wt_tabs.items():
36
36
  manager = WTLayoutGenerator()
37
37
  full_session_name = f"{self.session_name_prefix}_{session_name}"
38
38
  manager.create_wt_layout(tab_config=tab_config, session_name=full_session_name)
39
39
  self.managers.append(manager)
40
-
40
+
41
41
  logger.info(f"Initialized WTLocalManager with {len(self.managers)} sessions")
42
42
 
43
43
  def get_all_session_names(self) -> List[str]:
@@ -51,20 +51,20 @@ class WTLocalManager:
51
51
  session_name = manager.session_name or "unknown"
52
52
  try:
53
53
  script_path = manager.script_path
54
-
54
+
55
55
  if not script_path:
56
56
  results[session_name] = {
57
57
  "success": False,
58
58
  "error": "No script file path available"
59
59
  }
60
60
  continue
61
-
61
+
62
62
  # Execute the PowerShell script to start Windows Terminal
63
63
  cmd = f"powershell -ExecutionPolicy Bypass -File \"{script_path}\""
64
-
64
+
65
65
  logger.info(f"Starting session '{session_name}' with script: {script_path}")
66
66
  result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30)
67
-
67
+
68
68
  if result.returncode == 0:
69
69
  results[session_name] = {
70
70
  "success": True,
@@ -77,14 +77,14 @@ class WTLocalManager:
77
77
  "error": result.stderr or result.stdout
78
78
  }
79
79
  logger.error(f"❌ Failed to start session '{session_name}': {result.stderr}")
80
-
80
+
81
81
  except Exception as e:
82
82
  results[session_name] = {
83
83
  "success": False,
84
84
  "error": str(e)
85
85
  }
86
86
  logger.error(f"❌ Exception starting session '{session_name}': {e}")
87
-
87
+
88
88
  return results
89
89
 
90
90
  def kill_all_sessions(self) -> Dict[str, Any]:
@@ -95,30 +95,30 @@ class WTLocalManager:
95
95
  try:
96
96
  # Kill all Windows Terminal processes (Windows Terminal doesn't have session-specific killing)
97
97
  cmd = "powershell -Command \"Get-Process -Name 'WindowsTerminal' -ErrorAction SilentlyContinue | Stop-Process -Force\""
98
-
98
+
99
99
  logger.info(f"Killing Windows Terminal processes for session '{session_name}'")
100
100
  result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=10)
101
-
101
+
102
102
  results[session_name] = {
103
103
  "success": result.returncode == 0,
104
104
  "message": "Windows Terminal processes killed" if result.returncode == 0 else result.stderr
105
105
  }
106
-
106
+
107
107
  except Exception as e:
108
108
  results[session_name] = {
109
109
  "success": False,
110
110
  "error": str(e)
111
111
  }
112
-
112
+
113
113
  return results
114
114
 
115
115
  def attach_to_session(self, session_name: Optional[str] = None) -> str:
116
116
  """
117
117
  Generate command to attach to a specific session or list attachment commands for all.
118
-
118
+
119
119
  Args:
120
120
  session_name: Specific session to attach to, or None for all sessions
121
-
121
+
122
122
  Returns:
123
123
  Command string to attach to session(s)
124
124
  """
@@ -140,20 +140,20 @@ class WTLocalManager:
140
140
  def check_all_sessions_status(self) -> Dict[str, Dict[str, Any]]:
141
141
  """Check the status of all sessions and their commands."""
142
142
  status_report = {}
143
-
143
+
144
144
  for manager in self.managers:
145
145
  session_name = manager.session_name or "default"
146
-
146
+
147
147
  # Get session status
148
148
  session_status = WTLayoutGenerator.check_wt_session_status(session_name)
149
-
149
+
150
150
  # Get commands status for this session
151
151
  commands_status = manager.check_all_commands_status()
152
-
152
+
153
153
  # Calculate summary for this session
154
154
  running_count = sum(1 for status in commands_status.values() if status.get("running", False))
155
155
  total_count = len(commands_status)
156
-
156
+
157
157
  status_report[session_name] = {
158
158
  "session_status": session_status,
159
159
  "commands_status": commands_status,
@@ -164,21 +164,21 @@ class WTLocalManager:
164
164
  "session_healthy": session_status.get("session_exists", False)
165
165
  }
166
166
  }
167
-
167
+
168
168
  return status_report
169
169
 
170
170
  def get_global_summary(self) -> Dict[str, Any]:
171
171
  """Get a global summary across all sessions."""
172
172
  all_status = self.check_all_sessions_status()
173
-
173
+
174
174
  total_sessions = len(all_status)
175
- healthy_sessions = sum(1 for status in all_status.values()
175
+ healthy_sessions = sum(1 for status in all_status.values()
176
176
  if status["summary"]["session_healthy"])
177
- total_commands = sum(status["summary"]["total_commands"]
177
+ total_commands = sum(status["summary"]["total_commands"]
178
178
  for status in all_status.values())
179
- total_running = sum(status["summary"]["running_commands"]
179
+ total_running = sum(status["summary"]["running_commands"]
180
180
  for status in all_status.values())
181
-
181
+
182
182
  return {
183
183
  "total_sessions": total_sessions,
184
184
  "healthy_sessions": healthy_sessions,
@@ -194,11 +194,11 @@ class WTLocalManager:
194
194
  """Print a comprehensive status report for all sessions."""
195
195
  all_status = self.check_all_sessions_status()
196
196
  global_summary = self.get_global_summary()
197
-
197
+
198
198
  print("=" * 80)
199
199
  print("πŸ–₯️ WINDOWS TERMINAL LOCAL MANAGER STATUS REPORT")
200
200
  print("=" * 80)
201
-
201
+
202
202
  # Global summary
203
203
  print("🌐 GLOBAL SUMMARY:")
204
204
  print(f" Total sessions: {global_summary['total_sessions']}")
@@ -207,16 +207,16 @@ class WTLocalManager:
207
207
  print(f" Running commands: {global_summary['running_commands']}")
208
208
  print(f" All healthy: {'βœ…' if global_summary['all_sessions_healthy'] else '❌'}")
209
209
  print()
210
-
210
+
211
211
  # Per-session details
212
212
  for session_name, status in all_status.items():
213
213
  session_status = status["session_status"]
214
214
  commands_status = status["commands_status"]
215
215
  summary = status["summary"]
216
-
216
+
217
217
  print(f"πŸͺŸ SESSION: {session_name}")
218
218
  print("-" * 60)
219
-
219
+
220
220
  # Session health
221
221
  if session_status.get("wt_running", False):
222
222
  if session_status.get("session_exists", False):
@@ -229,7 +229,7 @@ class WTLocalManager:
229
229
  print("⚠️ Windows Terminal is running but no session windows found")
230
230
  else:
231
231
  print(f"❌ Windows Terminal session issue: {session_status.get('error', 'Unknown error')}")
232
-
232
+
233
233
  # Commands in this session
234
234
  print(f" Commands ({summary['running_commands']}/{summary['total_commands']} running):")
235
235
  for tab_name, cmd_status in commands_status.items():
@@ -238,29 +238,29 @@ class WTLocalManager:
238
238
  if len(cmd_status.get("command", "")) > 50:
239
239
  cmd_text += "..."
240
240
  print(f" {status_icon} {tab_name}: {cmd_text}")
241
-
241
+
242
242
  if cmd_status.get("processes"):
243
243
  for proc in cmd_status["processes"][:2]: # Show first 2 processes
244
244
  print(f" └─ PID {proc['pid']}: {proc['name']}")
245
245
  print()
246
-
246
+
247
247
  print("=" * 80)
248
248
 
249
249
  def run_monitoring_routine(self, wait_ms: int = 30000) -> None:
250
250
  """
251
251
  Run a continuous monitoring routine that checks status periodically.
252
-
252
+
253
253
  Args:
254
254
  wait_ms: How long to wait between checks in milliseconds (default: 30000ms = 30s)
255
255
  """
256
256
  def routine(scheduler: Scheduler):
257
257
  print(f"\n⏰ Monitoring cycle {scheduler.cycle} at {datetime.now()}")
258
258
  print("-" * 50)
259
-
259
+
260
260
  if scheduler.cycle % 2 == 0:
261
261
  # Detailed status check every other cycle
262
262
  all_status = self.check_all_sessions_status()
263
-
263
+
264
264
  # Create DataFrame-like data for easier viewing
265
265
  status_data = []
266
266
  for session_name, status in all_status.items():
@@ -272,7 +272,7 @@ class WTLocalManager:
272
272
  "command": cmd_status.get("command", "Unknown")[:50] + "..." if len(cmd_status.get("command", "")) > 50 else cmd_status.get("command", ""),
273
273
  "processes": len(cmd_status.get("processes", []))
274
274
  })
275
-
275
+
276
276
  if status_data:
277
277
  # Format data as table
278
278
  headers = ["session", "tab", "running", "command", "processes"]
@@ -283,7 +283,7 @@ class WTLocalManager:
283
283
  for row in status_data:
284
284
  values = [str(row.get(h, ""))[:15] for h in headers]
285
285
  print(" | ".join(f"{v:<15}" for v in values))
286
-
286
+
287
287
  # Check if all sessions have stopped
288
288
  running_count = sum(1 for row in status_data if row.get("running", False))
289
289
  if running_count == 0:
@@ -296,25 +296,25 @@ class WTLocalManager:
296
296
  # Quick summary check
297
297
  global_summary = self.get_global_summary()
298
298
  print(f"πŸ“Š Quick Summary: {global_summary['running_commands']}/{global_summary['total_commands']} commands running across {global_summary['healthy_sessions']}/{global_summary['total_sessions']} sessions")
299
-
299
+
300
300
  logger.info(f"Starting monitoring routine with {wait_ms}ms intervals")
301
- sched = Scheduler(routine=routine, wait_ms=wait_ms)
301
+ sched = Scheduler(routine=routine, wait_ms=wait_ms, logger=logger)
302
302
  sched.run(max_cycles=None)
303
303
 
304
304
  def save(self, session_id: Optional[str] = None) -> str:
305
305
  """Save the manager state to disk."""
306
306
  if session_id is None:
307
307
  session_id = str(uuid.uuid4())[:8]
308
-
308
+
309
309
  # Create session directory
310
310
  session_dir = TMP_SERIALIZATION_DIR / session_id
311
311
  session_dir.mkdir(parents=True, exist_ok=True)
312
-
312
+
313
313
  # Save the session2wt_tabs configuration
314
314
  config_file = session_dir / "session2wt_tabs.json"
315
- with open(config_file, 'w', encoding='utf-8') as f:
316
- json.dump(self.session2wt_tabs, f, indent=2, ensure_ascii=False)
317
-
315
+ text = json.dumps(self.session2wt_tabs, indent=2, ensure_ascii=False)
316
+ config_file.write_text(text, encoding="utf-8")
317
+
318
318
  # Save metadata
319
319
  metadata = {
320
320
  "session_name_prefix": self.session_name_prefix,
@@ -324,13 +324,13 @@ class WTLocalManager:
324
324
  "manager_type": "WTLocalManager"
325
325
  }
326
326
  metadata_file = session_dir / "metadata.json"
327
- with open(metadata_file, 'w', encoding='utf-8') as f:
328
- json.dump(metadata, f, indent=2, ensure_ascii=False)
329
-
327
+ text = json.dumps(metadata, indent=2, ensure_ascii=False)
328
+ metadata_file.write_text(text, encoding="utf-8")
329
+
330
330
  # Save each manager's state
331
331
  managers_dir = session_dir / "managers"
332
332
  managers_dir.mkdir(exist_ok=True)
333
-
333
+
334
334
  for i, manager in enumerate(self.managers):
335
335
  manager_data = {
336
336
  "session_name": manager.session_name,
@@ -338,9 +338,9 @@ class WTLocalManager:
338
338
  "script_path": manager.script_path
339
339
  }
340
340
  manager_file = managers_dir / f"manager_{i}_{manager.session_name}.json"
341
- with open(manager_file, 'w', encoding='utf-8') as f:
342
- json.dump(manager_data, f, indent=2, ensure_ascii=False)
343
-
341
+ text = json.dumps(manager_data, indent=2, ensure_ascii=False)
342
+ manager_file.write_text(text, encoding="utf-8")
343
+
344
344
  logger.info(f"βœ… Saved WTLocalManager session to: {session_dir}")
345
345
  return session_id
346
346
 
@@ -348,18 +348,18 @@ class WTLocalManager:
348
348
  def load(cls, session_id: str) -> 'WTLocalManager':
349
349
  """Load a saved manager state from disk."""
350
350
  session_dir = TMP_SERIALIZATION_DIR / session_id
351
-
351
+
352
352
  if not session_dir.exists():
353
353
  raise FileNotFoundError(f"Session directory not found: {session_dir}")
354
-
354
+
355
355
  # Load configuration
356
356
  config_file = session_dir / "session2wt_tabs.json"
357
357
  if not config_file.exists():
358
358
  raise FileNotFoundError(f"Configuration file not found: {config_file}")
359
-
359
+
360
360
  with open(config_file, 'r', encoding='utf-8') as f:
361
361
  session2wt_tabs = json.load(f)
362
-
362
+
363
363
  # Load metadata
364
364
  metadata_file = session_dir / "metadata.json"
365
365
  session_name_prefix = "LocalWTMgr" # default fallback
@@ -367,32 +367,32 @@ class WTLocalManager:
367
367
  with open(metadata_file, 'r', encoding='utf-8') as f:
368
368
  metadata = json.load(f)
369
369
  session_name_prefix = metadata.get("session_name_prefix", "LocalWTMgr")
370
-
370
+
371
371
  # Create new instance
372
372
  instance = cls(session2wt_tabs=session2wt_tabs, session_name_prefix=session_name_prefix)
373
-
373
+
374
374
  # Load saved manager states
375
375
  managers_dir = session_dir / "managers"
376
376
  if managers_dir.exists():
377
377
  instance.managers = []
378
378
  manager_files = sorted(managers_dir.glob("manager_*.json"))
379
-
379
+
380
380
  for manager_file in manager_files:
381
381
  try:
382
382
  with open(manager_file, 'r', encoding='utf-8') as f:
383
383
  manager_data = json.load(f)
384
-
384
+
385
385
  # Recreate the manager
386
386
  manager = WTLayoutGenerator()
387
387
  manager.session_name = manager_data["session_name"]
388
388
  manager.tab_config = manager_data["tab_config"]
389
389
  manager.script_path = manager_data["script_path"]
390
-
390
+
391
391
  instance.managers.append(manager)
392
-
392
+
393
393
  except Exception as e:
394
394
  logger.warning(f"Failed to load manager from {manager_file}: {e}")
395
-
395
+
396
396
  logger.info(f"βœ… Loaded WTLocalManager session from: {session_dir}")
397
397
  return instance
398
398
 
@@ -401,23 +401,23 @@ class WTLocalManager:
401
401
  """List all saved session IDs."""
402
402
  if not TMP_SERIALIZATION_DIR.exists():
403
403
  return []
404
-
404
+
405
405
  sessions = []
406
406
  for item in TMP_SERIALIZATION_DIR.iterdir():
407
407
  if item.is_dir() and (item / "metadata.json").exists():
408
408
  sessions.append(item.name)
409
-
409
+
410
410
  return sorted(sessions)
411
411
 
412
412
  @staticmethod
413
413
  def delete_session(session_id: str) -> bool:
414
414
  """Delete a saved session."""
415
415
  session_dir = TMP_SERIALIZATION_DIR / session_id
416
-
416
+
417
417
  if not session_dir.exists():
418
418
  logger.warning(f"Session directory not found: {session_dir}")
419
419
  return False
420
-
420
+
421
421
  try:
422
422
  import shutil
423
423
  shutil.rmtree(session_dir)
@@ -430,33 +430,33 @@ class WTLocalManager:
430
430
  def list_active_sessions(self) -> List[Dict[str, Any]]:
431
431
  """List currently active Windows Terminal sessions managed by this instance."""
432
432
  active_sessions = []
433
-
433
+
434
434
  try:
435
435
  # Get all running Windows Terminal processes
436
436
  result = subprocess.run(
437
- ['powershell', '-Command',
437
+ ['powershell', '-Command',
438
438
  'Get-Process -Name "WindowsTerminal" -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, StartTime, MainWindowTitle | ConvertTo-Json -Depth 2'],
439
439
  capture_output=True,
440
440
  text=True,
441
441
  timeout=10
442
442
  )
443
-
443
+
444
444
  if result.returncode == 0 and result.stdout.strip():
445
445
  import json
446
446
  all_processes = json.loads(result.stdout.strip())
447
447
  if not isinstance(all_processes, list):
448
448
  all_processes = [all_processes]
449
-
449
+
450
450
  # Filter to only our managed sessions
451
451
  for manager in self.managers:
452
452
  session_name = manager.session_name
453
453
  session_windows = []
454
-
454
+
455
455
  for proc in all_processes:
456
456
  window_title = proc.get("MainWindowTitle", "")
457
457
  if session_name in window_title or not window_title:
458
458
  session_windows.append(proc)
459
-
459
+
460
460
  active_sessions.append({
461
461
  "session_name": session_name,
462
462
  "is_active": len(session_windows) > 0,
@@ -464,29 +464,29 @@ class WTLocalManager:
464
464
  "tabs": list(manager.tab_config.keys()),
465
465
  "windows": session_windows
466
466
  })
467
-
467
+
468
468
  except Exception as e:
469
469
  logger.error(f"Error listing active sessions: {e}")
470
-
470
+
471
471
  return active_sessions
472
472
 
473
473
  def get_wt_overview(self) -> Dict[str, Any]:
474
474
  """Get overview of all Windows Terminal windows and processes."""
475
475
  try:
476
476
  result = subprocess.run(
477
- ['powershell', '-Command',
477
+ ['powershell', '-Command',
478
478
  'Get-Process -Name "WindowsTerminal" -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, StartTime, MainWindowTitle, CPU | ConvertTo-Json -Depth 2'],
479
479
  capture_output=True,
480
480
  text=True,
481
481
  timeout=10
482
482
  )
483
-
483
+
484
484
  if result.returncode == 0 and result.stdout.strip():
485
485
  import json
486
486
  processes = json.loads(result.stdout.strip())
487
487
  if not isinstance(processes, list):
488
488
  processes = [processes]
489
-
489
+
490
490
  return {
491
491
  "success": True,
492
492
  "total_windows": len(processes),
@@ -528,23 +528,23 @@ if __name__ == "__main__":
528
528
  "πŸ“ˆMetrics": ("~", "Get-Counter \"\\Processor(_Total)\\% Processor Time\" -SampleInterval 2 -MaxSamples 30")
529
529
  }
530
530
  }
531
-
531
+
532
532
  try:
533
533
  # Create the local manager
534
534
  manager = WTLocalManager(sample_sessions, session_name_prefix="DevEnv")
535
535
  print(f"βœ… Local manager created with {len(manager.managers)} sessions")
536
-
536
+
537
537
  # Show session names
538
538
  print(f"πŸ“‹ Sessions: {manager.get_all_session_names()}")
539
-
539
+
540
540
  # Print attachment commands (without actually starting)
541
541
  print("\nπŸ“Ž Attachment commands:")
542
542
  print(manager.attach_to_session())
543
-
543
+
544
544
  # Show current status
545
545
  print("\nπŸ” Current status:")
546
546
  manager.print_status_report()
547
-
547
+
548
548
  # Show Windows Terminal overview
549
549
  print("\nπŸ–₯️ Windows Terminal Overview:")
550
550
  overview = manager.get_wt_overview()
@@ -553,25 +553,25 @@ if __name__ == "__main__":
553
553
  print(f" Managed sessions: {overview['managed_sessions']}")
554
554
  else:
555
555
  print(f" Error: {overview.get('error', 'Unknown')}")
556
-
556
+
557
557
  # Demonstrate save/load
558
558
  print("\nπŸ’Ύ Demonstrating save/load...")
559
559
  session_id = manager.save()
560
560
  print(f"βœ… Saved session: {session_id}")
561
-
561
+
562
562
  # List saved sessions
563
563
  saved_sessions = WTLocalManager.list_saved_sessions()
564
564
  print(f"πŸ“‹ Saved sessions: {saved_sessions}")
565
-
565
+
566
566
  # Load and verify
567
567
  loaded_manager = WTLocalManager.load(session_id)
568
568
  print(f"βœ… Loaded session with {len(loaded_manager.managers)} sessions")
569
-
569
+
570
570
  # Show how to start monitoring (commented out to prevent infinite loop in demo)
571
571
  print("\n⏰ To start monitoring, run:")
572
572
  print("manager.run_monitoring_routine(wait_ms=30000) # 30 seconds")
573
-
573
+
574
574
  except Exception as e:
575
575
  print(f"❌ Error: {e}")
576
576
  import traceback
577
- traceback.print_exc()
577
+ traceback.print_exc()