From a64743082785de99e07237dd92876f22284f87e1 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sun, 22 Mar 2026 18:15:33 +0000 Subject: [PATCH] Initial upload: shell-history-semantic-search v0.1.0 --- src/shell_history_search/parsers/__init__.py | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/shell_history_search/parsers/__init__.py diff --git a/src/shell_history_search/parsers/__init__.py b/src/shell_history_search/parsers/__init__.py new file mode 100644 index 0000000..c64a1f4 --- /dev/null +++ b/src/shell_history_search/parsers/__init__.py @@ -0,0 +1,48 @@ +from abc import ABC, abstractmethod +from dataclasses import dataclass +from pathlib import Path +from typing import Iterator, Optional +import hashlib + + +__all__ = [ + "HistoryEntry", + "HistoryParser", +] + + +@dataclass +class HistoryEntry: + command: str + shell_type: str + timestamp: Optional[int] + hostname: Optional[str] + command_hash: str + + @classmethod + def create_hash(cls, command: str) -> str: + return hashlib.sha256(command.encode()).hexdigest()[:16] + + +class HistoryParser(ABC): + shell_type: str = "unknown" + + @abstractmethod + def parse(self, history_path: Path) -> Iterator[HistoryEntry]: + pass + + @abstractmethod + def get_history_path(self) -> Path: + pass + + def read_history_file(self, history_path: Path) -> Iterator[str]: + if not history_path.exists(): + return + + try: + with open(history_path, "r", encoding="utf-8", errors="replace") as f: + for line in f: + yield line.rstrip("\n") + except OSError as e: + import logging + logging.warning(f"Could not read history file {history_path}: {e}") \ No newline at end of file