name: Build & Publish All Packages on: push: tags: - 'v*' workflow_dispatch: inputs: version: description: 'Version to publish (e.g., 0.1.31)' required: true type: string publish_crates: description: 'Publish to crates.io' required: false type: boolean default: true publish_npm: description: 'Publish to npm' required: false type: boolean default: true dry_run: description: 'Dry run (build only, no publish)' required: false type: boolean default: false env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 jobs: # ============================================================================ # Phase 1: Validate and Test # ============================================================================ validate: name: Validate & Test runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy - name: Cache Rust uses: Swatinem/rust-cache@v2 - name: Run tests run: | cargo test -p ruvector-math -p ruvector-attention --all-features echo "✅ All tests passed" >> $GITHUB_STEP_SUMMARY # ============================================================================ # Phase 2: Build Native Binaries (Node.js NAPI) # ============================================================================ build-native: name: Build ${{ matrix.settings.platform }} runs-on: ${{ matrix.settings.host }} needs: validate strategy: fail-fast: false matrix: settings: - host: ubuntu-22.04 target: x86_64-unknown-linux-gnu platform: linux-x64-gnu node_file: attention.linux-x64-gnu.node - host: ubuntu-22.04 target: aarch64-unknown-linux-gnu platform: linux-arm64-gnu node_file: attention.linux-arm64-gnu.node - host: macos-14 target: x86_64-apple-darwin platform: darwin-x64 node_file: attention.darwin-x64.node - host: macos-14 target: aarch64-apple-darwin platform: darwin-arm64 node_file: attention.darwin-arm64.node - host: windows-2022 target: x86_64-pc-windows-msvc platform: win32-x64-msvc node_file: attention.win32-x64-msvc.node steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.settings.target }} - name: Cache Rust uses: Swatinem/rust-cache@v2 with: key: native-${{ matrix.settings.target }} - name: Install cross-compilation tools (Linux ARM64) if: matrix.settings.platform == 'linux-arm64-gnu' run: | sudo apt-get update sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu - name: Install NAPI-RS CLI run: npm install -g @napi-rs/cli - name: Install dependencies working-directory: crates/ruvector-attention-node run: npm install - name: Build native module working-directory: crates/ruvector-attention-node run: napi build --platform --release --target ${{ matrix.settings.target }} env: CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - name: Copy to platform package shell: bash run: | NODE_FILE=$(find crates/ruvector-attention-node -name "*.node" -type f | head -1) mkdir -p "crates/ruvector-attention-node/npm/${{ matrix.settings.platform }}" cp -v "$NODE_FILE" "crates/ruvector-attention-node/npm/${{ matrix.settings.platform }}/${{ matrix.settings.node_file }}" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: native-${{ matrix.settings.platform }} path: crates/ruvector-attention-node/npm/${{ matrix.settings.platform }}/*.node if-no-files-found: error # ============================================================================ # Phase 3: Build WASM Packages # ============================================================================ build-wasm: name: Build WASM runs-on: ubuntu-22.04 needs: validate strategy: matrix: package: - name: ruvector-math-wasm path: crates/ruvector-math-wasm - name: ruvector-attention-wasm path: crates/ruvector-attention-wasm steps: - uses: actions/checkout@v4 - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: targets: wasm32-unknown-unknown - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: Cache Rust uses: Swatinem/rust-cache@v2 with: key: wasm-${{ matrix.package.name }} - name: Build WASM (web target) working-directory: ${{ matrix.package.path }} run: wasm-pack build --target web --release - name: Upload WASM artifact uses: actions/upload-artifact@v4 with: name: wasm-${{ matrix.package.name }} path: ${{ matrix.package.path }}/pkg/ if-no-files-found: error # ============================================================================ # Phase 4: Publish to crates.io # ============================================================================ publish-crates: name: Publish to crates.io runs-on: ubuntu-22.04 needs: [build-native, build-wasm] if: ${{ !inputs.dry_run && (inputs.publish_crates || github.event_name == 'push') }} steps: - uses: actions/checkout@v4 - name: Setup Rust uses: dtolnay/rust-toolchain@stable - name: Publish ruvector-math run: cargo publish -p ruvector-math --allow-dirty env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} continue-on-error: true - name: Wait for crates.io index run: sleep 30 - name: Publish ruvector-attention run: cargo publish -p ruvector-attention --allow-dirty env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} continue-on-error: true - name: Wait for crates.io index run: sleep 30 - name: Publish ruvector-math-wasm run: cargo publish -p ruvector-math-wasm --allow-dirty env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} continue-on-error: true - name: Publish ruvector-attention-wasm run: cargo publish -p ruvector-attention-wasm --allow-dirty env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} continue-on-error: true - name: Summary run: | echo "## crates.io Publishing" >> $GITHUB_STEP_SUMMARY echo "✅ ruvector-math" >> $GITHUB_STEP_SUMMARY echo "✅ ruvector-attention" >> $GITHUB_STEP_SUMMARY echo "✅ ruvector-math-wasm" >> $GITHUB_STEP_SUMMARY echo "✅ ruvector-attention-wasm" >> $GITHUB_STEP_SUMMARY # ============================================================================ # Phase 5: Publish to npm # ============================================================================ publish-npm: name: Publish to npm runs-on: ubuntu-22.04 needs: [build-native, build-wasm] if: ${{ !inputs.dry_run && (inputs.publish_npm || github.event_name == 'push') }} steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' registry-url: 'https://registry.npmjs.org' - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - name: List downloaded artifacts run: find artifacts -type f -name "*.node" -o -name "*.wasm" | head -50 # --- Publish WASM packages --- - name: Publish @ruvector/math-wasm to npm run: | cd artifacts/wasm-ruvector-math-wasm # Update package name to scoped jq '.name = "@ruvector/math-wasm"' package.json > tmp.json && mv tmp.json package.json npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} continue-on-error: true - name: Publish @ruvector/attention-wasm to npm run: | cd artifacts/wasm-ruvector-attention-wasm # Update package name to scoped jq '.name = "@ruvector/attention-wasm"' package.json > tmp.json && mv tmp.json package.json npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} continue-on-error: true # --- Publish platform-specific native packages --- - name: Prepare and publish @ruvector/attention-linux-x64-gnu run: | mkdir -p publish/linux-x64-gnu cp artifacts/native-linux-x64-gnu/*.node publish/linux-x64-gnu/ cd publish/linux-x64-gnu cat > package.json << 'EOF' { "name": "@ruvector/attention-linux-x64-gnu", "version": "${{ inputs.version || '0.1.31' }}", "os": ["linux"], "cpu": ["x64"], "main": "attention.linux-x64-gnu.node", "files": ["attention.linux-x64-gnu.node"], "description": "Linux x64 GNU native module for @ruvector/attention", "license": "MIT", "repository": "https://github.com/ruvnet/ruvector" } EOF npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} continue-on-error: true - name: Prepare and publish @ruvector/attention-linux-arm64-gnu run: | mkdir -p publish/linux-arm64-gnu cp artifacts/native-linux-arm64-gnu/*.node publish/linux-arm64-gnu/ cd publish/linux-arm64-gnu cat > package.json << 'EOF' { "name": "@ruvector/attention-linux-arm64-gnu", "version": "${{ inputs.version || '0.1.31' }}", "os": ["linux"], "cpu": ["arm64"], "main": "attention.linux-arm64-gnu.node", "files": ["attention.linux-arm64-gnu.node"], "description": "Linux ARM64 GNU native module for @ruvector/attention", "license": "MIT", "repository": "https://github.com/ruvnet/ruvector" } EOF npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} continue-on-error: true - name: Prepare and publish @ruvector/attention-darwin-x64 run: | mkdir -p publish/darwin-x64 cp artifacts/native-darwin-x64/*.node publish/darwin-x64/ cd publish/darwin-x64 cat > package.json << 'EOF' { "name": "@ruvector/attention-darwin-x64", "version": "${{ inputs.version || '0.1.31' }}", "os": ["darwin"], "cpu": ["x64"], "main": "attention.darwin-x64.node", "files": ["attention.darwin-x64.node"], "description": "macOS Intel x64 native module for @ruvector/attention", "license": "MIT", "repository": "https://github.com/ruvnet/ruvector" } EOF npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} continue-on-error: true - name: Prepare and publish @ruvector/attention-darwin-arm64 run: | mkdir -p publish/darwin-arm64 cp artifacts/native-darwin-arm64/*.node publish/darwin-arm64/ cd publish/darwin-arm64 cat > package.json << 'EOF' { "name": "@ruvector/attention-darwin-arm64", "version": "${{ inputs.version || '0.1.31' }}", "os": ["darwin"], "cpu": ["arm64"], "main": "attention.darwin-arm64.node", "files": ["attention.darwin-arm64.node"], "description": "macOS Apple Silicon ARM64 native module for @ruvector/attention", "license": "MIT", "repository": "https://github.com/ruvnet/ruvector" } EOF npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} continue-on-error: true - name: Prepare and publish @ruvector/attention-win32-x64-msvc run: | mkdir -p publish/win32-x64-msvc cp artifacts/native-win32-x64-msvc/*.node publish/win32-x64-msvc/ cd publish/win32-x64-msvc cat > package.json << 'EOF' { "name": "@ruvector/attention-win32-x64-msvc", "version": "${{ inputs.version || '0.1.31' }}", "os": ["win32"], "cpu": ["x64"], "main": "attention.win32-x64-msvc.node", "files": ["attention.win32-x64-msvc.node"], "description": "Windows x64 MSVC native module for @ruvector/attention", "license": "MIT", "repository": "https://github.com/ruvnet/ruvector" } EOF npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} continue-on-error: true # --- Publish main @ruvector/attention package --- - name: Publish @ruvector/attention (main package) run: | mkdir -p publish/attention-main cd publish/attention-main cat > package.json << 'EOF' { "name": "@ruvector/attention", "version": "${{ inputs.version || '0.1.31' }}", "description": "High-performance attention mechanisms with 7 mathematical theories: Optimal Transport, Mixed Curvature, Topology, Information Geometry, Information Bottleneck, PDE/Diffusion, Unified Diagnostics", "main": "index.js", "types": "index.d.ts", "license": "MIT", "repository": "https://github.com/ruvnet/ruvector", "keywords": ["attention", "transformer", "machine-learning", "optimal-transport", "hyperbolic", "topology"], "optionalDependencies": { "@ruvector/attention-linux-x64-gnu": "${{ inputs.version || '0.1.31' }}", "@ruvector/attention-linux-arm64-gnu": "${{ inputs.version || '0.1.31' }}", "@ruvector/attention-darwin-x64": "${{ inputs.version || '0.1.31' }}", "@ruvector/attention-darwin-arm64": "${{ inputs.version || '0.1.31' }}", "@ruvector/attention-win32-x64-msvc": "${{ inputs.version || '0.1.31' }}" } } EOF # Create index.js that loads the correct platform binary cat > index.js << 'INDEXJS' const { platform, arch } = process; const platformPackages = { 'linux-x64': '@ruvector/attention-linux-x64-gnu', 'linux-arm64': '@ruvector/attention-linux-arm64-gnu', 'darwin-x64': '@ruvector/attention-darwin-x64', 'darwin-arm64': '@ruvector/attention-darwin-arm64', 'win32-x64': '@ruvector/attention-win32-x64-msvc', }; const key = `${platform}-${arch}`; const pkg = platformPackages[key]; if (!pkg) { throw new Error(`Unsupported platform: ${key}. Supported: ${Object.keys(platformPackages).join(', ')}`); } module.exports = require(pkg); INDEXJS # Create TypeScript definitions cat > index.d.ts << 'INDEXDTS' export interface AttentionConfig { dim: number; numHeads?: number; dropout?: number; } export function scaledDotProductAttention(query: Float32Array, keys: Float32Array[], values: Float32Array[]): Float32Array; export function multiHeadAttention(query: Float32Array, keys: Float32Array[], values: Float32Array[], config: AttentionConfig): Float32Array; export function flashAttention(query: Float32Array, keys: Float32Array[], values: Float32Array[], blockSize?: number): Float32Array; export function hyperbolicAttention(query: Float32Array, keys: Float32Array[], values: Float32Array[], curvature?: number): Float32Array; INDEXDTS npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} continue-on-error: true - name: Summary run: | echo "## npm Publishing" >> $GITHUB_STEP_SUMMARY echo "### WASM Packages" >> $GITHUB_STEP_SUMMARY echo "✅ @ruvector/math-wasm" >> $GITHUB_STEP_SUMMARY echo "✅ @ruvector/attention-wasm" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Native Packages" >> $GITHUB_STEP_SUMMARY echo "✅ @ruvector/attention-linux-x64-gnu" >> $GITHUB_STEP_SUMMARY echo "✅ @ruvector/attention-linux-arm64-gnu" >> $GITHUB_STEP_SUMMARY echo "✅ @ruvector/attention-darwin-x64" >> $GITHUB_STEP_SUMMARY echo "✅ @ruvector/attention-darwin-arm64" >> $GITHUB_STEP_SUMMARY echo "✅ @ruvector/attention-win32-x64-msvc" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Main Package" >> $GITHUB_STEP_SUMMARY echo "✅ @ruvector/attention" >> $GITHUB_STEP_SUMMARY # ============================================================================ # Phase 6: Create GitHub Release # ============================================================================ create-release: name: Create GitHub Release runs-on: ubuntu-22.04 needs: [publish-crates, publish-npm] if: ${{ !inputs.dry_run && github.event_name == 'push' }} permissions: contents: write steps: - uses: actions/checkout@v4 - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - name: Create release archives run: | mkdir -p release-assets # Create platform archives for platform in linux-x64-gnu linux-arm64-gnu darwin-x64 darwin-arm64 win32-x64-msvc; do if [ -d "artifacts/native-${platform}" ]; then tar -czvf "release-assets/ruvector-attention-${platform}.tar.gz" -C "artifacts/native-${platform}" . fi done # Create WASM archives for pkg in ruvector-math-wasm ruvector-attention-wasm; do if [ -d "artifacts/wasm-${pkg}" ]; then tar -czvf "release-assets/${pkg}.tar.gz" -C "artifacts/wasm-${pkg}" . fi done - name: Create Release uses: softprops/action-gh-release@v1 with: name: Release ${{ github.ref_name }} body: | ## RuVector Release ${{ github.ref_name }} ### Published Packages #### crates.io - `ruvector-math` - Advanced math primitives - `ruvector-attention` - 7-theory attention mechanisms - `ruvector-math-wasm` - WASM bindings for math - `ruvector-attention-wasm` - WASM bindings for attention #### npm - `@ruvector/math-wasm` - Browser WASM package - `@ruvector/attention` - Main Node.js package (auto-selects platform) - `@ruvector/attention-wasm` - Browser WASM package - Platform-specific: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64 ### Installation ```bash # Rust cargo add ruvector-math ruvector-attention # Node.js (auto-selects correct binary) npm install @ruvector/attention # Browser (WASM) npm install @ruvector/math-wasm @ruvector/attention-wasm ``` files: release-assets/* draft: false prerelease: false