machineconfig 3.99__py3-none-any.whl → 7.66__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 (418) hide show
  1. machineconfig/__init__.py +0 -28
  2. machineconfig/cluster/remote/distribute.py +0 -1
  3. machineconfig/cluster/remote/file_manager.py +0 -2
  4. machineconfig/cluster/remote/script_execution.py +1 -2
  5. machineconfig/cluster/sessions_managers/{enhanced_command_runner.py → helpers/enhanced_command_runner.py} +4 -6
  6. machineconfig/cluster/sessions_managers/helpers/load_balancer_helper.py +145 -0
  7. machineconfig/cluster/sessions_managers/utils/load_balancer.py +53 -0
  8. machineconfig/cluster/sessions_managers/utils/maker.py +69 -0
  9. machineconfig/cluster/sessions_managers/wt_local.py +128 -330
  10. machineconfig/cluster/sessions_managers/wt_local_manager.py +53 -187
  11. machineconfig/cluster/sessions_managers/wt_remote.py +51 -43
  12. machineconfig/cluster/sessions_managers/wt_remote_manager.py +49 -197
  13. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +6 -19
  14. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  15. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  16. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +4 -2
  17. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  18. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  19. machineconfig/cluster/sessions_managers/zellij_local.py +81 -375
  20. machineconfig/cluster/sessions_managers/zellij_local_manager.py +22 -172
  21. machineconfig/cluster/sessions_managers/zellij_remote.py +40 -41
  22. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +13 -10
  23. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +4 -8
  24. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +5 -20
  25. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +3 -9
  26. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -1
  27. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper.py +298 -0
  28. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_restart.py +77 -0
  29. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_with_panes.py +228 -0
  30. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_manager_helper.py +165 -0
  31. machineconfig/jobs/{python → installer}/check_installations.py +2 -16
  32. machineconfig/jobs/installer/custom/boxes.py +61 -0
  33. machineconfig/jobs/installer/custom/gh.py +69 -53
  34. machineconfig/jobs/installer/custom/hx.py +77 -20
  35. machineconfig/jobs/installer/custom_dev/alacritty.py +45 -30
  36. machineconfig/jobs/installer/custom_dev/brave.py +43 -35
  37. machineconfig/jobs/installer/custom_dev/bypass_paywall.py +31 -20
  38. machineconfig/jobs/installer/custom_dev/cloudflare_warp_cli.py +23 -0
  39. machineconfig/jobs/installer/custom_dev/code.py +33 -21
  40. machineconfig/jobs/installer/custom_dev/dubdb_adbc.py +30 -0
  41. machineconfig/jobs/installer/custom_dev/espanso.py +64 -41
  42. machineconfig/jobs/installer/custom_dev/goes.py +41 -36
  43. machineconfig/jobs/installer/custom_dev/lvim.py +49 -33
  44. machineconfig/jobs/installer/custom_dev/nerdfont.py +71 -47
  45. machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +32 -26
  46. machineconfig/jobs/installer/custom_dev/redis.py +51 -33
  47. machineconfig/jobs/installer/custom_dev/sysabc.py +119 -0
  48. machineconfig/jobs/installer/custom_dev/wezterm.py +55 -39
  49. machineconfig/jobs/installer/custom_dev/winget.py +1 -0
  50. machineconfig/jobs/installer/installer_data.json +3406 -0
  51. machineconfig/jobs/installer/linux_scripts/brave.sh +4 -14
  52. machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +5 -17
  53. machineconfig/jobs/installer/linux_scripts/docker.sh +5 -17
  54. machineconfig/jobs/installer/linux_scripts/docker_start.sh +6 -14
  55. machineconfig/jobs/installer/linux_scripts/edge.sh +3 -11
  56. machineconfig/jobs/{linux/msc → installer/linux_scripts}/lid.sh +2 -8
  57. machineconfig/jobs/installer/linux_scripts/nerdfont.sh +5 -17
  58. machineconfig/jobs/{linux/msc → installer/linux_scripts}/network.sh +2 -8
  59. machineconfig/jobs/installer/linux_scripts/ngrok.sh +6 -0
  60. machineconfig/jobs/installer/linux_scripts/q.sh +9 -0
  61. machineconfig/jobs/installer/linux_scripts/redis.sh +6 -17
  62. machineconfig/jobs/installer/linux_scripts/vscode.sh +5 -17
  63. machineconfig/jobs/installer/linux_scripts/wezterm.sh +4 -12
  64. machineconfig/jobs/installer/package_groups.py +255 -0
  65. machineconfig/logger.py +0 -1
  66. machineconfig/profile/backup.toml +49 -0
  67. machineconfig/profile/bash_shell_profiles.md +11 -0
  68. machineconfig/profile/create_helper.py +74 -0
  69. machineconfig/profile/create_links.py +288 -0
  70. machineconfig/profile/create_links_export.py +100 -0
  71. machineconfig/profile/create_shell_profile.py +136 -0
  72. machineconfig/profile/mapper.toml +258 -0
  73. machineconfig/scripts/Restore-ThunderbirdProfile.ps1 +92 -0
  74. machineconfig/scripts/__init__.py +0 -4
  75. machineconfig/scripts/linux/{share_cloud.sh → other/share_cloud.sh} +14 -25
  76. machineconfig/scripts/linux/wrap_mcfg +47 -0
  77. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  78. machineconfig/scripts/python/agents.py +198 -0
  79. machineconfig/scripts/python/ai/command_runner/command_runner.sh +9 -0
  80. machineconfig/scripts/python/ai/command_runner/prompt.txt +9 -0
  81. machineconfig/scripts/python/ai/generate_files.py +307 -42
  82. machineconfig/scripts/python/ai/initai.py +3 -28
  83. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +17 -18
  84. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +17 -18
  85. machineconfig/scripts/python/ai/solutions/_shared.py +9 -1
  86. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +1 -1
  87. machineconfig/scripts/python/ai/solutions/copilot/prompts/pyright_fix.md +16 -0
  88. machineconfig/scripts/python/ai/solutions/generic.py +27 -4
  89. machineconfig/scripts/python/ai/vscode_tasks.py +37 -0
  90. machineconfig/scripts/python/cloud.py +29 -0
  91. machineconfig/scripts/python/croshell.py +117 -181
  92. machineconfig/scripts/python/define.py +31 -0
  93. machineconfig/scripts/python/devops.py +44 -124
  94. machineconfig/scripts/python/devops_navigator.py +10 -0
  95. machineconfig/scripts/python/env_manager/__init__.py +1 -0
  96. machineconfig/scripts/python/env_manager/path_manager_backend.py +47 -0
  97. machineconfig/scripts/python/env_manager/path_manager_tui.py +228 -0
  98. machineconfig/scripts/python/explore.py +49 -0
  99. machineconfig/scripts/python/fire_jobs.py +106 -244
  100. machineconfig/scripts/python/ftpx.py +125 -68
  101. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.json +14 -0
  102. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +37 -0
  103. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_cursor_agents.py +22 -0
  104. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +42 -0
  105. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  106. machineconfig/scripts/python/helpers_agents/fire_agents_help_launch.py +110 -0
  107. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +34 -0
  108. machineconfig/scripts/python/helpers_agents/fire_agents_load_balancer.py +22 -0
  109. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +6 -0
  110. machineconfig/scripts/python/helpers_agents/templates/template.ps1 +14 -0
  111. machineconfig/scripts/python/helpers_agents/templates/template.sh +24 -0
  112. machineconfig/scripts/python/{cloud_copy.py → helpers_cloud/cloud_copy.py} +30 -23
  113. machineconfig/scripts/python/{cloud_mount.py → helpers_cloud/cloud_mount.py} +11 -19
  114. machineconfig/scripts/python/{cloud_sync.py → helpers_cloud/cloud_sync.py} +12 -18
  115. machineconfig/scripts/python/{helpers → helpers_cloud}/helpers2.py +3 -3
  116. machineconfig/scripts/python/helpers_croshell/crosh.py +39 -0
  117. machineconfig/scripts/python/{start_slidev.py → helpers_croshell/start_slidev.py} +17 -7
  118. machineconfig/scripts/python/helpers_devops/cli_config.py +95 -0
  119. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +89 -0
  120. machineconfig/scripts/python/helpers_devops/cli_data.py +25 -0
  121. machineconfig/scripts/python/helpers_devops/cli_nw.py +134 -0
  122. machineconfig/scripts/python/helpers_devops/cli_repos.py +182 -0
  123. machineconfig/scripts/python/helpers_devops/cli_self.py +134 -0
  124. machineconfig/scripts/python/helpers_devops/cli_share_file.py +137 -0
  125. machineconfig/scripts/python/helpers_devops/cli_share_server.py +141 -0
  126. machineconfig/scripts/python/helpers_devops/cli_terminal.py +156 -0
  127. machineconfig/scripts/python/helpers_devops/cli_utils.py +96 -0
  128. machineconfig/scripts/python/{devops_backup_retrieve.py → helpers_devops/devops_backup_retrieve.py} +7 -10
  129. machineconfig/scripts/python/helpers_devops/devops_status.py +511 -0
  130. machineconfig/scripts/python/helpers_devops/devops_update_repos.py +269 -0
  131. machineconfig/scripts/python/helpers_devops/themes/choose_pwsh_theme.ps1 +81 -0
  132. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +3 -0
  133. machineconfig/scripts/python/{choose_wezterm_theme.py → helpers_devops/themes/choose_wezterm_theme.py} +2 -2
  134. machineconfig/scripts/python/helpers_fire_command/__init__.py +0 -0
  135. machineconfig/scripts/python/{helpers/helpers4.py → helpers_fire_command/file_wrangler.py} +57 -87
  136. machineconfig/scripts/python/helpers_fire_command/fire_jobs_args_helper.py +145 -0
  137. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +110 -0
  138. machineconfig/scripts/python/helpers_fire_command/fire_jobs_streamlit_helper.py +0 -0
  139. machineconfig/scripts/python/helpers_msearch/__init__.py +5 -0
  140. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfag +1 -1
  141. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfg +1 -1
  142. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfrga +1 -1
  143. machineconfig/scripts/python/helpers_navigator/__init__.py +20 -0
  144. machineconfig/scripts/python/helpers_navigator/command_builder.py +111 -0
  145. machineconfig/scripts/python/helpers_navigator/command_detail.py +44 -0
  146. machineconfig/scripts/python/helpers_navigator/command_tree.py +588 -0
  147. machineconfig/scripts/python/helpers_navigator/data_models.py +28 -0
  148. machineconfig/scripts/python/helpers_navigator/main_app.py +272 -0
  149. machineconfig/scripts/python/helpers_navigator/search_bar.py +15 -0
  150. machineconfig/scripts/python/helpers_repos/action.py +209 -0
  151. machineconfig/scripts/python/helpers_repos/action_helper.py +150 -0
  152. machineconfig/scripts/python/{repos_helper_clone.py → helpers_repos/clone.py} +6 -7
  153. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +218 -0
  154. machineconfig/scripts/python/helpers_repos/count_lines.py +348 -0
  155. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +17 -0
  156. machineconfig/scripts/python/helpers_repos/entrypoint.py +77 -0
  157. machineconfig/scripts/python/helpers_repos/grource.py +340 -0
  158. machineconfig/scripts/python/{repos_helper_record.py → helpers_repos/record.py} +7 -4
  159. machineconfig/scripts/python/helpers_repos/sync.py +66 -0
  160. machineconfig/scripts/python/{repos_helper_update.py → helpers_repos/update.py} +3 -3
  161. machineconfig/scripts/python/helpers_sessions/__init__.py +0 -0
  162. machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +58 -0
  163. machineconfig/scripts/python/helpers_utils/download.py +152 -0
  164. machineconfig/scripts/python/helpers_utils/path.py +108 -0
  165. machineconfig/scripts/python/interactive.py +79 -160
  166. machineconfig/scripts/python/machineconfig.py +63 -0
  167. machineconfig/scripts/python/msearch.py +21 -0
  168. machineconfig/scripts/python/nw/__init__.py +0 -0
  169. machineconfig/scripts/python/{devops_add_identity.py → nw/devops_add_identity.py} +1 -3
  170. machineconfig/scripts/python/{devops_add_ssh_key.py → nw/devops_add_ssh_key.py} +74 -44
  171. machineconfig/scripts/{linux → python/nw}/mount_nfs +1 -1
  172. machineconfig/scripts/python/{mount_nfs.py → nw/mount_nfs.py} +19 -16
  173. machineconfig/scripts/{linux → python/nw}/mount_nw_drive +1 -2
  174. machineconfig/scripts/python/{mount_ssh.py → nw/mount_ssh.py} +7 -8
  175. machineconfig/scripts/python/{onetimeshare.py → nw/onetimeshare.py} +0 -1
  176. machineconfig/scripts/python/nw/ssh_debug_linux.py +391 -0
  177. machineconfig/scripts/python/nw/ssh_debug_windows.py +338 -0
  178. machineconfig/scripts/python/{wifi_conn.py → nw/wifi_conn.py} +1 -53
  179. machineconfig/scripts/python/{wsl_windows_transfer.py → nw/wsl_windows_transfer.py} +6 -5
  180. machineconfig/scripts/python/sessions.py +167 -0
  181. machineconfig/scripts/python/terminal.py +127 -0
  182. machineconfig/scripts/python/utils.py +66 -0
  183. machineconfig/scripts/windows/{mount_nfs.ps1 → mounts/mount_nfs.ps1} +1 -3
  184. machineconfig/scripts/windows/{mount_ssh.ps1 → mounts/mount_ssh.ps1} +1 -1
  185. machineconfig/scripts/windows/{share_smb.ps1 → mounts/share_smb.ps1} +0 -6
  186. machineconfig/scripts/windows/wrap_mcfg.ps1 +60 -0
  187. machineconfig/settings/broot/br.sh +0 -4
  188. machineconfig/settings/broot/conf.toml +1 -1
  189. machineconfig/settings/helix/config.toml +16 -0
  190. machineconfig/settings/helix/languages.toml +13 -4
  191. machineconfig/settings/helix/yazi-picker.sh +12 -0
  192. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  193. machineconfig/settings/lf/linux/exe/previewer.sh +9 -3
  194. machineconfig/settings/lf/linux/lfrc +10 -12
  195. machineconfig/settings/lf/windows/fzf_edit.ps1 +2 -2
  196. machineconfig/settings/lf/windows/lfrc +18 -38
  197. machineconfig/settings/lf/windows/mkfile.ps1 +1 -1
  198. machineconfig/settings/linters/.ruff.toml +1 -1
  199. machineconfig/settings/lvim/windows/archive/config_additional.lua +0 -6
  200. machineconfig/settings/marimo/marimo.toml +80 -0
  201. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  202. machineconfig/settings/pistol/pistol.conf +1 -1
  203. machineconfig/settings/shells/bash/init.sh +55 -31
  204. machineconfig/settings/shells/nushell/config.nu +1 -34
  205. machineconfig/settings/shells/nushell/init.nu +127 -0
  206. machineconfig/settings/shells/pwsh/init.ps1 +60 -43
  207. machineconfig/settings/shells/starship/starship.toml +16 -0
  208. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  209. machineconfig/settings/shells/wt/settings.json +32 -17
  210. machineconfig/settings/shells/zsh/init.sh +89 -0
  211. machineconfig/settings/svim/linux/init.toml +0 -4
  212. machineconfig/settings/svim/windows/init.toml +0 -3
  213. machineconfig/settings/yazi/init.lua +57 -0
  214. machineconfig/settings/yazi/keymap_linux.toml +79 -0
  215. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  216. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  217. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  218. machineconfig/settings/yazi/yazi.toml +13 -0
  219. machineconfig/setup_linux/__init__.py +10 -0
  220. machineconfig/setup_linux/apps_desktop.sh +89 -0
  221. machineconfig/setup_linux/apps_gui.sh +64 -0
  222. machineconfig/setup_linux/{nix → others}/cli_installation.sh +9 -29
  223. machineconfig/setup_linux/ssh/openssh_all.sh +25 -0
  224. machineconfig/setup_linux/ssh/openssh_wsl.sh +38 -0
  225. machineconfig/setup_linux/uv.sh +15 -0
  226. machineconfig/setup_linux/web_shortcuts/interactive.sh +26 -6
  227. machineconfig/setup_mac/__init__.py +16 -0
  228. machineconfig/setup_mac/apps_gui.sh +248 -0
  229. machineconfig/setup_mac/ssh/openssh_setup.sh +114 -0
  230. machineconfig/setup_mac/uv.sh +36 -0
  231. machineconfig/setup_windows/__init__.py +8 -0
  232. machineconfig/setup_windows/others/power_options.ps1 +7 -0
  233. machineconfig/setup_windows/ssh/add-sshkey.ps1 +29 -0
  234. machineconfig/setup_windows/ssh/add_identity.ps1 +11 -0
  235. machineconfig/setup_windows/ssh/openssh-server.ps1 +37 -0
  236. machineconfig/setup_windows/uv.ps1 +10 -0
  237. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +27 -9
  238. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +16 -0
  239. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +37 -23
  240. machineconfig/utils/accessories.py +7 -5
  241. machineconfig/utils/cloud/onedrive/README.md +139 -0
  242. machineconfig/utils/code.py +140 -93
  243. machineconfig/utils/files/art/fat_croco.txt +10 -0
  244. machineconfig/utils/files/art/halfwit_croco.txt +9 -0
  245. machineconfig/utils/files/art/happy_croco.txt +22 -0
  246. machineconfig/utils/files/art/water_croco.txt +11 -0
  247. machineconfig/utils/files/ascii_art.py +118 -0
  248. machineconfig/utils/files/dbms.py +257 -0
  249. machineconfig/utils/files/headers.py +68 -0
  250. machineconfig/utils/files/ouch/__init__.py +0 -0
  251. machineconfig/utils/files/ouch/decompress.py +45 -0
  252. machineconfig/utils/files/read.py +95 -0
  253. machineconfig/utils/installer_utils/github_release_bulk.py +2 -12
  254. machineconfig/utils/installer_utils/installer_class.py +68 -126
  255. machineconfig/utils/installer_utils/installer_cli.py +181 -0
  256. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +38 -85
  257. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +69 -69
  258. machineconfig/utils/io.py +77 -23
  259. machineconfig/utils/links.py +309 -100
  260. machineconfig/utils/meta.py +255 -0
  261. machineconfig/utils/notifications.py +1 -1
  262. machineconfig/utils/options.py +10 -25
  263. machineconfig/utils/path_extended.py +94 -104
  264. machineconfig/utils/path_helper.py +75 -22
  265. machineconfig/utils/procs.py +50 -74
  266. machineconfig/utils/scheduler.py +94 -97
  267. machineconfig/utils/scheduling.py +0 -3
  268. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +5 -17
  269. machineconfig/utils/schemas/installer/installer_types.py +0 -1
  270. machineconfig/utils/schemas/layouts/layout_types.py +2 -1
  271. machineconfig/utils/source_of_truth.py +3 -6
  272. machineconfig/utils/ssh.py +742 -254
  273. machineconfig/utils/ssh_utils/utils.py +0 -0
  274. machineconfig/utils/terminal.py +3 -140
  275. machineconfig/utils/tst.py +20 -0
  276. machineconfig/utils/upgrade_packages.py +109 -28
  277. machineconfig/utils/ve.py +13 -5
  278. machineconfig-7.66.dist-info/METADATA +124 -0
  279. machineconfig-7.66.dist-info/RECORD +451 -0
  280. machineconfig-7.66.dist-info/entry_points.txt +15 -0
  281. machineconfig/cluster/templates/utils.py +0 -51
  282. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -49
  283. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -85
  284. machineconfig/jobs/installer/packages_custom_dev.json +0 -226
  285. machineconfig/jobs/installer/packages_custom_essential.json +0 -39
  286. machineconfig/jobs/installer/packages_github_dev.json +0 -1110
  287. machineconfig/jobs/installer/packages_github_essential.json +0 -804
  288. machineconfig/jobs/linux/msc/cli_agents.sh +0 -37
  289. machineconfig/jobs/python/create_bootable_media.py +0 -16
  290. machineconfig/jobs/python/python_cargo_build_share.py +0 -59
  291. machineconfig/jobs/python/python_ve_symlink.py +0 -29
  292. machineconfig/jobs/python/tasks.py +0 -3
  293. machineconfig/jobs/python/vscode/api.py +0 -49
  294. machineconfig/jobs/python/vscode/sync_code.py +0 -58
  295. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +0 -14
  296. machineconfig/jobs/windows/start_terminal.ps1 +0 -6
  297. machineconfig/jobs/windows/startup_file.cmd +0 -2
  298. machineconfig/profile/create.py +0 -170
  299. machineconfig/profile/shell.py +0 -176
  300. machineconfig/scripts/cloud/init.sh +0 -119
  301. machineconfig/scripts/linux/choose_wezterm_theme +0 -3
  302. machineconfig/scripts/linux/cloud_copy +0 -2
  303. machineconfig/scripts/linux/cloud_mount +0 -2
  304. machineconfig/scripts/linux/cloud_repo_sync +0 -2
  305. machineconfig/scripts/linux/cloud_sync +0 -2
  306. machineconfig/scripts/linux/croshell +0 -3
  307. machineconfig/scripts/linux/devops +0 -2
  308. machineconfig/scripts/linux/fire +0 -2
  309. machineconfig/scripts/linux/fire_agents +0 -2
  310. machineconfig/scripts/linux/ftpx +0 -2
  311. machineconfig/scripts/linux/fzf2g +0 -21
  312. machineconfig/scripts/linux/fzffg +0 -25
  313. machineconfig/scripts/linux/gh_models +0 -2
  314. machineconfig/scripts/linux/initai +0 -2
  315. machineconfig/scripts/linux/kill_process +0 -2
  316. machineconfig/scripts/linux/programs +0 -21
  317. machineconfig/scripts/linux/repos +0 -2
  318. machineconfig/scripts/linux/scheduler +0 -2
  319. machineconfig/scripts/linux/share_smb +0 -1
  320. machineconfig/scripts/linux/start_slidev +0 -2
  321. machineconfig/scripts/linux/start_terminals +0 -3
  322. machineconfig/scripts/linux/warp-cli.sh +0 -122
  323. machineconfig/scripts/linux/wifi_conn +0 -2
  324. machineconfig/scripts/linux/z_ls +0 -104
  325. machineconfig/scripts/python/ai/solutions/copilot/prompts/allLintersAndTypeCheckers.prompt.md +0 -5
  326. machineconfig/scripts/python/cloud_repo_sync.py +0 -186
  327. machineconfig/scripts/python/devops_devapps_install.py +0 -159
  328. machineconfig/scripts/python/devops_update_repos.py +0 -180
  329. machineconfig/scripts/python/dotfile.py +0 -52
  330. machineconfig/scripts/python/fire_agents.py +0 -175
  331. machineconfig/scripts/python/fire_agents_help_launch.py +0 -143
  332. machineconfig/scripts/python/fire_agents_load_balancer.py +0 -50
  333. machineconfig/scripts/python/fire_jobs_args_helper.py +0 -75
  334. machineconfig/scripts/python/fire_jobs_layout_helper.py +0 -74
  335. machineconfig/scripts/python/get_zellij_cmd.py +0 -15
  336. machineconfig/scripts/python/gh_models.py +0 -104
  337. machineconfig/scripts/python/helpers/repo_sync_helpers.py +0 -114
  338. machineconfig/scripts/python/repos.py +0 -80
  339. machineconfig/scripts/python/repos_helper_action.py +0 -335
  340. machineconfig/scripts/python/share_terminal.py +0 -104
  341. machineconfig/scripts/python/snapshot.py +0 -25
  342. machineconfig/scripts/python/start_terminals.py +0 -121
  343. machineconfig/scripts/python/t4.py +0 -17
  344. machineconfig/scripts/windows/choose_wezterm_theme.ps1 +0 -1
  345. machineconfig/scripts/windows/cloud_copy.ps1 +0 -1
  346. machineconfig/scripts/windows/cloud_mount.ps1 +0 -1
  347. machineconfig/scripts/windows/cloud_repo_sync.ps1 +0 -1
  348. machineconfig/scripts/windows/cloud_sync.ps1 +0 -1
  349. machineconfig/scripts/windows/croshell.ps1 +0 -1
  350. machineconfig/scripts/windows/devops.ps1 +0 -1
  351. machineconfig/scripts/windows/dotfile.ps1 +0 -1
  352. machineconfig/scripts/windows/fire.ps1 +0 -1
  353. machineconfig/scripts/windows/ftpx.ps1 +0 -1
  354. machineconfig/scripts/windows/gpt.ps1 +0 -1
  355. machineconfig/scripts/windows/grep.ps1 +0 -2
  356. machineconfig/scripts/windows/initai.ps1 +0 -1
  357. machineconfig/scripts/windows/kill_process.ps1 +0 -1
  358. machineconfig/scripts/windows/nano.ps1 +0 -3
  359. machineconfig/scripts/windows/pomodoro.ps1 +0 -1
  360. machineconfig/scripts/windows/reload_path.ps1 +0 -3
  361. machineconfig/scripts/windows/repos.ps1 +0 -1
  362. machineconfig/scripts/windows/scheduler.ps1 +0 -1
  363. machineconfig/scripts/windows/snapshot.ps1 +0 -1
  364. machineconfig/scripts/windows/start_slidev.ps1 +0 -1
  365. machineconfig/scripts/windows/start_terminals.ps1 +0 -1
  366. machineconfig/scripts/windows/wifi_conn.ps1 +0 -2
  367. machineconfig/scripts/windows/wsl_rdp_windows_port_forwarding.ps1 +0 -46
  368. machineconfig/scripts/windows/wsl_ssh_windows_port_forwarding.ps1 +0 -76
  369. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  370. machineconfig/setup_linux/others/openssh-server_add_pub_key.sh +0 -57
  371. machineconfig/setup_linux/web_shortcuts/ascii_art.sh +0 -93
  372. machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -11
  373. machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -52
  374. machineconfig/setup_windows/web_shortcuts/all.ps1 +0 -18
  375. machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +0 -36
  376. machineconfig/setup_windows/web_shortcuts/croshell.ps1 +0 -16
  377. machineconfig/setup_windows/web_shortcuts/ssh.ps1 +0 -11
  378. machineconfig/utils/ai/generate_file_checklist.py +0 -68
  379. machineconfig-3.99.dist-info/METADATA +0 -167
  380. machineconfig-3.99.dist-info/RECORD +0 -409
  381. machineconfig-3.99.dist-info/entry_points.txt +0 -18
  382. machineconfig/cluster/{templates → remote}/run_cloud.py +0 -0
  383. machineconfig/cluster/{templates → remote}/run_cluster.py +0 -0
  384. machineconfig/cluster/{templates → remote}/run_remote.py +0 -0
  385. machineconfig/scripts/linux/{share_nfs → other/share_nfs} +0 -0
  386. machineconfig/scripts/linux/{start_docker → other/start_docker} +0 -0
  387. machineconfig/scripts/linux/{switch_ip → other/switch_ip} +0 -0
  388. machineconfig/{jobs/python → scripts/python/helpers_agents}/__init__.py +0 -0
  389. machineconfig/scripts/python/{helpers → helpers_agents/agentic_frameworks}/__init__.py +0 -0
  390. machineconfig/scripts/python/{fire_agents_help_search.py → helpers_agents/fire_agents_help_search.py} +0 -0
  391. machineconfig/{jobs/windows/msc/cli_agents.bat → scripts/python/helpers_cloud/__init__.py} +0 -0
  392. machineconfig/scripts/python/{helpers → helpers_cloud}/cloud_helpers.py +1 -1
  393. /machineconfig/scripts/python/{helpers → helpers_cloud}/helpers5.py +0 -0
  394. /machineconfig/{jobs/windows/msc/cli_agents.ps1 → scripts/python/helpers_croshell/__init__.py} +0 -0
  395. /machineconfig/scripts/python/{pomodoro.py → helpers_croshell/pomodoro.py} +0 -0
  396. /machineconfig/scripts/python/{scheduler.py → helpers_croshell/scheduler.py} +0 -0
  397. /machineconfig/scripts/python/{viewer.py → helpers_croshell/viewer.py} +0 -0
  398. /machineconfig/scripts/python/{viewer_template.py → helpers_croshell/viewer_template.py} +0 -0
  399. /machineconfig/scripts/python/{fire_jobs_streamlit_helper.py → helpers_devops/__init__.py} +0 -0
  400. /machineconfig/scripts/{windows/share_nfs.ps1 → python/helpers_devops/themes/__init__.py} +0 -0
  401. /machineconfig/{settings/yazi/keymap.toml → scripts/python/helpers_devops/themes/choose_starship_theme.ps1} +0 -0
  402. /machineconfig/scripts/python/{cloud_manager.py → helpers_fire_command/cloud_manager.py} +0 -0
  403. /machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/skrg +0 -0
  404. /machineconfig/scripts/{windows → python/helpers_msearch/scripts_windows}/fzfb.ps1 +0 -0
  405. /machineconfig/scripts/{windows → python/helpers_msearch/scripts_windows}/fzfg.ps1 +0 -0
  406. /machineconfig/scripts/{windows → python/helpers_msearch/scripts_windows}/fzfrga.bat +0 -0
  407. /machineconfig/scripts/{linux → python/nw}/mount_drive +0 -0
  408. /machineconfig/scripts/python/{mount_nw_drive.py → nw/mount_nw_drive.py} +0 -0
  409. /machineconfig/scripts/{linux → python/nw}/mount_smb +0 -0
  410. /machineconfig/scripts/windows/{mount_nw.ps1 → mounts/mount_nw.ps1} +0 -0
  411. /machineconfig/scripts/windows/{mount_smb.ps1 → mounts/mount_smb.ps1} +0 -0
  412. /machineconfig/scripts/windows/{share_cloud.cmd → mounts/share_cloud.cmd} +0 -0
  413. /machineconfig/scripts/windows/{unlock_bitlocker.ps1 → mounts/unlock_bitlocker.ps1} +0 -0
  414. /machineconfig/setup_linux/{web_shortcuts → others}/android.sh +0 -0
  415. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_add_key.ps1 +0 -0
  416. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_copy-ssh-id.ps1 +0 -0
  417. {machineconfig-3.99.dist-info → machineconfig-7.66.dist-info}/WHEEL +0 -0
  418. {machineconfig-3.99.dist-info → machineconfig-7.66.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,65 @@
1
- from machineconfig.utils.path_extended import PathExtended as PathExtended, PLike
1
+ from machineconfig.utils.path_extended import PathExtended, PLike
2
+ from machineconfig.profile.create_links_export import ON_CONFLICT_STRICT
2
3
  from machineconfig.utils.accessories import randstr
3
4
  from rich.console import Console
4
5
  from rich.panel import Panel
5
-
6
+ import hashlib
7
+ from typing import TypedDict, Literal
6
8
 
7
9
  console = Console()
8
10
 
9
11
 
12
+ ActionType = Literal[
13
+ "already_linked",
14
+ "relinking",
15
+ "fixing_broken_link",
16
+ "identical_files",
17
+ "backupConfigDefaultPath",
18
+ "backing_up_source",
19
+ "backing_up_target",
20
+ "relink2newSelfManagedPath",
21
+ "relinking_to_new_target",
22
+ "move2selfManagedPath",
23
+ "moving_to_target",
24
+ "new_link",
25
+ "newLinkAndSelfManagedPath",
26
+ "new_link_and_target",
27
+ "linking",
28
+ "copying",
29
+ "error"
30
+ ]
31
+
32
+
33
+ class OperationResult(TypedDict):
34
+ action: ActionType
35
+ details: str
36
+
37
+ class OperationRecord(TypedDict):
38
+ action: ActionType
39
+ details: str
40
+ program: str
41
+ file_key: str
42
+ defaultPath: str
43
+ selfManaged: str
44
+ operation: str
45
+ status: str
46
+
47
+
48
+ def files_are_identical(file1: PathExtended, file2: PathExtended) -> bool:
49
+ """Check if two files are identical by comparing their SHA256 hashes."""
50
+ def get_file_hash(path: PathExtended) -> str:
51
+ hash_sha256 = hashlib.sha256()
52
+ with open(path, "rb") as f:
53
+ for chunk in iter(lambda: f.read(4096), b""):
54
+ hash_sha256.update(chunk)
55
+ return hash_sha256.hexdigest()
56
+
57
+ try:
58
+ return get_file_hash(file1) == get_file_hash(file2)
59
+ except (OSError, IOError):
60
+ return False
61
+
62
+
10
63
  def build_links(target_paths: list[tuple[PLike, str]], repo_root: PLike):
11
64
  """Build symboic links from various relevant paths (e.g. data) to `repo_root/links/<name>` to facilitate easy access from
12
65
  tree explorer of the IDE.
@@ -28,134 +81,290 @@ def build_links(target_paths: list[tuple[PLike, str]], repo_root: PLike):
28
81
  tmp_results_root.mkdir(parents=True, exist_ok=True)
29
82
  target_dirs_filtered.append((tmp_results_root, "tmp_results"))
30
83
 
84
+ links_dir = repo_root_obj.joinpath("links")
85
+ links_dir.mkdir(parents=True, exist_ok=True)
86
+
31
87
  for a_target_path, a_name in target_dirs_filtered:
32
- links_path = repo_root_obj.joinpath("links", a_name)
33
- links_path.symlink_to(target=a_target_path)
88
+ links_path = links_dir.joinpath(a_name)
89
+ if links_path.exists() or links_path.is_symlink():
90
+ if links_path.is_symlink() and links_path.resolve() == a_target_path.resolve():
91
+ continue
92
+ links_path.unlink(missing_ok=True)
93
+ try:
94
+ links_path.symlink_to(target=a_target_path)
95
+ except OSError as ex:
96
+ console.print(Panel(f"❌ Failed to create symlink {links_path} -> {a_target_path}: {ex}", title="Symlink Error", expand=False))
34
97
 
35
98
 
36
- def symlink_func(this: PathExtended, to_this: PathExtended, prioritize_to_this: bool):
37
- """helper function. creates a symlink from `this` to `to_this`.
99
+ def symlink_map(config_file_default_path: PathExtended, self_managed_config_file_path: PathExtended,
100
+ on_conflict: ON_CONFLICT_STRICT
101
+ ) -> OperationResult:
102
+ """helper function. creates a symlink from `config_file_default_path` to `self_managed_config_file_path`.
38
103
 
39
- this: exists AND to_this exists AND this is a symlink pointing to to_this ===> Resolution: AUTO: do nothing, already linked correctly.
40
- this: exists AND to_this exists AND this is a symlink pointing to somewhere else ===> Resolution: AUTO: delete this symlink, create symlink to to_this
41
- this: exists AND to_this exists AND this is a concrete path ===> Resolution: DANGER: require user input to decide (param prioritize_to_this). Give two options: 1) prioritize `this`: to_this is backed up as to_this.orig_<randstr()>, to_this is deleted, and symlink is created from this to to_this as normal; 2) prioritize `to_this`: `this` is backed up as this.orig_<randstr()>, `this` is deleted, and symlink is created from this to to_this as normal.
104
+ Returns a dict with 'action' and 'details' keys describing what was done.
42
105
 
43
- this: exists AND to_this doesn't exist AND this is a symlink pointing to somewhere else ===> Resolution: AUTO: delete this symlink, create symlink to to_this (touch to_this)
44
- this: exists AND to_this doesn't exist AND this is a symlink pointing to to_this ===> Resolution: AUTO: delete this symlink, create symlink to to_this (touch to_this)
45
- this: exists AND to_this doesn't exist AND this is a concrete path ===> Resolution: AUTO: move this to to_this, then create symlink from this to to_this.
106
+ on_conflict strategies:
107
+ - throw-error: Raise exception when files differ
108
+ - overwrite-self-managed: Delete self_managed_config_file_path (self-managed), move config_file_default_path to self_managed_config_file_path, create symlink
109
+ - backup-self-managed: Backup self_managed_config_file_path (self-managed), move config_file_default_path to self_managed_config_file_path, create symlink
110
+ - overwrite-default-path: Delete config_file_default_path (default path), create symlink to self_managed_config_file_path
111
+ - backup-default-path: Backup config_file_default_path (default path), create symlink to self_managed_config_file_path
46
112
 
47
- this: doesn't exist AND to_this exists ===> Resolution: AUTO: create link from this to to_this
48
- this: doesn't exist AND to_this doesn't exist ===> Resolution: AUTO: create link from this to to_this (touch to_this)
113
+ Note: `config_file_default_path` is the default system location, `self_managed_config_file_path` is the self-managed config location
49
114
 
50
115
  """
51
- this = PathExtended(this).expanduser().absolute()
52
- to_this = PathExtended(to_this).expanduser().absolute()
116
+ config_file_default_path = PathExtended(config_file_default_path).expanduser().absolute()
117
+ self_managed_config_file_path = PathExtended(self_managed_config_file_path).expanduser().absolute()
118
+
119
+ if config_file_default_path.resolve() == self_managed_config_file_path.resolve():
120
+ raise ValueError(f"config_file_default_path and self_managed_config_file_path resolve to the same location: {config_file_default_path.resolve()}")
121
+
122
+ action_taken = ""
123
+ details = ""
124
+
125
+ # Handle broken symlinks first - they exist as symlinks but point to non-existent targets
126
+ if config_file_default_path.is_symlink() and not config_file_default_path.exists():
127
+ action_taken = "fixing_broken_link"
128
+ details = "Removed broken symlink and will create new one"
129
+ console.print(Panel(f"🔄 FIXING BROKEN LINK | Removing broken symlink {config_file_default_path}, will create link to {self_managed_config_file_path}", title="Fixing Broken Link", expand=False))
130
+ config_file_default_path.unlink()
131
+
53
132
  # Case analysis based on docstring
54
- if this.exists():
55
- if to_this.exists():
56
- if this.is_symlink():
133
+ if config_file_default_path.exists():
134
+ if self_managed_config_file_path.exists():
135
+ if config_file_default_path.is_symlink():
57
136
  # Check if symlink already points to correct target
58
137
  try:
59
- if this.readlink().resolve() == to_this.resolve():
60
- # Case: this exists AND to_this exists AND this is a symlink pointing to to_this
61
- console.print(Panel(f"✅ ALREADY LINKED | {this} ➡️ {to_this}", title="Already Linked", expand=False))
62
- return
138
+ if config_file_default_path.resolve() == self_managed_config_file_path.resolve():
139
+ # Case: config_file_default_path exists AND self_managed_config_file_path exists AND config_file_default_path is a symlink pointing to self_managed_config_file_path
140
+ action_taken = "already_linked"
141
+ details = "Symlink already correctly points to target"
142
+ console.print(Panel(f"✅ ALREADY LINKED | {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Already Linked", expand=False))
143
+ return {"action": action_taken, "details": details}
63
144
  else:
64
- # Case: this exists AND to_this exists AND this is a symlink pointing to somewhere else
65
- console.print(Panel(f"🔄 RELINKING | Updating symlink from {this} ➡️ {to_this}", title="Relinking", expand=False))
66
- this.delete(sure=True)
145
+ # Case: config_file_default_path exists AND self_managed_config_file_path exists AND config_file_default_path is a symlink pointing to somewhere else
146
+ action_taken = "relinking"
147
+ details = "Updated existing symlink to point to new target"
148
+ console.print(Panel(f"🔄 RELINKING | Updating symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Relinking", expand=False))
149
+ config_file_default_path.delete(sure=True)
67
150
  except OSError:
68
151
  # Broken symlink case
69
- console.print(Panel(f"🔄 FIXING BROKEN LINK | Fixing broken symlink from {this} ➡️ {to_this}", title="Fixing Broken Link", expand=False))
70
- this.delete(sure=True)
152
+ action_taken = "fixing_broken_link"
153
+ details = "Removed broken symlink and will create new one"
154
+ console.print(Panel(f"🔄 FIXING BROKEN LINK | Fixing broken symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Fixing Broken Link", expand=False))
155
+ config_file_default_path.delete(sure=True)
71
156
  else:
72
- # Case: this exists AND to_this exists AND this is a concrete path
73
- if prioritize_to_this:
74
- # prioritize `to_this`: `this` is backed up, `this` is deleted, symlink created
75
- backup_name = f"{this}.orig_{randstr()}"
76
- console.print(Panel(f"📦 BACKING UP | Moving {this} to {backup_name}, prioritizing {to_this}", title="Backing Up", expand=False))
77
- this.move(path=backup_name)
157
+ # Case: config_file_default_path exists AND self_managed_config_file_path exists AND config_file_default_path is a concrete path
158
+ if files_are_identical(config_file_default_path, self_managed_config_file_path):
159
+ # Files are identical, just delete this and create symlink
160
+ action_taken = "identical_files"
161
+ details = "Files identical, removed config_file_default_path and will create symlink"
162
+ console.print(Panel(f"🔗 IDENTICAL FILES | Files are identical, deleting {config_file_default_path} and creating symlink to {self_managed_config_file_path}", title="Identical Files", expand=False))
163
+ config_file_default_path.delete(sure=True)
78
164
  else:
79
- # prioritize `this`: to_this is backed up, to_this is deleted, this content moved to to_this location
80
- backup_name = f"{to_this}.orig_{randstr()}"
81
- console.print(Panel(f"📦 BACKING UP | Moving {to_this} to {backup_name}, prioritizing {this}", title="Backing Up", expand=False))
82
- to_this.move(path=backup_name)
83
- this.move(path=to_this)
165
+ # Files are different, use on_conflict strategy
166
+ import subprocess
167
+ command = f"""delta --side-by-side "{config_file_default_path}" "{self_managed_config_file_path}" """
168
+ try:
169
+ console.print(Panel(f"🆘 CONFLICT DETECTED | Showing diff between {config_file_default_path} and {self_managed_config_file_path}", title="Conflict Detected", expand=False))
170
+ subprocess.run(command, shell=True, check=True)
171
+ except Exception:
172
+ console.print(Panel("⚠️ Could not show diff using 'delta'. Please install 'delta' for better diff visualization.", title="Delta Not Found", expand=False))
173
+
174
+ match on_conflict:
175
+ case "throw-error":
176
+ raise RuntimeError(f"Conflict detected: {config_file_default_path} and {self_managed_config_file_path} both exist with different content")
177
+ case "overwrite-self-managed":
178
+ action_taken = "backing_up_target"
179
+ details = "Overwriting self-managed config, moving default path to self-managed location"
180
+ console.print(Panel(f"📦 OVERWRITE SELF-MANAGED | Deleting {self_managed_config_file_path}, moving {config_file_default_path} to {self_managed_config_file_path}", title="Overwrite Self-Managed", expand=False))
181
+ self_managed_config_file_path.delete(sure=True)
182
+ config_file_default_path.move(path=self_managed_config_file_path)
183
+ case "backup-self-managed":
184
+ backup_name = f"{self_managed_config_file_path}.orig_{randstr()}"
185
+ action_taken = "backing_up_target"
186
+ details = f"Backed up self-managed config to {backup_name}"
187
+ console.print(Panel(f"📦 BACKUP SELF-MANAGED | Moving {self_managed_config_file_path} to {backup_name}, moving {config_file_default_path} to {self_managed_config_file_path}", title="Backup Self-Managed", expand=False))
188
+ self_managed_config_file_path.move(path=backup_name)
189
+ config_file_default_path.move(path=self_managed_config_file_path)
190
+ case "overwrite-default-path":
191
+ action_taken = "backupConfigDefaultPath"
192
+ details = "Overwriting default path, creating symlink to self-managed config"
193
+ console.print(Panel(f"📦 OVERWRITE DEFAULT | Deleting {config_file_default_path}, creating symlink to {self_managed_config_file_path}", title="Overwrite Default", expand=False))
194
+ config_file_default_path.delete(sure=True)
195
+ case "backup-default-path":
196
+ backup_name = f"{config_file_default_path}.orig_{randstr()}"
197
+ action_taken = "backupConfigDefaultPath"
198
+ details = f"Backed up default path to {backup_name}"
199
+ console.print(Panel(f"📦 BACKUP DEFAULT | Moving {config_file_default_path} to {backup_name}, creating symlink to {self_managed_config_file_path}", title="Backup Default", expand=False))
200
+ config_file_default_path.move(path=backup_name)
84
201
  else:
85
- # to_this doesn't exist
86
- if this.is_symlink():
87
- # Case: this exists AND to_this doesn't exist AND this is a symlink (pointing anywhere)
88
- console.print(Panel(f"🔄 RELINKING | Updating symlink from {this} ➡️ {to_this}", title="Relinking", expand=False))
89
- this.delete(sure=True)
90
- # Create to_this
91
- to_this.parent.mkdir(parents=True, exist_ok=True)
92
- to_this.touch()
202
+ # self_managed_config_file_path doesn't exist
203
+ if config_file_default_path.is_symlink():
204
+ # Case: config_file_default_path exists AND self_managed_config_file_path doesn't exist AND config_file_default_path is a symlink (pointing anywhere)
205
+ action_taken = "relink2newSelfManagedPath"
206
+ details = "Removed existing symlink, will create self_managed_config_file_path and new symlink"
207
+ console.print(Panel(f"🔄 RELINKING | Updating symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Relinking", expand=False))
208
+ config_file_default_path.delete(sure=True)
209
+ # Create self_managed_config_file_path
210
+ self_managed_config_file_path.parent.mkdir(parents=True, exist_ok=True)
211
+ self_managed_config_file_path.touch()
93
212
  else:
94
- # Case: this exists AND to_this doesn't exist AND this is a concrete path
95
- console.print(Panel(f"📁 MOVING | Moving {this} to {to_this}, then creating symlink", title="Moving", expand=False))
96
- this.move(path=to_this)
213
+ # Case: config_file_default_path exists AND self_managed_config_file_path doesn't exist AND config_file_default_path is a concrete path
214
+ action_taken = "move2selfManagedPath"
215
+ details = "Moved config_file_default_path to self_managed_config_file_path location, will create symlink"
216
+ console.print(Panel(f"📁 MOVING | Moving {config_file_default_path} to {self_managed_config_file_path}, then creating symlink", title="Moving", expand=False))
217
+ config_file_default_path.move(path=self_managed_config_file_path)
97
218
  else:
98
- # this doesn't exist
99
- if to_this.exists():
100
- # Case: this doesn't exist AND to_this exists
101
- console.print(Panel(f"🆕 NEW LINK | Creating new symlink from {this} ➡️ {to_this}", title="New Link", expand=False))
219
+ # config_file_default_path doesn't exist
220
+ if self_managed_config_file_path.exists():
221
+ # Case: config_file_default_path doesn't exist AND self_managed_config_file_path exists
222
+ action_taken = "new_link"
223
+ details = "Creating new symlink to existing self_managed_config_file_path"
224
+ console.print(Panel(f"🆕 NEW LINK | Creating new symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="New Link", expand=False))
102
225
  else:
103
- # Case: this doesn't exist AND to_this doesn't exist
104
- console.print(Panel(f"🆕 NEW LINK & TARGET | Creating {to_this} and symlink from {this} ➡️ {to_this}", title="New Link & Target", expand=False))
105
- to_this.parent.mkdir(parents=True, exist_ok=True)
106
- to_this.touch()
226
+ # Case: config_file_default_path doesn't exist AND self_managed_config_file_path doesn't exist
227
+ action_taken = "newLinkAndSelfManagedPath"
228
+ details = "Creating self_managed_config_file_path file and new symlink"
229
+ console.print(Panel(f"🆕 NEW LINK & TARGET | Creating {self_managed_config_file_path} and symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="New Link & Target", expand=False))
230
+ self_managed_config_file_path.parent.mkdir(parents=True, exist_ok=True)
231
+ self_managed_config_file_path.touch()
232
+
107
233
  # Create the symlink
108
234
  try:
109
- console.print(Panel(f"🔗 LINKING | Creating symlink from {this} ➡️ {to_this}", title="Linking", expand=False))
110
- PathExtended(this).symlink_to(target=to_this, verbose=True, overwrite=True)
235
+ if not action_taken:
236
+ action_taken = "linking"
237
+ details = "Creating symlink"
238
+ console.print(Panel(f"🔗 LINKING | Creating symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Linking", expand=False))
239
+ PathExtended(config_file_default_path).symlink_to(target=self_managed_config_file_path, verbose=True, overwrite=False)
240
+ return {"action": action_taken, "details": details}
111
241
  except Exception as ex:
112
- console.print(Panel(f"❌ ERROR | Failed at linking {this} ➡️ {to_this}. Reason: {ex}", title="Error", expand=False))
242
+ action_taken = "error"
243
+ details = f"Failed to create symlink: {str(ex)}"
244
+ console.print(Panel(f"❌ ERROR | Failed at linking {config_file_default_path} ➡️ {self_managed_config_file_path}. Reason: {ex}", title="Error", expand=False))
245
+ return {"action": action_taken, "details": details}
113
246
 
114
247
 
115
- def symlink_copy(this: PathExtended, to_this: PathExtended, prioritize_to_this: bool):
116
- this = PathExtended(this).expanduser().absolute()
117
- to_this = PathExtended(to_this).expanduser().absolute()
118
- if this.exists():
119
- if to_this.exists():
120
- if this.is_symlink():
248
+ def copy_map(config_file_default_path: PathExtended, self_managed_config_file_path: PathExtended, on_conflict: ON_CONFLICT_STRICT) -> OperationResult:
249
+ config_file_default_path = PathExtended(config_file_default_path).expanduser().absolute()
250
+ self_managed_config_file_path = PathExtended(self_managed_config_file_path).expanduser().absolute()
251
+
252
+ if config_file_default_path.resolve() == self_managed_config_file_path.resolve():
253
+ raise ValueError(f"config_file_default_path and self_managed_config_file_path resolve to the same location: {config_file_default_path.resolve()}")
254
+
255
+ action_taken = ""
256
+ details = ""
257
+
258
+ # Handle broken symlinks first - they exist as symlinks but point to non-existent targets
259
+ if config_file_default_path.is_symlink() and not config_file_default_path.exists():
260
+ action_taken = "fixing_broken_link"
261
+ details = "Removed broken symlink and will copy new file"
262
+ console.print(Panel(f"🔄 FIXING BROKEN LINK | Removing broken symlink {config_file_default_path}, will copy from {self_managed_config_file_path}", title="Fixing Broken Link", expand=False))
263
+ config_file_default_path.unlink()
264
+
265
+ match (config_file_default_path.exists(), self_managed_config_file_path.exists()):
266
+ case (True, True):
267
+ # Both files exist
268
+ if config_file_default_path.is_symlink():
121
269
  try:
122
- if this.readlink().resolve() == to_this.resolve():
123
- console.print(Panel(f"✅ ALREADY LINKED | {this} ➡️ {to_this}", title="Already Linked", expand=False))
124
- return
270
+ if config_file_default_path.resolve() == self_managed_config_file_path.resolve():
271
+ action_taken = "already_linked"
272
+ details = "File at default path is already a symlink to self-managed config"
273
+ console.print(Panel(f"✅ ALREADY CORRECT | {config_file_default_path} already points to {self_managed_config_file_path}", title="Already Correct", expand=False))
274
+ return {"action": action_taken, "details": details}
125
275
  else:
126
- console.print(Panel(f"🔄 RELINKING | Updating symlink from {this} ➡️ {to_this}", title="Relinking", expand=False))
127
- this.delete(sure=True)
276
+ action_taken = "relinking"
277
+ details = "Removing symlink at default path that points elsewhere"
278
+ console.print(Panel(f"🔄 REMOVING SYMLINK | Removing symlink {config_file_default_path} (points elsewhere), will copy from {self_managed_config_file_path}", title="Removing Symlink", expand=False))
279
+ config_file_default_path.delete(sure=True)
128
280
  except OSError:
129
- console.print(Panel(f"🔄 FIXING BROKEN LINK | Fixing broken symlink from {this} ➡️ {to_this}", title="Fixing Broken Link", expand=False))
130
- this.delete(sure=True)
281
+ action_taken = "fixing_broken_link"
282
+ details = "Removed broken symlink at default path"
283
+ console.print(Panel(f"🔄 FIXING BROKEN SYMLINK | Removing broken symlink {config_file_default_path}, will copy from {self_managed_config_file_path}", title="Fixing Broken Symlink", expand=False))
284
+ config_file_default_path.delete(sure=True)
131
285
  else:
132
- if prioritize_to_this:
133
- backup_name = f"{this}.orig_{randstr()}"
134
- console.print(Panel(f"📦 BACKING UP | Moving {this} to {backup_name}, prioritizing {to_this}", title="Backing Up", expand=False))
135
- this.move(path=backup_name)
286
+ # Check if files are identical first
287
+ if files_are_identical(config_file_default_path, self_managed_config_file_path):
288
+ # Files are identical, just delete this and proceed with copy
289
+ action_taken = "identical_files"
290
+ details = "Files identical, removed config_file_default_path and will copy"
291
+ console.print(Panel(f"🔗 IDENTICAL FILES | Files are identical, deleting {config_file_default_path} and copying from {self_managed_config_file_path}", title="Identical Files", expand=False))
292
+ config_file_default_path.delete(sure=True)
136
293
  else:
137
- backup_name = f"{to_this}.orig_{randstr()}"
138
- console.print(Panel(f"📦 BACKING UP | Moving {to_this} to {backup_name}, prioritizing {this}", title="Backing Up", expand=False))
139
- to_this.move(path=backup_name)
140
- this.move(path=to_this)
141
- else:
142
- if this.is_symlink():
143
- console.print(Panel(f"🔄 RELINKING | Updating symlink from {this} ➡️ {to_this}", title="Relinking", expand=False))
144
- this.delete(sure=True)
145
- to_this.parent.mkdir(parents=True, exist_ok=True)
146
- to_this.touch()
294
+ # Files are different, use on_conflict strategy
295
+ import subprocess
296
+ command = f"""delta --side-by-side "{config_file_default_path}" "{self_managed_config_file_path}" """
297
+ try:
298
+ console.print(Panel(f"🆘 CONFLICT DETECTED | Showing diff between {config_file_default_path} and {self_managed_config_file_path}", title="Conflict Detected", expand=False))
299
+ subprocess.run(command, shell=True, check=True)
300
+ except Exception:
301
+ console.print(Panel("⚠️ Could not show diff using 'delta'. Please install 'delta' for better diff visualization.", title="Delta Not Found", expand=False))
302
+
303
+ match on_conflict:
304
+ case "throw-error":
305
+ raise RuntimeError(f"Conflict detected: {config_file_default_path} and {self_managed_config_file_path} both exist with different content")
306
+ case "overwrite-self-managed":
307
+ action_taken = "backing_up_target"
308
+ details = "Overwriting self-managed config with default path content"
309
+ console.print(Panel(f"📦 OVERWRITE SELF-MANAGED | Deleting {self_managed_config_file_path}, moving {config_file_default_path} to {self_managed_config_file_path}", title="Overwrite Self-Managed", expand=False))
310
+ self_managed_config_file_path.delete(sure=True)
311
+ config_file_default_path.move(path=self_managed_config_file_path)
312
+ case "backup-self-managed":
313
+ backup_name = f"{self_managed_config_file_path}.orig_{randstr()}"
314
+ action_taken = "backing_up_target"
315
+ details = f"Backed up self-managed config to {backup_name}"
316
+ console.print(Panel(f"📦 BACKUP SELF-MANAGED | Moving {self_managed_config_file_path} to {backup_name}, moving {config_file_default_path} to {self_managed_config_file_path}", title="Backup Self-Managed", expand=False))
317
+ self_managed_config_file_path.move(path=backup_name)
318
+ config_file_default_path.move(path=self_managed_config_file_path)
319
+ case "overwrite-default-path":
320
+ action_taken = "backupConfigDefaultPath"
321
+ details = "Overwriting default path with self-managed config"
322
+ console.print(Panel(f"📦 OVERWRITE DEFAULT | Deleting {config_file_default_path}, will copy from {self_managed_config_file_path}", title="Overwrite Default", expand=False))
323
+ config_file_default_path.delete(sure=True)
324
+ case "backup-default-path":
325
+ backup_name = f"{config_file_default_path}.orig_{randstr()}"
326
+ action_taken = "backupConfigDefaultPath"
327
+ details = f"Backed up default path to {backup_name}"
328
+ console.print(Panel(f"📦 BACKUP DEFAULT | Moving {config_file_default_path} to {backup_name}, will copy from {self_managed_config_file_path}", title="Backup Default", expand=False))
329
+ config_file_default_path.move(path=backup_name)
330
+ case (True, False):
331
+ # config_file_default_path exists, self_managed_config_file_path doesn't
332
+ if config_file_default_path.is_symlink():
333
+ action_taken = "relink2newSelfManagedPath"
334
+ details = "Removed existing symlink, will create self_managed_config_file_path and copy"
335
+ console.print(Panel(f"🔄 REMOVING SYMLINK | Removing symlink {config_file_default_path}, creating {self_managed_config_file_path}", title="Removing Symlink", expand=False))
336
+ config_file_default_path.delete(sure=True)
337
+ self_managed_config_file_path.parent.mkdir(parents=True, exist_ok=True)
338
+ self_managed_config_file_path.touch()
147
339
  else:
148
- console.print(Panel(f"📁 MOVING | Moving {this} to {to_this}, then copying", title="Moving", expand=False))
149
- this.move(path=to_this)
150
- else:
151
- if to_this.exists():
152
- console.print(Panel(f"🆕 NEW LINK | Copying {to_this} to {this}", title="New Link", expand=False))
153
- else:
154
- console.print(Panel(f"🆕 NEW LINK & TARGET | Creating {to_this} and copying to {this}", title="New Link & Target", expand=False))
155
- to_this.parent.mkdir(parents=True, exist_ok=True)
156
- to_this.touch()
340
+ action_taken = "move2selfManagedPath"
341
+ details = "Moved config_file_default_path to self_managed_config_file_path location, will copy back"
342
+ console.print(Panel(f"📁 MOVING | Moving {config_file_default_path} to {self_managed_config_file_path}, then copying back", title="Moving", expand=False))
343
+ config_file_default_path.move(path=self_managed_config_file_path)
344
+ case (False, True):
345
+ # config_file_default_path doesn't exist, self_managed_config_file_path does
346
+ action_taken = "new_link"
347
+ details = "Copying existing self_managed_config_file_path to config_file_default_path location"
348
+ console.print(Panel(f"🆕 NEW COPY | Copying {self_managed_config_file_path} to {config_file_default_path}", title="New Copy", expand=False))
349
+ case (False, False):
350
+ # Neither exists
351
+ action_taken = "newLinkAndSelfManagedPath"
352
+ details = "Creating self_managed_config_file_path file and copying to config_file_default_path"
353
+ console.print(Panel(f"🆕 NEW FILE & COPY | Creating {self_managed_config_file_path} and copying to {config_file_default_path}", title="New File & Copy", expand=False))
354
+ self_managed_config_file_path.parent.mkdir(parents=True, exist_ok=True)
355
+ self_managed_config_file_path.touch()
356
+
157
357
  try:
158
- console.print(Panel(f"📋 COPYING | Copying {to_this} to {this}", title="Copying", expand=False))
159
- to_this.copy(path=this, overwrite=True, verbose=True)
358
+ if not action_taken:
359
+ action_taken = "copying"
360
+ details = "Copying file"
361
+ console.print(Panel(f"📋 COPYING | Copying {self_managed_config_file_path} to {config_file_default_path}", title="Copying", expand=False))
362
+ self_managed_config_file_path.copy(path=config_file_default_path, overwrite=True, verbose=True)
363
+ return {"action": action_taken, "details": details}
160
364
  except Exception as ex:
161
- console.print(Panel(f"❌ ERROR | Failed at copying {to_this} to {this}. Reason: {ex}", title="Error", expand=False))
365
+ action_taken = "error"
366
+ details = f"Failed to copy file: {str(ex)}"
367
+ console.print(Panel(f"❌ ERROR | Failed at copying {self_managed_config_file_path} to {config_file_default_path}. Reason: {ex}", title="Error", expand=False))
368
+ return {"action": action_taken, "details": details}
369
+
370
+