""" Comprehensive hook tracking models for Claude Code sessions. """ from datetime import datetime from typing import Optional, Dict, Any from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Boolean, Float, JSON from sqlalchemy.orm import relationship from app.models.base import Base class HookEvent(Base): """ Base model for all hook events with common fields. """ __tablename__ = "hook_events" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) hook_type = Column(String(50), nullable=False, index=True) timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) data = Column(JSON, nullable=True) # Flexible JSON data for hook-specific information # Relationships session = relationship("Session", back_populates="hook_events") def __repr__(self): return f"" class ToolError(Base): """Track failed tool calls with error details.""" __tablename__ = "tool_errors" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) tool_name = Column(String(100), nullable=False, index=True) error_type = Column(String(100), nullable=False, index=True) error_message = Column(Text, nullable=False) stack_trace = Column(Text, nullable=True) parameters = Column(JSON, nullable=True) timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) session = relationship("Session") def __repr__(self): return f"" class WaitingPeriodNew(Base): """Track periods when Claude is thinking vs actively working.""" __tablename__ = "waiting_periods_new" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) start_time = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) end_time = Column(DateTime, nullable=True) duration_ms = Column(Integer, nullable=True) reason = Column(String(100), nullable=True, index=True) # thinking, processing, waiting_for_input context = Column(Text, nullable=True) # What was happening when waiting started session = relationship("Session") def __repr__(self): return f"" class PerformanceMetric(Base): """Monitor system performance during development.""" __tablename__ = "performance_metrics" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) metric_type = Column(String(50), nullable=False, index=True) # memory, cpu, disk value = Column(Float, nullable=False) unit = Column(String(20), nullable=False) # MB, %, seconds threshold_exceeded = Column(Boolean, default=False) timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) session = relationship("Session") def __repr__(self): return f"" class CodeQualityEvent(Base): """Track code quality analysis, linting, and testing.""" __tablename__ = "code_quality_events" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) event_type = Column(String(50), nullable=False, index=True) # lint, format, test, build, analysis file_path = Column(Text, nullable=True) tool_name = Column(String(100), nullable=True) # eslint, prettier, pytest, etc. status = Column(String(20), nullable=False, index=True) # success, warning, error issues_count = Column(Integer, default=0) details = Column(JSON, nullable=True) # Specific issues, test results, etc. duration_ms = Column(Integer, nullable=True) timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) session = relationship("Session") def __repr__(self): return f"" class WorkflowEvent(Base): """Track development workflow patterns.""" __tablename__ = "workflow_events" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) event_type = Column(String(50), nullable=False, index=True) # context_switch, search_query, browser_tab, etc. description = Column(Text, nullable=True) event_metadata = Column(JSON, nullable=True) # Event-specific data source = Column(String(100), nullable=True) # Where the event came from duration_ms = Column(Integer, nullable=True) # For events with duration timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) session = relationship("Session") def __repr__(self): return f"" class LearningEvent(Base): """Track learning sessions and knowledge acquisition.""" __tablename__ = "learning_events" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) event_type = Column(String(50), nullable=False, index=True) # tutorial, documentation, experimentation topic = Column(String(200), nullable=True, index=True) # What was being learned resource_url = Column(Text, nullable=True) # Documentation URL, tutorial link confidence_before = Column(Integer, nullable=True) # 1-10 scale confidence_after = Column(Integer, nullable=True) # 1-10 scale notes = Column(Text, nullable=True) duration_ms = Column(Integer, nullable=True) timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) session = relationship("Session") def __repr__(self): return f"" class EnvironmentEvent(Base): """Track environment and configuration changes.""" __tablename__ = "environment_events" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) event_type = Column(String(50), nullable=False, index=True) # env_change, config_update, security_scan environment = Column(String(50), nullable=True, index=True) # dev, staging, prod config_file = Column(Text, nullable=True) changes = Column(JSON, nullable=True) # What changed impact_level = Column(String(20), nullable=True) # low, medium, high, critical timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) session = relationship("Session") def __repr__(self): return f"" class CollaborationEvent(Base): """Track collaboration and external interactions.""" __tablename__ = "collaboration_events" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) event_type = Column(String(50), nullable=False, index=True) # external_resource, ai_question, review_request interaction_type = Column(String(50), nullable=True) # documentation, stackoverflow, api_docs query_or_topic = Column(Text, nullable=True) resource_url = Column(Text, nullable=True) response_quality = Column(Integer, nullable=True) # 1-5 rating time_to_resolution = Column(Integer, nullable=True) # minutes event_metadata = Column(JSON, nullable=True) timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) session = relationship("Session") def __repr__(self): return f"" class ProjectIntelligence(Base): """Track high-level project development patterns.""" __tablename__ = "project_intelligence" id = Column(Integer, primary_key=True, index=True) session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True) event_type = Column(String(50), nullable=False, index=True) # refactor, feature_flag, debugging_session scope = Column(String(20), nullable=True, index=True) # small, medium, large complexity = Column(String(20), nullable=True, index=True) # low, medium, high start_time = Column(DateTime, nullable=False, default=datetime.utcnow) end_time = Column(DateTime, nullable=True) duration_minutes = Column(Integer, nullable=True) files_affected = Column(JSON, nullable=True) # List of file paths outcome = Column(String(20), nullable=True) # success, partial, failed, abandoned notes = Column(Text, nullable=True) timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True) session = relationship("Session") def __repr__(self): return f"" # Add hook_events relationship to Session model def add_hook_relationships(): """Add hook event relationships to the Session model.""" from app.models.session import Session Session.hook_events = relationship("HookEvent", back_populates="session", cascade="all, delete-orphan") Session.tool_errors = relationship("ToolError", cascade="all, delete-orphan") Session.waiting_periods_new = relationship("WaitingPeriodNew", cascade="all, delete-orphan") Session.performance_metrics = relationship("PerformanceMetric", cascade="all, delete-orphan") Session.code_quality_events = relationship("CodeQualityEvent", cascade="all, delete-orphan") Session.workflow_events = relationship("WorkflowEvent", cascade="all, delete-orphan") Session.learning_events = relationship("LearningEvent", cascade="all, delete-orphan") Session.environment_events = relationship("EnvironmentEvent", cascade="all, delete-orphan") Session.collaboration_events = relationship("CollaborationEvent", cascade="all, delete-orphan") Session.project_intelligence = relationship("ProjectIntelligence", cascade="all, delete-orphan")