Commit Graph
950 Commits
Author SHA1 Message Date
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 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 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 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 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
Jinwoo-HandOrca 11f45095cd fix zsh startup command double echo
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:53 -04:00
Jinwoo-HandOrca 2c6f710b56 checkpoint mobile terminal streaming work
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:53 -04:00
Jinwoo-HandOrca fc75b28f7d Add end-to-end encryption for mobile WebSocket transport
Replace the disabled TLS cert pinning approach with application-layer
E2EE using tweetnacl (Curve25519 ECDH + XSalsa20-Poly1305). The
WebSocket stays plain ws:// but all RPC traffic is encrypted after
a one-round-trip handshake.

Desktop: generate persistent Curve25519 keypair, E2EE channel module
handles handshake state machine and transparent encrypt/decrypt.
Mobile: ephemeral keypair per connection for forward secrecy, expo-crypto
PRNG polyfill for Hermes compatibility.

Pairing schema updated from v1 (certFingerprint) to v2 (publicKeyB64).
Mock server updated with E2EE support. 24 tests covering crypto,
channel handshake, and integration.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:24 -04:00
Jinwoo-HandOrca 466b2659a8 Implement mobile terminal fit-to-phone with robust restore
Add end-to-end mobile-fit override system that lets a phone client resize
a PTY to phone dimensions and restore to desktop dimensions on disconnect
or user request.

Key changes:
- Runtime: resizeForClient() manages override lifecycle with ownership,
  clamping, and auto-restore on client disconnect. Always resizes PTY
  directly on restore instead of relying on fragile renderer chain.
- RPC: terminal.resizeForClient method for mobile clients via WebSocket.
- Renderer: safeFit() respects active overrides, desktop banner with
  Restore button, override change listener with rAF + fallback safety net.
- Mobile: fit-to-phone with CSS scale zoom, auto-fit only for terminals
  created during the mobile session (not existing desktop terminals).
- Tests: 14 unit tests + 3 integration tests for override lifecycle.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:24 -04:00
Jinwoo-HandOrca c1e8623e5f Improve mobile worktree and terminal UX
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:23 -04:00
Jinwoo-HandOrca 4fe89e656a fix mobile terminal geometry sync
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:23 -04:00
Jinwoo-HandOrca 1c8f23f1e5 add mobile pairing desktop support
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:23 -04:00
Jinwoo-HandOrca 5f8c9ef312 fix mobile terminal streaming
Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:23 -04:00
Jinwoo-HandOrca 5af331c93c feat(mobile): use plain ws:// transport until mobile cert pinning is implemented
React Native's built-in WebSocket rejects self-signed TLS certs with no
way to pin by fingerprint. Use plain ws:// for now — per-device token
auth still prevents unauthorized access. TLS will be re-enabled once the
Expo native module for certificate pinning is built (Phase 1 checklist).

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:23 -04:00
Jinwoo-HandOrca 9c8be97668 fix(mobile): replace hand-rolled ASN.1 cert with OpenSSL, enable WebSocket transport
The hand-rolled X.509 certificate generation produced malformed certs
that OpenSSL and Node's HTTPS server couldn't parse, silently preventing
the WebSocket transport from starting. Replace with openssl CLI call
which is available on all target platforms.

Also enable WebSocket transport by default so mobile clients can connect.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:23 -04:00
Jinwoo-HandOrca 7740bf7ef8 feat(mobile): add streaming RPC tests and GitHub Actions CI workflow
- 7 unit tests for RpcDispatcher streaming: scrollback emit, live data
  chunks, unsubscribe cleanup, one-shot fallback, error handling
- GitHub Actions workflow for mobile: typecheck + lint on PR, Android
  debug build with JDK 17 (temurin)

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:22 -04:00
Jinwoo-HandOrca 95324c686e feat(mobile): add Expo mobile app with QR pairing and WebSocket RPC transport
Adds the Orca Mobile companion app (Expo SDK 55 / React Native 0.83) with:
- QR code pairing flow: scan orca://pair# URL, validate auth, save host profile
- WebSocket RPC client with auto-reconnect, exponential backoff, streaming support
- Three screens: host list, worktree list, terminal session with live output
- Mock WebSocket server for development without a running Orca desktop instance
- Desktop-side: TLS certificate management, device registry, mobile IPC handlers,
  WebSocket transport layer, and pairing offer encode/decode with Zod validation
- Unit tests for WebSocket transport and pairing codec

Co-authored-by: Orca <help@stably.ai>
2026-04-30 18:03:22 -04:00
Brennan BensonandOrca df31f40f1e fix(window): meaningful visible area + atomic bounds/maximized persist (#1288)
Co-authored-by: Orca <help@stably.ai>
2026-04-30 13:54:32 -07:00
Brennan BensonandOrca 8b56b16b9a fix(window): discard off-screen saved bounds and refuse to persist min-size bounds (#1287)
Co-authored-by: Orca <help@stably.ai>
2026-04-30 13:38:54 -07:00
Brennan BensonandOrca 0f3aaab9f8 feat: default sidebar sort to 'recent' instead of alphabetical (#1285)
Co-authored-by: Orca <help@stably.ai>
2026-04-30 11:07:54 -07:00
8e5114a7bf feat: implement hierarchical tree view for PR diff file list fixes #1109 (#1278)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
2026-04-30 01:28:52 -07:00
Jinwoo HongandOrca cb73b372ff feat(file-explorer): support drag-and-drop file import over SSH (#1279)
Co-authored-by: Orca <help@stably.ai>
2026-04-30 01:28:43 -07:00
79faafcc98 Add sparse checkout worktree creation (#1131)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
2026-04-30 00:43:00 -07:00
NeilandOrca 8c83c8c971 chore: move dev-app-update.yml into config/ (#1276)
Co-authored-by: Orca <help@stably.ai>
2026-04-30 00:11:14 -07:00
NeilandOrca 4318f3bfa7 chore: reduce root-directory clutter (#1275)
Co-authored-by: Orca <help@stably.ai>
2026-04-30 00:09:46 -07:00
JinjingandOrca 61909fff03 fix(tab-bar): dismiss tab context menu on window blur for webview clicks (#1274)
Electron <webview> elements run in a separate process, so clicks inside
them don't dispatch pointerdown on the renderer document. Radix
DropdownMenu relies on document pointerdown for outside-click detection
and therefore misses webview clicks, leaving the menu stuck open.
Listening for window blur catches the moment focus leaves the renderer
(including into a webview) and closes the menu.

Co-authored-by: Orca <help@stably.ai>
2026-04-30 00:02:46 -07:00
NeilandOrca fb3d46710b fix(mac-perms): fall through to Privacy pane when in-app prompt is a no-op (#1273)
Co-authored-by: Orca <help@stably.ai>
2026-04-29 23:50:41 -07:00
Jinwoo HongandOrca 066c245d14 fix(terminal): force WebGL repaint after split when dimensions match (#1272)
Co-authored-by: Orca <help@stably.ai>
2026-04-29 23:33:36 -07:00
NeilandOrca a02987e604 feat(settings): replace task-icon toggle with Tasks-button toggle, expose in View menu (#1271)
Co-authored-by: Orca <help@stably.ai>
2026-04-29 21:13:13 -07:00
Neil 020780c4dd feat(hooks): restore always-trust repo option
Restores repo-level always-trust for orca.yaml hooks and surfaces CLI warnings when --run-hooks is omitted and a hook is skipped.
2026-04-29 20:47:04 -07:00
JinjingandOrca db956ed6db fix(window): prevent teardown resize events from clobbering saved window bounds (#1269)
On close/quit (especially auto-updater relaunch via quitAndInstall),
Electron/OS emit resize/move/unmaximize while the window is torn down.
The debounced persistence was capturing those near-minimum bounds, so
the next launch came up at minWidth x minHeight.

- Freeze bounds persistence on window 'close' and app 'before-quit'
  (updater strips the window 'close' listener before quitting, so
  the app-level latch is needed as a second line of defense).
- Release the freeze on will-prevent-unload so aborted Cmd+Q keeps
  saving bounds.
- On restore, discard saved bounds at/below the min dimensions to
  recover users who already persisted corrupt bounds.

Co-authored-by: Orca <help@stably.ai>
2026-04-29 20:37:19 -07:00
JinjingandOrca 6f9c97ef99 fix(browser-pane): keep focus in Orca window when destroying focused webview (#1270)
Before removing a <webview> that currently owns focus, blur the active
element and refocus the window. Without this, macOS hands activation to
the previously-active app (e.g. Slack) because the focused webContents
is gone with no replacement, pulling the user out of Orca on worktree
delete.

Co-authored-by: Orca <help@stably.ai>
2026-04-29 20:30:28 -07:00
Jinwoo HongandOrca 7993fb5aaa feat(status-bar): show inline usage for inactive accounts in switcher (#1259)
Co-authored-by: Orca <help@stably.ai>
2026-04-29 19:29:11 -07:00
Brennan BensonandOrca b5d8eb6d31 fix(sidebar): restore green dot for 'active' worktree status (#1266)
Co-authored-by: Orca <help@stably.ai>
2026-04-29 19:03:52 -07:00
Brennan BensonandOrca c1620496cf feat(agent-cockpit): replace bottom-panel dashboard with inline per-card agents list (#1251)
Co-authored-by: Orca <help@stably.ai>
2026-04-29 18:51:24 -07:00
mcd77 89f41bfda2 feat(hooks): gate orca.yaml execution on trust
Audited and rebased PR 1138. Squashed to remove the original untrusted commit stack; hook execution now requires explicit UI trust or CLI --run-hooks opt-in.
2026-04-29 18:29:53 -07:00
Jinwoo HongandOrca 2329f56180 Exit beta: SSH badge removal + always-on daemon PTY (#1253)
Co-authored-by: Orca <help@stably.ai>
2026-04-29 17:48:24 -07:00
NeilandOrca b5b5e1b727 refactor(settings): move provider accounts into dedicated Agent Accounts pane (#1264)
* refactor(settings): move provider accounts into dedicated Agent Accounts pane

Extracts the Claude, Codex, Gemini, and OpenCode Go account/provider sections
out of General and into a new "Agent Accounts" sidebar section so related
controls live together and General stays focused on workspace/editor/updates.

Co-authored-by: Orca <help@stably.ai>

* feat(settings): show provider logos on Agent Accounts headings

Adds the Claude, Codex, Gemini, and OpenCode Go brand icons to each provider
section heading so the Agent Accounts pane reads as a provider list at a
glance instead of a wall of text.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-04-29 17:31:11 -07:00
Brennan BensonandOrca e3f689c382 feat(agent-cockpit): bold-until-viewed weight on dashboard rows (#1262)
Co-authored-by: Orca <help@stably.ai>
2026-04-29 17:23:07 -07:00
NeilandOrca 9fe66f531b perf(new-workspace): cache + dedupe Create-from work-item fetches (#1263)
* perf(new-workspace): cache + dedupe Create-from work-item fetches

The Create-from tab was slow because it bypassed the renderer's existing
60s work-items cache: every sub-tab switch or modal re-open fired a fresh
`gh pr list --search is:pr is:open` / `gh issue list --search is:issue is:open`,
which also forces the main-side slow path (`listQueriedWorkItems`, uncached)
instead of the fast `listRecentWorkItems` path that wraps `gh api --cache 120s`.

- Route the PR + issue effects through the store's `fetchWorkItems` so
  repeat opens / sub-tab toggles hit the 60s renderer cache + inflight
  dedupe, and show cached data instantly while revalidating.
- Drop the `is:pr is:open` / `is:issue is:open` qualifiers when no query
  is typed so the backend takes the fast cached recent-items path. Both
  effects now share the same cache key on empty query, so PR ↔ Issue
  switching issues a single underlying gh call.
- Add a small module-scoped 60s branches cache so `searchBaseRefs` isn't
  reshelled out every time the Branches sub-tab becomes visible.

Measured on a cold orca repo: first render dropped from ~1,230 ms
(`is:pr` + `is:issue` sequential) to ~45 ms for the unqualified list,
with subsequent opens and sub-tab swaps serving from cache in <5 ms.

Co-authored-by: Orca <help@stably.ai>

* perf(new-workspace): finish create-from launch sooner

---------

Co-authored-by: Orca <help@stably.ai>
2026-04-29 17:14:37 -07:00
Brennan BensonandOrca 10a0566b13 refactor(shortcuts): remove dead Cmd+Shift+D dashboard shortcut (#1260)
Co-authored-by: Orca <help@stably.ai>
2026-04-29 16:59:09 -07:00