File size: 3,742 Bytes
6d1f5ee
 
 
 
 
 
5a5ae07
 
 
 
 
 
 
6d1f5ee
 
 
 
5a5ae07
 
6d1f5ee
 
 
 
 
 
 
 
 
 
5a5ae07
 
 
6d1f5ee
5a5ae07
 
 
 
 
 
 
 
 
 
 
 
6d1f5ee
5a5ae07
 
 
6d1f5ee
 
5a5ae07
 
 
 
 
 
 
 
 
 
6d1f5ee
5a5ae07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6d1f5ee
5a5ae07
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# -*- coding: utf-8 -*-
import os
import shutil
import time
import subprocess
from pathlib import Path
from typing import Optional

from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel
import httpx

app = FastAPI(title="Space 5 — Backup Daemon & Vault Server")

# Load Configs
SPACE_2_URL = os.environ.get("SPACE_2_URL", "https://augment17-claude-code-backend.hf.space")
BACKEND_API_KEY = os.environ.get("BACKEND_API_KEY", "")
GITHUB_TOKEN = "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"
BACKUP_GIT_REPO = f"https://oauth2:{GITHUB_TOKEN}@github.com/shyota1/llm-second-brain.git"
BACKUP_LOCAL_DIR = "/tmp/git_backup_repo"
MAX_PART_SIZE_MB = 50

def run_cmd(cmd, cwd=None):
    try:
        subprocess.run(cmd, shell=True, check=True, cwd=cwd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        return True
    except subprocess.CalledProcessError:
        return False

class VaultPushRequest(BaseModel):
    project_name: Optional[str] = "unknown"
    summary: Optional[str] = ""

@app.post("/api/vault/push")
async def vault_push(req: VaultPushRequest):
    """
    Exposes the push trigger called by Space 2 after successful iterations.
    Downloads the workspace snapshot and pushes to GitHub backup repository.
    """
    print(f"[Vault] Received push request for project '{req.project_name}'")
    try:
        # 1. Clean local backup directory
        if os.path.exists(BACKUP_LOCAL_DIR):
            shutil.rmtree(BACKUP_LOCAL_DIR)
        os.makedirs(BACKUP_LOCAL_DIR, exist_ok=True)

        # 2. Download zip from Space 2
        archive_path = Path("/tmp/workspace_backup.zip")
        if archive_path.exists():
            archive_path.unlink()

        download_url = f"{SPACE_2_URL}/api/backup/download"
        headers = {"Authorization": f"Bearer {BACKEND_API_KEY}"}
        
        print(f"[Vault] Downloading snapshot from {SPACE_2_URL}…")
        async with httpx.AsyncClient(timeout=60.0) as client:
            response = await client.get(download_url, headers=headers)
            if response.status_code != 200:
                raise HTTPException(status_code=500, detail=f"Download failed with status {response.status_code}")
            archive_path.write_bytes(response.content)
        print("[Vault] Download completed.")

        # 3. Copy snapshot to backup folder
        target_dest = Path(BACKUP_LOCAL_DIR) / "workspace_backup.zip"
        shutil.copy(archive_path, target_dest)
        archive_path.unlink()

        # 4. Git init and push
        run_cmd("git init", cwd=BACKUP_LOCAL_DIR)
        run_cmd("git config user.name 'Vault Backup Agent'", cwd=BACKUP_LOCAL_DIR)
        run_cmd("git config user.email 'vault@agent.internal'", cwd=BACKUP_LOCAL_DIR)
        run_cmd(f"git remote add origin {BACKUP_GIT_REPO}", cwd=BACKUP_LOCAL_DIR)
        run_cmd("git checkout -b backup", cwd=BACKUP_LOCAL_DIR)
        run_cmd("git add -A", cwd=BACKUP_LOCAL_DIR)
        run_cmd(f'git commit -m "Auto-backup {req.project_name}: {time.strftime("%Y-%m-%d %H:%M:%S")}"', cwd=BACKUP_LOCAL_DIR)
        
        success = run_cmd("git push origin backup --force", cwd=BACKUP_LOCAL_DIR)
        if success:
            print("[Vault] Backup synced to GitHub successfully.")
            return {"status": "success", "project_name": req.project_name}
        else:
            print("[Vault Error] Git push failed.")
            raise HTTPException(status_code=500, detail="Git push failed")
    except Exception as e:
        print(f"[Vault Error] Backup failed: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/health")
def health():
    return {"status": "healthy", "service": "vault-daemon"}