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
@@ -15,25 +15,25 @@ logger = logging.getLogger(__name__)
15
15
 
16
16
  class WTLayoutGenerator:
17
17
  """Handles generation of Windows Terminal command strings for multi-tab layouts."""
18
-
18
+
19
19
  @staticmethod
20
20
  def generate_random_suffix(length: int = 8) -> str:
21
21
  """Generate a random string suffix for unique window names."""
22
22
  return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length))
23
-
23
+
24
24
  @staticmethod
25
25
  def parse_command(command: str) -> Tuple[str, List[str]]:
26
26
  """Parse a command string into command and arguments."""
27
27
  try:
28
28
  parts = shlex.split(command)
29
- if not parts:
29
+ if not parts:
30
30
  raise ValueError("Empty command provided")
31
31
  return parts[0], parts[1:] if len(parts) > 1 else []
32
32
  except ValueError as e:
33
33
  logger.error(f"Error parsing command '{command}': {e}")
34
34
  parts = command.split()
35
35
  return parts[0] if parts else "", parts[1:] if len(parts) > 1 else []
36
-
36
+
37
37
  @staticmethod
38
38
  def escape_for_wt(text: str) -> str:
39
39
  """Escape text for use in Windows Terminal commands."""
@@ -43,79 +43,79 @@ class WTLayoutGenerator:
43
43
  if ' ' in text or ';' in text or '&' in text or '|' in text:
44
44
  return f'"{text}"'
45
45
  return text
46
-
46
+
47
47
  @staticmethod
48
48
  def create_tab_command(tab_name: str, cwd: str, command: str, is_first_tab: bool = False) -> str:
49
49
  """Create a Windows Terminal tab command string."""
50
50
  cmd, args = WTLayoutGenerator.parse_command(command)
51
-
51
+
52
52
  # Convert paths to Windows format if needed
53
53
  if cwd.startswith('~/'):
54
54
  cwd = cwd.replace('~/', f"{Path.home()}/")
55
55
  elif cwd == '~':
56
56
  cwd = str(Path.home())
57
-
57
+
58
58
  # Build the wt command parts
59
59
  tab_parts = []
60
-
60
+
61
61
  if not is_first_tab:
62
62
  tab_parts.append("new-tab")
63
-
63
+
64
64
  # Add profile if specified (could be extended to support different shells)
65
65
  # tab_parts.extend(["-p", "\"Command Prompt\""]) # or "PowerShell", "WSL", etc.
66
-
66
+
67
67
  # Add starting directory
68
68
  tab_parts.extend(["-d", WTLayoutGenerator.escape_for_wt(cwd)])
69
-
69
+
70
70
  # Add tab title
71
71
  tab_parts.extend(["--title", WTLayoutGenerator.escape_for_wt(tab_name)])
72
-
72
+
73
73
  # Add the command to execute
74
74
  full_command = command if not args else f"{cmd} {' '.join(args)}"
75
75
  tab_parts.append(WTLayoutGenerator.escape_for_wt(full_command))
76
-
76
+
77
77
  return " ".join(tab_parts)
78
-
78
+
79
79
  @staticmethod
80
80
  def validate_tab_config(tab_config: Dict[str, Tuple[str, str]]) -> None:
81
81
  """Validate tab configuration format and content."""
82
- if not tab_config:
82
+ if not tab_config:
83
83
  raise ValueError("Tab configuration cannot be empty")
84
84
  for tab_name, (cwd, command) in tab_config.items():
85
- if not tab_name.strip():
85
+ if not tab_name.strip():
86
86
  raise ValueError(f"Invalid tab name: {tab_name}")
87
- if not command.strip():
87
+ if not command.strip():
88
88
  raise ValueError(f"Invalid command for tab '{tab_name}': {command}")
89
- if not cwd.strip():
89
+ if not cwd.strip():
90
90
  raise ValueError(f"Invalid cwd for tab '{tab_name}': {cwd}")
91
-
92
- def generate_wt_command(self, tab_config: Dict[str, Tuple[str, str]],
93
- window_name: str | None = None,
91
+
92
+ def generate_wt_command(self, tab_config: Dict[str, Tuple[str, str]],
93
+ window_name: str | None = None,
94
94
  maximized: bool = False,
95
95
  focus: bool = True) -> str:
96
96
  """Generate complete Windows Terminal command string."""
97
97
  self.validate_tab_config(tab_config)
98
-
98
+
99
99
  # Start building the wt command
100
100
  wt_parts = ["wt"]
101
-
101
+
102
102
  # Add window options
103
103
  if maximized:
104
104
  wt_parts.append("--maximized")
105
-
105
+
106
106
  if focus:
107
107
  wt_parts.append("--focus")
108
-
108
+
109
109
  if window_name:
110
110
  wt_parts.extend(["-w", WTLayoutGenerator.escape_for_wt(window_name)])
111
-
111
+
112
112
  # Add tabs
113
113
  tab_commands = []
114
114
  for i, (tab_name, (cwd, command)) in enumerate(tab_config.items()):
115
115
  is_first = i == 0
116
116
  tab_cmd = self.create_tab_command(tab_name, cwd, command, is_first)
117
117
  tab_commands.append(tab_cmd)
118
-
118
+
119
119
  # Join all parts with semicolons (Windows Terminal command separator)
120
120
  if tab_commands:
121
121
  if len(tab_commands) == 1:
@@ -126,65 +126,67 @@ class WTLayoutGenerator:
126
126
  wt_parts.append(tab_commands[0]) # First tab
127
127
  for tab_cmd in tab_commands[1:]:
128
128
  wt_parts.extend([";", tab_cmd])
129
-
129
+
130
130
  return " ".join(wt_parts)
131
-
132
- def create_wt_script(self, tab_config: Dict[str, Tuple[str, str]],
131
+
132
+ def create_wt_script(self, tab_config: Dict[str, Tuple[str, str]],
133
133
  output_dir: Path, session_name: str,
134
134
  window_name: str | None = None) -> str:
135
135
  """Create a Windows Terminal script file and return its absolute path."""
136
136
  self.validate_tab_config(tab_config)
137
-
137
+
138
138
  # Generate unique suffix for this script
139
139
  random_suffix = self.generate_random_suffix()
140
140
  wt_command = self.generate_wt_command(tab_config, window_name or session_name)
141
-
141
+
142
142
  try:
143
143
  # Create output directory if it doesn't exist
144
144
  output_dir.mkdir(parents=True, exist_ok=True)
145
-
145
+
146
146
  # Create both .bat and .ps1 versions for flexibility
147
147
  bat_file = output_dir / f"wt_layout_{session_name}_{random_suffix}.bat"
148
148
  ps1_file = output_dir / f"wt_layout_{session_name}_{random_suffix}.ps1"
149
-
149
+
150
150
  # Create batch file
151
- with open(bat_file, 'w', encoding='utf-8') as f:
152
- f.write(f"@echo off\n")
153
- f.write(f"REM Windows Terminal layout for {session_name}\n")
154
- f.write(f"{wt_command}\n")
155
-
151
+ text = f"""@echo off
152
+ REM Windows Terminal layout for {session_name}
153
+ {wt_command}
154
+ """
155
+ bat_file.write_text(text, encoding="utf-8")
156
+
156
157
  # Create PowerShell file (better for complex commands)
157
- with open(ps1_file, 'w', encoding='utf-8') as f:
158
- f.write(f"# Windows Terminal layout for {session_name}\n")
159
- f.write(f"# Generated on {random_suffix}\n")
160
- f.write(f"{wt_command}\n")
161
-
158
+ text = f"""# Windows Terminal layout for {session_name}
159
+ # Generated on {random_suffix}
160
+ {wt_command}
161
+ """
162
+ ps1_file.write_text(text, encoding="utf-8")
163
+
162
164
  logger.info(f"Windows Terminal script files created: {bat_file.absolute()}")
163
165
  return str(bat_file.absolute())
164
-
166
+
165
167
  except OSError as e:
166
168
  logger.error(f"Failed to create script file: {e}")
167
169
  raise
168
-
169
- def generate_split_pane_command(self, tab_config: Dict[str, Tuple[str, str]],
170
+
171
+ def generate_split_pane_command(self, tab_config: Dict[str, Tuple[str, str]],
170
172
  window_name: str | None = None) -> str:
171
173
  """Generate Windows Terminal command with split panes instead of separate tabs."""
172
174
  self.validate_tab_config(tab_config)
173
-
175
+
174
176
  wt_parts = ["wt"]
175
-
177
+
176
178
  if window_name:
177
179
  wt_parts.extend(["-w", WTLayoutGenerator.escape_for_wt(window_name)])
178
-
180
+
179
181
  # First pane (main tab)
180
182
  first_tab = list(tab_config.items())[0]
181
183
  tab_name, (cwd, command) = first_tab
182
-
184
+
183
185
  # Start with first tab
184
186
  wt_parts.extend(["-d", WTLayoutGenerator.escape_for_wt(cwd)])
185
187
  wt_parts.extend(["--title", WTLayoutGenerator.escape_for_wt(tab_name)])
186
188
  wt_parts.append(WTLayoutGenerator.escape_for_wt(command))
187
-
189
+
188
190
  # Add split panes for remaining tabs
189
191
  for tab_name, (cwd, command) in list(tab_config.items())[1:]:
190
192
  wt_parts.append(";")
@@ -192,5 +194,5 @@ class WTLayoutGenerator:
192
194
  wt_parts.extend(["-d", WTLayoutGenerator.escape_for_wt(cwd)])
193
195
  wt_parts.extend(["--title", WTLayoutGenerator.escape_for_wt(tab_name)])
194
196
  wt_parts.append(WTLayoutGenerator.escape_for_wt(command))
195
-
196
- return " ".join(wt_parts)
197
+
198
+ return " ".join(wt_parts)
@@ -14,16 +14,16 @@ logger = logging.getLogger(__name__)
14
14
 
15
15
  class WTProcessMonitor:
16
16
  """Handles process status checking and verification on local and remote Windows machines."""
17
-
17
+
18
18
  def __init__(self, remote_executor: Optional[WTRemoteExecutor] = None):
19
19
  self.remote_executor = remote_executor
20
20
  self.is_local = remote_executor is None
21
-
21
+
22
22
  @property
23
23
  def location_name(self) -> str:
24
24
  """Get the location name for status reporting."""
25
25
  return "local" if self.is_local else (self.remote_executor.remote_name if self.remote_executor else "unknown")
26
-
26
+
27
27
  def _run_command(self, command: str, timeout: int = 30) -> subprocess.CompletedProcess[str]:
28
28
  """Run command either locally or remotely."""
29
29
  if self.is_local:
@@ -37,8 +37,8 @@ class WTProcessMonitor:
37
37
  if self.remote_executor is None:
38
38
  raise ValueError("Remote executor is None but is_local is False")
39
39
  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]],
40
+
41
+ def check_command_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]],
42
42
  use_verification: bool = True) -> Dict[str, Any]:
43
43
  """Check command status with optional process verification."""
44
44
  if tab_name not in tab_config:
@@ -50,27 +50,27 @@ class WTProcessMonitor:
50
50
  "command": None,
51
51
  "location": self.location_name
52
52
  }
53
-
53
+
54
54
  # Use the verified method by default for more accurate results
55
55
  if use_verification:
56
56
  return self.get_verified_process_status(tab_name, tab_config)
57
-
57
+
58
58
  return self._basic_process_check(tab_name, tab_config)
59
-
59
+
60
60
  def _basic_process_check(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
61
61
  """Basic process checking without verification."""
62
62
  _, command = tab_config[tab_name]
63
-
63
+
64
64
  try:
65
65
  check_script = self._create_process_check_script(command)
66
66
  result = self._run_command(check_script, timeout=15)
67
-
67
+
68
68
  if result.returncode == 0:
69
69
  try:
70
70
  # Parse PowerShell output (JSON format)
71
71
  output_lines = [line.strip() for line in result.stdout.strip().split('\n') if line.strip()]
72
72
  matching_processes = []
73
-
73
+
74
74
  for line in output_lines:
75
75
  if line.startswith('{') and line.endswith('}'):
76
76
  try:
@@ -78,7 +78,7 @@ class WTProcessMonitor:
78
78
  matching_processes.append(proc_info)
79
79
  except json.JSONDecodeError:
80
80
  continue
81
-
81
+
82
82
  if matching_processes:
83
83
  return {
84
84
  "status": "running",
@@ -109,14 +109,14 @@ class WTProcessMonitor:
109
109
  }
110
110
  else:
111
111
  return {
112
- "status": "error",
112
+ "status": "error",
113
113
  "error": f"Command failed: {result.stderr}",
114
114
  "running": False,
115
115
  "command": command,
116
116
  "tab_name": tab_name,
117
117
  "location": self.location_name
118
118
  }
119
-
119
+
120
120
  except Exception as e:
121
121
  logger.error(f"Error checking command status for tab '{tab_name}': {e}")
122
122
  return {
@@ -127,14 +127,14 @@ class WTProcessMonitor:
127
127
  "tab_name": tab_name,
128
128
  "location": self.location_name
129
129
  }
130
-
130
+
131
131
  def _create_process_check_script(self, command: str) -> str:
132
132
  """Create PowerShell script for checking processes."""
133
133
  # Escape command for PowerShell
134
134
  escaped_command = command.replace("'", "''").replace('"', '""')
135
135
  cmd_parts = [part for part in command.split() if len(part) > 2]
136
136
  primary_cmd = cmd_parts[0] if cmd_parts else ''
137
-
137
+
138
138
  return f"""
139
139
  $targetCommand = '{escaped_command}'
140
140
  $cmdParts = @({', '.join([f"'{part}'" for part in cmd_parts])})
@@ -144,23 +144,23 @@ $currentPid = $PID
144
144
  Get-Process | ForEach-Object {{
145
145
  try {{
146
146
  if ($_.Id -eq $currentPid) {{ return }}
147
-
147
+
148
148
  $cmdline = ""
149
149
  try {{
150
150
  $cmdline = (Get-WmiObject Win32_Process -Filter "ProcessId = $($_.Id)").CommandLine
151
151
  }} catch {{
152
152
  $cmdline = $_.ProcessName
153
153
  }}
154
-
154
+
155
155
  if ($cmdline -and $cmdline -ne "") {{
156
156
  if ($cmdline -like "*PowerShell*" -and $cmdline -like "*Get-Process*") {{ return }}
157
-
157
+
158
158
  $matchesPrimary = $cmdline -like "*$primaryCmd*" -and $primaryCmd -ne "powershell"
159
159
  $matchCount = 0
160
160
  foreach ($part in $cmdParts[1..($cmdParts.Length-1)]) {{
161
161
  if ($cmdline -like "*$part*") {{ $matchCount++ }}
162
162
  }}
163
-
163
+
164
164
  if ($matchesPrimary -and $matchCount -ge 2) {{
165
165
  $procInfo = @{{
166
166
  "pid" = $_.Id
@@ -178,7 +178,7 @@ Get-Process | ForEach-Object {{
178
178
  }}
179
179
  }}
180
180
  """
181
-
181
+
182
182
  def force_fresh_process_check(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
183
183
  """Force a fresh process check with additional validation."""
184
184
  if tab_name not in tab_config:
@@ -189,18 +189,18 @@ Get-Process | ForEach-Object {{
189
189
  "command": None,
190
190
  "location": self.location_name
191
191
  }
192
-
192
+
193
193
  _, command = tab_config[tab_name]
194
-
194
+
195
195
  try:
196
196
  # Get timestamp for freshness validation
197
197
  timestamp_cmd = "Get-Date -UFormat %s"
198
198
  timestamp_result = self._run_command(timestamp_cmd, timeout=5)
199
199
  check_timestamp = timestamp_result.stdout.strip() if timestamp_result.returncode == 0 else "unknown"
200
-
200
+
201
201
  check_script = self._create_fresh_check_script(command)
202
202
  result = self._run_command(check_script, timeout=15)
203
-
203
+
204
204
  if result.returncode == 0:
205
205
  try:
206
206
  # Parse the output to extract JSON
@@ -209,7 +209,7 @@ Get-Process | ForEach-Object {{
209
209
  if line.startswith('{') and '"processes"' in line:
210
210
  check_result = json.loads(line)
211
211
  matching_processes = check_result.get("processes", [])
212
-
212
+
213
213
  return {
214
214
  "status": "running" if matching_processes else "not_running",
215
215
  "running": bool(matching_processes),
@@ -220,7 +220,7 @@ Get-Process | ForEach-Object {{
220
220
  "check_timestamp": check_timestamp,
221
221
  "method": "force_fresh_check"
222
222
  }
223
-
223
+
224
224
  # Fallback if no JSON found
225
225
  return {
226
226
  "status": "not_running",
@@ -244,14 +244,14 @@ Get-Process | ForEach-Object {{
244
244
  }
245
245
  else:
246
246
  return {
247
- "status": "error",
247
+ "status": "error",
248
248
  "error": f"Command failed: {result.stderr}",
249
249
  "running": False,
250
250
  "command": command,
251
251
  "tab_name": tab_name,
252
252
  "location": self.location_name
253
253
  }
254
-
254
+
255
255
  except Exception as e:
256
256
  logger.error(f"Error in fresh process check for tab '{tab_name}': {e}")
257
257
  return {
@@ -262,13 +262,13 @@ Get-Process | ForEach-Object {{
262
262
  "tab_name": tab_name,
263
263
  "location": self.location_name
264
264
  }
265
-
265
+
266
266
  def _create_fresh_check_script(self, command: str) -> str:
267
267
  """Create enhanced PowerShell process checking script with freshness validation."""
268
268
  escaped_command = command.replace("'", "''").replace('"', '""')
269
269
  cmd_parts = [part for part in command.split() if len(part) > 2]
270
270
  primary_cmd = cmd_parts[0] if cmd_parts else ''
271
-
271
+
272
272
  return f"""
273
273
  Start-Sleep -Milliseconds 100
274
274
 
@@ -282,30 +282,30 @@ $matchingProcesses = @()
282
282
  Get-Process | ForEach-Object {{
283
283
  try {{
284
284
  if ($_.Id -eq $currentPid) {{ return }}
285
-
285
+
286
286
  $cmdline = ""
287
287
  try {{
288
288
  $cmdline = (Get-WmiObject Win32_Process -Filter "ProcessId = $($_.Id)").CommandLine
289
289
  }} catch {{
290
290
  $cmdline = $_.ProcessName
291
291
  }}
292
-
292
+
293
293
  if ($cmdline -and $cmdline -ne "") {{
294
294
  # Skip our own checking processes
295
295
  if ($cmdline -like "*Get-Process*" -or $cmdline -like "*force_fresh_check*") {{ return }}
296
-
296
+
297
297
  # Skip processes that started very recently (likely our own scripts)
298
298
  if ($_.StartTime -and ($checkTime - $_.StartTime).TotalSeconds -lt 5) {{ return }}
299
-
299
+
300
300
  $matchesPrimary = $cmdline -like "*$primaryCmd*" -and $primaryCmd -ne "powershell"
301
301
  $matchCount = 0
302
302
  foreach ($part in $cmdParts[1..($cmdParts.Length-1)]) {{
303
303
  if ($cmdline -like "*$part*") {{ $matchCount++ }}
304
304
  }}
305
-
305
+
306
306
  if ($matchesPrimary -and $matchCount -ge 2) {{
307
307
  $isDirectCommand = -not ($cmdline -like "*-Command*" -or $cmdline -like "*Get-Process*")
308
-
308
+
309
309
  if ($isDirectCommand -or ($targetCommand -in $cmdline -and $cmdline -notlike "*powershell -Command*")) {{
310
310
  $procInfo = @{{
311
311
  "pid" = $_.Id
@@ -334,21 +334,21 @@ $result = @{{
334
334
 
335
335
  Write-Output $result
336
336
  """
337
-
337
+
338
338
  def verify_process_alive(self, pid: int) -> bool:
339
339
  """Verify if a process with given PID is actually alive."""
340
340
  try:
341
341
  verify_cmd = f"Get-Process -Id {pid} -ErrorAction SilentlyContinue | Select-Object -First 1"
342
342
  result = self._run_command(verify_cmd, timeout=5)
343
-
343
+
344
344
  return result.returncode == 0 and result.stdout.strip() != ""
345
345
  except Exception:
346
346
  return False
347
-
347
+
348
348
  def get_verified_process_status(self, tab_name: str, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Any]:
349
349
  """Get process status with additional verification that processes are actually alive."""
350
350
  status = self.force_fresh_process_check(tab_name, tab_config)
351
-
351
+
352
352
  if status.get("running") and status.get("processes"):
353
353
  verified_processes = []
354
354
  for proc in status["processes"]:
@@ -359,35 +359,35 @@ Write-Output $result
359
359
  else:
360
360
  proc["verified_alive"] = False
361
361
  logger.warning(f"Process PID {pid} found in process list but not actually alive")
362
-
362
+
363
363
  status["processes"] = verified_processes
364
364
  status["running"] = bool(verified_processes)
365
365
  status["status"] = "running" if verified_processes else "not_running"
366
366
  status["verification_method"] = "get_process_check"
367
-
367
+
368
368
  return status
369
-
369
+
370
370
  def check_all_commands_status(self, tab_config: Dict[str, Tuple[str, str]]) -> Dict[str, Dict[str, Any]]:
371
371
  """Check status of all commands in the tab configuration."""
372
372
  if not tab_config:
373
373
  logger.warning("No tab configuration provided.")
374
374
  return {}
375
-
375
+
376
376
  status_report = {}
377
377
  for tab_name in tab_config:
378
378
  status_report[tab_name] = self.check_command_status(tab_name, tab_config)
379
379
  return status_report
380
-
380
+
381
381
  def get_windows_terminal_windows(self) -> Dict[str, Any]:
382
382
  """Get information about currently running Windows Terminal windows."""
383
383
  try:
384
384
  wt_info_cmd = """
385
- Get-Process -Name 'WindowsTerminal' -ErrorAction SilentlyContinue |
385
+ Get-Process -Name 'WindowsTerminal' -ErrorAction SilentlyContinue |
386
386
  Select-Object Id, ProcessName, StartTime, @{Name="WindowTitle";Expression={(Get-Process -Id $_.Id).MainWindowTitle}} |
387
387
  ConvertTo-Json -Depth 2
388
388
  """
389
389
  result = self._run_command(wt_info_cmd, timeout=15)
390
-
390
+
391
391
  if result.returncode == 0 and result.stdout.strip():
392
392
  try:
393
393
  wt_processes = json.loads(result.stdout)
@@ -415,4 +415,4 @@ ConvertTo-Json -Depth 2
415
415
  "success": False,
416
416
  "error": str(e),
417
417
  "location": self.location_name
418
- }
418
+ }