specsync 2.0.0

Bidirectional spec-to-code validation — language-agnostic, blazing fast
name: 'spec-sync'
description: 'Validate module specs against source code with SpecSync'
branding:
  icon: 'check-circle'
  color: 'green'

inputs:
  version:
    description: 'SpecSync version to use (e.g. "1.0.0" or "latest")'
    required: false
    default: 'latest'
  strict:
    description: 'Treat warnings as errors'
    required: false
    default: 'false'
  require-coverage:
    description: 'Minimum file coverage percentage (0-100)'
    required: false
    default: '0'
  root:
    description: 'Project root directory'
    required: false
    default: '.'
  args:
    description: 'Additional arguments to pass to specsync check'
    required: false
    default: ''

runs:
  using: 'composite'
  steps:
    - name: Download SpecSync
      shell: bash
      env:
        SPECSYNC_VERSION: ${{ inputs.version }}
      run: |
        set -euo pipefail

        # Detect OS
        case "$RUNNER_OS" in
          Linux)   OS="linux" ;;
          macOS)   OS="macos" ;;
          Windows) OS="windows" ;;
          *)
            echo "::error::Unsupported runner OS: $RUNNER_OS"
            exit 1
            ;;
        esac

        # Detect architecture
        ARCH="$(uname -m)"
        case "$ARCH" in
          x86_64|amd64)  ARCH="x86_64" ;;
          aarch64|arm64) ARCH="aarch64" ;;
          *)
            echo "::error::Unsupported architecture: $ARCH"
            exit 1
            ;;
        esac

        REPO="CorvidLabs/spec-sync"

        # Determine download URL
        if [ "$SPECSYNC_VERSION" = "latest" ]; then
          BASE_URL="https://github.com/${REPO}/releases/latest/download"
        else
          BASE_URL="https://github.com/${REPO}/releases/download/v${SPECSYNC_VERSION}"
        fi

        # Download and install
        INSTALL_DIR="${RUNNER_TEMP}/specsync"
        mkdir -p "$INSTALL_DIR"

        if [ "$OS" = "windows" ]; then
          ARCHIVE="specsync-${OS}-${ARCH}.exe.zip"
          curl -fsSL "${BASE_URL}/${ARCHIVE}" -o "${INSTALL_DIR}/specsync.zip"
          unzip -o "${INSTALL_DIR}/specsync.zip" -d "$INSTALL_DIR"
          mv "${INSTALL_DIR}/specsync-${OS}-${ARCH}.exe" "${INSTALL_DIR}/specsync.exe"
        else
          ARCHIVE="specsync-${OS}-${ARCH}.tar.gz"
          curl -fsSL "${BASE_URL}/${ARCHIVE}" | tar xz -C "$INSTALL_DIR"
          mv "${INSTALL_DIR}/specsync-${OS}-${ARCH}" "${INSTALL_DIR}/specsync"
          chmod +x "${INSTALL_DIR}/specsync"
        fi

        # Add to PATH
        echo "${INSTALL_DIR}" >> "$GITHUB_PATH"
        echo "::notice::SpecSync installed (${OS}/${ARCH}) from ${BASE_URL}/${ARCHIVE}"

    - name: Run SpecSync
      shell: bash
      working-directory: ${{ inputs.root }}
      env:
        INPUT_STRICT: ${{ inputs.strict }}
        INPUT_REQUIRE_COVERAGE: ${{ inputs.require-coverage }}
        INPUT_ARGS: ${{ inputs.args }}
      run: |
        set -euo pipefail

        CMD="specsync check"

        if [ "$INPUT_STRICT" = "true" ]; then
          CMD="$CMD --strict"
        fi

        if [ "$INPUT_REQUIRE_COVERAGE" != "0" ]; then
          CMD="$CMD --require-coverage $INPUT_REQUIRE_COVERAGE"
        fi

        if [ -n "$INPUT_ARGS" ]; then
          CMD="$CMD $INPUT_ARGS"
        fi

        echo "::group::SpecSync Check"
        echo "Running: $CMD"
        eval "$CMD"
        echo "::endgroup::"