first commit

This commit is contained in:
w4nn4d13
2026-04-06 13:37:26 +05:30
commit 065eae9134
52 changed files with 1918 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
"""Utility helpers for ExecuTrace."""
Binary file not shown.
Binary file not shown.
+23
View File
@@ -0,0 +1,23 @@
from __future__ import annotations
import hashlib
BLOCK_SIZE = 1024 * 64
def sha256_bytes(data: bytes) -> str:
digest = hashlib.sha256()
digest.update(data)
return digest.hexdigest()
def sha256_file(path: str) -> str:
digest = hashlib.sha256()
with open(path, "rb") as f:
while True:
block = f.read(BLOCK_SIZE)
if not block:
break
digest.update(block)
return digest.hexdigest()
+69
View File
@@ -0,0 +1,69 @@
"""Interactive CLI utilities for user input and selection."""
from __future__ import annotations
import os
from pathlib import Path
from typing import Literal
def prompt_storage_location(default: str | None = None) -> str:
"""Prompt user for storage location with optional default."""
if default is None:
default = str(Path.home() / ".exectrace" / "workflows")
prompt_text = f"Enter storage path (press Enter for default: {default}): "
user_input = input(prompt_text).strip()
if not user_input:
return default
# Expand home directory
path = Path(user_input).expanduser()
# Create directory if it doesn't exist
path.mkdir(parents=True, exist_ok=True)
return str(path)
def prompt_file_format() -> Literal["json", "xml"]:
"""Prompt user to choose file format (JSON or XML)."""
while True:
print("Choose file format:")
print(" 1) JSON (default)")
print(" 2) XML")
choice = input("Enter choice (1 or 2, default: 1): ").strip().lower()
if not choice or choice == "1":
return "json"
elif choice == "2":
return "xml"
else:
print("Invalid choice. Please enter 1 or 2.")
def prompt_confirmation(message: str) -> bool:
"""Prompt user for yes/no confirmation."""
while True:
response = input(f"{message} (y/n): ").strip().lower()
if response in ("y", "yes"):
return True
elif response in ("n", "no"):
return False
else:
print("Please enter 'y' or 'n'.")
def list_directories(base_path: str | None = None) -> list[str]:
"""List subdirectories in a path for selection (future feature)."""
if base_path is None:
base_path = str(Path.home())
try:
base = Path(base_path)
dirs = sorted([d.name for d in base.iterdir() if d.is_dir()])
return dirs
except (OSError, PermissionError):
return []
+14
View File
@@ -0,0 +1,14 @@
from __future__ import annotations
import logging
def get_logger(name: str = "exectrace", level: int = logging.INFO) -> logging.Logger:
logger = logging.getLogger(name)
if not logger.handlers:
handler = logging.StreamHandler()
formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(name)s: %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(level)
return logger
+21
View File
@@ -0,0 +1,21 @@
from __future__ import annotations
import re
from typing import Iterable
DEFAULT_PATTERNS = [
re.compile(r"(?i)(api[_-]?key\s*[=:]\s*)([^\s]+)"),
re.compile(r"(?i)(token\s*[=:]\s*)([^\s]+)"),
re.compile(r"(?i)(password\s*[=:]\s*)([^\s]+)"),
re.compile(r"(?i)(secret\s*[=:]\s*)([^\s]+)"),
re.compile(r"(?i)(Authorization:\s*Bearer\s+)([^\s]+)"),
]
def redact_text(text: str, patterns: Iterable[re.Pattern] | None = None) -> str:
"""Redact common secrets from captured command text."""
active_patterns = list(patterns) if patterns is not None else DEFAULT_PATTERNS
result = text
for pattern in active_patterns:
result = pattern.sub(r"\1<REDACTED>", result)
return result
+11
View File
@@ -0,0 +1,11 @@
from __future__ import annotations
from datetime import datetime, timezone
ISO_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
def utc_now_iso() -> str:
"""Return a UTC timestamp in ISO-8601 format."""
return datetime.now(tz=timezone.utc).strftime(ISO_FORMAT)