Ship War Room UX, CEO inbox, mobile chat, and Agents NAS workspace.

Make A2A togglable, keep reply context while reading, route agent data to //10.4.7.11/share/Agents, and polish themes plus export-intel sync cancel.
This commit is contained in:
Aissa
2026-08-16 22:40:32 +00:00
parent 910ba465d7
commit c5ea8cbb63
26 changed files with 2891 additions and 407 deletions
+41 -3
View File
@@ -11,6 +11,39 @@ STATUS_PATH = Path("/tmp/export-intel-sync-status.json")
LOG_PATH = Path("/tmp/export-intel-sync-progress.jsonl")
LOCK_PATH = Path("/tmp/export-intel-sync.lock")
CANCEL_PATH = Path("/tmp/export-intel-sync-cancel.flag")
class SyncCancelled(Exception):
"""Raised when a running sync job is cancelled by the user."""
def request_cancel(reason: str = "user") -> dict[str, Any]:
CANCEL_PATH.write_text(json.dumps({"ts": _now(), "reason": reason}))
log_event("cancel_requested", reason=reason)
# Mark running jobs as cancelling
status = _load_status()
for job in status.get("jobs", {}).values():
if job.get("status") == "running":
job["status"] = "cancelling"
job["message"] = "Annuleren…"
job["updated_at"] = _now()
_save_status(status)
return {"ok": True, "cancel_requested": True}
def clear_cancel() -> None:
CANCEL_PATH.unlink(missing_ok=True)
def is_cancel_requested() -> bool:
return CANCEL_PATH.exists()
def raise_if_cancelled() -> None:
if is_cancel_requested():
raise SyncCancelled("Sync geannuleerd door gebruiker")
_active_job_id: Optional[str] = None
@@ -68,6 +101,7 @@ def _clear_lock() -> None:
def start_job(job_type: str, label: str, total: int = 0, meta: Optional[dict[str, Any]] = None) -> str:
clear_cancel()
job_id = f"{job_type}-{_now():.0f}"
status = _load_status()
job = {
@@ -138,7 +172,10 @@ def finish_job(job_id: str, result: Optional[dict[str, Any]] = None, error: Opti
job = status["jobs"].get(job_id)
if not job:
return
job["status"] = "error" if error else "completed"
if error and "geannuleerd" in str(error).lower():
job["status"] = "cancelled"
else:
job["status"] = "error" if error else "completed"
job["updated_at"] = _now()
job["finished_at"] = _now()
job["percent"] = 100 if not error else job.get("percent", 0)
@@ -151,9 +188,10 @@ def finish_job(job_id: str, result: Optional[dict[str, Any]] = None, error: Opti
log_event("job_finish", job_id=job_id, status=job["status"], error=error)
if get_active_job() == job_id:
set_active_job(None)
running = [j for j in status["jobs"].values() if j.get("status") == "running"]
running = [j for j in status["jobs"].values() if j.get("status") in ("running", "cancelling")]
if not running:
_clear_lock()
clear_cancel()
def tail_log(limit: int = 40) -> list[dict[str, Any]]:
@@ -172,7 +210,7 @@ def tail_log(limit: int = 40) -> list[dict[str, Any]]:
def get_monitor_snapshot(db_counts: Optional[dict[str, Any]] = None) -> dict[str, Any]:
status = _load_status()
jobs = status.get("jobs", {})
active = [j for j in jobs.values() if j.get("status") == "running"]
active = [j for j in jobs.values() if j.get("status") in ("running", "cancelling")]
recent = [jobs[jid] for jid in status.get("history", [])[:8] if jid in jobs and jobs[jid].get("status") != "running"]
lock = _read_json(LOCK_PATH, None) if LOCK_PATH.exists() else None
return {