machineconfig 8.14__py3-none-any.whl → 8.50__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 (273) 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 +63 -58
  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 +274 -0
  73. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_self.py +40 -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 +117 -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 +186 -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 +47 -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 +25 -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 +11 -91
  170. machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
  171. machineconfig/utils/installer_utils/install_from_url.py +1 -1
  172. machineconfig/utils/installer_utils/installer_class.py +12 -4
  173. machineconfig/utils/installer_utils/installer_cli.py +1 -15
  174. machineconfig/utils/installer_utils/installer_helper.py +2 -2
  175. machineconfig/utils/installer_utils/installer_locator_utils.py +13 -13
  176. machineconfig/utils/installer_utils/installer_runner.py +4 -4
  177. machineconfig/utils/io.py +25 -8
  178. machineconfig/utils/meta.py +6 -4
  179. machineconfig/utils/options.py +49 -19
  180. machineconfig/utils/options_utils/__init__.py +0 -0
  181. machineconfig/utils/options_utils/options_tv_linux.py +211 -0
  182. machineconfig/utils/options_utils/options_tv_windows.py +88 -0
  183. machineconfig/utils/options_utils/tv_options.py +37 -0
  184. machineconfig/utils/path_extended.py +6 -6
  185. machineconfig/utils/scheduler.py +8 -2
  186. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  187. machineconfig/utils/source_of_truth.py +6 -1
  188. machineconfig/utils/ssh.py +69 -18
  189. machineconfig/utils/ssh_utils/abc.py +1 -1
  190. machineconfig/utils/ssh_utils/copy_from_here.py +17 -12
  191. machineconfig/utils/ssh_utils/utils.py +21 -5
  192. machineconfig/utils/ssh_utils/wsl.py +107 -170
  193. machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
  194. machineconfig/utils/upgrade_packages.py +4 -8
  195. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/METADATA +29 -22
  196. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/RECORD +251 -211
  197. machineconfig/jobs/installer/check_installations.py +0 -248
  198. machineconfig/profile/backup.toml +0 -49
  199. machineconfig/profile/mapper.toml +0 -263
  200. machineconfig/scripts/python/helpers_devops/cli_config.py +0 -105
  201. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -89
  202. machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
  203. machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -208
  204. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
  205. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
  206. machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
  207. machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
  208. machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -620
  209. machineconfig/scripts/python/helpers_network/ssh_add_identity.py +0 -116
  210. machineconfig/scripts/python/helpers_network/ssh_add_ssh_key.py +0 -153
  211. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +0 -391
  212. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +0 -338
  213. machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -77
  214. machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
  215. machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
  216. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
  217. machineconfig/utils/options_tv.py +0 -119
  218. machineconfig/utils/tst.py +0 -20
  219. /machineconfig/{scripts/python/helpers_agents → jobs/installer/checks}/__init__.py +0 -0
  220. /machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
  221. /machineconfig/scripts/python/{helpers_agents/agentic_frameworks → graph}/__init__.py +0 -0
  222. /machineconfig/scripts/python/{helpers_cloud → helpers}/__init__.py +0 -0
  223. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
  224. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
  225. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_agents}/__init__.py +0 -0
  226. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_agents/agentic_frameworks}/__init__.py +0 -0
  227. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
  228. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
  229. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_helper_types.py +0 -0
  230. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
  231. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aichat/config.yaml +0 -0
  232. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aider/.aider.conf.yml +0 -0
  233. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/copilot/config.yml +0 -0
  234. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/crush/crush.json +0 -0
  235. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/gemini/settings.json +0 -0
  236. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/privacy.py +0 -0
  237. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/prompt.txt +0 -0
  238. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.ps1 +0 -0
  239. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.sh +0 -0
  240. /machineconfig/scripts/python/{helpers_devops/themes → helpers/helpers_cloud}/__init__.py +0 -0
  241. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +0 -0
  242. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
  243. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_croshell}/__init__.py +0 -0
  244. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +0 -0
  245. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
  246. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
  247. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
  248. /machineconfig/scripts/python/{helpers_network → helpers/helpers_devops}/__init__.py +0 -0
  249. /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_devops/themes}/__init__.py +0 -0
  250. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  251. /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_fire_command/__init__.py} +0 -0
  252. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
  253. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/f.py +0 -0
  254. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/file_wrangler.py +0 -0
  255. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +0 -0
  256. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_streamlit_helper.py +0 -0
  257. /machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/__init__.py +0 -0
  258. /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
  259. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nfs.py +0 -0
  260. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nw_drive.py +0 -0
  261. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/onetimeshare.py +0 -0
  262. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/wifi_conn.py +0 -0
  263. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -0
  264. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_1.py +0 -0
  265. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
  266. /machineconfig/scripts/python/helpers/{ast_search.py → helpers_search/ast_search.py} +0 -0
  267. /machineconfig/scripts/python/helpers/{qr_code.py → helpers_search/qr_code.py} +0 -0
  268. /machineconfig/scripts/python/helpers/{repo_rag.py → helpers_search/repo_rag.py} +0 -0
  269. /machineconfig/scripts/python/helpers/{symantic_search.py → helpers_search/symantic_search.py} +0 -0
  270. /machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/pdf.py +0 -0
  271. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/WHEEL +0 -0
  272. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/entry_points.txt +0 -0
  273. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,22 @@
1
1
 
2
- from typing import Optional, Literal, Annotated
3
2
 
3
+ from typing import Optional, Literal, Annotated
4
4
  import typer
5
+ from machineconfig.utils.ssh_utils.abc import MACHINECONFIG_VERSION
6
+
7
+
8
+ def get_tmp_file():
9
+ from pathlib import Path
10
+ import platform
11
+ from machineconfig.utils.accessories import randstr
12
+ name = randstr(8)
13
+ if platform.system() == "Windows":
14
+ suffix = "ps1"
15
+ else:
16
+ suffix = "sh"
17
+ tmp_file = Path.home().joinpath(f"tmp_results/tmp_files/{name}.{suffix}")
18
+ tmp_file.parent.mkdir(parents=True, exist_ok=True)
19
+ return tmp_file
5
20
 
6
21
 
7
22
  def main(
@@ -29,6 +44,7 @@ def main(
29
44
  "remove-rclone-conflict": "remove-rclone-conflict",
30
45
  }
31
46
  on_conflict = on_conflict_mapper[on_conflict]
47
+ import platform
32
48
  import git
33
49
  from rich.console import Console
34
50
  from rich.panel import Panel
@@ -38,10 +54,15 @@ def main(
38
54
  from machineconfig.utils.source_of_truth import CONFIG_ROOT, DEFAULTS_PATH
39
55
  from machineconfig.utils.code import get_uv_command_executing_python_script
40
56
  from pathlib import Path
41
- import platform
42
57
  import subprocess
43
58
  console = Console()
44
59
 
60
+ def _bash_single_quote(val: str) -> str:
61
+ return "'" + val.replace("'", "'\"'\"'") + "'"
62
+
63
+ def _ps_single_quote(val: str) -> str:
64
+ return "'" + val.replace("'", "''") + "'"
65
+
45
66
  if cloud is None:
46
67
  try:
47
68
  from machineconfig.utils.io import read_ini
@@ -57,7 +78,8 @@ def main(
57
78
  try:
58
79
  repo_local_obj = git.Repo(repo_local_root, search_parent_directories=True)
59
80
  except git.InvalidGitRepositoryError:
60
- typer.echo(f"[red]Error:[/] The specified path '{repo_local_root}' is not a valid git repository.")
81
+ msg = typer.style("Error: ", fg=typer.colors.RED) + f"The specified path '{repo_local_root}' is not a valid git repository."
82
+ typer.echo(msg)
61
83
  typer.Exit(code=1)
62
84
  return ""
63
85
  repo_local_root = PathExtended(repo_local_obj.working_dir) # cwd might have been in a sub directory of repo_root, so its better to redefine it.
@@ -80,43 +102,89 @@ def main(
80
102
  if repo_remote_obj.is_dirty():
81
103
  console.print(Panel(f"⚠️ WARNING: REMOTE REPOSITORY IS DIRTY\nLocation: {repo_remote_root}\nPlease commit or stash changes before proceeding.", title="Warning", border_style="yellow"))
82
104
 
83
- script = f"""
105
+ message_resolved = "sync" if message is None or message.strip() == "" else message
106
+
107
+ repo_local_root_str = str(repo_local_root)
108
+ repo_remote_root_str = str(repo_remote_root)
109
+
110
+ script_bash = f"""
84
111
  echo ""
85
- echo 'echo -e "\\033[1;34m═════ COMMITTING LOCAL CHANGES ═════\\033[0m"'
86
- cd {repo_local_root}
112
+ echo -e "\\033[1;34m═════ COMMITTING LOCAL CHANGES ═════\\033[0m"
113
+ cd {_bash_single_quote(repo_local_root_str)}
87
114
  git status
88
- git add .
89
- git commit -am "{message}"
115
+ git add -A
116
+ if git diff --cached --quiet; then
117
+ echo "-> No staged changes to commit."
118
+ else
119
+ git commit -m {_bash_single_quote(message_resolved)} || true
120
+ fi
90
121
  echo ""
91
122
  echo ""
92
- echo 'echo -e "\\033[1;34m═════ PULLING LATEST FROM REMOTE ═════\\033[0m"'
93
- cd {repo_local_root}
94
- echo '-> Trying to removing originEnc remote from local repo if it exists.'
95
- # git remote remove originEnc
123
+ echo -e "\\033[1;34m═════ PULLING LATEST FROM REMOTE ═════\\033[0m"
124
+ cd {_bash_single_quote(repo_local_root_str)}
125
+ echo "-> Trying to removing originEnc remote from local repo if it exists."
96
126
  git remote remove originEnc 2>/dev/null || true
97
- echo '-> Adding originEnc remote to local repo'
98
- git remote add originEnc {repo_remote_root}
99
- echo '-> Fetching originEnc remote.'
127
+ echo "-> Adding originEnc remote to local repo"
128
+ git remote add originEnc {_bash_single_quote(repo_remote_root_str)}
129
+ echo "-> Fetching originEnc remote."
100
130
  git pull originEnc master
101
131
 
102
132
  """
103
133
 
134
+ script_powershell = f"""
135
+ Write-Host ""
136
+ Write-Host "═════ COMMITTING LOCAL CHANGES ═════" -ForegroundColor Blue
137
+ Set-Location -LiteralPath {_ps_single_quote(repo_local_root_str)}
138
+ git status
139
+ git add -A
140
+ git diff --cached --quiet
141
+ if ($LASTEXITCODE -eq 0) {{
142
+ Write-Host "-> No staged changes to commit."
143
+ }} else {{
144
+ git commit -m {_ps_single_quote(message_resolved)}
145
+ if ($LASTEXITCODE -ne 0) {{
146
+ Write-Host "-> Commit skipped/failed (continuing)."
147
+ }}
148
+ }}
149
+
150
+ Write-Host ""
151
+ Write-Host ""
152
+ Write-Host "═════ PULLING LATEST FROM REMOTE ═════" -ForegroundColor Blue
153
+ Set-Location -LiteralPath {_ps_single_quote(repo_local_root_str)}
154
+ Write-Host "-> Trying to remove originEnc remote from local repo if it exists."
155
+ git remote remove originEnc 2>$null
156
+ Write-Host "-> Adding originEnc remote to local repo"
157
+ git remote add originEnc {_ps_single_quote(repo_remote_root_str)}
158
+ Write-Host "-> Fetching originEnc remote."
159
+ git pull originEnc master
160
+ exit $LASTEXITCODE
161
+ """
162
+
163
+ script = script_powershell if platform.system() == "Windows" else script_bash
164
+
104
165
  if Path.home().joinpath("code/machineconfig").exists():
105
166
  uv_project_dir = f"""{str(Path.home().joinpath("code/machineconfig"))}"""
106
167
  uv_with = None
107
168
  else:
108
- uv_with = ["machineconfig>=8.14"]
169
+ uv_with = [MACHINECONFIG_VERSION]
109
170
  uv_project_dir = None
110
171
 
111
- import tempfile
112
- shell_path = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
172
+ shell_path = get_tmp_file()
113
173
  shell_path.write_text(script, encoding="utf-8")
114
-
115
- command = f". {shell_path}"
116
174
  if platform.system() == "Windows":
117
- completed = subprocess.run(["powershell", "-Command", command], capture_output=True, check=False, text=True)
175
+ completed = subprocess.run(
176
+ ["powershell", "-ExecutionPolicy", "Bypass", "-File", str(shell_path)],
177
+ capture_output=True,
178
+ check=False,
179
+ text=True,
180
+ )
118
181
  else:
119
- completed = subprocess.run(command, shell=True, capture_output=True, check=False, text=True)
182
+ completed = subprocess.run(
183
+ ["bash", str(shell_path)],
184
+ capture_output=True,
185
+ check=False,
186
+ text=True,
187
+ )
120
188
  res = Response.from_completed_process(completed).capture().print()
121
189
 
122
190
  if res.is_successful(strict_err=True, strict_returcode=True):
@@ -134,31 +202,37 @@ git pull originEnc master
134
202
  option1 = "Delete remote copy and push local:"
135
203
  from machineconfig.utils.meta import lambda_to_python_script
136
204
  def func2(remote_repo: str, local_repo: str, cloud: str):
137
- from machineconfig.scripts.python.helpers_repos.sync import delete_remote_repo_copy_and_push_local
205
+ from machineconfig.scripts.python.helpers.helpers_repos.sync import delete_remote_repo_copy_and_push_local
138
206
  delete_remote_repo_copy_and_push_local(remote_repo=remote_repo, local_repo=local_repo, cloud=cloud)
139
207
  program_1_py = lambda_to_python_script(lambda: func2(remote_repo=str(repo_remote_root), local_repo=str(repo_local_root), cloud=str(cloud_resolved)),
140
208
  in_global=True, import_module=False)
141
209
  program1, _pyfile1 = get_uv_command_executing_python_script(python_script=program_1_py, uv_with=uv_with, uv_project_dir=uv_project_dir)
142
210
  # ================================================================================
211
+
143
212
  option2 = "Delete local repo and replace it with remote copy:"
144
- program_2 = f"""
145
- rm -rfd {repo_local_root}
146
- mv {repo_remote_root} {repo_local_root}
147
- """
213
+ if platform.system() == "Windows":
214
+ program_2 = f"""
215
+ Remove-Item -LiteralPath {_ps_single_quote(repo_local_root_str)} -Recurse -Force -ErrorAction SilentlyContinue
216
+ Move-Item -LiteralPath {_ps_single_quote(repo_remote_root_str)} -Destination {_ps_single_quote(repo_local_root_str)} -Force
217
+ """
218
+ else:
219
+ program_2 = f"""
220
+ rm -rfd {_bash_single_quote(repo_local_root_str)}
221
+ mv {_bash_single_quote(repo_remote_root_str)} {_bash_single_quote(repo_local_root_str)}
222
+ """
148
223
  if platform.system() in ["Linux", "Darwin"]:
149
224
  program_2 += """
150
225
  sudo chmod 600 $HOME/.ssh/*
151
226
  sudo chmod 700 $HOME/.ssh
152
227
  sudo chmod +x $HOME/dotfiles/scripts/linux -R
153
228
  """
154
- import tempfile
155
- shell_file_2 = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
229
+ shell_file_2 = get_tmp_file()
156
230
  shell_file_2.write_text(program_2, encoding="utf-8")
157
231
 
158
232
  # ================================================================================
159
233
  option3 = "Inspect repos:"
160
234
  def func(repo_local_root: str, repo_remote_root: str):
161
- from machineconfig.scripts.python.helpers_repos.sync import inspect_repos
235
+ from machineconfig.scripts.python.helpers.helpers_repos.sync import inspect_repos
162
236
  inspect_repos(repo_local_root=repo_local_root, repo_remote_root=repo_remote_root)
163
237
  # program_3_py = function_to_script(func=func, call_with_kwargs={"repo_local_root": str(repo_local_root), "repo_remote_root": str(repo_remote_root)})
164
238
  # shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, ve_path=None, executable=executable)
@@ -168,14 +242,24 @@ sudo chmod +x $HOME/dotfiles/scripts/linux -R
168
242
  # ================================================================================
169
243
 
170
244
  option4 = "Remove problematic rclone file from repo and replace with remote:"
171
- program_4 = f"""
245
+ if platform.system() == "Windows":
246
+ program_4 = f"""
247
+ Remove-Item -LiteralPath "$HOME/dotfiles/creds/rclone/rclone.conf" -Force -ErrorAction SilentlyContinue
248
+ New-Item -ItemType Directory -Path "$HOME/dotfiles/creds/rclone" -Force | Out-Null
249
+ Copy-Item -LiteralPath "$HOME/.config/machineconfig/remote/dotfiles/creds/rclone/rclone.conf" -Destination "$HOME/dotfiles/creds/rclone/rclone.conf" -Force
250
+ Set-Location -LiteralPath "$HOME/dotfiles"
251
+ git commit -am "finished merging"
252
+ {program1}
253
+ """
254
+ else:
255
+ program_4 = f"""
172
256
  rm $HOME/dotfiles/creds/rclone/rclone.conf
173
257
  cp $HOME/.config/machineconfig/remote/dotfiles/creds/rclone/rclone.conf $HOME/dotfiles/creds/rclone
174
258
  cd $HOME/dotfiles
175
259
  git commit -am "finished merging"
176
260
  {program1}
177
- """
178
- shell_file_4 = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
261
+ """
262
+ shell_file_4 = get_tmp_file()
179
263
  shell_file_4.write_text(program_4, encoding="utf-8")
180
264
  # ================================================================================
181
265
 
@@ -169,7 +169,7 @@ def visualize(
169
169
  if platform.system() == "Windows":
170
170
  print(f"⚠️ Portable gource not found at {gource_exe}, installing...")
171
171
  install_gource_windows()
172
- # Check again after installation
172
+ gource_exe = get_gource_executable() # Re-fetch path after installation
173
173
  if gource_exe.exists():
174
174
  print(f"✅ Gource installed successfully at: {gource_exe}")
175
175
  gource_cmd: str = str(gource_exe)
@@ -177,7 +177,8 @@ def visualize(
177
177
  print("❌ Installation failed, falling back to system gource")
178
178
  raise typer.Exit(1)
179
179
  else:
180
- raise FileNotFoundError(f"Gource executable not found at {gource_exe}. Please install gource using your package manager.")
180
+ print(f"❌ Error: Gource executable not found at {gource_exe}. Please install gource using your package manager.")
181
+ raise typer.Exit(1)
181
182
  else:
182
183
  gource_cmd = str(gource_exe)
183
184
 
@@ -3,7 +3,6 @@ from pathlib import Path
3
3
  from machineconfig.utils.schemas.repos.repos_types import GitVersionInfo, RepoRecordDict, RepoRemote
4
4
 
5
5
  from machineconfig.utils.schemas.repos.repos_types import RepoRecordFile
6
- from machineconfig.utils.source_of_truth import CONFIG_ROOT
7
6
  from machineconfig.utils.io import save_json
8
7
 
9
8
  from typing import Optional
@@ -12,7 +11,7 @@ from rich import print as pprint
12
11
  from rich.progress import Progress, TaskID, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn, MofNCompleteColumn
13
12
 
14
13
 
15
- def build_tree_structure(repos: list[RepoRecordDict], repos_root: PathExtended) -> str:
14
+ def build_tree_structure(repos: list[RepoRecordDict], repos_root: Path) -> str:
16
15
  """Build a tree structure representation of all repositories."""
17
16
  if not repos:
18
17
  return "No repositories found."
@@ -186,10 +185,18 @@ def record_repos_recursively(repos_root: str, r: bool, progress: Progress | None
186
185
  return res
187
186
 
188
187
 
189
- def main_record(repos_root: Path):
190
- print("\n📝 Recording repositories...")
191
- repos_root = PathExtended(repos_root).expanduser().absolute()
188
+ def _resolve_directory(directory: Optional[str]) -> Path:
189
+ import typer
190
+ if directory is None:
191
+ directory = Path.cwd().as_posix()
192
+ typer.echo(f"📁 Using directory: {directory}")
193
+ return Path(directory).expanduser().absolute().resolve()
194
+
192
195
 
196
+ def main_record(repos_root_str: Optional[str]) -> Path:
197
+ print("\n📝 Recording repositories...")
198
+ repos_root = _resolve_directory(directory=repos_root_str)
199
+
193
200
  # Count total directories and repositories for accurate progress tracking
194
201
  print("🔍 Analyzing directory structure...")
195
202
  total_dirs = count_total_directories(str(repos_root), r=True)
@@ -222,7 +229,7 @@ def main_record(repos_root: Path):
222
229
  if repos_with_no_remotes:
223
230
  print(f"\n⚠️ WARNING: {len(repos_with_no_remotes)} repositories have no remotes configured:")
224
231
  for repo in repos_with_no_remotes:
225
- repo_path = PathExtended(repo["parentDir"]).joinpath(repo["name"])
232
+ repo_path = Path(repo["parentDir"]).joinpath(repo["name"])
226
233
  print(f" • {repo['name']} ({repo_path})")
227
234
  print(" These repositories may be local-only or have configuration issues.")
228
235
  else:
@@ -231,7 +238,7 @@ def main_record(repos_root: Path):
231
238
  if dirty_repos:
232
239
  print(f"\n⚠️ WARNING: {len(dirty_repos)} repositories have uncommitted changes:")
233
240
  for repo in dirty_repos:
234
- repo_path = PathExtended(repo["parentDir"]).joinpath(repo["name"])
241
+ repo_path = Path(repo["parentDir"]).joinpath(repo["name"])
235
242
  print(f" • {repo['name']} ({repo_path}) [branch: {repo['currentBranch']}]")
236
243
  print(" These repositories have uncommitted changes that may need attention.")
237
244
  else:
@@ -239,12 +246,25 @@ def main_record(repos_root: Path):
239
246
 
240
247
  # Display repository tree structure
241
248
  print("\n🌳 Repository Tree Structure:")
242
- tree_structure = build_tree_structure(repo_records, repos_root)
249
+ tree_structure = build_tree_structure(repos=repo_records, repos_root=repos_root)
243
250
  print(tree_structure)
244
251
 
245
- relative_repos_root = PathExtended(repos_root).expanduser().absolute().relative_to(Path.home())
246
- save_path = CONFIG_ROOT.joinpath("repos").joinpath(relative_repos_root).joinpath("repos.json")
247
- save_json(obj=res, path=save_path, indent=4)
248
- pprint(f"📁 Result saved at {PathExtended(save_path)}")
252
+ spec_path_default = Path(repos_root).expanduser().absolute().joinpath("repos.json")
253
+ from machineconfig.scripts.python.helpers.helpers_devops.cli_config_dotfile import get_backup_path, record_mapping
254
+ spec_path_self_managed = get_backup_path(
255
+ orig_path=spec_path_default,
256
+ sensitivity="private",
257
+ destination=None,
258
+ shared=False,
259
+ )
260
+ save_json(obj=res, path=spec_path_self_managed, indent=4)
261
+ pprint(f"📁 Result saved at {PathExtended(spec_path_self_managed)}")
262
+
263
+ # record_mapping(
264
+ # orig_path=spec_path_default,
265
+
266
+ # )
267
+ _ = record_mapping
268
+
249
269
  print(">>>>>>>>> Finished Recording")
250
- return save_path
270
+ return spec_path_self_managed
@@ -1,13 +1,23 @@
1
1
  from git import Repo
2
- from machineconfig.scripts.python.helpers_repos.repo_analyzer_1 import count_python_lines, get_default_branch
2
+ from machineconfig.scripts.python.helpers.helpers_repos.repo_analyzer_1 import count_python_lines, get_default_branch
3
3
  from datetime import datetime
4
4
  import polars as pl
5
5
  from pathlib import Path
6
- from typing import Any, Dict, List, Union, Optional
6
+ from typing import cast, TypedDict
7
7
 
8
8
 
9
- def print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exception]":
10
- import polars as pl
9
+ class FileDataRow(TypedDict):
10
+ filename: str
11
+ lines: int
12
+
13
+
14
+ class CommitDataRow(TypedDict):
15
+ hash: str
16
+ dtmExit: datetime
17
+ lines: int
18
+
19
+
20
+ def print_python_files_by_size_impl(repo_path: str) -> pl.DataFrame | Exception:
11
21
  import plotly.graph_objects as go
12
22
  import plotly.express as px
13
23
 
@@ -16,7 +26,7 @@ def print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exce
16
26
  if not os.path.exists(repo_path):
17
27
  return ValueError(f"Repository path does not exist: {repo_path}")
18
28
  # Initialize data storage
19
- file_data: "List[Dict[str, Union[str, int]]]" = []
29
+ file_data: list[FileDataRow] = []
20
30
 
21
31
  # Walk through the repository
22
32
  for root, _, files in os.walk(repo_path):
@@ -66,7 +76,8 @@ def print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exce
66
76
  table.add_column("Lines", justify="right")
67
77
 
68
78
  for idx, row in enumerate(df.iter_rows(named=True), 1):
69
- table.add_row(str(idx), row["filename"], f"{row['lines']:,}")
79
+ typed_row = cast(FileDataRow, row)
80
+ table.add_row(str(idx), typed_row["filename"], f"{typed_row['lines']:,}")
70
81
 
71
82
  console.print(table)
72
83
  print(f"\n📁 Total Python files: {file_count}")
@@ -118,7 +129,7 @@ def print_python_files_by_size_impl(repo_path: str) -> "Union[pl.DataFrame, Exce
118
129
  )
119
130
 
120
131
  # Define pie chart figure before conditionally using it
121
- fig2: "Optional[go.Figure]" = None
132
+ fig2: go.Figure | None = None
122
133
 
123
134
  # Add pie chart showing distribution
124
135
  if len(df) > top_n:
@@ -175,14 +186,15 @@ def analyze_over_time(repo_path: str):
175
186
  repo: Repo = Repo(repo_path)
176
187
  branch_name: str = get_default_branch(repo)
177
188
  print(f"🔍 Using branch: {branch_name}")
178
- commit_data: "List[Dict[str, Any]]" = []
189
+ commit_data: list[CommitDataRow] = []
179
190
  print("⏳ Analyzing commits...")
180
191
  try:
181
192
  commits = list(repo.iter_commits(branch_name))
182
193
  from datetime import timezone
183
194
  from rich.progress import track
184
195
  for commit in track(commits, description="Processing commits..."):
185
- commit_data.append({"hash": commit.hexsha, "dtmExit": datetime.fromtimestamp(commit.committed_date, tz=timezone.utc), "lines": count_python_lines(commit)})
196
+ lines, _files = count_python_lines(commit)
197
+ commit_data.append({"hash": commit.hexsha, "dtmExit": datetime.fromtimestamp(commit.committed_date, tz=timezone.utc), "lines": lines})
186
198
  except Exception as e:
187
199
  print(f"❌ Error analyzing commits: {str(e)}")
188
200
  return
@@ -199,20 +211,50 @@ def analyze_over_time(repo_path: str):
199
211
  # Add markers for significant points (min, max, last)
200
212
  min_idx = df["lines"].arg_min()
201
213
  max_idx = df["lines"].arg_max()
202
- min_point = df.slice(min_idx, 1).to_dicts()[0] if min_idx is not None else {}
203
- max_point = df.slice(max_idx, 1).to_dicts()[0] if max_idx is not None else {}
204
- last_point = df.slice(-1, 1).to_dicts()[0]
214
+ last_point = cast(CommitDataRow, df.slice(-1, 1).to_dicts()[0])
215
+
216
+ marker_x: list[datetime] = []
217
+ marker_y: list[int] = []
218
+ marker_sizes: list[int] = []
219
+ marker_colors: list[str] = []
220
+ marker_symbols: list[str] = []
221
+ marker_texts: list[str] = []
222
+
223
+ if min_idx is not None:
224
+ min_point = cast(CommitDataRow, df.slice(min_idx, 1).to_dicts()[0])
225
+ marker_x.append(min_point["dtmExit"])
226
+ marker_y.append(min_point["lines"])
227
+ marker_sizes.append(10)
228
+ marker_colors.append("#ff4f4f")
229
+ marker_symbols.append("circle")
230
+ marker_texts.append(f"🔽 Min: {min_point['lines']:,} lines")
231
+
232
+ if max_idx is not None:
233
+ max_point = cast(CommitDataRow, df.slice(max_idx, 1).to_dicts()[0])
234
+ marker_x.append(max_point["dtmExit"])
235
+ marker_y.append(max_point["lines"])
236
+ marker_sizes.append(14)
237
+ marker_colors.append("#4fff4f")
238
+ marker_symbols.append("star")
239
+ marker_texts.append(f"🔼 Max: {max_point['lines']:,} lines")
240
+
241
+ marker_x.append(last_point["dtmExit"])
242
+ marker_y.append(last_point["lines"])
243
+ marker_sizes.append(12)
244
+ marker_colors.append("#4f4fff")
245
+ marker_symbols.append("diamond")
246
+ marker_texts.append(f"📊 Current: {last_point['lines']:,} lines")
205
247
 
206
248
  # Add markers for significant points
207
249
  fig.add_trace(
208
250
  go.Scatter(
209
- x=[min_point["dtmExit"], max_point["dtmExit"], last_point["dtmExit"]],
210
- y=[min_point["lines"], max_point["lines"], last_point["lines"]],
251
+ x=marker_x,
252
+ y=marker_y,
211
253
  mode="markers",
212
- marker={"size": [10, 14, 12], "color": ["#ff4f4f", "#4fff4f", "#4f4fff"], "line": {"width": 2, "color": "white"}, "symbol": ["circle", "star", "diamond"]},
254
+ marker={"size": marker_sizes, "color": marker_colors, "line": {"width": 2, "color": "white"}, "symbol": marker_symbols},
213
255
  name="Key Points",
214
256
  hovertemplate="<b>%{text}</b><br>Date: %{x}<br>Lines: %{y:,}<extra></extra>",
215
- text=[f"🔽 Min: {min_point['lines']:,} lines", f"🔼 Max: {max_point['lines']:,} lines", f"📊 Current: {last_point['lines']:,} lines"],
257
+ text=marker_texts,
216
258
  )
217
259
  )
218
260
 
@@ -264,6 +306,8 @@ def analyze_over_time(repo_path: str):
264
306
  # Print statistics
265
307
  print("\n📊 Repository Statistics:")
266
308
  print(f"📚 Total commits analyzed: {len(df)}")
267
- print(f"🔙 Initial line count: {df['lines'][-1]:,}")
268
- print(f"🔜 Final line count: {df['lines'][0]:,}")
269
- print(f"📈 Net change: {df['lines'][0] - df['lines'][-1]:,} lines")
309
+ initial_lines = int(df['lines'][-1])
310
+ final_lines = int(df['lines'][0])
311
+ print(f"🔙 Initial line count: {initial_lines:,}")
312
+ print(f"🔜 Final line count: {final_lines:,}")
313
+ print(f"📈 Net change: {final_lines - initial_lines:,} lines")
@@ -246,12 +246,6 @@ def update_repository(repo: git.Repo, auto_uv_sync: bool, allow_password_prompt:
246
246
  result["permissions_updated"] = True
247
247
  print(f"✅ Set permissions for {linux_jobs_path}")
248
248
 
249
- lf_exe_path = repo_path / "src" / "machineconfig" / "settings" / "lf" / "linux" / "exe"
250
- if lf_exe_path.exists():
251
- set_permissions_recursive(lf_exe_path)
252
- result["permissions_updated"] = True
253
- print(f"✅ Set permissions for {lf_exe_path}")
254
-
255
249
  # Run uv sync if dependencies changed and auto_sync is enabled
256
250
  if result["dependencies_changed"] and auto_uv_sync:
257
251
  result["uv_sync_ran"] = True
@@ -0,0 +1,81 @@
1
+
2
+ from typing import Literal
3
+
4
+
5
+ def list_available_scripts(where: Literal["all", "a", "private", "p", "public", "b", "library", "l", "dynamic", "d", "custom", "c"]) -> None:
6
+ from pathlib import Path
7
+ from machineconfig.utils.source_of_truth import CONFIG_ROOT, LIBRARY_ROOT, DEFAULTS_PATH
8
+
9
+ private_root = Path.home().joinpath("dotfiles/scripts")
10
+ public_root = CONFIG_ROOT.joinpath("scripts")
11
+ library_root = LIBRARY_ROOT.joinpath("jobs", "scripts")
12
+
13
+ def get_custom_roots() -> list[Path]:
14
+ custom_roots: list[Path] = []
15
+ if DEFAULTS_PATH.is_file():
16
+ from configparser import ConfigParser
17
+ config = ConfigParser()
18
+ config.read(DEFAULTS_PATH)
19
+ if config.has_section("general") and config.has_option("general", "scripts"):
20
+ custom_dirs = config.get("general", "scripts").split(",")
21
+ for custom_dir in custom_dirs:
22
+ custom_path = Path(custom_dir.strip()).expanduser().resolve()
23
+ if custom_path.is_dir():
24
+ custom_roots.append(custom_path)
25
+ return custom_roots
26
+
27
+ locations: dict[str, Path | str] = {}
28
+ match where:
29
+ case "all" | "a":
30
+ locations = {"private": private_root, "public": public_root, "library": library_root}
31
+ for idx, custom in enumerate(get_custom_roots()): locations[f"custom_{idx}"] = custom
32
+ locations["dynamic"] = "https://github.com/thisismygitrepo/machineconfig/tree/main/src/machineconfig/jobs/scripts_dynamic"
33
+ case "private" | "p":
34
+ locations = {"private": private_root}
35
+ case "public" | "b":
36
+ locations = {"public": public_root}
37
+ case "library" | "l":
38
+ locations = {"library": library_root}
39
+ case "dynamic" | "d":
40
+ locations = {"dynamic": "https://github.com/thisismygitrepo/machineconfig/tree/main/src/machineconfig/jobs/scripts_dynamic"}
41
+ case "custom" | "c":
42
+ for idx, custom in enumerate(get_custom_roots()): locations[f"custom_{idx}"] = custom
43
+
44
+ def _print_files_by_type(files: list[str]) -> None:
45
+ categories: dict[str, list[str]] = {".py": [], ".sh": [], ".ps1": [], ".cmd": [], ".bat": [], "other": []}
46
+ for f in files:
47
+ ext = Path(f).suffix.lower() if "." in str(f) else ""
48
+ if ext in categories: categories[ext].append(str(f))
49
+ else: categories["other"].append(str(f))
50
+ for ext, cat_files in categories.items():
51
+ if cat_files:
52
+ label = ext if ext else "other"
53
+ print(f" [{label}]")
54
+ for cf in sorted(cat_files): print(f" • {cf}")
55
+
56
+ for loc_name, loc_path in locations.items():
57
+ print(f"\n📁 {loc_name.upper()} ({loc_path}):")
58
+ print("-" * 60)
59
+ if isinstance(loc_path, Path):
60
+ if loc_path.is_dir():
61
+ files = [f for f in loc_path.rglob("*") if f.is_file() and f.suffix in (".py", ".sh", ".ps1", ".bat", ".cmd", "")]
62
+ if files:
63
+ relative_files = [str(f.relative_to(loc_path)) for f in files]
64
+ _print_files_by_type(relative_files)
65
+ else:
66
+ print(" (empty)")
67
+ else:
68
+ print(" ⚠️ Directory does not exist")
69
+ else:
70
+ api_url = "https://api.github.com/repos/thisismygitrepo/machineconfig/contents/src/machineconfig/jobs/scripts_dynamic"
71
+ try:
72
+ import requests
73
+ response = requests.get(api_url, timeout=10)
74
+ if response.status_code == 200:
75
+ items = response.json()
76
+ files = [item["name"] for item in items if item["type"] == "file"]
77
+ _print_files_by_type(files)
78
+ else:
79
+ print(f" ⚠️ Could not fetch from GitHub (status: {response.status_code})")
80
+ except Exception as e:
81
+ print(f" ⚠️ Could not fetch from GitHub: {e}")