claude-hooks/lib/cli.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

202 lines
6.4 KiB
Python

#!/usr/bin/env python3
"""
Claude Hooks CLI - Command line interface for managing hooks
"""
import argparse
import json
import sys
from datetime import datetime
from pathlib import Path
from .backup_manager import BackupManager
from .session_state import SessionStateManager
from .shadow_learner import ShadowLearner
from .context_monitor import ContextMonitor
def list_backups():
"""List available backups"""
backup_manager = BackupManager()
backups = backup_manager.list_backups()
if not backups:
print("No backups found.")
return
print("Available Backups:")
print("==================")
for backup in backups:
timestamp = backup.get("timestamp", "unknown")
backup_id = backup.get("backup_id", "unknown")
reason = backup.get("session_state", {}).get("backup_history", [])
if reason:
reason = reason[-1].get("reason", "unknown")
else:
reason = "unknown"
print(f"🗂️ {backup_id}")
print(f" 📅 {timestamp}")
print(f" 📝 {reason}")
print()
def show_session_status():
"""Show current session status"""
session_manager = SessionStateManager()
context_monitor = ContextMonitor()
summary = session_manager.get_session_summary()
context_summary = context_monitor.get_session_summary()
print("Session Status:")
print("===============")
print(f"Session ID: {summary.get('session_id', 'unknown')}")
print(f"Duration: {summary.get('session_stats', {}).get('duration_minutes', 0)} minutes")
print(f"Context Usage: {context_summary.get('context_usage_ratio', 0):.1%}")
print(f"Tool Calls: {summary.get('session_stats', {}).get('total_tool_calls', 0)}")
print(f"Files Modified: {len(summary.get('modified_files', []))}")
print(f"Commands Executed: {summary.get('session_stats', {}).get('total_commands', 0)}")
print(f"Backups Created: {len(summary.get('backup_history', []))}")
print()
if summary.get('modified_files'):
print("Modified Files:")
for file_path in summary['modified_files']:
print(f" - {file_path}")
print()
if context_summary.get('should_backup'):
print("⚠️ Backup recommended (high context usage)")
else:
print("✅ No backup needed currently")
def show_patterns():
"""Show learned patterns"""
shadow_learner = ShadowLearner()
print("Learned Patterns:")
print("=================")
# Command patterns
command_patterns = shadow_learner.db.command_patterns
if command_patterns:
print("\n🖥️ Command Patterns:")
for pattern_id, pattern in list(command_patterns.items())[:10]: # Show top 10
cmd = pattern.trigger.get("command", "unknown")
confidence = pattern.confidence
evidence = pattern.evidence_count
success_rate = pattern.success_rate
print(f" {cmd}")
print(f" Confidence: {confidence:.1%}")
print(f" Evidence: {evidence} samples")
print(f" Success Rate: {success_rate:.1%}")
# Context patterns
context_patterns = shadow_learner.db.context_patterns
if context_patterns:
print("\n🔍 Context Patterns:")
for pattern_id, pattern in list(context_patterns.items())[:5]: # Show top 5
error_type = pattern.trigger.get("error_type", "unknown")
confidence = pattern.confidence
evidence = pattern.evidence_count
print(f" {error_type}")
print(f" Confidence: {confidence:.1%}")
print(f" Evidence: {evidence} samples")
if not command_patterns and not context_patterns:
print("No patterns learned yet. Use Claude Code to start building the knowledge base!")
def clear_patterns():
"""Clear learned patterns"""
response = input("Are you sure you want to clear all learned patterns? (y/N): ")
if response.lower() == 'y':
shadow_learner = ShadowLearner()
shadow_learner.db = shadow_learner._load_database() # Reset to empty
shadow_learner.save_database()
print("✅ Patterns cleared successfully")
else:
print("Operation cancelled")
def export_data():
"""Export all hook data"""
export_dir = Path("claude_hooks_export")
export_dir.mkdir(exist_ok=True)
# Export session state
session_manager = SessionStateManager()
summary = session_manager.get_session_summary()
with open(export_dir / "session_data.json", 'w') as f:
json.dump(summary, f, indent=2)
# Export patterns
shadow_learner = ShadowLearner()
with open(export_dir / "patterns.json", 'w') as f:
json.dump(shadow_learner.db.to_dict(), f, indent=2)
# Export logs
logs_dir = Path(".claude_hooks/logs")
if logs_dir.exists():
import shutil
shutil.copytree(logs_dir, export_dir / "logs", dirs_exist_ok=True)
print(f"✅ Data exported to {export_dir}")
def main():
"""Main CLI entry point"""
parser = argparse.ArgumentParser(description="Claude Code Hooks CLI")
subparsers = parser.add_subparsers(dest="command", help="Available commands")
# List backups
subparsers.add_parser("list-backups", help="List available backups")
# Show session status
subparsers.add_parser("status", help="Show current session status")
# Show patterns
subparsers.add_parser("patterns", help="Show learned patterns")
# Clear patterns
subparsers.add_parser("clear-patterns", help="Clear all learned patterns")
# Export data
subparsers.add_parser("export", help="Export all hook data")
args = parser.parse_args()
if not args.command:
parser.print_help()
return
try:
if args.command == "list-backups":
list_backups()
elif args.command == "status":
show_session_status()
elif args.command == "patterns":
show_patterns()
elif args.command == "clear-patterns":
clear_patterns()
elif args.command == "export":
export_data()
else:
print(f"Unknown command: {args.command}")
parser.print_help()
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()