machineconfig 5.36__py3-none-any.whl → 5.38__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 (91) hide show
  1. machineconfig/cluster/remote/script_execution.py +0 -1
  2. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +0 -2
  3. machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +12 -12
  4. machineconfig/jobs/installer/installer_data.json +53 -2
  5. machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -3
  6. machineconfig/scripts/linux/{share_cloud.sh → other/share_cloud.sh} +3 -0
  7. machineconfig/scripts/python/ai/solutions/generic.py +1 -0
  8. machineconfig/scripts/python/croshell.py +5 -2
  9. machineconfig/scripts/python/devops.py +4 -21
  10. machineconfig/scripts/python/devops_helpers/cli_nw.py +2 -1
  11. machineconfig/scripts/python/devops_helpers/cli_repos.py +1 -3
  12. machineconfig/scripts/python/devops_helpers/cli_self.py +6 -6
  13. machineconfig/scripts/python/devops_helpers/cli_share_server.py +109 -0
  14. machineconfig/scripts/python/devops_helpers/cli_terminal.py +35 -23
  15. machineconfig/scripts/python/devops_helpers/devops_add_ssh_key.py +0 -1
  16. machineconfig/scripts/python/devops_helpers/devops_update_repos.py +63 -44
  17. machineconfig/scripts/python/devops_helpers/themes/choose_pwsh_theme.ps1 +16 -15
  18. machineconfig/scripts/python/devops_navigator.py +183 -80
  19. machineconfig/scripts/python/helpers_fire/{fire_gemini.py → agentic_frameworks/fire_gemini.py} +12 -9
  20. machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_qwen.py +43 -0
  21. machineconfig/scripts/python/helpers_fire/fire_agents_help_launch.py +4 -4
  22. machineconfig/scripts/python/helpers_fire/template.ps1 +29 -0
  23. machineconfig/scripts/python/interactive.py +3 -2
  24. machineconfig/scripts/python/nw/mount_nw_drive +1 -2
  25. machineconfig/scripts/python/repos_helpers/update.py +1 -1
  26. machineconfig/scripts/windows/mounts/share_nfs.ps1 +0 -0
  27. machineconfig/settings/lf/linux/lfrc +0 -2
  28. machineconfig/settings/lf/windows/lfrc +0 -4
  29. machineconfig/settings/shells/bash/commands.sh +24 -0
  30. machineconfig/settings/shells/bash/init.sh +5 -0
  31. machineconfig/settings/shells/pwsh/commands.ps1 +33 -0
  32. machineconfig/settings/shells/pwsh/init.ps1 +4 -0
  33. machineconfig/setup_linux/web_shortcuts/interactive.sh +1 -2
  34. machineconfig/setup_windows/machineconfig.ps1 +2 -0
  35. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +1 -1
  36. machineconfig/utils/files/dbms.py +4 -1
  37. machineconfig/utils/installer_utils/installer.py +12 -0
  38. machineconfig/utils/installer_utils/installer_abc.py +26 -9
  39. machineconfig/utils/installer_utils/installer_class.py +1 -1
  40. machineconfig/utils/io.py +0 -18
  41. machineconfig/utils/scheduler.py +3 -4
  42. {machineconfig-5.36.dist-info → machineconfig-5.38.dist-info}/METADATA +7 -4
  43. {machineconfig-5.36.dist-info → machineconfig-5.38.dist-info}/RECORD +63 -86
  44. machineconfig/jobs/windows/start_terminal.ps1 +0 -6
  45. machineconfig/jobs/windows/startup_file.cmd +0 -2
  46. machineconfig/scripts/cloud/init.sh +0 -105
  47. machineconfig/scripts/linux/agents +0 -2
  48. machineconfig/scripts/linux/cloud +0 -2
  49. machineconfig/scripts/linux/croshell +0 -3
  50. machineconfig/scripts/linux/devops +0 -2
  51. machineconfig/scripts/linux/fire +0 -2
  52. machineconfig/scripts/linux/ftpx +0 -2
  53. machineconfig/scripts/linux/kill_process +0 -2
  54. machineconfig/scripts/linux/sessions +0 -2
  55. machineconfig/scripts/linux/start_terminals +0 -3
  56. machineconfig/scripts/windows/agents.ps1 +0 -1
  57. machineconfig/scripts/windows/cloud.ps1 +0 -1
  58. machineconfig/scripts/windows/croshell.ps1 +0 -1
  59. machineconfig/scripts/windows/devops.ps1 +0 -1
  60. machineconfig/scripts/windows/fire.ps1 +0 -1
  61. machineconfig/scripts/windows/ftpx.ps1 +0 -1
  62. machineconfig/scripts/windows/gpt.ps1 +0 -1
  63. machineconfig/scripts/windows/grep.ps1 +0 -2
  64. machineconfig/scripts/windows/kill_process.ps1 +0 -1
  65. machineconfig/scripts/windows/nano.ps1 +0 -3
  66. machineconfig/scripts/windows/scheduler.ps1 +0 -1
  67. machineconfig/scripts/windows/sessions.ps1 +0 -1
  68. machineconfig/scripts/windows/snapshot.ps1 +0 -1
  69. machineconfig/scripts/windows/start_terminals.ps1 +0 -1
  70. machineconfig/scripts/windows/wsl_rdp_windows_port_forwarding.ps1 +0 -46
  71. machineconfig/scripts/windows/wsl_ssh_windows_port_forwarding.ps1 +0 -76
  72. /machineconfig/scripts/linux/{share_nfs → other/share_nfs} +0 -0
  73. /machineconfig/scripts/linux/{share_smb → other/share_smb} +0 -0
  74. /machineconfig/scripts/linux/{start_docker → other/start_docker} +0 -0
  75. /machineconfig/scripts/linux/{switch_ip → other/switch_ip} +0 -0
  76. /machineconfig/scripts/{windows/share_nfs.ps1 → python/helpers_fire/agentic_frameworks/__init__.py} +0 -0
  77. /machineconfig/scripts/python/helpers_fire/{fire_crush.json → agentic_frameworks/fire_crush.json} +0 -0
  78. /machineconfig/scripts/python/helpers_fire/{fire_crush.py → agentic_frameworks/fire_crush.py} +0 -0
  79. /machineconfig/scripts/python/helpers_fire/{fire_cursor_agents.py → agentic_frameworks/fire_cursor_agents.py} +0 -0
  80. /machineconfig/scripts/windows/{mount_nfs.ps1 → mounts/mount_nfs.ps1} +0 -0
  81. /machineconfig/scripts/windows/{mount_nw.ps1 → mounts/mount_nw.ps1} +0 -0
  82. /machineconfig/scripts/windows/{mount_smb.ps1 → mounts/mount_smb.ps1} +0 -0
  83. /machineconfig/scripts/windows/{mount_ssh.ps1 → mounts/mount_ssh.ps1} +0 -0
  84. /machineconfig/scripts/windows/{pomodoro.ps1 → mounts/pomodoro.ps1} +0 -0
  85. /machineconfig/scripts/windows/{reload_path.ps1 → mounts/reload_path.ps1} +0 -0
  86. /machineconfig/scripts/windows/{share_cloud.cmd → mounts/share_cloud.cmd} +0 -0
  87. /machineconfig/scripts/windows/{share_smb.ps1 → mounts/share_smb.ps1} +0 -0
  88. /machineconfig/scripts/windows/{unlock_bitlocker.ps1 → mounts/unlock_bitlocker.ps1} +0 -0
  89. {machineconfig-5.36.dist-info → machineconfig-5.38.dist-info}/WHEEL +0 -0
  90. {machineconfig-5.36.dist-info → machineconfig-5.38.dist-info}/entry_points.txt +0 -0
  91. {machineconfig-5.36.dist-info → machineconfig-5.38.dist-info}/top_level.txt +0 -0
@@ -169,7 +169,6 @@
169
169
  # if params.session_name != "":
170
170
  # if platform.system() in ["Linux", "Darwin"]:
171
171
  # Terminal().run(f"""zellij --session {params.session_name} action new-tab --name results """)
172
- # # --layout ~/code/machineconfig/src/machineconfig/settings/zellij/layouts/d.kdl --cwd {res_folder.as_posix()}
173
172
  # Terminal().run(f"""zellij --session {params.session_name} action write-chars "cd {res_folder.as_posix()};lf" """)
174
173
  # elif platform.system() == "Windows":
175
174
  # Terminal().run(f"""wt --window {params.session_name} new-tab --title results -startingDirectory {res_folder.as_posix()} lf """)
@@ -51,12 +51,10 @@ class ProcessMonitor:
51
51
  return {"status": "unknown", "error": f"Tab '{tab_name}' not found in layout config", "running": False, "command": "", "tab_name": tab_name, "processes": [], "remote": self.remote_executor.remote_name}
52
52
 
53
53
  command = tab_config["command"]
54
-
55
54
  try:
56
55
  check_script = self._create_process_check_script(command)
57
56
  remote_cmd = f"$HOME/code/machineconfig/.venv/bin/python -c {shlex.quote(check_script)}"
58
57
  result = self.remote_executor.run_command(remote_cmd, timeout=15)
59
-
60
58
  if result.returncode == 0:
61
59
  try:
62
60
  matching_processes = json.loads(result.stdout.strip())
@@ -25,14 +25,14 @@ nerd_fonts: InstallerData = {
25
25
  "doc": "Nerd Fonts is a project that patches developer targeted fonts with a high number of glyphs (icons)",
26
26
  "fileNamePattern": {
27
27
  "amd64": {
28
- "windows": "CaskaydiaCoveNerdFontWindows.zip",
29
- "linux": "CaskaydiaCoveNerdFontLinux.zip",
30
- "macos": "CaskaydiaCoveNerdFontMac.zip",
28
+ "windows": "CascadiaCode.zip",
29
+ "linux": "CascadiaCode.zip",
30
+ "macos": "CascadiaCode.zip",
31
31
  },
32
32
  "arm64": {
33
- "windows": "CaskaydiaCoveNerdFontWindows.zip",
34
- "linux": "CaskaydiaCoveNerdFontLinux.zip",
35
- "macos": "CaskaydiaCoveNerdFontMac.zip",
33
+ "windows": "CascadiaCode.zip",
34
+ "linux": "CascadiaCode.zip",
35
+ "macos": "CascadiaCode.zip",
36
36
  }
37
37
  }
38
38
  }
@@ -40,10 +40,10 @@ nerd_fonts: InstallerData = {
40
40
 
41
41
  # Patterns to match any installed variant (NF, Nerd Font, Mono, Propo, style weights) of Cascadia/Caskaydia
42
42
  # We'll compile them at runtime for flexibility. Keep them simple to avoid false positives.
43
- REQUIRED_FONT_PATTERNS: tuple[str, ...] = (
44
- r"caskaydiacove.*(nf|nerd ?font)",
45
- r"cascadiacode.*(nf|nerd ?font)"
46
- )
43
+ # REQUIRED_FONT_PATTERNS: tuple[str, ...] = (
44
+ # r"caskaydiacove.*(nf|nerd ?font)",
45
+ # r"cascadiacode.*(nf|nerd ?font)"
46
+ # )
47
47
 
48
48
 
49
49
  console = Console()
@@ -92,7 +92,7 @@ def _missing_required_fonts(installed_fonts: Iterable[str]) -> list[str]:
92
92
 
93
93
  installed_norm = [f.lower().replace(" ", "") for f in installed_fonts]
94
94
  missing: list[str] = []
95
- for pattern in REQUIRED_FONT_PATTERNS:
95
+ for pattern in ["cascadiacode*"]:
96
96
  regex = re.compile(pattern)
97
97
  if not any(regex.search(f) for f in installed_norm):
98
98
  missing.append(pattern)
@@ -136,7 +136,7 @@ def install_nerd_fonts() -> None:
136
136
  file = PathExtended.tmpfile(suffix=".ps1")
137
137
  file.parent.mkdir(parents=True, exist_ok=True)
138
138
 
139
- raw_content = LIBRARY_ROOT.joinpath("setup_windows/wt_and_pwsh/install_fonts.ps1").read_text(encoding="utf-8").replace(r".\fonts-to-be-installed", str(folder))
139
+ raw_content = LIBRARY_ROOT.joinpath("jobs/installer/pwsh_scripts/install_fonts.ps1").read_text(encoding="utf-8").replace(r".\fonts-to-be-installed", str(folder))
140
140
  # PowerShell 5.1 can choke on certain unicode chars in some locales; keep ASCII only.
141
141
  content = "".join(ch for ch in raw_content if ord(ch) < 128)
142
142
  file.write_text(content, encoding="utf-8")
@@ -188,6 +188,40 @@
188
188
  }
189
189
  }
190
190
  },
191
+ {
192
+ "appName": "croc",
193
+ "repoURL": "https://github.com/schollz/croc",
194
+ "doc": "🦎 Easily and securely send things from one computer to another",
195
+ "fileNamePattern": {
196
+ "amd64": {
197
+ "linux": "croc_{version}_Linux-64bit.tar.gz",
198
+ "windows": "croc_{version}_Windows-64bit.zip",
199
+ "macos": "croc_{version}_macOS-64bit.tar.gz"
200
+ },
201
+ "arm64": {
202
+ "linux": "croc_{version}_Linux-ARM64.tar.gz",
203
+ "windows": null,
204
+ "macos": "croc_{version}_macOS-ARM64.tar.gz"
205
+ }
206
+ }
207
+ },
208
+ {
209
+ "appName": "wormhole-rs",
210
+ "repoURL": "https://github.com/magic-wormhole/magic-wormhole.rs",
211
+ "doc": "🐛 Get things from one computer to another, safely (Rust implementation)",
212
+ "fileNamePattern": {
213
+ "amd64": {
214
+ "linux": "magic-wormhole-cli-x86_64-unknown-linux-gnu.tgz",
215
+ "windows": "magic-wormhole-cli-x86_64-pc-windows-gnu.tgz",
216
+ "macos": "magic-wormhole-cli-aarch64-apple-darwin.tgz"
217
+ },
218
+ "arm64": {
219
+ "linux": null,
220
+ "windows": null,
221
+ "macos": null
222
+ }
223
+ }
224
+ },
191
225
  {
192
226
  "appName": "easy-sharing",
193
227
  "repoURL": "CMD",
@@ -1328,9 +1362,9 @@
1328
1362
  }
1329
1363
  },
1330
1364
  {
1331
- "appName": "bitwarden",
1365
+ "appName": "bw",
1332
1366
  "repoURL": "CMD",
1333
- "doc": "🔐 bw is a password manager.",
1367
+ "doc": "🔐 bitwarden is a password manager.",
1334
1368
  "fileNamePattern": {
1335
1369
  "amd64": {
1336
1370
  "linux": "npm install -g @bitwarden/cli",
@@ -1752,6 +1786,23 @@
1752
1786
  }
1753
1787
  }
1754
1788
  },
1789
+ {
1790
+ "appName": "docker",
1791
+ "repoURL": "CMD",
1792
+ "doc": "🐳 Docker is an open platform for developing, shipping, and running applications.",
1793
+ "fileNamePattern": {
1794
+ "amd64": {
1795
+ "linux": "docker.sh",
1796
+ "macos": "docker.sh",
1797
+ "windows": null
1798
+ },
1799
+ "arm64": {
1800
+ "linux": "docker.sh",
1801
+ "macos": "docker.sh",
1802
+ "windows": null
1803
+ }
1804
+ }
1805
+ },
1755
1806
  {
1756
1807
  "appName": "lazydocker",
1757
1808
  "repoURL": "https://github.com/jesseduffield/lazydocker",
@@ -5,9 +5,7 @@
5
5
  # winget install Microsoft.VC++2015-2022Redist-x86
6
6
 
7
7
 
8
- . "$env:USERPROFILE\code\machineconfig\.venv\Scripts\Activate.ps1"
9
- Set-Location C:
10
- python -m pip install --global-option=build_ext --global-option="-IC:\Program Files\Graphviz\include" --global-option="-LC:\Program Files\Graphviz\lib" pygraphviz
8
+ uv pip install --global-option=build_ext --global-option="-IC:\Program Files\Graphviz\include" --global-option="-LC:\Program Files\Graphviz\lib" pygraphviz
11
9
  # not including the options as above (from https://pygraphviz.github.io/documentation/stable/install.html)
12
10
  # would result in an error like this: pygraphviz/graphviz_wrap.c(2711): fatal error C1083: Cannot open include file: 'graphviz/cgraph.h': No such file or directory
13
11
 
@@ -1,4 +1,5 @@
1
1
  #!/bin/bash
2
+ # https://temp.sh/
2
3
  # 📤 CLOUD FILE SHARING SCRIPT 📤
3
4
  # This script uploads files or directories to transfer.sh for easy sharing
4
5
  # Usage: share_cloud <file|directory> or command | share_cloud <file_name>
@@ -14,6 +15,8 @@ if [ $# -eq 0 ]; then
14
15
  return 1
15
16
  fi
16
17
 
18
+ # https://temp.sh/
19
+
17
20
  # Process the input
18
21
  if tty -s; then
19
22
  # Direct file/directory upload mode
@@ -46,6 +46,7 @@ def adjust_gitignore(repo_root: Path) -> None:
46
46
  ".ai",
47
47
  "GEMINI.md",
48
48
  "CLAUDE.md",
49
+ "CRUSH.md",
49
50
  ".cursor",
50
51
  ".github/instructions",
51
52
  ".github/chatmodes",
@@ -46,6 +46,7 @@ console = Console()
46
46
  p = PathExtended(r'{path}').absolute()
47
47
  try:
48
48
  from machineconfig.utils.files.read import Read
49
+ from machineconfig.utils.accessories import pprint
49
50
  dat = Read.read(p)
50
51
  if isinstance(dat, dict):
51
52
  panel_title = f"📄 File Data: {{p.name}}"
@@ -64,12 +65,12 @@ except Exception as e:
64
65
  def main(
65
66
  python: Annotated[bool, typer.Option("--python", "-p", help="flag to use python over IPython.")] = False,
66
67
  fzf: Annotated[bool, typer.Option("--fzf", "-F", help="search with fuzzy finder for python scripts and run them")] = False,
67
- ve: Annotated[Optional[str], typer.Option("--ve", "-v", help="virtual enviroment to use, defaults to activated ve, if existed, else ve.")] = None,
68
68
  profile: Annotated[Optional[str], typer.Option("--profile", "-P", help="ipython profile to use, defaults to default profile.")] = None,
69
69
  read: Annotated[str, typer.Option("--read", "-r", help="read a binary file.")] = "",
70
70
  jupyter: Annotated[bool, typer.Option("--jupyter", "-j", help="run in jupyter interactive console")] = False,
71
71
  streamlit_viewer: Annotated[bool, typer.Option("--stViewer", "-s", help="view in streamlit app")] = False,
72
72
  visidata: Annotated[bool, typer.Option("--visidata", "-V", help="open data file in visidata")] = False,
73
+ local: Annotated[bool, typer.Option("--local", "-l", help="run in local mode, not in virtual env.")]= False,
73
74
  ) -> None:
74
75
  # ==================================================================================
75
76
  # flags processing
@@ -141,7 +142,9 @@ from pathlib import Path
141
142
  else:
142
143
  if interpreter == "ipython": profile = f" --profile {ipython_profile} --no-banner"
143
144
  else: profile = ""
144
- fire_line = f"uv run --python 3.13 --with machineconfig[plot] {interpreter} {interactivity} {profile} {str(pyfile)}"
145
+ if local: ve_line = "--project $HOME/code/machineconfig"
146
+ else: ve_line = "--with machineconfig[plot]"
147
+ fire_line = f"uv run --python 3.13 {ve_line} {interpreter} {interactivity} {profile} {str(pyfile)}"
145
148
 
146
149
  from machineconfig.utils.code import run_shell_script
147
150
  run_shell_script(fire_line, clean_env=False)
@@ -5,7 +5,7 @@ from typing import Optional
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
8
- from machineconfig.scripts.python.devops_helpers.cli_self import self_app
8
+ from machineconfig.scripts.python.devops_helpers.cli_self import cli_app as cli_app
9
9
  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
 
@@ -21,29 +21,12 @@ def install( which: Optional[str] = typer.Option(None, "--which", "-w", help="Co
21
21
  installer_entry_point.main(which=which, group=group, interactive=interactive)
22
22
 
23
23
 
24
- app.add_typer(cli_repos.app, name="repos", help="📁 Manage git repositories")
24
+ app.add_typer(cli_repos.app, name="repos")
25
25
  app.add_typer(cli_config.config_apps, name="config")
26
26
  app.add_typer(cli_data.app_data, name="data")
27
- app.add_typer(self_app, name="self")
27
+ app.add_typer(cli_app, name="self")
28
28
  app.add_typer(cli_network.nw_apps, name="network")
29
29
 
30
30
 
31
-
32
-
33
- # @app.command()
34
- # def scheduler():
35
- # """⏰ SCHEDULER"""
36
- # # from machineconfig.scripts.python.scheduler import main as helper
37
- # # helper()
38
-
39
-
40
-
41
- # @app.command()
42
- # def scheduler():
43
- # """⏰ SCHEDULER"""
44
- # # from machineconfig.scripts.python.scheduler import main as helper
45
- # # helper()
46
-
47
-
48
31
  if __name__ == "__main__":
49
- pass
32
+ app()
@@ -1,5 +1,6 @@
1
1
 
2
2
  import machineconfig.scripts.python.devops_helpers.cli_terminal as cli_terminal
3
+ import machineconfig.scripts.python.devops_helpers.cli_share_server as cli_share_server
3
4
  import typer
4
5
  from typing import Optional
5
6
 
@@ -7,7 +8,7 @@ nw_apps = typer.Typer(help="🔐 Network subcommands", no_args_is_help=True)
7
8
 
8
9
 
9
10
  nw_apps.command(name="share-terminal", help="📡 Share terminal via web browser")(cli_terminal.main)
10
-
11
+ nw_apps.command(name="share-server", help="🌐 Start local/global server to share files/folders via web browser", no_args_is_help=True)(cli_share_server.main)
11
12
 
12
13
  @nw_apps.command()
13
14
  def install_ssh_server():
@@ -8,7 +8,6 @@ in the event that username@github.com is not mentioned in the remote url.
8
8
  from pathlib import Path
9
9
  from typing import Annotated, Optional
10
10
  import typer
11
- from git import Repo, InvalidGitRepositoryError
12
11
  from machineconfig.scripts.python.helpers_repos.secure_repo import main as secure_repo_main
13
12
 
14
13
 
@@ -26,7 +25,6 @@ CloudOption = Annotated[Optional[str], typer.Option("--cloud", "-c", help="☁
26
25
  def push(directory: DirectoryArgument = None, recursive: RecursiveOption = False, no_sync: NoSyncOption = False) -> None:
27
26
  """🚀 Push changes across repositories."""
28
27
  from machineconfig.scripts.python.repos_helpers.entrypoint import git_operations
29
-
30
28
  git_operations(directory, pull=False, commit=False, push=True, recursive=recursive, no_sync=no_sync)
31
29
 
32
30
 
@@ -143,7 +141,7 @@ def cleanup(repo: DirectoryArgument = None, recursive: RecursiveOption = False)
143
141
  repo = Path.cwd().as_posix()
144
142
 
145
143
  arg_path = Path(repo).expanduser().absolute()
146
-
144
+ from git import Repo, InvalidGitRepositoryError
147
145
  if not recursive:
148
146
  # Check if the directory is a git repo
149
147
  try:
@@ -1,25 +1,25 @@
1
1
 
2
2
  import typer
3
3
 
4
- self_app = typer.Typer(help="🔄 SELF operations subcommands", no_args_is_help=True)
4
+ cli_app = typer.Typer(help="🔄 SELF operations subcommands", no_args_is_help=True)
5
5
 
6
6
 
7
- @self_app.command()
7
+ @cli_app.command()
8
8
  def update():
9
9
  """🔄 UPDATE essential repos"""
10
10
  import machineconfig.scripts.python.devops_helpers.devops_update_repos as helper
11
11
  helper.main()
12
- @self_app.command()
12
+ @cli_app.command()
13
13
  def interactive():
14
14
  """🤖 INTERACTIVE configuration of machine."""
15
15
  from machineconfig.scripts.python.interactive import main
16
16
  main()
17
- @self_app.command()
17
+ @cli_app.command()
18
18
  def status():
19
19
  """📊 STATUS of machine, shell profile, apps, symlinks, dotfiles, etc."""
20
20
  import machineconfig.scripts.python.devops_helpers.devops_status as helper
21
21
  helper.main()
22
- @self_app.command()
22
+ @cli_app.command()
23
23
  def clone():
24
24
  """📋 CLONE machienconfig locally and incorporate to shell profile for faster execution and nightly updates."""
25
25
  import platform
@@ -33,7 +33,7 @@ def clone():
33
33
  create_default_shell_profile(method="reference")
34
34
  run_shell_script(MACHINECONFIG.read_text(encoding="utf-8"))
35
35
 
36
- @self_app.command()
36
+ @cli_app.command()
37
37
  def navigate():
38
38
  """📚 NAVIGATE command structure with TUI"""
39
39
  from machineconfig.scripts.python.devops_navigator import main
@@ -0,0 +1,109 @@
1
+ from pathlib import Path
2
+ from typing import Optional, Annotated
3
+ import typer
4
+ # import typer
5
+
6
+
7
+
8
+ def display_share_url(local_ip_v4: str, port: int, protocol: str = "http") -> None:
9
+ """Display a flashy, unmissable share URL announcement."""
10
+
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+ from rich.text import Text
14
+ from rich.align import Align
15
+ console = Console()
16
+
17
+ # Create the main message with styling
18
+ url_text = Text(f"{protocol}://{local_ip_v4}:{port}", style="bold bright_cyan underline")
19
+ message = Text.assemble(
20
+ ("🚀 ", "bright_red"),
21
+ ("Share server is now accessible at: ", "bright_white bold"),
22
+ url_text,
23
+ (" 🚀", "bright_red")
24
+ )
25
+
26
+ # Create a fancy panel with borders and styling
27
+ panel = Panel(
28
+ Align.center(message),
29
+ title="[bold bright_green]🌐 SHARE SERVER READY 🌐[/bold bright_green]",
30
+ subtitle="[italic bright_yellow]⚡ Click the link above to access your shared files! ⚡[/italic bright_yellow]",
31
+ border_style="bright_magenta",
32
+ padding=(1, 2),
33
+ expand=False
34
+ )
35
+
36
+ # Print with extra spacing and attention-grabbing elements
37
+ console.print(panel)
38
+
39
+
40
+ def main(
41
+ path: Annotated[str, typer.Argument(help="Path to the file or directory to share")],
42
+ port: Annotated[Optional[int], typer.Option("--port", "-p", help="Port to run the share server on (default: 8080)")] = None,
43
+ username: Annotated[Optional[str], typer.Option("--username", "-u", help="Username for share access (default: current user)")] = None,
44
+ password: Annotated[Optional[str], typer.Option("--password", "-w", help="Password for share access (default: from ~/dotfiles/creds/passwords/quick_password)")] = None,
45
+ over_internet: Annotated[bool, typer.Option("--over-internet", "-i", help="Expose the share server over the internet using ngrok")] = False
46
+ ) -> None:
47
+ from machineconfig.utils.installer_utils.installer import install_if_missing
48
+ install_if_missing("ezshare")
49
+ if over_internet: install_if_missing("ngrok")
50
+
51
+ if username is None:
52
+ import getpass
53
+ username = getpass.getuser()
54
+ if password is None:
55
+ pwd_path = Path.home().joinpath("dotfiles/creds/passwords/quick_password")
56
+ if pwd_path.exists():
57
+ password = pwd_path.read_text(encoding="utf-8").strip()
58
+ else:
59
+ raise ValueError("Password not provided and default password file does not exist.")
60
+
61
+ if port is None:
62
+ port = 8080 # Default port for ezshare
63
+
64
+ import socket
65
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
66
+ s.connect(('8.8.8.8',80))
67
+ local_ip_v4 = s.getsockname()[0]
68
+ s.close()
69
+
70
+ # Display the flashy share announcement
71
+ protocol = "http"
72
+ display_share_url(local_ip_v4, port, protocol)
73
+ import subprocess
74
+ import time
75
+ # Build ezshare command
76
+ ezshare_cmd = f"ezshare --port {port} --username {username} --password {password} {path}"
77
+ ezshare_process = subprocess.Popen(ezshare_cmd, shell=True)
78
+ processes = [ezshare_process]
79
+
80
+ if over_internet:
81
+ ngrok_process = subprocess.Popen(f"ngrok http {port}", shell=True)
82
+ processes.append(ngrok_process)
83
+ time.sleep(3)
84
+ try:
85
+ import requests
86
+ response = requests.get("http://localhost:4040/api/tunnels")
87
+ data = response.json()
88
+ public_url = data['tunnels'][0]['public_url']
89
+ print(f"🌐 Ngrok tunnel ready: {public_url}")
90
+ except Exception as e:
91
+ print(f"Could not retrieve ngrok URL: {e}")
92
+
93
+ try:
94
+ while True:
95
+ print("Share server is running. Press Ctrl+C to stop.")
96
+ time.sleep(2)
97
+ except KeyboardInterrupt:
98
+ print("\nTerminating processes...")
99
+ for p in processes:
100
+ p.terminate()
101
+ p.wait()
102
+
103
+
104
+ def main_with_parser():
105
+ typer.run(main)
106
+
107
+
108
+ if __name__ == "__main__":
109
+ pass
@@ -1,8 +1,8 @@
1
-
2
-
3
1
  from pathlib import Path
4
2
  from typing import Optional, Annotated
5
3
  import typer
4
+ import subprocess
5
+ import time
6
6
 
7
7
 
8
8
 
@@ -49,19 +49,6 @@ def display_terminal_url(local_ip_v4: str, port: int, protocol: str = "http") ->
49
49
  # console.print("🔥" * 60 + "\n", style="bright_red bold")
50
50
 
51
51
 
52
- def install_ttyd():
53
- # uv run --python 3.13 --with machineconfig devops install ttyd
54
- from machineconfig.utils.installer_utils.installer_abc import check_tool_exists
55
- exists = check_tool_exists("ttyd")
56
- if exists:
57
- print("✅ ttyd is already installed.")
58
- return
59
- print("⏳ ttyd not found. Installing...")
60
- from machineconfig.utils.installer_utils.installer import main
61
- main(which="ttyd")
62
-
63
-
64
-
65
52
  def main(
66
53
  port: Annotated[Optional[int], typer.Option("--port", "-p", help="Port to run the terminal server on (default: 7681)")] = None,
67
54
  username: Annotated[Optional[str], typer.Option("--username", "-u", help="Username for terminal access (default: current user)")] = None,
@@ -70,9 +57,13 @@ def main(
70
57
  ssl: Annotated[bool, typer.Option("--ssl", "-S", help="Enable SSL")] = False,
71
58
  ssl_cert: Annotated[Optional[str], typer.Option("--ssl-cert", "-C", help="SSL certificate file path")] = None,
72
59
  ssl_key: Annotated[Optional[str], typer.Option("--ssl-key", "-K", help="SSL key file path")] = None,
73
- ssl_ca: Annotated[Optional[str], typer.Option("--ssl-ca", "-A", help="SSL CA file path for client certificate verification")] = None
60
+ ssl_ca: Annotated[Optional[str], typer.Option("--ssl-ca", "-A", help="SSL CA file path for client certificate verification")] = None,
61
+ over_internet: Annotated[bool, typer.Option("--over-internet", "-i", help="Expose the terminal over the internet using ngrok")] = False
74
62
  ) -> None:
75
- install_ttyd()
63
+ from machineconfig.utils.installer_utils.installer import install_if_missing
64
+ install_if_missing("ttyd")
65
+ if over_internet: install_if_missing("ngrok")
66
+
76
67
  if username is None:
77
68
  import getpass
78
69
  username = getpass.getuser()
@@ -128,12 +119,33 @@ def main(
128
119
  start_command = "powershell"
129
120
  else:
130
121
  start_command = "bash"
131
- code = f"""
132
- #!/bin/bash
133
- ttyd --writable -t enableSixel=true {ssl_args} --port {port} --credential "{username}:{password}" -t 'theme={{"background": "black"}}' {start_command}
134
- """
135
- from machineconfig.utils.code import run_shell_script
136
- run_shell_script(code, display_script=False)
122
+
123
+ ttyd_cmd = f"ttyd --writable -t enableSixel=true {ssl_args} --port {port} --credential \"{username}:{password}\" -t 'theme={{\"background\": \"black\"}}' {start_command}"
124
+ ttyd_process = subprocess.Popen(ttyd_cmd, shell=True)
125
+ processes = [ttyd_process]
126
+
127
+ if over_internet:
128
+ ngrok_process = subprocess.Popen(f"ngrok http {port}", shell=True)
129
+ processes.append(ngrok_process)
130
+ time.sleep(3)
131
+ try:
132
+ import requests
133
+ response = requests.get("http://localhost:4040/api/tunnels")
134
+ data = response.json()
135
+ public_url = data['tunnels'][0]['public_url']
136
+ print(f"🌐 Ngrok tunnel ready: {public_url}")
137
+ except Exception as e:
138
+ print(f"Could not retrieve ngrok URL: {e}")
139
+
140
+ try:
141
+ while True:
142
+ print("Terminal server is running. Press Ctrl+C to stop.")
143
+ time.sleep(2)
144
+ except KeyboardInterrupt:
145
+ print("\nTerminating processes...")
146
+ for p in processes:
147
+ p.terminate()
148
+ p.wait()
137
149
 
138
150
 
139
151
  def main_with_parser():
@@ -2,7 +2,6 @@
2
2
 
3
3
  from platform import system
4
4
  from machineconfig.utils.source_of_truth import LIBRARY_ROOT
5
- from machineconfig.utils.options import choose_from_options
6
5
  from machineconfig.utils.path_extended import PathExtended
7
6
  from rich.console import Console
8
7
  from rich.panel import Panel