Run 31 collided with a prior manual upload at versionCode 31. Add a
+100 offset so the next workflow run uploads at versionCode 132 and
all subsequent runs continue monotonically past historical conflicts.
Refs #32
* ci(play): add track/status inputs to publish workflow
Lets the Play publish run target a public track (production/beta) and
choose draft vs completed, instead of being hard-wired to internal.
Defaults stay internal/completed so tag-push and release triggers are
unchanged. Enables promoting the app to a publicly-downloadable track —
the prerequisite for any real download growth.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(play): record user authorization for production go-live
* docs(fdroid): correct metadata to cc.agentlabs.opencode + agentlabs.cc, flag post-rename tag gate
The fdroiddata submission still referenced the old package ai.opencode.mobile
and v0.3.1. Update package id, website, and document the real blocker: F-Droid
mainline needs a release tag built AFTER the package rename (v0.4.1 APK is the
old id) plus Play production live and a reproducible build. Signing fingerprint
is unchanged across the rename.
* docs(launch): ready-to-fire distribution kit (Show HN, Reddit, PH, X, dev.to)
Copy-paste launch posts + ordered fire checklist so distribution starts the
moment the public listing is live. Store URLs left as {{PLAY_URL}}/{{FDROID_URL}}
placeholders; web hub agentlabs.cc/opencode is live now.
---------
Co-authored-by: engineer <engineer@opencode.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
publish-play-store.yml caches android/build + intermediates with a
restore-keys prefix fallback. After the package rename, that fallback
restored a generated autolinking tree (ReactNativeApplicationEntryPoint.java)
referencing the OLD package ai.opencode.mobile.BuildConfig, so
compileReleaseJavaWithJavac failed. Delete generated + intermediates
before prebuild so they regenerate for cc.agentlabs.opencode.
Build.yml has no Gradle cache, which is why it built the new package fine.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The earlier rename commit did not persist the package-identity edits for
app.json, build.gradle, fastlane, the publish workflow, and the Kotlin
package declarations (they were reverted in the working tree after staging).
HEAD therefore still built ai.opencode.mobile. This commits the real
cc.agentlabs.opencode identity so CI builds the rebranded package.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(security): fail closed on biometric init error
H-03: setting isAuthenticated: true on initialization failure was a
security bypass — any crash during biometric setup granted full access.
Fail closed instead; user sees auth prompt on next open.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(security): use Crypto.randomUUID for connection IDs
H-04: Math.random() is not cryptographically random. Connection IDs are
used as SecureStore key suffixes; switch to expo-crypto randomUUID for
a secure source.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(deps): pin expo-crypto to ~15.0.9
15.0.10 does not exist on npm; ~15.0.9 is the latest stable in the 15.x series compatible with Expo SDK 54.
* feat: add OpenCode Connect coming-soon waitlist card
Adds a discoverable 'OpenCode Connect — Coming Soon' card to the
add-connection quick-connect screen. Users can enter their email and
tap 'Join Waitlist' to send a pre-filled mailto. No backend required.
* fix(cua): detect actual screen dimensions and fix JSON parsing
- Get real screen size via `wm size` instead of hardcoding 1080x2400;
emulator is 1080x1920 so y-coordinates were systematically off
- Extract first JSON object via regex when model returns multiple objects
- Use AZURE_OPENAI_MODEL env var for deployment name (defaults gpt-5.4)
- Add AZURE_DEV_AI_* path for Azure AI Foundry endpoints
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(security): SHA-pin upload-google-play and sanitize notification bodies
M-02: Pin r0adkll/upload-google-play to commit SHA e738b9d (v1.1.5)
to prevent supply-chain hijack via tag mutation.
M-03: Sanitize all push notification bodies — strip control chars,
truncate to 200 chars. Prevents server-supplied strings (error messages,
file paths from permission patterns, session titles) from leaking
unbounded text into the OS notification drawer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(privacy): add telemetry consent gate for Sentry crash reporting
Sentry was always-on, violating F-Droid anti-feature policy and user
trust norms. Now gated behind explicit opt-in:
- First-launch consent modal (TelemetryConsentModal) shows once on
fresh install; user can Allow or Decline.
- Consent state persisted in expo-secure-store (survives restarts).
- Settings > Privacy section: crash reporting toggle + privacy policy link.
- initSentry() called only after consent granted — not on app start.
Closes#3 (partial)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(config): add real icons and complete iOS/Android app.json config
- Add 1024×1024 app icon, 432×432 adaptive icon foreground, 200×200 splash
- iOS: push notification entitlement (aps-environment: production), speech/
microphone/camera/photo usage descriptions for future features, disable
ITSAppUsesNonExemptEncryption
- Android: adaptive icon with dark background (#0F172A), versionCode: 1
- expo-notifications plugin wired in app.json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(dist): add iOS CI workflow, README rewrite, CONTRIBUTING, and LICENSE
- publish-app-store.yml: EAS Build + TestFlight submission; runs on tag/release/
workflow_dispatch; bumps ios.buildNumber from github.run_number
- README: full rewrite — features, install badges, connection guide, contributing
- CONTRIBUTING.md: contribution guide for OSS contributors
- LICENSE: MIT
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(dist): add store listings, strategy, privacy policy, F-Droid/IzzyOnDroid templates
- distribution/strategy.md: monetization strategy (free client + opencode Cloud)
- distribution/play-listing.md: Google Play store copy (name, description, tags)
- distribution/app-store-listing.md: App Store listing copy
- distribution/privacy-policy.{md,html}: GDPR-compliant privacy policy
- distribution/PLAY_CONSOLE_SETUP.md: Play Console setup runbook
- distribution/ios-enrollment-runbook.md: Apple Developer Program enrollment steps
- distribution/SIGNING-KEY-FINGERPRINTS.md: keystore fingerprint for reproducible builds
- distribution/fdroid-submission/: F-Droid metadata template
- distribution/izzyondroid-submission/: IzzyOnDroid submission template
- distribution/whatsnew/: Play Store release notes (en-US)
- distribution/whatsnew-ios/: TestFlight release notes
- distribution/play-graphics/: Play Store screenshot placeholders
- distribution/app-store-graphics/: App Store screenshot placeholders
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(telemetry): handle SecureStore failure + Android back button
- add .catch() on loadTelemetryConsent() so SecureStore rejection
shows the consent modal instead of blocking startup forever
- add onRequestClose={onDecline} to Modal so Android back button
records the decline rather than silently dismissing
- fix catch block in telemetry.ts to not clobber _resolved when
SecureStore read fails mid-session
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ci): run gradlew clean to prevent stale modules.json duplicate
Sentry Gradle plugin writes modules.json to src/main/assets; cached
build intermediates contain an old copy → mergeReleaseAssets fails
with 'Duplicate resources'. Running clean before assembleRelease
clears the intermediate state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ci): remove android build output cache causing duplicate modules.json
Caching android/app/build/intermediates and android/app/.cxx causes
two issues:
1. Stale modules.json in intermediates → Duplicate resources error
2. .cxx CMake artifacts reference absolute paths → ninja clean fails
Keeping only Gradle distribution cache (~/.gradle) which is safe.
Expo prebuild regenerates android sources fresh each run anyway.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- actions/setup-node cache: npm
- actions/cache for ~/.gradle/caches, ~/.gradle/wrapper, android/.gradle
- actions/cache for Android intermediates (android/app/build/intermediates,
android/build, android/app/.cxx)
- Skip debug keystore regeneration if cached
- Add workflow_dispatch to publish-play-store for manual re-runs
Cuts a clean run from ~6m to ~2-3m once warm.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The sentry-cli source-map upload during bundleRelease fails with
"An organization ID or slug is required" because SENTRY_ORG,
SENTRY_PROJECT and SENTRY_AUTH_TOKEN were only declared in build.yml.
Also align npm install with --legacy-peer-deps to match build.yml.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>