machineconfig 8.12__py3-none-any.whl → 8.45__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of machineconfig might be problematic. Click here for more details.

Files changed (273) 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 +225 -140
  13. machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
  14. machineconfig/jobs/installer/package_groups.py +10 -9
  15. machineconfig/jobs/installer/python_scripts/boxes.py +1 -2
  16. machineconfig/jobs/installer/python_scripts/code.py +10 -8
  17. machineconfig/jobs/installer/python_scripts/hx.py +30 -13
  18. machineconfig/jobs/installer/python_scripts/nerfont_windows_helper.py +6 -5
  19. machineconfig/jobs/installer/python_scripts/sysabc.py +25 -19
  20. machineconfig/jobs/installer/python_scripts/yazi.py +33 -17
  21. machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
  22. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +1 -1
  23. machineconfig/jobs/scripts_dynamic/a.py +413 -10
  24. machineconfig/profile/create_links.py +77 -20
  25. machineconfig/profile/create_links_export.py +40 -51
  26. machineconfig/profile/mapper_data.toml +30 -0
  27. machineconfig/profile/mapper_dotfiles.toml +253 -0
  28. machineconfig/scripts/python/agents.py +70 -172
  29. machineconfig/scripts/python/ai/initai.py +3 -1
  30. machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
  31. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
  32. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +7 -5
  33. machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
  34. machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
  35. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +1 -1
  36. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +29 -0
  37. machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
  38. machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
  39. machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
  40. machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
  41. machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
  42. machineconfig/scripts/python/ai/utils/vscode_tasks.py +6 -3
  43. machineconfig/scripts/python/cloud.py +58 -11
  44. machineconfig/scripts/python/croshell.py +4 -156
  45. machineconfig/scripts/python/devops.py +57 -40
  46. machineconfig/scripts/python/devops_navigator.py +17 -3
  47. machineconfig/scripts/python/fire_jobs.py +8 -207
  48. machineconfig/scripts/python/ftpx.py +5 -225
  49. machineconfig/scripts/python/graph/cli_graph.json +8743 -0
  50. machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
  51. machineconfig/scripts/python/{env_manager → helpers/helper_env}/env_manager_tui.py +1 -1
  52. machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
  53. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.py +1 -1
  54. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
  55. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_gemini.py +1 -1
  56. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_qwen.py +1 -1
  57. machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
  58. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_launch.py +5 -5
  59. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +6 -6
  60. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +10 -5
  61. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +3 -3
  62. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
  63. machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +225 -0
  64. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
  65. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +7 -6
  66. machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
  67. machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +267 -0
  68. machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +98 -0
  69. machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
  70. machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +76 -0
  71. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_nw.py +52 -72
  72. machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +265 -0
  73. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_self.py +45 -21
  74. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_file.py +44 -30
  75. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_server.py +26 -43
  76. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_terminal.py +12 -6
  77. machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
  78. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +12 -6
  79. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
  80. machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +69 -45
  81. machineconfig/scripts/python/helpers/helpers_devops/run_script.py +197 -0
  82. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
  83. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
  84. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +3 -3
  85. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
  86. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +3 -3
  87. machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
  88. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_linux/fzfg +4 -3
  89. machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
  90. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_windows/fzfg.ps1 +1 -1
  91. machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
  92. machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
  93. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
  94. machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
  95. machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
  96. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
  97. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
  98. machineconfig/scripts/python/helpers/helpers_network/__init__.py +0 -0
  99. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address.py +15 -17
  100. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address_switch.py +1 -1
  101. machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
  102. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_ssh.py +2 -2
  103. machineconfig/scripts/python/helpers/helpers_network/ssh_add_identity.py +73 -0
  104. machineconfig/scripts/python/helpers/helpers_network/ssh_add_ssh_key.py +175 -0
  105. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_linux.py +319 -0
  106. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_windows.py +275 -0
  107. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
  108. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
  109. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +116 -33
  110. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +3 -2
  111. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -13
  112. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_2.py +63 -19
  113. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
  114. machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
  115. machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
  116. machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +177 -0
  117. machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +1 -1
  118. machineconfig/scripts/python/helpers/helpers_terminal/__init__.py +0 -0
  119. machineconfig/scripts/python/helpers/helpers_terminal/terminal_impl.py +96 -0
  120. machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/download.py +1 -1
  121. machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/python.py +49 -29
  122. machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
  123. machineconfig/scripts/python/mcfg_entry.py +133 -48
  124. machineconfig/scripts/python/msearch.py +15 -61
  125. machineconfig/scripts/python/sessions.py +59 -194
  126. machineconfig/scripts/python/terminal.py +18 -96
  127. machineconfig/scripts/python/utils.py +101 -20
  128. machineconfig/settings/atuin/config.toml +294 -0
  129. machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
  130. machineconfig/settings/linters/.ruff.toml +1 -0
  131. machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
  132. machineconfig/settings/shells/bash/init.sh +6 -3
  133. machineconfig/settings/shells/pwsh/init.ps1 +69 -1
  134. machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
  135. machineconfig/settings/shells/wezterm/wezterm.lua +4 -1
  136. machineconfig/settings/shells/wt/settings.json +20 -7
  137. machineconfig/settings/shells/zsh/init.sh +34 -4
  138. machineconfig/settings/television/cable_unix/bash-history.toml +1 -1
  139. machineconfig/settings/television/cable_windows/pwsh-history.toml +1 -1
  140. machineconfig/settings/tv/config.toml +234 -0
  141. machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
  142. machineconfig/settings/wsl/.wslconfig +5 -30
  143. machineconfig/settings/yazi/yazi_linux.toml +18 -8
  144. machineconfig/settings/zellij/layouts/st.kdl +2 -2
  145. machineconfig/settings/zellij/layouts/st2.kdl +1 -1
  146. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  147. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +3 -0
  148. machineconfig/setup_mac/__init__.py +0 -2
  149. machineconfig/setup_windows/__init__.py +0 -1
  150. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +14 -13
  151. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +4 -3
  152. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -3
  153. machineconfig/type_hinting/sql/__init__.py +1 -0
  154. machineconfig/type_hinting/sql/base.py +216 -0
  155. machineconfig/type_hinting/sql/core_schema.py +64 -0
  156. machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
  157. machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
  158. machineconfig/type_hinting/typedict/__init__.py +1 -0
  159. machineconfig/type_hinting/typedict/ast_utils.py +130 -0
  160. machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
  161. machineconfig/type_hinting/typedict/generators.py +231 -0
  162. machineconfig/type_hinting/typedict/polars_schema.py +24 -0
  163. machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
  164. machineconfig/utils/accessories.py +24 -0
  165. machineconfig/utils/code.py +79 -37
  166. machineconfig/utils/files/ascii_art.py +10 -14
  167. machineconfig/utils/files/headers.py +3 -5
  168. machineconfig/utils/files/read.py +8 -1
  169. machineconfig/utils/installer_utils/github_release_bulk.py +1 -0
  170. machineconfig/utils/installer_utils/install_from_url.py +1 -1
  171. machineconfig/utils/installer_utils/installer_class.py +12 -4
  172. machineconfig/utils/installer_utils/installer_cli.py +1 -15
  173. machineconfig/utils/installer_utils/installer_helper.py +2 -2
  174. machineconfig/utils/installer_utils/installer_locator_utils.py +13 -13
  175. machineconfig/utils/installer_utils/installer_runner.py +4 -4
  176. machineconfig/utils/meta.py +6 -4
  177. machineconfig/utils/options.py +49 -19
  178. machineconfig/utils/options_utils/__init__.py +0 -0
  179. machineconfig/utils/options_utils/options_tv_linux.py +211 -0
  180. machineconfig/utils/options_utils/options_tv_windows.py +88 -0
  181. machineconfig/utils/options_utils/tv_options.py +37 -0
  182. machineconfig/utils/path_extended.py +6 -6
  183. machineconfig/utils/scheduler.py +8 -2
  184. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  185. machineconfig/utils/source_of_truth.py +6 -1
  186. machineconfig/utils/ssh.py +73 -22
  187. machineconfig/utils/ssh_utils/abc.py +1 -1
  188. machineconfig/utils/ssh_utils/copy_from_here.py +2 -2
  189. machineconfig/utils/ssh_utils/utils.py +2 -2
  190. machineconfig/utils/ssh_utils/wsl.py +107 -170
  191. machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
  192. machineconfig/utils/upgrade_packages.py +4 -8
  193. {machineconfig-8.12.dist-info → machineconfig-8.45.dist-info}/METADATA +29 -22
  194. {machineconfig-8.12.dist-info → machineconfig-8.45.dist-info}/RECORD +249 -211
  195. machineconfig/jobs/installer/check_installations.py +0 -248
  196. machineconfig/jobs/scripts/bash_scripts/mint_keyboard_shortcuts.sh +0 -30
  197. machineconfig/profile/backup.toml +0 -49
  198. machineconfig/profile/mapper.toml +0 -263
  199. machineconfig/scripts/python/helpers_devops/cli_config.py +0 -105
  200. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -89
  201. machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
  202. machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -208
  203. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
  204. machineconfig/scripts/python/helpers_devops/run_script.py +0 -168
  205. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
  206. machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
  207. machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
  208. machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -620
  209. machineconfig/scripts/python/helpers_network/ssh_add_identity.py +0 -116
  210. machineconfig/scripts/python/helpers_network/ssh_add_ssh_key.py +0 -153
  211. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +0 -391
  212. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +0 -338
  213. machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -77
  214. machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
  215. machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
  216. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
  217. machineconfig/utils/options_tv.py +0 -119
  218. machineconfig/utils/tst.py +0 -20
  219. /machineconfig/{scripts/python/helpers_agents → jobs/installer/checks}/__init__.py +0 -0
  220. /machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
  221. /machineconfig/scripts/python/{helpers_agents/agentic_frameworks → graph}/__init__.py +0 -0
  222. /machineconfig/scripts/python/{helpers_cloud → helpers}/__init__.py +0 -0
  223. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
  224. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
  225. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_agents}/__init__.py +0 -0
  226. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_agents/agentic_frameworks}/__init__.py +0 -0
  227. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
  228. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
  229. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_helper_types.py +0 -0
  230. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
  231. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aichat/config.yaml +0 -0
  232. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aider/.aider.conf.yml +0 -0
  233. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/copilot/config.yml +0 -0
  234. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/crush/crush.json +0 -0
  235. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/gemini/settings.json +0 -0
  236. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/privacy.py +0 -0
  237. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/prompt.txt +0 -0
  238. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.ps1 +0 -0
  239. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.sh +0 -0
  240. /machineconfig/scripts/python/{helpers_devops/themes → helpers/helpers_cloud}/__init__.py +0 -0
  241. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +0 -0
  242. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
  243. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_croshell}/__init__.py +0 -0
  244. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +0 -0
  245. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
  246. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
  247. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
  248. /machineconfig/scripts/python/{helpers_network → helpers/helpers_devops}/__init__.py +0 -0
  249. /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_devops/themes}/__init__.py +0 -0
  250. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  251. /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_fire_command/__init__.py} +0 -0
  252. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
  253. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/f.py +0 -0
  254. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/file_wrangler.py +0 -0
  255. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +0 -0
  256. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_streamlit_helper.py +0 -0
  257. /machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/__init__.py +0 -0
  258. /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
  259. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nfs.py +0 -0
  260. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nw_drive.py +0 -0
  261. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/onetimeshare.py +0 -0
  262. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/wifi_conn.py +0 -0
  263. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -0
  264. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_1.py +0 -0
  265. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
  266. /machineconfig/scripts/python/helpers/{ast_search.py → helpers_search/ast_search.py} +0 -0
  267. /machineconfig/scripts/python/helpers/{qr_code.py → helpers_search/qr_code.py} +0 -0
  268. /machineconfig/scripts/python/helpers/{repo_rag.py → helpers_search/repo_rag.py} +0 -0
  269. /machineconfig/scripts/python/helpers/{symantic_search.py → helpers_search/symantic_search.py} +0 -0
  270. /machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/pdf.py +0 -0
  271. {machineconfig-8.12.dist-info → machineconfig-8.45.dist-info}/WHEEL +0 -0
  272. {machineconfig-8.12.dist-info → machineconfig-8.45.dist-info}/entry_points.txt +0 -0
  273. {machineconfig-8.12.dist-info → machineconfig-8.45.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.python 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.python 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,18 +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/ssh/openssh-server_add-sshkey.ps1"
219
- import urllib.request
220
- with urllib.request.urlopen(code_url) as response:
221
- code = response.read().decode("utf-8")
222
- 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)
223
257
 
224
258
  def get_remote_repr(self, add_machine: bool = False) -> str:
225
259
  return f"{self.username}@{self.hostname}:{self.port}" + (
226
260
  f" [{self.remote_specs['system']}][{self.remote_specs['distro']}]" if add_machine else ""
227
261
  )
262
+
228
263
  def get_local_repr(self, add_machine: bool = False) -> str:
229
264
  import getpass
265
+
230
266
  return f"{getpass.getuser()}@{platform.node()}" + (f" [{platform.system()}][{self.local_specs['distro']}]" if add_machine else "")
231
267
 
232
268
  def get_ssh_conn_str(self, command: str) -> str:
@@ -246,7 +282,9 @@ class SSH:
246
282
  res.output.returncode = os.system(command)
247
283
  return res
248
284
 
249
- 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:
250
288
  raw = self.ssh.exec_command(command)
251
289
  res = Response(stdin=raw[0], stdout=raw[1], stderr=raw[2], cmd=command, desc=description) # type: ignore
252
290
  if verbose_output:
@@ -273,12 +311,12 @@ class SSH:
273
311
  with_clause += ""
274
312
  match on:
275
313
  case "local":
276
- uv_run_cmd = get_uv_run_command(platform=self.local_specs["system"])
314
+ uv_cmd = get_uv_command(platform=self.local_specs["system"])
277
315
  case "remote":
278
- uv_run_cmd = get_uv_run_command(platform=self.remote_specs["system"])
316
+ uv_cmd = get_uv_command(platform=self.remote_specs["system"])
279
317
  case _:
280
318
  raise ValueError(f"Invalid value for 'on': {on}. Must be 'local' or 'remote'")
281
- 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())}"""
282
320
  return uv_cmd
283
321
 
284
322
  def run_py_remotely(
@@ -301,8 +339,7 @@ class SSH:
301
339
  )
302
340
 
303
341
  def run_lambda_function(self, func: Callable[..., Any], import_module: bool, uv_with: Optional[list[str]], uv_project_dir: Optional[str]):
304
- command = lambda_to_python_script(func,
305
- in_global=True, import_module=import_module)
342
+ command = lambda_to_python_script(func, in_global=True, import_module=import_module)
306
343
  # turns ou that the code below for some reason runs but zellij doesn't start, looks like things are assigned to different user.
307
344
  # return self.run_py(python_code=command, uv_with=uv_with, uv_project_dir=uv_project_dir,
308
345
  # description=f"run_py_func {func.__name__} on {self.get_remote_repr(add_machine=False)}",
@@ -334,25 +371,39 @@ class SSH:
334
371
 
335
372
  def create_parent_dir_and_check_if_exists(self, path_rel2home: str, overwrite_existing: bool) -> None:
336
373
  from machineconfig.utils.ssh_utils.utils import create_dir_and_check_if_exists
374
+
337
375
  return create_dir_and_check_if_exists(self, path_rel2home=path_rel2home, overwrite_existing=overwrite_existing)
338
376
 
339
377
  def check_remote_is_dir(self, source_path: Union[str, Path]) -> bool:
340
378
  from machineconfig.utils.ssh_utils.utils import check_remote_is_dir
379
+
341
380
  return check_remote_is_dir(self, source_path=source_path)
342
381
 
343
382
  def expand_remote_path(self, source_path: Union[str, Path]) -> str:
344
383
  from machineconfig.utils.ssh_utils.utils import expand_remote_path
384
+
345
385
  return expand_remote_path(self, source_path=source_path)
346
386
 
347
- 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:
348
390
  from machineconfig.utils.ssh_utils.copy_from_here import copy_from_here
349
- 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)
350
391
 
351
- 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:
352
404
  from machineconfig.utils.ssh_utils.copy_to_here import copy_to_here
353
- return copy_to_here(self, source=source, target=target, compress_with_zip=compress_with_zip, recursive=recursive, internal_call=internal_call)
354
405
 
355
-
406
+ return copy_to_here(self, source=source, target=target, compress_with_zip=compress_with_zip, recursive=recursive, internal_call=internal_call)
356
407
 
357
408
 
358
409
  if __name__ == "__main__":
@@ -1,5 +1,5 @@
1
1
 
2
2
 
3
- MACHINECONFIG_VERSION = "machineconfig>=8.12"
3
+ MACHINECONFIG_VERSION = "machineconfig>=8.45"
4
4
  DEFAULT_PICKLE_SUBDIR = "tmp_results/tmp_scripts/ssh"
5
5
 
@@ -5,7 +5,7 @@ from pathlib import Path
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
9
 
10
10
 
11
11
  def copy_from_here(
@@ -96,7 +96,7 @@ def copy_from_here(
96
96
  remote_tmp_py = tmp_py_file.relative_to(Path.home()).as_posix()
97
97
  self.copy_from_here(source_path=str(tmp_py_file), target_rel2home=None, compress_with_zip=False, recursive=False, overwrite_existing=True)
98
98
  self.run_shell_cmd_on_remote(
99
- command=f"""{get_uv_run_command(platform=self.remote_specs['system'])} python {remote_tmp_py}""",
99
+ command=f"""{get_uv_command(platform=self.remote_specs['system'])} run python {remote_tmp_py}""",
100
100
  verbose_output=False,
101
101
  description=f"UNZIPPING {target_rel2home}",
102
102
  strict_stderr=True,
@@ -3,7 +3,7 @@ from pathlib import Path
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
6
+ from machineconfig.utils.code import get_uv_command
7
7
  from typing import Union
8
8
 
9
9
 
@@ -36,7 +36,7 @@ def create_dir_and_check_if_exists(self: "SSH", path_rel2home: str, overwrite_ex
36
36
  tmp_remote_path = ".tmp_pyfile.py"
37
37
  self.sftp.put(localpath=str(tmp_py_file), remotepath=str(Path(self.remote_specs["home_dir"]).joinpath(tmp_remote_path)))
38
38
  resp = self.run_shell_cmd_on_remote(
39
- command=f"""{get_uv_run_command(platform=self.remote_specs['system'])} python {tmp_remote_path}""",
39
+ command=f"""{get_uv_command(platform=self.remote_specs['system'])} run python {tmp_remote_path}""",
40
40
  verbose_output=False,
41
41
  description=f"Creating target dir {path_rel2home}",
42
42
  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)