# Contributing to Mole ## Setup ```bash # Install development tools brew install shfmt shellcheck bats-core # Install git hooks (validates universal binaries) ./scripts/setup-hooks.sh ``` ## Development Run all quality checks before committing: ```bash ./scripts/check.sh ``` This command runs: - Code formatting check - ShellCheck linting - Unit tests Individual commands: ```bash # Format code ./scripts/format.sh # Run tests only ./tests/run.sh ``` ## Code Style ### Basic Rules - Bash 3.2+ compatible (macOS default) - 4 spaces indent - Use `set -euo pipefail` in all scripts - Quote all variables: `"$variable"` - Use `[[ ]]` not `[ ]` for tests - Use `local` for function variables, `readonly` for constants - Function names: `snake_case` - BSD commands not GNU (e.g., `stat -f%z` not `stat --format`) Config: `.editorconfig` and `.shellcheckrc` ### File Operations **Always use safe wrappers, never `rm -rf` directly:** ```bash # Single file/directory safe_remove "/path/to/file" # Purge files older than 7 days safe_find_delete "$dir" "*.log" 7 "f" # With sudo safe_sudo_remove "/Library/Caches/com.example" ``` See `lib/core/file_ops.sh` for all safe functions. ### Pipefail Safety All commands that might fail must be handled: ```bash # Correct: handle failure find /nonexistent -name "*.cache" 2>/dev/null || true # Correct: check array before use if [[ ${#array[@]} -gt 0 ]]; then for item in "${array[@]}"; do process "$item" done fi # Correct: arithmetic operations ((count++)) || true ``` ### Error Handling ```bash # Network requests with timeout result=$(curl -fsSL --connect-timeout 2 --max-time 3 "$url" 2>/dev/null || echo "") # Command existence check if ! command -v brew >/dev/null 2>&1; then log_warning "Homebrew not installed" return 0 fi ``` ### UI and Logging ```bash # Logging log_info "Starting cleanup" log_success "Cache cleaned" log_warning "Some files skipped" log_error "Operation failed" # Spinners with_spinner "Cleaning cache" rm -rf "$cache_dir" # Or inline start_inline_spinner "Processing..." # ... work ... stop_inline_spinner "Complete" ``` ### Debug Mode Enable debug output with `--debug`: ```bash mo --debug clean ./bin/clean.sh --debug ``` Modules check the internal `MO_DEBUG` variable: ```bash if [[ "${MO_DEBUG:-0}" == "1" ]]; then echo "[MODULE] Debug message" >&2 fi ``` Format: `[MODULE_NAME] message` output to stderr. ## Requirements - macOS 10.14 or newer, works on Intel and Apple Silicon - Default macOS Bash 3.2+ plus administrator privileges for cleanup tasks - Install Command Line Tools with `xcode-select --install` for curl, tar, and related utilities - Go 1.24+ is required to build the `mo status` or `mo analyze` TUI binaries locally. ## Go Components `mo status` and `mo analyze` use Go with Bubble Tea for interactive dashboards. **Code organization:** - Each module split into focused files by responsibility - `cmd/analyze/` - Disk analyzer with 7 files under 500 lines each - `cmd/status/` - System monitor with metrics split into 11 domain files **Development workflow:** - Format code with `gofmt -w ./cmd/...` - Run `go vet ./cmd/...` to check for issues - Build with `go build ./...` to verify all packages compile **Building Universal Binaries:** ⚠️ **IMPORTANT**: Never use `go build` directly to create `bin/analyze-go` or `bin/status-go`! Mole must support both Intel and Apple Silicon Macs. Always use the build scripts: ```bash # Build universal binaries (x86_64 + arm64) ./scripts/build-analyze.sh ./scripts/build-status.sh ``` For local development/testing, you can use: - `go run ./cmd/status` or `go run ./cmd/analyze` (quick iteration) - `go build ./cmd/status` (creates single-arch binary for testing) The pre-commit hook will prevent you from accidentally committing non-universal binaries. **Guidelines:** - Keep files focused on single responsibility - Extract constants instead of magic numbers - Use context for timeout control on external commands - Add comments explaining **why** something is done, not just **what** is being done. ## Pull Requests 1. Fork and create branch 2. Make changes 3. Run checks: `./scripts/check.sh` 4. Commit and push 5. Open PR CI will verify formatting, linting, and tests.