mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
add live console status to sync watch
This commit is contained in:
@@ -8,7 +8,10 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.live import Live
|
||||
from rich.table import Table
|
||||
from watchfiles import awatch, Change
|
||||
import os
|
||||
|
||||
@@ -16,8 +19,6 @@ from basic_memory.config import ProjectConfig
|
||||
from basic_memory.sync.sync_service import SyncService
|
||||
from basic_memory.services.file_service import FileService
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
class WatchEvent(BaseModel):
|
||||
timestamp: datetime
|
||||
@@ -79,6 +80,56 @@ class WatchService:
|
||||
self.state = WatchServiceState()
|
||||
self.status_path = config.home / ".basic-memory" / "watch-status.json"
|
||||
self.status_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
self.console = Console()
|
||||
|
||||
def generate_table(self) -> Table:
|
||||
"""Generate status display table"""
|
||||
table = Table(title="Basic Memory Sync Status")
|
||||
|
||||
# Add status row
|
||||
table.add_column("Status", style="cyan")
|
||||
table.add_column("Last Scan", style="cyan")
|
||||
table.add_column("Files", style="cyan")
|
||||
table.add_column("Errors", style="red")
|
||||
|
||||
# Add main status row
|
||||
table.add_row(
|
||||
"✓ Running" if self.state.running else "✗ Stopped",
|
||||
self.state.last_scan.strftime("%H:%M:%S") if self.state.last_scan else "-",
|
||||
str(self.state.synced_files),
|
||||
f"{self.state.error_count} ({self.state.last_error.strftime('%H:%M:%S') if self.state.last_error else 'none'})",
|
||||
)
|
||||
|
||||
if self.state.recent_events:
|
||||
# Add recent events
|
||||
table.add_section()
|
||||
table.add_row("Recent Events", "", "", "")
|
||||
|
||||
for event in self.state.recent_events[:5]: # Show last 5 events
|
||||
color = {
|
||||
"new": "green",
|
||||
"modified": "yellow",
|
||||
"moved": "blue",
|
||||
"deleted": "red",
|
||||
"error": "red",
|
||||
}.get(event.action, "white")
|
||||
|
||||
icon = {
|
||||
"new": "✚",
|
||||
"modified": "✎",
|
||||
"moved": "→",
|
||||
"deleted": "✖",
|
||||
"error": "!",
|
||||
}.get(event.action, "*")
|
||||
|
||||
table.add_row(
|
||||
f"[{color}]{icon} {event.action}[/{color}]",
|
||||
event.timestamp.strftime("%H:%M:%S"),
|
||||
f"[{color}]{event.path}[/{color}]",
|
||||
f"[dim]{event.checksum[:8] if event.checksum else ''}[/dim]",
|
||||
)
|
||||
|
||||
return table
|
||||
|
||||
async def run(self):
|
||||
"""Watch for file changes and sync them"""
|
||||
@@ -86,24 +137,26 @@ class WatchService:
|
||||
self.state.start_time = datetime.now()
|
||||
await self.write_status()
|
||||
|
||||
console.print("\n[cyan]Watching for changes...[/cyan]")
|
||||
try:
|
||||
async for changes in awatch(
|
||||
self.config.home,
|
||||
watch_filter=self.filter_changes,
|
||||
debounce=self.config.sync_delay,
|
||||
recursive=True,
|
||||
):
|
||||
# just sync the whole dir
|
||||
await self.handle_changes(self.config.home)
|
||||
with Live(self.generate_table(), refresh_per_second=4, console=self.console) as live:
|
||||
try:
|
||||
async for changes in awatch(
|
||||
self.config.home,
|
||||
watch_filter=self.filter_changes,
|
||||
debounce=self.config.sync_delay,
|
||||
recursive=True,
|
||||
):
|
||||
# Process changes
|
||||
await self.handle_changes(self.config.home)
|
||||
# Update display
|
||||
live.update(self.generate_table())
|
||||
|
||||
except Exception as e:
|
||||
self.state.record_error(str(e))
|
||||
await self.write_status()
|
||||
raise
|
||||
finally:
|
||||
self.state.running = False
|
||||
await self.write_status()
|
||||
except Exception as e:
|
||||
self.state.record_error(str(e))
|
||||
await self.write_status()
|
||||
raise
|
||||
finally:
|
||||
self.state.running = False
|
||||
await self.write_status()
|
||||
|
||||
async def write_status(self):
|
||||
"""Write current state to status file"""
|
||||
@@ -124,31 +177,21 @@ class WatchService:
|
||||
|
||||
# Update stats
|
||||
for path in report.new:
|
||||
event = self.state.add_event(
|
||||
self.state.add_event(
|
||||
path=path, action="new", status="success", checksum=report.checksums[path]
|
||||
)
|
||||
console.print(
|
||||
f"{event.timestamp.isoformat(timespec='minutes')} New:\t\t [green]{path}[/green] ({event.checksum[:8]})"
|
||||
)
|
||||
for path in report.modified:
|
||||
event = self.state.add_event(
|
||||
self.state.add_event(
|
||||
path=path, action="modified", status="success", checksum=report.checksums[path]
|
||||
)
|
||||
console.print(
|
||||
f"{event.timestamp.isoformat(timespec='minutes')} Modified:\t [yellow]{path}[/yellow] ({event.checksum[:8]})"
|
||||
)
|
||||
for old_path, new_path in report.moves.items():
|
||||
event = self.state.add_event(
|
||||
self.state.add_event(
|
||||
path=f"{old_path} -> {new_path}",
|
||||
action="moved",
|
||||
status="success",
|
||||
checksum=report.checksums[new_path],
|
||||
)
|
||||
console.print(
|
||||
f"{event.timestamp.isoformat(timespec='minutes')} Moved:\t\t [blue]{old_path} -> {new_path}[/blue] ({event.checksum[:8]})"
|
||||
)
|
||||
for path in report.deleted:
|
||||
event = self.state.add_event(path=path, action="deleted", status="success")
|
||||
console.print(f"{event.timestamp.isoformat(timespec='minutes')} Deleted:\t [red]{path}[/red]")
|
||||
self.state.add_event(path=path, action="deleted", status="success")
|
||||
|
||||
await self.write_status()
|
||||
|
||||
Reference in New Issue
Block a user