backup-2025-12-19-20: Automated backup - 10 files changed
📋 Files modified: 10 ⏰ Timestamp: 2025-12-19 20:27:31 UTC 🔒 Security: PASSED (no secrets detected) 💾 Automated by Git Agent
This commit is contained in:
235
tools/slash_commands.py
Normal file
235
tools/slash_commands.py
Normal file
@ -0,0 +1,235 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
OpenCode Slash Commands for Git Agent
|
||||
Provides custom slash commands for Git operations in the Uniswap Auto CLP project
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class GitSlashCommand:
|
||||
"""Base class for Git-related slash commands"""
|
||||
|
||||
def __init__(self):
|
||||
self.project_root = "K:\\Projects\\uniswap_auto_clp"
|
||||
self.git_agent_path = os.path.join(self.project_root, "tools", "git_agent.py")
|
||||
|
||||
def run_git_agent(self, args: List[str]) -> Dict[str, Any]:
|
||||
"""Execute git_agent.py with specified arguments"""
|
||||
try:
|
||||
cmd = ["python", self.git_agent_path] + args
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
cwd=self.project_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False
|
||||
)
|
||||
|
||||
return {
|
||||
"success": result.returncode == 0,
|
||||
"stdout": result.stdout.strip(),
|
||||
"stderr": result.stderr.strip(),
|
||||
"returncode": result.returncode
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"stdout": "",
|
||||
"stderr": str(e),
|
||||
"returncode": -1
|
||||
}
|
||||
|
||||
def get_backup_branches(self) -> List[str]:
|
||||
"""Get list of backup branches for restore functionality"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "branch", "-a"],
|
||||
cwd=self.project_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
branches = []
|
||||
for line in result.stdout.strip().split('\n'):
|
||||
branch = line.strip().replace('* ', '').replace('remotes/origin/', '')
|
||||
if branch.startswith('backup-'):
|
||||
branches.append(branch)
|
||||
|
||||
branches.sort(key=lambda x: x.replace('backup-', ''), reverse=True)
|
||||
return branches
|
||||
|
||||
return []
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
def format_backup_time(self, time_input: str) -> Optional[str]:
|
||||
"""Convert user time input to backup branch name format"""
|
||||
try:
|
||||
# Handle different input formats
|
||||
if len(time_input) == 10: # YYYY-MM-DD
|
||||
return f"backup-{time_input}"
|
||||
elif len(time_input) == 13: # YYYY-MM-DD-HH
|
||||
return f"backup-{time_input}"
|
||||
elif len(time_input) == 8: # MM-DD-HH
|
||||
current_year = datetime.now().year
|
||||
return f"backup-{current_year}-{time_input}"
|
||||
else:
|
||||
# Try to match partial patterns
|
||||
if '-' in time_input:
|
||||
parts = time_input.split('-')
|
||||
if len(parts) == 2 and len(parts[1]) == 2: # MM-DD
|
||||
current_year = datetime.now().year
|
||||
return f"backup-{current_year}-{parts[0]}-{parts[1]}-00"
|
||||
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
class GitBackupCommand(GitSlashCommand):
|
||||
"""Handle /git-backup command"""
|
||||
|
||||
def execute(self) -> str:
|
||||
result = self.run_git_agent(["--backup"])
|
||||
|
||||
if result["success"]:
|
||||
return "✅ **Backup completed successfully**\n\nAutomated backup created and pushed to remote repository."
|
||||
else:
|
||||
error_msg = result["stderr"] or result["stdout"] or "Unknown error"
|
||||
return f"❌ **Backup failed**\n\nError: {error_msg}"
|
||||
|
||||
class GitStatusCommand(GitSlashCommand):
|
||||
"""Handle /git-status command"""
|
||||
|
||||
def execute(self) -> str:
|
||||
result = self.run_git_agent(["--status"])
|
||||
|
||||
if result["success"]:
|
||||
return f"📊 **Git Agent Status**\n\n```\n{result['stdout']}\n```"
|
||||
else:
|
||||
error_msg = result["stderr"] or result["stdout"] or "Unknown error"
|
||||
return f"❌ **Status check failed**\n\nError: {error_msg}"
|
||||
|
||||
class GitCleanupCommand(GitSlashCommand):
|
||||
"""Handle /git-cleanup command"""
|
||||
|
||||
def execute(self) -> str:
|
||||
result = self.run_git_agent(["--cleanup"])
|
||||
|
||||
if result["success"]:
|
||||
return "✅ **Cleanup completed**\n\nOld backup branches have been removed according to retention policy."
|
||||
else:
|
||||
error_msg = result["stderr"] or result["stdout"] or "Unknown error"
|
||||
return f"❌ **Cleanup failed**\n\nError: {error_msg}"
|
||||
|
||||
class GitRestoreCommand(GitSlashCommand):
|
||||
"""Handle /git-restore command"""
|
||||
|
||||
def execute(self, time_input: str = None) -> str:
|
||||
if not time_input:
|
||||
# Show available backups
|
||||
branches = self.get_backup_branches()
|
||||
if not branches:
|
||||
return "📂 **No backup branches found**\n\nUse `/git-backup` to create a backup first."
|
||||
|
||||
response = "📂 **Available Backups**\n\nChoose a backup to restore:\n"
|
||||
for i, branch in enumerate(branches[:10]): # Show last 10
|
||||
# Extract timestamp from branch name
|
||||
timestamp = branch.replace('backup-', '')
|
||||
formatted_time = self.format_timestamp_display(timestamp)
|
||||
response += f"• `{timestamp}` - {formatted_time}\n"
|
||||
|
||||
if len(branches) > 10:
|
||||
response += f"\n... and {len(branches) - 10} more backups"
|
||||
|
||||
response += "\n\n**Usage:** `/git-restore <timestamp>` (e.g., `2025-12-19-14`)"
|
||||
return response
|
||||
|
||||
# Try to restore specific backup
|
||||
branch_name = self.format_backup_time(time_input)
|
||||
if not branch_name:
|
||||
return f"❌ **Invalid time format**\n\nExpected format: `YYYY-MM-DD-HH` (e.g., `2025-12-19-14`)"
|
||||
|
||||
# Check if branch exists
|
||||
branches = self.get_backup_branches()
|
||||
matching_branches = [b for b in branches if branch_name in b]
|
||||
|
||||
if not matching_branches:
|
||||
return f"❌ **Backup not found**\n\nNo backup found for: `{time_input}`\n\nUse `/git-restore` to see available backups."
|
||||
|
||||
# Use the most recent matching branch
|
||||
target_branch = matching_branches[0]
|
||||
|
||||
try:
|
||||
# Checkout the backup branch
|
||||
result = subprocess.run(
|
||||
["git", "checkout", target_branch],
|
||||
cwd=self.project_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
timestamp = target_branch.replace('backup-', '')
|
||||
formatted_time = self.format_timestamp_display(timestamp)
|
||||
return f"✅ **Restored to backup**\n\nBranch: `{target_branch}`\nTime: {formatted_time}\n\n⚠️ **Note:** You're now on a backup branch. Use `git checkout main` to return to the main branch when done."
|
||||
else:
|
||||
return f"❌ **Restore failed**\n\nError: {result.stderr.strip()}"
|
||||
|
||||
except Exception as e:
|
||||
return f"❌ **Restore failed**\n\nError: {str(e)}"
|
||||
|
||||
def format_timestamp_display(self, timestamp: str) -> str:
|
||||
"""Format backup timestamp for display"""
|
||||
try:
|
||||
if len(timestamp) >= 10:
|
||||
date_part = timestamp[:10]
|
||||
if len(timestamp) >= 13:
|
||||
time_part = timestamp[11:13] + ":00"
|
||||
return f"{date_part} {time_part} UTC"
|
||||
return f"{date_part}"
|
||||
return timestamp
|
||||
except Exception:
|
||||
return timestamp
|
||||
|
||||
# Command registry
|
||||
COMMAND_HANDLERS = {
|
||||
"git-backup": GitBackupCommand,
|
||||
"git-status": GitStatusCommand,
|
||||
"git-cleanup": GitCleanupCommand,
|
||||
"git-restore": GitRestoreCommand,
|
||||
}
|
||||
|
||||
def execute_command(command_name: str, args: List[str] = None) -> str:
|
||||
"""Execute a slash command and return the response"""
|
||||
if args is None:
|
||||
args = []
|
||||
|
||||
handler_class = COMMAND_HANDLERS.get(command_name)
|
||||
if not handler_class:
|
||||
return f"❌ **Unknown command:** `{command_name}`"
|
||||
|
||||
handler = handler_class()
|
||||
|
||||
if command_name == "git-restore":
|
||||
return handler.execute(args[0] if args else None)
|
||||
else:
|
||||
return handler.execute()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test functionality
|
||||
if len(sys.argv) > 1:
|
||||
command = sys.argv[1]
|
||||
command_args = sys.argv[2:] if len(sys.argv) > 2 else []
|
||||
print(execute_command(command, command_args))
|
||||
else:
|
||||
print("Available commands:")
|
||||
for cmd in COMMAND_HANDLERS.keys():
|
||||
print(f" /{cmd}")
|
||||
Reference in New Issue
Block a user