All checks were successful
Build and Deploy Log Center / build-and-deploy (push) Successful in 1m31s
165 lines
5.1 KiB
Python
165 lines
5.1 KiB
Python
"""
|
||
Repair Agent CLI - 命令行入口
|
||
"""
|
||
import typer
|
||
from loguru import logger
|
||
from rich.console import Console
|
||
from rich.table import Table
|
||
|
||
from .agent import RepairEngine, TaskManager
|
||
from .config import settings
|
||
|
||
app = typer.Typer(
|
||
name="repair-agent",
|
||
help="自动化 Bug 修复代理",
|
||
)
|
||
console = Console()
|
||
|
||
|
||
@app.command()
|
||
def list(
|
||
project: str = typer.Option(None, "--project", "-p", help="筛选项目ID"),
|
||
):
|
||
"""查看待修复的 Bug 列表"""
|
||
task_manager = TaskManager()
|
||
bugs = task_manager.fetch_pending_bugs(project)
|
||
|
||
if not bugs:
|
||
console.print("[yellow]没有待修复的 Bug[/yellow]")
|
||
return
|
||
|
||
table = Table(title="待修复 Bug 列表")
|
||
table.add_column("ID", style="cyan")
|
||
table.add_column("项目", style="green")
|
||
table.add_column("错误类型", style="red")
|
||
table.add_column("消息", style="white")
|
||
table.add_column("文件", style="blue")
|
||
table.add_column("状态", style="yellow")
|
||
|
||
for bug in bugs:
|
||
table.add_row(
|
||
str(bug.id),
|
||
bug.project_id,
|
||
bug.error.type,
|
||
bug.error.message[:50] + "..." if len(bug.error.message) > 50 else bug.error.message,
|
||
bug.error.file_path or "-",
|
||
bug.status.value,
|
||
)
|
||
|
||
console.print(table)
|
||
task_manager.close()
|
||
|
||
|
||
@app.command()
|
||
def fix(
|
||
project: str = typer.Argument(..., help="项目ID (如 rtc_backend)"),
|
||
test: bool = typer.Option(True, "--test/--no-test", help="是否运行测试"),
|
||
commit: bool = typer.Option(False, "--commit", "-c", help="是否自动提交"),
|
||
):
|
||
"""修复指定项目的所有 Bug"""
|
||
console.print(f"[bold blue]开始修复项目: {project}[/bold blue]")
|
||
|
||
engine = RepairEngine()
|
||
result = engine.fix_project(
|
||
project_id=project,
|
||
run_tests=test,
|
||
auto_commit=commit,
|
||
)
|
||
|
||
if result.total == 0:
|
||
console.print("[yellow]没有需要修复的 Bug[/yellow]")
|
||
else:
|
||
console.print(f"\n[bold]修复结果:[/bold]")
|
||
console.print(f" 总计: {result.total}")
|
||
console.print(f" [green]成功: {result.success_count}[/green]")
|
||
console.print(f" [red]失败: {result.failed_count}[/red]")
|
||
|
||
if result.results:
|
||
console.print("\n[bold]详细结果:[/bold]")
|
||
for r in result.results:
|
||
status = "[green]✓[/green]" if r.success else "[red]✗[/red]"
|
||
console.print(f" {status} Bug #{r.bug_id}: {r.message}")
|
||
if r.modified_files:
|
||
console.print(f" 修改文件: {', '.join(r.modified_files)}")
|
||
|
||
engine.close()
|
||
|
||
|
||
@app.command("fix-one")
|
||
def fix_one(
|
||
bug_id: int = typer.Argument(..., help="Bug ID"),
|
||
test: bool = typer.Option(True, "--test/--no-test", help="是否运行测试"),
|
||
):
|
||
"""修复单个 Bug"""
|
||
console.print(f"[bold blue]开始修复 Bug #{bug_id}[/bold blue]")
|
||
|
||
engine = RepairEngine()
|
||
result = engine.fix_single_bug(bug_id, run_tests=test)
|
||
|
||
if result.success:
|
||
console.print(f"[green]✓ 修复成功![/green]")
|
||
if result.modified_files:
|
||
console.print(f" 修改文件: {', '.join(result.modified_files)}")
|
||
else:
|
||
console.print(f"[red]✗ 修复失败: {result.message}[/red]")
|
||
|
||
engine.close()
|
||
|
||
|
||
@app.command()
|
||
def status():
|
||
"""查看配置状态"""
|
||
console.print("[bold]Repair Agent 配置状态[/bold]\n")
|
||
|
||
console.print(f"Log Center URL: [cyan]{settings.log_center_url}[/cyan]")
|
||
console.print(f"Claude CLI: [cyan]{settings.claude_cli_path}[/cyan]")
|
||
console.print(f"最大重试次数: [cyan]{settings.max_retry_count}[/cyan]")
|
||
console.print(f"最大修改行数: [cyan]{settings.max_modified_lines}[/cyan]")
|
||
console.print(f"最大修改文件数: [cyan]{settings.max_modified_files}[/cyan]")
|
||
console.print(f"核心文件关键词: [cyan]{settings.critical_files}[/cyan]")
|
||
|
||
console.print("\n[bold]项目路径映射:[/bold]")
|
||
console.print(f" rtc_backend: [blue]{settings.path_rtc_backend}[/blue]")
|
||
console.print(f" rtc_web: [blue]{settings.path_rtc_web}[/blue]")
|
||
console.print(f" airhub_app: [blue]{settings.path_airhub_app}[/blue]")
|
||
|
||
|
||
@app.command()
|
||
def analyze(
|
||
bug_id: int = typer.Argument(..., help="Bug ID"),
|
||
):
|
||
"""分析单个 Bug(不修复)"""
|
||
engine = RepairEngine()
|
||
bug = engine.task_manager.get_bug_detail(bug_id)
|
||
|
||
if not bug:
|
||
console.print(f"[red]Bug #{bug_id} 不存在[/red]")
|
||
return
|
||
|
||
project_path = settings.get_project_path(bug.project_id)
|
||
if not project_path:
|
||
console.print(f"[red]未找到项目路径: {bug.project_id}[/red]")
|
||
return
|
||
|
||
console.print(f"[bold blue]分析 Bug #{bug_id}[/bold blue]\n")
|
||
console.print(bug.format_for_prompt())
|
||
|
||
console.print("\n[bold]AI 分析结果:[/bold]")
|
||
success, output = engine.claude_service.analyze_bug(bug, project_path)
|
||
|
||
if success:
|
||
console.print(output)
|
||
else:
|
||
console.print(f"[red]分析失败: {output}[/red]")
|
||
|
||
engine.close()
|
||
|
||
|
||
def main():
|
||
"""入口函数"""
|
||
app()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|