//! Pure domain entity for the edit log — an append-only log of file mutations. //! //! Records every file mutation made by any tool, enabling audit trails //! and potential undo operations. Each entry captures the tool name, //! target path, reason, content hash, and byte delta. //! //! # Architecture //! This is a pure data structure with **no I/O logic**. Load/save //! responsibilities live in `EditLogRepository` (domain::repository). //! //! ## Data Flow //! 1. Tools call `EditLog::push()` to record each mutation //! 2. The in-memory `EditLog` is periodically flushed to disk by the repo //! 3. Oldest entries are evicted from the in-memory cache when //! `MAX_MEMORY_ENTRIES` is exceeded (prevents unbounded growth) use serde::{Deserialize, Serialize}; /// A single recorded file edit event. /// /// ## Fields /// - `ts` — Unix timestamp (seconds) when the edit occurred /// - `tool` — name of the tool that performed the edit (e.g. "Bash", "Edit") /// - `path` — absolute file path that was modified /// - `reason` — human-readable explanation of why the edit was made /// - `content_sha256` — SHA-256 hex digest of the content *after* the edit /// - `bytes_delta` — signed byte count change (+added, -removed) /// - `origin` — origin identifier (which agent / session context) /// - `session_id` — session in which this edit was performed #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EditLogEntry { pub ts: i64, pub tool: String, pub path: String, pub reason: String, pub content_sha256: String, pub bytes_delta: i64, pub origin: String, pub session_id: String, } /// Maximum number of edit entries held in memory at once. /// /// Beyond this limit, old entries are dropped from the in-memory cache /// to prevent unbounded memory growth in long-running sessions. pub const MAX_MEMORY_ENTRIES: usize = 10_000; /// In-memory view of a session's edit log. /// /// Wraps a `Vec` and provides basic query helpers. #[derive(Debug, Clone)] pub struct EditLog { /// Ordered list of edit entries (newest appended last). pub entries: Vec, } impl EditLog { /// Create an empty edit log with no entries. pub fn new() -> Self { Self { entries: Vec::new(), } } /// Return the number of in-memory entries. pub fn len(&self) -> usize { self.entries.len() } /// Return `true` if the log contains no entries. pub fn is_empty(&self) -> bool { self.entries.is_empty() } } impl Default for EditLog { /// Returns an empty `EditLog` via `EditLog::new()`. fn default() -> Self { Self::new() } }