lwc 0.17.11

Agent-driven proactive memory CLI for AI agents — autonomously recall, maintain, and evolve persistent, source-grounded knowledge across sessions.
name: Build release artifacts

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

permissions:
  contents: read

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

jobs:
  quality:
    name: Release acceptance gates
    runs-on: ubuntu-24.04
    timeout-minutes: 45

    steps:
      - uses: actions/checkout@v7

      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - uses: actions/setup-node@v6
        with:
          node-version: "24"
          package-manager-cache: false

      - uses: Swatinem/rust-cache@v2
        with:
          key: release-quality
          cache-targets: false

      - name: Viewer
        working-directory: web
        run: |
          npm ci
          npm test
          npm run typecheck
          npm run build
          git diff --exit-code -- dist

      - name: Format
        run: cargo fmt --all -- --check

      - name: Clippy
        run: cargo clippy --locked --all-targets --all-features -- -D warnings

      - name: Full test suite
        run: cargo test --locked --all-targets --all-features

      - name: npm package
        run: node --test tests/npm_package.mjs

      - name: Fallback build and tests
        run: cargo test --locked --all-targets --no-default-features

      - name: Release graph benchmark budgets
        run: >-
          cargo test --locked --release --test graph_benchmark
          external_graph_rebuild_and_update_are_document_granular
          -- --ignored --nocapture

      - name: Package verification
        env:
          CARGO_TARGET_DIR: ${{ runner.temp }}/lwc-package-target
        run: cargo package --locked

  build:
    needs: quality
    name: ${{ matrix.target }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - runner: macos-15-intel
            target: x86_64-apple-darwin
            archive: tar
          - runner: macos-15
            target: aarch64-apple-darwin
            archive: tar
          - runner: ubuntu-24.04
            target: x86_64-unknown-linux-gnu
            archive: tar
          - runner: ubuntu-24.04-arm
            target: aarch64-unknown-linux-gnu
            archive: tar
          - runner: windows-2025
            target: x86_64-pc-windows-msvc
            archive: zip
          - runner: windows-11-arm
            target: aarch64-pc-windows-msvc
            archive: zip
    runs-on: ${{ matrix.runner }}
    timeout-minutes: 45

    steps:
      - uses: actions/checkout@v7

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - uses: Swatinem/rust-cache@v2
        with:
          key: ${{ matrix.target }}

      - name: Test
        run: cargo test --locked --release --target ${{ matrix.target }}

      - name: Build
        run: cargo build --locked --release --target ${{ matrix.target }} --bins

      - name: Smoke test Unix binary
        if: matrix.archive == 'tar'
        shell: bash
        run: |
          project="$(mktemp -d)"
          cd "$project"
          "${GITHUB_WORKSPACE}/target/${{ matrix.target }}/release/lwc" init
          "${GITHUB_WORKSPACE}/target/${{ matrix.target }}/release/lwc" config show
          "${GITHUB_WORKSPACE}/target/${{ matrix.target }}/release/lwc" graph status

      - name: Smoke test Windows binary
        if: matrix.archive == 'zip'
        shell: pwsh
        run: |
          $project = Join-Path $env:RUNNER_TEMP "lwc-smoke"
          New-Item -ItemType Directory -Force -Path $project | Out-Null
          Push-Location $project
          & "$env:GITHUB_WORKSPACE\target\${{ matrix.target }}\release\lwc.exe" init
          & "$env:GITHUB_WORKSPACE\target\${{ matrix.target }}\release\lwc.exe" config show
          & "$env:GITHUB_WORKSPACE\target\${{ matrix.target }}\release\lwc.exe" graph status
          Pop-Location

      - name: Package Unix archive
        if: matrix.archive == 'tar'
        shell: bash
        run: |
          version="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -1)"
          archive="lwc-${version}-${{ matrix.target }}"
          mkdir -p "dist/${archive}"
          cp "target/${{ matrix.target }}/release/lwc" "dist/${archive}/"
          cp README.md README.zh-CN.md LICENSE "dist/${archive}/"
          tar -C dist -czf "dist/${archive}.tar.gz" "${archive}"
          cd dist
          shasum -a 256 "${archive}.tar.gz" > "${archive}.tar.gz.sha256"
          cd ..
          for plugin in tutor book practice; do
            archive="lwc-${plugin}-${version}-${{ matrix.target }}"
            mkdir -p "dist/${archive}"
            cp "target/${{ matrix.target }}/release/lwc-${plugin}" "dist/${archive}/"
            tar -C dist -czf "dist/${archive}.tar.gz" "${archive}"
            (
              cd dist
              shasum -a 256 "${archive}.tar.gz" > "${archive}.tar.gz.sha256"
            )
          done

      - name: Package Windows archive
        if: matrix.archive == 'zip'
        shell: pwsh
        run: |
          $version = (Select-String '^version = "([^"]+)"' Cargo.toml).Matches[0].Groups[1].Value
          $archive = "lwc-$version-${{ matrix.target }}"
          $stage = Join-Path dist $archive
          New-Item -ItemType Directory -Force -Path $stage | Out-Null
          Copy-Item "target\${{ matrix.target }}\release\lwc.exe" $stage
          Copy-Item README.md, README.zh-CN.md, LICENSE $stage
          Compress-Archive -Path $stage -DestinationPath "dist\$archive.zip"
          $hash = (Get-FileHash "dist\$archive.zip" -Algorithm SHA256).Hash.ToLower()
          "$hash  $archive.zip" | Set-Content "dist\$archive.zip.sha256" -Encoding ascii
          foreach ($plugin in @("tutor", "book", "practice")) {
            $archive = "lwc-$plugin-$version-${{ matrix.target }}"
            $stage = Join-Path dist $archive
            New-Item -ItemType Directory -Force -Path $stage | Out-Null
            Copy-Item "target\${{ matrix.target }}\release\lwc-$plugin.exe" $stage
            Compress-Archive -Path $stage -DestinationPath "dist\$archive.zip"
            $hash = (Get-FileHash "dist\$archive.zip" -Algorithm SHA256).Hash.ToLower()
            "$hash  $archive.zip" | Set-Content "dist\$archive.zip.sha256" -Encoding ascii
          }

      - name: Upload archive
        uses: actions/upload-artifact@v4
        with:
          name: lwc-${{ matrix.target }}
          path: |
            dist/*.tar.gz
            dist/*.tar.gz.sha256
            dist/*.zip
            dist/*.zip.sha256
          if-no-files-found: error
          compression-level: 0

  checksums:
    name: Combined checksums
    needs: build
    runs-on: ubuntu-24.04
    timeout-minutes: 5

    steps:
      - uses: actions/download-artifact@v4
        with:
          pattern: lwc-*
          path: artifacts
          merge-multiple: true

      - name: Combine checksums
        run: find artifacts -type f -name '*.sha256' -exec cat {} + | tr -d '\r' | sort -k2 > SHA256SUMS

      - uses: actions/upload-artifact@v4
        with:
          name: lwc-checksums
          path: SHA256SUMS
          if-no-files-found: error

  release:
    name: Publish GitHub Release
    if: startsWith(github.ref, 'refs/tags/v')
    needs:
      - build
      - checksums
    runs-on: ubuntu-24.04
    timeout-minutes: 10
    permissions:
      contents: write

    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0

      - uses: actions/download-artifact@v4
        with:
          pattern: lwc-*
          path: release-assets
          merge-multiple: true

      - uses: actions/setup-node@v6
        with:
          node-version: "24"
          package-manager-cache: false

      - name: Validate annotated release notes
        shell: bash
        run: |
          test "$(git cat-file -t "${GITHUB_REF_NAME}")" = "tag"
          notes="$(git for-each-ref --format='%(contents)' "refs/tags/${GITHUB_REF_NAME}")"
          test -n "$(printf '%s' "$notes" | tr -d '[:space:]')"
          printf '%s\n' "$notes" > "${RUNNER_TEMP}/release-notes.md"

      - name: Publish release assets
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh release create "${GITHUB_REF_NAME}" \
            --repo "${GITHUB_REPOSITORY}" \
            --verify-tag \
            --title "lwc ${GITHUB_REF_NAME}" \
            --notes-file "${RUNNER_TEMP}/release-notes.md" \
            release-assets/*.tar.gz \
            release-assets/*.zip \
            release-assets/SHA256SUMS \
            install.sh

      - name: Smoke npm installer against release assets
        run: |
          npm install --global ./npm --prefix "${RUNNER_TEMP}/lwc-npm"
          "${RUNNER_TEMP}/lwc-npm/bin/lwc" --version