diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 765da827..d252c077 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,26 @@ Thank you for your interest in contributing to Voicebox! This document provides ### Development Setup -**Using the Makefile (recommended for macOS/Linux):** Run `make setup` to install all dependencies, then `make dev` to start development servers. See `make help` for all available commands. +**Using `just` (recommended):** + +Install [just](https://github.com/casey/just) (`brew install just` or `cargo install just`), then: + +```bash +just setup # creates venv, installs Python + JS deps +just dev # starts backend + desktop app in one terminal +``` + +Other useful commands: + +```bash +just dev-web # backend + web app (no Tauri/Rust build) +just dev-backend # backend only +just kill # stop all dev processes +just clean-all # nuke everything and start fresh +just --list # see all available commands +``` + +**Using the Makefile:** Run `make setup` then `make dev`. See `make help` for all commands. **Manual setup (required for Windows):** diff --git a/justfile b/justfile new file mode 100644 index 00000000..b0e1981f --- /dev/null +++ b/justfile @@ -0,0 +1,189 @@ +# Voicebox development commands +# Install: brew install just (or cargo install just) +# Usage: just --list + +# Directories +backend_dir := "backend" +tauri_dir := "tauri" +app_dir := "app" +web_dir := "web" +venv := backend_dir / "venv" +venv_bin := venv / "bin" +python := venv_bin / "python" +pip := venv_bin / "pip" + +# Detect best python for venv creation +system_python := `command -v python3.12 2>/dev/null || command -v python3.13 2>/dev/null || echo python3` + +# ─── Setup ──────────────────────────────────────────────────────────── + +# Full project setup (python venv + JS deps + dev sidecar) +setup: setup-python setup-js + @echo "" + @echo "Setup complete! Run: just dev" + +# Create venv and install Python dependencies +setup-python: + #!/usr/bin/env bash + set -euo pipefail + if [ ! -d "{{ venv }}" ]; then + echo "Creating Python virtual environment..." + PY_MINOR=$({{ system_python }} -c "import sys; print(sys.version_info[1])") + if [ "$PY_MINOR" -gt 13 ]; then + echo "Warning: Python 3.$PY_MINOR detected. ML packages may not be compatible." + echo "Recommended: brew install python@3.12" + fi + {{ system_python }} -m venv {{ venv }} + fi + echo "Installing Python dependencies..." + {{ pip }} install --upgrade pip -q + {{ pip }} install -r {{ backend_dir }}/requirements.txt + # Apple Silicon: install MLX backend + if [ "$(uname -m)" = "arm64" ] && [ "$(uname)" = "Darwin" ]; then + echo "Detected Apple Silicon — installing MLX dependencies..." + {{ pip }} install -r {{ backend_dir }}/requirements-mlx.txt + fi + {{ pip }} install git+https://github.com/QwenLM/Qwen3-TTS.git + echo "Python environment ready." + +# Install JavaScript dependencies +setup-js: + bun install + +# ─── Development ────────────────────────────────────────────────────── + +# Start backend + frontend for development (two processes, one terminal) +dev: _ensure-venv _ensure-sidecar + #!/usr/bin/env bash + set -euo pipefail + trap 'kill 0' EXIT + + echo "Starting backend on http://localhost:17493 ..." + {{ venv_bin }}/uvicorn backend.main:app --reload --port 17493 & + sleep 2 + + echo "Starting Tauri desktop app..." + cd {{ tauri_dir }} && bun run tauri dev & + + wait + +# Start backend only +dev-backend: _ensure-venv + {{ venv_bin }}/uvicorn backend.main:app --reload --port 17493 + +# Start Tauri desktop app only (backend must be running separately) +dev-frontend: _ensure-sidecar + cd {{ tauri_dir }} && bun run tauri dev + +# Start backend + web app (no Tauri) +dev-web: _ensure-venv + #!/usr/bin/env bash + set -euo pipefail + trap 'kill 0' EXIT + {{ venv_bin }}/uvicorn backend.main:app --reload --port 17493 & + sleep 2 + cd {{ web_dir }} && bun run dev & + wait + +# Kill all dev processes +kill: + -pkill -f "uvicorn backend.main:app" 2>/dev/null || true + -pkill -f "vite" 2>/dev/null || true + @echo "Dev processes killed." + +# ─── Build ──────────────────────────────────────────────────────────── + +# Build everything (server binary + desktop app) +build: build-server build-tauri + +# Build Python server binary +build-server: _ensure-venv + PATH="{{ venv_bin }}:$PATH" ./scripts/build-server.sh + +# Build Tauri desktop app +build-tauri: + cd {{ tauri_dir }} && bun run tauri build + +# Build web app +build-web: + cd {{ web_dir }} && bun run build + +# ─── Code Quality ──────────────────────────────────────────────────── + +# Run all checks (lint + format + typecheck) +check: + bun run check + +# Lint with Biome +lint: + bun run lint + +# Format with Biome +format: + bun run format + +# Fix lint + format issues +fix: + bun run check:fix + +# ─── Database ───────────────────────────────────────────────────────── + +# Initialize SQLite database +db-init: _ensure-venv + cd {{ backend_dir }} && {{ python }} -c "from database import init_db; init_db()" + +# Reset database (delete + reinit) +db-reset: + rm -f {{ backend_dir }}/data/voicebox.db + just db-init + +# ─── Utilities ──────────────────────────────────────────────────────── + +# Generate TypeScript API client (backend must be running) +generate-api: + ./scripts/generate-api.sh + +# Open API docs in browser +docs: + open http://localhost:17493/docs 2>/dev/null || xdg-open http://localhost:17493/docs + +# Tail backend logs +logs: + tail -f {{ backend_dir }}/logs/*.log 2>/dev/null || echo "No log files found" + +# ─── Clean ──────────────────────────────────────────────────────────── + +# Clean build artifacts +clean: + rm -rf {{ tauri_dir }}/src-tauri/target/release + rm -rf {{ web_dir }}/dist + rm -rf {{ app_dir }}/dist + +# Clean Python venv and cache +clean-python: + rm -rf {{ venv }} + find {{ backend_dir }} -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true + +# Nuclear clean (everything including node_modules) +clean-all: clean clean-python + rm -rf node_modules + rm -rf {{ app_dir }}/node_modules + rm -rf {{ tauri_dir }}/node_modules + rm -rf {{ web_dir }}/node_modules + cd {{ tauri_dir }}/src-tauri && cargo clean + +# ─── Internal ───────────────────────────────────────────────────────── + +# Ensure venv exists (prompt to run setup if not) +[private] +_ensure-venv: + #!/usr/bin/env bash + if [ ! -d "{{ venv }}" ]; then + echo "Python venv not found. Run: just setup" + exit 1 + fi + +# Ensure Tauri dev sidecar placeholder exists +[private] +_ensure-sidecar: + bun run setup:dev