From 8f6c721f06df238834227403b3d5c92de7a5c283 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Tue, 21 Apr 2026 10:19:39 -0500 Subject: [PATCH] Added executable root launcher for audita --- README.md | 17 ++++++++++++++++- audita | 24 ++++++++++++++++++++++++ pyproject.toml | 2 +- src/audita/cli.py | 5 ++--- src/audita/llm.py | 3 +-- tests/test_cli.py | 12 ++++++++++++ tests/test_launcher.py | 31 +++++++++++++++++++++++++++++++ 7 files changed, 87 insertions(+), 7 deletions(-) create mode 100755 audita create mode 100644 tests/test_cli.py create mode 100644 tests/test_launcher.py diff --git a/README.md b/README.md index e241da7..0fd7b68 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,22 @@ Set an OpenRouter API key, then process a transcript with a glossary: ```sh export OPENROUTER_API_KEY=... -uv run audia process transcript.json --glossary glossary.yaml --output corrected.json +uv run audita process transcript.json --glossary glossary.yaml --output corrected.json +``` + +From a checked-out repository, you can also use the root launcher: + +```sh +./audita process transcript.json --glossary glossary.yaml --output corrected.json +``` + +For a system-wide command, install the source tree under `/usr/local/src/audita`, sync dependencies there, and symlink the root launcher into your `PATH`: + +```sh +cd /usr/local/src/audita +uv sync --extra dev +ln -s /usr/local/src/audita/audita /usr/local/bin/audita +audita process transcript.json --glossary glossary.yaml --output corrected.json ``` Without `--output`, Audita writes the corrected transcript JSON to stdout and progress logs to stderr. diff --git a/audita b/audita new file mode 100755 index 0000000..815f6bc --- /dev/null +++ b/audita @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +import os +import shutil +import sys +from pathlib import Path + + +def main() -> int: + uv = shutil.which("uv") + if uv is None: + print( + "audita: error: uv is required to run this launcher. Install uv and run `uv sync` in the Audita project.", + file=sys.stderr, + ) + return 1 + + project_root = Path(__file__).resolve().parent + command = [uv, "run", "--project", str(project_root), "python", "-m", "audita", *sys.argv[1:]] + os.execv(uv, command) + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/pyproject.toml b/pyproject.toml index a140d68..1489bb4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ dev = [ ] [project.scripts] -audia = "audita.cli:main" +audita = "audita.cli:main" [build-system] requires = ["hatchling"] diff --git a/src/audita/cli.py b/src/audita/cli.py index bb98d0e..2961c0d 100644 --- a/src/audita/cli.py +++ b/src/audita/cli.py @@ -22,7 +22,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int: def _build_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser(prog="audia") + parser = argparse.ArgumentParser(prog="audita") subparsers = parser.add_subparsers(dest="command", required=True) process = subparsers.add_parser("process", help="correct a transcript using a glossary") @@ -65,6 +65,5 @@ def _process(args: argparse.Namespace) -> int: sys.stdout.write(transcript_to_json(revised)) return 0 except AuditaError as exc: - print(f"audia: error: {exc}", file=sys.stderr) + print(f"audita: error: {exc}", file=sys.stderr) return 1 - diff --git a/src/audita/llm.py b/src/audita/llm.py index 9bad628..f08a639 100644 --- a/src/audita/llm.py +++ b/src/audita/llm.py @@ -13,7 +13,7 @@ class InstructorLLMClient: from openai import OpenAI except ImportError as exc: raise AuditaLLMError( - "The LLM dependencies are not installed. Run `uv sync` before using audia." + "The LLM dependencies are not installed. Run `uv sync` before using audita." ) from exc self._instructor = instructor @@ -42,4 +42,3 @@ def _normalize_openrouter_model(model: str) -> str: if model.startswith(prefix): return model[len(prefix) :] return model - diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..fa5daab --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,12 @@ +import pytest + +from audita.cli import main + + +def test_cli_help_uses_audita_program_name(capsys): + with pytest.raises(SystemExit) as exc: + main(["--help"]) + + assert exc.value.code == 0 + assert capsys.readouterr().out.startswith("usage: audita ") + diff --git a/tests/test_launcher.py b/tests/test_launcher.py new file mode 100644 index 0000000..b19a249 --- /dev/null +++ b/tests/test_launcher.py @@ -0,0 +1,31 @@ +import os +import shutil +import subprocess +from pathlib import Path + +import pytest + + +ROOT = Path(__file__).resolve().parents[1] +LAUNCHER = ROOT / "audita" + + +def test_root_launcher_exists_and_is_executable(): + assert LAUNCHER.is_file() + assert os.access(LAUNCHER, os.X_OK) + + +def test_root_launcher_help_smoke(): + if shutil.which("uv") is None: + pytest.skip("uv is not installed") + + result = subprocess.run( + [str(LAUNCHER), "--help"], + cwd=ROOT, + text=True, + capture_output=True, + check=False, + ) + + assert result.returncode == 0 + assert result.stdout.startswith("usage: audita ")