Files
gh-comzine-claude-code-mark…/skills/meta-automation-architect/scripts/agent_reuse.py
2025-11-29 18:16:25 +08:00

303 lines
9.6 KiB
Python

#!/usr/bin/env python3
"""
Agent Reuse Manager
Avoids regenerating automation for similar projects
Reuses successful configurations
"""
import json
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Optional
from difflib import SequenceMatcher
class AgentReuseManager:
"""Manages reuse of automation configurations"""
def __init__(self, storage_path: str = ".claude/meta-automation/configurations"):
self.storage_dir = Path(storage_path)
self.storage_dir.mkdir(parents=True, exist_ok=True)
self.index_path = self.storage_dir / "index.json"
self.index = self._load_index()
def _load_index(self) -> Dict:
"""Load configuration index"""
if self.index_path.exists():
try:
with open(self.index_path, 'r') as f:
return json.load(f)
except:
return {'configurations': []}
return {'configurations': []}
def _save_index(self):
"""Save configuration index"""
with open(self.index_path, 'w') as f:
json.dump(self.index, f, indent=2)
def save_configuration(self, config: Dict) -> str:
"""
Save a successful automation configuration
Args:
config: {
'project_type': str,
'project_name': str,
'tech_stack': List[str],
'agents_used': List[str],
'skills_generated': List[str],
'commands_generated': List[str],
'hooks_generated': List[str],
'success_metrics': Dict,
'user_satisfaction': int (1-5)
}
Returns:
Configuration ID
"""
config_id = datetime.now().strftime("%Y%m%d_%H%M%S")
# Add metadata
config_with_meta = {
**config,
'config_id': config_id,
'created_at': datetime.now().isoformat(),
'reuse_count': 0
}
# Save full configuration
config_path = self.storage_dir / f"{config_id}.json"
with open(config_path, 'w') as f:
json.dump(config_with_meta, f, indent=2)
# Update index
self.index['configurations'].append({
'config_id': config_id,
'project_type': config['project_type'],
'project_name': config.get('project_name', 'unknown'),
'tech_stack': config.get('tech_stack', []),
'created_at': config_with_meta['created_at'],
'reuse_count': 0
})
self._save_index()
return config_id
def find_similar_configurations(self, project_info: Dict, min_similarity: float = 0.7) -> List[Dict]:
"""
Find similar configurations that could be reused
Args:
project_info: {
'project_type': str,
'tech_stack': List[str],
'existing_tools': List[str]
}
min_similarity: Minimum similarity score (0-1)
Returns:
List of similar configurations sorted by similarity
"""
similar = []
for config_ref in self.index['configurations']:
config = self._load_configuration(config_ref['config_id'])
if not config:
continue
similarity = self._calculate_similarity(project_info, config)
if similarity >= min_similarity:
similar.append({
**config_ref,
'similarity': round(similarity, 2),
'full_config': config
})
# Sort by similarity (descending)
similar.sort(key=lambda x: x['similarity'], reverse=True)
return similar
def _calculate_similarity(self, project_info: Dict, config: Dict) -> float:
"""
Calculate similarity between project and configuration
Returns:
Similarity score 0-1
"""
score = 0.0
weights = {
'project_type': 0.4,
'tech_stack': 0.4,
'size': 0.2
}
# Project type match
if project_info.get('project_type') == config.get('project_type'):
score += weights['project_type']
# Tech stack similarity
project_stack = set(project_info.get('tech_stack', []))
config_stack = set(config.get('tech_stack', []))
if project_stack and config_stack:
intersection = len(project_stack & config_stack)
union = len(project_stack | config_stack)
tech_similarity = intersection / union if union > 0 else 0
score += weights['tech_stack'] * tech_similarity
return min(score, 1.0)
def reuse_configuration(self, config_id: str) -> Dict:
"""
Reuse a configuration
Args:
config_id: ID of configuration to reuse
Returns:
Configuration to apply
"""
config = self._load_configuration(config_id)
if not config:
return None
# Increment reuse count
config['reuse_count'] += 1
self._save_configuration(config_id, config)
# Update index
for cfg in self.index['configurations']:
if cfg['config_id'] == config_id:
cfg['reuse_count'] += 1
self._save_index()
return config
def get_reuse_recommendation(self, project_info: Dict) -> Optional[Dict]:
"""
Get recommendation for reusing a configuration
Args:
project_info: Information about current project
Returns:
Recommendation or None if no good match
"""
similar = self.find_similar_configurations(project_info, min_similarity=0.75)
if not similar:
return None
best_match = similar[0]
return {
'recommended': True,
'config_id': best_match['config_id'],
'similarity': best_match['similarity'],
'project_name': best_match['project_name'],
'created_at': best_match['created_at'],
'reuse_count': best_match['reuse_count'],
'time_saved': '5-10 minutes (no need to regenerate)',
'agents': best_match['full_config']['agents_used'],
'skills': best_match['full_config']['skills_generated'],
'reason': f"This configuration was successful for a similar {best_match['project_type']} project"
}
def _load_configuration(self, config_id: str) -> Optional[Dict]:
"""Load a configuration file"""
config_path = self.storage_dir / f"{config_id}.json"
if not config_path.exists():
return None
try:
with open(config_path, 'r') as f:
return json.load(f)
except:
return None
def _save_configuration(self, config_id: str, config: Dict):
"""Save a configuration file"""
config_path = self.storage_dir / f"{config_id}.json"
with open(config_path, 'w') as f:
json.dump(config, f, indent=2)
def get_statistics(self) -> Dict:
"""Get reuse statistics"""
total_configs = len(self.index['configurations'])
total_reuses = sum(cfg['reuse_count'] for cfg in self.index['configurations'])
project_types = {}
for cfg in self.index['configurations']:
ptype = cfg['project_type']
if ptype not in project_types:
project_types[ptype] = 0
project_types[ptype] += 1
return {
'total_configurations': total_configs,
'total_reuses': total_reuses,
'average_reuses': round(total_reuses / total_configs, 1) if total_configs > 0 else 0,
'project_types': project_types,
'most_reused': sorted(
self.index['configurations'],
key=lambda x: x['reuse_count'],
reverse=True
)[:3]
}
# Example usage
if __name__ == '__main__':
manager = AgentReuseManager()
# Save a configuration
print("Saving successful configuration...")
config_id = manager.save_configuration({
'project_type': 'programming',
'project_name': 'my-web-app',
'tech_stack': ['TypeScript', 'React', 'Next.js'],
'agents_used': ['project-analyzer', 'security-analyzer', 'test-coverage-analyzer'],
'skills_generated': ['security-scanner', 'test-generator'],
'commands_generated': ['/security-check', '/generate-tests'],
'hooks_generated': ['pre-commit-security'],
'success_metrics': {
'time_saved': 50,
'issues_prevented': 3
},
'user_satisfaction': 5
})
print(f"Saved configuration: {config_id}\n")
# Find similar
print("Finding similar configurations for new project...")
similar = manager.find_similar_configurations({
'project_type': 'programming',
'tech_stack': ['TypeScript', 'React', 'Vite'], # Similar but not exact
'existing_tools': ['ESLint']
})
print(f"Found {len(similar)} similar configurations\n")
if similar:
print("Best match:")
print(json.dumps({
'config_id': similar[0]['config_id'],
'similarity': similar[0]['similarity'],
'project_name': similar[0]['project_name']
}, indent=2))
# Get recommendation
print("\nRecommendation:")
rec = manager.get_reuse_recommendation({
'project_type': 'programming',
'tech_stack': ['TypeScript', 'React', 'Vite']
})
print(json.dumps(rec, indent=2))
# Statistics
print("\nReuse Statistics:")
stats = manager.get_statistics()
print(json.dumps(stats, indent=2))