machineconfig 6.23__py3-none-any.whl → 8.12__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 (402) hide show
  1. machineconfig/cluster/remote/cloud_manager.py +1 -1
  2. machineconfig/cluster/remote/distribute.py +0 -1
  3. machineconfig/cluster/remote/file_manager.py +0 -2
  4. machineconfig/cluster/sessions_managers/{utils → helpers}/enhanced_command_runner.py +4 -6
  5. machineconfig/cluster/sessions_managers/utils/load_balancer.py +1 -1
  6. machineconfig/cluster/sessions_managers/utils/maker.py +69 -0
  7. machineconfig/cluster/sessions_managers/wt_local.py +16 -221
  8. machineconfig/cluster/sessions_managers/wt_local_manager.py +55 -193
  9. machineconfig/cluster/sessions_managers/wt_remote_manager.py +42 -198
  10. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  11. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  12. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  13. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  14. machineconfig/cluster/sessions_managers/zellij_local.py +3 -3
  15. machineconfig/cluster/sessions_managers/zellij_local_manager.py +5 -3
  16. machineconfig/cluster/sessions_managers/zellij_remote.py +2 -2
  17. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +3 -2
  18. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +2 -2
  19. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +3 -7
  20. machineconfig/cluster/sessions_managers/{helpers → zellij_utils}/zellij_local_helper_with_panes.py +1 -1
  21. machineconfig/jobs/installer/check_installations.py +0 -1
  22. machineconfig/jobs/installer/installer_data.json +1408 -201
  23. machineconfig/jobs/installer/linux_scripts/q.sh +10 -7
  24. machineconfig/jobs/installer/linux_scripts/redis.sh +1 -0
  25. machineconfig/jobs/installer/package_groups.py +63 -92
  26. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  27. machineconfig/jobs/installer/python_scripts/boxes.py +61 -0
  28. machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +5 -3
  29. machineconfig/jobs/installer/python_scripts/cloudflare_warp_cli.py +23 -0
  30. machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +4 -1
  31. machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +1 -1
  32. machineconfig/jobs/installer/{custom → python_scripts}/hx.py +75 -18
  33. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +2 -2
  34. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +27 -22
  35. machineconfig/jobs/installer/python_scripts/sysabc.py +139 -0
  36. machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +2 -19
  37. machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +10 -14
  38. machineconfig/jobs/installer/python_scripts/yazi.py +121 -0
  39. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nfs +0 -1
  40. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +13 -0
  41. machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +4 -0
  42. machineconfig/jobs/scripts_dynamic/a.py +25 -0
  43. machineconfig/logger.py +0 -1
  44. machineconfig/profile/create_helper.py +56 -18
  45. machineconfig/profile/create_links.py +2 -1
  46. machineconfig/profile/create_links_export.py +64 -18
  47. machineconfig/profile/create_shell_profile.py +90 -132
  48. machineconfig/profile/mapper.toml +18 -8
  49. machineconfig/scripts/__init__.py +0 -4
  50. machineconfig/scripts/linux/wrap_mcfg +46 -0
  51. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  52. machineconfig/scripts/python/agents.py +82 -60
  53. machineconfig/scripts/python/ai/initai.py +1 -19
  54. machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
  55. machineconfig/scripts/python/ai/{command_runner → scripts}/command_runner.sh +1 -1
  56. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +1 -1
  57. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
  58. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
  59. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
  60. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +5 -5
  61. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +4 -0
  62. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
  63. machineconfig/scripts/python/ai/solutions/generic.py +1 -1
  64. machineconfig/scripts/python/ai/{generate_files.py → utils/generate_files.py} +2 -2
  65. machineconfig/scripts/python/ai/{vscode_tasks.py → utils/vscode_tasks.py} +7 -2
  66. machineconfig/scripts/python/cloud.py +14 -9
  67. machineconfig/scripts/python/croshell.py +135 -117
  68. machineconfig/scripts/python/devops.py +48 -25
  69. machineconfig/scripts/python/devops_navigator.py +1 -5
  70. machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
  71. machineconfig/scripts/python/env_manager/path_manager_tui.py +18 -9
  72. machineconfig/scripts/python/fire_jobs.py +127 -118
  73. machineconfig/scripts/python/ftpx.py +44 -17
  74. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  75. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  76. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  77. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  78. machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_crush.json +1 -1
  79. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +39 -0
  80. machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_cursor_agents.py +3 -4
  81. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +55 -0
  82. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  83. machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_help_launch.py +37 -15
  84. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +41 -0
  85. machineconfig/scripts/python/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
  86. machineconfig/scripts/python/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
  87. machineconfig/scripts/python/helpers_agents/privacy/configs/copilot/config.yml +1 -0
  88. machineconfig/scripts/python/helpers_agents/privacy/configs/crush/crush.json +10 -0
  89. machineconfig/scripts/python/helpers_agents/privacy/configs/gemini/settings.json +12 -0
  90. machineconfig/scripts/python/helpers_agents/privacy/privacy.py +109 -0
  91. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +10 -0
  92. machineconfig/scripts/python/helpers_agents/templates/template.sh +34 -0
  93. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/cloud_copy.py +28 -21
  94. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/cloud_mount.py +19 -17
  95. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/cloud_sync.py +12 -11
  96. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/helpers2.py +1 -1
  97. machineconfig/scripts/python/helpers_croshell/crosh.py +39 -0
  98. machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/start_slidev.py +6 -7
  99. machineconfig/scripts/python/helpers_devops/cli_config.py +105 -0
  100. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +89 -0
  101. machineconfig/scripts/python/helpers_devops/cli_data.py +25 -0
  102. machineconfig/scripts/python/helpers_devops/cli_nw.py +221 -0
  103. machineconfig/scripts/python/{devops_helpers → helpers_devops}/cli_repos.py +60 -36
  104. machineconfig/scripts/python/helpers_devops/cli_self.py +172 -0
  105. machineconfig/scripts/python/helpers_devops/cli_share_file.py +137 -0
  106. machineconfig/scripts/python/helpers_devops/cli_share_server.py +142 -0
  107. machineconfig/scripts/python/{devops_helpers/cli_terminal.py → helpers_devops/cli_share_terminal.py} +15 -17
  108. machineconfig/scripts/python/{devops_helpers → helpers_devops}/devops_backup_retrieve.py +7 -10
  109. machineconfig/scripts/python/{devops_helpers → helpers_devops}/devops_status.py +7 -19
  110. machineconfig/scripts/python/{devops_helpers → helpers_devops}/devops_update_repos.py +1 -1
  111. machineconfig/scripts/python/helpers_devops/run_script.py +168 -0
  112. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +3 -0
  113. machineconfig/scripts/python/{devops_helpers → helpers_devops}/themes/choose_wezterm_theme.py +1 -1
  114. machineconfig/scripts/python/{helpers_fire/helpers4.py → helpers_fire_command/file_wrangler.py} +57 -20
  115. machineconfig/scripts/python/helpers_fire_command/fire_jobs_args_helper.py +2 -0
  116. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +26 -16
  117. machineconfig/scripts/python/helpers_msearch/__init__.py +5 -0
  118. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfg +3 -3
  119. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +59 -0
  120. machineconfig/scripts/python/helpers_navigator/__init__.py +20 -0
  121. machineconfig/scripts/python/{helper_navigator → helpers_navigator}/command_builder.py +1 -1
  122. machineconfig/scripts/python/{helper_navigator → helpers_navigator}/command_detail.py +1 -1
  123. machineconfig/scripts/python/{helper_navigator → helpers_navigator}/command_tree.py +160 -23
  124. machineconfig/scripts/python/{helper_navigator → helpers_navigator}/main_app.py +5 -5
  125. machineconfig/scripts/python/helpers_network/address.py +176 -0
  126. machineconfig/scripts/python/helpers_network/address_switch.py +78 -0
  127. machineconfig/scripts/python/{nw → helpers_network}/mount_nfs.py +2 -2
  128. machineconfig/scripts/python/{nw → helpers_network}/mount_ssh.py +1 -1
  129. machineconfig/scripts/python/{nw/devops_add_identity.py → helpers_network/ssh_add_identity.py} +35 -1
  130. machineconfig/scripts/python/{nw/devops_add_ssh_key.py → helpers_network/ssh_add_ssh_key.py} +26 -7
  131. machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_linux.py +7 -7
  132. machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_windows.py +4 -4
  133. machineconfig/scripts/python/{nw → helpers_network}/wifi_conn.py +1 -53
  134. machineconfig/scripts/python/helpers_repos/action.py +209 -0
  135. machineconfig/scripts/python/helpers_repos/action_helper.py +150 -0
  136. machineconfig/scripts/python/{repos_helpers → helpers_repos}/clone.py +0 -1
  137. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +80 -37
  138. machineconfig/scripts/python/{repos_helpers → helpers_repos}/entrypoint.py +5 -5
  139. machineconfig/scripts/python/helpers_repos/grource.py +2 -2
  140. machineconfig/scripts/python/{repos_helpers → helpers_repos}/record.py +3 -2
  141. machineconfig/scripts/python/helpers_repos/repo_analyzer_1.py +160 -0
  142. machineconfig/scripts/python/{repos_helpers/count_lines.py → helpers_repos/repo_analyzer_2.py} +113 -192
  143. machineconfig/scripts/python/{repos_helpers → helpers_repos}/sync.py +5 -5
  144. machineconfig/scripts/python/{sessions_helpers → helpers_sessions}/sessions_multiprocess.py +19 -13
  145. machineconfig/scripts/python/helpers_utils/download.py +150 -0
  146. machineconfig/scripts/python/helpers_utils/pdf.py +96 -0
  147. machineconfig/scripts/python/helpers_utils/python.py +187 -0
  148. machineconfig/scripts/python/interactive.py +26 -35
  149. machineconfig/scripts/python/{entry.py → mcfg_entry.py} +24 -10
  150. machineconfig/scripts/python/msearch.py +72 -0
  151. machineconfig/scripts/python/sessions.py +101 -38
  152. machineconfig/scripts/python/terminal.py +136 -0
  153. machineconfig/scripts/python/utils.py +62 -0
  154. machineconfig/scripts/windows/wrap_mcfg.ps1 +63 -0
  155. machineconfig/settings/broot/conf.toml +1 -1
  156. machineconfig/settings/helix/config.toml +16 -0
  157. machineconfig/settings/helix/languages.toml +13 -4
  158. machineconfig/settings/helix/yazi-picker.sh +12 -0
  159. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  160. machineconfig/settings/lf/linux/exe/previewer.sh +3 -2
  161. machineconfig/settings/lf/linux/lfrc +10 -11
  162. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  163. machineconfig/settings/lf/windows/lfrc +15 -17
  164. machineconfig/settings/lf/windows/mkfile.ps1 +1 -1
  165. machineconfig/settings/linters/.ruff.toml +1 -1
  166. machineconfig/settings/marimo/marimo.toml +80 -0
  167. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  168. machineconfig/settings/shells/bash/init.sh +57 -10
  169. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
  170. machineconfig/settings/shells/nushell/config.nu +2 -35
  171. machineconfig/settings/shells/nushell/env.nu +45 -6
  172. machineconfig/settings/shells/nushell/init.nu +314 -0
  173. machineconfig/settings/shells/pwsh/init.ps1 +59 -23
  174. machineconfig/settings/shells/starship/starship.toml +16 -0
  175. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  176. machineconfig/settings/shells/wt/settings.json +32 -17
  177. machineconfig/settings/shells/zsh/init.sh +89 -0
  178. machineconfig/settings/television/cable_unix/alias.toml +8 -0
  179. machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
  180. machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
  181. machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
  182. machineconfig/settings/television/cable_unix/channels.toml +19 -0
  183. machineconfig/settings/television/cable_unix/dirs.toml +13 -0
  184. machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
  185. machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
  186. machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
  187. machineconfig/settings/television/cable_unix/env.toml +17 -0
  188. machineconfig/settings/television/cable_unix/files.toml +11 -0
  189. machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
  190. machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
  191. machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
  192. machineconfig/settings/television/cable_unix/git-log.toml +12 -0
  193. machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
  194. machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
  195. machineconfig/settings/television/cable_unix/guix.toml +20 -0
  196. machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
  197. machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
  198. machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
  199. machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
  200. machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
  201. machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
  202. machineconfig/settings/television/cable_unix/procs.toml +20 -0
  203. machineconfig/settings/television/cable_unix/text.toml +17 -0
  204. machineconfig/settings/television/cable_unix/tldr.toml +18 -0
  205. machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
  206. machineconfig/settings/television/cable_windows/alias.toml +7 -0
  207. machineconfig/settings/television/cable_windows/dirs.toml +13 -0
  208. machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
  209. machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
  210. machineconfig/settings/television/cable_windows/env.toml +17 -0
  211. machineconfig/settings/television/cable_windows/files.toml +14 -0
  212. machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
  213. machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
  214. machineconfig/settings/television/cable_windows/git-log.toml +11 -0
  215. machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
  216. machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
  217. machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
  218. machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
  219. machineconfig/settings/television/cable_windows/text.toml +17 -0
  220. machineconfig/settings/yazi/init.lua +61 -0
  221. machineconfig/settings/yazi/keymap_linux.toml +94 -0
  222. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  223. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  224. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  225. machineconfig/settings/yazi/theme.toml +4 -0
  226. machineconfig/settings/yazi/yazi_linux.toml +84 -0
  227. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  228. machineconfig/settings/zellij/layouts/st.kdl +39 -8
  229. machineconfig/setup_linux/__init__.py +2 -2
  230. machineconfig/setup_linux/apps_desktop.sh +8 -27
  231. machineconfig/setup_linux/web_shortcuts/interactive.sh +27 -11
  232. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +31 -0
  233. machineconfig/setup_mac/__init__.py +16 -0
  234. machineconfig/setup_mac/apps_gui.sh +248 -0
  235. machineconfig/setup_mac/ssh/openssh_setup.sh +114 -0
  236. machineconfig/setup_mac/uv.sh +36 -0
  237. machineconfig/setup_windows/__init__.py +3 -5
  238. machineconfig/setup_windows/ssh/openssh-server.ps1 +1 -1
  239. machineconfig/setup_windows/uv.ps1 +8 -1
  240. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +26 -10
  241. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +30 -0
  242. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  243. machineconfig/utils/accessories.py +7 -5
  244. machineconfig/utils/code.py +143 -167
  245. machineconfig/utils/files/art/fat_croco.txt +10 -0
  246. machineconfig/utils/files/art/halfwit_croco.txt +9 -0
  247. machineconfig/utils/files/art/happy_croco.txt +22 -0
  248. machineconfig/utils/files/art/water_croco.txt +11 -0
  249. machineconfig/utils/files/ascii_art.py +1 -1
  250. machineconfig/utils/files/headers.py +6 -11
  251. machineconfig/utils/files/read.py +3 -9
  252. machineconfig/utils/installer_utils/github_release_bulk.py +156 -119
  253. machineconfig/utils/installer_utils/install_from_url.py +183 -0
  254. machineconfig/utils/installer_utils/installer_class.py +44 -101
  255. machineconfig/utils/installer_utils/installer_cli.py +175 -0
  256. machineconfig/utils/installer_utils/installer_helper.py +129 -0
  257. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +39 -87
  258. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +17 -63
  259. machineconfig/utils/io.py +77 -4
  260. machineconfig/utils/links.py +56 -38
  261. machineconfig/utils/meta.py +235 -145
  262. machineconfig/utils/options.py +46 -18
  263. machineconfig/utils/options_tv.py +119 -0
  264. machineconfig/utils/path_extended.py +46 -97
  265. machineconfig/utils/path_helper.py +76 -23
  266. machineconfig/utils/procs.py +10 -23
  267. machineconfig/utils/scheduler.py +84 -115
  268. machineconfig/utils/scheduling.py +0 -3
  269. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  270. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  271. machineconfig/utils/ssh.py +214 -476
  272. machineconfig/utils/ssh_utils/abc.py +5 -0
  273. machineconfig/utils/ssh_utils/copy_from_here.py +111 -0
  274. machineconfig/utils/ssh_utils/copy_to_here.py +303 -0
  275. machineconfig/utils/ssh_utils/utils.py +142 -0
  276. machineconfig/utils/ssh_utils/wsl.py +210 -0
  277. machineconfig/utils/terminal.py +3 -113
  278. machineconfig/utils/upgrade_packages.py +114 -28
  279. machineconfig/utils/ve.py +12 -4
  280. machineconfig-8.12.dist-info/METADATA +132 -0
  281. machineconfig-8.12.dist-info/RECORD +504 -0
  282. {machineconfig-6.23.dist-info → machineconfig-8.12.dist-info}/entry_points.txt +5 -1
  283. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -41
  284. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -71
  285. machineconfig/jobs/linux/msc/cli_agents.sh +0 -16
  286. machineconfig/jobs/python/python_ve_symlink.py +0 -37
  287. machineconfig/jobs/python/vscode/api.py +0 -57
  288. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +0 -12
  289. machineconfig/jobs/windows/archive/openssh-server_add_key.ps1 +0 -7
  290. machineconfig/jobs/windows/archive/openssh-server_copy-ssh-id.ps1 +0 -14
  291. machineconfig/scripts/linux/fzf2g +0 -21
  292. machineconfig/scripts/linux/fzfag +0 -17
  293. machineconfig/scripts/linux/fzffg +0 -25
  294. machineconfig/scripts/linux/fzfrga +0 -21
  295. machineconfig/scripts/linux/other/share_smb +0 -1
  296. machineconfig/scripts/linux/other/switch_ip +0 -20
  297. machineconfig/scripts/linux/skrg +0 -4
  298. machineconfig/scripts/linux/warp-cli.sh +0 -122
  299. machineconfig/scripts/linux/z_ls +0 -104
  300. machineconfig/scripts/python/ai/command_runner/prompt.txt +0 -9
  301. machineconfig/scripts/python/devops_helpers/cli_config.py +0 -81
  302. machineconfig/scripts/python/devops_helpers/cli_config_dotfile.py +0 -84
  303. machineconfig/scripts/python/devops_helpers/cli_data.py +0 -18
  304. machineconfig/scripts/python/devops_helpers/cli_nw.py +0 -73
  305. machineconfig/scripts/python/devops_helpers/cli_self.py +0 -117
  306. machineconfig/scripts/python/devops_helpers/cli_share_server.py +0 -104
  307. machineconfig/scripts/python/helper_navigator/__init__.py +0 -20
  308. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_crush.py +0 -37
  309. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_gemini.py +0 -44
  310. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_qwen.py +0 -43
  311. machineconfig/scripts/python/helpers_fire/fire_agents_helper_types.py +0 -30
  312. machineconfig/scripts/python/helpers_fire/prompt.txt +0 -2
  313. machineconfig/scripts/python/helpers_fire/template.sh +0 -15
  314. machineconfig/scripts/python/helpers_repos/secure_repo.py +0 -15
  315. machineconfig/scripts/python/nw/add_ssh_key.py +0 -148
  316. machineconfig/scripts/python/nw/wsl_windows_transfer.py +0 -66
  317. machineconfig/scripts/python/repos_helpers/action.py +0 -378
  318. machineconfig/scripts/python/repos_helpers/count_lines_frontend.py +0 -17
  319. machineconfig/scripts/windows/fzfb.ps1 +0 -3
  320. machineconfig/scripts/windows/fzfg.ps1 +0 -2
  321. machineconfig/scripts/windows/fzfrga.bat +0 -20
  322. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
  323. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  324. machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
  325. machineconfig/settings/lf/windows/tst.ps1 +0 -1
  326. machineconfig/settings/shells/pwsh/profile.ps1 +0 -0
  327. machineconfig/settings/yazi/keymap.toml +0 -0
  328. machineconfig/settings/yazi/yazi.toml +0 -4
  329. machineconfig/setup_linux/apps.sh +0 -66
  330. machineconfig/setup_linux/nix/cli_installation.sh +0 -137
  331. machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
  332. machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
  333. machineconfig/setup_windows/apps.ps1 +0 -62
  334. machineconfig/setup_windows/others/obs.ps1 +0 -4
  335. machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
  336. machineconfig/setup_windows/wt_and_pwsh/__init__.py +0 -0
  337. machineconfig/utils/installer_utils/installer.py +0 -225
  338. machineconfig-6.23.dist-info/METADATA +0 -84
  339. machineconfig-6.23.dist-info/RECORD +0 -428
  340. machineconfig/cluster/sessions_managers/{utils → helpers}/load_balancer_helper.py +0 -0
  341. machineconfig/cluster/sessions_managers/{helpers → zellij_utils}/zellij_local_helper.py +0 -0
  342. machineconfig/cluster/sessions_managers/{helpers → zellij_utils}/zellij_local_helper_restart.py +0 -0
  343. machineconfig/cluster/sessions_managers/{helpers → zellij_utils}/zellij_local_manager_helper.py +0 -0
  344. machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +0 -0
  345. machineconfig/jobs/{linux/msc → installer/linux_scripts}/network.sh +0 -0
  346. machineconfig/jobs/installer/{custom_dev → python_scripts}/__init__.py +0 -0
  347. machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
  348. machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
  349. machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
  350. machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
  351. machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
  352. machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
  353. machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
  354. machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
  355. machineconfig/{setup_linux/web_shortcuts → jobs/scripts/bash_scripts}/android.sh +0 -0
  356. machineconfig/jobs/{linux/msc → scripts/bash_scripts}/lid.sh +0 -0
  357. machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/mint_keyboard_shortcuts.sh +0 -0
  358. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_drive +0 -0
  359. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nw_drive +0 -0
  360. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_smb +0 -0
  361. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_cloud.sh +0 -0
  362. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_nfs +0 -0
  363. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/start_docker +0 -0
  364. machineconfig/{scripts → jobs/scripts/powershell_scripts}/Restore-ThunderbirdProfile.ps1 +0 -0
  365. machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/docker.ps1 +0 -0
  366. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nfs.ps1 +0 -0
  367. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nw.ps1 +0 -0
  368. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_smb.ps1 +0 -0
  369. machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/power_options.ps1 +0 -0
  370. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_cloud.cmd +0 -0
  371. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_smb.ps1 +0 -0
  372. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
  373. machineconfig/{jobs/python → scripts/python/ai/utils}/__init__.py +0 -0
  374. machineconfig/scripts/python/{cloud_helpers → helpers_agents}/__init__.py +0 -0
  375. machineconfig/scripts/python/{croshell_helpers → helpers_agents/agentic_frameworks}/__init__.py +0 -0
  376. machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_help_search.py +0 -0
  377. machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_load_balancer.py +0 -0
  378. machineconfig/scripts/python/{helpers_fire → helpers_agents/templates}/template.ps1 +0 -0
  379. machineconfig/scripts/python/{devops_helpers → helpers_cloud}/__init__.py +0 -0
  380. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/cloud_helpers.py +1 -1
  381. /machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/helpers5.py +0 -0
  382. /machineconfig/scripts/python/{devops_helpers/themes → helpers_croshell}/__init__.py +0 -0
  383. /machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/pomodoro.py +0 -0
  384. /machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/scheduler.py +0 -0
  385. /machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/viewer.py +0 -0
  386. /machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/viewer_template.py +0 -0
  387. /machineconfig/scripts/python/{helpers_fire → helpers_devops}/__init__.py +0 -0
  388. /machineconfig/scripts/python/{helpers_fire/agentic_frameworks → helpers_devops/themes}/__init__.py +0 -0
  389. /machineconfig/scripts/python/{devops_helpers → helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  390. /machineconfig/{jobs/windows/msc/cli_agents.bat → scripts/python/helpers_devops/themes/choose_starship_theme.ps1} +0 -0
  391. /machineconfig/{jobs/windows/msc/cli_agents.ps1 → scripts/python/helpers_fire_command/f.py} +0 -0
  392. /machineconfig/scripts/python/{helper_navigator → helpers_navigator}/data_models.py +0 -0
  393. /machineconfig/scripts/python/{helper_navigator → helpers_navigator}/search_bar.py +0 -0
  394. /machineconfig/scripts/python/{helpers_repos → helpers_network}/__init__.py +0 -0
  395. /machineconfig/scripts/python/{nw → helpers_network}/mount_nw_drive.py +0 -0
  396. /machineconfig/scripts/python/{nw → helpers_network}/onetimeshare.py +0 -0
  397. /machineconfig/scripts/python/{repos_helpers → helpers_repos}/update.py +0 -0
  398. /machineconfig/scripts/python/{nw → helpers_sessions}/__init__.py +0 -0
  399. /machineconfig/{scripts/python/sessions_helpers → settings/wt}/__init__.py +0 -0
  400. /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
  401. {machineconfig-6.23.dist-info → machineconfig-8.12.dist-info}/WHEEL +0 -0
  402. {machineconfig-6.23.dist-info → machineconfig-8.12.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  from machineconfig.utils.accessories import randstr
2
+ from machineconfig.utils.io import decrypt, encrypt
2
3
 
3
4
  from datetime import datetime
4
5
  import time
@@ -10,10 +11,13 @@ from platform import system
10
11
  from typing import Any, Optional, Union, Callable, TypeAlias, Literal
11
12
 
12
13
 
14
+
13
15
  OPLike: TypeAlias = Union[str, "PathExtended", Path, None]
14
16
  PLike: TypeAlias = Union[str, "PathExtended", Path]
15
17
  FILE_MODE: TypeAlias = Literal["r", "w", "x", "a"]
16
18
  SHUTIL_FORMATS: TypeAlias = Literal["zip", "tar", "gztar", "bztar", "xztar"]
19
+ DECOMPRESS_SUPPORTED_FORMATS = [".tar.gz", ".tgz", ".tar", ".gz", ".tar.bz", ".tbz", ".tar.xz", ".zip", ".7z",
20
+ ".tar.bz2", ".tbz2", ".xz"]
17
21
 
18
22
 
19
23
  def _is_user_admin() -> bool:
@@ -54,81 +58,6 @@ def _run_shell_command(
54
58
  )
55
59
 
56
60
 
57
- def pwd2key(password: str, salt: Optional[bytes] = None, iterations: int = 10) -> bytes: # Derive a secret key from a given password and salt"""
58
- import base64
59
-
60
- if salt is None:
61
- import hashlib
62
-
63
- m = hashlib.sha256()
64
- m.update(password.encode(encoding="utf-8"))
65
- return base64.urlsafe_b64encode(s=m.digest()) # make url-safe bytes required by Ferent.
66
- from cryptography.hazmat.primitives import hashes
67
- from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
68
-
69
- return base64.urlsafe_b64encode(PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=iterations, backend=None).derive(password.encode()))
70
-
71
-
72
- def encrypt(msg: bytes, key: Optional[bytes] = None, pwd: Optional[str] = None, salted: bool = True, iteration: Optional[int] = None, gen_key: bool = False) -> bytes:
73
- import base64
74
- from cryptography.fernet import Fernet
75
-
76
- salt, iteration = None, None
77
- if pwd is not None: # generate it from password
78
- assert (key is None) and (type(pwd) is str), "❌ You can either pass key or pwd, or none of them, but not both."
79
- import secrets
80
-
81
- iteration = iteration or secrets.randbelow(exclusive_upper_bound=1_000_000)
82
- salt = secrets.token_bytes(nbytes=16) if salted else None
83
- key_resolved = pwd2key(password=pwd, salt=salt, iterations=iteration)
84
- elif key is None:
85
- if gen_key:
86
- key_resolved = Fernet.generate_key()
87
- Path.home().joinpath("dotfiles/creds/data/encrypted_files_key.bytes").write_bytes(key_resolved)
88
- else:
89
- try:
90
- key_resolved = Path.home().joinpath("dotfiles/creds/data/encrypted_files_key.bytes").read_bytes()
91
- print(f"⚠️ Using key from: {Path.home().joinpath('dotfiles/creds/data/encrypted_files_key.bytes')}")
92
- except FileNotFoundError as err:
93
- print("\n" * 3, "~" * 50, """Consider Loading up your dotfiles or pass `gen_key=True` to make and save one.""", "~" * 50, "\n" * 3)
94
- raise FileNotFoundError(err) from err
95
- elif isinstance(key, (str, PathExtended, Path)):
96
- key_resolved = Path(key).read_bytes() # a path to a key file was passed, read it:
97
- elif type(key) is bytes:
98
- key_resolved = key # key passed explicitly
99
- else:
100
- raise TypeError("❌ Key must be either a path, bytes object or None.")
101
- code = Fernet(key=key_resolved).encrypt(msg)
102
- if pwd is not None and salt is not None and iteration is not None:
103
- return base64.urlsafe_b64encode(b"%b%b%b" % (salt, iteration.to_bytes(4, "big"), base64.urlsafe_b64decode(code)))
104
- return code
105
-
106
-
107
- def decrypt(token: bytes, key: Optional[bytes] = None, pwd: Optional[str] = None, salted: bool = True) -> bytes:
108
- import base64
109
-
110
- if pwd is not None:
111
- assert key is None, "❌ You can either pass key or pwd, or none of them, but not both."
112
- if salted:
113
- decoded = base64.urlsafe_b64decode(token)
114
- salt, iterations, token = decoded[:16], decoded[16:20], base64.urlsafe_b64encode(decoded[20:])
115
- key_resolved = pwd2key(password=pwd, salt=salt, iterations=int.from_bytes(bytes=iterations, byteorder="big"))
116
- else:
117
- key_resolved = pwd2key(password=pwd) # trailing `;` prevents IPython from caching the result.
118
- elif type(key) is bytes:
119
- assert pwd is None, "❌ You can either pass key or pwd, or none of them, but not both."
120
- key_resolved = key # passsed explicitly
121
- elif key is None:
122
- key_resolved = Path.home().joinpath("dotfiles/creds/data/encrypted_files_key.bytes").read_bytes() # read from file
123
- elif isinstance(key, (str, Path)):
124
- key_resolved = Path(key).read_bytes() # passed a path to a file containing kwy
125
- else:
126
- raise TypeError(f"❌ Key must be either str, P, Path, bytes or None. Recieved: {type(key)}")
127
- from cryptography.fernet import Fernet
128
-
129
- return Fernet(key=key_resolved).decrypt(token)
130
-
131
-
132
61
  def validate_name(astring: str, replace: str = "_") -> str:
133
62
  import re
134
63
 
@@ -225,7 +154,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
225
154
  # ======================================= File Editing / Reading ===================================
226
155
  def download(self, folder: OPLike = None, name: Optional[str] = None, allow_redirects: bool = True, timeout: Optional[int] = None, params: Any = None) -> "PathExtended":
227
156
  import requests
228
-
229
157
  response = requests.get(self.as_url_str(), allow_redirects=allow_redirects, timeout=timeout, params=params) # Alternative: from urllib import request; request.urlopen(url).read().decode('utf-8').
230
158
  assert response.status_code == 200, f"Download failed with status code {response.status_code}\n{response.text}"
231
159
  if name is not None:
@@ -553,9 +481,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
553
481
  **kwargs: Any,
554
482
  ) -> "PathExtended":
555
483
  path_resolved, slf = self._resolve_path(folder, name, path, self.name).expanduser().resolve(), self.expanduser().resolve()
556
- # if use_7z: # benefits over regular zip and encrypt: can handle very large files with low memory footprint
557
- # path_resolved = path_resolved + '.7z' if not path_resolved.suffix == '.7z' else path_resolved
558
- # with install_n_import("py7zr").SevenZipFile(file=path_resolved, mode=mode, password=pwd) as archive: archive.writeall(path=str(slf), arcname=None)
559
484
  arcname_obj = PathExtended(arcname or slf.name)
560
485
  if arcname_obj.name != slf.name:
561
486
  arcname_obj /= slf.name # arcname has to start from somewhere and end with filename
@@ -628,15 +553,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
628
553
  folder = folder if not content else folder.parent
629
554
  if slf.suffix == ".7z":
630
555
  raise NotImplementedError("I have not implemented this yet")
631
- # if overwrite: P(folder).delete(sure=True)
632
- # result = folder
633
- # import py7zr
634
- # with py7zr.SevenZipFile(file=slf, mode='r', password=pwd) as archive:
635
- # if pattern is not None:
636
- # import re
637
- # pat = re.compile(pattern)
638
- # archive.extract(path=folder, targets=[f for f in archive.getnames() if pat.match(f)])
639
- # else: archive.extractall(path=folder)
640
556
  else:
641
557
  if overwrite:
642
558
  if not content:
@@ -771,21 +687,54 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
771
687
  return ret
772
688
 
773
689
  def decompress(self, folder: OPLike = None, name: Optional[str] = None, path: OPLike = None, inplace: bool = False, orig: bool = False, verbose: bool = True) -> "PathExtended":
774
- if ".tar.gz" in str(self) or ".tgz" in str(self):
690
+ if str(self).endswith(".tar.gz") or str(self).endswith(".tgz"):
775
691
  # res = self.ungz_untar(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
776
692
  return self.ungz(name=f"tmp_{randstr()}.tar", inplace=inplace).untar(folder=folder, name=name, path=path, inplace=True, orig=orig, verbose=verbose) # this works for .tgz suffix as well as .tar.gz
777
- elif ".gz" in str(self):
693
+ elif str(self).endswith(".tar"):
694
+ res = self.untar(folder=folder, name=name, path=path, inplace=inplace, orig=orig, verbose=verbose)
695
+ elif str(self).endswith(".gz"):
778
696
  res = self.ungz(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
779
- elif ".tar.bz" in str(self) or "tbz" in str(self):
697
+ elif str(self).endswith(".tar.bz") or str(self).endswith(".tbz") or str(self).endswith(".tar.bz2"):
780
698
  res = self.unbz(name=f"tmp_{randstr()}.tar", inplace=inplace)
781
699
  return res.untar(folder=folder, name=name, path=path, inplace=True, orig=orig, verbose=verbose)
782
- elif ".tar.xz" in str(self):
700
+ elif str(self).endswith(".tar.xz"):
783
701
  # res = self.unxz_untar(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
784
702
  res = self.unxz(inplace=inplace).untar(folder=folder, name=name, path=path, inplace=True, orig=orig, verbose=verbose)
785
- elif ".zip" in str(self):
703
+ elif str(self).endswith(".zip"):
786
704
  res = self.unzip(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
705
+ elif str(self).endswith(".7z"):
706
+ def unzip_7z(archive_path: str, dest_dir: Optional[str] = None) -> Path:
707
+ """
708
+ Uncompresses a .7z archive to a directory and returns the Path to the extraction directory.
709
+
710
+ :param archive_path: path to the .7z archive file
711
+ :param dest_dir: optional path to directory to extract into; if None a temporary dir will be created
712
+ :return: pathlib.Path pointing to the destination directory where contents were extracted
713
+ :raises: FileNotFoundError if archive does not exist; py7zr.Bad7zFile or other error if extraction fails
714
+ """
715
+ import py7zr # type: ignore
716
+ import tempfile
717
+ from pathlib import Path
718
+ archive_path_obj = Path(archive_path)
719
+ if not archive_path_obj.is_file():
720
+ raise FileNotFoundError(f"Archive file not found: {archive_path_obj!r}")
721
+ if dest_dir is None:
722
+ # create a temporary directory
723
+ dest = Path(tempfile.mkdtemp(prefix=f"unzip7z_{archive_path_obj.stem}_"))
724
+ else:
725
+ dest = Path(dest_dir)
726
+ dest.mkdir(parents=True, exist_ok=True)
727
+ # Perform extraction
728
+ with py7zr.SevenZipFile(str(archive_path_obj), mode='r') as archive:
729
+ archive.extractall(path=str(dest))
730
+ # Return the extraction directory path
731
+ return dest
732
+ from machineconfig.utils.code import run_lambda_function
733
+ destination_dir = str(self.expanduser().resolve()).replace(".7z", "")
734
+ run_lambda_function(lambda: unzip_7z(archive_path=str(self), dest_dir=destination_dir), uv_project_dir=None, uv_with=["py7zr"])
735
+ res = PathExtended(destination_dir)
787
736
  else:
788
- res = self
737
+ raise ValueError(f"Cannot decompress file with unknown extension: {self}")
789
738
  return res
790
739
 
791
740
  def encrypt(
@@ -861,7 +810,7 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
861
810
  path = self
862
811
  else:
863
812
  try:
864
- path = self.rel2home()
813
+ path = PathExtended(self.expanduser().absolute().relative_to(Path.home()))
865
814
  except ValueError as ve:
866
815
  if strict:
867
816
  raise ve
@@ -909,9 +858,10 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
909
858
  rp = localpath.get_remote_path(root=root, os_specific=os_specific, rel2home=rel2home, strict=strict) # if rel2home else (P(root) / localpath if root is not None else localpath)
910
859
  else:
911
860
  rp = PathExtended(remotepath)
912
-
913
861
  from rclone_python import rclone
862
+ print(f"⬆️ UPLOADING {repr(localpath)} TO {cloud}:{rp.as_posix()}`") if verbose else None
914
863
  rclone.copyto(in_path=localpath.as_posix(), out_path=f"{cloud}:{rp.as_posix()}", )
864
+
915
865
  _ = [item.delete(sure=True) for item in to_del]
916
866
  if verbose:
917
867
  print(f"{'⬆️' * 5} UPLOAD COMPLETED.")
@@ -922,7 +872,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
922
872
  command = f"rclone link '{cloud}:{rp.as_posix()}'"
923
873
  completed = _run_shell_command(command, shell_to_use)
924
874
  from machineconfig.utils.terminal import Response
925
-
926
875
  res = Response.from_completed_process(completed).capture()
927
876
  tmp = res.op2path(strict_err=False, strict_returncode=False)
928
877
  if tmp is None:
@@ -1,18 +1,16 @@
1
- from machineconfig.utils.path_extended import PathExtended
2
- from machineconfig.utils.options import choose_from_options
3
1
  from machineconfig.utils.source_of_truth import EXCLUDE_DIRS
4
2
  from rich.console import Console
5
3
  from rich.panel import Panel
6
4
  import platform
7
5
  import subprocess
8
6
  from pathlib import Path
9
-
7
+ from typing import Optional
10
8
 
11
9
  console = Console()
12
10
 
13
11
 
14
- def sanitize_path(a_path: str) -> PathExtended:
15
- path = PathExtended(a_path)
12
+ def sanitize_path(a_path: str) -> Path:
13
+ path = Path(a_path)
16
14
  if Path.cwd() == Path.home() and not path.exists():
17
15
  result = input("Current working directory is home, and passed path is not full path, are you sure you want to continue, [y]/n? ") or "y"
18
16
  if result == "y":
@@ -23,13 +21,13 @@ def sanitize_path(a_path: str) -> PathExtended:
23
21
  if platform.system() == "Windows": # path copied from Linux/Mac to Windows
24
22
  # For Linux: /home/username, for Mac: /Users/username
25
23
  skip_parts = 3 if path.as_posix().startswith("/home") else 3 # Both have 3 parts to skip
26
- path = PathExtended.home().joinpath(*path.parts[skip_parts:])
24
+ path = Path.home().joinpath(*path.parts[skip_parts:])
27
25
  assert path.exists(), f"File not found: {path}"
28
26
  source_os = "Linux" if path.as_posix().startswith("/home") else "macOS"
29
27
  console.print(Panel(f"🔗 PATH MAPPING | {source_os} → Windows: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
30
- elif platform.system() in ["Linux", "Darwin"] and PathExtended.home().as_posix() not in path.as_posix(): # copied between Unix-like systems with different username
28
+ elif platform.system() in ["Linux", "Darwin"] and Path.home().as_posix() not in path.as_posix(): # copied between Unix-like systems with different username
31
29
  skip_parts = 3 # Both /home/username and /Users/username have 3 parts to skip
32
- path = PathExtended.home().joinpath(*path.parts[skip_parts:])
30
+ path = Path.home().joinpath(*path.parts[skip_parts:])
33
31
  assert path.exists(), f"File not found: {path}"
34
32
  current_os = "Linux" if platform.system() == "Linux" else "macOS"
35
33
  source_os = "Linux" if path.as_posix().startswith("/home") else "macOS"
@@ -37,12 +35,12 @@ def sanitize_path(a_path: str) -> PathExtended:
37
35
  elif path.as_posix().startswith("C:"):
38
36
  if platform.system() in ["Linux", "Darwin"]: # path copied from Windows to Linux/Mac
39
37
  xx = str(a_path).replace("\\\\", "/")
40
- path = PathExtended.home().joinpath(*PathExtended(xx).parts[3:]) # exclude C:\\Users\\username
38
+ path = Path.home().joinpath(*Path(xx).parts[3:]) # exclude C:\\Users\\username
41
39
  assert path.exists(), f"File not found: {path}"
42
40
  target_os = "Linux" if platform.system() == "Linux" else "macOS"
43
41
  console.print(Panel(f"🔗 PATH MAPPING | Windows → {target_os}: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
44
- elif platform.system() == "Windows" and PathExtended.home().as_posix() not in path.as_posix(): # copied from Windows to Windows with different username
45
- path = PathExtended.home().joinpath(*path.parts[2:])
42
+ elif platform.system() == "Windows" and Path.home().as_posix() not in path.as_posix(): # copied from Windows to Windows with different username
43
+ path = Path.home().joinpath(*path.parts[2:])
46
44
  assert path.exists(), f"File not found: {path}"
47
45
  console.print(Panel(f"🔗 PATH MAPPING | Windows → Windows: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
48
46
  return path.expanduser().absolute()
@@ -67,49 +65,58 @@ def find_scripts(root: Path, name_substring: str, suffixes: set[str]) -> tuple[l
67
65
  return filename_matches, partial_path_matches
68
66
 
69
67
 
70
- def match_file_name(sub_string: str, search_root: PathExtended, suffixes: set[str]) -> PathExtended:
68
+ def match_file_name(sub_string: str, search_root: Path, suffixes: set[str]) -> Path:
71
69
  search_root_obj = search_root.absolute()
72
70
  # assume subscript is filename only, not a sub_path. There is no need to fzf over the paths.
73
71
  filename_matches, partial_path_matches = find_scripts(search_root_obj, sub_string, suffixes)
74
72
  if len(filename_matches) == 1:
75
- return PathExtended(filename_matches[0])
73
+ return Path(filename_matches[0])
76
74
  console.print(Panel(f"Partial filename {search_root_obj} match with case-insensitivity failed. This generated #{len(filename_matches)} results.", title="Search", expand=False))
77
75
  if len(filename_matches) < 20:
78
76
  print("\n".join([a_potential_match.as_posix() for a_potential_match in filename_matches]))
79
77
  if len(filename_matches) > 1:
80
- print("Try to narrow down filename_matches search by case-sensitivity.")
78
+ print(f"Try to narrow down filename_matches search by case-sensitivity, found {len(filename_matches)} results. First @ {filename_matches[0].as_posix()}")
81
79
  # let's see if avoiding .lower() helps narrowing down to one result
82
80
  reduced_scripts = [a_potential_match for a_potential_match in filename_matches if sub_string in a_potential_match.name]
83
81
  if len(reduced_scripts) == 1:
84
- return PathExtended(reduced_scripts[0])
82
+ return Path(reduced_scripts[0])
85
83
  elif len(reduced_scripts) > 1:
86
- choice = choose_from_options(multi=False, msg="Multiple matches found", options=reduced_scripts, fzf=True)
87
- return PathExtended(choice)
84
+ from machineconfig.utils.options import choose_from_options
85
+ choice = choose_from_options(multi=False, msg="Multiple matches found", options=reduced_scripts, tv=True)
86
+ return Path(choice)
88
87
  print(f"Result: This still generated {len(reduced_scripts)} results.")
89
88
  if len(reduced_scripts) < 10:
90
89
  print("\n".join([a_potential_match.as_posix() for a_potential_match in reduced_scripts]))
91
90
 
92
91
  console.print(Panel(f"Partial path match with case-insensitivity failed. This generated #{len(partial_path_matches)} results.", title="Search", expand=False))
93
92
  if len(partial_path_matches) == 1:
94
- return PathExtended(partial_path_matches[0])
93
+ return Path(partial_path_matches[0])
95
94
  elif len(partial_path_matches) > 1:
96
95
  print("Try to narrow down partial_path_matches search by case-sensitivity.")
97
96
  reduced_scripts = [a_potential_match for a_potential_match in partial_path_matches if sub_string in a_potential_match.as_posix()]
98
97
  if len(reduced_scripts) == 1:
99
- return PathExtended(reduced_scripts[0])
100
- print(f"Result: This still generated {len(reduced_scripts)} results.")
98
+ return Path(reduced_scripts[0])
99
+ print(f"Result: This still generated {len(reduced_scripts)} results.")
100
+
101
101
  try:
102
- fzf_cmd = f"cd '{search_root_obj}'; fd --type file --strip-cwd-prefix | fzf --ignore-case --exact --query={sub_string}"
102
+
103
+ if len(partial_path_matches) == 0:
104
+ print("No partial path matches found, trying to do fd with --no-ignore ...")
105
+ fzf_cmd = f"cd '{search_root_obj}'; fd --no-ignore --type file --strip-cwd-prefix | fzf --ignore-case --exact --query={sub_string}"
106
+ else:
107
+ fzf_cmd = f"cd '{search_root_obj}'; fd --type file --strip-cwd-prefix | fzf --ignore-case --exact --query={sub_string}"
103
108
  console.print(Panel(f"🔍 Second attempt: SEARCH STRATEGY | Using fd to search for '{sub_string}' in '{search_root_obj}' ...\n{fzf_cmd}", title="Search Strategy", expand=False))
104
109
  search_res_raw = subprocess.run(fzf_cmd, stdout=subprocess.PIPE, text=True, check=True, shell=True).stdout
105
- search_res = search_res_raw.strip().split("\\n")[:-1]
110
+ search_res = search_res_raw.strip().split("\n")
106
111
  except subprocess.CalledProcessError as cpe:
107
112
  console.print(Panel(f"❌ ERROR | FZF search failed with '{sub_string}' in '{search_root_obj}'.\n{cpe}", title="Error", expand=False))
108
113
  import sys
109
-
110
114
  sys.exit(f"💥 FILE NOT FOUND | Path {sub_string} does not exist @ root {search_root_obj}. No search results.")
111
115
  if len(search_res) == 1:
112
116
  return search_root_obj.joinpath(search_res_raw)
117
+ elif len(search_res) == 0:
118
+ msg = Panel(f"💥 FILE NOT FOUND | Path {sub_string} does not exist @ root {search_root_obj}. No search results", title="File Not Found", expand=False)
119
+ raise FileNotFoundError(msg)
113
120
 
114
121
  print(f"⚠️ WARNING | Multiple search results found for `{sub_string}`:\n'{search_res}'")
115
122
  cmd = f"cd '{search_root_obj}'; fd --type file | fzf --select-1 --query={sub_string}"
@@ -121,3 +128,49 @@ def match_file_name(sub_string: str, search_root: PathExtended, suffixes: set[st
121
128
  msg = Panel(f"💥 FILE NOT FOUND | Path {sub_string} does not exist @ root {search_root_obj}. No search results", title="File Not Found", expand=False)
122
129
  raise FileNotFoundError(msg) from cpe
123
130
  return search_root_obj.joinpath(res)
131
+
132
+
133
+ def search_for_files_of_interest(path_obj: Path, suffixes: set[str]) -> list[Path]:
134
+ if path_obj.is_file():
135
+ return [path_obj]
136
+ files: list[Path] = []
137
+ directories_to_visit: list[Path] = [path_obj]
138
+ while directories_to_visit:
139
+ current_dir = directories_to_visit.pop()
140
+ for entry in current_dir.iterdir():
141
+ if entry.is_dir():
142
+ if entry.name == ".venv":
143
+ continue
144
+ directories_to_visit.append(entry)
145
+ continue
146
+ if entry.suffix not in suffixes:
147
+ continue
148
+ if entry.suffix == ".py" and entry.name == "__init__.py":
149
+ continue
150
+ files.append(entry)
151
+ return files
152
+
153
+
154
+ def get_choice_file(path: str, suffixes: Optional[set[str]]):
155
+ path_obj = sanitize_path(path)
156
+ if suffixes is None:
157
+ import platform
158
+ if platform.system() == "Windows":
159
+ suffixes = {".py", ".ps1", ".sh"}
160
+ elif platform.system() in ["Linux", "Darwin"]:
161
+ suffixes = {".py", ".sh"}
162
+ else:
163
+ suffixes = {".py"}
164
+ if not path_obj.exists():
165
+ print(f"🔍 Searching for file matching `{path}` under `{Path.cwd()}`, but only if suffix matches {suffixes}")
166
+ choice_file = match_file_name(sub_string=path, search_root=Path.cwd(), suffixes=suffixes)
167
+ elif path_obj.is_dir():
168
+ print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
169
+ files = search_for_files_of_interest(path_obj, suffixes=suffixes)
170
+ print(f"🔍 Got #{len(files)} results.")
171
+ from machineconfig.utils.options import choose_from_options
172
+ choice_file = choose_from_options(multi=False, options=files, tv=True, msg="Choose one option")
173
+ choice_file = Path(choice_file)
174
+ else:
175
+ choice_file = path_obj
176
+ return choice_file
@@ -106,51 +106,45 @@ class ProcessManager:
106
106
  """Format process data as table string for display."""
107
107
  if not self.data:
108
108
  return ""
109
-
110
109
  # Create header
111
110
  _headers = ["Command", "PID", "Name", "Username", "CPU%", "Memory(MB)", "Status", "Create Time"]
112
111
  header_line = f"{'Command':<50} {'PID':<8} {'Name':<20} {'Username':<12} {'CPU%':<8} {'Memory(MB)':<12} {'Status':<12} {'Create Time':<20}"
113
112
  separator = "-" * len(header_line)
114
-
115
113
  lines = [header_line, separator]
116
-
117
114
  for process in self.data:
118
115
  # Format create_time as string
119
116
  create_time_str = process["create_time"].strftime("%Y-%m-%d %H:%M:%S")
120
117
  # Truncate command if too long
121
118
  command = process["command"][:47] + "..." if len(process["command"]) > 50 else process["command"]
122
-
123
119
  line = f"{command:<50} {process['pid']:<8} {process['name'][:19]:<20} {process['username'][:11]:<12} {process['cpu_percent']:<8.1f} {process['memory_usage_mb']:<12.2f} {process['status'][:11]:<12} {create_time_str:<20}"
124
120
  lines.append(line)
125
-
126
121
  return "\n".join(lines)
127
122
 
128
123
  def choose_and_kill(self):
129
124
  # header for interactive process selection
130
125
  title = "🎯 INTERACTIVE PROCESS SELECTION AND TERMINATION"
131
126
  console.print(Panel(title, title="[bold blue]Process Info[/bold blue]", border_style="blue"))
132
-
133
127
  # Format data as table for display
134
128
  formatted_data = self._format_process_table()
135
- options = formatted_data.split("\n")[1:] # Skip header
136
- res = choose_from_options(options=formatted_data.split("\n"), msg="📋 Select processes to manage:", fzf=True, multi=True)
137
- indices = [options.index(val) for val in res]
129
+ all_lines = formatted_data.split("\n")
130
+ header_and_separator = all_lines[:2] # First two lines: header and separator
131
+ options = all_lines[2:] # Skip header and separator, only process lines
132
+ res = choose_from_options(options=all_lines, msg="📋 Select processes to manage:", tv=True, multi=True)
133
+ # Filter out header and separator if they were selected
134
+ selected_lines = [line for line in res if line not in header_and_separator]
135
+ indices = [options.index(val) for val in selected_lines]
138
136
  selected_processes = [self.data[i] for i in indices]
139
-
140
137
  print("\n📊 All Processes:")
141
138
  print(formatted_data)
142
139
  print("\n🎯 Selected Processes:")
143
140
  for process in selected_processes:
144
141
  print(f"PID: {process['pid']}, Name: {process['name']}, Memory: {process['memory_usage_mb']:.2f}MB")
145
-
146
142
  for idx, process in enumerate(selected_processes):
147
143
  pprint(dict(process), f"📌 Process {idx}")
148
-
149
144
  kill_all = input("\n⚠️ Confirm killing ALL selected processes? y/[n] ").lower() == "y"
150
145
  if kill_all:
151
146
  self.kill(pids=[p["pid"] for p in selected_processes])
152
147
  return
153
-
154
148
  kill_by_index = input("\n🔫 Kill by index? (enter numbers separated by spaces, e.g. '1 4') or [n] to cancel: ")
155
149
  if kill_by_index != "" and kill_by_index != "n":
156
150
  indices = [int(val) for val in kill_by_index.split(" ")]
@@ -164,12 +158,10 @@ class ProcessManager:
164
158
  # header for filtering processes by name
165
159
  title = "🔍 FILTERING AND TERMINATING PROCESSES BY NAME"
166
160
  console.print(Panel(title, title="[bold blue]Process Info[/bold blue]", border_style="blue"))
167
-
168
161
  # Filter processes by name
169
162
  filtered_processes = [p for p in self.data if p["name"] == name]
170
163
  # Sort by create_time (ascending)
171
164
  filtered_processes.sort(key=lambda x: x["create_time"])
172
-
173
165
  print(f"🎯 Found {len(filtered_processes)} processes matching name: '{name}'")
174
166
  self.kill(pids=[p["pid"] for p in filtered_processes])
175
167
  console.print(Panel("", title="[bold blue]Process Info[/bold blue]", border_style="blue"))
@@ -186,40 +178,35 @@ class ProcessManager:
186
178
  pids = []
187
179
  if commands is None:
188
180
  commands = []
189
-
190
181
  killed_count = 0
191
-
192
182
  for name in names:
193
183
  matching_processes = [p for p in self.data if p["name"] == name]
194
184
  if len(matching_processes) > 0:
195
185
  for process in matching_processes:
196
186
  psutil.Process(process["pid"]).kill()
197
- print(f"💀 Killed process {name} with PID {process['pid']}. It lived {get_age(process['create_time'])}. RIP 🪦💐")
187
+ print(f"💀 Killed process {name} with PID {process['pid']}. It lived {get_age(process['create_time'])}. RIP 💐")
198
188
  killed_count += 1
199
189
  else:
200
190
  print(f'❓ No process named "{name}" found')
201
-
202
191
  for pid in pids:
203
192
  try:
204
193
  proc = psutil.Process(pid)
205
194
  proc_name = proc.name()
206
195
  proc_lifetime = get_age(datetime.fromtimestamp(proc.create_time(), tz=None))
207
196
  proc.kill()
208
- print(f'💀 Killed process with PID {pid} and name "{proc_name}". It lived {proc_lifetime}. RIP 🪦💐')
197
+ print(f'💀 Killed process with PID {pid} and name "{proc_name}". It lived {proc_lifetime}. RIP 💐')
209
198
  killed_count += 1
210
199
  except psutil.NoSuchProcess:
211
200
  print(f"❓ No process with PID {pid} found")
212
-
213
201
  for command in commands:
214
202
  matching_processes = [p for p in self.data if command in p["command"]]
215
203
  if len(matching_processes) > 0:
216
204
  for process in matching_processes:
217
205
  psutil.Process(process["pid"]).kill()
218
- print(f'💀 Killed process with "{command}" in its command & PID {process["pid"]}. It lived {get_age(process["create_time"])}. RIP 🪦💐')
206
+ print(f'💀 Killed process with "{command}" in its command & PID {process["pid"]}. It lived {get_age(process["create_time"])}. RIP 💐')
219
207
  killed_count += 1
220
208
  else:
221
209
  print(f'❓ No process has "{command}" in its command.')
222
-
223
210
  console.print(Panel(f"✅ Termination complete: {killed_count} processes terminated", title="[bold blue]Process Info[/bold blue]", border_style="blue"))
224
211
 
225
212