machineconfig 5.85__py3-none-any.whl → 5.87__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 (32) hide show
  1. machineconfig/jobs/installer/installer_data.json +6 -6
  2. machineconfig/profile/create_links_export.py +9 -9
  3. machineconfig/scripts/python/agents.py +17 -17
  4. machineconfig/scripts/python/croshell.py +1 -1
  5. machineconfig/scripts/python/devops.py +8 -6
  6. machineconfig/scripts/python/devops_helpers/cli_config.py +10 -10
  7. machineconfig/scripts/python/devops_helpers/cli_nw.py +7 -6
  8. machineconfig/scripts/python/devops_helpers/cli_repos.py +20 -20
  9. machineconfig/scripts/python/devops_helpers/cli_self.py +6 -6
  10. machineconfig/scripts/python/devops_helpers/cli_share_server.py +2 -9
  11. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +8 -8
  12. machineconfig/scripts/python/helpers_repos/grource.py +1 -1
  13. machineconfig/scripts/python/helpers_repos/secure_repo.py +6 -6
  14. machineconfig/scripts/python/interactive.py +2 -2
  15. machineconfig/scripts/python/nw/add_ssh_key.py +5 -5
  16. machineconfig/scripts/python/nw/devops_add_ssh_key.py +5 -5
  17. machineconfig/scripts/python/nw/mount_nfs +1 -1
  18. machineconfig/scripts/python/nw/ssh_debug_windows.py +338 -0
  19. machineconfig/scripts/python/repos_helpers/count_lines.py +4 -4
  20. machineconfig/scripts/python/repos_helpers/count_lines_frontend.py +3 -2
  21. machineconfig/scripts/python/sessions.py +15 -15
  22. machineconfig/scripts/python/sessions_helpers/sessions_multiprocess.py +4 -4
  23. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
  24. machineconfig/setup_linux/web_shortcuts/interactive.sh +1 -1
  25. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +1 -1
  26. machineconfig/utils/installer_utils/installer.py +5 -5
  27. machineconfig/utils/ssh.py +1 -1
  28. {machineconfig-5.85.dist-info → machineconfig-5.87.dist-info}/METADATA +2 -2
  29. {machineconfig-5.85.dist-info → machineconfig-5.87.dist-info}/RECORD +32 -31
  30. {machineconfig-5.85.dist-info → machineconfig-5.87.dist-info}/WHEEL +0 -0
  31. {machineconfig-5.85.dist-info → machineconfig-5.87.dist-info}/entry_points.txt +0 -0
  32. {machineconfig-5.85.dist-info → machineconfig-5.87.dist-info}/top_level.txt +0 -0
@@ -245,14 +245,14 @@
245
245
  "doc": "🔗 Easy file sharing tool",
246
246
  "fileNamePattern": {
247
247
  "amd64": {
248
- "linux": "npm install -g ezshare",
249
- "windows": "npm install -g ezshare",
250
- "macos": "npm install -g ezshare"
248
+ "linux": "npm i -g @ezshare/cli",
249
+ "windows": "npm i -g @ezshare/cli",
250
+ "macos": "npm i -g @ezshare/cli"
251
251
  },
252
252
  "arm64": {
253
- "linux": "npm install -g ezshare",
254
- "windows": "npm install -g ezshare",
255
- "macos": "npm install -g ezshare"
253
+ "linux": "npm i -g @ezshare/cli",
254
+ "windows": "npm i -g @ezshare/cli",
255
+ "macos": "npm i -g @ezshare/cli"
256
256
  }
257
257
  }
258
258
  },
@@ -1,12 +1,12 @@
1
1
 
2
2
  import typer
3
- from typing import Optional, Literal
3
+ from typing import Optional, Literal, Annotated
4
4
 
5
5
 
6
- def main_public_from_parser(method: Literal["symlink", "copy"] = typer.Option(..., help="Method to use for setting up the config file."),
7
- on_conflict: Literal["throwError", "overwriteDefaultPath", "backupDefaultPath"] = typer.Option(..., help="Action to take on conflict"),
8
- which: Optional[str] = typer.Option(None, help="Specific items to process"),
9
- interactive: bool = typer.Option(False, help="Run in interactive mode")):
6
+ def main_public_from_parser(method: Annotated[Literal["symlink", "copy"], typer.Option(..., help="Method to use for setting up the config file.")],
7
+ on_conflict: Annotated[Literal["throwError", "overwriteDefaultPath", "backupDefaultPath"], typer.Option(..., help="Action to take on conflict")],
8
+ which: Annotated[Optional[str], typer.Option(..., help="Specific items to process")] = None,
9
+ interactive: Annotated[bool, typer.Option(..., help="Run in interactive mode")] = False):
10
10
  """Terminology:
11
11
  SOURCE = Self-Managed-Config-File-Path
12
12
  TARGET = Config-File-Default-Path
@@ -31,10 +31,10 @@ def main_public_from_parser(method: Literal["symlink", "copy"] = typer.Option(..
31
31
  apply_mapper(mapper_data=items_objections, on_conflict=on_conflict, method=method)
32
32
 
33
33
 
34
- def main_private_from_parser(method: Literal["symlink", "copy"] = typer.Option(..., help="Method to use for linking files"),
35
- on_conflict: Literal["throwError", "overwriteSelfManaged", "backupSelfManaged", "overwriteDefaultPath", "backupDefaultPath"] = typer.Option("throwError", help="Action to take on conflict"),
36
- which: Optional[str] = typer.Option(None, help="Specific items to process"),
37
- interactive: bool = typer.Option(False, help="Run in interactive mode")):
34
+ def main_private_from_parser(method: Annotated[Literal["symlink", "copy"], typer.Option(..., help="Method to use for linking files")],
35
+ on_conflict: Annotated[Literal["throwError", "overwriteSelfManaged", "backupSelfManaged", "overwriteDefaultPath", "backupDefaultPath"], typer.Option(..., help="Action to take on conflict")] = "throwError",
36
+ which: Annotated[Optional[str], typer.Option(..., help="Specific items to process")] = None,
37
+ interactive: Annotated[bool, typer.Option(..., help="Run in interactive mode")] = False):
38
38
  from machineconfig.profile.create_links import ConfigMapper, read_mapper
39
39
 
40
40
  mapper_full = read_mapper()["private"]
@@ -3,25 +3,25 @@
3
3
  """
4
4
 
5
5
  from pathlib import Path
6
- from typing import cast, Optional, get_args
6
+ from typing import cast, Optional, get_args, Annotated
7
7
  import typer
8
8
  from machineconfig.scripts.python.helpers_fire.fire_agents_helper_types import AGENTS, HOST, MODEL, PROVIDER
9
9
 
10
10
 
11
11
  def create(
12
- agent: AGENTS = typer.Option(..., "--agents", "-a", help=f"Agent type. One of {', '.join(get_args(AGENTS)[:3])}"),
13
- host: HOST = typer.Option(..., "--host", "-h", help=f"Machine to run agents on. One of {', '.join(get_args(HOST))}"),
14
- model: MODEL = typer.Option(..., "--model", "-m", help=f"Model to use (for crush agent). One of {', '.join(get_args(MODEL)[:3])}"),
15
- provider: PROVIDER = typer.Option(..., "--provider", "-p", help=f"Provider to use (for crush agent). One of {', '.join(get_args(PROVIDER)[:3])}"),
16
- context_path: Optional[Path] = typer.Option(None, "--context-path", "-c", help="Path to the context file/folder, defaults to .ai/todo/"),
17
- separator: str = typer.Option("\n", "--separator", "-s", help="Separator for context"),
18
- agent_load: int = typer.Option(13, "--agent-load", "-al", help="Number of tasks per prompt"),
19
- prompt: Optional[str] = typer.Option(None, "--prompt", "-P", help="Prompt prefix as string"),
20
- prompt_path: Optional[Path] = typer.Option(None, "--prompt-path", "-pp", help="Path to prompt file"),
21
- job_name: str = typer.Option("AI_Agents", "--job-name", "-j", help="Job name"),
22
- separate: bool = typer.Option(True, "--separate", "-S", help="Keep prompt material in separate file to the context."),
23
- output_path: Optional[Path] = typer.Option(None, "--output-path", "-o", help="Path to write the layout.json file"),
24
- agents_dir: Optional[Path] = typer.Option(None, "--agents-dir", "-ad", help="Directory to store agent files. If not provided, will be constructed automatically."),
12
+ agent: Annotated[AGENTS, typer.Option(..., "--agents", "-a", help=f"Agent type. One of {', '.join(get_args(AGENTS)[:3])}")],
13
+ host: Annotated[HOST, typer.Option(..., "--host", "-h", help=f"Machine to run agents on. One of {', '.join(get_args(HOST))}")],
14
+ model: Annotated[MODEL, typer.Option(..., "--model", "-m", help=f"Model to use (for crush agent). One of {', '.join(get_args(MODEL)[:3])}")],
15
+ provider: Annotated[PROVIDER, typer.Option(..., "--provider", "-p", help=f"Provider to use (for crush agent). One of {', '.join(get_args(PROVIDER)[:3])}")],
16
+ context_path: Annotated[Optional[Path], typer.Option(..., "--context-path", "-c", help="Path to the context file/folder, defaults to .ai/todo/")] = None,
17
+ separator: Annotated[str, typer.Option(..., "--separator", "-s", help="Separator for context")] = "\n",
18
+ agent_load: Annotated[int, typer.Option(..., "--agent-load", "-al", help="Number of tasks per prompt")] = 13,
19
+ prompt: Annotated[Optional[str], typer.Option(..., "--prompt", "-P", help="Prompt prefix as string")] = None,
20
+ prompt_path: Annotated[Optional[Path], typer.Option(..., "--prompt-path", "-pp", help="Path to prompt file")] = None,
21
+ job_name: Annotated[str, typer.Option(..., "--job-name", "-j", help="Job name")] = "AI_Agents",
22
+ separate: Annotated[bool, typer.Option(..., "--separate", "-S", help="Keep prompt material in separate file to the context.")] = True,
23
+ output_path: Annotated[Optional[Path], typer.Option(..., "--output-path", "-o", help="Path to write the layout.json file")] = None,
24
+ agents_dir: Annotated[Optional[Path], typer.Option(..., "--agents-dir", "-ad", help="Directory to store agent files. If not provided, will be constructed automatically.")] = None,
25
25
  ):
26
26
 
27
27
  from machineconfig.scripts.python.helpers_fire.fire_agents_help_launch import prep_agent_launch, get_agents_launch_layout
@@ -94,9 +94,9 @@ agents create "{context_path_resolved}" \\
94
94
 
95
95
 
96
96
  def collect(
97
- agent_dir: str = typer.Argument(..., help="Path to the agent directory containing the prompts folder"),
98
- output_path: str = typer.Argument(..., help="Path to write the concatenated material files"),
99
- separator: str = typer.Option("\n", help="Separator to use when concatenating material files"),
97
+ agent_dir: Annotated[str, typer.Argument(..., help="Path to the agent directory containing the prompts folder")],
98
+ output_path: Annotated[str, typer.Argument(..., help="Path to write the concatenated material files")],
99
+ separator: Annotated[str, typer.Option(..., help="Separator to use when concatenating material files")] = "\n",
100
100
  ) -> None:
101
101
  """Collect all material files from an agent directory and concatenate them."""
102
102
  if not Path(agent_dir).exists() or not Path(agent_dir).is_dir():
@@ -149,7 +149,7 @@ from pathlib import Path
149
149
  else:
150
150
  console.print(Panel("❌ Could not determine the local machineconfig repo root. Please ensure the `REPO_ROOT` in `source_of_truth.py` is correctly set to the local path of the machineconfig repo, or do not use the `--local` flag.", title="Error", border_style="red"))
151
151
  return
152
- else: ve_line = """--with "machineconfig[plot]>=5.84" """
152
+ else: ve_line = """--with "machineconfig[plot]>=5.87" """
153
153
  fire_line = f"uv run --python 3.14 {ve_line} {interpreter} {interactivity} {profile} {str(pyfile)}"
154
154
 
155
155
  from machineconfig.utils.code import run_shell_script
@@ -1,7 +1,7 @@
1
1
  """devops with emojis"""
2
2
 
3
3
  import typer
4
- from typing import Optional
4
+ from typing import Optional, Annotated
5
5
 
6
6
  import machineconfig.scripts.python.devops_helpers.cli_repos as cli_repos
7
7
  import machineconfig.scripts.python.devops_helpers.cli_config as cli_config
@@ -10,15 +10,17 @@ import machineconfig.scripts.python.devops_helpers.cli_data as cli_data
10
10
  import machineconfig.scripts.python.devops_helpers.cli_nw as cli_network
11
11
 
12
12
 
13
- def get_app():
14
- app = typer.Typer(help="🛠️ DevOps operations", no_args_is_help=True, add_completion=True)
15
- def install(which: Optional[str] = typer.Argument(None, help="Comma-separated list of program names to install, or group name if --group flag is set."),
16
- group: bool = typer.Option(False, "--group", "-g", help="Treat 'which' as a group name. A group is bundle of apps."),
17
- interactive: bool = typer.Option(False, "--interactive", "-ia", help="Interactive selection of programs to install."),
13
+ def install(which: Annotated[Optional[str], typer.Argument(..., help="Comma-separated list of program names to install, or group name if --group flag is set.")],
14
+ group: Annotated[bool, typer.Option(..., "--group", "-g", help="Treat 'which' as a group name. A group is bundle of apps.")] = False,
15
+ interactive: Annotated[bool, typer.Option(..., "--interactive", "-ia", help="Interactive selection of programs to install.")] = False,
18
16
  ) -> None:
19
17
  """📦 Install essential packages"""
20
18
  import machineconfig.utils.installer_utils.installer as installer_entry_point
21
19
  installer_entry_point.main(which=which, group=group, interactive=interactive)
20
+
21
+
22
+ def get_app():
23
+ app = typer.Typer(help="🛠️ DevOps operations", no_args_is_help=True, add_completion=True)
22
24
  _ = install
23
25
  app.command("install", no_args_is_help=True, help="🛠️ [i] Install essential packages")(install)
24
26
  app.command("i", no_args_is_help=True, help="Install essential packages", hidden=True)(install)
@@ -6,18 +6,18 @@ import typer
6
6
 
7
7
 
8
8
 
9
- def private(method: Literal["symlink", "copy"] = typer.Option(..., "--method", "-m", help="Method to use for linking files"),
10
- on_conflict: Literal["throwError", "overwriteSelfManaged", "backupSelfManaged", "overwriteDefaultPath", "backupDefaultPath"] = typer.Option("throwError", "--on-conflict", "-o", help="Action to take on conflict"),
11
- which: Optional[str] = typer.Option(None, "--which", "-w", help="Specific items to process"),
12
- interactive: bool = typer.Option(False, "--interactive", "-ia", help="Run in interactive mode")):
9
+ def private(method: Annotated[Literal["symlink", "copy"], typer.Option(..., "--method", "-m", help="Method to use for linking files")],
10
+ on_conflict: Annotated[Literal["throwError", "overwriteSelfManaged", "backupSelfManaged", "overwriteDefaultPath", "backupDefaultPath"], typer.Option(..., "--on-conflict", "-o", help="Action to take on conflict")] = "throwError",
11
+ which: Annotated[Optional[str], typer.Option(..., "--which", "-w", help="Specific items to process")] = None,
12
+ interactive: Annotated[bool, typer.Option(..., "--interactive", "-ia", help="Run in interactive mode")] = False):
13
13
  """🔗 Manage private configuration files."""
14
14
  import machineconfig.profile.create_links_export as create_links_export
15
15
  create_links_export.main_private_from_parser(method=method, on_conflict=on_conflict, which=which, interactive=interactive)
16
16
 
17
- def public(method: Literal["symlink", "copy"] = typer.Option(..., "--method", "-m", help="Method to use for setting up the config file."),
18
- on_conflict: Literal["throwError", "overwriteDefaultPath", "backupDefaultPath"] = typer.Option("throwError", "--on-conflict", "-o", help="Action to take on conflict"),
19
- which: Optional[str] = typer.Option(None, "--which", "-w", help="Specific items to process"),
20
- interactive: bool = typer.Option(False, "--interactive", "-ia", help="Run in interactive mode")):
17
+ def public(method: Annotated[Literal["symlink", "copy"], typer.Option(..., "--method", "-m", help="Method to use for setting up the config file.")],
18
+ on_conflict: Annotated[Literal["throwError", "overwriteDefaultPath", "backupDefaultPath"], typer.Option(..., "--on-conflict", "-o", help="Action to take on conflict")] = "throwError",
19
+ which: Annotated[Optional[str], typer.Option(..., "--which", "-w", help="Specific items to process")] = None,
20
+ interactive: Annotated[bool, typer.Option(..., "--interactive", "-ia", help="Run in interactive mode")] = False):
21
21
  """🔗 Manage public configuration files."""
22
22
  import machineconfig.profile.create_links_export as create_links_export
23
23
  create_links_export.main_public_from_parser(method=method, on_conflict=on_conflict, which=which, interactive=interactive)
@@ -42,7 +42,7 @@ def path():
42
42
  from pathlib import Path
43
43
  path = Path(navigator.__file__).resolve().parent.joinpath("path_manager_tui.py")
44
44
  from machineconfig.utils.code import run_shell_script
45
- run_shell_script(f"""uv run --with "machineconfig>=5.84,textual" {path}""")
45
+ run_shell_script(f"""uv run --with "machineconfig>=5.87,textual" {path}""")
46
46
 
47
47
  def pwsh_theme():
48
48
  """🔗 Select powershell prompt theme."""
@@ -51,7 +51,7 @@ def pwsh_theme():
51
51
  import subprocess
52
52
  subprocess.run(["pwsh", "-File", str(file)])
53
53
 
54
- def copy_assets(which: Literal["scripts", "settings", "both"] = typer.Argument(..., help="Which assets to copy")):
54
+ def copy_assets(which: Annotated[Literal["scripts", "settings", "both"], typer.Argument(..., help="Which assets to copy")]):
55
55
  """🔗 Copy asset files from library to machine."""
56
56
  import machineconfig.profile.create_helper as create_helper
57
57
  match which:
@@ -2,7 +2,7 @@
2
2
  import machineconfig.scripts.python.devops_helpers.cli_terminal as cli_terminal
3
3
  import machineconfig.scripts.python.devops_helpers.cli_share_server as cli_share_server
4
4
  import typer
5
- from typing import Optional
5
+ from typing import Optional, Annotated
6
6
 
7
7
 
8
8
 
@@ -19,10 +19,10 @@ def install_ssh_server():
19
19
  run_shell_script(script=SSH_SERVER.read_text(encoding="utf-8"))
20
20
 
21
21
 
22
- def add_ssh_key(path: Optional[str] = typer.Option(None, help="Path to the public key file"),
23
- choose: bool = typer.Option(False, "--choose", "-c", help="Choose from available public keys in ~/.ssh/*.pub"),
24
- value: bool = typer.Option(False, "--value", "-v", help="Paste the public key content manually"),
25
- github: Optional[str] = typer.Option(None, "--github", "-g", help="Fetch public keys from a GitHub username")
22
+ def add_ssh_key(path: Annotated[Optional[str], typer.Option(..., help="Path to the public key file")] = None,
23
+ choose: Annotated[bool, typer.Option(..., "--choose", "-c", help="Choose from available public keys in ~/.ssh/*.pub")] = False,
24
+ value: Annotated[bool, typer.Option(..., "--value", "-v", help="Paste the public key content manually")] = False,
25
+ github: Annotated[Optional[str], typer.Option(..., "--github", "-g", help="Fetch public keys from a GitHub username")] = None
26
26
  ):
27
27
  """🔑 SSH add pub key to this machine so its accessible by owner of corresponding private key."""
28
28
  import machineconfig.scripts.python.nw.devops_add_ssh_key as helper
@@ -49,7 +49,8 @@ def debug_ssh():
49
49
  import machineconfig.scripts.python.nw.ssh_debug_linux as helper
50
50
  helper.ssh_debug_linux()
51
51
  elif system() == "Windows":
52
- raise NotImplementedError("SSH debug for Windows is not implemented yet.")
52
+ import machineconfig.scripts.python.nw.ssh_debug_windows as helper
53
+ helper.ssh_debug_windows()
53
54
  else:
54
55
  raise NotImplementedError(f"Platform {system()} is not supported.")
55
56
 
@@ -87,26 +87,26 @@ def analyze(directory: DirectoryArgument = None) -> None:
87
87
 
88
88
 
89
89
  def viz(
90
- repo: str = typer.Option(Path.cwd().__str__(), "--repo", "-r", help="Path to git repository to visualize"),
91
- output_file: Optional[Path] = typer.Option(None, "--output", "-o", help="Output video file (e.g., output.mp4). If specified, gource will render to video."),
92
- resolution: str = typer.Option("1920x1080", "--resolution", "-res", help="Video resolution (e.g., 1920x1080, 1280x720)"),
93
- seconds_per_day: float = typer.Option(0.1, "--seconds-per-day", "-spd", help="Speed of simulation (lower = faster)"),
94
- auto_skip_seconds: float = typer.Option(1.0, "--auto-skip-seconds", "-as", help="Skip to next entry if nothing happens for X seconds"),
95
- title: Optional[str] = typer.Option(None, "--title", "-t", help="Title for the visualization"),
96
- hide_items: list[str] = typer.Option([], "--hide", "-h", help="Items to hide: bloom, date, dirnames, files, filenames, mouse, progress, root, tree, users, usernames"),
97
- key_items: bool = typer.Option(False, "--key", "-k", help="Show file extension key"),
98
- fullscreen: bool = typer.Option(False, "--fullscreen", "-f", help="Run in fullscreen mode"),
99
- viewport: Optional[str] = typer.Option(None, "--viewport", "-v", help="Camera viewport (e.g., '1000x1000')"),
100
- start_date: Optional[str] = typer.Option(None, "--start-date", help="Start date (YYYY-MM-DD)"),
101
- stop_date: Optional[str] = typer.Option(None, "--stop-date", help="Stop date (YYYY-MM-DD)"),
102
- user_image_dir: Optional[Path] = typer.Option(None, "--user-image-dir", help="Directory with user avatar images"),
103
- max_files: int = typer.Option(0, "--max-files", help="Maximum number of files to show (0 = no limit)"),
104
- max_file_lag: float = typer.Option(5.0, "--max-file-lag", help="Max time files remain on screen after last change"),
105
- file_idle_time: int = typer.Option(0, "--file-idle-time", help="Time in seconds files remain idle before being removed"),
106
- framerate: int = typer.Option(60, "--framerate", help="Frames per second for video output"),
107
- background_color: str = typer.Option("000000", "--background-color", help="Background color in hex (e.g., 000000 for black)"),
108
- font_size: int = typer.Option(22, "--font-size", help="Font size"),
109
- camera_mode: str = typer.Option("overview", "--camera-mode", help="Camera mode: overview or track"),
90
+ repo: Annotated[str, typer.Option(..., "--repo", "-r", help="Path to git repository to visualize")] = Path.cwd().__str__(),
91
+ output_file: Annotated[Optional[Path], typer.Option(..., "--output", "-o", help="Output video file (e.g., output.mp4). If specified, gource will render to video.")] = None,
92
+ resolution: Annotated[str, typer.Option(..., "--resolution", "-res", help="Video resolution (e.g., 1920x1080, 1280x720)")] = "1920x1080",
93
+ seconds_per_day: Annotated[float, typer.Option(..., "--seconds-per-day", "-spd", help="Speed of simulation (lower = faster)")] = 0.1,
94
+ auto_skip_seconds: Annotated[float, typer.Option(..., "--auto-skip-seconds", "-as", help="Skip to next entry if nothing happens for X seconds")] = 1.0,
95
+ title: Annotated[Optional[str], typer.Option(..., "--title", "-t", help="Title for the visualization")] = None,
96
+ hide_items: Annotated[list[str], typer.Option(..., "--hide", "-h", help="Items to hide: bloom, date, dirnames, files, filenames, mouse, progress, root, tree, users, usernames")] = [],
97
+ key_items: Annotated[bool, typer.Option(..., "--key", "-k", help="Show file extension key")] = False,
98
+ fullscreen: Annotated[bool, typer.Option(..., "--fullscreen", "-f", help="Run in fullscreen mode")] = False,
99
+ viewport: Annotated[Optional[str], typer.Option(..., "--viewport", "-v", help="Camera viewport (e.g., '1000x1000')")] = None,
100
+ start_date: Annotated[Optional[str], typer.Option(..., "--start-date", help="Start date (YYYY-MM-DD)")] = None,
101
+ stop_date: Annotated[Optional[str], typer.Option(..., "--stop-date", help="Stop date (YYYY-MM-DD)")] = None,
102
+ user_image_dir: Annotated[Optional[Path], typer.Option(..., "--user-image-dir", help="Directory with user avatar images")] = None,
103
+ max_files: Annotated[int, typer.Option(..., "--max-files", help="Maximum number of files to show (0 = no limit)")] = 0,
104
+ max_file_lag: Annotated[float, typer.Option(..., "--max-file-lag", help="Max time files remain on screen after last change")] = 5.0,
105
+ file_idle_time: Annotated[int, typer.Option(..., "--file-idle-time", help="Time in seconds files remain idle before being removed")] = 0,
106
+ framerate: Annotated[int, typer.Option(..., "--framerate", help="Frames per second for video output")] = 60,
107
+ background_color: Annotated[str, typer.Option(..., "--background-color", help="Background color in hex (e.g., 000000 for black)")] = "000000",
108
+ font_size: Annotated[int, typer.Option(..., "--font-size", help="Font size")] = 22,
109
+ camera_mode: Annotated[str, typer.Option(..., "--camera-mode", help="Camera mode: overview or track")] = "overview",
110
110
  ) -> None:
111
111
  """🎬 Visualize repository activity using Gource."""
112
112
  from machineconfig.scripts.python.helpers_repos.grource import visualize
@@ -1,6 +1,6 @@
1
1
 
2
2
  import typer
3
- from typing import Optional
3
+ from typing import Optional, Annotated
4
4
 
5
5
 
6
6
  def update():
@@ -41,9 +41,9 @@ def install():
41
41
  # main_public_from_parser()
42
42
  import platform
43
43
  if platform.system() == "Windows":
44
- run_shell_script(r"""$HOME\.local\bin\uv.exe tool install machineconfig>=5.84""")
44
+ run_shell_script(r"""$HOME\.local\bin\uv.exe tool install machineconfig>=5.87""")
45
45
  else:
46
- run_shell_script("""$HOME/.local/bin/uv tool install machineconfig>=5.84""")
46
+ run_shell_script("""$HOME/.local/bin/uv tool install machineconfig>=5.87""")
47
47
 
48
48
  def navigate():
49
49
  """📚 NAVIGATE command structure with TUI"""
@@ -51,11 +51,11 @@ def navigate():
51
51
  from pathlib import Path
52
52
  path = Path(navigator.__file__).resolve().parent.joinpath("devops_navigator.py")
53
53
  from machineconfig.utils.code import run_shell_script
54
- run_shell_script(f"""uv run --with "machineconfig>=5.84,textual" {path}""")
54
+ run_shell_script(f"""uv run --with "machineconfig>=5.87,textual" {path}""")
55
55
 
56
56
 
57
- def run_python(ip: str = typer.Argument(..., help="Python command to run in the machineconfig environment"),
58
- command: Optional[bool] = typer.Option(False, "--command", "-c", help="Run as command")):
57
+ def run_python(ip: Annotated[str, typer.Argument(..., help="Python command to run in the machineconfig environment")],
58
+ command: Annotated[Optional[bool], typer.Option(..., "--command", "-c", help="Run as command")] = False):
59
59
  """🐍 RUN python command/file in the machineconfig environment"""
60
60
  if command:
61
61
  exec(ip)
@@ -1,19 +1,15 @@
1
1
  from pathlib import Path
2
2
  from typing import Optional, Annotated
3
3
  import typer
4
- # import typer
5
-
6
4
 
7
5
 
8
6
  def display_share_url(local_ip_v4: str, port: int, protocol: str = "http") -> None:
9
7
  """Display a flashy, unmissable share URL announcement."""
10
-
11
8
  from rich.console import Console
12
9
  from rich.panel import Panel
13
10
  from rich.text import Text
14
11
  from rich.align import Align
15
12
  console = Console()
16
-
17
13
  # Create the main message with styling
18
14
  url_text = Text(f"{protocol}://{local_ip_v4}:{port}", style="bold bright_cyan underline")
19
15
  message = Text.assemble(
@@ -22,7 +18,6 @@ def display_share_url(local_ip_v4: str, port: int, protocol: str = "http") -> No
22
18
  url_text,
23
19
  (" 🚀", "bright_red")
24
20
  )
25
-
26
21
  # Create a fancy panel with borders and styling
27
22
  panel = Panel(
28
23
  Align.center(message),
@@ -32,7 +27,6 @@ def display_share_url(local_ip_v4: str, port: int, protocol: str = "http") -> No
32
27
  padding=(1, 2),
33
28
  expand=False
34
29
  )
35
-
36
30
  # Print with extra spacing and attention-grabbing elements
37
31
  console.print(panel)
38
32
 
@@ -45,9 +39,8 @@ def main(
45
39
  over_internet: Annotated[bool, typer.Option("--over-internet", "-i", help="Expose the share server over the internet using ngrok")] = False
46
40
  ) -> None:
47
41
  from machineconfig.utils.installer_utils.installer import install_if_missing
48
- install_if_missing("ezshare")
49
- if over_internet: install_if_missing("ngrok")
50
-
42
+ install_if_missing(which="ezshare")
43
+ if over_internet: install_if_missing(which="ngrok", )
51
44
  if username is None:
52
45
  import getpass
53
46
  username = getpass.getuser()
@@ -10,18 +10,18 @@ from machineconfig.utils.code import get_shell_file_executing_python_script, wri
10
10
 
11
11
  import platform
12
12
  import subprocess
13
- from typing import Optional, Literal
13
+ from typing import Optional, Literal, Annotated
14
14
 
15
15
 
16
16
  console = Console()
17
17
 
18
18
 
19
19
  def main(
20
- cloud: Optional[str] = typer.Option(None, "--cloud", "-c", help="Cloud storage profile name. If not provided, uses default from config."),
21
- repo: Optional[str] = typer.Option(None, "--repo", "-r", help="Path to the local repository. Defaults to current working directory."),
22
- message: Optional[str] = typer.Option(None, "--message", "-m", help="Commit message for local changes."),
23
- on_conflict: Literal["ask", "push-local-merge", "overwrite-local", "stop-on-conflict", "remove-rclone-conflict"] = typer.Option("ask", "--on-conflict", "-oc", help="Action to take on merge conflict. Default is 'ask'."),
24
- pwd: Optional[str] = typer.Option(None, "--password", help="Password for encryption/decryption of the remote repository."),
20
+ cloud: Annotated[Optional[str], typer.Option(..., "--cloud", "-c", help="Cloud storage profile name. If not provided, uses default from config.")] = None,
21
+ repo: Annotated[Optional[str], typer.Option(..., "--repo", "-r", help="Path to the local repository. Defaults to current working directory.")] = None,
22
+ message: Annotated[Optional[str], typer.Option(..., "--message", "-m", help="Commit message for local changes.")] = None,
23
+ on_conflict: Annotated[Literal["ask", "push-local-merge", "overwrite-local", "stop-on-conflict", "remove-rclone-conflict"], typer.Option(..., "--on-conflict", "-oc", help="Action to take on merge conflict. Default is 'ask'.")] = "ask",
24
+ pwd: Annotated[Optional[str], typer.Option(..., "--password", help="Password for encryption/decryption of the remote repository.")] = None,
25
25
  ):
26
26
  if cloud is None:
27
27
  try:
@@ -101,7 +101,7 @@ git pull originEnc master
101
101
  return "done"
102
102
  from machineconfig.utils.meta import function_to_script
103
103
  program_1_py = function_to_script(func=func2, call_with_args=None, call_with_kwargs={"remote_repo": str(repo_remote_root), "local_repo": str(repo_local_root), "cloud": cloud_resolved})
104
- shell_file_1 = get_shell_file_executing_python_script(python_script=program_1_py, ve_path=None, executable="""uv run --with "machineconfig>=5.84" """)
104
+ shell_file_1 = get_shell_file_executing_python_script(python_script=program_1_py, ve_path=None, executable="""uv run --with "machineconfig>=5.87" """)
105
105
  # ================================================================================
106
106
  option2 = "Delete local repo and replace it with remote copy:"
107
107
  program_2 = f"""
@@ -122,7 +122,7 @@ sudo chmod +x $HOME/dotfiles/scripts/linux -R
122
122
  inspect_repos(repo_local_root=repo_local_root, repo_remote_root=repo_remote_root)
123
123
  return "done"
124
124
  program_3_py = function_to_script(func=func, call_with_args=None, call_with_kwargs={"repo_local_root": str(repo_local_root), "repo_remote_root": str(repo_remote_root)})
125
- shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, ve_path=None, executable="""uv run --with "machineconfig>=5.84" """)
125
+ shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, ve_path=None, executable="""uv run --with "machineconfig>=5.87" """)
126
126
  # ================================================================================
127
127
 
128
128
  option4 = "Remove problematic rclone file from repo and replace with remote:"
@@ -319,7 +319,7 @@ def visualize(
319
319
 
320
320
 
321
321
  def install(
322
- version: Optional[str] = typer.Option("0.53", "--version", "-v", help="Gource version to install"),
322
+ version: Annotated[Optional[str], typer.Option(..., "--version", "-v", help="Gource version to install")] = "0.53",
323
323
  ) -> None:
324
324
  """Install portable Gource on Windows (no admin privileges required)."""
325
325
  if platform.system() == "Windows":
@@ -1,15 +1,15 @@
1
1
 
2
2
  import typer
3
- from typing import Optional, Literal
3
+ from typing import Optional, Literal, Annotated
4
4
  from pathlib import Path
5
5
 
6
6
 
7
7
  def main(
8
- cloud: Optional[str] = typer.Option(None, "--cloud", "-c", help="Cloud storage profile name. If not provided, uses default from config."),
9
- repo: Optional[str] = typer.Option(Path.cwd().as_posix(), "--repo", "-r", help="Path to the local repository. Defaults to cwd."),
10
- message: Optional[str] = typer.Option(None, "--message", "-m", help="Commit message for local changes."),
11
- on_conflict: Literal["ask", "push-local-merge", "overwrite-local", "stop-on-conflict", "remove-rclone-conflict"] = typer.Option("ask", "--on-conflict", "-oc", help="Action to take on merge conflict. Default is 'ask'."),
12
- pwd: Optional[str] = typer.Option(None, "--password", help="Password for encryption/decryption of the remote repository."),
8
+ cloud: Annotated[Optional[str], typer.Option(..., "--cloud", "-c", help="Cloud storage profile name. If not provided, uses default from config.")] = None,
9
+ repo: Annotated[Optional[str], typer.Option(..., "--repo", "-r", help="Path to the local repository. Defaults to cwd.")] = Path.cwd().as_posix(),
10
+ message: Annotated[Optional[str], typer.Option(..., "--message", "-m", help="Commit message for local changes.")] = None,
11
+ on_conflict: Annotated[Literal["ask", "push-local-merge", "overwrite-local", "stop-on-conflict", "remove-rclone-conflict"], typer.Option(..., "--on-conflict", "-oc", help="Action to take on merge conflict. Default is 'ask'.")] = "ask",
12
+ pwd: Annotated[Optional[str], typer.Option(..., "--password", help="Password for encryption/decryption of the remote repository.")] = None,
13
13
  ):
14
14
  from machineconfig.scripts.python.helpers_repos.cloud_repo_sync import main as program_content
15
15
  program_content(cloud=cloud, repo=repo, message=message, on_conflict=on_conflict, pwd=pwd)
@@ -130,9 +130,9 @@ def execute_installations(selected_options: list[str]) -> None:
130
130
  console.print(Panel("🐍 [bold green]PYTHON ENVIRONMENT[/bold green]\n[italic]Virtual environment setup[/italic]", border_style="green"))
131
131
  import platform
132
132
  if platform.system() == "Windows":
133
- run_shell_script(r"""$HOME\.local\bin\uv.exe tool install machineconfig>=5.84""")
133
+ run_shell_script(r"""$HOME\.local\bin\uv.exe tool install machineconfig>=5.87""")
134
134
  else:
135
- run_shell_script("""$HOME/.local/bin/uv tool install machineconfig>=5.84""")
135
+ run_shell_script("""$HOME/.local/bin/uv tool install machineconfig>=5.87""")
136
136
  if "install_ssh_server" in selected_options:
137
137
  console.print(Panel("🔒 [bold red]SSH SERVER[/bold red]\n[italic]Remote access setup[/italic]", border_style="red"))
138
138
  import platform
@@ -6,7 +6,7 @@ from machineconfig.utils.path_extended import PathExtended
6
6
  from rich.console import Console
7
7
  from rich.panel import Panel
8
8
  from rich import box # Import box
9
- from typing import Optional
9
+ from typing import Optional, Annotated
10
10
  import typer
11
11
 
12
12
 
@@ -77,10 +77,10 @@ sudo service ssh --full-restart
77
77
  """
78
78
 
79
79
 
80
- def main(pub_path: Optional[str] = typer.Argument(None, help="Path to the public key file"),
81
- pub_choose: bool = typer.Option(False, "--choose", "-c", help="Choose from available public keys in ~/.ssh"),
82
- pub_val: bool = typer.Option(False, "--paste", "-p", help="Paste the public key content manually"),
83
- from_github: Optional[str] = typer.Option(None, "--from-github", "-g", help="Fetch public keys from a GitHub username")
80
+ def main(pub_path: Annotated[Optional[str], typer.Argument(..., help="Path to the public key file")] = None,
81
+ pub_choose: Annotated[bool, typer.Option(..., "--choose", "-c", help="Choose from available public keys in ~/.ssh")] = False,
82
+ pub_val: Annotated[bool, typer.Option(..., "--paste", "-p", help="Paste the public key content manually")] = False,
83
+ from_github: Annotated[Optional[str], typer.Option(..., "--from-github", "-g", help="Fetch public keys from a GitHub username")] = None
84
84
  ) -> None:
85
85
  if pub_path:
86
86
  key_path = PathExtended(pub_path).expanduser().absolute()
@@ -6,7 +6,7 @@ from machineconfig.utils.path_extended import PathExtended
6
6
  from rich.console import Console
7
7
  from rich.panel import Panel
8
8
  from rich import box
9
- from typing import Optional
9
+ from typing import Optional, Annotated
10
10
  import typer
11
11
 
12
12
 
@@ -66,10 +66,10 @@ sudo service ssh --full-restart
66
66
  return program
67
67
 
68
68
 
69
- def main(pub_path: Optional[str] = typer.Argument(None, help="Path to the public key file"),
70
- pub_choose: bool = typer.Option(False, "--choose", "-c", help="Choose from available public keys in ~/.ssh"),
71
- pub_val: bool = typer.Option(False, "--paste", "-p", help="Paste the public key content manually"),
72
- from_github: Optional[str] = typer.Option(None, "--from-github", "-g", help="Fetch public keys from a GitHub username")
69
+ def main(pub_path: Annotated[Optional[str], typer.Argument(..., help="Path to the public key file")] = None,
70
+ pub_choose: Annotated[bool, typer.Option(..., "--choose", "-c", help="Choose from available public keys in ~/.ssh")] = False,
71
+ pub_val: Annotated[bool, typer.Option(..., "--paste", "-p", help="Paste the public key content manually")] = False,
72
+ from_github: Annotated[Optional[str], typer.Option(..., "--from-github", "-g", help="Fetch public keys from a GitHub username")] = None
73
73
  ) -> None:
74
74
 
75
75
  if pub_path:
@@ -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>=5.84" python -m machineconfig.scripts.python.mount_nfs
8
+ uv run --python 3.14 --with "machineconfig>=5.87" 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."