machineconfig 3.0__py3-none-any.whl → 3.2__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.
- machineconfig/__init__.py +16 -17
- machineconfig/cluster/sessions_managers/enhanced_command_runner.py +6 -6
- machineconfig/cluster/sessions_managers/wt_local.py +7 -7
- machineconfig/cluster/sessions_managers/wt_local_manager.py +8 -8
- machineconfig/cluster/sessions_managers/wt_remote.py +8 -8
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +6 -6
- machineconfig/cluster/sessions_managers/zellij_local.py +156 -77
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +18 -15
- machineconfig/cluster/sessions_managers/zellij_remote.py +14 -61
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +15 -12
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +9 -3
- machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +2 -2
- machineconfig/cluster/sessions_managers/zellij_utils/monitoring_types.py +40 -67
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +19 -17
- machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +2 -2
- machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +1 -1
- machineconfig/jobs/python/python_ve_symlink.py +1 -1
- machineconfig/profile/create.py +8 -0
- machineconfig/scripts/linux/kill_process +1 -1
- machineconfig/scripts/python/ai/mcinit.py +1 -2
- machineconfig/scripts/python/cloud_mount.py +1 -1
- machineconfig/scripts/python/cloud_repo_sync.py +1 -0
- machineconfig/scripts/python/cloud_sync.py +1 -0
- machineconfig/scripts/python/croshell.py +1 -0
- machineconfig/scripts/python/devops.py +11 -1
- machineconfig/scripts/python/devops_add_identity.py +1 -0
- machineconfig/scripts/python/devops_add_ssh_key.py +1 -0
- machineconfig/scripts/python/devops_backup_retrieve.py +1 -0
- machineconfig/scripts/python/devops_devapps_install.py +5 -7
- machineconfig/scripts/python/devops_update_repos.py +21 -20
- machineconfig/scripts/python/fire_agents.py +21 -11
- machineconfig/scripts/python/fire_agents_help_launch.py +4 -3
- machineconfig/scripts/python/fire_agents_help_search.py +1 -2
- machineconfig/scripts/python/fire_agents_load_balancer.py +8 -10
- machineconfig/scripts/python/fire_jobs.py +1 -0
- machineconfig/scripts/python/helpers/cloud_helpers.py +1 -0
- machineconfig/scripts/python/mount_nfs.py +2 -0
- machineconfig/scripts/python/mount_nw_drive.py +1 -1
- machineconfig/scripts/python/mount_ssh.py +1 -0
- machineconfig/scripts/python/repos.py +0 -2
- machineconfig/scripts/python/repos_helper_record.py +43 -66
- machineconfig/scripts/python/repos_helper_update.py +3 -2
- machineconfig/scripts/python/start_slidev.py +1 -0
- machineconfig/scripts/python/start_terminals.py +1 -1
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +1 -0
- machineconfig/utils/code.py +0 -1
- machineconfig/utils/notifications.py +2 -2
- machineconfig/utils/procs.py +10 -15
- machineconfig/utils/schemas/fire_agents/fire_agents_input.py +9 -4
- machineconfig/utils/schemas/layouts/layout_types.py +2 -0
- machineconfig/utils/schemas/repos/repos_types.py +0 -3
- machineconfig/utils/ssh.py +9 -11
- machineconfig/utils/utils2.py +1 -2
- machineconfig/utils/ve.py +0 -1
- {machineconfig-3.0.dist-info → machineconfig-3.2.dist-info}/METADATA +1 -1
- {machineconfig-3.0.dist-info → machineconfig-3.2.dist-info}/RECORD +59 -59
- {machineconfig-3.0.dist-info → machineconfig-3.2.dist-info}/entry_points.txt +1 -0
- {machineconfig-3.0.dist-info → machineconfig-3.2.dist-info}/WHEEL +0 -0
- {machineconfig-3.0.dist-info → machineconfig-3.2.dist-info}/top_level.txt +0 -0
|
@@ -6,9 +6,10 @@ Process monitoring and status checking utilities for remote commands.
|
|
|
6
6
|
import json
|
|
7
7
|
import shlex
|
|
8
8
|
import logging
|
|
9
|
-
from typing import Dict
|
|
9
|
+
from typing import Dict
|
|
10
10
|
from machineconfig.cluster.sessions_managers.zellij_utils.remote_executor import RemoteExecutor
|
|
11
11
|
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
12
|
+
from machineconfig.cluster.sessions_managers.zellij_utils.monitoring_types import CommandStatus, ProcessInfo
|
|
12
13
|
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
14
15
|
|
|
@@ -19,7 +20,7 @@ class ProcessMonitor:
|
|
|
19
20
|
def __init__(self, remote_executor: RemoteExecutor):
|
|
20
21
|
self.remote_executor = remote_executor
|
|
21
22
|
|
|
22
|
-
def check_command_status(self, tab_name: str, layout_config: LayoutConfig, use_verification: bool
|
|
23
|
+
def check_command_status(self, tab_name: str, layout_config: LayoutConfig, use_verification: bool) -> CommandStatus:
|
|
23
24
|
"""Check command status with optional process verification."""
|
|
24
25
|
# Find the tab with the given name
|
|
25
26
|
tab_config = None
|
|
@@ -29,7 +30,7 @@ class ProcessMonitor:
|
|
|
29
30
|
break
|
|
30
31
|
|
|
31
32
|
if tab_config is None:
|
|
32
|
-
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "
|
|
33
|
+
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "command": "", "tab_name": tab_name, "processes": [], "remote": self.remote_executor.remote_name}
|
|
33
34
|
|
|
34
35
|
# Use the verified method by default for more accurate results
|
|
35
36
|
if use_verification:
|
|
@@ -37,7 +38,7 @@ class ProcessMonitor:
|
|
|
37
38
|
|
|
38
39
|
return self._basic_process_check(tab_name, layout_config)
|
|
39
40
|
|
|
40
|
-
def _basic_process_check(self, tab_name: str, layout_config: LayoutConfig) ->
|
|
41
|
+
def _basic_process_check(self, tab_name: str, layout_config: LayoutConfig) -> CommandStatus:
|
|
41
42
|
"""Basic process checking without verification."""
|
|
42
43
|
# Find the tab with the given name
|
|
43
44
|
tab_config = None
|
|
@@ -47,7 +48,7 @@ class ProcessMonitor:
|
|
|
47
48
|
break
|
|
48
49
|
|
|
49
50
|
if tab_config is None:
|
|
50
|
-
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "command":
|
|
51
|
+
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "command": "", "tab_name": tab_name, "processes": [], "remote": self.remote_executor.remote_name}
|
|
51
52
|
|
|
52
53
|
command = tab_config["command"]
|
|
53
54
|
|
|
@@ -66,13 +67,13 @@ class ProcessMonitor:
|
|
|
66
67
|
return {"status": "not_running", "running": False, "processes": [], "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
67
68
|
except json.JSONDecodeError as e:
|
|
68
69
|
logger.error(f"Failed to parse remote process check output: {e}")
|
|
69
|
-
return {"status": "error", "error": f"Failed to parse remote output: {e}", "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
70
|
+
return {"status": "error", "error": f"Failed to parse remote output: {e}", "running": False, "processes": [], "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
70
71
|
else:
|
|
71
|
-
return {"status": "error", "error": f"Remote command failed: {result.stderr}", "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
72
|
+
return {"status": "error", "error": f"Remote command failed: {result.stderr}", "running": False, "processes": [], "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
72
73
|
|
|
73
74
|
except Exception as e:
|
|
74
75
|
logger.error(f"Error checking command status for tab '{tab_name}': {e}")
|
|
75
|
-
return {"status": "error", "error": str(e), "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
76
|
+
return {"status": "error", "error": str(e), "running": False, "processes": [], "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
76
77
|
|
|
77
78
|
def _create_process_check_script(self, command: str) -> str:
|
|
78
79
|
"""Create Python script for checking processes on remote machine."""
|
|
@@ -124,7 +125,7 @@ if __name__ == "__main__":
|
|
|
124
125
|
print(json.dumps(processes))
|
|
125
126
|
"""
|
|
126
127
|
|
|
127
|
-
def force_fresh_process_check(self, tab_name: str, layout_config: LayoutConfig) ->
|
|
128
|
+
def force_fresh_process_check(self, tab_name: str, layout_config: LayoutConfig) -> CommandStatus:
|
|
128
129
|
"""Force a fresh process check with additional validation."""
|
|
129
130
|
# Find the tab with the given name
|
|
130
131
|
tab_config = None
|
|
@@ -134,7 +135,7 @@ if __name__ == "__main__":
|
|
|
134
135
|
break
|
|
135
136
|
|
|
136
137
|
if tab_config is None:
|
|
137
|
-
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "command":
|
|
138
|
+
return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "command": "", "tab_name": tab_name, "processes": [], "remote": self.remote_executor.remote_name}
|
|
138
139
|
|
|
139
140
|
command = tab_config["command"]
|
|
140
141
|
|
|
@@ -150,7 +151,8 @@ if __name__ == "__main__":
|
|
|
150
151
|
if result.returncode == 0:
|
|
151
152
|
try:
|
|
152
153
|
check_result = json.loads(result.stdout.strip())
|
|
153
|
-
|
|
154
|
+
raw_processes = check_result.get("processes", [])
|
|
155
|
+
matching_processes: list[ProcessInfo] = raw_processes # runtime JSON provides shape
|
|
154
156
|
|
|
155
157
|
return {
|
|
156
158
|
"status": "running" if matching_processes else "not_running",
|
|
@@ -164,13 +166,13 @@ if __name__ == "__main__":
|
|
|
164
166
|
}
|
|
165
167
|
except json.JSONDecodeError as e:
|
|
166
168
|
logger.error(f"Failed to parse fresh check output: {e}")
|
|
167
|
-
return {"status": "error", "error": f"Failed to parse output: {e}", "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name, "raw_output": result.stdout}
|
|
169
|
+
return {"status": "error", "error": f"Failed to parse output: {e}", "running": False, "processes": [], "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name, "raw_output": result.stdout}
|
|
168
170
|
else:
|
|
169
|
-
return {"status": "error", "error": f"Remote command failed: {result.stderr}", "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
171
|
+
return {"status": "error", "error": f"Remote command failed: {result.stderr}", "running": False, "processes": [], "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
170
172
|
|
|
171
173
|
except Exception as e:
|
|
172
174
|
logger.error(f"Error in fresh process check for tab '{tab_name}': {e}")
|
|
173
|
-
return {"status": "error", "error": str(e), "running": False, "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
175
|
+
return {"status": "error", "error": str(e), "running": False, "processes": [], "command": command, "tab_name": tab_name, "remote": self.remote_executor.remote_name}
|
|
174
176
|
|
|
175
177
|
def _create_fresh_check_script(self, command: str) -> str:
|
|
176
178
|
"""Create enhanced process checking script with freshness validation."""
|
|
@@ -255,7 +257,7 @@ if __name__ == "__main__":
|
|
|
255
257
|
except Exception:
|
|
256
258
|
return False
|
|
257
259
|
|
|
258
|
-
def get_verified_process_status(self, tab_name: str, layout_config: LayoutConfig) ->
|
|
260
|
+
def get_verified_process_status(self, tab_name: str, layout_config: LayoutConfig) -> CommandStatus:
|
|
259
261
|
"""Get process status with additional verification that processes are actually alive."""
|
|
260
262
|
status = self.force_fresh_process_check(tab_name, layout_config)
|
|
261
263
|
|
|
@@ -277,7 +279,7 @@ if __name__ == "__main__":
|
|
|
277
279
|
|
|
278
280
|
return status
|
|
279
281
|
|
|
280
|
-
def check_all_commands_status(self, layout_config: LayoutConfig) -> Dict[str,
|
|
282
|
+
def check_all_commands_status(self, layout_config: LayoutConfig) -> Dict[str, CommandStatus]:
|
|
281
283
|
"""Check status of all commands in the layout configuration."""
|
|
282
284
|
if not layout_config or not layout_config.get("layoutTabs"):
|
|
283
285
|
logger.warning("No layout configuration provided.")
|
|
@@ -286,5 +288,5 @@ if __name__ == "__main__":
|
|
|
286
288
|
status_report = {}
|
|
287
289
|
for tab in layout_config["layoutTabs"]:
|
|
288
290
|
tab_name = tab["tabName"]
|
|
289
|
-
status_report[tab_name] = self.check_command_status(tab_name, layout_config)
|
|
291
|
+
status_report[tab_name] = self.check_command_status(tab_name, layout_config, True)
|
|
290
292
|
return status_report
|
|
@@ -16,7 +16,7 @@ class RemoteExecutor:
|
|
|
16
16
|
def __init__(self, remote_name: str):
|
|
17
17
|
self.remote_name = remote_name
|
|
18
18
|
|
|
19
|
-
def run_command(self, command: str, timeout: int
|
|
19
|
+
def run_command(self, command: str, timeout: int) -> subprocess.CompletedProcess[str]:
|
|
20
20
|
"""Execute a command on the remote machine via SSH."""
|
|
21
21
|
ssh_cmd = ["ssh", self.remote_name, command]
|
|
22
22
|
try:
|
|
@@ -47,7 +47,7 @@ class RemoteExecutor:
|
|
|
47
47
|
def create_remote_directory(self, remote_dir: str) -> bool:
|
|
48
48
|
"""Create a directory on the remote machine."""
|
|
49
49
|
try:
|
|
50
|
-
result = self.run_command(f"mkdir -p {remote_dir}")
|
|
50
|
+
result = self.run_command(f"mkdir -p {remote_dir}", 30)
|
|
51
51
|
return result.returncode == 0
|
|
52
52
|
except Exception as e:
|
|
53
53
|
logger.error(f"Failed to create remote directory {remote_dir}: {e}")
|
|
@@ -57,7 +57,7 @@ class SessionManager:
|
|
|
57
57
|
except Exception as e:
|
|
58
58
|
return {"zellij_running": False, "error": str(e), "session_name": self.session_name, "remote": self.remote_executor.remote_name}
|
|
59
59
|
|
|
60
|
-
def start_zellij_session(self, layout_file_path: Optional[str]
|
|
60
|
+
def start_zellij_session(self, layout_file_path: Optional[str]) -> Dict[str, Any]:
|
|
61
61
|
"""Start a Zellij session on the remote machine with the generated layout."""
|
|
62
62
|
try:
|
|
63
63
|
if layout_file_path:
|
machineconfig/profile/create.py
CHANGED
|
@@ -3,6 +3,7 @@ This script Takes away all config files from the computer, place them in one dir
|
|
|
3
3
|
`dotfiles`, and create symlinks to those files from thier original locations.
|
|
4
4
|
|
|
5
5
|
"""
|
|
6
|
+
|
|
6
7
|
from rich.console import Console
|
|
7
8
|
|
|
8
9
|
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
@@ -21,10 +22,16 @@ from typing import Optional, Any, TypedDict
|
|
|
21
22
|
system = platform.system() # Linux or Windows
|
|
22
23
|
ERROR_LIST: list[Any] = [] # append to this after every exception captured.
|
|
23
24
|
SYSTEM = system.lower()
|
|
25
|
+
|
|
26
|
+
|
|
24
27
|
def get_other_systems(current_system: str) -> list[str]:
|
|
25
28
|
all_systems = ["linux", "windows", "darwin"]
|
|
26
29
|
return [s for s in all_systems if s != current_system.lower()]
|
|
30
|
+
|
|
31
|
+
|
|
27
32
|
OTHER_SYSTEMS = get_other_systems(SYSTEM)
|
|
33
|
+
|
|
34
|
+
|
|
28
35
|
class SymlinkMapper(TypedDict):
|
|
29
36
|
this: str
|
|
30
37
|
to_this: str
|
|
@@ -143,6 +150,7 @@ def apply_mapper(choice: Optional[str] = None):
|
|
|
143
150
|
def main(choice: Optional[str] = None):
|
|
144
151
|
console = Console()
|
|
145
152
|
print("\n")
|
|
153
|
+
|
|
146
154
|
console.rule("[bold blue]🔗 CREATING SYMLINKS 🔗")
|
|
147
155
|
apply_mapper(choice=choice)
|
|
148
156
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
uv run --python 3.13 --no-dev --project $HOME/code/machineconfig kill_process "$@"
|
|
2
|
+
uv run --python 3.13 --no-dev --project $HOME/code/machineconfig kill_process "$@"
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
from pathlib import Path
|
|
3
2
|
from machineconfig.utils.ve import get_repo_root
|
|
4
3
|
|
|
@@ -8,7 +7,6 @@ uv add --upgrade-package pytest --dev
|
|
|
8
7
|
"""
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
|
|
12
10
|
def add_ai_configs(repo_root: Path) -> None:
|
|
13
11
|
import machineconfig as mc
|
|
14
12
|
|
|
@@ -109,5 +107,6 @@ def main() -> None:
|
|
|
109
107
|
repo_root = Path.cwd()
|
|
110
108
|
add_ai_configs(repo_root=repo_root)
|
|
111
109
|
|
|
110
|
+
|
|
112
111
|
if __name__ == "__main__":
|
|
113
112
|
add_ai_configs(repo_root=Path.cwd())
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Cloud mount script"""
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
from machineconfig.utils.options import choose_one_option
|
|
5
4
|
from machineconfig.utils.utils2 import read_ini
|
|
6
5
|
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
@@ -146,6 +145,7 @@ zellij action move-focus up
|
|
|
146
145
|
# print(f"running command: \n{txt}")
|
|
147
146
|
# PROGRAM_PATH.write_text(txt, encoding="utf-8")
|
|
148
147
|
import subprocess
|
|
148
|
+
|
|
149
149
|
subprocess.run(txt, shell=True, check=True)
|
|
150
150
|
# draw success box dynamically
|
|
151
151
|
title1 = "✅ Cloud mount command prepared successfully"
|
|
@@ -163,6 +163,7 @@ git commit -am "finished merging"
|
|
|
163
163
|
raise ValueError(f"Unknown action: {action}")
|
|
164
164
|
# PROGRAM_PATH.write_text(program_content, encoding="utf-8")
|
|
165
165
|
import subprocess
|
|
166
|
+
|
|
166
167
|
subprocess.run(program_content, shell=True, check=True)
|
|
167
168
|
|
|
168
169
|
return program_content
|
|
@@ -209,6 +209,7 @@ print(f"🐊 Crocodile Shell | Running @ {Path.cwd()}")
|
|
|
209
209
|
# PROGRAM_PATH.write_text(data=final_program, encoding="utf-8")
|
|
210
210
|
# (PROGRAM_PATH + ".py").write_text(str(pyfile), encoding='utf-8')
|
|
211
211
|
import subprocess
|
|
212
|
+
|
|
212
213
|
subprocess.run(final_program, shell=True, check=True)
|
|
213
214
|
|
|
214
215
|
# if platform.system() == "Windows":
|
|
@@ -31,6 +31,7 @@ class Options(Enum):
|
|
|
31
31
|
def args_parser():
|
|
32
32
|
console.print(Panel("🛠️ DevOps Tool Suite", title_align="left", border_style="blue", width=BOX_WIDTH))
|
|
33
33
|
import argparse
|
|
34
|
+
|
|
34
35
|
parser = argparse.ArgumentParser()
|
|
35
36
|
new_line = "\n\n"
|
|
36
37
|
parser.add_argument("-w", "--which", help=f"""which option to run\nChoose one of those:\n{new_line.join([f"{item.name}: {item.value}" for item in list(Options)])}""", type=str, default=None) # , choices=[op.value for op in Options]
|
|
@@ -56,26 +57,30 @@ def main(which: Optional[str] = None):
|
|
|
56
57
|
if choice_key == Options.update.value:
|
|
57
58
|
console.print(Panel("🔄 Updating essential repositories...", width=BOX_WIDTH, border_style="blue"))
|
|
58
59
|
import machineconfig.scripts.python.devops_update_repos as helper
|
|
60
|
+
|
|
59
61
|
helper.main()
|
|
60
62
|
elif choice_key == Options.cli_install.value:
|
|
61
63
|
console.print(Panel("⚙️ Installing development applications...", width=BOX_WIDTH, border_style="blue"))
|
|
62
64
|
import machineconfig.scripts.python.devops_devapps_install as helper
|
|
63
|
-
helper.main()
|
|
65
|
+
helper.main(which=None)
|
|
64
66
|
|
|
65
67
|
elif choice_key == Options.sym_new.value:
|
|
66
68
|
console.print(Panel("🔄 Creating new symlinks...", width=BOX_WIDTH, border_style="blue"))
|
|
67
69
|
import machineconfig.jobs.python.python_ve_symlink as helper
|
|
70
|
+
|
|
68
71
|
helper.main()
|
|
69
72
|
|
|
70
73
|
elif choice_key == Options.sym_path_shell.value:
|
|
71
74
|
console.print(Panel("🔗 Setting up symlinks, PATH, and shell profile...", width=BOX_WIDTH, border_style="blue"))
|
|
72
75
|
import machineconfig.profile.create as helper
|
|
76
|
+
|
|
73
77
|
helper.main()
|
|
74
78
|
"echo '✅ done with symlinks'"
|
|
75
79
|
|
|
76
80
|
elif choice_key == Options.ssh_add_pubkey.value:
|
|
77
81
|
console.print(Panel("🔑 Adding public SSH key to this machine...", width=BOX_WIDTH, border_style="blue"))
|
|
78
82
|
import machineconfig.scripts.python.devops_add_ssh_key as helper
|
|
83
|
+
|
|
79
84
|
helper.main()
|
|
80
85
|
|
|
81
86
|
elif choice_key == Options.ssh_use_pair.value:
|
|
@@ -85,6 +90,7 @@ def main(which: Optional[str] = None):
|
|
|
85
90
|
elif choice_key == Options.ssh_add_id.value: # so that you can SSH directly withuot pointing to identity key.
|
|
86
91
|
console.print(Panel("🗝️ Adding SSH identity (private key) to this machine...", width=BOX_WIDTH, border_style="blue"))
|
|
87
92
|
import machineconfig.scripts.python.devops_add_identity as helper
|
|
93
|
+
|
|
88
94
|
helper.main()
|
|
89
95
|
|
|
90
96
|
elif choice_key == Options.ssh_setup.value:
|
|
@@ -93,6 +99,7 @@ def main(which: Optional[str] = None):
|
|
|
93
99
|
_program_linux = """curl https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/openssh_all.sh | sudo bash # https://github.com/thisismygitrepo.keys"""
|
|
94
100
|
_program_linux if system() == "Linux" else _program_windows
|
|
95
101
|
import subprocess
|
|
102
|
+
|
|
96
103
|
subprocess.run(_program_linux if system() == "Linux" else _program_windows, shell=True, check=True)
|
|
97
104
|
|
|
98
105
|
elif choice_key == Options.ssh_setup_wsl.value:
|
|
@@ -102,11 +109,13 @@ def main(which: Optional[str] = None):
|
|
|
102
109
|
elif choice_key == Options.backup.value:
|
|
103
110
|
console.print(Panel("💾 Creating backup...", width=BOX_WIDTH, border_style="blue"))
|
|
104
111
|
from machineconfig.scripts.python.devops_backup_retrieve import main_backup_retrieve
|
|
112
|
+
|
|
105
113
|
main_backup_retrieve(direction="BACKUP")
|
|
106
114
|
|
|
107
115
|
elif choice_key == Options.retreive.value:
|
|
108
116
|
console.print(Panel("📥 Retrieving backup...", width=BOX_WIDTH, border_style="blue"))
|
|
109
117
|
from machineconfig.scripts.python.devops_backup_retrieve import main_backup_retrieve
|
|
118
|
+
|
|
110
119
|
main_backup_retrieve(direction="RETRIEVE")
|
|
111
120
|
|
|
112
121
|
elif choice_key == Options.scheduler.value:
|
|
@@ -118,5 +127,6 @@ def main(which: Optional[str] = None):
|
|
|
118
127
|
console.print(Panel("❌ ERROR: Invalid choice", title_align="left", border_style="red", width=BOX_WIDTH))
|
|
119
128
|
raise ValueError(f"Unimplemented choice: {choice_key}")
|
|
120
129
|
|
|
130
|
+
|
|
121
131
|
if __name__ == "__main__":
|
|
122
132
|
args_parser()
|
|
@@ -78,6 +78,7 @@ def main() -> None:
|
|
|
78
78
|
print(Panel(Text(success_message, justify="center"), expand=False, border_style="green"))
|
|
79
79
|
|
|
80
80
|
import subprocess
|
|
81
|
+
|
|
81
82
|
# run program
|
|
82
83
|
subprocess.run(program, shell=True, check=True, text=True)
|
|
83
84
|
print(Panel("🔐 Identity added to SSH agent", expand=False, border_style="green"))
|
|
@@ -74,6 +74,7 @@ def main_backup_retrieve(direction: OPTIONS, which: Optional[str] = None) -> Non
|
|
|
74
74
|
print_code(program, lexer="shell", desc=f"{direction} script")
|
|
75
75
|
console.print(Panel(f"✅ {direction} SCRIPT GENERATION COMPLETE\n🚀 Ready to execute the operations", title="[bold green]Script Generation Complete[/bold green]", border_style="green"))
|
|
76
76
|
import subprocess
|
|
77
|
+
|
|
77
78
|
subprocess.run(program, shell=True, check=True)
|
|
78
79
|
|
|
79
80
|
|
|
@@ -13,7 +13,7 @@ from typing import Any, Optional, Literal, TypeAlias, get_args
|
|
|
13
13
|
WHICH_CAT: TypeAlias = Literal["AllEssentials", "EssentialsAndOthers", "SystemInstallers", "PrecheckedCloudInstaller"]
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def main(which: Optional[WHICH_CAT | str]
|
|
16
|
+
def main(which: Optional[WHICH_CAT | str]) -> None:
|
|
17
17
|
if which is not None and which in get_args(WHICH_CAT): # install by category
|
|
18
18
|
return get_programs_by_category(program_name=which) # type: ignore
|
|
19
19
|
|
|
@@ -39,18 +39,15 @@ def main(which: Optional[WHICH_CAT | str] = None) -> None:
|
|
|
39
39
|
|
|
40
40
|
# interactive installation
|
|
41
41
|
installers = [Installer.from_dict(d=vd, name=name) for __kat, vds in get_all_dicts(system=system()).items() for name, vd in vds.items()]
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
# Check installed programs with progress indicator
|
|
44
|
-
with Progress(
|
|
45
|
-
SpinnerColumn(),
|
|
46
|
-
TextColumn("[progress.description]{task.description}"),
|
|
47
|
-
) as progress:
|
|
44
|
+
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}")) as progress:
|
|
48
45
|
task = progress.add_task("✅ Checking installed programs...", total=len(installers))
|
|
49
46
|
options = []
|
|
50
47
|
for x in installers:
|
|
51
48
|
options.append(x.get_description())
|
|
52
49
|
progress.update(task, advance=1)
|
|
53
|
-
|
|
50
|
+
|
|
54
51
|
options += list(get_args(WHICH_CAT))
|
|
55
52
|
# print("s"*1000)
|
|
56
53
|
program_names = choose_multiple_options(msg="", options=options, header="🚀 CHOOSE DEV APP", default="AllEssentials")
|
|
@@ -67,6 +64,7 @@ def main(which: Optional[WHICH_CAT | str] = None) -> None:
|
|
|
67
64
|
an_installer = installers[options.index(a_program_name)]
|
|
68
65
|
total_program += "\n" + an_installer.install_robust(version=None) # finish the task
|
|
69
66
|
import subprocess
|
|
67
|
+
|
|
70
68
|
subprocess.run(total_program, shell=True, check=True)
|
|
71
69
|
|
|
72
70
|
|
|
@@ -13,20 +13,20 @@ def _display_summary(results: list[RepositoryUpdateResult]) -> None:
|
|
|
13
13
|
print("\n" + "=" * 80)
|
|
14
14
|
print("📊 REPOSITORY UPDATE SUMMARY")
|
|
15
15
|
print("=" * 80)
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
# Calculate statistics
|
|
18
18
|
total_repos = len(results)
|
|
19
19
|
successful_repos = sum(1 for r in results if r["status"] == "success")
|
|
20
20
|
error_repos = sum(1 for r in results if r["status"] == "error")
|
|
21
21
|
skipped_repos = sum(1 for r in results if r["status"] == "skipped")
|
|
22
22
|
auth_failed_repos = sum(1 for r in results if r["status"] == "auth_failed")
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
repos_with_changes = sum(1 for r in results if r["commits_changed"])
|
|
25
25
|
repos_with_uncommitted = sum(1 for r in results if r["had_uncommitted_changes"])
|
|
26
26
|
repos_with_dep_changes = sum(1 for r in results if r["dependencies_changed"])
|
|
27
27
|
uv_sync_runs = sum(1 for r in results if r["uv_sync_ran"])
|
|
28
28
|
uv_sync_successes = sum(1 for r in results if r["uv_sync_ran"] and r["uv_sync_success"])
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
# Overview statistics
|
|
31
31
|
print("📈 OVERVIEW:")
|
|
32
32
|
print(f" Total repositories processed: {total_repos}")
|
|
@@ -36,59 +36,59 @@ def _display_summary(results: list[RepositoryUpdateResult]) -> None:
|
|
|
36
36
|
if auth_failed_repos > 0:
|
|
37
37
|
print(f" 🔐 Authentication failed: {auth_failed_repos}")
|
|
38
38
|
print()
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
print("🔄 CHANGES:")
|
|
41
41
|
print(f" Repositories with new commits: {repos_with_changes}")
|
|
42
42
|
print(f" Repositories with dependency changes: {repos_with_dep_changes}")
|
|
43
43
|
print(f" Repositories with uncommitted changes: {repos_with_uncommitted}")
|
|
44
44
|
print()
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
print("📦 UV SYNC:")
|
|
47
47
|
print(f" uv sync operations attempted: {uv_sync_runs}")
|
|
48
48
|
print(f" uv sync operations successful: {uv_sync_successes}")
|
|
49
49
|
if uv_sync_runs > uv_sync_successes:
|
|
50
50
|
print(f" uv sync operations failed: {uv_sync_runs - uv_sync_successes}")
|
|
51
51
|
print()
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
# Detailed results per repository
|
|
54
54
|
print("📋 DETAILED RESULTS:")
|
|
55
55
|
for result in results:
|
|
56
56
|
repo_name = Path(result["repo_path"]).name
|
|
57
57
|
status_icon = {"success": "✅", "error": "❌", "skipped": "⏭️", "auth_failed": "🔐"}.get(result["status"], "❓")
|
|
58
58
|
print(f" {status_icon} {repo_name}")
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
if result["status"] == "error" and result["error_message"]:
|
|
61
61
|
print(f" 💥 Error: {result['error_message']}")
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
if result["commits_changed"]:
|
|
64
64
|
print(f" 🔄 Updated: {result['commit_before'][:8]} → {result['commit_after'][:8]}")
|
|
65
65
|
elif result["status"] == "success":
|
|
66
66
|
print(" 📍 Already up to date")
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
if result["had_uncommitted_changes"]:
|
|
69
69
|
files_str = ", ".join(result["uncommitted_files"])
|
|
70
70
|
print(f" ⚠️ Had uncommitted changes: {files_str}")
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
if result["dependencies_changed"]:
|
|
73
73
|
changes = []
|
|
74
74
|
if result["pyproject_changed"]:
|
|
75
75
|
changes.append("pyproject.toml")
|
|
76
76
|
print(f" 📋 Dependencies changed: {', '.join(changes)}")
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
if result["uv_sync_ran"]:
|
|
79
79
|
sync_status = "✅" if result["uv_sync_success"] else "❌"
|
|
80
80
|
print(f" 📦 uv sync: {sync_status}")
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
if result["is_machineconfig_repo"] and result["permissions_updated"]:
|
|
83
83
|
print(" 🛠 Updated permissions for machineconfig files")
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
if result["remotes_processed"]:
|
|
86
86
|
print(f" 📡 Processed remotes: {', '.join(result['remotes_processed'])}")
|
|
87
87
|
if result["remotes_skipped"]:
|
|
88
88
|
print(f" ⏭️ Skipped remotes: {', '.join(result['remotes_skipped'])}")
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
print("\n" + "=" * 80)
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
# Final status
|
|
93
93
|
if error_repos == 0 and auth_failed_repos == 0:
|
|
94
94
|
print("🎉 All repositories processed successfully!")
|
|
@@ -131,18 +131,18 @@ def main(verbose: bool = True, allow_password_prompt: bool = False) -> None:
|
|
|
131
131
|
# Process repositories
|
|
132
132
|
results: list[RepositoryUpdateResult] = []
|
|
133
133
|
repos_with_changes = []
|
|
134
|
-
|
|
134
|
+
|
|
135
135
|
for expanded_path in repos:
|
|
136
136
|
try:
|
|
137
137
|
repo = git.Repo(str(expanded_path), search_parent_directories=True)
|
|
138
138
|
# Update repository and get detailed results
|
|
139
139
|
result = update_repository(repo, allow_password_prompt=allow_password_prompt, auto_sync=True)
|
|
140
140
|
results.append(result)
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
# Keep track of repos with dependency changes for additional uv sync
|
|
143
143
|
if result["dependencies_changed"] and not result["uv_sync_ran"]:
|
|
144
144
|
repos_with_changes.append(Path(repo.working_dir))
|
|
145
|
-
|
|
145
|
+
|
|
146
146
|
except Exception as ex:
|
|
147
147
|
# Create a result for failed repos
|
|
148
148
|
error_result: RepositoryUpdateResult = {
|
|
@@ -167,13 +167,14 @@ def main(verbose: bool = True, allow_password_prompt: bool = False) -> None:
|
|
|
167
167
|
print(f"""❌ Repository Error: Path: {expanded_path}
|
|
168
168
|
Exception: {ex}
|
|
169
169
|
{"-" * 50}""")
|
|
170
|
-
|
|
170
|
+
|
|
171
171
|
# Run uv sync for repositories where pyproject.toml changed but sync wasn't run yet
|
|
172
172
|
for repo_path in repos_with_changes:
|
|
173
173
|
run_uv_sync(repo_path)
|
|
174
|
-
|
|
174
|
+
|
|
175
175
|
# Generate and display summary
|
|
176
176
|
_display_summary(results)
|
|
177
177
|
|
|
178
|
+
|
|
178
179
|
if __name__ == "__main__":
|
|
179
180
|
main()
|
|
@@ -16,7 +16,7 @@ from machineconfig.scripts.python.fire_agents_help_launch import prep_agent_laun
|
|
|
16
16
|
from machineconfig.scripts.python.fire_agents_help_search import search_files_by_pattern, search_python_files
|
|
17
17
|
from machineconfig.scripts.python.fire_agents_load_balancer import chunk_prompts, SPLITTING_STRATEGY, DEFAULT_AGENT_CAP
|
|
18
18
|
from machineconfig.utils.options import choose_one_option
|
|
19
|
-
from machineconfig.utils.schemas.layouts.layout_types import
|
|
19
|
+
from machineconfig.utils.schemas.layouts.layout_types import TabConfig, LayoutConfig
|
|
20
20
|
from machineconfig.utils.ve import get_repo_root
|
|
21
21
|
|
|
22
22
|
SEARCH_STRATEGIES: TypeAlias = Literal["file_path", "keyword_search", "filename_pattern"]
|
|
@@ -138,24 +138,34 @@ manager.run_monitoring_routine()
|
|
|
138
138
|
"""
|
|
139
139
|
(agents_dir / "aa_agents_relaunch.py").write_text(data=regenerate_py_code, encoding="utf-8")
|
|
140
140
|
(agents_dir / "layout.json").write_text(data=json.dumps(layoutfile, indent=2), encoding="utf-8")
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
|
|
142
|
+
MAX_TABS = 10
|
|
143
|
+
if len(layoutfile["layouts"][0]["layoutTabs"]) > MAX_TABS:
|
|
144
|
+
print(f"Too many tabs (>{MAX_TABS}) to launch. Skipping launch.")
|
|
143
145
|
sys.exit(0)
|
|
144
146
|
from machineconfig.cluster.sessions_managers.zellij_local_manager import ZellijLocalManager
|
|
147
|
+
|
|
145
148
|
manager = ZellijLocalManager(session_layouts=layoutfile["layouts"])
|
|
146
|
-
manager.start_all_sessions()
|
|
147
|
-
manager.run_monitoring_routine()
|
|
149
|
+
manager.start_all_sessions(poll_interval=2, poll_seconds=2)
|
|
150
|
+
manager.run_monitoring_routine(wait_ms=2000)
|
|
148
151
|
|
|
149
152
|
|
|
150
|
-
def
|
|
153
|
+
def split_too_many_tabs_to_run_in_sequential_sessions(layout_tabs: list[TabConfig], every: int):
|
|
154
|
+
from machineconfig.utils.utils2 import split
|
|
155
|
+
from machineconfig.cluster.sessions_managers.zellij_local_manager import ZellijLocalManager
|
|
156
|
+
for idx, layout_tabs_chunk in enumerate(split(layout_tabs, every=every)):
|
|
157
|
+
a_layout_file: LayoutConfig = {"layoutName": f"split_{idx}", "layoutTabs": layout_tabs_chunk}
|
|
158
|
+
manager = ZellijLocalManager(session_layouts=[a_layout_file])
|
|
159
|
+
manager.start_all_sessions(poll_interval=2, poll_seconds=2)
|
|
160
|
+
manager.run_monitoring_routine(wait_ms=2000)
|
|
161
|
+
manager.kill_all_sessions()
|
|
162
|
+
def split_too_many_layouts_to_run_in_sequential_sessions(layouts: list[LayoutConfig], every: int):
|
|
151
163
|
from machineconfig.utils.utils2 import split
|
|
152
164
|
from machineconfig.cluster.sessions_managers.zellij_local_manager import ZellijLocalManager
|
|
153
|
-
for layout_chunk in split(
|
|
165
|
+
for _idx, layout_chunk in enumerate(split(layouts, every=every)):
|
|
154
166
|
manager = ZellijLocalManager(session_layouts=layout_chunk)
|
|
155
|
-
manager.start_all_sessions()
|
|
156
|
-
manager.run_monitoring_routine()
|
|
157
|
-
|
|
158
|
-
|
|
167
|
+
manager.start_all_sessions(poll_interval=2, poll_seconds=2)
|
|
168
|
+
manager.run_monitoring_routine(wait_ms=2000)
|
|
159
169
|
|
|
160
170
|
|
|
161
171
|
if __name__ == "__main__": # pragma: no cover
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
from machineconfig.utils.utils2 import randstr
|
|
3
2
|
|
|
4
3
|
import random
|
|
@@ -16,6 +15,7 @@ AGENT_NAME_FORMATTER = "agent_{idx}_cmd.sh" # e.g., agent_0_cmd.sh
|
|
|
16
15
|
|
|
17
16
|
def get_gemini_api_keys() -> list[str]:
|
|
18
17
|
from machineconfig.utils.utils2 import read_ini
|
|
18
|
+
|
|
19
19
|
config = read_ini(Path.home().joinpath("dotfiles/creds/llm/gemini/api_keys.ini"))
|
|
20
20
|
res: list[str] = []
|
|
21
21
|
for a_section_name in list(config.sections()):
|
|
@@ -27,7 +27,8 @@ def get_gemini_api_keys() -> list[str]:
|
|
|
27
27
|
print(f"Found {len(res)} Gemini API keys configured.")
|
|
28
28
|
return res
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
|
|
31
|
+
def prep_agent_launch(repo_root: Path, prompts_material: list[str], prompt_prefix: str, keep_material_in_separate_file: bool, agent: AGENTS, *, job_name: str) -> Path:
|
|
31
32
|
session_root = repo_root / ".ai" / f"tmp_prompts/{job_name}_{randstr()}"
|
|
32
33
|
session_root.mkdir(parents=True, exist_ok=True)
|
|
33
34
|
prompt_folder = session_root / "prompts"
|
|
@@ -115,7 +116,6 @@ echo "---------END OF AGENT OUTPUT---------"
|
|
|
115
116
|
"""
|
|
116
117
|
agent_cmd_launch_path.write_text(cmd_prefix + cmd + cmd_postfix, encoding="utf-8")
|
|
117
118
|
|
|
118
|
-
|
|
119
119
|
# print(f"Launching a template with #{len(tab_config)} agents")
|
|
120
120
|
if len(all_materials_scripts) > 0:
|
|
121
121
|
all_materials_list_path = session_root / "all_materials_redistributed.txt"
|
|
@@ -126,6 +126,7 @@ echo "---------END OF AGENT OUTPUT---------"
|
|
|
126
126
|
|
|
127
127
|
def get_agents_launch_layout(session_root: Path):
|
|
128
128
|
from machineconfig.utils.schemas.layouts.layout_types import TabConfig, LayoutConfig, LayoutsFile
|
|
129
|
+
|
|
129
130
|
tab_config: list[TabConfig] = []
|
|
130
131
|
prompt_root = session_root / "prompts"
|
|
131
132
|
all_dirs_under_prompts = [d for d in prompt_root.iterdir() if d.is_dir()]
|