- onboard-client.py: client replica scaffolding CLI - gws/: Google Workspace sync (Gmail, Calendar, Drive) - lifestream/: life event stream collector - muscriptor-mcp/: audio → MIDI MCP server - music-mcp/: music library MCP server - data_sharing/: consent-gated data sharing (Python + TS) - sync-mirrors.py: GitHub → Forgejo mirror engine - brain-to-gbrain.py, vault-sync.py, test-all.sh - shared/: TS data-sharing library + index - dirac: provider registry update - .gitignore: exclude Rust build artifacts Co-authored-by: Álvaro de Campos <campos@portugalfuturista.org>
138 lines
4.2 KiB
Python
138 lines
4.2 KiB
Python
"""
|
|
Sync orchestrator — collect → filter → transmit.
|
|
|
|
This is the main entry point for the data sharing cycle. It:
|
|
1. Loads consent from the workspace config.toml
|
|
2. Collects consented data from the local brain
|
|
3. Transmits via the configured transport
|
|
4. Reports the result
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from .consent import ConsentRecord, load_consent
|
|
from .collector import collect
|
|
from .transports import get_transport, TransmissionResult
|
|
|
|
|
|
def run_sync(
|
|
replica_root: Path | None = None,
|
|
config_path: str | Path | None = None,
|
|
dry_run: bool = False,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Execute the full data-sharing cycle.
|
|
|
|
Args:
|
|
replica_root: Path to the replica-omnisciente root. Auto-detected if None.
|
|
config_path: Path to config.toml. Auto-detected if None.
|
|
dry_run: If True, collect but don't transmit.
|
|
|
|
Returns:
|
|
Summary dict with consent state, collection stats, and transmission result.
|
|
"""
|
|
if replica_root is None:
|
|
# Auto-detect: parent of scripts/ directory
|
|
replica_root = Path(__file__).resolve().parents[2]
|
|
|
|
# 1. Load consent
|
|
consent = load_consent(config_path)
|
|
|
|
if not consent.enabled:
|
|
return {
|
|
"status": "disabled",
|
|
"message": "Data sharing is disabled. Set [data_sharing].enabled = true in config.toml",
|
|
"consent": _consent_summary(consent),
|
|
}
|
|
|
|
granted = consent.granted_categories()
|
|
if not granted:
|
|
return {
|
|
"status": "no_consent",
|
|
"message": "Data sharing is enabled but no categories are opted in. "
|
|
"Enable at least one category in [data_sharing.categories].",
|
|
"consent": _consent_summary(consent),
|
|
}
|
|
|
|
# 2. Collect
|
|
payload = collect(replica_root, consent)
|
|
|
|
# 3. Transmit (or preview)
|
|
if dry_run:
|
|
return {
|
|
"status": "dry_run",
|
|
"message": f"Would transmit {sum(payload.get('_summary', {}).values())} items "
|
|
f"via {consent.transport}",
|
|
"consent": _consent_summary(consent),
|
|
"payload_preview": {
|
|
"schema_version": payload.get("schema_version"),
|
|
"categories": payload.get("_summary"),
|
|
"payload_size_bytes": len(json.dumps(payload).encode("utf-8")),
|
|
},
|
|
}
|
|
|
|
transport = get_transport(consent.transport)
|
|
result = transport.transmit(payload, consent)
|
|
|
|
return {
|
|
"status": "success" if result.success else "failed",
|
|
"message": result.message,
|
|
"consent": _consent_summary(consent),
|
|
"transmission": {
|
|
"transport": result.transport,
|
|
"bytes_sent": result.bytes_sent,
|
|
"timestamp": result.timestamp,
|
|
},
|
|
"items_collected": payload.get("_summary", {}),
|
|
}
|
|
|
|
|
|
def _consent_summary(consent: ConsentRecord) -> dict[str, Any]:
|
|
"""Summarize consent state for reporting."""
|
|
return {
|
|
"enabled": consent.enabled,
|
|
"transport": consent.transport,
|
|
"endpoint": consent.endpoint or "(not set)",
|
|
"categories_granted": consent.granted_categories(),
|
|
"retention_days": consent.retention_days,
|
|
"redact_secrets": consent.redact_secrets,
|
|
}
|
|
|
|
|
|
def show_status(
|
|
replica_root: Path | None = None,
|
|
config_path: str | Path | None = None,
|
|
) -> str:
|
|
"""
|
|
Return a human-readable status string for CLI display.
|
|
|
|
Shows current consent state and what would be shared.
|
|
"""
|
|
consent = load_consent(config_path)
|
|
|
|
lines = [
|
|
"=" * 50,
|
|
" DATA SHARING STATUS",
|
|
"=" * 50,
|
|
"",
|
|
consent.to_display(),
|
|
"",
|
|
]
|
|
|
|
if not consent.enabled:
|
|
lines.append("Data sharing is OFF — nothing is sent to Portugal Futurista.")
|
|
elif not consent.granted_categories():
|
|
lines.append("Data sharing enabled but NO categories opted in.")
|
|
lines.append("Nothing will be sent.")
|
|
else:
|
|
lines.append(f"Ready to share: {', '.join(consent.granted_categories())}")
|
|
lines.append(f"via {consent.transport} transport")
|
|
|
|
lines.append("")
|
|
return "\n".join(lines)
|