Macha is now a standalone NixOS flake that can be imported into other systems. This provides: - Independent versioning - Easier reusability - Cleaner separation of concerns - Better development workflow Includes: - Complete autonomous system code - NixOS module with full configuration options - Queue-based architecture with priority system - Chunked map-reduce for large outputs - ChromaDB knowledge base - Tool calling system - Multi-host SSH management - Gotify notification integration All capabilities from DESIGN.md are preserved.
223 lines
6.7 KiB
Python
223 lines
6.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Git Context - Extract context from NixOS configuration repository
|
|
"""
|
|
|
|
import subprocess
|
|
from typing import Dict, List, Any, Optional
|
|
from datetime import datetime, timedelta
|
|
from pathlib import Path
|
|
|
|
|
|
class GitContext:
|
|
"""Extract context from git repository"""
|
|
|
|
def __init__(self, repo_path: str = "/etc/nixos"):
|
|
"""
|
|
Initialize git context extractor
|
|
|
|
Args:
|
|
repo_path: Path to the git repository (default: /etc/nixos for NixOS systems)
|
|
"""
|
|
self.repo_path = Path(repo_path)
|
|
|
|
def _run_git(self, args: List[str]) -> tuple[bool, str]:
|
|
"""Run git command"""
|
|
try:
|
|
result = subprocess.run(
|
|
["git", "-C", str(self.repo_path)] + args,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=10
|
|
)
|
|
return (result.returncode == 0, result.stdout.strip())
|
|
except Exception as e:
|
|
return (False, str(e))
|
|
|
|
def get_current_branch(self) -> str:
|
|
"""Get current git branch"""
|
|
success, output = self._run_git(["rev-parse", "--abbrev-ref", "HEAD"])
|
|
return output if success else "unknown"
|
|
|
|
def get_remote_url(self) -> str:
|
|
"""Get git remote URL"""
|
|
success, output = self._run_git(["remote", "get-url", "origin"])
|
|
return output if success else ""
|
|
|
|
def get_recent_commits(self, count: int = 10, since: str = "1 week ago") -> List[Dict[str, str]]:
|
|
"""
|
|
Get recent commits
|
|
|
|
Args:
|
|
count: Number of commits to retrieve
|
|
since: Time range (e.g., "1 week ago", "3 days ago")
|
|
|
|
Returns:
|
|
List of commit dictionaries with hash, author, date, message
|
|
"""
|
|
success, output = self._run_git([
|
|
"log",
|
|
f"--since={since}",
|
|
f"-n{count}",
|
|
"--format=%H|%an|%ar|%s"
|
|
])
|
|
|
|
if not success:
|
|
return []
|
|
|
|
commits = []
|
|
for line in output.split('\n'):
|
|
if not line.strip():
|
|
continue
|
|
parts = line.split('|', 3)
|
|
if len(parts) == 4:
|
|
commits.append({
|
|
"hash": parts[0][:8], # Short hash
|
|
"author": parts[1],
|
|
"date": parts[2],
|
|
"message": parts[3]
|
|
})
|
|
|
|
return commits
|
|
|
|
def get_system_config_files(self, system_name: str) -> List[str]:
|
|
"""
|
|
Get configuration files for a specific system
|
|
|
|
Args:
|
|
system_name: Name of the system (e.g., "macha", "rhiannon")
|
|
|
|
Returns:
|
|
List of configuration file paths
|
|
"""
|
|
system_dir = self.repo_path / "systems" / system_name
|
|
config_files = []
|
|
|
|
if system_dir.exists():
|
|
# Main config
|
|
if (system_dir.parent / f"{system_name}.nix").exists():
|
|
config_files.append(f"systems/{system_name}.nix")
|
|
|
|
# System-specific configs
|
|
for config_file in system_dir.rglob("*.nix"):
|
|
config_files.append(str(config_file.relative_to(self.repo_path)))
|
|
|
|
return config_files
|
|
|
|
def get_recent_changes_for_system(self, system_name: str, since: str = "1 week ago") -> List[Dict[str, str]]:
|
|
"""
|
|
Get recent changes affecting a specific system
|
|
|
|
Args:
|
|
system_name: Name of the system
|
|
since: Time range
|
|
|
|
Returns:
|
|
List of commits that affected this system
|
|
"""
|
|
config_files = self.get_system_config_files(system_name)
|
|
|
|
if not config_files:
|
|
return []
|
|
|
|
# Get commits that touched these files
|
|
file_args = []
|
|
for f in config_files:
|
|
file_args.extend(["--", f])
|
|
|
|
success, output = self._run_git([
|
|
"log",
|
|
f"--since={since}",
|
|
"-n10",
|
|
"--format=%H|%an|%ar|%s"
|
|
] + file_args)
|
|
|
|
if not success:
|
|
return []
|
|
|
|
commits = []
|
|
for line in output.split('\n'):
|
|
if not line.strip():
|
|
continue
|
|
parts = line.split('|', 3)
|
|
if len(parts) == 4:
|
|
commits.append({
|
|
"hash": parts[0][:8],
|
|
"author": parts[1],
|
|
"date": parts[2],
|
|
"message": parts[3]
|
|
})
|
|
|
|
return commits
|
|
|
|
def get_system_context_summary(self, system_name: str) -> str:
|
|
"""
|
|
Get a summary of git context for a system
|
|
|
|
Args:
|
|
system_name: Name of the system
|
|
|
|
Returns:
|
|
Human-readable summary
|
|
"""
|
|
lines = []
|
|
|
|
# Repository info
|
|
repo_url = self.get_remote_url()
|
|
branch = self.get_current_branch()
|
|
|
|
if repo_url:
|
|
lines.append(f"Configuration Repository: {repo_url}")
|
|
lines.append(f"Branch: {branch}")
|
|
|
|
# Recent changes to this system
|
|
recent_changes = self.get_recent_changes_for_system(system_name, "2 weeks ago")
|
|
|
|
if recent_changes:
|
|
lines.append(f"\nRecent configuration changes (last 2 weeks):")
|
|
for commit in recent_changes[:5]:
|
|
lines.append(f" - {commit['date']}: {commit['message']} ({commit['author']})")
|
|
else:
|
|
lines.append("\nNo recent configuration changes")
|
|
|
|
return "\n".join(lines)
|
|
|
|
def get_all_managed_systems(self) -> List[str]:
|
|
"""
|
|
Get list of all systems managed by this repository
|
|
|
|
Returns:
|
|
List of system names
|
|
"""
|
|
systems = []
|
|
systems_dir = self.repo_path / "systems"
|
|
|
|
if systems_dir.exists():
|
|
for system_file in systems_dir.glob("*.nix"):
|
|
if system_file.stem not in ["default"]:
|
|
systems.append(system_file.stem)
|
|
|
|
return sorted(systems)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
git = GitContext()
|
|
|
|
print("Repository:", git.get_remote_url())
|
|
print("Branch:", git.get_current_branch())
|
|
print("\nManaged Systems:")
|
|
for system in git.get_all_managed_systems():
|
|
print(f" - {system}")
|
|
|
|
print("\nRecent Commits:")
|
|
for commit in git.get_recent_commits(5):
|
|
print(f" {commit['hash']}: {commit['message']} - {commit['author']}, {commit['date']}")
|
|
|
|
if len(sys.argv) > 1:
|
|
system = sys.argv[1]
|
|
print(f"\nContext for {system}:")
|
|
print(git.get_system_context_summary(system))
|
|
|