machineconfig 7.64__py3-none-any.whl → 7.83__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 (104) hide show
  1. machineconfig/cluster/sessions_managers/utils/maker.py +4 -2
  2. machineconfig/jobs/installer/custom/yazi.py +120 -0
  3. machineconfig/jobs/installer/custom_dev/nerdfont.py +1 -1
  4. machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +26 -12
  5. machineconfig/jobs/installer/custom_dev/sysabc.py +26 -5
  6. machineconfig/jobs/installer/installer_data.json +232 -96
  7. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  8. machineconfig/profile/create_helper.py +0 -12
  9. machineconfig/profile/create_links_export.py +2 -2
  10. machineconfig/profile/mapper.toml +2 -2
  11. machineconfig/scripts/__init__.py +0 -4
  12. machineconfig/scripts/python/agents.py +22 -17
  13. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +4 -0
  14. machineconfig/scripts/python/croshell.py +22 -17
  15. machineconfig/scripts/python/devops.py +1 -1
  16. machineconfig/scripts/python/devops_navigator.py +0 -4
  17. machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
  18. machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
  19. machineconfig/scripts/python/fire_jobs.py +13 -13
  20. machineconfig/scripts/python/ftpx.py +36 -12
  21. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  22. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  23. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  24. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  25. machineconfig/scripts/python/helpers_cloud/cloud_copy.py +28 -21
  26. machineconfig/scripts/python/helpers_cloud/cloud_helpers.py +1 -1
  27. machineconfig/scripts/python/helpers_cloud/cloud_mount.py +19 -17
  28. machineconfig/scripts/python/helpers_cloud/cloud_sync.py +8 -7
  29. machineconfig/scripts/python/helpers_croshell/start_slidev.py +6 -7
  30. machineconfig/scripts/python/helpers_devops/cli_config.py +10 -0
  31. machineconfig/scripts/python/helpers_devops/cli_nw.py +90 -10
  32. machineconfig/scripts/python/helpers_devops/cli_self.py +8 -7
  33. machineconfig/scripts/python/helpers_devops/cli_share_file.py +7 -7
  34. machineconfig/scripts/python/helpers_devops/cli_share_server.py +12 -11
  35. machineconfig/scripts/python/helpers_devops/cli_terminal.py +8 -10
  36. machineconfig/scripts/python/helpers_devops/cli_utils.py +2 -1
  37. machineconfig/scripts/python/helpers_devops/devops_status.py +7 -19
  38. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +20 -9
  39. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfg +2 -2
  40. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +58 -1
  41. machineconfig/scripts/python/helpers_navigator/command_tree.py +50 -18
  42. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +5 -3
  43. machineconfig/scripts/python/helpers_repos/count_lines.py +40 -11
  44. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +1 -1
  45. machineconfig/scripts/python/helpers_utils/download.py +4 -3
  46. machineconfig/scripts/python/helpers_utils/path.py +87 -34
  47. machineconfig/scripts/python/interactive.py +1 -1
  48. machineconfig/scripts/python/{machineconfig.py → mcfg_entry.py} +4 -0
  49. machineconfig/scripts/python/msearch.py +55 -6
  50. machineconfig/scripts/python/nw/address.py +132 -0
  51. machineconfig/scripts/python/nw/devops_add_ssh_key.py +8 -5
  52. machineconfig/scripts/python/terminal.py +2 -2
  53. machineconfig/scripts/python/utils.py +12 -11
  54. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
  55. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  56. machineconfig/settings/shells/nushell/config.nu +2 -2
  57. machineconfig/settings/shells/nushell/env.nu +45 -6
  58. machineconfig/settings/shells/nushell/init.nu +282 -95
  59. machineconfig/settings/shells/pwsh/init.ps1 +1 -0
  60. machineconfig/settings/yazi/init.lua +4 -0
  61. machineconfig/settings/yazi/keymap_linux.toml +11 -4
  62. machineconfig/settings/yazi/theme.toml +4 -0
  63. machineconfig/settings/yazi/yazi_linux.toml +84 -0
  64. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  65. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  66. machineconfig/setup_windows/uv.ps1 +8 -1
  67. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +10 -10
  68. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -2
  69. machineconfig/utils/accessories.py +7 -4
  70. machineconfig/utils/code.py +4 -2
  71. machineconfig/utils/installer_utils/github_release_bulk.py +104 -62
  72. machineconfig/utils/installer_utils/install_from_url.py +200 -0
  73. machineconfig/utils/installer_utils/installer_class.py +25 -74
  74. machineconfig/utils/installer_utils/installer_cli.py +40 -50
  75. machineconfig/utils/installer_utils/installer_helper.py +100 -0
  76. machineconfig/utils/installer_utils/installer_runner.py +5 -8
  77. machineconfig/utils/links.py +2 -2
  78. machineconfig/utils/meta.py +2 -2
  79. machineconfig/utils/options.py +3 -3
  80. machineconfig/utils/path_extended.py +1 -1
  81. machineconfig/utils/path_helper.py +0 -1
  82. machineconfig/utils/ssh.py +143 -409
  83. machineconfig/utils/ssh_utils/abc.py +8 -0
  84. machineconfig/utils/ssh_utils/copy_from_here.py +110 -0
  85. machineconfig/utils/ssh_utils/copy_to_here.py +302 -0
  86. machineconfig/utils/ssh_utils/utils.py +141 -0
  87. machineconfig/utils/ssh_utils/wsl.py +210 -0
  88. machineconfig/utils/upgrade_packages.py +2 -1
  89. machineconfig/utils/ve.py +11 -4
  90. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/METADATA +2 -2
  91. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/RECORD +96 -89
  92. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/entry_points.txt +2 -2
  93. machineconfig/scripts/python/explore.py +0 -49
  94. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfag +0 -17
  95. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfrga +0 -21
  96. machineconfig/scripts/python/helpers_msearch/scripts_linux/skrg +0 -4
  97. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfb.ps1 +0 -3
  98. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfrga.bat +0 -20
  99. machineconfig/settings/yazi/yazi.toml +0 -17
  100. machineconfig/setup_linux/others/cli_installation.sh +0 -137
  101. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_fire_command/f.py} +0 -0
  102. /machineconfig/scripts/{Restore-ThunderbirdProfile.ps1 → windows/mounts/Restore-ThunderbirdProfile.ps1} +0 -0
  103. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/WHEEL +0 -0
  104. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/top_level.txt +0 -0
@@ -34,13 +34,63 @@ def add_ssh_identity():
34
34
  helper.main()
35
35
 
36
36
 
37
- def show_address():
38
- import socket
39
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
40
- s.connect(('8.8.8.8',80))
41
- local_ip_v4 = s.getsockname()[0]
42
- s.close()
43
- print(f"This computer is @ {local_ip_v4}")
37
+ def show_address() -> None:
38
+ """📌 Show this computer addresses on network"""
39
+ from machineconfig.utils.installer_utils.installer_cli import install_if_missing
40
+ import subprocess
41
+ install_if_missing("ipinfo")
42
+ result = subprocess.run(
43
+ ["ipinfo", "myip", "--json"],
44
+ check=True,
45
+ capture_output=True,
46
+ text=True,
47
+ encoding="utf-8",
48
+ )
49
+ import json
50
+ loaded_json = json.loads(result.stdout)
51
+ from rich import print_json
52
+ print_json(data=loaded_json)
53
+
54
+ import machineconfig.scripts.python.nw.address as helper
55
+ from rich.table import Table
56
+ from rich.console import Console
57
+ res = helper.get_all_ipv4_addresses()
58
+ res.append( ("Public IP", loaded_json.get("ip", "N/A")))
59
+
60
+ # loc = loaded_json["loc"]
61
+ # cmd = f"""curl "https://maps.geoapify.com/v1/staticmap?style=osm-bright&width=600&height=300&center=lonlat:{loc}&zoom=6&marker=lonlat:{loc};color:%23ff0000;size:medium&apiKey=$GEOAPIFY_API_KEY" -o map.png && chafa map.png"""
62
+ # from machineconfig.utils.code import run_shell_script
63
+ # run_shell_script(script=cmd)
64
+
65
+ table = Table(title="Network Interfaces")
66
+ table.add_column("Interface", style="cyan")
67
+ table.add_column("IP Address", style="green")
68
+
69
+ for iface, ip in res:
70
+ table.add_row(iface, ip)
71
+
72
+ console = Console()
73
+ console.print(table)
74
+
75
+ res = helper.select_lan_ipv4(prefer_vpn=False)
76
+ if res is not None:
77
+ # ip, iface = res
78
+ # print(f"Selected IP: {ip} on interface: {iface}")
79
+ print(f"LAN IPv4: {res}")
80
+ else:
81
+ print("No network interfaces found.")
82
+
83
+
84
+
85
+ def bind_wsl_port(port: Annotated[int, typer.Option(..., "--port", "-p", help="Port number to bind")]):
86
+ code = f"""
87
+
88
+ $wsl_ip = (wsl.exe hostname -I).Trim().Split(' ')[0]
89
+ netsh interface portproxy add v4tov4 listenport={port} listenaddress=0.0.0.0 connectport={port} connectaddress=$wsl_ip
90
+
91
+ """
92
+ from machineconfig.utils.code import exit_then_run_shell_script
93
+ exit_then_run_shell_script(code)
44
94
 
45
95
 
46
96
  def debug_ssh():
@@ -101,10 +151,32 @@ def wifi_select(
101
151
  console.print("[blue]👋 Goodbye![/blue]")
102
152
 
103
153
 
154
+
155
+ def reset_cloudflare_tunnel():
156
+ code = """
157
+ # cloudflared tunnel route dns glenn # creates CNAMES in Cloudflare dashboard
158
+ # sudo systemctl stop cloudflared
159
+ # test: cloudflared tunnel run glenn
160
+ home_dir=$HOME
161
+ cloudflared_path="$home_dir/.local/bin/cloudflared"
162
+ sudo $cloudflared_path service uninstall
163
+ sudo rm /etc/cloudflared/config.yml || true
164
+ sudo $cloudflared_path --config $home_dir/.cloudflared/config.yml service install
165
+ """
166
+ print(code)
167
+ def add_ip_exclusion_to_warp(ip: Annotated[str, typer.Option(..., "--ip", help="IP address to exclude from WARP")]):
168
+ code = f"""
169
+ sudo warp-cli tunnel ip add {ip}
170
+ sudo warp-cli disconnect
171
+ sudo warp-cli connect
172
+ """
173
+ print(code)
174
+
175
+
104
176
  def get_app():
105
177
  nw_apps = typer.Typer(help="🔐 [n] Network subcommands", no_args_is_help=True, add_help_option=False, add_completion=False)
106
- nw_apps.command(name="share-terminal", help="📡 [t] Share terminal via web browser")(cli_terminal.main)
107
- nw_apps.command(name="t", help="Share terminal via web browser", hidden=True)(cli_terminal.main)
178
+ nw_apps.command(name="share-terminal", help="📡 [t] Share terminal via web browser")(cli_terminal.share_terminal)
179
+ nw_apps.command(name="t", help="Share terminal via web browser", hidden=True)(cli_terminal.share_terminal)
108
180
 
109
181
  nw_apps.command(name="share-server", help="🌐 [s] Start local/global server to share files/folders via web browser", no_args_is_help=True)(cli_share_server.web_file_explorer)
110
182
  nw_apps.command(name="s", help="Start local/global server to share files/folders via web browser", hidden=True, no_args_is_help=True)(cli_share_server.web_file_explorer)
@@ -128,7 +200,15 @@ def get_app():
128
200
  nw_apps.command(name="debug-ssh", help="🐛 [d] Debug SSH connection")(debug_ssh)
129
201
  nw_apps.command(name="d", help="Debug SSH connection", hidden=True)(debug_ssh)
130
202
 
131
- nw_apps.command(name="wifi-select", no_args_is_help=True, help="📶 WiFi connection utility.")(wifi_select)
203
+ nw_apps.command(name="wifi-select", no_args_is_help=True, help="📶 [w] WiFi connection utility.")(wifi_select)
132
204
  nw_apps.command(name="w", no_args_is_help=True, hidden=True)(wifi_select)
133
205
 
206
+ nw_apps.command(name="bind-wsl-port", help="🔌 [b] Bind WSL port to Windows host", no_args_is_help=True)(bind_wsl_port)
207
+ nw_apps.command(name="b", help="Bind WSL port to Windows host", hidden=True, no_args_is_help=True)(bind_wsl_port)
208
+
209
+ nw_apps.command(name="reset-cloudflare-tunnel", help="☁️ [r] Reset Cloudflare tunnel service")(reset_cloudflare_tunnel)
210
+ nw_apps.command(name="r", help="Reset Cloudflare tunnel service", hidden=True)(reset_cloudflare_tunnel)
211
+ nw_apps.command(name="add-ip-exclusion-to-warp", help="🚫 [p] Add IP exclusion to WARP")(add_ip_exclusion_to_warp)
212
+ nw_apps.command(name="p", help="Add IP exclusion to WARP", hidden=True)(add_ip_exclusion_to_warp)
213
+
134
214
  return nw_apps
@@ -30,7 +30,8 @@ uv tool install --upgrade machineconfig
30
30
  if platform.system() == "Windows":
31
31
  from machineconfig.utils.code import exit_then_run_shell_script, get_uv_command_executing_python_script
32
32
  from machineconfig.utils.meta import lambda_to_python_script
33
- python_script = lambda_to_python_script(lambda: copy_both_assets(), in_global=True, import_module=False)
33
+ python_script = lambda_to_python_script(lambda: copy_both_assets(),
34
+ in_global=True, import_module=False)
34
35
  uv_command, _py_file = get_uv_command_executing_python_script(python_script=python_script, uv_with=["machineconfig"], uv_project_dir=None)
35
36
  exit_then_run_shell_script(shell_script + "\n" + uv_command, strict=True)
36
37
  else:
@@ -48,13 +49,13 @@ def install(no_copy_assets: Annotated[bool, typer.Option("--no-assets-copy", "-n
48
49
  from machineconfig.utils.code import run_shell_script
49
50
  from pathlib import Path
50
51
  if Path.home().joinpath("code/machineconfig").exists():
51
- run_shell_script(f"""$HOME/.local/bin/uv tool install --upgrade --editable "{str(Path.home().joinpath("code/machineconfig"))}" """)
52
+ run_shell_script(f""" "$HOME/.local/bin/uv" tool install --upgrade --editable "{str(Path.home().joinpath("code/machineconfig"))}" """)
52
53
  else:
53
54
  import platform
54
55
  if platform.system() == "Windows":
55
- run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=7.64" """)
56
+ run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=7.83" """)
56
57
  else:
57
- run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=7.64" """)
58
+ run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=7.83" """)
58
59
  from machineconfig.profile.create_shell_profile import create_default_shell_profile
59
60
  if not no_copy_assets:
60
61
  create_default_shell_profile() # involves copying assets too
@@ -77,10 +78,10 @@ def navigate():
77
78
  import machineconfig.scripts.python as navigator
78
79
  from pathlib import Path
79
80
  path = Path(navigator.__file__).resolve().parent.joinpath("devops_navigator.py")
80
- from machineconfig.utils.code import run_shell_script
81
+ from machineconfig.utils.code import exit_then_run_shell_script
81
82
  if Path.home().joinpath("code/machineconfig").exists(): executable = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" --with textual"""
82
- else: executable = """--with "machineconfig>=7.64,textual" """
83
- run_shell_script(f"""uv run {executable} {path}""")
83
+ else: executable = """--with "machineconfig>=7.83,textual" """
84
+ exit_then_run_shell_script(f"""uv run {executable} {path}""")
84
85
 
85
86
 
86
87
  def run_python(ip: Annotated[str, typer.Argument(..., help="Python command to run in the machineconfig environment")],
@@ -1,6 +1,5 @@
1
+
1
2
  import typer
2
- # import platform
3
- # import sys
4
3
  from typing import Annotated
5
4
 
6
5
 
@@ -103,12 +102,13 @@ def share_file_send(path: Annotated[str, typer.Argument(help="Path to the file o
103
102
  from machineconfig.utils.installer_utils.installer_cli import install_if_missing
104
103
  install_if_missing(which="croc")
105
104
  # Get relay server IP from environment or use default
106
- import socket
105
+ import machineconfig.scripts.python.nw.address as helper
106
+ res = helper.select_lan_ipv4(prefer_vpn=False)
107
+ if res is None:
108
+ typer.echo("❌ Error: Could not determine local LAN IPv4 address for relay.", err=True)
109
+ raise typer.Exit(code=1)
110
+ local_ip_v4 = res
107
111
  import platform
108
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
109
- s.connect(('8.8.8.8',80))
110
- local_ip_v4 = s.getsockname()[0]
111
- s.close()
112
112
  relay_port = "443"
113
113
  is_windows = platform.system() == "Windows"
114
114
 
@@ -38,18 +38,16 @@ def web_file_explorer(
38
38
  username: Annotated[Optional[str], typer.Option("--username", "-u", help="Username for share access (default: current user)")] = None,
39
39
  password: Annotated[Optional[str], typer.Option("--password", "-w", help="Password for share access (default: from ~/dotfiles/creds/passwords/quick_password)")] = None,
40
40
  over_internet: Annotated[bool, typer.Option("--over-internet", "-i", help="Expose the share server over the internet using ngrok")] = False,
41
- backend: Annotated[str, typer.Option("--backend", "-b", help="Backend to use: filebrowser (default), miniserve, or easy-sharing")] = "filebrowser"
41
+ backend: Annotated[str, typer.Option("--backend", "-b", help="Backend to use: filebrowser (default), miniserve, qrcp, or easy-sharing")] = "miniserve",
42
42
  ) -> None:
43
43
  from machineconfig.utils.installer_utils.installer_cli import install_if_missing
44
-
45
- if backend not in ["filebrowser", "miniserve", "easy-sharing"]:
46
- typer.echo(f"❌ ERROR: Invalid backend '{backend}'. Must be one of: filebrowser, miniserve, easy-sharing", err=True)
44
+
45
+ if backend not in ["filebrowser", "miniserve", "qrcp", "easy-sharing"]:
46
+ typer.echo(f"❌ ERROR: Invalid backend '{backend}'. Must be one of: filebrowser, miniserve, qrcp, easy-sharing", err=True)
47
47
  raise typer.Exit(code=1)
48
-
49
48
  install_if_missing(which=backend)
50
49
  if over_internet:
51
50
  install_if_missing(which="ngrok")
52
-
53
51
  if username is None:
54
52
  import getpass
55
53
  username = getpass.getuser()
@@ -65,11 +63,12 @@ def web_file_explorer(
65
63
  if port is None:
66
64
  port = 8080
67
65
 
68
- import socket
69
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
70
- s.connect(('8.8.8.8', 80))
71
- local_ip_v4 = s.getsockname()[0]
72
- s.close()
66
+ import machineconfig.scripts.python.nw.address as helper
67
+ res = helper.select_lan_ipv4(prefer_vpn=False)
68
+ if res is None:
69
+ typer.echo("❌ ERROR: Could not determine local LAN IPv4 address for share server.", err=True)
70
+ raise typer.Exit(code=1)
71
+ local_ip_v4 = res
73
72
 
74
73
  protocol = "http"
75
74
  display_share_url(local_ip_v4, port, protocol)
@@ -90,6 +89,8 @@ filebrowser --address 0.0.0.0 --port {port} --root "{path_obj}" --database {db_p
90
89
  command = f"""miniserve --port {port} --interfaces 0.0.0.0 --auth {username}:{password} --upload-files --mkdir --enable-tar --enable-tar-gz --enable-zip --qrcode "{path_obj}" """
91
90
  elif backend == "easy-sharing":
92
91
  command = f"""easy-sharing --port {port} --username {username} --password "{password}" "{path_obj}" """
92
+ elif backend == "qrcp":
93
+ command = f"""qrcp "{path_obj}" """
93
94
  else:
94
95
  typer.echo(f"❌ ERROR: Unknown backend '{backend}'", err=True)
95
96
  raise typer.Exit(code=1)
@@ -17,13 +17,11 @@ reference:
17
17
 
18
18
  def display_terminal_url(local_ip_v4: str, port: int, protocol: str = "http") -> None:
19
19
  """Display a flashy, unmissable terminal URL announcement."""
20
-
21
20
  from rich.console import Console
22
21
  from rich.panel import Panel
23
22
  from rich.text import Text
24
23
  from rich.align import Align
25
24
  console = Console()
26
-
27
25
  # Create the main message with styling
28
26
  url_text = Text(f"{protocol}://{local_ip_v4}:{port}", style="bold bright_cyan underline")
29
27
  message = Text.assemble(
@@ -42,14 +40,13 @@ def display_terminal_url(local_ip_v4: str, port: int, protocol: str = "http") ->
42
40
  padding=(1, 2),
43
41
  expand=False
44
42
  )
45
-
46
43
  # Print with extra spacing and attention-grabbing elements
47
44
  # console.print("\n" + "🔥" * 60 + "\n", style="bright_red bold")
48
45
  console.print(panel)
49
46
  # console.print("🔥" * 60 + "\n", style="bright_red bold")
50
47
 
51
48
 
52
- def main(
49
+ def share_terminal(
53
50
  port: Annotated[Optional[int], typer.Option("--port", "-p", help="Port to run the terminal server on (default: 7681)")] = None,
54
51
  username: Annotated[Optional[str], typer.Option("--username", "-u", help="Username for terminal access (default: current user)")] = None,
55
52
  password: Annotated[Optional[str], typer.Option("--password", "-w", help="Password for terminal access (default: from ~/dotfiles/creds/passwords/quick_password)")] = None,
@@ -96,11 +93,12 @@ def main(
96
93
  if ssl_ca and not Path(ssl_ca).exists():
97
94
  raise FileNotFoundError(f"SSL CA file not found: {ssl_ca}")
98
95
 
99
- import socket
100
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
101
- s.connect(('8.8.8.8',80))
102
- local_ip_v4 = s.getsockname()[0]
103
- s.close()
96
+ import machineconfig.scripts.python.nw.address as helper
97
+ res = helper.select_lan_ipv4(prefer_vpn=False)
98
+ if res is None:
99
+ print("❌ Error: Could not determine local LAN IPv4 address for terminal.")
100
+ raise typer.Exit(code=1)
101
+ local_ip_v4 = res
104
102
 
105
103
  # Display the flashy terminal announcement
106
104
  protocol = "https" if ssl else "http"
@@ -149,7 +147,7 @@ def main(
149
147
 
150
148
 
151
149
  def main_with_parser():
152
- typer.run(main)
150
+ typer.run(share_terminal)
153
151
 
154
152
 
155
153
  if __name__ == "__main__":
@@ -36,7 +36,8 @@ def merge_pdfs(
36
36
  writer.write(output_path)
37
37
  print(f"✅ Merged PDF saved to: {output_path}")
38
38
  from machineconfig.utils.meta import lambda_to_python_script
39
- code = lambda_to_python_script(lambda : merge_pdfs_internal(pdfs=pdfs, output=output, compress=compress), in_global=True, import_module=False)
39
+ code = lambda_to_python_script(lambda : merge_pdfs_internal(pdfs=pdfs, output=output, compress=compress),
40
+ in_global=True, import_module=False)
40
41
  from machineconfig.utils.code import run_shell_script, get_uv_command_executing_python_script
41
42
  uv_command, _py_file = get_uv_command_executing_python_script(python_script=code, uv_with=["pypdf"], uv_project_dir=None)
42
43
  run_shell_script(uv_command)
@@ -17,22 +17,6 @@ from machineconfig.utils.source_of_truth import CONFIG_ROOT, DEFAULTS_PATH, LIBR
17
17
  console = Console()
18
18
 
19
19
 
20
- def _check_system_info() -> dict[str, str]:
21
- """Gather basic system information."""
22
- import socket
23
- import os
24
-
25
- return {
26
- "hostname": socket.gethostname(),
27
- "system": platform.system(),
28
- "release": platform.release(),
29
- "version": platform.version(),
30
- "machine": platform.machine(),
31
- "processor": platform.processor() or "Unknown",
32
- "python_version": platform.python_version(),
33
- "user": os.getenv("USER") or os.getenv("USERNAME") or "Unknown",
34
- }
35
-
36
20
 
37
21
  def _check_shell_profile_status() -> dict[str, Any]:
38
22
  """Check shell profile configuration status."""
@@ -480,10 +464,14 @@ def main() -> None:
480
464
  console.print("\n")
481
465
  console.print(Panel(Text("📊 Machine Status Report", justify="center", style="bold white"), style="bold blue", padding=(1, 2)))
482
466
  console.print("\n")
483
-
484
- system_info = _check_system_info()
467
+
468
+ # system_info = _check_system_info()
469
+ # from machineconfig.scripts.python.helpers_devops.devops_system_info import _check_system_info
470
+ from machineconfig.scripts.python.helpers_utils.path import get_machine_specs
471
+ system_info = get_machine_specs()
472
+ from typing import cast
473
+ system_info = cast(dict[str, str], system_info)
485
474
  _display_system_info(system_info)
486
-
487
475
  shell_status = _check_shell_profile_status()
488
476
  _display_shell_status(shell_status)
489
477
 
@@ -54,15 +54,13 @@ def choose_function_or_lines(choice_file: Path, kwargs_dict: dict[str, object])
54
54
 
55
55
 
56
56
  def get_command_streamlit(choice_file: Path, environment: str, repo_root: Optional[Path]) -> str:
57
- import socket
58
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
59
- try:
60
- s.connect(("8.8.8.8", 1))
61
- local_ip_v4 = s.getsockname()[0]
62
- except Exception:
63
- local_ip_v4 = socket.gethostbyname(socket.gethostname())
64
- finally:
65
- s.close()
57
+ # from machineconfig.scripts.python.helpers_utils.path import get_machine_specs
58
+ from machineconfig.scripts.python.nw.address import select_lan_ipv4
59
+ res = select_lan_ipv4(prefer_vpn=False)
60
+ if res is None:
61
+ raise RuntimeError("Could not determine local LAN IPv4 address for streamlit app.")
62
+ local_ip_v4 = res
63
+
66
64
  computer_name = platform.node()
67
65
  port = 8501
68
66
  toml_path: Optional[Path] = None
@@ -100,6 +98,19 @@ def get_command_streamlit(choice_file: Path, environment: str, repo_root: Option
100
98
  except Exception as ex:
101
99
  print(ex)
102
100
  raise ex
101
+ from machineconfig.utils.installer_utils.installer_cli import install_if_missing
102
+ install_if_missing("qrterminal")
103
+ script = f"""
104
+ qrterminal "http://{local_ip_v4}:{port}"
105
+ echo "http://{local_ip_v4}:{port}"
106
+ qrterminal "http://{computer_name}:{port}"
107
+ echo "http://{computer_name}:{port}"
108
+ """
109
+ # from machineconfig.utils.code import run_shell_script
110
+ # run_shell_script(script)
111
+ from machineconfig.utils.code import print_code
112
+ print_code(code=script, lexer="shell", desc="Streamlit QR Codes and URLs")
113
+
103
114
  message = f"🚀 Streamlit app is running @:\n1- http://{local_ip_v4}:{port}\n2- http://{computer_name}:{port}\n3- http://localhost:{port}"
104
115
  from rich.panel import Panel
105
116
  from rich import print as rprint
@@ -13,9 +13,9 @@ IFS=: read -ra selected < <(
13
13
  --bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
14
14
  --bind "ctrl-f:unbind(change,ctrl-f)+change-prompt(2. fzf> )+enable-search+clear-query+rebind(ctrl-r)" \
15
15
  --bind "ctrl-r:unbind(ctrl-r)+change-prompt(1. ripgrep> )+disable-search+reload($RG_PREFIX {q} || true)+rebind(change,ctrl-f)" \
16
- --prompt '1. Ripgrep> ' \
16
+ --prompt '1. ripgrep> ' \
17
17
  --delimiter : \
18
- --header '╱ CTRL-R (Ripgrep mode) ╱ CTRL-F (fzf mode) ╱' \
18
+ --header '╱ CTRL-R (ripgrep mode) ╱ CTRL-F (fzf mode) ╱' \
19
19
  --preview 'bat --color=always {1} --highlight-line {2}' \
20
20
  --preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
21
21
  )
@@ -1,2 +1,59 @@
1
+ #!/usr/bin/env pwsh
2
+ [CmdletBinding()]
3
+ param(
4
+ [Parameter(ValueFromRemainingArguments = $true)]
5
+ [string[]]$QueryTokens
6
+ )
1
7
 
2
- Invoke-PsFzfRipgrep $args
8
+ if ($null -eq $QueryTokens) {
9
+ $QueryTokens = @()
10
+ }
11
+
12
+ $initialQuery = if ($QueryTokens.Count -gt 0) { [string]::Join(' ', $QueryTokens) } else { '' }
13
+ $rgPrefix = 'rg --column --line-number --no-heading --color=always --smart-case '
14
+
15
+ $escapedDefault = if ($initialQuery.Length -gt 0) {
16
+ $rgPrefix + '"' + $initialQuery.Replace('"', '""') + '" || type nul'
17
+ } else {
18
+ 'type nul'
19
+ }
20
+
21
+ $previousDefault = $env:FZF_DEFAULT_COMMAND
22
+ $env:FZF_DEFAULT_COMMAND = $escapedDefault
23
+
24
+ $reloadBinding = "change:reload:$rgPrefix{q} || type nul"
25
+ $ctrlFBinding = 'ctrl-f:unbind(change,ctrl-f)+change-prompt(2. fzf> )+enable-search+clear-query+rebind(ctrl-r)'
26
+ $ctrlRBinding = "ctrl-r:unbind(ctrl-r)+change-prompt(1. ripgrep> )+disable-search+reload($rgPrefix{q} || type nul)+rebind(change,ctrl-f)"
27
+
28
+ try {
29
+ $selectionRaw = & fzf --ansi `
30
+ --color 'hl:-1:underline,hl+:-1:underline:reverse' `
31
+ --disabled `
32
+ --query $initialQuery `
33
+ --bind $reloadBinding `
34
+ --bind $ctrlFBinding `
35
+ --bind $ctrlRBinding `
36
+ --prompt '1. ripgrep> ' `
37
+ --delimiter ':' `
38
+ --header 'CTRL-R (ripgrep mode) | CTRL-F (fzf mode)' `
39
+ --preview 'bat --color=always {1} --highlight-line {2}' `
40
+ --preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
41
+ }
42
+ finally {
43
+ if ($null -ne $previousDefault) {
44
+ $env:FZF_DEFAULT_COMMAND = $previousDefault
45
+ } else {
46
+ Remove-Item Env:FZF_DEFAULT_COMMAND -ErrorAction SilentlyContinue
47
+ }
48
+ }
49
+
50
+ if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($selectionRaw)) {
51
+ exit
52
+ }
53
+
54
+ if ($selectionRaw -match '^(?<path>.+?):(?<line>\d+):(?<column>\d+):') {
55
+ $path = $Matches['path']
56
+ $line = [int]$Matches['line']
57
+ $column = [int]$Matches['column']
58
+ & hx ("{0}:{1}:{2}" -f $path,$line,$column)
59
+ }
@@ -188,15 +188,7 @@ class CommandTree(Tree[CommandInfo]):
188
188
  description="Configure your shell profile",
189
189
  command="devops config shell",
190
190
  parent="config",
191
- help_text="devops config shell <copy|reference>"
192
- ))
193
-
194
- config_node.add("🔗 path - Navigate PATH variable", data=CommandInfo(
195
- name="path",
196
- description="Navigate PATH variable with TUI",
197
- command="devops config path",
198
- parent="config",
199
- help_text="devops config path"
191
+ help_text="devops config shell --which <default|nushell>"
200
192
  ))
201
193
 
202
194
  config_node.add("🔗 starship-theme - Select starship theme", data=CommandInfo(
@@ -560,7 +552,23 @@ class CommandTree(Tree[CommandInfo]):
560
552
  description="Choose a process to kill interactively",
561
553
  command="utils kill-process",
562
554
  parent="utils",
563
- help_text="utils kill-process"
555
+ help_text="utils kill-process --interactive"
556
+ ))
557
+
558
+ utils_node.add("📚 path - Navigate PATH variable", data=CommandInfo(
559
+ name="path",
560
+ description="Navigate PATH variable with TUI",
561
+ command="utils path",
562
+ parent="utils",
563
+ help_text="utils path"
564
+ ))
565
+
566
+ utils_node.add("⬆️ upgrade-packages - Upgrade dependencies", data=CommandInfo(
567
+ name="upgrade-packages",
568
+ description="Upgrade project dependencies",
569
+ command="utils upgrade-packages",
570
+ parent="utils",
571
+ help_text="utils upgrade-packages"
564
572
  ))
565
573
 
566
574
  utils_node.add("⬇️ download - Download file", data=CommandInfo(
@@ -571,18 +579,42 @@ class CommandTree(Tree[CommandInfo]):
571
579
  help_text="utils download <url> --destination <path> --decompress"
572
580
  ))
573
581
 
574
- utils_node.add("📄 merge-pdfs - Merge PDF files", data=CommandInfo(
575
- name="merge-pdfs",
576
- description="Merge two PDF files into one",
577
- command="utils merge-pdfs",
578
- parent="utils",
579
- help_text="utils merge-pdfs <file1> <file2> --output <file>"
580
- ))
581
-
582
582
  utils_node.add("🖥️ get-machine-specs - Get machine specifications", data=CommandInfo(
583
583
  name="get-machine-specs",
584
584
  description="Get machine specifications",
585
585
  command="utils get-machine-specs",
586
586
  parent="utils",
587
587
  help_text="utils get-machine-specs"
588
+ ))
589
+
590
+ utils_node.add("🚀 init-project - Initialize project", data=CommandInfo(
591
+ name="init-project",
592
+ description="Initialize a project with a uv virtual environment and install dev packages",
593
+ command="utils init-project",
594
+ parent="utils",
595
+ help_text="utils init-project"
596
+ ))
597
+
598
+ utils_node.add("✏️ edit - Open file in editor", data=CommandInfo(
599
+ name="edit",
600
+ description="Open a file in the default editor",
601
+ command="utils edit",
602
+ parent="utils",
603
+ help_text="utils edit <file>"
604
+ ))
605
+
606
+ utils_node.add("📄 pdf-merge - Merge PDF files", data=CommandInfo(
607
+ name="pdf-merge",
608
+ description="Merge two PDF files into one",
609
+ command="utils pdf-merge",
610
+ parent="utils",
611
+ help_text="utils pdf-merge <file1> <file2> --output <file>"
612
+ ))
613
+
614
+ utils_node.add("� pdf-compress - Compress PDF file", data=CommandInfo(
615
+ name="pdf-compress",
616
+ description="Compress a PDF file",
617
+ command="utils pdf-compress",
618
+ parent="utils",
619
+ help_text="utils pdf-compress <file> --output <file>"
588
620
  ))
@@ -105,7 +105,7 @@ git pull originEnc master
105
105
  uv_project_dir = f"""{str(Path.home().joinpath("code/machineconfig"))}"""
106
106
  uv_with = None
107
107
  else:
108
- uv_with = ["machineconfig>=7.64"]
108
+ uv_with = ["machineconfig>=7.83"]
109
109
  uv_project_dir = None
110
110
 
111
111
  import tempfile
@@ -136,7 +136,8 @@ git pull originEnc master
136
136
  def func2(remote_repo: str, local_repo: str, cloud: str):
137
137
  from machineconfig.scripts.python.helpers_repos.sync import delete_remote_repo_copy_and_push_local
138
138
  delete_remote_repo_copy_and_push_local(remote_repo=remote_repo, local_repo=local_repo, cloud=cloud)
139
- program_1_py = lambda_to_python_script(lambda: func2(remote_repo=str(repo_remote_root), local_repo=str(repo_local_root), cloud=str(cloud_resolved)), in_global=True, import_module=False)
139
+ program_1_py = lambda_to_python_script(lambda: func2(remote_repo=str(repo_remote_root), local_repo=str(repo_local_root), cloud=str(cloud_resolved)),
140
+ in_global=True, import_module=False)
140
141
  program1, _pyfile1 = get_uv_command_executing_python_script(python_script=program_1_py, uv_with=uv_with, uv_project_dir=uv_project_dir)
141
142
  # ================================================================================
142
143
  option2 = "Delete local repo and replace it with remote copy:"
@@ -161,7 +162,8 @@ sudo chmod +x $HOME/dotfiles/scripts/linux -R
161
162
  inspect_repos(repo_local_root=repo_local_root, repo_remote_root=repo_remote_root)
162
163
  # program_3_py = function_to_script(func=func, call_with_kwargs={"repo_local_root": str(repo_local_root), "repo_remote_root": str(repo_remote_root)})
163
164
  # shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, ve_path=None, executable=executable)
164
- program_3_py = lambda_to_python_script(lambda: func(repo_local_root=str(repo_local_root), repo_remote_root=str(repo_remote_root)), in_global=True, import_module=False)
165
+ program_3_py = lambda_to_python_script(lambda: func(repo_local_root=str(repo_local_root), repo_remote_root=str(repo_remote_root)),
166
+ in_global=True, import_module=False)
165
167
  program3, _pyfile3 = get_uv_command_executing_python_script(python_script=program_3_py, uv_with=uv_with, uv_project_dir=uv_project_dir)
166
168
  # ================================================================================
167
169