"""CLI entry for Beaver.""" from pathlib import Path try: import typer except ModuleNotFoundError: # pragma: no cover - fallback for skeleton-only environments class _FallbackTyper: def __init__(self, *_args, **_kwargs) -> None: pass def command(self): def decorator(func): return func return decorator def __call__(self) -> None: raise RuntimeError("typer is not installed") @staticmethod def echo(message: str) -> None: print(message) @staticmethod def Option(default=None, *_args, **_kwargs): return default typer = _FallbackTyper() # type: ignore[assignment] from beaver.services.agent_service import AgentService from beaver.services.hermes_migration import HermesMigrationService from beaver.skills.specs import SkillSpecStore app = typer.Typer(help="Beaver backend CLI") if hasattr(typer, "Typer") else typer @app.command() def run( message: str | None = typer.Option(None, "--message", "-m", help="Run one direct Beaver request."), workspace: str | None = typer.Option(None, "--workspace", help="Workspace root for this run."), config: str | None = typer.Option(None, "--config", help="Backend config path for this run."), ) -> None: """Thin CLI wrapper around AgentService. CLI 现在不再自己维护执行逻辑,只负责: 1. 解析命令行参数 2. 调 AgentService 3. 打印结果 """ service = AgentService(workspace=workspace, config_path=config) if not message: service.create_loop() typer.echo("Beaver engine booted.") return result = service.run_direct(message, source="cli") typer.echo(result.output_text) @app.command("migrate-hermes") def migrate_hermes( repo: str = typer.Option(..., "--repo", help="Local checkout of https://github.com/NousResearch/hermes-agent."), workspace: str | None = typer.Option(None, "--workspace", help="Workspace root to import skills into."), manifest: str | None = typer.Option(None, "--manifest", help="Path for hermes_migration_manifest.json."), dry_run: bool = typer.Option(False, "--dry-run", help="Only write the manifest without importing skills."), ) -> None: """Import no-credential Hermes Agent skills and write a manifest.""" service = AgentService(workspace=workspace) loaded = service.create_loop().boot() store = loaded.skill_spec_store or SkillSpecStore(loaded.workspace) migration = HermesMigrationService(store, manifest_path=Path(manifest) if manifest else None) result = migration.migrate(repo, dry_run=dry_run) typer.echo( f"Hermes migration complete: {len(result['included'])} included, " f"{len(result['skipped'])} skipped." ) def main() -> None: """Project script entrypoint.""" app()