Add Vertex regions; bump ZAi defaults; stream fix #250
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: Build macOS | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| tags: [ 'v*' ] | |
| pull_request: | |
| branches: [ main, develop ] | |
| workflow_dispatch: # Manual trigger | |
| concurrency: | |
| group: build-macos-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| VSCODE_QUALITY: stable | |
| jobs: | |
| build-macos-arm64: | |
| name: Build macOS (ARM64) | |
| runs-on: macos-latest | |
| timeout-minutes: 120 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'npm' | |
| - name: Setup Python 3 | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.11' | |
| - name: Install tsx (TypeScript runner) | |
| run: npm install -g tsx | |
| - name: Run preinstall script manually | |
| run: tsx build/npm/preinstall.ts | |
| - name: Install dependencies (skip scripts) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: npm install --ignore-scripts | |
| - name: Run postinstall script manually | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: tsx build/npm/postinstall.ts | |
| - name: Rebuild native modules | |
| run: npm rebuild | |
| - name: Generate DOM whitelist from MDN | |
| run: node build/scripts/generateDOMWhitelist.mjs | |
| - name: Install roopik-zoo extension dependencies | |
| working-directory: extensions/roopik-zoo | |
| run: | | |
| if ! npm install; then | |
| echo "Normal install failed, trying with --legacy-peer-deps..." | |
| npm install --legacy-peer-deps | |
| node ../../.github/scripts/install-all-peer-deps.js || true | |
| fi | |
| - name: Install @roo-code/types dependencies | |
| working-directory: extensions/roopik-zoo/packages/types | |
| run: npm install | |
| - name: Build @roo-code/types package | |
| working-directory: extensions/roopik-zoo/packages/types | |
| run: npm run build | |
| - name: Install @roo-code/build dependencies | |
| working-directory: extensions/roopik-zoo/packages/build | |
| run: npm install | |
| - name: Build @roo-code/build package | |
| working-directory: extensions/roopik-zoo/packages/build | |
| run: npm run build | |
| - name: Create .env file for roopik-zoo | |
| working-directory: extensions/roopik-zoo | |
| env: | |
| ROO_CODE_API_URL: ${{ secrets.ROO_CODE_API_URL || 'https://app.roocode.com' }} | |
| ROO_CODE_PROVIDER_URL: ${{ secrets.ROO_CODE_PROVIDER_URL || 'https://app.roocode.com/proxy/v1' }} | |
| POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY || '' }} | |
| run: | | |
| cat > .env << EOF | |
| ROO_CODE_API_URL=${ROO_CODE_API_URL} | |
| ROO_CODE_PROVIDER_URL=${ROO_CODE_PROVIDER_URL} | |
| POSTHOG_API_KEY=${POSTHOG_API_KEY} | |
| EOF | |
| - name: Build roopik-zoo extension | |
| working-directory: extensions/roopik-zoo | |
| run: npm run build | |
| - name: Install roopik extension dependencies (skip postinstall) | |
| working-directory: extensions/roopik | |
| run: npm install --ignore-scripts | |
| - name: Install roopik webview dependencies | |
| working-directory: extensions/roopik/webview | |
| run: npm install | |
| - name: Build roopik extension | |
| working-directory: extensions/roopik | |
| run: npm run build | |
| - name: Build MCP STDIO binary (macOS ARM64) | |
| working-directory: tools/roopik/mcp-stdio-server | |
| run: | | |
| npm ci | |
| mkdir -p ../../../resources/mcp-binaries | |
| npm run build:binary:mac-arm64 | |
| - name: Build macOS application (arm64) | |
| env: | |
| BUILD_SOURCEVERSION: ${{ github.sha }} | |
| run: npm run gulp vscode-darwin-arm64 | |
| - name: Import Apple signing certificate | |
| env: | |
| AGENT_TEMPDIRECTORY: ${{ runner.temp }} | |
| MAC_CERT_P12: ${{ secrets.MAC_CERT_P12 }} | |
| MAC_CERT_PASSWORD: ${{ secrets.MAC_CERT_PASSWORD }} | |
| run: | | |
| KEYCHAIN_PATH="$AGENT_TEMPDIRECTORY/buildagent.keychain" | |
| CERT_PATH="$AGENT_TEMPDIRECTORY/mac_cert.p12" | |
| echo "$MAC_CERT_P12" | base64 --decode > "$CERT_PATH" | |
| security create-keychain -p "" "$KEYCHAIN_PATH" | |
| security import "$CERT_PATH" -k "$KEYCHAIN_PATH" -P "$MAC_CERT_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security | |
| security list-keychains -s "$KEYCHAIN_PATH" | |
| security unlock-keychain -p "" "$KEYCHAIN_PATH" | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" "$KEYCHAIN_PATH" | |
| - name: Debug signing identities | |
| env: | |
| AGENT_TEMPDIRECTORY: ${{ runner.temp }} | |
| run: security find-identity -v -p codesigning "$AGENT_TEMPDIRECTORY/buildagent.keychain" | |
| - name: Codesign app | |
| env: | |
| AGENT_TEMPDIRECTORY: ${{ runner.temp }} | |
| VSCODE_ARCH: arm64 | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| run: | | |
| APP_PATH="$(find ../VSCode-darwin-arm64 -maxdepth 2 -name "*.app" -print -quit)" | |
| if [ -z "$APP_PATH" ]; then | |
| echo "No .app found under ../VSCode-darwin-arm64" | |
| exit 1 | |
| fi | |
| SIGN_IDENTITY="$(security find-identity -v -p codesigning "$AGENT_TEMPDIRECTORY/buildagent.keychain" \ | |
| | awk -v team="$APPLE_TEAM_ID" '/Developer ID Application/ && $0 ~ team {print $2; exit}')" | |
| if [ -z "$SIGN_IDENTITY" ]; then | |
| echo "No Developer ID Application identity found in build.keychain" | |
| exit 1 | |
| fi | |
| echo "Using signing identity SHA: $SIGN_IDENTITY" | |
| BUILD_DIR="$(dirname "$GITHUB_WORKSPACE")" | |
| DEBUG=electron-osx-sign* CODESIGN_IDENTITY="$SIGN_IDENTITY" tsx build/darwin/sign.ts "$BUILD_DIR" | |
| # Verify | |
| codesign --verify --deep --strict --verbose=2 "$APP_PATH" | |
| - name: Prepare signed artifact | |
| run: | | |
| APP_PATH="$(find ../VSCode-darwin-arm64 -maxdepth 2 -name "*.app" -print -quit)" | |
| if [ -z "$APP_PATH" ]; then | |
| echo "No .app found under ../VSCode-darwin-arm64" | |
| exit 1 | |
| fi | |
| mkdir -p .artifacts | |
| SIGNED_ZIP=".artifacts/Roopik-macos-signed.zip" | |
| ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "$SIGNED_ZIP" | |
| - name: Upload macOS artifacts (arm64) | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: roopik-macos-arm64 | |
| path: | | |
| .artifacts/Roopik-macos-signed.zip | |
| retention-days: 10 | |
| notarize-macos-arm64: | |
| name: Notarize macOS (ARM64) | |
| runs-on: macos-latest | |
| timeout-minutes: 60 | |
| needs: build-macos-arm64 | |
| steps: | |
| - name: Download signed artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: roopik-macos-arm64 | |
| - name: Notarize and staple | |
| env: | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }} | |
| run: | | |
| SIGNED_ZIP="$(find . -name 'Roopik-macos-signed.zip' -print -quit)" | |
| if [ -z "$SIGNED_ZIP" ]; then | |
| echo "Signed zip not found in downloaded artifacts." | |
| find . -maxdepth 3 -type f -name "*.zip" -print | |
| exit 1 | |
| fi | |
| rm -rf .notarize | |
| mkdir -p .notarize | |
| ditto -x -k "$SIGNED_ZIP" .notarize | |
| APP_PATH="$(find .notarize -maxdepth 3 -name "*.app" -print -quit)" | |
| if [ -z "$APP_PATH" ]; then | |
| echo "No .app found in notarize payload" | |
| exit 1 | |
| fi | |
| DMG_ROOT=".dmgroot" | |
| DMG_NAME="Roopik-macos.dmg" | |
| rm -rf "$DMG_ROOT" | |
| mkdir -p "$DMG_ROOT" | |
| cp -R "$APP_PATH" "$DMG_ROOT/" | |
| ln -s /Applications "$DMG_ROOT/Applications" | |
| rm -f "$DMG_NAME" | |
| hdiutil detach "/Volumes/Roopik" -force || true | |
| hdiutil create -volname "Roopik" -srcfolder "$DMG_ROOT" -ov -format UDZO "$DMG_NAME" | |
| SUBMIT_JSON="$(xcrun notarytool submit "$DMG_NAME" \ | |
| --apple-id "$APPLE_ID" \ | |
| --team-id "$APPLE_TEAM_ID" \ | |
| --password "$APPLE_APP_PASSWORD" \ | |
| --output-format json)" | |
| echo "$SUBMIT_JSON" | |
| REQUEST_ID="$(echo "$SUBMIT_JSON" | /usr/bin/python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")" | |
| echo "Notarization request id: $REQUEST_ID" | |
| MAX_ATTEMPTS=60 | |
| SLEEP_SECONDS=60 | |
| ATTEMPT=1 | |
| while [ "$ATTEMPT" -le "$MAX_ATTEMPTS" ]; do | |
| LOG_JSON="$(xcrun notarytool log "$REQUEST_ID" \ | |
| --apple-id "$APPLE_ID" \ | |
| --team-id "$APPLE_TEAM_ID" \ | |
| --password "$APPLE_APP_PASSWORD" \ | |
| --output-format json 2>/dev/null || true)" | |
| STATUS="Pending" | |
| if [ -n "$LOG_JSON" ] && [[ "$LOG_JSON" == \{* || "$LOG_JSON" == \[* ]]; then | |
| STATUS="$(/usr/bin/python3 -c 'import json,sys; print(json.load(sys.stdin).get("status","Pending"))' <<<"$LOG_JSON")" | |
| fi | |
| echo "Notarization status ($ATTEMPT/$MAX_ATTEMPTS): $STATUS" | |
| if [ "$STATUS" = "Accepted" ]; then | |
| break | |
| fi | |
| if [ "$STATUS" = "Invalid" ]; then | |
| echo "$LOG_JSON" | |
| exit 1 | |
| fi | |
| sleep "$SLEEP_SECONDS" | |
| ATTEMPT=$((ATTEMPT + 1)) | |
| done | |
| if [ "$STATUS" != "Accepted" ]; then | |
| echo "Notarization did not finish in time. Request id: $REQUEST_ID" | |
| exit 1 | |
| fi | |
| xcrun stapler staple "$APP_PATH" | |
| xcrun stapler staple "$DMG_NAME" | |
| NOTARIZED_ZIP="./Roopik-macos-notarized.zip" | |
| ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "$NOTARIZED_ZIP" | |
| NOTARIZED_DMG="./Roopik-macos-notarized.dmg" | |
| mv "$DMG_NAME" "$NOTARIZED_DMG" | |
| mkdir -p .artifacts/public | |
| cp "$NOTARIZED_ZIP" .artifacts/public/roopik-macos-latest.zip | |
| cp "$NOTARIZED_DMG" .artifacts/public/roopik-macos-latest.dmg | |
| - name: Upload macOS release artifact (arm64) | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: roopik-macos-release | |
| path: .artifacts/public/ | |
| retention-days: 10 | |
| - name: Install AWS CLI | |
| continue-on-error: true | |
| run: brew install awscli | |
| - name: Upload macOS installers to R2 | |
| continue-on-error: true | |
| env: | |
| R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }} | |
| R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} | |
| R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} | |
| R2_BUCKET: ${{ secrets.R2_BUCKET }} | |
| R2_PUBLIC_BASE_URL: ${{ secrets.R2_PUBLIC_BASE_URL }} | |
| run: | | |
| export PATH="$HOME/Library/Python/3.11/bin:$PATH" | |
| endpoint="https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com" | |
| prefix="macos/" | |
| export AWS_ACCESS_KEY_ID="$R2_ACCESS_KEY_ID" | |
| export AWS_SECRET_ACCESS_KEY="$R2_SECRET_ACCESS_KEY" | |
| export AWS_EC2_METADATA_DISABLED=true | |
| aws s3 cp "Roopik-macos-notarized.dmg" "s3://${R2_BUCKET}/${prefix}roopik-macos-latest.dmg" --endpoint-url "$endpoint" --no-progress | |
| aws s3 cp "Roopik-macos-notarized.zip" "s3://${R2_BUCKET}/${prefix}roopik-macos-latest.zip" --endpoint-url "$endpoint" --no-progress | |
| if [ -z "${R2_PUBLIC_BASE_URL:-}" ]; then | |
| echo "R2_PUBLIC_BASE_URL not set, skipping update manifest upload." | |
| exit 0 | |
| fi | |
| # Re-find APP_PATH since environment variables don't persist between steps | |
| # Look in .notarize folder where we zipped it from earlier | |
| APP_PATH="$(find .notarize -maxdepth 3 -name "*.app" -print -quit)" | |
| if [ -z "$APP_PATH" ]; then | |
| echo "Could not find .app to read version from!" | |
| # Fallback to package.json version if APP_PATH fails | |
| version="$(node -p "require('./package.json').version")" | |
| else | |
| version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP_PATH/Contents/Info.plist" 2>/dev/null || true)" | |
| if [ -z "$version" ]; then | |
| version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' "$APP_PATH/Contents/Info.plist" 2>/dev/null || true)" | |
| fi | |
| fi | |
| if [ -z "$version" ]; then | |
| version="0.0.0" | |
| fi | |
| commit="${{ github.sha }}" | |
| hash="$(shasum -a 256 "Roopik-macos-notarized.zip" | awk '{print tolower($1)}')" | |
| pub_date="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" | |
| base="${R2_PUBLIC_BASE_URL%/}" | |
| url="${base}/macos/roopik-macos-latest.zip" | |
| json="$(printf '{"version":"%s","productVersion":"%s","url":"%s","sha256hash":"%s","pub_date":"%s"}' "$commit" "$version" "$url" "$hash" "$pub_date")" | |
| printf '%s' "$json" > latest.json | |
| aws s3 cp latest.json "s3://${R2_BUCKET}/macos/stable/latest.json" --endpoint-url "$endpoint" --no-progress | |