vibewatch 0.2.1

A file watcher utility with glob pattern support
vibewatch-0.2.1 is not a library.

VibeWatch

CI codecov Crates.io Downloads License Rust Version

A fast and extensible file watcher utility built in Rust with glob pattern support and cross-platform compatibility.

Features

  • Custom command execution: Run commands on file changes with event-specific triggers (--on-create, --on-modify, --on-delete, --on-change)
  • Template substitution: Use {file_path}, {relative_path}, {absolute_path}, {event_type} in commands
  • Cross-platform file watching: Fully tested on Linux, macOS, and Windows with platform-specific event handling
  • Glob pattern support: Include and exclude files using glob patterns like *.rs, node_modules/**
  • Extensible architecture: Clean separation of concerns for easy feature additions
  • Fast performance: Built in Rust for minimal resource usage
  • Flexible CLI: Intuitive command-line interface with verbose logging support
  • Comprehensive testing: 95.77% code coverage with 187 tests covering unit, filesystem, and integration scenarios

Installation

From crates.io (Recommended)

cargo install vibewatch

From Binary Releases

Download pre-built binaries for Linux, macOS, or Windows from the latest release.

From Source

Make sure you have Rust installed via mise or rustup:

# Clone and build
git clone https://github.com/rodrigogs/vibewatch.git
cd vibewatch
cargo build --release

⚡ Performance

vibewatch v0.2.0 includes significant performance optimizations:

  • 40-60% fewer memory allocations through static strings and optimized path handling
  • 15-30% faster event processing via async channels (tokio)
  • 80-95% fewer redundant commands with intelligent event debouncing
  • Proper shell parsing with quote support via shell-words crate

Benchmarks

Run comprehensive benchmarks yourself:

cargo bench                               # All benchmarks
cargo bench --bench template_substitution # Specific suite

The benchmark suite includes:

  • Template substitution - Single-pass vs multi-pass string operations
  • Path normalization - Platform-specific optimization validation
  • Pattern matching - Glob compilation and matching performance

See commit messages for detailed optimization rationale.

Usage

Command Execution on File Changes

The primary use case is executing commands when files change:

# Run tests on any change
vibewatch . --on-change "npm test"

# Format Rust files when modified
vibewatch src --include "*.rs" --on-modify "rustfmt {file_path}"

# Run linter on TypeScript files
vibewatch . --include "*.{ts,tsx}" --exclude "node_modules/**" --on-modify "npx eslint {file_path} --fix"

# Different commands for different events
vibewatch src \
  --on-create "git add {file_path}" \
  --on-modify "cargo check" \
  --on-delete "echo Removed: {relative_path}"

Available Templates:

  • {file_path} - Full path to the changed file
  • {relative_path} - Path relative to watched directory
  • {absolute_path} - Absolute path to the changed file
  • {event_type} - Type of event (create, modify, delete)

Watch-Only Mode

Watch a directory and log all file changes (no commands):

vibewatch /path/to/directory

Include Patterns

Watch only specific file types:

vibewatch /path/to/directory --include "*.rs" --include "*.ts"

Exclude Patterns

Ignore common directories and files:

vibewatch /path/to/directory --exclude "node_modules/**" --exclude ".git/**" --exclude "target/**"

Combined Patterns

Use both include and exclude patterns:

vibewatch . \
  --include "*.rs" \
  --include "*.ts" \
  --include "*.tsx" \
  --exclude "target/**" \
  --exclude "node_modules/**" \
  --verbose

Options

Directory:

  • <DIRECTORY>: Directory to watch (can be relative or absolute)

Command Execution:

  • --on-create <COMMAND>: Run command when files are created
  • --on-modify <COMMAND>: Run command when files are modified
  • --on-delete <COMMAND>: Run command when files are deleted
  • --on-change <COMMAND>: Run command on any file change (fallback)

Filtering:

  • -i, --include <PATTERN>: Include patterns like *.ts, *.tsx, *.rs
  • -e, --exclude <PATTERN>: Exclude patterns like node_modules/**, .git/**, .next/**

General:

  • -v, --verbose: Enable verbose output with debug logging
  • -h, --help: Show help message
  • -V, --version: Show version information

Examples

Auto-format TypeScript on save

vibewatch src \
  --include "*.ts" --include "*.tsx" \
  --exclude "node_modules/**" --exclude "dist/**" \
  --on-modify "npx prettier --write {file_path}"

Run Rust tests on file changes

vibewatch . \
  --include "*.rs" --include "Cargo.toml" \
  --exclude "target/**" \
  --on-change "cargo test"

Rebuild documentation on changes

vibewatch docs \
  --include "*.md" --include "*.rst" \
  --exclude "_build/**" \
  --on-change "mdbook build"

Watch and restart development server

vibewatch src \
  --include "*.js" --include "*.json" \
  --exclude "node_modules/**" \
  --on-change "pkill -f 'node server.js' && node server.js &"

Auto-commit on file creation

vibewatch src \
  --on-create "git add {file_path} && git commit -m 'Add {relative_path}'"

Architecture

The application is structured for extensibility:

  • main.rs: CLI argument parsing and application entry point
  • watcher.rs: Core file watching logic using the notify crate
  • filter.rs: Glob pattern matching for include/exclude functionality

Common Glob Patterns

Exclude Patterns

  • node_modules/** - Node.js dependencies
  • .git/** - Git repository files
  • .next/** - Next.js build files
  • target/** - Rust build directory
  • dist/** - Build output directory
  • *.tmp - Temporary files
  • *.swp - Vim swap files

Include Patterns

  • *.rs - Rust source files
  • *.ts, *.tsx - TypeScript files
  • *.js, *.jsx - JavaScript files
  • *.py - Python files
  • *.go - Go files
  • *.cpp, *.c, *.h - C/C++ files
  • *.md - Markdown files

Future Enhancements

The following features are planned for future releases:

  • Configuration file support: Store watch patterns and commands in .vibewatch.toml
  • Ignore file support: Respect .gitignore, .watchignore patterns

Requirements

  • Rust 1.70+ (managed via mise)
  • Unix-like system (macOS, Linux) or Windows

Development

Quick Start with Just

The project uses just for task automation:

# Install just (if not already installed)
cargo install just
# or: brew install just

# List all available tasks
just --list

# Common tasks
just test              # Run all tests
just coverage          # Generate coverage report
just lint              # Run linter
just check             # Run all checks (fmt, lint, test)
just demo              # Run vibewatch on src/ directory

Running Tests

# Run all tests (187 total: 140 unit + 21 filesystem + 26 integration)
cargo test
# or: just test

# Run tests with output
cargo test -- --nocapture
# or: just test-verbose

# Run specific test suite
cargo test --test it  # Integration tests only
# or: just test-integration test_name

Code Coverage

The project maintains 95.77% code coverage (996/1040 lines):

# Generate coverage report
cargo llvm-cov --all-features --workspace --html

# View report
open target/llvm-cov/html/index.html

Coverage by file:

  • filter.rs: 100.00% (190/190) ✅
  • main.rs: 98.05% (252/257) ✅
  • watcher.rs: 93.42% (554/593) ✅

Note: The remaining 4.23% uncovered lines are in main() and start_watching() functions that run as subprocesses during integration tests. Coverage tools cannot track across process boundaries. These lines are functionally tested through our comprehensive integration test suite.

Development Commands

# Run with debug logging
RUST_LOG=debug cargo run -- /path/to/directory --verbose

# Build for release
cargo build --release

# Run linter
cargo clippy

# Format code
cargo fmt

Contributing

Commit Message Convention

This project uses Conventional Commits for automated versioning and changelog generation.

Format: <type>(<optional scope>): <description>

Types:

  • feat: - New feature (triggers minor version bump)
  • fix: - Bug fix (triggers patch version bump)
  • docs: - Documentation changes
  • chore: - Maintenance tasks
  • refactor: - Code refactoring
  • test: - Adding or updating tests
  • feat!: or fix!: - Breaking changes (triggers major version bump)

Examples:

feat: add support for symlink watching
fix: resolve race condition in file detection
docs: update README with new examples
feat!: change CLI argument structure (breaking change)

Release Process

Releases are automated via Release Please:

  1. Commit using conventional commits - Each commit to master is analyzed
  2. Release PR is created - Release Please opens a PR with updated version and CHANGELOG
  3. Merge the Release PR - This triggers:
    • GitHub Release creation
    • Binary builds for Linux, macOS, Windows (x86_64, ARM64)
    • Optional publish to crates.io (if CARGO_TOKEN secret is configured)

Manual release: Just merge the automatically created "chore: release X.Y.Z" PR.

Setup Required: Release Please needs a Personal Access Token to create PRs. See docs/RELEASE_PLEASE_SETUP.md for detailed setup instructions.

CI/CD

All PRs and pushes to master run:

  • ✅ Tests (187 tests on Linux, macOS, Windows)
  • ✅ Formatting check (cargo fmt --check)
  • ✅ Linting (cargo clippy)
  • ✅ Coverage report (uploaded to Codecov)

Documentation

For comprehensive technical documentation:

  • Release Please Setup: docs/RELEASE_PLEASE_SETUP.md - Configure automated releases with PAT
  • Testing Guide: docs/TESTING.md - Test organization, best practices, and quick reference
  • Coverage Analysis: docs/COVERAGE.md - Detailed coverage metrics and industry benchmarks
  • Integration Tests: docs/INTEGRATION_TEST.md - Testing research, rationale, and best practices
  • Justfile Guide: docs/JUSTFILE_IMPLEMENTATION.md - Task runner implementation and benefits