machineconfig 1.97__py3-none-any.whl → 2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of machineconfig might be problematic. Click here for more details.

Files changed (268) hide show
  1. machineconfig/cluster/cloud_manager.py +22 -29
  2. machineconfig/cluster/data_transfer.py +2 -3
  3. machineconfig/cluster/distribute.py +0 -2
  4. machineconfig/cluster/file_manager.py +4 -5
  5. machineconfig/cluster/job_params.py +1 -4
  6. machineconfig/cluster/loader_runner.py +8 -11
  7. machineconfig/cluster/remote_machine.py +4 -5
  8. machineconfig/cluster/script_execution.py +2 -2
  9. machineconfig/cluster/script_notify_upon_completion.py +0 -1
  10. machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +4 -6
  11. machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -1
  12. machineconfig/cluster/sessions_managers/enhanced_command_runner.py +35 -75
  13. machineconfig/cluster/sessions_managers/wt_local.py +113 -185
  14. machineconfig/cluster/sessions_managers/wt_local_manager.py +127 -197
  15. machineconfig/cluster/sessions_managers/wt_remote.py +60 -67
  16. machineconfig/cluster/sessions_managers/wt_remote_manager.py +110 -149
  17. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +61 -64
  18. machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +72 -172
  19. machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +27 -60
  20. machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +58 -137
  21. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +46 -74
  22. machineconfig/cluster/sessions_managers/zellij_local.py +91 -147
  23. machineconfig/cluster/sessions_managers/zellij_local_manager.py +165 -190
  24. machineconfig/cluster/sessions_managers/zellij_remote.py +51 -58
  25. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +40 -46
  26. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +19 -17
  27. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +30 -31
  28. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +64 -134
  29. machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +7 -11
  30. machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +27 -55
  31. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +14 -13
  32. machineconfig/cluster/templates/cli_click.py +0 -1
  33. machineconfig/cluster/templates/cli_gooey.py +0 -2
  34. machineconfig/cluster/templates/cli_trogon.py +0 -1
  35. machineconfig/cluster/templates/run_cloud.py +0 -1
  36. machineconfig/cluster/templates/run_cluster.py +0 -1
  37. machineconfig/cluster/templates/run_remote.py +0 -1
  38. machineconfig/cluster/templates/utils.py +27 -11
  39. machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
  40. machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
  41. machineconfig/jobs/python/check_installations.py +9 -9
  42. machineconfig/jobs/python/create_bootable_media.py +0 -2
  43. machineconfig/jobs/python/python_cargo_build_share.py +2 -2
  44. machineconfig/jobs/python/python_ve_symlink.py +9 -11
  45. machineconfig/jobs/python/tasks.py +0 -1
  46. machineconfig/jobs/python/vscode/api.py +5 -5
  47. machineconfig/jobs/python/vscode/link_ve.py +20 -21
  48. machineconfig/jobs/python/vscode/select_interpreter.py +28 -29
  49. machineconfig/jobs/python/vscode/sync_code.py +14 -18
  50. machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  51. machineconfig/jobs/python_custom_installers/archive/ngrok.py +15 -15
  52. machineconfig/jobs/python_custom_installers/dev/aider.py +10 -18
  53. machineconfig/jobs/python_custom_installers/dev/alacritty.py +12 -21
  54. machineconfig/jobs/python_custom_installers/dev/brave.py +13 -22
  55. machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +13 -20
  56. machineconfig/jobs/python_custom_installers/dev/code.py +17 -24
  57. machineconfig/jobs/python_custom_installers/dev/cursor.py +10 -21
  58. machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +12 -11
  59. machineconfig/jobs/python_custom_installers/dev/espanso.py +19 -23
  60. machineconfig/jobs/python_custom_installers/dev/goes.py +9 -16
  61. machineconfig/jobs/python_custom_installers/dev/lvim.py +13 -21
  62. machineconfig/jobs/python_custom_installers/dev/nerdfont.py +15 -22
  63. machineconfig/jobs/python_custom_installers/dev/redis.py +15 -23
  64. machineconfig/jobs/python_custom_installers/dev/wezterm.py +15 -22
  65. machineconfig/jobs/python_custom_installers/dev/winget.py +32 -50
  66. machineconfig/jobs/python_custom_installers/docker.py +15 -24
  67. machineconfig/jobs/python_custom_installers/gh.py +18 -26
  68. machineconfig/jobs/python_custom_installers/hx.py +33 -17
  69. machineconfig/jobs/python_custom_installers/warp-cli.py +15 -23
  70. machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  71. machineconfig/jobs/python_generic_installers/config.json +412 -389
  72. machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
  73. machineconfig/jobs/python_windows_installers/dev/config.json +1 -1
  74. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -1
  75. machineconfig/jobs/windows/msc/cli_agents.bat +0 -0
  76. machineconfig/jobs/windows/msc/cli_agents.ps1 +0 -0
  77. machineconfig/jobs/windows/start_terminal.ps1 +1 -1
  78. machineconfig/logger.py +50 -0
  79. machineconfig/profile/create.py +50 -36
  80. machineconfig/profile/create_hardlinks.py +33 -26
  81. machineconfig/profile/shell.py +87 -60
  82. machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  83. machineconfig/scripts/cloud/init.sh +2 -2
  84. machineconfig/scripts/linux/checkout_versions +1 -1
  85. machineconfig/scripts/linux/choose_wezterm_theme +1 -1
  86. machineconfig/scripts/linux/cloud_copy +1 -1
  87. machineconfig/scripts/linux/cloud_manager +1 -1
  88. machineconfig/scripts/linux/cloud_mount +1 -1
  89. machineconfig/scripts/linux/cloud_repo_sync +1 -1
  90. machineconfig/scripts/linux/cloud_sync +1 -1
  91. machineconfig/scripts/linux/croshell +1 -1
  92. machineconfig/scripts/linux/devops +3 -5
  93. machineconfig/scripts/linux/fire +2 -1
  94. machineconfig/scripts/linux/fire_agents +3 -3
  95. machineconfig/scripts/linux/ftpx +1 -1
  96. machineconfig/scripts/linux/gh_models +1 -1
  97. machineconfig/scripts/linux/kill_process +1 -1
  98. machineconfig/scripts/linux/mcinit +2 -2
  99. machineconfig/scripts/linux/repos +1 -1
  100. machineconfig/scripts/linux/scheduler +1 -1
  101. machineconfig/scripts/linux/start_slidev +1 -1
  102. machineconfig/scripts/linux/start_terminals +1 -1
  103. machineconfig/scripts/linux/url2md +1 -1
  104. machineconfig/scripts/linux/warp-cli.sh +122 -0
  105. machineconfig/scripts/linux/wifi_conn +1 -1
  106. machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
  107. machineconfig/scripts/python/__pycache__/croshell.cpython-313.pyc +0 -0
  108. machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
  109. machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
  110. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
  111. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-313.pyc +0 -0
  112. machineconfig/scripts/python/ai/__init__.py +0 -0
  113. machineconfig/scripts/python/ai/__pycache__/__init__.cpython-313.pyc +0 -0
  114. machineconfig/scripts/python/ai/__pycache__/generate_files.cpython-313.pyc +0 -0
  115. machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-313.pyc +0 -0
  116. machineconfig/scripts/python/ai/chatmodes/Thinking-Beast-Mode.chatmode.md +337 -0
  117. machineconfig/scripts/python/ai/chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md +644 -0
  118. machineconfig/scripts/python/ai/chatmodes/deepResearch.chatmode.md +81 -0
  119. machineconfig/scripts/python/ai/configs/.gemini/settings.json +81 -0
  120. machineconfig/scripts/python/ai/generate_files.py +84 -0
  121. machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +45 -0
  122. machineconfig/scripts/python/ai/mcinit.py +107 -0
  123. machineconfig/scripts/python/ai/prompts/allLintersAndTypeCheckers.prompt.md +5 -0
  124. machineconfig/scripts/python/ai/prompts/research-report-skeleton.prompt.md +38 -0
  125. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +52 -0
  126. machineconfig/scripts/python/archive/tmate_conn.py +5 -5
  127. machineconfig/scripts/python/archive/tmate_start.py +3 -3
  128. machineconfig/scripts/python/choose_wezterm_theme.py +2 -2
  129. machineconfig/scripts/python/cloud_copy.py +20 -19
  130. machineconfig/scripts/python/cloud_mount.py +10 -8
  131. machineconfig/scripts/python/cloud_repo_sync.py +15 -15
  132. machineconfig/scripts/python/cloud_sync.py +1 -1
  133. machineconfig/scripts/python/croshell.py +18 -16
  134. machineconfig/scripts/python/devops.py +6 -6
  135. machineconfig/scripts/python/devops_add_identity.py +9 -7
  136. machineconfig/scripts/python/devops_add_ssh_key.py +19 -19
  137. machineconfig/scripts/python/devops_backup_retrieve.py +14 -14
  138. machineconfig/scripts/python/devops_devapps_install.py +3 -3
  139. machineconfig/scripts/python/devops_update_repos.py +141 -53
  140. machineconfig/scripts/python/dotfile.py +3 -3
  141. machineconfig/scripts/python/fire_agents.py +202 -41
  142. machineconfig/scripts/python/fire_jobs.py +20 -21
  143. machineconfig/scripts/python/ftpx.py +4 -3
  144. machineconfig/scripts/python/gh_models.py +94 -94
  145. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
  146. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
  147. machineconfig/scripts/python/helpers/cloud_helpers.py +3 -3
  148. machineconfig/scripts/python/helpers/helpers2.py +3 -3
  149. machineconfig/scripts/python/helpers/helpers4.py +8 -7
  150. machineconfig/scripts/python/helpers/helpers5.py +7 -7
  151. machineconfig/scripts/python/helpers/repo_sync_helpers.py +2 -2
  152. machineconfig/scripts/python/mount_nfs.py +4 -3
  153. machineconfig/scripts/python/mount_nw_drive.py +4 -4
  154. machineconfig/scripts/python/mount_ssh.py +4 -3
  155. machineconfig/scripts/python/repos.py +9 -9
  156. machineconfig/scripts/python/scheduler.py +1 -1
  157. machineconfig/scripts/python/start_slidev.py +9 -8
  158. machineconfig/scripts/python/start_terminals.py +1 -1
  159. machineconfig/scripts/python/viewer.py +40 -40
  160. machineconfig/scripts/python/wifi_conn.py +65 -66
  161. machineconfig/scripts/python/wsl_windows_transfer.py +2 -2
  162. machineconfig/scripts/windows/checkout_version.ps1 +1 -3
  163. machineconfig/scripts/windows/choose_wezterm_theme.ps1 +1 -3
  164. machineconfig/scripts/windows/cloud_copy.ps1 +2 -6
  165. machineconfig/scripts/windows/cloud_manager.ps1 +1 -1
  166. machineconfig/scripts/windows/cloud_repo_sync.ps1 +1 -2
  167. machineconfig/scripts/windows/cloud_sync.ps1 +2 -2
  168. machineconfig/scripts/windows/croshell.ps1 +2 -2
  169. machineconfig/scripts/windows/devops.ps1 +1 -4
  170. machineconfig/scripts/windows/dotfile.ps1 +1 -3
  171. machineconfig/scripts/windows/fire.ps1 +1 -1
  172. machineconfig/scripts/windows/ftpx.ps1 +2 -2
  173. machineconfig/scripts/windows/gpt.ps1 +1 -1
  174. machineconfig/scripts/windows/kill_process.ps1 +1 -2
  175. machineconfig/scripts/windows/mcinit.ps1 +2 -2
  176. machineconfig/scripts/windows/mount_nfs.ps1 +1 -1
  177. machineconfig/scripts/windows/mount_ssh.ps1 +1 -1
  178. machineconfig/scripts/windows/pomodoro.ps1 +1 -1
  179. machineconfig/scripts/windows/py2exe.ps1 +1 -3
  180. machineconfig/scripts/windows/repos.ps1 +1 -1
  181. machineconfig/scripts/windows/scheduler.ps1 +1 -1
  182. machineconfig/scripts/windows/snapshot.ps1 +2 -2
  183. machineconfig/scripts/windows/start_slidev.ps1 +1 -1
  184. machineconfig/scripts/windows/start_terminals.ps1 +1 -1
  185. machineconfig/scripts/windows/wifi_conn.ps1 +1 -1
  186. machineconfig/scripts/windows/wsl_windows_transfer.ps1 +1 -3
  187. machineconfig/settings/lf/linux/lfrc +1 -1
  188. machineconfig/settings/linters/.ruff.toml +2 -2
  189. machineconfig/settings/linters/.ruff_cache/.gitignore +2 -0
  190. machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +1 -0
  191. machineconfig/settings/lvim/windows/archive/config_additional.lua +1 -1
  192. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +71 -71
  193. machineconfig/settings/shells/wt/settings.json +8 -8
  194. machineconfig/settings/svim/linux/init.toml +1 -1
  195. machineconfig/settings/svim/windows/init.toml +1 -1
  196. machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -54
  197. machineconfig/setup_linux/web_shortcuts/interactive.sh +6 -6
  198. machineconfig/setup_linux/web_shortcuts/tmp.sh +2 -0
  199. machineconfig/setup_windows/web_shortcuts/all.ps1 +2 -2
  200. machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +1 -1
  201. machineconfig/setup_windows/web_shortcuts/croshell.ps1 +1 -1
  202. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +5 -5
  203. machineconfig/setup_windows/wt_and_pwsh/install_fonts.ps1 +51 -15
  204. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +75 -18
  205. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +52 -42
  206. machineconfig/utils/ai/browser_user_wrapper.py +5 -5
  207. machineconfig/utils/ai/generate_file_checklist.py +19 -22
  208. machineconfig/utils/ai/url2md.py +5 -3
  209. machineconfig/utils/cloud/onedrive/setup_oauth.py +5 -4
  210. machineconfig/utils/cloud/onedrive/transaction.py +192 -227
  211. machineconfig/utils/code.py +71 -43
  212. machineconfig/utils/installer.py +77 -85
  213. machineconfig/utils/installer_utils/installer_abc.py +29 -17
  214. machineconfig/utils/installer_utils/installer_class.py +188 -83
  215. machineconfig/utils/io_save.py +3 -15
  216. machineconfig/utils/links.py +22 -11
  217. machineconfig/utils/notifications.py +197 -0
  218. machineconfig/utils/options.py +38 -25
  219. machineconfig/utils/path.py +18 -6
  220. machineconfig/utils/path_reduced.py +637 -316
  221. machineconfig/utils/procs.py +69 -63
  222. machineconfig/utils/scheduling.py +11 -13
  223. machineconfig/utils/ssh.py +351 -0
  224. machineconfig/utils/terminal.py +225 -0
  225. machineconfig/utils/utils.py +13 -12
  226. machineconfig/utils/utils2.py +43 -10
  227. machineconfig/utils/utils5.py +242 -46
  228. machineconfig/utils/ve.py +11 -6
  229. {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/METADATA +15 -9
  230. {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/RECORD +232 -235
  231. machineconfig/cluster/self_ssh.py +0 -57
  232. machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
  233. machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
  234. machineconfig/jobs/python/archive/python_tools.txt +0 -12
  235. machineconfig/jobs/python/vscode/__pycache__/select_interpreter.cpython-311.pyc +0 -0
  236. machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  237. machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  238. machineconfig/jobs/python_generic_installers/update.py +0 -3
  239. machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
  240. machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
  241. machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
  242. machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
  243. machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  244. machineconfig/scripts/linux/activate_ve +0 -87
  245. machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
  246. machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
  247. machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
  248. machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
  249. machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
  250. machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
  251. machineconfig/scripts/python/__pycache__/devops_backup_retrieve.cpython-311.pyc +0 -0
  252. machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
  253. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
  254. machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
  255. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
  256. machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
  257. machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
  258. machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
  259. machineconfig/scripts/python/ai/init.py +0 -56
  260. machineconfig/scripts/python/ai/rules/python/dev.md +0 -31
  261. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
  262. machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
  263. machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
  264. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
  265. machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
  266. machineconfig/scripts/windows/activate_ve.ps1 +0 -54
  267. {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/WHEEL +0 -0
  268. {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@
3
3
  Process monitoring and status checking utilities for Windows Terminal commands.
4
4
  Adapted from zellij process monitor but focused on Windows processes.
5
5
  """
6
+
6
7
  import json
7
8
  import logging
8
9
  import subprocess
@@ -14,153 +15,105 @@ logger = logging.getLogger(__name__)
14
15
 
15
16
  class WTProcessMonitor:
16
17
  """Handles process status checking and verification on local and remote Windows machines."""
17
-
18
+
18
19
  def __init__(self, remote_executor: Optional[WTRemoteExecutor] = None):
19
20
  self.remote_executor = remote_executor
20
21
  self.is_local = remote_executor is None
21
-
22
+
22
23
  @property
23
24
  def location_name(self) -> str:
24
25
  """Get the location name for status reporting."""
25
26
  return "local" if self.is_local else (self.remote_executor.remote_name if self.remote_executor else "unknown")
26
-
27
+
27
28
  def _run_command(self, command: str, timeout: int = 30) -> subprocess.CompletedProcess[str]:
28
29
  """Run command either locally or remotely."""
29
30
  if self.is_local:
30
- return subprocess.run(
31
- ["powershell", "-Command", command],
32
- capture_output=True,
33
- text=True,
34
- timeout=timeout
35
- )
31
+ return subprocess.run(["powershell", "-Command", command], capture_output=True, text=True, timeout=timeout)
36
32
  else:
37
33
  if self.remote_executor is None:
38
34
  raise ValueError("Remote executor is None but is_local is False")
39
35
  return self.remote_executor.run_command(command, timeout)
40
-
41
- def check_command_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]],
42
- use_verification: bool = True) -> Dict[str, Any]:
36
+
37
+ def check_command_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]], use_verification: bool = True) -> Dict[str, Any]:
43
38
  """Check command status with optional process verification."""
44
39
  if tab_name not in tab_config:
45
- return {
46
- "status": "unknown",
47
- "error": f"Tab '{tab_name}' not found in tracked configuration",
48
- "running": False,
49
- "pid": None,
50
- "command": None,
51
- "location": self.location_name
52
- }
53
-
40
+ return {"status": "unknown", "error": f"Tab '{tab_name}' not found in tracked configuration", "running": False, "pid": None, "command": None, "location": self.location_name}
41
+
54
42
  # Use the verified method by default for more accurate results
55
43
  if use_verification:
56
44
  return self.get_verified_process_status(tab_name, tab_config)
57
-
45
+
58
46
  return self._basic_process_check(tab_name, tab_config)
59
-
47
+
60
48
  def _basic_process_check(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
61
49
  """Basic process checking without verification."""
62
50
  _, command = tab_config[tab_name]
63
-
51
+
64
52
  try:
65
53
  check_script = self._create_process_check_script(command)
66
54
  result = self._run_command(check_script, timeout=15)
67
-
55
+
68
56
  if result.returncode == 0:
69
57
  try:
70
58
  # Parse PowerShell output (JSON format)
71
- output_lines = [line.strip() for line in result.stdout.strip().split('\n') if line.strip()]
59
+ output_lines = [line.strip() for line in result.stdout.strip().split("\n") if line.strip()]
72
60
  matching_processes = []
73
-
61
+
74
62
  for line in output_lines:
75
- if line.startswith('{') and line.endswith('}'):
63
+ if line.startswith("{") and line.endswith("}"):
76
64
  try:
77
65
  proc_info = json.loads(line)
78
66
  matching_processes.append(proc_info)
79
67
  except json.JSONDecodeError:
80
68
  continue
81
-
69
+
82
70
  if matching_processes:
83
- return {
84
- "status": "running",
85
- "running": True,
86
- "processes": matching_processes,
87
- "command": command,
88
- "tab_name": tab_name,
89
- "location": self.location_name
90
- }
71
+ return {"status": "running", "running": True, "processes": matching_processes, "command": command, "tab_name": tab_name, "location": self.location_name}
91
72
  else:
92
- return {
93
- "status": "not_running",
94
- "running": False,
95
- "processes": [],
96
- "command": command,
97
- "tab_name": tab_name,
98
- "location": self.location_name
99
- }
73
+ return {"status": "not_running", "running": False, "processes": [], "command": command, "tab_name": tab_name, "location": self.location_name}
100
74
  except Exception as e:
101
75
  logger.error(f"Failed to parse process check output: {e}")
102
- return {
103
- "status": "error",
104
- "error": f"Failed to parse output: {e}",
105
- "running": False,
106
- "command": command,
107
- "tab_name": tab_name,
108
- "location": self.location_name
109
- }
76
+ return {"status": "error", "error": f"Failed to parse output: {e}", "running": False, "command": command, "tab_name": tab_name, "location": self.location_name}
110
77
  else:
111
- return {
112
- "status": "error",
113
- "error": f"Command failed: {result.stderr}",
114
- "running": False,
115
- "command": command,
116
- "tab_name": tab_name,
117
- "location": self.location_name
118
- }
119
-
78
+ return {"status": "error", "error": f"Command failed: {result.stderr}", "running": False, "command": command, "tab_name": tab_name, "location": self.location_name}
79
+
120
80
  except Exception as e:
121
81
  logger.error(f"Error checking command status for tab '{tab_name}': {e}")
122
- return {
123
- "status": "error",
124
- "error": str(e),
125
- "running": False,
126
- "command": command,
127
- "tab_name": tab_name,
128
- "location": self.location_name
129
- }
130
-
82
+ return {"status": "error", "error": str(e), "running": False, "command": command, "tab_name": tab_name, "location": self.location_name}
83
+
131
84
  def _create_process_check_script(self, command: str) -> str:
132
85
  """Create PowerShell script for checking processes."""
133
86
  # Escape command for PowerShell
134
87
  escaped_command = command.replace("'", "''").replace('"', '""')
135
88
  cmd_parts = [part for part in command.split() if len(part) > 2]
136
- primary_cmd = cmd_parts[0] if cmd_parts else ''
137
-
89
+ primary_cmd = cmd_parts[0] if cmd_parts else ""
90
+
138
91
  return f"""
139
92
  $targetCommand = '{escaped_command}'
140
- $cmdParts = @({', '.join([f"'{part}'" for part in cmd_parts])})
93
+ $cmdParts = @({", ".join([f"'{part}'" for part in cmd_parts])})
141
94
  $primaryCmd = '{primary_cmd}'
142
95
  $currentPid = $PID
143
96
 
144
97
  Get-Process | ForEach-Object {{
145
98
  try {{
146
99
  if ($_.Id -eq $currentPid) {{ return }}
147
-
100
+
148
101
  $cmdline = ""
149
102
  try {{
150
103
  $cmdline = (Get-WmiObject Win32_Process -Filter "ProcessId = $($_.Id)").CommandLine
151
104
  }} catch {{
152
105
  $cmdline = $_.ProcessName
153
106
  }}
154
-
107
+
155
108
  if ($cmdline -and $cmdline -ne "") {{
156
109
  if ($cmdline -like "*PowerShell*" -and $cmdline -like "*Get-Process*") {{ return }}
157
-
110
+
158
111
  $matchesPrimary = $cmdline -like "*$primaryCmd*" -and $primaryCmd -ne "powershell"
159
112
  $matchCount = 0
160
113
  foreach ($part in $cmdParts[1..($cmdParts.Length-1)]) {{
161
114
  if ($cmdline -like "*$part*") {{ $matchCount++ }}
162
115
  }}
163
-
116
+
164
117
  if ($matchesPrimary -and $matchCount -ge 2) {{
165
118
  $procInfo = @{{
166
119
  "pid" = $_.Id
@@ -178,38 +131,32 @@ Get-Process | ForEach-Object {{
178
131
  }}
179
132
  }}
180
133
  """
181
-
134
+
182
135
  def force_fresh_process_check(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
183
136
  """Force a fresh process check with additional validation."""
184
137
  if tab_name not in tab_config:
185
- return {
186
- "status": "unknown",
187
- "error": f"Tab '{tab_name}' not found in tracked configuration",
188
- "running": False,
189
- "command": None,
190
- "location": self.location_name
191
- }
192
-
138
+ return {"status": "unknown", "error": f"Tab '{tab_name}' not found in tracked configuration", "running": False, "command": None, "location": self.location_name}
139
+
193
140
  _, command = tab_config[tab_name]
194
-
141
+
195
142
  try:
196
143
  # Get timestamp for freshness validation
197
144
  timestamp_cmd = "Get-Date -UFormat %s"
198
145
  timestamp_result = self._run_command(timestamp_cmd, timeout=5)
199
146
  check_timestamp = timestamp_result.stdout.strip() if timestamp_result.returncode == 0 else "unknown"
200
-
147
+
201
148
  check_script = self._create_fresh_check_script(command)
202
149
  result = self._run_command(check_script, timeout=15)
203
-
150
+
204
151
  if result.returncode == 0:
205
152
  try:
206
153
  # Parse the output to extract JSON
207
- output_lines = [line.strip() for line in result.stdout.strip().split('\n') if line.strip()]
154
+ output_lines = [line.strip() for line in result.stdout.strip().split("\n") if line.strip()]
208
155
  for line in output_lines:
209
- if line.startswith('{') and '"processes"' in line:
156
+ if line.startswith("{") and '"processes"' in line:
210
157
  check_result = json.loads(line)
211
158
  matching_processes = check_result.get("processes", [])
212
-
159
+
213
160
  return {
214
161
  "status": "running" if matching_processes else "not_running",
215
162
  "running": bool(matching_processes),
@@ -218,62 +165,32 @@ Get-Process | ForEach-Object {{
218
165
  "tab_name": tab_name,
219
166
  "location": self.location_name,
220
167
  "check_timestamp": check_timestamp,
221
- "method": "force_fresh_check"
168
+ "method": "force_fresh_check",
222
169
  }
223
-
170
+
224
171
  # Fallback if no JSON found
225
- return {
226
- "status": "not_running",
227
- "running": False,
228
- "processes": [],
229
- "command": command,
230
- "tab_name": tab_name,
231
- "location": self.location_name,
232
- "raw_output": result.stdout
233
- }
172
+ return {"status": "not_running", "running": False, "processes": [], "command": command, "tab_name": tab_name, "location": self.location_name, "raw_output": result.stdout}
234
173
  except json.JSONDecodeError as e:
235
174
  logger.error(f"Failed to parse fresh check output: {e}")
236
- return {
237
- "status": "error",
238
- "error": f"Failed to parse output: {e}",
239
- "running": False,
240
- "command": command,
241
- "tab_name": tab_name,
242
- "location": self.location_name,
243
- "raw_output": result.stdout
244
- }
175
+ return {"status": "error", "error": f"Failed to parse output: {e}", "running": False, "command": command, "tab_name": tab_name, "location": self.location_name, "raw_output": result.stdout}
245
176
  else:
246
- return {
247
- "status": "error",
248
- "error": f"Command failed: {result.stderr}",
249
- "running": False,
250
- "command": command,
251
- "tab_name": tab_name,
252
- "location": self.location_name
253
- }
254
-
177
+ return {"status": "error", "error": f"Command failed: {result.stderr}", "running": False, "command": command, "tab_name": tab_name, "location": self.location_name}
178
+
255
179
  except Exception as e:
256
180
  logger.error(f"Error in fresh process check for tab '{tab_name}': {e}")
257
- return {
258
- "status": "error",
259
- "error": str(e),
260
- "running": False,
261
- "command": command,
262
- "tab_name": tab_name,
263
- "location": self.location_name
264
- }
265
-
181
+ return {"status": "error", "error": str(e), "running": False, "command": command, "tab_name": tab_name, "location": self.location_name}
182
+
266
183
  def _create_fresh_check_script(self, command: str) -> str:
267
184
  """Create enhanced PowerShell process checking script with freshness validation."""
268
185
  escaped_command = command.replace("'", "''").replace('"', '""')
269
186
  cmd_parts = [part for part in command.split() if len(part) > 2]
270
- primary_cmd = cmd_parts[0] if cmd_parts else ''
271
-
187
+ primary_cmd = cmd_parts[0] if cmd_parts else ""
188
+
272
189
  return f"""
273
190
  Start-Sleep -Milliseconds 100
274
191
 
275
192
  $targetCommand = '{escaped_command}'
276
- $cmdParts = @({', '.join([f"'{part}'" for part in cmd_parts])})
193
+ $cmdParts = @({", ".join([f"'{part}'" for part in cmd_parts])})
277
194
  $primaryCmd = '{primary_cmd}'
278
195
  $currentPid = $PID
279
196
  $checkTime = Get-Date
@@ -282,30 +199,30 @@ $matchingProcesses = @()
282
199
  Get-Process | ForEach-Object {{
283
200
  try {{
284
201
  if ($_.Id -eq $currentPid) {{ return }}
285
-
202
+
286
203
  $cmdline = ""
287
204
  try {{
288
205
  $cmdline = (Get-WmiObject Win32_Process -Filter "ProcessId = $($_.Id)").CommandLine
289
206
  }} catch {{
290
207
  $cmdline = $_.ProcessName
291
208
  }}
292
-
209
+
293
210
  if ($cmdline -and $cmdline -ne "") {{
294
211
  # Skip our own checking processes
295
212
  if ($cmdline -like "*Get-Process*" -or $cmdline -like "*force_fresh_check*") {{ return }}
296
-
213
+
297
214
  # Skip processes that started very recently (likely our own scripts)
298
215
  if ($_.StartTime -and ($checkTime - $_.StartTime).TotalSeconds -lt 5) {{ return }}
299
-
216
+
300
217
  $matchesPrimary = $cmdline -like "*$primaryCmd*" -and $primaryCmd -ne "powershell"
301
218
  $matchCount = 0
302
219
  foreach ($part in $cmdParts[1..($cmdParts.Length-1)]) {{
303
220
  if ($cmdline -like "*$part*") {{ $matchCount++ }}
304
221
  }}
305
-
222
+
306
223
  if ($matchesPrimary -and $matchCount -ge 2) {{
307
224
  $isDirectCommand = -not ($cmdline -like "*-Command*" -or $cmdline -like "*Get-Process*")
308
-
225
+
309
226
  if ($isDirectCommand -or ($targetCommand -in $cmdline -and $cmdline -notlike "*powershell -Command*")) {{
310
227
  $procInfo = @{{
311
228
  "pid" = $_.Id
@@ -334,21 +251,21 @@ $result = @{{
334
251
 
335
252
  Write-Output $result
336
253
  """
337
-
254
+
338
255
  def verify_process_alive(self, pid: int) -> bool:
339
256
  """Verify if a process with given PID is actually alive."""
340
257
  try:
341
258
  verify_cmd = f"Get-Process -Id {pid} -ErrorAction SilentlyContinue | Select-Object -First 1"
342
259
  result = self._run_command(verify_cmd, timeout=5)
343
-
260
+
344
261
  return result.returncode == 0 and result.stdout.strip() != ""
345
262
  except Exception:
346
263
  return False
347
-
264
+
348
265
  def get_verified_process_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
349
266
  """Get process status with additional verification that processes are actually alive."""
350
267
  status = self.force_fresh_process_check(tab_name, tab_config)
351
-
268
+
352
269
  if status.get("running") and status.get("processes"):
353
270
  verified_processes = []
354
271
  for proc in status["processes"]:
@@ -359,60 +276,43 @@ Write-Output $result
359
276
  else:
360
277
  proc["verified_alive"] = False
361
278
  logger.warning(f"Process PID {pid} found in process list but not actually alive")
362
-
279
+
363
280
  status["processes"] = verified_processes
364
281
  status["running"] = bool(verified_processes)
365
282
  status["status"] = "running" if verified_processes else "not_running"
366
283
  status["verification_method"] = "get_process_check"
367
-
284
+
368
285
  return status
369
-
286
+
370
287
  def check_all_commands_status(self, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Dict[str, Any]]:
371
288
  """Check status of all commands in the tab configuration."""
372
289
  if not tab_config:
373
290
  logger.warning("No tab configuration provided.")
374
291
  return {}
375
-
292
+
376
293
  status_report = {}
377
294
  for tab_name in tab_config:
378
295
  status_report[tab_name] = self.check_command_status(tab_name, tab_config)
379
296
  return status_report
380
-
297
+
381
298
  def get_windows_terminal_windows(self) -> Dict[str, Any]:
382
299
  """Get information about currently running Windows Terminal windows."""
383
300
  try:
384
301
  wt_info_cmd = """
385
- Get-Process -Name 'WindowsTerminal' -ErrorAction SilentlyContinue |
302
+ Get-Process -Name 'WindowsTerminal' -ErrorAction SilentlyContinue |
386
303
  Select-Object Id, ProcessName, StartTime, @{Name="WindowTitle";Expression={(Get-Process -Id $_.Id).MainWindowTitle}} |
387
304
  ConvertTo-Json -Depth 2
388
305
  """
389
306
  result = self._run_command(wt_info_cmd, timeout=15)
390
-
307
+
391
308
  if result.returncode == 0 and result.stdout.strip():
392
309
  try:
393
310
  wt_processes = json.loads(result.stdout)
394
- return {
395
- "success": True,
396
- "windows": wt_processes if isinstance(wt_processes, list) else [wt_processes],
397
- "location": self.location_name
398
- }
311
+ return {"success": True, "windows": wt_processes if isinstance(wt_processes, list) else [wt_processes], "location": self.location_name}
399
312
  except json.JSONDecodeError:
400
- return {
401
- "success": False,
402
- "error": "Failed to parse Windows Terminal process info",
403
- "location": self.location_name
404
- }
313
+ return {"success": False, "error": "Failed to parse Windows Terminal process info", "location": self.location_name}
405
314
  else:
406
- return {
407
- "success": True,
408
- "windows": [],
409
- "message": "No Windows Terminal processes found",
410
- "location": self.location_name
411
- }
315
+ return {"success": True, "windows": [], "message": "No Windows Terminal processes found", "location": self.location_name}
412
316
  except Exception as e:
413
317
  logger.error(f"Failed to get Windows Terminal windows: {e}")
414
- return {
415
- "success": False,
416
- "error": str(e),
417
- "location": self.location_name
418
- }
318
+ return {"success": False, "error": str(e), "location": self.location_name}
@@ -3,6 +3,7 @@
3
3
  Remote command execution utilities for SSH operations with Windows Terminal.
4
4
  Adapted from zellij remote executor but focused on Windows Terminal commands.
5
5
  """
6
+
6
7
  import subprocess
7
8
  import logging
8
9
  from typing import Dict, Any, Optional, List
@@ -12,26 +13,21 @@ logger = logging.getLogger(__name__)
12
13
 
13
14
  class WTRemoteExecutor:
14
15
  """Handles SSH command execution on remote Windows machines with Windows Terminal."""
15
-
16
+
16
17
  def __init__(self, remote_name: str):
17
18
  self.remote_name = remote_name
18
-
19
+
19
20
  def run_command(self, command: str, timeout: int = 30, shell: str = "powershell") -> subprocess.CompletedProcess[str]:
20
21
  """Execute a command on the remote machine via SSH."""
21
22
  # For Windows Terminal on remote machines, we need to use PowerShell or CMD
22
23
  if shell == "powershell":
23
24
  # Wrap command in PowerShell invocation if needed
24
25
  if not command.startswith("powershell"):
25
- command = f"powershell -Command \"{command}\""
26
-
26
+ command = f'powershell -Command "{command}"'
27
+
27
28
  ssh_cmd = ["ssh", self.remote_name, command]
28
29
  try:
29
- result = subprocess.run(
30
- ssh_cmd,
31
- capture_output=True,
32
- text=True,
33
- timeout=timeout
34
- )
30
+ result = subprocess.run(ssh_cmd, capture_output=True, text=True, timeout=timeout)
35
31
  return result
36
32
  except subprocess.TimeoutExpired:
37
33
  logger.error(f"SSH command timed out after {timeout}s: {command}")
@@ -39,7 +35,7 @@ class WTRemoteExecutor:
39
35
  except Exception as e:
40
36
  logger.error(f"SSH command failed: {e}")
41
37
  raise
42
-
38
+
43
39
  def copy_file_to_remote(self, local_file: str, remote_path: str) -> Dict[str, Any]:
44
40
  """Copy a file to the remote machine using SCP."""
45
41
  scp_cmd = ["scp", local_file, f"{self.remote_name}:{remote_path}"]
@@ -54,7 +50,7 @@ class WTRemoteExecutor:
54
50
  except Exception as e:
55
51
  logger.error(f"SCP operation failed: {e}")
56
52
  return {"success": False, "error": str(e)}
57
-
53
+
58
54
  def create_remote_directory(self, remote_dir: str) -> bool:
59
55
  """Create a directory on the remote machine."""
60
56
  try:
@@ -64,7 +60,7 @@ class WTRemoteExecutor:
64
60
  except Exception as e:
65
61
  logger.error(f"Failed to create remote directory {remote_dir}: {e}")
66
62
  return False
67
-
63
+
68
64
  def start_wt_session_interactive(self, wt_command: str) -> None:
69
65
  """Start a Windows Terminal session interactively via SSH."""
70
66
  try:
@@ -75,7 +71,7 @@ class WTRemoteExecutor:
75
71
  except Exception as e:
76
72
  logger.error(f"Failed to start Windows Terminal session: {e}")
77
73
  raise
78
-
74
+
79
75
  def check_wt_available(self) -> bool:
80
76
  """Check if Windows Terminal is available on the remote machine."""
81
77
  try:
@@ -83,30 +79,21 @@ class WTRemoteExecutor:
83
79
  return result.returncode == 0
84
80
  except Exception:
85
81
  return False
86
-
82
+
87
83
  def get_remote_windows_info(self) -> Dict[str, Any]:
88
84
  """Get information about the remote Windows system."""
89
85
  try:
90
86
  # Get Windows version and terminal info
91
87
  version_cmd = "Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion"
92
88
  result = self.run_command(version_cmd, timeout=15)
93
-
89
+
94
90
  wt_available = self.check_wt_available()
95
-
96
- return {
97
- "windows_info": result.stdout if result.returncode == 0 else "Unknown",
98
- "wt_available": wt_available,
99
- "remote_name": self.remote_name
100
- }
91
+
92
+ return {"windows_info": result.stdout if result.returncode == 0 else "Unknown", "wt_available": wt_available, "remote_name": self.remote_name}
101
93
  except Exception as e:
102
94
  logger.error(f"Failed to get remote Windows info: {e}")
103
- return {
104
- "windows_info": "Error getting info",
105
- "wt_available": False,
106
- "remote_name": self.remote_name,
107
- "error": str(e)
108
- }
109
-
95
+ return {"windows_info": "Error getting info", "wt_available": False, "remote_name": self.remote_name, "error": str(e)}
96
+
110
97
  def run_wt_command(self, wt_command: str, detached: bool = True) -> subprocess.CompletedProcess[str]:
111
98
  """Run a Windows Terminal command on the remote machine."""
112
99
  try:
@@ -116,39 +103,27 @@ class WTRemoteExecutor:
116
103
  else:
117
104
  # Run in foreground
118
105
  full_command = f"wt {wt_command}"
119
-
106
+
120
107
  return self.run_command(full_command, timeout=30)
121
108
  except Exception as e:
122
109
  logger.error(f"Failed to run Windows Terminal command: {e}")
123
110
  raise
124
-
111
+
125
112
  def list_wt_processes(self) -> Dict[str, Any]:
126
113
  """List Windows Terminal processes on the remote machine."""
127
114
  try:
128
115
  # Get all WindowsTerminal.exe processes
129
116
  ps_command = "Get-Process -Name 'WindowsTerminal' -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, StartTime, CPU"
130
117
  result = self.run_command(ps_command, timeout=15)
131
-
118
+
132
119
  if result.returncode == 0:
133
- return {
134
- "success": True,
135
- "processes": result.stdout,
136
- "remote": self.remote_name
137
- }
120
+ return {"success": True, "processes": result.stdout, "remote": self.remote_name}
138
121
  else:
139
- return {
140
- "success": False,
141
- "error": result.stderr,
142
- "remote": self.remote_name
143
- }
122
+ return {"success": False, "error": result.stderr, "remote": self.remote_name}
144
123
  except Exception as e:
145
124
  logger.error(f"Failed to list Windows Terminal processes: {e}")
146
- return {
147
- "success": False,
148
- "error": str(e),
149
- "remote": self.remote_name
150
- }
151
-
125
+ return {"success": False, "error": str(e), "remote": self.remote_name}
126
+
152
127
  def kill_wt_processes(self, process_ids: Optional[List[Any]] = None) -> Dict[str, Any]:
153
128
  """Kill Windows Terminal processes on the remote machine."""
154
129
  try:
@@ -158,18 +133,10 @@ class WTRemoteExecutor:
158
133
  else:
159
134
  # Kill all Windows Terminal processes
160
135
  kill_cmd = "Get-Process -Name 'WindowsTerminal' -ErrorAction SilentlyContinue | Stop-Process -Force"
161
-
136
+
162
137
  result = self.run_command(kill_cmd, timeout=10)
163
-
164
- return {
165
- "success": result.returncode == 0,
166
- "message": "Processes killed" if result.returncode == 0 else result.stderr,
167
- "remote": self.remote_name
168
- }
138
+
139
+ return {"success": result.returncode == 0, "message": "Processes killed" if result.returncode == 0 else result.stderr, "remote": self.remote_name}
169
140
  except Exception as e:
170
141
  logger.error(f"Failed to kill Windows Terminal processes: {e}")
171
- return {
172
- "success": False,
173
- "error": str(e),
174
- "remote": self.remote_name
175
- }
142
+ return {"success": False, "error": str(e), "remote": self.remote_name}