Coverage for src / moai_adk / cli / commands / analyze.py: 0.00%
58 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-20 20:52 +0900
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-20 20:52 +0900
1#!/usr/bin/env python3
2"""
3Analyze command for MoAI-ADK
5Analyze Claude Code sessions and generate improvement suggestions.
6"""
9from pathlib import Path
10from typing import Optional
12import click
13from rich.console import Console
14from rich.table import Table
16from moai_adk.core.analysis.session_analyzer import SessionAnalyzer
18console = Console()
21@click.command()
22@click.option("--days", "-d", default=7, help="Number of days to analyze (default: 7)")
23@click.option("--output", "-o", type=click.Path(), help="Output file path")
24@click.option("--verbose", "-v", is_flag=True, help="Verbose output")
25@click.option(
26 "--report-only", "-r", is_flag=True, help="Generate report only (no console output)"
27)
28@click.option(
29 "--project-path",
30 "-p",
31 type=click.Path(),
32 help="Project root path (default: current directory)",
33)
34def analyze(
35 days: int,
36 output: Optional[Path],
37 verbose: bool,
38 report_only: bool,
39 project_path: Optional[Path],
40):
41 """
42 Analyze Claude Code sessions from the last N days
44 Analyzes Claude Code session logs to identify usage patterns,
45 error frequencies, and generate improvement suggestions.
47 Examples:
48 moai-adk analyze session
49 moai-adk analyze session --days 14 --verbose
50 moai-adk analyze session --output /path/to/report.md
51 """
52 if project_path is None:
53 project_path = Path.cwd()
55 # Validate project path
56 if not (project_path / ".moai").exists():
57 console.print(
58 "[red]Error:[/red] Not a MoAI-ADK project (missing .moai directory)"
59 )
60 console.print(f"[blue]Current path:[/blue] {project_path}")
61 return
63 # Initialize analyzer
64 analyzer = SessionAnalyzer(days_back=days, verbose=verbose)
66 if not report_only:
67 console.print(f"[blue]📊 Analyzing sessions from last {days} days...[/blue]")
69 # Parse sessions
70 patterns = analyzer.parse_sessions()
72 if not report_only:
73 console.print(
74 f"[green]✅ Analyzed {patterns['total_sessions']} sessions[/green]"
75 )
76 console.print(f"[blue] Total events: {patterns['total_events']}[/blue]")
78 # Display summary table
79 table = Table(title="Session Summary")
80 table.add_column("Metric", style="cyan")
81 table.add_column("Value", style="green")
83 table.add_row("Total Sessions", str(patterns["total_sessions"]))
84 table.add_row("Total Events", str(patterns["total_events"]))
85 table.add_row("Failed Sessions", str(patterns["failed_sessions"]))
86 table.add_row("Success Rate", f"{patterns.get('success_rate', 0):.1f}%")
88 console.print(table)
90 # Show top tools
91 if patterns["tool_usage"]:
92 console.print("\n[bold]🔧 Top Tools Used:[/bold]")
93 top_tools = sorted(
94 patterns["tool_usage"].items(), key=lambda x: x[1], reverse=True
95 )[:10]
97 tools_table = Table()
98 tools_table.add_column("Tool", style="cyan")
99 tools_table.add_column("Usage", style="green")
101 for tool, count in top_tools:
102 tools_table.add_row(f"`{tool}`", str(count))
104 console.print(tools_table)
106 # Save report
107 output_path_obj = Path(output) if output else None
108 report_path = analyzer.save_report(output_path_obj, project_path)
110 if not report_only:
111 console.print(f"\n[green]📄 Report saved: {report_path}[/green]")
113 # Show key suggestions
114 report_content = analyzer.generate_report()
115 if "💡 Improvement Suggestions" in report_content:
116 console.print("\n[bold yellow]💡 Key Suggestions:[/bold yellow]")
117 # Extract suggestions section
118 suggestions_start = report_content.find("💡 Improvement Suggestions")
119 if suggestions_start != -1:
120 suggestions_section = report_content[suggestions_start:]
121 # Extract first few suggestions
122 lines = suggestions_section.split("\n")[
123 2:
124 ] # Skip header and empty line
125 for line in lines[:10]: # Show first 10 lines
126 if line.strip() and not line.startswith("---"):
127 console.print(line)