chore: archive tools/ui_inspector snapshot before migration removal.

Keep the last in-template copy on main so history can restore it; product continues in jiangchang-ui-recorder.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-07 11:19:14 +08:00
parent 46bc573777
commit 633ecff4e2
92 changed files with 13704 additions and 288 deletions

View File

@@ -0,0 +1,6 @@
"""Shared event, action, and evidence pipeline."""
from .event_journal import EventJournal
__all__ = ["EventJournal"]

View File

@@ -0,0 +1,49 @@
"""Append-only raw interaction journal.
Raw events are facts. They are persisted before semantic reduction so a
future reducer can rebuild Action Flow without asking the user to repeat the
workflow.
"""
from __future__ import annotations
import json
import threading
from dataclasses import asdict, is_dataclass
from datetime import datetime
from pathlib import Path
from typing import Any
from redaction import sanitize_artifact
class EventJournal:
def __init__(self, flow_dir: Path) -> None:
self.path = Path(flow_dir) / "journal" / "raw_events.jsonl"
self.path.parent.mkdir(parents=True, exist_ok=True)
self._lock = threading.Lock()
self._sequence = 0
def append(self, event: Any, *, channel: str = "surface") -> int:
if is_dataclass(event) and not isinstance(event, type):
payload = asdict(event)
elif isinstance(event, dict):
payload = dict(event)
else:
payload = dict(getattr(event, "__dict__", {}) or {})
with self._lock:
self._sequence += 1
record = {
"journal_sequence": self._sequence,
"received_at": datetime.now().astimezone().isoformat(),
"channel": channel,
"event": sanitize_artifact(payload),
}
line = json.dumps(
record, ensure_ascii=False, sort_keys=True, separators=(",", ":")
)
with self.path.open("a", encoding="utf-8", newline="\n") as stream:
stream.write(line + "\n")
stream.flush()
return self._sequence