Commit Graph
7880 Commits
Author SHA1 Message Date
Brennan Benson fb3e18fcdc fix(mobile): keep the live tab's session-option record from eviction
`getScopedRecord` returned an existing record without re-inserting it, so the
per-tab record map evicted by insertion order rather than recency. A long-lived
active tab is the oldest key, so crossing the 32-scope cap silently dropped its
tracked model and reset the pill to "Model". Desktop's scope cache does
delete-then-set for exactly this reason.

Also moves the shared session-option tests to src/shared so the root suite runs
them (they only exercised src/shared logic the Electron renderer consumes, but
sat under mobile/ where only mobile's vitest project sees them), and restores
two "why" comments dropped while extracting the shared modules.
2026-08-04 01:56:05 -07:00
Brennan Benson 3eafcb4500 refactor: share native chat session option logic 2026-08-03 20:10:33 -07:00
Brennan Benson c208bc883c fix(mobile): synchronize native chat refs after commit 2026-08-03 17:59:52 -07:00
Brennan Benson 13f6d086c6 fix(mobile): keep session option sends scoped 2026-08-03 17:41:55 -07:00
Brennan Benson c9b57c3e4b feat(mobile): native-chat model/session-option picker + shared slash catalog (STA-3332)
Piece A — shared slash catalog + send classification:
- Mobile composer now serves getVerifiedNativeChatCommands from the shared
  catalog (agent-aware, with description rows) instead of a hardcoded
  provider-agnostic list that advertised commands Claude does not have.
- classifyNativeChatSend moves to src/shared/native-chat-slash-commands.ts
  (renderer re-exports keep desktop import paths stable); mobile's send seam
  now gates optimistic echoes on it, so slash sends no longer create a
  'Queued' bubble that no transcript echo can ever retire, and the
  ack-lost hold only arms for chat sends.

Piece B — mobile model/session-option pickers:
- New per-tab session-option tracking (state/commands/labels modules) ported
  from the desktop live flow, reading the shared agent-session-option
  catalog for Claude AND Codex.
- Composer pill row (model + options) opening an inline choice card in the
  proven Ask-card pattern; applies use catalog modelApply semantics
  (/model <value> via the existing send path), Codex-style agent-picker
  entries dispatch the picker command and flip the tab to the terminal view.
- Current model seeds from the hook-reported provider model when derivable;
  typed /model-style commands update tracked state (recordOutgoingCommand
  parity); dispatched values render as sent-not-confirmed.
2026-08-03 16:45:51 -07:00
JinjingandOrca d7fe9d6bcc fix(ai-vault): support session scanning in SSH worktrees (#11004)
* fix(ai-vault): support session scanning in SSH worktrees

Add relay-native aiVault.listSessions scanning that discovers agent
sessions on SSH hosts. Includes fallback to filesystem crawl for
legacy relays, full cancellation support, result validation, and
scan coalescing to reduce redundant work.

* fix(ai-vault): scan sessions in SSH worktrees with coordinated cancellat

- Extract batching logic to `mapRemoteScanBatches` for reuse and proper cancellation checkpoints
- Move `AiVaultScanCoordinator` from relay to main to handle concurrent same-key requests with individual cancellation signals
- Report scope path truncation consistently across relay and SSH fallback paths
- Gracefully degrade relay handler on unsupported platforms instead of aborting startup
- Refactor issue display to separate blocking errors, scope notices, and skipped transcript counts

* fix(ai-vault): stabilize SSH session scan CI

Swallow async WSL relay stdin EPIPE so the live hook-relay shard no longer
fails after all tests pass. Merge main, resolve scan/relay conflicts, and
align cancellation/host-issue reporting with IPC expectations.

* fix(ai-vault): harden session scan cancellation, relay timeouts, and preemption

Thread the abort signal through every scan and parse path so superseded or
cancelled scans stop promptly instead of parsing every remaining transcript
for a caller that already left.  Replace the fragile message-text relay
timeout check with a typed error code so unrelated errors carrying the
phrase "timed out after" no longer suppress the filesystem fallback.  Fix
scan coordinator preemption so a forced Refresh in one window no longer
re-enters as a spurious cancellation in another.  Add a host-leg cache for
the all-hosts view and cap filesystem concurrency so a single slow remote
home cannot stall the whole merge.

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

* fix(ai-vault): use stable React keys for scan issue banners

Drop array-index keys so react-doctor/no-array-index-as-key passes.
Uniqueness comes from host, kind, agent, path, and message.

* fix(ai-vault): SSH session scanning with configurable depth limits

Implement depth-aware caching and proper scan boundaries to make SSH session
scanning reliable in worktrees. Users can now select between faster (250
sessions) and comprehensive (unlimited) history scans. The scanner:
- Deduplicates scans across relay, host leg, runtime, and renderer layers
- Reuses larger scans to serve smaller depth requests
- Properly bounds in-scope discovery per-limit
- Fixes timeout enforcement when SSH providers ignore abort signals

* Move sessionLimit ref update to useLayoutEffect

Keep render pure for React Doctor by deferring ref updates to
a layout effect, which still executes before render-dependent
effects that consume the ref.

* fix(adhoc): stamp version prefix from main, not the feature branch

Adhoc builds check out arbitrary refs whose package.json often lags
version bumps (e.g. 1.4.165-rc.0 while main is 1.4.168-rc.1). Hourly
always builds main so it already tracks the product line; adhoc now
resolves the base version from origin/main (or ORCA_ADHOC_BASE_VERSION)
so branch builds share that prefix.

* Revert "fix(adhoc): stamp version prefix from main, not the feature branch"

This reverts commit a26a18eb3fd83f7e7d2db9a6a7c3e02e0f79089a.

* fix(ai-vault): fix scoped backfill and coordinator race conditions

Resolve race where the last waiter leaving could abort an already-settled scan (add `settled` flag). Redesign scoped session backfill to keep searching through newer files until the scope reaches its requested session quota instead of stopping at the candidate limit; out-of-scope files no longer consume the scope budget. Centralize scan limit normalization and fix error classification for cancelled scans using the proper helper instead of checking Error.name. Disambiguate cache keys using JSON and add cancellation check after scope discovery phase.

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-03 16:17:00 -07:00
Brennan Benson a7282fed40 Fix Codex launch draft delivery after delayed setup (#12347)
* fix: preserve Codex launch drafts through setup

* test: enforce single startup draft delivery

* test: name startup draft release behavior
2026-08-03 16:06:29 -07:00
Jinjing 5941c6c9db Improve send comments to ai (#12150)
* Post fixing replies after launching PR comment resolution agents

Orca now automatically replies to selected comments after launching an
agent to resolve them. Review-thread comments get nested replies; review
summaries and issue comments get top-level @-replies. Payloads are
snapshotted at queue time and posted only after prompt delivery
succeeds. Bounded concurrency (4) prevents SSH slowdown.

* Batch conversation replies instead of posting per-comment

Combine N unresolvable comments into a single PR conversation reply to avoid timeline spam. Review threads still get one nested reply each. Refactor helper functions to pr-comment-fixing-reply-body.ts and change replyAsConversation(comment, body) → replyAsConversation(body).

* Handle bot account mentions in PR conversation replies

Use buildPRCommentConversationReplyBody to properly handle GitHub App
bot accounts, which don't resolve as @-mentions. Enforce delivery semantics
with type-safe PendingPRCommentAiAck payloads and improve error handling
around agent launch to prevent stranded state.

* Fix React Doctor ref-mutated-during-render errors in ChecksPanel

Move comment-resolution payload ref clears and latest-callback mirrors
into effects so render stays pure for the static analysis gate.
2026-08-03 15:58:20 -07:00
Jinjing ea68d97c28 Optimize worktree parent picker: conditional mount, virtualization, lazy status loading (#12225)
* Optimize worktree parent picker: conditional mount, virtualization, lazy

- Mount WorktreeParentPickerPopover only when open to avoid hundreds of
  unmounted instances subscribing to lineage and worktree store updates.
- Virtualize the candidate list and resolve activity statuses only for
  visible rows, eliminating redundant status subscriptions.
- Extract filtering, placement calculations, and row rendering into
  separate modules for testability and clarity.

* Memoize worktree parent picker search handler

Wrap search state update in useCallback to stabilize the handler
across re-renders. Reduces unnecessary effect runs and enables better
memoization of child components.

* Optimize worktree parent picker: defer unmount, memoize IDs

- Defer unmount until exit animation completes (200ms) to prevent premature teardown
- Memoize visibleWorktreeIds to prevent status hook from rebuilding its selector on every render
2026-08-03 15:57:05 -07:00
OrcaWinandOrcaWin 25213ec04d test(terminal): harden daemon upgrade adoption (#12353)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-03 15:03:37 -07:00
Jinjing 031115b0a5 test(ssh): freeze FrameDecoder clock in framing unit tests (#12356)
Default 4ms maxTurnMs can defer later frames via setImmediate under
CI load, so multi-frame assertions after a single feed were flaky.
2026-08-03 15:01:26 -07:00
Brennan Benson 7de40ffbd8 fix(terminal): stop keyboard effect re-registering on every pane render (STA-3291) (#12348)
createExpandCollapseActions minted five fresh closures per TerminalPane
render; four are deps of useTerminalKeyboardShortcuts, so its seven
window listeners tore down and re-registered on every render and all
effect-owned IME chord/modifier state silently reset. Memoize the
actions via useExpandCollapseActions and pin registration stability
with a render-churn regression test.

Fixes #12269
2026-08-03 14:41:22 -07:00
github-actions[bot] 17df980b7d release: v1.4.168-rc.1 v1.4.168-rc.1 2026-08-03 21:22:26 +00:00
OrcaWinandOrcaWin e5174a452b fix(terminal): reattach panes across daemon protocol upgrade (#12351)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-03 14:19:44 -07:00
Jinwoo HongandOrcaWin a4944f5343 fix(orchestration): retain update settlement authority (#12336)
* fix(orchestration): retain update settlement authority

* test(orchestration): register update settlement gate

* fix(orchestration): close update settlement audit gaps

* test(orchestration): correct update settlement evidence

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-03 14:00:27 -07:00
Jinwoo HongandOrcaWin d3c34c7067 fix(mobile): redial when the app resumes mid-dial (#12344)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-03 13:53:59 -07:00
github-actions[bot] b04bd82394 release: v1.4.168-rc.0 2026-08-03 20:50:51 +00:00
OrcaWinandOrcaWin e25381cdd3 fix(relay): tolerate cell clock skew in pairing invite expiry validation (#12340)
The cell stamps invite expiry at exactly now+10min from its own clock while
the desktop rejected anything past now+10min from the local clock with zero
tolerance, so any cell clock ahead of the machine by more than network
transit made every Relay pairing code fail with an opaque toast. Same
defect class as the host-proof freshness incident; same 30s leeway.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-03 13:15:30 -07:00
Brennan Benson 056c2d9496 fix(runtime): bind mobile WS listener to loopback until pairing (STA-2370) (#11956)
The runtime RPC WebSocket listener bound to 0.0.0.0:6769 at startup, so a
desktop with no paired device was reachable from the whole LAN before the
user opted in. Default the bind to 127.0.0.1 and widen to all interfaces
only on an explicit opt-in:

- createMobilePairingOffer / getRuntimePairingUrl widen (ensureNetworkExposure)
  before advertising a LAN endpoint; the rebind reuses the resolved port so an
  already-issued offer stays valid, and concurrent offers share one rebind.
- orca serve and E2E set exposeNetworkByDefault to bind wide at startup.
- A previously-connected device (lastSeenAt > 0) rebinds wide at startup so
  reconnect after restart keeps working; a pending/never-connected offer does
  not persist exposure across a restart.

The advertised pairing endpoint still resolves to a concrete interface address,
never the 0.0.0.0 bind host.
2026-08-03 13:06:11 -07:00
OrcaWin 2c6a9d1446 fix(browser): recover embedded guests after lifecycle loss (#11717) 2026-08-03 13:02:56 -07:00
814b87c421 fix(sidebar): route project adds to the intended host, not the global runtime (#9541)
* fix(sidebar): route local folder adds to the intended host, not the global runtime

Adding a local folder while connected to a remote runtime failed with
"<path> was checked on <host>, but that host did not report a usable folder"
because addRepoPath decides local-vs-remote purely from the global
settings.activeRuntimeEnvironmentId when no explicit host is passed.

Two local-add flows relied on that global fallback and got misrouted:

- useAddRepoLocalFolderFlow (native picker / drag-drop): the Add Project
  host selector can display "Local" (selectedRuntimeEnvironmentId = null, so
  the guard passes) while the global still points at an unavailable runtime.
  Native-picked/dropped paths are always local, so force local routing.

- AddProjectFromFolderDialog ("Add folder as project" on a subfolder): a
  subfolder lives on the active repo's host, so carry that host through the
  modal data and route by it — local for local projects, the owning runtime
  for runtime projects — instead of the globally-active runtime.

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

* fix(sidebar): route runtime server-path adds by selected runtime, not global

The Add Project "server path" step (reached only when a runtime host is
selected) called addRepoPath(path, kind) with no explicit host, so it
inherited the global settings.activeRuntimeEnvironmentId. When that global
diverged from the dialog's selected runtime, the add was misrouted off the
host the user picked — the same root cause as #9541, opposite direction.

Route the server-path add by the dialog's selected runtime explicitly.
Co-locate selectedRuntimeEnvironmentId in useAddRepoHostSelection next to
selectedSshTargetId so the dialog reads it from one place.

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

* fix(sidebar): route the pre-add git server-path scan by the selected runtime

For kind === 'git', scanNestedRepos runs before addRepoPath and can
early-exit the flow into the nested-repo review, but it still routed by the
global active runtime — so it could scan the wrong host even after the add
itself was correctly routed to the selected runtime (CodeRabbit).

- scanNestedRepos accepts an optional runtimeEnvironmentId in its controls;
  when present it routes by that host, else falls back to the global
  (existing callers unchanged).
- useAddRepoServerPathFlow passes the selected runtime into the scan and
  derives runtimeKind/streaming support from it instead of the global-reading
  getNestedRepoRuntimeKind(null), so telemetry and the nested review target
  the same host as the add.

Adds renderer- and store-level regression tests covering scan routing to the
selected runtime, the null-override local case, and the nested-review handoff.

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

* fix(sidebar): make nested-scan cancellation route by the scan's owning host

Follow-up to CodeRabbit review of the scan-routing change:

1. scanNestedRepos treated `{ runtimeEnvironmentId: undefined }` as an explicit
   local override via the `in` check. Only null or a string is now explicit;
   undefined falls back to the global (matches getAddRepoPathRouteSettings).

2. scanNestedRepos gained a routing override but cancelNestedRepoScan still
   routed by the global — an asymmetric contract where an override-routed scan
   could be un-cancellable if the global diverged mid-scan. cancelNestedRepoScan
   now takes the same override, and useAddRepoNestedReviewState remembers each
   scan's owning host by scanId (set when the scan is registered) so both stop
   and reset cancel on the host the scan actually ran on. The local folder flow
   routes its scan explicitly local so scan, cancel, and add all agree.

Adds store-level regression tests (explicit override wins, undefined falls back
to global, cancel routes by override) and a new useAddRepoNestedReviewState test
covering cancel-by-owning-runtime for stop and reset.

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

* fix(sidebar): keep subfolder adds on their owning host

* fix(onboarding): keep completion on captured host

* chore(review): drop unreachable onboarding recovery

* fix(sidebar): preserve paired runtime checkout ownership

* fix(runtime): index paired worktrees by logical owner

* fix: fail closed on worktree owner alias collisions

* docs(sidebar): clarify host-routing intent flagged in review

Two Greptile P2 notes, addressed as comments (no behavior change):
- project-added-default-checkout.ts: the runtime branch's `hostId === executionHostId`
  is NOT unreachable — a colliding repo id can carry a runtime-qualified hostId with
  no runtimeOwnerEnvironmentId (see the "repo IDs collide" test). Documented why the
  comparison is reachable and load-bearing rather than replacing it.
- AddProjectFromFolderDialog.tsx: note that omitting the runtimeEnvironmentId spread
  intentionally signals local (NonGitFolderDialog coerces absence to null).

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

* test(activity): control portal readiness observer delivery

---------

Co-authored-by: fanyunqian.1 <fanyunqian.1@bytedance.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-03 12:53:11 -07:00
Brennan Benson 866bcda465 fix(terminal): recover degraded daemon spawn routing (#12277)
* fix(terminal): recover degraded daemon spawn routing

* fix(terminal): preserve fresh-session recovery semantics

* fix(terminal): avoid retaining exited recovery sessions
2026-08-03 12:47:41 -07:00
OrcaWinandBrennan Benson 34291f07e9 fix(runtime): skip unchanged worktrees when publishing mobile session snapshots (#12207)
* test(runtime): prove mobile session publication rebuilds every worktree

buildMobileSessionTabSnapshots consults its per-worktree cache after building
the content, so a republish saves the fanout but none of the work. With 300
worktrees, an unchanged republish still does 601 units of per-worktree work,
and a single changed worktree does 602.

Publication is keyed on agentStatusByPaneKey/agentStatusEpoch, so this runs on
every agent status tick. On a multi-client runtime host with 381 worktrees this
allocated ~350 MB/min and rode the renderer into repeated 4 GB OOMs.

Tests are marked it.fails so the branch stays green; drop .fails when the build
loop skips worktrees whose inputs are unchanged.

* refactor(runtime): make mobile session snapshot inputs explicit per worktree

Every per-worktree builder in buildMobileSessionTabSnapshots took the whole
AppState, so a worktree's real input set was the transitive closure of seven
helpers and could not be memoized safely. Introduce MobileSessionWorktreeInputs
— built once per worktree — and thread it through the group projection and the
terminal/markdown/file/browser tab builders so the compiler proves the input
set. Tab- and pane-keyed slices are narrowed to this worktree's tab ids, file
ids, browser workspace/page ids, and pane keys; agent statuses are bucketed per
worktree once per publication via a tab-id index.

No behavior change. Dropping AppState from the projection path also removes the
second per-worktree read of browserTabsByWorktree, so the publication-cost
counter falls from 601 to 1 per publication and its two cases now pass.

* fix(runtime): skip unchanged worktrees before building mobile session content

buildMobileSessionTabSnapshots consulted its per-worktree cache only after
building that worktree's three Maps, group projection, and full tab array, so
the cache suppressed the fanout but none of the computation. Every agent-status
tick therefore rebuilt every worktree, which drove sustained 4 GB renderer
working sets on a host holding 381 worktrees.

Cache MobileSessionWorktreeInputs alongside each snapshot and reuse the snapshot
when every input field is reference-equal, before any intermediate structure is
allocated. Worktrees with a mounted TerminalPane always rebuild: their live
DOM/PaneManager state is invisible to store references. Absent per-worktree
slices now resolve to shared empty values so an empty worktree can compare equal
to its last publication. jsonContentEquals stays as the backstop on the rebuild
path for inputs that churn by reference without changing output.

With 300 worktrees, per-worktree content builds go from 300 to 0 on an unchanged
republish and from 300 to 1 when one worktree changes.

* test(runtime): cover agent status publication cost

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-03 12:09:32 -07:00
OrcaWin cd68a8b00c fix: preserve live agent PTYs through graph hydration (#11789) 2026-08-03 11:11:14 -07:00
OrcaWin 128e3e335e fix(packaging): prune non-target native binaries (#12174) 2026-08-03 10:54:00 -07:00
Jinjing e08eba674c test(terminal): cover live macOS Korean syllable flush (#12284) 2026-08-03 03:07:52 -07:00
40d5f36608 fix(native-chat): adopt IME deletions at composition end (#12281)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: fengxinzi1814 <55725821+fengxinzi1814@users.noreply.github.com>
2026-08-03 02:56:35 -07:00
Neil caf6add53a test(terminal): cover leading Korean vowels (#12282) 2026-08-03 02:55:16 -07:00
Neil 035d8c2a54 fix(terminal): preserve macOS Korean composition (#12280) 2026-08-03 02:46:22 -07:00
f82d4100b7 fix(terminal): flush Hangul syllables before the next composition (#12278)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Hyunggyun Lyou <hg.lyou@miraeasset.com>
2026-08-03 02:45:08 -07:00
6f7a30ac2e test(terminal): preserve Windows IME Shift commits (#12276)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: yoke233 <yoke2012@gmail.com>
2026-08-03 02:21:56 -07:00
Neil 339045b150 fix(runtime): coalesce concurrent host terminal focus (#11841)
Bound exclusive host navigation to a generation-aware latest-wins
single-flight so bulk open and switch fan-out stay responsive on large
remote fleets. Add freeze repro harnesses and navigated settlement.
2026-08-03 02:18:05 -07:00
Him188andClaude Fable 5 8e9640cb1d fix(terminal): stop cancelled IME compositions replaying stale preedit
Backspacing away an entire Pinyin preedit ended the composition with
empty data, no textarea residue, and no input/keypress events — yet
_sendPendingComposition fell back to the last non-empty
compositionupdate data and typed its first character into the PTY.
Only trust that fallback when observed input evidence corroborates it;
a composition with no evidence in any channel was cancelled.

Fixes the macOS Pinyin regression from #11293 (stray letter left after
deleting a preedit); same fix covers IBus/fcitx Backspace cancellation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 01:53:02 -07:00
KimYounghwan8750 173abf8b12 test(terminal): replay the native Windows IME Shift shape
Adapted from the physical Windows event trace contributed on #11878.
2026-08-03 01:30:58 -07:00
OrcaWin a5655321b5 style(terminal): keep IME ownership rationale concise 2026-08-03 01:30:58 -07:00
KimYounghwan8750andClaude Fable 5 bacdf3a31d fix(terminal): keep press evidence per Enter press, not per code
A single slot per code let a rapid second Enter press go unguarded: the
first release found a mismatched timeStamp, dropped the only entry, and
the second release then synthesized the Shift+Enter this guard exists to
prevent. Track one entry per press and drain exactly one per physical
release, so every press stays guarded until its own release. Auto-repeat
keydowns do not stack an entry, since the whole run ends in one release,
and the list is bounded so a press whose release never arrives cannot
grow it without end.

Refs #11878

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 01:30:58 -07:00
KimYounghwan8750andClaude Fable 5 ad0a70aa14 fix(terminal): require press-time evidence before synthesizing an IME Enter-keyup newline
On Windows, the Enter-keyup synthesis path inferred the modified-Enter
chord from release-time modifier state. A plain committing Enter
(Process/229, no modifiers) followed by a rolled-over Shift for the next
doubled consonant made the keyup report shiftKey=true and synthesized a
Shift+Enter the user never chorded; a directly-sent Shift+Enter could
likewise send a second newline from its keyup once the next composition
started. Record observed Enter keydowns (code -> timeStamp) and let the
keyup synthesis run only for presses whose keydown the IME swallowed
entirely; a balancing keyup that copies the keydown timeStamp keeps the
evidence for the later physical release.

Refs #11878

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 01:30:58 -07:00
Neilandholdn2 ca9562ceee fix(terminal): block IME-owned Process shortcuts
Adapted from #11616 commit 9f449d75b and #12120 commit 290f42a36.

Co-authored-by: holdn2 <club.makersfarm@gmail.com>
2026-08-03 01:30:58 -07:00
kunsanglee 8af6876510 fix(terminal): distinguish IME Process keys from Enter
Adapted from #11273 commits c690ee609, 506524085, and cc69fa7bf.
2026-08-03 01:30:58 -07:00
OrcaWinandOrcaWin 9e42b5fd41 fix(terminal): clear stale Windows IME modifiers (#12259)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-03 01:04:18 -07:00
Siddiqui QamarandOrcaWin f3c824bc28 fix(terminal): expand environment variables in Windows PATH (#11987)
* fix(terminal): expand variables in Windows PATH

* fix(terminal): preserve expanded Windows PATH at spawn

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-03 01:00:58 -07:00
NeilandOrca 1dbf55e4df Stop reporting supported Linux hosts as an unsupported remote platform (#12209)
Co-authored-by: Orca <help@stably.ai>
2026-08-03 00:50:20 -07:00
Brennan Benson 3d68212f7b fix(mobile): surface worktree catalog failures instead of silent 0 worktrees (STA-3123) (#12235)
* fix(mobile): surface worktree catalog failures instead of showing 0 worktrees (STA-3123)

A connected host whose worktree.ps request fails now shows an explicit
catalog-failure state (with the RPC error code) on the host page, and
'Worktree list unavailable' on the home host card, instead of silently
rendering as a healthy host with zero workspaces.

* fix(mobile): mark cached worktree catalogs unavailable
2026-08-03 00:48:30 -07:00
Neil 18dbcf001f fix(tabs): restore Cmd/Ctrl+Shift+T tab positions (#12236) 2026-08-03 00:08:09 -07:00
OrcaWinandOrcaWin d48cac7d0f fix(onboarding): run skill setup in the configured Windows runtime (#12103) (#12204)
* fix(onboarding): run skill setup in the configured Windows runtime (#12103)

Onboarding was the one skill-setup surface that did not route its install
command through the resolved runtime. Settings, the feature-wall panels and
the Linear prompt all wrap theirs as `wsl.exe -d <distro> -- sh -c ...` and
pass a matching shell override; onboarding spawned a bare terminal and handed
it the raw `npx skills add ...`. With Node inside WSL, npx is not on the
Windows PATH, so the install failed.

The runtime resolver had a second gap behind that: it only consulted
per-project settings, and onboarding runs before any project exists. With no
project it returned undefined and fell through to the Windows host, ignoring
a global WSL default entirely. `getLocalAgentPreflightContext` already had a
no-project fallback for PATH detection; the skill-install path had none.

- extract that fallback as `getGlobalWindowsExecutionRuntimeContext` and
  rewire the existing agent-preflight branch through it so the two cannot drift
- adopt it in `useActiveProjectSkillRuntime` when no project is active. WSL
  only: a windows-host default already matches the old no-project behavior,
  and resolving it would hand skill discovery a target where it had none,
  re-triggering scans for every host-default user
- build the onboarding terminal's command for the runtime and pass its shell
  override
- register the CLI in WSL rather than on the host, so `orca` lands on the PATH
  the install actually runs on, and wrap the copied command to match

* fix(onboarding): keep skill setup runtime consistent

* test(onboarding): satisfy runtime settings contract

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-02 23:28:34 -07:00
JinjingandOrca db5325204f Route terminal links based on pane ownership, not global state (#12233)
* fix(terminal): route remote-runtime link clicks to the system browser

Terminal link clicks classified ownership from the global
activeRuntimeEnvironmentId, which is null when runtimes are bound per
workspace, so a link clicked in a remote-hosted pane opened a local-only
Orca browser tab and never reached the host. Thread each pane's resolved
runtimeEnvironmentId into openHttpLink as sourceOwner across the OSC 8,
WebLinksAddon, and click-fallback paths.

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

* fix(terminal): route link clicks based on pane ownership, not global sta

Clicking links on remote-hosted panes was routing based on global runtime state, causing unexpected reconnections. Now link routing decisions (where to open: Orca vs system browser) are based on the actual pane's owner — local, SSH connection, remote runtime, or unknown — regardless of whether any runtime is globally active. This ensures a local pane can route to Orca while another pane's remote runtime is active, and a remote pane always routes to the system browser.

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-02 23:27:58 -07:00
Brennan Benson 93a2ad8fd8 fix(browser): bound retained webview guests across worktree switches (#12194)
* fix(browser): bound retained webview guests across worktree switches

* fix(browser): merge duplicate imports flagged by import/no-duplicates

* fix(browser): evict guests without unmounting the worktree surface

Unmounting the surface disposed every parked terminal byte watcher for the
evicted worktree (bell/title/agent-completion facts dropped for good after
the 15s handoff TTL) and skipped the force-park scrollback capture remote
panes rely on. Destroy the guests only: hidden slots mount no BrowserPane,
so nothing resurrects a destroyed guest before the next visit, and no slot
ever unmount-detaches a live guest (STA-3228). Terminal-state vetoes and
the eviction re-render bump are no longer needed; the only veto left is a
guest an automation/mobile controller is actively driving.

* fix(browser): veto eviction for downloading pages; keep zoom; add kill switch

Main cancels a page's active downloads when its guest unregisters (tab-close
semantics), so eviction now vetoes worktrees with a page still writing a
download, tracked app-wide because download state was pane-local and hidden
panes are unmounted. Eviction is not a user close: re-remember explicit zoom
past the destroy-path forget so a revisit reasserts the user's zoom instead
of resetting same-host siblings through Chromium's partition-wide HostZoomMap.
browserGuestWorktreeRetentionBudget mirrors the terminal budget kill switch.
2026-08-02 23:11:53 -07:00
Brennan Benson aa03e2475e fix(mobile): gate native chat approval card on a paused agent (STA-3144) (#12206) 2026-08-02 22:58:53 -07:00
Brennan Benson 153acf3156 feat(crash-reports): add byte attribution to renderer memory highwater breadcrumbs (#12198)
* feat(crash-reports): add byte attribution to renderer memory highwater breadcrumbs

Entry counts stay flat when a slice grows by value weight (97b9e86d leaked
~700MB while its biggest slice grew by 4 entries), so highwater breadcrumbs
now carry sampled per-slice KB estimates for the store plus a live pane
census (managers, panes, estimated scrollback KB) — the dominant heap cost
the store census cannot see.

* fix(crash-reports): bound renderer OOM profiling

* fix(crash-reports): total raw store estimate bytes
2026-08-02 22:51:25 -07:00
Brennan Benson b4d9ae44a5 fix(mobile): deliver the agent launch command when a create settles over a bare renderer PTY (#12197)
A mobile New Tab -> Codex create resolves the launch command and hands it
to the renderer, but when the renderer's startup queue is lost (the #7587
stall class) the pane spawns a plain shell and the create still settles
ready via PTY adoption - silently binding the phone to a bare terminal
forever, since the ready status also disables the #7837 activation-time
materialize recovery.

Record the resolved launch command on the pending create and, at every
renderer-backed settle point, deliver it to the adopted PTY when no spawn
command was recorded for it. Spawn commands are noted per PTY by both
spawn IPC handlers, so a missing record on the locally registered live
PTY proves the launch never ran; delivery types the command exactly like
the create would have, and the note prevents double delivery.

Fixes STA-3214
2026-08-02 22:47:44 -07:00