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)
|