From 130193f1b7197b9ab7adc07426dcd197d9073725 Mon Sep 17 00:00:00 2001 From: basantnema31 Date: Wed, 3 Jun 2026 13:33:37 +0530 Subject: [PATCH] feat: add shell tab completion for CLI commands for #38 --- cli/oss_commands.py | 48 +++++++++++++++++------------------- completion.sh | 2 ++ main.py | 60 ++++++++++++++++++++------------------------- pyproject.toml | 3 +-- 4 files changed, 53 insertions(+), 60 deletions(-) create mode 100644 completion.sh diff --git a/cli/oss_commands.py b/cli/oss_commands.py index df03989..15eb82c 100644 --- a/cli/oss_commands.py +++ b/cli/oss_commands.py @@ -10,7 +10,7 @@ from pathlib import Path from typing import Optional -import click +import typer from rich.console import Console from rich.panel import Panel from rich.table import Table @@ -66,15 +66,13 @@ def get_repo_from_cwd(cwd: Path) -> Optional[tuple[str, str]]: return None -@click.group(name="oss-dev", help="OSS Dev Agent - Work on GitHub issues") -@click.option( - "--cwd", - "-c", - type=click.Path(exists=True, file_okay=False, path_type=Path), - help="Working directory (default: current directory)", -) -@click.pass_context -def oss_dev_group(ctx: click.Context, cwd: Optional[Path]): +oss_dev_group = typer.Typer(name="oss-dev", help="OSS Dev Agent - Work on GitHub issues") + +@oss_dev_group.callback() +def oss_dev_callback( + ctx: typer.Context, + cwd: Optional[Path] = typer.Option(None, "--cwd", "-c", help="Working directory (default: current directory)") +): """OSS Dev Agent command group.""" ctx.ensure_object(dict) @@ -98,9 +96,10 @@ def oss_dev_group(ctx: click.Context, cwd: Optional[Path]): @oss_dev_group.command(name="fix", help="Start working on a GitHub issue") -@click.argument("issue_url", required=True) -@click.pass_context -def oss_fix(ctx: click.Context, issue_url: str): +def oss_fix( + ctx: typer.Context, + issue_url: str = typer.Argument(..., help="GitHub issue URL") +): """Start working on a GitHub issue from scratch.""" from config.config import Config from oss.workflow import OSSWorkflow @@ -406,9 +405,10 @@ async def run_fix(): @oss_dev_group.command(name="review", help="Work on an issue in the current repository") -@click.argument("issue_number", type=int, required=True) -@click.pass_context -def oss_review(ctx: click.Context, issue_number: int): +def oss_review( + ctx: typer.Context, + issue_number: int = typer.Argument(..., help="Issue number") +): """Work on an issue when already in the repository.""" from config.config import Config from oss.workflow import OSSWorkflow @@ -503,8 +503,7 @@ async def run_review(): @oss_dev_group.command(name="resume", help="Continue work on current branch") -@click.pass_context -def oss_resume(ctx: click.Context): +def oss_resume(ctx: typer.Context): """Continue work on current branch.""" from config.config import Config from oss.workflow import OSSWorkflow @@ -577,8 +576,7 @@ async def run_resume(): @oss_dev_group.command(name="status", help="Show current work status") -@click.pass_context -def oss_status(ctx: click.Context): +def oss_status(ctx: typer.Context): """Show current work status.""" from config.config import Config from oss.workflow import OSSWorkflow @@ -679,8 +677,7 @@ def oss_status(ctx: click.Context): @oss_dev_group.command(name="list", help="List active branches with issues") -@click.pass_context -def oss_list(ctx: click.Context): +def oss_list(ctx: typer.Context): """List active branches with issues.""" from config.config import Config from oss.memory import BranchMemoryManager @@ -737,9 +734,10 @@ def oss_list(ctx: click.Context): @oss_dev_group.command(name="switch", help="Switch to a different branch or issue") -@click.argument("target", required=True) -@click.pass_context -def oss_switch(ctx: click.Context, target: str): +def oss_switch( + ctx: typer.Context, + target: str = typer.Argument(..., help="Target branch or issue to switch to") +): """Switch to a different branch or issue.""" from config.config import Config from oss.workflow import OSSWorkflow diff --git a/completion.sh b/completion.sh new file mode 100644 index 0000000..9726a10 --- /dev/null +++ b/completion.sh @@ -0,0 +1,2 @@ +#!/bin/bash +# Shell completion diff --git a/main.py b/main.py index 689c166..6f0ede4 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,7 @@ import asyncio from pathlib import Path import sys -import click +import typer from agent.agent import Agent from agent.events import AgentEventType @@ -454,18 +454,21 @@ async def _handle_oss_status(self) -> None: pass -@click.group() -@click.version_option(__version__, "--version", "-V", prog_name="oss-dev", message="%(prog)s v%(version)s") -@click.option( - "--cwd", - "-c", - type=click.Path(exists=True, file_okay=False, path_type=Path), - help="Current working directory", +app = typer.Typer( + help="AI Coding Agent - CLI interface for AI-powered coding assistance.\nUse 'oss-dev' subcommands for OSS contribution workflows.", + no_args_is_help=True, ) -@click.pass_context + +def _version_callback(value: bool) -> None: + if value: + typer.echo(f"oss-dev v{__version__}") + raise typer.Exit() + +@app.callback(invoke_without_command=True) def main( - ctx: click.Context, - cwd: Path | None, + ctx: typer.Context, + version: bool = typer.Option(False, "--version", "-V", help="Show version.", callback=_version_callback, is_eager=True), + cwd: Path | None = typer.Option(None, "--cwd", "-c", help="Current working directory"), ): """ AI Coding Agent - CLI interface for AI-powered coding assistance. @@ -477,16 +480,12 @@ def main( ctx.obj["cwd"] = cwd -@main.command() -@click.argument("prompt", required=True) -@click.option( - "--cwd", - "-c", - type=click.Path(exists=True, file_okay=False, path_type=Path), - help="Current working directory", -) -@click.pass_context -def chat(ctx: click.Context, prompt: str, cwd: Path | None): +@app.command() +def chat( + ctx: typer.Context, + prompt: str = typer.Argument(..., help="Run a single prompt through the agent"), + cwd: Path | None = typer.Option(None, "--cwd", "-c", help="Current working directory") +): """Run a single prompt through the agent.""" cwd = cwd or ctx.obj.get("cwd") or Path.cwd() @@ -508,15 +507,11 @@ def chat(ctx: click.Context, prompt: str, cwd: Path | None): sys.exit(1) -@main.command() -@click.option( - "--cwd", - "-c", - type=click.Path(exists=True, file_okay=False, path_type=Path), - help="Current working directory", -) -@click.pass_context -def interactive(ctx: click.Context, cwd: Path | None): +@app.command() +def interactive( + ctx: typer.Context, + cwd: Path | None = typer.Option(None, "--cwd", "-c", help="Current working directory") +): """Start interactive agent session.""" cwd = cwd or ctx.obj.get("cwd") or Path.cwd() @@ -537,9 +532,8 @@ def interactive(ctx: click.Context, cwd: Path | None): # Add OSS command group -# Fixed missing import for OSS commands from cli.oss_commands import oss_dev_group -main.add_command(oss_dev_group) +app.add_typer(oss_dev_group, name="oss-dev") if __name__ == "__main__": - main() + app() diff --git a/pyproject.toml b/pyproject.toml index 8743a29..44327e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,8 +25,7 @@ dependencies = [ ] [project.scripts] -oss-dev = "main:main" -oss-dev-new = "oss_dev.cli.app:app" +oss-dev = "main:app" [dependency-groups] dev = [