* fix(computer-use): scroll, expand and set sliders on Windows without raising the window
* fix(computer-use): wait for Windows scroll and slider writes to settle before verifying
* fix(computer-use): reject NaN for Windows slider set-value
* test(computer-use): wait on the Windows fixture state with vi.waitFor and a schema
* test(computer-use): check activation per action against a holder window in the Windows fixture
* test(computer-use): log fixture window events for activation failures
* fix(computer-use): report foreground when a Windows app raises itself for a UI Automation action
WPF activates its own window for Scroll, ExpandCollapse, RangeValue and SelectionItem calls from any UIA client, so the runtime now compares the foreground window before and after a pattern action instead of assuming background. The Windows e2e checks delivery against the fixture's own activation count, with a holder window in another process.
* test(computer-use): skip an unstarted holder when closing the Windows fixture
* fix(computer-use): bound Windows pattern scroll paging and tighten slider read-back
* fix(computer-use): cap Windows slider read-back tolerance and run the UIA e2e only on CI
* fix(tabs): a new tab in a workspace whose layout outlived its groups becomes the layout (was invisible: empty strip, 0-size pane until a workspace switch)
* test(tabs): fixture for a new tab in a workspace whose layout outlived its groups
* feat(dictation): optional AI cleanup of dictated text, with a correction word
Off by default. When on, a dictation's text goes through the user's agent
CLI (the AI text actions' runner, Haiku by default for Claude) before it
lands: the pill says "Cleaning up…" and the text is inserted once. Failure
or a 10 s timeout inserts it as heard with a warning; the pill's X skips
cleanup. A consent dialog asks before text first goes to an agent. The
correction word ("scratch that") survives filler removal for cleanup to act
on. The microphone test gets "Try cleanup", and phone dictation the computer
transcribes is cleaned on the host.
* fix(dictation): keep finals that arrive during cleanup and tighten cleanup edges
Nemotron 3.5 was cut at Silero pauses and decoded per phrase like an
offline model, so it showed no text until a pause, paid a decode per
pause, and lost context across cuts. A model that reports streaming now
gets every chunk fed into one transcribe-cpp stream. Its text shows as
it grows and is committed when the speaker goes quiet, with coverage set
inside the quiet so a CPU replay after a GPU crash starts clear of words
already posted, and at stop. Past 20 s uncommitted the stream restarts
at the next pause Silero hears (25 s at the latest), keeping the CPU
fallback's backlog bounded. A second dictation started beside a live
one stays pause-cut and decodes only to commit, since the model serves
one stream at a time. Offline models are unchanged.
* test(speech): cover the recognizer's span commits, coverage and cancel with a fake transcribe-cpp
* test(speech): share one typed fake VAD stream between the segmenter and recognizer tests
* fix(native-chat): let a chat continue on the account you switch to after a usage limit
A usage-limit reset belongs to the account that hit it. After a switch the
host kept holding the chat until the old account's reset, and desktop and
phone hid Continue until then, so Switch Account on the card did nothing.
The host now releases the hold once the chat would start on another
account, letting only that account's own reading hold it, and publishes the
earlier continue time that both clients read.
* fix(native-chat): save the account a usage limit hit, per cut
The fallback to the chat's founding account could report a switch that
never happened for a chat that had already moved, releasing it before the
new account's reset. Save the cut's account while the child that ran it is
live, use only that, and key the switch time by the cut it belongs to.
* fix(native-chat): record the account each chat runtime launched on
record.accountHome names only the founding account, so after a switch
nothing said which account a usage limit hit. Owner proof now records the
account each runtime fence launched under, every host cut carries its
turn's fence, and the hold reads the cut's account from that pair. This
replaces the sweep's saved copy, which a fast child exit could miss.
Spending the new account showed before a switch now holds the chat until
its own reset; only a reading taken after the switch releases it.
* fix(native-chat): restart the switch time when the chat moves to yet another account
A second switch for the same cut kept the first switch's time, so a reading
of the newer account taken before it was chosen could release the chat.
* fix(browser): keep guest input bound to its webContents
* test(browser): reject unresolved guest input routes
* test(browser): keep text on the guest when the root frame probe fails
* fix(browser): insert guest text only into a confirmed focused frame
Electron's webContents.insertText crashes the guest renderer and never
settles when no local frame holds focus (a fresh tab, or focus in a
cross-site frame after a root probe timeout). Use it only when the focus
probe confirms a focused element or same-site frame, refuse otherwise,
and reject promptly if the renderer dies or stops answering.
* test(browser): explain the busy-page e2e timeout
* fix(browser): expire guest text edits at the renderer mutation boundary
* fix(browser): preserve focused local frame contexts for text edits
The agent already has full thread data from selectedCommentGroups. Report
only the host-resolvable thread count in the human-readable section to
avoid duplicating thread bodies in the JSON payload.
* fix(computer): verify macOS type-text and paste-text sent as keys by reading the field back
When text can't be written through AXValue (Chromium/Electron fields, fields
that refuse the write), type-text and paste-text send keys or Cmd+V and always
reported unverified. Now the helper predicts the focused field's value from its
value and selection before sending, then reads it back until it settles:
verified on a match, unverified (text_mismatch) otherwise. Secure fields and
fields without a readable value and selection stay unverified as before, and
the result never repeats the typed text or the field's contents.
* fix(computer): keep the caret put after a refused macOS text write and skip unprovable readbacks
A refused AX value write no longer moves the caret before falling back to keys, so the keys and the prediction both use the user's selection. Text with control characters, a value the field already holds, and a field still filling at the 2 s cap stay unverified rather than verified or text_mismatch. The quiet window starts after the first read answers.
* fix(computer): bound macOS text readback size and say a mismatch can mean keys went elsewhere
* fix(computer): treat a macOS text readback past the cap as undetermined
Selection checked only the account's identity file, so an account with
.claude.json intact but no usable login in its Keychain item or
credentials file passed, and every chat that follows the selection failed
its next start as signed out. Select now makes the same credential read
the usage meter makes for the account; an unreadable store still allows
the switch.
* fix(computer): refuse quit, log out and lock shortcuts unless explicitly allowed
* fix(computer): close Linux keysym bypasses in the system shortcut guard
* fix(computer): refuse Linux keycode, L1/L2 and VT-switch keysym bypasses
* fix(computer): catch control characters in Linux keycode tokens and point recovery at the stated effect
* feat(computer): show where snapshots were cut and read one element's subtree
* fix(computer): validate subtree targets against the fresh walk and keep scope for focused input
* fix(computer): return whole-window action results after subtree reads
* fix(computer): count kept records toward the macOS limit and index subtree reads against the latest cache
* fix(computer): index Linux/Windows subtree reads against the snapshot they started from
Capture the terminal screen, output position and unfinished parser state together on the existing output queue so restored output continues at the correct byte. Retire reconstructed partial escape state on Reset.
Tracked in #34435 and STA-12466.
Co-authored-by: liaoxingyu <3114147163@qq.com>
* perf(renderer): paint modal backdrops, sticky headers and pane overlays solid instead of blurring
Dialogs, palettes and sheets blurred the whole workspace, and sticky headers,
pinned bars, the mobile-driver scrim and markdown table controls re-blurred
whatever scrolled or changed beneath them. The workspace now stays sharp under
the existing dim with a solid dialog panel at today's color, and each sticky or
pinned bar paints the opaque equivalent of its tint over the surface it sits on.
Reduce Visual Effects keeps its behavior; the CSS-value-only blur e2e spec is
removed and its onboarding recovery test moves to the onboarding spec.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(fixtures): describe the sheet fixture's dimmed, unblurred workspace
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* perf(renderer): narrow to the mobile-driver overlay; keep every other blur as on main
Brennan 11-12 kept modal blur, and only the mobile-driver overlay met its
measurement rule. Restore every other surface, the e2e blur spec and the
fixture copy to the synced base.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(skills): stop calling another Orca build's skill copy out of date
Every Orca build on a host (the installed app, dev builds, the CLI, a paired
server) shares one skills folder, and each one auto-updates it to the text it
ships. A build only recognises SKILL.md text from itself or older releases, so
a copy a newer build (or a dev build) wrote looked like a user edit: the
nudge said "An installed Orca skill is out of date" and Update offered to
replace it with older text.
Whenever Orca writes a skill it now leaves a marker,
~/.agents/.orca-skill-digests/<skill>/<sha256>, on the disk of the host that
plans. A copy whose bytes match a marker plans as leave 'other-build': it
reads as current, is never nudged, and silent update leaves it alone. A user
edit changes the bytes, so it is still asked about. A paired server plans and
records on its own disk, so the client never compares hosts.
* fix(skills): mark copies already at this build's digest so other builds see them as Orca's
A copy that already equals this build's bundle plans keep-only, so no write
ever recorded its marker, and copies written before the marker existed stayed
'edited' to any other build. Executing a plan now records the marker whenever
a location holds this build's bytes, and the silent update records it for
keep-only entries. The startup scan asks the host (this machine or a paired
server) once per session to run that keep-only update, so an already-current
build marks its copy on its first run. Preview stays read-only.
* chore(skills): drop unreachable other-build setup copy and document touched planners
'other-build' leaves are always replaceable, so the non-replaceable setup
attention lookup never selects one; it now shares the generic fallback and its
dedicated string is removed. Add short docstrings to the touched planning,
execution and copy functions.
* fix(skills): retry the startup marker when the host did not record it
A marking-only call kept its session mark even when the host never ran the
recording, so a failed or busy call left the copy unmarked for the rest of the
session. Release the mark when the call rejects, another update held the
target, or the host reports the skill busy or changed, so the next plan
refresh asks again. A host without silent update keeps its mark, avoiding a
call per scan.
* fix(skills): include Codex session's P2 fixes; warn only when a marker call may have written
Includes two P2 review fixes from a Codex session in this worktree:
- A newly selected agent links to a recognized other-build shared copy
instead of being left as shared-not-current, and execution re-checks that
shared copy so the dependent link is skipped if it changed after planning.
- Installed-skill views refresh after every silent-update call, since a
marking-only call re-plans on the host and can still update a copy.
A rejected marking-only call now shows the uncertain-outcome warning only
when the request reached a paired host and its reply was lost. A refusal
before sending, or the host's own error reply, cannot hide a write: the mark
is released for retry without a warning. Calls that started real updates
keep warning on any rejection. Restores the docstrings removed in that
session.
* fix(skills): stop retrying a failed skill marker on every plan refresh
Every marker call ends in a plan refresh, and a refresh re-scans. Freeing
the mark after a busy or failed call made each refresh ask again, so a host
that stayed busy or unreachable looped without end. Ask once per target,
skill and bytes per session; a later session, a manual update or any write
of the skill records the marker instead.
* fix(skills): recognise another build's copy under a skill's former name
A build from before a rename records its marker under the former name.
Check that marker for former-name copies too, so a renamed build no longer
calls such a copy edited and nudges about it. A user edit, a cloud receipt
or extra files still keep the copy as it was.
* fix(skills): warn about any failed skill update that may have reached the host
A paired host's timeout or lost reply also arrives as an RPC error, so an
RPC error is no proof that nothing was written. Only a refusal before
sending now stays quiet.
* fix(skills): send a silent skill update only to the host that was checked
Pin the update to the runtime and pairing that answered the capability
check, so a re-pair while the check awaits cannot send it to another host.
* fix(skills): record markers without updating, and never offer to replace another build's copy
A marker call now asks the host to record copies already at its bytes and
nothing else, so it can never write a skill and needs no warning or
re-plan; hosts that predate it reject the request and write nothing. It
is sent only in a scan that starts no update.
Another build's copy is no longer offered for Replace, which could
downgrade it, and its dialog line reads "Kept: written by another Orca
version".
* fix(skills): keep other-build setup current across host pairings
* fix(skills): preserve other-build prerequisites during migration
* fix(tab-group): keep a grabbable tab in narrow tab-group strips
Tabs were the only shrinkable item in a pane's strip, and the only drag
source, so a narrow pane clipped them to 0px while +, quick commands, the
pane-actions menu and the reserved window-chrome spacers kept their width.
Give the tab area a 40px floor and let the action chrome clip before it.
* test(tab-group): open the right sidebar so the narrow-strip e2e is platform-neutral
* test(tab-group): assert the dragged tab moves between strips in the DOM
* fix(tab-group): hide strip actions whole instead of clipping their focus targets
Narrow strips clipped the new-tab, quick-command and pane-actions buttons
behind the 40px tab floor, so Tab could focus a control that was mostly or
entirely out of view. Measure the room left after the reserved spacers and
drop each control whole, and so out of Tab order, below the width where it
fits: quick commands first, then pane actions, then new tab (groups with a
tab only). Close split pane stays in every tab's context menu.
The e2e now measures only pixels that start a tab drag (not the close
button), drags from that run, and walks the strip with Tab at normal and
narrow widths, asserting every focused control is fully visible.
* fix(tab-group): offer quick commands from pane actions when the strip hides them
When a narrow strip folds the quick-command button away, the pane actions
menu now carries the same Quick Commands submenu the terminal and chat
menus use, so running or adding a command still works from the strip.
The narrow-strip e2e no longer sleeps or casts: it retries the first Tab
until focus lands in the strip, and a new test checks the menu offers quick
commands only when the button is hidden.
* fix(tab-group): drop the window-drag gap before strip controls clip
With the right sidebar closed, the 40px window-drag gap only shrank after
the tab bar hit its floor, so "+" and the actions clipped behind it while
the width rules said they fit. Hide the gap below the width where it and
every control fit, so the existing thresholds hold.
Adds an e2e that sweeps the top-right strip with the right sidebar closed
and asserts no focused strip control is clipped.
* feat(computer-use): add orca computer wait for text, enabled controls and window titles
* fix(computer-use): bound wait reads by the deadline and wait out missing Linux/Windows windows
* fix(computer-use): read disabled traits after role text with parentheses and bound the capability probe
* fix(source-control): keep merged reviews visible after an equivalent local rebase
* fix(source-control): retry proofs after fetching missing review heads
* fix(source-control): compare merged-review deltas without decoding
* fix(source-control): retry unproven equivalence after history fetches
* fix(native-chat): Enter on the chosen answer confirms instead of deselecting
In a single-select question without previews, Enter on the already-chosen
row now does what the footer says (Next/Submit) rather than clearing the
pick. Click, Space and digits still toggle; Enter on an unchosen row still
picks and auto-advances; preview, free-text and confirm-button paths are
unchanged.
Replace the class-name assertions in the answer card test with behavior:
focus without aria-pressed, and Skip becoming a button named Submit.
* test(native-chat): Enter on the chosen last-step answer submits once
* fix(native-chat): option rows handle Enter themselves, so async cards confirm too
The async question card does not take focus, so the card-level key hook is
off there and a native Enter on the chosen row clicked it off. Each option
row now handles Enter (pick, or Next/Submit on the chosen single-select row)
and prevents the native click; the hook keeps digits and arrows. Click,
Space, digits and multi-select toggling are unchanged.
Adds a test through the real async caller.
* test(native-chat): drive async-card Enter through an enabled, focused row
The send mock now reports the created message, so the returned row is enabled;
assert it is enabled and focused before pressing Enter.
* fix(computer): check macOS click targets are enabled, in view and on top before sending input
* fix(computer): scope macOS click cover checks to the target window
* fix(computer): scroll before trusting container hits and stop hit walks at the shared container
* refactor(computer): share the one-scroll rule in the macOS click check
* test(artifacts): restore publishing permission regression tests
#41012 and #41007 removed the tests that guard #40948 (new profiles allow
artifact publishing, profiles saved before the setting stay off, web clients
fail closed until the host grant is mirrored) and #40982 (moving a project
between profiles must not grant publishing to an older profile). Restore them
against current paths. Each fails when the code it guards is reverted.
* test(artifacts): keep only guards that fail when their fix is reverted
Drop the explicit opt-out and explicit-choice transfer cases: saved values
already win in both paths, so reverting #40948 or #40982 does not fail them.
Name the web test for what it checks: the local fallback, not host mirroring.
* fix(computer-use): capture KDE Wayland windows through the desktop portal
KWin is the only process on KDE Wayland that knows where a window is and
what covers it, so a one-shot KWin script reports window geometry and
stacking. Orca crops the xdg-desktop-portal screenshot to that window and
returns a screenshot error when the window is hidden, covered, or moves
during capture, or when the portal prompt is unanswered or denied.
* fix(computer-use): refuse KDE screenshots during Show Desktop or off every screen
* fix(computer-use): clean up oversized portal files and skip shaded KDE windows
* fix(computer): select list and table rows when a macOS click leaves them unselected
A plain click on an AXRow/AXCell answered success (AXPress) or unverified synthetic input while nothing got selected: AppKit rows have no AXPress, and background pointer input does not select them. After the click, read the selection back; if the row is still unselected, write it through the owning table/outline/list (AXSelectedCells/AXSelectedRows/AXSelectedChildren), falling back to the row's own AXSelected, and report verified only when the selection reads back on.
* fix(computer): find a cell's row through wrapper groups