Commit Graph
19701 Commits
Author SHA1 Message Date
Kelvin Amoaba f736cab7d7 feat(dictation): resample desktop dictation to 16 kHz in an AudioWorklet with an anti-alias filter (#39290)
* feat(dictation): capture desktop audio in an AudioWorklet at 16 kHz

Desktop dictation captured with a ScriptProcessorNode on the renderer's
main thread and shipped hardware-rate buffers, which main then decimated
to 16 kHz with linear interpolation and no low-pass, folding everything
above 8 kHz back into the speech band.

An AudioWorklet now resamples to 16 kHz with a windowed-sinc low-pass,
posts 100 ms frames, and sends a level every 50 ms for the meter and
silence auto-stop. Desktop and the web client share it.

* refactor(dictation): share the sinc resampler and meter window, one frame sink

Move the resampler to src/shared beside the meter it feeds, share the
50 ms meter window with the phone's, drop the constant per-chunk sample
rate from buffered audio, and send frames through one deliverFrame so
the speech-host port can replace it later.
2026-11-07 05:07:31 +00:00
Kelvin Amoaba df38124cce refactor(mobile): drop the unused playback path from the dictation audio module (#39293) 2026-11-07 05:03:22 +00:00
Jinwoo Hong c912144aae Show the machine on folder workspace cards (#39280)
* Show the machine on folder workspace cards, as other workspace cards do

* Build folder fixture rows without passing the array index

* Add a fixture for a folder card on another machine

* Drop the folder card screenshot fixture

* Put an unstamped folder card on the host it runs on

A folder workspace with no host stamp resolved to its project group's host for
labels and sections but to local for its card row. Stamp it the way catalog
adoption does so the card, label and section agree with runtime dispatch.
2026-11-07 00:02:39 -05:00
Kelvin Amoaba f89638f2b4 perf(mobile): return to LAN soon after joining Wi-Fi (#39165)
* perf(mobile): return to LAN soon after joining Wi-Fi

* perf(mobile): allow one arrival per dwell and keep 12 s for Tailscale probes

* perf(mobile): defer a second arrival to the dwell and keep 12 s for non-private hosts

* refactor(mobile): share one network read across hosts and build the fingerprint once
2026-11-07 04:58:07 +00:00
Kelvin Amoaba 1813a01fa6 perf(browser): credit screencast frames to the phone (#39189) 2026-11-07 04:57:47 +00:00
Kelvin Amoaba b26ad4bd58 perf(runtime): resume a phone terminal from what it already received (#39156)
* perf(runtime): resume a phone terminal from what it already received

* fix(runtime): carry a missed cwd change on resume and keep points the ring covers

* fix(runtime): resume only onto the grid the missed output was written for

* test(runtime): type the resume token without a cast
2026-11-07 04:57:33 +00:00
Kelvin Amoaba f9b95a7b6f perf(mobile): ack terminal output after xterm parses it (#39151)
* perf(mobile): ack terminal output after xterm parses it

* fix(mobile): retry refused terminal acks and share one ack across echoes

* fix(mobile): retry a refused terminal ack on the timer, never inline

* test(mobile): keep only terminal credit tests that fail without it

* refactor(mobile): key terminal ack settles by stream token

* test(mobile): type the credit test timer steps

* test(mobile): use T[] for the parsed callback list
2026-11-07 04:57:18 +00:00
Kelvin Amoaba a319c0eccb fix(mobile): bring attachments back with an unconfirmed chat send (#39258)
* fix(mobile): bring attachments back with an unconfirmed chat send

* refactor(mobile): share the draft chip removal and build the send intent once
2026-11-07 04:56:26 +00:00
Kelvin Amoaba f29c96745c perf(mobile): stop recomputing chat row keys and projection on every commit (#39216)
* perf(mobile): stop recomputing chat row keys and projection on every commit

* refactor(mobile): drop write-only grouped field from chat projection
2026-11-07 04:56:12 +00:00
Kelvin Amoaba 0e5d2cb5ea fix(mobile): keep a parked chat reader steady while a reply streams (#39209)
React Native Web repeats the last scroll event 100 ms after scrolling
stops. The page list cleared its record of its own scroll write on the
first matching event, so the repeat after each place-keeping correction
counted as the reader scrolling. For a parked reader that froze the
streaming reply below for 300 ms about every 0.7 s and released it in
one step, which showed as lurches of 20-40 px.
2026-11-07 04:55:58 +00:00
Kelvin Amoaba 2980a713c8 perf(mobile): use mobile-only chat coalesce and reveal timings (#39183) 2026-11-07 04:55:44 +00:00
Kelvin Amoaba 6708f76690 perf(mobile): show the model picker's models as soon as a chat opens (#39152)
* perf(mobile): show the model picker's models as soon as a chat opens

* fix(mobile): retry skill scans and trailing command reads through the query

* fix(mobile): keep menu-read commands across a re-probe and rescan skills on demand

* refactor(mobile): read chat query state from the client and give the model catalog query its own module

* test(mobile): give the reopen seed catalog its fetchedAt

* fix(mobile): keep the query layer out of the phone options hook's module graph
2026-11-07 04:55:30 +00:00
Kelvin Amoaba 9d32a61bb4 perf(mobile): load the new-tab agent list with the session and share it with "Fix with" labels (#39148)
* perf(mobile): load the new-tab agent list with the session and share it with "Fix with" labels

* fix(mobile): wait for host status before detecting agents

* fix(mobile): read the agent list again on each open after a failed read

* refactor(mobile): name the source control agent through the shared label hook

* chore(mobile): type the new-tab recording adapter with a type import
2026-11-07 04:55:16 +00:00
Kelvin Amoaba b0cd6d391c perf(mobile): open a session with its last tab strip (#39158) 2026-11-07 04:55:01 +00:00
NeilandShemYu 1712936c29 feat(usage): show Muse subscription quota in the status bar (#38907)
* feat(usage): show Muse subscription quota in the status bar

Reads `muse usage --json` (Muse Code 1.4.13+), which reports the
subscription allowance without a model turn, and maps `allowance.window`
to the five-hour session meter and `allowance.weekly` to the weekly meter.
`rateLimits.muse` now appears in `orca account list --json`.

- Gate on `muse --help` listing `usage`: older builds treat an unknown
  subcommand as a prompt, so Orca never sends `usage` to them.
- Run with MUSE_NO_AUTO_UPDATE=1 and MUSE_LOGIN=0 so a background poll
  never self-updates the launcher or starts a device sign-in.
- Missing CLI, signed out, API-key login / no allowance, non-JSON output,
  and timeouts each map to an explicit unavailable/error snapshot.
- Hidden meters skip the spawn, and Muse publishes after the sibling batch
  so a slow CLI cannot delay Grok/Cursor/ZCode/Antigravity.
- Default-on status-bar item with a one-shot migration, CLI-detection
  gating, visibility menu and Settings toggle, remote-owner mapping.

Based on the design in #34232 by ShemYu.

Co-authored-by: ShemYu <11490047+ShemYu@users.noreply.github.com>

* fix(usage): cap Muse usedPercent and date readings by fetch time

Muse can report over-quota usage above 100; clamp to the 0-100 meter
contract like the other providers. Use the fetch time for updatedAt so a
cached older asOfMs cannot make every window focus trigger a refresh.

* fix(usage): prevent Muse launcher installation during polling

* fix(usage): gate Muse on its version file and run the active build directly

- Read the launcher's `.muse-version` and require 1.4.13 or newer (the
  release that added `muse usage`); only installs without that file fall
  back to `muse --help`, cached by launcher path, mtime and size.
- Execute `muse-bin-<version>` directly when it exists, so the launcher's
  update, sign-in and install paths never run; the env guards stay for
  the launcher fallback. A version change during the call discards the
  reading as stale.
- Start the Muse fetch at the beginning of the full cycle and cap it near
  8s (6s usage, 2s help), so a slow CLI holds the shared queue far less.

---------

Co-authored-by: ShemYu <11490047+ShemYu@users.noreply.github.com>
2026-11-06 20:53:57 -08:00
Kelvin Amoaba b051519599 refactor(dictation): run the desktop dictation controller on a shared session state machine (#39284)
* refactor(dictation): run the desktop controller on a shared session state machine

* test(dictation): assert session machine behaviour, not run numbering

* refactor(dictation): allow a new start from the error phase

* test(dictation): drop the error-restart case no desktop path depends on yet

* refactor(dictation): derive stop-during-start from the phase and share the start teardown
2026-11-07 04:53:39 +00:00
buf0-bot[bot] 3d8a285132 Update README downloads badge (#39291)
Co-authored-by: buf0-bot[bot] <252831055+buf0-bot[bot]@users.noreply.github.com>
2026-11-07 04:51:25 +00:00
Neil ab6d40a9df revert: onboarding Antigravity installer (#39172) (#39282)
This reverts commit 88fa7ed2a9.

Also drops the agyInstall strings a later locale sync added to the
non-English locale files, so no orphaned keys remain.
2026-11-06 20:50:07 -08:00
Kelvin Amoaba 1763014bea perf(mobile): reopen Files folders from memory (#39175)
* perf(mobile): reopen Files folders from memory

* test(mobile): re-record Files explorer goldens for query reads

* fix(mobile): paint cached Files rows before the host client attaches

* refactor(mobile): share query observer options and Files' empty-state rules

* test(mobile): type the Files explorer test host
2026-11-07 04:41:21 +00:00
Kelvin Amoaba 51f532115e perf(mobile): open Review with the Changes data already loaded (#39159)
* perf(mobile): open Review with the Changes data already loaded

* fix(mobile): keep the open diff through re-keys and wait for Review rebuilds

* fix(mobile): release Review writes once their files show, retry only fixed diffs

* fix(mobile): follow language switches in Review's diff states

* fix(mobile): keep Changes' compare key out of render and type the Review adapters
2026-11-07 04:41:07 +00:00
Neil 121e8ba354 fix(muse): keep panes working while spawned background subagents run (#38911)
Hold the lead Stop through the shared child-work fold while UUID children
are live between SubagentStart and SubagentStop. A child that sends no hook
for 10 minutes stops holding the row. Interrupt (subscribed async, as Muse
requires), SessionStart and SessionEnd clear tracked children, and the
existing transcript-poll replay of the held Stop then reaches done.

Fixes #28090
2026-11-06 20:36:59 -08:00
Neil 4ced677eba Stop polling a Muse session log that has gone silent (#38902)
* fix(agent-hooks): bound Muse transcript polling when the session goes silent

A Muse session that ended without Stop kept its 1s session-log poll alive
until the pane closed or another hook arrived. Idle polls now probe the
owner's process after 60s without log growth (an exited owner is reconciled,
which clears the poll) and stop after 30 min of silence; the next hook
re-arms polling.

Linear: STA-8313

* fix(agent-hooks): re-arm the Muse poll after a presence probe restates the row

A live owner's suspension flip (Ctrl-Z/fg) makes the idle presence probe write
a new row; the next poll tick saw a superseded row and stopped, and no hook
re-armed it. Re-arm on the restated row, keeping the idle clock, unless a newer
hook already owns the pending poll.

Linear: STA-8313

* fix(muse): back off quiet transcript polling safely

* fix(muse): replace the presence probe with a 5s quiet-log back-off

Back a quiet Muse log off from 1s to a 5s cadence instead of probing
presence; log growth, a status change, or any hook for the session
(including ignored ones) restores 1s. Removes the idle presence probe and
the row-restatement re-arm, which Muse rows never needed: Muse hooks carry
no trusted process identity, so the probe always returned early.
2026-11-06 20:36:52 -08:00
Kelvin Amoaba c108ee4ea7 fix(mobile): reread Source Control settings when a screen opens or the app returns (#39266)
* fix(mobile): reread Source Control settings when a screen opens or the app returns

* test(mobile): use the shared hook harness for the settings reread test
2026-11-07 04:05:49 +00:00
Kelvin Amoaba 93187e7d66 feat(mobile): show a thin refresh line under the header while cached data refreshes (#39170)
* feat(mobile): show a thin refresh line under the header while cached data refreshes

* fix(mobile): start the refresh line still under unknown motion and key it by execution host

* fix(mobile): draw the refresh line only once the motion preference is known

* fix(mobile): start the refresh sweep at the left edge on each reveal

* refactor(mobile): drive the refresh line from the screen's own refetch and keep its timers in the header

* test(mobile): give the Changes content fixture the new refreshing field
2026-11-07 04:05:35 +00:00
Kelvin Amoaba 309b9b66e6 perf(mobile): stop a hidden host list refetching on every change (#39210)
* perf(mobile): stop a hidden host list refetching on every change

The host list's change-event path fetched worktree.ps (and the server rows read) on every worktreesChanged or reposChanged with no throttle, even while the page was buried under a session or the app was backgrounded. Hidden pages now note what they owe and the foreground refresh catches up once; visible pages read at most once per 3 s.

* perf(mobile): count poll reads in the change throttle and queue the catch-up read

* perf(mobile): leave the poll out of the change throttle and queue the catch-up only after skipped notices

* test(mobile): drop the throttle timing test

* refactor(mobile): one owed flag and one full catch-up read for a hidden host list
2026-11-07 04:05:20 +00:00
Kelvin Amoaba c158c82c71 perf(mobile): skip the Suspense fallback on page boot (#39184)
* perf(mobile): skip the Suspense fallback on page boot

* fix(mobile): keep open-target boots on the lazy path

* test(mobile): pin that the page waits for its held route chunk

* refactor(mobile): preload every page layout and keep screens apart
2026-11-07 04:04:45 +00:00
Kelvin Amoaba 0f854c5209 perf(mobile): render the cached page build first and talk only after the connection's verdict (#39174)
* perf(mobile): render the cached page build first and talk only after the connection's verdict

* test(mobile): give ready shell states their page window
2026-11-07 04:04:32 +00:00
Kelvin Amoaba 22f09f4257 refactor(mobile): read host capabilities from one status read per connection (#39157) 2026-11-07 04:04:19 +00:00
Kelvin Amoaba cc6a66ed01 feat(mobile): let pages read and write the device store (#39147)
* feat(mobile): let pages read and write the device store

* fix(mobile): import zod as a namespace in the page store verb

The page bundle check rejects `import { z }`: it ships zod's locale tables.
2026-11-07 04:02:52 +00:00
193dd5726f Git Graph tab: all branches, commit details and file changes (#6746)
* Add Git Graph view showing all branches and commit history

Adds a full-pane Git Graph tab that visualizes the whole repository —
all local branches, remote-tracking branches, tags, merges, and HEAD —
instead of only the current branch's linear history shown in the Source
Control sidebar today.

- Add an opt-in allRefs scope to the shared git-history loader so the
  graph query enumerates --branches --remotes --tags HEAD; the default
  current-branch path is unchanged. The flag is forwarded through the
  local IPC, SSH provider, and runtime RPC boundaries so it works in all
  environments.
- New git-graph tab content type with a full-pane GitGraphPane that
  reuses the existing graph SVG/row components, virtualizes rows, and
  opens a commit's combined diff on click. Wired into the tab strip as a
  chip (activate/close/keyboard-cycle) mirroring the simulator pattern.
- Entry point: an Open Git Graph button in the Source Control commits
  header (Cmd/Ctrl-click opens in a split).

Closes #4521

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

* Address review: virtual-tab guards, nav-order, truncation copy

- Treat the Git Graph (and mobile emulator) tab chip as a virtual tab:
  add an isVirtual contract to EditorFileTab/EditorFileTabContextMenu so
  rename, copy-path, copy-relative-path, and reveal-in-finder are disabled
  for tabs whose filePath is a display label, not an on-disk path. Prevents
  a rename on the synthetic 'Git Graph' path running a real file operation.
- Forward gitGraphIds through the legacy reconcileTabOrder fallback in
  getActiveTabNavOrder so keyboard tab navigation does not drop git-graph
  tabs when no split-group layout exists yet.
- Make the truncation banner explicit: 'Showing first N commits across all
  branches' (was 'of many'), across all locales.
- Tests: virtual-tab hides path actions; git-graph survives the legacy
  nav-order fallback.

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

* Forward allRefs over SSH relay and web runtime paths

Two boundaries re-destructured git.history params and dropped the new
allRefs flag, leaving the repo-wide Git Graph inert (linear default-branch
history) for SSH and web-runtime worktrees:

- src/relay/git-handler.ts: the relay host's git.history handler forwarded
  only { limit, baseRef }. Add allRefs so the SSH host enumerates all refs.
  Adds an end-to-end relay test (a feature-branch commit absent from linear
  history appears only when allRefs is forwarded).
- src/renderer/src/web/web-preload-api.ts: the web preload history shim
  destructured only { worktreePath, limit, baseRef }. Forward allRefs.

Also fix a request-id race in useGitGraphHistory: bump requestIdRef before
the null-context early return so an in-flight fetch from a prior worktree
can't resolve and overwrite the 'idle' state after the worktree clears.

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

* Support filtered and pinned Git history

Resolve branch and tag roots on the host, keep paging tied to the chosen revision set, and echo the applied filter across Git transports.

Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>

* Add the Git Graph tab and commit details

Open the all-branch view from Source Control or the command palette, preserve older clients' layouts, and keep the sidebar HEAD-only.

* Restore files the main merge left at stale versions

The earlier merge of origin/main kept older or missing copies of 61 files
unrelated to the Git Graph (CI script tests, reliability gates, shard
timings and five terminal runtime files). Take main's version of each so
the PR changes only its own files.

* Limit pinned history to explicit graph scopes

Keep All and HEAD snapshots free of redundant ref names, and filter ref searches before nested-tag peeling. Default history requests retain unpinned paging without evicting graph tokens.

Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>

* Preserve canonical placement for older graph clients

Pass graph-free record deltas through without rebuilding layouts, retain existing empty groups, and translate content creation into canonical groups while preserving hidden graph tabs.

* Retain Git Graph browsing state for the tab lifetime

Own history retrieval, selection and scroll in one renderer controller that retires on close or owner/filter changes. Accumulate parent pages before publishing, share action-time workspace navigation, serialize ref searches, and scope refreshes to the workspace.

* Apply Git Graph branch selections on picker close

Keep checkbox changes local until dismissal, then normalize and apply one chosen ref set. Allow picker reads to use a qualified host scope.

* Keep Git Graph navigation bound to its tab owner

Retain the tab's qualified owner and Git connection across workspace focus changes. Newer selections and refreshes supersede pending parent navigation without losing fetched pages.

Report stale workspace switches and let the commit menu handle empty space in the Branch / Tag cell. Cover twin-owner retention, superseded navigation and picker apply-on-close with renderer regressions.

* Translate desktop layout commands against canonical state

Resolve older desktops' visible groups, tab gaps and split paths inside the canonical mutation, including detach and cross-partition moves. Keep initial admission visibility-aware and cache graph presence for binding-only frames.

* Refine Git Graph picker and owner transitions

Discard branch drafts on Escape or owner changes, follow updated tab ownership, and report workspace lookup failures for the current owner. Keep parent navigation queued behind pending history loads.

* Drop the redundant default from the exhaustive layout command switch

* Align Git Graph with changed-code quality rules

Use typed fixtures and an event guard, keep primitive styling on content wrappers, and prune loaded-commit bookkeeping after render.

* Route Git Graph opening through the existing editor action

Use workspace record selectors for stable owner inputs and remove two
loading labels orphaned by the graph changes from all locale catalogs.

* Preserve Git Graph selection and keep row content visible

Refresh and token recovery retain loaded depth and selection in one
accumulating operation. Keep the published view until it settles, and
only fall back to the first commit after history is exhausted.

Prioritize current and open-workspace refs, reserve their markers, clip
wide graphs and retain filenames when long paths need truncation.

* Bound Git Graph refresh and allow graph column resizing

Restore the loaded depth without searching for vanished selections, retain the published result on retrieval errors, and keep newer selections visible. Allow the bounded graph column to expand to every lane through the existing resize mechanism.

* Retain Git Graph history for errors without a message

Detect failed retrieval independently of its message and cover an empty-message rejection in the existing partial-failure regression.

* Retain Git Graph widths and preserve shifted selections

Separate committed and live resize widths, retaining the chosen width for the graph tab lifetime. Allow one bounded extra history page for selections shifted by new commits, and give the resize separator a translated label.

* Preserve nullable Git Graph owner fallback

* Fix Git Graph layout imports after the RPC method move

* Route the Git Graph owner connection through the source-control connection helper

* Keep the Git Graph button idle in hidden Source Control sections

* Re-probe Git Graph support when the owner's runtime status changes

---------

Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>
2026-11-06 19:59:47 -08:00
Neil 944ed9f2ca refactor(terminal): organize remaining pane features by owner (#39270)
* refactor: organize remaining terminal pane features by owner

* refactor(terminal): consolidate replay guard type imports

* refactor(terminal): retarget notification mocks and generated consumer import

* refactor(terminal): repair benchmark owner lookup and stale mock export
2026-11-06 19:45:07 -08:00
Kelvin Amoaba bd88cdeca8 perf(mobile): trim the page bundle back under its old budget (#39182)
* perf(mobile): trim the page bundle back under its old budget

* build(mobile): simplify the route entry anchors and zod table guard

* fix(mobile): import zod as a type in the RPC result reader
2026-11-07 03:28:04 +00:00
Brennan Benson 1a00fd0bb5 Fix main after folder Source Control and pane lifecycle merges (#39273)
Point the main-surface launch test at resolveQueuedInitialCwd's new module and prune the layout-writer baseline entry the merged code no longer uses.
2026-11-06 19:16:50 -08:00
Brennan Benson 7270350443 fix(chat): shrink composer workspace footer and center its text on icons (#39261) 2026-11-06 19:09:50 -08:00
Brennan Benson 299a47af4a Use one shared Hide button for chat cards (#38999)
* feat(native-chat): one Hide button and toast for chat cards; PR card setting beside Changed files

The opened-PR card now uses the changed-files card's Hide control and Hidden
toast through a shared NativeChatCardHideButton, and its switch moves to
Settings > Chat UI > Appearance next to Changed files summary, where Reset
restores both. The saved key is unchanged.

* refactor(native-chat): read the opened-PR card switch through its predicate

* test(settings): Reset turns both hidden chat cards back on

* Preserve the existing opened pull request Hide aria label

* fix(native-chat): keep the gap before the PR card's Hide button
2026-11-06 19:09:12 -08:00
Brennan Benson 04bb0d0810 test(agent-launch): import resolveQueuedInitialCwd from its new home (#39269) 2026-11-06 18:52:05 -08:00
Jinwoo Hong 66cd756f91 Hooks admit the lead's final reply with its turn; the launcher records undelivered prompts and proven exits (#38239) 2026-11-06 21:46:08 -05:00
Kelvin Amoaba 15d71e2dc0 fix(homebrew): keep macOS 13.0–13.3 Macs on the Orca they can open (#39264)
Orca now needs macOS 13.4, but depends_on can only say Ventura, and
Homebrew 7 upgrades auto_updates casks by default. A preflight step
refuses the upgrade below 13.4 so Homebrew reverts to the installed app.
2026-11-07 02:32:34 +00:00
Brennan Benson f308486115 Show Source Control for folder workspaces (#38831)
* Separate editor tab placement from content ownership

* Show scoped Source Control sections for attached worktrees

* Preserve active diff refresh and validate section catalogs

* Complete folder section test worktree metadata

* Use contextual types for scoped Source Control actions

* Preserve optional scoped action parameters

* Preserve editor ownership through restore, mirroring and workspace removal

* Retire Source Control drafts only after confirmed owner removal

* Limit section work to visible expanded repositories

* Keep editor follow-up actions and bulk closes in their invoking views

* Track the consolidated editor order writer in its owning module

* Use complete typed fixtures for repair contracts

* Preserve live editor placement during layout readback

* Pass projected editor placement directly to serialization

* Read attached worktree lineage from shared graph module

* Retain inferred owner checks and scope placement retirement

* Preserve selection in untouched workspaces during purge

* Exercise editor placements in existing launch and lifecycle fixtures

* Preserve shared buffer prompts and editor strip order

* Pause inactive section context subscriptions

* Keep section recovery and file actions in the folder workspace

* Describe attached Source Control in folder workspace CLI help

* Attribute Git metadata signals once per dispatch

* Watch mounted source control sections outside the warm budget

* Resolve section watches only for served filesystem roots

* Restore restart-stable editor identity across SSH opens

* Apply section terminal routing to explicit Chat choices

* Include cross-store descendants in folder workspace panels

* Keep cross-host recovery on its existing workspace route

* Start cross-host section agents in their workspace without navigation

* Update memoized Source Control labels on language changes

* Remove unused terminal close-to-right implementation

* Suspend inactive Source Control body observers

* Retain base ref query while section observation pauses

* Cover retained base ref search across section visibility

* Resolve note menu ownership from the retained snapshot

* Preserve section agent working directories and background placement

* Keep Source Control sections active while their overlays are open

* Read current settings when Source Control commands execute

* Adapt editor and browser test stores to view subscriptions

* Preserve bound store hooks for ordinary app views

* Trust agent starts outside the placement workspace

* Trust the section worktree through transient launch ownership

* Extract editor follow-up file actions from the panel

* Fail section launches when trust capability lookup fails

Preserve explicit unsupported-host fallback, propagate lookup failures to the existing launch error path, and let the existing transport retry refresh rejected capability probes.

* Follow the moved pane launch test in web configs

* Preserve section file ownership during refresh and close

* Share tab order removal across editor close paths

* Verify companion editor close through the real store

* Close all workspace split copies for legacy mobile file requests

* Keep unmatched mobile close requests within their workspace

* Reuse the agent menu render snapshot

* Keep attached folder roots scoped to their resolved host

* Apply repository trust decisions to the launch trust owner
2026-11-06 18:25:57 -08:00
Brennan Benson d6842fdb5f Keep reopened ACP sends moving while effort options load (#39223) 2026-11-06 18:17:40 -08:00
Brennan Benson c6f07596ad Phone chat: empty Cmd/Ctrl+Enter steers the first queued message, and holding Cmd/Ctrl shows what it will do (#39215)
* fix(mobile): Cmd/Ctrl+Enter on an empty chat composer steers the first queued message

Matches desktop (#38732) in the paired web page: with nothing typed, the
chord steers the head waiting card through that card's own Steer, only
where its other way is steer.

* fix(mobile): empty Cmd/Ctrl+Enter sends the first queued card after a Stop, as desktop does

Desktop's rule (#38877) also sends the head card when no turn runs, and
goal mode keeps the empty chord inert. The queue list's handle now runs the
head card's own Send when idle, and steers mid-turn only where the chord's
other way is steer.

* test(mobile): type the queued-card handle refusal cases

* feat(mobile): holding Cmd/Ctrl in the phone chat composer shows what Cmd/Ctrl+Enter will do, as desktop does

Desktop's held-modifier preview moves into src/shared so the phone web
composer runs the same rule: Send becomes Queue, Steer or Steer queued
and the head queued card lights while the chord's modifier is held
alone on a hardware keyboard. The queue's empty-chord rule is one
function the preview and the press both read.

* fix(mobile): build the held-chord preview with the phone's own React, and offer only presses that act

The shared hook now takes its React hooks from the caller, as the shared
attachment preview does: the phone bundle resolves a different React copy
than the repo root, so importing react from src/shared broke every phone
web composer (Invalid hook call).

The preview also matches what a press does: one pill press per hold (a
double-click can't send a card after the draft went), a picked /plan-style
skill counts as a message, a head card whose own action is on its way shows
no Steer queued, and the lit state lives in the tray so a chat switch keeps it.

* fix(mobile): held-chord pill takes one click like desktop, keeps busy state per chat, lights only the head row

- The pill ignores a click whose detail is above 1, as desktop does, so a
  deliberate later click in the same hold still acts.
- In-flight card ids are kept per chat with functional updates, so a chat
  settling after a switch can't clear the current chat's record.
- The lit state is a small store only the head row subscribes to, so a hold
  re-renders one row, not the whole queue.
- The desktop preview test moves back beside the desktop wrapper it drives.

* refactor(mobile): one owner for queued-card actions, read by both the list and the held-chord cue

The queue list owned its in-flight guard per mount and the tray mirrored it
for the composer's Steer queued cue; each mirror leaked (cross-chat and
same-chat remount overwrites, an all-chats copy per change). As desktop's
queued-messages controller does, the tray now owns one action store: pending
keys per chat, admitted synchronously, released per action, published by
copying only the changed chat. The list takes those actions as a prop (it
keeps its own only when mounted alone), and the empty chord presses the head
through the same run, so the cue and the press can't disagree. The list's
imperative handle goes away.

Also replaces a type assertion on the pill's click detail with an in guard.

* test(native-chat): desktop chord-preview wrapper re-exports the hold delay its test reads
2026-11-06 18:17:24 -08:00
Brennan Benson a5b267e130 Show a spinner on the native chat fork button while the fork opens (#39255) 2026-11-06 18:16:59 -08:00
Kelvin Amoaba 8038fed16c feat(dictation): stop desktop dictation after a minute of silence (#39131)
* feat(dictation): stop desktop dictation after a minute of silence

A toggle dictation left running keeps the mic open indefinitely. Stop it
a minute after the last speech, with a toast, like the phone's tap mode.
A held push-to-talk key is never stopped; its release ends the session.

Mobile's timer moves into src/shared so both apps use the same rule, and
the shared meter now records when it last heard speech.

* fix(dictation): gate the silence stop on hold mode, as the phone does

* refactor(dictation): let the desktop silence hook own the hold-mode rule, as mobile's does

* refactor(dictation): move the capture meter into its own hook

* refactor(dictation): initialise the capture meter ref without a render write
2026-11-07 02:11:20 +00:00
Neil 7823b122f1 refactor(renderer): organize terminal pane lifecycle and layout owners (#39242) 2026-11-06 17:52:55 -08:00
Brennan Benson f712c0161d fix(native-chat): never draw a focus ring around the conversation (#39214)
* fix(native-chat): drop focus ring that boxed the whole transcript

* fix(native-chat): keep the transcript focus ring for Tab focus only

* fix(native-chat): show the transcript focus ring after keyboard focus, not clicks

* fix(native-chat): keep the transcript focus ring as it was across app switches

* fix(native-chat): never draw a focus ring on the conversation
2026-11-06 17:42:25 -08:00
Kelvin Amoaba 25b288f8b0 fix(web): dictate in the paired web client through the host (#39126)
* fix(web): dictate through the paired host in the web client

The web client's speech API was the fallback proxy and its voice settings were
local-only, so the mic stayed disabled even when the host had dictation set up.
Send audio over the speech.dictation RPCs the phone uses, and follow the host's
voice enabled/model, which the host now publishes in settings.get.

* fix(web): cancel failed starts and keep heard text on a dropped chunk

* fix(web): keep heard text when finish fails and read host voice only from settings.get

* refactor(web): tighten the web speech adapter

* fix(web): keep the focus-read count by reusing the settings already read

* fix(web): import the uuid helper from its new home

* fix(web): cancel the host dictation when finish fails

* fix(web): stop waiting on a stalled chunk backlog after 10 s

* fix(web): match feedAudio's cap result now that the desktop bridge reports it
2026-11-07 01:31:58 +00:00
Kelvin Amoaba 9dacf1e6db fix(mobile): make dictation start reliably on a slow or sleeping desktop (#39142)
* fix(mobile): keep speech said while dictation starts and fail fast on a dead host

* fix(mobile): let a tap or long-press end dictation while it starts

* fix(mobile): wait for the host's cancel before the next dictation starts

* fix(mobile): let a start wait out the previous start on the host too

* refactor(mobile): track host dictation work per client, not per screen

* test(mobile): read the start's dictation id without a cast

* fix(mobile): finish instead of cancel when a held mic is released while starting
2026-11-07 01:25:34 +00:00
Neil e841431af9 feat(web): use E2EE v2 for the pairing token on plain-http pages (#39220)
* feat(web): use E2EE v2 for the pairing token on plain-http pages

Plain-http pages cannot hold a device key, so their sockets always sent
the pairing token over the legacy framing. They now send it over E2EE
v2 (with the usual client capabilities) to hosts that accept it:

- A reconnecting socket tries v2. A host that refuses the v2 hello, or
  refuses capabilities on v2 token auth, is noted and the socket
  reconnects with the legacy framing, as the device-key migration
  already does for older hosts.
- After a v2 token sign-in succeeds, the host's pinned key is kept in
  local storage and every socket to it uses v2; it is never downgraded.
- One-shot and Crew sockets, which cannot absorb a refused attempt, keep
  legacy framing until the host has proven v2. Keyed (https) pages are
  unchanged.

* feat(web): recover a latched host that was downgraded, without a legacy downgrade path

A plain-http page that had signed in to a host over v2 kept retrying v2
forever if the host was later downgraded below v2 token auth. When a
latched host refuses v2, the next socket now only reads the host's status
over legacy framing (keyed to its pinned key), the way a key migration
socket works. If the host's own status lacks
pairing.e2ee-v2-token-capabilities.v1, the latch is released and the page
reconnects over legacy; otherwise it stays on v2. A refusal faked on the
path cannot produce the host's answer, so it cannot force legacy.

The token framing logic moves to web-token-framing.ts.
2026-11-06 17:24:34 -08:00
Kelvin Amoaba 1740dc3e34 fix(dictation): space dictated text from existing text and copy what can't be inserted (#39111)
* fix(dictation): space dictated text from its neighbours and keep text that can't be inserted

* fix(dictation): don't report a contentEditable insert as landed when nothing was inserted

* refactor(dictation): read caret neighbours per block and trim the spacing helpers
2026-11-07 01:24:19 +00:00
Neil 0efe201fbf feat(remote-runtime): use E2EE v2 for desktop and CLI connections to remote runtimes (#39218)
* feat(remote-runtime): use E2EE v2 for desktop and CLI connections to remote runtimes

Desktop connections to remote runtimes (orca serve, orcad, managed SSH,
browser bridge) and the orca CLI now use E2EE v2 framing for hosts that
support it, and fall back to the legacy framing for hosts that do not.

- One-shot requests try v2 first. A host that refuses the v2 hello
  (hosts from before v2) or refuses capabilities on v2 token auth gets
  one transparent legacy redial; nothing but the handshake is sent before
  authentication, so the redial is safe.
- After a v2 sign-in succeeds, the host's pinned key is remembered in the
  profile (shared by the app and the CLI). Every connection to that host,
  including long-lived sockets, then uses v2 and never falls back.
- Long-lived sockets keep legacy framing until a host has proven v2, so
  they never see an older host refuse a v2 hello.
- Hosts accept clientCapabilities on direct v2 token auth, so desktop and
  CLI clients keep their capability negotiation on v2. Relay token auth
  stays exact.

* feat(remote-runtime): recover a latched host that was downgraded, without a legacy downgrade path

A host this profile had signed in to over v2 was refused for good if it
was later downgraded below capability-carrying v2 token auth. Hosts now
advertise pairing.e2ee-v2-token-capabilities.v1. When a latched host
refuses v2, a one-shot request asks the host over legacy framing (keyed
to its pinned key, so only the real host can answer) for status.get:

- no capability: the host itself says it was downgraded; the latch is
  dropped and the request goes ahead over legacy;
- capability present, or no answer: the request fails with an error
  that says to update the host or check the network path. Only the
  read-only status check ever ran over legacy.

A refusal faked on the path cannot produce the host's answer, so it
cannot force legacy framing for a latched host.
2026-11-06 17:14:56 -08:00