machineconfig 7.64__py3-none-any.whl → 7.79__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 (78) hide show
  1. machineconfig/cluster/sessions_managers/utils/maker.py +4 -2
  2. machineconfig/jobs/installer/custom_dev/sysabc.py +26 -0
  3. machineconfig/jobs/installer/installer_data.json +70 -2
  4. machineconfig/profile/create_links_export.py +2 -2
  5. machineconfig/scripts/__init__.py +0 -4
  6. machineconfig/scripts/python/agents.py +22 -17
  7. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +3 -0
  8. machineconfig/scripts/python/croshell.py +22 -17
  9. machineconfig/scripts/python/devops.py +1 -1
  10. machineconfig/scripts/python/devops_navigator.py +0 -4
  11. machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
  12. machineconfig/scripts/python/fire_jobs.py +13 -13
  13. machineconfig/scripts/python/ftpx.py +36 -12
  14. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  15. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  16. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  17. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  18. machineconfig/scripts/python/helpers_cloud/cloud_copy.py +28 -21
  19. machineconfig/scripts/python/helpers_cloud/cloud_helpers.py +1 -1
  20. machineconfig/scripts/python/helpers_cloud/cloud_mount.py +19 -17
  21. machineconfig/scripts/python/helpers_cloud/cloud_sync.py +8 -7
  22. machineconfig/scripts/python/helpers_croshell/start_slidev.py +6 -7
  23. machineconfig/scripts/python/helpers_devops/cli_nw.py +88 -7
  24. machineconfig/scripts/python/helpers_devops/cli_self.py +7 -6
  25. machineconfig/scripts/python/helpers_devops/cli_share_file.py +7 -7
  26. machineconfig/scripts/python/helpers_devops/cli_share_server.py +12 -11
  27. machineconfig/scripts/python/helpers_devops/cli_terminal.py +6 -5
  28. machineconfig/scripts/python/helpers_devops/cli_utils.py +2 -1
  29. machineconfig/scripts/python/helpers_devops/devops_status.py +7 -19
  30. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +20 -9
  31. machineconfig/scripts/python/helpers_navigator/command_tree.py +50 -18
  32. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +5 -3
  33. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +1 -1
  34. machineconfig/scripts/python/helpers_utils/download.py +4 -3
  35. machineconfig/scripts/python/helpers_utils/path.py +81 -31
  36. machineconfig/scripts/python/interactive.py +1 -1
  37. machineconfig/scripts/python/{machineconfig.py → mcfg_entry.py} +4 -0
  38. machineconfig/scripts/python/msearch.py +21 -2
  39. machineconfig/scripts/python/nw/address.py +132 -0
  40. machineconfig/scripts/python/nw/devops_add_ssh_key.py +8 -5
  41. machineconfig/scripts/python/terminal.py +2 -2
  42. machineconfig/scripts/python/utils.py +10 -9
  43. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
  44. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  45. machineconfig/settings/shells/nushell/config.nu +2 -2
  46. machineconfig/settings/shells/nushell/env.nu +45 -6
  47. machineconfig/settings/shells/nushell/init.nu +282 -95
  48. machineconfig/settings/shells/pwsh/init.ps1 +1 -0
  49. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  50. machineconfig/setup_windows/uv.ps1 +8 -1
  51. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +10 -10
  52. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -2
  53. machineconfig/utils/accessories.py +7 -4
  54. machineconfig/utils/code.py +4 -2
  55. machineconfig/utils/installer_utils/install_from_url.py +180 -0
  56. machineconfig/utils/installer_utils/installer_class.py +18 -10
  57. machineconfig/utils/installer_utils/installer_cli.py +14 -9
  58. machineconfig/utils/links.py +2 -2
  59. machineconfig/utils/meta.py +2 -2
  60. machineconfig/utils/options.py +3 -3
  61. machineconfig/utils/path_extended.py +1 -1
  62. machineconfig/utils/path_helper.py +0 -1
  63. machineconfig/utils/ssh.py +143 -409
  64. machineconfig/utils/ssh_utils/abc.py +8 -0
  65. machineconfig/utils/ssh_utils/copy_from_here.py +110 -0
  66. machineconfig/utils/ssh_utils/copy_to_here.py +302 -0
  67. machineconfig/utils/ssh_utils/utils.py +141 -0
  68. machineconfig/utils/ssh_utils/wsl.py +168 -0
  69. machineconfig/utils/upgrade_packages.py +2 -1
  70. machineconfig/utils/ve.py +11 -4
  71. {machineconfig-7.64.dist-info → machineconfig-7.79.dist-info}/METADATA +1 -1
  72. {machineconfig-7.64.dist-info → machineconfig-7.79.dist-info}/RECORD +77 -68
  73. {machineconfig-7.64.dist-info → machineconfig-7.79.dist-info}/entry_points.txt +2 -2
  74. machineconfig/scripts/python/explore.py +0 -49
  75. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_fire_command/f.py} +0 -0
  76. /machineconfig/scripts/{Restore-ThunderbirdProfile.ps1 → windows/mounts/Restore-ThunderbirdProfile.ps1} +0 -0
  77. {machineconfig-7.64.dist-info → machineconfig-7.79.dist-info}/WHEEL +0 -0
  78. {machineconfig-7.64.dist-info → machineconfig-7.79.dist-info}/top_level.txt +0 -0
@@ -3,9 +3,7 @@
3
3
 
4
4
  import typer
5
5
 
6
- from typing import Optional
7
- from pathlib import Path
8
- from typing import Annotated, Literal, TypedDict
6
+ from typing import Optional, Annotated, Literal, TypedDict
9
7
 
10
8
 
11
9
  def path():
@@ -17,43 +15,76 @@ def path():
17
15
  uv_with = ["textual"]
18
16
  uv_project_dir = None
19
17
  if not Path.home().joinpath("code/machineconfig").exists():
20
- uv_with.append("machineconfig>=7.64")
18
+ uv_with.append("machineconfig>=7.79")
21
19
  else:
22
20
  uv_project_dir = str(Path.home().joinpath("code/machineconfig"))
23
21
  run_shell_script(get_uv_command_executing_python_script(python_script=path.read_text(encoding="utf-8"), uv_with=uv_with, uv_project_dir=uv_project_dir)[0])
24
22
 
25
23
 
26
- def init_project(python: Annotated[Literal["3.13", "3.14"], typer.Option("--python", "-p", help="Python version for the uv virtual environment.")]= "3.13") -> None:
27
- _ = python
28
- repo_root = Path.cwd()
29
- if not (repo_root / "pyproject.toml").exists():
30
- typer.echo(" Error: pyproject.toml not found.", err=True)
31
- raise typer.Exit(code=1)
32
- print("Adding group `plot` with common data science and plotting packages...")
33
- script = """
34
- uv add --group plot \
35
- # Data & computation
36
- numpy pandas polars duckdb-engine python-magic \
37
- # Plotting / visualization
38
- matplotlib plotly kaleido \
39
- # Notebooks / interactive
40
- ipython ipykernel jupyterlab nbformat marimo \
41
- # Code analysis / type checking / linting
42
- mypy pyright ruff pylint pyrefly \
43
- # Packaging / build / dev
44
- cleanpy \
45
- # CLI / debugging / utilities
46
- ipdb pudb \
47
- # Type hints for packages
48
- types-python-dateutil types-pyyaml types-requests types-tqdm \
49
- types-mysqlclient types-paramiko types-pytz types-sqlalchemy types-toml types-urllib3 \
50
-
24
+ def init_project(
25
+ name: Annotated[Optional[str], typer.Option("--name", "-n", help="Name of the project.")]= None,
26
+ tmp_directory: Annotated[bool, typer.Option("--tmp-directory/--no-tmp-directory", "-t/-nt", help="Use a temporary directory for the project initialization.")]= False,
27
+ python: Annotated[Literal["3.13", "3.14"], typer.Option("--python", "-p", help="Python version for the uv virtual environment.")]= "3.13",
28
+ packages: Annotated[Optional[str], typer.Option("--packages", "-p", help="Additional packages to include in the uv virtual environment.")]= None,
29
+ group: Annotated[Optional[str], typer.Option("--group", "-g", help="Group name for the packages.")]= "plot",
30
+ types_packages: Annotated[bool, typer.Option("--types-packages/--no-types-packages", "-T/-NT", help="Include types packages for better type hinting.")]= True,
31
+ linting_debug_packages: Annotated[bool, typer.Option("--linting-debug-packages/--no-linting-debug-packages", "-L/-NL", help="Include linting and debugging packages.")]= True,
32
+ ia_packages: Annotated[bool, typer.Option("--ia-packages/--no-ia-packages", "-I/-NI", help="Include interactive and IA packages.")]= True,
33
+ plot_packages: Annotated[bool, typer.Option("--plot-packages/--no-plot-packages", "-P/-NP", help="Include plotting packages.")]= True,
34
+ data_packages: Annotated[bool, typer.Option("--data-packages/--no-data-packages", "-D/-ND", help="Include data manipulation packages.")]= True,
35
+ ) -> None:
36
+ if packages is not None:
37
+ packages_add_line = f"uv add {packages}"
38
+ else:
39
+ packages_add_line = ""
40
+ from pathlib import Path
41
+ if not tmp_directory:
42
+ repo_root = Path.cwd()
43
+ if not (repo_root / "pyproject.toml").exists():
44
+ typer.echo("❌ Error: pyproject.toml not found.", err=True)
45
+ raise typer.Exit(code=1)
46
+ starting_code = ""
47
+ else:
48
+ if name is not None:
49
+ from machineconfig.utils.accessories import randstr
50
+ repo_root = Path.home().joinpath(f"tmp_results/tmp_projects/{name}")
51
+ else:
52
+ from machineconfig.utils.accessories import randstr
53
+ repo_root = Path.home().joinpath(f"tmp_results/tmp_projects/{randstr(6)}")
54
+ repo_root.mkdir(parents=True, exist_ok=True)
55
+ print(f"Using temporary directory for project initialization: {repo_root}")
56
+ starting_code = f"""
57
+ cd {repo_root}
58
+ uv init --python {python}
59
+ uv venv
51
60
  """
52
- from machineconfig.utils.code import run_shell_script
53
- run_shell_script(script)
61
+ print(f"Adding group `{group}` with common data science and plotting packages...")
62
+ total_packages: list[str] = []
63
+
64
+ if types_packages:
65
+ total_packages.append("types-python-dateutil types-pyyaml types-requests types-tqdm types-mysqlclient types-paramiko types-pytz types-sqlalchemy types-toml types-urllib3")
66
+ if linting_debug_packages:
67
+ total_packages.append("mypy pyright ruff pylint pyrefly cleanpy ipdb pudb")
68
+ if ia_packages:
69
+ total_packages.append("ipython ipykernel jupyterlab nbformat marimo")
70
+ if plot_packages:
71
+ total_packages.append("python-magic matplotlib plotly kaleido")
72
+ if data_packages:
73
+ total_packages.append("numpy pandas polars duckdb-engine sqlalchemy psycopg2-binary pyarrow tqdm openpyxl")
74
+ from machineconfig.utils.ve import get_ve_activate_line
75
+ script = f"""
76
+ {starting_code}
77
+ {packages_add_line}
78
+ uv add --group {group} {" ".join(total_packages)}
79
+ {get_ve_activate_line(ve_root=str(repo_root.joinpath(".venv")))}
80
+ ls
81
+ """
82
+ from machineconfig.utils.code import exit_then_run_shell_script
83
+ exit_then_run_shell_script(script)
54
84
 
55
85
 
56
86
  def edit_file_with_hx(path: Annotated[Optional[str], typer.Argument(..., help="The root directory of the project to edit, or a file path.")] = None) -> None:
87
+ from pathlib import Path
57
88
  if path is None:
58
89
  root_path = Path.cwd()
59
90
  print(f"No path provided. Using current working directory: {root_path}")
@@ -82,6 +113,13 @@ class MachineSpecs(TypedDict):
82
113
  system: str
83
114
  distro: str
84
115
  home_dir: str
116
+ hostname: str
117
+ release: str
118
+ version: str
119
+ machine: str
120
+ processor: str
121
+ python_version: str
122
+ user: str
85
123
 
86
124
 
87
125
  def get_machine_specs() -> MachineSpecs:
@@ -90,11 +128,21 @@ def get_machine_specs() -> MachineSpecs:
90
128
  UV_RUN_CMD = "$HOME/.local/bin/uv run" if platform.system() != "Windows" else """& "$env:USERPROFILE/.local/bin/uv" run"""
91
129
  command = f"""{UV_RUN_CMD} --with distro python -c "import distro; print(distro.name(pretty=True))" """
92
130
  import subprocess
131
+ from pathlib import Path
132
+ import socket
133
+ import os
93
134
  distro = subprocess.run(command, shell=True, capture_output=True, text=True).stdout.strip()
94
135
  specs: MachineSpecs = {
95
136
  "system": platform.system(),
96
137
  "distro": distro,
97
138
  "home_dir": str(Path.home()),
139
+ "hostname": socket.gethostname(),
140
+ "release": platform.release(),
141
+ "version": platform.version(),
142
+ "machine": platform.machine(),
143
+ "processor": platform.processor() or "Unknown",
144
+ "python_version": platform.python_version(),
145
+ "user": os.getenv("USER") or os.getenv("USERNAME") or "Unknown",
98
146
  }
99
147
  print(specs)
100
148
  from machineconfig.utils.source_of_truth import CONFIG_ROOT
@@ -104,3 +152,5 @@ def get_machine_specs() -> MachineSpecs:
104
152
  path.write_text(json.dumps(specs, indent=4), encoding="utf-8")
105
153
  return specs
106
154
 
155
+ if __name__ == "__main__":
156
+ get_machine_specs()
@@ -111,7 +111,7 @@ def execute_installations(selected_options: list[str]) -> None:
111
111
  console.print(Panel("⚡ [bold bright_yellow]CLI APPLICATIONS[/bold bright_yellow]\n[italic]Command-line tools installation[/italic]", border_style="bright_yellow"))
112
112
  console.print("🔧 Installing CLI applications", style="bold cyan")
113
113
  try:
114
- from machineconfig.utils.installer_utils.installer_cli import main as devops_devapps_install_main
114
+ from machineconfig.utils.installer_utils.installer_cli import main_installer_cli as devops_devapps_install_main
115
115
  devops_devapps_install_main(group=True, which=maybe_a_group, interactive=False)
116
116
  console.print("✅ CLI applications installed successfully", style="bold green")
117
117
  except Exception as e:
@@ -57,3 +57,7 @@ def get_app():
57
57
  def main():
58
58
  app = get_app()
59
59
  app()
60
+
61
+
62
+ if __name__ == "__main__":
63
+ main()
@@ -1,8 +1,27 @@
1
1
 
2
2
  import typer
3
+ from typing import Annotated
3
4
 
4
5
 
5
- def machineconfig_find():
6
+ def machineconfig_search(
7
+ directory: Annotated[str, typer.Option(..., "--directory", "-d", help="The directory to search")] = ".",
8
+ ast: Annotated[bool, typer.Option(..., "--ast", "-a", help="The abstract syntax tree search/ tree sitter search of symbols")] = False):
9
+
10
+ if ast:
11
+ from machineconfig.scripts.python.helpers.ast_search import get_repo_symbols
12
+ symbols = get_repo_symbols(directory)
13
+ from machineconfig.utils.options import choose_from_options
14
+ try:
15
+ res = choose_from_options(options=symbols, msg="Select a symbol to search for:", fzf=True, multi=False)
16
+ from rich import print_json
17
+ import json
18
+ res_json = json.dumps(res, indent=4)
19
+ print_json(res_json)
20
+ return None
21
+ except Exception as e:
22
+ print(f"❌ Error during selection: {e}")
23
+ return None
24
+
6
25
  from machineconfig.scripts.python.helpers_msearch import FZFG_LINUX_PATH, FZFG_WINDOWS_PATH
7
26
  import platform
8
27
  if platform.system() == "Linux":
@@ -17,5 +36,5 @@ def machineconfig_find():
17
36
 
18
37
  def main():
19
38
  app = typer.Typer(add_completion=False, no_args_is_help=True)
20
- app.command(name="msearch", help="machineconfig search helper", no_args_is_help=False)(machineconfig_find)
39
+ app.command(name="msearch", help="machineconfig search helper", no_args_is_help=False)(machineconfig_search)
21
40
  app()
@@ -0,0 +1,132 @@
1
+
2
+ from typing import cast, Optional
3
+
4
+
5
+ def get_all_ipv4_addresses() -> list[tuple[str, str]]:
6
+ import psutil
7
+ import socket
8
+ result: list[tuple[str, str]] = []
9
+ for iface, addrs in psutil.net_if_addrs().items():
10
+ for addr in addrs:
11
+ if addr.family == socket.AF_INET:
12
+ ip = addr.address
13
+ result.append((iface, ip))
14
+ return result
15
+
16
+
17
+ def select_lan_ipv4(prefer_vpn: bool) -> Optional[str]:
18
+ """
19
+ Choose the best 'real LAN' IPv4:
20
+ - Excludes loopback/link-local and (by default) VPN/tunnel/container ifaces
21
+ - Prefers physical-looking ifaces (eth/en*/wlan/wl*)
22
+ - Prefers RFC1918 LANs: 192.168/16 > 10/8 > 172.16/12
23
+ - Requires interface is UP
24
+ Set prefer_vpn=True to allow tunnel/VPN ifaces to compete.
25
+ """
26
+
27
+ import ipaddress
28
+ import re
29
+ from collections.abc import Sequence
30
+ import psutil
31
+
32
+ # Down-rank or exclude: tunnels/VPNs/bridges/containers (add your own if needed)
33
+ VIRTUAL_IFACE_PAT = re.compile(
34
+ r"^(?:lo|loopback|docker\d*|br-.*|veth.*|virbr.*|bridge.*|"
35
+ r"vboxnet.*|vmnet.*|zt.*|ham.*|tailscale.*|wg\d*|utun\d*|llw\d*|awdl\d*|"
36
+ r"tun\d*|tap\d*|cloudflarewarp.*|warp.*)$",
37
+ re.IGNORECASE,
38
+ )
39
+
40
+ # Light preference for names that look like real NICs
41
+ PHYSICAL_IFACE_PAT = re.compile(
42
+ r"^(?:eth\d*|en\d*|enp.*|ens.*|eno.*|wlan\d*|wl.*|.*wifi.*|.*ethernet.*)$",
43
+ re.IGNORECASE,
44
+ )
45
+
46
+ # Known noisy CIDRs to avoid
47
+ NOISY_NETS: list[ipaddress.IPv4Network] = [
48
+ ipaddress.IPv4Network("100.64.0.0/10"), # CGNAT (Tailscale/others)
49
+ ipaddress.IPv4Network("172.17.0.0/16"), # docker0 default
50
+ ipaddress.IPv4Network("172.18.0.0/16"),
51
+ ipaddress.IPv4Network("172.19.0.0/16"),
52
+ ipaddress.IPv4Network("192.168.49.0/24"), # minikube default
53
+ ipaddress.IPv4Network("10.0.2.0/24"), # VirtualBox NAT
54
+ ]
55
+
56
+ def _in_any(ip: ipaddress.IPv4Address, nets: Sequence[ipaddress.IPv4Network]) -> bool:
57
+ return any(ip in n for n in nets)
58
+
59
+ stats = psutil.net_if_stats()
60
+ best = None
61
+ best_score = -10**9
62
+ import socket
63
+ for iface, addrs in psutil.net_if_addrs().items():
64
+ st = stats.get(iface)
65
+ if not st or not st.isup:
66
+ continue
67
+
68
+ for a in addrs:
69
+ if a.family != socket.AF_INET or not a.address:
70
+ continue
71
+
72
+ ip_str = a.address
73
+ try:
74
+ ip = cast(ipaddress.IPv4Address, ipaddress.ip_address(ip_str))
75
+ except ValueError:
76
+ continue
77
+
78
+ # Exclude unusable classes
79
+ if ip.is_loopback or ip.is_link_local: # 127.0.0.0/8, 169.254.0.0/16
80
+ continue
81
+
82
+ # Hard filter: if it looks virtual and we don't prefer VPNs, skip it
83
+ if not prefer_vpn and VIRTUAL_IFACE_PAT.match(iface):
84
+ continue
85
+
86
+ # Hard filter: known noisy subnets (docker, cgnat, etc.)
87
+ if _in_any(ip, NOISY_NETS) and not prefer_vpn:
88
+ continue
89
+
90
+ # Base score
91
+ score = 0
92
+
93
+ # Prefer physical-looking names
94
+ if PHYSICAL_IFACE_PAT.match(iface):
95
+ score += 200
96
+
97
+ # Broadcast present usually means L2 LAN (not point-to-point)
98
+ # (psutil puts it on the same entry as .broadcast)
99
+ if getattr(a, "broadcast", None):
100
+ score += 100
101
+
102
+ # Prefer private RFC1918; rank families
103
+ if ip.is_private:
104
+ # Order: 192.168.x.x > 10.x.x.x > 172.16-31.x.x
105
+ ip_net = ipaddress.IPv4Network((ip, 32), strict=False)
106
+ if ipaddress.IPv4Network("192.168.0.0/16").supernet_of(ip_net):
107
+ score += 90
108
+ elif ipaddress.IPv4Network("10.0.0.0/8").supernet_of(ip_net):
109
+ score += 70
110
+ elif ipaddress.IPv4Network("172.16.0.0/12").supernet_of(ip_net):
111
+ score += 50
112
+ else:
113
+ # Public on a NIC is unusual for a home/office LAN
114
+ score -= 50
115
+
116
+ # Slight nudge by interface speed if known (>0 means psutil knows it)
117
+ # (Many tunnels report 0)
118
+ if getattr(st, "speed", 0) > 0:
119
+ score += 20
120
+
121
+ # Deterministic tie-breaker: prefer shorter iface name (eth0 over eth10)
122
+ score -= len(iface) * 0.01
123
+
124
+ if score > best_score:
125
+ best_score = score
126
+ best = ip_str
127
+
128
+ return best
129
+
130
+
131
+ if __name__ == "__main__":
132
+ print(select_lan_ipv4(False) or "No LAN IPv4 found")
@@ -137,11 +137,14 @@ def main(pub_path: Annotated[Optional[str], typer.Argument(..., help="Path to th
137
137
  console.print(Panel("🚀 SSH KEY AUTHORIZATION READY\nRun the generated script to apply changes", box=box.DOUBLE_EDGE, title_align="left"))
138
138
  from machineconfig.utils.code import run_shell_script
139
139
  run_shell_script(script=program)
140
- import socket
141
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
142
- s.connect(('8.8.8.8', 80))
143
- local_ip_v4 = s.getsockname()[0]
144
- s.close()
140
+
141
+ import machineconfig.scripts.python.nw.address as helper
142
+ res = helper.select_lan_ipv4(prefer_vpn=False)
143
+ if res is None:
144
+ console.print(Panel("❌ ERROR: Could not determine local LAN IPv4 address", title="[bold red]Error[/bold red]", border_style="red"))
145
+ raise typer.Exit(code=1)
146
+ local_ip_v4 = res
147
+
145
148
  console.print(Panel(f"🌐 This computer is accessible at: {local_ip_v4}", title="[bold green]Network Info[/bold green]", border_style="green"))
146
149
  console.print(Panel("✅ SSH KEY AUTHORIZATION COMPLETED", box=box.DOUBLE_EDGE, title_align="left"))
147
150
 
@@ -1,5 +1,3 @@
1
- import subprocess
2
- # from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
3
1
  import typer
4
2
  from typing import Annotated
5
3
 
@@ -26,6 +24,7 @@ def choose_zellij_session(
26
24
  typer.Exit()
27
25
  return
28
26
  cmd = "zellij list-sessions"
27
+ import subprocess
29
28
  sessions: list[str] = subprocess.check_output(cmd, shell=True).decode().strip().split("\n")
30
29
  # filter out empty lines and keep raw lines (they contain creation info)
31
30
  sessions = [s for s in sessions if s.strip()]
@@ -63,6 +62,7 @@ def choose_zellij_session(
63
62
 
64
63
  def get_session_tabs() -> list[tuple[str, str]]:
65
64
  cmd = "zellij list-sessions"
65
+ import subprocess
66
66
  sessions: list[str] = subprocess.check_output(cmd, shell=True).decode().strip().split("\n")
67
67
  sessions = [strip_ansi_codes(s) for s in sessions]
68
68
  active_sessions = [s for s in sessions if "EXITED" not in s]
@@ -6,6 +6,7 @@ from machineconfig.scripts.python.helpers_utils.download import download
6
6
  import typer
7
7
  from typing import Annotated
8
8
 
9
+
9
10
  def kill_process(
10
11
  # name: Annotated[Optional[str], typer.Option(..., "--name", "-n", help="Name of the process to kill")],
11
12
  # command: Annotated[str, typer.Option(..., "--command", "-c", help="Match by command line instead of process name")] = "",
@@ -29,27 +30,27 @@ def upgrade_packages():
29
30
 
30
31
  def get_app() -> typer.Typer:
31
32
  app = typer.Typer(help="🛠️ utilities operations", no_args_is_help=True, add_help_option=False, add_completion=False)
32
- app.command(name="kill-process", no_args_is_help=False, help="[k] Choose a process to kill")(kill_process)
33
+ app.command(name="kill-process", no_args_is_help=False, help="⚔️ [k] Choose a process to kill")(kill_process)
33
34
  app.command(name="k", no_args_is_help=False, help="Choose a process to kill", hidden=True)(kill_process)
34
35
 
35
- app.command("path", no_args_is_help=False, help="📚 [p] NAVIGATE PATH variable with TUI")(path)
36
+ app.command("path", no_args_is_help=False, help="📚 [p] NAVIGATE PATH variable with TUI")(path)
36
37
  app.command("p", no_args_is_help=False, help="NAVIGATE PATH variable with TUI", hidden=True)(path)
37
38
 
38
- app.command(name="upgrade-packages", no_args_is_help=False, help="[up] Upgrade project dependencies.")(upgrade_packages)
39
+ app.command(name="upgrade-packages", no_args_is_help=False, help="⬆️ [up] Upgrade project dependencies.")(upgrade_packages)
39
40
  app.command(name="up", no_args_is_help=False, hidden=True)(upgrade_packages)
40
41
 
41
- app.command(name="download", no_args_is_help=True, help="[d] Download a file from a URL and optionally decompress it.")(download)
42
+ app.command(name="download", no_args_is_help=True, help="⬇️ [d] Download a file from a URL and optionally decompress it.")(download)
42
43
  app.command(name="d", no_args_is_help=True, hidden=True)(download)
43
- app.command(name="get-machine-specs", no_args_is_help=False, help="[g] Get machine specifications.")(get_machine_specs)
44
+ app.command(name="get-machine-specs", no_args_is_help=False, help="💻 [g] Get machine specifications.")(get_machine_specs)
44
45
  app.command(name="g", no_args_is_help=False, hidden=True)(get_machine_specs)
45
- app.command(name="init-project", no_args_is_help=False, help="[i] Initialize a project with a uv virtual environment and install dev packages.")(init_project)
46
+ app.command(name="init-project", no_args_is_help=False, help="🚀 [i] Initialize a project with a uv virtual environment and install dev packages.")(init_project)
46
47
  app.command(name="i", no_args_is_help=False, hidden=True)(init_project)
47
- app.command(name="edit", no_args_is_help=False, help="[e] Open a file in the default editor.")(edit_file_with_hx)
48
+ app.command(name="edit", no_args_is_help=False, help="✏️ [e] Open a file in the default editor.")(edit_file_with_hx)
48
49
  app.command(name="e", no_args_is_help=False, hidden=True)(edit_file_with_hx)
49
50
 
50
- app.command(name="pdf-merge", no_args_is_help=True, help="[pm] Merge two PDF files into one.")(merge_pdfs)
51
+ app.command(name="pdf-merge", no_args_is_help=True, help="📄 [pm] Merge two PDF files into one.")(merge_pdfs)
51
52
  app.command(name="pm", no_args_is_help=True, hidden=True)(merge_pdfs)
52
- app.command(name="pdf-compress", no_args_is_help=True, help="[pc] Compress a PDF file.")(compress_pdf)
53
+ app.command(name="pdf-compress", no_args_is_help=True, help="📦 [pc] Compress a PDF file.")(compress_pdf)
53
54
  app.command(name="pc", no_args_is_help=True, hidden=True)(compress_pdf)
54
55
 
55
56
  # app.command(name="copy", no_args_is_help=True, help="[c] Copy files or directories.")(copy)
@@ -7,7 +7,7 @@ $user = ''
7
7
  $sharePath = ''
8
8
  $driveLetter = ''
9
9
 
10
- uv run --python 3.14 --with "machineconfig>=7.64" python -m machineconfig.scripts.python.mount_ssh
10
+ uv run --python 3.14 --with "machineconfig>=7.79" python -m machineconfig.scripts.python.mount_ssh
11
11
 
12
12
  net use T: \\sshfs.kr\$user@$host.local
13
13
  # this worked: net use T: \\sshfs\alex@alex-p51s-5.local
@@ -17,7 +17,7 @@
17
17
 
18
18
  function lfcd {
19
19
  $tmp = [System.IO.Path]::GetTempFileName()
20
- ~\AppData\Local\Microsoft\WindowsApps\lf.exe -last-dir-path="$tmp" $args
20
+ & "$env:USERPROFILE\AppData\Local\Microsoft\WindowsApps\lf.exe" -last-dir-path="$tmp" $args
21
21
  if (Test-Path -PathType Leaf "$tmp")
22
22
  {
23
23
  $dir = Get-Content "$tmp"
@@ -1,3 +1,3 @@
1
+ # machineconfig Nushell configuration loader
1
2
 
2
-
3
- use C:\Users\aalsaf01\.config\machineconfig\settings\shells\nushell\init.nu
3
+ use "~/.config/machineconfig/settings/shells/nushell/init.nu"
@@ -1,13 +1,52 @@
1
+ # machineconfig Nushell environment setup
1
2
 
3
+ def reduce_non_empty [segments: list<string>] -> list<string> {
4
+ segments
5
+ | reduce --fold [] { |segment, acc|
6
+ if (($segment | str length) > 0) {
7
+ $acc | append $segment
8
+ } else {
9
+ $acc
10
+ }
11
+ }
12
+ }
2
13
 
3
- # as per https://github.com/starship/starship?tab=readme-ov-file#step-1-install-starship
4
- mkdir ~/.cache/starship
5
- starship init nu | save -f ~/.cache/starship/init.nu
14
+ let default_root = ($env.HOME | path join ".config" "machineconfig")
15
+ let config_root = (
16
+ $env.CONFIG_ROOT?
17
+ | default $default_root
18
+ | path expand
19
+ )
6
20
 
21
+ load-env { CONFIG_ROOT: $config_root }
7
22
 
23
+ let existing_segments = (
24
+ $env.PATH?
25
+ | default ""
26
+ | split row (char esep)
27
+ | reduce_non_empty
28
+ )
8
29
 
9
- # echo $nu.env-path
10
- # as per https://github.com/ajeetdsouza/zoxide?tab=readme-ov-file#installation
11
- zoxide init nushell | save -f ~/.zoxide.nu
30
+ let desired_paths = [
31
+ ($config_root | path join "scripts")
32
+ ($env.HOME | path join "dotfiles" "scripts" "linux")
33
+ ($env.HOME | path join ".local" "bin")
34
+ ($env.HOME | path join ".cargo" "bin")
35
+ "/usr/games"
36
+ ]
37
+
38
+ let merged_segments = (
39
+ $desired_paths
40
+ | reduce --fold $existing_segments { |entry, acc|
41
+ if (($entry | path exists) and (not ($entry in $acc))) {
42
+ $acc | append $entry
43
+ } else {
44
+ $acc
45
+ }
46
+ }
47
+ )
48
+
49
+ let new_path = ($merged_segments | str join (char esep))
50
+ load-env { PATH: $new_path }
12
51
 
13
52