machineconfig 6.84__py3-none-any.whl → 6.86__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 (58) hide show
  1. machineconfig/cluster/sessions_managers/wt_local.py +16 -221
  2. machineconfig/cluster/sessions_managers/wt_local_manager.py +33 -174
  3. machineconfig/cluster/sessions_managers/wt_remote_manager.py +39 -197
  4. machineconfig/cluster/sessions_managers/wt_utils/manager_persistence.py +52 -0
  5. machineconfig/cluster/sessions_managers/wt_utils/monitoring_helpers.py +50 -0
  6. machineconfig/cluster/sessions_managers/wt_utils/status_reporting.py +76 -0
  7. machineconfig/cluster/sessions_managers/wt_utils/wt_helpers.py +199 -0
  8. machineconfig/scripts/python/agents.py +18 -7
  9. machineconfig/scripts/python/ai/vscode_tasks.py +7 -2
  10. machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
  11. machineconfig/scripts/python/fire_jobs.py +31 -66
  12. machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_crush.py +6 -5
  13. machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
  14. machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_gemini.py +2 -3
  15. machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_qwen.py +2 -2
  16. machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_help_launch.py +4 -4
  17. machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_helper_types.py +2 -2
  18. machineconfig/scripts/python/helpers_agents/templates/prompt.txt +6 -0
  19. machineconfig/scripts/python/helpers_agents/templates/template.sh +24 -0
  20. machineconfig/scripts/python/helpers_devops/cli_config.py +1 -1
  21. machineconfig/scripts/python/helpers_devops/cli_nw.py +50 -0
  22. machineconfig/scripts/python/helpers_devops/cli_self.py +3 -3
  23. machineconfig/scripts/python/helpers_devops/cli_utils.py +18 -1
  24. machineconfig/scripts/python/{helpers_fire/helpers4.py → helpers_fire_command/file_wrangler.py} +15 -0
  25. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +1 -1
  26. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +1 -1
  27. machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +1 -1
  28. machineconfig/scripts/python/nw/mount_nfs +1 -1
  29. machineconfig/scripts/python/nw/wifi_conn.py +1 -53
  30. machineconfig/scripts/python/sessions.py +1 -1
  31. machineconfig/scripts/python/terminal.py +46 -17
  32. machineconfig/scripts/python/utils.py +10 -21
  33. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
  34. machineconfig/scripts/windows/term.ps1 +48 -0
  35. machineconfig/setup_linux/web_shortcuts/interactive.sh +1 -1
  36. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +1 -1
  37. machineconfig/utils/code.py +18 -13
  38. machineconfig/utils/installer.py +0 -1
  39. machineconfig/utils/meta.py +4 -3
  40. machineconfig/utils/path_helper.py +1 -1
  41. machineconfig/utils/scheduling.py +0 -2
  42. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  43. machineconfig/utils/ssh.py +2 -2
  44. machineconfig/utils/upgrade_packages.py +28 -24
  45. {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/METADATA +1 -1
  46. {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/RECORD +55 -52
  47. machineconfig/scripts/linux/warp-cli.sh +0 -122
  48. machineconfig/scripts/python/helpers_fire/prompt.txt +0 -2
  49. machineconfig/scripts/python/helpers_fire/template.sh +0 -15
  50. /machineconfig/scripts/python/{helpers_fire → helpers_agents}/__init__.py +0 -0
  51. /machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/__init__.py +0 -0
  52. /machineconfig/scripts/python/{helpers_fire → helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
  53. /machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_help_search.py +0 -0
  54. /machineconfig/scripts/python/{helpers_fire → helpers_agents}/fire_agents_load_balancer.py +0 -0
  55. /machineconfig/scripts/python/{helpers_fire → helpers_agents/templates}/template.ps1 +0 -0
  56. {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/WHEEL +0 -0
  57. {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/entry_points.txt +0 -0
  58. {machineconfig-6.84.dist-info → machineconfig-6.86.dist-info}/top_level.txt +0 -0
@@ -54,6 +54,52 @@ def debug_ssh():
54
54
  else:
55
55
  raise NotImplementedError(f"Platform {system()} is not supported.")
56
56
 
57
+ def wifi_select(
58
+ ssid: Annotated[str, typer.Option("-n", "--ssid", help="🔗 SSID of WiFi (from config)")] = "MyPhoneHotSpot",
59
+ manual: Annotated[bool, typer.Option("-m", "--manual", help="🔍 Manual network selection mode")] = False,
60
+ list_: Annotated[bool, typer.Option("-l", "--list", help="📡 List available networks only")] = False,
61
+ ) -> None:
62
+ """Main function with fallback network selection"""
63
+ from rich.panel import Panel
64
+ from rich.prompt import Confirm
65
+ from rich.console import Console
66
+ from machineconfig.scripts.python.nw.wifi_conn import try_config_connection, manual_network_selection, display_available_networks
67
+ console = Console()
68
+ console.print(Panel("📶 Welcome to the WiFi Connector Tool", title="[bold blue]WiFi Connection[/bold blue]", border_style="blue"))
69
+
70
+ # If user just wants to list networks
71
+ if list_:
72
+ display_available_networks()
73
+ return
74
+
75
+ # If user wants manual mode, skip config and go straight to selection
76
+ if manual:
77
+ console.print("[blue]🔍 Manual network selection mode[/blue]")
78
+ if manual_network_selection():
79
+ console.print("[green]🎉 Successfully connected![/green]")
80
+ else:
81
+ console.print("[red]❌ Failed to connect[/red]")
82
+ return
83
+
84
+ # Try to connect using configuration first
85
+ console.print(f"[blue]🔍 Attempting to connect to configured network: {ssid}[/blue]")
86
+
87
+ if try_config_connection(ssid):
88
+ console.print("[green]🎉 Successfully connected using configuration![/green]")
89
+ return
90
+
91
+ # Configuration failed, offer fallback options
92
+ console.print("\n[yellow]⚠️ Configuration connection failed or not available[/yellow]")
93
+
94
+ if Confirm.ask("[blue]Would you like to manually select a network?[/blue]", default=True):
95
+ if manual_network_selection():
96
+ console.print("[green]🎉 Successfully connected![/green]")
97
+ else:
98
+ console.print("[red]❌ Failed to connect[/red]")
99
+ else:
100
+ console.print("[blue]👋 Goodbye![/blue]")
101
+
102
+
57
103
  def get_app():
58
104
  nw_apps = typer.Typer(help="🔐 [n] Network subcommands", no_args_is_help=True, add_help_option=False, add_completion=False)
59
105
  nw_apps.command(name="share-terminal", help="📡 [t] Share terminal via web browser")(cli_terminal.main)
@@ -70,4 +116,8 @@ def get_app():
70
116
  nw_apps.command(name="a", help="Show this computer addresses on network", hidden=True)(show_address)
71
117
  nw_apps.command(name="debug-ssh", help="🐛 [d] Debug SSH connection")(debug_ssh)
72
118
  nw_apps.command(name="d", help="Debug SSH connection", hidden=True)(debug_ssh)
119
+
120
+ nw_apps.command(name="wifi-select", no_args_is_help=True, help="[w] WiFi connection utility.")(wifi_select)
121
+ nw_apps.command(name="w", no_args_is_help=True, hidden=True)(wifi_select)
122
+
73
123
  return nw_apps
@@ -41,9 +41,9 @@ def install(no_copy_assets: Annotated[bool, typer.Option("--no-assets-copy", "-n
41
41
  else:
42
42
  import platform
43
43
  if platform.system() == "Windows":
44
- run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=6.84" """)
44
+ run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=6.86" """)
45
45
  else:
46
- run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=6.84" """)
46
+ run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=6.86" """)
47
47
  from machineconfig.profile.create_shell_profile import create_default_shell_profile
48
48
  if not no_copy_assets:
49
49
  create_default_shell_profile() # involves copying assets too
@@ -68,7 +68,7 @@ def navigate():
68
68
  path = Path(navigator.__file__).resolve().parent.joinpath("devops_navigator.py")
69
69
  from machineconfig.utils.code import run_shell_script
70
70
  if Path.home().joinpath("code/machineconfig").exists(): executable = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" --with textual"""
71
- else: executable = """--with "machineconfig>=6.84,textual" """
71
+ else: executable = """--with "machineconfig>=6.86,textual" """
72
72
  run_shell_script(f"""uv run {executable} {path}""")
73
73
 
74
74
 
@@ -198,7 +198,7 @@ def init_project(python: Annotated[Literal["3.13", "3.14"], typer.Option("--pyth
198
198
  if not (repo_root / "pyproject.toml").exists():
199
199
  typer.echo("❌ Error: pyproject.toml not found.", err=True)
200
200
  raise typer.Exit(code=1)
201
- print(f"Adding group `plot` with common data science and plotting packages...")
201
+ print("Adding group `plot` with common data science and plotting packages...")
202
202
  script = """
203
203
  uv add --group plot \
204
204
  # Data & computation
@@ -219,3 +219,20 @@ uv add --group plot \
219
219
  """
220
220
  from machineconfig.utils.code import run_shell_script
221
221
  run_shell_script(script)
222
+ # def add_dev_packages(repo_dir: Annotated[Optional[str], typer.Option(..., "--repo-dir", "-r", help="Path to the repository root directory")] = None):
223
+ # if repo_dir is None:
224
+ # r_dir = Path.cwd()
225
+ # else:
226
+ # r_dir = Path(repo_dir).resolve()
227
+ # if not r_dir.exists() or not r_dir.is_dir() or not (r_dir / "pyproject.toml").exists():
228
+ # typer.echo(f"❌ The provided repo directory `{r_dir}` is not valid or does not contain a `pyproject.toml` file.")
229
+ # raise typer.Exit(code=1)
230
+ # command = f"""
231
+ # cd "{r_dir}" || exit 1
232
+ # uv add nbformat ipdb ipykernel ipython pylint pyright mypy pyrefly ty pytest
233
+ # """
234
+ # from machineconfig.utils.code import run_shell_script
235
+ # typer.echo(f"➡️ Installing dev packages in repo at `{r_dir}`...")
236
+ # run_shell_script(command)
237
+ # typer.echo(f"✅ Dev packages installed successfully in repo at `{r_dir}`.")
238
+ # # TODO: see upgrade packages.
@@ -110,3 +110,18 @@ def get_import_module_code(module_path: str):
110
110
  module_name = "IncorrectModuleName"
111
111
  # TODO: use py_compile to check if the statement is valid code to avoid syntax errors that can't be caught.
112
112
  return f"from {module_name} import *"
113
+
114
+
115
+ def wrap_import_in_try_except(import_line: str, pyfile: str, repo_root: Optional[str] = None) -> None:
116
+ try:
117
+ exec(import_line) # type: ignore
118
+ except (ImportError, ModuleNotFoundError) as ex:
119
+ print(fr"❌ Failed to import `{pyfile}` as a module: {ex} ")
120
+ print("⚠️ Attempting import with ad-hoc `$PATH` manipulation. DO NOT pickle any objects in this session as correct deserialization cannot be guaranteed.")
121
+ import sys
122
+ from pathlib import Path
123
+ sys.path.append(str(Path(pyfile).parent))
124
+ if repo_root is not None:
125
+ sys.path.append(repo_root)
126
+ exec(f"from {Path(pyfile).stem} import *")
127
+ print(fr"✅ Successfully imported `{pyfile}`")
@@ -22,7 +22,7 @@ def choose_function_or_lines(choice_file: PathExtended, kwargs_dict: dict[str, o
22
22
  choice_function: Optional[str] = None
23
23
 
24
24
  if choice_file.suffix == ".py":
25
- from machineconfig.scripts.python.helpers_fire.helpers4 import parse_pyfile
25
+ from machineconfig.scripts.python.helpers_fire_command.file_wrangler import parse_pyfile
26
26
  options, func_args = parse_pyfile(file_path=str(choice_file))
27
27
  choice_function_tmp = choose_from_options(msg="Choose a function to run", options=options, fzf=True, multi=False)
28
28
  assert isinstance(choice_function_tmp, str), f"choice_function must be a string. Got {type(choice_function_tmp)}"
@@ -80,7 +80,7 @@ git pull originEnc master
80
80
  uv_project_dir = f"""{str(Path.home().joinpath("code/machineconfig"))}"""
81
81
  uv_with = None
82
82
  else:
83
- uv_with = ["machineconfig>=6.84"]
83
+ uv_with = ["machineconfig>=6.86"]
84
84
  uv_project_dir = None
85
85
 
86
86
  import tempfile
@@ -21,7 +21,7 @@ def create_from_function(
21
21
  suffixes = {".py"}
22
22
  choice_file = match_file_name(sub_string=path, search_root=PathExtended.cwd(), suffixes=suffixes)
23
23
  elif path_obj.is_dir():
24
- from machineconfig.scripts.python.helpers_fire.helpers4 import search_for_files_of_interest
24
+ from machineconfig.scripts.python.helpers_fire_command.file_wrangler import search_for_files_of_interest
25
25
  print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
26
26
  files = search_for_files_of_interest(path_obj)
27
27
  print(f"🔍 Got #{len(files)} results.")
@@ -5,7 +5,7 @@
5
5
  # mkdir ~/data/local
6
6
  # sudo mount -o nolock,noatime,nodiratime,proto=tcp,timeo=600,retrans=2,noac alex-p51s-5:/home/alex/data/local ./data/local
7
7
 
8
- uv run --python 3.14 --with "machineconfig>=6.84" python -m machineconfig.scripts.python.mount_nfs
8
+ uv run --python 3.14 --with "machineconfig>=6.86" python -m machineconfig.scripts.python.mount_nfs
9
9
  # Check if remote server is reachable and share folder exists
10
10
  if ! ping -c 1 "$remote_server" &> /dev/null; then
11
11
  echo "💥 Error: Remote server $remote_server is not reachable."
@@ -28,8 +28,6 @@ Usage examples:
28
28
 
29
29
  """
30
30
 
31
- from typing import Annotated
32
- import typer
33
31
  import configparser
34
32
  from pathlib import Path
35
33
  import os
@@ -38,8 +36,7 @@ import subprocess
38
36
  import getpass
39
37
  from typing import List, Dict, Optional
40
38
  from rich.console import Console
41
- from rich.panel import Panel
42
- from rich.prompt import Prompt, Confirm
39
+ from rich.prompt import Prompt
43
40
  from rich.table import Table
44
41
 
45
42
  console = Console()
@@ -263,51 +260,6 @@ def manual_network_selection() -> bool:
263
260
  return False
264
261
 
265
262
 
266
- def main(
267
- ssid: Annotated[str, typer.Option("-n", "--ssid", help="🔗 SSID of WiFi (from config)")] = "MyPhoneHotSpot",
268
- manual: Annotated[bool, typer.Option("-m", "--manual", help="🔍 Manual network selection mode")] = False,
269
- list_: Annotated[bool, typer.Option("-l", "--list", help="📡 List available networks only")] = False,
270
- ) -> None:
271
- """Main function with fallback network selection"""
272
- console.print(Panel("📶 Welcome to the WiFi Connector Tool", title="[bold blue]WiFi Connection[/bold blue]", border_style="blue"))
273
-
274
- # If user just wants to list networks
275
- if list_:
276
- display_available_networks()
277
- return
278
-
279
- # If user wants manual mode, skip config and go straight to selection
280
- if manual:
281
- console.print("[blue]🔍 Manual network selection mode[/blue]")
282
- if manual_network_selection():
283
- console.print("[green]🎉 Successfully connected![/green]")
284
- else:
285
- console.print("[red]❌ Failed to connect[/red]")
286
- return
287
-
288
- # Try to connect using configuration first
289
- console.print(f"[blue]🔍 Attempting to connect to configured network: {ssid}[/blue]")
290
-
291
- if try_config_connection(ssid):
292
- console.print("[green]🎉 Successfully connected using configuration![/green]")
293
- return
294
-
295
- # Configuration failed, offer fallback options
296
- console.print("\n[yellow]⚠️ Configuration connection failed or not available[/yellow]")
297
-
298
- if Confirm.ask("[blue]Would you like to manually select a network?[/blue]", default=True):
299
- if manual_network_selection():
300
- console.print("[green]🎉 Successfully connected![/green]")
301
- else:
302
- console.print("[red]❌ Failed to connect[/red]")
303
- else:
304
- console.print("[blue]👋 Goodbye![/blue]")
305
-
306
-
307
- def arg_parser() -> None:
308
- typer.run(main)
309
-
310
-
311
263
  def get_current_wifi_name() -> str:
312
264
  """Get the name of the currently connected WiFi network"""
313
265
  console.print("\n[blue]🔍 Checking current WiFi connection...[/blue]")
@@ -412,7 +364,3 @@ def create_new_connection(name: str, ssid: str, password: str):
412
364
  except Exception as e:
413
365
  console.print(f"[red]❌ Unexpected error: {e}[/red]")
414
366
  raise
415
-
416
-
417
- if __name__ == "__main__":
418
- arg_parser()
@@ -51,7 +51,7 @@ def select_layout(layouts_json_file: Path, selected_layouts_names: Optional[list
51
51
 
52
52
  def find_layout_file(layout_path: str, ) -> Path:
53
53
  from machineconfig.utils.path_extended import PathExtended
54
- from machineconfig.scripts.python.helpers_fire.helpers4 import search_for_files_of_interest
54
+ from machineconfig.scripts.python.helpers_fire_command.file_wrangler import search_for_files_of_interest
55
55
  from machineconfig.utils.options import choose_from_options
56
56
  from machineconfig.utils.path_helper import match_file_name, sanitize_path
57
57
  path_obj = sanitize_path(layout_path)
@@ -1,4 +1,5 @@
1
1
  import subprocess
2
+ # from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
2
3
  import typer
3
4
  from typing import Annotated
4
5
 
@@ -9,7 +10,21 @@ def strip_ansi_codes(text: str) -> str:
9
10
  return re.sub(r'\x1b\[[0-9;]*[a-zA-Z]', '', text)
10
11
 
11
12
 
12
- def choose_zellij_session():
13
+ def choose_zellij_session(
14
+ new_session: Annotated[bool, typer.Option("--new-session", "-n", help="Create a new Zellij session instead of attaching to an existing one.", show_default=True)] = False,
15
+ kill_all: Annotated[bool, typer.Option("--kill-all", "-k", help="Kill all existing Zellij sessions before creating a new one.", show_default=True)] = False):
16
+
17
+ if new_session:
18
+ cmd = """
19
+ zellij --layout st2
20
+ """
21
+ if kill_all:
22
+ cmd = f"""zellij kill-sessions
23
+ {cmd}"""
24
+ from machineconfig.utils.code import exit_then_run_shell_script
25
+ exit_then_run_shell_script(cmd, strict=True)
26
+ typer.Exit()
27
+ return
13
28
  cmd = "zellij list-sessions"
14
29
  sessions: list[str] = subprocess.check_output(cmd, shell=True).decode().strip().split("\n")
15
30
  sessions.sort(key=lambda s: "EXITED" in s)
@@ -32,16 +47,6 @@ def choose_zellij_session():
32
47
  exit_then_run_shell_script(result, strict=True)
33
48
 
34
49
 
35
- def new_zellij_session(kill_all: Annotated[bool, typer.Option("--kill-all", "-k", help="Kill all existing Zellij sessions before creating a new one.", show_default=True)] = False):
36
- cmd = """
37
- zellij --layout st2
38
- """
39
- if kill_all:
40
- cmd = f"""zellij kill-sessions
41
- {cmd}"""
42
- from machineconfig.utils.code import exit_then_run_shell_script
43
- exit_then_run_shell_script(cmd, strict=True)
44
-
45
50
 
46
51
  def get_session_tabs() -> list[tuple[str, str]]:
47
52
  cmd = "zellij list-sessions"
@@ -64,16 +69,40 @@ def get_session_tabs() -> list[tuple[str, str]]:
64
69
  print(result)
65
70
  return result
66
71
 
72
+ def start_wt(layout_name: Annotated[str, typer.Argument(help="Layout name to start.")]):
73
+ from pathlib import Path
74
+ layouts_file = Path.home().joinpath("dotfiles/machineconfig/layouts.json")
75
+ if not layouts_file.exists():
76
+ typer.echo(f"❌ Layouts file not found: {layouts_file}")
77
+ # available
78
+ raise typer.Exit(code=1)
79
+ import json
80
+ from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile
81
+ layouts_data: LayoutsFile = json.loads(layouts_file.read_text(encoding="utf-8"))
82
+ chosen_layout = next((a_layout for a_layout in layouts_data["layouts"] if a_layout["layoutName"] == layout_name), None)
83
+ if not chosen_layout:
84
+ typer.echo(f"❌ Layout '{layout_name}' not found in layouts file.")
85
+ available_layouts = [a_layout["layoutName"] for a_layout in layouts_data["layouts"]]
86
+ typer.echo(f"Available layouts: {', '.join(available_layouts)}")
87
+ raise typer.Exit(code=1)
88
+ from machineconfig.cluster.sessions_managers.wt_local import run_wt_layout
89
+ run_wt_layout(layout_config=chosen_layout)
90
+
91
+ # cmd = f'powershell -ExecutionPolicy Bypass -File "./{layout_name}_layout.ps1"'
92
+ # from machineconfig.utils.code import exit_then_run_shell_script
93
+ # exit_then_run_shell_script(cmd, strict=True)
94
+
67
95
 
68
96
  def main():
69
97
  app = typer.Typer(help="🖥️ Terminal utilities", no_args_is_help=True, add_help_option=False)
70
- app.command(name="choose-zellij-session", no_args_is_help=False, help="[c] Choose a Zellij session to attach to")(choose_zellij_session)
71
- app.command(name="c", hidden=True, no_args_is_help=False, help="[c] Choose a Zellij session to attach to")(choose_zellij_session)
72
- app.command(name="new-zellij-session", no_args_is_help=False, help="[n] new zellij session.")(new_zellij_session)
73
- app.command(name="n", hidden=True, no_args_is_help=False, help="[n] new zellij session.")(new_zellij_session)
98
+ app.command(name="attach-to-zellij", no_args_is_help=False, help="[z] Choose a Zellij session to attach to")(choose_zellij_session)
99
+ app.command(name="z", hidden=True, no_args_is_help=False, help="[z] Choose a Zellij session to attach to")(choose_zellij_session)
100
+
101
+ app.command(name="start-wt", no_args_is_help=True, help="[w] Start a Windows Terminal layout by name.")(start_wt)
102
+ app.command(name="w", hidden=True, no_args_is_help=True, help="[w] Start a Windows Terminal layout by name.")(start_wt)
74
103
 
75
- app.command(name="get-session-tabs", no_args_is_help=False, help="Get all Zellij session tabs.")(get_session_tabs)
76
- app.command(name="gst", hidden=True, no_args_is_help=False, help="Get all Zellij session tabs.")(get_session_tabs)
104
+ app.command(name="get-session-tabs", no_args_is_help=False, help="[zt] Get all Zellij session tabs.")(get_session_tabs)
105
+ app.command(name="zt", hidden=True, no_args_is_help=False, help="[zt] Get all Zellij session tabs.")(get_session_tabs)
77
106
  app()
78
107
 
79
108
 
@@ -2,9 +2,7 @@
2
2
 
3
3
  from machineconfig.scripts.python.helpers_devops.cli_utils import download, merge_pdfs, get_machine_specs, init_project, compress_pdf
4
4
  import typer
5
- from typing import Annotated, Optional
6
- from pathlib import Path
7
-
5
+ from typing import Annotated
8
6
 
9
7
  def kill_process(
10
8
  # name: Annotated[Optional[str], typer.Option(..., "--name", "-n", help="Name of the process to kill")],
@@ -21,30 +19,20 @@ def kill_process(
21
19
  # )
22
20
 
23
21
 
24
- def add_dev_packages(repo_dir: Annotated[Optional[str], typer.Option(..., "--repo-dir", "-r", help="Path to the repository root directory")] = None):
25
- if repo_dir is None:
26
- r_dir = Path.cwd()
27
- else:
28
- r_dir = Path(repo_dir).resolve()
29
- if not r_dir.exists() or not r_dir.is_dir() or not (r_dir / "pyproject.toml").exists():
30
- typer.echo(f"❌ The provided repo directory `{r_dir}` is not valid or does not contain a `pyproject.toml` file.")
31
- raise typer.Exit(code=1)
32
- command = f"""
33
- cd "{r_dir}" || exit 1
34
- uv add nbformat ipdb ipykernel ipython pylint pyright mypy pyrefly ty pytest
35
- """
36
- from machineconfig.utils.code import run_shell_script
37
- typer.echo(f"➡️ Installing dev packages in repo at `{r_dir}`...")
38
- run_shell_script(command)
39
- typer.echo(f"✅ Dev packages installed successfully in repo at `{r_dir}`.")
40
- # TODO: see upgrade packages.
41
-
22
+ def upgrade_packages():
23
+ from machineconfig.utils.upgrade_packages import generate_uv_add_commands
24
+ from pathlib import Path
25
+ generate_uv_add_commands(pyproject_path=Path.cwd() / "pyproject.toml", output_path=Path.cwd() / "pyproject_init.sh")
42
26
 
43
27
 
44
28
  def get_app() -> typer.Typer:
45
29
  app = typer.Typer(help="🛠️ utilities operations", no_args_is_help=True, add_help_option=False, add_completion=False)
46
30
  app.command(name="kill-process", no_args_is_help=False, help="[k] Choose a process to kill")(kill_process)
47
31
  app.command(name="k", no_args_is_help=False, help="Choose a process to kill", hidden=True)(kill_process)
32
+
33
+ app.command(name="upgrade-packages", no_args_is_help=False, help="[up] Upgrade project dependencies.")(upgrade_packages)
34
+ app.command(name="up", no_args_is_help=False, hidden=True)(upgrade_packages)
35
+
48
36
  app.command(name="download", no_args_is_help=True, help="[d] Download a file from a URL and optionally decompress it.")(download)
49
37
  app.command(name="d", no_args_is_help=True, hidden=True)(download)
50
38
  app.command(name="get-machine-specs", no_args_is_help=False, help="[g] Get machine specifications.")(get_machine_specs)
@@ -56,6 +44,7 @@ def get_app() -> typer.Typer:
56
44
  app.command(name="pm", no_args_is_help=True, hidden=True)(merge_pdfs)
57
45
  app.command(name="pdf-compress", no_args_is_help=True, help="[pc] Compress a PDF file.")(compress_pdf)
58
46
  app.command(name="pc", no_args_is_help=True, hidden=True)(compress_pdf)
47
+
59
48
  return app
60
49
 
61
50
  # def func():
@@ -7,7 +7,7 @@ $user = ''
7
7
  $sharePath = ''
8
8
  $driveLetter = ''
9
9
 
10
- uv run --python 3.14 --with "machineconfig>=6.84" python -m machineconfig.scripts.python.mount_ssh
10
+ uv run --python 3.14 --with "machineconfig>=6.86" 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
@@ -0,0 +1,48 @@
1
+ # Equivalent PowerShell script for term.ps1
2
+
3
+ Set-StrictMode -Version Latest
4
+ $ErrorActionPreference = 'Stop'
5
+
6
+ # Generate random name using timestamp and SHA256 hash
7
+ $timestampNs = [DateTimeOffset]::Now.ToUnixTimeMilliseconds() * 1000000
8
+ $hashInput = [System.Text.Encoding]::UTF8.GetBytes($timestampNs.ToString())
9
+ $sha256 = [System.Security.Cryptography.SHA256]::Create()
10
+ $hashBytes = $sha256.ComputeHash($hashInput)
11
+ $hashString = -join ($hashBytes | ForEach-Object { $_.ToString('x2') })
12
+ $randomName = $hashString.Substring(0, 16)
13
+
14
+ $opDir = "$env:USERPROFILE\tmp_results\tmp_scripts\machineconfig"
15
+ $opProgramPath = "$opDir\$randomName.ps1"
16
+ $global:OP_PROGRAM_PATH = $opProgramPath
17
+
18
+ # ANSI color/style codes (using Write-Host colors)
19
+ $bold = [char]27 + '[1m'
20
+ $reset = [char]27 + '[0m'
21
+ $green = [char]27 + '[32m'
22
+ $yellow = [char]27 + '[33m'
23
+ $blue = [char]27 + '[34m'
24
+ $red = [char]27 + '[31m'
25
+
26
+ $timestamp = Get-Date -Format 'u'
27
+
28
+ Write-Host "${bold}${blue}🛠️ terminal — running term${reset}"
29
+ Write-Host "${blue}Timestamp:${reset} ${timestamp}"
30
+ Write-Host "${blue}Op program path:${reset} ${opProgramPath}"
31
+
32
+ terminal $args
33
+
34
+ if (Test-Path $opProgramPath) {
35
+ Write-Host "${green}✅ Found op program:${reset} ${opProgramPath}"
36
+ # Assuming bat is available; otherwise, use Get-Content
37
+ & bat --style=plain --paging=never $opProgramPath
38
+ Write-Host "${green}▶ Running...${reset}"
39
+ . $opProgramPath
40
+ $status = $LASTEXITCODE
41
+ if ($status -eq 0) {
42
+ Write-Host "${green}✅ Completed successfully (exit ${status})${reset}"
43
+ } else {
44
+ Write-Host "${yellow}⚠️ Program exited with status ${status}${reset}"
45
+ }
46
+ } else {
47
+ Write-Host "${yellow}⚠️ No op program found at: ${opProgramPath}${reset}"
48
+ }
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
  . <( curl -sSL "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/uv.sh")
3
3
  mcfg() {
4
- "$HOME/.local/bin/uv" run --python 3.14 --with "machineconfig>=6.84" mcfg "$@"
4
+ "$HOME/.local/bin/uv" run --python 3.14 --with "machineconfig>=6.86" mcfg "$@"
5
5
  }
6
6
  alias d="mcfg devops"
7
7
  alias c="mcfg cloud"
@@ -2,7 +2,7 @@
2
2
 
3
3
  iex (iwr "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/uv.ps1").Content
4
4
  function mcfg {
5
- & "$HOME\.local\bin\uv.exe" run --python 3.14 --with "machineconfig>=6.84" mcfg $args
5
+ & "$HOME\.local\bin\uv.exe" run --python 3.14 --with "machineconfig>=6.86" mcfg $args
6
6
  }
7
7
  function d { mcfg devops @args }
8
8
  function c { mcfg cloud @args }
@@ -7,18 +7,23 @@ from pathlib import Path
7
7
 
8
8
  def print_code(code: str, lexer: str, desc: str, subtitle: str = ""):
9
9
  import platform
10
- from rich.console import Console
11
- from rich.panel import Panel
12
- from rich.syntax import Syntax
13
- if lexer == "shell":
14
- if platform.system() == "Windows":
15
- lexer = "powershell"
16
- elif platform.system() in ["Linux", "Darwin"]:
17
- lexer = "sh"
18
- else:
19
- raise NotImplementedError(f"Platform {platform.system()} not supported for lexer {lexer}")
20
- console = Console()
21
- console.print(Panel(Syntax(code=code, lexer=lexer), title=f"📄 {desc}", subtitle=subtitle), style="bold red")
10
+ try:
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+ from rich.syntax import Syntax
14
+ if lexer == "shell":
15
+ if platform.system() == "Windows":
16
+ lexer = "powershell"
17
+ elif platform.system() in ["Linux", "Darwin"]:
18
+ lexer = "sh"
19
+ else:
20
+ raise NotImplementedError(f"Platform {platform.system()} not supported for lexer {lexer}")
21
+ console = Console()
22
+ console.print(Panel(Syntax(code=code, lexer=lexer), title=f"📄 {desc}", subtitle=subtitle), style="bold red")
23
+ except ImportError:
24
+ print(f"--- {desc} ---")
25
+ print(code)
26
+ print(f"--- End of {desc} ---")
22
27
 
23
28
 
24
29
  def get_uv_command_executing_python_script(python_script: str, uv_with: Optional[list[str]], uv_project_dir: Optional[str]) -> tuple[str, Path]:
@@ -51,7 +56,7 @@ def run_python_script_in_marimo(py_script: str, uv_project_with: Optional[str]):
51
56
  if uv_project_with is not None:
52
57
  requirements = f"""--with "marimo" --project {uv_project_with} """
53
58
  else:
54
- requirements = f"""--with "marimo" """
59
+ requirements = """--with "marimo" """
55
60
  fire_line = f"""
56
61
  cd {tmp_dir}
57
62
  uv run {requirements} marimo convert {pyfile.name} -o marimo_nb.py
@@ -214,7 +214,6 @@ def get_machineconfig_version() -> str:
214
214
  from importlib.metadata import PackageNotFoundError, version as _pkg_version
215
215
  from pathlib import Path
216
216
  import tomllib
217
-
218
217
  name: str = "machineconfig"
219
218
  try:
220
219
  return _pkg_version(name)
@@ -5,7 +5,7 @@ from typing import Any
5
5
 
6
6
 
7
7
  def get_import_module_string(py_file: str) -> str:
8
- from machineconfig.scripts.python.helpers_fire.helpers4 import get_import_module_code
8
+ from machineconfig.scripts.python.helpers_fire_command.file_wrangler import get_import_module_code
9
9
  from machineconfig.utils.accessories import get_repo_root
10
10
  from pathlib import Path
11
11
  repo_root = get_repo_root(Path(py_file))
@@ -230,8 +230,9 @@ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_modu
230
230
  if lines[-1].startswith("return "):
231
231
  lines[-1] = lines[-1].replace("return ", "# return ", 1)
232
232
  result_text = "\n".join(lines)
233
- if "Optional[" in result_text or "Any" in result_text or "Union[" in result_text or "Literal[" in result_text:
234
- result_text = "from typing import *\n\n" + result_text
233
+
234
+ if "Optional" in result_text or "Any" in result_text or "Union" in result_text or "Literal" in result_text:
235
+ result_text = "from typing import Optional, Any, Union, Literal\n\n" + result_text
235
236
 
236
237
  if import_prefix:
237
238
  result_text = f"{import_prefix}{result_text}"
@@ -77,7 +77,7 @@ def match_file_name(sub_string: str, search_root: PathExtended, suffixes: set[st
77
77
  if len(filename_matches) < 20:
78
78
  print("\n".join([a_potential_match.as_posix() for a_potential_match in filename_matches]))
79
79
  if len(filename_matches) > 1:
80
- print("Try to narrow down filename_matches search by case-sensitivity.")
80
+ print(f"Try to narrow down filename_matches search by case-sensitivity, found {len(filename_matches)} results. First @ {filename_matches[0].as_posix()}")
81
81
  # let's see if avoiding .lower() helps narrowing down to one result
82
82
  reduced_scripts = [a_potential_match for a_potential_match in filename_matches if sub_string in a_potential_match.name]
83
83
  if len(reduced_scripts) == 1:
@@ -139,8 +139,6 @@
139
139
  # start: datetime
140
140
  # end: datetime
141
141
  # status: str
142
-
143
- # @classmethod
144
142
  # def from_path(cls, path: PathExtended, return_default_if_not_found: bool=False):
145
143
  # if not path.exists():
146
144
  # if return_default_if_not_found:
@@ -6,7 +6,7 @@ capturing all user inputs collected during interactive execution.
6
6
 
7
7
  from pathlib import Path
8
8
  from typing import TypedDict, Literal, NotRequired
9
- from machineconfig.scripts.python.helpers_fire.fire_agents_help_launch import AGENTS
9
+ from machineconfig.scripts.python.helpers_agents.fire_agents_help_launch import AGENTS
10
10
 
11
11
  SEARCH_STRATEGIES = Literal["file_path", "keyword_search", "filename_pattern"]
12
12
 
@@ -8,7 +8,7 @@ from machineconfig.utils.terminal import Response
8
8
  from machineconfig.utils.accessories import pprint, randstr
9
9
  from machineconfig.utils.meta import lambda_to_python_script
10
10
  UV_RUN_CMD = "$HOME/.local/bin/uv run" if platform.system() != "Windows" else """& "$env:USERPROFILE/.local/bin/uv" run"""
11
- MACHINECONFIG_VERSION = "machineconfig>=6.84"
11
+ MACHINECONFIG_VERSION = "machineconfig>=6.86"
12
12
  DEFAULT_PICKLE_SUBDIR = "tmp_results/tmp_scripts/ssh"
13
13
 
14
14
  class SSH:
@@ -115,7 +115,7 @@ class SSH:
115
115
  self.tqdm_wrap = RichProgressWrapper
116
116
  from machineconfig.scripts.python.helpers_devops.cli_utils import get_machine_specs
117
117
  self.local_specs: MachineSpecs = get_machine_specs()
118
- resp = self.run_shell(command=f"""~/.local/bin/utils get-machine-specs """, verbose_output=False, description="Getting remote machine specs", strict_stderr=False, strict_return_code=False)
118
+ resp = self.run_shell(command="""~/.local/bin/utils get-machine-specs """, verbose_output=False, description="Getting remote machine specs", strict_stderr=False, strict_return_code=False)
119
119
  json_str = resp.op
120
120
  import ast
121
121
  self.remote_specs: MachineSpecs = cast(MachineSpecs, ast.literal_eval(json_str))