machineconfig 5.37__py3-none-any.whl → 5.39__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.
- machineconfig/cluster/remote/script_execution.py +0 -1
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +2 -4
- machineconfig/jobs/installer/check_installations.py +2 -2
- machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +12 -12
- machineconfig/jobs/installer/installer_data.json +53 -2
- machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -3
- machineconfig/profile/create_helper.py +26 -0
- machineconfig/profile/{create.py → create_links.py} +6 -6
- machineconfig/profile/{create_frontend.py → create_links_export.py} +6 -10
- machineconfig/profile/{shell.py → create_shell_profile.py} +12 -37
- machineconfig/scripts/linux/{share_cloud.sh → other/share_cloud.sh} +3 -0
- machineconfig/scripts/linux/z_ls +2 -2
- machineconfig/scripts/python/agents.py +0 -1
- machineconfig/scripts/python/ai/initai.py +3 -4
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +0 -1
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +0 -1
- machineconfig/scripts/python/ai/solutions/generic.py +1 -0
- machineconfig/scripts/python/croshell.py +12 -2
- machineconfig/scripts/python/croshell_helpers/start_slidev.py +2 -2
- machineconfig/scripts/python/devops.py +4 -21
- machineconfig/scripts/python/devops_helpers/cli_config.py +8 -8
- machineconfig/scripts/python/devops_helpers/cli_config_dotfile.py +3 -3
- machineconfig/scripts/python/devops_helpers/cli_nw.py +2 -1
- machineconfig/scripts/python/devops_helpers/cli_repos.py +1 -3
- machineconfig/scripts/python/devops_helpers/cli_self.py +22 -9
- machineconfig/scripts/python/devops_helpers/cli_share_server.py +109 -0
- machineconfig/scripts/python/devops_helpers/cli_terminal.py +35 -23
- machineconfig/scripts/python/devops_helpers/devops_status.py +7 -80
- machineconfig/scripts/python/devops_helpers/devops_update_repos.py +64 -45
- machineconfig/scripts/python/devops_helpers/themes/choose_pwsh_theme.ps1 +16 -15
- machineconfig/scripts/python/devops_navigator.py +183 -80
- machineconfig/scripts/python/fire_jobs.py +4 -1
- machineconfig/scripts/python/ftpx.py +0 -1
- machineconfig/scripts/python/helpers_fire/{fire_gemini.py → agentic_frameworks/fire_gemini.py} +12 -9
- machineconfig/scripts/python/helpers_fire/agentic_frameworks/fire_qwen.py +43 -0
- machineconfig/scripts/python/helpers_fire/fire_agents_help_launch.py +4 -4
- machineconfig/scripts/python/helpers_fire/template.ps1 +29 -0
- machineconfig/scripts/python/helpers_fire/template.sh +1 -1
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +3 -3
- machineconfig/scripts/python/interactive.py +5 -4
- machineconfig/scripts/python/nw/mount_nfs +1 -1
- machineconfig/scripts/python/nw/mount_nw_drive +1 -2
- machineconfig/scripts/python/repos_helpers/count_lines_frontend.py +1 -1
- machineconfig/scripts/python/repos_helpers/entrypoint.py +2 -2
- machineconfig/scripts/python/repos_helpers/record.py +2 -2
- machineconfig/scripts/python/sessions_helpers/sessions_multiprocess.py +3 -1
- machineconfig/scripts/windows/{mount_nfs.ps1 → mounts/mount_nfs.ps1} +1 -3
- machineconfig/scripts/windows/{mount_ssh.ps1 → mounts/mount_ssh.ps1} +1 -1
- machineconfig/settings/lf/linux/lfrc +4 -7
- machineconfig/settings/lf/windows/lfrc +4 -22
- machineconfig/settings/lvim/windows/archive/config_additional.lua +0 -6
- machineconfig/settings/pistol/pistol.conf +1 -1
- machineconfig/settings/shells/bash/init.sh +9 -8
- machineconfig/settings/shells/pwsh/init.ps1 +10 -4
- machineconfig/settings/svim/linux/init.toml +0 -4
- machineconfig/settings/svim/windows/init.toml +0 -3
- machineconfig/setup_linux/web_shortcuts/interactive.sh +22 -0
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +34 -1
- machineconfig/utils/files/dbms.py +4 -1
- machineconfig/utils/installer_utils/installer.py +12 -0
- machineconfig/utils/installer_utils/installer_abc.py +26 -9
- machineconfig/utils/installer_utils/installer_class.py +1 -1
- machineconfig/utils/io.py +0 -18
- machineconfig/utils/scheduler.py +3 -4
- machineconfig/utils/source_of_truth.py +2 -4
- machineconfig/utils/ssh.py +1 -1
- {machineconfig-5.37.dist-info → machineconfig-5.39.dist-info}/METADATA +8 -4
- {machineconfig-5.37.dist-info → machineconfig-5.39.dist-info}/RECORD +84 -114
- machineconfig/jobs/windows/start_terminal.ps1 +0 -6
- machineconfig/jobs/windows/startup_file.cmd +0 -2
- machineconfig/scripts/cloud/init.sh +0 -105
- machineconfig/scripts/linux/agents +0 -2
- machineconfig/scripts/linux/cloud +0 -2
- machineconfig/scripts/linux/croshell +0 -3
- machineconfig/scripts/linux/devops +0 -2
- machineconfig/scripts/linux/fire +0 -2
- machineconfig/scripts/linux/ftpx +0 -2
- machineconfig/scripts/linux/kill_process +0 -2
- machineconfig/scripts/linux/sessions +0 -2
- machineconfig/scripts/linux/start_terminals +0 -3
- machineconfig/scripts/windows/agents.ps1 +0 -1
- machineconfig/scripts/windows/cloud.ps1 +0 -1
- machineconfig/scripts/windows/croshell.ps1 +0 -1
- machineconfig/scripts/windows/devops.ps1 +0 -1
- machineconfig/scripts/windows/fire.ps1 +0 -1
- machineconfig/scripts/windows/ftpx.ps1 +0 -1
- machineconfig/scripts/windows/gpt.ps1 +0 -1
- machineconfig/scripts/windows/grep.ps1 +0 -2
- machineconfig/scripts/windows/kill_process.ps1 +0 -1
- machineconfig/scripts/windows/nano.ps1 +0 -3
- machineconfig/scripts/windows/pomodoro.ps1 +0 -1
- machineconfig/scripts/windows/reload_path.ps1 +0 -3
- machineconfig/scripts/windows/scheduler.ps1 +0 -1
- machineconfig/scripts/windows/sessions.ps1 +0 -1
- machineconfig/scripts/windows/snapshot.ps1 +0 -1
- machineconfig/scripts/windows/start_slidev.ps1 +0 -1
- machineconfig/scripts/windows/start_terminals.ps1 +0 -1
- machineconfig/scripts/windows/wsl_rdp_windows_port_forwarding.ps1 +0 -46
- machineconfig/scripts/windows/wsl_ssh_windows_port_forwarding.ps1 +0 -76
- machineconfig/setup_linux/machineconfig.sh +0 -20
- machineconfig/setup_windows/machineconfig.ps1 +0 -27
- /machineconfig/scripts/linux/{share_nfs → other/share_nfs} +0 -0
- /machineconfig/scripts/linux/{share_smb → other/share_smb} +0 -0
- /machineconfig/scripts/linux/{start_docker → other/start_docker} +0 -0
- /machineconfig/scripts/linux/{switch_ip → other/switch_ip} +0 -0
- /machineconfig/scripts/{windows/share_nfs.ps1 → python/helpers_fire/agentic_frameworks/__init__.py} +0 -0
- /machineconfig/scripts/python/helpers_fire/{fire_crush.json → agentic_frameworks/fire_crush.json} +0 -0
- /machineconfig/scripts/python/helpers_fire/{fire_crush.py → agentic_frameworks/fire_crush.py} +0 -0
- /machineconfig/scripts/python/helpers_fire/{fire_cursor_agents.py → agentic_frameworks/fire_cursor_agents.py} +0 -0
- /machineconfig/scripts/windows/{mount_nw.ps1 → mounts/mount_nw.ps1} +0 -0
- /machineconfig/scripts/windows/{mount_smb.ps1 → mounts/mount_smb.ps1} +0 -0
- /machineconfig/scripts/windows/{share_cloud.cmd → mounts/share_cloud.cmd} +0 -0
- /machineconfig/scripts/windows/{share_smb.ps1 → mounts/share_smb.ps1} +0 -0
- /machineconfig/scripts/windows/{unlock_bitlocker.ps1 → mounts/unlock_bitlocker.ps1} +0 -0
- {machineconfig-5.37.dist-info → machineconfig-5.39.dist-info}/WHEEL +0 -0
- {machineconfig-5.37.dist-info → machineconfig-5.39.dist-info}/entry_points.txt +0 -0
- {machineconfig-5.37.dist-info → machineconfig-5.39.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
|
-
remote_cmd = f"$HOME
|
|
56
|
+
remote_cmd = f"$HOME/.local/bin devops self run-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())
|
|
@@ -145,7 +143,7 @@ if __name__ == "__main__":
|
|
|
145
143
|
check_timestamp = timestamp_result.stdout.strip() if timestamp_result.returncode == 0 else "unknown"
|
|
146
144
|
|
|
147
145
|
check_script = self._create_fresh_check_script(command)
|
|
148
|
-
remote_cmd = f"$HOME
|
|
146
|
+
remote_cmd = f"$HOME/.local/bin/devops self run-python -c {shlex.quote(check_script)}"
|
|
149
147
|
result = self.remote_executor.run_command(remote_cmd, timeout=15)
|
|
150
148
|
|
|
151
149
|
if result.returncode == 0:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
import platform
|
|
3
|
-
from machineconfig.utils.source_of_truth import
|
|
3
|
+
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
APP_SUMMARY_PATH =
|
|
6
|
+
APP_SUMMARY_PATH = CONFIG_ROOT.joinpath(f"profile/records/{platform.system().lower()}/apps_summary_report.csv")
|
|
7
7
|
# CLOUD: str = "gdw" # Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
|
|
8
8
|
# # my onedrive doesn't allow sharing.
|
|
9
9
|
|
|
@@ -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": "
|
|
29
|
-
"linux": "
|
|
30
|
-
"macos": "
|
|
28
|
+
"windows": "CascadiaCode.zip",
|
|
29
|
+
"linux": "CascadiaCode.zip",
|
|
30
|
+
"macos": "CascadiaCode.zip",
|
|
31
31
|
},
|
|
32
32
|
"arm64": {
|
|
33
|
-
"windows": "
|
|
34
|
-
"linux": "
|
|
35
|
-
"macos": "
|
|
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
|
-
|
|
45
|
-
|
|
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
|
|
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("
|
|
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": "
|
|
1365
|
+
"appName": "bw",
|
|
1332
1366
|
"repoURL": "CMD",
|
|
1333
|
-
"doc": "🔐
|
|
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
|
-
|
|
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
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Literal
|
|
3
|
+
from machineconfig.utils.source_of_truth import LIBRARY_ROOT, CONFIG_ROOT
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def copy_assets_to_machine(which: Literal["scripts", "settings"]):
|
|
7
|
+
# callers, symlink public, shell profile adder (requires init.ps1 and scripts dir to be present on machine)
|
|
8
|
+
import platform
|
|
9
|
+
if platform.system().lower() == "windows":
|
|
10
|
+
system = "windows"
|
|
11
|
+
elif platform.system().lower() == "linux" or platform.system().lower() == "darwin":
|
|
12
|
+
system = "linux"
|
|
13
|
+
else:
|
|
14
|
+
raise NotImplementedError(f"System {platform.system().lower()} not supported")
|
|
15
|
+
match which:
|
|
16
|
+
case "scripts":
|
|
17
|
+
source = LIBRARY_ROOT.joinpath("scripts", system)
|
|
18
|
+
target = CONFIG_ROOT.joinpath("scripts", system)
|
|
19
|
+
case "settings":
|
|
20
|
+
source = LIBRARY_ROOT.joinpath("settings", system)
|
|
21
|
+
target = CONFIG_ROOT.joinpath("settings", system)
|
|
22
|
+
from machineconfig.utils.path_extended import PathExtended
|
|
23
|
+
PathExtended(source).copy(folder=target.parent)
|
|
24
|
+
PathExtended(source).copy(folder=target.parent)
|
|
25
|
+
|
|
26
|
+
|
|
@@ -13,7 +13,7 @@ from rich.table import Table
|
|
|
13
13
|
|
|
14
14
|
from machineconfig.utils.path_extended import PathExtended
|
|
15
15
|
from machineconfig.utils.links import symlink_map, copy_map
|
|
16
|
-
from machineconfig.utils.source_of_truth import LIBRARY_ROOT,
|
|
16
|
+
from machineconfig.utils.source_of_truth import LIBRARY_ROOT, CONFIG_ROOT
|
|
17
17
|
|
|
18
18
|
import platform
|
|
19
19
|
import subprocess
|
|
@@ -63,7 +63,7 @@ def read_mapper() -> MapperFileData:
|
|
|
63
63
|
"contents": file_base.get("contents"),
|
|
64
64
|
"copy": file_base.get("copy"),
|
|
65
65
|
}
|
|
66
|
-
if "
|
|
66
|
+
if "CONFIG_ROOT" in file_map["self_managed_config_file_path"]:
|
|
67
67
|
if program_key not in public:
|
|
68
68
|
public[program_key] = []
|
|
69
69
|
public[program_key].append(file_map)
|
|
@@ -107,7 +107,7 @@ def apply_mapper(mapper_data: dict[str, list[ConfigMapper]],
|
|
|
107
107
|
console.rule(f"🔄 Processing [bold]{program_name}[/] symlinks", style="cyan")
|
|
108
108
|
for a_mapper in program_files:
|
|
109
109
|
config_file_default_path = PathExtended(a_mapper["config_file_default_path"])
|
|
110
|
-
self_managed_config_file_path = PathExtended(a_mapper["self_managed_config_file_path"].replace("
|
|
110
|
+
self_managed_config_file_path = PathExtended(a_mapper["self_managed_config_file_path"].replace("CONFIG_ROOT", CONFIG_ROOT.as_posix()))
|
|
111
111
|
|
|
112
112
|
# Determine whether to use copy or symlink
|
|
113
113
|
use_copy = method == "copy" or a_mapper.get("copy", False)
|
|
@@ -215,7 +215,7 @@ def apply_mapper(mapper_data: dict[str, list[ConfigMapper]],
|
|
|
215
215
|
|
|
216
216
|
if system == "Linux":
|
|
217
217
|
console.print("\n[bold]📜 Setting executable permissions for scripts...[/bold]")
|
|
218
|
-
subprocess.run(f"chmod +x {
|
|
218
|
+
subprocess.run(f"chmod +x {CONFIG_ROOT.joinpath(f'scripts/{system.lower()}')} -R", shell=True, capture_output=True, text=True)
|
|
219
219
|
console.print("[green]✅ Script permissions updated[/green]")
|
|
220
220
|
|
|
221
221
|
# Display operation summary table
|
|
@@ -250,8 +250,8 @@ def apply_mapper(mapper_data: dict[str, list[ConfigMapper]],
|
|
|
250
250
|
# Export operation records to CSV
|
|
251
251
|
import csv
|
|
252
252
|
from datetime import datetime
|
|
253
|
-
|
|
254
|
-
csv_dir = PathExtended(
|
|
253
|
+
|
|
254
|
+
csv_dir = PathExtended(CONFIG_ROOT).joinpath("symlink_operations")
|
|
255
255
|
csv_dir.mkdir(parents=True, exist_ok=True)
|
|
256
256
|
|
|
257
257
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import typer
|
|
3
3
|
from typing import Optional, Literal
|
|
4
|
-
from pathlib import Path
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
def main_public_from_parser(method: Literal["symlink", "copy"] = typer.Option(..., help="Method to use for setting up the config file."),
|
|
@@ -12,12 +11,7 @@ def main_public_from_parser(method: Literal["symlink", "copy"] = typer.Option(..
|
|
|
12
11
|
SOURCE = Self-Managed-Config-File-Path
|
|
13
12
|
TARGET = Config-File-Default-Path
|
|
14
13
|
For public config files, the source always exists, because we know it comes from machineconfig repo."""
|
|
15
|
-
from machineconfig.profile.
|
|
16
|
-
if method == "symlink":
|
|
17
|
-
machineconfig_repo_path = Path.home().joinpath("code/machineconfig")
|
|
18
|
-
if not machineconfig_repo_path.exists() or not machineconfig_repo_path.is_dir():
|
|
19
|
-
raise FileNotFoundError(f"machineconfig repo not found at {machineconfig_repo_path}. Cannot create symlinks to non-existing source files.")
|
|
20
|
-
|
|
14
|
+
from machineconfig.profile.create_links import ConfigMapper, read_mapper
|
|
21
15
|
mapper_full = read_mapper()["public"]
|
|
22
16
|
if which is None:
|
|
23
17
|
assert interactive is True
|
|
@@ -31,7 +25,9 @@ def main_public_from_parser(method: Literal["symlink", "copy"] = typer.Option(..
|
|
|
31
25
|
items_chosen = which.split(",")
|
|
32
26
|
items_objections: dict[str, list[ConfigMapper]] = {item: mapper_full[item] for item in items_chosen if item in mapper_full}
|
|
33
27
|
|
|
34
|
-
from machineconfig.profile.
|
|
28
|
+
from machineconfig.profile.create_links import apply_mapper
|
|
29
|
+
from machineconfig.profile.create_helper import copy_assets_to_machine
|
|
30
|
+
copy_assets_to_machine(which="settings") # config files live here and will be linked to.
|
|
35
31
|
apply_mapper(mapper_data=items_objections, on_conflict=on_conflict, method=method)
|
|
36
32
|
|
|
37
33
|
|
|
@@ -39,7 +35,7 @@ def main_private_from_parser(method: Literal["symlink", "copy"] = typer.Option(.
|
|
|
39
35
|
on_conflict: Literal["throwError", "overwriteSelfManaged", "backupSelfManaged", "overwriteDefaultPath", "backupDefaultPath"] = typer.Option("throwError", help="Action to take on conflict"),
|
|
40
36
|
which: Optional[str] = typer.Option(None, help="Specific items to process"),
|
|
41
37
|
interactive: bool = typer.Option(False, help="Run in interactive mode")):
|
|
42
|
-
from machineconfig.profile.
|
|
38
|
+
from machineconfig.profile.create_links import ConfigMapper, read_mapper
|
|
43
39
|
|
|
44
40
|
mapper_full = read_mapper()["private"]
|
|
45
41
|
if which is None:
|
|
@@ -54,5 +50,5 @@ def main_private_from_parser(method: Literal["symlink", "copy"] = typer.Option(.
|
|
|
54
50
|
items_chosen = which.split(",")
|
|
55
51
|
items_objections: dict[str, list[ConfigMapper]] = {item: mapper_full[item] for item in items_chosen if item in mapper_full}
|
|
56
52
|
|
|
57
|
-
from machineconfig.profile.
|
|
53
|
+
from machineconfig.profile.create_links import apply_mapper
|
|
58
54
|
apply_mapper(mapper_data=items_objections, on_conflict=on_conflict, method=method)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"""shell"""
|
|
2
2
|
|
|
3
|
-
from typing import Literal
|
|
4
3
|
from machineconfig.utils.path_extended import PathExtended
|
|
5
|
-
from machineconfig.utils.source_of_truth import
|
|
4
|
+
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
6
5
|
|
|
7
6
|
import platform
|
|
8
7
|
import os
|
|
@@ -36,51 +35,27 @@ def get_shell_profile_path() -> PathExtended:
|
|
|
36
35
|
return profile_path
|
|
37
36
|
|
|
38
37
|
|
|
39
|
-
def create_default_shell_profile(
|
|
40
|
-
if method == "reference":
|
|
41
|
-
machineconfig_repo_path = PathExtended.home().joinpath("code/machineconfig")
|
|
42
|
-
if not machineconfig_repo_path.exists() or not machineconfig_repo_path.is_dir():
|
|
43
|
-
raise FileNotFoundError(f"machineconfig repo not found at {machineconfig_repo_path}. Cannot create symlinks to non-existing source files.")
|
|
44
|
-
|
|
38
|
+
def create_default_shell_profile() -> None:
|
|
45
39
|
shell_profile_path = get_shell_profile_path()
|
|
46
40
|
shell_profile = shell_profile_path.read_text(encoding="utf-8")
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
init_script_copy_path = PathExtended(CONFIG_PATH).joinpath("profile/init.ps1").collapseuser()
|
|
52
|
-
init_script_copy_path.parent.mkdir(parents=True, exist_ok=True)
|
|
53
|
-
init_script.copy(path=init_script_copy_path, overwrite=True)
|
|
42
|
+
from machineconfig.profile.create_helper import copy_assets_to_machine
|
|
43
|
+
copy_assets_to_machine("settings") # init.ps1 or init.sh live here
|
|
44
|
+
copy_assets_to_machine("scripts") # init scripts are going to reference those scripts.
|
|
54
45
|
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
if system == "Windows":
|
|
47
|
+
init_script = PathExtended(CONFIG_ROOT).joinpath("settings/shells/pwsh/init.ps1")
|
|
48
|
+
source_line = f""". {str(init_script.collapseuser()).replace("~", "$HOME")}"""
|
|
57
49
|
else:
|
|
58
|
-
init_script = PathExtended(
|
|
59
|
-
|
|
60
|
-
init_script_copy_path.parent.mkdir(parents=True, exist_ok=True)
|
|
61
|
-
init_script.copy(path=init_script_copy_path, overwrite=True)
|
|
62
|
-
|
|
63
|
-
source_using_reference = f"""source {str(init_script.collapseuser()).replace("~", "$HOME")}"""
|
|
64
|
-
source_using_copy = f"""source {str(init_script_copy_path).replace("~", "$HOME")}"""
|
|
65
|
-
|
|
66
|
-
match method:
|
|
67
|
-
case "copy":
|
|
68
|
-
line_of_interest = source_using_copy
|
|
69
|
-
line_other = source_using_reference
|
|
70
|
-
case "reference":
|
|
71
|
-
line_of_interest = source_using_reference
|
|
72
|
-
line_other = source_using_copy
|
|
50
|
+
init_script = PathExtended(CONFIG_ROOT).joinpath("settings/shells/bash/init.sh")
|
|
51
|
+
source_line = f"""source {str(init_script).replace("~", "$HOME")}"""
|
|
73
52
|
|
|
74
53
|
was_shell_updated = False
|
|
75
|
-
if
|
|
76
|
-
shell_profile = shell_profile.replace(line_other, "")
|
|
77
|
-
was_shell_updated = True
|
|
78
|
-
|
|
79
|
-
if line_of_interest in shell_profile:
|
|
54
|
+
if source_line in shell_profile:
|
|
80
55
|
console.print(Panel("🔄 PROFILE | Skipping init script sourcing - already present in profile", title="[bold blue]Profile[/bold blue]", border_style="blue"))
|
|
81
56
|
else:
|
|
82
57
|
console.print(Panel("📝 PROFILE | Adding init script sourcing to profile", title="[bold blue]Profile[/bold blue]", border_style="blue"))
|
|
83
|
-
shell_profile += "\n" +
|
|
58
|
+
shell_profile += "\n" + source_line + "\n"
|
|
84
59
|
if system == "Linux":
|
|
85
60
|
result = subprocess.run(["cat", "/proc/version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
|
|
86
61
|
if result.returncode == 0 and result.stdout:
|
|
@@ -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
|
machineconfig/scripts/linux/z_ls
CHANGED
|
@@ -40,11 +40,11 @@ fi
|
|
|
40
40
|
if [[ "${ZJ_SESSIONS}" == *"(current)"* ]]; then
|
|
41
41
|
# if so, then we are in a zellijsession
|
|
42
42
|
echo "already inside a session, existing."
|
|
43
|
-
COMMANDS=$(ls $HOME/
|
|
43
|
+
COMMANDS=$(ls $HOME/.config/machineconfig/settings/zellij/commands)
|
|
44
44
|
# fzf the results
|
|
45
45
|
res="$(echo -e "${COMMANDS}" | fzf --ansi)"
|
|
46
46
|
# run the bash fiZJ_SESSIONSle chosen
|
|
47
|
-
bash $HOME/
|
|
47
|
+
bash $HOME/.config/machineconfig/settings/zellij/commands/$res
|
|
48
48
|
|
|
49
49
|
else # ==> we are not in a zellijsession
|
|
50
50
|
if [ "${NO_SESSIONS}" -ge 1 ]; then # sessions do exist
|
|
@@ -103,7 +103,6 @@ def create(
|
|
|
103
103
|
layoutfile = get_agents_launch_layout(session_root=agents_dir)
|
|
104
104
|
regenerate_py_code = f"""
|
|
105
105
|
#!/usr/bin/env uv run --python 3.13 --with machineconfig
|
|
106
|
-
#!/usr/bin/env uv run --no-dev --project $HOME/code/machineconfig
|
|
107
106
|
fire_agents create --context-path "{prompt_material_path}" \\
|
|
108
107
|
--{search_strategy} "{context_path or keyword_search or filename_pattern}" \\
|
|
109
108
|
--prompt-path "{prompt_path or ''}" \\
|
|
@@ -23,12 +23,11 @@ uv init --python 3.13
|
|
|
23
23
|
uv venv
|
|
24
24
|
uv add --upgrade-package pylint pyright mypy pyrefly ty --dev # linters and type checkers
|
|
25
25
|
uv add --upgrade-package pytest --dev
|
|
26
|
-
|
|
26
|
+
uv add typer --dev
|
|
27
27
|
|
|
28
28
|
"""
|
|
29
|
-
import
|
|
30
|
-
|
|
31
|
-
subprocess.run(command_to_run, shell=True, check=True)
|
|
29
|
+
from machineconfig.utils.code import run_shell_script
|
|
30
|
+
run_shell_script(command_to_run)
|
|
32
31
|
else:
|
|
33
32
|
print("Terminating initai ...")
|
|
34
33
|
return
|
|
@@ -66,7 +66,6 @@ uv run -m cleanpy .
|
|
|
66
66
|
uv run -m ruff clean
|
|
67
67
|
# uv run -m ruff format .
|
|
68
68
|
uv run -m ruff check . --fix
|
|
69
|
-
uv run --no-dev --project $HOME/code/machineconfig -m machineconfig.scripts.python.ai.generate_files
|
|
70
69
|
|
|
71
70
|
New-Item -ItemType Directory -Force -Path .ai/linters | Out-Null
|
|
72
71
|
|
|
@@ -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,16 @@ from pathlib import Path
|
|
|
141
142
|
else:
|
|
142
143
|
if interpreter == "ipython": profile = f" --profile {ipython_profile} --no-banner"
|
|
143
144
|
else: profile = ""
|
|
144
|
-
|
|
145
|
+
if local:
|
|
146
|
+
from machineconfig.utils.source_of_truth import LIBRARY_ROOT
|
|
147
|
+
repo_root = LIBRARY_ROOT.parent.parent
|
|
148
|
+
if repo_root.parent.name == "code" and repo_root.name == "machineconfig" and repo_root.exists() and repo_root.is_dir():
|
|
149
|
+
ve_line = f"--project {str(repo_root)}"
|
|
150
|
+
else:
|
|
151
|
+
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"))
|
|
152
|
+
return
|
|
153
|
+
else: ve_line = "--with machineconfig[plot]"
|
|
154
|
+
fire_line = f"uv run --python 3.13 {ve_line} {interpreter} {interactivity} {profile} {str(pyfile)}"
|
|
145
155
|
|
|
146
156
|
from machineconfig.utils.code import run_shell_script
|
|
147
157
|
run_shell_script(fire_line, clean_env=False)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
slidev
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from machineconfig.utils.source_of_truth import
|
|
5
|
+
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
6
6
|
from machineconfig.utils.code import print_code
|
|
7
7
|
from machineconfig.utils.path_extended import PathExtended
|
|
8
8
|
from machineconfig.utils.terminal import Response
|
|
@@ -13,7 +13,7 @@ import platform
|
|
|
13
13
|
|
|
14
14
|
PORT_DEFAULT = 3030
|
|
15
15
|
|
|
16
|
-
SLIDEV_REPO = PathExtended(
|
|
16
|
+
SLIDEV_REPO = PathExtended(CONFIG_ROOT).joinpath(".cache/slidev")
|
|
17
17
|
if not SLIDEV_REPO.joinpath("components").exists():
|
|
18
18
|
print("📦 Initializing Slidev repository...")
|
|
19
19
|
subprocess.run(f"cd {SLIDEV_REPO.parent};npm init slidev@latest", check=False, shell=True, text=True)
|
|
@@ -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
|
-
|
|
8
|
+
import machineconfig.scripts.python.devops_helpers.cli_self as cli_self
|
|
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"
|
|
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(
|
|
27
|
+
app.add_typer(cli_self.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
|
-
|
|
32
|
+
app()
|
|
@@ -13,8 +13,8 @@ def private(method: Literal["symlink", "copy"] = typer.Option(..., "--method", "
|
|
|
13
13
|
which: Optional[str] = typer.Option(None, "--which", "-w", help="Specific items to process"),
|
|
14
14
|
interactive: bool = typer.Option(False, "--interactive", "-ia", help="Run in interactive mode")):
|
|
15
15
|
"""🔗 Manage private configuration files."""
|
|
16
|
-
import machineconfig.profile.
|
|
17
|
-
|
|
16
|
+
import machineconfig.profile.create_links_export as create_links_export
|
|
17
|
+
create_links_export.main_private_from_parser(method=method, on_conflict=on_conflict, which=which, interactive=interactive)
|
|
18
18
|
|
|
19
19
|
@config_apps.command(no_args_is_help=True)
|
|
20
20
|
def public(method: Literal["symlink", "copy"] = typer.Option(..., "--method", "-m", help="Method to use for setting up the config file."),
|
|
@@ -22,8 +22,8 @@ def public(method: Literal["symlink", "copy"] = typer.Option(..., "--method", "-
|
|
|
22
22
|
which: Optional[str] = typer.Option(None, "--which", "-w", help="Specific items to process"),
|
|
23
23
|
interactive: bool = typer.Option(False, "--interactive", "-ia", help="Run in interactive mode")):
|
|
24
24
|
"""🔗 Manage public configuration files."""
|
|
25
|
-
import machineconfig.profile.
|
|
26
|
-
|
|
25
|
+
import machineconfig.profile.create_links_export as create_links_export
|
|
26
|
+
create_links_export.main_public_from_parser(method=method, on_conflict=on_conflict, which=which, interactive=interactive)
|
|
27
27
|
|
|
28
28
|
@config_apps.command(no_args_is_help=True)
|
|
29
29
|
def dotfile(file: Annotated[str, typer.Argument(help="file/folder path.")],
|
|
@@ -35,11 +35,11 @@ def dotfile(file: Annotated[str, typer.Argument(help="file/folder path.")],
|
|
|
35
35
|
dotfile_module.main(file=file, overwrite=overwrite, dest=dest)
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
@config_apps.command(no_args_is_help=
|
|
39
|
-
def shell(
|
|
38
|
+
@config_apps.command(no_args_is_help=False)
|
|
39
|
+
def shell():
|
|
40
40
|
"""🔗 Configure your shell profile."""
|
|
41
|
-
from machineconfig.profile.
|
|
42
|
-
create_default_shell_profile(
|
|
41
|
+
from machineconfig.profile.create_shell_profile import create_default_shell_profile
|
|
42
|
+
create_default_shell_profile()
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
@config_apps.command(no_args_is_help=False)
|
|
@@ -23,7 +23,7 @@ def main(
|
|
|
23
23
|
|
|
24
24
|
from machineconfig.utils.links import symlink_map
|
|
25
25
|
from machineconfig.utils.path_extended import PathExtended
|
|
26
|
-
from machineconfig.utils.source_of_truth import
|
|
26
|
+
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
27
27
|
console = Console()
|
|
28
28
|
orig_path = PathExtended(file).expanduser().absolute()
|
|
29
29
|
if dest == "":
|
|
@@ -35,7 +35,7 @@ def main(
|
|
|
35
35
|
junction = orig_path.split(at=".config", sep=-1)[1]
|
|
36
36
|
else:
|
|
37
37
|
junction = orig_path.rel2home()
|
|
38
|
-
new_path = PathExtended(
|
|
38
|
+
new_path = PathExtended(CONFIG_ROOT).parent.parent.joinpath(junction)
|
|
39
39
|
else:
|
|
40
40
|
dest_path = PathExtended(dest).expanduser().absolute()
|
|
41
41
|
dest_path.mkdir(parents=True, exist_ok=True)
|
|
@@ -59,7 +59,7 @@ def main(
|
|
|
59
59
|
|
|
60
60
|
mapper_snippet = "\n".join(
|
|
61
61
|
[
|
|
62
|
-
f"[bold]📝 Edit configuration file:[/] [cyan]nano {PathExtended(
|
|
62
|
+
f"[bold]📝 Edit configuration file:[/] [cyan]nano {PathExtended(CONFIG_ROOT)}/symlinks/mapper.toml[/cyan]",
|
|
63
63
|
"",
|
|
64
64
|
f"[{new_path.parent.name}]",
|
|
65
65
|
f"{orig_path.name.split('.')[0]} = {{ this = '{orig_path.collapseuser().as_posix()}', to_this = '{new_path.collapseuser().as_posix()}' }}",
|