diff --git a/.github/workflows/mobile-android-release.yml b/.github/workflows/mobile-android-release.yml index b9e6e1b1b02..2f502341dc9 100644 --- a/.github/workflows/mobile-android-release.yml +++ b/.github/workflows/mobile-android-release.yml @@ -38,6 +38,10 @@ jobs: permissions: contents: write + outputs: + publish_release: ${{ steps.release.outputs.publish_release }} + version: ${{ steps.release.outputs.version }} + defaults: run: working-directory: mobile @@ -231,3 +235,76 @@ jobs: android/app/build/outputs/apk/release/*.apk \ "${{ steps.apk.outputs.checksum }}" fi + + # Why a separate job: the release is already published here, so a failed bump only leaves + # the site's APK download on the previous release and must not fail the release run. + bump-apk-download: + needs: android-build + if: needs.android-build.outputs.publish_release == 'true' + runs-on: ubuntu-latest + continue-on-error: true + permissions: + contents: read + env: + VERSION: ${{ needs.android-build.outputs.version }} + SITE_REPO: stablyai/orca-marketing-website + BRANCH: bump/android-apk-${{ needs.android-build.outputs.version }} + steps: + - name: Checkout orca + uses: actions/checkout@v6 + with: + sparse-checkout: config/scripts + + # Why the buf0-bot app, as in homebrew-bump.yml: GITHUB_TOKEN cannot push to another + # repo, and a PR it opened would not run the site's checks. + - name: Generate buf0-bot token + id: app-token + uses: actions/create-github-app-token@v3 + with: + app-id: 2590194 + private-key: ${{ secrets.BUFO_BOT_PRIVATE_KEY }} + owner: stablyai + repositories: orca-marketing-website + permission-contents: write + permission-pull-requests: write + + - name: Checkout marketing site + uses: actions/checkout@v6 + with: + repository: stablyai/orca-marketing-website + path: site + token: ${{ steps.app-token.outputs.token }} + + - name: Open the version bump PR + working-directory: site + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + set -euo pipefail + node ../config/scripts/bump-android-apk-download-version.mjs src/lib/downloadTargets.ts "$VERSION" + if git diff --quiet; then + echo "The site's main branch already has Android APK $VERSION or newer." >> "$GITHUB_STEP_SUMMARY" + exit 0 + fi + + title="Point the Android APK download at $VERSION" + git config user.name "buf0-bot[bot]" + git config user.email "252831055+buf0-bot[bot]@users.noreply.github.com" + git checkout -b "$BRANCH" + git commit -am "$title" + # Why --force: a rerun rebuilds the branch on the site's current main. + git push --force origin "$BRANCH" + + # Why: a rerun of the same release reuses its open PR instead of opening another. + pr="$(gh pr list --repo "$SITE_REPO" --head "$BRANCH" --state open --json url --jq '.[].url')" + if [ -z "$pr" ]; then + pr="$(gh pr create --repo "$SITE_REPO" --base main --head "$BRANCH" --title "$title" \ + --body "Opened by the [Android release run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID) for mobile-android-v$VERSION. Merging points /download/android and every APK link on the site at the new APK.")" + fi + echo "Android APK download bump: $pr" >> "$GITHUB_STEP_SUMMARY" + + - name: Report a failed bump + if: failure() + run: | + echo "::warning::The release is published, but the site's Android APK download was not bumped to $VERSION." + printf '### Android APK download not bumped\n\nThe release is published, but /download/android still serves the previous APK. Rerun this job, or set `ANDROID_RELEASE_VERSION` in `src/lib/downloadTargets.ts` of %s to `%s` by hand.\n' "$SITE_REPO" "$VERSION" >> "$GITHUB_STEP_SUMMARY" diff --git a/README.md b/README.md index 81fa5c0c79c..6def4187048 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Monitor and steer your agents from your phone — get notified when an agent finishes and send follow-ups from anywhere. -[iOS App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) · [Android APK 0.0.55](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) · [Docs →](https://www.onorca.dev/docs/mobile) +[iOS App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) · [Android APK](https://www.onorca.dev/download/android) · [Docs →](https://www.onorca.dev/docs/mobile) @@ -234,7 +234,7 @@ yay -S stably-orca-bin Pair with your desktop app to monitor and steer your agents from your phone. - **iOS:** [Download on the App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) -- **Android:** [Download APK 0.0.55](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) · [Install guide](https://www.onorca.dev/docs/android-apk) +- **Android:** [Download APK](https://www.onorca.dev/download/android) · [Install guide](https://www.onorca.dev/docs/android-apk) --- diff --git a/config/scripts/bump-android-apk-download-version.mjs b/config/scripts/bump-android-apk-download-version.mjs new file mode 100644 index 00000000000..6294c5b0b88 --- /dev/null +++ b/config/scripts/bump-android-apk-download-version.mjs @@ -0,0 +1,41 @@ +#!/usr/bin/env node + +// Rewrites the marketing site's ANDROID_RELEASE_VERSION, which /download/android and every +// APK link derive from. Usage: bump-android-apk-download-version.mjs + +import { readFileSync, writeFileSync } from 'node:fs' +import { pathToFileURL } from 'node:url' +import { compareReleaseTags } from './stable-release-tags.mjs' + +const VERSION_LINE = /^(export const ANDROID_RELEASE_VERSION = ")(\d+\.\d+\.\d+)(";)$/m + +/** The source pointing at `version`, unchanged when it already names that or a newer one. */ +export function bumpAndroidApkDownloadVersion(source, version) { + if (!/^\d+\.\d+\.\d+$/.test(version)) { + throw new Error(`Android release version must use x.y.z format: ${version}`) + } + const match = VERSION_LINE.exec(source) + if (!match) { + throw new Error('ANDROID_RELEASE_VERSION declaration not found') + } + // Why: rerunning an older release must not walk the download back. + if (compareReleaseTags(match[2], version) >= 0) { + return { previousVersion: match[2], source } + } + return { + previousVersion: match[2], + source: source.replace(VERSION_LINE, `$1${version}$3`) + } +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + const [file, version] = process.argv.slice(2) + const before = readFileSync(file, 'utf8') + const { previousVersion, source } = bumpAndroidApkDownloadVersion(before, version) + if (source === before) { + console.log(`Android APK download already at ${previousVersion}; nothing to bump`) + } else { + writeFileSync(file, source) + console.log(`Android APK download bumped ${previousVersion} -> ${version}`) + } +} diff --git a/config/scripts/bump-android-apk-download-version.test.mjs b/config/scripts/bump-android-apk-download-version.test.mjs new file mode 100644 index 00000000000..a607dc2ab5d --- /dev/null +++ b/config/scripts/bump-android-apk-download-version.test.mjs @@ -0,0 +1,36 @@ +import { describe, expect, it } from 'vitest' +import { bumpAndroidApkDownloadVersion } from './bump-android-apk-download-version.mjs' + +const source = (version) => + [ + 'import { getDownloadPlatforms } from "./downloadPlatforms";', + '', + `export const ANDROID_RELEASE_VERSION = "${version}";`, + 'export const ANDROID_DOWNLOAD_URL = `https://github.com/stablyai/orca/releases/download/mobile-android-v${ANDROID_RELEASE_VERSION}/app-release.apk`;', + '' + ].join('\n') + +describe('bumpAndroidApkDownloadVersion', () => { + it('rewrites only the version declaration', () => { + expect(bumpAndroidApkDownloadVersion(source('0.0.52'), '0.0.55')).toEqual({ + previousVersion: '0.0.52', + source: source('0.0.55') + }) + }) + + it('compares numerically, not as text', () => { + expect(bumpAndroidApkDownloadVersion(source('0.0.9'), '0.0.10').source).toBe(source('0.0.10')) + }) + + it('leaves the same or a newer version in place', () => { + expect(bumpAndroidApkDownloadVersion(source('0.0.55'), '0.0.55').source).toBe(source('0.0.55')) + expect(bumpAndroidApkDownloadVersion(source('0.0.56'), '0.0.55').source).toBe(source('0.0.56')) + }) + + it('fails loudly when the declaration moved or the version is malformed', () => { + expect(() => bumpAndroidApkDownloadVersion('export const OTHER = "0.0.1";', '0.0.55')).toThrow( + 'ANDROID_RELEASE_VERSION declaration not found' + ) + expect(() => bumpAndroidApkDownloadVersion(source('0.0.52'), 'v0.0.55')).toThrow('x.y.z') + }) +}) diff --git a/docs/readme/README.es.md b/docs/readme/README.es.md index a2ba37f6641..76b997525ab 100644 --- a/docs/readme/README.es.md +++ b/docs/readme/README.es.md @@ -36,7 +36,7 @@ Supervisa y dirige a tus agentes desde el teléfono — recibe una notificación cuando un agente termine y envía instrucciones de seguimiento desde cualquier lugar. -[App Store de iOS](https://apps.apple.com/us/app/orca-ide/id6766130217) · [APK para Android](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) · [Docs →](https://www.onorca.dev/docs/mobile) +[App Store de iOS](https://apps.apple.com/us/app/orca-ide/id6766130217) · [APK para Android](https://www.onorca.dev/download/android) · [Docs →](https://www.onorca.dev/docs/mobile) @@ -231,7 +231,7 @@ yay -S stably-orca-bin Vincúlala con tu app de escritorio para supervisar y dirigir a tus agentes desde el teléfono. - **iOS:** [Descargar desde App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) -- **Android:** [Descargar el APK](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) +- **Android:** [Descargar el APK](https://www.onorca.dev/download/android) --- diff --git a/docs/readme/README.fr.md b/docs/readme/README.fr.md index 25e793af78d..3e8b89eb802 100644 --- a/docs/readme/README.fr.md +++ b/docs/readme/README.fr.md @@ -40,7 +40,7 @@ Surveillez et pilotez vos agents depuis votre téléphone — soyez notifié quand un agent termine, et envoyez des instructions de suivi où que vous soyez. -[App Store iOS](https://apps.apple.com/us/app/orca-ide/id6766130217) · [APK Android 0.0.55](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) · [Docs →](https://www.onorca.dev/docs/mobile) +[App Store iOS](https://apps.apple.com/us/app/orca-ide/id6766130217) · [APK Android](https://www.onorca.dev/download/android) · [Docs →](https://www.onorca.dev/docs/mobile) @@ -238,7 +238,7 @@ yay -S stably-orca-bin Associez-la à l'app de bureau pour surveiller et piloter vos agents depuis votre téléphone. - **iOS :** [Télécharger sur l'App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) -- **Android :** [Télécharger l'APK 0.0.55](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) +- **Android :** [Télécharger l'APK](https://www.onorca.dev/download/android) --- diff --git a/docs/readme/README.ja.md b/docs/readme/README.ja.md index e0b7bc3247c..ff4cde89bc6 100644 --- a/docs/readme/README.ja.md +++ b/docs/readme/README.ja.md @@ -36,7 +36,7 @@ スマートフォンからエージェントを監視・操作 — エージェントの完了を通知で受け取り、どこからでもフォローアップを送信できます。 -[iOS App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) · [Android APK](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) · [ドキュメント →](https://www.onorca.dev/docs/mobile) +[iOS App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) · [Android APK](https://www.onorca.dev/download/android) · [ドキュメント →](https://www.onorca.dev/docs/mobile) @@ -231,7 +231,7 @@ yay -S stably-orca-bin デスクトップアプリとペアリングして、スマートフォンからエージェントを監視・操作できます。 - **iOS:** [App Store からダウンロード](https://apps.apple.com/us/app/orca-ide/id6766130217) -- **Android:** [APK をダウンロード](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) +- **Android:** [APK をダウンロード](https://www.onorca.dev/download/android) --- diff --git a/docs/readme/README.ko.md b/docs/readme/README.ko.md index 11608a46915..731197ba92e 100644 --- a/docs/readme/README.ko.md +++ b/docs/readme/README.ko.md @@ -36,7 +36,7 @@ 휴대폰에서 에이전트를 모니터링하고 조종하세요 — 에이전트가 완료되면 알림을 받고 어디서든 후속 지시를 보낼 수 있습니다. -[iOS App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) · [Android APK 0.0.55](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) · [문서 →](https://www.onorca.dev/docs/mobile) +[iOS App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) · [Android APK](https://www.onorca.dev/download/android) · [문서 →](https://www.onorca.dev/docs/mobile) @@ -233,7 +233,7 @@ yay -S stably-orca-bin 데스크톱 앱과 페어링해 휴대폰에서 에이전트를 모니터링하고 조종하세요. - **iOS:** [App Store에서 다운로드](https://apps.apple.com/us/app/orca-ide/id6766130217) -- **Android:** [APK 0.0.55 다운로드](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) · [설치 가이드](https://www.onorca.dev/docs/android-apk) +- **Android:** [APK 다운로드](https://www.onorca.dev/download/android) · [설치 가이드](https://www.onorca.dev/docs/android-apk) --- diff --git a/docs/readme/README.pt.md b/docs/readme/README.pt.md index 1958db54cfa..44b87a271fe 100644 --- a/docs/readme/README.pt.md +++ b/docs/readme/README.pt.md @@ -36,7 +36,7 @@ Monitore e conduza seus agentes pelo celular — receba uma notificação quando um agente terminar e envie instruções de acompanhamento de qualquer lugar. -[App Store para iOS](https://apps.apple.com/us/app/orca-ide/id6766130217) · [APK Android 0.0.55](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) · [Docs →](https://www.onorca.dev/docs/mobile) +[App Store para iOS](https://apps.apple.com/us/app/orca-ide/id6766130217) · [APK Android](https://www.onorca.dev/download/android) · [Docs →](https://www.onorca.dev/docs/mobile) @@ -233,7 +233,7 @@ yay -S stably-orca-bin Conecte ao app desktop para monitorar e conduzir seus agentes pelo celular. - **iOS:** [Baixar na App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) -- **Android:** [Baixar APK 0.0.55](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) +- **Android:** [Baixar APK](https://www.onorca.dev/download/android) --- diff --git a/docs/readme/README.zh-CN.md b/docs/readme/README.zh-CN.md index d047f53304f..15776aaf833 100644 --- a/docs/readme/README.zh-CN.md +++ b/docs/readme/README.zh-CN.md @@ -36,7 +36,7 @@ 用手机监控并指挥你的智能体 — 智能体完成时收到通知,随时随地发送后续指令。 -[iOS App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) · [Android APK](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) · [文档 →](https://www.onorca.dev/docs/mobile) +[iOS App Store](https://apps.apple.com/us/app/orca-ide/id6766130217) · [Android APK](https://www.onorca.dev/download/android) · [文档 →](https://www.onorca.dev/docs/mobile) @@ -231,7 +231,7 @@ yay -S stably-orca-bin 与桌面应用配对,用手机监控并指挥你的智能体。 - **iOS:** [从 App Store 下载](https://apps.apple.com/us/app/orca-ide/id6766130217) -- **Android:** [下载 APK](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.55/app-release.apk) +- **Android:** [下载 APK](https://www.onorca.dev/download/android) --- diff --git a/docs/site/content/docs/mobile.mdx b/docs/site/content/docs/mobile.mdx index 5883cb81fcd..dd02717a238 100644 --- a/docs/site/content/docs/mobile.mdx +++ b/docs/site/content/docs/mobile.mdx @@ -10,8 +10,8 @@ The Orca mobile companion is an iOS/Android app that pairs with your desktop Orc The mobile companion is in beta. Install iOS from the [App Store](https://apps.apple.com/us/app/orca-ide/id6766130217), join the [TestFlight preview - channel](https://testflight.apple.com/join/YjeGMQBA), or install Android from the [current APK - 0.0.48](https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.48/app-release.apk). + channel](https://testflight.apple.com/join/YjeGMQBA), or install Android from the [current + APK](https://www.onorca.dev/download/android). ## What you can do from mobile diff --git a/src/renderer/src/components/mobile/mobile-platform-copy.ts b/src/renderer/src/components/mobile/mobile-platform-copy.ts index 45149f90858..8c229ef1b85 100644 --- a/src/renderer/src/components/mobile/mobile-platform-copy.ts +++ b/src/renderer/src/components/mobile/mobile-platform-copy.ts @@ -22,7 +22,7 @@ const IOS_CHANNEL_COPY: Record = { const ANDROID_COPY: InstallCopy = { ctaLabel: 'Download APK', - url: 'https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.52/app-release.apk' + url: 'https://www.onorca.dev/download/android' } export function getInstallCopy(platform: Platform, iosChannel: IosChannel): InstallCopy { diff --git a/src/renderer/src/components/settings/MobileSettingsPane.tsx b/src/renderer/src/components/settings/MobileSettingsPane.tsx index 203e95abbae..f4a77a5776f 100644 --- a/src/renderer/src/components/settings/MobileSettingsPane.tsx +++ b/src/renderer/src/components/settings/MobileSettingsPane.tsx @@ -12,8 +12,7 @@ import { MobileRelayBetaNotice } from './MobileRelayBetaNotice' export { getMobileSettingsPaneSearchEntries } const ORCA_IOS_APP_STORE_URL = 'https://apps.apple.com/app/orca-ide/id6766130217' -const ORCA_ANDROID_APK_URL = - 'https://github.com/stablyai/orca/releases/download/mobile-android-v0.0.52/app-release.apk' +const ORCA_ANDROID_APK_URL = 'https://www.onorca.dev/download/android' export function MobileSettingsPane(): React.JSX.Element { const showMobileButton = useAppStore((s) => s.settings?.showMobileButton !== false)