machineconfig 5.27__py3-none-any.whl → 5.28__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/sessions_managers/zellij_local_manager.py +1 -0
- machineconfig/jobs/installer/linux_scripts/brave.sh +4 -14
- machineconfig/jobs/installer/linux_scripts/docker.sh +5 -17
- machineconfig/jobs/installer/linux_scripts/docker_start.sh +6 -14
- machineconfig/jobs/installer/linux_scripts/edge.sh +3 -11
- machineconfig/jobs/installer/linux_scripts/nerdfont.sh +5 -17
- machineconfig/jobs/installer/linux_scripts/pgsql.sh +3 -11
- machineconfig/jobs/installer/linux_scripts/redis.sh +5 -17
- machineconfig/jobs/installer/linux_scripts/timescaledb.sh +6 -20
- machineconfig/jobs/installer/linux_scripts/vscode.sh +5 -17
- machineconfig/jobs/installer/linux_scripts/warp-cli.sh +5 -17
- machineconfig/jobs/installer/linux_scripts/wezterm.sh +3 -11
- machineconfig/jobs/linux/msc/lid.sh +2 -8
- machineconfig/jobs/linux/msc/network.sh +2 -8
- machineconfig/scripts/cloud/init.sh +6 -20
- machineconfig/scripts/linux/share_cloud.sh +11 -25
- machineconfig/scripts/python/agents.py +22 -31
- machineconfig/scripts/python/cloud_repo_sync.py +14 -29
- machineconfig/scripts/python/devops.py +7 -10
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +1 -1
- machineconfig/scripts/python/helpers_fire/fire_agents_help_launch.py +30 -48
- machineconfig/scripts/python/helpers_fire/fire_agents_helper_types.py +24 -6
- machineconfig/scripts/python/helpers_fire/fire_crush.json +14 -0
- machineconfig/scripts/python/helpers_fire/fire_crush.py +37 -0
- machineconfig/scripts/python/helpers_fire/fire_cursor_agents.py +23 -0
- machineconfig/scripts/python/helpers_fire/fire_gemini.py +41 -0
- machineconfig/scripts/python/helpers_fire/fire_q.py +19 -0
- machineconfig/scripts/python/helpers_fire/prompt.txt +2 -0
- machineconfig/scripts/python/helpers_fire/template.ps1 +0 -0
- machineconfig/scripts/python/helpers_fire/template.sh +31 -0
- machineconfig/scripts/python/interactive.py +21 -19
- machineconfig/scripts/python/repos.py +4 -1
- machineconfig/scripts/python/secure_repo.py +15 -0
- machineconfig/settings/broot/br.sh +0 -4
- machineconfig/setup_linux/__init__.py +2 -2
- machineconfig/setup_linux/apps.sh +7 -9
- machineconfig/setup_linux/apps_desktop.sh +11 -35
- machineconfig/setup_linux/apps_gui.sh +4 -14
- machineconfig/setup_linux/nix/cli_installation.sh +9 -29
- machineconfig/setup_linux/web_shortcuts/interactive.sh +1 -1
- machineconfig/setup_windows/__init__.py +2 -2
- machineconfig/utils/code.py +3 -3
- machineconfig/utils/files/read.py +1 -1
- machineconfig/utils/installer.py +15 -21
- machineconfig/utils/installer_utils/installer.py +3 -4
- machineconfig/utils/installer_utils/installer_abc.py +4 -4
- machineconfig/utils/installer_utils/installer_class.py +11 -46
- machineconfig/utils/io.py +0 -1
- {machineconfig-5.27.dist-info → machineconfig-5.28.dist-info}/METADATA +3 -3
- {machineconfig-5.27.dist-info → machineconfig-5.28.dist-info}/RECORD +57 -50
- {machineconfig-5.27.dist-info → machineconfig-5.28.dist-info}/entry_points.txt +0 -1
- machineconfig/scripts/linux/cloud_repo_sync +0 -2
- machineconfig/scripts/windows/cloud_repo_sync.ps1 +0 -1
- /machineconfig/setup_linux/{repos.sh → machineconfig.sh} +0 -0
- /machineconfig/setup_linux/{ve.sh → uv.sh} +0 -0
- /machineconfig/setup_windows/{repos.ps1 → machineconfig.ps1} +0 -0
- /machineconfig/setup_windows/{ve.ps1 → uv.ps1} +0 -0
- {machineconfig-5.27.dist-info → machineconfig-5.28.dist-info}/WHEEL +0 -0
- {machineconfig-5.27.dist-info → machineconfig-5.28.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#=======================================================================
|
|
3
2
|
# ☁️ CLOUD CONFIGURATION INITIALIZATION SCRIPT ☁️
|
|
4
|
-
#=======================================================================
|
|
5
3
|
# This script initializes cloud configuration settings and sets up the environment
|
|
6
4
|
|
|
7
|
-
echo """
|
|
8
|
-
🔑 COLLECTING CONFIGURATION PARAMETERS | Setting up cloud environment
|
|
9
|
-
#=======================================================================
|
|
5
|
+
echo """🔑 COLLECTING CONFIGURATION PARAMETERS | Setting up cloud environment
|
|
10
6
|
"""
|
|
11
7
|
|
|
12
8
|
# Check for required environment variables and prompt if not set
|
|
@@ -41,9 +37,7 @@ if [ -z "$DECRYPTION_PASSWORD" ]; then
|
|
|
41
37
|
echo ""
|
|
42
38
|
fi
|
|
43
39
|
|
|
44
|
-
echo """
|
|
45
|
-
📦 INSTALLING ESSENTIALS | Setting up core dependencies
|
|
46
|
-
#=======================================================================
|
|
40
|
+
echo """📦 INSTALLING ESSENTIALS | Setting up core dependencies
|
|
47
41
|
"""
|
|
48
42
|
|
|
49
43
|
# Set up package manager
|
|
@@ -65,9 +59,7 @@ echo "🚀 Activating Python virtual environment..."
|
|
|
65
59
|
echo "📋 Setting up code repositories..."
|
|
66
60
|
curl bit.ly/cfgreposlinux -L | bash
|
|
67
61
|
|
|
68
|
-
echo """
|
|
69
|
-
⚙️ CONFIGURING ENVIRONMENT | Setting up dotfiles
|
|
70
|
-
#=======================================================================
|
|
62
|
+
echo """⚙️ CONFIGURING ENVIRONMENT | Setting up dotfiles
|
|
71
63
|
"""
|
|
72
64
|
|
|
73
65
|
# Link configuration files
|
|
@@ -87,9 +79,7 @@ source ~/code/machineconfig/src/machineconfig/setup_linux/symlinks.sh
|
|
|
87
79
|
echo "🔄 Reloading shell configuration..."
|
|
88
80
|
. ~/.bashrc
|
|
89
81
|
|
|
90
|
-
echo """
|
|
91
|
-
📦 INSTALLING DEVELOPMENT TOOLS | Setting up development environment
|
|
92
|
-
#=======================================================================
|
|
82
|
+
echo """📦 INSTALLING DEVELOPMENT TOOLS | Setting up development environment
|
|
93
83
|
"""
|
|
94
84
|
|
|
95
85
|
# Activate virtual environment
|
|
@@ -104,16 +94,12 @@ python -m fire machineconfig.scripts.python.devops_devapps_install main --which=
|
|
|
104
94
|
echo "🔄 Reloading shell configuration..."
|
|
105
95
|
. ~/.bashrc
|
|
106
96
|
|
|
107
|
-
echo """
|
|
108
|
-
✅ FINALIZING CONFIGURATION | Running cloud-specific initialization
|
|
109
|
-
#=======================================================================
|
|
97
|
+
echo """✅ FINALIZING CONFIGURATION | Running cloud-specific initialization
|
|
110
98
|
"""
|
|
111
99
|
|
|
112
100
|
# Run cloud-specific initialization script
|
|
113
101
|
echo "⚙️ Running cloud-specific configuration: $CLOUD_CONFIG_NAME"
|
|
114
102
|
. $HOME/dotfiles/config/cloud/$CLOUD_CONFIG_NAME/init.sh
|
|
115
103
|
|
|
116
|
-
echo """
|
|
117
|
-
✅ INITIALIZATION COMPLETE | Cloud environment has been set up successfully
|
|
118
|
-
#=======================================================================
|
|
104
|
+
echo """✅ INITIALIZATION COMPLETE | Cloud environment has been set up successfully
|
|
119
105
|
"""
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#=======================================================================
|
|
3
2
|
# 📤 CLOUD FILE SHARING SCRIPT 📤
|
|
4
|
-
#=======================================================================
|
|
5
3
|
# This script uploads files or directories to transfer.sh for easy sharing
|
|
6
4
|
# Usage: share_cloud <file|directory> or command | share_cloud <file_name>
|
|
7
5
|
|
|
8
6
|
# Check if arguments are provided
|
|
9
7
|
if [ $# -eq 0 ]; then
|
|
10
|
-
echo """
|
|
11
|
-
|
|
12
|
-
#=======================================================================
|
|
13
|
-
|
|
8
|
+
echo """ ❌ ERROR | No arguments specified
|
|
9
|
+
|
|
14
10
|
📋 USAGE:
|
|
15
11
|
share_cloud <file|directory>
|
|
16
12
|
command | share_cloud <file_name>
|
|
@@ -26,19 +22,15 @@ if tty -s; then
|
|
|
26
22
|
|
|
27
23
|
# Check if the file exists
|
|
28
24
|
if [ ! -e "$file" ]; then
|
|
29
|
-
echo """
|
|
30
|
-
|
|
31
|
-
#=======================================================================
|
|
32
|
-
|
|
25
|
+
echo """ ❌ ERROR | File not found
|
|
26
|
+
|
|
33
27
|
🔍 File \"$file\" does not exist
|
|
34
28
|
""">&2
|
|
35
29
|
return 1
|
|
36
30
|
fi
|
|
37
31
|
|
|
38
|
-
echo """
|
|
39
|
-
|
|
40
|
-
#=======================================================================
|
|
41
|
-
"""
|
|
32
|
+
echo """ 📤 UPLOADING | Sharing file to transfer.sh
|
|
33
|
+
"""
|
|
42
34
|
|
|
43
35
|
# Handle directories by creating a zip archive
|
|
44
36
|
if [ -d "$file" ]; then
|
|
@@ -53,23 +45,17 @@ if tty -s; then
|
|
|
53
45
|
else
|
|
54
46
|
# Pipe mode - reading from stdin
|
|
55
47
|
file_name=$1
|
|
56
|
-
echo """
|
|
57
|
-
|
|
58
|
-
#=======================================================================
|
|
59
|
-
"""
|
|
48
|
+
echo """ 📤 UPLOADING | Sharing from stdin to transfer.sh
|
|
49
|
+
"""
|
|
60
50
|
echo "📋 Creating file \"$file_name\" from piped input..."
|
|
61
51
|
curl --progress-bar --upload-file "-" "https://transfer.sh/$file_name" | tee /dev/null
|
|
62
52
|
|
|
63
53
|
# Display QR code for the URL
|
|
64
|
-
echo """
|
|
65
|
-
|
|
66
|
-
#=======================================================================
|
|
67
|
-
"""
|
|
54
|
+
echo """ 📱 QR CODE | Scan with mobile device to access file
|
|
55
|
+
"""
|
|
68
56
|
qr "https://transfer.sh/$file_name"
|
|
69
57
|
fi
|
|
70
58
|
|
|
71
|
-
echo """
|
|
72
|
-
✅ UPLOAD COMPLETE | File is available at the URL above
|
|
73
|
-
#=======================================================================
|
|
59
|
+
echo """✅ UPLOAD COMPLETE | File is available at the URL above
|
|
74
60
|
"""
|
|
75
61
|
echo "⚠️ NOTE: Files are automatically deleted after 14 days"
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import cast, Iterable, Optional, get_args
|
|
7
7
|
import typer
|
|
8
|
-
from machineconfig.scripts.python.helpers_fire.fire_agents_helper_types import AGENTS
|
|
8
|
+
from machineconfig.scripts.python.helpers_fire.fire_agents_helper_types import AGENTS, MATCHINE, MODEL, PROVIDER
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def _write_list_file(target: Path, files: Iterable[Path]) -> None:
|
|
@@ -19,11 +19,16 @@ def create(
|
|
|
19
19
|
filename_pattern: Optional[str] = typer.Option(None, help="Filename pattern to match"),
|
|
20
20
|
separator: str = typer.Option("\n", help="Separator for context"),
|
|
21
21
|
tasks_per_prompt: int = typer.Option(13, help="Number of tasks per prompt"),
|
|
22
|
+
|
|
22
23
|
agent: AGENTS = typer.Option(..., help=f"Agent type. One of {', '.join(get_args(AGENTS))}"),
|
|
24
|
+
machine: MATCHINE = typer.Option(..., help=f"Machine to run agents on. One of {', '.join(get_args(MATCHINE))}"),
|
|
25
|
+
model: MODEL = typer.Option(..., help=f"Model to use (for crush agent). One of {', '.join(get_args(MODEL))}"),
|
|
26
|
+
provider: PROVIDER = typer.Option(..., help=f"Provider to use (for crush agent). One of {', '.join(get_args(PROVIDER))}"),
|
|
27
|
+
|
|
23
28
|
prompt: Optional[str] = typer.Option(None, help="Prompt prefix as string"),
|
|
24
29
|
prompt_path: Optional[Path] = typer.Option(None, help="Path to prompt file"),
|
|
25
30
|
job_name: str = typer.Option("AI_Agents", help="Job name"),
|
|
26
|
-
|
|
31
|
+
separate_prompt_from_context: bool = typer.Option(True, help="Keep prompt material in separate file to the context."),
|
|
27
32
|
output_path: Optional[Path] = typer.Option(None, help="Path to write the layout.json file"),
|
|
28
33
|
agents_dir: Optional[Path] = typer.Option(None, help="Directory to store agent files. If not provided, will be constructed automatically."),
|
|
29
34
|
):
|
|
@@ -84,14 +89,17 @@ def create(
|
|
|
84
89
|
else:
|
|
85
90
|
prompt_prefix = cast(str, prompt)
|
|
86
91
|
agent_selected = agent
|
|
87
|
-
keep_material_in_separate_file_input =
|
|
92
|
+
keep_material_in_separate_file_input = separate_prompt_from_context
|
|
88
93
|
prompt_material_re_splitted = chunk_prompts(prompt_material_path, tasks_per_prompt=tasks_per_prompt, joiner=separator)
|
|
89
94
|
if agents_dir is None: agents_dir = repo_root / ".ai" / f"tmp_prompts/{job_name}_{randstr()}"
|
|
90
95
|
else:
|
|
91
96
|
import shutil
|
|
92
97
|
if agents_dir.exists():
|
|
93
98
|
shutil.rmtree(agents_dir)
|
|
94
|
-
prep_agent_launch(agents_dir=agents_dir, prompts_material=prompt_material_re_splitted,
|
|
99
|
+
prep_agent_launch(repo_root=repo_root, agents_dir=agents_dir, prompts_material=prompt_material_re_splitted,
|
|
100
|
+
keep_material_in_separate_file=keep_material_in_separate_file_input,
|
|
101
|
+
prompt_prefix=prompt_prefix, machine=machine, agent=agent_selected, model=model, provider=provider,
|
|
102
|
+
job_name=job_name)
|
|
95
103
|
layoutfile = get_agents_launch_layout(session_root=agents_dir)
|
|
96
104
|
regenerate_py_code = f"""
|
|
97
105
|
#!/usr/bin/env uv run --python 3.13 --with machineconfig
|
|
@@ -100,10 +108,11 @@ fire_agents create --context-path "{prompt_material_path}" \\
|
|
|
100
108
|
--{search_strategy} "{context_path or keyword_search or filename_pattern}" \\
|
|
101
109
|
--prompt-path "{prompt_path or ''}" \\
|
|
102
110
|
--agent "{agent_selected}" \\
|
|
111
|
+
--machine "{machine}" \\
|
|
103
112
|
--job-name "{job_name}" \\
|
|
104
113
|
--tasks-per-prompt {tasks_per_prompt} \\
|
|
105
114
|
--separator "{separator}" \\
|
|
106
|
-
{"--
|
|
115
|
+
{"--separate-prompt-from-context" if keep_material_in_separate_file_input else ""}
|
|
107
116
|
"""
|
|
108
117
|
(agents_dir / "aa_agents_relaunch.py").write_text(data=regenerate_py_code, encoding="utf-8")
|
|
109
118
|
layout_output_path = output_path if output_path is not None else agents_dir / "layout.json"
|
|
@@ -155,30 +164,12 @@ def collect(
|
|
|
155
164
|
|
|
156
165
|
|
|
157
166
|
def template():
|
|
158
|
-
template_bash = """#!/bin/bash
|
|
159
|
-
JOB_NAME="outpatient_mapping"
|
|
160
|
-
REPO_ROOT="$HOME/code/work/winter_planning/"
|
|
161
|
-
CONTEXT_PATH="$REPO_ROOT/data/outpatient_mapping/op_services_collected.csv"
|
|
162
|
-
PROMPT_PATH="$REPO_ROOT/data/outpatient_mapping/prompt"
|
|
163
|
-
|
|
164
|
-
AGENTS_DIR="$REPO_ROOT/.ai/agents/$JOB_NAME"
|
|
165
|
-
LAYOUT_PATH="$REPO_ROOT/.ai/agents/$JOB_NAME/layout_unbalanced.json"
|
|
166
|
-
LAYOUT_BALANCED_PATH="$REPO_ROOT/.ai/agents/$JOB_NAME/layout_balanced.json"
|
|
167
|
-
|
|
168
|
-
agents create --context-path $CONTEXT_PATH --tasks-per-prompt 10 --agent crush --prompt-path $PROMPT_PATH --keep-separate --output-path $LAYOUT_PATH --agents-dir $AGENTS_DIR
|
|
169
|
-
sessions balance-load $LAYOUT_PATH --max-thresh 6 --breaking-method moreLayouts --thresh-type number --output-path $LAYOUT_BALANCED_PATH
|
|
170
|
-
|
|
171
|
-
sessions run $LAYOUT_BALANCED_PATH --kill-upon-completion
|
|
172
|
-
agents collect $AGENTS_DIR "$REPO_ROOT/.ai/agents/$JOB_NAME/collected.txt"
|
|
173
|
-
"""
|
|
174
|
-
template_powershell = """
|
|
175
|
-
|
|
176
|
-
"""
|
|
177
167
|
from platform import system
|
|
178
|
-
|
|
179
|
-
|
|
168
|
+
import machineconfig.scripts.python.helpers_fire as module
|
|
169
|
+
if system() == "Linux" or system() == "Darwin":
|
|
170
|
+
template_path = Path(module.__file__).parent / "template.sh"
|
|
180
171
|
elif system() == "Windows":
|
|
181
|
-
|
|
172
|
+
template_path = Path(module.__file__).parent / "template.ps1"
|
|
182
173
|
else:
|
|
183
174
|
raise typer.BadParameter(f"Unsupported OS: {system()}")
|
|
184
175
|
|
|
@@ -189,16 +180,16 @@ agents collect $AGENTS_DIR "$REPO_ROOT/.ai/agents/$JOB_NAME/collected.txt"
|
|
|
189
180
|
raise typer.Exit(1)
|
|
190
181
|
save_path = repo_root / ".ai" / "agents" / "template_fire_agents.sh"
|
|
191
182
|
save_path.parent.mkdir(parents=True, exist_ok=True)
|
|
192
|
-
save_path.write_text(
|
|
183
|
+
save_path.write_text(template_path.read_text(encoding="utf-8"), encoding="utf-8")
|
|
193
184
|
typer.echo(f"Template bash script written to {save_path}")
|
|
194
185
|
|
|
195
186
|
|
|
196
187
|
def main_from_parser():
|
|
197
188
|
import sys
|
|
198
189
|
agents_app = typer.Typer(help="🤖 AI Agents management subcommands")
|
|
199
|
-
agents_app.command("create")(create)
|
|
200
|
-
agents_app.command("collect")(collect)
|
|
201
|
-
agents_app.command("template")(template)
|
|
190
|
+
agents_app.command("create", no_args_is_help=True)(create)
|
|
191
|
+
agents_app.command("collect", no_args_is_help=True)(collect)
|
|
192
|
+
agents_app.command("create-template", no_args_is_help=False, help="Create a template for fire agents")(template)
|
|
202
193
|
if len(sys.argv) == 1:
|
|
203
194
|
agents_app(["--help"])
|
|
204
195
|
else:
|
|
@@ -3,31 +3,31 @@ from rich.console import Console
|
|
|
3
3
|
from rich.panel import Panel
|
|
4
4
|
import typer
|
|
5
5
|
|
|
6
|
-
from machineconfig.utils.io import read_ini
|
|
7
6
|
from machineconfig.utils.path_extended import PathExtended
|
|
8
7
|
from machineconfig.utils.terminal import Response
|
|
9
8
|
from machineconfig.utils.source_of_truth import CONFIG_PATH, DEFAULTS_PATH
|
|
10
|
-
from machineconfig.utils.options import choose_from_options
|
|
11
9
|
from machineconfig.utils.code import get_shell_file_executing_python_script, write_shell_script_to_file
|
|
12
10
|
|
|
13
11
|
import platform
|
|
14
12
|
import subprocess
|
|
15
13
|
from typing import Optional, Literal
|
|
16
14
|
from pathlib import Path
|
|
17
|
-
|
|
15
|
+
|
|
18
16
|
|
|
19
17
|
console = Console()
|
|
20
18
|
|
|
21
19
|
|
|
22
20
|
def main(
|
|
23
21
|
cloud: Optional[str] = typer.Option(None, "--cloud", "-c", help="Cloud storage profile name. If not provided, uses default from config."),
|
|
24
|
-
|
|
22
|
+
repo: Optional[str] = typer.Option(None, "--repo", "-r", help="Path to the local repository. Defaults to current working directory."),
|
|
25
23
|
message: Optional[str] = typer.Option(None, "--message", "-m", help="Commit message for local changes."),
|
|
26
24
|
on_conflict: Literal["ask", "pushLocalMerge", "overwriteLocal", "InspectRepos", "RemoveLocalRclone"] = typer.Option("ask", "--on-conflict", "-oc", help="Action to take on merge conflict. Default is 'ask'."),
|
|
27
25
|
pwd: Optional[str] = typer.Option(None, "--password", help="Password for encryption/decryption of the remote repository."),
|
|
28
26
|
):
|
|
29
27
|
if cloud is None:
|
|
30
28
|
try:
|
|
29
|
+
from machineconfig.utils.io import read_ini
|
|
30
|
+
|
|
31
31
|
cloud_resolved = read_ini(DEFAULTS_PATH)["general"]["rclone_config_name"]
|
|
32
32
|
console.print(Panel(f"⚠️ Using default cloud: `{cloud_resolved}` from {DEFAULTS_PATH}", title="Default Cloud", border_style="yellow"))
|
|
33
33
|
except FileNotFoundError:
|
|
@@ -35,7 +35,7 @@ def main(
|
|
|
35
35
|
return ""
|
|
36
36
|
else:
|
|
37
37
|
cloud_resolved = cloud
|
|
38
|
-
repo_local_root = PathExtended.cwd() if
|
|
38
|
+
repo_local_root = PathExtended.cwd() if repo is None else PathExtended(repo).expanduser().absolute()
|
|
39
39
|
repo_local_obj = git.Repo(repo_local_root, search_parent_directories=True)
|
|
40
40
|
repo_local_root = PathExtended(repo_local_obj.working_dir) # cwd might have been in a sub directory of repo_root, so its better to redefine it.
|
|
41
41
|
PathExtended(CONFIG_PATH).joinpath("remote").mkdir(parents=True, exist_ok=True)
|
|
@@ -139,15 +139,17 @@ git commit -am "finished merging"
|
|
|
139
139
|
|
|
140
140
|
console.print(Panel("🔄 RESOLVE MERGE CONFLICT\nChoose an option to resolve the conflict:", title_align="left", border_style="blue"))
|
|
141
141
|
|
|
142
|
-
print(f"•
|
|
143
|
-
print(f"•
|
|
144
|
-
print(f"•
|
|
145
|
-
print(f"•
|
|
142
|
+
print(f"• {option1:75} 👉 {shell_file_1}")
|
|
143
|
+
print(f"• {option2:75} 👉 {shell_file_2}")
|
|
144
|
+
print(f"• {option3:75} 👉 {shell_file_3}")
|
|
145
|
+
print(f"• {option4:75} 👉 {shell_file_4}")
|
|
146
|
+
print("\n\n")
|
|
146
147
|
|
|
147
148
|
program_content = None
|
|
148
149
|
match on_conflict:
|
|
149
150
|
case "ask":
|
|
150
|
-
|
|
151
|
+
import questionary
|
|
152
|
+
choice = questionary.select("Choose one option:", choices=[option1, option2, option3, option4]).ask()
|
|
151
153
|
if choice == option1:
|
|
152
154
|
program_content = shell_file_1.read_text(encoding="utf-8")
|
|
153
155
|
elif choice == option2:
|
|
@@ -168,24 +170,7 @@ git commit -am "finished merging"
|
|
|
168
170
|
program_content = program_4
|
|
169
171
|
case _:
|
|
170
172
|
raise ValueError(f"Unknown action: {on_conflict}")
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
from machineconfig.utils.code import run_shell_script
|
|
174
|
+
run_shell_script(script=program_content)
|
|
174
175
|
return program_content
|
|
175
176
|
|
|
176
|
-
|
|
177
|
-
def args_parser():
|
|
178
|
-
# Check if no arguments provided (excluding the script name)
|
|
179
|
-
if len(sys.argv) == 1:
|
|
180
|
-
app = typer.Typer(add_completion=False, help="Sync a local git repository with a remote encrypted cloud copy.")
|
|
181
|
-
app.command()(main)
|
|
182
|
-
app(["--help"])
|
|
183
|
-
return
|
|
184
|
-
|
|
185
|
-
app = typer.Typer(add_completion=False, no_args_is_help=True, help="Sync a local git repository with a remote encrypted cloud copy.")
|
|
186
|
-
app.command()(main)
|
|
187
|
-
app()
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if __name__ == "__main__":
|
|
191
|
-
args_parser()
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
"""devops with emojis"""
|
|
2
2
|
|
|
3
3
|
import typer
|
|
4
|
-
from typing import Literal, Annotated, Optional
|
|
4
|
+
from typing import Literal, Annotated, Optional
|
|
5
5
|
|
|
6
|
-
import machineconfig.scripts.python.share_terminal as share_terminal
|
|
7
6
|
import machineconfig.scripts.python.repos as repos
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
import machineconfig.scripts.python.share_terminal as share_terminal
|
|
10
8
|
|
|
11
9
|
app = typer.Typer(help="🛠️ DevOps operations", no_args_is_help=True)
|
|
12
10
|
@app.command(no_args_is_help=True)
|
|
13
11
|
def install( which: Optional[str] = typer.Option(None, "--which", "-w", help="Comma-separated list of program names to install."),
|
|
14
|
-
group: Optional[
|
|
12
|
+
group: Optional[str] = typer.Option(None, "--group", "-g", help="Groups names. A group is bundle of apps. See available groups when running interactively."),
|
|
15
13
|
interactive: bool = typer.Option(False, "--interactive", "-ia", help="Interactive selection of programs to install."),
|
|
16
14
|
) -> None:
|
|
17
15
|
"""📦 Install essential packages"""
|
|
@@ -30,7 +28,6 @@ app.add_typer(nw_apps, name="network")
|
|
|
30
28
|
self_app = typer.Typer(help="🔄 SELF operations subcommands", no_args_is_help=True)
|
|
31
29
|
app.add_typer(self_app, name="self")
|
|
32
30
|
|
|
33
|
-
|
|
34
31
|
@self_app.command()
|
|
35
32
|
def update():
|
|
36
33
|
"""🔄 UPDATE essential repos"""
|
|
@@ -53,12 +50,12 @@ def clone():
|
|
|
53
50
|
from machineconfig.utils.code import run_shell_script
|
|
54
51
|
from machineconfig.profile.shell import create_default_shell_profile
|
|
55
52
|
if platform.system() == "Windows":
|
|
56
|
-
from machineconfig.setup_windows import
|
|
53
|
+
from machineconfig.setup_windows import MACHINECONFIG
|
|
57
54
|
create_default_shell_profile(method="copy")
|
|
58
55
|
else:
|
|
59
|
-
from machineconfig.setup_linux import
|
|
56
|
+
from machineconfig.setup_linux import MACHINECONFIG
|
|
60
57
|
create_default_shell_profile(method="reference")
|
|
61
|
-
run_shell_script(
|
|
58
|
+
run_shell_script(MACHINECONFIG.read_text(encoding="utf-8"))
|
|
62
59
|
|
|
63
60
|
|
|
64
61
|
|
|
@@ -125,7 +122,7 @@ def setup():
|
|
|
125
122
|
else:
|
|
126
123
|
raise NotImplementedError(f"Platform {platform.system()} is not supported.")
|
|
127
124
|
from machineconfig.utils.code import run_shell_script
|
|
128
|
-
run_shell_script(
|
|
125
|
+
run_shell_script(script=program)
|
|
129
126
|
|
|
130
127
|
|
|
131
128
|
@app_data.command()
|
|
@@ -82,5 +82,5 @@ def check_dotfiles_version_is_beyond(commit_dtm: str, update: bool) -> bool:
|
|
|
82
82
|
console.print(Panel(f"🔄 UPDATE REQUIRED | Updating dotfiles because {dtm} < {datetime.fromisoformat(commit_dtm)}", border_style="bold blue", expand=False))
|
|
83
83
|
from machineconfig.scripts.python.cloud_repo_sync import main
|
|
84
84
|
|
|
85
|
-
main(cloud=None,
|
|
85
|
+
main(cloud=None, repo=dotfiles_path)
|
|
86
86
|
return res
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
import random
|
|
3
3
|
import shlex
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from machineconfig.scripts.python.helpers_fire.fire_agents_helper_types import AGENTS, AGENT_NAME_FORMATTER
|
|
5
|
+
from machineconfig.scripts.python.helpers_fire.fire_agents_helper_types import AGENTS, AGENT_NAME_FORMATTER, MATCHINE, PROVIDER, MODEL
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def
|
|
8
|
+
def get_api_keys(provider: PROVIDER) -> list[str]:
|
|
9
9
|
from machineconfig.utils.io import read_ini
|
|
10
|
-
|
|
11
|
-
config = read_ini(Path.home().joinpath("dotfiles/creds/llm/gemini/api_keys.ini"))
|
|
10
|
+
config = read_ini(Path.home().joinpath(f"dotfiles/creds/llm/{provider}/api_keys.ini"))
|
|
12
11
|
res: list[str] = []
|
|
13
12
|
for a_section_name in list(config.sections()):
|
|
14
13
|
a_section = config[a_section_name]
|
|
@@ -16,11 +15,12 @@ def get_gemini_api_keys() -> list[str]:
|
|
|
16
15
|
api_key = a_section["api_key"].strip()
|
|
17
16
|
if api_key:
|
|
18
17
|
res.append(api_key)
|
|
19
|
-
print(f"Found {len(res)}
|
|
18
|
+
print(f"Found {len(res)} {provider} API keys configured.")
|
|
20
19
|
return res
|
|
21
20
|
|
|
22
21
|
|
|
23
|
-
def prep_agent_launch(agents_dir: Path, prompts_material: list[str], prompt_prefix: str, keep_material_in_separate_file: bool,
|
|
22
|
+
def prep_agent_launch(repo_root: Path, agents_dir: Path, prompts_material: list[str], prompt_prefix: str, keep_material_in_separate_file: bool,
|
|
23
|
+
machine: MATCHINE, model: MODEL, provider: PROVIDER, agent: AGENTS, *, job_name: str) -> None:
|
|
24
24
|
agents_dir.mkdir(parents=True, exist_ok=True)
|
|
25
25
|
prompt_folder = agents_dir / "prompts"
|
|
26
26
|
prompt_folder.mkdir(parents=True, exist_ok=True)
|
|
@@ -32,21 +32,22 @@ def prep_agent_launch(agents_dir: Path, prompts_material: list[str], prompt_pref
|
|
|
32
32
|
if keep_material_in_separate_file:
|
|
33
33
|
prompt_material_path = prompt_root / f"agent_{idx}_material.txt"
|
|
34
34
|
prompt_material_path.write_text(a_prompt_material, encoding="utf-8")
|
|
35
|
-
prompt_path.write_text(prompt_prefix + f"""\nPlease only look @ {prompt_material_path}. You don't need to do any other work beside the content of this material file.""", encoding="utf-8")
|
|
35
|
+
prompt_path.write_text(prompt_prefix + f"""\nPlease only look @ {prompt_material_path.relative_to(repo_root)}. You don't need to do any other work beside the content of this material file.""", encoding="utf-8")
|
|
36
36
|
else:
|
|
37
37
|
prompt_material_path = prompt_path
|
|
38
38
|
prompt_path.write_text(prompt_prefix + """\nPlease only look @ the following:\n""" + a_prompt_material, encoding="utf-8")
|
|
39
39
|
|
|
40
40
|
agent_cmd_launch_path = prompt_root / AGENT_NAME_FORMATTER.format(idx=idx) # e.g., agent_0_cmd.sh
|
|
41
41
|
random_sleep_time = random.uniform(0, 5)
|
|
42
|
-
cmd_prefix = f"""
|
|
43
|
-
#!/usr/bin/env bash
|
|
44
|
-
|
|
45
|
-
sleep 5
|
|
46
|
-
timeout 3 copilot --banner
|
|
42
|
+
cmd_prefix = f"""#!/usr/bin/env bash
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
echo "Using machine: {machine}, model: {model}, provider: {provider}, and agent: {agent}"
|
|
45
|
+
echo "{job_name}-{idx} CMD {agent_cmd_launch_path}"
|
|
46
|
+
echo "{job_name}-{idx} PROMPT {prompt_path}"
|
|
47
|
+
echo "{job_name}-{idx} CONTEXT {prompt_material_path}"
|
|
48
|
+
echo "Starting agent {agent} in 5 seconds... Press Ctrl+C to cancel."
|
|
49
|
+
# sleep 5
|
|
50
|
+
# timeout 3 copilot --banner
|
|
50
51
|
|
|
51
52
|
export FIRE_AGENTS_AGENT_NAME="{agent}"
|
|
52
53
|
export FIRE_AGENTS_JOB_NAME="{job_name}"
|
|
@@ -56,56 +57,37 @@ export FIRE_AGENTS_AGENT_LAUNCHER="{agent_cmd_launch_path}"
|
|
|
56
57
|
|
|
57
58
|
echo "Sleeping for {random_sleep_time:.2f} seconds to stagger agent startups..."
|
|
58
59
|
sleep {random_sleep_time:.2f}
|
|
59
|
-
echo "Launching agent {agent} with prompt from {prompt_path}"
|
|
60
|
-
echo "Launching agent {agent} with command from {agent_cmd_launch_path}"
|
|
61
60
|
echo "--------START OF AGENT OUTPUT--------"
|
|
62
61
|
sleep 0.1
|
|
63
62
|
|
|
64
63
|
"""
|
|
65
64
|
match agent:
|
|
66
65
|
case "gemini":
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
# else:
|
|
73
|
-
model_arg = f"--model {shlex.quote(model)}"
|
|
74
|
-
# Need a real shell for the pipeline; otherwise '| gemini ...' is passed as args to 'cat'
|
|
75
|
-
safe_path = shlex.quote(str(prompt_path))
|
|
76
|
-
api_keys = get_gemini_api_keys()
|
|
77
|
-
api_key = api_keys[idx % len(api_keys)] if api_keys else ""
|
|
78
|
-
# Export the environment variable so it's available to subshells
|
|
79
|
-
cmd = f"""
|
|
80
|
-
|
|
81
|
-
export GEMINI_API_KEY={shlex.quote(api_key)}
|
|
82
|
-
echo "Using Gemini API key $GEMINI_API_KEY"
|
|
83
|
-
|
|
84
|
-
gemini {model_arg} --yolo --prompt {safe_path}
|
|
85
|
-
"""
|
|
66
|
+
assert provider == "google", "Gemini agent only works with google provider."
|
|
67
|
+
api_keys = get_api_keys(provider="google")
|
|
68
|
+
api_key = api_keys[idx % len(api_keys)] if len(api_keys) > 0 else None
|
|
69
|
+
from machineconfig.scripts.python.helpers_fire.fire_gemini import fire_gemini
|
|
70
|
+
cmd = fire_gemini(api_key=api_key, prompt_path=prompt_path, machine=machine)
|
|
86
71
|
case "cursor-agent":
|
|
87
|
-
|
|
88
|
-
cmd =
|
|
89
|
-
|
|
90
|
-
cursor-agent --print --output-format text {prompt_path}
|
|
91
|
-
|
|
92
|
-
"""
|
|
72
|
+
from machineconfig.scripts.python.helpers_fire.fire_cursor_agents import fire_cursor
|
|
73
|
+
cmd = fire_cursor(prompt_path=prompt_path, machine=machine, api_key=None)
|
|
74
|
+
raise NotImplementedError("Cursor agent is not implemented yet, api key missing")
|
|
93
75
|
case "crush":
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
76
|
+
from machineconfig.scripts.python.helpers_fire.fire_crush import fire_crush
|
|
77
|
+
api_keys = get_api_keys(provider=provider)
|
|
78
|
+
api_key = api_keys[idx % len(api_keys)] if len(api_keys) > 0 else None
|
|
79
|
+
cmd = fire_crush(api_key=api_key, prompt_path=prompt_path, machine=machine, repo_root=repo_root, model=model, provider=provider)
|
|
97
80
|
case "q":
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
"""
|
|
81
|
+
from machineconfig.scripts.python.helpers_fire.fire_q import fire_q
|
|
82
|
+
cmd = fire_q(api_key="", prompt_path=prompt_path, machine=machine)
|
|
101
83
|
case _:
|
|
102
84
|
raise ValueError(f"Unsupported agent type: {agent}")
|
|
85
|
+
|
|
103
86
|
cmd_postfix = """
|
|
104
87
|
sleep 0.1
|
|
105
88
|
echo "---------END OF AGENT OUTPUT---------"
|
|
106
89
|
"""
|
|
107
90
|
agent_cmd_launch_path.write_text(cmd_prefix + cmd + cmd_postfix, encoding="utf-8")
|
|
108
|
-
|
|
109
91
|
return None
|
|
110
92
|
|
|
111
93
|
|
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
|
|
2
|
-
from typing import Literal, TypeAlias
|
|
2
|
+
from typing import Literal, TypeAlias, TypedDict
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
AGENTS: TypeAlias = Literal[
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
AGENTS: TypeAlias = Literal["cursor-agent", "gemini", "crush", "q", "opencode"]
|
|
6
|
+
MATCHINE: TypeAlias = Literal["local", "docker"]
|
|
7
|
+
PROVIDER: TypeAlias = Literal["azure", "google", "aws", "openai", "anthropic", "openrouter", "xai"]
|
|
8
|
+
MODEL: TypeAlias = Literal["zai/glm-4.6", "anthropic/sonnet-4.5", "google/gemini-2.5-pro", "openai/gpt-5-codex",
|
|
9
|
+
"openrouter/supernova", "x-ai/grok-4-fast:free",
|
|
10
|
+
]
|
|
11
|
+
PROVIDER2MODEL: dict[PROVIDER, list[MODEL]] = {
|
|
12
|
+
"azure": ["zai/glm-4.6"],
|
|
13
|
+
"google": ["google/gemini-2.5-pro"],
|
|
14
|
+
"aws": [],
|
|
15
|
+
"openai": ["openai/gpt-5-codex"],
|
|
16
|
+
"anthropic": ["anthropic/sonnet-4.5"],
|
|
17
|
+
"openrouter": ["openrouter/supernova"],
|
|
18
|
+
"xai": ["x-ai/grok-4-fast:free"]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class AI_SPEC(TypedDict):
|
|
22
|
+
provider: PROVIDER
|
|
23
|
+
model: MODEL
|
|
24
|
+
agent: AGENTS
|
|
25
|
+
machine: MATCHINE
|
|
10
26
|
|
|
27
|
+
|
|
28
|
+
AGENT_NAME_FORMATTER = "agent_{idx}_cmd.sh" # e.g., agent_0_cmd.sh
|
|
11
29
|
SEARCH_STRATEGIES: TypeAlias = Literal["file_path", "keyword_search", "filename_pattern"]
|
|
12
30
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
# import shlex
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from machineconfig.scripts.python.helpers_fire.fire_agents_helper_types import MATCHINE, PROVIDER, MODEL
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def fire_crush(api_key: Optional[str], model: MODEL, provider: PROVIDER, machine: MATCHINE, prompt_path: Path, repo_root: Path) -> str:
|
|
9
|
+
match machine:
|
|
10
|
+
case "local":
|
|
11
|
+
cmd = f"""
|
|
12
|
+
crush run {prompt_path}
|
|
13
|
+
"""
|
|
14
|
+
case "docker":
|
|
15
|
+
assert api_key is not None, "API key is required for Crush agent in docker mode."
|
|
16
|
+
json_path = Path(__file__).parent / "fire_crush.json"
|
|
17
|
+
json_template = json_path.read_text(encoding="utf-8")
|
|
18
|
+
json_filled = json_template.replace("{api_key}", api_key).replace("{model}", model).replace("{provider}", provider)
|
|
19
|
+
import tempfile
|
|
20
|
+
temp_config_file_local = tempfile.mkstemp(suffix=".json")[1]
|
|
21
|
+
Path(temp_config_file_local).write_text(json_filled, encoding="utf-8")
|
|
22
|
+
cmd = f"""
|
|
23
|
+
|
|
24
|
+
# -e "PATH_PROMPT=$PATH_PROMPT"
|
|
25
|
+
# opencode --model "{provider}/{model}" run {prompt_path}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
echo "Running prompt @ {prompt_path.relative_to(repo_root)} using Docker with Crush..."
|
|
29
|
+
docker run -it --rm \
|
|
30
|
+
-v "{repo_root}:/workspace/{repo_root.name}" \
|
|
31
|
+
-v "{temp_config_file_local}:/root/.local/share/crush/crush.json" \
|
|
32
|
+
-w "/workspace/{repo_root.name}" \
|
|
33
|
+
statistician/machineconfig:latest \
|
|
34
|
+
bash -i -c "source ~/.bashrc && cd /workspace/{repo_root.name} && cat /root/.local/share/crush/crush.json && crush run 'Please act on contents of this prompt ./{prompt_path.relative_to(repo_root)}'"
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
return cmd
|