Add commands and parsers modules
Some checks failed
CI / test (push) Has been cancelled
CI / lint (push) Has been cancelled

This commit is contained in:
2026-01-30 05:29:49 +00:00
parent e801bb04c7
commit 2fb2366224

View File

@@ -0,0 +1,186 @@
"""Visualize command for CLI."""
from pathlib import Path
from typing import Optional
import click
from rich.console import Console
from rich.panel import Panel
from rich.text import Text
from ..core.database import SessionDatabase
from ..core.session import Session
from ..parsers.git_parser import GitLogParser
from ..parsers.pattern_analyzer import PatternDetector, SequenceAnalyzer
from ..exporters.ascii_generator import ASCIIGenerator, GitGraphGenerator
from ..exporters.mermaid_generator import MermaidGenerator
console = Console()
@click.command(name="visualize")
@click.argument("source", type=str)
@click.option(
"--session-id",
"-s",
type=int,
help="Session ID to visualize",
)
@click.option(
"--style",
"visual_style",
type=click.Choice(["compact", "detailed", "minimal"]),
default="detailed",
help="Visualization style",
)
@click.option(
"--format",
"-f",
type=click.Choice(["ascii", "mermaid"]),
default="ascii",
help="Output format",
)
@click.option(
"--output",
"-o",
type=click.Path(path_type=Path),
help="Output file",
)
@click.option(
"--analyze/--no-analyze",
default=True,
help="Include pattern analysis",
)
@click.pass_context
def visualize_cmd(
ctx: click.Context,
source: str,
session_id: Optional[int],
visual_style: str,
format: str,
output: Optional[Path],
analyze: bool,
) -> None:
"""Visualize a session or git workflow."""
db_path = ctx.obj.get("db", Path.home() / ".termflow" / "sessions.db")
if source == "session":
_visualize_session(
db_path,
session_id,
visual_style,
format,
output,
analyze,
)
elif source == "git":
_visualize_git(
Path.cwd(),
visual_style,
format,
output,
)
else:
console.print(f"[red]Unknown source: {source}[/red]")
console.print("Use 'session' or 'git' as source")
def _visualize_session(
db_path: Path,
session_id: Optional[int],
style: str,
format: str,
output: Optional[Path],
analyze: bool,
) -> None:
"""Visualize a terminal session."""
db = SessionDatabase(db_path)
if session_id is None:
sessions = db.get_all_sessions()
if not sessions:
console.print("[yellow]No sessions found[/yellow]")
return
session_id = sessions[0]["id"]
session = db.get_session(session_id)
if not session:
console.print(f"[red]Session {session_id} not found[/red]")
return
commands = db.get_session_commands(session_id)
command_list = [cmd.get("command", "") for cmd in commands]
if analyze:
detector = PatternDetector()
patterns = detector.analyze_commands(command_list)
if patterns:
text = Text()
text.append(f"Found {len(patterns)} patterns:\n", style="bold")
for i, pattern in enumerate(patterns[:5], 1):
text.append(f" {i}. {pattern.commands} (x{pattern.frequency})\n")
console.print(Panel(text, title="Pattern Analysis"))
metadata = {
"title": f"Session: {session.get('name', 'Unknown')}",
"command_count": len(command_list),
"session_name": session.get("name", ""),
}
if format == "ascii":
ascii_gen = ASCIIGenerator(style=style)
result = ascii_gen.generate_from_commands(command_list, metadata)
else:
mermaid_gen = MermaidGenerator()
result = mermaid_gen.generate_flowchart(
command_list,
title=f"Session: {session.get('name', 'Unknown')}",
metadata=metadata,
)
if output:
with open(output, "w") as f:
f.write(result)
console.print(f"[cyan]Visualization saved to {output}[/cyan]")
else:
console.print(Panel(result, title=f"Session Flow: {session.get('name', 'Unknown')}"))
def _visualize_git(
repo_path: Path,
style: str,
format: str,
output: Optional[Path],
) -> None:
"""Visualize git workflow."""
parser = GitLogParser(repo_path)
if not parser.is_git_repo():
console.print("[red]Not a git repository[/red]")
return
commits = parser.parse_log(max_count=50)
parser.get_commit_parents()
workflow = parser.analyze_workflow()
if format == "ascii":
graph_gen = GitGraphGenerator()
result = graph_gen.generate_from_parser(parser)
else:
mermaid_gen = MermaidGenerator()
result = mermaid_gen.generate_git_graph_from_parser(parser)
stats_text = Text()
stats_text.append(f"Commits: {len(commits)}\n", style="bold")
stats_text.append(f"Merges: {workflow.merge_count}\n")
stats_text.append(f"Features: {workflow.feature_count}\n")
stats_text.append(f"Branches: {len(workflow.branches)}")
if output:
with open(output, "w") as f:
f.write(result)
console.print(f"[cyan]Visualization saved to {output}[/cyan]")
else:
console.print(Panel(result, title="Git Workflow"))
console.print(Panel(stats_text, title="Statistics"))