Commit Graph
19803 Commits
Author SHA1 Message Date
b07b0432a4 fix(cursor): write workspace trust where cursor-agent reads it (#38807)
* fix(cursor): write workspace trust where cursor-agent reads it

cursor-agent names ~/.cursor/projects/<dir> by replacing every
non-alphanumeric character with '-', collapsing repeats, and trimming
dashes. Orca only replaced Windows-illegal characters, so paths with
'_', '.', spaces or non-ASCII got a marker cursor-agent never reads and
the trust menu appeared on every fresh worktree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(cursor): cover space, non-ASCII and Windows paths in the trust slug test

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
2026-11-07 09:09:52 -05:00
OrcaWinandOrcaWin 3c4990dc03 test: remove 263 low-value tests (#39504)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 06:07:51 -08:00
OrcaWinandOrcaWin bd68461280 test: remove 264 low-value tests (#39500)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 05:56:06 -08:00
OrcaWinandOrcaWin c39a1b3627 test: remove 665 low-value tests (#39498)
* test: remove 262 low-value tests

* test: remove 665 low-value tests

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 05:43:22 -08:00
Kelvin Amoaba 7234301afb fix(mobile): finish Android dictation on a call, alarm or leaving the app (#39492)
* fix(mobile): finish Android dictation on a call, alarm or leaving the app

A transient audio-focus loss (call, alarm, assistant) left the mic recording
silence, and pausing the activity closed the mic only to reopen it on resume,
splicing a silent gap into the dictation. Both now end the recording and emit
an interruption, so dictation finishes and inserts what was heard. The
dictation hook also finishes when the app goes to the background, which
covers iOS and shells without this native change.

* fix(mobile): keep a dictation that is waiting on the Android mic prompt

* fix(mobile): keep Android recording state consistent across the focus and JS threads

* refactor(mobile): name the Android pause path for what it does and stop retaking focus on resume

* fix(mobile): keep what the open mic heard when leaving during a pending host start

* fix(mobile): close the open mic at once when leaving during a pending host start

* fix(mobile): a second page capture end waits for the stop already in flight
2026-11-07 13:30:50 +00:00
Kelvin Amoaba b9832c2106 fix(mobile): show the phone speech download size only for English (#39496) 2026-11-07 13:19:23 +00:00
OrcaWinandOrcaWin 5fc5aa435e test: remove 295 low-value tests (#39494)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 05:10:40 -08:00
Kelvin Amoaba 3501cd2f1c fix(mobile): keep on-device speech text revisions rising across sessions on iOS (#39481) 2026-11-07 12:53:36 +00:00
OrcaWinandOrcaWin 274b3e359f test: remove 65 low-value tests (#39491)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 04:51:05 -08:00
Kelvin Amoaba 5dae65c4b4 fix(mobile): treat a slow phone speech service as busy, not unsupported (#39489) 2026-11-07 12:36:51 +00:00
OrcaWinandOrcaWin 3ca9cb8bc2 test: remove 242 low-value tests (#39487)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 04:36:43 -08:00
OrcaWinandOrcaWin cecfa9865d test: remove 158 low-value tests (#39483)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 04:18:13 -08:00
Neil 27a724e303 refactor(backend): import defining owners and extract ACP startup (#39417)
* refactor(backend): use defining owners for orchestration and ACP startup

* test(orchestration): trim redundant observations and retain safety cases

* test(orchestration): seed restored sessions with one fixed operation clock
2026-11-07 04:15:38 -08:00
Kelvin Amoaba 9ea9ea9a19 fix(mobile): show the phone speech download size and drop a cancelled session's late text (#39479)
* fix(mobile): show the phone speech download size and drop a cancelled session's late text

* fix(mobile): show the Android language download size too

* fix(mobile): keep a recognizer error raised while its start resolves, and read the download size aloud
2026-11-07 12:07:17 +00:00
OrcaWinandOrcaWin c8ed5c6be4 test: remove 295 low-value tests (#39480)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 04:03:51 -08:00
Neil 09722a6cf2 feat(antigravity): run Full access chats on the host's agy with --dangerously-skip-permissions (#39471)
agy has no Full access session mode, so Full access chats always fell back to
Orca's managed runtime, which kept most people off the host's agy (and off
Intel Macs, where only the host can run it). agy 1.5.2+ `agy acp` accepts
--dangerously-skip-permissions, which approves tool requests but not plans.

Host chats now launch with that flag only in Full access, in agy's default
mode. Switching permission mid-chat already restarts the ACP process and
resumes the session, so the flag follows the chat's mode. The flag never
approves plans, and Orca still leaves agy's requests to the person, so plan
approvals keep surfacing.

The cached readiness check launches with the flag, so a build that rejects it
keeps chats on Orca's runtime without an extra spawn; such a binary is not
checked again until it changes. Because ask and Full access both run agy's
default mode, the reported mode is read per launch, so a Full access chat
does not show as Ask.

Refs #39006, #33188
2026-11-07 03:58:51 -08:00
Neil c0e8e4e6eb docs(plugins): theme background video ships in 1.4.254 (#39478)
#39450 merged after the 1.4.253 cut, so the videoPath since-version and the
theme reference name 1.4.254.
2026-11-07 03:49:08 -08:00
Neil b0dd73e7aa feat(plugins): play a looping video behind app themes (#39450)
App themes may set background.videoPath: a muted, looping MP4 or WebM (H.264
recommended, VP9 or AV1; one video track, no audio; <= 60 s, 8 MB, 2.3 MP)
played over the required static background.path. Main checks it from container
headers without decoding and serves it on the orca-plugin-image slot
theme-<i>-video; images stay static-only. The renderer reveals it on its first
frame, keeps the still on any failure or a decoded size past the limits, plays
it only while main reports the window focused, shown and not minimized and no
dialog is open, and omits it under prefers-reduced-motion.

Animated WebP was measured and declined: software-decoded every frame, it cost
11-23 points of CPU vs 3-10 for the same loop as video.

Implements #38363 proposed by @dohaidang.
2026-11-07 03:32:14 -08:00
Neil 23808bb73f refactor(renderer): organize host and terminal owners and remove forwarding shells (#39320)
* refactor(renderer): organize host and terminal implementation owners

* fix(refactor): align active adoption reliability references

* refactor(terminal): remove forwarding shells and stale mocks

* fix(renderer): consolidate direct owner imports

* fix(refactor): route incoming issue trust type to its owner

* test(runtime): give independent status viewers separate pairing tickets

* style(refactor): normalize rebased terminal mock formatting
2026-11-07 03:31:13 -08:00
Neil aa3cf3b027 refactor(native-chat): tidy the rail wake hook and cover it with tests (#39477)
Store absolute deadlines instead of two last-seen timestamps, and let
scroll events with no wake pending return before reading the clock.
Behaviour is unchanged.
2026-11-07 11:27:47 +00:00
Kelvin Amoaba 2d79ec271c fix(mobile): report a slow Android speech service as busy, not unsupported (#39476)
* fix(mobile): report a slow Android speech service as busy, not unsupported

* fix(mobile): replace only the speech recognizer the service disconnected
2026-11-07 11:23:06 +00:00
OrcaWinandOrcaWin a523f1d4c5 test: remove 32 low-value shared helper tests (#39475)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 03:20:35 -08:00
0173de9b52 fix(plugins): don't count time asleep as worker idle time (#28299)
* fix(plugins): don't count time asleep as worker idle time

The idle reaper measured idleness with the wall clock, so after a sleep longer than the reap window its first sweep reaped every worker before their own timers could fire. A sweep gap well past the 60s interval now starts a fresh idle window.

* fix(plugins): count a sleep before the first idle sweep as asleep, not idle

Start the reaper's sleep-detection clock when the first worker starts, so the
first sweep after waking can see the gap even if no sweep ran before the lid
closed.

* fix(plugins): keep worker manager under max-lines and restore real timers after sleep tests

Move the idle-candidate filter into PluginWorkerIdleClock so the rebased manager
stays within the 300-line lint cap, and reset fake timers after the idle-reap
tests so the sleep-before-first-sweep case does not leak them.

---------

Co-authored-by: petersindex <287557875+petersindex@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
2026-11-07 03:19:46 -08:00
NeilandJinwoo-H e7b0e4029e fix(antigravity): say why a downloaded chat runtime failed its start check (#39456)
The managed-runtime install message now names the observed cause after the
existing headline: a timeout, an exit code with a redacted stderr excerpt, or
the version the server answered as. The host agy check that shares the
initialize helper is unchanged.

Takes over #34167 by @Jinwoo-H (away), ported onto main after #39006.

Co-authored-by: Jinwoo-H <73622457+Jinwoo-H@users.noreply.github.com>
2026-11-07 03:17:56 -08:00
NeilandCopilot 8ceea00464 perf(terminal): stop painting busy TUI frames twice on non-Windows DOM terminals (#39462)
Live foreground output with background colors or in-place rewrites
requested a synchronous xterm row repair after every write, on top of
the dirty-row frame xterm had already queued while parsing. Busy
OpenCode frames all carry background SGR, so DOM panes painted each
frame twice.

The synchronous repair exists for Windows ConPTY DOM rendering. Keep it
there and let other platforms merge the repair into xterm's queued
frame. Replay and snapshot refresh policy is unchanged.

Drop tests that only asserted the private synchronous refresh call.

Fixes #22458

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-07 03:16:44 -08:00
BingZandNeil a93741a901 fix(plugins): surface reserved-identity install errors for local forks (#12606)
* fix(plugins): surface reserved-identity install errors for local forks

Official template forks keep stablyai/orca-* identities that correctly
cannot install from a local path, but the UI swallowed the reason as a
generic failure. Keep the security block and show actionable rename
guidance in the install dialog (#12598).

* test(plugins): mock i18n for reserved-identity error presentation

* fix(plugins): match reserved-identity errors before git heuristic

Production trust strings mention github.com; the broad /(git|...)/ check
matched the "git" substring inside "github" and mis-surfaced reserved
fork installs as fetch failures. Prefer reserved-identity matching and
lock presentation tests to the full pluginInstallTrustError strings.

* fix(plugins): map the current reserved-name install refusal to rename guidance

Main now refuses reserved plugin keys from every non-official source with
"<key> uses a name reserved for official Orca plugins; ...", so the
author's matcher on the old "reserved plugin identity" string never fired
and forks of official templates still saw the generic install failure.
Match the current string (before the Git heuristic), use one message that
tells the user to rename id/publisher, and register the English key.

Refs #12598

---------

Co-authored-by: Neil <neil@stably.ai>
2026-11-07 03:07:37 -08:00
Pr1pandNeil 3585a38b72 fix(plugins): resolve workspace context for remote active workspaces (#38671)
* fix(plugins): resolve the active workspace context on remote hosts

* fix(plugins): scope the remote workspace context to its host

* docs(plugins): document the remote context resolver

* fix(plugins): keep remote context ids raw and never fall back for local rows

The stored-row fallback returned host-qualified ids (ssh:host|repo::path), which no
terminal selector or agent-status row matches, so agents.list stayed empty for the
remote workspace. It also answered for a removed local worktree, turning a stale
focus that used to read null into a context for a workspace that no longer exists.

* fix(plugins): resolve a focused paired-server workspace from the desktop's server rows

A paired orcad server's workspaces live in that server's store, so neither the local
catalog nor the desktop's stored rows can name one and workspace.readContext,
workspace.changed and agents.list saw no context. The runtime now asks the relay host
catalog, which answers from the worktree.ps rows the desktop already caches. Only a
miss on a reachable server fetches, bounded at 1.5 s and at most once per 10 s per
missing workspace; an unreachable or hung server answers null.

* fix(plugins): keep a stale local focus stamp resolving as before, and cover #38653 end to end

A focus stamped 'local' whose repo row now routes elsewhere resolved through the
unscoped selector before #38653; the host-scoped lookup turned it into null. A
local stamp now retries unscoped, so local and unstamped focus answers exactly
what main did. Remote stamps keep the scoped lookup, so a paired-server focus
never borrows a local twin's context.

Tests: real-git parity of local, folder and SSH contexts against the pre-change
selector answer for every session shape the renderer writes; panel polling
against a hung or failing server (one fetch, one bounded wait per 10 s window);
an e2e that pairs a desktop with a headless Orca server, clicks a local and a
server row, reads workspace.readContext from a plugin panel, and keeps polling
fast after the server goes away.

---------

Co-authored-by: Neil <neil@stably.ai>
2026-11-07 03:04:32 -08:00
Neil 35975c0580 feat(themes): theme tokens for chat text styling and a readable chat selection (#39432)
* feat(themes): public plugin theme tokens for chat text and selection

Themes can now set chat bold text, muted text, inline code, code blocks and
the chat selection. Omitted tokens paint exactly what chat painted before,
except the selection, which now keeps selected text 4.5:1 by default.

* docs(themes): note the bubble and code-block checks for chat text tokens

* fix(themes): never lower the chat selection under its visible floor
2026-11-07 03:02:23 -08:00
OrcaWinandOrcaWin 07e55b91f7 refactor(renderer): spell out logical assignments React Compiler can't lower yet (#39339)
React Compiler skips any function containing `??=`, `||=` or `&&=`. Rewrite
the statement-position ones whose target re-reads without side effects
(identifiers and plain member chains) as the equivalent `if`:

  a ??= b  ->  if (a == null) { a = b }
  a ||= b  ->  if (!a) { a = b }
  a &&= b  ->  if (a) { a = b }

21 files; 25 fewer bailouts and 12 more compiled functions in the
compiler-compat baseline.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 02:59:48 -08:00
cb3f367b33 fix(plugins): isolate development watcher retries by root (#38289)
* fix(plugins): isolate development watcher retries by root

* test(plugins): keep coverage for late binding checks after housekeeping disposal

The per-root rewrite replaced the old housekeeping unit tests; restore the
disposal/coalescing case so a slow check that resolves after dispose cannot
restart a watcher or refresh, and per-root checks do not stack.

* fix(plugins): skip the full plugin rediscovery while a dev folder retry keeps failing

A maintenance retry that subscribes already refreshes itself; one that keeps failing (an
unreachable WSL share) rediscovered every plugin each tick. Only a changed root binding needs
discovery now.

Also covers what the per-root rewrite must keep: adding/removing a folder leaves the others'
watchers and frame revisions alone and releases its subscriptions, a rejecting registration
retries once per tick, Linux sibling folders keep separate parent watches, and an Electron e2e
where deleting/recreating/removing one dev folder never reloads another folder's open panel.

---------

Co-authored-by: be0hhh <182023099+be0hhh@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
2026-11-07 02:58:29 -08:00
Agustin Varela b62351f9ce fix(plugins): forward sidebar and zoom shortcuts from plugin frames (#37939)
A focused plugin frame resolved Mod+B/Mod+L to the sidebar toggles and
Mod+=/-/0 to zoom, but the guest forwarder had no sidebar branch and
dropped zoom for non-page guests, so the plugin kept the keys.
2026-11-07 02:57:26 -08:00
OrcaWinandOrcaWin 67c9d04ee4 test: remove 131 low-value terminal, session and transport tests (#39460)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 02:55:40 -08:00
Neil 068d9ad3fd fix(plugins): keep a workspace-scoped panel edit made just before a workspace switch (#39413)
* fix(plugins): keep a workspace-scoped panel edit made just before a workspace switch

The guest's persist queue holds atoms, not values, and the renderer stored each
ui.persist under whichever workspace was active when it arrived. An edit made
less than 0.4 s before a switch was flushed after the new workspace's hydrate,
so workspace B's value was written under B and A's edit was lost.

The host now names each ui.hydrate; the guest flushes pending writes before
applying the next hydrate and tags ui.persist with the hydration its values came
from, and the renderer stores the write under that hydration's workspace.
(STA-13316)

* test(plugins): cover workspace-persist hydration routing edge cases and add switch e2e

Adds unit coverage for A->B->A routing, legacy (no hydration) persists, the eight-hydration window, plugin-scope entries, and guest flush/tagging; adds an Electron e2e that types in workspace A, switches inside the persist debounce, and checks both workspaces after switching back and after the panel's guest is recreated. Regenerates orca-testing.mjs after rebasing on main.
2026-11-07 02:50:30 -08:00
Neil 186b18e2b9 fix(plugins): stop a late replacing command from repeating the built-in action (#39407)
* fix(plugins): stop a late replacing command from repeating the built-in action

The renderer ran Orca's own action after 2 s but the still-running replacing
command could then call commands.run for the same action, doing it twice.
Main now owns the 2 s cutoff: it rejects at the deadline (the renderer falls
back on that answer) and from then refuses the late handler's commands.run of
the replaced action; a handler that already ran the action is not followed by a
fallback. The deadline now starts when the renderer asked, not after plugins
load. The renderer's own timer is only a safety net. (STA-13530)

* test(plugins): cover replacement races and verify the sidebar toggles once end to end

A handler's commands.run now counts for the oldest in-flight press only, so a second
concurrent press whose handler fails still gets Orca's fallback. Adds unit cases for a
throwing/crashed handler, two presses racing, and a press after a late handler returns,
plus an Electron e2e spec driving fast, late (2.1 s), throwing and no-op replacements of
sidebar.left.toggle.
2026-11-07 02:50:17 -08:00
Neil 9ef524f973 fix(plugins): stop terminal inventories for agent status events nobody hears (#39383)
* fix(plugins): stop terminal inventories for agent status events nobody hears

Each agent.status.changed event for plugins lists the workspace's terminals,
which refreshes every PTY provider and host. Interest was only checked when an
event was admitted, so after the last panel closed the queued backlog kept
running full inventories with no one to deliver to.

Recheck interest before each lookup and drop the backlog once nobody listens,
and let events queued behind a slow lookup share one listing per workspace
while keeping arrival order. (STA-13319)

* fix(plugins): keep the agent status queue moving past a throwing delivery

A synchronous throw from one emitEvent dropped the rest of its batch and left
later queued events waiting for the next arrival. Catch per delivery, and cover
a failed listing, a 1000-event storm, a panel reopening mid-lookup, and several
panels on the real bridge; the panel e2e now checks a burst arrives in order.
(STA-13319)
2026-11-07 02:50:04 -08:00
OrcaWinandOrcaWin 153d6d000c test: remove 18 low-value session tests (#39459)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 02:44:40 -08:00
Neil 55f353f4cc fix(ssh): keep old relay channels off the host's own SSH connection (#39435)
* fix(ssh): keep old relay channels off the host's own SSH connection

Each old relay still running a shell held one exec session on the target's
connection. At sshd's MaxSessions (default 10) every later exec failed, so the
host stuck at Connecting with 'Could not detect the remote platform: (SSH)
Channel open failure: open failed'.

* test: say why the session-limit repro needs a longer timeout

* test: note why the relay channel fakes are cast

* test: move the many-relays repro into the existing legacy relay bridge suite
2026-11-07 02:40:00 -08:00
OrcaWinandOrcaWin f6874cc512 refactor(renderer): make memo invalidators and layout flushes compiler-safe (#39414)
React Compiler drops bare `void x;` reads, narrows callback deps to the fields
read, and oxc 0.152 emits `a[q.head++]` as a prefix update. Rewrite those
sites so they behave the same with the compiler on, and identically to today
with it off:

- `void tick` memo invalidators -> `recomputeOn([tick], () => ...)`
- `void el.offsetWidth` transition resets -> `forceLayoutReflow(el)`
- pty termination queue reads, then advances, the head index
- host agent preference subscription takes the whole subscription object

Prunes the compiler-compat hazard baseline from 40 to 2 entries.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 02:37:53 -08:00
Neil b1221ed985 fix(antigravity): pick the host's agy only when its sign-in serves sessions (#39452)
A keychain item for agy does not prove agy can sign in silently: agy acp then
answers every session request with "Authentication required", and Orca never
authenticates the host (oauth-personal opens a browser). The host check now
also lists sessions after initialize (which writes no conversation, unlike
session/new), so a signed-out agy keeps new chats on Orca's runtime. Any
answer except an incompatible binary is rechecked after 5 minutes so a lapsed
or restored sign-in is noticed. agy settings that name a modelProvider select
API-key auth, whose key host launches drop, so they keep chats off the host.

Refs #39006
2026-11-07 02:26:11 -08:00
Neil ee04233cf2 feat(pairing): show which devices still sign in with their original pairing code (#38949)
* feat(pairing): show which devices still sign in with their original pairing code

Settings lists paired phones and access links that signed in with a pairing
code but never exchanged it (apps from before single-use pairing) with
"Uses an older pairing method. Update ...". Display only; rows from older
builds are never flagged.

* fix(pairing): no update hint for links used by plain-http browsers or still pairing

A link that served a session-only browser key is marked, so the hint stays
off after a host restart drops those keys. Codes still inside the pairing
window are not flagged either: an updated client exchanges within moments.
2026-11-07 02:17:33 -08:00
OrcaWinandOrcaWin 92ef9440db test: remove 221 low-value cloud, mobile and journal tests (#39449)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 02:12:41 -08:00
Neil 51f3c956ed feat(plugins): let plugins ship web fonts for the terminal, editor and interface (#39416)
* feat(plugins): let plugins contribute web fonts to the font pickers

Plugins declare font families under contributes.fonts (WOFF/WOFF2 only).
Install checks each file's signature against its extension and caps file
size, family count and plugin total; main never parses a font. Files are
served over the plugin image scheme only while the plugin is enabled,
typed and nosniff. The renderer registers each family under a name that
carries the plugin key, so a plugin font cannot shadow an installed or
built-in font, and it applies only once the user picks it. Disabling or
uninstalling removes the faces; uninstalling also resets font settings
that named them.

Refs #38607

* fix(plugins): harden plugin fonts and re-measure editors when they load

- Refuse WOFF/WOFF2-wrapped font collections by checking the flavor bytes.
- Check dev folders' font files at discovery, not only at install.
- Re-check family, weight and style from the plugin list in the renderer.
- Track loaded families (case-insensitively) from document font loads, so
  the code editor re-measures and terminals, previews, the SSH terminal and
  the dashboard popout re-apply only when their own font changes.
- Register plugin fonts in the dashboard popout window.
- Give dev-folder font URLs their change count so edits reload.
- Keep monospace fallbacks unless the chosen family is exactly that font.

* fix(terminal): keep every fallback only for plugin font families

System font choices keep their existing fallback list unchanged.

* fix(plugins): leave the dashboard popout's plugin list alone; add the font row string

Registering fonts there started the plugin auto-update watcher in a window with no toaster, which could consume update notices. Adds the new contribution-row string to the English catalog and the fonts list to the RPC test manifest.
2026-11-07 02:08:35 -08:00
OrcaWinandOrcaWin a89cdae5dc build(renderer): fail compiler-compat baseline shrinks only in touched files (#39440)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 01:59:33 -08:00
Jinjing 76182c1cf5 Use Cmd+K for search on new Mac profiles (#38884)
* Use Cmd+K for search on new Mac profiles

Preserve existing search and terminal clear shortcuts during migration
on desktop and web.

* Preserve legacy Mac shortcuts during web profile migration

* Preserve keybinding resets across profiles and platforms

* Preserve legacy shortcuts and markdown link bindings

* Separate profile shortcut defaults from shared overrides

* Check shortcut conflicts when restoring defaults

* Fix tab shortcuts targeting floating workspace panels
2026-11-07 01:58:17 -08:00
Neil aed52aaa9b perf: stop host-status pings rebuilding title catalog and rereading server config (#39340)
* perf: stop host-status pings rebuilding the title catalog and rereading server config

Host-status updates walked every saved tab for title-refresh support before checking whether any host's support changed, and remote RPC/tunnel/worker checks reread, rehardened and reparsed the saved-server registry files on every call. Gate the title walk on an actual per-host capability flip, and reuse the merged registry read while a stat signature of its three files is unchanged.

* perf: invalidate registry read cache on in-process writes

Coarse-timestamp filesystems can reuse an inode within one tick, so a same-size rewrite could slip past the stat signature; writers in this process now bump a generation that is part of the signature.

* perf: key the registry read cache on file bytes, not stat metadata

A stat signature can miss a same-size rewrite on coarse-timestamp filesystems or a reused inode. Comparing the files' exact bytes (plus mode/ctime and the directory mode, which the uncached read re-hardens) means a hit can never serve data that differs from disk, from any writer.

* perf: only reuse a registry read once hardening holds and the path is unchanged

Reuse now requires the files' permissions to already be restricted (POSIX), so a transient chmod failure is retried on the next read as before; Windows hits keep the ACL verify-and-retry. Snapshots also record each path entry's identity, so a symlink re-pointed and restored mid-read cannot pin the value read through the other target.

* perf: build the cached registry value from the exact bytes it is keyed on

The value was computed by a second, independent read, so a directory or symlink swapped and restored around it could pin data the key's bytes never held. Each reader is split into read + parse-text, and on a miss the cache hardens, snapshots once, and parses that snapshot. Reuse also now requires the exact 0600/0700 modes the readers set, so an incomplete owner mode is repaired as before.

* perf: require the full hardened mode, including special bits, before reusing a registry read

* perf: keep Windows on the plain registry reader

Measured on a Windows host: a cache hit still has to re-verify ACLs, so it cost as much as the read it skipped (0.37 ms vs 0.33 ms). Windows now always uses the original reader, keeping its behavior byte-for-byte unchanged.
2026-11-07 09:56:47 +00:00
a147277d75 perf(daemon): cache Linux CLK_TCK instead of forking getconf per read (#39439)
* perf(daemon): cache Linux CLK_TCK instead of forking getconf per start-time read

CLK_TCK is fixed for the kernel's lifetime, so the daemon identity check
no longer runs a synchronous getconf process on every read.

* fix(daemon): retry invalid Linux clock tick reads

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-07 01:54:37 -08:00
Kelvin Amoaba 1283e070e3 feat(mobile): transcribe dictation on iPhone with Apple's on-device speech model (#39410)
* feat(mobile): transcribe dictation on device with SpeechTranscriber on iOS 26

* fix(mobile): fall back to the dictation model, reserve locales and stop a finishing session on cancel

* fix(mobile): resolve on-device speech locales deterministically and report the simulator unsupported

* refactor(mobile): simplify the on-device speech engine and skip conversion when formats match
2026-11-07 09:51:50 +00:00
Neil e1379b34f3 feat(pairing): Add server and orca environment add exchange the link for their own token (#38948)
* feat(pairing): Add server and orca environment add exchange the link for their own token

After verifying the host, Add server (and repair) swap the access link's
token for one generated on this computer when the host advertises
pairing.ticket-exchange.v1, and save that instead. orca environment add does
the same with a short best-effort probe. Any failure saves the link as today;
the host keeps accepting it until the new token is used.

* test(pairing): Add server and CLI leave links unchanged for a released host

* fix(pairing): Add server and orca environment add sign in once after exchanging, and the CLI rejects a refused code

After exchanging a link, sign in once with the new token so the host
retires the link right away instead of at the first later use; a host
downgraded in between would not know the new token.

orca environment add no longer saves a pairing code the host refuses
(for example one another device already used); it asks for a new code.
2026-11-07 01:48:16 -08:00
Neil 4d8d355fd1 fix(setup-trust): remember up to 20 approved setup scripts per repo (#39436)
Hosts now trim a longer approved-hash list instead of refusing the create, so a
future client with a bigger list still works against this host.
2026-11-07 01:39:32 -08:00
Kelvin Amoaba ffaf887e78 feat(mobile): transcribe dictation on the phone, with the computer as fallback (#39386)
* feat(mobile): define the on-device speech contract for the native audio module and page bridge

* feat(mobile): dictate on the phone first and replay to the computer when the phone fails

* refactor(mobile): type the on-device speech module without a cast

* fix(mobile): point dictation's finish ref at the committed callback

* test(mobile): wait on the takeover request instead of a fixed sleep

* fix(mobile): release each dictation request's own share of a replayed backlog

* fix(mobile): let the computer's text replace the phone's after a fallback
2026-11-07 09:37:45 +00:00