name: Release

# Cut a release by pushing a version tag:
#
#   npm version patch          # or minor / major — bumps package.json + manifest, commits, tags
#   git push --follow-tags     # pushes the commit AND the v* tag
#
# The tag push triggers this workflow, which re-runs the full check suite, builds
# the Claude Desktop `.mcpb` bundle, and publishes a GitHub Release with the
# bundle attached + auto-generated notes. npm publishing stays manual by default;
# set repository variable TDMCP_AUTO_NPM_PUBLISH=true and NPM_TOKEN to opt in.

on:
  push:
    tags:
      - "v*"

# Least privilege by default; the job below elevates only what it needs.
permissions:
  contents: read

concurrency:
  group: release-${{ github.ref }}
  cancel-in-progress: false

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write # create the GitHub Release + upload the .mcpb asset
      id-token: write # npm publish provenance, used only when explicitly enabled
    steps:
      - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
        with:
          persist-credentials: false

      - name: Use Node.js 20
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: 20.x
          cache: npm
          registry-url: "https://registry.npmjs.org"

      - name: Verify tag matches package.json and manifest versions
        run: |
          TAG="${GITHUB_REF_NAME#v}"
          PKG="$(node -p "require('./package.json').version")"
          MANIFEST="$(node -p "require('./dxt/manifest.json').version")"
          SERVER="$(node -p "require('./server.json').version")"
          SERVER_PKG="$(node -p "require('./server.json').packages[0].version")"
          SAFESKILL="$(node -p "require('./safeskill.manifest.json').version")"
          echo "tag=$TAG  package.json=$PKG  manifest=$MANIFEST  server.json=$SERVER  server package=$SERVER_PKG  safeskill=$SAFESKILL"
          if [ "$TAG" != "$PKG" ]; then
            echo "::error::Tag v$TAG does not match package.json version $PKG. Bump with 'npm version' before tagging."
            exit 1
          fi
          if [ "$MANIFEST" != "$PKG" ]; then
            echo "::error::dxt/manifest.json version $MANIFEST does not match package.json $PKG (the 'version' npm script keeps them in sync)."
            exit 1
          fi
          if [ "$SERVER" != "$PKG" ]; then
            echo "::error::server.json version $SERVER does not match package.json $PKG."
            exit 1
          fi
          if [ "$SERVER_PKG" != "$PKG" ]; then
            echo "::error::server.json package version $SERVER_PKG does not match package.json $PKG."
            exit 1
          fi
          if [ "$SAFESKILL" != "$PKG" ]; then
            echo "::error::safeskill.manifest.json version $SAFESKILL does not match package.json $PKG."
            exit 1
          fi

      - name: Install dependencies
        run: npm ci

      - name: Import knowledge base
        run: npm run import:bottobot

      - name: Typecheck
        run: npm run typecheck

      - name: Lint
        run: npm run lint

      - name: Validate recipes
        run: npm run validate:recipes

      - name: Test
        run: npm test

      - name: Build
        run: npm run build

      - name: Build .mcpb bundle
        run: npm run build:mcpb

      - name: Test bridge (Python)
        run: npm run test:bridge

      - name: Publish GitHub Release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # A release may already exist if it was published from the GitHub UI
          # (publishing there creates the tag, which triggers this workflow). In
          # that case just (re)attach the bundle; otherwise create the release.
          if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
            gh release upload "$GITHUB_REF_NAME" tdmcp.mcpb --clobber
          else
            gh release create "$GITHUB_REF_NAME" tdmcp.mcpb \
              --title "$GITHUB_REF_NAME" \
              --generate-notes \
              --verify-tag
          fi

      - name: Check npm publish mode
        id: npm_publish
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
          AUTO_NPM_PUBLISH: ${{ vars.TDMCP_AUTO_NPM_PUBLISH }}
        run: |
          if [ "$AUTO_NPM_PUBLISH" = "true" ] && [ -n "$NPM_TOKEN" ]; then
            echo "enabled=true" >> "$GITHUB_OUTPUT"
          else
            echo "enabled=false" >> "$GITHUB_OUTPUT"
            {
              echo "### npm publish not run"
              echo ""
              if [ "$AUTO_NPM_PUBLISH" != "true" ]; then
                echo "Automatic npm publishing is disabled. Publish \`@dpantani/tdmcp@${GITHUB_REF_NAME#v}\` manually after reviewing the GitHub release."
              else
                echo "\`NPM_TOKEN\` is not set. Publish \`@dpantani/tdmcp@${GITHUB_REF_NAME#v}\` manually after reviewing the GitHub release."
              fi
            } >> "$GITHUB_STEP_SUMMARY"
          fi

      - name: Publish to npm
        if: steps.npm_publish.outputs.enabled == 'true'
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: |
          npm publish --access public --provenance
          {
            echo "### ✅ Published to npm"
            echo ""
            echo "\`@dpantani/tdmcp@${GITHUB_REF_NAME#v}\` is live on npm."
          } >> "$GITHUB_STEP_SUMMARY"
