Commit Graph

150 Commits

Author SHA1 Message Date
Dennis V
c9a1382261 fix(cua): use --print-logs not --verbose (opencode serve has no --verbose) 2026-06-22 06:18:20 +00:00
Dennis V
f5471dcf5d ci(cua): add prompt_async probe + verbose server log for debugging send_message regression 2026-06-22 05:55:26 +00:00
Den
e6fbd0f608 ci(play): offset versionCode by +100 to skip collision at 31 (#34)
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
2026-06-21 22:54:14 -07:00
Dennis V
ae124d7311 release: bump app.json/package.json to 0.4.5, add changelog 32.txt
- app.json 0.4.4 -> 0.4.5 (matches build.gradle versionName)
- package.json 0.4.3 -> 0.4.5
- fastlane changelog 32.txt: notes #32 fix (sessions list shows workspace projects)
2026-06-22 05:01:44 +00:00
Den
79d26f0fbd fix(sessions): scope default to server CWD, not $HOME (#32) (#33)
Recent sessions disappeared from the list when opencode serve was launched
outside $HOME (e.g. ~/workspace/opencode). The list path scoped to
server.home, but opencode-server resolves x-opencode-directory to a project
id by exact-match, not subtree prefix. $HOME mapped to the synthetic
'global' project, which never contained the user's workspace sessions.

Change the single-source-of-truth rule to return null (no scope header) when
the connection has no explicit directory. The server then uses its own CWD
project — the same project sessions are actually created in. Both list and
create paths still derive from sessionScopeDirectory, so #10's drift cure is
preserved.

Verified against 100.108.64.76:4096: no header returns the recent workspace
sessions (Opencode npm install, autopilot_exit, ...); header=$HOME returns
only the empty global project.

Closes #32
2026-06-21 22:01:05 -07:00
Dennis V
0779a11284 docs: update HANDOFF.md — v0.4.5 submitted to Play Store production
- App in review as of 2026-06-21 (versionCode 32)
- Website live at opencode.agentlabs.cc
- CUA test rewritten with full onboarding showcase
- Next actions: wait for review, keep demo server alive, announce on approval

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01No3k1AEioE4PNUZg12TxQo
2026-06-21 04:00:38 +00:00
Dennis V
db75606df0 chore: bump versionCode to 32 (v0.4.5), add goal.md execution plan
- versionCode 6 → 32 to supersede existing internal track release
- versionName 0.4.4 → 0.4.5
- goal.md: add current_mission section with blocking checklist and execution plan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01No3k1AEioE4PNUZg12TxQo
2026-06-21 01:38:44 +00:00
Dennis V
3c498972ce feat(cua): full onboarding showcase test - connect, session, TypeScript task, settings
Rewrites android-cua-smoke.py to demonstrate the complete first-run journey
instead of the previous "ping" smoke test. The new structured multi-phase
flow covers: server connection setup, session list, new session creation,
TypeScript hello-world task submission (watching tool calls/file writes),
output verification, and Settings/model-selection screenshot.

Key changes:
- run_onboarding_showcase() orchestrates 6 sequential CUA phases with
  per-phase goals, step budgets, and PASS/FAIL phase tracking
- run_cua_step() replaces run_cua() — accepts step_label, action_delay,
  saves labeled screenshots (/tmp/cua_<phase>_<step>.png) for debugging
- Global --speed-multiplier flag scales all _sleep() calls (0.5 = 2x faster)
- Showcase is now the default mode; legacy --goal / --scenarios flags retained
  for backwards compat and CI regression scenarios
- Tighter action_delay (0.7s) and trimmed history window (14 turns) vs
  previous 1.0s / 12 turns
- Phase banner log lines ("STEP N: ...") narrate the video in real time

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01No3k1AEioE4PNUZg12TxQo
2026-06-21 01:20:44 +00:00
Dennis V
09b034eaf3 feat(distribution): add Play Store ASO listing content
Structured store listing copy for cc.agentlabs.opencode:
- Optimized title, short description, and full description
- Keyword strategy for AI coding agent / developer tools niche
- Screenshot captions for 5 key screens
- Notes for Play Console entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01No3k1AEioE4PNUZg12TxQo
2026-06-20 21:13:30 +00:00
Den
d6e84ff513 fix: stale session client ref and CUA smoke test improvements (#30)
* fix(sessions): use latestConnState.client to avoid stale reference after reconnect

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKGMRpgihA4io2frodqLjt

* fix(cua): lru_cache get_screen_size, remove redundant if-matches guard, drop inner import re

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKGMRpgihA4io2frodqLjt

* fix(cua): use center-x comparator for send button, defer screen_w fetch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKGMRpgihA4io2frodqLjt

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 03:38:06 -07:00
Den
9365a72e93 fix(ci): add emulator to PATH and increase CUA smoke timeout to 60min (#27)
* fix(ci): add emulator to PATH and increase CUA smoke timeout to 60min

- Add 'Add emulator to PATH' step after setup-android so emulator binary
  is found (was: command not found, causing adb wait-for-device to hang
  until the 30min job timeout)
- Increase timeout-minutes from 30 to 60 to accommodate full build
- Add npm cache and Gradle cache (same as build.yml) to speed up rebuild

* fix: address code review findings for cua-emulator-path

- Fix stale Gradle cache causing build failure after package rename
  (ai.opencode.mobile → cc.agentlabs.opencode): add purge step matching
  the one already present in publish-play-store.yml
- Fix adb launch command using old package name ai.opencode.mobile;
  updated to cc.agentlabs.opencode/.MainActivity

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKGMRpgihA4io2frodqLjt

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 02:56:44 -07:00
Den
71a1feb232 fix(ci): bump opencode Azure apiVersion to support /responses endpoint (#22) (#24)
* fix(ci): bump opencode Azure apiVersion to support /responses endpoint (#22)

The CUA smoke probe was returning MODEL_CAPABLE=false because opencode's
@ai-sdk/azure provider got 'API version not supported' from Azure on
/openai/v1/responses with apiVersion=2024-08-01-preview. Split into two
envs: keep the CUA driver on 2024-08-01-preview (chat-completions only)
and bump the opencode-side provider config to 2025-04-01-preview, which
supports the new responses API.

Effect: send_message/multi_turn scenarios get included again in CUA smoke
when the probe succeeds.

* ci(cua): bound curl timeouts + diag dump on server-start hang (#22)

Step 11 'Start opencode server' has hung past the 45-min job timeout in
two consecutive runs (27195348071, 27198238465). Local boot of
opencode-ai 1.16.2 with the same heredoc config is healthy in 3s, so
something is wrong specifically on the GH-hosted runner — likely curl
post-loop waiting indefinitely on an unresponsive server.

Adds:
- set -x for command tracing
- --connect-timeout 2 -m 5 on every curl so hangs cannot exceed 5s
- HEALTHY flag + explicit exit 1 (drops the unbounded post-loop curl)
- Periodic dump every 10s: server log tail, ss listening sockets,
  process liveness — so we can see WHY the server isn't replying

Pure diagnostics; no behaviour change for the green path.

* fix(ci): use api-version=preview for /openai/v1/responses (#22)

Reproduced the probe failure locally against the same Azure resource:
all date-based api-versions (2024-08-01-preview, 2024-12-01-preview,
2025-01-01-preview, 2025-03-01-preview, 2025-04-01-preview) return:

    {"error":{"code":"BadRequest","message":"API version not supported"}}

Only api-version=preview and api-version=v1 succeed (200). This is the
new Azure OpenAI v1 responses-API style; date strings are reserved for
the legacy /openai/deployments/{model}/chat/completions endpoint.

@ai-sdk/azure 3.x already defaults apiVersion to "preview" (per the
type definition: "Custom api version to use. Defaults to `preview`."),
so this aligns the workflow with the SDK default. Probe should now
return MODEL_CAPABLE=true and the send_message scenario will run.

* test(cua): extend send_message and multi_turn waits to 30s

Assistant bubbles can take 15+ seconds to appear after send. Previous
5-second wait was too short and caused false failures even when API
calls succeeded. Re-check screenshots periodically up to 30s total.

* fix(cua): screen-relative send button threshold for #22

The send action's auto-locate filtered for y1 > 2200 and fell back to
hardcoded (996, 2358) — both assume a 1080x2400 panel. The CI emulator
(API 30 google_apis pixel profile) is 1080x1920, so:
  - the bottom_buttons filter never matched any clickable element
  - the fallback tap landed off-screen
  → 'ping' message never sent, scenario timed out with no bubbles.

Switch to a screen-relative threshold (bottom 25%) and a fallback that
uses get_screen_size() to land in the bottom-right corner regardless of
device resolution. This was masked until now because send_message was
gated by MODEL_CAPABLE=false in earlier CI runs.

Refs: #22

---------

Co-authored-by: dzianisv <dzianis.varabyou@gmail.com>
2026-06-13 23:34:48 -07:00
Den
a9822048e4 ux(quick-connect): hint users to Advanced for custom server username (#23) (#25)
Quick Connect now shows a one-line hint under the password field stating
that username defaults to 'opencode' and pointing to Advanced options for
servers using a custom OPENCODE_SERVER_USERNAME. Tap-target to switch
modes is included.

Closes #23

Co-authored-by: dzianisv <dzianis.varabyou@gmail.com>
2026-06-09 03:31:46 -07:00
engineer
3bdeeb6bef fdroid(mainline): add Binaries field to recipe; sync local metadata + log
MR #39530 remaining blocker was the missing top-level Binaries: field
(maintainer: AllowedAPKSigningKeys rejects the APK without it). Added
Binaries pointing at the GitHub release APK (v%v) and synced the stale
local distribution copy to the canonical fork recipe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 09:21:45 -07:00
engineer
18fcfab2bc marketing: add real on-device demo GIF (connect -> sessions -> streaming reply)
Built from the on-device verification capture (360px, 92KB, looping). Added to README
hero (top repo conversion surface) + docs-site/ and distribution/ for landing + launch
attachment. Demo media is the #1 conversion lever for HN/Reddit/PH — none existed before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 09:19:10 -07:00
engineer
8c75007ee5 launch: pre-flight accuracy pass on Show HN + Reddit copy
Fixed claims a technical audience would catch:
- Android build is Gradle (assembleRelease/bundleRelease), NOT EAS — EAS is only in
  the unshipped iOS workflow. Changed 'GitHub Actions + EAS' -> 'GitHub Actions (Gradle)'.
- App is Android-only: dropped 'iOS Keychain', kept 'Android Keystore'.
- Diff viewer renders into native views (ScrollView), not a FlatList.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 09:15:59 -07:00
engineer
92a022cfd1 qa: HEAD release build verified on-device — Quick Connect now succeeds (auth fix confirmed)
Built the actual release APK from HEAD (auth + UI fixes, BUILD SUCCESSFUL 11m48s) and
installed on the emulator. Same Quick Connect path that gave 401 on the CI APK now
CONNECTS and loads the sessions list. Definitive on-device proof of the fix on the
shipping build. Screenshots 07-08.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 09:13:28 -07:00
engineer
2476d4def5 qa: on-device GUI verification — connect+reply flow GREEN, auth bug reproduced
Ran a native arm64 emulator against the live opencode server, driven via adb (free
model, no LLM). Verified on real device: telemetry consent, empty state, Quick Connect
401 auth bug REPRODUCED, Advanced+username=opencode connects + loads sessions, chat
renders (bubbles/thinking/tokens), and LIVE send -> streaming reply. Screenshots +
writeup under docs/qa/. Closes the pre-posting test-gate pixel-GUI residual for the
connect->session->reply journey.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 08:51:07 -07:00
engineer
108260cec7 release: bump versionCode 5->6 for v0.4.4 + add changelog 6.txt
v0.4.3 already shipped as versionCode 5; a duplicate code would be rejected by Play and ignored by F-Droid. Bump to 6 unblocks the v0.4.4 release. QA gate passed (units + on-device E2E + visual render check screenshots in docs/qa/render-check/).
2026-06-08 08:36:53 -07:00
engineer
b0b30ea203 docs(qa): visual render-check evidence — real Gemini reply renders bug-free
Clears the owner's hard visual gate: a real gemini-2.5-flash reply rendered
through the actual app components (MessageBubble→Markdown/CodeBlock, DiffView)
via Expo web export, screenshotted in a real browser.

Per-surface verdict (all PASS, no app code changes needed):
- markdown: heading+bullets, high contrast light & dark
- code block: 430-char single line horizontally scrolls (scrolled-right reveals
  the line END), not truncated/wrapped
- diff: fenced ```diff + native DiffView render +/- coloring and scroll

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 08:33:50 -07:00
engineer
4b21ed73c2 fix(connect): default Basic-auth username to 'opencode' when password set (critical)
Quick Connect (the DEFAULT add-connection mode) has no username field, so every
auth-build site (username && password ? {..} : undefined) produced undefined auth
whenever a password was set but username empty -> NO Authorization header -> 401
against a password-protected server. This is the common setup
(OPENCODE_SERVER_PASSWORD=... opencode serve) and a top install->churn cause:
user sets a password, can't connect, gives up.

Fix: extract buildAuth() to a pure, testable module; when a password is present but
username is empty, default username to 'opencode' (the server's own default,
OPENCODE_SERVER_USERNAME ?? 'opencode'). Advanced mode's explicit username is
preserved. Replaced all 6 inline ternaries in connections.ts.

+3 regression tests (68 total pass), typecheck clean. Found while setting up an
on-device emulator test of the connect flow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 07:50:19 -07:00
engineer
e39cec3847 fix(launch): Expo SDK 52->54 in HN/Reddit copy; add reply-flow E2E evidence; version refs
- Launch posts claimed Expo SDK 52 but app is on SDK 54 (factual accuracy
  before public posting — HN/Reddit devs check this)
- docs/qa/REPLY-FLOW-E2E-2026-06-08.md: verified send->streaming reply works
  against the live opencode server via app-identical sdk.ts calls (free model);
  closes the 'opencode can't reply in CI' residual at the data-contract level
- owner-submissions.md: 0.4.3 -> 0.4.4

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 07:42:19 -07:00
engineer
bd082a4dee docs(site): add remote-access (Tailscale/Cloudflare/ngrok) and honest iOS pages
New high-intent SEO pages:
- /remote-access/ — step-by-step Tailscale, Cloudflare Tunnel, ngrok setups
  for reaching a self-hosted opencode server from Android anywhere. HowTo +
  FAQ + BreadcrumbList structured data.
- /ios/ — honest 'no iOS app yet' page: current Android app, why, options,
  roadmap, how to follow. FAQ + BreadcrumbList structured data.

Added to sitemap.xml; internal links from index, guide, opencode-on-phone,
and troubleshooting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 07:40:13 -07:00
engineer
11b4389371 docs(qa): add 5-min on-device RENDER-CHECK runbook (owner gate residual: reply/code/diff visual verify) 2026-06-08 07:33:59 -07:00
engineer
2dcc999992 fix(ci): repair dash-mangled scenario selection + make model probe accurate
Run 27139243275 FAILED with "/usr/bin/sh: Syntax error: end of file unexpected
(expecting fi)" — android-emulator-runner runs the script under dash, which
mangled the multi-line if/then/else/fi I added, so the scenarios never ran (a
real bug I introduced, not environmental). Fix:
- Move scenario-set selection into the probe step (runs under bash) and export
  SCENARIOS as a step output; the emulator script is now single-line.
- The earlier probe returned a FALSE NEGATIVE: it POSTed to /session/{id}/message
  with no model, but that endpoint REQUIRES model {providerID,modelID} (per the
  opencode SDK the app uses). Probe now sends azure/gpt-5.4 exactly like the app,
  uses -s + %{http_code} (not -sf) so the body/status are visible, and only flags
  capable on HTTP 200 + an assistant text part.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 06:23:34 -07:00
engineer
cfb0d9fe32 test(ci): widen cua-smoke gate to real core journey (connect→send→reply→list)
The CI opencode server had NO LLM provider configured — the server log only
showed "listening", never a model. opencode-ai (released npm pkg) does not read
AZURE_OPENAI_* for its own LLM; it needs an explicit provider in opencode.json +
a default `model`. So send_message/multi_turn could never pass and the gate was
stuck on --only-connect-scenario (UI journey minus the model reply).

- Wire opencode to the same Azure resource the CUA driver uses via a generated
  ~/.config/opencode/opencode.json (@ai-sdk/azure provider, resourceName derived
  from the endpoint secret at runtime, apiKey from env, default model azure/gpt-5.4).
- Add a deterministic REST probe step: create a session + send a prompt and check
  for an assistant reply BEFORE the ~30min emulator run, exporting MODEL_CAPABLE.
- Add --scenarios to android-cua-smoke.py to run an explicit named set.
- Emulator step now runs connect_and_verify_sessions + send_message +
  verify_session_list when MODEL_CAPABLE=true; falls back to the UI-only journey
  (connect + verify_session_list) otherwise, logging the environmental reason.
- Raise --max-steps to 40 so multiple scenarios fit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 05:58:19 -07:00
engineer
42fa36f3cd fix(ux): 10 UI/UX bugs from pre-release audit (toward no-bug launch gate)
Found via parallel screen audit; each confirmed in code:
- AuthGate: auto-prompt biometrics on lock (useEffect was imported but unused)
- CodeBlock: horizontal scroll for long code lines (were wrapped/mangled)
- DiffView: horizontal scroll instead of numberOfLines=1 truncation
- chat: biometric-cancel on send shows feedback instead of silently dropping msg
- chat: send failure restores input + attachments and alerts
- chat: removed dead /compact + /clear builtin commands (advertised, no-op)
- sessions: delete + rename failures alert instead of silent; rename guarded
  against double-submit
- sessions: onRefresh spinner no longer hangs forever if a refresh rejects
- add/edit connection: validate URL has http(s):// scheme before save/test

typecheck clean, 65/65 unit tests pass. Runtime UI behavior still needs on-device
verification per the pre-posting test gate (HANDOFF §0b).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 05:34:12 -07:00
engineer
609bd45889 docs(handoff): 17 commits ahead; record ASO/SEO additions + pre-posting test gate
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 05:18:43 -07:00
engineer
2ec2a87143 seo(site): add /opencode-on-phone/ — targets proven 'setup opencode on phone' query
Google 'opencode android' surfaces a 40+ comment Reddit thread ('best way to
setup opencode on phone') and not us. New high-intent page answers it directly:
HowTo + FAQ + Breadcrumb JSON-LD, 4-step setup, tunnel table, Termux contrast.
Linked from landing footer + in-content, added to sitemap (priority 0.8).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 05:18:04 -07:00
engineer
2b5519a115 aso(play): keyword-optimize title + short desc, fix dead privacy URL
- title.txt: 'OpenCode Mobile' -> 'OpenCode Mobile: AI Coding' (26/30 chars,
  adds the 'AI coding' search keyword to the strongest Play ranking field)
- short_description: front-load 'AI coding agent for Android' (71/80)
- full_description: dead privacy URL opencode.vibebrowser.app (000) ->
  live dzianisv.github.io/opencode-mobile/privacy/ (200) — was a Play
  rejection risk

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 05:18:04 -07:00
engineer
f14bd39d66 release: bump version 0.4.3 -> 0.4.4
Ships accumulated work incl session-scope fix (ee7082a) to F-Droid + Play
via v0.4.4 tag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 05:10:57 -07:00
engineer
da1e89157e docs(handoff): refresh push backlog (13 commits ahead, SEO cluster + screenshots)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 04:44:57 -07:00
engineer
b40651748f site: add app screenshot strip to landing (connect → chat → diff)
Visual proof above the fold-ish: 3 UI previews with captions + descriptive
alt text. Responsive flex strip, lazy-loaded. Conversion lever for first-time
visitors — landing had QR codes but no app visuals.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 04:44:06 -07:00
engineer
6232430fe6 seo(site): ship comparison, vs-termux, claude-code-android pages + internal links
3 long-tail pages targeting 'opencode vs chatgpt/copilot', 'vs termux',
'claude code on android'. Added to sitemap, footer nav, in-content links
from landing + guide + troubleshooting. All have canonical + install CTAs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 04:42:20 -07:00
engineer
fb03a9af47 seo(site): add /features/ page (capabilities, use cases, comparison)
Targets "opencode mobile features", "AI coding android", and
"opencode vs ChatGPT for coding" queries not covered by existing pages.
Includes SoftwareApplication + BreadcrumbList structured data.
Adds /features/ to sitemap and internal footer nav on all 5 pages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 10:00:05 -07:00
engineer
c3244b7eca docs(readme): add non-affiliation note (per upstream opencode request)
The upstream opencode project asks 'opencode-*' named projects to clarify they are
not built by or affiliated with the opencode team. Adds that note near the top.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:00:09 -07:00
engineer
13c21f3921 seo(site): add /troubleshooting/ page (connection-error queries) + internal links
Authentic troubleshooting content mapping the app's six connection-failure
diagnostics (malformed-url, no-internet, tls, health-failed, timeout,
server-unreachable) to concrete fixes. Targets real problem queries
('opencode mobile can't connect', 'opencode tailscale setup', 'network request
failed'). FAQPage + BreadcrumbList JSON-LD for rich results. Linked from landing,
guide, and download footers; added to sitemap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 01:39:44 -07:00
engineer
2b3de23e45 ci: run typecheck + unit tests on push/PR
build.yml only built the APK — the 65 unit tests and typecheck never ran in CI,
so regressions in the covered logic (headers/SSE/diagnostics/settings/etc.) could
land silently. Add a fast 'test' job (Node 24, native TS test-running) so every
push and PR enforces typecheck + npm test before merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:24:11 -07:00
engineer
6013d1d86d test(lib): cover agent-activity status labels (57→65 tests)
Extract TOOL_STATUS + statusFromPart from stores/events.ts into a pure
status-labels.ts (type-only Part import, erased at runtime; events.ts delegates).
8 tests pin the live 'what is the agent doing' labels: reasoning/text/known-tool
mappings, shared labels (search/edit groups), unknown-tool degrade to
'Running <tool>...', and the no-tool/unknown-type fallthroughs. typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:22:39 -07:00
engineer
39c4347092 test(lib): cover connection URL parsing + failure classification (42→57 tests)
Extract parseUrl + classify from diagnostics.ts into a pure diagnostics-classify.ts
(diagnostics.ts imports + re-exports the types; behavior unchanged) so the
connection-failure decision tree — the user-facing 'why did connecting fail'
guidance — is unit-testable without react-native/expo. 15 tests: URL parsing
(port defaults, IPv4-vs-hostname, path/query stripping, malformed rejection) and
every classify branch (malformed, ok, tls, no-internet, health-failed, timeout,
server-unreachable incl. the hostname-only MagicDNS hint). typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:20:27 -07:00
engineer
48bc314dfc test(stores): cover settings merge/clamp + notification sanitizer (29→42 tests)
Extract two pure helpers so they're testable without zustand/expo:
- settings-merge.ts: clampPageSize + forward-compatible mergeStoredSettings (the
  upgrade path where stored data predates a new notification category must yield
  the default, not undefined). stores/settings.ts now delegates.
- notify-format.ts: sanitizeBody (strip C0/DEL control chars, trim, cap at 200)
  used for server-supplied notification text. stores/events.ts now imports it.
Behavior unchanged; typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:01:29 -07:00
engineer
dd55ca471d test(lib): cover SSE event-stream framing (20→29 tests)
Extract the SSE chunk-buffering from sdk.ts into a pure SSEParser (sdk.ts delegates;
behavior unchanged) and pin the framing rules that are easy to break when an event
splits across network reads: partial trailing lines held until completed, frames
reassembled across 2-3 reads, [DONE] sentinel and empty/non-data lines filtered,
each frame emitted exactly once. typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:58:19 -07:00
engineer
3499167b60 test(lib): cover request-header building + log ring buffer (4→20 tests)
Extract the auth + directory-header encoding from sdk.ts into a pure, dep-free
headers.ts (sdk.ts now delegates — behavior unchanged) so the connection-critical
logic is unit-testable without expo/fetch. Add 8 header tests (ASCII passthrough,
non-ASCII/CJK percent-encoding stays header-safe, Basic auth, empty-dir handling)
and 8 logbuffer tests (serialization incl. circular-ref fallback, 200-entry ring
cap, copy semantics, formatting). typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:55:31 -07:00
engineer
b2ca5793d1 seo(site): trim meta descriptions to ~150 chars (avoid SERP truncation)
Landing/guide/download descriptions were 257/246/217 chars and truncated in
Google results. Tightened to ~150 while keeping target keywords.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:42:49 -07:00
engineer
26d61498ad seo(site): add /download/ page (transactional intent) + internal links + sitemap
Targets 'download opencode android', 'opencode apk', 'opencode f-droid'.
Serves the live install channels (self-hosted F-Droid repo + signed APK)
with SoftwareApplication + BreadcrumbList structured data. Linked from
landing hero, landing footer, and guide footer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:27:34 -07:00
engineer
b0aaddf263 refactor(readiness-check): port check.sh → check.ts (native Node 26, fetch+JSON, no curl/jq/python3)
Easier to maintain in this TS repo: typed gate definitions, native fetch/JSON
(drops the fragile jq/python3/grep branches), runs via `node check.ts` with no build/deps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 07:27:43 -07:00
engineer
6563f5ef53 fix(ui): correct mirrored chat empty-state + clipped IP placeholder; add readiness-check skill; privacy page nav/meta
- app/session/[id].tsx: chat empty-state rendered mirrored on Android (inverted FlatList) — now an untransformed overlay
- app/connection/add.tsx: shortened clipped host placeholder
- .agents/skills/readiness-check: production-readiness gate (Play+F-Droid published, app+site health)
- docs/privacy: back-nav + canonical/theme-color/description meta
Verified: tsc clean, CUA smoke green (run 26814702062)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 06:16:22 -07:00
Den
c46f273ecd fix(fdroid): disable dependenciesInfo signing block for F-Droid compliance 2026-06-03 04:52:23 -07:00
Den
a5769ca19f fix(fdroid): add expo-application installreferrer-free stub for F-Droid builds 2026-06-03 04:52:16 -07:00
Den
87d7777bf4 fix(fdroid): remove interface supertype from FirebaseMessagingDelegate stub to fix Unresolved reference compile error 2026-06-03 04:13:34 -07:00