diff --git a/README.md b/README.md index 011ab13..d2b591b 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,12 @@ After successfully installing the dependencies, you can run SeedPass using the f python src/main.py ``` +You can also use the new Typer-based CLI: +```bash +seedpass --help +``` +For details see [docs/advanced_cli.md](docs/advanced_cli.md). + ### Running the Application 1. **Start the Application:** diff --git a/pyproject.toml b/pyproject.toml index daed3ac..4165dd2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,10 @@ +[project] +name = "seedpass" +version = "0.1.0" + +[project.scripts] +seedpass = "seedpass.cli:app" + [tool.mypy] python_version = "3.11" strict = true diff --git a/requirements.lock b/requirements.lock index 478be5c..5b74e12 100644 --- a/requirements.lock +++ b/requirements.lock @@ -61,3 +61,4 @@ varint==1.0.2 websocket-client==1.7.0 websockets==15.0.1 yarl==1.20.1 +typer==0.12.3 diff --git a/src/requirements.txt b/src/requirements.txt index 184df64..5e9e0a0 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -24,3 +24,4 @@ pyotp>=2.8.0 freezegun pyperclip qrcode>=8.2 +typer>=0.12.3 diff --git a/src/seedpass/__init__.py b/src/seedpass/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/seedpass/cli.py b/src/seedpass/cli.py new file mode 100644 index 0000000..885ae6a --- /dev/null +++ b/src/seedpass/cli.py @@ -0,0 +1,73 @@ +import typer +from typing import Optional + +app = typer.Typer(help="SeedPass command line interface") + +# Global option shared across all commands +fingerprint_option = typer.Option( + None, + "--fingerprint", + "-f", + help="Specify which seed profile to use", +) + +# Sub command groups +entry_app = typer.Typer(help="Manage individual entries") +vault_app = typer.Typer(help="Manage the entire vault") +nostr_app = typer.Typer(help="Interact with Nostr relays") +config_app = typer.Typer(help="Manage configuration values") +fingerprint_app = typer.Typer(help="Manage seed profiles") +util_app = typer.Typer(help="Utility commands") + +app.add_typer(entry_app, name="entry") +app.add_typer(vault_app, name="vault") +app.add_typer(nostr_app, name="nostr") +app.add_typer(config_app, name="config") +app.add_typer(fingerprint_app, name="fingerprint") +app.add_typer(util_app, name="util") + + +@app.callback() +def main(ctx: typer.Context, fingerprint: Optional[str] = fingerprint_option) -> None: + """SeedPass CLI entry point.""" + ctx.obj = {"fingerprint": fingerprint} + + +@entry_app.command("list") +def entry_list(ctx: typer.Context) -> None: + """List entries in the vault.""" + typer.echo(f"Listing entries for fingerprint: {ctx.obj.get('fingerprint')}") + + +@vault_app.command("export") +def vault_export( + ctx: typer.Context, file: str = typer.Option(..., help="Output file") +) -> None: + """Export the vault.""" + typer.echo( + f"Exporting vault for fingerprint {ctx.obj.get('fingerprint')} to {file}" + ) + + +@nostr_app.command("sync") +def nostr_sync(ctx: typer.Context) -> None: + """Sync with configured Nostr relays.""" + typer.echo(f"Syncing vault for fingerprint: {ctx.obj.get('fingerprint')}") + + +@config_app.command("get") +def config_get(ctx: typer.Context, key: str) -> None: + """Get a configuration value.""" + typer.echo(f"Get config '{key}' for fingerprint: {ctx.obj.get('fingerprint')}") + + +@fingerprint_app.command("list") +def fingerprint_list(ctx: typer.Context) -> None: + """List available seed profiles.""" + typer.echo("Listing seed profiles") + + +@util_app.command("generate-password") +def generate_password(ctx: typer.Context, length: int = 24) -> None: + """Generate a strong password.""" + typer.echo(f"Generate password of length {length} for {ctx.obj.get('fingerprint')}")