machineconfig 8.14__py3-none-any.whl → 8.45__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 (269) hide show
  1. machineconfig/cluster/remote/run_cluster.py +1 -1
  2. machineconfig/cluster/remote/run_remote.py +1 -1
  3. machineconfig/cluster/sessions_managers/utils/maker.py +10 -8
  4. machineconfig/cluster/sessions_managers/wt_local.py +1 -1
  5. machineconfig/cluster/sessions_managers/wt_local_manager.py +1 -1
  6. machineconfig/cluster/sessions_managers/zellij_local.py +1 -1
  7. machineconfig/cluster/sessions_managers/zellij_local_manager.py +1 -1
  8. machineconfig/jobs/installer/checks/check_installations.py +133 -0
  9. machineconfig/jobs/installer/checks/install_utils.py +132 -0
  10. machineconfig/jobs/installer/checks/report_utils.py +39 -0
  11. machineconfig/jobs/installer/checks/vt_utils.py +89 -0
  12. machineconfig/jobs/installer/installer_data.json +225 -140
  13. machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
  14. machineconfig/jobs/installer/package_groups.py +10 -9
  15. machineconfig/jobs/installer/python_scripts/boxes.py +1 -2
  16. machineconfig/jobs/installer/python_scripts/code.py +10 -8
  17. machineconfig/jobs/installer/python_scripts/hx.py +30 -13
  18. machineconfig/jobs/installer/python_scripts/nerfont_windows_helper.py +6 -5
  19. machineconfig/jobs/installer/python_scripts/sysabc.py +25 -19
  20. machineconfig/jobs/installer/python_scripts/yazi.py +33 -17
  21. machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
  22. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +1 -1
  23. machineconfig/jobs/scripts_dynamic/a.py +413 -10
  24. machineconfig/profile/create_links.py +77 -20
  25. machineconfig/profile/create_links_export.py +40 -51
  26. machineconfig/profile/mapper_data.toml +30 -0
  27. machineconfig/profile/mapper_dotfiles.toml +253 -0
  28. machineconfig/scripts/python/agents.py +70 -172
  29. machineconfig/scripts/python/ai/initai.py +3 -1
  30. machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
  31. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
  32. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +7 -5
  33. machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
  34. machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
  35. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +1 -1
  36. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +29 -0
  37. machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
  38. machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
  39. machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
  40. machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
  41. machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
  42. machineconfig/scripts/python/ai/utils/vscode_tasks.py +6 -3
  43. machineconfig/scripts/python/cloud.py +58 -11
  44. machineconfig/scripts/python/croshell.py +4 -156
  45. machineconfig/scripts/python/devops.py +57 -40
  46. machineconfig/scripts/python/devops_navigator.py +17 -3
  47. machineconfig/scripts/python/fire_jobs.py +8 -207
  48. machineconfig/scripts/python/ftpx.py +5 -225
  49. machineconfig/scripts/python/graph/cli_graph.json +8743 -0
  50. machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
  51. machineconfig/scripts/python/{env_manager → helpers/helper_env}/env_manager_tui.py +1 -1
  52. machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
  53. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.py +1 -1
  54. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
  55. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_gemini.py +1 -1
  56. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_qwen.py +1 -1
  57. machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
  58. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_launch.py +5 -5
  59. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +6 -6
  60. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +10 -5
  61. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +3 -3
  62. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
  63. machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +225 -0
  64. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
  65. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +7 -6
  66. machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
  67. machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +267 -0
  68. machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +98 -0
  69. machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
  70. machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +76 -0
  71. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_nw.py +52 -72
  72. machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +265 -0
  73. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_self.py +39 -23
  74. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_file.py +44 -30
  75. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_server.py +26 -43
  76. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_terminal.py +12 -6
  77. machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
  78. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +12 -6
  79. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
  80. machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +68 -52
  81. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/run_script.py +75 -58
  82. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
  83. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
  84. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +3 -3
  85. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
  86. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +3 -3
  87. machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
  88. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_linux/fzfg +4 -3
  89. machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
  90. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_windows/fzfg.ps1 +1 -1
  91. machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
  92. machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
  93. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
  94. machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
  95. machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
  96. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
  97. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
  98. machineconfig/scripts/python/helpers/helpers_network/__init__.py +0 -0
  99. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address.py +15 -17
  100. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address_switch.py +1 -1
  101. machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
  102. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_ssh.py +2 -2
  103. machineconfig/scripts/python/helpers/helpers_network/ssh_add_identity.py +73 -0
  104. machineconfig/scripts/python/helpers/helpers_network/ssh_add_ssh_key.py +175 -0
  105. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_linux.py +319 -0
  106. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_windows.py +275 -0
  107. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
  108. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
  109. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +116 -33
  110. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +3 -2
  111. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -13
  112. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_2.py +63 -19
  113. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
  114. machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
  115. machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
  116. machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +177 -0
  117. machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +1 -1
  118. machineconfig/scripts/python/helpers/helpers_terminal/__init__.py +0 -0
  119. machineconfig/scripts/python/helpers/helpers_terminal/terminal_impl.py +96 -0
  120. machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/download.py +1 -1
  121. machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/python.py +46 -26
  122. machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
  123. machineconfig/scripts/python/mcfg_entry.py +133 -48
  124. machineconfig/scripts/python/msearch.py +15 -61
  125. machineconfig/scripts/python/sessions.py +59 -194
  126. machineconfig/scripts/python/terminal.py +18 -96
  127. machineconfig/scripts/python/utils.py +101 -20
  128. machineconfig/settings/atuin/config.toml +294 -0
  129. machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
  130. machineconfig/settings/linters/.ruff.toml +1 -0
  131. machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
  132. machineconfig/settings/shells/bash/init.sh +6 -3
  133. machineconfig/settings/shells/pwsh/init.ps1 +69 -1
  134. machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
  135. machineconfig/settings/shells/wezterm/wezterm.lua +4 -1
  136. machineconfig/settings/shells/wt/settings.json +20 -7
  137. machineconfig/settings/shells/zsh/init.sh +34 -4
  138. machineconfig/settings/television/cable_unix/bash-history.toml +1 -1
  139. machineconfig/settings/television/cable_windows/pwsh-history.toml +1 -1
  140. machineconfig/settings/tv/config.toml +234 -0
  141. machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
  142. machineconfig/settings/wsl/.wslconfig +5 -30
  143. machineconfig/settings/yazi/yazi_linux.toml +18 -8
  144. machineconfig/settings/zellij/layouts/st.kdl +2 -2
  145. machineconfig/settings/zellij/layouts/st2.kdl +1 -1
  146. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  147. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +3 -0
  148. machineconfig/setup_mac/__init__.py +0 -2
  149. machineconfig/setup_windows/__init__.py +0 -1
  150. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +14 -13
  151. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +4 -3
  152. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -3
  153. machineconfig/type_hinting/sql/__init__.py +1 -0
  154. machineconfig/type_hinting/sql/base.py +216 -0
  155. machineconfig/type_hinting/sql/core_schema.py +64 -0
  156. machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
  157. machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
  158. machineconfig/type_hinting/typedict/__init__.py +1 -0
  159. machineconfig/type_hinting/typedict/ast_utils.py +130 -0
  160. machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
  161. machineconfig/type_hinting/typedict/generators.py +231 -0
  162. machineconfig/type_hinting/typedict/polars_schema.py +24 -0
  163. machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
  164. machineconfig/utils/accessories.py +24 -0
  165. machineconfig/utils/code.py +41 -13
  166. machineconfig/utils/files/ascii_art.py +10 -14
  167. machineconfig/utils/files/headers.py +3 -5
  168. machineconfig/utils/files/read.py +8 -1
  169. machineconfig/utils/installer_utils/github_release_bulk.py +1 -0
  170. machineconfig/utils/installer_utils/install_from_url.py +1 -1
  171. machineconfig/utils/installer_utils/installer_class.py +12 -4
  172. machineconfig/utils/installer_utils/installer_cli.py +1 -15
  173. machineconfig/utils/installer_utils/installer_helper.py +2 -2
  174. machineconfig/utils/installer_utils/installer_locator_utils.py +13 -13
  175. machineconfig/utils/installer_utils/installer_runner.py +4 -4
  176. machineconfig/utils/meta.py +6 -4
  177. machineconfig/utils/options.py +49 -19
  178. machineconfig/utils/options_utils/__init__.py +0 -0
  179. machineconfig/utils/options_utils/options_tv_linux.py +211 -0
  180. machineconfig/utils/options_utils/options_tv_windows.py +88 -0
  181. machineconfig/utils/options_utils/tv_options.py +37 -0
  182. machineconfig/utils/path_extended.py +6 -6
  183. machineconfig/utils/scheduler.py +8 -2
  184. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  185. machineconfig/utils/source_of_truth.py +6 -1
  186. machineconfig/utils/ssh.py +69 -18
  187. machineconfig/utils/ssh_utils/abc.py +1 -1
  188. machineconfig/utils/ssh_utils/wsl.py +107 -170
  189. machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
  190. machineconfig/utils/upgrade_packages.py +4 -8
  191. {machineconfig-8.14.dist-info → machineconfig-8.45.dist-info}/METADATA +29 -22
  192. {machineconfig-8.14.dist-info → machineconfig-8.45.dist-info}/RECORD +247 -208
  193. machineconfig/jobs/installer/check_installations.py +0 -248
  194. machineconfig/profile/backup.toml +0 -49
  195. machineconfig/profile/mapper.toml +0 -263
  196. machineconfig/scripts/python/helpers_devops/cli_config.py +0 -105
  197. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -89
  198. machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
  199. machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -208
  200. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
  201. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
  202. machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
  203. machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
  204. machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -620
  205. machineconfig/scripts/python/helpers_network/ssh_add_identity.py +0 -116
  206. machineconfig/scripts/python/helpers_network/ssh_add_ssh_key.py +0 -153
  207. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +0 -391
  208. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +0 -338
  209. machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -77
  210. machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
  211. machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
  212. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
  213. machineconfig/utils/options_tv.py +0 -119
  214. machineconfig/utils/tst.py +0 -20
  215. /machineconfig/{scripts/python/helpers_agents → jobs/installer/checks}/__init__.py +0 -0
  216. /machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
  217. /machineconfig/scripts/python/{helpers_agents/agentic_frameworks → graph}/__init__.py +0 -0
  218. /machineconfig/scripts/python/{helpers_cloud → helpers}/__init__.py +0 -0
  219. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
  220. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
  221. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_agents}/__init__.py +0 -0
  222. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_agents/agentic_frameworks}/__init__.py +0 -0
  223. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
  224. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
  225. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_helper_types.py +0 -0
  226. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
  227. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aichat/config.yaml +0 -0
  228. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aider/.aider.conf.yml +0 -0
  229. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/copilot/config.yml +0 -0
  230. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/crush/crush.json +0 -0
  231. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/gemini/settings.json +0 -0
  232. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/privacy.py +0 -0
  233. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/prompt.txt +0 -0
  234. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.ps1 +0 -0
  235. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.sh +0 -0
  236. /machineconfig/scripts/python/{helpers_devops/themes → helpers/helpers_cloud}/__init__.py +0 -0
  237. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +0 -0
  238. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
  239. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_croshell}/__init__.py +0 -0
  240. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +0 -0
  241. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
  242. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
  243. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
  244. /machineconfig/scripts/python/{helpers_network → helpers/helpers_devops}/__init__.py +0 -0
  245. /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_devops/themes}/__init__.py +0 -0
  246. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  247. /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_fire_command/__init__.py} +0 -0
  248. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
  249. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/f.py +0 -0
  250. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/file_wrangler.py +0 -0
  251. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +0 -0
  252. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_streamlit_helper.py +0 -0
  253. /machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/__init__.py +0 -0
  254. /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
  255. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nfs.py +0 -0
  256. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nw_drive.py +0 -0
  257. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/onetimeshare.py +0 -0
  258. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/wifi_conn.py +0 -0
  259. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -0
  260. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_1.py +0 -0
  261. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
  262. /machineconfig/scripts/python/helpers/{ast_search.py → helpers_search/ast_search.py} +0 -0
  263. /machineconfig/scripts/python/helpers/{qr_code.py → helpers_search/qr_code.py} +0 -0
  264. /machineconfig/scripts/python/helpers/{repo_rag.py → helpers_search/repo_rag.py} +0 -0
  265. /machineconfig/scripts/python/helpers/{symantic_search.py → helpers_search/symantic_search.py} +0 -0
  266. /machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/pdf.py +0 -0
  267. {machineconfig-8.14.dist-info → machineconfig-8.45.dist-info}/WHEEL +0 -0
  268. {machineconfig-8.14.dist-info → machineconfig-8.45.dist-info}/entry_points.txt +0 -0
  269. {machineconfig-8.14.dist-info → machineconfig-8.45.dist-info}/top_level.txt +0 -0
@@ -58,7 +58,7 @@
58
58
 
59
59
  # # Execute each job sequentially (replace former List.apply behavior)
60
60
  # # If parallel execution is needed, consider a ThreadPool/ProcessPool
61
- # results: List[PathExtended] = [
61
+ # results: List[Path] = [
62
62
  # ExpensiveComputation.func_single_job(workload_params=job_params, **kwargs)
63
63
  # for job_params in per_job_workload_params
64
64
  # ]
@@ -7,7 +7,7 @@
7
7
  # from machineconfig.cluster.remote_machine import RemoteMachine, RemoteMachineConfig, WorkloadParams
8
8
  # from machineconfig.cluster.templates.utils import expensive_function
9
9
  # # from machineconfig.cluster.self_ssh import SelfSSH
10
- # data: list[PathExtended] = []
10
+ # data: list[Path] = []
11
11
  # config = RemoteMachineConfig(
12
12
  # # connection
13
13
  # # ssh_obj=SelfSSH(), # overrides ssh_params
@@ -4,7 +4,7 @@ from typing import Optional, Literal
4
4
  from machineconfig.utils.schemas.layouts.layout_types import TabConfig, LayoutConfig
5
5
  from pathlib import Path
6
6
 
7
- def get_fire_tab_using_uv(func: FunctionType, tab_weight: int, import_module: bool, uv_with: Optional[list[str]], uv_project_dir: Optional[str]) -> tuple[TabConfig, Path]:
7
+ def get_fire_tab_using_uv(func: FunctionType, tab_weight: int, import_module: bool, uv_with: Optional[list[str]], uv_project_dir: Optional[str], start_dir: str) -> tuple[TabConfig, Path]:
8
8
  from machineconfig.utils.meta import lambda_to_python_script
9
9
  if func.__name__ == "<lambda>":
10
10
  py_script = lambda_to_python_script(func,
@@ -16,12 +16,12 @@ def get_fire_tab_using_uv(func: FunctionType, tab_weight: int, import_module: bo
16
16
  command_to_run, py_script_path = get_uv_command_executing_python_script(python_script=py_script, uv_with=uv_with, uv_project_dir=uv_project_dir)
17
17
  tab_config: TabConfig = {
18
18
  "command": command_to_run,
19
- "startDir": "$HOME",
19
+ "startDir": start_dir,
20
20
  "tabName": func.__name__,
21
21
  "tabWeight": tab_weight
22
22
  }
23
23
  return tab_config, py_script_path
24
- def get_fire_tab_using_fire(func: FunctionType, tab_weight: int) -> TabConfig:
24
+ def get_fire_tab_using_fire(func: FunctionType, tab_weight: int, start_dir: str) -> TabConfig:
25
25
  import inspect
26
26
  from machineconfig.utils.source_of_truth import CONFIG_ROOT
27
27
  import platform
@@ -37,7 +37,7 @@ def get_fire_tab_using_fire(func: FunctionType, tab_weight: int) -> TabConfig:
37
37
  command_to_run = f"""{wrap_mcfg} fire {path_relative} {func.__name__} """
38
38
  tab_config: TabConfig = {
39
39
  "command": command_to_run,
40
- "startDir": "$HOME",
40
+ "startDir": start_dir,
41
41
  "tabName": func.__name__,
42
42
  "tabWeight": tab_weight
43
43
  }
@@ -45,20 +45,22 @@ def get_fire_tab_using_fire(func: FunctionType, tab_weight: int) -> TabConfig:
45
45
 
46
46
 
47
47
 
48
- def make_layout_from_functions(functions: list[FunctionType], functions_weights: Optional[list[int]], import_module: bool, tab_configs: list[TabConfig],
48
+ def make_layout_from_functions(functions: list[FunctionType], functions_weights: Optional[list[int]],
49
+ import_module: bool, tab_configs: list[TabConfig],
49
50
  layout_name: str, method: Literal["script", "fire"],
50
- uv_with: Optional[list[str]] = None, uv_project_dir: Optional[str] = None
51
+ uv_with: Optional[list[str]], uv_project_dir: Optional[str],
52
+ start_dir: str
51
53
  ) -> LayoutConfig:
52
54
  tabs2artifacts: list[tuple[TabConfig, list[Path]]] = []
53
55
  for a_func, tab_weight in zip(functions, functions_weights or [1]*len(functions)):
54
56
  match method:
55
57
  case "script":
56
58
  tab_config, artifact_files_1 = get_fire_tab_using_uv(a_func, tab_weight=tab_weight, import_module=import_module,
57
- uv_with=uv_with, uv_project_dir=uv_project_dir
59
+ uv_with=uv_with, uv_project_dir=uv_project_dir, start_dir=start_dir
58
60
  )
59
61
  artifact_files = [artifact_files_1]
60
62
  case "fire":
61
- tab_config = get_fire_tab_using_fire(a_func, tab_weight=tab_weight)
63
+ tab_config = get_fire_tab_using_fire(a_func, tab_weight=tab_weight, start_dir=start_dir)
62
64
  artifact_files = []
63
65
  tabs2artifacts.append((tab_config, artifact_files))
64
66
  list_of_tabs = [tab for tab, _ in tabs2artifacts] + tab_configs
@@ -206,7 +206,7 @@ if __name__ == "__main__":
206
206
  sample_layout: LayoutConfig = {"layoutName": "TestLayout",
207
207
  "layoutTabs": [
208
208
  {"tabName": "Frontend", "startDir": "~/code", "command": "btm"},
209
- {"tabName": "Monitor", "startDir": "~", "command": "lf"}
209
+ {"tabName": "Monitor", "startDir": "~", "command": "yazi"},
210
210
  ]}
211
211
  try:
212
212
  session_name = sample_layout["layoutName"]
@@ -333,7 +333,7 @@ if __name__ == "__main__":
333
333
  {
334
334
  "layoutName": "DevelopmentEnv",
335
335
  "layoutTabs": [
336
- {"tabName": "🚀Frontend", "startDir": "~/code/myapp/frontend", "command": "npm run dev"},
336
+ {"tabName": "🚀Frontend", "startDir": "~/code/myapp/frontend", "command": "bun run dev"},
337
337
  {"tabName": "⚙️Backend", "startDir": "~/code/myapp/backend", "command": "python manage.py runserver"},
338
338
  {"tabName": "📊Monitor", "startDir": "~", "command": "Get-Process | Sort-Object CPU -Descending | Select-Object -First 10"},
339
339
  ],
@@ -206,7 +206,7 @@ if __name__ == "__main__":
206
206
  # Example usage with new schema
207
207
  sample_layout: LayoutConfig = {
208
208
  "layoutName": "SampleBots",
209
- "layoutTabs": [{"tabName": "Explorer", "startDir": "~/code", "command": "lf"}, {"tabName": "🤖Bot2", "startDir": "~", "command": "cmatrix"}, {"tabName": "📊Monitor", "startDir": "~", "command": "htop"}, {"tabName": "📝Logs", "startDir": "/var/log", "command": "tail -f /var/log/app.log"}],
209
+ "layoutTabs": [{"tabName": "Explorer", "startDir": "~/code", "command": "yazi"}, {"tabName": "🤖Bot2", "startDir": "~", "command": "cmatrix"}, {"tabName": "📊Monitor", "startDir": "~", "command": "htop"}, {"tabName": "📝Logs", "startDir": "/var/log", "command": "tail -f /var/log/app.log"}],
210
210
  }
211
211
  try:
212
212
  # Create layout using the generator with new design
@@ -314,7 +314,7 @@ if __name__ == "__main__":
314
314
  {
315
315
  "layoutName": "Development",
316
316
  "layoutTabs": [
317
- {"tabName": "🚀Frontend", "startDir": "~/code/myapp/frontend", "command": "npm run dev"},
317
+ {"tabName": "🚀Frontend", "startDir": "~/code/myapp/frontend", "command": "bun run dev"},
318
318
  {"tabName": "⚙️Backend", "startDir": "~/code/myapp/backend", "command": "python manage.py runserver"},
319
319
  {"tabName": "📊Monitor", "startDir": "~", "command": "htop"},
320
320
  ],
@@ -0,0 +1,133 @@
1
+ """
2
+ Check Installations
3
+ ===================
4
+
5
+ This module scans installed applications using VirusTotal and generates a safety report.
6
+ It also provides functionality to download and install pre-checked applications.
7
+ """
8
+
9
+ import csv
10
+ import platform
11
+ from datetime import datetime
12
+ from typing import Optional
13
+
14
+ from rich.console import Console
15
+ from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn
16
+
17
+ from machineconfig.jobs.installer.checks.install_utils import upload_app
18
+ from machineconfig.jobs.installer.checks.report_utils import AppData, generate_markdown_report
19
+ from machineconfig.jobs.installer.checks.vt_utils import get_vt_client, scan_file
20
+ from machineconfig.utils.installer_utils.installer_runner import get_installed_cli_apps
21
+ from machineconfig.utils.path_extended import PathExtended
22
+ from machineconfig.utils.source_of_truth import CONFIG_ROOT, INSTALL_VERSION_ROOT
23
+
24
+ # Constants
25
+ APP_SUMMARY_PATH = CONFIG_ROOT.joinpath(f"profile/records/{platform.system().lower()}/apps_summary_report.csv")
26
+
27
+ console = Console()
28
+
29
+ def main() -> None:
30
+ """Main execution function."""
31
+ console.rule("[bold blue]MachineConfig Installation Checker[/bold blue]")
32
+
33
+ # 1. Gather Installed Apps
34
+ with console.status("[bold green]Gathering installed applications...[/bold green]"):
35
+ apps_paths = get_installed_cli_apps()
36
+ # Filter and find versions
37
+ # This part mimics the original logic but simplifies it
38
+ # We assume apps_paths contains PathExtended objects
39
+
40
+ # Find version files
41
+ install_version_root_ext = PathExtended(INSTALL_VERSION_ROOT)
42
+ version_files = list(install_version_root_ext.search()) if install_version_root_ext.exists() else []
43
+
44
+ apps_to_scan: list[tuple[PathExtended, Optional[str]]] = []
45
+
46
+ for app_path in apps_paths:
47
+ # Try to find version
48
+ version = None
49
+ # Simple matching logic: check if any version file matches the app name
50
+ # This is a heuristic from the original code
51
+ matching_versions = [v for v in version_files if v.stem == app_path.stem]
52
+ if matching_versions:
53
+ version = matching_versions[0].read_text(encoding="utf-8").strip()
54
+
55
+ apps_to_scan.append((app_path, version))
56
+
57
+ console.print(f"[green]Found {len(apps_to_scan)} applications to check.[/green]")
58
+
59
+ # 2. Scan Apps with VirusTotal
60
+ app_data_list: list[AppData] = []
61
+
62
+ try:
63
+ client = get_vt_client()
64
+
65
+ with Progress(
66
+ SpinnerColumn(),
67
+ TextColumn("[progress.description]{task.description}"),
68
+ BarColumn(),
69
+ TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
70
+ console=console
71
+ ) as progress:
72
+ scan_task = progress.add_task("[cyan]Scanning apps...", total=len(apps_to_scan))
73
+
74
+ for app_path, version in apps_to_scan:
75
+ progress.update(scan_task, description=f"Scanning {app_path.name}...")
76
+
77
+ positive_pct, _ = scan_file(app_path, client, progress, scan_task)
78
+
79
+ # Upload if safe (optional, based on original code logic which uploaded everything?)
80
+ # Original code uploaded everything.
81
+ progress.update(scan_task, description=f"Uploading {app_path.name}...")
82
+ app_url = upload_app(app_path) or ""
83
+
84
+ app_data_list.append({
85
+ "app_name": app_path.stem,
86
+ "version": version,
87
+ "positive_pct": positive_pct,
88
+ "scan_time": datetime.now().strftime("%Y-%m-%d %H:%M"),
89
+ "app_path": app_path.collapseuser(strict=False).as_posix(),
90
+ "app_url": app_url
91
+ })
92
+
93
+ progress.advance(scan_task)
94
+
95
+ except FileNotFoundError as e:
96
+ console.print(f"[bold red]{e}[/bold red]")
97
+ console.print("[yellow]Skipping scanning due to missing credentials.[/yellow]")
98
+ # Fallback: just list apps without scan results
99
+ for app_path, version in apps_to_scan:
100
+ app_data_list.append({
101
+ "app_name": app_path.stem,
102
+ "version": version,
103
+ "positive_pct": None,
104
+ "scan_time": datetime.now().strftime("%Y-%m-%d %H:%M"),
105
+ "app_path": app_path.collapseuser(strict=False).as_posix(),
106
+ "app_url": ""
107
+ })
108
+ except Exception as e:
109
+ console.print(f"[bold red]An unexpected error occurred during scanning: {e}[/bold red]")
110
+
111
+ # 3. Generate Reports
112
+ if app_data_list:
113
+ # CSV Report
114
+ APP_SUMMARY_PATH.parent.mkdir(parents=True, exist_ok=True)
115
+ csv_path = APP_SUMMARY_PATH.with_suffix(".csv")
116
+
117
+ with open(csv_path, 'w', newline='', encoding='utf-8') as csvfile:
118
+ fieldnames = list(app_data_list[0].keys())
119
+ writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
120
+ writer.writeheader()
121
+ writer.writerows(app_data_list)
122
+
123
+ console.print(f"[green]CSV report saved to: {csv_path}[/green]")
124
+
125
+ # Markdown Report
126
+ md_path = APP_SUMMARY_PATH.with_suffix(".md")
127
+ generate_markdown_report(app_data_list, md_path)
128
+ console.print(f"[green]Markdown report saved to: {md_path}[/green]")
129
+
130
+
131
+
132
+ if __name__ == '__main__':
133
+ main()
@@ -0,0 +1,132 @@
1
+ """
2
+ Installation Utilities
3
+ ======================
4
+
5
+ This module provides functionality to download and install pre-checked applications.
6
+ """
7
+
8
+ import csv
9
+ import platform
10
+ from concurrent.futures import ThreadPoolExecutor
11
+ from pathlib import Path
12
+ from typing import Any, Optional
13
+
14
+ import gdown
15
+ from rich.console import Console
16
+
17
+ from machineconfig.utils.path_extended import PathExtended
18
+ from machineconfig.utils.source_of_truth import CONFIG_ROOT
19
+
20
+ # Constants
21
+ APP_SUMMARY_PATH = CONFIG_ROOT.joinpath(f"profile/records/{platform.system().lower()}/apps_summary_report.csv")
22
+ CLOUD_STORAGE_NAME = "gdw" # Default cloud storage name for rclone
23
+
24
+ console = Console()
25
+
26
+ def upload_app(path: PathExtended) -> Optional[str]:
27
+ """Uploads the app to cloud storage and returns the shareable link."""
28
+ try:
29
+ # Using PathExtended.to_cloud
30
+ # Assuming 'gdw' is the configured remote in rclone
31
+ link_path = path.to_cloud(CLOUD_STORAGE_NAME, rel2home=True, share=True, os_specific=True, verbose=False)
32
+ if link_path:
33
+ return str(link_path)
34
+ return None
35
+ except Exception as e:
36
+ console.print(f"[red]Failed to upload {path}: {e}[/red]")
37
+ return None
38
+
39
+ def download_google_drive_file(url: str) -> PathExtended:
40
+ """Downloads a file from Google Drive using gdown."""
41
+ try:
42
+ # Extract ID from URL
43
+ # Assuming URL format like https://drive.google.com/file/d/FILE_ID/view or similar
44
+ # or https://drive.google.com/uc?id=FILE_ID
45
+ if "id=" in url:
46
+ file_id = url.split("id=")[1].split("&")[0]
47
+ elif "/d/" in url:
48
+ file_id = url.split("/d/")[1].split("/")[0]
49
+ else:
50
+ # Fallback to gdown's auto detection or just pass URL
51
+ file_id = url
52
+
53
+ # Create a temporary directory for download
54
+ output_dir = PathExtended.tmpdir(prefix="gdown_")
55
+ # gdown.download returns the output filename
56
+ output_file = gdown.download(id=file_id, output=str(output_dir) + "/", quiet=False, fuzzy=True)
57
+
58
+ if not output_file:
59
+ raise ValueError(f"Download failed for {url}")
60
+
61
+ return PathExtended(output_file)
62
+ except Exception as e:
63
+ raise RuntimeError(f"Failed to download from Google Drive: {e}") from e
64
+
65
+ def install_cli_app(app_url: str) -> bool:
66
+ """Downloads and installs a CLI app."""
67
+ try:
68
+ if not app_url:
69
+ return False
70
+
71
+ exe_path = download_google_drive_file(app_url)
72
+ console.print(f"[green]Downloaded {exe_path.name}[/green]")
73
+
74
+ system = platform.system().lower()
75
+ if system in ["linux", "darwin"]:
76
+ exe_path.chmod(0o755) # Make executable
77
+ # Move to local bin (requires user to have write access or sudo, which we can't easily do here without interaction)
78
+ # Using ~/.local/bin is safer
79
+ install_path = Path.home() / ".local/bin"
80
+ install_path.mkdir(parents=True, exist_ok=True)
81
+ target = install_path / exe_path.name
82
+ exe_path.rename(target)
83
+ console.print(f"[green]Installed to {target}[/green]")
84
+ elif system == "windows":
85
+ install_path = Path.home() / "AppData/Local/Microsoft/WindowsApps"
86
+ install_path.mkdir(parents=True, exist_ok=True)
87
+ target = install_path / exe_path.name
88
+ # Use shutil.move or PathExtended.move
89
+ exe_path.move(path=target, overwrite=True)
90
+ console.print(f"[green]Installed to {target}[/green]")
91
+
92
+ return True
93
+ except Exception as e:
94
+ console.print(f"[red]Failed to install app from {app_url}: {e}[/red]")
95
+ return False
96
+
97
+ def load_summary_report() -> list[dict[str, Any]]:
98
+ """Loads the summary report from CSV."""
99
+ if APP_SUMMARY_PATH.exists():
100
+ with open(APP_SUMMARY_PATH, 'r', encoding='utf-8') as csvfile:
101
+ reader = csv.DictReader(csvfile)
102
+ return list(reader)
103
+ else:
104
+ console.print(f"[yellow]Warning: Summary report not found at {APP_SUMMARY_PATH}[/yellow]")
105
+ return []
106
+
107
+ def download_safe_apps(name: str = "essentials") -> None:
108
+ """Downloads and installs safe apps."""
109
+ data = load_summary_report()
110
+ if not data:
111
+ console.print("[red]No app data available to install.[/red]")
112
+ return
113
+
114
+ apps_to_install = []
115
+ if name == "essentials":
116
+ # Install all available apps in the report? Or filter?
117
+ # Original code installed all if name="essentials" (implied by logic)
118
+ apps_to_install = [item['app_url'] for item in data if item.get('app_url')]
119
+ else:
120
+ apps_to_install = [item['app_url'] for item in data if item.get('app_name') == name and item.get('app_url')]
121
+
122
+ if not apps_to_install:
123
+ console.print(f"[yellow]No apps found to install for '{name}'.[/yellow]")
124
+ return
125
+
126
+ console.print(f"[bold]Installing {len(apps_to_install)} apps...[/bold]")
127
+
128
+ with ThreadPoolExecutor(max_workers=5) as executor:
129
+ results = list(executor.map(install_cli_app, apps_to_install))
130
+
131
+ success_count = sum(results)
132
+ console.print(f"[bold green]Successfully installed {success_count}/{len(apps_to_install)} apps.[/bold green]")
@@ -0,0 +1,39 @@
1
+ """
2
+ Report Utilities
3
+ ================
4
+
5
+ This module provides functionality to generate reports for installed applications.
6
+ """
7
+
8
+ from pathlib import Path
9
+ from typing import Optional, TypedDict
10
+ from rich.console import Console
11
+ from rich.panel import Panel
12
+
13
+ console = Console()
14
+
15
+ class AppData(TypedDict):
16
+ app_name: str
17
+ version: Optional[str]
18
+ positive_pct: Optional[float]
19
+ scan_time: str
20
+ app_path: str
21
+ app_url: str
22
+
23
+ def generate_markdown_report(data: list[AppData], output_path: Path) -> None:
24
+ """Generates a Markdown table from the app data."""
25
+ if not data:
26
+ return
27
+
28
+ keys = list(data[0].keys())
29
+ header = "| " + " | ".join(key.replace("_", " ").title() for key in keys) + " |"
30
+ separator = "| " + " | ".join("---" for _ in keys) + " |"
31
+ rows = []
32
+ for row in data:
33
+ # Fix: row is a dict, keys are strings.
34
+ row_values = [str(row.get(key, '')) for key in keys]
35
+ rows.append("| " + " | ".join(row_values) + " |")
36
+
37
+ content = "\n".join([header, separator] + rows)
38
+ output_path.write_text(content, encoding="utf-8")
39
+ console.print(Panel(content, title="Safety Report Summary", expand=False))
@@ -0,0 +1,89 @@
1
+ """
2
+ VirusTotal Utilities
3
+ ====================
4
+
5
+ This module provides functionality to interact with VirusTotal API.
6
+ """
7
+
8
+ import time
9
+ from pathlib import Path
10
+ from typing import Any, Optional, TypedDict
11
+
12
+ import vt
13
+ from rich.progress import Progress, TaskID
14
+
15
+ # Constants
16
+ VT_TOKEN_PATH = Path.home().joinpath("dotfiles/creds/tokens/virustotal")
17
+
18
+ class ScanResult(TypedDict):
19
+ result: Optional[str]
20
+ category: str
21
+
22
+ def get_vt_client() -> vt.Client:
23
+ """Retrieves the VirusTotal client using the token from the credentials file."""
24
+ if not VT_TOKEN_PATH.exists():
25
+ raise FileNotFoundError(f"VirusTotal token not found at {VT_TOKEN_PATH}")
26
+
27
+ token = VT_TOKEN_PATH.read_text(encoding="utf-8").split("\n")[0].strip()
28
+ return vt.Client(token)
29
+
30
+ def scan_file(path: Path, client: vt.Client, progress: Optional[Progress] = None, task_id: Optional[TaskID] = None) -> tuple[Optional[float], list[Any]]:
31
+ """
32
+ Scans a file using VirusTotal.
33
+
34
+ Args:
35
+ path: Path to the file to scan.
36
+ client: VirusTotal client instance.
37
+ progress: Optional Rich progress bar.
38
+ task_id: Optional Task ID for the progress bar.
39
+
40
+ Returns:
41
+ A tuple containing the positive percentage (0-100) and the list of result details.
42
+ Returns (None, []) if scanning fails or file is skipped.
43
+ """
44
+ if path.is_dir():
45
+ if progress and task_id:
46
+ progress.console.print(f"[yellow]📁 Skipping directory: {path}[/yellow]")
47
+ return None, []
48
+
49
+ try:
50
+ with open(path, "rb") as f:
51
+ analysis = client.scan_file(f)
52
+
53
+ repeat_counter = 0
54
+ while True:
55
+ try:
56
+ anal = client.get_object("/analyses/{}", analysis.id)
57
+ if anal.status == "completed":
58
+ break
59
+ except Exception as e:
60
+ repeat_counter += 1
61
+ if repeat_counter > 3:
62
+ raise ValueError(f"❌ Error scanning {path}: {e}") from e
63
+ if progress and task_id:
64
+ progress.console.print(f"[red]⚠️ Error scanning {path}, retrying... ({repeat_counter}/3)[/red]")
65
+ time.sleep(5)
66
+
67
+ time.sleep(10) # Wait before checking status again
68
+
69
+ # Process results
70
+ results_data = list(anal.results.values())
71
+ malicious = []
72
+ for result_item in results_data:
73
+ result_dict = result_item.__dict__ if hasattr(result_item, '__dict__') else {
74
+ 'result': getattr(result_item, 'result', None),
75
+ 'category': getattr(result_item, 'category', 'unknown')
76
+ }
77
+
78
+ if result_dict.get('result') is None and result_dict.get('category') in ["undetected", "type-unsupported", "failure", "timeout", "confirmed-timeout"]:
79
+ continue
80
+
81
+ malicious.append(result_item)
82
+
83
+ positive_pct = round(len(malicious) / len(results_data) * 100, 1) if results_data else 0.0
84
+ return positive_pct, results_data
85
+
86
+ except Exception as e:
87
+ if progress and task_id:
88
+ progress.console.print(f"[bold red]❌ Failed to scan {path}: {e}[/bold red]")
89
+ return None, []