mirror of
https://github.com/SuperClaude-Org/SuperClaude_Framework.git
synced 2025-12-29 16:16:08 +00:00
Revolutionary transformation from hardcoded Python intelligence to hot-reloadable YAML patterns, enabling dynamic configuration without code changes. ## Phase 1: Foundation Intelligence Complete ### YAML Intelligence Patterns (6 files) - intelligence_patterns.yaml: Multi-dimensional pattern recognition with adaptive learning - mcp_orchestration.yaml: Server selection decision trees with load balancing - hook_coordination.yaml: Parallel execution patterns with dependency resolution - performance_intelligence.yaml: Resource zones and auto-optimization triggers - validation_intelligence.yaml: Health scoring and proactive diagnostic patterns - user_experience.yaml: Project detection and smart UX adaptations ### Python Infrastructure Enhanced (4 components) - intelligence_engine.py: Generic YAML pattern interpreter with hot-reload - learning_engine.py: Enhanced with YAML intelligence integration - yaml_loader.py: Added intelligence configuration helper methods - validate_system.py: New YAML-driven validation with health scoring ### Key Features Implemented - Hot-reload intelligence: Update patterns without code changes or restarts - Declarative configuration: All intelligence logic expressed in YAML - Graceful fallbacks: System works correctly even with missing YAML files - Multi-pattern coordination: Intelligent recommendations from multiple sources - Health scoring: Component-weighted validation with predictive diagnostics - Generic architecture: Single engine consumes all intelligence pattern types ### Testing Results ✅ All components integrate correctly ✅ Hot-reload mechanism functional ✅ Graceful error handling verified ✅ YAML-driven validation operational ✅ Health scoring system working (detected real system issues) This enables users to modify intelligence behavior by editing YAML files, add new pattern types without coding, and hot-reload improvements in real-time. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
794 lines
34 KiB
Python
794 lines
34 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
SuperClaude-Lite Post-Tool-Use Hook
|
|
|
|
Implements RULES.md + PRINCIPLES.md validation and learning system.
|
|
Performance target: <100ms execution time.
|
|
|
|
This hook runs after every tool usage and provides:
|
|
- Quality validation against SuperClaude principles
|
|
- Effectiveness measurement and learning
|
|
- Error pattern detection and prevention
|
|
- Performance optimization feedback
|
|
- Adaptation and improvement recommendations
|
|
"""
|
|
|
|
import sys
|
|
import json
|
|
import time
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Dict, Any, List, Optional, Tuple
|
|
|
|
# Add shared modules to path
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "shared"))
|
|
|
|
from framework_logic import FrameworkLogic, ValidationResult, OperationContext, OperationType, RiskLevel
|
|
from pattern_detection import PatternDetector
|
|
from mcp_intelligence import MCPIntelligence
|
|
from compression_engine import CompressionEngine
|
|
from learning_engine import LearningEngine, LearningType, AdaptationScope
|
|
from yaml_loader import config_loader
|
|
from logger import log_hook_start, log_hook_end, log_decision, log_error
|
|
|
|
|
|
class PostToolUseHook:
|
|
"""
|
|
Post-tool-use hook implementing SuperClaude validation and learning.
|
|
|
|
Responsibilities:
|
|
- Validate tool execution against RULES.md and PRINCIPLES.md
|
|
- Measure operation effectiveness and quality
|
|
- Learn from successful and failed patterns
|
|
- Detect error patterns and suggest improvements
|
|
- Record performance metrics for optimization
|
|
- Generate adaptation recommendations
|
|
"""
|
|
|
|
def __init__(self):
|
|
start_time = time.time()
|
|
|
|
# Initialize core components
|
|
self.framework_logic = FrameworkLogic()
|
|
self.pattern_detector = PatternDetector()
|
|
self.mcp_intelligence = MCPIntelligence()
|
|
self.compression_engine = CompressionEngine()
|
|
|
|
# Initialize learning engine with installation directory cache
|
|
import os
|
|
cache_dir = Path(os.path.expanduser("~/.claude/cache"))
|
|
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
self.learning_engine = LearningEngine(cache_dir)
|
|
|
|
# Load hook-specific configuration from SuperClaude config
|
|
self.hook_config = config_loader.get_hook_config('post_tool_use')
|
|
|
|
# Load validation configuration (from YAML if exists, otherwise use hook config)
|
|
try:
|
|
self.validation_config = config_loader.load_config('validation')
|
|
except FileNotFoundError:
|
|
# Fall back to hook configuration if YAML file not found
|
|
self.validation_config = self.hook_config.get('configuration', {})
|
|
|
|
# Load quality standards (from YAML if exists, otherwise use hook config)
|
|
try:
|
|
self.quality_standards = config_loader.load_config('performance')
|
|
except FileNotFoundError:
|
|
# Fall back to performance targets from global configuration
|
|
self.quality_standards = config_loader.get_performance_targets()
|
|
|
|
# Performance tracking using configuration
|
|
self.initialization_time = (time.time() - start_time) * 1000
|
|
self.performance_target_ms = config_loader.get_hook_config('post_tool_use', 'performance_target_ms', 100)
|
|
|
|
def process_tool_result(self, tool_result: dict) -> dict:
|
|
"""
|
|
Process tool execution result with validation and learning.
|
|
|
|
Args:
|
|
tool_result: Tool execution result from Claude Code
|
|
|
|
Returns:
|
|
Enhanced result with SuperClaude validation and insights
|
|
"""
|
|
start_time = time.time()
|
|
|
|
# Log hook start
|
|
log_hook_start("post_tool_use", {
|
|
"tool_name": tool_result.get('tool_name', 'unknown'),
|
|
"success": tool_result.get('success', False),
|
|
"has_error": bool(tool_result.get('error'))
|
|
})
|
|
|
|
try:
|
|
# Extract execution context
|
|
context = self._extract_execution_context(tool_result)
|
|
|
|
# Validate against SuperClaude principles
|
|
validation_result = self._validate_tool_result(context)
|
|
|
|
# Log validation decision
|
|
if not validation_result.is_valid:
|
|
log_decision(
|
|
"post_tool_use",
|
|
"validation_failure",
|
|
validation_result.failed_checks[0] if validation_result.failed_checks else "unknown",
|
|
f"Tool '{context['tool_name']}' failed validation: {validation_result.message}"
|
|
)
|
|
|
|
# Measure effectiveness and quality
|
|
effectiveness_metrics = self._measure_effectiveness(context, validation_result)
|
|
|
|
# Detect patterns and learning opportunities
|
|
learning_analysis = self._analyze_learning_opportunities(context, effectiveness_metrics)
|
|
|
|
# Record learning events
|
|
self._record_learning_events(context, effectiveness_metrics, learning_analysis)
|
|
|
|
# Generate recommendations
|
|
recommendations = self._generate_recommendations(context, validation_result, learning_analysis)
|
|
|
|
# Create validation report
|
|
validation_report = self._create_validation_report(
|
|
context, validation_result, effectiveness_metrics,
|
|
learning_analysis, recommendations
|
|
)
|
|
|
|
# Detect patterns in tool execution
|
|
pattern_analysis = self._analyze_execution_patterns(context, validation_result)
|
|
|
|
# Log pattern detection
|
|
if pattern_analysis.get('error_pattern_detected'):
|
|
log_decision(
|
|
"post_tool_use",
|
|
"error_pattern_detected",
|
|
pattern_analysis.get('pattern_type', 'unknown'),
|
|
pattern_analysis.get('description', 'Error pattern identified')
|
|
)
|
|
|
|
# Performance tracking
|
|
execution_time = (time.time() - start_time) * 1000
|
|
validation_report['performance_metrics'] = {
|
|
'processing_time_ms': execution_time,
|
|
'target_met': execution_time < self.performance_target_ms,
|
|
'quality_score': self._calculate_quality_score(context, validation_result)
|
|
}
|
|
|
|
# Log successful completion
|
|
log_hook_end(
|
|
"post_tool_use",
|
|
int(execution_time),
|
|
True,
|
|
{
|
|
"tool_name": context['tool_name'],
|
|
"validation_passed": validation_result.is_valid,
|
|
"quality_score": validation_report['performance_metrics']['quality_score']
|
|
}
|
|
)
|
|
|
|
return validation_report
|
|
|
|
except Exception as e:
|
|
# Log error
|
|
execution_time = (time.time() - start_time) * 1000
|
|
log_error(
|
|
"post_tool_use",
|
|
str(e),
|
|
{"tool_name": tool_result.get('tool_name', 'unknown')}
|
|
)
|
|
log_hook_end("post_tool_use", int(execution_time), False)
|
|
|
|
# Graceful fallback on error
|
|
return self._create_fallback_result(tool_result, str(e))
|
|
|
|
def _extract_execution_context(self, tool_result: dict) -> dict:
|
|
"""Extract and enrich tool execution context."""
|
|
context = {
|
|
'tool_name': tool_result.get('tool_name', ''),
|
|
'execution_status': tool_result.get('status', 'unknown'),
|
|
'execution_time_ms': tool_result.get('execution_time_ms', 0),
|
|
'parameters_used': tool_result.get('parameters', {}),
|
|
'result_data': tool_result.get('result', {}),
|
|
'error_info': tool_result.get('error', {}),
|
|
'mcp_servers_used': tool_result.get('mcp_servers', []),
|
|
'performance_data': tool_result.get('performance', {}),
|
|
'user_intent': tool_result.get('user_intent', ''),
|
|
'session_context': tool_result.get('session_context', {}),
|
|
'timestamp': time.time()
|
|
}
|
|
|
|
# Analyze operation characteristics
|
|
context.update(self._analyze_operation_outcome(context))
|
|
|
|
# Extract quality indicators
|
|
context.update(self._extract_quality_indicators(context))
|
|
|
|
return context
|
|
|
|
def _analyze_operation_outcome(self, context: dict) -> dict:
|
|
"""Analyze the outcome of the tool operation."""
|
|
outcome_analysis = {
|
|
'success': context['execution_status'] == 'success',
|
|
'partial_success': False,
|
|
'error_occurred': context['execution_status'] == 'error',
|
|
'performance_acceptable': True,
|
|
'quality_indicators': [],
|
|
'risk_factors': []
|
|
}
|
|
|
|
# Analyze execution status
|
|
if context['execution_status'] in ['partial', 'warning']:
|
|
outcome_analysis['partial_success'] = True
|
|
|
|
# Performance analysis
|
|
execution_time = context.get('execution_time_ms', 0)
|
|
if execution_time > 5000: # 5 second threshold
|
|
outcome_analysis['performance_acceptable'] = False
|
|
outcome_analysis['risk_factors'].append('slow_execution')
|
|
|
|
# Error analysis
|
|
if context.get('error_info'):
|
|
error_type = context['error_info'].get('type', 'unknown')
|
|
outcome_analysis['error_type'] = error_type
|
|
outcome_analysis['error_recoverable'] = error_type not in ['fatal', 'security', 'corruption']
|
|
|
|
# Quality indicators from result data
|
|
result_data = context.get('result_data', {})
|
|
if result_data:
|
|
if result_data.get('validation_passed'):
|
|
outcome_analysis['quality_indicators'].append('validation_passed')
|
|
if result_data.get('tests_passed'):
|
|
outcome_analysis['quality_indicators'].append('tests_passed')
|
|
if result_data.get('linting_clean'):
|
|
outcome_analysis['quality_indicators'].append('linting_clean')
|
|
|
|
return outcome_analysis
|
|
|
|
def _extract_quality_indicators(self, context: dict) -> dict:
|
|
"""Extract quality indicators from execution context."""
|
|
quality_indicators = {
|
|
'code_quality_score': 0.0,
|
|
'security_compliance': True,
|
|
'performance_efficiency': 1.0,
|
|
'error_handling_present': False,
|
|
'documentation_adequate': False,
|
|
'test_coverage_acceptable': False
|
|
}
|
|
|
|
# Analyze tool output for quality indicators
|
|
tool_name = context['tool_name']
|
|
result_data = context.get('result_data', {})
|
|
|
|
# Code quality analysis
|
|
if tool_name in ['Write', 'Edit', 'Generate']:
|
|
# Check for quality indicators in the result
|
|
if 'quality_score' in result_data:
|
|
quality_indicators['code_quality_score'] = result_data['quality_score']
|
|
|
|
# Infer quality from operation success and performance
|
|
if context.get('success') and context.get('performance_acceptable'):
|
|
quality_indicators['code_quality_score'] = max(
|
|
quality_indicators['code_quality_score'], 0.7
|
|
)
|
|
|
|
# Security compliance
|
|
if context.get('error_type') in ['security', 'vulnerability']:
|
|
quality_indicators['security_compliance'] = False
|
|
|
|
# Performance efficiency
|
|
execution_time = context.get('execution_time_ms', 0)
|
|
expected_time = context.get('performance_data', {}).get('expected_time_ms', 1000)
|
|
if execution_time > 0 and expected_time > 0:
|
|
quality_indicators['performance_efficiency'] = min(expected_time / execution_time, 2.0)
|
|
|
|
# Error handling detection
|
|
if tool_name in ['Write', 'Edit'] and 'try' in str(result_data).lower():
|
|
quality_indicators['error_handling_present'] = True
|
|
|
|
# Documentation assessment
|
|
if tool_name in ['Document', 'Generate'] or 'doc' in context.get('user_intent', '').lower():
|
|
quality_indicators['documentation_adequate'] = context.get('success', False)
|
|
|
|
return quality_indicators
|
|
|
|
def _validate_tool_result(self, context: dict) -> ValidationResult:
|
|
"""Validate execution against SuperClaude principles."""
|
|
# Create operation data for validation
|
|
operation_data = {
|
|
'operation_type': context['tool_name'],
|
|
'has_error_handling': context.get('error_handling_present', False),
|
|
'affects_logic': context['tool_name'] in ['Write', 'Edit', 'Generate'],
|
|
'has_tests': context.get('test_coverage_acceptable', False),
|
|
'is_public_api': 'api' in context.get('user_intent', '').lower(),
|
|
'has_documentation': context.get('documentation_adequate', False),
|
|
'handles_user_input': 'input' in context.get('user_intent', '').lower(),
|
|
'has_input_validation': context.get('security_compliance', True),
|
|
'evidence': context.get('success', False)
|
|
}
|
|
|
|
# Run framework validation
|
|
validation_result = self.framework_logic.validate_operation(operation_data)
|
|
|
|
# Enhance with SuperClaude-specific validations
|
|
validation_result = self._enhance_validation_with_superclaude_rules(
|
|
validation_result, context
|
|
)
|
|
|
|
return validation_result
|
|
|
|
def _enhance_validation_with_superclaude_rules(self,
|
|
base_validation: ValidationResult,
|
|
context: dict) -> ValidationResult:
|
|
"""Enhance validation with SuperClaude-specific rules."""
|
|
enhanced_validation = ValidationResult(
|
|
is_valid=base_validation.is_valid,
|
|
issues=base_validation.issues.copy(),
|
|
warnings=base_validation.warnings.copy(),
|
|
suggestions=base_validation.suggestions.copy(),
|
|
quality_score=base_validation.quality_score
|
|
)
|
|
|
|
# RULES.md validation
|
|
|
|
# Rule: Always use Read tool before Write or Edit operations
|
|
if context['tool_name'] in ['Write', 'Edit']:
|
|
session_context = context.get('session_context', {})
|
|
recent_tools = session_context.get('recent_tools', [])
|
|
if not any('Read' in tool for tool in recent_tools[-3:]):
|
|
enhanced_validation.warnings.append(
|
|
"RULES violation: No Read operation detected before Write/Edit"
|
|
)
|
|
enhanced_validation.quality_score -= 0.1
|
|
|
|
# Rule: Use absolute paths only
|
|
params = context.get('parameters_used', {})
|
|
for param_name, param_value in params.items():
|
|
if 'path' in param_name.lower() and isinstance(param_value, str):
|
|
if not os.path.isabs(param_value) and not param_value.startswith(('http', 'https')):
|
|
enhanced_validation.issues.append(
|
|
f"RULES violation: Relative path used in {param_name}: {param_value}"
|
|
)
|
|
enhanced_validation.quality_score -= 0.2
|
|
|
|
# Rule: Validate before execution for high-risk operations
|
|
if context.get('risk_factors'):
|
|
if not context.get('validation_performed', False):
|
|
enhanced_validation.warnings.append(
|
|
"RULES recommendation: High-risk operation should include validation"
|
|
)
|
|
|
|
# PRINCIPLES.md validation
|
|
|
|
# Principle: Evidence > assumptions
|
|
if not context.get('evidence_provided', False) and context.get('assumptions_made', False):
|
|
enhanced_validation.suggestions.append(
|
|
"PRINCIPLES: Provide evidence to support assumptions"
|
|
)
|
|
|
|
# Principle: Code > documentation
|
|
if context['tool_name'] == 'Document' and not context.get('working_code_exists', True):
|
|
enhanced_validation.warnings.append(
|
|
"PRINCIPLES: Documentation should follow working code, not precede it"
|
|
)
|
|
|
|
# Principle: Efficiency > verbosity
|
|
result_size = len(str(context.get('result_data', '')))
|
|
if result_size > 5000 and not context.get('complexity_justifies_length', False):
|
|
enhanced_validation.suggestions.append(
|
|
"PRINCIPLES: Consider token efficiency techniques for large outputs"
|
|
)
|
|
|
|
# Recalculate overall validity
|
|
enhanced_validation.is_valid = (
|
|
len(enhanced_validation.issues) == 0 and
|
|
enhanced_validation.quality_score >= 0.7
|
|
)
|
|
|
|
return enhanced_validation
|
|
|
|
def _measure_effectiveness(self, context: dict, validation_result: ValidationResult) -> dict:
|
|
"""Measure operation effectiveness and quality."""
|
|
effectiveness_metrics = {
|
|
'overall_effectiveness': 0.0,
|
|
'quality_score': validation_result.quality_score,
|
|
'performance_score': 0.0,
|
|
'user_satisfaction_estimate': 0.0,
|
|
'learning_value': 0.0,
|
|
'improvement_potential': 0.0
|
|
}
|
|
|
|
# Performance scoring
|
|
execution_time = context.get('execution_time_ms', 0)
|
|
expected_time = context.get('performance_data', {}).get('expected_time_ms', 1000)
|
|
if execution_time > 0:
|
|
time_ratio = expected_time / max(execution_time, 1)
|
|
effectiveness_metrics['performance_score'] = min(time_ratio, 1.0)
|
|
else:
|
|
effectiveness_metrics['performance_score'] = 1.0
|
|
|
|
# User satisfaction estimation
|
|
if context.get('success'):
|
|
base_satisfaction = 0.8
|
|
if validation_result.quality_score > 0.8:
|
|
base_satisfaction += 0.15
|
|
if effectiveness_metrics['performance_score'] > 0.8:
|
|
base_satisfaction += 0.05
|
|
effectiveness_metrics['user_satisfaction_estimate'] = min(base_satisfaction, 1.0)
|
|
else:
|
|
# Reduce satisfaction based on error severity
|
|
error_severity = self._assess_error_severity(context)
|
|
effectiveness_metrics['user_satisfaction_estimate'] = max(0.3 - error_severity * 0.3, 0.0)
|
|
|
|
# Learning value assessment
|
|
if context.get('mcp_servers_used'):
|
|
effectiveness_metrics['learning_value'] += 0.2 # MCP usage provides learning
|
|
if context.get('error_occurred'):
|
|
effectiveness_metrics['learning_value'] += 0.3 # Errors provide valuable learning
|
|
if context.get('complexity_score', 0) > 0.6:
|
|
effectiveness_metrics['learning_value'] += 0.2 # Complex operations provide insights
|
|
|
|
effectiveness_metrics['learning_value'] = min(effectiveness_metrics['learning_value'], 1.0)
|
|
|
|
# Improvement potential
|
|
if len(validation_result.suggestions) > 0:
|
|
effectiveness_metrics['improvement_potential'] = min(len(validation_result.suggestions) * 0.2, 1.0)
|
|
|
|
# Overall effectiveness calculation
|
|
weights = {
|
|
'quality': 0.3,
|
|
'performance': 0.25,
|
|
'satisfaction': 0.35,
|
|
'learning': 0.1
|
|
}
|
|
|
|
effectiveness_metrics['overall_effectiveness'] = (
|
|
effectiveness_metrics['quality_score'] * weights['quality'] +
|
|
effectiveness_metrics['performance_score'] * weights['performance'] +
|
|
effectiveness_metrics['user_satisfaction_estimate'] * weights['satisfaction'] +
|
|
effectiveness_metrics['learning_value'] * weights['learning']
|
|
)
|
|
|
|
return effectiveness_metrics
|
|
|
|
def _assess_error_severity(self, context: dict) -> float:
|
|
"""Assess error severity on a scale of 0.0 to 1.0."""
|
|
if not context.get('error_occurred'):
|
|
return 0.0
|
|
|
|
error_type = context.get('error_type', 'unknown')
|
|
|
|
severity_map = {
|
|
'fatal': 1.0,
|
|
'security': 0.9,
|
|
'corruption': 0.8,
|
|
'timeout': 0.6,
|
|
'validation': 0.4,
|
|
'warning': 0.2,
|
|
'unknown': 0.5
|
|
}
|
|
|
|
return severity_map.get(error_type, 0.5)
|
|
|
|
def _analyze_learning_opportunities(self, context: dict, effectiveness_metrics: dict) -> dict:
|
|
"""Analyze learning opportunities from the execution."""
|
|
learning_analysis = {
|
|
'patterns_detected': [],
|
|
'success_factors': [],
|
|
'failure_factors': [],
|
|
'optimization_opportunities': [],
|
|
'adaptation_recommendations': []
|
|
}
|
|
|
|
# Pattern detection
|
|
if context.get('mcp_servers_used'):
|
|
for server in context['mcp_servers_used']:
|
|
if effectiveness_metrics['overall_effectiveness'] > 0.8:
|
|
learning_analysis['patterns_detected'].append(f"effective_{server}_usage")
|
|
elif effectiveness_metrics['overall_effectiveness'] < 0.5:
|
|
learning_analysis['patterns_detected'].append(f"ineffective_{server}_usage")
|
|
|
|
# Success factor analysis
|
|
if effectiveness_metrics['overall_effectiveness'] > 0.8:
|
|
if effectiveness_metrics['performance_score'] > 0.8:
|
|
learning_analysis['success_factors'].append('optimal_performance')
|
|
if effectiveness_metrics['quality_score'] > 0.8:
|
|
learning_analysis['success_factors'].append('high_quality_output')
|
|
if context.get('mcp_servers_used'):
|
|
learning_analysis['success_factors'].append('effective_mcp_coordination')
|
|
|
|
# Failure factor analysis
|
|
if effectiveness_metrics['overall_effectiveness'] < 0.5:
|
|
if effectiveness_metrics['performance_score'] < 0.5:
|
|
learning_analysis['failure_factors'].append('poor_performance')
|
|
if effectiveness_metrics['quality_score'] < 0.5:
|
|
learning_analysis['failure_factors'].append('quality_issues')
|
|
if context.get('error_occurred'):
|
|
learning_analysis['failure_factors'].append(f"error_{context.get('error_type', 'unknown')}")
|
|
|
|
# Optimization opportunities
|
|
if effectiveness_metrics['improvement_potential'] > 0.3:
|
|
learning_analysis['optimization_opportunities'].append('validation_improvements_available')
|
|
|
|
if context.get('execution_time_ms', 0) > 2000:
|
|
learning_analysis['optimization_opportunities'].append('performance_optimization_needed')
|
|
|
|
# Adaptation recommendations
|
|
if len(learning_analysis['success_factors']) > 0:
|
|
learning_analysis['adaptation_recommendations'].append(
|
|
f"Reinforce patterns: {', '.join(learning_analysis['success_factors'])}"
|
|
)
|
|
|
|
if len(learning_analysis['failure_factors']) > 0:
|
|
learning_analysis['adaptation_recommendations'].append(
|
|
f"Address failure patterns: {', '.join(learning_analysis['failure_factors'])}"
|
|
)
|
|
|
|
return learning_analysis
|
|
|
|
def _record_learning_events(self, context: dict, effectiveness_metrics: dict, learning_analysis: dict):
|
|
"""Record learning events for future adaptation."""
|
|
overall_effectiveness = effectiveness_metrics['overall_effectiveness']
|
|
|
|
# Record general operation learning
|
|
self.learning_engine.record_learning_event(
|
|
LearningType.OPERATION_PATTERN,
|
|
AdaptationScope.USER,
|
|
context,
|
|
{
|
|
'tool_name': context['tool_name'],
|
|
'mcp_servers': context.get('mcp_servers_used', []),
|
|
'success_factors': learning_analysis['success_factors'],
|
|
'failure_factors': learning_analysis['failure_factors']
|
|
},
|
|
overall_effectiveness,
|
|
0.8, # High confidence in post-execution analysis
|
|
{'hook': 'post_tool_use', 'effectiveness': overall_effectiveness}
|
|
)
|
|
|
|
# Track tool preference if execution was successful
|
|
if context.get('success') and overall_effectiveness > 0.7:
|
|
operation_type = self._categorize_operation(context['tool_name'])
|
|
if operation_type:
|
|
self.learning_engine.update_last_preference(
|
|
f"tool_{operation_type}",
|
|
context['tool_name']
|
|
)
|
|
|
|
# Record MCP server effectiveness
|
|
for server in context.get('mcp_servers_used', []):
|
|
self.learning_engine.record_learning_event(
|
|
LearningType.EFFECTIVENESS_FEEDBACK,
|
|
AdaptationScope.USER,
|
|
context,
|
|
{'mcp_server': server},
|
|
overall_effectiveness,
|
|
0.9, # Very high confidence in direct feedback
|
|
{'server_performance': effectiveness_metrics['performance_score']}
|
|
)
|
|
|
|
# Record error patterns if applicable
|
|
if context.get('error_occurred'):
|
|
self.learning_engine.record_learning_event(
|
|
LearningType.ERROR_RECOVERY,
|
|
AdaptationScope.PROJECT,
|
|
context,
|
|
{
|
|
'error_type': context.get('error_type'),
|
|
'recovery_successful': context.get('error_recoverable', False),
|
|
'context_factors': learning_analysis['failure_factors']
|
|
},
|
|
1.0 - self._assess_error_severity(context), # Inverse of severity
|
|
1.0, # Full confidence in error data
|
|
{'error_learning': True}
|
|
)
|
|
|
|
def _generate_recommendations(self, context: dict, validation_result: ValidationResult,
|
|
learning_analysis: dict) -> dict:
|
|
"""Generate recommendations for improvement."""
|
|
recommendations = {
|
|
'immediate_actions': [],
|
|
'optimization_suggestions': [],
|
|
'learning_adaptations': [],
|
|
'prevention_measures': []
|
|
}
|
|
|
|
# Immediate actions from validation issues
|
|
for issue in validation_result.issues:
|
|
recommendations['immediate_actions'].append(f"Fix: {issue}")
|
|
|
|
for warning in validation_result.warnings:
|
|
recommendations['immediate_actions'].append(f"Address: {warning}")
|
|
|
|
# Optimization suggestions
|
|
for suggestion in validation_result.suggestions:
|
|
recommendations['optimization_suggestions'].append(suggestion)
|
|
|
|
for opportunity in learning_analysis['optimization_opportunities']:
|
|
recommendations['optimization_suggestions'].append(f"Optimize: {opportunity}")
|
|
|
|
# Learning adaptations
|
|
for adaptation in learning_analysis['adaptation_recommendations']:
|
|
recommendations['learning_adaptations'].append(adaptation)
|
|
|
|
# Prevention measures for errors
|
|
if context.get('error_occurred'):
|
|
error_type = context.get('error_type', 'unknown')
|
|
if error_type == 'timeout':
|
|
recommendations['prevention_measures'].append("Consider parallel execution for large operations")
|
|
elif error_type == 'validation':
|
|
recommendations['prevention_measures'].append("Enable pre-validation for similar operations")
|
|
elif error_type == 'security':
|
|
recommendations['prevention_measures'].append("Implement security validation checks")
|
|
|
|
return recommendations
|
|
|
|
def _calculate_quality_score(self, context: dict, validation_result: ValidationResult) -> float:
|
|
"""Calculate quality score based on validation and execution."""
|
|
base_score = validation_result.quality_score
|
|
|
|
# Adjust for execution time
|
|
execution_time = context.get('execution_time_ms', 0)
|
|
time_ratio = execution_time / max(self.performance_target_ms, 1)
|
|
time_penalty = min(time_ratio, 1.0)
|
|
|
|
# Initialize error penalty (no penalty when no error occurs)
|
|
error_penalty = 1.0
|
|
|
|
# Adjust for error occurrence
|
|
if context.get('error_occurred'):
|
|
error_severity = self._assess_error_severity(context)
|
|
error_penalty = 1.0 - error_severity
|
|
|
|
# Combine adjustments
|
|
quality_score = base_score * time_penalty * error_penalty
|
|
|
|
return quality_score
|
|
|
|
def _create_validation_report(self, context: dict, validation_result: ValidationResult,
|
|
effectiveness_metrics: dict, learning_analysis: dict,
|
|
recommendations: dict) -> dict:
|
|
"""Create comprehensive validation report."""
|
|
return {
|
|
'tool_name': context['tool_name'],
|
|
'execution_status': context['execution_status'],
|
|
'timestamp': context['timestamp'],
|
|
|
|
'validation': {
|
|
'is_valid': validation_result.is_valid,
|
|
'quality_score': validation_result.quality_score,
|
|
'issues': validation_result.issues,
|
|
'warnings': validation_result.warnings,
|
|
'suggestions': validation_result.suggestions
|
|
},
|
|
|
|
'effectiveness': effectiveness_metrics,
|
|
|
|
'learning': {
|
|
'patterns_detected': learning_analysis['patterns_detected'],
|
|
'success_factors': learning_analysis['success_factors'],
|
|
'failure_factors': learning_analysis['failure_factors'],
|
|
'learning_value': effectiveness_metrics['learning_value']
|
|
},
|
|
|
|
'recommendations': recommendations,
|
|
|
|
'compliance': {
|
|
'rules_compliance': len([i for i in validation_result.issues if 'RULES' in i]) == 0,
|
|
'principles_alignment': len([w for w in validation_result.warnings if 'PRINCIPLES' in w]) == 0,
|
|
'superclaude_score': self._calculate_superclaude_compliance_score(validation_result)
|
|
},
|
|
|
|
'metadata': {
|
|
'hook_version': 'post_tool_use_1.0',
|
|
'validation_timestamp': time.time(),
|
|
'learning_events_recorded': len(learning_analysis['patterns_detected']) + 1
|
|
}
|
|
}
|
|
|
|
def _calculate_superclaude_compliance_score(self, validation_result: ValidationResult) -> float:
|
|
"""Calculate overall SuperClaude compliance score."""
|
|
base_score = validation_result.quality_score
|
|
|
|
# Penalties for specific violations
|
|
rules_violations = len([i for i in validation_result.issues if 'RULES' in i])
|
|
principles_violations = len([w for w in validation_result.warnings if 'PRINCIPLES' in w])
|
|
|
|
penalty = (rules_violations * 0.2) + (principles_violations * 0.1)
|
|
|
|
return max(base_score - penalty, 0.0)
|
|
|
|
def _create_fallback_result(self, tool_result: dict, error: str) -> dict:
|
|
"""Create fallback validation report on error."""
|
|
return {
|
|
'tool_name': tool_result.get('tool_name', 'unknown'),
|
|
'execution_status': 'validation_error',
|
|
'timestamp': time.time(),
|
|
'error': error,
|
|
'fallback_mode': True,
|
|
|
|
'validation': {
|
|
'is_valid': False,
|
|
'quality_score': 0.0,
|
|
'issues': [f"Validation hook error: {error}"],
|
|
'warnings': [],
|
|
'suggestions': ['Fix validation hook error']
|
|
},
|
|
|
|
'effectiveness': {
|
|
'overall_effectiveness': 0.0,
|
|
'quality_score': 0.0,
|
|
'performance_score': 0.0,
|
|
'user_satisfaction_estimate': 0.0,
|
|
'learning_value': 0.0
|
|
},
|
|
|
|
'performance_metrics': {
|
|
'processing_time_ms': 0,
|
|
'target_met': False,
|
|
'error_occurred': True
|
|
}
|
|
}
|
|
|
|
def _analyze_execution_patterns(self, context: dict, validation_result: ValidationResult) -> dict:
|
|
"""Analyze patterns in tool execution."""
|
|
pattern_analysis = {
|
|
'error_pattern_detected': False,
|
|
'pattern_type': 'unknown',
|
|
'description': 'No error pattern detected'
|
|
}
|
|
|
|
# Check for error occurrence
|
|
if context.get('error_occurred'):
|
|
error_type = context.get('error_type', 'unknown')
|
|
|
|
# Check for specific error types
|
|
if error_type in ['fatal', 'security', 'corruption']:
|
|
pattern_analysis['error_pattern_detected'] = True
|
|
pattern_analysis['pattern_type'] = error_type
|
|
pattern_analysis['description'] = f"Error pattern detected: {error_type}"
|
|
|
|
return pattern_analysis
|
|
|
|
def _categorize_operation(self, tool_name: str) -> Optional[str]:
|
|
"""Categorize tool into operation type for preference tracking."""
|
|
operation_map = {
|
|
'read': ['Read', 'Get', 'List', 'Search', 'Find'],
|
|
'write': ['Write', 'Create', 'Generate'],
|
|
'edit': ['Edit', 'Update', 'Modify', 'Replace'],
|
|
'analyze': ['Analyze', 'Validate', 'Check', 'Test'],
|
|
'mcp': ['Context7', 'Sequential', 'Magic', 'Playwright', 'Morphllm', 'Serena']
|
|
}
|
|
|
|
for operation_type, tools in operation_map.items():
|
|
if any(tool in tool_name for tool in tools):
|
|
return operation_type
|
|
|
|
return None
|
|
|
|
|
|
def main():
|
|
"""Main hook execution function."""
|
|
try:
|
|
# Read tool result from stdin
|
|
tool_result = json.loads(sys.stdin.read())
|
|
|
|
# Initialize and run hook
|
|
hook = PostToolUseHook()
|
|
result = hook.process_tool_result(tool_result)
|
|
|
|
# Output result as JSON
|
|
print(json.dumps(result, indent=2))
|
|
|
|
except Exception as e:
|
|
# Output error as JSON
|
|
error_result = {
|
|
'validation_error': True,
|
|
'error': str(e),
|
|
'fallback_mode': True
|
|
}
|
|
print(json.dumps(error_result, indent=2))
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |