docs(adf): add research and design documents for LLM client auto-conf… #196
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Comprehensive Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| - 'terraphim_server-v*' | |
| - 'terraphim-ai-desktop-v*' | |
| - 'terraphim_agent-v*' | |
| - 'terraphim_grep-v*' | |
| workflow_dispatch: | |
| inputs: | |
| test_run: | |
| description: 'Test run without creating release' | |
| required: false | |
| default: false | |
| type: boolean | |
| permissions: | |
| contents: write | |
| packages: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| verify-versions: | |
| name: Verify version consistency | |
| runs-on: ubuntu-22.04 | |
| continue-on-error: true | |
| outputs: | |
| version: ${{ steps.extract.outputs.version }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Extract version from tag | |
| id: extract | |
| run: | | |
| # Get the tag name | |
| TAG="${{ github.ref_name }}" | |
| echo "Tag: $TAG" | |
| # Extract version (strip v prefix and any component prefix) | |
| if [[ "$TAG" == *"-v"* ]]; then | |
| # Component-specific tag like terraphim_agent-v1.5.2 | |
| VERSION="${TAG##*-v}" | |
| elif [[ "$TAG" == v* ]]; then | |
| # Standard version tag like v1.5.2 | |
| VERSION="${TAG#v}" | |
| else | |
| echo "::error::Invalid tag format: $TAG (expected v* or component-v*)" | |
| exit 1 | |
| fi | |
| echo "Extracted version: $VERSION" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| # Also set as env var for fallback | |
| echo "VERSION_FALLBACK=$VERSION" >> $GITHUB_ENV | |
| - name: Verify Cargo.toml versions match tag | |
| env: | |
| EXPECTED_VERSION: ${{ steps.extract.outputs.version }} | |
| run: | | |
| echo "Expected version: $EXPECTED_VERSION" | |
| # Get workspace version | |
| WORKSPACE_VERSION=$(cargo metadata --no-deps --format-version=1 | jq -r '.packages[] | select(.name == "terraphim_server") | .version') | |
| echo "Workspace version (from terraphim_server): $WORKSPACE_VERSION" | |
| # Check key binaries | |
| BINARIES=("terraphim_server" "terraphim_agent" "terraphim-cli" "terraphim_grep") | |
| FAILED=0 | |
| for pkg in "${BINARIES[@]}"; do | |
| PKG_VERSION=$(cargo metadata --no-deps --format-version=1 | jq -r --arg name "$pkg" '.packages[] | select(.name == $name) | .version') | |
| echo "Package $pkg version: $PKG_VERSION" | |
| if [ "$PKG_VERSION" != "$EXPECTED_VERSION" ]; then | |
| echo "::error::Version mismatch for $pkg: expected $EXPECTED_VERSION, got $PKG_VERSION" | |
| FAILED=1 | |
| fi | |
| done | |
| if [ $FAILED -eq 1 ]; then | |
| echo "" | |
| echo "::error::Version verification failed! Update workspace.package.version in Cargo.toml to match the release tag." | |
| echo "Run: cargo metadata --no-deps --format-version=1 | jq '.packages[] | {name: .name, version: .version}' to see all versions" | |
| exit 1 | |
| fi | |
| echo "All versions match expected: $EXPECTED_VERSION" | |
| build-binaries: | |
| name: Build binaries for ${{ matrix.target }} | |
| needs: verify-versions | |
| # Only build if version verification passed | |
| if: needs.verify-versions.result == 'success' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Linux builds -- run on bigbox self-hosted runner for faster Docker | |
| # access (cross uses Docker for musl targets) and to keep paid runner | |
| # minutes for the macOS notarise + Windows builds that bigbox can't host. | |
| - os: [self-hosted, bigbox] | |
| target: x86_64-unknown-linux-gnu | |
| use_cross: false | |
| - os: [self-hosted, bigbox] | |
| target: x86_64-unknown-linux-musl | |
| use_cross: true | |
| - os: [self-hosted, bigbox] | |
| target: aarch64-unknown-linux-musl | |
| use_cross: true | |
| # NOTE: armv7 removed - neo_frizbee dependency doesn't support 32-bit | |
| # - os: [self-hosted, bigbox] | |
| # target: armv7-unknown-linux-musleabihf | |
| # use_cross: true | |
| # macOS builds -- both run on self-hosted Apple Silicon Mac | |
| # (has zig installed for zlob dependency, can build both architectures) | |
| - os: [self-hosted, macOS] | |
| target: x86_64-apple-darwin | |
| use_cross: false | |
| - os: [self-hosted, macOS] | |
| target: aarch64-apple-darwin | |
| use_cross: false | |
| # Windows builds | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| use_cross: false | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Cleanup self-hosted runner | |
| if: contains(matrix.os, 'self-hosted') | |
| run: | | |
| # Clean up stale keychains from previous runs | |
| find /tmp -name "*.keychain-db" -mmin +60 -delete 2>/dev/null || true | |
| find /tmp -name "signing.keychain*" -delete 2>/dev/null || true | |
| # Clean up stale certificates | |
| find /tmp -name "certificate.p12" -delete 2>/dev/null || true | |
| # Clean up old build artifacts | |
| rm -rf ~/actions-runner/_work/terraphim-ai/terraphim-ai/target/release/*.zip 2>/dev/null || true | |
| echo "Cleanup completed" | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install zig (required by zlob dependency) | |
| if: contains(matrix.target, 'apple-darwin') || contains(matrix.target, 'windows') | |
| shell: bash | |
| run: | | |
| if command -v zig &>/dev/null; then | |
| echo "zig already installed" | |
| elif command -v brew &>/dev/null; then | |
| brew install zig | |
| elif command -v choco &>/dev/null; then | |
| choco install zig -y | |
| else | |
| echo "No package manager found for zig installation" | |
| exit 1 | |
| fi | |
| zig version | |
| - name: Install cross | |
| if: matrix.use_cross | |
| run: cargo install cross | |
| - name: Clear cross custom images | |
| if: matrix.use_cross | |
| run: docker rmi $(docker images -q cross-custom-*) 2>/dev/null || true | |
| - name: Setup zig for cross builds | |
| if: matrix.use_cross | |
| run: | | |
| # Mount bigbox's zig installation into cross containers | |
| # Bigbox has zig 0.16.0 installed at /usr/local/zig-x86_64-linux-0.16.0/ | |
| ZIG_INSTALL="/usr/local/zig-x86_64-linux-0.16.0" | |
| ZIG_BIN="$ZIG_INSTALL/zig" | |
| ZIG_OPTS="-v $ZIG_INSTALL:$ZIG_INSTALL" | |
| ZIG_OPTS="$ZIG_OPTS -e ZIG=$ZIG_BIN" | |
| ZIG_OPTS="$ZIG_OPTS -e ZIG_GLOBAL_CACHE_DIR=/tmp/zig-global-cache" | |
| ZIG_OPTS="$ZIG_OPTS -e ZIG_LOCAL_CACHE_DIR=/tmp/zig-local-cache" | |
| echo "CROSS_CONTAINER_OPTS=$ZIG_OPTS" >> $GITHUB_ENV | |
| echo "ZIG=$ZIG_BIN" >> $GITHUB_ENV | |
| - name: Cache dependencies | |
| if: matrix.target != 'x86_64-unknown-linux-gnu' | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: ${{ matrix.os }}-${{ matrix.target }} | |
| - name: Setup Node.js (for frontend build) | |
| if: "!matrix.use_cross" | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 20 | |
| cache: yarn | |
| cache-dependency-path: desktop/yarn.lock | |
| - name: Build frontend assets | |
| if: "!matrix.use_cross" | |
| working-directory: ./desktop | |
| run: | | |
| yarn install --frozen-lockfile | |
| yarn build | |
| - name: Copy frontend to server dist for rust-embed (Unix) | |
| if: "!matrix.use_cross && matrix.os != 'windows-latest'" | |
| run: | | |
| rm -r terraphim_server/dist/assets 2>/dev/null || true | |
| cp -a desktop/dist/. terraphim_server/dist/ | |
| # Verify frontend assets | |
| echo "Frontend assets copied to terraphim_server/dist/:" | |
| ls -la terraphim_server/dist/ | |
| # Force rebuild by touching build.rs | |
| touch terraphim_server/build.rs | |
| - name: Copy frontend to server dist for rust-embed (Windows) | |
| if: "matrix.os == 'windows-latest'" | |
| shell: pwsh | |
| run: | | |
| # Create dist directory if it doesn't exist | |
| New-Item -ItemType Directory -Force -Path terraphim_server/dist | |
| # Remove old assets if they exist | |
| Remove-Item -Recurse -Force terraphim_server/dist/assets -ErrorAction SilentlyContinue | |
| # Copy frontend assets | |
| Copy-Item -Recurse -Force desktop/dist/* terraphim_server/dist/ | |
| # Verify | |
| Get-ChildItem terraphim_server/dist/ | |
| # Touch build.rs to force rebuild | |
| (Get-Item terraphim_server/build.rs).LastWriteTime = Get-Date | |
| - name: Build server binary | |
| if: "!matrix.use_cross" | |
| shell: bash | |
| run: | | |
| # Clean to ensure fresh UI embedding | |
| cargo clean -p terraphim_server --target ${{ matrix.target }} | |
| # Build with fresh UI | |
| cargo build --release \ | |
| --target ${{ matrix.target }} -p terraphim_server --bin terraphim_server | |
| - name: Build TUI binary | |
| shell: bash | |
| run: | | |
| ${{ matrix.use_cross && 'cross' || 'cargo' }} build --release \ | |
| --target ${{ matrix.target }} -p terraphim_agent --bin terraphim-agent | |
| - name: Build CLI binary | |
| shell: bash | |
| run: | | |
| ${{ matrix.use_cross && 'cross' || 'cargo' }} build --release \ | |
| --target ${{ matrix.target }} -p terraphim-cli --bin terraphim-cli | |
| - name: Build Grep binary | |
| shell: bash | |
| run: | | |
| ${{ matrix.use_cross && 'cross' || 'cargo' }} build --release \ | |
| --target ${{ matrix.target }} -p terraphim_grep --bin terraphim-grep \ | |
| --features "code-search openrouter" | |
| - name: Verify binary versions (native builds only) | |
| if: matrix.target == 'x86_64-unknown-linux-gnu' | |
| shell: bash | |
| env: | |
| EXPECTED_VERSION: ${{ needs.verify-versions.outputs.version }} | |
| run: | | |
| echo "Verifying binary --version output matches expected: $EXPECTED_VERSION" | |
| # Verify terraphim-agent | |
| AGENT_VERSION=$(./target/${{ matrix.target }}/release/terraphim-agent --version 2>&1 | head -1) | |
| echo "terraphim-agent: $AGENT_VERSION" | |
| if [[ "$AGENT_VERSION" != *"$EXPECTED_VERSION"* ]]; then | |
| echo "::error::terraphim-agent version mismatch: expected $EXPECTED_VERSION in '$AGENT_VERSION'" | |
| exit 1 | |
| fi | |
| # Verify terraphim-cli | |
| CLI_VERSION=$(./target/${{ matrix.target }}/release/terraphim-cli --version 2>&1 | head -1) | |
| echo "terraphim-cli: $CLI_VERSION" | |
| if [[ "$CLI_VERSION" != *"$EXPECTED_VERSION"* ]]; then | |
| echo "::error::terraphim-cli version mismatch: expected $EXPECTED_VERSION in '$CLI_VERSION'" | |
| exit 1 | |
| fi | |
| # Verify terraphim_server | |
| SERVER_VERSION=$(./target/${{ matrix.target }}/release/terraphim_server --version 2>&1 | head -1) | |
| echo "terraphim_server: $SERVER_VERSION" | |
| if [[ "$SERVER_VERSION" != *"$EXPECTED_VERSION"* ]]; then | |
| echo "::error::terraphim_server version mismatch: expected $EXPECTED_VERSION in '$SERVER_VERSION'" | |
| exit 1 | |
| fi | |
| # Verify terraphim-grep | |
| GREP_VERSION=$(./target/${{ matrix.target }}/release/terraphim-grep --version 2>&1 | head -1) | |
| echo "terraphim-grep: $GREP_VERSION" | |
| if [[ "$GREP_VERSION" != *"$EXPECTED_VERSION"* ]]; then | |
| echo "::error::terraphim-grep version mismatch: expected $EXPECTED_VERSION in '$GREP_VERSION'" | |
| exit 1 | |
| fi | |
| echo "All binary versions verified successfully!" | |
| - name: Prepare artifacts (Unix) | |
| if: matrix.os != 'windows-latest' | |
| env: | |
| VERSION: ${{ needs.verify-versions.outputs.version }} | |
| run: | | |
| mkdir -p artifacts | |
| # Create tar.gz archives with version in filename for auto-update compatibility | |
| # Server binary only exists for non-cross builds | |
| if [ -f "target/${{ matrix.target }}/release/terraphim_server" ]; then | |
| tar -czf "artifacts/terraphim_server-${VERSION}-${{ matrix.target }}.tar.gz" \ | |
| -C "target/${{ matrix.target }}/release" terraphim_server | |
| fi | |
| tar -czf "artifacts/terraphim-agent-${VERSION}-${{ matrix.target }}.tar.gz" \ | |
| -C "target/${{ matrix.target }}/release" terraphim-agent | |
| tar -czf "artifacts/terraphim-cli-${VERSION}-${{ matrix.target }}.tar.gz" \ | |
| -C "target/${{ matrix.target }}/release" terraphim-cli | |
| tar -czf "artifacts/terraphim-grep-${VERSION}-${{ matrix.target }}.tar.gz" \ | |
| -C "target/${{ matrix.target }}/release" terraphim-grep | |
| # Also copy raw binaries for backward compatibility | |
| if [ -f "target/${{ matrix.target }}/release/terraphim_server" ]; then | |
| cp target/${{ matrix.target }}/release/terraphim_server artifacts/terraphim_server-${{ matrix.target }} | |
| fi | |
| cp target/${{ matrix.target }}/release/terraphim-agent artifacts/terraphim-agent-${{ matrix.target }} | |
| cp target/${{ matrix.target }}/release/terraphim-cli artifacts/terraphim-cli-${{ matrix.target }} | |
| cp target/${{ matrix.target }}/release/terraphim-grep artifacts/terraphim-grep-${{ matrix.target }} | |
| chmod +x artifacts/* | |
| - name: Prepare artifacts (Windows) | |
| if: matrix.os == 'windows-latest' | |
| shell: bash | |
| env: | |
| VERSION: ${{ needs.verify-versions.outputs.version }} | |
| run: | | |
| mkdir -p artifacts | |
| # Create zip archives using 7z (pre-installed on windows-latest runners) | |
| # cd into release dir so zip contains only the exe filename (like zip -j) | |
| cd "target/${{ matrix.target }}/release" | |
| if [ -f "terraphim_server.exe" ]; then | |
| 7z a -tzip "../../../artifacts/terraphim_server-${VERSION}-${{ matrix.target }}.zip" terraphim_server.exe | |
| fi | |
| 7z a -tzip "../../../artifacts/terraphim-agent-${VERSION}-${{ matrix.target }}.zip" terraphim-agent.exe | |
| 7z a -tzip "../../../artifacts/terraphim-cli-${VERSION}-${{ matrix.target }}.zip" terraphim-cli.exe | |
| 7z a -tzip "../../../artifacts/terraphim-grep-${VERSION}-${{ matrix.target }}.zip" terraphim-grep.exe | |
| cd - | |
| # Also copy raw binaries for backward compatibility | |
| cp target/${{ matrix.target }}/release/terraphim_server.exe artifacts/terraphim_server-${{ matrix.target }}.exe || true | |
| cp target/${{ matrix.target }}/release/terraphim-agent.exe artifacts/terraphim-agent-${{ matrix.target }}.exe || true | |
| cp target/${{ matrix.target }}/release/terraphim-cli.exe artifacts/terraphim-cli-${{ matrix.target }}.exe || true | |
| cp target/${{ matrix.target }}/release/terraphim-grep.exe artifacts/terraphim-grep-${{ matrix.target }}.exe || true | |
| - name: Upload binary artifacts | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: binaries-${{ matrix.target }} | |
| path: artifacts/* | |
| create-universal-macos: | |
| name: Create macOS universal binaries | |
| needs: build-binaries | |
| # Run if macOS builds completed (even if other targets failed) | |
| if: always() && needs.build-binaries.result != 'cancelled' | |
| runs-on: [self-hosted, macOS] | |
| steps: | |
| - name: Download x86_64 macOS binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: binaries-x86_64-apple-darwin | |
| path: x86_64 | |
| - name: Download aarch64 macOS binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: binaries-aarch64-apple-darwin | |
| path: aarch64 | |
| - name: Create universal binaries | |
| run: | | |
| mkdir -p universal | |
| # Create universal binary for terraphim_server | |
| lipo -create \ | |
| x86_64/terraphim_server-x86_64-apple-darwin \ | |
| aarch64/terraphim_server-aarch64-apple-darwin \ | |
| -output universal/terraphim_server-universal-apple-darwin | |
| # Create universal binary for terraphim-agent | |
| lipo -create \ | |
| x86_64/terraphim-agent-x86_64-apple-darwin \ | |
| aarch64/terraphim-agent-aarch64-apple-darwin \ | |
| -output universal/terraphim-agent-universal-apple-darwin | |
| # Create universal binary for terraphim-grep | |
| lipo -create \ | |
| x86_64/terraphim-grep-x86_64-apple-darwin \ | |
| aarch64/terraphim-grep-aarch64-apple-darwin \ | |
| -output universal/terraphim-grep-universal-apple-darwin | |
| chmod +x universal/* | |
| # Verify universal binaries | |
| echo "Verifying universal binaries:" | |
| file universal/terraphim_server-universal-apple-darwin | |
| file universal/terraphim-agent-universal-apple-darwin | |
| file universal/terraphim-grep-universal-apple-darwin | |
| lipo -info universal/terraphim_server-universal-apple-darwin | |
| lipo -info universal/terraphim-agent-universal-apple-darwin | |
| lipo -info universal/terraphim-grep-universal-apple-darwin | |
| - name: Upload universal binaries | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: binaries-universal-apple-darwin | |
| path: universal/* | |
| sign-and-notarize-macos: | |
| name: Sign and notarize macOS binaries | |
| needs: create-universal-macos | |
| # Run if universal binary creation completed (even if other jobs failed) | |
| if: always() && needs.create-universal-macos.result == 'success' | |
| runs-on: [self-hosted, macOS] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Download universal macOS binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: binaries-universal-apple-darwin | |
| path: universal | |
| - name: Install 1Password CLI | |
| uses: 1password/install-cli-action@v2 | |
| - name: Load signing credentials from 1Password | |
| env: | |
| OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} | |
| run: | | |
| echo "Loading credentials from 1Password..." | |
| # Read credentials with --no-newline to avoid trailing characters | |
| echo "APPLE_ID=$(op read 'op://TerraphimPlatform/apple.developer.credentials/username' --no-newline)" >> $GITHUB_ENV | |
| echo "APPLE_TEAM_ID=$(op read 'op://TerraphimPlatform/apple.developer.credentials/APPLE_TEAM_ID' --no-newline)" >> $GITHUB_ENV | |
| echo "APPLE_APP_PASSWORD=$(op read 'op://TerraphimPlatform/apple.developer.credentials/APPLE_APP_SPECIFIC_PASSWORD' --no-newline)" >> $GITHUB_ENV | |
| echo "CERT_BASE64=$(op read 'op://TerraphimPlatform/apple.developer.certificate/base64' --no-newline)" >> $GITHUB_ENV | |
| echo "CERT_PASSWORD=$(op read 'op://TerraphimPlatform/apple.developer.certificate/password' --no-newline)" >> $GITHUB_ENV | |
| echo "✅ Credentials loaded successfully" | |
| - name: Sign and notarize terraphim_server | |
| env: | |
| RUNNER_TEMP: ${{ runner.temp }} | |
| run: | | |
| chmod +x scripts/sign-macos-binary.sh | |
| ./scripts/sign-macos-binary.sh \ | |
| "universal/terraphim_server-universal-apple-darwin" \ | |
| "$APPLE_ID" \ | |
| "$APPLE_TEAM_ID" \ | |
| "$APPLE_APP_PASSWORD" \ | |
| "$CERT_BASE64" \ | |
| "$CERT_PASSWORD" | |
| - name: Sign and notarize terraphim-agent | |
| env: | |
| RUNNER_TEMP: ${{ runner.temp }} | |
| run: | | |
| ./scripts/sign-macos-binary.sh \ | |
| "universal/terraphim-agent-universal-apple-darwin" \ | |
| "$APPLE_ID" \ | |
| "$APPLE_TEAM_ID" \ | |
| "$APPLE_APP_PASSWORD" \ | |
| "$CERT_BASE64" \ | |
| "$CERT_PASSWORD" | |
| - name: Sign and notarize terraphim-grep | |
| env: | |
| RUNNER_TEMP: ${{ runner.temp }} | |
| run: | | |
| ./scripts/sign-macos-binary.sh \ | |
| "universal/terraphim-grep-universal-apple-darwin" \ | |
| "$APPLE_ID" \ | |
| "$APPLE_TEAM_ID" \ | |
| "$APPLE_APP_PASSWORD" \ | |
| "$CERT_BASE64" \ | |
| "$CERT_PASSWORD" | |
| - name: Verify signed binaries | |
| run: | | |
| echo "==> Verifying terraphim_server" | |
| codesign --verify --deep --strict --verbose=2 universal/terraphim_server-universal-apple-darwin | |
| file universal/terraphim_server-universal-apple-darwin | |
| echo "==> Verifying terraphim-agent" | |
| codesign --verify --deep --strict --verbose=2 universal/terraphim-agent-universal-apple-darwin | |
| file universal/terraphim-agent-universal-apple-darwin | |
| echo "==> Verifying terraphim-grep" | |
| codesign --verify --deep --strict --verbose=2 universal/terraphim-grep-universal-apple-darwin | |
| file universal/terraphim-grep-universal-apple-darwin | |
| - name: Upload signed binaries | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: binaries-signed-universal-apple-darwin | |
| path: universal/* | |
| build-debian-packages: | |
| name: Build Debian packages | |
| runs-on: [self-hosted, bigbox] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install cargo-deb | |
| run: cargo install cargo-deb | |
| - name: Cache dependencies | |
| uses: Swatinem/rust-cache@v2 | |
| - name: Setup Node.js (for frontend assets) | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 20 | |
| cache: yarn | |
| cache-dependency-path: desktop/yarn.lock | |
| - name: Build frontend assets | |
| working-directory: ./desktop | |
| run: | | |
| yarn install --frozen-lockfile | |
| yarn build | |
| - name: Copy frontend to server dist for rust-embed | |
| run: | | |
| rm -r terraphim_server/dist/assets 2>/dev/null || true | |
| cp -a desktop/dist/. terraphim_server/dist/ | |
| # Verify frontend assets are in place | |
| echo "Frontend assets in terraphim_server/dist/:" | |
| ls -la terraphim_server/dist/ | |
| # Force rebuild by touching build.rs | |
| touch terraphim_server/build.rs | |
| - name: Build Debian packages | |
| run: | | |
| # Clean terraphim_server to ensure fresh UI embedding | |
| cargo clean -p terraphim_server | |
| # Build server package (requires desktop/dist from frontend build) | |
| cargo deb -p terraphim_server --output target/debian/ | |
| # Build agent package | |
| cargo deb -p terraphim_agent --output target/debian/ | |
| # Build grep package (requires code-search + openrouter features for the | |
| # hybrid pipeline; cargo-deb reads [package.metadata.deb] from the crate's | |
| # Cargo.toml). The compile step uses the same features the release binary | |
| # build uses so behaviour parity with the tarball artefacts is preserved. | |
| cargo deb -p terraphim_grep --output target/debian/ \ | |
| -- --features "code-search openrouter" | |
| - name: Upload Debian packages | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: debian-packages | |
| path: target/debian/*.deb | |
| trigger-desktop-release: | |
| name: Trigger Desktop Release | |
| needs: verify-versions | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - name: Trigger terraphim-ai-desktop release workflow | |
| uses: actions/github-script@v9 | |
| continue-on-error: true | |
| with: | |
| github-token: ${{ secrets.DESKTOP_REPO_TOKEN }} | |
| script: | | |
| const tag = context.ref.replace('refs/tags/', ''); | |
| console.log(`Triggering desktop release for tag: ${tag}`); | |
| await github.rest.actions.createWorkflowDispatch({ | |
| owner: 'terraphim', | |
| repo: 'terraphim-ai-desktop', | |
| workflow_id: 'release-comprehensive.yml', | |
| ref: 'main' | |
| }); | |
| console.log('Desktop release workflow triggered successfully'); | |
| build-docker: | |
| name: Build and push Docker images | |
| uses: ./.github/workflows/docker-multiarch.yml | |
| with: | |
| platforms: linux/amd64,linux/arm64 | |
| ubuntu-versions: '["20.04", "22.04"]' | |
| push: ${{ !inputs.test_run }} | |
| tag: ${{ github.ref_name }} | |
| dockerhub-username: ${{ vars.DOCKERHUB_USERNAME || '' }} | |
| test_run: ${{ inputs.test_run || false }} | |
| secrets: inherit # pragma: allowlist secret | |
| verify-release-assets: | |
| name: Verify release assets | |
| needs: [build-binaries, sign-and-notarize-macos, build-debian-packages] | |
| # Run even if some builds failed, but verify critical assets exist | |
| if: always() && needs.sign-and-notarize-macos.result == 'success' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Download all binary artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: binaries-* | |
| path: all-binaries | |
| merge-multiple: true | |
| continue-on-error: true | |
| - name: Verify expected macOS assets exist | |
| env: | |
| VERSION: ${{ needs.verify-versions.outputs.version }} | |
| run: | | |
| echo "Downloaded artifacts:" | |
| find all-binaries -type f 2>/dev/null | sort || true | |
| echo "" | |
| # Critical macOS assets that must exist for auto-update to work | |
| CRITICAL_ASSETS=( | |
| "terraphim-agent-x86_64-apple-darwin" | |
| "terraphim-agent-aarch64-apple-darwin" | |
| "terraphim-agent-universal-apple-darwin" | |
| "terraphim-grep-x86_64-apple-darwin" | |
| "terraphim-grep-aarch64-apple-darwin" | |
| "terraphim-grep-universal-apple-darwin" | |
| ) | |
| MISSING=0 | |
| for asset in "${CRITICAL_ASSETS[@]}"; do | |
| if [ -f "all-binaries/$asset" ]; then | |
| echo " ✅ $asset" | |
| else | |
| echo " ❌ MISSING: $asset" | |
| MISSING=$((MISSING + 1)) | |
| fi | |
| done | |
| if [ $MISSING -gt 0 ]; then | |
| echo "" | |
| echo "❌ Verification failed: $MISSING critical macOS assets are missing" | |
| echo "This will break auto-update for macOS users. Aborting release." | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "✅ All critical macOS assets verified" | |
| create-release: | |
| name: Create GitHub release | |
| needs: [verify-versions, verify-release-assets] | |
| # Create release if version and assets verification passed | |
| if: always() && needs.verify-versions.result == 'success' && needs.verify-release-assets.result == 'success' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Download binary artifacts | |
| uses: actions/download-artifact@v4 | |
| id: download | |
| with: | |
| pattern: binaries-* | |
| path: release-assets | |
| merge-multiple: true | |
| - name: Download Debian package artifacts | |
| uses: actions/download-artifact@v4 | |
| id: download_debian | |
| with: | |
| name: debian-packages | |
| path: release-assets | |
| merge-multiple: true | |
| - name: Retry artifact download if needed | |
| if: steps.download.outcome == 'failure' || steps.download_debian.outcome == 'failure' | |
| run: | | |
| echo "Artifact download failed, retrying with gh CLI..." | |
| for attempt in 1 2 3; do | |
| echo "Download attempt $attempt..." | |
| sleep 30 | |
| rm -rf binaries-* debian-packages | |
| gh run download ${{ github.run_id }} --dir . -n debian-packages | |
| gh api \ | |
| repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts \ | |
| --jq '.artifacts[].name' \ | |
| | grep '^binaries-' \ | |
| | while read artifact_name; do | |
| gh run download ${{ github.run_id }} --dir . -n "$artifact_name" | |
| done && break | |
| if [ $attempt -eq 3 ]; then | |
| echo "Failed to download artifacts after 3 attempts" | |
| exit 1 | |
| fi | |
| done | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Prepare release assets | |
| run: | | |
| # Artifacts are already downloaded to release-assets/ with merge-multiple | |
| # Just verify everything is there | |
| echo "Release assets:" | |
| ls -la release-assets/ | |
| - name: Generate checksums | |
| working-directory: release-assets | |
| run: | | |
| sha256sum * > checksums.txt | |
| - name: Extract release notes from tag | |
| id: release-notes | |
| run: | | |
| if [[ "${{ github.ref }}" == refs/tags/* ]]; then | |
| TAG=${GITHUB_REF#refs/tags/} | |
| echo "Creating release for tag: $TAG" | |
| # Extract component and version from tag | |
| if [[ "$TAG" == *"-v"* ]]; then | |
| COMPONENT=${TAG%-v*} | |
| VERSION=${TAG##*-v} | |
| echo "Component: $COMPONENT, Version: $VERSION" | |
| TITLE="$COMPONENT v$VERSION" | |
| else | |
| TITLE="$TAG" | |
| fi | |
| echo "title=$TITLE" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: ${{ steps.release-notes.outputs.title }} | |
| draft: false | |
| prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }} | |
| files: release-assets/* | |
| body: | | |
| ## Release Assets | |
| ### macOS Universal Binaries (Intel + Apple Silicon) | |
| **Signed and Notarized** - No Gatekeeper warnings | |
| - `terraphim_server-universal-apple-darwin`: Server binary for all Macs | |
| - `terraphim-agent-universal-apple-darwin`: TUI binary for all Macs | |
| - `terraphim-grep-universal-apple-darwin`: Hybrid grep CLI for all Macs | |
| ### Server Binaries | |
| - `terraphim_server-*`: Server binaries for various platforms | |
| ### TUI Binaries | |
| - `terraphim-agent-*`: Terminal UI binaries for various platforms | |
| ### Grep Binaries | |
| - `terraphim-grep-*`: Hybrid grep CLI (knowledge-graph boost + LLM fallback) | |
| for various platforms. See | |
| [crates/terraphim_grep/RELEASE_NOTES_v1.20.0.md](https://github.com/terraphim/terraphim-ai/blob/main/crates/terraphim_grep/RELEASE_NOTES_v1.20.0.md) | |
| for crate-focused details. | |
| ### Desktop Applications | |
| Desktop applications are now built and released separately in the [terraphim-ai-desktop](https://github.com/terraphim/terraphim-ai-desktop) repository. | |
| - `*.dmg`: macOS desktop installer | |
| - `*.AppImage`: Linux portable desktop app | |
| - `*.msi`, `*.exe`: Windows desktop installers | |
| ### Debian Packages | |
| - `*.deb`: Debian/Ubuntu packages for easy installation | |
| ### Docker Images | |
| - `ghcr.io/terraphim/terraphim-server:latest`: Multi-arch server image | |
| ### Installation | |
| ```bash | |
| # Install via Homebrew (macOS/Linux) | |
| brew tap terraphim/terraphim | |
| brew install terraphim-server | |
| brew install terraphim-agent | |
| # Install Debian package (Ubuntu/Debian) | |
| sudo dpkg -i terraphim-server_*.deb | |
| # Run with Docker | |
| docker run ghcr.io/terraphim/terraphim-server:latest | |
| ``` | |
| See `checksums.txt` for file integrity verification. | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| update-homebrew: | |
| name: Update Homebrew formulas | |
| needs: create-release | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - name: Extract version from tag | |
| id: version | |
| run: | | |
| VERSION=${GITHUB_REF#refs/tags/v} | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Updating Homebrew formulas for version: $VERSION" | |
| - name: Download release checksums | |
| run: | | |
| VERSION=${{ steps.version.outputs.version }} | |
| curl -sL "https://github.com/terraphim/terraphim-ai/releases/download/v${VERSION}/checksums.txt" -o checksums.txt | |
| cat checksums.txt | |
| - name: Calculate universal binary checksums | |
| id: checksums | |
| run: | | |
| # Extract SHA256 for all binaries from checksums.txt | |
| # macOS universal binaries | |
| SERVER_SHA=$(grep "terraphim_server-universal-apple-darwin" checksums.txt | awk '{print $1}') | |
| AGENT_SHA=$(grep "terraphim-agent-universal-apple-darwin" checksums.txt | awk '{print $1}') | |
| GREP_SHA=$(grep "terraphim-grep-universal-apple-darwin" checksums.txt | awk '{print $1}') | |
| # Linux GNU binaries (for Homebrew) | |
| SERVER_LINUX_GNU_SHA=$(grep "terraphim_server-x86_64-unknown-linux-gnu" checksums.txt | grep -v tar.gz | awk '{print $1}') | |
| AGENT_LINUX_GNU_SHA=$(grep "terraphim-agent-x86_64-unknown-linux-gnu" checksums.txt | grep -v tar.gz | awk '{print $1}') | |
| GREP_LINUX_GNU_SHA=$(grep "terraphim-grep-x86_64-unknown-linux-gnu" checksums.txt | grep -v tar.gz | awk '{print $1}') | |
| # Fallback to MUSL if GNU not available | |
| if [ -z "$SERVER_LINUX_GNU_SHA" ]; then | |
| SERVER_LINUX_GNU_SHA=$(grep "terraphim_server-x86_64-unknown-linux-musl" checksums.txt | grep -v tar.gz | awk '{print $1}') | |
| echo "⚠️ Using MUSL fallback for server" | |
| fi | |
| if [ -z "$AGENT_LINUX_GNU_SHA" ]; then | |
| AGENT_LINUX_GNU_SHA=$(grep "terraphim-agent-x86_64-unknown-linux-musl" checksums.txt | grep -v tar.gz | awk '{print $1}') | |
| echo "⚠️ Using MUSL fallback for agent" | |
| fi | |
| if [ -z "$GREP_LINUX_GNU_SHA" ]; then | |
| GREP_LINUX_GNU_SHA=$(grep "terraphim-grep-x86_64-unknown-linux-musl" checksums.txt | grep -v tar.gz | awk '{print $1}') | |
| echo "⚠️ Using MUSL fallback for grep" | |
| fi | |
| echo "server_sha=$SERVER_SHA" >> $GITHUB_OUTPUT | |
| echo "agent_sha=$AGENT_SHA" >> $GITHUB_OUTPUT | |
| echo "grep_sha=$GREP_SHA" >> $GITHUB_OUTPUT | |
| echo "server_linux_gnu_sha=$SERVER_LINUX_GNU_SHA" >> $GITHUB_OUTPUT | |
| echo "agent_linux_gnu_sha=$AGENT_LINUX_GNU_SHA" >> $GITHUB_OUTPUT | |
| echo "grep_linux_gnu_sha=$GREP_LINUX_GNU_SHA" >> $GITHUB_OUTPUT | |
| echo "Server universal binary SHA256: $SERVER_SHA" | |
| echo "Agent universal binary SHA256: $AGENT_SHA" | |
| echo "Grep universal binary SHA256: $GREP_SHA" | |
| echo "Server Linux GNU SHA256: $SERVER_LINUX_GNU_SHA" | |
| echo "Agent Linux GNU SHA256: $AGENT_LINUX_GNU_SHA" | |
| echo "Grep Linux GNU SHA256: $GREP_LINUX_GNU_SHA" | |
| - name: Clone Homebrew tap | |
| run: | | |
| git clone https://github.com/terraphim/homebrew-terraphim.git | |
| cd homebrew-terraphim | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Update formulas | |
| env: | |
| VERSION: ${{ steps.version.outputs.version }} | |
| SERVER_SHA: ${{ steps.checksums.outputs.server_sha }} | |
| AGENT_SHA: ${{ steps.checksums.outputs.agent_sha }} | |
| GREP_SHA: ${{ steps.checksums.outputs.grep_sha }} | |
| SERVER_LINUX_GNU_SHA: ${{ steps.checksums.outputs.server_linux_gnu_sha }} | |
| AGENT_LINUX_GNU_SHA: ${{ steps.checksums.outputs.agent_linux_gnu_sha }} | |
| GREP_LINUX_GNU_SHA: ${{ steps.checksums.outputs.grep_linux_gnu_sha }} | |
| run: | | |
| cd homebrew-terraphim | |
| # Update terraphim-server.rb - switch to pre-built universal binary | |
| cat > Formula/terraphim-server.rb << EOF | |
| class TerraphimServer < Formula | |
| desc "Privacy-first AI assistant HTTP server with semantic search" | |
| homepage "https://github.com/terraphim/terraphim-ai" | |
| version "${VERSION}" | |
| license "Apache-2.0" | |
| on_macos do | |
| url "https://github.com/terraphim/terraphim-ai/releases/download/v${VERSION}/terraphim_server-universal-apple-darwin" | |
| sha256 "${SERVER_SHA}" | |
| end | |
| on_linux do | |
| url "https://github.com/terraphim/terraphim-ai/releases/download/v${VERSION}/terraphim_server-x86_64-unknown-linux-gnu" | |
| sha256 "${SERVER_LINUX_GNU_SHA}" | |
| end | |
| def install | |
| if OS.mac? | |
| bin.install "terraphim_server-universal-apple-darwin" => "terraphim_server" | |
| else | |
| bin.install "terraphim_server-x86_64-unknown-linux-gnu" => "terraphim_server" | |
| end | |
| end | |
| service do | |
| run opt_bin/"terraphim_server" | |
| keep_alive true | |
| log_path var/"log/terraphim-server.log" | |
| error_log_path var/"log/terraphim-server-error.log" | |
| end | |
| test do | |
| assert_match "terraphim", shell_output("#{bin}/terraphim_server --version 2>&1", 0) | |
| end | |
| end | |
| EOF | |
| # Update terraphim-agent.rb - switch to pre-built universal binary | |
| cat > Formula/terraphim-agent.rb << EOF | |
| class TerraphimAgent < Formula | |
| desc "Interactive TUI and REPL for Terraphim AI semantic search" | |
| homepage "https://github.com/terraphim/terraphim-ai" | |
| version "${VERSION}" | |
| license "Apache-2.0" | |
| on_macos do | |
| url "https://github.com/terraphim/terraphim-ai/releases/download/v${VERSION}/terraphim-agent-universal-apple-darwin" | |
| sha256 "${AGENT_SHA}" | |
| end | |
| on_linux do | |
| url "https://github.com/terraphim/terraphim-ai/releases/download/v${VERSION}/terraphim-agent-x86_64-unknown-linux-gnu" | |
| sha256 "${AGENT_LINUX_GNU_SHA}" | |
| end | |
| def install | |
| if OS.mac? | |
| bin.install "terraphim-agent-universal-apple-darwin" => "terraphim-agent" | |
| else | |
| bin.install "terraphim-agent-x86_64-unknown-linux-gnu" => "terraphim-agent" | |
| end | |
| end | |
| test do | |
| assert_match "terraphim", shell_output("#{bin}/terraphim-agent --version 2>&1", 0) | |
| end | |
| end | |
| EOF | |
| # Update terraphim-grep.rb -- hybrid grep CLI with KG boost and LLM fallback | |
| cat > Formula/terraphim-grep.rb << EOF | |
| class TerraphimGrep < Formula | |
| desc "Intelligent hybrid grep with knowledge-graph boosting and LLM fallback" | |
| homepage "https://github.com/terraphim/terraphim-ai" | |
| version "${VERSION}" | |
| license "MIT" | |
| on_macos do | |
| url "https://github.com/terraphim/terraphim-ai/releases/download/v${VERSION}/terraphim-grep-universal-apple-darwin" | |
| sha256 "${GREP_SHA}" | |
| end | |
| on_linux do | |
| url "https://github.com/terraphim/terraphim-ai/releases/download/v${VERSION}/terraphim-grep-x86_64-unknown-linux-gnu" | |
| sha256 "${GREP_LINUX_GNU_SHA}" | |
| end | |
| def install | |
| if OS.mac? | |
| bin.install "terraphim-grep-universal-apple-darwin" => "terraphim-grep" | |
| else | |
| bin.install "terraphim-grep-x86_64-unknown-linux-gnu" => "terraphim-grep" | |
| end | |
| end | |
| test do | |
| assert_match "terraphim", shell_output("#{bin}/terraphim-grep --version 2>&1", 0) | |
| end | |
| end | |
| EOF | |
| git add Formula/ | |
| git commit -m "feat: update formulas to v${VERSION} with universal binaries | |
| - terraphim-server v${VERSION} | |
| - terraphim-agent v${VERSION} | |
| - terraphim-grep v${VERSION} | |
| 🤖 Automated update from release workflow" | |
| - name: Install 1Password CLI | |
| uses: 1password/install-cli-action@v2 | |
| - name: Push to Homebrew tap | |
| env: | |
| OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} | |
| run: | | |
| cd homebrew-terraphim | |
| # Get token from 1Password | |
| HOMEBREW_TAP_TOKEN=$(op read "op://TerraphimPlatform/homebrew-tap-token/token" 2>/dev/null || echo "") | |
| if [ -n "$HOMEBREW_TAP_TOKEN" ]; then | |
| git remote set-url origin "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/terraphim/homebrew-terraphim.git" | |
| git push origin main | |
| echo "✅ Homebrew formulas updated successfully" | |
| else | |
| echo "⚠️ homebrew-tap-token not found in 1Password - skipping push" | |
| echo "Ensure token exists at: op://TerraphimPlatform/homebrew-tap-token/token" | |
| fi | |
| publish-crates: | |
| name: Publish Rust crates to crates.io | |
| needs: verify-versions | |
| runs-on: ubuntu-latest | |
| # Use always() to run even if some upstream jobs failed, but only for version tags | |
| if: always() && startsWith(github.ref, 'refs/tags/v') && needs.verify-versions.result == 'success' | |
| # NOTE: environment removed to avoid approval requirements | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt, clippy | |
| - name: Install 1Password CLI | |
| uses: 1password/install-cli-action@v2 | |
| - name: Cache Cargo dependencies | |
| uses: Swatinem/rust-cache@v2 | |
| # NOTE: Tests are skipped here since CI workflow already validates everything | |
| # The redundant test step was causing failures due to missing frontend assets | |
| # All tests are run by CI before the release is created | |
| - name: Get crates.io token from 1Password | |
| id: token | |
| env: | |
| OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} | |
| run: | | |
| TOKEN=$(op read "op://TerraphimPlatform/crates.io.token/token") | |
| echo "token=$TOKEN" >> $GITHUB_OUTPUT | |
| - name: Publish crates in dependency order | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ steps.token.outputs.token }} | |
| run: | | |
| # Make script executable | |
| chmod +x ./scripts/publish-crates.sh | |
| # Extract version from tag | |
| VERSION=${GITHUB_REF#refs/tags/v} | |
| # Run publish script with version | |
| ./scripts/publish-crates.sh --version "$VERSION" | |
| - name: Verify published packages | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ steps.token.outputs.token }} | |
| run: | | |
| echo "🔍 Verifying packages are available on crates.io..." | |
| # Allow some time for crates.io to index | |
| sleep 30 | |
| cargo install --dry-run terraphim_agent || echo "⚠️ Installation dry-run failed (may need more time)" | |
| echo "✅ Publishing workflow completed!" |