machineconfig 6.82__py3-none-any.whl → 8.51__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 (461) hide show
  1. machineconfig/cluster/remote/cloud_manager.py +1 -1
  2. machineconfig/cluster/remote/run_cluster.py +1 -1
  3. machineconfig/cluster/remote/run_remote.py +1 -1
  4. machineconfig/cluster/sessions_managers/utils/maker.py +29 -15
  5. machineconfig/cluster/sessions_managers/wt_local.py +17 -222
  6. machineconfig/cluster/sessions_managers/wt_local_manager.py +56 -194
  7. machineconfig/cluster/sessions_managers/wt_remote_manager.py +42 -198
  8. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  9. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  10. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  11. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  12. machineconfig/cluster/sessions_managers/zellij_local.py +1 -1
  13. machineconfig/cluster/sessions_managers/zellij_local_manager.py +4 -2
  14. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +3 -2
  15. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +2 -2
  16. machineconfig/jobs/installer/checks/check_installations.py +133 -0
  17. machineconfig/jobs/installer/checks/install_utils.py +132 -0
  18. machineconfig/jobs/installer/checks/report_utils.py +39 -0
  19. machineconfig/jobs/installer/checks/vt_utils.py +89 -0
  20. machineconfig/jobs/installer/installer_data.json +1500 -310
  21. machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
  22. machineconfig/jobs/installer/linux_scripts/q.sh +10 -7
  23. machineconfig/jobs/installer/linux_scripts/redis.sh +1 -0
  24. machineconfig/jobs/installer/package_groups.py +62 -91
  25. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  26. machineconfig/jobs/installer/{custom → python_scripts}/boxes.py +2 -3
  27. machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +5 -3
  28. machineconfig/jobs/installer/python_scripts/cloudflare_warp_cli.py +23 -0
  29. machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +14 -9
  30. machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +1 -1
  31. machineconfig/jobs/installer/python_scripts/hx.py +214 -0
  32. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +2 -2
  33. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +32 -26
  34. machineconfig/jobs/installer/python_scripts/sysabc.py +145 -0
  35. machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +2 -19
  36. machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +10 -14
  37. machineconfig/jobs/installer/python_scripts/yazi.py +139 -0
  38. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nfs +0 -1
  39. machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
  40. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +13 -0
  41. machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +4 -0
  42. machineconfig/jobs/scripts_dynamic/a.py +428 -0
  43. machineconfig/logger.py +1 -2
  44. machineconfig/profile/create_helper.py +56 -18
  45. machineconfig/profile/create_links.py +79 -21
  46. machineconfig/profile/create_links_export.py +87 -36
  47. machineconfig/profile/create_shell_profile.py +92 -127
  48. machineconfig/profile/mapper_data.toml +45 -0
  49. machineconfig/profile/mapper_dotfiles.toml +249 -0
  50. machineconfig/scripts/__init__.py +0 -4
  51. machineconfig/scripts/linux/wrap_mcfg +46 -0
  52. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  53. machineconfig/scripts/python/agents.py +85 -165
  54. machineconfig/scripts/python/ai/initai.py +4 -2
  55. machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
  56. machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
  57. machineconfig/scripts/python/ai/{command_runner → scripts}/command_runner.sh +1 -1
  58. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
  59. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +8 -6
  60. machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
  61. machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
  62. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
  63. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
  64. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
  65. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +6 -6
  66. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +33 -0
  67. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
  68. machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
  69. machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
  70. machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
  71. machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
  72. machineconfig/scripts/python/ai/{generate_files.py → utils/generate_files.py} +2 -2
  73. machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
  74. machineconfig/scripts/python/ai/{vscode_tasks.py → utils/vscode_tasks.py} +13 -5
  75. machineconfig/scripts/python/cloud.py +58 -11
  76. machineconfig/scripts/python/croshell.py +10 -162
  77. machineconfig/scripts/python/devops.py +73 -36
  78. machineconfig/scripts/python/devops_navigator.py +16 -6
  79. machineconfig/scripts/python/fire_jobs.py +8 -222
  80. machineconfig/scripts/python/ftpx.py +7 -200
  81. machineconfig/scripts/python/graph/cli_graph.json +8743 -0
  82. machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
  83. machineconfig/scripts/python/helpers/helper_env/env_manager_tui.py +204 -0
  84. machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
  85. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +1 -1
  86. machineconfig/scripts/python/helpers/helpers_agents/agentic_frameworks/fire_crush.py +39 -0
  87. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +3 -4
  88. machineconfig/scripts/python/helpers/helpers_agents/agentic_frameworks/fire_gemini.py +55 -0
  89. machineconfig/scripts/python/helpers/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  90. machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
  91. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_help_launch.py +38 -16
  92. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_helper_types.py +11 -14
  93. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
  94. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
  95. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/copilot/config.yml +1 -0
  96. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/crush/crush.json +10 -0
  97. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/gemini/settings.json +12 -0
  98. machineconfig/scripts/python/helpers/helpers_agents/privacy/privacy.py +109 -0
  99. machineconfig/scripts/python/helpers/helpers_agents/templates/prompt.txt +10 -0
  100. machineconfig/scripts/python/helpers/helpers_agents/templates/template.sh +34 -0
  101. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +32 -25
  102. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +29 -22
  103. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +9 -8
  104. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
  105. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +3 -3
  106. machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +225 -0
  107. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
  108. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +12 -12
  109. machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
  110. machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +262 -0
  111. machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +98 -0
  112. machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
  113. machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +67 -0
  114. machineconfig/scripts/python/helpers/helpers_devops/cli_nw.py +201 -0
  115. machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +274 -0
  116. machineconfig/scripts/python/helpers/helpers_devops/cli_self.py +197 -0
  117. machineconfig/scripts/python/helpers/helpers_devops/cli_share_file.py +151 -0
  118. machineconfig/scripts/python/helpers/helpers_devops/cli_share_server.py +125 -0
  119. machineconfig/scripts/python/{helpers_devops/cli_terminal.py → helpers/helpers_devops/cli_share_terminal.py} +26 -22
  120. machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
  121. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +17 -23
  122. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
  123. machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +78 -71
  124. machineconfig/scripts/python/helpers/helpers_devops/run_script.py +197 -0
  125. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
  126. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
  127. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +4 -4
  128. machineconfig/scripts/python/{helpers_fire/helpers4.py → helpers/helpers_fire_command/file_wrangler.py} +57 -20
  129. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +1 -0
  130. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
  131. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +26 -16
  132. machineconfig/scripts/python/helpers/helpers_msearch/__init__.py +5 -0
  133. machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
  134. machineconfig/scripts/{linux → python/helpers/helpers_msearch/scripts_linux}/fzfg +6 -5
  135. machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
  136. machineconfig/scripts/python/helpers/helpers_msearch/scripts_windows/fzfg.ps1 +59 -0
  137. machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
  138. machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
  139. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
  140. machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
  141. machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
  142. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
  143. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
  144. machineconfig/scripts/python/helpers/helpers_network/address.py +174 -0
  145. machineconfig/scripts/python/helpers/helpers_network/address_switch.py +78 -0
  146. machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
  147. machineconfig/scripts/python/{nw → helpers/helpers_network}/mount_nfs.py +2 -2
  148. machineconfig/scripts/python/{nw → helpers/helpers_network}/mount_ssh.py +3 -3
  149. machineconfig/scripts/python/helpers/helpers_network/ssh_add_identity.py +73 -0
  150. machineconfig/scripts/python/helpers/helpers_network/ssh_add_ssh_key.py +175 -0
  151. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_linux.py +319 -0
  152. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_windows.py +275 -0
  153. machineconfig/scripts/python/{nw → helpers/helpers_network}/wifi_conn.py +1 -53
  154. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
  155. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
  156. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -1
  157. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +159 -48
  158. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +4 -3
  159. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -12
  160. machineconfig/scripts/python/helpers/helpers_repos/repo_analyzer_1.py +160 -0
  161. machineconfig/scripts/python/{helpers_repos/count_lines.py → helpers/helpers_repos/repo_analyzer_2.py} +156 -191
  162. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
  163. machineconfig/scripts/python/helpers/helpers_search/ast_search.py +74 -0
  164. machineconfig/scripts/python/helpers/helpers_search/qr_code.py +166 -0
  165. machineconfig/scripts/python/helpers/helpers_search/repo_rag.py +325 -0
  166. machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
  167. machineconfig/scripts/python/helpers/helpers_search/symantic_search.py +25 -0
  168. machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
  169. machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +186 -0
  170. machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +20 -14
  171. machineconfig/scripts/python/helpers/helpers_terminal/__init__.py +0 -0
  172. machineconfig/scripts/python/helpers/helpers_terminal/terminal_impl.py +96 -0
  173. machineconfig/scripts/python/helpers/helpers_utils/download.py +150 -0
  174. machineconfig/scripts/python/helpers/helpers_utils/pdf.py +96 -0
  175. machineconfig/scripts/python/helpers/helpers_utils/python.py +210 -0
  176. machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
  177. machineconfig/scripts/python/mcfg_entry.py +143 -0
  178. machineconfig/scripts/python/msearch.py +26 -0
  179. machineconfig/scripts/python/sessions.py +69 -135
  180. machineconfig/scripts/python/terminal.py +58 -0
  181. machineconfig/scripts/python/utils.py +115 -38
  182. machineconfig/scripts/windows/wrap_mcfg.ps1 +63 -0
  183. machineconfig/settings/atuin/config.toml +294 -0
  184. machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
  185. machineconfig/settings/broot/conf.toml +1 -1
  186. machineconfig/settings/helix/config.toml +16 -0
  187. machineconfig/settings/helix/languages.toml +13 -4
  188. machineconfig/settings/helix/yazi-picker.sh +12 -0
  189. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  190. machineconfig/settings/lf/linux/exe/previewer.sh +3 -2
  191. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  192. machineconfig/settings/lf/windows/lfrc +14 -16
  193. machineconfig/settings/linters/.ruff.toml +2 -1
  194. machineconfig/settings/marimo/marimo.toml +1 -1
  195. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  196. machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
  197. machineconfig/settings/shells/bash/init.sh +47 -12
  198. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
  199. machineconfig/settings/shells/nushell/config.nu +25 -33
  200. machineconfig/settings/shells/nushell/env.nu +21 -8
  201. machineconfig/settings/shells/nushell/init.nu +138 -0
  202. machineconfig/settings/shells/pwsh/init.ps1 +111 -17
  203. machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
  204. machineconfig/settings/shells/starship/starship.toml +16 -0
  205. machineconfig/settings/shells/wezterm/wezterm.lua +6 -1
  206. machineconfig/settings/shells/wt/settings.json +27 -18
  207. machineconfig/settings/shells/zsh/init.sh +42 -23
  208. machineconfig/settings/television/cable_unix/alias.toml +8 -0
  209. machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
  210. machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
  211. machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
  212. machineconfig/settings/television/cable_unix/channels.toml +19 -0
  213. machineconfig/settings/television/cable_unix/dirs.toml +13 -0
  214. machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
  215. machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
  216. machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
  217. machineconfig/settings/television/cable_unix/env.toml +17 -0
  218. machineconfig/settings/television/cable_unix/files.toml +11 -0
  219. machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
  220. machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
  221. machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
  222. machineconfig/settings/television/cable_unix/git-log.toml +12 -0
  223. machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
  224. machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
  225. machineconfig/settings/television/cable_unix/guix.toml +20 -0
  226. machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
  227. machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
  228. machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
  229. machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
  230. machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
  231. machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
  232. machineconfig/settings/television/cable_unix/procs.toml +20 -0
  233. machineconfig/settings/television/cable_unix/text.toml +17 -0
  234. machineconfig/settings/television/cable_unix/tldr.toml +18 -0
  235. machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
  236. machineconfig/settings/television/cable_windows/alias.toml +7 -0
  237. machineconfig/settings/television/cable_windows/dirs.toml +13 -0
  238. machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
  239. machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
  240. machineconfig/settings/television/cable_windows/env.toml +17 -0
  241. machineconfig/settings/television/cable_windows/files.toml +14 -0
  242. machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
  243. machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
  244. machineconfig/settings/television/cable_windows/git-log.toml +11 -0
  245. machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
  246. machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
  247. machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
  248. machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
  249. machineconfig/settings/television/cable_windows/text.toml +17 -0
  250. machineconfig/settings/tv/config.toml +234 -0
  251. machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
  252. machineconfig/settings/wsl/.wslconfig +5 -30
  253. machineconfig/settings/wt/__init__.py +0 -0
  254. machineconfig/settings/yazi/init.lua +61 -0
  255. machineconfig/settings/yazi/keymap_linux.toml +94 -0
  256. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  257. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  258. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  259. machineconfig/settings/yazi/theme.toml +4 -0
  260. machineconfig/settings/yazi/yazi_linux.toml +94 -0
  261. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  262. machineconfig/settings/zellij/layouts/st.kdl +40 -9
  263. machineconfig/settings/zellij/layouts/st2.kdl +1 -1
  264. machineconfig/setup_linux/__init__.py +2 -2
  265. machineconfig/setup_linux/apps_desktop.sh +8 -27
  266. machineconfig/setup_linux/web_shortcuts/interactive.sh +27 -12
  267. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +34 -0
  268. machineconfig/setup_mac/__init__.py +1 -4
  269. machineconfig/setup_mac/apps_gui.sh +248 -0
  270. machineconfig/setup_windows/__init__.py +2 -5
  271. machineconfig/setup_windows/uv.ps1 +8 -1
  272. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +28 -12
  273. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +31 -0
  274. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  275. machineconfig/type_hinting/sql/__init__.py +1 -0
  276. machineconfig/type_hinting/sql/base.py +216 -0
  277. machineconfig/type_hinting/sql/core_schema.py +64 -0
  278. machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
  279. machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
  280. machineconfig/type_hinting/typedict/__init__.py +1 -0
  281. machineconfig/type_hinting/typedict/ast_utils.py +130 -0
  282. machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
  283. machineconfig/type_hinting/typedict/generators.py +231 -0
  284. machineconfig/type_hinting/typedict/polars_schema.py +24 -0
  285. machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
  286. machineconfig/utils/accessories.py +31 -4
  287. machineconfig/utils/code.py +163 -51
  288. machineconfig/utils/files/ascii_art.py +11 -15
  289. machineconfig/utils/files/headers.py +6 -7
  290. machineconfig/utils/files/read.py +8 -1
  291. machineconfig/utils/installer_utils/github_release_bulk.py +95 -138
  292. machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
  293. machineconfig/utils/installer_utils/install_from_url.py +183 -0
  294. machineconfig/utils/installer_utils/installer_class.py +53 -102
  295. machineconfig/utils/installer_utils/installer_cli.py +161 -0
  296. machineconfig/utils/installer_utils/installer_helper.py +129 -0
  297. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +42 -91
  298. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +20 -65
  299. machineconfig/utils/io.py +94 -9
  300. machineconfig/utils/links.py +56 -38
  301. machineconfig/utils/meta.py +38 -21
  302. machineconfig/utils/options.py +81 -23
  303. machineconfig/utils/options_utils/__init__.py +0 -0
  304. machineconfig/utils/options_utils/options_tv_linux.py +211 -0
  305. machineconfig/utils/options_utils/options_tv_windows.py +88 -0
  306. machineconfig/utils/options_utils/tv_options.py +37 -0
  307. machineconfig/utils/path_extended.py +52 -102
  308. machineconfig/utils/path_helper.py +76 -23
  309. machineconfig/utils/procs.py +1 -1
  310. machineconfig/utils/scheduler.py +26 -53
  311. machineconfig/utils/scheduling.py +0 -2
  312. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  313. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  314. machineconfig/utils/source_of_truth.py +6 -1
  315. machineconfig/utils/ssh.py +216 -419
  316. machineconfig/utils/ssh_utils/abc.py +5 -0
  317. machineconfig/utils/ssh_utils/copy_from_here.py +116 -0
  318. machineconfig/utils/ssh_utils/copy_to_here.py +303 -0
  319. machineconfig/utils/ssh_utils/utils.py +158 -0
  320. machineconfig/utils/ssh_utils/wsl.py +147 -0
  321. machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
  322. machineconfig/utils/terminal.py +1 -0
  323. machineconfig/utils/upgrade_packages.py +107 -35
  324. machineconfig/utils/ve.py +12 -4
  325. machineconfig-8.51.dist-info/METADATA +140 -0
  326. machineconfig-8.51.dist-info/RECORD +543 -0
  327. {machineconfig-6.82.dist-info → machineconfig-8.51.dist-info}/entry_points.txt +4 -1
  328. machineconfig/jobs/installer/check_installations.py +0 -248
  329. machineconfig/jobs/installer/custom/hx.py +0 -140
  330. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -41
  331. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -71
  332. machineconfig/jobs/installer/powershell_scripts/archive_pygraphviz.ps1 +0 -12
  333. machineconfig/jobs/installer/powershell_scripts/openssh-server_add_key.ps1 +0 -7
  334. machineconfig/jobs/installer/powershell_scripts/openssh-server_copy-ssh-id.ps1 +0 -14
  335. machineconfig/profile/backup.toml +0 -49
  336. machineconfig/profile/mapper.toml +0 -256
  337. machineconfig/scripts/linux/fzf2g +0 -21
  338. machineconfig/scripts/linux/fzfag +0 -17
  339. machineconfig/scripts/linux/fzffg +0 -25
  340. machineconfig/scripts/linux/fzfrga +0 -21
  341. machineconfig/scripts/linux/mcfgs +0 -38
  342. machineconfig/scripts/linux/other/share_smb +0 -1
  343. machineconfig/scripts/linux/other/switch_ip +0 -20
  344. machineconfig/scripts/linux/skrg +0 -4
  345. machineconfig/scripts/linux/warp-cli.sh +0 -122
  346. machineconfig/scripts/linux/z_ls +0 -104
  347. machineconfig/scripts/python/ai/command_runner/prompt.txt +0 -9
  348. machineconfig/scripts/python/helpers_devops/cli_config.py +0 -120
  349. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -77
  350. machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
  351. machineconfig/scripts/python/helpers_devops/cli_nw.py +0 -73
  352. machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -181
  353. machineconfig/scripts/python/helpers_devops/cli_self.py +0 -122
  354. machineconfig/scripts/python/helpers_devops/cli_share_server.py +0 -104
  355. machineconfig/scripts/python/helpers_devops/cli_utils.py +0 -221
  356. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
  357. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
  358. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_crush.py +0 -37
  359. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_gemini.py +0 -44
  360. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_qwen.py +0 -43
  361. machineconfig/scripts/python/helpers_fire/prompt.txt +0 -2
  362. machineconfig/scripts/python/helpers_fire/template.sh +0 -15
  363. machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
  364. machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
  365. machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -588
  366. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +0 -17
  367. machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -76
  368. machineconfig/scripts/python/helpers_repos/secure_repo.py +0 -15
  369. machineconfig/scripts/python/mcfg.py +0 -48
  370. machineconfig/scripts/python/nw/add_ssh_key.py +0 -148
  371. machineconfig/scripts/python/nw/devops_add_identity.py +0 -82
  372. machineconfig/scripts/python/nw/devops_add_ssh_key.py +0 -134
  373. machineconfig/scripts/python/nw/ssh_debug_linux.py +0 -391
  374. machineconfig/scripts/python/nw/ssh_debug_windows.py +0 -338
  375. machineconfig/scripts/python/nw/wsl_windows_transfer.py +0 -66
  376. machineconfig/scripts/windows/fzfb.ps1 +0 -3
  377. machineconfig/scripts/windows/fzfg.ps1 +0 -2
  378. machineconfig/scripts/windows/fzfrga.bat +0 -20
  379. machineconfig/scripts/windows/mcfgs.ps1 +0 -17
  380. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
  381. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  382. machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
  383. machineconfig/settings/lf/windows/tst.ps1 +0 -1
  384. machineconfig/settings/yazi/yazi.toml +0 -4
  385. machineconfig/setup_linux/apps.sh +0 -66
  386. machineconfig/setup_linux/others/cli_installation.sh +0 -137
  387. machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh +0 -30
  388. machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
  389. machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
  390. machineconfig/setup_mac/apps.sh +0 -73
  391. machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
  392. machineconfig/setup_windows/apps.ps1 +0 -62
  393. machineconfig/setup_windows/others/obs.ps1 +0 -4
  394. machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
  395. machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
  396. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
  397. machineconfig/utils/installer_utils/installer.py +0 -225
  398. machineconfig/utils/tst.py +0 -20
  399. machineconfig-6.82.dist-info/METADATA +0 -82
  400. machineconfig-6.82.dist-info/RECORD +0 -441
  401. machineconfig/jobs/installer/{custom_dev → checks}/__init__.py +0 -0
  402. machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +0 -0
  403. machineconfig/{scripts/python/helpers_cloud → jobs/installer/python_scripts}/__init__.py +0 -0
  404. machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
  405. machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
  406. machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
  407. machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
  408. machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
  409. machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
  410. machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
  411. machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
  412. machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/android.sh +0 -0
  413. machineconfig/jobs/{installer/linux_scripts → scripts/bash_scripts}/lid.sh +0 -0
  414. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_drive +0 -0
  415. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nw_drive +0 -0
  416. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_smb +0 -0
  417. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_cloud.sh +0 -0
  418. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_nfs +0 -0
  419. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/start_docker +0 -0
  420. machineconfig/{scripts → jobs/scripts/powershell_scripts}/Restore-ThunderbirdProfile.ps1 +0 -0
  421. machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/docker.ps1 +0 -0
  422. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nfs.ps1 +0 -0
  423. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nw.ps1 +0 -0
  424. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_smb.ps1 +0 -0
  425. machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/power_options.ps1 +0 -0
  426. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_cloud.cmd +0 -0
  427. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_smb.ps1 +0 -0
  428. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
  429. machineconfig/scripts/python/{helpers_croshell → ai/utils}/__init__.py +0 -0
  430. machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
  431. machineconfig/scripts/python/{helpers_devops → graph}/__init__.py +0 -0
  432. machineconfig/scripts/python/{helpers_devops/themes → helpers}/__init__.py +0 -0
  433. machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
  434. machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
  435. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/__init__.py +0 -0
  436. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/agentic_frameworks/__init__.py +0 -0
  437. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
  438. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
  439. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents/templates}/template.ps1 +0 -0
  440. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_cloud}/__init__.py +0 -0
  441. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +1 -1
  442. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
  443. /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_croshell}/__init__.py +0 -0
  444. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
  445. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
  446. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
  447. /machineconfig/scripts/python/{nw → helpers/helpers_devops}/__init__.py +0 -0
  448. /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers/helpers_devops/themes}/__init__.py +0 -0
  449. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  450. /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_fire_command/__init__.py} +0 -0
  451. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
  452. /machineconfig/scripts/python/{helpers_fire_command/fire_jobs_streamlit_helper.py → helpers/helpers_fire_command/f.py} +0 -0
  453. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers/helpers_fire_command/fire_jobs_streamlit_helper.py} +0 -0
  454. /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
  455. /machineconfig/{settings/yazi/keymap.toml → scripts/python/helpers/helpers_network/__init__.py} +0 -0
  456. /machineconfig/scripts/python/{nw → helpers/helpers_network}/mount_nw_drive.py +0 -0
  457. /machineconfig/scripts/python/{nw → helpers/helpers_network}/onetimeshare.py +0 -0
  458. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
  459. /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
  460. {machineconfig-6.82.dist-info → machineconfig-8.51.dist-info}/WHEEL +0 -0
  461. {machineconfig-6.82.dist-info → machineconfig-8.51.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,5 @@
1
+
2
+
3
+ MACHINECONFIG_VERSION = "machineconfig>=8.51"
4
+ DEFAULT_PICKLE_SUBDIR = "tmp_results/tmp_scripts/ssh"
5
+
@@ -0,0 +1,116 @@
1
+
2
+
3
+ from typing import Optional, TYPE_CHECKING
4
+ from pathlib import Path, PurePosixPath, PureWindowsPath
5
+ from machineconfig.utils.accessories import randstr
6
+ from machineconfig.utils.meta import lambda_to_python_script
7
+ from machineconfig.utils.ssh_utils.abc import DEFAULT_PICKLE_SUBDIR
8
+ from machineconfig.utils.code import get_uv_command
9
+
10
+ if TYPE_CHECKING:
11
+ from machineconfig.utils.ssh import SSH
12
+
13
+
14
+ def _build_remote_path(self: "SSH", home_dir: str, rel_path: str) -> str:
15
+ if self.remote_specs["system"] == "Windows":
16
+ return str(PureWindowsPath(home_dir) / rel_path)
17
+ return str(PurePosixPath(home_dir) / PurePosixPath(rel_path.replace("\\", "/")))
18
+
19
+
20
+ def copy_from_here(
21
+ self: "SSH", source_path: str, target_rel2home: Optional[str], compress_with_zip: bool, recursive: bool, overwrite_existing: bool
22
+ ) -> None:
23
+ if self.sftp is None:
24
+ raise RuntimeError(f"SFTP connection not available for {self.hostname}. Cannot transfer files.")
25
+ source_obj = Path(source_path).expanduser().absolute()
26
+ if not source_obj.exists():
27
+ raise RuntimeError(f"SSH Error: source `{source_obj}` does not exist!")
28
+ if target_rel2home is None:
29
+ try:
30
+ target_rel2home = str(source_obj.relative_to(Path.home()))
31
+ except ValueError:
32
+ raise RuntimeError(f"If target is not specified, source must be relative to home directory, but got: {source_obj}")
33
+ if not compress_with_zip and source_obj.is_dir():
34
+ if not recursive:
35
+ raise RuntimeError(
36
+ f"SSH Error: source `{source_obj}` is a directory! Set `recursive=True` for recursive sending or `compress_with_zip=True` to zip it first."
37
+ )
38
+ file_paths_to_upload: list[Path] = [file_path for file_path in source_obj.rglob("*") if file_path.is_file()]
39
+ self.create_parent_dir_and_check_if_exists(path_rel2home=target_rel2home, overwrite_existing=overwrite_existing)
40
+ for idx, file_path in enumerate(file_paths_to_upload):
41
+ print(f" {idx + 1:03d}. {file_path}")
42
+ for file_path in file_paths_to_upload:
43
+ remote_file_target = Path(target_rel2home).joinpath(file_path.relative_to(source_obj))
44
+ self.copy_from_here(
45
+ source_path=str(file_path),
46
+ target_rel2home=str(remote_file_target),
47
+ compress_with_zip=False,
48
+ recursive=False,
49
+ overwrite_existing=overwrite_existing,
50
+ )
51
+ return None
52
+ if compress_with_zip:
53
+ print("🗜️ ZIPPING ...")
54
+ import shutil
55
+
56
+ zip_path = Path(str(source_obj) + "_archive")
57
+ if source_obj.is_dir():
58
+ shutil.make_archive(str(zip_path), "zip", source_obj)
59
+ else:
60
+ shutil.make_archive(str(zip_path), "zip", source_obj.parent, source_obj.name)
61
+ source_obj = Path(str(zip_path) + ".zip")
62
+ if not target_rel2home.endswith(".zip"):
63
+ target_rel2home = target_rel2home + ".zip"
64
+ if Path(target_rel2home).parent.as_posix() not in {"", "."}:
65
+ self.create_parent_dir_and_check_if_exists(path_rel2home=target_rel2home, overwrite_existing=overwrite_existing)
66
+ remote_target_full = _build_remote_path(self, self.remote_specs["home_dir"], target_rel2home)
67
+ print(f"""📤 [SFTP UPLOAD] Sending file: {repr(source_obj)} ==> Remote Path: {remote_target_full}""")
68
+ try:
69
+ with self.tqdm_wrap(ascii=True, unit="b", unit_scale=True) as pbar:
70
+ if self.sftp is None: # type: ignore[unreachable]
71
+ raise RuntimeError(f"SFTP connection lost for {self.hostname}")
72
+ print(f"Uploading {source_obj} to\n{remote_target_full}")
73
+ self.sftp.put(localpath=str(source_obj), remotepath=remote_target_full, callback=pbar.view_bar)
74
+ except Exception:
75
+ if compress_with_zip and source_obj.exists() and str(source_obj).endswith("_archive.zip"):
76
+ source_obj.unlink()
77
+ raise
78
+
79
+ if compress_with_zip:
80
+
81
+ def unzip_archive(zip_file_path: str, overwrite_flag: bool) -> None:
82
+ from pathlib import Path
83
+ import shutil
84
+ import zipfile
85
+
86
+ archive_path = Path(zip_file_path).expanduser()
87
+ extraction_directory = archive_path.parent / archive_path.stem
88
+ if overwrite_flag and extraction_directory.exists():
89
+ shutil.rmtree(extraction_directory)
90
+ with zipfile.ZipFile(archive_path, "r") as archive_handle:
91
+ archive_handle.extractall(extraction_directory)
92
+ archive_path.unlink()
93
+
94
+ remote_zip_path = _build_remote_path(self, self.remote_specs["home_dir"], target_rel2home)
95
+ command = lambda_to_python_script(
96
+ lambda: unzip_archive(zip_file_path=remote_zip_path, overwrite_flag=overwrite_existing), in_global=True, import_module=False
97
+ )
98
+ tmp_py_file = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/create_target_dir_{randstr()}.py")
99
+ tmp_py_file.parent.mkdir(parents=True, exist_ok=True)
100
+ tmp_py_file.write_text(command, encoding="utf-8")
101
+ remote_tmp_py = tmp_py_file.relative_to(Path.home()).as_posix()
102
+ self.copy_from_here(source_path=str(tmp_py_file), target_rel2home=None, compress_with_zip=False, recursive=False, overwrite_existing=True)
103
+ self.run_shell_cmd_on_remote(
104
+ command=f"""{get_uv_command(platform=self.remote_specs['system'])} run python {remote_tmp_py}""",
105
+ verbose_output=False,
106
+ description=f"UNZIPPING {target_rel2home}",
107
+ strict_stderr=True,
108
+ strict_return_code=True,
109
+ )
110
+ source_obj.unlink()
111
+ tmp_py_file.unlink(missing_ok=True)
112
+ return None
113
+
114
+
115
+ if __name__ == "__main__":
116
+ from machineconfig.utils.ssh import SSH
@@ -0,0 +1,303 @@
1
+
2
+
3
+ from typing import Optional, Union
4
+ from pathlib import Path
5
+ from machineconfig.utils.accessories import randstr
6
+ from machineconfig.utils.meta import lambda_to_python_script
7
+ from machineconfig.utils.ssh_utils.abc import MACHINECONFIG_VERSION, DEFAULT_PICKLE_SUBDIR
8
+
9
+
10
+ def copy_to_here(
11
+ self: "SSH",
12
+ source: Union[str, Path],
13
+ target: Optional[Union[str, Path]],
14
+ compress_with_zip: bool = False,
15
+ recursive: bool = False,
16
+ internal_call: bool = False,
17
+ ) -> None:
18
+ if self.sftp is None:
19
+ raise RuntimeError(f"SFTP connection not available for {self.hostname}. Cannot transfer files.")
20
+
21
+ if not internal_call:
22
+ print(f"{'⬇️' * 5} SFTP DOWNLOADING FROM `{source}` TO `{target}`")
23
+
24
+ source_obj = Path(source)
25
+ expanded_source = self.expand_remote_path(source_path=source_obj)
26
+
27
+ if not compress_with_zip:
28
+ is_dir = self.check_remote_is_dir(source_path=expanded_source)
29
+
30
+ if is_dir:
31
+ if not recursive:
32
+ raise RuntimeError(
33
+ f"SSH Error: source `{source_obj}` is a directory! Set recursive=True for recursive transfer or compress_with_zip=True to zip it."
34
+ )
35
+
36
+ def search_files(directory_path: str, json_output_path: str) -> list[str]:
37
+ from pathlib import Path
38
+ import json
39
+
40
+ file_paths_list = [
41
+ file_path.as_posix() for file_path in Path(directory_path).expanduser().absolute().rglob("*") if file_path.is_file()
42
+ ]
43
+ json_result_path = Path(json_output_path)
44
+ json_result_path.parent.mkdir(parents=True, exist_ok=True)
45
+ json_result_path.write_text(json.dumps(file_paths_list, indent=2), encoding="utf-8")
46
+ print(json_result_path.as_posix())
47
+ return file_paths_list
48
+
49
+ remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
50
+ command = lambda_to_python_script(
51
+ lambda: search_files(directory_path=expanded_source, json_output_path=remote_json_output),
52
+ in_global=True, import_module=False
53
+ )
54
+ response = self.run_py_remotely(
55
+ python_code=command,
56
+ uv_with=[MACHINECONFIG_VERSION],
57
+ uv_project_dir=None,
58
+ description="Searching for files in source",
59
+ verbose_output=False,
60
+ strict_stderr=False,
61
+ strict_return_code=False,
62
+ )
63
+ remote_json_path = response.op.strip()
64
+ if not remote_json_path:
65
+ raise RuntimeError(f"Could not resolve source path {source} - no response from remote")
66
+
67
+ local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
68
+ self.simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
69
+ import json
70
+
71
+ try:
72
+ source_list_str = json.loads(local_json.read_text(encoding="utf-8"))
73
+ except (json.JSONDecodeError, FileNotFoundError) as err:
74
+ raise RuntimeError(f"Could not resolve source path {source} - invalid JSON response: {err}") from err
75
+ finally:
76
+ if local_json.exists():
77
+ local_json.unlink()
78
+ assert isinstance(source_list_str, list), f"Could not resolve source path {source}"
79
+ file_paths_to_download = [Path(file_path_str) for file_path_str in source_list_str]
80
+
81
+ if target is None:
82
+
83
+ def collapse_to_home_dir(absolute_path: str, json_output_path: str) -> str:
84
+ from pathlib import Path
85
+ import json
86
+
87
+ source_absolute_path = Path(absolute_path).expanduser().absolute()
88
+ try:
89
+ relative_to_home = source_absolute_path.relative_to(Path.home())
90
+ collapsed_path_posix = (Path("~") / relative_to_home).as_posix()
91
+ json_result_path = Path(json_output_path)
92
+ json_result_path.parent.mkdir(parents=True, exist_ok=True)
93
+ json_result_path.write_text(json.dumps(collapsed_path_posix, indent=2), encoding="utf-8")
94
+ print(json_result_path.as_posix())
95
+ return collapsed_path_posix
96
+ except ValueError:
97
+ raise RuntimeError(f"Source path must be relative to home directory: {source_absolute_path}")
98
+
99
+ remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
100
+ command = lambda_to_python_script(
101
+ lambda: collapse_to_home_dir(absolute_path=expanded_source, json_output_path=remote_json_output),
102
+ in_global=True,
103
+ import_module=False,
104
+ )
105
+ response = self.run_py_remotely(
106
+ python_code=command,
107
+ uv_with=[MACHINECONFIG_VERSION],
108
+ uv_project_dir=None,
109
+ description="Finding default target via relative source path",
110
+ verbose_output=False,
111
+ strict_stderr=False,
112
+ strict_return_code=False,
113
+ )
114
+ remote_json_path_dir = response.op.strip()
115
+ if not remote_json_path_dir:
116
+ raise RuntimeError("Could not resolve target path - no response from remote")
117
+
118
+ local_json_dir = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
119
+ self.simple_sftp_get(remote_path=remote_json_path_dir, local_path=local_json_dir)
120
+ import json
121
+
122
+ try:
123
+ target_dir_str = json.loads(local_json_dir.read_text(encoding="utf-8"))
124
+ except (json.JSONDecodeError, FileNotFoundError) as err:
125
+ raise RuntimeError(f"Could not resolve target path - invalid JSON response: {err}") from err
126
+ finally:
127
+ if local_json_dir.exists():
128
+ local_json_dir.unlink()
129
+ assert isinstance(target_dir_str, str), "Could not resolve target path"
130
+ target = Path(target_dir_str)
131
+
132
+ target_dir = Path(target).expanduser().absolute()
133
+
134
+ for idx, file_path in enumerate(file_paths_to_download):
135
+ print(f" {idx + 1:03d}. {file_path}")
136
+
137
+ for file_path in file_paths_to_download:
138
+ local_file_target = target_dir.joinpath(Path(file_path).relative_to(expanded_source))
139
+ self.copy_to_here(source=file_path, target=local_file_target, compress_with_zip=False, recursive=False, internal_call=True)
140
+
141
+ return None
142
+
143
+ if compress_with_zip:
144
+ print("🗜️ ZIPPING ...")
145
+
146
+ def zip_source(path_to_zip: str, json_output_path: str) -> str:
147
+ from pathlib import Path
148
+ import shutil
149
+ import json
150
+
151
+ source_to_compress = Path(path_to_zip).expanduser().absolute()
152
+ archive_base_path = source_to_compress.parent / (source_to_compress.name + "_archive")
153
+ if source_to_compress.is_dir():
154
+ shutil.make_archive(str(archive_base_path), "zip", source_to_compress)
155
+ else:
156
+ shutil.make_archive(str(archive_base_path), "zip", source_to_compress.parent, source_to_compress.name)
157
+ zip_file_path = str(archive_base_path) + ".zip"
158
+ json_result_path = Path(json_output_path)
159
+ json_result_path.parent.mkdir(parents=True, exist_ok=True)
160
+ json_result_path.write_text(json.dumps(zip_file_path, indent=2), encoding="utf-8")
161
+ print(json_result_path.as_posix())
162
+ return zip_file_path
163
+
164
+ remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
165
+ command = lambda_to_python_script(
166
+ lambda: zip_source(path_to_zip=expanded_source, json_output_path=remote_json_output),
167
+ in_global=True, import_module=False
168
+ )
169
+ response = self.run_py_remotely(
170
+ python_code=command,
171
+ uv_with=[MACHINECONFIG_VERSION],
172
+ uv_project_dir=None,
173
+ description=f"Zipping source file {source}",
174
+ verbose_output=False,
175
+ strict_stderr=False,
176
+ strict_return_code=False,
177
+ )
178
+ remote_json_path = response.op.strip()
179
+ if not remote_json_path:
180
+ raise RuntimeError(f"Could not zip {source} - no response from remote")
181
+
182
+ local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
183
+ self.simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
184
+ import json
185
+
186
+ try:
187
+ zipped_path = json.loads(local_json.read_text(encoding="utf-8"))
188
+ except (json.JSONDecodeError, FileNotFoundError) as err:
189
+ raise RuntimeError(f"Could not zip {source} - invalid JSON response: {err}") from err
190
+ finally:
191
+ if local_json.exists():
192
+ local_json.unlink()
193
+ assert isinstance(zipped_path, str), f"Could not zip {source}"
194
+ source_obj = Path(zipped_path)
195
+ expanded_source = zipped_path
196
+
197
+ if target is None:
198
+
199
+ def collapse_to_home(absolute_path: str, json_output_path: str) -> str:
200
+ from pathlib import Path
201
+ import json
202
+
203
+ source_absolute_path = Path(absolute_path).expanduser().absolute()
204
+ try:
205
+ relative_to_home = source_absolute_path.relative_to(Path.home())
206
+ collapsed_path_posix = (Path("~") / relative_to_home).as_posix()
207
+ json_result_path = Path(json_output_path)
208
+ json_result_path.parent.mkdir(parents=True, exist_ok=True)
209
+ json_result_path.write_text(json.dumps(collapsed_path_posix, indent=2), encoding="utf-8")
210
+ print(json_result_path.as_posix())
211
+ return collapsed_path_posix
212
+ except ValueError:
213
+ raise RuntimeError(f"Source path must be relative to home directory: {source_absolute_path}")
214
+
215
+ remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
216
+ command = lambda_to_python_script(
217
+ lambda: collapse_to_home(absolute_path=expanded_source, json_output_path=remote_json_output),
218
+ in_global=True, import_module=False
219
+ )
220
+ response = self.run_py_remotely(
221
+ python_code=command,
222
+ uv_with=[MACHINECONFIG_VERSION],
223
+ uv_project_dir=None,
224
+ description="Finding default target via relative source path",
225
+ verbose_output=False,
226
+ strict_stderr=False,
227
+ strict_return_code=False,
228
+ )
229
+ remote_json_path = response.op.strip()
230
+ if not remote_json_path:
231
+ raise RuntimeError("Could not resolve target path - no response from remote")
232
+
233
+ local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
234
+ self.simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
235
+ import json
236
+
237
+ try:
238
+ target_str = json.loads(local_json.read_text(encoding="utf-8"))
239
+ except (json.JSONDecodeError, FileNotFoundError) as err:
240
+ raise RuntimeError(f"Could not resolve target path - invalid JSON response: {err}") from err
241
+ finally:
242
+ if local_json.exists():
243
+ local_json.unlink()
244
+ assert isinstance(target_str, str), "Could not resolve target path"
245
+ target = Path(target_str)
246
+ assert str(target).startswith("~"), f"If target is not specified, source must be relative to home.\n{target=}"
247
+
248
+ target_obj = Path(target).expanduser().absolute()
249
+ target_obj.parent.mkdir(parents=True, exist_ok=True)
250
+
251
+ if compress_with_zip and target_obj.suffix != ".zip":
252
+ target_obj = target_obj.with_suffix(target_obj.suffix + ".zip")
253
+
254
+ print(f"""📥 [DOWNLOAD] Receiving: {expanded_source} ==> Local Path: {target_obj}""")
255
+ try:
256
+ with self.tqdm_wrap(ascii=True, unit="b", unit_scale=True) as pbar:
257
+ if self.sftp is None: # type: ignore[unreachable]
258
+ raise RuntimeError(f"SFTP connection lost for {self.hostname}")
259
+ self.sftp.get(remotepath=expanded_source, localpath=str(target_obj), callback=pbar.view_bar) # type: ignore
260
+ except Exception:
261
+ if target_obj.exists():
262
+ target_obj.unlink()
263
+ raise
264
+
265
+ if compress_with_zip:
266
+ import zipfile
267
+
268
+ extract_to = target_obj.parent / target_obj.stem
269
+ with zipfile.ZipFile(target_obj, "r") as zip_ref:
270
+ zip_ref.extractall(extract_to)
271
+ target_obj.unlink()
272
+ target_obj = extract_to
273
+
274
+ def delete_temp_zip(path_to_delete: str) -> None:
275
+ from pathlib import Path
276
+ import shutil
277
+
278
+ file_or_dir_path = Path(path_to_delete)
279
+ if file_or_dir_path.exists():
280
+ if file_or_dir_path.is_dir():
281
+ shutil.rmtree(file_or_dir_path)
282
+ else:
283
+ file_or_dir_path.unlink()
284
+
285
+ command = lambda_to_python_script(lambda: delete_temp_zip(path_to_delete=expanded_source),
286
+ in_global=True, import_module=False)
287
+ self.run_py_remotely(
288
+ python_code=command,
289
+ uv_with=[MACHINECONFIG_VERSION],
290
+ uv_project_dir=None,
291
+ description="Cleaning temp zip files @ remote.",
292
+ verbose_output=False,
293
+ strict_stderr=True,
294
+ strict_return_code=True,
295
+ )
296
+
297
+ print("\n")
298
+ return None
299
+
300
+
301
+ if __name__ == "__main__":
302
+ from machineconfig.utils.ssh import SSH
303
+
@@ -0,0 +1,158 @@
1
+
2
+ from pathlib import Path, PurePosixPath, PureWindowsPath
3
+ from machineconfig.utils.accessories import randstr
4
+ from machineconfig.utils.meta import lambda_to_python_script
5
+ from machineconfig.utils.ssh_utils.abc import MACHINECONFIG_VERSION, DEFAULT_PICKLE_SUBDIR
6
+ from machineconfig.utils.code import get_uv_command
7
+ from typing import Union, TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from machineconfig.utils.ssh import SSH
11
+
12
+
13
+ def _build_remote_path(self: "SSH", home_dir: str, rel_path: str) -> str:
14
+ if self.remote_specs["system"] == "Windows":
15
+ return str(PureWindowsPath(home_dir) / rel_path)
16
+ return str(PurePosixPath(home_dir) / PurePosixPath(rel_path.replace("\\", "/")))
17
+
18
+
19
+ def _normalize_rel_path_for_remote(self: "SSH", rel_path: str) -> str:
20
+ if self.remote_specs["system"] == "Windows":
21
+ return str(PureWindowsPath(rel_path))
22
+ return rel_path.replace("\\", "/")
23
+
24
+
25
+ def create_dir_and_check_if_exists(self: "SSH", path_rel2home: str, overwrite_existing: bool) -> None:
26
+ """Helper to create a directory on remote machine and return its path."""
27
+ path_rel2home_normalized = _normalize_rel_path_for_remote(self, path_rel2home)
28
+ def create_target_dir(target_rel2home: str, overwrite: bool):
29
+ from pathlib import Path
30
+ import shutil
31
+ target_path_abs = Path(target_rel2home).expanduser()
32
+ if not target_path_abs.is_absolute():
33
+ target_path_abs = Path.home().joinpath(target_path_abs)
34
+ if overwrite and target_path_abs.exists():
35
+ if str(target_path_abs) == str(Path.home()):
36
+ raise RuntimeError("Refusing to overwrite home directory!")
37
+ if target_path_abs.is_dir():
38
+ shutil.rmtree(target_path_abs)
39
+ else:
40
+ target_path_abs.unlink()
41
+ print(f"Creating directory for path: {target_path_abs}")
42
+ target_path_abs.parent.mkdir(parents=True, exist_ok=True)
43
+ command = lambda_to_python_script(
44
+ lambda: create_target_dir(target_rel2home=path_rel2home_normalized, overwrite=overwrite_existing),
45
+ in_global=True, import_module=False
46
+ )
47
+ tmp_py_file = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/create_target_dir_{randstr()}.py")
48
+ tmp_py_file.parent.mkdir(parents=True, exist_ok=True)
49
+ tmp_py_file.write_text(command, encoding="utf-8")
50
+ assert self.sftp is not None
51
+ tmp_remote_path = ".tmp_pyfile.py"
52
+ remote_tmp_full = _build_remote_path(self, self.remote_specs["home_dir"], tmp_remote_path)
53
+ self.sftp.put(localpath=str(tmp_py_file), remotepath=remote_tmp_full)
54
+ resp = self.run_shell_cmd_on_remote(
55
+ command=f"""{get_uv_command(platform=self.remote_specs['system'])} run python {tmp_remote_path}""",
56
+ verbose_output=False,
57
+ description=f"Creating target dir {path_rel2home}",
58
+ strict_stderr=True,
59
+ strict_return_code=True,
60
+ )
61
+ resp.print(desc=f"Created target dir {path_rel2home}")
62
+
63
+
64
+ def check_remote_is_dir(self: "SSH", source_path: Union[str, Path]) -> bool:
65
+ """Helper to check if a remote path is a directory."""
66
+
67
+ def check_is_dir(path_to_check: str, json_output_path: str) -> bool:
68
+ from pathlib import Path
69
+ import json
70
+
71
+ is_directory = Path(path_to_check).expanduser().absolute().is_dir()
72
+ json_result_path = Path(json_output_path)
73
+ json_result_path.parent.mkdir(parents=True, exist_ok=True)
74
+ json_result_path.write_text(json.dumps(is_directory, indent=2), encoding="utf-8")
75
+ print(json_result_path.as_posix())
76
+ return is_directory
77
+
78
+ remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
79
+ command = lambda_to_python_script(
80
+ lambda: check_is_dir(path_to_check=str(source_path), json_output_path=remote_json_output),
81
+ in_global=True, import_module=False
82
+ )
83
+ response = self.run_py_remotely(
84
+ python_code=command,
85
+ uv_with=[MACHINECONFIG_VERSION],
86
+ uv_project_dir=None,
87
+ description=f"Check if source `{source_path}` is a dir",
88
+ verbose_output=False,
89
+ strict_stderr=False,
90
+ strict_return_code=False,
91
+ )
92
+ remote_json_path = response.op.strip()
93
+ if not remote_json_path:
94
+ raise RuntimeError(f"Failed to check if {source_path} is directory - no response from remote")
95
+
96
+ local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
97
+ self.simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
98
+ import json
99
+
100
+ try:
101
+ result = json.loads(local_json.read_text(encoding="utf-8"))
102
+ except (json.JSONDecodeError, FileNotFoundError) as err:
103
+ raise RuntimeError(f"Failed to check if {source_path} is directory - invalid JSON response: {err}") from err
104
+ finally:
105
+ if local_json.exists():
106
+ local_json.unlink()
107
+ assert isinstance(result, bool), f"Failed to check if {source_path} is directory"
108
+ return result
109
+
110
+ def expand_remote_path(self: "SSH", source_path: Union[str, Path]) -> str:
111
+ """Helper to expand a path on the remote machine."""
112
+
113
+ def expand_source(path_to_expand: str, json_output_path: str) -> str:
114
+ from pathlib import Path
115
+ import json
116
+
117
+ expanded_path_posix = Path(path_to_expand).expanduser().absolute().as_posix()
118
+ json_result_path = Path(json_output_path)
119
+ json_result_path.parent.mkdir(parents=True, exist_ok=True)
120
+ json_result_path.write_text(json.dumps(expanded_path_posix, indent=2), encoding="utf-8")
121
+ print(json_result_path.as_posix())
122
+ return expanded_path_posix
123
+
124
+ remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
125
+ command = lambda_to_python_script(
126
+ lambda: expand_source(path_to_expand=str(source_path), json_output_path=remote_json_output),
127
+ in_global=True, import_module=False
128
+ )
129
+ response = self.run_py_remotely(
130
+ python_code=command,
131
+ uv_with=[MACHINECONFIG_VERSION],
132
+ uv_project_dir=None,
133
+ description="Resolving source path by expanding user",
134
+ verbose_output=False,
135
+ strict_stderr=False,
136
+ strict_return_code=False,
137
+ )
138
+ remote_json_path = response.op.strip()
139
+ if not remote_json_path:
140
+ raise RuntimeError(f"Could not resolve source path {source_path} - no response from remote")
141
+
142
+ local_json = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/local_{randstr()}.json")
143
+ self.simple_sftp_get(remote_path=remote_json_path, local_path=local_json)
144
+ import json
145
+
146
+ try:
147
+ result = json.loads(local_json.read_text(encoding="utf-8"))
148
+ except (json.JSONDecodeError, FileNotFoundError) as err:
149
+ raise RuntimeError(f"Could not resolve source path {source_path} - invalid JSON response: {err}") from err
150
+ finally:
151
+ if local_json.exists():
152
+ local_json.unlink()
153
+ assert isinstance(result, str), f"Could not resolve source path {source_path}"
154
+ return result
155
+
156
+
157
+ if __name__ == "__main__":
158
+ from machineconfig.utils.ssh import SSH