beachcomber 0.4.0

A centralized daemon that caches shell state (git, battery, hostname, etc.) so every consumer reads from one fast cache instead of independently forking shells
Documentation
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  CARGO_TERM_COLOR: always

jobs:
  rust-version:
    name: Read Rust version
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.parse.outputs.version }}
    steps:
      - uses: actions/checkout@v4
      - name: Parse Rust version from mise.toml
        id: parse
        run: echo "version=$(grep '^rust' mise.toml | sed 's/.*"\(.*\)"/\1/')" >> "$GITHUB_OUTPUT"

  check:
    name: Check
    needs: rust-version
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ needs.rust-version.outputs.version }}
          components: clippy, rustfmt
      - uses: Swatinem/rust-cache@v2
      - name: Check
        run: cargo check --all-targets
      - name: Clippy
        run: cargo clippy --all-targets -- -D warnings
      - name: Format
        run: cargo fmt -- --check

  check-linux:
    name: Check (Linux)
    needs: rust-version
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ needs.rust-version.outputs.version }}
          components: clippy, rustfmt
      - uses: Swatinem/rust-cache@v2
      - name: Check
        run: cargo check --all-targets
      - name: Clippy
        run: cargo clippy --all-targets -- -D warnings
      - name: Format
        run: cargo fmt -- --check

  test:
    name: Test
    needs: rust-version
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ needs.rust-version.outputs.version }}
      - uses: Swatinem/rust-cache@v2
      - name: Run tests
        run: cargo test -- --skip watcher_ --skip uptime_provider_executes

  test-linux:
    name: Test (Linux)
    needs: rust-version
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ needs.rust-version.outputs.version }}
      - uses: Swatinem/rust-cache@v2
      - name: Run tests
        run: cargo test -- --skip watcher_

  bench:
    name: Benchmark
    needs: rust-version
    runs-on: macos-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ needs.rust-version.outputs.version }}
      - uses: Swatinem/rust-cache@v2
      - name: Run benchmarks
        run: cargo bench -- --output-format=bencher 2>/dev/null | tee bench-results.txt
      - name: Upload benchmark results
        uses: actions/upload-artifact@v4
        with:
          name: bench-results
          path: bench-results.txt

  test-python:
    name: Test Python SDK
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: sdks/python
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - name: Install dependencies
        run: pip install pytest
      - name: Run tests
        run: pytest -v

  test-node:
    name: Test Node.js SDK
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: sdks/node
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - name: Install dependencies
        run: npm ci
      - name: Build
        run: npm run build
      - name: Run tests
        run: npm test

  test-go:
    name: Test Go SDK
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: sdks/go
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.21'
      - name: Run tests
        run: go test -v ./...

  test-ruby:
    name: Test Ruby SDK
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: sdks/ruby
    steps:
      - uses: actions/checkout@v4
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.3'
      - name: Run tests
        run: rake test

  test-lua:
    name: Test Lua SDK
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: sdks/lua
    steps:
      - uses: actions/checkout@v4
      - uses: leafo/gh-actions-lua@v10
        with:
          luaVersion: '5.4'
      - uses: leafo/gh-actions-luarocks@v4
      - name: Install luasocket
        run: luarocks install luasocket
      - name: Run tests
        run: lua test/test_runner.lua

  test-c:
    name: Test C SDK
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: sdks/c
    steps:
      - uses: actions/checkout@v4
      - name: Build and test
        run: make test

  validate-npm-installer:
    name: Validate npm installer
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: placeholders/npm
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - name: Syntax check
        run: node --check install.js
      - name: Verify package.json is valid
        run: node -e "JSON.parse(require('fs').readFileSync('package.json', 'utf8'))"
      - name: Dry-run pack
        run: npm pack --dry-run

  validate-pypi-installer:
    name: Validate PyPI installer
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: placeholders/pypi
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - name: Syntax check
        run: python -m py_compile beachcomber_installer/__init__.py
      - name: Verify package builds
        run: pip install build && python -m build