machineconfig 5.33__py3-none-any.whl → 5.35__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 (23) hide show
  1. machineconfig/jobs/installer/installer_data.json +17 -0
  2. machineconfig/jobs/installer/package_groups.py +1 -0
  3. machineconfig/scripts/python/agents.py +8 -4
  4. machineconfig/scripts/python/croshell.py +1 -1
  5. machineconfig/scripts/python/devops_helpers/cli_config.py +10 -1
  6. machineconfig/scripts/python/devops_helpers/cli_nw.py +19 -20
  7. machineconfig/scripts/python/devops_helpers/devops_add_ssh_key.py +62 -38
  8. machineconfig/scripts/python/devops_helpers/themes/__init__.py +0 -0
  9. machineconfig/scripts/python/devops_helpers/{choose_pwsh_theme.ps1 → themes/choose_pwsh_theme.ps1} +38 -2
  10. machineconfig/scripts/python/interactive.py +2 -2
  11. machineconfig/setup_linux/web_shortcuts/interactive.sh +1 -1
  12. machineconfig/setup_windows/ssh/{openssh-server_add-sshkey.ps1 → add-sshkey.ps1} +0 -3
  13. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -2
  14. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +1 -1
  15. machineconfig/utils/files/dbms.py +76 -177
  16. {machineconfig-5.33.dist-info → machineconfig-5.35.dist-info}/METADATA +14 -3
  17. {machineconfig-5.33.dist-info → machineconfig-5.35.dist-info}/RECORD +22 -22
  18. machineconfig/setup_windows/ssh/openssh_all.ps1 +0 -22
  19. /machineconfig/scripts/python/devops_helpers/{choose_wezterm_theme.py → themes/choose_wezterm_theme.py} +0 -0
  20. /machineconfig/setup_windows/ssh/{openssh-server_add_identity.ps1 → add_identity.ps1} +0 -0
  21. {machineconfig-5.33.dist-info → machineconfig-5.35.dist-info}/WHEEL +0 -0
  22. {machineconfig-5.33.dist-info → machineconfig-5.35.dist-info}/entry_points.txt +0 -0
  23. {machineconfig-5.33.dist-info → machineconfig-5.35.dist-info}/top_level.txt +0 -0
@@ -2059,6 +2059,23 @@
2059
2059
  }
2060
2060
  }
2061
2061
  },
2062
+ {
2063
+ "appName": "qwen-code",
2064
+ "repoURL": "CMD",
2065
+ "doc": "Terminal-based CLI agents and tools for productivity and coding.",
2066
+ "fileNamePattern": {
2067
+ "amd64": {
2068
+ "linux": "npm install -g @qwen-code/qwen-code@latest",
2069
+ "windows": "npm install -g @qwen-code/qwen-code@latest",
2070
+ "macos": "npm install -g @qwen-code/qwen-code@latest"
2071
+ },
2072
+ "arm64": {
2073
+ "linux": "npm install -g @qwen-code/qwen-code@latest",
2074
+ "windows": "npm install -g @qwen-code/qwen-code@latest",
2075
+ "macos": "npm install -g @qwen-code/qwen-code@latest"
2076
+ }
2077
+ }
2078
+ },
2062
2079
  {
2063
2080
  "appName": "github-copilot-cli",
2064
2081
  "repoURL": "CMD",
@@ -11,6 +11,7 @@ PACKAGES_AI_TOOLS = [
11
11
  "chatgpt",
12
12
  "mods",
13
13
  "q",
14
+ "qwen-code",
14
15
  "cursor-cli",
15
16
  "droid",
16
17
  "auggie",
@@ -188,14 +188,18 @@ def init_config():
188
188
  from machineconfig.scripts.python.ai.initai import add_ai_configs
189
189
  add_ai_configs(repo_root=Path.cwd())
190
190
 
191
+ def generate_files():
192
+ from machineconfig.scripts.python.ai.generate_files import main
193
+ main()
191
194
 
192
195
  def main_from_parser():
193
196
  import sys
194
197
  agents_app = typer.Typer(help="🤖 AI Agents management subcommands")
195
- agents_app.command("create", no_args_is_help=True)(create)
196
- agents_app.command("collect", no_args_is_help=True)(collect)
197
- agents_app.command("create-template", no_args_is_help=False, help="Create a template for fire agents")(template)
198
- agents_app.command("init-config", no_args_is_help=False, help="Initialize AI configurations in the current repository")(init_config)
198
+ agents_app.command("create", no_args_is_help=True, help="Create agents layout file, ready to run.")(create)
199
+ agents_app.command("collect", no_args_is_help=True, help="Collect all agent materials into a single file.")(collect)
200
+ agents_app.command("make-template", no_args_is_help=False, help="Create a template for fire agents")(template)
201
+ agents_app.command("make-config", no_args_is_help=False, help="Initialize AI configurations in the current repository")(init_config)
202
+ agents_app.command("make-todo", no_args_is_help=False, help="Generate a markdown file listing all Python files in the repo")(generate_files)
199
203
  if len(sys.argv) == 1:
200
204
  agents_app(["--help"])
201
205
  else:
@@ -144,7 +144,7 @@ from pathlib import Path
144
144
  fire_line = f"uv run --python 3.13 --with machineconfig[plot] {interpreter} {interactivity} {profile} {str(pyfile)}"
145
145
 
146
146
  from machineconfig.utils.code import run_shell_script
147
- run_shell_script(fire_line, clean_env=True)
147
+ run_shell_script(fire_line, clean_env=False)
148
148
 
149
149
 
150
150
  def arg_parser() -> None:
@@ -1,7 +1,7 @@
1
1
 
2
2
 
3
3
  from typing import Literal, Annotated, Optional
4
-
4
+ from pathlib import Path
5
5
  import typer
6
6
 
7
7
  config_apps = typer.Typer(help="⚙️ Configuration subcommands", no_args_is_help=True)
@@ -41,3 +41,12 @@ def shell(method: Annotated[Literal["copy", "reference"], typer.Argument(help="C
41
41
  from machineconfig.profile.shell import create_default_shell_profile
42
42
  create_default_shell_profile(method=method)
43
43
 
44
+
45
+ @config_apps.command(no_args_is_help=False)
46
+ def pwsh_theme():
47
+ """🔗 Configure your shell profile."""
48
+ import machineconfig.scripts.python.devops_helpers.themes as themes
49
+ file = Path(themes.__file__).parent / "choose_pwsh_theme.ps1"
50
+ import subprocess
51
+ # subprocess.run(["pwsh", "-File", str(file)])
52
+ subprocess.run(["pwsh", "-File", str(file)])
@@ -1,6 +1,8 @@
1
1
 
2
2
  import machineconfig.scripts.python.devops_helpers.cli_terminal as cli_terminal
3
3
  import typer
4
+ from typing import Optional
5
+
4
6
  nw_apps = typer.Typer(help="🔐 Network subcommands", no_args_is_help=True)
5
7
 
6
8
 
@@ -8,32 +10,29 @@ nw_apps.command(name="share-terminal", help="📡 Share terminal via web browser
8
10
 
9
11
 
10
12
  @nw_apps.command()
11
- def add_key():
12
- """🔑 SSH add pub key to this machine"""
13
- import machineconfig.scripts.python.devops_helpers.devops_add_ssh_key as helper
14
- helper.main()
15
- @nw_apps.command()
16
- def add_identity():
17
- """🗝️ SSH add identity (private key) to this machine"""
18
- import machineconfig.scripts.python.devops_helpers.devops_add_identity as helper
19
- helper.main()
20
- @nw_apps.command()
21
- def connect():
22
- """🔐 SSH use key pair to connect two machines"""
23
- raise NotImplementedError
24
-
25
- @nw_apps.command()
26
- def setup():
27
- """📡 SSH setup"""
13
+ def install_ssh_server():
14
+ """📡 SSH install server"""
28
15
  import platform
29
16
  if platform.system() == "Windows":
30
17
  from machineconfig.setup_windows import SSH_SERVER
31
- program = SSH_SERVER.read_text(encoding="utf-8")
32
18
  elif platform.system() == "Linux" or platform.system() == "Darwin":
33
19
  from machineconfig.setup_linux import SSH_SERVER
34
- program = SSH_SERVER.read_text(encoding="utf-8")
35
20
  else:
36
21
  raise NotImplementedError(f"Platform {platform.system()} is not supported.")
37
22
  from machineconfig.utils.code import run_shell_script
38
- run_shell_script(script=program)
23
+ run_shell_script(script=SSH_SERVER.read_text(encoding="utf-8"))
39
24
 
25
+ @nw_apps.command(no_args_is_help=True)
26
+ def add_ssh_key(path: Optional[str] = typer.Option(None, help="Path to the public key file"),
27
+ choose: bool = typer.Option(False, "--choose", "-c", help="Choose from available public keys in ~/.ssh/*.pub"),
28
+ value: bool = typer.Option(False, "--value", "-v", help="Paste the public key content manually"),
29
+ github: Optional[str] = typer.Option(None, "--github", "-g", help="Fetch public keys from a GitHub username")
30
+ ):
31
+ """🔑 SSH add pub key to this machine so its accessible by owner of corresponding private key."""
32
+ import machineconfig.scripts.python.devops_helpers.devops_add_ssh_key as helper
33
+ helper.main(pub_path=path, pub_choose=choose, pub_val=value, from_github=github)
34
+ @nw_apps.command()
35
+ def add_ssh_identity():
36
+ """🗝️ SSH add identity (private key) to this machine"""
37
+ import machineconfig.scripts.python.devops_helpers.devops_add_identity as helper
38
+ helper.main()
@@ -7,14 +7,27 @@ from machineconfig.utils.path_extended import PathExtended
7
7
  from rich.console import Console
8
8
  from rich.panel import Panel
9
9
  from rich import box # Import box
10
+ from typing import Optional
11
+ import typer
10
12
 
11
13
 
12
14
  console = Console()
13
15
 
16
+ """
17
+ if (!$pubkey_string) {
18
+ $pubkey_url = 'https://github.com/thisismygitrepo.keys' # (CHANGE APPROPRIATELY)
19
+ $pubkey_string = (Invoke-WebRequest $pubkey_url).Content
20
+ } else {
21
+ Write-Output "pubkey_string is already defined."
22
+ }
23
+ echo $null >> $HOME/.ssh/authorized_keys # powershell way of touching a file if it doesn't exist
24
+ echo $pubkey_string >> $HOME/.ssh/authorized_keys
25
+ echo $pubkey_string > $HOME/.ssh/pubkey.pub
26
+ """
27
+
14
28
 
15
29
  def get_add_ssh_key_script(path_to_key: PathExtended):
16
30
  console.print(Panel("🔑 SSH KEY CONFIGURATION", title="[bold blue]SSH Setup[/bold blue]"))
17
-
18
31
  if system() == "Linux":
19
32
  authorized_keys = PathExtended.home().joinpath(".ssh/authorized_keys")
20
33
  console.print(Panel(f"🐧 Linux SSH configuration\n📄 Authorized keys file: {authorized_keys}", title="[bold blue]System Info[/bold blue]"))
@@ -30,7 +43,6 @@ def get_add_ssh_key_script(path_to_key: PathExtended):
30
43
  keys_text = authorized_keys.read_text(encoding="utf-8").split(split)
31
44
  key_count = len([k for k in keys_text if k.strip()])
32
45
  console.print(Panel(f"🔍 Current SSH authorization status\n✅ Found {key_count} authorized key(s)", title="[bold blue]Status[/bold blue]"))
33
-
34
46
  if path_to_key.read_text(encoding="utf-8") in authorized_keys.read_text(encoding="utf-8"):
35
47
  console.print(Panel(f"⚠️ Key already authorized\nKey: {path_to_key.name}\nStatus: Already present in authorized_keys file\nNo action required", title="[bold yellow]Warning[/bold yellow]"))
36
48
  program = ""
@@ -39,7 +51,7 @@ def get_add_ssh_key_script(path_to_key: PathExtended):
39
51
  if system() == "Linux":
40
52
  program = f"cat {path_to_key} >> ~/.ssh/authorized_keys"
41
53
  elif system() == "Windows":
42
- program_path = LIBRARY_ROOT.joinpath("setup_windows/openssh-server_add-sshkey.ps1")
54
+ program_path = LIBRARY_ROOT.joinpath("setup_windows/add-sshkey.ps1")
43
55
  program = program_path.expanduser().read_text(encoding="utf-8")
44
56
  place_holder = r'$sshfile = "$env:USERPROFILE\.ssh\pubkey.pub"'
45
57
  assert place_holder in program, f"This section performs string manipulation on the script {program_path} to add the key to the authorized_keys file. The script has changed and the string {place_holder} is not found."
@@ -58,7 +70,6 @@ def get_add_ssh_key_script(path_to_key: PathExtended):
58
70
 
59
71
  if system() == "Linux":
60
72
  program += """
61
-
62
73
  sudo chmod 700 ~/.ssh
63
74
  sudo chmod 644 ~/.ssh/authorized_keys
64
75
  sudo chmod 644 ~/.ssh/*.pub
@@ -68,51 +79,64 @@ sudo service ssh --full-restart
68
79
  return program
69
80
 
70
81
 
71
- def main() -> None:
72
- console.print(Panel("🔐 SSH PUBLIC KEY AUTHORIZATION TOOL", box=box.DOUBLE_EDGE, title_align="left"))
73
-
74
- console.print(Panel("🔍 Searching for public keys...", title="[bold blue]SSH Setup[/bold blue]", border_style="blue"))
75
-
76
- pub_keys = PathExtended.home().joinpath(".ssh").search("*.pub")
77
-
78
- if pub_keys:
79
- console.print(Panel(f"✅ Found {len(pub_keys)} public key(s)", title="[bold green]Status[/bold green]", border_style="green"))
80
- else:
81
- console.print(Panel("⚠️ No public keys found", title="[bold yellow]Warning[/bold yellow]", border_style="yellow"))
82
-
83
- all_keys_option = f"all pub keys available ({len(pub_keys)})"
84
- i_have_path_option = "I have the path to the key file"
85
- i_paste_option = "I want to paste the key itself"
86
-
87
- res = choose_from_options("Which public key to add? ", options=[str(x) for x in pub_keys] + [all_keys_option, i_have_path_option, i_paste_option], multi=False)
88
- if res == all_keys_option:
82
+ def main(pub_path: Optional[str] = typer.Argument(None, help="Path to the public key file"),
83
+ pub_choose: bool = typer.Option(False, "--choose", "-c", help="Choose from available public keys in ~/.ssh"),
84
+ pub_val: bool = typer.Option(False, "--paste", "-p", help="Paste the public key content manually"),
85
+ from_github: Optional[str] = typer.Option(None, "--from-github", "-g", help="Fetch public keys from a GitHub username")
86
+ ) -> None:
87
+
88
+ if pub_path:
89
+ key_path = PathExtended(pub_path).expanduser().absolute()
90
+ if not key_path.exists():
91
+ console.print(Panel(f"❌ ERROR: Provided key path does not exist\nPath: {key_path}", title="[bold red]Error[/bold red]"))
92
+ raise FileNotFoundError(f"Provided key path does not exist: {key_path}")
93
+ console.print(Panel(f"📄 Using provided public key file: {key_path}", title="[bold blue]Info[/bold blue]"))
94
+ program = get_add_ssh_key_script(key_path)
95
+ from machineconfig.utils.code import run_shell_script
96
+ run_shell_script(script=program)
97
+ console.print(Panel("✅ SSH KEY AUTHORIZATION COMPLETED", box=box.DOUBLE_EDGE, title_align="left"))
98
+ return
99
+ elif pub_choose:
100
+ console.print(Panel("🔐 SSH PUBLIC KEY AUTHORIZATION TOOL", box=box.DOUBLE_EDGE, title_align="left"))
101
+ console.print(Panel("🔍 Searching for public keys...", title="[bold blue]SSH Setup[/bold blue]", border_style="blue"))
102
+ pub_keys = PathExtended.home().joinpath(".ssh").search("*.pub")
103
+ if pub_keys:
104
+ console.print(Panel(f"✅ Found {len(pub_keys)} public key(s)", title="[bold green]Status[/bold green]", border_style="green"))
105
+ else:
106
+ console.print(Panel("⚠️ No public keys found", title="[bold yellow]Warning[/bold yellow]", border_style="yellow"))
107
+ return
89
108
  console.print(Panel(f"🔄 Processing all {len(pub_keys)} public keys...", title="[bold blue]Processing[/bold blue]", border_style="blue"))
90
109
  program = "\n\n\n".join([get_add_ssh_key_script(key) for key in pub_keys])
91
110
 
92
- elif res == i_have_path_option:
93
- console.print(Panel("📂 Please provide the path to your public key", title="[bold blue]Input Required[/bold blue]", border_style="blue"))
94
- key_path = PathExtended(input("📋 Path: ")).expanduser().absolute()
95
- console.print(Panel(f"📄 Using key from path: {key_path}", title="[bold blue]Info[/bold blue]", border_style="blue"))
96
- program = get_add_ssh_key_script(key_path)
97
-
98
- elif res == i_paste_option:
111
+ elif pub_val:
99
112
  console.print(Panel("📋 Please provide a filename and paste the public key content", title="[bold blue]Input Required[/bold blue]", border_style="blue"))
100
113
  key_filename = input("📝 File name (default: my_pasted_key.pub): ") or "my_pasted_key.pub"
101
114
  key_path = PathExtended.home().joinpath(f".ssh/{key_filename}")
102
115
  key_path.write_text(input("🔑 Paste the public key here: "), encoding="utf-8")
103
116
  console.print(Panel(f"💾 Key saved to: {key_path}", title="[bold green]Success[/bold green]", border_style="green"))
104
117
  program = get_add_ssh_key_script(key_path)
105
-
118
+ elif from_github:
119
+ console.print(Panel(f"🌐 Fetching public keys from GitHub user: {from_github}", title="[bold blue]GitHub Fetch[/bold blue]", border_style="blue"))
120
+ import requests
121
+ response = requests.get(f"https://api.github.com/users/{from_github}/keys")
122
+ if response.status_code != 200:
123
+ console.print(Panel(f"❌ ERROR: Failed to fetch keys from GitHub user {from_github}\nStatus Code: {response.status_code}", title="[bold red]Error[/bold red]", border_style="red"))
124
+ raise RuntimeError(f"Failed to fetch keys from GitHub user {from_github}: Status Code {response.status_code}")
125
+ keys = response.json()
126
+ if not keys:
127
+ console.print(Panel(f"⚠️ No public keys found for GitHub user: {from_github}", title="[bold yellow]Warning[/bold yellow]", border_style="yellow"))
128
+ return
129
+ console.print(Panel(f"✅ Found {len(keys)} public key(s) for user: {from_github}", title="[bold green]Success[/bold green]", border_style="green"))
130
+ key_path = PathExtended.home().joinpath(f".ssh/{from_github}_github_keys.pub")
131
+ key_path.write_text("\n".join([key["key"] for key in keys]), encoding="utf-8")
132
+ console.print(Panel(f"💾 Keys saved to: {key_path}", title="[bold green]Success[/bold green]", border_style="green"))
133
+ program = get_add_ssh_key_script(key_path)
106
134
  else:
107
- console.print(Panel(f"🔑 Using selected key: {PathExtended(res).name}", title="[bold blue]Info[/bold blue]", border_style="blue"))
108
- program = get_add_ssh_key_script(PathExtended(res))
109
-
135
+ console.print(Panel(" ERROR: No method provided to add SSH key\nUse --help for options", title="[bold red]Error[/bold red]", border_style="red"))
136
+ raise ValueError("No method provided to add SSH key. Use --help for options.")
110
137
  console.print(Panel("🚀 SSH KEY AUTHORIZATION READY\nRun the generated script to apply changes", box=box.DOUBLE_EDGE, title_align="left"))
111
-
112
- # return program
113
- import subprocess
114
-
115
- subprocess.run(program, shell=True, check=True)
138
+ from machineconfig.utils.code import run_shell_script
139
+ run_shell_script(script=program)
116
140
  console.print(Panel("✅ SSH KEY AUTHORIZATION COMPLETED", box=box.DOUBLE_EDGE, title_align="left"))
117
141
 
118
142
 
@@ -37,8 +37,44 @@ if ($selectedThemeName) {
37
37
  oh-my-posh init pwsh --config $selectedThemeName | Invoke-Expression
38
38
 
39
39
  Write-Host "`nTheme applied to current session!" -ForegroundColor Green
40
- Write-Host "To make this permanent, add this line to your PowerShell profile:" -ForegroundColor Cyan
41
- Write-Host "oh-my-posh init pwsh --config '$selectedThemeName' | Invoke-Expression" -ForegroundColor Yellow
40
+
41
+ # Safely update the PowerShell profile
42
+ $profilePath = $PROFILE
43
+ $ompLine = "oh-my-posh init pwsh --config '$selectedThemeName' | Invoke-Expression"
44
+
45
+ # Create profile directory if it doesn't exist
46
+ $profileDir = Split-Path $profilePath -Parent
47
+ if (-not (Test-Path $profileDir)) {
48
+ New-Item -ItemType Directory -Path $profileDir -Force | Out-Null
49
+ }
50
+
51
+ # Read existing profile content or create empty array
52
+ $profileContent = @()
53
+ if (Test-Path $profilePath) {
54
+ $profileContent = Get-Content $profilePath
55
+ }
56
+
57
+ # Check if oh-my-posh line already exists and replace it, or add it
58
+ $found = $false
59
+ for ($i = 0; $i -lt $profileContent.Count; $i++) {
60
+ if ($profileContent[$i] -match "oh-my-posh init pwsh") {
61
+ $profileContent[$i] = $ompLine
62
+ $found = $true
63
+ break
64
+ }
65
+ }
66
+
67
+ if (-not $found) {
68
+ # Add the line at the end with a blank line before it
69
+ $profileContent += ""
70
+ $profileContent += $ompLine
71
+ }
72
+
73
+ # Write back to profile
74
+ $profileContent | Set-Content $profilePath -Encoding UTF8
75
+
76
+ Write-Host "Profile updated successfully!" -ForegroundColor Green
77
+ Write-Host "The theme will be applied automatically in future PowerShell sessions." -ForegroundColor Cyan
42
78
  } else {
43
79
  Write-Host "`nNo theme selected." -ForegroundColor DarkGray
44
80
  }
@@ -19,7 +19,7 @@ for better user experience with checkbox selections.
19
19
 
20
20
  import sys
21
21
  from pathlib import Path
22
- from typing import cast
22
+ # from typing import cast
23
23
  import platform
24
24
 
25
25
  import questionary
@@ -29,7 +29,7 @@ from rich.panel import Panel
29
29
  from rich.text import Text
30
30
  from machineconfig.utils.code import run_shell_script
31
31
 
32
- _ = cast
32
+ # _ = cast
33
33
  console = Console()
34
34
 
35
35
 
@@ -1,4 +1,4 @@
1
1
  #!/bin/bash
2
2
 
3
3
  . <( curl -sSL "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/uv.sh")
4
- $HOME/.local/bin/uv run --python 3.13 --with machineconfig devops self interactive
4
+ $HOME/.local/bin/uv run --python 3.13 --with machineconfig devops "$@"
@@ -7,16 +7,13 @@
7
7
 
8
8
  $ErrorActionPreference = "Stop"
9
9
  $sshd_dir = "$env:ProgramData\ssh"
10
-
11
10
  $sshfile = "$env:USERPROFILE\.ssh\pubkey.pub" # this directory is for normal users, not admins.
12
11
  # Once they are populated, we can create administrators_authorized_keys
13
12
 
14
13
  Get-Content $sshfile >> "$sshd_dir\administrators_authorized_keys"
15
-
16
14
  # set appropirate persmissions for this file
17
15
  Set-Location $sshd_dir
18
16
  icacls administrators_authorized_keys /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
19
-
20
17
  # Lastly, enabling public key authentication.
21
18
  $sshd_config = "$sshd_dir\sshd_config"
22
19
  (Get-Content $sshd_config) -replace '#PubkeyAuthentication', 'PubkeyAuthentication' | Out-File -encoding ASCII $sshd_config
@@ -20,9 +20,7 @@ Add-WindowsCapability -Online -Name OpenSSH.Client
20
20
  $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
21
21
 
22
22
  Set-Service -Name sshd -StartupType Automatic
23
-
24
23
  #Get-Service -Name ssh-agent | Set-Service -StartupType Automatic
25
-
26
24
  #Set-Service -Name ssh-agent -StartupType Automatic
27
25
  #Start-Service ssh-agent
28
26
  # Starting the service for the first time will populate the directory with config files.
@@ -1,4 +1,4 @@
1
1
 
2
2
 
3
3
  iex (iwr "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/uv.ps1").Content
4
- & "$HOME\.local\bin\uv.exe" run --python 3.13 --with machineconfig devops self interactive
4
+ & "$HOME\.local\bin\uv.exe" run --python 3.13 --with machineconfig devops $args
@@ -3,11 +3,9 @@ from typing import Optional, Any, Callable
3
3
 
4
4
  import polars as pl
5
5
 
6
- from sqlalchemy.orm import sessionmaker, Session
7
- from sqlalchemy import text, inspect as inspect__
8
- from sqlalchemy.engine import Engine, Connection, create_engine
9
- from sqlalchemy.ext.asyncio import create_async_engine
10
- from sqlalchemy.engine import Inspector
6
+ from sqlalchemy.orm import sessionmaker
7
+ from sqlalchemy import create_engine, text, inspect as inspect__
8
+ from sqlalchemy.engine import Engine
11
9
  from sqlalchemy.sql.schema import MetaData
12
10
  from pathlib import Path as P
13
11
 
@@ -15,75 +13,23 @@ OPLike = Optional[P] | str | None
15
13
 
16
14
 
17
15
  class DBMS:
18
- def __init__(self, engine: Engine, sch: Optional[str] = None, vws: bool = False):
16
+ def __init__(self, engine: Engine):
19
17
  self.eng: Engine = engine
20
- self.con: Optional[Connection] = None
21
- self.ses: Optional[Session] = None
22
- self.insp: Optional[Inspector] = None
23
- self.meta: Optional[MetaData] = None
24
- db_path = P(self.eng.url.database) if self.eng.url.database else None
25
- if db_path and db_path.exists():
26
- self.path: Optional[P] = db_path
27
- else: self.path = None
28
18
 
29
- # self.db = db
30
- self.sch = sch
31
- self.vws: bool = vws
32
- self.schema: list[str] = []
33
-
34
- self.sch_tab: dict[str, list[str]]
35
- self.sch_vws: dict[str, list[str]]
36
- self.description: Optional[pl.DataFrame] = None
37
- # self.tables = None
38
- # self.views = None
39
- # self.sch_tab: Optional[Struct] = None
40
- # self.sch_vws: Optional[Struct] = None
41
- # if inspect: self.refresh()
42
- # self.ip_formatter: Optional[Any] = None
43
- # self.db_specs: Optional[Any] = None
44
- if self.path is not None:
45
- if self.path.is_file():
46
- path_repr = self.path.as_uri()
47
- else:
48
- path_repr = self.path
49
- print(f"Database at {path_repr} is ready.")
50
-
51
- def refresh(self, sch: Optional[str] = None) -> 'DBMS': # fails if multiple schemas are there and None is specified
52
- self.con = self.eng.connect()
53
- self.ses = sessionmaker()(bind=self.eng) # ORM style
54
- self.meta = MetaData()
55
- self.meta.reflect(bind=self.eng, schema=sch or self.sch)
56
- insp = inspect__(subject=self.eng)
57
- self.insp = insp
58
- assert self.insp is not None
59
- self.schema = self.insp.get_schema_names()
60
- print(f"Inspecting tables of schema `{self.schema}` {self.eng}")
61
- self.sch_tab = {k: v for k, v in zip(self.schema, [insp.get_table_names(schema=x) for x in self.schema])} # dict(zip(self.schema, self.schema.apply(lambda x: self.insp.get_table_names(schema=x)))) #
62
- print(f"Inspecting views of schema `{self.schema}` {self.eng}")
63
- self.sch_vws = {k: v for k, v in zip(self.schema, [insp.get_view_names(schema=x) for x in self.schema])}
64
- return self
65
-
66
- @classmethod
67
- def from_local_db(cls, path: OPLike = None, echo: bool = False, share_across_threads: bool = False, pool_size: int = 5, **kwargs: Any):
68
- return cls(engine=cls.make_sql_engine(path=path, echo=echo, share_across_threads=share_across_threads, pool_size=pool_size, **kwargs))
19
+ @staticmethod
20
+ def from_local_db(path: OPLike = None, echo: bool = False, share_across_threads: bool = False, pool_size: int = 5, **kwargs: Any):
21
+ return DBMS(engine=DBMS.make_sql_engine(path=path, echo=echo, share_across_threads=share_across_threads, pool_size=pool_size, **kwargs))
69
22
 
70
23
  def __repr__(self): return f"DataBase @ {self.eng}"
71
- def get_columns(self, table: str, sch: Optional[str] = None):
72
- assert self.meta is not None
73
- return self.meta.tables[self._get_table_identifier(table=table, sch=sch)].exported_columns.keys()
74
24
  def close(self, sleep: int = 2):
75
- if self.path:
76
- print(f"Terminating database `{self.path.as_uri() if self.path.is_file() and 'memory' not in str(self.path) else self.path}`")
77
- if self.con: self.con.close()
78
- if self.ses: self.ses.close()
79
25
  self.eng.pool.dispose()
80
26
  self.eng.dispose()
81
27
  time.sleep(sleep)
82
- def _get_table_identifier(self, table: str, sch: Optional[str]):
83
- if sch is None: sch = self.sch
28
+ @staticmethod
29
+ def _get_table_identifier(engine: Engine, table: str, sch: Optional[str]):
84
30
  if sch is not None:
85
31
  # Handle DuckDB schema names that contain dots (e.g., "klines.main")
86
- if self.eng.url.drivername == 'duckdb' and '.' in sch and sch.endswith('.main'):
32
+ if engine.url.drivername == 'duckdb' and '.' in sch and sch.endswith('.main'):
87
33
  # For DuckDB schemas like "klines.main", just use the table name without schema
88
34
  return f'"{table}"'
89
35
  else:
@@ -91,83 +37,6 @@ class DBMS:
91
37
  else:
92
38
  return f'"{table}"'
93
39
 
94
- @staticmethod
95
- def make_sql_engine(path: OPLike = None, echo: bool = False, dialect: str = "sqlite", driver: str = ["pysqlite", "DBAPI"][0], pool_size: int = 5, share_across_threads: bool = True, **kwargs: Any):
96
- """Establish lazy initialization with database"""
97
- from sqlalchemy.pool import StaticPool, NullPool
98
- _ = NullPool
99
- _ = driver
100
- if str(path) == "memory":
101
- print("Linking to in-memory database.")
102
- if share_across_threads:
103
- # see: https://docs.sqlalchemy.org/en/14/dialects/sqlite.html#using-a-memory-database-in-multiple-threads
104
- return create_engine(url=f"{dialect}+{driver}:///:memory:", echo=echo, future=True, poolclass=StaticPool, connect_args={"check_same_thread": False})
105
- else:
106
- return create_engine(url=f"{dialect}+{driver}:///:memory:", echo=echo, future=True, pool_size=pool_size, **kwargs)
107
- if path is None:
108
- tmp_dir = P.home().joinpath(".tmp").joinpath("tmp_dbs")
109
- tmp_dir.mkdir(parents=True, exist_ok=True)
110
- import tempfile
111
- with tempfile.NamedTemporaryFile(suffix=".sqlite", dir=str(tmp_dir), delete=False) as tmp_file:
112
- path = P(tmp_file.name)
113
- else:
114
- path = P(path).expanduser().resolve()
115
- path.parent.mkdir(parents=True, exist_ok=True)
116
- path_repr = path.as_uri() if path.is_file() else path
117
- dialect = path.suffix.removeprefix('.')
118
- print(f"Linking to database at {path_repr}")
119
- connect_args = kwargs.pop("connect_args", {}) or {}
120
- try:
121
- if path.suffix == ".duckdb": # only apply for duckdb files
122
- # don't overwrite user's explicit setting if already provided
123
- connect_args.setdefault("read_only", True)
124
- print(" - Opening DuckDB in read-only mode.")
125
- except Exception:
126
- pass
127
- if pool_size == 0:
128
- res = create_engine(url=f"{dialect}:///{path}", echo=echo, future=True, poolclass=NullPool, connect_args=connect_args, **kwargs) # echo flag is just a short for the more formal way of logging sql commands.
129
- else:
130
- res = create_engine(url=f"{dialect}:///{path}", echo=echo, future=True, pool_size=pool_size, connect_args=connect_args, **kwargs) # echo flag is just a short for the more formal way of logging sql commands.
131
- return res
132
- @staticmethod
133
- def make_sql_async_engine(path: OPLike = None, echo: bool = False, dialect: str = "sqlite", driver: str = "aiosqlite", pool_size: int = 5, share_across_threads: bool = True, **kwargs: Any):
134
- """Establish lazy initialization with database"""
135
- from sqlalchemy.pool import StaticPool, NullPool
136
- _ = NullPool
137
- if str(path) == "memory":
138
- print("Linking to in-memory database.")
139
- if share_across_threads:
140
- # see: https://docs.sqlalchemy.org/en/14/dialects/sqlite.html#using-a-memory-database-in-multiple-threads
141
- return create_async_engine(url=f"{dialect}+{driver}://", echo=echo, future=True, poolclass=StaticPool, connect_args={"mode": "memory", "cache": "shared"})
142
- else:
143
- return create_async_engine(url=f"{dialect}+{driver}:///:memory:", echo=echo, future=True, pool_size=pool_size, **kwargs)
144
- if path is None:
145
- tmp_dir = P.home().joinpath(".tmp").joinpath("tmp_dbs")
146
- tmp_dir.mkdir(parents=True, exist_ok=True)
147
- import tempfile
148
- with tempfile.NamedTemporaryFile(suffix=".sqlite", dir=str(tmp_dir), delete=False) as tmp_file:
149
- path = P(tmp_file.name)
150
- else:
151
- path = P(path).expanduser().resolve()
152
- path.parent.mkdir(parents=True, exist_ok=True)
153
- path_repr = path.as_uri() if path.is_file() else path
154
- dialect = path.suffix.removeprefix('.')
155
- print(f"Linking to database at {path_repr}")
156
- # Add DuckDB-specific read-only flag automatically when pointing to an existing .duckdb file
157
- connect_args = kwargs.pop("connect_args", {}) or {}
158
- try:
159
- if path.suffix == ".duckdb": # only apply for duckdb files
160
- # don't overwrite user's explicit setting if already provided
161
- connect_args.setdefault("read_only", True)
162
- print(" - Opening DuckDB in read-only mode.")
163
- except Exception:
164
- pass
165
- if pool_size == 0:
166
- res = create_async_engine(url=f"{dialect}+{driver}:///{path}", echo=echo, future=True, poolclass=NullPool, connect_args=connect_args, **kwargs) # echo flag is just a short for the more formal way of logging sql commands.
167
- else:
168
- res = create_async_engine(url=f"{dialect}+{driver}:///{path}", echo=echo, future=True, pool_size=pool_size, connect_args=connect_args, **kwargs) # echo flag is just a short for the more formal way of logging sql commands.
169
- return res
170
-
171
40
  # ==================== QUERIES =====================================
172
41
  def execute_as_you_go(self, *commands: str, res_func: Callable[[Any], Any] = lambda x: x.all(), df: bool = False):
173
42
  with self.eng.begin() as conn:
@@ -194,17 +63,41 @@ class DBMS:
194
63
  # return result if not df else pl.DataFrame(result)
195
64
 
196
65
  # ========================== TABLES =====================================
197
- def read_table(self, table: Optional[str] = None, sch: Optional[str] = None, size: int = 5):
66
+ def insert_dicts(self, table: str, *mydicts: dict[str, Any]) -> None:
67
+ cmd = f"""INSERT INTO {table} VALUES """
68
+ for mydict in mydicts: cmd += f"""({tuple(mydict)}), """
69
+ self.execute_begin_once(cmd)
70
+
71
+ def refresh(self, sch: Optional[str] = None) -> dict[str, Any]:
72
+ con = self.eng.connect()
73
+ ses = sessionmaker()(bind=self.eng)
74
+ meta = MetaData()
75
+ meta.reflect(bind=self.eng, schema=sch)
76
+ insp = inspect__(subject=self.eng)
77
+ schema = insp.get_schema_names()
78
+ sch_tab = {k: v for k, v in zip(schema, [insp.get_table_names(schema=x) for x in schema])}
79
+ sch_vws = {k: v for k, v in zip(schema, [insp.get_view_names(schema=x) for x in schema])}
80
+ return {'con': con, 'ses': ses, 'meta': meta, 'insp': insp, 'schema': schema, 'sch_tab': sch_tab, 'sch_vws': sch_vws}
81
+
82
+ def get_columns(self, table: str, sch: Optional[str] = None) -> list[str]:
83
+ meta = MetaData()
84
+ meta.reflect(bind=self.eng, schema=sch)
85
+ return list(meta.tables[self._get_table_identifier(self.eng, table, sch)].exported_columns.keys())
86
+
87
+ def read_table(self, table: Optional[str] = None, sch: Optional[str] = None, size: int = 5) -> pl.DataFrame:
88
+ insp = inspect__(self.eng)
89
+ schema = insp.get_schema_names()
90
+ sch_tab = {k: v for k, v in zip(schema, [insp.get_table_names(schema=x) for x in schema])}
198
91
  if sch is None:
199
92
  # First try to find schemas that have tables (excluding system schemas)
200
93
  schemas_with_tables = []
201
- for schema_name in self.schema:
94
+ for schema_name in schema:
202
95
  if schema_name not in ["information_schema", "pg_catalog", "system"]:
203
- if schema_name in self.sch_tab and len(self.sch_tab[schema_name]) > 0:
96
+ if schema_name in sch_tab and len(sch_tab[schema_name]) > 0:
204
97
  schemas_with_tables.append(schema_name)
205
98
 
206
99
  if len(schemas_with_tables) == 0:
207
- raise ValueError(f"No schemas with tables found. Available schemas: {self.schema}")
100
+ raise ValueError(f"No schemas with tables found. Available schemas: {schema}")
208
101
 
209
102
  # Prefer non-"main" schemas if available, otherwise use main
210
103
  if len(schemas_with_tables) > 1 and "main" in schemas_with_tables:
@@ -214,64 +107,71 @@ class DBMS:
214
107
  print(f"Auto-selected schema: `{sch}` from available schemas: {schemas_with_tables}")
215
108
 
216
109
  if table is None:
217
- if sch not in self.sch_tab:
218
- raise ValueError(f"Schema `{sch}` not found. Available schemas: {list(self.sch_tab.keys())}")
219
- tables = self.sch_tab[sch]
110
+ if sch not in sch_tab:
111
+ raise ValueError(f"Schema `{sch}` not found. Available schemas: {list(sch_tab.keys())}")
112
+ tables = sch_tab[sch]
220
113
  assert len(tables) > 0, f"No tables found in schema `{sch}`"
221
114
  import random
222
115
  table = random.choice(tables)
223
116
  print(f"Reading table `{table}` from schema `{sch}`")
224
- if self.con:
117
+ with self.eng.connect() as conn:
225
118
  try:
226
- res = self.con.execute(text(f'''SELECT * FROM {self._get_table_identifier(table, sch)} '''))
119
+ res = conn.execute(text(f'''SELECT * FROM {self._get_table_identifier(self.eng, table, sch)} '''))
227
120
  return pl.DataFrame(res.fetchmany(size))
228
121
  except Exception:
229
122
  print(f"Error executing query for table `{table}` in schema `{sch}`")
230
- print(f"Available schemas and tables: {self.sch_tab}")
123
+ print(f"Available schemas and tables: {sch_tab}")
231
124
  raise
232
125
 
233
- def insert_dicts(self, table: str, *mydicts: dict[str, Any]) -> None:
234
- cmd = f"""INSERT INTO {table} VALUES """
235
- for mydict in mydicts: cmd += f"""({tuple(mydict)}), """
236
- self.execute_begin_once(cmd)
237
-
238
- def describe_db(self):
239
- self.refresh()
240
- assert self.meta is not None
126
+ def describe_db(self, sch: Optional[str] = None) -> pl.DataFrame:
127
+ meta = MetaData()
128
+ meta.reflect(bind=self.eng, schema=sch)
129
+ ses = sessionmaker()(bind=self.eng)
241
130
  res_all = []
242
- assert self.ses is not None
243
131
  from rich.progress import Progress
244
132
  with Progress() as progress:
245
- task = progress.add_task("Inspecting tables", total=len(self.meta.sorted_tables))
246
- for tbl in self.meta.sorted_tables:
133
+ task = progress.add_task("Inspecting tables", total=len(meta.sorted_tables))
134
+ for tbl in meta.sorted_tables:
247
135
  table = tbl.name
248
- if self.sch is not None:
249
- table = f"{self.sch}.{table}"
250
- count = self.ses.query(tbl).count()
136
+ if sch is not None:
137
+ table = f"{sch}.{table}"
138
+ count = ses.query(tbl).count()
251
139
  res = dict(table=table, count=count, size_mb=count * len(tbl.exported_columns) * 10 / 1e6,
252
- columns=len(tbl.exported_columns), schema=self.sch)
140
+ columns=len(tbl.exported_columns), schema=sch)
253
141
  res_all.append(res)
254
142
  progress.update(task, advance=1)
255
- self.description = pl.DataFrame(res_all)
256
- return self.description
143
+ return pl.DataFrame(res_all)
257
144
 
258
145
  def describe_table(self, table: str, sch: Optional[str] = None, dtype: bool = True) -> None:
259
146
  print(table.center(100, "="))
260
- self.refresh()
261
- assert self.meta is not None
262
- tbl = self.meta.tables[table]
263
- assert self.ses is not None
264
- count = self.ses.query(tbl).count()
147
+ meta = MetaData()
148
+ meta.reflect(bind=self.eng, schema=sch)
149
+ tbl = meta.tables[self._get_table_identifier(self.eng, table, sch)]
150
+ ses = sessionmaker()(bind=self.eng)
151
+ count = ses.query(tbl).count()
265
152
  res = dict(name=table, count=count, size_mb=count * len(tbl.exported_columns) * 10 / 1e6)
266
153
  from machineconfig.utils.accessories import pprint
267
154
  pprint(res, title="TABLE DETAILS")
268
155
  dat = self.read_table(table=table, sch=sch, size=2)
269
- df = dat # dat is already a polars DataFrame
156
+ df = dat
270
157
  print("SAMPLE:\n", df)
271
- assert self.insp is not None
272
- if dtype: print("\nDETAILED COLUMNS:\n", pl.DataFrame(self.insp.get_columns(table)))
158
+ insp = inspect__(self.eng)
159
+ if dtype: print("\nDETAILED COLUMNS:\n", pl.DataFrame(insp.get_columns(self._get_table_identifier(self.eng, table, sch))))
273
160
  print("\n" * 3)
274
161
 
162
+ @staticmethod
163
+ def make_sql_engine(path: OPLike = None, echo: bool = False, share_across_threads: bool = False, pool_size: int = 5, **kwargs: Any) -> Engine:
164
+ if path is None:
165
+ url = 'sqlite:///:memory:'
166
+ elif isinstance(path, str) and path.startswith(('sqlite://', 'postgresql://', 'mysql://', 'duckdb://')):
167
+ url = path
168
+ else:
169
+ path_str = str(P(path))
170
+ url = f'sqlite:///{path_str}'
171
+ connect_args = {}
172
+ if share_across_threads and 'sqlite' in url:
173
+ connect_args['check_same_thread'] = False
174
+ return create_engine(url, echo=echo, pool_size=pool_size, connect_args=connect_args, **kwargs)
275
175
 
276
176
  DB_TMP_PATH = P.home().joinpath(".tmp").joinpath("tmp_dbs").joinpath("results").joinpath("data.sqlite")
277
177
 
@@ -290,7 +190,6 @@ def to_db(table: str, idx: int, idx_max: int, data: Any):
290
190
  text(insert_row),
291
191
  {'time': time_now, 'idx': idx, 'idx_max': idx_max, 'data': data_blob}
292
192
  )
293
- # conn.commit()
294
193
  db.close()
295
194
 
296
195
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machineconfig
3
- Version: 5.33
3
+ Version: 5.35
4
4
  Summary: Dotfiles management package
5
5
  Author-email: Alex Al-Saffar <programmer@usa.com>
6
6
  License: Apache 2.0
@@ -29,8 +29,19 @@ Requires-Dist: questionary>=2.1.1
29
29
  Requires-Dist: typer>=0.19.2
30
30
  Provides-Extra: windows
31
31
  Requires-Dist: pywin32; extra == "windows"
32
- Provides-Extra: docs
33
- Requires-Dist: pdoc>=15.0.2; extra == "docs"
32
+ Provides-Extra: plot
33
+ Requires-Dist: duckdb-engine>=0.17.0; extra == "plot"
34
+ Requires-Dist: sqlalchemy>=2.0.43; extra == "plot"
35
+ Requires-Dist: ipykernel>=6.30.1; extra == "plot"
36
+ Requires-Dist: ipython>=9.5.0; extra == "plot"
37
+ Requires-Dist: jupyterlab>=4.4.9; extra == "plot"
38
+ Requires-Dist: kaleido>=1.1.0; extra == "plot"
39
+ Requires-Dist: matplotlib>=3.10.6; extra == "plot"
40
+ Requires-Dist: nbformat>=5.10.4; extra == "plot"
41
+ Requires-Dist: numpy>=2.3.3; extra == "plot"
42
+ Requires-Dist: plotly>=6.3.0; extra == "plot"
43
+ Requires-Dist: polars>=1.33.1; extra == "plot"
44
+ Requires-Dist: python-magic>=0.4.27; extra == "plot"
34
45
 
35
46
 
36
47
  <p align="center">
@@ -46,8 +46,8 @@ machineconfig/cluster/templates/cli_trogon.py,sha256=PFWGy8SFYIhT9r3ZV4oIEYfImsQ
46
46
  machineconfig/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  machineconfig/jobs/installer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  machineconfig/jobs/installer/check_installations.py,sha256=wOtvWzyJSxbuFueFfcOc4gX_UbTRWv6tWpRcG-3Ml_8,10780
49
- machineconfig/jobs/installer/installer_data.json,sha256=ExwnBwbnk_RzBa-aIqk5JTPdO_qWpuLuV6gMALQ1b4w,72527
50
- machineconfig/jobs/installer/package_groups.py,sha256=IuF6FBVMs4jGsoSZZZdzaBO0wfA3ef2ZmgP8gFdBAl8,5361
49
+ machineconfig/jobs/installer/installer_data.json,sha256=py5S8uf0RscDXDZWIsnrFoG2x90zt4XGhpW5w16CGpU,73161
50
+ machineconfig/jobs/installer/package_groups.py,sha256=lS8uG-gGLLodJm4grhGuhAJl7shTWfwKB2wGSD0PHzY,5378
51
51
  machineconfig/jobs/installer/custom/gh.py,sha256=gn7TUSrsLx7uqFqj1Z-iYglS0EYBSgtJ9jWHxaJIfXM,4119
52
52
  machineconfig/jobs/installer/custom/hx.py,sha256=YQClQXqWtGvon8BLFGf1Fp20JPkHgZeEZ6ebmCJQQfI,5838
53
53
  machineconfig/jobs/installer/custom_dev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -127,14 +127,14 @@ machineconfig/scripts/linux/switch_ip,sha256=NQfeKMBSbFY3eP6M-BadD-TQo5qMP96DTp7
127
127
  machineconfig/scripts/linux/warp-cli.sh,sha256=shFFZ9viet_DSEEHT8kxlGRHoJpO6o85pKYnc3rIkaA,3868
128
128
  machineconfig/scripts/linux/z_ls,sha256=ATZtu0ccN3AKvAOxkwLq1xgQjJ3en5byEWJ3Q8afnNg,3340
129
129
  machineconfig/scripts/python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
- machineconfig/scripts/python/agents.py,sha256=KVMf9lL1xAiFb0QfM9hV_GwUWzOymt_ALE8VG81aBJo,10200
130
+ machineconfig/scripts/python/agents.py,sha256=Bu2_my11RpvgOqUZuY8E0U8rlaKNL1IwBALIH8dYelU,10549
131
131
  machineconfig/scripts/python/cloud.py,sha256=kRH9Pt1yEkASFskIVEgRmkidrksdkgv2-bBmjLSxzSo,814
132
- machineconfig/scripts/python/croshell.py,sha256=4XIqEFmYCGn_CpeeAaN-1hBAwwWLQR0PKxBFNRvP2j0,6475
132
+ machineconfig/scripts/python/croshell.py,sha256=VRRf8oyh2DIkIv5sK7eV6thIglXa3tDD_FYlPc0NA2k,6476
133
133
  machineconfig/scripts/python/devops.py,sha256=3mG-4RlF9vzcfXO7ISsxwRICQpJRR8JMqxtxKLE70fs,1822
134
134
  machineconfig/scripts/python/devops_navigator.py,sha256=iR6HAYt0TA7efV_g6Lr9gPczN6mqvS0V5hShD1x-9R8,29537
135
135
  machineconfig/scripts/python/fire_jobs.py,sha256=UxMkQ8WqxmZx_u1gn9LV_Cn4FjbCAtuWUWupZl1UkUI,13486
136
136
  machineconfig/scripts/python/ftpx.py,sha256=17oCDB59C9z1RIpEoBTgmv8NFDTqhWzKWew9TqbP8vM,9406
137
- machineconfig/scripts/python/interactive.py,sha256=Rd406f3WpdTzDv7-dY1xbB90YHBk-EUBpsViX3QDGZM,11773
137
+ machineconfig/scripts/python/interactive.py,sha256=Zghe-b2Y6WIDPEhzsO1NDheTv4PAz4357SeL5AXJfh0,11777
138
138
  machineconfig/scripts/python/sessions.py,sha256=lO_aTnh7T05XoCa8Ox-ROAWBKMtbo-DZzlFDUqzSipM,8716
139
139
  machineconfig/scripts/python/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
140
140
  machineconfig/scripts/python/ai/generate_files.py,sha256=Vfjgd0skJu-WTgqUxmOVFzaNMfSFBaFmY5oGGVY7MZY,2860
@@ -177,20 +177,21 @@ machineconfig/scripts/python/croshell_helpers/start_slidev.py,sha256=FAJ1_WkAQ7K
177
177
  machineconfig/scripts/python/croshell_helpers/viewer.py,sha256=heQNjB9fwn3xxbPgMofhv1Lp6Vtkl76YjjexWWBM0pM,2041
178
178
  machineconfig/scripts/python/croshell_helpers/viewer_template.py,sha256=ve3Q1-iKhCLc0VJijKvAeOYp2xaFOeIOC_XW956GWCc,3944
179
179
  machineconfig/scripts/python/devops_helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
180
- machineconfig/scripts/python/devops_helpers/choose_pwsh_theme.ps1,sha256=bl27f8XAeLrm6WggorGmPR5uhsNwj5ayWsxus4UrKI8,1843
181
- machineconfig/scripts/python/devops_helpers/choose_wezterm_theme.py,sha256=pRXAGe2IpysYshsaF8CKEwHI8EGPtLcM8PtiAqM7vmM,3425
182
- machineconfig/scripts/python/devops_helpers/cli_config.py,sha256=LObo-YBjpfCB0_0CYQlYBqTtApM1RUOE_H28gEcH7PY,2870
180
+ machineconfig/scripts/python/devops_helpers/cli_config.py,sha256=hoQXU44kCdvYMxLXZErC1xcExRmb1EMgSi7IUDQl7KA,3262
183
181
  machineconfig/scripts/python/devops_helpers/cli_config_dotfile.py,sha256=9W9i8Qbs6i2NfTq0knywB3StvE_sHaZYZ0RslTyoVz8,2734
184
182
  machineconfig/scripts/python/devops_helpers/cli_data.py,sha256=f_2espL92n6SoNb5sFVMvrK7LA29HzfrFAKhxKaud1M,510
185
- machineconfig/scripts/python/devops_helpers/cli_nw.py,sha256=J3_ugdGrEhuL-4sEOTHrlZR4WYvQOYR9ALXNjxBWIlA,1397
183
+ machineconfig/scripts/python/devops_helpers/cli_nw.py,sha256=S4_6OwH_lZ73BPP6dY_InrB2rmwif6_h6DFLy8hlihY,1821
186
184
  machineconfig/scripts/python/devops_helpers/cli_repos.py,sha256=n8UnFjFIgTro-OMf47y5PAdYzqVYCSM6-5P90MvJOpw,9683
187
185
  machineconfig/scripts/python/devops_helpers/cli_self.py,sha256=XGWPZVZmwKaDOY_5IYj2l_Ke0ocjhfXP9NK5-nFwFSg,1467
188
186
  machineconfig/scripts/python/devops_helpers/cli_terminal.py,sha256=-SNCDrQHBDUZw2cNNrEw3K3owzmZASBjd5deBKB49YY,5358
189
187
  machineconfig/scripts/python/devops_helpers/devops_add_identity.py,sha256=wvjNgqsLmqD2SxbNCW_usqfp0LI-TDvcJJKGOWt2oFw,3775
190
- machineconfig/scripts/python/devops_helpers/devops_add_ssh_key.py,sha256=BXB-9RvuSZO0YTbnM2azeABW2ngLW4SKhhAGAieMzfw,6873
188
+ machineconfig/scripts/python/devops_helpers/devops_add_ssh_key.py,sha256=MwyHbpRP9r6DajARCdjEKVNrhEdv_yjd0lXxgEwjwsA,9179
191
189
  machineconfig/scripts/python/devops_helpers/devops_backup_retrieve.py,sha256=nK47Rc7gQuDCnkk6_sW1y82gBnDJ9TdHU8XwMPFBK9c,5591
192
190
  machineconfig/scripts/python/devops_helpers/devops_status.py,sha256=C1akn6mGteBVV9CiQnUX6H32ehnCgMdCyNgojXVQeqA,23287
193
191
  machineconfig/scripts/python/devops_helpers/devops_update_repos.py,sha256=dtBh9mNNJEukyV47Cug98S0hvG9e1U43B0EQSeNtvvs,9394
192
+ machineconfig/scripts/python/devops_helpers/themes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
193
+ machineconfig/scripts/python/devops_helpers/themes/choose_pwsh_theme.ps1,sha256=BrJNDHoSK_fHjHwbJqRf3sufSa7SKseBS2kT0qxibJQ,2958
194
+ machineconfig/scripts/python/devops_helpers/themes/choose_wezterm_theme.py,sha256=pRXAGe2IpysYshsaF8CKEwHI8EGPtLcM8PtiAqM7vmM,3425
194
195
  machineconfig/scripts/python/helpers_fire/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
195
196
  machineconfig/scripts/python/helpers_fire/fire_agents_help_launch.py,sha256=RAee8ethEIxyQpRKqe6u9NwIOKWTspAF-nzmPap6a5k,5506
196
197
  machineconfig/scripts/python/helpers_fire/fire_agents_help_search.py,sha256=qIfSS_su2YJ1Gb0_lu4cbjlJlYMBw0v52NTGiSrGjk8,2991
@@ -376,7 +377,7 @@ machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh,sha256=F5dbg0n9RHsKG
376
377
  machineconfig/setup_linux/ssh/openssh_all.sh,sha256=3dg6HEUFbHQOzLfSAtzK_D_GB8rGCCp_aBnxNdnidVc,824
377
378
  machineconfig/setup_linux/ssh/openssh_wsl.sh,sha256=1eeRGrloVB34K5z8yWVUMG5b9pV-WBfHgV9jqXiYgCQ,1398
378
379
  machineconfig/setup_linux/web_shortcuts/android.sh,sha256=gzep6bBhK7FCBvGcXK0fdJCtkSfBOftt0aFyDZq_eMs,68
379
- machineconfig/setup_linux/web_shortcuts/interactive.sh,sha256=NwrHKEPHW1PIkl3Yi7BEQL8Mdsfs7_FX5Ci7cKOrGZg,219
380
+ machineconfig/setup_linux/web_shortcuts/interactive.sh,sha256=cFfIhRRGGHprXkZptfKdVG7XExbJqAXL7CHkQvn5I6A,207
380
381
  machineconfig/setup_windows/__init__.py,sha256=wVpUqoLqXl-_-bRd7gZw_PJ7WZ2GtOqfFMzo_lIwieg,454
381
382
  machineconfig/setup_windows/apps.ps1,sha256=G5GqZ9G0aiQr_A-HaahtRdzpaTTdW6n3DRKMZWDTSPc,11214
382
383
  machineconfig/setup_windows/machineconfig.ps1,sha256=gIQBOLIh65oUXgSjYMeYeD6lU1Bu80LZ59xqRc3T3BA,918
@@ -384,11 +385,10 @@ machineconfig/setup_windows/uv.ps1,sha256=mzkFJUQ57dukVQtY7WqAQIVUDMcixnkir8aNM_
384
385
  machineconfig/setup_windows/others/docker.ps1,sha256=M8NfsSxH8YlmY92J4rSe1xWOwTW8IFrdgb8cI8Riu2E,311
385
386
  machineconfig/setup_windows/others/obs.ps1,sha256=2andchcXpxS3rqZjGaMpY5VShxTAKWvw6eCrayjuaLo,30
386
387
  machineconfig/setup_windows/others/power_options.ps1,sha256=c7Hn94jBD5GWF29CxMhmNpuM0hgXTQgVJmIRR_7sdcY,182
387
- machineconfig/setup_windows/ssh/openssh-server.ps1,sha256=7FopRdNn8hQbst4Cq_T1qoU_Q397Q_O6B2JgH2FdZxE,2531
388
- machineconfig/setup_windows/ssh/openssh-server_add-sshkey.ps1,sha256=qiNC02kzUZi6KBV7O-nRQ7pQ0OGixbq-rUvSCQ7TVxc,1656
389
- machineconfig/setup_windows/ssh/openssh-server_add_identity.ps1,sha256=b8ZXpmNUSw3IMYvqSY7ClpdWPG39FS7MefoWnRhWN2U,506
390
- machineconfig/setup_windows/ssh/openssh_all.ps1,sha256=-mBGNRJSxsY6Z3gFMwIoL_3poj943acjfzXwGo2YFu4,864
391
- machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=47KY5sr8Cy3bfzFCszwnGeQpIHpjh7r8_znv3TZhqWY,221
388
+ machineconfig/setup_windows/ssh/add-sshkey.ps1,sha256=qfPdqCpd9KP3VhH4ifsUm1Xvec7c0QVl4Wt8JIAm9HQ,1653
389
+ machineconfig/setup_windows/ssh/add_identity.ps1,sha256=b8ZXpmNUSw3IMYvqSY7ClpdWPG39FS7MefoWnRhWN2U,506
390
+ machineconfig/setup_windows/ssh/openssh-server.ps1,sha256=OMlYQdvuJQNxF5EILLPizB6BZAT3jAmDsv1WcVVxpFQ,2529
391
+ machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=2thf2ONXtwOLEDRpg0tX_dj-P74hZMfk7s9MUm7J2jA,210
392
392
  machineconfig/setup_windows/wt_and_pwsh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
393
393
  machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py,sha256=ogxJnwpdcpH7N6dFJu95UCNoGYirZKQho_3X0F_hmXs,6791
394
394
  machineconfig/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -414,7 +414,7 @@ machineconfig/utils/ai/generate_file_checklist.py,sha256=ajbmhcBToRugl75c_KZRq2X
414
414
  machineconfig/utils/cloud/onedrive/setup_oauth.py,sha256=ZTVkqgrwbV_EoPvyT8dyOTUE0ur3BW4sa9o6QYtt5Bo,2341
415
415
  machineconfig/utils/cloud/onedrive/transaction.py,sha256=m-aNcnWj_gfZVvJOSpkdIqjZxU_3nXx2CA-qKbQgP3I,26232
416
416
  machineconfig/utils/files/ascii_art.py,sha256=cNJaJC07vx94fS44-tzgfbfBeCwXVrgpnWGBLUnfC38,5212
417
- machineconfig/utils/files/dbms.py,sha256=xJTg6H_AvZWsduuDaSs4_KdUu__rO8LXrE_hrcXTgNM,17203
417
+ machineconfig/utils/files/dbms.py,sha256=oXDIqWLDiSO2icdeTMgTfd84yq6beDk89FCC8OZ8NcI,11277
418
418
  machineconfig/utils/files/headers.py,sha256=F-sudsZ1JyAcmZNO4FdcyhoClbCdb2vMlqceT36zfhE,3717
419
419
  machineconfig/utils/files/read.py,sha256=R1bvIIdiFX9N0JyzUISqVfewYFq30cY3z0kqSlKGtuA,4566
420
420
  machineconfig/utils/files/ouch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -428,8 +428,8 @@ machineconfig/utils/schemas/fire_agents/fire_agents_input.py,sha256=Xbi59rU35AzR
428
428
  machineconfig/utils/schemas/installer/installer_types.py,sha256=QClRY61QaduBPJoSpdmTIdgS9LS-RvE-QZ-D260tD3o,1214
429
429
  machineconfig/utils/schemas/layouts/layout_types.py,sha256=TcqlZdGVoH8htG5fHn1KWXhRdPueAcoyApppZsPAPto,2020
430
430
  machineconfig/utils/schemas/repos/repos_types.py,sha256=ECVr-3IVIo8yjmYmVXX2mnDDN1SLSwvQIhx4KDDQHBQ,405
431
- machineconfig-5.33.dist-info/METADATA,sha256=HrFrUFDbEj0yvarH5SepTjuBvN6gS2RV5J_-E_JeteQ,2495
432
- machineconfig-5.33.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
433
- machineconfig-5.33.dist-info/entry_points.txt,sha256=z7b9guivf0GSKUG6b8ALgbDoRg2LuPfkGP_p-PxgX9g,469
434
- machineconfig-5.33.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
435
- machineconfig-5.33.dist-info/RECORD,,
431
+ machineconfig-5.35.dist-info/METADATA,sha256=1L8ZKnBEELZm81pwox26G8qLNAQVewvC1I2nyfIVS1g,3040
432
+ machineconfig-5.35.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
433
+ machineconfig-5.35.dist-info/entry_points.txt,sha256=z7b9guivf0GSKUG6b8ALgbDoRg2LuPfkGP_p-PxgX9g,469
434
+ machineconfig-5.35.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
435
+ machineconfig-5.35.dist-info/RECORD,,
@@ -1,22 +0,0 @@
1
-
2
- # install server (sshd).
3
- Invoke-WebRequest https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/openssh-server.ps1 | Invoke-Expression
4
-
5
- if (!$pubkey_string) {
6
- $pubkey_url = 'https://github.com/thisismygitrepo.keys' # (CHANGE APPROPRIATELY)
7
- $pubkey_string = (Invoke-WebRequest $pubkey_url).Content
8
- } else {
9
- Write-Output "pubkey_string is already defined."
10
- }
11
-
12
-
13
- echo $null >> $HOME/.ssh/authorized_keys # powershell way of touching a file if it doesn't exist
14
- echo $pubkey_string >> $HOME/.ssh/authorized_keys
15
- echo $pubkey_string > $HOME/.ssh/pubkey.pub
16
-
17
- Invoke-WebRequest https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/openssh-server_add-sshkey.ps1 | Invoke-Expression
18
- ipconfig.exe
19
-
20
- echo "Done"
21
- echo "USE: ssh $env:USERNAME@$env:COMPUTERNAME -p 22"
22
-