machineconfig 5.15__py3-none-any.whl → 7.98__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.
Files changed (472) hide show
  1. machineconfig/__init__.py +0 -28
  2. machineconfig/cluster/remote/cloud_manager.py +1 -1
  3. machineconfig/cluster/remote/distribute.py +0 -1
  4. machineconfig/cluster/remote/file_manager.py +0 -2
  5. machineconfig/cluster/remote/script_execution.py +0 -1
  6. machineconfig/cluster/sessions_managers/{utils → helpers}/enhanced_command_runner.py +4 -6
  7. machineconfig/cluster/sessions_managers/utils/load_balancer.py +1 -1
  8. machineconfig/cluster/sessions_managers/utils/maker.py +69 -0
  9. machineconfig/cluster/sessions_managers/wt_local.py +114 -289
  10. machineconfig/cluster/sessions_managers/wt_local_manager.py +70 -210
  11. machineconfig/cluster/sessions_managers/wt_remote.py +51 -43
  12. machineconfig/cluster/sessions_managers/wt_remote_manager.py +52 -198
  13. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +6 -19
  14. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  15. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  16. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +4 -2
  17. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  18. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  19. machineconfig/cluster/sessions_managers/zellij_local.py +81 -375
  20. machineconfig/cluster/sessions_managers/zellij_local_manager.py +25 -170
  21. machineconfig/cluster/sessions_managers/zellij_remote.py +40 -41
  22. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +16 -12
  23. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +4 -8
  24. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +5 -20
  25. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +3 -9
  26. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -1
  27. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper.py +298 -0
  28. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_restart.py +77 -0
  29. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_helper_with_panes.py +228 -0
  30. machineconfig/cluster/sessions_managers/zellij_utils/zellij_local_manager_helper.py +165 -0
  31. machineconfig/jobs/{python → installer}/check_installations.py +2 -3
  32. machineconfig/jobs/installer/custom/boxes.py +61 -0
  33. machineconfig/jobs/installer/custom/hx.py +76 -19
  34. machineconfig/jobs/installer/custom/yazi.py +119 -0
  35. machineconfig/jobs/installer/custom_dev/alacritty.py +4 -4
  36. machineconfig/jobs/installer/custom_dev/brave.py +5 -9
  37. machineconfig/jobs/installer/custom_dev/cloudflare_warp_cli.py +23 -0
  38. machineconfig/jobs/installer/custom_dev/code.py +4 -1
  39. machineconfig/jobs/installer/custom_dev/dubdb_adbc.py +30 -0
  40. machineconfig/jobs/installer/custom_dev/nerdfont.py +1 -1
  41. machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +33 -28
  42. machineconfig/jobs/installer/custom_dev/sysabc.py +139 -0
  43. machineconfig/jobs/installer/custom_dev/wezterm.py +2 -19
  44. machineconfig/jobs/installer/custom_dev/winget.py +10 -14
  45. machineconfig/jobs/installer/installer_data.json +1487 -229
  46. machineconfig/jobs/installer/linux_scripts/brave.sh +4 -14
  47. machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +5 -17
  48. machineconfig/jobs/installer/linux_scripts/docker.sh +5 -17
  49. machineconfig/jobs/installer/linux_scripts/docker_start.sh +6 -14
  50. machineconfig/jobs/installer/linux_scripts/edge.sh +3 -11
  51. machineconfig/jobs/{linux/msc → installer/linux_scripts}/lid.sh +2 -8
  52. machineconfig/jobs/installer/linux_scripts/nerdfont.sh +5 -17
  53. machineconfig/jobs/{linux/msc → installer/linux_scripts}/network.sh +2 -8
  54. machineconfig/jobs/installer/linux_scripts/q.sh +10 -6
  55. machineconfig/jobs/installer/linux_scripts/redis.sh +6 -17
  56. machineconfig/jobs/installer/linux_scripts/vscode.sh +5 -17
  57. machineconfig/jobs/installer/linux_scripts/wezterm.sh +4 -12
  58. machineconfig/jobs/installer/package_groups.py +106 -177
  59. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  60. machineconfig/logger.py +0 -1
  61. machineconfig/profile/backup.toml +49 -0
  62. machineconfig/profile/bash_shell_profiles.md +11 -0
  63. machineconfig/profile/create_helper.py +62 -0
  64. machineconfig/profile/create_links.py +288 -0
  65. machineconfig/profile/create_links_export.py +100 -0
  66. machineconfig/profile/create_shell_profile.py +147 -0
  67. machineconfig/profile/mapper.toml +263 -0
  68. machineconfig/scripts/__init__.py +0 -4
  69. machineconfig/scripts/linux/{share_cloud.sh → other/share_cloud.sh} +14 -25
  70. machineconfig/scripts/linux/wrap_mcfg +46 -0
  71. machineconfig/scripts/nu/wrap_mcfg.nu +69 -0
  72. machineconfig/scripts/python/agents.py +123 -117
  73. machineconfig/scripts/python/ai/initai.py +3 -28
  74. machineconfig/scripts/python/ai/scripts/command_runner.ps1 +33 -0
  75. machineconfig/scripts/python/ai/scripts/command_runner.sh +9 -0
  76. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +17 -18
  77. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +17 -18
  78. machineconfig/scripts/python/ai/solutions/_shared.py +9 -1
  79. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Thinking-Beast-Mode.chatmode.md → agents/Thinking-Beast-Mode.agent.md} +0 -1
  80. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md → agents/Ultimate-Transparent-Thinking-Beast-Mode.agent.md} +0 -1
  81. machineconfig/scripts/python/ai/solutions/copilot/{chatmodes/deepResearch.chatmode.md → agents/deepResearch.agent.md} +2 -2
  82. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +5 -5
  83. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +5 -1
  84. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/watch_exec.prompt.md +20 -0
  85. machineconfig/scripts/python/ai/solutions/copilot/prompts/pyright_fix.md +16 -0
  86. machineconfig/scripts/python/ai/solutions/generic.py +28 -5
  87. machineconfig/scripts/python/ai/utils/generate_files.py +348 -0
  88. machineconfig/scripts/python/ai/utils/vscode_tasks.py +37 -0
  89. machineconfig/scripts/python/cloud.py +29 -0
  90. machineconfig/scripts/python/croshell.py +137 -113
  91. machineconfig/scripts/python/devops.py +61 -101
  92. machineconfig/scripts/python/devops_navigator.py +6 -0
  93. machineconfig/scripts/python/env_manager/__init__.py +1 -0
  94. machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
  95. machineconfig/scripts/python/env_manager/path_manager_backend.py +47 -0
  96. machineconfig/scripts/python/env_manager/path_manager_tui.py +228 -0
  97. machineconfig/scripts/python/fire_jobs.py +110 -150
  98. machineconfig/scripts/python/ftpx.py +51 -24
  99. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  100. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  101. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  102. machineconfig/scripts/python/helpers/run_py_script.py +79 -0
  103. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  104. machineconfig/scripts/python/helpers/tmp_py_scripts/a.py +26 -0
  105. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.json +14 -0
  106. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_crush.py +39 -0
  107. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_cursor_agents.py +22 -0
  108. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_gemini.py +55 -0
  109. machineconfig/scripts/python/helpers_agents/agentic_frameworks/fire_qwen.py +30 -0
  110. machineconfig/scripts/python/helpers_agents/fire_agents_help_launch.py +126 -0
  111. machineconfig/scripts/python/helpers_agents/fire_agents_helper_types.py +41 -0
  112. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +10 -0
  113. machineconfig/scripts/python/helpers_agents/templates/template.ps1 +14 -0
  114. machineconfig/scripts/python/helpers_agents/templates/template.sh +32 -0
  115. machineconfig/scripts/python/{cloud_copy.py → helpers_cloud/cloud_copy.py} +30 -23
  116. machineconfig/scripts/python/{cloud_mount.py → helpers_cloud/cloud_mount.py} +29 -35
  117. machineconfig/scripts/python/{cloud_sync.py → helpers_cloud/cloud_sync.py} +12 -18
  118. machineconfig/scripts/python/{helpers → helpers_cloud}/helpers2.py +1 -1
  119. machineconfig/scripts/python/helpers_croshell/crosh.py +39 -0
  120. machineconfig/scripts/python/{start_slidev.py → helpers_croshell/start_slidev.py} +8 -9
  121. machineconfig/scripts/python/helpers_devops/cli_config.py +105 -0
  122. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +89 -0
  123. machineconfig/scripts/python/helpers_devops/cli_data.py +25 -0
  124. machineconfig/scripts/python/helpers_devops/cli_nw.py +214 -0
  125. machineconfig/scripts/python/helpers_devops/cli_repos.py +215 -0
  126. machineconfig/scripts/python/helpers_devops/cli_self.py +172 -0
  127. machineconfig/scripts/python/helpers_devops/cli_share_file.py +137 -0
  128. machineconfig/scripts/python/helpers_devops/cli_share_server.py +142 -0
  129. machineconfig/scripts/python/{share_terminal.py → helpers_devops/cli_share_terminal.py} +45 -35
  130. machineconfig/scripts/python/helpers_devops/cli_utils.py +96 -0
  131. machineconfig/scripts/python/{devops_backup_retrieve.py → helpers_devops/devops_backup_retrieve.py} +7 -10
  132. machineconfig/scripts/python/helpers_devops/devops_status.py +499 -0
  133. machineconfig/scripts/python/{devops_update_repos.py → helpers_devops/devops_update_repos.py} +68 -49
  134. machineconfig/scripts/python/helpers_devops/themes/choose_pwsh_theme.ps1 +81 -0
  135. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +3 -0
  136. machineconfig/scripts/python/{choose_wezterm_theme.py → helpers_devops/themes/choose_wezterm_theme.py} +3 -3
  137. machineconfig/scripts/python/helpers_fire_command/__init__.py +0 -0
  138. machineconfig/scripts/python/helpers_fire_command/f.py +0 -0
  139. machineconfig/scripts/python/{helpers/helpers4.py → helpers_fire_command/file_wrangler.py} +56 -20
  140. machineconfig/scripts/python/{fire_jobs_args_helper.py → helpers_fire_command/fire_jobs_args_helper.py} +5 -1
  141. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +121 -0
  142. machineconfig/scripts/python/helpers_fire_command/fire_jobs_streamlit_helper.py +0 -0
  143. machineconfig/scripts/python/helpers_msearch/__init__.py +5 -0
  144. machineconfig/scripts/{linux → python/helpers_msearch/scripts_linux}/fzfg +3 -3
  145. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +59 -0
  146. machineconfig/scripts/python/helpers_navigator/__init__.py +20 -0
  147. machineconfig/scripts/python/helpers_navigator/command_builder.py +111 -0
  148. machineconfig/scripts/python/helpers_navigator/command_detail.py +44 -0
  149. machineconfig/scripts/python/helpers_navigator/command_tree.py +620 -0
  150. machineconfig/scripts/python/helpers_navigator/data_models.py +28 -0
  151. machineconfig/scripts/python/helpers_navigator/main_app.py +272 -0
  152. machineconfig/scripts/python/helpers_navigator/search_bar.py +15 -0
  153. machineconfig/scripts/python/helpers_network/__init__.py +0 -0
  154. machineconfig/scripts/python/helpers_network/address.py +132 -0
  155. machineconfig/scripts/python/{devops_add_identity.py → helpers_network/devops_add_identity.py} +0 -2
  156. machineconfig/scripts/python/helpers_network/devops_add_ssh_key.py +153 -0
  157. machineconfig/scripts/{linux → python/helpers_network}/mount_nfs +0 -1
  158. machineconfig/scripts/python/{mount_nfs.py → helpers_network/mount_nfs.py} +3 -3
  159. machineconfig/scripts/{linux → python/helpers_network}/mount_nw_drive +1 -2
  160. machineconfig/scripts/python/{mount_ssh.py → helpers_network/mount_ssh.py} +3 -3
  161. machineconfig/scripts/python/{onetimeshare.py → helpers_network/onetimeshare.py} +0 -1
  162. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +391 -0
  163. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +338 -0
  164. machineconfig/scripts/python/{wifi_conn.py → helpers_network/wifi_conn.py} +1 -53
  165. machineconfig/scripts/python/{wsl_windows_transfer.py → helpers_network/wsl_windows_transfer.py} +5 -4
  166. machineconfig/scripts/python/helpers_repos/action.py +209 -0
  167. machineconfig/scripts/python/helpers_repos/action_helper.py +150 -0
  168. machineconfig/scripts/python/{repos_helper_clone.py → helpers_repos/clone.py} +2 -3
  169. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +218 -0
  170. machineconfig/scripts/python/{repos_helper.py → helpers_repos/entrypoint.py} +9 -17
  171. machineconfig/scripts/python/helpers_repos/grource.py +340 -0
  172. machineconfig/scripts/python/{repos_helper_record.py → helpers_repos/record.py} +4 -3
  173. machineconfig/scripts/python/helpers_repos/repo_analyzer_1.py +160 -0
  174. machineconfig/scripts/python/{count_lines.py → helpers_repos/repo_analyzer_2.py} +113 -192
  175. machineconfig/scripts/python/helpers_repos/sync.py +66 -0
  176. machineconfig/scripts/python/{repos_helper_update.py → helpers_repos/update.py} +3 -3
  177. machineconfig/scripts/python/helpers_sessions/__init__.py +0 -0
  178. machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +65 -0
  179. machineconfig/scripts/python/helpers_utils/download.py +150 -0
  180. machineconfig/scripts/python/helpers_utils/path.py +185 -0
  181. machineconfig/scripts/python/interactive.py +64 -84
  182. machineconfig/scripts/python/mcfg_entry.py +58 -0
  183. machineconfig/scripts/python/msearch.py +71 -0
  184. machineconfig/scripts/python/sessions.py +119 -45
  185. machineconfig/scripts/python/terminal.py +133 -0
  186. machineconfig/scripts/python/utils.py +64 -0
  187. machineconfig/scripts/windows/mounts/Restore-ThunderbirdProfile.ps1 +92 -0
  188. machineconfig/scripts/windows/{mount_nfs.ps1 → mounts/mount_nfs.ps1} +1 -3
  189. machineconfig/scripts/windows/{mount_ssh.ps1 → mounts/mount_ssh.ps1} +1 -1
  190. machineconfig/scripts/windows/{share_smb.ps1 → mounts/share_smb.ps1} +0 -6
  191. machineconfig/scripts/windows/wrap_mcfg.ps1 +63 -0
  192. machineconfig/settings/broot/br.sh +0 -4
  193. machineconfig/settings/broot/conf.toml +1 -1
  194. machineconfig/settings/helix/config.toml +16 -0
  195. machineconfig/settings/helix/languages.toml +13 -4
  196. machineconfig/settings/helix/yazi-picker.sh +12 -0
  197. machineconfig/settings/lf/linux/exe/lfcd.sh +1 -0
  198. machineconfig/settings/lf/linux/exe/previewer.sh +9 -3
  199. machineconfig/settings/lf/linux/lfrc +10 -12
  200. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  201. machineconfig/settings/lf/windows/lfrc +18 -38
  202. machineconfig/settings/lf/windows/mkfile.ps1 +1 -1
  203. machineconfig/settings/linters/.ruff.toml +1 -1
  204. machineconfig/settings/lvim/windows/archive/config_additional.lua +0 -6
  205. machineconfig/settings/marimo/marimo.toml +80 -0
  206. machineconfig/settings/marimo/snippets/globalize.py +34 -0
  207. machineconfig/settings/pistol/pistol.conf +1 -1
  208. machineconfig/settings/shells/bash/init.sh +82 -31
  209. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +1 -1
  210. machineconfig/settings/shells/nushell/config.nu +2 -35
  211. machineconfig/settings/shells/nushell/env.nu +45 -6
  212. machineconfig/settings/shells/nushell/init.nu +314 -0
  213. machineconfig/settings/shells/pwsh/init.ps1 +61 -43
  214. machineconfig/settings/shells/starship/starship.toml +16 -0
  215. machineconfig/settings/shells/wezterm/wezterm.lua +2 -0
  216. machineconfig/settings/shells/wt/settings.json +32 -17
  217. machineconfig/settings/shells/zsh/init.sh +89 -0
  218. machineconfig/settings/svim/linux/init.toml +0 -4
  219. machineconfig/settings/svim/windows/init.toml +0 -3
  220. machineconfig/settings/television/cable_unix/alias.toml +8 -0
  221. machineconfig/settings/television/cable_unix/aws-buckets.toml +14 -0
  222. machineconfig/settings/television/cable_unix/aws-instances.toml +13 -0
  223. machineconfig/settings/television/cable_unix/bash-history.toml +8 -0
  224. machineconfig/settings/television/cable_unix/channels.toml +19 -0
  225. machineconfig/settings/television/cable_unix/dirs.toml +13 -0
  226. machineconfig/settings/television/cable_unix/distrobox-list.toml +42 -0
  227. machineconfig/settings/television/cable_unix/docker-images.toml +13 -0
  228. machineconfig/settings/television/cable_unix/dotfiles.toml +11 -0
  229. machineconfig/settings/television/cable_unix/env.toml +17 -0
  230. machineconfig/settings/television/cable_unix/files.toml +11 -0
  231. machineconfig/settings/television/cable_unix/fish-history.toml +8 -0
  232. machineconfig/settings/television/cable_unix/git-branch.toml +11 -0
  233. machineconfig/settings/television/cable_unix/git-diff.toml +10 -0
  234. machineconfig/settings/television/cable_unix/git-log.toml +12 -0
  235. machineconfig/settings/television/cable_unix/git-reflog.toml +12 -0
  236. machineconfig/settings/television/cable_unix/git-repos.toml +16 -0
  237. machineconfig/settings/television/cable_unix/guix.toml +20 -0
  238. machineconfig/settings/television/cable_unix/just-recipes.toml +18 -0
  239. machineconfig/settings/television/cable_unix/k8s-deployments.toml +36 -0
  240. machineconfig/settings/television/cable_unix/k8s-pods.toml +50 -0
  241. machineconfig/settings/television/cable_unix/k8s-services.toml +36 -0
  242. machineconfig/settings/television/cable_unix/man-pages.toml +24 -0
  243. machineconfig/settings/television/cable_unix/nu-history.toml +7 -0
  244. machineconfig/settings/television/cable_unix/procs.toml +20 -0
  245. machineconfig/settings/television/cable_unix/text.toml +17 -0
  246. machineconfig/settings/television/cable_unix/tldr.toml +18 -0
  247. machineconfig/settings/television/cable_unix/zsh-history.toml +9 -0
  248. machineconfig/settings/television/cable_windows/alias.toml +7 -0
  249. machineconfig/settings/television/cable_windows/dirs.toml +13 -0
  250. machineconfig/settings/television/cable_windows/docker-images.toml +13 -0
  251. machineconfig/settings/television/cable_windows/dotfiles.toml +11 -0
  252. machineconfig/settings/television/cable_windows/env.toml +17 -0
  253. machineconfig/settings/television/cable_windows/files.toml +14 -0
  254. machineconfig/settings/television/cable_windows/git-branch.toml +11 -0
  255. machineconfig/settings/television/cable_windows/git-diff.toml +10 -0
  256. machineconfig/settings/television/cable_windows/git-log.toml +11 -0
  257. machineconfig/settings/television/cable_windows/git-reflog.toml +11 -0
  258. machineconfig/settings/television/cable_windows/git-repos.toml +15 -0
  259. machineconfig/settings/television/cable_windows/nu-history.toml +7 -0
  260. machineconfig/settings/television/cable_windows/pwsh-history.toml +6 -0
  261. machineconfig/settings/television/cable_windows/text.toml +17 -0
  262. machineconfig/settings/yazi/init.lua +61 -0
  263. machineconfig/settings/yazi/keymap_linux.toml +94 -0
  264. machineconfig/settings/yazi/keymap_windows.toml +78 -0
  265. machineconfig/settings/yazi/shell/yazi_cd.ps1 +33 -0
  266. machineconfig/settings/yazi/shell/yazi_cd.sh +8 -0
  267. machineconfig/settings/yazi/theme.toml +4 -0
  268. machineconfig/settings/yazi/yazi_linux.toml +84 -0
  269. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  270. machineconfig/setup_linux/__init__.py +11 -0
  271. machineconfig/setup_linux/apps_desktop.sh +89 -0
  272. machineconfig/setup_linux/apps_gui.sh +64 -0
  273. machineconfig/setup_linux/ssh/openssh_all.sh +25 -0
  274. machineconfig/setup_linux/ssh/openssh_wsl.sh +38 -0
  275. machineconfig/setup_linux/uv.sh +15 -0
  276. machineconfig/setup_linux/web_shortcuts/interactive.sh +26 -6
  277. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +31 -0
  278. machineconfig/setup_mac/__init__.py +16 -0
  279. machineconfig/setup_mac/apps_gui.sh +248 -0
  280. machineconfig/setup_mac/ssh/openssh_setup.sh +114 -0
  281. machineconfig/setup_mac/uv.sh +36 -0
  282. machineconfig/setup_windows/__init__.py +11 -0
  283. machineconfig/setup_windows/others/power_options.ps1 +7 -0
  284. machineconfig/setup_windows/ssh/add-sshkey.ps1 +29 -0
  285. machineconfig/setup_windows/ssh/add_identity.ps1 +11 -0
  286. machineconfig/setup_windows/ssh/openssh-server.ps1 +37 -0
  287. machineconfig/setup_windows/uv.ps1 +17 -0
  288. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +27 -10
  289. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +30 -0
  290. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +17 -0
  291. machineconfig/utils/accessories.py +7 -5
  292. machineconfig/utils/cloud/onedrive/README.md +139 -0
  293. machineconfig/utils/code.py +155 -105
  294. machineconfig/utils/files/art/fat_croco.txt +10 -0
  295. machineconfig/utils/files/art/halfwit_croco.txt +9 -0
  296. machineconfig/utils/files/art/happy_croco.txt +22 -0
  297. machineconfig/utils/files/art/water_croco.txt +11 -0
  298. machineconfig/utils/files/ascii_art.py +1 -1
  299. machineconfig/utils/files/dbms.py +257 -0
  300. machineconfig/utils/files/headers.py +11 -14
  301. machineconfig/utils/files/ouch/__init__.py +0 -0
  302. machineconfig/utils/files/ouch/decompress.py +45 -0
  303. machineconfig/utils/files/read.py +10 -18
  304. machineconfig/utils/installer_utils/github_release_bulk.py +156 -119
  305. machineconfig/utils/installer_utils/install_from_url.py +183 -0
  306. machineconfig/utils/installer_utils/installer_class.py +64 -181
  307. machineconfig/utils/installer_utils/installer_cli.py +175 -0
  308. machineconfig/utils/installer_utils/installer_helper.py +129 -0
  309. machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +66 -97
  310. machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +49 -82
  311. machineconfig/utils/io.py +77 -23
  312. machineconfig/utils/links.py +254 -162
  313. machineconfig/utils/meta.py +256 -0
  314. machineconfig/utils/notifications.py +1 -1
  315. machineconfig/utils/options.py +46 -18
  316. machineconfig/utils/options_tv.py +119 -0
  317. machineconfig/utils/path_extended.py +48 -101
  318. machineconfig/utils/path_helper.py +76 -23
  319. machineconfig/utils/procs.py +50 -70
  320. machineconfig/utils/scheduler.py +88 -124
  321. machineconfig/utils/scheduling.py +0 -3
  322. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  323. machineconfig/utils/schemas/layouts/layout_types.py +1 -1
  324. machineconfig/utils/source_of_truth.py +3 -6
  325. machineconfig/utils/ssh.py +263 -274
  326. machineconfig/utils/ssh_utils/abc.py +5 -0
  327. machineconfig/utils/ssh_utils/copy_from_here.py +111 -0
  328. machineconfig/utils/ssh_utils/copy_to_here.py +302 -0
  329. machineconfig/utils/ssh_utils/utils.py +142 -0
  330. machineconfig/utils/ssh_utils/wsl.py +210 -0
  331. machineconfig/utils/terminal.py +3 -113
  332. machineconfig/utils/tst.py +20 -0
  333. machineconfig/utils/upgrade_packages.py +114 -28
  334. machineconfig/utils/ve.py +12 -4
  335. machineconfig-7.98.dist-info/METADATA +132 -0
  336. machineconfig-7.98.dist-info/RECORD +504 -0
  337. machineconfig-7.98.dist-info/entry_points.txt +13 -0
  338. machineconfig/cluster/sessions_managers/ffile.py +0 -4
  339. machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -49
  340. machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -85
  341. machineconfig/jobs/linux/msc/cli_agents.sh +0 -16
  342. machineconfig/jobs/python/python_ve_symlink.py +0 -37
  343. machineconfig/jobs/python/vscode/api.py +0 -57
  344. machineconfig/jobs/python/vscode/sync_code.py +0 -73
  345. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +0 -14
  346. machineconfig/jobs/windows/start_terminal.ps1 +0 -6
  347. machineconfig/jobs/windows/startup_file.cmd +0 -2
  348. machineconfig/profile/create.py +0 -303
  349. machineconfig/profile/shell.py +0 -176
  350. machineconfig/scripts/cloud/init.sh +0 -119
  351. machineconfig/scripts/linux/agents +0 -2
  352. machineconfig/scripts/linux/choose_wezterm_theme +0 -3
  353. machineconfig/scripts/linux/cloud_copy +0 -2
  354. machineconfig/scripts/linux/cloud_mount +0 -2
  355. machineconfig/scripts/linux/cloud_repo_sync +0 -2
  356. machineconfig/scripts/linux/cloud_sync +0 -2
  357. machineconfig/scripts/linux/croshell +0 -3
  358. machineconfig/scripts/linux/devops +0 -2
  359. machineconfig/scripts/linux/fire +0 -2
  360. machineconfig/scripts/linux/ftpx +0 -2
  361. machineconfig/scripts/linux/fzf2g +0 -21
  362. machineconfig/scripts/linux/fzfag +0 -17
  363. machineconfig/scripts/linux/fzffg +0 -25
  364. machineconfig/scripts/linux/fzfrga +0 -21
  365. machineconfig/scripts/linux/gh_models +0 -2
  366. machineconfig/scripts/linux/initai +0 -2
  367. machineconfig/scripts/linux/kill_process +0 -2
  368. machineconfig/scripts/linux/scheduler +0 -2
  369. machineconfig/scripts/linux/sessions +0 -2
  370. machineconfig/scripts/linux/share_smb +0 -1
  371. machineconfig/scripts/linux/skrg +0 -4
  372. machineconfig/scripts/linux/start_slidev +0 -2
  373. machineconfig/scripts/linux/start_terminals +0 -3
  374. machineconfig/scripts/linux/warp-cli.sh +0 -122
  375. machineconfig/scripts/linux/wifi_conn +0 -2
  376. machineconfig/scripts/linux/z_ls +0 -104
  377. machineconfig/scripts/python/ai/generate_files.py +0 -83
  378. machineconfig/scripts/python/ai/solutions/copilot/prompts/allLintersAndTypeCheckers.prompt.md +0 -5
  379. machineconfig/scripts/python/cloud_repo_sync.py +0 -190
  380. machineconfig/scripts/python/count_lines_frontend.py +0 -16
  381. machineconfig/scripts/python/devops_add_ssh_key.py +0 -120
  382. machineconfig/scripts/python/dotfile.py +0 -78
  383. machineconfig/scripts/python/fire_agents_help_launch.py +0 -120
  384. machineconfig/scripts/python/fire_agents_helper_types.py +0 -12
  385. machineconfig/scripts/python/fire_jobs_route_helper.py +0 -65
  386. machineconfig/scripts/python/get_zellij_cmd.py +0 -15
  387. machineconfig/scripts/python/gh_models.py +0 -104
  388. machineconfig/scripts/python/helpers/repo_sync_helpers.py +0 -116
  389. machineconfig/scripts/python/repos.py +0 -132
  390. machineconfig/scripts/python/repos_helper_action.py +0 -378
  391. machineconfig/scripts/python/snapshot.py +0 -25
  392. machineconfig/scripts/python/start_terminals.py +0 -121
  393. machineconfig/scripts/python/t4.py +0 -17
  394. machineconfig/scripts/windows/agents.ps1 +0 -1
  395. machineconfig/scripts/windows/choose_wezterm_theme.ps1 +0 -1
  396. machineconfig/scripts/windows/cloud_copy.ps1 +0 -1
  397. machineconfig/scripts/windows/cloud_mount.ps1 +0 -1
  398. machineconfig/scripts/windows/cloud_repo_sync.ps1 +0 -1
  399. machineconfig/scripts/windows/cloud_sync.ps1 +0 -1
  400. machineconfig/scripts/windows/croshell.ps1 +0 -1
  401. machineconfig/scripts/windows/devops.ps1 +0 -1
  402. machineconfig/scripts/windows/dotfile.ps1 +0 -1
  403. machineconfig/scripts/windows/fire.ps1 +0 -1
  404. machineconfig/scripts/windows/ftpx.ps1 +0 -1
  405. machineconfig/scripts/windows/fzfb.ps1 +0 -3
  406. machineconfig/scripts/windows/fzfg.ps1 +0 -2
  407. machineconfig/scripts/windows/fzfrga.bat +0 -20
  408. machineconfig/scripts/windows/gpt.ps1 +0 -1
  409. machineconfig/scripts/windows/grep.ps1 +0 -2
  410. machineconfig/scripts/windows/initai.ps1 +0 -1
  411. machineconfig/scripts/windows/kill_process.ps1 +0 -1
  412. machineconfig/scripts/windows/nano.ps1 +0 -3
  413. machineconfig/scripts/windows/pomodoro.ps1 +0 -1
  414. machineconfig/scripts/windows/reload_path.ps1 +0 -3
  415. machineconfig/scripts/windows/scheduler.ps1 +0 -1
  416. machineconfig/scripts/windows/sessions.ps1 +0 -1
  417. machineconfig/scripts/windows/snapshot.ps1 +0 -1
  418. machineconfig/scripts/windows/start_slidev.ps1 +0 -1
  419. machineconfig/scripts/windows/start_terminals.ps1 +0 -1
  420. machineconfig/scripts/windows/wifi_conn.ps1 +0 -2
  421. machineconfig/scripts/windows/wsl_rdp_windows_port_forwarding.ps1 +0 -46
  422. machineconfig/scripts/windows/wsl_ssh_windows_port_forwarding.ps1 +0 -76
  423. machineconfig/settings/lf/linux/exe/fzf_nano.sh +0 -16
  424. machineconfig/settings/lf/windows/fzf_edit.ps1 +0 -6
  425. machineconfig/settings/lf/windows/tst.ps1 +0 -1
  426. machineconfig/settings/yazi/yazi.toml +0 -4
  427. machineconfig/setup_linux/nix/cli_installation.sh +0 -157
  428. machineconfig/setup_linux/others/openssh-server_add_pub_key.sh +0 -57
  429. machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -11
  430. machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -52
  431. machineconfig/setup_windows/web_shortcuts/all.ps1 +0 -18
  432. machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +0 -36
  433. machineconfig/setup_windows/web_shortcuts/croshell.ps1 +0 -16
  434. machineconfig/setup_windows/web_shortcuts/ssh.ps1 +0 -11
  435. machineconfig/utils/ai/generate_file_checklist.py +0 -68
  436. machineconfig/utils/installer_utils/installer.py +0 -189
  437. machineconfig-5.15.dist-info/METADATA +0 -188
  438. machineconfig-5.15.dist-info/RECORD +0 -415
  439. machineconfig-5.15.dist-info/entry_points.txt +0 -18
  440. machineconfig/cluster/sessions_managers/{utils → helpers}/load_balancer_helper.py +0 -0
  441. machineconfig/scripts/linux/{share_nfs → other/share_nfs} +0 -0
  442. machineconfig/scripts/linux/{start_docker → other/start_docker} +0 -0
  443. machineconfig/scripts/linux/{switch_ip → other/switch_ip} +0 -0
  444. machineconfig/{jobs/python → scripts/python/ai/utils}/__init__.py +0 -0
  445. machineconfig/scripts/python/{helpers → helpers_agents}/__init__.py +0 -0
  446. machineconfig/{jobs/windows/msc/cli_agents.bat → scripts/python/helpers_agents/agentic_frameworks/__init__.py} +0 -0
  447. machineconfig/scripts/python/{fire_agents_help_search.py → helpers_agents/fire_agents_help_search.py} +0 -0
  448. machineconfig/scripts/python/{fire_agents_load_balancer.py → helpers_agents/fire_agents_load_balancer.py} +0 -0
  449. machineconfig/{jobs/windows/msc/cli_agents.ps1 → scripts/python/helpers_cloud/__init__.py} +0 -0
  450. machineconfig/scripts/python/{helpers → helpers_cloud}/cloud_helpers.py +1 -1
  451. /machineconfig/scripts/python/{helpers → helpers_cloud}/helpers5.py +0 -0
  452. /machineconfig/scripts/python/{fire_jobs_streamlit_helper.py → helpers_croshell/__init__.py} +0 -0
  453. /machineconfig/scripts/python/{pomodoro.py → helpers_croshell/pomodoro.py} +0 -0
  454. /machineconfig/scripts/python/{scheduler.py → helpers_croshell/scheduler.py} +0 -0
  455. /machineconfig/scripts/python/{viewer.py → helpers_croshell/viewer.py} +0 -0
  456. /machineconfig/scripts/python/{viewer_template.py → helpers_croshell/viewer_template.py} +0 -0
  457. /machineconfig/scripts/{windows/share_nfs.ps1 → python/helpers_devops/__init__.py} +0 -0
  458. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_devops/themes/__init__.py} +0 -0
  459. /machineconfig/{settings/yazi/keymap.toml → scripts/python/helpers_devops/themes/choose_starship_theme.ps1} +0 -0
  460. /machineconfig/scripts/python/{cloud_manager.py → helpers_fire_command/cloud_manager.py} +0 -0
  461. /machineconfig/scripts/{linux → python/helpers_network}/mount_drive +0 -0
  462. /machineconfig/scripts/python/{mount_nw_drive.py → helpers_network/mount_nw_drive.py} +0 -0
  463. /machineconfig/scripts/{linux → python/helpers_network}/mount_smb +0 -0
  464. /machineconfig/scripts/windows/{mount_nw.ps1 → mounts/mount_nw.ps1} +0 -0
  465. /machineconfig/scripts/windows/{mount_smb.ps1 → mounts/mount_smb.ps1} +0 -0
  466. /machineconfig/scripts/windows/{share_cloud.cmd → mounts/share_cloud.cmd} +0 -0
  467. /machineconfig/scripts/windows/{unlock_bitlocker.ps1 → mounts/unlock_bitlocker.ps1} +0 -0
  468. /machineconfig/setup_linux/{web_shortcuts → others}/android.sh +0 -0
  469. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_add_key.ps1 +0 -0
  470. /machineconfig/{jobs/windows/archive → setup_windows/ssh}/openssh-server_copy-ssh-id.ps1 +0 -0
  471. {machineconfig-5.15.dist-info → machineconfig-7.98.dist-info}/WHEEL +0 -0
  472. {machineconfig-5.15.dist-info → machineconfig-7.98.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,298 @@
1
+ #!/usr/bin/env python3
2
+ import shlex
3
+ import subprocess
4
+ import random
5
+ import string
6
+ import psutil
7
+ import logging
8
+ from typing import List
9
+ from pathlib import Path
10
+
11
+ from machineconfig.cluster.sessions_managers.zellij_utils.monitoring_types import CommandStatus, ZellijSessionStatus
12
+ from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig, TabConfig
13
+
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ def generate_random_suffix(length: int) -> str:
19
+ """Generate a random string suffix for unique layout file names."""
20
+ return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
21
+
22
+
23
+ def parse_command(command: str) -> tuple[str, List[str]]:
24
+ """Parse a command string into executable and arguments."""
25
+ try:
26
+ parts = shlex.split(command)
27
+ if not parts:
28
+ raise ValueError("Empty command provided")
29
+ return parts[0], parts[1:] if len(parts) > 1 else []
30
+ except ValueError as e:
31
+ logger.error(f"Error parsing command '{command}': {e}")
32
+ parts = command.split()
33
+ return parts[0] if parts else "", parts[1:] if len(parts) > 1 else []
34
+
35
+
36
+ def format_args_for_kdl(args: List[str]) -> str:
37
+ """Format command arguments for KDL layout format."""
38
+ if not args:
39
+ return ""
40
+ formatted_args = []
41
+ for arg in args:
42
+ if " " in arg or '"' in arg or "'" in arg:
43
+ escaped_arg = arg.replace('"', '\\"')
44
+ formatted_args.append(f'"{escaped_arg}"')
45
+ else:
46
+ formatted_args.append(f'"{arg}"')
47
+ return " ".join(formatted_args)
48
+
49
+
50
+ def create_tab_section(tab_config: TabConfig) -> str:
51
+ """Create a KDL tab section from tab configuration."""
52
+ tab_name = tab_config["tabName"]
53
+ cwd = tab_config["startDir"]
54
+ command = tab_config["command"]
55
+ cmd, args = parse_command(command)
56
+ args_str = format_args_for_kdl(args)
57
+ tab_cwd = cwd or "~"
58
+ escaped_tab_name = tab_name.replace('"', '\\"')
59
+ tab_section = f' tab name="{escaped_tab_name}" cwd="{tab_cwd}" {{\n'
60
+ tab_section += f' pane command="{cmd}" {{\n'
61
+ if args_str:
62
+ tab_section += f" args {args_str}\n"
63
+ tab_section += " }\n }\n"
64
+ return tab_section
65
+
66
+
67
+ def validate_layout_config(layout_config: LayoutConfig) -> None:
68
+ """Validate layout configuration."""
69
+ if not layout_config["layoutTabs"]:
70
+ raise ValueError("Layout must contain at least one tab")
71
+ for tab in layout_config["layoutTabs"]:
72
+ if not tab["tabName"].strip():
73
+ raise ValueError(f"Invalid tab name: {tab['tabName']}")
74
+ if not tab["command"].strip():
75
+ raise ValueError(f"Invalid command for tab '{tab['tabName']}': {tab['command']}")
76
+ if not tab["startDir"].strip():
77
+ raise ValueError(f"Invalid startDir for tab '{tab['tabName']}': {tab['startDir']}")
78
+
79
+
80
+ def check_command_status(tab_name: str, layout_config: LayoutConfig) -> CommandStatus:
81
+ """Check the running status of a command for a specific tab."""
82
+ # Find the tab with the given name
83
+ tab_config = None
84
+ for tab in layout_config["layoutTabs"]:
85
+ if tab["tabName"] == tab_name:
86
+ tab_config = tab
87
+ break
88
+
89
+ if tab_config is None:
90
+ return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "command": "", "cwd": "", "tab_name": tab_name, "processes": []}
91
+
92
+ command = tab_config["command"]
93
+ cwd = tab_config["startDir"]
94
+ cmd, args = parse_command(command)
95
+ try:
96
+ shells = {"bash", "sh", "zsh", "fish"}
97
+ matching_processes = []
98
+ for proc in psutil.process_iter(["pid", "name", "cmdline", "status", "ppid", "create_time", "memory_info"]):
99
+ try:
100
+ info = proc.info
101
+ proc_cmdline: list[str] | None = info.get("cmdline") # type: ignore[assignment]
102
+ if not proc_cmdline:
103
+ continue
104
+ if info.get("status") in ["zombie", "dead", "stopped"]:
105
+ continue
106
+ proc_name = info.get("name", "")
107
+ is_match = False
108
+ joined_cmdline = " ".join(proc_cmdline)
109
+ # Primary matching heuristics - more precise matching
110
+ if proc_name == cmd and cmd not in shells:
111
+ # For non-shell commands, match if args appear in cmdline
112
+ if not args or any(arg in joined_cmdline for arg in args):
113
+ is_match = True
114
+ elif proc_name == cmd and cmd in shells:
115
+ # For shell commands, require more precise matching to avoid false positives
116
+ if args:
117
+ # Check if all args appear as separate cmdline arguments (not just substrings)
118
+ args_found = 0
119
+ for arg in args:
120
+ for cmdline_arg in proc_cmdline[1:]: # Skip shell name
121
+ if arg == cmdline_arg or (len(arg) > 3 and arg in cmdline_arg):
122
+ args_found += 1
123
+ break
124
+ # Require at least as many args found as we're looking for
125
+ if args_found >= len(args):
126
+ is_match = True
127
+ elif cmd in proc_cmdline[0] and cmd not in shells:
128
+ # Non-shell command in first argument
129
+ is_match = True
130
+
131
+ # Additional shell wrapper filter - be more restrictive for shells
132
+ if is_match and proc_name in shells and args:
133
+ # For shell processes, ensure the match is actually meaningful
134
+ # Don't match generic shell sessions just because they contain common paths
135
+ meaningful_match = False
136
+ for arg in args:
137
+ # Only consider it meaningful if the arg is substantial (not just a common path)
138
+ if len(arg) > 10 and any(arg == cmdline_arg for cmdline_arg in proc_cmdline[1:]):
139
+ meaningful_match = True
140
+ break
141
+ # Or if it's an exact script name match
142
+ elif arg.endswith(".py") or arg.endswith(".sh") or arg.endswith(".rb"):
143
+ if any(arg in cmdline_arg for cmdline_arg in proc_cmdline[1:]):
144
+ meaningful_match = True
145
+ break
146
+ if not meaningful_match:
147
+ is_match = False
148
+ if not is_match:
149
+ continue
150
+ try:
151
+ proc_obj = psutil.Process(info["pid"]) # type: ignore[index]
152
+ if proc_obj.status() not in ["running", "sleeping"]:
153
+ continue
154
+ mem_info = None
155
+ try:
156
+ mem = proc_obj.memory_info()
157
+ mem_info = mem.rss / (1024 * 1024)
158
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
159
+ pass
160
+ matching_processes.append(
161
+ {
162
+ "pid": info["pid"], # type: ignore[index]
163
+ "name": proc_name,
164
+ "cmdline": proc_cmdline,
165
+ "status": info.get("status", "unknown"),
166
+ "cmdline_str": joined_cmdline,
167
+ "create_time": info.get("create_time", 0.0),
168
+ **({"memory_mb": float(mem_info)} if mem_info is not None else {}),
169
+ }
170
+ )
171
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
172
+ continue
173
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
174
+ continue
175
+
176
+ # Second-pass filtering: remove idle wrapper shells that have no meaningful (non-shell) descendants
177
+ filtered_active = []
178
+ for proc_info in matching_processes:
179
+ try:
180
+ proc_obj = psutil.Process(proc_info["pid"]) # type: ignore[index]
181
+ if not proc_obj.is_running():
182
+ continue
183
+ status_val = proc_obj.status()
184
+ if status_val not in ["running", "sleeping"]:
185
+ continue
186
+ proc_name = proc_info.get("name", "")
187
+ if proc_name in shells:
188
+ descendants = proc_obj.children(recursive=True)
189
+ # Keep shell only if there exists a non-shell alive descendant OR descendant cmdline still includes our command token
190
+ meaningful = False
191
+ for child in descendants:
192
+ try:
193
+ if not child.is_running():
194
+ continue
195
+ child_name = child.name()
196
+ child_cmdline = " ".join(child.cmdline())
197
+ if child_name not in shells:
198
+ meaningful = True
199
+ break
200
+ if cmd in child_cmdline or any(arg in child_cmdline for arg in args):
201
+ meaningful = True
202
+ break
203
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
204
+ continue
205
+ if not meaningful:
206
+ continue # discard idle wrapper shell
207
+ filtered_active.append(proc_info)
208
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
209
+ continue
210
+
211
+ if filtered_active:
212
+ # Heuristic: if the only remaining processes are wrapper shells invoking a script that already completed, mark as not running.
213
+ # Case: layout launches 'bash <script.sh>' where script finishes and leaves an idle shell whose cmdline still shows the script path.
214
+ try:
215
+ if all(p.get("name") in shells for p in filtered_active):
216
+ script_paths = [arg for arg in args if arg.endswith(".sh")]
217
+ shell_only = True
218
+ stale_script_overall = False
219
+ for p in filtered_active:
220
+ proc_shell = psutil.Process(p["pid"]) # type: ignore[index]
221
+ create_time = getattr(proc_shell, "create_time", lambda: None)()
222
+ cmdline_joined = " ".join(p.get("cmdline", []))
223
+ stale_script = False
224
+ for spath in script_paths:
225
+ script_file = Path(spath)
226
+ if script_file.exists():
227
+ try:
228
+ # If script mtime older than process start AND no non-shell descendants -> likely finished
229
+ if create_time and script_file.stat().st_mtime < create_time:
230
+ stale_script = True
231
+ except OSError:
232
+ pass
233
+ if spath not in cmdline_joined:
234
+ stale_script = False
235
+ # If shell has any alive non-shell descendants, treat as running
236
+ descendants = proc_shell.children(recursive=True)
237
+ for d in descendants:
238
+ try:
239
+ if d.is_running() and d.name() not in shells:
240
+ shell_only = False
241
+ break
242
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
243
+ continue
244
+ if not shell_only:
245
+ break
246
+ if stale_script:
247
+ stale_script_overall = True
248
+ if shell_only and stale_script_overall:
249
+ return {"status": "not_running", "running": False, "processes": [], "command": command, "cwd": cwd, "tab_name": tab_name}
250
+ except Exception:
251
+ pass
252
+ return {"status": "running", "running": True, "processes": filtered_active, "command": command, "cwd": cwd, "tab_name": tab_name}
253
+ return {"status": "not_running", "running": False, "processes": [], "command": command, "cwd": cwd, "tab_name": tab_name}
254
+
255
+ except Exception as e:
256
+ logger.error(f"Error checking command status for tab '{tab_name}': {e}")
257
+ return {"status": "error", "error": str(e), "running": False, "command": command, "cwd": cwd, "tab_name": tab_name, "processes": []}
258
+
259
+
260
+ def check_zellij_session_status(session_name: str) -> ZellijSessionStatus:
261
+ """Check if a Zellij session is running."""
262
+ try:
263
+ # Run zellij list-sessions command
264
+ result = subprocess.run(["zellij", "list-sessions"], capture_output=True, text=True, timeout=10)
265
+
266
+ if result.returncode == 0:
267
+ sessions = result.stdout.strip().split("\n") if result.stdout.strip() else []
268
+ session_running = any(session_name in session for session in sessions)
269
+
270
+ return {"zellij_running": True, "session_exists": session_running, "session_name": session_name, "all_sessions": sessions}
271
+ else:
272
+ return {"zellij_running": False, "session_exists": False, "session_name": session_name, "all_sessions": [], "error": result.stderr}
273
+
274
+ except subprocess.TimeoutExpired:
275
+ return {"zellij_running": False, "session_exists": False, "session_name": session_name, "all_sessions": [], "error": "Timeout while checking Zellij sessions"}
276
+ except FileNotFoundError:
277
+ return {"zellij_running": False, "session_exists": False, "session_name": session_name, "all_sessions": [], "error": "Zellij not found in PATH"}
278
+ except Exception as e:
279
+ return {"zellij_running": False, "session_exists": False, "session_name": session_name, "all_sessions": [], "error": str(e)}
280
+
281
+
282
+ def get_layout_preview(layout_config: LayoutConfig, layout_template: str | None) -> str:
283
+ """Generate a preview of the layout configuration."""
284
+ if layout_template is None:
285
+ layout_template = """layout {
286
+ default_tab_template {
287
+ // the default zellij tab-bar and status bar plugins
288
+ pane size=1 borderless=true {
289
+ plugin location="zellij:compact-bar"
290
+ }
291
+ children
292
+ }
293
+ """
294
+ validate_layout_config(layout_config)
295
+ layout_content = layout_template
296
+ for tab in layout_config["layoutTabs"]:
297
+ layout_content += "\n" + create_tab_section(tab)
298
+ return layout_content + "\n}\n"
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env python3
2
+ import subprocess
3
+ import time
4
+ import logging
5
+ from rich.console import Console
6
+
7
+ from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
8
+
9
+
10
+ logger = logging.getLogger(__name__)
11
+ console = Console()
12
+
13
+
14
+ def restart_tab_process(tab_name: str, layout_config: LayoutConfig, session_name: str) -> bool:
15
+ """Restart the process running in a specific Zellij tab without changing the layout.
16
+
17
+ This function will:
18
+ 1. Navigate to the specified tab
19
+ 2. Send Ctrl+C to stop the running process
20
+ 3. Clear the screen
21
+ 4. Re-execute the original command
22
+
23
+ The tab layout and configuration remain unchanged - only the process is restarted.
24
+ """
25
+ if not layout_config:
26
+ logger.error("No layout config available. Cannot restart tab.")
27
+ return False
28
+
29
+ tab_config = None
30
+ for tab in layout_config["layoutTabs"]:
31
+ if tab["tabName"] == tab_name:
32
+ tab_config = tab
33
+ break
34
+
35
+ if tab_config is None:
36
+ logger.error(f"Tab '{tab_name}' not found in layout config.")
37
+ console.print(f"[bold red]❌ Tab '{tab_name}' not found in layout[/bold red]")
38
+ return False
39
+
40
+ command = tab_config.get("command", "")
41
+ if not command:
42
+ logger.warning(f"No command configured for tab '{tab_name}'")
43
+ console.print(f"[bold yellow]⚠️ No command to restart for tab '{tab_name}'[/bold yellow]")
44
+ return False
45
+
46
+ console.print(f"[bold cyan]🔄 Restarting tab[/bold cyan] [yellow]'{tab_name}'[/yellow]")
47
+ console.print(f"[dim]Command: {command}[/dim]")
48
+
49
+ try:
50
+ session_arg = f"--session {session_name}" if session_name else ""
51
+
52
+ subprocess.run(f"zellij {session_arg} action go-to-tab-name '{tab_name}'", shell=True, check=True, capture_output=True, text=True)
53
+ time.sleep(0.5)
54
+
55
+ subprocess.run(f"zellij {session_arg} action write-chars '\\u0003'", shell=True, check=True, capture_output=True, text=True)
56
+ time.sleep(0.3)
57
+
58
+ subprocess.run(f"zellij {session_arg} action write-chars 'clear'", shell=True, check=True, capture_output=True, text=True)
59
+ subprocess.run(f"zellij {session_arg} action write-chars '\\n'", shell=True, check=True, capture_output=True, text=True)
60
+ time.sleep(0.2)
61
+
62
+ escaped_command = command.replace("'", "'\\''")
63
+ subprocess.run(f"zellij {session_arg} action write-chars '{escaped_command}'", shell=True, check=True, capture_output=True, text=True)
64
+ subprocess.run(f"zellij {session_arg} action write-chars '\\n'", shell=True, check=True, capture_output=True, text=True)
65
+
66
+ console.print(f"[bold green]✅ Tab '{tab_name}' restarted successfully[/bold green]")
67
+ return True
68
+
69
+ except subprocess.CalledProcessError as e:
70
+ logger.error(f"Failed to restart tab '{tab_name}': {e}")
71
+ console.print(f"[bold red]❌ Failed to restart tab '{tab_name}'[/bold red]")
72
+ console.print(f"[red]Error: {e}[/red]")
73
+ return False
74
+ except Exception as e:
75
+ logger.error(f"Unexpected error while restarting tab '{tab_name}': {e}")
76
+ console.print(f"[bold red]❌ Unexpected error: {e}[/bold red]")
77
+ return False
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Helper functions for generating Zellij KDL layouts with support for multiple panes per tab.
4
+ This module extends the basic layout functionality to organize multiple commands into panes within a single tab.
5
+ """
6
+ import shlex
7
+ import random
8
+ import string
9
+ import logging
10
+ from pathlib import Path
11
+ from typing import Literal
12
+
13
+ from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig, TabConfig
14
+
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ def generate_random_suffix(length: int) -> str:
20
+ """Generate a random string suffix for unique layout file names."""
21
+ return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
22
+
23
+
24
+ def parse_command(command: str) -> tuple[str, list[str]]:
25
+ """Parse a command string into executable and arguments."""
26
+ try:
27
+ parts = shlex.split(command)
28
+ if not parts:
29
+ raise ValueError("Empty command provided")
30
+ return parts[0], parts[1:] if len(parts) > 1 else []
31
+ except ValueError as e:
32
+ logger.error(f"Error parsing command '{command}': {e}")
33
+ parts = command.split()
34
+ return parts[0] if parts else "", parts[1:] if len(parts) > 1 else []
35
+
36
+
37
+ def format_args_for_kdl(args: list[str]) -> str:
38
+ """Format command arguments for KDL layout format."""
39
+ if not args:
40
+ return ""
41
+ formatted_args = []
42
+ for arg in args:
43
+ if " " in arg or '"' in arg or "'" in arg:
44
+ escaped_arg = arg.replace('"', '\\"')
45
+ formatted_args.append(f'"{escaped_arg}"')
46
+ else:
47
+ formatted_args.append(f'"{arg}"')
48
+ return " ".join(formatted_args)
49
+
50
+
51
+ def create_pane_kdl(tab_config: TabConfig, indent_level: int) -> str:
52
+ """Create a KDL pane definition from a tab configuration."""
53
+ indent = " " * indent_level
54
+ cmd, args = parse_command(tab_config["command"])
55
+ args_str = format_args_for_kdl(args)
56
+ pane_content = f'{indent}pane command="{cmd}" {{\n'
57
+ if args_str:
58
+ pane_content += f'{indent} args {args_str}\n'
59
+ pane_content += f'{indent}}}\n'
60
+ return pane_content
61
+
62
+
63
+ def create_tab_with_panes(
64
+ tab_configs: list[TabConfig],
65
+ tab_name: str,
66
+ common_cwd: str,
67
+ split_direction: Literal["vertical", "horizontal"] = "vertical",
68
+ ) -> str:
69
+ """
70
+ Create a KDL tab section with multiple panes from multiple tab configurations.
71
+
72
+ Args:
73
+ tab_configs: List of TabConfig objects to be organized as panes within one tab
74
+ tab_name: Name for the tab (derived from configs)
75
+ common_cwd: Common working directory for the tab
76
+ split_direction: Direction to split panes ('vertical' or 'horizontal')
77
+
78
+ Returns:
79
+ KDL formatted string for the tab with multiple panes
80
+ """
81
+ escaped_tab_name = tab_name.replace('"', '\\"')
82
+ tab_section = f' tab name="{escaped_tab_name}" cwd="{common_cwd}" {{\n'
83
+ if len(tab_configs) == 1:
84
+ cmd, args = parse_command(tab_configs[0]["command"])
85
+ args_str = format_args_for_kdl(args)
86
+ tab_section += f' pane command="{cmd}" {{\n'
87
+ if args_str:
88
+ tab_section += f" args {args_str}\n"
89
+ tab_section += " }\n"
90
+ else:
91
+ tab_section += f' pane split_direction="{split_direction}" {{\n'
92
+ for config in tab_configs:
93
+ tab_section += create_pane_kdl(config, indent_level=3)
94
+ tab_section += " }\n"
95
+ tab_section += " }\n"
96
+ return tab_section
97
+
98
+
99
+ def generate_tab_name(tab_configs: list[TabConfig], tab_index: int) -> str:
100
+ """
101
+ Generate a meaningful tab name from a list of tab configurations.
102
+
103
+ Args:
104
+ tab_configs: List of TabConfig objects in this tab
105
+ tab_index: Index of the tab (1-based)
106
+
107
+ Returns:
108
+ A descriptive tab name
109
+ """
110
+ if len(tab_configs) == 1:
111
+ return tab_configs[0]["tabName"]
112
+ first_name = tab_configs[0]["tabName"].strip()
113
+ if first_name.startswith("🤖") or first_name.startswith("📊") or first_name.startswith("📝"):
114
+ base_name = first_name[:2]
115
+ return f"{base_name}Group{tab_index}"
116
+ words = first_name.split()
117
+ if words:
118
+ first_word = words[0].strip(":")
119
+ return f"{first_word}×{len(tab_configs)}"
120
+ return f"Tab{tab_index}[{len(tab_configs)}]"
121
+
122
+
123
+ def determine_common_cwd(tab_configs: list[TabConfig]) -> str:
124
+ """
125
+ Determine the common working directory for a group of tab configs.
126
+
127
+ Args:
128
+ tab_configs: List of TabConfig objects
129
+
130
+ Returns:
131
+ The most common directory or the first one if no commonality
132
+ """
133
+ if not tab_configs:
134
+ return "~"
135
+ dirs = [config["startDir"] for config in tab_configs]
136
+ if len(set(dirs)) == 1:
137
+ return dirs[0]
138
+ return dirs[0]
139
+
140
+
141
+ def create_zellij_layout_with_panes(
142
+ layout_config: LayoutConfig,
143
+ output_path: str,
144
+ panes_per_tab: int = 1,
145
+ split_direction: Literal["vertical", "horizontal"] = "vertical",
146
+ ) -> str:
147
+ """
148
+ Create a Zellij KDL layout file with support for multiple panes per tab.
149
+
150
+ Args:
151
+ layout_config: The LayoutConfig object containing all tabs/commands
152
+ panes_per_tab: Number of panes to group into each tab (default: 1 = same as original behavior)
153
+ split_direction: Direction to split panes within a tab ('vertical' or 'horizontal')
154
+ output_path: Path to save the layout file (directory or full file path)
155
+
156
+ Returns:
157
+ Absolute path to the created layout file
158
+
159
+ Example:
160
+ >>> layout = {"layoutName": "MyLayout", "layoutTabs": [...]}
161
+ >>> path = create_zellij_layout_with_panes(layout, panes_per_tab=2, split_direction="vertical", output_path="/tmp/layout.kdl")
162
+ """
163
+ if panes_per_tab < 1:
164
+ raise ValueError("panes_per_tab must be at least 1")
165
+ layout_tabs = layout_config["layoutTabs"]
166
+ if not layout_tabs:
167
+ raise ValueError("Layout must contain at least one tab")
168
+ layout_template = """layout {
169
+ default_tab_template {
170
+ // the default zellij tab-bar and status bar plugins
171
+ pane size=1 borderless=true {
172
+ plugin location="zellij:compact-bar"
173
+ }
174
+ children
175
+ }
176
+ """
177
+ layout_content = layout_template
178
+ grouped_tabs: list[list[TabConfig]] = []
179
+ for i in range(0, len(layout_tabs), panes_per_tab):
180
+ group = layout_tabs[i : i + panes_per_tab]
181
+ grouped_tabs.append(group)
182
+ for tab_index, group in enumerate(grouped_tabs, start=1):
183
+ tab_name = generate_tab_name(group, tab_index)
184
+ common_cwd = determine_common_cwd(group)
185
+ layout_content += "\n" + create_tab_with_panes(group, tab_name, common_cwd, split_direction)
186
+ layout_content += "\n}\n"
187
+ try:
188
+ path_obj = Path(output_path)
189
+ if path_obj.is_dir():
190
+ raise ValueError("Output path must be a file path ending with .kdl, not a directory")
191
+ if path_obj.suffix == ".kdl":
192
+ layout_file = path_obj
193
+ layout_file.parent.mkdir(parents=True, exist_ok=True)
194
+ else:
195
+ raise ValueError("Output path must end with .kdl")
196
+ layout_file.write_text(layout_content, encoding="utf-8")
197
+ logger.info(f"Created Zellij layout file: {layout_file.absolute()}")
198
+ return str(layout_file.absolute())
199
+ except OSError as e:
200
+ logger.error(f"Failed to create layout file: {e}")
201
+ raise
202
+
203
+
204
+ if __name__ == "__main__":
205
+ sample_layout: LayoutConfig = {
206
+ "layoutName": "TestMultiPane",
207
+ "layoutTabs": [
208
+ {"tabName": "🤖Bot1", "startDir": "~/code/project1", "command": "python bot1.py"},
209
+ {"tabName": "🤖Bot2", "startDir": "~/code/project1", "command": "python bot2.py"},
210
+ {"tabName": "🤖Bot3", "startDir": "~/code/project1", "command": "python bot3.py"},
211
+ {"tabName": "🤖Bot4", "startDir": "~/code/project2", "command": "python bot4.py"},
212
+ {"tabName": "📊Monitor", "startDir": "~", "command": "htop"},
213
+ {"tabName": "📝Logs", "startDir": "/var/log", "command": "tail -f /var/log/app.log"},
214
+ ],
215
+ }
216
+ print("=" * 80)
217
+ print("DEMO 1: panes_per_tab=1 (same as original behavior)")
218
+ print("=" * 80)
219
+ layout_path_1 = create_zellij_layout_with_panes(sample_layout, "/tmp/zellij_test_123.kdl", panes_per_tab=1)
220
+ print(f"✅ Layout created: {layout_path_1}")
221
+ layout_path_2 = create_zellij_layout_with_panes(layout_config=sample_layout, output_path="/tmp/zellij_test_1234.kdl", panes_per_tab=2, split_direction="vertical")
222
+ print(f"✅ Layout created: {layout_path_2}")
223
+ print("DEMO 3: panes_per_tab=3 (three panes per tab, horizontal split)")
224
+ layout_path_3 = create_zellij_layout_with_panes(layout_config=sample_layout, output_path="/tmp/zellij_test_12345.kdl", panes_per_tab=3, split_direction="horizontal")
225
+ print(f"✅ Layout created: {layout_path_3}")
226
+
227
+ from machineconfig.cluster.sessions_managers.helpers.enhanced_command_runner import enhanced_zellij_session_start
228
+ enhanced_zellij_session_start(session_name="tmp", layout_path=layout_path_3)