Commit Graph

209 Commits

Author SHA1 Message Date
engineer
6df5d4004e docs(tasks): record F-Droid self-hosted deprioritization + session state 2026-06-01 15:22:33 -07:00
engineer
1e07e36d5c fix(ci): pin androguard==4.1.4 for F-Droid publish (verified locally)
Reproduced locally against the v0.4.2 APK: androguard 4.0.x fails resource
parsing ('res1 must be zero!'), 4.1.0/4.1.1 fail signature parsing
('NoOverwriteDict' object has no attribute 'append'), and 4.1.4 parses both
cleanly. fdroidserver 2.4.4's own resolver pulls a buggy 4.1.x, so pin 4.1.4.
2026-06-01 15:00:59 -07:00
engineer
1c242e6a21 fix(ci): use latest fdroidserver for F-Droid publish
Pinning fdroidserver 2.4.4 hit androguard parse bugs on modern aapt2 APKs
(4.1+: NoOverwriteDict.append; 4.0.x: 'res1 must be zero!'). Upgrade to latest
fdroidserver which ships a compatible androguard.
2026-06-01 14:37:32 -07:00
engineer
8e06b860ac fix(dist): remove AI-generated fake screenshots; use real app captures
The phone-01/02/03 'screenshots' were AI-generated mockups (Apple '9:41'
marketing clock on an Android app, synthetic dark-theme rendering that doesn't
match the app's actual light theme, text overlapping buttons). Shipping these
as screenshots violates Google Play's real-screenshot policy and misleads users.

- Delete the three fake mockups.
- Add a real screenshot captured from the app running on an Android emulator
  (build cc.agentlabs.opencode) under play-graphics/screenshots/.
- Fix README store badges: were falsely marked 'available' linking the old
  ai.opencode.mobile package. Now: real APK download (GitHub releases),
  Google Play 'coming soon', F-Droid 'submitted' (MR #39530).

Connected-state screenshots (session list, streaming chat, diff viewer) will be
captured from the end-to-end smoke test (app + real opencode server).
2026-06-01 14:36:23 -07:00
engineer
dcb6ee0c66 fix(ci): pin androguard<4.1 for F-Droid publish
fdroidserver 2.4.4 + androguard 4.1+ crashes in 'fdroid update' with
"'NoOverwriteDict' object has no attribute 'append'" while parsing the APK
v2/v3 signature. Pin androguard>=4.0,<4.1 to restore the self-hosted F-Droid
repo publish.
2026-06-01 14:16:07 -07:00
engineer
0d25b3705c chore: release v0.4.2 — first post-rename build (cc.agentlabs.opencode)
First tagged release after the ai.opencode.mobile -> cc.agentlabs.opencode
rename. Produces a signed cc.agentlabs.opencode APK on the GitHub release and
refreshes the self-hosted F-Droid repo to the current package — prerequisite
for the F-Droid mainline / IzzyOnDroid submissions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 13:41:59 -07:00
engineer
6351dd6e71 docs: repoint website links to www.vibebrowser.app/opencode
The canonical public landing page is https://www.vibebrowser.app/opencode.
Repoint README and store-listing website references from agentlabs.cc/opencode
to www.vibebrowser.app/opencode. Privacy-policy URLs and GitHub repo links
left unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 13:20:39 -07:00
engineer
6dc7e71a40 docs: point website/homepage links to agentlabs.cc/opencode
Update product/marketing website references in README and store-listing
docs from the old vibebrowser.app subdomain to the new landing page at
https://agentlabs.cc/opencode. Privacy-policy URLs and source-repo links
left unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 15:08:27 -07:00
engineer
a481e63bd3 docs(agents): add work-tracking discipline (use GitHub issue, not /tmp/AGENTS churn)
Track multi-step/upgrade work in the related GitHub issue via gh issue
comment, not by editing AGENTS.md or writing /tmp scratch files. Verify
steps in the real channel before claiming done. Drive web UIs via
snapshot->act-on-current-uids->re-snapshot, never batched/guessed clicks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 13:54:12 -07:00
engineer
c667331593 docs(privacy): publish privacy policy via GitHub Pages (cc.agentlabs.opencode)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 13:14:15 -07:00
engineer
67e4c1f379 fix(ci): purge stale generated sources before publish build
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>
2026-05-30 13:12:58 -07:00
engineer
b808ad114e docs(tasks): correct verify.md with real CUA launch+screenshot evidence
Replace earlier paraphrased launch block with verbatim job-log lines
(am start cc.agentlabs.opencode/.MainActivity, 15 driven steps) and
screenshot proof (Sessions + Add-Connection render). Failure is the
env connection-timeout gap (#15), not a rename regression.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 05:07:35 -07:00
engineer
6985e74965 docs(tasks): rebrand-cc-agentlabs ownership audit trail
Rename verified: HEAD builds cc.agentlabs.opencode (build green) and the
app launches at runtime under the new package. CUA session goal blocked
by CI env (no opencode server) -> issue #15.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 05:05:35 -07:00
engineer
dff9dc5a79 docs(tasks): rebrand-cc-agentlabs ownership audit trail
success/design/verify/decisions/worklog for the package rename slice.
Rename verified: build green + runtime launch of cc.agentlabs.opencode.
CUA session goal blocked by env (no opencode server in CI) -> issue #15.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 05:04:45 -07:00
engineer
6405e2b9d9 refactor: commit package rename for core build files
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>
2026-05-30 04:17:31 -07:00
engineer
c699d0b0bb fix(ci): set CUA smoke APP_PACKAGE to cc.agentlabs.opencode
Rename commit missed the Python launcher constant; HEAD still targeted
the old package so the smoke could not find the installed app.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 04:14:53 -07:00
engineer
9cd5911f23 fix(ci): drop stale ai.opencode.mobile launch in CUA smoke
Rename left both old and new package am-start lines; old package is no
longer installed and pollutes the smoke launch. Launch only
cc.agentlabs.opencode/.MainActivity.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 04:12:00 -07:00
engineer
a4cd22ef4b docs(aso): finalize Play Store SEO listing copy
Add ASO audit and apply recommendations to play-listing.md (optimized
title, short/full description, category, tags), refresh whatsnew, and
update AGENTS.md Play Console section for the cc.agentlabs.opencode rebrand.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 04:09:16 -07:00
engineer
927bcc3689 refactor: rename package ai.opencode.mobile -> cc.agentlabs.opencode
Rebrand to agentlabs.cc domain. Updates applicationId/namespace, Kotlin
package + source dir, Expo bundleIdentifier/package, CI publish + CUA
workflows, fastlane, and the CUA smoke launcher. Targets new Play Console
app (id 4976021563707170091); legacy ai.opencode.mobile app is orphaned.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 03:54:24 -07:00
engineer
7098823248 fix(android): add org/project to sentry.properties
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-29 10:32:01 -07:00
engineer
ec906341de fix(ci): disable Sentry upload in CUA smoke test build
CUA test doesn't need source maps uploaded to Sentry.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-28 01:25:45 -07:00
engineer
1c098f742b fix(ci): use reactivecircus/android-emulator-runner for reliable boot
- Switch from manual emulator management to the proven emulator-runner action
- Use API 30 (boots faster than 34 with software rendering)
- Build APK before starting emulator to minimize emulator uptime
- All emulator-dependent steps run inside the action's script block
- Move env vars to job level for cleaner structure

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-28 01:16:54 -07:00
engineer
e3384677bc fix(ci): enable KVM and fix emulator boot in CUA smoke test
- Enable KVM for hardware acceleration (required for x86_64 emulator)
- Use nohup for emulator process to prevent terminal association issues
- Add avdmanager list to verify AVD creation
- Include platform-tools in sdkmanager install
- Increase boot timeout to 180s
- Upload emulator.log as artifact for debugging
- Reduce job timeout to 45min (was 60)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-28 00:23:56 -07:00
engineer
7ec3461304 fix: use release keystore in CI when RELEASE_STORE_FILE is set
The build.gradle now reads RELEASE_STORE_FILE, RELEASE_STORE_PASSWORD,
RELEASE_KEY_ALIAS, and RELEASE_KEY_PASSWORD env vars for release signing.
Falls back to debug keystore for local development.

Also updates whatsnew for v0.4.1.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-28 00:20:21 -07:00
engineer
88bde78b10 docs: add chrome-devtools config and Play Console info to AGENTS.md
- Document chrome-devtools-mcp setup (autoConnect, port 9333, no --remote-debugging-port)
- Add Google Play Console details (app ID, service account, console URL)
- Document CUA test trigger requirements (mandatory before merge/release)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-27 15:28:30 -07:00
engineer
c12d61ba4f ci: trigger CUA smoke test on release tags + document test policy
- Add v* tag trigger to cua-smoke.yml so releases are E2E tested
- Add 'When to run CUA test' section to AGENTS.md documenting mandatory testing

Closes #13 (partial)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-27 14:58:36 -07:00
engineer
d0b118e265 chore: release v0.4.1 — CI improvements & cleanup
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-27 09:17:27 -07:00
Den
3fc29de724 chore: apply CI improvements and remove stale task artifacts (#12)
- Increase CUA smoke test timeout to 60min
- Add npm and Gradle caching to CI workflow
- Add emulator to PATH explicitly
- Remove .tasks/ directory (stale tracking files)

Closes #11

Co-authored-by: engineer <engineer@opencode.ai>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-27 09:05:11 -07:00
Den
32f7af4e11 fix(sessions): recover home-scoped list after fresh connect
* fix(sessions): use active connection client directly, remove roots filter

Root cause A: loadSessions was calling clientForDirectory(serverHome) which
scoped the session list to /home/azureuser — a different project than the
server's active CWD. Sessions in the current project (e.g. opencode-mobile)
were never returned.

Root cause B: roots:true filtered out sessions that have a parentID (sub-task /
AUTO-REVIEW sessions), hiding valid sessions from the list.

Fix: use connState.client directly (the connection's active directory) and drop
the roots filter so all sessions for that project are visible.

Also adds a verify_session_list CUA smoke scenario that navigates back to the
sessions tab after creating a session and asserts the list is non-empty —
covering the regression path that was previously untested.

* fix(sessions): fetch serverHome in addConnection so loadSessions shows correct sessions

Root cause: addConnection() built the HTTP client but never fetched serverHome
(only loadConnections and setActiveConnection did). When the user adds a new
connection (fresh install / first sign-in), serverHome = null, so loadSessions
fell through to connState.client (the server's CWD). On this dev server the CWD
is the deploy directory — 11 old May-19 sessions that are not the user's recent
work sessions.

Fix: addConnection now fetches currentProject + serverHome via the same
Promise.all as setActiveConnection, before calling set(). This ensures
loadSessions immediately uses clientForDirectory(serverHome) → the global
project → the user's actual recent parent sessions.

Also adds --opencode-url flag to the CUA smoke script, which appends a
connect_and_verify_sessions scenario that reproduces the regression:
  python scripts/android-cua-smoke.py --opencode-url http://100.108.64.76:4096

* fix(sessions): recover home scope after fresh connect

Resolve stale deploy-only session list by recovering server home during first load and keeping regression coverage in default Android CUA smoke and CI.

* chore(release): bump version to 0.4.0
2026-05-26 19:50:17 -07:00
Dzianis Vauchok
64aa4a3bce chore(ci): upgrade upload/download-artifact to Node.js 24-compatible versions
upload-artifact v7, download-artifact v8. Clears last Node.js 20 deprecation warning.
2026-05-26 09:31:55 +00:00
Dzianis Vauchok
d45ee297f8 chore(ci): upgrade actions to Node.js 24-compatible versions
checkout v6, setup-node v6, setup-java v5, cache v5, setup-android v4.
GitHub forces Node.js 24 for all action runners on June 2, 2026.
2026-05-26 09:10:26 +00:00
Dzianis Vauchok
586b01e7f8 chore: release v0.3.2 — session visibility fix 2026-05-26 08:30:49 +00:00
Den
a42d04e1d0 fix: cross-directory session visibility and API routing
fix: remove roots filter from session list to show all sessions
2026-05-26 01:30:00 -07:00
Dzianis Vauchok
0ef3dd37b6 fix: use directory-aware client for delete, rename, command, permissions, questions
- sessions.ts: deleteSession looks up session.directory and uses clientFor()
  instead of bare client, so cross-project deletes hit the right server path
- index.tsx: submitRename uses clientForDirectory(session.directory) so renames
  work for sessions not owned by the active project directory
- index.tsx: handleSwitchDirectory calls catalog.load() after a directory switch
  so agents/commands/providers refresh for the new project
- session/[id].tsx: introduce sessionClient (directory-aware) and use it in
  handlePermissionReply, handleQuestionReply, handleQuestionReject, slash-command
  send, and the refreshPending bootstrap call; also add 'directory' to useEffect deps
- catalog.ts: remove debug console.log
2026-05-26 08:29:35 +00:00
Dzianis Vauchok
ce598e2a52 fix: use server home path for session listing to show all projects
When no project directory is explicitly selected, the session list was
filtered to the server's CWD, hiding sessions from other projects.

Fix by using the server's home path (fetched from /path) as the
x-opencode-directory header when listing sessions without an explicit
project directory. This ensures recent sessions across all projects
appear in the list.
2026-05-26 08:29:35 +00:00
Dzianis Vauchok
d3d60f55ab fix: reload sessions on tab focus instead of only on client change
The sessions screen was using useEffect with [client] to load sessions,
which only fired when the client object reference changed. If the app
was backgrounded and later foregrounded (common scenario on mobile),
the session list was never refreshed, showing stale data.

Replaced with useFocusEffect from expo-router so sessions are
reloaded every time the sessions tab is focused — including:
- Initial mount
- Coming back from background
- Switching tabs and returning
2026-05-26 08:29:35 +00:00
Den
416ab446c4 feat(5): F-Droid CI pipeline — self-hosted repo via GitHub Pages (#7)
* feat(5): F-Droid CI pipeline — self-hosted repo via GitHub Pages

- New publish-fdroid.yml workflow: builds APK, generates F-Droid repo
  index via fdroidserver, deploys to gh-pages/fdroid/repo
- gitignore: add __pycache__/ and *.pyc
- Generated F-Droid repo signing keystore + stored as GH secrets
- GitHub Pages enabled for gh-pages branch

Closes #5

* fix(5): review findings — pin fdroidserver, add index verification, clean perms

- Pin fdroidserver to 2.4.4 (verified version)
- Add post-update index.xml existence check
- Remove unnecessary pages:write + id-token:write perms

* docs(5): add test report and review artifacts
2026-05-26 01:06:22 -07:00
Dennis V
8dc881cc11 fix(ci): skip iOS EAS steps gracefully when Apple credentials not set
All EAS build/submit steps now guard on check-apple output.
Workflow emits a warning instead of failing when EAS_TOKEN is absent
(Apple Developer enrollment still pending).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 01:31:09 +00:00
Dennis V
b8fb390f5c feat(release): production signing in build.yml + F-Droid metadata filled
- build.yml: use production keystore (KEYSTORE_BASE64) on tag pushes,
  fall back to debug key for PRs/branch builds — build.gradle already
  reads RELEASE_STORE_FILE env var so no Gradle changes needed
- distribution/fdroid-submission/metadata.yml: filled
  AllowedAPKSigningKeys with actual SHA-256 fingerprint, commit tag
  updated to v0.3.1, version bumped to 0.3.1
- app.json: bump version 0.2.3 → 0.3.1, versionCode 1 → 2
- Add eas.json + EAS README for iOS App Store builds
- Add fastlane/metadata/android for Play Store / F-Droid graphics
- Add distribution docs: applestore, fdroid, market, playstore,
  security, threat-model, opencode-site-deploy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 01:26:35 +00:00
Dennis V
2dd49117af feat(cua): add screen recording + ArchiveBox upload to smoke test
- Record each scenario as MP4 via ADB screenrecord in a background thread
- Pull video to /tmp/cua_<scenario>.mp4 after test completes (always)
- Upload to ArchiveBox if ARCHIVEBOX_URL + ARCHIVEBOX_API_KEY env vars set;
  gracefully skips when not configured (CI default)
- Upload all artifacts (PNG screenshots + MP4 videos) always, not only on failure
- Pass ARCHIVEBOX_URL/ARCHIVEBOX_API_KEY secrets to workflow (optional)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 01:20:47 +00:00
Den
2b9b571d6e feat(privacy+dist): telemetry consent gate + app store distribution prep (#4)
* 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>
2026-05-25 17:42:03 -07:00
Dennis V
7ea41216c8 feat(release): add keystore setup + Play Store deployment guide
- Generated PKCS12 keystore (production-release.jks, alias: upload)
- Updated GitHub secrets: KEYSTORE_BASE64/PASSWORD/KEY_ALIAS/KEY_PASSWORD
- Added keystores/ to .gitignore
- Added distribution/PLAY_CONSOLE_SETUP.md: step-by-step guide to
  create GCP service account, link to Play Console, first manual
  upload, and configure PLAY_STORE_SERVICE_ACCOUNT_JSON secret
- Installed android-playstore-setup skills (sub-skills)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 10:51:56 +00:00
Dennis V
884ef13ff7 ci: cache npm + Gradle to slash compute usage
- 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>
2026-05-23 09:53:32 +00:00
Dennis V
86d87db9e5 fix(ci): pass Sentry env vars to publish-play-store workflow
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>
2026-05-23 09:52:38 +00:00
Dennis V
24667ee4f4 feat(crash): comprehensive crash + error reporting for v0.2.3
Adds full-stack crash capture so any unexpected failure — React render,
uncaught JS exception, unhandled promise rejection, or native — is
reported to Sentry with rich, scrubbed context. Expected operational
errors (timeouts, biometric cancel, etc.) stay local to preserve signal.

Changes:
- src/lib/sentry.ts: explicit native crash handlers, release/dist tags
  from app.json, beforeSend/beforeBreadcrumb URL+secret scrubbing,
  addBreadcrumb/captureException helpers, ErrorUtils + onunhandledrejection
  wrappers that always feed the in-memory log buffer (so offline Share
  Report includes the crash too).
- src/components/ErrorBoundary.tsx: new app-wide React boundary with a
  dark recovery screen — error message, top stack/component frames,
  Share Report (clipboard + native share sheet) and Try Again.
- src/lib/diagnostics.ts: buildCrashReport() reuses the existing
  DiagnosticReport pipeline so crashes and connect failures share one
  UI and one transport.
- _layout.tsx: wraps app in ErrorBoundary; emits app.lifecycle
  breadcrumb at startup.
- stores/{connections,events,sessions}.ts: high-signal breadcrumbs at
  connect, SSE connect/disconnect/reconnect, and session select.
- (tabs)/settings.tsx: fix unhandled promise on notificationsGranted().
- app.json: bump expo.version to 0.2.3.
- docs/prd.md, docs/tdd.md: new product + technical design docs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 09:00:26 +00:00
Dennis V
678750d16f docs: add Bitwarden secrets management instructions to AGENTS.md 2026-05-23 04:02:45 +00:00
Den
30be6636c2 feat(diagnostics): active connect-failure triage + Sentry + in-app share (#2)
* feat(diagnostics): active connect-failure triage + Sentry + in-app share

Replaces the opaque "Connection Failed" / "Network request failed" dead-end
with on-device diagnostics that classify *why* a connect attempt failed.

On failure (quick connect and edit-connection test), the app now:
- runs parallel probes: target /global/health, target root, and a public
  204 endpoint (internet reachability check)
- classifies the cause: malformed-url, no-internet, server-unreachable,
  health-failed, tls-error, timeout
- shows a plain-English summary + a "Share report" button that copies a
  full report (target URL, per-probe results w/ error.cause, device/app
  info, recent log ring-buffer) to the clipboard and opens the share sheet
- captures the same structured context to Sentry (auto-upload), gated on
  EXPO_PUBLIC_SENTRY_DSN so dev/CI builds work without secrets

New: src/lib/logbuffer.ts (ring buffer + logger), src/lib/diagnostics.ts
(regex URL parse — Hermes URL is incomplete — probe + report + share),
src/lib/sentry.ts (no-op-without-DSN wrapper, scrubs basic-auth from URLs).

Wired Sentry.wrap around RootLayout and initSentry() at module load.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(sentry): wire Sentry DSN + source-map upload env into build; bump to 0.2.2

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 17:07:44 -07:00
Den
e9991cb61b fix(connect): fix tailnet 'Connection Failed' (pasted-URL double scheme) + surface real error (#1)
* fix(connect): surface real connection error instead of generic dialog

testConnection swallowed the actual fetch error and returned a bare
boolean, so every failure collapsed to the same "Connection Failed"
text. On-device this made tailnet/LAN connect failures impossible to
diagnose (DNS vs timeout vs 401 vs cleartext all looked identical).

- testConnection now returns { ok, error } with the real error message
- add.tsx and [id].tsx dialogs show the error + target URL, plus a
  Tailscale/MagicDNS hint
- IP field keyboard: decimal-pad -> url, so tailnet hostnames can be
  typed (not just pasted)

Verified backend is healthy and reachable over tailnet (health 200,
port 4096 open in packet filter, cleartext present in shipped v0.2.0
APK), so the failure is client-side and was previously unobservable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(connect): normalize pasted IP/URL to avoid double scheme

Quick-connect blindly did `http://${ip}:${port}`. Pasting a full URL
(e.g. "http://100.108.64.76:4096", as the clipboard auto-paste offers)
produced "http://http://100.108.64.76:4096:4096" -> malformed URL ->
"Network request failed". This is the real tailnet connect failure:
typing a bare IP worked, pasting the displayed URL did not.

buildUrl now strips an existing http(s) scheme, drops any path, and
lifts a trailing :port out of the host field, so pasted full URLs,
host:port, and bare hosts all resolve to a single well-formed URL.

Reproduced and fixed on the Android emulator (paste full URL: fails
before, connects after).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 04:44:13 -07:00
Ubuntu
d9794a4817 fix(ci): add --legacy-peer-deps to npm install for peer dep conflicts 2026-05-19 09:07:19 +00:00
Ubuntu
5071c445ac docs: add HANDOFF.md with project status and memory notes 2026-05-19 09:06:32 +00:00