machineconfig 7.98__py3-none-any.whl → 8.51__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) 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 +26 -20
  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/powershell_scripts/mount_ssh.ps1 +13 -0
  26. machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +4 -0
  27. machineconfig/jobs/scripts_dynamic/a.py +428 -0
  28. machineconfig/logger.py +1 -1
  29. machineconfig/profile/create_helper.py +21 -10
  30. machineconfig/profile/create_links.py +77 -20
  31. machineconfig/profile/create_links_export.py +63 -58
  32. machineconfig/profile/create_shell_profile.py +14 -0
  33. machineconfig/profile/mapper_data.toml +45 -0
  34. machineconfig/profile/mapper_dotfiles.toml +249 -0
  35. machineconfig/scripts/python/agents.py +76 -171
  36. machineconfig/scripts/python/ai/initai.py +3 -1
  37. machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
  38. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
  39. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +8 -6
  40. machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
  41. machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
  42. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +1 -1
  43. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +29 -0
  44. machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
  45. machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
  46. machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
  47. machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
  48. machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
  49. machineconfig/scripts/python/ai/utils/vscode_tasks.py +6 -3
  50. machineconfig/scripts/python/cloud.py +58 -11
  51. machineconfig/scripts/python/croshell.py +4 -155
  52. machineconfig/scripts/python/devops.py +57 -38
  53. machineconfig/scripts/python/devops_navigator.py +17 -3
  54. machineconfig/scripts/python/fire_jobs.py +10 -193
  55. machineconfig/scripts/python/ftpx.py +5 -224
  56. machineconfig/scripts/python/graph/cli_graph.json +8743 -0
  57. machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
  58. machineconfig/scripts/python/{env_manager → helpers/helper_env}/env_manager_tui.py +1 -1
  59. machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
  60. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.py +1 -1
  61. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
  62. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_gemini.py +1 -1
  63. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_qwen.py +1 -1
  64. machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
  65. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_launch.py +10 -7
  66. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
  67. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
  68. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/copilot/config.yml +1 -0
  69. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/crush/crush.json +10 -0
  70. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/gemini/settings.json +12 -0
  71. machineconfig/scripts/python/helpers/helpers_agents/privacy/privacy.py +109 -0
  72. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.sh +3 -1
  73. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +6 -6
  74. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +10 -5
  75. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +4 -4
  76. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
  77. machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +225 -0
  78. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
  79. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +7 -6
  80. machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
  81. machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +262 -0
  82. machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +98 -0
  83. machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
  84. machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +67 -0
  85. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_nw.py +69 -82
  86. machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +274 -0
  87. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_self.py +47 -22
  88. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_file.py +44 -30
  89. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_server.py +26 -43
  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/run_script.py +197 -0
  96. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
  97. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
  98. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +3 -3
  99. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/file_wrangler.py +1 -0
  100. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +1 -0
  101. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
  102. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +3 -3
  103. machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
  104. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_linux/fzfg +4 -3
  105. machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
  106. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_windows/fzfg.ps1 +1 -1
  107. machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
  108. machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
  109. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
  110. machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
  111. machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
  112. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
  113. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
  114. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address.py +52 -10
  115. machineconfig/scripts/python/helpers/helpers_network/address_switch.py +78 -0
  116. machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
  117. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_ssh.py +2 -2
  118. machineconfig/scripts/python/helpers/helpers_network/ssh_add_identity.py +73 -0
  119. machineconfig/scripts/python/helpers/helpers_network/ssh_add_ssh_key.py +175 -0
  120. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_linux.py +319 -0
  121. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_windows.py +275 -0
  122. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
  123. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
  124. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +118 -34
  125. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +3 -2
  126. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -13
  127. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_2.py +63 -19
  128. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
  129. machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
  130. machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
  131. machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +186 -0
  132. machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +1 -2
  133. machineconfig/scripts/python/helpers/helpers_terminal/__init__.py +0 -0
  134. machineconfig/scripts/python/helpers/helpers_terminal/terminal_impl.py +96 -0
  135. machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/download.py +1 -1
  136. machineconfig/scripts/python/{helpers_devops/cli_utils.py → helpers/helpers_utils/pdf.py} +2 -2
  137. machineconfig/scripts/python/{helpers_utils/path.py → helpers/helpers_utils/python.py} +65 -40
  138. machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
  139. machineconfig/scripts/python/mcfg_entry.py +133 -48
  140. machineconfig/scripts/python/msearch.py +16 -61
  141. machineconfig/scripts/python/sessions.py +68 -203
  142. machineconfig/scripts/python/terminal.py +27 -102
  143. machineconfig/scripts/python/utils.py +101 -22
  144. machineconfig/settings/atuin/config.toml +294 -0
  145. machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
  146. machineconfig/settings/linters/.ruff.toml +2 -1
  147. machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
  148. machineconfig/settings/shells/bash/init.sh +6 -3
  149. machineconfig/settings/shells/nushell/config.nu +23 -1
  150. machineconfig/settings/shells/nushell/env.nu +22 -48
  151. machineconfig/settings/shells/nushell/init.nu +64 -240
  152. machineconfig/settings/shells/pwsh/init.ps1 +69 -1
  153. machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
  154. machineconfig/settings/shells/wezterm/wezterm.lua +4 -1
  155. machineconfig/settings/shells/wt/settings.json +21 -21
  156. machineconfig/settings/shells/zsh/init.sh +25 -4
  157. machineconfig/settings/television/cable_unix/bash-history.toml +1 -1
  158. machineconfig/settings/television/cable_windows/pwsh-history.toml +1 -1
  159. machineconfig/settings/tv/config.toml +234 -0
  160. machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
  161. machineconfig/settings/wsl/.wslconfig +5 -30
  162. machineconfig/settings/wt/__init__.py +0 -0
  163. machineconfig/settings/yazi/yazi_linux.toml +18 -8
  164. machineconfig/settings/zellij/layouts/st.kdl +40 -9
  165. machineconfig/settings/zellij/layouts/st2.kdl +1 -1
  166. machineconfig/setup_linux/__init__.py +0 -1
  167. machineconfig/setup_linux/apps_desktop.sh +8 -27
  168. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  169. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +3 -0
  170. machineconfig/setup_mac/__init__.py +0 -2
  171. machineconfig/setup_windows/__init__.py +2 -5
  172. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +14 -13
  173. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +4 -3
  174. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -3
  175. machineconfig/type_hinting/sql/__init__.py +1 -0
  176. machineconfig/type_hinting/sql/base.py +216 -0
  177. machineconfig/type_hinting/sql/core_schema.py +64 -0
  178. machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
  179. machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
  180. machineconfig/type_hinting/typedict/__init__.py +1 -0
  181. machineconfig/type_hinting/typedict/ast_utils.py +130 -0
  182. machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
  183. machineconfig/type_hinting/typedict/generators.py +231 -0
  184. machineconfig/type_hinting/typedict/polars_schema.py +24 -0
  185. machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
  186. machineconfig/utils/accessories.py +24 -0
  187. machineconfig/utils/code.py +78 -33
  188. machineconfig/utils/files/ascii_art.py +10 -14
  189. machineconfig/utils/files/headers.py +3 -5
  190. machineconfig/utils/files/read.py +8 -1
  191. machineconfig/utils/installer_utils/github_release_bulk.py +11 -91
  192. machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
  193. machineconfig/utils/installer_utils/install_from_url.py +1 -1
  194. machineconfig/utils/installer_utils/installer_class.py +12 -4
  195. machineconfig/utils/installer_utils/installer_cli.py +1 -15
  196. machineconfig/utils/installer_utils/installer_helper.py +2 -2
  197. machineconfig/utils/installer_utils/installer_locator_utils.py +13 -13
  198. machineconfig/utils/installer_utils/installer_runner.py +4 -4
  199. machineconfig/utils/io.py +25 -8
  200. machineconfig/utils/meta.py +6 -4
  201. machineconfig/utils/options.py +49 -19
  202. machineconfig/utils/options_utils/__init__.py +0 -0
  203. machineconfig/utils/options_utils/options_tv_linux.py +211 -0
  204. machineconfig/utils/options_utils/options_tv_windows.py +88 -0
  205. machineconfig/utils/options_utils/tv_options.py +37 -0
  206. machineconfig/utils/path_extended.py +8 -7
  207. machineconfig/utils/scheduler.py +8 -2
  208. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  209. machineconfig/utils/source_of_truth.py +6 -1
  210. machineconfig/utils/ssh.py +73 -23
  211. machineconfig/utils/ssh_utils/abc.py +1 -1
  212. machineconfig/utils/ssh_utils/copy_from_here.py +19 -14
  213. machineconfig/utils/ssh_utils/copy_to_here.py +2 -1
  214. machineconfig/utils/ssh_utils/utils.py +23 -7
  215. machineconfig/utils/ssh_utils/wsl.py +107 -170
  216. machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
  217. machineconfig/utils/upgrade_packages.py +4 -8
  218. {machineconfig-7.98.dist-info → machineconfig-8.51.dist-info}/METADATA +30 -22
  219. machineconfig-8.51.dist-info/RECORD +543 -0
  220. machineconfig/jobs/installer/check_installations.py +0 -248
  221. machineconfig/profile/backup.toml +0 -49
  222. machineconfig/profile/mapper.toml +0 -263
  223. machineconfig/scripts/linux/other/switch_ip +0 -20
  224. machineconfig/scripts/python/helpers/run_py_script.py +0 -79
  225. machineconfig/scripts/python/helpers/tmp_py_scripts/a.py +0 -26
  226. machineconfig/scripts/python/helpers_devops/cli_config.py +0 -105
  227. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -89
  228. machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
  229. machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -215
  230. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
  231. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
  232. machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
  233. machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
  234. machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -620
  235. machineconfig/scripts/python/helpers_network/devops_add_identity.py +0 -82
  236. machineconfig/scripts/python/helpers_network/devops_add_ssh_key.py +0 -153
  237. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +0 -391
  238. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +0 -338
  239. machineconfig/scripts/python/helpers_network/wsl_windows_transfer.py +0 -67
  240. machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -77
  241. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
  242. machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh +0 -30
  243. machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
  244. machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
  245. machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
  246. machineconfig/setup_windows/others/obs.ps1 +0 -4
  247. machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
  248. machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
  249. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
  250. machineconfig/setup_windows/ssh/openssh-server_add_key.ps1 +0 -7
  251. machineconfig/setup_windows/ssh/openssh-server_copy-ssh-id.ps1 +0 -14
  252. machineconfig/utils/options_tv.py +0 -119
  253. machineconfig/utils/tst.py +0 -20
  254. machineconfig-7.98.dist-info/RECORD +0 -504
  255. /machineconfig/jobs/installer/{custom_dev → checks}/__init__.py +0 -0
  256. /machineconfig/{scripts/python/helpers_agents → jobs/installer/python_scripts}/__init__.py +0 -0
  257. /machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
  258. /machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
  259. /machineconfig/jobs/installer/{custom_dev → python_scripts}/cloudflare_warp_cli.py +0 -0
  260. /machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
  261. /machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +0 -0
  262. /machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
  263. /machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
  264. /machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
  265. /machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
  266. /machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
  267. /machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +0 -0
  268. /machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/android.sh +0 -0
  269. /machineconfig/jobs/{installer/linux_scripts → scripts/bash_scripts}/lid.sh +0 -0
  270. /machineconfig/{scripts/python/helpers_network → jobs/scripts/bash_scripts}/mount_drive +0 -0
  271. /machineconfig/{scripts/python/helpers_network → jobs/scripts/bash_scripts}/mount_nfs +0 -0
  272. /machineconfig/{scripts/python/helpers_network → jobs/scripts/bash_scripts}/mount_nw_drive +0 -0
  273. /machineconfig/{scripts/python/helpers_network → jobs/scripts/bash_scripts}/mount_smb +0 -0
  274. /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_cloud.sh +0 -0
  275. /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_nfs +0 -0
  276. /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/start_docker +0 -0
  277. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/Restore-ThunderbirdProfile.ps1 +0 -0
  278. /machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/docker.ps1 +0 -0
  279. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nfs.ps1 +0 -0
  280. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nw.ps1 +0 -0
  281. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_smb.ps1 +0 -0
  282. /machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/power_options.ps1 +0 -0
  283. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_cloud.cmd +0 -0
  284. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_smb.ps1 +0 -0
  285. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
  286. /machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
  287. /machineconfig/scripts/python/{helpers_agents/agentic_frameworks → graph}/__init__.py +0 -0
  288. /machineconfig/scripts/python/{helpers_cloud → helpers}/__init__.py +0 -0
  289. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
  290. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
  291. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_agents}/__init__.py +0 -0
  292. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_agents/agentic_frameworks}/__init__.py +0 -0
  293. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
  294. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
  295. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_helper_types.py +0 -0
  296. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
  297. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/prompt.txt +0 -0
  298. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.ps1 +0 -0
  299. /machineconfig/scripts/python/{helpers_devops/themes → helpers/helpers_cloud}/__init__.py +0 -0
  300. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +0 -0
  301. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
  302. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_croshell}/__init__.py +0 -0
  303. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +0 -0
  304. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
  305. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
  306. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
  307. /machineconfig/scripts/python/{helpers_network → helpers/helpers_devops}/__init__.py +0 -0
  308. /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_devops/themes}/__init__.py +0 -0
  309. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  310. /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers/helpers_fire_command}/__init__.py +0 -0
  311. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
  312. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/f.py +0 -0
  313. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_streamlit_helper.py +0 -0
  314. /machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/__init__.py +0 -0
  315. /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
  316. /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_network/__init__.py} +0 -0
  317. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nfs.py +0 -0
  318. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nw_drive.py +0 -0
  319. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/onetimeshare.py +0 -0
  320. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/wifi_conn.py +0 -0
  321. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -0
  322. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_1.py +0 -0
  323. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
  324. /machineconfig/scripts/python/helpers/{ast_search.py → helpers_search/ast_search.py} +0 -0
  325. /machineconfig/scripts/python/helpers/{qr_code.py → helpers_search/qr_code.py} +0 -0
  326. /machineconfig/scripts/python/helpers/{repo_rag.py → helpers_search/repo_rag.py} +0 -0
  327. /machineconfig/scripts/python/helpers/{symantic_search.py → helpers_search/symantic_search.py} +0 -0
  328. /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
  329. {machineconfig-7.98.dist-info → machineconfig-8.51.dist-info}/WHEEL +0 -0
  330. {machineconfig-7.98.dist-info → machineconfig-8.51.dist-info}/entry_points.txt +0 -0
  331. {machineconfig-7.98.dist-info → machineconfig-8.51.dist-info}/top_level.txt +0 -0
@@ -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)
@@ -0,0 +1,217 @@
1
+ import os
2
+ import platform
3
+ import stat
4
+ import shutil
5
+ 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 ensure_linux_environment() -> None:
41
+ if platform.system() != "Linux":
42
+ raise RuntimeError("change_ssh_port requires Linux environment")
43
+
44
+
45
+ def infer_windows_home_from_permissions(windows_username: str | None) -> Path:
46
+ base_dir = Path("/mnt/c/Users")
47
+ try:
48
+ entries = list(base_dir.iterdir())
49
+ except FileNotFoundError as exc:
50
+ raise RuntimeError("unable to find /mnt/c/Users") from exc
51
+ if windows_username:
52
+ candidate = base_dir / windows_username
53
+ if candidate.is_dir():
54
+ return candidate
55
+ raise RuntimeError(f"specified Windows user directory not found: {candidate}")
56
+ candidates: list[Path] = []
57
+ for entry in entries:
58
+ if not entry.is_dir():
59
+ continue
60
+ if entry.name.lower() == "public" or entry.name.lower() == "all users":
61
+ continue
62
+ try:
63
+ mode = stat.S_IMODE(entry.stat().st_mode)
64
+ except OSError:
65
+ continue
66
+ if mode == 0o777:
67
+ candidates.append(entry)
68
+ if len(candidates) != 1:
69
+ wsl_user = os.environ.get("USER") or os.environ.get("LOGNAME")
70
+ if wsl_user:
71
+ for candidate in candidates:
72
+ if candidate.name == wsl_user:
73
+ return candidate
74
+ non_default = [c for c in candidates if c.name.lower() not in ("default", "default user")]
75
+ if len(non_default) == 1:
76
+ return non_default[0]
77
+ options = ", ".join(sorted(candidate.name for candidate in candidates)) or "none"
78
+ raise RuntimeError(f"unable to infer Windows home directory (candidates: {options})")
79
+ return candidates[0]
80
+
81
+
82
+ def resolve_windows_home_from_wsl(windows_username: str | None) -> Path:
83
+ if windows_username:
84
+ return infer_windows_home_from_permissions(windows_username)
85
+ user_profile = os.environ.get("USERPROFILE")
86
+ if user_profile:
87
+ windows_path = PureWindowsPath(user_profile)
88
+ drive = windows_path.drive
89
+ if drive:
90
+ drive_letter = drive.rstrip(":").lower()
91
+ tail = Path(*windows_path.parts[1:])
92
+ candidate = Path("/mnt") / drive_letter / tail
93
+ if candidate.exists():
94
+ return candidate
95
+ return infer_windows_home_from_permissions(windows_username)
96
+
97
+
98
+ def decode_wsl_output(raw_bytes: bytes) -> str:
99
+ try:
100
+ return raw_bytes.decode("utf-16-le")
101
+ except UnicodeDecodeError:
102
+ return raw_bytes.decode()
103
+
104
+
105
+ def get_single_wsl_distribution() -> str:
106
+ process = subprocess.run(["wsl.exe", "-l"], capture_output=True, text=False, check=True)
107
+ stdout = decode_wsl_output(process.stdout).replace("\ufeff", "")
108
+ distributions: list[str] = []
109
+ for raw_line in stdout.splitlines():
110
+ line = raw_line.strip()
111
+ if not line or line.lower().startswith("windows subsystem for linux"):
112
+ continue
113
+ normalized = line.lstrip("* ").replace("(Default)", "").strip()
114
+ if normalized:
115
+ distributions.append(normalized)
116
+ if len(distributions) != 1:
117
+ raise RuntimeError("unable to pick a single WSL distribution")
118
+ return distributions[0]
119
+
120
+
121
+ def resolve_wsl_home_on_windows() -> Path:
122
+ distribution = get_single_wsl_distribution()
123
+ home_root = Path(rf"\\wsl$\{distribution}\home")
124
+ try:
125
+ entries = list(home_root.iterdir())
126
+ except FileNotFoundError as exc:
127
+ raise RuntimeError(f"unable to locate WSL home directories for {distribution}") from exc
128
+ except OSError as exc:
129
+ raise RuntimeError(f"unable to inspect WSL home directories for {distribution}") from exc
130
+ user_dirs = [entry for entry in entries if entry.is_dir()]
131
+ if len(user_dirs) != 1:
132
+ options = ", ".join(sorted(entry.name for entry in user_dirs)) or "none"
133
+ raise RuntimeError(f"unable to infer WSL user directory (candidates: {options})")
134
+ return user_dirs[0]
135
+
136
+
137
+ def quote_for_powershell(path: Path) -> str:
138
+ return "'" + str(path).replace("'", "''") + "'"
139
+
140
+
141
+ def run_windows_copy_command(source_path: Path, target_path: Path) -> None:
142
+ source_is_dir = source_path.is_dir()
143
+ parent_literal = quote_for_powershell(target_path.parent)
144
+ source_literal = quote_for_powershell(source_path)
145
+ target_literal = quote_for_powershell(target_path)
146
+ script = (
147
+ "$ErrorActionPreference = 'Stop'; "
148
+ f"New-Item -ItemType Directory -Path {parent_literal} -Force | Out-Null; "
149
+ f"Copy-Item -LiteralPath {source_literal} -Destination {target_literal}"
150
+ f"{' -Recurse' if source_is_dir else ''} -Force"
151
+ )
152
+ print(f"Copying {source_path} to {target_path}")
153
+ subprocess.run(["powershell.exe", "-NoLogo", "-NoProfile", "-Command", script], check=True)
154
+
155
+
156
+ def ensure_symlink(link_path: Path, target_path: Path) -> bool:
157
+ if not target_path.exists():
158
+ raise FileNotFoundError(target_path)
159
+ if link_path.is_symlink():
160
+ existing_target = Path(os.path.realpath(link_path))
161
+ desired_target = Path(os.path.realpath(target_path))
162
+ if os.path.normcase(str(existing_target)) == os.path.normcase(str(desired_target)):
163
+ return False
164
+ link_path.unlink()
165
+ elif link_path.exists():
166
+ raise FileExistsError(link_path)
167
+ link_path.symlink_to(target_path, target_is_directory=True)
168
+ return True
169
+
170
+
171
+ def parse_port_spec(port_spec: str) -> list[int]:
172
+ ports: list[int] = []
173
+ for part in port_spec.split(","):
174
+ part = part.strip()
175
+ if not part:
176
+ continue
177
+ if "-" in part:
178
+ range_parts = part.split("-", maxsplit=1)
179
+ start = int(range_parts[0].strip())
180
+ end = int(range_parts[1].strip())
181
+ if start > end:
182
+ raise ValueError(f"Invalid port range: {part} (start > end)")
183
+ ports.extend(range(start, end + 1))
184
+ else:
185
+ ports.append(int(part))
186
+ return ports
187
+
188
+
189
+ def normalize_port_spec_for_firewall(port_spec: str) -> tuple[str, str]:
190
+ """Validates and normalizes port spec for New-NetFirewallRule -LocalPort parameter.
191
+ Returns (normalized_spec, human_readable_description).
192
+ New-NetFirewallRule natively supports ranges (e.g. '5000-5020') and comma-separated values.
193
+ """
194
+ parts: list[str] = []
195
+ for raw_part in port_spec.split(","):
196
+ part = raw_part.strip()
197
+ if not part:
198
+ continue
199
+ if "-" in part:
200
+ range_parts = part.split("-", maxsplit=1)
201
+ start = int(range_parts[0].strip())
202
+ end = int(range_parts[1].strip())
203
+ if start < 1 or start > 65535 or end < 1 or end > 65535:
204
+ raise ValueError(f"Port numbers must be between 1 and 65535: {part}")
205
+ if start > end:
206
+ raise ValueError(f"Invalid port range: {part} (start > end)")
207
+ parts.append(f"{start}-{end}")
208
+ else:
209
+ port = int(part)
210
+ if port < 1 or port > 65535:
211
+ raise ValueError(f"Invalid port number: {port}")
212
+ parts.append(str(port))
213
+ if not parts:
214
+ raise ValueError("No valid ports provided")
215
+ normalized = ",".join(parts)
216
+ description = normalized.replace(",", ", ")
217
+ return normalized, description
@@ -33,21 +33,21 @@ def generate_uv_add_commands(pyproject_path: Path, output_path: Path) -> None:
33
33
  if "project" in pyproject_data and "dependencies" in pyproject_data["project"]:
34
34
  main_deps: list[str] = pyproject_data["project"]["dependencies"]
35
35
  if main_deps:
36
- package_names: list[str] = [extract_package_name(dep) for dep in main_deps]
36
+ package_names: list[str] = [f"'{extract_package_name(dep)}'" for dep in main_deps]
37
37
  commands.append(f"uv add --no-cache {' '.join(package_names)}")
38
38
 
39
39
  if "project" in pyproject_data and "optional-dependencies" in pyproject_data["project"]:
40
40
  optional_deps: dict[str, list[str]] = pyproject_data["project"]["optional-dependencies"]
41
41
  for group_name, deps in optional_deps.items():
42
42
  if deps:
43
- package_names = [extract_package_name(dep) for dep in deps]
43
+ package_names = [f"'{extract_package_name(dep)}'" for dep in deps]
44
44
  commands.append(f"uv add --no-cache --group {group_name} {' '.join(package_names)}")
45
45
 
46
46
  if "dependency-groups" in pyproject_data:
47
47
  dep_groups: dict[str, list[str]] = pyproject_data["dependency-groups"]
48
48
  for group_name, deps in dep_groups.items():
49
49
  if deps:
50
- package_names = [extract_package_name(dep) for dep in deps]
50
+ package_names = [f"'{extract_package_name(dep)}'" for dep in deps]
51
51
  if group_name == "dev":
52
52
  commands.append(f"uv add --no-cache --dev {' '.join(package_names)}")
53
53
  else:
@@ -78,12 +78,8 @@ def extract_package_name(dependency_spec: str) -> str:
78
78
  "rich>=14.0.0" -> "rich"
79
79
  "requests>=2.32.5" -> "requests"
80
80
  "pywin32" -> "pywin32"
81
- "package[extra]>=1.0" -> "package"
81
+ "package[extra]>=1.0" -> "package[extra]"
82
82
  """
83
- # Handle extras like "package[extra]>=1.0" first
84
- if "[" in dependency_spec:
85
- dependency_spec = dependency_spec.split("[")[0].strip()
86
-
87
83
  # Split on common version operators and take the first part
88
84
  for operator in [">=", "<=", "==", "!=", ">", "<", "~=", "===", "@"]:
89
85
  if operator in dependency_spec:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machineconfig
3
- Version: 7.98
3
+ Version: 8.51
4
4
  Summary: Dotfiles management package
5
5
  Author-email: Alex Al-Saffar <programmer@usa.com>
6
6
  License: Apache 2.0
@@ -11,20 +11,21 @@ Classifier: License :: OSI Approved :: Apache Software License
11
11
  Classifier: Operating System :: OS Independent
12
12
  Requires-Python: >=3.13
13
13
  Description-Content-Type: text/markdown
14
- Requires-Dist: cryptography>=44.0.2
15
- Requires-Dist: fire>=0.7.0
14
+ Requires-Dist: cryptography>=46.0.3
15
+ Requires-Dist: fire>=0.7.1
16
+ Requires-Dist: gitpython>=3.1.45
16
17
  Requires-Dist: joblib>=1.5.2
17
- Requires-Dist: paramiko>=3.5.1
18
+ Requires-Dist: numpy>=2.4.1
19
+ Requires-Dist: paramiko>=4.0.0
20
+ Requires-Dist: psutil>=7.1.3
21
+ Requires-Dist: questionary>=2.1.1
18
22
  Requires-Dist: randomname>=0.2.1
23
+ Requires-Dist: rclone-python>=0.1.23
19
24
  Requires-Dist: requests>=2.32.5
20
- Requires-Dist: rich>=14.0.0
25
+ Requires-Dist: rich>=14.2.0
21
26
  Requires-Dist: tenacity>=9.1.2
22
- Requires-Dist: psutil>=7.0.0
23
- Requires-Dist: gitpython>=3.1.44
24
- Requires-Dist: rclone-python>=0.1.23
25
- Requires-Dist: questionary>=2.1.1
26
- Requires-Dist: typer-slim>=0.19.2
27
- Requires-Dist: typer>=0.19.2
27
+ Requires-Dist: typer==0.20.0
28
+ Requires-Dist: typer-slim==0.20.0
28
29
  Provides-Extra: windows
29
30
  Requires-Dist: pywin32; extra == "windows"
30
31
  Provides-Extra: plot
@@ -50,14 +51,15 @@ Requires-Dist: python-magic>=0.4.27; extra == "plot"
50
51
  </p>
51
52
 
52
53
 
53
- # 🧠 Welcome to **Machineconfig**
54
+ # 🗜 Welcome to **Machineconfig**
54
55
 
55
- **Machineconfig** is a cli-based cross-platform **Stack Manager** It is a swiss-army knife; a *Package Manager*, *Configuration Manager*, *Automation Tool*, *Dotfiles Manager*, *Data Solution*, and *Code Manager*, among other functionalities covered, all rolled into one seamless experience, that is consistent across different platforms.
56
+ Your stack is awesome, but you need a stack manager, to have a tight grip over it, put it together and maintain it.
57
+ Entering, **Machineconfig**, a cli-based cross-platform **Stack Manager** — It is a swiss-army knife; a *Package Manager*, *Configuration Manager*, *Automation Tool*, *Dotfiles Manager*, *Data Solution*, and *Code Manager*, among other functionalities covered, all rolled into one seamless experience, that is consistent across different platforms.
56
58
 
57
59
 
58
- ## 💡 Motivation
59
- Your stack is awesome, but you need stack a manager for it, to put it together and maintain it.
60
- What is your stack? Say you have a new computer/ VM, how to set it?
60
+ ## Workflow:
61
+ What is your stack? Say you have a new computer/ VM, how do you go about setting it up with your stack?
62
+ Surely, you have:
61
63
  * A bunch of CLI tools.
62
64
  * [Optional] A bunch of softwares (GUIs for desktop environment)
63
65
  * [Public] A bunch of configuration files for your tools.
@@ -100,22 +102,28 @@ Machineconfig builds on shoulder of giants. A suite of best-in-class stack of pr
100
102
  # Install On Windows:
101
103
 
102
104
  ```powershell
103
- # install tool the tool only:
104
105
  powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Skip if UV is already installed
105
106
  uv tool install --upgrade --python 3.14 machineconfig
106
- # interactive install of machineconfig and following on to run it and make basic machine configuration (RECOMMENDED):
107
- iex (iwr bit.ly/cfgwindows).Content # Or, if UV is installed: iex (uvx machineconfig define)
108
- # Quick install and configure (optionals are accepted by default):
109
- iex (iwr bit.ly/cfgwq).Content
110
107
  ```
111
108
 
112
109
 
113
110
  # Install On Linux and MacOS
114
111
 
115
112
  ```bash
116
- # install the tool only:
117
113
  curl -LsSf https://astral.sh/uv/install.sh | sh # Skip if UV is already installed
118
114
  uv tool install --upgrade --python 3.14 machineconfig
115
+ ```
116
+
117
+
118
+ # Quickies ...
119
+ ```powershell
120
+ # interactive install of machineconfig and following on to run it and make basic machine configuration (RECOMMENDED):
121
+ irm bit.ly/cfgwindows | iex # Or, if UV is installed: iex (uvx machineconfig define)
122
+ # Quick install and configure (optionals are accepted by default):
123
+ irm bit.ly/cfgwq | iex
124
+ ```
125
+
126
+ ```bash
119
127
  # interactive install of machineconfig and following on to run it and make basic machine configuration (RECOMMENDED):
120
128
  . <(curl -L bit.ly/cfglinux) # Or, if UV is installed: . <(uvx machineconfig define)
121
129
  ```