claude-hooks/lib/models.py
Ryan Malloy 162ca67098 Initial commit: Claude Code Hooks with Diátaxis documentation
 Features:
- 🧠 Shadow learner that builds intelligence from command patterns
- 🛡️ Smart command validation with safety checks
- 💾 Automatic context monitoring and backup system
- 🔄 Session continuity across Claude restarts

📚 Documentation:
- Complete Diátaxis-organized documentation
- Learning-oriented tutorial for getting started
- Task-oriented how-to guides for specific problems
- Information-oriented reference for quick lookup
- Understanding-oriented explanations of architecture

🚀 Installation:
- One-command installation script
- Bootstrap prompt for installation via Claude
- Cross-platform compatibility
- Comprehensive testing suite

🎯 Ready for real-world use and community feedback!

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-19 18:25:34 -06:00

198 lines
6.1 KiB
Python

#!/usr/bin/env python3
"""Data models for Claude Code Hooks system"""
from dataclasses import dataclass, field
from datetime import datetime
from typing import Dict, List, Optional, Any
import json
@dataclass
class ToolExecution:
"""Single tool execution record"""
timestamp: datetime
tool: str
parameters: Dict[str, Any]
success: bool
error_message: Optional[str] = None
execution_time: float = 0.0
context: Dict[str, Any] = field(default_factory=dict)
def to_dict(self) -> Dict[str, Any]:
return {
"timestamp": self.timestamp.isoformat(),
"tool": self.tool,
"parameters": self.parameters,
"success": self.success,
"error_message": self.error_message,
"execution_time": self.execution_time,
"context": self.context
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'ToolExecution':
return cls(
timestamp=datetime.fromisoformat(data["timestamp"]),
tool=data["tool"],
parameters=data["parameters"],
success=data["success"],
error_message=data.get("error_message"),
execution_time=data.get("execution_time", 0.0),
context=data.get("context", {})
)
@dataclass
class Pattern:
"""Learned pattern with confidence scoring"""
pattern_id: str
pattern_type: str # "command_failure", "tool_sequence", "context_error"
trigger: Dict[str, Any] # What triggers this pattern
prediction: Dict[str, Any] # What we predict will happen
confidence: float # 0.0 to 1.0
evidence_count: int # How many times we've seen this
last_seen: datetime
success_rate: float = 0.0
def to_dict(self) -> Dict[str, Any]:
return {
"pattern_id": self.pattern_id,
"pattern_type": self.pattern_type,
"trigger": self.trigger,
"prediction": self.prediction,
"confidence": self.confidence,
"evidence_count": self.evidence_count,
"last_seen": self.last_seen.isoformat(),
"success_rate": self.success_rate
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Pattern':
return cls(
pattern_id=data["pattern_id"],
pattern_type=data["pattern_type"],
trigger=data["trigger"],
prediction=data["prediction"],
confidence=data["confidence"],
evidence_count=data["evidence_count"],
last_seen=datetime.fromisoformat(data["last_seen"]),
success_rate=data.get("success_rate", 0.0)
)
@dataclass
class HookResult:
"""Result of hook execution"""
allow: bool
message: str = ""
warning: bool = False
metadata: Dict[str, Any] = field(default_factory=dict)
@classmethod
def success(cls, message: str = "Operation allowed") -> 'HookResult':
return cls(allow=True, message=message)
@classmethod
def blocked(cls, reason: str) -> 'HookResult':
return cls(allow=False, message=reason)
@classmethod
def allow_with_warning(cls, warning: str) -> 'HookResult':
return cls(allow=True, message=warning, warning=True)
def to_claude_response(self) -> Dict[str, Any]:
"""Convert to Claude Code hook response format"""
response = {
"allow": self.allow,
"message": self.message
}
if self.metadata:
response.update(self.metadata)
return response
@dataclass
class ValidationResult:
"""Result of validation operations"""
allowed: bool
reason: str = ""
severity: str = "info" # info, warning, medium, high, critical
suggestions: List[str] = field(default_factory=list)
@property
def is_critical(self) -> bool:
return self.severity == "critical"
@property
def is_blocking(self) -> bool:
return not self.allowed
@dataclass
class BackupDecision:
"""Decision about whether to trigger backup"""
should_backup: bool
reason: str
urgency: str = "medium" # low, medium, high
metadata: Dict[str, Any] = field(default_factory=dict)
@dataclass
class BackupResult:
"""Result of backup operation"""
success: bool
backup_id: str = ""
backup_path: str = ""
error: str = ""
git_success: bool = False
fallback_performed: bool = False
components: Dict[str, Any] = field(default_factory=dict)
@dataclass
class GitBackupResult:
"""Result of git backup operation"""
success: bool
commit_id: str = ""
message: str = ""
error: str = ""
class PatternDatabase:
"""Fast lookup database for learned patterns"""
def __init__(self):
self.command_patterns: Dict[str, Pattern] = {}
self.sequence_patterns: List[Pattern] = []
self.context_patterns: Dict[str, Pattern] = {}
self.execution_history: List[ToolExecution] = []
def to_dict(self) -> Dict[str, Any]:
return {
"command_patterns": {k: v.to_dict() for k, v in self.command_patterns.items()},
"sequence_patterns": [p.to_dict() for p in self.sequence_patterns],
"context_patterns": {k: v.to_dict() for k, v in self.context_patterns.items()},
"execution_history": [e.to_dict() for e in self.execution_history[-100:]] # Keep last 100
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'PatternDatabase':
db = cls()
# Load command patterns
for k, v in data.get("command_patterns", {}).items():
db.command_patterns[k] = Pattern.from_dict(v)
# Load sequence patterns
for p in data.get("sequence_patterns", []):
db.sequence_patterns.append(Pattern.from_dict(p))
# Load context patterns
for k, v in data.get("context_patterns", {}).items():
db.context_patterns[k] = Pattern.from_dict(v)
# Load execution history
for e in data.get("execution_history", []):
db.execution_history.append(ToolExecution.from_dict(e))
return db