machineconfig 7.50__py3-none-any.whl → 8.12__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 (298) hide show
  1. machineconfig/cluster/remote/cloud_manager.py +1 -1
  2. machineconfig/cluster/sessions_managers/utils/maker.py +23 -11
  3. machineconfig/cluster/sessions_managers/wt_local_manager.py +22 -19
  4. machineconfig/cluster/sessions_managers/wt_remote_manager.py +3 -1
  5. machineconfig/cluster/sessions_managers/zellij_local_manager.py +3 -1
  6. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +3 -2
  7. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +2 -2
  8. machineconfig/jobs/installer/installer_data.json +1185 -165
  9. machineconfig/jobs/installer/linux_scripts/q.sh +10 -7
  10. machineconfig/jobs/installer/linux_scripts/redis.sh +1 -0
  11. machineconfig/jobs/installer/package_groups.py +52 -84
  12. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  13. machineconfig/jobs/installer/{custom → python_scripts}/boxes.py +2 -2
  14. machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +5 -3
  15. machineconfig/jobs/installer/python_scripts/cloudflare_warp_cli.py +23 -0
  16. machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +4 -1
  17. machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +1 -1
  18. machineconfig/jobs/installer/{custom → python_scripts}/hx.py +16 -12
  19. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +2 -2
  20. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +27 -22
  21. machineconfig/jobs/installer/python_scripts/sysabc.py +139 -0
  22. machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +2 -19
  23. machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +10 -14
  24. machineconfig/jobs/installer/python_scripts/yazi.py +121 -0
  25. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nfs +0 -1
  26. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +13 -0
  27. machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +4 -0
  28. machineconfig/jobs/scripts_dynamic/a.py +25 -0
  29. machineconfig/logger.py +0 -1
  30. machineconfig/profile/create_helper.py +21 -22
  31. machineconfig/profile/create_links_export.py +25 -11
  32. machineconfig/profile/create_shell_profile.py +14 -3
  33. machineconfig/profile/mapper.toml +8 -6
  34. machineconfig/scripts/__init__.py +0 -4
  35. machineconfig/scripts/linux/wrap_mcfg +20 -21
  36. machineconfig/scripts/python/agents.py +74 -50
  37. machineconfig/scripts/python/ai/initai.py +1 -1
  38. machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
  39. machineconfig/scripts/python/ai/{command_runner → scripts}/command_runner.sh +1 -1
  40. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +1 -1
  41. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
  42. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
  43. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
  44. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +5 -5
  45. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +4 -0
  46. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
  47. machineconfig/scripts/python/ai/solutions/generic.py +1 -1
  48. machineconfig/scripts/python/ai/{generate_files.py → utils/generate_files.py} +2 -2
  49. machineconfig/scripts/python/cloud.py +6 -6
  50. machineconfig/scripts/python/croshell.py +67 -60
  51. machineconfig/scripts/python/devops.py +41 -21
  52. machineconfig/scripts/python/devops_navigator.py +0 -4
  53. machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
  54. machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
  55. machineconfig/scripts/python/fire_jobs.py +95 -67
  56. machineconfig/scripts/python/ftpx.py +44 -17
  57. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  58. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  59. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  60. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  61. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.json +1 -1
  62. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +9 -7
  63. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +21 -8
  64. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +0 -12
  65. machineconfig/scripts/python/helpers_agents/fire_agents_help_launch.py +30 -11
  66. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +9 -2
  67. machineconfig/scripts/python/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
  68. machineconfig/scripts/python/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
  69. machineconfig/scripts/python/helpers_agents/privacy/configs/copilot/config.yml +1 -0
  70. machineconfig/scripts/python/helpers_agents/privacy/configs/crush/crush.json +10 -0
  71. machineconfig/scripts/python/helpers_agents/privacy/configs/gemini/settings.json +12 -0
  72. machineconfig/scripts/python/helpers_agents/privacy/privacy.py +109 -0
  73. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +8 -4
  74. machineconfig/scripts/python/helpers_agents/templates/template.sh +18 -8
  75. machineconfig/scripts/python/helpers_cloud/cloud_copy.py +28 -21
  76. machineconfig/scripts/python/helpers_cloud/cloud_helpers.py +1 -1
  77. machineconfig/scripts/python/helpers_cloud/cloud_mount.py +19 -17
  78. machineconfig/scripts/python/helpers_cloud/cloud_sync.py +8 -7
  79. machineconfig/scripts/python/helpers_croshell/crosh.py +3 -3
  80. machineconfig/scripts/python/helpers_croshell/start_slidev.py +6 -7
  81. machineconfig/scripts/python/helpers_devops/cli_config.py +19 -25
  82. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +22 -13
  83. machineconfig/scripts/python/helpers_devops/cli_nw.py +113 -26
  84. machineconfig/scripts/python/helpers_devops/cli_repos.py +37 -11
  85. machineconfig/scripts/python/helpers_devops/cli_self.py +84 -39
  86. machineconfig/scripts/python/helpers_devops/cli_share_file.py +9 -9
  87. machineconfig/scripts/python/helpers_devops/cli_share_server.py +13 -12
  88. machineconfig/scripts/python/helpers_devops/{cli_terminal.py → cli_share_terminal.py} +15 -17
  89. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +4 -4
  90. machineconfig/scripts/python/helpers_devops/devops_status.py +7 -19
  91. machineconfig/scripts/python/helpers_devops/run_script.py +168 -0
  92. machineconfig/scripts/python/helpers_devops/themes/choose_wezterm_theme.py +1 -1
  93. machineconfig/scripts/python/helpers_fire_command/file_wrangler.py +2 -19
  94. machineconfig/scripts/python/helpers_fire_command/fire_jobs_args_helper.py +1 -0
  95. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +25 -15
  96. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfg +3 -3
  97. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +58 -1
  98. machineconfig/scripts/python/helpers_navigator/command_tree.py +50 -18
  99. machineconfig/scripts/python/helpers_network/address.py +176 -0
  100. machineconfig/scripts/python/helpers_network/address_switch.py +78 -0
  101. machineconfig/scripts/python/{nw → helpers_network}/mount_nfs.py +2 -2
  102. machineconfig/scripts/python/{nw → helpers_network}/mount_ssh.py +1 -1
  103. machineconfig/scripts/python/{nw/devops_add_identity.py → helpers_network/ssh_add_identity.py} +35 -1
  104. machineconfig/scripts/python/{nw/devops_add_ssh_key.py → helpers_network/ssh_add_ssh_key.py} +26 -7
  105. machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_linux.py +7 -7
  106. machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_windows.py +4 -4
  107. machineconfig/scripts/python/helpers_repos/clone.py +0 -1
  108. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +13 -5
  109. machineconfig/scripts/python/helpers_repos/entrypoint.py +2 -1
  110. machineconfig/scripts/python/helpers_repos/record.py +2 -1
  111. machineconfig/scripts/python/helpers_repos/repo_analyzer_1.py +160 -0
  112. machineconfig/scripts/python/helpers_repos/{count_lines.py → repo_analyzer_2.py} +113 -192
  113. machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +19 -13
  114. machineconfig/scripts/python/helpers_utils/download.py +150 -0
  115. machineconfig/scripts/python/helpers_utils/pdf.py +96 -0
  116. machineconfig/scripts/python/helpers_utils/python.py +187 -0
  117. machineconfig/scripts/python/interactive.py +17 -26
  118. machineconfig/scripts/python/{machineconfig.py → mcfg_entry.py} +4 -5
  119. machineconfig/scripts/python/msearch.py +57 -6
  120. machineconfig/scripts/python/sessions.py +100 -31
  121. machineconfig/scripts/python/terminal.py +26 -17
  122. machineconfig/scripts/python/utils.py +17 -15
  123. machineconfig/scripts/windows/wrap_mcfg.ps1 +6 -3
  124. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  125. machineconfig/settings/linters/.ruff.toml +1 -1
  126. machineconfig/settings/shells/bash/init.sh +29 -2
  127. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
  128. machineconfig/settings/shells/nushell/config.nu +2 -2
  129. machineconfig/settings/shells/nushell/env.nu +45 -6
  130. machineconfig/settings/shells/nushell/init.nu +282 -95
  131. machineconfig/settings/shells/pwsh/init.ps1 +1 -0
  132. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  133. machineconfig/settings/shells/zsh/init.sh +1 -8
  134. machineconfig/settings/television/cable_unix/alias.toml +8 -0
  135. machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
  136. machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
  137. machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
  138. machineconfig/settings/television/cable_unix/channels.toml +19 -0
  139. machineconfig/settings/television/cable_unix/dirs.toml +13 -0
  140. machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
  141. machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
  142. machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
  143. machineconfig/settings/television/cable_unix/env.toml +17 -0
  144. machineconfig/settings/television/cable_unix/files.toml +11 -0
  145. machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
  146. machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
  147. machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
  148. machineconfig/settings/television/cable_unix/git-log.toml +12 -0
  149. machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
  150. machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
  151. machineconfig/settings/television/cable_unix/guix.toml +20 -0
  152. machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
  153. machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
  154. machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
  155. machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
  156. machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
  157. machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
  158. machineconfig/settings/television/cable_unix/procs.toml +20 -0
  159. machineconfig/settings/television/cable_unix/text.toml +17 -0
  160. machineconfig/settings/television/cable_unix/tldr.toml +18 -0
  161. machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
  162. machineconfig/settings/television/cable_windows/alias.toml +7 -0
  163. machineconfig/settings/television/cable_windows/dirs.toml +13 -0
  164. machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
  165. machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
  166. machineconfig/settings/television/cable_windows/env.toml +17 -0
  167. machineconfig/settings/television/cable_windows/files.toml +14 -0
  168. machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
  169. machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
  170. machineconfig/settings/television/cable_windows/git-log.toml +11 -0
  171. machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
  172. machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
  173. machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
  174. machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
  175. machineconfig/settings/television/cable_windows/text.toml +17 -0
  176. machineconfig/settings/wt/__init__.py +0 -0
  177. machineconfig/settings/yazi/init.lua +49 -24
  178. machineconfig/settings/yazi/keymap_linux.toml +19 -4
  179. machineconfig/settings/yazi/keymap_windows.toml +0 -1
  180. machineconfig/settings/yazi/shell/yazi_cd.ps1 +29 -5
  181. machineconfig/settings/yazi/theme.toml +4 -0
  182. machineconfig/settings/yazi/yazi_linux.toml +84 -0
  183. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  184. machineconfig/settings/zellij/layouts/st.kdl +39 -8
  185. machineconfig/setup_linux/__init__.py +1 -2
  186. machineconfig/setup_linux/apps_desktop.sh +8 -27
  187. machineconfig/setup_linux/web_shortcuts/interactive.sh +12 -10
  188. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +31 -0
  189. machineconfig/setup_mac/__init__.py +2 -3
  190. machineconfig/setup_windows/__init__.py +3 -5
  191. machineconfig/setup_windows/ssh/openssh-server.ps1 +1 -1
  192. machineconfig/setup_windows/uv.ps1 +8 -1
  193. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +12 -10
  194. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +30 -0
  195. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  196. machineconfig/utils/accessories.py +7 -4
  197. machineconfig/utils/code.py +39 -11
  198. machineconfig/utils/files/headers.py +2 -2
  199. machineconfig/utils/installer_utils/github_release_bulk.py +156 -119
  200. machineconfig/utils/installer_utils/install_from_url.py +183 -0
  201. machineconfig/utils/installer_utils/installer_class.py +43 -100
  202. machineconfig/utils/installer_utils/installer_cli.py +175 -0
  203. machineconfig/utils/installer_utils/installer_helper.py +129 -0
  204. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +36 -85
  205. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +16 -59
  206. machineconfig/utils/io.py +0 -1
  207. machineconfig/utils/links.py +2 -2
  208. machineconfig/utils/meta.py +30 -16
  209. machineconfig/utils/options.py +42 -24
  210. machineconfig/utils/options_tv.py +119 -0
  211. machineconfig/utils/path_extended.py +42 -20
  212. machineconfig/utils/path_helper.py +75 -22
  213. machineconfig/utils/procs.py +1 -1
  214. machineconfig/utils/scheduler.py +20 -53
  215. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  216. machineconfig/utils/ssh.py +159 -418
  217. machineconfig/utils/ssh_utils/abc.py +5 -0
  218. machineconfig/utils/ssh_utils/copy_from_here.py +111 -0
  219. machineconfig/utils/ssh_utils/copy_to_here.py +303 -0
  220. machineconfig/utils/ssh_utils/utils.py +142 -0
  221. machineconfig/utils/ssh_utils/wsl.py +210 -0
  222. machineconfig/utils/terminal.py +1 -0
  223. machineconfig/utils/upgrade_packages.py +6 -1
  224. machineconfig/utils/ve.py +12 -4
  225. machineconfig-8.12.dist-info/METADATA +132 -0
  226. {machineconfig-7.50.dist-info → machineconfig-8.12.dist-info}/RECORD +265 -215
  227. {machineconfig-7.50.dist-info → machineconfig-8.12.dist-info}/entry_points.txt +2 -4
  228. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -41
  229. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -71
  230. machineconfig/jobs/installer/powershell_scripts/archive_pygraphviz.ps1 +0 -12
  231. machineconfig/jobs/installer/powershell_scripts/openssh-server_add_key.ps1 +0 -7
  232. machineconfig/jobs/installer/powershell_scripts/openssh-server_copy-ssh-id.ps1 +0 -14
  233. machineconfig/scripts/linux/other/switch_ip +0 -20
  234. machineconfig/scripts/python/ai/command_runner/prompt.txt +0 -9
  235. machineconfig/scripts/python/define.py +0 -31
  236. machineconfig/scripts/python/explore.py +0 -49
  237. machineconfig/scripts/python/helpers_devops/cli_utils.py +0 -246
  238. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfag +0 -17
  239. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfrga +0 -21
  240. machineconfig/scripts/python/helpers_msearch/scripts_linux/skrg +0 -4
  241. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfb.ps1 +0 -3
  242. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfrga.bat +0 -20
  243. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +0 -17
  244. machineconfig/scripts/python/nw/add_ssh_key.py +0 -148
  245. machineconfig/scripts/python/nw/wsl_windows_transfer.py +0 -66
  246. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
  247. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  248. machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
  249. machineconfig/settings/lf/windows/tst.ps1 +0 -1
  250. machineconfig/settings/yazi/yazi.toml +0 -17
  251. machineconfig/setup_linux/apps.sh +0 -66
  252. machineconfig/setup_linux/others/cli_installation.sh +0 -137
  253. machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
  254. machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
  255. machineconfig/setup_mac/apps.sh +0 -73
  256. machineconfig/setup_windows/apps.ps1 +0 -62
  257. machineconfig/setup_windows/others/obs.ps1 +0 -4
  258. machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
  259. machineconfig/utils/installer_utils/installer.py +0 -221
  260. machineconfig-7.50.dist-info/METADATA +0 -92
  261. /machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +0 -0
  262. /machineconfig/jobs/installer/{custom_dev → python_scripts}/__init__.py +0 -0
  263. /machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
  264. /machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
  265. /machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
  266. /machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
  267. /machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
  268. /machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
  269. /machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
  270. /machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
  271. /machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/android.sh +0 -0
  272. /machineconfig/jobs/{installer/linux_scripts → scripts/bash_scripts}/lid.sh +0 -0
  273. /machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/mint_keyboard_shortcuts.sh +0 -0
  274. /machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_drive +0 -0
  275. /machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nw_drive +0 -0
  276. /machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_smb +0 -0
  277. /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_cloud.sh +0 -0
  278. /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_nfs +0 -0
  279. /machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/start_docker +0 -0
  280. /machineconfig/{scripts → jobs/scripts/powershell_scripts}/Restore-ThunderbirdProfile.ps1 +0 -0
  281. /machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/docker.ps1 +0 -0
  282. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nfs.ps1 +0 -0
  283. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nw.ps1 +0 -0
  284. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_smb.ps1 +0 -0
  285. /machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/power_options.ps1 +0 -0
  286. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_cloud.cmd +0 -0
  287. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_smb.ps1 +0 -0
  288. /machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
  289. /machineconfig/scripts/python/{nw → ai/utils}/__init__.py +0 -0
  290. /machineconfig/scripts/python/ai/{vscode_tasks.py → utils/vscode_tasks.py} +0 -0
  291. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_fire_command/f.py} +0 -0
  292. /machineconfig/{setup_windows/wt_and_pwsh → scripts/python/helpers_network}/__init__.py +0 -0
  293. /machineconfig/scripts/python/{nw → helpers_network}/mount_nw_drive.py +0 -0
  294. /machineconfig/scripts/python/{nw → helpers_network}/onetimeshare.py +0 -0
  295. /machineconfig/scripts/python/{nw → helpers_network}/wifi_conn.py +0 -0
  296. /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
  297. {machineconfig-7.50.dist-info → machineconfig-8.12.dist-info}/WHEEL +0 -0
  298. {machineconfig-7.50.dist-info → machineconfig-8.12.dist-info}/top_level.txt +0 -0
@@ -7,39 +7,20 @@ fire
7
7
 
8
8
  """
9
9
 
10
- from machineconfig.utils.ve import get_ve_path_and_ipython_profile
11
- from machineconfig.utils.options import choose_from_options
12
- from machineconfig.utils.path_helper import match_file_name, sanitize_path
13
- from machineconfig.utils.path_extended import PathExtended
14
- from machineconfig.utils.accessories import get_repo_root, randstr
15
- from machineconfig.scripts.python.helpers_fire_command.fire_jobs_args_helper import FireJobArgs, extract_kwargs, parse_fire_args_from_context
16
-
17
- import platform
18
10
  from typing import Optional, Annotated
19
- from pathlib import Path
20
11
  import typer
21
12
 
22
13
 
23
- def route(args: FireJobArgs, fire_args: str = "") -> None:
24
- path_obj = sanitize_path(args.path)
25
- if not path_obj.exists():
26
- suffixes = {".py", ".sh", ".ps1"}
27
- choice_file = match_file_name(sub_string=args.path, search_root=PathExtended.cwd(), suffixes=suffixes)
28
- elif path_obj.is_dir():
29
- from machineconfig.scripts.python.helpers_fire_command.file_wrangler import search_for_files_of_interest
30
- print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
31
- files = search_for_files_of_interest(path_obj)
32
- print(f"🔍 Got #{len(files)} results.")
33
- choice_file = choose_from_options(multi=False, options=files, fzf=True, msg="Choose one option")
34
- choice_file = PathExtended(choice_file)
35
- else:
36
- choice_file = path_obj
37
-
38
- repo_root = get_repo_root(Path(choice_file))
14
+ def route(args: "FireJobArgs", fire_args: str = "") -> None:
15
+ from pathlib import Path
16
+ from machineconfig.utils.path_helper import get_choice_file
17
+ from machineconfig.utils.accessories import get_repo_root, randstr
18
+ choice_file = get_choice_file(args.path, suffixes=None)
19
+ repo_root = get_repo_root(choice_file)
39
20
  print(f"💾 Selected file: {choice_file}.\nRepo root: {repo_root}")
40
21
  if args.marimo:
41
22
  print(f"🧽 Preparing to launch Marimo notebook for `{choice_file}`...")
42
- tmp_dir = PathExtended.tmp().joinpath(f"tmp_scripts/marimo/{choice_file.stem}_{randstr()}")
23
+ tmp_dir = Path.home().joinpath(f"tmp_results/tmp_scripts/marimo/{choice_file.stem}_{randstr()}")
43
24
  tmp_dir.mkdir(parents=True, exist_ok=True)
44
25
  script = f"""
45
26
  cd {tmp_dir}
@@ -53,7 +34,7 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
53
34
 
54
35
  # ========================= preparing kwargs_dict
55
36
  if choice_file.suffix == ".py":
56
-
37
+ from machineconfig.scripts.python.helpers_fire_command.fire_jobs_args_helper import extract_kwargs
57
38
  kwargs_dict = extract_kwargs(args) # This now returns empty dict, but kept for compatibility
58
39
  else:
59
40
  kwargs_dict = {}
@@ -62,70 +43,108 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
62
43
  choice_function: Optional[str] = None # Initialize to avoid unbound variable
63
44
  if args.choose_function:
64
45
  from machineconfig.scripts.python.helpers_fire_command.fire_jobs_route_helper import choose_function_or_lines
46
+
65
47
  choice_function, choice_file, kwargs_dict = choose_function_or_lines(choice_file, kwargs_dict)
66
48
  else:
67
49
  choice_function = args.function
68
50
 
69
51
  if choice_file.suffix == ".py":
70
- from machineconfig.scripts.python.helpers_fire_command.fire_jobs_route_helper import get_command_streamlit
52
+ module_line = "-m" if args.module else ""
71
53
  with_project = f"--project {repo_root} " if repo_root is not None else ""
54
+ interactive_line = "-i" if args.interactive else ""
55
+ if args.interactive:
56
+ from machineconfig.utils.ve import get_ve_path_and_ipython_profile
57
+ _ve_root_from_file, ipy_profile = get_ve_path_and_ipython_profile(init_path=choice_file)
58
+ if ipy_profile is None:
59
+ ipy_profile = "default"
60
+ ipython_line = f"--no-banner --profile {ipy_profile} "
61
+ else:
62
+ ipython_line = ""
63
+
72
64
  if args.streamlit:
73
- exe = get_command_streamlit(choice_file=choice_file, environment=args.environment, repo_root=repo_root)
74
- exe = f"uv run {with_project} {exe} "
75
- elif args.jupyter: exe = f"uv run {with_project} jupyter-lab"
65
+ from machineconfig.scripts.python.helpers_fire_command.fire_jobs_route_helper import get_command_streamlit
66
+ interpreter_line = get_command_streamlit(choice_file=choice_file, environment=args.environment, repo_root=repo_root)
67
+ elif args.jupyter:
68
+ interpreter_line = "jupyter-lab"
69
+ else:
70
+ interpreter_line = "python" if not args.interactive else "ipython"
71
+
72
+ exe_line = f"uv run {with_project} {interpreter_line} {interactive_line} {module_line} {ipython_line}"
73
+
74
+
75
+ elif choice_file.suffix == ".ps1" or choice_file.suffix == ".sh":
76
+ exe_line = "."
77
+ elif choice_file.suffix == "":
78
+ exe_line = ""
79
+ else:
80
+ raise NotImplementedError(f"File type {choice_file.suffix} not supported, in the sense that I don't know how to fire it.")
81
+
82
+ if args.module and choice_file.suffix == ".py":
83
+ if repo_root is not None:
84
+ choice_file_adjusted = ".".join(Path(choice_file).relative_to(repo_root).parts).replace(".py", "")
76
85
  else:
77
- if args.interactive:
78
- _ve_root_from_file, ipy_profile = get_ve_path_and_ipython_profile(choice_file)
79
- if ipy_profile is None:
80
- ipy_profile = "default"
81
- exe = f"uv run {with_project} ipython -i --no-banner --profile {ipy_profile} "
82
- else:
83
- exe = f"uv run {with_project} python "
84
- elif choice_file.suffix == ".ps1" or choice_file.suffix == ".sh": exe = "."
85
- elif choice_file.suffix == "": exe = ""
86
- else: raise NotImplementedError(f"File type {choice_file.suffix} not supported, in the sense that I don't know how to fire it.")
87
-
88
- if args.module or (args.debug and args.choose_function): # because debugging tools do not support choosing functions and don't interplay with fire module. So the only way to have debugging and choose function options is to import the file as a module into a new script and run the function of interest there and debug the new script.
86
+ choice_file_adjusted = ".".join(Path(choice_file).relative_to(Path.cwd()).parts).replace(".py", "")
87
+ else:
88
+ choice_file_adjusted = str(choice_file)
89
+
90
+ if args.script or (args.debug and args.choose_function):
91
+ # because debugging tools do not support choosing functions and don't interplay with fire module. So the only way to have debugging and choose function options is to import the file as a module into a new script and run the function of interest there and debug the new script.
89
92
  assert choice_file.suffix == ".py", f"File must be a python file to be imported as a module. Got {choice_file}"
90
93
  from machineconfig.scripts.python.helpers_fire_command.file_wrangler import get_import_module_code, wrap_import_in_try_except
91
94
  from machineconfig.utils.meta import lambda_to_python_script
92
95
  from machineconfig.utils.code import print_code
96
+
93
97
  import_code = get_import_module_code(str(choice_file))
94
- import_code_robust = lambda_to_python_script(lambda: wrap_import_in_try_except(import_line=import_code, pyfile=str(choice_file), repo_root=str(repo_root) if repo_root is not None else None), in_global=True, import_module=False)
95
- code_printing = lambda_to_python_script(lambda: print_code(code=import_code_robust, lexer="python", desc="import code"), in_global=True, import_module=False)
96
- if choice_function is not None: calling = f"""res = {choice_function}({("**" + str(kwargs_dict)) if kwargs_dict else ""})"""
97
- else: calling = """# No function selected to call. You can add your code here."""
98
+ import_code_robust = lambda_to_python_script(
99
+ lambda: wrap_import_in_try_except(
100
+ import_line=import_code, pyfile=str(choice_file), repo_root=str(repo_root) if repo_root is not None else None
101
+ ),
102
+ in_global=True,
103
+ import_module=False,
104
+ )
105
+ # print(f"🧩 Preparing import code for module import:\n{import_code}")
106
+ code_printing = lambda_to_python_script(
107
+ lambda: print_code(code=import_code_robust, lexer="python", desc="import as module code"),
108
+ in_global=True, import_module=False
109
+ )
110
+ print(f"🧩 Preparing import code for module import:\n{import_code}")
111
+ if choice_function is not None:
112
+ calling = f"""res = {choice_function}({("**" + str(kwargs_dict)) if kwargs_dict else ""})"""
113
+ else:
114
+ calling = """# No function selected to call. You can add your code here."""
98
115
  choice_file = Path.home().joinpath(f"tmp_results/tmp_scripts/python/{Path(choice_file).parent.name}_{Path(choice_file).stem}_{randstr()}.py")
99
116
  choice_file.parent.mkdir(parents=True, exist_ok=True)
100
117
  choice_file.write_text(import_code_robust + "\n" + code_printing + "\n" + calling, encoding="utf-8")
101
118
 
102
- # ========================= determining basic command structure: putting together exe & choice_file & choice_function & pdb
103
119
  if args.debug:
120
+ import platform
104
121
  if platform.system() == "Windows":
105
- command = f"{exe} -m ipdb {choice_file} " # pudb is not available on windows machines, use poor man's debugger instead.
122
+ command = f"{exe_line} -m ipdb {choice_file_adjusted} " # pudb is not available on windows machines, use poor man's debugger instead.
106
123
  elif platform.system() in ["Linux", "Darwin"]:
107
- command = f"{exe} -m pudb {choice_file} " # TODO: functions not supported yet in debug mode.
124
+ command = f"{exe_line} -m pudb {choice_file_adjusted} " # TODO: functions not supported yet in debug mode.
108
125
  else:
109
126
  raise NotImplementedError(f"Platform {platform.system()} not supported.")
110
127
  elif args.module:
111
128
  # both selected function and kwargs are mentioned in the made up script, therefore no need for fire module.
112
- command = f"{exe} {choice_file} "
129
+ command = f"{exe_line} {choice_file_adjusted} "
113
130
  elif choice_function is not None and choice_file.suffix == ".py":
114
- command = f"{exe} -m fire {choice_file} {choice_function} {fire_args}"
131
+ command = f"{exe_line} -m fire {choice_file_adjusted} {choice_function} {fire_args}"
115
132
  elif args.streamlit:
116
133
  # for .streamlit config to work, it needs to be in the current directory.
117
134
  if args.holdDirectory:
118
- command = f"{exe} {choice_file}"
135
+ command = f"{exe_line} {choice_file}"
119
136
  else:
120
- command = f"cd {choice_file.parent}\n{exe} {choice_file.name}\ncd {PathExtended.cwd()}"
137
+ command = f"cd {choice_file.parent}\n{exe_line} {choice_file.name}\ncd {Path.cwd()}"
121
138
  elif args.cmd:
122
- command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
139
+ command = rf""" cd /d {choice_file.parent} & {exe_line} {choice_file.name} """
123
140
  else:
124
- if choice_file.suffix == "": command = f"{exe} {choice_file} {fire_args}"
125
- else: command = f"{exe} {choice_file} "
126
-
141
+ if choice_file.suffix == "":
142
+ command = f"{exe_line} {choice_file} {fire_args}"
143
+ else:
144
+ command = f"{exe_line} {choice_file} "
127
145
 
128
- if not args.cmd: pass
146
+ if not args.cmd:
147
+ pass
129
148
  else:
130
149
  new_line = "\n"
131
150
  command = rf"""start cmd -Argument "/k {command.replace(new_line, " & ")} " """ # this works from powershell
@@ -134,23 +153,27 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
134
153
  if choice_function is not None:
135
154
  command += f"--function {choice_function} "
136
155
 
137
- if args.optimized: command = command.replace("python ", "python -OO ")
156
+ if args.optimized:
157
+ command = command.replace("python ", "python -OO ")
138
158
 
139
159
  from rich.panel import Panel
140
160
  from rich.console import Console
141
161
  from rich.syntax import Syntax
162
+
142
163
  console = Console()
143
164
  if args.zellij_tab is not None:
144
- comman_path__ = PathExtended.tmpfile(suffix=".sh")
165
+ comman_path__ = Path.home().joinpath(f"tmp_results/tmp_scripts/zellij_commands/{choice_file.stem}_{randstr()}.sh")
145
166
  comman_path__.parent.mkdir(parents=True, exist_ok=True)
146
167
  comman_path__.write_text(command, encoding="utf-8")
147
168
  console.print(Panel(Syntax(command, lexer="shell"), title=f"🔥 fire command @ {comman_path__}: "), style="bold red")
148
169
  import subprocess
170
+
149
171
  existing_tab_names = subprocess.run(["zellij", "action", "query-tab-names"], capture_output=True, text=True, check=True).stdout.splitlines()
150
172
  if args.zellij_tab in existing_tab_names:
151
173
  print(f"⚠️ Tab name `{args.zellij_tab}` already exists. Please choose a different name.")
152
174
  args.zellij_tab += f"_{randstr(3)}"
153
175
  from machineconfig.cluster.sessions_managers.zellij_local import run_command_in_zellij_tab
176
+
154
177
  command = run_command_in_zellij_tab(command=str(comman_path__), tab_name=args.zellij_tab, cwd=None)
155
178
  if args.watch:
156
179
  command = "watchexec --restart --exts py,sh,ps1 " + command
@@ -158,16 +181,17 @@ uv run --project {repo_root} --with marimo marimo edit --host 0.0.0.0 marimo_nb.
158
181
  command = f"\ngit -C {choice_file.parent} pull\n" + command
159
182
  if args.PathExport:
160
183
  from machineconfig.scripts.python.helpers_fire_command.file_wrangler import add_to_path
184
+
161
185
  export_line = add_to_path(path_variable="PYTHONPATH", directory=str(repo_root))
162
186
  command = export_line + "\n" + command
163
187
  if args.loop:
188
+ import platform
164
189
  if platform.system() in ["Linux", "Darwin"]:
165
190
  command = command + "\nsleep 0.5"
166
191
  elif platform.system() == "Windows":
167
192
  command = "$ErrorActionPreference = 'SilentlyContinue';\n" + command + "\nStart-Sleep -Seconds 0.5"
168
193
  else:
169
194
  raise NotImplementedError(f"Platform {platform.system()} not supported.")
170
-
171
195
  from machineconfig.utils.code import exit_then_run_shell_script
172
196
  exit_then_run_shell_script(script=command, strict=False)
173
197
 
@@ -185,23 +209,24 @@ def fire(
185
209
  jupyter: Annotated[bool, typer.Option("--jupyter", "-j", help="Open in a jupyter notebook")] = False,
186
210
  marimo: Annotated[bool, typer.Option("--marimo", "-M", help="Open in a marimo notebook")] = False,
187
211
  module: Annotated[bool, typer.Option("--module", "-m", help="Launch the main file")] = False,
212
+ script: Annotated[bool, typer.Option("--script", "-s", help="Launch as a script without fire")] = False,
188
213
  optimized: Annotated[bool, typer.Option("--optimized", "-O", help="Run the optimized version of the function")] = False,
189
214
  zellij_tab: Annotated[Optional[str], typer.Option("--zellij-tab", "-z", help="Open in a new zellij tab")] = None,
190
-
191
215
  submit_to_cloud: Annotated[bool, typer.Option("--submit-to-cloud", "-C", help="Submit to cloud compute")] = False,
192
216
  remote: Annotated[bool, typer.Option("--remote", "-r", help="Launch on a remote machine")] = False,
193
-
194
217
  streamlit: Annotated[bool, typer.Option("--streamlit", "-S", help="Run as streamlit app")] = False,
195
218
  environment: Annotated[str, typer.Option("--environment", "-E", help="Choose ip, localhost, hostname or arbitrary url")] = "",
196
- holdDirectory: Annotated[bool, typer.Option("--holdDirectory", "-D", help="Hold current directory and avoid cd'ing to the script directory")] = False,
219
+ holdDirectory: Annotated[
220
+ bool, typer.Option("--holdDirectory", "-D", help="Hold current directory and avoid cd'ing to the script directory")
221
+ ] = False,
197
222
  PathExport: Annotated[bool, typer.Option("--PathExport", "-P", help="Augment the PYTHONPATH with repo root")] = False,
198
-
199
223
  git_pull: Annotated[bool, typer.Option("--git-pull", "-g", help="Start by pulling the git repo")] = False,
200
224
  watch: Annotated[bool, typer.Option("--watch", "-w", help="Watch the file for changes")] = False,
201
225
  ) -> None:
202
226
  """Main function to process fire jobs arguments."""
203
227
 
204
228
  # Get Fire arguments from context
229
+ from machineconfig.scripts.python.helpers_fire_command.fire_jobs_args_helper import FireJobArgs, parse_fire_args_from_context
205
230
  fire_args = parse_fire_args_from_context(ctx)
206
231
 
207
232
  args = FireJobArgs(
@@ -218,6 +243,7 @@ def fire(
218
243
  submit_to_cloud=submit_to_cloud,
219
244
  remote=remote,
220
245
  module=module,
246
+ script=script,
221
247
  streamlit=streamlit,
222
248
  environment=environment,
223
249
  holdDirectory=holdDirectory,
@@ -235,12 +261,14 @@ def fire(
235
261
  except Exception as e:
236
262
  # For other exceptions, print clean error message and exit
237
263
  import sys
264
+
238
265
  print(f"❌ Error: {e}", file=sys.stderr)
239
266
  sys.exit(1)
240
267
 
241
268
 
242
269
  def get_app():
243
270
  from typer import Typer
271
+
244
272
  app = Typer(add_completion=False)
245
273
  app.command(context_settings={"allow_extra_args": True, "allow_interspersed_args": False})(fire)
246
274
  return app
@@ -252,4 +280,4 @@ def main():
252
280
 
253
281
 
254
282
  if __name__ == "__main__":
255
- pass
283
+ from machineconfig.scripts.python.helpers_fire_command.fire_jobs_args_helper import FireJobArgs
@@ -6,17 +6,7 @@ Currently, the only way to work around this is to predifine the host in ~/.ssh/c
6
6
  """
7
7
 
8
8
  import typer
9
- from typing_extensions import Annotated
10
- from rich.console import Console
11
- from rich.panel import Panel
12
-
13
- from machineconfig.utils.ssh import SSH
14
- from machineconfig.utils.path_extended import PathExtended
15
- from machineconfig.scripts.python.helpers_cloud.helpers2 import ES
16
- from machineconfig.utils.accessories import pprint
17
-
18
-
19
- console = Console()
9
+ from typing import Annotated
20
10
 
21
11
 
22
12
  def ftpx(
@@ -25,7 +15,42 @@ def ftpx(
25
15
  recursive: Annotated[bool, typer.Option("--recursive", "-r", help="Send recursively.")] = False,
26
16
  zipFirst: Annotated[bool, typer.Option("--zipFirst", "-z", help="Zip before sending.")] = False,
27
17
  cloud: Annotated[bool, typer.Option("--cloud", "-c", help="Transfer through the cloud.")] = False,
18
+ overwrite_existing: Annotated[bool, typer.Option("--overwrite-existing", "-o", help="Overwrite existing files on remote when sending from local to remote.")] = False,
28
19
  ) -> None:
20
+ """File transfer utility though SSH."""
21
+ from pathlib import Path
22
+ if target == "wsl" or source == "wsl":
23
+ from machineconfig.utils.ssh_utils.wsl import copy_when_inside_windows
24
+ if target == "wsl":
25
+ target_obj = Path(source).expanduser().absolute().relative_to(Path.home())
26
+ source_obj = target_obj
27
+ else:
28
+ source_obj = Path(target).expanduser().absolute().relative_to(Path.home())
29
+ target_obj = source_obj
30
+ copy_when_inside_windows(source_obj, target_obj, overwrite_existing)
31
+ return
32
+ elif source == "win" or target == "win":
33
+ if source == "win":
34
+ source_obj = Path(target).expanduser().absolute().relative_to(Path.home())
35
+ target_obj = source_obj
36
+ else:
37
+ target_obj = Path(source).expanduser().absolute().relative_to(Path.home())
38
+ source_obj = target_obj
39
+ from machineconfig.utils.ssh_utils.wsl import copy_when_inside_wsl
40
+ copy_when_inside_wsl(source_obj, target_obj, overwrite_existing)
41
+ return
42
+
43
+ from rich.console import Console
44
+ from rich.panel import Panel
45
+
46
+ from machineconfig.utils.ssh import SSH
47
+ from machineconfig.utils.path_extended import PathExtended
48
+ from machineconfig.scripts.python.helpers_cloud.helpers2 import ES
49
+ from machineconfig.utils.accessories import pprint
50
+
51
+
52
+ console = Console()
53
+
29
54
  console.print(
30
55
  Panel(
31
56
  "\n".join(
@@ -133,7 +158,7 @@ def ftpx(
133
158
  border_style="cyan",
134
159
  )
135
160
  )
136
- ssh.run_shell(command=f"cloud_copy {resolved_source} :^", verbose_output=True, description="Uploading from remote to the cloud.", strict_stderr=False, strict_return_code=False)
161
+ ssh.run_shell_cmd_on_remote(command=f"cloud_copy {resolved_source} :^", verbose_output=True, description="Uploading from remote to the cloud.", strict_stderr=False, strict_return_code=False)
137
162
  console.print(
138
163
  Panel.fit(
139
164
  "⬇️ Cloud transfer mode — downloading from cloud to local...",
@@ -141,12 +166,14 @@ def ftpx(
141
166
  border_style="cyan",
142
167
  )
143
168
  )
144
- ssh.run_locally(command=f"cloud_copy :^ {resolved_target}")
169
+ ssh.run_shell_cmd_on_local(command=f"cloud_copy :^ {resolved_target}")
145
170
  received_file = PathExtended(resolved_target) # type: ignore
146
171
  else:
147
172
  if source_is_remote:
148
- assert resolved_source is not None, """
149
- ❌ Path Error: Source must be a remote path (machine:path)"""
173
+ if resolved_source is None:
174
+ typer.echo("""❌ Path Error: Source must be a remote path (machine:path)""")
175
+ typer.Exit(code=1)
176
+ return
150
177
  target_display = resolved_target or "<auto>"
151
178
  console.print(
152
179
  Panel(
@@ -183,7 +210,7 @@ def ftpx(
183
210
  padding=(1, 2),
184
211
  )
185
212
  )
186
- received_file = ssh.copy_from_here(source_path=resolved_source, target_rel2home=resolved_target, compress_with_zip=zipFirst, recursive=recursive, overwrite_existing=False)
213
+ received_file = ssh.copy_from_here(source_path=resolved_source, target_rel2home=resolved_target, compress_with_zip=zipFirst, recursive=recursive, overwrite_existing=overwrite_existing)
187
214
 
188
215
  if source_is_remote and isinstance(received_file, PathExtended):
189
216
  console.print(
@@ -213,7 +240,7 @@ def ftpx(
213
240
  def main() -> None:
214
241
  """Entry point function that uses typer to parse arguments and call main."""
215
242
  app = typer.Typer()
216
- app.command(no_args_is_help=True, help="File transfer utility though SSH.")(ftpx)
243
+ app.command(no_args_is_help=True, help=ftpx.__doc__, short_help="File transfer utility though SSH.")(ftpx)
217
244
  app()
218
245
 
219
246
 
@@ -0,0 +1,74 @@
1
+
2
+ import ast
3
+ import os
4
+ from typing import TypedDict
5
+
6
+
7
+ class SymbolInfo(TypedDict):
8
+ """Represents a symbol (module, class, or function) in the repository."""
9
+ type: str
10
+ name: str
11
+ path: str
12
+ # line: int | None
13
+ # column: int | None
14
+ docstring: str
15
+
16
+
17
+ def _get_docstring(node: ast.AsyncFunctionDef | ast.FunctionDef | ast.ClassDef | ast.Module) -> str:
18
+ """Extract docstring from an AST node."""
19
+ return ast.get_docstring(node) or ""
20
+
21
+
22
+ def _extract_symbols(tree: ast.AST, module_path: str, source: str) -> list[SymbolInfo]:
23
+ """Extract symbols from an AST tree."""
24
+ symbols: list[SymbolInfo] = []
25
+
26
+ for node in ast.walk(tree):
27
+ if isinstance(node, ast.FunctionDef | ast.AsyncFunctionDef):
28
+ symbol: SymbolInfo = {
29
+ "type": "function",
30
+ "name": node.name,
31
+ "path": f"{module_path}.{node.name}",
32
+ "docstring": _get_docstring(node),
33
+ }
34
+ symbols.append(symbol)
35
+ elif isinstance(node, ast.ClassDef):
36
+ symbol: SymbolInfo = {
37
+ "type": "class",
38
+ "name": node.name,
39
+ "path": f"{module_path}.{node.name}",
40
+ "docstring": _get_docstring(node),
41
+ }
42
+ symbols.append(symbol)
43
+
44
+ return symbols
45
+
46
+
47
+ def get_repo_symbols(repo_path: str) -> list[SymbolInfo]:
48
+ skip_dirs = {'.venv', 'venv', '__pycache__', '.mypy_cache', '.pytest_cache', '.git'}
49
+ results: list[SymbolInfo] = []
50
+ counter: int = 0
51
+ for root, dirs, files in os.walk(repo_path):
52
+ dirs[:] = [d for d in dirs if d not in skip_dirs and not d.startswith('.')]
53
+ for file in files:
54
+ if not file.endswith(".py"):
55
+ continue
56
+ file_path = os.path.join(root, file)
57
+ module_path = (
58
+ os.path.relpath(file_path, repo_path)
59
+ .replace(os.sep, ".")
60
+ .removesuffix(".py")
61
+ )
62
+ try:
63
+ if counter % 100 == 0: print(f"🔍 Parsing {counter}: {file_path}...")
64
+ with open(file_path, encoding="utf-8") as f:
65
+ source = f.read()
66
+ tree = ast.parse(source, filename=file_path)
67
+ symbols = _extract_symbols(tree, module_path, source)
68
+ results.extend(symbols)
69
+ except Exception as e:
70
+ print(f"⚠️ Error parsing {file_path}: {e}")
71
+ continue
72
+ counter += 1
73
+
74
+ return results
@@ -0,0 +1,166 @@
1
+
2
+
3
+ from typing import Literal
4
+
5
+
6
+ def generate_qrcode_grid(
7
+ strings: list[str],
8
+ output_path: str,
9
+ per_row: int = 3,
10
+ qr_size: int = 200,
11
+ label_height: int = 30,
12
+ padding: int = 20,
13
+ label_max_chars: int = 25,
14
+ format: Literal["svg", "png"] = "svg",
15
+ ) -> str:
16
+ from pathlib import Path
17
+ if not strings:
18
+ raise ValueError("strings list cannot be empty")
19
+
20
+ output_path_obj = Path(output_path)
21
+ output_path_obj.parent.mkdir(parents=True, exist_ok=True)
22
+
23
+ if format == "svg":
24
+ return _generate_svg(strings, output_path, per_row, qr_size, label_height, padding, label_max_chars)
25
+ elif format == "png":
26
+ return _generate_png(strings, output_path, per_row, qr_size, label_height, padding, label_max_chars)
27
+ else:
28
+ raise ValueError(f"Unsupported format: {format}")
29
+
30
+
31
+ def _generate_svg(
32
+ strings: list[str],
33
+ output_path: str,
34
+ per_row: int,
35
+ qr_size: int,
36
+ label_height: int,
37
+ padding: int,
38
+ label_max_chars: int,
39
+ ) -> str:
40
+ num_items = len(strings)
41
+ num_rows = (num_items + per_row - 1) // per_row
42
+
43
+ cell_width = qr_size
44
+ cell_height = qr_size + label_height
45
+ total_width = per_row * cell_width + (per_row + 1) * padding
46
+ total_height = num_rows * cell_height + (num_rows + 1) * padding
47
+
48
+ from xml.etree import ElementTree as ET
49
+
50
+ import qrcode
51
+ svg_root = ET.Element(
52
+ "svg",
53
+ xmlns="http://www.w3.org/2000/svg",
54
+ width=str(total_width),
55
+ height=str(total_height),
56
+ viewBox=f"0 0 {total_width} {total_height}",
57
+ )
58
+
59
+ _bg_rect = ET.SubElement(svg_root, "rect", width=str(total_width), height=str(total_height), fill="white")
60
+
61
+ for idx, text in enumerate(strings):
62
+ row = idx // per_row
63
+ col = idx % per_row
64
+
65
+ x_offset = padding + col * (cell_width + padding)
66
+ y_offset = padding + row * (cell_height + padding)
67
+
68
+ qr = qrcode.QRCode(version=1, error_correction=qrcode.ERROR_CORRECT_L, box_size=10, border=2, image_factory=qrcode.image.svg.SvgPathImage) # type: ignore
69
+ qr.add_data(text)
70
+ qr.make(fit=True)
71
+
72
+ qr_img = qr.make_image()
73
+ qr_svg_string = qr_img.to_string(encoding="unicode")
74
+
75
+ qr_tree = ET.fromstring(qr_svg_string)
76
+
77
+ group = ET.SubElement(svg_root, "g", transform=f"translate({x_offset}, {y_offset})")
78
+
79
+ qr_group = ET.SubElement(group, "g")
80
+ for child in qr_tree:
81
+ qr_group.append(child)
82
+
83
+ label_text = text[:label_max_chars] if len(text) > label_max_chars else text
84
+ text_y = qr_size + label_height // 2
85
+
86
+ text_elem = ET.SubElement(
87
+ group,
88
+ "text",
89
+ x=str(qr_size // 2),
90
+ y=str(text_y),
91
+ fill="black",
92
+ attrib={
93
+ "font-family": "monospace",
94
+ "font-size": "12",
95
+ "text-anchor": "middle",
96
+ "dominant-baseline": "middle",
97
+ },
98
+ )
99
+ text_elem.text = label_text
100
+
101
+ tree = ET.ElementTree(svg_root)
102
+ ET.indent(tree, space=" ")
103
+ tree.write(output_path, encoding="unicode", xml_declaration=True)
104
+
105
+ return output_path
106
+
107
+
108
+ def _generate_png(
109
+ strings: list[str],
110
+ output_path: str,
111
+ per_row: int,
112
+ qr_size: int,
113
+ label_height: int,
114
+ padding: int,
115
+ label_max_chars: int,
116
+ ) -> str:
117
+ num_items = len(strings)
118
+ num_rows = (num_items + per_row - 1) // per_row
119
+
120
+ cell_width = qr_size
121
+ cell_height = qr_size + label_height
122
+ total_width = per_row * cell_width + (per_row + 1) * padding
123
+ total_height = num_rows * cell_height + (num_rows + 1) * padding
124
+
125
+ import qrcode
126
+ import qrcode.image.pil
127
+ from PIL import Image, ImageDraw, ImageFont
128
+ img = Image.new("RGB", (total_width, total_height), color="white")
129
+ draw = ImageDraw.Draw(img)
130
+
131
+ try:
132
+ font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 12)
133
+ except OSError:
134
+ try:
135
+ font = ImageFont.truetype("arial.ttf", 12)
136
+ except OSError:
137
+ font = ImageFont.load_default()
138
+
139
+ for idx, text in enumerate(strings):
140
+ row = idx // per_row
141
+ col = idx % per_row
142
+
143
+ x_offset = padding + col * (cell_width + padding)
144
+ y_offset = padding + row * (cell_height + padding)
145
+
146
+ qr = qrcode.QRCode(version=1, error_correction=qrcode.ERROR_CORRECT_L, box_size=10, border=2, image_factory=qrcode.image.pil.PilImage)
147
+ qr.add_data(text)
148
+ qr.make(fit=True)
149
+
150
+ qr_img = qr.make_image(fill_color="black", back_color="white")
151
+ qr_img_resized = qr_img.resize((qr_size, qr_size), Image.Resampling.LANCZOS)
152
+
153
+ img.paste(qr_img_resized, (x_offset, y_offset))
154
+
155
+ label_text = text[:label_max_chars] if len(text) > label_max_chars else text
156
+
157
+ bbox = draw.textbbox((0, 0), label_text, font=font)
158
+ text_width = bbox[2] - bbox[0]
159
+ text_x = x_offset + (qr_size - text_width) // 2
160
+ text_y = y_offset + qr_size + label_height // 2 - 6
161
+
162
+ draw.text((text_x, text_y), label_text, fill="black", font=font)
163
+
164
+ img.save(output_path, format="PNG")
165
+
166
+ return output_path