diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e5eee0e --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +# Copy this file to .env and fill values when needed. +JARVIS_ENV=development diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d3916b --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Python +__pycache__/ +*.py[cod] +*.pyo +*.pyd +.Python +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ + +# Virtual environments +.venv/ +venv/ +env/ + +# Build artifacts +build/ +dist/ +*.egg-info/ + +# IDE/editor +.vscode/ +.idea/ + +# OS files +.DS_Store +Thumbs.db + +# Local environment +.env diff --git a/README.md b/README.md new file mode 100644 index 0000000..1021364 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# jarvis_glm + +A Windows-friendly Python 3.11+ scaffold for a future Jarvis voice assistant. + +## Quickstart + +1. Create and activate a virtual environment. +2. Install package and dev tooling: + +```bash +pip install -e .[dev] +``` + +## CLI + +Run environment diagnostics: + +```bash +python -m jarvis doctor +``` + +## Development checks + +```bash +pytest +ruff check . +mypy +``` diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..a1549b2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,45 @@ +[build-system] +requires = ["setuptools>=68", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "jarvis_glm" +version = "0.1.0" +description = "Windows-friendly voice assistant scaffold" +readme = "README.md" +requires-python = ">=3.11" +authors = [{ name = "Jarvis Team" }] +dependencies = [] + +[project.optional-dependencies] +dev = [ + "pytest>=8.0", + "ruff>=0.6.0", + "mypy>=1.10", +] + +[tool.setuptools] +package-dir = {"" = "src"} + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.pytest.ini_options] +minversion = "8.0" +addopts = "-ra" +testpaths = ["tests"] + +[tool.ruff] +line-length = 100 +target-version = "py311" +src = ["src", "tests"] + +[tool.ruff.lint] +select = ["E", "F", "I", "B", "UP"] + +[tool.mypy] +python_version = "3.11" +strict = true +mypy_path = ["src"] +packages = ["jarvis"] +warn_unused_configs = true diff --git a/src/jarvis/__init__.py b/src/jarvis/__init__.py new file mode 100644 index 0000000..858909d --- /dev/null +++ b/src/jarvis/__init__.py @@ -0,0 +1,5 @@ +"""jarvis package.""" + +__all__ = ["__version__"] + +__version__ = "0.1.0" diff --git a/src/jarvis/__main__.py b/src/jarvis/__main__.py new file mode 100644 index 0000000..0fff28a --- /dev/null +++ b/src/jarvis/__main__.py @@ -0,0 +1,34 @@ +"""CLI entrypoint for jarvis.""" + +from __future__ import annotations + +import argparse + +from jarvis.doctor import format_diagnostics + + +def build_parser() -> argparse.ArgumentParser: + """Build command-line parser.""" + parser = argparse.ArgumentParser(prog="jarvis", description="Jarvis assistant CLI") + subparsers = parser.add_subparsers(dest="command") + + subparsers.add_parser("doctor", help="Print environment diagnostics") + + return parser + + +def main() -> int: + """Run the jarvis CLI.""" + parser = build_parser() + args = parser.parse_args() + + if args.command == "doctor": + print(format_diagnostics()) + return 0 + + parser.print_help() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/jarvis/doctor.py b/src/jarvis/doctor.py new file mode 100644 index 0000000..8133f29 --- /dev/null +++ b/src/jarvis/doctor.py @@ -0,0 +1,27 @@ +"""Environment diagnostics for Jarvis CLI.""" + +from __future__ import annotations + +import os +import platform +import sys + + +def collect_diagnostics() -> dict[str, str]: + """Collect basic diagnostics for the current runtime environment.""" + return { + "python_executable": sys.executable, + "python_version": platform.python_version(), + "platform": platform.platform(), + "system": platform.system(), + "machine": platform.machine(), + "windows_comspec": os.environ.get("COMSPEC", "not set"), + } + + +def format_diagnostics() -> str: + """Format diagnostics as human-readable text.""" + diagnostics = collect_diagnostics() + lines = ["Jarvis Doctor", "============="] + lines.extend(f"{key}: {value}" for key, value in diagnostics.items()) + return "\n".join(lines) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..a36031a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,9 @@ +from __future__ import annotations + +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +SRC = ROOT / "src" + +sys.path.insert(0, str(SRC)) diff --git a/tests/test_doctor.py b/tests/test_doctor.py new file mode 100644 index 0000000..1d4f489 --- /dev/null +++ b/tests/test_doctor.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +import os +import subprocess +import sys +from pathlib import Path + +from jarvis.doctor import collect_diagnostics, format_diagnostics + + +def test_collect_diagnostics_contains_expected_keys() -> None: + diagnostics = collect_diagnostics() + + assert diagnostics["python_executable"] + assert diagnostics["python_version"] + assert diagnostics["platform"] + + +def test_format_diagnostics_header() -> None: + output = format_diagnostics() + + assert "Jarvis Doctor" in output + assert "python_version:" in output + + +def test_module_cli_doctor() -> None: + root = Path(__file__).resolve().parents[1] + src = root / "src" + env = os.environ.copy() + env["PYTHONPATH"] = str(src) + + result = subprocess.run( + [sys.executable, "-m", "jarvis", "doctor"], + check=False, + capture_output=True, + text=True, + env=env, + ) + + assert result.returncode == 0 + assert "Jarvis Doctor" in result.stdout