Add comprehensive development intelligence system that tracks: - Development sessions with automatic start/stop - Full conversation history with semantic search - Tool usage and file operation analytics - Think time and engagement analysis - Git activity correlation - Learning pattern recognition - Productivity insights and metrics Features: - FastAPI backend with SQLite database - Modern web dashboard with interactive charts - Claude Code hook integration for automatic tracking - Comprehensive test suite with 100+ tests - Complete API documentation (OpenAPI/Swagger) - Privacy-first design with local data storage 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
220 lines
8.1 KiB
Python
220 lines
8.1 KiB
Python
"""
|
|
Pydantic schemas for API request/response models.
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from typing import Optional, List, Dict, Any, Union
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
# Base schemas
|
|
class TimestampMixin(BaseModel):
|
|
"""Mixin for timestamp fields."""
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
# Session schemas
|
|
class SessionStartRequest(BaseModel):
|
|
"""Request schema for starting a session."""
|
|
session_type: str = Field(..., description="Type of session: startup, resume, or clear")
|
|
working_directory: str = Field(..., description="Current working directory")
|
|
git_branch: Optional[str] = Field(None, description="Current git branch")
|
|
git_repo: Optional[str] = Field(None, description="Git repository URL")
|
|
environment: Optional[Dict[str, Any]] = Field(None, description="Environment variables and context")
|
|
|
|
|
|
class SessionEndRequest(BaseModel):
|
|
"""Request schema for ending a session."""
|
|
session_id: int = Field(..., description="ID of the session to end")
|
|
end_reason: str = Field(default="normal", description="Reason for ending: normal, interrupted, or timeout")
|
|
|
|
|
|
class SessionResponse(BaseModel):
|
|
"""Response schema for session operations."""
|
|
session_id: int
|
|
project_id: int
|
|
status: str
|
|
message: Optional[str] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Conversation schemas
|
|
class ConversationRequest(BaseModel):
|
|
"""Request schema for logging conversations."""
|
|
session_id: int = Field(..., description="Associated session ID")
|
|
timestamp: datetime = Field(default_factory=datetime.utcnow, description="When the exchange occurred")
|
|
user_prompt: Optional[str] = Field(None, description="User's input message")
|
|
claude_response: Optional[str] = Field(None, description="Claude's response")
|
|
tools_used: Optional[List[str]] = Field(None, description="Tools used in the response")
|
|
files_affected: Optional[List[str]] = Field(None, description="Files mentioned or modified")
|
|
context: Optional[Dict[str, Any]] = Field(None, description="Additional context")
|
|
tokens_input: Optional[int] = Field(None, description="Estimated input token count")
|
|
tokens_output: Optional[int] = Field(None, description="Estimated output token count")
|
|
exchange_type: str = Field(..., description="Type of exchange: user_prompt or claude_response")
|
|
|
|
|
|
class ConversationResponse(BaseModel):
|
|
"""Response schema for conversation operations."""
|
|
id: int
|
|
session_id: int
|
|
timestamp: datetime
|
|
exchange_type: str
|
|
content_length: int
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Activity schemas
|
|
class ActivityRequest(BaseModel):
|
|
"""Request schema for recording activities."""
|
|
session_id: int = Field(..., description="Associated session ID")
|
|
conversation_id: Optional[int] = Field(None, description="Associated conversation ID")
|
|
timestamp: datetime = Field(default_factory=datetime.utcnow, description="When the activity occurred")
|
|
tool_name: str = Field(..., description="Name of the tool used")
|
|
action: str = Field(..., description="Specific action taken")
|
|
file_path: Optional[str] = Field(None, description="Target file path if applicable")
|
|
metadata: Optional[Dict[str, Any]] = Field(None, description="Tool-specific metadata")
|
|
success: bool = Field(default=True, description="Whether the operation succeeded")
|
|
error_message: Optional[str] = Field(None, description="Error details if failed")
|
|
lines_added: Optional[int] = Field(None, description="Lines added for Edit/Write operations")
|
|
lines_removed: Optional[int] = Field(None, description="Lines removed for Edit operations")
|
|
|
|
|
|
class ActivityResponse(BaseModel):
|
|
"""Response schema for activity operations."""
|
|
id: int
|
|
session_id: int
|
|
tool_name: str
|
|
action: str
|
|
timestamp: datetime
|
|
success: bool
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Waiting period schemas
|
|
class WaitingStartRequest(BaseModel):
|
|
"""Request schema for starting a waiting period."""
|
|
session_id: int = Field(..., description="Associated session ID")
|
|
timestamp: datetime = Field(default_factory=datetime.utcnow, description="When waiting started")
|
|
context_before: Optional[str] = Field(None, description="Context before waiting")
|
|
|
|
|
|
class WaitingEndRequest(BaseModel):
|
|
"""Request schema for ending a waiting period."""
|
|
session_id: int = Field(..., description="Associated session ID")
|
|
timestamp: datetime = Field(default_factory=datetime.utcnow, description="When waiting ended")
|
|
duration_seconds: Optional[int] = Field(None, description="Total waiting duration")
|
|
context_after: Optional[str] = Field(None, description="Context after waiting")
|
|
|
|
|
|
class WaitingPeriodResponse(BaseModel):
|
|
"""Response schema for waiting period operations."""
|
|
id: int
|
|
session_id: int
|
|
start_time: datetime
|
|
end_time: Optional[datetime]
|
|
duration_seconds: Optional[int]
|
|
engagement_score: float
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Git operation schemas
|
|
class GitOperationRequest(BaseModel):
|
|
"""Request schema for git operations."""
|
|
session_id: int = Field(..., description="Associated session ID")
|
|
timestamp: datetime = Field(default_factory=datetime.utcnow, description="When the operation occurred")
|
|
operation: str = Field(..., description="Type of git operation")
|
|
command: str = Field(..., description="Full git command executed")
|
|
result: Optional[str] = Field(None, description="Command output")
|
|
success: bool = Field(default=True, description="Whether the command succeeded")
|
|
files_changed: Optional[List[str]] = Field(None, description="Files affected by the operation")
|
|
lines_added: Optional[int] = Field(None, description="Lines added")
|
|
lines_removed: Optional[int] = Field(None, description="Lines removed")
|
|
commit_hash: Optional[str] = Field(None, description="Git commit SHA")
|
|
branch_from: Optional[str] = Field(None, description="Source branch")
|
|
branch_to: Optional[str] = Field(None, description="Target branch")
|
|
|
|
|
|
class GitOperationResponse(BaseModel):
|
|
"""Response schema for git operations."""
|
|
id: int
|
|
session_id: int
|
|
operation: str
|
|
timestamp: datetime
|
|
success: bool
|
|
commit_hash: Optional[str]
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Project schemas
|
|
class ProjectSummary(BaseModel):
|
|
"""Summary information about a project."""
|
|
id: int
|
|
name: str
|
|
path: str
|
|
git_repo: Optional[str]
|
|
languages: Optional[List[str]]
|
|
total_sessions: int
|
|
total_time_minutes: int
|
|
last_activity: Optional[datetime]
|
|
files_modified_count: int
|
|
lines_changed_count: int
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class TimelineEvent(BaseModel):
|
|
"""Individual event in project timeline."""
|
|
timestamp: datetime
|
|
type: str # session_start, session_end, conversation, activity, git_operation
|
|
data: Dict[str, Any]
|
|
|
|
|
|
class ProjectTimeline(BaseModel):
|
|
"""Project timeline with events."""
|
|
project: ProjectSummary
|
|
timeline: List[TimelineEvent]
|
|
|
|
|
|
# Analytics schemas
|
|
class ProductivityMetrics(BaseModel):
|
|
"""Productivity analytics response."""
|
|
engagement_score: float = Field(..., description="Overall engagement level (0-100)")
|
|
average_session_length: float = Field(..., description="Minutes per session")
|
|
think_time_average: float = Field(..., description="Average waiting time between interactions")
|
|
files_per_session: float = Field(..., description="Average files touched per session")
|
|
tools_most_used: List[Dict[str, Union[str, int]]] = Field(..., description="Most frequently used tools")
|
|
productivity_trends: List[Dict[str, Union[str, float]]] = Field(..., description="Daily productivity scores")
|
|
|
|
|
|
class ConversationSearchResult(BaseModel):
|
|
"""Search result for conversation search."""
|
|
id: int
|
|
project_name: str
|
|
timestamp: datetime
|
|
user_prompt: Optional[str]
|
|
claude_response: Optional[str]
|
|
relevance_score: float
|
|
context: List[str]
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Error schemas
|
|
class ErrorResponse(BaseModel):
|
|
"""Standard error response."""
|
|
error: str
|
|
message: str
|
|
details: Optional[Dict[str, Any]] = None |