machineconfig 5.66__py3-none-any.whl → 5.68__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/jobs/installer/installer_data.json +3 -3
- machineconfig/scripts/python/agents.py +41 -28
- machineconfig/scripts/python/ai/generate_files.py +127 -17
- machineconfig/scripts/python/ai/solutions/generic.py +1 -0
- machineconfig/scripts/python/croshell.py +1 -1
- machineconfig/scripts/python/devops_helpers/cli_config.py +1 -1
- machineconfig/scripts/python/devops_helpers/cli_self.py +3 -3
- machineconfig/scripts/python/ftpx.py +6 -6
- machineconfig/scripts/python/interactive.py +2 -2
- machineconfig/scripts/python/nw/mount_nfs +1 -1
- machineconfig/scripts/python/nw/mount_nfs.py +2 -2
- machineconfig/scripts/python/nw/mount_ssh.py +1 -1
- machineconfig/scripts/python/repos_helpers/count_lines_frontend.py +1 -1
- machineconfig/scripts/python/sessions.py +1 -1
- machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
- machineconfig/setup_linux/apps.sh +0 -1
- machineconfig/setup_linux/web_shortcuts/interactive.sh +7 -7
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +7 -7
- machineconfig/utils/ssh.py +466 -247
- machineconfig/utils/ssh_utils/utils.py +0 -0
- {machineconfig-5.66.dist-info → machineconfig-5.68.dist-info}/METADATA +1 -1
- {machineconfig-5.66.dist-info → machineconfig-5.68.dist-info}/RECORD +25 -24
- {machineconfig-5.66.dist-info → machineconfig-5.68.dist-info}/WHEEL +0 -0
- {machineconfig-5.66.dist-info → machineconfig-5.68.dist-info}/entry_points.txt +0 -0
- {machineconfig-5.66.dist-info → machineconfig-5.68.dist-info}/top_level.txt +0 -0
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"fileNamePattern": {
|
|
9
9
|
"amd64": {
|
|
10
10
|
"linux": "jq-linux-amd64",
|
|
11
|
-
"windows":
|
|
12
|
-
"macos":
|
|
11
|
+
"windows": "jq-windows-amd64.exe",
|
|
12
|
+
"macos": "jq-macos-amd64"
|
|
13
13
|
},
|
|
14
14
|
"arm64": {
|
|
15
15
|
"linux": "jq-linux-arm64",
|
|
16
16
|
"windows": null,
|
|
17
|
-
"macos":
|
|
17
|
+
"macos": "jq-macos-arm64"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
},
|
|
@@ -9,19 +9,17 @@ from machineconfig.scripts.python.helpers_fire.fire_agents_helper_types import A
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def create(
|
|
12
|
-
|
|
12
|
+
agent: AGENTS = typer.Option(default=..., help=f"Agent type. One of {', '.join(get_args(AGENTS)[:3])}"),
|
|
13
|
+
machine: MATCHINE = typer.Option(default=..., help=f"Machine to run agents on. One of {', '.join(get_args(MATCHINE))}"),
|
|
14
|
+
model: MODEL = typer.Option(default=..., help=f"Model to use (for crush agent). One of {', '.join(get_args(MODEL)[:3])}"),
|
|
15
|
+
provider: PROVIDER = typer.Option(default=..., help=f"Provider to use (for crush agent). One of {', '.join(get_args(PROVIDER)[:3])}"),
|
|
16
|
+
context_path: Optional[Path] = typer.Option(None, help="Path to the context file/folder, defaults to .ai/todo/"),
|
|
13
17
|
separator: str = typer.Option("\n", help="Separator for context"),
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
agent: AGENTS = typer.Option(..., help=f"Agent type. One of {', '.join(get_args(AGENTS))}"),
|
|
17
|
-
machine: MATCHINE = typer.Option(..., help=f"Machine to run agents on. One of {', '.join(get_args(MATCHINE))}"),
|
|
18
|
-
model: MODEL = typer.Option(..., help=f"Model to use (for crush agent). One of {', '.join(get_args(MODEL))}"),
|
|
19
|
-
provider: PROVIDER = typer.Option(..., help=f"Provider to use (for crush agent). One of {', '.join(get_args(PROVIDER))}"),
|
|
20
|
-
|
|
18
|
+
agent_load: int = typer.Option(13, help="Number of tasks per prompt"),
|
|
21
19
|
prompt: Optional[str] = typer.Option(None, help="Prompt prefix as string"),
|
|
22
20
|
prompt_path: Optional[Path] = typer.Option(None, help="Path to prompt file"),
|
|
23
21
|
job_name: str = typer.Option("AI_Agents", help="Job name"),
|
|
24
|
-
|
|
22
|
+
separate: bool = typer.Option(True, help="Keep prompt material in separate file to the context."),
|
|
25
23
|
output_path: Optional[Path] = typer.Option(None, help="Path to write the layout.json file"),
|
|
26
24
|
agents_dir: Optional[Path] = typer.Option(None, help="Directory to store agent files. If not provided, will be constructed automatically."),
|
|
27
25
|
):
|
|
@@ -43,40 +41,49 @@ def create(
|
|
|
43
41
|
raise typer.Exit(1)
|
|
44
42
|
typer.echo(f"Operating @ {repo_root}")
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
if context_path is None:
|
|
45
|
+
context_path = repo_root / ".ai" / "todo"
|
|
46
|
+
|
|
47
|
+
context_path_resolved = context_path.expanduser().resolve()
|
|
48
|
+
if not context_path_resolved.exists():
|
|
49
|
+
raise typer.BadParameter(f"Path does not exist: {context_path_resolved}")
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
if context_path_resolved.is_file():
|
|
52
|
+
prompt_material_re_splitted = chunk_prompts(context_path_resolved, tasks_per_prompt=agent_load, joiner=separator)
|
|
53
|
+
elif context_path_resolved.is_dir():
|
|
54
|
+
files = [f for f in context_path_resolved.rglob("*") if f.is_file()]
|
|
55
|
+
if not files:
|
|
56
|
+
raise typer.BadParameter(f"No files found in directory: {context_path_resolved}")
|
|
57
|
+
concatenated = separator.join(f.read_text(encoding="utf-8") for f in files)
|
|
58
|
+
prompt_material_re_splitted = [concatenated]
|
|
59
|
+
else:
|
|
60
|
+
raise typer.BadParameter(f"Path is neither file nor directory: {context_path_resolved}")
|
|
52
61
|
|
|
53
62
|
if prompt_path is not None:
|
|
54
63
|
prompt_prefix = prompt_path.read_text(encoding="utf-8")
|
|
55
64
|
else:
|
|
56
65
|
prompt_prefix = cast(str, prompt)
|
|
57
66
|
agent_selected = agent
|
|
58
|
-
keep_material_in_separate_file_input = separate_prompt_from_context
|
|
59
|
-
prompt_material_re_splitted = chunk_prompts(prompt_material_path, tasks_per_prompt=tasks_per_prompt, joiner=separator)
|
|
60
67
|
if agents_dir is None: agents_dir = repo_root / ".ai" / f"tmp_prompts/{job_name}_{randstr()}"
|
|
61
68
|
else:
|
|
62
69
|
import shutil
|
|
63
70
|
if agents_dir.exists():
|
|
64
71
|
shutil.rmtree(agents_dir)
|
|
65
72
|
prep_agent_launch(repo_root=repo_root, agents_dir=agents_dir, prompts_material=prompt_material_re_splitted,
|
|
66
|
-
keep_material_in_separate_file=
|
|
73
|
+
keep_material_in_separate_file=separate,
|
|
67
74
|
prompt_prefix=prompt_prefix, machine=machine, agent=agent_selected, model=model, provider=provider,
|
|
68
75
|
job_name=job_name)
|
|
69
76
|
layoutfile = get_agents_launch_layout(session_root=agents_dir)
|
|
70
77
|
regenerate_py_code = f"""
|
|
71
78
|
#!/usr/bin/env uv run --python 3.14 --with machineconfig
|
|
72
|
-
agents create "{
|
|
79
|
+
agents create "{context_path_resolved}" \\
|
|
73
80
|
--prompt-path "{prompt_path or ''}" \\
|
|
74
81
|
--agent "{agent_selected}" \\
|
|
75
82
|
--machine "{machine}" \\
|
|
76
83
|
--job-name "{job_name}" \\
|
|
77
|
-
--
|
|
84
|
+
--agent_load {agent_load} \\
|
|
78
85
|
--separator "{separator}" \\
|
|
79
|
-
{"--separate
|
|
86
|
+
{"--separate" if separate else ""}
|
|
80
87
|
"""
|
|
81
88
|
(agents_dir / "aa_agents_relaunch.py").write_text(data=regenerate_py_code, encoding="utf-8")
|
|
82
89
|
layout_output_path = output_path if output_path is not None else agents_dir / "layout.json"
|
|
@@ -153,8 +160,18 @@ def init_config():
|
|
|
153
160
|
add_ai_configs(repo_root=Path.cwd())
|
|
154
161
|
|
|
155
162
|
def get_app():
|
|
156
|
-
agents_app = typer.Typer(help="🤖 AI Agents management subcommands")
|
|
157
|
-
|
|
163
|
+
agents_app = typer.Typer(help="🤖 AI Agents management subcommands", no_args_is_help=True)
|
|
164
|
+
sep = "\n"
|
|
165
|
+
agents_full_help = f"""
|
|
166
|
+
Create agents layout file, ready to run.
|
|
167
|
+
{sep}
|
|
168
|
+
PROVIDER options: {', '.join(get_args(PROVIDER))}
|
|
169
|
+
{sep}
|
|
170
|
+
AGENT options: {', '.join(get_args(AGENTS))}
|
|
171
|
+
{sep}
|
|
172
|
+
MODEL options: {sep.join(get_args(MODEL))}
|
|
173
|
+
"""
|
|
174
|
+
agents_app.command("create", no_args_is_help=True, help=agents_full_help)(create)
|
|
158
175
|
agents_app.command("collect", no_args_is_help=True, help="Collect all agent materials into a single file.")(collect)
|
|
159
176
|
agents_app.command("make-template", no_args_is_help=False, help="Create a template for fire agents")(template)
|
|
160
177
|
agents_app.command("make-config", no_args_is_help=False, help="Initialize AI configurations in the current repository")(init_config)
|
|
@@ -164,14 +181,10 @@ def get_app():
|
|
|
164
181
|
agents_app.command(name="make-symlinks", no_args_is_help=True, help="Create symlinks to the current repo in ~/code_copies/")(create_symlink_command)
|
|
165
182
|
return agents_app
|
|
166
183
|
|
|
184
|
+
|
|
167
185
|
def main():
|
|
168
186
|
agents_app = get_app()
|
|
169
|
-
|
|
170
|
-
if len(sys.argv) == 1:
|
|
171
|
-
agents_app(["--help"])
|
|
172
|
-
else:
|
|
173
|
-
agents_app()
|
|
174
|
-
|
|
187
|
+
agents_app()
|
|
175
188
|
|
|
176
189
|
if __name__ == "__main__": # pragma: no cover
|
|
177
190
|
pass
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
"""Script to generate a markdown table with checkboxes for all Python and shell files in the repo."""
|
|
3
3
|
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Annotated, Literal
|
|
5
|
+
from typing import Annotated, Literal, Optional
|
|
6
6
|
from rich.console import Console
|
|
7
7
|
from rich.panel import Panel
|
|
8
8
|
import typer
|
|
9
9
|
import subprocess
|
|
10
|
+
import shutil
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def get_python_files(repo_root: Path, exclude_init: bool = False) -> list[str]:
|
|
13
14
|
"""Get all Python files relative to repo root."""
|
|
14
|
-
excluded_parts = {".venv", "__pycache__", ".git", "build", "dist"}
|
|
15
|
+
excluded_parts = {".venv", "__pycache__", ".git", "build", "dist", ".ai"}
|
|
15
16
|
excluded_patterns = {"*.egg-info"}
|
|
16
17
|
|
|
17
18
|
# Get all .py files recursively
|
|
@@ -112,6 +113,47 @@ def filter_files_by_content(repo_root: Path, files: list[str], keyword: str) ->
|
|
|
112
113
|
return filtered_files
|
|
113
114
|
|
|
114
115
|
|
|
116
|
+
def generate_csv_content(python_files: list[str], shell_files: list[str], repo_root: Path, include_line_count: bool = False) -> str:
|
|
117
|
+
"""Generate CSV content with file information."""
|
|
118
|
+
import csv
|
|
119
|
+
import io
|
|
120
|
+
|
|
121
|
+
output = io.StringIO()
|
|
122
|
+
writer = csv.writer(output)
|
|
123
|
+
|
|
124
|
+
# Write header
|
|
125
|
+
if include_line_count:
|
|
126
|
+
writer.writerow(["Type", "Index", "File Path", "Line Count", "Status"])
|
|
127
|
+
else:
|
|
128
|
+
writer.writerow(["Type", "Index", "File Path", "Status"])
|
|
129
|
+
|
|
130
|
+
# Write Python files
|
|
131
|
+
for index, file_path in enumerate(python_files, start=1):
|
|
132
|
+
clean_path = file_path.lstrip("./")
|
|
133
|
+
if include_line_count:
|
|
134
|
+
line_count = count_lines(repo_root / file_path)
|
|
135
|
+
writer.writerow(["Python", index, clean_path, line_count, "[ ]"])
|
|
136
|
+
else:
|
|
137
|
+
writer.writerow(["Python", index, clean_path, "[ ]"])
|
|
138
|
+
|
|
139
|
+
# Write shell files
|
|
140
|
+
for index, file_path in enumerate(shell_files, start=1):
|
|
141
|
+
clean_path = file_path.lstrip("./")
|
|
142
|
+
if include_line_count:
|
|
143
|
+
line_count = count_lines(repo_root / file_path)
|
|
144
|
+
writer.writerow(["Shell", index, clean_path, line_count, "[ ]"])
|
|
145
|
+
else:
|
|
146
|
+
writer.writerow(["Shell", index, clean_path, "[ ]"])
|
|
147
|
+
|
|
148
|
+
return output.getvalue()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def generate_txt_content(python_files: list[str], shell_files: list[str]) -> str:
|
|
152
|
+
"""Generate plain text content with file paths."""
|
|
153
|
+
all_files = python_files + shell_files
|
|
154
|
+
return "\n".join(file.lstrip("./") for file in all_files)
|
|
155
|
+
|
|
156
|
+
|
|
115
157
|
def generate_markdown_table(python_files: list[str], shell_files: list[str], repo_root: Path, include_line_count: bool = False) -> str:
|
|
116
158
|
"""Generate markdown table with checkboxes."""
|
|
117
159
|
header = "# File Checklist\n\n"
|
|
@@ -159,6 +201,40 @@ def generate_markdown_table(python_files: list[str], shell_files: list[str], rep
|
|
|
159
201
|
return header + content
|
|
160
202
|
|
|
161
203
|
|
|
204
|
+
def split_files_into_chunks(all_files: list[str], split_every: Optional[int] = None, split_to: Optional[int] = None) -> list[list[str]]:
|
|
205
|
+
"""Split files into chunks based on split_every or split_to."""
|
|
206
|
+
if split_every is not None:
|
|
207
|
+
# Split into chunks of split_every files each
|
|
208
|
+
return [all_files[i:i + split_every] for i in range(0, len(all_files), split_every)]
|
|
209
|
+
elif split_to is not None:
|
|
210
|
+
# Split into exactly split_to chunks
|
|
211
|
+
if split_to <= 0:
|
|
212
|
+
return [all_files]
|
|
213
|
+
chunk_size = max(1, len(all_files) // split_to)
|
|
214
|
+
chunks = []
|
|
215
|
+
for i in range(split_to):
|
|
216
|
+
start = i * chunk_size
|
|
217
|
+
end = start + chunk_size if i < split_to - 1 else len(all_files)
|
|
218
|
+
chunks.append(all_files[start:end])
|
|
219
|
+
return chunks
|
|
220
|
+
else:
|
|
221
|
+
# No splitting
|
|
222
|
+
return [all_files]
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def generate_content(python_files: list[str], shell_files: list[str], repo_root: Path,
|
|
226
|
+
format_type: str, include_line_count: bool) -> str:
|
|
227
|
+
"""Generate content based on format type."""
|
|
228
|
+
if format_type == "csv":
|
|
229
|
+
return generate_csv_content(python_files, shell_files, repo_root, include_line_count)
|
|
230
|
+
elif format_type == "md":
|
|
231
|
+
return generate_markdown_table(python_files, shell_files, repo_root, include_line_count)
|
|
232
|
+
elif format_type == "txt":
|
|
233
|
+
return generate_txt_content(python_files, shell_files)
|
|
234
|
+
else:
|
|
235
|
+
raise ValueError(f"Unsupported format: {format_type}")
|
|
236
|
+
|
|
237
|
+
|
|
162
238
|
def create_repo_symlinks(repo_root: Path) -> None:
|
|
163
239
|
"""Create 5 symlinks to repo_root at ~/code_copies/${repo_name}_copy_{i}."""
|
|
164
240
|
repo_name: str = repo_root.name
|
|
@@ -174,22 +250,30 @@ def create_repo_symlinks(repo_root: Path) -> None:
|
|
|
174
250
|
def main(
|
|
175
251
|
pattern: Annotated[str, typer.Argument(help="Pattern or keyword to match files by")],
|
|
176
252
|
repo: Annotated[str, typer.Argument(help="Repository path. Can be any directory within a git repository.")] = str(Path.cwd()),
|
|
177
|
-
strategy: Annotated[Literal["name", "keywords"], typer.Option("--strategy", help="Strategy to filter files: 'name' for filename matching, 'keywords' for content matching")] = "name",
|
|
178
|
-
exclude_init: Annotated[bool, typer.Option("--exclude-init", help="Exclude __init__.py files from the checklist")] =
|
|
179
|
-
include_line_count: Annotated[bool, typer.Option("--line-count", help="Include line count column in the
|
|
180
|
-
output_path: Annotated[str, typer.Option("--output-path", help="
|
|
253
|
+
strategy: Annotated[Literal["name", "keywords"], typer.Option("-s", "--strategy", help="Strategy to filter files: 'name' for filename matching, 'keywords' for content matching")] = "name",
|
|
254
|
+
exclude_init: Annotated[bool, typer.Option("-x", "--exclude-init", help="Exclude __init__.py files from the checklist")] = True,
|
|
255
|
+
include_line_count: Annotated[bool, typer.Option("-l", "--line-count", help="Include line count column in the output")] = False,
|
|
256
|
+
output_path: Annotated[str, typer.Option("-o", "--output-path", help="Base path for output files relative to repo root")] = ".ai/todo/files",
|
|
257
|
+
format_type: Annotated[Literal["csv", "md", "txt"], typer.Option("-f", "--format", help="Output format: csv, md (markdown), or txt")] = "md",
|
|
258
|
+
split_every: Annotated[Optional[int], typer.Option("--split-every", "-e", help="Split output into multiple files, each containing at most this many results")] = None,
|
|
259
|
+
split_to: Annotated[Optional[int], typer.Option("--split-to", "-t", help="Split output into exactly this many files")] = None,
|
|
181
260
|
) -> None:
|
|
182
|
-
"""Generate
|
|
261
|
+
"""Generate checklist with Python and shell script files in the repository filtered by pattern."""
|
|
183
262
|
repo_path = Path(repo).expanduser().absolute()
|
|
184
263
|
if not is_git_repository(repo_path):
|
|
185
264
|
console = Console()
|
|
186
265
|
console.print(Panel(f"❌ ERROR | Not a git repository or not in a git repository: {repo_path}", border_style="bold red", expand=False))
|
|
187
266
|
raise typer.Exit(code=1)
|
|
188
267
|
|
|
189
|
-
|
|
268
|
+
# Delete .ai/todo directory at the start
|
|
269
|
+
todo_dir = repo_path / ".ai" / "todo"
|
|
270
|
+
if todo_dir.exists():
|
|
271
|
+
shutil.rmtree(todo_dir)
|
|
272
|
+
|
|
273
|
+
output_base = repo_path / output_path
|
|
190
274
|
|
|
191
275
|
# Ensure output directory exists
|
|
192
|
-
|
|
276
|
+
output_base.parent.mkdir(parents=True, exist_ok=True)
|
|
193
277
|
|
|
194
278
|
# Get Python and shell files
|
|
195
279
|
python_files = get_python_files(repo_path, exclude_init=exclude_init)
|
|
@@ -206,20 +290,46 @@ def main(
|
|
|
206
290
|
print(f"Repo path: {repo_path}")
|
|
207
291
|
print(f"Strategy: {strategy}")
|
|
208
292
|
print(f"Pattern: {pattern}")
|
|
293
|
+
print(f"Format: {format_type}")
|
|
209
294
|
print(f"Found {len(python_files)} Python files")
|
|
210
295
|
print(f"Found {len(shell_files)} Shell script files")
|
|
211
296
|
|
|
212
|
-
#
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
#
|
|
216
|
-
|
|
297
|
+
# Combine all files for splitting
|
|
298
|
+
all_files = python_files + shell_files
|
|
299
|
+
|
|
300
|
+
# Split files into chunks
|
|
301
|
+
file_chunks = split_files_into_chunks(all_files, split_every, split_to)
|
|
302
|
+
|
|
303
|
+
# Determine file extension based on format
|
|
304
|
+
extension = {"csv": ".csv", "md": ".md", "txt": ".txt"}[format_type]
|
|
305
|
+
|
|
306
|
+
output_files = []
|
|
307
|
+
for i, chunk in enumerate(file_chunks):
|
|
308
|
+
# Split chunk back into python and shell files
|
|
309
|
+
chunk_python = [f for f in chunk if f in python_files]
|
|
310
|
+
chunk_shell = [f for f in chunk if f in shell_files]
|
|
311
|
+
|
|
312
|
+
# Generate content for this chunk
|
|
313
|
+
content = generate_content(chunk_python, chunk_shell, repo_path, format_type, include_line_count)
|
|
314
|
+
|
|
315
|
+
# Determine output file path
|
|
316
|
+
if len(file_chunks) == 1:
|
|
317
|
+
output_file = output_base.with_suffix(extension)
|
|
318
|
+
else:
|
|
319
|
+
output_file = output_base.parent / f"{output_base.name}_{i+1}{extension}"
|
|
320
|
+
|
|
321
|
+
# Write to file
|
|
322
|
+
output_file.write_text(content)
|
|
323
|
+
output_files.append(output_file)
|
|
217
324
|
|
|
218
325
|
console = Console()
|
|
219
|
-
|
|
220
|
-
📄
|
|
326
|
+
success_msg = f"""✅ SUCCESS | Files generated successfully!
|
|
327
|
+
📄 Output files: {', '.join(str(f.relative_to(repo_path)) for f in output_files)}
|
|
221
328
|
🐍 Python files: {len(python_files)}
|
|
222
|
-
🔧 Shell files: {len(shell_files)}
|
|
329
|
+
🔧 Shell files: {len(shell_files)}
|
|
330
|
+
📊 Total chunks: {len(file_chunks)}"""
|
|
331
|
+
|
|
332
|
+
console.print(Panel(success_msg, border_style="bold blue", expand=False))
|
|
223
333
|
|
|
224
334
|
|
|
225
335
|
def create_symlink_command(num: Annotated[int, typer.Argument(help="Number of symlinks to create (1-5).")] = 5) -> None:
|
|
@@ -150,7 +150,7 @@ from pathlib import Path
|
|
|
150
150
|
else:
|
|
151
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
152
|
return
|
|
153
|
-
else: ve_line = "--with machineconfig[plot]>=5.
|
|
153
|
+
else: ve_line = "--with machineconfig[plot]>=5.67"
|
|
154
154
|
fire_line = f"uv run --python 3.14 {ve_line} {interpreter} {interactivity} {profile} {str(pyfile)}"
|
|
155
155
|
|
|
156
156
|
from machineconfig.utils.code import run_shell_script
|
|
@@ -48,7 +48,7 @@ def path():
|
|
|
48
48
|
from pathlib import Path
|
|
49
49
|
path = Path(navigator.__file__).resolve().parent.joinpath("path_manager_tui.py")
|
|
50
50
|
from machineconfig.utils.code import run_shell_script
|
|
51
|
-
run_shell_script(f"uv run --with machineconfig>=5.
|
|
51
|
+
run_shell_script(f"uv run --with machineconfig>=5.67,textual {path}")
|
|
52
52
|
|
|
53
53
|
@config_apps.command(no_args_is_help=False)
|
|
54
54
|
def pwsh_theme():
|
|
@@ -31,9 +31,9 @@ def install():
|
|
|
31
31
|
# main_public_from_parser()
|
|
32
32
|
import platform
|
|
33
33
|
if platform.system() == "Windows":
|
|
34
|
-
run_shell_script(r"""$HOME\.local\bin\uv.exe tool install machineconfig>=5.
|
|
34
|
+
run_shell_script(r"""$HOME\.local\bin\uv.exe tool install machineconfig>=5.67""")
|
|
35
35
|
else:
|
|
36
|
-
run_shell_script("""$HOME/.local/bin/uv tool install machineconfig>=5.
|
|
36
|
+
run_shell_script("""$HOME/.local/bin/uv tool install machineconfig>=5.67""")
|
|
37
37
|
|
|
38
38
|
@cli_app.command(no_args_is_help=False)
|
|
39
39
|
def navigate():
|
|
@@ -42,7 +42,7 @@ def navigate():
|
|
|
42
42
|
from pathlib import Path
|
|
43
43
|
path = Path(navigator.__file__).resolve().parent.joinpath("devops_navigator.py")
|
|
44
44
|
from machineconfig.utils.code import run_shell_script
|
|
45
|
-
run_shell_script(f"uv run --with machineconfig>=5.
|
|
45
|
+
run_shell_script(f"uv run --with machineconfig>=5.67,textual {path}")
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
@cli_app.command(no_args_is_help=True)
|
|
@@ -105,7 +105,7 @@ def ftpx(
|
|
|
105
105
|
from paramiko.ssh_exception import AuthenticationException # type: ignore
|
|
106
106
|
|
|
107
107
|
try:
|
|
108
|
-
ssh = SSH(rf"{machine}")
|
|
108
|
+
ssh = SSH(host=rf"{machine}", username=None, hostname=None, ssh_key_path=None, password=None, port=22, enable_compression=True)
|
|
109
109
|
except AuthenticationException:
|
|
110
110
|
console.print(
|
|
111
111
|
Panel(
|
|
@@ -123,7 +123,7 @@ def ftpx(
|
|
|
123
123
|
import getpass
|
|
124
124
|
|
|
125
125
|
pwd = getpass.getpass()
|
|
126
|
-
ssh = SSH(rf"{machine}", pwd=
|
|
126
|
+
ssh = SSH(host=rf"{machine}", username=None, hostname=None, ssh_key_path=None, password=pwd, port=22, enable_compression=True)
|
|
127
127
|
|
|
128
128
|
if cloud:
|
|
129
129
|
console.print(
|
|
@@ -133,7 +133,7 @@ def ftpx(
|
|
|
133
133
|
border_style="cyan",
|
|
134
134
|
)
|
|
135
135
|
)
|
|
136
|
-
ssh.
|
|
136
|
+
ssh.run_shell(command=f"cloud_copy {resolved_source} :^", verbose_output=True, description="Uploading from remote to the cloud.", strict_stderr=False, strict_return_code=False)
|
|
137
137
|
console.print(
|
|
138
138
|
Panel.fit(
|
|
139
139
|
"⬇️ Cloud transfer mode — downloading from cloud to local...",
|
|
@@ -141,7 +141,7 @@ def ftpx(
|
|
|
141
141
|
border_style="cyan",
|
|
142
142
|
)
|
|
143
143
|
)
|
|
144
|
-
ssh.run_locally(f"cloud_copy :^ {resolved_target}")
|
|
144
|
+
ssh.run_locally(command=f"cloud_copy :^ {resolved_target}")
|
|
145
145
|
received_file = PathExtended(resolved_target) # type: ignore
|
|
146
146
|
else:
|
|
147
147
|
if source_is_remote:
|
|
@@ -163,7 +163,7 @@ def ftpx(
|
|
|
163
163
|
padding=(1, 2),
|
|
164
164
|
)
|
|
165
165
|
)
|
|
166
|
-
received_file = ssh.copy_to_here(source=resolved_source, target=resolved_target, z=zipFirst, r=recursive)
|
|
166
|
+
received_file = ssh.copy_to_here(source=resolved_source, target=resolved_target, z=zipFirst, r=recursive, init=True)
|
|
167
167
|
else:
|
|
168
168
|
assert resolved_source is not None, """
|
|
169
169
|
❌ Path Error: Target must be a remote path (machine:path)"""
|
|
@@ -183,7 +183,7 @@ def ftpx(
|
|
|
183
183
|
padding=(1, 2),
|
|
184
184
|
)
|
|
185
185
|
)
|
|
186
|
-
received_file = ssh.copy_from_here(
|
|
186
|
+
received_file = ssh.copy_from_here(source_path=resolved_source, target_path=resolved_target, compress_with_zip=zipFirst, recursive=recursive, overwrite_existing=False)
|
|
187
187
|
|
|
188
188
|
if source_is_remote and isinstance(received_file, PathExtended):
|
|
189
189
|
console.print(
|
|
@@ -130,9 +130,9 @@ def execute_installations(selected_options: list[str]) -> None:
|
|
|
130
130
|
console.print(Panel("🐍 [bold green]PYTHON ENVIRONMENT[/bold green]\n[italic]Virtual environment setup[/italic]", border_style="green"))
|
|
131
131
|
import platform
|
|
132
132
|
if platform.system() == "Windows":
|
|
133
|
-
run_shell_script(r"""$HOME\.local\bin\uv.exe tool install machineconfig>=5.
|
|
133
|
+
run_shell_script(r"""$HOME\.local\bin\uv.exe tool install machineconfig>=5.67""")
|
|
134
134
|
else:
|
|
135
|
-
run_shell_script("""$HOME/.local/bin/uv tool install machineconfig>=5.
|
|
135
|
+
run_shell_script("""$HOME/.local/bin/uv tool install machineconfig>=5.67""")
|
|
136
136
|
if "install_ssh_server" in selected_options:
|
|
137
137
|
console.print(Panel("🔒 [bold red]SSH SERVER[/bold red]\n[italic]Remote access setup[/italic]", border_style="red"))
|
|
138
138
|
import platform
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# mkdir ~/data/local
|
|
6
6
|
# sudo mount -o nolock,noatime,nodiratime,proto=tcp,timeo=600,retrans=2,noac alex-p51s-5:/home/alex/data/local ./data/local
|
|
7
7
|
|
|
8
|
-
uv run --python 3.14 --with machineconfig>=5.
|
|
8
|
+
uv run --python 3.14 --with machineconfig>=5.67python -m machineconfig.scripts.python.mount_nfs
|
|
9
9
|
# Check if remote server is reachable and share folder exists
|
|
10
10
|
if ! ping -c 1 "$remote_server" &> /dev/null; then
|
|
11
11
|
echo "💥 Error: Remote server $remote_server is not reachable."
|
|
@@ -20,8 +20,8 @@ def main():
|
|
|
20
20
|
tmp = choose_ssh_host(multi=False)
|
|
21
21
|
assert isinstance(tmp, str)
|
|
22
22
|
ssh = SSH(tmp)
|
|
23
|
-
default = f"{ssh.hostname}:{ssh.
|
|
24
|
-
share_info = choose_from_options(msg="📂 Choose a share path:", options=[f"{ssh.hostname}:{item.split(' ')[0]}" for item in ssh.
|
|
23
|
+
default = f"{ssh.hostname}:{ssh.run_shell('echo $HOME').op}/data/share_nfs"
|
|
24
|
+
share_info = choose_from_options(msg="📂 Choose a share path:", options=[f"{ssh.hostname}:{item.split(' ')[0]}" for item in ssh.run_shell("cat /etc/exports").op.split("\n") if not item.startswith("#")] + [default], default=default, multi=False)
|
|
25
25
|
assert isinstance(share_info, str), f"❌ share_info must be a string. Got {type(share_info)}"
|
|
26
26
|
|
|
27
27
|
remote_server = share_info.split(":")[0]
|
|
@@ -19,7 +19,7 @@ def main():
|
|
|
19
19
|
tmp = choose_ssh_host(multi=False)
|
|
20
20
|
assert isinstance(tmp, str)
|
|
21
21
|
ssh = SSH(host=tmp)
|
|
22
|
-
share_info = f"{ssh.username}@{ssh.hostname}:{ssh.
|
|
22
|
+
share_info = f"{ssh.username}@{ssh.hostname}:{ssh.run_shell('echo $HOME').op}/data/share_ssh"
|
|
23
23
|
else:
|
|
24
24
|
ssh = SSH(share_info.split(":")[0])
|
|
25
25
|
|
|
@@ -7,7 +7,7 @@ def analyze_repo_development(repo_path: str = typer.Argument(..., help="Path to
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
count_lines_path = Path(count_lines.__file__)
|
|
9
9
|
# --project $HOME/code/ machineconfig --group plot
|
|
10
|
-
cmd = f"""uv run --python 3.14 --with machineconfig[plot]>=5.
|
|
10
|
+
cmd = f"""uv run --python 3.14 --with machineconfig[plot]>=5.67 {count_lines_path} analyze-over-time {repo_path}"""
|
|
11
11
|
from machineconfig.utils.code import run_shell_script
|
|
12
12
|
run_shell_script(cmd)
|
|
13
13
|
|
|
@@ -141,7 +141,7 @@ def get_app():
|
|
|
141
141
|
layouts_app.command("create-from-function", no_args_is_help=True, help="Create a layout from a function")(create_from_function)
|
|
142
142
|
layouts_app.command("run", no_args_is_help=True, help="Run the selected layout(s)")(run)
|
|
143
143
|
layouts_app.command("balance-load", no_args_is_help=True, help="Balance the load across sessions")(balance_load)
|
|
144
|
-
layouts_app.command("kill-process", no_args_is_help=
|
|
144
|
+
layouts_app.command("kill-process", no_args_is_help=False, help="Choose a process to kill")(kill_process)
|
|
145
145
|
return layouts_app
|
|
146
146
|
|
|
147
147
|
|
|
@@ -7,7 +7,7 @@ $user = ''
|
|
|
7
7
|
$sharePath = ''
|
|
8
8
|
$driveLetter = ''
|
|
9
9
|
|
|
10
|
-
uv run --python 3.14 --with machineconfig>=5.
|
|
10
|
+
uv run --python 3.14 --with machineconfig>=5.67python -m machineconfig.scripts.python.mount_ssh
|
|
11
11
|
|
|
12
12
|
net use T: \\sshfs.kr\$user@$host.local
|
|
13
13
|
# this worked: net use T: \\sshfs\alex@alex-p51s-5.local
|
|
@@ -14,7 +14,6 @@ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|
|
|
14
14
|
echo "🔧 Configuring NVM environment..."
|
|
15
15
|
export NVM_DIR="$HOME/.nvm"
|
|
16
16
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
17
|
-
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
|
|
18
17
|
echo "📥 Installing latest Node.js..."
|
|
19
18
|
nvm install node || true
|
|
20
19
|
echo "📥 Installing SQLite - lightweight SQL database..."
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
. <( curl -sSL "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/uv.sh")
|
|
3
3
|
devops() {
|
|
4
|
-
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.
|
|
4
|
+
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.67 devops "$@"
|
|
5
5
|
}
|
|
6
6
|
agents() {
|
|
7
|
-
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.
|
|
7
|
+
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.67 agents "$@"
|
|
8
8
|
}
|
|
9
9
|
cloud() {
|
|
10
|
-
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.
|
|
10
|
+
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.67 cloud "$@"
|
|
11
11
|
}
|
|
12
12
|
croshell() {
|
|
13
|
-
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.
|
|
13
|
+
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.67 croshell "$@"
|
|
14
14
|
}
|
|
15
15
|
fire() {
|
|
16
|
-
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.
|
|
16
|
+
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.67fire "$@"
|
|
17
17
|
}
|
|
18
18
|
ftpx() {
|
|
19
|
-
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.
|
|
19
|
+
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.67ftpx "$@"
|
|
20
20
|
}
|
|
21
21
|
sessions() {
|
|
22
|
-
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.
|
|
22
|
+
"$HOME/.local/bin/uv" run --python 3.14 --with machineconfig>=5.67sessions "$@"
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
echo "devops command is now defined in this shell session."
|
|
@@ -2,30 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
iex (iwr "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/uv.ps1").Content
|
|
4
4
|
function devops {
|
|
5
|
-
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.
|
|
5
|
+
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.67 devops $args
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
function cloud {
|
|
9
|
-
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.
|
|
9
|
+
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.67 cloud $args
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
function croshell {
|
|
13
|
-
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.
|
|
13
|
+
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.67 croshell $args
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function agents {
|
|
17
|
-
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.
|
|
17
|
+
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.67 agents $args
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function fire {
|
|
21
|
-
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.
|
|
21
|
+
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.67 fire $args
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
function ftpx {
|
|
25
|
-
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.
|
|
25
|
+
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.67 ftpx $args
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function sessions {
|
|
29
|
-
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.
|
|
29
|
+
& "$HOME\.local\bin\uv.exe" run --python 3.14 --with machineconfig>=5.67 sessions $args
|
|
30
30
|
}
|
|
31
31
|
|