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.
- machineconfig/cluster/cloud_manager.py +22 -29
- machineconfig/cluster/data_transfer.py +2 -3
- machineconfig/cluster/distribute.py +0 -2
- machineconfig/cluster/file_manager.py +4 -5
- machineconfig/cluster/job_params.py +1 -4
- machineconfig/cluster/loader_runner.py +8 -11
- machineconfig/cluster/remote_machine.py +4 -5
- machineconfig/cluster/script_execution.py +2 -2
- machineconfig/cluster/script_notify_upon_completion.py +0 -1
- machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +4 -6
- machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -1
- machineconfig/cluster/sessions_managers/enhanced_command_runner.py +35 -75
- machineconfig/cluster/sessions_managers/wt_local.py +113 -185
- machineconfig/cluster/sessions_managers/wt_local_manager.py +127 -197
- machineconfig/cluster/sessions_managers/wt_remote.py +60 -67
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +110 -149
- machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +61 -64
- machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +72 -172
- machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +27 -60
- machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +58 -137
- machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +46 -74
- machineconfig/cluster/sessions_managers/zellij_local.py +91 -147
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +165 -190
- machineconfig/cluster/sessions_managers/zellij_remote.py +51 -58
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +40 -46
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +19 -17
- machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +30 -31
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +64 -134
- machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +7 -11
- machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +27 -55
- machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +14 -13
- machineconfig/cluster/templates/cli_click.py +0 -1
- machineconfig/cluster/templates/cli_gooey.py +0 -2
- machineconfig/cluster/templates/cli_trogon.py +0 -1
- machineconfig/cluster/templates/run_cloud.py +0 -1
- machineconfig/cluster/templates/run_cluster.py +0 -1
- machineconfig/cluster/templates/run_remote.py +0 -1
- machineconfig/cluster/templates/utils.py +27 -11
- machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
- machineconfig/jobs/python/check_installations.py +9 -9
- machineconfig/jobs/python/create_bootable_media.py +0 -2
- machineconfig/jobs/python/python_cargo_build_share.py +2 -2
- machineconfig/jobs/python/python_ve_symlink.py +9 -11
- machineconfig/jobs/python/tasks.py +0 -1
- machineconfig/jobs/python/vscode/api.py +5 -5
- machineconfig/jobs/python/vscode/link_ve.py +20 -21
- machineconfig/jobs/python/vscode/select_interpreter.py +28 -29
- machineconfig/jobs/python/vscode/sync_code.py +14 -18
- machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_custom_installers/archive/ngrok.py +15 -15
- machineconfig/jobs/python_custom_installers/dev/aider.py +10 -18
- machineconfig/jobs/python_custom_installers/dev/alacritty.py +12 -21
- machineconfig/jobs/python_custom_installers/dev/brave.py +13 -22
- machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +13 -20
- machineconfig/jobs/python_custom_installers/dev/code.py +17 -24
- machineconfig/jobs/python_custom_installers/dev/cursor.py +10 -21
- machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +12 -11
- machineconfig/jobs/python_custom_installers/dev/espanso.py +19 -23
- machineconfig/jobs/python_custom_installers/dev/goes.py +9 -16
- machineconfig/jobs/python_custom_installers/dev/lvim.py +13 -21
- machineconfig/jobs/python_custom_installers/dev/nerdfont.py +15 -22
- machineconfig/jobs/python_custom_installers/dev/redis.py +15 -23
- machineconfig/jobs/python_custom_installers/dev/wezterm.py +15 -22
- machineconfig/jobs/python_custom_installers/dev/winget.py +32 -50
- machineconfig/jobs/python_custom_installers/docker.py +15 -24
- machineconfig/jobs/python_custom_installers/gh.py +18 -26
- machineconfig/jobs/python_custom_installers/hx.py +33 -17
- machineconfig/jobs/python_custom_installers/warp-cli.py +15 -23
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_generic_installers/config.json +412 -389
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_windows_installers/dev/config.json +1 -1
- machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -1
- machineconfig/jobs/windows/msc/cli_agents.bat +0 -0
- machineconfig/jobs/windows/msc/cli_agents.ps1 +0 -0
- machineconfig/jobs/windows/start_terminal.ps1 +1 -1
- machineconfig/logger.py +50 -0
- machineconfig/profile/create.py +50 -36
- machineconfig/profile/create_hardlinks.py +33 -26
- machineconfig/profile/shell.py +87 -60
- machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/cloud/init.sh +2 -2
- machineconfig/scripts/linux/checkout_versions +1 -1
- machineconfig/scripts/linux/choose_wezterm_theme +1 -1
- machineconfig/scripts/linux/cloud_copy +1 -1
- machineconfig/scripts/linux/cloud_manager +1 -1
- machineconfig/scripts/linux/cloud_mount +1 -1
- machineconfig/scripts/linux/cloud_repo_sync +1 -1
- machineconfig/scripts/linux/cloud_sync +1 -1
- machineconfig/scripts/linux/croshell +1 -1
- machineconfig/scripts/linux/devops +3 -5
- machineconfig/scripts/linux/fire +2 -1
- machineconfig/scripts/linux/fire_agents +3 -3
- machineconfig/scripts/linux/ftpx +1 -1
- machineconfig/scripts/linux/gh_models +1 -1
- machineconfig/scripts/linux/kill_process +1 -1
- machineconfig/scripts/linux/mcinit +2 -2
- machineconfig/scripts/linux/repos +1 -1
- machineconfig/scripts/linux/scheduler +1 -1
- machineconfig/scripts/linux/start_slidev +1 -1
- machineconfig/scripts/linux/start_terminals +1 -1
- machineconfig/scripts/linux/url2md +1 -1
- machineconfig/scripts/linux/warp-cli.sh +122 -0
- machineconfig/scripts/linux/wifi_conn +1 -1
- machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__init__.py +0 -0
- machineconfig/scripts/python/ai/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/generate_files.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/chatmodes/Thinking-Beast-Mode.chatmode.md +337 -0
- machineconfig/scripts/python/ai/chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md +644 -0
- machineconfig/scripts/python/ai/chatmodes/deepResearch.chatmode.md +81 -0
- machineconfig/scripts/python/ai/configs/.gemini/settings.json +81 -0
- machineconfig/scripts/python/ai/generate_files.py +84 -0
- machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +45 -0
- machineconfig/scripts/python/ai/mcinit.py +107 -0
- machineconfig/scripts/python/ai/prompts/allLintersAndTypeCheckers.prompt.md +5 -0
- machineconfig/scripts/python/ai/prompts/research-report-skeleton.prompt.md +38 -0
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +52 -0
- machineconfig/scripts/python/archive/tmate_conn.py +5 -5
- machineconfig/scripts/python/archive/tmate_start.py +3 -3
- machineconfig/scripts/python/choose_wezterm_theme.py +2 -2
- machineconfig/scripts/python/cloud_copy.py +20 -19
- machineconfig/scripts/python/cloud_mount.py +10 -8
- machineconfig/scripts/python/cloud_repo_sync.py +15 -15
- machineconfig/scripts/python/cloud_sync.py +1 -1
- machineconfig/scripts/python/croshell.py +18 -16
- machineconfig/scripts/python/devops.py +6 -6
- machineconfig/scripts/python/devops_add_identity.py +9 -7
- machineconfig/scripts/python/devops_add_ssh_key.py +19 -19
- machineconfig/scripts/python/devops_backup_retrieve.py +14 -14
- machineconfig/scripts/python/devops_devapps_install.py +3 -3
- machineconfig/scripts/python/devops_update_repos.py +141 -53
- machineconfig/scripts/python/dotfile.py +3 -3
- machineconfig/scripts/python/fire_agents.py +202 -41
- machineconfig/scripts/python/fire_jobs.py +20 -21
- machineconfig/scripts/python/ftpx.py +4 -3
- machineconfig/scripts/python/gh_models.py +94 -94
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/cloud_helpers.py +3 -3
- machineconfig/scripts/python/helpers/helpers2.py +3 -3
- machineconfig/scripts/python/helpers/helpers4.py +8 -7
- machineconfig/scripts/python/helpers/helpers5.py +7 -7
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +2 -2
- machineconfig/scripts/python/mount_nfs.py +4 -3
- machineconfig/scripts/python/mount_nw_drive.py +4 -4
- machineconfig/scripts/python/mount_ssh.py +4 -3
- machineconfig/scripts/python/repos.py +9 -9
- machineconfig/scripts/python/scheduler.py +1 -1
- machineconfig/scripts/python/start_slidev.py +9 -8
- machineconfig/scripts/python/start_terminals.py +1 -1
- machineconfig/scripts/python/viewer.py +40 -40
- machineconfig/scripts/python/wifi_conn.py +65 -66
- machineconfig/scripts/python/wsl_windows_transfer.py +2 -2
- machineconfig/scripts/windows/checkout_version.ps1 +1 -3
- machineconfig/scripts/windows/choose_wezterm_theme.ps1 +1 -3
- machineconfig/scripts/windows/cloud_copy.ps1 +2 -6
- machineconfig/scripts/windows/cloud_manager.ps1 +1 -1
- machineconfig/scripts/windows/cloud_repo_sync.ps1 +1 -2
- machineconfig/scripts/windows/cloud_sync.ps1 +2 -2
- machineconfig/scripts/windows/croshell.ps1 +2 -2
- machineconfig/scripts/windows/devops.ps1 +1 -4
- machineconfig/scripts/windows/dotfile.ps1 +1 -3
- machineconfig/scripts/windows/fire.ps1 +1 -1
- machineconfig/scripts/windows/ftpx.ps1 +2 -2
- machineconfig/scripts/windows/gpt.ps1 +1 -1
- machineconfig/scripts/windows/kill_process.ps1 +1 -2
- machineconfig/scripts/windows/mcinit.ps1 +2 -2
- machineconfig/scripts/windows/mount_nfs.ps1 +1 -1
- machineconfig/scripts/windows/mount_ssh.ps1 +1 -1
- machineconfig/scripts/windows/pomodoro.ps1 +1 -1
- machineconfig/scripts/windows/py2exe.ps1 +1 -3
- machineconfig/scripts/windows/repos.ps1 +1 -1
- machineconfig/scripts/windows/scheduler.ps1 +1 -1
- machineconfig/scripts/windows/snapshot.ps1 +2 -2
- machineconfig/scripts/windows/start_slidev.ps1 +1 -1
- machineconfig/scripts/windows/start_terminals.ps1 +1 -1
- machineconfig/scripts/windows/wifi_conn.ps1 +1 -1
- machineconfig/scripts/windows/wsl_windows_transfer.ps1 +1 -3
- machineconfig/settings/lf/linux/lfrc +1 -1
- machineconfig/settings/linters/.ruff.toml +2 -2
- machineconfig/settings/linters/.ruff_cache/.gitignore +2 -0
- machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +1 -0
- machineconfig/settings/lvim/windows/archive/config_additional.lua +1 -1
- machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +71 -71
- machineconfig/settings/shells/wt/settings.json +8 -8
- machineconfig/settings/svim/linux/init.toml +1 -1
- machineconfig/settings/svim/windows/init.toml +1 -1
- machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -54
- machineconfig/setup_linux/web_shortcuts/interactive.sh +6 -6
- machineconfig/setup_linux/web_shortcuts/tmp.sh +2 -0
- machineconfig/setup_windows/web_shortcuts/all.ps1 +2 -2
- machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/croshell.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +5 -5
- machineconfig/setup_windows/wt_and_pwsh/install_fonts.ps1 +51 -15
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +75 -18
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +52 -42
- machineconfig/utils/ai/browser_user_wrapper.py +5 -5
- machineconfig/utils/ai/generate_file_checklist.py +19 -22
- machineconfig/utils/ai/url2md.py +5 -3
- machineconfig/utils/cloud/onedrive/setup_oauth.py +5 -4
- machineconfig/utils/cloud/onedrive/transaction.py +192 -227
- machineconfig/utils/code.py +71 -43
- machineconfig/utils/installer.py +77 -85
- machineconfig/utils/installer_utils/installer_abc.py +29 -17
- machineconfig/utils/installer_utils/installer_class.py +188 -83
- machineconfig/utils/io_save.py +3 -15
- machineconfig/utils/links.py +22 -11
- machineconfig/utils/notifications.py +197 -0
- machineconfig/utils/options.py +38 -25
- machineconfig/utils/path.py +18 -6
- machineconfig/utils/path_reduced.py +637 -316
- machineconfig/utils/procs.py +69 -63
- machineconfig/utils/scheduling.py +11 -13
- machineconfig/utils/ssh.py +351 -0
- machineconfig/utils/terminal.py +225 -0
- machineconfig/utils/utils.py +13 -12
- machineconfig/utils/utils2.py +43 -10
- machineconfig/utils/utils5.py +242 -46
- machineconfig/utils/ve.py +11 -6
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/METADATA +15 -9
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/RECORD +232 -235
- machineconfig/cluster/self_ssh.py +0 -57
- machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/archive/python_tools.txt +0 -12
- machineconfig/jobs/python/vscode/__pycache__/select_interpreter.cpython-311.pyc +0 -0
- machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/update.py +0 -3
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
- machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/linux/activate_ve +0 -87
- machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_backup_retrieve.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/init.py +0 -56
- machineconfig/scripts/python/ai/rules/python/dev.md +0 -31
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/windows/activate_ve.ps1 +0 -54
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/WHEEL +0 -0
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/top_level.txt +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
|
|
4
4
|
# import subprocess
|
|
5
|
-
from machineconfig.utils.path_reduced import
|
|
5
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
6
6
|
from machineconfig.utils.utils2 import read_ini, read_toml
|
|
7
7
|
from machineconfig.utils.utils import LIBRARY_ROOT, DEFAULTS_PATH, print_code, choose_cloud_interactively, choose_multiple_options
|
|
8
8
|
from machineconfig.scripts.python.helpers.helpers2 import ES
|
|
@@ -17,7 +17,7 @@ OPTIONS = Literal["BACKUP", "RETRIEVE"]
|
|
|
17
17
|
|
|
18
18
|
def main_backup_retrieve(direction: OPTIONS, which: Optional[str] = None):
|
|
19
19
|
console = Console()
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
try:
|
|
22
22
|
cloud: str = read_ini(DEFAULTS_PATH)['general']['rclone_config_name']
|
|
23
23
|
console.print(Panel(f"⚠️ DEFAULT CLOUD CONFIGURATION\n🌥️ Using default cloud: {cloud}", title="[bold blue]Cloud Configuration[/bold blue]", border_style="blue"))
|
|
@@ -26,13 +26,13 @@ def main_backup_retrieve(direction: OPTIONS, which: Optional[str] = None):
|
|
|
26
26
|
cloud = choose_cloud_interactively()
|
|
27
27
|
|
|
28
28
|
bu_file: dict[str, Any] = read_toml(LIBRARY_ROOT.joinpath("profile/backup.toml"))
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
console.print(Panel(f"🧰 LOADING BACKUP CONFIGURATION\n📄 File: {LIBRARY_ROOT.joinpath('profile/backup.toml')}", title="[bold blue]Backup Configuration[/bold blue]", border_style="blue"))
|
|
31
|
-
|
|
32
|
-
if system() == "Linux":
|
|
31
|
+
|
|
32
|
+
if system() == "Linux":
|
|
33
33
|
bu_file = {key: val for key, val in bu_file.items() if "windows" not in key}
|
|
34
34
|
console.print(Panel(f"🐧 LINUX ENVIRONMENT DETECTED\n🔍 Filtering out Windows-specific entries\n✅ Found {len(bu_file)} applicable backup configuration entries", title="[bold blue]Linux Environment[/bold blue]", border_style="blue"))
|
|
35
|
-
elif system() == "Windows":
|
|
35
|
+
elif system() == "Windows":
|
|
36
36
|
bu_file = {key: val for key, val in bu_file.items() if "linux" not in key}
|
|
37
37
|
console.print(Panel(f"🪟 WINDOWS ENVIRONMENT DETECTED\n🔍 Filtering out Linux-specific entries\n✅ Found {len(bu_file)} applicable backup configuration entries", title="[bold blue]Windows Environment[/bold blue]", border_style="blue"))
|
|
38
38
|
|
|
@@ -59,14 +59,14 @@ def main_backup_retrieve(direction: OPTIONS, which: Optional[str] = None):
|
|
|
59
59
|
flags += 'o' if system().lower() in item_name else ''
|
|
60
60
|
console.print(Panel(f"📦 PROCESSING: {item_name}\n📂 Path: {PathExtended(item['path']).as_posix()}\n🏳️ Flags: {flags or 'None'}", title=f"[bold blue]Processing Item: {item_name}[/bold blue]", border_style="blue"))
|
|
61
61
|
if flags: flags = "-" + flags
|
|
62
|
-
if direction == "BACKUP":
|
|
62
|
+
if direction == "BACKUP":
|
|
63
63
|
program += f"""\ncloud_copy "{PathExtended(item['path']).as_posix()}" $cloud {flags}\n"""
|
|
64
|
-
elif direction == "RETRIEVE":
|
|
64
|
+
elif direction == "RETRIEVE":
|
|
65
65
|
program += f"""\ncloud_copy $cloud "{PathExtended(item['path']).as_posix()}" {flags}\n"""
|
|
66
66
|
else:
|
|
67
67
|
console.print(Panel("❌ ERROR: INVALID DIRECTION\n⚠️ Direction must be either \"BACKUP\" or \"RETRIEVE\"", title="[bold red]Error: Invalid Direction[/bold red]", border_style="red"))
|
|
68
|
-
raise RuntimeError(f"Unknown direction: {direction}")
|
|
69
|
-
if item_name == "dotfiles" and system() == "Linux":
|
|
68
|
+
raise RuntimeError(f"Unknown direction: {direction}")
|
|
69
|
+
if item_name == "dotfiles" and system() == "Linux":
|
|
70
70
|
program += """\nchmod 700 ~/.ssh/*\n"""
|
|
71
71
|
console.print(Panel("🔒 SPECIAL HANDLING: SSH PERMISSIONS\n🛠️ Setting secure permissions for SSH files\n📝 Command: chmod 700 ~/.ssh/*", title="[bold blue]Special Handling: SSH Permissions[/bold blue]", border_style="blue"))
|
|
72
72
|
print_code(program, lexer="shell", desc=f"{direction} script")
|
|
@@ -76,14 +76,14 @@ def main_backup_retrieve(direction: OPTIONS, which: Optional[str] = None):
|
|
|
76
76
|
|
|
77
77
|
def main(direction: OPTIONS, which: Optional[str] = None):
|
|
78
78
|
console = Console()
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
console.print(Panel(f"🔄 {direction} OPERATION STARTED\n⏱️ {'-' * 58}", title="[bold blue]Operation Initiated[/bold blue]", border_style="blue"))
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
code = main_backup_retrieve(direction=direction, which=which)
|
|
83
83
|
from machineconfig.utils.utils import write_shell_script_to_default_program_path
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
console.print(Panel("💾 GENERATING SHELL SCRIPT\n📄 Filename: backup_retrieve.sh", title="[bold blue]Shell Script Generation[/bold blue]", border_style="blue"))
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
write_shell_script_to_default_program_path(program=code, desc="backup_retrieve.sh", preserve_cwd=True, display=True, execute=False)
|
|
88
88
|
|
|
89
89
|
|
|
@@ -70,10 +70,10 @@ def get_programs_by_category(program_name: WHICH_CAT):
|
|
|
70
70
|
program = ""
|
|
71
71
|
|
|
72
72
|
case "SystemInstallers":
|
|
73
|
-
if system() == "Windows": options_system = parse_apps_installer_windows(LIBRARY_ROOT.joinpath("setup_windows/apps.ps1").read_text())
|
|
73
|
+
if system() == "Windows": options_system = parse_apps_installer_windows(LIBRARY_ROOT.joinpath("setup_windows/apps.ps1").read_text(encoding="utf-8"))
|
|
74
74
|
elif system() == "Linux":
|
|
75
|
-
options_system_1 = parse_apps_installer_linux(LIBRARY_ROOT.joinpath("setup_linux/apps_dev.sh").read_text())
|
|
76
|
-
options_system_2 = parse_apps_installer_linux(LIBRARY_ROOT.joinpath("setup_linux/apps.sh").read_text())
|
|
75
|
+
options_system_1 = parse_apps_installer_linux(LIBRARY_ROOT.joinpath("setup_linux/apps_dev.sh").read_text(encoding="utf-8"))
|
|
76
|
+
options_system_2 = parse_apps_installer_linux(LIBRARY_ROOT.joinpath("setup_linux/apps.sh").read_text(encoding="utf-8"))
|
|
77
77
|
options_system = {**options_system_1, **options_system_2}
|
|
78
78
|
else: raise NotImplementedError(f"❌ System {system()} not supported")
|
|
79
79
|
program_names = choose_multiple_options(msg="", options=sorted(list(options_system.keys())), header="🚀 CHOOSE DEV APP")
|
|
@@ -1,21 +1,135 @@
|
|
|
1
1
|
"""Update repositories with fancy output
|
|
2
2
|
"""
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import git
|
|
4
|
+
import subprocess
|
|
5
|
+
import hashlib
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
5
8
|
from machineconfig.utils.utils import DEFAULTS_PATH
|
|
6
9
|
from machineconfig.utils.utils2 import read_ini
|
|
7
|
-
from platform import system
|
|
8
10
|
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
def _get_file_hash(file_path: Path) -> str | None:
|
|
13
|
+
"""Get SHA256 hash of a file, return None if file doesn't exist."""
|
|
14
|
+
if not file_path.exists():
|
|
15
|
+
return None
|
|
16
|
+
return hashlib.sha256(file_path.read_bytes()).hexdigest()
|
|
17
|
+
|
|
11
18
|
|
|
19
|
+
def _set_permissions_recursive(path: Path, executable: bool = True) -> None:
|
|
20
|
+
"""Set permissions recursively for a directory."""
|
|
21
|
+
if not path.exists():
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
if path.is_file():
|
|
25
|
+
if executable:
|
|
26
|
+
path.chmod(0o755)
|
|
27
|
+
else:
|
|
28
|
+
path.chmod(0o644)
|
|
29
|
+
elif path.is_dir():
|
|
30
|
+
path.chmod(0o755)
|
|
31
|
+
for item in path.rglob('*'):
|
|
32
|
+
_set_permissions_recursive(item, executable)
|
|
12
33
|
|
|
13
|
-
|
|
34
|
+
|
|
35
|
+
def _run_uv_sync(repo_path: Path) -> None:
|
|
36
|
+
"""Run uv sync in the given repository path."""
|
|
37
|
+
try:
|
|
38
|
+
print(f"🔄 Running uv sync in {repo_path}")
|
|
39
|
+
result = subprocess.run(
|
|
40
|
+
["uv", "sync"],
|
|
41
|
+
cwd=repo_path,
|
|
42
|
+
capture_output=True,
|
|
43
|
+
text=True,
|
|
44
|
+
check=True
|
|
45
|
+
)
|
|
46
|
+
print("✅ uv sync completed successfully")
|
|
47
|
+
if result.stdout:
|
|
48
|
+
print(f"📝 Output: {result.stdout}")
|
|
49
|
+
except subprocess.CalledProcessError as e:
|
|
50
|
+
print(f"❌ uv sync failed: {e}")
|
|
51
|
+
if e.stderr:
|
|
52
|
+
print(f"📝 Error: {e.stderr}")
|
|
53
|
+
except FileNotFoundError:
|
|
54
|
+
print("⚠️ uv command not found. Please install uv first.")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _update_repository(repo: git.Repo) -> bool:
|
|
58
|
+
"""Update a single repository and return True if pyproject.toml or uv.lock changed."""
|
|
59
|
+
repo_path = Path(repo.working_dir)
|
|
60
|
+
print(f"🔄 {'Updating ' + str(repo_path):.^80}")
|
|
61
|
+
|
|
62
|
+
# Check if this repo has pyproject.toml or uv.lock
|
|
63
|
+
pyproject_path = repo_path / "pyproject.toml"
|
|
64
|
+
uv_lock_path = repo_path / "uv.lock"
|
|
65
|
+
|
|
66
|
+
# Get hashes before pull
|
|
67
|
+
pyproject_hash_before = _get_file_hash(pyproject_path)
|
|
68
|
+
uv_lock_hash_before = _get_file_hash(uv_lock_path)
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
# Perform git pull for each remote
|
|
72
|
+
dependencies_changed = False
|
|
73
|
+
for remote in repo.remotes:
|
|
74
|
+
try:
|
|
75
|
+
print(f"📥 Pulling from {remote.name} {repo.active_branch.name}")
|
|
76
|
+
pull_info = remote.pull(repo.active_branch.name)
|
|
77
|
+
for info in pull_info:
|
|
78
|
+
if info.flags & info.FAST_FORWARD:
|
|
79
|
+
print("✅ Fast-forward pull completed")
|
|
80
|
+
elif info.flags & info.NEW_HEAD:
|
|
81
|
+
print("✅ Repository updated")
|
|
82
|
+
else:
|
|
83
|
+
print(f"✅ Pull completed: {info.flags}")
|
|
84
|
+
except Exception as e:
|
|
85
|
+
print(f"⚠️ Failed to pull from {remote.name}: {e}")
|
|
86
|
+
continue
|
|
87
|
+
|
|
88
|
+
# Check if pyproject.toml or uv.lock changed after pull
|
|
89
|
+
pyproject_hash_after = _get_file_hash(pyproject_path)
|
|
90
|
+
uv_lock_hash_after = _get_file_hash(uv_lock_path)
|
|
91
|
+
|
|
92
|
+
if pyproject_hash_before != pyproject_hash_after:
|
|
93
|
+
print("📋 pyproject.toml has changed")
|
|
94
|
+
dependencies_changed = True
|
|
95
|
+
|
|
96
|
+
if uv_lock_hash_before != uv_lock_hash_after:
|
|
97
|
+
print("🔒 uv.lock has changed")
|
|
98
|
+
dependencies_changed = True
|
|
99
|
+
|
|
100
|
+
# Special handling for machineconfig repository
|
|
101
|
+
if "machineconfig" in str(repo_path):
|
|
102
|
+
print("🛠 Special handling for machineconfig repository...")
|
|
103
|
+
scripts_path = Path.home() / "scripts"
|
|
104
|
+
if scripts_path.exists():
|
|
105
|
+
_set_permissions_recursive(scripts_path)
|
|
106
|
+
print(f"✅ Set permissions for {scripts_path}")
|
|
107
|
+
|
|
108
|
+
linux_jobs_path = repo_path / "src" / "machineconfig" / "jobs" / "linux"
|
|
109
|
+
if linux_jobs_path.exists():
|
|
110
|
+
_set_permissions_recursive(linux_jobs_path)
|
|
111
|
+
print(f"✅ Set permissions for {linux_jobs_path}")
|
|
112
|
+
|
|
113
|
+
lf_exe_path = repo_path / "src" / "machineconfig" / "settings" / "lf" / "linux" / "exe"
|
|
114
|
+
if lf_exe_path.exists():
|
|
115
|
+
_set_permissions_recursive(lf_exe_path)
|
|
116
|
+
print(f"✅ Set permissions for {lf_exe_path}")
|
|
117
|
+
|
|
118
|
+
return dependencies_changed
|
|
119
|
+
|
|
120
|
+
except Exception as e:
|
|
121
|
+
print(f"❌ Error updating repository {repo_path}: {e}")
|
|
122
|
+
return False
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def main(verbose: bool = True) -> str:
|
|
126
|
+
"""Main function to update all configured repositories."""
|
|
14
127
|
_ = verbose
|
|
15
|
-
repos: list[str] = ["~/code/
|
|
128
|
+
repos: list[str] = ["~/code/machineconfig", "~/code/machineconfig", ]
|
|
16
129
|
try:
|
|
17
130
|
tmp = read_ini(DEFAULTS_PATH)['general']['repos'].split(",")
|
|
18
|
-
if tmp[-1] == "":
|
|
131
|
+
if tmp[-1] == "":
|
|
132
|
+
tmp = tmp[:-1]
|
|
19
133
|
repos += tmp
|
|
20
134
|
except (FileNotFoundError, KeyError, IndexError):
|
|
21
135
|
print(f"""
|
|
@@ -26,7 +140,7 @@ def main(verbose: bool=True) -> str:
|
|
|
26
140
|
print("""
|
|
27
141
|
┌────────────────────────────────────────────────────────────────
|
|
28
142
|
│ ✨ Example Configuration:
|
|
29
|
-
│
|
|
143
|
+
│
|
|
30
144
|
│ [general]
|
|
31
145
|
│ repos = ~/code/repo1,~/code/repo2
|
|
32
146
|
│ rclone_config_name = onedrivePersonal
|
|
@@ -34,57 +148,31 @@ def main(verbose: bool=True) -> str:
|
|
|
34
148
|
│ to_email = myemail@email.com
|
|
35
149
|
└────────────────────────────────────────────────────────────────""")
|
|
36
150
|
|
|
37
|
-
|
|
151
|
+
# Process repositories
|
|
152
|
+
repos_with_changes = []
|
|
38
153
|
for a_package_path in repos:
|
|
39
154
|
try:
|
|
40
|
-
|
|
41
|
-
repo = git.Repo(str(
|
|
42
|
-
|
|
155
|
+
expanded_path = PathExtended(a_package_path).expanduser()
|
|
156
|
+
repo = git.Repo(str(expanded_path), search_parent_directories=True)
|
|
157
|
+
|
|
158
|
+
# Update repository and check if dependencies changed
|
|
159
|
+
dependencies_changed = _update_repository(repo)
|
|
160
|
+
|
|
161
|
+
if dependencies_changed:
|
|
162
|
+
repos_with_changes.append(Path(repo.working_dir))
|
|
163
|
+
|
|
43
164
|
except Exception as ex:
|
|
44
|
-
print(f"""
|
|
45
|
-
|
|
46
|
-
Path: {a_package_path}
|
|
47
|
-
Exception: {ex}
|
|
165
|
+
print(f"""❌ Repository Error: Path: {a_package_path}
|
|
166
|
+
Exception: {ex}
|
|
48
167
|
{'-' * 50}""")
|
|
49
168
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if "machineconfig" in str(a_repo.working_dir): # special treatment because of executables.
|
|
54
|
-
an_addition = f"""
|
|
55
|
-
echo ""
|
|
56
|
-
echo "🔄 {("Updating " + str(a_repo.working_dir)).center(80, "═")}"
|
|
57
|
-
echo "🛠 Special handling for machineconfig repository..."
|
|
58
|
-
cd "{a_repo.working_dir}"
|
|
59
|
-
# git reset --hard
|
|
60
|
-
git pull origin &
|
|
61
|
-
chmod +x ~/scripts -R
|
|
62
|
-
chmod +x ~/code/machineconfig/src/machineconfig/jobs/linux -R
|
|
63
|
-
chmod +x ~/code/machineconfig/src/machineconfig/settings/lf/linux/exe -R
|
|
64
|
-
"""
|
|
65
|
-
additions.append(an_addition)
|
|
66
|
-
else:
|
|
67
|
-
additions.append(f"""
|
|
68
|
-
echo "🔄 {("Updating " + str(a_repo.working_dir)).center(80, "═")}"
|
|
69
|
-
cd "{a_repo.working_dir}"
|
|
70
|
-
{sep.join([f'git pull {remote.name} {a_repo.active_branch.name} &' for remote in a_repo.remotes])}
|
|
71
|
-
"""
|
|
72
|
-
)
|
|
73
|
-
program = "\n".join(additions)
|
|
169
|
+
# Run uv sync for repositories where pyproject.toml or uv.lock changed
|
|
170
|
+
for repo_path in repos_with_changes:
|
|
171
|
+
_run_uv_sync(repo_path)
|
|
74
172
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
echo "🔄 {("Updating " + str(a_repo.working_dir)).center(80, "═")}"
|
|
78
|
-
cd "{a_repo.working_dir}"
|
|
79
|
-
{sep.join([f'git pull {remote.name} {a_repo.active_branch.name}' for remote in a_repo.remotes])}
|
|
80
|
-
""" for a_repo in repos_objs])
|
|
81
|
-
else: raise NotImplementedError(f"""
|
|
82
|
-
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
83
|
-
┃ ⚠️ Unsupported System: {system()}
|
|
84
|
-
┃ ℹ️ This functionality is only available on Windows and Linux
|
|
85
|
-
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
|
|
86
|
-
return program
|
|
173
|
+
# print("\n🎉 All repositories updated successfully!")
|
|
174
|
+
return """echo "🎉 All repositories updated successfully!" """
|
|
87
175
|
|
|
88
176
|
|
|
89
177
|
if __name__ == '__main__':
|
|
90
|
-
|
|
178
|
+
main()
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
from machineconfig.utils.path_reduced import
|
|
5
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
6
6
|
from machineconfig.profile.create import symlink_func
|
|
7
7
|
from machineconfig.utils.utils import LIBRARY_ROOT, REPO_ROOT
|
|
8
8
|
import argparse
|
|
@@ -25,7 +25,7 @@ def main():
|
|
|
25
25
|
elif ".config" in str(orig_path): junction = orig_path.split(at=".config", sep=-1)[1]
|
|
26
26
|
else: junction = orig_path.rel2home()
|
|
27
27
|
new_path = REPO_ROOT.joinpath(junction)
|
|
28
|
-
else:
|
|
28
|
+
else:
|
|
29
29
|
dest_path = PathExtended(args.dest).expanduser().absolute()
|
|
30
30
|
dest_path.mkdir(parents=True, exist_ok=True)
|
|
31
31
|
new_path = dest_path.joinpath(orig_path.name)
|
|
@@ -35,7 +35,7 @@ def main():
|
|
|
35
35
|
print("""
|
|
36
36
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
37
37
|
┃ ✅ Symbolic Link Created Successfully
|
|
38
|
-
┃
|
|
38
|
+
┃
|
|
39
39
|
┃ 🔄 To enshrine this mapping, add the following to mapper.toml:
|
|
40
40
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
|
|
41
41
|
print(f"""
|
|
@@ -1,63 +1,224 @@
|
|
|
1
1
|
|
|
2
|
+
"""Utility to launch multiple AI agent prompts in a Zellij session.
|
|
3
|
+
|
|
4
|
+
Improved design notes:
|
|
5
|
+
* Clear separation of: input collection, prompt preparation, agent launch.
|
|
6
|
+
* Configurable max agent cap (default 15) with interactive confirmation if exceeded.
|
|
7
|
+
* Added type aliases + docstrings for maintainability.
|
|
8
|
+
* Preserves original core behavior & command generation for each agent type.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
2
12
|
|
|
3
13
|
from pathlib import Path
|
|
4
|
-
|
|
14
|
+
import shlex
|
|
15
|
+
from math import ceil
|
|
16
|
+
from typing import Literal, TypeAlias, get_args, Iterable
|
|
17
|
+
|
|
5
18
|
from machineconfig.cluster.sessions_managers.zellij_local_manager import ZellijLocalManager
|
|
19
|
+
from machineconfig.utils.utils2 import randstr
|
|
20
|
+
import random
|
|
21
|
+
# import time
|
|
22
|
+
|
|
23
|
+
AGENTS: TypeAlias = Literal["cursor-agent", "gemini", "crush", "q",
|
|
24
|
+
# warp terminal
|
|
25
|
+
]
|
|
26
|
+
TabConfig = dict[str, tuple[str, str]] # tab name -> (cwd, command)
|
|
27
|
+
DEFAULT_AGENT_CAP = 6
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_gemini_api_keys() -> list[str]:
|
|
31
|
+
from machineconfig.utils.utils2 import read_ini
|
|
32
|
+
config = read_ini(Path.home().joinpath("dotfiles/creds/llm/gemini/api_keys.ini"))
|
|
33
|
+
res: list[str] = []
|
|
34
|
+
for a_section_name in list(config.sections()):
|
|
35
|
+
a_section = config[a_section_name]
|
|
36
|
+
if "api_key" in a_section:
|
|
37
|
+
api_key = a_section["api_key"].strip()
|
|
38
|
+
if api_key:
|
|
39
|
+
res.append(api_key)
|
|
40
|
+
# res = [v for k, v in config.items("api_keys") if k.startswith("key") and v.strip() != ""]
|
|
41
|
+
print(f"Found {len(res)} Gemini API keys configured.")
|
|
42
|
+
return res
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _search_python_files(repo_root: Path, keyword: str) -> list[Path]:
|
|
46
|
+
"""Return all Python files under repo_root whose text contains keyword.
|
|
47
|
+
|
|
48
|
+
Errors reading individual files are ignored (decoded with 'ignore').
|
|
49
|
+
"""
|
|
50
|
+
py_files = list(repo_root.rglob("*.py"))
|
|
51
|
+
keyword_lower = keyword.lower()
|
|
52
|
+
matches: list[Path] = []
|
|
53
|
+
for f in py_files:
|
|
54
|
+
try:
|
|
55
|
+
if keyword_lower in f.read_text(encoding="utf-8", errors="ignore").lower():
|
|
56
|
+
matches.append(f)
|
|
57
|
+
except OSError:
|
|
58
|
+
# Skip unreadable file
|
|
59
|
+
continue
|
|
60
|
+
return matches
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _write_list_file(target: Path, files: Iterable[Path]) -> None:
|
|
64
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
65
|
+
target.write_text("\n".join(str(f) for f in files), encoding="utf-8")
|
|
66
|
+
def _chunk_prompts(prompts: list[str], max_agents: int) -> list[str]:
|
|
67
|
+
prompts = [p for p in prompts if p.strip() != ""] # drop blank entries
|
|
68
|
+
if len(prompts) <= max_agents:
|
|
69
|
+
return prompts
|
|
70
|
+
print(f"Chunking {len(prompts)} prompts into groups for up to {max_agents} agents because it exceeds the cap.")
|
|
71
|
+
chunk_size = ceil(len(prompts) / max_agents)
|
|
72
|
+
grouped: list[str] = []
|
|
73
|
+
for i in range(0, len(prompts), chunk_size):
|
|
74
|
+
grouped.append("\nTargeted Locations:\n".join(prompts[i : i + chunk_size]))
|
|
75
|
+
return grouped
|
|
76
|
+
def _confirm(message: str, default_no: bool = True) -> bool:
|
|
77
|
+
suffix = "[y/N]" if default_no else "[Y/n]"
|
|
78
|
+
answer = input(f"{message} {suffix} ").strip().lower()
|
|
79
|
+
if answer in {"y", "yes"}:
|
|
80
|
+
return True
|
|
81
|
+
if not default_no and answer == "":
|
|
82
|
+
return True
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def launch_agents(repo_root: Path, prompts: list[str], agent: AGENTS, *, max_agents: int = DEFAULT_AGENT_CAP) -> TabConfig:
|
|
87
|
+
"""Create tab configuration for a set of agent prompts.
|
|
6
88
|
|
|
89
|
+
If number of prompts exceeds max_agents, ask user for confirmation.
|
|
90
|
+
(Original behavior raised an error; now interactive override.)
|
|
91
|
+
"""
|
|
92
|
+
if not prompts:
|
|
93
|
+
raise ValueError("No prompts provided")
|
|
94
|
+
|
|
95
|
+
if len(prompts) > max_agents:
|
|
96
|
+
proceed = _confirm(
|
|
97
|
+
message=(
|
|
98
|
+
f"You are about to launch {len(prompts)} agents which exceeds the cap ({max_agents}). Proceed?"
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
if not proceed:
|
|
102
|
+
print("Aborting per user choice.")
|
|
103
|
+
return {}
|
|
104
|
+
|
|
105
|
+
tab_config: TabConfig = {}
|
|
106
|
+
tmp_dir = repo_root / ".ai" / f"tmp_prompts/{randstr()}"
|
|
107
|
+
tmp_dir.mkdir(parents=True, exist_ok=True)
|
|
7
108
|
|
|
8
|
-
def launch_agents(repo_root: Path, prompts: list[str]):
|
|
9
|
-
tab_config: dict[str, tuple[str, str]] = {}
|
|
10
109
|
for idx, a_prompt in enumerate(prompts):
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
110
|
+
prompt_path = tmp_dir / f"agent{idx}_prompt.txt"
|
|
111
|
+
prompt_path.write_text(a_prompt, encoding="utf-8")
|
|
112
|
+
cmd_path = tmp_dir / f"agent{idx}_cmd.sh"
|
|
113
|
+
match agent:
|
|
114
|
+
case "gemini":
|
|
115
|
+
# model = "gemini-2.5-pro"
|
|
116
|
+
# model = "gemini-2.5-flash-lite"
|
|
117
|
+
model = None # auto-select
|
|
118
|
+
if model is None:
|
|
119
|
+
model_arg = ""
|
|
120
|
+
else:
|
|
121
|
+
model_arg = f"--model {shlex.quote(model)}"
|
|
122
|
+
# Need a real shell for the pipeline; otherwise '| gemini ...' is passed as args to 'cat'
|
|
123
|
+
safe_path = shlex.quote(str(prompt_path))
|
|
124
|
+
api_keys = get_gemini_api_keys()
|
|
125
|
+
api_key = api_keys[idx % len(api_keys)] if api_keys else ""
|
|
126
|
+
# Export the environment variable so it's available to subshells
|
|
127
|
+
cmd = f"""
|
|
128
|
+
export GEMINI_API_KEY={shlex.quote(api_key)}
|
|
129
|
+
echo "Using Gemini API key $GEMINI_API_KEY"
|
|
130
|
+
cat {prompt_path}
|
|
131
|
+
GEMINI_API_KEY={shlex.quote(api_key)} bash -lc 'cat {safe_path} | gemini {model_arg} --yolo --prompt'
|
|
132
|
+
"""
|
|
133
|
+
case "cursor-agent":
|
|
134
|
+
# As originally implemented
|
|
135
|
+
cmd = f"""
|
|
136
|
+
|
|
137
|
+
cursor-agent --print --output-format text < {prompt_path}
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
case "crush":
|
|
141
|
+
cmd = f"""
|
|
142
|
+
# cat {prompt_path} | crush run
|
|
143
|
+
crush run {prompt_path}
|
|
144
|
+
"""
|
|
145
|
+
case "q":
|
|
146
|
+
cmd = f"""
|
|
147
|
+
q chat --no-interactive --trust-all-tools {prompt_path}
|
|
148
|
+
"""
|
|
149
|
+
case _:
|
|
150
|
+
raise ValueError(f"Unsupported agent type: {agent}")
|
|
151
|
+
random_sleep_time = random.uniform(0, 5)
|
|
152
|
+
cmd_prefix = f"""
|
|
153
|
+
echo "Sleeping for {random_sleep_time:.2f} seconds to stagger agent startups..."
|
|
154
|
+
sleep {random_sleep_time:.2f}
|
|
155
|
+
echo "Launching `{agent}` with prompt from {prompt_path}"
|
|
156
|
+
echo "Launching `{agent}` with command from {cmd_path}"
|
|
157
|
+
echo "--------START OF AGENT OUTPUT--------"
|
|
158
|
+
sleep 0.1
|
|
159
|
+
"""
|
|
160
|
+
cmd_postfix = """
|
|
161
|
+
sleep 0.1
|
|
162
|
+
echo "---------END OF AGENT OUTPUT---------"
|
|
163
|
+
"""
|
|
164
|
+
cmd_path.write_text(cmd_prefix+cmd+cmd_postfix, encoding="utf-8")
|
|
165
|
+
fire_cmd = f"bash {shlex.quote(str(cmd_path))}"
|
|
166
|
+
tab_config[f"Agent{idx}"] = (str(repo_root), fire_cmd)
|
|
167
|
+
|
|
17
168
|
print(f"Launching a template with #{len(tab_config)} agents")
|
|
18
169
|
return tab_config
|
|
19
170
|
|
|
20
171
|
|
|
21
|
-
def main():
|
|
172
|
+
def main(): # noqa: C901 - (complexity acceptable for CLI glue)
|
|
22
173
|
repo_root = Path.cwd()
|
|
23
174
|
print(f"Operating @ {repo_root}")
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
175
|
+
|
|
176
|
+
file_path_input = input("Enter path to target file [press Enter to generate it from searching]: ").strip()
|
|
177
|
+
if file_path_input == "":
|
|
178
|
+
keyword = input("Enter keyword to search recursively for all .py files containing it: ").strip()
|
|
179
|
+
if not keyword:
|
|
180
|
+
print("No keyword supplied. Exiting.")
|
|
181
|
+
return
|
|
182
|
+
matching_files = _search_python_files(repo_root, keyword)
|
|
32
183
|
if not matching_files:
|
|
33
184
|
print(f"💥 No .py files found containing keyword: {keyword}")
|
|
34
185
|
return
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
186
|
+
for idx, mf in enumerate(matching_files):
|
|
187
|
+
print(f"{idx:>3}: {mf}")
|
|
188
|
+
print(f"\nFound {len(matching_files)} .py files containing keyword: {keyword}")
|
|
189
|
+
target_list_file = repo_root / ".ai" / "target_file.txt"
|
|
190
|
+
_write_list_file(target_list_file, matching_files)
|
|
39
191
|
separator = "\n"
|
|
192
|
+
source_text = target_list_file.read_text(encoding="utf-8", errors="ignore")
|
|
40
193
|
else:
|
|
41
|
-
|
|
194
|
+
target_file_path = Path(file_path_input).expanduser().resolve()
|
|
195
|
+
if not target_file_path.exists() or not target_file_path.is_file():
|
|
196
|
+
print(f"Invalid file path: {target_file_path}")
|
|
197
|
+
return
|
|
198
|
+
separator = input("Enter separator [\\n]: ").strip() or "\n"
|
|
199
|
+
if not target_file_path.exists():
|
|
200
|
+
print(f"File does not exist: {target_file_path}")
|
|
201
|
+
return
|
|
202
|
+
source_text = target_file_path.read_text(encoding="utf-8", errors="ignore")
|
|
42
203
|
|
|
43
|
-
|
|
204
|
+
raw_prompts = source_text.split(separator)
|
|
205
|
+
print(f"Loaded {len(raw_prompts)} raw prompts from source.")
|
|
44
206
|
prefix = input("Enter prefix prompt: ")
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
tab_config = launch_agents(repo_root=repo_root, prompts=combined_prompts)
|
|
207
|
+
combined_prompts = _chunk_prompts(raw_prompts, DEFAULT_AGENT_CAP)
|
|
208
|
+
combined_prompts = [prefix + "\n" + p for p in combined_prompts]
|
|
209
|
+
|
|
210
|
+
from machineconfig.utils.options import choose_one_option
|
|
211
|
+
agent_selected = choose_one_option(header="Select agent type", options=get_args(AGENTS))
|
|
212
|
+
|
|
213
|
+
tab_config = launch_agents(
|
|
214
|
+
repo_root=repo_root,
|
|
215
|
+
prompts=combined_prompts,
|
|
216
|
+
agent=agent_selected,
|
|
217
|
+
max_agents=DEFAULT_AGENT_CAP,
|
|
218
|
+
)
|
|
219
|
+
if not tab_config:
|
|
220
|
+
return
|
|
221
|
+
|
|
61
222
|
from machineconfig.utils.utils2 import randstr
|
|
62
223
|
random_name = randstr(length=3)
|
|
63
224
|
manager = ZellijLocalManager(session2zellij_tabs={"Agents": tab_config}, session_name_prefix=random_name)
|
|
@@ -65,5 +226,5 @@ def main():
|
|
|
65
226
|
manager.run_monitoring_routine()
|
|
66
227
|
|
|
67
228
|
|
|
68
|
-
if __name__ == "__main__":
|
|
229
|
+
if __name__ == "__main__": # pragma: no cover
|
|
69
230
|
main()
|