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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (461) hide show
  1. machineconfig/cluster/remote/cloud_manager.py +1 -1
  2. machineconfig/cluster/remote/run_cluster.py +1 -1
  3. machineconfig/cluster/remote/run_remote.py +1 -1
  4. machineconfig/cluster/sessions_managers/utils/maker.py +29 -15
  5. machineconfig/cluster/sessions_managers/wt_local.py +17 -222
  6. machineconfig/cluster/sessions_managers/wt_local_manager.py +56 -194
  7. machineconfig/cluster/sessions_managers/wt_remote_manager.py +42 -198
  8. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  9. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  10. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  11. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  12. machineconfig/cluster/sessions_managers/zellij_local.py +1 -1
  13. machineconfig/cluster/sessions_managers/zellij_local_manager.py +4 -2
  14. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +3 -2
  15. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +2 -2
  16. machineconfig/jobs/installer/checks/check_installations.py +133 -0
  17. machineconfig/jobs/installer/checks/install_utils.py +132 -0
  18. machineconfig/jobs/installer/checks/report_utils.py +39 -0
  19. machineconfig/jobs/installer/checks/vt_utils.py +89 -0
  20. machineconfig/jobs/installer/installer_data.json +1500 -310
  21. machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
  22. machineconfig/jobs/installer/linux_scripts/q.sh +10 -7
  23. machineconfig/jobs/installer/linux_scripts/redis.sh +1 -0
  24. machineconfig/jobs/installer/package_groups.py +62 -91
  25. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  26. machineconfig/jobs/installer/{custom → python_scripts}/boxes.py +2 -3
  27. machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +5 -3
  28. machineconfig/jobs/installer/python_scripts/cloudflare_warp_cli.py +23 -0
  29. machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +14 -9
  30. machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +1 -1
  31. machineconfig/jobs/installer/python_scripts/hx.py +214 -0
  32. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +2 -2
  33. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +32 -26
  34. machineconfig/jobs/installer/python_scripts/sysabc.py +145 -0
  35. machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +2 -19
  36. machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +10 -14
  37. machineconfig/jobs/installer/python_scripts/yazi.py +139 -0
  38. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nfs +0 -1
  39. machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
  40. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +13 -0
  41. machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +4 -0
  42. machineconfig/jobs/scripts_dynamic/a.py +428 -0
  43. machineconfig/logger.py +1 -2
  44. machineconfig/profile/create_helper.py +56 -18
  45. machineconfig/profile/create_links.py +79 -21
  46. machineconfig/profile/create_links_export.py +87 -36
  47. machineconfig/profile/create_shell_profile.py +92 -127
  48. machineconfig/profile/mapper_data.toml +45 -0
  49. machineconfig/profile/mapper_dotfiles.toml +249 -0
  50. machineconfig/scripts/__init__.py +0 -4
  51. machineconfig/scripts/linux/wrap_mcfg +46 -0
  52. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  53. machineconfig/scripts/python/agents.py +85 -165
  54. machineconfig/scripts/python/ai/initai.py +4 -2
  55. machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
  56. machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
  57. machineconfig/scripts/python/ai/{command_runner → scripts}/command_runner.sh +1 -1
  58. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
  59. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +8 -6
  60. machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
  61. machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
  62. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
  63. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
  64. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
  65. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +6 -6
  66. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +33 -0
  67. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
  68. machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
  69. machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
  70. machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
  71. machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
  72. machineconfig/scripts/python/ai/{generate_files.py → utils/generate_files.py} +2 -2
  73. machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
  74. machineconfig/scripts/python/ai/{vscode_tasks.py → utils/vscode_tasks.py} +13 -5
  75. machineconfig/scripts/python/cloud.py +58 -11
  76. machineconfig/scripts/python/croshell.py +10 -162
  77. machineconfig/scripts/python/devops.py +73 -36
  78. machineconfig/scripts/python/devops_navigator.py +16 -6
  79. machineconfig/scripts/python/fire_jobs.py +8 -222
  80. machineconfig/scripts/python/ftpx.py +7 -200
  81. machineconfig/scripts/python/graph/cli_graph.json +8743 -0
  82. machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
  83. machineconfig/scripts/python/helpers/helper_env/env_manager_tui.py +204 -0
  84. machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
  85. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +1 -1
  86. machineconfig/scripts/python/helpers/helpers_agents/agentic_frameworks/fire_crush.py +39 -0
  87. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +3 -4
  88. machineconfig/scripts/python/helpers/helpers_agents/agentic_frameworks/fire_gemini.py +55 -0
  89. machineconfig/scripts/python/helpers/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  90. machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
  91. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_help_launch.py +38 -16
  92. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_helper_types.py +11 -14
  93. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
  94. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
  95. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/copilot/config.yml +1 -0
  96. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/crush/crush.json +10 -0
  97. machineconfig/scripts/python/helpers/helpers_agents/privacy/configs/gemini/settings.json +12 -0
  98. machineconfig/scripts/python/helpers/helpers_agents/privacy/privacy.py +109 -0
  99. machineconfig/scripts/python/helpers/helpers_agents/templates/prompt.txt +10 -0
  100. machineconfig/scripts/python/helpers/helpers_agents/templates/template.sh +34 -0
  101. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +32 -25
  102. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +29 -22
  103. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +9 -8
  104. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
  105. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +3 -3
  106. machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +225 -0
  107. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
  108. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +12 -12
  109. machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
  110. machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +262 -0
  111. machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +98 -0
  112. machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
  113. machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +67 -0
  114. machineconfig/scripts/python/helpers/helpers_devops/cli_nw.py +201 -0
  115. machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +274 -0
  116. machineconfig/scripts/python/helpers/helpers_devops/cli_self.py +197 -0
  117. machineconfig/scripts/python/helpers/helpers_devops/cli_share_file.py +151 -0
  118. machineconfig/scripts/python/helpers/helpers_devops/cli_share_server.py +125 -0
  119. machineconfig/scripts/python/{helpers_devops/cli_terminal.py → helpers/helpers_devops/cli_share_terminal.py} +26 -22
  120. machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
  121. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +17 -23
  122. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
  123. machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +78 -71
  124. machineconfig/scripts/python/helpers/helpers_devops/run_script.py +197 -0
  125. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
  126. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
  127. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +4 -4
  128. machineconfig/scripts/python/{helpers_fire/helpers4.py → helpers/helpers_fire_command/file_wrangler.py} +57 -20
  129. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +1 -0
  130. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
  131. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +26 -16
  132. machineconfig/scripts/python/helpers/helpers_msearch/__init__.py +5 -0
  133. machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
  134. machineconfig/scripts/{linux → python/helpers/helpers_msearch/scripts_linux}/fzfg +6 -5
  135. machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
  136. machineconfig/scripts/python/helpers/helpers_msearch/scripts_windows/fzfg.ps1 +59 -0
  137. machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
  138. machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
  139. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
  140. machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
  141. machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
  142. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
  143. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
  144. machineconfig/scripts/python/helpers/helpers_network/address.py +174 -0
  145. machineconfig/scripts/python/helpers/helpers_network/address_switch.py +78 -0
  146. machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
  147. machineconfig/scripts/python/{nw → helpers/helpers_network}/mount_nfs.py +2 -2
  148. machineconfig/scripts/python/{nw → helpers/helpers_network}/mount_ssh.py +3 -3
  149. machineconfig/scripts/python/helpers/helpers_network/ssh_add_identity.py +73 -0
  150. machineconfig/scripts/python/helpers/helpers_network/ssh_add_ssh_key.py +175 -0
  151. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_linux.py +319 -0
  152. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_windows.py +275 -0
  153. machineconfig/scripts/python/{nw → helpers/helpers_network}/wifi_conn.py +1 -53
  154. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
  155. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
  156. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -1
  157. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +159 -48
  158. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +4 -3
  159. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -12
  160. machineconfig/scripts/python/helpers/helpers_repos/repo_analyzer_1.py +160 -0
  161. machineconfig/scripts/python/{helpers_repos/count_lines.py → helpers/helpers_repos/repo_analyzer_2.py} +156 -191
  162. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
  163. machineconfig/scripts/python/helpers/helpers_search/ast_search.py +74 -0
  164. machineconfig/scripts/python/helpers/helpers_search/qr_code.py +166 -0
  165. machineconfig/scripts/python/helpers/helpers_search/repo_rag.py +325 -0
  166. machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
  167. machineconfig/scripts/python/helpers/helpers_search/symantic_search.py +25 -0
  168. machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
  169. machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +186 -0
  170. machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +20 -14
  171. machineconfig/scripts/python/helpers/helpers_terminal/__init__.py +0 -0
  172. machineconfig/scripts/python/helpers/helpers_terminal/terminal_impl.py +96 -0
  173. machineconfig/scripts/python/helpers/helpers_utils/download.py +150 -0
  174. machineconfig/scripts/python/helpers/helpers_utils/pdf.py +96 -0
  175. machineconfig/scripts/python/helpers/helpers_utils/python.py +210 -0
  176. machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
  177. machineconfig/scripts/python/mcfg_entry.py +143 -0
  178. machineconfig/scripts/python/msearch.py +26 -0
  179. machineconfig/scripts/python/sessions.py +69 -135
  180. machineconfig/scripts/python/terminal.py +58 -0
  181. machineconfig/scripts/python/utils.py +115 -38
  182. machineconfig/scripts/windows/wrap_mcfg.ps1 +63 -0
  183. machineconfig/settings/atuin/config.toml +294 -0
  184. machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
  185. machineconfig/settings/broot/conf.toml +1 -1
  186. machineconfig/settings/helix/config.toml +16 -0
  187. machineconfig/settings/helix/languages.toml +13 -4
  188. machineconfig/settings/helix/yazi-picker.sh +12 -0
  189. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  190. machineconfig/settings/lf/linux/exe/previewer.sh +3 -2
  191. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  192. machineconfig/settings/lf/windows/lfrc +14 -16
  193. machineconfig/settings/linters/.ruff.toml +2 -1
  194. machineconfig/settings/marimo/marimo.toml +1 -1
  195. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  196. machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
  197. machineconfig/settings/shells/bash/init.sh +47 -12
  198. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
  199. machineconfig/settings/shells/nushell/config.nu +25 -33
  200. machineconfig/settings/shells/nushell/env.nu +21 -8
  201. machineconfig/settings/shells/nushell/init.nu +138 -0
  202. machineconfig/settings/shells/pwsh/init.ps1 +111 -17
  203. machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
  204. machineconfig/settings/shells/starship/starship.toml +16 -0
  205. machineconfig/settings/shells/wezterm/wezterm.lua +6 -1
  206. machineconfig/settings/shells/wt/settings.json +27 -18
  207. machineconfig/settings/shells/zsh/init.sh +42 -23
  208. machineconfig/settings/television/cable_unix/alias.toml +8 -0
  209. machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
  210. machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
  211. machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
  212. machineconfig/settings/television/cable_unix/channels.toml +19 -0
  213. machineconfig/settings/television/cable_unix/dirs.toml +13 -0
  214. machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
  215. machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
  216. machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
  217. machineconfig/settings/television/cable_unix/env.toml +17 -0
  218. machineconfig/settings/television/cable_unix/files.toml +11 -0
  219. machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
  220. machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
  221. machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
  222. machineconfig/settings/television/cable_unix/git-log.toml +12 -0
  223. machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
  224. machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
  225. machineconfig/settings/television/cable_unix/guix.toml +20 -0
  226. machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
  227. machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
  228. machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
  229. machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
  230. machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
  231. machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
  232. machineconfig/settings/television/cable_unix/procs.toml +20 -0
  233. machineconfig/settings/television/cable_unix/text.toml +17 -0
  234. machineconfig/settings/television/cable_unix/tldr.toml +18 -0
  235. machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
  236. machineconfig/settings/television/cable_windows/alias.toml +7 -0
  237. machineconfig/settings/television/cable_windows/dirs.toml +13 -0
  238. machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
  239. machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
  240. machineconfig/settings/television/cable_windows/env.toml +17 -0
  241. machineconfig/settings/television/cable_windows/files.toml +14 -0
  242. machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
  243. machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
  244. machineconfig/settings/television/cable_windows/git-log.toml +11 -0
  245. machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
  246. machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
  247. machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
  248. machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
  249. machineconfig/settings/television/cable_windows/text.toml +17 -0
  250. machineconfig/settings/tv/config.toml +234 -0
  251. machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
  252. machineconfig/settings/wsl/.wslconfig +5 -30
  253. machineconfig/settings/wt/__init__.py +0 -0
  254. machineconfig/settings/yazi/init.lua +61 -0
  255. machineconfig/settings/yazi/keymap_linux.toml +94 -0
  256. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  257. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  258. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  259. machineconfig/settings/yazi/theme.toml +4 -0
  260. machineconfig/settings/yazi/yazi_linux.toml +94 -0
  261. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  262. machineconfig/settings/zellij/layouts/st.kdl +40 -9
  263. machineconfig/settings/zellij/layouts/st2.kdl +1 -1
  264. machineconfig/setup_linux/__init__.py +2 -2
  265. machineconfig/setup_linux/apps_desktop.sh +8 -27
  266. machineconfig/setup_linux/web_shortcuts/interactive.sh +27 -12
  267. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +34 -0
  268. machineconfig/setup_mac/__init__.py +1 -4
  269. machineconfig/setup_mac/apps_gui.sh +248 -0
  270. machineconfig/setup_windows/__init__.py +2 -5
  271. machineconfig/setup_windows/uv.ps1 +8 -1
  272. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +28 -12
  273. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +31 -0
  274. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  275. machineconfig/type_hinting/sql/__init__.py +1 -0
  276. machineconfig/type_hinting/sql/base.py +216 -0
  277. machineconfig/type_hinting/sql/core_schema.py +64 -0
  278. machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
  279. machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
  280. machineconfig/type_hinting/typedict/__init__.py +1 -0
  281. machineconfig/type_hinting/typedict/ast_utils.py +130 -0
  282. machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
  283. machineconfig/type_hinting/typedict/generators.py +231 -0
  284. machineconfig/type_hinting/typedict/polars_schema.py +24 -0
  285. machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
  286. machineconfig/utils/accessories.py +31 -4
  287. machineconfig/utils/code.py +163 -51
  288. machineconfig/utils/files/ascii_art.py +11 -15
  289. machineconfig/utils/files/headers.py +6 -7
  290. machineconfig/utils/files/read.py +8 -1
  291. machineconfig/utils/installer_utils/github_release_bulk.py +95 -138
  292. machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
  293. machineconfig/utils/installer_utils/install_from_url.py +183 -0
  294. machineconfig/utils/installer_utils/installer_class.py +53 -102
  295. machineconfig/utils/installer_utils/installer_cli.py +161 -0
  296. machineconfig/utils/installer_utils/installer_helper.py +129 -0
  297. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +42 -91
  298. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +20 -65
  299. machineconfig/utils/io.py +94 -9
  300. machineconfig/utils/links.py +56 -38
  301. machineconfig/utils/meta.py +38 -21
  302. machineconfig/utils/options.py +81 -23
  303. machineconfig/utils/options_utils/__init__.py +0 -0
  304. machineconfig/utils/options_utils/options_tv_linux.py +211 -0
  305. machineconfig/utils/options_utils/options_tv_windows.py +88 -0
  306. machineconfig/utils/options_utils/tv_options.py +37 -0
  307. machineconfig/utils/path_extended.py +52 -102
  308. machineconfig/utils/path_helper.py +76 -23
  309. machineconfig/utils/procs.py +1 -1
  310. machineconfig/utils/scheduler.py +26 -53
  311. machineconfig/utils/scheduling.py +0 -2
  312. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  313. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  314. machineconfig/utils/source_of_truth.py +6 -1
  315. machineconfig/utils/ssh.py +216 -419
  316. machineconfig/utils/ssh_utils/abc.py +5 -0
  317. machineconfig/utils/ssh_utils/copy_from_here.py +116 -0
  318. machineconfig/utils/ssh_utils/copy_to_here.py +303 -0
  319. machineconfig/utils/ssh_utils/utils.py +158 -0
  320. machineconfig/utils/ssh_utils/wsl.py +147 -0
  321. machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
  322. machineconfig/utils/terminal.py +1 -0
  323. machineconfig/utils/upgrade_packages.py +107 -35
  324. machineconfig/utils/ve.py +12 -4
  325. machineconfig-8.51.dist-info/METADATA +140 -0
  326. machineconfig-8.51.dist-info/RECORD +543 -0
  327. {machineconfig-6.82.dist-info → machineconfig-8.51.dist-info}/entry_points.txt +4 -1
  328. machineconfig/jobs/installer/check_installations.py +0 -248
  329. machineconfig/jobs/installer/custom/hx.py +0 -140
  330. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -41
  331. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -71
  332. machineconfig/jobs/installer/powershell_scripts/archive_pygraphviz.ps1 +0 -12
  333. machineconfig/jobs/installer/powershell_scripts/openssh-server_add_key.ps1 +0 -7
  334. machineconfig/jobs/installer/powershell_scripts/openssh-server_copy-ssh-id.ps1 +0 -14
  335. machineconfig/profile/backup.toml +0 -49
  336. machineconfig/profile/mapper.toml +0 -256
  337. machineconfig/scripts/linux/fzf2g +0 -21
  338. machineconfig/scripts/linux/fzfag +0 -17
  339. machineconfig/scripts/linux/fzffg +0 -25
  340. machineconfig/scripts/linux/fzfrga +0 -21
  341. machineconfig/scripts/linux/mcfgs +0 -38
  342. machineconfig/scripts/linux/other/share_smb +0 -1
  343. machineconfig/scripts/linux/other/switch_ip +0 -20
  344. machineconfig/scripts/linux/skrg +0 -4
  345. machineconfig/scripts/linux/warp-cli.sh +0 -122
  346. machineconfig/scripts/linux/z_ls +0 -104
  347. machineconfig/scripts/python/ai/command_runner/prompt.txt +0 -9
  348. machineconfig/scripts/python/helpers_devops/cli_config.py +0 -120
  349. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -77
  350. machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
  351. machineconfig/scripts/python/helpers_devops/cli_nw.py +0 -73
  352. machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -181
  353. machineconfig/scripts/python/helpers_devops/cli_self.py +0 -122
  354. machineconfig/scripts/python/helpers_devops/cli_share_server.py +0 -104
  355. machineconfig/scripts/python/helpers_devops/cli_utils.py +0 -221
  356. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
  357. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
  358. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_crush.py +0 -37
  359. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_gemini.py +0 -44
  360. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_qwen.py +0 -43
  361. machineconfig/scripts/python/helpers_fire/prompt.txt +0 -2
  362. machineconfig/scripts/python/helpers_fire/template.sh +0 -15
  363. machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
  364. machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
  365. machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -588
  366. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +0 -17
  367. machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -76
  368. machineconfig/scripts/python/helpers_repos/secure_repo.py +0 -15
  369. machineconfig/scripts/python/mcfg.py +0 -48
  370. machineconfig/scripts/python/nw/add_ssh_key.py +0 -148
  371. machineconfig/scripts/python/nw/devops_add_identity.py +0 -82
  372. machineconfig/scripts/python/nw/devops_add_ssh_key.py +0 -134
  373. machineconfig/scripts/python/nw/ssh_debug_linux.py +0 -391
  374. machineconfig/scripts/python/nw/ssh_debug_windows.py +0 -338
  375. machineconfig/scripts/python/nw/wsl_windows_transfer.py +0 -66
  376. machineconfig/scripts/windows/fzfb.ps1 +0 -3
  377. machineconfig/scripts/windows/fzfg.ps1 +0 -2
  378. machineconfig/scripts/windows/fzfrga.bat +0 -20
  379. machineconfig/scripts/windows/mcfgs.ps1 +0 -17
  380. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
  381. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  382. machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
  383. machineconfig/settings/lf/windows/tst.ps1 +0 -1
  384. machineconfig/settings/yazi/yazi.toml +0 -4
  385. machineconfig/setup_linux/apps.sh +0 -66
  386. machineconfig/setup_linux/others/cli_installation.sh +0 -137
  387. machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh +0 -30
  388. machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
  389. machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
  390. machineconfig/setup_mac/apps.sh +0 -73
  391. machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
  392. machineconfig/setup_windows/apps.ps1 +0 -62
  393. machineconfig/setup_windows/others/obs.ps1 +0 -4
  394. machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
  395. machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
  396. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
  397. machineconfig/utils/installer_utils/installer.py +0 -225
  398. machineconfig/utils/tst.py +0 -20
  399. machineconfig-6.82.dist-info/METADATA +0 -82
  400. machineconfig-6.82.dist-info/RECORD +0 -441
  401. machineconfig/jobs/installer/{custom_dev → checks}/__init__.py +0 -0
  402. machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +0 -0
  403. machineconfig/{scripts/python/helpers_cloud → jobs/installer/python_scripts}/__init__.py +0 -0
  404. machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
  405. machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
  406. machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
  407. machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
  408. machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
  409. machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
  410. machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
  411. machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
  412. machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/android.sh +0 -0
  413. machineconfig/jobs/{installer/linux_scripts → scripts/bash_scripts}/lid.sh +0 -0
  414. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_drive +0 -0
  415. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nw_drive +0 -0
  416. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_smb +0 -0
  417. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_cloud.sh +0 -0
  418. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_nfs +0 -0
  419. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/start_docker +0 -0
  420. machineconfig/{scripts → jobs/scripts/powershell_scripts}/Restore-ThunderbirdProfile.ps1 +0 -0
  421. machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/docker.ps1 +0 -0
  422. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nfs.ps1 +0 -0
  423. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nw.ps1 +0 -0
  424. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_smb.ps1 +0 -0
  425. machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/power_options.ps1 +0 -0
  426. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_cloud.cmd +0 -0
  427. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_smb.ps1 +0 -0
  428. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
  429. machineconfig/scripts/python/{helpers_croshell → ai/utils}/__init__.py +0 -0
  430. machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
  431. machineconfig/scripts/python/{helpers_devops → graph}/__init__.py +0 -0
  432. machineconfig/scripts/python/{helpers_devops/themes → helpers}/__init__.py +0 -0
  433. machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
  434. machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
  435. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/__init__.py +0 -0
  436. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/agentic_frameworks/__init__.py +0 -0
  437. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
  438. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
  439. machineconfig/scripts/python/{helpers_fire → helpers/helpers_agents/templates}/template.ps1 +0 -0
  440. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_cloud}/__init__.py +0 -0
  441. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +1 -1
  442. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
  443. /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_croshell}/__init__.py +0 -0
  444. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
  445. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
  446. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
  447. /machineconfig/scripts/python/{nw → helpers/helpers_devops}/__init__.py +0 -0
  448. /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers/helpers_devops/themes}/__init__.py +0 -0
  449. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  450. /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_fire_command/__init__.py} +0 -0
  451. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
  452. /machineconfig/scripts/python/{helpers_fire_command/fire_jobs_streamlit_helper.py → helpers/helpers_fire_command/f.py} +0 -0
  453. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers/helpers_fire_command/fire_jobs_streamlit_helper.py} +0 -0
  454. /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
  455. /machineconfig/{settings/yazi/keymap.toml → scripts/python/helpers/helpers_network/__init__.py} +0 -0
  456. /machineconfig/scripts/python/{nw → helpers/helpers_network}/mount_nw_drive.py +0 -0
  457. /machineconfig/scripts/python/{nw → helpers/helpers_network}/onetimeshare.py +0 -0
  458. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
  459. /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
  460. {machineconfig-6.82.dist-info → machineconfig-8.51.dist-info}/WHEEL +0 -0
  461. {machineconfig-6.82.dist-info → machineconfig-8.51.dist-info}/top_level.txt +0 -0
@@ -5,12 +5,41 @@ Extracts GitHub repository URLs and fetches latest release data with rate limiti
5
5
  """
6
6
 
7
7
  import json
8
- import time
9
- import subprocess
8
+ import requests
10
9
  from pathlib import Path
11
- from typing import Any, Dict, Optional, Set
10
+ from typing import Any, Dict, Optional, Set, TypedDict
12
11
  from urllib.parse import urlparse
13
12
 
13
+ from machineconfig.utils.installer_utils.github_release_scraper import scrape_github_release_page
14
+
15
+
16
+ class AssetInfo(TypedDict):
17
+ """Type definition for GitHub release asset information."""
18
+ name: str
19
+ size: int
20
+ download_count: int
21
+ content_type: str
22
+ created_at: str
23
+ updated_at: str
24
+ browser_download_url: str
25
+
26
+
27
+ class ReleaseInfo(TypedDict):
28
+ """Type definition for GitHub release information."""
29
+ tag_name: str
30
+ name: str
31
+ published_at: str
32
+ assets: list[AssetInfo]
33
+ assets_count: int
34
+
35
+
36
+ class OutputData(TypedDict):
37
+ """Type definition for the output JSON data structure."""
38
+ generated_at: str
39
+ total_repositories: int
40
+ successful_fetches: int
41
+ releases: Dict[str, Optional[ReleaseInfo]]
42
+
14
43
 
15
44
  def is_github_repo(url: str) -> bool:
16
45
  """Check if URL is a GitHub repository URL."""
@@ -19,170 +48,98 @@ def is_github_repo(url: str) -> bool:
19
48
  return parsed.netloc == "github.com" and len(parsed.path.split("/")) >= 3
20
49
  except Exception:
21
50
  return False
22
-
23
-
24
51
  def extract_github_repos_from_json(json_file_path: Path) -> Set[str]:
25
52
  """Extract GitHub repository URLs from installer JSON file."""
26
53
  github_repos: Set[str] = set()
27
-
28
54
  try:
29
55
  with open(json_file_path, 'r', encoding='utf-8') as file:
30
56
  data = json.load(file)
31
-
32
57
  for installer in data.get("installers", []):
33
58
  repo_url = installer.get("repoURL", "")
34
59
  if is_github_repo(repo_url):
35
60
  github_repos.add(repo_url)
36
-
37
61
  except (json.JSONDecodeError, FileNotFoundError) as e:
38
62
  print(f"Error reading {json_file_path}: {e}")
39
-
40
63
  return github_repos
41
-
42
-
43
- def get_repo_name_from_url(repo_url: str) -> str:
44
- """Extract owner/repo from GitHub URL."""
64
+ def get_repo_name_from_url(repo_url: str) -> Optional[tuple[str, str]]:
65
+ """Extract owner/repo from GitHub URL as a tuple (username, repo_name)."""
45
66
  try:
46
67
  parsed = urlparse(repo_url)
47
68
  path_parts = parsed.path.strip("/").split("/")
48
- return f"{path_parts[0]}/{path_parts[1]}"
69
+ return (path_parts[0], path_parts[1])
49
70
  except (IndexError, AttributeError):
50
- return ""
71
+ return None
72
+
51
73
 
74
+ def fetch_github_release_data(
75
+ username: str,
76
+ repo_name: str,
77
+ version: Optional[str] = None,
78
+ ) -> Optional[Dict[str, Any]]:
79
+ """Fetch GitHub release data for the latest or a specific tag. Falls back to HTML scraping if API fails."""
52
80
 
53
- def fetch_github_release_data(repo_name: str) -> Optional[Dict[str, Any]]:
54
- """Fetch latest release data from GitHub API using curl."""
55
81
  try:
56
- cmd = [
57
- "curl", "-s",
58
- f"https://api.github.com/repos/{repo_name}/releases/latest"
59
- ]
60
-
61
- result = subprocess.run(
62
- cmd,
63
- capture_output=True,
64
- text=True,
65
- timeout=30
66
- )
67
-
68
- if result.returncode != 0:
69
- print(f"❌ Failed to fetch data for {repo_name}: {result.stderr}")
70
- return None
71
-
72
- response_data = json.loads(result.stdout)
73
-
74
- # Check if API returned an error
75
- if "message" in response_data:
76
- if "API rate limit exceeded" in response_data.get("message", ""):
77
- print(f"🚫 Rate limit exceeded for {repo_name}")
78
- return None
79
- elif "Not Found" in response_data.get("message", ""):
80
- print(f"🔍 No releases found for {repo_name}")
81
- return None
82
-
82
+ requested_version = (version or "").strip()
83
+ if requested_version and requested_version.lower() != "latest":
84
+ url = f"https://api.github.com/repos/{username}/{repo_name}/releases/tags/{requested_version}"
85
+ else:
86
+ url = f"https://api.github.com/repos/{username}/{repo_name}/releases/latest"
87
+
88
+ response = requests.get(url, timeout=30)
89
+ if response.status_code != 200:
90
+ print(f"⚠️ API failed for {username}/{repo_name}: HTTP {response.status_code}, trying HTML scraper...")
91
+ return scrape_github_release_page(username, repo_name, version)
92
+
93
+ response_data = response.json()
94
+ message = response_data.get("message")
95
+ if isinstance(message, str):
96
+ if "API rate limit exceeded" in message:
97
+ print(f"🚫 Rate limit exceeded for {username}/{repo_name}, trying HTML scraper...")
98
+ return scrape_github_release_page(username, repo_name, version)
99
+ if "Not Found" in message:
100
+ print(f"🔍 No releases found via API for {username}/{repo_name}, trying HTML scraper...")
101
+ return scrape_github_release_page(username, repo_name, version)
102
+
83
103
  return response_data
84
-
85
- except (subprocess.TimeoutExpired, json.JSONDecodeError, subprocess.SubprocessError) as e:
86
- print(f" Error fetching {repo_name}: {e}")
104
+
105
+ except (requests.RequestException, requests.Timeout, json.JSONDecodeError) as error:
106
+ print(f"⚠️ API error for {username}/{repo_name}: {error}, trying HTML scraper...")
107
+ return scrape_github_release_page(username, repo_name, version)
108
+
109
+
110
+ def get_release_info(
111
+ username: str,
112
+ repo_name: str,
113
+ version: Optional[str] = None,
114
+ ) -> Optional[ReleaseInfo]:
115
+ """Return sanitized release information for the requested repository."""
116
+ release_data = fetch_github_release_data(username, repo_name, version)
117
+ if not release_data:
87
118
  return None
119
+ return extract_release_info(release_data)
88
120
 
89
121
 
90
- def extract_release_info(release_data: Dict[str, Any]) -> Dict[str, Any]:
122
+ def extract_release_info(release_data: Dict[str, Any]) -> Optional[ReleaseInfo]:
91
123
  """Extract relevant information from GitHub release data."""
92
124
  if not release_data:
93
- return {}
94
-
95
- asset_names = [asset["name"] for asset in release_data.get("assets", [])]
96
-
125
+ return None
126
+ assets: list[AssetInfo] = []
127
+ for asset in release_data.get("assets", []):
128
+ asset_info: AssetInfo = {
129
+ "name": asset.get("name", ""),
130
+ "size": asset.get("size", 0),
131
+ "download_count": asset.get("download_count", 0),
132
+ "content_type": asset.get("content_type", ""),
133
+ "created_at": asset.get("created_at", ""),
134
+ "updated_at": asset.get("updated_at", ""),
135
+ "browser_download_url": asset.get("browser_download_url", "")
136
+ }
137
+ assets.append(asset_info)
97
138
  return {
98
139
  "tag_name": release_data.get("tag_name", ""),
99
140
  "name": release_data.get("name", ""),
100
141
  "published_at": release_data.get("published_at", ""),
101
- "assets": asset_names,
102
- "assets_count": len(asset_names)
142
+ "assets": assets,
143
+ "assets_count": len(assets)
103
144
  }
104
145
 
105
-
106
- def main() -> None:
107
- """Main function to process installer JSON files and fetch GitHub release data."""
108
- # Define paths
109
- current_dir = Path(__file__).parent
110
- installer_dir = current_dir.parent.parent / "jobs" / "installer"
111
-
112
- standard_json = installer_dir / "installer_data.json"
113
- output_json = current_dir / "github_releases.json"
114
-
115
- print("🔍 Starting GitHub release data extraction...")
116
- print(f"📁 Processing files from: {installer_dir}")
117
-
118
- # Extract GitHub repositories from both files
119
- all_github_repos: Set[str] = set()
120
-
121
- if standard_json.exists():
122
- print(f"📄 Reading {standard_json.name}...")
123
- repos = extract_github_repos_from_json(standard_json)
124
- all_github_repos.update(repos)
125
- print(f" Found {len(repos)} GitHub repos")
126
- else:
127
- print(f"⚠️ File not found: {standard_json}")
128
- print(f"🎯 Total unique GitHub repositories found: {len(all_github_repos)}")
129
-
130
- if not all_github_repos:
131
- print("❌ No GitHub repositories found. Exiting.")
132
- return
133
-
134
- # Fetch release data with rate limiting
135
- release_mapping: Dict[str, Any] = {}
136
- total_repos = len(all_github_repos)
137
-
138
- print(f"\n🚀 Fetching release data for {total_repos} repositories...")
139
- print("⏰ Rate limiting: 5 seconds between requests")
140
- print("-" * 60)
141
-
142
- for i, repo_url in enumerate(sorted(all_github_repos), 1):
143
- repo_name = get_repo_name_from_url(repo_url)
144
-
145
- if not repo_name:
146
- print(f"⚠️ [{i:3d}/{total_repos}] Invalid repo URL: {repo_url}")
147
- continue
148
-
149
- print(f"📡 [{i:3d}/{total_repos}] Fetching: {repo_name}", end=" ... ")
150
-
151
- release_data = fetch_github_release_data(repo_name)
152
-
153
- if release_data:
154
- release_info = extract_release_info(release_data)
155
- release_mapping[repo_url] = release_info
156
- assets_count = release_info.get("assets_count", 0)
157
- tag = release_info.get("tag_name", "unknown")
158
- print(f"✅ {tag} ({assets_count} assets)")
159
- else:
160
- release_mapping[repo_url] = {}
161
- print("❌ No data")
162
-
163
- # Rate limiting - wait 5 seconds between requests (except for the last one)
164
- if i < total_repos:
165
- time.sleep(5)
166
-
167
- # Save results
168
- output_data = {
169
- "generated_at": time.strftime("%Y-%m-%d %H:%M:%S UTC", time.gmtime()),
170
- "total_repositories": len(all_github_repos),
171
- "successful_fetches": len([v for v in release_mapping.values() if v]),
172
- "releases": release_mapping
173
- }
174
-
175
- with open(output_json, 'w', encoding='utf-8') as f:
176
- json.dump(output_data, f, indent=2, ensure_ascii=False)
177
-
178
- successful = len([v for v in release_mapping.values() if v])
179
- print("\n📊 Summary:")
180
- print(f" Total repositories processed: {len(all_github_repos)}")
181
- print(f" Successful fetches: {successful}")
182
- print(f" Failed fetches: {len(all_github_repos) - successful}")
183
- print(f" Output saved to: {output_json}")
184
- print("✅ Done!")
185
-
186
-
187
- if __name__ == "__main__":
188
- main()
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env python3
2
+ """HTML scraper for GitHub release pages as fallback when API rate limit is exceeded."""
3
+
4
+ import re
5
+ from typing import Any, Optional
6
+ import requests
7
+
8
+
9
+ def extract_tag_from_html(html: str, owner: str, repo: str) -> str:
10
+ patterns = [
11
+ rf'/{re.escape(owner)}/{re.escape(repo)}/releases/tag/([^"\'<>\s]+)',
12
+ rf'/{re.escape(owner)}/{re.escape(repo)}/tree/([^"\'<>\s]+)',
13
+ r'<span[^>]*class="[^"]*ml-1[^"]*"[^>]*>([^<]+)</span>',
14
+ ]
15
+ for pattern in patterns:
16
+ match = re.search(pattern, html, re.IGNORECASE)
17
+ if match:
18
+ tag = match.group(1).strip()
19
+ if tag and not tag.startswith("http"):
20
+ return tag
21
+ return ""
22
+
23
+
24
+ def extract_release_name(html: str) -> str:
25
+ patterns = [
26
+ r'<h1[^>]*class="[^"]*d-inline[^"]*"[^>]*>([^<]+)</h1>',
27
+ r'<bdi[^>]*class="[^"]*mr-2[^"]*"[^>]*>([^<]+)</bdi>',
28
+ r'<h1[^>]*>([^<]+)</h1>',
29
+ ]
30
+ for pattern in patterns:
31
+ match = re.search(pattern, html)
32
+ if match:
33
+ name = match.group(1).strip()
34
+ if name:
35
+ return name
36
+ return ""
37
+
38
+
39
+ def extract_published_at(html: str) -> str:
40
+ pattern = r'<relative-time[^>]*datetime="([^"]+)"'
41
+ match = re.search(pattern, html)
42
+ if match:
43
+ return match.group(1)
44
+ return ""
45
+
46
+
47
+ def fetch_expanded_assets(username: str, repo_name: str, tag_name: str, headers: dict[str, str]) -> list[dict[str, Any]]:
48
+ """Fetch assets from the expanded_assets endpoint which contains all downloadable files."""
49
+ assets: list[dict[str, Any]] = []
50
+ expanded_url = f"https://github.com/{username}/{repo_name}/releases/expanded_assets/{tag_name}"
51
+ try:
52
+ response = requests.get(expanded_url, timeout=30, headers=headers)
53
+ if response.status_code != 200:
54
+ print(f"⚠️ [Scraper] Could not fetch expanded assets for {username}/{repo_name}: HTTP {response.status_code}")
55
+ return assets
56
+ html = response.text
57
+ pattern = r'href="([^"]*?/releases/download/[^"]+)"[^>]*>.*?<span[^>]*class="[^"]*Truncate-text[^"]*text-bold[^"]*"[^>]*>([^<]+)</span>'
58
+ seen_urls: set[str] = set()
59
+ matches = re.findall(pattern, html, re.DOTALL)
60
+ for href, name in matches:
61
+ asset_name = name.strip()
62
+ if not asset_name or asset_name.isspace():
63
+ continue
64
+ download_url = f"https://github.com{href}" if href.startswith("/") else href
65
+ if download_url in seen_urls:
66
+ continue
67
+ seen_urls.add(download_url)
68
+ assets.append({"name": asset_name, "size": 0, "download_count": 0, "content_type": "", "created_at": "", "updated_at": "", "browser_download_url": download_url})
69
+ except requests.RequestException as error:
70
+ print(f"⚠️ [Scraper] Error fetching expanded assets for {username}/{repo_name}: {error}")
71
+ return assets
72
+
73
+
74
+ def scrape_github_release_page(username: str, repo_name: str, version: Optional[str] = None) -> Optional[dict[str, Any]]:
75
+ """Scrape GitHub release page HTML to extract release information. Falls back to this when API rate limit is hit."""
76
+ try:
77
+ requested_version = (version or "").strip()
78
+ if requested_version and requested_version.lower() != "latest":
79
+ url = f"https://github.com/{username}/{repo_name}/releases/tag/{requested_version}"
80
+ else:
81
+ url = f"https://github.com/{username}/{repo_name}/releases/latest"
82
+ headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"}
83
+ response = requests.get(url, timeout=30, headers=headers, allow_redirects=True)
84
+ if response.status_code != 200:
85
+ print(f"❌ [Scraper] Failed to fetch page for {username}/{repo_name}: HTTP {response.status_code}")
86
+ return None
87
+ html = response.text
88
+ tag_name = extract_tag_from_html(html, username, repo_name)
89
+ if not tag_name:
90
+ print(f"🔍 [Scraper] No tag found for {username}/{repo_name}")
91
+ return None
92
+ release_name = extract_release_name(html) or tag_name
93
+ published_at = extract_published_at(html)
94
+ assets = fetch_expanded_assets(username, repo_name, tag_name, headers)
95
+ print(f"✅ [Scraper] Found {len(assets)} assets for {username}/{repo_name} @ {tag_name}")
96
+ return {"tag_name": tag_name, "name": release_name, "published_at": published_at, "assets": assets}
97
+ except requests.RequestException as error:
98
+ print(f"❌ [Scraper] Error fetching {username}/{repo_name}: {error}")
99
+ return None
@@ -0,0 +1,183 @@
1
+
2
+
3
+ import platform
4
+ from typing import TYPE_CHECKING, Optional
5
+
6
+ from machineconfig.utils.installer_utils.installer_helper import install_deb_package, download_and_prepare
7
+ from machineconfig.utils.installer_utils.installer_locator_utils import find_move_delete_linux, find_move_delete_windows
8
+ from machineconfig.utils.installer_utils.github_release_bulk import (
9
+ get_repo_name_from_url,
10
+ fetch_github_release_data,
11
+ extract_release_info,
12
+ AssetInfo,
13
+ )
14
+ from machineconfig.utils.path_extended import PathExtended
15
+ from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT
16
+
17
+ if TYPE_CHECKING:
18
+ from rich.console import Console
19
+
20
+ SUPPORTED_GITHUB_HOSTS = {"github.com", "www.github.com"}
21
+
22
+
23
+ def _format_size(size_bytes: int) -> str:
24
+ if size_bytes <= 0:
25
+ return "0 B"
26
+ units = ("B", "KiB", "MiB", "GiB", "TiB")
27
+ value = float(size_bytes)
28
+ index = 0
29
+ while value >= 1024 and index < len(units) - 1:
30
+ value /= 1024
31
+ index += 1
32
+ return f"{value:.1f} {units[index]}"
33
+
34
+
35
+ def _derive_tool_name(repo_name: str, asset_name: Optional[str]) -> Optional[str]:
36
+ repo_segment = repo_name.split("/", maxsplit=1)[-1]
37
+ repo_clean = repo_segment.replace(".git", "").lower()
38
+ repo_filtered = "".join(char for char in repo_clean if char.isalnum())
39
+ if repo_filtered:
40
+ return repo_filtered
41
+ if asset_name is None:
42
+ return None
43
+ asset_clean = asset_name.lower()
44
+ asset_filtered = "".join(char for char in asset_clean if char.isalnum())
45
+ if asset_filtered:
46
+ return asset_filtered
47
+ return None
48
+
49
+
50
+ def _finalize_install(repo_name: str, asset_name: Optional[str], version: str, extracted_path: PathExtended, console: "Console") -> None:
51
+ from rich.panel import Panel
52
+ if extracted_path.suffix == ".deb":
53
+ install_deb_package(extracted_path)
54
+ tool_name_deb = _derive_tool_name(repo_name, asset_name)
55
+ if tool_name_deb is not None:
56
+ INSTALL_VERSION_ROOT.joinpath(tool_name_deb).parent.mkdir(parents=True, exist_ok=True)
57
+ INSTALL_VERSION_ROOT.joinpath(tool_name_deb).write_text(version, encoding="utf-8")
58
+ console.print(Panel(f"Installed Debian package for [green]{tool_name_deb}[/green]", title="✅ Complete", border_style="green"))
59
+ return
60
+ system_name = platform.system()
61
+ tool_name = _derive_tool_name(repo_name, asset_name)
62
+ rename_target = f"{tool_name}.exe" if system_name == "Windows" else tool_name
63
+ try:
64
+ if system_name == "Windows":
65
+ installed_path = find_move_delete_windows(downloaded_file_path=extracted_path, tool_name=tool_name, delete=True, rename_to=rename_target)
66
+ elif system_name in {"Linux", "Darwin"}:
67
+ installed_path = find_move_delete_linux(downloaded=extracted_path, tool_name=tool_name, delete=True, rename_to=rename_target)
68
+ else:
69
+ console.print(Panel(f"Unsupported operating system: {system_name}", title="❌ Error", border_style="red"))
70
+ return None
71
+ except IndexError:
72
+ if system_name == "Windows":
73
+ installed_path = find_move_delete_windows(downloaded_file_path=extracted_path, tool_name=None, delete=True, rename_to=rename_target)
74
+ elif system_name in {"Linux", "Darwin"}:
75
+ installed_path = find_move_delete_linux(downloaded=extracted_path, tool_name="", delete=True, rename_to=rename_target)
76
+ else:
77
+ raise
78
+ if tool_name is not None:
79
+ INSTALL_VERSION_ROOT.joinpath(tool_name).parent.mkdir(parents=True, exist_ok=True)
80
+ INSTALL_VERSION_ROOT.joinpath(tool_name).write_text(version, encoding="utf-8")
81
+ console.print(Panel(f"Installed [green]{tool_name}[/green] to {installed_path}\nVersion: {version}", title="✅ Complete", border_style="green"))
82
+
83
+
84
+ def install_from_github_url(github_url: str) -> None:
85
+ from machineconfig.utils.options import choose_from_options
86
+ from rich.console import Console
87
+ from rich.panel import Panel
88
+
89
+ console = Console()
90
+ repo_info = get_repo_name_from_url(github_url)
91
+ if repo_info is None:
92
+ console.print(Panel(f"Invalid GitHub URL: {github_url}", title="❌ Error", border_style="red"))
93
+ return None
94
+ owner, repo = repo_info
95
+ repo_name = f"{owner}/{repo}"
96
+ console.print(Panel(f"Fetching latest release for [green]{repo_name}[/green]", title="🌐 GitHub", border_style="blue"))
97
+ release_raw = fetch_github_release_data(owner, repo)
98
+ if not release_raw:
99
+ console.print(Panel("No releases available for this repository.", title="❌ Error", border_style="red"))
100
+ return None
101
+
102
+ release_info = extract_release_info(release_raw)
103
+ if not release_info:
104
+ console.print(Panel("Failed to parse release information.", title="❌ Error", border_style="red"))
105
+ return None
106
+
107
+ assets = release_info["assets"]
108
+ if not assets:
109
+ console.print(Panel("No downloadable assets found in the latest release.", title="❌ Error", border_style="red"))
110
+ return None
111
+ binary_assets = assets
112
+ selection_pool = binary_assets if binary_assets else assets
113
+ if not selection_pool:
114
+ console.print(Panel("No assets available for installation.", title="❌ Error", border_style="red"))
115
+ return None
116
+
117
+ # First pass: collect all formatted data and calculate column widths
118
+ asset_data = []
119
+ for asset in selection_pool:
120
+ name = asset["name"]
121
+ download_url = asset["browser_download_url"]
122
+ if name == "" or download_url == "":
123
+ continue
124
+ size = asset["size"]
125
+ download_count = asset.get("download_count", 0)
126
+ created_at = asset.get("created_at", "")
127
+
128
+ # Format each field
129
+ size_str = f"[{_format_size(size)}]"
130
+ downloads_str = f"{download_count:,}"
131
+ date_str = created_at.split("T")[0] if created_at else "N/A"
132
+
133
+ asset_data.append({
134
+ "name": name,
135
+ "size_str": size_str,
136
+ "downloads_str": downloads_str,
137
+ "date_str": date_str,
138
+ "asset": asset
139
+ })
140
+
141
+ # Calculate maximum widths for alignment
142
+ max_name_len = max(len(item["name"]) for item in asset_data) if asset_data else 0
143
+ max_size_len = max(len(item["size_str"]) for item in asset_data) if asset_data else 0
144
+ max_downloads_len = max(len(item["downloads_str"]) for item in asset_data) if asset_data else 0
145
+
146
+ # Second pass: build aligned labels
147
+ options_map: dict[str, AssetInfo] = {}
148
+ for item in asset_data:
149
+ name_padded = item["name"].ljust(max_name_len)
150
+ size_padded = item["size_str"].ljust(max_size_len)
151
+ downloads_padded = item["downloads_str"].rjust(max_downloads_len)
152
+
153
+ label = f"{name_padded} {size_padded} | #🔽 {downloads_padded} | 📅 {item['date_str']}"
154
+ options_map[label] = item["asset"]
155
+
156
+ if not options_map:
157
+ console.print(Panel("Release assets lack download URLs.", title="❌ Error", border_style="red"))
158
+ return None
159
+ selection_label = choose_from_options(options=list(options_map.keys()), msg="Select a release asset", multi=False, header="📦 GitHub Release Assets", tv=True)
160
+ selected_asset = options_map[selection_label]
161
+ download_url_value = selected_asset["browser_download_url"]
162
+ asset_name_value = selected_asset["name"]
163
+ if download_url_value == "":
164
+ console.print(Panel("Selected asset lacks a download URL.", title="❌ Error", border_style="red"))
165
+ return None
166
+ asset_name = asset_name_value if asset_name_value != "" else "github_binary"
167
+ version = release_info["tag_name"] if release_info["tag_name"] != "" else "latest"
168
+ console.print(Panel(f"Downloading [cyan]{asset_name}[/cyan]", title="⬇️ Download", border_style="magenta"))
169
+ extracted_path = download_and_prepare(download_url_value)
170
+ _finalize_install(repo_name=repo_name, asset_name=asset_name, version=version, extracted_path=extracted_path, console=console)
171
+
172
+
173
+ def install_from_binary_url(binary_url: str) -> None:
174
+ from rich.console import Console
175
+ # from rich.panel import Panel
176
+ console = Console()
177
+ # parsed = urlparse(binary_url)
178
+ # asset_candidate = parsed.path.split("/")[-1] if parsed.path else ""
179
+ # asset_name = asset_candidate if asset_candidate != "" else "binary_asset"
180
+ # host = parsed.netloc if parsed.netloc != "" else "remote host"
181
+ # console.print(Panel(f"Downloading from [green]{binary_url}[/green]", title="⬇️ Download", border_style="magenta"))
182
+ extracted_path = download_and_prepare(binary_url)
183
+ _finalize_install(repo_name="", asset_name=None, version="latest", extracted_path=extracted_path, console=console)