git_sync: full case-dir backup to Gitea (sweep + explicit commits)
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m25s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m25s
The case repo is the user's backup, so anything in the dir must end up
on Gitea. Two layers:
1. Periodic sweep (every 30s) — git_sync.sweep_loop runs as a FastAPI
background task. It scans every case dir, runs git status --porcelain
on each, and commit_and_push's any dirty changes with an auto-built
Hebrew message ("אוטו: טיוטות (2) · מסמכים"). Catches files written
outside the API path: agent research artefacts, manual edits, etc.
2. Explicit commits at known write paths — DOCX export, interim draft,
apply_user_edit, revise_draft, mark-final, analysis DOCX export.
These give immediate feedback with descriptive messages instead of
waiting up to 30s for the sweep.
safe.directory injection added to _git_env so sweep + explicit commits
work even when the running uid differs from the case-dir owner (host
runs vs. uniform-root container).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
23
web/app.py
23
web/app.py
@@ -28,7 +28,7 @@ from pydantic import BaseModel
|
||||
import asyncpg
|
||||
|
||||
from legal_mcp import config
|
||||
from legal_mcp.services import chunker, db, embeddings, extractor, processor, proofreader, research_md
|
||||
from legal_mcp.services import chunker, db, embeddings, extractor, git_sync, processor, proofreader, research_md
|
||||
from legal_mcp.tools import cases as cases_tools, search as search_tools, workflow as workflow_tools, drafting as drafting_tools, precedents as precedents_tools
|
||||
|
||||
# Import integration clients (same directory)
|
||||
@@ -69,9 +69,17 @@ _progress = ProgressStore(config.REDIS_URL, ttl_seconds=PROGRESS_TTL_SECONDS)
|
||||
async def lifespan(app: FastAPI):
|
||||
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
|
||||
await db.init_schema()
|
||||
yield
|
||||
await db.close_pool()
|
||||
await _progress.close()
|
||||
sync_task = asyncio.create_task(git_sync.sweep_loop())
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
sync_task.cancel()
|
||||
try:
|
||||
await sync_task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
await db.close_pool()
|
||||
await _progress.close()
|
||||
|
||||
|
||||
app = FastAPI(title="העלאת מסמכים משפטיים", lifespan=lifespan)
|
||||
@@ -1832,6 +1840,9 @@ async def api_research_analysis_export_docx(case_number: str):
|
||||
except Exception as e:
|
||||
logger.exception("Failed to export analysis DOCX for %s", case_number)
|
||||
raise HTTPException(500, f"שגיאה בייצוא: {e}")
|
||||
case_dir = config.find_case_dir(case_number)
|
||||
if case_dir.exists():
|
||||
commit_and_push(case_dir, f"ניתוח משפטי: {path.name}")
|
||||
return FileResponse(
|
||||
path,
|
||||
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
@@ -2260,6 +2271,10 @@ async def api_mark_final(case_number: str, filename: str):
|
||||
UUID(case["id"]),
|
||||
)
|
||||
|
||||
case_dir = config.find_case_dir(case_number)
|
||||
if case_dir.exists():
|
||||
commit_and_push(case_dir, f"גרסה סופית: {final_name}")
|
||||
|
||||
return {
|
||||
"final_filename": final_name,
|
||||
"training_copy": str(training_dest),
|
||||
|
||||
Reference in New Issue
Block a user