diff --git a/shell_memory/models.py b/shell_memory/models.py new file mode 100644 index 0000000..de3c159 --- /dev/null +++ b/shell_memory/models.py @@ -0,0 +1,126 @@ +"""Data models for Shell Memory CLI.""" + +from dataclasses import dataclass, field +from datetime import datetime +from typing import List, Optional +import hashlib + + +@dataclass +class Command: + """Represents a recorded terminal command.""" + id: Optional[int] = None + command: str = "" + description: str = "" + tags: List[str] = field(default_factory=list) + created_at: datetime = field(default_factory=datetime.now) + usage_count: int = 0 + + def to_dict(self) -> dict: + return { + "id": self.id, + "command": self.command, + "description": self.description, + "tags": self.tags, + "created_at": self.created_at.isoformat(), + "usage_count": self.usage_count, + } + + @classmethod + def from_dict(cls, data: dict) -> "Command": + return cls( + id=data.get("id"), + command=data.get("command", ""), + description=data.get("description", ""), + tags=data.get("tags", []), + created_at=datetime.fromisoformat(data["created_at"]) if "created_at" in data else datetime.now(), + usage_count=data.get("usage_count", 0), + ) + + +@dataclass +class Pattern: + """Represents a detected command pattern.""" + id: Optional[int] = None + name: str = "" + command_ids: List[int] = field(default_factory=list) + frequency: int = 0 + last_seen: datetime = field(default_factory=datetime.now) + + def sequence_hash(self) -> str: + hash_input = ",".join(map(str, self.command_ids)) + return hashlib.md5(hash_input.encode()).hexdigest() + + def to_dict(self) -> dict: + return { + "id": self.id, + "name": self.name, + "command_ids": self.command_ids, + "frequency": self.frequency, + "last_seen": self.last_seen.isoformat(), + } + + @classmethod + def from_dict(cls, data: dict) -> "Pattern": + return cls( + id=data.get("id"), + name=data.get("name", ""), + command_ids=data.get("command_ids", []), + frequency=data.get("frequency", 0), + last_seen=datetime.fromisoformat(data["last_seen"]) if "last_seen" in data else datetime.now(), + ) + + +@dataclass +class Session: + """Represents a recorded terminal session.""" + id: Optional[int] = None + name: str = "" + commands: List[dict] = field(default_factory=list) + start_time: datetime = field(default_factory=datetime.now) + end_time: Optional[datetime] = None + + def to_dict(self) -> dict: + return { + "id": self.id, + "name": self.name, + "commands": self.commands, + "start_time": self.start_time.isoformat(), + "end_time": self.end_time.isoformat() if self.end_time else None, + } + + @classmethod + def from_dict(cls, data: dict) -> "Session": + return cls( + id=data.get("id"), + name=data.get("name", ""), + commands=data.get("commands", []), + start_time=datetime.fromisoformat(data["start_time"]) if "start_time" in data else datetime.now(), + end_time=datetime.fromisoformat(data["end_time"]) if data.get("end_time") else None, + ) + + +@dataclass +class ScriptTemplate: + """Represents a script template for natural language generation.""" + id: Optional[int] = None + keywords: List[str] = field(default_factory=list) + template: str = "" + description: str = "" + + def to_dict(self) -> dict: + return { + "id": self.id, + "keywords": self.keywords, + "template": self.template, + "description": self.description, + } + + @classmethod + def from_dict(cls, data: dict) -> "ScriptTemplate": + return cls( + id=data.get("id"), + keywords=data.get("keywords", []), + template=data.get("template", ""), + description=data.get("description", ""), + ) \ No newline at end of file