basemind 0.0.1

Code-map MCP server + scanner — content-addressed, Fjall-backed inverted index over tree-sitter outlines
name: Publish Packages

on:
  push:
    tags:
      - v[0-9]+.*
  workflow_dispatch:
    inputs:
      tag:
        description: "Release tag to publish (e.g., v0.1.0)"
        required: true
        type: string

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: write
  id-token: write

jobs:
  meta:
    name: Resolve versions
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.version }}
      python_version: ${{ steps.version.outputs.python_version }}
      tag: ${{ steps.version.outputs.tag }}
      crates_exists: ${{ steps.published.outputs.crates_exists }}
      npm_exists: ${{ steps.published.outputs.npm_exists }}
      pypi_exists: ${{ steps.published.outputs.pypi_exists }}
      release_assets_exist: ${{ steps.release_assets.outputs.release_assets_exist }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || '' }}

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: "20"

      - name: Extract version from tag
        id: version
        run: |
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            tag="${{ github.event.inputs.tag }}"
          else
            tag="${GITHUB_REF#refs/tags/}"
          fi

          version="${tag#v}"
          python_version="${version//-rc./rc}"

          {
            echo "version=$version"
            echo "python_version=$python_version"
            echo "tag=$tag"
          } >> "$GITHUB_OUTPUT"

          echo "Git tag: $tag"
          echo "Cargo/npm version: $version"
          echo "Python version: $python_version"

      - name: Detect already-published versions
        id: published
        run: |
          version="${{ steps.version.outputs.version }}"
          python_version="${{ steps.version.outputs.python_version }}"

          crates_exists=false
          if curl -fsS "https://crates.io/api/v1/crates/gitmind/${version}" >/dev/null; then
            crates_exists=true
          fi

          npm_exists=false
          if npm view "gitmind@${version}" version >/dev/null 2>&1; then
            npm_exists=true
          fi

          pypi_exists=false
          if curl -fsS "https://pypi.org/pypi/gitmind/${python_version}/json" >/dev/null; then
            pypi_exists=true
          fi

          {
            echo "crates_exists=$crates_exists"
            echo "npm_exists=$npm_exists"
            echo "pypi_exists=$pypi_exists"
          } >> "$GITHUB_OUTPUT"

          echo "Already published?"
          echo "  crates.io: $crates_exists"
          echo "  npm:       $npm_exists"
          echo "  PyPI:      $pypi_exists"

      - name: Detect existing GitHub release assets
        id: release_assets
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          tag="${{ steps.version.outputs.tag }}"
          release_assets_exist=false

          if gh release view "$tag" >/dev/null 2>&1; then
            count="$(gh release view "$tag" --json assets --jq '.assets | length')"
            if [ "${count:-0}" -gt 0 ]; then
              release_assets_exist=true
            fi
          fi

          echo "release_assets_exist=$release_assets_exist" >> "$GITHUB_OUTPUT"
          echo "GitHub release assets exist? $release_assets_exist"

  release_assets:
    name: Publish GitHub release assets
    needs: meta
    if: needs.meta.outputs.release_assets_exist != 'true'
    runs-on: macos-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || '' }}

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,x86_64-apple-darwin,aarch64-apple-darwin,x86_64-pc-windows-gnu

      - name: Install Zig
        run: brew install zig mingw-w64

      - name: Build and publish GitHub release assets
        uses: goreleaser/goreleaser-action@v7
        with:
          distribution: goreleaser
          version: "~> v2"
          args: release --clean --skip=validate
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TOKEN }}

  publish_crates:
    name: Publish crates.io
    needs: meta
    if: needs.meta.outputs.crates_exists != 'true'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || '' }}

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Authenticate to crates.io
        uses: rust-lang/crates-io-auth-action@v1
        id: crates_auth

      - name: Publish to crates.io
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.crates_auth.outputs.token }}
        run: |
          set -euo pipefail
          if cargo publish --allow-dirty 2>cargo-publish.err; then
            exit 0
          fi

          if grep -Eq "crate .* already exists" cargo-publish.err; then
            echo "crate already published; skipping"
            exit 0
          fi

          cat cargo-publish.err >&2
          exit 1

  publish_npm:
    name: Publish npm
    needs: meta
    if: needs.meta.outputs.npm_exists != 'true'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || '' }}

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: "20"
          registry-url: "https://registry.npmjs.org"

      - name: Update npm
        run: npm install -g npm@latest

      - name: Publish to npm
        env:
          NODE_AUTH_TOKEN: ""
        run: |
          unset NODE_AUTH_TOKEN
          cd npm-package
          version="${{ needs.meta.outputs.version }}"
          if [[ "$version" == *"-rc."* ]]; then
            npm_tag="beta"
          else
            npm_tag="latest"
          fi

          npm publish --provenance --access public --tag "$npm_tag"

  publish_pypi:
    name: Publish PyPI
    needs: meta
    if: needs.meta.outputs.pypi_exists != 'true'
    runs-on: ubuntu-latest
    environment: pypi
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || '' }}

      - name: Setup Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.8"

      - name: Build Python package
        run: |
          python -m pip install --upgrade pip
          python -m pip install build
          cd pip-package
          python -m build

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          packages-dir: pip-package/dist
          skip-existing: true