Files
odysseus/scripts/build_sft_environment_inventories.py
T

94 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""Snapshot non-sensitive fixture inventories for SFT expansion owners."""
from __future__ import annotations
import argparse
import json
import sys
from collections import Counter
from pathlib import Path
from typing import Any
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from core.database import CalendarCal, CalendarEvent, Document, Memory, Note, ScheduledTask, Session, SessionLocal, UserTool # noqa: E402
from scripts.sft_email_overseer import PROFILES # noqa: E402
OWNERS = ["sft_maya_ops", "sft_jules_research", "sft_nora_design", "sft_omar_finance"]
def clip(value: Any, limit: int = 180) -> str:
text = str(value or "").replace("\n", " ").strip()
return text[:limit] + ("..." if len(text) > limit else "")
def email_inventory() -> dict[str, list[dict[str, Any]]]:
payload = json.loads((ROOT / "data/fixture_email_messages.json").read_text(encoding="utf-8"))
rows = payload.get("messages") if isinstance(payload, dict) else payload
out = {owner: [] for owner in OWNERS}
for row in rows or []:
owner = str(row.get("owner") or "")
if owner not in out:
continue
out[owner].append({
"uid": str(row.get("uid") or ""),
"account": row.get("account") or row.get("account_id"),
"from": clip(row.get("from") or row.get("sender")),
"subject": clip(row.get("subject")),
"date": row.get("date"),
"attachments": [att.get("filename") for att in (row.get("attachments") or []) if isinstance(att, dict)],
})
return out
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--out", type=Path, required=True)
parser.add_argument("--sample-limit", type=int, default=30)
args = parser.parse_args()
mail = email_inventory()
db = SessionLocal()
try:
inventories = []
for owner in OWNERS:
calendars = db.query(CalendarCal).filter(CalendarCal.owner == owner).all()
calendar_ids = [cal.id for cal in calendars]
events = db.query(CalendarEvent).filter(CalendarEvent.calendar_id.in_(calendar_ids)).order_by(CalendarEvent.dtstart).all() if calendar_ids else []
notes = db.query(Note).filter(Note.owner == owner, Note.archived.is_(False)).order_by(Note.updated_at.desc()).all()
memories = db.query(Memory).filter(Memory.owner == owner).order_by(Memory.timestamp.desc()).all()
documents = db.query(Document).filter(Document.owner == owner, Document.archived.is_(False)).order_by(Document.updated_at.desc()).all()
tasks = db.query(ScheduledTask).filter(ScheduledTask.owner == owner).order_by(ScheduledTask.updated_at.desc()).all()
sessions = db.query(Session).filter(Session.owner == owner, Session.archived.is_(False)).order_by(Session.updated_at.desc()).all()
disabled_tools = [row.name for row in db.query(UserTool).filter(UserTool.owner == owner, UserTool.is_active.is_(False)).all()]
emails = mail.get(owner, [])
inventories.append({
"owner": owner,
"profile": PROFILES[owner],
"counts": {
"emails": len(emails), "notes": len(notes), "memories": len(memories),
"documents": len(documents), "tasks": len(tasks), "calendars": len(calendars),
"calendar_events": len(events), "sessions": len(sessions),
},
"email_accounts": dict(Counter(str(row.get("account") or "unknown") for row in emails)),
"emails": emails[: args.sample_limit],
"notes": [{"id": row.id, "title": clip(row.title), "content": clip(row.content), "type": row.note_type, "label": row.label} for row in notes[: args.sample_limit]],
"memories": [{"id": row.id, "text": clip(row.text), "category": row.category} for row in memories[: args.sample_limit]],
"documents": [{"id": row.id, "title": clip(row.title), "language": row.language, "content": clip(row.current_content)} for row in documents[: args.sample_limit]],
"tasks": [{"id": row.id, "name": clip(row.name), "status": row.status, "schedule": row.schedule} for row in tasks[: args.sample_limit]],
"calendars": [{"id": row.id, "name": row.name, "source": row.source} for row in calendars],
"events": [{"uid": row.uid, "summary": clip(row.summary), "start": row.dtstart.isoformat(), "all_day": row.all_day} for row in events[: args.sample_limit]],
"sessions": [{"id": row.id, "name": clip(row.name), "mode": row.mode} for row in sessions[: args.sample_limit]],
"disabled_tools": disabled_tools,
})
finally:
db.close()
args.out.parent.mkdir(parents=True, exist_ok=True)
args.out.write_text(json.dumps({"environments": inventories}, ensure_ascii=False, indent=2), encoding="utf-8")
print(json.dumps({row["owner"]: row["counts"] for row in inventories}, indent=2))
if __name__ == "__main__":
main()