machineconfig 5.15__py3-none-any.whl → 7.98__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.
Files changed (472) hide show
  1. machineconfig/__init__.py +0 -28
  2. machineconfig/cluster/remote/cloud_manager.py +1 -1
  3. machineconfig/cluster/remote/distribute.py +0 -1
  4. machineconfig/cluster/remote/file_manager.py +0 -2
  5. machineconfig/cluster/remote/script_execution.py +0 -1
  6. machineconfig/cluster/sessions_managers/{utils → helpers}/enhanced_command_runner.py +4 -6
  7. machineconfig/cluster/sessions_managers/utils/load_balancer.py +1 -1
  8. machineconfig/cluster/sessions_managers/utils/maker.py +69 -0
  9. machineconfig/cluster/sessions_managers/wt_local.py +114 -289
  10. machineconfig/cluster/sessions_managers/wt_local_manager.py +70 -210
  11. machineconfig/cluster/sessions_managers/wt_remote.py +51 -43
  12. machineconfig/cluster/sessions_managers/wt_remote_manager.py +52 -198
  13. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +6 -19
  14. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  15. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  16. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +4 -2
  17. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  18. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  19. machineconfig/cluster/sessions_managers/zellij_local.py +81 -375
  20. machineconfig/cluster/sessions_managers/zellij_local_manager.py +25 -170
  21. machineconfig/cluster/sessions_managers/zellij_remote.py +40 -41
  22. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +16 -12
  23. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +4 -8
  24. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +5 -20
  25. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +3 -9
  26. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -1
  27. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper.py +298 -0
  28. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_restart.py +77 -0
  29. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_with_panes.py +228 -0
  30. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_manager_helper.py +165 -0
  31. machineconfig/jobs/{python → installer}/check_installations.py +2 -3
  32. machineconfig/jobs/installer/custom/boxes.py +61 -0
  33. machineconfig/jobs/installer/custom/hx.py +76 -19
  34. machineconfig/jobs/installer/custom/yazi.py +119 -0
  35. machineconfig/jobs/installer/custom_dev/alacritty.py +4 -4
  36. machineconfig/jobs/installer/custom_dev/brave.py +5 -9
  37. machineconfig/jobs/installer/custom_dev/cloudflare_warp_cli.py +23 -0
  38. machineconfig/jobs/installer/custom_dev/code.py +4 -1
  39. machineconfig/jobs/installer/custom_dev/dubdb_adbc.py +30 -0
  40. machineconfig/jobs/installer/custom_dev/nerdfont.py +1 -1
  41. machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +33 -28
  42. machineconfig/jobs/installer/custom_dev/sysabc.py +139 -0
  43. machineconfig/jobs/installer/custom_dev/wezterm.py +2 -19
  44. machineconfig/jobs/installer/custom_dev/winget.py +10 -14
  45. machineconfig/jobs/installer/installer_data.json +1487 -229
  46. machineconfig/jobs/installer/linux_scripts/brave.sh +4 -14
  47. machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +5 -17
  48. machineconfig/jobs/installer/linux_scripts/docker.sh +5 -17
  49. machineconfig/jobs/installer/linux_scripts/docker_start.sh +6 -14
  50. machineconfig/jobs/installer/linux_scripts/edge.sh +3 -11
  51. machineconfig/jobs/{linux/msc → installer/linux_scripts}/lid.sh +2 -8
  52. machineconfig/jobs/installer/linux_scripts/nerdfont.sh +5 -17
  53. machineconfig/jobs/{linux/msc → installer/linux_scripts}/network.sh +2 -8
  54. machineconfig/jobs/installer/linux_scripts/q.sh +10 -6
  55. machineconfig/jobs/installer/linux_scripts/redis.sh +6 -17
  56. machineconfig/jobs/installer/linux_scripts/vscode.sh +5 -17
  57. machineconfig/jobs/installer/linux_scripts/wezterm.sh +4 -12
  58. machineconfig/jobs/installer/package_groups.py +106 -177
  59. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  60. machineconfig/logger.py +0 -1
  61. machineconfig/profile/backup.toml +49 -0
  62. machineconfig/profile/bash_shell_profiles.md +11 -0
  63. machineconfig/profile/create_helper.py +62 -0
  64. machineconfig/profile/create_links.py +288 -0
  65. machineconfig/profile/create_links_export.py +100 -0
  66. machineconfig/profile/create_shell_profile.py +147 -0
  67. machineconfig/profile/mapper.toml +263 -0
  68. machineconfig/scripts/__init__.py +0 -4
  69. machineconfig/scripts/linux/{share_cloud.sh → other/share_cloud.sh} +14 -25
  70. machineconfig/scripts/linux/wrap_mcfg +46 -0
  71. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  72. machineconfig/scripts/python/agents.py +123 -117
  73. machineconfig/scripts/python/ai/initai.py +3 -28
  74. machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
  75. machineconfig/scripts/python/ai/scripts/command_runner.sh +9 -0
  76. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +17 -18
  77. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +17 -18
  78. machineconfig/scripts/python/ai/solutions/_shared.py +9 -1
  79. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
  80. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
  81. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
  82. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +5 -5
  83. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +5 -1
  84. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
  85. machineconfig/scripts/python/ai/solutions/copilot/prompts/pyright_fix.md +16 -0
  86. machineconfig/scripts/python/ai/solutions/generic.py +28 -5
  87. machineconfig/scripts/python/ai/utils/generate_files.py +348 -0
  88. machineconfig/scripts/python/ai/utils/vscode_tasks.py +37 -0
  89. machineconfig/scripts/python/cloud.py +29 -0
  90. machineconfig/scripts/python/croshell.py +137 -113
  91. machineconfig/scripts/python/devops.py +61 -101
  92. machineconfig/scripts/python/devops_navigator.py +6 -0
  93. machineconfig/scripts/python/env_manager/__init__.py +1 -0
  94. machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
  95. machineconfig/scripts/python/env_manager/path_manager_backend.py +47 -0
  96. machineconfig/scripts/python/env_manager/path_manager_tui.py +228 -0
  97. machineconfig/scripts/python/fire_jobs.py +110 -150
  98. machineconfig/scripts/python/ftpx.py +51 -24
  99. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  100. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  101. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  102. machineconfig/scripts/python/helpers/run_py_script.py +79 -0
  103. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  104. machineconfig/scripts/python/helpers/tmp_py_scripts/a.py +26 -0
  105. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.json +14 -0
  106. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +39 -0
  107. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_cursor_agents.py +22 -0
  108. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +55 -0
  109. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  110. machineconfig/scripts/python/helpers_agents/fire_agents_help_launch.py +126 -0
  111. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +41 -0
  112. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +10 -0
  113. machineconfig/scripts/python/helpers_agents/templates/template.ps1 +14 -0
  114. machineconfig/scripts/python/helpers_agents/templates/template.sh +32 -0
  115. machineconfig/scripts/python/{cloud_copy.py → helpers_cloud/cloud_copy.py} +30 -23
  116. machineconfig/scripts/python/{cloud_mount.py → helpers_cloud/cloud_mount.py} +29 -35
  117. machineconfig/scripts/python/{cloud_sync.py → helpers_cloud/cloud_sync.py} +12 -18
  118. machineconfig/scripts/python/{helpers → helpers_cloud}/helpers2.py +1 -1
  119. machineconfig/scripts/python/helpers_croshell/crosh.py +39 -0
  120. machineconfig/scripts/python/{start_slidev.py → helpers_croshell/start_slidev.py} +8 -9
  121. machineconfig/scripts/python/helpers_devops/cli_config.py +105 -0
  122. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +89 -0
  123. machineconfig/scripts/python/helpers_devops/cli_data.py +25 -0
  124. machineconfig/scripts/python/helpers_devops/cli_nw.py +214 -0
  125. machineconfig/scripts/python/helpers_devops/cli_repos.py +215 -0
  126. machineconfig/scripts/python/helpers_devops/cli_self.py +172 -0
  127. machineconfig/scripts/python/helpers_devops/cli_share_file.py +137 -0
  128. machineconfig/scripts/python/helpers_devops/cli_share_server.py +142 -0
  129. machineconfig/scripts/python/{share_terminal.py → helpers_devops/cli_share_terminal.py} +45 -35
  130. machineconfig/scripts/python/helpers_devops/cli_utils.py +96 -0
  131. machineconfig/scripts/python/{devops_backup_retrieve.py → helpers_devops/devops_backup_retrieve.py} +7 -10
  132. machineconfig/scripts/python/helpers_devops/devops_status.py +499 -0
  133. machineconfig/scripts/python/{devops_update_repos.py → helpers_devops/devops_update_repos.py} +68 -49
  134. machineconfig/scripts/python/helpers_devops/themes/choose_pwsh_theme.ps1 +81 -0
  135. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +3 -0
  136. machineconfig/scripts/python/{choose_wezterm_theme.py → helpers_devops/themes/choose_wezterm_theme.py} +3 -3
  137. machineconfig/scripts/python/helpers_fire_command/__init__.py +0 -0
  138. machineconfig/scripts/python/helpers_fire_command/f.py +0 -0
  139. machineconfig/scripts/python/{helpers/helpers4.py → helpers_fire_command/file_wrangler.py} +56 -20
  140. machineconfig/scripts/python/{fire_jobs_args_helper.py → helpers_fire_command/fire_jobs_args_helper.py} +5 -1
  141. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +121 -0
  142. machineconfig/scripts/python/helpers_fire_command/fire_jobs_streamlit_helper.py +0 -0
  143. machineconfig/scripts/python/helpers_msearch/__init__.py +5 -0
  144. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfg +3 -3
  145. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +59 -0
  146. machineconfig/scripts/python/helpers_navigator/__init__.py +20 -0
  147. machineconfig/scripts/python/helpers_navigator/command_builder.py +111 -0
  148. machineconfig/scripts/python/helpers_navigator/command_detail.py +44 -0
  149. machineconfig/scripts/python/helpers_navigator/command_tree.py +620 -0
  150. machineconfig/scripts/python/helpers_navigator/data_models.py +28 -0
  151. machineconfig/scripts/python/helpers_navigator/main_app.py +272 -0
  152. machineconfig/scripts/python/helpers_navigator/search_bar.py +15 -0
  153. machineconfig/scripts/python/helpers_network/__init__.py +0 -0
  154. machineconfig/scripts/python/helpers_network/address.py +132 -0
  155. machineconfig/scripts/python/{devops_add_identity.py → helpers_network/devops_add_identity.py} +0 -2
  156. machineconfig/scripts/python/helpers_network/devops_add_ssh_key.py +153 -0
  157. machineconfig/scripts/{linux → python/helpers_network}/mount_nfs +0 -1
  158. machineconfig/scripts/python/{mount_nfs.py → helpers_network/mount_nfs.py} +3 -3
  159. machineconfig/scripts/{linux → python/helpers_network}/mount_nw_drive +1 -2
  160. machineconfig/scripts/python/{mount_ssh.py → helpers_network/mount_ssh.py} +3 -3
  161. machineconfig/scripts/python/{onetimeshare.py → helpers_network/onetimeshare.py} +0 -1
  162. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +391 -0
  163. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +338 -0
  164. machineconfig/scripts/python/{wifi_conn.py → helpers_network/wifi_conn.py} +1 -53
  165. machineconfig/scripts/python/{wsl_windows_transfer.py → helpers_network/wsl_windows_transfer.py} +5 -4
  166. machineconfig/scripts/python/helpers_repos/action.py +209 -0
  167. machineconfig/scripts/python/helpers_repos/action_helper.py +150 -0
  168. machineconfig/scripts/python/{repos_helper_clone.py → helpers_repos/clone.py} +2 -3
  169. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +218 -0
  170. machineconfig/scripts/python/{repos_helper.py → helpers_repos/entrypoint.py} +9 -17
  171. machineconfig/scripts/python/helpers_repos/grource.py +340 -0
  172. machineconfig/scripts/python/{repos_helper_record.py → helpers_repos/record.py} +4 -3
  173. machineconfig/scripts/python/helpers_repos/repo_analyzer_1.py +160 -0
  174. machineconfig/scripts/python/{count_lines.py → helpers_repos/repo_analyzer_2.py} +113 -192
  175. machineconfig/scripts/python/helpers_repos/sync.py +66 -0
  176. machineconfig/scripts/python/{repos_helper_update.py → helpers_repos/update.py} +3 -3
  177. machineconfig/scripts/python/helpers_sessions/__init__.py +0 -0
  178. machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +65 -0
  179. machineconfig/scripts/python/helpers_utils/download.py +150 -0
  180. machineconfig/scripts/python/helpers_utils/path.py +185 -0
  181. machineconfig/scripts/python/interactive.py +64 -84
  182. machineconfig/scripts/python/mcfg_entry.py +58 -0
  183. machineconfig/scripts/python/msearch.py +71 -0
  184. machineconfig/scripts/python/sessions.py +119 -45
  185. machineconfig/scripts/python/terminal.py +133 -0
  186. machineconfig/scripts/python/utils.py +64 -0
  187. machineconfig/scripts/windows/mounts/Restore-ThunderbirdProfile.ps1 +92 -0
  188. machineconfig/scripts/windows/{mount_nfs.ps1 → mounts/mount_nfs.ps1} +1 -3
  189. machineconfig/scripts/windows/{mount_ssh.ps1 → mounts/mount_ssh.ps1} +1 -1
  190. machineconfig/scripts/windows/{share_smb.ps1 → mounts/share_smb.ps1} +0 -6
  191. machineconfig/scripts/windows/wrap_mcfg.ps1 +63 -0
  192. machineconfig/settings/broot/br.sh +0 -4
  193. machineconfig/settings/broot/conf.toml +1 -1
  194. machineconfig/settings/helix/config.toml +16 -0
  195. machineconfig/settings/helix/languages.toml +13 -4
  196. machineconfig/settings/helix/yazi-picker.sh +12 -0
  197. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  198. machineconfig/settings/lf/linux/exe/previewer.sh +9 -3
  199. machineconfig/settings/lf/linux/lfrc +10 -12
  200. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  201. machineconfig/settings/lf/windows/lfrc +18 -38
  202. machineconfig/settings/lf/windows/mkfile.ps1 +1 -1
  203. machineconfig/settings/linters/.ruff.toml +1 -1
  204. machineconfig/settings/lvim/windows/archive/config_additional.lua +0 -6
  205. machineconfig/settings/marimo/marimo.toml +80 -0
  206. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  207. machineconfig/settings/pistol/pistol.conf +1 -1
  208. machineconfig/settings/shells/bash/init.sh +82 -31
  209. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
  210. machineconfig/settings/shells/nushell/config.nu +2 -35
  211. machineconfig/settings/shells/nushell/env.nu +45 -6
  212. machineconfig/settings/shells/nushell/init.nu +314 -0
  213. machineconfig/settings/shells/pwsh/init.ps1 +61 -43
  214. machineconfig/settings/shells/starship/starship.toml +16 -0
  215. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  216. machineconfig/settings/shells/wt/settings.json +32 -17
  217. machineconfig/settings/shells/zsh/init.sh +89 -0
  218. machineconfig/settings/svim/linux/init.toml +0 -4
  219. machineconfig/settings/svim/windows/init.toml +0 -3
  220. machineconfig/settings/television/cable_unix/alias.toml +8 -0
  221. machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
  222. machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
  223. machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
  224. machineconfig/settings/television/cable_unix/channels.toml +19 -0
  225. machineconfig/settings/television/cable_unix/dirs.toml +13 -0
  226. machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
  227. machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
  228. machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
  229. machineconfig/settings/television/cable_unix/env.toml +17 -0
  230. machineconfig/settings/television/cable_unix/files.toml +11 -0
  231. machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
  232. machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
  233. machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
  234. machineconfig/settings/television/cable_unix/git-log.toml +12 -0
  235. machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
  236. machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
  237. machineconfig/settings/television/cable_unix/guix.toml +20 -0
  238. machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
  239. machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
  240. machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
  241. machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
  242. machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
  243. machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
  244. machineconfig/settings/television/cable_unix/procs.toml +20 -0
  245. machineconfig/settings/television/cable_unix/text.toml +17 -0
  246. machineconfig/settings/television/cable_unix/tldr.toml +18 -0
  247. machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
  248. machineconfig/settings/television/cable_windows/alias.toml +7 -0
  249. machineconfig/settings/television/cable_windows/dirs.toml +13 -0
  250. machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
  251. machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
  252. machineconfig/settings/television/cable_windows/env.toml +17 -0
  253. machineconfig/settings/television/cable_windows/files.toml +14 -0
  254. machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
  255. machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
  256. machineconfig/settings/television/cable_windows/git-log.toml +11 -0
  257. machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
  258. machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
  259. machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
  260. machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
  261. machineconfig/settings/television/cable_windows/text.toml +17 -0
  262. machineconfig/settings/yazi/init.lua +61 -0
  263. machineconfig/settings/yazi/keymap_linux.toml +94 -0
  264. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  265. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  266. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  267. machineconfig/settings/yazi/theme.toml +4 -0
  268. machineconfig/settings/yazi/yazi_linux.toml +84 -0
  269. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  270. machineconfig/setup_linux/__init__.py +11 -0
  271. machineconfig/setup_linux/apps_desktop.sh +89 -0
  272. machineconfig/setup_linux/apps_gui.sh +64 -0
  273. machineconfig/setup_linux/ssh/openssh_all.sh +25 -0
  274. machineconfig/setup_linux/ssh/openssh_wsl.sh +38 -0
  275. machineconfig/setup_linux/uv.sh +15 -0
  276. machineconfig/setup_linux/web_shortcuts/interactive.sh +26 -6
  277. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +31 -0
  278. machineconfig/setup_mac/__init__.py +16 -0
  279. machineconfig/setup_mac/apps_gui.sh +248 -0
  280. machineconfig/setup_mac/ssh/openssh_setup.sh +114 -0
  281. machineconfig/setup_mac/uv.sh +36 -0
  282. machineconfig/setup_windows/__init__.py +11 -0
  283. machineconfig/setup_windows/others/power_options.ps1 +7 -0
  284. machineconfig/setup_windows/ssh/add-sshkey.ps1 +29 -0
  285. machineconfig/setup_windows/ssh/add_identity.ps1 +11 -0
  286. machineconfig/setup_windows/ssh/openssh-server.ps1 +37 -0
  287. machineconfig/setup_windows/uv.ps1 +17 -0
  288. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +27 -10
  289. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +30 -0
  290. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  291. machineconfig/utils/accessories.py +7 -5
  292. machineconfig/utils/cloud/onedrive/README.md +139 -0
  293. machineconfig/utils/code.py +155 -105
  294. machineconfig/utils/files/art/fat_croco.txt +10 -0
  295. machineconfig/utils/files/art/halfwit_croco.txt +9 -0
  296. machineconfig/utils/files/art/happy_croco.txt +22 -0
  297. machineconfig/utils/files/art/water_croco.txt +11 -0
  298. machineconfig/utils/files/ascii_art.py +1 -1
  299. machineconfig/utils/files/dbms.py +257 -0
  300. machineconfig/utils/files/headers.py +11 -14
  301. machineconfig/utils/files/ouch/__init__.py +0 -0
  302. machineconfig/utils/files/ouch/decompress.py +45 -0
  303. machineconfig/utils/files/read.py +10 -18
  304. machineconfig/utils/installer_utils/github_release_bulk.py +156 -119
  305. machineconfig/utils/installer_utils/install_from_url.py +183 -0
  306. machineconfig/utils/installer_utils/installer_class.py +64 -181
  307. machineconfig/utils/installer_utils/installer_cli.py +175 -0
  308. machineconfig/utils/installer_utils/installer_helper.py +129 -0
  309. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +66 -97
  310. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +49 -82
  311. machineconfig/utils/io.py +77 -23
  312. machineconfig/utils/links.py +254 -162
  313. machineconfig/utils/meta.py +256 -0
  314. machineconfig/utils/notifications.py +1 -1
  315. machineconfig/utils/options.py +46 -18
  316. machineconfig/utils/options_tv.py +119 -0
  317. machineconfig/utils/path_extended.py +48 -101
  318. machineconfig/utils/path_helper.py +76 -23
  319. machineconfig/utils/procs.py +50 -70
  320. machineconfig/utils/scheduler.py +88 -124
  321. machineconfig/utils/scheduling.py +0 -3
  322. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  323. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  324. machineconfig/utils/source_of_truth.py +3 -6
  325. machineconfig/utils/ssh.py +263 -274
  326. machineconfig/utils/ssh_utils/abc.py +5 -0
  327. machineconfig/utils/ssh_utils/copy_from_here.py +111 -0
  328. machineconfig/utils/ssh_utils/copy_to_here.py +302 -0
  329. machineconfig/utils/ssh_utils/utils.py +142 -0
  330. machineconfig/utils/ssh_utils/wsl.py +210 -0
  331. machineconfig/utils/terminal.py +3 -113
  332. machineconfig/utils/tst.py +20 -0
  333. machineconfig/utils/upgrade_packages.py +114 -28
  334. machineconfig/utils/ve.py +12 -4
  335. machineconfig-7.98.dist-info/METADATA +132 -0
  336. machineconfig-7.98.dist-info/RECORD +504 -0
  337. machineconfig-7.98.dist-info/entry_points.txt +13 -0
  338. machineconfig/cluster/sessions_managers/ffile.py +0 -4
  339. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -49
  340. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -85
  341. machineconfig/jobs/linux/msc/cli_agents.sh +0 -16
  342. machineconfig/jobs/python/python_ve_symlink.py +0 -37
  343. machineconfig/jobs/python/vscode/api.py +0 -57
  344. machineconfig/jobs/python/vscode/sync_code.py +0 -73
  345. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +0 -14
  346. machineconfig/jobs/windows/start_terminal.ps1 +0 -6
  347. machineconfig/jobs/windows/startup_file.cmd +0 -2
  348. machineconfig/profile/create.py +0 -303
  349. machineconfig/profile/shell.py +0 -176
  350. machineconfig/scripts/cloud/init.sh +0 -119
  351. machineconfig/scripts/linux/agents +0 -2
  352. machineconfig/scripts/linux/choose_wezterm_theme +0 -3
  353. machineconfig/scripts/linux/cloud_copy +0 -2
  354. machineconfig/scripts/linux/cloud_mount +0 -2
  355. machineconfig/scripts/linux/cloud_repo_sync +0 -2
  356. machineconfig/scripts/linux/cloud_sync +0 -2
  357. machineconfig/scripts/linux/croshell +0 -3
  358. machineconfig/scripts/linux/devops +0 -2
  359. machineconfig/scripts/linux/fire +0 -2
  360. machineconfig/scripts/linux/ftpx +0 -2
  361. machineconfig/scripts/linux/fzf2g +0 -21
  362. machineconfig/scripts/linux/fzfag +0 -17
  363. machineconfig/scripts/linux/fzffg +0 -25
  364. machineconfig/scripts/linux/fzfrga +0 -21
  365. machineconfig/scripts/linux/gh_models +0 -2
  366. machineconfig/scripts/linux/initai +0 -2
  367. machineconfig/scripts/linux/kill_process +0 -2
  368. machineconfig/scripts/linux/scheduler +0 -2
  369. machineconfig/scripts/linux/sessions +0 -2
  370. machineconfig/scripts/linux/share_smb +0 -1
  371. machineconfig/scripts/linux/skrg +0 -4
  372. machineconfig/scripts/linux/start_slidev +0 -2
  373. machineconfig/scripts/linux/start_terminals +0 -3
  374. machineconfig/scripts/linux/warp-cli.sh +0 -122
  375. machineconfig/scripts/linux/wifi_conn +0 -2
  376. machineconfig/scripts/linux/z_ls +0 -104
  377. machineconfig/scripts/python/ai/generate_files.py +0 -83
  378. machineconfig/scripts/python/ai/solutions/copilot/prompts/allLintersAndTypeCheckers.prompt.md +0 -5
  379. machineconfig/scripts/python/cloud_repo_sync.py +0 -190
  380. machineconfig/scripts/python/count_lines_frontend.py +0 -16
  381. machineconfig/scripts/python/devops_add_ssh_key.py +0 -120
  382. machineconfig/scripts/python/dotfile.py +0 -78
  383. machineconfig/scripts/python/fire_agents_help_launch.py +0 -120
  384. machineconfig/scripts/python/fire_agents_helper_types.py +0 -12
  385. machineconfig/scripts/python/fire_jobs_route_helper.py +0 -65
  386. machineconfig/scripts/python/get_zellij_cmd.py +0 -15
  387. machineconfig/scripts/python/gh_models.py +0 -104
  388. machineconfig/scripts/python/helpers/repo_sync_helpers.py +0 -116
  389. machineconfig/scripts/python/repos.py +0 -132
  390. machineconfig/scripts/python/repos_helper_action.py +0 -378
  391. machineconfig/scripts/python/snapshot.py +0 -25
  392. machineconfig/scripts/python/start_terminals.py +0 -121
  393. machineconfig/scripts/python/t4.py +0 -17
  394. machineconfig/scripts/windows/agents.ps1 +0 -1
  395. machineconfig/scripts/windows/choose_wezterm_theme.ps1 +0 -1
  396. machineconfig/scripts/windows/cloud_copy.ps1 +0 -1
  397. machineconfig/scripts/windows/cloud_mount.ps1 +0 -1
  398. machineconfig/scripts/windows/cloud_repo_sync.ps1 +0 -1
  399. machineconfig/scripts/windows/cloud_sync.ps1 +0 -1
  400. machineconfig/scripts/windows/croshell.ps1 +0 -1
  401. machineconfig/scripts/windows/devops.ps1 +0 -1
  402. machineconfig/scripts/windows/dotfile.ps1 +0 -1
  403. machineconfig/scripts/windows/fire.ps1 +0 -1
  404. machineconfig/scripts/windows/ftpx.ps1 +0 -1
  405. machineconfig/scripts/windows/fzfb.ps1 +0 -3
  406. machineconfig/scripts/windows/fzfg.ps1 +0 -2
  407. machineconfig/scripts/windows/fzfrga.bat +0 -20
  408. machineconfig/scripts/windows/gpt.ps1 +0 -1
  409. machineconfig/scripts/windows/grep.ps1 +0 -2
  410. machineconfig/scripts/windows/initai.ps1 +0 -1
  411. machineconfig/scripts/windows/kill_process.ps1 +0 -1
  412. machineconfig/scripts/windows/nano.ps1 +0 -3
  413. machineconfig/scripts/windows/pomodoro.ps1 +0 -1
  414. machineconfig/scripts/windows/reload_path.ps1 +0 -3
  415. machineconfig/scripts/windows/scheduler.ps1 +0 -1
  416. machineconfig/scripts/windows/sessions.ps1 +0 -1
  417. machineconfig/scripts/windows/snapshot.ps1 +0 -1
  418. machineconfig/scripts/windows/start_slidev.ps1 +0 -1
  419. machineconfig/scripts/windows/start_terminals.ps1 +0 -1
  420. machineconfig/scripts/windows/wifi_conn.ps1 +0 -2
  421. machineconfig/scripts/windows/wsl_rdp_windows_port_forwarding.ps1 +0 -46
  422. machineconfig/scripts/windows/wsl_ssh_windows_port_forwarding.ps1 +0 -76
  423. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  424. machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
  425. machineconfig/settings/lf/windows/tst.ps1 +0 -1
  426. machineconfig/settings/yazi/yazi.toml +0 -4
  427. machineconfig/setup_linux/nix/cli_installation.sh +0 -157
  428. machineconfig/setup_linux/others/openssh-server_add_pub_key.sh +0 -57
  429. machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -11
  430. machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -52
  431. machineconfig/setup_windows/web_shortcuts/all.ps1 +0 -18
  432. machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +0 -36
  433. machineconfig/setup_windows/web_shortcuts/croshell.ps1 +0 -16
  434. machineconfig/setup_windows/web_shortcuts/ssh.ps1 +0 -11
  435. machineconfig/utils/ai/generate_file_checklist.py +0 -68
  436. machineconfig/utils/installer_utils/installer.py +0 -189
  437. machineconfig-5.15.dist-info/METADATA +0 -188
  438. machineconfig-5.15.dist-info/RECORD +0 -415
  439. machineconfig-5.15.dist-info/entry_points.txt +0 -18
  440. machineconfig/cluster/sessions_managers/{utils → helpers}/load_balancer_helper.py +0 -0
  441. machineconfig/scripts/linux/{share_nfs → other/share_nfs} +0 -0
  442. machineconfig/scripts/linux/{start_docker → other/start_docker} +0 -0
  443. machineconfig/scripts/linux/{switch_ip → other/switch_ip} +0 -0
  444. machineconfig/{jobs/python → scripts/python/ai/utils}/__init__.py +0 -0
  445. machineconfig/scripts/python/{helpers → helpers_agents}/__init__.py +0 -0
  446. machineconfig/{jobs/windows/msc/cli_agents.bat → scripts/python/helpers_agents/agentic_frameworks/__init__.py} +0 -0
  447. machineconfig/scripts/python/{fire_agents_help_search.py → helpers_agents/fire_agents_help_search.py} +0 -0
  448. machineconfig/scripts/python/{fire_agents_load_balancer.py → helpers_agents/fire_agents_load_balancer.py} +0 -0
  449. machineconfig/{jobs/windows/msc/cli_agents.ps1 → scripts/python/helpers_cloud/__init__.py} +0 -0
  450. machineconfig/scripts/python/{helpers → helpers_cloud}/cloud_helpers.py +1 -1
  451. /machineconfig/scripts/python/{helpers → helpers_cloud}/helpers5.py +0 -0
  452. /machineconfig/scripts/python/{fire_jobs_streamlit_helper.py → helpers_croshell/__init__.py} +0 -0
  453. /machineconfig/scripts/python/{pomodoro.py → helpers_croshell/pomodoro.py} +0 -0
  454. /machineconfig/scripts/python/{scheduler.py → helpers_croshell/scheduler.py} +0 -0
  455. /machineconfig/scripts/python/{viewer.py → helpers_croshell/viewer.py} +0 -0
  456. /machineconfig/scripts/python/{viewer_template.py → helpers_croshell/viewer_template.py} +0 -0
  457. /machineconfig/scripts/{windows/share_nfs.ps1 → python/helpers_devops/__init__.py} +0 -0
  458. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_devops/themes/__init__.py} +0 -0
  459. /machineconfig/{settings/yazi/keymap.toml → scripts/python/helpers_devops/themes/choose_starship_theme.ps1} +0 -0
  460. /machineconfig/scripts/python/{cloud_manager.py → helpers_fire_command/cloud_manager.py} +0 -0
  461. /machineconfig/scripts/{linux → python/helpers_network}/mount_drive +0 -0
  462. /machineconfig/scripts/python/{mount_nw_drive.py → helpers_network/mount_nw_drive.py} +0 -0
  463. /machineconfig/scripts/{linux → python/helpers_network}/mount_smb +0 -0
  464. /machineconfig/scripts/windows/{mount_nw.ps1 → mounts/mount_nw.ps1} +0 -0
  465. /machineconfig/scripts/windows/{mount_smb.ps1 → mounts/mount_smb.ps1} +0 -0
  466. /machineconfig/scripts/windows/{share_cloud.cmd → mounts/share_cloud.cmd} +0 -0
  467. /machineconfig/scripts/windows/{unlock_bitlocker.ps1 → mounts/unlock_bitlocker.ps1} +0 -0
  468. /machineconfig/setup_linux/{web_shortcuts → others}/android.sh +0 -0
  469. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_add_key.ps1 +0 -0
  470. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_copy-ssh-id.ps1 +0 -0
  471. {machineconfig-5.15.dist-info → machineconfig-7.98.dist-info}/WHEEL +0 -0
  472. {machineconfig-5.15.dist-info → machineconfig-7.98.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,209 @@
1
+ from machineconfig.scripts.python.helpers_repos.action_helper import GitAction, GitOperationResult, GitOperationSummary, print_git_operations_summary
2
+ from machineconfig.utils.path_extended import PathExtended
3
+ from machineconfig.utils.accessories import randstr
4
+ from machineconfig.scripts.python.helpers_repos.update import update_repository
5
+
6
+ from typing import Optional, Dict, Any, List, cast
7
+ import concurrent.futures
8
+ import os
9
+
10
+ from rich import print as pprint
11
+
12
+
13
+ def git_action(path: PathExtended, action: GitAction, mess: Optional[str], r: bool, auto_uv_sync: bool) -> GitOperationResult:
14
+ """Perform git actions using Python instead of shell scripts. Returns detailed operation result."""
15
+ from git.exc import InvalidGitRepositoryError
16
+ from git.repo import Repo
17
+
18
+ try:
19
+ repo = Repo(str(path), search_parent_directories=False)
20
+ except InvalidGitRepositoryError:
21
+ pprint(f"⚠️ Skipping {path} because it is not a git repository.")
22
+ if r:
23
+ results = [git_action(path=sub_path, action=action, mess=mess, r=r, auto_uv_sync=auto_uv_sync) for sub_path in path.search()]
24
+ # For recursive calls, we need to aggregate results somehow
25
+ # For now, return success if all recursive operations succeeded
26
+ all_successful = all(result.success for result in results)
27
+ return GitOperationResult(
28
+ repo_path=path,
29
+ action=action.value,
30
+ success=all_successful,
31
+ message=f"Recursive operation: {len([r for r in results if r.success])}/{len(results)} succeeded",
32
+ is_git_repo=False,
33
+ )
34
+ else:
35
+ return GitOperationResult(repo_path=path, action=action.value, success=False, message="Not a git repository", is_git_repo=False)
36
+
37
+ print(f">>>>>>>>> 🔧{action} - {path}")
38
+ remote_count = len(repo.remotes)
39
+
40
+ try:
41
+ if action == GitAction.commit:
42
+ if mess is None:
43
+ mess = "auto_commit_" + randstr()
44
+
45
+ # Check if there are changes to commit
46
+ if repo.is_dirty() or repo.untracked_files:
47
+ repo.git.add(A=True) # Stage all changes
48
+ repo.index.commit(mess)
49
+ print(f"✅ Committed changes with message: {mess}")
50
+ return GitOperationResult(
51
+ repo_path=path,
52
+ action=action.value,
53
+ success=True,
54
+ message=f"Committed changes with message: {mess}",
55
+ had_changes=True,
56
+ remote_count=remote_count,
57
+ )
58
+ else:
59
+ print("ℹ️ No changes to commit")
60
+ return GitOperationResult(
61
+ repo_path=path, action=action.value, success=True, message="No changes to commit", had_changes=False, remote_count=remote_count
62
+ )
63
+
64
+ elif action == GitAction.push:
65
+ if not repo.remotes:
66
+ print("⚠️ No remotes configured for push")
67
+ return GitOperationResult(repo_path=path, action=action.value, success=False, message="No remotes configured", remote_count=0)
68
+
69
+ success = True
70
+ failed_remotes = []
71
+ for remote in repo.remotes:
72
+ try:
73
+ print(f"🚀 Pushing to {remote.url}")
74
+ remote.push(repo.active_branch.name)
75
+ print(f"✅ Pushed to {remote.name}")
76
+ except Exception as e:
77
+ print(f"❌ Failed to push to {remote.name}: {e}")
78
+ failed_remotes.append(f"{remote.name}: {str(e)}")
79
+ success = False
80
+
81
+ message = "Push successful" if success else f"Push failed for: {', '.join(failed_remotes)}"
82
+ return GitOperationResult(repo_path=path, action=action.value, success=success, message=message, remote_count=remote_count)
83
+
84
+ elif action == GitAction.pull:
85
+ # Use the enhanced update function with uv sync support
86
+ try:
87
+ update_repository(repo, auto_uv_sync=auto_uv_sync, allow_password_prompt=False)
88
+ print("✅ Pull completed")
89
+ return GitOperationResult(
90
+ repo_path=path, action=action.value, success=True, message="Pull completed successfully", remote_count=remote_count
91
+ )
92
+ except Exception as e:
93
+ print(f"❌ Pull failed: {e}")
94
+ return GitOperationResult(
95
+ repo_path=path, action=action.value, success=False, message=f"Pull failed: {str(e)}", remote_count=remote_count
96
+ )
97
+
98
+ except Exception as e:
99
+ print(f"❌ Error performing {action} on {path}: {e}")
100
+ return GitOperationResult(repo_path=path, action=action.value, success=False, message=f"Error: {str(e)}", remote_count=remote_count)
101
+
102
+ # This should never be reached, but just in case
103
+ return GitOperationResult(repo_path=path, action=action.value, success=False, message="Unknown error", remote_count=remote_count)
104
+
105
+
106
+ def perform_git_operations(repos_root: PathExtended, pull: bool, commit: bool, push: bool, recursive: bool, auto_uv_sync: bool) -> None:
107
+ """Perform git operations on all repositories and provide detailed summary."""
108
+ print(f"\n🔄 Performing Git actions on repositories @ `{repos_root}`...")
109
+ summary = GitOperationSummary()
110
+ # Keep track of which operations we are performing
111
+ operations_performed: List[str] = []
112
+ if pull:
113
+ operations_performed.append("pull")
114
+ if commit:
115
+ operations_performed.append("commit")
116
+ if push:
117
+ operations_performed.append("push")
118
+
119
+ # Collect all candidate paths first
120
+ paths = list(repos_root.search("*"))
121
+
122
+ def _process_path(a_path: PathExtended) -> Dict[str, Any]:
123
+ """Worker that processes a single path and returns metadata and results."""
124
+ from git.exc import InvalidGitRepositoryError
125
+ from git.repo import Repo
126
+
127
+ result_payload: Dict[str, Any] = {"path": a_path, "is_git": False, "results": [], "repo_remotes_count": 0}
128
+ print(f"{('Handling ' + str(a_path)).center(80, '-')}")
129
+
130
+ try:
131
+ repo = Repo(str(a_path), search_parent_directories=False)
132
+ except InvalidGitRepositoryError:
133
+ result_payload["non_git"] = True
134
+ pprint(f"⚠️ Skipping {a_path} because it is not a git repository.")
135
+ return result_payload
136
+
137
+ # It's a git repo
138
+ result_payload["is_git"] = True
139
+ result_payload["repo_remotes_count"] = len(repo.remotes)
140
+
141
+ # Perform configured operations sequentially for this repo (the repo-level work is done concurrently between repos)
142
+ try:
143
+ if pull:
144
+ r = git_action(path=a_path, action=GitAction.pull, mess=None, r=recursive, auto_uv_sync=auto_uv_sync)
145
+ result_payload["results"].append(r)
146
+ if commit:
147
+ r = git_action(path=a_path, action=GitAction.commit, mess=None, r=recursive, auto_uv_sync=auto_uv_sync)
148
+ result_payload["results"].append(r)
149
+ if push:
150
+ r = git_action(path=a_path, action=GitAction.push, mess=None, r=recursive, auto_uv_sync=auto_uv_sync)
151
+ result_payload["results"].append(r)
152
+ except Exception as e:
153
+ # Capture any unexpected exception for this path
154
+ pprint(f"❌ Error processing {a_path}: {e}")
155
+
156
+ return result_payload
157
+
158
+ # Choose a reasonable number of workers
159
+ max_workers = min(32, (os.cpu_count() or 1) * 5, len(paths) or 1)
160
+
161
+ # Run the workers in parallel and aggregate results
162
+ with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as exc:
163
+ future_to_path = {exc.submit(_process_path, p): p for p in paths}
164
+ for fut in concurrent.futures.as_completed(future_to_path):
165
+ payload = fut.result()
166
+ a_path = cast(PathExtended, payload.get("path"))
167
+ summary.total_paths_processed += 1
168
+
169
+ if not payload.get("is_git"):
170
+ summary.non_git_paths += 1
171
+ continue
172
+
173
+ # git repo found
174
+ summary.git_repos_found += 1
175
+ if payload.get("repo_remotes_count", 0) == 0:
176
+ summary.repos_without_remotes.append(a_path)
177
+
178
+ for r in payload.get("results", []):
179
+ action_name = r.action if hasattr(r, "action") else ""
180
+ # Pull
181
+ if action_name == "pull":
182
+ summary.pulls_attempted += 1
183
+ if r.success:
184
+ summary.pulls_successful += 1
185
+ else:
186
+ summary.pulls_failed += 1
187
+ summary.failed_operations.append(r)
188
+ # Commit
189
+ elif action_name == "commit":
190
+ summary.commits_attempted += 1
191
+ if r.success:
192
+ if getattr(r, "had_changes", False):
193
+ summary.commits_successful += 1
194
+ else:
195
+ summary.commits_no_changes += 1
196
+ else:
197
+ summary.commits_failed += 1
198
+ summary.failed_operations.append(r)
199
+ # Push
200
+ elif action_name == "push":
201
+ summary.pushes_attempted += 1
202
+ if r.success:
203
+ summary.pushes_successful += 1
204
+ else:
205
+ summary.pushes_failed += 1
206
+ summary.failed_operations.append(r)
207
+
208
+ # Print the detailed summary
209
+ print_git_operations_summary(summary, operations_performed)
@@ -0,0 +1,150 @@
1
+ from enum import Enum
2
+ from machineconfig.utils.path_extended import PathExtended
3
+
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from rich.columns import Columns
8
+ from rich.panel import Panel
9
+ from rich.table import Table
10
+
11
+
12
+ @dataclass
13
+ class GitOperationResult:
14
+ """Result of a git operation on a single repository."""
15
+ repo_path: PathExtended
16
+ action: str
17
+ success: bool
18
+ message: str
19
+ is_git_repo: bool = True
20
+ had_changes: bool = False
21
+ remote_count: int = 0
22
+
23
+
24
+ class GitAction(Enum):
25
+ commit = "commit"
26
+ push = "push"
27
+ pull = "pull"
28
+
29
+
30
+ @dataclass
31
+ class GitOperationSummary:
32
+ """Summary of all git operations performed."""
33
+
34
+ # Basic statistics
35
+ total_paths_processed: int = 0
36
+ git_repos_found: int = 0
37
+ non_git_paths: int = 0
38
+
39
+ # Per-operation statistics
40
+ commits_attempted: int = 0
41
+ commits_successful: int = 0
42
+ commits_no_changes: int = 0
43
+ commits_failed: int = 0
44
+
45
+ pulls_attempted: int = 0
46
+ pulls_successful: int = 0
47
+ pulls_failed: int = 0
48
+
49
+ pushes_attempted: int = 0
50
+ pushes_successful: int = 0
51
+ pushes_failed: int = 0
52
+
53
+ def __post_init__(self):
54
+ self.failed_operations: list[GitOperationResult] = []
55
+ self.repos_without_remotes: list[PathExtended] = []
56
+
57
+
58
+ def print_git_operations_summary(summary: GitOperationSummary, operations_performed: list[str]) -> None:
59
+ """Print a detailed summary of git operations with rich formatting and tables."""
60
+ from rich.console import Console
61
+
62
+ console = Console()
63
+
64
+ # Main summary panel
65
+ summary_stats = [
66
+ f"Total paths processed: {summary.total_paths_processed}",
67
+ f"Git repositories found: {summary.git_repos_found}",
68
+ f"Non-git paths skipped: {summary.non_git_paths}",
69
+ ]
70
+
71
+ console.print(Panel.fit("\n".join(summary_stats), title="[bold blue]📊 Git Operations Summary[/bold blue]", border_style="blue"))
72
+
73
+ # Statistics panels in columns
74
+ stat_panels = []
75
+
76
+ if "commit" in operations_performed:
77
+ commit_stats = [
78
+ f"Attempted: {summary.commits_attempted}",
79
+ f"Successful: {summary.commits_successful}",
80
+ f"No changes: {summary.commits_no_changes}",
81
+ f"Failed: {summary.commits_failed}",
82
+ ]
83
+ stat_panels.append(Panel.fit("\n".join(commit_stats), title="[bold green]💾 Commit Operations[/bold green]", border_style="green"))
84
+
85
+ if "pull" in operations_performed:
86
+ pull_stats = [f"Attempted: {summary.pulls_attempted}", f"Successful: {summary.pulls_successful}", f"Failed: {summary.pulls_failed}"]
87
+ stat_panels.append(Panel.fit("\n".join(pull_stats), title="[bold cyan]⬇️ Pull Operations[/bold cyan]", border_style="cyan"))
88
+
89
+ if "push" in operations_performed:
90
+ push_stats = [f"Attempted: {summary.pushes_attempted}", f"Successful: {summary.pushes_successful}", f"Failed: {summary.pushes_failed}"]
91
+ stat_panels.append(Panel.fit("\n".join(push_stats), title="[bold magenta]🚀 Push Operations[/bold magenta]", border_style="magenta"))
92
+
93
+ if stat_panels:
94
+ console.print(Columns(stat_panels, equal=True, expand=True))
95
+
96
+ # Repositories without remotes warning
97
+ if summary.repos_without_remotes:
98
+ repos_table = Table(title="[bold yellow]⚠️ Repositories Without Remotes[/bold yellow]")
99
+ repos_table.add_column("Repository Name", style="cyan", no_wrap=True)
100
+ repos_table.add_column("Full Path", style="dim")
101
+
102
+ for repo_path in summary.repos_without_remotes:
103
+ repos_table.add_row(repo_path.name, str(repo_path))
104
+
105
+ console.print(repos_table)
106
+ console.print("[yellow]These repositories cannot be pushed to remote servers.[/yellow]")
107
+ elif "push" in operations_performed:
108
+ console.print("[green]✅ All repositories have remote configurations.[/green]")
109
+
110
+ # Failed operations table
111
+ if summary.failed_operations:
112
+ failed_table = Table(title=f"[bold red]❌ Failed Operations ({len(summary.failed_operations)} total)[/bold red]")
113
+ failed_table.add_column("Action", style="bold red", no_wrap=True)
114
+ failed_table.add_column("Repository", style="cyan", no_wrap=True)
115
+ failed_table.add_column("Problem", style="red")
116
+
117
+ # Group failed operations by type for better organization
118
+ failed_by_action = {}
119
+ for failed_op in summary.failed_operations:
120
+ if failed_op.action not in failed_by_action:
121
+ failed_by_action[failed_op.action] = []
122
+ failed_by_action[failed_op.action].append(failed_op)
123
+
124
+ for action, failures in failed_by_action.items():
125
+ for failure in failures:
126
+ repo_name = failure.repo_path.name if failure.is_git_repo else f"{failure.repo_path.name} (not git repo)"
127
+ problem = failure.message if failure.is_git_repo else "Not a git repository"
128
+ failed_table.add_row(action.upper(), repo_name, problem)
129
+
130
+ console.print(failed_table)
131
+ else:
132
+ console.print("[green]✅ All git operations completed successfully![/green]")
133
+
134
+ # Overall success assessment
135
+ total_failed = len(summary.failed_operations)
136
+ total_operations = summary.commits_attempted + summary.pulls_attempted + summary.pushes_attempted
137
+
138
+ if total_failed == 0 and total_operations > 0:
139
+ console.print(f"\n[bold green]🎉 SUCCESS: All {total_operations} operations completed successfully![/bold green]")
140
+ elif total_operations == 0:
141
+ console.print("\n[blue]📝 No git operations were performed.[/blue]")
142
+ else:
143
+ success_rate = ((total_operations - total_failed) / total_operations * 100) if total_operations > 0 else 0
144
+ if total_failed > 0:
145
+ console.print(
146
+ f"\n[bold yellow]⚖️ SUMMARY: {total_operations - total_failed}/{total_operations} operations succeeded ({success_rate:.1f}% success rate)[/bold yellow]"
147
+ )
148
+ console.print("[yellow]Review the failed operations table above for details on what needs attention.[/yellow]")
149
+ else:
150
+ console.print(f"\n[bold green]⚖️ SUMMARY: {total_operations}/{total_operations} operations succeeded (100% success rate)[/bold green]")
@@ -1,4 +1,3 @@
1
- from __future__ import annotations
2
1
 
3
2
  from pathlib import Path
4
3
  from typing import Literal, Optional, cast
@@ -95,8 +94,8 @@ def clone_single_repo(repo_spec: RepoRecordDict, preferred_remote: Optional[str]
95
94
 
96
95
 
97
96
  def clone_repos(spec_path: Path, preferred_remote: Optional[str], checkout_branch_flag: bool, checkout_commit_flag: bool) -> list[tuple[CloneStatus, str]]:
98
- data = cast(RepoRecordFile, read_json(path=spec_path))
99
- repos = data["repos"]
97
+ spec_file = cast(RepoRecordFile, read_json(path=spec_path))
98
+ repos = spec_file["repos"]
100
99
  results: list[tuple[CloneStatus, str]] = []
101
100
  with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), BarColumn(), MofNCompleteColumn(), TimeElapsedColumn()) as progress:
102
101
  task_id = progress.add_task("Processing repositories...", total=len(repos))
@@ -0,0 +1,218 @@
1
+
2
+ from typing import Optional, Literal, Annotated
3
+
4
+ import typer
5
+
6
+
7
+ def main(
8
+ cloud: Annotated[Optional[str], typer.Option(..., "--cloud", "-c", help="Cloud storage profile name. If not provided, uses default from config.")] = None,
9
+ repo: Annotated[Optional[str], typer.Option(..., "--repo", "-r", help="Path to the local repository. Defaults to current working directory.")] = None,
10
+ message: Annotated[Optional[str], typer.Option(..., "--message", "-m", help="Commit message for local changes.")] = None,
11
+ on_conflict: Annotated[Literal["ask", "a",
12
+ "push-local-merge", "p",
13
+ "overwrite-local", "o",
14
+ "stop-on-conflict", "s",
15
+ "remove-rclone-conflict", "r"
16
+ ], typer.Option(..., "--on-conflict", "-o", help="Action to take on merge conflict. Default is 'ask'.")] = "ask",
17
+ pwd: Annotated[Optional[str], typer.Option(..., "--password", help="Password for encryption/decryption of the remote repository.")] = None,
18
+ ):
19
+ on_conflict_mapper: dict[str, Literal["ask", "push-local-merge", "overwrite-local", "stop-on-conflict", "remove-rclone-conflict"]] = {
20
+ "a": "ask",
21
+ "ask": "ask",
22
+ "p": "push-local-merge",
23
+ "push-local-merge": "push-local-merge",
24
+ "o": "overwrite-local",
25
+ "overwrite-local": "overwrite-local",
26
+ "s": "stop-on-conflict",
27
+ "stop-on-conflict": "stop-on-conflict",
28
+ "r": "remove-rclone-conflict",
29
+ "remove-rclone-conflict": "remove-rclone-conflict",
30
+ }
31
+ on_conflict = on_conflict_mapper[on_conflict]
32
+ import git
33
+ from rich.console import Console
34
+ from rich.panel import Panel
35
+
36
+ from machineconfig.utils.path_extended import PathExtended
37
+ from machineconfig.utils.terminal import Response
38
+ from machineconfig.utils.source_of_truth import CONFIG_ROOT, DEFAULTS_PATH
39
+ from machineconfig.utils.code import get_uv_command_executing_python_script
40
+ from pathlib import Path
41
+ import platform
42
+ import subprocess
43
+ console = Console()
44
+
45
+ if cloud is None:
46
+ try:
47
+ from machineconfig.utils.io import read_ini
48
+
49
+ cloud_resolved = read_ini(DEFAULTS_PATH)["general"]["rclone_config_name"]
50
+ console.print(Panel(f"⚠️ Using default cloud: `{cloud_resolved}` from {DEFAULTS_PATH}", title="Default Cloud", border_style="yellow"))
51
+ except FileNotFoundError:
52
+ console.print(Panel(f"❌ ERROR: No cloud profile found\nLocation: {DEFAULTS_PATH}\nPlease set one up or provide one via the --cloud flag.", title="Error", border_style="red"))
53
+ return ""
54
+ else:
55
+ cloud_resolved = cloud
56
+ repo_local_root = PathExtended.cwd() if repo is None else PathExtended(repo).expanduser().absolute()
57
+ try:
58
+ repo_local_obj = git.Repo(repo_local_root, search_parent_directories=True)
59
+ except git.InvalidGitRepositoryError:
60
+ typer.echo(f"[red]Error:[/] The specified path '{repo_local_root}' is not a valid git repository.")
61
+ typer.Exit(code=1)
62
+ return ""
63
+ repo_local_root = PathExtended(repo_local_obj.working_dir) # cwd might have been in a sub directory of repo_root, so its better to redefine it.
64
+ local_relative_home = PathExtended(repo_local_root.expanduser().absolute().relative_to(Path.home()))
65
+ PathExtended(CONFIG_ROOT).joinpath("remote").mkdir(parents=True, exist_ok=True)
66
+ repo_remote_root = PathExtended(CONFIG_ROOT).joinpath("remote", local_relative_home)
67
+ repo_remote_root.delete(sure=True)
68
+ try:
69
+ console.print(Panel("📥 DOWNLOADING REMOTE REPOSITORY", title_align="left", border_style="blue"))
70
+ remote_path = repo_local_root.get_remote_path(rel2home=True, os_specific=False, root="myhome") + ".zip.enc"
71
+ res = repo_remote_root.from_cloud(remotepath=remote_path, cloud=cloud_resolved, unzip=True, decrypt=True, rel2home=True, os_specific=False, pwd=pwd)
72
+ if res is None:
73
+ raise AssertionError("Remote repo does not exist.")
74
+ except AssertionError:
75
+ console.print(Panel("🆕 Remote repository doesn't exist\n📤 Creating new remote and exiting...", title_align="left", border_style="green"))
76
+ repo_local_root.to_cloud(cloud=cloud_resolved, zip=True, encrypt=True, rel2home=True, pwd=pwd, os_specific=False)
77
+ return ""
78
+
79
+ repo_remote_obj = git.Repo(repo_remote_root)
80
+ if repo_remote_obj.is_dirty():
81
+ console.print(Panel(f"⚠️ WARNING: REMOTE REPOSITORY IS DIRTY\nLocation: {repo_remote_root}\nPlease commit or stash changes before proceeding.", title="Warning", border_style="yellow"))
82
+
83
+ script = f"""
84
+ echo ""
85
+ echo 'echo -e "\\033[1;34m═════ COMMITTING LOCAL CHANGES ═════\\033[0m"'
86
+ cd {repo_local_root}
87
+ git status
88
+ git add .
89
+ git commit -am "{message}"
90
+ echo ""
91
+ echo ""
92
+ echo 'echo -e "\\033[1;34m═════ PULLING LATEST FROM REMOTE ═════\\033[0m"'
93
+ cd {repo_local_root}
94
+ echo '-> Trying to removing originEnc remote from local repo if it exists.'
95
+ # git remote remove originEnc
96
+ git remote remove originEnc 2>/dev/null || true
97
+ echo '-> Adding originEnc remote to local repo'
98
+ git remote add originEnc {repo_remote_root}
99
+ echo '-> Fetching originEnc remote.'
100
+ git pull originEnc master
101
+
102
+ """
103
+
104
+ if Path.home().joinpath("code/machineconfig").exists():
105
+ uv_project_dir = f"""{str(Path.home().joinpath("code/machineconfig"))}"""
106
+ uv_with = None
107
+ else:
108
+ uv_with = ["machineconfig>=7.98"]
109
+ uv_project_dir = None
110
+
111
+ import tempfile
112
+ shell_path = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
113
+ shell_path.write_text(script, encoding="utf-8")
114
+
115
+ command = f". {shell_path}"
116
+ if platform.system() == "Windows":
117
+ completed = subprocess.run(["powershell", "-Command", command], capture_output=True, check=False, text=True)
118
+ else:
119
+ completed = subprocess.run(command, shell=True, capture_output=True, check=False, text=True)
120
+ res = Response.from_completed_process(completed).capture().print()
121
+
122
+ if res.is_successful(strict_err=True, strict_returcode=True):
123
+ console.print(Panel("✅ Pull succeeded!\n🧹 Removing originEnc remote and local copy\n📤 Pushing merged repository to cloud storage", title="Success", border_style="green"))
124
+ repo_remote_root.delete(sure=True)
125
+ from git.remote import Remote
126
+
127
+ Remote.remove(repo_local_obj, "originEnc")
128
+ repo_local_root.to_cloud(cloud=cloud_resolved, zip=True, encrypt=True, rel2home=True, pwd=pwd, os_specific=False)
129
+ return "success"
130
+ else:
131
+ console.print(Panel(f"⚠️ MERGE FAILED\n💾 Keeping local copy of remote at:\n📂 {repo_remote_root}", title="Merge Failed", border_style="red"))
132
+
133
+ # ================================================================================
134
+ option1 = "Delete remote copy and push local:"
135
+ from machineconfig.utils.meta import lambda_to_python_script
136
+ def func2(remote_repo: str, local_repo: str, cloud: str):
137
+ from machineconfig.scripts.python.helpers_repos.sync import delete_remote_repo_copy_and_push_local
138
+ delete_remote_repo_copy_and_push_local(remote_repo=remote_repo, local_repo=local_repo, cloud=cloud)
139
+ program_1_py = lambda_to_python_script(lambda: func2(remote_repo=str(repo_remote_root), local_repo=str(repo_local_root), cloud=str(cloud_resolved)),
140
+ in_global=True, import_module=False)
141
+ program1, _pyfile1 = get_uv_command_executing_python_script(python_script=program_1_py, uv_with=uv_with, uv_project_dir=uv_project_dir)
142
+ # ================================================================================
143
+ option2 = "Delete local repo and replace it with remote copy:"
144
+ program_2 = f"""
145
+ rm -rfd {repo_local_root}
146
+ mv {repo_remote_root} {repo_local_root}
147
+ """
148
+ if platform.system() in ["Linux", "Darwin"]:
149
+ program_2 += """
150
+ sudo chmod 600 $HOME/.ssh/*
151
+ sudo chmod 700 $HOME/.ssh
152
+ sudo chmod +x $HOME/dotfiles/scripts/linux -R
153
+ """
154
+ import tempfile
155
+ shell_file_2 = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
156
+ shell_file_2.write_text(program_2, encoding="utf-8")
157
+
158
+ # ================================================================================
159
+ option3 = "Inspect repos:"
160
+ def func(repo_local_root: str, repo_remote_root: str):
161
+ from machineconfig.scripts.python.helpers_repos.sync import inspect_repos
162
+ inspect_repos(repo_local_root=repo_local_root, repo_remote_root=repo_remote_root)
163
+ # program_3_py = function_to_script(func=func, call_with_kwargs={"repo_local_root": str(repo_local_root), "repo_remote_root": str(repo_remote_root)})
164
+ # shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, ve_path=None, executable=executable)
165
+ program_3_py = lambda_to_python_script(lambda: func(repo_local_root=str(repo_local_root), repo_remote_root=str(repo_remote_root)),
166
+ in_global=True, import_module=False)
167
+ program3, _pyfile3 = get_uv_command_executing_python_script(python_script=program_3_py, uv_with=uv_with, uv_project_dir=uv_project_dir)
168
+ # ================================================================================
169
+
170
+ option4 = "Remove problematic rclone file from repo and replace with remote:"
171
+ program_4 = f"""
172
+ rm $HOME/dotfiles/creds/rclone/rclone.conf
173
+ cp $HOME/.config/machineconfig/remote/dotfiles/creds/rclone/rclone.conf $HOME/dotfiles/creds/rclone
174
+ cd $HOME/dotfiles
175
+ git commit -am "finished merging"
176
+ {program1}
177
+ """
178
+ shell_file_4 = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
179
+ shell_file_4.write_text(program_4, encoding="utf-8")
180
+ # ================================================================================
181
+
182
+ console.print(Panel("🔄 RESOLVE MERGE CONFLICT\nChoose an option to resolve the conflict:", title_align="left", border_style="blue"))
183
+
184
+ print(f"• {option1:75} 👉 {program1}")
185
+ print(f"• {option2:75} 👉 {shell_file_2}")
186
+ print(f"• {option3:75} 👉 {program3}")
187
+ print(f"• {option4:75} 👉 {shell_file_4}")
188
+ print("\n\n")
189
+
190
+ program_content = None
191
+ match on_conflict:
192
+ case "ask":
193
+ import questionary
194
+ choice = questionary.select("Choose one option:", choices=[option1, option2, option3, option4]).ask()
195
+ if choice == option1:
196
+ program_content = program1
197
+ elif choice == option2:
198
+ program_content = program_2
199
+ elif choice == option3:
200
+ program_content = program3
201
+ elif choice == option4:
202
+ program_content = program_4
203
+ else:
204
+ raise NotImplementedError(f"Choice {choice} not implemented.")
205
+ case "push-local-merge":
206
+ program_content = program1
207
+ case "overwrite-local":
208
+ program_content = program_2
209
+ case "stop-on-conflict":
210
+ program_content = program3
211
+ case "remove-rclone-conflict":
212
+ program_content = program_4
213
+ case _:
214
+ raise ValueError(f"Unknown action: {on_conflict}")
215
+ from machineconfig.utils.code import run_shell_script
216
+ run_shell_script(script=program_content)
217
+ return program_content
218
+
@@ -3,19 +3,11 @@
3
3
 
4
4
  from typing import Optional
5
5
  from pathlib import Path
6
- from machineconfig.utils.source_of_truth import CONFIG_PATH, DEFAULTS_PATH
6
+ from machineconfig.utils.source_of_truth import CONFIG_ROOT, DEFAULTS_PATH
7
7
 
8
8
  import typer
9
9
 
10
10
 
11
-
12
- def print_banner() -> None:
13
- typer.echo("\n" + "=" * 50)
14
- typer.echo("📂 Welcome to the Repository Manager")
15
- typer.echo("=" * 50 + "\n")
16
-
17
-
18
-
19
11
  def resolve_directory(directory: Optional[str]) -> Path:
20
12
  if directory is None:
21
13
  directory = Path.cwd().as_posix()
@@ -28,12 +20,11 @@ def git_operations(
28
20
  commit: bool,
29
21
  push: bool,
30
22
  recursive: bool,
31
- no_sync: bool,
23
+ auto_uv_sync: bool,
32
24
  ) -> None:
33
- print_banner()
25
+
34
26
  repos_root = resolve_directory(directory)
35
- auto_sync = not no_sync
36
- from machineconfig.scripts.python.repos_helper_action import perform_git_operations
27
+ from machineconfig.scripts.python.helpers_repos.action import perform_git_operations
37
28
  from machineconfig.utils.path_extended import PathExtended
38
29
  perform_git_operations(
39
30
  repos_root=PathExtended(repos_root),
@@ -41,13 +32,14 @@ def git_operations(
41
32
  commit=commit,
42
33
  push=push,
43
34
  recursive=recursive,
44
- auto_sync=auto_sync,
35
+ auto_uv_sync=auto_uv_sync,
45
36
  )
46
37
  def resolve_spec_path(directory: Optional[str], cloud: Optional[str]) -> Path:
47
38
  repos_root = resolve_directory(directory)
48
39
  from machineconfig.utils.path_extended import PathExtended
49
40
  if not repos_root.exists() or repos_root.name != "repos.json":
50
- candidate = Path(CONFIG_PATH).joinpath("repos").joinpath(PathExtended(repos_root).rel2home()).joinpath("repos.json")
41
+ relative_repos_root = PathExtended(repos_root).expanduser().absolute().relative_to(Path.home())
42
+ candidate = Path(CONFIG_ROOT).joinpath("repos").joinpath(relative_repos_root).joinpath("repos.json")
51
43
  repos_root = candidate
52
44
  if not repos_root.exists():
53
45
  cloud_name: Optional[str]
@@ -73,10 +65,10 @@ def clone_from_specs(
73
65
  checkout_branch_flag: bool,
74
66
  checkout_commit_flag: bool,
75
67
  ) -> None:
76
- print_banner()
68
+
77
69
  typer.echo("\n📥 Cloning or checking out repositories...")
78
70
  spec_path = resolve_spec_path(directory, cloud)
79
- from machineconfig.scripts.python.repos_helper_clone import clone_repos
71
+ from machineconfig.scripts.python.helpers_repos.clone import clone_repos
80
72
  clone_repos(
81
73
  spec_path=spec_path,
82
74
  preferred_remote=None,