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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. machineconfig/cluster/remote/run_cluster.py +1 -1
  2. machineconfig/cluster/remote/run_remote.py +1 -1
  3. machineconfig/cluster/sessions_managers/utils/maker.py +10 -8
  4. machineconfig/cluster/sessions_managers/wt_local.py +1 -1
  5. machineconfig/cluster/sessions_managers/wt_local_manager.py +1 -1
  6. machineconfig/cluster/sessions_managers/zellij_local.py +1 -1
  7. machineconfig/cluster/sessions_managers/zellij_local_manager.py +1 -1
  8. machineconfig/jobs/installer/checks/check_installations.py +133 -0
  9. machineconfig/jobs/installer/checks/install_utils.py +132 -0
  10. machineconfig/jobs/installer/checks/report_utils.py +39 -0
  11. machineconfig/jobs/installer/checks/vt_utils.py +89 -0
  12. machineconfig/jobs/installer/installer_data.json +271 -152
  13. machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
  14. machineconfig/jobs/installer/package_groups.py +11 -9
  15. machineconfig/jobs/installer/{custom → python_scripts}/boxes.py +1 -2
  16. machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +1 -1
  17. machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +10 -8
  18. machineconfig/jobs/installer/{custom → python_scripts}/hx.py +30 -13
  19. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +1 -1
  20. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +6 -5
  21. machineconfig/jobs/installer/{custom_dev → python_scripts}/sysabc.py +28 -43
  22. machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +1 -1
  23. machineconfig/jobs/installer/{custom → python_scripts}/yazi.py +39 -19
  24. machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
  25. machineconfig/jobs/scripts_dynamic/a.py +428 -0
  26. machineconfig/logger.py +1 -1
  27. machineconfig/profile/create_helper.py +21 -10
  28. machineconfig/profile/create_links.py +77 -20
  29. machineconfig/profile/create_links_export.py +63 -58
  30. machineconfig/profile/create_shell_profile.py +14 -0
  31. machineconfig/profile/mapper_data.toml +45 -0
  32. machineconfig/profile/mapper_dotfiles.toml +249 -0
  33. machineconfig/scripts/python/agents.py +76 -171
  34. machineconfig/scripts/python/ai/initai.py +3 -1
  35. machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
  36. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
  37. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +8 -6
  38. machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
  39. machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
  40. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +1 -1
  41. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +29 -0
  42. machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
  43. machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
  44. machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
  45. machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
  46. machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
  47. machineconfig/scripts/python/ai/utils/vscode_tasks.py +6 -3
  48. machineconfig/scripts/python/cloud.py +58 -11
  49. machineconfig/scripts/python/croshell.py +4 -155
  50. machineconfig/scripts/python/devops.py +57 -38
  51. machineconfig/scripts/python/devops_navigator.py +17 -3
  52. machineconfig/scripts/python/fire_jobs.py +10 -193
  53. machineconfig/scripts/python/ftpx.py +5 -224
  54. machineconfig/scripts/python/graph/cli_graph.json +8743 -0
  55. machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
  56. machineconfig/scripts/python/{env_manager → helpers/helper_env}/env_manager_tui.py +1 -1
  57. machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
  58. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.py +1 -1
  59. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
  60. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_gemini.py +1 -1
  61. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_qwen.py +1 -1
  62. machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
  63. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_launch.py +10 -7
  64. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
  65. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
  66. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/copilot/config.yml +1 -0
  67. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/crush/crush.json +10 -0
  68. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/gemini/settings.json +12 -0
  69. machineconfig/scripts/python/helpers/helpers_agents/privacy/privacy.py +109 -0
  70. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.sh +3 -1
  71. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +6 -6
  72. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +10 -5
  73. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +4 -4
  74. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
  75. machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +229 -0
  76. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
  77. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +7 -6
  78. machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
  79. machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +262 -0
  80. machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +130 -0
  81. machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
  82. machineconfig/scripts/python/helpers/helpers_devops/cli_config_mount.py +77 -0
  83. machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +71 -0
  84. machineconfig/scripts/python/helpers/helpers_devops/cli_nw.py +285 -0
  85. machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +274 -0
  86. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_self.py +84 -33
  87. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_file.py +44 -30
  88. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_server.py +26 -43
  89. machineconfig/scripts/python/helpers/helpers_devops/cli_share_temp.py +69 -0
  90. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_terminal.py +12 -6
  91. machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
  92. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +12 -6
  93. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
  94. machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +64 -50
  95. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/commands.py +25 -0
  96. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/device_entry.py +17 -0
  97. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/devices.py +17 -0
  98. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/linux.py +103 -0
  99. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/macos.py +100 -0
  100. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/selection.py +47 -0
  101. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/utils.py +28 -0
  102. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/windows.py +91 -0
  103. machineconfig/scripts/python/helpers/helpers_devops/run_script.py +197 -0
  104. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
  105. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
  106. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +3 -3
  107. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/file_wrangler.py +1 -0
  108. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +1 -0
  109. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
  110. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +3 -3
  111. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_streamlit_helper.py +0 -0
  112. machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
  113. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_linux/fzfg +4 -3
  114. machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
  115. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_windows/fzfg.ps1 +2 -7
  116. machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
  117. machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
  118. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
  119. machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
  120. machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
  121. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
  122. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
  123. machineconfig/scripts/python/helpers/helpers_network/__init__.py +0 -0
  124. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address.py +52 -10
  125. machineconfig/scripts/python/helpers/helpers_network/address_switch.py +78 -0
  126. machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
  127. machineconfig/scripts/python/helpers/helpers_network/ssh/__init__.py +0 -0
  128. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_add_identity.py +73 -0
  129. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_add_key_windows.py +23 -0
  130. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_add_ssh_key.py +169 -0
  131. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_cloud_init.py +33 -0
  132. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_linux.py +338 -0
  133. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_linux_utils.py +35 -0
  134. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_windows.py +245 -0
  135. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_windows_utils.py +34 -0
  136. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
  137. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
  138. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +120 -37
  139. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +3 -2
  140. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -13
  141. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_2.py +63 -19
  142. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
  143. machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
  144. machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
  145. machineconfig/scripts/python/helpers/helpers_sessions/attach_impl.py +87 -0
  146. machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +114 -0
  147. machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +1 -2
  148. machineconfig/scripts/python/helpers/helpers_sessions/utils.py +69 -0
  149. machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/download.py +1 -1
  150. machineconfig/scripts/python/{helpers_devops/cli_utils.py → helpers/helpers_utils/pdf.py} +2 -2
  151. machineconfig/scripts/python/{helpers_utils/path.py → helpers/helpers_utils/python.py} +65 -40
  152. machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
  153. machineconfig/scripts/python/mcfg_entry.py +126 -48
  154. machineconfig/scripts/python/msearch.py +16 -61
  155. machineconfig/scripts/python/sessions.py +137 -191
  156. machineconfig/scripts/python/utils.py +104 -24
  157. machineconfig/settings/atuin/config.toml +294 -0
  158. machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
  159. machineconfig/settings/linters/.ruff.toml +2 -1
  160. machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
  161. machineconfig/settings/shells/bash/init.sh +6 -10
  162. machineconfig/settings/shells/nushell/config.nu +23 -1
  163. machineconfig/settings/shells/nushell/env.nu +22 -48
  164. machineconfig/settings/shells/nushell/init.nu +64 -240
  165. machineconfig/settings/shells/pwsh/init.ps1 +71 -5
  166. machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
  167. machineconfig/settings/shells/wezterm/wezterm.lua +4 -0
  168. machineconfig/settings/shells/wt/settings.json +31 -37
  169. machineconfig/settings/shells/zsh/init.sh +25 -5
  170. machineconfig/settings/television/cable_unix/bash-history.toml +1 -1
  171. machineconfig/settings/television/cable_windows/pwsh-history.toml +1 -1
  172. machineconfig/settings/tv/config.toml +234 -0
  173. machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
  174. machineconfig/settings/wsl/.wslconfig +5 -30
  175. machineconfig/settings/wt/__init__.py +0 -0
  176. machineconfig/settings/yazi/yazi_linux.toml +18 -8
  177. machineconfig/settings/zellij/__init__.py +0 -0
  178. machineconfig/settings/zellij/config.kdl +0 -295
  179. machineconfig/settings/zellij/layouts/__init__.py +0 -0
  180. machineconfig/settings/zellij/layouts/st.kdl +39 -9
  181. machineconfig/settings/zellij/layouts/st2.kdl +6 -2
  182. machineconfig/setup_linux/__init__.py +0 -1
  183. machineconfig/setup_linux/apps_desktop.sh +8 -27
  184. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  185. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +3 -0
  186. machineconfig/setup_mac/__init__.py +0 -2
  187. machineconfig/setup_windows/__init__.py +2 -5
  188. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +14 -13
  189. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +4 -3
  190. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -3
  191. machineconfig/type_hinting/sql/__init__.py +1 -0
  192. machineconfig/type_hinting/sql/base.py +216 -0
  193. machineconfig/type_hinting/sql/core_schema.py +64 -0
  194. machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
  195. machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
  196. machineconfig/type_hinting/typedict/__init__.py +1 -0
  197. machineconfig/type_hinting/typedict/ast_utils.py +130 -0
  198. machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
  199. machineconfig/type_hinting/typedict/generators.py +231 -0
  200. machineconfig/type_hinting/typedict/polars_schema.py +24 -0
  201. machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
  202. machineconfig/utils/accessories.py +24 -0
  203. machineconfig/utils/code.py +78 -33
  204. machineconfig/utils/files/ascii_art.py +10 -14
  205. machineconfig/utils/files/headers.py +3 -5
  206. machineconfig/utils/files/read.py +8 -1
  207. machineconfig/utils/installer_utils/github_release_bulk.py +11 -91
  208. machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
  209. machineconfig/utils/installer_utils/install_from_url.py +1 -1
  210. machineconfig/utils/installer_utils/installer_class.py +12 -4
  211. machineconfig/utils/installer_utils/installer_cli.py +7 -17
  212. machineconfig/utils/installer_utils/installer_helper.py +52 -36
  213. machineconfig/utils/installer_utils/installer_locator_utils.py +15 -25
  214. machineconfig/utils/installer_utils/installer_runner.py +4 -4
  215. machineconfig/utils/io.py +25 -8
  216. machineconfig/utils/meta.py +6 -4
  217. machineconfig/utils/options.py +49 -19
  218. machineconfig/utils/options_utils/__init__.py +0 -0
  219. machineconfig/utils/options_utils/options_tv_linux.py +211 -0
  220. machineconfig/utils/options_utils/options_tv_windows.py +88 -0
  221. machineconfig/utils/options_utils/tv_options.py +37 -0
  222. machineconfig/utils/path_extended.py +8 -7
  223. machineconfig/utils/procs.py +35 -27
  224. machineconfig/utils/scheduler.py +8 -2
  225. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  226. machineconfig/utils/schemas/layouts/layout_types.py +10 -0
  227. machineconfig/utils/source_of_truth.py +7 -1
  228. machineconfig/utils/ssh.py +73 -23
  229. machineconfig/utils/ssh_utils/abc.py +1 -1
  230. machineconfig/utils/ssh_utils/copy_from_here.py +19 -14
  231. machineconfig/utils/ssh_utils/copy_to_here.py +2 -1
  232. machineconfig/utils/ssh_utils/utils.py +23 -7
  233. machineconfig/utils/ssh_utils/wsl.py +107 -170
  234. machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
  235. machineconfig/utils/upgrade_packages.py +4 -8
  236. {machineconfig-7.98.dist-info → machineconfig-8.61.dist-info}/METADATA +30 -23
  237. machineconfig-8.61.dist-info/RECORD +539 -0
  238. {machineconfig-7.98.dist-info → machineconfig-8.61.dist-info}/entry_points.txt +0 -1
  239. machineconfig/jobs/installer/check_installations.py +0 -248
  240. machineconfig/profile/backup.toml +0 -49
  241. machineconfig/profile/mapper.toml +0 -263
  242. machineconfig/scripts/linux/other/share_cloud.sh +0 -64
  243. machineconfig/scripts/linux/other/share_nfs +0 -49
  244. machineconfig/scripts/linux/other/start_docker +0 -23
  245. machineconfig/scripts/linux/other/switch_ip +0 -20
  246. machineconfig/scripts/python/helpers/run_py_script.py +0 -79
  247. machineconfig/scripts/python/helpers/tmp_py_scripts/a.py +0 -26
  248. machineconfig/scripts/python/helpers_devops/cli_config.py +0 -105
  249. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -89
  250. machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
  251. machineconfig/scripts/python/helpers_devops/cli_nw.py +0 -214
  252. machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -215
  253. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
  254. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
  255. machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
  256. machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
  257. machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -620
  258. machineconfig/scripts/python/helpers_network/devops_add_identity.py +0 -82
  259. machineconfig/scripts/python/helpers_network/devops_add_ssh_key.py +0 -153
  260. machineconfig/scripts/python/helpers_network/mount_drive +0 -128
  261. machineconfig/scripts/python/helpers_network/mount_nfs +0 -49
  262. machineconfig/scripts/python/helpers_network/mount_nfs.py +0 -85
  263. machineconfig/scripts/python/helpers_network/mount_nw_drive +0 -61
  264. machineconfig/scripts/python/helpers_network/mount_nw_drive.py +0 -48
  265. machineconfig/scripts/python/helpers_network/mount_smb +0 -3
  266. machineconfig/scripts/python/helpers_network/mount_ssh.py +0 -64
  267. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +0 -391
  268. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +0 -338
  269. machineconfig/scripts/python/helpers_network/wsl_windows_transfer.py +0 -67
  270. machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -77
  271. machineconfig/scripts/python/terminal.py +0 -133
  272. machineconfig/scripts/windows/mounts/Restore-ThunderbirdProfile.ps1 +0 -92
  273. machineconfig/scripts/windows/mounts/mount_nfs.ps1 +0 -42
  274. machineconfig/scripts/windows/mounts/mount_nw.ps1 +0 -9
  275. machineconfig/scripts/windows/mounts/mount_smb.ps1 +0 -2
  276. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
  277. machineconfig/scripts/windows/mounts/share_cloud.cmd +0 -34
  278. machineconfig/scripts/windows/mounts/share_smb.ps1 +0 -16
  279. machineconfig/settings/zellij/config.orig.kdl +0 -295
  280. machineconfig/setup_linux/others/android.sh +0 -2
  281. machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh +0 -30
  282. machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
  283. machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
  284. machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
  285. machineconfig/setup_windows/others/docker.ps1 +0 -7
  286. machineconfig/setup_windows/others/obs.ps1 +0 -4
  287. machineconfig/setup_windows/others/power_options.ps1 +0 -7
  288. machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
  289. machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
  290. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
  291. machineconfig/setup_windows/ssh/openssh-server_add_key.ps1 +0 -7
  292. machineconfig/setup_windows/ssh/openssh-server_copy-ssh-id.ps1 +0 -14
  293. machineconfig/utils/options_tv.py +0 -119
  294. machineconfig/utils/tst.py +0 -20
  295. machineconfig-7.98.dist-info/RECORD +0 -504
  296. /machineconfig/{jobs/installer/custom_dev → cluster/sessions_managers/wt_utils/examples}/__init__.py +0 -0
  297. /machineconfig/{scripts/python/helpers_agents → jobs/installer/checks}/__init__.py +0 -0
  298. /machineconfig/{scripts/python/helpers_agents/agentic_frameworks → jobs/installer/python_scripts}/__init__.py +0 -0
  299. /machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
  300. /machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
  301. /machineconfig/jobs/installer/{custom_dev → python_scripts}/cloudflare_warp_cli.py +0 -0
  302. /machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
  303. /machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +0 -0
  304. /machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
  305. /machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
  306. /machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
  307. /machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
  308. /machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
  309. /machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +0 -0
  310. /machineconfig/jobs/{installer/linux_scripts → scripts/bash_scripts}/lid.sh +0 -0
  311. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
  312. /machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
  313. /machineconfig/scripts/python/{helpers_cloud → graph}/__init__.py +0 -0
  314. /machineconfig/scripts/python/{helpers_croshell → helpers}/__init__.py +0 -0
  315. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
  316. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
  317. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_agents}/__init__.py +0 -0
  318. /machineconfig/scripts/python/{helpers_devops/themes → helpers/helpers_agents/agentic_frameworks}/__init__.py +0 -0
  319. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
  320. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
  321. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_helper_types.py +0 -0
  322. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
  323. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/prompt.txt +0 -0
  324. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.ps1 +0 -0
  325. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_cloud}/__init__.py +0 -0
  326. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +0 -0
  327. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
  328. /machineconfig/scripts/python/{helpers_network → helpers/helpers_croshell}/__init__.py +0 -0
  329. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +0 -0
  330. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
  331. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
  332. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
  333. /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_devops}/__init__.py +0 -0
  334. /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers/helpers_devops/mount_helpers}/__init__.py +0 -0
  335. /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_devops/themes/__init__.py} +0 -0
  336. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  337. /machineconfig/scripts/python/{helpers_fire_command/f.py → helpers/helpers_fire_command/__init__.py} +0 -0
  338. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
  339. /machineconfig/scripts/python/{helpers_fire_command/fire_jobs_streamlit_helper.py → helpers/helpers_fire_command/f.py} +0 -0
  340. /machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/__init__.py +0 -0
  341. /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
  342. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/onetimeshare.py +0 -0
  343. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/wifi_conn.py +0 -0
  344. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -0
  345. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_1.py +0 -0
  346. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
  347. /machineconfig/scripts/python/helpers/{ast_search.py → helpers_search/ast_search.py} +0 -0
  348. /machineconfig/scripts/python/helpers/{qr_code.py → helpers_search/qr_code.py} +0 -0
  349. /machineconfig/scripts/python/helpers/{repo_rag.py → helpers_search/repo_rag.py} +0 -0
  350. /machineconfig/scripts/python/helpers/{symantic_search.py → helpers_search/symantic_search.py} +0 -0
  351. /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
  352. {machineconfig-7.98.dist-info → machineconfig-8.61.dist-info}/WHEEL +0 -0
  353. {machineconfig-7.98.dist-info → machineconfig-8.61.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,262 @@
1
+ """BR: Backup and Retrieve"""
2
+
3
+ import re
4
+ from platform import system
5
+ from typing import Literal, Optional
6
+ from pathlib import Path
7
+
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+
11
+ from machineconfig.utils.io import read_ini
12
+ from machineconfig.utils.source_of_truth import DEFAULTS_PATH
13
+ from machineconfig.utils.code import print_code
14
+ from machineconfig.utils.options import choose_cloud_interactively
15
+ from machineconfig.scripts.python.helpers.helpers_cloud.helpers2 import ES
16
+ from machineconfig.scripts.python.helpers.helpers_devops.backup_config import (
17
+ BackupConfig, BackupGroup, VALID_OS, USER_BACKUP_PATH, DEFAULT_BACKUP_HEADER,
18
+ normalize_os_name, os_applies, read_backup_config,
19
+ )
20
+ from machineconfig.profile.create_links_export import REPO_LOOSE
21
+
22
+ DIRECTION = Literal["BACKUP", "RETRIEVE"]
23
+
24
+
25
+ def _sanitize_entry_name(value: str) -> str:
26
+ token = value.strip().replace(".", "_").replace("-", "_")
27
+ token = re.sub(r"\s+", "_", token)
28
+ token = re.sub(r"[^A-Za-z0-9_]", "_", token)
29
+ return token or "backup_item"
30
+
31
+
32
+ def _format_backup_entry_block(
33
+ entry_name: str,
34
+ path_local: str,
35
+ path_cloud: str,
36
+ zip: bool,
37
+ encrypt: bool,
38
+ rel2home: bool,
39
+ os_value: str,
40
+ ) -> str:
41
+ parts = [
42
+ f"path_local = '{path_local}'",
43
+ f"path_cloud = '{path_cloud}'",
44
+ f"encrypt = {str(encrypt).lower()}",
45
+ f"zip = {str(zip).lower()}",
46
+ f"rel2home = {str(rel2home).lower()}",
47
+ f"os = '{os_value}'",
48
+ ]
49
+ return f"{entry_name} = {{ {', '.join(parts)} }}"
50
+
51
+
52
+ def _upsert_backup_entry(content: str, group_name: str, entry_name: str, entry_line: str) -> tuple[str, bool]:
53
+ header = f"[{group_name}]"
54
+ lines = content.splitlines()
55
+ new_lines: list[str] = []
56
+ in_target = False
57
+ entry_written = False
58
+ replaced = False
59
+ for line in lines:
60
+ stripped = line.strip()
61
+ if stripped.startswith("[") and stripped.endswith("]"):
62
+ if in_target and not entry_written:
63
+ new_lines.append(entry_line)
64
+ entry_written = True
65
+ in_target = False
66
+ if stripped == header:
67
+ in_target = True
68
+ new_lines.append(line)
69
+ continue
70
+ if in_target:
71
+ if stripped.startswith(f"{entry_name} ="):
72
+ new_lines.append(entry_line)
73
+ replaced = True
74
+ entry_written = True
75
+ continue
76
+ new_lines.append(line)
77
+ if not entry_written:
78
+ if header not in content:
79
+ if new_lines and new_lines[-1].strip():
80
+ new_lines.append("")
81
+ new_lines.append(header)
82
+ new_lines.append(entry_line)
83
+ updated = "\n".join(new_lines).rstrip() + "\n"
84
+ return updated, replaced
85
+
86
+
87
+ def register_backup_entry(
88
+ path_local: str,
89
+ group: str,
90
+ entry_name: Optional[str] = None,
91
+ path_cloud: Optional[str] = None,
92
+ zip: bool = True,
93
+ encrypt: bool = True,
94
+ rel2home: Optional[bool] = None,
95
+ os: str = "any",
96
+ ) -> tuple[Path, str, bool]:
97
+ local_path = Path(path_local).expanduser().absolute()
98
+ if not local_path.exists():
99
+ raise ValueError(f"Local path does not exist: {local_path}")
100
+ os_parts = [part.strip() for part in os.split(",")]
101
+ os_tokens: list[str] = []
102
+ for part in os_parts:
103
+ if not part:
104
+ continue
105
+ token = normalize_os_name(part)
106
+ if token in {"any", "all", "*"}:
107
+ os_tokens = ["any"]
108
+ break
109
+ if token not in VALID_OS:
110
+ raise ValueError(f"Invalid os value: {os!r}. Expected one of: {sorted(VALID_OS)}")
111
+ os_tokens.append(token)
112
+ if not os_tokens:
113
+ raise ValueError(f"Invalid os value: {os!r}. Expected one of: {sorted(VALID_OS)}")
114
+ home = Path.home()
115
+ in_home = local_path.is_relative_to(home)
116
+ if rel2home is None:
117
+ rel2home = in_home
118
+ if rel2home and not in_home:
119
+ raise ValueError("rel2home is true, but the local path is not under the home directory.")
120
+ group_name = _sanitize_entry_name(group) if group and group.strip() else "default"
121
+ if entry_name is None or not entry_name.strip():
122
+ base_name = _sanitize_entry_name(local_path.stem)
123
+ os_tag = "any" if "any" in os_tokens else "_".join(os_tokens)
124
+ entry_name = f"{base_name}_{os_tag}" if os_tag != "any" else base_name
125
+ else:
126
+ entry_name = _sanitize_entry_name(entry_name)
127
+ local_display = f"~/{local_path.relative_to(home)}" if rel2home and in_home else local_path.as_posix()
128
+ cloud_value = path_cloud.strip() if path_cloud and path_cloud.strip() else ES
129
+ os_value = "any" if "any" in os_tokens else ",".join(os_tokens)
130
+ entry_block = _format_backup_entry_block(
131
+ entry_name=entry_name,
132
+ path_local=local_display,
133
+ path_cloud=cloud_value,
134
+ zip=zip,
135
+ encrypt=encrypt,
136
+ rel2home=rel2home,
137
+ os_value=os_value,
138
+ )
139
+ USER_BACKUP_PATH.parent.mkdir(parents=True, exist_ok=True)
140
+ if USER_BACKUP_PATH.exists():
141
+ content = USER_BACKUP_PATH.read_text(encoding="utf-8")
142
+ else:
143
+ content = DEFAULT_BACKUP_HEADER
144
+ updated, replaced = _upsert_backup_entry(content=content, group_name=group_name, entry_name=entry_name, entry_line=entry_block)
145
+ USER_BACKUP_PATH.write_text(updated, encoding="utf-8")
146
+ return USER_BACKUP_PATH, entry_name, replaced
147
+
148
+
149
+ def main_backup_retrieve(direction: DIRECTION, which: Optional[str], cloud: Optional[str], repo: REPO_LOOSE) -> None:
150
+ console = Console()
151
+ if cloud is None or not cloud.strip():
152
+ try:
153
+ cloud = read_ini(DEFAULTS_PATH)["general"]["rclone_config_name"].strip()
154
+ console.print(Panel(f"⚠️ DEFAULT CLOUD CONFIGURATION\n🌥️ Using default cloud: {cloud}", title="[bold blue]Cloud Configuration[/bold blue]", border_style="blue"))
155
+ except (FileNotFoundError, KeyError, IndexError):
156
+ console.print(Panel("🔍 DEFAULT CLOUD NOT FOUND\n🔄 Please select a cloud configuration from the options below", title="[bold red]Error: Cloud Not Found[/bold red]", border_style="red"))
157
+ cloud = choose_cloud_interactively().strip()
158
+ else:
159
+ cloud = cloud.strip()
160
+ console.print(Panel(f"🌥️ Using provided cloud: {cloud}", title="[bold blue]Cloud Configuration[/bold blue]", border_style="blue"))
161
+ assert cloud is not None
162
+ bu_file: BackupConfig = read_backup_config(repo=repo)
163
+ system_raw = system()
164
+ normalized_system = normalize_os_name(system_raw)
165
+ filtered: BackupConfig = {}
166
+ for group_name, group_items in bu_file.items():
167
+ matched: BackupGroup = {}
168
+ for key, val in group_items.items():
169
+ if os_applies(val["os"], system_name=normalized_system):
170
+ matched[key] = val
171
+ if matched:
172
+ filtered[group_name] = matched
173
+ bu_file = filtered
174
+ console.print(Panel(
175
+ f"🖥️ {system_raw} ENVIRONMENT DETECTED\n"
176
+ "🔍 Filtering entries by os field\n"
177
+ f"✅ Found {sum(len(item) for item in bu_file.values())} applicable backup configuration entries",
178
+ title="[bold blue]Environment[/bold blue]",
179
+ border_style="blue",
180
+ ))
181
+
182
+ if which is None:
183
+ from machineconfig.utils.options_utils.tv_options import choose_from_dict_with_preview
184
+ choices = choose_from_dict_with_preview(
185
+ options_to_preview_mapping=bu_file, extension="toml", multi=True, preview_size_percent=75.0,
186
+ )
187
+ if len(choices) == 0:
188
+ console.print(Panel("❌ NO ITEMS SELECTED\n⚠️ Exiting without processing any items", title="[bold red]No Items Selected[/bold red]", border_style="red"))
189
+ return
190
+ else:
191
+ choices = [token.strip() for token in which.split(",")] if which else []
192
+ console.print(Panel(f"🔖 PRE-SELECTED ITEMS\n📝 Using: {', '.join(choices)}", title="[bold blue]Pre-selected Items[/bold blue]", border_style="blue"))
193
+
194
+ items: BackupConfig
195
+ if "all" in choices:
196
+ items = bu_file
197
+ console.print(Panel(f"📋 PROCESSING ALL ENTRIES\n🔢 Total entries to process: {sum(len(item) for item in bu_file.values())}", title="[bold blue]Process All Entries[/bold blue]", border_style="blue"))
198
+ else:
199
+ items = {}
200
+ unknown: list[str] = []
201
+ for choice in choices:
202
+ if not choice:
203
+ continue
204
+ if choice in bu_file:
205
+ items[choice] = bu_file[choice]
206
+ continue
207
+ if "." in choice:
208
+ group_name, item_name = choice.split(".", 1)
209
+ if group_name in bu_file and item_name in bu_file[group_name]:
210
+ items.setdefault(group_name, {})[item_name] = bu_file[group_name][item_name]
211
+ continue
212
+ unknown.append(choice)
213
+ if unknown:
214
+ raise ValueError(f"Unknown backup entries: {', '.join(unknown)}")
215
+ console.print(Panel(f"📋 PROCESSING SELECTED ENTRIES\n🔢 Total entries to process: {sum(len(item) for item in items.values())}", title="[bold blue]Process Selected Entries[/bold blue]", border_style="blue"))
216
+ program = ""
217
+ console.print(Panel(f"🚀 GENERATING {direction} SCRIPT\n🌥️ Cloud: {cloud}\n🗂️ Items: {sum(len(item) for item in items.values())}", title="[bold blue]Script Generation[/bold blue]", border_style="blue"))
218
+ for group_name, group_items in items.items():
219
+ for item_name, item in group_items.items():
220
+ display_name = f"{group_name}.{item_name}"
221
+ flags = ""
222
+ flags += "z" if item["zip"] else ""
223
+ flags += "e" if item["encrypt"] else ""
224
+ flags += "r" if item["rel2home"] else ""
225
+ flags += "o" if "any" not in item["os"] else ""
226
+ local_path = Path(item["path_local"]).as_posix()
227
+ if item["path_cloud"] in (None, ES):
228
+ remote_path = ES
229
+ remote_display = f"{ES} (deduced)"
230
+ else:
231
+ remote_path = Path(item["path_cloud"]).as_posix()
232
+ remote_display = remote_path
233
+ remote_spec = f"{cloud}:{remote_path}"
234
+ console.print(Panel(
235
+ f"📦 PROCESSING: {display_name}\n"
236
+ f"📂 Local path: {local_path}\n"
237
+ f"☁️ Remote path: {remote_display}\n"
238
+ f"🏳️ Flags: {flags or 'None'}",
239
+ title=f"[bold blue]Processing Item: {display_name}[/bold blue]",
240
+ border_style="blue",
241
+ ))
242
+ flag_arg = f" -{flags}" if flags else ""
243
+ if direction == "BACKUP":
244
+ program += f"""\ncloud copy "{local_path}" "{remote_spec}"{flag_arg}\n"""
245
+ elif direction == "RETRIEVE":
246
+ program += f"""\ncloud copy "{remote_spec}" "{local_path}"{flag_arg}\n"""
247
+ else:
248
+ console.print(Panel('❌ ERROR: INVALID DIRECTION\n⚠️ Direction must be either "BACKUP" or "RETRIEVE"', title="[bold red]Error: Invalid Direction[/bold red]", border_style="red"))
249
+ raise RuntimeError(f"Unknown direction: {direction}")
250
+ if group_name == "dotfiles" and system_raw == "Linux":
251
+ program += """\nchmod 700 ~/.ssh/*\n"""
252
+ console.print(Panel("🔒 SPECIAL HANDLING: SSH PERMISSIONS\n🛠️ Setting secure permissions for SSH files\n📝 Command: chmod 700 ~/.ssh/*", title="[bold blue]Special Handling: SSH Permissions[/bold blue]", border_style="blue"))
253
+ print_code(code=program, lexer="shell", desc=f"{direction} script")
254
+ console.print(Panel(f"✅ {direction} SCRIPT GENERATION COMPLETE\n🚀 Ready to execute the operations", title="[bold green]Script Generation Complete[/bold green]", border_style="green"))
255
+ # import subprocess
256
+ # subprocess.run(program, shell=True, check=True)
257
+ from machineconfig.utils.code import run_shell_script
258
+ run_shell_script(program, display_script=True, clean_env=False)
259
+
260
+
261
+ if __name__ == "__main__":
262
+ pass
@@ -0,0 +1,130 @@
1
+
2
+
3
+ from typing import Literal, Annotated
4
+ from pathlib import Path
5
+ import typer
6
+ import machineconfig.scripts.python.helpers.helpers_devops.cli_config_dotfile as dotfile_module
7
+ import machineconfig.profile.create_links_export as create_links_export
8
+
9
+
10
+ def configure_shell_profile(which: Annotated[Literal["default", "d", "nushell", "n"], typer.Option(..., "--which", "-w", help="Which shell profile to create/configure")]="default"):
11
+ """🔗 Configure your shell profile."""
12
+ from machineconfig.profile.create_shell_profile import create_default_shell_profile, create_nu_shell_profile
13
+ match which:
14
+ case "nushell" | "n":
15
+ create_nu_shell_profile()
16
+ return
17
+ case "default" | "d":
18
+ create_default_shell_profile()
19
+ return
20
+ msg = typer.style("Error: ", fg=typer.colors.RED) + f"Unknown shell profile type: {which}"
21
+ typer.echo(msg)
22
+
23
+
24
+
25
+ def pwsh_theme():
26
+ """🔗 Select powershell prompt theme."""
27
+ import machineconfig.scripts.python.helpers.helpers_devops.themes as themes
28
+ file_path = themes.__file__
29
+ # if file_path is None:
30
+ # typer.echo("❌ ERROR: Could not locate themes module file.", err=True)
31
+ # raise typer.Exit(code=1)
32
+ file = Path(file_path).parent / "choose_pwsh_theme.ps1"
33
+ import subprocess
34
+ subprocess.run(["pwsh", "-File", str(file)])
35
+
36
+
37
+ def starship_theme():
38
+ """🔗 Select starship prompt theme."""
39
+ import subprocess
40
+ import platform
41
+ import os
42
+ from pathlib import Path
43
+
44
+ current_dir = Path(__file__).parent.joinpath("themes")
45
+
46
+ if platform.system() == "Windows":
47
+ script_path = current_dir / "choose_starship_theme.ps1"
48
+ try:
49
+ subprocess.run(["pwsh", "-File", str(script_path)], check=True)
50
+ except FileNotFoundError:
51
+ # Fallback to powershell if pwsh is not available
52
+ subprocess.run(["powershell", "-File", str(script_path)], check=True)
53
+ else:
54
+ script_path = current_dir / "choose_starship_theme.sh"
55
+ # Ensure executable
56
+ os.chmod(script_path, 0o755)
57
+ subprocess.run(["bash", str(script_path)])
58
+
59
+
60
+ def copy_assets(which: Annotated[Literal["scripts", "s", "settings", "t", "both", "b"], typer.Argument(..., help="Which assets to copy")]):
61
+ """🔗 Copy asset files from library to machine."""
62
+ import machineconfig.profile.create_helper as create_helper
63
+ match which:
64
+ case "both" | "b":
65
+ create_helper.copy_assets_to_machine(which="scripts")
66
+ create_helper.copy_assets_to_machine(which="settings")
67
+ return
68
+ case "scripts" | "s":
69
+ create_helper.copy_assets_to_machine(which="scripts")
70
+ return
71
+ case "settings" | "t":
72
+ create_helper.copy_assets_to_machine(which="settings")
73
+ return
74
+ msg = typer.style("Error: ", fg=typer.colors.RED) + f"Unknown asset type: {which}"
75
+ typer.echo(msg)
76
+
77
+
78
+ def list_devices() -> None:
79
+ """🔗 List available mountable devices."""
80
+ import machineconfig.scripts.python.helpers.helpers_devops.cli_config_mount as mount_module
81
+ mount_module.list_devices()
82
+
83
+
84
+ def mount_device(
85
+ device_query: Annotated[str | None, typer.Option("--device", "-d", help="Device query (path, key, or label).")] = None,
86
+ mount_point: Annotated[str | None, typer.Option("--mount-point", "-p", help="Mount point (use '-' for default on macOS).")] = None,
87
+ interactive: Annotated[bool, typer.Option("--interactive", "-i", help="Pick device and mount point interactively.")] = False,
88
+ ) -> None:
89
+ """🔗 Mount a device to a mount point."""
90
+ import machineconfig.scripts.python.helpers.helpers_devops.cli_config_mount as mount_module
91
+ if interactive:
92
+ mount_module.mount_interactive()
93
+ return
94
+ if device_query is None or mount_point is None:
95
+ msg = typer.style("Error: ", fg=typer.colors.RED) + "--device and --mount-point are required unless --interactive is set"
96
+ typer.echo(msg)
97
+ raise typer.Exit(2)
98
+ mount_module.mount_device(device_query=device_query, mount_point=mount_point)
99
+
100
+
101
+ def get_app():
102
+ config_apps = typer.Typer(help="⚙️ [c] configuration subcommands", no_args_is_help=True, add_help_option=True, add_completion=False)
103
+ config_apps.command("sync", no_args_is_help=True, help="🔗 [s] Sync dotfiles.")(create_links_export.main_from_parser)
104
+ config_apps.command("s", no_args_is_help=True, help="Sync dotfiles.", hidden=True)(create_links_export.main_from_parser)
105
+
106
+ config_apps.command("register", no_args_is_help=True, help="🔗 [r] Register dotfiles agains user mapper.toml")(dotfile_module.register_dotfile)
107
+ config_apps.command("r", no_args_is_help=True, hidden=True)(dotfile_module.register_dotfile)
108
+
109
+ config_apps.command("export-dotfiles", no_args_is_help=True, help="🔗 [e] Export dotfiles for migration to new machine.")(dotfile_module.export_dotfiles)
110
+ config_apps.command("e", no_args_is_help=True, help="Export dotfiles for migration to new machine.", hidden=True)(dotfile_module.export_dotfiles)
111
+ config_apps.command("import-dotfiles", no_args_is_help=False, help="🔗 [i] Import dotfiles from exported archive.")(dotfile_module.import_dotfiles)
112
+ config_apps.command("i", no_args_is_help=False, help="Import dotfiles from exported archive.", hidden=True)(dotfile_module.import_dotfiles)
113
+
114
+ config_apps.command("shell", no_args_is_help=False, help="🔗 [S] Configure your shell profile.")(configure_shell_profile)
115
+ config_apps.command("S", no_args_is_help=False, help="Configure your shell profile.", hidden=True)(configure_shell_profile)
116
+ config_apps.command("starship-theme", no_args_is_help=False, help="🔗 [t] Select starship prompt theme.")(starship_theme)
117
+ config_apps.command("t", no_args_is_help=False, help="Select starship prompt theme.", hidden=True)(starship_theme)
118
+ config_apps.command("pwsh-theme", no_args_is_help=False, help="🔗 [T] Select powershell prompt theme.")(pwsh_theme)
119
+ config_apps.command("T", no_args_is_help=False, help="Select powershell prompt theme.", hidden=True)(pwsh_theme)
120
+
121
+ config_apps.command("copy-assets", no_args_is_help=True, help="🔗 [c] Copy asset files from library to machine.", hidden=False)(copy_assets)
122
+ config_apps.command("c", no_args_is_help=True, help="Copy asset files from library to machine.", hidden=True)(copy_assets)
123
+
124
+ config_apps.command("list-devices", no_args_is_help=False, help="🔗 [l] List available devices for mounting.")(list_devices)
125
+ config_apps.command("l", no_args_is_help=False, help="List available devices for mounting.", hidden=True)(list_devices)
126
+ config_apps.command("mount", no_args_is_help=True, help="🔗 [m] Mount a device to a mount point.")(mount_device)
127
+ config_apps.command("m", no_args_is_help=True, help="Mount a device to a mount point.", hidden=True)(mount_device)
128
+
129
+
130
+ return config_apps
@@ -0,0 +1,274 @@
1
+
2
+ """Like yadm and dotter."""
3
+
4
+ from git import Optional
5
+ from machineconfig.profile.create_links_export import ON_CONFLICT_LOOSE, ON_CONFLICT_MAPPER, METHOD_LOOSE, METHOD_MAP
6
+ from typing import Annotated, Literal
7
+ from pathlib import Path
8
+ import typer
9
+
10
+ from machineconfig.utils.source_of_truth import CONFIG_ROOT
11
+ BACKUP_ROOT_PRIVATE = Path.home().joinpath("dotfiles/machineconfig/mapper/files")
12
+ BACKUP_ROOT_PUBLIC = Path(CONFIG_ROOT).joinpath("dotfiles/mapper")
13
+
14
+
15
+
16
+ def _write_to_user_mapper(section: str, entry_name: str, original_path: Path, self_managed_path: Path, method: Literal["symlink", "copy"], is_contents: bool, os_filter: str) -> Path:
17
+ from machineconfig.profile.create_links import USER_MAPPER_PATH
18
+ mapper_path = USER_MAPPER_PATH
19
+ mapper_path.parent.mkdir(parents=True, exist_ok=True)
20
+ if mapper_path.exists():
21
+ content = mapper_path.read_text(encoding="utf-8")
22
+ else:
23
+ content = "# User-defined config file mappings\n# Created by `d c` CLI tool\n\n"
24
+ home = Path.home()
25
+ original_str = f"~/{original_path.relative_to(home)}" if original_path.is_relative_to(home) else original_path.as_posix()
26
+ self_managed_str = f"~/{self_managed_path.relative_to(home)}" if self_managed_path.is_relative_to(home) else self_managed_path.as_posix()
27
+ entry_dict_parts: list[str] = [f"original = '{original_str}'", f"self_managed = '{self_managed_str}'"]
28
+ if is_contents:
29
+ entry_dict_parts.append("contents = true")
30
+ if method == "copy":
31
+ entry_dict_parts.append("copy = true")
32
+ entry_dict_parts.append(f"os = '{os_filter}'")
33
+ entry_line = f"{entry_name} = {{ {', '.join(entry_dict_parts)} }}"
34
+ section_header = f"[{section}]"
35
+ if section_header in content:
36
+ lines = content.split("\n")
37
+ new_lines: list[str] = []
38
+ in_section = False
39
+ entry_updated = False
40
+ for line in lines:
41
+ if line.strip().startswith("[") and line.strip().endswith("]"):
42
+ if in_section and not entry_updated:
43
+ new_lines.append(entry_line)
44
+ entry_updated = True
45
+ in_section = line.strip() == section_header
46
+ if in_section and line.strip().startswith(f"{entry_name} ="):
47
+ new_lines.append(entry_line)
48
+ entry_updated = True
49
+ continue
50
+ new_lines.append(line)
51
+ if in_section and not entry_updated:
52
+ new_lines.append(entry_line)
53
+ content = "\n".join(new_lines)
54
+ else:
55
+ content = content.rstrip() + f"\n\n{section_header}\n{entry_line}\n"
56
+ mapper_path.write_text(content, encoding="utf-8")
57
+ return mapper_path
58
+
59
+ def record_mapping(orig_path: Path, new_path: Path, method: METHOD_LOOSE, section: str, os_filter: str) -> None:
60
+ entry_name = orig_path.stem.replace(".", "_").replace("-", "_")
61
+ method_resolved = METHOD_MAP[method]
62
+ mapper_file = _write_to_user_mapper(section=section, entry_name=entry_name, original_path=orig_path, self_managed_path=new_path, method=method_resolved, is_contents=False, os_filter=os_filter)
63
+ home = Path.home()
64
+ orig_display = f"~/{orig_path.relative_to(home)}" if orig_path.is_relative_to(home) else orig_path.as_posix()
65
+ new_display = f"~/{new_path.relative_to(home)}" if new_path.is_relative_to(home) else new_path.as_posix()
66
+ from rich.console import Console
67
+ from rich.panel import Panel
68
+ console = Console()
69
+ console.print(Panel(f"📝 Mapping recorded in: [cyan]{mapper_file}[/cyan]\n[{section}]\n{entry_name} = {{ original = '{orig_display}', self_managed = '{new_display}', os = '{os_filter}' }}", title="Mapper Entry Saved", border_style="cyan", padding=(1, 2),))
70
+
71
+
72
+ def get_backup_path(orig_path: Path, sensitivity: Literal["private", "v", "public", "b"], destination: Optional[str], shared: bool) -> Path:
73
+ match sensitivity:
74
+ case "private" | "v":
75
+ backup_root = BACKUP_ROOT_PRIVATE
76
+ case "public" | "b":
77
+ backup_root = BACKUP_ROOT_PUBLIC
78
+ if destination is None:
79
+ if shared:
80
+ new_path = backup_root.joinpath("shared").joinpath(orig_path.name)
81
+ else:
82
+ new_path = backup_root.joinpath(orig_path.relative_to(Path.home()))
83
+ else:
84
+ if shared:
85
+ dest_path = Path(destination).expanduser().absolute()
86
+ new_path = dest_path.joinpath("shared").joinpath(orig_path.name)
87
+ else:
88
+ dest_path = Path(destination).expanduser().absolute()
89
+ new_path = dest_path.joinpath(orig_path.name)
90
+ return new_path
91
+
92
+
93
+ def get_original_path_from_backup_path(backup_path: Path, sensitivity: Literal["private", "v", "public", "b"], destination: Optional[str], shared: bool) -> Path:
94
+ match sensitivity:
95
+ case "private" | "v":
96
+ backup_root = BACKUP_ROOT_PRIVATE
97
+ case "public" | "b":
98
+ backup_root = BACKUP_ROOT_PUBLIC
99
+ if destination is None:
100
+ if shared:
101
+ relative_part = backup_path.relative_to(backup_root.joinpath("shared"))
102
+ else:
103
+ relative_part = backup_path.relative_to(backup_root)
104
+ original_path = Path.home().joinpath(relative_part)
105
+ else:
106
+ dest_path = Path(destination).expanduser().absolute()
107
+ if shared:
108
+ relative_part = backup_path.relative_to(dest_path.joinpath("shared"))
109
+ else:
110
+ relative_part = backup_path.relative_to(dest_path)
111
+ original_path = Path.home().joinpath(relative_part)
112
+ return original_path
113
+
114
+
115
+ def register_dotfile(
116
+ file: Annotated[str, typer.Argument(help="file/folder path.")],
117
+ method: Annotated[METHOD_LOOSE, typer.Option(..., "--method", "-m", help="Method to use for linking files")] = "copy",
118
+ on_conflict: Annotated[ON_CONFLICT_LOOSE, typer.Option(..., "--on-conflict", "-o", help="Action to take on conflict")] = "throw-error",
119
+ sensitivity: Annotated[Literal["private", "v", "public", "b"], typer.Option(..., "--sensitivity", "-s", help="Sensitivity of the config file.")] = "private",
120
+ destination: Annotated[Optional[str], typer.Option("--destination", "-d", help="destination folder (override the default, use at your own risk)")] = None,
121
+ section: Annotated[str, typer.Option("--section", "-se", help="Section name in mapper_dotfiles.toml to record this mapping.")] = "default",
122
+ os_filter: Annotated[str, typer.Option("--os", help="Comma-separated OS list or 'any' to apply everywhere.")] = "any",
123
+ shared: Annotated[bool, typer.Option("--shared", "-sh", help="Whether the config file is shared across destinations directory.")] = False,
124
+ record: Annotated[bool, typer.Option("--record", "-r", help="Record the mapping in user's mapper.toml")] = True,
125
+ ) -> None:
126
+ from rich.console import Console
127
+ from rich.panel import Panel
128
+ from machineconfig.utils.links import symlink_map, copy_map
129
+ console = Console()
130
+ orig_path = Path(file).expanduser().absolute()
131
+ new_path = get_backup_path(orig_path=orig_path, sensitivity=sensitivity, destination=destination, shared=shared)
132
+ if not orig_path.exists() and not new_path.exists():
133
+ console.print(f"[red]Error:[/] Neither original file nor self-managed file exists:\n Original: {orig_path}\n Self-managed: {new_path}")
134
+ raise typer.Exit(code=1)
135
+ new_path.parent.mkdir(parents=True, exist_ok=True)
136
+ match method:
137
+ case "copy" | "c":
138
+ try:
139
+ copy_map(config_file_default_path=orig_path, self_managed_config_file_path=new_path, on_conflict=ON_CONFLICT_MAPPER[on_conflict]) # type: ignore[arg-type]
140
+ except Exception as e:
141
+ msg = typer.style("Error: ", fg=typer.colors.RED) + str(e)
142
+ typer.echo(msg)
143
+ typer.Exit(code=1)
144
+ return
145
+ case "symlink" | "s":
146
+ try:
147
+ symlink_map(config_file_default_path=orig_path, self_managed_config_file_path=new_path, on_conflict=ON_CONFLICT_MAPPER[on_conflict]) # type: ignore[arg-type]
148
+ except Exception as e:
149
+ msg = typer.style("Error: ", fg=typer.colors.RED) + str(e)
150
+ typer.echo(msg)
151
+ typer.Exit(code=1)
152
+ return
153
+ case _:
154
+ raise ValueError(f"Unknown method: {method}")
155
+ console.print(Panel("\n".join(["✅ Symbolic link created successfully!", "🔄 Add the following snippet to mapper.toml to persist this mapping:",]), title="Symlink Created", border_style="green", padding=(1, 2),))
156
+ if record:
157
+ record_mapping(orig_path=orig_path, new_path=new_path, method=method, section=section, os_filter=os_filter)
158
+
159
+
160
+ def export_dotfiles(
161
+ pwd: Annotated[str, typer.Argument(..., help="Password for zip encryption")],
162
+ over_internet: Annotated[bool, typer.Option("--over-internet", "-i", help="Use internet-based transfer (wormhole-magic)")] = False,
163
+ over_ssh: Annotated[bool, typer.Option("--over-ssh", "-s", help="Use SSH-based transfer (scp) to a remote machine")] = False,
164
+ ):
165
+ """🔗 Export dotfiles for migration to new machine."""
166
+ if over_ssh:
167
+ code_sample = """ftpx ~/dotfiles user@remote_host:^ -z"""
168
+ print("🔗 Exporting dotfiles via SSH-based transfer (scp).")
169
+ print(f"💡 Run the following command on your local machine to copy dotfiles to the remote machine:\n{code_sample}")
170
+ remote_address = typer.prompt("Enter the remote machine address (user@host) to copy dotfiles to ")
171
+ code_concrete = f"fptx ~/dotfiles {remote_address}:^ -z"
172
+ from machineconfig.utils.code import run_shell_script
173
+ run_shell_script(code_concrete, display_script=True, clean_env=False)
174
+ dotfiles_dir = Path.home().joinpath("dotfiles")
175
+ if not dotfiles_dir.exists() or not dotfiles_dir.is_dir():
176
+ print(f"❌ Dotfiles directory does not exist: {dotfiles_dir}")
177
+ raise typer.Exit(code=1)
178
+ dotfiles_zip = Path.home().joinpath("dotfiles.zip")
179
+ if dotfiles_zip.exists():
180
+ dotfiles_zip.unlink()
181
+ import shutil
182
+ zipfile = shutil.make_archive(base_name=str(dotfiles_zip)[:-4], format="zip", root_dir=str(dotfiles_dir), base_dir=".", verbose=False)
183
+ from machineconfig.utils.io import encrypt
184
+ zipfile_enc_bytes = encrypt(
185
+ msg=Path(zipfile).read_bytes(),
186
+ pwd=pwd,
187
+ )
188
+ Path(zipfile).unlink()
189
+ zipfile_enc_path = Path(f"{zipfile}.enc")
190
+ if zipfile_enc_path.exists():
191
+ zipfile_enc_path.unlink()
192
+ zipfile_enc_path.write_bytes(zipfile_enc_bytes)
193
+ print(f"✅ Dotfiles exported to: {zipfile_enc_path}")
194
+ if over_internet:
195
+ # rm ~/dotfiles.zip || true
196
+ # ouch c ~/dotfiles dotfiles.zip
197
+ # # INSECURE OVER INTERNET: uvx wormhole-magic send ~/dotfiles.zip
198
+ raise NotImplementedError("Internet-based transfer not yet implemented.")
199
+ else:
200
+ # devops network share-server --no-auth ./dotfiles.zip
201
+ import machineconfig.scripts.python.helpers.helpers_devops.cli_share_server as cli_share_server
202
+ from machineconfig.scripts.python.helpers.helpers_network.address import select_lan_ipv4
203
+ localipv4 = select_lan_ipv4(prefer_vpn=False)
204
+ port = 8888
205
+ msg = f"""On the remote machine, run the following:
206
+ d c i -u http://{localipv4}:{port} -p {pwd}
207
+ """
208
+ from machineconfig.utils.accessories import display_with_flashy_style
209
+ display_with_flashy_style(msg=msg, title="Remote Machine Instructions",)
210
+ cli_share_server.web_file_explorer(
211
+ path=str(zipfile_enc_path),
212
+ no_auth=True,
213
+ port=port,
214
+ # bind_address="
215
+ )
216
+
217
+
218
+ def import_dotfiles(
219
+ url: Annotated[Optional[str], typer.Option(..., "--url", "-u", help="URL or local path to the encrypted dotfiles zip")] = None,
220
+ pwd: Annotated[Optional[str], typer.Option(..., "--pwd", "-p", help="Password for zip decryption")] = None,
221
+ use_ssh: Annotated[bool, typer.Option("--use-ssh", "-s", help="Use SSH-based transfer (scp) from a remote machine that has dotfiles.")]=False,
222
+ ):
223
+ # # INSECURE cd $HOME; uvx wormhole-magic receive dotfiles.zip.enc --accept-file
224
+ # ☁️ [bold blue]Method 3: USING INTERNET SECURE SHARE[/bold blue]
225
+ # [dim]cd ~
226
+ # cloud copy SHARE_URL . --config ss[/dim]
227
+ if use_ssh:
228
+ print("🔗 Importing dotfiles via SSH-based transfer (scp).")
229
+ code = """fptx $USER@$(hostname):^ ~/dotfiles -z"""
230
+ print(f"💡 Run the following command on the remote machine that has the dotfiles:\n{code}")
231
+ url = typer.prompt("Enter the remote machine address (user@host) to copy dotfiles from ")
232
+ code_concrete = f"fptx {url}:^ ~/dotfiles -z"
233
+ from machineconfig.utils.code import run_shell_script
234
+ run_shell_script(code_concrete, display_script=True, clean_env=False)
235
+ print("✅ Dotfiles copied via SSH.")
236
+ return
237
+ if url is None:
238
+ url = typer.prompt("Enter the URL or local path to the encrypted dotfiles zip (e..g 192.168.20.4:8888) ")
239
+ if pwd is None:
240
+ pwd = typer.prompt("Enter the password for zip decryption", hide_input=True)
241
+ from machineconfig.scripts.python.helpers.helpers_utils.download import download
242
+ downloaded_file = download(url=url, decompress=False, output_dir=str(Path.home()))
243
+ if downloaded_file is None or not downloaded_file.exists():
244
+ print(f"❌ Failed to download file from URL: {url}")
245
+ raise typer.Exit(code=1)
246
+ zipfile_enc_path = downloaded_file
247
+ from machineconfig.utils.io import decrypt
248
+ zipfile_bytes = decrypt(
249
+ token=zipfile_enc_path.read_bytes(),
250
+ pwd=pwd,
251
+ )
252
+ zipfile_path = Path(str(zipfile_enc_path)[:-4])
253
+ if zipfile_path.exists():
254
+ print(f"⚠️ WARNING: Overwriting existing file: {zipfile_path}")
255
+ zipfile_path.unlink()
256
+ zipfile_path.write_bytes(zipfile_bytes)
257
+ print(f"✅ Decrypted zip file saved to: {zipfile_path}")
258
+ import zipfile
259
+ if Path.home().joinpath("dotfiles").exists():
260
+ print(f"⚠️ WARNING: Overwriting existing directory: {Path.home().joinpath('dotfiles')}")
261
+ import shutil
262
+ shutil.rmtree(Path.home().joinpath("dotfiles"))
263
+ with zipfile.ZipFile(zipfile_path, 'r') as zip_ref:
264
+ zip_ref.extractall(Path.home().joinpath("dotfiles"))
265
+ print(f"✅ Dotfiles extracted to: {Path.home().joinpath('dotfiles')}")
266
+ zipfile_path.unlink()
267
+
268
+
269
+ def arg_parser() -> None:
270
+ typer.run(register_dotfile)
271
+
272
+
273
+ if __name__ == "__main__":
274
+ arg_parser()