Adds an ios-build job to the Mobile Release workflow (build + sign + TestFlight upload on a macOS runner via fastlane + App Store Connect API key), and fixes a pre-existing Mobile Checks bug where the mobile typecheck needed root deps for ../src imports.
Merged with --admin: the only failing check is the repo-wide pr.yml '@/lib/utils' vitest resolution break affecting all open PRs, unrelated to this change.
* release: v1.4.48-rc.0 [rc-slot:2026-06-05-15]
* release: v0.0.1-rc.0 [rc-slot:2026-06-06-03]
* fix(mobile): respect Android device rotation lock instead of forcing rotation
The app rotated on Android even when the system auto-rotate lock was on.
Expo's top-level `orientation: "default"` emits `android:screenOrientation="unspecified"`,
which auto-rotates on many devices regardless of the lock, and the
`react-native-screens` `orientation: 'all'` screenOption mapped to FULL_SENSOR,
which forces rotation outright.
react-native-screens exposes no orientation value that honors the rotation lock
(even 'default' calls setRequestedOrientation(UNSPECIFIED) at runtime, overriding
the manifest). The Android value that respects the lock is "fullUser", which must
come from the manifest. So:
- Add an `android-respect-rotation-lock` Expo config plugin that sets the main
activity to `android:screenOrientation="fullUser"` (honors the lock; allows all
orientations when unlocked, matching iOS).
- Remove the runtime `orientation` screenOption so the manifest value governs.
iOS behavior is unchanged (UISupportedInterfaceOrientations still lists all four).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* release: v1.4.48-rc.0 [rc-slot:2026-06-05-15]
* release: v0.0.1-rc.0 [rc-slot:2026-06-06-03]
* feat(mobile): add terminal text size (zoom) setting
The mobile terminal fits the desktop's full column count to the phone
width with a CSS scale, which cancels out xterm's raw fontSize — so there
was no way to make text bigger or smaller. Add a persisted baseline zoom
multiplier the WebView applies on top of the fit.
- Settings → Terminal → "Text size": 50%–200% presets.
- Pinch-to-zoom in the terminal snaps to the same presets and persists.
- Per-device display preference; does not change the desktop terminal.
- Extracts the xterm WebView HTML into terminal-webview-html.ts to keep
TerminalWebView.tsx within its max-lines budget.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(mobile): make terminal text size reflow columns instead of CSS scaling
Text size now drives the real xterm fontSize rather than a CSS transform
baseline. A larger cell means fewer columns fit the phone width, so the
existing measure -> terminal.updateViewport pipeline resizes the PTY and the
shell rewraps to the new width (and smaller sizes show more columns). Pinch
still snaps to a preset, but now changes the font size and reflows instead of
scaling pixels; the refit hook re-fits the PTY whenever the scale changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(mobile): restore terminal touch scrollback (undefined contentWiderThanViewport)
The single-finger touchmove handler gated horizontal panning on
contentWiderThanViewport(), which is never defined — so every one-finger
touchmove threw a ReferenceError before reaching the vertical-scroll code
below it, killing all touch scrolling including scrollback.
Replace the call with the inline overflow check clampPan() already uses
(scrollWidth * getTotalScale() > innerWidth). Vertical scroll now always runs;
two-finger pinch-to-zoom is unaffected. Merged two adjacent var decls to keep
the file under its max-lines cap without a disable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(mobile): guard terminal text scale viewport refit
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* release: v1.4.48-rc.0 [rc-slot:2026-06-05-15]
* release: v0.0.1-rc.0 [rc-slot:2026-06-06-03]
* feat(mobile): add terminal keyboard autocomplete toggle
Terminal command inputs disable autocorrect/suggestions and use a
password-class keyboard so the OS never rewrites commands, flags, or
paths. Some users want phone-style typing in the command bar.
Add a Settings → Terminal "Autocomplete & autocorrect" toggle
(persisted locally, default off). When on, the command bar enables
autoCorrect/spellCheck and uses the default keyboard so Android shows
its suggestion strip; iOS drops the ascii-capable restriction. The
direct keyboard-capture input is unchanged — it streams raw keystrokes
where suggestions cannot apply.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(mobile): remount command input when autocomplete toggles
Android caches the IME inputType at mount, so flipping the toggle did
not switch suggestions on until the field remounted.
* fix(mobile): guard autocomplete pref loads against unmount and fast toggle
Address review feedback: the settings toggle's initial load could clobber
a fast user toggle, and the session focus-effect could setState after the
screen unfocused. Both now use a guard flag.
* test mobile terminal autocomplete preference
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Add mobile diff review
* Wrap mobile review notes prompt
* Fix mobile review unreviewed navigation
* Clear review completion when a refreshed diff invalidates a reviewed file
mergeMobileDiffReviewState invalidates a file's reviewed flag when its
diff identity changes, but left completedAt set — inconsistent with
markUnreviewed. Drop completedAt on invalidation and add a regression
test.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Improve mobile session tab scrolling and editor keyboard layout
- Auto-scroll the active session tab into view within the horizontal
tab strip, using a new layout-aware utility with minimal scrolling.
- Use visual viewport measurements in the editor WebView to accurately
report keyboard insets and lift floating controls above the keyboard,
as native events can under-report covered areas.
* Fix active tab scrolling and normalize editor keyboard inset
- Ensure the active session tab is scrolled into view immediately when
its layout finishes to prevent it from remaining hidden off-screen.
- Round, clamp, and validate WebView visualViewport bottom measurements
to avoid rendering inconsistencies from fractional or invalid insets.
- Trigger an immediate keyboard inset report on script initialization.
* Update tabStripOffsetRef when scrolling mobile tab strip
Ensure the cached offset is updated to match the next scroll position. Without this update, subsequent scroll calculations would use stale offset values.
Fix Android terminal text overflow and stale foldable viewport handling.
- Pin terminal WebView textZoom so Android system font scale cannot inflate xterm glyphs past measured cells.
- Refit mobile terminal viewport on window dimension changes for fold/unfold, rotation, and split-screen.
- Harden viewport refit fallback handling for stale async runs and updateViewport responses.
Fixes#4579
Adds a focused React Doctor oxlint gate for high-signal state/effect rules, disables the noisy js-combine-iterations React Doctor rule, and refactors the mobile new-worktree modal away from prop-change state reset effects.
Bounds the mobile terminal WebView pre-ready write backlog, avoids Array.shift() in the embedded xterm write drain, disposes old xterm observers, and clears successful fallback timers.
Removed duplicate 'openclaude' entry at index 3 of MOBILE_TUI_AGENT_AUTO_PICK_ORDER so mobile pickers no longer render two OpenClaude rows or emit duplicate-key warnings.
Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* Move mobile browser refs out of effects
* Use layout effect for mobile browser ref mirrors
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Move mobile tasks client ref sync out of effect
* Use layout effect for mobile tasks client ref
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Auto-generated workspace names walked the marine-creature list in order
and deduped only within the active repo (the default when workspaces are
nested), so the first auto-named worktree in every repo landed on
"Nautilus". That guaranteed identical branch names across repos, which
appear flat and indistinguishable in the sidebar.
The in-order walk also produced "Nautilus-2", "Nautilus-3", ... within a
single repo: the suggester ignores branches left behind by deleted
worktrees, so it kept re-proposing "Nautilus", and the create-time retry
loop suffixed it to dodge the lingering branch. Random selection now
yields a fresh creature each time instead of marching the same name.
- Dedup against worktrees in every repo, not just the active one
- Pick randomly from the unused pool instead of the first list entry
- Lowercase the result to match branch-name convention (fix/seahorse)
- Expand the corpus 260 -> 552 (more marine species plus public-domain
mythological sea creatures) so random picks rarely repeat
getSuggestedCreatureName drops the now-unused repoId/nestWorkspaces
params; the RNG is injectable for deterministic tests.
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Add agent enablement controls
Implements the Enable/Disable Agents Dashboard behavior described in docs/enable-disable-agents-dashboard.md, including persisted agent enablement state, filtered launch surfaces, and settings UI affordances.
* Clarify agent availability controls
* Respect disabled agents across workspace and AI defaults
- Filter disabled TUI agents from mobile and quick workspace selection
- Avoid implicitly choosing disabled agents for commit/PR AI settings
- Broadcast settings changes to open windows for disabled-agent updates
* rm design doc
* fix: complete agent enablement propagation