From b62f50151f0f7b3fc7bd385ce052d14d73ee7c20 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Thu, 29 Jan 2026 13:20:36 +0000 Subject: [PATCH] Add core context generator module --- src/contextgen/cli.py | 177 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 src/contextgen/cli.py diff --git a/src/contextgen/cli.py b/src/contextgen/cli.py new file mode 100644 index 0000000..7aa4f81 --- /dev/null +++ b/src/contextgen/cli.py @@ -0,0 +1,177 @@ +"""Command-line interface for Project Context Generator.""" + +import sys +from pathlib import Path + +import click + +from contextgen.context_generator import ContextGenerator +from contextgen.mcp.server import MCPServer + + +@click.group() +@click.version_option(version="0.1.0") +@click.option( + "--project", + type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path), + help="Path to project directory (defaults to current directory)", +) +@click.pass_context +def main(ctx: click.Context, project: Path | None) -> None: + """Project Context Generator - Analyze codebases and generate AI-friendly context.""" + ctx.ensure_object(dict) + ctx.obj["project"] = project or Path.cwd() + + +@main.command() +@click.option( + "--output", + "-o", + type=click.Path(path_type=Path), + help="Output file path (prints to stdout if not specified)", +) +@click.option( + "--format", + "-f", + type=click.Choice(["json", "yaml"]), + default="json", + help="Output format (default: json)", +) +@click.pass_context +def generate(ctx: click.Context, output: Path | None, format: str) -> None: + """Generate context file for the project.""" + project_path = ctx.obj["project"] + + click.echo(f"Analyzing project: {project_path}", err=True) + + try: + generator = ContextGenerator(project_path) + context = generator.generate() + + if output: + generator.save(output, format) + click.echo(f"Context saved to: {output}", err=True) + else: + if format == "json": + import json + click.echo(json.dumps(context, indent=2)) + else: + import yaml + click.echo(yaml.dump(context, default_flow_style=False)) + + click.echo("Context generated successfully!", err=True) + + except Exception as e: + click.echo(f"Error: {e}", err=True) + sys.exit(1) + + +@main.command() +@click.option( + "--template", + "-t", + type=str, + default="standard", + help="Template to use (minimal, standard, comprehensive)", +) +@click.option( + "--output", + "-o", + type=click.Path(path_type=Path), + help="Output file path (prints to stdout if not specified)", +) +@click.option( + "--template-dir", + type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path), + help="Directory containing custom templates", +) +@click.pass_context +def render(ctx: click.Context, template: str, output: Path | None, template_dir: Path | None) -> None: + """Render context using a template.""" + project_path = ctx.obj["project"] + + click.echo(f"Generating context with template: {template}", err=True) + + try: + generator = ContextGenerator(project_path) + rendered = generator.generate_from_template(template, template_dir) + + if output: + output.write_text(rendered, encoding="utf-8") + click.echo(f"Context saved to: {output}", err=True) + else: + click.echo(rendered) + + click.echo("Context rendered successfully!", err=True) + + except ValueError as e: + click.echo(f"Template error: {e}", err=True) + sys.exit(1) + except Exception as e: + click.echo(f"Error: {e}", err=True) + sys.exit(1) + + +@main.command() +@click.pass_context +def mcp(ctx: click.Context) -> None: + """Run as MCP server (for AI tool integration).""" + project_path = ctx.obj["project"] + + click.echo(f"Starting MCP server for: {project_path}", err=True) + + try: + server = MCPServer(project_path) + server.run_stdio() + except Exception as e: + click.echo(f"Error: {e}", err=True) + sys.exit(1) + + +@main.command() +@click.pass_context +def info(ctx: click.Context) -> None: + """Show quick overview of the project.""" + project_path = ctx.obj["project"] + + try: + generator = ContextGenerator(project_path) + context = generator.generate() + + click.echo(f"Project: {context['project']['name']}") + click.echo(f"Primary Language: {context['analysis'].get('primary_language', 'Unknown')}") + + frameworks = context['analysis'].get('frameworks', []) + if frameworks: + click.echo(f"Frameworks: {', '.join(f['name'] for f in frameworks[:3])}") + + key_files = context['structure'].get('key_files', {}) + if key_files: + click.echo(f"Key Files: {', '.join(key_files.keys())}") + + conventions = context.get('conventions', {}) + if conventions: + naming = conventions.get('naming', {}) + click.echo(f"Naming Style: {naming.get('dominant_style', 'Unknown')}") + + except Exception as e: + click.echo(f"Error: {e}", err=True) + sys.exit(1) + + +@main.command() +@click.pass_context +def templates(ctx: click.Context) -> None: + """List available templates.""" + from contextgen.templates.engine import TemplateEngine + + engine = TemplateEngine() + templates = engine.list_templates() + + click.echo("Available templates:") + for template in templates: + click.echo(f" - {template}") + + +if __name__ == "__main__": + main()