machineconfig 7.98__py3-none-any.whl → 8.61__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 (353) hide show
  1. machineconfig/cluster/remote/run_cluster.py +1 -1
  2. machineconfig/cluster/remote/run_remote.py +1 -1
  3. machineconfig/cluster/sessions_managers/utils/maker.py +10 -8
  4. machineconfig/cluster/sessions_managers/wt_local.py +1 -1
  5. machineconfig/cluster/sessions_managers/wt_local_manager.py +1 -1
  6. machineconfig/cluster/sessions_managers/zellij_local.py +1 -1
  7. machineconfig/cluster/sessions_managers/zellij_local_manager.py +1 -1
  8. machineconfig/jobs/installer/checks/check_installations.py +133 -0
  9. machineconfig/jobs/installer/checks/install_utils.py +132 -0
  10. machineconfig/jobs/installer/checks/report_utils.py +39 -0
  11. machineconfig/jobs/installer/checks/vt_utils.py +89 -0
  12. machineconfig/jobs/installer/installer_data.json +271 -152
  13. machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
  14. machineconfig/jobs/installer/package_groups.py +11 -9
  15. machineconfig/jobs/installer/{custom → python_scripts}/boxes.py +1 -2
  16. machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +1 -1
  17. machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +10 -8
  18. machineconfig/jobs/installer/{custom → python_scripts}/hx.py +30 -13
  19. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +1 -1
  20. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +6 -5
  21. machineconfig/jobs/installer/{custom_dev → python_scripts}/sysabc.py +28 -43
  22. machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +1 -1
  23. machineconfig/jobs/installer/{custom → python_scripts}/yazi.py +39 -19
  24. machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
  25. machineconfig/jobs/scripts_dynamic/a.py +428 -0
  26. machineconfig/logger.py +1 -1
  27. machineconfig/profile/create_helper.py +21 -10
  28. machineconfig/profile/create_links.py +77 -20
  29. machineconfig/profile/create_links_export.py +63 -58
  30. machineconfig/profile/create_shell_profile.py +14 -0
  31. machineconfig/profile/mapper_data.toml +45 -0
  32. machineconfig/profile/mapper_dotfiles.toml +249 -0
  33. machineconfig/scripts/python/agents.py +76 -171
  34. machineconfig/scripts/python/ai/initai.py +3 -1
  35. machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
  36. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
  37. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +8 -6
  38. machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
  39. machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
  40. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +1 -1
  41. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +29 -0
  42. machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
  43. machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
  44. machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
  45. machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
  46. machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
  47. machineconfig/scripts/python/ai/utils/vscode_tasks.py +6 -3
  48. machineconfig/scripts/python/cloud.py +58 -11
  49. machineconfig/scripts/python/croshell.py +4 -155
  50. machineconfig/scripts/python/devops.py +57 -38
  51. machineconfig/scripts/python/devops_navigator.py +17 -3
  52. machineconfig/scripts/python/fire_jobs.py +10 -193
  53. machineconfig/scripts/python/ftpx.py +5 -224
  54. machineconfig/scripts/python/graph/cli_graph.json +8743 -0
  55. machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
  56. machineconfig/scripts/python/{env_manager → helpers/helper_env}/env_manager_tui.py +1 -1
  57. machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
  58. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.py +1 -1
  59. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
  60. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_gemini.py +1 -1
  61. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_qwen.py +1 -1
  62. machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
  63. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_launch.py +10 -7
  64. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
  65. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
  66. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/copilot/config.yml +1 -0
  67. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/crush/crush.json +10 -0
  68. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/gemini/settings.json +12 -0
  69. machineconfig/scripts/python/helpers/helpers_agents/privacy/privacy.py +109 -0
  70. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.sh +3 -1
  71. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +6 -6
  72. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +10 -5
  73. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +4 -4
  74. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
  75. machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +229 -0
  76. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
  77. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +7 -6
  78. machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
  79. machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +262 -0
  80. machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +130 -0
  81. machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
  82. machineconfig/scripts/python/helpers/helpers_devops/cli_config_mount.py +77 -0
  83. machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +71 -0
  84. machineconfig/scripts/python/helpers/helpers_devops/cli_nw.py +285 -0
  85. machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +274 -0
  86. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_self.py +84 -33
  87. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_file.py +44 -30
  88. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_server.py +26 -43
  89. machineconfig/scripts/python/helpers/helpers_devops/cli_share_temp.py +69 -0
  90. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_terminal.py +12 -6
  91. machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
  92. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +12 -6
  93. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
  94. machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +64 -50
  95. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/commands.py +25 -0
  96. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/device_entry.py +17 -0
  97. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/devices.py +17 -0
  98. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/linux.py +103 -0
  99. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/macos.py +100 -0
  100. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/selection.py +47 -0
  101. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/utils.py +28 -0
  102. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/windows.py +91 -0
  103. machineconfig/scripts/python/helpers/helpers_devops/run_script.py +197 -0
  104. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
  105. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
  106. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +3 -3
  107. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/file_wrangler.py +1 -0
  108. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +1 -0
  109. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
  110. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +3 -3
  111. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_streamlit_helper.py +0 -0
  112. machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
  113. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_linux/fzfg +4 -3
  114. machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
  115. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_windows/fzfg.ps1 +2 -7
  116. machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
  117. machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
  118. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
  119. machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
  120. machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
  121. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
  122. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
  123. machineconfig/scripts/python/helpers/helpers_network/__init__.py +0 -0
  124. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address.py +52 -10
  125. machineconfig/scripts/python/helpers/helpers_network/address_switch.py +78 -0
  126. machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
  127. machineconfig/scripts/python/helpers/helpers_network/ssh/__init__.py +0 -0
  128. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_add_identity.py +73 -0
  129. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_add_key_windows.py +23 -0
  130. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_add_ssh_key.py +169 -0
  131. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_cloud_init.py +33 -0
  132. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_linux.py +338 -0
  133. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_linux_utils.py +35 -0
  134. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_windows.py +245 -0
  135. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_windows_utils.py +34 -0
  136. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
  137. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
  138. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +120 -37
  139. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +3 -2
  140. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -13
  141. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_2.py +63 -19
  142. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
  143. machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
  144. machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
  145. machineconfig/scripts/python/helpers/helpers_sessions/attach_impl.py +87 -0
  146. machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +114 -0
  147. machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +1 -2
  148. machineconfig/scripts/python/helpers/helpers_sessions/utils.py +69 -0
  149. machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/download.py +1 -1
  150. machineconfig/scripts/python/{helpers_devops/cli_utils.py → helpers/helpers_utils/pdf.py} +2 -2
  151. machineconfig/scripts/python/{helpers_utils/path.py → helpers/helpers_utils/python.py} +65 -40
  152. machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
  153. machineconfig/scripts/python/mcfg_entry.py +126 -48
  154. machineconfig/scripts/python/msearch.py +16 -61
  155. machineconfig/scripts/python/sessions.py +137 -191
  156. machineconfig/scripts/python/utils.py +104 -24
  157. machineconfig/settings/atuin/config.toml +294 -0
  158. machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
  159. machineconfig/settings/linters/.ruff.toml +2 -1
  160. machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
  161. machineconfig/settings/shells/bash/init.sh +6 -10
  162. machineconfig/settings/shells/nushell/config.nu +23 -1
  163. machineconfig/settings/shells/nushell/env.nu +22 -48
  164. machineconfig/settings/shells/nushell/init.nu +64 -240
  165. machineconfig/settings/shells/pwsh/init.ps1 +71 -5
  166. machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
  167. machineconfig/settings/shells/wezterm/wezterm.lua +4 -0
  168. machineconfig/settings/shells/wt/settings.json +31 -37
  169. machineconfig/settings/shells/zsh/init.sh +25 -5
  170. machineconfig/settings/television/cable_unix/bash-history.toml +1 -1
  171. machineconfig/settings/television/cable_windows/pwsh-history.toml +1 -1
  172. machineconfig/settings/tv/config.toml +234 -0
  173. machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
  174. machineconfig/settings/wsl/.wslconfig +5 -30
  175. machineconfig/settings/wt/__init__.py +0 -0
  176. machineconfig/settings/yazi/yazi_linux.toml +18 -8
  177. machineconfig/settings/zellij/__init__.py +0 -0
  178. machineconfig/settings/zellij/config.kdl +0 -295
  179. machineconfig/settings/zellij/layouts/__init__.py +0 -0
  180. machineconfig/settings/zellij/layouts/st.kdl +39 -9
  181. machineconfig/settings/zellij/layouts/st2.kdl +6 -2
  182. machineconfig/setup_linux/__init__.py +0 -1
  183. machineconfig/setup_linux/apps_desktop.sh +8 -27
  184. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  185. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +3 -0
  186. machineconfig/setup_mac/__init__.py +0 -2
  187. machineconfig/setup_windows/__init__.py +2 -5
  188. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +14 -13
  189. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +4 -3
  190. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -3
  191. machineconfig/type_hinting/sql/__init__.py +1 -0
  192. machineconfig/type_hinting/sql/base.py +216 -0
  193. machineconfig/type_hinting/sql/core_schema.py +64 -0
  194. machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
  195. machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
  196. machineconfig/type_hinting/typedict/__init__.py +1 -0
  197. machineconfig/type_hinting/typedict/ast_utils.py +130 -0
  198. machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
  199. machineconfig/type_hinting/typedict/generators.py +231 -0
  200. machineconfig/type_hinting/typedict/polars_schema.py +24 -0
  201. machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
  202. machineconfig/utils/accessories.py +24 -0
  203. machineconfig/utils/code.py +78 -33
  204. machineconfig/utils/files/ascii_art.py +10 -14
  205. machineconfig/utils/files/headers.py +3 -5
  206. machineconfig/utils/files/read.py +8 -1
  207. machineconfig/utils/installer_utils/github_release_bulk.py +11 -91
  208. machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
  209. machineconfig/utils/installer_utils/install_from_url.py +1 -1
  210. machineconfig/utils/installer_utils/installer_class.py +12 -4
  211. machineconfig/utils/installer_utils/installer_cli.py +7 -17
  212. machineconfig/utils/installer_utils/installer_helper.py +52 -36
  213. machineconfig/utils/installer_utils/installer_locator_utils.py +15 -25
  214. machineconfig/utils/installer_utils/installer_runner.py +4 -4
  215. machineconfig/utils/io.py +25 -8
  216. machineconfig/utils/meta.py +6 -4
  217. machineconfig/utils/options.py +49 -19
  218. machineconfig/utils/options_utils/__init__.py +0 -0
  219. machineconfig/utils/options_utils/options_tv_linux.py +211 -0
  220. machineconfig/utils/options_utils/options_tv_windows.py +88 -0
  221. machineconfig/utils/options_utils/tv_options.py +37 -0
  222. machineconfig/utils/path_extended.py +8 -7
  223. machineconfig/utils/procs.py +35 -27
  224. machineconfig/utils/scheduler.py +8 -2
  225. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  226. machineconfig/utils/schemas/layouts/layout_types.py +10 -0
  227. machineconfig/utils/source_of_truth.py +7 -1
  228. machineconfig/utils/ssh.py +73 -23
  229. machineconfig/utils/ssh_utils/abc.py +1 -1
  230. machineconfig/utils/ssh_utils/copy_from_here.py +19 -14
  231. machineconfig/utils/ssh_utils/copy_to_here.py +2 -1
  232. machineconfig/utils/ssh_utils/utils.py +23 -7
  233. machineconfig/utils/ssh_utils/wsl.py +107 -170
  234. machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
  235. machineconfig/utils/upgrade_packages.py +4 -8
  236. {machineconfig-7.98.dist-info → machineconfig-8.61.dist-info}/METADATA +30 -23
  237. machineconfig-8.61.dist-info/RECORD +539 -0
  238. {machineconfig-7.98.dist-info → machineconfig-8.61.dist-info}/entry_points.txt +0 -1
  239. machineconfig/jobs/installer/check_installations.py +0 -248
  240. machineconfig/profile/backup.toml +0 -49
  241. machineconfig/profile/mapper.toml +0 -263
  242. machineconfig/scripts/linux/other/share_cloud.sh +0 -64
  243. machineconfig/scripts/linux/other/share_nfs +0 -49
  244. machineconfig/scripts/linux/other/start_docker +0 -23
  245. machineconfig/scripts/linux/other/switch_ip +0 -20
  246. machineconfig/scripts/python/helpers/run_py_script.py +0 -79
  247. machineconfig/scripts/python/helpers/tmp_py_scripts/a.py +0 -26
  248. machineconfig/scripts/python/helpers_devops/cli_config.py +0 -105
  249. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -89
  250. machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
  251. machineconfig/scripts/python/helpers_devops/cli_nw.py +0 -214
  252. machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -215
  253. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
  254. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
  255. machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
  256. machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
  257. machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -620
  258. machineconfig/scripts/python/helpers_network/devops_add_identity.py +0 -82
  259. machineconfig/scripts/python/helpers_network/devops_add_ssh_key.py +0 -153
  260. machineconfig/scripts/python/helpers_network/mount_drive +0 -128
  261. machineconfig/scripts/python/helpers_network/mount_nfs +0 -49
  262. machineconfig/scripts/python/helpers_network/mount_nfs.py +0 -85
  263. machineconfig/scripts/python/helpers_network/mount_nw_drive +0 -61
  264. machineconfig/scripts/python/helpers_network/mount_nw_drive.py +0 -48
  265. machineconfig/scripts/python/helpers_network/mount_smb +0 -3
  266. machineconfig/scripts/python/helpers_network/mount_ssh.py +0 -64
  267. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +0 -391
  268. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +0 -338
  269. machineconfig/scripts/python/helpers_network/wsl_windows_transfer.py +0 -67
  270. machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -77
  271. machineconfig/scripts/python/terminal.py +0 -133
  272. machineconfig/scripts/windows/mounts/Restore-ThunderbirdProfile.ps1 +0 -92
  273. machineconfig/scripts/windows/mounts/mount_nfs.ps1 +0 -42
  274. machineconfig/scripts/windows/mounts/mount_nw.ps1 +0 -9
  275. machineconfig/scripts/windows/mounts/mount_smb.ps1 +0 -2
  276. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
  277. machineconfig/scripts/windows/mounts/share_cloud.cmd +0 -34
  278. machineconfig/scripts/windows/mounts/share_smb.ps1 +0 -16
  279. machineconfig/settings/zellij/config.orig.kdl +0 -295
  280. machineconfig/setup_linux/others/android.sh +0 -2
  281. machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh +0 -30
  282. machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
  283. machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
  284. machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
  285. machineconfig/setup_windows/others/docker.ps1 +0 -7
  286. machineconfig/setup_windows/others/obs.ps1 +0 -4
  287. machineconfig/setup_windows/others/power_options.ps1 +0 -7
  288. machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
  289. machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
  290. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
  291. machineconfig/setup_windows/ssh/openssh-server_add_key.ps1 +0 -7
  292. machineconfig/setup_windows/ssh/openssh-server_copy-ssh-id.ps1 +0 -14
  293. machineconfig/utils/options_tv.py +0 -119
  294. machineconfig/utils/tst.py +0 -20
  295. machineconfig-7.98.dist-info/RECORD +0 -504
  296. /machineconfig/{jobs/installer/custom_dev → cluster/sessions_managers/wt_utils/examples}/__init__.py +0 -0
  297. /machineconfig/{scripts/python/helpers_agents → jobs/installer/checks}/__init__.py +0 -0
  298. /machineconfig/{scripts/python/helpers_agents/agentic_frameworks → jobs/installer/python_scripts}/__init__.py +0 -0
  299. /machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
  300. /machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
  301. /machineconfig/jobs/installer/{custom_dev → python_scripts}/cloudflare_warp_cli.py +0 -0
  302. /machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
  303. /machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +0 -0
  304. /machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
  305. /machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
  306. /machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
  307. /machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
  308. /machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
  309. /machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +0 -0
  310. /machineconfig/jobs/{installer/linux_scripts → scripts/bash_scripts}/lid.sh +0 -0
  311. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
  312. /machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
  313. /machineconfig/scripts/python/{helpers_cloud → graph}/__init__.py +0 -0
  314. /machineconfig/scripts/python/{helpers_croshell → helpers}/__init__.py +0 -0
  315. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
  316. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
  317. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_agents}/__init__.py +0 -0
  318. /machineconfig/scripts/python/{helpers_devops/themes → helpers/helpers_agents/agentic_frameworks}/__init__.py +0 -0
  319. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
  320. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
  321. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_helper_types.py +0 -0
  322. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
  323. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/prompt.txt +0 -0
  324. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.ps1 +0 -0
  325. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_cloud}/__init__.py +0 -0
  326. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +0 -0
  327. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
  328. /machineconfig/scripts/python/{helpers_network → helpers/helpers_croshell}/__init__.py +0 -0
  329. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +0 -0
  330. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
  331. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
  332. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
  333. /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_devops}/__init__.py +0 -0
  334. /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers/helpers_devops/mount_helpers}/__init__.py +0 -0
  335. /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_devops/themes/__init__.py} +0 -0
  336. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  337. /machineconfig/scripts/python/{helpers_fire_command/f.py → helpers/helpers_fire_command/__init__.py} +0 -0
  338. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
  339. /machineconfig/scripts/python/{helpers_fire_command/fire_jobs_streamlit_helper.py → helpers/helpers_fire_command/f.py} +0 -0
  340. /machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/__init__.py +0 -0
  341. /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
  342. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/onetimeshare.py +0 -0
  343. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/wifi_conn.py +0 -0
  344. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -0
  345. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_1.py +0 -0
  346. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
  347. /machineconfig/scripts/python/helpers/{ast_search.py → helpers_search/ast_search.py} +0 -0
  348. /machineconfig/scripts/python/helpers/{qr_code.py → helpers_search/qr_code.py} +0 -0
  349. /machineconfig/scripts/python/helpers/{repo_rag.py → helpers_search/repo_rag.py} +0 -0
  350. /machineconfig/scripts/python/helpers/{symantic_search.py → helpers_search/symantic_search.py} +0 -0
  351. /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
  352. {machineconfig-7.98.dist-info → machineconfig-8.61.dist-info}/WHEEL +0 -0
  353. {machineconfig-7.98.dist-info → machineconfig-8.61.dist-info}/top_level.txt +0 -0
@@ -2,8 +2,8 @@ from typing import Callable, Optional, Any, cast, Union, Literal
2
2
  import os
3
3
  from pathlib import Path
4
4
  import platform
5
- from machineconfig.scripts.python.helpers_utils.path import MachineSpecs
6
- from machineconfig.utils.code import get_uv_run_command
5
+ from machineconfig.scripts.python.helpers.helpers_utils.python import MachineSpecs
6
+ from machineconfig.utils.code import get_uv_command
7
7
  import rich.console
8
8
  from machineconfig.utils.terminal import Response
9
9
  from machineconfig.utils.accessories import pprint, randstr
@@ -14,7 +14,6 @@ from machineconfig.utils.ssh_utils.abc import DEFAULT_PICKLE_SUBDIR
14
14
  class SSH:
15
15
  @staticmethod
16
16
  def from_config_file(host: str) -> "SSH":
17
- """Create SSH instance from SSH config file entry."""
18
17
  return SSH(host=host, username=None, hostname=None, ssh_key_path=None, password=None, port=22, enable_compression=False)
19
18
 
20
19
  def __init__(
@@ -148,8 +147,10 @@ class SSH:
148
147
  def view_bar(self, transferred: int, total: int) -> None:
149
148
  if self.progress and self.task is not None:
150
149
  self.progress.update(self.task, completed=transferred, total=total)
150
+
151
151
  self.tqdm_wrap = RichProgressWrapper
152
- from machineconfig.scripts.python.helpers_utils.path import get_machine_specs
152
+ from machineconfig.scripts.python.helpers.helpers_utils.python import get_machine_specs
153
+
153
154
  self.local_specs: MachineSpecs = get_machine_specs()
154
155
  resp = self.run_shell_cmd_on_remote(
155
156
  command="""~/.local/bin/utils get-machine-specs """,
@@ -160,6 +161,7 @@ class SSH:
160
161
  )
161
162
  json_str = resp.op
162
163
  import ast
164
+
163
165
  self.remote_specs: MachineSpecs = cast(MachineSpecs, ast.literal_eval(json_str))
164
166
  self.terminal_responses: list[Response] = []
165
167
 
@@ -177,10 +179,22 @@ class SSH:
177
179
  local_console = rich.console.Console(file=local_buffer, width=40)
178
180
  remote_console = rich.console.Console(file=remote_buffer, width=40)
179
181
  inspect(
180
- type("LocalInfo", (object,), dict(self.local_specs))(), value=False, title="SSHing From", docs=False, dunder=False, sort=False, console=local_console
182
+ type("LocalInfo", (object,), dict(self.local_specs))(),
183
+ value=False,
184
+ title="SSHing From",
185
+ docs=False,
186
+ dunder=False,
187
+ sort=False,
188
+ console=local_console,
181
189
  )
182
190
  inspect(
183
- type("RemoteInfo", (object,), dict(self.remote_specs))(), value=False, title="SSHing To", docs=False, dunder=False, sort=False, console=remote_console
191
+ type("RemoteInfo", (object,), dict(self.remote_specs))(),
192
+ value=False,
193
+ title="SSHing To",
194
+ docs=False,
195
+ dunder=False,
196
+ sort=False,
197
+ console=remote_console,
184
198
  )
185
199
  local_lines = local_buffer.getvalue().split("\n")
186
200
  remote_lines = remote_buffer.getvalue().split("\n")
@@ -215,19 +229,40 @@ class SSH:
215
229
  self.copy_from_here(source_path="~/.ssh/id_rsa.pub", target_rel2home=None, compress_with_zip=False, recursive=False, overwrite_existing=False)
216
230
  if self.remote_specs["system"] != "Windows":
217
231
  raise RuntimeError("send_ssh_key is only supported for Windows remote machines")
218
- code_url = "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/refs/heads/main/src/machineconfig/setup_windows/openssh-server_add-sshkey.ps1"
219
- import urllib.request
220
-
221
- with urllib.request.urlopen(code_url) as response:
222
- code = response.read().decode("utf-8")
223
- return self.run_shell_cmd_on_remote(command=code, verbose_output=True, description="", strict_stderr=False, strict_return_code=False)
232
+ python_code = '''
233
+ from pathlib import Path
234
+ import subprocess
235
+ sshd_dir = Path("C:/ProgramData/ssh")
236
+ admin_auth_keys = sshd_dir / "administrators_authorized_keys"
237
+ sshd_config = sshd_dir / "sshd_config"
238
+ pubkey_path = Path.home() / ".ssh" / "id_rsa.pub"
239
+ key_content = pubkey_path.read_text(encoding="utf-8").strip()
240
+ if admin_auth_keys.exists():
241
+ existing = admin_auth_keys.read_text(encoding="utf-8")
242
+ if not existing.endswith("\\n"):
243
+ existing += "\\n"
244
+ admin_auth_keys.write_text(existing + key_content + "\\n", encoding="utf-8")
245
+ else:
246
+ admin_auth_keys.write_text(key_content + "\\n", encoding="utf-8")
247
+ icacls_cmd = f'icacls "{admin_auth_keys}" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"'
248
+ subprocess.run(icacls_cmd, shell=True, check=True)
249
+ if sshd_config.exists():
250
+ config_text = sshd_config.read_text(encoding="utf-8")
251
+ config_text = config_text.replace("#PubkeyAuthentication", "PubkeyAuthentication")
252
+ sshd_config.write_text(config_text, encoding="utf-8")
253
+ subprocess.run("Restart-Service sshd -Force", shell=True, check=True)
254
+ print("SSH key added successfully")
255
+ '''
256
+ return self.run_py_remotely(python_code=python_code, uv_with=None, uv_project_dir=None, description="Adding SSH key to Windows remote", verbose_output=True, strict_stderr=False, strict_return_code=False)
224
257
 
225
258
  def get_remote_repr(self, add_machine: bool = False) -> str:
226
259
  return f"{self.username}@{self.hostname}:{self.port}" + (
227
260
  f" [{self.remote_specs['system']}][{self.remote_specs['distro']}]" if add_machine else ""
228
261
  )
262
+
229
263
  def get_local_repr(self, add_machine: bool = False) -> str:
230
264
  import getpass
265
+
231
266
  return f"{getpass.getuser()}@{platform.node()}" + (f" [{platform.system()}][{self.local_specs['distro']}]" if add_machine else "")
232
267
 
233
268
  def get_ssh_conn_str(self, command: str) -> str:
@@ -247,7 +282,9 @@ class SSH:
247
282
  res.output.returncode = os.system(command)
248
283
  return res
249
284
 
250
- def run_shell_cmd_on_remote(self, command: str, verbose_output: bool, description: str, strict_stderr: bool, strict_return_code: bool) -> Response:
285
+ def run_shell_cmd_on_remote(
286
+ self, command: str, verbose_output: bool, description: str, strict_stderr: bool, strict_return_code: bool
287
+ ) -> Response:
251
288
  raw = self.ssh.exec_command(command)
252
289
  res = Response(stdin=raw[0], stdout=raw[1], stderr=raw[2], cmd=command, desc=description) # type: ignore
253
290
  if verbose_output:
@@ -274,12 +311,12 @@ class SSH:
274
311
  with_clause += ""
275
312
  match on:
276
313
  case "local":
277
- uv_run_cmd = get_uv_run_command(platform=self.local_specs["system"])
314
+ uv_cmd = get_uv_command(platform=self.local_specs["system"])
278
315
  case "remote":
279
- uv_run_cmd = get_uv_run_command(platform=self.remote_specs["system"])
316
+ uv_cmd = get_uv_command(platform=self.remote_specs["system"])
280
317
  case _:
281
318
  raise ValueError(f"Invalid value for 'on': {on}. Must be 'local' or 'remote'")
282
- uv_cmd = f"""{uv_run_cmd} {with_clause} python {py_path.relative_to(Path.home())}"""
319
+ uv_cmd = f"""{uv_cmd} run {with_clause} python {py_path.relative_to(Path.home())}"""
283
320
  return uv_cmd
284
321
 
285
322
  def run_py_remotely(
@@ -302,8 +339,7 @@ class SSH:
302
339
  )
303
340
 
304
341
  def run_lambda_function(self, func: Callable[..., Any], import_module: bool, uv_with: Optional[list[str]], uv_project_dir: Optional[str]):
305
- command = lambda_to_python_script(func,
306
- in_global=True, import_module=import_module)
342
+ command = lambda_to_python_script(func, in_global=True, import_module=import_module)
307
343
  # turns ou that the code below for some reason runs but zellij doesn't start, looks like things are assigned to different user.
308
344
  # return self.run_py(python_code=command, uv_with=uv_with, uv_project_dir=uv_project_dir,
309
345
  # description=f"run_py_func {func.__name__} on {self.get_remote_repr(add_machine=False)}",
@@ -335,25 +371,39 @@ class SSH:
335
371
 
336
372
  def create_parent_dir_and_check_if_exists(self, path_rel2home: str, overwrite_existing: bool) -> None:
337
373
  from machineconfig.utils.ssh_utils.utils import create_dir_and_check_if_exists
374
+
338
375
  return create_dir_and_check_if_exists(self, path_rel2home=path_rel2home, overwrite_existing=overwrite_existing)
339
376
 
340
377
  def check_remote_is_dir(self, source_path: Union[str, Path]) -> bool:
341
378
  from machineconfig.utils.ssh_utils.utils import check_remote_is_dir
379
+
342
380
  return check_remote_is_dir(self, source_path=source_path)
343
381
 
344
382
  def expand_remote_path(self, source_path: Union[str, Path]) -> str:
345
383
  from machineconfig.utils.ssh_utils.utils import expand_remote_path
384
+
346
385
  return expand_remote_path(self, source_path=source_path)
347
386
 
348
- def copy_from_here(self, source_path: str, target_rel2home: Optional[str], compress_with_zip: bool, recursive: bool, overwrite_existing: bool) -> None:
387
+ def copy_from_here(
388
+ self, source_path: str, target_rel2home: Optional[str], compress_with_zip: bool, recursive: bool, overwrite_existing: bool
389
+ ) -> None:
349
390
  from machineconfig.utils.ssh_utils.copy_from_here import copy_from_here
350
- return copy_from_here(self, source_path=source_path, target_rel2home=target_rel2home, compress_with_zip=compress_with_zip, recursive=recursive, overwrite_existing=overwrite_existing)
351
391
 
352
- def copy_to_here(self, source: Union[str, Path], target: Optional[Union[str, Path]], compress_with_zip: bool, recursive: bool, internal_call: bool = False) -> None:
392
+ return copy_from_here(
393
+ self,
394
+ source_path=source_path,
395
+ target_rel2home=target_rel2home,
396
+ compress_with_zip=compress_with_zip,
397
+ recursive=recursive,
398
+ overwrite_existing=overwrite_existing,
399
+ )
400
+
401
+ def copy_to_here(
402
+ self, source: Union[str, Path], target: Optional[Union[str, Path]], compress_with_zip: bool, recursive: bool, internal_call: bool = False
403
+ ) -> None:
353
404
  from machineconfig.utils.ssh_utils.copy_to_here import copy_to_here
354
- return copy_to_here(self, source=source, target=target, compress_with_zip=compress_with_zip, recursive=recursive, internal_call=internal_call)
355
405
 
356
-
406
+ return copy_to_here(self, source=source, target=target, compress_with_zip=compress_with_zip, recursive=recursive, internal_call=internal_call)
357
407
 
358
408
 
359
409
  if __name__ == "__main__":
@@ -1,5 +1,5 @@
1
1
 
2
2
 
3
- MACHINECONFIG_VERSION = "machineconfig>=7.98"
3
+ MACHINECONFIG_VERSION = "machineconfig>=8.61"
4
4
  DEFAULT_PICKLE_SUBDIR = "tmp_results/tmp_scripts/ssh"
5
5
 
@@ -1,11 +1,20 @@
1
1
 
2
2
 
3
- from typing import Optional
4
- from pathlib import Path
3
+ from typing import Optional, TYPE_CHECKING
4
+ from pathlib import Path, PurePosixPath, PureWindowsPath
5
5
  from machineconfig.utils.accessories import randstr
6
6
  from machineconfig.utils.meta import lambda_to_python_script
7
7
  from machineconfig.utils.ssh_utils.abc import DEFAULT_PICKLE_SUBDIR
8
- from machineconfig.utils.code import get_uv_run_command
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("\\", "/")))
9
18
 
10
19
 
11
20
  def copy_from_here(
@@ -54,15 +63,14 @@ def copy_from_here(
54
63
  target_rel2home = target_rel2home + ".zip"
55
64
  if Path(target_rel2home).parent.as_posix() not in {"", "."}:
56
65
  self.create_parent_dir_and_check_if_exists(path_rel2home=target_rel2home, overwrite_existing=overwrite_existing)
57
- print(f"""📤 [SFTP UPLOAD] Sending file: {repr(source_obj)} ==> Remote Path: {target_rel2home}""")
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}""")
58
68
  try:
59
69
  with self.tqdm_wrap(ascii=True, unit="b", unit_scale=True) as pbar:
60
70
  if self.sftp is None: # type: ignore[unreachable]
61
71
  raise RuntimeError(f"SFTP connection lost for {self.hostname}")
62
- print(f"Uploading {source_obj} to\n{Path(self.remote_specs['home_dir']).joinpath(target_rel2home)}")
63
- self.sftp.put(
64
- localpath=str(source_obj), remotepath=str(Path(self.remote_specs["home_dir"]).joinpath(target_rel2home)), callback=pbar.view_bar
65
- )
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)
66
74
  except Exception:
67
75
  if compress_with_zip and source_obj.exists() and str(source_obj).endswith("_archive.zip"):
68
76
  source_obj.unlink()
@@ -83,12 +91,9 @@ def copy_from_here(
83
91
  archive_handle.extractall(extraction_directory)
84
92
  archive_path.unlink()
85
93
 
94
+ remote_zip_path = _build_remote_path(self, self.remote_specs["home_dir"], target_rel2home)
86
95
  command = lambda_to_python_script(
87
- lambda: unzip_archive(
88
- zip_file_path=str(Path(self.remote_specs["home_dir"]).joinpath(target_rel2home)), overwrite_flag=overwrite_existing
89
- ),
90
- in_global=True,
91
- import_module=False,
96
+ lambda: unzip_archive(zip_file_path=remote_zip_path, overwrite_flag=overwrite_existing), in_global=True, import_module=False
92
97
  )
93
98
  tmp_py_file = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/create_target_dir_{randstr()}.py")
94
99
  tmp_py_file.parent.mkdir(parents=True, exist_ok=True)
@@ -96,7 +101,7 @@ def copy_from_here(
96
101
  remote_tmp_py = tmp_py_file.relative_to(Path.home()).as_posix()
97
102
  self.copy_from_here(source_path=str(tmp_py_file), target_rel2home=None, compress_with_zip=False, recursive=False, overwrite_existing=True)
98
103
  self.run_shell_cmd_on_remote(
99
- command=f"""{get_uv_run_command(platform=self.remote_specs['system'])} python {remote_tmp_py}""",
104
+ command=f"""{get_uv_command(platform=self.remote_specs['system'])} run python {remote_tmp_py}""",
100
105
  verbose_output=False,
101
106
  description=f"UNZIPPING {target_rel2home}",
102
107
  strict_stderr=True,
@@ -8,7 +8,7 @@ from machineconfig.utils.ssh_utils.abc import MACHINECONFIG_VERSION, DEFAULT_PIC
8
8
 
9
9
 
10
10
  def copy_to_here(
11
- self: SSH,
11
+ self: "SSH",
12
12
  source: Union[str, Path],
13
13
  target: Optional[Union[str, Path]],
14
14
  compress_with_zip: bool = False,
@@ -300,3 +300,4 @@ def copy_to_here(
300
300
 
301
301
  if __name__ == "__main__":
302
302
  from machineconfig.utils.ssh import SSH
303
+
@@ -1,15 +1,30 @@
1
1
 
2
- from pathlib import Path
2
+ from pathlib import Path, PurePosixPath, PureWindowsPath
3
3
  from machineconfig.utils.accessories import randstr
4
4
  from machineconfig.utils.meta import lambda_to_python_script
5
5
  from machineconfig.utils.ssh_utils.abc import MACHINECONFIG_VERSION, DEFAULT_PICKLE_SUBDIR
6
- from machineconfig.utils.code import get_uv_run_command
7
- from typing import Union
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("\\", "/")
8
23
 
9
24
 
10
25
  def create_dir_and_check_if_exists(self: "SSH", path_rel2home: str, overwrite_existing: bool) -> None:
11
26
  """Helper to create a directory on remote machine and return its path."""
12
-
27
+ path_rel2home_normalized = _normalize_rel_path_for_remote(self, path_rel2home)
13
28
  def create_target_dir(target_rel2home: str, overwrite: bool):
14
29
  from pathlib import Path
15
30
  import shutil
@@ -26,7 +41,7 @@ def create_dir_and_check_if_exists(self: "SSH", path_rel2home: str, overwrite_ex
26
41
  print(f"Creating directory for path: {target_path_abs}")
27
42
  target_path_abs.parent.mkdir(parents=True, exist_ok=True)
28
43
  command = lambda_to_python_script(
29
- lambda: create_target_dir(target_rel2home=path_rel2home, overwrite=overwrite_existing),
44
+ lambda: create_target_dir(target_rel2home=path_rel2home_normalized, overwrite=overwrite_existing),
30
45
  in_global=True, import_module=False
31
46
  )
32
47
  tmp_py_file = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/create_target_dir_{randstr()}.py")
@@ -34,9 +49,10 @@ def create_dir_and_check_if_exists(self: "SSH", path_rel2home: str, overwrite_ex
34
49
  tmp_py_file.write_text(command, encoding="utf-8")
35
50
  assert self.sftp is not None
36
51
  tmp_remote_path = ".tmp_pyfile.py"
37
- self.sftp.put(localpath=str(tmp_py_file), remotepath=str(Path(self.remote_specs["home_dir"]).joinpath(tmp_remote_path)))
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)
38
54
  resp = self.run_shell_cmd_on_remote(
39
- command=f"""{get_uv_run_command(platform=self.remote_specs['system'])} python {tmp_remote_path}""",
55
+ command=f"""{get_uv_command(platform=self.remote_specs['system'])} run python {tmp_remote_path}""",
40
56
  verbose_output=False,
41
57
  description=f"Creating target dir {path_rel2home}",
42
58
  strict_stderr=True,
@@ -1,167 +1,35 @@
1
- import os
2
1
  import platform
3
- import stat
2
+ import re
4
3
  import shutil
5
4
  import subprocess
6
- from pathlib import Path, PureWindowsPath
7
-
8
-
9
- def _ensure_relative_path(requested: Path | str) -> Path:
10
- path = Path(requested)
11
- if path.is_absolute():
12
- raise ValueError("paths must be relative to the home directory")
13
- if any(part == ".." for part in path.parts):
14
- raise ValueError("paths must stay within the home directory")
15
- return path
16
-
17
-
18
- def _remove_path(path: Path) -> None:
19
- if path.is_symlink() or path.is_file():
20
- path.unlink()
21
- return
22
- shutil.rmtree(path)
23
-
24
-
25
- def _ensure_wsl_environment() -> None:
26
- if os.environ.get("WSL_DISTRO_NAME"):
27
- return
28
- if "microsoft" in platform.release().lower():
29
- return
30
- raise RuntimeError("copy_when_inside_wsl must run inside WSL")
31
-
32
-
33
- def _ensure_windows_environment() -> None:
34
- if os.name != "nt":
35
- raise RuntimeError("copy_when_inside_windows must run inside Windows")
36
- if os.environ.get("WSL_DISTRO_NAME"):
37
- raise RuntimeError("copy_when_inside_windows must run inside Windows")
38
-
39
-
40
- def _infer_windows_home_from_permissions() -> Path:
41
- base_dir = Path("/mnt/c/Users")
42
- try:
43
- entries = list(base_dir.iterdir())
44
- except FileNotFoundError as exc:
45
- raise RuntimeError("unable to find /mnt/c/Users") from exc
46
- candidates: list[Path] = []
47
- for entry in entries:
48
- if not entry.is_dir():
49
- continue
50
- if entry.name.lower() == "public" or entry.name.lower() == "all users":
51
- continue
52
- try:
53
- mode = stat.S_IMODE(entry.stat().st_mode)
54
- except OSError:
55
- continue
56
- if mode == 0o777:
57
- candidates.append(entry)
58
- if len(candidates) != 1:
59
- options = ", ".join(sorted(candidate.name for candidate in candidates)) or "none"
60
- raise RuntimeError(f"unable to infer Windows home directory (candidates: {options})")
61
- return candidates[0]
62
-
63
-
64
- def _resolve_windows_home_from_wsl() -> Path:
65
- user_profile = os.environ.get("USERPROFILE")
66
- if user_profile:
67
- windows_path = PureWindowsPath(user_profile)
68
- drive = windows_path.drive
69
- if drive:
70
- drive_letter = drive.rstrip(":").lower()
71
- tail = Path(*windows_path.parts[1:])
72
- candidate = Path("/mnt") / drive_letter / tail
73
- if candidate.exists():
74
- return candidate
75
- return _infer_windows_home_from_permissions()
76
-
77
-
78
- def _decode_wsl_output(raw_bytes: bytes) -> str:
79
- try:
80
- return raw_bytes.decode("utf-16-le")
81
- except UnicodeDecodeError:
82
- return raw_bytes.decode()
83
-
84
-
85
- def _get_single_wsl_distribution() -> str:
86
- process = subprocess.run(["wsl.exe", "-l"], capture_output=True, text=False, check=True)
87
- stdout = _decode_wsl_output(process.stdout).replace("\ufeff", "")
88
- distributions: list[str] = []
89
- for raw_line in stdout.splitlines():
90
- line = raw_line.strip()
91
- if not line or line.lower().startswith("windows subsystem for linux"):
92
- continue
93
- normalized = line.lstrip("* ").replace("(Default)", "").strip()
94
- if normalized:
95
- distributions.append(normalized)
96
- if len(distributions) != 1:
97
- raise RuntimeError("unable to pick a single WSL distribution")
98
- return distributions[0]
99
-
100
-
101
- def _resolve_wsl_home_on_windows() -> Path:
102
- distribution = _get_single_wsl_distribution()
103
- home_root = Path(rf"\\wsl$\{distribution}\home")
104
- try:
105
- entries = list(home_root.iterdir())
106
- except FileNotFoundError as exc:
107
- raise RuntimeError(f"unable to locate WSL home directories for {distribution}") from exc
108
- except OSError as exc:
109
- raise RuntimeError(f"unable to inspect WSL home directories for {distribution}") from exc
110
- user_dirs = [entry for entry in entries if entry.is_dir()]
111
- if len(user_dirs) != 1:
112
- options = ", ".join(sorted(entry.name for entry in user_dirs)) or "none"
113
- raise RuntimeError(f"unable to infer WSL user directory (candidates: {options})")
114
- return user_dirs[0]
115
-
116
-
117
- def _quote_for_powershell(path: Path) -> str:
118
- return "'" + str(path).replace("'", "''") + "'"
119
-
120
-
121
- def _run_windows_copy_command(source_path: Path, target_path: Path) -> None:
122
- source_is_dir = source_path.is_dir()
123
- parent_literal = _quote_for_powershell(target_path.parent)
124
- source_literal = _quote_for_powershell(source_path)
125
- target_literal = _quote_for_powershell(target_path)
126
- script = (
127
- "$ErrorActionPreference = 'Stop'; "
128
- f"New-Item -ItemType Directory -Path {parent_literal} -Force | Out-Null; "
129
- f"Copy-Item -LiteralPath {source_literal} -Destination {target_literal}"
130
- f"{' -Recurse' if source_is_dir else ''} -Force"
131
- )
132
- print(f"Copying {source_path} to {target_path}")
133
- subprocess.run(
134
- ["powershell.exe", "-NoLogo", "-NoProfile", "-Command", script],
135
- check=True,
136
- )
137
-
138
-
139
- def _ensure_symlink(link_path: Path, target_path: Path) -> None:
140
- if not target_path.exists():
141
- raise FileNotFoundError(target_path)
142
- if link_path.is_symlink():
143
- existing_target = Path(os.path.realpath(link_path))
144
- desired_target = Path(os.path.realpath(target_path))
145
- if os.path.normcase(str(existing_target)) == os.path.normcase(str(desired_target)):
146
- return
147
- link_path.unlink()
148
- elif link_path.exists():
149
- raise FileExistsError(link_path)
150
- link_path.symlink_to(target_path, target_is_directory=True)
151
-
152
-
153
- def copy_when_inside_wsl(source: Path | str, target: Path | str, overwrite: bool) -> None:
154
- _ensure_wsl_environment()
155
- source_relative = _ensure_relative_path(source)
156
- target_relative = _ensure_relative_path(target)
5
+ from pathlib import Path
6
+
7
+ from machineconfig.utils.ssh_utils.wsl_helper import (
8
+ ensure_relative_path,
9
+ remove_path,
10
+ ensure_wsl_environment,
11
+ ensure_windows_environment,
12
+ ensure_linux_environment,
13
+ resolve_windows_home_from_wsl,
14
+ resolve_wsl_home_on_windows,
15
+ run_windows_copy_command,
16
+ ensure_symlink,
17
+ normalize_port_spec_for_firewall,
18
+ )
19
+
20
+
21
+ def copy_when_inside_wsl(source: Path | str, target: Path | str, overwrite: bool, windows_username: str | None) -> None:
22
+ ensure_wsl_environment()
23
+ source_relative = ensure_relative_path(source)
24
+ target_relative = ensure_relative_path(target)
157
25
  source_path = Path.home() / source_relative
158
- target_path = _resolve_windows_home_from_wsl() / target_relative
26
+ target_path = resolve_windows_home_from_wsl(windows_username) / target_relative
159
27
  if not source_path.exists():
160
28
  raise FileNotFoundError(source_path)
161
29
  if target_path.exists():
162
30
  if not overwrite:
163
31
  raise FileExistsError(target_path)
164
- _remove_path(target_path)
32
+ remove_path(target_path)
165
33
  target_path.parent.mkdir(parents=True, exist_ok=True)
166
34
  if source_path.is_dir():
167
35
  shutil.copytree(source_path, target_path, dirs_exist_ok=False)
@@ -171,40 +39,109 @@ def copy_when_inside_wsl(source: Path | str, target: Path | str, overwrite: bool
171
39
 
172
40
 
173
41
  def copy_when_inside_windows(source: Path | str, target: Path | str, overwrite: bool) -> None:
174
- _ensure_windows_environment()
175
- source_relative = _ensure_relative_path(source)
176
- target_relative = _ensure_relative_path(target)
42
+ ensure_windows_environment()
43
+ source_relative = ensure_relative_path(source)
44
+ target_relative = ensure_relative_path(target)
177
45
  source_path = Path.home() / source_relative
178
- target_path = _resolve_wsl_home_on_windows() / target_relative
46
+ target_path = resolve_wsl_home_on_windows() / target_relative
179
47
  if not source_path.exists():
180
48
  raise FileNotFoundError(source_path)
181
49
  if target_path.exists():
182
50
  if not overwrite:
183
51
  raise FileExistsError(target_path)
184
- _remove_path(target_path)
185
- _run_windows_copy_command(source_path, target_path)
52
+ remove_path(target_path)
53
+ run_windows_copy_command(source_path, target_path)
186
54
 
187
55
 
188
- def link_wsl_and_windows() -> None:
56
+ def link_wsl_and_windows(windows_username: str | None) -> None:
189
57
  system = platform.system()
190
58
  if system == "Darwin":
191
59
  raise RuntimeError("link_wsl_and_windows is not designed for macOS")
192
60
  try:
193
- _ensure_wsl_environment()
61
+ ensure_wsl_environment()
194
62
  except RuntimeError:
195
63
  try:
196
- _ensure_windows_environment()
64
+ ensure_windows_environment()
197
65
  except RuntimeError as exc:
198
66
  raise RuntimeError("link_wsl_and_windows must run inside Windows or WSL") from exc
199
- target_path = _resolve_wsl_home_on_windows()
67
+ print("🔗 Running inside Windows, linking to WSL home...")
68
+ target_path = resolve_wsl_home_on_windows()
200
69
  link_path = Path.home() / "wsl"
201
- _ensure_symlink(link_path, target_path)
70
+ created = ensure_symlink(link_path, target_path)
71
+ if created:
72
+ print(f"✅ Created symlink: {link_path} -> {target_path}")
73
+ else:
74
+ print(f"✅ Symlink already exists: {link_path} -> {target_path}")
202
75
  return
203
- target_path = _resolve_windows_home_from_wsl()
76
+ print("🔗 Running inside WSL, linking to Windows home...")
77
+ target_path = resolve_windows_home_from_wsl(windows_username)
204
78
  link_path = Path.home() / "win"
205
- _ensure_symlink(link_path, target_path)
79
+ created = ensure_symlink(link_path, target_path)
80
+ if created:
81
+ print(f"✅ Created symlink: {link_path} -> {target_path}")
82
+ else:
83
+ print(f"✅ Symlink already exists: {link_path} -> {target_path}")
84
+
85
+
86
+ def open_wsl_port(ports_spec: str) -> None:
87
+ ensure_windows_environment()
88
+ normalized_ports, description = normalize_port_spec_for_firewall(ports_spec)
89
+ rule_name = f"WSL Ports {description}"
90
+ # Build PowerShell array syntax for -LocalPort parameter (e.g., @('3000-4000','8080'))
91
+ port_parts = normalized_ports.split(",")
92
+ ps_array = "@(" + ",".join(f"'{p}'" for p in port_parts) + ")"
93
+ script = f"New-NetFirewallRule -DisplayName '{rule_name}' -Direction Inbound -LocalPort {ps_array} -Protocol TCP -Action Allow"
94
+ print(f"🔥 Opening firewall for ports: {description}...")
95
+ result = subprocess.run(["powershell.exe", "-NoLogo", "-NoProfile", "-Command", script], capture_output=True, text=True)
96
+ if result.returncode == 0:
97
+ print(f"✅ Firewall rule created for ports: {description}")
98
+ else:
99
+ print(f"❌ Failed to create firewall rule: {result.stderr.strip()}")
100
+
101
+
102
+ def change_ssh_port(port: int) -> None:
103
+ ensure_linux_environment()
104
+ if port < 1 or port > 65535:
105
+ raise ValueError(f"Invalid port number: {port}")
106
+
107
+ sshd_config = Path("/etc/ssh/sshd_config")
108
+ if not sshd_config.exists():
109
+ raise FileNotFoundError(f"SSH config file not found: {sshd_config}")
110
+
111
+ print(f"🔧 Changing SSH port to {port}...")
112
+
113
+ content = sshd_config.read_text()
114
+ new_content = re.sub(r"^#?\s*Port\s+\d+", f"Port {port}", content, flags=re.MULTILINE)
115
+ if f"Port {port}" not in new_content:
116
+ new_content = f"Port {port}\n" + new_content
117
+
118
+ print(f"📝 Updating {sshd_config}...")
119
+ result = subprocess.run(["sudo", "tee", str(sshd_config)], input=new_content.encode(), capture_output=True)
120
+ if result.returncode != 0:
121
+ raise RuntimeError(f"Failed to update sshd_config: {result.stderr.decode()}")
122
+ print(f"✅ Updated {sshd_config}")
123
+
124
+ override_dir = Path("/etc/systemd/system/ssh.socket.d")
125
+ override_file = override_dir / "override.conf"
126
+ override_content = f"""[Socket]
127
+ ListenStream=
128
+ ListenStream={port}
129
+ """
130
+ print(f"📝 Creating systemd socket override at {override_file}...")
131
+ subprocess.run(["sudo", "mkdir", "-p", str(override_dir)], check=True)
132
+ result = subprocess.run(["sudo", "tee", str(override_file)], input=override_content.encode(), capture_output=True)
133
+ if result.returncode != 0:
134
+ raise RuntimeError(f"Failed to create override file: {result.stderr.decode()}")
135
+ print("✅ Created systemd socket override")
136
+
137
+ print("🔄 Restarting SSH services...")
138
+ subprocess.run(["sudo", "systemctl", "daemon-reload"], check=True)
139
+ subprocess.run(["sudo", "systemctl", "restart", "ssh.socket"], check=False)
140
+ subprocess.run(["sudo", "service", "ssh", "restart"], check=False)
141
+ print(f"✅ SSH port changed to {port}")
142
+ print(f"⚠️ Remember to open port {port} in Windows Firewall if running in WSL")
206
143
 
207
144
 
208
145
  if __name__ == "__main__":
209
- copy_when_inside_wsl(Path("projects/source.txt"), Path("windows_projects/source.txt"), True)
210
- copy_when_inside_windows(Path("documents/example.txt"), Path("linux_documents/example.txt"), True)
146
+ copy_when_inside_wsl(Path("projects/source.txt"), Path("windows_projects/source.txt"), overwrite=True, windows_username=None)
147
+ copy_when_inside_windows(Path("documents/example.txt"), Path("linux_documents/example.txt"), overwrite=True)