name: Publish npm

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:

jobs:
  publish:
    name: Publish to npm
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      contents: read
      id-token: write

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - uses: oven-sh/setup-bun@v2
        with:
          bun-version: latest

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          registry-url: https://registry.npmjs.org

      - uses: mlugg/setup-zig@v2
        with:
          version: 0.15.2

      - name: Install dependencies
        run: bun install --frozen-lockfile

      - name: Get version
        id: version
        run: echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"

      - name: Replace workspace:* with version
        run: |
          VERSION=${{ steps.version.outputs.version }}
          for f in packages/*/package.json apps/cli/package.json; do
            if [ -f "$f" ]; then
              jq --arg v "$VERSION" '
                if .dependencies then
                  .dependencies |= with_entries(
                    if .value == "workspace:*" then .value = $v else . end
                  )
                else . end |
                if .devDependencies then
                  .devDependencies |= with_entries(
                    if .value == "workspace:*" then .value = $v else . end
                  )
                else . end
              ' "$f" > "$f.tmp" && mv "$f.tmp" "$f"
              echo "Updated $f"
            fi
          done

      - name: Checkout openpencil-skill
        uses: actions/checkout@v4
        with:
          repository: zseven-w/openpencil-skill
          path: external/openpencil-skill

      - name: Compile CLI
        env:
          SKILL_ROOT: ${{ github.workspace }}/external/openpencil-skill
        run: bun run cli:compile

      - name: Verify CLI build
        run: node apps/cli/dist/openpencil-cli.cjs --version

      # Publish in topological order. For each package:
      #   1. Resolve the real name from its package.json (no hand-written
      #      name — avoids drift between workflow and package manifest).
      #   2. Query the registry for that exact name@version. If it already
      #      exists, skip (idempotent re-runs of the same tag are safe).
      #   3. Otherwise, publish. Real errors (auth, network, notarize, etc.)
      #      still fail the step because we only skip on a verified hit.
      - name: Publish all packages (skip versions already on registry)
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
          VERSION: ${{ steps.version.outputs.version }}
        run: |
          set -euo pipefail
          PACKAGES=(
            packages/pen-types
            packages/pen-core
            packages/pen-figma
            packages/pen-renderer
            packages/pen-engine
            packages/pen-react
            packages/pen-mcp
            packages/pen-sdk
            packages/pen-ai-skills
            apps/cli
          )
          for dir in "${PACKAGES[@]}"; do
            name=$(jq -r .name "$dir/package.json")
            echo "::group::$name@$VERSION  ($dir)"
            if npm view "$name@$VERSION" version >/dev/null 2>&1; then
              echo "✓ already on registry — skipping"
            else
              ( cd "$dir" && npm publish --access public )
              echo "✓ published"
            fi
            echo "::endgroup::"
          done
