diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index aed3e01..e24547c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -58,7 +58,6 @@ body: value: | - SumVox version: (run `sumvox --version`) - OS: (e.g., macOS 14.1, Ubuntu 22.04) - - Rust version: (run `rustc --version`) - LLM provider: (e.g., Gemini, Claude) - TTS provider: (e.g., Google TTS, macOS say) validations: @@ -70,11 +69,13 @@ body: label: Configuration description: Please paste your config file (remove API keys!) placeholder: | - { - "version": "1.0.0", - "llm": { ... } - } - render: json + [[llm.providers]] + name = "google" + model = "..." + + [[tts.providers]] + name = "macos" + render: toml - type: textarea id: logs diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 75f3e42..7ddf777 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,5 @@ blank_issues_enabled: true contact_links: - - name: Question or Discussion - url: https://github.com/musingfox/sumvox/discussions - about: Ask questions or discuss ideas - name: Documentation url: https://github.com/musingfox/sumvox/blob/main/README.md about: Read the documentation diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ebc13ce..602c4ab 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,85 +1,7 @@ ## Description - + -## Type of Change +## Testing - - -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] Documentation update -- [ ] Performance improvement -- [ ] Code refactoring -- [ ] Test addition/update - -## Related Issues - - - -Closes # - -## Changes Made - - - -- -- -- - -## Testing Performed - - - -- [ ] All existing tests pass (`cargo test`) -- [ ] Added new tests for changes -- [ ] Manual testing performed -- [ ] Tested on macOS -- [ ] Tested on Linux - -### Test Details - - - -```bash -# Commands you ran for testing -cargo test -cargo run -- ... -``` - -## Configuration Changes - - - -```json -{ - "before": "...", - "after": "..." -} -``` - -## Checklist - - - -- [ ] My code follows the project's code style (`cargo fmt`) -- [ ] I have run clippy (`cargo clippy -- -D warnings`) -- [ ] I have added tests that prove my fix/feature works -- [ ] I have updated documentation (README, CLAUDE.md, etc.) -- [ ] My changes generate no new warnings -- [ ] I have added entries to CHANGELOG.md (if applicable) -- [ ] My commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) -- [ ] All tests pass locally - -## Screenshots/Logs - - - -``` -Paste relevant logs here -``` - -## Additional Context - - + diff --git a/CHANGELOG.md b/CHANGELOG.md index 49c419d..e19a03d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -343,6 +343,15 @@ When upgrading to v1.1.0: - Homebrew tap: `musingfox/sumvox` - Configuration: Edit YAML file directly instead of using environment variables +[Unreleased]: https://github.com/musingfox/sumvox/compare/v1.9.0...HEAD +[1.9.0]: https://github.com/musingfox/sumvox/releases/tag/v1.9.0 +[1.8.0]: https://github.com/musingfox/sumvox/releases/tag/v1.8.0 +[1.7.1]: https://github.com/musingfox/sumvox/releases/tag/v1.7.1 +[1.7.0]: https://github.com/musingfox/sumvox/releases/tag/v1.7.0 +[1.6.0]: https://github.com/musingfox/sumvox/releases/tag/v1.6.0 +[1.5.1]: https://github.com/musingfox/sumvox/releases/tag/v1.5.1 +[1.5.0]: https://github.com/musingfox/sumvox/releases/tag/v1.5.0 +[1.4.1]: https://github.com/musingfox/sumvox/releases/tag/v1.4.1 [1.4.0]: https://github.com/musingfox/sumvox/releases/tag/v1.4.0 [1.3.1]: https://github.com/musingfox/sumvox/releases/tag/v1.3.1 [1.3.0]: https://github.com/musingfox/sumvox/releases/tag/v1.3.0 diff --git a/CLAUDE.md b/CLAUDE.md index b72687a..7fbc2b2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,165 +1,27 @@ -# Project Configuration +# SumVox -## Overview +Rust CLI and Claude Code hook that summarizes AI coding sessions with an LLM and speaks the result. +Docs are only a cache: the code, `sumvox --help` and `config/recommended.toml` are the source of truth. -**Project**: SumVox -**Language**: Rust -**Type**: CLI Tool / Claude Code Hook -**Purpose**: Intelligent voice notifications for AI coding tools with multi-model LLM support +## Commands -## Task Management System +- `just check`: fmt check, clippy `-D warnings`, `cargo test` (hermetic: no network, no audio). +- `just test-e2e` (`cargo test --test e2e -- --ignored`): real APIs and audio; needs + `config/e2e_test.toml` copied from `config/e2e_test.toml.example`. -**System**: Local -**Location**: `.agents/tasks/` +## Gotchas -## Development Environment +- `config/e2e_test.toml` is gitignored but holds real keys: never force-add it, and stage files + by name rather than `git add -A` (a renamed copy is not ignored). +- No hard-coded provider, model or voice identities in runtime code. Config is the single source; + CLI flags only select a configured entry. +- `llvm-cov --branch` segfaults on the `async_trait` provider files (`src/llm/`, `src/tts/`): + exclude them from branch coverage. +- All playback goes through `src/audio/player.rs`; the summarize-then-speak flow lives in + `src/pipeline.rs`, shared by `say`, `sum`, `json` and the hooks. +- `src/notify_log.rs` (muted flag, `history.log`, `now_playing`) is the contract with the menu bar + app in `menubar/`; change both together. -### Build & Run +## Pointers -```bash -# Development build -cargo build - -# Release build (optimized) -cargo build --release - -# Run with debug logging -RUST_LOG=debug cargo run - -# Run tests -cargo test - -# Run with specific input -echo '{"session_id":"test",...}' | cargo run -``` - -### Configuration - -- **Main config**: `~/.config/sumvox/config.toml` -- **Hook script**: `.claude/hooks/run_sumvox_hook.sh` -- **Binary location**: `target/release/sumvox` -- **Example config**: `config/recommended.toml` - -### Environment Variables - -```bash -# Logging (optional) -export RUST_LOG=info # or debug, trace -``` - -**Note:** API keys are configured in `~/.config/sumvox/config.toml`, not as environment variables. - -## Testing - -```bash -# Run all tests -cargo test - -# Run tests with output -cargo test -- --nocapture - -# Run specific test -cargo test test_name - -# Run tests in specific module -cargo test llm:: -cargo test tts:: -``` - -## CLI Commands - -```bash -# Initialize config -sumvox init - -# Direct TTS -sumvox say "Hello world" - -# Summarize text -sumvox sum "Long text to summarize..." - -# Test with specific providers -sumvox say "Test" --tts macos --voice Daniel -``` - -## Architecture - -### Key Modules - -- `src/main.rs` - Entry point, hook orchestration -- `src/config.rs` - Configuration loading/saving -- `src/transcript.rs` - Claude Code transcript parsing -- `src/llm/` - Multi-provider LLM support (Gemini, Anthropic, OpenAI, xAI Grok, Ollama) -- `src/tts/` - Text-to-Speech engines (macOS say, espeak-ng, piper, Google TTS, Google Cloud TTS, xAI TTS, OpenAI TTS, ElevenLabs) -- `src/audio/` - Playback: `player.rs` is the single choke point (afplay on macOS, probed CLI player elsewhere) -- `src/pipeline.rs` - Shared summarize → speak flow used by `say`/`sum`/`json` and the hook handlers -- `src/provider_factory.rs` - Provider creation with fallback chain -- `src/notify_log.rs` - Mute flag, history log and now_playing file shared with the menu bar app - -### Configuration Format - -See `~/.config/sumvox/config.toml`: - -- LLM providers array with fallback chain -- TTS providers array with fallback chain -- Summarization settings (turns, prompt_template) -- Hook-specific configurations (notification_filter, tts_provider overrides) - -## Project Structure - -``` -sumvox/ -├── src/ -│ ├── main.rs # Entry point -│ ├── cli.rs # CLI parsing -│ ├── config.rs # Configuration loading/saving -│ ├── transcript.rs # Transcript parsing -│ ├── error.rs # Error types -│ ├── queue.rs # Serializes concurrent hook invocations -│ ├── notify_log.rs # History log + mute flag for the menu bar app -│ ├── hooks/ # Hook handlers -│ ├── pipeline.rs # Shared summarize → speak flow -│ ├── llm/ # LLM providers -│ ├── tts/ # TTS engines -│ ├── audio/ # Playback (player.rs, file.rs, normalize.rs, wav_header.rs) -│ └── provider_factory.rs -├── menubar/ -│ └── SumVoxMenu.swift # Optional macOS status bar app (just menubar) -├── config/ -│ └── recommended.toml # Example configuration with comments -├── .github/ -│ ├── workflows/ # CI/CD -│ └── ISSUE_TEMPLATE/ # Issue templates -├── homebrew/ -│ └── sumvox.rb # Homebrew formula -├── Cargo.toml -├── README.md -├── QUICKSTART.md -├── CHANGELOG.md -├── CONTRIBUTING.md -└── LICENSE -``` - -## Release Process - -See the "Release Process" section in [CONTRIBUTING.md](CONTRIBUTING.md) for detailed release steps. - -Quick version: - -```bash -# Using justfile -just release 1.0.0 - -# Or manually -git tag -a v1.0.0 -m "Release v1.0.0" -git push origin v1.0.0 -``` - -## Recommended Configuration - -See `config/recommended.toml` for the Gemini-based setup: - -- Google Gemini for LLM (tested and optimized) -- macOS TTS for notifications (fast and free) -- Google TTS for summaries (high quality) -- TOML format with inline comments for easy customization +Contributor workflow: CONTRIBUTING.md. Agent task state: `.agents/README.md`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b6c83dd..f127cd8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,481 +1,73 @@ # Contributing to SumVox -Thank you for your interest in contributing to SumVox! This guide will help you get started. +## Setup -## Code of Conduct - -Be respectful, constructive, and collaborative. We're all here to build better tools. - -## Development Setup - -### Prerequisites - -- A stable Rust toolchain (install via [rustup](https://rustup.rs/)) — CI builds on `stable` -- macOS or Linux. On Linux, install `espeak-ng` and an audio player (`ffplay`, `paplay`, ...) - so the local TTS path is exercisable -- API keys for testing (Gemini recommended) - -### Getting Started - -1. **Fork and clone** the repository: - ```bash - gh repo fork musingfox/sumvox --clone - cd sumvox - ``` - -2. **Build the project**: - ```bash - cargo build - ``` - -3. **Run tests**: - ```bash - cargo test - ``` - -4. **Set up development config**: - ```bash - cargo run -- init - # then edit ~/.config/sumvox/config.toml and set an API key - ``` - -### Project Structure - -``` -sumvox/ -├── src/ -│ ├── main.rs # Entry point and hook orchestration -│ ├── cli.rs # CLI argument parsing -│ ├── config.rs # Configuration loading, migration and saving -│ ├── pipeline.rs # Shared summarize -> speak flow (say / sum / json / hooks) -│ ├── transcript.rs # Claude Code transcript parsing -│ ├── queue.rs # Serializes concurrent hook invocations -│ ├── notify_log.rs # History log + mute flag for the menu bar app -│ ├── error.rs # Error types -│ ├── hooks/ # Hook handlers (claude_code.rs) -│ ├── llm/ # LLM providers (gemini, anthropic, openai, ollama, cost_tracker) -│ ├── tts/ # TTS engines (macos, espeak, piper, google, cloud_tts, -│ │ # openai, xai, elevenlabs) -│ ├── audio/ # Playback: player.rs (choke point), file.rs, normalize.rs, -│ │ # wav_header.rs -│ └── provider_factory.rs # LLM provider creation -├── config/ -│ ├── recommended.toml # Annotated reference configuration -│ └── e2e_test.toml.example # Template for the e2e suite's config -├── menubar/ # macOS menu bar companion app (Swift) -├── tests/ # Integration tests (e2e.rs, recommended_config.rs) -└── Cargo.toml # Dependencies and metadata -``` - -## Testing - -### Running Tests - -```bash -# All tests -cargo test - -# Specific module -cargo test llm:: -cargo test tts:: - -# With output -cargo test -- --nocapture -``` - -The `e2e` suite drives the built binary end to end and needs a real config: +You need a stable Rust toolchain (edition 2021) and [`just`](https://github.com/casey/just) +(`cargo install just`). `just` lists the available recipes. ```bash -cp config/e2e_test.toml.example config/e2e_test.toml # then fill in API keys -cargo test --test e2e -``` - -It runs on macOS and Linux from the same config — the harness rewrites the `macos` engine to -`espeak` on non-macOS hosts, so `espeak-ng` must be installed there. `SUMVOX_DISABLE` must not be -set in the shell, or the binary exits before doing anything. - -### Writing Tests - -- Unit tests: Add `#[cfg(test)]` modules in source files -- Integration tests: Add files to `tests/` directory -- Mock external APIs using `mockito` crate -- Test both success and error paths - -Example: -```rust -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_provider_fallback() { - // Test implementation - } -} +just check # cargo fmt --check, cargo clippy -- -D warnings, cargo test ``` -## Code Style +CI runs the same three checks. Commit subjects follow Conventional Commits +(`feat`, `fix`, `docs`, `refactor`, `test`, `chore`, ...), and user-visible changes get a line +under `[Unreleased]` in [CHANGELOG.md](CHANGELOG.md). -### Formatting +## Tests -- Use `rustfmt` for consistent formatting: - ```bash - cargo fmt - ``` - -### Linting +- `cargo test` is hermetic: no network, no audio, no API keys. Tests that need real audio are + `#[ignore]`d. +- `just test-e2e` (`cargo test --test e2e -- --ignored`) drives the built binary against real + APIs and plays audio. It reads `config/e2e_test.toml`: -- Run `clippy` before committing: ```bash - cargo clippy -- -D warnings + cp config/e2e_test.toml.example config/e2e_test.toml # then fill in API keys ``` -### Conventions - -- Use descriptive variable names -- Add comments for complex logic only -- Write self-documenting code -- Follow Rust naming conventions: - - `snake_case` for functions and variables - - `PascalCase` for types and structs - - `SCREAMING_SNAKE_CASE` for constants - -## Commit Messages - -We follow [Conventional Commits](https://www.conventionalcommits.org/): - -``` -(): - - - -