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
@@ -1,9 +1,23 @@
1
1
 
2
- from typing import Optional, Literal, Annotated
3
2
 
3
+ from typing import Optional, Literal, Annotated
4
4
  import typer
5
5
 
6
6
 
7
+ def get_tmp_file():
8
+ from pathlib import Path
9
+ import platform
10
+ from machineconfig.utils.accessories import randstr
11
+ name = randstr(8)
12
+ if platform.system() == "Windows":
13
+ suffix = "ps1"
14
+ else:
15
+ suffix = "sh"
16
+ tmp_file = Path.home().joinpath(f"tmp_results/tmp_files/{name}.{suffix}")
17
+ tmp_file.parent.mkdir(parents=True, exist_ok=True)
18
+ return tmp_file
19
+
20
+
7
21
  def main(
8
22
  cloud: Annotated[Optional[str], typer.Option(..., "--cloud", "-c", help="Cloud storage profile name. If not provided, uses default from config.")] = None,
9
23
  repo: Annotated[Optional[str], typer.Option(..., "--repo", "-r", help="Path to the local repository. Defaults to current working directory.")] = None,
@@ -29,6 +43,7 @@ def main(
29
43
  "remove-rclone-conflict": "remove-rclone-conflict",
30
44
  }
31
45
  on_conflict = on_conflict_mapper[on_conflict]
46
+ import platform
32
47
  import git
33
48
  from rich.console import Console
34
49
  from rich.panel import Panel
@@ -38,10 +53,15 @@ def main(
38
53
  from machineconfig.utils.source_of_truth import CONFIG_ROOT, DEFAULTS_PATH
39
54
  from machineconfig.utils.code import get_uv_command_executing_python_script
40
55
  from pathlib import Path
41
- import platform
42
56
  import subprocess
43
57
  console = Console()
44
58
 
59
+ def _bash_single_quote(val: str) -> str:
60
+ return "'" + val.replace("'", "'\"'\"'") + "'"
61
+
62
+ def _ps_single_quote(val: str) -> str:
63
+ return "'" + val.replace("'", "''") + "'"
64
+
45
65
  if cloud is None:
46
66
  try:
47
67
  from machineconfig.utils.io import read_ini
@@ -57,7 +77,8 @@ def main(
57
77
  try:
58
78
  repo_local_obj = git.Repo(repo_local_root, search_parent_directories=True)
59
79
  except git.InvalidGitRepositoryError:
60
- typer.echo(f"[red]Error:[/] The specified path '{repo_local_root}' is not a valid git repository.")
80
+ msg = typer.style("Error: ", fg=typer.colors.RED) + f"The specified path '{repo_local_root}' is not a valid git repository."
81
+ typer.echo(msg)
61
82
  typer.Exit(code=1)
62
83
  return ""
63
84
  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 +101,89 @@ def main(
80
101
  if repo_remote_obj.is_dirty():
81
102
  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
103
 
83
- script = f"""
104
+ message_resolved = "sync" if message is None or message.strip() == "" else message
105
+
106
+ repo_local_root_str = str(repo_local_root)
107
+ repo_remote_root_str = str(repo_remote_root)
108
+
109
+ script_bash = f"""
84
110
  echo ""
85
- echo 'echo -e "\\033[1;34m═════ COMMITTING LOCAL CHANGES ═════\\033[0m"'
86
- cd {repo_local_root}
111
+ echo -e "\\033[1;34m═════ COMMITTING LOCAL CHANGES ═════\\033[0m"
112
+ cd {_bash_single_quote(repo_local_root_str)}
87
113
  git status
88
- git add .
89
- git commit -am "{message}"
114
+ git add -A
115
+ if git diff --cached --quiet; then
116
+ echo "-> No staged changes to commit."
117
+ else
118
+ git commit -m {_bash_single_quote(message_resolved)} || true
119
+ fi
90
120
  echo ""
91
121
  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
122
+ echo -e "\\033[1;34m═════ PULLING LATEST FROM REMOTE ═════\\033[0m"
123
+ cd {_bash_single_quote(repo_local_root_str)}
124
+ echo "-> Trying to removing originEnc remote from local repo if it exists."
96
125
  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.'
126
+ echo "-> Adding originEnc remote to local repo"
127
+ git remote add originEnc {_bash_single_quote(repo_remote_root_str)}
128
+ echo "-> Fetching originEnc remote."
100
129
  git pull originEnc master
101
130
 
102
131
  """
103
132
 
133
+ script_powershell = f"""
134
+ Write-Host ""
135
+ Write-Host "═════ COMMITTING LOCAL CHANGES ═════" -ForegroundColor Blue
136
+ Set-Location -LiteralPath {_ps_single_quote(repo_local_root_str)}
137
+ git status
138
+ git add -A
139
+ git diff --cached --quiet
140
+ if ($LASTEXITCODE -eq 0) {{
141
+ Write-Host "-> No staged changes to commit."
142
+ }} else {{
143
+ git commit -m {_ps_single_quote(message_resolved)}
144
+ if ($LASTEXITCODE -ne 0) {{
145
+ Write-Host "-> Commit skipped/failed (continuing)."
146
+ }}
147
+ }}
148
+
149
+ Write-Host ""
150
+ Write-Host ""
151
+ Write-Host "═════ PULLING LATEST FROM REMOTE ═════" -ForegroundColor Blue
152
+ Set-Location -LiteralPath {_ps_single_quote(repo_local_root_str)}
153
+ Write-Host "-> Trying to remove originEnc remote from local repo if it exists."
154
+ git remote remove originEnc 2>$null
155
+ Write-Host "-> Adding originEnc remote to local repo"
156
+ git remote add originEnc {_ps_single_quote(repo_remote_root_str)}
157
+ Write-Host "-> Fetching originEnc remote."
158
+ git pull originEnc master
159
+ exit $LASTEXITCODE
160
+ """
161
+
162
+ script = script_powershell if platform.system() == "Windows" else script_bash
163
+
104
164
  if Path.home().joinpath("code/machineconfig").exists():
105
165
  uv_project_dir = f"""{str(Path.home().joinpath("code/machineconfig"))}"""
106
166
  uv_with = None
107
167
  else:
108
- uv_with = ["machineconfig>=8.14"]
168
+ uv_with = ["machineconfig>=8.45"]
109
169
  uv_project_dir = None
110
170
 
111
- import tempfile
112
- shell_path = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
171
+ shell_path = get_tmp_file()
113
172
  shell_path.write_text(script, encoding="utf-8")
114
-
115
- command = f". {shell_path}"
116
173
  if platform.system() == "Windows":
117
- completed = subprocess.run(["powershell", "-Command", command], capture_output=True, check=False, text=True)
174
+ completed = subprocess.run(
175
+ ["powershell", "-ExecutionPolicy", "Bypass", "-File", str(shell_path)],
176
+ capture_output=True,
177
+ check=False,
178
+ text=True,
179
+ )
118
180
  else:
119
- completed = subprocess.run(command, shell=True, capture_output=True, check=False, text=True)
181
+ completed = subprocess.run(
182
+ ["bash", str(shell_path)],
183
+ capture_output=True,
184
+ check=False,
185
+ text=True,
186
+ )
120
187
  res = Response.from_completed_process(completed).capture().print()
121
188
 
122
189
  if res.is_successful(strict_err=True, strict_returcode=True):
@@ -134,31 +201,37 @@ git pull originEnc master
134
201
  option1 = "Delete remote copy and push local:"
135
202
  from machineconfig.utils.meta import lambda_to_python_script
136
203
  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
204
+ from machineconfig.scripts.python.helpers.helpers_repos.sync import delete_remote_repo_copy_and_push_local
138
205
  delete_remote_repo_copy_and_push_local(remote_repo=remote_repo, local_repo=local_repo, cloud=cloud)
139
206
  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
207
  in_global=True, import_module=False)
141
208
  program1, _pyfile1 = get_uv_command_executing_python_script(python_script=program_1_py, uv_with=uv_with, uv_project_dir=uv_project_dir)
142
209
  # ================================================================================
210
+
143
211
  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
- """
212
+ if platform.system() == "Windows":
213
+ program_2 = f"""
214
+ Remove-Item -LiteralPath {_ps_single_quote(repo_local_root_str)} -Recurse -Force -ErrorAction SilentlyContinue
215
+ Move-Item -LiteralPath {_ps_single_quote(repo_remote_root_str)} -Destination {_ps_single_quote(repo_local_root_str)} -Force
216
+ """
217
+ else:
218
+ program_2 = f"""
219
+ rm -rfd {_bash_single_quote(repo_local_root_str)}
220
+ mv {_bash_single_quote(repo_remote_root_str)} {_bash_single_quote(repo_local_root_str)}
221
+ """
148
222
  if platform.system() in ["Linux", "Darwin"]:
149
223
  program_2 += """
150
224
  sudo chmod 600 $HOME/.ssh/*
151
225
  sudo chmod 700 $HOME/.ssh
152
226
  sudo chmod +x $HOME/dotfiles/scripts/linux -R
153
227
  """
154
- import tempfile
155
- shell_file_2 = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
228
+ shell_file_2 = get_tmp_file()
156
229
  shell_file_2.write_text(program_2, encoding="utf-8")
157
230
 
158
231
  # ================================================================================
159
232
  option3 = "Inspect repos:"
160
233
  def func(repo_local_root: str, repo_remote_root: str):
161
- from machineconfig.scripts.python.helpers_repos.sync import inspect_repos
234
+ from machineconfig.scripts.python.helpers.helpers_repos.sync import inspect_repos
162
235
  inspect_repos(repo_local_root=repo_local_root, repo_remote_root=repo_remote_root)
163
236
  # 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
237
  # shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, ve_path=None, executable=executable)
@@ -168,14 +241,24 @@ sudo chmod +x $HOME/dotfiles/scripts/linux -R
168
241
  # ================================================================================
169
242
 
170
243
  option4 = "Remove problematic rclone file from repo and replace with remote:"
171
- program_4 = f"""
244
+ if platform.system() == "Windows":
245
+ program_4 = f"""
246
+ Remove-Item -LiteralPath "$HOME/dotfiles/creds/rclone/rclone.conf" -Force -ErrorAction SilentlyContinue
247
+ New-Item -ItemType Directory -Path "$HOME/dotfiles/creds/rclone" -Force | Out-Null
248
+ Copy-Item -LiteralPath "$HOME/.config/machineconfig/remote/dotfiles/creds/rclone/rclone.conf" -Destination "$HOME/dotfiles/creds/rclone/rclone.conf" -Force
249
+ Set-Location -LiteralPath "$HOME/dotfiles"
250
+ git commit -am "finished merging"
251
+ {program1}
252
+ """
253
+ else:
254
+ program_4 = f"""
172
255
  rm $HOME/dotfiles/creds/rclone/rclone.conf
173
256
  cp $HOME/.config/machineconfig/remote/dotfiles/creds/rclone/rclone.conf $HOME/dotfiles/creds/rclone
174
257
  cd $HOME/dotfiles
175
258
  git commit -am "finished merging"
176
259
  {program1}
177
- """
178
- shell_file_4 = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
260
+ """
261
+ shell_file_4 = get_tmp_file()
179
262
  shell_file_4.write_text(program_4, encoding="utf-8")
180
263
  # ================================================================================
181
264
 
@@ -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}")