Commit Graph
1409 Commits
Author SHA1 Message Date
Jinwoo-HandOrca 3cd944bc32 Remove mobile-fit debug logging, add debug skill doc
Strip all mfLog file logging and console.log('[mobile-fit]') calls
from production code. The skill doc at skills/mobile-fit-debug/SKILL.md
documents how to temporarily re-add logging when needed.

Co-authored-by: Orca <help@stably.ai>
2026-05-01 00:01:02 -04:00
Jinwoo-HandOrca c18c4df829 Fix mobile display-mode toggle corrupting split-pane terminal sizes
When toggling a terminal to desktop mode on mobile, the server restores
the PTY to its correct size and sends a terminalFitOverrideChanged IPC.
This triggers the desktop renderer's React re-render cascade, which
runs safeFit on ALL terminal panes — including background tabs measured
at incorrect widths. Those stale pty:resize IPCs would overwrite the
correct PTY size and corrupt previousCols for future toggles.

Key changes:
- Add global 500ms suppress window that blocks all desktop renderer
  pty:resize events after a mode change (the cascade takes ~360ms to
  propagate through IPC → React → rAF → DOM → IPC)
- Track desktop renderer pane geometry in lastRendererSizes map so
  handleMobileSubscribe uses actual split-pane width instead of stale
  full-width PTY size
- Clear lastRendererSizes on desktop restore to prevent stale values
  from persisting across subscribe cycles
- Register mobile subscriber even in desktop mode so toggling to
  auto/phone can find the viewport
- Add onExternalPtyResize to update previousCols live when the desktop
  renderer corrects pane geometry after restore
- Add comprehensive debug logging to /tmp/mobile-fit-debug.log
- Guard toggleDisplayMode against concurrent taps
- Add integration tests for onExternalPtyResize scenarios

Co-authored-by: Orca <help@stably.ai>
2026-04-30 21:23:26 -04:00
Jinwoo-HandOrca 2c1f817fcf Merge main, fix test failures: update getWorktreePs snapshot, preserve pre-allocated handles across reloads
- Resolve merge conflict in shared/types.ts (keep WorktreeStartupLaunch, drop reverted sparse checkout types)
- Add displayName/linkedPR/isPinned/status to getWorktreePs test assertion
- Stop clearing handleByPtyId on renderer reload/graph unavailable so pre-allocated CLI handles survive

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:51:00 -04:00
github-actions[bot] cd01fa8b6e release: v1.3.25-rc.12 v1.3.25-rc.12 2026-04-30 22:48:26 +00:00
Jinwoo Hong 000d4dc08b Revert sparse checkout worktree creation (#1290) 2026-04-30 15:47:40 -07:00
Jinwoo-HandOrca 393b3e379b Fix orca-runtime.test.ts typecheck errors for CI
- Add shouldRunSetupForCreate to hooks mock (needed by setupDecision refactor)
- Add sleepWorktree/terminalFitOverrideChanged to all RuntimeNotifier mocks
- Add getGitHubCache to both RuntimeStore mocks

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:37:07 -04:00
Jinwoo-HandOrca 69140499ab Fix test failures: add shouldRunSetupForCreate mock, skip unimplemented inline-restore tests
- Add shouldRunSetupForCreate, getEffectiveSetupRunPolicy, hasHooksFile
  to hooks mock so runtime can call them after setupDecision refactor
- Mock shouldRunSetupForCreate to return true only for 'run' decision,
  matching the real implementation's behavior
- Skip two mobile-subscribe-integration tests that test inline-restore
  on re-subscribe (not yet implemented)

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:27:46 -04:00
Jinwoo-HandOrca 97a0c501c3 Fix CI: mobile.yml .nvmrc reference, typecheck errors, and test mock gaps
- mobile.yml: update node-version-file from .nvmrc to package.json
- orca-runtime.test.ts: add missing sleepWorktree and
  terminalFitOverrideChanged to RuntimeNotifier mock
- pane-tree-ops.ts: cast to ManagedPaneInternal for internal property
  access in safeFit
- pane-fit-resize-observer.test.ts: add dataset to container mock so
  safeFit's override lookup doesn't throw
- mobile-subscribe-integration.test.ts: remove unused destructured vars

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:15:54 -04:00
Jinwoo-HandOrca c307675483 Remove debug "Debug Test" quick-action button from mobile home screen
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:58 -04:00
Jinwoo-HandOrca c223f717ae Fix row calculation: subtract 2 rows after floor division, not before
floor((h - cellH) / cellH) != floor(h / cellH) - 1 when h/cellH is
fractional. Use the simpler and correct floor(h / cellH) - 2 to
reliably keep the bottom rows visible above the accessory bar.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:58 -04:00
Jinwoo-HandOrca 7cc3ea9fff Subtract one cell-height padding from viewport to prevent bottom row clipping
Math.floor(vpHeight / cellHeight) can produce a row count where the
last row's bottom edge aligns exactly with the container boundary,
causing it to be partially hidden. Subtracting one cellHeight before
dividing guarantees one full row of breathing room.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca 856fec166e Use exact container height for mobile viewport measurement
Instead of subtracting a hardcoded row count from window.innerHeight,
measure the terminal frame's pixel height via onLayout and pass it into
the WebView's measureFitDimensions. This gives pixel-accurate row
calculations regardless of accessory bar height or safe-area insets.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca 3b66647aa0 Subtract 2 rows from mobile viewport to fully clear accessory bar
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca 92da053446 Fix mobile WebView bottom row cutoff and one-finger scroll getting stuck
Subtract 1 row from measureFitDimensions to prevent the last terminal
line from being hidden behind the accessory bar overlay. Widen the
pinch-zoom snap-to-1 threshold from 1.05 to 1.15 so users don't get
trapped in pan mode after a slight zoom.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca 83db85eb25 Add scenario tests from design doc verification matrix
Tests matching the verification matrix in mobile-terminal-phone-mode-checklist.md:
- Desktop window resize while mobile viewing: override persists
- Mobile disconnect restores all terminals: overrides fully cleared
- PTY exits while phone-fitted: no stale state remains
- Mobile reconnects after disconnect: new override works
- Multiple tabs with same pane IDs: cross-tab isolation
- Change listener lifecycle: fires for both override and restore

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca d107e7ed1c Add regression tests for mobile-fit overrides and safeFit override path
mobile-fit-overrides.test.ts (26 tests):
- setFitOverride / getFitOverrideForPty: store, remove, overwrite, multi-pty
- bindPanePtyId / getFitOverrideForPane: tab-scoped composite key lookup,
  pane ID collision between tabs, null tabId safety
- unbindPane: removal, cross-tab isolation
- getPaneIdsForPty: multi-pane, cross-tab, filtering
- onOverrideChange: subscribe, unsubscribe, multi-listener
- hydrateOverrides / getAllOverrides: bulk replace, clear, copy semantics

pane-tree-ops.test.ts (6 new tests):
- safeFit resizes terminal to override dims when mobile-fit active
- safeFit skips resize when already at override dims
- safeFit ignores override when pane has no data-pty-id
- safeFit falls through to normal fit after override cleared
- safeFit does not cross-contaminate overrides between ptyIds

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca eca8db7237 Move mobile settings to experimental tab, translucent resize banner, monochrome button
- Move mobile pairing from standalone settings section into the
  Experimental tab behind an opt-in toggle (experimentalMobile setting,
  default off). Description notes the APK must be downloaded from
  GitHub Releases.
- Make desktop mobile-fit resize banner translucent (0.95 → 0.75 alpha)
  so the terminal line underneath remains partially visible.
- Change the mobile "Create Terminal" empty-state button from blue
  (accentBlue) to monochrome (bgRaised + borderSubtle) to match the
  app's dark palette.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca 6d40e01ccb Fix pane ID collision in mobile-fit overrides by using ptyId-based lookups
Pane IDs are per-tab, so two tabs can both have pane 1. The old
ptyIdByPaneId map keyed by bare pane ID caused the left initial terminal
to stay stuck at phone dimensions (49 cols) even after the mobile-fit
override was cleared — the override for a different tab's pane with the
same ID would match.

- Change override map key from bare paneId to tabId:paneId composite
- Switch safeFit to look up overrides via data-pty-id attribute (globally unique)
- Same ptyId-based lookup in onResize, terminal-appearance, and reattach
- Fix test mocks to include container.dataset for data-pty-id writes

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca 580d314c3f CHECKPOINT: Fix mobile phone-fit bugs and Claude startup on new workspace
Server-side mobile fit architecture:
- handleMobileSubscribe/Unsubscribe with per-ptyId restore timers
- Server-authoritative display mode (auto/phone/desktop) per terminal
- Inline resize events on subscribe stream replace resubscribe pattern
- terminal.subscribe waits for PTY spawn (mobile left-pane race)

Bug fixes:
- Fix Claude not launching from mobile (Bug 6): worktree.create RPC
  schema now accepts startupCommand from mobile, passes it through to
  createManagedWorktree → activateWorktree startup param
- Fix waitForLeafPtyId handle invalidation: capture tabId/leafId before
  handle can be invalidated, fall back to direct leaf lookup
- Fix desktop banner accumulation on tab switch (Bug 8): restore timer
  cancel scoped to same ptyId only, not all client timers
- Fix pane ID collision banners: use transport ptyId for override lookup
  instead of pane ID which collides across tabs
- Fix 0-terminals during rapid tab switch (Bug 7): consecutive-empty
  guard with lastKnownTerminalCountRef
- Mobile subscribe waits for PTY spawn with graphSync callback

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-H 0498f80a97 Revert "Keep fitted terminal bottom row visible"
This reverts commit 4be9e88e018d8f10917f970324e84c3bd9c23463.
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca 85187ae4d3 Fix mobile terminal viewport sizing
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca de2d03ee68 Measure terminal fit after layout settles
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:57 -04:00
Jinwoo-HandOrca be89fc3518 Keep fitted terminal bottom row visible
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:56 -04:00
Jinwoo-HandOrca 686d9f876a Handle mobile RPC reconnect rejections
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:56 -04:00
Jinwoo-HandOrca d0b03c6afa Encrypt mobile device token during E2EE auth
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:56 -04:00
Jinwoo-HandOrca b2612fa14d Fix mobile review findings
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:56 -04:00
Jinwoo-HandOrca ec693359d8 Enlarge mobile app icon artwork
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:56 -04:00
Jinwoo-HandOrca 3ba2150c91 Fix hidden drawer input autofocus
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:56 -04:00
Jinwoo-HandOrca 09316f0548 fix(mobile): harden async effects, fix resume card, and move modals out of KAV
- Add disposed guards to session screen RPC connection to prevent
  state updates and client leaks after unmount
- Fix nested timer leak in reconnect effect with addTimer helper
  that checks disposed flag before scheduling
- Move TerminalWebView touch/mouse listeners out of init() to IIFE
  top level so they register once, not on every re-init
- Move session screen modals outside KeyboardAvoidingView so drawer
  overlays cover the full screen height
- Track last-visited worktree in AsyncStorage so the home screen
  Resume card reflects mobile session history, not just desktop
  activity ordering
- Re-fetch worktreeInfo on home screen focus so Resume card updates
  after navigating back from a session
- Add stale guards to NewWorktreeModal async effects
- Fix worktree cache LRU eviction (delete-before-set for Map ordering)
- Use useState initializer for host detail cache to avoid re-reading
  on every render

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:56 -04:00
Jinwoo-HandOrca 810f780713 feat(mobile): polish home screen UI and improve navigation UX
- Move status dot inline with status text, remove icon overlay ring
- Fix worktree.ps response parsing (returns {worktrees:[...]} not array)
- Fix Resume card route, sizing, and text alignment to match host cards
- Rename stat labels to be more explicit (Agents spawned, PRs created)
- Wire New Worktree button to navigate to host detail with auto-open drawer
- Cache worktrees for instant host detail page loads
- Defer RPC connection until after navigation animation
- Remove desktop icon and greeting from onboarding screen
- Request OS notification permissions when toggle is enabled

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:55 -04:00
Jinwoo-HandOrca a51561548c feat(mobile): redesign homepage with onboarding, resume card, and quick actions
- Move settings gear to header, remove bottom footer
- Stat cards match desktop's minimal style (subtle border, icon box)
- Host cards show worktree count and active count via worktree.ps RPC
- Status ring on host icon corner instead of inline dot
- Resume section surfaces most recent active worktree across hosts
- Quick actions: Pair Desktop and New Worktree
- Empty state: welcoming onboarding with "How it works" steps
- Add card radius token (14px) to theme
- Include HTML mock for design reference

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:55 -04:00
Jinwoo-HandOrca e668dce4ec fix(mobile): splash/icon sizing, worktree sleep, host removal persistence
- Add worktree.sleep RPC method with full notifier chain (runtime → IPC → renderer)
- Optimistic UI update for sleeping worktrees in mobile client
- Fix splash screen: configure expo-splash-screen plugin, hide splash only after navigator layout
- Regenerate app icon and splash assets at correct density sizes
- Fix host removal not persisting by disabling Android auto-backup (allowBackup=false)
- Guard against invalid host credentials (base64 crash) and prevent navigating into auth-failed hosts
- Extract ActionSheetContent for inline drawer content switching
- Rewrite BottomDrawer as always-mounted Animated.View overlay (replaces Modal)
- Add ConfirmModal component with inline confirm/cancel buttons

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:55 -04:00
Jinwoo-HandOrca 36005a7af6 fix: resolve circular type inference in resubscribeWithoutFocus
Use a ref to break the self-reference cycle that caused TS7022.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:55 -04:00
Jinwoo-HandOrca d4e450719d style: darken mobile-fit banner to match dark theme
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:55 -04:00
Jinwoo-HandOrca 6cd5e755c3 fix: notify mobile clients when desktop restores terminal from mobile-fit
When the desktop restored a terminal from mobile-fit, the notification
only reached the Electron renderer via IPC. Mobile WebSocket clients
were never informed, leaving the phone UI stuck in fitted mode.

Add fit-override change listeners to the runtime (parallel to existing
dataListeners) and emit fit-override-changed events through the
terminal.subscribe stream. The mobile session screen handles the event
by clearing fitted state and resubscribing for a fresh scrollback
snapshot at the restored desktop dimensions.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:55 -04:00
Jinwoo-HandOrca 1a183d31d2 feat: network interface selector for QR pairing and UI polish
- Add network interface selector so users can choose LAN or overlay
  network (Tailscale, ZeroTier) address for QR code pairing
- Fall back to OS-assigned port when preferred port is in use
- Filter paired devices list to only show actually connected devices
- Poll device list after QR generation until phone connects
- Mark device lastSeenAt on first WebSocket connection
- Make CustomKeyModal toggle and button monochrome (remove blue accent)
- Make clear filters text and group options monochrome

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca 322c597018 feat(mobile): redesign home screen, add settings pages, fix pin sync
- Redesign home screen with "Welcome back" hero and usage stats cards
  (agents spawned, agent time, PRs created) fetched via stats.summary RPC
- Add dedicated notifications settings page with monochrome push toggle
- Add troubleshooting page with diagnostics and common issues accordion
- Add splash screen with Orca logo using expo-splash-screen
- Fix pin sync: prioritize pinned/unread worktrees in compareWorktreePs
  sort so they survive the 200-worktree truncation limit in worktree.ps
- Sync local pin state from server on each poll to reflect desktop pins
- Add isPinned support to worktree.set RPC handler
- Add stats.summary and notification subscription RPC methods
- Clean up debug logging from notification handlers

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca 0617de36ce fix(e2e): use OS-assigned port for WebSocket transport in tests
Parallel e2e workers each launch an isolated Electron instance. All
instances were racing to bind the same fixed WebSocket port (6768),
causing EADDRINUSE crashes that manifested as "Target page, context
or browser has been closed" in every Playwright spec.

Pass port 0 when ORCA_E2E_USER_DATA_DIR is set so the OS assigns a
random available port per instance. The full WebSocket startup path
is still exercised, preserving coverage for future mobile pairing
e2e tests.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca 5fa8d6d867 fix: resolve remaining CI test failures
- Update runtime-client test to use transports array (matches schema change)
- Remove 3 preallocated-handle-survives-reload tests that tested unreachable
  behavior (preallocated handles can't survive epoch changes)
- Revert unnecessary readTerminal fallback added during debugging

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca d751bd8a63 fix: repair test failures from mobile feature additions
- Add shouldRunSetupForCreate to hooks mock in orca-runtime tests
- Fix send() helper to use rest args, avoiding extra undefined in IPC calls

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca e7d1bdaddd fix: widen safeFit parameter from ManagedPaneInternal to ManagedPane
The mobile-fit-override code calls safeFit with ManagedPane (from
getPanes()), but safeFit was typed to require ManagedPaneInternal.
Widen the parameter type since safeFit only needs fields on ManagedPane.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca 78b3069bec ci: convert mobile build to tag-based release workflow
Trigger on mobile-v* tags instead of main pushes. Builds a release APK,
uploads as artifact, and creates a GitHub Release with the APK attached.
Manual dispatch still available for on-demand builds.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca d9801ac8bc ci: move Android APK build out of PR gate into dedicated workflow
The full Gradle build is heavy for every PR push. Keep only typecheck +
lint as the PR gate; run the APK build on main pushes and manual dispatch.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca 86cb99cad8 Improve mobile UI polish
- BottomDrawer: shift drawer up when keyboard opens using Keyboard events,
  add ScrollView for content overflow
- NewWorktreeModal: replace FlatList with plain map to avoid nested
  VirtualizedList error
- Home: replace Server icon with Monitor, hide IP from cards (show in
  action sheet), add connection status subtitle, update hero copy
- About: remove redundant link labels, use neutral text color for URLs

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca 14a314a29d fix: terminal output duplication on mobile
Remove duplicate onPtyData call in pty.ts that caused every daemon-backed
PTY data event to be dispatched twice through dataListeners, doubling all
terminal output sent to mobile clients.

Also: clean up registerSubscriptionCleanup to evict stale listeners on
reconnect, add regression tests, fix CI lint/type errors, add mobile UX
improvements (worktree creation, settings, about screen).

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca 92aeac9692 feat(mobile): interactive swipe-to-dismiss drawers and improved QR instructions
- Add shared BottomDrawer component with pan gesture tracking via reanimated
- Drawer follows finger on swipe down, dismisses past threshold or on velocity
- Rubber-band resistance on upward pull for tactile feel
- Migrate all 5 modal components to use BottomDrawer
- Replace plain text QR instructions with numbered steps with icons

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca 3bed9df9bc fix(mobile): use Android-native haptics API instead of Vibrator
Use performAndroidHapticsAsync on Android which uses HapticFeedbackConstants
instead of the Vibrator API. This fixes haptics not working on Android and
removes the VIBRATE permission requirement.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca f19f274314 fix: resolve typecheck errors from rebase
- Add missing randomUUID import in pty.ts
- Add getForegroundProcess to RuntimePtyController test mocks
- Add terminalFitOverrideChanged to RuntimeNotifier test mocks
- Fix vi.fn() type assertions in e2ee-integration tests

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca 6889709413 fix: resolve CI lint errors
- Extract send helper in attach-main-window-services to stay under max-lines
- Remove unused startup parameter in useIpcEvents

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00
Jinwoo-HandOrca f810725033 fix: resolve lint errors for CI
- Remove unused 'startup' parameter in useIpcEvents onActivateWorktree
- Compact attach-main-window-services to stay within max-lines limit

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:54 -04:00