machineconfig 6.23__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 (402) hide show
  1. machineconfig/cluster/remote/cloud_manager.py +1 -1
  2. machineconfig/cluster/remote/distribute.py +0 -1
  3. machineconfig/cluster/remote/file_manager.py +0 -2
  4. machineconfig/cluster/sessions_managers/{utils → helpers}/enhanced_command_runner.py +4 -6
  5. machineconfig/cluster/sessions_managers/utils/load_balancer.py +1 -1
  6. machineconfig/cluster/sessions_managers/utils/maker.py +69 -0
  7. machineconfig/cluster/sessions_managers/wt_local.py +16 -221
  8. machineconfig/cluster/sessions_managers/wt_local_manager.py +55 -193
  9. machineconfig/cluster/sessions_managers/wt_remote_manager.py +42 -198
  10. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  11. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  12. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  13. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  14. machineconfig/cluster/sessions_managers/zellij_local.py +3 -3
  15. machineconfig/cluster/sessions_managers/zellij_local_manager.py +5 -3
  16. machineconfig/cluster/sessions_managers/zellij_remote.py +2 -2
  17. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +3 -2
  18. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +2 -2
  19. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +3 -7
  20. machineconfig/cluster/sessions_managers/{helpers → zellij_utils}/zellij_local_helper_with_panes.py +1 -1
  21. machineconfig/jobs/installer/check_installations.py +0 -1
  22. machineconfig/jobs/installer/installer_data.json +1408 -201
  23. machineconfig/jobs/installer/linux_scripts/q.sh +10 -7
  24. machineconfig/jobs/installer/linux_scripts/redis.sh +1 -0
  25. machineconfig/jobs/installer/package_groups.py +63 -92
  26. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  27. machineconfig/jobs/installer/python_scripts/boxes.py +61 -0
  28. machineconfig/jobs/installer/{custom_dev → python_scripts}/brave.py +5 -3
  29. machineconfig/jobs/installer/python_scripts/cloudflare_warp_cli.py +23 -0
  30. machineconfig/jobs/installer/{custom_dev → python_scripts}/code.py +4 -1
  31. machineconfig/jobs/installer/{custom_dev → python_scripts}/dubdb_adbc.py +1 -1
  32. machineconfig/jobs/installer/{custom → python_scripts}/hx.py +75 -18
  33. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerdfont.py +2 -2
  34. machineconfig/jobs/installer/{custom_dev → python_scripts}/nerfont_windows_helper.py +27 -22
  35. machineconfig/jobs/installer/python_scripts/sysabc.py +139 -0
  36. machineconfig/jobs/installer/{custom_dev → python_scripts}/wezterm.py +2 -19
  37. machineconfig/jobs/installer/{custom_dev → python_scripts}/winget.py +10 -14
  38. machineconfig/jobs/installer/python_scripts/yazi.py +121 -0
  39. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nfs +0 -1
  40. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +13 -0
  41. machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +4 -0
  42. machineconfig/jobs/scripts_dynamic/a.py +25 -0
  43. machineconfig/logger.py +0 -1
  44. machineconfig/profile/create_helper.py +56 -18
  45. machineconfig/profile/create_links.py +2 -1
  46. machineconfig/profile/create_links_export.py +64 -18
  47. machineconfig/profile/create_shell_profile.py +90 -132
  48. machineconfig/profile/mapper.toml +18 -8
  49. machineconfig/scripts/__init__.py +0 -4
  50. machineconfig/scripts/linux/wrap_mcfg +46 -0
  51. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  52. machineconfig/scripts/python/agents.py +82 -60
  53. machineconfig/scripts/python/ai/initai.py +1 -19
  54. machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
  55. machineconfig/scripts/python/ai/{command_runner → scripts}/command_runner.sh +1 -1
  56. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +1 -1
  57. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
  58. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
  59. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
  60. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +5 -5
  61. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +4 -0
  62. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
  63. machineconfig/scripts/python/ai/solutions/generic.py +1 -1
  64. machineconfig/scripts/python/ai/{generate_files.py → utils/generate_files.py} +2 -2
  65. machineconfig/scripts/python/ai/{vscode_tasks.py → utils/vscode_tasks.py} +7 -2
  66. machineconfig/scripts/python/cloud.py +14 -9
  67. machineconfig/scripts/python/croshell.py +135 -117
  68. machineconfig/scripts/python/devops.py +48 -25
  69. machineconfig/scripts/python/devops_navigator.py +1 -5
  70. machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
  71. machineconfig/scripts/python/env_manager/path_manager_tui.py +18 -9
  72. machineconfig/scripts/python/fire_jobs.py +127 -118
  73. machineconfig/scripts/python/ftpx.py +44 -17
  74. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  75. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  76. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  77. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  78. machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_crush.json +1 -1
  79. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +39 -0
  80. machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_cursor_agents.py +3 -4
  81. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +55 -0
  82. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  83. machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_help_launch.py +37 -15
  84. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +41 -0
  85. machineconfig/scripts/python/helpers_agents/privacy/configs/aichat/config.yaml +5 -0
  86. machineconfig/scripts/python/helpers_agents/privacy/configs/aider/.aider.conf.yml +2 -0
  87. machineconfig/scripts/python/helpers_agents/privacy/configs/copilot/config.yml +1 -0
  88. machineconfig/scripts/python/helpers_agents/privacy/configs/crush/crush.json +10 -0
  89. machineconfig/scripts/python/helpers_agents/privacy/configs/gemini/settings.json +12 -0
  90. machineconfig/scripts/python/helpers_agents/privacy/privacy.py +109 -0
  91. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +10 -0
  92. machineconfig/scripts/python/helpers_agents/templates/template.sh +34 -0
  93. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/cloud_copy.py +28 -21
  94. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/cloud_mount.py +19 -17
  95. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/cloud_sync.py +12 -11
  96. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/helpers2.py +1 -1
  97. machineconfig/scripts/python/helpers_croshell/crosh.py +39 -0
  98. machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/start_slidev.py +6 -7
  99. machineconfig/scripts/python/helpers_devops/cli_config.py +105 -0
  100. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +89 -0
  101. machineconfig/scripts/python/helpers_devops/cli_data.py +25 -0
  102. machineconfig/scripts/python/helpers_devops/cli_nw.py +221 -0
  103. machineconfig/scripts/python/{devops_helpers → helpers_devops}/cli_repos.py +60 -36
  104. machineconfig/scripts/python/helpers_devops/cli_self.py +172 -0
  105. machineconfig/scripts/python/helpers_devops/cli_share_file.py +137 -0
  106. machineconfig/scripts/python/helpers_devops/cli_share_server.py +142 -0
  107. machineconfig/scripts/python/{devops_helpers/cli_terminal.py → helpers_devops/cli_share_terminal.py} +15 -17
  108. machineconfig/scripts/python/{devops_helpers → helpers_devops}/devops_backup_retrieve.py +7 -10
  109. machineconfig/scripts/python/{devops_helpers → helpers_devops}/devops_status.py +7 -19
  110. machineconfig/scripts/python/{devops_helpers → helpers_devops}/devops_update_repos.py +1 -1
  111. machineconfig/scripts/python/helpers_devops/run_script.py +168 -0
  112. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +3 -0
  113. machineconfig/scripts/python/{devops_helpers → helpers_devops}/themes/choose_wezterm_theme.py +1 -1
  114. machineconfig/scripts/python/{helpers_fire/helpers4.py → helpers_fire_command/file_wrangler.py} +57 -20
  115. machineconfig/scripts/python/helpers_fire_command/fire_jobs_args_helper.py +2 -0
  116. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +26 -16
  117. machineconfig/scripts/python/helpers_msearch/__init__.py +5 -0
  118. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfg +3 -3
  119. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +59 -0
  120. machineconfig/scripts/python/helpers_navigator/__init__.py +20 -0
  121. machineconfig/scripts/python/{helper_navigator → helpers_navigator}/command_builder.py +1 -1
  122. machineconfig/scripts/python/{helper_navigator → helpers_navigator}/command_detail.py +1 -1
  123. machineconfig/scripts/python/{helper_navigator → helpers_navigator}/command_tree.py +160 -23
  124. machineconfig/scripts/python/{helper_navigator → helpers_navigator}/main_app.py +5 -5
  125. machineconfig/scripts/python/helpers_network/address.py +176 -0
  126. machineconfig/scripts/python/helpers_network/address_switch.py +78 -0
  127. machineconfig/scripts/python/{nw → helpers_network}/mount_nfs.py +2 -2
  128. machineconfig/scripts/python/{nw → helpers_network}/mount_ssh.py +1 -1
  129. machineconfig/scripts/python/{nw/devops_add_identity.py → helpers_network/ssh_add_identity.py} +35 -1
  130. machineconfig/scripts/python/{nw/devops_add_ssh_key.py → helpers_network/ssh_add_ssh_key.py} +26 -7
  131. machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_linux.py +7 -7
  132. machineconfig/scripts/python/{nw → helpers_network}/ssh_debug_windows.py +4 -4
  133. machineconfig/scripts/python/{nw → helpers_network}/wifi_conn.py +1 -53
  134. machineconfig/scripts/python/helpers_repos/action.py +209 -0
  135. machineconfig/scripts/python/helpers_repos/action_helper.py +150 -0
  136. machineconfig/scripts/python/{repos_helpers → helpers_repos}/clone.py +0 -1
  137. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +80 -37
  138. machineconfig/scripts/python/{repos_helpers → helpers_repos}/entrypoint.py +5 -5
  139. machineconfig/scripts/python/helpers_repos/grource.py +2 -2
  140. machineconfig/scripts/python/{repos_helpers → helpers_repos}/record.py +3 -2
  141. machineconfig/scripts/python/helpers_repos/repo_analyzer_1.py +160 -0
  142. machineconfig/scripts/python/{repos_helpers/count_lines.py → helpers_repos/repo_analyzer_2.py} +113 -192
  143. machineconfig/scripts/python/{repos_helpers → helpers_repos}/sync.py +5 -5
  144. machineconfig/scripts/python/{sessions_helpers → helpers_sessions}/sessions_multiprocess.py +19 -13
  145. machineconfig/scripts/python/helpers_utils/download.py +150 -0
  146. machineconfig/scripts/python/helpers_utils/pdf.py +96 -0
  147. machineconfig/scripts/python/helpers_utils/python.py +187 -0
  148. machineconfig/scripts/python/interactive.py +26 -35
  149. machineconfig/scripts/python/{entry.py → mcfg_entry.py} +24 -10
  150. machineconfig/scripts/python/msearch.py +72 -0
  151. machineconfig/scripts/python/sessions.py +101 -38
  152. machineconfig/scripts/python/terminal.py +136 -0
  153. machineconfig/scripts/python/utils.py +62 -0
  154. machineconfig/scripts/windows/wrap_mcfg.ps1 +63 -0
  155. machineconfig/settings/broot/conf.toml +1 -1
  156. machineconfig/settings/helix/config.toml +16 -0
  157. machineconfig/settings/helix/languages.toml +13 -4
  158. machineconfig/settings/helix/yazi-picker.sh +12 -0
  159. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  160. machineconfig/settings/lf/linux/exe/previewer.sh +3 -2
  161. machineconfig/settings/lf/linux/lfrc +10 -11
  162. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  163. machineconfig/settings/lf/windows/lfrc +15 -17
  164. machineconfig/settings/lf/windows/mkfile.ps1 +1 -1
  165. machineconfig/settings/linters/.ruff.toml +1 -1
  166. machineconfig/settings/marimo/marimo.toml +80 -0
  167. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  168. machineconfig/settings/shells/bash/init.sh +57 -10
  169. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
  170. machineconfig/settings/shells/nushell/config.nu +2 -35
  171. machineconfig/settings/shells/nushell/env.nu +45 -6
  172. machineconfig/settings/shells/nushell/init.nu +314 -0
  173. machineconfig/settings/shells/pwsh/init.ps1 +59 -23
  174. machineconfig/settings/shells/starship/starship.toml +16 -0
  175. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  176. machineconfig/settings/shells/wt/settings.json +32 -17
  177. machineconfig/settings/shells/zsh/init.sh +89 -0
  178. machineconfig/settings/television/cable_unix/alias.toml +8 -0
  179. machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
  180. machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
  181. machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
  182. machineconfig/settings/television/cable_unix/channels.toml +19 -0
  183. machineconfig/settings/television/cable_unix/dirs.toml +13 -0
  184. machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
  185. machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
  186. machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
  187. machineconfig/settings/television/cable_unix/env.toml +17 -0
  188. machineconfig/settings/television/cable_unix/files.toml +11 -0
  189. machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
  190. machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
  191. machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
  192. machineconfig/settings/television/cable_unix/git-log.toml +12 -0
  193. machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
  194. machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
  195. machineconfig/settings/television/cable_unix/guix.toml +20 -0
  196. machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
  197. machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
  198. machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
  199. machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
  200. machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
  201. machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
  202. machineconfig/settings/television/cable_unix/procs.toml +20 -0
  203. machineconfig/settings/television/cable_unix/text.toml +17 -0
  204. machineconfig/settings/television/cable_unix/tldr.toml +18 -0
  205. machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
  206. machineconfig/settings/television/cable_windows/alias.toml +7 -0
  207. machineconfig/settings/television/cable_windows/dirs.toml +13 -0
  208. machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
  209. machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
  210. machineconfig/settings/television/cable_windows/env.toml +17 -0
  211. machineconfig/settings/television/cable_windows/files.toml +14 -0
  212. machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
  213. machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
  214. machineconfig/settings/television/cable_windows/git-log.toml +11 -0
  215. machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
  216. machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
  217. machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
  218. machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
  219. machineconfig/settings/television/cable_windows/text.toml +17 -0
  220. machineconfig/settings/yazi/init.lua +61 -0
  221. machineconfig/settings/yazi/keymap_linux.toml +94 -0
  222. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  223. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  224. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  225. machineconfig/settings/yazi/theme.toml +4 -0
  226. machineconfig/settings/yazi/yazi_linux.toml +84 -0
  227. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  228. machineconfig/settings/zellij/layouts/st.kdl +39 -8
  229. machineconfig/setup_linux/__init__.py +2 -2
  230. machineconfig/setup_linux/apps_desktop.sh +8 -27
  231. machineconfig/setup_linux/web_shortcuts/interactive.sh +27 -11
  232. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +31 -0
  233. machineconfig/setup_mac/__init__.py +16 -0
  234. machineconfig/setup_mac/apps_gui.sh +248 -0
  235. machineconfig/setup_mac/ssh/openssh_setup.sh +114 -0
  236. machineconfig/setup_mac/uv.sh +36 -0
  237. machineconfig/setup_windows/__init__.py +3 -5
  238. machineconfig/setup_windows/ssh/openssh-server.ps1 +1 -1
  239. machineconfig/setup_windows/uv.ps1 +8 -1
  240. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +26 -10
  241. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +30 -0
  242. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  243. machineconfig/utils/accessories.py +7 -5
  244. machineconfig/utils/code.py +143 -167
  245. machineconfig/utils/files/art/fat_croco.txt +10 -0
  246. machineconfig/utils/files/art/halfwit_croco.txt +9 -0
  247. machineconfig/utils/files/art/happy_croco.txt +22 -0
  248. machineconfig/utils/files/art/water_croco.txt +11 -0
  249. machineconfig/utils/files/ascii_art.py +1 -1
  250. machineconfig/utils/files/headers.py +6 -11
  251. machineconfig/utils/files/read.py +3 -9
  252. machineconfig/utils/installer_utils/github_release_bulk.py +156 -119
  253. machineconfig/utils/installer_utils/install_from_url.py +183 -0
  254. machineconfig/utils/installer_utils/installer_class.py +44 -101
  255. machineconfig/utils/installer_utils/installer_cli.py +175 -0
  256. machineconfig/utils/installer_utils/installer_helper.py +129 -0
  257. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +39 -87
  258. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +17 -63
  259. machineconfig/utils/io.py +77 -4
  260. machineconfig/utils/links.py +56 -38
  261. machineconfig/utils/meta.py +235 -145
  262. machineconfig/utils/options.py +46 -18
  263. machineconfig/utils/options_tv.py +119 -0
  264. machineconfig/utils/path_extended.py +46 -97
  265. machineconfig/utils/path_helper.py +76 -23
  266. machineconfig/utils/procs.py +10 -23
  267. machineconfig/utils/scheduler.py +84 -115
  268. machineconfig/utils/scheduling.py +0 -3
  269. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  270. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  271. machineconfig/utils/ssh.py +214 -476
  272. machineconfig/utils/ssh_utils/abc.py +5 -0
  273. machineconfig/utils/ssh_utils/copy_from_here.py +111 -0
  274. machineconfig/utils/ssh_utils/copy_to_here.py +303 -0
  275. machineconfig/utils/ssh_utils/utils.py +142 -0
  276. machineconfig/utils/ssh_utils/wsl.py +210 -0
  277. machineconfig/utils/terminal.py +3 -113
  278. machineconfig/utils/upgrade_packages.py +114 -28
  279. machineconfig/utils/ve.py +12 -4
  280. machineconfig-8.12.dist-info/METADATA +132 -0
  281. machineconfig-8.12.dist-info/RECORD +504 -0
  282. {machineconfig-6.23.dist-info → machineconfig-8.12.dist-info}/entry_points.txt +5 -1
  283. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -41
  284. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -71
  285. machineconfig/jobs/linux/msc/cli_agents.sh +0 -16
  286. machineconfig/jobs/python/python_ve_symlink.py +0 -37
  287. machineconfig/jobs/python/vscode/api.py +0 -57
  288. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +0 -12
  289. machineconfig/jobs/windows/archive/openssh-server_add_key.ps1 +0 -7
  290. machineconfig/jobs/windows/archive/openssh-server_copy-ssh-id.ps1 +0 -14
  291. machineconfig/scripts/linux/fzf2g +0 -21
  292. machineconfig/scripts/linux/fzfag +0 -17
  293. machineconfig/scripts/linux/fzffg +0 -25
  294. machineconfig/scripts/linux/fzfrga +0 -21
  295. machineconfig/scripts/linux/other/share_smb +0 -1
  296. machineconfig/scripts/linux/other/switch_ip +0 -20
  297. machineconfig/scripts/linux/skrg +0 -4
  298. machineconfig/scripts/linux/warp-cli.sh +0 -122
  299. machineconfig/scripts/linux/z_ls +0 -104
  300. machineconfig/scripts/python/ai/command_runner/prompt.txt +0 -9
  301. machineconfig/scripts/python/devops_helpers/cli_config.py +0 -81
  302. machineconfig/scripts/python/devops_helpers/cli_config_dotfile.py +0 -84
  303. machineconfig/scripts/python/devops_helpers/cli_data.py +0 -18
  304. machineconfig/scripts/python/devops_helpers/cli_nw.py +0 -73
  305. machineconfig/scripts/python/devops_helpers/cli_self.py +0 -117
  306. machineconfig/scripts/python/devops_helpers/cli_share_server.py +0 -104
  307. machineconfig/scripts/python/helper_navigator/__init__.py +0 -20
  308. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_crush.py +0 -37
  309. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_gemini.py +0 -44
  310. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_qwen.py +0 -43
  311. machineconfig/scripts/python/helpers_fire/fire_agents_helper_types.py +0 -30
  312. machineconfig/scripts/python/helpers_fire/prompt.txt +0 -2
  313. machineconfig/scripts/python/helpers_fire/template.sh +0 -15
  314. machineconfig/scripts/python/helpers_repos/secure_repo.py +0 -15
  315. machineconfig/scripts/python/nw/add_ssh_key.py +0 -148
  316. machineconfig/scripts/python/nw/wsl_windows_transfer.py +0 -66
  317. machineconfig/scripts/python/repos_helpers/action.py +0 -378
  318. machineconfig/scripts/python/repos_helpers/count_lines_frontend.py +0 -17
  319. machineconfig/scripts/windows/fzfb.ps1 +0 -3
  320. machineconfig/scripts/windows/fzfg.ps1 +0 -2
  321. machineconfig/scripts/windows/fzfrga.bat +0 -20
  322. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +0 -13
  323. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  324. machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
  325. machineconfig/settings/lf/windows/tst.ps1 +0 -1
  326. machineconfig/settings/shells/pwsh/profile.ps1 +0 -0
  327. machineconfig/settings/yazi/keymap.toml +0 -0
  328. machineconfig/settings/yazi/yazi.toml +0 -4
  329. machineconfig/setup_linux/apps.sh +0 -66
  330. machineconfig/setup_linux/nix/cli_installation.sh +0 -137
  331. machineconfig/setup_linux/ssh/openssh_all.sh +0 -25
  332. machineconfig/setup_linux/ssh/openssh_wsl.sh +0 -38
  333. machineconfig/setup_windows/apps.ps1 +0 -62
  334. machineconfig/setup_windows/others/obs.ps1 +0 -4
  335. machineconfig/setup_windows/ssh/add_identity.ps1 +0 -11
  336. machineconfig/setup_windows/wt_and_pwsh/__init__.py +0 -0
  337. machineconfig/utils/installer_utils/installer.py +0 -225
  338. machineconfig-6.23.dist-info/METADATA +0 -84
  339. machineconfig-6.23.dist-info/RECORD +0 -428
  340. machineconfig/cluster/sessions_managers/{utils → helpers}/load_balancer_helper.py +0 -0
  341. machineconfig/cluster/sessions_managers/{helpers → zellij_utils}/zellij_local_helper.py +0 -0
  342. machineconfig/cluster/sessions_managers/{helpers → zellij_utils}/zellij_local_helper_restart.py +0 -0
  343. machineconfig/cluster/sessions_managers/{helpers → zellij_utils}/zellij_local_manager_helper.py +0 -0
  344. machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +0 -0
  345. machineconfig/jobs/{linux/msc → installer/linux_scripts}/network.sh +0 -0
  346. machineconfig/jobs/installer/{custom_dev → python_scripts}/__init__.py +0 -0
  347. machineconfig/jobs/installer/{custom_dev → python_scripts}/alacritty.py +0 -0
  348. machineconfig/jobs/installer/{custom_dev → python_scripts}/bypass_paywall.py +0 -0
  349. machineconfig/jobs/installer/{custom_dev → python_scripts}/cursor.py +0 -0
  350. machineconfig/jobs/installer/{custom_dev → python_scripts}/espanso.py +0 -0
  351. machineconfig/jobs/installer/{custom → python_scripts}/gh.py +0 -0
  352. machineconfig/jobs/installer/{custom_dev → python_scripts}/goes.py +0 -0
  353. machineconfig/jobs/installer/{custom_dev → python_scripts}/lvim.py +0 -0
  354. machineconfig/jobs/installer/{custom_dev → python_scripts}/redis.py +0 -0
  355. machineconfig/{setup_linux/web_shortcuts → jobs/scripts/bash_scripts}/android.sh +0 -0
  356. machineconfig/jobs/{linux/msc → scripts/bash_scripts}/lid.sh +0 -0
  357. machineconfig/{setup_linux/others → jobs/scripts/bash_scripts}/mint_keyboard_shortcuts.sh +0 -0
  358. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_drive +0 -0
  359. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_nw_drive +0 -0
  360. machineconfig/{scripts/python/nw → jobs/scripts/bash_scripts}/mount_smb +0 -0
  361. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_cloud.sh +0 -0
  362. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/share_nfs +0 -0
  363. machineconfig/{scripts/linux/other → jobs/scripts/bash_scripts}/start_docker +0 -0
  364. machineconfig/{scripts → jobs/scripts/powershell_scripts}/Restore-ThunderbirdProfile.ps1 +0 -0
  365. machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/docker.ps1 +0 -0
  366. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nfs.ps1 +0 -0
  367. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_nw.ps1 +0 -0
  368. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/mount_smb.ps1 +0 -0
  369. machineconfig/{setup_windows/others → jobs/scripts/powershell_scripts}/power_options.ps1 +0 -0
  370. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_cloud.cmd +0 -0
  371. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/share_smb.ps1 +0 -0
  372. machineconfig/{scripts/windows/mounts → jobs/scripts/powershell_scripts}/unlock_bitlocker.ps1 +0 -0
  373. machineconfig/{jobs/python → scripts/python/ai/utils}/__init__.py +0 -0
  374. machineconfig/scripts/python/{cloud_helpers → helpers_agents}/__init__.py +0 -0
  375. machineconfig/scripts/python/{croshell_helpers → helpers_agents/agentic_frameworks}/__init__.py +0 -0
  376. machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_help_search.py +0 -0
  377. machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_load_balancer.py +0 -0
  378. machineconfig/scripts/python/{helpers_fire → helpers_agents/templates}/template.ps1 +0 -0
  379. machineconfig/scripts/python/{devops_helpers → helpers_cloud}/__init__.py +0 -0
  380. machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/cloud_helpers.py +1 -1
  381. /machineconfig/scripts/python/{cloud_helpers → helpers_cloud}/helpers5.py +0 -0
  382. /machineconfig/scripts/python/{devops_helpers/themes → helpers_croshell}/__init__.py +0 -0
  383. /machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/pomodoro.py +0 -0
  384. /machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/scheduler.py +0 -0
  385. /machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/viewer.py +0 -0
  386. /machineconfig/scripts/python/{croshell_helpers → helpers_croshell}/viewer_template.py +0 -0
  387. /machineconfig/scripts/python/{helpers_fire → helpers_devops}/__init__.py +0 -0
  388. /machineconfig/scripts/python/{helpers_fire/agentic_frameworks → helpers_devops/themes}/__init__.py +0 -0
  389. /machineconfig/scripts/python/{devops_helpers → helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  390. /machineconfig/{jobs/windows/msc/cli_agents.bat → scripts/python/helpers_devops/themes/choose_starship_theme.ps1} +0 -0
  391. /machineconfig/{jobs/windows/msc/cli_agents.ps1 → scripts/python/helpers_fire_command/f.py} +0 -0
  392. /machineconfig/scripts/python/{helper_navigator → helpers_navigator}/data_models.py +0 -0
  393. /machineconfig/scripts/python/{helper_navigator → helpers_navigator}/search_bar.py +0 -0
  394. /machineconfig/scripts/python/{helpers_repos → helpers_network}/__init__.py +0 -0
  395. /machineconfig/scripts/python/{nw → helpers_network}/mount_nw_drive.py +0 -0
  396. /machineconfig/scripts/python/{nw → helpers_network}/onetimeshare.py +0 -0
  397. /machineconfig/scripts/python/{repos_helpers → helpers_repos}/update.py +0 -0
  398. /machineconfig/scripts/python/{nw → helpers_sessions}/__init__.py +0 -0
  399. /machineconfig/{scripts/python/sessions_helpers → settings/wt}/__init__.py +0 -0
  400. /machineconfig/{setup_windows/wt_and_pwsh → settings/wt}/set_wt_settings.py +0 -0
  401. {machineconfig-6.23.dist-info → machineconfig-8.12.dist-info}/WHEEL +0 -0
  402. {machineconfig-6.23.dist-info → machineconfig-8.12.dist-info}/top_level.txt +0 -0
@@ -1,166 +1,256 @@
1
1
  """Metaprogramming utilities for analyzing and serializing Python functions."""
2
2
 
3
- import ast
4
- import inspect
5
- import textwrap
6
- from types import FunctionType, ModuleType
3
+ from collections.abc import Callable
7
4
  from typing import Any
8
5
 
9
6
 
10
- def function_to_script(func: FunctionType, call_with_args: tuple[Any, ...] | None = None, call_with_kwargs: dict[str, Any] | None = None) -> str:
11
- """Convert a function to a standalone executable Python script.
12
-
13
- This function analyzes a given function and generates a complete Python script
14
- that includes all necessary imports, global variables, the function definition,
15
- and optionally a function call.
7
+ def get_import_module_string(py_file: str) -> str:
8
+ from machineconfig.scripts.python.helpers_fire_command.file_wrangler import get_import_module_code
9
+ from machineconfig.utils.accessories import get_repo_root
10
+ from pathlib import Path
11
+ repo_root = get_repo_root(Path(py_file))
12
+ import_line = get_import_module_code(py_file)
13
+ if repo_root is not None:
14
+ repo_root_add = f"""sys.path.append(r'{repo_root}')"""
15
+ else:
16
+ repo_root_add = ""
17
+ txt: str = f"""
18
+ try:
19
+ {import_line}
20
+ except (ImportError, ModuleNotFoundError) as ex:
21
+ print(fr"❌ Failed to import `{py_file}` as a module: {{ex}} ")
22
+ print(fr"⚠️ Attempting import with ad-hoc `$PATH` manipulation. DO NOT pickle any objects in this session as correct deserialization cannot be guaranteed.")
23
+ import sys
24
+ sys.path.append(r'{Path(py_file).parent}')
25
+ {repo_root_add}
26
+ from {Path(py_file).stem} import *
27
+ print(fr"✅ Successfully imported `{py_file}`")
28
+ """
29
+ return txt
30
+
31
+
32
+ def lambda_to_python_script(lmb: Callable[[], Any],
33
+ in_global: bool, import_module: bool) -> str:
34
+ """
35
+ caveats: always use keyword arguments in the lambda call for best results.
36
+ return statement not allowed in the wrapped function (otherwise it can be put in the global space)
37
+ type hint in kwargs has nothing that is not built in, e.g. Optional will not work as it requires an import.
38
+
39
+ Given a no-arg lambda like `lambda: func(a=var1, b=var2)`,
40
+ return a string containing the full function definition of `func`
41
+ but with the defaults for the parameters provided in the call replaced
42
+ by the *actual* values (repr) taken from the lambda's globals.
43
+
44
+ All imports are local to this function.
16
45
 
17
46
  Args:
18
- func: The function to convert to a script
19
- call_with_args: Optional tuple of positional arguments to call the function with
20
- call_with_kwargs: Optional dict of keyword arguments to call the function with
21
-
22
- Returns:
23
- A complete Python script as a string that can be executed independently
24
-
25
- Raises:
26
- ValueError: If the function cannot be inspected or analyzed
47
+ lmb: A lambda function with no arguments
48
+ in_global: If True, return kwargs as global variable assignments followed by dedented body.
49
+ If False, return the full function definition with updated defaults.
50
+ import_module: When True, prepend module import bootstrap code for the function's source file.
27
51
  """
28
- if not callable(func) or not hasattr(func, '__code__'):
29
- raise ValueError(f"Expected a function, got {type(func)}")
30
-
31
- call_with_args = call_with_args or ()
32
- call_with_kwargs = call_with_kwargs or {}
33
-
34
- imports = _extract_imports(func)
35
- globals_needed = _extract_globals(func)
36
- source_code = _get_function_source(func)
37
- call_statement = _generate_call_statement(func, call_with_args, call_with_kwargs)
38
-
39
- script_parts: list[str] = []
40
-
41
- if imports:
42
- script_parts.append(imports)
43
- script_parts.append("")
44
-
45
- if globals_needed:
46
- script_parts.append(globals_needed)
47
- script_parts.append("")
48
-
49
- script_parts.append(source_code)
50
- script_parts.append("")
51
-
52
- if call_statement:
53
- script_parts.append("")
54
- script_parts.append("if __name__ == '__main__':")
55
- script_parts.append(f" {call_statement}")
56
-
57
- return "\n".join(script_parts)
52
+ # local imports
53
+ import inspect as _inspect
54
+ import ast as _ast
55
+ import textwrap as _textwrap
56
+ import types as _types
57
+ from pathlib import Path as _Path
58
58
 
59
+ def _stringify_annotation(annotation: Any) -> Any:
60
+ if annotation is _inspect.Signature.empty or annotation is _inspect.Parameter.empty:
61
+ return annotation
62
+ if isinstance(annotation, str):
63
+ return annotation
64
+ try:
65
+ return _inspect.formatannotation(annotation)
66
+ except Exception:
67
+ return str(annotation)
59
68
 
60
- def _get_function_source(func: FunctionType) -> str:
61
- """Extract the source code of a function."""
62
- try:
63
- source = inspect.getsource(func)
64
- return textwrap.dedent(source)
65
- except (OSError, TypeError) as e:
66
- raise ValueError(f"Cannot get source code for function {func.__name__}: {e}") from e
69
+ # sanity checks
70
+ if not (callable(lmb) and isinstance(lmb, _types.LambdaType)):
71
+ raise TypeError("Expected a lambda function object")
72
+
73
+ src = _inspect.getsource(lmb)
74
+ src = _textwrap.dedent(src)
75
+ tree = _ast.parse(src)
67
76
 
77
+ # find first Lambda node
78
+ lambda_node = None
79
+ for n in _ast.walk(tree):
80
+ if isinstance(n, _ast.Lambda):
81
+ lambda_node = n
82
+ break
83
+ if lambda_node is None:
84
+ raise ValueError("Could not find a lambda expression in source")
68
85
 
69
- def _extract_imports(func: FunctionType) -> str:
70
- """Extract all import statements needed by the function."""
71
- import_statements: set[str] = set()
86
+ body = lambda_node.body
87
+ if not isinstance(body, _ast.Call):
88
+ raise ValueError("Lambda body is not a call expression")
89
+
90
+ globals_dict = getattr(lmb, "__globals__", {})
72
91
 
73
- source = _get_function_source(func)
74
- func_globals = func.__globals__
92
+ # Also capture closure variables from the lambda
93
+ closure_dict: dict[str, Any] = {}
94
+ if lmb.__closure__:
95
+ code_obj = lmb.__code__
96
+ freevars = code_obj.co_freevars
97
+ for i, var_name in enumerate(freevars):
98
+ closure_dict[var_name] = lmb.__closure__[i].cell_contents
75
99
 
100
+ # Merge globals and closures (closures take precedence for shadowing)
101
+ eval_namespace = {**globals_dict, **closure_dict}
102
+
103
+ # resolve the function object being called
76
104
  try:
77
- tree = ast.parse(source)
78
- except SyntaxError as e:
79
- raise ValueError(f"Failed to parse function source: {e}") from e
80
-
81
- used_names: set[str] = set()
82
- for node in ast.walk(tree):
83
- if isinstance(node, ast.Name):
84
- used_names.add(node.id)
85
- elif isinstance(node, ast.Attribute):
86
- if isinstance(node.value, ast.Name):
87
- used_names.add(node.value.id)
88
-
89
- for name in used_names:
90
- if name in func_globals:
91
- obj = func_globals[name]
92
-
93
- if isinstance(obj, ModuleType):
94
- module_name = obj.__name__
95
- if name == module_name.split('.')[-1]:
96
- import_statements.add(f"import {module_name}")
97
- else:
98
- import_statements.add(f"import {module_name} as {name}")
99
-
100
- elif hasattr(obj, '__module__') and obj.__module__ != '__main__':
101
- try:
102
- module_name = obj.__module__
103
- obj_name = obj.__name__ if hasattr(obj, '__name__') else name
104
-
105
- if module_name and module_name != 'builtins':
106
- if obj_name == name:
107
- import_statements.add(f"from {module_name} import {obj_name}")
108
- else:
109
- import_statements.add(f"from {module_name} import {obj_name} as {name}")
110
- except AttributeError:
111
- pass
112
-
113
- return "\n".join(sorted(import_statements))
105
+ func_ref_src = _ast.unparse(body.func)
106
+ except AttributeError:
107
+ func_ref_src = _ast.get_source_segment(src, body.func) or ""
108
+ try:
109
+ func_obj = eval(func_ref_src, eval_namespace)
110
+ except Exception as e:
111
+ raise RuntimeError(f"Could not resolve function reference '{func_ref_src}': {e}")
114
112
 
113
+ if not callable(func_obj):
114
+ raise TypeError("Resolved object is not callable")
115
115
 
116
- def _extract_globals(func: FunctionType) -> str:
117
- """Extract global variables needed by the function."""
118
- global_assignments: list[str] = []
119
-
120
- source = _get_function_source(func)
121
- func_globals = func.__globals__
122
-
116
+ func_name = getattr(func_obj, "__name__", "<unknown>")
117
+
118
+ import_prefix: str = ""
119
+ if import_module:
120
+ module_file = _inspect.getsourcefile(func_obj)
121
+ module_path_candidate: str = module_file if module_file is not None else _inspect.getfile(func_obj)
122
+ import_prefix = get_import_module_string(str(_Path(module_path_candidate)))
123
+
124
+ # Evaluate each keyword argument value in the lambda's globals to get real Python objects
125
+ call_kwargs: dict[str, Any] = {}
126
+ for kw in body.keywords:
127
+ if kw.arg is None:
128
+ # **kwargs in call — evaluate to dict and merge
129
+ try:
130
+ val = eval(compile(_ast.Expression(kw.value), "<lambda_eval>", "eval"), eval_namespace)
131
+ if isinstance(val, dict):
132
+ call_kwargs.update(val)
133
+ else:
134
+ raise ValueError("Keyword expansion did not evaluate to a dict")
135
+ except Exception as e:
136
+ raise RuntimeError(f"Failed to evaluate **kwargs expression: {e}")
137
+ else:
138
+ try:
139
+ val = eval(compile(_ast.Expression(kw.value), "<lambda_eval>", "eval"), eval_namespace)
140
+ call_kwargs[kw.arg] = val
141
+ except Exception as e:
142
+ raise RuntimeError(f"Failed to evaluate value for kw '{kw.arg}': {e}")
143
+
144
+ # Try to get original source and dedent it for body extraction
123
145
  try:
124
- tree = ast.parse(source)
125
- except SyntaxError as e:
126
- raise ValueError(f"Failed to parse function source: {e}") from e
127
-
128
- used_names: set[str] = set()
129
- for node in ast.walk(tree):
130
- if isinstance(node, ast.Name):
131
- used_names.add(node.id)
132
- elif isinstance(node, ast.Attribute):
133
- if isinstance(node.value, ast.Name):
134
- used_names.add(node.value.id)
135
-
136
- for name in used_names:
137
- if name in func_globals:
138
- obj = func_globals[name]
146
+ orig_src = _inspect.getsource(func_obj)
147
+ ded = _textwrap.dedent(orig_src)
148
+ lines = ded.splitlines()
149
+ def_index = None
150
+ for i, ln in enumerate(lines):
151
+ if ln.lstrip().startswith(f"def {func_name}("):
152
+ def_index = i
153
+ break
154
+ if def_index is None:
155
+ body_lines = ded.splitlines()
156
+ else:
157
+ signature_end_index = None
158
+ for i in range(def_index, len(lines)):
159
+ line_no_comment = lines[i].split("#", 1)[0].rstrip()
160
+ if line_no_comment.endswith(":"):
161
+ signature_end_index = i
162
+ break
163
+ if signature_end_index is None:
164
+ body_lines = lines[def_index + 1 :]
165
+ else:
166
+ body_lines = lines[signature_end_index + 1 :]
167
+ # ensure we have a body, otherwise use pass
168
+ if not any(line.strip() for line in body_lines):
169
+ body_text = " pass\n"
170
+ else:
171
+ joined_body = "\n".join(body_lines)
172
+ if not joined_body.endswith("\n"):
173
+ joined_body = f"{joined_body}\n"
174
+ body_text = joined_body
175
+ except (OSError, IOError, TypeError):
176
+ body_text = " pass\n"
177
+
178
+ # Build a replaced signature using inspect.signature
179
+ sig = _inspect.signature(func_obj)
180
+ new_params: list[_inspect.Parameter] = []
181
+ for name, param in sig.parameters.items():
182
+ # If the call provided a value for this parameter, replace default
183
+ if name in call_kwargs:
184
+ new_default = call_kwargs[name]
185
+ else:
186
+ new_default = param.default
187
+
188
+ normalized_annotation = _stringify_annotation(param.annotation)
189
+
190
+ if new_default is _inspect.Parameter.empty:
191
+ new_param = _inspect.Parameter(name, param.kind, annotation=normalized_annotation)
192
+ else:
193
+ new_param = _inspect.Parameter(
194
+ name, param.kind, default=new_default, annotation=normalized_annotation
195
+ )
196
+ new_params.append(new_param)
197
+
198
+ return_annotation = _stringify_annotation(sig.return_annotation)
199
+ new_sig = _inspect.Signature(parameters=new_params, return_annotation=return_annotation)
200
+
201
+ # If in_global mode, return kwargs as global assignments + dedented body
202
+ if in_global:
203
+ global_assignments: list[str] = []
204
+ for name, param in sig.parameters.items():
205
+ # Get the value from call_kwargs if provided, else use original default
206
+ if name in call_kwargs:
207
+ value = call_kwargs[name]
208
+ elif param.default is not _inspect.Parameter.empty:
209
+ value = param.default
210
+ else:
211
+ # No value provided and no default - skip this parameter
212
+ continue
139
213
 
140
- if not isinstance(obj, (ModuleType, FunctionType, type)):
141
- if not (hasattr(obj, '__module__') and hasattr(obj, '__name__')):
142
- try:
143
- repr_str = repr(obj)
144
- if len(repr_str) < 1000 and '\n' not in repr_str:
145
- global_assignments.append(f"{name} = {repr_str}")
146
- except Exception:
147
- global_assignments.append(f"# Warning: Could not serialize global variable '{name}'")
148
-
149
- return "\n".join(global_assignments)
214
+ # Build type annotation string if available
215
+ if param.annotation is not _inspect.Parameter.empty:
216
+ annotation_literal = _stringify_annotation(param.annotation)
217
+ if isinstance(annotation_literal, str):
218
+ global_assignments.append(f"{name}: {repr(annotation_literal)} = {repr(value)}")
219
+ else:
220
+ global_assignments.append(f"{name} = {repr(value)}")
221
+ else:
222
+ global_assignments.append(f"{name} = {repr(value)}")
223
+
224
+ # Dedent the body text to remove function indentation
225
+ dedented_body = _textwrap.dedent(body_text).rstrip()
226
+
227
+ # Combine global assignments and body
228
+ if global_assignments:
229
+ result_parts: list[str] = ["\n".join(global_assignments), "", dedented_body]
230
+ result_text = "\n".join(result_parts)
231
+ else:
232
+ result_text = dedented_body
233
+ else:
234
+ header = f"def {func_name}{new_sig}:\n"
235
+ result_text = header + body_text
150
236
 
237
+ if in_global:
238
+ lines = result_text.splitlines()
239
+ if lines[-1].startswith("return "):
240
+ lines[-1] = lines[-1].replace("return ", "# return ", 1)
241
+ result_text = "\n".join(lines)
151
242
 
152
- def _generate_call_statement(func: FunctionType, args: tuple[Any, ...], kwargs: dict[str, Any]) -> str:
153
- """Generate a function call statement with the given arguments."""
154
- if not args and not kwargs:
155
- return f"{func.__name__}()"
156
-
157
- arg_parts: list[str] = []
158
-
159
- for arg in args:
160
- arg_parts.append(repr(arg))
161
-
162
- for key, value in kwargs.items():
163
- arg_parts.append(f"{key}={repr(value)}")
164
-
165
- args_str = ", ".join(arg_parts)
166
- return f"{func.__name__}({args_str})"
243
+ if "Optional" in result_text or "Any" in result_text or "Union" in result_text or "Literal" in result_text:
244
+ result_text = "from typing import Optional, Any, Union, Literal\n\n" + result_text
245
+ if import_prefix:
246
+ result_text = f"{import_prefix}{result_text}"
247
+ return result_text
248
+
249
+ if __name__ == "__main__":
250
+ from machineconfig.utils.code import print_code
251
+ import_code_robust = "<import_code_robust>"
252
+ res = lambda_to_python_script(
253
+ lambda: print_code(code=import_code_robust, lexer="python", desc="import as module code"),
254
+ in_global=True, import_module=False
255
+ )
256
+ print(res)
@@ -1,38 +1,66 @@
1
+
1
2
  from pathlib import Path
2
- from machineconfig.utils.installer_utils.installer_abc import check_tool_exists
3
3
  from rich.text import Text
4
4
  from rich.panel import Panel
5
5
  from rich.console import Console
6
6
  import subprocess
7
- from typing import Optional, Union, Iterable, overload, Literal
7
+ from typing import Optional, Union, Iterable, overload, Literal, cast
8
8
 
9
9
  @overload
10
- def choose_from_options[T](msg: str, options: Iterable[T], multi: Literal[False], custom_input: bool = False, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, fzf: bool = False) -> T: ...
10
+ def choose_from_options[T](options: Iterable[T], msg: str, multi: Literal[False], custom_input: bool = False, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, tv: bool = False) -> T: ...
11
11
  @overload
12
- def choose_from_options[T](msg: str, options: Iterable[T], multi: Literal[True], custom_input: bool = True, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, fzf: bool = False, ) -> list[T]: ...
13
- def choose_from_options[T](msg: str, options: Iterable[T], multi: bool, custom_input: bool = True, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, fzf: bool = False, ) -> Union[T, list[T]]:
12
+ def choose_from_options[T](options: Iterable[T], msg: str, multi: Literal[True], custom_input: bool = True, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, tv: bool = False, ) -> list[T]: ...
13
+ def choose_from_options[T](options: Iterable[T], msg: str, multi: bool, custom_input: bool = True, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, tv: bool = False, ) -> Union[T, list[T]]:
14
14
  # TODO: replace with https://github.com/tmbo/questionary
15
15
  # # also see https://github.com/charmbracelet/gum
16
16
  options_strings: list[str] = [str(x) for x in options]
17
17
  default_string = str(default) if default is not None else None
18
18
  console = Console()
19
- fzf_exists = check_tool_exists("fzf")
20
- # print("\n" * 10, f"{fzf=}, {fzf_exists=}", "\n" * 10)
21
- if fzf and fzf_exists:
22
- from pyfzf.pyfzf import FzfPrompt
23
- fzf_prompt = FzfPrompt()
24
- nl = "\n"
25
- choice_string_multi: list[str] = fzf_prompt.prompt(choices=options_strings, fzf_options=("--multi" if multi else "") + f' --prompt "{prompt.replace(nl, " ")}" ') # --border-label={msg.replace(nl, ' ')}")
26
- # --border=rounded doens't work on older versions of fzf installed at Ubuntu 20.04
19
+ from machineconfig.utils.installer_utils.installer_locator_utils import check_tool_exists
20
+ # from machineconfig.utils.installer_utils.installer_cli import check_tool_exists
21
+ # print("ch1")
22
+ if tv and check_tool_exists("tv"):
23
+ # from pyfzf.pyfzf import FzfPrompt
24
+ # fzf_prompt = FzfPrompt()
25
+ # nl = "\n"
26
+ # choice_string_multi: list[str] = fzf_prompt.prompt(choices=options_strings, fzf_options=("--multi" if multi else "") + f' --prompt "{prompt.replace(nl, " ")}" --ansi') # --border-label={msg.replace(nl, ' ')}")
27
+ # print("ch2")
28
+ from machineconfig.utils.accessories import randstr
29
+ options_txt_path = Path.home().joinpath("tmp_results/tmp_files/choices_" + randstr(6) + ".txt")
30
+ options_txt_path.parent.mkdir(parents=True, exist_ok=True)
31
+ options_txt_path.write_text("\n".join(options_strings), encoding="utf-8")
32
+
33
+ # Run `tv` interactively so the user can make selections. We redirect tv's
34
+ # stdout to a temporary output file so we can read the chosen lines after
35
+ # the interactive session completes. Do not capture_output or redirect
36
+ # stdin/stderr here so `tv` stays attached to the terminal.
37
+ tv_out_path = options_txt_path.with_name(options_txt_path.stem + "_out.txt")
38
+ tv_cmd = f"""cat {options_txt_path} | tv --ansi true --source-output "{{strip_ansi}}" > {tv_out_path}"""
39
+ res = subprocess.run(tv_cmd, shell=True)
40
+
41
+ # If tv returned a non-zero code and there is no output file, treat it as an error.
42
+ if res.returncode != 0 and not tv_out_path.exists():
43
+ raise RuntimeError(f"Got error running tv command: {tv_cmd}\nreturncode: {res.returncode}")
44
+
45
+ # Read selections (if any) from the output file created by tv.
46
+ out_text = tv_out_path.read_text(encoding="utf-8") if tv_out_path.exists() else ""
47
+ choice_string_multi = [x for x in out_text.splitlines() if x.strip() != ""]
48
+
49
+ # Cleanup temporary files
50
+ options_txt_path.unlink(missing_ok=True)
51
+ tv_out_path.unlink(missing_ok=True)
27
52
  if not multi:
28
53
  try:
29
54
  choice_one_string = choice_string_multi[0]
55
+ if isinstance(list(options)[0], str): return cast(T, choice_one_string)
30
56
  choice_idx = options_strings.index(choice_one_string)
31
57
  return list(options)[choice_idx]
32
58
  except IndexError as ie:
33
59
  print(f"❌ Error: {options=}, {choice_string_multi=}")
34
60
  print(f"🔍 Available choices: {choice_string_multi}")
35
61
  raise ie
62
+ if isinstance(list(options)[0], str):
63
+ return cast(list[T], choice_string_multi)
36
64
  choice_idx_s = [options_strings.index(x) for x in choice_string_multi]
37
65
  return [list(options)[x] for x in choice_idx_s]
38
66
  else:
@@ -55,7 +83,7 @@ def choose_from_options[T](msg: str, options: Iterable[T], multi: bool, custom_i
55
83
  if choice_string == "":
56
84
  if default_string is None:
57
85
  console.print(Panel("🧨 Default option not available!", title="Error", expand=False))
58
- return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, fzf=fzf, multi=multi, custom_input=custom_input)
86
+ return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, tv=tv, multi=multi, custom_input=custom_input)
59
87
  choice_idx = options_strings.index(default_string)
60
88
  assert default is not None, "🧨 Default option not available!"
61
89
  choice_one: T = default
@@ -73,7 +101,7 @@ def choose_from_options[T](msg: str, options: Iterable[T], multi: bool, custom_i
73
101
  _ = ie
74
102
  # raise ValueError(f"Unknown choice. {choice_string}") from ie
75
103
  console.print(Panel(f"❓ Unknown choice: '{choice_string}'", title="Error", expand=False))
76
- return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, fzf=fzf, multi=multi, custom_input=custom_input)
104
+ return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, tv=tv, multi=multi, custom_input=custom_input)
77
105
  except (TypeError, ValueError) as te: # int(choice_string) failed due to # either the number is invalid, or the input is custom.
78
106
  if choice_string in options_strings: # string input
79
107
  choice_idx = options_strings.index(choice_one) # type: ignore
@@ -84,7 +112,7 @@ def choose_from_options[T](msg: str, options: Iterable[T], multi: bool, custom_i
84
112
  _ = te
85
113
  # raise ValueError(f"Unknown choice. {choice_string}") from te
86
114
  console.print(Panel(f"❓ Unknown choice: '{choice_string}'", title="Error", expand=False))
87
- return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, fzf=fzf, multi=multi, custom_input=custom_input)
115
+ return choose_from_options(msg=msg, options=options, header=header, tail=tail, prompt=prompt, default=default, tv=tv, multi=multi, custom_input=custom_input)
88
116
  console.print(Panel(f"✅ Selected option {choice_idx}: {choice_one}", title="Selected", expand=False))
89
117
  if multi:
90
118
  return [choice_one]
@@ -103,7 +131,7 @@ def choose_cloud_interactively() -> str:
103
131
  raise ValueError(f"Got {tmp} from rclone listremotes")
104
132
  if len(remotes) == 0:
105
133
  raise RuntimeError("You don't have remotes. Configure your rclone first to get cloud services access.")
106
- cloud: str = choose_from_options(msg="WHICH CLOUD?", multi=False, options=list(remotes), default=remotes[0], fzf=True)
134
+ cloud: str = choose_from_options(msg="WHICH CLOUD?", multi=False, options=list(remotes), default=remotes[0], tv=True)
107
135
  console.print(Panel(f"✅ SELECTED CLOUD | {cloud}", border_style="bold blue", expand=False))
108
136
  return cloud
109
137
 
@@ -121,4 +149,4 @@ def choose_ssh_host(multi: Literal[False]) -> str: ...
121
149
  @overload
122
150
  def choose_ssh_host(multi: Literal[True]) -> list[str]: ...
123
151
  def choose_ssh_host(multi: bool):
124
- return choose_from_options(msg="", options=get_ssh_hosts(), multi=multi, fzf=True)
152
+ return choose_from_options(msg="", options=get_ssh_hosts(), multi=multi, tv=True)
@@ -0,0 +1,119 @@
1
+
2
+
3
+ #!/usr/bin/env python3
4
+ import base64
5
+ import pathlib
6
+ import subprocess
7
+ import tempfile
8
+ import os
9
+
10
+
11
+ def main(options_to_preview_mapping: dict[str, str]) -> str | None:
12
+ keys = list(options_to_preview_mapping.keys())
13
+ if not keys:
14
+ return None
15
+ with tempfile.TemporaryDirectory(prefix="tv_channel_") as tmpdir:
16
+ tempdir = pathlib.Path(tmpdir)
17
+ entries: list[str] = []
18
+ index_map: dict[int, str] = {}
19
+ preview_map_path = tempdir / "previews.tsv"
20
+ preview_rows: list[str] = []
21
+ for idx, key in enumerate(keys):
22
+ display_key = key.replace("\t", " ").replace("\n", " ")
23
+ entries.append(f"{idx}\t{display_key}")
24
+ index_map[idx] = key
25
+ encoded_preview = base64.b64encode(options_to_preview_mapping[key].encode("utf-8")).decode("ascii")
26
+ preview_rows.append(f"{idx}\t{encoded_preview}")
27
+ preview_map_path.write_text("\n".join(preview_rows), encoding="utf-8")
28
+ entries_path = tempdir / "entries.tsv"
29
+ entries_path.write_text("\n".join(entries), encoding="utf-8")
30
+ preview_script = tempdir / "preview.sh"
31
+ preview_script.write_text(
32
+ """#!/usr/bin/env bash
33
+ set -euo pipefail
34
+
35
+ idx="$1"
36
+ script_dir="$(cd -- "$(dirname -- "$0")" && pwd)"
37
+ previews_file="${script_dir}/previews.tsv"
38
+
39
+ if [[ ! -f "${previews_file}" ]]; then
40
+ exit 0
41
+ fi
42
+
43
+ encoded_preview="$(awk -F '\t' -v idx="${idx}" '($1==idx){print $2; exit}' "${previews_file}" || true)"
44
+
45
+ if [[ -z "${encoded_preview}" ]]; then
46
+ exit 0
47
+ fi
48
+
49
+ preview_content="$(printf '%s' "${encoded_preview}" | base64 --decode)"
50
+
51
+ if command -v bat >/dev/null 2>&1; then
52
+ printf '%s' "${preview_content}" | glow -
53
+ elif command -v bat >/dev/null 2>&1; then
54
+ printf '%s' "${preview_content}" | bat --language=markdown --color=always --style=plain --paging=never
55
+ elif command -v glow >/dev/null 2>&1; then
56
+ printf '%s' "${preview_content}" | glow -
57
+ else
58
+ printf '%s' "${preview_content}"
59
+ fi
60
+ """,
61
+ encoding="utf-8"
62
+ )
63
+ preview_script.chmod(0o755)
64
+ channel_config = f"""[metadata]
65
+ name = "temp_options"
66
+ description = "Temporary channel for selecting options"
67
+
68
+ [source]
69
+ command = "cat '{entries_path}'"
70
+ display = "{{split:\\t:1}}"
71
+ output = "{{split:\\t:0}}"
72
+
73
+ [preview]
74
+ command = "{preview_script} {{split:\\t:0}}"
75
+
76
+ [ui.preview_panel]
77
+ size = 50
78
+ """
79
+ channel_path = tempdir / "temp_options.toml"
80
+ channel_path.write_text(channel_config, encoding="utf-8")
81
+ env = os.environ.copy()
82
+ tv_config_dir = pathlib.Path.home() / ".config" / "television"
83
+ if not tv_config_dir.exists():
84
+ tv_config_dir = pathlib.Path(os.getenv("XDG_CONFIG_HOME", str(pathlib.Path.home() / ".config"))) / "television"
85
+ cable_dir = tv_config_dir / "cable"
86
+ cable_dir.mkdir(parents=True, exist_ok=True)
87
+ temp_channel_link = cable_dir / "temp_options.toml"
88
+ if temp_channel_link.exists() or temp_channel_link.is_symlink():
89
+ temp_channel_link.unlink()
90
+ temp_channel_link.symlink_to(channel_path)
91
+ output_file = tempdir / "selection.txt"
92
+ try:
93
+ result = subprocess.run(["tv", "temp_options"], check=False, stdout=output_file.open("w"), text=True, env=env)
94
+ finally:
95
+ if temp_channel_link.exists() or temp_channel_link.is_symlink():
96
+ temp_channel_link.unlink()
97
+ if result.returncode not in (0, 130):
98
+ raise SystemExit(result.returncode)
99
+ if result.returncode == 130:
100
+ return None
101
+ if not output_file.exists():
102
+ return None
103
+ selected = output_file.read_text().strip()
104
+ if not selected:
105
+ return None
106
+ try:
107
+ index = int(selected)
108
+ except ValueError:
109
+ return None
110
+ return index_map.get(index)
111
+
112
+
113
+ if __name__ == "__main__":
114
+ demo_mapping = {
115
+ "Option 1": "# Option 1\nThis is the preview for option 1.",
116
+ "Option 2": "# Option 2\nThis is the preview for option 2.",
117
+ "Option 3": "# Option 3\nThis is the preview for option 3."
118
+ }
119
+ main(demo_mapping)